minimal-agent 0.18.13 → 0.18.14
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 +1 -3
- package/plugins/workflow-runner/src/runtime/context.js +1 -1
- package/plugins/workflow-runner/src/runtime/context.ts +1 -1
- package/plugins/workflow-runner/test/embeddedExecution.test.ts +2 -5
- package/plugins/workflow-runner/test/execLifetime.test.ts +15 -2
- package/skills/ssh-remote-dev/SKILL.md +61 -0
- package/skills/ssh-remote-dev/agents/openai.yaml +4 -0
- package/src/advisor/README.md +62 -24
- package/src/advisor/advisorNudge.js +199 -0
- package/src/advisor/advisorNudge.ts +232 -0
- package/src/advisor/deliveryReview.js +35 -12
- package/src/advisor/deliveryReview.ts +35 -11
- package/src/advisor/presentation.js +7 -10
- package/src/advisor/presentation.ts +10 -13
- package/src/advisor/reviewContext.js +22 -58
- package/src/advisor/reviewContext.ts +24 -67
- package/src/cli/configMenu.js +17 -128
- package/src/cli/configMenu.tsx +17 -193
- package/src/cli/print.js +2 -0
- package/src/cli/print.ts +2 -0
- package/src/cli/streamJson.js +2 -0
- package/src/cli/streamJson.ts +2 -0
- package/src/cli/wizards/advisorWizard.js +9 -7
- package/src/cli/wizards/advisorWizard.tsx +9 -7
- package/src/cli/wizards/contextAdvisorWizard.js +9 -7
- package/src/cli/wizards/contextAdvisorWizard.tsx +9 -7
- package/src/cli/wizards/providerPresets.js +27 -1
- package/src/cli/wizards/providerPresets.ts +44 -2
- package/src/cli/wizards/providerWizard.js +51 -10
- package/src/cli/wizards/providerWizard.tsx +59 -9
- package/src/config/configDefaults.js +1 -1
- package/src/config/configDefaults.ts +1 -1
- package/src/config/configDiagnostics.js +1 -21
- package/src/config/configDiagnostics.ts +3 -23
- package/src/config/configFile.js +11 -4
- package/src/config/configFile.ts +27 -7
- package/src/config/configManagement.js +1 -0
- package/src/config/configManagement.ts +2 -0
- package/src/config/configService.js +12 -8
- package/src/config/configService.ts +16 -11
- package/src/config/numericLimits.js +0 -4
- package/src/config/numericLimits.ts +0 -4
- package/src/config/reasoningEffort.js +16 -0
- package/src/config/reasoningEffort.ts +18 -0
- package/src/context/budgetPlan.js +1 -1
- package/src/context/budgetPlan.ts +1 -1
- package/src/context/optimizeConversation.js +1 -1
- package/src/context/optimizeConversation.ts +1 -1
- package/src/harness/stallGuard.js +8 -13
- package/src/harness/stallGuard.ts +8 -12
- package/src/llm/client.js +64 -17
- package/src/llm/client.ts +62 -7
- package/src/llm/providers/openaiFormat.js +14 -3
- package/src/llm/providers/openaiFormat.ts +17 -3
- package/src/llm/providers/responsesFormat.js +275 -0
- package/src/llm/providers/responsesFormat.ts +306 -0
- package/src/loop/README.md +18 -3
- package/src/loop/liveDiagramGate.js +63 -0
- package/src/loop/liveDiagramGate.ts +61 -0
- package/src/loop/messages.js +12 -0
- package/src/loop/messages.ts +13 -0
- package/src/loop/options.ts +7 -2
- package/src/loop/toolBatch.js +0 -1
- package/src/loop/toolBatch.ts +0 -1
- package/src/loop/toolExecutor.js +11 -46
- package/src/loop/toolExecutor.ts +12 -55
- package/src/loop/toolPresentation.js +2 -13
- package/src/loop/toolPresentation.ts +2 -13
- package/src/loop/toolSemantics.js +3 -4
- package/src/loop/toolSemantics.ts +4 -6
- package/src/loop.js +222 -214
- package/src/loop.ts +226 -232
- package/src/memory/dependencies.js +11 -3
- package/src/memory/dependencies.ts +11 -3
- package/src/memory/episodicMemory.js +59 -18
- package/src/memory/episodicMemory.ts +58 -18
- package/src/memory/experienceStore.js +4 -3
- package/src/memory/experienceStore.ts +4 -3
- package/src/memory/factCandidates.js +53 -1
- package/src/memory/factCandidates.ts +54 -1
- package/src/memory/factLearning.js +2 -2
- package/src/memory/factLearning.ts +2 -2
- package/src/memory/jobPolicy.js +24 -5
- package/src/memory/jobPolicy.ts +25 -5
- package/src/memory/learning.js +2 -2
- package/src/memory/learning.ts +2 -2
- package/src/memory/learningModel.js +7 -0
- package/src/memory/learningModel.ts +7 -0
- package/src/memory/managementService.js +8 -7
- package/src/memory/managementService.ts +16 -8
- package/src/memory/memoryService.js +104 -33
- package/src/memory/memoryService.ts +132 -28
- package/src/memory/projectKnowledge.js +39 -3
- package/src/memory/projectKnowledge.ts +45 -3
- package/src/memory/recallQuery.js +56 -0
- package/src/memory/recallQuery.ts +58 -0
- package/src/memory/retrieval.js +39 -10
- package/src/memory/retrieval.ts +46 -11
- package/src/memory/turnJournal.js +75 -10
- package/src/memory/turnJournal.ts +66 -10
- package/src/memory/types.ts +7 -1
- package/src/prompts/delegation.js +2 -1
- package/src/prompts/delegation.ts +3 -1
- package/src/prompts/policyRegistry.js +9 -12
- package/src/prompts/policyRegistry.ts +9 -12
- package/src/prompts/promptAssembly.js +6 -5
- package/src/prompts/promptAssembly.ts +8 -6
- package/src/prompts/visualPresentation.js +39 -10
- package/src/prompts/visualPresentation.ts +38 -9
- package/src/runtime/answerPreparation.js +1 -1
- package/src/runtime/answerPreparation.ts +1 -1
- package/src/runtime/fileLock.js +19 -3
- package/src/runtime/fileLock.ts +19 -3
- package/src/runtime/invocationPolicy.js +1 -1
- package/src/runtime/invocationPolicy.ts +1 -1
- package/src/runtime/outputContract.js +0 -4
- package/src/runtime/outputContract.ts +0 -7
- package/src/session/runAgentTurn.js +3 -0
- package/src/session/runAgentTurn.ts +3 -0
- package/src/team/onlineToolContract.js +0 -1
- package/src/team/onlineToolContract.ts +0 -1
- package/src/tools/advisor/advisor.js +207 -365
- package/src/tools/advisor/advisor.ts +211 -383
- package/src/tools/agent/agentTypes.js +0 -1
- package/src/tools/agent/agentTypes.ts +0 -1
- package/src/tools/agent/coordinator.js +4 -1
- package/src/tools/agent/coordinator.ts +4 -1
- package/src/tools/bash/semantics.js +4 -5
- package/src/tools/bash/semantics.ts +4 -5
- package/src/tools/capabilities.js +2 -3
- package/src/tools/capabilities.ts +2 -4
- package/src/tools/index.js +0 -16
- package/src/tools/index.ts +0 -16
- package/src/tools/memory/maintenance.js +8 -9
- package/src/tools/memory/maintenance.ts +13 -11
- package/src/tools/memory/memory.js +5 -1
- package/src/tools/memory/memory.ts +5 -0
- package/src/tools/optimizeConversation/README.md +4 -6
- package/src/tools/toolPromptGuides.js +2 -9
- package/src/tools/toolPromptGuides.ts +2 -9
- package/src/types.ts +28 -105
- package/src/ui/App.js +2 -0
- package/src/ui/App.tsx +1 -0
- package/src/ui/MessageList.js +8 -44
- package/src/ui/MessageList.tsx +3 -81
- package/src/ui/hooks/useChat.js +2 -0
- package/src/ui/hooks/useChat.ts +2 -0
- package/src/ui/toolProgress.js +1 -1
- package/src/ui/toolProgress.ts +1 -1
- package/src/web/protocol.ts +10 -3
- package/src/advisor/advisorCoordinator.js +0 -734
- package/src/advisor/advisorCoordinator.ts +0 -825
- package/src/cli/wizards/sshHostWizard.js +0 -156
- package/src/cli/wizards/sshHostWizard.tsx +0 -214
- package/src/context/sshHosts.js +0 -290
- package/src/context/sshHosts.ts +0 -312
- package/src/loop/publication.js +0 -94
- package/src/loop/publication.ts +0 -124
- package/src/runtime/finalAnswer.js +0 -9
- package/src/runtime/finalAnswer.ts +0 -13
- package/src/tools/advisor/advisorDecision.js +0 -79
- package/src/tools/advisor/advisorDecision.ts +0 -92
- package/src/tools/ssh/ssh.js +0 -152
- package/src/tools/ssh/ssh.ts +0 -167
- package/src/tools/ssh/sshAvailability.js +0 -35
- package/src/tools/ssh/sshAvailability.ts +0 -39
- package/src/tools/ssh/sshClient.js +0 -177
- package/src/tools/ssh/sshClient.ts +0 -189
- package/src/tools/ssh/sshDownload.js +0 -77
- package/src/tools/ssh/sshDownload.ts +0 -92
- package/src/tools/ssh/sshHostsTool.js +0 -36
- package/src/tools/ssh/sshHostsTool.ts +0 -48
- package/src/tools/ssh/sshUpload.js +0 -72
- package/src/tools/ssh/sshUpload.ts +0 -85
package/src/cli/configMenu.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text, useInput } from 'ink';
|
|
3
3
|
import { useCallback, useEffect, useState } from 'react';
|
|
4
|
-
import { testAdvisorConnection, testConfiguredModel,
|
|
4
|
+
import { testAdvisorConnection, testConfiguredModel, testToolConnection, } from '../config/configDiagnostics.js';
|
|
5
5
|
import { configService } from '../config/configService.js';
|
|
6
|
-
import { getWorkingDir } from '../bootstrap/workingDir.js';
|
|
7
|
-
import { listSshHosts, removeSshHost, setDefaultSshHost, } from '../context/sshHosts.js';
|
|
8
|
-
import { workspaceIndexService } from '../context/workspaceIndex.js';
|
|
9
6
|
import { applyNetworkProxy } from '../network/proxy.js';
|
|
10
7
|
import { AgentRuntimeWizard } from './wizards/agentRuntimeWizard.js';
|
|
11
8
|
import { BrowserWizard } from './wizards/browserWizard.js';
|
|
@@ -14,11 +11,9 @@ import { ImageWizard } from './wizards/imageWizard.js';
|
|
|
14
11
|
import { OpenRouterWizard } from './wizards/openRouterWizard.js';
|
|
15
12
|
import { ProviderWizard } from './wizards/providerWizard.js';
|
|
16
13
|
import { SearchWizard } from './wizards/searchWizard.js';
|
|
17
|
-
import { SshHostWizard } from './wizards/sshHostWizard.js';
|
|
18
14
|
import { TtsWizard } from './wizards/ttsWizard.js';
|
|
19
15
|
import { NetworkProxyWizard } from './wizards/networkProxyWizard.js';
|
|
20
|
-
const MAIN = ['模型与上下文', '工具与代理', '
|
|
21
|
-
const SSH_HOST_ACTIONS = ['编辑', '测试连接', '设为默认主机', '删除', '返回'];
|
|
16
|
+
const MAIN = ['模型与上下文', '工具与代理', '网络与 VPN 代理', '浏览器', '完成并返回聊天'];
|
|
22
17
|
const MODEL_CONTEXT = ['模型管理', '压缩与顾问', '测试顾问连接', '返回'];
|
|
23
18
|
const TOOLS = [
|
|
24
19
|
'电脑操作与子代理',
|
|
@@ -48,34 +43,15 @@ export function ConfigMenu({ onDone }) {
|
|
|
48
43
|
const [editingModelId, setEditingModelId] = useState(null);
|
|
49
44
|
const [message, setMessage] = useState(null);
|
|
50
45
|
const [busy, setBusy] = useState(false);
|
|
51
|
-
const [sshWorkspaceId, setSshWorkspaceId] = useState(null);
|
|
52
|
-
const [sshHosts, setSshHosts] = useState(null);
|
|
53
|
-
const [editingSshAlias, setEditingSshAlias] = useState(null);
|
|
54
46
|
const refresh = useCallback(async () => {
|
|
55
47
|
const snapshot = await configService.reload();
|
|
56
48
|
applyNetworkProxy(snapshot.config?.networkProxy);
|
|
57
49
|
setConfig(snapshot.config);
|
|
58
50
|
setReadOnly(snapshot.readOnly);
|
|
59
51
|
}, []);
|
|
60
|
-
const refreshSshHosts = useCallback(async (workspaceId) => {
|
|
61
|
-
setSshHosts(await listSshHosts(workspaceId));
|
|
62
|
-
}, []);
|
|
63
52
|
useEffect(() => {
|
|
64
53
|
void refresh();
|
|
65
|
-
|
|
66
|
-
// 保证 /config 里编辑的主机和 SSH 工具运行时读到的是同一份数据。找不到(从未
|
|
67
|
-
// 注册过)就注册一次——能走到这里说明用户已经在一个真实交互会话里,不是
|
|
68
|
-
// e2e/cron 那类刻意排除的临时目录。
|
|
69
|
-
void (async () => {
|
|
70
|
-
const cwd = getWorkingDir();
|
|
71
|
-
const found = await workspaceIndexService.findByPath(cwd).catch(() => null);
|
|
72
|
-
const workspace = found ?? await workspaceIndexService.register(cwd).catch(() => null);
|
|
73
|
-
if (!workspace)
|
|
74
|
-
return;
|
|
75
|
-
setSshWorkspaceId(workspace.id);
|
|
76
|
-
await refreshSshHosts(workspace.id);
|
|
77
|
-
})();
|
|
78
|
-
}, [refresh, refreshSshHosts]);
|
|
54
|
+
}, [refresh]);
|
|
79
55
|
const navigate = (next) => {
|
|
80
56
|
setIndex(0);
|
|
81
57
|
setMessage(null);
|
|
@@ -98,27 +74,6 @@ export function ConfigMenu({ onDone }) {
|
|
|
98
74
|
setBusy(false);
|
|
99
75
|
}
|
|
100
76
|
}, [refresh]);
|
|
101
|
-
const mutateSsh = useCallback(async (operation, success) => {
|
|
102
|
-
if (!sshWorkspaceId) {
|
|
103
|
-
setMessage('无法确定当前工作区');
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
setBusy(true);
|
|
107
|
-
setMessage(null);
|
|
108
|
-
try {
|
|
109
|
-
await operation();
|
|
110
|
-
await refreshSshHosts(sshWorkspaceId);
|
|
111
|
-
setMessage(success);
|
|
112
|
-
return true;
|
|
113
|
-
}
|
|
114
|
-
catch (error) {
|
|
115
|
-
setMessage(error.message || '操作失败');
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
118
|
-
finally {
|
|
119
|
-
setBusy(false);
|
|
120
|
-
}
|
|
121
|
-
}, [sshWorkspaceId, refreshSshHosts]);
|
|
122
77
|
useInput((input, key) => {
|
|
123
78
|
if (busy ||
|
|
124
79
|
[
|
|
@@ -131,7 +86,6 @@ export function ConfigMenu({ onDone }) {
|
|
|
131
86
|
'tts',
|
|
132
87
|
'network-proxy',
|
|
133
88
|
'browser',
|
|
134
|
-
'ssh-host-wizard',
|
|
135
89
|
].includes(screen))
|
|
136
90
|
return;
|
|
137
91
|
const back = () => {
|
|
@@ -145,10 +99,6 @@ export function ConfigMenu({ onDone }) {
|
|
|
145
99
|
navigate('models');
|
|
146
100
|
else if (screen === 'tools')
|
|
147
101
|
navigate('main');
|
|
148
|
-
else if (screen === 'ssh-hosts')
|
|
149
|
-
navigate('main');
|
|
150
|
-
else if (screen === 'ssh-host-actions' || screen === 'delete-ssh-host')
|
|
151
|
-
navigate('ssh-hosts');
|
|
152
102
|
};
|
|
153
103
|
if (key.escape || (key.ctrl && input === 'c')) {
|
|
154
104
|
back();
|
|
@@ -164,11 +114,7 @@ export function ConfigMenu({ onDone }) {
|
|
|
164
114
|
? MODEL_ACTIONS.length
|
|
165
115
|
: screen === 'models'
|
|
166
116
|
? (config?.models.length ?? 0) + 1
|
|
167
|
-
:
|
|
168
|
-
? (sshHosts?.hosts.length ?? 0) + 1
|
|
169
|
-
: screen === 'ssh-host-actions'
|
|
170
|
-
? SSH_HOST_ACTIONS.length
|
|
171
|
-
: 1;
|
|
117
|
+
: 1;
|
|
172
118
|
if (key.upArrow) {
|
|
173
119
|
setIndex((value) => (value - 1 + length) % length);
|
|
174
120
|
return;
|
|
@@ -187,14 +133,6 @@ export function ConfigMenu({ onDone }) {
|
|
|
187
133
|
});
|
|
188
134
|
return;
|
|
189
135
|
}
|
|
190
|
-
if (screen === 'delete-ssh-host') {
|
|
191
|
-
if (key.return && sshWorkspaceId && editingSshAlias)
|
|
192
|
-
void mutateSsh(() => removeSshHost(sshWorkspaceId, editingSshAlias), '主机已删除').then((ok) => {
|
|
193
|
-
if (ok)
|
|
194
|
-
navigate('ssh-hosts');
|
|
195
|
-
});
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
136
|
if (screen === 'tools' &&
|
|
199
137
|
(input === 'd' || input === 't') &&
|
|
200
138
|
index >= 1 &&
|
|
@@ -218,44 +156,12 @@ export function ConfigMenu({ onDone }) {
|
|
|
218
156
|
else if (index === 1)
|
|
219
157
|
navigate('tools');
|
|
220
158
|
else if (index === 2)
|
|
221
|
-
navigate('ssh-hosts');
|
|
222
|
-
else if (index === 3)
|
|
223
159
|
navigate('network-proxy');
|
|
224
|
-
else if (index ===
|
|
160
|
+
else if (index === 3)
|
|
225
161
|
navigate('browser');
|
|
226
162
|
else
|
|
227
163
|
onDone();
|
|
228
164
|
}
|
|
229
|
-
else if (screen === 'ssh-hosts') {
|
|
230
|
-
const hosts = sshHosts?.hosts ?? [];
|
|
231
|
-
if (index === hosts.length) {
|
|
232
|
-
setEditingSshAlias(null);
|
|
233
|
-
navigate('ssh-host-wizard');
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
setEditingSshAlias(hosts[index]?.alias ?? null);
|
|
237
|
-
navigate('ssh-host-actions');
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
else if (screen === 'ssh-host-actions' && sshWorkspaceId && editingSshAlias) {
|
|
241
|
-
const host = sshHosts?.hosts.find((entry) => entry.alias === editingSshAlias);
|
|
242
|
-
if (!host)
|
|
243
|
-
return;
|
|
244
|
-
if (index === 0)
|
|
245
|
-
navigate('ssh-host-wizard');
|
|
246
|
-
else if (index === 1)
|
|
247
|
-
void mutateSsh(async () => {
|
|
248
|
-
const result = await testSshHostConnection(sshWorkspaceId, editingSshAlias);
|
|
249
|
-
if (!result.ok)
|
|
250
|
-
throw new Error(result.message);
|
|
251
|
-
}, '连接正常');
|
|
252
|
-
else if (index === 2)
|
|
253
|
-
void mutateSsh(() => setDefaultSshHost(sshWorkspaceId, editingSshAlias), '已设为默认主机');
|
|
254
|
-
else if (index === 3)
|
|
255
|
-
navigate('delete-ssh-host');
|
|
256
|
-
else
|
|
257
|
-
navigate('ssh-hosts');
|
|
258
|
-
}
|
|
259
165
|
else if (screen === 'model-context') {
|
|
260
166
|
if (index === 0)
|
|
261
167
|
navigate('models');
|
|
@@ -336,22 +242,18 @@ export function ConfigMenu({ onDone }) {
|
|
|
336
242
|
? 'models'
|
|
337
243
|
: screen === 'context-advisor'
|
|
338
244
|
? 'model-context'
|
|
339
|
-
: screen === '
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
? 'tools'
|
|
351
|
-
: 'main');
|
|
245
|
+
: screen === 'browser' ||
|
|
246
|
+
screen === 'tools' ||
|
|
247
|
+
screen === 'network-proxy'
|
|
248
|
+
? 'main'
|
|
249
|
+
: screen === 'agent-runtime' ||
|
|
250
|
+
screen === 'search' ||
|
|
251
|
+
screen === 'image' ||
|
|
252
|
+
screen === 'openrouter' ||
|
|
253
|
+
screen === 'tts'
|
|
254
|
+
? 'tools'
|
|
255
|
+
: 'main');
|
|
352
256
|
void refresh();
|
|
353
|
-
if (screen === 'ssh-host-wizard' && sshWorkspaceId)
|
|
354
|
-
void refreshSshHosts(sshWorkspaceId);
|
|
355
257
|
};
|
|
356
258
|
const editing = editingModelId
|
|
357
259
|
? config.models.find((model) => model.id === editingModelId)
|
|
@@ -362,7 +264,6 @@ export function ConfigMenu({ onDone }) {
|
|
|
362
264
|
const mainItems = [
|
|
363
265
|
`模型与上下文(${usableModels}/${config.models.length} 个模型可用)`,
|
|
364
266
|
`工具与代理(${configuredTools}/4 项已配置${draftTools ? ` · ${draftTools} 项草稿` : ''})`,
|
|
365
|
-
`远程主机 (SSH)(当前工作区 ${sshHosts?.hosts.length ?? 0} 个${sshHosts?.defaultHostAlias ? ` · 默认 ${sshHosts.defaultHostAlias}` : ''})`,
|
|
366
267
|
`网络与 VPN 代理(${config.networkProxy?.enabled ? `已启用 · ${config.networkProxy.host}:${config.networkProxy.port}` : '已关闭'})`,
|
|
367
268
|
`浏览器(${config.browser?.enabled !== false ? '已启用' : '已关闭'})`,
|
|
368
269
|
'完成并返回聊天',
|
|
@@ -398,8 +299,6 @@ export function ConfigMenu({ onDone }) {
|
|
|
398
299
|
return (_jsx(OpenRouterWizard, { existing: config.tools.openRouter, onDone: back, onCancel: back }));
|
|
399
300
|
if (screen === 'tts')
|
|
400
301
|
return (_jsx(TtsWizard, { existing: config.tools.textToSpeech, onDone: back, onCancel: back }));
|
|
401
|
-
if (screen === 'ssh-host-wizard')
|
|
402
|
-
return sshWorkspaceId ? (_jsx(SshHostWizard, { workspaceId: sshWorkspaceId, existing: sshHosts?.hosts.find((h) => h.alias === editingSshAlias) ?? null, onDone: back, onCancel: back })) : (_jsx(Box, { paddingX: 1, children: _jsx(Text, { color: "red", children: "\u65E0\u6CD5\u786E\u5B9A\u5F53\u524D\u5DE5\u4F5C\u533A\uFF0C\u65E0\u6CD5\u914D\u7F6E SSH \u4E3B\u673A" }) }));
|
|
403
302
|
if (screen === 'main')
|
|
404
303
|
return (_jsx(MenuList, { title: "minimal-agent \u00B7 \u914D\u7F6E\u4E2D\u5FC3", items: mainItems, index: index }));
|
|
405
304
|
if (screen === 'model-context')
|
|
@@ -409,22 +308,12 @@ export function ConfigMenu({ onDone }) {
|
|
|
409
308
|
? 'green'
|
|
410
309
|
: 'red', children: message }))] }));
|
|
411
310
|
if (screen === 'models')
|
|
412
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "\u6A21\u578B\u7BA1\u7406" }), _jsx(Text, { color: "gray", children: "\u2605 \u57FA\u5EA7 \u00B7 \u2191\u2193 \u9009\u62E9 \u00B7 Enter \u64CD\u4F5C \u00B7 ESC \u8FD4\u56DE" }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [config.models.map((model, i) => (_jsxs(Text, { color: index === i ? 'cyan' : undefined, children: [index === i ? '> ' : ' ', model.id === config.baseModelId ? '★ ' : ' ', model.displayName ?? model.model, ' ', _jsxs(Text, { color: "gray", children: ["(", model.apiFormat, "/", model.model, !model.enabled
|
|
311
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "\u6A21\u578B\u7BA1\u7406" }), _jsx(Text, { color: "gray", children: "\u2605 \u57FA\u5EA7 \u00B7 \u2191\u2193 \u9009\u62E9 \u00B7 Enter \u64CD\u4F5C \u00B7 ESC \u8FD4\u56DE" }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [config.models.map((model, i) => (_jsxs(Text, { color: index === i ? 'cyan' : undefined, children: [index === i ? '> ' : ' ', model.id === config.baseModelId ? '★ ' : ' ', model.displayName ?? model.model, ' ', _jsxs(Text, { color: "gray", children: ["(", model.apiFormat, "/", model.model, model.reasoningEffort ? ` · 推理${model.reasoningEffort}` : '', !model.enabled
|
|
413
312
|
? ' · 已停用'
|
|
414
313
|
: !model.apiKey
|
|
415
314
|
? ' · 无密钥'
|
|
416
315
|
: '', ")"] })] }, model.id))), _jsxs(Text, { color: index === config.models.length ? 'cyan' : undefined, children: [index === config.models.length ? '> ' : ' ', "\uFF0B \u6DFB\u52A0\u6A21\u578B"] })] }), message && _jsx(Text, { color: "yellow", children: message })] }));
|
|
417
316
|
if (screen === 'delete-model')
|
|
418
317
|
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Text, { color: "red", bold: true, children: "\u786E\u8BA4\u5220\u9664\u6A21\u578B" }), _jsxs(Text, { children: ["\u5C06\u5220\u9664\u201C", editing?.displayName ?? editing?.model, "\u201D\u3002\u8BE5\u64CD\u4F5C\u4E0D\u53EF\u64A4\u9500\u3002"] }), _jsx(Text, { color: "gray", children: "Enter \u786E\u8BA4\u5220\u9664 \u00B7 ESC \u53D6\u6D88" })] }));
|
|
419
|
-
if (screen === 'ssh-hosts') {
|
|
420
|
-
const hosts = sshHosts?.hosts ?? [];
|
|
421
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsxs(Text, { color: "cyan", bold: true, children: ["\u8FDC\u7A0B\u4E3B\u673A (SSH) \u00B7 \u5F53\u524D\u5DE5\u4F5C\u533A\uFF1A", getWorkingDir()] }), _jsx(Text, { color: "gray", children: "\u2606 \u9ED8\u8BA4\u4E3B\u673A \u00B7 \u2191\u2193 \u9009\u62E9 \u00B7 Enter \u64CD\u4F5C \u00B7 ESC \u8FD4\u56DE" }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [hosts.length === 0 && index === 0 && (_jsx(Text, { color: "gray", children: "\uFF08\u5F53\u524D\u5DE5\u4F5C\u533A\u5C1A\u672A\u914D\u7F6E\u4EFB\u4F55\u4E3B\u673A\uFF09" })), hosts.map((host, i) => (_jsxs(Text, { color: index === i ? 'cyan' : undefined, children: [index === i ? '> ' : ' ', host.alias === sshHosts?.defaultHostAlias ? '☆ ' : ' ', host.alias, ' ', _jsxs(Text, { color: "gray", children: ["(", host.username, "@", host.host, ":", host.port, " \u00B7 ", host.authMethod === 'password' ? '密码' : '密钥', " \u00B7 ", host.remoteShell, ")"] })] }, host.alias))), _jsxs(Text, { color: index === hosts.length ? 'cyan' : undefined, children: [index === hosts.length ? '> ' : ' ', "\uFF0B \u6DFB\u52A0\u4E3B\u673A"] })] }), message && _jsx(Text, { color: message.includes('正常') || message.includes('已') ? 'green' : 'red', children: message })] }));
|
|
422
|
-
}
|
|
423
|
-
if (screen === 'ssh-host-actions') {
|
|
424
|
-
const host = sshHosts?.hosts.find((entry) => entry.alias === editingSshAlias);
|
|
425
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(MenuList, { title: host ? `${host.alias}(${host.username}@${host.host}:${host.port})` : 'SSH 主机操作', items: SSH_HOST_ACTIONS, index: index }), busy && _jsx(Text, { color: "yellow", children: "\u6B63\u5728\u5904\u7406..." }), message && (_jsx(Text, { color: message.includes('正常') || message.includes('已') ? 'green' : 'red', children: message }))] }));
|
|
426
|
-
}
|
|
427
|
-
if (screen === 'delete-ssh-host')
|
|
428
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Text, { color: "red", bold: true, children: "\u786E\u8BA4\u5220\u9664 SSH \u4E3B\u673A" }), _jsxs(Text, { children: ["\u5C06\u5220\u9664\u4E3B\u673A\u201C", editingSshAlias, "\u201D\u3002\u8BE5\u64CD\u4F5C\u4E0D\u53EF\u64A4\u9500\u3002"] }), _jsx(Text, { color: "gray", children: "Enter \u786E\u8BA4\u5220\u9664 \u00B7 ESC \u53D6\u6D88" })] }));
|
|
429
318
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(MenuList, { title: editing?.displayName ?? editing?.model ?? '模型操作', items: MODEL_ACTIONS, index: index }), busy && _jsx(Text, { color: "yellow", children: "\u6B63\u5728\u5904\u7406..." }), message && (_jsx(Text, { color: message.includes('正常') || message.includes('已') ? 'green' : 'red', children: message }))] }));
|
|
430
319
|
}
|
package/src/cli/configMenu.tsx
CHANGED
|
@@ -4,19 +4,10 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|
|
4
4
|
import {
|
|
5
5
|
testAdvisorConnection,
|
|
6
6
|
testConfiguredModel,
|
|
7
|
-
testSshHostConnection,
|
|
8
7
|
testToolConnection,
|
|
9
8
|
} from '../config/configDiagnostics.js';
|
|
10
9
|
import type { MinimalAgentConfig, ModelConfig } from '../config/configFile.js';
|
|
11
10
|
import { configService } from '../config/configService.js';
|
|
12
|
-
import { getWorkingDir } from '../bootstrap/workingDir.js';
|
|
13
|
-
import {
|
|
14
|
-
listSshHosts,
|
|
15
|
-
removeSshHost,
|
|
16
|
-
setDefaultSshHost,
|
|
17
|
-
type SshHostsData,
|
|
18
|
-
} from '../context/sshHosts.js';
|
|
19
|
-
import { workspaceIndexService } from '../context/workspaceIndex.js';
|
|
20
11
|
import { applyNetworkProxy } from '../network/proxy.js';
|
|
21
12
|
import type { Provider } from '../types.js';
|
|
22
13
|
import { AgentRuntimeWizard } from './wizards/agentRuntimeWizard.js';
|
|
@@ -26,7 +17,6 @@ import { ImageWizard } from './wizards/imageWizard.js';
|
|
|
26
17
|
import { OpenRouterWizard } from './wizards/openRouterWizard.js';
|
|
27
18
|
import { ProviderWizard } from './wizards/providerWizard.js';
|
|
28
19
|
import { SearchWizard } from './wizards/searchWizard.js';
|
|
29
|
-
import { SshHostWizard } from './wizards/sshHostWizard.js';
|
|
30
20
|
import { TtsWizard } from './wizards/ttsWizard.js';
|
|
31
21
|
import { NetworkProxyWizard } from './wizards/networkProxyWizard.js';
|
|
32
22
|
|
|
@@ -45,10 +35,6 @@ type Screen =
|
|
|
45
35
|
| 'openrouter'
|
|
46
36
|
| 'tts'
|
|
47
37
|
| 'browser'
|
|
48
|
-
| 'ssh-hosts'
|
|
49
|
-
| 'ssh-host-actions'
|
|
50
|
-
| 'delete-ssh-host'
|
|
51
|
-
| 'ssh-host-wizard'
|
|
52
38
|
| 'network-proxy';
|
|
53
39
|
|
|
54
40
|
interface Props {
|
|
@@ -56,8 +42,7 @@ interface Props {
|
|
|
56
42
|
onDone: (provider?: Provider) => void;
|
|
57
43
|
}
|
|
58
44
|
|
|
59
|
-
const MAIN = ['模型与上下文', '工具与代理', '
|
|
60
|
-
const SSH_HOST_ACTIONS = ['编辑', '测试连接', '设为默认主机', '删除', '返回'];
|
|
45
|
+
const MAIN = ['模型与上下文', '工具与代理', '网络与 VPN 代理', '浏览器', '完成并返回聊天'];
|
|
61
46
|
const MODEL_CONTEXT = ['模型管理', '压缩与顾问', '测试顾问连接', '返回'];
|
|
62
47
|
const TOOLS = [
|
|
63
48
|
'电脑操作与子代理',
|
|
@@ -114,33 +99,15 @@ export function ConfigMenu({ onDone }: Props): JSX.Element {
|
|
|
114
99
|
const [editingModelId, setEditingModelId] = useState<string | null>(null);
|
|
115
100
|
const [message, setMessage] = useState<string | null>(null);
|
|
116
101
|
const [busy, setBusy] = useState(false);
|
|
117
|
-
const [sshWorkspaceId, setSshWorkspaceId] = useState<string | null>(null);
|
|
118
|
-
const [sshHosts, setSshHosts] = useState<SshHostsData | null>(null);
|
|
119
|
-
const [editingSshAlias, setEditingSshAlias] = useState<string | null>(null);
|
|
120
102
|
const refresh = useCallback(async () => {
|
|
121
103
|
const snapshot = await configService.reload();
|
|
122
104
|
applyNetworkProxy(snapshot.config?.networkProxy);
|
|
123
105
|
setConfig(snapshot.config);
|
|
124
106
|
setReadOnly(snapshot.readOnly);
|
|
125
107
|
}, []);
|
|
126
|
-
const refreshSshHosts = useCallback(async (workspaceId: string) => {
|
|
127
|
-
setSshHosts(await listSshHosts(workspaceId));
|
|
128
|
-
}, []);
|
|
129
108
|
useEffect(() => {
|
|
130
109
|
void refresh();
|
|
131
|
-
|
|
132
|
-
// 保证 /config 里编辑的主机和 SSH 工具运行时读到的是同一份数据。找不到(从未
|
|
133
|
-
// 注册过)就注册一次——能走到这里说明用户已经在一个真实交互会话里,不是
|
|
134
|
-
// e2e/cron 那类刻意排除的临时目录。
|
|
135
|
-
void (async () => {
|
|
136
|
-
const cwd = getWorkingDir();
|
|
137
|
-
const found = await workspaceIndexService.findByPath(cwd).catch(() => null);
|
|
138
|
-
const workspace = found ?? await workspaceIndexService.register(cwd).catch(() => null);
|
|
139
|
-
if (!workspace) return;
|
|
140
|
-
setSshWorkspaceId(workspace.id);
|
|
141
|
-
await refreshSshHosts(workspace.id);
|
|
142
|
-
})();
|
|
143
|
-
}, [refresh, refreshSshHosts]);
|
|
110
|
+
}, [refresh]);
|
|
144
111
|
const navigate = (next: Screen) => {
|
|
145
112
|
setIndex(0);
|
|
146
113
|
setMessage(null);
|
|
@@ -167,31 +134,6 @@ export function ConfigMenu({ onDone }: Props): JSX.Element {
|
|
|
167
134
|
},
|
|
168
135
|
[refresh],
|
|
169
136
|
);
|
|
170
|
-
const mutateSsh = useCallback(
|
|
171
|
-
async (
|
|
172
|
-
operation: () => Promise<unknown>,
|
|
173
|
-
success: string,
|
|
174
|
-
): Promise<boolean> => {
|
|
175
|
-
if (!sshWorkspaceId) {
|
|
176
|
-
setMessage('无法确定当前工作区');
|
|
177
|
-
return false;
|
|
178
|
-
}
|
|
179
|
-
setBusy(true);
|
|
180
|
-
setMessage(null);
|
|
181
|
-
try {
|
|
182
|
-
await operation();
|
|
183
|
-
await refreshSshHosts(sshWorkspaceId);
|
|
184
|
-
setMessage(success);
|
|
185
|
-
return true;
|
|
186
|
-
} catch (error) {
|
|
187
|
-
setMessage((error as Error).message || '操作失败');
|
|
188
|
-
return false;
|
|
189
|
-
} finally {
|
|
190
|
-
setBusy(false);
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
[sshWorkspaceId, refreshSshHosts],
|
|
194
|
-
);
|
|
195
137
|
|
|
196
138
|
useInput((input, key) => {
|
|
197
139
|
if (
|
|
@@ -206,7 +148,6 @@ export function ConfigMenu({ onDone }: Props): JSX.Element {
|
|
|
206
148
|
'tts',
|
|
207
149
|
'network-proxy',
|
|
208
150
|
'browser',
|
|
209
|
-
'ssh-host-wizard',
|
|
210
151
|
].includes(screen)
|
|
211
152
|
)
|
|
212
153
|
return;
|
|
@@ -217,9 +158,6 @@ export function ConfigMenu({ onDone }: Props): JSX.Element {
|
|
|
217
158
|
else if (screen === 'model-actions' || screen === 'delete-model')
|
|
218
159
|
navigate('models');
|
|
219
160
|
else if (screen === 'tools') navigate('main');
|
|
220
|
-
else if (screen === 'ssh-hosts') navigate('main');
|
|
221
|
-
else if (screen === 'ssh-host-actions' || screen === 'delete-ssh-host')
|
|
222
|
-
navigate('ssh-hosts');
|
|
223
161
|
};
|
|
224
162
|
if (key.escape || (key.ctrl && input === 'c')) {
|
|
225
163
|
back();
|
|
@@ -236,11 +174,7 @@ export function ConfigMenu({ onDone }: Props): JSX.Element {
|
|
|
236
174
|
? MODEL_ACTIONS.length
|
|
237
175
|
: screen === 'models'
|
|
238
176
|
? (config?.models.length ?? 0) + 1
|
|
239
|
-
:
|
|
240
|
-
? (sshHosts?.hosts.length ?? 0) + 1
|
|
241
|
-
: screen === 'ssh-host-actions'
|
|
242
|
-
? SSH_HOST_ACTIONS.length
|
|
243
|
-
: 1;
|
|
177
|
+
: 1;
|
|
244
178
|
if (key.upArrow) {
|
|
245
179
|
setIndex((value) => (value - 1 + length) % length);
|
|
246
180
|
return;
|
|
@@ -262,16 +196,6 @@ export function ConfigMenu({ onDone }: Props): JSX.Element {
|
|
|
262
196
|
});
|
|
263
197
|
return;
|
|
264
198
|
}
|
|
265
|
-
if (screen === 'delete-ssh-host') {
|
|
266
|
-
if (key.return && sshWorkspaceId && editingSshAlias)
|
|
267
|
-
void mutateSsh(
|
|
268
|
-
() => removeSshHost(sshWorkspaceId, editingSshAlias),
|
|
269
|
-
'主机已删除',
|
|
270
|
-
).then((ok) => {
|
|
271
|
-
if (ok) navigate('ssh-hosts');
|
|
272
|
-
});
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
199
|
if (
|
|
276
200
|
screen === 'tools' &&
|
|
277
201
|
(input === 'd' || input === 't') &&
|
|
@@ -297,35 +221,9 @@ export function ConfigMenu({ onDone }: Props): JSX.Element {
|
|
|
297
221
|
if (screen === 'main') {
|
|
298
222
|
if (index === 0) navigate('model-context');
|
|
299
223
|
else if (index === 1) navigate('tools');
|
|
300
|
-
else if (index === 2) navigate('
|
|
301
|
-
else if (index === 3) navigate('
|
|
302
|
-
else if (index === 4) navigate('browser');
|
|
224
|
+
else if (index === 2) navigate('network-proxy');
|
|
225
|
+
else if (index === 3) navigate('browser');
|
|
303
226
|
else onDone();
|
|
304
|
-
} else if (screen === 'ssh-hosts') {
|
|
305
|
-
const hosts = sshHosts?.hosts ?? [];
|
|
306
|
-
if (index === hosts.length) {
|
|
307
|
-
setEditingSshAlias(null);
|
|
308
|
-
navigate('ssh-host-wizard');
|
|
309
|
-
} else {
|
|
310
|
-
setEditingSshAlias(hosts[index]?.alias ?? null);
|
|
311
|
-
navigate('ssh-host-actions');
|
|
312
|
-
}
|
|
313
|
-
} else if (screen === 'ssh-host-actions' && sshWorkspaceId && editingSshAlias) {
|
|
314
|
-
const host = sshHosts?.hosts.find((entry) => entry.alias === editingSshAlias);
|
|
315
|
-
if (!host) return;
|
|
316
|
-
if (index === 0) navigate('ssh-host-wizard');
|
|
317
|
-
else if (index === 1)
|
|
318
|
-
void mutateSsh(async () => {
|
|
319
|
-
const result = await testSshHostConnection(sshWorkspaceId, editingSshAlias);
|
|
320
|
-
if (!result.ok) throw new Error(result.message);
|
|
321
|
-
}, '连接正常');
|
|
322
|
-
else if (index === 2)
|
|
323
|
-
void mutateSsh(
|
|
324
|
-
() => setDefaultSshHost(sshWorkspaceId, editingSshAlias),
|
|
325
|
-
'已设为默认主机',
|
|
326
|
-
);
|
|
327
|
-
else if (index === 3) navigate('delete-ssh-host');
|
|
328
|
-
else navigate('ssh-hosts');
|
|
329
227
|
} else if (screen === 'model-context') {
|
|
330
228
|
if (index === 0) navigate('models');
|
|
331
229
|
else if (index === 1) navigate('context-advisor');
|
|
@@ -418,22 +316,19 @@ export function ConfigMenu({ onDone }: Props): JSX.Element {
|
|
|
418
316
|
? 'models'
|
|
419
317
|
: screen === 'context-advisor'
|
|
420
318
|
? 'model-context'
|
|
421
|
-
: screen === '
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
? 'tools'
|
|
433
|
-
: 'main',
|
|
319
|
+
: screen === 'browser' ||
|
|
320
|
+
screen === 'tools' ||
|
|
321
|
+
screen === 'network-proxy'
|
|
322
|
+
? 'main'
|
|
323
|
+
: screen === 'agent-runtime' ||
|
|
324
|
+
screen === 'search' ||
|
|
325
|
+
screen === 'image' ||
|
|
326
|
+
screen === 'openrouter' ||
|
|
327
|
+
screen === 'tts'
|
|
328
|
+
? 'tools'
|
|
329
|
+
: 'main',
|
|
434
330
|
);
|
|
435
331
|
void refresh();
|
|
436
|
-
if (screen === 'ssh-host-wizard' && sshWorkspaceId) void refreshSshHosts(sshWorkspaceId);
|
|
437
332
|
};
|
|
438
333
|
const editing = editingModelId
|
|
439
334
|
? config.models.find((model) => model.id === editingModelId)
|
|
@@ -446,7 +341,6 @@ export function ConfigMenu({ onDone }: Props): JSX.Element {
|
|
|
446
341
|
const mainItems = [
|
|
447
342
|
`模型与上下文(${usableModels}/${config.models.length} 个模型可用)`,
|
|
448
343
|
`工具与代理(${configuredTools}/4 项已配置${draftTools ? ` · ${draftTools} 项草稿` : ''})`,
|
|
449
|
-
`远程主机 (SSH)(当前工作区 ${sshHosts?.hosts.length ?? 0} 个${sshHosts?.defaultHostAlias ? ` · 默认 ${sshHosts.defaultHostAlias}` : ''})`,
|
|
450
344
|
`网络与 VPN 代理(${config.networkProxy?.enabled ? `已启用 · ${config.networkProxy.host}:${config.networkProxy.port}` : '已关闭'})`,
|
|
451
345
|
`浏览器(${config.browser?.enabled !== false ? '已启用' : '已关闭'})`,
|
|
452
346
|
'完成并返回聊天',
|
|
@@ -531,19 +425,6 @@ export function ConfigMenu({ onDone }: Props): JSX.Element {
|
|
|
531
425
|
onCancel={back}
|
|
532
426
|
/>
|
|
533
427
|
);
|
|
534
|
-
if (screen === 'ssh-host-wizard')
|
|
535
|
-
return sshWorkspaceId ? (
|
|
536
|
-
<SshHostWizard
|
|
537
|
-
workspaceId={sshWorkspaceId}
|
|
538
|
-
existing={sshHosts?.hosts.find((h) => h.alias === editingSshAlias) ?? null}
|
|
539
|
-
onDone={back}
|
|
540
|
-
onCancel={back}
|
|
541
|
-
/>
|
|
542
|
-
) : (
|
|
543
|
-
<Box paddingX={1}>
|
|
544
|
-
<Text color="red">无法确定当前工作区,无法配置 SSH 主机</Text>
|
|
545
|
-
</Box>
|
|
546
|
-
);
|
|
547
428
|
if (screen === 'main')
|
|
548
429
|
return (
|
|
549
430
|
<MenuList
|
|
@@ -600,6 +481,7 @@ export function ConfigMenu({ onDone }: Props): JSX.Element {
|
|
|
600
481
|
{model.displayName ?? model.model}{' '}
|
|
601
482
|
<Text color="gray">
|
|
602
483
|
({model.apiFormat}/{model.model}
|
|
484
|
+
{model.reasoningEffort ? ` · 推理${model.reasoningEffort}` : ''}
|
|
603
485
|
{!model.enabled
|
|
604
486
|
? ' · 已停用'
|
|
605
487
|
: !model.apiKey
|
|
@@ -628,64 +510,6 @@ export function ConfigMenu({ onDone }: Props): JSX.Element {
|
|
|
628
510
|
<Text color="gray">Enter 确认删除 · ESC 取消</Text>
|
|
629
511
|
</Box>
|
|
630
512
|
);
|
|
631
|
-
if (screen === 'ssh-hosts') {
|
|
632
|
-
const hosts = sshHosts?.hosts ?? [];
|
|
633
|
-
return (
|
|
634
|
-
<Box flexDirection="column" paddingX={1}>
|
|
635
|
-
<Text color="cyan" bold>
|
|
636
|
-
远程主机 (SSH) · 当前工作区:{getWorkingDir()}
|
|
637
|
-
</Text>
|
|
638
|
-
<Text color="gray">☆ 默认主机 · ↑↓ 选择 · Enter 操作 · ESC 返回</Text>
|
|
639
|
-
<Box flexDirection="column" marginTop={1}>
|
|
640
|
-
{hosts.length === 0 && index === 0 && (
|
|
641
|
-
<Text color="gray">(当前工作区尚未配置任何主机)</Text>
|
|
642
|
-
)}
|
|
643
|
-
{hosts.map((host, i) => (
|
|
644
|
-
<Text key={host.alias} color={index === i ? 'cyan' : undefined}>
|
|
645
|
-
{index === i ? '> ' : ' '}
|
|
646
|
-
{host.alias === sshHosts?.defaultHostAlias ? '☆ ' : ' '}
|
|
647
|
-
{host.alias}{' '}
|
|
648
|
-
<Text color="gray">
|
|
649
|
-
({host.username}@{host.host}:{host.port} · {host.authMethod === 'password' ? '密码' : '密钥'} · {host.remoteShell})
|
|
650
|
-
</Text>
|
|
651
|
-
</Text>
|
|
652
|
-
))}
|
|
653
|
-
<Text color={index === hosts.length ? 'cyan' : undefined}>
|
|
654
|
-
{index === hosts.length ? '> ' : ' '}+ 添加主机
|
|
655
|
-
</Text>
|
|
656
|
-
</Box>
|
|
657
|
-
{message && <Text color={message.includes('正常') || message.includes('已') ? 'green' : 'red'}>{message}</Text>}
|
|
658
|
-
</Box>
|
|
659
|
-
);
|
|
660
|
-
}
|
|
661
|
-
if (screen === 'ssh-host-actions') {
|
|
662
|
-
const host = sshHosts?.hosts.find((entry) => entry.alias === editingSshAlias);
|
|
663
|
-
return (
|
|
664
|
-
<Box flexDirection="column">
|
|
665
|
-
<MenuList
|
|
666
|
-
title={host ? `${host.alias}(${host.username}@${host.host}:${host.port})` : 'SSH 主机操作'}
|
|
667
|
-
items={SSH_HOST_ACTIONS}
|
|
668
|
-
index={index}
|
|
669
|
-
/>
|
|
670
|
-
{busy && <Text color="yellow">正在处理...</Text>}
|
|
671
|
-
{message && (
|
|
672
|
-
<Text color={message.includes('正常') || message.includes('已') ? 'green' : 'red'}>
|
|
673
|
-
{message}
|
|
674
|
-
</Text>
|
|
675
|
-
)}
|
|
676
|
-
</Box>
|
|
677
|
-
);
|
|
678
|
-
}
|
|
679
|
-
if (screen === 'delete-ssh-host')
|
|
680
|
-
return (
|
|
681
|
-
<Box flexDirection="column" paddingX={1}>
|
|
682
|
-
<Text color="red" bold>
|
|
683
|
-
确认删除 SSH 主机
|
|
684
|
-
</Text>
|
|
685
|
-
<Text>将删除主机“{editingSshAlias}”。该操作不可撤销。</Text>
|
|
686
|
-
<Text color="gray">Enter 确认删除 · ESC 取消</Text>
|
|
687
|
-
</Box>
|
|
688
|
-
);
|
|
689
513
|
return (
|
|
690
514
|
<Box flexDirection="column">
|
|
691
515
|
<MenuList
|
package/src/cli/print.js
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
* minimal-agent -p --output-format json "提示" # 结构化结局
|
|
23
23
|
* ============================================================
|
|
24
24
|
*/
|
|
25
|
+
import { previousUserRequest } from '../memory/recallQuery.js';
|
|
25
26
|
import { getContextPath, saveContext } from '../context/persistContext.js';
|
|
26
27
|
import { updateSessionMetadata } from '../context/sessionRegistry.js';
|
|
27
28
|
import { workspaceIndexService } from '../context/workspaceIndex.js';
|
|
@@ -328,6 +329,7 @@ export async function runPrintMode(provider, args, initialHistory, options) {
|
|
|
328
329
|
memoryAccess: runtimeContext.memoryAccess,
|
|
329
330
|
browser: browserPromptRuntime(runtimeContext.browser, provider.supportsVision),
|
|
330
331
|
currentUserInput: prompt,
|
|
332
|
+
previousUserInput: previousUserRequest(history),
|
|
331
333
|
contextWindow: provider.contextWindow,
|
|
332
334
|
},
|
|
333
335
|
}).catch(() => undefined);
|
package/src/cli/print.ts
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* ============================================================
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
+
import { previousUserRequest } from '../memory/recallQuery.js';
|
|
26
27
|
import { getContextPath, saveContext } from '../context/persistContext.js';
|
|
27
28
|
import { updateSessionMetadata } from '../context/sessionRegistry.js';
|
|
28
29
|
import { workspaceIndexService } from '../context/workspaceIndex.js';
|
|
@@ -473,6 +474,7 @@ export async function runPrintMode(
|
|
|
473
474
|
memoryAccess: runtimeContext.memoryAccess,
|
|
474
475
|
browser: browserPromptRuntime(runtimeContext.browser, provider.supportsVision),
|
|
475
476
|
currentUserInput: prompt,
|
|
477
|
+
previousUserInput: previousUserRequest(history),
|
|
476
478
|
contextWindow: provider.contextWindow,
|
|
477
479
|
},
|
|
478
480
|
}).catch(() => undefined);
|
package/src/cli/streamJson.js
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* - 跑完 / 中断 / 出错都先 saveContext 再退出(finalize 还会 unref stdin,让本轮结束后进程能退出)。
|
|
19
19
|
* ============================================================
|
|
20
20
|
*/
|
|
21
|
+
import { previousUserRequest } from '../memory/recallQuery.js';
|
|
21
22
|
import crypto from 'node:crypto';
|
|
22
23
|
import { getWorkingDir } from '../bootstrap/workingDir.js';
|
|
23
24
|
import { forceCompact } from '../context/compact.js';
|
|
@@ -351,6 +352,7 @@ export async function runStreamJsonMode(provider, args, initialHistory, options)
|
|
|
351
352
|
memoryAccess: runtimeContext.memoryAccess,
|
|
352
353
|
browser: browserPromptRuntime(runtimeContext.browser, provider.supportsVision),
|
|
353
354
|
currentUserInput: prompt,
|
|
355
|
+
previousUserInput: previousUserRequest(history),
|
|
354
356
|
contextWindow: provider.contextWindow,
|
|
355
357
|
},
|
|
356
358
|
}).catch(() => undefined);
|
package/src/cli/streamJson.ts
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
* ============================================================
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
+
import { previousUserRequest } from '../memory/recallQuery.js';
|
|
22
23
|
import crypto from 'node:crypto';
|
|
23
24
|
import { getWorkingDir } from '../bootstrap/workingDir.js';
|
|
24
25
|
import { forceCompact } from '../context/compact.js';
|
|
@@ -458,6 +459,7 @@ export async function runStreamJsonMode(
|
|
|
458
459
|
memoryAccess: runtimeContext.memoryAccess,
|
|
459
460
|
browser: browserPromptRuntime(runtimeContext.browser, provider.supportsVision),
|
|
460
461
|
currentUserInput: prompt,
|
|
462
|
+
previousUserInput: previousUserRequest(history),
|
|
461
463
|
contextWindow: provider.contextWindow,
|
|
462
464
|
},
|
|
463
465
|
}).catch(() => undefined);
|