@gajae-code/coding-agent 0.5.4 → 0.6.1
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/CHANGELOG.md +23 -0
- package/dist/types/cli/web-search-cli.d.ts +12 -0
- package/dist/types/commands/rlm.d.ts +10 -0
- package/dist/types/commands/web-search.d.ts +54 -0
- package/dist/types/config/keybindings.d.ts +10 -0
- package/dist/types/config/model-profiles.d.ts +2 -1
- package/dist/types/config/model-registry.d.ts +3 -0
- package/dist/types/config/models-config-schema.d.ts +3 -0
- package/dist/types/config/settings-schema.d.ts +61 -3
- package/dist/types/edit/notebook.d.ts +3 -0
- package/dist/types/eval/py/executor.d.ts +3 -0
- package/dist/types/eval/py/kernel.d.ts +3 -1
- package/dist/types/eval/py/runtime.d.ts +9 -1
- package/dist/types/exec/bash-executor.d.ts +4 -0
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -0
- package/dist/types/extensibility/custom-tools/wrapper.d.ts +1 -0
- package/dist/types/extensibility/extensions/types.d.ts +2 -0
- package/dist/types/extensibility/extensions/wrapper.d.ts +1 -0
- package/dist/types/gjc-runtime/launch-tmux.d.ts +6 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +14 -0
- package/dist/types/gjc-runtime/tmux-common.d.ts +6 -0
- package/dist/types/gjc-runtime/tmux-gc.d.ts +3 -3
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +4 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +18 -0
- package/dist/types/goals/state.d.ts +1 -1
- package/dist/types/goals/tools/goal-tool.d.ts +2 -0
- package/dist/types/main.d.ts +11 -0
- package/dist/types/modes/components/custom-editor.d.ts +4 -2
- package/dist/types/modes/components/custom-model-preset-wizard.d.ts +12 -0
- package/dist/types/modes/components/model-selector.d.ts +5 -2
- package/dist/types/modes/components/status-line.d.ts +4 -1
- package/dist/types/modes/controllers/input-controller.d.ts +3 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
- package/dist/types/modes/print-mode.d.ts +6 -0
- package/dist/types/modes/rpc/rpc-client.d.ts +21 -0
- package/dist/types/modes/rpc/rpc-socket-security.d.ts +7 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +13 -0
- package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +2 -0
- package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +1 -0
- package/dist/types/rlm/artifacts.d.ts +9 -0
- package/dist/types/rlm/complete-research-tool.d.ts +35 -0
- package/dist/types/rlm/data-context.d.ts +6 -0
- package/dist/types/rlm/index.d.ts +35 -0
- package/dist/types/rlm/notebook.d.ts +12 -0
- package/dist/types/rlm/preset.d.ts +23 -0
- package/dist/types/rlm/python-tool.d.ts +16 -0
- package/dist/types/rlm/report.d.ts +14 -0
- package/dist/types/rlm/types.d.ts +37 -0
- package/dist/types/sdk.d.ts +7 -0
- package/dist/types/session/agent-session.d.ts +21 -0
- package/dist/types/tools/bash-allowed-prefixes.d.ts +6 -1
- package/dist/types/tools/browser/attach.d.ts +19 -3
- package/dist/types/tools/browser/registry.d.ts +15 -0
- package/dist/types/tools/browser/render.d.ts +3 -0
- package/dist/types/tools/browser.d.ts +18 -1
- package/dist/types/tools/computer/render.d.ts +17 -0
- package/dist/types/tools/computer.d.ts +465 -0
- package/dist/types/tools/index.d.ts +24 -1
- package/dist/types/tools/job.d.ts +13 -0
- package/dist/types/tools/tool-timeouts.d.ts +5 -0
- package/dist/types/web/search/index.d.ts +32 -2
- package/dist/types/web/search/providers/base.d.ts +22 -0
- package/dist/types/web/search/providers/xai.d.ts +64 -0
- package/dist/types/web/search/types.d.ts +11 -3
- package/package.json +7 -7
- package/src/cli/web-search-cli.ts +123 -8
- package/src/cli.ts +2 -0
- package/src/commands/rlm.ts +19 -0
- package/src/commands/web-search.ts +66 -0
- package/src/config/keybindings.ts +11 -0
- package/src/config/model-profiles.ts +11 -3
- package/src/config/model-registry.ts +55 -1
- package/src/config/models-config-schema.ts +1 -0
- package/src/config/settings-schema.ts +67 -1
- package/src/edit/notebook.ts +6 -2
- package/src/eval/py/executor.ts +8 -1
- package/src/eval/py/kernel.ts +9 -4
- package/src/eval/py/runtime.ts +153 -32
- package/src/exec/bash-executor.ts +10 -4
- package/src/extensibility/custom-tools/types.ts +2 -0
- package/src/extensibility/custom-tools/wrapper.ts +2 -0
- package/src/extensibility/extensions/types.ts +2 -0
- package/src/extensibility/extensions/wrapper.ts +1 -0
- package/src/gjc-runtime/launch-tmux.ts +129 -1
- package/src/gjc-runtime/session-state-sidecar.ts +61 -1
- package/src/gjc-runtime/tmux-common.ts +26 -2
- package/src/gjc-runtime/tmux-gc.ts +40 -27
- package/src/gjc-runtime/tmux-sessions.ts +13 -1
- package/src/gjc-runtime/ultragoal-runtime.ts +340 -18
- package/src/goals/runtime.ts +4 -3
- package/src/goals/state.ts +1 -1
- package/src/goals/tools/goal-tool.ts +16 -3
- package/src/internal-urls/docs-index.generated.ts +13 -9
- package/src/main.ts +28 -3
- package/src/modes/components/custom-editor.ts +13 -4
- package/src/modes/components/custom-model-preset-wizard.ts +293 -0
- package/src/modes/components/hook-selector.ts +1 -1
- package/src/modes/components/model-selector.ts +72 -29
- package/src/modes/components/skill-message.ts +62 -8
- package/src/modes/components/status-line.ts +13 -1
- package/src/modes/controllers/input-controller.ts +60 -11
- package/src/modes/controllers/selector-controller.ts +39 -0
- package/src/modes/interactive-mode.ts +1 -1
- package/src/modes/print-mode.ts +14 -4
- package/src/modes/rpc/rpc-client.ts +250 -80
- package/src/modes/rpc/rpc-mode.ts +6 -12
- package/src/modes/rpc/rpc-socket-security.ts +103 -0
- package/src/modes/rpc/rpc-types.ts +10 -0
- package/src/modes/shared/agent-wire/command-dispatch.ts +7 -0
- package/src/modes/shared/agent-wire/command-validation.ts +1 -0
- package/src/modes/shared/agent-wire/scopes.ts +1 -0
- package/src/modes/shared/agent-wire/unattended-session.ts +9 -0
- package/src/modes/utils/hotkeys-markdown.ts +4 -2
- package/src/modes/utils/ui-helpers.ts +2 -2
- package/src/prompts/goals/goal-continuation.md +1 -0
- package/src/prompts/goals/goal-mode-active.md +1 -0
- package/src/prompts/system/rlm-report-command.md +1 -0
- package/src/prompts/system/rlm-research.md +23 -0
- package/src/prompts/tools/bash.md +23 -2
- package/src/prompts/tools/browser.md +7 -3
- package/src/prompts/tools/computer.md +74 -0
- package/src/prompts/tools/goal.md +3 -0
- package/src/prompts/tools/job.md +9 -1
- package/src/prompts/tools/web-search.md +7 -0
- package/src/rlm/artifacts.ts +60 -0
- package/src/rlm/complete-research-tool.ts +163 -0
- package/src/rlm/data-context.ts +26 -0
- package/src/rlm/index.ts +339 -0
- package/src/rlm/notebook.ts +108 -0
- package/src/rlm/preset.ts +76 -0
- package/src/rlm/python-tool.ts +68 -0
- package/src/rlm/report.ts +70 -0
- package/src/rlm/types.ts +40 -0
- package/src/sdk.ts +12 -0
- package/src/session/agent-session.ts +48 -3
- package/src/slash-commands/builtin-registry.ts +17 -0
- package/src/tools/bash-allowed-prefixes.ts +84 -1
- package/src/tools/bash.ts +80 -13
- package/src/tools/browser/attach.ts +103 -3
- package/src/tools/browser/registry.ts +176 -2
- package/src/tools/browser/render.ts +9 -1
- package/src/tools/browser.ts +33 -0
- package/src/tools/computer/render.ts +78 -0
- package/src/tools/computer.ts +640 -0
- package/src/tools/index.ts +41 -1
- package/src/tools/job.ts +88 -5
- package/src/tools/json-tree.ts +42 -29
- package/src/tools/renderers.ts +2 -0
- package/src/tools/tool-timeouts.ts +1 -0
- package/src/web/search/index.ts +27 -2
- package/src/web/search/provider.ts +16 -1
- package/src/web/search/providers/base.ts +22 -0
- package/src/web/search/providers/xai.ts +511 -0
- package/src/web/search/render.ts +7 -0
- package/src/web/search/types.ts +11 -1
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import type { TextContent } from "@gajae-code/ai";
|
|
2
2
|
import type { Component } from "@gajae-code/tui";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
Box,
|
|
5
|
+
Container,
|
|
6
|
+
Markdown,
|
|
7
|
+
replaceTabs,
|
|
8
|
+
Spacer,
|
|
9
|
+
Text,
|
|
10
|
+
truncateToWidth,
|
|
11
|
+
wrapTextWithAnsi,
|
|
12
|
+
} from "@gajae-code/tui";
|
|
4
13
|
import { getMarkdownTheme, theme } from "../../modes/theme/theme";
|
|
5
14
|
import type { CustomMessage, SkillPromptDetails } from "../../session/messages";
|
|
6
15
|
|
|
16
|
+
const COLLAPSED_ARGS_PREVIEW_WIDTH = 96;
|
|
17
|
+
const COLLAPSED_ARGS_PREVIEW_LINES = 6;
|
|
7
18
|
export class SkillMessageComponent extends Container {
|
|
8
19
|
#box: Box;
|
|
9
20
|
#contentComponent?: Component;
|
|
@@ -43,14 +54,16 @@ export class SkillMessageComponent extends Container {
|
|
|
43
54
|
const name = details?.name ?? "unknown";
|
|
44
55
|
const args = details?.args?.trim();
|
|
45
56
|
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
const summary = args ? truncateToWidth(args.replace(/\s+/g, " "), 72) : undefined;
|
|
57
|
+
// Collapsed view keeps args readable without exposing the full prompt body.
|
|
58
|
+
// Each visual line is bounded, but multi-line arguments remain multi-line so
|
|
59
|
+
// the invocation context is not mistaken for a one-line truncated payload.
|
|
60
|
+
const argsPreview = args ? this.#formatArgsPreview(args) : [];
|
|
51
61
|
const header = `${theme.fg("customMessageLabel", theme.bold("[skill]"))} ${theme.fg("customMessageText", name)}`;
|
|
52
|
-
|
|
53
|
-
|
|
62
|
+
this.#box.addChild(new Text(header, 0, 0));
|
|
63
|
+
if (argsPreview.length > 0) {
|
|
64
|
+
this.#box.addChild(new Spacer(1));
|
|
65
|
+
this.#box.addChild(new Text(argsPreview.map(line => theme.fg("customMessageText", line)).join("\n"), 0, 0));
|
|
66
|
+
}
|
|
54
67
|
|
|
55
68
|
if (!this.#expanded) {
|
|
56
69
|
return;
|
|
@@ -70,6 +83,18 @@ export class SkillMessageComponent extends Container {
|
|
|
70
83
|
);
|
|
71
84
|
}
|
|
72
85
|
|
|
86
|
+
if (args) {
|
|
87
|
+
this.#box.addChild(new Spacer(1));
|
|
88
|
+
const argsHeader = theme.fg("customMessageLabel", theme.bold("Arguments"));
|
|
89
|
+
this.#box.addChild(new Text(argsHeader, 0, 0));
|
|
90
|
+
this.#box.addChild(new Spacer(1));
|
|
91
|
+
this.#box.addChild(
|
|
92
|
+
new Markdown(replaceTabs(args), 0, 0, getMarkdownTheme(), {
|
|
93
|
+
color: (value: string) => theme.fg("customMessageText", value),
|
|
94
|
+
}),
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
73
98
|
const text = this.#extractText();
|
|
74
99
|
if (!text) {
|
|
75
100
|
return;
|
|
@@ -86,6 +111,35 @@ export class SkillMessageComponent extends Container {
|
|
|
86
111
|
this.#box.addChild(this.#contentComponent);
|
|
87
112
|
}
|
|
88
113
|
|
|
114
|
+
#formatArgsPreview(args: string): string[] {
|
|
115
|
+
const preview: string[] = [];
|
|
116
|
+
let omitted = false;
|
|
117
|
+
const sourceLines = replaceTabs(args).split(/\r?\n/);
|
|
118
|
+
for (let index = 0; index < sourceLines.length; index += 1) {
|
|
119
|
+
const sourceLine = sourceLines[index]?.trimEnd() ?? "";
|
|
120
|
+
const wrapped = wrapTextWithAnsi(sourceLine.length > 0 ? sourceLine : " ", COLLAPSED_ARGS_PREVIEW_WIDTH);
|
|
121
|
+
for (const line of wrapped.length > 0 ? wrapped : [""]) {
|
|
122
|
+
if (preview.length >= COLLAPSED_ARGS_PREVIEW_LINES) {
|
|
123
|
+
omitted = true;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
preview.push(truncateToWidth(line, COLLAPSED_ARGS_PREVIEW_WIDTH));
|
|
127
|
+
}
|
|
128
|
+
if (omitted) break;
|
|
129
|
+
}
|
|
130
|
+
if (sourceLines.length > 0 && preview.length === COLLAPSED_ARGS_PREVIEW_LINES) {
|
|
131
|
+
const visibleSource = preview.join("\n");
|
|
132
|
+
omitted ||= replaceTabs(args).trimEnd().length > visibleSource.trimEnd().length;
|
|
133
|
+
}
|
|
134
|
+
if (omitted && preview.length > 0) {
|
|
135
|
+
preview[preview.length - 1] = truncateToWidth(
|
|
136
|
+
`${preview[preview.length - 1]} …`,
|
|
137
|
+
COLLAPSED_ARGS_PREVIEW_WIDTH,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
return preview;
|
|
141
|
+
}
|
|
142
|
+
|
|
89
143
|
#extractText(): string {
|
|
90
144
|
if (typeof this.message.content === "string") {
|
|
91
145
|
return this.message.content;
|
|
@@ -44,6 +44,10 @@ export interface StatusLineSettings {
|
|
|
44
44
|
sessionAccent?: boolean;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
export interface StatusLineComponentOptions {
|
|
48
|
+
version?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
47
51
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
48
52
|
// Per-message token cache
|
|
49
53
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -161,6 +165,7 @@ export class StatusLineComponent implements Component {
|
|
|
161
165
|
#skillHudEntries: SkillActiveEntry[] = [];
|
|
162
166
|
#skillHudLastFetch = 0;
|
|
163
167
|
#skillHudInFlight = false;
|
|
168
|
+
#version: string | undefined;
|
|
164
169
|
|
|
165
170
|
// Git status caching (1s TTL)
|
|
166
171
|
#cachedGitStatus: { staged: number; unstaged: number; untracked: number } | null = null;
|
|
@@ -197,7 +202,10 @@ export class StatusLineComponent implements Component {
|
|
|
197
202
|
#nonMessageTokensCache: number | undefined;
|
|
198
203
|
#nonMessageInputsKey: string | undefined;
|
|
199
204
|
|
|
200
|
-
constructor(
|
|
205
|
+
constructor(
|
|
206
|
+
private readonly session: AgentSession,
|
|
207
|
+
options: StatusLineComponentOptions = {},
|
|
208
|
+
) {
|
|
201
209
|
this.#settings = {
|
|
202
210
|
preset: settings.get("statusLine.preset"),
|
|
203
211
|
leftSegments: settings.get("statusLine.leftSegments"),
|
|
@@ -208,6 +216,7 @@ export class StatusLineComponent implements Component {
|
|
|
208
216
|
segmentOptions: settings.getGroup("statusLine").segmentOptions,
|
|
209
217
|
sessionAccent: settings.get("statusLine.sessionAccent"),
|
|
210
218
|
};
|
|
219
|
+
this.#version = options.version?.trim() || undefined;
|
|
211
220
|
}
|
|
212
221
|
|
|
213
222
|
updateSettings(settings: StatusLineSettings): void {
|
|
@@ -701,6 +710,9 @@ export class StatusLineComponent implements Component {
|
|
|
701
710
|
const label = `${formatCount("job", runningBackgroundJobs)} running`;
|
|
702
711
|
rightParts.push(theme.fg("statusLineSubagents", `${icon}${label}`));
|
|
703
712
|
}
|
|
713
|
+
if (this.#version) {
|
|
714
|
+
rightParts.push(theme.fg("dim", `v${this.#version}`));
|
|
715
|
+
}
|
|
704
716
|
const topFillWidth = Math.max(0, width);
|
|
705
717
|
const left = [...leftParts];
|
|
706
718
|
const right = [...rightParts];
|
|
@@ -34,6 +34,8 @@ function isExpandable(obj: unknown): obj is Expandable {
|
|
|
34
34
|
export class InputController {
|
|
35
35
|
constructor(private ctx: InteractiveModeContext) {}
|
|
36
36
|
|
|
37
|
+
#lastBackgroundFoldKeyTime = 0;
|
|
38
|
+
|
|
37
39
|
/** Set after a first Esc silently consumes a queued steer. Kept until the
|
|
38
40
|
* queued steer is either cancelled by a second Esc or drained by continuation,
|
|
39
41
|
* so abort cleanup going idle cannot turn the second Esc into an idle action. */
|
|
@@ -195,6 +197,8 @@ export class InputController {
|
|
|
195
197
|
this.ctx.editor.onExpandTools = () => this.toggleToolOutputExpansion();
|
|
196
198
|
this.ctx.editor.setActionKeys("app.message.dequeue", this.ctx.keybindings.getKeys("app.message.dequeue"));
|
|
197
199
|
this.ctx.editor.onDequeue = () => this.handleDequeue();
|
|
200
|
+
this.ctx.editor.setActionKeys("app.message.queue", this.ctx.keybindings.getKeys("app.message.queue"));
|
|
201
|
+
this.ctx.editor.onQueue = () => void this.handleQueueSubmit();
|
|
198
202
|
|
|
199
203
|
this.ctx.editor.clearCustomKeyHandlers();
|
|
200
204
|
// Wire up extension shortcuts
|
|
@@ -206,16 +210,22 @@ export class InputController {
|
|
|
206
210
|
}
|
|
207
211
|
|
|
208
212
|
for (const key of this.ctx.keybindings.getKeys("app.session.new")) {
|
|
209
|
-
this.ctx.editor.setCustomKeyHandler(key, () => this.ctx.handleClearCommand());
|
|
213
|
+
this.ctx.editor.setCustomKeyHandler(key, () => void this.ctx.handleClearCommand());
|
|
210
214
|
}
|
|
211
215
|
for (const key of this.ctx.keybindings.getKeys("app.session.tree")) {
|
|
212
|
-
this.ctx.editor.setCustomKeyHandler(key, () =>
|
|
216
|
+
this.ctx.editor.setCustomKeyHandler(key, () => {
|
|
217
|
+
this.ctx.showTreeSelector();
|
|
218
|
+
});
|
|
213
219
|
}
|
|
214
220
|
for (const key of this.ctx.keybindings.getKeys("app.session.fork")) {
|
|
215
|
-
this.ctx.editor.setCustomKeyHandler(key, () =>
|
|
221
|
+
this.ctx.editor.setCustomKeyHandler(key, () => {
|
|
222
|
+
this.ctx.showUserMessageSelector();
|
|
223
|
+
});
|
|
216
224
|
}
|
|
217
225
|
for (const key of this.ctx.keybindings.getKeys("app.session.resume")) {
|
|
218
|
-
this.ctx.editor.setCustomKeyHandler(key, () =>
|
|
226
|
+
this.ctx.editor.setCustomKeyHandler(key, () => {
|
|
227
|
+
this.ctx.showSessionSelector();
|
|
228
|
+
});
|
|
219
229
|
}
|
|
220
230
|
for (const key of this.ctx.keybindings.getKeys("app.message.followUp")) {
|
|
221
231
|
this.ctx.editor.setCustomKeyHandler(key, () => void this.handleFollowUp());
|
|
@@ -224,13 +234,22 @@ export class InputController {
|
|
|
224
234
|
this.ctx.editor.setCustomKeyHandler(key, () => void this.ctx.handleSTTToggle());
|
|
225
235
|
}
|
|
226
236
|
for (const key of this.ctx.keybindings.getKeys("app.clipboard.copyLine")) {
|
|
227
|
-
this.ctx.editor.setCustomKeyHandler(key, () =>
|
|
237
|
+
this.ctx.editor.setCustomKeyHandler(key, () => {
|
|
238
|
+
this.handleCopyCurrentLine();
|
|
239
|
+
});
|
|
228
240
|
}
|
|
229
241
|
for (const key of this.ctx.keybindings.getKeys("app.session.observe")) {
|
|
230
|
-
this.ctx.editor.setCustomKeyHandler(key, () =>
|
|
242
|
+
this.ctx.editor.setCustomKeyHandler(key, () => {
|
|
243
|
+
this.ctx.showSessionObserver();
|
|
244
|
+
});
|
|
231
245
|
}
|
|
232
246
|
for (const key of this.ctx.keybindings.getKeys("app.jobs.open")) {
|
|
233
|
-
this.ctx.editor.setCustomKeyHandler(key, () =>
|
|
247
|
+
this.ctx.editor.setCustomKeyHandler(key, () => {
|
|
248
|
+
this.ctx.showJobsOverlay();
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
for (const key of this.ctx.keybindings.getKeys("app.tool.backgroundFold")) {
|
|
252
|
+
this.ctx.editor.setCustomKeyHandler(key, () => this.handleForegroundToolBackgroundFold());
|
|
234
253
|
}
|
|
235
254
|
|
|
236
255
|
this.ctx.editor.onChange = (text: string) => {
|
|
@@ -311,8 +330,8 @@ export class InputController {
|
|
|
311
330
|
// Handle skill commands (/skill:name [args]). While streaming, Enter
|
|
312
331
|
// honors `busyPromptMode`: "steer" interrupts the active turn, "queue"
|
|
313
332
|
// runs after it completes (matches the free-text Enter semantics applied
|
|
314
|
-
// a few lines below at the streaming branch).
|
|
315
|
-
// through `handleFollowUp` and
|
|
333
|
+
// a few lines below at the streaming branch). Explicit queue shortcuts
|
|
334
|
+
// route through `handleFollowUp` and dispatch as `followUp`.
|
|
316
335
|
if (await this.#invokeSkillCommand(text, this.#busyStreamingBehavior())) {
|
|
317
336
|
return;
|
|
318
337
|
}
|
|
@@ -481,7 +500,7 @@ export class InputController {
|
|
|
481
500
|
* completes (in submission order). Only consulted while streaming.
|
|
482
501
|
*/
|
|
483
502
|
#busyStreamingBehavior(): "steer" | "followUp" {
|
|
484
|
-
return this.ctx.settings.get("busyPromptMode") === "
|
|
503
|
+
return this.ctx.settings.get("busyPromptMode") === "steer" ? "steer" : "followUp";
|
|
485
504
|
}
|
|
486
505
|
|
|
487
506
|
/**
|
|
@@ -580,7 +599,7 @@ export class InputController {
|
|
|
580
599
|
|
|
581
600
|
// Skill commands invoke through the custom-message path regardless of
|
|
582
601
|
// which keybinding submitted them. Enter routes them as `steer`;
|
|
583
|
-
//
|
|
602
|
+
// explicit queue shortcuts route them as `followUp`.
|
|
584
603
|
if (await this.#invokeSkillCommand(text, "followUp")) {
|
|
585
604
|
return;
|
|
586
605
|
}
|
|
@@ -602,6 +621,11 @@ export class InputController {
|
|
|
602
621
|
await this.ctx.withLocalSubmission(text, () => this.ctx.session.prompt(text));
|
|
603
622
|
}
|
|
604
623
|
|
|
624
|
+
/** Send editor text explicitly as a queued next-turn message. */
|
|
625
|
+
async handleQueueSubmit(): Promise<void> {
|
|
626
|
+
return this.handleFollowUp();
|
|
627
|
+
}
|
|
628
|
+
|
|
605
629
|
restoreQueuedMessagesToEditor(options?: { abort?: boolean; currentText?: string }): number {
|
|
606
630
|
this.ctx.locallySubmittedUserSignatures.clear();
|
|
607
631
|
const { steering, followUp } = this.ctx.session.clearQueue();
|
|
@@ -690,6 +714,31 @@ export class InputController {
|
|
|
690
714
|
process.kill(0, "SIGTSTP");
|
|
691
715
|
}
|
|
692
716
|
|
|
717
|
+
handleForegroundToolBackgroundFold(): boolean {
|
|
718
|
+
if (!this.ctx.session.hasForegroundBashBackgroundRequestHandler?.()) {
|
|
719
|
+
this.#lastBackgroundFoldKeyTime = 0;
|
|
720
|
+
return false;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
const now = Date.now();
|
|
724
|
+
if (now - this.#lastBackgroundFoldKeyTime > 750) {
|
|
725
|
+
this.#lastBackgroundFoldKeyTime = now;
|
|
726
|
+
this.ctx.showStatus("Press Ctrl+B again to fold supported foreground bash into a background job");
|
|
727
|
+
return true;
|
|
728
|
+
}
|
|
729
|
+
this.#lastBackgroundFoldKeyTime = 0;
|
|
730
|
+
|
|
731
|
+
if (!this.ctx.session.requestForegroundBashBackground?.()) {
|
|
732
|
+
this.ctx.showWarning(
|
|
733
|
+
"No supported foreground tool can be folded. Use managed async bash/auto-background; raw Ctrl+Z/bg is not supported inside the TUI.",
|
|
734
|
+
);
|
|
735
|
+
return true;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
this.ctx.showStatus("Folding foreground bash into a quiet background job…");
|
|
739
|
+
return true;
|
|
740
|
+
}
|
|
741
|
+
|
|
693
742
|
handleTextPaste(text: string): boolean | Promise<boolean> {
|
|
694
743
|
const imagePath = this.#getPastedImagePathCandidate(text);
|
|
695
744
|
return imagePath ? this.#attachPastedImagePath(imagePath) : false;
|
|
@@ -49,6 +49,10 @@ import {
|
|
|
49
49
|
import { setSessionTerminalTitle } from "../../utils/title-generator";
|
|
50
50
|
import { AgentDashboard } from "../components/agent-dashboard";
|
|
51
51
|
import { AssistantMessageComponent } from "../components/assistant-message";
|
|
52
|
+
import {
|
|
53
|
+
CustomModelPresetWizardComponent,
|
|
54
|
+
type CustomModelPresetWizardSubmit,
|
|
55
|
+
} from "../components/custom-model-preset-wizard";
|
|
52
56
|
import { CustomProviderWizardComponent, type CustomProviderWizardSubmit } from "../components/custom-provider-wizard";
|
|
53
57
|
import { ExtensionDashboard } from "../components/extensions";
|
|
54
58
|
import { HistorySearchComponent } from "../components/history-search";
|
|
@@ -213,6 +217,36 @@ export class SelectorController {
|
|
|
213
217
|
this.ctx.ui.requestRender();
|
|
214
218
|
}
|
|
215
219
|
|
|
220
|
+
showCustomModelPresetWizard(): void {
|
|
221
|
+
this.showSelector(done => {
|
|
222
|
+
let wizard: CustomModelPresetWizardComponent;
|
|
223
|
+
const submit = async (input: CustomModelPresetWizardSubmit): Promise<void> => {
|
|
224
|
+
try {
|
|
225
|
+
const profile = await this.ctx.session.modelRegistry.saveCustomModelProfile(input.name, input.profile);
|
|
226
|
+
await this.ctx.session.modelRegistry.refresh("offline");
|
|
227
|
+
await this.ctx.notifyConfigChanged?.();
|
|
228
|
+
this.ctx.showStatus(`Custom model preset created: ${profile.displayName ?? profile.name}`);
|
|
229
|
+
done();
|
|
230
|
+
this.ctx.ui.requestRender();
|
|
231
|
+
} catch (err) {
|
|
232
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
233
|
+
wizard.setSubmitError(`Preset creation failed: ${message}`);
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
wizard = new CustomModelPresetWizardComponent(
|
|
237
|
+
input => {
|
|
238
|
+
void submit(input);
|
|
239
|
+
},
|
|
240
|
+
() => {
|
|
241
|
+
done();
|
|
242
|
+
this.ctx.ui.requestRender();
|
|
243
|
+
},
|
|
244
|
+
() => this.ctx.ui.requestRender(),
|
|
245
|
+
);
|
|
246
|
+
return { component: wizard, focus: wizard };
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
216
250
|
showCustomProviderWizard(): void {
|
|
217
251
|
this.showSelector(done => {
|
|
218
252
|
let wizard: CustomProviderWizardComponent;
|
|
@@ -618,6 +652,11 @@ export class SelectorController {
|
|
|
618
652
|
this.ctx.session.scopedModels,
|
|
619
653
|
async selection => {
|
|
620
654
|
try {
|
|
655
|
+
if (selection.kind === "createProfile") {
|
|
656
|
+
done();
|
|
657
|
+
this.showCustomModelPresetWizard();
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
621
660
|
if (selection.kind === "profile") {
|
|
622
661
|
await activateModelProfile(
|
|
623
662
|
{
|
|
@@ -406,7 +406,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
406
406
|
this.hookWidgetContainerBelow = new Container();
|
|
407
407
|
this.editorContainer = new Container();
|
|
408
408
|
this.editorContainer.addChild(this.editor);
|
|
409
|
-
this.statusLine = new StatusLineComponent(session);
|
|
409
|
+
this.statusLine = new StatusLineComponent(session, { version: this.#version });
|
|
410
410
|
this.statusLine.setAutoCompactEnabled(session.autoCompactionEnabled);
|
|
411
411
|
|
|
412
412
|
this.hideThinkingBlock = settings.get("hideThinkingBlock");
|
package/src/modes/print-mode.ts
CHANGED
|
@@ -23,6 +23,12 @@ export interface PrintModeOptions {
|
|
|
23
23
|
initialMessage?: string;
|
|
24
24
|
/** Images to attach to the initial message */
|
|
25
25
|
initialImages?: ImageContent[];
|
|
26
|
+
/**
|
|
27
|
+
* When true, an assistant error/abort does not call process.exit(); print mode
|
|
28
|
+
* returns instead so the caller (e.g. RLM autonomous mode) can run its own
|
|
29
|
+
* finalization/cleanup before the process exits.
|
|
30
|
+
*/
|
|
31
|
+
suppressProcessExit?: boolean;
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
/**
|
|
@@ -84,10 +90,14 @@ export async function runPrintMode(session: AgentSession, options: PrintModeOpti
|
|
|
84
90
|
) {
|
|
85
91
|
const errorLine = sanitizeText(assistantMsg.errorMessage || `Request ${assistantMsg.stopReason}`);
|
|
86
92
|
const flushed = process.stderr.write(`${errorLine}\n`);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
93
|
+
// When the caller owns finalization (RLM autonomous), return instead of
|
|
94
|
+
// exiting so its cleanup runs; the caller surfaces a non-zero exit itself.
|
|
95
|
+
if (!options.suppressProcessExit) {
|
|
96
|
+
if (flushed) {
|
|
97
|
+
process.exit(1);
|
|
98
|
+
} else {
|
|
99
|
+
process.stderr.once("drain", () => process.exit(1));
|
|
100
|
+
}
|
|
91
101
|
}
|
|
92
102
|
}
|
|
93
103
|
|