@north-light/crouter 0.3.170 → 0.3.172
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/api/client.d.ts +37 -11
- package/dist/api/client.js +84 -15
- package/dist/api/dto/human.d.ts +53 -39
- package/dist/api/dto/human.js +2 -3
- package/dist/api/dto/inbox.d.ts +0 -1
- package/dist/api/dto/nodes.d.ts +12 -0
- package/dist/api/dto/review-comments.d.ts +137 -0
- package/dist/api/dto/review-comments.js +5 -0
- package/dist/api/dto/reviews.d.ts +109 -0
- package/dist/api/dto/reviews.js +5 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +2 -0
- package/dist/api/routes.d.ts +17 -4
- package/dist/api/routes.js +21 -5
- package/dist/build-root.d.ts +1 -16
- package/dist/build-root.js +1 -25
- package/dist/builtin-memory/00-runtime-base.md +7 -5
- package/dist/builtin-memory/04-base-worker.md +1 -1
- package/dist/builtin-memory/04-orchestration-kernel.md +7 -7
- package/dist/builtin-memory/05-kinds/design/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/design/01-orchestrator.md +1 -1
- package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/explore/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/plan/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +1 -1
- package/dist/builtin-memory/05-kinds/review/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/review/companion/00-base.md +20 -0
- package/dist/builtin-memory/05-kinds/spec/00-base.md +3 -7
- package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +3 -3
- package/dist/builtin-memory/05-kinds/spec/requirements.md +3 -3
- package/dist/builtin-memory/design.md +2 -2
- package/dist/builtin-memory/insights/capture.md +50 -0
- package/dist/builtin-memory/insights/init.md +45 -0
- package/dist/builtin-memory/insights/listen.md +9 -0
- package/dist/builtin-memory/internal/agent-shaping.md +2 -2
- package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
- package/dist/builtin-memory/internal/plugins.md +12 -11
- package/dist/builtin-memory/internal/storage-tiers.md +2 -2
- package/dist/builtin-memory/{planning.md → plan/roadmap.md} +3 -3
- package/dist/builtin-memory/plan.md +19 -0
- package/dist/builtin-memory/spec/guide.md +38 -0
- package/dist/builtin-memory/spec/requirements.md +31 -0
- package/dist/builtin-memory/spec/roadmap.md +35 -0
- package/dist/builtin-memory/spec.md +10 -86
- package/dist/builtin-pi-packages/pi-crtr-extensions/README.md +3 -4
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/provider-rotation.test.ts +49 -5
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +56 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +920 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +221 -156
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +4 -5
- package/dist/cli.js +2 -6
- package/dist/clients/attach/__tests__/attach-chrome-remote.test.js +7 -35
- package/dist/clients/attach/__tests__/attach-keybindings.test.js +32 -16
- package/dist/clients/attach/__tests__/context-message.test.js +142 -6
- package/dist/clients/attach/__tests__/crtr-output.test.js +29 -45
- package/dist/clients/attach/__tests__/diagram.test.js +1 -1
- package/dist/clients/attach/__tests__/file-review-focus.test.js +48 -0
- package/dist/clients/attach/__tests__/group-activity.test.js +266 -0
- package/dist/clients/attach/__tests__/input-controller-extension-command.test.js +32 -0
- package/dist/clients/attach/__tests__/session-identity-refresh.test.js +32 -0
- package/dist/clients/attach/__tests__/titled-editor-preview.test.js +1 -2
- package/dist/clients/attach/chrome/header.d.ts +10 -0
- package/dist/clients/attach/chrome/header.js +30 -0
- package/dist/clients/attach/chrome/recap.d.ts +7 -0
- package/dist/clients/attach/chrome/recap.js +19 -0
- package/dist/clients/attach/chrome/status-line.d.ts +3 -0
- package/dist/clients/attach/chrome/status-line.js +5 -0
- package/dist/clients/attach/chrome/widgets.js +11 -21
- package/dist/clients/attach/command.js +11 -7
- package/dist/clients/attach/config.d.ts +4 -0
- package/dist/clients/attach/config.js +3 -0
- package/dist/clients/attach/input/controller.d.ts +19 -0
- package/dist/clients/attach/input/controller.js +62 -28
- package/dist/clients/attach/input/titled-editor.d.ts +0 -4
- package/dist/clients/attach/input/titled-editor.js +2 -10
- package/dist/clients/attach/overlays/file-review.d.ts +9 -5
- package/dist/clients/attach/overlays/file-review.js +9 -70
- package/dist/clients/attach/overlays/help.d.ts +33 -0
- package/dist/clients/attach/overlays/help.js +204 -0
- package/dist/clients/attach/render/activity-slot.d.ts +4 -0
- package/dist/clients/attach/render/activity-slot.js +13 -0
- package/dist/clients/attach/render/chat-view.d.ts +117 -12
- package/dist/clients/attach/render/chat-view.js +604 -135
- package/dist/clients/attach/render/context-message.d.ts +2 -1
- package/dist/clients/attach/render/context-message.js +17 -13
- package/dist/clients/attach/render/crtr-output.js +1 -3
- package/dist/clients/attach/render/diagram.js +2 -2
- package/dist/clients/attach/render/edit-diff.d.ts +4 -1
- package/dist/clients/attach/render/edit-diff.js +7 -11
- package/dist/clients/attach/render/group-activity.d.ts +32 -0
- package/dist/clients/attach/render/group-activity.js +206 -0
- package/dist/clients/attach/render/group-recap.d.ts +10 -0
- package/dist/clients/attach/render/group-recap.js +93 -0
- package/dist/clients/attach/render/html-markdown.d.ts +17 -0
- package/dist/clients/attach/render/html-markdown.js +228 -0
- package/dist/clients/attach/render/measured-container.d.ts +96 -0
- package/dist/clients/attach/render/measured-container.js +322 -0
- package/dist/clients/attach/render/scroll-animation.d.ts +8 -0
- package/dist/clients/attach/render/scroll-animation.js +80 -0
- package/dist/clients/attach/render/tool-calls.js +6 -6
- package/dist/clients/attach/render/transcript-copy.d.ts +9 -0
- package/dist/clients/attach/render/transcript-copy.js +81 -0
- package/dist/clients/attach/render/viewport.d.ts +29 -0
- package/dist/clients/attach/render/viewport.js +159 -0
- package/dist/clients/attach/session/bindings.d.ts +10 -7
- package/dist/clients/attach/session/bindings.js +23 -8
- package/dist/clients/attach/session/connection.js +4 -5
- package/dist/clients/attach/session/context.d.ts +6 -4
- package/dist/clients/attach/session/frame.d.ts +34 -0
- package/dist/clients/attach/session/frame.js +176 -0
- package/dist/clients/attach/session/frames.d.ts +4 -1
- package/dist/clients/attach/session/frames.js +14 -1
- package/dist/clients/attach/session/identity.js +4 -3
- package/dist/clients/attach/session/input-wiring.d.ts +14 -4
- package/dist/clients/attach/session/input-wiring.js +15 -13
- package/dist/clients/attach/session/invariant.d.ts +9 -0
- package/dist/clients/attach/session/invariant.js +15 -0
- package/dist/clients/attach/session/keys.d.ts +10 -2
- package/dist/clients/attach/session/keys.js +13 -5
- package/dist/clients/attach/session/layout.d.ts +10 -8
- package/dist/clients/attach/session/layout.js +33 -34
- package/dist/clients/attach/session/mouse.d.ts +18 -0
- package/dist/clients/attach/session/mouse.js +64 -0
- package/dist/clients/attach/session/pane-tag.d.ts +3 -0
- package/dist/clients/attach/session/pane-tag.js +51 -8
- package/dist/clients/attach/session/reconnect.d.ts +3 -0
- package/dist/clients/attach/session/reconnect.js +42 -5
- package/dist/clients/attach/session/surface-frame.d.ts +20 -0
- package/dist/clients/attach/session/surface-frame.js +73 -0
- package/dist/clients/attach/session/surface-host.d.ts +64 -0
- package/dist/clients/attach/session/surface-host.js +255 -0
- package/dist/clients/attach/session/whip.d.ts +17 -0
- package/dist/clients/attach/session/whip.js +334 -0
- package/dist/clients/attach/slash/dispatch.d.ts +13 -1
- package/dist/clients/attach/slash/dispatch.js +51 -29
- package/dist/clients/attach/viewer.js +907 -819
- package/dist/clients/conversation/conversation.d.ts +65 -0
- package/dist/clients/conversation/conversation.js +318 -0
- package/dist/clients/conversation/frames.d.ts +30 -0
- package/dist/clients/conversation/frames.js +52 -0
- package/dist/clients/conversation/region.d.ts +51 -0
- package/dist/clients/conversation/region.js +265 -0
- package/dist/clients/conversation/submit.d.ts +38 -0
- package/dist/clients/conversation/submit.js +51 -0
- package/dist/clients/inbox/__tests__/inbox-controller.test.js +247 -0
- package/dist/clients/inbox/__tests__/mount-panel.test.js +776 -0
- package/dist/clients/inbox/controller.d.ts +79 -0
- package/dist/clients/inbox/controller.js +448 -0
- package/dist/clients/inbox/deck-adapter.d.ts +29 -0
- package/dist/clients/inbox/deck-adapter.js +62 -0
- package/dist/clients/inbox/layout.d.ts +8 -0
- package/dist/clients/inbox/layout.js +9 -0
- package/dist/clients/inbox/resolve.d.ts +10 -0
- package/dist/clients/inbox/resolve.js +34 -0
- package/dist/clients/inbox/review/__tests__/editor-roundtrip.test.js +29 -0
- package/dist/clients/inbox/review/__tests__/remap.test.js +196 -0
- package/dist/clients/inbox/review/__tests__/review-core.test.js +341 -0
- package/dist/clients/inbox/review/anchors.d.ts +41 -0
- package/dist/clients/inbox/review/anchors.js +89 -0
- package/dist/clients/inbox/review/columns.d.ts +22 -0
- package/dist/clients/inbox/review/columns.js +40 -0
- package/dist/clients/inbox/review/comments-client.d.ts +66 -0
- package/dist/clients/inbox/review/comments-client.js +98 -0
- package/dist/clients/inbox/review/composition.d.ts +60 -0
- package/dist/clients/inbox/review/composition.js +278 -0
- package/dist/clients/inbox/review/document-region.d.ts +120 -0
- package/dist/clients/inbox/review/document-region.js +902 -0
- package/dist/clients/inbox/review/frame.d.ts +45 -0
- package/dist/clients/inbox/review/frame.js +215 -0
- package/dist/clients/inbox/review/keys.d.ts +67 -0
- package/dist/clients/inbox/review/keys.js +130 -0
- package/dist/clients/inbox/review/launch.d.ts +10 -0
- package/dist/clients/inbox/review/launch.js +129 -0
- package/dist/clients/inbox/review/live-source.d.ts +24 -0
- package/dist/clients/inbox/review/live-source.js +160 -0
- package/dist/clients/inbox/review/nvim.d.ts +13 -0
- package/dist/clients/inbox/review/nvim.js +42 -0
- package/dist/clients/inbox/review/remap.d.ts +51 -0
- package/dist/clients/inbox/review/remap.js +157 -0
- package/dist/clients/inbox/review/review-client.d.ts +30 -0
- package/dist/clients/inbox/review/review-client.js +107 -0
- package/dist/clients/inbox/review/roundtrip.d.ts +5 -0
- package/dist/clients/inbox/review/roundtrip.js +36 -0
- package/dist/clients/inbox/review/state.d.ts +143 -0
- package/dist/clients/inbox/review/state.js +282 -0
- package/dist/clients/inbox/review-adapter.d.ts +29 -0
- package/dist/clients/inbox/review-adapter.js +92 -0
- package/dist/clients/inbox/review-visibility.d.ts +5 -0
- package/dist/clients/inbox/review-visibility.js +19 -0
- package/dist/clients/inbox/surface.d.ts +19 -0
- package/dist/clients/inbox/surface.js +128 -0
- package/dist/clients/inbox/tui/ansi.d.ts +66 -0
- package/dist/clients/inbox/tui/ansi.js +317 -0
- package/dist/clients/inbox/tui/clipboard.d.ts +2 -0
- package/dist/clients/inbox/tui/clipboard.js +26 -0
- package/dist/clients/inbox/tui/input.d.ts +7 -0
- package/dist/clients/inbox/tui/input.js +653 -0
- package/dist/clients/inbox/tui/keys.d.ts +28 -0
- package/dist/clients/inbox/tui/keys.js +111 -0
- package/dist/clients/inbox/tui/panel.d.ts +2 -0
- package/dist/clients/inbox/tui/panel.js +217 -0
- package/dist/clients/inbox/tui/render.d.ts +37 -0
- package/dist/clients/inbox/tui/render.js +476 -0
- package/dist/clients/inbox/tui/types.d.ts +57 -0
- package/dist/clients/inbox/tui/types.js +1 -0
- package/dist/clients/inbox/tui.d.ts +6 -0
- package/dist/clients/inbox/tui.js +74 -0
- package/dist/clients/surfaces/host.d.ts +66 -0
- package/dist/clients/surfaces/host.js +1 -0
- package/dist/clients/surfaces/region.d.ts +16 -0
- package/dist/clients/surfaces/region.js +1 -0
- package/dist/clients/web/__tests__/push-engine.test.js +14 -158
- package/dist/clients/web/dev-server.d.ts +3 -3
- package/dist/clients/web/dev-server.js +9 -23
- package/dist/clients/web/events.js +4 -6
- package/dist/clients/web/push-engine.d.ts +2 -66
- package/dist/clients/web/push-engine.js +30 -161
- package/dist/clients/web/push-registry.d.ts +0 -4
- package/dist/clients/web/push-registry.js +2 -7
- package/dist/clients/web/server.js +3 -35
- package/dist/clients/web/web-client/shared/protocol.d.ts +0 -108
- package/dist/clients/web/web-cmd.js +2 -2
- package/dist/commands/__tests__/human.test.js +27 -15
- package/dist/commands/api-client.js +3 -3
- package/dist/commands/canvas-browse.js +1 -1
- package/dist/commands/canvas-issue.js +1 -1
- package/dist/commands/canvas-use.js +1 -1
- package/dist/commands/human/doc.d.ts +2 -0
- package/dist/commands/human/doc.js +98 -0
- package/dist/commands/human/inbox.d.ts +2 -0
- package/dist/commands/human/inbox.js +101 -0
- package/dist/commands/human/prompts.d.ts +2 -3
- package/dist/commands/human/prompts.js +27 -180
- package/dist/commands/human/queue.d.ts +1 -5
- package/dist/commands/human/queue.js +54 -216
- package/dist/commands/human/review.d.ts +2 -0
- package/dist/commands/human/review.js +298 -0
- package/dist/commands/human/shared.d.ts +2 -69
- package/dist/commands/human/shared.js +1 -181
- package/dist/commands/human.js +15 -20
- package/dist/commands/memory/__tests__/lint.test.d.ts +1 -0
- package/dist/commands/memory/__tests__/lint.test.js +15 -0
- package/dist/commands/memory/delete.js +2 -2
- package/dist/commands/memory/lint.d.ts +1 -0
- package/dist/commands/memory/lint.js +21 -3
- package/dist/commands/memory/read.js +4 -4
- package/dist/commands/node.js +8 -7
- package/dist/commands/pkg/plugin-manage.js +143 -68
- package/dist/commands/surface-inspect.js +2 -2
- package/dist/commands/surface.js +6 -12
- package/dist/commands/sys/__tests__/setup-core.test.js +9 -5
- package/dist/commands/sys/__tests__/setup-front-door.test.js +7 -42
- package/dist/commands/sys/config.js +29 -3
- package/dist/commands/sys/feedback.js +1 -1
- package/dist/commands/sys/setup-core.d.ts +12 -11
- package/dist/commands/sys/setup-core.js +55 -46
- package/dist/commands/sys/setup-wizard.d.ts +4 -1
- package/dist/commands/sys/setup-wizard.js +50 -9
- package/dist/commands/sys/sync-deps.js +1 -1
- package/dist/commands/sys.js +4 -6
- package/dist/core/__tests__/broker-sdk-wiring.test.js +6 -1
- package/dist/core/__tests__/broker-snapshot-history.test.js +9 -1
- package/dist/core/__tests__/dead-node-policy-table.test.js +3 -4
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +8 -5
- package/dist/core/__tests__/fixtures/fake-engine.js +28 -2
- package/dist/core/__tests__/full/broker-provider-retry.test.js +87 -2
- package/dist/core/__tests__/full/broker-whip-interrupt.test.d.ts +1 -0
- package/dist/core/__tests__/full/broker-whip-interrupt.test.js +39 -0
- package/dist/core/__tests__/full/detach-focus.test.js +1 -1
- package/dist/core/__tests__/human-deliver-e2e.test.js +64 -64
- package/dist/core/__tests__/human-deliver.test.js +71 -345
- package/dist/core/__tests__/inline-memory-refs.test.js +2 -12
- package/dist/core/__tests__/memory-resolver-precedence.test.js +12 -15
- package/dist/core/__tests__/migration.test.js +10 -0
- package/dist/core/__tests__/model-pin-durability.test.js +14 -0
- package/dist/core/__tests__/phase4-review-migration.test.d.ts +1 -0
- package/dist/core/__tests__/phase4-review-migration.test.js +100 -0
- package/dist/core/__tests__/phase4-review-store.test.d.ts +1 -0
- package/dist/core/__tests__/phase4-review-store.test.js +143 -0
- package/dist/core/__tests__/remote-canvas-target.test.js +2 -2
- package/dist/core/__tests__/revive.test.js +22 -53
- package/dist/core/__tests__/session-cycles.test.js +48 -18
- package/dist/core/__tests__/spawn-no-kickoff.test.js +8 -12
- package/dist/core/__tests__/stop-guard.test.js +16 -1
- package/dist/core/__tests__/tmux-surface.test.js +21 -25
- package/dist/core/asset-root.d.ts +7 -0
- package/dist/core/asset-root.js +18 -0
- package/dist/core/broker-client/client.d.ts +0 -7
- package/dist/core/broker-client/client.js +4 -10
- package/dist/core/broker-client/transport-relay.d.ts +3 -4
- package/dist/core/broker-client/transport-relay.js +3 -4
- package/dist/core/canvas/__tests__/attention.test.js +1 -1
- package/dist/core/canvas/__tests__/remote-canvas-source.test.js +1 -1
- package/dist/core/canvas/__tests__/remote-transport.test.d.ts +1 -0
- package/dist/core/{view/__tests__/transport-remote.test.js → canvas/__tests__/remote-transport.test.js} +2 -2
- package/dist/core/canvas/__tests__/render-remote.test.js +1 -1
- package/dist/core/canvas/attention.js +4 -4
- package/dist/core/canvas/canvas.d.ts +6 -11
- package/dist/core/canvas/canvas.js +11 -33
- package/dist/core/canvas/db.js +207 -38
- package/dist/core/canvas/extensions.d.ts +1 -1
- package/dist/core/canvas/extensions.js +8 -1
- package/dist/core/canvas/index.d.ts +0 -1
- package/dist/core/canvas/index.js +0 -1
- package/dist/core/canvas/nav-model.d.ts +1 -1
- package/dist/core/canvas/nav-model.js +1 -1
- package/dist/core/canvas/paths.d.ts +5 -0
- package/dist/core/canvas/paths.js +16 -0
- package/dist/core/canvas/remote-canvas-source.js +2 -2
- package/dist/core/canvas/remote-transport.d.ts +7 -0
- package/dist/core/{view/transport-remote.js → canvas/remote-transport.js} +3 -4
- package/dist/core/canvas/source.js +1 -1
- package/dist/core/canvas/status-glyph.js +4 -12
- package/dist/core/canvas/types.d.ts +10 -35
- package/dist/core/clipboard-text.d.ts +8 -0
- package/dist/core/clipboard-text.js +18 -0
- package/dist/core/command-manifests/registry.d.ts +1 -3
- package/dist/core/command-plugins/bundle.d.ts +29 -0
- package/dist/core/command-plugins/bundle.js +198 -0
- package/dist/core/command-plugins/discovery.d.ts +0 -8
- package/dist/core/command-plugins/discovery.js +2 -39
- package/dist/core/command-plugins/transport/http-fetch.d.ts +4 -30
- package/dist/core/command-plugins/transport/http-fetch.js +17 -95
- package/dist/core/command.d.ts +1 -13
- package/dist/core/command.js +1 -16
- package/dist/core/config.d.ts +4 -0
- package/dist/core/config.js +28 -3
- package/dist/core/document-lines.d.ts +4 -0
- package/dist/core/document-lines.js +6 -0
- package/dist/core/feed/feed.d.ts +2 -0
- package/dist/core/feed/feed.js +11 -7
- package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +1 -0
- package/dist/core/human/__tests__/inbox-cancel-worker.js +7 -0
- package/dist/core/human/__tests__/inbox-claim-worker.d.ts +1 -0
- package/dist/core/human/__tests__/inbox-claim-worker.js +17 -0
- package/dist/core/human/__tests__/inbox-core.test.d.ts +1 -0
- package/dist/core/human/__tests__/inbox-core.test.js +144 -0
- package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +1 -0
- package/dist/core/human/__tests__/inbox-stale-claim-worker.js +8 -0
- package/dist/core/human/__tests__/visible-paths.test.d.ts +1 -0
- package/dist/{clients/attach → core/human}/__tests__/visible-paths.test.js +9 -0
- package/dist/core/human/claim.d.ts +23 -0
- package/dist/core/human/claim.js +67 -0
- package/dist/core/human/convention.d.ts +30 -0
- package/dist/core/human/convention.js +202 -0
- package/dist/core/human/deck-factories.d.ts +8 -0
- package/dist/core/human/deck-factories.js +15 -0
- package/dist/core/human/deck-schema.d.ts +70 -0
- package/dist/core/human/deck-schema.js +92 -0
- package/dist/core/human/root.d.ts +7 -0
- package/dist/core/human/root.js +37 -0
- package/dist/core/human/scan.d.ts +3 -0
- package/dist/core/human/scan.js +76 -0
- package/dist/core/human/summary.d.ts +8 -0
- package/dist/core/human/summary.js +44 -0
- package/dist/core/human/tickets.d.ts +49 -0
- package/dist/core/human/tickets.js +190 -0
- package/dist/core/human/types.d.ts +136 -0
- package/dist/core/human/types.js +5 -0
- package/dist/{clients/attach → core/human}/visible-paths.d.ts +1 -1
- package/dist/{clients/attach → core/human}/visible-paths.js +3 -2
- package/dist/core/inspector/chrome.d.ts +6 -0
- package/dist/core/inspector/chrome.js +14 -0
- package/dist/core/inspector/contract.d.ts +105 -0
- package/dist/core/inspector/contract.js +1 -0
- package/dist/core/inspector/core.d.ts +4 -5
- package/dist/core/inspector/core.js +3 -5
- package/dist/core/inspector/host.d.ts +46 -0
- package/dist/core/{tui → inspector}/host.js +42 -208
- package/dist/core/inspector/text.d.ts +2 -2
- package/dist/core/inspector/transport.d.ts +6 -0
- package/dist/core/inspector/transport.js +36 -0
- package/dist/core/inspector/tui.d.ts +2 -2
- package/dist/core/inspector/tui.js +15 -15
- package/dist/core/keybindings/__tests__/inbox-affordance.test.js +11 -11
- package/dist/core/keybindings/__tests__/resolve.test.js +10 -19
- package/dist/core/keybindings/attach-control.d.ts +9 -3
- package/dist/core/keybindings/attach-control.js +3 -1
- package/dist/core/keybindings/catalog.d.ts +6 -5
- package/dist/core/keybindings/catalog.js +61 -133
- package/dist/core/keybindings/inbox.d.ts +5 -6
- package/dist/core/keybindings/inbox.js +9 -10
- package/dist/core/keybindings/index.d.ts +3 -3
- package/dist/core/keybindings/index.js +3 -3
- package/dist/core/keybindings/persistence.d.ts +5 -1
- package/dist/core/keybindings/persistence.js +24 -6
- package/dist/core/keybindings/resolve.d.ts +6 -0
- package/dist/core/keybindings/resolve.js +10 -3
- package/dist/core/memory/inline-ref-grammar.js +2 -3
- package/dist/core/memory-resolver.d.ts +27 -29
- package/dist/core/memory-resolver.js +45 -39
- package/dist/core/model-routes.d.ts +33 -0
- package/dist/core/model-routes.js +42 -3
- package/dist/core/preview-registry.js +17 -55
- package/dist/core/profiles/select.js +3 -3
- package/dist/core/{view/remote-canvas-target.d.ts → remote-canvas-target.d.ts} +2 -2
- package/dist/core/{view/remote-canvas-target.js → remote-canvas-target.js} +4 -4
- package/dist/core/review/__tests__/capture-origin.test.d.ts +1 -0
- package/dist/core/review/__tests__/capture-origin.test.js +139 -0
- package/dist/core/review/__tests__/comments.test.d.ts +1 -0
- package/dist/core/review/__tests__/comments.test.js +98 -0
- package/dist/core/review/__tests__/project.test.d.ts +1 -0
- package/dist/core/review/__tests__/project.test.js +71 -0
- package/dist/core/review/__tests__/remap.test.d.ts +1 -0
- package/dist/core/review/__tests__/remap.test.js +159 -0
- package/dist/core/review/__tests__/stage-identity.test.d.ts +1 -0
- package/dist/core/review/__tests__/stage-identity.test.js +140 -0
- package/dist/core/review/birth.d.ts +7 -0
- package/dist/core/review/birth.js +23 -0
- package/dist/core/review/comments.d.ts +69 -0
- package/dist/core/review/comments.js +295 -0
- package/dist/core/review/companion.d.ts +35 -0
- package/dist/core/review/companion.js +205 -0
- package/dist/core/review/document.d.ts +27 -0
- package/dist/core/review/document.js +138 -0
- package/dist/core/review/project.d.ts +13 -0
- package/dist/core/review/project.js +58 -0
- package/dist/core/review/realize.d.ts +19 -0
- package/dist/core/review/realize.js +217 -0
- package/dist/core/review/remap.d.ts +24 -0
- package/dist/core/review/remap.js +156 -0
- package/dist/core/review/signal.d.ts +5 -0
- package/dist/core/review/signal.js +31 -0
- package/dist/core/review/stage.d.ts +26 -0
- package/dist/core/review/stage.js +184 -0
- package/dist/core/review/store.d.ts +46 -0
- package/dist/core/review/store.js +163 -0
- package/dist/core/review/ticket-filter.d.ts +17 -0
- package/dist/core/review/ticket-filter.js +32 -0
- package/dist/core/review/types.d.ts +130 -0
- package/dist/core/review/types.js +23 -0
- package/dist/core/runtime/__tests__/session-visibility.test.d.ts +1 -0
- package/dist/core/runtime/__tests__/session-visibility.test.js +119 -0
- package/dist/core/runtime/bearings.d.ts +5 -17
- package/dist/core/runtime/bearings.js +88 -71
- package/dist/core/runtime/broker-protocol.d.ts +31 -8
- package/dist/core/runtime/broker.d.ts +15 -1
- package/dist/core/runtime/broker.js +573 -141
- package/dist/core/runtime/canvas-extensions.d.ts +4 -5
- package/dist/core/runtime/canvas-extensions.js +5 -5
- package/dist/core/runtime/front-door.js +4 -4
- package/dist/core/runtime/headless-pi.d.ts +24 -0
- package/dist/core/runtime/headless-pi.js +152 -0
- package/dist/core/runtime/kickoff.d.ts +1 -5
- package/dist/core/runtime/kickoff.js +1 -5
- package/dist/core/runtime/model-registry.d.ts +3 -0
- package/dist/core/runtime/model-registry.js +13 -0
- package/dist/core/runtime/naming-persist.d.ts +4 -0
- package/dist/core/runtime/naming-persist.js +27 -1
- package/dist/core/runtime/naming.d.ts +17 -12
- package/dist/core/runtime/naming.js +91 -140
- package/dist/core/runtime/node-read.js +19 -10
- package/dist/core/runtime/nodes.d.ts +9 -14
- package/dist/core/runtime/nodes.js +3 -53
- package/dist/core/runtime/package-health.d.ts +6 -21
- package/dist/core/runtime/package-health.js +12 -123
- package/dist/core/runtime/placement-tmux.d.ts +2 -1
- package/dist/core/runtime/placement-tmux.js +6 -4
- package/dist/core/runtime/placement.d.ts +1 -0
- package/dist/core/runtime/placement.js +4 -8
- package/dist/core/runtime/promote.js +3 -0
- package/dist/core/runtime/recap.d.ts +2 -7
- package/dist/core/runtime/recap.js +35 -69
- package/dist/core/runtime/revive.js +34 -77
- package/dist/core/runtime/session-cycles.d.ts +4 -0
- package/dist/core/runtime/session-cycles.js +14 -1
- package/dist/core/runtime/session-visibility.d.ts +37 -0
- package/dist/core/runtime/session-visibility.js +83 -0
- package/dist/core/runtime/spawn.js +10 -22
- package/dist/core/runtime/stop-guard.d.ts +1 -1
- package/dist/core/runtime/stop-guard.js +18 -13
- package/dist/core/runtime/surface-bg.js +1 -1
- package/dist/core/runtime/tmux-chrome.d.ts +1 -1
- package/dist/core/runtime/tmux-chrome.js +1 -1
- package/dist/core/runtime/tmux.d.ts +35 -7
- package/dist/core/runtime/tmux.js +439 -62
- package/dist/core/runtime/tool-group-summary.d.ts +19 -0
- package/dist/core/runtime/tool-group-summary.js +88 -0
- package/dist/core/scope.d.ts +2 -7
- package/dist/core/scope.js +9 -35
- package/dist/core/substrate/schema.d.ts +2 -2
- package/dist/core/termrender/code-doc.d.ts +12 -0
- package/dist/core/termrender/code-doc.js +92 -0
- package/dist/core/termrender/display.d.ts +12 -0
- package/dist/core/termrender/display.js +19 -0
- package/dist/core/termrender/termrender.d.ts +73 -0
- package/dist/core/termrender/termrender.js +795 -0
- package/dist/core/termrender/version.d.ts +1 -0
- package/dist/core/termrender/version.js +1 -0
- package/dist/core/tui/terminal.js +1 -2
- package/dist/core/user-settings.d.ts +71 -3
- package/dist/core/user-settings.js +83 -1
- package/dist/daemon/api/__tests__/inbox.test.js +44 -133
- package/dist/daemon/api/handlers/human.d.ts +0 -10
- package/dist/daemon/api/handlers/human.js +104 -702
- package/dist/daemon/api/handlers/inbox.js +113 -142
- package/dist/daemon/api/handlers/review-comments.d.ts +2 -0
- package/dist/daemon/api/handlers/review-comments.js +500 -0
- package/dist/daemon/api/handlers/reviews.d.ts +2 -0
- package/dist/daemon/api/handlers/reviews.js +287 -0
- package/dist/daemon/api/map.d.ts +22 -7
- package/dist/daemon/api/map.js +159 -11
- package/dist/daemon/api/server.js +4 -0
- package/dist/daemon/cron-run.js +6 -9
- package/dist/daemon/crtrd.js +17 -33
- package/dist/daemon/fleet.d.ts +1 -8
- package/dist/daemon/fleet.js +4 -30
- package/dist/daemon/human/finish.d.ts +14 -0
- package/dist/daemon/human/finish.js +115 -0
- package/dist/daemon/human/sweep.d.ts +6 -0
- package/dist/daemon/human/sweep.js +49 -0
- package/dist/daemon/messaging/node-message.d.ts +18 -0
- package/dist/daemon/messaging/node-message.js +70 -0
- package/dist/daemon/review/comment-notify.d.ts +26 -0
- package/dist/daemon/review/comment-notify.js +107 -0
- package/dist/daemon/review/deliver.d.ts +7 -0
- package/dist/daemon/review/deliver.js +56 -0
- package/dist/daemon/review/finish.d.ts +22 -0
- package/dist/daemon/review/finish.js +254 -0
- package/dist/daemon/review/sweep.d.ts +11 -0
- package/dist/daemon/review/sweep.js +120 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -2
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +42 -64
- package/dist/pi-extensions/__tests__/canvas-recap.test.d.ts +1 -0
- package/dist/pi-extensions/__tests__/canvas-recap.test.js +159 -0
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +16 -38
- package/dist/pi-extensions/__tests__/canvas-structured-output.test.d.ts +1 -0
- package/dist/pi-extensions/__tests__/canvas-structured-output.test.js +63 -0
- package/dist/pi-extensions/canvas-context-intro.d.ts +8 -11
- package/dist/pi-extensions/canvas-context-intro.js +50 -104
- package/dist/pi-extensions/canvas-recap.d.ts +15 -2
- package/dist/pi-extensions/canvas-recap.js +192 -69
- package/dist/pi-extensions/canvas-review-boundary.d.ts +59 -0
- package/dist/pi-extensions/canvas-review-boundary.js +81 -0
- package/dist/pi-extensions/canvas-stophook.d.ts +3 -3
- package/dist/pi-extensions/canvas-stophook.js +78 -128
- package/dist/pi-extensions/canvas-structured-output.js +52 -8
- package/dist/shared/generated-context.d.ts +29 -4
- package/dist/shared/generated-context.js +122 -7
- package/dist/shared/tool-groups.d.ts +23 -0
- package/dist/shared/tool-groups.js +60 -0
- package/dist/shared/working-activity.d.ts +8 -0
- package/dist/shared/working-activity.js +26 -0
- package/dist/types.d.ts +36 -2
- package/dist/types.js +51 -0
- package/dist/web-client/assets/index-CCPaLeW7.css +2 -0
- package/dist/web-client/assets/index-kyOWsnZK.js +86 -0
- package/dist/web-client/index.html +2 -2
- package/dist/web-client/sw.js +1 -1
- package/docs/compat/hearth-crtr-v4.md +2 -2
- package/docs/compat/hearth-crtr-v5.md +4 -2
- package/docs/public-api.md +3 -3
- package/package.json +21 -14
- package/runtime.lock.json +4661 -1453
- package/scripts/postinstall.mjs +15 -2
- package/dist/builtin-pi-packages/pi-mode-switch/README.md +0 -36
- package/dist/builtin-pi-packages/pi-mode-switch/bin/mode +0 -36
- package/dist/builtin-pi-packages/pi-mode-switch/extensions/index.ts +0 -449
- package/dist/builtin-pi-packages/pi-mode-switch/package.json +0 -14
- package/dist/builtin-pi-packages/pi-mode-switch/tsconfig.json +0 -9
- package/dist/builtin-views/_lib/states.mjs +0 -161
- package/dist/builtin-views/canvas/core.mjs +0 -657
- package/dist/builtin-views/canvas/text.mjs +0 -58
- package/dist/builtin-views/canvas/tui.mjs +0 -168
- package/dist/builtin-views/canvas/web.jsx +0 -121
- package/dist/builtin-views/chat/core.mjs +0 -684
- package/dist/builtin-views/chat/text.mjs +0 -101
- package/dist/builtin-views/chat/tui.mjs +0 -360
- package/dist/builtin-views/chat/web.jsx +0 -362
- package/dist/builtin-views/git-pr/core.mjs +0 -673
- package/dist/builtin-views/git-pr/text.mjs +0 -84
- package/dist/builtin-views/git-pr/tui.mjs +0 -301
- package/dist/builtin-views/git-pr/web.jsx +0 -216
- package/dist/builtin-views/inbox/_lib/render.mjs +0 -175
- package/dist/builtin-views/inbox/core.mjs +0 -1273
- package/dist/builtin-views/inbox/text.mjs +0 -73
- package/dist/builtin-views/inbox/tui.mjs +0 -314
- package/dist/builtin-views/inbox/web.jsx +0 -188
- package/dist/builtin-views/linkedin/core.mjs +0 -906
- package/dist/builtin-views/linkedin/text.mjs +0 -69
- package/dist/builtin-views/linkedin/tui.mjs +0 -413
- package/dist/builtin-views/linkedin/web.jsx +0 -206
- package/dist/builtin-views/prompt-review/core.mjs +0 -735
- package/dist/builtin-views/prompt-review/text.mjs +0 -15
- package/dist/builtin-views/prompt-review/tui.mjs +0 -196
- package/dist/builtin-views/prompt-review/web.jsx +0 -484
- package/dist/builtin-views/workspace-sidebar/__tests__/core.test.js +0 -50
- package/dist/builtin-views/workspace-sidebar/__tests__/core.test.ts +0 -53
- package/dist/builtin-views/workspace-sidebar/core.mjs +0 -670
- package/dist/builtin-views/workspace-sidebar/text.mjs +0 -53
- package/dist/builtin-views/workspace-sidebar/tui.mjs +0 -141
- package/dist/builtin-views/workspace-sidebar/web.jsx +0 -109
- package/dist/clients/attach/session/mode.d.ts +0 -25
- package/dist/clients/attach/session/mode.js +0 -97
- package/dist/commands/sys/promptstudio.d.ts +0 -2
- package/dist/commands/sys/promptstudio.js +0 -65
- package/dist/commands/view-cycle.d.ts +0 -2
- package/dist/commands/view-cycle.js +0 -130
- package/dist/commands/view-list.d.ts +0 -2
- package/dist/commands/view-list.js +0 -66
- package/dist/commands/view-new.d.ts +0 -2
- package/dist/commands/view-new.js +0 -74
- package/dist/commands/view-pick.d.ts +0 -6
- package/dist/commands/view-pick.js +0 -129
- package/dist/commands/view-run.d.ts +0 -2
- package/dist/commands/view-run.js +0 -214
- package/dist/commands/view.d.ts +0 -2
- package/dist/commands/view.js +0 -31
- package/dist/commands/workspace.d.ts +0 -2
- package/dist/commands/workspace.js +0 -165
- package/dist/core/__tests__/chat-view-reconnect.test.js +0 -105
- package/dist/core/__tests__/full/consult-startup-failure.test.js +0 -124
- package/dist/core/canvas/__tests__/human-work-outbox.test.js +0 -123
- package/dist/core/canvas/human-work-outbox.d.ts +0 -73
- package/dist/core/canvas/human-work-outbox.js +0 -261
- package/dist/core/command-plugins/store.d.ts +0 -16
- package/dist/core/command-plugins/store.js +0 -64
- package/dist/core/keybindings/__tests__/bespoke-consumers.test.js +0 -40
- package/dist/core/runtime/fault-recovery-nudge.d.ts +0 -3
- package/dist/core/runtime/fault-recovery-nudge.js +0 -3
- package/dist/core/tui/__tests__/host-keybindings.test.js +0 -113
- package/dist/core/tui/host.d.ts +0 -66
- package/dist/core/view/__tests__/transport-cache.test.js +0 -62
- package/dist/core/view/bridge.d.ts +0 -10
- package/dist/core/view/bridge.js +0 -31
- package/dist/core/view/chrome.d.ts +0 -9
- package/dist/core/view/chrome.js +0 -22
- package/dist/core/view/contract.d.ts +0 -205
- package/dist/core/view/contract.js +0 -23
- package/dist/core/view/loader.d.ts +0 -31
- package/dist/core/view/loader.js +0 -188
- package/dist/core/view/stream-local.d.ts +0 -3
- package/dist/core/view/stream-local.js +0 -231
- package/dist/core/view/transport-cache.d.ts +0 -8
- package/dist/core/view/transport-cache.js +0 -38
- package/dist/core/view/transport-local.d.ts +0 -7
- package/dist/core/view/transport-local.js +0 -83
- package/dist/core/view/transport-remote.d.ts +0 -2
- package/dist/core/view/transport.d.ts +0 -10
- package/dist/core/view/transport.js +0 -15
- package/dist/pi-extensions/naming-tool.d.ts +0 -24
- package/dist/pi-extensions/naming-tool.js +0 -67
- package/dist/prompts/view.d.ts +0 -7
- package/dist/prompts/view.js +0 -172
- package/dist/web/ViewChrome.d.ts +0 -7
- package/dist/web/ViewChrome.js +0 -28
- package/dist/web/ViewPane.d.ts +0 -39
- package/dist/web/ViewPane.js +0 -48
- package/dist/web/index.d.ts +0 -8
- package/dist/web/index.js +0 -22
- package/dist/web/runtime.d.ts +0 -39
- package/dist/web/runtime.js +0 -232
- package/dist/web/states.d.ts +0 -24
- package/dist/web/states.js +0 -24
- package/dist/web/transport-http.d.ts +0 -5
- package/dist/web/transport-http.js +0 -34
- package/dist/web/transport-stream.d.ts +0 -3
- package/dist/web/transport-stream.js +0 -204
- package/dist/web-client/assets/index-U_NZ66VE.js +0 -79
- package/dist/web-client/assets/index-aaeu4adv.css +0 -2
- /package/dist/{builtin-views/workspace-sidebar/__tests__/core.test.d.ts → clients/attach/__tests__/file-review-focus.test.d.ts} +0 -0
- /package/dist/clients/attach/__tests__/{visible-paths.test.d.ts → group-activity.test.d.ts} +0 -0
- /package/dist/{core/__tests__/chat-view-reconnect.test.d.ts → clients/attach/__tests__/input-controller-extension-command.test.d.ts} +0 -0
- /package/dist/{core/__tests__/full/consult-startup-failure.test.d.ts → clients/attach/__tests__/session-identity-refresh.test.d.ts} +0 -0
- /package/dist/{core/canvas/__tests__/human-work-outbox.test.d.ts → clients/inbox/__tests__/inbox-controller.test.d.ts} +0 -0
- /package/dist/{core/keybindings/__tests__/bespoke-consumers.test.d.ts → clients/inbox/__tests__/mount-panel.test.d.ts} +0 -0
- /package/dist/{core/tui/__tests__/host-keybindings.test.d.ts → clients/inbox/review/__tests__/editor-roundtrip.test.d.ts} +0 -0
- /package/dist/{core/view/__tests__/transport-cache.test.d.ts → clients/inbox/review/__tests__/remap.test.d.ts} +0 -0
- /package/dist/{core/view/__tests__/transport-remote.test.d.ts → clients/inbox/review/__tests__/review-core.test.d.ts} +0 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import stringWidth from 'string-width';
|
|
2
|
+
import { renderMarkdownBlockAwareLines } from '../../../core/termrender/termrender.js';
|
|
3
|
+
import { RESET, BOLD, DIM, ITALIC, GREEN, YELLOW, CYAN, REVERSE, sanitize, singleLine, truncate, hline, wrap, hardWrap, centerHorizontal, clipLine, panLine, visibleWidth, } from './ansi.js';
|
|
4
|
+
/** Cells one h/l press pans by in the card body. */
|
|
5
|
+
const PAN_STEP = 8;
|
|
6
|
+
// ── Renderers ────────────────────────────────────────────────────────────────
|
|
7
|
+
export function renderOverview(state, cols, rows) {
|
|
8
|
+
const lines = [];
|
|
9
|
+
const title = `${BOLD}${CYAN} Decisions ${RESET}`;
|
|
10
|
+
const progress = `${state.responses.size}/${state.interactions.length} answered`;
|
|
11
|
+
lines.push('');
|
|
12
|
+
lines.push(` ${title} ${DIM}${progress}${RESET}`);
|
|
13
|
+
lines.push(` ${DIM}${hline(Math.min(cols - 4, 60))}${RESET}`);
|
|
14
|
+
lines.push('');
|
|
15
|
+
const rowsBuf = [];
|
|
16
|
+
for (let i = 0; i < state.interactions.length; i++) {
|
|
17
|
+
const interaction = state.interactions[i];
|
|
18
|
+
const response = state.responses.get(interaction.id);
|
|
19
|
+
const preAnswered = state.preAnsweredIds.has(interaction.id);
|
|
20
|
+
const icon = response
|
|
21
|
+
? (preAnswered ? `${DIM}◆${RESET}` : `${GREEN}✓${RESET}`)
|
|
22
|
+
: `${DIM}○${RESET}`;
|
|
23
|
+
const label = singleLine(interaction.title);
|
|
24
|
+
const cursor = i === state.currentIndex ? `${CYAN}▸${RESET} ` : ' ';
|
|
25
|
+
const labelMax = Math.max(10, cols - 16);
|
|
26
|
+
rowsBuf.push({
|
|
27
|
+
line: ` ${cursor}${icon} ${truncate(label, labelMax)}`,
|
|
28
|
+
questionIndex: i,
|
|
29
|
+
});
|
|
30
|
+
if (response) {
|
|
31
|
+
const summary = singleLine(responseSummary(response, interaction));
|
|
32
|
+
const summaryMax = Math.max(10, cols - 10);
|
|
33
|
+
rowsBuf.push({
|
|
34
|
+
line: ` ${DIM}${truncate(summary, summaryMax)}${RESET}`,
|
|
35
|
+
questionIndex: i,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const reserved = 4 + 3 + 2;
|
|
40
|
+
const available = Math.max(1, rows - reserved);
|
|
41
|
+
let scroll = state.scrollOffset || 0;
|
|
42
|
+
const focusRow = rowsBuf.findIndex((r) => r.questionIndex === state.currentIndex);
|
|
43
|
+
if (focusRow >= 0) {
|
|
44
|
+
if (focusRow < scroll)
|
|
45
|
+
scroll = focusRow;
|
|
46
|
+
if (focusRow >= scroll + available)
|
|
47
|
+
scroll = focusRow - available + 1;
|
|
48
|
+
}
|
|
49
|
+
scroll = Math.max(0, Math.min(scroll, Math.max(0, rowsBuf.length - available)));
|
|
50
|
+
if (scroll > 0) {
|
|
51
|
+
lines.push(` ${DIM}↑ ${scroll} more above${RESET}`);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
lines.push('');
|
|
55
|
+
}
|
|
56
|
+
const end = Math.min(rowsBuf.length, scroll + available);
|
|
57
|
+
for (let i = scroll; i < end; i++)
|
|
58
|
+
lines.push(rowsBuf[i].line);
|
|
59
|
+
if (end < rowsBuf.length) {
|
|
60
|
+
lines.push(` ${DIM}↓ ${rowsBuf.length - end} more below${RESET}`);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
lines.push('');
|
|
64
|
+
}
|
|
65
|
+
lines.push(` ${DIM}${hline(Math.min(cols - 4, 60))}${RESET}`);
|
|
66
|
+
lines.push(` ${DIM}enter${RESET} review ${DIM}j/k${RESET} navigate ${DIM}q${RESET} finish`);
|
|
67
|
+
while (lines.length < rows)
|
|
68
|
+
lines.push('');
|
|
69
|
+
// Overview content extends roughly cols-16 wide for option labels; center
|
|
70
|
+
// against a 60-col cap (the divider width) when the terminal is much wider.
|
|
71
|
+
const centered = centerHorizontal(lines.slice(0, rows), cols, Math.min(cols, 60) + 2);
|
|
72
|
+
return centered;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Render a (possibly multiline) input buffer with a visible cursor at
|
|
76
|
+
* `cursor` (a code-point index). A private-use sentinel is inserted at the
|
|
77
|
+
* cursor position, the result is hard-wrapped (so `\n` and width-wrapping
|
|
78
|
+
* behave exactly as they would without a cursor), then the sentinel is
|
|
79
|
+
* swapped for a reverse-video block on whichever wrapped line it landed on.
|
|
80
|
+
* `stringWidth('\uE000') === 1`, so it occupies exactly one column and never
|
|
81
|
+
* throws off the wrap math.
|
|
82
|
+
*/
|
|
83
|
+
export function renderInputBuffer(buffer, cursor, maxWidth) {
|
|
84
|
+
const chars = [...buffer];
|
|
85
|
+
const at = Math.max(0, Math.min(cursor, chars.length));
|
|
86
|
+
const withCaret = [...chars.slice(0, at), '\uE000', ...chars.slice(at)].join('');
|
|
87
|
+
const wrapped = hardWrap(withCaret, maxWidth);
|
|
88
|
+
return wrapped.map((line) => (line.includes('\uE000') ? line.replace('\uE000', `${REVERSE} ${RESET}`) : line));
|
|
89
|
+
}
|
|
90
|
+
/** Code-point bounds of every visual row `renderInputBuffer` paints, mirroring
|
|
91
|
+
* `hardWrap` (character-based, lossless) so a cursor index maps to the row the
|
|
92
|
+
* human actually sees. `end` is exclusive of the row's trailing '\n', if any. */
|
|
93
|
+
export function wrappedRowBounds(buffer, width) {
|
|
94
|
+
const chars = [...buffer];
|
|
95
|
+
const w = Math.max(1, width);
|
|
96
|
+
const rows = [];
|
|
97
|
+
let start = 0;
|
|
98
|
+
let rowW = 0;
|
|
99
|
+
for (let i = 0; i < chars.length; i++) {
|
|
100
|
+
const ch = chars[i];
|
|
101
|
+
if (ch === '\n') {
|
|
102
|
+
rows.push({ start, end: i });
|
|
103
|
+
start = i + 1;
|
|
104
|
+
rowW = 0;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const cw = stringWidth(ch);
|
|
108
|
+
if (rowW + cw > w) {
|
|
109
|
+
rows.push({ start, end: i });
|
|
110
|
+
start = i;
|
|
111
|
+
rowW = cw;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
rowW += cw;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
rows.push({ start, end: chars.length });
|
|
118
|
+
return rows;
|
|
119
|
+
}
|
|
120
|
+
/** Vertical motion by *visual* row — what up/down mean in a wrapped input box,
|
|
121
|
+
* where one long soft-wrapped paragraph spans many rows. Returns the new
|
|
122
|
+
* code-point cursor, unchanged when there is no row in that direction. */
|
|
123
|
+
export function verticalCursor(buffer, cursor, delta, width) {
|
|
124
|
+
const rows = wrappedRowBounds(buffer, width);
|
|
125
|
+
const at = Math.max(0, Math.min(cursor, [...buffer].length));
|
|
126
|
+
let r = 0;
|
|
127
|
+
for (let i = 0; i < rows.length; i++)
|
|
128
|
+
if (rows[i].start <= at)
|
|
129
|
+
r = i;
|
|
130
|
+
const target = rows[r + delta];
|
|
131
|
+
if (target === undefined)
|
|
132
|
+
return at;
|
|
133
|
+
return Math.min(target.start + (at - rows[r].start), target.end);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Build the item-review frame parts (pre/body/post) and derive the body's
|
|
137
|
+
* scroll bounds. Pure: reads state, mutates nothing. Both `renderItemReview`
|
|
138
|
+
* and the pre-render `clampItemReviewScroll` go through this, so the layout
|
|
139
|
+
* math has a single source of truth.
|
|
140
|
+
*/
|
|
141
|
+
function buildItemReviewLayout(state, cols, rows) {
|
|
142
|
+
const interaction = state.interactions[state.currentIndex];
|
|
143
|
+
const response = state.responses.get(interaction.id);
|
|
144
|
+
const maxW = Math.min(cols - 4, 120);
|
|
145
|
+
// Diagrams are pictures, not prose: they render at the pane's full width
|
|
146
|
+
// rather than the readability cap. The card stops being centered when one
|
|
147
|
+
// claims that width, so the extra columns are actually available to it.
|
|
148
|
+
const paneW = Math.max(20, cols - 4);
|
|
149
|
+
const mdLines = (md) => renderMarkdownBlockAwareLines(md, maxW, paneW);
|
|
150
|
+
// Pre-body: position, divider, title, subtitle (always visible)
|
|
151
|
+
const preLines = [];
|
|
152
|
+
const pos = `${state.currentIndex + 1}/${state.interactions.length}`;
|
|
153
|
+
preLines.push('');
|
|
154
|
+
preLines.push(` ${BOLD}${CYAN}[${pos}]${RESET}`);
|
|
155
|
+
preLines.push(` ${DIM}${hline(maxW)}${RESET}`);
|
|
156
|
+
preLines.push('');
|
|
157
|
+
for (const line of wrap(sanitize(interaction.title), maxW)) {
|
|
158
|
+
preLines.push(` ${BOLD}${line}${RESET}`);
|
|
159
|
+
}
|
|
160
|
+
// "Previously answered" marker — shown only while the seed is intact (no user
|
|
161
|
+
// override yet). The label comes from preAnswered.label so callers can be
|
|
162
|
+
// domain-specific ("Previously approved", "Carried over from prior pass").
|
|
163
|
+
if (state.preAnsweredIds.has(interaction.id)) {
|
|
164
|
+
const customLabel = interaction.preAnswered !== undefined ? interaction.preAnswered.label : undefined;
|
|
165
|
+
const label = typeof customLabel === 'string' && customLabel.length > 0
|
|
166
|
+
? customLabel
|
|
167
|
+
: 'Previously answered';
|
|
168
|
+
preLines.push(` ${DIM}${ITALIC}◆ ${sanitize(label)} — press n/p to review, or any option to override${RESET}`);
|
|
169
|
+
}
|
|
170
|
+
// Rendered subtitle and question body are scrollable so long content never
|
|
171
|
+
// overflows the fixed header.
|
|
172
|
+
const bodyLines = [];
|
|
173
|
+
if (interaction.subtitle) {
|
|
174
|
+
bodyLines.push('');
|
|
175
|
+
for (const line of mdLines(interaction.subtitle)) {
|
|
176
|
+
bodyLines.push(` ${line}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (interaction.body) {
|
|
180
|
+
bodyLines.push('');
|
|
181
|
+
for (const line of mdLines(interaction.body)) {
|
|
182
|
+
bodyLines.push(` ${line}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Post-body: input buffer or actions, then footer.
|
|
186
|
+
const postLines = [];
|
|
187
|
+
postLines.push('');
|
|
188
|
+
if (state.inputMode) {
|
|
189
|
+
postLines.push(` ${DIM}${hline(maxW)}${RESET}`);
|
|
190
|
+
const label = interaction.freetextLabel !== undefined
|
|
191
|
+
? interaction.freetextLabel
|
|
192
|
+
: state.inputMode.kind === 'comment' ? 'Comment' : 'Response';
|
|
193
|
+
// Show attached option in comment mode. For single-select the comment
|
|
194
|
+
// qualifies the pick; for multi-select an attached option means the
|
|
195
|
+
// comment is saved as a per-option note (and auto-checks the option).
|
|
196
|
+
let attachedLine;
|
|
197
|
+
if (state.inputMode.kind === 'comment') {
|
|
198
|
+
const attachedId = state.inputMode.selectedOptionId;
|
|
199
|
+
const opts = interaction.options;
|
|
200
|
+
if (opts.length > 0) {
|
|
201
|
+
const attached = attachedId !== undefined
|
|
202
|
+
? opts.find((o) => o.id === attachedId)
|
|
203
|
+
: undefined;
|
|
204
|
+
const valueText = attached !== undefined
|
|
205
|
+
? `${CYAN}${truncate(singleLine(attached.label), Math.max(10, maxW - 28))}${RESET}`
|
|
206
|
+
: `${DIM}none (overall)${RESET}`;
|
|
207
|
+
attachedLine = ` ${DIM}attached:${RESET} ${valueText} ${DIM}[tab to cycle]${RESET}`;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
for (const labelLine of wrap(`${singleLine(label)}:`, maxW)) {
|
|
211
|
+
postLines.push(` ${YELLOW}${labelLine}${RESET}`);
|
|
212
|
+
}
|
|
213
|
+
const bufLines = renderInputBuffer(state.inputMode.buffer, state.inputMode.cursor, maxW - 1);
|
|
214
|
+
for (const line of bufLines)
|
|
215
|
+
postLines.push(` ${line}`);
|
|
216
|
+
if (attachedLine !== undefined) {
|
|
217
|
+
postLines.push('');
|
|
218
|
+
postLines.push(attachedLine);
|
|
219
|
+
}
|
|
220
|
+
postLines.push('');
|
|
221
|
+
postLines.push(` ${DIM}enter${RESET} submit ${DIM}^J/⌥⏎${RESET} newline${state.editorAvailable ? ` ${DIM}^O${RESET} editor` : ''} ${DIM}esc${RESET} cancel`);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
postLines.push(...renderActions(interaction, state.selectedAction, maxW, response));
|
|
225
|
+
}
|
|
226
|
+
// Transient hint (e.g. an empty multi-select Enter that was rejected). Sits
|
|
227
|
+
// just above the footer; cleared on the next keypress.
|
|
228
|
+
if (state.hint !== undefined && state.hint.length > 0) {
|
|
229
|
+
postLines.push('');
|
|
230
|
+
for (const hintLine of wrap(sanitize(state.hint), maxW)) {
|
|
231
|
+
postLines.push(` ${YELLOW}${hintLine}${RESET}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// Derive the scroll window bounds. This builder never writes back into state
|
|
235
|
+
// — the host clamps state.scrollOffset via clampItemReviewScroll before render.
|
|
236
|
+
const reservedRows = preLines.length + postLines.length + 1; // +1 for footer
|
|
237
|
+
const bodyHeight = Math.max(1, rows - reservedRows);
|
|
238
|
+
const maxScroll = Math.max(0, bodyLines.length - bodyHeight);
|
|
239
|
+
const overflows = bodyLines.length > bodyHeight;
|
|
240
|
+
// Horizontal geometry, derived from what is actually on screen: a body row
|
|
241
|
+
// wider than the prose column takes the whole pane (which also drops the
|
|
242
|
+
// centering pad below), and anything past that pans.
|
|
243
|
+
const scroll = Math.max(0, Math.min(state.scrollOffset || 0, maxScroll));
|
|
244
|
+
const visible = visibleItemBodyLines(bodyLines, scroll, bodyHeight);
|
|
245
|
+
let widest = 0;
|
|
246
|
+
for (const line of visible)
|
|
247
|
+
widest = Math.max(widest, visibleWidth(line));
|
|
248
|
+
const bodyBoxW = widest > maxW + 2 ? paneW + 2 : maxW + 2;
|
|
249
|
+
return {
|
|
250
|
+
interaction, preLines, bodyLines, postLines,
|
|
251
|
+
maxW, bodyHeight, maxScroll, overflows,
|
|
252
|
+
bodyBoxW, maxHScroll: Math.max(0, widest - bodyBoxW),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/** Body rows as they are actually painted: vertical-scroll indicators replace
|
|
256
|
+
* their endpoint rows, so those hidden rows cannot make h/l available. */
|
|
257
|
+
function visibleItemBodyLines(bodyLines, scroll, bodyHeight) {
|
|
258
|
+
if (bodyLines.length <= bodyHeight)
|
|
259
|
+
return bodyLines;
|
|
260
|
+
const visible = bodyLines.slice(scroll, scroll + bodyHeight);
|
|
261
|
+
if (scroll > 0)
|
|
262
|
+
visible[0] = ` ${DIM}↑ ${scroll} more above${RESET}`;
|
|
263
|
+
const remainingBelow = bodyLines.length - (scroll + bodyHeight);
|
|
264
|
+
if (remainingBelow > 0)
|
|
265
|
+
visible[visible.length - 1] = ` ${DIM}↓ ${remainingBelow} more below${RESET}`;
|
|
266
|
+
return visible;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Clamp state.scrollOffset to the current body's scroll bounds. The host runs
|
|
270
|
+
* this as a pre-render step (from the input path) so `renderItemReview` stays a
|
|
271
|
+
* pure function of state — the clamp keeps u/d scrolling responsive without the
|
|
272
|
+
* renderer mutating state mid-frame.
|
|
273
|
+
*/
|
|
274
|
+
export function clampItemReviewScroll(state, cols, rows) {
|
|
275
|
+
const { maxScroll, maxHScroll } = buildItemReviewLayout(state, cols, rows);
|
|
276
|
+
state.scrollOffset = Math.max(0, Math.min(state.scrollOffset || 0, maxScroll));
|
|
277
|
+
state.bodyScrollOffsets[state.bodyMode] = state.scrollOffset;
|
|
278
|
+
// Publish the live horizontal reach so the input layer can tell whether h/l
|
|
279
|
+
// mean "pan" on this card, and keep the stored pan inside it across vertical
|
|
280
|
+
// scrolling and resize.
|
|
281
|
+
state.hscrollMax = maxHScroll;
|
|
282
|
+
state.hscrollOffset = Math.max(0, Math.min(state.hscrollOffset || 0, maxHScroll));
|
|
283
|
+
}
|
|
284
|
+
/** Pan the card body horizontally. Clamping happens in the pre-render clamp
|
|
285
|
+
* the host already runs, exactly like vertical over-scroll. */
|
|
286
|
+
export function panItemReview(state, direction) {
|
|
287
|
+
state.hscrollOffset = Math.max(0, (state.hscrollOffset || 0) + direction * PAN_STEP);
|
|
288
|
+
}
|
|
289
|
+
export function renderItemReview(state, cols, rows) {
|
|
290
|
+
const { interaction, preLines, bodyLines, postLines, maxW, bodyHeight, maxScroll, overflows, bodyBoxW, maxHScroll } = buildItemReviewLayout(state, cols, rows);
|
|
291
|
+
// Read-only clamp: renderer never mutates state (clampItemReviewScroll, run
|
|
292
|
+
// pre-render, keeps state.scrollOffset itself in bounds).
|
|
293
|
+
const scroll = Math.max(0, Math.min(state.scrollOffset || 0, maxScroll));
|
|
294
|
+
let visibleBody = visibleItemBodyLines(bodyLines, scroll, bodyHeight);
|
|
295
|
+
// Contain every body row in the card's rectangle: rows that fit are
|
|
296
|
+
// untouched, a diagram wider than the pane pans under h/l with ‹/› marking
|
|
297
|
+
// the content still off-screen.
|
|
298
|
+
const hscroll = Math.max(0, Math.min(state.hscrollOffset || 0, maxHScroll));
|
|
299
|
+
visibleBody = visibleBody.map((line) => panLine(line, hscroll, bodyBoxW));
|
|
300
|
+
// Footer hint — mention scroll keys when body overflows
|
|
301
|
+
const footerParts = interaction.multiSelect === true
|
|
302
|
+
? [
|
|
303
|
+
`${DIM}n/p${RESET} prev/next`,
|
|
304
|
+
`${DIM}space${RESET} toggle`,
|
|
305
|
+
`${DIM}enter${RESET} confirm`,
|
|
306
|
+
`${DIM}q${RESET} overview`,
|
|
307
|
+
]
|
|
308
|
+
: [
|
|
309
|
+
`${DIM}n/p${RESET} prev/next`,
|
|
310
|
+
`${DIM}q${RESET} overview`,
|
|
311
|
+
];
|
|
312
|
+
if (overflows) {
|
|
313
|
+
footerParts.unshift(state.inputMode ? `${DIM}pgup/pgdn${RESET} scroll` : `${DIM}u/d${RESET} scroll`);
|
|
314
|
+
}
|
|
315
|
+
if (maxHScroll > 0 && state.inputMode === null) {
|
|
316
|
+
footerParts.unshift(`${DIM}h/l${RESET} pan`);
|
|
317
|
+
}
|
|
318
|
+
const footer = ` ${footerParts.join(' ')}`;
|
|
319
|
+
// Assemble — pad to fill rows so post-body sits at the bottom
|
|
320
|
+
const lines = [...preLines, ...visibleBody, ...postLines];
|
|
321
|
+
while (lines.length < rows - 1)
|
|
322
|
+
lines.push('');
|
|
323
|
+
lines.push(footer);
|
|
324
|
+
// Final clamp (safety net for very small terminals)
|
|
325
|
+
const clamped = lines.length > rows
|
|
326
|
+
? [...lines.slice(0, rows - 1), footer]
|
|
327
|
+
: lines;
|
|
328
|
+
// Content occupies the body rectangle (prose column, or the full pane when a
|
|
329
|
+
// diagram claims it) — center the whole block when the terminal is wider,
|
|
330
|
+
// then contain every row so nothing can wrap past the card's rectangle.
|
|
331
|
+
return centerHorizontal(clamped, cols, bodyBoxW).map((line) => clipLine(line, cols));
|
|
332
|
+
}
|
|
333
|
+
/** The option list. Focus is always drawn so j/k and shortcuts show where they land. */
|
|
334
|
+
function renderActions(interaction, selectedAction, maxW, existing) {
|
|
335
|
+
const lines = [];
|
|
336
|
+
const opts = interaction.options;
|
|
337
|
+
// Prefix on first row: " X [s] " — 2 + 1 (cursor) + 1 + 3 ([s]) + 1 = 8 visible cols.
|
|
338
|
+
// Continuation rows align under the label so each option reads as a block.
|
|
339
|
+
const multi = interaction.multiSelect === true;
|
|
340
|
+
const checked = new Set(existing?.selectedOptionIds ?? []);
|
|
341
|
+
const prefixWidth = multi ? 12 : 8;
|
|
342
|
+
const indent = ' '.repeat(prefixWidth);
|
|
343
|
+
const contentMax = Math.max(20, maxW - prefixWidth);
|
|
344
|
+
const optionComments = existing !== undefined ? existing.optionComments : undefined;
|
|
345
|
+
for (let i = 0; i < opts.length; i++) {
|
|
346
|
+
const o = opts[i];
|
|
347
|
+
const cursor = i === selectedAction ? `${CYAN}▸${RESET}` : ' ';
|
|
348
|
+
const sc = o.shortcut === undefined ? ' ' : o.shortcut;
|
|
349
|
+
const keyBadge = `${DIM}[${sc}]${RESET}`;
|
|
350
|
+
const box = multi
|
|
351
|
+
? (checked.has(o.id) ? `${GREEN}[x]${RESET}` : `${DIM}[ ]${RESET}`) + ' '
|
|
352
|
+
: '';
|
|
353
|
+
const labelLines = wrap(sanitize(o.label), contentMax);
|
|
354
|
+
for (let j = 0; j < labelLines.length; j++) {
|
|
355
|
+
const prefix = j === 0 ? ` ${cursor} ${box}${keyBadge} ` : indent;
|
|
356
|
+
lines.push(`${prefix}${labelLines[j]}`);
|
|
357
|
+
}
|
|
358
|
+
if (o.description) {
|
|
359
|
+
const descLines = wrap(`— ${sanitize(o.description)}`, contentMax);
|
|
360
|
+
for (const dl of descLines) {
|
|
361
|
+
lines.push(`${indent}${DIM}${dl}${RESET}`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (multi && optionComments !== undefined) {
|
|
365
|
+
const note = optionComments[o.id];
|
|
366
|
+
if (typeof note === 'string' && note.length > 0) {
|
|
367
|
+
const noteLines = wrap(`✎ ${sanitize(note)}`, contentMax);
|
|
368
|
+
for (const nl of noteLines) {
|
|
369
|
+
lines.push(`${indent}${YELLOW}${nl}${RESET}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (interaction.allowFreetext && opts.length > 0) {
|
|
375
|
+
const cursor = opts.length === selectedAction ? `${CYAN}▸${RESET}` : ' ';
|
|
376
|
+
let label;
|
|
377
|
+
if (interaction.freetextLabel !== undefined)
|
|
378
|
+
label = interaction.freetextLabel;
|
|
379
|
+
else if (multi)
|
|
380
|
+
label = 'Add overall comment (c on an option for per-option)';
|
|
381
|
+
else
|
|
382
|
+
label = 'Add comment';
|
|
383
|
+
const ftLines = wrap(sanitize(label), contentMax);
|
|
384
|
+
for (let j = 0; j < ftLines.length; j++) {
|
|
385
|
+
const prefix = j === 0 ? ` ${cursor} ${DIM}[c]${RESET} ` : ' '.repeat(8);
|
|
386
|
+
lines.push(`${prefix}${ftLines[j]}`);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
else if (interaction.allowFreetext && opts.length === 0) {
|
|
390
|
+
const ftLabel = interaction.freetextLabel !== undefined ? interaction.freetextLabel : 'Enter response';
|
|
391
|
+
const ftLines = wrap(sanitize(ftLabel), contentMax);
|
|
392
|
+
for (let j = 0; j < ftLines.length; j++) {
|
|
393
|
+
const prefix = j === 0 ? ` ${DIM}[r]${RESET} ` : ' '.repeat(6);
|
|
394
|
+
lines.push(`${prefix}${ftLines[j]}`);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
if (existing) {
|
|
398
|
+
lines.push('');
|
|
399
|
+
for (const curLine of wrap(`Current: ${responseSummary(existing, interaction)}`, maxW)) {
|
|
400
|
+
lines.push(` ${GREEN}${curLine}${RESET}`);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return lines;
|
|
404
|
+
}
|
|
405
|
+
export function renderFinal(state, cols, rows) {
|
|
406
|
+
const header = [];
|
|
407
|
+
const footer = [];
|
|
408
|
+
const maxW = Math.min(cols - 4, 60);
|
|
409
|
+
const total = state.interactions.length;
|
|
410
|
+
const answered = state.responses.size;
|
|
411
|
+
header.push('');
|
|
412
|
+
header.push(` ${BOLD}${CYAN} Summary ${RESET}`);
|
|
413
|
+
header.push(` ${DIM}${hline(maxW)}${RESET}`);
|
|
414
|
+
header.push('');
|
|
415
|
+
header.push(` ${answered}/${total} questions answered`);
|
|
416
|
+
header.push('');
|
|
417
|
+
footer.push('');
|
|
418
|
+
footer.push(` ${DIM}${hline(maxW)}${RESET}`);
|
|
419
|
+
if (answered < total) {
|
|
420
|
+
footer.push(` ${YELLOW}${total - answered} unanswered — press p to go back${RESET}`);
|
|
421
|
+
}
|
|
422
|
+
footer.push(` ${DIM}enter${RESET} submit ${DIM}p${RESET} go back`);
|
|
423
|
+
const questionRows = [];
|
|
424
|
+
for (const interaction of state.interactions) {
|
|
425
|
+
const response = state.responses.get(interaction.id);
|
|
426
|
+
const preAnswered = state.preAnsweredIds.has(interaction.id);
|
|
427
|
+
const icon = response
|
|
428
|
+
? (preAnswered ? `${DIM}◆${RESET}` : `${GREEN}✓${RESET}`)
|
|
429
|
+
: `${YELLOW}○${RESET}`;
|
|
430
|
+
const label = singleLine(interaction.title);
|
|
431
|
+
questionRows.push(` ${icon} ${truncate(label, Math.max(10, maxW - 4))}`);
|
|
432
|
+
if (response) {
|
|
433
|
+
questionRows.push(` ${DIM}${truncate(singleLine(responseSummary(response, interaction)), Math.max(10, maxW - 6))}${RESET}`);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
const available = Math.max(1, rows - header.length - footer.length - 1);
|
|
437
|
+
let visible = questionRows;
|
|
438
|
+
if (questionRows.length > available) {
|
|
439
|
+
visible = [
|
|
440
|
+
...questionRows.slice(0, available - 1),
|
|
441
|
+
` ${DIM}… ${questionRows.length - (available - 1)} more rows omitted${RESET}`,
|
|
442
|
+
];
|
|
443
|
+
}
|
|
444
|
+
const lines = [...header, ...visible, ...footer];
|
|
445
|
+
while (lines.length < rows)
|
|
446
|
+
lines.push('');
|
|
447
|
+
return centerHorizontal(lines.slice(0, rows), cols, maxW + 2);
|
|
448
|
+
}
|
|
449
|
+
export function responseSummary(r, interaction) {
|
|
450
|
+
if (r.selectedOptionIds !== undefined) {
|
|
451
|
+
const oc = r.optionComments;
|
|
452
|
+
const parts = r.selectedOptionIds
|
|
453
|
+
.map((id) => interaction.options.find((o) => o.id === id))
|
|
454
|
+
.filter((o) => o !== undefined)
|
|
455
|
+
.map((o) => {
|
|
456
|
+
const note = oc !== undefined ? oc[o.id] : undefined;
|
|
457
|
+
return typeof note === 'string' && note.length > 0
|
|
458
|
+
? `${sanitize(o.label)} ("${sanitize(note)}")`
|
|
459
|
+
: sanitize(o.label);
|
|
460
|
+
});
|
|
461
|
+
const picks = parts.length > 0 ? parts.join(', ') : '(none)';
|
|
462
|
+
if (r.freetext)
|
|
463
|
+
return `${picks}: "${sanitize(r.freetext)}"`;
|
|
464
|
+
return picks;
|
|
465
|
+
}
|
|
466
|
+
const opt = r.selectedOptionId
|
|
467
|
+
? interaction.options.find((o) => o.id === r.selectedOptionId)
|
|
468
|
+
: undefined;
|
|
469
|
+
if (opt && r.freetext)
|
|
470
|
+
return `${sanitize(opt.label)}: "${sanitize(r.freetext)}"`;
|
|
471
|
+
if (opt)
|
|
472
|
+
return sanitize(opt.label);
|
|
473
|
+
if (r.freetext)
|
|
474
|
+
return sanitize(r.freetext);
|
|
475
|
+
return '(empty)';
|
|
476
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Key } from './keys.js';
|
|
2
|
+
import type { Deck, Interaction, InteractionResponse } from '../../../core/human/types.js';
|
|
3
|
+
export type Phase = 'overview' | 'item-review' | 'final';
|
|
4
|
+
export type InputMode = null | {
|
|
5
|
+
kind: 'comment';
|
|
6
|
+
buffer: string;
|
|
7
|
+
cursor: number;
|
|
8
|
+
selectedOptionId?: string;
|
|
9
|
+
} | {
|
|
10
|
+
kind: 'freetext';
|
|
11
|
+
buffer: string;
|
|
12
|
+
cursor: number;
|
|
13
|
+
};
|
|
14
|
+
export interface TuiState {
|
|
15
|
+
phase: Phase;
|
|
16
|
+
currentIndex: number;
|
|
17
|
+
interactions: Interaction[];
|
|
18
|
+
responses: Map<string, InteractionResponse>;
|
|
19
|
+
preAnsweredIds: Set<string>;
|
|
20
|
+
inputMode: InputMode;
|
|
21
|
+
selectedAction: number;
|
|
22
|
+
bodyMode: 'question';
|
|
23
|
+
scrollOffset: number;
|
|
24
|
+
bodyScrollOffsets: {
|
|
25
|
+
question: number;
|
|
26
|
+
};
|
|
27
|
+
hscrollOffset: number;
|
|
28
|
+
hscrollMax: number;
|
|
29
|
+
wrapWidth: number;
|
|
30
|
+
editorAvailable: boolean;
|
|
31
|
+
hint?: string;
|
|
32
|
+
persist?: () => void;
|
|
33
|
+
}
|
|
34
|
+
export interface MountedPanelOpts {
|
|
35
|
+
deck: Deck;
|
|
36
|
+
progressPath?: string;
|
|
37
|
+
onEditorRequest?: () => void;
|
|
38
|
+
cols: number;
|
|
39
|
+
rows: number;
|
|
40
|
+
onProgress?: (responses: InteractionResponse[]) => void;
|
|
41
|
+
onComplete?: (responses: InteractionResponse[]) => void;
|
|
42
|
+
onExit?: () => void;
|
|
43
|
+
onDirty?: () => void;
|
|
44
|
+
}
|
|
45
|
+
export interface MountedPanel {
|
|
46
|
+
handleKey(input: string, key: Key): void;
|
|
47
|
+
render(): string[];
|
|
48
|
+
handleResize(cols: number, rows: number): string[];
|
|
49
|
+
unmount(): void;
|
|
50
|
+
loadDeck(deck: Deck, opts?: {
|
|
51
|
+
progressPath?: string;
|
|
52
|
+
}): void;
|
|
53
|
+
canAcceptHostKeys(): boolean;
|
|
54
|
+
atDeckTop(): boolean;
|
|
55
|
+
getInputBuffer(): string | undefined;
|
|
56
|
+
setInputBuffer(text: string): void;
|
|
57
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TicketSummary } from '../../core/human/types.js';
|
|
2
|
+
export declare const KIND_ICON: Record<string, string>;
|
|
3
|
+
export declare const KIND_COLOR: Record<string, string>;
|
|
4
|
+
export declare function formatTimeAgo(iso: string): string;
|
|
5
|
+
/** Pure inbox rows; selection and terminal ownership belong to InboxController. */
|
|
6
|
+
export declare function buildInboxLines(items: TicketSummary[], width: number, selectedIndex: number, height?: number): string[];
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { RESET, BOLD, DIM, ITALIC, CYAN, RED, GRAY, YELLOW, truncateRow } from './tui/ansi.js';
|
|
2
|
+
function ansiColor(text, color) {
|
|
3
|
+
switch (color) {
|
|
4
|
+
case 'gray': return `${GRAY}${text}${RESET}`;
|
|
5
|
+
case 'cyan': return `${CYAN}${text}${RESET}`;
|
|
6
|
+
case 'red': return `${RED}${text}${RESET}`;
|
|
7
|
+
case 'yellow': return `${YELLOW}${text}${RESET}`;
|
|
8
|
+
default: return text;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export const KIND_ICON = { notify: '✉', decision: '◆', context: '✎', error: '⚠', review: '▤' };
|
|
12
|
+
export const KIND_COLOR = { notify: 'gray', decision: 'cyan', context: 'cyan', error: 'red', review: 'yellow' };
|
|
13
|
+
export function formatTimeAgo(iso) {
|
|
14
|
+
const minutes = Math.floor((Date.now() - new Date(iso).getTime()) / 60000);
|
|
15
|
+
if (minutes >= 60)
|
|
16
|
+
return `${Math.floor(minutes / 60)}h ago`;
|
|
17
|
+
if (minutes > 0)
|
|
18
|
+
return `${minutes}m ago`;
|
|
19
|
+
return 'just now';
|
|
20
|
+
}
|
|
21
|
+
/** Pure inbox rows; selection and terminal ownership belong to InboxController. */
|
|
22
|
+
export function buildInboxLines(items, width, selectedIndex, height = Number.MAX_SAFE_INTEGER) {
|
|
23
|
+
if (items.length === 0)
|
|
24
|
+
return [` ${DIM}${ITALIC}No pending interactions${RESET}`];
|
|
25
|
+
const contentWidth = width - 4;
|
|
26
|
+
const itemLines = items.map((item, index) => buildItemLines(item, index, selectedIndex, contentWidth));
|
|
27
|
+
const window = visibleWindow(itemLines, selectedIndex, Math.max(1, height - 2));
|
|
28
|
+
const lines = [` ${BOLD}${items.length} pending${RESET}`, ''];
|
|
29
|
+
if (window.start > 0)
|
|
30
|
+
lines.push(` ${DIM}↑ ${window.start} above${RESET}`);
|
|
31
|
+
for (let index = window.start; index < window.end; index++)
|
|
32
|
+
lines.push(...itemLines[index]);
|
|
33
|
+
if (window.end < items.length)
|
|
34
|
+
lines.push(` ${DIM}↓ ${items.length - window.end} below${RESET}`);
|
|
35
|
+
return lines;
|
|
36
|
+
}
|
|
37
|
+
function buildItemLines(item, index, selectedIndex, contentWidth) {
|
|
38
|
+
const kind = item.kind === 'deck' ? item.interactionKind ?? 'decision' : 'review';
|
|
39
|
+
const icon = KIND_ICON[kind] ?? '·';
|
|
40
|
+
// The inbox is a title-first triage surface. Origin details remain available
|
|
41
|
+
// after opening a ticket, rather than consuming the list's scarce row width.
|
|
42
|
+
const age = formatTimeAgo(item.blockedSince);
|
|
43
|
+
const cursor = index === selectedIndex ? `${CYAN}▸${RESET} ` : ' ';
|
|
44
|
+
const titleWidth = Math.max(1, contentWidth - age.length - 6);
|
|
45
|
+
const row = `${cursor}${ansiColor(icon, KIND_COLOR[kind] ?? 'cyan')} ${BOLD}${truncateRow(item.title || `(${item.id.slice(0, 8)})`, titleWidth)}${RESET} ${DIM}${age}${RESET}`;
|
|
46
|
+
const subtitle = item.claim ? `claimed by ${item.claim.owner} · ${item.subtitle}` : item.subtitle;
|
|
47
|
+
return [row, ` ${DIM}${truncateRow(subtitle, contentWidth - 6)}${RESET}`];
|
|
48
|
+
}
|
|
49
|
+
/** Select a contiguous row window that always contains the selected ticket. */
|
|
50
|
+
function visibleWindow(rows, selectedIndex, capacity) {
|
|
51
|
+
let start = Math.max(0, Math.min(selectedIndex, rows.length - 1));
|
|
52
|
+
let end = start + 1;
|
|
53
|
+
let preferBelow = true;
|
|
54
|
+
while (true) {
|
|
55
|
+
const below = end < rows.length ? { start, end: end + 1 } : undefined;
|
|
56
|
+
const above = start > 0 ? { start: start - 1, end } : undefined;
|
|
57
|
+
const preferred = preferBelow ? [below, above] : [above, below];
|
|
58
|
+
const next = preferred.find((candidate) => candidate !== undefined && windowHeight(rows, candidate.start, candidate.end) <= capacity);
|
|
59
|
+
if (next === undefined)
|
|
60
|
+
break;
|
|
61
|
+
start = next.start;
|
|
62
|
+
end = next.end;
|
|
63
|
+
preferBelow = !preferBelow;
|
|
64
|
+
}
|
|
65
|
+
return { start, end };
|
|
66
|
+
}
|
|
67
|
+
function windowHeight(rows, start, end) {
|
|
68
|
+
let height = start > 0 ? 1 : 0;
|
|
69
|
+
for (let index = start; index < end; index++)
|
|
70
|
+
height += rows[index].length;
|
|
71
|
+
if (end < rows.length)
|
|
72
|
+
height++;
|
|
73
|
+
return height;
|
|
74
|
+
}
|