openhorse 0.2.21 → 0.2.23
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 +25 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +189 -49
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/parser.d.ts.map +1 -1
- package/dist/commands/parser.js +8 -3
- package/dist/commands/parser.js.map +1 -1
- package/dist/commands/types.d.ts +2 -0
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/types.js.map +1 -1
- package/dist/core/cost-tracker.d.ts +45 -5
- package/dist/core/cost-tracker.d.ts.map +1 -1
- package/dist/core/cost-tracker.js +78 -13
- package/dist/core/cost-tracker.js.map +1 -1
- package/dist/framework/index.d.ts +1 -1
- package/dist/framework/index.d.ts.map +1 -1
- package/dist/framework/index.js.map +1 -1
- package/dist/framework/query.d.ts +25 -0
- package/dist/framework/query.d.ts.map +1 -1
- package/dist/framework/query.js +196 -49
- package/dist/framework/query.js.map +1 -1
- package/dist/framework/store.d.ts +6 -1
- package/dist/framework/store.d.ts.map +1 -1
- package/dist/framework/store.js +10 -1
- package/dist/framework/store.js.map +1 -1
- 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/ledger.d.ts.map +1 -1
- package/dist/harness/ledger.js +6 -2
- package/dist/harness/ledger.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/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/ink-ui/components/StatusLine.d.ts.map +1 -1
- package/dist/ink-ui/components/StatusLine.js +0 -2
- package/dist/ink-ui/components/StatusLine.js.map +1 -1
- package/dist/ink-ui/screens/ReplScreen.d.ts.map +1 -1
- package/dist/ink-ui/screens/ReplScreen.js +12 -5
- package/dist/ink-ui/screens/ReplScreen.js.map +1 -1
- package/dist/runtime/agent-runtime-controller.d.ts.map +1 -1
- package/dist/runtime/agent-runtime-controller.js +11 -1
- package/dist/runtime/agent-runtime-controller.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 +345 -90
- package/dist/runtime/chat-controller.js.map +1 -1
- package/dist/runtime/rich-text/ansi-parser.d.ts +1 -1
- package/dist/runtime/rich-text/ansi-parser.d.ts.map +1 -1
- package/dist/runtime/rich-text/ansi-parser.js +93 -55
- package/dist/runtime/rich-text/ansi-parser.js.map +1 -1
- package/dist/runtime/rich-text/layout.d.ts +2 -11
- package/dist/runtime/rich-text/layout.d.ts.map +1 -1
- package/dist/runtime/rich-text/layout.js +280 -245
- package/dist/runtime/rich-text/layout.js.map +1 -1
- package/dist/runtime/rich-text/markdown-parser.js +31 -24
- package/dist/runtime/rich-text/markdown-parser.js.map +1 -1
- package/dist/runtime/rich-text/types.d.ts +1 -1
- package/dist/runtime/rich-text/types.d.ts.map +1 -1
- package/dist/runtime/subagents/production.d.ts.map +1 -1
- package/dist/runtime/subagents/production.js +28 -3
- package/dist/runtime/subagents/production.js.map +1 -1
- package/dist/runtime/subagents/result-parser.d.ts.map +1 -1
- package/dist/runtime/subagents/result-parser.js +54 -40
- package/dist/runtime/subagents/result-parser.js.map +1 -1
- package/dist/runtime/subagents/types.d.ts +2 -0
- package/dist/runtime/subagents/types.d.ts.map +1 -1
- package/dist/runtime/subagents/types.js +5 -1
- package/dist/runtime/subagents/types.js.map +1 -1
- 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 +17 -0
- package/dist/runtime/ui-events.d.ts.map +1 -1
- package/dist/runtime/ui-events.js.map +1 -1
- package/dist/runtime/ui-view-model.d.ts +9 -0
- package/dist/runtime/ui-view-model.d.ts.map +1 -1
- package/dist/runtime/ui-view-model.js +59 -37
- package/dist/runtime/ui-view-model.js.map +1 -1
- package/dist/services/compact/auto-compact.d.ts +15 -2
- package/dist/services/compact/auto-compact.d.ts.map +1 -1
- package/dist/services/compact/auto-compact.js +56 -24
- package/dist/services/compact/auto-compact.js.map +1 -1
- package/dist/services/compact/compact.d.ts +2 -0
- package/dist/services/compact/compact.d.ts.map +1 -1
- package/dist/services/compact/compact.js +22 -5
- package/dist/services/compact/compact.js.map +1 -1
- package/dist/services/compact/coordinator.d.ts +26 -0
- package/dist/services/compact/coordinator.d.ts.map +1 -0
- package/dist/services/compact/coordinator.js +44 -0
- package/dist/services/compact/coordinator.js.map +1 -0
- package/dist/services/compact/index.d.ts +1 -0
- package/dist/services/compact/index.d.ts.map +1 -1
- package/dist/services/compact/index.js +3 -1
- package/dist/services/compact/index.js.map +1 -1
- package/dist/services/compact/summary-generator.d.ts +6 -2
- package/dist/services/compact/summary-generator.d.ts.map +1 -1
- package/dist/services/compact/summary-generator.js +73 -31
- package/dist/services/compact/summary-generator.js.map +1 -1
- package/dist/services/config-dir.d.ts +11 -1
- package/dist/services/config-dir.d.ts.map +1 -1
- package/dist/services/config-dir.js +19 -2
- package/dist/services/config-dir.js.map +1 -1
- package/dist/services/config.d.ts +4 -2
- package/dist/services/config.d.ts.map +1 -1
- package/dist/services/config.js +40 -0
- package/dist/services/config.js.map +1 -1
- package/dist/services/doctor.d.ts +2 -0
- package/dist/services/doctor.d.ts.map +1 -1
- package/dist/services/doctor.js +8 -1
- package/dist/services/doctor.js.map +1 -1
- package/dist/services/global-config.d.ts +10 -0
- package/dist/services/global-config.d.ts.map +1 -1
- package/dist/services/global-config.js.map +1 -1
- package/dist/services/llm.d.ts +21 -4
- package/dist/services/llm.d.ts.map +1 -1
- package/dist/services/llm.js +66 -8
- package/dist/services/llm.js.map +1 -1
- package/dist/services/model-context.d.ts +36 -0
- package/dist/services/model-context.d.ts.map +1 -1
- package/dist/services/model-context.js +245 -32
- package/dist/services/model-context.js.map +1 -1
- package/dist/services/redaction.js +1 -1
- package/dist/services/redaction.js.map +1 -1
- package/dist/services/session-storage.d.ts +42 -1
- package/dist/services/session-storage.d.ts.map +1 -1
- package/dist/services/session-storage.js +175 -54
- 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/services/usage-state.d.ts +55 -5
- package/dist/services/usage-state.d.ts.map +1 -1
- package/dist/services/usage-state.js +185 -59
- package/dist/services/usage-state.js.map +1 -1
- package/dist/services/verification-profile.d.ts.map +1 -1
- package/dist/services/verification-profile.js +3 -2
- package/dist/services/verification-profile.js.map +1 -1
- package/dist/services/workspace-diff.d.ts.map +1 -1
- package/dist/services/workspace-diff.js +34 -3
- package/dist/services/workspace-diff.js.map +1 -1
- package/dist/services/yaml-config.js +1 -1
- package/dist/skills/runtime.d.ts +9 -5
- package/dist/skills/runtime.d.ts.map +1 -1
- package/dist/skills/runtime.js +157 -12
- package/dist/skills/runtime.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 +21 -0
- package/dist/terminal-ui/launch.d.ts.map +1 -1
- package/dist/terminal-ui/launch.js +203 -45
- 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 +42 -0
- package/dist/terminal-ui/raw-editor.d.ts.map +1 -1
- package/dist/terminal-ui/raw-editor.js +337 -41
- package/dist/terminal-ui/raw-editor.js.map +1 -1
- package/dist/tools/bash_security.d.ts.map +1 -1
- package/dist/tools/bash_security.js +14 -5
- package/dist/tools/bash_security.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +176 -73
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/plan.d.ts.map +1 -1
- package/dist/tools/plan.js +7 -0
- package/dist/tools/plan.js.map +1 -1
- package/dist/tools/web.d.ts +10 -0
- package/dist/tools/web.d.ts.map +1 -1
- package/dist/tools/web.js +81 -1
- package/dist/tools/web.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 +57 -3
- package/dist/tui-core/input-parser.js.map +1 -1
- package/dist/tui-core/style.d.ts +16 -0
- package/dist/tui-core/style.d.ts.map +1 -1
- package/dist/tui-core/style.js +22 -1
- package/dist/tui-core/style.js.map +1 -1
- package/dist/tui-ui/inline-surface.d.ts +69 -12
- package/dist/tui-ui/inline-surface.d.ts.map +1 -1
- package/dist/tui-ui/inline-surface.js +366 -94
- 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 +2 -0
- package/dist/tui-ui/launch.d.ts.map +1 -1
- package/dist/tui-ui/launch.js +289 -43
- package/dist/tui-ui/launch.js.map +1 -1
- package/dist/tui-ui/layout.d.ts +52 -2
- package/dist/tui-ui/layout.d.ts.map +1 -1
- package/dist/tui-ui/layout.js +230 -76
- package/dist/tui-ui/layout.js.map +1 -1
- package/dist/tui-ui/runner.d.ts +101 -8
- package/dist/tui-ui/runner.d.ts.map +1 -1
- package/dist/tui-ui/runner.js +843 -51
- package/dist/tui-ui/runner.js.map +1 -1
- package/dist/tui-ui/state.d.ts +70 -4
- package/dist/tui-ui/state.d.ts.map +1 -1
- package/dist/tui-ui/state.js +251 -20
- 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/theme.d.ts +13 -0
- package/dist/tui-ui/theme.d.ts.map +1 -0
- package/dist/tui-ui/theme.js +20 -0
- package/dist/tui-ui/theme.js.map +1 -0
- package/dist/tui-ui/transcript-cache.d.ts +5 -3
- package/dist/tui-ui/transcript-cache.d.ts.map +1 -1
- package/dist/tui-ui/transcript-cache.js +16 -9
- package/dist/tui-ui/transcript-cache.js.map +1 -1
- 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 +22 -0
- package/dist/tui-ui/transcript-layout.d.ts.map +1 -0
- package/dist/tui-ui/transcript-layout.js +439 -0
- package/dist/tui-ui/transcript-layout.js.map +1 -0
- package/dist/ui/status-bar.d.ts +1 -1
- package/dist/ui/status-bar.d.ts.map +1 -1
- package/dist/ui/status-bar.js +2 -15
- package/dist/ui/status-bar.js.map +1 -1
- package/dist/ui-v2/components/shell.d.ts.map +1 -1
- package/dist/ui-v2/components/shell.js +0 -8
- package/dist/ui-v2/components/shell.js.map +1 -1
- package/package.json +1 -1
|
@@ -21,6 +21,7 @@ export declare function formatTerminalStatusMessage(message: string, width?: num
|
|
|
21
21
|
export declare function formatTerminalSessionRestored(event: RuntimeSessionRestoredEvent): string;
|
|
22
22
|
export interface TerminalWriter {
|
|
23
23
|
write(text: string): void;
|
|
24
|
+
writeAsync?: (text: string) => Promise<boolean>;
|
|
24
25
|
}
|
|
25
26
|
export declare function visibleLength(text: string): number;
|
|
26
27
|
export declare function terminalContentWidth(fallback?: number): number;
|
|
@@ -36,6 +37,7 @@ export declare class TerminalEventSink implements UiEventSink {
|
|
|
36
37
|
private readonly entries;
|
|
37
38
|
private readonly printedContent;
|
|
38
39
|
private readonly pendingAssistantOutput;
|
|
40
|
+
private readonly finalizedEntryIds;
|
|
39
41
|
private idCounter;
|
|
40
42
|
private pendingPicker;
|
|
41
43
|
private pickerOffset;
|
|
@@ -48,6 +50,9 @@ export declare class TerminalEventSink implements UiEventSink {
|
|
|
48
50
|
* future timeline rendering.
|
|
49
51
|
*/
|
|
50
52
|
private readonly subtaskTimeline;
|
|
53
|
+
private static readonly MAX_FINALIZED_METADATA;
|
|
54
|
+
private static readonly MAX_PRINTED_CONTENT;
|
|
55
|
+
private static readonly MAX_SUBTASK_TIMELINE;
|
|
51
56
|
constructor(runtime: OpenHorseUiRuntime, writer?: TerminalWriter);
|
|
52
57
|
append(entry: TranscriptAppendEntry): string;
|
|
53
58
|
update(id: string, patch: Partial<Omit<TranscriptEntry, 'id'>>): void;
|
|
@@ -66,6 +71,7 @@ export declare class TerminalEventSink implements UiEventSink {
|
|
|
66
71
|
private moveSessionPickerPage;
|
|
67
72
|
private printEntry;
|
|
68
73
|
private printAssistantDelta;
|
|
74
|
+
private writeWithAcknowledgement;
|
|
69
75
|
/**
|
|
70
76
|
* R8: consume the typed subagent event into the shared timeline view-model.
|
|
71
77
|
* Does not print (the chat-controller transcript summary already drives
|
|
@@ -74,8 +80,23 @@ export declare class TerminalEventSink implements UiEventSink {
|
|
|
74
80
|
subtaskEvent(event: RuntimeSubtaskEvent): void;
|
|
75
81
|
/** R8: read-only access to the typed subagent timeline (for parity tests). */
|
|
76
82
|
getSubtaskTimeline(): SubtaskTimelineEntry[];
|
|
83
|
+
/**
|
|
84
|
+
* After finalize, the entry content is in native scrollback.
|
|
85
|
+
* Replace the full body with a lightweight marker so memory doesn't grow
|
|
86
|
+
* with scrollback length.
|
|
87
|
+
*/
|
|
88
|
+
private releaseEntryBody;
|
|
89
|
+
/**
|
|
90
|
+
* Evict oldest entries from a Map when it exceeds the configured limit.
|
|
91
|
+
* Uses Map's insertion-order iteration — oldest entries are evicted first.
|
|
92
|
+
* Mirrors evictOldest in session-storage.ts; kept private to avoid a shared
|
|
93
|
+
* dependency on session-storage internals.
|
|
94
|
+
*/
|
|
95
|
+
private evictIfNeeded;
|
|
77
96
|
}
|
|
78
97
|
export declare function renderTerminalBanner(runtime: OpenHorseUiRuntime): string;
|
|
98
|
+
export declare function renderTerminalContextStatus(runtime: OpenHorseUiRuntime): string;
|
|
99
|
+
export declare function promptText(runtime: OpenHorseUiRuntime): string;
|
|
79
100
|
export declare function formatTerminalPermissionPrompt(request: ToolPermissionRequest, cwd: string): string;
|
|
80
101
|
export declare function parseEditInput(input: string): {
|
|
81
102
|
isEdit: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"launch.d.ts","sourceRoot":"","sources":["../../src/terminal-ui/launch.ts"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"launch.d.ts","sourceRoot":"","sources":["../../src/terminal-ui/launch.ts"],"names":[],"mappings":"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"}
|
|
@@ -18,6 +18,8 @@ exports.formatTerminalSessionPickerHeader = formatTerminalSessionPickerHeader;
|
|
|
18
18
|
exports.formatTerminalEditPreviewHeader = formatTerminalEditPreviewHeader;
|
|
19
19
|
exports.formatTerminalEditPreviewCandidate = formatTerminalEditPreviewCandidate;
|
|
20
20
|
exports.renderTerminalBanner = renderTerminalBanner;
|
|
21
|
+
exports.renderTerminalContextStatus = renderTerminalContextStatus;
|
|
22
|
+
exports.promptText = promptText;
|
|
21
23
|
exports.formatTerminalPermissionPrompt = formatTerminalPermissionPrompt;
|
|
22
24
|
exports.parseEditInput = parseEditInput;
|
|
23
25
|
exports.renderTerminalShortcuts = renderTerminalShortcuts;
|
|
@@ -34,9 +36,11 @@ const redaction_1 = require("../services/redaction");
|
|
|
34
36
|
const completion_1 = require("./completion");
|
|
35
37
|
const editor_1 = require("./editor");
|
|
36
38
|
const raw_editor_1 = require("./raw-editor");
|
|
39
|
+
const output_queue_1 = require("./output-queue");
|
|
37
40
|
const ACCENT = chalk_1.default.hex('#80E6E8');
|
|
38
41
|
const DIM = chalk_1.default.hex('#567089');
|
|
39
42
|
const ERROR = chalk_1.default.hex('#FF7A7A');
|
|
43
|
+
const WARNING = chalk_1.default.hex('#F2C14E');
|
|
40
44
|
const TOOL = chalk_1.default.hex('#7FA2B8');
|
|
41
45
|
const BORDER = chalk_1.default.hex('#38556A');
|
|
42
46
|
function stripTrailingNewlines(text) {
|
|
@@ -109,7 +113,10 @@ function resolveTerminalSessionPickerInput(input, request) {
|
|
|
109
113
|
};
|
|
110
114
|
}
|
|
111
115
|
if (numeric) {
|
|
112
|
-
return {
|
|
116
|
+
return {
|
|
117
|
+
type: 'error',
|
|
118
|
+
message: `No session at index ${numeric[1]} or id prefix "${trimmed}".`,
|
|
119
|
+
};
|
|
113
120
|
}
|
|
114
121
|
return {
|
|
115
122
|
type: 'error',
|
|
@@ -163,9 +170,9 @@ function hasErrorLayerPrefix(message) {
|
|
|
163
170
|
const lower = message.toLowerCase();
|
|
164
171
|
return TERMINAL_ERROR_LAYERS.some(layer => {
|
|
165
172
|
const label = layer.toLowerCase();
|
|
166
|
-
return lower.startsWith(`[${label}] `)
|
|
167
|
-
|
|
168
|
-
|
|
173
|
+
return (lower.startsWith(`[${label}] `) ||
|
|
174
|
+
lower.startsWith(`error [${label}]:`) ||
|
|
175
|
+
lower.startsWith(`error: [${label}] `));
|
|
169
176
|
});
|
|
170
177
|
}
|
|
171
178
|
function inferTerminalErrorLayer(message) {
|
|
@@ -180,16 +187,16 @@ function inferTerminalErrorLayer(message) {
|
|
|
180
187
|
return 'session';
|
|
181
188
|
if (/\b(renderer|terminal|tty|prompt|resize|input editor|scrollback)\b/u.test(lower))
|
|
182
189
|
return 'renderer';
|
|
183
|
-
if (/\btool\b/u.test(lower)
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
190
|
+
if (/\btool\b/u.test(lower) ||
|
|
191
|
+
/\b(exec_command|read_file|write_file|edit_file|grep|glob|list_files)\b/u.test(lower) ||
|
|
192
|
+
/command exited with code/u.test(lower) ||
|
|
193
|
+
/path is a directory|not a file|enoent|eacces/u.test(lower)) {
|
|
187
194
|
return 'tool';
|
|
188
195
|
}
|
|
189
|
-
if (/\b(provider|model|llm|api|quota|rate limit|rate_limit|provider_busy)\b/u.test(lower)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
196
|
+
if (/\b(provider|model|llm|api|quota|rate limit|rate_limit|provider_busy)\b/u.test(lower) ||
|
|
197
|
+
/\b(openai|anthropic|dashscope|bailian|xunfei|glm|qwen)\b/u.test(lower) ||
|
|
198
|
+
/\bstatus code\b/u.test(lower) ||
|
|
199
|
+
/notEnoughCvError|engineInternalError/i.test(message)) {
|
|
193
200
|
return 'provider';
|
|
194
201
|
}
|
|
195
202
|
return 'runtime';
|
|
@@ -217,6 +224,16 @@ function formatTerminalSessionRestored(event) {
|
|
|
217
224
|
if (view.summary) {
|
|
218
225
|
lines.push(fitLine(' Summary: ', (0, redaction_1.redactTraceText)(view.summary)));
|
|
219
226
|
}
|
|
227
|
+
if (view.summaryGeneratedAt) {
|
|
228
|
+
const origin = view.checkpointId ? 'compact checkpoint' : 'generated on resume';
|
|
229
|
+
lines.push(` Generated: ${new Date(view.summaryGeneratedAt).toLocaleString()} (${origin})`);
|
|
230
|
+
}
|
|
231
|
+
if (typeof view.summaryCoveredMessages === 'number') {
|
|
232
|
+
lines.push(` Covers: ${view.summaryCoveredMessages} source messages`);
|
|
233
|
+
}
|
|
234
|
+
if (typeof view.transcriptMessages === 'number') {
|
|
235
|
+
lines.push(`✔ Restored ${view.restoredMessages} model-context messages / ${view.transcriptMessages} transcript messages`);
|
|
236
|
+
}
|
|
220
237
|
return lines.join('\n');
|
|
221
238
|
}
|
|
222
239
|
class DirectTerminalWriter {
|
|
@@ -343,6 +360,7 @@ class TerminalEventSink {
|
|
|
343
360
|
this.entries = new Map();
|
|
344
361
|
this.printedContent = new Map();
|
|
345
362
|
this.pendingAssistantOutput = new Map();
|
|
363
|
+
this.finalizedEntryIds = new Set();
|
|
346
364
|
this.idCounter = 0;
|
|
347
365
|
this.pendingPicker = null;
|
|
348
366
|
this.pickerOffset = 0;
|
|
@@ -358,14 +376,25 @@ class TerminalEventSink {
|
|
|
358
376
|
}
|
|
359
377
|
append(entry) {
|
|
360
378
|
const id = `terminal-${++this.idCounter}`;
|
|
379
|
+
const { live, ...transcriptEntry } = entry;
|
|
361
380
|
const fullEntry = {
|
|
362
381
|
id,
|
|
363
|
-
|
|
364
|
-
title: entry.title,
|
|
365
|
-
content: entry.content,
|
|
382
|
+
...transcriptEntry,
|
|
366
383
|
};
|
|
367
384
|
this.entries.set(id, fullEntry);
|
|
368
|
-
|
|
385
|
+
const finalized = live !== true;
|
|
386
|
+
const write = this.printEntry(fullEntry, finalized);
|
|
387
|
+
if (finalized) {
|
|
388
|
+
if (write instanceof Promise) {
|
|
389
|
+
void write.then(written => {
|
|
390
|
+
if (written)
|
|
391
|
+
this.releaseEntryBody(id);
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
this.releaseEntryBody(id);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
369
398
|
return id;
|
|
370
399
|
}
|
|
371
400
|
update(id, patch) {
|
|
@@ -382,11 +411,22 @@ class TerminalEventSink {
|
|
|
382
411
|
return;
|
|
383
412
|
const next = patch ? { ...existing, ...patch } : existing;
|
|
384
413
|
this.entries.set(id, next);
|
|
385
|
-
this.printEntry(next, true);
|
|
414
|
+
const write = this.printEntry(next, true);
|
|
415
|
+
if (write instanceof Promise) {
|
|
416
|
+
void write.then(written => {
|
|
417
|
+
if (written)
|
|
418
|
+
this.releaseEntryBody(id);
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
this.releaseEntryBody(id);
|
|
423
|
+
}
|
|
386
424
|
}
|
|
387
425
|
remove(id) {
|
|
388
426
|
this.entries.delete(id);
|
|
389
427
|
this.printedContent.delete(id);
|
|
428
|
+
this.pendingAssistantOutput.delete(id);
|
|
429
|
+
this.finalizedEntryIds.delete(id);
|
|
390
430
|
}
|
|
391
431
|
replaceTranscript(entries) {
|
|
392
432
|
this.entries.clear();
|
|
@@ -472,7 +512,12 @@ class TerminalEventSink {
|
|
|
472
512
|
case 'selected':
|
|
473
513
|
this.pendingPicker = null;
|
|
474
514
|
this.pickerOffset = 0;
|
|
475
|
-
return {
|
|
515
|
+
return {
|
|
516
|
+
type: 'select_session',
|
|
517
|
+
sessionId: selection.sessionId,
|
|
518
|
+
allProjects: picker.allProjects,
|
|
519
|
+
source: 'picker',
|
|
520
|
+
};
|
|
476
521
|
case 'error':
|
|
477
522
|
this.writer.write(`${ERROR(selection.message)}\n`);
|
|
478
523
|
return '';
|
|
@@ -525,16 +570,17 @@ class TerminalEventSink {
|
|
|
525
570
|
if (!entry.content)
|
|
526
571
|
return;
|
|
527
572
|
if (entry.role === 'assistant') {
|
|
528
|
-
this.printAssistantDelta(entry, finalized);
|
|
529
|
-
return;
|
|
573
|
+
return this.printAssistantDelta(entry, finalized);
|
|
530
574
|
}
|
|
531
575
|
const previous = this.printedContent.get(entry.id);
|
|
532
576
|
if (previous === entry.content && !finalized)
|
|
533
577
|
return;
|
|
534
578
|
this.printedContent.set(entry.id, entry.content);
|
|
579
|
+
// v0.2.23: bound printed content.
|
|
580
|
+
this.evictIfNeeded(this.printedContent, TerminalEventSink.MAX_PRINTED_CONTENT);
|
|
535
581
|
const formatted = formatTranscriptEntry(entry);
|
|
536
582
|
if (formatted) {
|
|
537
|
-
this.
|
|
583
|
+
return this.writeWithAcknowledgement(`${formatted}\n`);
|
|
538
584
|
}
|
|
539
585
|
}
|
|
540
586
|
printAssistantDelta(entry, finalized) {
|
|
@@ -545,19 +591,26 @@ class TerminalEventSink {
|
|
|
545
591
|
const delta = next.startsWith(previous) ? next.slice(previous.length) : `\n${next}`;
|
|
546
592
|
const pending = `${this.pendingAssistantOutput.get(entry.id) ?? ''}${delta}`;
|
|
547
593
|
this.printedContent.set(entry.id, next);
|
|
594
|
+
// v0.2.23: bound printed content.
|
|
595
|
+
this.evictIfNeeded(this.printedContent, TerminalEventSink.MAX_PRINTED_CONTENT);
|
|
548
596
|
const shouldFlush = finalized || pending.includes('\n') || visibleLength(pending) >= 80;
|
|
549
597
|
if (shouldFlush) {
|
|
550
598
|
this.pendingAssistantOutput.delete(entry.id);
|
|
551
599
|
if (pending) {
|
|
552
|
-
this.
|
|
600
|
+
return this.writeWithAcknowledgement(pending);
|
|
553
601
|
}
|
|
554
602
|
else if (finalized && next && !next.endsWith('\n')) {
|
|
555
|
-
this.
|
|
603
|
+
return this.writeWithAcknowledgement('\n');
|
|
556
604
|
}
|
|
557
605
|
return;
|
|
558
606
|
}
|
|
559
607
|
this.pendingAssistantOutput.set(entry.id, pending);
|
|
560
608
|
}
|
|
609
|
+
writeWithAcknowledgement(text) {
|
|
610
|
+
if (this.writer.writeAsync)
|
|
611
|
+
return this.writer.writeAsync(text);
|
|
612
|
+
this.writer.write(text);
|
|
613
|
+
}
|
|
561
614
|
/**
|
|
562
615
|
* R8: consume the typed subagent event into the shared timeline view-model.
|
|
563
616
|
* Does not print (the chat-controller transcript summary already drives
|
|
@@ -565,13 +618,61 @@ class TerminalEventSink {
|
|
|
565
618
|
*/
|
|
566
619
|
subtaskEvent(event) {
|
|
567
620
|
this.subtaskTimeline.set(event.taskId, (0, ui_view_model_1.subtaskEventToTimelineEntry)(event));
|
|
621
|
+
// v0.2.23: bound subtask timeline.
|
|
622
|
+
this.evictIfNeeded(this.subtaskTimeline, TerminalEventSink.MAX_SUBTASK_TIMELINE);
|
|
568
623
|
}
|
|
569
624
|
/** R8: read-only access to the typed subagent timeline (for parity tests). */
|
|
570
625
|
getSubtaskTimeline() {
|
|
571
626
|
return Array.from(this.subtaskTimeline.values());
|
|
572
627
|
}
|
|
628
|
+
// --- v0.2.23: bounded state helpers ---
|
|
629
|
+
/**
|
|
630
|
+
* After finalize, the entry content is in native scrollback.
|
|
631
|
+
* Replace the full body with a lightweight marker so memory doesn't grow
|
|
632
|
+
* with scrollback length.
|
|
633
|
+
*/
|
|
634
|
+
releaseEntryBody(id) {
|
|
635
|
+
const entry = this.entries.get(id);
|
|
636
|
+
if (!entry)
|
|
637
|
+
return;
|
|
638
|
+
// Keep role/id/title but replace heavy content with a marker.
|
|
639
|
+
this.entries.set(id, {
|
|
640
|
+
...entry,
|
|
641
|
+
content: `[scrollback:${entry.role} posted ${entry.content.length} chars]`,
|
|
642
|
+
});
|
|
643
|
+
this.printedContent.delete(id);
|
|
644
|
+
this.pendingAssistantOutput.delete(id);
|
|
645
|
+
this.finalizedEntryIds.delete(id);
|
|
646
|
+
this.finalizedEntryIds.add(id);
|
|
647
|
+
while (this.finalizedEntryIds.size > TerminalEventSink.MAX_FINALIZED_METADATA) {
|
|
648
|
+
const oldest = this.finalizedEntryIds.values().next().value;
|
|
649
|
+
if (!oldest)
|
|
650
|
+
break;
|
|
651
|
+
this.finalizedEntryIds.delete(oldest);
|
|
652
|
+
this.entries.delete(oldest);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Evict oldest entries from a Map when it exceeds the configured limit.
|
|
657
|
+
* Uses Map's insertion-order iteration — oldest entries are evicted first.
|
|
658
|
+
* Mirrors evictOldest in session-storage.ts; kept private to avoid a shared
|
|
659
|
+
* dependency on session-storage internals.
|
|
660
|
+
*/
|
|
661
|
+
evictIfNeeded(map, limit) {
|
|
662
|
+
while (map.size > limit) {
|
|
663
|
+
const firstKey = map.keys().next().value;
|
|
664
|
+
if (firstKey !== undefined)
|
|
665
|
+
map.delete(firstKey);
|
|
666
|
+
else
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
573
670
|
}
|
|
574
671
|
exports.TerminalEventSink = TerminalEventSink;
|
|
672
|
+
// --- v0.2.23: bounded state configuration ---
|
|
673
|
+
TerminalEventSink.MAX_FINALIZED_METADATA = 512;
|
|
674
|
+
TerminalEventSink.MAX_PRINTED_CONTENT = 512;
|
|
675
|
+
TerminalEventSink.MAX_SUBTASK_TIMELINE = 100;
|
|
575
676
|
function renderTerminalBanner(runtime) {
|
|
576
677
|
const width = Math.max(2, terminalContentWidth(88));
|
|
577
678
|
const line = '─'.repeat(Math.max(0, width - 2));
|
|
@@ -599,9 +700,17 @@ function renderTerminalBanner(runtime) {
|
|
|
599
700
|
function printBanner(runtime) {
|
|
600
701
|
process.stdout.write(renderTerminalBanner(runtime));
|
|
601
702
|
}
|
|
703
|
+
function renderTerminalContextStatus(runtime) {
|
|
704
|
+
const usage = runtime.store.getSnapshot().contextUsage;
|
|
705
|
+
const status = (0, ui_view_model_1.contextUsageStatusText)(usage);
|
|
706
|
+
if (!status)
|
|
707
|
+
return '';
|
|
708
|
+
return usage && usage.percent >= usage.warningThresholdPercent ? WARNING(status) : DIM(status);
|
|
709
|
+
}
|
|
602
710
|
function promptText(runtime) {
|
|
603
711
|
const session = runtime.getSession()?.id.slice(0, 8) ?? 'new';
|
|
604
|
-
|
|
712
|
+
const context = renderTerminalContextStatus(runtime);
|
|
713
|
+
return `${DIM(`[${session}]`)}${context ? ` ${context}` : ''} ${ACCENT('›')} `;
|
|
605
714
|
}
|
|
606
715
|
function compactPermissionValue(value, maxWidth) {
|
|
607
716
|
const singleLine = (0, redaction_1.redactTraceText)(value).replace(/\s+/g, ' ').trim();
|
|
@@ -666,6 +775,7 @@ function renderTerminalShortcuts() {
|
|
|
666
775
|
`${ACCENT('Shortcuts')}`,
|
|
667
776
|
`${BORDER('─'.repeat(Math.min(width, 32)))}`,
|
|
668
777
|
`${DIM('Enter')} send ${DIM('Tab')} complete`,
|
|
778
|
+
`${DIM('Ctrl+J')} newline`,
|
|
669
779
|
`${DIM('Ctrl+C')} interrupt; twice exits`,
|
|
670
780
|
`${DIM('/paste')} ${DIM('/edit')} ${DIM('/resume')}`,
|
|
671
781
|
`${DIM('/last-tool')} ${DIM('/trace')}`,
|
|
@@ -677,6 +787,7 @@ function renderTerminalShortcuts() {
|
|
|
677
787
|
`${ACCENT('Shortcuts')}`,
|
|
678
788
|
`${BORDER('─'.repeat(Math.min(width, 40)))}`,
|
|
679
789
|
`${DIM('Enter')} send ${DIM('Tab')} complete ${DIM('↑/↓')} history`,
|
|
790
|
+
`${DIM('Alt+Enter/Ctrl+J')} newline`,
|
|
680
791
|
`${DIM('Ctrl+U/W')} edit ${DIM('Ctrl+C')} interrupt; twice exits`,
|
|
681
792
|
`${DIM('/paste')} multiline ${DIM('/edit')} editor ${DIM('/resume')} sessions`,
|
|
682
793
|
`${DIM('/last-tool')} tool detail ${DIM('/trace')} timeline`,
|
|
@@ -687,6 +798,7 @@ function renderTerminalShortcuts() {
|
|
|
687
798
|
`${ACCENT('Terminal shortcuts')}`,
|
|
688
799
|
`${BORDER('─'.repeat(48))}`,
|
|
689
800
|
`${DIM('Enter')} send current input`,
|
|
801
|
+
`${DIM('Alt+Enter')} insert newline (${DIM('Ctrl+J')} also works)`,
|
|
690
802
|
`${DIM('Tab')} complete slash command or @file mention`,
|
|
691
803
|
`${DIM('↑/↓')} navigate local input history`,
|
|
692
804
|
`${DIM('Ctrl+U')} clear current input`,
|
|
@@ -720,7 +832,9 @@ class TerminalInputComposer {
|
|
|
720
832
|
if (!this.mode && ['/paste', '/multi', '/multiline'].includes(trimmed)) {
|
|
721
833
|
this.mode = 'paste';
|
|
722
834
|
this.lines.length = 0;
|
|
723
|
-
return {
|
|
835
|
+
return {
|
|
836
|
+
notice: DIM('Multiline input: paste or type lines, finish with /end, cancel with /cancel.'),
|
|
837
|
+
};
|
|
724
838
|
}
|
|
725
839
|
if (this.mode === 'paste') {
|
|
726
840
|
if (trimmed === '/cancel') {
|
|
@@ -730,7 +844,9 @@ class TerminalInputComposer {
|
|
|
730
844
|
if (trimmed === '/end') {
|
|
731
845
|
const submitted = this.lines.join('\n').trimEnd();
|
|
732
846
|
this.reset();
|
|
733
|
-
return submitted
|
|
847
|
+
return submitted
|
|
848
|
+
? { input: submitted }
|
|
849
|
+
: { cancelled: true, notice: DIM('Multiline input was empty.') };
|
|
734
850
|
}
|
|
735
851
|
this.lines.push(input);
|
|
736
852
|
return {};
|
|
@@ -797,12 +913,36 @@ function normalizeTerminalAnswer(input) {
|
|
|
797
913
|
}
|
|
798
914
|
async function launchTerminalUI(runtime) {
|
|
799
915
|
printBanner(runtime);
|
|
800
|
-
let
|
|
801
|
-
|
|
802
|
-
|
|
916
|
+
let agentController;
|
|
917
|
+
let writer;
|
|
918
|
+
const editor = new raw_editor_1.RawTerminalEditor({
|
|
919
|
+
cwd: runtime.cwd,
|
|
920
|
+
onSubmit: input => handleInput(input),
|
|
921
|
+
onCtrlC: () => handleSigint(),
|
|
922
|
+
onNotice: message => { void writer.write(`${DIM(message)}\n`); },
|
|
923
|
+
});
|
|
924
|
+
const outputAdapter = {
|
|
925
|
+
write: text => editor.writeExternalBatch([text]),
|
|
926
|
+
on: (event, listener) => { process.stdout.on(event, listener); },
|
|
927
|
+
off: (event, listener) => { process.stdout.off(event, listener); },
|
|
928
|
+
};
|
|
929
|
+
const outputQueue = new output_queue_1.TerminalOutputQueue(outputAdapter);
|
|
930
|
+
let outputBatchSequence = 0;
|
|
931
|
+
writer = {
|
|
932
|
+
write: text => {
|
|
933
|
+
void outputQueue.enqueue({
|
|
934
|
+
id: `terminal-output-${++outputBatchSequence}`,
|
|
935
|
+
chunks: [text],
|
|
936
|
+
releaseEntryIds: [],
|
|
937
|
+
}).catch(() => undefined);
|
|
938
|
+
},
|
|
939
|
+
writeAsync: text => outputQueue.enqueue({
|
|
940
|
+
id: `terminal-output-${++outputBatchSequence}`,
|
|
941
|
+
chunks: [text],
|
|
942
|
+
releaseEntryIds: [],
|
|
943
|
+
}).then(() => true, () => false),
|
|
803
944
|
};
|
|
804
945
|
const events = new TerminalEventSink(runtime, writer);
|
|
805
|
-
let agentController;
|
|
806
946
|
let stopping = false;
|
|
807
947
|
let settled = false;
|
|
808
948
|
let resolveLaunch = null;
|
|
@@ -823,21 +963,25 @@ async function launchTerminalUI(runtime) {
|
|
|
823
963
|
return undefined;
|
|
824
964
|
}
|
|
825
965
|
confirmingTool = true;
|
|
826
|
-
void editor
|
|
966
|
+
void editor
|
|
967
|
+
.ask(formatTerminalPermissionPrompt(event.request, runtime.cwd), event.request.abortSignal)
|
|
968
|
+
.then(answer => {
|
|
827
969
|
agentController.handle({
|
|
828
970
|
type: 'permission_decision',
|
|
829
971
|
requestId: event.request.id,
|
|
830
972
|
approved: /^y(es)?$/i.test(answer.trim()),
|
|
831
973
|
source: 'keyboard',
|
|
832
974
|
});
|
|
833
|
-
})
|
|
975
|
+
})
|
|
976
|
+
.catch(() => {
|
|
834
977
|
agentController.handle({
|
|
835
978
|
type: 'permission_decision',
|
|
836
979
|
requestId: event.request.id,
|
|
837
980
|
approved: false,
|
|
838
981
|
source: 'programmatic',
|
|
839
982
|
});
|
|
840
|
-
})
|
|
983
|
+
})
|
|
984
|
+
.finally(() => {
|
|
841
985
|
confirmingTool = false;
|
|
842
986
|
prompt();
|
|
843
987
|
});
|
|
@@ -861,12 +1005,6 @@ async function launchTerminalUI(runtime) {
|
|
|
861
1005
|
events.append({ role: 'error', content: message });
|
|
862
1006
|
},
|
|
863
1007
|
});
|
|
864
|
-
editor = new raw_editor_1.RawTerminalEditor({
|
|
865
|
-
cwd: runtime.cwd,
|
|
866
|
-
onSubmit: input => handleInput(input),
|
|
867
|
-
onCtrlC: () => handleSigint(),
|
|
868
|
-
onNotice: message => writer.write(`${DIM(message)}\n`),
|
|
869
|
-
});
|
|
870
1008
|
const prompt = () => {
|
|
871
1009
|
if (stopping)
|
|
872
1010
|
return;
|
|
@@ -883,8 +1021,16 @@ async function launchTerminalUI(runtime) {
|
|
|
883
1021
|
return;
|
|
884
1022
|
stopping = true;
|
|
885
1023
|
await agentController.stopActiveTurn();
|
|
886
|
-
|
|
887
|
-
|
|
1024
|
+
try {
|
|
1025
|
+
await outputQueue.close();
|
|
1026
|
+
}
|
|
1027
|
+
catch {
|
|
1028
|
+
// Terminal output failure must not block shutdown.
|
|
1029
|
+
}
|
|
1030
|
+
finally {
|
|
1031
|
+
editor.stop();
|
|
1032
|
+
await runtime.shutdown();
|
|
1033
|
+
}
|
|
888
1034
|
process.stdout.write('\n');
|
|
889
1035
|
finishLaunch();
|
|
890
1036
|
};
|
|
@@ -937,7 +1083,11 @@ async function launchTerminalUI(runtime) {
|
|
|
937
1083
|
if (!stopping)
|
|
938
1084
|
editor.start();
|
|
939
1085
|
if (result.error) {
|
|
940
|
-
events.append({
|
|
1086
|
+
events.append({
|
|
1087
|
+
role: 'error',
|
|
1088
|
+
content: `Editor failed: ${result.error}`,
|
|
1089
|
+
errorLayer: 'renderer',
|
|
1090
|
+
});
|
|
941
1091
|
prompt();
|
|
942
1092
|
return;
|
|
943
1093
|
}
|
|
@@ -981,7 +1131,7 @@ async function launchTerminalUI(runtime) {
|
|
|
981
1131
|
prompt();
|
|
982
1132
|
};
|
|
983
1133
|
try {
|
|
984
|
-
process.stdout.write(`${DIM('Ready.
|
|
1134
|
+
process.stdout.write(`${DIM('Ready. Terminal editor supports CJK, Alt/Option+Enter or Ctrl+J newlines, multiline paste, and live revision. /edit is available for oversized drafts.')}\n`);
|
|
985
1135
|
editor.start();
|
|
986
1136
|
prompt();
|
|
987
1137
|
await new Promise(resolve => {
|
|
@@ -991,8 +1141,16 @@ async function launchTerminalUI(runtime) {
|
|
|
991
1141
|
finally {
|
|
992
1142
|
if (!stopping) {
|
|
993
1143
|
stopping = true;
|
|
994
|
-
|
|
995
|
-
|
|
1144
|
+
try {
|
|
1145
|
+
await outputQueue.close();
|
|
1146
|
+
}
|
|
1147
|
+
catch {
|
|
1148
|
+
// Terminal output failure must not block shutdown.
|
|
1149
|
+
}
|
|
1150
|
+
finally {
|
|
1151
|
+
editor.stop();
|
|
1152
|
+
await runtime.shutdown();
|
|
1153
|
+
}
|
|
996
1154
|
process.stdout.write('\n');
|
|
997
1155
|
}
|
|
998
1156
|
}
|