@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
|
Binary file
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<meta name="color-scheme" content="dark light" />
|
|
6
7
|
<title>crouter</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-D36PNBj4.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BZUxTkv5.css">
|
|
9
10
|
</head>
|
|
10
11
|
<body>
|
|
11
12
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crouton-kit/crouter",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "crtr —
|
|
3
|
+
"version": "0.3.33",
|
|
4
|
+
"description": "crtr — agent runtime with memory, plugins, and marketplaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -28,7 +28,10 @@
|
|
|
28
28
|
"bin"
|
|
29
29
|
],
|
|
30
30
|
"scripts": {
|
|
31
|
-
"build": "rm -rf dist && tsc && cp -R src/builtin-personas dist/builtin-personas && cp -R src/builtin-views dist/builtin-views && cp -R src/builtin-memory dist/builtin-memory && vite build --config src/clients/web/web-client/vite.config.ts",
|
|
31
|
+
"build": "rm -rf dist && tsc && cp -R src/builtin-personas dist/builtin-personas && cp -R src/builtin-views dist/builtin-views && cp -R src/builtin-memory dist/builtin-memory && npm run build:attach && vite build --config src/clients/web/web-client/vite.config.ts",
|
|
32
|
+
"lint:web-px": "node scripts/lint-web-px.mjs",
|
|
33
|
+
"build:attach": "esbuild src/clients/attach/attach-cmd.ts --bundle --minify --format=esm --platform=node --target=node22 --alias:@earendil-works/pi-tui=$PWD/node_modules/@earendil-works/pi-tui --outfile=dist/clients/attach/attach-cmd.js --log-level=warning --banner:js=\"import{createRequire as __cr}from'node:module';const require=__cr(import.meta.url);\"",
|
|
34
|
+
"hearth:wake-proxy": "node dist/hearth/wake-proxy/main.js",
|
|
32
35
|
"dev": "tsx src/cli.ts",
|
|
33
36
|
"link": "npm link",
|
|
34
37
|
"prepublishOnly": "npm run build",
|
|
@@ -41,26 +44,45 @@
|
|
|
41
44
|
},
|
|
42
45
|
"license": "MIT",
|
|
43
46
|
"dependencies": {
|
|
44
|
-
"@
|
|
45
|
-
"@
|
|
46
|
-
"@earendil-works/pi-
|
|
47
|
-
"@earendil-works/pi-
|
|
47
|
+
"@blaxel/core": "^0.2.94",
|
|
48
|
+
"@crouton-kit/humanloop": "^0.3.19",
|
|
49
|
+
"@earendil-works/pi-agent-core": "0.79.9",
|
|
50
|
+
"@earendil-works/pi-ai": "0.79.9",
|
|
51
|
+
"@earendil-works/pi-coding-agent": "0.79.9",
|
|
52
|
+
"@earendil-works/pi-tui": "0.79.9",
|
|
53
|
+
"@fontsource-variable/fraunces": "^5.2.9",
|
|
54
|
+
"@fontsource-variable/instrument-sans": "^5.2.8",
|
|
55
|
+
"@fontsource-variable/martian-mono": "^5.2.7",
|
|
56
|
+
"@fontsource/fragment-mono": "^5.2.8",
|
|
48
57
|
"@tailwindcss/vite": "^4.3.0",
|
|
58
|
+
"@tanstack/react-virtual": "^3.13.0",
|
|
59
|
+
"@types/markdown-it": "^14.1.2",
|
|
49
60
|
"@vitejs/plugin-react": "^6.0.2",
|
|
50
|
-
"
|
|
51
|
-
"
|
|
61
|
+
"class-variance-authority": "^0.7.1",
|
|
62
|
+
"clsx": "^2.1.1",
|
|
63
|
+
"cron-parser": "^5.6.0",
|
|
64
|
+
"dompurify": "^3.2.3",
|
|
65
|
+
"highlight.js": "^11.11.1",
|
|
66
|
+
"lucide-react": "^0.469.0",
|
|
67
|
+
"markdown-it": "^14.1.0",
|
|
68
|
+
"radix-ui": "^1.5.0",
|
|
52
69
|
"react": "^19.2.7",
|
|
53
70
|
"react-dom": "^19.2.7",
|
|
71
|
+
"react-router-dom": "^7.1.1",
|
|
72
|
+
"tailwind-merge": "^2.6.0",
|
|
54
73
|
"tailwindcss": "^4.3.0",
|
|
74
|
+
"tw-animate-css": "^1.0.0",
|
|
55
75
|
"vite": "^8.0.16",
|
|
56
76
|
"ws": "^8.21.0",
|
|
57
|
-
"yaml": "^2.9.0"
|
|
77
|
+
"yaml": "^2.9.0",
|
|
78
|
+
"zustand": "^5.0.2"
|
|
58
79
|
},
|
|
59
80
|
"devDependencies": {
|
|
60
81
|
"@types/node": "^22.0.0",
|
|
61
82
|
"@types/react": "^19.2.17",
|
|
62
83
|
"@types/react-dom": "^19.2.3",
|
|
63
84
|
"@types/ws": "^8.18.1",
|
|
85
|
+
"esbuild": "^0.27.7",
|
|
64
86
|
"tsx": "^4.0.0",
|
|
65
87
|
"typescript": "^5.7.0"
|
|
66
88
|
}
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
// Run with: node --import tsx/esm --test src/core/__tests__/error-stall-recycle.test.ts
|
|
2
|
-
//
|
|
3
|
-
// BUG-REGRESSION (§I error-stall; gh issue #4 — node mqaeqzdu-0746b3b7, a 9h
|
|
4
|
-
// zombie). A provider outage exhausted the engine's SDK retry budget mid-task:
|
|
5
|
-
// pi appended trailing stopReason:'error' assistant messages to the session
|
|
6
|
-
// .jsonl and PARKED (the stophook's agent_end returns early on 'error' — "stay
|
|
7
|
-
// alive for re-steering"). A headless node has no human to re-steer it, so the
|
|
8
|
-
// broker stayed alive, status stayed 'active', and the daemon's pid-only
|
|
9
|
-
// liveness check read it healthy for 9 hours while its parent believed it was
|
|
10
|
-
// working. The daemon is the authority: a live, not-busy, intent-null engine
|
|
11
|
-
// whose session file has been quiet past ERROR_STALL_QUIET_MS and whose last
|
|
12
|
-
// assistant message stopped with 'error' is force-killed, so the ordinary
|
|
13
|
-
// dead-pid crash path grace-revives RESUME on the saved session — the exact
|
|
14
|
-
// manual recovery (kill broker + canvas revive) that fixed the zombie by hand.
|
|
15
|
-
//
|
|
16
|
-
// Three legs: the pure truth table (E1 — errorStallVerdict), the tail-signature
|
|
17
|
-
// parser (E2 — trailingEngineError), and the daemon integration over a real
|
|
18
|
-
// live pid the daemon must SIGTERM (E3 — superviseTick with an injected clock).
|
|
19
|
-
// Regression check: drop §I and E3's "engine killed" assert goes RED (the
|
|
20
|
-
// parked error engine lives forever, never recovered).
|
|
21
|
-
import { test } from 'node:test';
|
|
22
|
-
import assert from 'node:assert/strict';
|
|
23
|
-
import { spawn } from 'node:child_process';
|
|
24
|
-
import { writeFileSync, utimesSync, mkdtempSync, rmSync } from 'node:fs';
|
|
25
|
-
import { join } from 'node:path';
|
|
26
|
-
import { tmpdir } from 'node:os';
|
|
27
|
-
import { createHeadlessHarness } from './helpers/harness.js';
|
|
28
|
-
import { errorStallVerdict, trailingEngineError, ERROR_STALL_QUIET_MS, isPidAlive, } from '../../daemon/crtrd.js';
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
// Session-jsonl line builders (the shape pi writes: {type:'message', message}).
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
function line(message) {
|
|
33
|
-
return JSON.stringify({ type: 'message', id: 'x', timestamp: new Date().toISOString(), message });
|
|
34
|
-
}
|
|
35
|
-
const assistant = (stopReason, errorMessage) => line({ role: 'assistant', stopReason, ...(errorMessage === undefined ? {} : { errorMessage }) });
|
|
36
|
-
const toolResult = () => line({ role: 'toolResult' });
|
|
37
|
-
const user = () => line({ role: 'user' });
|
|
38
|
-
// ---------------------------------------------------------------------------
|
|
39
|
-
// E1 — the pure error-stall truth table.
|
|
40
|
-
// ---------------------------------------------------------------------------
|
|
41
|
-
test('E1 errorStallVerdict: kill ONLY a live, not-busy, intent-null engine, quiet past grace, with a trailing error', () => {
|
|
42
|
-
const G = ERROR_STALL_QUIET_MS;
|
|
43
|
-
// The one 'kill' case.
|
|
44
|
-
assert.equal(errorStallVerdict(true, null, false, G, true), 'kill', 'alive+no-intent+!busy+quiet>=grace+error → kill');
|
|
45
|
-
assert.equal(errorStallVerdict(true, null, false, G + 60_000, true), 'kill', 'well past grace → kill');
|
|
46
|
-
// Recent session activity → leave (something is still making progress).
|
|
47
|
-
assert.equal(errorStallVerdict(true, null, false, G - 1, true), 'leave', 'within quiet grace → leave');
|
|
48
|
-
assert.equal(errorStallVerdict(true, null, false, null, true), 'leave', 'unknown quiet span → leave');
|
|
49
|
-
// No trailing error → a healthy park (attended root, awaiting node) — leave.
|
|
50
|
-
assert.equal(errorStallVerdict(true, null, false, G + 60_000, false), 'leave', 'last turn not an error → leave');
|
|
51
|
-
// A working engine is NEVER killed (wedged-on-bash is recovered by killing the
|
|
52
|
-
// subprocess, not the node).
|
|
53
|
-
assert.equal(errorStallVerdict(true, null, true, G + 60_000, true), 'leave', 'busy (mid-turn) → leave');
|
|
54
|
-
// A pending intent belongs to other paths (§H refresh; idle-release dormancy).
|
|
55
|
-
assert.equal(errorStallVerdict(true, 'refresh', false, G + 60_000, true), 'leave', 'intent=refresh → leave (§H owns it)');
|
|
56
|
-
assert.equal(errorStallVerdict(true, 'idle-release', false, G + 60_000, true), 'leave', 'intent=idle-release → leave');
|
|
57
|
-
// A dead/unknown pid is the ordinary revive path's job.
|
|
58
|
-
assert.equal(errorStallVerdict(false, null, false, G + 60_000, true), 'leave', 'dead pid → leave');
|
|
59
|
-
assert.equal(errorStallVerdict(null, null, false, G + 60_000, true), 'leave', 'unknown pid → leave');
|
|
60
|
-
});
|
|
61
|
-
// ---------------------------------------------------------------------------
|
|
62
|
-
// E2 — the tail-signature parser.
|
|
63
|
-
// ---------------------------------------------------------------------------
|
|
64
|
-
test('E2 trailingEngineError: only a trailing error assistant turn matches', () => {
|
|
65
|
-
// The observed zombie shape: trailing zero-token error assistant messages.
|
|
66
|
-
assert.equal(trailingEngineError([assistant('toolUse'), toolResult(), assistant('error', 'Connection error.')].join('\n')), 'Connection error.', 'trailing error turn → its errorMessage');
|
|
67
|
-
// Trailing non-assistant lines (toolResults, an injected user message that
|
|
68
|
-
// never got a response) are walked past to the last assistant turn.
|
|
69
|
-
assert.equal(trailingEngineError([assistant('error', 'Connection error.'), user()].join('\n')), 'Connection error.', 'trailing injected user line is walked past');
|
|
70
|
-
// A healthy park / human abort is NOT a wedge.
|
|
71
|
-
assert.equal(trailingEngineError([assistant('error', 'x'), toolResult(), assistant('stop')].join('\n')), null, 'recovered after an earlier error → null');
|
|
72
|
-
assert.equal(trailingEngineError(assistant('aborted')), null, 'human Esc → null');
|
|
73
|
-
// A tail cut mid-line (the 64KB boundary) is skipped, not fatal.
|
|
74
|
-
assert.equal(trailingEngineError(['ut"}}garbage-fragment', assistant('error', 'boom')].join('\n')), 'boom', 'cut first fragment is skipped');
|
|
75
|
-
// An error turn with no errorMessage still reads as a wedge.
|
|
76
|
-
assert.notEqual(trailingEngineError(assistant('error')), null, 'error with no errorMessage still matches');
|
|
77
|
-
assert.equal(trailingEngineError(null), null, 'no tail → null');
|
|
78
|
-
assert.equal(trailingEngineError(''), null, 'empty tail → null');
|
|
79
|
-
});
|
|
80
|
-
// ---------------------------------------------------------------------------
|
|
81
|
-
// E3 — daemon integration: a parked trailing-error engine is force-recycled.
|
|
82
|
-
// ---------------------------------------------------------------------------
|
|
83
|
-
const T0 = 9_000_000_000;
|
|
84
|
-
test('E3 daemon force-kills a wedged engine: live, not-busy, intent-null, session quiet past grace with a trailing error turn', { timeout: 30_000 }, async () => {
|
|
85
|
-
const h = await createHeadlessHarness({ sessionPrefix: 'crtr-e3' });
|
|
86
|
-
const dir = mkdtempSync(join(tmpdir(), 'crtr-e3-'));
|
|
87
|
-
// Real live subprocesses standing in for the parked engines; `sleep` dies on
|
|
88
|
-
// SIGTERM, so the daemon's force-kill is directly observable.
|
|
89
|
-
const wedged = spawn('sleep', ['300'], { stdio: 'ignore' });
|
|
90
|
-
const parked = spawn('sleep', ['300'], { stdio: 'ignore' });
|
|
91
|
-
try {
|
|
92
|
-
// The WEDGED node: session ends in an error turn, quiet for > the grace.
|
|
93
|
-
const wedgedFile = join(dir, 'wedged.jsonl');
|
|
94
|
-
writeFileSync(wedgedFile, [assistant('toolUse'), toolResult(), assistant('error', 'Connection error.')].join('\n') + '\n');
|
|
95
|
-
const staleSec = (T0 - ERROR_STALL_QUIET_MS - 1) / 1000;
|
|
96
|
-
utimesSync(wedgedFile, staleSec, staleSec);
|
|
97
|
-
const wedgedId = h.fabricateBrokerNode({
|
|
98
|
-
kind: 'developer',
|
|
99
|
-
status: 'active',
|
|
100
|
-
pi_pid: wedged.pid,
|
|
101
|
-
pi_session_id: 'sess-e3-wedged',
|
|
102
|
-
pi_session_file: wedgedFile,
|
|
103
|
-
});
|
|
104
|
-
// The CONTROL node: equally old and quiet, but its last turn is a healthy
|
|
105
|
-
// 'stop' (an attended root overnight) — must NEVER be killed.
|
|
106
|
-
const parkedFile = join(dir, 'parked.jsonl');
|
|
107
|
-
writeFileSync(parkedFile, [assistant('toolUse'), toolResult(), assistant('stop')].join('\n') + '\n');
|
|
108
|
-
utimesSync(parkedFile, staleSec, staleSec);
|
|
109
|
-
h.fabricateBrokerNode({
|
|
110
|
-
kind: 'developer',
|
|
111
|
-
status: 'active',
|
|
112
|
-
pi_pid: parked.pid,
|
|
113
|
-
pi_session_id: 'sess-e3-parked',
|
|
114
|
-
pi_session_file: parkedFile,
|
|
115
|
-
});
|
|
116
|
-
assert.equal(isPidAlive(wedged.pid), true, 'precondition: the wedged engine is alive');
|
|
117
|
-
// --- TICK @ T0: the session has already been quiet past the grace (the
|
|
118
|
-
// file mtime is the clock — no arming tick), so the daemon SIGTERMs
|
|
119
|
-
// the wedged engine on sight. ---
|
|
120
|
-
await h.tick(T0);
|
|
121
|
-
await h.waitFor(() => (isPidAlive(wedged.pid) ? null : true), {
|
|
122
|
-
label: 'daemon SIGTERM killed the wedged trailing-error engine (§I)',
|
|
123
|
-
timeoutMs: 10_000,
|
|
124
|
-
});
|
|
125
|
-
assert.equal(isPidAlive(wedged.pid), false, 'the wedged engine was force-killed');
|
|
126
|
-
assert.equal(isPidAlive(parked.pid), true, 'the healthily-parked engine was NOT touched');
|
|
127
|
-
assert.equal(h.node(wedgedId).intent ?? null, null, 'intent stays null — the dead-pid CRASH branch owns the revive (resume)');
|
|
128
|
-
}
|
|
129
|
-
finally {
|
|
130
|
-
for (const c of [wedged, parked]) {
|
|
131
|
-
try {
|
|
132
|
-
c.kill('SIGKILL');
|
|
133
|
-
}
|
|
134
|
-
catch {
|
|
135
|
-
/* already gone */
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
rmSync(dir, { recursive: true, force: true });
|
|
139
|
-
await h.dispose();
|
|
140
|
-
}
|
|
141
|
-
});
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
// Regression test for the `--dry-run` `wrote` count (found by P8 integration).
|
|
2
|
-
//
|
|
3
|
-
// Bug: under `--dry-run`, reconcilePair returned `wrote: counts.writes` — the
|
|
4
|
-
// WOULD-BE endpoint write total — even though nothing is written to disk. That
|
|
5
|
-
// contradicts the `sys sync -h` contract ("wrote … 0 under --dry-run") and the
|
|
6
|
-
// rendered "DRY RUN (nothing written)" header, which together promise 0. The
|
|
7
|
-
// fix makes `wrote` reflect ACTUAL writes (0 under dry-run) while still using
|
|
8
|
-
// the would-be counts internally to decide synced-vs-noop.
|
|
9
|
-
//
|
|
10
|
-
// This test FAILS on the pre-fix code (wrote === number of files that WOULD be
|
|
11
|
-
// written, e.g. 2 for a one-sided bootstrap) and PASSES on the current code.
|
|
12
|
-
//
|
|
13
|
-
// Run: node --import tsx/esm --test src/core/skill-sync/__tests__/dry-run-wrote-count.test.ts
|
|
14
|
-
import { test, before, after } from 'node:test';
|
|
15
|
-
import assert from 'node:assert/strict';
|
|
16
|
-
import { mkdtempSync, rmSync, mkdirSync, writeFileSync, existsSync } from 'node:fs';
|
|
17
|
-
import { tmpdir, homedir } from 'node:os';
|
|
18
|
-
import { join } from 'node:path';
|
|
19
|
-
import { reconcilePair } from '../engine.js';
|
|
20
|
-
import { DEFAULT_PROFILE } from '../profile.js';
|
|
21
|
-
// The engine resolves user-scope endpoints + the snapshot store off homedir(),
|
|
22
|
-
// which reads $HOME at call time — so isolating $HOME isolates everything.
|
|
23
|
-
let home;
|
|
24
|
-
let prevHome;
|
|
25
|
-
const PAIR = {
|
|
26
|
-
id: 'dryrun-regression',
|
|
27
|
-
crtr: { scope: 'user', name: 'dr' },
|
|
28
|
-
claude: { scope: 'user', name: 'dr' },
|
|
29
|
-
};
|
|
30
|
-
before(() => {
|
|
31
|
-
prevHome = process.env.HOME;
|
|
32
|
-
home = mkdtempSync(join(tmpdir(), 'crtr-sync-dryrun-'));
|
|
33
|
-
process.env.HOME = home;
|
|
34
|
-
// One-sided bootstrap: only the crtr side exists. A real sync here would
|
|
35
|
-
// materialize the Claude side + write the snapshot (2 endpoint files written).
|
|
36
|
-
const crtrDir = join(home, '.crouter', 'memory', 'dr');
|
|
37
|
-
mkdirSync(crtrDir, { recursive: true });
|
|
38
|
-
writeFileSync(join(crtrDir, 'SKILL.md'), '---\nkind: knowledge\nwhen-and-why-to-read: "When the regression applies, this doc should be read."\n---\n# DR\nbody\n', 'utf8');
|
|
39
|
-
});
|
|
40
|
-
after(() => {
|
|
41
|
-
if (prevHome === undefined)
|
|
42
|
-
delete process.env.HOME;
|
|
43
|
-
else
|
|
44
|
-
process.env.HOME = prevHome;
|
|
45
|
-
rmSync(home, { recursive: true, force: true });
|
|
46
|
-
assert.equal(homedir(), prevHome ?? homedir()); // sanity: $HOME restored
|
|
47
|
-
});
|
|
48
|
-
test('--dry-run reports wrote === 0 and writes nothing to disk', () => {
|
|
49
|
-
const res = reconcilePair(PAIR, DEFAULT_PROFILE, { dryRun: true });
|
|
50
|
-
// Status still reflects that a real run WOULD sync this pair...
|
|
51
|
-
assert.equal(res.status, 'synced', 'dry-run should still classify the pending change as synced');
|
|
52
|
-
// ...but the `wrote` count is ACTUAL writes — zero under --dry-run.
|
|
53
|
-
assert.equal(res.wrote, 0, 'dry-run must report wrote === 0 (contract: 0 under --dry-run)');
|
|
54
|
-
// And nothing was actually written: no Claude bundle, no snapshot.
|
|
55
|
-
assert.ok(!existsSync(join(home, '.claude', 'skills', 'dr', 'SKILL.md')), 'dry-run must not materialize the Claude endpoint');
|
|
56
|
-
assert.ok(!existsSync(join(home, '.crouter', 'skill-sync', 'snapshots', PAIR.id)), 'dry-run must not write the snapshot base');
|
|
57
|
-
});
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Built-in export registry for the skill-sync subsystem.
|
|
3
|
-
*
|
|
4
|
-
* These are the crtr-*generated* host artifacts — the `crtr-skills` boot skill
|
|
5
|
-
* and any CLI slash-commands. Unlike the user-authored bidirectional manifest
|
|
6
|
-
* pairs (engine.ts), an export pair has a single source of truth (code), so it
|
|
7
|
-
* is one-way: render → marker-guarded write (see export.ts). The generators
|
|
8
|
-
* (`bootSkillBody`, `renderSlashTemplate`) and their version markers were moved
|
|
9
|
-
* here verbatim from bootstrap.ts when skill-sync became the sole host writer —
|
|
10
|
-
* marker strings are byte-identical so already-deployed artifacts roll forward.
|
|
11
|
-
*/
|
|
12
|
-
import { homedir } from 'node:os';
|
|
13
|
-
import { join } from 'node:path';
|
|
14
|
-
import { collectSlashSpecs } from '../command.js';
|
|
15
|
-
// ── Boot skill ───────────────────────────────────────────────────────────────
|
|
16
|
-
const BOOT_SKILL_NAME = 'crtr-skills';
|
|
17
|
-
const BOOT_SKILL_MARKER = '<!-- crtr-boot-skill v2 -->';
|
|
18
|
-
export const BOOT_SKILL_MARKER_PREFIX = '<!-- crtr-boot-skill v';
|
|
19
|
-
function bootSkillBody() {
|
|
20
|
-
return `---
|
|
21
|
-
name: crtr-skills
|
|
22
|
-
description: 'Author, list, search, and load crtr memory documents (knowledge, preferences) via the crtr CLI. These are durable agent memory — markdown future LLM sessions load on demand. Use when the user wants to remember/save knowledge, build a context primer, or recall a previously saved doc. Triggers: "save", "remember", "build context for", "what skills do we have", "skill for X".'
|
|
23
|
-
argument-hint: [topic or verb]
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
${BOOT_SKILL_MARKER}
|
|
27
|
-
|
|
28
|
-
# /crtr-skills — crtr memory router
|
|
29
|
-
|
|
30
|
-
crtr memory documents = durable agent memory (kind: knowledge or preference).
|
|
31
|
-
Written for **future LLM sessions**, not the user. \`crtr memory\` is the
|
|
32
|
-
surface — author, discover, and load them.
|
|
33
|
-
|
|
34
|
-
## Route by intent
|
|
35
|
-
|
|
36
|
-
- **Capture** ("save", "remember", "build context for", "make a skill"):
|
|
37
|
-
\`crtr memory write <name> --kind <knowledge|preference>\` with the
|
|
38
|
-
body piped on stdin — e.g.
|
|
39
|
-
\`crtr memory write $ARGUMENTS --kind knowledge <<'EOF' … EOF\`. Run
|
|
40
|
-
\`crtr memory write -h\` for the full frontmatter schema
|
|
41
|
-
(--when-and-why-to-read, --short-form, --scope, visibility rungs), then
|
|
42
|
-
\`crtr memory lint\` to validate what you wrote.
|
|
43
|
-
- **Find** ("what do we have on X"): \`crtr memory find "$ARGUMENTS"\` →
|
|
44
|
-
\`crtr memory read <name>\` on the best hit (add --body/--grep to search
|
|
45
|
-
bodies).
|
|
46
|
-
- **Load by name**: \`crtr memory read <name>\`.
|
|
47
|
-
- **List all**: \`crtr memory list\`.
|
|
48
|
-
|
|
49
|
-
If \`$ARGUMENTS\` is empty, ask the user what they want before running.
|
|
50
|
-
|
|
51
|
-
## Rules
|
|
52
|
-
|
|
53
|
-
- CLI stdout is the prompt — act on it, don't paraphrase to the user.
|
|
54
|
-
- Append \`-h\` at any leaf (\`crtr memory write -h\`) for its full schema
|
|
55
|
-
before authoring.
|
|
56
|
-
- If \`crtr\` is not on PATH, tell the user and stop.
|
|
57
|
-
`;
|
|
58
|
-
}
|
|
59
|
-
// ── Slash commands ───────────────────────────────────────────────────────────
|
|
60
|
-
const SLASH_CMD_MARKER = '<!-- crtr-mode-cmd v1 -->';
|
|
61
|
-
export const SLASH_CMD_MARKER_PREFIX = '<!-- crtr-mode-cmd v';
|
|
62
|
-
/** Render a SlashSpec to a full template file (frontmatter + marker + body). */
|
|
63
|
-
function renderSlashTemplate(spec) {
|
|
64
|
-
const hint = spec.argumentHint !== undefined
|
|
65
|
-
? `argument-hint: ${JSON.stringify(spec.argumentHint)}\n`
|
|
66
|
-
: '';
|
|
67
|
-
return `---\ndescription: ${spec.description}\n${hint}---\n\n${SLASH_CMD_MARKER}\n\n${spec.body}\n`;
|
|
68
|
-
}
|
|
69
|
-
// ── Host roots ───────────────────────────────────────────────────────────────
|
|
70
|
-
function claudeSkillsRoot() {
|
|
71
|
-
return join(homedir(), '.claude', 'skills');
|
|
72
|
-
}
|
|
73
|
-
function piSkillsRoot() {
|
|
74
|
-
return join(homedir(), '.pi', 'agent', 'skills');
|
|
75
|
-
}
|
|
76
|
-
function claudeCommandsRoot() {
|
|
77
|
-
return join(homedir(), '.claude', 'commands');
|
|
78
|
-
}
|
|
79
|
-
function piPromptsRoot() {
|
|
80
|
-
return join(homedir(), '.pi', 'agent', 'prompts');
|
|
81
|
-
}
|
|
82
|
-
// ── Registry ─────────────────────────────────────────────────────────────────
|
|
83
|
-
/** The crtr-generated export artifacts for this command tree: the boot skill
|
|
84
|
-
* (both hosts, bundle layout) plus one pair per opted-in slash command (both
|
|
85
|
-
* hosts, file layout). */
|
|
86
|
-
export function builtinExportPairs(root) {
|
|
87
|
-
const pairs = [
|
|
88
|
-
{
|
|
89
|
-
id: '@boot/crtr-skills',
|
|
90
|
-
name: BOOT_SKILL_NAME,
|
|
91
|
-
markerPrefix: BOOT_SKILL_MARKER_PREFIX,
|
|
92
|
-
render: bootSkillBody,
|
|
93
|
-
targets: [
|
|
94
|
-
{ host: 'claude', dir: claudeSkillsRoot, layout: 'bundle' },
|
|
95
|
-
{ host: 'pi', dir: piSkillsRoot, layout: 'bundle' },
|
|
96
|
-
],
|
|
97
|
-
},
|
|
98
|
-
];
|
|
99
|
-
for (const spec of collectSlashSpecs(root)) {
|
|
100
|
-
pairs.push({
|
|
101
|
-
id: `@cmd/${spec.name}`,
|
|
102
|
-
name: spec.name,
|
|
103
|
-
markerPrefix: SLASH_CMD_MARKER_PREFIX,
|
|
104
|
-
render: () => renderSlashTemplate(spec),
|
|
105
|
-
targets: [
|
|
106
|
-
{ host: 'claude', dir: claudeCommandsRoot, layout: 'file' },
|
|
107
|
-
{ host: 'pi', dir: piPromptsRoot, layout: 'file' },
|
|
108
|
-
],
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
return pairs;
|
|
112
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude-plugin endpoint resolution for skill-sync.
|
|
3
|
-
*
|
|
4
|
-
* The `claude-plugin` endpoint scope addresses a skill IN PLACE at the path
|
|
5
|
-
* where Claude actually installs the owning plugin — `<installPath>/skills/<name>`
|
|
6
|
-
* — instead of forcing a copy under `~/.claude/skills/`. The install path is read
|
|
7
|
-
* from Claude's OWN registry (`~/.claude/plugins/installed_plugins.json`), keyed
|
|
8
|
-
* by the marketplace-qualified plugin key (`<plugin>@<marketplace>`), gated on the
|
|
9
|
-
* enable state in `~/.claude/settings.json` → `enabledPlugins`.
|
|
10
|
-
*
|
|
11
|
-
* This is Claude's registry, deliberately NOT crtr's plugin registry
|
|
12
|
-
* (`resolver.ts` / `findPluginByName`): the two are independent installs.
|
|
13
|
-
*
|
|
14
|
-
* Strictness (no lenient fallback): a key that is unknown, disabled, or whose
|
|
15
|
-
* recorded install path is missing on disk is a HARD error naming it.
|
|
16
|
-
*/
|
|
17
|
-
/**
|
|
18
|
-
* Resolve a Claude plugin's on-disk install path from its marketplace-qualified
|
|
19
|
-
* key (`<plugin>@<marketplace>`, e.g. `devcore@crouton-kit`). Throws naming the
|
|
20
|
-
* key when it is not installed, not enabled, or has no install path present on
|
|
21
|
-
* disk.
|
|
22
|
-
*/
|
|
23
|
-
export declare function resolveClaudePluginInstallPath(key: string): string;
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude-plugin endpoint resolution for skill-sync.
|
|
3
|
-
*
|
|
4
|
-
* The `claude-plugin` endpoint scope addresses a skill IN PLACE at the path
|
|
5
|
-
* where Claude actually installs the owning plugin — `<installPath>/skills/<name>`
|
|
6
|
-
* — instead of forcing a copy under `~/.claude/skills/`. The install path is read
|
|
7
|
-
* from Claude's OWN registry (`~/.claude/plugins/installed_plugins.json`), keyed
|
|
8
|
-
* by the marketplace-qualified plugin key (`<plugin>@<marketplace>`), gated on the
|
|
9
|
-
* enable state in `~/.claude/settings.json` → `enabledPlugins`.
|
|
10
|
-
*
|
|
11
|
-
* This is Claude's registry, deliberately NOT crtr's plugin registry
|
|
12
|
-
* (`resolver.ts` / `findPluginByName`): the two are independent installs.
|
|
13
|
-
*
|
|
14
|
-
* Strictness (no lenient fallback): a key that is unknown, disabled, or whose
|
|
15
|
-
* recorded install path is missing on disk is a HARD error naming it.
|
|
16
|
-
*/
|
|
17
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
18
|
-
import { homedir } from 'node:os';
|
|
19
|
-
import { join } from 'node:path';
|
|
20
|
-
import { usage } from '../errors.js';
|
|
21
|
-
function claudeDir() {
|
|
22
|
-
return join(homedir(), '.claude');
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Resolve a Claude plugin's on-disk install path from its marketplace-qualified
|
|
26
|
-
* key (`<plugin>@<marketplace>`, e.g. `devcore@crouton-kit`). Throws naming the
|
|
27
|
-
* key when it is not installed, not enabled, or has no install path present on
|
|
28
|
-
* disk.
|
|
29
|
-
*/
|
|
30
|
-
export function resolveClaudePluginInstallPath(key) {
|
|
31
|
-
const registryPath = join(claudeDir(), 'plugins', 'installed_plugins.json');
|
|
32
|
-
if (!existsSync(registryPath)) {
|
|
33
|
-
throw usage(`skill-sync: Claude plugin registry not found at ${registryPath}`);
|
|
34
|
-
}
|
|
35
|
-
let registry;
|
|
36
|
-
try {
|
|
37
|
-
registry = JSON.parse(readFileSync(registryPath, 'utf8'));
|
|
38
|
-
}
|
|
39
|
-
catch (err) {
|
|
40
|
-
throw usage(`skill-sync: invalid ${registryPath}: ${err.message}`);
|
|
41
|
-
}
|
|
42
|
-
const entries = registry.plugins?.[key];
|
|
43
|
-
if (!Array.isArray(entries) || entries.length === 0) {
|
|
44
|
-
throw usage(`skill-sync: Claude plugin "${key}" is not installed ` +
|
|
45
|
-
`(no entry in ${registryPath})`);
|
|
46
|
-
}
|
|
47
|
-
if (!isClaudePluginEnabled(key)) {
|
|
48
|
-
throw usage(`skill-sync: Claude plugin "${key}" is installed but not enabled ` +
|
|
49
|
-
`(settings.json enabledPlugins)`);
|
|
50
|
-
}
|
|
51
|
-
const install = entries.find((e) => e.installPath && existsSync(e.installPath));
|
|
52
|
-
if (!install?.installPath) {
|
|
53
|
-
throw usage(`skill-sync: Claude plugin "${key}" has no install path present on disk`);
|
|
54
|
-
}
|
|
55
|
-
return install.installPath;
|
|
56
|
-
}
|
|
57
|
-
/** True iff `enabledPlugins[key] === true` in `~/.claude/settings.json`. A
|
|
58
|
-
* missing or unparseable settings file means "not enabled" — the caller turns
|
|
59
|
-
* that into a hard error naming the key. */
|
|
60
|
-
function isClaudePluginEnabled(key) {
|
|
61
|
-
const settingsPath = join(claudeDir(), 'settings.json');
|
|
62
|
-
if (!existsSync(settingsPath))
|
|
63
|
-
return false;
|
|
64
|
-
try {
|
|
65
|
-
const settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
66
|
-
return settings.enabledPlugins?.[key] === true;
|
|
67
|
-
}
|
|
68
|
-
catch {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reconcile engine (Phase P6) — the single, per-pair, direction-agnostic
|
|
3
|
-
* reconcile for bidirectional crtr ↔ Claude skill sync.
|
|
4
|
-
*
|
|
5
|
-
* `reconcilePair` is the ONLY reconcile routine (R-U3): there is no forward
|
|
6
|
-
* path + reverse path. Body and asset reconciliation is a symmetric 3-way merge
|
|
7
|
-
* (base = snapshot, ours = crtr, theirs = claude); frontmatter is the only
|
|
8
|
-
* asymmetric axis and all of that asymmetry lives in the translation profile
|
|
9
|
-
* (P5). The snapshot (P3) is the sole change-detector (R-U4): nothing here reads
|
|
10
|
-
* mtimes, fingerprints, or a stamp file.
|
|
11
|
-
*
|
|
12
|
-
* Strictness (R-U6): a conflict — overlapping body/asset merge, a both-sides
|
|
13
|
-
* non-equivalent frontmatter divergence, an asset deleted-on-one ∧ edited-on-the
|
|
14
|
-
* other, or a first-sync divergence with no common base — writes NOTHING for the
|
|
15
|
-
* pair, leaves both endpoints + the snapshot byte-untouched, and surfaces a
|
|
16
|
-
* git-style conflict report. There is no "best-effort" partial write and no
|
|
17
|
-
* silent side-pick.
|
|
18
|
-
*
|
|
19
|
-
* `--dry-run` (R-O1): every merge is computed and the would-be status returned,
|
|
20
|
-
* but no endpoint file, snapshot, or conflict report is touched.
|
|
21
|
-
*/
|
|
22
|
-
import type { Pair } from './manifest.js';
|
|
23
|
-
import type { TranslationProfile } from './profile.js';
|
|
24
|
-
/** The outcome of reconciling one pair. `wrote` counts endpoint files
|
|
25
|
-
* created/updated (never deletions, never the snapshot bookkeeping). */
|
|
26
|
-
export interface PairResult {
|
|
27
|
-
id: string;
|
|
28
|
-
status: 'synced' | 'conflict' | 'noop';
|
|
29
|
-
wrote: number;
|
|
30
|
-
}
|
|
31
|
-
export interface ReconcileOpts {
|
|
32
|
-
dryRun: boolean;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Reconcile a single enrolled pair (R-E2). Resolves both endpoints, loads (or
|
|
36
|
-
* seeds) the snapshot, 3-way merges body + assets and translate-and-owns the
|
|
37
|
-
* frontmatter, then either writes through cleanly to both sides or reports the
|
|
38
|
-
* conflict and skips. Never throws on a *content* conflict (that is a reported
|
|
39
|
-
* outcome); throws only on a structural/configuration error (an unresolvable
|
|
40
|
-
* endpoint, both endpoints missing) so the caller surfaces it as a hard stop.
|
|
41
|
-
*/
|
|
42
|
-
export declare function reconcilePair(pair: Pair, profile: TranslationProfile, opts: ReconcileOpts): PairResult;
|