@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,160 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFileSync, statSync, watch } from 'node:fs';
|
|
3
|
+
import { basename, dirname } from 'node:path';
|
|
4
|
+
import { documentLines } from '../../../core/document-lines.js';
|
|
5
|
+
import { checkReviewableFile } from '../../../core/human/visible-paths.js';
|
|
6
|
+
/** The trailing delay used to collapse an editor's write/rename burst. */
|
|
7
|
+
export const COALESCE_MS = 120;
|
|
8
|
+
function hashText(text) {
|
|
9
|
+
return createHash('sha256').update(text, 'utf8').digest('hex');
|
|
10
|
+
}
|
|
11
|
+
function staleReasonFromCheck(reason) {
|
|
12
|
+
if (reason.includes('UTF-8'))
|
|
13
|
+
return 'binary';
|
|
14
|
+
if (reason.includes('too large') || reason.includes('too long'))
|
|
15
|
+
return 'too-large';
|
|
16
|
+
return 'unreadable';
|
|
17
|
+
}
|
|
18
|
+
function readSource(absFile) {
|
|
19
|
+
try {
|
|
20
|
+
const stat = statSync(absFile);
|
|
21
|
+
if (!stat.isFile())
|
|
22
|
+
return { status: 'stale', reason: 'missing' };
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
return {
|
|
26
|
+
status: 'stale',
|
|
27
|
+
reason: error.code === 'ENOENT' ? 'missing' : 'unreadable',
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const check = checkReviewableFile(absFile);
|
|
31
|
+
if (!check.ok) {
|
|
32
|
+
if (check.reason === 'not a file')
|
|
33
|
+
return { status: 'stale', reason: 'unreadable' };
|
|
34
|
+
return { status: 'stale', reason: staleReasonFromCheck(check.reason) };
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const text = readFileSync(absFile, 'utf8');
|
|
38
|
+
return {
|
|
39
|
+
status: 'live',
|
|
40
|
+
text,
|
|
41
|
+
sha256: hashText(text),
|
|
42
|
+
loadedAt: new Date().toISOString(),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return { status: 'stale', reason: 'unreadable' };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function initialSnapshot(absFile) {
|
|
50
|
+
const result = readSource(absFile);
|
|
51
|
+
if (result.status === 'stale') {
|
|
52
|
+
throw new Error(`Unable to open live source ${absFile}: ${result.reason}`);
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
text: result.text,
|
|
56
|
+
lines: documentLines(result.text),
|
|
57
|
+
revision: 0,
|
|
58
|
+
status: 'live',
|
|
59
|
+
sha256: result.sha256,
|
|
60
|
+
loadedAt: result.loadedAt,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** Watch the containing directory so atomic replacement of the file remains live. */
|
|
64
|
+
export function openLiveSource(absFile) {
|
|
65
|
+
let snapshot = initialSnapshot(absFile);
|
|
66
|
+
const openedText = snapshot.text;
|
|
67
|
+
const listeners = new Set();
|
|
68
|
+
const target = basename(absFile);
|
|
69
|
+
let watcher;
|
|
70
|
+
let timer;
|
|
71
|
+
let closed = false;
|
|
72
|
+
const refreshNow = () => {
|
|
73
|
+
if (closed)
|
|
74
|
+
return;
|
|
75
|
+
const result = readSource(absFile);
|
|
76
|
+
const previous = snapshot;
|
|
77
|
+
if (result.status === 'stale') {
|
|
78
|
+
const next = {
|
|
79
|
+
...previous,
|
|
80
|
+
status: 'stale',
|
|
81
|
+
staleReason: result.reason,
|
|
82
|
+
};
|
|
83
|
+
snapshot = next;
|
|
84
|
+
if (previous.status === next.status)
|
|
85
|
+
return;
|
|
86
|
+
for (const listener of listeners) {
|
|
87
|
+
if (!closed)
|
|
88
|
+
listener(next, previous);
|
|
89
|
+
}
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const textChanged = result.text !== previous.text;
|
|
93
|
+
const statusChanged = previous.status !== 'live';
|
|
94
|
+
const next = {
|
|
95
|
+
text: result.text,
|
|
96
|
+
lines: textChanged ? documentLines(result.text) : previous.lines,
|
|
97
|
+
revision: previous.revision + (textChanged ? 1 : 0),
|
|
98
|
+
status: 'live',
|
|
99
|
+
sha256: result.sha256,
|
|
100
|
+
loadedAt: textChanged || statusChanged ? result.loadedAt : previous.loadedAt,
|
|
101
|
+
};
|
|
102
|
+
snapshot = next;
|
|
103
|
+
if (!textChanged && !statusChanged)
|
|
104
|
+
return;
|
|
105
|
+
for (const listener of listeners) {
|
|
106
|
+
if (!closed)
|
|
107
|
+
listener(next, previous);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const scheduleRefresh = () => {
|
|
111
|
+
if (closed)
|
|
112
|
+
return;
|
|
113
|
+
if (timer !== undefined)
|
|
114
|
+
clearTimeout(timer);
|
|
115
|
+
timer = setTimeout(() => {
|
|
116
|
+
timer = undefined;
|
|
117
|
+
if (!closed)
|
|
118
|
+
refreshNow();
|
|
119
|
+
}, COALESCE_MS);
|
|
120
|
+
};
|
|
121
|
+
try {
|
|
122
|
+
watcher = watch(dirname(absFile), (_event, filename) => {
|
|
123
|
+
if (!closed && filename !== null && String(filename) === target)
|
|
124
|
+
scheduleRefresh();
|
|
125
|
+
});
|
|
126
|
+
watcher.on('error', () => {
|
|
127
|
+
// The next explicit refresh remains authoritative; a directory watcher
|
|
128
|
+
// error must not terminate the viewer process.
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// A source that was readable at open remains usable through refreshNow().
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
current: () => snapshot,
|
|
136
|
+
openText: () => openedText,
|
|
137
|
+
onChange: (fn) => {
|
|
138
|
+
if (!closed)
|
|
139
|
+
listeners.add(fn);
|
|
140
|
+
},
|
|
141
|
+
refreshNow,
|
|
142
|
+
close: () => {
|
|
143
|
+
if (closed)
|
|
144
|
+
return;
|
|
145
|
+
closed = true;
|
|
146
|
+
if (timer !== undefined) {
|
|
147
|
+
clearTimeout(timer);
|
|
148
|
+
timer = undefined;
|
|
149
|
+
}
|
|
150
|
+
listeners.clear();
|
|
151
|
+
try {
|
|
152
|
+
watcher?.close();
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
// Teardown is best effort when the watcher has already failed.
|
|
156
|
+
}
|
|
157
|
+
watcher = undefined;
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Open the reviewed file in the user's configured editor, optionally at a specific line.
|
|
3
|
+
* Resolves $VISUAL, then $EDITOR, then falls back to 'vi'.
|
|
4
|
+
* For vi-family editors (nvim, vim, vi, view), passes the line with the +line syntax.
|
|
5
|
+
* For other editors, opens the file without line positioning.
|
|
6
|
+
*
|
|
7
|
+
* @param absFile - Absolute path to the file to edit
|
|
8
|
+
* @param line - 1-based line number (only used for vi-family editors)
|
|
9
|
+
* @returns An object with an optional `error` property if the editor launch or execution failed
|
|
10
|
+
*/
|
|
11
|
+
export declare function openReviewedFileInEditor(absFile: string, line: number): {
|
|
12
|
+
error?: string;
|
|
13
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Open the reviewed file in the user's configured editor, optionally at a specific line.
|
|
4
|
+
* Resolves $VISUAL, then $EDITOR, then falls back to 'vi'.
|
|
5
|
+
* For vi-family editors (nvim, vim, vi, view), passes the line with the +line syntax.
|
|
6
|
+
* For other editors, opens the file without line positioning.
|
|
7
|
+
*
|
|
8
|
+
* @param absFile - Absolute path to the file to edit
|
|
9
|
+
* @param line - 1-based line number (only used for vi-family editors)
|
|
10
|
+
* @returns An object with an optional `error` property if the editor launch or execution failed
|
|
11
|
+
*/
|
|
12
|
+
export function openReviewedFileInEditor(absFile, line) {
|
|
13
|
+
const editor = process.env.VISUAL ?? process.env.EDITOR ?? 'vi';
|
|
14
|
+
// Extract the first shell token (the command itself)
|
|
15
|
+
const firstToken = editor.trim().split(/\s+/)[0];
|
|
16
|
+
if (!firstToken) {
|
|
17
|
+
return { error: 'editor configuration is empty' };
|
|
18
|
+
}
|
|
19
|
+
// Determine if this is a vi-family editor
|
|
20
|
+
const editorBasename = firstToken.split('/').pop() || firstToken;
|
|
21
|
+
const isViFamily = ['nvim', 'vim', 'vi', 'view'].includes(editorBasename);
|
|
22
|
+
// Build the command arguments
|
|
23
|
+
const args = isViFamily ? [`+${line}`, absFile] : [absFile];
|
|
24
|
+
try {
|
|
25
|
+
const result = spawnSync(firstToken, args, { stdio: 'inherit' });
|
|
26
|
+
// Check for errors
|
|
27
|
+
if (result.error) {
|
|
28
|
+
return { error: result.error.message };
|
|
29
|
+
}
|
|
30
|
+
if (result.signal !== null) {
|
|
31
|
+
return { error: `editor was killed by signal ${result.signal}` };
|
|
32
|
+
}
|
|
33
|
+
if (result.status !== 0) {
|
|
34
|
+
return { error: `editor exited with code ${result.status}` };
|
|
35
|
+
}
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
40
|
+
return { error: message };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line-based range remapping with whole-line LCS.
|
|
3
|
+
*
|
|
4
|
+
* Normalizes lines, trims common prefix/suffix, applies monotone LCS to the
|
|
5
|
+
* middle section, and builds a stable mapping from old→new line numbers.
|
|
6
|
+
* Remapped ranges become detached when no line survives, shifted when partly
|
|
7
|
+
* deleted, or kept when both endpoints are unmoved.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* A monotone partial mapping from old line numbers to new ones (both 0-based).
|
|
11
|
+
* Returns undefined when a line was deleted.
|
|
12
|
+
*/
|
|
13
|
+
export interface LineMap {
|
|
14
|
+
get(oldLine: number): number | undefined;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The result of remapping a range: kept (unmoved), shifted (partially survived),
|
|
18
|
+
* or detached (no lines survived).
|
|
19
|
+
*/
|
|
20
|
+
export type RemapResult = {
|
|
21
|
+
kind: 'kept';
|
|
22
|
+
line: number;
|
|
23
|
+
endLine: number;
|
|
24
|
+
} | {
|
|
25
|
+
kind: 'shifted';
|
|
26
|
+
line: number;
|
|
27
|
+
endLine: number;
|
|
28
|
+
} | {
|
|
29
|
+
kind: 'detached';
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Build a monotone line-number mapping from old→new using LCS.
|
|
33
|
+
*
|
|
34
|
+
* - Normalizes all lines using D14: `line.replace(/\s+/g, ' ').trim()`
|
|
35
|
+
* - Trims common prefix and suffix before LCS
|
|
36
|
+
* - Applies whole-line LCS to the middle section
|
|
37
|
+
* - Returns a map where `get(oldLine)` is the new line number or undefined
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildLineMap(oldLines: readonly string[], newLines: readonly string[]): LineMap;
|
|
40
|
+
/**
|
|
41
|
+
* Remap a range [line, endLine) using the built LineMap.
|
|
42
|
+
*
|
|
43
|
+
* Returns:
|
|
44
|
+
* - `kept`: both endpoints are unmoved
|
|
45
|
+
* - `shifted`: the range is partially deleted; maps to the min/max of survivors
|
|
46
|
+
* - `detached`: no lines from the range survived
|
|
47
|
+
*/
|
|
48
|
+
export declare function remapRange(map: LineMap, range: {
|
|
49
|
+
line: number;
|
|
50
|
+
endLine: number;
|
|
51
|
+
}): RemapResult;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Line-based range remapping with whole-line LCS.
|
|
3
|
+
*
|
|
4
|
+
* Normalizes lines, trims common prefix/suffix, applies monotone LCS to the
|
|
5
|
+
* middle section, and builds a stable mapping from old→new line numbers.
|
|
6
|
+
* Remapped ranges become detached when no line survives, shifted when partly
|
|
7
|
+
* deleted, or kept when both endpoints are unmoved.
|
|
8
|
+
*/
|
|
9
|
+
/** Normalize a line for comparison: collapse whitespace and trim. */
|
|
10
|
+
function normalizeLine(line) {
|
|
11
|
+
return line.replace(/\s+/g, ' ').trim();
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Build a monotone line-number mapping from old→new using LCS.
|
|
15
|
+
*
|
|
16
|
+
* - Normalizes all lines using D14: `line.replace(/\s+/g, ' ').trim()`
|
|
17
|
+
* - Trims common prefix and suffix before LCS
|
|
18
|
+
* - Applies whole-line LCS to the middle section
|
|
19
|
+
* - Returns a map where `get(oldLine)` is the new line number or undefined
|
|
20
|
+
*/
|
|
21
|
+
export function buildLineMap(oldLines, newLines) {
|
|
22
|
+
// Normalize all lines once
|
|
23
|
+
const oldNorm = oldLines.map(normalizeLine);
|
|
24
|
+
const newNorm = newLines.map(normalizeLine);
|
|
25
|
+
// Find common prefix length
|
|
26
|
+
let prefixLen = 0;
|
|
27
|
+
const minPrefix = Math.min(oldNorm.length, newNorm.length);
|
|
28
|
+
while (prefixLen < minPrefix &&
|
|
29
|
+
oldNorm[prefixLen] === newNorm[prefixLen]) {
|
|
30
|
+
prefixLen++;
|
|
31
|
+
}
|
|
32
|
+
// Find common suffix length
|
|
33
|
+
let suffixLen = 0;
|
|
34
|
+
const minSuffix = Math.min(oldNorm.length - prefixLen, newNorm.length - prefixLen);
|
|
35
|
+
while (suffixLen < minSuffix &&
|
|
36
|
+
oldNorm[oldNorm.length - 1 - suffixLen] ===
|
|
37
|
+
newNorm[newNorm.length - 1 - suffixLen]) {
|
|
38
|
+
suffixLen++;
|
|
39
|
+
}
|
|
40
|
+
// Extract middle sections for LCS
|
|
41
|
+
const oldMiddleEnd = oldNorm.length - suffixLen;
|
|
42
|
+
const newMiddleEnd = newNorm.length - suffixLen;
|
|
43
|
+
const oldMiddle = oldNorm.slice(prefixLen, oldMiddleEnd);
|
|
44
|
+
const newMiddle = newNorm.slice(prefixLen, newMiddleEnd);
|
|
45
|
+
// Compute LCS on the middle section
|
|
46
|
+
const lcsMap = computeLCS(oldMiddle, newMiddle);
|
|
47
|
+
// Build the final map: prefix + lcsMap + suffix
|
|
48
|
+
const map = new Map();
|
|
49
|
+
// Common prefix: identity mapping
|
|
50
|
+
for (let i = 0; i < prefixLen; i++) {
|
|
51
|
+
map.set(i, i);
|
|
52
|
+
}
|
|
53
|
+
// Middle section from LCS
|
|
54
|
+
lcsMap.forEach((newIdx, oldIdx) => {
|
|
55
|
+
map.set(prefixLen + oldIdx, prefixLen + newIdx);
|
|
56
|
+
});
|
|
57
|
+
// Common suffix: offset identity mapping
|
|
58
|
+
for (let i = 0; i < suffixLen; i++) {
|
|
59
|
+
const oldLine = oldMiddleEnd + i;
|
|
60
|
+
const newLine = newMiddleEnd + i;
|
|
61
|
+
map.set(oldLine, newLine);
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
get(oldLine) {
|
|
65
|
+
return map.get(oldLine);
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Compute LCS (Longest Common Subsequence) as a monotone mapping of old→new indices.
|
|
71
|
+
* Uses dynamic programming to find matching lines and returns only the matching pairs.
|
|
72
|
+
*
|
|
73
|
+
* For optimal whole-line matching, we want the longest common subsequence
|
|
74
|
+
* of line indices, preserving the relative order in both sequences.
|
|
75
|
+
*/
|
|
76
|
+
function computeLCS(oldLines, newLines) {
|
|
77
|
+
const m = oldLines.length;
|
|
78
|
+
const n = newLines.length;
|
|
79
|
+
if (m === 0 || n === 0) {
|
|
80
|
+
return new Map();
|
|
81
|
+
}
|
|
82
|
+
// DP table: dp[i][j] = length of LCS for oldLines[0..i-1] and newLines[0..j-1]
|
|
83
|
+
const dp = Array(m + 1)
|
|
84
|
+
.fill(null)
|
|
85
|
+
.map(() => Array(n + 1).fill(0));
|
|
86
|
+
for (let i = 1; i <= m; i++) {
|
|
87
|
+
for (let j = 1; j <= n; j++) {
|
|
88
|
+
if (oldLines[i - 1] === newLines[j - 1]) {
|
|
89
|
+
dp[i][j] = dp[i - 1][j - 1] + 1;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Backtrack to find the LCS and build the mapping
|
|
97
|
+
const matches = new Map();
|
|
98
|
+
let i = m;
|
|
99
|
+
let j = n;
|
|
100
|
+
while (i > 0 && j > 0) {
|
|
101
|
+
if (oldLines[i - 1] === newLines[j - 1]) {
|
|
102
|
+
// Match found
|
|
103
|
+
matches.set(i - 1, j - 1);
|
|
104
|
+
i--;
|
|
105
|
+
j--;
|
|
106
|
+
}
|
|
107
|
+
else if (dp[i - 1][j] > dp[i][j - 1]) {
|
|
108
|
+
// oldLines[i-1] was deleted
|
|
109
|
+
i--;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// newLines[j-1] was inserted
|
|
113
|
+
j--;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return matches;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Remap a range [line, endLine) using the built LineMap.
|
|
120
|
+
*
|
|
121
|
+
* Returns:
|
|
122
|
+
* - `kept`: both endpoints are unmoved
|
|
123
|
+
* - `shifted`: the range is partially deleted; maps to the min/max of survivors
|
|
124
|
+
* - `detached`: no lines from the range survived
|
|
125
|
+
*/
|
|
126
|
+
export function remapRange(map, range) {
|
|
127
|
+
const oldStart = range.line;
|
|
128
|
+
const oldEnd = range.endLine;
|
|
129
|
+
// Collect all surviving line numbers in the old range
|
|
130
|
+
let minNew;
|
|
131
|
+
let maxNew;
|
|
132
|
+
for (let oldLine = oldStart; oldLine < oldEnd; oldLine++) {
|
|
133
|
+
const newLine = map.get(oldLine);
|
|
134
|
+
if (newLine !== undefined) {
|
|
135
|
+
if (minNew === undefined || newLine < minNew) {
|
|
136
|
+
minNew = newLine;
|
|
137
|
+
}
|
|
138
|
+
if (maxNew === undefined || newLine > maxNew) {
|
|
139
|
+
maxNew = newLine;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (minNew === undefined) {
|
|
144
|
+
return { kind: 'detached' };
|
|
145
|
+
}
|
|
146
|
+
// Check if both endpoints were preserved in their exact positions
|
|
147
|
+
const startSurvived = map.get(oldStart);
|
|
148
|
+
const endSurvived = map.get(oldEnd - 1);
|
|
149
|
+
if (startSurvived === oldStart && endSurvived === oldEnd - 1) {
|
|
150
|
+
return { kind: 'kept', line: startSurvived, endLine: endSurvived + 1 };
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
kind: 'shifted',
|
|
154
|
+
line: minNew,
|
|
155
|
+
endLine: maxNew + 1,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare class ReviewTerminalError extends Error {
|
|
2
|
+
readonly state: 'approved' | 'canceled';
|
|
3
|
+
readonly resultPath?: string;
|
|
4
|
+
readonly reason?: string;
|
|
5
|
+
constructor(state: 'approved', resultPath: string);
|
|
6
|
+
constructor(state: 'canceled', reason?: string);
|
|
7
|
+
}
|
|
8
|
+
export interface OpenedReview {
|
|
9
|
+
reviewId: string;
|
|
10
|
+
companionNodeId: string;
|
|
11
|
+
file: string;
|
|
12
|
+
cwd: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ReviewClient {
|
|
15
|
+
open(reviewId: string): Promise<OpenedReview>;
|
|
16
|
+
byBridge(bridgeNodeId: string): Promise<{
|
|
17
|
+
reviewId: string;
|
|
18
|
+
}>;
|
|
19
|
+
createInline(p: {
|
|
20
|
+
originNodeId: string;
|
|
21
|
+
file: string;
|
|
22
|
+
}): Promise<OpenedReview>;
|
|
23
|
+
submit(reviewId: string): Promise<{
|
|
24
|
+
changed: boolean;
|
|
25
|
+
resultPath: string;
|
|
26
|
+
}>;
|
|
27
|
+
cancel(reviewId: string, reason: string): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
/** The terminal's complete daemon seam for review lifecycle operations. */
|
|
30
|
+
export declare function createReviewClient(): ReviewClient;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { ApiError } from '../../../api/errors.js';
|
|
3
|
+
import { cliClient } from '../../../commands/api-client.js';
|
|
4
|
+
export class ReviewTerminalError extends Error {
|
|
5
|
+
state;
|
|
6
|
+
resultPath;
|
|
7
|
+
reason;
|
|
8
|
+
constructor(state, detail) {
|
|
9
|
+
if (state === 'approved') {
|
|
10
|
+
if (detail === undefined || detail === '')
|
|
11
|
+
throw new Error('approved review omitted its canonical result path');
|
|
12
|
+
super(`review is already approved; see ${detail}`);
|
|
13
|
+
this.resultPath = detail;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
super(detail === undefined || detail === '' ? 'review is already canceled' : `review is already canceled: ${detail}`);
|
|
17
|
+
if (detail !== undefined && detail !== '')
|
|
18
|
+
this.reason = detail;
|
|
19
|
+
}
|
|
20
|
+
this.name = 'ReviewTerminalError';
|
|
21
|
+
this.state = state;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/** The terminal's complete daemon seam for review lifecycle operations. */
|
|
25
|
+
export function createReviewClient() {
|
|
26
|
+
return {
|
|
27
|
+
async open(reviewId) {
|
|
28
|
+
try {
|
|
29
|
+
const opened = await cliClient().openReview(reviewId);
|
|
30
|
+
if (opened.disposition === 'terminal')
|
|
31
|
+
throw terminalError(opened.review);
|
|
32
|
+
return await openedReview(opened.review, opened.companion_node_id);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
throw terminalErrorFromApi(error);
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
async byBridge(bridgeNodeId) {
|
|
39
|
+
const review = await cliClient().getReviewByBridge(bridgeNodeId);
|
|
40
|
+
return { reviewId: review.review_id };
|
|
41
|
+
},
|
|
42
|
+
async createInline(p) {
|
|
43
|
+
const review = await cliClient().createReview({
|
|
44
|
+
origin_kind: 'inline',
|
|
45
|
+
origin_node_id: p.originNodeId,
|
|
46
|
+
file: p.file,
|
|
47
|
+
idempotency_key: randomUUID(),
|
|
48
|
+
});
|
|
49
|
+
return await openedReview(review, review.companion_node_id);
|
|
50
|
+
},
|
|
51
|
+
async submit(reviewId) {
|
|
52
|
+
const submitted = await cliClient().submitReview(reviewId);
|
|
53
|
+
return {
|
|
54
|
+
changed: requireChanged(submitted.review),
|
|
55
|
+
resultPath: requireResultPath(submitted.review),
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
async cancel(reviewId, reason) {
|
|
59
|
+
await cliClient().cancelReview(reviewId, { reason, actor: 'human' });
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async function openedReview(review, companionNodeId) {
|
|
64
|
+
if (review.state !== 'open')
|
|
65
|
+
throw terminalError(review);
|
|
66
|
+
const companion = await cliClient().getNode(companionNodeId);
|
|
67
|
+
return {
|
|
68
|
+
reviewId: review.review_id,
|
|
69
|
+
companionNodeId,
|
|
70
|
+
file: review.file,
|
|
71
|
+
cwd: companion.cwd,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function terminalErrorFromApi(error) {
|
|
75
|
+
if (!(error instanceof ApiError) || error.status !== 409 || error.code !== 'review_terminal_conflict')
|
|
76
|
+
return error;
|
|
77
|
+
const review = error.details?.review;
|
|
78
|
+
if (!isTerminalReview(review))
|
|
79
|
+
return error;
|
|
80
|
+
return terminalError(review);
|
|
81
|
+
}
|
|
82
|
+
function terminalError(review) {
|
|
83
|
+
if (review.state !== 'approved' && review.state !== 'canceled') {
|
|
84
|
+
throw new Error(`terminal review ${review.review_id} has invalid state ${review.state}`);
|
|
85
|
+
}
|
|
86
|
+
return review.state === 'approved'
|
|
87
|
+
? new ReviewTerminalError('approved', requireResultPath(review))
|
|
88
|
+
: new ReviewTerminalError('canceled', review.cancel_reason);
|
|
89
|
+
}
|
|
90
|
+
function requireChanged(review) {
|
|
91
|
+
if (typeof review.changed !== 'boolean') {
|
|
92
|
+
throw new Error(`approved review ${review.review_id} omitted its changed disposition`);
|
|
93
|
+
}
|
|
94
|
+
return review.changed;
|
|
95
|
+
}
|
|
96
|
+
function requireResultPath(review) {
|
|
97
|
+
if (typeof review.result_path !== 'string' || review.result_path === '') {
|
|
98
|
+
throw new Error(`terminal review ${review.review_id} omitted its canonical result path`);
|
|
99
|
+
}
|
|
100
|
+
return review.result_path;
|
|
101
|
+
}
|
|
102
|
+
function isTerminalReview(value) {
|
|
103
|
+
if (typeof value !== 'object' || value === null)
|
|
104
|
+
return false;
|
|
105
|
+
const state = value.state;
|
|
106
|
+
return state === 'approved' || state === 'canceled';
|
|
107
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
/** Run $EDITOR against a temporary buffer. Terminal ownership stays with the host. */
|
|
7
|
+
export function editBufferInEditor(buffer) {
|
|
8
|
+
const tmpFile = join(tmpdir(), `crtr-input-${randomUUID()}.txt`);
|
|
9
|
+
const editor = process.env.EDITOR || 'vi';
|
|
10
|
+
try {
|
|
11
|
+
writeFileSync(tmpFile, buffer);
|
|
12
|
+
// $EDITOR may be a shell fragment such as "code --wait".
|
|
13
|
+
const result = spawnSync('/bin/sh', ['-c', `${editor} "$1"`, 'sh', tmpFile], { stdio: 'inherit' });
|
|
14
|
+
if (result.error)
|
|
15
|
+
return { text: buffer, error: `$EDITOR ("${editor}") failed to launch: ${result.error.message}` };
|
|
16
|
+
if (result.signal !== null)
|
|
17
|
+
return { text: buffer, error: `$EDITOR ("${editor}") was killed by signal ${result.signal}` };
|
|
18
|
+
if (result.status === 127 || result.status === 126)
|
|
19
|
+
return { text: buffer, error: `$EDITOR ("${editor}") failed to launch (shell exit ${result.status})` };
|
|
20
|
+
if (result.status !== 0)
|
|
21
|
+
return { text: buffer, error: `$EDITOR ("${editor}") exited with status ${result.status}` };
|
|
22
|
+
let text = readFileSync(tmpFile, 'utf8');
|
|
23
|
+
if (text.endsWith('\n') && !buffer.endsWith('\n'))
|
|
24
|
+
text = text.slice(0, -1);
|
|
25
|
+
return { text };
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
return { text: buffer, error: `$EDITOR round-trip failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
try {
|
|
32
|
+
unlinkSync(tmpFile);
|
|
33
|
+
}
|
|
34
|
+
catch { /* best-effort cleanup */ }
|
|
35
|
+
}
|
|
36
|
+
}
|