@crouton-kit/crouter 0.3.27 → 0.3.29
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.js +4 -2
- 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 +8 -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 +3 -3
- 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__/reconnect-giveup.test.js +30 -0
- package/dist/clients/attach/__tests__/slash-quit-copy.test.js +42 -0
- package/dist/clients/attach/__tests__/titled-editor.test.d.ts +1 -0
- package/dist/clients/attach/__tests__/titled-editor.test.js +39 -0
- package/dist/clients/attach/attach-cmd.js +445 -41
- 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 +12 -0
- package/dist/clients/attach/canvas-panels.js +78 -0
- 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 +43 -0
- package/dist/clients/attach/graph-overlay.js +306 -0
- package/dist/clients/attach/input-controller.d.ts +81 -13
- package/dist/clients/attach/input-controller.js +307 -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 +44 -1
- package/dist/clients/attach/slash-commands.js +250 -27
- 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 +37 -2
- package/dist/clients/attach/view-socket.js +131 -7
- 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 +1 -1
- package/dist/commands/dashboard.js +5 -1
- package/dist/commands/human/prompts.js +3 -3
- package/dist/commands/human/queue.d.ts +17 -0
- package/dist/commands/human/queue.js +111 -4
- package/dist/commands/memory/__tests__/lint-schema.test.js +27 -4
- package/dist/commands/memory/lint.d.ts +5 -4
- package/dist/commands/memory/lint.js +23 -7
- 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 +20 -7
- 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/feedback.d.ts +1 -0
- package/dist/commands/sys/feedback.js +163 -0
- package/dist/commands/sys/sync.d.ts +1 -0
- package/dist/commands/sys/sync.js +187 -0
- package/dist/commands/sys.js +4 -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__/broker-snapshot-history.test.d.ts +1 -0
- package/dist/core/__tests__/broker-snapshot-history.test.js +105 -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 +24 -1
- package/dist/core/__tests__/fixtures/fake-engine.js +32 -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__/human-stranded-deliver.test.d.ts +1 -0
- package/dist/core/__tests__/human-stranded-deliver.test.js +108 -0
- package/dist/core/__tests__/lifecycle.test.js +1 -19
- 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.d.ts +1 -0
- package/dist/core/__tests__/on-read-dedup-resume.test.js +81 -0
- 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.d.ts +162 -0
- package/dist/core/canvas/nav-model.js +487 -0
- package/dist/core/canvas/paths.d.ts +7 -0
- package/dist/core/canvas/paths.js +9 -0
- 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-sdk.d.ts +0 -12
- package/dist/core/runtime/broker-sdk.js +77 -6
- package/dist/core/runtime/broker.d.ts +5 -1
- package/dist/core/runtime/broker.js +520 -59
- package/dist/core/runtime/close.d.ts +12 -2
- package/dist/core/runtime/close.js +37 -16
- package/dist/core/runtime/front-door.js +14 -7
- 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 -334
- package/dist/core/runtime/placement.js +262 -828
- 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 +45 -135
- package/dist/core/runtime/spawn.d.ts +15 -11
- package/dist/core/runtime/spawn.js +168 -136
- 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 -43
- package/dist/core/runtime/tmux.js +38 -80
- 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/spawn.d.ts +14 -0
- package/dist/core/spawn.js +29 -9
- package/dist/core/substrate/index.d.ts +2 -2
- package/dist/core/substrate/index.js +7 -7
- package/dist/core/substrate/injected-store.d.ts +10 -0
- package/dist/core/substrate/injected-store.js +55 -0
- 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 +16 -11
- package/dist/core/substrate/schema.js +32 -31
- 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 +29 -20
- package/dist/pi-extensions/canvas-nav.js +35 -385
- 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 +15 -13
- package/dist/pi-extensions/canvas-stophook.js +119 -103
- 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 -221
- 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__/reconnect-giveup.test.d.ts} +0 -0
- /package/dist/{core/__tests__/relaunch.test.d.ts → clients/attach/__tests__/slash-quit-copy.test.d.ts} +0 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type Component, type TUI } from '@earendil-works/pi-tui';
|
|
2
|
+
import type { AttachPalette } from './config-load.js';
|
|
3
|
+
export declare class GraphOverlay implements Component {
|
|
4
|
+
private readonly tui;
|
|
5
|
+
private readonly self;
|
|
6
|
+
private readonly getAsks;
|
|
7
|
+
private readonly palette;
|
|
8
|
+
private handle;
|
|
9
|
+
/** Manual fold OVERRIDES (h collapses → userCollapsed, l expands → userExpanded);
|
|
10
|
+
* both override the default activity-driven policy and survive open/close. */
|
|
11
|
+
private readonly userExpanded;
|
|
12
|
+
private readonly userCollapsed;
|
|
13
|
+
private readonly folds;
|
|
14
|
+
/** Cursor as a node id (indices shift as topology changes). */
|
|
15
|
+
private cursorId;
|
|
16
|
+
/** Viewport scroll offset (row index of the top visible tree row). */
|
|
17
|
+
private scrollTop;
|
|
18
|
+
/** Transient y/n confirm gate (kill). */
|
|
19
|
+
private pendingConfirm;
|
|
20
|
+
constructor(tui: TUI, self: string, getAsks: () => Record<string, number>, palette: AttachPalette);
|
|
21
|
+
isOpen(): boolean;
|
|
22
|
+
open(): void;
|
|
23
|
+
close(): void;
|
|
24
|
+
toggle(): void;
|
|
25
|
+
/** Repaint if shown (the low-rate ask poll calls this). */
|
|
26
|
+
refresh(): void;
|
|
27
|
+
invalidate(): void;
|
|
28
|
+
render(width: number): string[];
|
|
29
|
+
/** A top/bottom border row: `<lc>─ <label> ────<rc>`, frame in the theme border
|
|
30
|
+
* color, the label keeping its own styling. The label is visible-truncated to
|
|
31
|
+
* the available span so a long label (a narrow pane, or a long `kill <name>?`
|
|
32
|
+
* confirm) never spills past the corner. */
|
|
33
|
+
private borderRow;
|
|
34
|
+
handleInput(data: string): void;
|
|
35
|
+
private dispatch;
|
|
36
|
+
/** Focus node `id` from the overlay by shelling `crtr node focus <id> --pane <here>`.
|
|
37
|
+
* Under the one-viewer-per-node model `--pane` is the ANCHOR to open beside: if
|
|
38
|
+
* `id` has no viewer yet a fresh one splits beside this pane; if it already has
|
|
39
|
+
* one, that viewer is navigated in place (this pane is left as-is). We pass
|
|
40
|
+
* TMUX_PANE explicitly so the anchor is THIS pane even if env resolution differs. */
|
|
41
|
+
private focusTarget;
|
|
42
|
+
private shellCrtr;
|
|
43
|
+
}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
// graph-overlay.ts — the alt+g GRAPH navigator overlay for `crtr attach` (Unit Q).
|
|
2
|
+
//
|
|
3
|
+
// Native reimplementation of canvas-nav.ts's GRAPH modal as a pi-tui OVERLAY
|
|
4
|
+
// (the viewer has no pi extension host). `tui.showOverlay(this, …)` mounts this
|
|
5
|
+
// Component as a BOUNDED, centered modal (~72% of the terminal, themed frame) and
|
|
6
|
+
// CAPTURES keyboard focus (mirrors extension-dialogs.ts);
|
|
7
|
+
// `OverlayHandle.hide()` tears it down and restores focus to the editor. While
|
|
8
|
+
// shown, every key routes to handleInput() — a fold-aware NERDTree of the local
|
|
9
|
+
// subscription graph with the canvas-nav keymap:
|
|
10
|
+
// j/k move · h/l fold/ascend-descend · g/G top/bottom · ↵ focus (swap into
|
|
11
|
+
// this pane) · m focus manager · x kill (y/n confirm) · esc close.
|
|
12
|
+
// `e` is a tmux-menu prefixBind, not a GRAPH key, so it is swallowed (per
|
|
13
|
+
// canvas-nav). All model/render comes from the shared nav-model layer; keys are
|
|
14
|
+
// decoded with pi-tui's canonical matchesKey (kitty/CSI-u aware).
|
|
15
|
+
//
|
|
16
|
+
// Enter/m/x SHELL `crtr` out-of-process (node focus / node close) — the viewer
|
|
17
|
+
// itself never spawns pi or opens a session (the §0 one-writer invariant). It
|
|
18
|
+
// passes its own pane as `crtr node focus --pane <anchor>`: under the
|
|
19
|
+
// one-viewer-per-node model the target's existing viewer is navigated in place,
|
|
20
|
+
// or a fresh viewer opens BESIDE this pane — never a second pane for the same node.
|
|
21
|
+
import { execFile } from 'node:child_process';
|
|
22
|
+
import { matchesKey, truncateToWidth } from '@earendil-works/pi-tui';
|
|
23
|
+
import { fullName } from '../../core/canvas/index.js';
|
|
24
|
+
import { beginFrame, cNode, managerOf, sortedChildIds, climbRoot, computeSubtreeActivity, buildGraphModel, renderGraphRow, focusedNodeIds, shortId, visibleWidth, VIEWPORT_FALLBACK_ROWS, DIM, RESET, BOLD, YELLOW, } from '../../core/canvas/nav-model.js';
|
|
25
|
+
// A BOUNDED, centered modal (CTO ruling: not full-bleed). Width/height are capped
|
|
26
|
+
// at ~72% of the terminal; the overlay clips our lines to maxHeight, and render()
|
|
27
|
+
// budgets the panel to the SAME fraction (HEIGHT_PCT) so the framed box is never
|
|
28
|
+
// clipped. margin keeps it off the screen edges.
|
|
29
|
+
const HEIGHT_PCT = 0.72;
|
|
30
|
+
const OVERLAY_OPTIONS = { anchor: 'center', width: '72%', minWidth: 48, maxHeight: '72%', margin: 1 };
|
|
31
|
+
// Viewer-specific hint: nav-model's shared GRAPH_HINT advertises "e expand",
|
|
32
|
+
// but that key is the tmux pane-expand prefix-bind canvas-nav installs in its
|
|
33
|
+
// host pane — the attach overlay has no such bind and swallows `e`, so the key
|
|
34
|
+
// would do nothing here. Drop it.
|
|
35
|
+
const GRAPH_HINT = `${DIM}jk move · hl fold · ↵ focus · x kill · m mgr · esc${RESET}`;
|
|
36
|
+
export class GraphOverlay {
|
|
37
|
+
tui;
|
|
38
|
+
self;
|
|
39
|
+
getAsks;
|
|
40
|
+
palette;
|
|
41
|
+
handle;
|
|
42
|
+
/** Manual fold OVERRIDES (h collapses → userCollapsed, l expands → userExpanded);
|
|
43
|
+
* both override the default activity-driven policy and survive open/close. */
|
|
44
|
+
userExpanded = new Set();
|
|
45
|
+
userCollapsed = new Set();
|
|
46
|
+
folds = { userExpanded: this.userExpanded, userCollapsed: this.userCollapsed };
|
|
47
|
+
/** Cursor as a node id (indices shift as topology changes). */
|
|
48
|
+
cursorId;
|
|
49
|
+
/** Viewport scroll offset (row index of the top visible tree row). */
|
|
50
|
+
scrollTop = 0;
|
|
51
|
+
/** Transient y/n confirm gate (kill). */
|
|
52
|
+
pendingConfirm;
|
|
53
|
+
constructor(tui, self, getAsks, palette) {
|
|
54
|
+
this.tui = tui;
|
|
55
|
+
this.self = self;
|
|
56
|
+
this.getAsks = getAsks;
|
|
57
|
+
this.palette = palette;
|
|
58
|
+
}
|
|
59
|
+
isOpen() {
|
|
60
|
+
return this.handle !== undefined;
|
|
61
|
+
}
|
|
62
|
+
open() {
|
|
63
|
+
if (this.handle !== undefined)
|
|
64
|
+
return;
|
|
65
|
+
this.scrollTop = 0;
|
|
66
|
+
this.pendingConfirm = undefined;
|
|
67
|
+
if (this.cursorId === undefined || cNode(this.cursorId) === null)
|
|
68
|
+
this.cursorId = this.self;
|
|
69
|
+
this.handle = this.tui.showOverlay(this, OVERLAY_OPTIONS);
|
|
70
|
+
this.tui.requestRender();
|
|
71
|
+
}
|
|
72
|
+
close() {
|
|
73
|
+
if (this.handle === undefined)
|
|
74
|
+
return;
|
|
75
|
+
this.pendingConfirm = undefined;
|
|
76
|
+
this.handle.hide();
|
|
77
|
+
this.handle = undefined;
|
|
78
|
+
this.tui.requestRender();
|
|
79
|
+
}
|
|
80
|
+
toggle() {
|
|
81
|
+
if (this.handle === undefined)
|
|
82
|
+
this.open();
|
|
83
|
+
else
|
|
84
|
+
this.close();
|
|
85
|
+
}
|
|
86
|
+
/** Repaint if shown (the low-rate ask poll calls this). */
|
|
87
|
+
refresh() {
|
|
88
|
+
if (this.handle !== undefined)
|
|
89
|
+
this.tui.requestRender();
|
|
90
|
+
}
|
|
91
|
+
invalidate() {
|
|
92
|
+
/* no cached render state — rebuilt every render() */
|
|
93
|
+
}
|
|
94
|
+
// -------------------------------------------------------------------------
|
|
95
|
+
render(width) {
|
|
96
|
+
// Fresh snapshot per paint (mirror canvas-nav's per-frame cache).
|
|
97
|
+
beginFrame();
|
|
98
|
+
const asks = this.getAsks();
|
|
99
|
+
const activity = computeSubtreeActivity(climbRoot(this.self), this.self);
|
|
100
|
+
const rows = buildGraphModel(this.self, this.folds, activity.expand);
|
|
101
|
+
// Re-resolve the cursor id → row (it may have vanished under a fold/close).
|
|
102
|
+
let cursorIdx = rows.findIndex((r) => r.id === this.cursorId);
|
|
103
|
+
if (cursorIdx < 0) {
|
|
104
|
+
cursorIdx = rows.findIndex((r) => r.id === this.self);
|
|
105
|
+
if (cursorIdx < 0)
|
|
106
|
+
cursorIdx = 0;
|
|
107
|
+
}
|
|
108
|
+
this.cursorId = rows[cursorIdx]?.id ?? this.self;
|
|
109
|
+
// Bounded panel budget (centered modal, not full-bleed): the box height
|
|
110
|
+
// shrinks to content but is capped at HEIGHT_PCT of the terminal — matching
|
|
111
|
+
// the overlay's maxHeight so our framed lines are never clipped. 2 rows go to
|
|
112
|
+
// the top/bottom border, the rest to tree rows.
|
|
113
|
+
const term = process.stdout.rows ?? VIEWPORT_FALLBACK_ROWS;
|
|
114
|
+
// Never exceed the overlay's own maxHeight (term-2 after the margin), so the
|
|
115
|
+
// bottom border is never slice-clipped even on a very short terminal.
|
|
116
|
+
const maxPanelH = Math.max(3, Math.min(Math.floor(term * HEIGHT_PCT), term - 2));
|
|
117
|
+
const treeArea = Math.max(2, Math.min(rows.length, maxPanelH - 2));
|
|
118
|
+
// Track the cursor within treeArea, reserving ↑/↓ "more" indicators. Up to
|
|
119
|
+
// 4 passes converge the mutual dependency between window size and indicators
|
|
120
|
+
// (an indicator steals a tree row → can re-home scrollTop → toggles the other
|
|
121
|
+
// indicator); see canvas-nav.ts renderGraph for the rationale.
|
|
122
|
+
let viewportH = treeArea;
|
|
123
|
+
for (let pass = 0; pass < 4; pass++) {
|
|
124
|
+
if (cursorIdx < this.scrollTop)
|
|
125
|
+
this.scrollTop = cursorIdx;
|
|
126
|
+
if (cursorIdx >= this.scrollTop + viewportH)
|
|
127
|
+
this.scrollTop = cursorIdx - viewportH + 1;
|
|
128
|
+
this.scrollTop = Math.max(0, Math.min(this.scrollTop, Math.max(0, rows.length - viewportH)));
|
|
129
|
+
const fit = treeArea - (this.scrollTop > 0 ? 1 : 0) - (this.scrollTop + viewportH < rows.length ? 1 : 0);
|
|
130
|
+
if (fit === viewportH)
|
|
131
|
+
break;
|
|
132
|
+
viewportH = Math.max(1, fit);
|
|
133
|
+
}
|
|
134
|
+
const end = Math.min(rows.length, this.scrollTop + viewportH);
|
|
135
|
+
const focused = focusedNodeIds();
|
|
136
|
+
const body = [];
|
|
137
|
+
if (this.scrollTop > 0)
|
|
138
|
+
body.push(`${DIM} ↑ ${this.scrollTop} more${RESET}`);
|
|
139
|
+
for (let i = this.scrollTop; i < end; i++) {
|
|
140
|
+
body.push(renderGraphRow(rows[i], i === cursorIdx, focused, activity.activeBelow, asks));
|
|
141
|
+
}
|
|
142
|
+
if (end < rows.length)
|
|
143
|
+
body.push(`${DIM} ↓ ${rows.length - end} more${RESET}`);
|
|
144
|
+
while (body.length < treeArea)
|
|
145
|
+
body.push(''); // fill so the overlay is opaque
|
|
146
|
+
const title = `${BOLD}⌗ canvas graph${RESET} ${DIM}(${cursorIdx + 1}/${rows.length})${RESET}`;
|
|
147
|
+
const hint = this.pendingConfirm !== undefined
|
|
148
|
+
? `${YELLOW}${this.pendingConfirm.label} ${BOLD}y/n${RESET}`
|
|
149
|
+
: GRAPH_HINT;
|
|
150
|
+
// Frame the panel: title in the top border, hint in the bottom border, tree
|
|
151
|
+
// rows boxed with themed side bars (truncate/pad to the inner width so the
|
|
152
|
+
// right edge stays flush and opaque).
|
|
153
|
+
const B = this.palette.border;
|
|
154
|
+
const innerW = Math.max(1, width - 4); // "│ " + content + " │"
|
|
155
|
+
// Hard-cut (empty ellipsis) + pad to innerW: ANSI-aware, so the cursor fill
|
|
156
|
+
// bar reaches the right border flush with no stray "…" and the box edge is
|
|
157
|
+
// opaque.
|
|
158
|
+
const boxed = body.map((line) => `${B('│')} ${truncateToWidth(line, innerW, '', true)} ${B('│')}`);
|
|
159
|
+
// Paint the WHOLE modal — border rows + boxed body + opaque space-fill — on
|
|
160
|
+
// the theme's distinct-surface background (selectedBg) so the float reads as
|
|
161
|
+
// a separate surface, not a hole in the viewer behind it (CTO ruling).
|
|
162
|
+
const S = this.palette.surface;
|
|
163
|
+
return [
|
|
164
|
+
this.borderRow('╭', '╮', title, width),
|
|
165
|
+
...boxed,
|
|
166
|
+
this.borderRow('╰', '╯', hint, width),
|
|
167
|
+
].map(S);
|
|
168
|
+
}
|
|
169
|
+
/** A top/bottom border row: `<lc>─ <label> ────<rc>`, frame in the theme border
|
|
170
|
+
* color, the label keeping its own styling. The label is visible-truncated to
|
|
171
|
+
* the available span so a long label (a narrow pane, or a long `kill <name>?`
|
|
172
|
+
* confirm) never spills past the corner. */
|
|
173
|
+
borderRow(lc, rc, label, width) {
|
|
174
|
+
const B = this.palette.border;
|
|
175
|
+
const span = Math.max(1, width - 5); // lc ─ _ <span> _ ─… rc
|
|
176
|
+
const lbl = truncateToWidth(label, span, '…');
|
|
177
|
+
const fill = Math.max(0, width - 5 - visibleWidth(lbl));
|
|
178
|
+
return `${B(`${lc}─`)} ${lbl} ${B('─'.repeat(fill) + rc)}`;
|
|
179
|
+
}
|
|
180
|
+
// -------------------------------------------------------------------------
|
|
181
|
+
handleInput(data) {
|
|
182
|
+
try {
|
|
183
|
+
this.dispatch(data);
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
/* a key handler is best-effort; never throw out of the input pump */
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
dispatch(data) {
|
|
190
|
+
// y/n confirm gate takes precedence over everything.
|
|
191
|
+
if (this.pendingConfirm !== undefined) {
|
|
192
|
+
if (matchesKey(data, 'y')) {
|
|
193
|
+
const act = this.pendingConfirm.action;
|
|
194
|
+
this.pendingConfirm = undefined;
|
|
195
|
+
act();
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
this.pendingConfirm = undefined; // any other key cancels
|
|
199
|
+
}
|
|
200
|
+
this.tui.requestRender();
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (matchesKey(data, 'escape')) {
|
|
204
|
+
this.close();
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const rows = buildGraphModel(this.self, this.folds);
|
|
208
|
+
let idx = rows.findIndex((r) => r.id === this.cursorId);
|
|
209
|
+
if (idx < 0)
|
|
210
|
+
idx = Math.max(0, rows.findIndex((r) => r.id === this.self));
|
|
211
|
+
const cur = rows[idx];
|
|
212
|
+
if (matchesKey(data, 'j')) {
|
|
213
|
+
idx = Math.min(rows.length - 1, idx + 1);
|
|
214
|
+
this.cursorId = rows[idx]?.id ?? this.cursorId;
|
|
215
|
+
this.tui.requestRender();
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (matchesKey(data, 'k')) {
|
|
219
|
+
idx = Math.max(0, idx - 1);
|
|
220
|
+
this.cursorId = rows[idx]?.id ?? this.cursorId;
|
|
221
|
+
this.tui.requestRender();
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (matchesKey(data, 'g')) {
|
|
225
|
+
this.cursorId = rows[0]?.id ?? this.cursorId;
|
|
226
|
+
this.tui.requestRender();
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
if (matchesKey(data, 'shift+g')) {
|
|
230
|
+
this.cursorId = rows[rows.length - 1]?.id ?? this.cursorId;
|
|
231
|
+
this.tui.requestRender();
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (matchesKey(data, 'h')) {
|
|
235
|
+
if (cur !== undefined && cur.hasKids && !cur.collapsed) {
|
|
236
|
+
this.userCollapsed.add(cur.id);
|
|
237
|
+
this.userExpanded.delete(cur.id);
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
const p = managerOf(this.cursorId ?? this.self);
|
|
241
|
+
if (p !== undefined && rows.some((r) => r.id === p))
|
|
242
|
+
this.cursorId = p;
|
|
243
|
+
}
|
|
244
|
+
this.tui.requestRender();
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (matchesKey(data, 'l')) {
|
|
248
|
+
if (cur !== undefined && cur.collapsed && cur.hasKids) {
|
|
249
|
+
this.userExpanded.add(cur.id);
|
|
250
|
+
this.userCollapsed.delete(cur.id);
|
|
251
|
+
}
|
|
252
|
+
else if (cur !== undefined && cur.hasKids) {
|
|
253
|
+
const c = sortedChildIds(cur.id)[0];
|
|
254
|
+
if (c !== undefined)
|
|
255
|
+
this.cursorId = c;
|
|
256
|
+
}
|
|
257
|
+
this.tui.requestRender();
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (matchesKey(data, 'enter')) {
|
|
261
|
+
if (this.cursorId !== undefined)
|
|
262
|
+
this.focusTarget(this.cursorId);
|
|
263
|
+
this.close();
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (matchesKey(data, 'm')) {
|
|
267
|
+
const mgr = managerOf(this.self);
|
|
268
|
+
if (mgr !== undefined) {
|
|
269
|
+
this.focusTarget(mgr);
|
|
270
|
+
this.close();
|
|
271
|
+
}
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (matchesKey(data, 'x')) {
|
|
275
|
+
const target = this.cursorId ?? this.self;
|
|
276
|
+
const n = cNode(target);
|
|
277
|
+
const nm = n !== null ? fullName(n) : shortId(target);
|
|
278
|
+
this.pendingConfirm = { label: `kill ${nm}?`, action: () => this.shellCrtr(['node', 'close', '--node', target]) };
|
|
279
|
+
this.tui.requestRender();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
// Modal: swallow everything else (incl. the `e` tmux-menu bind) so a stray
|
|
283
|
+
// key never reaches the editor underneath.
|
|
284
|
+
}
|
|
285
|
+
// -------------------------------------------------------------------------
|
|
286
|
+
/** Focus node `id` from the overlay by shelling `crtr node focus <id> --pane <here>`.
|
|
287
|
+
* Under the one-viewer-per-node model `--pane` is the ANCHOR to open beside: if
|
|
288
|
+
* `id` has no viewer yet a fresh one splits beside this pane; if it already has
|
|
289
|
+
* one, that viewer is navigated in place (this pane is left as-is). We pass
|
|
290
|
+
* TMUX_PANE explicitly so the anchor is THIS pane even if env resolution differs. */
|
|
291
|
+
focusTarget(id) {
|
|
292
|
+
const argv = ['node', 'focus', id];
|
|
293
|
+
const pane = process.env['TMUX_PANE'];
|
|
294
|
+
if (pane !== undefined && pane !== '')
|
|
295
|
+
argv.push('--pane', pane);
|
|
296
|
+
this.shellCrtr(argv);
|
|
297
|
+
}
|
|
298
|
+
shellCrtr(argv) {
|
|
299
|
+
try {
|
|
300
|
+
execFile('crtr', argv, () => { });
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
/* best-effort */
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { CustomEditor } from '@earendil-works/pi-coding-agent';
|
|
2
|
-
import type { KeybindingsManager, TUI } from '@earendil-works/pi-tui';
|
|
3
|
-
import { type BrokerSnapshot, type ClientToBroker, type RpcExtensionUIRequest, type RpcExtensionUIResponse } from '../../core/runtime/broker-protocol.js';
|
|
2
|
+
import type { Component, KeybindingsManager, TUI } from '@earendil-works/pi-tui';
|
|
3
|
+
import { type BrokerDataFrame, type BrokerSnapshot, type ClientToBroker, type RpcExtensionUIRequest, type RpcExtensionUIResponse } from '../../core/runtime/broker-protocol.js';
|
|
4
|
+
import type { ReadOpRequest } from './view-socket.js';
|
|
5
|
+
import { type Picker, type PickerControls } from './pickers.js';
|
|
4
6
|
export interface InputControllerHooks {
|
|
5
7
|
/** Send a command frame to the broker. */
|
|
6
8
|
onCommand: (frame: ClientToBroker) => void;
|
|
@@ -11,20 +13,56 @@ export interface InputControllerHooks {
|
|
|
11
13
|
* reports notices up the same way it reports commands. Absent → notices are
|
|
12
14
|
* dropped silently. */
|
|
13
15
|
onNotice?: (message: string) => void;
|
|
16
|
+
/** OPTIONAL: the canvas node this viewer is attached to — forwarded to the
|
|
17
|
+
* slash context so `/promote` targets it (Unit Q wires it from runAttach). */
|
|
18
|
+
nodeId?: string;
|
|
19
|
+
/** OPTIONAL: toggle the GRAPH overlay — forwarded to the slash context so
|
|
20
|
+
* `/graph` opens/closes it (Unit Q wires it from runAttach). */
|
|
21
|
+
onGraph?: () => void;
|
|
22
|
+
/** OPTIONAL: detach the viewer — forwarded to the slash context so `/quit`
|
|
23
|
+
* tears down the TUI/socket (the engine keeps running). Wired by attach-cmd. */
|
|
24
|
+
onQuit?: () => void;
|
|
25
|
+
/** OPTIONAL: copy the last assistant message to the clipboard — forwarded to
|
|
26
|
+
* the slash context so `/copy` works. Wired by attach-cmd (it owns ChatView). */
|
|
27
|
+
onCopy?: () => void;
|
|
28
|
+
/** OPTIONAL: Ctrl+O / app.tools.expand — flip global tool-output expansion in
|
|
29
|
+
* the render layer (ChatView owns the components). Absent → the key no-ops. */
|
|
30
|
+
onToggleToolsExpand?: () => void;
|
|
31
|
+
/** OPTIONAL: Ctrl+T / app.thinking.toggle — flip thinking-block visibility in
|
|
32
|
+
* the render layer. Absent → the key no-ops. */
|
|
33
|
+
onToggleThinking?: () => void;
|
|
34
|
+
/** OPTIONAL: issue a correlated read-op and resolve with the broker's `data`
|
|
35
|
+
* reply. MUST be wired by attach-cmd (`onRequest: (f) => socket.request(f)`)
|
|
36
|
+
* for the native pickers to work; when absent every picker degrades to a
|
|
37
|
+
* text-arg notice. */
|
|
38
|
+
onRequest?: (frame: ReadOpRequest) => Promise<BrokerDataFrame>;
|
|
39
|
+
/** OPTIONAL pair: mount/unmount a native picker INLINE in the viewer's layout
|
|
40
|
+
* (attach-cmd slots it directly under the editor). When BOTH are wired,
|
|
41
|
+
* showPicker uses them instead of a centered overlay; absent → overlay
|
|
42
|
+
* fallback. The controller stays layout-agnostic either way (T5/T7 own it). */
|
|
43
|
+
onMountPicker?: (component: Component) => void;
|
|
44
|
+
onUnmountPicker?: () => void;
|
|
45
|
+
/** OPTIONAL: open the native /login provider picker (viewer-local auth flow). */
|
|
46
|
+
openLoginPicker?: () => void;
|
|
47
|
+
/** OPTIONAL: open the native /logout provider picker (viewer-local auth flow). */
|
|
48
|
+
openLogoutPicker?: () => void;
|
|
14
49
|
}
|
|
15
50
|
export declare class InputController {
|
|
16
51
|
private readonly tui;
|
|
17
52
|
private readonly editor;
|
|
18
53
|
private readonly keybindings;
|
|
19
54
|
private readonly hooks;
|
|
20
|
-
/** Images pasted since the last send, attached to the next prompt/follow-up. */
|
|
21
|
-
private pendingImages;
|
|
22
|
-
/** Running base64-byte total of `pendingImages` (review M2 aggregate budget). */
|
|
23
|
-
private pendingImageBytes;
|
|
24
55
|
/** The currently-rendered blocking dialog, if any (for supersede/dismiss). */
|
|
25
56
|
private dialog;
|
|
57
|
+
/** The currently-open native picker overlay, if any (for supersede/dismiss). */
|
|
58
|
+
private picker;
|
|
59
|
+
/** Monotonic open counter — a slow read-op reply whose `seq` is no longer the
|
|
60
|
+
* latest is dropped, so an earlier picker never pops over a later request. */
|
|
61
|
+
private openSeq;
|
|
26
62
|
/** Latest engine state from `welcome`/`session_info_changed` (for `/session`). */
|
|
27
63
|
private state;
|
|
64
|
+
/** Timestamp of the last lone Esc, for double-tap → tree detection (0 = none). */
|
|
65
|
+
private lastEscapeAt;
|
|
28
66
|
constructor(tui: TUI, editor: CustomEditor, keybindings: KeybindingsManager, hooks: InputControllerHooks);
|
|
29
67
|
/** Render a blocking extension dialog and route its answer to the broker.
|
|
30
68
|
* Supersedes any dialog already on screen (e.g. a re-route on control
|
|
@@ -35,20 +73,50 @@ export declare class InputController {
|
|
|
35
73
|
setState(state: BrokerSnapshot['state']): void;
|
|
36
74
|
private wire;
|
|
37
75
|
private slashContext;
|
|
76
|
+
/** Send a command frame to the broker (picker selection sink). */
|
|
77
|
+
private send;
|
|
78
|
+
/** Fetch a picker payload (narrowed on `kind`), then build + show its overlay
|
|
79
|
+
* iff this open is still the latest (m4: a stale slow reply is dropped). Any
|
|
80
|
+
* failure — unwired channel, wrong kind, request error, or a throwing builder
|
|
81
|
+
* — surfaces a notice instead of an unhandled rejection (m5). */
|
|
82
|
+
private openPicker;
|
|
83
|
+
/** Show a picker built by `build` (given a `close` that tears it down).
|
|
84
|
+
* Mounted INLINE under the editor when attach-cmd wires onMountPicker/
|
|
85
|
+
* onUnmountPicker (the integrated chrome path); otherwise falls back to a
|
|
86
|
+
* centered overlay. Supersedes any picker already on screen. Routes focus to
|
|
87
|
+
* the builder's declared focus target (an inner list for fork/settings) and
|
|
88
|
+
* ALWAYS restores editor focus on close — `OverlayHandle.hide()` only
|
|
89
|
+
* auto-restores when the OUTER component held focus, which is not the case
|
|
90
|
+
* once we focus an inner child. A throwing builder is caught into a notice (m5). */
|
|
91
|
+
private showPicker;
|
|
92
|
+
private openModelPicker;
|
|
93
|
+
private openSessionPicker;
|
|
94
|
+
private openTreePicker;
|
|
95
|
+
private openForkPicker;
|
|
96
|
+
private openSettingsPicker;
|
|
97
|
+
private openScopedModelsPicker;
|
|
98
|
+
/** Open a viewer-local auth picker (login/logout) — uses the same showPicker
|
|
99
|
+
* machinery as read-op pickers, but with a locally-built component (no read-op
|
|
100
|
+
* request; auth operations are viewer-local in tmux-local attach). */
|
|
101
|
+
openAuthPicker(build: (controls: PickerControls) => Picker): void;
|
|
38
102
|
private handleSubmit;
|
|
39
103
|
private handleFollowUp;
|
|
104
|
+
/** Ctrl+G / app.editor.external — open the current editor text in $VISUAL/$EDITOR
|
|
105
|
+
* and load the saved result back. Ported from pi's `openExternalEditor`: stop
|
|
106
|
+
* the TUI to release the terminal, run the editor with inherited stdio, and on
|
|
107
|
+
* a clean exit (status 0) replace the editor text; the socket keeps running in
|
|
108
|
+
* the background throughout. */
|
|
109
|
+
private openExternalEditor;
|
|
110
|
+
/** Alt+Up / app.message.dequeue — clear the broker's queued steering + follow-up
|
|
111
|
+
* messages and restore them to the editor, prepended to any in-progress text
|
|
112
|
+
* (pi's `restoreQueuedMessagesToEditor`: queued text first, joined by blank
|
|
113
|
+
* lines). A read-AND-mutate op over the correlated request channel. */
|
|
114
|
+
private handleDequeue;
|
|
40
115
|
/** Send a drive frame iff the WHOLE encoded frame fits under MAX_FRAME_BYTES
|
|
41
116
|
* (the broker destroys the socket on any line over its 24 MiB read cap). Over
|
|
42
117
|
* the ceiling → notify + refuse so the caller leaves the editor + pending
|
|
43
118
|
* images intact for the user to trim, never a socket-destroying overflow. */
|
|
44
119
|
private emitDrive;
|
|
45
120
|
private handlePaste;
|
|
46
|
-
/** Snapshot the pending images as an `images?` payload (undefined when none)
|
|
47
|
-
* WITHOUT clearing — so a frame refused by `emitDrive` (too large) keeps them
|
|
48
|
-
* for the user to trim. The caller clears via `clearPendingImages` only after a
|
|
49
|
-
* successful send. */
|
|
50
|
-
private pendingImagesPayload;
|
|
51
|
-
/** Drop all pending images + reset the aggregate byte counter (after a send). */
|
|
52
|
-
private clearPendingImages;
|
|
53
121
|
private notify;
|
|
54
122
|
}
|