@crouton-kit/crouter 0.3.70 → 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 +622 -724
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +231 -68
- 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 +361 -90
- 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/clients/attach/__tests__/attach-chrome-remote.test.js +3 -3
- 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 +738 -735
- 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 +11 -17
- package/dist/clients/attach/slash-commands.d.ts +9 -0
- package/dist/clients/attach/slash-commands.js +127 -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 +9 -2
- 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 +23 -3
- package/dist/commands/sys/setup.js +42 -12
- 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__/host-teardown-process-group.test.js +15 -4
- 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/browse/__tests__/model.test.js +23 -5
- 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/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 +163 -14
- package/dist/core/runtime/launch.d.ts +39 -6
- package/dist/core/runtime/launch.js +78 -20
- 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/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/contract.d.ts +17 -3
- 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/types.d.ts +3 -13
- package/dist/types.js +2 -26
- package/dist/web-client/assets/{index-DiFuLcp6.js → index--md2ylfi.js} +1 -1
- package/dist/web-client/index.html +1 -1
- package/dist/web-client/sw.js +1 -1
- package/package.json +3 -3
- 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
|
@@ -6,7 +6,7 @@ export declare const PROMPT_LINES = 3;
|
|
|
6
6
|
export declare const REPLY_LINES = 3;
|
|
7
7
|
export declare const PREVIEW_BODY: number;
|
|
8
8
|
export declare const PREVIEW_HEIGHT: number;
|
|
9
|
-
export declare function headerHeight(
|
|
9
|
+
export declare function headerHeight(inputLine: boolean): number;
|
|
10
10
|
export interface RenderState {
|
|
11
11
|
tree: Tree;
|
|
12
12
|
visible: VisibleRow[];
|
|
@@ -25,6 +25,18 @@ export interface RenderState {
|
|
|
25
25
|
/** Lifecycle filter: when true, `terminal` (one-shot worker) nodes are hidden
|
|
26
26
|
* — surfaced as a status-line cue. */
|
|
27
27
|
residentsOnly: boolean;
|
|
28
|
+
/** User-starred node ids — drives the ★ row marker + the Pinned tab. */
|
|
29
|
+
pinned: Set<string>;
|
|
30
|
+
/** Inline rename input: when true, the header shows a rename prompt bound to
|
|
31
|
+
* `renameBuf` and the footer becomes commit/cancel. */
|
|
32
|
+
rename?: boolean;
|
|
33
|
+
renameBuf?: string;
|
|
34
|
+
/** Inline message input: when true, the header shows a message prompt bound to
|
|
35
|
+
* `messageBuf` (delivered via `crtr node msg`). */
|
|
36
|
+
message?: boolean;
|
|
37
|
+
messageBuf?: string;
|
|
38
|
+
/** When true, the whole body is replaced by the keybinding help overlay. */
|
|
39
|
+
help?: boolean;
|
|
28
40
|
/** When set, a close-out (`x`) is awaiting y/n confirmation because the node (or
|
|
29
41
|
* a descendant) is actively streaming. Holds the node id being confirmed; the
|
|
30
42
|
* footer becomes the y/n prompt. null/undefined = no pending confirm. */
|
|
@@ -26,9 +26,11 @@ export const PROMPT_LINES = 3;
|
|
|
26
26
|
export const REPLY_LINES = 3;
|
|
27
27
|
export const PREVIEW_BODY = PROMPT_LINES + REPLY_LINES;
|
|
28
28
|
export const PREVIEW_HEIGHT = PREVIEW_BODY + 2;
|
|
29
|
-
// header = title + tab bar + status line + column header + separator (+
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
// header = title + tab bar + status line + column header + separator (+ input line)
|
|
30
|
+
// `inputLine` is true whenever a text-input mode is open (search / rename / message)
|
|
31
|
+
// — each adds one prompt row above the column header.
|
|
32
|
+
export function headerHeight(inputLine) {
|
|
33
|
+
return 5 + (inputLine ? 1 : 0);
|
|
32
34
|
}
|
|
33
35
|
// ── Row table layout ──────────────────────────────────────────────────────────
|
|
34
36
|
// A row is three zones: a fixed-width STATUS rail (glyph + word) on the left, the
|
|
@@ -57,6 +59,7 @@ const FG_CYAN = '36';
|
|
|
57
59
|
const FG_GRAY = '90'; // bright-black
|
|
58
60
|
const FG_BRIGHT_YELLOW = '93';
|
|
59
61
|
const FG_BRIGHT_CYAN = '96'; // query-match highlight (ties to the cyan search accent)
|
|
62
|
+
const FG_MAGENTA = '35'; // pin star (distinct from the yellow ⚑ asks flag)
|
|
60
63
|
// STATUS_GLYPH + STATUS_COLOR are imported from ../status-glyph.js (the shared
|
|
61
64
|
// canvas-graph map). STATUS_COLOR there is NUMERIC SGR (e.g. 32) — wrap with
|
|
62
65
|
// `sgr()` where a string ANSI code is needed (Span fg / template literals accept
|
|
@@ -232,7 +235,7 @@ function assembleRow(left, right, width, color, lineBase, fill) {
|
|
|
232
235
|
}
|
|
233
236
|
/** One table row: `<status rail> <indent><collapse> <name> <flags>` ........ `<meta>`.
|
|
234
237
|
* `showCwd` adds the project column (All-dirs view); `now` drives the age. */
|
|
235
|
-
function rowLine(row, tree, width, isCursor, query, caps, showCwd, now) {
|
|
238
|
+
function rowLine(row, tree, width, isCursor, query, caps, showCwd, now, isPinned) {
|
|
236
239
|
const node = tree.nodes.get(row.id);
|
|
237
240
|
if (node === undefined)
|
|
238
241
|
return '';
|
|
@@ -254,12 +257,15 @@ function rowLine(row, tree, width, isCursor, query, caps, showCwd, now) {
|
|
|
254
257
|
// label live in the rail). Dim yellow so it reads as secondary detail.
|
|
255
258
|
if (r.hanging != null)
|
|
256
259
|
flags.push({ text: ` · ${faultSummary(r.hanging, now)}`, style: { fg: FG_YELLOW, dim: true } });
|
|
260
|
+
// Pin marker travels just before the name so a starred node is scannable in any
|
|
261
|
+
// tab/sort. Magenta keeps it distinct from the yellow ⚑ asks flag.
|
|
262
|
+
const pinMark = isPinned ? [{ text: '★ ', style: { fg: FG_MAGENTA, bold: true } }] : [];
|
|
257
263
|
const status = statusRail(r);
|
|
258
264
|
const right = metaCluster(r, now, showCwd);
|
|
259
265
|
const treeLead = `${indent}${collapse} `;
|
|
260
|
-
// Clip the NAME (only) so gutter + status + tree + name + flags + meta all
|
|
261
|
-
// the cluster is dropped first (assembleRow) when even a 4-col name won't fit
|
|
262
|
-
const fixed = spansWidth([gutter]) + spansWidth(status) + [...treeLead].length + spansWidth(flags);
|
|
266
|
+
// Clip the NAME (only) so gutter + status + tree + pin + name + flags + meta all
|
|
267
|
+
// fit; the cluster is dropped first (assembleRow) when even a 4-col name won't fit.
|
|
268
|
+
const fixed = spansWidth([gutter]) + spansWidth(status) + [...treeLead].length + spansWidth(pinMark) + spansWidth(flags);
|
|
263
269
|
const rightW = spansWidth(right);
|
|
264
270
|
const nameMax = Math.max(4, width - fixed - rightW - 1);
|
|
265
271
|
const nameStyle = { dim: !isCursor && terminal, bold: isCursor }; // dim terminal names; bold the cursor row
|
|
@@ -267,6 +273,7 @@ function rowLine(row, tree, width, isCursor, query, caps, showCwd, now) {
|
|
|
267
273
|
gutter,
|
|
268
274
|
...status,
|
|
269
275
|
{ text: treeLead, style: { dim: true } },
|
|
276
|
+
...pinMark,
|
|
270
277
|
...nameSpans(clip(r.name, nameMax), query, nameStyle),
|
|
271
278
|
...flags,
|
|
272
279
|
];
|
|
@@ -403,16 +410,63 @@ function previewPanel(r, width, caps, now, query) {
|
|
|
403
410
|
}
|
|
404
411
|
return out;
|
|
405
412
|
}
|
|
413
|
+
/** The keybinding help overlay — a full-screen cheatsheet that replaces the body
|
|
414
|
+
* while `?` is held open. Grouped by intent so the whole key surface is legible in
|
|
415
|
+
* one glance (the footer only ever advertises the common few). */
|
|
416
|
+
const HELP_ROWS = [
|
|
417
|
+
['Move', '↑/↓ j/k', 'up / down'],
|
|
418
|
+
['', 'g / G', 'top / bottom'],
|
|
419
|
+
['', '.', 'jump to this node (recenter)'],
|
|
420
|
+
['Tree', '→/← h/l', 'expand / collapse'],
|
|
421
|
+
['', 'space', 'toggle fold'],
|
|
422
|
+
['Tabs', 'Tab / 1-5', 'All · Live · Dormant · Attention · Pinned'],
|
|
423
|
+
['Find', '/', 'fuzzy search (name · kind · id · prompts)'],
|
|
424
|
+
['Pin', 'f', 'star / unstar — floats to top, Pinned tab'],
|
|
425
|
+
['Open', '⏎', 'resume the node'],
|
|
426
|
+
['Act', 'm', 'message the node (no resume)'],
|
|
427
|
+
['', 'R', 'rename the node'],
|
|
428
|
+
['', 'x', 'close-out node + subtree'],
|
|
429
|
+
['', 'K', 'revive now (a hanging node)'],
|
|
430
|
+
['View', 's', 'cycle sort (attention/tree/relevance/recency)'],
|
|
431
|
+
['', 'c', 'toggle cwd scope'],
|
|
432
|
+
['', 'r', 'toggle residents-only'],
|
|
433
|
+
['', 'p', 'toggle preview panel'],
|
|
434
|
+
['Quit', 'q / Esc', ''],
|
|
435
|
+
];
|
|
436
|
+
function renderHelp(size, caps) {
|
|
437
|
+
const cols = Math.max(20, size.cols);
|
|
438
|
+
const rows = Math.max(8, size.rows);
|
|
439
|
+
const width = cols - 1;
|
|
440
|
+
const lines = [];
|
|
441
|
+
lines.push(`${BOLD}Canvas navigator — keys${RESET}`);
|
|
442
|
+
lines.push('');
|
|
443
|
+
const dim = (s) => `${DIM}${s}${RESET}`;
|
|
444
|
+
for (const [group, keys, desc] of HELP_ROWS) {
|
|
445
|
+
const g = group.padEnd(6);
|
|
446
|
+
const k = keys.padEnd(12);
|
|
447
|
+
const line = ` ${dim(g)}${BOLD}${k}${RESET}${desc === '' ? '' : ` ${dim(desc)}`}`;
|
|
448
|
+
lines.push(clip(line, width));
|
|
449
|
+
}
|
|
450
|
+
lines.push('');
|
|
451
|
+
lines.push(dim(' ? or any key to close'));
|
|
452
|
+
while (lines.length < rows - 1)
|
|
453
|
+
lines.push('');
|
|
454
|
+
const body = lines.map((l) => `${l}${ESC}K`).join('\r\n');
|
|
455
|
+
return `${ESC}H${body}${ESC}J`;
|
|
456
|
+
}
|
|
406
457
|
/**
|
|
407
458
|
* Render the whole frame. Returns a single string that, written as-is, repaints
|
|
408
459
|
* the screen in place. `caps` gates all hue (defaults to a no-color frame so
|
|
409
460
|
* existing callers / non-TTY paths stay color-free).
|
|
410
461
|
*/
|
|
411
462
|
export function renderFrame(state, size, caps = { color: false, color256: false }) {
|
|
463
|
+
if (state.help === true)
|
|
464
|
+
return renderHelp(size, caps);
|
|
412
465
|
const cols = Math.max(20, size.cols);
|
|
413
466
|
const rows = Math.max(8, size.rows);
|
|
414
467
|
const width = cols - 1; // leave the last column for \x1b[K
|
|
415
468
|
const now = Date.now();
|
|
469
|
+
const inputMode = state.search || state.rename === true || state.message === true;
|
|
416
470
|
const lines = [];
|
|
417
471
|
// line 1 — title + right-aligned status summary (each glyph in its status hue).
|
|
418
472
|
const title = `${BOLD}Canvas${RESET} — ${state.totalNodes} nodes`;
|
|
@@ -428,10 +482,12 @@ export function renderFrame(state, size, caps = { color: false, color256: false
|
|
|
428
482
|
lines.push(tabBar(state.tab, caps.color));
|
|
429
483
|
// line 3 — status line (scope · sort · filter).
|
|
430
484
|
lines.push(statusLine(state));
|
|
431
|
-
// line 4 —
|
|
432
|
-
if (
|
|
433
|
-
const
|
|
434
|
-
|
|
485
|
+
// line 4 — the text-input prompt, only while a search / rename / message is open.
|
|
486
|
+
if (inputMode) {
|
|
487
|
+
const prefix = state.rename === true ? 'rename ▸' : state.message === true ? 'msg ▸' : '/';
|
|
488
|
+
const buf = state.rename === true ? (state.renameBuf ?? '') : state.message === true ? (state.messageBuf ?? '') : state.query;
|
|
489
|
+
const p = caps.color ? `${ESC}${FG_CYAN}m${prefix}${RESET}` : prefix;
|
|
490
|
+
lines.push(`${p} ${buf}▎`);
|
|
435
491
|
}
|
|
436
492
|
// column header (table labels) + separator.
|
|
437
493
|
const showCwd = state.cwdScope === null; // project column only matters across dirs
|
|
@@ -451,7 +507,8 @@ export function renderFrame(state, size, caps = { color: false, color256: false
|
|
|
451
507
|
}
|
|
452
508
|
else {
|
|
453
509
|
for (let i = start; i < end; i++) {
|
|
454
|
-
|
|
510
|
+
const vr = state.visible[i];
|
|
511
|
+
lines.push(rowLine(vr, state.tree, width, i === state.cursor, state.query, caps, showCwd, now, state.pinned.has(vr.id)));
|
|
455
512
|
}
|
|
456
513
|
for (let i = end - start; i < viewport; i++)
|
|
457
514
|
lines.push('');
|
|
@@ -477,11 +534,11 @@ export function renderFrame(state, size, caps = { color: false, color256: false
|
|
|
477
534
|
const selRow = state.visible[state.cursor];
|
|
478
535
|
const cursorRow = selRow !== undefined ? state.tree.nodes.get(selRow.id)?.row : undefined;
|
|
479
536
|
const hangingHint = cursorRow?.hanging != null ? 'K revive now ' : '';
|
|
480
|
-
const footer =
|
|
537
|
+
const footer = inputMode
|
|
481
538
|
? '⏎ commit Esc cancel ⌫ delete'
|
|
482
539
|
: state.readOnly === true
|
|
483
|
-
? '↑↓ move →/← tree
|
|
484
|
-
: `${hangingHint}↑↓ move
|
|
540
|
+
? '↑↓ move →/← tree / search f pin Tab tabs ? more q quit — read-only remote canvas'
|
|
541
|
+
: `${hangingHint}↑↓ move ⏎ resume / search f pin m msg x close R rename ? more q quit`;
|
|
485
542
|
lines.push(`${DIM}${clip(footer, width)}${RESET}`);
|
|
486
543
|
}
|
|
487
544
|
// Assemble: home, each line cleared to EOL, then clear below.
|
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
// nav-model.ts — the pure model/render layer
|
|
1
|
+
// nav-model.ts — the pure model/render layer for attach's canvas chrome.
|
|
2
2
|
//
|
|
3
|
-
// Extracted from src/pi-extensions/canvas-nav.ts so a SINGLE source feeds both
|
|
4
|
-
// the legacy pi extension (canvas-nav) and the headless `crtr surface attach` viewer.
|
|
5
3
|
// Everything here is pi-API-free: it reads the canvas (sqlite + meta.json + node
|
|
6
|
-
// telemetry) and produces ANSI-styled strings
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
// Mutable interaction state that the legacy extension held at module scope —
|
|
11
|
-
// the per-node ask counts and the manual fold overrides — is threaded through
|
|
12
|
-
// parameters here (see `asks` and `FoldState`) so this layer owns no singletons
|
|
13
|
-
// and each consumer keeps its own state.
|
|
4
|
+
// telemetry) and produces ANSI-styled strings plus a flattened graph model.
|
|
5
|
+
// Per-view interaction state, including ask counts and manual fold overrides, is
|
|
6
|
+
// threaded through parameters (see `asks` and `FoldState`) so this layer owns no
|
|
7
|
+
// singletons and each consumer keeps its own state.
|
|
14
8
|
import { execFileSync } from 'node:child_process';
|
|
15
9
|
import { existsSync, readFileSync } from 'node:fs';
|
|
16
10
|
import { join } from 'node:path';
|
|
@@ -23,6 +23,11 @@ export declare function canvasDbPath(): string;
|
|
|
23
23
|
* local-disk hosts. Parent dir is created on use so both paths just work. */
|
|
24
24
|
export declare function viewSocketPath(nodeId: string): string;
|
|
25
25
|
export declare function nodesRoot(): string;
|
|
26
|
+
/** Global, cwd-agnostic broker cache of per-session picker metadata, keyed by
|
|
27
|
+
* absolute `.jsonl` path. Shared across every node's broker (paths are absolute)
|
|
28
|
+
* and survives broker restarts so the first `/resume` open after a restart is
|
|
29
|
+
* also fast. Machine-local performance state — safe to delete; rebuilt on demand. */
|
|
30
|
+
export declare function sessionListCachePath(): string;
|
|
26
31
|
export declare function nodeDir(nodeId: string): string;
|
|
27
32
|
export declare function contextDir(nodeId: string): string;
|
|
28
33
|
/** Replace the literal env-var tokens `$CRTR_CONTEXT_DIR` / `$CRTR_NODE_ID` in
|
|
@@ -63,6 +63,13 @@ export function viewSocketPath(nodeId) {
|
|
|
63
63
|
export function nodesRoot() {
|
|
64
64
|
return join(crtrHome(), 'nodes');
|
|
65
65
|
}
|
|
66
|
+
/** Global, cwd-agnostic broker cache of per-session picker metadata, keyed by
|
|
67
|
+
* absolute `.jsonl` path. Shared across every node's broker (paths are absolute)
|
|
68
|
+
* and survives broker restarts so the first `/resume` open after a restart is
|
|
69
|
+
* also fast. Machine-local performance state — safe to delete; rebuilt on demand. */
|
|
70
|
+
export function sessionListCachePath() {
|
|
71
|
+
return join(crtrHome(), 'session-list-cache.json');
|
|
72
|
+
}
|
|
66
73
|
export function nodeDir(nodeId) {
|
|
67
74
|
return join(nodesRoot(), nodeId);
|
|
68
75
|
}
|
package/dist/core/config.d.ts
CHANGED
|
@@ -1,11 +1,32 @@
|
|
|
1
|
-
import type { Scope, ScopeConfig, ScopeState, KindConfig, ModelLaddersConfig } from '../types.js';
|
|
1
|
+
import type { Scope, ScopeConfig, ScopeState, CanvasNavConfig, KindConfig, ModelLaddersConfig } from '../types.js';
|
|
2
2
|
export declare function configPath(scope: Scope): string | null;
|
|
3
3
|
export declare function statePath(scope: Scope): string | null;
|
|
4
|
-
export
|
|
4
|
+
export type ConsumerCompatibleScopeConfig = ScopeConfig & {
|
|
5
|
+
readonly canvasNav: CanvasNavConfig;
|
|
6
|
+
};
|
|
7
|
+
export declare function readConfig(scope: Scope): ConsumerCompatibleScopeConfig;
|
|
5
8
|
export declare function readState(scope: Scope): ScopeState;
|
|
9
|
+
type RawConfig = Record<string, unknown>;
|
|
10
|
+
export declare function updateRawConfigAtomically(scope: Scope, mutate: (latest: RawConfig) => RawConfig): RawConfig;
|
|
6
11
|
export declare function writeConfig(scope: Scope, config: ScopeConfig): void;
|
|
12
|
+
/** Persist a RAW PARTIAL config to a scope's config.json exactly as given.
|
|
13
|
+
* Unlike `writeConfig`, this makes no promise that every field is present --
|
|
14
|
+
* callers pass the sparse partial that should live on disk, so an untouched
|
|
15
|
+
* key stays absent (and `readConfig`/`mergeConfig` re-derive it live from
|
|
16
|
+
* whichever build is running). This is the single central primitive every
|
|
17
|
+
* mutation path funnels through so no writer ever freezes a fully
|
|
18
|
+
* materialized `modelLadders` (concrete model ids that go stale across
|
|
19
|
+
* builds -- the live-Hearth freeze bug) onto disk. */
|
|
20
|
+
export declare function writeRawConfig(scope: Scope, config: Partial<ScopeConfig>): void;
|
|
7
21
|
export declare function writeState(scope: Scope, state: ScopeState): void;
|
|
8
22
|
export declare function ensureScopeInitialized(scope: Scope, root: string): void;
|
|
23
|
+
/** Raw (un-defaulted) partial config for one scope, or null if the scope has
|
|
24
|
+
* no root or no config.json. Used by `readMergedLaunchConfig` to layer
|
|
25
|
+
* scopes onto each other WITHOUT each scope's own default-fill masking a
|
|
26
|
+
* lower-precedence scope's real customization (see that function's comment
|
|
27
|
+
* for why `readConfig(scope)`, which already defaults-fills, is unusable
|
|
28
|
+
* for cross-scope layering). */
|
|
29
|
+
export declare function readRawScopeConfig(scope: Scope): Partial<ScopeConfig> | null;
|
|
9
30
|
export interface MergedLaunchConfig {
|
|
10
31
|
kinds: Record<string, KindConfig>;
|
|
11
32
|
modelLadders: ModelLaddersConfig;
|
|
@@ -65,5 +86,35 @@ export declare function subKindsAvailableTo(kind: string): {
|
|
|
65
86
|
kind: string;
|
|
66
87
|
whenToUse: string;
|
|
67
88
|
}[];
|
|
89
|
+
/** Apply `mutate` to a scope's MERGED config (so callers can read + write any
|
|
90
|
+
* field), then persist only a RAW PARTIAL: every top-level key the mutation
|
|
91
|
+
* left untouched keeps its exact on-disk raw value (absent stays absent, a
|
|
92
|
+
* sparse override stays sparse), and only keys the mutation actually changed
|
|
93
|
+
* are written. `modelLadders` gets sub-field-granular sparse handling via
|
|
94
|
+
* `sparseModelLaddersToPersist`. Result: a fresh bootstrap or any unrelated
|
|
95
|
+
* `sys config set` no longer freezes a full concrete `modelLadders` to disk,
|
|
96
|
+
* and a direct ladder-rung set still persists only the touched rung -- all
|
|
97
|
+
* through one lock-protected atomic update path. */
|
|
68
98
|
export declare function updateConfig(scope: Scope, mutate: (cfg: ScopeConfig) => void): ScopeConfig;
|
|
99
|
+
/** Persist a model as the DEFAULT for a kind — the `/model`-picker "defaults
|
|
100
|
+
* going forward" write. Writes a SPARSE `kinds.<kind>` patch (just the one
|
|
101
|
+
* model field, merged by `normalizeKindPatch`/`mergeKinds` over whatever the
|
|
102
|
+
* lower scopes define — never a frozen full kind entry) into the PROFILE's
|
|
103
|
+
* config.json when the node runs under a profile, else the user scope's.
|
|
104
|
+
* Mode-aware: an orchestrator's pick lands on `orchestratorModel` (base
|
|
105
|
+
* workers of the same kind keep their own default), a base node's on `model`.
|
|
106
|
+
* Callers pass a model string in any form `normalizeModel` accepts; portable
|
|
107
|
+
* ladder tokens (`ultra`, `anthropic/strong`) are preferred by callers since
|
|
108
|
+
* they never go stale across builds. */
|
|
109
|
+
export declare function persistDefaultKindModel(opts: {
|
|
110
|
+
kind: string;
|
|
111
|
+
model: string;
|
|
112
|
+
orchestrator?: boolean;
|
|
113
|
+
profileId?: string | null;
|
|
114
|
+
}): {
|
|
115
|
+
scope: 'profile' | 'user';
|
|
116
|
+
path: string;
|
|
117
|
+
field: 'model' | 'orchestratorModel';
|
|
118
|
+
};
|
|
69
119
|
export declare function updateState(scope: Scope, mutate: (s: ScopeState) => void): ScopeState;
|
|
120
|
+
export {};
|