@steerable/agent-shell-web 0.6.56 → 0.6.57

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steerable/agent-shell-web",
3
- "version": "0.6.56",
3
+ "version": "0.6.57",
4
4
  "type": "module",
5
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",
@@ -45,8 +45,8 @@
45
45
  "react-router-dom": "^6.30.0",
46
46
  "rehype-raw": "^7.0.0",
47
47
  "remark-gfm": "^4.0.1",
48
- "@steerable/agent-ui": "0.6.56",
49
- "@steerable/agent-protocol": "0.6.56"
48
+ "@steerable/agent-ui": "0.6.57",
49
+ "@steerable/agent-protocol": "0.6.57"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@tailwindcss/vite": "^4.3.0",
@@ -59,7 +59,7 @@
59
59
  "typescript": "^5.8.3",
60
60
  "vite": "^5.4.21",
61
61
  "vitest": "^3.2.4",
62
- "@steerable/pack-sdk": "0.6.56"
62
+ "@steerable/pack-sdk": "0.6.57"
63
63
  },
64
64
  "scripts": {
65
65
  "gen": "echo agent-shell-web",
@@ -0,0 +1,67 @@
1
+ import { useState } from 'react';
2
+ import { LuLoader, LuTerminal } from 'react-icons/lu';
3
+ import { t } from '@/i18n';
4
+ import { installCommandLineTool } from '@/lib/local-api';
5
+
6
+ export function CliInstallSettingsPanel(props: {
7
+ binName: string;
8
+ install?: () => Promise<{ path: string; onPath: boolean }>;
9
+ }) {
10
+ const install = props.install ?? (() => installCommandLineTool(props.binName));
11
+ const [running, setRunning] = useState(false);
12
+ const [message, setMessage] = useState<string | null>(null);
13
+ const [error, setError] = useState<string | null>(null);
14
+
15
+ const onClick = async () => {
16
+ setRunning(true);
17
+ setMessage(null);
18
+ setError(null);
19
+ try {
20
+ const result = await install();
21
+ setMessage(result.onPath
22
+ ? t('Installed {path}', { path: result.path })
23
+ : t('Installed {path}. Add its directory to PATH.', { path: result.path }));
24
+ } catch (err) {
25
+ setError(err instanceof Error ? err.message : String(err));
26
+ } finally {
27
+ setRunning(false);
28
+ }
29
+ };
30
+
31
+ return (
32
+ <div className="space-y-2 rounded-agent-md border border-agent-border bg-agent-card p-2.5" data-testid="cli-install-settings">
33
+ <p className="text-xs text-agent-muted-foreground">
34
+ {t('Install the command-line tool on your PATH so you can run it from a terminal.')}
35
+ </p>
36
+ <button
37
+ type="button"
38
+ data-testid="cli-install-button"
39
+ onClick={() => void onClick()}
40
+ disabled={running}
41
+ className="inline-flex items-center gap-1.5 rounded-agent-md bg-agent-primary px-3 py-1.5 text-xs font-medium text-agent-primary-foreground transition hover:bg-agent-primary/90 disabled:opacity-50"
42
+ >
43
+ {running ? (
44
+ <>
45
+ <LuLoader className="h-3.5 w-3.5 animate-spin" />
46
+ {t('Installing…')}
47
+ </>
48
+ ) : (
49
+ <>
50
+ <LuTerminal className="h-3.5 w-3.5" />
51
+ {t('Install command-line tool')}
52
+ </>
53
+ )}
54
+ </button>
55
+ {message && (
56
+ <p data-testid="cli-install-message" className="text-xs text-agent-foreground">
57
+ {message}
58
+ </p>
59
+ )}
60
+ {error && (
61
+ <p data-testid="cli-install-error" className="text-xs text-agent-destructive">
62
+ {t('Install failed: {error}', { error })}
63
+ </p>
64
+ )}
65
+ </div>
66
+ );
67
+ }
@@ -188,6 +188,14 @@ function AgentLayoutContent() {
188
188
  });
189
189
  return unsubscribe;
190
190
  }, []);
191
+ useEffect(() => {
192
+ const bridge = getHostBridge();
193
+ if (!bridge?.onStoreChanged) return;
194
+ const unsubscribe = bridge.onStoreChanged(() => {
195
+ void refreshChatsRef.current();
196
+ });
197
+ return unsubscribe;
198
+ }, []);
191
199
  useEffect(() => {
192
200
  const onImported = () => {
193
201
  void refreshChatsRef.current();
@@ -239,6 +239,11 @@ export interface HostBridge {
239
239
  onChatCreated?: (
240
240
  callback: (payload: { chatId: string; agentId?: string | null }) => void,
241
241
  ) => () => void;
242
+ /**
243
+ * 另一个进程提交了宿主库。侧栏据此重新拉会话列表。
244
+ * 载荷为空;渲染端不依赖里面的字段。
245
+ */
246
+ onStoreChanged?: (callback: () => void) => () => void;
242
247
  /**
243
248
  * 4.6a 后台任务状态推送。任务到达终态或 worktree 合并/丢弃完成时主进程
244
249
  * 广播;载荷只有 chatId/taskId,面板收到后重新拉列表。
@@ -266,6 +266,8 @@ export function createHttpBridge(): HostBridge {
266
266
  onChatCreated: (callback) =>
267
267
  subscribeChannel<{ chatId: string; agentId?: string | null }>('chat-created', callback),
268
268
 
269
+ onStoreChanged: (callback) => subscribeChannel('store:changed', () => callback()),
270
+
269
271
  onTaskUpdated: (callback) =>
270
272
  subscribeChannel<{ chatId: string; taskId: string }>(
271
273
  'task-updated',
@@ -767,6 +767,14 @@ export interface DiagnoseResult {
767
767
  hint: string | null;
768
768
  }
769
769
 
770
+ export async function installCommandLineTool(name: string) {
771
+ return bridge().localBackend.request<{ path: string; onPath: boolean }>({
772
+ method: 'POST',
773
+ path: '/api/v2/cli/install',
774
+ body: { name },
775
+ });
776
+ }
777
+
770
778
  export async function diagnoseLlmConnection(input: {
771
779
  baseUrl?: string;
772
780
  apiKey?: string;