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
package/spec-cli/src/uploads.ts
DELETED
|
@@ -1,253 +0,0 @@
|
|
|
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 type { ReadableStream as NodeReadableStream } from 'node:stream/web'
|
|
8
|
-
import { repoRoot } from './git.js'
|
|
9
|
-
import { readUploadPolicy, type UploadPolicy } from './layout.js'
|
|
10
|
-
|
|
11
|
-
// The backend's tmpdir is the worker's filesystem. Completed files stay directly under this sink; private
|
|
12
|
-
// metadata and partial bytes live below .staging until an exact-length transfer is promoted atomically.
|
|
13
|
-
const UPLOAD_DIR = join(tmpdir(), 'spexcode-uploads')
|
|
14
|
-
const STAGING_DIR = join(UPLOAD_DIR, '.staging')
|
|
15
|
-
|
|
16
|
-
type UploadMeta = {
|
|
17
|
-
version: 1
|
|
18
|
-
id: string
|
|
19
|
-
name: string
|
|
20
|
-
size: number
|
|
21
|
-
offset: number
|
|
22
|
-
createdAt: number
|
|
23
|
-
updatedAt: number
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export type UploadStatus = Pick<UploadMeta, 'id' | 'name' | 'size' | 'offset'> & Pick<UploadPolicy,
|
|
27
|
-
'chunkBytes' | 'concurrency' | 'requestTimeoutMs' | 'retryLimit' | 'retryDelayMs'>
|
|
28
|
-
|
|
29
|
-
export class UploadError extends Error {
|
|
30
|
-
constructor(readonly status: number, message: string, readonly offset?: number) {
|
|
31
|
-
super(message)
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const uploadPolicy = (): UploadPolicy => readUploadPolicy(repoRoot())
|
|
36
|
-
|
|
37
|
-
export const evidenceMaxBytes = (): number => uploadPolicy().evidenceMaxBytes
|
|
38
|
-
|
|
39
|
-
function ensureDirs(): void {
|
|
40
|
-
mkdirSync(STAGING_DIR, { recursive: true })
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function safeName(name: string): string {
|
|
44
|
-
const base = basename(name || '').replace(/[^A-Za-z0-9._-]/g, '_').replace(/^\.+/, '')
|
|
45
|
-
return base || 'upload'
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function validId(id: string): boolean {
|
|
49
|
-
return /^[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i.test(id)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function metaPath(id: string): string {
|
|
53
|
-
return join(STAGING_DIR, `${id}.json`)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function partPath(id: string): string {
|
|
57
|
-
return join(STAGING_DIR, `${id}.part`)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function removeTransfer(id: string): void {
|
|
61
|
-
rmSync(metaPath(id), { force: true })
|
|
62
|
-
rmSync(partPath(id), { force: true })
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function readMetaFile(id: string): UploadMeta | null {
|
|
66
|
-
if (!validId(id)) return null
|
|
67
|
-
try {
|
|
68
|
-
const meta = JSON.parse(readFileSync(metaPath(id), 'utf8')) as UploadMeta
|
|
69
|
-
if (meta.version !== 1 || meta.id !== id || typeof meta.name !== 'string' ||
|
|
70
|
-
!Number.isSafeInteger(meta.size) || meta.size <= 0 ||
|
|
71
|
-
!Number.isSafeInteger(meta.offset) || meta.offset < 0 || meta.offset > meta.size ||
|
|
72
|
-
!Number.isSafeInteger(meta.createdAt) || !Number.isSafeInteger(meta.updatedAt)) return null
|
|
73
|
-
return meta
|
|
74
|
-
} catch {
|
|
75
|
-
return null
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function writeMeta(meta: UploadMeta): void {
|
|
80
|
-
const path = metaPath(meta.id)
|
|
81
|
-
const temp = `${path}.${process.pid}.${randomUUID()}.tmp`
|
|
82
|
-
writeFileSync(temp, JSON.stringify(meta) + '\n')
|
|
83
|
-
renameSync(temp, path)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function actualOffset(meta: UploadMeta): number {
|
|
87
|
-
try {
|
|
88
|
-
return statSync(partPath(meta.id)).size
|
|
89
|
-
} catch {
|
|
90
|
-
return 0
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function status(meta: UploadMeta, policy: UploadPolicy): UploadStatus {
|
|
95
|
-
const { chunkBytes, concurrency, requestTimeoutMs, retryLimit, retryDelayMs } = policy
|
|
96
|
-
return { id: meta.id, name: meta.name, size: meta.size, offset: meta.offset, chunkBytes, concurrency, requestTimeoutMs, retryLimit, retryDelayMs }
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function syncOffset(meta: UploadMeta): UploadMeta {
|
|
100
|
-
const offset = actualOffset(meta)
|
|
101
|
-
if (offset > meta.size) throw new UploadError(409, 'upload staging file exceeds its declared length')
|
|
102
|
-
if (offset !== meta.offset) {
|
|
103
|
-
meta.offset = offset
|
|
104
|
-
meta.updatedAt = Date.now()
|
|
105
|
-
writeMeta(meta)
|
|
106
|
-
}
|
|
107
|
-
return meta
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function loadUpload(id: string, policy: UploadPolicy): UploadMeta {
|
|
111
|
-
const meta = readMetaFile(id)
|
|
112
|
-
if (!meta) throw new UploadError(404, 'upload not found')
|
|
113
|
-
if (Date.now() - meta.updatedAt > policy.incompleteTtlMs) {
|
|
114
|
-
removeTransfer(id)
|
|
115
|
-
throw new UploadError(404, 'upload expired')
|
|
116
|
-
}
|
|
117
|
-
return syncOffset(meta)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function reservedBytes(policy: UploadPolicy): number {
|
|
121
|
-
let total = 0
|
|
122
|
-
for (const entry of readdirSync(STAGING_DIR, { withFileTypes: true })) {
|
|
123
|
-
if (!entry.isFile() || !entry.name.endsWith('.json')) continue
|
|
124
|
-
const meta = readMetaFile(entry.name.slice(0, -5))
|
|
125
|
-
if (!meta || Date.now() - meta.updatedAt > policy.incompleteTtlMs) continue
|
|
126
|
-
total += Math.max(0, meta.size - actualOffset(meta))
|
|
127
|
-
}
|
|
128
|
-
return total
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function reserveCapacity(size: number, policy: UploadPolicy): void {
|
|
132
|
-
let available = 0
|
|
133
|
-
try {
|
|
134
|
-
const fs = statfsSync(UPLOAD_DIR)
|
|
135
|
-
available = Number(fs.bavail) * Number(fs.bsize)
|
|
136
|
-
} catch {
|
|
137
|
-
// A filesystem that cannot report capacity will still fail loudly during the stream write.
|
|
138
|
-
return
|
|
139
|
-
}
|
|
140
|
-
if (size > Math.max(0, available - policy.minFreeBytes - reservedBytes(policy))) {
|
|
141
|
-
throw new UploadError(507, 'insufficient backend disk capacity for this upload')
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export function cleanupExpiredUploads(policy = uploadPolicy()): void {
|
|
146
|
-
ensureDirs()
|
|
147
|
-
const now = Date.now()
|
|
148
|
-
for (const entry of readdirSync(STAGING_DIR, { withFileTypes: true })) {
|
|
149
|
-
if (!entry.isFile() || !entry.name.endsWith('.json')) continue
|
|
150
|
-
const id = entry.name.slice(0, -5)
|
|
151
|
-
const meta = readMetaFile(id)
|
|
152
|
-
if (!meta || now - meta.updatedAt > policy.incompleteTtlMs) removeTransfer(id)
|
|
153
|
-
}
|
|
154
|
-
for (const entry of readdirSync(STAGING_DIR, { withFileTypes: true })) {
|
|
155
|
-
if (!entry.isFile() || !entry.name.endsWith('.part')) continue
|
|
156
|
-
const id = entry.name.slice(0, -5)
|
|
157
|
-
if (readMetaFile(id)) continue
|
|
158
|
-
try {
|
|
159
|
-
if (now - statSync(partPath(id)).mtimeMs > policy.incompleteTtlMs) rmSync(partPath(id), { force: true })
|
|
160
|
-
} catch { /* raced a cancellation or another cleanup pass */ }
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export function startUploadReaper(): void {
|
|
165
|
-
const sweep = () => {
|
|
166
|
-
const policy = uploadPolicy()
|
|
167
|
-
cleanupExpiredUploads(policy)
|
|
168
|
-
const timer = setTimeout(sweep, policy.cleanupIntervalMs)
|
|
169
|
-
timer.unref()
|
|
170
|
-
}
|
|
171
|
-
sweep()
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export function createUpload(name: unknown, size: unknown): UploadStatus {
|
|
175
|
-
const policy = uploadPolicy()
|
|
176
|
-
if (typeof name !== 'string' || !name.trim()) throw new UploadError(400, 'file name is required')
|
|
177
|
-
if (typeof size !== 'number' || !Number.isSafeInteger(size) || size <= 0) throw new UploadError(400, 'file must not be empty')
|
|
178
|
-
if (size > policy.maxBytes) throw new UploadError(413, 'file exceeds the configured upload limit')
|
|
179
|
-
ensureDirs()
|
|
180
|
-
cleanupExpiredUploads(policy)
|
|
181
|
-
reserveCapacity(size, policy)
|
|
182
|
-
const now = Date.now()
|
|
183
|
-
const meta: UploadMeta = { version: 1, id: randomUUID(), name: safeName(name), size, offset: 0, createdAt: now, updatedAt: now }
|
|
184
|
-
writeMeta(meta)
|
|
185
|
-
return status(meta, policy)
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
export function uploadStatus(id: string): UploadStatus {
|
|
189
|
-
const policy = uploadPolicy()
|
|
190
|
-
return status(loadUpload(id, policy), policy)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export async function appendUpload(id: string, offset: unknown, body: ReadableStream<Uint8Array> | null, contentLength?: string): Promise<UploadStatus> {
|
|
194
|
-
const policy = uploadPolicy()
|
|
195
|
-
const meta = loadUpload(id, policy)
|
|
196
|
-
if (typeof offset !== 'number' || !Number.isSafeInteger(offset) || offset < 0) throw new UploadError(400, 'upload offset must be a non-negative integer')
|
|
197
|
-
if (offset !== meta.offset) throw new UploadError(409, 'upload offset does not match the committed bytes', meta.offset)
|
|
198
|
-
if (!body) throw new UploadError(400, 'upload chunk is required')
|
|
199
|
-
const declared = contentLength == null ? null : Number(contentLength)
|
|
200
|
-
if (declared != null && (!Number.isSafeInteger(declared) || declared <= 0)) throw new UploadError(400, 'content-length must be a positive integer')
|
|
201
|
-
if (declared != null && (declared > policy.chunkBytes || meta.offset + declared > meta.size)) {
|
|
202
|
-
throw new UploadError(413, 'upload chunk exceeds its declared bounds')
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
let written = 0
|
|
206
|
-
const before = meta.offset
|
|
207
|
-
const limiter = new Transform({
|
|
208
|
-
transform(chunk, _encoding, callback) {
|
|
209
|
-
written += chunk.length
|
|
210
|
-
if (written > policy.chunkBytes || before + written > meta.size) {
|
|
211
|
-
callback(new UploadError(413, 'upload chunk exceeds its declared bounds'))
|
|
212
|
-
return
|
|
213
|
-
}
|
|
214
|
-
callback(null, chunk)
|
|
215
|
-
},
|
|
216
|
-
})
|
|
217
|
-
try {
|
|
218
|
-
await pipeline(Readable.fromWeb(body as unknown as NodeReadableStream), limiter, createWriteStream(partPath(id), { flags: 'a' }))
|
|
219
|
-
} catch (error) {
|
|
220
|
-
if (error instanceof UploadError) {
|
|
221
|
-
truncateSync(partPath(id), before)
|
|
222
|
-
throw error
|
|
223
|
-
}
|
|
224
|
-
// An interrupted connection may have committed a valid prefix. The next GET reports its actual length.
|
|
225
|
-
meta.offset = actualOffset(meta)
|
|
226
|
-
meta.updatedAt = Date.now()
|
|
227
|
-
writeMeta(meta)
|
|
228
|
-
throw new UploadError(500, `upload write failed: ${(error as Error).message}`)
|
|
229
|
-
}
|
|
230
|
-
if (written === 0) throw new UploadError(400, 'upload chunk is empty')
|
|
231
|
-
meta.offset = actualOffset(meta)
|
|
232
|
-
meta.updatedAt = Date.now()
|
|
233
|
-
writeMeta(meta)
|
|
234
|
-
return status(meta, policy)
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
export function completeUpload(id: string): string {
|
|
238
|
-
const meta = loadUpload(id, uploadPolicy())
|
|
239
|
-
if (meta.offset !== meta.size) throw new UploadError(409, `upload is incomplete (${meta.offset} of ${meta.size} bytes)`, meta.offset)
|
|
240
|
-
const path = join(UPLOAD_DIR, `${Date.now().toString(36)}-${meta.id}-${safeName(meta.name)}`)
|
|
241
|
-
try {
|
|
242
|
-
renameSync(partPath(id), path)
|
|
243
|
-
rmSync(metaPath(id), { force: true })
|
|
244
|
-
return path
|
|
245
|
-
} catch (error) {
|
|
246
|
-
throw new UploadError(500, `upload completion failed: ${(error as Error).message}`)
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
export function cancelUpload(id: string): void {
|
|
251
|
-
loadUpload(id, uploadPolicy())
|
|
252
|
-
removeTransfer(id)
|
|
253
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { appendFileSync, copyFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs'
|
|
2
|
-
import { dirname, join } from 'node:path'
|
|
3
|
-
import { git } from './git.js'
|
|
4
|
-
|
|
5
|
-
export function seedWorktreeHostState(main: string, wt: string): void {
|
|
6
|
-
const f = 'spexcode.local.json'
|
|
7
|
-
try {
|
|
8
|
-
if (!existsSync(join(main, f)) || existsSync(join(wt, f))) return
|
|
9
|
-
copyFileSync(join(main, f), join(wt, f))
|
|
10
|
-
} catch (e) {
|
|
11
|
-
console.error(`spexcode: could not seed ${f} from ${main} into worktree ${wt} — that worker runs on defaults (${e})`)
|
|
12
|
-
return
|
|
13
|
-
}
|
|
14
|
-
hideSeededFromGit(wt, [f])
|
|
15
|
-
}
|
|
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: string, seeded: string[]): void {
|
|
23
|
-
for (const f of seeded) {
|
|
24
|
-
try {
|
|
25
|
-
if (isIgnored(wt, f)) continue
|
|
26
|
-
const exclude = join(git(['-C', wt, 'rev-parse', '--path-format=absolute', '--git-common-dir']).trim(), 'info', 'exclude')
|
|
27
|
-
mkdirSync(dirname(exclude), { recursive: true })
|
|
28
|
-
const cur = existsSync(exclude) ? readFileSync(exclude, 'utf8') : ''
|
|
29
|
-
appendFileSync(exclude, `${cur && !cur.endsWith('\n') ? '\n' : ''}${f}\n`)
|
|
30
|
-
} catch (e) {
|
|
31
|
-
console.error(`spexcode: could not hide seeded ${f} in the shared info/exclude for ${wt} — it will show untracked there (${e})`)
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function isIgnored(wt: string, f: string): boolean {
|
|
37
|
-
try { git(['-C', wt, 'check-ignore', '-q', f]); return true }
|
|
38
|
-
catch (e: any) {
|
|
39
|
-
if (e?.status === 1) return false // check-ignore's documented "not ignored" exit
|
|
40
|
-
throw e
|
|
41
|
-
}
|
|
42
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
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>"` — give each 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), monitor with `spex session watch`, 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); to WAIT for a worker, background `spex session wait <id>` — it is edge-triggered: 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 — which is also how you wait for a dispatched merge to actually land; never block on `spex session watch stream`, which STREAMS forever and will freeze your turn. **Stay parked while your fleet runs:** `spex session new` registers its managed child watch automatically, and a managed watch's send delivery is a real wake-up, so park while those watches exist. For an existing governed worker run one-shot `spex session watch <child>`; use `watch list`/`watch cancel <child>` to manage the relation. With no governed parent address, background a `spex session wait <child>` instead. 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:
|
|
@@ -1,28 +0,0 @@
|
|
|
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
|
-
Code comments are navigation aids, not a second specification. The owning spec body is the current contract:
|
|
9
|
-
intent, invariants, externally observable behavior, and product policy belong there once, rather than being
|
|
10
|
-
restated beside each implementation.
|
|
11
|
-
|
|
12
|
-
Before retaining or adding a comment, ask in this order:
|
|
13
|
-
|
|
14
|
-
1. Does it state intent or a contract? Put that fact in the owning spec body if it is not already there, then
|
|
15
|
-
remove the code comment.
|
|
16
|
-
2. Does it explain a non-obvious local decision — ordering, a platform or library behavior, a measured pitfall,
|
|
17
|
-
or why an otherwise plausible implementation is unsafe? Keep a short comment beside the decision. It should
|
|
18
|
-
name the fact the reader cannot recover from code alone, not re-explain the whole feature.
|
|
19
|
-
3. Does it merely translate the next line or restate a type/name? Remove it.
|
|
20
|
-
|
|
21
|
-
Never turn subtraction into amnesia. A measured value, version-specific behavior, rejected alternative, or other
|
|
22
|
-
implementation fact absent from the spec must remain in code unless it is truly product contract, in which case
|
|
23
|
-
move the fact to the spec before deleting the comment. `@@@title - explanation` is reserved for the genuinely
|
|
24
|
-
tricky local reasoning that survives this test; a tag is not a license to repeat the spec.
|
|
25
|
-
|
|
26
|
-
This division gives each information channel one repair path: a changed product promise updates its spec; a changed
|
|
27
|
-
implementation hazard updates its nearby comment; code that makes either false updates both as their distinct facts
|
|
28
|
-
require. The rule complements [[spec-first]]: reading the contract first is what makes redundant code prose visible.
|
|
@@ -1,23 +0,0 @@
|
|
|
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
|
-
The CLI is noun-first: `spex <noun> <verb> [object] [flags]`. `spex help` is the authoritative command map;
|
|
10
|
-
use a noun's `--help` for exact usage. Ordinary Git, shell, editor, branch, and worktree tools remain available;
|
|
11
|
-
SpexCode commands manage only SpexCode state.
|
|
12
|
-
|
|
13
|
-
Four disciplines, non-negotiable:
|
|
14
|
-
|
|
15
|
-
1. SPEC FIRST. Before reading or changing governed code, read the governing spec BODY. Use `spex spec owner
|
|
16
|
-
<path>` or `spex spec search <topic>` to find it; read neighboring bodies when the contract needs their context.
|
|
17
|
-
The body is the contract; update it with code when intent changes.
|
|
18
|
-
2. COMMIT BEFORE YOU DECLARE. Commit the spec and the code it justifies before declaring done or proposing merge.
|
|
19
|
-
Independent intent gets its own sibling node; do not ride it on an assigned node.
|
|
20
|
-
3. THE BODY IS A LIVING CURRENT-STATE DOCUMENT. Rewrite present intent in place; never add a `## vN` changelog.
|
|
21
|
-
4. KEEP THE LOSS SIGNAL HONEST. Before declaring, run both: `spex spec lint` is the blocking correctness gate;
|
|
22
|
-
`spex eval lint --changed` reports measurement gaps. Re-run changed eval scenarios through the real product, commit the verified tree, then
|
|
23
|
-
file with `spex eval add`; the reading's `codeSha` must name that commit, and evidence must fit the behavior.
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: atomic-landing
|
|
3
|
-
surface: system
|
|
4
|
-
status: active
|
|
5
|
-
hue: 30
|
|
6
|
-
desc: A config plugin — the trunk checkout is the fleet's one landing door, so a merge must be trivial by the time it reaches it: sync and resolve in YOUR OWN worktree, land only when your branch already contains the trunk, and wait rather than race for a busy door.
|
|
7
|
-
code:
|
|
8
|
-
---
|
|
9
|
-
## Landing is atomic — conflicts belong in YOUR worktree, never in the shared checkout
|
|
10
|
-
|
|
11
|
-
Every worktree lands through ONE shared directory: the trunk checkout. Git refuses any merge while that
|
|
12
|
-
directory's index holds an unresolved one, so a merge that stops to ask about conflicts holds the fleet's
|
|
13
|
-
only landing door for as long as a human takes to think — while a merge that *cannot* conflict holds it for
|
|
14
|
-
milliseconds. Land only the second kind.
|
|
15
|
-
|
|
16
|
-
- **Sync first, in your own worktree.** Before you land, merge the trunk INTO your branch (`git merge
|
|
17
|
-
<base>`) right where you work: resolve every conflict there and re-run what proves your work — the tests,
|
|
18
|
-
the scenario you measured. Your worktree is the only place that has your context, your tooling, and nobody
|
|
19
|
-
waiting behind you.
|
|
20
|
-
- **The landing itself must be trivial.** `git merge-base --is-ancestor <base> <branch>` must be TRUE at the
|
|
21
|
-
moment you land: your branch already contains the trunk, so the merge writes a commit and nothing else. If
|
|
22
|
-
it is false — the trunk moved while you were testing — do NOT land: sync again, then land. Resolving
|
|
23
|
-
conflicts *in the shared checkout* is the one forbidden move; it blocks everyone behind a half-merged index,
|
|
24
|
-
and it decides the conflict in the place with the least context about the other side.
|
|
25
|
-
- **A busy door is a wait, not a race.** If the shared checkout is already mid-merge, you cannot land — wait
|
|
26
|
-
and retry, bounded. Never `git merge --abort` someone else's in-progress merge and never resolve their
|
|
27
|
-
conflicts for them: that is their work in flight, and aborting it destroys the part they had already
|
|
28
|
-
reasoned through. If your OWN landing ends up half-merged, abort yours and report rather than leaving the
|
|
29
|
-
trunk mid-state.
|
|
30
|
-
- **An auto-merge is not a tested merge.** A clean merge proves the texts didn't overlap, not that the
|
|
31
|
-
combination works: two branches can each be green and their merge red. That is why the sync happens where
|
|
32
|
-
you can re-run the proof, and why "it merged without conflicts" is never the standard for landing.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: forge-link
|
|
3
|
-
surface: system
|
|
4
|
-
status: active
|
|
5
|
-
hue: 280
|
|
6
|
-
desc: A config plugin — agents link an issue or change request opened through the resolved forge to the spec node it serves via one `Spec: <id>` body line.
|
|
7
|
-
code:
|
|
8
|
-
---
|
|
9
|
-
When you open an issue or change request through the repository's resolved forge, link it to the spec node(s) it serves by adding one line to its **body**: `Spec: <node-id>` (comma-separate several). The id is the node's **leaf** name — the folder under `.spec/…/<id>/spec.md`, e.g. `sessions`, never the slash-path. An unrecognized id silently links nothing, so use a real node id (`spex graph --json` lists them). This is the one linking marker on every forge.
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: memory-hygiene
|
|
3
|
-
surface: system
|
|
4
|
-
status: active
|
|
5
|
-
hue: 200
|
|
6
|
-
desc: A config plugin — keep the project-keyed agent memory free of session- and role-specific facts, so N agents in one folder never inherit a confused identity.
|
|
7
|
-
code:
|
|
8
|
-
---
|
|
9
|
-
## Memory hygiene — keep the shared store identity-clean
|
|
10
|
-
|
|
11
|
-
SpexCode's agent memory is keyed by the **main project**, so every agent running under this project — the main checkout AND every worktree — reads the **same** memory. That makes session- and role-specific facts toxic: one agent's note silently becomes every agent's belief. So, when deciding whether to record a memory:
|
|
12
|
-
|
|
13
|
-
- **Never record session-specific content** — this task, this worktree's transient state, a one-off decision, who you're talking to right now. Memory is ONLY for durable, cross-session project/user facts.
|
|
14
|
-
- **On a non-main worktree** (you are on a `node/<id>` branch, not the main checkout): do **not** record any memory for this session at all. Its work is transient and will merge or close; a durable lesson is recorded later, from main, once it has actually landed.
|
|
15
|
-
- **Even on main, never record a transient ROLE or IDENTITY** — "I am the supervisor", "I'm the coordinator", "I'm the agent doing X". These are per-launch facts, not durable ones. Recording one makes the next launched agent read *itself* as that role, and several agents in one folder dissolve into mutual-supervision confusion (everyone thinks they're the supervisor, everyone watches everyone).
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: reproduce-before-fix
|
|
3
|
-
surface: system
|
|
4
|
-
status: active
|
|
5
|
-
hue: 140
|
|
6
|
-
desc: A config plugin — a bug fix must first REPRODUCE the failure as a failing eval, then fix, verify, commit, and file the passing eval. The fail→pass pair on one scenario is the fix's proof (the A/B).
|
|
7
|
-
code:
|
|
8
|
-
---
|
|
9
|
-
## Reproduce before you fix — the fix's proof is a fail→pass pair
|
|
10
|
-
|
|
11
|
-
If your task is to FIX A BUG, reproduce it *first*, as a measurement — before you touch the fix. A claim that something is broken is worth nothing until the loss signal shows it broken; a claim that you fixed it is worth nothing until the same signal shows it passing. So a bug fix is bracketed by two readings of ONE scenario:
|
|
12
|
-
|
|
13
|
-
- **A — reproduce (fail).** Find the eval-core scenario whose expected the bug violates (if none fits, ADD one to the node's `eval.md` — a description + the expected correct behaviour), run it, and file the failing reading with evidence that SHOWS the bug: `spex eval add <node> --scenario <s> --fail --note "<what's wrong>"` plus an `--image`/`--video` of the actual broken behaviour. This is not ceremony — reproducing is how you learn what actually breaks, and a fix aimed at an unreproduced bug aims at a guess.
|
|
14
|
-
- **B — fix, verify, commit, then file (pass).** Four moves, in order: make the code honor the spec; run the SAME scenario against your **working tree** until it actually passes — confidence is earned here, before any commit; **commit** the verified tree; only then file the passing reading, `spex eval add <node> --scenario <s> --pass`, so its `codeSha` names the very commit you measured (the sidecar append lands last, on top of it). Confidence and anchoring are two different acts: you test the uncommitted tree, but the reading's sha anchor can only land after the commit — this is NOT "commit first, then test" (blind commits with routine rollbacks are bad git). A git sha names only a commit and an uncommitted change has none, so a reading filed from a dirty tree is born mis-anchored — its `codeSha` is a HEAD that does not contain the change it claims to measure — and freshness later marking it stale is the mis-anchor being correctly exposed, not an engine bug. (A needs no such care: it measures the bug on the old, already-committed HEAD, so its anchor is honest as-is.)
|
|
15
|
-
|
|
16
|
-
The two readings on the same scenario are the **A/B** — the error→correct transition, the fix's proof-of-work. eval already keeps per-scenario reading history, so the pair is durable and navigable end to end: the dashboard annotator flips between A (fail) and B (pass), and a trunk delivery (deliver-port) carries that pair as the evidence the fix is real. Don't skip A because the fix looks obvious — an obvious fix with no reproduced failure leaves the loss signal blind to exactly the regression you just closed.
|
|
17
|
-
|
|
18
|
-
This does not apply to building new intent (there is no prior failure to reproduce) — it is the discipline for **repair**: keep the loss signal honest across a bug's whole lifecycle, not just at the end.
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Dashboard-Ba_jhxp1.js","assets/index-DrVao0Ep.js","assets/index-CsI8DElI.css","assets/SessionWindow-CixDi4PI.js","assets/Thread-C6Go8HRh.js","assets/PageScroll-hT7UTLvD.js","assets/data-B-RQmit6.js","assets/Modal-CQgYymmr.js","assets/bindings-BC9vqpYU.js","assets/Dashboard-C5ap-Sga.css","assets/MobileApp-CHgEHORJ.js","assets/launch-BBH02b1v.js","assets/launch-Cp579UoJ.css","assets/ProjectsPage-CtXxakF9.js"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{u as N,r as a,j as n,I as D,a as B,P as k,i as z,_ as T,D as M,b as G}from"./index-DrVao0Ep.js";import{a as J,l as q,s as F,p as V}from"./data-B-RQmit6.js";const h=async e=>(e.headers.get("content-type")||"").includes("json")?e.json().catch(()=>null):null,H=5e3,O=(e,r,t)=>({title:typeof(e==null?void 0:e.title)=="string"&&e.title?e.title:r,icon:typeof(e==null?void 0:e.icon)=="string"&&e.icon?e.icon:t});function x(e){if(!e||typeof e!="object")return null;const r=e.id??e.projectId;return r?{id:String(r),identity:O(e.identity||{title:e.name,icon:e.icon},e.name||String(r),"spexcode"),root:typeof e.root=="string"?e.root:"",online:typeof e.online=="boolean"?e.online:null,url:e.url||"",port:e.port??null,gated:!!(e.gated??e.locked??e.hasPassword),configRevision:typeof e.configRevision=="string"?e.configRevision:""}:null}const W=e=>{const r=Array.isArray(e)?e:Array.isArray(e==null?void 0:e.projects)?e.projects:null;return r?r.map(x).filter(Boolean):null},Y=10;function ce(e,r,t=Y){const s=Array.isArray(e)?e:[],o=Math.max(1,Math.ceil(s.length/t)),l=Math.min(Math.max(1,Number.isInteger(r)?r:1),o);return{items:s.slice((l-1)*t,l*t),page:l,pageCount:o}}function Z(e,r,t){var s;if(!e)return t;if(!r)return null;if(r.state==="ok"){const o=(s=r.projects)==null?void 0:s.find(l=>l.id===e);return(o==null?void 0:o.identity)||{title:e,icon:"spexcode"}}return{title:(t==null?void 0:t.title)||e,icon:(t==null?void 0:t.icon)||"spexcode"}}const K=e=>(e==null?void 0:e.state)==="ok"?e.gateway.identity:{title:"Projects",icon:"gateway"},Q=e=>(e==null?void 0:e.title)||"SpexCode",R=(e,r)=>(r==null?void 0:r.state)==="absent"&&e&&e.state!=="absent"?e:r;async function X(){let e;try{e=await fetch("/projects",{cache:"no-store",headers:{Accept:"application/json"}})}catch{return{state:"absent"}}if(e.status===401)return{state:"denied",reason:"admin-login"};if(e.status===403)return{state:"denied",reason:"locked"};if(!e.ok)return{state:"absent"};const r=await h(e),t=W(r);if(!t)return{state:"absent"};const s=r!=null&&r.gateway&&typeof r.gateway=="object"?{identity:O(r.gateway,"Projects","gateway"),revision:typeof r.gateway.revision=="string"?r.gateway.revision:""}:{identity:{title:"Projects",icon:"gateway"},revision:""};return{state:"ok",adminGated:!!(r!=null&&r.adminGated),gateway:s,projects:t}}async function ie(e,{timeoutMs:r=2500}={}){try{const t=await fetch(`/p/${encodeURIComponent(e)}/health`,{cache:"no-store",signal:AbortSignal.timeout(r)});return!t.ok||t.redirected?"unreachable":(await t.text()).trim()==="ok"?"running":"unreachable"}catch{return"unreachable"}}async function C(e,r,t){let s;try{s=await fetch(e,{method:r,headers:{"Content-Type":"application/json",Accept:"application/json"},...r==="PUT"?{body:JSON.stringify({password:t})}:{}})}catch{return{ok:!1,error:"network"}}const o=await h(s)||{};return{ok:s.ok&&o.ok!==!1,status:s.status,...o.error?{error:o.error}:{}}}const le=(e,r)=>C(`/projects/${encodeURIComponent(e)}/password`,"PUT",r),ue=e=>C(`/projects/${encodeURIComponent(e)}/password`,"DELETE"),pe=e=>C("/projects/admin-password","PUT",e),de=()=>C("/projects/admin-password","DELETE");async function ee(e,r){const t=e==="admin"?"/login":`/p/${encodeURIComponent(e.projectId)}/login`;let s;try{s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({password:r})})}catch{return{ok:!1,error:"network"}}return s.status===401?{ok:!1,error:"wrong-password"}:s.status===403?{ok:!1,error:"locked"}:s.ok||s.redirected?{ok:!0}:{ok:!1,error:`http-${s.status}`}}async function fe(e=""){let r;try{const s=e?`?path=${encodeURIComponent(e)}`:"";r=await fetch(`/projects/browse${s}`,{cache:"no-store",headers:{Accept:"application/json"}})}catch{return{ok:!1,error:"network"}}const t=await h(r);return r.ok?typeof(t==null?void 0:t.path)!="string"||!Array.isArray(t==null?void 0:t.entries)?{ok:!1,error:"unexpected answer"}:{ok:!0,path:t.path,parent:typeof t.parent=="string"?t.parent:null,home:typeof t.home=="string"?t.home:t.path,gitRoot:typeof t.gitRoot=="string"?t.gitRoot:null,initialized:!!t.initialized,cataloged:!!t.cataloged,entries:t.entries.filter(s=>s&&typeof s.name=="string"&&typeof s.path=="string").map(s=>({name:s.name,path:s.path,git:!!s.git,initialized:!!s.initialized}))}:{ok:!1,status:r.status,error:(t==null?void 0:t.error)||`http-${r.status}`}}async function he(e,r={}){let t;try{t=await fetch("/projects",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({root:e,...r})})}catch{return{ok:!1,error:"network"}}const s=await h(t);if(!t.ok)return{ok:!1,status:t.status,error:(s==null?void 0:s.error)||`http-${t.status}`,...s!=null&&s.init&&typeof s.init=="object"?{code:s.init.code??null,output:String(s.init.output??"")}:{}};const o=x(s);return o?{ok:!0,project:o,setup:s.setup??null}:{ok:!1,error:"unexpected answer"}}async function je(e){let r;try{r=await fetch(`/projects/${encodeURIComponent(e)}/config`,{cache:"no-store",headers:{Accept:"application/json"}})}catch{return{ok:!1,error:"network"}}const t=await h(r);return r.ok?typeof(t==null?void 0:t.content)!="string"||typeof(t==null?void 0:t.revision)!="string"?{ok:!1,error:"unexpected answer"}:{ok:!0,content:t.content,revision:t.revision}:{ok:!1,status:r.status,error:(t==null?void 0:t.error)||`http-${r.status}`}}async function me(e,r,t){let s;try{s=await fetch(`/projects/${encodeURIComponent(e)}/config`,{method:"PUT",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({content:r,revision:t})})}catch{return{ok:!1,error:"network"}}const o=await h(s);return s.ok?typeof(o==null?void 0:o.content)!="string"||typeof(o==null?void 0:o.revision)!="string"?{ok:!1,error:"unexpected answer"}:{ok:!0,content:o.content,revision:o.revision}:{ok:!1,status:s.status,error:(o==null?void 0:o.error)||`http-${s.status}`}}async function $(e,r,t){let s;try{s=await fetch(e,{method:"PUT",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({icon:r,revision:t})})}catch{return{ok:!1,error:"network"}}const o=await h(s);return s.ok?{ok:!0,...o}:{ok:!1,status:s.status,error:(o==null?void 0:o.error)||`http-${s.status}`}}const ke=(e,r)=>$("/projects/icon",e,r),ge=(e,r,t)=>$(`/projects/${encodeURIComponent(e)}/icon`,r,t);async function U(e,r,t={}){let s;try{s=await fetch(`/projects/${encodeURIComponent(e)}/${r}`,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(t)})}catch{return{ok:!1,error:"network"}}const o=await h(s);return s.ok?!o||typeof o!="object"?{ok:!1,error:"unexpected answer"}:{ok:o.ok===!0,code:o.code??null,output:String(o.output??"")}:{ok:!1,status:s.status,error:(o==null?void 0:o.error)||`http-${s.status}`}}const we=(e,r)=>U(e,"init",{harness:r}),ye=e=>U(e,"doctor");async function Pe(e){let r;try{r=await fetch(`/projects/${encodeURIComponent(e)}/serve`,{method:"POST",headers:{Accept:"application/json"}})}catch{return{ok:!1,error:"network"}}const t=await h(r);return r.status===409?{ok:!0,already:!0,project:x(t==null?void 0:t.project)}:r.ok?{ok:!0,project:x(t==null?void 0:t.project)}:{ok:!1,status:r.status,error:(t==null?void 0:t.error)||`http-${r.status}`}}function I({scope:e,projectLabel:r,locked:t,onUnlocked:s}){const o=N(),[l,S]=a.useState(""),[j,A]=a.useState(!1),[g,P]=a.useState(null),m=e==="admin",p=async b=>{if(b.preventDefault(),!l||j)return;A(!0),P(null);const w=await ee(m?"admin":{projectId:e.projectId},l);A(!1),w.ok?(S(""),s()):P(w.error==="wrong-password"?o("credential.wrong"):o("credential.failed"))};return n.jsx("div",{className:"cred-wrap",children:n.jsxs("form",{className:"cred-card",onSubmit:p,children:[n.jsx("div",{className:"cred-brand",children:"$ spexcode"}),n.jsxs("div",{className:"cred-title",children:[n.jsx(D,{name:"lock",size:14,className:"cred-lock"}),t?o("credential.lockedTitle"):m?o("credential.adminTitle"):o("credential.projectTitle",{name:r||e&&e.projectId||""})]}),t?n.jsx("p",{className:"cred-sub",children:o("credential.lockedBody")}):n.jsxs(n.Fragment,{children:[n.jsx("p",{className:"cred-sub",children:o(m?"credential.adminBody":"credential.projectBody")}),g&&n.jsx("div",{className:"cred-err",children:g}),n.jsx("input",{className:"cred-input",type:"password",autoFocus:!0,required:!0,placeholder:"••••••••••","aria-label":o("credential.passwordLabel"),value:l,onChange:b=>S(b.target.value)}),n.jsx("button",{className:"cred-submit",type:"submit",disabled:j||!l,children:o(j?"credential.checking":"credential.unlock")})]})]})})}const te=a.lazy(()=>T(()=>import("./Dashboard-Ba_jhxp1.js").then(e=>e.D),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9]))),re=a.lazy(()=>T(()=>import("./MobileApp-CHgEHORJ.js"),__vite__mapDeps([10,1,2,3,4,5,6,11,12]))),se=a.lazy(()=>T(()=>import("./ProjectsPage-CtXxakF9.js"),__vite__mapDeps([13,1,2,7,5,6])));window.addEventListener("vite:preloadError",e=>{const r=String(e.payload);sessionStorage.getItem("spexcode.chunkReload")!==r&&(sessionStorage.setItem("spexcode.chunkReload",r),e.preventDefault(),location.reload())});function oe(){const e=N(),r=B(),[t,s]=a.useState(null),[o,l]=a.useState(!1),S=a.useRef(new Map),j=a.useCallback((u,c)=>{s(J(u,S.current,c))},[]),[A,g]=a.useState(!1),[P,m]=a.useState(null),[p,b]=a.useState(null);a.useEffect(()=>{let u=!0;const c=()=>X().then(y=>{u&&b(L=>R(L,y))}).catch(()=>{u&&b(y=>R(y,{state:"absent"}))});c();const d=setInterval(c,H);return()=>{u=!1,clearInterval(d)}},[]);const w=a.useRef(0),f=a.useCallback(()=>{const u=++w.current;return q().then(c=>{if(!(u!==w.current||!c)){if(c.authRequired){m(c.authRequired);return}m(null),g(!1),j(c.board,!0),c.seal()}}).catch(()=>{u===w.current&&g(!0)})},[j]),v=!k&&!t&&!!p&&p.state!=="absent",E=!k&&!t&&p===null;a.useEffect(()=>{if(v||E)return;f();const u=F({onBoard:(d,y)=>{w.current++,g(!1),j(d,!!(y!=null&&y.authoritative))},onLegacyChange:()=>{f()},onStatus:l}),c=setInterval(()=>{f()},15e3);return()=>{u(),clearInterval(c)}},[f,j,v,E]);const _=t?V(t):null,i=k?Z(k,p,_):v?K(p):_;return a.useEffect(()=>{i&&(document.title=Q(i))},[i==null?void 0:i.title]),a.useEffect(()=>{if(!i)return;const u=v?M:G,c=z(i.icon,u);let d=document.querySelector("link[rel~='icon']");d||(d=document.createElement("link"),d.rel="icon",document.head.appendChild(d)),d.getAttribute("href")!==c&&d.setAttribute("href",c)},[i==null?void 0:i.icon,v]),P&&k?n.jsx(I,{scope:{projectId:k},projectLabel:(i==null?void 0:i.title)||k,onUnlocked:()=>{m(null),f()}}):t?n.jsx(a.Suspense,{fallback:n.jsx("div",{className:"loading",children:e("hud.loading")}),children:r?n.jsx(re,{specs:t.nodes,sessions:t.sessions,issuesStamp:t.issuesStamp,reloadBoard:f}):n.jsx(te,{specs:t.nodes,sessions:t.sessions,issuesStamp:t.issuesStamp,reload:f,identity:i,catalog:p,boardLive:o})}):v?n.jsx(a.Suspense,{fallback:n.jsx("div",{className:"loading",children:e("hud.loading")}),children:n.jsx(se,{})}):P?n.jsx(I,{scope:"admin",locked:P==="locked",onUnlocked:()=>{m(null),f()}}):A&&(k||p&&p.state==="absent")?n.jsxs("div",{className:"loading load-error",children:[n.jsx("span",{children:e("hud.loadError")}),n.jsx("button",{className:"load-retry",onClick:()=>{g(!1),f()},children:e("hud.retry")})]}):n.jsx("div",{className:"loading",children:e("hud.loading")})}const be=Object.freeze(Object.defineProperty({__proto__:null,default:oe},Symbol.toStringTag,{value:"Module"}));export{be as A,H as C,ce as a,I as b,de as c,fe as d,je as e,ye as f,ke as g,he as h,we as i,me as j,ge as k,X as l,Pe as m,ue as n,le as o,ie as p,pe as s};
|