feat: expand secure assistant workflows
Harden runtime execution and add local knowledge, Smart Heartbeat, usage visibility, responsive product surfaces, and cross-platform packaging support. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
parent
6ef1795b81
commit
b3fdf96962
+70
-1
@@ -25,13 +25,19 @@ import type {
|
||||
AssistantArtifact,
|
||||
AssistantMemory,
|
||||
AssistantSchedule,
|
||||
AssistantHeartbeatConfig,
|
||||
AssistantHeartbeatEntry,
|
||||
AssistantHeartbeatRun,
|
||||
AssistantExpert,
|
||||
AssistantTask,
|
||||
TokenUsageSummary,
|
||||
ConversationSnapshot,
|
||||
WorkspaceChanges,
|
||||
ProjectCreateInput,
|
||||
MemoryCreateInput,
|
||||
ScheduleCreateInput,
|
||||
HeartbeatCreateInput,
|
||||
HeartbeatUpdateInput,
|
||||
ExpertCreateInput
|
||||
} from '../shared/assistant-contracts'
|
||||
|
||||
@@ -44,6 +50,9 @@ const desktopApi: DesktopApi = {
|
||||
hide: async () => {
|
||||
await ipcRenderer.invoke(ipcChannels.appHide)
|
||||
},
|
||||
clearLocalData: async () => {
|
||||
await ipcRenderer.invoke(ipcChannels.appClearLocalData)
|
||||
},
|
||||
onNewConversation: (listener) => {
|
||||
const handler = (): void => listener()
|
||||
ipcRenderer.on(ipcChannels.conversationNew, handler)
|
||||
@@ -154,7 +163,22 @@ const desktopApi: DesktopApi = {
|
||||
},
|
||||
tasks: {
|
||||
list: () =>
|
||||
ipcRenderer.invoke(ipcChannels.tasksList) as Promise<AssistantTask[]>
|
||||
ipcRenderer.invoke(ipcChannels.tasksList) as Promise<AssistantTask[]>,
|
||||
setStatus: async (
|
||||
taskId: string,
|
||||
status: 'completed' | 'cancelled'
|
||||
) => {
|
||||
await ipcRenderer.invoke(ipcChannels.tasksSetStatus, {
|
||||
taskId,
|
||||
status
|
||||
})
|
||||
}
|
||||
},
|
||||
usage: {
|
||||
getTokenSummary: () =>
|
||||
ipcRenderer.invoke(
|
||||
ipcChannels.tokenUsageSummary
|
||||
) as Promise<TokenUsageSummary>
|
||||
},
|
||||
artifacts: {
|
||||
list: (projectId?: string) =>
|
||||
@@ -162,6 +186,11 @@ const desktopApi: DesktopApi = {
|
||||
ipcChannels.artifactsList,
|
||||
projectId
|
||||
) as Promise<AssistantArtifact[]>,
|
||||
get: (artifactId: string) =>
|
||||
ipcRenderer.invoke(
|
||||
ipcChannels.artifactsGet,
|
||||
artifactId
|
||||
) as Promise<AssistantArtifact>,
|
||||
importFiles: (projectId?: string) =>
|
||||
ipcRenderer.invoke(
|
||||
ipcChannels.artifactsImportFiles,
|
||||
@@ -216,6 +245,46 @@ const desktopApi: DesktopApi = {
|
||||
await ipcRenderer.invoke(ipcChannels.schedulesRunNow, scheduleId)
|
||||
}
|
||||
},
|
||||
heartbeats: {
|
||||
list: (projectId?: string) =>
|
||||
ipcRenderer.invoke(ipcChannels.heartbeatsList, {
|
||||
projectId
|
||||
}) as Promise<AssistantHeartbeatConfig[]>,
|
||||
create: (input: HeartbeatCreateInput) =>
|
||||
ipcRenderer.invoke(
|
||||
ipcChannels.heartbeatsCreate,
|
||||
input
|
||||
) as Promise<AssistantHeartbeatConfig>,
|
||||
update: (heartbeatId: string, input: HeartbeatUpdateInput) =>
|
||||
ipcRenderer.invoke(ipcChannels.heartbeatsUpdate, {
|
||||
id: heartbeatId,
|
||||
config: input
|
||||
}) as Promise<AssistantHeartbeatConfig>,
|
||||
setPaused: async (heartbeatId: string, paused: boolean) => {
|
||||
await ipcRenderer.invoke(ipcChannels.heartbeatsSetPaused, {
|
||||
id: heartbeatId,
|
||||
paused
|
||||
})
|
||||
},
|
||||
remove: async (heartbeatId: string) => {
|
||||
await ipcRenderer.invoke(ipcChannels.heartbeatsRemove, {
|
||||
id: heartbeatId
|
||||
})
|
||||
},
|
||||
runNow: (heartbeatId: string) =>
|
||||
ipcRenderer.invoke(ipcChannels.heartbeatsRunNow, {
|
||||
id: heartbeatId,
|
||||
idempotencyKey: crypto.randomUUID()
|
||||
}) as Promise<AssistantHeartbeatRun>,
|
||||
history: (heartbeatId?: string) =>
|
||||
ipcRenderer.invoke(ipcChannels.heartbeatsHistory, {
|
||||
configId: heartbeatId,
|
||||
limit: 200
|
||||
}) as Promise<{
|
||||
runs: AssistantHeartbeatRun[]
|
||||
entries: AssistantHeartbeatEntry[]
|
||||
}>
|
||||
},
|
||||
experts: {
|
||||
list: () =>
|
||||
ipcRenderer.invoke(
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
describe('sandboxed preload', () => {
|
||||
it('does not import Node built-ins unavailable in Electron sandbox', () => {
|
||||
const source = readFileSync(
|
||||
join(process.cwd(), 'src', 'preload', 'index.ts'),
|
||||
'utf8'
|
||||
)
|
||||
expect(source).not.toMatch(/\bfrom\s+['"]node:/u)
|
||||
expect(source).not.toMatch(/\brequire\(\s*['"]node:/u)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user