@steerable/agent-shell-web 0.6.18 → 0.6.20

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 (55) hide show
  1. package/package.json +15 -8
  2. package/src/lib/chat-transport.ts +1 -2
  3. package/src/lib/electron-bridge.ts +2 -2
  4. package/src/lib/http-bridge.ts +18 -4
  5. package/vite.base.d.ts +7 -0
  6. package/vite.base.js +83 -0
  7. package/src/brand.test.ts +0 -22
  8. package/src/components/AgentSidebar.test.tsx +0 -791
  9. package/src/components/ChatHeader.test.tsx +0 -230
  10. package/src/components/LocalLlmSettingsModal.test.tsx +0 -372
  11. package/src/components/chat/ApprovalModal.test.tsx +0 -83
  12. package/src/components/chat/AskUserModalHost.test.tsx +0 -176
  13. package/src/components/chat/AskUserQuestionMenu.test.tsx +0 -190
  14. package/src/components/chat/AssistantMessage.test.tsx +0 -68
  15. package/src/components/chat/ChatInput.test.tsx +0 -609
  16. package/src/components/chat/ExecPolicyPicker.test.tsx +0 -26
  17. package/src/components/chat/Markdown.test.tsx +0 -170
  18. package/src/components/chat/ModelPicker.test.tsx +0 -149
  19. package/src/components/chat/SessionTreeModal.test.tsx +0 -161
  20. package/src/components/chat/TaskOutcomeCards.test.tsx +0 -97
  21. package/src/components/chat/TaskPanelModal.test.tsx +0 -198
  22. package/src/components/chat/TaskProcessPanel.test.tsx +0 -111
  23. package/src/components/chat/TurnProcessGroup.test.tsx +0 -161
  24. package/src/components/chat/elapsed.test.ts +0 -42
  25. package/src/components/chat/executed-actions-model.test.ts +0 -134
  26. package/src/components/chat/orchestration-children-model.test.ts +0 -115
  27. package/src/components/chat/turn-timeline.test.ts +0 -97
  28. package/src/components/chat/useChatTasks.test.ts +0 -136
  29. package/src/components/settings/AgentsSettingsPanel.test.tsx +0 -229
  30. package/src/components/settings/InsightsSettingsPanel.test.tsx +0 -132
  31. package/src/components/settings/LlmSettingsPanel.test.tsx +0 -461
  32. package/src/components/settings/ModelIdCombobox.test.tsx +0 -88
  33. package/src/components/settings/SecuritySettingsPanel.test.tsx +0 -122
  34. package/src/components/settings/SkillsSettingsPanel.test.tsx +0 -62
  35. package/src/components/settings/WebSearchSettingsPanel.test.tsx +0 -90
  36. package/src/components/settings/compat-flags-model.test.ts +0 -71
  37. package/src/components/settings/llm-vendors.test.ts +0 -171
  38. package/src/components/settings/model-capabilities.test.ts +0 -88
  39. package/src/components/settings/preset-choice-model.test.ts +0 -96
  40. package/src/hooks/useChatsAndAgents.test.ts +0 -165
  41. package/src/lib/attachments.test.ts +0 -127
  42. package/src/lib/chat-title.test.ts +0 -53
  43. package/src/lib/chat-transport.test.ts +0 -277
  44. package/src/lib/date-groups.test.ts +0 -62
  45. package/src/lib/demo-flag.test.ts +0 -17
  46. package/src/lib/electron-bridge.test.ts +0 -54
  47. package/src/lib/exec-policy.test.ts +0 -71
  48. package/src/lib/http-bridge.test.ts +0 -246
  49. package/src/lib/insights.test.ts +0 -56
  50. package/src/lib/local-api.test.ts +0 -353
  51. package/src/lib/pending-first-message.test.ts +0 -17
  52. package/src/lib/slash-sources.test.ts +0 -161
  53. package/src/pages/AgentPage.test.tsx +0 -627
  54. package/src/pages/SettingsPage.test.tsx +0 -102
  55. package/vite.base.ts +0 -94
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@steerable/agent-shell-web",
3
- "version": "0.6.18",
3
+ "version": "0.6.20",
4
4
  "type": "module",
5
- "description": "Steerable framework — product-neutral renderer SPA source for @steerable/agent-shell (React + Vite). Consumed by product web entry points via the `@/` alias (anchored at this package's src/) and the createProductViteConfig factory. Published as a source package (src/ + vite.base.ts), not a build artifact.",
5
+ "description": "Steerable framework — product-neutral renderer SPA source for @steerable/agent-shell (React + Vite). Consumed by product web entry points via the `@/` alias (anchored at this package's src/) and the createProductViteConfig factory. Published as a source package (src/), plus the compiled vite.base config factory (vite.base.js + .d.ts) for Node-side config loading.",
6
6
  "license": "Apache-2.0",
