openhorse 0.2.22 → 0.2.24
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/commands/target-command.d.ts +21 -0
- package/dist/commands/target-command.d.ts.map +1 -0
- package/dist/commands/target-command.js +81 -0
- package/dist/commands/target-command.js.map +1 -0
- package/dist/harness/capsule.d.ts +1 -0
- package/dist/harness/capsule.d.ts.map +1 -1
- package/dist/harness/capsule.js +38 -9
- package/dist/harness/capsule.js.map +1 -1
- package/dist/harness/contract.d.ts +2 -0
- package/dist/harness/contract.d.ts.map +1 -1
- package/dist/harness/contract.js +78 -14
- package/dist/harness/contract.js.map +1 -1
- package/dist/harness/index.d.ts +2 -2
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +4 -1
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/state.d.ts.map +1 -1
- package/dist/harness/state.js +37 -7
- package/dist/harness/state.js.map +1 -1
- package/dist/runtime/agent-runtime-controller.d.ts +5 -0
- package/dist/runtime/agent-runtime-controller.d.ts.map +1 -1
- package/dist/runtime/agent-runtime-controller.js +54 -0
- package/dist/runtime/agent-runtime-controller.js.map +1 -1
- package/dist/runtime/agent-runtime-protocol.d.ts +4 -0
- package/dist/runtime/agent-runtime-protocol.d.ts.map +1 -1
- package/dist/runtime/agent-runtime-protocol.js.map +1 -1
- package/dist/runtime/aggregate-tool-presenter.d.ts +13 -0
- package/dist/runtime/aggregate-tool-presenter.d.ts.map +1 -0
- package/dist/runtime/aggregate-tool-presenter.js +44 -0
- package/dist/runtime/aggregate-tool-presenter.js.map +1 -0
- package/dist/runtime/chat-controller.d.ts +9 -2
- package/dist/runtime/chat-controller.d.ts.map +1 -1
- package/dist/runtime/chat-controller.js +129 -17
- package/dist/runtime/chat-controller.js.map +1 -1
- package/dist/runtime/goal-coordinator.d.ts +66 -0
- package/dist/runtime/goal-coordinator.d.ts.map +1 -0
- package/dist/runtime/goal-coordinator.js +200 -0
- package/dist/runtime/goal-coordinator.js.map +1 -0
- package/dist/runtime/goals/accounting.d.ts +17 -0
- package/dist/runtime/goals/accounting.d.ts.map +1 -0
- package/dist/runtime/goals/accounting.js +45 -0
- package/dist/runtime/goals/accounting.js.map +1 -0
- package/dist/runtime/goals/completion-audit.d.ts +24 -0
- package/dist/runtime/goals/completion-audit.d.ts.map +1 -0
- package/dist/runtime/goals/completion-audit.js +48 -0
- package/dist/runtime/goals/completion-audit.js.map +1 -0
- package/dist/runtime/goals/coordinator.d.ts +42 -0
- package/dist/runtime/goals/coordinator.d.ts.map +1 -0
- package/dist/runtime/goals/coordinator.js +277 -0
- package/dist/runtime/goals/coordinator.js.map +1 -0
- package/dist/runtime/goals/prompt.d.ts +16 -0
- package/dist/runtime/goals/prompt.d.ts.map +1 -0
- package/dist/runtime/goals/prompt.js +50 -0
- package/dist/runtime/goals/prompt.js.map +1 -0
- package/dist/runtime/goals/tools.d.ts +43 -0
- package/dist/runtime/goals/tools.d.ts.map +1 -0
- package/dist/runtime/goals/tools.js +88 -0
- package/dist/runtime/goals/tools.js.map +1 -0
- package/dist/runtime/goals/types.d.ts +167 -0
- package/dist/runtime/goals/types.d.ts.map +1 -0
- package/dist/runtime/goals/types.js +72 -0
- package/dist/runtime/goals/types.js.map +1 -0
- package/dist/runtime/tool-detail-repository.d.ts +45 -0
- package/dist/runtime/tool-detail-repository.d.ts.map +1 -0
- package/dist/runtime/tool-detail-repository.js +131 -0
- package/dist/runtime/tool-detail-repository.js.map +1 -0
- package/dist/runtime/tool-output-presentation.d.ts +89 -0
- package/dist/runtime/tool-output-presentation.d.ts.map +1 -0
- package/dist/runtime/tool-output-presentation.js +329 -0
- package/dist/runtime/tool-output-presentation.js.map +1 -0
- package/dist/runtime/ui-events.d.ts +4 -0
- package/dist/runtime/ui-events.d.ts.map +1 -1
- package/dist/runtime/ui-events.js.map +1 -1
- package/dist/services/goal-sidecar.d.ts +96 -0
- package/dist/services/goal-sidecar.d.ts.map +1 -0
- package/dist/services/goal-sidecar.js +145 -0
- package/dist/services/goal-sidecar.js.map +1 -0
- package/dist/services/goal-storage.d.ts +22 -0
- package/dist/services/goal-storage.d.ts.map +1 -0
- package/dist/services/goal-storage.js +153 -0
- package/dist/services/goal-storage.js.map +1 -0
- package/dist/services/model-context.d.ts.map +1 -1
- package/dist/services/model-context.js +7 -0
- package/dist/services/model-context.js.map +1 -1
- package/dist/services/session-storage.d.ts +7 -0
- package/dist/services/session-storage.d.ts.map +1 -1
- package/dist/services/session-storage.js +64 -27
- package/dist/services/session-storage.js.map +1 -1
- package/dist/services/storage-maintenance.d.ts.map +1 -1
- package/dist/services/storage-maintenance.js +3 -2
- package/dist/services/storage-maintenance.js.map +1 -1
- package/dist/terminal-ui/editor.d.ts.map +1 -1
- package/dist/terminal-ui/editor.js +14 -3
- package/dist/terminal-ui/editor.js.map +1 -1
- package/dist/terminal-ui/launch.d.ts +19 -0
- package/dist/terminal-ui/launch.d.ts.map +1 -1
- package/dist/terminal-ui/launch.js +187 -24
- package/dist/terminal-ui/launch.js.map +1 -1
- package/dist/terminal-ui/output-queue.d.ts +43 -0
- package/dist/terminal-ui/output-queue.d.ts.map +1 -0
- package/dist/terminal-ui/output-queue.js +139 -0
- package/dist/terminal-ui/output-queue.js.map +1 -0
- package/dist/terminal-ui/raw-editor.d.ts +33 -0
- package/dist/terminal-ui/raw-editor.d.ts.map +1 -1
- package/dist/terminal-ui/raw-editor.js +142 -23
- package/dist/terminal-ui/raw-editor.js.map +1 -1
- package/dist/tools/goal.d.ts +17 -0
- package/dist/tools/goal.d.ts.map +1 -0
- package/dist/tools/goal.js +191 -0
- package/dist/tools/goal.js.map +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +133 -58
- package/dist/tools/index.js.map +1 -1
- package/dist/tui-core/input-parser.d.ts +9 -2
- package/dist/tui-core/input-parser.d.ts.map +1 -1
- package/dist/tui-core/input-parser.js +37 -2
- package/dist/tui-core/input-parser.js.map +1 -1
- package/dist/tui-ui/inline-surface.d.ts +7 -1
- package/dist/tui-ui/inline-surface.d.ts.map +1 -1
- package/dist/tui-ui/inline-surface.js +23 -2
- package/dist/tui-ui/inline-surface.js.map +1 -1
- package/dist/tui-ui/input-ownership.d.ts +46 -0
- package/dist/tui-ui/input-ownership.d.ts.map +1 -0
- package/dist/tui-ui/input-ownership.js +74 -0
- package/dist/tui-ui/input-ownership.js.map +1 -0
- package/dist/tui-ui/launch.d.ts +1 -0
- package/dist/tui-ui/launch.d.ts.map +1 -1
- package/dist/tui-ui/launch.js +104 -2
- package/dist/tui-ui/launch.js.map +1 -1
- package/dist/tui-ui/layout.d.ts +1 -0
- package/dist/tui-ui/layout.d.ts.map +1 -1
- package/dist/tui-ui/layout.js +5 -1
- package/dist/tui-ui/layout.js.map +1 -1
- package/dist/tui-ui/runner.d.ts +32 -0
- package/dist/tui-ui/runner.d.ts.map +1 -1
- package/dist/tui-ui/runner.js +553 -24
- package/dist/tui-ui/runner.js.map +1 -1
- package/dist/tui-ui/state.d.ts +65 -0
- package/dist/tui-ui/state.d.ts.map +1 -1
- package/dist/tui-ui/state.js +187 -2
- package/dist/tui-ui/state.js.map +1 -1
- package/dist/tui-ui/theme-profile.d.ts +25 -0
- package/dist/tui-ui/theme-profile.d.ts.map +1 -0
- package/dist/tui-ui/theme-profile.js +130 -0
- package/dist/tui-ui/theme-profile.js.map +1 -0
- package/dist/tui-ui/transcript-inspector-layout.d.ts +9 -0
- package/dist/tui-ui/transcript-inspector-layout.d.ts.map +1 -0
- package/dist/tui-ui/transcript-inspector-layout.js +97 -0
- package/dist/tui-ui/transcript-inspector-layout.js.map +1 -0
- package/dist/tui-ui/transcript-inspector-surface.d.ts +18 -0
- package/dist/tui-ui/transcript-inspector-surface.d.ts.map +1 -0
- package/dist/tui-ui/transcript-inspector-surface.js +88 -0
- package/dist/tui-ui/transcript-inspector-surface.js.map +1 -0
- package/dist/tui-ui/transcript-inspector.d.ts +35 -0
- package/dist/tui-ui/transcript-inspector.d.ts.map +1 -0
- package/dist/tui-ui/transcript-inspector.js +128 -0
- package/dist/tui-ui/transcript-inspector.js.map +1 -0
- package/dist/tui-ui/transcript-layout.d.ts +1 -0
- package/dist/tui-ui/transcript-layout.d.ts.map +1 -1
- package/dist/tui-ui/transcript-layout.js +44 -3
- package/dist/tui-ui/transcript-layout.js.map +1 -1
- package/package.json +1 -1
package/dist/tui-ui/runner.js
CHANGED
|
@@ -8,10 +8,16 @@ const layout_1 = require("./layout");
|
|
|
8
8
|
const pickers_1 = require("./pickers");
|
|
9
9
|
const render_scheduler_1 = require("./render-scheduler");
|
|
10
10
|
const state_1 = require("./state");
|
|
11
|
+
const input_ownership_1 = require("./input-ownership");
|
|
12
|
+
const transcript_inspector_1 = require("./transcript-inspector");
|
|
13
|
+
const transcript_inspector_layout_1 = require("./transcript-inspector-layout");
|
|
11
14
|
const transcript_cache_1 = require("./transcript-cache");
|
|
12
15
|
const transcript_layout_1 = require("./transcript-layout");
|
|
13
16
|
const theme_1 = require("./theme");
|
|
14
17
|
const history_1 = require("../runtime/composer/history");
|
|
18
|
+
const promises_1 = require("fs/promises");
|
|
19
|
+
const os_1 = require("os");
|
|
20
|
+
const path_1 = require("path");
|
|
15
21
|
/** Actions that should use 'stream' priority (FPS-capped). */
|
|
16
22
|
const STREAM_ACTIONS = new Set([
|
|
17
23
|
'updateTranscript',
|
|
@@ -25,20 +31,36 @@ class TuiRunner {
|
|
|
25
31
|
constructor(options) {
|
|
26
32
|
this.options = options;
|
|
27
33
|
this.parser = new input_parser_1.TuiInputParser();
|
|
34
|
+
this.inputOwnership = new input_ownership_1.TuiInputOwnershipController();
|
|
28
35
|
this.transcriptCache = new transcript_cache_1.TranscriptLayoutCache();
|
|
29
36
|
this.history = history_1.initialHistoryState;
|
|
30
37
|
this.surfaceFailed = false;
|
|
38
|
+
this.inspectorReady = false;
|
|
39
|
+
this.inspectorSearchActive = false;
|
|
40
|
+
this.modalTransition = Promise.resolve();
|
|
41
|
+
this.commitSequence = 0;
|
|
42
|
+
this.commitInFlight = false;
|
|
43
|
+
this.commitMismatchRetries = 0;
|
|
31
44
|
this.state = state_1.initialTuiUiState;
|
|
32
45
|
this.lastFrame = null;
|
|
33
46
|
this.surfaceResizePending = false;
|
|
34
47
|
this.resizeEpoch = 0;
|
|
35
48
|
this.surfaceResizeGeneration = 0;
|
|
36
|
-
this.counters = {
|
|
49
|
+
this.counters = {
|
|
50
|
+
layoutCount: 0,
|
|
51
|
+
paintCount: 0,
|
|
52
|
+
changedRows: 0,
|
|
53
|
+
commitCount: 0,
|
|
54
|
+
};
|
|
37
55
|
this.width = options.width;
|
|
38
56
|
this.height = options.height;
|
|
39
57
|
this.surface = options.surface ?? null;
|
|
40
58
|
this.theme = (0, theme_1.resolveTuiTheme)(options.theme);
|
|
41
59
|
this.themeId = options.themeId ?? theme_1.DEFAULT_TUI_THEME_ID;
|
|
60
|
+
this.inspectorSurface = options.inspectorSurface ?? null;
|
|
61
|
+
this.inspectorController = options.detailRepository
|
|
62
|
+
? new transcript_inspector_1.TranscriptInspectorController(options.detailRepository, options.cwd ?? process.cwd())
|
|
63
|
+
: null;
|
|
42
64
|
this.scheduler = (0, render_scheduler_1.createTuiRenderScheduler)(() => this.renderLive(), options.schedulerDeps);
|
|
43
65
|
this.events = (0, state_1.createTuiUiEventSink)(action => this.dispatch(action));
|
|
44
66
|
// Initial render: paint the live region immediately.
|
|
@@ -59,6 +81,8 @@ class TuiRunner {
|
|
|
59
81
|
}
|
|
60
82
|
/** Stop stale-width paints as soon as the terminal reports SIGWINCH. */
|
|
61
83
|
beginResize(width = this.width) {
|
|
84
|
+
if (this.state.inspector)
|
|
85
|
+
return;
|
|
62
86
|
if (!this.surface || this.surfaceFailed)
|
|
63
87
|
return;
|
|
64
88
|
this.surfaceResizePending = true;
|
|
@@ -66,6 +90,12 @@ class TuiRunner {
|
|
|
66
90
|
this.surfaceResizeGeneration = this.surface.beginResize(width);
|
|
67
91
|
}
|
|
68
92
|
resize(width, height) {
|
|
93
|
+
if (this.state.inspector) {
|
|
94
|
+
this.width = width;
|
|
95
|
+
this.height = height;
|
|
96
|
+
this.paintInspector();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
69
99
|
this.beginResize(width);
|
|
70
100
|
const resizeEpoch = this.resizeEpoch;
|
|
71
101
|
const surfaceResizeGeneration = this.surfaceResizeGeneration;
|
|
@@ -102,19 +132,16 @@ class TuiRunner {
|
|
|
102
132
|
dispatch(action) {
|
|
103
133
|
const prevState = this.state;
|
|
104
134
|
this.state = (0, state_1.tuiUiReducer)(this.state, action);
|
|
135
|
+
if (action.type === 'setToolOutputViewMode' && action.mode !== prevState.toolOutputViewMode) {
|
|
136
|
+
this.transcriptCache.clear();
|
|
137
|
+
}
|
|
105
138
|
// Check if any transcript entries became committable (finalized).
|
|
106
139
|
this.tryCommit(prevState);
|
|
107
140
|
const priority = STREAM_ACTIONS.has(action.type) ? 'stream' : 'immediate';
|
|
108
141
|
this.scheduler.request(priority);
|
|
109
142
|
}
|
|
110
143
|
feedInput(chunk) {
|
|
111
|
-
const
|
|
112
|
-
if ((0, input_parser_1.isLikelyUnbracketedMultilinePaste)(raw)) {
|
|
113
|
-
const event = { type: 'paste', value: (0, input_parser_1.normalizePastedText)(raw) };
|
|
114
|
-
this.applyInputEvent(event);
|
|
115
|
-
return [event];
|
|
116
|
-
}
|
|
117
|
-
const events = this.parser.feed(chunk);
|
|
144
|
+
const events = this.parser.feed(chunk, { detectUnbracketedMultilinePaste: true });
|
|
118
145
|
for (const event of events) {
|
|
119
146
|
this.applyInputEvent(event);
|
|
120
147
|
}
|
|
@@ -143,6 +170,10 @@ class TuiRunner {
|
|
|
143
170
|
* transcript so tests can inspect complete content via getLastFrame().
|
|
144
171
|
*/
|
|
145
172
|
renderLive() {
|
|
173
|
+
if (this.state.inspector) {
|
|
174
|
+
this.paintInspector();
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
146
177
|
if (this.surface && !this.surfaceFailed) {
|
|
147
178
|
if (this.surfaceResizePending)
|
|
148
179
|
return;
|
|
@@ -188,7 +219,7 @@ class TuiRunner {
|
|
|
188
219
|
* but not yet queued.
|
|
189
220
|
*/
|
|
190
221
|
tryCommit(prevState, force = false) {
|
|
191
|
-
if (!this.surface || this.surfaceResizePending)
|
|
222
|
+
if (!this.surface || this.surfaceResizePending || this.state.inspector || this.commitInFlight)
|
|
192
223
|
return;
|
|
193
224
|
const prevCommittable = prevState.committableTranscriptCount;
|
|
194
225
|
const currCommittable = this.state.committableTranscriptCount;
|
|
@@ -209,6 +240,7 @@ class TuiRunner {
|
|
|
209
240
|
rows: this.layoutTranscriptRecord(entry, this.transcriptWidth),
|
|
210
241
|
}));
|
|
211
242
|
const batch = {
|
|
243
|
+
batchId: `tui-commit-${++this.commitSequence}`,
|
|
212
244
|
generation: this.state.transcriptGeneration,
|
|
213
245
|
reason: 'finalize',
|
|
214
246
|
entries: committedEntries,
|
|
@@ -218,38 +250,89 @@ class TuiRunner {
|
|
|
218
250
|
// live region).
|
|
219
251
|
const generation = batch.generation;
|
|
220
252
|
const getLatestLiveFrame = () => this.buildLiveFrame(this.width);
|
|
253
|
+
this.commitInFlight = true;
|
|
254
|
+
let continueCommit = true;
|
|
221
255
|
// Surface commit is async (serialized FIFO). Fire-and-forget: the
|
|
222
256
|
// commit's internal getLatestLiveFrame already rebuilds the live region,
|
|
223
257
|
// so no additional scheduler paint is needed here.
|
|
224
258
|
void this.surface
|
|
225
259
|
.commit(batch, getLatestLiveFrame)
|
|
226
|
-
.then(
|
|
227
|
-
if (
|
|
260
|
+
.then(result => {
|
|
261
|
+
if (result.batchId !== batch.batchId ||
|
|
262
|
+
result.generation !== generation ||
|
|
263
|
+
result.committedEntries !== entriesToCommit.length) {
|
|
264
|
+
if (this.state.transcriptGeneration === generation) {
|
|
265
|
+
this.state = {
|
|
266
|
+
...this.state,
|
|
267
|
+
queuedTranscriptCount: Math.max(0, this.state.queuedTranscriptCount - entriesToCommit.length),
|
|
268
|
+
};
|
|
269
|
+
this.commitMismatchRetries += 1;
|
|
270
|
+
if (this.commitMismatchRetries > 1) {
|
|
271
|
+
continueCommit = false;
|
|
272
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, {
|
|
273
|
+
type: 'setStatus',
|
|
274
|
+
message: 'TUI transcript acknowledgement mismatch; retained content for retry.',
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
void this.surface?.forceRedraw(this.buildLiveFrame(this.width));
|
|
228
279
|
return;
|
|
229
|
-
|
|
280
|
+
}
|
|
281
|
+
const acknowledgement = (0, state_1.acknowledgeTranscriptCommit)(this.state, {
|
|
282
|
+
generation,
|
|
283
|
+
recordIds: result.displayKeys ?? [],
|
|
284
|
+
});
|
|
285
|
+
if (!acknowledgement.accepted) {
|
|
286
|
+
if (this.state.transcriptGeneration === generation) {
|
|
287
|
+
this.state = {
|
|
288
|
+
...this.state,
|
|
289
|
+
queuedTranscriptCount: Math.max(0, this.state.queuedTranscriptCount - entriesToCommit.length),
|
|
290
|
+
};
|
|
291
|
+
this.commitMismatchRetries += 1;
|
|
292
|
+
if (this.commitMismatchRetries > 1) {
|
|
293
|
+
continueCommit = false;
|
|
294
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, {
|
|
295
|
+
type: 'setStatus',
|
|
296
|
+
message: 'TUI transcript acknowledgement mismatch; retained content for retry.',
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
void this.surface?.forceRedraw(this.buildLiveFrame(this.width));
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
this.state = acknowledgement.state;
|
|
304
|
+
this.commitMismatchRetries = 0;
|
|
230
305
|
this.counters.commitCount += 1;
|
|
231
306
|
})
|
|
232
|
-
.catch(error => this.handleSurfaceError(error))
|
|
307
|
+
.catch(error => this.handleSurfaceError(error))
|
|
308
|
+
.finally(() => {
|
|
309
|
+
this.commitInFlight = false;
|
|
310
|
+
if (!this.surfaceFailed && continueCommit)
|
|
311
|
+
this.tryCommit(this.state, true);
|
|
312
|
+
});
|
|
233
313
|
}
|
|
234
314
|
/** Layout a transcript record once per revision/width/theme combination. */
|
|
235
315
|
layoutTranscriptRecord(entry, width) {
|
|
236
316
|
const cached = this.transcriptCache.get(entry.id, entry.revision, this.state.transcriptGeneration, width, this.themeId);
|
|
237
317
|
if (cached)
|
|
238
318
|
return cached;
|
|
239
|
-
const rows = (0, transcript_layout_1.layoutTranscriptEntry)(entry, {
|
|
319
|
+
const rows = (0, transcript_layout_1.layoutTranscriptEntry)(entry, {
|
|
320
|
+
width,
|
|
321
|
+
theme: this.theme,
|
|
322
|
+
toolOutputMode: this.state.toolOutputViewMode,
|
|
323
|
+
});
|
|
240
324
|
this.transcriptCache.set(entry.id, entry.revision, rows, this.state.transcriptGeneration, width, this.themeId);
|
|
241
325
|
return rows;
|
|
242
326
|
}
|
|
243
327
|
get transcriptWidth() {
|
|
244
|
-
return this.surface
|
|
245
|
-
? Math.max(1, this.width - 1)
|
|
246
|
-
: Math.max(1, this.width);
|
|
328
|
+
return this.surface ? Math.max(1, this.width - 1) : Math.max(1, this.width);
|
|
247
329
|
}
|
|
248
330
|
transcriptLayoutOptions() {
|
|
249
331
|
return {
|
|
250
332
|
transcriptWidth: this.transcriptWidth,
|
|
251
333
|
theme: this.theme,
|
|
252
|
-
|
|
334
|
+
toolOutputMode: this.state.toolOutputViewMode,
|
|
335
|
+
layoutTranscriptRecord: (entry, width) => this.layoutTranscriptRecord(entry, width),
|
|
253
336
|
};
|
|
254
337
|
}
|
|
255
338
|
handleSurfaceError(error) {
|
|
@@ -264,6 +347,10 @@ class TuiRunner {
|
|
|
264
347
|
this.options.onSurfaceError?.(error);
|
|
265
348
|
}
|
|
266
349
|
applyInputEvent(event) {
|
|
350
|
+
if (this.state.inspector) {
|
|
351
|
+
this.applyInspectorInput(event);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
267
354
|
if (this.state.overlay?.type === 'permission') {
|
|
268
355
|
if (event.type === 'text') {
|
|
269
356
|
const answer = event.value.trim().toLowerCase();
|
|
@@ -308,10 +395,16 @@ class TuiRunner {
|
|
|
308
395
|
this.dispatch({ type: 'moveOverlaySelection', delta: 1 });
|
|
309
396
|
return;
|
|
310
397
|
case 'pageup':
|
|
311
|
-
this.dispatch({
|
|
398
|
+
this.dispatch({
|
|
399
|
+
type: 'moveOverlaySelection',
|
|
400
|
+
delta: -Math.max(1, overlay.request.maxVisibleItems ?? 10),
|
|
401
|
+
});
|
|
312
402
|
return;
|
|
313
403
|
case 'pagedown':
|
|
314
|
-
this.dispatch({
|
|
404
|
+
this.dispatch({
|
|
405
|
+
type: 'moveOverlaySelection',
|
|
406
|
+
delta: Math.max(1, overlay.request.maxVisibleItems ?? 10),
|
|
407
|
+
});
|
|
315
408
|
return;
|
|
316
409
|
case 'enter':
|
|
317
410
|
this.submitPrompt({ allowEmpty: true });
|
|
@@ -357,6 +450,11 @@ class TuiRunner {
|
|
|
357
450
|
this.completeCommand(overlay.items[overlay.selectedIndex], false);
|
|
358
451
|
return;
|
|
359
452
|
case 'enter':
|
|
453
|
+
if (/^\/(?:tool-output|redraw)(?:\s|$)/u.test(this.state.prompt.value.trim())) {
|
|
454
|
+
this.dispatch({ type: 'closeOverlay' });
|
|
455
|
+
this.submitPrompt();
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
360
458
|
this.completeCommand(overlay.items[overlay.selectedIndex], true);
|
|
361
459
|
return;
|
|
362
460
|
case 'escape':
|
|
@@ -415,6 +513,12 @@ class TuiRunner {
|
|
|
415
513
|
return;
|
|
416
514
|
}
|
|
417
515
|
switch (key) {
|
|
516
|
+
case 'ctrl+o':
|
|
517
|
+
this.openToolInspector();
|
|
518
|
+
return;
|
|
519
|
+
case 'ctrl+l':
|
|
520
|
+
this.forceOwnedRedraw();
|
|
521
|
+
return;
|
|
418
522
|
case 'enter':
|
|
419
523
|
this.submitPrompt();
|
|
420
524
|
return;
|
|
@@ -472,7 +576,7 @@ class TuiRunner {
|
|
|
472
576
|
historyBack() {
|
|
473
577
|
if (this.state.overlay)
|
|
474
578
|
return; // overlay handles up/down itself
|
|
475
|
-
const { value
|
|
579
|
+
const { value } = this.state.prompt;
|
|
476
580
|
const next = (0, history_1.historyPrevious)(this.history, value);
|
|
477
581
|
this.history = next;
|
|
478
582
|
const displayValue = (0, history_1.historyCurrentValue)(next, value);
|
|
@@ -537,7 +641,11 @@ class TuiRunner {
|
|
|
537
641
|
const { value, cursor } = this.state.prompt;
|
|
538
642
|
const { line } = lineColOfCursor(value, cursor);
|
|
539
643
|
const lines = value.split('\n');
|
|
540
|
-
this.dispatch({
|
|
644
|
+
this.dispatch({
|
|
645
|
+
type: 'setPrompt',
|
|
646
|
+
value,
|
|
647
|
+
cursor: cursorOfLineCol(value, line, lines[line].length),
|
|
648
|
+
});
|
|
541
649
|
}
|
|
542
650
|
submitPrompt(options = {}) {
|
|
543
651
|
const input = this.state.prompt.value;
|
|
@@ -546,6 +654,8 @@ class TuiRunner {
|
|
|
546
654
|
// Push to history before clearing.
|
|
547
655
|
this.history = (0, history_1.pushHistoryEntry)(this.history, input);
|
|
548
656
|
this.dispatch({ type: 'setPrompt', value: '', cursor: 0 });
|
|
657
|
+
if (this.handleLocalCommand(input))
|
|
658
|
+
return;
|
|
549
659
|
try {
|
|
550
660
|
const submission = this.options.onSubmit?.(input);
|
|
551
661
|
if (submission) {
|
|
@@ -559,6 +669,42 @@ class TuiRunner {
|
|
|
559
669
|
reportSubmitFailure() {
|
|
560
670
|
this.events.append({ role: 'error', content: 'Input submission failed.' });
|
|
561
671
|
}
|
|
672
|
+
handleLocalCommand(input) {
|
|
673
|
+
const command = input.trim();
|
|
674
|
+
if (command === '/redraw') {
|
|
675
|
+
this.forceOwnedRedraw();
|
|
676
|
+
return true;
|
|
677
|
+
}
|
|
678
|
+
const match = command.match(/^\/tool-output(?:\s+(adaptive|collapsed|full))?$/u);
|
|
679
|
+
if (match) {
|
|
680
|
+
const mode = match[1];
|
|
681
|
+
if (mode)
|
|
682
|
+
this.dispatch({ type: 'setToolOutputViewMode', mode });
|
|
683
|
+
this.dispatch({
|
|
684
|
+
type: 'setStatus',
|
|
685
|
+
message: `tool output: ${mode ?? this.state.toolOutputViewMode}`,
|
|
686
|
+
});
|
|
687
|
+
return true;
|
|
688
|
+
}
|
|
689
|
+
if (command.startsWith('/tool-output')) {
|
|
690
|
+
this.dispatch({
|
|
691
|
+
type: 'setStatus',
|
|
692
|
+
message: 'Usage: /tool-output adaptive|collapsed|full',
|
|
693
|
+
});
|
|
694
|
+
return true;
|
|
695
|
+
}
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
forceOwnedRedraw() {
|
|
699
|
+
if (this.surface && !this.surfaceFailed) {
|
|
700
|
+
void this.surface
|
|
701
|
+
.forceRedraw(this.buildLiveFrame(this.width))
|
|
702
|
+
.catch(error => this.handleSurfaceError(error));
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
this.lastFrame = null;
|
|
706
|
+
this.scheduler.request('immediate');
|
|
707
|
+
}
|
|
562
708
|
updatePrompt(next) {
|
|
563
709
|
this.dispatch({ type: 'setPrompt', value: next.value, cursor: next.cursor });
|
|
564
710
|
this.syncPromptOverlay(next.value);
|
|
@@ -571,7 +717,7 @@ class TuiRunner {
|
|
|
571
717
|
this.dispatch({
|
|
572
718
|
type: 'showCommandPalette',
|
|
573
719
|
query: value.slice(1),
|
|
574
|
-
items: (
|
|
720
|
+
items: visibleTuiCommandItems(value),
|
|
575
721
|
});
|
|
576
722
|
return;
|
|
577
723
|
}
|
|
@@ -593,7 +739,8 @@ class TuiRunner {
|
|
|
593
739
|
if (!item)
|
|
594
740
|
return;
|
|
595
741
|
const command = (0, commands_1.getCommands)().find(candidate => candidate.name === item.value);
|
|
596
|
-
const needsArgs =
|
|
742
|
+
const needsArgs = item.value === 'tool-output' ||
|
|
743
|
+
Boolean(command?.argumentHint || command?.params?.some(param => param.required));
|
|
597
744
|
const value = `/${item.value}${needsArgs ? ' ' : ''}`;
|
|
598
745
|
const promptAlreadyMatchesCommand = this.state.prompt.value.trim() === `/${item.value}`;
|
|
599
746
|
const nextValue = promptAlreadyMatchesCommand ? `/${item.value}` : value;
|
|
@@ -620,6 +767,366 @@ class TuiRunner {
|
|
|
620
767
|
this.dispatch({ type: 'closeOverlay' });
|
|
621
768
|
void this.options.onPermissionDecision?.(overlay.request.id, approved);
|
|
622
769
|
}
|
|
770
|
+
/** Restore any temporary Inspector terminal ownership before shutdown. */
|
|
771
|
+
async closeModalSurface() {
|
|
772
|
+
if (this.state.inspector || this.inspectorSurface?.isMounted) {
|
|
773
|
+
this.closeToolInspector();
|
|
774
|
+
}
|
|
775
|
+
await this.modalTransition;
|
|
776
|
+
}
|
|
777
|
+
/** Wait until the current Inspector ownership transition is complete. */
|
|
778
|
+
async waitForModalSurface() {
|
|
779
|
+
await this.modalTransition;
|
|
780
|
+
}
|
|
781
|
+
/** Flush every finalized transcript batch, including batches queued by acknowledgements. */
|
|
782
|
+
async flushTranscriptCommits() {
|
|
783
|
+
if (!this.surface || this.surfaceFailed)
|
|
784
|
+
return;
|
|
785
|
+
for (let attempt = 0; attempt < 1024; attempt += 1) {
|
|
786
|
+
await this.surface.whenIdle();
|
|
787
|
+
await Promise.resolve();
|
|
788
|
+
if (!this.commitInFlight && (0, state_1.pendingCommitRecords)(this.state).length === 0)
|
|
789
|
+
return;
|
|
790
|
+
if (!this.commitInFlight)
|
|
791
|
+
this.tryCommit(this.state, true);
|
|
792
|
+
}
|
|
793
|
+
throw new Error('TUI transcript commits did not settle');
|
|
794
|
+
}
|
|
795
|
+
openToolInspector() {
|
|
796
|
+
if (this.state.inspector || !this.inspectorController || !this.inspectorSurface)
|
|
797
|
+
return;
|
|
798
|
+
this.inputOwnership.capture('inspector', {
|
|
799
|
+
value: this.state.prompt.value,
|
|
800
|
+
cursor: this.state.prompt.cursor,
|
|
801
|
+
parserState: this.parser.getState(),
|
|
802
|
+
});
|
|
803
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, { type: 'openToolInspector' });
|
|
804
|
+
this.inspectorReady = false;
|
|
805
|
+
this.inspectorSearchActive = false;
|
|
806
|
+
this.modalTransition = this.modalTransition
|
|
807
|
+
.then(async () => {
|
|
808
|
+
await this.surface?.suspend();
|
|
809
|
+
this.inspectorReady = true;
|
|
810
|
+
await this.inspectorSurface.mount(this.buildInspectorFrame());
|
|
811
|
+
})
|
|
812
|
+
.catch(error => this.handleSurfaceError(error));
|
|
813
|
+
}
|
|
814
|
+
closeToolInspector() {
|
|
815
|
+
if (!this.state.inspector && !this.inspectorSurface?.isMounted)
|
|
816
|
+
return;
|
|
817
|
+
this.inspectorController?.cancel();
|
|
818
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, { type: 'closeToolInspector' });
|
|
819
|
+
const snapshot = this.inputOwnership.restore();
|
|
820
|
+
if (snapshot) {
|
|
821
|
+
this.parser.setState(snapshot.parserState);
|
|
822
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, {
|
|
823
|
+
type: 'setPrompt',
|
|
824
|
+
value: snapshot.value,
|
|
825
|
+
cursor: snapshot.cursor,
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
this.inspectorReady = false;
|
|
829
|
+
this.inspectorSearchActive = false;
|
|
830
|
+
this.modalTransition = this.modalTransition
|
|
831
|
+
.then(async () => {
|
|
832
|
+
await this.inspectorSurface?.unmount();
|
|
833
|
+
if (this.surface) {
|
|
834
|
+
await this.surface.restore(() => this.buildLiveFrame(this.width), this.width, this.height);
|
|
835
|
+
}
|
|
836
|
+
this.scheduler.request('immediate');
|
|
837
|
+
})
|
|
838
|
+
.catch(error => this.handleSurfaceError(error));
|
|
839
|
+
}
|
|
840
|
+
applyInspectorInput(event) {
|
|
841
|
+
if (event.type === 'paste')
|
|
842
|
+
return;
|
|
843
|
+
if (event.type === 'text') {
|
|
844
|
+
if (!this.inspectorSearchActive) {
|
|
845
|
+
if (event.value === 'j') {
|
|
846
|
+
this.moveInspectorSelection(1);
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
if (event.value === 'k') {
|
|
850
|
+
this.moveInspectorSelection(-1);
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
if (event.value === ' ') {
|
|
854
|
+
void this.loadSelectedInspectorDetail(false);
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
if (event.value === 'g') {
|
|
858
|
+
this.moveInspectorSelectionTo('first');
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
if (event.value === 'G') {
|
|
862
|
+
this.moveInspectorSelectionTo('last');
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
if (event.value === 'n' && this.state.inspector?.searchQuery) {
|
|
866
|
+
this.moveInspectorSelection(1, true);
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
if (event.value === 'N' && this.state.inspector?.searchQuery) {
|
|
870
|
+
this.moveInspectorSelection(-1, true);
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
if (event.value === 'v') {
|
|
874
|
+
this.openSelectedInspectorDetailInEditor();
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
if (!this.inspectorSearchActive && (event.value === 'q' || event.value === 'Q')) {
|
|
879
|
+
this.closeToolInspector();
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
if (!this.inspectorSearchActive && event.value === '/') {
|
|
883
|
+
this.inspectorSearchActive = true;
|
|
884
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, { type: 'setToolInspectorSearch', query: '' });
|
|
885
|
+
this.paintInspector();
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
if (!this.inspectorSearchActive && event.value === '[') {
|
|
889
|
+
this.exportInspectorResults();
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
892
|
+
if (this.inspectorSearchActive) {
|
|
893
|
+
const query = `${this.state.inspector?.searchQuery ?? ''}${event.value}`;
|
|
894
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, { type: 'setToolInspectorSearch', query });
|
|
895
|
+
this.paintInspector();
|
|
896
|
+
}
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
switch (event.key) {
|
|
900
|
+
case 'ctrl+o':
|
|
901
|
+
case 'escape':
|
|
902
|
+
this.closeToolInspector();
|
|
903
|
+
return;
|
|
904
|
+
case 'ctrl+c':
|
|
905
|
+
this.closeToolInspector();
|
|
906
|
+
return;
|
|
907
|
+
case 'up':
|
|
908
|
+
this.moveInspectorSelection(-1);
|
|
909
|
+
return;
|
|
910
|
+
case 'down':
|
|
911
|
+
this.moveInspectorSelection(1);
|
|
912
|
+
return;
|
|
913
|
+
case 'pageup':
|
|
914
|
+
case 'ctrl+u':
|
|
915
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, { type: 'scrollToolInspector', delta: -10 });
|
|
916
|
+
this.paintInspector();
|
|
917
|
+
return;
|
|
918
|
+
case 'pagedown':
|
|
919
|
+
case 'ctrl+d':
|
|
920
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, { type: 'scrollToolInspector', delta: 10 });
|
|
921
|
+
void this.loadSelectedInspectorDetail(true);
|
|
922
|
+
return;
|
|
923
|
+
case 'home':
|
|
924
|
+
this.moveInspectorSelectionTo('first');
|
|
925
|
+
return;
|
|
926
|
+
case 'end':
|
|
927
|
+
this.moveInspectorSelectionTo('last');
|
|
928
|
+
return;
|
|
929
|
+
case 'backspace': {
|
|
930
|
+
if (!this.inspectorSearchActive)
|
|
931
|
+
return;
|
|
932
|
+
const query = this.state.inspector?.searchQuery ?? '';
|
|
933
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, {
|
|
934
|
+
type: 'setToolInspectorSearch',
|
|
935
|
+
query: query.slice(0, -1),
|
|
936
|
+
});
|
|
937
|
+
this.paintInspector();
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
case 'enter':
|
|
941
|
+
if (this.inspectorSearchActive) {
|
|
942
|
+
this.inspectorSearchActive = false;
|
|
943
|
+
this.paintInspector();
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
void this.loadSelectedInspectorDetail(false);
|
|
947
|
+
return;
|
|
948
|
+
case 'ctrl+e':
|
|
949
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, { type: 'toggleAllToolInspectorEntries' });
|
|
950
|
+
this.paintInspector();
|
|
951
|
+
return;
|
|
952
|
+
case 'ctrl+l':
|
|
953
|
+
this.paintInspector();
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
async loadSelectedInspectorDetail(append) {
|
|
958
|
+
const inspector = this.state.inspector;
|
|
959
|
+
if (!inspector || !this.inspectorController)
|
|
960
|
+
return;
|
|
961
|
+
const view = this.inspectorController.view(this.state.recentToolDetails, inspector);
|
|
962
|
+
const selected = view.selected;
|
|
963
|
+
if (!selected)
|
|
964
|
+
return;
|
|
965
|
+
const expanded = inspector.expandedCallIds.includes(selected.callId);
|
|
966
|
+
if (!append && expanded) {
|
|
967
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, {
|
|
968
|
+
type: 'toggleToolInspectorEntry',
|
|
969
|
+
callId: selected.callId,
|
|
970
|
+
});
|
|
971
|
+
this.paintInspector();
|
|
972
|
+
return;
|
|
973
|
+
}
|
|
974
|
+
if (!expanded) {
|
|
975
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, {
|
|
976
|
+
type: 'toggleToolInspectorEntry',
|
|
977
|
+
callId: selected.callId,
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
this.paintInspector();
|
|
981
|
+
await this.inspectorController.load(selected, append && view.detail?.nextOffsetBytes !== undefined);
|
|
982
|
+
if (this.state.inspector)
|
|
983
|
+
this.paintInspector();
|
|
984
|
+
}
|
|
985
|
+
moveInspectorSelection(delta, wrap = false) {
|
|
986
|
+
const inspector = this.state.inspector;
|
|
987
|
+
if (!inspector || !this.inspectorController)
|
|
988
|
+
return;
|
|
989
|
+
const view = this.inspectorController.view(this.state.recentToolDetails, inspector);
|
|
990
|
+
if (view.entries.length === 0)
|
|
991
|
+
return;
|
|
992
|
+
const target = wrap
|
|
993
|
+
? (view.selectedIndex + delta + view.entries.length) % view.entries.length
|
|
994
|
+
: Math.max(0, Math.min(view.entries.length - 1, view.selectedIndex + delta));
|
|
995
|
+
this.inspectorController.cancel();
|
|
996
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, { type: 'setToolInspectorSelection', index: target });
|
|
997
|
+
this.paintInspector();
|
|
998
|
+
}
|
|
999
|
+
moveInspectorSelectionTo(edge) {
|
|
1000
|
+
const inspector = this.state.inspector;
|
|
1001
|
+
if (!inspector || !this.inspectorController)
|
|
1002
|
+
return;
|
|
1003
|
+
const view = this.inspectorController.view(this.state.recentToolDetails, inspector);
|
|
1004
|
+
if (view.entries.length === 0)
|
|
1005
|
+
return;
|
|
1006
|
+
this.inspectorController.cancel();
|
|
1007
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, {
|
|
1008
|
+
type: 'setToolInspectorSelection',
|
|
1009
|
+
index: edge === 'first' ? 0 : view.entries.length - 1,
|
|
1010
|
+
});
|
|
1011
|
+
this.paintInspector();
|
|
1012
|
+
}
|
|
1013
|
+
exportInspectorResults() {
|
|
1014
|
+
const inspector = this.state.inspector;
|
|
1015
|
+
if (!inspector || !this.inspectorController)
|
|
1016
|
+
return;
|
|
1017
|
+
const entries = this.inspectorController.view(this.state.recentToolDetails, inspector).entries;
|
|
1018
|
+
this.closeToolInspector();
|
|
1019
|
+
this.modalTransition = this.modalTransition
|
|
1020
|
+
.then(async () => {
|
|
1021
|
+
if (!this.surface) {
|
|
1022
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, {
|
|
1023
|
+
type: 'setStatus',
|
|
1024
|
+
message: 'Inspector export requires an inline terminal surface.',
|
|
1025
|
+
});
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
for (const entry of entries) {
|
|
1029
|
+
let pageIndex = 0;
|
|
1030
|
+
for await (const page of this.inspectorController.readPages(entry)) {
|
|
1031
|
+
const heading = pageIndex === 0 ? `#${entry.sequence} ${entry.toolName}\n` : '';
|
|
1032
|
+
const rows = (0, transcript_layout_1.layoutTranscriptEntry)({
|
|
1033
|
+
role: 'tool',
|
|
1034
|
+
content: `${heading}${page.content}`,
|
|
1035
|
+
}, {
|
|
1036
|
+
width: this.transcriptWidth,
|
|
1037
|
+
theme: this.theme,
|
|
1038
|
+
toolOutputMode: 'full',
|
|
1039
|
+
});
|
|
1040
|
+
await this.surface.commit({
|
|
1041
|
+
batchId: `tui-inspector-export-${++this.commitSequence}`,
|
|
1042
|
+
generation: this.state.transcriptGeneration,
|
|
1043
|
+
reason: 'append',
|
|
1044
|
+
entries: [
|
|
1045
|
+
{
|
|
1046
|
+
displayKey: `inspector-export-${entry.callId}-${pageIndex}`,
|
|
1047
|
+
rows,
|
|
1048
|
+
},
|
|
1049
|
+
],
|
|
1050
|
+
}, () => this.buildLiveFrame(this.width));
|
|
1051
|
+
pageIndex += 1;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, {
|
|
1055
|
+
type: 'setStatus',
|
|
1056
|
+
message: `Exported ${entries.length} tool result${entries.length === 1 ? '' : 's'} to scrollback.`,
|
|
1057
|
+
});
|
|
1058
|
+
this.scheduler.request('immediate');
|
|
1059
|
+
})
|
|
1060
|
+
.catch(error => this.handleSurfaceError(error));
|
|
1061
|
+
}
|
|
1062
|
+
openSelectedInspectorDetailInEditor() {
|
|
1063
|
+
const inspector = this.state.inspector;
|
|
1064
|
+
if (!inspector || !this.inspectorController)
|
|
1065
|
+
return;
|
|
1066
|
+
const selected = this.inspectorController.view(this.state.recentToolDetails, inspector).selected;
|
|
1067
|
+
if (!selected)
|
|
1068
|
+
return;
|
|
1069
|
+
if (!this.options.onOpenExternalEditor) {
|
|
1070
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, {
|
|
1071
|
+
type: 'setStatus',
|
|
1072
|
+
message: 'External editor is unavailable in this TUI environment.',
|
|
1073
|
+
});
|
|
1074
|
+
this.paintInspector();
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
1077
|
+
this.closeToolInspector();
|
|
1078
|
+
this.modalTransition = this.modalTransition
|
|
1079
|
+
.then(async () => {
|
|
1080
|
+
const directory = await (0, promises_1.mkdtemp)((0, path_1.join)((0, os_1.tmpdir)(), 'openhorse-tool-'));
|
|
1081
|
+
const filePath = (0, path_1.join)(directory, `${selected.sequence}-${safeFileName(selected.toolName)}.txt`);
|
|
1082
|
+
try {
|
|
1083
|
+
await this.inspectorController.writeDetailToFile(selected, filePath);
|
|
1084
|
+
await this.options.onOpenExternalEditor(filePath);
|
|
1085
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, {
|
|
1086
|
+
type: 'setStatus',
|
|
1087
|
+
message: `Viewed #${selected.sequence} ${selected.toolName} in external editor.`,
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
finally {
|
|
1091
|
+
await (0, promises_1.rm)(directory, { recursive: true, force: true });
|
|
1092
|
+
}
|
|
1093
|
+
this.forceOwnedRedraw();
|
|
1094
|
+
})
|
|
1095
|
+
.catch(error => {
|
|
1096
|
+
this.state = (0, state_1.tuiUiReducer)(this.state, {
|
|
1097
|
+
type: 'setStatus',
|
|
1098
|
+
message: `External editor failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
1099
|
+
});
|
|
1100
|
+
this.forceOwnedRedraw();
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
paintInspector() {
|
|
1104
|
+
if (!this.state.inspector ||
|
|
1105
|
+
!this.inspectorController ||
|
|
1106
|
+
!this.inspectorSurface ||
|
|
1107
|
+
!this.inspectorReady)
|
|
1108
|
+
return;
|
|
1109
|
+
const frame = this.buildInspectorFrame();
|
|
1110
|
+
this.lastFrame = frame;
|
|
1111
|
+
void this.inspectorSurface.paint(frame).catch(error => this.handleSurfaceError(error));
|
|
1112
|
+
}
|
|
1113
|
+
buildInspectorFrame() {
|
|
1114
|
+
const inspector = this.state.inspector;
|
|
1115
|
+
const view = inspector && this.inspectorController
|
|
1116
|
+
? this.inspectorController.view(this.state.recentToolDetails, inspector)
|
|
1117
|
+
: {
|
|
1118
|
+
entries: [],
|
|
1119
|
+
selectedIndex: 0,
|
|
1120
|
+
expandedCallIds: [],
|
|
1121
|
+
searchQuery: '',
|
|
1122
|
+
detailOffset: 0,
|
|
1123
|
+
};
|
|
1124
|
+
return (0, transcript_inspector_layout_1.renderTranscriptInspectorFrame)(view, {
|
|
1125
|
+
width: this.width,
|
|
1126
|
+
height: this.height,
|
|
1127
|
+
theme: this.theme,
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
623
1130
|
}
|
|
624
1131
|
exports.TuiRunner = TuiRunner;
|
|
625
1132
|
function insertAtCursor(value, cursor, text) {
|
|
@@ -629,6 +1136,28 @@ function insertAtCursor(value, cursor, text) {
|
|
|
629
1136
|
cursor: safeCursor + text.length,
|
|
630
1137
|
};
|
|
631
1138
|
}
|
|
1139
|
+
function visibleTuiCommandItems(input) {
|
|
1140
|
+
const query = input.startsWith('/')
|
|
1141
|
+
? input.slice(1).trim().split(/\s+/u, 1)[0].toLowerCase()
|
|
1142
|
+
: '';
|
|
1143
|
+
const local = [
|
|
1144
|
+
{
|
|
1145
|
+
value: 'tool-output',
|
|
1146
|
+
label: '/tool-output',
|
|
1147
|
+
description: 'Set TUI tool output mode',
|
|
1148
|
+
},
|
|
1149
|
+
{
|
|
1150
|
+
value: 'redraw',
|
|
1151
|
+
label: '/redraw',
|
|
1152
|
+
description: 'Redraw the TUI-owned live region',
|
|
1153
|
+
},
|
|
1154
|
+
].filter(item => item.value.includes(query));
|
|
1155
|
+
const localNames = new Set(local.map(item => item.value));
|
|
1156
|
+
return [...local, ...(0, pickers_1.visibleCommandItems)(input).filter(item => !localNames.has(item.value))];
|
|
1157
|
+
}
|
|
1158
|
+
function safeFileName(value) {
|
|
1159
|
+
return value.replace(/[^a-zA-Z0-9._-]+/gu, '-').replace(/^-+|-+$/gu, '') || 'tool';
|
|
1160
|
+
}
|
|
632
1161
|
function deleteBeforeCursor(value, cursor) {
|
|
633
1162
|
const safeCursor = clampCursor(value, cursor);
|
|
634
1163
|
if (safeCursor === 0)
|