Prompts submitted while a turn runs queue above the composer (edit, remove, auto-send on completion; interruption or a failure pauses the queue with an explicit resume). Permission requests and elicitations route from the ACP client in main to renderer cards with the request options — pending cards replay when the renderer reloads, replacing the blocking OS dialogs. The task plan docks above the composer instead of scrolling inside the thread, multi-line user bubbles trim their padding lines, and a turn that ends abnormally shows an inline error line in the transcript.
55 lines
2.2 KiB
JavaScript
55 lines
2.2 KiB
JavaScript
const { contextBridge, ipcRenderer } = require('electron')
|
|
|
|
const api = {
|
|
runtime: {
|
|
start: () => ipcRenderer.invoke('runtime:start'),
|
|
stop: () => ipcRenderer.invoke('runtime:stop'),
|
|
restart: () => ipcRenderer.invoke('runtime:restart'),
|
|
status: () => ipcRenderer.invoke('runtime:status'),
|
|
onStatus: (callback) => {
|
|
const listener = (_event, payload) => { callback(payload) }
|
|
ipcRenderer.on('runtime:status-update', listener)
|
|
return () => { ipcRenderer.removeListener('runtime:status-update', listener) }
|
|
},
|
|
onStderr: (callback) => {
|
|
const listener = (_event, payload) => { callback(payload) }
|
|
ipcRenderer.on('runtime:stderr', listener)
|
|
return () => { ipcRenderer.removeListener('runtime:stderr', listener) }
|
|
},
|
|
},
|
|
sessions: {
|
|
list: () => ipcRenderer.invoke('sessions:list'),
|
|
create: () => ipcRenderer.invoke('sessions:create'),
|
|
load: (sessionId) => ipcRenderer.invoke('sessions:load', { sessionId }),
|
|
prompt: (sessionId, text) => ipcRenderer.invoke('sessions:prompt', { sessionId, text }),
|
|
cancel: (sessionId) => ipcRenderer.invoke('sessions:cancel', { sessionId }),
|
|
reveal: (sessionId) => ipcRenderer.invoke('sessions:reveal', { sessionId }),
|
|
onUpdate: (callback) => {
|
|
const listener = (_event, payload) => { callback(payload) }
|
|
ipcRenderer.on('sessions:update', listener)
|
|
return () => { ipcRenderer.removeListener('sessions:update', listener) }
|
|
},
|
|
},
|
|
trace: {
|
|
read: (sessionId) => ipcRenderer.invoke('trace:read', { sessionId }),
|
|
},
|
|
feedback: {
|
|
list: (sessionId, targetId) => ipcRenderer.invoke('feedback:list', { sessionId, targetId }),
|
|
add: (entry) => ipcRenderer.invoke('feedback:add', entry),
|
|
},
|
|
dev: {
|
|
status: () => ipcRenderer.invoke('dev:status'),
|
|
openPath: (path) => ipcRenderer.invoke('dev:open-path', { path }),
|
|
},
|
|
interaction: {
|
|
onRequest: (callback) => {
|
|
const listener = (_event, payload) => { callback(payload) }
|
|
ipcRenderer.on('interaction:request', listener)
|
|
return () => { ipcRenderer.removeListener('interaction:request', listener) }
|
|
},
|
|
respond: (id, response) => ipcRenderer.invoke('interaction:respond', { id, response }),
|
|
},
|
|
}
|
|
|
|
contextBridge.exposeInMainWorld('dshDesktop', api)
|