spexcode 0.6.1 → 0.6.5
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 +99 -149
- package/bin/spex.mjs +4 -0
- package/node_modules/@spexcode/spec-cli/bin/spex.mjs +76 -0
- package/node_modules/@spexcode/spec-cli/dist/attach.d.ts +2 -0
- package/node_modules/@spexcode/spec-cli/dist/attach.js +48 -0
- package/node_modules/@spexcode/spec-cli/dist/claude-headless.d.ts +33 -0
- package/node_modules/@spexcode/spec-cli/dist/claude-headless.js +307 -0
- package/node_modules/@spexcode/spec-cli/dist/cli.d.ts +1 -0
- package/node_modules/@spexcode/spec-cli/dist/cli.js +1859 -0
- package/node_modules/@spexcode/spec-cli/dist/client.d.ts +111 -0
- package/node_modules/@spexcode/spec-cli/dist/client.js +476 -0
- package/node_modules/@spexcode/spec-cli/dist/cockpit.d.ts +7 -0
- package/node_modules/@spexcode/spec-cli/dist/cockpit.js +26 -0
- package/node_modules/@spexcode/spec-cli/dist/codex-headless.d.ts +1 -0
- package/{spec-cli/src/codex-headless.ts → node_modules/@spexcode/spec-cli/dist/codex-headless.js} +3 -9
- package/node_modules/@spexcode/spec-cli/dist/codex-runtime-generations.d.ts +53 -0
- package/node_modules/@spexcode/spec-cli/dist/codex-runtime-generations.js +686 -0
- package/node_modules/@spexcode/spec-cli/dist/commit-surgery.d.ts +1 -0
- package/node_modules/@spexcode/spec-cli/dist/commit-surgery.js +90 -0
- package/node_modules/@spexcode/spec-cli/dist/contract-filter.d.ts +14 -0
- package/node_modules/@spexcode/spec-cli/dist/contract-filter.js +219 -0
- package/node_modules/@spexcode/spec-cli/dist/dashboard-assets.d.ts +6 -0
- package/node_modules/@spexcode/spec-cli/dist/dashboard-assets.js +50 -0
- package/node_modules/@spexcode/spec-cli/dist/delivery-queue.d.ts +23 -0
- package/node_modules/@spexcode/spec-cli/dist/delivery-queue.js +179 -0
- package/node_modules/@spexcode/spec-cli/dist/doctor.d.ts +9 -0
- package/node_modules/@spexcode/spec-cli/dist/doctor.js +547 -0
- package/node_modules/@spexcode/spec-cli/dist/eval-host.d.ts +1 -0
- package/node_modules/@spexcode/spec-cli/dist/eval-host.js +19 -0
- package/node_modules/@spexcode/spec-cli/dist/execution-trace.d.ts +26 -0
- package/node_modules/@spexcode/spec-cli/dist/execution-trace.js +475 -0
- package/node_modules/@spexcode/spec-cli/dist/file-write.d.ts +2 -0
- package/node_modules/@spexcode/spec-cli/dist/file-write.js +26 -0
- package/node_modules/@spexcode/spec-cli/dist/flat.d.ts +89 -0
- package/node_modules/@spexcode/spec-cli/dist/flat.js +1076 -0
- package/node_modules/@spexcode/spec-cli/dist/gateway-auth.d.ts +56 -0
- package/node_modules/@spexcode/spec-cli/dist/gateway-auth.js +168 -0
- package/node_modules/@spexcode/spec-cli/dist/gateway-hub.d.ts +28 -0
- package/node_modules/@spexcode/spec-cli/dist/gateway-hub.js +361 -0
- package/node_modules/@spexcode/spec-cli/dist/gateway.d.ts +37 -0
- package/node_modules/@spexcode/spec-cli/dist/gateway.js +503 -0
- package/node_modules/@spexcode/spec-cli/dist/graphCache.d.ts +27 -0
- package/node_modules/@spexcode/spec-cli/dist/graphCache.js +716 -0
- package/node_modules/@spexcode/spec-cli/dist/graphSnapshot.d.ts +14 -0
- package/node_modules/@spexcode/spec-cli/dist/graphSnapshot.js +35 -0
- package/node_modules/@spexcode/spec-cli/dist/graphStream.d.ts +85 -0
- package/node_modules/@spexcode/spec-cli/dist/graphStream.js +1195 -0
- package/node_modules/@spexcode/spec-cli/dist/guidance-catalog.d.ts +64 -0
- package/node_modules/@spexcode/spec-cli/dist/guidance-catalog.js +166 -0
- package/node_modules/@spexcode/spec-cli/dist/guide.d.ts +8 -0
- package/{spec-cli/src/guide.ts → node_modules/@spexcode/spec-cli/dist/guide.js} +115 -22
- package/node_modules/@spexcode/spec-cli/dist/harness-select.d.ts +18 -0
- package/node_modules/@spexcode/spec-cli/dist/harness-select.js +62 -0
- package/node_modules/@spexcode/spec-cli/dist/harness.d.ts +325 -0
- package/node_modules/@spexcode/spec-cli/dist/harness.js +3026 -0
- package/node_modules/@spexcode/spec-cli/dist/headless-controller.d.ts +9 -0
- package/node_modules/@spexcode/spec-cli/dist/headless-controller.js +47 -0
- package/node_modules/@spexcode/spec-cli/dist/help.d.ts +10 -0
- package/node_modules/@spexcode/spec-cli/dist/help.js +574 -0
- package/node_modules/@spexcode/spec-cli/dist/hook-prompts.d.ts +18 -0
- package/node_modules/@spexcode/spec-cli/dist/hook-prompts.js +122 -0
- package/node_modules/@spexcode/spec-cli/dist/hooks.d.ts +1 -0
- package/{spec-cli/src/hooks.ts → node_modules/@spexcode/spec-cli/dist/hooks.js} +15 -15
- package/node_modules/@spexcode/spec-cli/dist/host-resources.d.ts +97 -0
- package/node_modules/@spexcode/spec-cli/dist/host-resources.js +795 -0
- package/node_modules/@spexcode/spec-cli/dist/host.d.ts +88 -0
- package/node_modules/@spexcode/spec-cli/dist/host.js +663 -0
- package/node_modules/@spexcode/spec-cli/dist/index.d.ts +1 -0
- package/node_modules/@spexcode/spec-cli/dist/index.js +899 -0
- package/node_modules/@spexcode/spec-cli/dist/init.d.ts +1 -0
- package/node_modules/@spexcode/spec-cli/dist/init.js +284 -0
- package/node_modules/@spexcode/spec-cli/dist/issues-cli.d.ts +6 -0
- package/node_modules/@spexcode/spec-cli/dist/issues-cli.js +334 -0
- package/node_modules/@spexcode/spec-cli/dist/issues.d.ts +69 -0
- package/node_modules/@spexcode/spec-cli/dist/issues.js +189 -0
- package/node_modules/@spexcode/spec-cli/dist/lint.d.ts +34 -0
- package/node_modules/@spexcode/spec-cli/dist/lint.js +476 -0
- package/node_modules/@spexcode/spec-cli/dist/listen.d.ts +7 -0
- package/{spec-cli/src/listen.ts → node_modules/@spexcode/spec-cli/dist/listen.js} +13 -17
- package/node_modules/@spexcode/spec-cli/dist/localIssues.d.ts +65 -0
- package/node_modules/@spexcode/spec-cli/dist/localIssues.js +582 -0
- package/node_modules/@spexcode/spec-cli/dist/login-page.d.ts +5 -0
- package/{spec-cli/src/login-page.ts → node_modules/@spexcode/spec-cli/dist/login-page.js} +7 -7
- package/node_modules/@spexcode/spec-cli/dist/loop-in.d.ts +23 -0
- package/{spec-cli/src/loop-in.ts → node_modules/@spexcode/spec-cli/dist/loop-in.js} +35 -45
- package/node_modules/@spexcode/spec-cli/dist/machine-peer.d.ts +69 -0
- package/node_modules/@spexcode/spec-cli/dist/machine-peer.js +603 -0
- package/node_modules/@spexcode/spec-cli/dist/materialize.d.ts +18 -0
- package/node_modules/@spexcode/spec-cli/dist/materialize.js +468 -0
- package/node_modules/@spexcode/spec-cli/dist/mentions.d.ts +50 -0
- package/node_modules/@spexcode/spec-cli/dist/mentions.js +117 -0
- package/node_modules/@spexcode/spec-cli/dist/opencode-headless.d.ts +4 -0
- package/node_modules/@spexcode/spec-cli/dist/opencode-headless.js +208 -0
- package/node_modules/@spexcode/spec-cli/dist/opencode.d.ts +3 -0
- package/{spec-cli/src/opencode.ts → node_modules/@spexcode/spec-cli/dist/opencode.js} +9 -13
- package/node_modules/@spexcode/spec-cli/dist/pi-harness.d.ts +3 -0
- package/{spec-cli/src/pi-harness.ts → node_modules/@spexcode/spec-cli/dist/pi-harness.js} +45 -40
- package/node_modules/@spexcode/spec-cli/dist/pi-headless.d.ts +25 -0
- package/node_modules/@spexcode/spec-cli/dist/pi-headless.js +196 -0
- package/node_modules/@spexcode/spec-cli/dist/plugin-harness.d.ts +21 -0
- package/node_modules/@spexcode/spec-cli/dist/plugin-harness.js +146 -0
- package/node_modules/@spexcode/spec-cli/dist/pty-bridge.d.ts +10 -0
- package/node_modules/@spexcode/spec-cli/dist/pty-bridge.js +404 -0
- package/node_modules/@spexcode/spec-cli/dist/pty-helper.d.mts +1 -0
- package/node_modules/@spexcode/spec-cli/dist/pty-helper.mjs +101 -0
- package/node_modules/@spexcode/spec-cli/dist/pty-native-helper.d.mts +2 -0
- package/node_modules/@spexcode/spec-cli/dist/pty-native-helper.mjs +23 -0
- package/node_modules/@spexcode/spec-cli/dist/public-graph.d.ts +46 -0
- package/node_modules/@spexcode/spec-cli/dist/public-graph.js +56 -0
- package/node_modules/@spexcode/spec-cli/dist/ranker.d.ts +15 -0
- package/node_modules/@spexcode/spec-cli/dist/ranker.js +188 -0
- package/node_modules/@spexcode/spec-cli/dist/reaper.d.ts +6 -0
- package/node_modules/@spexcode/spec-cli/dist/reaper.js +81 -0
- package/node_modules/@spexcode/spec-cli/dist/reviews.d.ts +189 -0
- package/node_modules/@spexcode/spec-cli/dist/reviews.js +350 -0
- package/node_modules/@spexcode/spec-cli/dist/runtime-guard.d.ts +6 -0
- package/node_modules/@spexcode/spec-cli/dist/runtime-guard.js +37 -0
- package/node_modules/@spexcode/spec-cli/dist/runtime-ownership.d.ts +21 -0
- package/node_modules/@spexcode/spec-cli/dist/runtime-ownership.js +84 -0
- package/node_modules/@spexcode/spec-cli/dist/search.bench.d.mts +1 -0
- package/node_modules/@spexcode/spec-cli/dist/search.bench.mjs +75 -0
- package/node_modules/@spexcode/spec-cli/dist/search.d.ts +20 -0
- package/node_modules/@spexcode/spec-cli/dist/search.js +61 -0
- package/node_modules/@spexcode/spec-cli/dist/session-cursors.d.ts +14 -0
- package/node_modules/@spexcode/spec-cli/dist/session-cursors.js +82 -0
- package/node_modules/@spexcode/spec-cli/dist/session-declarations.d.ts +13 -0
- package/node_modules/@spexcode/spec-cli/dist/session-declarations.js +126 -0
- package/node_modules/@spexcode/spec-cli/dist/session-execution.d.ts +10 -0
- package/node_modules/@spexcode/spec-cli/dist/session-execution.js +70 -0
- package/node_modules/@spexcode/spec-cli/dist/session-files.d.ts +28 -0
- package/node_modules/@spexcode/spec-cli/dist/session-files.js +130 -0
- package/node_modules/@spexcode/spec-cli/dist/session-follow.d.ts +31 -0
- package/node_modules/@spexcode/spec-cli/dist/session-follow.js +179 -0
- package/node_modules/@spexcode/spec-cli/dist/session-reparent.d.ts +10 -0
- package/node_modules/@spexcode/spec-cli/dist/session-reparent.js +33 -0
- package/node_modules/@spexcode/spec-cli/dist/session-timeline.d.ts +51 -0
- package/node_modules/@spexcode/spec-cli/dist/session-timeline.js +233 -0
- package/node_modules/@spexcode/spec-cli/dist/session-web.d.ts +24 -0
- package/node_modules/@spexcode/spec-cli/dist/session-web.js +141 -0
- package/node_modules/@spexcode/spec-cli/dist/sessions.d.ts +412 -0
- package/node_modules/@spexcode/spec-cli/dist/sessions.js +4239 -0
- package/node_modules/@spexcode/spec-cli/dist/sh.d.ts +1 -0
- package/node_modules/@spexcode/spec-cli/dist/sh.js +3 -0
- package/node_modules/@spexcode/spec-cli/dist/shim-runtime.d.ts +1 -0
- package/{spec-cli/src/shim-runtime.ts → node_modules/@spexcode/spec-cli/dist/shim-runtime.js} +3 -4
- package/node_modules/@spexcode/spec-cli/dist/slash-commands.d.ts +9 -0
- package/node_modules/@spexcode/spec-cli/dist/slash-commands.js +307 -0
- package/node_modules/@spexcode/spec-cli/dist/source-files.d.ts +9 -0
- package/node_modules/@spexcode/spec-cli/dist/source-files.js +113 -0
- package/node_modules/@spexcode/spec-cli/dist/supervise.d.ts +1 -0
- package/node_modules/@spexcode/spec-cli/dist/supervise.js +308 -0
- package/node_modules/@spexcode/spec-cli/dist/tree.d.ts +25 -0
- package/node_modules/@spexcode/spec-cli/dist/tree.js +98 -0
- package/node_modules/@spexcode/spec-cli/dist/tsx-bin.d.ts +3 -0
- package/node_modules/@spexcode/spec-cli/dist/tsx-bin.js +41 -0
- package/node_modules/@spexcode/spec-cli/dist/uninstall.d.ts +3 -0
- package/node_modules/@spexcode/spec-cli/dist/uninstall.js +177 -0
- package/node_modules/@spexcode/spec-cli/dist/uploads.d.ts +36 -0
- package/node_modules/@spexcode/spec-cli/dist/uploads.js +243 -0
- package/node_modules/@spexcode/spec-cli/dist/worktree-sources.d.ts +1 -0
- package/node_modules/@spexcode/spec-cli/dist/worktree-sources.js +47 -0
- package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/dispatch.sh +5 -5
- package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/harness.sh +27 -7
- package/node_modules/@spexcode/spec-cli/package.json +47 -0
- package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/commands/supervisor/spec.md +8 -0
- package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/core/comment-altitude/spec.md +9 -0
- package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-first/spec-first.sh +1 -1
- package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-of-file/spec-of-file.sh +1 -0
- package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/core/spec.md +22 -0
- package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/stop-gate/spec.md +2 -2
- package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/stop-gate/stop-gate.sh +31 -29
- package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/prompts/atomic-landing/spec.md +15 -0
- package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/prompts/forge-link/spec.md +10 -0
- package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/prompts/memory-hygiene/spec.md +13 -0
- package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/prompts/reproduce-before-fix/spec.md +12 -0
- package/node_modules/@spexcode/spec-core/dist/anchors.d.ts +94 -0
- package/node_modules/@spexcode/spec-core/dist/anchors.js +730 -0
- package/node_modules/@spexcode/spec-core/dist/git.d.ts +166 -0
- package/node_modules/@spexcode/spec-core/dist/git.js +2736 -0
- package/node_modules/@spexcode/spec-core/dist/graph-delta.d.ts +44 -0
- package/node_modules/@spexcode/spec-core/dist/graph-delta.js +72 -0
- package/node_modules/@spexcode/spec-core/dist/graph.d.ts +34 -0
- package/node_modules/@spexcode/spec-core/dist/graph.js +237 -0
- package/node_modules/@spexcode/spec-core/dist/graphDelta.d.ts +3 -0
- package/node_modules/@spexcode/spec-core/dist/graphDelta.js +13 -0
- package/node_modules/@spexcode/spec-core/dist/harness-identity.d.ts +31 -0
- package/node_modules/@spexcode/spec-core/dist/harness-identity.js +20 -0
- package/node_modules/@spexcode/spec-core/dist/identity-presets.d.ts +152 -0
- package/node_modules/@spexcode/spec-core/dist/identity-presets.js +132 -0
- package/node_modules/@spexcode/spec-core/dist/index.d.ts +45 -0
- package/node_modules/@spexcode/spec-core/dist/index.js +19 -0
- package/node_modules/@spexcode/spec-core/dist/layout.d.ts +183 -0
- package/node_modules/@spexcode/spec-core/dist/layout.js +548 -0
- package/node_modules/@spexcode/spec-core/dist/process-identity.d.ts +37 -0
- package/node_modules/@spexcode/spec-core/dist/process-identity.js +214 -0
- package/node_modules/@spexcode/spec-core/dist/project-identity.d.ts +12 -0
- package/node_modules/@spexcode/spec-core/dist/project-identity.js +71 -0
- package/node_modules/@spexcode/spec-core/dist/project-store.d.ts +3 -0
- package/node_modules/@spexcode/spec-core/dist/project-store.js +14 -0
- package/node_modules/@spexcode/spec-core/dist/resilience.d.ts +2 -0
- package/node_modules/@spexcode/spec-core/dist/resilience.js +40 -0
- package/node_modules/@spexcode/spec-core/dist/review/index.d.ts +3 -0
- package/node_modules/@spexcode/spec-core/dist/review/index.js +5 -0
- package/node_modules/@spexcode/spec-core/dist/review/reviewFilters.d.ts +77 -0
- package/node_modules/@spexcode/spec-core/dist/review/reviewFilters.js +308 -0
- package/node_modules/@spexcode/spec-core/dist/review/reviewQuery.d.ts +66 -0
- package/node_modules/@spexcode/spec-core/dist/review/reviewQuery.js +180 -0
- package/node_modules/@spexcode/spec-core/dist/review/session.d.ts +4 -0
- package/node_modules/@spexcode/spec-core/dist/review/session.js +8 -0
- package/node_modules/@spexcode/spec-core/dist/reviewSnapshot.d.ts +15 -0
- package/node_modules/@spexcode/spec-core/dist/reviewSnapshot.js +12 -0
- package/node_modules/@spexcode/spec-core/dist/root-lru.d.ts +4 -0
- package/{spec-cli/src/root-lru.ts → node_modules/@spexcode/spec-core/dist/root-lru.js} +26 -30
- package/node_modules/@spexcode/spec-core/dist/specs.d.ts +117 -0
- package/node_modules/@spexcode/spec-core/dist/specs.js +489 -0
- package/node_modules/@spexcode/spec-core/package.json +28 -0
- package/node_modules/@spexcode/spec-eval/dist/cache.d.ts +10 -0
- package/node_modules/@spexcode/spec-eval/dist/cache.js +50 -0
- package/node_modules/@spexcode/spec-eval/dist/cli.d.ts +22 -0
- package/node_modules/@spexcode/spec-eval/dist/cli.js +981 -0
- package/node_modules/@spexcode/spec-eval/dist/evaltab.d.ts +98 -0
- package/node_modules/@spexcode/spec-eval/dist/evaltab.js +176 -0
- package/node_modules/@spexcode/spec-eval/dist/filing.d.ts +16 -0
- package/node_modules/@spexcode/spec-eval/dist/filing.js +36 -0
- package/node_modules/@spexcode/spec-eval/dist/freshness.d.ts +48 -0
- package/node_modules/@spexcode/spec-eval/dist/freshness.js +799 -0
- package/node_modules/@spexcode/spec-eval/dist/host.d.ts +46 -0
- package/node_modules/@spexcode/spec-eval/dist/host.js +53 -0
- package/node_modules/@spexcode/spec-eval/dist/humanok.d.ts +11 -0
- package/node_modules/@spexcode/spec-eval/dist/humanok.js +27 -0
- package/node_modules/@spexcode/spec-eval/dist/index.d.ts +4 -0
- package/node_modules/@spexcode/spec-eval/dist/index.js +4 -0
- package/node_modules/@spexcode/spec-eval/dist/remarks.d.ts +31 -0
- package/node_modules/@spexcode/spec-eval/dist/remarks.js +1 -0
- package/node_modules/@spexcode/spec-eval/dist/scenariofresh.d.ts +13 -0
- package/node_modules/@spexcode/spec-eval/dist/scenariofresh.js +303 -0
- package/node_modules/@spexcode/spec-eval/dist/scenarios.d.ts +99 -0
- package/node_modules/@spexcode/spec-eval/dist/scenarios.js +650 -0
- package/node_modules/@spexcode/spec-eval/dist/sessioneval.d.ts +307 -0
- package/node_modules/@spexcode/spec-eval/dist/sessioneval.js +1883 -0
- package/node_modules/@spexcode/spec-eval/dist/sidecar.d.ts +55 -0
- package/node_modules/@spexcode/spec-eval/dist/sidecar.js +82 -0
- package/node_modules/@spexcode/spec-eval/dist/timeline.d.ts +25 -0
- package/node_modules/@spexcode/spec-eval/dist/timeline.js +65 -0
- package/node_modules/@spexcode/spec-eval/dist/ui-path.d.ts +1 -0
- package/node_modules/@spexcode/spec-eval/dist/ui-path.js +2 -0
- package/node_modules/@spexcode/spec-eval/package.json +36 -0
- package/node_modules/@spexcode/spec-forge/dist/cache.d.ts +29 -0
- package/node_modules/@spexcode/spec-forge/dist/cache.js +59 -0
- package/node_modules/@spexcode/spec-forge/dist/cli.d.ts +1 -0
- package/node_modules/@spexcode/spec-forge/dist/cli.js +100 -0
- package/node_modules/@spexcode/spec-forge/dist/drivers/github.d.ts +2 -0
- package/node_modules/@spexcode/spec-forge/dist/drivers/github.js +116 -0
- package/node_modules/@spexcode/spec-forge/dist/drivers/gitlab.d.ts +7 -0
- package/node_modules/@spexcode/spec-forge/dist/drivers/gitlab.js +144 -0
- package/node_modules/@spexcode/spec-forge/dist/drivers.d.ts +10 -0
- package/node_modules/@spexcode/spec-forge/dist/drivers.js +83 -0
- package/node_modules/@spexcode/spec-forge/dist/index.d.ts +4 -0
- package/node_modules/@spexcode/spec-forge/dist/index.js +4 -0
- package/node_modules/@spexcode/spec-forge/dist/links.d.ts +15 -0
- package/node_modules/@spexcode/spec-forge/dist/links.js +65 -0
- package/node_modules/@spexcode/spec-forge/dist/needs-eval.d.ts +10 -0
- package/node_modules/@spexcode/spec-forge/dist/needs-eval.js +20 -0
- package/node_modules/@spexcode/spec-forge/dist/port.d.ts +53 -0
- package/node_modules/@spexcode/spec-forge/dist/port.js +1 -0
- package/node_modules/@spexcode/spec-forge/dist/resident.d.ts +7 -0
- package/node_modules/@spexcode/spec-forge/dist/resident.js +43 -0
- package/node_modules/@spexcode/spec-forge/package.json +32 -0
- package/package.json +33 -19
- package/spec-cli/bin/spex.mjs +0 -69
- package/spec-cli/src/anchors.ts +0 -706
- package/spec-cli/src/attach.ts +0 -43
- package/spec-cli/src/claude-headless.ts +0 -321
- package/spec-cli/src/cli.ts +0 -1115
- package/spec-cli/src/client.ts +0 -315
- package/spec-cli/src/cockpit.ts +0 -43
- package/spec-cli/src/codex-runtime-generations.ts +0 -646
- package/spec-cli/src/commit-surgery.ts +0 -68
- package/spec-cli/src/contract-filter.ts +0 -202
- package/spec-cli/src/delivery-queue.ts +0 -107
- package/spec-cli/src/doctor.ts +0 -516
- package/spec-cli/src/file-write.ts +0 -22
- package/spec-cli/src/gateway-auth.ts +0 -181
- package/spec-cli/src/gateway-hub.ts +0 -356
- package/spec-cli/src/gateway.ts +0 -368
- package/spec-cli/src/git.ts +0 -2180
- package/spec-cli/src/graph.ts +0 -221
- package/spec-cli/src/graphCache.ts +0 -641
- package/spec-cli/src/graphDelta.ts +0 -77
- package/spec-cli/src/graphStream.ts +0 -1019
- package/spec-cli/src/harness-select.ts +0 -77
- package/spec-cli/src/harness.ts +0 -2747
- package/spec-cli/src/headless-controller.ts +0 -63
- package/spec-cli/src/help.ts +0 -480
- package/spec-cli/src/host-resources.ts +0 -707
- package/spec-cli/src/host.ts +0 -611
- package/spec-cli/src/identity-presets.d.ts +0 -13
- package/spec-cli/src/identity-presets.js +0 -128
- package/spec-cli/src/index.ts +0 -730
- package/spec-cli/src/init.ts +0 -258
- package/spec-cli/src/issues-cli.ts +0 -276
- package/spec-cli/src/issues.ts +0 -237
- package/spec-cli/src/layout.ts +0 -557
- package/spec-cli/src/lint.ts +0 -458
- package/spec-cli/src/localIssues.ts +0 -538
- package/spec-cli/src/materialize.ts +0 -412
- package/spec-cli/src/mentions.ts +0 -81
- package/spec-cli/src/opencode-headless.ts +0 -205
- package/spec-cli/src/pi-headless.ts +0 -153
- package/spec-cli/src/plugin-harness.ts +0 -157
- package/spec-cli/src/process-identity.ts +0 -207
- package/spec-cli/src/project-identity.ts +0 -73
- package/spec-cli/src/project-store.ts +0 -17
- package/spec-cli/src/pty-bridge.ts +0 -396
- package/spec-cli/src/pty-helper.mjs +0 -96
- package/spec-cli/src/pty-native-helper.mjs +0 -22
- package/spec-cli/src/ranker.ts +0 -191
- package/spec-cli/src/reaper.ts +0 -125
- package/spec-cli/src/resilience.ts +0 -41
- package/spec-cli/src/reviewSnapshot.ts +0 -28
- package/spec-cli/src/reviews.ts +0 -405
- package/spec-cli/src/runtime-guard.ts +0 -35
- package/spec-cli/src/runtime-ownership.ts +0 -88
- package/spec-cli/src/search.bench.mjs +0 -80
- package/spec-cli/src/search.ts +0 -63
- package/spec-cli/src/session-cursors.ts +0 -91
- package/spec-cli/src/session-follow.ts +0 -182
- package/spec-cli/src/session-timeline.ts +0 -98
- package/spec-cli/src/sessions.ts +0 -3403
- package/spec-cli/src/sh.ts +0 -3
- package/spec-cli/src/slash-commands.ts +0 -318
- package/spec-cli/src/source-files.ts +0 -104
- package/spec-cli/src/specs.ts +0 -498
- package/spec-cli/src/supervise.ts +0 -245
- package/spec-cli/src/tree.ts +0 -118
- package/spec-cli/src/tsx-bin.ts +0 -18
- package/spec-cli/src/uninstall.ts +0 -171
- package/spec-cli/src/uploads.ts +0 -253
- package/spec-cli/src/worktree-sources.ts +0 -42
- package/spec-cli/templates/spec/project/.plugins/commands/supervisor/spec.md +0 -8
- package/spec-cli/templates/spec/project/.plugins/core/comment-altitude/spec.md +0 -28
- package/spec-cli/templates/spec/project/.plugins/core/spec.md +0 -23
- package/spec-cli/templates/spec/project/.plugins/prompts/atomic-landing/spec.md +0 -32
- package/spec-cli/templates/spec/project/.plugins/prompts/forge-link/spec.md +0 -9
- package/spec-cli/templates/spec/project/.plugins/prompts/memory-hygiene/spec.md +0 -15
- package/spec-cli/templates/spec/project/.plugins/prompts/reproduce-before-fix/spec.md +0 -18
- package/spec-dashboard/dist/assets/App-F9uaAVcH.js +0 -2
- package/spec-dashboard/dist/assets/Dashboard-Ba_jhxp1.js +0 -27
- package/spec-dashboard/dist/assets/Dashboard-C5ap-Sga.css +0 -1
- package/spec-dashboard/dist/assets/EvalsPage-FixoOg_n.js +0 -2
- package/spec-dashboard/dist/assets/IssuesPage-CuKLFhH3.js +0 -1
- package/spec-dashboard/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/spec-dashboard/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/spec-dashboard/dist/assets/MobileApp-CHgEHORJ.js +0 -2
- package/spec-dashboard/dist/assets/Modal-CQgYymmr.js +0 -1
- package/spec-dashboard/dist/assets/PageScroll-hT7UTLvD.js +0 -1
- package/spec-dashboard/dist/assets/ProjectsPage-CtXxakF9.js +0 -1
- package/spec-dashboard/dist/assets/SessionInterface-6GBZ9nXN.css +0 -32
- package/spec-dashboard/dist/assets/SessionInterface-Bpie-9fs.js +0 -39
- package/spec-dashboard/dist/assets/SessionWindow-CixDi4PI.js +0 -1
- package/spec-dashboard/dist/assets/Settings-C2MsucfE.js +0 -1
- package/spec-dashboard/dist/assets/Thread-C6Go8HRh.js +0 -13
- package/spec-dashboard/dist/assets/bindings-BC9vqpYU.js +0 -1
- package/spec-dashboard/dist/assets/data-B-RQmit6.js +0 -1
- package/spec-dashboard/dist/assets/index-CsI8DElI.css +0 -1
- package/spec-dashboard/dist/assets/index-DrVao0Ep.js +0 -41
- package/spec-dashboard/dist/assets/launch-BBH02b1v.js +0 -276
- package/spec-dashboard/dist/assets/launch-Cp579UoJ.css +0 -1
- package/spec-dashboard/dist/assets/terminalFont-C6oGNKrf.js +0 -1
- package/spec-dashboard/dist/index.html +0 -29
- package/spec-dashboard/src/reviewFilters.js +0 -322
- package/spec-dashboard/src/reviewQuery.js +0 -174
- package/spec-dashboard/src/session.js +0 -199
- package/spec-eval/src/cache.ts +0 -57
- package/spec-eval/src/cli.ts +0 -889
- package/spec-eval/src/evaltab.ts +0 -262
- package/spec-eval/src/filing.ts +0 -39
- package/spec-eval/src/freshness.ts +0 -557
- package/spec-eval/src/humanok.ts +0 -28
- package/spec-eval/src/scenariofresh.ts +0 -244
- package/spec-eval/src/scenarios.ts +0 -672
- package/spec-eval/src/sessioneval.ts +0 -2226
- package/spec-eval/src/sidecar.ts +0 -93
- package/spec-eval/src/timeline.ts +0 -54
- package/spec-forge/src/__fixtures__/github-forge.json +0 -63
- package/spec-forge/src/cache.ts +0 -66
- package/spec-forge/src/cli.ts +0 -99
- package/spec-forge/src/drivers/github.ts +0 -132
- package/spec-forge/src/drivers/gitlab.ts +0 -153
- package/spec-forge/src/drivers.ts +0 -73
- package/spec-forge/src/links.ts +0 -72
- package/spec-forge/src/needs-eval.ts +0 -29
- package/spec-forge/src/port.ts +0 -36
- package/spec-forge/src/resident.ts +0 -46
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/README.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/compat/mark-active-0.5.2-eef1.fixture +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/hooks/compat/mark-active-sed-v0.fixture +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/commit-msg +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/post-checkout +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/post-merge +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/pre-commit +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/prepare-commit-msg +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/hooks/reference-transaction +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/extract/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/regroup/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/rename/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/commands/tidy/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/idle/idle.sh +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/idle/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/mark-active/mark-active.sh +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/mark-active/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/session-fail/fail.sh +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/session-fail/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-first/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/core/spec-of-file/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/skills/distill/digest.mjs +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/skills/distill/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/skills/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-core}/templates/spexcode.json +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type UploadPolicy } from '@spexcode/spec-core';
|
|
2
|
+
type UploadMeta = {
|
|
3
|
+
version: 1;
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
size: number;
|
|
7
|
+
offset: number;
|
|
8
|
+
createdAt: number;
|
|
9
|
+
updatedAt: number;
|
|
10
|
+
};
|
|
11
|
+
export type UploadStatus = Pick<UploadMeta, 'id' | 'name' | 'size' | 'offset'> & Pick<UploadPolicy, 'chunkBytes' | 'concurrency' | 'requestTimeoutMs' | 'retryLimit' | 'retryDelayMs'>;
|
|
12
|
+
export declare class UploadError extends Error {
|
|
13
|
+
readonly status: number;
|
|
14
|
+
readonly offset?: number | undefined;
|
|
15
|
+
constructor(status: number, message: string, offset?: number | undefined);
|
|
16
|
+
}
|
|
17
|
+
export declare const evidenceMaxBytes: () => number;
|
|
18
|
+
export declare function cleanupExpiredUploads(policy?: Required<{
|
|
19
|
+
maxBytes?: number;
|
|
20
|
+
chunkBytes?: number;
|
|
21
|
+
concurrency?: number;
|
|
22
|
+
requestTimeoutMs?: number;
|
|
23
|
+
retryLimit?: number;
|
|
24
|
+
retryDelayMs?: number;
|
|
25
|
+
incompleteTtlMs?: number;
|
|
26
|
+
cleanupIntervalMs?: number;
|
|
27
|
+
minFreeBytes?: number;
|
|
28
|
+
evidenceMaxBytes?: number;
|
|
29
|
+
}>): void;
|
|
30
|
+
export declare function startUploadReaper(): void;
|
|
31
|
+
export declare function createUpload(name: unknown, size: unknown): UploadStatus;
|
|
32
|
+
export declare function uploadStatus(id: string): UploadStatus;
|
|
33
|
+
export declare function appendUpload(id: string, offset: unknown, body: ReadableStream<Uint8Array> | null, contentLength?: string): Promise<UploadStatus>;
|
|
34
|
+
export declare function completeUpload(id: string): string;
|
|
35
|
+
export declare function cancelUpload(id: string): void;
|
|
36
|
+
export {};
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { createWriteStream, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, statfsSync, truncateSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { basename, join } from 'node:path';
|
|
5
|
+
import { Readable, Transform } from 'node:stream';
|
|
6
|
+
import { pipeline } from 'node:stream/promises';
|
|
7
|
+
import { repoRoot } from '@spexcode/spec-core';
|
|
8
|
+
import { readUploadPolicy } from '@spexcode/spec-core';
|
|
9
|
+
// The backend's tmpdir is the worker's filesystem. Completed files stay directly under this sink; private
|
|
10
|
+
// metadata and partial bytes live below .staging until an exact-length transfer is promoted atomically.
|
|
11
|
+
const UPLOAD_DIR = join(tmpdir(), 'spexcode-uploads');
|
|
12
|
+
const STAGING_DIR = join(UPLOAD_DIR, '.staging');
|
|
13
|
+
export class UploadError extends Error {
|
|
14
|
+
status;
|
|
15
|
+
offset;
|
|
16
|
+
constructor(status, message, offset) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.status = status;
|
|
19
|
+
this.offset = offset;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const uploadPolicy = () => readUploadPolicy(repoRoot());
|
|
23
|
+
export const evidenceMaxBytes = () => uploadPolicy().evidenceMaxBytes;
|
|
24
|
+
function ensureDirs() {
|
|
25
|
+
mkdirSync(STAGING_DIR, { recursive: true });
|
|
26
|
+
}
|
|
27
|
+
function safeName(name) {
|
|
28
|
+
const base = basename(name || '').replace(/[^A-Za-z0-9._-]/g, '_').replace(/^\.+/, '');
|
|
29
|
+
return base || 'upload';
|
|
30
|
+
}
|
|
31
|
+
function validId(id) {
|
|
32
|
+
return /^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(id);
|
|
33
|
+
}
|
|
34
|
+
function metaPath(id) {
|
|
35
|
+
return join(STAGING_DIR, `${id}.json`);
|
|
36
|
+
}
|
|
37
|
+
function partPath(id) {
|
|
38
|
+
return join(STAGING_DIR, `${id}.part`);
|
|
39
|
+
}
|
|
40
|
+
function removeTransfer(id) {
|
|
41
|
+
rmSync(metaPath(id), { force: true });
|
|
42
|
+
rmSync(partPath(id), { force: true });
|
|
43
|
+
}
|
|
44
|
+
function readMetaFile(id) {
|
|
45
|
+
if (!validId(id))
|
|
46
|
+
return null;
|
|
47
|
+
try {
|
|
48
|
+
const meta = JSON.parse(readFileSync(metaPath(id), 'utf8'));
|
|
49
|
+
if (meta.version !== 1 || meta.id !== id || typeof meta.name !== 'string' ||
|
|
50
|
+
!Number.isSafeInteger(meta.size) || meta.size <= 0 ||
|
|
51
|
+
!Number.isSafeInteger(meta.offset) || meta.offset < 0 || meta.offset > meta.size ||
|
|
52
|
+
!Number.isSafeInteger(meta.createdAt) || !Number.isSafeInteger(meta.updatedAt))
|
|
53
|
+
return null;
|
|
54
|
+
return meta;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function writeMeta(meta) {
|
|
61
|
+
const path = metaPath(meta.id);
|
|
62
|
+
const temp = `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
63
|
+
writeFileSync(temp, JSON.stringify(meta) + '\n');
|
|
64
|
+
renameSync(temp, path);
|
|
65
|
+
}
|
|
66
|
+
function actualOffset(meta) {
|
|
67
|
+
try {
|
|
68
|
+
return statSync(partPath(meta.id)).size;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function status(meta, policy) {
|
|
75
|
+
const { chunkBytes, concurrency, requestTimeoutMs, retryLimit, retryDelayMs } = policy;
|
|
76
|
+
return { id: meta.id, name: meta.name, size: meta.size, offset: meta.offset, chunkBytes, concurrency, requestTimeoutMs, retryLimit, retryDelayMs };
|
|
77
|
+
}
|
|
78
|
+
function syncOffset(meta) {
|
|
79
|
+
const offset = actualOffset(meta);
|
|
80
|
+
if (offset > meta.size)
|
|
81
|
+
throw new UploadError(409, 'upload staging file exceeds its declared length');
|
|
82
|
+
if (offset !== meta.offset) {
|
|
83
|
+
meta.offset = offset;
|
|
84
|
+
meta.updatedAt = Date.now();
|
|
85
|
+
writeMeta(meta);
|
|
86
|
+
}
|
|
87
|
+
return meta;
|
|
88
|
+
}
|
|
89
|
+
function loadUpload(id, policy) {
|
|
90
|
+
const meta = readMetaFile(id);
|
|
91
|
+
if (!meta)
|
|
92
|
+
throw new UploadError(404, 'upload not found');
|
|
93
|
+
if (Date.now() - meta.updatedAt > policy.incompleteTtlMs) {
|
|
94
|
+
removeTransfer(id);
|
|
95
|
+
throw new UploadError(404, 'upload expired');
|
|
96
|
+
}
|
|
97
|
+
return syncOffset(meta);
|
|
98
|
+
}
|
|
99
|
+
function reservedBytes(policy) {
|
|
100
|
+
let total = 0;
|
|
101
|
+
for (const entry of readdirSync(STAGING_DIR, { withFileTypes: true })) {
|
|
102
|
+
if (!entry.isFile() || !entry.name.endsWith('.json'))
|
|
103
|
+
continue;
|
|
104
|
+
const meta = readMetaFile(entry.name.slice(0, -5));
|
|
105
|
+
if (!meta || Date.now() - meta.updatedAt > policy.incompleteTtlMs)
|
|
106
|
+
continue;
|
|
107
|
+
total += Math.max(0, meta.size - actualOffset(meta));
|
|
108
|
+
}
|
|
109
|
+
return total;
|
|
110
|
+
}
|
|
111
|
+
function reserveCapacity(size, policy) {
|
|
112
|
+
let available = 0;
|
|
113
|
+
try {
|
|
114
|
+
const fs = statfsSync(UPLOAD_DIR);
|
|
115
|
+
available = Number(fs.bavail) * Number(fs.bsize);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// A filesystem that cannot report capacity will still fail loudly during the stream write.
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (size > Math.max(0, available - policy.minFreeBytes - reservedBytes(policy))) {
|
|
122
|
+
throw new UploadError(507, 'insufficient backend disk capacity for this upload');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
export function cleanupExpiredUploads(policy = uploadPolicy()) {
|
|
126
|
+
ensureDirs();
|
|
127
|
+
const now = Date.now();
|
|
128
|
+
for (const entry of readdirSync(STAGING_DIR, { withFileTypes: true })) {
|
|
129
|
+
if (!entry.isFile() || !entry.name.endsWith('.json'))
|
|
130
|
+
continue;
|
|
131
|
+
const id = entry.name.slice(0, -5);
|
|
132
|
+
const meta = readMetaFile(id);
|
|
133
|
+
if (!meta || now - meta.updatedAt > policy.incompleteTtlMs)
|
|
134
|
+
removeTransfer(id);
|
|
135
|
+
}
|
|
136
|
+
for (const entry of readdirSync(STAGING_DIR, { withFileTypes: true })) {
|
|
137
|
+
if (!entry.isFile() || !entry.name.endsWith('.part'))
|
|
138
|
+
continue;
|
|
139
|
+
const id = entry.name.slice(0, -5);
|
|
140
|
+
if (readMetaFile(id))
|
|
141
|
+
continue;
|
|
142
|
+
try {
|
|
143
|
+
if (now - statSync(partPath(id)).mtimeMs > policy.incompleteTtlMs)
|
|
144
|
+
rmSync(partPath(id), { force: true });
|
|
145
|
+
}
|
|
146
|
+
catch { /* raced a cancellation or another cleanup pass */ }
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
export function startUploadReaper() {
|
|
150
|
+
const sweep = () => {
|
|
151
|
+
const policy = uploadPolicy();
|
|
152
|
+
cleanupExpiredUploads(policy);
|
|
153
|
+
const timer = setTimeout(sweep, policy.cleanupIntervalMs);
|
|
154
|
+
timer.unref();
|
|
155
|
+
};
|
|
156
|
+
sweep();
|
|
157
|
+
}
|
|
158
|
+
export function createUpload(name, size) {
|
|
159
|
+
const policy = uploadPolicy();
|
|
160
|
+
if (typeof name !== 'string' || !name.trim())
|
|
161
|
+
throw new UploadError(400, 'file name is required');
|
|
162
|
+
if (typeof size !== 'number' || !Number.isSafeInteger(size) || size <= 0)
|
|
163
|
+
throw new UploadError(400, 'file must not be empty');
|
|
164
|
+
if (size > policy.maxBytes)
|
|
165
|
+
throw new UploadError(413, 'file exceeds the configured upload limit');
|
|
166
|
+
ensureDirs();
|
|
167
|
+
cleanupExpiredUploads(policy);
|
|
168
|
+
reserveCapacity(size, policy);
|
|
169
|
+
const now = Date.now();
|
|
170
|
+
const meta = { version: 1, id: randomUUID(), name: safeName(name), size, offset: 0, createdAt: now, updatedAt: now };
|
|
171
|
+
writeMeta(meta);
|
|
172
|
+
return status(meta, policy);
|
|
173
|
+
}
|
|
174
|
+
export function uploadStatus(id) {
|
|
175
|
+
const policy = uploadPolicy();
|
|
176
|
+
return status(loadUpload(id, policy), policy);
|
|
177
|
+
}
|
|
178
|
+
export async function appendUpload(id, offset, body, contentLength) {
|
|
179
|
+
const policy = uploadPolicy();
|
|
180
|
+
const meta = loadUpload(id, policy);
|
|
181
|
+
if (typeof offset !== 'number' || !Number.isSafeInteger(offset) || offset < 0)
|
|
182
|
+
throw new UploadError(400, 'upload offset must be a non-negative integer');
|
|
183
|
+
if (offset !== meta.offset)
|
|
184
|
+
throw new UploadError(409, 'upload offset does not match the committed bytes', meta.offset);
|
|
185
|
+
if (!body)
|
|
186
|
+
throw new UploadError(400, 'upload chunk is required');
|
|
187
|
+
const declared = contentLength == null ? null : Number(contentLength);
|
|
188
|
+
if (declared != null && (!Number.isSafeInteger(declared) || declared <= 0))
|
|
189
|
+
throw new UploadError(400, 'content-length must be a positive integer');
|
|
190
|
+
if (declared != null && (declared > policy.chunkBytes || meta.offset + declared > meta.size)) {
|
|
191
|
+
throw new UploadError(413, 'upload chunk exceeds its declared bounds');
|
|
192
|
+
}
|
|
193
|
+
let written = 0;
|
|
194
|
+
const before = meta.offset;
|
|
195
|
+
const limiter = new Transform({
|
|
196
|
+
transform(chunk, _encoding, callback) {
|
|
197
|
+
written += chunk.length;
|
|
198
|
+
if (written > policy.chunkBytes || before + written > meta.size) {
|
|
199
|
+
callback(new UploadError(413, 'upload chunk exceeds its declared bounds'));
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
callback(null, chunk);
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
try {
|
|
206
|
+
await pipeline(Readable.fromWeb(body), limiter, createWriteStream(partPath(id), { flags: 'a' }));
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
if (error instanceof UploadError) {
|
|
210
|
+
truncateSync(partPath(id), before);
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
213
|
+
// An interrupted connection may have committed a valid prefix. The next GET reports its actual length.
|
|
214
|
+
meta.offset = actualOffset(meta);
|
|
215
|
+
meta.updatedAt = Date.now();
|
|
216
|
+
writeMeta(meta);
|
|
217
|
+
throw new UploadError(500, `upload write failed: ${error.message}`);
|
|
218
|
+
}
|
|
219
|
+
if (written === 0)
|
|
220
|
+
throw new UploadError(400, 'upload chunk is empty');
|
|
221
|
+
meta.offset = actualOffset(meta);
|
|
222
|
+
meta.updatedAt = Date.now();
|
|
223
|
+
writeMeta(meta);
|
|
224
|
+
return status(meta, policy);
|
|
225
|
+
}
|
|
226
|
+
export function completeUpload(id) {
|
|
227
|
+
const meta = loadUpload(id, uploadPolicy());
|
|
228
|
+
if (meta.offset !== meta.size)
|
|
229
|
+
throw new UploadError(409, `upload is incomplete (${meta.offset} of ${meta.size} bytes)`, meta.offset);
|
|
230
|
+
const path = join(UPLOAD_DIR, `${Date.now().toString(36)}-${meta.id}-${safeName(meta.name)}`);
|
|
231
|
+
try {
|
|
232
|
+
renameSync(partPath(id), path);
|
|
233
|
+
rmSync(metaPath(id), { force: true });
|
|
234
|
+
return path;
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
throw new UploadError(500, `upload completion failed: ${error.message}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
export function cancelUpload(id) {
|
|
241
|
+
loadUpload(id, uploadPolicy());
|
|
242
|
+
removeTransfer(id);
|
|
243
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function seedWorktreeHostState(main: string, wt: string): void;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { git } from '@spexcode/spec-core';
|
|
4
|
+
export function seedWorktreeHostState(main, wt) {
|
|
5
|
+
const f = 'spexcode.local.json';
|
|
6
|
+
try {
|
|
7
|
+
if (!existsSync(join(main, f)) || existsSync(join(wt, f)))
|
|
8
|
+
return;
|
|
9
|
+
copyFileSync(join(main, f), join(wt, f));
|
|
10
|
+
}
|
|
11
|
+
catch (e) {
|
|
12
|
+
console.error(`spexcode: could not seed ${f} from ${main} into worktree ${wt} — that worker runs on defaults (${e})`);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
hideSeededFromGit(wt, [f]);
|
|
16
|
+
}
|
|
17
|
+
// what we seed, we hide: a seeded entry git still sees is force-add bait (a real PR once carried seeded
|
|
18
|
+
// files into a product repo). `.git/info/exclude` lives in the COMMON git dir, so one write hides the entry
|
|
19
|
+
// in every linked worktree AND the main checkout. Only entries seeded by THIS call and reported un-ignored
|
|
20
|
+
// by `git check-ignore` are written: idempotent across dispatches, and a repo whose materialize already ignores
|
|
21
|
+
// the overlay (materialize's block under any policy) writes nothing — the self-heal for a half-configured repo.
|
|
22
|
+
function hideSeededFromGit(wt, seeded) {
|
|
23
|
+
for (const f of seeded) {
|
|
24
|
+
try {
|
|
25
|
+
if (isIgnored(wt, f))
|
|
26
|
+
continue;
|
|
27
|
+
const exclude = join(git(['-C', wt, 'rev-parse', '--path-format=absolute', '--git-common-dir']).trim(), 'info', 'exclude');
|
|
28
|
+
mkdirSync(dirname(exclude), { recursive: true });
|
|
29
|
+
const cur = existsSync(exclude) ? readFileSync(exclude, 'utf8') : '';
|
|
30
|
+
appendFileSync(exclude, `${cur && !cur.endsWith('\n') ? '\n' : ''}${f}\n`);
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
console.error(`spexcode: could not hide seeded ${f} in the shared info/exclude for ${wt} — it will show untracked there (${e})`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function isIgnored(wt, f) {
|
|
38
|
+
try {
|
|
39
|
+
git(['-C', wt, 'check-ignore', '-q', f]);
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
if (e?.status === 1)
|
|
44
|
+
return false; // check-ignore's documented "not ignored" exit
|
|
45
|
+
throw e;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -16,14 +16,14 @@
|
|
|
16
16
|
# session-worktree creation, and the pre-commit/post-checkout/post-merge hooks). .plugins edits are
|
|
17
17
|
# git-transactional: they take effect at the commit/checkout/merge that carries them, like any other source.
|
|
18
18
|
set -u
|
|
19
|
-
# args: `<harness> <Event>`. A harness id as $1 (claude|codex|opencode|pi|plugin) is consumed; otherwise we keep
|
|
19
|
+
# args: `<harness> <Event>`. A harness id as $1 (claude|codex|opencode|pi|zcode|plugin) is consumed; otherwise we keep
|
|
20
20
|
# $1 as the event and default the harness to claude — so a stale shim still written as `dispatch.sh <Event>`
|
|
21
21
|
# keeps working. `plugin` is the bundle form ([[plugin-harness]]), `opencode` the generated event-bus plugin
|
|
22
|
-
# ([[opencode-harness]]),
|
|
23
|
-
# payloads (Claude tool names + file_path), so they join the claude branch in harness.sh via
|
|
24
|
-
# no parse arm of their own.
|
|
22
|
+
# ([[opencode-harness]]), `pi` the generated extension ([[pi-harness]]), and `zcode` the native adapter: all four
|
|
23
|
+
# carry Claude-shaped payloads (Claude tool names + file_path), so they join the claude branch in harness.sh via
|
|
24
|
+
# the default case — no parse arm of their own.
|
|
25
25
|
harness=claude
|
|
26
|
-
case "${1:-}" in claude|codex|opencode|pi|plugin) harness="$1"; shift ;; esac
|
|
26
|
+
case "${1:-}" in claude|codex|opencode|pi|zcode|plugin) harness="$1"; shift ;; esac
|
|
27
27
|
event="${1:?usage: dispatch.sh <harness> <Event>}"
|
|
28
28
|
export SPEXCODE_HARNESS="$harness"
|
|
29
29
|
# the harness.sh path (the adapter's shell mirror) — sibling of this script; hook handlers source it, and we
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# @@@ harness.sh - the SHELL face of the [[harness-adapter]] (spec-cli/src/harness.ts). The hook scripts run
|
|
3
3
|
# as pure shell, so they cannot import the TS adapter; this sourced library is its mirror. dispatch.sh sources
|
|
4
|
-
# it and exports SPEXCODE_HARNESS (claude|codex|opencode) — baked into the shim by each adapter, so a hook learns its
|
|
4
|
+
# it and exports SPEXCODE_HARNESS (claude|codex|opencode|zcode) — baked into the shim by each adapter, so a hook learns its
|
|
5
5
|
# harness deterministically, never by sniffing the payload shape. EVERY harness-divergent payload-parse lives
|
|
6
6
|
# HERE; the hook scripts stay harness-agnostic and just call hp_* (the one place Claude's tool names appear in
|
|
7
7
|
# shell, plus codex's Bash-command mapping). The session-id + global-store resolution is harness-agnostic and
|
|
8
8
|
# lives here too, so the six hooks no longer each repeat the git-common-dir → project-key dance.
|
|
9
|
-
# SPEXCODE_HARNESS is claude|codex|opencode|pi|plugin: `plugin` is the bundle form ([[plugin-harness]]) and its
|
|
10
|
-
# host (
|
|
11
|
-
# `pi`'s generated extension ([[pi-harness]])
|
|
12
|
-
# `case "$SPEXCODE_HARNESS"` below routes all
|
|
9
|
+
# SPEXCODE_HARNESS is claude|codex|opencode|pi|zcode|plugin: `plugin` is the bundle form ([[plugin-harness]]) and its
|
|
10
|
+
# host (adopter-a/Claude) shares Claude's payload shape; `opencode`'s generated plugin ([[opencode-harness]]),
|
|
11
|
+
# `pi`'s generated extension ([[pi-harness]]), and z-code's native hook payload all share that Claude shape — so every
|
|
12
|
+
# `case "$SPEXCODE_HARNESS"` below routes all four through the claude branch via the default case; only codex
|
|
13
13
|
# keeps parse arms of its own.
|
|
14
14
|
|
|
15
15
|
|
|
@@ -68,11 +68,28 @@ hp_field() {
|
|
|
68
68
|
# every child tool call fired mark-active against the PARENT's record — the parent read `working` forever and
|
|
69
69
|
# every park/done declaration was clobbered within seconds (measured). Same staleness class the codex branch
|
|
70
70
|
# already guards against (payload-first below); claude now follows the same rule.
|
|
71
|
+
# The claude preference is RESOLUTION-AWARE, not blind. "Claude's payload id equals its governed record id"
|
|
72
|
+
# holds only while the launched conversation lives: a compaction/continuation MINTS A NEW conversation id
|
|
73
|
+
# while the record keeps the launched one, and a blindly-preferred payload id then resolves to no record at
|
|
74
|
+
# all — hp_store_dir echoes a path nothing sits at, so every record-dependent hook (stop-gate, mark-active,
|
|
75
|
+
# idle, session-fail) silently no-ops and the session reads `working` forever (measured: a live session froze
|
|
76
|
+
# at `active` while its terminal still answered). So the payload wins only when a record actually answers to
|
|
77
|
+
# it, and an unresolvable payload falls back to the launched SPEXCODE_SESSION_ID. This cannot reopen the
|
|
78
|
+
# subagent bug above: a Task subagent's payload carries the PARENT's session_id, which DOES resolve, so the
|
|
79
|
+
# preference is unchanged there — the divergent branch is reached only when the two ids differ AND the
|
|
80
|
+
# payload names nothing. The common path costs one string compare (the ids are equal), never a store read.
|
|
71
81
|
hp_session_id() {
|
|
72
82
|
local pid
|
|
73
83
|
case "$SPEXCODE_HARNESS" in
|
|
74
84
|
codex) hp_field "$1" session_id ;;
|
|
75
|
-
*) pid=$(hp_field "$1" session_id)
|
|
85
|
+
*) pid=$(hp_field "$1" session_id)
|
|
86
|
+
if [ -n "$pid" ] && [ -n "$SPEXCODE_SESSION_ID" ] && [ "$pid" != "$SPEXCODE_SESSION_ID" ] \
|
|
87
|
+
&& [ ! -e "$(hp_store_dir "$pid")/session.json" ] \
|
|
88
|
+
&& [ -e "$(hp_store_dir "$SPEXCODE_SESSION_ID")/session.json" ]; then
|
|
89
|
+
printf '%s' "$SPEXCODE_SESSION_ID"
|
|
90
|
+
else
|
|
91
|
+
printf '%s' "${pid:-$SPEXCODE_SESSION_ID}"
|
|
92
|
+
fi ;;
|
|
76
93
|
esac
|
|
77
94
|
}
|
|
78
95
|
|
|
@@ -91,7 +108,7 @@ hp_is_subagent() {
|
|
|
91
108
|
printf '%s' "${1%%\"tool_input\"*}" | grep -q '"agent_id"[[:space:]]*:' && printf 1
|
|
92
109
|
}
|
|
93
110
|
|
|
94
|
-
# the per-PROJECT GLOBAL runtime dir (mirrors spec-
|
|
111
|
+
# the per-PROJECT GLOBAL runtime dir (mirrors packages/spec-core/src/layout.ts `runtimeRoot`): <store>/projects/<enc>,
|
|
95
112
|
# keyed by the project (dirname of the ABSOLUTE git-common-dir, so the answer is identical from main or any
|
|
96
113
|
# worktree). The per-session dirs and the per-tree materialize slots (hp_tree_dir) live under it.
|
|
97
114
|
# Echoes the dir; returns non-zero (echoing nothing) when git can't resolve, so a caller can `|| exit 0`.
|
|
@@ -129,6 +146,9 @@ hp_store_dir() {
|
|
|
129
146
|
local rd; rd=$(hp_runtime_dir) || return 1
|
|
130
147
|
local direct="$rd/sessions/$1"
|
|
131
148
|
if [ -e "$direct/session.json" ]; then printf '%s' "$direct"; return 0; fi
|
|
149
|
+
# same two-halves-of-absence rule as layout.ts's readAliasedRecordEntry: an id owning a store dir is already
|
|
150
|
+
# one of ours, so its emptiness is settled and the alias grep is the wrong question (and a whole-store scan).
|
|
151
|
+
if [ -d "$direct" ]; then printf '%s' "$direct"; return 0; fi
|
|
132
152
|
local hit
|
|
133
153
|
hit=$(grep -lF "\"harness_session_id\": \"$1\"" "$rd"/sessions/*/session.json 2>/dev/null | head -1)
|
|
134
154
|
[ -n "$hit" ] && { printf '%s' "${hit%/session.json}"; return 0; }
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@spexcode/spec-cli",
|
|
3
|
+
"version": "0.6.5",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "SpexCode CLI + server. The root spexcode package delegates to this compiled package; dashboard assets live in @spexcode/spec-dashboard.",
|
|
6
|
+
"bin": {
|
|
7
|
+
"spex": "bin/spex.mjs"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./dist/index.js",
|
|
11
|
+
"./bin/spex.mjs": "./bin/spex.mjs",
|
|
12
|
+
"./ranker": "./dist/ranker.js",
|
|
13
|
+
"./eval-host": "./dist/eval-host.js",
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"bin",
|
|
18
|
+
"dist",
|
|
19
|
+
"templates",
|
|
20
|
+
"hooks"
|
|
21
|
+
],
|
|
22
|
+
"bundledDependencies": [
|
|
23
|
+
"@spexcode/spec-core",
|
|
24
|
+
"@spexcode/spec-eval",
|
|
25
|
+
"@spexcode/spec-forge"
|
|
26
|
+
],
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "node ../scripts/build-dist.mjs",
|
|
32
|
+
"prepublishOnly": "node ../scripts/release-publish.mjs --from-package-publish",
|
|
33
|
+
"serve": "npm run build && node bin/spex.mjs serve",
|
|
34
|
+
"lint": "npm run build && node bin/spex.mjs spec lint",
|
|
35
|
+
"test": "tsx --import ../scripts/test-home.mjs --test src/*.test.ts"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@spexcode/spec-core": "0.6.5",
|
|
39
|
+
"@spexcode/spec-eval": "0.6.5",
|
|
40
|
+
"@spexcode/spec-forge": "0.6.5"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^20.16.0",
|
|
44
|
+
"tsx": "^4.19.2",
|
|
45
|
+
"typescript": "^5.6.3"
|
|
46
|
+
}
|
|
47
|
+
}
|
package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/commands/supervisor/spec.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: supervisor
|
|
3
|
+
surface: command
|
|
4
|
+
status: active
|
|
5
|
+
hue: 280
|
|
6
|
+
desc: Launch a supervisor agent that manages other agents from the main checkout to drive a goal to completion.
|
|
7
|
+
---
|
|
8
|
+
You are a SpexCode supervisor — a **manager**, not a feature worker. Your work base is the main checkout (the repository root), NOT your own worktree: do all git via `git -C <root>`, everything else via the `spex` CLI, and never write feature code. This preset IS your complete playbook (dispatch → monitor → review → merge → close, and how to parallelize) — the CLI's own `spex help session` is the reference for every verb's exact semantics. Drive the goal: decompose it into worker-sized tasks and dispatch one worker per independent task (`spex session new "<task>"` creates the parent-child relation and automatically installs your managed `parent` watch; inspect that existing relation/source with `spex session watch list`, so do NOT add a manual watch for this child — give it ONLY its task; a task about one specific node mentions it as `[[<id>]]`, which only sets the branch name and board attribution; the session's real node links come from what it edits), review proposals with `spex session review <id>`, dispatch the merge of good ones back to their own session (`spex session merge <id>`; the doer syncs the base into its own worktree first, so what reaches `<root>` is a trivial merge) and confirm it landed, then close. `<root>` is the fleet's ONE landing door — it takes one landing at a time, so a worker whose merge finds it mid-merge waits rather than racing, and you never fix up another lane's half-merged index yourself. Never let a worker self-merge; keep `spex spec lint` at 0 errors. To READ a worker's current state, use the one-shot snapshots (`spex session review <id>` or `spex session ls` — both return immediately); for a local next-lifecycle-edge read when no managed delivery exists, background `spex session wait <id>` — it returns only when it OBSERVES the worker transition from non-actionable into an actionable status (an already-actionable arrival state does not return it), printing the observed status path; `spex session watch stream` is human-only and STREAMS forever, so never block on it. **Stay parked while your fleet runs:** `spex session new`'s managed watch delivery is a real wake-up, so park while it exists. A manual `spex session watch <id>` is deliberate ongoing supervision of an existing session, not a one-off wait: it adds your `manual` source, and every future AUTHORED state transition is queued as a message to the watcher until `spex session watch cancel <id>` removes that source. That creates continuing traffic/noise, so use manual watch only when you want that consequence; `watch list` inspects the relation/source and `watch cancel` removes only the manual source. An `@<session>` explanation request is point-to-point: use `spex session send <id> "<question>"`; the reply hint returns over send, never watch/wait. Only go `asking` when you genuinely need the human. This matters because the dashboard **folds each child under you and shows YOUR own status for the whole group** (session-nesting, no child-status aggregation), so a supervisor that stays parked-while-they-run is what makes that folded group status honest. Two footguns that bite a fresh supervisor. First: before `spex session close <id>`, confirm the merge landed (`git -C <root> log -1` shows HEAD at the new merge commit) — closing an unmerged branch discards the work. Second: `<id>` always names a WORKER YOU DISPATCHED, spelled out — never `.` and never your own id. `.` means the session running the command, so `close .` deletes your own worktree, branch and record mid-turn and takes your fleet's manager down with it; your own ending is a declaration (`done --propose close`), never a close you run on yourself. **DRAIN THE ISSUES** (issues / local-issues) as part of your loop: `spex issue ls` lists every open concern in one place — the taste concerns finished sessions recorded locally, AND the forge's issues, store-tagged. Cluster the same concern yourself (use judgment — duplicates are a recurrence SIGNAL, not noise; fold them into one) and weigh by recurrence AND novelty — **recurrence is salience, not importance, so never just fix the highest count**: a sharp single-voice concern can outrank a popular gripe. For the ones worth acting on, `spex session new "<task>"` a worker to land it (mention the concern's node as `[[<id>]]` if it has one), then `spex issue ls resolve <id> --as accepted|landed` (or `rejected`, with a reply saying why) so the store reflects the decision. Report progress as you go and when the goal is complete. Your goal follows:
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: comment-altitude
|
|
3
|
+
surface: system
|
|
4
|
+
status: active
|
|
5
|
+
hue: 200
|
|
6
|
+
desc: A config plugin — code comments navigate non-obvious local reasoning; specs own product intent and contract.
|
|
7
|
+
---
|
|
8
|
+
Specs own intent, invariants, policy, and observable contracts. Comments only navigate non-obvious local decisions.
|
|
9
|
+
`spex guide spec` has the comment-altitude details.
|
|
@@ -37,7 +37,7 @@ EOF
|
|
|
37
37
|
[ -n "$owner" ] || exit 0
|
|
38
38
|
|
|
39
39
|
mkdir -p "$sdir"; : > "$sent"
|
|
40
|
-
reason
|
|
40
|
+
reason=$($S internal hook-prompt spec-first --path "$path" --owner "$owner") || exit 1
|
|
41
41
|
esc=$(printf '%s' "$reason" | sed 's/\\/\\\\/g; s/"/\\"/g' | awk 'BEGIN{ORS=""} NR>1{print "\\n"} {print}')
|
|
42
42
|
printf '{"decision":"block","reason":"%s"}\n' "$esc"
|
|
43
43
|
exit 0
|
|
@@ -60,6 +60,7 @@ done <<EOF
|
|
|
60
60
|
$paths
|
|
61
61
|
EOF
|
|
62
62
|
[ -n "$msg" ] || exit 0
|
|
63
|
+
msg=$($S internal hook-prompt spec-of-file --details "$msg") || exit 1
|
|
63
64
|
esc=$(printf '%s' "$msg" | sed 's/\\/\\\\/g; s/"/\\"/g' | awk 'BEGIN{ORS=""} NR>1{print "\\n"} {print}')
|
|
64
65
|
printf '{"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"%s"}}\n' "$esc"
|
|
65
66
|
exit 0
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: core
|
|
3
|
+
surface: system
|
|
4
|
+
status: active
|
|
5
|
+
hue: 200
|
|
6
|
+
desc: A config plugin — the minimal spec-discipline contract folded into every launched agent.
|
|
7
|
+
code:
|
|
8
|
+
---
|
|
9
|
+
Use noun-first CLI commands; `spex help` is the authoritative command map.
|
|
10
|
+
|
|
11
|
+
Anything a human needs to inspect, whether a file or a local webpage, goes out through `spex session files add` or
|
|
12
|
+
`spex session web add`: never paste an absolute path or `host:port`, and never start a static server yourself.
|
|
13
|
+
|
|
14
|
+
When this session has a clearly running child session (`active` or `parked`), the parent is supervising rather
|
|
15
|
+
than finished: declare `park`, not `done`/`awaiting`, until the child reports a settled state.
|
|
16
|
+
|
|
17
|
+
1. **Spec first:** before governed code, read its spec body with `spex spec owner <path>` or `spex spec search`.
|
|
18
|
+
Update that current-state body with any changed intent.
|
|
19
|
+
2. **Commit before declare:** commit the code and spec it justifies before done or merge; independent intent gets
|
|
20
|
+
its own node.
|
|
21
|
+
3. **Keep the loss signal honest:** run `spex spec lint` (the blocking correctness gate) and `spex eval lint --changed`. Measure changed scenarios
|
|
22
|
+
through the real product, commit the verified tree, then file with `spex eval add`; the reading's `codeSha` must name that commit.
|
|
@@ -10,9 +10,9 @@ block: true
|
|
|
10
10
|
---
|
|
11
11
|
The blocking stop gate, with two jobs, each holding a hard loop-break so it never blocks twice on the same cause and never lets a dishonest stop through.
|
|
12
12
|
|
|
13
|
-
The COMMIT gate keeps a done/merge proposal honest: such a proposal is rejected while the branch still carries uncommitted work or is zero commits ahead of main, because the ritual commits the spec and code BEFORE proposing. Clean work is allowed to stop; a dirty proposal blocks once with the reason, and if the agent ignores it the gate escapes by downgrading to `asking` so a false "ready to merge" can never stand.
|
|
13
|
+
The COMMIT gate keeps a done/merge proposal honest: such a proposal is rejected while the branch still carries uncommitted work or is zero commits ahead of main, because the ritual commits the spec and code BEFORE proposing. Clean work is allowed to stop; a dirty proposal blocks once with the reason, and if the agent ignores it the gate escapes by downgrading to `asking` so a false "ready to merge" can never stand. `done --propose nothing` is a porcelain trap, not a declaration: it writes no state and names merge, close, ask, and park as the real destinations; legacy `nothing` records remain readable.
|
|
14
14
|
|
|
15
|
-
The DECLARE gate refuses to let a session stop in an undeclared `active` state, since a state is a claim the board and other agents act on, not a box ticked to end a turn. A declared state stops freely; an undeclared first stop emits `{"decision":"block"}` and the dispatcher exits 2 so the harness actually interrupts the stop and shows the reason; on the forced continuation it
|
|
15
|
+
The DECLARE gate refuses to let a session stop in an undeclared `active` state, since a state is a claim the board and other agents act on, not a box ticked to end a turn. A declared state stops freely; an undeclared first stop emits `{"decision":"block"}` and the dispatcher exits 2 so the harness actually interrupts the stop and shows the reason; on the forced continuation it declares `asking`, so the loop is guaranteed to end without inventing a completion state. state owns the choice: a posted file or web artifact, a reported finding/recommendation awaiting a human decision, or any handoff awaiting human direction selects `asking`; `close-pending` requires genuinely settled work with no such outstanding decision or follow-up.
|
|
16
16
|
|
|
17
17
|
The block text is where the declaration ritual is taught, so it is written to be read at two depths. The FULL teaching text prints once per session: it names the PATH-independent CLI once as a shared prefix, lists the five choices as a compact menu each with its application condition (park policed hardest — a false park is the most damaging mislabel). A real wake source is either a background job or a managed session-follow subscription whose normal send delivery will re-enter the parent; a caller without that address must still arm background `session wait`. It ends with the ordering discipline: declare LAST, then stop — a declaration followed by more tool calls honestly re-flips the record to active ([[mark-active]], by design), so making the declaration the turn's final call is what eliminates the park→block→re-park loop at its source. Every later undeclared stop in the same session gets a ONE-LINE version instead (a heavy session hits the gate 15-20 times a night; re-printing the full menu is token noise). The once-sentinel is a plain file beside the session record in the global store — the same per-session-sentinel mechanism as the CLI's note-truncation notice, never a second scheme. The terse line stays self-explanatory: it carries the command menu, the declare-LAST reminder, and the `spex help session` recovery entry, so an agent that never saw the full text (a compacted context) recovers every choice's condition from the entry rather than from memory — the whole full-to-terse information gap is closable from the line itself.
|
|
18
18
|
|