@steerable/agent-shell-web 0.6.48 → 0.6.50
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 +4 -4
- package/src/components/AgentSidebar.tsx +411 -298
- package/src/components/ChatHeader.tsx +74 -4
- package/src/components/chat/ApprovalModal.tsx +8 -0
- package/src/components/chat/ApprovalPromptProvider.tsx +16 -1
- package/src/components/chat/AskUserPromptProvider.tsx +14 -0
- package/src/components/chat/AssistantMessage.tsx +1 -1
- package/src/components/chat/ChatInput.tsx +82 -31
- package/src/components/chat/SuggestedReplies.tsx +5 -2
- package/src/components/chat/TurnFilesCard.tsx +417 -69
- package/src/components/chat/turn-files.ts +273 -0
- package/src/components/settings/PortableSettingsPanel.tsx +493 -0
- package/src/components/settings/PythonRunnerSettingsPanel.tsx +231 -0
- package/src/layouts/AgentLayout.tsx +23 -0
- package/src/lib/electron-bridge.ts +44 -0
- package/src/lib/host-paste.ts +85 -0
- package/src/lib/local-api.ts +18 -0
- package/src/lib/portable.ts +229 -0
- package/src/lib/tauri-bridge.ts +40 -1
- package/src/main.tsx +2 -0
- package/src/pages/AgentPage.tsx +17 -0
- package/src/pages/SettingsPage.tsx +15 -1
- package/src/styles/index.css +29 -0
- package/src/vite-env.d.ts +2 -0
- package/vite.base.js +1 -0
package/src/lib/tauri-bridge.ts
CHANGED
|
@@ -8,7 +8,11 @@
|
|
|
8
8
|
import { invoke } from '@tauri-apps/api/core';
|
|
9
9
|
import { listen, type UnlistenFn } from '@tauri-apps/api/event';
|
|
10
10
|
import html2canvas from 'html2canvas';
|
|
11
|
-
import type {
|
|
11
|
+
import type {
|
|
12
|
+
AppReleaseSnapshot,
|
|
13
|
+
HostBridge,
|
|
14
|
+
PythonRunnerSnapshot,
|
|
15
|
+
} from './electron-bridge';
|
|
12
16
|
import { createHttpBridge } from './http-bridge';
|
|
13
17
|
|
|
14
18
|
type VoidCallback = () => void;
|
|
@@ -38,6 +42,7 @@ export function createTauriBridge(): HostBridge {
|
|
|
38
42
|
const bridge = createHttpBridge();
|
|
39
43
|
const newChatMenu = createMenuSubscription('menu:new-chat');
|
|
40
44
|
const terminalMenu = createMenuSubscription('menu:open-terminal');
|
|
45
|
+
const pasteMenu = createMenuSubscription('menu:paste');
|
|
41
46
|
|
|
42
47
|
return {
|
|
43
48
|
...bridge,
|
|
@@ -85,6 +90,9 @@ export function createTauriBridge(): HostBridge {
|
|
|
85
90
|
offMenuNewChat: newChatMenu.off,
|
|
86
91
|
onMenuOpenTerminal: terminalMenu.on,
|
|
87
92
|
offMenuOpenTerminal: terminalMenu.off,
|
|
93
|
+
onMenuPaste: pasteMenu.on,
|
|
94
|
+
offMenuPaste: pasteMenu.off,
|
|
95
|
+
readClipboardText: () => invoke<string>('host_read_clipboard_text'),
|
|
88
96
|
app: {
|
|
89
97
|
snapshot: () => invoke<AppReleaseSnapshot>('app_release_snapshot'),
|
|
90
98
|
check: () => invoke<AppReleaseSnapshot>('app_release_check'),
|
|
@@ -106,6 +114,37 @@ export function createTauriBridge(): HostBridge {
|
|
|
106
114
|
};
|
|
107
115
|
},
|
|
108
116
|
},
|
|
117
|
+
pythonRunner: {
|
|
118
|
+
snapshot: () => invoke<PythonRunnerSnapshot>('python_runner_snapshot'),
|
|
119
|
+
download: (url) =>
|
|
120
|
+
invoke<PythonRunnerSnapshot>('python_runner_download', {
|
|
121
|
+
url: url ?? null,
|
|
122
|
+
}),
|
|
123
|
+
cancel: () => invoke<PythonRunnerSnapshot>('python_runner_cancel'),
|
|
124
|
+
pickLocal: () => invoke<string | null>('python_runner_pick_local'),
|
|
125
|
+
useLocal: (path) =>
|
|
126
|
+
invoke<PythonRunnerSnapshot>('python_runner_use_local', { path }),
|
|
127
|
+
useDefault: () =>
|
|
128
|
+
invoke<PythonRunnerSnapshot>('python_runner_use_default'),
|
|
129
|
+
restart: () => invoke<void>('python_runner_restart'),
|
|
130
|
+
onState(callback) {
|
|
131
|
+
let unlisten: UnlistenFn | undefined;
|
|
132
|
+
let cancelled = false;
|
|
133
|
+
const pending = listen<PythonRunnerSnapshot>(
|
|
134
|
+
'python-runner-state',
|
|
135
|
+
(event) => callback(event.payload),
|
|
136
|
+
);
|
|
137
|
+
void pending.then((stop) => {
|
|
138
|
+
if (cancelled) stop();
|
|
139
|
+
else unlisten = stop;
|
|
140
|
+
});
|
|
141
|
+
return () => {
|
|
142
|
+
cancelled = true;
|
|
143
|
+
if (unlisten) unlisten();
|
|
144
|
+
else void pending.then((stop) => stop());
|
|
145
|
+
};
|
|
146
|
+
},
|
|
147
|
+
},
|
|
109
148
|
};
|
|
110
149
|
}
|
|
111
150
|
|
package/src/main.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import { SettingsPage } from './pages/SettingsPage';
|
|
|
8
8
|
import { getPackRoutes } from './packs/registry';
|
|
9
9
|
import { getBrandLogoUrl, BRAND_NAME } from './brand';
|
|
10
10
|
import { getAppShellGate } from './auth/gate';
|
|
11
|
+
import { installHostPaste } from './lib/host-paste';
|
|
11
12
|
import './styles/index.css';
|
|
12
13
|
|
|
13
14
|
// 浏览器 dev mock 的安装在 bootstrap() 开头(动态 import + DEV 门)。
|
|
@@ -98,6 +99,7 @@ export async function bootstrap(): Promise<void> {
|
|
|
98
99
|
// (品牌 logo 由包经 setBrandLogoUrl 注入,见 brand.ts)。
|
|
99
100
|
document.title = BRAND_NAME;
|
|
100
101
|
document.querySelector<HTMLLinkElement>('link[rel="icon"]')?.setAttribute('href', getBrandLogoUrl());
|
|
102
|
+
installHostPaste();
|
|
101
103
|
|
|
102
104
|
const rootEl = document.getElementById('root');
|
|
103
105
|
if (!rootEl) {
|
package/src/pages/AgentPage.tsx
CHANGED
|
@@ -1042,6 +1042,22 @@ function AgentChatView({
|
|
|
1042
1042
|
];
|
|
1043
1043
|
}, [messages, remoteContent, chatId]);
|
|
1044
1044
|
const effectiveIsStreaming = isStreaming || remoteStreaming;
|
|
1045
|
+
|
|
1046
|
+
useEffect(() => {
|
|
1047
|
+
if (!chatId) return;
|
|
1048
|
+
window.dispatchEvent(
|
|
1049
|
+
new CustomEvent("chat:streaming-change", {
|
|
1050
|
+
detail: { chatId, isStreaming: effectiveIsStreaming },
|
|
1051
|
+
}),
|
|
1052
|
+
);
|
|
1053
|
+
return () => {
|
|
1054
|
+
window.dispatchEvent(
|
|
1055
|
+
new CustomEvent("chat:streaming-change", {
|
|
1056
|
+
detail: { chatId, isStreaming: false },
|
|
1057
|
+
}),
|
|
1058
|
+
);
|
|
1059
|
+
};
|
|
1060
|
+
}, [chatId, effectiveIsStreaming]);
|
|
1045
1061
|
const effectiveCurrentTurnActions: ExecutedAction[] = remoteStreaming
|
|
1046
1062
|
? ((liveStream.executedActions as ExecutedAction[] | undefined) ?? [])
|
|
1047
1063
|
: currentTurnActions;
|
|
@@ -1101,6 +1117,7 @@ function AgentChatView({
|
|
|
1101
1117
|
chatSlots={ctx.chatSlots}
|
|
1102
1118
|
rightPanel={ctx.rightPanel}
|
|
1103
1119
|
onToggleChatSlot={ctx.onToggleChatSlot}
|
|
1120
|
+
onToggleRightPanel={ctx.onToggleChatSlot}
|
|
1104
1121
|
/>
|
|
1105
1122
|
}
|
|
1106
1123
|
onRegenerate={
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { useRef, useState } from 'react';
|
|
2
|
-
import { LuActivity, LuBlocks, LuBot, LuChartBar, LuMonitor, LuNetwork, LuPlug, LuSearch, LuSettings, LuShieldCheck } from 'react-icons/lu';
|
|
2
|
+
import { LuActivity, LuBlocks, LuBot, LuChartBar, LuDownload, LuMonitor, LuNetwork, LuPlug, LuSearch, LuSettings, LuShieldCheck } from 'react-icons/lu';
|
|
3
3
|
import { useOutletContext, useSearchParams } from 'react-router-dom';
|
|
4
4
|
import { isElectron } from '@/lib/electron-bridge';
|
|
5
5
|
import { AgentsSettingsPanel } from '@/components/settings/AgentsSettingsPanel';
|
|
6
6
|
import { AppearanceSettingsPanel } from '@/components/settings/AppearanceSettingsPanel';
|
|
7
7
|
import { AppUpdateSettingsPanel } from '@/components/settings/AppUpdateSettingsPanel';
|
|
8
|
+
import { PortableSettingsPanel } from '@/components/settings/PortableSettingsPanel';
|
|
9
|
+
import { PythonRunnerSettingsPanel } from '@/components/settings/PythonRunnerSettingsPanel';
|
|
8
10
|
import { DiagnoseSettingsPanel } from '@/components/settings/DiagnoseSettingsPanel';
|
|
9
11
|
import { InsightsSettingsPanel } from '@/components/settings/InsightsSettingsPanel';
|
|
10
12
|
import {
|
|
@@ -21,6 +23,7 @@ import { UsagePanel } from '@/components/settings/UsagePanel';
|
|
|
21
23
|
import { WebSearchSettingsPanel } from '@/components/settings/WebSearchSettingsPanel';
|
|
22
24
|
import { getPackSettingsPanels } from '@/packs/registry';
|
|
23
25
|
import { settingsChrome } from '@/lib/host-tools';
|
|
26
|
+
import { isPortableEnabled } from '@/lib/portable';
|
|
24
27
|
import type { AgentOutletContext } from '@/layouts/AgentLayout';
|
|
25
28
|
|
|
26
29
|
type SettingsSection = 'skills' | 'mcp' | 'agents' | 'general';
|
|
@@ -218,6 +221,17 @@ export function SettingsPage() {
|
|
|
218
221
|
</section>
|
|
219
222
|
))}
|
|
220
223
|
|
|
224
|
+
{isPortableEnabled() && (
|
|
225
|
+
<section className="space-y-2" data-testid="settings-section-portable">
|
|
226
|
+
<h2 className="flex items-center gap-1.5 text-xs font-semibold text-agent-foreground">
|
|
227
|
+
<LuDownload className="h-3.5 w-3.5 text-agent-muted-foreground" />
|
|
228
|
+
备份与迁移
|
|
229
|
+
</h2>
|
|
230
|
+
<PortableSettingsPanel />
|
|
231
|
+
</section>
|
|
232
|
+
)}
|
|
233
|
+
|
|
234
|
+
<PythonRunnerSettingsPanel />
|
|
221
235
|
<AppUpdateSettingsPanel />
|
|
222
236
|
</>
|
|
223
237
|
)}
|
package/src/styles/index.css
CHANGED
|
@@ -164,3 +164,32 @@ body {
|
|
|
164
164
|
.chat-input-surface:has(.chat-input-editor[data-composing]) .chat-input-mirror {
|
|
165
165
|
visibility: hidden;
|
|
166
166
|
}
|
|
167
|
+
|
|
168
|
+
/*
|
|
169
|
+
* Thin scrollbars everywhere. The system "always show" bar is about 15px.
|
|
170
|
+
* Kept in the base layer so a utility can still hide a scrollbar.
|
|
171
|
+
*/
|
|
172
|
+
@layer base {
|
|
173
|
+
* {
|
|
174
|
+
scrollbar-width: thin;
|
|
175
|
+
scrollbar-color: color-mix(in oklab, var(--color-agent-foreground) 28%, transparent) transparent;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
*::-webkit-scrollbar {
|
|
179
|
+
width: 6px;
|
|
180
|
+
height: 6px;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
*::-webkit-scrollbar-track {
|
|
184
|
+
background: transparent;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
*::-webkit-scrollbar-thumb {
|
|
188
|
+
background: color-mix(in oklab, var(--color-agent-foreground) 28%, transparent);
|
|
189
|
+
border-radius: 999px;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
*::-webkit-scrollbar-thumb:hover {
|
|
193
|
+
background: color-mix(in oklab, var(--color-agent-foreground) 45%, transparent);
|
|
194
|
+
}
|
|
195
|
+
}
|
package/src/vite-env.d.ts
CHANGED
package/vite.base.js
CHANGED
|
@@ -58,6 +58,7 @@ export function createProductViteConfig(options) {
|
|
|
58
58
|
'import.meta.env.VITE_APPROVAL': JSON.stringify(product.approval ?? 'host'),
|
|
59
59
|
'import.meta.env.VITE_CHAT_MODES': JSON.stringify(JSON.stringify(product.chatModes ?? ['agent', 'plan'])),
|
|
60
60
|
'import.meta.env.VITE_SETTINGS': JSON.stringify(JSON.stringify(product.settings ?? {})),
|
|
61
|
+
'import.meta.env.VITE_PORTABLE': JSON.stringify(product.portable === true ? 'true' : 'false'),
|
|
61
62
|
},
|
|
62
63
|
resolve: {
|
|
63
64
|
alias: {
|