deepclause-sdk 0.0.61 → 0.0.63
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/README.md +47 -5
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +9 -2
- package/dist/agent.js.map +1 -1
- package/dist/cli/compile.d.ts +10 -0
- package/dist/cli/compile.d.ts.map +1 -1
- package/dist/cli/compile.js +62 -11
- package/dist/cli/compile.js.map +1 -1
- package/dist/cli/config.d.ts +5 -0
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +61 -0
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/index.js +105 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/run.d.ts +1 -0
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +1 -0
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/tool-args.d.ts +2 -0
- package/dist/cli/tool-args.d.ts.map +1 -0
- package/dist/cli/tool-args.js +39 -0
- package/dist/cli/tool-args.js.map +1 -0
- package/dist/cli/tui.d.ts +27 -1
- package/dist/cli/tui.d.ts.map +1 -1
- package/dist/cli/tui.js +428 -34
- package/dist/cli/tui.js.map +1 -1
- package/dist/compiler.d.ts +10 -0
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +27 -6
- package/dist/compiler.js.map +1 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +26 -19
- package/dist/runner.js.map +1 -1
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +44 -0
- package/dist/sdk.js.map +1 -1
- package/dist/system/assets/docs/CONDUCTOR_PROMPT.md +30 -5
- package/dist/system/assets/docs/TUI.md +139 -0
- package/dist/system/assets/index.d.ts +11 -1
- package/dist/system/assets/index.d.ts.map +1 -1
- package/dist/system/assets/index.js +62 -7
- package/dist/system/assets/index.js.map +1 -1
- package/dist/system/runtime/agentvm-manager.d.ts +28 -1
- package/dist/system/runtime/agentvm-manager.d.ts.map +1 -1
- package/dist/system/runtime/agentvm-manager.js +18 -2
- package/dist/system/runtime/agentvm-manager.js.map +1 -1
- package/dist/system/runtime/conductor.d.ts.map +1 -1
- package/dist/system/runtime/conductor.js +8 -4
- package/dist/system/runtime/conductor.js.map +1 -1
- package/dist/system/runtime/dml-executor.js +58 -54
- package/dist/system/runtime/dml-executor.js.map +1 -1
- package/dist/system/runtime/runtime-tools.d.ts +2 -1
- package/dist/system/runtime/runtime-tools.d.ts.map +1 -1
- package/dist/system/runtime/runtime-tools.js +17 -2
- package/dist/system/runtime/runtime-tools.js.map +1 -1
- package/dist/system/runtime/shell-manager.d.ts +3 -3
- package/dist/system/runtime/shell-manager.d.ts.map +1 -1
- package/dist/system/runtime/shell-manager.js +31 -3
- package/dist/system/runtime/shell-manager.js.map +1 -1
- package/dist/system/runtime/shell-tool-events.d.ts +11 -0
- package/dist/system/runtime/shell-tool-events.d.ts.map +1 -0
- package/dist/system/runtime/shell-tool-events.js +139 -0
- package/dist/system/runtime/shell-tool-events.js.map +1 -0
- package/dist/system/runtime/skill-creator.d.ts +3 -0
- package/dist/system/runtime/skill-creator.d.ts.map +1 -1
- package/dist/system/runtime/skill-creator.js +41 -25
- package/dist/system/runtime/skill-creator.js.map +1 -1
- package/dist/types.d.ts +12 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/cli/tui.js
CHANGED
|
@@ -4,11 +4,16 @@ import { emitKeypressEvents } from 'readline';
|
|
|
4
4
|
import { createInterface } from 'readline/promises';
|
|
5
5
|
import { stdin as input, stdout as output } from 'process';
|
|
6
6
|
import { listCommands } from './commands.js';
|
|
7
|
-
import { getConfigPath, loadConfig, resolveModelSlot } from './config.js';
|
|
7
|
+
import { getConfigPath, loadConfig, resolveModelSlot, setModel } from './config.js';
|
|
8
8
|
import { run } from './run.js';
|
|
9
|
+
import { formatToolArgs } from './tool-args.js';
|
|
9
10
|
import { createLocalSkill, createConductorSession, getConductorSessionDetail, listConductorSessions, runConductorTurn, } from '../system/runtime/conductor.js';
|
|
11
|
+
import { getSystemAssetSourcePaths } from '../system/assets/index.js';
|
|
12
|
+
import { createShellManager } from '../system/runtime/shell-manager.js';
|
|
13
|
+
import { buildToolCompletionEvent, buildToolFailureEvent, buildToolStartEvent, createShellToolEventBridge, } from '../system/runtime/shell-tool-events.js';
|
|
10
14
|
const IGNORED_LIVE_LOG_TOOLS = new Set(['set_result', 'update_memory']);
|
|
11
|
-
const BUILTIN_SLASH_COMMANDS = ['new', 'sessions', 'help', 'compile', 'skill-creator', 'cancel', 'exit', 'quit'];
|
|
15
|
+
const BUILTIN_SLASH_COMMANDS = ['new', 'sessions', 'help', 'compile', 'skill-creator', 'set-model', 'cancel', 'exit', 'quit'];
|
|
16
|
+
const MODEL_SLOTS = ['gateway', 'run', 'compile'];
|
|
12
17
|
const CHILD_EVENT_INDENT = '\t';
|
|
13
18
|
const CHILD_EVENT_TAB_WIDTH = 4;
|
|
14
19
|
const MAX_ACTIVITY_LINES = 400;
|
|
@@ -67,10 +72,7 @@ export class LiveExecutionPrinter {
|
|
|
67
72
|
this.flushStream();
|
|
68
73
|
switch (event.type) {
|
|
69
74
|
case 'tool_call':
|
|
70
|
-
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
this.writeLine(`${formatEventPrefix(logEvent)}tool ${event.toolName}(${formatToolArgs(event.toolArgs)})`);
|
|
75
|
+
this.handleToolCall(logEvent);
|
|
74
76
|
break;
|
|
75
77
|
case 'output':
|
|
76
78
|
if (event.content) {
|
|
@@ -126,9 +128,17 @@ export class LiveExecutionPrinter {
|
|
|
126
128
|
this.streamOpen = false;
|
|
127
129
|
this.activeStreamKey = null;
|
|
128
130
|
}
|
|
131
|
+
handleToolCall(logEvent) {
|
|
132
|
+
const line = formatToolEventLine(logEvent);
|
|
133
|
+
if (!line) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
this.writeLine(line);
|
|
137
|
+
}
|
|
129
138
|
}
|
|
130
|
-
class ActivityBuffer {
|
|
139
|
+
export class ActivityBuffer {
|
|
131
140
|
lines = [];
|
|
141
|
+
activeTools = new Map();
|
|
132
142
|
activeStreamKey = null;
|
|
133
143
|
activeStreamLine = '';
|
|
134
144
|
handle(logEvent) {
|
|
@@ -143,10 +153,7 @@ class ActivityBuffer {
|
|
|
143
153
|
this.flushStream();
|
|
144
154
|
switch (event.type) {
|
|
145
155
|
case 'tool_call':
|
|
146
|
-
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
this.pushLine(`${formatEventPrefix(logEvent)}tool ${event.toolName}(${formatToolArgs(event.toolArgs)})`);
|
|
156
|
+
this.handleToolCall(logEvent);
|
|
150
157
|
break;
|
|
151
158
|
case 'output':
|
|
152
159
|
if (event.content) {
|
|
@@ -185,16 +192,25 @@ class ActivityBuffer {
|
|
|
185
192
|
}
|
|
186
193
|
finish() {
|
|
187
194
|
this.flushStream();
|
|
195
|
+
this.activeTools.clear();
|
|
188
196
|
}
|
|
189
197
|
clear() {
|
|
190
198
|
this.lines.length = 0;
|
|
199
|
+
this.activeTools.clear();
|
|
191
200
|
this.activeStreamKey = null;
|
|
192
201
|
this.activeStreamLine = '';
|
|
193
202
|
}
|
|
194
203
|
snapshot() {
|
|
195
|
-
|
|
204
|
+
const body = this.activeStreamLine
|
|
196
205
|
? [...this.lines, this.activeStreamLine]
|
|
197
206
|
: [...this.lines];
|
|
207
|
+
const activeLines = this.buildActiveToolLines();
|
|
208
|
+
if (activeLines.length === 0) {
|
|
209
|
+
return body;
|
|
210
|
+
}
|
|
211
|
+
return body.length > 0
|
|
212
|
+
? [...activeLines, '', ...body]
|
|
213
|
+
: activeLines;
|
|
198
214
|
}
|
|
199
215
|
handleStream(logEvent) {
|
|
200
216
|
const streamKey = logEvent.scope === 'child' ? `child:${logEvent.childSlug ?? '?'}` : 'main';
|
|
@@ -225,6 +241,43 @@ class ActivityBuffer {
|
|
|
225
241
|
this.lines.splice(0, this.lines.length - MAX_ACTIVITY_LINES);
|
|
226
242
|
}
|
|
227
243
|
}
|
|
244
|
+
handleToolCall(logEvent) {
|
|
245
|
+
const { event } = logEvent;
|
|
246
|
+
if (!event.toolName || IGNORED_LIVE_LOG_TOOLS.has(event.toolName)) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
if (event.toolState) {
|
|
250
|
+
const scopeKey = toolScopeKey(logEvent);
|
|
251
|
+
if (event.toolState === 'starting' || event.toolState === 'running') {
|
|
252
|
+
this.activeTools.set(scopeKey, {
|
|
253
|
+
scopeKey,
|
|
254
|
+
scopeLabel: toolScopeLabel(logEvent),
|
|
255
|
+
toolName: event.toolName,
|
|
256
|
+
toolState: event.toolState,
|
|
257
|
+
toolPid: event.toolPid,
|
|
258
|
+
toolBackend: event.toolBackend,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
this.activeTools.delete(scopeKey);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const line = formatToolEventLine(logEvent);
|
|
266
|
+
if (line) {
|
|
267
|
+
this.pushLine(line);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
buildActiveToolLines() {
|
|
271
|
+
if (this.activeTools.size === 0) {
|
|
272
|
+
return [];
|
|
273
|
+
}
|
|
274
|
+
const lines = ['Active Tool Status'];
|
|
275
|
+
const entries = [...this.activeTools.values()].sort((left, right) => left.scopeKey.localeCompare(right.scopeKey));
|
|
276
|
+
for (const entry of entries) {
|
|
277
|
+
lines.push(formatActiveToolStatus(entry));
|
|
278
|
+
}
|
|
279
|
+
return lines;
|
|
280
|
+
}
|
|
228
281
|
}
|
|
229
282
|
class FullscreenTui {
|
|
230
283
|
workspaceRoot;
|
|
@@ -263,6 +316,7 @@ class FullscreenTui {
|
|
|
263
316
|
editorState = null;
|
|
264
317
|
recentFiles = [];
|
|
265
318
|
lastSubmittedInput = null;
|
|
319
|
+
shellWorkspacePath;
|
|
266
320
|
renderTimer = null;
|
|
267
321
|
animationTimer = null;
|
|
268
322
|
closeResolver = null;
|
|
@@ -272,6 +326,7 @@ class FullscreenTui {
|
|
|
272
326
|
constructor(workspaceRoot, options = {}) {
|
|
273
327
|
this.workspaceRoot = workspaceRoot;
|
|
274
328
|
this.options = options;
|
|
329
|
+
this.shellWorkspacePath = path.resolve(workspaceRoot, 'workspace');
|
|
275
330
|
}
|
|
276
331
|
async start() {
|
|
277
332
|
try {
|
|
@@ -428,8 +483,12 @@ class FullscreenTui {
|
|
|
428
483
|
await this.applyCompletion();
|
|
429
484
|
return;
|
|
430
485
|
case 'escape':
|
|
431
|
-
|
|
432
|
-
|
|
486
|
+
{
|
|
487
|
+
const previousInput = this.inputValue;
|
|
488
|
+
this.inputValue = '';
|
|
489
|
+
this.cursor = 0;
|
|
490
|
+
this.refreshCommandBarStatus(previousInput);
|
|
491
|
+
}
|
|
433
492
|
break;
|
|
434
493
|
default:
|
|
435
494
|
if (text && !key.ctrl && !key.meta) {
|
|
@@ -711,7 +770,7 @@ class FullscreenTui {
|
|
|
711
770
|
this.requestRender();
|
|
712
771
|
return;
|
|
713
772
|
}
|
|
714
|
-
const parsed =
|
|
773
|
+
const parsed = parseCommandBarInput(rawInput);
|
|
715
774
|
if (this.busy && !this.pendingPrompt && !canSubmitParsedInputWhileBusy(parsed)) {
|
|
716
775
|
this.statusLine = 'Execution is still running. Use /cancel or Ctrl+C to stop it.';
|
|
717
776
|
this.requestRender();
|
|
@@ -725,6 +784,10 @@ class FullscreenTui {
|
|
|
725
784
|
await this.executeSkill(parsed.name, parsed.args);
|
|
726
785
|
return;
|
|
727
786
|
}
|
|
787
|
+
if (parsed.kind === 'shell') {
|
|
788
|
+
await this.executeShellCommand(parsed.command);
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
728
791
|
await this.executeTask(parsed.prompt);
|
|
729
792
|
}
|
|
730
793
|
async executeBuiltin(parsed) {
|
|
@@ -749,6 +812,9 @@ class FullscreenTui {
|
|
|
749
812
|
case 'skill-creator':
|
|
750
813
|
await this.executeSkillCreator(parsed.name, parsed.rawArgs);
|
|
751
814
|
return;
|
|
815
|
+
case 'set-model':
|
|
816
|
+
await this.executeSetModel(parsed.rawArgs);
|
|
817
|
+
return;
|
|
752
818
|
case 'sessions':
|
|
753
819
|
await this.refreshSessions({ createIfMissing: true, selectedSessionId: this.selectedSessionId });
|
|
754
820
|
await this.refreshCommands();
|
|
@@ -931,6 +997,78 @@ class FullscreenTui {
|
|
|
931
997
|
}
|
|
932
998
|
}
|
|
933
999
|
}
|
|
1000
|
+
async executeShellCommand(commandText) {
|
|
1001
|
+
const trimmedCommand = commandText.trim();
|
|
1002
|
+
if (!trimmedCommand) {
|
|
1003
|
+
this.statusLine = 'Enter a shell command after !.';
|
|
1004
|
+
this.requestRender();
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
const sessionId = this.selectedSessionId || 'global';
|
|
1008
|
+
const activity = this.activityFor(sessionId);
|
|
1009
|
+
this.lastSubmittedInput = { kind: 'shell', command: trimmedCommand };
|
|
1010
|
+
this.focusedPane = 'messages';
|
|
1011
|
+
this.paneScroll.messages = 0;
|
|
1012
|
+
this.paneScroll.process = 0;
|
|
1013
|
+
this.beginExecutionPreview(sessionId, 'shell', {
|
|
1014
|
+
role: 'system',
|
|
1015
|
+
kind: 'output',
|
|
1016
|
+
tag: 'shell',
|
|
1017
|
+
content: `!${trimmedCommand}`,
|
|
1018
|
+
}, 'shell');
|
|
1019
|
+
activity.pushLine(`shell !${trimmedCommand}`);
|
|
1020
|
+
this.busy = true;
|
|
1021
|
+
this.currentAbortController = new AbortController();
|
|
1022
|
+
this.startAnimation();
|
|
1023
|
+
this.statusLine = `Running !${trimmedCommand}...`;
|
|
1024
|
+
this.requestRender();
|
|
1025
|
+
try {
|
|
1026
|
+
const result = await runShellCommand(this.workspaceRoot, trimmedCommand, {
|
|
1027
|
+
sandbox: this.options.sandbox,
|
|
1028
|
+
signal: this.currentAbortController.signal,
|
|
1029
|
+
onEvent: (event) => {
|
|
1030
|
+
activity.handle(event);
|
|
1031
|
+
this.requestRender();
|
|
1032
|
+
},
|
|
1033
|
+
});
|
|
1034
|
+
activity.finish();
|
|
1035
|
+
await this.refreshCommands();
|
|
1036
|
+
this.finishExecutionPreview(result.success
|
|
1037
|
+
? { persist: true, finalText: formatShellCommandSummary(result) }
|
|
1038
|
+
: { persist: true, error: formatShellCommandSummary(result) });
|
|
1039
|
+
this.statusLine = result.success ? 'Shell command finished.' : 'Shell command failed.';
|
|
1040
|
+
}
|
|
1041
|
+
catch (error) {
|
|
1042
|
+
activity.finish();
|
|
1043
|
+
const message = error.message;
|
|
1044
|
+
this.finishExecutionPreview({ persist: true, error: message });
|
|
1045
|
+
this.statusLine = isAbortError(error) ? 'Shell command cancelled.' : 'Shell command failed.';
|
|
1046
|
+
}
|
|
1047
|
+
finally {
|
|
1048
|
+
this.busy = false;
|
|
1049
|
+
this.currentAbortController = null;
|
|
1050
|
+
this.stopAnimation();
|
|
1051
|
+
if (this.exitRequested) {
|
|
1052
|
+
this.close();
|
|
1053
|
+
}
|
|
1054
|
+
else {
|
|
1055
|
+
this.requestRender();
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
async executeSetModel(rawArgs) {
|
|
1060
|
+
try {
|
|
1061
|
+
const { model, slot } = parseSetModelCommandArgs(rawArgs);
|
|
1062
|
+
const result = await setModel(this.workspaceRoot, model, slot);
|
|
1063
|
+
const slotsLabel = result.updatedSlots.join(', ');
|
|
1064
|
+
this.currentProcessActivity().pushLine(`config model ${result.modelId} slots=${slotsLabel}`);
|
|
1065
|
+
this.statusLine = `Model set to ${result.modelId} for ${slotsLabel}. Applies on the next turn.`;
|
|
1066
|
+
}
|
|
1067
|
+
catch (error) {
|
|
1068
|
+
this.statusLine = error.message;
|
|
1069
|
+
}
|
|
1070
|
+
this.requestRender();
|
|
1071
|
+
}
|
|
934
1072
|
async requestClarification(promptText) {
|
|
935
1073
|
this.ensureClarificationVisible(promptText);
|
|
936
1074
|
return this.promptForValue(promptText, 'clarify');
|
|
@@ -1101,7 +1239,8 @@ class FullscreenTui {
|
|
|
1101
1239
|
label: 'Run',
|
|
1102
1240
|
items: [
|
|
1103
1241
|
{ id: 'run.prompt', label: 'Send Prompt…', description: 'Return to the command bar and enter a freeform prompt.', shortcut: 'Enter' },
|
|
1104
|
-
{ id: 'run.
|
|
1242
|
+
{ id: 'run.shell', label: 'Run Shell Command…', description: 'Prefill the command bar for a direct workspace shell command.' },
|
|
1243
|
+
{ id: 'run.repeat', label: 'Repeat Last Command', description: 'Re-run the last prompt, shell command, or skill invocation.', enabled: !!this.lastSubmittedInput },
|
|
1105
1244
|
{ id: 'run.cancel', label: 'Cancel Current Execution', description: 'Abort the running task or skill.', shortcut: '/cancel', enabled: this.busy },
|
|
1106
1245
|
{ id: 'run.clear', label: 'Clear Execution Pane', description: 'Discard the current session execution log.' },
|
|
1107
1246
|
{ id: 'run.refreshSkills', label: 'Refresh Skill Catalog', description: 'Re-scan the workspace for compiled skills.' },
|
|
@@ -1124,7 +1263,7 @@ class FullscreenTui {
|
|
|
1124
1263
|
label: 'Help',
|
|
1125
1264
|
items: [
|
|
1126
1265
|
{ id: 'help.shortcuts', label: 'Keyboard Shortcuts', description: 'Show the fullscreen keyboard map.' },
|
|
1127
|
-
{ id: 'help.slash', label: '
|
|
1266
|
+
{ id: 'help.slash', label: 'Commands', description: 'Show slash commands, shell commands, and direct skill invocation.' },
|
|
1128
1267
|
{ id: 'help.about', label: 'About This TUI', description: 'Show a short explanation of the fullscreen workspace.' },
|
|
1129
1268
|
],
|
|
1130
1269
|
},
|
|
@@ -1204,6 +1343,13 @@ class FullscreenTui {
|
|
|
1204
1343
|
this.closeMenuMode();
|
|
1205
1344
|
this.statusLine = 'Command bar ready.';
|
|
1206
1345
|
return;
|
|
1346
|
+
case 'run.shell':
|
|
1347
|
+
this.closeMenuMode();
|
|
1348
|
+
this.inputValue = '!';
|
|
1349
|
+
this.cursor = this.inputValue.length;
|
|
1350
|
+
this.statusLine = formatShellModeStatus(this.workspaceRoot, this.shellWorkspacePath, this.options.sandbox);
|
|
1351
|
+
this.requestRender();
|
|
1352
|
+
return;
|
|
1207
1353
|
case 'run.repeat':
|
|
1208
1354
|
await this.repeatLastCommand();
|
|
1209
1355
|
return;
|
|
@@ -1245,13 +1391,14 @@ class FullscreenTui {
|
|
|
1245
1391
|
this.openTextViewer('Keyboard Shortcuts', getShortcutHelpLines().join('\n'), { preferredExtension: '.txt' });
|
|
1246
1392
|
return;
|
|
1247
1393
|
case 'help.slash':
|
|
1248
|
-
this.openTextViewer('
|
|
1394
|
+
this.openTextViewer('Commands', getSlashHelpLines().join('\n'), { preferredExtension: '.txt' });
|
|
1249
1395
|
return;
|
|
1250
1396
|
case 'help.about':
|
|
1251
1397
|
this.openTextViewer('About This TUI', [
|
|
1252
1398
|
'DeepClause fullscreen TUI',
|
|
1253
1399
|
'',
|
|
1254
1400
|
'Use F10 or Ctrl+G for the menu bar, Ctrl+W to cycle panes, and /cancel to stop a running execution.',
|
|
1401
|
+
'Type !<command> to run a direct shell command in the configured workspace shell.',
|
|
1255
1402
|
'The Skills and Files menus open searchable pickers, and Ctrl+P opens the action palette directly.',
|
|
1256
1403
|
].join('\n'), { preferredExtension: '.txt' });
|
|
1257
1404
|
return;
|
|
@@ -1787,7 +1934,7 @@ class FullscreenTui {
|
|
|
1787
1934
|
async repeatLastCommand() {
|
|
1788
1935
|
if (!this.lastSubmittedInput) {
|
|
1789
1936
|
this.closeMenuMode();
|
|
1790
|
-
this.statusLine = 'No previous prompt or skill to repeat yet.';
|
|
1937
|
+
this.statusLine = 'No previous prompt, shell command, or skill to repeat yet.';
|
|
1791
1938
|
this.requestRender();
|
|
1792
1939
|
return;
|
|
1793
1940
|
}
|
|
@@ -1802,6 +1949,10 @@ class FullscreenTui {
|
|
|
1802
1949
|
await this.executeSkill(this.lastSubmittedInput.name, this.lastSubmittedInput.args);
|
|
1803
1950
|
return;
|
|
1804
1951
|
}
|
|
1952
|
+
if (this.lastSubmittedInput.kind === 'shell') {
|
|
1953
|
+
await this.executeShellCommand(this.lastSubmittedInput.command);
|
|
1954
|
+
return;
|
|
1955
|
+
}
|
|
1805
1956
|
if (this.lastSubmittedInput.kind === 'builtin') {
|
|
1806
1957
|
await this.executeBuiltin(this.lastSubmittedInput);
|
|
1807
1958
|
}
|
|
@@ -1818,7 +1969,9 @@ class FullscreenTui {
|
|
|
1818
1969
|
kind,
|
|
1819
1970
|
rootTag,
|
|
1820
1971
|
activeChildTag: kind === 'skill' ? rootTag : undefined,
|
|
1821
|
-
entries:
|
|
1972
|
+
entries: kind === 'shell'
|
|
1973
|
+
? [lead]
|
|
1974
|
+
: [lead, { role: 'assistant', content: '', pending: true }],
|
|
1822
1975
|
};
|
|
1823
1976
|
}
|
|
1824
1977
|
updatePreviewFromEvent(logEvent) {
|
|
@@ -1863,6 +2016,9 @@ class FullscreenTui {
|
|
|
1863
2016
|
if (this.currentPreview.kind === 'task') {
|
|
1864
2017
|
return logEvent.scope === 'main';
|
|
1865
2018
|
}
|
|
2019
|
+
if (this.currentPreview.kind === 'shell') {
|
|
2020
|
+
return false;
|
|
2021
|
+
}
|
|
1866
2022
|
return logEvent.scope === 'child' && logEvent.childSlug === this.currentPreview.rootTag;
|
|
1867
2023
|
}
|
|
1868
2024
|
insertPreviewMessage(entry) {
|
|
@@ -1919,6 +2075,23 @@ class FullscreenTui {
|
|
|
1919
2075
|
return;
|
|
1920
2076
|
}
|
|
1921
2077
|
this.currentPreview.activeChildTag = undefined;
|
|
2078
|
+
if (this.currentPreview.kind === 'shell') {
|
|
2079
|
+
const detail = typeof options.error === 'string' && options.error.trim()
|
|
2080
|
+
? { role: 'system', kind: 'output', tag: 'shell', content: options.error, error: true }
|
|
2081
|
+
: typeof options.finalText === 'string' && options.finalText.trim()
|
|
2082
|
+
? { role: 'system', kind: 'output', tag: 'shell', content: options.finalText }
|
|
2083
|
+
: null;
|
|
2084
|
+
if (detail) {
|
|
2085
|
+
this.currentPreview.entries.push(detail);
|
|
2086
|
+
}
|
|
2087
|
+
if (options.persist) {
|
|
2088
|
+
const existing = this.ephemeralMessagesBySessionId.get(this.currentPreview.sessionId) ?? [];
|
|
2089
|
+
existing.push(...this.currentPreview.entries.map((entry) => ({ ...entry, pending: false })));
|
|
2090
|
+
this.ephemeralMessagesBySessionId.set(this.currentPreview.sessionId, existing);
|
|
2091
|
+
}
|
|
2092
|
+
this.currentPreview = null;
|
|
2093
|
+
return;
|
|
2094
|
+
}
|
|
1922
2095
|
const assistant = this.ensurePreviewAssistantMessage();
|
|
1923
2096
|
if (typeof options.finalText === 'string' && options.finalText.trim()) {
|
|
1924
2097
|
assistant.content = options.finalText;
|
|
@@ -2029,24 +2202,49 @@ class FullscreenTui {
|
|
|
2029
2202
|
return this.activityFor(this.selectedSessionId || 'global');
|
|
2030
2203
|
}
|
|
2031
2204
|
insertText(text) {
|
|
2205
|
+
const previousInput = this.inputValue;
|
|
2032
2206
|
this.inputValue = `${this.inputValue.slice(0, this.cursor)}${text}${this.inputValue.slice(this.cursor)}`;
|
|
2033
2207
|
this.cursor += text.length;
|
|
2208
|
+
this.refreshCommandBarStatus(previousInput);
|
|
2034
2209
|
}
|
|
2035
2210
|
deleteBackward() {
|
|
2036
2211
|
if (this.cursor === 0) {
|
|
2037
2212
|
return;
|
|
2038
2213
|
}
|
|
2214
|
+
const previousInput = this.inputValue;
|
|
2039
2215
|
this.inputValue = `${this.inputValue.slice(0, this.cursor - 1)}${this.inputValue.slice(this.cursor)}`;
|
|
2040
2216
|
this.cursor -= 1;
|
|
2217
|
+
this.refreshCommandBarStatus(previousInput);
|
|
2041
2218
|
}
|
|
2042
2219
|
deleteForward() {
|
|
2043
2220
|
if (this.cursor >= this.inputValue.length) {
|
|
2044
2221
|
return;
|
|
2045
2222
|
}
|
|
2223
|
+
const previousInput = this.inputValue;
|
|
2046
2224
|
this.inputValue = `${this.inputValue.slice(0, this.cursor)}${this.inputValue.slice(this.cursor + 1)}`;
|
|
2225
|
+
this.refreshCommandBarStatus(previousInput);
|
|
2047
2226
|
}
|
|
2048
2227
|
async refreshCommands() {
|
|
2049
2228
|
this.commands = await listCommands(this.workspaceRoot);
|
|
2229
|
+
await this.refreshShellContext();
|
|
2230
|
+
}
|
|
2231
|
+
async refreshShellContext() {
|
|
2232
|
+
const config = await loadConfig(this.workspaceRoot);
|
|
2233
|
+
this.shellWorkspacePath = path.resolve(this.workspaceRoot, config.workspace || './workspace');
|
|
2234
|
+
}
|
|
2235
|
+
refreshCommandBarStatus(previousInput = '') {
|
|
2236
|
+
if (this.busy || this.pendingPrompt || this.uiMode !== 'command') {
|
|
2237
|
+
return;
|
|
2238
|
+
}
|
|
2239
|
+
const wasShell = previousInput.trimStart().startsWith('!');
|
|
2240
|
+
const isShell = this.inputValue.trimStart().startsWith('!');
|
|
2241
|
+
if (isShell) {
|
|
2242
|
+
this.statusLine = formatShellModeStatus(this.workspaceRoot, this.shellWorkspacePath, this.options.sandbox);
|
|
2243
|
+
return;
|
|
2244
|
+
}
|
|
2245
|
+
if (wasShell) {
|
|
2246
|
+
this.statusLine = 'Command bar ready.';
|
|
2247
|
+
}
|
|
2050
2248
|
}
|
|
2051
2249
|
async refreshSessions(options = {}) {
|
|
2052
2250
|
let sessions = await listConductorSessions(this.workspaceRoot);
|
|
@@ -2284,6 +2482,7 @@ class FullscreenTui {
|
|
|
2284
2482
|
return ['No session selected.'];
|
|
2285
2483
|
}
|
|
2286
2484
|
const contextSize = summarizeContextSize(this.sessionDetail);
|
|
2485
|
+
const systemAssetSources = getSystemAssetSourcePaths(this.workspaceRoot);
|
|
2287
2486
|
const usageEntries = Object.entries(this.sessionDetail.usageByModel ?? {})
|
|
2288
2487
|
.sort((left, right) => right[1].totalTokens - left[1].totalTokens || left[0].localeCompare(right[0]));
|
|
2289
2488
|
const body = [
|
|
@@ -2294,6 +2493,17 @@ class FullscreenTui {
|
|
|
2294
2493
|
`Assistant Memory ${formatByteSize(contextSize.assistantMemoryBytes)} (~${formatInteger(contextSize.assistantMemoryTokens)} tok)`,
|
|
2295
2494
|
`Total ${formatByteSize(contextSize.totalBytes)} (~${formatInteger(contextSize.totalTokens)} tok)`,
|
|
2296
2495
|
'',
|
|
2496
|
+
'System Asset Sources',
|
|
2497
|
+
`Conductor DML ${formatSystemAssetSourcePath(this.workspaceRoot, systemAssetSources.conductorDml)}`,
|
|
2498
|
+
`Conductor Prompt ${formatSystemAssetSourcePath(this.workspaceRoot, systemAssetSources.conductorPrompt)}`,
|
|
2499
|
+
`Skill Creator DML ${formatSystemAssetSourcePath(this.workspaceRoot, systemAssetSources.skillCreatorDml)}`,
|
|
2500
|
+
`Skill Creator Prompt ${formatSystemAssetSourcePath(this.workspaceRoot, systemAssetSources.skillCreatorPrompt)}`,
|
|
2501
|
+
'Changes apply on the next turn or /compile run. No TUI reload is required.',
|
|
2502
|
+
'',
|
|
2503
|
+
'Shell Execution',
|
|
2504
|
+
`Backend ${this.options.sandbox ? 'sandbox' : 'host'}`,
|
|
2505
|
+
`CWD ${this.shellWorkspacePath}`,
|
|
2506
|
+
'',
|
|
2297
2507
|
'Session Token Usage',
|
|
2298
2508
|
];
|
|
2299
2509
|
if (usageEntries.length === 0) {
|
|
@@ -2553,7 +2763,7 @@ async function startLineTui(workspaceRoot = process.cwd(), options = {}) {
|
|
|
2553
2763
|
if (!line) {
|
|
2554
2764
|
continue;
|
|
2555
2765
|
}
|
|
2556
|
-
const parsed =
|
|
2766
|
+
const parsed = parseCommandBarInput(line);
|
|
2557
2767
|
if (parsed.kind === 'builtin') {
|
|
2558
2768
|
switch (parsed.name) {
|
|
2559
2769
|
case 'cancel':
|
|
@@ -2611,8 +2821,41 @@ async function startLineTui(workspaceRoot = process.cwd(), options = {}) {
|
|
|
2611
2821
|
console.log(divider('-'));
|
|
2612
2822
|
console.log('');
|
|
2613
2823
|
continue;
|
|
2824
|
+
case 'set-model': {
|
|
2825
|
+
try {
|
|
2826
|
+
const { model, slot } = parseSetModelCommandArgs(parsed.rawArgs);
|
|
2827
|
+
const result = await setModel(workspaceRoot, model, slot);
|
|
2828
|
+
console.log(`Model set to ${result.modelId} (${result.updatedSlots.join(', ')}).`);
|
|
2829
|
+
}
|
|
2830
|
+
catch (error) {
|
|
2831
|
+
console.log(`${paint('error', ANSI.red)} ${error.message}`);
|
|
2832
|
+
}
|
|
2833
|
+
continue;
|
|
2834
|
+
}
|
|
2614
2835
|
}
|
|
2615
2836
|
}
|
|
2837
|
+
if (parsed.kind === 'shell') {
|
|
2838
|
+
console.log(divider('-'));
|
|
2839
|
+
console.log(`${paint('shell', ANSI.dim)} !${parsed.command}`);
|
|
2840
|
+
console.log(divider('-'));
|
|
2841
|
+
const printer = new LiveExecutionPrinter();
|
|
2842
|
+
try {
|
|
2843
|
+
const result = await runShellCommand(workspaceRoot, parsed.command, {
|
|
2844
|
+
sandbox: options.sandbox,
|
|
2845
|
+
onEvent: (event) => printer.handle(event),
|
|
2846
|
+
});
|
|
2847
|
+
printer.finish();
|
|
2848
|
+
console.log(formatShellCommandSummary(result));
|
|
2849
|
+
}
|
|
2850
|
+
catch (error) {
|
|
2851
|
+
printer.finish();
|
|
2852
|
+
console.log(`${paint('error', ANSI.red)} ${error.message}`);
|
|
2853
|
+
}
|
|
2854
|
+
console.log('');
|
|
2855
|
+
console.log(divider('-'));
|
|
2856
|
+
console.log('');
|
|
2857
|
+
continue;
|
|
2858
|
+
}
|
|
2616
2859
|
if (parsed.kind === 'skill') {
|
|
2617
2860
|
console.log(divider('-'));
|
|
2618
2861
|
console.log(`${paint('skill', ANSI.dim)} /${parsed.name}${parsed.args.length > 0 ? ` ${parsed.args.join(' ')}` : ''}`);
|
|
@@ -2734,6 +2977,40 @@ async function runSkillCreatorCommand(workspaceRoot, sessionId, spec, options =
|
|
|
2734
2977
|
onEvent: options.onEvent,
|
|
2735
2978
|
});
|
|
2736
2979
|
}
|
|
2980
|
+
async function runShellCommand(workspaceRoot, command, options = {}) {
|
|
2981
|
+
const trimmedCommand = command.trim();
|
|
2982
|
+
if (!trimmedCommand) {
|
|
2983
|
+
throw new Error('command is required');
|
|
2984
|
+
}
|
|
2985
|
+
const toolName = 'shell';
|
|
2986
|
+
const toolArgs = { command: trimmedCommand };
|
|
2987
|
+
const emit = (event) => options.onEvent?.({ scope: 'main', event });
|
|
2988
|
+
emit(buildToolStartEvent(toolName, toolArgs));
|
|
2989
|
+
let shellManager = null;
|
|
2990
|
+
try {
|
|
2991
|
+
const config = await loadConfig(workspaceRoot);
|
|
2992
|
+
const workspacePath = path.resolve(workspaceRoot, config.workspace || './workspace');
|
|
2993
|
+
shellManager = createShellManager({
|
|
2994
|
+
workspacePath,
|
|
2995
|
+
sandbox: options.sandbox,
|
|
2996
|
+
});
|
|
2997
|
+
const observer = createShellToolEventBridge({
|
|
2998
|
+
toolName,
|
|
2999
|
+
toolArgs,
|
|
3000
|
+
emit,
|
|
3001
|
+
});
|
|
3002
|
+
const result = await shellManager.exec(trimmedCommand, options.signal, observer);
|
|
3003
|
+
emit(buildToolCompletionEvent(toolName, toolArgs, result));
|
|
3004
|
+
return result;
|
|
3005
|
+
}
|
|
3006
|
+
catch (error) {
|
|
3007
|
+
emit(buildToolFailureEvent(toolName, toolArgs, error));
|
|
3008
|
+
throw error;
|
|
3009
|
+
}
|
|
3010
|
+
finally {
|
|
3011
|
+
await shellManager?.dispose();
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
2737
3014
|
function formatSkillCreatorSummary(workspaceRoot, result) {
|
|
2738
3015
|
const slug = typeof result.slug === 'string' ? result.slug : 'unknown-skill';
|
|
2739
3016
|
const outputPath = typeof result.output_path === 'string' ? result.output_path : '';
|
|
@@ -2743,6 +3020,15 @@ function formatSkillCreatorSummary(workspaceRoot, result) {
|
|
|
2743
3020
|
const relativeOutputPath = path.relative(workspaceRoot, outputPath);
|
|
2744
3021
|
return `Published /${slug} to ${relativeOutputPath || outputPath}.`;
|
|
2745
3022
|
}
|
|
3023
|
+
function formatShellCommandSummary(result) {
|
|
3024
|
+
if (result.success) {
|
|
3025
|
+
return result.summary || 'Shell command completed successfully.';
|
|
3026
|
+
}
|
|
3027
|
+
return result.summary || `Shell command failed with exit code ${result.exitCode}.`;
|
|
3028
|
+
}
|
|
3029
|
+
function isAbortError(error) {
|
|
3030
|
+
return error instanceof Error && error.name === 'AbortError';
|
|
3031
|
+
}
|
|
2746
3032
|
export function previewMessageFromEvent(logEvent) {
|
|
2747
3033
|
switch (logEvent.event.type) {
|
|
2748
3034
|
case 'output':
|
|
@@ -2826,7 +3112,14 @@ export function parseCommandArgs(rawArgs) {
|
|
|
2826
3112
|
}
|
|
2827
3113
|
return args;
|
|
2828
3114
|
}
|
|
2829
|
-
export function
|
|
3115
|
+
export function parseCommandBarInput(line) {
|
|
3116
|
+
const trimmedStart = line.trimStart();
|
|
3117
|
+
if (trimmedStart.startsWith('\\!')) {
|
|
3118
|
+
return { kind: 'text', prompt: trimmedStart.slice(1).trim() };
|
|
3119
|
+
}
|
|
3120
|
+
if (trimmedStart.startsWith('!')) {
|
|
3121
|
+
return { kind: 'shell', command: trimmedStart.slice(1).trim() };
|
|
3122
|
+
}
|
|
2830
3123
|
const trimmed = line.trim();
|
|
2831
3124
|
if (!trimmed.startsWith('/')) {
|
|
2832
3125
|
return { kind: 'text', prompt: trimmed };
|
|
@@ -2858,6 +3151,9 @@ export function parseSlashInput(line) {
|
|
|
2858
3151
|
args: parseCommandArgs(rawArgs),
|
|
2859
3152
|
};
|
|
2860
3153
|
}
|
|
3154
|
+
export function parseSlashInput(line) {
|
|
3155
|
+
return parseCommandBarInput(line);
|
|
3156
|
+
}
|
|
2861
3157
|
export function canSubmitParsedInputWhileBusy(parsed) {
|
|
2862
3158
|
return parsed.kind === 'builtin' && (parsed.name === 'cancel' || parsed.name === 'exit' || parsed.name === 'quit');
|
|
2863
3159
|
}
|
|
@@ -2940,11 +3236,56 @@ async function createSessionInteractive(rl, workspaceRoot) {
|
|
|
2940
3236
|
function renderHeader(session) {
|
|
2941
3237
|
console.log(divider('='));
|
|
2942
3238
|
console.log(`${paint('DeepClause', ANSI.bold, ANSI.cyan)} ${paint('interactive conductor', ANSI.dim)}`);
|
|
2943
|
-
console.log(`${paint('commands', ANSI.dim)} /compile <spec> /new /sessions /help /exit /skill args`);
|
|
3239
|
+
console.log(`${paint('commands', ANSI.dim)} /compile <spec> /set-model <model> /new /sessions /help /exit /skill args`);
|
|
2944
3240
|
console.log(`${paint('session', ANSI.dim)} ${paint(session.id, ANSI.cyan)}`);
|
|
2945
3241
|
console.log(divider('='));
|
|
2946
3242
|
console.log('');
|
|
2947
3243
|
}
|
|
3244
|
+
export function parseSetModelCommandArgs(rawArgs) {
|
|
3245
|
+
const args = parseCommandArgs(rawArgs);
|
|
3246
|
+
let model;
|
|
3247
|
+
let slot;
|
|
3248
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
3249
|
+
const arg = args[index];
|
|
3250
|
+
if (arg === '--slot') {
|
|
3251
|
+
const candidate = args[index + 1];
|
|
3252
|
+
if (!candidate) {
|
|
3253
|
+
throw new Error('Provide a slot after --slot.');
|
|
3254
|
+
}
|
|
3255
|
+
if (!isModelSlot(candidate)) {
|
|
3256
|
+
throw new Error('Slot must be one of: gateway, run, compile.');
|
|
3257
|
+
}
|
|
3258
|
+
if (slot) {
|
|
3259
|
+
throw new Error('Provide --slot only once.');
|
|
3260
|
+
}
|
|
3261
|
+
slot = candidate;
|
|
3262
|
+
index += 1;
|
|
3263
|
+
continue;
|
|
3264
|
+
}
|
|
3265
|
+
if (arg.startsWith('--slot=')) {
|
|
3266
|
+
const candidate = arg.slice('--slot='.length);
|
|
3267
|
+
if (!isModelSlot(candidate)) {
|
|
3268
|
+
throw new Error('Slot must be one of: gateway, run, compile.');
|
|
3269
|
+
}
|
|
3270
|
+
if (slot) {
|
|
3271
|
+
throw new Error('Provide --slot only once.');
|
|
3272
|
+
}
|
|
3273
|
+
slot = candidate;
|
|
3274
|
+
continue;
|
|
3275
|
+
}
|
|
3276
|
+
if (arg.startsWith('--')) {
|
|
3277
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
3278
|
+
}
|
|
3279
|
+
if (model) {
|
|
3280
|
+
throw new Error('Provide exactly one model for /set-model.');
|
|
3281
|
+
}
|
|
3282
|
+
model = arg;
|
|
3283
|
+
}
|
|
3284
|
+
if (!model) {
|
|
3285
|
+
throw new Error('Provide a model after /set-model.');
|
|
3286
|
+
}
|
|
3287
|
+
return { model, slot };
|
|
3288
|
+
}
|
|
2948
3289
|
function streamLabel(logEvent) {
|
|
2949
3290
|
return logEvent.scope === 'child'
|
|
2950
3291
|
? `${CHILD_EVENT_INDENT}[${logEvent.childSlug ?? '?'}] llm`
|
|
@@ -2955,6 +3296,16 @@ function formatEventPrefix(logEvent) {
|
|
|
2955
3296
|
? `${CHILD_EVENT_INDENT}[${logEvent.childSlug ?? '?'}] `
|
|
2956
3297
|
: '';
|
|
2957
3298
|
}
|
|
3299
|
+
function toolScopeKey(logEvent) {
|
|
3300
|
+
return logEvent.scope === 'child'
|
|
3301
|
+
? `child:${logEvent.childSlug ?? '?'}`
|
|
3302
|
+
: 'main';
|
|
3303
|
+
}
|
|
3304
|
+
function toolScopeLabel(logEvent) {
|
|
3305
|
+
return logEvent.scope === 'child'
|
|
3306
|
+
? logEvent.childSlug ?? '?'
|
|
3307
|
+
: 'main';
|
|
3308
|
+
}
|
|
2958
3309
|
function parseTaggedPrompt(promptText) {
|
|
2959
3310
|
const match = promptText.match(/^\[([^\]]+)\]\s*(.*)$/);
|
|
2960
3311
|
if (!match) {
|
|
@@ -2996,19 +3347,57 @@ export function formatDisplayMessageHeader(entry, spinner = '') {
|
|
|
2996
3347
|
return formatSystemMessageHeader(entry, spinner);
|
|
2997
3348
|
}
|
|
2998
3349
|
}
|
|
2999
|
-
function
|
|
3000
|
-
|
|
3001
|
-
|
|
3350
|
+
function formatSystemAssetSourcePath(workspaceRoot, filePath) {
|
|
3351
|
+
const relativePath = path.relative(workspaceRoot, filePath);
|
|
3352
|
+
if (relativePath && !relativePath.startsWith('..') && !path.isAbsolute(relativePath)) {
|
|
3353
|
+
return relativePath || '.';
|
|
3002
3354
|
}
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3355
|
+
return filePath;
|
|
3356
|
+
}
|
|
3357
|
+
function formatToolEventLine(logEvent) {
|
|
3358
|
+
const { event } = logEvent;
|
|
3359
|
+
if (!event.toolName || IGNORED_LIVE_LOG_TOOLS.has(event.toolName)) {
|
|
3360
|
+
return null;
|
|
3361
|
+
}
|
|
3362
|
+
const prefix = formatEventPrefix(logEvent);
|
|
3363
|
+
const callLabel = `${event.toolName}(${formatToolArgs(event.toolArgs, 80)})`;
|
|
3364
|
+
if (!event.toolState) {
|
|
3365
|
+
return `${prefix}tool ${callLabel}`;
|
|
3010
3366
|
}
|
|
3011
|
-
return
|
|
3367
|
+
return `${prefix}tool ${callLabel} ${event.toolState}${formatToolEventDetails(event)}`;
|
|
3368
|
+
}
|
|
3369
|
+
function formatToolEventDetails(event) {
|
|
3370
|
+
const details = [];
|
|
3371
|
+
if (typeof event.toolPid === 'number') {
|
|
3372
|
+
details.push(`pid=${event.toolPid}`);
|
|
3373
|
+
}
|
|
3374
|
+
else if (event.toolBackend === 'sandbox') {
|
|
3375
|
+
details.push('sandbox');
|
|
3376
|
+
}
|
|
3377
|
+
if (typeof event.toolExitCode === 'number') {
|
|
3378
|
+
details.push(`exit=${event.toolExitCode}`);
|
|
3379
|
+
}
|
|
3380
|
+
const message = event.toolError
|
|
3381
|
+
?? (event.toolSummary && event.toolSummary !== 'Command completed successfully' ? event.toolSummary : undefined);
|
|
3382
|
+
if (message) {
|
|
3383
|
+
details.push(message);
|
|
3384
|
+
}
|
|
3385
|
+
return details.length > 0 ? ` ${details.join(' ')}` : '';
|
|
3386
|
+
}
|
|
3387
|
+
function formatActiveToolStatus(entry) {
|
|
3388
|
+
const details = [];
|
|
3389
|
+
if (typeof entry.toolPid === 'number') {
|
|
3390
|
+
details.push(`pid=${entry.toolPid}`);
|
|
3391
|
+
}
|
|
3392
|
+
else if (entry.toolBackend === 'sandbox') {
|
|
3393
|
+
details.push('sandbox');
|
|
3394
|
+
}
|
|
3395
|
+
const detailSuffix = details.length > 0 ? ` ${details.join(' ')}` : '';
|
|
3396
|
+
return `${entry.scopeLabel} ${entry.toolName} ${entry.toolState}${detailSuffix}`;
|
|
3397
|
+
}
|
|
3398
|
+
function formatShellModeStatus(workspaceRoot, shellWorkspacePath, sandbox) {
|
|
3399
|
+
const displayPath = path.relative(workspaceRoot, shellWorkspacePath) || '.';
|
|
3400
|
+
return `Shell mode: ${sandbox ? 'AgentVM sandbox' : 'host shell'} in ${displayPath}. Enter runs, /cancel stops.`;
|
|
3012
3401
|
}
|
|
3013
3402
|
function buildHelpLines() {
|
|
3014
3403
|
return [
|
|
@@ -3017,10 +3406,12 @@ function buildHelpLines() {
|
|
|
3017
3406
|
'/sessions refresh or choose sessions',
|
|
3018
3407
|
'/compile <spec> compile and publish a new local skill',
|
|
3019
3408
|
'/skill-creator <spec> alias for /compile',
|
|
3409
|
+
'/set-model <model> [--slot <slot>] update the configured model selection',
|
|
3020
3410
|
'/cancel abort the current execution',
|
|
3021
3411
|
'/help show this help',
|
|
3022
3412
|
'/quit exit the TUI',
|
|
3023
3413
|
'/<skill> [args] run a compiled skill directly',
|
|
3414
|
+
'!<command> run a shell command directly in the workspace shell',
|
|
3024
3415
|
'keys',
|
|
3025
3416
|
'F10 / Ctrl+G open the menu bar',
|
|
3026
3417
|
'Ctrl+P open the action palette',
|
|
@@ -3041,6 +3432,9 @@ function getShortcutHelpLines() {
|
|
|
3041
3432
|
const keysIndex = lines.indexOf('keys');
|
|
3042
3433
|
return keysIndex === -1 ? [] : lines.slice(keysIndex);
|
|
3043
3434
|
}
|
|
3435
|
+
function isModelSlot(value) {
|
|
3436
|
+
return MODEL_SLOTS.includes(value);
|
|
3437
|
+
}
|
|
3044
3438
|
function computePaneWidths(columns) {
|
|
3045
3439
|
const available = Math.max(36, columns - 2);
|
|
3046
3440
|
let left = Math.max(18, Math.floor(available * 0.2));
|