@crouton-kit/crouter 0.3.28 → 0.3.30
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/build-root.d.ts +15 -7
- package/dist/build-root.js +48 -34
- package/dist/builtin-memory/crouter-development/marketplaces.md +7 -6
- package/dist/builtin-memory/crouter-development/personas/base-prompt.md +1 -1
- package/dist/builtin-memory/crouter-development/personas/orchestrator-prompt.md +1 -1
- package/dist/builtin-memory/crouter-development/personas.md +1 -1
- package/dist/builtin-memory/crouter-development/plugins.md +20 -18
- package/dist/builtin-memory/design.md +1 -1
- package/dist/builtin-memory/development.md +1 -1
- package/dist/builtin-memory/internal/INDEX.md +1 -1
- package/dist/builtin-memory/internal/examples/INDEX.md +1 -1
- package/dist/builtin-memory/internal/examples/imessage-assistant.md +2 -2
- package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
- package/dist/builtin-memory/internal/storage-tiers.md +1 -1
- package/dist/builtin-memory/planning.md +1 -1
- package/dist/builtin-memory/spec.md +6 -4
- package/dist/builtin-personas/orchestration-kernel.md +4 -5
- package/dist/builtin-personas/runtime-base.md +5 -4
- package/dist/builtin-personas/spec/PERSONA.md +8 -4
- package/dist/builtin-personas/spec/orchestrator.md +5 -3
- package/dist/builtin-personas/spec/requirements/PERSONA.md +10 -0
- package/dist/builtin-views/canvas/core.mjs +586 -0
- package/dist/builtin-views/canvas/text.mjs +58 -0
- package/dist/builtin-views/canvas/tui.mjs +165 -0
- package/dist/builtin-views/canvas/web.jsx +120 -0
- package/dist/builtin-views/git-pr/core.mjs +673 -0
- package/dist/builtin-views/git-pr/text.mjs +84 -0
- package/dist/builtin-views/git-pr/tui.mjs +302 -0
- package/dist/builtin-views/git-pr/web.jsx +216 -0
- package/dist/builtin-views/inbox/_lib/render.mjs +1 -3
- package/dist/builtin-views/inbox/core.mjs +1273 -0
- package/dist/builtin-views/inbox/text.mjs +73 -0
- package/dist/builtin-views/inbox/tui.mjs +312 -0
- package/dist/builtin-views/inbox/web.jsx +188 -0
- package/dist/builtin-views/linkedin/core.mjs +906 -0
- package/dist/builtin-views/linkedin/text.mjs +69 -0
- package/dist/builtin-views/linkedin/tui.mjs +427 -0
- package/dist/builtin-views/linkedin/web.jsx +206 -0
- package/dist/builtin-views/workspace-sidebar/core.mjs +621 -0
- package/dist/builtin-views/workspace-sidebar/text.mjs +53 -0
- package/dist/builtin-views/workspace-sidebar/tui.mjs +142 -0
- package/dist/builtin-views/workspace-sidebar/web.jsx +109 -0
- package/dist/cli.js +22 -17
- package/dist/clients/attach/__tests__/action-parity.test.js +48 -0
- package/dist/clients/attach/__tests__/clipboard-image.test.js +76 -0
- package/dist/clients/attach/__tests__/editor-newline.test.js +57 -0
- package/dist/clients/attach/__tests__/git-info.test.js +31 -0
- package/dist/clients/attach/__tests__/onrequest-wired.test.js +20 -0
- package/dist/clients/attach/__tests__/slash-quit-copy.test.js +42 -0
- package/dist/clients/attach/__tests__/titled-editor.test.js +39 -0
- package/dist/clients/attach/attach-cmd.js +282 -46
- package/dist/clients/attach/auth-pickers.d.ts +9 -0
- package/dist/clients/attach/auth-pickers.js +194 -0
- package/dist/clients/attach/canvas-panels.d.ts +4 -2
- package/dist/clients/attach/canvas-panels.js +45 -17
- package/dist/clients/attach/chat-view.d.ts +27 -2
- package/dist/clients/attach/chat-view.js +98 -9
- package/dist/clients/attach/clipboard-image.d.ts +47 -8
- package/dist/clients/attach/clipboard-image.js +150 -26
- package/dist/clients/attach/clipboard-text.d.ts +3 -0
- package/dist/clients/attach/clipboard-text.js +39 -0
- package/dist/clients/attach/config-load.d.ts +54 -7
- package/dist/clients/attach/config-load.js +99 -3
- package/dist/clients/attach/context-message.d.ts +12 -0
- package/dist/clients/attach/context-message.js +72 -0
- package/dist/clients/attach/git-info.d.ts +20 -0
- package/dist/clients/attach/git-info.js +44 -0
- package/dist/clients/attach/graph-overlay.d.ts +13 -4
- package/dist/clients/attach/graph-overlay.js +59 -19
- package/dist/clients/attach/input-controller.d.ts +75 -13
- package/dist/clients/attach/input-controller.js +305 -67
- package/dist/clients/attach/pickers.d.ts +58 -0
- package/dist/clients/attach/pickers.js +171 -0
- package/dist/clients/attach/slash-commands.d.ts +22 -0
- package/dist/clients/attach/slash-commands.js +91 -25
- package/dist/clients/attach/titled-editor.d.ts +33 -0
- package/dist/clients/attach/titled-editor.js +84 -0
- package/dist/clients/attach/view-socket.d.ts +18 -1
- package/dist/clients/attach/view-socket.js +70 -1
- package/dist/clients/web/dev-server.d.ts +7 -0
- package/dist/clients/web/dev-server.js +59 -0
- package/dist/clients/web/events.d.ts +14 -0
- package/dist/clients/web/events.js +151 -0
- package/dist/clients/web/server.d.ts +18 -0
- package/dist/clients/web/server.js +450 -0
- package/dist/clients/web/web-cmd.d.ts +2 -0
- package/dist/clients/web/web-cmd.js +120 -0
- package/dist/commands/canvas.js +1 -2
- package/dist/commands/chord.js +4 -25
- package/dist/commands/dashboard.js +5 -1
- package/dist/commands/memory/__tests__/lint-schema.test.js +6 -6
- package/dist/commands/memory/lint.js +14 -2
- package/dist/commands/memory/read.js +2 -2
- package/dist/commands/memory/shared.d.ts +7 -1
- package/dist/commands/memory/shared.js +18 -3
- package/dist/commands/memory/write.js +8 -4
- package/dist/commands/memory.js +4 -4
- package/dist/commands/node.d.ts +1 -1
- package/dist/commands/node.js +64 -65
- package/dist/commands/pkg.js +1 -2
- package/dist/commands/revive.js +11 -3
- package/dist/commands/sys/sync.d.ts +1 -0
- package/dist/commands/sys/sync.js +187 -0
- package/dist/commands/sys.js +3 -2
- package/dist/commands/view-cycle.js +2 -2
- package/dist/commands/view-list.js +8 -8
- package/dist/commands/view-new.js +21 -17
- package/dist/commands/view-pick.js +1 -1
- package/dist/commands/view-run.js +35 -14
- package/dist/commands/view.js +8 -6
- package/dist/commands/workspace.d.ts +2 -0
- package/dist/commands/workspace.js +161 -0
- package/dist/core/__tests__/broker-double-spawn.test.d.ts +1 -0
- package/dist/core/__tests__/broker-double-spawn.test.js +143 -0
- package/dist/core/__tests__/broker-fork-seam.test.d.ts +1 -0
- package/dist/core/__tests__/broker-fork-seam.test.js +102 -0
- package/dist/core/__tests__/broker-sdk-wiring.test.js +2 -0
- package/dist/core/__tests__/child-death-wake.test.js +56 -111
- package/dist/core/__tests__/close.test.js +14 -20
- package/dist/core/__tests__/context-intro.test.js +19 -19
- package/dist/core/__tests__/daemon-boot.test.js +30 -23
- package/dist/core/__tests__/draw-style.test.js +1 -1
- package/dist/core/__tests__/error-stall-recycle.test.d.ts +1 -0
- package/dist/core/__tests__/error-stall-recycle.test.js +141 -0
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +17 -1
- package/dist/core/__tests__/fixtures/fake-engine.js +22 -2
- package/dist/core/__tests__/fixtures/fake-pi-host.js +2 -2
- package/dist/core/__tests__/focuses.test.js +25 -13
- package/dist/core/__tests__/fork.test.js +22 -5
- package/dist/core/__tests__/full/broker-control-preempt.test.d.ts +1 -0
- package/dist/core/__tests__/full/broker-control-preempt.test.js +61 -0
- package/dist/core/__tests__/full/broker-model-changed-broadcast.test.d.ts +1 -0
- package/dist/core/__tests__/full/broker-model-changed-broadcast.test.js +57 -0
- package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.d.ts +1 -0
- package/dist/core/__tests__/full/broker-navigate-tree-rewelcome.test.js +80 -0
- package/dist/core/__tests__/full/broker-pane-resolution.test.js +90 -0
- package/dist/core/__tests__/full/cascade-close.test.js +22 -8
- package/dist/core/__tests__/full/detach-focus.test.js +66 -169
- package/dist/core/__tests__/helpers/harness.d.ts +6 -9
- package/dist/core/__tests__/helpers/harness.js +19 -36
- package/dist/core/__tests__/human-node-not-supervised.test.d.ts +1 -0
- package/dist/core/__tests__/human-node-not-supervised.test.js +83 -0
- package/dist/core/__tests__/lifecycle.test.js +1 -19
- package/dist/core/__tests__/listing-completeness.test.js +2 -2
- package/dist/core/__tests__/live-mutation-verbs.test.js +5 -5
- package/dist/core/__tests__/memory-resolver.test.js +1 -1
- package/dist/core/__tests__/on-read-dedup-resume.test.js +2 -2
- package/dist/core/__tests__/refresh-stall-recycle.test.d.ts +1 -0
- package/dist/core/__tests__/refresh-stall-recycle.test.js +88 -0
- package/dist/core/__tests__/relaunch-root.test.d.ts +1 -0
- package/dist/core/__tests__/relaunch-root.test.js +114 -0
- package/dist/core/__tests__/reset.test.js +19 -79
- package/dist/core/__tests__/steer-note.test.js +9 -7
- package/dist/core/__tests__/tmux-surface.test.js +13 -7
- package/dist/core/bootstrap.d.ts +0 -3
- package/dist/core/bootstrap.js +1 -143
- package/dist/core/canvas/browse/__tests__/model.test.js +86 -1
- package/dist/core/canvas/browse/__tests__/render.test.js +2 -1
- package/dist/core/canvas/browse/app.js +131 -8
- package/dist/core/canvas/browse/model.d.ts +23 -5
- package/dist/core/canvas/browse/model.js +68 -13
- package/dist/core/canvas/browse/render.d.ts +7 -1
- package/dist/core/canvas/browse/render.js +178 -47
- package/dist/core/canvas/canvas.js +1 -1
- package/dist/core/canvas/focuses.d.ts +4 -4
- package/dist/core/canvas/focuses.js +7 -7
- package/dist/core/canvas/nav-model.js +8 -7
- package/dist/core/canvas/render.d.ts +68 -9
- package/dist/core/canvas/render.js +195 -61
- package/dist/core/canvas/types.d.ts +16 -23
- package/dist/core/config.js +1 -4
- package/dist/core/memory-resolver.js +43 -5
- package/dist/core/runtime/bearings.d.ts +1 -1
- package/dist/core/runtime/bearings.js +8 -8
- package/dist/core/runtime/branded-host.d.ts +16 -0
- package/dist/core/runtime/branded-host.js +127 -0
- package/dist/core/runtime/broker-protocol.d.ts +212 -6
- package/dist/core/runtime/broker.d.ts +4 -1
- package/dist/core/runtime/broker.js +494 -58
- package/dist/core/runtime/close.d.ts +12 -2
- package/dist/core/runtime/close.js +37 -16
- package/dist/core/runtime/front-door.js +6 -14
- package/dist/core/runtime/host.d.ts +14 -34
- package/dist/core/runtime/host.js +14 -50
- package/dist/core/runtime/launch.d.ts +12 -9
- package/dist/core/runtime/launch.js +27 -15
- package/dist/core/runtime/lifecycle.d.ts +1 -1
- package/dist/core/runtime/lifecycle.js +15 -19
- package/dist/core/runtime/nodes.d.ts +0 -55
- package/dist/core/runtime/nodes.js +6 -74
- package/dist/core/runtime/placement.d.ts +91 -335
- package/dist/core/runtime/placement.js +291 -858
- package/dist/core/runtime/promote.d.ts +2 -0
- package/dist/core/runtime/promote.js +24 -6
- package/dist/core/runtime/recap.d.ts +8 -0
- package/dist/core/runtime/recap.js +107 -0
- package/dist/core/runtime/recycle.js +25 -61
- package/dist/core/runtime/reset.d.ts +43 -37
- package/dist/core/runtime/reset.js +131 -218
- package/dist/core/runtime/revive.d.ts +9 -29
- package/dist/core/runtime/revive.js +40 -139
- package/dist/core/runtime/spawn.d.ts +15 -16
- package/dist/core/runtime/spawn.js +165 -194
- package/dist/core/runtime/surface-bg.d.ts +11 -0
- package/dist/core/runtime/surface-bg.js +68 -0
- package/dist/core/runtime/tmux.d.ts +15 -52
- package/dist/core/runtime/tmux.js +35 -99
- package/dist/core/scope.d.ts +1 -2
- package/dist/core/scope.js +1 -5
- package/dist/core/skill-sync/__tests__/dry-run-wrote-count.test.d.ts +1 -0
- package/dist/core/skill-sync/__tests__/dry-run-wrote-count.test.js +57 -0
- package/dist/core/skill-sync/builtins.d.ts +42 -0
- package/dist/core/skill-sync/builtins.js +112 -0
- package/dist/core/skill-sync/claude-plugins.d.ts +23 -0
- package/dist/core/skill-sync/claude-plugins.js +71 -0
- package/dist/core/skill-sync/engine.d.ts +42 -0
- package/dist/core/skill-sync/engine.js +633 -0
- package/dist/core/skill-sync/export.d.ts +23 -0
- package/dist/core/skill-sync/export.js +86 -0
- package/dist/core/skill-sync/manifest.d.ts +64 -0
- package/dist/core/skill-sync/manifest.js +181 -0
- package/dist/core/skill-sync/profile.d.ts +76 -0
- package/dist/core/skill-sync/profile.js +173 -0
- package/dist/core/skill-sync/snapshot.d.ts +57 -0
- package/dist/core/skill-sync/snapshot.js +120 -0
- package/dist/core/substrate/index.d.ts +1 -1
- package/dist/core/substrate/index.js +1 -1
- package/dist/core/substrate/injected-store.js +3 -3
- package/dist/core/substrate/on-read.js +68 -6
- package/dist/core/substrate/render.d.ts +8 -11
- package/dist/core/substrate/render.js +29 -43
- package/dist/core/substrate/schema.d.ts +10 -3
- package/dist/core/substrate/schema.js +6 -3
- package/dist/core/tui/host.d.ts +12 -4
- package/dist/core/tui/host.js +280 -149
- package/dist/core/view/bridge.d.ts +10 -0
- package/dist/core/view/bridge.js +31 -0
- package/dist/core/view/chrome.d.ts +9 -0
- package/dist/core/view/chrome.js +22 -0
- package/dist/core/view/contract.d.ts +171 -0
- package/dist/core/view/contract.js +23 -0
- package/dist/core/view/loader.d.ts +31 -0
- package/dist/core/view/loader.js +188 -0
- package/dist/core/view/transport-local.d.ts +7 -0
- package/dist/core/view/transport-local.js +70 -0
- package/dist/core/view/transport.d.ts +4 -0
- package/dist/core/view/transport.js +15 -0
- package/dist/daemon/crtrd.d.ts +38 -27
- package/dist/daemon/crtrd.js +303 -376
- package/dist/daemon/manage.js +6 -1
- package/dist/index.js +1 -1
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +28 -20
- package/dist/pi-extensions/canvas-context-intro.js +4 -4
- package/dist/pi-extensions/canvas-doc-substrate.js +16 -16
- package/dist/pi-extensions/canvas-nav.js +5 -0
- package/dist/pi-extensions/canvas-recap.d.ts +37 -0
- package/dist/pi-extensions/canvas-recap.js +236 -0
- package/dist/pi-extensions/canvas-resume.js +2 -1
- package/dist/pi-extensions/canvas-stophook.d.ts +14 -12
- package/dist/pi-extensions/canvas-stophook.js +87 -101
- package/dist/pi-extensions/canvas-view.js +2 -1
- package/dist/pi-extensions/widget-order-bus.d.ts +6 -0
- package/dist/pi-extensions/widget-order-bus.js +34 -0
- package/dist/prompts/view.d.ts +2 -2
- package/dist/prompts/view.js +145 -73
- package/dist/types.d.ts +1 -6
- package/dist/types.js +1 -3
- package/dist/web/ViewChrome.d.ts +7 -0
- package/dist/web/ViewChrome.js +28 -0
- package/dist/web/ViewPane.d.ts +39 -0
- package/dist/web/ViewPane.js +48 -0
- package/dist/web/index.d.ts +6 -0
- package/dist/web/index.js +16 -0
- package/dist/web/runtime.d.ts +39 -0
- package/dist/web/runtime.js +133 -0
- package/dist/web/states.d.ts +24 -0
- package/dist/web/states.js +24 -0
- package/dist/web/transport-http.d.ts +5 -0
- package/dist/web/transport-http.js +28 -0
- package/dist/web-client/assets/index-BUvQb4hR.css +2 -0
- package/dist/web-client/assets/index-ClLQXYAE.js +10 -0
- package/dist/web-client/index.html +13 -0
- package/package.json +20 -6
- package/dist/builtin-views/canvas/client.mjs +0 -303
- package/dist/builtin-views/canvas/view.mjs +0 -576
- package/dist/builtin-views/git-pr/client.mjs +0 -440
- package/dist/builtin-views/git-pr/view.mjs +0 -675
- package/dist/builtin-views/inbox/sources/gmail.mjs +0 -965
- package/dist/builtin-views/inbox/sources/linkedin.mjs +0 -427
- package/dist/builtin-views/inbox/view.mjs +0 -889
- package/dist/builtin-views/linkedin/client.mjs +0 -610
- package/dist/builtin-views/linkedin/view.mjs +0 -1171
- package/dist/commands/pkg/bridge.d.ts +0 -1
- package/dist/commands/pkg/bridge.js +0 -137
- package/dist/commands/skill/author.d.ts +0 -3
- package/dist/commands/skill/author.js +0 -140
- package/dist/commands/skill/shared.d.ts +0 -3
- package/dist/commands/skill/shared.js +0 -19
- package/dist/commands/skill.d.ts +0 -2
- package/dist/commands/skill.js +0 -21
- package/dist/commands/tmux-spread.d.ts +0 -2
- package/dist/commands/tmux-spread.js +0 -144
- package/dist/core/__tests__/full/daemon-liveness-pane.full.test.js +0 -292
- package/dist/core/__tests__/full/placement-focus.test.js +0 -309
- package/dist/core/__tests__/full/placement-reconcile.test.js +0 -212
- package/dist/core/__tests__/full/placement-revive.test.js +0 -238
- package/dist/core/__tests__/full/placement-teardown.test.js +0 -297
- package/dist/core/__tests__/home-session.test.js +0 -186
- package/dist/core/__tests__/relaunch.test.js +0 -335
- package/dist/core/bridge-map.d.ts +0 -19
- package/dist/core/bridge-map.js +0 -73
- package/dist/core/tui/contract.d.ts +0 -83
- package/dist/core/tui/contract.js +0 -8
- package/dist/core/tui/loader.d.ts +0 -16
- package/dist/core/tui/loader.js +0 -94
- package/dist/prompts/skill.d.ts +0 -2
- package/dist/prompts/skill.js +0 -650
- /package/dist/{core/__tests__/full/daemon-liveness-pane.full.test.d.ts → clients/attach/__tests__/action-parity.test.d.ts} +0 -0
- /package/dist/{core/__tests__/full/placement-focus.test.d.ts → clients/attach/__tests__/clipboard-image.test.d.ts} +0 -0
- /package/dist/{core/__tests__/full/placement-reconcile.test.d.ts → clients/attach/__tests__/editor-newline.test.d.ts} +0 -0
- /package/dist/{core/__tests__/full/placement-revive.test.d.ts → clients/attach/__tests__/git-info.test.d.ts} +0 -0
- /package/dist/{core/__tests__/full/placement-teardown.test.d.ts → clients/attach/__tests__/onrequest-wired.test.d.ts} +0 -0
- /package/dist/{core/__tests__/home-session.test.d.ts → clients/attach/__tests__/slash-quit-copy.test.d.ts} +0 -0
- /package/dist/{core/__tests__/relaunch.test.d.ts → clients/attach/__tests__/titled-editor.test.d.ts} +0 -0
|
@@ -9,10 +9,14 @@
|
|
|
9
9
|
// `pi --session` directly (see canvas-resume.ts header for the desync hazard).
|
|
10
10
|
import { execFileSync } from 'node:child_process';
|
|
11
11
|
import { resolve } from 'node:path';
|
|
12
|
-
import { dashboardRowsAll, renderForest } from '../render.js';
|
|
13
|
-
import { listNodes, subscriptionsOf } from '../canvas.js';
|
|
12
|
+
import { dashboardRowsAll, enrichRows, loadPreview, renderForest } from '../render.js';
|
|
13
|
+
import { listNodes, subscriptionsOf, getNode } from '../canvas.js';
|
|
14
|
+
import { closeNode } from '../../runtime/close.js';
|
|
14
15
|
import { setupTerminal, restoreTerminal, getTerminalSize, parseKeypress, } from '../../tui/terminal.js';
|
|
15
|
-
import { buildTree, flatten, TABS
|
|
16
|
+
import { buildTree, flatten, TABS } from './model.js';
|
|
17
|
+
// Sort cycle for the `s` key. Starts on the default `attention` ordering; one `s`
|
|
18
|
+
// press restores the structural `tree` view, then relevance/recency, then back.
|
|
19
|
+
const SORT_CYCLE = ['attention', 'tree', 'relevance', 'recency'];
|
|
16
20
|
import { renderFrame, detectColorCaps, headerHeight, PREVIEW_HEIGHT } from './render.js';
|
|
17
21
|
/** Viewport (body) height = total rows minus the header renderFrame draws (see
|
|
18
22
|
* render.ts headerHeight), the footer, and the preview panel when shown. Kept
|
|
@@ -50,11 +54,16 @@ export async function runBrowse(opts = {}) {
|
|
|
50
54
|
search: false,
|
|
51
55
|
scrollOffset: 0,
|
|
52
56
|
cwdScope: launchCwd, // default: this dir
|
|
53
|
-
sort: '
|
|
57
|
+
sort: 'attention', // default: attention ordering (attached/streaming/live first)
|
|
54
58
|
preview: true, // default ON (decision)
|
|
55
59
|
residentsOnly: true, // default ON: hide one-shot workers (decision)
|
|
60
|
+
pendingClose: null,
|
|
56
61
|
};
|
|
57
62
|
let visible = [];
|
|
63
|
+
// The DashboardRow ref the tree holds for a visible id. Enrichment mutates this
|
|
64
|
+
// object in place, so a later renderFrame (reading off the same tree) re-renders
|
|
65
|
+
// the upgraded label/ctx/preview without a re-snapshot.
|
|
66
|
+
const rowOf = (id) => tree.nodes.get(id)?.row;
|
|
58
67
|
// Color capability is fixed for the session (it's a property of the tty/env).
|
|
59
68
|
const caps = detectColorCaps();
|
|
60
69
|
// Restore the terminal exactly once, however we leave (quit, resume, crash).
|
|
@@ -114,11 +123,29 @@ export async function runBrowse(opts = {}) {
|
|
|
114
123
|
state.scrollOffset = state.cursor - viewport + 1;
|
|
115
124
|
if (state.scrollOffset < 0)
|
|
116
125
|
state.scrollOffset = 0;
|
|
126
|
+
// Lazy paint: enrich only the rows about to be drawn (full label + ctx + asks),
|
|
127
|
+
// and load the selected row's preview. Both are idempotent (guard-flagged), so
|
|
128
|
+
// calling them every flush is cheap once a row is warm.
|
|
129
|
+
const top = state.scrollOffset;
|
|
130
|
+
const bottom = Math.min(visible.length, top + viewport);
|
|
131
|
+
const slice = [];
|
|
132
|
+
for (let i = top; i < bottom; i++) {
|
|
133
|
+
const r = rowOf(visible[i].id);
|
|
134
|
+
if (r !== undefined)
|
|
135
|
+
slice.push(r);
|
|
136
|
+
}
|
|
137
|
+
enrichRows(slice);
|
|
138
|
+
const cur = curRow();
|
|
139
|
+
if (cur !== undefined) {
|
|
140
|
+
const r = rowOf(cur.id);
|
|
141
|
+
if (r !== undefined)
|
|
142
|
+
loadPreview(r);
|
|
143
|
+
}
|
|
117
144
|
const frame = renderFrame({
|
|
118
145
|
tree, visible, tab: state.tab, cursor: state.cursor, scrollOffset: state.scrollOffset,
|
|
119
146
|
query: state.query, search: state.search, totalNodes,
|
|
120
147
|
cwdScope: state.cwdScope, sort: state.sort, preview: state.preview,
|
|
121
|
-
residentsOnly: state.residentsOnly,
|
|
148
|
+
residentsOnly: state.residentsOnly, pendingClose: state.pendingClose,
|
|
122
149
|
}, size, caps);
|
|
123
150
|
process.stdout.write(frame);
|
|
124
151
|
};
|
|
@@ -128,6 +155,50 @@ export async function runBrowse(opts = {}) {
|
|
|
128
155
|
};
|
|
129
156
|
const curRow = () => visible[state.cursor];
|
|
130
157
|
const isExpanded = (id) => !state.collapsed.has(id);
|
|
158
|
+
// Every node in the snapshot subtree rooted at `id` (the node + all its tree
|
|
159
|
+
// descendants), used by the close-out streaming check.
|
|
160
|
+
const subtreeIds = (id) => {
|
|
161
|
+
const out = [];
|
|
162
|
+
const stack = [id];
|
|
163
|
+
const seen = new Set();
|
|
164
|
+
while (stack.length > 0) {
|
|
165
|
+
const cur = stack.pop();
|
|
166
|
+
if (seen.has(cur))
|
|
167
|
+
continue;
|
|
168
|
+
seen.add(cur);
|
|
169
|
+
out.push(cur);
|
|
170
|
+
for (const c of tree.nodes.get(cur)?.childIds ?? [])
|
|
171
|
+
stack.push(c);
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
174
|
+
};
|
|
175
|
+
// Is the node, or any descendant, GENUINELY mid-turn right now (from the snapshot)?
|
|
176
|
+
const anyStreaming = (id) => subtreeIds(id).some((x) => tree.nodes.get(x)?.row.streaming === true);
|
|
177
|
+
// Close-out (`x`): finalize the node to `done`, cascade-cancel its exclusive
|
|
178
|
+
// subtree, tear down each engine, and detach every attached viewer. Then reflect
|
|
179
|
+
// the new terminal statuses back into the live snapshot so the row updates in
|
|
180
|
+
// place (no re-snapshot). Best-effort: a teardown failure never wedges the picker.
|
|
181
|
+
const doClose = (id) => {
|
|
182
|
+
state.pendingClose = null;
|
|
183
|
+
let closed = [];
|
|
184
|
+
try {
|
|
185
|
+
closed = closeNode(id, { rootEvent: 'finalize' }).closed;
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
return; // unknown/already-gone node — nothing to reflect
|
|
189
|
+
}
|
|
190
|
+
for (const cid of closed) {
|
|
191
|
+
const n = tree.nodes.get(cid);
|
|
192
|
+
if (n === undefined)
|
|
193
|
+
continue;
|
|
194
|
+
const m = getNode(cid);
|
|
195
|
+
if (m !== null)
|
|
196
|
+
n.row.status = m.status; // real post-close status (done / canceled)
|
|
197
|
+
n.row.streaming = false;
|
|
198
|
+
n.row.viewed = false;
|
|
199
|
+
}
|
|
200
|
+
recompute(id);
|
|
201
|
+
};
|
|
131
202
|
const cycleTab = (dir) => {
|
|
132
203
|
const i = TABS.indexOf(state.tab);
|
|
133
204
|
state.tab = TABS[(i + dir + TABS.length) % TABS.length];
|
|
@@ -135,11 +206,12 @@ export async function runBrowse(opts = {}) {
|
|
|
135
206
|
state.scrollOffset = 0;
|
|
136
207
|
recompute();
|
|
137
208
|
};
|
|
138
|
-
// Cycle sort (tree → relevance → recency), keeping the
|
|
209
|
+
// Cycle sort (attention → tree → relevance → recency → attention), keeping the
|
|
210
|
+
// selected node put. One `s` from the default `attention` lands on `tree`.
|
|
139
211
|
const cycleSort = () => {
|
|
140
212
|
const keep = curRow()?.id;
|
|
141
|
-
const i =
|
|
142
|
-
state.sort =
|
|
213
|
+
const i = SORT_CYCLE.indexOf(state.sort);
|
|
214
|
+
state.sort = SORT_CYCLE[(i + 1) % SORT_CYCLE.length];
|
|
143
215
|
recompute(keep);
|
|
144
216
|
};
|
|
145
217
|
// Toggle cwd scope between the launch dir and All dirs (no-op if launch dir
|
|
@@ -204,6 +276,19 @@ export async function runBrowse(opts = {}) {
|
|
|
204
276
|
quit();
|
|
205
277
|
return;
|
|
206
278
|
}
|
|
279
|
+
// Close-out confirm sub-state: a streaming node is awaiting y/n. Swallow every
|
|
280
|
+
// other key so the confirm is modal.
|
|
281
|
+
if (state.pendingClose !== null) {
|
|
282
|
+
if (input === 'y' || input === 'Y') {
|
|
283
|
+
doClose(state.pendingClose);
|
|
284
|
+
flush();
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
// n / Esc / anything else cancels the close.
|
|
288
|
+
state.pendingClose = null;
|
|
289
|
+
flush();
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
207
292
|
const row = curRow();
|
|
208
293
|
// Quit.
|
|
209
294
|
if (input === 'q' || key.escape)
|
|
@@ -294,6 +379,18 @@ export async function runBrowse(opts = {}) {
|
|
|
294
379
|
flush();
|
|
295
380
|
return;
|
|
296
381
|
}
|
|
382
|
+
// Close-out the selected node (+ its exclusive subtree). If anything in that
|
|
383
|
+
// subtree is actively streaming, confirm first (y/n); otherwise close at once.
|
|
384
|
+
if (input === 'x') {
|
|
385
|
+
if (row !== undefined) {
|
|
386
|
+
if (anyStreaming(row.id))
|
|
387
|
+
state.pendingClose = row.id;
|
|
388
|
+
else
|
|
389
|
+
doClose(row.id);
|
|
390
|
+
}
|
|
391
|
+
flush();
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
297
394
|
// Sort / scope / residents / preview.
|
|
298
395
|
if (input === 's') {
|
|
299
396
|
cycleSort();
|
|
@@ -350,6 +447,32 @@ export async function runBrowse(opts = {}) {
|
|
|
350
447
|
}
|
|
351
448
|
setupTerminal();
|
|
352
449
|
flush();
|
|
450
|
+
// Background corpus warmer: after the instant first paint, progressively enrich
|
|
451
|
+
// + load-preview every row (in small chunks, off the event loop) so the prompt
|
|
452
|
+
// super-search corpus lights up shortly after the instant name/kind/id search.
|
|
453
|
+
// Mutates row objects only; re-flushes solely while a live search is open so new
|
|
454
|
+
// matches surface. Stops as soon as the terminal is restored (quit/resume/crash).
|
|
455
|
+
const warmRows = [...tree.nodes.values()].map((n) => n.row);
|
|
456
|
+
let warmIdx = 0;
|
|
457
|
+
const WARM_CHUNK = 30;
|
|
458
|
+
const warmChunk = () => {
|
|
459
|
+
if (restored)
|
|
460
|
+
return;
|
|
461
|
+
const end = Math.min(warmIdx + WARM_CHUNK, warmRows.length);
|
|
462
|
+
const slice = warmRows.slice(warmIdx, end);
|
|
463
|
+
enrichRows(slice);
|
|
464
|
+
for (const r of slice)
|
|
465
|
+
loadPreview(r);
|
|
466
|
+
warmIdx = end;
|
|
467
|
+
// A live search may match the freshly-warmed prompts → recompute + repaint.
|
|
468
|
+
if (state.search && state.query !== '') {
|
|
469
|
+
recompute(curRow()?.id);
|
|
470
|
+
flush();
|
|
471
|
+
}
|
|
472
|
+
if (warmIdx < warmRows.length)
|
|
473
|
+
setImmediate(warmChunk);
|
|
474
|
+
};
|
|
475
|
+
setImmediate(warmChunk);
|
|
353
476
|
await new Promise(() => {
|
|
354
477
|
const onData = (data) => {
|
|
355
478
|
try {
|
|
@@ -4,9 +4,11 @@ export type Tab = 'All' | 'Live' | 'Dormant' | 'Flagged';
|
|
|
4
4
|
export declare const TABS: readonly Tab[];
|
|
5
5
|
/** How the visible rows are ordered.
|
|
6
6
|
* tree — spanning-tree order, ancestors shown for context (the default).
|
|
7
|
+
* attention — FLAT list, tiered by where your attention belongs (attached/
|
|
8
|
+
* streaming/live), newest-message-first within each tier.
|
|
7
9
|
* relevance — FLAT list, best query match first (super-search).
|
|
8
10
|
* recency — FLAT list, newest `created` first. */
|
|
9
|
-
export type SortMode = 'tree' | 'relevance' | 'recency';
|
|
11
|
+
export type SortMode = 'tree' | 'attention' | 'relevance' | 'recency';
|
|
10
12
|
export declare const SORTS: readonly SortMode[];
|
|
11
13
|
/** Does a node belong to this tab's slice?
|
|
12
14
|
* All — every node.
|
|
@@ -88,6 +90,22 @@ export declare function fieldScore(query: string, text: string): number;
|
|
|
88
90
|
/** Weighted relevance of a row to the query across all searched fields. 0 means
|
|
89
91
|
* no field matched (excluded from relevance results, same as `queryMatch`). */
|
|
90
92
|
export declare function scoreRow(query: string, row: DashboardRow): number;
|
|
93
|
+
/** The "most recent message" signal for the attention sort: the pi session-file
|
|
94
|
+
* mtime (ms) the snapshot stamps on each row, falling back to the `created`
|
|
95
|
+
* birth timestamp when no session file exists. Larger = more recent.
|
|
96
|
+
*
|
|
97
|
+
* NOTE (phase-3 reconcile): phase 1 owns the field name on DashboardRow. We read
|
|
98
|
+
* `mtimeMs` here as the most likely name; if phase 1 lands a different name,
|
|
99
|
+
* update this single accessor. `created` is ISO 8601, so its epoch-ms is a
|
|
100
|
+
* monotonic stand-in within the same tier. */
|
|
101
|
+
export declare function attentionMtime(row: DashboardRow): number;
|
|
102
|
+
/** Attention tier (lower = higher priority, shown first):
|
|
103
|
+
* T0 — attached AND streaming (`viewed && streaming`)
|
|
104
|
+
* T1 — attached, not streaming (`viewed`)
|
|
105
|
+
* T2 — streaming, not attached
|
|
106
|
+
* T3 — live but neither (`status active|idle`)
|
|
107
|
+
* T4 — everything else (dormant: done/dead/canceled). */
|
|
108
|
+
export declare function attentionTier(row: DashboardRow): number;
|
|
91
109
|
export interface VisibleRow {
|
|
92
110
|
id: string;
|
|
93
111
|
depth: number;
|
|
@@ -103,10 +121,10 @@ export interface FlattenOpts {
|
|
|
103
121
|
* undefined = All dirs (no cwd filter). Like the tab predicate, it gates the
|
|
104
122
|
* matched set — ancestors from other dirs still render dimmed for tree context. */
|
|
105
123
|
cwdScope?: string | null;
|
|
106
|
-
/** Lifecycle filter: when true,
|
|
107
|
-
* the
|
|
108
|
-
*
|
|
109
|
-
*
|
|
124
|
+
/** Lifecycle filter: when true, `terminal` (one-shot worker) nodes are kept out
|
|
125
|
+
* of the TOP-LEVEL rows and the flat search results — but, in tree mode, still
|
|
126
|
+
* appear when you manually expand their parent fold (drilling into a resident).
|
|
127
|
+
* The resume picker defaults this ON. Undefined/false = every lifecycle. */
|
|
110
128
|
residentsOnly?: boolean;
|
|
111
129
|
/** Ordering. `tree` keeps the spanning tree + ancestor context; `relevance` /
|
|
112
130
|
* `recency` produce a FLAT ranked list of directly-matched rows. */
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// access (dashboardRowsAll / listNodes / subscriptionsOf) into buildTree, then
|
|
6
6
|
// drives flatten() on each keystroke.
|
|
7
7
|
export const TABS = ['All', 'Live', 'Dormant', 'Flagged'];
|
|
8
|
-
export const SORTS = ['tree', 'relevance', 'recency'];
|
|
8
|
+
export const SORTS = ['tree', 'attention', 'relevance', 'recency'];
|
|
9
9
|
/** Does a node belong to this tab's slice?
|
|
10
10
|
* All — every node.
|
|
11
11
|
* Live — active | idle.
|
|
@@ -287,6 +287,43 @@ export function scoreRow(query, row) {
|
|
|
287
287
|
FIELD_WEIGHTS.id * fieldScore(query, shortId(row.node_id)) +
|
|
288
288
|
FIELD_WEIGHTS.prompt * (prompt !== '' ? fieldScore(query, prompt) : 0));
|
|
289
289
|
}
|
|
290
|
+
// ---------------------------------------------------------------------------
|
|
291
|
+
// Attention tiering (default sort)
|
|
292
|
+
// ---------------------------------------------------------------------------
|
|
293
|
+
/** The "most recent message" signal for the attention sort: the pi session-file
|
|
294
|
+
* mtime (ms) the snapshot stamps on each row, falling back to the `created`
|
|
295
|
+
* birth timestamp when no session file exists. Larger = more recent.
|
|
296
|
+
*
|
|
297
|
+
* NOTE (phase-3 reconcile): phase 1 owns the field name on DashboardRow. We read
|
|
298
|
+
* `mtimeMs` here as the most likely name; if phase 1 lands a different name,
|
|
299
|
+
* update this single accessor. `created` is ISO 8601, so its epoch-ms is a
|
|
300
|
+
* monotonic stand-in within the same tier. */
|
|
301
|
+
export function attentionMtime(row) {
|
|
302
|
+
const m = row.mtimeMs;
|
|
303
|
+
if (typeof m === 'number' && Number.isFinite(m))
|
|
304
|
+
return m;
|
|
305
|
+
const t = Date.parse(row.created);
|
|
306
|
+
return Number.isFinite(t) ? t : 0;
|
|
307
|
+
}
|
|
308
|
+
/** Attention tier (lower = higher priority, shown first):
|
|
309
|
+
* T0 — attached AND streaming (`viewed && streaming`)
|
|
310
|
+
* T1 — attached, not streaming (`viewed`)
|
|
311
|
+
* T2 — streaming, not attached
|
|
312
|
+
* T3 — live but neither (`status active|idle`)
|
|
313
|
+
* T4 — everything else (dormant: done/dead/canceled). */
|
|
314
|
+
export function attentionTier(row) {
|
|
315
|
+
const viewed = row.viewed === true;
|
|
316
|
+
const streaming = row.streaming === true;
|
|
317
|
+
if (viewed && streaming)
|
|
318
|
+
return 0;
|
|
319
|
+
if (viewed)
|
|
320
|
+
return 1;
|
|
321
|
+
if (streaming)
|
|
322
|
+
return 2;
|
|
323
|
+
if (row.status === 'active' || row.status === 'idle')
|
|
324
|
+
return 3;
|
|
325
|
+
return 4;
|
|
326
|
+
}
|
|
290
327
|
/** Is this row inside the active cwd scope? No scope (null/undefined) = All dirs. */
|
|
291
328
|
export function cwdMatch(scope, row) {
|
|
292
329
|
return scope === null || scope === undefined || row.cwd === scope;
|
|
@@ -312,13 +349,19 @@ export function lifecycleMatch(residentsOnly, row) {
|
|
|
312
349
|
export function flatten(tree, opts) {
|
|
313
350
|
const { collapsed, tab, query, cwdScope, residentsOnly, sort = 'tree' } = opts;
|
|
314
351
|
// 1. Directly-matched nodes: tab predicate AND cwd scope AND lifecycle AND query.
|
|
352
|
+
// `matched` honors the residents-only filter (drives top-level rows, ancestor
|
|
353
|
+
// context, force-expand, and the flat search results below). `matchedAll` is
|
|
354
|
+
// the same set WITHOUT the lifecycle gate — it's how a terminal node becomes
|
|
355
|
+
// visible once you expand the resident parent that owns it (the fold-reveal
|
|
356
|
+
// below), so residents-only de-clutters the top level + search yet still lets
|
|
357
|
+
// you drill into a fold and see everything under it.
|
|
315
358
|
const matched = new Set();
|
|
359
|
+
const matchedAll = new Set();
|
|
316
360
|
for (const [id, node] of tree.nodes) {
|
|
317
|
-
if (tabPredicate(tab, node.row) &&
|
|
318
|
-
|
|
319
|
-
lifecycleMatch(residentsOnly, node.row)
|
|
320
|
-
|
|
321
|
-
matched.add(id);
|
|
361
|
+
if (tabPredicate(tab, node.row) && cwdMatch(cwdScope, node.row) && queryMatch(query, node.row)) {
|
|
362
|
+
matchedAll.add(id);
|
|
363
|
+
if (lifecycleMatch(residentsOnly, node.row))
|
|
364
|
+
matched.add(id);
|
|
322
365
|
}
|
|
323
366
|
}
|
|
324
367
|
// FLAT ranked modes (relevance / recency): no tree, no ancestors — just the
|
|
@@ -328,7 +371,14 @@ export function flatten(tree, opts) {
|
|
|
328
371
|
const ids = [...matched];
|
|
329
372
|
const createdOf = (id) => tree.nodes.get(id)?.row.created ?? '';
|
|
330
373
|
const byRecency = (a, b) => createdOf(b).localeCompare(createdOf(a));
|
|
331
|
-
if (sort === '
|
|
374
|
+
if (sort === 'attention') {
|
|
375
|
+
// Tiered (attached/streaming/live first), newest-message-first within tier.
|
|
376
|
+
const rowOf = (id) => tree.nodes.get(id).row;
|
|
377
|
+
ids.sort((a, b) => (attentionTier(rowOf(a)) - attentionTier(rowOf(b))) ||
|
|
378
|
+
(attentionMtime(rowOf(b)) - attentionMtime(rowOf(a))) ||
|
|
379
|
+
byRecency(a, b));
|
|
380
|
+
}
|
|
381
|
+
else if (sort === 'recency' || query === '') {
|
|
332
382
|
ids.sort(byRecency);
|
|
333
383
|
}
|
|
334
384
|
else {
|
|
@@ -354,14 +404,19 @@ export function flatten(tree, opts) {
|
|
|
354
404
|
return true; // force-expand to reveal matches
|
|
355
405
|
return !collapsed.has(id);
|
|
356
406
|
};
|
|
357
|
-
// 3. Walk the tree in order, emitting
|
|
358
|
-
// expanded ones.
|
|
407
|
+
// 3. Walk the tree in order, emitting shown nodes and descending only into
|
|
408
|
+
// expanded ones. A node is shown when it is `included` (matched or ancestor),
|
|
409
|
+
// OR — under residents-only — when its already-shown parent is expanded and the
|
|
410
|
+
// node matches everything but the lifecycle gate (`matchedAll`). That is the
|
|
411
|
+
// fold-reveal: a terminal worker hidden from the top level reappears the moment
|
|
412
|
+
// you open the resident fold that owns it. `parentShown` threads that down.
|
|
359
413
|
const out = [];
|
|
360
|
-
const walk = (id) => {
|
|
414
|
+
const walk = (id, parentShown) => {
|
|
361
415
|
const node = tree.nodes.get(id);
|
|
362
416
|
if (node === undefined)
|
|
363
417
|
return;
|
|
364
|
-
|
|
418
|
+
const show = included(id) || (residentsOnly === true && parentShown && matchedAll.has(id));
|
|
419
|
+
if (show) {
|
|
365
420
|
const hasChildren = node.childIds.length > 0;
|
|
366
421
|
out.push({
|
|
367
422
|
id,
|
|
@@ -373,10 +428,10 @@ export function flatten(tree, opts) {
|
|
|
373
428
|
}
|
|
374
429
|
if (isExpanded(id)) {
|
|
375
430
|
for (const c of node.childIds)
|
|
376
|
-
walk(c);
|
|
431
|
+
walk(c, show);
|
|
377
432
|
}
|
|
378
433
|
};
|
|
379
434
|
for (const r of tree.roots)
|
|
380
|
-
walk(r);
|
|
435
|
+
walk(r, false);
|
|
381
436
|
return out;
|
|
382
437
|
}
|
|
@@ -2,7 +2,9 @@ import type { Tab, Tree, VisibleRow, SortMode } from './model.js';
|
|
|
2
2
|
import { detectColorCaps, type ColorCaps } from '../../tui/draw.js';
|
|
3
3
|
export { detectColorCaps };
|
|
4
4
|
export type { ColorCaps };
|
|
5
|
-
export declare const
|
|
5
|
+
export declare const PROMPT_LINES = 3;
|
|
6
|
+
export declare const REPLY_LINES = 3;
|
|
7
|
+
export declare const PREVIEW_BODY: number;
|
|
6
8
|
export declare const PREVIEW_HEIGHT: number;
|
|
7
9
|
export declare function headerHeight(search: boolean): number;
|
|
8
10
|
export interface RenderState {
|
|
@@ -23,6 +25,10 @@ export interface RenderState {
|
|
|
23
25
|
/** Lifecycle filter: when true, `terminal` (one-shot worker) nodes are hidden
|
|
24
26
|
* — surfaced as a status-line cue. */
|
|
25
27
|
residentsOnly: boolean;
|
|
28
|
+
/** When set, a close-out (`x`) is awaiting y/n confirmation because the node (or
|
|
29
|
+
* a descendant) is actively streaming. Holds the node id being confirmed; the
|
|
30
|
+
* footer becomes the y/n prompt. null/undefined = no pending confirm. */
|
|
31
|
+
pendingClose?: string | null;
|
|
26
32
|
}
|
|
27
33
|
/**
|
|
28
34
|
* Render the whole frame. Returns a single string that, written as-is, repaints
|