@steerable/agent-shell 0.6.52 → 0.6.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/brand.js +1 -1
  2. package/dist/host/pack-assembly.d.ts +6 -16
  3. package/dist/host/pack-assembly.js +3 -4
  4. package/dist/host/runtime.js +2 -0
  5. package/dist/i18n.d.ts +23 -0
  6. package/dist/i18n.js +87 -0
  7. package/dist/image-attachment.d.ts +31 -4
  8. package/dist/image-attachment.js +13 -18
  9. package/dist/json-store.js +3 -6
  10. package/dist/local-backend/portable-bundle.d.ts +16 -2
  11. package/dist/local-backend/portable-bundle.js +29 -16
  12. package/dist/local-backend/portable-service.js +25 -11
  13. package/dist/local-backend/router.js +56 -17
  14. package/dist/local-backend/skills/10-goal/SKILL.md +1 -1
  15. package/dist/local-backend/skills/11-loop/SKILL.md +1 -1
  16. package/dist/local-backend/skills/12-create-skill/SKILL.md +2 -2
  17. package/dist/local-executor.d.ts +22 -0
  18. package/dist/local-executor.js +118 -1
  19. package/dist/local-script-registry.js +2 -2
  20. package/dist/mcp-executor.d.ts +42 -10
  21. package/dist/mcp-executor.js +248 -41
  22. package/dist/mcp-server-registry.d.ts +59 -11
  23. package/dist/mcp-server-registry.js +193 -28
  24. package/dist/product-config.d.ts +24 -14
  25. package/dist/project-registry.d.ts +3 -3
  26. package/dist/project-registry.js +2 -2
  27. package/dist/runtime.d.ts +8 -54
  28. package/dist/runtime.js +15 -129
  29. package/dist/scenario/pack.d.ts +1 -1
  30. package/dist/scenario/registry.d.ts +4 -5
  31. package/dist/scenario/registry.js +2 -10
  32. package/dist/server/start.js +1 -2
  33. package/dist/shell-exec.d.ts +62 -0
  34. package/dist/shell-exec.js +147 -0
  35. package/dist/shell-process.d.ts +3 -0
  36. package/dist/shell-process.js +137 -0
  37. package/dist/sidecar/boot.js +4 -0
  38. package/dist/sidecar/reverse-spawn.js +6 -15
  39. package/dist/sidecar/supervisor.d.ts +0 -2
  40. package/dist/sidecar/supervisor.js +7 -30
  41. package/dist/storage/index.js +1 -1
  42. package/dist/storage/write-lease-error.d.ts +2 -11
  43. package/dist/storage/write-lease-error.js +3 -8
  44. package/dist/tool-router.js +21 -6
  45. package/package.json +7 -14
  46. package/dist/app-update-electron.d.ts +0 -5
  47. package/dist/app-update-electron.js +0 -66
  48. package/dist/app-update.d.ts +0 -92
  49. package/dist/app-update.js +0 -213
  50. package/dist/host/ipc.d.ts +0 -11
  51. package/dist/host/ipc.js +0 -20
  52. package/dist/main.d.ts +0 -1
  53. package/dist/main.js +0 -967
  54. package/dist/preload-default.d.ts +0 -1
  55. package/dist/preload-default.js +0 -9
  56. package/dist/preload.cjs +0 -425
  57. package/dist/preload.d.ts +0 -20
  58. package/dist/preload.js +0 -442
  59. package/dist/single-instance.d.ts +0 -11
  60. package/dist/single-instance.js +0 -21
