spexcode 0.6.2 → 0.6.6
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 +3 -1
- package/bin/spex.mjs +4 -0
- package/node_modules/@spexcode/session-core/dist/delivery-queue.d.ts +23 -0
- package/node_modules/@spexcode/session-core/dist/delivery-queue.js +195 -0
- package/node_modules/@spexcode/session-core/dist/index.d.ts +5 -0
- package/node_modules/@spexcode/session-core/dist/index.js +5 -0
- package/node_modules/@spexcode/session-core/dist/internal.d.ts +3 -0
- package/node_modules/@spexcode/session-core/dist/internal.js +3 -0
- package/node_modules/@spexcode/session-core/dist/message.d.ts +22 -0
- package/node_modules/@spexcode/session-core/dist/message.js +52 -0
- package/node_modules/@spexcode/session-core/dist/record-lock.d.ts +7 -0
- package/node_modules/@spexcode/session-core/dist/record-lock.js +152 -0
- package/node_modules/@spexcode/session-core/dist/runtime-session.d.ts +50 -0
- package/node_modules/@spexcode/session-core/dist/runtime-session.js +286 -0
- package/node_modules/@spexcode/session-core/dist/session-cursors.d.ts +14 -0
- package/node_modules/@spexcode/session-core/dist/session-cursors.js +82 -0
- package/node_modules/@spexcode/session-core/dist/session-timeline.d.ts +46 -0
- package/node_modules/@spexcode/session-core/dist/session-timeline.js +216 -0
- package/node_modules/@spexcode/session-core/package.json +33 -0
- package/node_modules/@spexcode/spec-cli/bin/spex.mjs +77 -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 +36 -0
- package/node_modules/@spexcode/spec-cli/dist/claude-headless.js +316 -0
- package/node_modules/@spexcode/spec-cli/dist/cli.d.ts +1 -0
- package/node_modules/@spexcode/spec-cli/dist/cli.js +1908 -0
- package/node_modules/@spexcode/spec-cli/dist/client.d.ts +112 -0
- package/node_modules/@spexcode/spec-cli/dist/client.js +481 -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 +58 -0
- package/node_modules/@spexcode/spec-cli/dist/codex-runtime-generations.js +798 -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/doctor.d.ts +9 -0
- package/node_modules/@spexcode/spec-cli/dist/doctor.js +553 -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 +363 -0
- package/node_modules/@spexcode/spec-cli/dist/gateway.d.ts +38 -0
- package/node_modules/@spexcode/spec-cli/dist/gateway.js +527 -0
- package/node_modules/@spexcode/spec-cli/dist/graphCache.d.ts +27 -0
- package/node_modules/@spexcode/spec-cli/dist/graphCache.js +717 -0
- package/node_modules/@spexcode/spec-cli/dist/graphSnapshot.d.ts +14 -0
- package/node_modules/@spexcode/spec-cli/dist/graphSnapshot.js +36 -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} +36 -32
- 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 +338 -0
- package/node_modules/@spexcode/spec-cli/dist/harness.js +3146 -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 +15 -0
- package/node_modules/@spexcode/spec-cli/dist/help.js +594 -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 +8 -0
- package/node_modules/@spexcode/spec-cli/dist/listen.js +24 -0
- 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 +5 -0
- package/node_modules/@spexcode/spec-cli/dist/opencode-headless.js +215 -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/runtime-rotate.d.ts +1 -0
- package/node_modules/@spexcode/spec-cli/dist/runtime-rotate.js +58 -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-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 +11 -0
- package/node_modules/@spexcode/spec-cli/dist/session-timeline.js +20 -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 +433 -0
- package/node_modules/@spexcode/spec-cli/dist/sessions.js +4667 -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 +1 -1
- package/node_modules/@spexcode/spec-cli/package.json +49 -0
- package/node_modules/@spexcode/spec-cli/templates/spec/project/.plugins/commands/supervisor/spec.md +8 -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/{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-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 +170 -0
- package/node_modules/@spexcode/spec-core/dist/git.js +2768 -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 +187 -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 -728
- package/spec-cli/src/attach.ts +0 -43
- package/spec-cli/src/claude-headless.ts +0 -321
- package/spec-cli/src/cli.ts +0 -1258
- package/spec-cli/src/client.ts +0 -414
- 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 -165
- package/spec-cli/src/doctor.ts +0 -516
- package/spec-cli/src/execution-trace.ts +0 -444
- 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 -358
- package/spec-cli/src/gateway.ts +0 -461
- package/spec-cli/src/git.ts +0 -2556
- package/spec-cli/src/graph.ts +0 -271
- package/spec-cli/src/graphCache.ts +0 -710
- 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 -3025
- package/spec-cli/src/headless-controller.ts +0 -63
- package/spec-cli/src/help.ts +0 -492
- package/spec-cli/src/host-resources.ts +0 -762
- 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 -138
- package/spec-cli/src/index.ts +0 -818
- 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 -640
- package/spec-cli/src/lint.ts +0 -488
- package/spec-cli/src/listen.ts +0 -28
- package/spec-cli/src/localIssues.ts +0 -538
- package/spec-cli/src/materialize.ts +0 -417
- 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 -434
- 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-execution.ts +0 -68
- package/spec-cli/src/session-files.ts +0 -121
- package/spec-cli/src/session-follow.ts +0 -182
- package/spec-cli/src/session-reparent.ts +0 -33
- package/spec-cli/src/session-timeline.ts +0 -247
- package/spec-cli/src/session-web.ts +0 -135
- package/spec-cli/src/sessions.ts +0 -3883
- 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-dashboard/dist/assets/App-B6IbFbGu.js +0 -2
- package/spec-dashboard/dist/assets/Dashboard-C5ap-Sga.css +0 -1
- package/spec-dashboard/dist/assets/Dashboard-_sDk7Rcg.js +0 -27
- package/spec-dashboard/dist/assets/EvalsPage-BT357Lyt.js +0 -2
- package/spec-dashboard/dist/assets/IssuesPage-BG9rNOgV.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-D9yPMR3A.js +0 -2
- package/spec-dashboard/dist/assets/Modal-B3EcgeA3.js +0 -1
- package/spec-dashboard/dist/assets/PageScroll-CNZOugWV.js +0 -1
- package/spec-dashboard/dist/assets/ProjectsPage-C2CRHmvs.js +0 -1
- package/spec-dashboard/dist/assets/SessionInterface-6GBZ9nXN.css +0 -32
- package/spec-dashboard/dist/assets/SessionInterface-DOEjuT3l.js +0 -40
- package/spec-dashboard/dist/assets/SessionWindow-1nYgZ4CL.js +0 -1
- package/spec-dashboard/dist/assets/Settings-7WeTJn0V.js +0 -1
- package/spec-dashboard/dist/assets/Thread-CEbzAFQn.js +0 -13
- package/spec-dashboard/dist/assets/bindings-BC9vqpYU.js +0 -1
- package/spec-dashboard/dist/assets/data-SlvxNA2r.js +0 -1
- package/spec-dashboard/dist/assets/index-DLVeOHL-.js +0 -41
- package/spec-dashboard/dist/assets/index-DYLGfPjx.css +0 -1
- package/spec-dashboard/dist/assets/launch-Cp579UoJ.css +0 -1
- package/spec-dashboard/dist/assets/launch-yxCYr64x.js +0 -276
- package/spec-dashboard/dist/assets/sessionSurface--7l69h4F.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 -894
- package/spec-eval/src/evaltab.ts +0 -264
- package/spec-eval/src/filing.ts +0 -39
- package/spec-eval/src/freshness.ts +0 -836
- 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 -2220
- 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/comment-altitude/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/core/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/atomic-landing/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/forge-link/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/memory-hygiene/spec.md +0 -0
- /package/{spec-cli → node_modules/@spexcode/spec-cli}/templates/spec/project/.plugins/prompts/reproduce-before-fix/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
|
|
@@ -108,7 +108,7 @@ hp_is_subagent() {
|
|
|
108
108
|
printf '%s' "${1%%\"tool_input\"*}" | grep -q '"agent_id"[[:space:]]*:' && printf 1
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
# 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>,
|
|
112
112
|
# keyed by the project (dirname of the ABSOLUTE git-common-dir, so the answer is identical from main or any
|
|
113
113
|
# worktree). The per-session dirs and the per-tree materialize slots (hp_tree_dir) live under it.
|
|
114
114
|
# Echoes the dir; returns non-zero (echoing nothing) when git can't resolve, so a caller can `|| exit 0`.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@spexcode/spec-cli",
|
|
3
|
+
"version": "0.6.6",
|
|
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/session-core",
|
|
25
|
+
"@spexcode/spec-eval",
|
|
26
|
+
"@spexcode/spec-forge"
|
|
27
|
+
],
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "node ../scripts/build-dist.mjs",
|
|
33
|
+
"prepublishOnly": "node ../scripts/release-publish.mjs --from-package-publish",
|
|
34
|
+
"serve": "npm run build && node bin/spex.mjs serve",
|
|
35
|
+
"lint": "npm run build && node bin/spex.mjs spec lint",
|
|
36
|
+
"test": "tsx --import ../scripts/test-home.mjs --test src/*.test.ts"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@spexcode/session-core": "0.6.6",
|
|
40
|
+
"@spexcode/spec-core": "0.6.6",
|
|
41
|
+
"@spexcode/spec-eval": "0.6.6",
|
|
42
|
+
"@spexcode/spec-forge": "0.6.6"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^20.16.0",
|
|
46
|
+
"tsx": "^4.19.2",
|
|
47
|
+
"typescript": "^5.6.3"
|
|
48
|
+
}
|
|
49
|
+
}
|
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:
|
|
@@ -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
|
|
@@ -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
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# @@@ stop-gate - a blocking Stop hook with TWO jobs, each with a HARD loop-break (never blocks more than
|
|
3
3
|
# once on the same cause, never leaks a dishonest stop):
|
|
4
|
-
# (A) COMMIT GATE — a done/merge proposal (awaiting + merge
|
|
4
|
+
# (A) COMMIT GATE — a done/merge proposal (awaiting + merge; legacy nothing remains readable) is rejected while the node branch has
|
|
5
5
|
# uncommitted work or 0 commits ahead of main; the dogfood ritual commits BEFORE proposing. Clean ->
|
|
6
6
|
# allow; dirty -> block once with the reason, escape on the continuation to `asking` (needs the human).
|
|
7
7
|
# (B) DECLARE GATE — a session may not stop in an undeclared (`active`) state:
|
|
8
8
|
# declared (awaiting/parked/error/asking) . allow (the agent reported; nothing to do)
|
|
9
9
|
# active, first stop (stop_hook_active false) .. block ONCE — instruct the agent to declare
|
|
10
|
-
# active, the continuation (stop_hook_active true) auto-declare
|
|
11
|
-
#
|
|
10
|
+
# active, the continuation (stop_hook_active true) auto-declare `asking` and allow. Guaranteed to end
|
|
11
|
+
# without inventing a completion state.
|
|
12
12
|
# $SPEX is the PATH-independent CLI invocation (abs tsx + cli) injected by settingsArg, so the gate's own
|
|
13
13
|
# auto-default AND the command it shows the agent both work even when `spex` is absent from PATH.
|
|
14
14
|
# @@@ global store + governed gate - state lives in the per-session GLOBAL record session.json (keyed by the
|
|
@@ -65,12 +65,13 @@ eval_advisory() {
|
|
|
65
65
|
n=$(printf '%s\n' "$out" | grep -cE 'eval-(drift|missing|coverage):')
|
|
66
66
|
[ "${n:-0}" -gt 0 ] || return 0 # no gap in what you changed (or eval lint unavailable) -> nothing to nudge
|
|
67
67
|
ids=$(printf '%s\n' "$out" | sed -n "s/.*eval-[a-z]*: '\([^']*\)'.*/\1/p" | awk '!seen[$0]++' | head -6 | paste -sd' ' -)
|
|
68
|
-
msg
|
|
68
|
+
msg=$($S internal hook-prompt stop-gate --variant eval --count "$n" --ids "$ids") || return 0
|
|
69
69
|
esc=$(printf '%s' "$msg" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
|
70
70
|
printf '{"hookSpecificOutput":{"hookEventName":"Stop","additionalContext":"%s"}}\n' "$esc"
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
# @@@ commit gate - a declaration of done/merge (awaiting + proposal merge
|
|
73
|
+
# @@@ commit gate - a declaration of done/merge (awaiting + proposal merge; legacy nothing is accepted only
|
|
74
|
+
# for backward-readable records) is only honest once the
|
|
74
75
|
# node branch carries the work as COMMITS: the dogfood ritual commits spec+code BEFORE any proposal, yet a
|
|
75
76
|
# dashboard-launched agent kept proposing merge with 0 commits / a dirty tree. So before allowing such a
|
|
76
77
|
# declaration we run the deterministic check (`spex internal commit-gate`, which goes through git.ts's git()
|
|
@@ -79,8 +80,8 @@ eval_advisory() {
|
|
|
79
80
|
# it) escape the loop by downgrading to `asking` (needs the human) with a clear note, so a FALSE "ready to
|
|
80
81
|
# merge" never stands. (A propose-close declaration is exempt — it discards the worktree, so commits are moot.)
|
|
81
82
|
# The PROPOSAL rides into the check: `merge` claims there is committed work to land (so 0-ahead blocks too),
|
|
82
|
-
#
|
|
83
|
-
#
|
|
83
|
+
# New public `done --propose nothing` calls trap before this hook; keep its legacy branch so historic records
|
|
84
|
+
# stop normally instead of becoming corrupt.
|
|
84
85
|
if [ "${status:-active}" = awaiting ] && { [ "$proposal" = merge ] || [ "$proposal" = nothing ]; }; then
|
|
85
86
|
if gatemsg=$($S internal commit-gate "$proposal" 2>&1); then
|
|
86
87
|
# nudge ONCE: emit on the natural stop, but STAY SILENT on the forced re-stop the additionalContext
|
|
@@ -93,28 +94,19 @@ if [ "${status:-active}" = awaiting ] && { [ "$proposal" = merge ] || [ "$propos
|
|
|
93
94
|
$S session ask --session "$sid" --note "stopped with uncommitted work — commit your spec+code on the node branch, then re-declare done" >/dev/null 2>&1 || true
|
|
94
95
|
exit 0
|
|
95
96
|
fi
|
|
96
|
-
|
|
97
|
-
printf '
|
|
97
|
+
reason=$($S internal hook-prompt stop-gate --variant commit --reason "$gatemsg" --cli "$S" --propose "$proposal") || exit 1
|
|
98
|
+
esc=$(printf '%s' "$reason" | sed 's/[\\"]/\\&/g')
|
|
99
|
+
printf '{"decision":"block","reason":"%s"}\n' "$esc"
|
|
98
100
|
exit 0
|
|
99
101
|
fi
|
|
100
102
|
|
|
101
|
-
#
|
|
103
|
+
# Any other declared state (parked / error / asking / awaiting+close, plus legacy awaiting+nothing) stops.
|
|
102
104
|
[ "${status:-active}" != "active" ] && exit 0
|
|
103
105
|
|
|
104
106
|
if [ "$cont" = true ]; then
|
|
105
|
-
#
|
|
106
|
-
#
|
|
107
|
-
|
|
108
|
-
# IS `nothing`, so it is judged as `nothing` — an already-merged lane defaults honestly instead of being
|
|
109
|
-
# pushed to `asking` for having nothing left ahead of main.
|
|
110
|
-
if $S internal commit-gate nothing >/dev/null 2>&1; then
|
|
111
|
-
$S internal session-state awaiting --session "$sid" --propose nothing --note "auto: stopped without declaring" >/dev/null 2>&1 || true
|
|
112
|
-
# NOTE: no eval nudge on the auto-declare path. It only runs on the forced continuation (cont=true),
|
|
113
|
-
# where a guarded advisory could never fire anyway, and an unguarded one was a second loop vector (a
|
|
114
|
-
# mark-active tool call could re-enter this branch). The clean-done path above is the single nudge site.
|
|
115
|
-
else
|
|
116
|
-
$S session ask --session "$sid" --note "auto: stopped without declaring and with uncommitted work — commit your spec+code on the node branch, then declare" >/dev/null 2>&1 || true
|
|
117
|
-
fi
|
|
107
|
+
# The forced continuation also stopped without declaring. Escape into asking: no default may invent a
|
|
108
|
+
# completed lane, and the stopped agent now needs a human prompt to choose merge, close, ask, or park.
|
|
109
|
+
$S session ask --session "$sid" --note "auto: stopped without declaring — choose merge, close, ask, or park; done --propose nothing records no state" >/dev/null 2>&1 || true
|
|
118
110
|
exit 0
|
|
119
111
|
fi
|
|
120
112
|
|
|
@@ -129,19 +121,29 @@ fi
|
|
|
129
121
|
# of the full-to-terse information gap is recoverable from the entry, none of it from memory.
|
|
130
122
|
taught="$sdir/stop-gate-taught"
|
|
131
123
|
if [ -f "$taught" ]; then
|
|
132
|
-
|
|
124
|
+
reason=$($S internal hook-prompt stop-gate --variant terse --cli "$S") || exit 1
|
|
125
|
+
esc=$(printf '%s' "$reason" | sed 's/[\\"]/\\&/g')
|
|
126
|
+
printf '{"decision":"block","reason":"%s"}\n' "$esc"
|
|
133
127
|
exit 0
|
|
134
128
|
fi
|
|
135
129
|
touch "$taught" 2>/dev/null || true
|
|
136
130
|
# The full reason names the PATH-independent CLI ($S) ONCE as a shared `<CLI> session <choice>` prefix, then
|
|
137
|
-
# lists the
|
|
138
|
-
# instead of repeating the long abs path per option. It EMPHASIZES that each
|
|
139
|
-
# (not a box to tick to end the turn) and gives the precise APPLICATION CONDITION
|
|
140
|
-
# picks the TRUE one. park is policed hardest because a false park (no real background task) reads on the
|
|
131
|
+
# lists the four real states plus the `nothing` trap as a compact newline menu of bare subcommands — so the
|
|
132
|
+
# terminal output stays legible instead of repeating the long abs path per option. It EMPHASIZES that each
|
|
133
|
+
# state is a CLAIM others act on (not a box to tick to end the turn) and gives the precise APPLICATION CONDITION
|
|
134
|
+
# for each — so the agent picks the TRUE one. park is policed hardest because a false park (no real background task) reads on the
|
|
141
135
|
# board as "fine, self-resuming" when the agent actually needs the human, which is the most damaging mislabel.
|
|
142
136
|
# It ends with the ORDERING discipline — declare LAST, then stop — because a declaration followed by more
|
|
143
137
|
# tool calls honestly re-flips the record to active (mark-active, by design) and re-blocks the next stop;
|
|
144
138
|
# this block text is the one place every undeclared stopper is guaranteed to read, so the teaching that
|
|
145
139
|
# kills the park->block->re-park loop at its source lives here.
|
|
146
|
-
|
|
140
|
+
if [ -s "$sdir/files.json" ] && grep -qE '"[^"]+"' "$sdir/files.json"; then
|
|
141
|
+
reason=$($S internal hook-prompt stop-gate --variant artifact) || exit 1
|
|
142
|
+
esc=$(printf '%s' "$reason" | sed 's/[\\"]/\\&/g')
|
|
143
|
+
printf '{"decision":"block","reason":"%s"}\n' "$esc"
|
|
144
|
+
exit 0
|
|
145
|
+
fi
|
|
146
|
+
reason=$($S internal hook-prompt stop-gate --variant full --cli "$S") || exit 1
|
|
147
|
+
esc=$(printf '%s' "$reason" | sed 's/\\/\\\\/g; s/"/\\"/g' | awk 'BEGIN{ORS=""} NR>1{print "\\n"} {print}')
|
|
148
|
+
printf '{"decision":"block","reason":"%s"}\n' "$esc"
|
|
147
149
|
exit 0
|