7
7
  "homepage": "https://steerableframework.com/",
8
8
  "repository": {
@@ -14,13 +14,19 @@
14
14
  "url": "https://github.com/pathlyapp/steerable-framework/issues"
15
15
  },
16
16
  "exports": {
17
- "./vite.base": "./vite.base.ts",
17
+ "./vite.base": {
18
+ "types": "./vite.base.d.ts",
19
+ "default": "./vite.base.js"
20
+ },
18
21
  "./package.json": "./package.json"
19
22
  },
20
23
  "files": [
21
24
  "src",
25
+ "!src/**/*.test.ts",
26
+ "!src/**/*.test.tsx",
22
27
  "public",
23
- "vite.base.ts",
28
+ "vite.base.js",
29
+ "vite.base.d.ts",
24
30
  "README.md"
25
31
  ],
26
32
  "publishConfig": {
@@ -39,8 +45,8 @@
39
45
  "react-router-dom": "^6.30.0",
40
46
  "rehype-raw": "^7.0.0",
41
47
  "remark-gfm": "^4.0.1",
42
- "@steerable/agent-protocol": "0.6.18",
43
- "@steerable/agent-ui": "0.6.18"
48
+ "@steerable/agent-ui": "0.6.20",
49
+ "@steerable/agent-protocol": "0.6.20"
44
50
  },
45
51
  "devDependencies": {
46
52
  "@tailwindcss/vite": "^4.3.0",
@@ -53,11 +59,12 @@
53
59
  "typescript": "^5.8.3",
54
60
  "vite": "^5.4.21",
55
61
  "vitest": "^3.2.4",
56
- "@steerable/pack-sdk": "0.6.18"
62
+ "@steerable/pack-sdk": "0.6.20"
57
63
  },
58
64
  "scripts": {
59
65
  "gen": "echo agent-shell-web",
60
- "build": "tsc --noEmit",
66
+ "build": "tsc --noEmit && npm run build:vite-base",
67
+ "build:vite-base": "tsc vite.base.ts --module esnext --target es2022 --moduleResolution bundler --declaration --skipLibCheck --outDir .",
61
68
  "typecheck": "tsc --noEmit",
62
69
  "test": "vitest run",
63
70
  "lint": "tsc --noEmit",
@@ -20,8 +20,7 @@
20
20
  * - Standard content tokens: `data: {"content":"..."}\n\n`
21
21
  * - User message echo: `data: {"type":"user_message", "message":{...}}\n\n`
22
22
  * - Tool execution summary: `data: {"type":"executed_actions", "actions":[...]}\n\n`
23
- * - Per-round completion: `data: {"type":"completion", "status":"...", "reason":"..."}\n\n`
24
- * - Budget exhausted: `data: {"type":"budget_exhausted", "budget":{...}}\n\n`
23
+ * - Budget exhausted: `data: {"type":"budget_exhausted", "budget":{"kind":"..."}, "message":"..."}\n\n`
25
24
  * - Persisted message id: `data: {"type":"message_id", "messageId":"..."}\n\n`
26
25
  * - Named error event: `event: error\ndata: {"message":"..."}\n\n`
27
26
  * - Stream terminator: `data: [DONE]\n\n`
@@ -164,10 +164,10 @@ export interface ElectronBridge {
164
164
  ) => () => void;
165
165
  /**
166
166
  * 4.6a 后台任务状态推送。任务到达终态或 worktree 合并/丢弃完成时主进程
167
- * 广播;载荷只有 chatId/taskId/status,面板收到后重新拉列表。
167
+ * 广播;载荷只有 chatId/taskId,面板收到后重新拉列表。
168
168
  */
169
169
  onTaskUpdated?: (
170
- callback: (payload: { chatId: string; taskId: string; status: string }) => void,
170
+ callback: (payload: { chatId: string; taskId: string }) => void,
171
171
  ) => () => void;
172
172
  /**
173
173
  * 场景包广播事件订阅(3.1 通用化):按通道名订阅主进程/BS 后端的
@@ -28,6 +28,8 @@ interface BsBootstrap {
28
28
  platform: NodeJS.Platform;
29
29
  flavor: string;
30
30
  brandName: string;
31
+ /** 每次启动生成的 Bearer token;/api/v2/* 与 /host/* 全部要求携带。 */
32
+ token?: string;
31
33
  }
