@crouton-kit/crouter 0.3.61 → 0.3.62
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/builtin-views/canvas/core.mjs +2 -1
- package/dist/clients/attach/__tests__/context-message.test.d.ts +1 -0
- package/dist/clients/attach/__tests__/context-message.test.js +46 -0
- package/dist/clients/attach/__tests__/transport-relay.test.d.ts +1 -0
- package/dist/clients/attach/__tests__/transport-relay.test.js +176 -0
- package/dist/clients/attach/attach-cmd.js +747 -743
- package/dist/clients/attach/canvas-panels.d.ts +4 -4
- package/dist/clients/attach/canvas-panels.js +108 -37
- package/dist/clients/attach/chat-view.js +11 -0
- package/dist/clients/attach/context-message.d.ts +3 -1
- package/dist/clients/attach/context-message.js +30 -21
- package/dist/clients/attach/graph-overlay.d.ts +8 -1
- package/dist/clients/attach/graph-overlay.js +201 -22
- package/dist/clients/attach/transport-relay.d.ts +51 -0
- package/dist/clients/attach/transport-relay.js +196 -0
- package/dist/clients/attach/transport-socket.d.ts +29 -0
- package/dist/clients/attach/transport-socket.js +164 -0
- package/dist/clients/attach/transport.d.ts +32 -0
- package/dist/clients/attach/transport.js +26 -0
- package/dist/clients/attach/view-socket.d.ts +40 -44
- package/dist/clients/attach/view-socket.js +94 -197
- package/dist/commands/memory/delete.js +3 -3
- package/dist/commands/memory/origin.js +1 -1
- package/dist/commands/memory/read.js +3 -3
- package/dist/commands/memory/shared.d.ts +8 -6
- package/dist/commands/memory/shared.js +23 -9
- package/dist/commands/memory/write.js +3 -3
- package/dist/commands/node-worktree.js +9 -9
- package/dist/commands/node.js +71 -23
- package/dist/commands/sys/doctor.js +1 -0
- package/dist/core/__tests__/broker-fork-seam.test.js +17 -2
- package/dist/core/__tests__/broker-snapshot-history.test.js +12 -2
- package/dist/core/__tests__/canvas-inbox-watcher.test.js +79 -0
- package/dist/core/__tests__/context-intro.test.js +11 -0
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +9 -4
- package/dist/core/__tests__/fixtures/fake-engine.js +12 -4
- package/dist/core/__tests__/kickoff.test.js +21 -0
- package/dist/core/__tests__/spawn-root.test.js +60 -0
- package/dist/core/__tests__/worktree.test.js +24 -1
- package/dist/core/canvas/browse/app.d.ts +2 -0
- package/dist/core/canvas/browse/app.js +83 -48
- package/dist/core/canvas/db.js +3 -2
- package/dist/core/canvas/index.d.ts +1 -0
- package/dist/core/canvas/index.js +1 -0
- package/dist/core/canvas/nav-model.d.ts +5 -3
- package/dist/core/canvas/nav-model.js +7 -6
- package/dist/core/canvas/paths.d.ts +8 -0
- package/dist/core/canvas/paths.js +10 -0
- package/dist/core/canvas/render.d.ts +6 -0
- package/dist/core/canvas/render.js +117 -20
- package/dist/core/canvas/source.d.ts +26 -0
- package/dist/core/canvas/source.js +29 -0
- package/dist/core/canvas/status-glyph.js +1 -0
- package/dist/core/canvas/types.d.ts +4 -3
- package/dist/core/config.d.ts +18 -2
- package/dist/core/config.js +88 -10
- package/dist/core/fault-classifier.d.ts +2 -2
- package/dist/core/memory-resolver.d.ts +9 -6
- package/dist/core/memory-resolver.js +28 -4
- package/dist/core/profiles/__tests__/root-profile.test.d.ts +1 -0
- package/dist/core/profiles/__tests__/root-profile.test.js +69 -0
- package/dist/core/profiles/manifest.d.ts +2 -0
- package/dist/core/profiles/manifest.js +40 -7
- package/dist/core/profiles/select.d.ts +4 -4
- package/dist/core/profiles/select.js +13 -13
- package/dist/core/runtime/__tests__/spawn-env.test.d.ts +1 -0
- package/dist/core/runtime/__tests__/spawn-env.test.js +268 -0
- package/dist/core/runtime/bearings.d.ts +5 -4
- package/dist/core/runtime/bearings.js +12 -6
- package/dist/core/runtime/broker.js +59 -7
- package/dist/core/runtime/fault-recovery.js +4 -0
- package/dist/core/runtime/front-door.js +1 -1
- package/dist/core/runtime/host.js +43 -3
- package/dist/core/runtime/kickoff.js +6 -0
- package/dist/core/runtime/launch.d.ts +6 -1
- package/dist/core/runtime/launch.js +7 -1
- package/dist/core/runtime/nodes.d.ts +7 -6
- package/dist/core/runtime/nodes.js +3 -3
- package/dist/core/runtime/situational-context.d.ts +12 -0
- package/dist/core/runtime/situational-context.js +48 -0
- package/dist/core/runtime/spawn-env.d.ts +27 -0
- package/dist/core/runtime/spawn-env.js +169 -0
- package/dist/core/runtime/spawn.d.ts +16 -7
- package/dist/core/runtime/spawn.js +8 -2
- package/dist/core/substrate/session-cache.js +7 -1
- package/dist/core/substrate/subject.d.ts +1 -1
- package/dist/core/view/remote-canvas-target.d.ts +3 -0
- package/dist/core/view/remote-canvas-target.js +25 -0
- package/dist/core/worktree.d.ts +4 -4
- package/dist/core/worktree.js +41 -19
- package/dist/daemon/crtrd.js +32 -0
- package/dist/daemon/predicate-eval.js +12 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -0
- package/dist/pi-extensions/canvas-bash-valve.d.ts +2 -0
- package/dist/pi-extensions/canvas-bash-valve.js +238 -0
- package/dist/pi-extensions/canvas-inbox-watcher.d.ts +12 -0
- package/dist/pi-extensions/canvas-inbox-watcher.js +41 -5
- package/dist/types.d.ts +32 -0
- package/dist/types.js +7 -0
- package/dist/web-client/assets/index-BnmSLNLa.css +2 -0
- package/dist/web-client/assets/{index-BQufdMhB.js → index-BvzxXXGU.js} +18 -18
- package/dist/web-client/index.html +2 -2
- package/dist/web-client/sw.js +1 -1
- package/docs/public-api.md +5 -3
- package/package.json +2 -2
- package/dist/web-client/assets/fraunces-latin-ext-wght-normal-Ca2vKHc0.woff2 +0 -0
- package/dist/web-client/assets/fraunces-latin-wght-normal-ukD16Tqj.woff2 +0 -0
- package/dist/web-client/assets/fraunces-vietnamese-wght-normal-CnvboYUG.woff2 +0 -0
- package/dist/web-client/assets/index-FjfN-jvN.css +0 -2
- package/dist/web-client/assets/instrument-sans-latin-ext-wght-normal-B5bTHO_g.woff2 +0 -0
- package/dist/web-client/assets/instrument-sans-latin-wght-normal-BbzFLZTg.woff2 +0 -0
- package/dist/web-client/workbox-98f7a950.js +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type CanvasSource } from '../../core/canvas/source.js';
|
|
1
2
|
import type { AttachPalette } from './config-load.js';
|
|
2
3
|
export interface CanvasPanelLines {
|
|
3
4
|
/** Above-editor manager line(s) — empty for a root node (no manager). */
|
|
@@ -5,8 +6,7 @@ export interface CanvasPanelLines {
|
|
|
5
6
|
/** Below-editor report row(s) + self's trailing ⚑ asks line — empty when none. */
|
|
6
7
|
reports: string[];
|
|
7
8
|
}
|
|
8
|
-
/** Build the BASE panel line stacks for `nodeId`
|
|
9
|
-
*
|
|
10
|
-
* caller polls; pass `{}` to omit the ⚑ badges. `palette` (the live theme)
|
|
9
|
+
/** Build the BASE panel line stacks for `nodeId`. `asks` is the per-node
|
|
10
|
+
* pending-ask map the caller polls; pass `{}` to omit the ⚑ badges. `palette`
|
|
11
11
|
* drives the headers + dim cells; omit it and the panels render uncolored. */
|
|
12
|
-
export declare function buildCanvasPanelLines(nodeId: string, asks: Record<string, number>, palette?: AttachPalette): CanvasPanelLines
|
|
12
|
+
export declare function buildCanvasPanelLines(nodeId: string, asks: Record<string, number>, palette?: AttachPalette, source?: CanvasSource): Promise<CanvasPanelLines>;
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
// canvas-panels.ts — the subscribed-node panel for `crtr surface attach` (Unit Q).
|
|
2
2
|
//
|
|
3
|
-
// Native
|
|
4
|
-
// the
|
|
5
|
-
//
|
|
6
|
-
//
|
|
3
|
+
// Native implementation of canvas-nav.ts's BASE chrome (renderBase), reading
|
|
4
|
+
// through the CanvasSource seam so the viewer chrome and graph overlay share the
|
|
5
|
+
// same canvas read authority. Produces the two line stacks the viewer paints
|
|
6
|
+
// into Containers around the editor:
|
|
7
7
|
// managers → ABOVE the editor: this node's manager (its first subscriber).
|
|
8
8
|
// reports → BELOW the editor: this node's live reports (active|idle
|
|
9
9
|
// subscriptions), plus a trailing ⚑ line for self's own asks.
|
|
10
10
|
//
|
|
11
11
|
// Pure: given a node id + the per-node ask map it returns ANSI strings; the
|
|
12
|
-
// caller owns the Containers and the refresh trigger. beginFrame()
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
import { beginFrame,
|
|
12
|
+
// caller owns the Containers and the refresh trigger. beginFrame() clears the
|
|
13
|
+
// nav-model telemetry cache for this one build pass so token/activity cells are
|
|
14
|
+
// read fresh for every chrome frame.
|
|
15
|
+
import { beginFrame, navLabel, nodeGlyph, truncate, tokensCell, cycleBadge, askBadge, activityCell, YELLOW, RESET, DIM, GREEN, } from '../../core/canvas/nav-model.js';
|
|
16
|
+
import { localCanvasSource } from '../../core/canvas/source.js';
|
|
16
17
|
/** Column widths for the aligned panel rows (visible columns). name is sized to
|
|
17
18
|
* the widest label across BOTH panels (capped); kind is wide enough for the
|
|
18
19
|
* longest persona kind (`orchestrator` = 12) so real kinds never truncate;
|
|
@@ -28,49 +29,119 @@ function nameCell(s, w) {
|
|
|
28
29
|
function padStartVisible(s, w) {
|
|
29
30
|
return s.length >= w ? s.slice(0, w) : ' '.repeat(w - s.length) + s;
|
|
30
31
|
}
|
|
31
|
-
/** Build the BASE panel line stacks for `nodeId`
|
|
32
|
-
*
|
|
33
|
-
* caller polls; pass `{}` to omit the ⚑ badges. `palette` (the live theme)
|
|
32
|
+
/** Build the BASE panel line stacks for `nodeId`. `asks` is the per-node
|
|
33
|
+
* pending-ask map the caller polls; pass `{}` to omit the ⚑ badges. `palette`
|
|
34
34
|
* drives the headers + dim cells; omit it and the panels render uncolored. */
|
|
35
|
-
export function buildCanvasPanelLines(nodeId, asks, palette) {
|
|
36
|
-
// Fresh snapshot: drop the previous build's memoized reads so this pass sees
|
|
37
|
-
// current disk+db state, then read-once within it.
|
|
35
|
+
export async function buildCanvasPanelLines(nodeId, asks, palette, source = localCanvasSource) {
|
|
38
36
|
beginFrame();
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
const nodes = new Map();
|
|
38
|
+
const children = new Map();
|
|
39
|
+
const managersOf = new Map();
|
|
40
|
+
const node = (id) => {
|
|
41
|
+
const hit = nodes.get(id);
|
|
42
|
+
if (hit !== undefined)
|
|
43
|
+
return hit;
|
|
44
|
+
const p = source.getNode(id).catch(() => null);
|
|
45
|
+
nodes.set(id, p);
|
|
46
|
+
return p;
|
|
47
|
+
};
|
|
48
|
+
const convoChildIds = (id) => {
|
|
49
|
+
const hit = children.get(id);
|
|
50
|
+
if (hit !== undefined)
|
|
51
|
+
return hit;
|
|
52
|
+
const p = (async () => {
|
|
53
|
+
const refs = await source.subscriptionsOf(id).catch(() => []);
|
|
54
|
+
const out = [];
|
|
55
|
+
for (const ref of refs) {
|
|
56
|
+
if ((await node(ref.node_id))?.kind !== 'human')
|
|
57
|
+
out.push(ref.node_id);
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
})();
|
|
61
|
+
children.set(id, p);
|
|
62
|
+
return p;
|
|
63
|
+
};
|
|
64
|
+
const managerOf = (id) => {
|
|
65
|
+
const hit = managersOf.get(id);
|
|
66
|
+
if (hit !== undefined)
|
|
67
|
+
return hit;
|
|
68
|
+
const p = source.subscribersOf(id).then((refs) => refs[0]?.node_id).catch(() => undefined);
|
|
69
|
+
managersOf.set(id, p);
|
|
70
|
+
return p;
|
|
71
|
+
};
|
|
72
|
+
const liveReports = async (id) => {
|
|
73
|
+
const out = [];
|
|
74
|
+
for (const cid of await convoChildIds(id)) {
|
|
75
|
+
const st = (await node(cid))?.status;
|
|
76
|
+
if (st === 'active' || st === 'idle')
|
|
77
|
+
out.push(cid);
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
};
|
|
81
|
+
const climbRoot = async (self) => {
|
|
82
|
+
let cur = self;
|
|
83
|
+
const seen = new Set([cur]);
|
|
84
|
+
for (;;) {
|
|
85
|
+
const mgr = await managerOf(cur);
|
|
86
|
+
if (mgr === undefined || seen.has(mgr))
|
|
87
|
+
break;
|
|
88
|
+
seen.add(mgr);
|
|
89
|
+
cur = mgr;
|
|
90
|
+
}
|
|
91
|
+
return cur;
|
|
92
|
+
};
|
|
93
|
+
const activeBelow = new Map();
|
|
94
|
+
const computeActivity = async (root) => {
|
|
95
|
+
const seen = new Set();
|
|
96
|
+
const visit = async (id) => {
|
|
97
|
+
const selfActive = (await node(id))?.status === 'active';
|
|
98
|
+
if (seen.has(id))
|
|
99
|
+
return selfActive ? 1 : 0;
|
|
100
|
+
seen.add(id);
|
|
101
|
+
let below = 0;
|
|
102
|
+
for (const c of await convoChildIds(id))
|
|
103
|
+
below += await visit(c);
|
|
104
|
+
activeBelow.set(id, below);
|
|
105
|
+
return below + (selfActive ? 1 : 0);
|
|
106
|
+
};
|
|
107
|
+
await visit(root);
|
|
108
|
+
};
|
|
109
|
+
const childBadgeFor = async (n) => {
|
|
110
|
+
if (n === null || n.mode !== 'orchestrator')
|
|
111
|
+
return '';
|
|
112
|
+
const m = (await convoChildIds(n.node_id)).length;
|
|
113
|
+
return m > 0 ? ` ${DIM}⤳${m}${RESET}` : '';
|
|
114
|
+
};
|
|
115
|
+
const liveBelowBadgeFor = (n) => {
|
|
116
|
+
if (n === null || n.status === 'active')
|
|
117
|
+
return '';
|
|
118
|
+
const count = activeBelow.get(n.node_id) ?? 0;
|
|
119
|
+
return count > 0 ? ` ${GREEN}⇣${count}${RESET}` : '';
|
|
120
|
+
};
|
|
41
121
|
const muted = palette?.muted ?? ((s) => s);
|
|
42
122
|
const faint = palette?.faint ?? ((s) => s);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
// One shared name-column width across BOTH panels so the grids line up.
|
|
47
|
-
const mgr = managerOf(nodeId);
|
|
48
|
-
const live = liveReports(nodeId);
|
|
123
|
+
await computeActivity(await climbRoot(nodeId));
|
|
124
|
+
const mgr = await managerOf(nodeId);
|
|
125
|
+
const live = await liveReports(nodeId);
|
|
49
126
|
const gridIds = [...(mgr !== undefined ? [mgr] : []), ...live];
|
|
127
|
+
const gridNodes = await Promise.all(gridIds.map((id) => node(id)));
|
|
50
128
|
const nameW = gridIds.length > 0
|
|
51
|
-
? Math.min(NAME_CAP, Math.max(...gridIds.map((id) => navLabel(
|
|
129
|
+
? Math.min(NAME_CAP, Math.max(...gridIds.map((id, i) => navLabel(gridNodes[i] ?? null, id).length)))
|
|
52
130
|
: NAME_CAP;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const n = cNode(id);
|
|
131
|
+
const row = async (id) => {
|
|
132
|
+
const n = await node(id);
|
|
56
133
|
const name = nameCell(navLabel(n, id), nameW);
|
|
57
134
|
const kind = faint(nameCell(n?.kind ?? '', KIND_W));
|
|
58
135
|
const tokens = muted(padStartVisible(tokensCell(id), TOK_W));
|
|
59
|
-
const badges = `${cycleBadge(n)}${
|
|
136
|
+
const badges = `${cycleBadge(n)}${await childBadgeFor(n)}${liveBelowBadgeFor(n)}${askBadge(id, asks)}${activityCell(id, n)}`;
|
|
60
137
|
return truncate(` ${nodeGlyph(n)} ${name} ${kind} ${tokens}${badges}`);
|
|
61
138
|
};
|
|
62
|
-
// --- managers panel (↑) ---
|
|
63
139
|
const managers = [];
|
|
64
|
-
if (mgr !== undefined)
|
|
65
|
-
managers.push(row(mgr));
|
|
66
|
-
}
|
|
67
|
-
// --- reports panel (↓) ---
|
|
140
|
+
if (mgr !== undefined)
|
|
141
|
+
managers.push(await row(mgr));
|
|
68
142
|
const reports = [];
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
reports.push(row(id));
|
|
72
|
-
}
|
|
73
|
-
// Self's own pending asks (no self row in BASE) → a trailing inline line.
|
|
143
|
+
for (const id of live)
|
|
144
|
+
reports.push(await row(id));
|
|
74
145
|
const selfAsks = asks[nodeId] ?? 0;
|
|
75
146
|
if (selfAsks > 0)
|
|
76
147
|
reports.push(` ${YELLOW}⚑ ${selfAsks} pending${RESET}`);
|
|
@@ -25,6 +25,7 @@ import { AssistantMessageComponent, BashExecutionComponent, BranchSummaryMessage
|
|
|
25
25
|
import { ContextMessageComponent } from './context-message.js';
|
|
26
26
|
import { CRTR_OUTPUT_CUSTOM_TYPE, CrtrOutputMessageComponent, createCrtrBashToolDefinition, } from './crtr-output-render.js';
|
|
27
27
|
import { CRTR_CYCLE_DIVIDER_CUSTOM_TYPE } from '../../core/runtime/session-cycles.js';
|
|
28
|
+
import { SITUATIONAL_CONTEXT_CUSTOM_TYPE } from '../../core/runtime/situational-context.js';
|
|
28
29
|
import { transformMessageMermaid } from './mermaid-render.js';
|
|
29
30
|
/** customType stamped on the injected `<crtr-context>` bearings block (mirrors
|
|
30
31
|
* CONTEXT_INTRO_CUSTOM_TYPE in canvas-context-intro.ts — kept as a local literal
|
|
@@ -444,6 +445,16 @@ export class ChatView {
|
|
|
444
445
|
(s) => this.spinnerStyle(this.labelStyle(s))));
|
|
445
446
|
break;
|
|
446
447
|
}
|
|
448
|
+
// The hidden ambient `<situational-context>` update (canvas-inbox-watcher's
|
|
449
|
+
// ~non-birth wake path). Rendered collapsed exactly like `crtr-context`
|
|
450
|
+
// (same component, distinct label) so an existing-node ambient update is
|
|
451
|
+
// never more prominent in the transcript than the bearings block it rides
|
|
452
|
+
// alongside on fresh birth — the LLM sees the full content either way; only
|
|
453
|
+
// the viewer's display treatment differs.
|
|
454
|
+
if (message.customType === SITUATIONAL_CONTEXT_CUSTOM_TYPE) {
|
|
455
|
+
this.append(new ContextMessageComponent(this.userMessageText(message), this.toolOutputExpanded, this.dimStyle, (s) => this.spinnerStyle(this.labelStyle(s)), 'situational context', ' ambient context update — ctrl+o to expand'));
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
447
458
|
if (message.customType === CRTR_OUTPUT_CUSTOM_TYPE) {
|
|
448
459
|
this.append(new CrtrOutputMessageComponent(this.userMessageText(message), this.toolOutputExpanded, this.crtrOutputTheme()));
|
|
449
460
|
break;
|
|
@@ -3,8 +3,10 @@ export declare class ContextMessageComponent implements Component {
|
|
|
3
3
|
private readonly body;
|
|
4
4
|
private readonly dim;
|
|
5
5
|
private readonly label;
|
|
6
|
+
private readonly labelText;
|
|
7
|
+
private readonly collapsedHint;
|
|
6
8
|
private expanded;
|
|
7
|
-
constructor(body: string, expanded: boolean, dim: (s: string) => string, label: (s: string) => string);
|
|
9
|
+
constructor(body: string, expanded: boolean, dim: (s: string) => string, label: (s: string) => string, labelText?: string, collapsedHint?: string);
|
|
8
10
|
/** Ctrl+O global tool-output toggle (ChatView.isExpandable duck-type). */
|
|
9
11
|
setExpanded(expanded: boolean): void;
|
|
10
12
|
render(width: number): string[];
|
|
@@ -1,15 +1,20 @@
|
|
|
1
|
-
// context-message.ts — the viewer's foldable renderer for
|
|
2
|
-
// bearings block (
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
1
|
+
// context-message.ts — the viewer's foldable renderer for hidden-context custom
|
|
2
|
+
// messages: the `<crtr-context>` bearings block (customType `crtr-context`) and
|
|
3
|
+
// the ambient `<situational-context>` update (customType
|
|
4
|
+
// `crtr-situational-context`). Both are broker-injected (canvas-context-intro,
|
|
5
|
+
// canvas-inbox-watcher), so the VIEWER has no message renderer for either and
|
|
6
|
+
// would otherwise show the full block always. This reimplements the bearings
|
|
7
|
+
// renderer natively (src/pi-extensions/canvas-context-intro.ts:
|
|
8
|
+
// `renderContextMessage`) and reuses the same collapsed/expand shape for
|
|
9
|
+
// situational context so both render consistently: collapsed → one dim line;
|
|
10
|
+
// expanded (Ctrl+O) → label + full wrapped body. It implements `setExpanded`,
|
|
11
|
+
// so the Ctrl+O tool-output toggle (ChatView.toggleToolsExpanded →
|
|
12
|
+
// isExpandable) folds it alongside tool output.
|
|
10
13
|
import { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';
|
|
11
|
-
/**
|
|
14
|
+
/** Default label/hint for the `crtr-context` bearings block. Mirrors the
|
|
15
|
+
* extension's customType stamp. */
|
|
12
16
|
const LABEL = 'crtr context';
|
|
17
|
+
const COLLAPSED_HINT = ' orienting bearings — ctrl+o to expand';
|
|
13
18
|
/** Char-based wrap that never emits an over-width line (pi-tui hard-crashes on
|
|
14
19
|
* one). Visible-width aware so wide glyphs in the bearings tree count right. */
|
|
15
20
|
function wrapLine(line, width) {
|
|
@@ -34,11 +39,15 @@ export class ContextMessageComponent {
|
|
|
34
39
|
body;
|
|
35
40
|
dim;
|
|
36
41
|
label;
|
|
42
|
+
labelText;
|
|
43
|
+
collapsedHint;
|
|
37
44
|
expanded;
|
|
38
|
-
constructor(body, expanded, dim, label) {
|
|
45
|
+
constructor(body, expanded, dim, label, labelText = LABEL, collapsedHint = COLLAPSED_HINT) {
|
|
39
46
|
this.body = body;
|
|
40
47
|
this.dim = dim;
|
|
41
48
|
this.label = label;
|
|
49
|
+
this.labelText = labelText;
|
|
50
|
+
this.collapsedHint = collapsedHint;
|
|
42
51
|
this.expanded = expanded;
|
|
43
52
|
}
|
|
44
53
|
/** Ctrl+O global tool-output toggle (ChatView.isExpandable duck-type). */
|
|
@@ -48,18 +57,18 @@ export class ContextMessageComponent {
|
|
|
48
57
|
render(width) {
|
|
49
58
|
const w = width > 0 ? width : 80;
|
|
50
59
|
if (!this.expanded) {
|
|
51
|
-
// Paint the [
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
const
|
|
56
|
-
const rest =
|
|
57
|
-
const labelW = visibleWidth(
|
|
60
|
+
// Paint the [label] tag in the accent color and the rest dim, so the label
|
|
61
|
+
// reads distinctly in BOTH states. Truncate BEFORE painting so the ANSI
|
|
62
|
+
// wrappers never inflate the measured width (an over-wide line aborts the
|
|
63
|
+
// whole TUI render).
|
|
64
|
+
const labelTag = `[${this.labelText}]`;
|
|
65
|
+
const rest = this.collapsedHint;
|
|
66
|
+
const labelW = visibleWidth(labelTag);
|
|
58
67
|
if (labelW >= w)
|
|
59
|
-
return [this.label(truncateToWidth(
|
|
60
|
-
return [this.label(
|
|
68
|
+
return [this.label(truncateToWidth(labelTag, w, '…'))];
|
|
69
|
+
return [this.label(labelTag) + this.dim(truncateToWidth(rest, w - labelW, '…'))];
|
|
61
70
|
}
|
|
62
|
-
const lines = [this.label(truncateToWidth(`[${
|
|
71
|
+
const lines = [this.label(truncateToWidth(`[${this.labelText}]`, w, '…')), ''];
|
|
63
72
|
for (const raw of this.body.split('\n')) {
|
|
64
73
|
for (const seg of wrapLine(raw, w))
|
|
65
74
|
lines.push(seg);
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { type Component, type TUI } from '@earendil-works/pi-tui';
|
|
2
|
+
import { type CanvasSource } from '../../core/canvas/source.js';
|
|
2
3
|
import type { AttachPalette } from './config-load.js';
|
|
3
4
|
export declare class GraphOverlay implements Component {
|
|
4
5
|
private readonly tui;
|
|
5
6
|
private readonly self;
|
|
6
7
|
private readonly getAsks;
|
|
7
8
|
private readonly palette;
|
|
9
|
+
private readonly source;
|
|
8
10
|
private handle;
|
|
9
11
|
/** Manual fold OVERRIDES (h collapses → userCollapsed, l expands → userExpanded);
|
|
10
12
|
* both override the default activity-driven policy and survive open/close. */
|
|
@@ -17,7 +19,9 @@ export declare class GraphOverlay implements Component {
|
|
|
17
19
|
private scrollTop;
|
|
18
20
|
/** Transient y/n confirm gate (kill). */
|
|
19
21
|
private pendingConfirm;
|
|
20
|
-
|
|
22
|
+
private snapshot;
|
|
23
|
+
private snapshotSeq;
|
|
24
|
+
constructor(tui: TUI, self: string, getAsks: () => Record<string, number>, palette: AttachPalette, source?: CanvasSource);
|
|
21
25
|
isOpen(): boolean;
|
|
22
26
|
open(): void;
|
|
23
27
|
close(): void;
|
|
@@ -25,6 +29,8 @@ export declare class GraphOverlay implements Component {
|
|
|
25
29
|
/** Repaint if shown (the low-rate ask poll calls this). */
|
|
26
30
|
refresh(): void;
|
|
27
31
|
invalidate(): void;
|
|
32
|
+
private buildSnapshot;
|
|
33
|
+
private renderSnapshotRow;
|
|
28
34
|
render(width: number): string[];
|
|
29
35
|
/** A top/bottom border row: `<lc>─ <label> ────<rc>`, frame in the theme border
|
|
30
36
|
* color, the label keeping its own styling. The label is visible-truncated to
|
|
@@ -38,6 +44,7 @@ export declare class GraphOverlay implements Component {
|
|
|
38
44
|
* `id` has no viewer yet a fresh one splits beside this pane; if it already has
|
|
39
45
|
* one, that viewer is navigated in place (this pane is left as-is). We pass
|
|
40
46
|
* TMUX_PANE explicitly so the anchor is THIS pane even if env resolution differs. */
|
|
47
|
+
private logAsyncFailure;
|
|
41
48
|
private focusTarget;
|
|
42
49
|
private shellCrtr;
|
|
43
50
|
}
|