@crouton-kit/crouter 0.3.32 → 0.3.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/build-root.js +1 -0
- package/dist/builtin-memory/crouter-development/marketplaces.md +2 -2
- package/dist/builtin-memory/crouter-development/personas/base-prompt.md +2 -2
- package/dist/builtin-memory/crouter-development/personas/orchestrator-prompt.md +5 -5
- package/dist/builtin-memory/crouter-development/personas.md +3 -4
- package/dist/builtin-memory/crouter-development/plugins.md +18 -18
- package/dist/builtin-memory/design.md +4 -1
- package/dist/builtin-memory/development.md +4 -1
- package/dist/builtin-memory/internal/INDEX.md +1 -1
- package/dist/builtin-memory/internal/nodes-and-canvas.md +6 -6
- package/dist/builtin-memory/internal/storage-tiers.md +5 -5
- package/dist/builtin-memory/planning.md +4 -1
- package/dist/builtin-memory/product.md +80 -0
- package/dist/builtin-memory/spec.md +4 -1
- package/dist/builtin-personas/advisor/PERSONA.md +10 -0
- package/dist/builtin-personas/design/PERSONA.md +2 -2
- package/dist/builtin-personas/design/orchestrator.md +3 -3
- package/dist/builtin-personas/developer/PERSONA.md +1 -1
- package/dist/builtin-personas/developer/orchestrator.md +2 -2
- package/dist/builtin-personas/explore/PERSONA.md +3 -3
- package/dist/builtin-personas/explore/orchestrator.md +4 -2
- package/dist/builtin-personas/general/PERSONA.md +1 -1
- package/dist/builtin-personas/general/orchestrator.md +1 -1
- package/dist/builtin-personas/orchestration-kernel.md +7 -14
- package/dist/builtin-personas/plan/PERSONA.md +1 -1
- package/dist/builtin-personas/plan/orchestrator.md +2 -2
- package/dist/builtin-personas/plan/reviewers/architecture-fit/PERSONA.md +1 -1
- package/dist/builtin-personas/plan/reviewers/code-smells/PERSONA.md +1 -1
- package/dist/builtin-personas/plan/reviewers/pattern-consistency/PERSONA.md +1 -1
- package/dist/builtin-personas/plan/reviewers/requirements-coverage/PERSONA.md +1 -1
- package/dist/builtin-personas/plan/reviewers/security/PERSONA.md +1 -1
- package/dist/builtin-personas/product/PERSONA.md +18 -0
- package/dist/builtin-personas/product/orchestrator.md +14 -0
- package/dist/builtin-personas/product/teardown/PERSONA.md +13 -0
- package/dist/builtin-personas/review/PERSONA.md +1 -1
- package/dist/builtin-personas/review/orchestrator.md +1 -1
- package/dist/builtin-personas/runtime-base.md +5 -0
- package/dist/builtin-personas/spec/PERSONA.md +1 -1
- package/dist/builtin-personas/spec/orchestrator.md +2 -2
- package/dist/builtin-personas/spec/requirements/PERSONA.md +1 -1
- package/dist/builtin-views/canvas/core.mjs +82 -1
- package/dist/builtin-views/canvas/tui.mjs +9 -5
- package/dist/builtin-views/canvas/web.jsx +3 -2
- package/dist/builtin-views/chat/core.mjs +725 -0
- package/dist/builtin-views/chat/text.mjs +101 -0
- package/dist/builtin-views/chat/tui.mjs +368 -0
- package/dist/builtin-views/chat/web.jsx +367 -0
- package/dist/builtin-views/prompt-review/core.mjs +863 -0
- package/dist/builtin-views/prompt-review/text.mjs +15 -0
- package/dist/builtin-views/prompt-review/tui.mjs +196 -0
- package/dist/builtin-views/prompt-review/web.jsx +484 -0
- package/dist/builtin-views/settings/core.mjs +397 -0
- package/dist/builtin-views/settings/text.mjs +40 -0
- package/dist/builtin-views/settings/tui.mjs +95 -0
- package/dist/builtin-views/settings/web.jsx +167 -0
- package/dist/cli.js +16 -3
- package/dist/clients/attach/__tests__/autocomplete-and-bash-mode.test.js +96 -0
- package/dist/clients/attach/__tests__/bash-bang-routing.test.js +58 -0
- package/dist/clients/attach/__tests__/bundle-pi-tui-dedup.test.d.ts +1 -0
- package/dist/clients/attach/__tests__/bundle-pi-tui-dedup.test.js +56 -0
- package/dist/clients/attach/__tests__/titled-editor.test.js +22 -1
- package/dist/clients/attach/attach-cmd.d.ts +18 -0
- package/dist/clients/attach/attach-cmd.js +1723 -795
- package/dist/clients/attach/canvas-panels.js +2 -2
- package/dist/clients/attach/chat-view.d.ts +10 -0
- package/dist/clients/attach/chat-view.js +23 -0
- package/dist/clients/attach/config-load.d.ts +8 -4
- package/dist/clients/attach/config-load.js +2 -0
- package/dist/clients/attach/extension-dialogs.d.ts +2 -3
- package/dist/clients/attach/extension-dialogs.js +7 -9
- package/dist/clients/attach/graph-overlay.js +3 -2
- package/dist/clients/attach/input-controller.d.ts +4 -3
- package/dist/clients/attach/input-controller.js +24 -3
- package/dist/clients/attach/slash-commands.d.ts +7 -7
- package/dist/clients/attach/slash-commands.js +38 -14
- package/dist/clients/attach/titled-editor.js +18 -14
- package/dist/clients/attach/view-socket.d.ts +2 -1
- package/dist/clients/attach/view-socket.js +27 -8
- package/dist/clients/web/__tests__/source-cache.test.d.ts +1 -0
- package/dist/clients/web/__tests__/source-cache.test.js +32 -0
- package/dist/clients/web/dev-server.js +1 -0
- package/dist/clients/web/events.js +9 -11
- package/dist/clients/web/server.d.ts +4 -3
- package/dist/clients/web/server.js +138 -31
- package/dist/clients/web/source-cache.d.ts +10 -0
- package/dist/clients/web/source-cache.js +57 -0
- package/dist/clients/web/web-cmd.js +28 -9
- package/dist/commands/__tests__/human.test.js +30 -28
- package/dist/commands/canvas-history/search.js +1 -1
- package/dist/commands/canvas-history.js +5 -8
- package/dist/commands/canvas-issue.d.ts +2 -0
- package/dist/commands/canvas-issue.js +148 -0
- package/dist/commands/canvas-prune.js +19 -0
- package/dist/commands/canvas-rebuild-index.d.ts +2 -0
- package/dist/commands/canvas-rebuild-index.js +57 -0
- package/dist/commands/canvas-snapshot.d.ts +2 -0
- package/dist/commands/canvas-snapshot.js +48 -0
- package/dist/commands/canvas-tmux-spread.d.ts +2 -0
- package/dist/commands/canvas-tmux-spread.js +188 -0
- package/dist/commands/canvas.d.ts +1 -0
- package/dist/commands/canvas.js +16 -1
- package/dist/commands/chord.js +143 -48
- package/dist/commands/daemon.js +3 -3
- package/dist/commands/human/prompts.d.ts +0 -1
- package/dist/commands/human/prompts.js +39 -54
- package/dist/commands/human/queue.d.ts +12 -1
- package/dist/commands/human/queue.js +468 -73
- package/dist/commands/human/shared.d.ts +3 -4
- package/dist/commands/human/shared.js +3 -3
- package/dist/commands/human.js +11 -10
- package/dist/commands/memory/find.js +3 -2
- package/dist/commands/memory/list.js +4 -3
- package/dist/commands/memory/read.js +3 -3
- package/dist/commands/memory/shared.d.ts +1 -4
- package/dist/commands/memory/shared.js +6 -9
- package/dist/commands/memory/write.js +3 -3
- package/dist/commands/memory.js +4 -7
- package/dist/commands/node-context.d.ts +2 -0
- package/dist/commands/node-context.js +172 -0
- package/dist/commands/node-snapshot.d.ts +2 -0
- package/dist/commands/node-snapshot.js +123 -0
- package/dist/commands/node.js +228 -52
- package/dist/commands/pkg/plugin-inspect.js +6 -6
- package/dist/commands/pkg/plugin-manage.js +1 -1
- package/dist/commands/pkg/plugin.js +2 -2
- package/dist/commands/pkg.js +2 -2
- package/dist/commands/push.d.ts +2 -0
- package/dist/commands/push.js +79 -11
- package/dist/commands/revive.js +74 -1
- package/dist/commands/search/answer.d.ts +1 -0
- package/dist/commands/search/answer.js +50 -0
- package/dist/commands/search/contents.d.ts +1 -0
- package/dist/commands/search/contents.js +96 -0
- package/dist/commands/search/exa.d.ts +53 -0
- package/dist/commands/search/exa.js +155 -0
- package/dist/commands/search/puremd.d.ts +11 -0
- package/dist/commands/search/puremd.js +53 -0
- package/dist/commands/search/web.d.ts +1 -0
- package/dist/commands/search/web.js +65 -0
- package/dist/commands/search.d.ts +2 -0
- package/dist/commands/search.js +24 -0
- package/dist/commands/sys/__tests__/sync-import.test.d.ts +1 -0
- package/dist/commands/sys/__tests__/sync-import.test.js +72 -0
- package/dist/commands/sys/config.js +59 -10
- package/dist/commands/sys/doctor.js +56 -4
- package/dist/commands/sys/prompt-review.d.ts +1 -0
- package/dist/commands/sys/prompt-review.js +178 -0
- package/dist/commands/sys/promptstudio.d.ts +2 -0
- package/dist/commands/sys/promptstudio.js +65 -0
- package/dist/commands/sys/settings.d.ts +2 -0
- package/dist/commands/sys/settings.js +16 -0
- package/dist/commands/sys/sync.js +311 -159
- package/dist/commands/sys/sysprompt.d.ts +1 -0
- package/dist/commands/sys/sysprompt.js +86 -0
- package/dist/commands/sys.js +9 -5
- package/dist/commands/view-new.js +2 -2
- package/dist/core/__tests__/artifact-paths.test.d.ts +1 -0
- package/dist/core/__tests__/artifact-paths.test.js +44 -0
- package/dist/core/__tests__/broker-preflight.test.d.ts +1 -0
- package/dist/core/__tests__/broker-preflight.test.js +85 -0
- package/dist/core/__tests__/broker-sdk-wiring.test.js +15 -0
- package/dist/core/__tests__/canvas.test.js +37 -1
- package/dist/core/__tests__/chat-view-reconnect.test.d.ts +1 -0
- package/dist/core/__tests__/chat-view-reconnect.test.js +70 -0
- package/dist/core/__tests__/child-death-wake.test.js +11 -2
- package/dist/core/__tests__/close.test.js +39 -1
- package/dist/core/__tests__/connection-reconnect-resume.test.d.ts +1 -0
- package/dist/core/__tests__/connection-reconnect-resume.test.js +37 -0
- package/dist/core/__tests__/context-intro.test.js +48 -14
- package/dist/core/__tests__/daemon-boot.test.js +182 -9
- package/dist/core/__tests__/editor-label.test.d.ts +1 -0
- package/dist/core/__tests__/editor-label.test.js +26 -0
- package/dist/core/__tests__/fault-marker.test.d.ts +1 -0
- package/dist/core/__tests__/fault-marker.test.js +112 -0
- package/dist/core/__tests__/fault-retry-rewind.test.d.ts +1 -0
- package/dist/core/__tests__/fault-retry-rewind.test.js +123 -0
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +30 -4
- package/dist/core/__tests__/fixtures/fake-engine.js +156 -17
- package/dist/core/__tests__/fixtures/fake-pi-host.js +10 -1
- package/dist/core/__tests__/full/human-new-window-regression.test.js +1 -1
- package/dist/core/__tests__/helpers/harness.d.ts +1 -1
- package/dist/core/__tests__/helpers/harness.js +2 -2
- package/dist/core/__tests__/human-stranded-deliver.test.js +38 -1
- package/dist/core/__tests__/human-surface-target.test.js +1 -1
- package/dist/core/__tests__/kickoff.test.js +18 -19
- package/dist/core/__tests__/memory-resolver.test.js +12 -1
- package/dist/core/__tests__/migration.test.js +49 -14
- package/dist/core/__tests__/model-ladders.test.d.ts +1 -0
- package/dist/core/__tests__/model-ladders.test.js +160 -0
- package/dist/core/__tests__/node-env.test.d.ts +1 -0
- package/dist/core/__tests__/node-env.test.js +26 -0
- package/dist/core/__tests__/push-final-guard.test.js +7 -1
- package/dist/core/__tests__/relaunch-root.test.js +9 -9
- package/dist/core/__tests__/revive.test.js +36 -6
- package/dist/core/__tests__/spawn-root.test.js +24 -1
- package/dist/core/__tests__/stop-guard.test.js +10 -0
- package/dist/core/__tests__/stranded-relaunch.test.d.ts +1 -0
- package/dist/core/__tests__/stranded-relaunch.test.js +72 -0
- package/dist/core/__tests__/tmux-surface.test.js +5 -1
- package/dist/core/__tests__/unknown-path.test.js +19 -19
- package/dist/core/__tests__/yield-ensures-daemon.test.d.ts +1 -0
- package/dist/core/__tests__/yield-ensures-daemon.test.js +54 -0
- package/dist/core/artifact.d.ts +2 -33
- package/dist/core/artifact.js +27 -87
- package/dist/core/bootstrap.js +2 -0
- package/dist/core/canvas/browse/__tests__/model.test.js +35 -1
- package/dist/core/canvas/browse/app.js +87 -17
- package/dist/core/canvas/browse/model.d.ts +10 -1
- package/dist/core/canvas/browse/model.js +37 -1
- package/dist/core/canvas/browse/render.js +35 -33
- package/dist/core/canvas/canvas.d.ts +7 -0
- package/dist/core/canvas/canvas.js +54 -5
- package/dist/core/canvas/db.js +35 -8
- package/dist/core/canvas/labels.d.ts +6 -8
- package/dist/core/canvas/labels.js +8 -11
- package/dist/core/canvas/nav-model.d.ts +5 -4
- package/dist/core/canvas/nav-model.js +31 -17
- package/dist/core/canvas/paths.d.ts +18 -1
- package/dist/core/canvas/paths.js +31 -2
- package/dist/core/canvas/render.d.ts +25 -0
- package/dist/core/canvas/render.js +96 -13
- package/dist/core/canvas/status-glyph.d.ts +35 -0
- package/dist/core/canvas/status-glyph.js +104 -0
- package/dist/core/canvas/types.d.ts +2 -2
- package/dist/core/config.js +114 -16
- package/dist/core/fault-classifier.d.ts +41 -0
- package/dist/core/fault-classifier.js +110 -0
- package/dist/core/feed/inbox.d.ts +15 -0
- package/dist/core/feed/inbox.js +40 -14
- package/dist/core/frontmatter.d.ts +1 -11
- package/dist/core/frontmatter.js +1 -55
- package/dist/core/hearth/config.d.ts +2 -0
- package/dist/core/hearth/config.js +75 -0
- package/dist/core/hearth/guest-env.d.ts +2 -0
- package/dist/core/hearth/guest-env.js +11 -0
- package/dist/core/hearth/index.d.ts +5 -0
- package/dist/core/hearth/index.js +5 -0
- package/dist/core/hearth/provider.d.ts +21 -0
- package/dist/core/hearth/provider.js +10 -0
- package/dist/core/hearth/providers/blaxel-bootstrap.d.ts +10 -0
- package/dist/core/hearth/providers/blaxel-bootstrap.js +39 -0
- package/dist/core/hearth/providers/blaxel-home.d.ts +11 -0
- package/dist/core/hearth/providers/blaxel-home.js +126 -0
- package/dist/core/hearth/providers/blaxel.d.ts +26 -0
- package/dist/core/hearth/providers/blaxel.js +208 -0
- package/dist/core/hearth/providers/types.d.ts +72 -0
- package/dist/core/hearth/providers/types.js +1 -0
- package/dist/core/hearth/registry.d.ts +15 -0
- package/dist/core/hearth/registry.js +179 -0
- package/dist/core/hearth/types.d.ts +121 -0
- package/dist/core/hearth/types.js +1 -0
- package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.d.ts +1 -0
- package/dist/core/host-exports/__tests__/export-prunes-boot-skill.test.js +79 -0
- package/dist/core/{skill-sync → host-exports}/builtins.d.ts +21 -13
- package/dist/core/host-exports/builtins.js +68 -0
- package/dist/core/{skill-sync → host-exports}/export.d.ts +9 -6
- package/dist/core/{skill-sync → host-exports}/export.js +37 -14
- package/dist/core/io.js +1 -1
- package/dist/core/log.d.ts +9 -0
- package/dist/core/log.js +113 -0
- package/dist/core/memory-resolver.d.ts +8 -8
- package/dist/core/memory-resolver.js +15 -28
- package/dist/core/personas/index.d.ts +4 -4
- package/dist/core/personas/index.js +2 -2
- package/dist/core/personas/loader.d.ts +51 -0
- package/dist/core/personas/loader.js +54 -50
- package/dist/core/personas/resolve.d.ts +43 -27
- package/dist/core/personas/resolve.js +336 -94
- package/dist/core/runtime/auth-reload.d.ts +7 -0
- package/dist/core/runtime/auth-reload.js +69 -0
- package/dist/core/runtime/bearings.d.ts +35 -15
- package/dist/core/runtime/bearings.js +305 -44
- package/dist/core/runtime/branded-host.d.ts +4 -2
- package/dist/core/runtime/branded-host.js +66 -4
- package/dist/core/runtime/broker-protocol.d.ts +38 -3
- package/dist/core/runtime/broker.js +343 -18
- package/dist/core/runtime/close.js +37 -29
- package/dist/core/runtime/connectivity.d.ts +12 -0
- package/dist/core/runtime/connectivity.js +73 -0
- package/dist/core/runtime/fault-recovery-nudge.d.ts +2 -0
- package/dist/core/runtime/fault-recovery-nudge.js +2 -0
- package/dist/core/runtime/fault-recovery.d.ts +23 -0
- package/dist/core/runtime/fault-recovery.js +74 -0
- package/dist/core/runtime/fault.d.ts +25 -0
- package/dist/core/runtime/fault.js +176 -0
- package/dist/core/runtime/front-door.d.ts +1 -1
- package/dist/core/runtime/front-door.js +2 -2
- package/dist/core/runtime/host.d.ts +10 -0
- package/dist/core/runtime/host.js +71 -9
- package/dist/core/runtime/kickoff.js +31 -45
- package/dist/core/runtime/launch.d.ts +32 -18
- package/dist/core/runtime/launch.js +148 -43
- package/dist/core/runtime/model-swap.d.ts +18 -0
- package/dist/core/runtime/model-swap.js +95 -0
- package/dist/core/runtime/naming.d.ts +7 -0
- package/dist/core/runtime/naming.js +61 -9
- package/dist/core/runtime/nodes.js +6 -1
- package/dist/core/runtime/persona.js +16 -17
- package/dist/core/runtime/placement.d.ts +36 -31
- package/dist/core/runtime/placement.js +149 -64
- package/dist/core/runtime/promote.d.ts +2 -0
- package/dist/core/runtime/promote.js +23 -3
- package/dist/core/runtime/recycle.js +6 -4
- package/dist/core/runtime/reset.d.ts +5 -2
- package/dist/core/runtime/reset.js +2 -2
- package/dist/core/runtime/revive.d.ts +4 -0
- package/dist/core/runtime/revive.js +27 -9
- package/dist/core/runtime/roadmap.d.ts +1 -1
- package/dist/core/runtime/roadmap.js +1 -1
- package/dist/core/runtime/spawn.d.ts +2 -2
- package/dist/core/runtime/spawn.js +30 -6
- package/dist/core/runtime/stop-guard.js +6 -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 +29 -6
- package/dist/core/runtime/tmux.js +134 -80
- package/dist/core/runtime/view-socket-client.d.ts +46 -0
- package/dist/core/runtime/view-socket-client.js +203 -0
- package/dist/core/substrate/index.d.ts +1 -1
- package/dist/core/substrate/index.js +1 -1
- package/dist/core/substrate/on-read.js +16 -4
- package/dist/core/substrate/render.d.ts +10 -13
- package/dist/core/substrate/render.js +56 -51
- package/dist/core/tui/host.js +83 -18
- package/dist/core/view/__tests__/transport-cache.test.d.ts +1 -0
- package/dist/core/view/__tests__/transport-cache.test.js +62 -0
- package/dist/core/view/contract.d.ts +20 -0
- package/dist/core/view/stream-local.d.ts +3 -0
- package/dist/core/view/stream-local.js +184 -0
- package/dist/core/view/transport-cache.d.ts +8 -0
- package/dist/core/view/transport-cache.js +38 -0
- package/dist/core/view/transport-local.js +4 -0
- package/dist/core/view/transport.d.ts +7 -1
- package/dist/daemon/crtrd.d.ts +3 -19
- package/dist/daemon/crtrd.js +139 -178
- package/dist/daemon/manage.d.ts +18 -1
- package/dist/daemon/manage.js +54 -9
- package/dist/hearth/wake-proxy/__tests__/anthropic-oauth.test.d.ts +1 -0
- package/dist/hearth/wake-proxy/__tests__/anthropic-oauth.test.js +289 -0
- package/dist/hearth/wake-proxy/__tests__/config-timeout.test.d.ts +1 -0
- package/dist/hearth/wake-proxy/__tests__/config-timeout.test.js +34 -0
- package/dist/hearth/wake-proxy/__tests__/guest-source.test.d.ts +1 -0
- package/dist/hearth/wake-proxy/__tests__/guest-source.test.js +203 -0
- package/dist/hearth/wake-proxy/__tests__/hardening.test.d.ts +1 -0
- package/dist/hearth/wake-proxy/__tests__/hardening.test.js +59 -0
- package/dist/hearth/wake-proxy/__tests__/hearth-status-route.test.d.ts +1 -0
- package/dist/hearth/wake-proxy/__tests__/hearth-status-route.test.js +372 -0
- package/dist/hearth/wake-proxy/__tests__/http-running-route-fast-path.test.d.ts +1 -0
- package/dist/hearth/wake-proxy/__tests__/http-running-route-fast-path.test.js +258 -0
- package/dist/hearth/wake-proxy/__tests__/model-auth-routes.test.d.ts +1 -0
- package/dist/hearth/wake-proxy/__tests__/model-auth-routes.test.js +437 -0
- package/dist/hearth/wake-proxy/__tests__/source-bridge-gate.test.d.ts +1 -0
- package/dist/hearth/wake-proxy/__tests__/source-bridge-gate.test.js +455 -0
- package/dist/hearth/wake-proxy/__tests__/static-asset-allowlist.test.d.ts +1 -0
- package/dist/hearth/wake-proxy/__tests__/static-asset-allowlist.test.js +15 -0
- package/dist/hearth/wake-proxy/__tests__/warm-path-concurrency.test.d.ts +1 -0
- package/dist/hearth/wake-proxy/__tests__/warm-path-concurrency.test.js +141 -0
- package/dist/hearth/wake-proxy/__tests__/ws-teardown-accounting.test.d.ts +1 -0
- package/dist/hearth/wake-proxy/__tests__/ws-teardown-accounting.test.js +143 -0
- package/dist/hearth/wake-proxy/anthropic-oauth.d.ts +58 -0
- package/dist/hearth/wake-proxy/anthropic-oauth.js +189 -0
- package/dist/hearth/wake-proxy/auth.d.ts +22 -0
- package/dist/hearth/wake-proxy/auth.js +128 -0
- package/dist/hearth/wake-proxy/config.d.ts +2 -0
- package/dist/hearth/wake-proxy/config.js +151 -0
- package/dist/hearth/wake-proxy/guest-source.d.ts +14 -0
- package/dist/hearth/wake-proxy/guest-source.js +130 -0
- package/dist/hearth/wake-proxy/hearth-status.d.ts +44 -0
- package/dist/hearth/wake-proxy/hearth-status.js +267 -0
- package/dist/hearth/wake-proxy/home.d.ts +67 -0
- package/dist/hearth/wake-proxy/home.js +297 -0
- package/dist/hearth/wake-proxy/main.d.ts +1 -0
- package/dist/hearth/wake-proxy/main.js +134 -0
- package/dist/hearth/wake-proxy/model-auth.d.ts +13 -0
- package/dist/hearth/wake-proxy/model-auth.js +345 -0
- package/dist/hearth/wake-proxy/proxy.d.ts +35 -0
- package/dist/hearth/wake-proxy/proxy.js +716 -0
- package/dist/hearth/wake-proxy/public-source-gate.d.ts +9 -0
- package/dist/hearth/wake-proxy/public-source-gate.js +409 -0
- package/dist/hearth/wake-proxy/redact.d.ts +1 -0
- package/dist/hearth/wake-proxy/redact.js +17 -0
- package/dist/hearth/wake-proxy/server.d.ts +11 -0
- package/dist/hearth/wake-proxy/server.js +142 -0
- package/dist/hearth/wake-proxy/state.d.ts +18 -0
- package/dist/hearth/wake-proxy/state.js +342 -0
- package/dist/hearth/wake-proxy/types.d.ts +76 -0
- package/dist/hearth/wake-proxy/types.js +1 -0
- package/dist/index.js +3 -2
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +6 -5
- package/dist/pi-extensions/canvas-context-intro.js +7 -7
- package/dist/pi-extensions/canvas-doc-substrate.js +19 -22
- package/dist/pi-extensions/canvas-nav.js +15 -8
- package/dist/pi-extensions/canvas-stophook.d.ts +1 -1
- package/dist/pi-extensions/canvas-stophook.js +78 -11
- package/dist/types.d.ts +39 -20
- package/dist/types.js +38 -13
- package/dist/web/runtime.js +141 -42
- package/dist/web/transport-http.js +7 -5
- package/dist/web/transport-stream.d.ts +3 -0
- package/dist/web/transport-stream.js +204 -0
- package/dist/web-client/assets/fragment-mono-latin-400-normal-BYwT3kSJ.woff +0 -0
- package/dist/web-client/assets/fragment-mono-latin-400-normal-yxdJ5AmL.woff2 +0 -0
- package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-BbKYyvR9.woff2 +0 -0
- package/dist/web-client/assets/fragment-mono-latin-ext-400-normal-CT4YFKeK.woff +0 -0
- package/dist/web-client/assets/fraunces-latin-ext-wght-normal-Ca2vKHc0.woff2 +0 -0
- package/dist/web-client/assets/fraunces-latin-wght-normal-ukD16Tqj.woff2 +0 -0
- package/dist/web-client/assets/fraunces-vietnamese-wght-normal-CnvboYUG.woff2 +0 -0
- package/dist/web-client/assets/index-BZUxTkv5.css +2 -0
- package/dist/web-client/assets/index-D36PNBj4.js +80 -0
- package/dist/web-client/assets/instrument-sans-latin-ext-wght-normal-B5bTHO_g.woff2 +0 -0
- package/dist/web-client/assets/instrument-sans-latin-wght-normal-BbzFLZTg.woff2 +0 -0
- package/dist/web-client/assets/martian-mono-cyrillic-wght-normal-B84CD5C_.woff2 +0 -0
- package/dist/web-client/assets/martian-mono-latin-ext-wght-normal-DlL6xMw5.woff2 +0 -0
- package/dist/web-client/assets/martian-mono-latin-wght-normal-5W32yIyr.woff2 +0 -0
- package/dist/web-client/index.html +3 -2
- package/package.json +32 -10
- package/dist/core/__tests__/error-stall-recycle.test.js +0 -141
- package/dist/core/skill-sync/__tests__/dry-run-wrote-count.test.js +0 -57
- package/dist/core/skill-sync/builtins.js +0 -112
- package/dist/core/skill-sync/claude-plugins.d.ts +0 -23
- package/dist/core/skill-sync/claude-plugins.js +0 -71
- package/dist/core/skill-sync/engine.d.ts +0 -42
- package/dist/core/skill-sync/engine.js +0 -633
- package/dist/core/skill-sync/manifest.d.ts +0 -64
- package/dist/core/skill-sync/manifest.js +0 -181
- package/dist/core/skill-sync/profile.d.ts +0 -76
- package/dist/core/skill-sync/profile.js +0 -173
- package/dist/core/skill-sync/snapshot.d.ts +0 -57
- package/dist/core/skill-sync/snapshot.js +0 -120
- package/dist/pi-extensions/canvas-commands.d.ts +0 -37
- package/dist/pi-extensions/canvas-commands.js +0 -113
- package/dist/pi-extensions/canvas-resume.d.ts +0 -21
- package/dist/pi-extensions/canvas-resume.js +0 -83
- package/dist/pi-extensions/canvas-view.d.ts +0 -21
- package/dist/pi-extensions/canvas-view.js +0 -76
- package/dist/web-client/assets/index-BUvQb4hR.css +0 -2
- package/dist/web-client/assets/index-ClLQXYAE.js +0 -10
- /package/dist/{core/__tests__/error-stall-recycle.test.d.ts → clients/attach/__tests__/autocomplete-and-bash-mode.test.d.ts} +0 -0
- /package/dist/{core/skill-sync/__tests__/dry-run-wrote-count.test.d.ts → clients/attach/__tests__/bash-bang-routing.test.d.ts} +0 -0
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// their window; reviving opens a fresh one.
|
|
10
10
|
import { spawnSync } from 'node:child_process';
|
|
11
11
|
import { readConfig } from '../config.js';
|
|
12
|
+
import { defaultCanvasNavConfig } from '../../types.js';
|
|
12
13
|
import { surfaceTmuxStyleArgs } from './surface-bg.js';
|
|
13
14
|
// ---------------------------------------------------------------------------
|
|
14
15
|
// Shell quoting + tmux invocation
|
|
@@ -48,12 +49,32 @@ export function currentTmux() {
|
|
|
48
49
|
export function sessionExists(name) {
|
|
49
50
|
return tmux(['has-session', '-t', name]).ok;
|
|
50
51
|
}
|
|
52
|
+
/** Force bracketed-paste capabilities on for every terminal on this tmux server.
|
|
53
|
+
*
|
|
54
|
+
* Many terminfo entries lack the Enbp/Dsbp (enable/disable bracketed paste)
|
|
55
|
+
* capabilities. Without them tmux never asks the outer terminal to wrap pastes,
|
|
56
|
+
* so a multi-line paste arrives as raw `\r` and the inner app (pi, zsh, …)
|
|
57
|
+
* submits on the first newline — i.e. one paste lands as several messages.
|
|
58
|
+
* Declaring the caps for `*` restores bracketed paste so pastes stay atomic.
|
|
59
|
+
*
|
|
60
|
+
* `terminal-overrides` is a server option, so this is set once per server and
|
|
61
|
+
* is idempotent: we only append our entry when the Enbp marker isn't already
|
|
62
|
+
* present (e.g. the user's own tmux.conf already declares it). Must run only
|
|
63
|
+
* once a server exists — set-option errors out with no server running — so
|
|
64
|
+
* callers invoke it AFTER ensuring a session. */
|
|
65
|
+
function ensureBracketedPaste() {
|
|
66
|
+
const current = tmux(['show-options', '-s', 'terminal-overrides']).stdout;
|
|
67
|
+
if (current.includes('Enbp='))
|
|
68
|
+
return;
|
|
69
|
+
tmux(['set-option', '-sga', 'terminal-overrides', '*:Enbp=\E[?2004h:Dsbp=\E[?2004l']);
|
|
70
|
+
}
|
|
51
71
|
/** Create a detached session rooted at `cwd` if it doesn't exist. The session
|
|
52
72
|
* name is a root's tmux home; every node under that root is a window in it. */
|
|
53
73
|
export function ensureSession(name, cwd) {
|
|
54
|
-
if (sessionExists(name))
|
|
55
|
-
|
|
56
|
-
|
|
74
|
+
if (!sessionExists(name)) {
|
|
75
|
+
tmux(['new-session', '-d', '-s', name, '-c', cwd]);
|
|
76
|
+
}
|
|
77
|
+
ensureBracketedPaste();
|
|
57
78
|
}
|
|
58
79
|
function envFlags(env) {
|
|
59
80
|
const out = [];
|
|
@@ -149,6 +170,31 @@ export function closeWindow(window) {
|
|
|
149
170
|
export function renameWindow(window, name) {
|
|
150
171
|
return tmux(['rename-window', '-t', window, name]).ok;
|
|
151
172
|
}
|
|
173
|
+
/** Break a single PANE out into a BRAND-NEW window of its own (`tmux break-pane
|
|
174
|
+
* -d`). `-d` keeps the new window in the background (does not switch the client
|
|
175
|
+
* to it); `-s <pane>` names the source pane — the §2.2 HARD DRIVER INVARIANT, so
|
|
176
|
+
* the break never falls back to tmux's global current pane. The pane keeps its
|
|
177
|
+
* durable `%id` across the move (only its window changes), so callers can keep
|
|
178
|
+
* using the same pane handle. Returns the new `{window, pane}` location, or null
|
|
179
|
+
* if tmux fails. Used by `canvas tmux-spread` to lift the caller's viewer into a
|
|
180
|
+
* fresh window before tiling sibling viewers beside it. */
|
|
181
|
+
export function breakPane(pane) {
|
|
182
|
+
const r = tmux([
|
|
183
|
+
'break-pane',
|
|
184
|
+
'-d',
|
|
185
|
+
'-P',
|
|
186
|
+
'-F',
|
|
187
|
+
'#{window_id}\t#{pane_id}',
|
|
188
|
+
'-s',
|
|
189
|
+
pane,
|
|
190
|
+
]);
|
|
191
|
+
if (!r.ok)
|
|
192
|
+
return null;
|
|
193
|
+
const [window, p] = r.stdout.split('\t');
|
|
194
|
+
if (window === undefined || window === '' || p === undefined || p === '')
|
|
195
|
+
return null;
|
|
196
|
+
return { window, pane: p };
|
|
197
|
+
}
|
|
152
198
|
/** Close a single PANE. Its window closes automatically once this was the last
|
|
153
199
|
* pane, but sibling panes survive — so co-located nodes (several agents sharing
|
|
154
200
|
* one window via swap-pane focus) are torn down one at a time instead of all
|
|
@@ -226,6 +272,17 @@ export function paneCurrentPath(pane) {
|
|
|
226
272
|
const r = tmux(['display-message', '-p', '-t', pane, '#{pane_current_path}']);
|
|
227
273
|
return r.ok && r.stdout !== '' ? r.stdout : null;
|
|
228
274
|
}
|
|
275
|
+
/** Flash a transient status-line toast on the client showing `pane` (or the
|
|
276
|
+
* current client when `pane` is omitted). `ms` sets the display duration. Used
|
|
277
|
+
* by `crtr canvas issue new` to confirm a capture from inside its popup.
|
|
278
|
+
* Best-effort; never throws. */
|
|
279
|
+
export function displayMessage(message, pane, ms = 4000) {
|
|
280
|
+
const args = ['display-message', '-d', String(ms)];
|
|
281
|
+
if (pane !== undefined && pane !== '')
|
|
282
|
+
args.push('-t', pane);
|
|
283
|
+
args.push(message);
|
|
284
|
+
return tmux(args).ok;
|
|
285
|
+
}
|
|
229
286
|
/** Set a PANE-scoped tmux option (`tmux set-option -p -t <pane> <name> <value>`).
|
|
230
287
|
* Used to tag a pane with the view id it currently hosts (`@crtr_view`) so the
|
|
231
288
|
* view-nav cycle can read it back and switch to the next/prev view in place.
|
|
@@ -311,6 +368,21 @@ export function windowAlive(session, window) {
|
|
|
311
368
|
export function selectWindow(session, window) {
|
|
312
369
|
return tmux(['select-window', '-t', `${session}:${window}`]).ok;
|
|
313
370
|
}
|
|
371
|
+
/** Apply a named tmux layout to a window (`tmux select-layout -t <window>
|
|
372
|
+
* <layout>`). `canvas tmux-spread` calls it with `tiled` to evenly grid every
|
|
373
|
+
* viewer pane in the spread window (and between splits, to redistribute space so
|
|
374
|
+
* the next split has room). Best-effort; false if tmux fails. */
|
|
375
|
+
export function selectLayout(window, layout) {
|
|
376
|
+
return tmux(['select-layout', '-t', window, layout]).ok;
|
|
377
|
+
}
|
|
378
|
+
/** Make a pane the ACTIVE pane in its window (`tmux select-pane -t <pane>`). A
|
|
379
|
+
* `split-window -d` keeps the CALLER active, so a freshly-opened viewer pane is
|
|
380
|
+
* not focused until this runs — `focus` calls it so picking a node (e.g. from the
|
|
381
|
+
* alt+g graph) lands the keyboard on the new viewer. Best-effort; false if tmux
|
|
382
|
+
* fails. */
|
|
383
|
+
export function selectPane(pane) {
|
|
384
|
+
return tmux(['select-pane', '-t', pane]).ok;
|
|
385
|
+
}
|
|
314
386
|
/** Switch the tmux client to a different session (cross-session focus). Runs
|
|
315
387
|
* `tmux switch-client -t <session>`. Best-effort; never throws. The caller is
|
|
316
388
|
* responsible for following up with selectWindow to land on the right window. */
|
|
@@ -329,91 +401,73 @@ export function sendKeysEnter(pane, text) {
|
|
|
329
401
|
// ---------------------------------------------------------------------------
|
|
330
402
|
// Prefix menu — Alt+C opens a which-key-style tmux display-menu of crouter
|
|
331
403
|
// actions. Installed on the running server at root boot; idempotent (a re-bind
|
|
332
|
-
// overwrites the previous one).
|
|
333
|
-
//
|
|
404
|
+
// overwrites the previous one). Menu entries are data-driven: tmux renders the
|
|
405
|
+
// action tree, and every `crtr` / `popup` action routes through `crtr canvas
|
|
406
|
+
// chord` so node-relative vars resolve in one safe place.
|
|
334
407
|
// ---------------------------------------------------------------------------
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
408
|
+
function escapeTmuxFormats(value) {
|
|
409
|
+
return value.replace(/#/g, '##');
|
|
410
|
+
}
|
|
411
|
+
function runShellCmd(shellCmd) {
|
|
412
|
+
return `run-shell ${shellQuote(shellCmd)}`;
|
|
413
|
+
}
|
|
414
|
+
function tmuxCmd(args) {
|
|
415
|
+
return args.map(shellQuote).join(' ');
|
|
416
|
+
}
|
|
417
|
+
function chordShellCmd(run) {
|
|
418
|
+
return runShellCmd(`crtr canvas chord --pane '#{pane_id}' --run ${shellQuote(escapeTmuxFormats(run))} >/dev/null 2>&1`);
|
|
419
|
+
}
|
|
420
|
+
function popupCmd(run) {
|
|
421
|
+
return `display-popup -E -w 60% -h 50% -d "#{pane_current_path}" ${shellQuote(`crtr canvas chord --pane '#{pane_id}' --run ${shellQuote(escapeTmuxFormats(run))} --interactive`)}`;
|
|
422
|
+
}
|
|
423
|
+
function keysCmd(keys) {
|
|
424
|
+
return `send-keys -t '#{pane_id}' ${shellQuote(escapeTmuxFormats(keys))} Enter`;
|
|
425
|
+
}
|
|
426
|
+
function buildMenuArgs(title, items) {
|
|
427
|
+
const safeTitle = escapeTmuxFormats(title);
|
|
428
|
+
const args = ['display-menu', '-T', `#[align=centre]${safeTitle}`, ...surfaceTmuxStyleArgs()];
|
|
429
|
+
const boxW = Math.max(safeTitle.length, ...items.map((i) => escapeTmuxFormats(i.desc).length)) + 6;
|
|
430
|
+
const nudgeX = 1;
|
|
431
|
+
const nudgeY = 3;
|
|
432
|
+
args.push('-x', `#{e|-:#{pane_right},${boxW + nudgeX}}`, '-y', `#{e|+:#{pane_top},${nudgeY}}`);
|
|
433
|
+
for (const item of items) {
|
|
434
|
+
args.push(escapeTmuxFormats(item.desc), escapeTmuxFormats(item.key), renderAction(item.action, item.desc));
|
|
435
|
+
}
|
|
436
|
+
args.push('-esc / q to close', '', '');
|
|
437
|
+
return args;
|
|
438
|
+
}
|
|
439
|
+
function renderAction(action, label) {
|
|
440
|
+
const kind = action.kind ?? 'crtr';
|
|
441
|
+
switch (kind) {
|
|
442
|
+
case 'keys':
|
|
443
|
+
return keysCmd(action.keys);
|
|
444
|
+
case 'popup':
|
|
445
|
+
return popupCmd(action.run);
|
|
446
|
+
case 'menu':
|
|
447
|
+
return tmuxCmd(buildMenuArgs(label, action.items));
|
|
448
|
+
case 'crtr':
|
|
449
|
+
return chordShellCmd(action.run);
|
|
450
|
+
default:
|
|
451
|
+
throw new Error(`unknown canvas action kind: ${kind}`);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
/** Bind Alt+C to the crouter action menu. Best-effort; false if tmux fails. */
|
|
344
455
|
export function installMenuBinding() {
|
|
345
|
-
|
|
346
|
-
const items = [
|
|
347
|
-
// Promote types `/promote` into the agent's pane rather than shelling out:
|
|
348
|
-
// the slash command delivers the orchestration guidance into the node's
|
|
349
|
-
// context, which a bare `run-shell` (output discarded) could not.
|
|
350
|
-
{ name: 'promote to orchestrator', key: 'o', cmd: `send-keys -t '#{pane_id}' '/promote' Enter` },
|
|
351
|
-
// Resume types `/resume-node` into the agent's pane: the slash command opens
|
|
352
|
-
// a whole-canvas picker (incl. dormant nodes) and revives the choice via
|
|
353
|
-
// `crtr node focus` — the only sync-safe open (routes through reviveNode).
|
|
354
|
-
{ name: 'resume node', key: 'r', cmd: `send-keys -t '#{pane_id}' '/resume-node' Enter` },
|
|
355
|
-
// `d` runs `node demote`: flip the agent to TERMINAL in place — no finalize,
|
|
356
|
-
// no kill — it keeps running where it is, and because it is now terminal it
|
|
357
|
-
// is forced to push a final up the spine when it finishes. `D` runs `node
|
|
358
|
-
// demote --detach`, which ALSO closes the agent's viewer pane (frees the
|
|
359
|
-
// pane; the detached broker keeps generating). Neither ends it.
|
|
360
|
-
{ name: 'demote to terminal', key: 'd', cmd: `run-shell "crtr node demote --pane '#{pane_id}' >/dev/null 2>&1"` },
|
|
361
|
-
{ name: 'detach to background', key: 'D', cmd: `run-shell "crtr node demote --pane '#{pane_id}' --detach >/dev/null 2>&1"` },
|
|
362
|
-
// Close cascades down the subscribes_to spine (kills the subtree's windows,
|
|
363
|
-
// marks them canceled); revivable. Output discarded — the keypress just acts.
|
|
364
|
-
{ name: 'close agent + subtree', key: 'x', cmd: `run-shell "crtr node close --pane '#{pane_id}' >/dev/null 2>&1"` },
|
|
365
|
-
];
|
|
366
|
-
// Canvas-nav chords from config (default: g→graph, m→manager). The
|
|
367
|
-
// `__graph__` sentinel toggles the in-pi GRAPH modal via send-keys; every
|
|
368
|
-
// other bind shells the chord dispatcher, which resolves the pane's node and
|
|
369
|
-
// interpolates the bind at popup time. Keys colliding with the built-ins are
|
|
370
|
-
// skipped (the built-in wins).
|
|
371
|
-
let prefixBinds = {};
|
|
456
|
+
let prefixBinds;
|
|
372
457
|
try {
|
|
373
458
|
prefixBinds = readConfig('user').canvasNav.prefixBinds;
|
|
374
459
|
}
|
|
375
|
-
catch {
|
|
460
|
+
catch {
|
|
461
|
+
prefixBinds = defaultCanvasNavConfig().prefixBinds;
|
|
462
|
+
}
|
|
463
|
+
const items = [];
|
|
376
464
|
for (const [key, bind] of Object.entries(prefixBinds)) {
|
|
377
|
-
if (key.length !== 1
|
|
465
|
+
if (key.length !== 1)
|
|
378
466
|
continue;
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
? `send-keys -t '#{pane_id}' '/graph' Enter`
|
|
382
|
-
: `run-shell "crtr canvas chord --pane '#{pane_id}' --key ${key} >/dev/null 2>&1"`;
|
|
383
|
-
items.push({ name, key, cmd });
|
|
467
|
+
const desc = bind.desc ?? `chord ${key}`;
|
|
468
|
+
items.push({ key, desc, action: bind });
|
|
384
469
|
}
|
|
385
|
-
|
|
386
|
-
// (Escape / q / C-c), encoding-independent. We do NOT try to catch a re-pressed
|
|
387
|
-
// Alt+C: under `extended-keys on` (common, and what pi negotiates) the second
|
|
388
|
-
// Alt+C reaches the overlay as a CSI-u key (`\033[99;3u`) that tmux's menu does
|
|
389
|
-
// NOT match against an `M-c` mnemonic item, so a "close menu" row keyed M-c
|
|
390
|
-
// never fires and the menu just sits open (verified in tmux 3.6b: legacy Esc+c
|
|
391
|
-
// closes, CSI-u does not). Instead, a disabled (`-` prefix → dim, unselectable)
|
|
392
|
-
// last row tells the user the close keys that always work. Placed last so it
|
|
393
|
-
// reads as chrome below the actions.
|
|
394
|
-
items.push({ name: '-esc / q to close', key: '', cmd: '' });
|
|
395
|
-
// tmux's -x sets the menu's LEFT edge. To sit the box INSIDE the pane's
|
|
396
|
-
// top-right corner, shift x left by the box width (longest line + tmux chrome:
|
|
397
|
-
// borders + padding + the right-aligned mnemonic-key column) via format math.
|
|
398
|
-
const boxW = Math.max(title.length, ...items.map((i) => i.name.length)) + 6;
|
|
399
|
-
// Fine-tune nudges off the pane's top-right corner: a hair further left and
|
|
400
|
-
// one row down so the box doesn't kiss the pane border.
|
|
401
|
-
const nudgeX = 1; // extra columns left
|
|
402
|
-
const nudgeY = 3; // rows down
|
|
403
|
-
const args = [
|
|
404
|
-
'bind-key', '-n', 'M-c', 'display-menu',
|
|
405
|
-
'-T', `#[align=centre]${title}`,
|
|
406
|
-
// Frame the menu on the theme's distinct-surface background so it doesn't
|
|
407
|
-
// blend into the pane behind it (CTO ruling). Empty in the front door (theme
|
|
408
|
-
// not loaded there); the attach viewer re-installs this with the style once
|
|
409
|
-
// it has themed — see attach-cmd.ts.
|
|
410
|
-
...surfaceTmuxStyleArgs(),
|
|
411
|
-
'-x', `#{e|-:#{pane_right},${boxW + nudgeX}}`,
|
|
412
|
-
'-y', `#{e|+:#{pane_top},${nudgeY}}`,
|
|
413
|
-
];
|
|
414
|
-
for (const it of items)
|
|
415
|
-
args.push(it.name, it.key, it.cmd);
|
|
416
|
-
return tmux(args).ok;
|
|
470
|
+
return tmux(['bind-key', '-n', 'M-c', ...buildMenuArgs(' crtr ', items)]).ok;
|
|
417
471
|
}
|
|
418
472
|
// ---------------------------------------------------------------------------
|
|
419
473
|
// Nav bindings — Alt+] / Alt+[ DFS-walk the canvas one window at a time. Each
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { type NodeRow } from '../canvas/index.js';
|
|
3
|
+
import { type BrokerDataFrame, type BrokerToClient, type ClientToBroker, type DequeueFrame, type GetSettingsFrame, type GetTreeFrame, type ListModelsFrame, type ListScopedModelsFrame, type ListSessionsFrame } from './broker-protocol.js';
|
|
4
|
+
export type ReadOpRequest = Omit<ListModelsFrame, 'id'> | Omit<ListSessionsFrame, 'id'> | Omit<GetTreeFrame, 'id'> | Omit<GetSettingsFrame, 'id'> | Omit<ListScopedModelsFrame, 'id'> | Omit<DequeueFrame, 'id'>;
|
|
5
|
+
export declare function reconnectShouldGiveUp(row: NodeRow | null): boolean;
|
|
6
|
+
export declare class BrokerUnavailableError extends Error {
|
|
7
|
+
readonly nodeId: string;
|
|
8
|
+
constructor(nodeId: string);
|
|
9
|
+
}
|
|
10
|
+
export interface ViewSocketClientOptions {
|
|
11
|
+
emitUnmatchedDataFrames?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface ViewSocketClient {
|
|
14
|
+
on(event: 'connect', listener: () => void): this;
|
|
15
|
+
on(event: 'frame', listener: (frame: BrokerToClient) => void): this;
|
|
16
|
+
on(event: 'close', listener: () => void): this;
|
|
17
|
+
on(event: 'error', listener: (err: Error) => void): this;
|
|
18
|
+
once(event: 'connect', listener: () => void): this;
|
|
19
|
+
once(event: 'frame', listener: (frame: BrokerToClient) => void): this;
|
|
20
|
+
once(event: 'close', listener: () => void): this;
|
|
21
|
+
once(event: 'error', listener: (err: Error) => void): this;
|
|
22
|
+
off(event: 'connect', listener: () => void): this;
|
|
23
|
+
off(event: 'error', listener: (err: Error) => void): this;
|
|
24
|
+
}
|
|
25
|
+
export declare class ViewSocketClient extends EventEmitter {
|
|
26
|
+
private readonly nodeId;
|
|
27
|
+
private socket;
|
|
28
|
+
private decoder;
|
|
29
|
+
private closeEmitted;
|
|
30
|
+
private readonly emitUnmatchedDataFrames;
|
|
31
|
+
private pending;
|
|
32
|
+
constructor(nodeId: string, options?: ViewSocketClientOptions);
|
|
33
|
+
private recordSocketFault;
|
|
34
|
+
request(frame: ReadOpRequest): Promise<BrokerDataFrame>;
|
|
35
|
+
private rejectAllPending;
|
|
36
|
+
get socketPath(): string;
|
|
37
|
+
connect(): void;
|
|
38
|
+
redial(): Promise<void>;
|
|
39
|
+
send(frame: ClientToBroker): void;
|
|
40
|
+
close(): void;
|
|
41
|
+
private onData;
|
|
42
|
+
private onError;
|
|
43
|
+
private onClose;
|
|
44
|
+
private destroy;
|
|
45
|
+
private emitError;
|
|
46
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { createConnection } from 'node:net';
|
|
4
|
+
import { classify } from '../fault-classifier.js';
|
|
5
|
+
import { viewSocketPath } from '../canvas/paths.js';
|
|
6
|
+
import { clearFault, recordFault } from './fault.js';
|
|
7
|
+
import { CLIENT_READ_CAPS, encodeFrame, FrameDecoder, FrameOverflowError, } from './broker-protocol.js';
|
|
8
|
+
const REQUEST_TIMEOUT_MS = 10_000;
|
|
9
|
+
export function reconnectShouldGiveUp(row) {
|
|
10
|
+
if (row === null)
|
|
11
|
+
return true;
|
|
12
|
+
return row.status === 'done' || row.status === 'dead' || row.status === 'canceled';
|
|
13
|
+
}
|
|
14
|
+
export class BrokerUnavailableError extends Error {
|
|
15
|
+
nodeId;
|
|
16
|
+
constructor(nodeId) {
|
|
17
|
+
super(`node ${nodeId} has no running broker — focus or revive it first`);
|
|
18
|
+
this.nodeId = nodeId;
|
|
19
|
+
this.name = 'BrokerUnavailableError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export class ViewSocketClient extends EventEmitter {
|
|
23
|
+
nodeId;
|
|
24
|
+
socket;
|
|
25
|
+
decoder = new FrameDecoder(CLIENT_READ_CAPS);
|
|
26
|
+
closeEmitted = false;
|
|
27
|
+
emitUnmatchedDataFrames;
|
|
28
|
+
pending = new Map();
|
|
29
|
+
constructor(nodeId, options = {}) {
|
|
30
|
+
super();
|
|
31
|
+
this.nodeId = nodeId;
|
|
32
|
+
this.emitUnmatchedDataFrames = options.emitUnmatchedDataFrames ?? false;
|
|
33
|
+
}
|
|
34
|
+
recordSocketFault(op, err) {
|
|
35
|
+
const classified = classify('viewer↔broker', err);
|
|
36
|
+
recordFault(this.nodeId, {
|
|
37
|
+
link: 'viewer↔broker',
|
|
38
|
+
op,
|
|
39
|
+
kind: classified.kind,
|
|
40
|
+
retry: op === 'redial'
|
|
41
|
+
? { disposition: 'auto', by: 'client' }
|
|
42
|
+
: { disposition: 'manual' },
|
|
43
|
+
message: err instanceof Error ? err.message : String(err),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
request(frame) {
|
|
47
|
+
const id = randomUUID();
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
const sock = this.socket;
|
|
50
|
+
if (sock === undefined || sock.destroyed) {
|
|
51
|
+
reject(new Error(`cannot issue '${frame.type}': no live broker connection`));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const timer = setTimeout(() => {
|
|
55
|
+
this.pending.delete(id);
|
|
56
|
+
reject(new Error(`request '${frame.type}' timed out after ${REQUEST_TIMEOUT_MS}ms`));
|
|
57
|
+
}, REQUEST_TIMEOUT_MS);
|
|
58
|
+
if (typeof timer.unref === 'function')
|
|
59
|
+
timer.unref();
|
|
60
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
61
|
+
this.send({ ...frame, id });
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
rejectAllPending(reason) {
|
|
65
|
+
for (const { reject, timer } of this.pending.values()) {
|
|
66
|
+
clearTimeout(timer);
|
|
67
|
+
reject(new Error(reason));
|
|
68
|
+
}
|
|
69
|
+
this.pending.clear();
|
|
70
|
+
}
|
|
71
|
+
get socketPath() {
|
|
72
|
+
return viewSocketPath(this.nodeId);
|
|
73
|
+
}
|
|
74
|
+
connect() {
|
|
75
|
+
const socket = createConnection(this.socketPath);
|
|
76
|
+
this.socket = socket;
|
|
77
|
+
socket.on('connect', () => {
|
|
78
|
+
clearFault(this.nodeId, { link: 'viewer↔broker' });
|
|
79
|
+
this.emit('connect');
|
|
80
|
+
});
|
|
81
|
+
socket.on('data', (chunk) => this.onData(chunk));
|
|
82
|
+
socket.on('error', (err) => this.onError(err, 'connect'));
|
|
83
|
+
socket.on('close', () => this.onClose());
|
|
84
|
+
}
|
|
85
|
+
redial() {
|
|
86
|
+
this.destroy();
|
|
87
|
+
this.decoder = new FrameDecoder(CLIENT_READ_CAPS);
|
|
88
|
+
this.closeEmitted = false;
|
|
89
|
+
return new Promise((resolve, reject) => {
|
|
90
|
+
const socket = createConnection(this.socketPath);
|
|
91
|
+
this.socket = socket;
|
|
92
|
+
let settled = false;
|
|
93
|
+
socket.on('connect', () => {
|
|
94
|
+
if (settled)
|
|
95
|
+
return;
|
|
96
|
+
settled = true;
|
|
97
|
+
clearFault(this.nodeId, { link: 'viewer↔broker' });
|
|
98
|
+
this.emit('connect');
|
|
99
|
+
resolve();
|
|
100
|
+
});
|
|
101
|
+
socket.on('data', (chunk) => this.onData(chunk));
|
|
102
|
+
socket.on('error', (err) => {
|
|
103
|
+
if (settled) {
|
|
104
|
+
this.onError(err, 'redial');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
settled = true;
|
|
108
|
+
this.recordSocketFault('redial', err);
|
|
109
|
+
try {
|
|
110
|
+
socket.destroy();
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
/* ignore */
|
|
114
|
+
}
|
|
115
|
+
reject(err);
|
|
116
|
+
});
|
|
117
|
+
socket.on('close', () => this.onClose());
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
send(frame) {
|
|
121
|
+
const sock = this.socket;
|
|
122
|
+
if (sock === undefined || sock.destroyed)
|
|
123
|
+
return;
|
|
124
|
+
try {
|
|
125
|
+
sock.write(encodeFrame(frame));
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
/* dead socket — 'close' will fire and drive teardown */
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
close() {
|
|
132
|
+
this.destroy();
|
|
133
|
+
}
|
|
134
|
+
onData(chunk) {
|
|
135
|
+
let frames;
|
|
136
|
+
try {
|
|
137
|
+
frames = this.decoder.push(chunk);
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
const msg = err instanceof FrameOverflowError
|
|
141
|
+
? `broker sent an oversized frame (${err.message}) — disconnecting`
|
|
142
|
+
: `failed to decode a broker frame: ${String(err)}`;
|
|
143
|
+
this.rejectAllPending(msg);
|
|
144
|
+
this.emitError(new Error(msg));
|
|
145
|
+
this.destroy();
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
for (const raw of frames) {
|
|
149
|
+
const frame = raw;
|
|
150
|
+
if (frame.type === 'data') {
|
|
151
|
+
const entry = typeof frame.id === 'string' ? this.pending.get(frame.id) : undefined;
|
|
152
|
+
if (entry) {
|
|
153
|
+
this.pending.delete(frame.id);
|
|
154
|
+
clearTimeout(entry.timer);
|
|
155
|
+
entry.resolve(frame);
|
|
156
|
+
}
|
|
157
|
+
else if (this.emitUnmatchedDataFrames) {
|
|
158
|
+
this.emit('frame', frame);
|
|
159
|
+
}
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (frame.type === 'error' && typeof frame.id === 'string' && this.pending.has(frame.id)) {
|
|
163
|
+
const entry = this.pending.get(frame.id);
|
|
164
|
+
this.pending.delete(frame.id);
|
|
165
|
+
clearTimeout(entry.timer);
|
|
166
|
+
entry.reject(new Error(frame.message || `request failed: ${frame.code}`));
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
this.emit('frame', frame);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
onError(err, op) {
|
|
173
|
+
this.recordSocketFault(op, err);
|
|
174
|
+
if (err.code === 'ECONNREFUSED' || err.code === 'ENOENT') {
|
|
175
|
+
this.emitError(new BrokerUnavailableError(this.nodeId));
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
this.emitError(new Error(`view socket error: ${err.message}`));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
onClose() {
|
|
182
|
+
if (this.closeEmitted)
|
|
183
|
+
return;
|
|
184
|
+
this.closeEmitted = true;
|
|
185
|
+
this.rejectAllPending('broker connection closed');
|
|
186
|
+
this.emit('close');
|
|
187
|
+
}
|
|
188
|
+
destroy() {
|
|
189
|
+
const sock = this.socket;
|
|
190
|
+
if (sock !== undefined && !sock.destroyed) {
|
|
191
|
+
try {
|
|
192
|
+
sock.destroy();
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
/* ignore */
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
emitError(err) {
|
|
200
|
+
if (this.listenerCount('error') > 0)
|
|
201
|
+
this.emit('error', err);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
@@ -5,5 +5,5 @@ export type { NodeConfigSubject } from './subject.js';
|
|
|
5
5
|
export { gatePasses } from './gate.js';
|
|
6
6
|
export { INDEX_NAME, isIndexName, indexDirOf, displayName, buildCeilingIndex, effectiveRung, } from './ceiling.js';
|
|
7
7
|
export type { Surface } from './ceiling.js';
|
|
8
|
-
export { renderPreferencesSection, renderKnowledgeBlock,
|
|
8
|
+
export { renderPreferencesSection, renderKnowledgeBlock, } from './render.js';
|
|
9
9
|
export { renderOnReadDocs } from './on-read.js';
|
|
@@ -15,5 +15,5 @@ parseSubstrateFrontmatter, parseSubstrateDoc, previewLine, } from './schema.js';
|
|
|
15
15
|
export { scopeForCwd, spineDepth, assembleNodeSubject } from './subject.js';
|
|
16
16
|
export { gatePasses } from './gate.js';
|
|
17
17
|
export { INDEX_NAME, isIndexName, indexDirOf, displayName, buildCeilingIndex, effectiveRung, } from './ceiling.js';
|
|
18
|
-
export { renderPreferencesSection, renderKnowledgeBlock,
|
|
18
|
+
export { renderPreferencesSection, renderKnowledgeBlock, } from './render.js';
|
|
19
19
|
export { renderOnReadDocs } from './on-read.js';
|
|
@@ -23,6 +23,14 @@
|
|
|
23
23
|
// the doc fires only on its trigger, never positionally on every read under its
|
|
24
24
|
// scope. The two explicit triggers compose by OR.
|
|
25
25
|
//
|
|
26
|
+
// D6 — an explicitly-triggered doc also PIERCES the INDEX ceiling: it surfaces at
|
|
27
|
+
// its OWN fileReadVisibility, not min(own, ancestor INDEX rungs). The ceiling is
|
|
28
|
+
// the mechanism for collapsing a subtree's BOOT + POSITIONAL on-read surface; a
|
|
29
|
+
// cross-cutting applies-to/read-when trigger is the author deliberately opting
|
|
30
|
+
// ONE doc into surfacing when a specific file is read, so a `none`-capped
|
|
31
|
+
// ancestor INDEX (the default for a reference plugin pulled by name) must not
|
|
32
|
+
// veto it. Same stance as D5 — the explicit trigger is the more specific signal.
|
|
33
|
+
//
|
|
26
34
|
// Each candidate runs the substrate pipeline at its fileReadVisibility rung:
|
|
27
35
|
// parse → gatePasses(doc, assembleNodeSubject(nodeId)) → render
|
|
28
36
|
// (content → body, preview → previewLine, name → bare tag, none → skip).
|
|
@@ -157,7 +165,7 @@ function positionalCandidates(absReadFile) {
|
|
|
157
165
|
// D5: a doc with an explicit read-trigger (applies-to/read-when) does
|
|
158
166
|
// NOT fire positionally — it surfaces only via that trigger.
|
|
159
167
|
if (doc && !hasExplicitTrigger(doc))
|
|
160
|
-
out.push({ doc, realpath: real, order: depth });
|
|
168
|
+
out.push({ doc, realpath: real, order: depth, explicit: false });
|
|
161
169
|
}
|
|
162
170
|
}
|
|
163
171
|
}
|
|
@@ -218,7 +226,7 @@ function appliesToCandidates(absReadFile, taken) {
|
|
|
218
226
|
if (!globs.some((g) => globMatches(g, absReadFile, owningRootOf(doc))))
|
|
219
227
|
continue;
|
|
220
228
|
taken.add(real);
|
|
221
|
-
out.push({ doc, realpath: real, order: -1 });
|
|
229
|
+
out.push({ doc, realpath: real, order: -1, explicit: true });
|
|
222
230
|
}
|
|
223
231
|
return out;
|
|
224
232
|
}
|
|
@@ -261,7 +269,7 @@ function readWhenCandidates(readFileFm, taken) {
|
|
|
261
269
|
if (!evalCondition(doc.readWhen, readFileFm))
|
|
262
270
|
continue;
|
|
263
271
|
taken.add(real);
|
|
264
|
-
out.push({ doc, realpath: real, order: -1 });
|
|
272
|
+
out.push({ doc, realpath: real, order: -1, explicit: true });
|
|
265
273
|
}
|
|
266
274
|
return out;
|
|
267
275
|
}
|
|
@@ -350,7 +358,11 @@ export function renderOnReadDocs(nodeId, readFilePath, seen = new Set()) {
|
|
|
350
358
|
try {
|
|
351
359
|
if (!gatePasses(c.doc, subject))
|
|
352
360
|
continue; // gated out for this node
|
|
353
|
-
|
|
361
|
+
// D6: an explicit applies-to/read-when trigger pierces the INDEX ceiling
|
|
362
|
+
// and renders at the doc's own rung; positional docs honor the ceiling.
|
|
363
|
+
const rung = c.explicit
|
|
364
|
+
? c.doc.fileReadVisibility
|
|
365
|
+
: effectiveRung(c.doc, ceil, 'fileReadVisibility');
|
|
354
366
|
const doc = rung === c.doc.fileReadVisibility && displayName(c.doc.name) === c.doc.name
|
|
355
367
|
? c.doc
|
|
356
368
|
: { ...c.doc, fileReadVisibility: rung, name: displayName(c.doc.name) };
|
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
/** The
|
|
2
|
-
*
|
|
3
|
-
* `preview` → the routing line).
|
|
1
|
+
/** The system-prompt memory block: the always-present memory-usage guidance,
|
|
2
|
+
* then (when any are eligible) the `kind: preference` docs in one tree at their
|
|
3
|
+
* effective rung (the preference default rung is `preview` → the routing line).
|
|
4
|
+
* ALWAYS returns a non-empty `<memory kind="preference">` block — the guidance
|
|
5
|
+
* frame is unconditional, so the system-prompt splice is never empty even when
|
|
6
|
+
* no preference is eligible. */
|
|
4
7
|
export declare function renderPreferencesSection(nodeId: string): string;
|
|
5
|
-
/** The `<knowledge>` block embedded
|
|
6
|
-
* message (bearings.ts pushes
|
|
8
|
+
/** The `<memory kind="knowledge">` block embedded in the session_start bearings
|
|
9
|
+
* message (bearings.ts pushes it as a SIBLING of `<crtr-bearings>`, or drops it
|
|
7
10
|
* when ''). The consultable catalog: every eligible `kind: knowledge` resolver
|
|
8
11
|
* doc at its effective rung (most surface only as `[+N more]` counts unless
|
|
9
12
|
* author-promoted) PLUS the node-local memory docs (any kind), the latter
|
|
10
13
|
* floored to `name` so a `none`-rung node-local doc still shows its name rather
|
|
11
|
-
* than collapsing into a count. Procedural
|
|
12
|
-
* live here
|
|
13
|
-
* nothing is eligible. */
|
|
14
|
+
* than collapsing into a count. Procedural guidance and factual references both
|
|
15
|
+
* live here as `knowledge`. Returns '' when nothing is eligible. */
|
|
14
16
|
export declare function renderKnowledgeBlock(nodeId: string): string;
|
|
15
|
-
/** The memory-hygiene directive spliced into the system prompt after the
|
|
16
|
-
* preferences block. ALWAYS present for a canvas node (the memory system always
|
|
17
|
-
* exists), so the system-prompt splice stays non-empty even when both trees are
|
|
18
|
-
* empty. Guidance about USING the memory system, not a per-doc surface. */
|
|
19
|
-
export declare function renderMemoryGuidance(): string;
|