32
34
 
33
35
  function bootstrap(): BsBootstrap {
@@ -37,10 +39,18 @@ function bootstrap(): BsBootstrap {
37
39
  : { platform: 'linux', flavor: 'generic', brandName: '' };
38
40
  }
39
41
 
42
+ function authHeaders(): Record<string, string> {
43
+ const token = bootstrap().token;
44
+ return token ? { Authorization: `Bearer ${token}` } : {};
45
+ }
46
+
40
47
  async function http<T>(method: string, path: string, body?: unknown): Promise<T> {
41
48
  const res = await fetch(path, {
42
49
  method,
43
- headers: body !== undefined ? { 'Content-Type': 'application/json' } : undefined,
50
+ headers: {
51
+ ...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),
52
+ ...authHeaders(),
53
+ },
44
54
  body: body !== undefined ? JSON.stringify(body) : undefined,
45
55
  });
46
56
  const data = (await res.json().catch(() => null)) as T & { detail?: string };
@@ -63,7 +73,11 @@ let eventSource: EventSource | null = null;
63
73
 
64
74
  function ensureEventSource(): EventSource {
65
75
  if (eventSource) return eventSource;
66
- eventSource = new EventSource('/api/v2/events');
76
+ // EventSource 不能设请求头,token 走 query(server 端两种都收)。
77
+ const token = bootstrap().token;
78
+ eventSource = new EventSource(
79
+ `/api/v2/events${token ? `?token=${encodeURIComponent(token)}` : ''}`,
80
+ );
67
81
  return eventSource;
68
82
  }
69
83
 
@@ -112,7 +126,7 @@ async function startStream(
112
126
  try {
113
127
  res = await fetch(input.path, {
114
128
  method: input.method,
115
- headers: { 'Content-Type': 'application/json' },
129
+ headers: { 'Content-Type': 'application/json', ...authHeaders() },
116
130
  body: input.body !== undefined ? JSON.stringify(input.body) : undefined,
117
131
  signal: controller.signal,
118
132
  });
@@ -231,7 +245,7 @@ export function createHttpBridge(): ElectronBridge {
231
245
  subscribeChannel<{ chatId: string; agentId?: string | null }>('chat-created', callback),
232
246
 
233
247
  onTaskUpdated: (callback) =>
234
- subscribeChannel<{ chatId: string; taskId: string; status: string }>(
248
+ subscribeChannel<{ chatId: string; taskId: string }>(
235
249
  'task-updated',
236
250
  callback,
237
251
  ),
package/vite.base.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export interface ProductViteConfigOptions {
2
+ /** 产品目录(products/<id>/web 的上一级…即 products/<id>)。 */
3
+ productDir: string;
4
+ /** 产品 flavor(决定品牌 define 与激活包集合)。 */
5
+ flavor: string;
6
+ }
7
+ export declare function createProductViteConfig(options: ProductViteConfigOptions): import("vite").UserConfig;
package/vite.base.js ADDED
@@ -0,0 +1,83 @@
1
+ /**
2
+ * 产品 web 构建的共享 vite 配置工厂(2.3)。
3
+ *
4
+ * 每个产品(products/<id>/web/)有自己的 vite 入口:index.html +
5
+ * main.tsx(静态注册本产品的包渲染层贡献)+ vite.config.ts(调本工厂)。
6
+ * 产品的编译单元只含自己的包——未激活包代码不进 bundle,不依赖树摇
7
+ * 正确性(物理隔离与 node 侧对称)。
8
+ *
9
+ * Electron 加载产物时走 file:// 协议,必须用相对路径,否则资源 404。
10
+ * dev server 跑在固定端口,主进程的 IS_DEV 分支 loadURL('http://localhost:5173')。
11
+ */
12
+ import { defineConfig } from 'vite';
13
+ import react from '@vitejs/plugin-react';
14
+ import tailwindcss from '@tailwindcss/vite';
15
+ import path from 'node:path';
16
+ import { fileURLToPath } from 'node:url';
17
+ import { existsSync, readFileSync } from 'node:fs';
18
+ const HERE = path.dirname(fileURLToPath(import.meta.url));
19
+ export function createProductViteConfig(options) {
20
+ const { productDir, flavor } = options;
21
+ const repoRoot = path.resolve(productDir, '../..');
22
+ // shell 渲染层源码锚到本包自身(3.2 起住在框架仓库
23
+ // packages/agent-shell/web/src),产品经 `@/` 别名引用。
24
+ const webSrcDir = path.resolve(HERE, 'src');
25
+ const readJson = (p) => JSON.parse(readFileSync(p, 'utf8'));
26
+ // 产品品牌(3.1):product.json 的 brand 字段优先(无包产品的品牌
27
+ // 来源);否则取激活包 pack.json 的 brand(0.3g 机制,读
28
+ // products/manifest.json 的 flavor→包映射,第一个带 brand 的包)。
29
+ // 都没有则用 shell 中性默认(Agent Shell)。
30
+ const productJsonPath = path.join(productDir, 'product.json');
31
+ const product = existsSync(productJsonPath) ? readJson(productJsonPath) : {};
32
+ const manifest = readJson(path.join(repoRoot, 'products/manifest.json'));
33
+ let packBrand = null;
34
+ for (const packId of manifest.flavors?.[flavor] ?? []) {
35
+ const pack = readJson(path.join(repoRoot, 'packages', `pack-${packId}`, 'pack.json'));
36
+ if (pack.brand) {
37
+ packBrand = pack.brand;
38
+ break;
39
+ }
40
+ }
41
+ const brand = product.brand ?? packBrand;
42
+ return defineConfig({
43
+ // root 默认取 config 文件所在目录(products/<id>/web)。
44
+ base: './',
45
+ plugins: [react(), tailwindcss()],
46
+ define: {
47
+ // 显式 define 让 flavor 条件在构建期可静态折叠。
48
+ 'import.meta.env.VITE_APP_FLAVOR': JSON.stringify(flavor),
49
+ // 品牌 define:产品/包声明覆盖 shell 中性默认(Agent Shell)。
50
+ // logo 不走 define——资产必须静态 import 才进 bundle,由包 web 模块
51
+ // 在注册时经 setBrandLogoUrl 注入(本包 src/brand.ts)。
52
+ 'import.meta.env.VITE_BRAND_NAME': JSON.stringify(brand?.displayName ?? 'Steerable Shell'),
53
+ 'import.meta.env.VITE_BRAND_TAGLINE': JSON.stringify(brand?.tagline ?? '一款本地桌面 AI 伙伴'),
54
+ 'import.meta.env.VITE_DEFAULT_AGENT_ID': JSON.stringify(brand?.defaultAgentId ?? 'local-assistant'),
55
+ },
56
+ resolve: {
57
+ alias: {
58
+ // shell 渲染层源码(产品入口与包 web 模块都以 `@/` 引用它)。
59
+ '@': webSrcDir,
60
+ },
61
+ },
62
+ // 静态资产(favicon 等中性默认)随 shell web 包分发;产品可在自己的
63
+ // web root 放 public/ 覆盖(vite 不合并双 publicDir——需要产品级资产
64
+ // 时在产品 vite.config 里显式覆盖本字段)。
65
+ publicDir: path.resolve(HERE, 'public'),
66
+ server: {
67
+ port: 5173,
68
+ strictPort: true,
69
+ host: '127.0.0.1',
70
+ // 产品 root 在 products/<id>/web;shell 渲染层源码在框架仓库
71
+ // (3.2 起经 file: 依赖符号链接)——两个根都放行。
72
+ fs: { allow: [repoRoot, path.resolve(webSrcDir, '..')] },
73
+ },
74
+ build: {
75
+ // 产物落在产品目录:products/<id>/web/dist(打包期被 electron-builder
76
+ // 映射为包内 web-dist/)。
77
+ outDir: 'dist',
78
+ emptyOutDir: true,
79
+ sourcemap: true,
80
+ target: 'chrome120',
81
+ },
82
+ });
83
+ }
package/src/brand.test.ts DELETED
@@ -1,22 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { LOCAL_ASSISTANT_AGENT_ID, pickDefaultAgentId } from './brand';
3
-
4
- describe('pickDefaultAgentId', () => {
5
- const catalog = [
6
- { id: LOCAL_ASSISTANT_AGENT_ID },
7
- { id: 'data-analyst' },
8
- { id: 'all-round-assistant' },
9
- ];
10
-
11
- it('returns null when the catalog is empty', () => {
12
- expect(pickDefaultAgentId([])).toBeNull();
13
- });
14
-
15
- it('prefers the build-time default (shell: 电脑操作员) even when it is not first', () => {
16
- expect(pickDefaultAgentId(catalog)).toBe(LOCAL_ASSISTANT_AGENT_ID);
17
- });
18
-
19
- it('falls back to the first visible agent when the build default is absent', () => {
20
- expect(pickDefaultAgentId([{ id: 'writer' }, { id: 'reader' }])).toBe('writer');
21
- });
22
- });