@@ -1 +0,0 @@
1
- export {};
@@ -1,9 +0,0 @@
1
- /**
2
- * shell 默认 preload 入口:无包贡献的中性面(buildPreloadApi())。
3
- * 由本包构建(esbuild → dist/preload.cjs)打包成单文件 CJS,供
4
- * shell main.ts 的默认 preload 路径与纯 shell/demo 启动使用。
5
- * 带 invoke 型包贡献的产品用自己的 preload 入口(产品构建打包到
6
- * 产品 main.js 旁)并经 setPreloadPath 注入,不走本入口。
7
- */
8
- import { buildPreloadApi } from './preload.js';
9
- buildPreloadApi();
package/dist/preload.cjs DELETED
@@ -1,425 +0,0 @@
1
- "use strict";
2
-
3
- // src/preload.ts
4
- var import_electron = require("electron");
5
- var DEMO_TOKEN_KEY = "deeppath_access_token";
6
- var DEMO_USER_KEY = "deeppath_user";
7
- var demoToken = process.env.AGENT_DEMO_TOKEN;
8
- var demoUserJson = process.env.AGENT_DEMO_USER;
9
- function seedDemoCredentials() {
10
- if (!demoToken) return;
11
- try {
12
- if (window.localStorage.getItem(DEMO_TOKEN_KEY) !== demoToken) {
13
- window.localStorage.setItem(DEMO_TOKEN_KEY, demoToken);
14
- }
15
- if (demoUserJson && !window.localStorage.getItem(DEMO_USER_KEY)) {
16
- window.localStorage.setItem(DEMO_USER_KEY, demoUserJson);
17
- }
18
- const expires = new Date(Date.now() + 30 * 864e5).toUTCString();
19
- document.cookie = `${DEMO_TOKEN_KEY}=${encodeURIComponent(demoToken)}; expires=${expires}; path=/; SameSite=Lax`;
20
- } catch (err) {
21
- console.error("[agent-shell] failed to seed demo token", err);
22
- }
23
- }
24
- try {
25
- seedDemoCredentials();
26
- } catch {
27
- }
28
- window.addEventListener("DOMContentLoaded", seedDemoCredentials);
29
- function buildPreloadApi(packContributions = {}) {
30
- const electronAPI = {
31
- runtime: "local",
32
- platform: process.platform,
33
- onThemeChanged: (callback) => {
34
- import_electron.ipcRenderer.on("theme-changed", (_event, isDark) => callback(isDark));
35
- },
36
- offThemeChanged: () => {
37
- import_electron.ipcRenderer.removeAllListeners("theme-changed");
38
- },
39
- retryConnection: () => {
40
- import_electron.ipcRenderer.send("retry-connection");
41
- },
42
- checkNetworkStatus: async () => {
43
- return await import_electron.ipcRenderer.invoke("check-network-status");
44
- },
45
- onNetworkStatusChanged: (callback) => {
46
- import_electron.ipcRenderer.on("network-status-changed", callback);
47
- },
48
- offNetworkStatusChanged: () => {
49
- import_electron.ipcRenderer.removeAllListeners("network-status-changed");
50
- },
51
- showNotification: (payload) => {
52
- import_electron.ipcRenderer.send("show-notification", payload);
53
- },
54
- onNotificationClicked: (callback) => {
55
- import_electron.ipcRenderer.on("notification-clicked", (_event, data) => callback(data));
56
- },
57
- offNotificationClicked: () => {
58
- import_electron.ipcRenderer.removeAllListeners("notification-clicked");
59
- },
60
- onMenuNewChat: (callback) => {
61
- import_electron.ipcRenderer.on("menu:new-chat", () => callback());
62
- },
63
- offMenuNewChat: () => {
64
- import_electron.ipcRenderer.removeAllListeners("menu:new-chat");
65
- },
66
- onMenuOpenTerminal: (callback) => {
67
- import_electron.ipcRenderer.on("menu:open-terminal", () => callback());
68
- },
69
- offMenuOpenTerminal: () => {
70
- import_electron.ipcRenderer.removeAllListeners("menu:open-terminal");
71
- },
72
- /**
73
- * AI 标题异步就绪。Backend 在每条 chat 的首条助手回复完成后 fire-and-forget
74
- * 跑 LLM 生成标题;完成后通过这个通道把 `{chatId, title}` 广播到所有 renderer。
75
- *
76
- * 返回 unsubscribe 函数——和 onMenuNewChat 不一样,这个通道有可能多处订阅
77
- * (主窗 + 未来的设置窗),所以用 add/remove 配对而不是 removeAllListeners。
78
- */
79
- onChatTitleUpdated: (callback) => {
80
- const handler = (_event, payload) => {
81
- if (typeof payload?.chatId === "string" && typeof payload?.title === "string") {
82
- callback({ chatId: payload.chatId, title: payload.title });
83
- }
84
- };
85
- import_electron.ipcRenderer.on("chat-title-updated", handler);
86
- return () => {
87
- import_electron.ipcRenderer.removeListener("chat-title-updated", handler);
88
- };
89
- },
90
- /**
91
- * 回合追问建议就绪。Backend 在助手回复完成后 fire-and-forget 生成 3 条
92
- * 下一轮用户输入;启发式兜底会立刻推一次,LLM 成功后再替换。返回 unsubscribe。
93
- */
94
- onSuggestedReplies: (callback) => {
95
- const handler = (_event, payload) => {
96
- if (typeof payload?.chatId === "string" && typeof payload?.messageId === "string" && Array.isArray(payload.suggestions) && payload.suggestions.every((item) => typeof item === "string")) {
97
- callback({
98
- chatId: payload.chatId,
99
- messageId: payload.messageId,
100
- suggestions: payload.suggestions
101
- });
102
- }
103
- };
104
- import_electron.ipcRenderer.on("suggested-replies", handler);
105
- return () => {
106
- import_electron.ipcRenderer.removeListener("suggested-replies", handler);
107
- };
108
- },
109
- /**
110
- * 会话补建通知:Backend 在向本地不存在的 chatId 首次发送时按 URL 里的 id
111
- * 现场补建会话,并广播 `chat-created`({chatId, agentId})。返回 unsubscribe
112
- * (多处订阅用 add/remove 配对)。
113
- */
114
- onChatCreated: (callback) => {
115
- const handler = (_event, payload) => {
116
- if (typeof payload?.chatId === "string" && payload.chatId) {
117
- callback({
118
- chatId: payload.chatId,
119
- agentId: typeof payload.agentId === "string" ? payload.agentId : null
120
- });
121
- }
122
- };
123
- import_electron.ipcRenderer.on("chat-created", handler);
124
- return () => {
125
- import_electron.ipcRenderer.removeListener("chat-created", handler);
126
- };
127
- },
128
- /**
129
- * 场景包广播事件订阅(3.1 通用化):按通道名订阅主进程广播,载荷
130
- * 原样透传(收窄校验在订阅方——包——一侧)。通道名约定带包前缀
131
- * (如 `<pack>:updated`)。返回解除订阅函数。
132
- */
133
- onPackEvent: (channel, callback) => {
134
- const handler = (_event, payload) => {
135
- callback(payload);
136
- };
137
- import_electron.ipcRenderer.on(channel, handler);
138
- return () => {
139
- import_electron.ipcRenderer.removeListener(channel, handler);
140
- };
141
- },
142
- /**
143
- * 4.6a 后台任务状态推送:任务到达终态(completed/failed)或 worktree
144
- * 合并/丢弃完成时,主进程广播 `task-updated`。载荷只带 chatId/taskId
145
- * ——renderer 收到后重新拉任务列表(GET /chats/:id/tasks),
146
- * 不把整条任务记录塞进 IPC(避免与 SQLite 双写漂移)。
147
- */
148
- onTaskUpdated: (callback) => {
149
- const handler = (_event, payload) => {
150
- if (typeof payload?.chatId === "string" && typeof payload?.taskId === "string") {
151
- callback({ chatId: payload.chatId, taskId: payload.taskId });
152
- }
153
- };
154
- import_electron.ipcRenderer.on("task-updated", handler);
155
- return () => {
156
- import_electron.ipcRenderer.removeListener("task-updated", handler);
157
- };
158
- },
159
- onTaskProcess: (callback) => {
160
- const handler = (_event, payload) => {
161
- if (typeof payload?.chatId !== "string" || typeof payload?.taskId !== "string") return;
162
- callback({
163
- chatId: payload.chatId,
164
- taskId: payload.taskId,
165
- timeline: payload.timeline,
166
- live: payload.live === true
167
- });
168
- };
169
- import_electron.ipcRenderer.on("task-process", handler);
170
- return () => {
171
- import_electron.ipcRenderer.removeListener("task-process", handler);
172
- };
173
- },
174
- /**
175
- * W4-1 审批代数:sidecar 的 ApprovalExecutor 经反向通道请示,主进程把
176
- * 请求广播到 renderer(approval:request),输入区审批菜单应答后走
177
- * approval:decide 回到主进程。pending 供刷新后的 renderer 恢复仍在等待
178
- * 的请求。
179
- */
180
- approval: {
181
- onRequest: (callback) => {
182
- const handler = (_event, payload) => {
183
- const p = payload;
184
- if (typeof p?.requestId === "string" && typeof p?.toolName === "string") {
185
- callback(payload);
186
- }
187
- };
188
- import_electron.ipcRenderer.on("approval:request", handler);
189
- return () => {
190
- import_electron.ipcRenderer.removeListener("approval:request", handler);
191
- };
192
- },
193
- decide: async (decision) => {
194
- await import_electron.ipcRenderer.invoke("approval:decide", decision);
195
- },
196
- pending: async () => {
197
- return await import_electron.ipcRenderer.invoke("approval:pending");
198
- }
199
- },
200
- /**
201
- * W8 结构化提问:sidecar 的 ask_user 工具经反向通道请示,主进程把
202
- * 请求广播到 renderer(ask-user:request),问题卡片应答后走
203
- * ask-user:answer 回到主进程。pending 供刷新后的 renderer 恢复仍在等待
204
- * 的请求。
205
- */
206
- askUser: {
207
- onRequest: (callback) => {
208
- const handler = (_event, payload) => {
209
- const p = payload;
210
- if (typeof p?.requestId === "string" && Array.isArray(p?.questions)) {
211
- callback(payload);
212
- }
213
- };
214
- import_electron.ipcRenderer.on("ask-user:request", handler);
215
- return () => {
216
- import_electron.ipcRenderer.removeListener("ask-user:request", handler);
217
- };
218
- },
219
- answer: async (reply) => {
220
- await import_electron.ipcRenderer.invoke("ask-user:answer", reply);
221
- },
222
- pending: async () => {
223
- return await import_electron.ipcRenderer.invoke("ask-user:pending");
224
- }
225
- },
226
- local: {
227
- selectDirectory: async (options) => {
228
- return await import_electron.ipcRenderer.invoke("local:select-directory", options);
229
- },
230
- saveTextFile: async (options) => {
231
- return await import_electron.ipcRenderer.invoke("local:save-text-file", options);
232
- },
233
- captureScreenshot: async (rect) => {
234
- return await import_electron.ipcRenderer.invoke(
235
- "local:capture-screenshot",
236
- rect ? { rect } : {}
237
- );
238
- },
239
- execShell: async (request) => {
240
- return await import_electron.ipcRenderer.invoke("local:exec-shell", request);
241
- },
242
- readFile: async (request) => {
243
- return await import_electron.ipcRenderer.invoke("local:read-file", request);
244
- },
245
- writeFile: async (request) => {
246
- return await import_electron.ipcRenderer.invoke("local:write-file", request);
247
- },
248
- openPath: async (request) => {
249
- return await import_electron.ipcRenderer.invoke("local:open-path", request);
250
- },
251
- listScripts: async () => {
252
- return await import_electron.ipcRenderer.invoke("local:list-scripts");
253
- },
254
- addScript: async (input) => {
255
- return await import_electron.ipcRenderer.invoke("local:add-script", input);
256
- },
257
- updateScript: async (id, updates) => {
258
- return await import_electron.ipcRenderer.invoke("local:update-script", { id, updates });
259
- },
260
- deleteScript: async (id) => {
261
- return await import_electron.ipcRenderer.invoke("local:delete-script", id);
262
- },
263
- runScript: async (id) => {
264
- return await import_electron.ipcRenderer.invoke("local:run-script", id);
265
- },
266
- getPlatformInfo: () => ({ platform: process.platform }),
267
- updateSafetyConfig: async (config) => {
268
- return await import_electron.ipcRenderer.invoke("local:update-safety-config", config);
269
- }
270
- },
271
- /** 会话附件:把源文件路径 / base64 字节拷贝进会话空间(`attachments:save`)。 */
272
- attachments: {
273
- save: async (input) => {
274
- return await import_electron.ipcRenderer.invoke("attachments:save", input);
275
- }
276
- },
277
- localBackend: {
278
- request: async (input) => {
279
- const result = await import_electron.ipcRenderer.invoke("local-backend:request", input);
280
- if (!result.ok) {
281
- const err = new Error(result.error || "Local backend request failed");
282
- err.status = result.status;
283
- throw err;
284
- }
285
- return result.data;
286
- },
287
- /**
288
- * 启动一条本地后端流。
289
- * 注意:Electron contextBridge 不支持把 ReadableStream 跨上下文传给 renderer
290
- * (structured clone 会把它剥成空对象,导致 web UI 拿到的 Response.body 永远不出数据)。
291
- * 这里只暴露 `startStream(input, onEvent)` 原语,由 web UI 端在 renderer 上下文
292
- * 内自己构造 ReadableStream 并喂入 onEvent 回调(callback 跨上下文是 proxied 的)。
293
- *
294
- * 返回 streamId 用于后续 cancelStream(id)。
295
- */
296
- startStream: async (input, onEvent) => {
297
- const result = await import_electron.ipcRenderer.invoke("local-backend:stream", input);
298
- if (!result.ok || !result.streamId) {
299
- try {
300
- onEvent({ type: "error", error: result.error || `start stream failed (${result.status ?? 500})` });
301
- } catch {
302
- }
303
- return null;
304
- }
305
- const channel = `local-backend:stream:${result.streamId}`;
306
- const handler = (_event, payload) => {
307
- try {
308
- onEvent(payload);
309
- } catch (err) {
310
- console.error("[preload] stream event callback threw", err);
311
- }
312
- if (payload.type === "end" || payload.type === "error") {
313
- import_electron.ipcRenderer.removeListener(channel, handler);
314
- }
315
- };
316
- import_electron.ipcRenderer.on(channel, handler);
317
- return result.streamId;
318
- },
319
- cancelStream: (streamId) => {
320
- import_electron.ipcRenderer.send(`local-backend:stream:${streamId}:cancel`);
321
- },
322
- /**
323
- * 轮中转向:把一条用户消息注入该 chat 正在运行的 CoreLoop 回合。
324
- * 返回 true 表示已被接受(UI 立即上屏);false 表示当前没有可转向的
325
- * 回合(TS 循环路径或回合刚结束)——调用方应保留草稿。
326
- */
327
- steerChat: async (chatId, content) => {
328
- const result = await import_electron.ipcRenderer.invoke("local-backend:steer", {
329
- chatId,
330
- content
331
- });
332
- return result?.ok === true;
333
- },
334
- traces: {
335
- list: async (chatId, limit = 50) => {
336
- const path = `/api/v2/local/traces?chatId=${encodeURIComponent(chatId)}&limit=${limit}`;
337
- return await electronAPI.localBackend.request({ method: "GET", path });
338
- },
339
- get: async (traceId) => {
340
- const path = `/api/v2/local/traces/${encodeURIComponent(traceId)}`;
341
- return await electronAPI.localBackend.request({ method: "GET", path });
342
- }
343
- }
344
- },
345
- agent: {
346
- hasToken: async () => {
347
- return true;
348
- },
349
- provision: async (_userJWT) => {
350
- return { success: true };
351
- },
352
- start: async () => {
353
- return { success: true };
354
- },
355
- getStatus: async () => {
356
- return { status: "registered", agentId: "local-agent" };
357
- },
358
- getInfo: async () => {
359
- return {
360
- id: "local-agent",
361
- machineId: "local",
362
- name: "Local Agent",
363
- platform: process.platform,
364
- hostname: "localhost",
365
- shell: process.platform === "darwin" ? "zsh" : "bash",
366
- isOnline: true
367
- };
368
- },
369
- onNeedProvision: (_callback) => void 0,
370
- offNeedProvision: () => void 0
371
- },
372
- terminal: {
373
- list: async () => {
374
- return await import_electron.ipcRenderer.invoke("terminal:list");
375
- },
376
- spawn: async (options = {}) => {
377
- return await import_electron.ipcRenderer.invoke("terminal:spawn", options);
378
- },
379
- ensure: async (options = {}) => {
380
- return await import_electron.ipcRenderer.invoke("terminal:ensure", options);
381
- },
382
- write: async (id, data) => {
383
- return await import_electron.ipcRenderer.invoke("terminal:write", { id, data });
384
- },
385
- resize: async (id, cols, rows) => {
386
- return await import_electron.ipcRenderer.invoke("terminal:resize", { id, cols, rows });
387
- },
388
- kill: async (id) => {
389
- return await import_electron.ipcRenderer.invoke("terminal:kill", id);
390
- },
391
- exec: async (payload) => {
392
- return await import_electron.ipcRenderer.invoke("terminal:exec", payload);
393
- },
394
- onData: (callback) => {
395
- const fn = (_event, payload) => callback(payload);
396
- import_electron.ipcRenderer.on("terminal:data", fn);
397
- return () => import_electron.ipcRenderer.removeListener("terminal:data", fn);
398
- },
399
- onExit: (callback) => {
400
- const fn = (_event, payload) => callback(payload);
401
- import_electron.ipcRenderer.on("terminal:exit", fn);
402
- return () => import_electron.ipcRenderer.removeListener("terminal:exit", fn);
403
- },
404
- onSpawned: (callback) => {
405
- const fn = (_event, session) => callback(session);
406
- import_electron.ipcRenderer.on("terminal:spawned", fn);
407
- return () => import_electron.ipcRenderer.removeListener("terminal:spawned", fn);
408
- }
409
- },
410
- app: {
411
- snapshot: () => import_electron.ipcRenderer.invoke("app:release-snapshot"),
412
- check: () => import_electron.ipcRenderer.invoke("app:release-check"),
413
- install: () => import_electron.ipcRenderer.invoke("app:release-install"),
414
- onState: (callback) => {
415
- const fn = (_event, snapshot) => callback(snapshot);
416
- import_electron.ipcRenderer.on("app-update-state", fn);
417
- return () => import_electron.ipcRenderer.removeListener("app-update-state", fn);
418
- }
419
- }
420
- };
421
- import_electron.contextBridge.exposeInMainWorld("electron", { ...electronAPI, ...packContributions });
422
- }
423
-
424
- // src/preload-default.ts
425
- buildPreloadApi();
package/dist/preload.d.ts DELETED
@@ -1,20 +0,0 @@
1
- /**
2
- * 构建并暴露 window.electron API(2.3 pack-preload 组合)。
3
- *
4
- * 包贡献经参数合并进顶层命名空间(如某包给出 `{ <pack>, <pack>Mock }`
5
- * 这样的 invoke 型命名空间);shell 本体不含任何
6
- * 包符号。由产品 preload 入口(products/<id>/preload.ts)或 dev 入口
7
- * (devtools/dev-preload.ts)调用。
8
- */
9
- export declare function buildPreloadApi(packContributions?: Record<string, unknown>): void;
10
- /**
11
- * window.electron 的 API 面。shell 本体不含包符号(2.3 起包段由产品
12
- * preload 入口组合);渲染端的完整类型镜像维护在
13
- * apps/web/src/lib/electron-bridge.ts。
14
- */
15
- export type ElectronAPI = Record<string, unknown>;
16
- declare global {
17
- interface Window {
18
- electron: ElectronAPI;
19
- }
20
- }