@goah/cli 0.11.5 → 0.13.0
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/dist/cli.js +165 -66
- package/dist/cli.js.map +1 -1
- package/dist/console/assets/index-3sYrDMmt.css +1 -0
- package/dist/console/assets/index-Rtc_B7cs.js +52 -0
- package/dist/console/assets/index-Rtc_B7cs.js.map +1 -0
- package/dist/console/index.html +2 -2
- package/dist/control.d.ts +13 -13
- package/dist/control.d.ts.map +1 -1
- package/dist/control.js +77 -50
- package/dist/control.js.map +1 -1
- package/dist/index.d.ts +6 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +156 -28
- package/dist/index.js.map +1 -1
- package/dist/live-config.js +2 -2
- package/dist/live-config.js.map +1 -1
- package/dist/prompt-queue.d.ts.map +1 -1
- package/dist/prompt-queue.js +5 -0
- package/dist/prompt-queue.js.map +1 -1
- package/dist/setup-wizard.d.ts +13 -2
- package/dist/setup-wizard.d.ts.map +1 -1
- package/dist/setup-wizard.js +87 -63
- package/dist/setup-wizard.js.map +1 -1
- package/dist/thread-inspect.d.ts +47 -0
- package/dist/thread-inspect.d.ts.map +1 -0
- package/dist/thread-inspect.js +78 -0
- package/dist/thread-inspect.js.map +1 -0
- package/dist/transcript.d.ts +2 -0
- package/dist/transcript.d.ts.map +1 -0
- package/dist/transcript.js +2 -0
- package/dist/transcript.js.map +1 -0
- package/dist/tui-theme.d.ts +1 -0
- package/dist/tui-theme.d.ts.map +1 -1
- package/dist/tui-theme.js +1 -0
- package/dist/tui-theme.js.map +1 -1
- package/dist/tui.d.ts +8 -2
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +291 -90
- package/dist/tui.js.map +1 -1
- package/dist/update.d.ts +1 -0
- package/dist/update.d.ts.map +1 -1
- package/dist/update.js +15 -7
- package/dist/update.js.map +1 -1
- package/dist/web-console.d.ts +1 -1
- package/dist/web-console.d.ts.map +1 -1
- package/dist/web-console.js +27 -37
- package/dist/web-console.js.map +1 -1
- package/dist/welcome.d.ts +2 -2
- package/dist/welcome.d.ts.map +1 -1
- package/dist/welcome.js +24 -36
- package/dist/welcome.js.map +1 -1
- package/node_modules/goah-ledger-contract/dist/execution.d.ts +272 -130
- package/node_modules/goah-ledger-contract/dist/execution.d.ts.map +1 -1
- package/node_modules/goah-ledger-contract/dist/execution.js +31 -19
- package/node_modules/goah-ledger-contract/dist/execution.js.map +1 -1
- package/node_modules/goah-ledger-contract/dist/index.d.ts +1 -2
- package/node_modules/goah-ledger-contract/dist/index.d.ts.map +1 -1
- package/node_modules/goah-ledger-contract/dist/index.js +1 -2
- package/node_modules/goah-ledger-contract/dist/index.js.map +1 -1
- package/node_modules/goah-ledger-contract/dist/kernel.d.ts +1 -1
- package/node_modules/goah-ledger-contract/dist/kernel.d.ts.map +1 -1
- package/node_modules/goah-ledger-contract/dist/kernel.js +1 -1
- package/node_modules/goah-ledger-contract/dist/kernel.js.map +1 -1
- package/node_modules/goah-ledger-contract/dist/transcript.d.ts +63 -0
- package/node_modules/goah-ledger-contract/dist/transcript.d.ts.map +1 -0
- package/node_modules/goah-ledger-contract/dist/transcript.js +115 -0
- package/node_modules/goah-ledger-contract/dist/transcript.js.map +1 -0
- package/node_modules/goah-ledger-contract/package.json +3 -4
- package/node_modules/goah-ledger-sqlite/dist/index.d.ts +32 -23
- package/node_modules/goah-ledger-sqlite/dist/index.d.ts.map +1 -1
- package/node_modules/goah-ledger-sqlite/dist/index.js +764 -394
- package/node_modules/goah-ledger-sqlite/dist/index.js.map +1 -1
- package/node_modules/goah-ledger-sqlite/package.json +2 -2
- package/node_modules/goah-runner-pi/dist/configurator.d.ts.map +1 -1
- package/node_modules/goah-runner-pi/dist/configurator.js +186 -30
- package/node_modules/goah-runner-pi/dist/configurator.js.map +1 -1
- package/node_modules/goah-runner-pi/dist/credential-store.d.ts +2 -0
- package/node_modules/goah-runner-pi/dist/credential-store.d.ts.map +1 -1
- package/node_modules/goah-runner-pi/dist/credential-store.js +117 -23
- package/node_modules/goah-runner-pi/dist/credential-store.js.map +1 -1
- package/node_modules/goah-runner-pi/dist/index.d.ts +18 -6
- package/node_modules/goah-runner-pi/dist/index.d.ts.map +1 -1
- package/node_modules/goah-runner-pi/dist/index.js +97 -12
- package/node_modules/goah-runner-pi/dist/index.js.map +1 -1
- package/node_modules/goah-runner-pi/dist/pi-worker.d.ts +4 -2
- package/node_modules/goah-runner-pi/dist/pi-worker.d.ts.map +1 -1
- package/node_modules/goah-runner-pi/dist/pi-worker.js +220 -69
- package/node_modules/goah-runner-pi/dist/pi-worker.js.map +1 -1
- package/node_modules/goah-runner-pi/dist/steering-no-ack.test-fixture.d.ts +2 -0
- package/node_modules/goah-runner-pi/dist/steering-no-ack.test-fixture.d.ts.map +1 -0
- package/node_modules/goah-runner-pi/dist/steering-no-ack.test-fixture.js +3 -0
- package/node_modules/goah-runner-pi/dist/steering-no-ack.test-fixture.js.map +1 -0
- package/node_modules/goah-runner-pi/dist/steering-reject.test-fixture.d.ts +2 -0
- package/node_modules/goah-runner-pi/dist/steering-reject.test-fixture.d.ts.map +1 -0
- package/node_modules/goah-runner-pi/dist/steering-reject.test-fixture.js +5 -0
- package/node_modules/goah-runner-pi/dist/steering-reject.test-fixture.js.map +1 -0
- package/node_modules/goah-runner-pi/dist/steering-worker.test-fixture.d.ts +2 -0
- package/node_modules/goah-runner-pi/dist/steering-worker.test-fixture.d.ts.map +1 -0
- package/node_modules/goah-runner-pi/dist/steering-worker.test-fixture.js +5 -0
- package/node_modules/goah-runner-pi/dist/steering-worker.test-fixture.js.map +1 -0
- package/node_modules/goah-runner-pi/dist/test-helpers.d.ts +1 -1
- package/node_modules/goah-runner-pi/dist/test-helpers.d.ts.map +1 -1
- package/node_modules/goah-runner-pi/dist/test-helpers.js +3 -1
- package/node_modules/goah-runner-pi/dist/test-helpers.js.map +1 -1
- package/node_modules/goah-runner-pi/dist/verification-worker.d.ts.map +1 -1
- package/node_modules/goah-runner-pi/dist/verification-worker.js +3 -5
- package/node_modules/goah-runner-pi/dist/verification-worker.js.map +1 -1
- package/node_modules/goah-runner-pi/package.json +2 -2
- package/node_modules/goah-supervisor/dist/context-view.d.ts +4 -5
- package/node_modules/goah-supervisor/dist/context-view.d.ts.map +1 -1
- package/node_modules/goah-supervisor/dist/context-view.js +7 -20
- package/node_modules/goah-supervisor/dist/context-view.js.map +1 -1
- package/node_modules/goah-supervisor/dist/index.d.ts +38 -36
- package/node_modules/goah-supervisor/dist/index.d.ts.map +1 -1
- package/node_modules/goah-supervisor/dist/index.js +762 -575
- package/node_modules/goah-supervisor/dist/index.js.map +1 -1
- package/node_modules/goah-supervisor/dist/roles.d.ts +2 -1
- package/node_modules/goah-supervisor/dist/roles.d.ts.map +1 -1
- package/node_modules/goah-supervisor/dist/roles.js +20 -5
- package/node_modules/goah-supervisor/dist/roles.js.map +1 -1
- package/node_modules/goah-supervisor/dist/verification.d.ts +8 -29
- package/node_modules/goah-supervisor/dist/verification.d.ts.map +1 -1
- package/node_modules/goah-supervisor/dist/verification.js +71 -46
- package/node_modules/goah-supervisor/dist/verification.js.map +1 -1
- package/node_modules/goah-supervisor/package.json +2 -2
- package/node_modules/goah-testkit/dist/faux-runner-worker.js +16 -9
- package/node_modules/goah-testkit/dist/faux-runner-worker.js.map +1 -1
- package/node_modules/goah-testkit/dist/index.d.ts +13 -16
- package/node_modules/goah-testkit/dist/index.d.ts.map +1 -1
- package/node_modules/goah-testkit/dist/index.js +27 -44
- package/node_modules/goah-testkit/dist/index.js.map +1 -1
- package/node_modules/goah-testkit/package.json +5 -5
- package/package.json +7 -8
- package/dist/console/assets/index-BJTGvlCH.js +0 -52
- package/dist/console/assets/index-BJTGvlCH.js.map +0 -1
- package/dist/console/assets/index-msBn41Cl.css +0 -1
- package/dist/inspect.d.ts +0 -61
- package/dist/inspect.d.ts.map +0 -1
- package/dist/inspect.js +0 -110
- package/dist/inspect.js.map +0 -1
- package/dist/metrics.d.ts +0 -2
- package/dist/metrics.d.ts.map +0 -1
- package/dist/metrics.js +0 -2
- package/dist/metrics.js.map +0 -1
- package/dist/session.d.ts +0 -2
- package/dist/session.d.ts.map +0 -1
- package/dist/session.js +0 -2
- package/dist/session.js.map +0 -1
- package/node_modules/goah-ledger-contract/dist/metrics.d.ts +0 -40
- package/node_modules/goah-ledger-contract/dist/metrics.d.ts.map +0 -1
- package/node_modules/goah-ledger-contract/dist/metrics.js +0 -25
- package/node_modules/goah-ledger-contract/dist/metrics.js.map +0 -1
- package/node_modules/goah-ledger-contract/dist/session.d.ts +0 -63
- package/node_modules/goah-ledger-contract/dist/session.d.ts.map +0 -1
- package/node_modules/goah-ledger-contract/dist/session.js +0 -115
- package/node_modules/goah-ledger-contract/dist/session.js.map +0 -1
- package/node_modules/goah-testkit/dist/mock-connector-worker.d.ts +0 -2
- package/node_modules/goah-testkit/dist/mock-connector-worker.d.ts.map +0 -1
- package/node_modules/goah-testkit/dist/mock-connector-worker.js +0 -29
- package/node_modules/goah-testkit/dist/mock-connector-worker.js.map +0 -1
package/dist/tui.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/** Full-screen goah TUI: streaming CEO transcript over the resident Supervisor control socket. */
|
|
2
2
|
import { TuiAltScreen, Text, Markdown, Editor, ProcessTerminal, ScrollView, VStack } from "@earendil-works/pi-tui";
|
|
3
3
|
import { controlAvailable, requestControl, streamControl } from "./control.js";
|
|
4
|
-
import { readConsoleMetadata } from "./index.js";
|
|
4
|
+
import { loadConfig, readConsoleMetadata, readDefaultRunnerProfile } from "./index.js";
|
|
5
5
|
import { switchModel, reloadDaemon, readRunnerDisplay } from "./live-config.js";
|
|
6
6
|
import { welcomeSnapshot, renderWelcome } from "./welcome.js";
|
|
7
|
-
import { runSetupWizard, applyWizardResult } from "./setup-wizard.js";
|
|
7
|
+
import { chooseSetupSection, runRunnerCommandWizard, runSetupWizard, applyWizardResult } from "./setup-wizard.js";
|
|
8
8
|
import { installedVersion } from "./update.js";
|
|
9
9
|
import { tuiTheme } from "./tui-theme.js";
|
|
10
10
|
import { spawn } from "node:child_process";
|
|
11
|
-
import { closeSync, mkdirSync, openSync } from "node:fs";
|
|
11
|
+
import { closeSync, existsSync, mkdirSync, openSync } from "node:fs";
|
|
12
12
|
import { join, resolve } from "node:path";
|
|
13
13
|
class HeaderBar {
|
|
14
14
|
runner;
|
|
@@ -43,11 +43,16 @@ const markdownTheme = {
|
|
|
43
43
|
class ConversationView {
|
|
44
44
|
entries;
|
|
45
45
|
liveMarkdown = "";
|
|
46
|
-
|
|
46
|
+
liveThinking = "";
|
|
47
|
+
thinkingActive = false;
|
|
47
48
|
constructor(initial) { this.entries = [{ kind: "text", content: initial.join("\n") }]; }
|
|
48
49
|
addText(content) { this.entries.push({ kind: "text", content }); this.trim(); }
|
|
50
|
+
addUser(content) { this.entries.push({ kind: "user", content }); this.trim(); }
|
|
49
51
|
addMarkdown(content) {
|
|
50
52
|
this.liveMarkdown = "";
|
|
53
|
+
content = content.trim();
|
|
54
|
+
if (!content)
|
|
55
|
+
return;
|
|
51
56
|
const previous = this.entries.at(-1);
|
|
52
57
|
if (previous?.kind === "markdown" && previous.content === content)
|
|
53
58
|
return;
|
|
@@ -56,7 +61,30 @@ class ConversationView {
|
|
|
56
61
|
}
|
|
57
62
|
setLiveMarkdown(content) { this.liveMarkdown = content; }
|
|
58
63
|
clearLiveMarkdown() { this.liveMarkdown = ""; }
|
|
59
|
-
|
|
64
|
+
updateThinking(activity) {
|
|
65
|
+
if (activity.phase === "start") {
|
|
66
|
+
this.liveThinking = "";
|
|
67
|
+
this.thinkingActive = true;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (activity.phase === "delta") {
|
|
71
|
+
this.liveThinking += activity.text;
|
|
72
|
+
this.thinkingActive = true;
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (activity.phase === "clear") {
|
|
76
|
+
this.liveThinking = "";
|
|
77
|
+
this.thinkingActive = false;
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const content = (activity.text || this.liveThinking).trim();
|
|
81
|
+
this.liveThinking = "";
|
|
82
|
+
this.thinkingActive = false;
|
|
83
|
+
const previous = this.entries.at(-1);
|
|
84
|
+
if (content && !(previous?.kind === "thinking" && previous.content === content))
|
|
85
|
+
this.entries.push({ kind: "thinking", content });
|
|
86
|
+
this.trim();
|
|
87
|
+
}
|
|
60
88
|
updateTool(activity) {
|
|
61
89
|
const previous = this.entries.findLast((entry) => entry.kind === "tool" && entry.callId === activity.callId);
|
|
62
90
|
if (previous?.kind === "tool")
|
|
@@ -69,18 +97,25 @@ class ConversationView {
|
|
|
69
97
|
this.entries.splice(1, this.entries.length - 240); }
|
|
70
98
|
render(width) {
|
|
71
99
|
const rendered = this.entries.flatMap((entry) => entry.kind === "markdown"
|
|
72
|
-
? [
|
|
73
|
-
: entry.kind === "
|
|
74
|
-
?
|
|
75
|
-
:
|
|
76
|
-
|
|
100
|
+
? [...new Markdown(entry.content, 2, 0, markdownTheme).render(width), ""]
|
|
101
|
+
: entry.kind === "user"
|
|
102
|
+
? renderUserMessage(entry.content, width)
|
|
103
|
+
: entry.kind === "thinking"
|
|
104
|
+
? [tuiTheme.muted(" thinking"), ...new Markdown(entry.content, 2, 0, markdownTheme, { color: tuiTheme.muted, italic: true }).render(width), ""]
|
|
105
|
+
: entry.kind === "tool"
|
|
106
|
+
? new Text(toolActivityLine(entry), 2, 0).render(width)
|
|
107
|
+
: new Text(entry.content, 2, 0).render(width));
|
|
108
|
+
if (this.liveThinking)
|
|
109
|
+
rendered.push(tuiTheme.muted(" thinking"), ...new Markdown(this.liveThinking, 2, 0, markdownTheme, { color: tuiTheme.muted, italic: true }).render(width));
|
|
110
|
+
else if (this.thinkingActive)
|
|
77
111
|
rendered.push(tuiTheme.muted(" thinking…"));
|
|
78
112
|
if (this.liveMarkdown)
|
|
79
|
-
rendered.push(
|
|
113
|
+
rendered.push(...new Markdown(this.liveMarkdown, 2, 0, markdownTheme).render(width));
|
|
80
114
|
return rendered;
|
|
81
115
|
}
|
|
82
116
|
invalidate() { }
|
|
83
117
|
}
|
|
118
|
+
export function renderUserMessage(content, width) { return new Text(content, 2, 1, tuiTheme.userMessage).render(width); }
|
|
84
119
|
export function renderTuiHeader(width, runner, target, version) {
|
|
85
120
|
const brand = " GOAH ";
|
|
86
121
|
const release = width >= 34 ? ` v${version} ` : "";
|
|
@@ -115,13 +150,17 @@ export function classifyTuiInput(value, busy) {
|
|
|
115
150
|
return { action: "stop", text };
|
|
116
151
|
if (text === "/model" || text.startsWith("/model "))
|
|
117
152
|
return { action: "model", text };
|
|
118
|
-
if (text === "/
|
|
153
|
+
if (text === "/login" || text.startsWith("/login "))
|
|
154
|
+
return { action: "login", text };
|
|
155
|
+
if (text === "/logout" || text.startsWith("/logout "))
|
|
156
|
+
return { action: "logout", text };
|
|
157
|
+
if (text === "/setup" || text.startsWith("/setup "))
|
|
119
158
|
return { action: "setup", text };
|
|
120
159
|
if (text.startsWith("/goal ") || text.startsWith("/observe "))
|
|
121
160
|
return { action: "goal", text };
|
|
122
|
-
if (text.startsWith("/
|
|
123
|
-
return { action: "
|
|
124
|
-
return { action: busy ? "
|
|
161
|
+
if (text.startsWith("/"))
|
|
162
|
+
return { action: "unknown", text };
|
|
163
|
+
return { action: busy ? "steer" : "send", text };
|
|
125
164
|
}
|
|
126
165
|
export async function runGoahTui(configPath, stateDir, initialMessage) {
|
|
127
166
|
if (!process.stdout.isTTY || !process.stdin.isTTY)
|
|
@@ -130,11 +169,19 @@ export async function runGoahTui(configPath, stateDir, initialMessage) {
|
|
|
130
169
|
const snapshot = welcomeSnapshot(stateDir, runner);
|
|
131
170
|
const welcome = renderWelcome(snapshot, Boolean(snapshot.root || snapshot.handoffs.length || snapshot.conversation.length));
|
|
132
171
|
await ensureDaemon(configPath, stateDir);
|
|
172
|
+
const liveSnapshot = await requestControl(stateDir, { op: "status" }).catch(() => null);
|
|
173
|
+
const liveTurns = liveSnapshot && typeof liveSnapshot === "object" && !Array.isArray(liveSnapshot) && Array.isArray(liveSnapshot.turns) ? liveSnapshot.turns : [];
|
|
174
|
+
const liveInteractionTurnId = findLiveTurnId(liveTurns);
|
|
133
175
|
const terminal = new ProcessTerminal();
|
|
134
176
|
const tui = new TuiAltScreen(terminal, true, undefined, { mouse: true });
|
|
135
177
|
terminal.setTitle(`Goah · ${runner.target}`);
|
|
136
178
|
const headerView = new HeaderBar(runner.runner, runner.target, installedVersion());
|
|
137
179
|
const transcriptView = new ConversationView(welcome);
|
|
180
|
+
for (const row of snapshot.conversation)
|
|
181
|
+
if (row.speaker === "You")
|
|
182
|
+
transcriptView.addUser(row.text);
|
|
183
|
+
else
|
|
184
|
+
transcriptView.addMarkdown(row.text);
|
|
138
185
|
const conversationScroll = new ScrollView(transcriptView, { follow: "end", primary: true, scrollbar: "auto", scrollbarStyle: tuiTheme.muted });
|
|
139
186
|
const goalView = new GoalBar(snapshot.root);
|
|
140
187
|
const input = new Editor(tui, {
|
|
@@ -151,7 +198,11 @@ export async function runGoahTui(configPath, stateDir, initialMessage) {
|
|
|
151
198
|
]);
|
|
152
199
|
const busy = { active: false };
|
|
153
200
|
const queued = [];
|
|
201
|
+
const queuedTurnIds = [];
|
|
154
202
|
let activeStream = null;
|
|
203
|
+
let activeInteractionTurnId = null;
|
|
204
|
+
let steeringTail = Promise.resolve();
|
|
205
|
+
let configuring = false;
|
|
155
206
|
let exiting = false;
|
|
156
207
|
const push = (line) => {
|
|
157
208
|
transcriptView.addText(line);
|
|
@@ -159,23 +210,29 @@ export async function runGoahTui(configPath, stateDir, initialMessage) {
|
|
|
159
210
|
};
|
|
160
211
|
let liveText = "";
|
|
161
212
|
const appendLive = (text) => { liveText += text; transcriptView.setLiveMarkdown(liveText); tui.requestRender(); };
|
|
162
|
-
const commitLive = (text) => { liveText = ""; if (text)
|
|
213
|
+
const commitLive = (text) => { liveText = ""; transcriptView.clearLiveMarkdown(); if (text)
|
|
163
214
|
transcriptView.addMarkdown(text); tui.requestRender(); };
|
|
164
215
|
const pushResponse = (text) => { transcriptView.addMarkdown(text); tui.requestRender(); };
|
|
165
216
|
const updateTool = (activity) => { transcriptView.updateTool(activity); tui.requestRender(); };
|
|
166
|
-
const
|
|
167
|
-
const
|
|
217
|
+
const updateThinking = (activity) => { transcriptView.updateThinking(activity); tui.requestRender(); };
|
|
218
|
+
const setWakeState = (mode) => { statusView.setText(statusText(mode, mode === "queued" ? 1 : queued.length)); tui.requestRender(); };
|
|
219
|
+
const send = async (message, showUser = true) => {
|
|
168
220
|
busy.active = true;
|
|
169
221
|
const controller = new AbortController();
|
|
170
222
|
activeStream = controller;
|
|
171
223
|
statusView.setText(statusText("working", queued.length));
|
|
172
|
-
|
|
224
|
+
if (showUser) {
|
|
225
|
+
transcriptView.addUser(message);
|
|
226
|
+
tui.requestRender();
|
|
227
|
+
}
|
|
173
228
|
try {
|
|
174
|
-
await streamControl(stateDir, { op: "interact", message }, (frame) =>
|
|
229
|
+
await streamControl(stateDir, { op: "interact", message }, (frame) => { if (frame.type === "accepted")
|
|
230
|
+
activeInteractionTurnId = frame.turnId; if (frame.type === "result" || frame.type === "error")
|
|
231
|
+
activeInteractionTurnId = null; renderFrame(frame, push, appendLive, commitLive, pushResponse, updateTool, updateThinking, setWakeState, () => commitLive("")); }, controller.signal);
|
|
175
232
|
}
|
|
176
233
|
catch (error) {
|
|
177
234
|
transcriptView.clearLiveMarkdown();
|
|
178
|
-
transcriptView.
|
|
235
|
+
transcriptView.updateThinking({ phase: "clear", text: "" });
|
|
179
236
|
if (!controller.signal.aborted)
|
|
180
237
|
push(errorLine(error));
|
|
181
238
|
}
|
|
@@ -184,30 +241,153 @@ export async function runGoahTui(configPath, stateDir, initialMessage) {
|
|
|
184
241
|
activeStream = null;
|
|
185
242
|
busy.active = false;
|
|
186
243
|
await refreshGoalBar(stateDir, goalView, tui);
|
|
187
|
-
statusView.setText(statusText(queued.length ? "queued" : "ready", queued.length));
|
|
188
|
-
|
|
189
|
-
if (next)
|
|
190
|
-
void send(next);
|
|
244
|
+
statusView.setText(statusText(queuedTurnIds.length || queued.length ? "queued" : "ready", queuedTurnIds.length + queued.length));
|
|
245
|
+
continuePending();
|
|
191
246
|
}
|
|
192
247
|
};
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
248
|
+
const attachTurn = async (turnId) => {
|
|
249
|
+
busy.active = true;
|
|
250
|
+
activeInteractionTurnId = turnId;
|
|
251
|
+
const controller = new AbortController();
|
|
252
|
+
activeStream = controller;
|
|
253
|
+
statusView.setText(statusText("queued", 1));
|
|
254
|
+
try {
|
|
255
|
+
await streamControl(stateDir, { op: "turn.attach", turnId }, (frame) => { if (frame.type === "result" || frame.type === "error")
|
|
256
|
+
activeInteractionTurnId = null; renderFrame(frame, push, appendLive, commitLive, pushResponse, updateTool, updateThinking, setWakeState, () => commitLive("")); }, controller.signal);
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
if (!controller.signal.aborted)
|
|
260
|
+
push(errorLine(error));
|
|
261
|
+
}
|
|
262
|
+
finally {
|
|
263
|
+
if (activeStream === controller)
|
|
264
|
+
activeStream = null;
|
|
265
|
+
busy.active = false;
|
|
266
|
+
await refreshGoalBar(stateDir, goalView, tui);
|
|
267
|
+
statusView.setText(statusText("ready"));
|
|
268
|
+
continuePending();
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
const continuePending = () => {
|
|
272
|
+
if (exiting || configuring || busy.active)
|
|
196
273
|
return;
|
|
274
|
+
const turnId = queuedTurnIds.shift();
|
|
275
|
+
if (turnId) {
|
|
276
|
+
void attachTurn(turnId);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const next = queued.shift();
|
|
280
|
+
if (next)
|
|
281
|
+
void send(next, false);
|
|
282
|
+
};
|
|
283
|
+
const steer = async (message) => {
|
|
284
|
+
try {
|
|
285
|
+
const outcome = await requestControl(stateDir, { op: "turn.steer", message });
|
|
286
|
+
const value = outcome && typeof outcome === "object" && !Array.isArray(outcome) ? outcome : {};
|
|
287
|
+
const queuedBySupervisor = value.steered === false && typeof value.turnId === "string";
|
|
288
|
+
if (queuedBySupervisor) {
|
|
289
|
+
queuedTurnIds.push(String(value.turnId));
|
|
290
|
+
activeStream?.abort();
|
|
291
|
+
}
|
|
292
|
+
statusView.setText(queuedBySupervisor ? `${tuiTheme.warning("new Turn")} ${tuiTheme.muted("Runner stopped accepting steering; continuing in a fresh Turn")}` : `${tuiTheme.accent("working")} ${tuiTheme.muted("your update is steering this turn · /stop cancels")}`);
|
|
293
|
+
tui.requestRender();
|
|
294
|
+
if (queuedBySupervisor && !busy.active)
|
|
295
|
+
continuePending();
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
299
|
+
if (reason.includes("no longer accepting steering messages")) {
|
|
300
|
+
queued.push(message);
|
|
301
|
+
statusView.setText(statusText("working", queued.length));
|
|
302
|
+
if (!busy.active)
|
|
303
|
+
continuePending();
|
|
304
|
+
}
|
|
305
|
+
else
|
|
306
|
+
push(errorLine(error));
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
const submitSteer = (message) => {
|
|
310
|
+
transcriptView.addUser(message);
|
|
311
|
+
tui.requestRender();
|
|
312
|
+
steeringTail = steeringTail.then(() => exiting ? undefined : steer(message));
|
|
313
|
+
};
|
|
314
|
+
const withConfigurationScreen = async (work) => {
|
|
315
|
+
if (busy.active) {
|
|
316
|
+
const snapshot = await requestControl(stateDir, { op: "status" }).catch(() => null);
|
|
317
|
+
if (!snapshot) {
|
|
318
|
+
push("Cannot inspect the current turn; use /stop before changing Runner configuration.");
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const turns = snapshot && typeof snapshot === "object" && !Array.isArray(snapshot) && Array.isArray(snapshot.turns) ? snapshot.turns : [];
|
|
322
|
+
if (turns.some((turn) => turn.status === "in_progress")) {
|
|
323
|
+
push("Wait for the current Turn or use /stop before changing Runner configuration.");
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
197
326
|
}
|
|
327
|
+
else
|
|
328
|
+
configuring = true;
|
|
198
329
|
statusView.setText(statusText("setup"));
|
|
199
330
|
tui.stop();
|
|
200
331
|
try {
|
|
201
|
-
await
|
|
332
|
+
await work();
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
push(errorLine(error));
|
|
202
336
|
}
|
|
203
337
|
finally {
|
|
338
|
+
configuring = false;
|
|
204
339
|
if (!exiting) {
|
|
205
340
|
tui.start();
|
|
206
341
|
tui.requestRender(true);
|
|
207
342
|
statusView.setText(statusText("ready"));
|
|
343
|
+
continuePending();
|
|
208
344
|
}
|
|
209
345
|
}
|
|
210
346
|
};
|
|
347
|
+
const launchRunnerCommand = async (command, commandArgs = []) => withConfigurationScreen(async () => {
|
|
348
|
+
const current = configuredRunnerProfile(configPath);
|
|
349
|
+
if (!current)
|
|
350
|
+
throw new Error("No Runner Profile is configured; use /setup first.");
|
|
351
|
+
const result = await runRunnerCommandWizard(current, command, commandArgs);
|
|
352
|
+
try {
|
|
353
|
+
await applyWizardResult({ profile: result.profile }, existsSync(configPath) ? configPath : null);
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
await result.rollback?.();
|
|
357
|
+
throw error;
|
|
358
|
+
}
|
|
359
|
+
for (const line of result.output)
|
|
360
|
+
push(line);
|
|
361
|
+
push(await reloadDaemon(stateDir, configPath) ? "Configuration updated — applies to the next Turn." : "Configuration saved — restart Goah to apply it.");
|
|
362
|
+
});
|
|
363
|
+
const launchSetup = async (text) => withConfigurationScreen(async () => {
|
|
364
|
+
const current = configuredRunnerProfile(configPath);
|
|
365
|
+
const requested = text.slice("/setup".length).trim();
|
|
366
|
+
if (requested && !["runner", "model", "auth"].includes(requested))
|
|
367
|
+
throw new Error("usage: /setup [runner|model|auth]");
|
|
368
|
+
const section = requested || (current ? await chooseSetupSection(current) : "runner");
|
|
369
|
+
if (!section)
|
|
370
|
+
return;
|
|
371
|
+
if (section === "runner" || !current) {
|
|
372
|
+
const result = await runSetupWizard(current);
|
|
373
|
+
if (!result.profile)
|
|
374
|
+
return;
|
|
375
|
+
await applyWizardResult(result, existsSync(configPath) ? configPath : null);
|
|
376
|
+
push(await reloadDaemon(stateDir, configPath) ? "Runner profile updated — applies to the next Turn." : "Runner profile saved — restart Goah to apply it.");
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
const result = await runRunnerCommandWizard(current, section === "model" ? "model" : "auth");
|
|
380
|
+
try {
|
|
381
|
+
await applyWizardResult({ profile: result.profile }, existsSync(configPath) ? configPath : null);
|
|
382
|
+
}
|
|
383
|
+
catch (error) {
|
|
384
|
+
await result.rollback?.();
|
|
385
|
+
throw error;
|
|
386
|
+
}
|
|
387
|
+
for (const line of result.output)
|
|
388
|
+
push(line);
|
|
389
|
+
push(await reloadDaemon(stateDir, configPath) ? "Configuration updated — applies to the next Turn." : "Configuration saved — restart Goah to apply it.");
|
|
390
|
+
});
|
|
211
391
|
input.onSubmit = (line) => {
|
|
212
392
|
const { action, text } = classifyTuiInput(line, busy.active);
|
|
213
393
|
input.setText("");
|
|
@@ -219,7 +399,7 @@ export async function runGoahTui(configPath, stateDir, initialMessage) {
|
|
|
219
399
|
return;
|
|
220
400
|
}
|
|
221
401
|
if (action === "help") {
|
|
222
|
-
push(`${tuiTheme.strong("Commands")}\n /model /setup /status /records /history
|
|
402
|
+
push(`${tuiTheme.strong("Commands")}\n /model /login /logout /setup /status\n /records /history /goal /observe /stop /quit\n`);
|
|
223
403
|
return;
|
|
224
404
|
}
|
|
225
405
|
if (action === "status") {
|
|
@@ -236,27 +416,33 @@ export async function runGoahTui(configPath, stateDir, initialMessage) {
|
|
|
236
416
|
}
|
|
237
417
|
if (action === "model") {
|
|
238
418
|
if (text === "/model")
|
|
239
|
-
void
|
|
419
|
+
void launchRunnerCommand("model");
|
|
240
420
|
else
|
|
241
421
|
void switchModelCommand(text, configPath, stateDir, push);
|
|
242
422
|
return;
|
|
243
423
|
}
|
|
424
|
+
if (action === "login") {
|
|
425
|
+
void launchRunnerCommand("auth", ["login", text.slice("/login".length).trim()].filter(Boolean));
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (action === "logout") {
|
|
429
|
+
void launchRunnerCommand("auth", ["logout", text.slice("/logout".length).trim()].filter(Boolean));
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
244
432
|
if (action === "setup") {
|
|
245
|
-
void launchSetup();
|
|
433
|
+
void launchSetup(text);
|
|
246
434
|
return;
|
|
247
435
|
}
|
|
248
436
|
if (action === "goal") {
|
|
249
437
|
void slashGoal(text, stateDir, push).finally(() => refreshGoalBar(stateDir, goalView, tui));
|
|
250
438
|
return;
|
|
251
439
|
}
|
|
252
|
-
if (action === "
|
|
253
|
-
|
|
440
|
+
if (action === "unknown") {
|
|
441
|
+
push(errorLine(`Unknown command: ${text.split(/\s+/, 1)[0]}. Use /help to list commands.`));
|
|
254
442
|
return;
|
|
255
443
|
}
|
|
256
|
-
if (action === "
|
|
257
|
-
|
|
258
|
-
push(tuiTheme.muted(`queued ${text}`));
|
|
259
|
-
statusView.setText(statusText("working", queued.length));
|
|
444
|
+
if (action === "steer") {
|
|
445
|
+
submitSteer(text);
|
|
260
446
|
return;
|
|
261
447
|
}
|
|
262
448
|
if (action === "send")
|
|
@@ -269,7 +455,7 @@ export async function runGoahTui(configPath, stateDir, initialMessage) {
|
|
|
269
455
|
if (data !== "\x03")
|
|
270
456
|
return undefined;
|
|
271
457
|
exiting = true;
|
|
272
|
-
push(busy.active ? "Detached — the current
|
|
458
|
+
push(busy.active ? "Detached — the current Turn continues in the daemon. Use /stop before detaching when you intend to cancel it." : "Detached.");
|
|
273
459
|
activeStream?.abort();
|
|
274
460
|
tui.stop();
|
|
275
461
|
resolveExit();
|
|
@@ -278,8 +464,14 @@ export async function runGoahTui(configPath, stateDir, initialMessage) {
|
|
|
278
464
|
tui.start();
|
|
279
465
|
if (initialMessage)
|
|
280
466
|
void send(initialMessage);
|
|
467
|
+
else if (typeof liveInteractionTurnId === "string")
|
|
468
|
+
void attachTurn(liveInteractionTurnId);
|
|
281
469
|
await exited;
|
|
282
470
|
}
|
|
471
|
+
export function findLiveTurnId(turns) {
|
|
472
|
+
const id = [...turns].reverse().find((turn) => turn.status === "in_progress" && turn.source === "human")?.id;
|
|
473
|
+
return typeof id === "string" ? id : null;
|
|
474
|
+
}
|
|
283
475
|
async function runNonInteractive(configPath, stateDir, initialMessage) {
|
|
284
476
|
await ensureDaemon(configPath, stateDir);
|
|
285
477
|
console.log(`Console: ${(await waitForConsoleMetadata(stateDir)).url}`);
|
|
@@ -318,20 +510,28 @@ function frameToLine(frame) {
|
|
|
318
510
|
return lines.length ? lines.join("\n") : null;
|
|
319
511
|
}
|
|
320
512
|
/** Render one structured control-protocol frame into its own transcript channel. */
|
|
321
|
-
export function renderFrame(frame, push, appendLive = push, commitLive = push, pushResponse = push, updateTool = (activity) => push(toolActivityLine(activity)),
|
|
513
|
+
export function renderFrame(frame, push, appendLive = push, commitLive = push, pushResponse = push, updateTool = (activity) => push(toolActivityLine(activity)), updateThinking = () => { }, setWakeState = () => { }, clearLive = () => { }) {
|
|
322
514
|
if (frame.type === "error") {
|
|
323
|
-
|
|
515
|
+
updateThinking({ phase: "clear", text: "" });
|
|
516
|
+
clearLive();
|
|
324
517
|
push(`${tuiTheme.error("error")} ${safeError(frame.error)}\n`);
|
|
325
518
|
return;
|
|
326
519
|
}
|
|
327
|
-
if (frame.type === "accepted")
|
|
520
|
+
if (frame.type === "accepted") {
|
|
521
|
+
const value = frame.value && typeof frame.value === "object" && !Array.isArray(frame.value) ? frame.value : {};
|
|
522
|
+
setWakeState(value.steered === true ? "working" : "queued");
|
|
328
523
|
return;
|
|
524
|
+
}
|
|
329
525
|
if (frame.type === "result") {
|
|
330
526
|
const value = frame.value && typeof frame.value === "object" && !Array.isArray(frame.value) ? frame.value : {};
|
|
331
527
|
const response = value.response && typeof value.response === "object" && !Array.isArray(value.response) ? value.response : {};
|
|
332
|
-
|
|
528
|
+
const turn = value.turn && typeof value.turn === "object" && !Array.isArray(value.turn) ? value.turn : {};
|
|
529
|
+
const error = turn.error && typeof turn.error === "object" && !Array.isArray(turn.error) ? turn.error : {};
|
|
530
|
+
updateThinking({ phase: "done", text: "" });
|
|
333
531
|
if (typeof response.content === "string" && response.content.trim())
|
|
334
532
|
pushResponse(response.content.trim());
|
|
533
|
+
else if (turn.status === "failed" && typeof error.message === "string")
|
|
534
|
+
push(`${tuiTheme.error("error")} ${safeError(error.message)}\n`);
|
|
335
535
|
return;
|
|
336
536
|
}
|
|
337
537
|
if (frame.type !== "event")
|
|
@@ -341,8 +541,16 @@ export function renderFrame(frame, push, appendLive = push, commitLive = push, p
|
|
|
341
541
|
return;
|
|
342
542
|
const record = event;
|
|
343
543
|
const data = record.data && typeof record.data === "object" && !Array.isArray(record.data) ? record.data : {};
|
|
544
|
+
if (record.type === "wake.enqueued") {
|
|
545
|
+
setWakeState("queued");
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
if (record.type === "turn.started" || record.type === "transcript.started") {
|
|
549
|
+
setWakeState("working");
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
344
552
|
if (record.type === "tool.called") {
|
|
345
|
-
|
|
553
|
+
updateThinking({ phase: "done", text: "" });
|
|
346
554
|
updateTool({ kind: "tool", callId: String(data.callId ?? "tool"), name: String(data.name ?? "tool"), detail: toolDetail(data.arguments), status: "running" });
|
|
347
555
|
}
|
|
348
556
|
else if (record.type === "tool.completed") {
|
|
@@ -350,39 +558,50 @@ export function renderFrame(frame, push, appendLive = push, commitLive = push, p
|
|
|
350
558
|
}
|
|
351
559
|
else if (record.type === "message.assistant.delta") {
|
|
352
560
|
const delta = data.delta && typeof data.delta === "object" && !Array.isArray(data.delta) ? data.delta : {};
|
|
353
|
-
if (delta.type === "thinking_start"
|
|
354
|
-
|
|
561
|
+
if (delta.type === "thinking_start")
|
|
562
|
+
updateThinking({ phase: "start", text: "" });
|
|
563
|
+
else if (delta.type === "thinking_delta" && typeof delta.delta === "string")
|
|
564
|
+
updateThinking({ phase: "delta", text: delta.delta });
|
|
565
|
+
else if (delta.type === "thinking_end")
|
|
566
|
+
updateThinking({ phase: "done", text: typeof delta.content === "string" ? delta.content : "" });
|
|
355
567
|
else if (delta.type === "text_start" || delta.type === "text_delta") {
|
|
356
|
-
|
|
568
|
+
updateThinking({ phase: "done", text: "" });
|
|
357
569
|
if (delta.type === "text_delta" && typeof delta.delta === "string")
|
|
358
570
|
appendLive(delta.delta);
|
|
359
571
|
}
|
|
360
572
|
else if (delta.type === "toolcall_start" || delta.type === "toolcall_delta")
|
|
361
|
-
|
|
573
|
+
updateThinking({ phase: "done", text: "" });
|
|
362
574
|
}
|
|
363
575
|
else if (record.type === "message.assistant.completed") {
|
|
364
|
-
|
|
576
|
+
updateThinking({ phase: "done", text: "" });
|
|
365
577
|
const message = data.message && typeof data.message === "object" ? data.message : {};
|
|
578
|
+
if (message.stopReason === "error" || message.stopReason === "aborted") {
|
|
579
|
+
clearLive();
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
366
582
|
const text = messageText(message.content);
|
|
583
|
+
if (data.completionIntent === "handoff") {
|
|
584
|
+
clearLive();
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
367
587
|
if (text)
|
|
368
588
|
commitLive(text);
|
|
369
589
|
}
|
|
590
|
+
else if (record.type === "response.committed") {
|
|
591
|
+
if (typeof data.text === "string" && data.text.trim())
|
|
592
|
+
commitLive(data.text.trim());
|
|
593
|
+
}
|
|
370
594
|
else if (record.type === "handoff.recorded") {
|
|
371
595
|
if (typeof data.goalId === "string")
|
|
372
596
|
push(`${data.outcome === "blocked" ? tuiTheme.error("goal blocked") : tuiTheme.success("goal saved")} ${tuiTheme.muted(`${String(data.outcome).replaceAll("_", " ")} · record r${String(data.recordRevision)}`)}`);
|
|
373
|
-
else {
|
|
374
|
-
const results = Array.isArray(data.results) ? data.results : [];
|
|
375
|
-
for (const result of results)
|
|
376
|
-
if (typeof result === "string")
|
|
377
|
-
push(`${tuiTheme.success("done")} ${result}`);
|
|
378
|
-
}
|
|
379
597
|
}
|
|
380
598
|
else if (record.type === "ceo.human_requested") {
|
|
381
599
|
push(`${tuiTheme.warning("needs you")} ${safeError(compact(record.data ?? {}))}`);
|
|
382
600
|
}
|
|
383
|
-
else if (record.type === "
|
|
384
|
-
|
|
385
|
-
|
|
601
|
+
else if (record.type === "transcript.interrupted") {
|
|
602
|
+
updateThinking({ phase: "clear", text: "" });
|
|
603
|
+
clearLive();
|
|
604
|
+
push(`${tuiTheme.error("error")} ${safeError(typeof data.reason === "string" ? data.reason : "Turn failed")}\n`);
|
|
386
605
|
}
|
|
387
606
|
}
|
|
388
607
|
function toolDetail(value) {
|
|
@@ -407,7 +626,7 @@ async function printStatus(stateDir, push) {
|
|
|
407
626
|
const roots = Array.isArray(value.roots) ? value.roots : [];
|
|
408
627
|
const team = Array.isArray(value.team) ? value.team : [];
|
|
409
628
|
const pending = Array.isArray(value.pendingHuman) ? value.pendingHuman.length : 0;
|
|
410
|
-
push([tuiTheme.strong("Status"), roots[0] ? ` ${tuiTheme.active(" GOAL ")} ${String(roots[0].objective)} ${tuiTheme.muted(String(roots[0].phase))}` : ` ${tuiTheme.muted("No active Goal")}`, ` ${tuiTheme.muted(team.length ? team.map((member) => `${String(member.agent)} ${String(member.
|
|
629
|
+
push([tuiTheme.strong("Status"), roots[0] ? ` ${tuiTheme.active(" GOAL ")} ${String(roots[0].objective)} ${tuiTheme.muted(String(roots[0].phase))}` : ` ${tuiTheme.muted("No active Goal")}`, ` ${tuiTheme.muted(team.length ? team.map((member) => `${String(member.agent)} ${String(member.motion)}${member.lastOutcome ? `/${String(member.lastOutcome)}` : ""}`).join(" · ") : "No Goal Agents")}`, ...(pending ? [` ${tuiTheme.warning(`${pending} decision${pending === 1 ? "" : "s"} need you`)}`] : []), ""].join("\n"));
|
|
411
630
|
}
|
|
412
631
|
catch (error) {
|
|
413
632
|
push(errorLine(error));
|
|
@@ -447,8 +666,15 @@ async function printRecords(text, stateDir, push) {
|
|
|
447
666
|
}
|
|
448
667
|
async function stopCeoWake(stateDir, push) {
|
|
449
668
|
try {
|
|
450
|
-
const
|
|
451
|
-
|
|
669
|
+
const snapshot = await requestControl(stateDir, { op: "status" });
|
|
670
|
+
const turns = snapshot && typeof snapshot === "object" && !Array.isArray(snapshot) && Array.isArray(snapshot.turns) ? snapshot.turns : [];
|
|
671
|
+
const turnId = findLiveTurnId(turns);
|
|
672
|
+
if (!turnId) {
|
|
673
|
+
push(tuiTheme.muted("No active Turn."));
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
await requestControl(stateDir, { op: "turn.interrupt", turnId });
|
|
677
|
+
push(`${tuiTheme.warning("stopping")} Current Turn was interrupted.`);
|
|
452
678
|
}
|
|
453
679
|
catch (error) {
|
|
454
680
|
push(errorLine(error));
|
|
@@ -480,25 +706,6 @@ async function slashGoal(text, stateDir, push) {
|
|
|
480
706
|
push(errorLine(error));
|
|
481
707
|
}
|
|
482
708
|
}
|
|
483
|
-
/** /approve ID --reason TEXT --evidence SEQ[,SEQ] (and /reject with the same shape). */
|
|
484
|
-
async function slashApprove(text, stateDir, push) {
|
|
485
|
-
const approve = text.startsWith("/approve ");
|
|
486
|
-
const rest = text.slice(approve ? 9 : 8).match(/^(\S+)(?:\s+--reason\s+(.*?))?(?:\s+--evidence\s+([\d,]+))?$/);
|
|
487
|
-
if (!rest) {
|
|
488
|
-
push(errorLine("usage: /approve ACTION_ID --reason TEXT --evidence SEQ[,SEQ]"));
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
const [, id = "", reason = "terminal approval", evidence = ""] = rest;
|
|
492
|
-
try {
|
|
493
|
-
const op = approve ? { op: "action.approve", id, reason, evidence: evidence ? evidence.split(",").map(Number) : [] }
|
|
494
|
-
: { op: "action.reject", id, reason, evidence: evidence ? evidence.split(",").map(Number) : [] };
|
|
495
|
-
await requestControl(stateDir, op);
|
|
496
|
-
push(`${tuiTheme.success(approve ? "approved" : "rejected")} ${id}`);
|
|
497
|
-
}
|
|
498
|
-
catch (error) {
|
|
499
|
-
push(errorLine(error));
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
709
|
async function ensureDaemon(configPath, stateDir) {
|
|
503
710
|
if (await controlAvailable(stateDir)) {
|
|
504
711
|
const version = await requestControl(stateDir, { op: "daemon.version" }).catch(() => null);
|
|
@@ -544,7 +751,7 @@ function safeError(value) {
|
|
|
544
751
|
const named = sanitized.match(/^(?:TypeError|RangeError|ReferenceError|SyntaxError|Error):\s*[^\n]+/m)?.[0];
|
|
545
752
|
if (named)
|
|
546
753
|
return named;
|
|
547
|
-
return sanitized.split("\n").map((line) => line.trim()).find((line) => line && !line.startsWith("file://") && !line.startsWith("at ") && line !== "^") ?? "
|
|
754
|
+
return sanitized.split("\n").map((line) => line.trim()).find((line) => line && !line.startsWith("file://") && !line.startsWith("at ") && line !== "^") ?? "Turn failed";
|
|
548
755
|
}
|
|
549
756
|
function messageText(value) {
|
|
550
757
|
if (typeof value === "string")
|
|
@@ -570,14 +777,8 @@ async function switchModelCommand(text, configPath, stateDir, push) {
|
|
|
570
777
|
push(errorLine(error));
|
|
571
778
|
}
|
|
572
779
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
if (!result.profile) {
|
|
577
|
-
push("setup cancelled; nothing changed");
|
|
578
|
-
return;
|
|
579
|
-
}
|
|
580
|
-
applyWizardResult(result, configPath);
|
|
581
|
-
push(await reloadDaemon(stateDir, configPath) ? "config reloaded — applies to the next wake" : `saved to ${resolve(configPath)}; daemon will pick it up on next start`);
|
|
780
|
+
function configuredRunnerProfile(configPath) {
|
|
781
|
+
const workspace = existsSync(configPath) ? loadConfig(configPath) : null;
|
|
782
|
+
return workspace?.runnerProfiles?.find((profile) => profile.id === "default") ?? workspace?.runnerProfiles?.[0] ?? readDefaultRunnerProfile();
|
|
582
783
|
}
|
|
583
784
|
//# sourceMappingURL=tui.js.map
|