@crouton-kit/crouter 0.3.31 → 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 +9 -3
- 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 +37 -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/__tests__/empty-node-guard.test.d.ts +1 -0
- package/dist/core/feed/__tests__/empty-node-guard.test.js +45 -0
- package/dist/core/feed/feed.js +8 -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,484 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/**
|
|
3
|
+
* Prompt Studio — web presenter for the `prompt-review` builtin.
|
|
4
|
+
*
|
|
5
|
+
* Browser-only. Pure read of state; all data/behavior live in core.mjs.
|
|
6
|
+
*
|
|
7
|
+
* @module prompt-review/web
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
11
|
+
import { Loading, NotReady, ErrorState, Empty } from '@crouton-kit/crouter/web';
|
|
12
|
+
import { toast } from '../../clients/web/web-client/lib/toast.js';
|
|
13
|
+
import { configHeadline, diffReviews, selectedLayer, compareSelectedLayer, kindLabel, layerLabel } from './core.mjs';
|
|
14
|
+
|
|
15
|
+
/** @typedef {import('./core.mjs').ReviewState} ReviewState */
|
|
16
|
+
|
|
17
|
+
const BUDGET = 200_000;
|
|
18
|
+
|
|
19
|
+
const GROUP_STYLES = {
|
|
20
|
+
protocol: 'border-cyan-200 bg-cyan-50 text-cyan-800',
|
|
21
|
+
persona: 'border-amber-200 bg-amber-50 text-amber-800',
|
|
22
|
+
generated: 'border-violet-200 bg-violet-50 text-violet-800',
|
|
23
|
+
substrate: 'border-lime-200 bg-lime-50 text-lime-800',
|
|
24
|
+
};
|
|
25
|
+
const SCOPE_STYLES = {
|
|
26
|
+
builtin: 'border-slate-200 bg-slate-50 text-slate-700',
|
|
27
|
+
project: 'border-emerald-200 bg-emerald-50 text-emerald-800',
|
|
28
|
+
user: 'border-amber-200 bg-amber-50 text-amber-800',
|
|
29
|
+
generated: 'border-violet-200 bg-violet-50 text-violet-800',
|
|
30
|
+
runtime: 'border-lime-200 bg-lime-50 text-lime-800',
|
|
31
|
+
};
|
|
32
|
+
const DIFF_STYLES = {
|
|
33
|
+
added: 'border-emerald-200 bg-emerald-50 text-emerald-800',
|
|
34
|
+
removed: 'border-rose-200 bg-rose-50 text-rose-800',
|
|
35
|
+
changed: 'border-amber-200 bg-amber-50 text-amber-800',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** @param {string} kind */
|
|
39
|
+
function kindChipCls(kind) {
|
|
40
|
+
if (!kind) return 'border-slate-200 bg-slate-50 text-slate-700';
|
|
41
|
+
if (kind === 'base') return 'border-cyan-200 bg-cyan-50 text-cyan-800';
|
|
42
|
+
if (kind === 'orchestrator') return 'border-violet-200 bg-violet-50 text-violet-800';
|
|
43
|
+
return 'border-slate-200 bg-slate-50 text-slate-700';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** @param {string} scope */
|
|
47
|
+
function scopeCls(scope) {
|
|
48
|
+
return SCOPE_STYLES[scope] || 'border-slate-200 bg-slate-50 text-slate-700';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** @param {string} group */
|
|
52
|
+
function groupCls(group) {
|
|
53
|
+
return GROUP_STYLES[group] || 'border-slate-200 bg-slate-50 text-slate-700';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** @param {number} n @returns {string} */
|
|
57
|
+
function fmt(n) {
|
|
58
|
+
return new Intl.NumberFormat('en-US').format(Math.max(0, Math.floor(n || 0)));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** @param {string} text @returns {string[]} */
|
|
62
|
+
function lines(text) {
|
|
63
|
+
return String(text || '').replace(/\r\n/g, '\n').split('\n');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** @param {string} text @returns {string} */
|
|
67
|
+
function snippet(text) {
|
|
68
|
+
return lines(text)
|
|
69
|
+
.map((l) => l.trim())
|
|
70
|
+
.filter(Boolean)
|
|
71
|
+
.slice(0, 4)
|
|
72
|
+
.join('\n');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** @param {string} text @returns {string} */
|
|
76
|
+
function maybeEllipsize(text) {
|
|
77
|
+
const s = String(text || '');
|
|
78
|
+
return s.length > 140 ? `${s.slice(0, 137)}…` : s;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** @param {string} text */
|
|
82
|
+
async function copyText(text) {
|
|
83
|
+
if (!text) return false;
|
|
84
|
+
try {
|
|
85
|
+
await navigator.clipboard.writeText(text);
|
|
86
|
+
return true;
|
|
87
|
+
} catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** @param {string} label @param {string} value @param {string} cls */
|
|
93
|
+
function Pill({ label, value, cls }) {
|
|
94
|
+
return <span className={`inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[11px] ${cls}`}><span className="opacity-60">{label}</span><span className="font-semibold">{value}</span></span>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** @param {{ label: string, active?: boolean, onClick: () => void, className?: string, title?: string, children: any }} props */
|
|
98
|
+
function Button(props) {
|
|
99
|
+
return (
|
|
100
|
+
<button
|
|
101
|
+
type="button"
|
|
102
|
+
title={props.title}
|
|
103
|
+
onClick={props.onClick}
|
|
104
|
+
className={`rounded-lg border px-3 py-1.5 text-left text-sm transition ${props.active ? 'border-slate-900 bg-slate-900 text-white' : 'border-slate-200 bg-white text-slate-700 hover:bg-slate-50'} ${props.className || ''}`}
|
|
105
|
+
>
|
|
106
|
+
{props.children}
|
|
107
|
+
</button>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** @param {{ state: ReviewState, dispatch: (intent:string, payload?:unknown)=>void }} props */
|
|
112
|
+
function ConfigPanel({ state, dispatch }) {
|
|
113
|
+
const kinds = state.list?.kinds || [{ kind: state.config.kind, whenToUse: '' }];
|
|
114
|
+
const modeSet = state.list?.modes || ['base', 'orchestrator'];
|
|
115
|
+
const lifecycleSet = state.list?.lifecycles || ['terminal', 'resident'];
|
|
116
|
+
const kindSub = state.list?.subPersonas?.[state.config.kind] || [];
|
|
117
|
+
const currentNodeLabel = state.config.node ? (state.liveNodes.find((n) => n.node_id === state.config.node)?.name || state.config.node) : 'none';
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<section className="flex min-h-0 flex-col overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm">
|
|
121
|
+
<div className="border-b border-slate-200 px-4 py-3">
|
|
122
|
+
<div className="text-xs font-semibold uppercase tracking-[0.2em] text-slate-400">Config</div>
|
|
123
|
+
<div className="mt-1 text-sm text-slate-600">{configHeadline(state.config)}</div>
|
|
124
|
+
</div>
|
|
125
|
+
<div className="min-h-0 flex-1 space-y-4 overflow-y-auto p-4">
|
|
126
|
+
<div>
|
|
127
|
+
<div className="mb-2 text-xs font-semibold uppercase tracking-[0.18em] text-slate-400">Kind</div>
|
|
128
|
+
<select
|
|
129
|
+
className="w-full rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm outline-none focus:border-slate-400"
|
|
130
|
+
value={state.config.kind}
|
|
131
|
+
onChange={(e) => dispatch('setKind', e.target.value)}
|
|
132
|
+
>
|
|
133
|
+
{kinds.map((k) => (
|
|
134
|
+
<option key={k.kind} value={k.kind}>{k.kind}</option>
|
|
135
|
+
))}
|
|
136
|
+
</select>
|
|
137
|
+
{kindSub.length ? <div className="mt-2 text-xs text-slate-500">Sub-personas: {kindSub.map((k) => k.kind).join(', ')}</div> : <div className="mt-2 text-xs text-slate-400">No sub-personas listed.</div>}
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<div>
|
|
141
|
+
<div className="mb-2 text-xs font-semibold uppercase tracking-[0.18em] text-slate-400">Mode</div>
|
|
142
|
+
<div className="grid grid-cols-2 gap-2">
|
|
143
|
+
{modeSet.map((mode) => <Button key={mode} label={mode} active={state.config.mode === mode} onClick={() => dispatch('setMode', mode)}><span className="capitalize">{mode}</span></Button>)}
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<div>
|
|
148
|
+
<div className="mb-2 text-xs font-semibold uppercase tracking-[0.18em] text-slate-400">Lifecycle</div>
|
|
149
|
+
<div className="grid grid-cols-2 gap-2">
|
|
150
|
+
{lifecycleSet.map((value) => <Button key={value} label={value} active={state.config.lifecycle === value} onClick={() => dispatch('setLifecycle', value)}><span className="capitalize">{value}</span></Button>)}
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<div>
|
|
155
|
+
<div className="mb-2 text-xs font-semibold uppercase tracking-[0.18em] text-slate-400">Has manager</div>
|
|
156
|
+
<button
|
|
157
|
+
type="button"
|
|
158
|
+
onClick={() => dispatch('toggleHasManager')}
|
|
159
|
+
className={`flex w-full items-center justify-between rounded-lg border px-3 py-2 text-sm ${state.config.hasManager ? 'border-cyan-200 bg-cyan-50 text-cyan-800' : 'border-slate-200 bg-slate-50 text-slate-700'}`}
|
|
160
|
+
>
|
|
161
|
+
<span>{state.config.hasManager ? 'yes' : 'no'}</span>
|
|
162
|
+
<span className="text-xs opacity-60">re-fetches prompt</span>
|
|
163
|
+
</button>
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
<div>
|
|
167
|
+
<div className="mb-2 text-xs font-semibold uppercase tracking-[0.18em] text-slate-400">Node</div>
|
|
168
|
+
<select
|
|
169
|
+
className="w-full rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm outline-none focus:border-slate-400"
|
|
170
|
+
value={state.config.node || ''}
|
|
171
|
+
onChange={(e) => dispatch('setNode', e.target.value || null)}
|
|
172
|
+
>
|
|
173
|
+
<option value="">none</option>
|
|
174
|
+
{state.liveNodes.map((node) => <option key={node.node_id} value={node.node_id}>{node.name} · {node.kind} · {node.status}</option>)}
|
|
175
|
+
</select>
|
|
176
|
+
<div className="mt-2 text-xs text-slate-500">{currentNodeLabel}</div>
|
|
177
|
+
</div>
|
|
178
|
+
|
|
179
|
+
<div className="rounded-xl border border-slate-200 bg-slate-50 p-3">
|
|
180
|
+
<div className="text-xs font-semibold uppercase tracking-[0.18em] text-slate-400">Sub-personas</div>
|
|
181
|
+
{kindSub.length ? (
|
|
182
|
+
<div className="mt-2 space-y-2">
|
|
183
|
+
{kindSub.map((item) => (
|
|
184
|
+
<div key={item.kind} className="rounded-lg border border-slate-200 bg-white px-3 py-2">
|
|
185
|
+
<div className="font-medium text-slate-900">{item.kind}</div>
|
|
186
|
+
<div className="text-xs text-slate-500">{item.whenToUse}</div>
|
|
187
|
+
</div>
|
|
188
|
+
))}
|
|
189
|
+
</div>
|
|
190
|
+
) : <div className="mt-2 text-xs text-slate-500">No sub-persona entries for this kind.</div>}
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
</section>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** @param {{ layer: import('./core.mjs').PromptLayer, state: ReviewState, selected: boolean, dispatch: (intent:string, payload?:unknown)=>void }} props */
|
|
198
|
+
function LayerBlock({ layer, state, selected, dispatch }) {
|
|
199
|
+
const expanded = !!state.expanded[layer.id];
|
|
200
|
+
const included = layer.included;
|
|
201
|
+
const opacity = included ? 'opacity-100' : 'opacity-55';
|
|
202
|
+
const cond = !included && layer.condition ? `✕ ${layer.condition}` : null;
|
|
203
|
+
const source = layer.sourcePath || layer.source;
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<div className={`rounded-xl border ${selected ? 'border-slate-900 ring-1 ring-slate-900/10' : 'border-slate-200'} bg-white ${opacity}`}>
|
|
207
|
+
<button
|
|
208
|
+
type="button"
|
|
209
|
+
onClick={() => { dispatch('selectLayer', layer.id); dispatch('toggleLayerExpanded', layer.id); }}
|
|
210
|
+
className="flex w-full items-start gap-3 px-3 py-3 text-left"
|
|
211
|
+
>
|
|
212
|
+
<div className="mt-0.5 text-slate-400">{expanded ? '▾' : '▸'}</div>
|
|
213
|
+
<div className="min-w-0 flex-1">
|
|
214
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
215
|
+
<div className="truncate font-semibold text-slate-900">{layer.label}</div>
|
|
216
|
+
<span className={`rounded-full border px-2 py-0.5 text-[11px] ${groupCls(layer.group)}`}>{layer.group}</span>
|
|
217
|
+
<span className={`rounded-full border px-2 py-0.5 text-[11px] ${scopeCls(layer.scope)}`}>{layer.scope}</span>
|
|
218
|
+
<span className="rounded-full border border-slate-200 bg-slate-50 px-2 py-0.5 text-[11px] text-slate-700">≈{fmt(layer.tokens)} tok</span>
|
|
219
|
+
{!included ? <span className="rounded-full border border-rose-200 bg-rose-50 px-2 py-0.5 text-[11px] text-rose-700">excluded</span> : null}
|
|
220
|
+
</div>
|
|
221
|
+
<div className="mt-1 flex flex-wrap items-center gap-2 text-xs text-slate-500">
|
|
222
|
+
<span className="truncate">{layer.source}</span>
|
|
223
|
+
{cond ? <span className="rounded-full border border-rose-200 bg-rose-50 px-2 py-0.5 text-rose-700">{cond}</span> : null}
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
</button>
|
|
227
|
+
{expanded ? (
|
|
228
|
+
<div className="border-t border-slate-200 px-3 py-3">
|
|
229
|
+
<pre className="max-h-72 overflow-auto whitespace-pre-wrap break-words rounded-lg bg-slate-950 px-3 py-2 font-mono text-[12px] leading-5 text-slate-100">{layer.text}</pre>
|
|
230
|
+
<div className="mt-2 flex flex-wrap items-center gap-2 text-xs text-slate-500">
|
|
231
|
+
<span>{included ? 'included' : 'excluded'}</span>
|
|
232
|
+
<span>·</span>
|
|
233
|
+
<span>{fmt(layer.chars)} chars</span>
|
|
234
|
+
<span>·</span>
|
|
235
|
+
<span>{source}</span>
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
) : null}
|
|
239
|
+
</div>
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** @param {{ state: ReviewState, dispatch: (intent:string, payload?:unknown)=>void }} props */
|
|
244
|
+
function AssembledPanel({ state, dispatch }) {
|
|
245
|
+
const review = state.review || [];
|
|
246
|
+
const selected = selectedLayer(state) || review[0] || null;
|
|
247
|
+
const raw = state.assembled || '';
|
|
248
|
+
const budgetPct = Math.min(100, (state.totalTokens / BUDGET) * 100);
|
|
249
|
+
|
|
250
|
+
return (
|
|
251
|
+
<section className="flex min-h-0 flex-col overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm">
|
|
252
|
+
<div className="border-b border-slate-200 px-4 py-3">
|
|
253
|
+
<div className="flex items-center gap-2">
|
|
254
|
+
<div className="text-xs font-semibold uppercase tracking-[0.2em] text-slate-400">Assembled</div>
|
|
255
|
+
<div className="ml-auto flex items-center gap-2">
|
|
256
|
+
<Button label="layered" active={state.viewMode === 'layered'} onClick={() => dispatch('setViewMode', 'layered')} className="px-2 py-1 text-xs"><span>Layered</span></Button>
|
|
257
|
+
<Button label="raw" active={state.viewMode === 'raw'} onClick={() => dispatch('setViewMode', 'raw')} className="px-2 py-1 text-xs"><span>Raw</span></Button>
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
260
|
+
<div className="mt-1 text-sm text-slate-600">{configHeadline(state.config)}</div>
|
|
261
|
+
</div>
|
|
262
|
+
<div className="min-h-0 flex-1 overflow-y-auto p-4">
|
|
263
|
+
{state.viewMode === 'raw' ? (
|
|
264
|
+
<pre
|
|
265
|
+
className="select-text whitespace-pre-wrap break-words rounded-xl border border-slate-200 bg-slate-950 p-4 font-mono text-[12px] leading-5 text-slate-100"
|
|
266
|
+
onMouseUp={(e) => {
|
|
267
|
+
const sel = window.getSelection?.()?.toString() || '';
|
|
268
|
+
dispatch('captureRawSelection', sel);
|
|
269
|
+
}}
|
|
270
|
+
>{raw}</pre>
|
|
271
|
+
) : (
|
|
272
|
+
<div className="space-y-3">
|
|
273
|
+
{review.map((layer) => <LayerBlock key={layer.id} layer={layer} state={state} selected={selected?.id === layer.id} dispatch={dispatch} />)}
|
|
274
|
+
</div>
|
|
275
|
+
)}
|
|
276
|
+
</div>
|
|
277
|
+
<div className="border-t border-slate-200 p-4">
|
|
278
|
+
<div className="flex items-center justify-between text-xs text-slate-500">
|
|
279
|
+
<div>≈{fmt(state.totalTokens)} tokens · {fmt(state.totalChars)} chars</div>
|
|
280
|
+
<div>{Math.round(budgetPct)}% of {fmt(BUDGET)} budget</div>
|
|
281
|
+
</div>
|
|
282
|
+
<div className="mt-2 h-2 overflow-hidden rounded-full bg-slate-100">
|
|
283
|
+
<div className={`h-full rounded-full ${budgetPct > 90 ? 'bg-rose-500' : budgetPct > 75 ? 'bg-amber-500' : 'bg-cyan-500'}`} style={{ width: `${Math.min(100, budgetPct)}%` }} />
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
</section>
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** @param {{ state: ReviewState, dispatch: (intent:string, payload?:unknown)=>void }} props */
|
|
291
|
+
function CommentDraft({ state, dispatch }) {
|
|
292
|
+
const draft = state.draftComment;
|
|
293
|
+
if (!draft) return null;
|
|
294
|
+
return (
|
|
295
|
+
<div className="rounded-xl border border-slate-200 bg-slate-50 p-3">
|
|
296
|
+
<div className="flex items-center gap-2 text-xs text-slate-500">
|
|
297
|
+
<span className="font-semibold text-slate-700">Commenting on</span>
|
|
298
|
+
<span className="rounded-full border border-slate-200 bg-white px-2 py-0.5 text-slate-700">{draft.label}</span>
|
|
299
|
+
<span className={`rounded-full border px-2 py-0.5 ${scopeCls(draft.scope)}`}>{draft.scope}</span>
|
|
300
|
+
</div>
|
|
301
|
+
{draft.anchor ? <div className="mt-2 rounded-lg border border-slate-200 bg-white p-2 text-xs text-slate-600"><div className="mb-1 font-semibold text-slate-500">Anchor</div><pre className="whitespace-pre-wrap break-words font-mono text-[11px] leading-5">{draft.anchor}</pre></div> : null}
|
|
302
|
+
<textarea
|
|
303
|
+
autoFocus
|
|
304
|
+
value={draft.body}
|
|
305
|
+
onChange={(e) => dispatch('setCommentBody', e.target.value)}
|
|
306
|
+
rows={4}
|
|
307
|
+
placeholder="Write the review comment here…"
|
|
308
|
+
className="mt-2 w-full rounded-lg border border-slate-200 bg-white p-3 font-mono text-sm outline-none focus:border-slate-400"
|
|
309
|
+
/>
|
|
310
|
+
<div className="mt-2 flex gap-2">
|
|
311
|
+
<button type="button" onClick={() => dispatch('saveComment')} className="rounded-lg bg-slate-900 px-3 py-1.5 text-sm text-white hover:bg-slate-800">Save comment</button>
|
|
312
|
+
<button type="button" onClick={() => dispatch('cancelComment')} className="rounded-lg border border-slate-200 bg-white px-3 py-1.5 text-sm text-slate-700 hover:bg-slate-50">Cancel</button>
|
|
313
|
+
</div>
|
|
314
|
+
</div>
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** @param {{ comment: ReviewState['comments'][number], index: number, onDelete: () => void }} props */
|
|
319
|
+
function CommentRow({ comment, index, onDelete }) {
|
|
320
|
+
return (
|
|
321
|
+
<div className="rounded-xl border border-slate-200 bg-white p-3">
|
|
322
|
+
<div className="flex items-center gap-2 text-xs text-slate-500">
|
|
323
|
+
<span className="font-semibold text-slate-900">{comment.label}</span>
|
|
324
|
+
<span className={`rounded-full border px-2 py-0.5 ${scopeCls(comment.scope)}`}>{comment.scope}</span>
|
|
325
|
+
<span className="ml-auto text-slate-400">#{index + 1}</span>
|
|
326
|
+
</div>
|
|
327
|
+
{comment.anchor ? <pre className="mt-2 whitespace-pre-wrap break-words rounded-lg bg-slate-50 p-2 font-mono text-[11px] leading-5 text-slate-600">{comment.anchor}</pre> : null}
|
|
328
|
+
<div className="mt-2 whitespace-pre-wrap text-sm text-slate-800">{comment.body}</div>
|
|
329
|
+
<div className="mt-2 flex items-center gap-2 text-xs text-slate-500">
|
|
330
|
+
{comment.sourcePath ? <span className="truncate">{comment.sourcePath}</span> : <span className="text-slate-400">generated layer</span>}
|
|
331
|
+
<button type="button" onClick={onDelete} className="ml-auto rounded-full border border-slate-200 px-2 py-0.5 hover:bg-slate-50">Remove</button>
|
|
332
|
+
</div>
|
|
333
|
+
</div>
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/** @param {{ state: ReviewState, dispatch: (intent:string, payload?:unknown)=>void }} props */
|
|
338
|
+
function InspectorPanel({ state, dispatch }) {
|
|
339
|
+
const layer = selectedLayer(state) || state.review?.[0] || null;
|
|
340
|
+
const compareLayer = compareSelectedLayer(state) || state.compareReview?.[0] || null;
|
|
341
|
+
const diffs = useMemo(() => diffReviews(state.review || [], state.compareReview || []), [state.review, state.compareReview]);
|
|
342
|
+
const compareCfg = state.compareConfig || state.config;
|
|
343
|
+
|
|
344
|
+
return (
|
|
345
|
+
<section className="flex min-h-0 flex-col overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm">
|
|
346
|
+
<div className="border-b border-slate-200 px-4 py-3">
|
|
347
|
+
<div className="flex items-center gap-2">
|
|
348
|
+
<div className="text-xs font-semibold uppercase tracking-[0.2em] text-slate-400">Inspector</div>
|
|
349
|
+
<button type="button" onClick={() => dispatch('beginComment')} disabled={!layer} className="ml-auto rounded-full border border-slate-200 bg-white px-3 py-1 text-xs text-slate-700 hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-40">Add comment</button>
|
|
350
|
+
</div>
|
|
351
|
+
<div className="mt-1 text-sm text-slate-600">{layer ? layer.label : 'No layer selected'}</div>
|
|
352
|
+
</div>
|
|
353
|
+
|
|
354
|
+
<div className="min-h-0 flex-1 space-y-4 overflow-y-auto p-4">
|
|
355
|
+
{layer ? (
|
|
356
|
+
<div className="rounded-xl border border-slate-200 bg-slate-50 p-3">
|
|
357
|
+
<div className="flex items-start gap-2">
|
|
358
|
+
<div className="min-w-0 flex-1">
|
|
359
|
+
<div className="font-semibold text-slate-900">{layer.label}</div>
|
|
360
|
+
<div className="mt-1 text-xs text-slate-500">{layer.source}</div>
|
|
361
|
+
</div>
|
|
362
|
+
<span className={`rounded-full border px-2 py-0.5 text-[11px] ${groupCls(layer.group)}`}>{layer.group}</span>
|
|
363
|
+
</div>
|
|
364
|
+
<div className="mt-3 flex flex-wrap gap-2 text-[11px]">
|
|
365
|
+
<Pill label="scope" value={layer.scope} cls={scopeCls(layer.scope)} />
|
|
366
|
+
<Pill label="status" value={layer.included ? 'included' : 'excluded'} cls={layer.included ? 'border-emerald-200 bg-emerald-50 text-emerald-800' : 'border-rose-200 bg-rose-50 text-rose-800'} />
|
|
367
|
+
<Pill label="tokens" value={`≈${fmt(layer.tokens)}`} cls="border-slate-200 bg-white text-slate-700" />
|
|
368
|
+
<Pill label="chars" value={fmt(layer.chars)} cls="border-slate-200 bg-white text-slate-700" />
|
|
369
|
+
</div>
|
|
370
|
+
{layer.condition ? <div className="mt-2 rounded-lg border border-rose-200 bg-rose-50 px-3 py-2 text-xs text-rose-700">Condition: {layer.condition}</div> : null}
|
|
371
|
+
<div className="mt-2 flex items-center gap-2 text-xs text-slate-500">
|
|
372
|
+
<div className="min-w-0 flex-1 truncate font-mono">{layer.sourcePath || 'no source path (generated or runtime-spliced)'}</div>
|
|
373
|
+
{layer.sourcePath ? <button type="button" onClick={async () => { const ok = await copyText(layer.sourcePath || ''); toast(ok ? 'Source path copied' : 'Could not copy source path', ok ? 'success' : 'info'); }} className="rounded-full border border-slate-200 px-2 py-0.5 hover:bg-white">Copy path</button> : null}
|
|
374
|
+
</div>
|
|
375
|
+
<pre className="mt-3 max-h-44 overflow-auto whitespace-pre-wrap break-words rounded-lg bg-slate-950 px-3 py-2 font-mono text-[12px] leading-5 text-slate-100">{layer.text}</pre>
|
|
376
|
+
</div>
|
|
377
|
+
) : <Empty label="No layer selected." />}
|
|
378
|
+
|
|
379
|
+
<div className="rounded-xl border border-slate-200 bg-slate-50 p-3">
|
|
380
|
+
<div className="flex items-center gap-2">
|
|
381
|
+
<div className="text-xs font-semibold uppercase tracking-[0.18em] text-slate-400">Compare</div>
|
|
382
|
+
<button type="button" onClick={() => dispatch('toggleCompareOpen')} className="ml-auto rounded-full border border-slate-200 bg-white px-3 py-1 text-xs text-slate-700 hover:bg-slate-50">{state.compareOpen ? 'Hide' : 'Show'}</button>
|
|
383
|
+
</div>
|
|
384
|
+
{state.compareOpen ? (
|
|
385
|
+
<div className="mt-3 space-y-3">
|
|
386
|
+
<div className="grid grid-cols-1 gap-2 lg:grid-cols-2">
|
|
387
|
+
<select className="w-full rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm outline-none focus:border-slate-400" value={compareCfg.kind} onChange={(e) => dispatch('setCompareKind', e.target.value)}>
|
|
388
|
+
{(state.list?.kinds || [{ kind: compareCfg.kind }]).map((k) => <option key={k.kind} value={k.kind}>{k.kind}</option>)}
|
|
389
|
+
</select>
|
|
390
|
+
<div className="grid grid-cols-2 gap-2">
|
|
391
|
+
<button type="button" onClick={() => dispatch('setCompareMode', 'base')} className={`rounded-lg border px-2 py-1 text-sm ${compareCfg.mode === 'base' ? 'border-slate-900 bg-slate-900 text-white' : 'border-slate-200 bg-white text-slate-700'}`}>base</button>
|
|
392
|
+
<button type="button" onClick={() => dispatch('setCompareMode', 'orchestrator')} className={`rounded-lg border px-2 py-1 text-sm ${compareCfg.mode === 'orchestrator' ? 'border-slate-900 bg-slate-900 text-white' : 'border-slate-200 bg-white text-slate-700'}`}>orchestrator</button>
|
|
393
|
+
</div>
|
|
394
|
+
</div>
|
|
395
|
+
<div className="grid grid-cols-1 gap-2 lg:grid-cols-2">
|
|
396
|
+
<div className="grid grid-cols-2 gap-2">
|
|
397
|
+
<button type="button" onClick={() => dispatch('setCompareLifecycle', 'terminal')} className={`rounded-lg border px-2 py-1 text-sm ${compareCfg.lifecycle === 'terminal' ? 'border-slate-900 bg-slate-900 text-white' : 'border-slate-200 bg-white text-slate-700'}`}>terminal</button>
|
|
398
|
+
<button type="button" onClick={() => dispatch('setCompareLifecycle', 'resident')} className={`rounded-lg border px-2 py-1 text-sm ${compareCfg.lifecycle === 'resident' ? 'border-slate-900 bg-slate-900 text-white' : 'border-slate-200 bg-white text-slate-700'}`}>resident</button>
|
|
399
|
+
</div>
|
|
400
|
+
<button type="button" onClick={() => dispatch('toggleCompareHasManager')} className={`flex items-center justify-between rounded-lg border px-3 py-2 text-sm ${compareCfg.hasManager ? 'border-cyan-200 bg-cyan-50 text-cyan-800' : 'border-slate-200 bg-white text-slate-700'}`}>
|
|
401
|
+
<span>manager {compareCfg.hasManager ? 'yes' : 'no'}</span>
|
|
402
|
+
<span className="text-xs opacity-60">compare</span>
|
|
403
|
+
</button>
|
|
404
|
+
</div>
|
|
405
|
+
<select className="w-full rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm outline-none focus:border-slate-400" value={compareCfg.node || ''} onChange={(e) => dispatch('setCompareNode', e.target.value || null)}>
|
|
406
|
+
<option value="">no node</option>
|
|
407
|
+
{state.liveNodes.map((node) => <option key={node.node_id} value={node.node_id}>{node.name} · {node.kind} · {node.status}</option>)}
|
|
408
|
+
</select>
|
|
409
|
+
{state.compareReview ? (
|
|
410
|
+
<div className="rounded-xl border border-slate-200 bg-white p-3">
|
|
411
|
+
<div className="flex items-center gap-2 text-xs text-slate-500"><span className="font-semibold text-slate-900">Compared selection</span><span className="rounded-full border border-slate-200 bg-slate-50 px-2 py-0.5">{compareLayer?.label || 'none'}</span></div>
|
|
412
|
+
{compareLayer ? <pre className="mt-2 max-h-40 overflow-auto whitespace-pre-wrap break-words rounded-lg bg-slate-950 px-3 py-2 font-mono text-[12px] leading-5 text-slate-100">{compareLayer.text}</pre> : null}
|
|
413
|
+
</div>
|
|
414
|
+
) : <div className="text-xs text-slate-500">Pick a second config to render the diff.</div>}
|
|
415
|
+
<div className="space-y-2">
|
|
416
|
+
{diffs.length ? diffs.map((diff) => (
|
|
417
|
+
<button key={diff.id} type="button" onClick={() => dispatch('selectCompareLayer', diff.id)} className={`w-full rounded-xl border px-3 py-3 text-left ${DIFF_STYLES[diff.kind] || 'border-slate-200 bg-white text-slate-700'}`}>
|
|
418
|
+
<div className="flex items-center gap-2 text-xs">
|
|
419
|
+
<span className="rounded-full border border-current/20 bg-white/70 px-2 py-0.5 font-semibold uppercase">{diff.kind}</span>
|
|
420
|
+
<span className="font-semibold text-slate-900">{diff.label}</span>
|
|
421
|
+
</div>
|
|
422
|
+
<div className="mt-1 whitespace-pre-wrap font-mono text-[11px] leading-5">{diff.diffText || diff.summary}</div>
|
|
423
|
+
</button>
|
|
424
|
+
)) : <div className="text-xs text-slate-500">No differences for the current pair.</div>}
|
|
425
|
+
</div>
|
|
426
|
+
</div>
|
|
427
|
+
) : <div className="mt-2 text-xs text-slate-500">Compare panel hidden.</div>}
|
|
428
|
+
</div>
|
|
429
|
+
|
|
430
|
+
{state.draftComment ? <CommentDraft state={state} dispatch={dispatch} /> : null}
|
|
431
|
+
|
|
432
|
+
<div className="space-y-2">
|
|
433
|
+
<div className="text-xs font-semibold uppercase tracking-[0.18em] text-slate-400">Comments</div>
|
|
434
|
+
{state.comments.length ? state.comments.map((comment, i) => <CommentRow key={`${comment.layerId}-${i}`} comment={comment} index={i} onDelete={() => dispatch('removeComment', i)} />) : <div className="rounded-xl border border-dashed border-slate-200 bg-slate-50 p-4 text-sm text-slate-500">No comments yet.</div>}
|
|
435
|
+
</div>
|
|
436
|
+
</div>
|
|
437
|
+
</section>
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/** @param {{ state: ReviewState, dispatch: (intent:string, payload?:unknown)=>void }} props */
|
|
442
|
+
function FooterBar({ state, dispatch }) {
|
|
443
|
+
return (
|
|
444
|
+
<div className="flex flex-wrap items-center gap-2 border-t border-slate-200 bg-white px-4 py-3 text-sm text-slate-600">
|
|
445
|
+
<button type="button" onClick={async () => { const ok = await copyText(state.assembled || ''); toast(ok ? 'Copied assembled prompt' : 'Could not copy assembled prompt', ok ? 'success' : 'info'); }} className="rounded-full border border-slate-200 bg-slate-50 px-3 py-1.5 hover:bg-slate-100" disabled={!state.assembled}>Copy raw</button>
|
|
446
|
+
<button type="button" onClick={() => dispatch('toggleCompareOpen')} className="rounded-full border border-slate-200 bg-slate-50 px-3 py-1.5 hover:bg-slate-100">Compare configs</button>
|
|
447
|
+
<button type="button" onClick={() => dispatch('exportComments')} className="rounded-full border border-slate-900 bg-slate-900 px-3 py-1.5 text-white hover:bg-slate-800" disabled={!state.review}>Export comments</button>
|
|
448
|
+
<div className="ml-auto text-xs text-slate-500">{state.lastExportPath ? <span className="font-mono">{state.lastExportPath}</span> : <span>Export writes a markdown file and copies its path.</span>}</div>
|
|
449
|
+
</div>
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/** @param {import('../../core/view/contract.js').ViewProps<ReviewState>} props */
|
|
454
|
+
export default function PromptReview({ state, dispatch }) {
|
|
455
|
+
const copiedPathRef = useRef('');
|
|
456
|
+
useEffect(() => {
|
|
457
|
+
if (!state.lastExportPath || state.lastExportPath === copiedPathRef.current) return;
|
|
458
|
+
copiedPathRef.current = state.lastExportPath;
|
|
459
|
+
void (async () => {
|
|
460
|
+
const ok = await copyText(state.lastExportPath || '');
|
|
461
|
+
toast(ok ? `Review copied: ${state.lastExportPath}` : `Export written: ${state.lastExportPath}`, ok ? 'success' : 'info');
|
|
462
|
+
})();
|
|
463
|
+
}, [state.lastExportPath]);
|
|
464
|
+
|
|
465
|
+
if (state.sourceError && !state.review) {
|
|
466
|
+
const d = state.sourceError.display;
|
|
467
|
+
const Takeover = d.level === 'error' ? ErrorState : NotReady;
|
|
468
|
+
return <Takeover headline={d.headline} explanation={d.explanation} nextStep={d.nextStep || undefined} onRetry={() => dispatch('refresh')} />;
|
|
469
|
+
}
|
|
470
|
+
if (!state.review) return <Loading label="Loading Prompt Studio…" />;
|
|
471
|
+
if (state.review.length === 0) return <Empty label="No prompt layers were returned." />;
|
|
472
|
+
|
|
473
|
+
return (
|
|
474
|
+
<div className="flex h-full min-h-0 flex-col bg-slate-50 text-slate-900">
|
|
475
|
+
{state.auxiliaryError ? <div className="border-b border-amber-200 bg-amber-50 px-4 py-2 text-xs text-amber-800">{state.auxiliaryError.display.explanation || state.auxiliaryError.display.headline}</div> : null}
|
|
476
|
+
<div className="grid min-h-0 flex-1 grid-cols-1 gap-3 p-4 lg:grid-cols-[18rem_minmax(0,1fr)_24rem]">
|
|
477
|
+
<ConfigPanel state={state} dispatch={dispatch} />
|
|
478
|
+
<AssembledPanel state={state} dispatch={dispatch} />
|
|
479
|
+
<InspectorPanel state={state} dispatch={dispatch} />
|
|
480
|
+
</div>
|
|
481
|
+
<FooterBar state={state} dispatch={dispatch} />
|
|
482
|
+
</div>
|
|
483
|
+
);
|
|
484
|
+
}
|