@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
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* Model ladders settings — web presenter for the `settings` view.
|
|
4
|
+
*
|
|
5
|
+
* Mouse-first: enum fields (default provider, persona strength) are click-to-pick
|
|
6
|
+
* chips that save immediately; free-text fields (matrix model ids, new persona)
|
|
7
|
+
* open an inline editor prefilled with the current value, with Save/Cancel.
|
|
8
|
+
*
|
|
9
|
+
* @module settings/web
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { Loading, NotReady, ErrorState } from '@crouton-kit/crouter/web';
|
|
13
|
+
|
|
14
|
+
/** @typedef {import('./core.mjs').SettingsState} SettingsState */
|
|
15
|
+
|
|
16
|
+
const STRENGTHS = ['ultra', 'strong', 'medium', 'light'];
|
|
17
|
+
const PROVIDERS = ['anthropic', 'openai'];
|
|
18
|
+
|
|
19
|
+
/** Inline editor for a free-text field (matrix model id, new persona pair). */
|
|
20
|
+
/** @param {{ state: SettingsState, dispatch: (intent:string, payload?:unknown)=>void }} props */
|
|
21
|
+
function Editor({ state, dispatch }) {
|
|
22
|
+
if (!state.edit) return null;
|
|
23
|
+
return (
|
|
24
|
+
<div className="rounded border border-cyan-300 bg-cyan-50 p-3">
|
|
25
|
+
<div className="mb-2 text-sm text-slate-600">Editing <span className="font-semibold text-slate-900">{state.edit.label}</span></div>
|
|
26
|
+
<div className="flex items-center gap-2">
|
|
27
|
+
<input
|
|
28
|
+
autoFocus
|
|
29
|
+
value={state.edit.draft}
|
|
30
|
+
placeholder={state.edit.kind === 'personaNew' ? 'kind strength' : 'model id'}
|
|
31
|
+
onChange={(e) => dispatch('setDraft', e.target.value)}
|
|
32
|
+
onKeyDown={(e) => {
|
|
33
|
+
if (e.key === 'Enter') { e.preventDefault(); dispatch('submitEdit'); }
|
|
34
|
+
else if (e.key === 'Escape') { e.preventDefault(); dispatch('cancelEdit'); }
|
|
35
|
+
}}
|
|
36
|
+
className="flex-1 rounded border border-slate-300 bg-white px-3 py-2 font-mono text-sm outline-none focus:border-cyan-500"
|
|
37
|
+
/>
|
|
38
|
+
<button type="button" onClick={() => dispatch('submitEdit')} className="rounded bg-cyan-600 px-3 py-2 text-sm font-semibold text-white hover:bg-cyan-700">Save</button>
|
|
39
|
+
<button type="button" onClick={() => dispatch('cancelEdit')} className="rounded border border-slate-300 bg-white px-3 py-2 text-sm text-slate-600 hover:bg-slate-100">Cancel</button>
|
|
40
|
+
</div>
|
|
41
|
+
{state.edit.kind === 'personaNew' ? <div className="mt-2 text-xs text-slate-500">Format: <code>kind strength</code> or <code>kind=strength</code> (strength = ultra·strong·medium·light).</div> : null}
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** A small segmented control of fixed choices that saves on click. */
|
|
47
|
+
/** @param {{ choices: string[], value: string, onPick: (c:string)=>void }} props */
|
|
48
|
+
function Segmented({ choices, value, onPick }) {
|
|
49
|
+
return (
|
|
50
|
+
<div className="inline-flex overflow-hidden rounded border border-slate-300">
|
|
51
|
+
{choices.map((c) => (
|
|
52
|
+
<button
|
|
53
|
+
key={c}
|
|
54
|
+
type="button"
|
|
55
|
+
onClick={() => onPick(c)}
|
|
56
|
+
className={`px-2.5 py-1 text-sm capitalize ${c === value ? 'bg-cyan-600 text-white' : 'bg-white text-slate-600 hover:bg-slate-100'} ${c !== choices[0] ? 'border-l border-slate-300' : ''}`}
|
|
57
|
+
>
|
|
58
|
+
{c}
|
|
59
|
+
</button>
|
|
60
|
+
))}
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** True when the editor is currently targeting this matrix cell. */
|
|
66
|
+
/** @param {SettingsState} state @param {string} strength @param {string} provider */
|
|
67
|
+
function isEditingCell(state, strength, provider) {
|
|
68
|
+
return !!state.edit && state.edit.kind === 'matrixCell' && state.edit.strength === strength && state.edit.provider === provider;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** @param {import('../../core/view/contract.js').ViewProps<SettingsState>} props */
|
|
72
|
+
export default function Settings({ state, dispatch }) {
|
|
73
|
+
if (state.sourceError && state.modelLadders === null) {
|
|
74
|
+
const d = state.sourceError.display;
|
|
75
|
+
const Comp = d.level === 'error' ? ErrorState : NotReady;
|
|
76
|
+
return <Comp headline={d.headline} explanation={d.explanation} nextStep={d.nextStep || undefined} onRetry={() => dispatch('refresh')} />;
|
|
77
|
+
}
|
|
78
|
+
if (state.modelLadders === null) {
|
|
79
|
+
return <Loading label="Loading model ladders…" />;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const ladders = state.modelLadders;
|
|
83
|
+
const personas = Object.keys(state.personaStrengths).sort((a, b) => a.localeCompare(b));
|
|
84
|
+
const editingPersonaNew = !!state.edit && state.edit.kind === 'personaNew';
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<div className="h-full overflow-auto text-sm">
|
|
88
|
+
<div className="space-y-5 p-4">
|
|
89
|
+
<div>
|
|
90
|
+
<h1 className="text-base font-semibold">Model ladders</h1>
|
|
91
|
+
<p className="text-xs text-slate-500">Click a model id to edit it; click a provider or strength to switch it. Changes save immediately.</p>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
{/* Default provider — enum, click to pick. */}
|
|
95
|
+
<div className="flex items-center gap-3">
|
|
96
|
+
<span className="font-semibold">Default provider</span>
|
|
97
|
+
<Segmented choices={PROVIDERS} value={ladders.defaultProvider ?? 'anthropic'} onPick={(p) => dispatch('applyValue', { kind: 'defaultProvider', value: p })} />
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
{/* Provider × strength matrix — each model id click-to-edit. */}
|
|
101
|
+
<div className="space-y-3">
|
|
102
|
+
{STRENGTHS.map((strength) => (
|
|
103
|
+
<div key={strength}>
|
|
104
|
+
<div className="mb-1 font-semibold capitalize">{strength}</div>
|
|
105
|
+
<div className="grid grid-cols-1 gap-2 md:grid-cols-2">
|
|
106
|
+
{PROVIDERS.map((provider) => {
|
|
107
|
+
const editing = isEditingCell(state, strength, provider);
|
|
108
|
+
if (editing) {
|
|
109
|
+
return (
|
|
110
|
+
<div key={provider} className="rounded border border-cyan-300 bg-cyan-50 p-2">
|
|
111
|
+
<div className="mb-1 text-xs uppercase tracking-wide text-slate-400">{provider}</div>
|
|
112
|
+
<div className="flex items-center gap-2">
|
|
113
|
+
<input
|
|
114
|
+
autoFocus
|
|
115
|
+
value={state.edit.draft}
|
|
116
|
+
onChange={(e) => dispatch('setDraft', e.target.value)}
|
|
117
|
+
onKeyDown={(e) => {
|
|
118
|
+
if (e.key === 'Enter') { e.preventDefault(); dispatch('submitEdit'); }
|
|
119
|
+
else if (e.key === 'Escape') { e.preventDefault(); dispatch('cancelEdit'); }
|
|
120
|
+
}}
|
|
121
|
+
className="flex-1 rounded border border-slate-300 bg-white px-2 py-1 font-mono text-sm outline-none focus:border-cyan-500"
|
|
122
|
+
/>
|
|
123
|
+
<button type="button" onClick={() => dispatch('submitEdit')} className="rounded bg-cyan-600 px-2 py-1 text-xs font-semibold text-white hover:bg-cyan-700">Save</button>
|
|
124
|
+
<button type="button" onClick={() => dispatch('cancelEdit')} className="rounded border border-slate-300 bg-white px-2 py-1 text-xs text-slate-600 hover:bg-slate-100">Cancel</button>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
const v = ladders[provider]?.[strength] ?? '—';
|
|
130
|
+
return (
|
|
131
|
+
<button
|
|
132
|
+
key={provider}
|
|
133
|
+
type="button"
|
|
134
|
+
title="Click to edit"
|
|
135
|
+
onClick={() => dispatch('beginEditFor', { kind: 'matrix', strength, provider })}
|
|
136
|
+
className="rounded border border-slate-200 bg-white px-2 py-1 text-left hover:border-cyan-400 hover:bg-cyan-50"
|
|
137
|
+
>
|
|
138
|
+
<div className="text-xs uppercase tracking-wide text-slate-400">{provider}</div>
|
|
139
|
+
<div className="truncate font-mono text-sm text-slate-800">{v}</div>
|
|
140
|
+
</button>
|
|
141
|
+
);
|
|
142
|
+
})}
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
))}
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
{/* Persona strengths — enum per persona, click to pick. */}
|
|
149
|
+
<div className="space-y-2">
|
|
150
|
+
<div className="font-semibold">Persona strengths</div>
|
|
151
|
+
{personas.length === 0 ? <div className="text-xs text-slate-400">None set yet.</div> : null}
|
|
152
|
+
{personas.map((persona) => (
|
|
153
|
+
<div key={persona} className="flex items-center gap-3">
|
|
154
|
+
<span className="w-40 truncate font-mono text-slate-800">{persona}</span>
|
|
155
|
+
<Segmented choices={STRENGTHS} value={state.personaStrengths[persona] ?? 'strong'} onPick={(s) => dispatch('applyValue', { kind: 'personaStrength', persona, value: s })} />
|
|
156
|
+
</div>
|
|
157
|
+
))}
|
|
158
|
+
{editingPersonaNew ? (
|
|
159
|
+
<Editor state={state} dispatch={dispatch} />
|
|
160
|
+
) : (
|
|
161
|
+
<button type="button" onClick={() => dispatch('beginEditFor', { kind: 'addPersona' })} className="rounded border border-dashed border-emerald-400 px-3 py-1.5 text-sm font-semibold text-emerald-700 hover:bg-emerald-50">+ add persona strength</button>
|
|
162
|
+
)}
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
);
|
|
167
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { enableCompileCache } from 'node:module';
|
|
2
3
|
import { runCli } from './core/command.js';
|
|
3
4
|
import { resolveRoot } from './build-root.js';
|
|
4
5
|
import { maybeBootRoot } from './core/runtime/front-door.js';
|
|
5
6
|
import { maybeAutoUpdate } from './core/auto-update.js';
|
|
6
7
|
import { ensureOfficialMarketplace, ensureProjectScope } from './core/bootstrap.js';
|
|
7
|
-
import { provisionExports } from './core/
|
|
8
|
+
import { provisionExports } from './core/host-exports/export.js';
|
|
9
|
+
// V8 compile-cache (Node 22+): persist compiled bytecode across runs so a cold
|
|
10
|
+
// `crtr` re-spawn skips recompiling its module graph. Biggest payoff is the
|
|
11
|
+
// heavy attach-viewer bundle that main() dynamic-imports via resolveRoot — this
|
|
12
|
+
// runs first, so the cache is active before that import() compiles. Measured
|
|
13
|
+
// neutral on the tiny leaf path (feed/node), a clear win on attach. Best-effort:
|
|
14
|
+
// older Node lacks the API.
|
|
15
|
+
try {
|
|
16
|
+
enableCompileCache();
|
|
17
|
+
}
|
|
18
|
+
catch { /* pre-22 Node: no compile cache */ }
|
|
8
19
|
async function main() {
|
|
9
20
|
// Lazy command tree: load only the subtree this invocation dispatches into.
|
|
10
21
|
// resolveRoot returns the full tree only for help/version/bare/unknown, where
|
|
@@ -12,14 +23,16 @@ async function main() {
|
|
|
12
23
|
// hot leaf-dispatch path loads one subtree, keeping the other 11 (and their
|
|
13
24
|
// heavy deps — the attach TUI, web/vite) off cold-start.
|
|
14
25
|
const root = await resolveRoot(process.argv[2]);
|
|
26
|
+
// Prune legacy generated host artifacts before the front door can boot pi,
|
|
27
|
+
// otherwise stale Agent Skills can leak into the prompt for bare `crtr`.
|
|
28
|
+
provisionExports(root, process.argv);
|
|
15
29
|
// The front door: bare `crtr` (or `crtr [dir] ["prompt"]`) boots a resident
|
|
16
30
|
// root node and execs pi in this terminal. Recognized subcommands fall through
|
|
17
31
|
// to the normal dispatcher. Must run before anything that assumes a subcommand.
|
|
18
|
-
if (maybeBootRoot(root, process.argv)) {
|
|
32
|
+
if (await maybeBootRoot(root, process.argv)) {
|
|
19
33
|
// bootRoot exec'd pi inline and exited; unreachable.
|
|
20
34
|
}
|
|
21
35
|
ensureOfficialMarketplace(process.argv);
|
|
22
|
-
provisionExports(root);
|
|
23
36
|
ensureProjectScope(process.argv);
|
|
24
37
|
maybeAutoUpdate(process.argv);
|
|
25
38
|
await runCli(root, process.argv);
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { chmodSync, mkdtempSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { CombinedAutocompleteProvider } from '@earendil-works/pi-tui';
|
|
7
|
+
import { buildAttachAutocompleteProvider, deriveBashMode, resolveEditorFrameStyles } from '../attach-cmd.js';
|
|
8
|
+
function writeFakeFd(binDir) {
|
|
9
|
+
const fdBin = join(binDir, 'fd');
|
|
10
|
+
writeFileSync(fdBin, `#!/usr/bin/env node
|
|
11
|
+
const fs = require('node:fs');
|
|
12
|
+
const path = require('node:path');
|
|
13
|
+
if (process.argv.includes('--version')) {
|
|
14
|
+
process.stdout.write('fd 0.0.0\\n');
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
17
|
+
const args = process.argv.slice(2);
|
|
18
|
+
const baseDirIndex = args.indexOf('--base-directory');
|
|
19
|
+
const baseDir = baseDirIndex >= 0 ? args[baseDirIndex + 1] : process.cwd();
|
|
20
|
+
const maxResultsIndex = args.indexOf('--max-results');
|
|
21
|
+
const maxResults = maxResultsIndex >= 0 ? Number(args[maxResultsIndex + 1]) : Infinity;
|
|
22
|
+
const fullPath = args.includes('--full-path');
|
|
23
|
+
let query = '';
|
|
24
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
25
|
+
const arg = args[i];
|
|
26
|
+
if (arg === '--base-directory' || arg === '--max-results' || arg === '--type' || arg === '--exclude') {
|
|
27
|
+
i += 1;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (arg === '--follow' || arg === '--hidden' || arg === '--full-path') continue;
|
|
31
|
+
if (!arg.startsWith('--')) query = arg;
|
|
32
|
+
}
|
|
33
|
+
const results = [];
|
|
34
|
+
function walk(dir, rel = '') {
|
|
35
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
36
|
+
for (const entry of entries) {
|
|
37
|
+
if (entry.name === '.git') continue;
|
|
38
|
+
const nextRel = rel ? rel + '/' + entry.name : entry.name;
|
|
39
|
+
const full = path.join(dir, entry.name);
|
|
40
|
+
if (!query || nextRel.includes(query) || entry.name.includes(query)) {
|
|
41
|
+
results.push((fullPath ? nextRel : nextRel) + (entry.isDirectory() ? '/' : ''));
|
|
42
|
+
if (results.length >= maxResults) return true;
|
|
43
|
+
}
|
|
44
|
+
if (entry.isDirectory() && walk(full, nextRel)) return true;
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
walk(baseDir);
|
|
49
|
+
process.stdout.write(results.join('\\n'));
|
|
50
|
+
`, 'utf8');
|
|
51
|
+
chmodSync(fdBin, 0o755);
|
|
52
|
+
return fdBin;
|
|
53
|
+
}
|
|
54
|
+
test('#6 attach threads the resolved fd path into @-mention file completion', async () => {
|
|
55
|
+
const base = mkdtempSync(join(tmpdir(), 'crtr-at-'));
|
|
56
|
+
const binDir = mkdtempSync(join(tmpdir(), 'crtr-fd-'));
|
|
57
|
+
mkdirSync(join(base, 'nested'));
|
|
58
|
+
writeFileSync(join(base, 'alpha.txt'), 'a');
|
|
59
|
+
writeFileSync(join(base, 'nested', 'beta.md'), 'b');
|
|
60
|
+
const fdPath = writeFakeFd(binDir);
|
|
61
|
+
let seen;
|
|
62
|
+
const provider = buildAttachAutocompleteProvider(base, fdPath, [], (items, cwd, passedFdPath) => {
|
|
63
|
+
seen = { cwd, fdPath: passedFdPath, items };
|
|
64
|
+
return new CombinedAutocompleteProvider(items, cwd, passedFdPath);
|
|
65
|
+
});
|
|
66
|
+
assert.equal(seen?.cwd, base);
|
|
67
|
+
assert.equal(seen?.fdPath, fdPath);
|
|
68
|
+
assert.ok((seen?.items.length ?? 0) > 0);
|
|
69
|
+
const result = await provider.getSuggestions(['@'], 0, 1, {
|
|
70
|
+
force: false,
|
|
71
|
+
signal: new AbortController().signal,
|
|
72
|
+
});
|
|
73
|
+
assert.ok(result, 'expected @ suggestions from the file picker');
|
|
74
|
+
assert.equal(result?.prefix, '@');
|
|
75
|
+
assert.ok(result?.items.some((item) => item.label === 'alpha.txt' || item.label === 'nested/'));
|
|
76
|
+
});
|
|
77
|
+
test('attach-cmd derives bash mode from the leading cue and switches frame colors', () => {
|
|
78
|
+
assert.equal(deriveBashMode('plain text'), 0);
|
|
79
|
+
assert.equal(deriveBashMode(' ! echo hi'), 1);
|
|
80
|
+
assert.equal(deriveBashMode('\t!! echo hi'), 2);
|
|
81
|
+
const pal = {
|
|
82
|
+
bashMode: (s) => `green:${s}`,
|
|
83
|
+
bashModeAlt: (s) => `bright:${s}`,
|
|
84
|
+
border: (s) => `border:${s}`,
|
|
85
|
+
};
|
|
86
|
+
const off = resolveEditorFrameStyles(0, undefined, pal);
|
|
87
|
+
assert.equal(off.titleStyle('x'), '\x1b[7m x \x1b[27m');
|
|
88
|
+
assert.notEqual(off.borderColor, pal.bashMode);
|
|
89
|
+
assert.notEqual(off.borderColor, pal.bashModeAlt);
|
|
90
|
+
const single = resolveEditorFrameStyles(1, undefined, pal);
|
|
91
|
+
assert.equal(single.borderColor, pal.bashMode);
|
|
92
|
+
assert.equal(single.titleStyle('x'), '\x1b[42m\x1b[97m\x1b[1m x \x1b[0m');
|
|
93
|
+
const double = resolveEditorFrameStyles(2, undefined, pal);
|
|
94
|
+
assert.equal(double.borderColor, pal.bashModeAlt);
|
|
95
|
+
assert.equal(double.titleStyle('x'), '\x1b[102m\x1b[30m\x1b[1m x \x1b[0m');
|
|
96
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Regression: typing `!cmd` in the attach viewer was sent to the engine as a
|
|
2
|
+
// normal PROMPT (the LLM saw the literal `!cmd` and took a turn) instead of
|
|
3
|
+
// running bash and injecting the output into context with no agent turn — pi's
|
|
4
|
+
// native `!`/`!!` semantics. The fix routes a leading `!` in InputController to a
|
|
5
|
+
// `bash` drive frame (and `!!` to one with excludeFromContext). These tests lock
|
|
6
|
+
// the routing decision (the user-visible crux) so it can't silently revert.
|
|
7
|
+
import { test } from 'node:test';
|
|
8
|
+
import assert from 'node:assert/strict';
|
|
9
|
+
import { mkdtempSync } from 'node:fs';
|
|
10
|
+
import { tmpdir } from 'node:os';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { TUI, ProcessTerminal } from '@earendil-works/pi-tui';
|
|
13
|
+
import { TitledEditor } from '../titled-editor.js';
|
|
14
|
+
import { InputController } from '../input-controller.js';
|
|
15
|
+
import { createKeybindingsManager } from '../config-load.js';
|
|
16
|
+
const ENTER = '\r';
|
|
17
|
+
function build() {
|
|
18
|
+
const agentDir = mkdtempSync(join(tmpdir(), 'crtr-bang-'));
|
|
19
|
+
const km = createKeybindingsManager(agentDir);
|
|
20
|
+
const tui = new TUI(new ProcessTerminal());
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
+
const editor = new TitledEditor(tui, { borderColor: (s) => s, selectList: {} }, km, {
|
|
23
|
+
paddingX: 1,
|
|
24
|
+
});
|
|
25
|
+
const frames = [];
|
|
26
|
+
const hooks = {
|
|
27
|
+
onCommand: (f) => frames.push(f),
|
|
28
|
+
onDialogResponse: () => { },
|
|
29
|
+
};
|
|
30
|
+
// eslint-disable-next-line no-new -- wiring the editor.onSubmit handler is the point
|
|
31
|
+
new InputController(tui, editor, km, hooks);
|
|
32
|
+
return { editor, frames };
|
|
33
|
+
}
|
|
34
|
+
test('`!cmd` routes to a bash frame, not a prompt', () => {
|
|
35
|
+
const { editor, frames } = build();
|
|
36
|
+
editor.setText('!ls -la');
|
|
37
|
+
editor.handleInput(ENTER);
|
|
38
|
+
assert.deepEqual(frames, [{ type: 'bash', command: 'ls -la', excludeFromContext: false }]);
|
|
39
|
+
assert.equal(editor.getText(), '', 'editor clears after a bash submit');
|
|
40
|
+
});
|
|
41
|
+
test('`!!cmd` routes to a bash frame with excludeFromContext', () => {
|
|
42
|
+
const { editor, frames } = build();
|
|
43
|
+
editor.setText('!!echo secret');
|
|
44
|
+
editor.handleInput(ENTER);
|
|
45
|
+
assert.deepEqual(frames, [{ type: 'bash', command: 'echo secret', excludeFromContext: true }]);
|
|
46
|
+
});
|
|
47
|
+
test('a bare `!` with no command is ignored (no frame, text kept)', () => {
|
|
48
|
+
const { editor, frames } = build();
|
|
49
|
+
editor.setText('! ');
|
|
50
|
+
editor.handleInput(ENTER);
|
|
51
|
+
assert.equal(frames.length, 0, 'a bare `!` must not emit a bash frame');
|
|
52
|
+
});
|
|
53
|
+
test('ordinary text still routes to a prompt frame (no regression)', () => {
|
|
54
|
+
const { editor, frames } = build();
|
|
55
|
+
editor.setText('hello world');
|
|
56
|
+
editor.handleInput(ENTER);
|
|
57
|
+
assert.deepEqual(frames, [{ type: 'prompt', text: 'hello world' }]);
|
|
58
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Regression: after the attach viewer was re-bundled (commit d72c0de), Alt+Enter
|
|
2
|
+
// silently stopped inserting a newline. Root cause was NOT in the editor logic —
|
|
3
|
+
// editor-newline.test.ts still passed because it runs UNBUNDLED (tsx), where
|
|
4
|
+
// config-load and pi-coding-agent's CustomEditor each load their own pi-tui from
|
|
5
|
+
// disk and `mirrorKeybindingsToEditor` reaches the editor's disk copy.
|
|
6
|
+
//
|
|
7
|
+
// In the BUNDLE, esbuild inlined TWO distinct pi-tui module instances — the
|
|
8
|
+
// top-level `node_modules/@earendil-works/pi-tui` (imported by config-load) and
|
|
9
|
+
// pi-coding-agent's nested `.../pi-coding-agent/node_modules/@earendil-works/pi-tui`
|
|
10
|
+
// (imported by CustomEditor). `setKeybindings` ran against the first global; the
|
|
11
|
+
// editor read `getKeybindings` from the second. The Alt+Enter newLine binding was
|
|
12
|
+
// invisible to the editor and the key fell through — swallowed. The runtime disk
|
|
13
|
+
// mirror can't help: it targets a third (on-disk) instance, not either bundled one.
|
|
14
|
+
//
|
|
15
|
+
// Fix: the build:attach script aliases @earendil-works/pi-tui to one absolute
|
|
16
|
+
// path so esbuild collapses both imports to a SINGLE bundled instance, and
|
|
17
|
+
// setKeybindings reaches the editor directly. This test bundles attach-cmd.ts
|
|
18
|
+
// the way the build script does and asserts exactly one pi-tui copy is inlined.
|
|
19
|
+
import { test } from 'node:test';
|
|
20
|
+
import assert from 'node:assert/strict';
|
|
21
|
+
import { readFileSync } from 'node:fs';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
import { dirname, join } from 'node:path';
|
|
24
|
+
import { build } from 'esbuild';
|
|
25
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
const repoRoot = join(here, '..', '..', '..', '..'); // src/clients/attach/__tests__ → package root
|
|
27
|
+
const entry = join(repoRoot, 'src/clients/attach/attach-cmd.ts');
|
|
28
|
+
const piTui = join(repoRoot, 'node_modules/@earendil-works/pi-tui');
|
|
29
|
+
/** Count distinct pi-tui package directories esbuild inlines into the bundle.
|
|
30
|
+
* Unminified output keeps each module's source path as a `// <path>` comment. */
|
|
31
|
+
function piTuiCopies(code) {
|
|
32
|
+
const copies = new Set();
|
|
33
|
+
for (const m of code.matchAll(/node_modules\/(?:\.pnpm\/)?@earendil-works\/(?:pi-coding-agent\/node_modules\/@earendil-works\/)?pi-tui/g)) {
|
|
34
|
+
copies.add(m[0]);
|
|
35
|
+
}
|
|
36
|
+
return copies;
|
|
37
|
+
}
|
|
38
|
+
test('build:attach aliases pi-tui to one path (sanity: package.json carries the alias)', () => {
|
|
39
|
+
const pkg = JSON.parse(readFileSync(join(repoRoot, 'package.json'), 'utf8'));
|
|
40
|
+
assert.match(pkg.scripts['build:attach'], /--alias:@earendil-works\/pi-tui=/, 'build:attach must alias pi-tui so the bundle inlines a single instance');
|
|
41
|
+
});
|
|
42
|
+
test('attach bundle inlines exactly ONE pi-tui instance (editor + config-load share the keybindings global)', async () => {
|
|
43
|
+
const result = await build({
|
|
44
|
+
entryPoints: [entry],
|
|
45
|
+
bundle: true,
|
|
46
|
+
write: false,
|
|
47
|
+
format: 'esm',
|
|
48
|
+
platform: 'node',
|
|
49
|
+
target: 'node22',
|
|
50
|
+
alias: { '@earendil-works/pi-tui': piTui },
|
|
51
|
+
logLevel: 'silent',
|
|
52
|
+
});
|
|
53
|
+
const code = result.outputFiles[0].text;
|
|
54
|
+
const copies = piTuiCopies(code);
|
|
55
|
+
assert.equal(copies.size, 1, `bundle must inline exactly one pi-tui (two = the Alt+Enter regression). Found: ${[...copies].join(', ')}`);
|
|
56
|
+
});
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { test } from 'node:test';
|
|
11
11
|
import assert from 'node:assert/strict';
|
|
12
12
|
import { visibleWidth } from '@earendil-works/pi-tui';
|
|
13
|
-
import { composeTopBorder } from '../titled-editor.js';
|
|
13
|
+
import { composeTopBorder, thinkingBorderColor, thinkingTitleStyle } from '../titled-editor.js';
|
|
14
14
|
const titleStyle = (s) => `\x1b[7m ${s} \x1b[27m`;
|
|
15
15
|
const borderColor = (s) => `\x1b[38;2;128;128;128m${s}\x1b[39m`;
|
|
16
16
|
const compose = (width, title, info) => composeTopBorder(width, title, info, titleStyle, borderColor);
|
|
@@ -37,3 +37,24 @@ test('info chip survives intact when there is room for it', () => {
|
|
|
37
37
|
assert.ok(line.includes(info), 'fitting info must not be truncated or dropped');
|
|
38
38
|
assert.equal(visibleWidth(line), 80);
|
|
39
39
|
});
|
|
40
|
+
test('thinking levels use an evenly spaced blue→orange scale', () => {
|
|
41
|
+
const cases = [
|
|
42
|
+
['minimal', '38;2;68;120;228', '48;2;68;120;228'],
|
|
43
|
+
['low', '38;2;108;128;188', '48;2;108;128;188'],
|
|
44
|
+
['medium', '38;2;148;136;148', '48;2;148;136;148'],
|
|
45
|
+
['high', '38;2;188;144;108', '48;2;188;144;108'],
|
|
46
|
+
['xhigh', '38;2;228;152;68', '48;2;228;152;68'],
|
|
47
|
+
];
|
|
48
|
+
const borderRgb = new Set();
|
|
49
|
+
const titleRgb = new Set();
|
|
50
|
+
for (const [level, border, title] of cases) {
|
|
51
|
+
const borderColor = thinkingBorderColor(level, (s) => s);
|
|
52
|
+
const titleStyle = thinkingTitleStyle(level, (s) => s);
|
|
53
|
+
assert.match(composeTopBorder(24, 'sess', '', (s) => s, borderColor), new RegExp(`\\x1b\\[${border}m`), `${level} border should use ${border}`);
|
|
54
|
+
assert.match(titleStyle('sess'), new RegExp(`\\x1b\\[${title}m`), `${level} title should use ${title}`);
|
|
55
|
+
borderRgb.add(border);
|
|
56
|
+
titleRgb.add(title);
|
|
57
|
+
}
|
|
58
|
+
assert.equal(borderRgb.size, cases.length, 'every thinking level needs its own border step');
|
|
59
|
+
assert.equal(titleRgb.size, cases.length, 'every thinking level needs its own title step');
|
|
60
|
+
});
|
|
@@ -1,2 +1,20 @@
|
|
|
1
|
+
import { CombinedAutocompleteProvider } from '@earendil-works/pi-tui';
|
|
1
2
|
import type { BranchDef } from '../../core/command.js';
|
|
3
|
+
import type { BrokerSnapshot } from '../../core/runtime/broker-protocol.js';
|
|
4
|
+
import { type AttachPalette } from './config-load.js';
|
|
5
|
+
/** Derive the shell-mode cue from the editor contents. Leading whitespace is
|
|
6
|
+
* ignored so pasted commands and indented text still toggle correctly. */
|
|
7
|
+
export declare function deriveBashMode(text: string): 0 | 1 | 2;
|
|
8
|
+
/** Resolve the editor border + title-chip styles for the current shell cue. */
|
|
9
|
+
export declare function resolveEditorFrameStyles(bashMode: 0 | 1 | 2, thinkingLevel: BrokerSnapshot['state']['thinkingLevel'] | undefined, pal: Pick<AttachPalette, 'bashMode' | 'bashModeAlt' | 'border'>): {
|
|
10
|
+
borderColor: (s: string) => string;
|
|
11
|
+
titleStyle: (s: string) => string;
|
|
12
|
+
};
|
|
13
|
+
export declare function buildAttachAutocompleteProvider(cwd: string, fdPath: string | null, commands?: ReadonlyArray<{
|
|
14
|
+
name: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
}>, createProvider?: (items: ReadonlyArray<{
|
|
17
|
+
name: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
}>, cwd: string, fdPath: string | null) => CombinedAutocompleteProvider): CombinedAutocompleteProvider;
|
|
2
20
|
export declare function registerAttach(): BranchDef;
|