@crouton-kit/crouter 0.3.68 → 0.3.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/builtin-memory/00-runtime-base.md +3 -10
- package/dist/builtin-memory/04-base-worker.md +18 -0
- package/dist/builtin-memory/04-orchestration-kernel.md +1 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/README.md +13 -34
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/provider-rotation.test.ts +639 -741
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +241 -58
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +2 -9
- package/dist/builtin-pi-packages/pi-crtr-extensions/lib/subscription-state.ts +365 -94
- package/dist/builtin-pi-packages/pi-crtr-extensions/package-lock.json +2 -2
- package/dist/builtin-pi-packages/pi-mode-switch/README.md +11 -39
- package/dist/builtin-pi-packages/pi-mode-switch/extensions/index.ts +20 -15
- package/dist/builtin-pi-packages/pi-mode-switch/package.json +1 -1
- package/dist/builtin-views/canvas/tui.mjs +8 -9
- package/dist/builtin-views/chat/tui.mjs +12 -12
- package/dist/builtin-views/git-pr/tui.mjs +7 -8
- package/dist/builtin-views/inbox/tui.mjs +27 -41
- package/dist/builtin-views/linkedin/tui.mjs +23 -37
- package/dist/builtin-views/prompt-review/tui.mjs +11 -11
- package/dist/builtin-views/settings/tui.mjs +11 -11
- package/dist/builtin-views/workspace-sidebar/tui.mjs +8 -9
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +1 -0
- package/dist/clients/attach/__tests__/attach-chrome-remote.test.js +11 -7
- package/dist/clients/attach/__tests__/crtr-output-render.test.js +1 -1
- package/dist/clients/attach/__tests__/mermaid-render.test.d.ts +1 -0
- package/dist/clients/attach/__tests__/mermaid-render.test.js +20 -0
- package/dist/clients/attach/__tests__/oauth-dialog-lifecycle.test.d.ts +1 -0
- package/dist/clients/attach/__tests__/oauth-dialog-lifecycle.test.js +110 -0
- package/dist/clients/attach/attach-cmd.d.ts +1 -1
- package/dist/clients/attach/attach-cmd.js +733 -730
- package/dist/clients/attach/auth-pickers.d.ts +12 -0
- package/dist/clients/attach/auth-pickers.js +11 -0
- package/dist/clients/attach/canvas-panels.js +2 -3
- package/dist/clients/attach/chat-view.d.ts +7 -8
- package/dist/clients/attach/chat-view.js +119 -79
- package/dist/clients/attach/edit-diff-render.d.ts +6 -0
- package/dist/clients/attach/edit-diff-render.js +263 -0
- package/dist/clients/attach/input-controller.d.ts +28 -2
- package/dist/clients/attach/input-controller.js +38 -5
- package/dist/clients/attach/mermaid-render.js +5 -2
- package/dist/clients/attach/pickers.d.ts +8 -7
- package/dist/clients/attach/pickers.js +13 -17
- package/dist/clients/attach/slash-commands.d.ts +9 -0
- package/dist/clients/attach/slash-commands.js +128 -7
- package/dist/clients/attach/titled-editor.d.ts +12 -1
- package/dist/clients/attach/titled-editor.js +103 -8
- package/dist/commands/canvas-browse.js +2 -2
- package/dist/commands/memory/lint.js +39 -5
- package/dist/commands/memory/write.js +1 -0
- package/dist/commands/node.js +12 -5
- package/dist/commands/profile/new.js +30 -5
- package/dist/commands/surface-tmux-spread.js +1 -3
- package/dist/commands/sys/__tests__/config-keybindings.test.d.ts +1 -0
- package/dist/commands/sys/__tests__/config-keybindings.test.js +55 -0
- package/dist/commands/sys/__tests__/config-model-ladders.test.d.ts +1 -0
- package/dist/commands/sys/__tests__/config-model-ladders.test.js +121 -0
- package/dist/commands/sys/config.js +18 -21
- package/dist/commands/sys/setup-core.d.ts +12 -1
- package/dist/commands/sys/setup-core.js +25 -3
- package/dist/commands/sys/setup.js +166 -20
- package/dist/core/__tests__/base-worker-prompt.test.d.ts +1 -0
- package/dist/core/__tests__/base-worker-prompt.test.js +24 -0
- package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +232 -1
- package/dist/core/__tests__/fault-classifier.test.js +15 -0
- package/dist/core/__tests__/full/broker-dialogs.test.js +7 -2
- package/dist/core/__tests__/full/broker-pane-resolution.test.js +9 -6
- package/dist/core/__tests__/full/cascade-close.test.js +5 -2
- package/dist/core/__tests__/full/dead-pane-regression.test.js +6 -3
- package/dist/core/__tests__/full/detach-focus.test.js +10 -5
- package/dist/core/__tests__/full/human-new-window-regression.test.js +6 -3
- package/dist/core/__tests__/full/review-render-pane-regression.test.js +2 -2
- package/dist/core/__tests__/helpers/harness.d.ts +1 -0
- package/dist/core/__tests__/helpers/harness.js +28 -4
- package/dist/core/__tests__/host-teardown-process-group.test.js +15 -4
- package/dist/core/__tests__/live-mutation-verbs.test.js +5 -4
- package/dist/core/__tests__/review-model-floor.test.js +1 -1
- package/dist/core/__tests__/stream-watchdog.test.d.ts +1 -0
- package/dist/core/__tests__/stream-watchdog.test.js +70 -0
- package/dist/core/__tests__/tmux-surface.test.js +72 -0
- package/dist/core/canvas/__tests__/remote-event-stream.test.js +11 -9
- package/dist/core/canvas/__tests__/render-remote.test.js +7 -4
- package/dist/core/canvas/browse/__tests__/model.test.js +23 -5
- package/dist/core/canvas/browse/__tests__/rebuild-coalescer.test.js +30 -13
- package/dist/core/canvas/browse/__tests__/render.test.js +1 -0
- package/dist/core/canvas/browse/app.js +164 -5
- package/dist/core/canvas/browse/model.d.ts +10 -6
- package/dist/core/canvas/browse/model.js +20 -12
- package/dist/core/canvas/browse/pins.d.ts +4 -0
- package/dist/core/canvas/browse/pins.js +29 -0
- package/dist/core/canvas/browse/render.d.ts +13 -1
- package/dist/core/canvas/browse/render.js +72 -15
- package/dist/core/canvas/nav-model.js +5 -11
- package/dist/core/canvas/paths.d.ts +5 -0
- package/dist/core/canvas/paths.js +7 -0
- package/dist/core/canvas/pid.d.ts +14 -10
- package/dist/core/canvas/pid.js +14 -10
- package/dist/core/config.d.ts +53 -2
- package/dist/core/config.js +228 -110
- package/dist/core/fault-classifier.js +1 -1
- package/dist/core/fs-utils.d.ts +1 -0
- package/dist/core/fs-utils.js +15 -1
- package/dist/core/keybindings/__tests__/resolve.test.d.ts +1 -0
- package/dist/core/keybindings/__tests__/resolve.test.js +224 -0
- package/dist/core/keybindings/catalog.d.ts +14 -0
- package/dist/core/keybindings/catalog.js +256 -0
- package/dist/core/keybindings/index.d.ts +5 -0
- package/dist/core/keybindings/index.js +4 -0
- package/dist/core/keybindings/match.d.ts +29 -0
- package/dist/core/keybindings/match.js +99 -0
- package/dist/core/keybindings/persistence.d.ts +14 -0
- package/dist/core/keybindings/persistence.js +31 -0
- package/dist/core/keybindings/resolve.d.ts +14 -0
- package/dist/core/keybindings/resolve.js +305 -0
- package/dist/core/keybindings/types.d.ts +37 -0
- package/dist/core/keybindings/types.js +1 -0
- package/dist/core/memory-resolver.d.ts +1 -1
- package/dist/core/memory-resolver.js +10 -3
- package/dist/core/predicate.d.ts +5 -3
- package/dist/core/predicate.js +5 -3
- package/dist/core/runtime/broker-protocol.d.ts +33 -5
- package/dist/core/runtime/broker.js +165 -14
- package/dist/core/runtime/launch.d.ts +39 -6
- package/dist/core/runtime/launch.js +79 -21
- package/dist/core/runtime/naming.js +3 -3
- package/dist/core/runtime/pi-cli.d.ts +6 -0
- package/dist/core/runtime/pi-cli.js +16 -2
- package/dist/core/runtime/placement.d.ts +2 -2
- package/dist/core/runtime/placement.js +4 -1
- package/dist/core/runtime/promote.js +4 -0
- package/dist/core/runtime/recap.d.ts +3 -3
- package/dist/core/runtime/recap.js +47 -44
- package/dist/core/runtime/recycle.js +6 -1
- package/dist/core/runtime/reset.js +5 -0
- package/dist/core/runtime/revive.js +28 -18
- package/dist/core/runtime/session-list-cache.d.ts +23 -0
- package/dist/core/runtime/session-list-cache.js +270 -0
- package/dist/core/runtime/spawn.js +51 -32
- package/dist/core/runtime/stream-watchdog.d.ts +26 -0
- package/dist/core/runtime/stream-watchdog.js +75 -0
- package/dist/core/runtime/tmux-chrome.d.ts +1 -1
- package/dist/core/runtime/tmux-chrome.js +2 -2
- package/dist/core/runtime/tmux.d.ts +18 -15
- package/dist/core/runtime/tmux.js +216 -110
- package/dist/core/tui/__tests__/host-keybindings.test.d.ts +1 -0
- package/dist/core/tui/__tests__/host-keybindings.test.js +112 -0
- package/dist/core/tui/host.d.ts +30 -1
- package/dist/core/tui/host.js +148 -34
- package/dist/core/view/__tests__/transport-remote.test.js +9 -6
- package/dist/core/view/contract.d.ts +17 -3
- package/dist/daemon/crtrd-cli.d.ts +1 -1
- package/dist/daemon/crtrd-cli.js +1 -0
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +41 -0
- package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.d.ts +1 -0
- package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +121 -0
- package/dist/pi-extensions/canvas-inbox-watcher.d.ts +1 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +203 -25
- package/dist/pi-extensions/canvas-recap.d.ts +4 -0
- package/dist/pi-extensions/canvas-recap.js +38 -37
- package/dist/pi-extensions/canvas-stophook.d.ts +11 -0
- package/dist/pi-extensions/canvas-stophook.js +33 -4
- package/dist/suppress-experimental-warnings.d.ts +1 -0
- package/dist/suppress-experimental-warnings.js +15 -0
- package/dist/types.d.ts +3 -13
- package/dist/types.js +12 -36
- package/dist/web-client/assets/{index-CnF5r8ky.js → index--md2ylfi.js} +18 -17
- package/dist/web-client/assets/index-BUdm9s9s.css +2 -0
- package/dist/web-client/index.html +3 -3
- package/dist/web-client/sw.js +1 -1
- package/package.json +11 -8
- package/scripts/postinstall.mjs +1 -1
- package/dist/pi-extensions/canvas-nav.d.ts +0 -43
- package/dist/pi-extensions/canvas-nav.js +0 -640
- package/dist/pi-extensions/widget-order-bus.d.ts +0 -6
- package/dist/pi-extensions/widget-order-bus.js +0 -34
- package/dist/web-client/assets/index-BnmSLNLa.css +0 -2
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import type { TUI } from '@earendil-works/pi-tui';
|
|
2
2
|
import type { Picker, PickerControls } from './pickers.js';
|
|
3
|
+
/** A compact auth summary for a provider — used by non-picker surfaces (e.g.
|
|
4
|
+
* the `crtr sys setup` login tab) to show which providers are already
|
|
5
|
+
* configured without mounting the full selector. */
|
|
6
|
+
export interface ProviderAuthSummary {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
configured: boolean;
|
|
10
|
+
}
|
|
11
|
+
/** Summarize which providers have a stored credential in `agentDir`'s auth.json.
|
|
12
|
+
* Mirrors the OAuth selector's provider list; `configured` is true when the
|
|
13
|
+
* provider has an explicit stored credential (OAuth token or API key). */
|
|
14
|
+
export declare function summarizeProviderAuth(agentDir: string): ProviderAuthSummary[];
|
|
3
15
|
/** `/login` — show the provider selector, then run pi's native login flow in
|
|
4
16
|
* the viewer. On success, notifies the broker to reload auth via reload_auth.
|
|
5
17
|
* Returns a Picker (OAuthSelectorComponent as the overlay). */
|
|
@@ -47,6 +47,17 @@ function buildProviderList(authStorage, registry) {
|
|
|
47
47
|
}
|
|
48
48
|
return providers;
|
|
49
49
|
}
|
|
50
|
+
/** Summarize which providers have a stored credential in `agentDir`'s auth.json.
|
|
51
|
+
* Mirrors the OAuth selector's provider list; `configured` is true when the
|
|
52
|
+
* provider has an explicit stored credential (OAuth token or API key). */
|
|
53
|
+
export function summarizeProviderAuth(agentDir) {
|
|
54
|
+
const { authStorage, registry } = buildLocalAuth(agentDir);
|
|
55
|
+
return buildProviderList(authStorage, registry).map((p) => ({
|
|
56
|
+
id: p.id,
|
|
57
|
+
name: p.name,
|
|
58
|
+
configured: authStorage.get(p.id) !== undefined,
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
50
61
|
/** Open the browser with a URL (best-effort; platform-specific). */
|
|
51
62
|
function openBrowser(url) {
|
|
52
63
|
const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// canvas-panels.ts — the subscribed-node panel for `crtr surface attach` (Unit Q).
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// same canvas read authority. Produces the two line stacks the viewer paints
|
|
3
|
+
// Reads through the CanvasSource seam so the viewer chrome and graph overlay
|
|
4
|
+
// share the same canvas read authority. Produces the two line stacks the viewer paints
|
|
6
5
|
// into Containers around the editor:
|
|
7
6
|
// managers → ABOVE the editor: this node's manager (its first subscriber).
|
|
8
7
|
// reports → BELOW the editor: this node's live reports (active|idle
|
|
@@ -28,9 +28,10 @@ export declare class ChatView {
|
|
|
28
28
|
private readonly tui;
|
|
29
29
|
/** The chat scroll area handed in by the attach command. */
|
|
30
30
|
private readonly container;
|
|
31
|
-
/**
|
|
32
|
-
*
|
|
33
|
-
|
|
31
|
+
/** Settled history is cached independently from the live status area so picker
|
|
32
|
+
* navigation does not re-render a long conversation on every key repeat. */
|
|
33
|
+
private readonly historyContainer;
|
|
34
|
+
/** Activity/status area below history. Holds working/compaction/retry loaders. */
|
|
34
35
|
private readonly statusContainer;
|
|
35
36
|
private readonly cwd;
|
|
36
37
|
private readonly showImages;
|
|
@@ -54,8 +55,6 @@ export declare class ChatView {
|
|
|
54
55
|
private bashComponent;
|
|
55
56
|
/** The single active activity loader (working/compaction/retry), if any. */
|
|
56
57
|
private activityLoader;
|
|
57
|
-
/** While true, `append` skips re-pinning the status container (bulk rebuild). */
|
|
58
|
-
private bulkMode;
|
|
59
58
|
/** Text of the most recent assistant message, kept current from the welcome
|
|
60
59
|
* snapshot AND the live event stream so `/copy` (getLastAssistantText) works
|
|
61
60
|
* whether the message arrived before or after attach. */
|
|
@@ -91,15 +90,15 @@ export declare class ChatView {
|
|
|
91
90
|
private addMessageToChat;
|
|
92
91
|
/** Tool component with native viewer renderers for crouter-owned tool output. */
|
|
93
92
|
private makeToolComponent;
|
|
94
|
-
/** Append
|
|
93
|
+
/** Append conversation content above the independent live status area. */
|
|
95
94
|
private append;
|
|
96
95
|
/** Approximate render width for inline mermaid diagrams. Only affects
|
|
97
96
|
* termrender's trailing padding (stripped in the transform), so the terminal
|
|
98
97
|
* column count is close enough without threading the live pane width here. */
|
|
99
98
|
private renderWidth;
|
|
100
|
-
/** Number of
|
|
99
|
+
/** Number of rendered conversation components. */
|
|
101
100
|
private chatChildCount;
|
|
102
|
-
/** Clear all chat content
|
|
101
|
+
/** Clear all chat content. */
|
|
103
102
|
private resetChat;
|
|
104
103
|
private makeLoader;
|
|
105
104
|
/** Swap the single active activity indicator (working/compaction/retry). */
|
|
@@ -27,6 +27,7 @@ import { CRTR_OUTPUT_CUSTOM_TYPE, CrtrOutputMessageComponent, createCrtrBashTool
|
|
|
27
27
|
import { CRTR_CYCLE_DIVIDER_CUSTOM_TYPE } from '../../core/runtime/session-cycles.js';
|
|
28
28
|
import { SITUATIONAL_CONTEXT_CUSTOM_TYPE } from '../../core/runtime/situational-context.js';
|
|
29
29
|
import { transformMessageMermaid } from './mermaid-render.js';
|
|
30
|
+
import { createCrtrEditToolDefinition } from './edit-diff-render.js';
|
|
30
31
|
/** customType stamped on the injected `<crtr-context>` bearings block (mirrors
|
|
31
32
|
* CONTEXT_INTRO_CUSTOM_TYPE in canvas-context-intro.ts — kept as a local literal
|
|
32
33
|
* so the viewer never imports the in-process extension). */
|
|
@@ -51,13 +52,56 @@ function isExpandable(obj) {
|
|
|
51
52
|
typeof obj.setExpanded === 'function');
|
|
52
53
|
}
|
|
53
54
|
const defaultErrorStyle = (s) => `\x1b[31m${s}\x1b[39m`;
|
|
55
|
+
/** Keep settled conversation history out of picker/editor render hot paths. The
|
|
56
|
+
* root TUI still compares the cached lines, but it no longer re-renders every
|
|
57
|
+
* markdown/tool component for each repeated navigation key. */
|
|
58
|
+
class RenderCacheContainer extends Container {
|
|
59
|
+
cachedWidth;
|
|
60
|
+
cachedLines;
|
|
61
|
+
volatile = false;
|
|
62
|
+
markDirty() {
|
|
63
|
+
this.cachedLines = undefined;
|
|
64
|
+
}
|
|
65
|
+
setVolatile(value) {
|
|
66
|
+
this.volatile = value;
|
|
67
|
+
if (value)
|
|
68
|
+
this.markDirty();
|
|
69
|
+
}
|
|
70
|
+
addChild(component) {
|
|
71
|
+
super.addChild(component);
|
|
72
|
+
this.markDirty();
|
|
73
|
+
}
|
|
74
|
+
removeChild(component) {
|
|
75
|
+
super.removeChild(component);
|
|
76
|
+
this.markDirty();
|
|
77
|
+
}
|
|
78
|
+
clear() {
|
|
79
|
+
super.clear();
|
|
80
|
+
this.markDirty();
|
|
81
|
+
}
|
|
82
|
+
invalidate() {
|
|
83
|
+
super.invalidate();
|
|
84
|
+
this.markDirty();
|
|
85
|
+
}
|
|
86
|
+
render(width) {
|
|
87
|
+
if (!this.volatile && this.cachedLines !== undefined && this.cachedWidth === width)
|
|
88
|
+
return this.cachedLines;
|
|
89
|
+
const lines = super.render(width);
|
|
90
|
+
if (!this.volatile) {
|
|
91
|
+
this.cachedWidth = width;
|
|
92
|
+
this.cachedLines = lines;
|
|
93
|
+
}
|
|
94
|
+
return lines;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
54
97
|
export class ChatView {
|
|
55
98
|
tui;
|
|
56
99
|
/** The chat scroll area handed in by the attach command. */
|
|
57
100
|
container;
|
|
58
|
-
/**
|
|
59
|
-
*
|
|
60
|
-
|
|
101
|
+
/** Settled history is cached independently from the live status area so picker
|
|
102
|
+
* navigation does not re-render a long conversation on every key repeat. */
|
|
103
|
+
historyContainer = new RenderCacheContainer();
|
|
104
|
+
/** Activity/status area below history. Holds working/compaction/retry loaders. */
|
|
61
105
|
statusContainer = new Container();
|
|
62
106
|
cwd;
|
|
63
107
|
showImages;
|
|
@@ -81,8 +125,6 @@ export class ChatView {
|
|
|
81
125
|
bashComponent;
|
|
82
126
|
/** The single active activity loader (working/compaction/retry), if any. */
|
|
83
127
|
activityLoader;
|
|
84
|
-
/** While true, `append` skips re-pinning the status container (bulk rebuild). */
|
|
85
|
-
bulkMode = false;
|
|
86
128
|
/** Text of the most recent assistant message, kept current from the welcome
|
|
87
129
|
* snapshot AND the live event stream so `/copy` (getLastAssistantText) works
|
|
88
130
|
* whether the message arrived before or after attach. */
|
|
@@ -100,6 +142,7 @@ export class ChatView {
|
|
|
100
142
|
this.spinnerStyle = opts.palette?.active ?? defaultSpinnerStyle;
|
|
101
143
|
this.dimStyle = opts.palette?.muted ?? defaultDimStyle;
|
|
102
144
|
this.errorStyle = opts.palette?.error ?? defaultErrorStyle;
|
|
145
|
+
this.container.addChild(this.historyContainer);
|
|
103
146
|
this.container.addChild(this.statusContainer);
|
|
104
147
|
}
|
|
105
148
|
// -------------------------------------------------------------------------
|
|
@@ -115,69 +158,58 @@ export class ChatView {
|
|
|
115
158
|
const renderedPendingTools = new Map();
|
|
116
159
|
const messages = snapshot.messages;
|
|
117
160
|
const lastIndex = messages.length - 1;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
161
|
+
for (let i = 0; i < messages.length; i++) {
|
|
162
|
+
const message = messages[i];
|
|
163
|
+
if (message.role === 'assistant') {
|
|
164
|
+
// Keep the `/copy` source current from the catch-up transcript too, not
|
|
165
|
+
// only the live stream (you usually attach AFTER the last reply landed).
|
|
166
|
+
const text = this.userMessageText(message);
|
|
167
|
+
if (text.trim())
|
|
168
|
+
this.lastAssistantText = text;
|
|
169
|
+
// If the snapshot caught an IN-FLIGHT assistant turn (state.isStreaming
|
|
170
|
+
// and this is the trailing, non-terminal assistant message), bind it as
|
|
171
|
+
// the live streaming component so the relayed message_update/message_end
|
|
172
|
+
// frames that follow `welcome` land on it. Otherwise the in-flight
|
|
173
|
+
// message would freeze at its snapshot value until the next turn — the
|
|
174
|
+
// common case, since you typically attach to a node that is working.
|
|
175
|
+
const isStreamingTail = i === lastIndex &&
|
|
176
|
+
snapshot.state.isStreaming &&
|
|
177
|
+
message.stopReason !== 'aborted' &&
|
|
178
|
+
message.stopReason !== 'error';
|
|
179
|
+
if (isStreamingTail) {
|
|
180
|
+
this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinking, getMarkdownTheme(), this.hiddenThinkingLabel);
|
|
181
|
+
this.append(this.streamingComponent);
|
|
182
|
+
this.streamingComponent.updateContent(message);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
this.addMessageToChat(message);
|
|
186
|
+
}
|
|
187
|
+
for (const content of this.assistantToolCalls(message)) {
|
|
188
|
+
const component = this.makeToolComponent(content.name, content.id, content.arguments);
|
|
189
|
+
this.append(component);
|
|
190
|
+
// (isStreamingTail is never aborted/error, so its tools fall through to
|
|
191
|
+
// renderedPendingTools → pendingTools, where live tool events find them.)
|
|
192
|
+
if (message.stopReason === 'aborted' || message.stopReason === 'error') {
|
|
193
|
+
const errorMessage = message.stopReason === 'aborted'
|
|
194
|
+
? 'Operation aborted'
|
|
195
|
+
: (message.errorMessage ?? 'Error');
|
|
196
|
+
component.updateResult({ content: [{ type: 'text', text: errorMessage }], isError: true });
|
|
146
197
|
}
|
|
147
198
|
else {
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
for (const content of this.assistantToolCalls(message)) {
|
|
151
|
-
const component = this.makeToolComponent(content.name, content.id, content.arguments);
|
|
152
|
-
this.append(component);
|
|
153
|
-
// (isStreamingTail is never aborted/error, so its tools fall through to
|
|
154
|
-
// renderedPendingTools → pendingTools, where live tool events find them.)
|
|
155
|
-
if (message.stopReason === 'aborted' || message.stopReason === 'error') {
|
|
156
|
-
const errorMessage = message.stopReason === 'aborted'
|
|
157
|
-
? 'Operation aborted'
|
|
158
|
-
: (message.errorMessage ?? 'Error');
|
|
159
|
-
component.updateResult({ content: [{ type: 'text', text: errorMessage }], isError: true });
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
renderedPendingTools.set(content.id, component);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
else if (message.role === 'toolResult') {
|
|
167
|
-
const component = renderedPendingTools.get(message.toolCallId);
|
|
168
|
-
if (component) {
|
|
169
|
-
component.updateResult(message);
|
|
170
|
-
renderedPendingTools.delete(message.toolCallId);
|
|
199
|
+
renderedPendingTools.set(content.id, component);
|
|
171
200
|
}
|
|
172
201
|
}
|
|
173
|
-
|
|
174
|
-
|
|
202
|
+
}
|
|
203
|
+
else if (message.role === 'toolResult') {
|
|
204
|
+
const component = renderedPendingTools.get(message.toolCallId);
|
|
205
|
+
if (component) {
|
|
206
|
+
component.updateResult(message);
|
|
207
|
+
renderedPendingTools.delete(message.toolCallId);
|
|
175
208
|
}
|
|
176
209
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
this.container.addChild(this.statusContainer);
|
|
210
|
+
else {
|
|
211
|
+
this.addMessageToChat(message);
|
|
212
|
+
}
|
|
181
213
|
}
|
|
182
214
|
for (const [id, component] of renderedPendingTools) {
|
|
183
215
|
this.pendingTools.set(id, component);
|
|
@@ -185,6 +217,7 @@ export class ChatView {
|
|
|
185
217
|
// If we attached mid-turn, the `agent_start` that spins up the working loader
|
|
186
218
|
// already fired before we connected — restore it from the snapshot's streaming
|
|
187
219
|
// state so an actively-working node shows the spinner right away.
|
|
220
|
+
this.historyContainer.setVolatile(snapshot.state.isStreaming);
|
|
188
221
|
if (snapshot.state.isStreaming)
|
|
189
222
|
this.setActivity(this.makeLoader('Working...'));
|
|
190
223
|
this.tui.requestRender();
|
|
@@ -205,10 +238,11 @@ export class ChatView {
|
|
|
205
238
|
* the caller can surface a notice. */
|
|
206
239
|
toggleToolsExpanded() {
|
|
207
240
|
this.toolOutputExpanded = !this.toolOutputExpanded;
|
|
208
|
-
for (const child of this.
|
|
241
|
+
for (const child of this.historyContainer.children) {
|
|
209
242
|
if (isExpandable(child))
|
|
210
243
|
child.setExpanded(this.toolOutputExpanded);
|
|
211
244
|
}
|
|
245
|
+
this.historyContainer.markDirty();
|
|
212
246
|
this.tui.requestRender();
|
|
213
247
|
return this.toolOutputExpanded;
|
|
214
248
|
}
|
|
@@ -217,10 +251,11 @@ export class ChatView {
|
|
|
217
251
|
* the container, so the loop covers it too). Returns the new HIDDEN state. */
|
|
218
252
|
toggleThinking() {
|
|
219
253
|
this.hideThinking = !this.hideThinking;
|
|
220
|
-
for (const child of this.
|
|
254
|
+
for (const child of this.historyContainer.children) {
|
|
221
255
|
if (child instanceof AssistantMessageComponent)
|
|
222
256
|
child.setHideThinkingBlock(this.hideThinking);
|
|
223
257
|
}
|
|
258
|
+
this.historyContainer.markDirty();
|
|
224
259
|
this.tui.requestRender();
|
|
225
260
|
return this.hideThinking;
|
|
226
261
|
}
|
|
@@ -232,16 +267,18 @@ export class ChatView {
|
|
|
232
267
|
switch (event.type) {
|
|
233
268
|
case 'agent_start': {
|
|
234
269
|
this.pendingTools.clear();
|
|
270
|
+
this.historyContainer.setVolatile(true);
|
|
235
271
|
this.setActivity(this.makeLoader('Working...'));
|
|
236
272
|
break;
|
|
237
273
|
}
|
|
238
274
|
case 'agent_end': {
|
|
239
275
|
// Drop a dangling streaming component (e.g. aborted before message_end).
|
|
240
276
|
if (this.streamingComponent) {
|
|
241
|
-
this.
|
|
277
|
+
this.historyContainer.removeChild(this.streamingComponent);
|
|
242
278
|
this.streamingComponent = undefined;
|
|
243
279
|
}
|
|
244
280
|
this.pendingTools.clear();
|
|
281
|
+
this.historyContainer.setVolatile(false);
|
|
245
282
|
this.setActivity(undefined);
|
|
246
283
|
break;
|
|
247
284
|
}
|
|
@@ -393,6 +430,7 @@ export class ChatView {
|
|
|
393
430
|
default:
|
|
394
431
|
break;
|
|
395
432
|
}
|
|
433
|
+
this.historyContainer.markDirty();
|
|
396
434
|
this.tui.requestRender();
|
|
397
435
|
}
|
|
398
436
|
// -------------------------------------------------------------------------
|
|
@@ -404,16 +442,20 @@ export class ChatView {
|
|
|
404
442
|
bashStart(command, excludeFromContext) {
|
|
405
443
|
const component = new BashExecutionComponent(command, this.tui, excludeFromContext);
|
|
406
444
|
this.bashComponent = component;
|
|
445
|
+
this.historyContainer.setVolatile(true);
|
|
407
446
|
this.append(component);
|
|
408
447
|
this.tui.requestRender();
|
|
409
448
|
}
|
|
410
449
|
bashOutput(chunk) {
|
|
411
450
|
this.bashComponent?.appendOutput(chunk);
|
|
451
|
+
this.historyContainer.markDirty();
|
|
412
452
|
this.tui.requestRender();
|
|
413
453
|
}
|
|
414
454
|
bashEnd(result) {
|
|
415
455
|
this.bashComponent?.setComplete(result.exitCode, result.cancelled, result.truncated ? { truncated: true } : undefined, result.fullOutputPath);
|
|
416
456
|
this.bashComponent = undefined;
|
|
457
|
+
this.historyContainer.setVolatile(false);
|
|
458
|
+
this.historyContainer.markDirty();
|
|
417
459
|
this.tui.requestRender();
|
|
418
460
|
}
|
|
419
461
|
// -------------------------------------------------------------------------
|
|
@@ -524,20 +566,18 @@ export class ChatView {
|
|
|
524
566
|
// -------------------------------------------------------------------------
|
|
525
567
|
/** Tool component with native viewer renderers for crouter-owned tool output. */
|
|
526
568
|
makeToolComponent(name, id, args) {
|
|
527
|
-
const toolDefinition = name === 'bash'
|
|
569
|
+
const toolDefinition = name === 'bash'
|
|
570
|
+
? createCrtrBashToolDefinition(args)
|
|
571
|
+
: name === 'edit'
|
|
572
|
+
? createCrtrEditToolDefinition(this.cwd)
|
|
573
|
+
: undefined;
|
|
528
574
|
const component = new ToolExecutionComponent(name, id, args, { showImages: this.showImages, imageWidthCells: this.imageWidthCells }, toolDefinition, this.tui, this.cwd);
|
|
529
575
|
component.setExpanded(this.toolOutputExpanded);
|
|
530
576
|
return component;
|
|
531
577
|
}
|
|
532
|
-
/** Append
|
|
578
|
+
/** Append conversation content above the independent live status area. */
|
|
533
579
|
append(child) {
|
|
534
|
-
|
|
535
|
-
this.container.addChild(child);
|
|
536
|
-
return;
|
|
537
|
-
}
|
|
538
|
-
this.container.removeChild(this.statusContainer);
|
|
539
|
-
this.container.addChild(child);
|
|
540
|
-
this.container.addChild(this.statusContainer);
|
|
580
|
+
this.historyContainer.addChild(child);
|
|
541
581
|
}
|
|
542
582
|
/** Approximate render width for inline mermaid diagrams. Only affects
|
|
543
583
|
* termrender's trailing padding (stripped in the transform), so the terminal
|
|
@@ -545,18 +585,18 @@ export class ChatView {
|
|
|
545
585
|
renderWidth() {
|
|
546
586
|
return Math.max(40, process.stdout.columns ?? 80);
|
|
547
587
|
}
|
|
548
|
-
/** Number of
|
|
588
|
+
/** Number of rendered conversation components. */
|
|
549
589
|
chatChildCount() {
|
|
550
|
-
return this.
|
|
590
|
+
return this.historyContainer.children.length;
|
|
551
591
|
}
|
|
552
|
-
/** Clear all chat content
|
|
592
|
+
/** Clear all chat content. */
|
|
553
593
|
resetChat() {
|
|
554
594
|
this.setActivity(undefined);
|
|
555
595
|
this.streamingComponent = undefined;
|
|
556
596
|
this.pendingTools.clear();
|
|
557
597
|
this.lastAssistantText = undefined;
|
|
558
|
-
this.
|
|
559
|
-
this.
|
|
598
|
+
this.historyContainer.setVolatile(false);
|
|
599
|
+
this.historyContainer.clear();
|
|
560
600
|
}
|
|
561
601
|
makeLoader(message) {
|
|
562
602
|
return new Loader(this.tui, this.spinnerStyle, this.dimStyle, message);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attach-viewer tool definition for `edit`: pi's builtin definition drives
|
|
3
|
+
* all state (preview computation, header, success/error bg), then the diff
|
|
4
|
+
* body is re-skinned Claude-Code-style after every render pass.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createCrtrEditToolDefinition(cwd: string): unknown;
|