@specship/specship-win32-arm64 0.24.0 → 0.28.0
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/bin/specship.cmd +31 -1
- package/lib/dist/activation/cheatsheet.d.ts +17 -1
- package/lib/dist/activation/cheatsheet.d.ts.map +1 -1
- package/lib/dist/activation/cheatsheet.js +47 -3
- package/lib/dist/activation/cheatsheet.js.map +1 -1
- package/lib/dist/activation/hook-output.d.ts +80 -0
- package/lib/dist/activation/hook-output.d.ts.map +1 -0
- package/lib/dist/activation/hook-output.js +103 -0
- package/lib/dist/activation/hook-output.js.map +1 -0
- package/lib/dist/activation/search-intercept.d.ts +60 -29
- package/lib/dist/activation/search-intercept.d.ts.map +1 -1
- package/lib/dist/activation/search-intercept.js +159 -55
- package/lib/dist/activation/search-intercept.js.map +1 -1
- package/lib/dist/activation/steering.d.ts +11 -13
- package/lib/dist/activation/steering.d.ts.map +1 -1
- package/lib/dist/activation/steering.js +25 -10
- package/lib/dist/activation/steering.js.map +1 -1
- package/lib/dist/behaviour/behaviour-surface.d.ts +47 -0
- package/lib/dist/behaviour/behaviour-surface.d.ts.map +1 -1
- package/lib/dist/behaviour/behaviour-surface.js +108 -2
- package/lib/dist/behaviour/behaviour-surface.js.map +1 -1
- package/lib/dist/bin/node-version-check.d.ts +22 -7
- package/lib/dist/bin/node-version-check.d.ts.map +1 -1
- package/lib/dist/bin/node-version-check.js +39 -9
- package/lib/dist/bin/node-version-check.js.map +1 -1
- package/lib/dist/bin/specship.js +989 -116
- package/lib/dist/bin/specship.js.map +1 -1
- package/lib/dist/commands/specship/learn.md +27 -3
- package/lib/dist/commands/specship/spec.md +85 -15
- package/lib/dist/db/spec-queries.d.ts +73 -3
- package/lib/dist/db/spec-queries.d.ts.map +1 -1
- package/lib/dist/db/spec-queries.js +139 -5
- package/lib/dist/db/spec-queries.js.map +1 -1
- package/lib/dist/db/sqlite-adapter.d.ts +7 -5
- package/lib/dist/db/sqlite-adapter.d.ts.map +1 -1
- package/lib/dist/db/sqlite-adapter.js +11 -9
- package/lib/dist/db/sqlite-adapter.js.map +1 -1
- package/lib/dist/enforce/changed-files.d.ts +39 -0
- package/lib/dist/enforce/changed-files.d.ts.map +1 -0
- package/lib/dist/enforce/changed-files.js +114 -0
- package/lib/dist/enforce/changed-files.js.map +1 -0
- package/lib/dist/enforce/enforce.d.ts +53 -2
- package/lib/dist/enforce/enforce.d.ts.map +1 -1
- package/lib/dist/enforce/enforce.js +95 -8
- package/lib/dist/enforce/enforce.js.map +1 -1
- package/lib/dist/enforce/mutation.d.ts +46 -0
- package/lib/dist/enforce/mutation.d.ts.map +1 -0
- package/lib/dist/enforce/mutation.js +104 -0
- package/lib/dist/enforce/mutation.js.map +1 -0
- package/lib/dist/enforce/suppressions.d.ts +33 -0
- package/lib/dist/enforce/suppressions.d.ts.map +1 -0
- package/lib/dist/enforce/suppressions.js +159 -0
- package/lib/dist/enforce/suppressions.js.map +1 -0
- package/lib/dist/extraction/grammars.d.ts +10 -0
- package/lib/dist/extraction/grammars.d.ts.map +1 -1
- package/lib/dist/extraction/grammars.js +32 -3
- package/lib/dist/extraction/grammars.js.map +1 -1
- package/lib/dist/extraction/index.d.ts +7 -0
- package/lib/dist/extraction/index.d.ts.map +1 -1
- package/lib/dist/extraction/index.js.map +1 -1
- package/lib/dist/extraction/specs/markdown-spec-extractor.d.ts +7 -0
- package/lib/dist/extraction/specs/markdown-spec-extractor.d.ts.map +1 -1
- package/lib/dist/extraction/specs/markdown-spec-extractor.js +97 -10
- package/lib/dist/extraction/specs/markdown-spec-extractor.js.map +1 -1
- package/lib/dist/extraction/wasm/tree-sitter-pascal.wasm.gz +0 -0
- package/lib/dist/extraction/wasm/tree-sitter-scala.wasm.gz +0 -0
- package/lib/dist/graph/spec-coverage.d.ts +142 -0
- package/lib/dist/graph/spec-coverage.d.ts.map +1 -0
- package/lib/dist/graph/spec-coverage.js +276 -0
- package/lib/dist/graph/spec-coverage.js.map +1 -0
- package/lib/dist/health/smoke-check.js +2 -2
- package/lib/dist/health/smoke-check.js.map +1 -1
- package/lib/dist/index.d.ts +75 -7
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +191 -23
- package/lib/dist/index.js.map +1 -1
- package/lib/dist/installer/gemini-commands.d.ts +107 -0
- package/lib/dist/installer/gemini-commands.d.ts.map +1 -0
- package/lib/dist/installer/gemini-commands.js +264 -0
- package/lib/dist/installer/gemini-commands.js.map +1 -0
- package/lib/dist/installer/index.d.ts +55 -8
- package/lib/dist/installer/index.d.ts.map +1 -1
- package/lib/dist/installer/index.js +72 -53
- package/lib/dist/installer/index.js.map +1 -1
- package/lib/dist/installer/init-offer.d.ts +14 -9
- package/lib/dist/installer/init-offer.d.ts.map +1 -1
- package/lib/dist/installer/init-offer.js +13 -9
- package/lib/dist/installer/init-offer.js.map +1 -1
- package/lib/dist/installer/install-defaults.d.ts +81 -0
- package/lib/dist/installer/install-defaults.d.ts.map +1 -0
- package/lib/dist/installer/install-defaults.js +95 -0
- package/lib/dist/installer/install-defaults.js.map +1 -0
- package/lib/dist/installer/instructions-template.d.ts +22 -0
- package/lib/dist/installer/instructions-template.d.ts.map +1 -1
- package/lib/dist/installer/instructions-template.js +37 -1
- package/lib/dist/installer/instructions-template.js.map +1 -1
- package/lib/dist/installer/targets/claude.d.ts +18 -0
- package/lib/dist/installer/targets/claude.d.ts.map +1 -1
- package/lib/dist/installer/targets/claude.js +70 -23
- package/lib/dist/installer/targets/claude.js.map +1 -1
- package/lib/dist/installer/targets/gemini.d.ts +85 -12
- package/lib/dist/installer/targets/gemini.d.ts.map +1 -1
- package/lib/dist/installer/targets/gemini.js +527 -30
- package/lib/dist/installer/targets/gemini.js.map +1 -1
- package/lib/dist/installer/targets/shared.d.ts +13 -0
- package/lib/dist/installer/targets/shared.d.ts.map +1 -1
- package/lib/dist/installer/targets/shared.js +22 -4
- package/lib/dist/installer/targets/shared.js.map +1 -1
- package/lib/dist/installer/targets/types.d.ts +12 -0
- package/lib/dist/installer/targets/types.d.ts.map +1 -1
- package/lib/dist/jira/auto-publish.d.ts +71 -4
- package/lib/dist/jira/auto-publish.d.ts.map +1 -1
- package/lib/dist/jira/auto-publish.js +186 -17
- package/lib/dist/jira/auto-publish.js.map +1 -1
- package/lib/dist/jira/reconcile.d.ts +24 -1
- package/lib/dist/jira/reconcile.d.ts.map +1 -1
- package/lib/dist/jira/reconcile.js +46 -2
- package/lib/dist/jira/reconcile.js.map +1 -1
- package/lib/dist/jira/repo-config.d.ts +9 -0
- package/lib/dist/jira/repo-config.d.ts.map +1 -1
- package/lib/dist/jira/repo-config.js +11 -0
- package/lib/dist/jira/repo-config.js.map +1 -1
- package/lib/dist/jira/types.d.ts +7 -0
- package/lib/dist/jira/types.d.ts.map +1 -1
- package/lib/dist/jira/types.js.map +1 -1
- package/lib/dist/knowledge/enforce.d.ts +75 -0
- package/lib/dist/knowledge/enforce.d.ts.map +1 -0
- package/lib/dist/knowledge/enforce.js +250 -0
- package/lib/dist/knowledge/enforce.js.map +1 -0
- package/lib/dist/knowledge/facts.d.ts +33 -0
- package/lib/dist/knowledge/facts.d.ts.map +1 -0
- package/lib/dist/knowledge/facts.js +117 -0
- package/lib/dist/knowledge/facts.js.map +1 -0
- package/lib/dist/knowledge/proposals.d.ts +88 -0
- package/lib/dist/knowledge/proposals.d.ts.map +1 -0
- package/lib/dist/knowledge/proposals.js +360 -0
- package/lib/dist/knowledge/proposals.js.map +1 -0
- package/lib/dist/knowledge/stale.d.ts +64 -0
- package/lib/dist/knowledge/stale.d.ts.map +1 -0
- package/lib/dist/knowledge/stale.js +174 -0
- package/lib/dist/knowledge/stale.js.map +1 -0
- package/lib/dist/mcp/fitness-tool.d.ts +5 -6
- package/lib/dist/mcp/fitness-tool.d.ts.map +1 -1
- package/lib/dist/mcp/fitness-tool.js +0 -16
- package/lib/dist/mcp/fitness-tool.js.map +1 -1
- package/lib/dist/mcp/gemini-session.d.ts +50 -0
- package/lib/dist/mcp/gemini-session.d.ts.map +1 -0
- package/lib/dist/mcp/gemini-session.js +159 -0
- package/lib/dist/mcp/gemini-session.js.map +1 -0
- package/lib/dist/mcp/health-tool.d.ts +26 -0
- package/lib/dist/mcp/health-tool.d.ts.map +1 -0
- package/lib/dist/mcp/health-tool.js +50 -0
- package/lib/dist/mcp/health-tool.js.map +1 -0
- package/lib/dist/mcp/jira-tools.d.ts.map +1 -1
- package/lib/dist/mcp/jira-tools.js +25 -0
- package/lib/dist/mcp/jira-tools.js.map +1 -1
- package/lib/dist/mcp/maintainability-tool.d.ts +5 -7
- package/lib/dist/mcp/maintainability-tool.d.ts.map +1 -1
- package/lib/dist/mcp/maintainability-tool.js +0 -16
- package/lib/dist/mcp/maintainability-tool.js.map +1 -1
- package/lib/dist/mcp/model-context.d.ts +31 -7
- package/lib/dist/mcp/model-context.d.ts.map +1 -1
- package/lib/dist/mcp/model-context.js +70 -21
- package/lib/dist/mcp/model-context.js.map +1 -1
- package/lib/dist/mcp/proxy.d.ts.map +1 -1
- package/lib/dist/mcp/proxy.js +5 -2
- package/lib/dist/mcp/proxy.js.map +1 -1
- package/lib/dist/mcp/server-instructions.d.ts +16 -15
- package/lib/dist/mcp/server-instructions.d.ts.map +1 -1
- package/lib/dist/mcp/server-instructions.js +72 -5
- package/lib/dist/mcp/server-instructions.js.map +1 -1
- package/lib/dist/mcp/session.js +1 -1
- package/lib/dist/mcp/session.js.map +1 -1
- package/lib/dist/mcp/spec-tools.d.ts +9 -1
- package/lib/dist/mcp/spec-tools.d.ts.map +1 -1
- package/lib/dist/mcp/spec-tools.js +282 -49
- package/lib/dist/mcp/spec-tools.js.map +1 -1
- package/lib/dist/mcp/tools.d.ts +49 -9
- package/lib/dist/mcp/tools.d.ts.map +1 -1
- package/lib/dist/mcp/tools.js +210 -58
- package/lib/dist/mcp/tools.js.map +1 -1
- package/lib/dist/pulse/pulse.d.ts +93 -0
- package/lib/dist/pulse/pulse.d.ts.map +1 -0
- package/lib/dist/pulse/pulse.js +401 -0
- package/lib/dist/pulse/pulse.js.map +1 -0
- package/lib/dist/reflect/apply.d.ts.map +1 -1
- package/lib/dist/reflect/apply.js +38 -3
- package/lib/dist/reflect/apply.js.map +1 -1
- package/lib/dist/reflect/auto-sweep.d.ts +26 -0
- package/lib/dist/reflect/auto-sweep.d.ts.map +1 -0
- package/lib/dist/reflect/auto-sweep.js +90 -0
- package/lib/dist/reflect/auto-sweep.js.map +1 -0
- package/lib/dist/reflect/cli.d.ts +62 -0
- package/lib/dist/reflect/cli.d.ts.map +1 -0
- package/lib/dist/reflect/cli.js +163 -0
- package/lib/dist/reflect/cli.js.map +1 -0
- package/lib/dist/reflect/miner.d.ts.map +1 -1
- package/lib/dist/reflect/miner.js +119 -0
- package/lib/dist/reflect/miner.js.map +1 -1
- package/lib/dist/reflect/sweep.d.ts +1 -0
- package/lib/dist/reflect/sweep.d.ts.map +1 -1
- package/lib/dist/reflect/sweep.js +62 -13
- package/lib/dist/reflect/sweep.js.map +1 -1
- package/lib/dist/reflect/targets.d.ts +2 -0
- package/lib/dist/reflect/targets.d.ts.map +1 -1
- package/lib/dist/reflect/targets.js +33 -0
- package/lib/dist/reflect/targets.js.map +1 -1
- package/lib/dist/reflect/types.d.ts +19 -2
- package/lib/dist/reflect/types.d.ts.map +1 -1
- package/lib/dist/resolution/spec-link-resolver.d.ts +44 -2
- package/lib/dist/resolution/spec-link-resolver.d.ts.map +1 -1
- package/lib/dist/resolution/spec-link-resolver.js +132 -0
- package/lib/dist/resolution/spec-link-resolver.js.map +1 -1
- package/lib/dist/resolution/test-title-links.d.ts +62 -0
- package/lib/dist/resolution/test-title-links.d.ts.map +1 -0
- package/lib/dist/resolution/test-title-links.js +97 -0
- package/lib/dist/resolution/test-title-links.js.map +1 -0
- package/lib/dist/search/query-parser.d.ts.map +1 -1
- package/lib/dist/search/query-parser.js +6 -1
- package/lib/dist/search/query-parser.js.map +1 -1
- package/lib/dist/server/project-registry.js +1 -1
- package/lib/dist/server/routes/claude.js +24 -43
- package/lib/dist/server/routes/graph.js +53 -7
- package/lib/dist/server/routes/knowledge.js +118 -0
- package/lib/dist/server/routes/mcp.js +4 -3
- package/lib/dist/server/routes/projects.js +4 -4
- package/lib/dist/server/routes/spec.js +49 -7
- package/lib/dist/server/server.js +31 -17
- package/lib/dist/skills/spec-author/SKILL.md +164 -0
- package/lib/dist/skills/spec-author/references/format.md +210 -0
- package/lib/dist/skills/spec-author/references/gap-questions.md +152 -0
- package/lib/dist/skills/spec-author/references/quality-rubric.md +125 -0
- package/lib/dist/skills/spec-author/references/review-checklist.md +175 -0
- package/lib/dist/spec-lint/lint.d.ts +82 -0
- package/lib/dist/spec-lint/lint.d.ts.map +1 -0
- package/lib/dist/spec-lint/lint.js +491 -0
- package/lib/dist/spec-lint/lint.js.map +1 -0
- package/lib/dist/spec-quality/criterion-ids.d.ts +13 -0
- package/lib/dist/spec-quality/criterion-ids.d.ts.map +1 -0
- package/lib/dist/spec-quality/criterion-ids.js +38 -0
- package/lib/dist/spec-quality/criterion-ids.js.map +1 -0
- package/lib/dist/spec-quality/evidence-kind.d.ts +54 -0
- package/lib/dist/spec-quality/evidence-kind.d.ts.map +1 -0
- package/lib/dist/spec-quality/evidence-kind.js +183 -0
- package/lib/dist/spec-quality/evidence-kind.js.map +1 -0
- package/lib/dist/spec-quality/link-persist.d.ts +65 -0
- package/lib/dist/spec-quality/link-persist.d.ts.map +1 -0
- package/lib/dist/spec-quality/link-persist.js +249 -0
- package/lib/dist/spec-quality/link-persist.js.map +1 -0
- package/lib/dist/spec-quality/plan-scope.d.ts +38 -0
- package/lib/dist/spec-quality/plan-scope.d.ts.map +1 -0
- package/lib/dist/spec-quality/plan-scope.js +129 -0
- package/lib/dist/spec-quality/plan-scope.js.map +1 -0
- package/lib/dist/spec-quality/postcheck.d.ts +85 -0
- package/lib/dist/spec-quality/postcheck.d.ts.map +1 -0
- package/lib/dist/spec-quality/postcheck.js +390 -0
- package/lib/dist/spec-quality/postcheck.js.map +1 -0
- package/lib/dist/spec-quality/readiness.d.ts +72 -0
- package/lib/dist/spec-quality/readiness.d.ts.map +1 -0
- package/lib/dist/spec-quality/readiness.js +226 -0
- package/lib/dist/spec-quality/readiness.js.map +1 -0
- package/lib/dist/statusline/index.js.map +1 -1
- package/lib/dist/statusline/render.d.ts +1 -1
- package/lib/dist/statusline/render.d.ts.map +1 -1
- package/lib/dist/statusline/render.js +3 -1
- package/lib/dist/statusline/render.js.map +1 -1
- package/lib/dist/ui/assets/index-BzuUWUAE.js +50 -0
- package/lib/dist/ui/index.html +1 -1
- package/lib/dist/verify/report-ingest.d.ts +88 -0
- package/lib/dist/verify/report-ingest.d.ts.map +1 -0
- package/lib/dist/verify/report-ingest.js +269 -0
- package/lib/dist/verify/report-ingest.js.map +1 -0
- package/lib/dist/workflows/agents/claude.d.ts +16 -0
- package/lib/dist/workflows/agents/claude.d.ts.map +1 -0
- package/lib/dist/workflows/agents/claude.js +82 -0
- package/lib/dist/workflows/agents/claude.js.map +1 -0
- package/lib/dist/workflows/agents/gemini.d.ts +21 -0
- package/lib/dist/workflows/agents/gemini.d.ts.map +1 -0
- package/lib/dist/workflows/agents/gemini.js +124 -0
- package/lib/dist/workflows/agents/gemini.js.map +1 -0
- package/lib/dist/workflows/agents/index.d.ts +28 -0
- package/lib/dist/workflows/agents/index.d.ts.map +1 -0
- package/lib/dist/workflows/agents/index.js +104 -0
- package/lib/dist/workflows/agents/index.js.map +1 -0
- package/lib/dist/workflows/agents/types.d.ts +55 -0
- package/lib/dist/workflows/agents/types.d.ts.map +1 -0
- package/lib/dist/workflows/agents/types.js +46 -0
- package/lib/dist/workflows/agents/types.js.map +1 -0
- package/lib/dist/workflows/batch.d.ts +63 -0
- package/lib/dist/workflows/batch.d.ts.map +1 -0
- package/lib/dist/workflows/batch.js +151 -0
- package/lib/dist/workflows/batch.js.map +1 -0
- package/lib/dist/workflows/defaults/claude-design-implement.yaml +3 -4
- package/lib/dist/workflows/defaults/spec-author.yaml +11 -9
- package/lib/dist/workflows/defaults/spec-fix.yaml +103 -12
- package/lib/dist/workflows/defaults/spec-implement-mixed.yaml +21 -193
- package/lib/dist/workflows/defaults/spec-implement.yaml +701 -41
- package/lib/dist/workflows/defaults/spec-verify.yaml +60 -9
- package/lib/dist/workflows/discovery.d.ts +13 -0
- package/lib/dist/workflows/discovery.d.ts.map +1 -1
- package/lib/dist/workflows/discovery.js +79 -17
- package/lib/dist/workflows/discovery.js.map +1 -1
- package/lib/dist/workflows/executor.d.ts +18 -0
- package/lib/dist/workflows/executor.d.ts.map +1 -1
- package/lib/dist/workflows/executor.js +130 -33
- package/lib/dist/workflows/executor.js.map +1 -1
- package/lib/dist/workflows/gc.d.ts +50 -0
- package/lib/dist/workflows/gc.d.ts.map +1 -0
- package/lib/dist/workflows/gc.js +120 -0
- package/lib/dist/workflows/gc.js.map +1 -0
- package/lib/dist/workflows/merge-queue.d.ts +64 -0
- package/lib/dist/workflows/merge-queue.d.ts.map +1 -0
- package/lib/dist/workflows/merge-queue.js +162 -0
- package/lib/dist/workflows/merge-queue.js.map +1 -0
- package/lib/dist/workflows/runners/approval.d.ts +1 -1
- package/lib/dist/workflows/runners/approval.d.ts.map +1 -1
- package/lib/dist/workflows/runners/approval.js +11 -2
- package/lib/dist/workflows/runners/approval.js.map +1 -1
- package/lib/dist/workflows/runners/bash.d.ts +15 -0
- package/lib/dist/workflows/runners/bash.d.ts.map +1 -1
- package/lib/dist/workflows/runners/bash.js +50 -1
- package/lib/dist/workflows/runners/bash.js.map +1 -1
- package/lib/dist/workflows/runners/prompt.d.ts +16 -41
- package/lib/dist/workflows/runners/prompt.d.ts.map +1 -1
- package/lib/dist/workflows/runners/prompt.js +55 -120
- package/lib/dist/workflows/runners/prompt.js.map +1 -1
- package/lib/dist/workflows/runners/types.d.ts +12 -0
- package/lib/dist/workflows/runners/types.d.ts.map +1 -1
- package/lib/dist/workflows/schemas/workflow.d.ts +17 -0
- package/lib/dist/workflows/schemas/workflow.d.ts.map +1 -1
- package/lib/dist/workflows/schemas/workflow.js +27 -0
- package/lib/dist/workflows/schemas/workflow.js.map +1 -1
- package/lib/node_modules/.package-lock.json +1 -1
- package/lib/package.json +8 -4
- package/package.json +5 -3
- package/lib/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
- package/lib/dist/extraction/wasm/tree-sitter-scala.wasm +0 -0
- package/lib/dist/server/ingest/impact-query.js +0 -343
- package/lib/dist/server/routes/events.js +0 -152
- package/lib/dist/ui/assets/index-CjjaftDw.js +0 -50
- package/node.exe +0 -4
|
@@ -13,23 +13,58 @@ nodes:
|
|
|
13
13
|
output_type: test_results
|
|
14
14
|
timeout: 600000
|
|
15
15
|
bash: |
|
|
16
|
+
# Same VERIFY_RESULT contract as spec-implement / spec-fix
|
|
17
|
+
# (REQ-REVINT-006, REQ-VSTATE-005): the marker is what the routing node
|
|
18
|
+
# reads. This node used to emit no marker at all and `exit 0` when it
|
|
19
|
+
# found no runner — a no-runner repo read as a clean verification pass.
|
|
16
20
|
if [ -f package.json ]; then
|
|
17
21
|
# Run against a built tree so a missing dist/ can't false-fail the
|
|
18
22
|
# verify leg (WF-REJECT-DOC, REQ-WFREJ-005).
|
|
19
|
-
npm run build --if-present
|
|
20
|
-
npm test
|
|
23
|
+
if ! npm run build --if-present; then echo "VERIFY_RESULT=build-failed"; exit 1; fi
|
|
24
|
+
if npm test; then echo "VERIFY_RESULT=ran-and-passed"; else echo "VERIFY_RESULT=ran-and-failed"; exit 1; fi
|
|
21
25
|
elif [ -f Cargo.toml ]; then
|
|
22
|
-
cargo
|
|
26
|
+
if ! cargo build; then echo "VERIFY_RESULT=build-failed"; exit 1; fi
|
|
27
|
+
if cargo test; then echo "VERIFY_RESULT=ran-and-passed"; else echo "VERIFY_RESULT=ran-and-failed"; exit 1; fi
|
|
23
28
|
elif [ -f pyproject.toml ] || [ -f requirements.txt ]; then
|
|
24
|
-
python -
|
|
29
|
+
if ! python -c 'import pytest' 2>/dev/null; then echo "VERIFY_RESULT=env-failed"; exit 1; fi
|
|
30
|
+
if python -m pytest; then echo "VERIFY_RESULT=ran-and-passed"; else echo "VERIFY_RESULT=ran-and-failed"; exit 1; fi
|
|
25
31
|
else
|
|
26
|
-
echo "no recognised test framework;
|
|
27
|
-
|
|
32
|
+
echo "no recognised test framework; tests did NOT run" >&2
|
|
33
|
+
echo "VERIFY_RESULT=skipped"
|
|
28
34
|
fi
|
|
29
35
|
|
|
36
|
+
- id: route_verify
|
|
37
|
+
kind: bash
|
|
38
|
+
depends_on: [run_tests]
|
|
39
|
+
output_type: verify_route
|
|
40
|
+
bash: |
|
|
41
|
+
# Deterministic routing (REQ-VSTATE-005.A1): code decides what the
|
|
42
|
+
# summarize node may do with link state.
|
|
43
|
+
VERIFY_OUT=$run_tests.output
|
|
44
|
+
MARKER=$(printf '%s' "$VERIFY_OUT" | grep -oE 'VERIFY_RESULT=[a-z-]+' | tail -n 1 | cut -d= -f2)
|
|
45
|
+
[ -n "$MARKER" ] || MARKER=missing
|
|
46
|
+
echo "VERIFY_RESULT=$MARKER"
|
|
47
|
+
case "$MARKER" in
|
|
48
|
+
ran-and-passed)
|
|
49
|
+
echo "LINK_ACTION=verify-evidenced" ;;
|
|
50
|
+
ran-and-failed)
|
|
51
|
+
echo "LINK_ACTION=verify-fail" ;;
|
|
52
|
+
skipped)
|
|
53
|
+
echo "LINK_ACTION=no-verify" ;;
|
|
54
|
+
env-failed)
|
|
55
|
+
echo "HALT_CAUSE=environment setup failed — nothing is known about the tests"
|
|
56
|
+
exit 1 ;;
|
|
57
|
+
build-failed)
|
|
58
|
+
echo "HALT_CAUSE=build failed — nothing is known about the tests"
|
|
59
|
+
exit 1 ;;
|
|
60
|
+
*)
|
|
61
|
+
echo "HALT_CAUSE=no VERIFY_RESULT marker found in the test output — an unknown result is never a pass"
|
|
62
|
+
exit 1 ;;
|
|
63
|
+
esac
|
|
64
|
+
|
|
30
65
|
- id: summarize
|
|
31
66
|
kind: prompt
|
|
32
|
-
depends_on: [
|
|
67
|
+
depends_on: [route_verify]
|
|
33
68
|
output_type: link_summary
|
|
34
69
|
trigger_rule: all_done
|
|
35
70
|
allowed_tools:
|
|
@@ -41,12 +76,23 @@ nodes:
|
|
|
41
76
|
|
|
42
77
|
$run_tests.output
|
|
43
78
|
|
|
79
|
+
Routing decision (computed in code — act on it, do not re-derive it
|
|
80
|
+
from the log above):
|
|
81
|
+
|
|
82
|
+
$route_verify.output
|
|
83
|
+
|
|
44
84
|
Promotion is EVIDENCE-BASED (VERIFY-EVID-DOC): a spec may only become
|
|
45
85
|
"verified" when a test linked to it as evidence passed. Evidence links
|
|
46
|
-
have kind='tests' and come from a `verifies:` block in the spec
|
|
47
|
-
`@verifies REQ-X` comment on the test
|
|
86
|
+
have kind='tests' and come from a `verifies:` block in the spec, an
|
|
87
|
+
`@verifies REQ-X` comment on the test, or a spec id inside an `it()`
|
|
88
|
+
title in a test file (REQ-VSTATE-002). A green suite alone proves
|
|
48
89
|
nothing about a spec with no linked tests — never blanket-promote.
|
|
49
90
|
|
|
91
|
+
- LINK_ACTION=verify-evidenced → proceed with steps 1–4 below.
|
|
92
|
+
- LINK_ACTION=verify-fail → only demote (step 3). Promote nothing.
|
|
93
|
+
- LINK_ACTION=no-verify → no test ran. Mutate no link state at all;
|
|
94
|
+
report that verification was skipped and stop.
|
|
95
|
+
|
|
50
96
|
1. Call specship_drifted to see any drifted/broken/orphaned links.
|
|
51
97
|
2. For each 'implemented' link whose spec HAS test-evidence links:
|
|
52
98
|
if all of that spec's evidence tests passed in the output above,
|
|
@@ -61,5 +107,10 @@ nodes:
|
|
|
61
107
|
"unevidenced" in your summary so the author can add `verifies:`
|
|
62
108
|
blocks (REQ-VEVID-003).
|
|
63
109
|
|
|
110
|
+
For a fully deterministic alternative to steps 2–3, run
|
|
111
|
+
`specship verify --report <vitest-json>` (REQ-VSTATE-004): it maps
|
|
112
|
+
reported test cases to `tests` links by file + title and moves the
|
|
113
|
+
state itself, with the run recorded as evidence.
|
|
114
|
+
|
|
64
115
|
Output: a short summary — how many links moved to verified, how many
|
|
65
116
|
to broken, which specs are unevidenced, and which are still drifted.
|
|
@@ -43,4 +43,17 @@ export declare function discoverWorkflows(projectRoot: string): WorkflowLoadResu
|
|
|
43
43
|
* Returns null if no workflow with that name exists in any scope.
|
|
44
44
|
*/
|
|
45
45
|
export declare function loadWorkflowByName(projectRoot: string, name: string): WorkflowWithSource | null;
|
|
46
|
+
/**
|
|
47
|
+
* Resolve `extends: <workflow>` + `node_overrides` (THROUGHPUT-DOC,
|
|
48
|
+
* REQ-THRU-004): the result is the base workflow's raw definition with the
|
|
49
|
+
* extending file's top-level fields on top and each named node's fields
|
|
50
|
+
* shallow-merged from `node_overrides`. One source for shared nodes — a
|
|
51
|
+
* variant like spec-implement-mixed only states what differs. Chains resolve
|
|
52
|
+
* recursively; a cycle, an unknown base, or an override naming no base node
|
|
53
|
+
* is an error.
|
|
54
|
+
*/
|
|
55
|
+
export declare function resolveExtends(raw: Record<string, unknown>, getBase: (name: string) => Record<string, unknown> | undefined, seen?: Set<string>): {
|
|
56
|
+
value?: Record<string, unknown>;
|
|
57
|
+
errors: ValidationError[];
|
|
58
|
+
};
|
|
46
59
|
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/workflows/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,EACL,kBAAkB,EAElB,eAAe,EAChB,MAAM,oBAAoB,CAAC;AAG5B,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,yDAAyD;IACzD,SAAS,EAAE,kBAAkB,EAAE,CAAC;IAChC,uCAAuC;IACvC,MAAM,EAAE,iBAAiB,EAAE,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,kBAAkB,
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/workflows/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,EACL,kBAAkB,EAElB,eAAe,EAChB,MAAM,oBAAoB,CAAC;AAG5B,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,aAAa,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,yDAAyD;IACzD,SAAS,EAAE,kBAAkB,EAAE,CAAC;IAChC,uCAAuC;IACvC,MAAM,EAAE,iBAAiB,EAAE,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,kBAAkB,CA4CzE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GACX,kBAAkB,GAAG,IAAI,CAG3B;AAuFD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC9D,IAAI,GAAE,GAAG,CAAC,MAAM,CAAa,GAC5B;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,MAAM,EAAE,eAAe,EAAE,CAAA;CAAE,CAiChE"}
|
|
@@ -50,6 +50,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
50
50
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
51
|
exports.discoverWorkflows = discoverWorkflows;
|
|
52
52
|
exports.loadWorkflowByName = loadWorkflowByName;
|
|
53
|
+
exports.resolveExtends = resolveExtends;
|
|
53
54
|
const fs = __importStar(require("fs"));
|
|
54
55
|
const path = __importStar(require("path"));
|
|
55
56
|
const os = __importStar(require("os"));
|
|
@@ -65,9 +66,17 @@ const defaults_1 = require("./defaults");
|
|
|
65
66
|
function discoverWorkflows(projectRoot) {
|
|
66
67
|
const byName = new Map();
|
|
67
68
|
const errors = [];
|
|
69
|
+
// Raw (pre-validation) definitions by name, so `extends:` can resolve
|
|
70
|
+
// against any workflow loaded at the same or a lower-precedence scope.
|
|
71
|
+
const rawByName = new Map();
|
|
72
|
+
for (const entry of defaults_1.bundledDefaults) {
|
|
73
|
+
const raw = parseRaw(entry.yaml);
|
|
74
|
+
if (raw.value && typeof raw.value.name === 'string')
|
|
75
|
+
rawByName.set(raw.value.name, raw.value);
|
|
76
|
+
}
|
|
68
77
|
// 1. Bundled (lowest precedence)
|
|
69
78
|
for (const entry of defaults_1.bundledDefaults) {
|
|
70
|
-
const result = parseAndValidate(entry.yaml);
|
|
79
|
+
const result = parseAndValidate(entry.yaml, rawByName);
|
|
71
80
|
if (result.workflow) {
|
|
72
81
|
byName.set(entry.name, {
|
|
73
82
|
workflow: result.workflow,
|
|
@@ -85,10 +94,10 @@ function discoverWorkflows(projectRoot) {
|
|
|
85
94
|
}
|
|
86
95
|
// 2. Global
|
|
87
96
|
const globalDir = path.join(os.homedir(), '.specship', 'workflows');
|
|
88
|
-
loadFromDir(globalDir, 'global', byName, errors);
|
|
97
|
+
loadFromDir(globalDir, 'global', byName, errors, rawByName);
|
|
89
98
|
// 3. Project (highest precedence)
|
|
90
99
|
const projectDir = path.join(projectRoot, '.specship', 'workflows');
|
|
91
|
-
loadFromDir(projectDir, 'project', byName, errors);
|
|
100
|
+
loadFromDir(projectDir, 'project', byName, errors, rawByName);
|
|
92
101
|
return {
|
|
93
102
|
workflows: [...byName.values()].sort((a, b) => a.workflow.name.localeCompare(b.workflow.name)),
|
|
94
103
|
errors,
|
|
@@ -105,7 +114,7 @@ function loadWorkflowByName(projectRoot, name) {
|
|
|
105
114
|
// =============================================================================
|
|
106
115
|
// internal
|
|
107
116
|
// =============================================================================
|
|
108
|
-
function loadFromDir(dir, scope, byName, errors) {
|
|
117
|
+
function loadFromDir(dir, scope, byName, errors, rawByName = new Map()) {
|
|
109
118
|
let entries;
|
|
110
119
|
try {
|
|
111
120
|
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
@@ -152,8 +161,11 @@ function loadFromDir(dir, scope, byName, errors) {
|
|
|
152
161
|
});
|
|
153
162
|
continue;
|
|
154
163
|
}
|
|
155
|
-
const result = parseAndValidate(source);
|
|
164
|
+
const result = parseAndValidate(source, rawByName);
|
|
156
165
|
if (result.workflow) {
|
|
166
|
+
const raw = parseRaw(source).value;
|
|
167
|
+
if (raw)
|
|
168
|
+
rawByName.set(result.workflow.name, raw);
|
|
157
169
|
byName.set(result.workflow.name, {
|
|
158
170
|
workflow: result.workflow,
|
|
159
171
|
scope,
|
|
@@ -169,22 +181,72 @@ function isYamlFile(name) {
|
|
|
169
181
|
const lower = name.toLowerCase();
|
|
170
182
|
return lower.endsWith('.yaml') || lower.endsWith('.yml');
|
|
171
183
|
}
|
|
172
|
-
function
|
|
173
|
-
let parsed;
|
|
184
|
+
function parseRaw(source) {
|
|
174
185
|
try {
|
|
175
|
-
|
|
186
|
+
const v = yaml.parse(source);
|
|
187
|
+
return v && typeof v === 'object' && !Array.isArray(v) ? { value: v } : { value: undefined };
|
|
176
188
|
}
|
|
177
189
|
catch (err) {
|
|
178
|
-
return {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
190
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Resolve `extends: <workflow>` + `node_overrides` (THROUGHPUT-DOC,
|
|
195
|
+
* REQ-THRU-004): the result is the base workflow's raw definition with the
|
|
196
|
+
* extending file's top-level fields on top and each named node's fields
|
|
197
|
+
* shallow-merged from `node_overrides`. One source for shared nodes — a
|
|
198
|
+
* variant like spec-implement-mixed only states what differs. Chains resolve
|
|
199
|
+
* recursively; a cycle, an unknown base, or an override naming no base node
|
|
200
|
+
* is an error.
|
|
201
|
+
*/
|
|
202
|
+
function resolveExtends(raw, getBase, seen = new Set()) {
|
|
203
|
+
const baseName = raw.extends;
|
|
204
|
+
if (baseName === undefined)
|
|
205
|
+
return { value: raw, errors: [] };
|
|
206
|
+
if (typeof baseName !== 'string' || baseName.trim() === '') {
|
|
207
|
+
return { errors: [{ path: '$.extends', message: '`extends` must name a workflow' }] };
|
|
208
|
+
}
|
|
209
|
+
if (seen.has(baseName)) {
|
|
210
|
+
return { errors: [{ path: '$.extends', message: `extends cycle through "${baseName}"` }] };
|
|
211
|
+
}
|
|
212
|
+
const baseRaw = getBase(baseName);
|
|
213
|
+
if (!baseRaw) {
|
|
214
|
+
return { errors: [{ path: '$.extends', message: `extends unknown workflow "${baseName}"` }] };
|
|
215
|
+
}
|
|
216
|
+
const base = resolveExtends(baseRaw, getBase, new Set([...seen, baseName]));
|
|
217
|
+
if (!base.value)
|
|
218
|
+
return base;
|
|
219
|
+
const { extends: _e, node_overrides: overridesRaw, ...own } = raw;
|
|
220
|
+
const overrides = overridesRaw && typeof overridesRaw === 'object' && !Array.isArray(overridesRaw)
|
|
221
|
+
? overridesRaw
|
|
222
|
+
: {};
|
|
223
|
+
const baseNodes = Array.isArray(base.value.nodes) ? base.value.nodes : [];
|
|
224
|
+
const ids = new Set(baseNodes.map((n) => n.id));
|
|
225
|
+
const errors = [];
|
|
226
|
+
for (const id of Object.keys(overrides)) {
|
|
227
|
+
if (!ids.has(id))
|
|
228
|
+
errors.push({ path: `$.node_overrides.${id}`, message: `override names no node "${id}" in "${baseName}"` });
|
|
229
|
+
}
|
|
230
|
+
if (errors.length > 0)
|
|
231
|
+
return { errors };
|
|
232
|
+
const nodes = baseNodes.map((n) => {
|
|
233
|
+
const o = overrides[String(n.id)];
|
|
234
|
+
return o && typeof o === 'object' ? { ...n, ...o, id: n.id } : n;
|
|
235
|
+
});
|
|
236
|
+
return { value: { ...base.value, ...own, nodes }, errors: [] };
|
|
237
|
+
}
|
|
238
|
+
function parseAndValidate(source, rawByName = new Map()) {
|
|
239
|
+
const raw = parseRaw(source);
|
|
240
|
+
if (raw.error !== undefined) {
|
|
241
|
+
return { errors: [{ path: '$', message: `YAML parse error: ${raw.error}` }] };
|
|
242
|
+
}
|
|
243
|
+
if (!raw.value) {
|
|
244
|
+
return { errors: [{ path: '$', message: 'workflow must be a YAML mapping' }] };
|
|
186
245
|
}
|
|
187
|
-
const
|
|
246
|
+
const resolved = resolveExtends(raw.value, (name) => rawByName.get(name));
|
|
247
|
+
if (!resolved.value)
|
|
248
|
+
return { errors: resolved.errors };
|
|
249
|
+
const validation = (0, workflow_1.validateWorkflow)(resolved.value);
|
|
188
250
|
if (!validation.ok || !validation.workflow) {
|
|
189
251
|
return { errors: validation.errors };
|
|
190
252
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/workflows/discovery.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCH,
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/workflows/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -41,6 +41,12 @@ export interface ExecuteOptions {
|
|
|
41
41
|
* finalize so a completion hook can recover it (e.g. `{ jira: { issueKey } }`).
|
|
42
42
|
*/
|
|
43
43
|
runMetadata?: Record<string, unknown>;
|
|
44
|
+
/**
|
|
45
|
+
* The headless agent for prompt steps (`--agent`). When unset it is resolved
|
|
46
|
+
* from SPECSHIP_WORKFLOW_AGENT, `workflow.agent`, then the launching host
|
|
47
|
+
* (REQ-AGENTADAPT-006). Either way it is stored on the run.
|
|
48
|
+
*/
|
|
49
|
+
agent?: string;
|
|
44
50
|
}
|
|
45
51
|
/**
|
|
46
52
|
* Invoked once a run settles to `completed` (never paused/failed/cancelled).
|
|
@@ -118,6 +124,10 @@ export declare class WorkflowExecutor {
|
|
|
118
124
|
* For bash/script nodes we substitute `bash` / `script` (with bash-safe
|
|
119
125
|
* shell escaping). For approval nodes we substitute `message`.
|
|
120
126
|
* cancel: substitute `cancel` reason.
|
|
127
|
+
*
|
|
128
|
+
* Prompt nodes also inherit the workflow-level defaults (REQ-AUDFIX-005):
|
|
129
|
+
* `model` applies when the node sets none (node wins); `systemPromptAppend`
|
|
130
|
+
* is the workflow value followed by the node value, joined by a blank line.
|
|
121
131
|
*/
|
|
122
132
|
private resolveNodeRefs;
|
|
123
133
|
private makeSubstitutionContext;
|
|
@@ -138,4 +148,12 @@ export declare class WorkflowExecutor {
|
|
|
138
148
|
* refuses to run a workflow that doesn't form a DAG.
|
|
139
149
|
*/
|
|
140
150
|
export declare function topoSort(nodes: DagNode[]): string[];
|
|
151
|
+
/**
|
|
152
|
+
* REQ-AUDFIX-004: prepare a `failed` run's metadata for a retrying resume.
|
|
153
|
+
* Failed nodes reset to `pending`, and so does every `skipped` node that is
|
|
154
|
+
* (transitively) downstream of a failed node — it was skipped only because of
|
|
155
|
+
* the failure, so it must be re-evaluated. Completed nodes are untouched, so
|
|
156
|
+
* they are not re-run. Pure — returns a new metadata object.
|
|
157
|
+
*/
|
|
158
|
+
export declare function resetFailedNodes(workflow: WorkflowDefinition, metadata: unknown): Record<string, unknown>;
|
|
141
159
|
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/workflows/executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,OAAO,EACL,kBAAkB,EAClB,OAAO,EAOR,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,WAAW,EACX,iBAAiB,EAGlB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAIzD,OAAO,EACL,UAAU,EAIX,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/workflows/executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -51,6 +51,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
51
51
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
52
|
exports.WorkflowExecutor = void 0;
|
|
53
53
|
exports.topoSort = topoSort;
|
|
54
|
+
exports.resetFailedNodes = resetFailedNodes;
|
|
54
55
|
const fs = __importStar(require("fs"));
|
|
55
56
|
const path = __importStar(require("path"));
|
|
56
57
|
const os = __importStar(require("os"));
|
|
@@ -64,6 +65,7 @@ const bash_1 = require("./runners/bash");
|
|
|
64
65
|
const script_1 = require("./runners/script");
|
|
65
66
|
const approval_1 = require("./runners/approval");
|
|
66
67
|
const cancel_1 = require("./runners/cancel");
|
|
68
|
+
const agents_1 = require("./agents");
|
|
67
69
|
class WorkflowExecutor {
|
|
68
70
|
specQueries;
|
|
69
71
|
worktrees;
|
|
@@ -100,6 +102,9 @@ class WorkflowExecutor {
|
|
|
100
102
|
async start(workflow, opts) {
|
|
101
103
|
const runId = opts.runId ?? (0, crypto_1.randomUUID)();
|
|
102
104
|
const now = Date.now();
|
|
105
|
+
// Resolved before anything is created, so an unknown agent leaves no run
|
|
106
|
+
// behind (REQ-AGENTADAPT-006.A4); stored so resume uses the same one (A3).
|
|
107
|
+
const agent = (0, agents_1.resolveWorkflowAgent)({ flag: opts.agent, projectRoot: opts.projectRoot });
|
|
103
108
|
// Pre-flight: required capabilities. `specship` is always available
|
|
104
109
|
// (we're running inside it); `git` and `tests` are checked lazily by
|
|
105
110
|
// the runner that uses them.
|
|
@@ -167,6 +172,7 @@ class WorkflowExecutor {
|
|
|
167
172
|
nodeStates: {},
|
|
168
173
|
completedNodes: [],
|
|
169
174
|
...(opts.runMetadata ?? {}),
|
|
175
|
+
[agents_1.RUN_AGENT_KEY]: agent,
|
|
170
176
|
},
|
|
171
177
|
};
|
|
172
178
|
this.specQueries.insertWorkflowRun(run);
|
|
@@ -200,6 +206,12 @@ class WorkflowExecutor {
|
|
|
200
206
|
lastActivityAt: now,
|
|
201
207
|
errorMessage: undefined,
|
|
202
208
|
};
|
|
209
|
+
// Retry-on-resume (REQ-AUDFIX-004): a `failed` run's failed nodes go back
|
|
210
|
+
// to pending, as do nodes skipped downstream of them, so driveExecution
|
|
211
|
+
// re-runs / re-evaluates them. Completed nodes keep their state + output.
|
|
212
|
+
if (existing.status === 'failed') {
|
|
213
|
+
refreshed.metadata = resetFailedNodes(workflow, refreshed.metadata);
|
|
214
|
+
}
|
|
203
215
|
this.specQueries.updateWorkflowRun(refreshed);
|
|
204
216
|
this.syncActiveRunMarker(refreshed.status, refreshed.inputs, refreshed.id);
|
|
205
217
|
this.event(runId, 'run_started', { resumed: true });
|
|
@@ -222,34 +234,12 @@ class WorkflowExecutor {
|
|
|
222
234
|
this.syncActiveRunMarker('rejected', refreshed.inputs, refreshed.id);
|
|
223
235
|
throw new Error(msg);
|
|
224
236
|
}
|
|
225
|
-
const outputs = new Map(Object.entries(meta.outputs ?? {}));
|
|
226
237
|
const reviseId = `${rejection.nodeId}__revise_${rejection.attempts}`;
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
};
|
|
233
|
-
// Resolve $nodeId.output refs in the on_reject prompt against the
|
|
234
|
-
// run's accumulated outputs, same as any other node.
|
|
235
|
-
const revise = this.resolveNodeRefs(rawRevise, outputs, opts.inputs, opts.variables);
|
|
236
|
-
this.event(runId, 'step_started', { stepId: reviseId, kind: 'prompt', revision: true });
|
|
237
|
-
const runner = this.runners.get('prompt');
|
|
238
|
-
const result = runner
|
|
239
|
-
? await runner.run(revise, {
|
|
240
|
-
cwd,
|
|
241
|
-
artifactsDir,
|
|
242
|
-
logsDir,
|
|
243
|
-
runId,
|
|
244
|
-
inputs: opts.inputs,
|
|
245
|
-
variables: opts.variables,
|
|
246
|
-
outputs,
|
|
247
|
-
verbose: opts.verbose,
|
|
248
|
-
emitEvent: (type, data) => this.event(runId, type, { stepId: reviseId, stepKind: 'prompt', ...data }),
|
|
249
|
-
})
|
|
250
|
-
: { status: 'failed', error: 'no runner for kind prompt' };
|
|
251
|
-
if (result.status !== 'completed') {
|
|
252
|
-
const err = result.status === 'failed' ? result.error : `revise step ${result.status}`;
|
|
238
|
+
// Every failure while preparing OR running the revision (an
|
|
239
|
+
// unresolvable $ref, a runner throw, a failed result) parks the run
|
|
240
|
+
// back at `rejected` with the error — never stuck in `running`
|
|
241
|
+
// (REQ-AUDFIX-003.A3).
|
|
242
|
+
const failRevision = (err) => {
|
|
253
243
|
this.event(runId, 'step_failed', { stepId: reviseId, error: err });
|
|
254
244
|
this.specQueries.updateWorkflowRun({
|
|
255
245
|
...refreshed,
|
|
@@ -257,7 +247,43 @@ class WorkflowExecutor {
|
|
|
257
247
|
errorMessage: `revision failed: ${err}`,
|
|
258
248
|
});
|
|
259
249
|
this.syncActiveRunMarker('rejected', refreshed.inputs, refreshed.id);
|
|
260
|
-
|
|
250
|
+
return new Error(`Run ${runId}: on_reject revision failed: ${err}`);
|
|
251
|
+
};
|
|
252
|
+
const outputs = new Map(Object.entries(meta.outputs ?? {}));
|
|
253
|
+
const rawRevise = {
|
|
254
|
+
id: reviseId,
|
|
255
|
+
kind: 'prompt',
|
|
256
|
+
prompt: `${onReject.prompt}\n\nReviewer feedback (rejection reason):\n` +
|
|
257
|
+
`${rejection.reason ?? '(no reason given)'}`,
|
|
258
|
+
};
|
|
259
|
+
let result;
|
|
260
|
+
try {
|
|
261
|
+
// Resolve $nodeId.output refs in the on_reject prompt against the
|
|
262
|
+
// run's accumulated outputs, same as any other node; workflow-level
|
|
263
|
+
// model/systemPromptAppend apply too (REQ-AUDFIX-005.A2).
|
|
264
|
+
const revise = this.resolveNodeRefs(rawRevise, outputs, opts.inputs, opts.variables, workflow);
|
|
265
|
+
this.event(runId, 'step_started', { stepId: reviseId, kind: 'prompt', revision: true });
|
|
266
|
+
const runner = this.runners.get('prompt');
|
|
267
|
+
result = runner
|
|
268
|
+
? await runner.run(revise, {
|
|
269
|
+
cwd,
|
|
270
|
+
artifactsDir,
|
|
271
|
+
logsDir,
|
|
272
|
+
runId,
|
|
273
|
+
inputs: opts.inputs,
|
|
274
|
+
variables: opts.variables,
|
|
275
|
+
outputs,
|
|
276
|
+
verbose: opts.verbose,
|
|
277
|
+
agent: runAgent(meta),
|
|
278
|
+
emitEvent: (type, data) => this.event(runId, type, { stepId: reviseId, stepKind: 'prompt', ...data }),
|
|
279
|
+
})
|
|
280
|
+
: { status: 'failed', error: 'no runner for kind prompt' };
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
throw failRevision(err instanceof Error ? err.message : String(err));
|
|
284
|
+
}
|
|
285
|
+
if (result.status !== 'completed') {
|
|
286
|
+
throw failRevision(result.status === 'failed' ? result.error : `revise step ${result.status}`);
|
|
261
287
|
}
|
|
262
288
|
this.event(runId, 'step_completed', {
|
|
263
289
|
stepId: reviseId,
|
|
@@ -266,8 +292,12 @@ class WorkflowExecutor {
|
|
|
266
292
|
});
|
|
267
293
|
await this.writeArtifact(artifactsDir, rawRevise, result.output);
|
|
268
294
|
// Persist the revise output + clear the pending rejection so the next
|
|
269
|
-
// reject starts a fresh attempt count from this one.
|
|
295
|
+
// reject starts a fresh attempt count from this one. With `revises`,
|
|
296
|
+
// the revision also REPLACES the revised node's output so every
|
|
297
|
+
// downstream `$<revises>.output` reads it (REQ-AUDFIX-003.A2).
|
|
270
298
|
outputs.set(reviseId, result.output);
|
|
299
|
+
if (onReject.revises)
|
|
300
|
+
outputs.set(onReject.revises, result.output);
|
|
271
301
|
const newMeta = {
|
|
272
302
|
...meta,
|
|
273
303
|
outputs: Object.fromEntries(outputs),
|
|
@@ -467,7 +497,7 @@ class WorkflowExecutor {
|
|
|
467
497
|
// Run the node. Resolve any $refs in node fields first.
|
|
468
498
|
let processed;
|
|
469
499
|
try {
|
|
470
|
-
processed = this.resolveNodeRefs(node, outputs, opts.inputs, opts.variables);
|
|
500
|
+
processed = this.resolveNodeRefs(node, outputs, opts.inputs, opts.variables, workflow);
|
|
471
501
|
}
|
|
472
502
|
catch (err) {
|
|
473
503
|
if (err instanceof condition_evaluator_1.OutputRefError) {
|
|
@@ -499,6 +529,7 @@ class WorkflowExecutor {
|
|
|
499
529
|
variables: opts.variables,
|
|
500
530
|
outputs,
|
|
501
531
|
verbose: opts.verbose,
|
|
532
|
+
agent: runAgent(meta),
|
|
502
533
|
// Stream a step's live activity (agent tool calls / messages) into the
|
|
503
534
|
// run view (WF-STREAM-DOC). Stamp the step id/kind so the UI can group.
|
|
504
535
|
emitEvent: (type, data) => this.event(run.id, type, { stepId: nodeId, stepKind: node.kind, ...data }),
|
|
@@ -522,6 +553,14 @@ class WorkflowExecutor {
|
|
|
522
553
|
}
|
|
523
554
|
case 'failed': {
|
|
524
555
|
nodeStates.set(nodeId, 'failed');
|
|
556
|
+
// Keep what the failed step printed as evidence (REQ-PIPETRUST-006.A2):
|
|
557
|
+
// stored in the run's outputs + written as its artifact. The node
|
|
558
|
+
// stays `failed`, so resume still re-runs it (resetFailedNodes is
|
|
559
|
+
// state-driven) and a successful re-run overwrites this output.
|
|
560
|
+
if (result.output) {
|
|
561
|
+
outputs.set(nodeId, result.output);
|
|
562
|
+
await this.writeArtifact(artifactsDir, node, result.output);
|
|
563
|
+
}
|
|
525
564
|
this.event(run.id, 'step_failed', { stepId: nodeId, error: result.error });
|
|
526
565
|
await this.finalize(run, workflow, nodeStates, outputs, 'failed', result.error);
|
|
527
566
|
return { run, nodeStates, outputs };
|
|
@@ -595,17 +634,25 @@ class WorkflowExecutor {
|
|
|
595
634
|
* For bash/script nodes we substitute `bash` / `script` (with bash-safe
|
|
596
635
|
* shell escaping). For approval nodes we substitute `message`.
|
|
597
636
|
* cancel: substitute `cancel` reason.
|
|
637
|
+
*
|
|
638
|
+
* Prompt nodes also inherit the workflow-level defaults (REQ-AUDFIX-005):
|
|
639
|
+
* `model` applies when the node sets none (node wins); `systemPromptAppend`
|
|
640
|
+
* is the workflow value followed by the node value, joined by a blank line.
|
|
598
641
|
*/
|
|
599
|
-
resolveNodeRefs(node, outputs, inputs, variables) {
|
|
642
|
+
resolveNodeRefs(node, outputs, inputs, variables, workflow) {
|
|
600
643
|
const ctx = this.makeSubstitutionContext(outputs, inputs, variables);
|
|
601
644
|
switch (node.kind) {
|
|
602
645
|
case 'prompt': {
|
|
603
646
|
const p = node;
|
|
647
|
+
const model = p.model ?? workflow?.model;
|
|
648
|
+
const appendParts = [workflow?.systemPromptAppend, p.systemPromptAppend].filter((v) => typeof v === 'string' && v.length > 0);
|
|
649
|
+
const systemPromptAppend = appendParts.length > 0 ? appendParts.join('\n\n') : undefined;
|
|
604
650
|
return {
|
|
605
651
|
...p,
|
|
652
|
+
...(model !== undefined ? { model } : {}),
|
|
606
653
|
prompt: (0, condition_evaluator_1.substituteRefs)(p.prompt, ctx, { forBash: false, nodeId: p.id }),
|
|
607
|
-
systemPromptAppend:
|
|
608
|
-
? (0, condition_evaluator_1.substituteRefs)(
|
|
654
|
+
systemPromptAppend: systemPromptAppend
|
|
655
|
+
? (0, condition_evaluator_1.substituteRefs)(systemPromptAppend, ctx, { forBash: false, nodeId: p.id })
|
|
609
656
|
: undefined,
|
|
610
657
|
};
|
|
611
658
|
}
|
|
@@ -699,6 +746,9 @@ class WorkflowExecutor {
|
|
|
699
746
|
// reject → resume → re-pause cycles (WF-REJECT-DOC, REQ-WFREJ-003).
|
|
700
747
|
if (prevMeta.rejection !== undefined)
|
|
701
748
|
meta.rejection = prevMeta.rejection;
|
|
749
|
+
// The run's agent stays fixed for every later step (REQ-AGENTADAPT-006.A3).
|
|
750
|
+
if (prevMeta[agents_1.RUN_AGENT_KEY] !== undefined)
|
|
751
|
+
meta[agents_1.RUN_AGENT_KEY] = prevMeta[agents_1.RUN_AGENT_KEY];
|
|
702
752
|
const updated = {
|
|
703
753
|
...run,
|
|
704
754
|
status,
|
|
@@ -812,10 +862,57 @@ function topoSort(nodes) {
|
|
|
812
862
|
}
|
|
813
863
|
return out;
|
|
814
864
|
}
|
|
865
|
+
/**
|
|
866
|
+
* REQ-AUDFIX-004: prepare a `failed` run's metadata for a retrying resume.
|
|
867
|
+
* Failed nodes reset to `pending`, and so does every `skipped` node that is
|
|
868
|
+
* (transitively) downstream of a failed node — it was skipped only because of
|
|
869
|
+
* the failure, so it must be re-evaluated. Completed nodes are untouched, so
|
|
870
|
+
* they are not re-run. Pure — returns a new metadata object.
|
|
871
|
+
*/
|
|
872
|
+
function resetFailedNodes(workflow, metadata) {
|
|
873
|
+
const meta = { ...(metadata ?? {}) };
|
|
874
|
+
const states = { ...(meta.nodeStates ?? {}) };
|
|
875
|
+
const failed = Object.keys(states).filter((id) => states[id] === 'failed');
|
|
876
|
+
if (failed.length === 0)
|
|
877
|
+
return meta;
|
|
878
|
+
// Dependents adjacency: id → nodes that depend on it.
|
|
879
|
+
const dependents = new Map();
|
|
880
|
+
for (const n of workflow.nodes) {
|
|
881
|
+
for (const dep of n.depends_on ?? []) {
|
|
882
|
+
const list = dependents.get(dep) ?? [];
|
|
883
|
+
list.push(n.id);
|
|
884
|
+
dependents.set(dep, list);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
const downstream = new Set();
|
|
888
|
+
const queue = [...failed];
|
|
889
|
+
while (queue.length > 0) {
|
|
890
|
+
const id = queue.shift();
|
|
891
|
+
for (const next of dependents.get(id) ?? []) {
|
|
892
|
+
if (!downstream.has(next)) {
|
|
893
|
+
downstream.add(next);
|
|
894
|
+
queue.push(next);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
for (const id of failed)
|
|
899
|
+
states[id] = 'pending';
|
|
900
|
+
for (const id of downstream) {
|
|
901
|
+
if (states[id] === 'skipped')
|
|
902
|
+
states[id] = 'pending';
|
|
903
|
+
}
|
|
904
|
+
meta.nodeStates = states;
|
|
905
|
+
return meta;
|
|
906
|
+
}
|
|
815
907
|
function sanitizeFilename(s) {
|
|
816
908
|
return s.replace(/[^a-zA-Z0-9._-]/g, '-').substring(0, 80);
|
|
817
909
|
}
|
|
818
910
|
function sleep(ms) {
|
|
819
911
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
820
912
|
}
|
|
913
|
+
/** The agent stored with a run; undefined for runs created before agents were recorded (→ default). */
|
|
914
|
+
function runAgent(meta) {
|
|
915
|
+
const a = meta[agents_1.RUN_AGENT_KEY];
|
|
916
|
+
return typeof a === 'string' && a ? a : undefined;
|
|
917
|
+
}
|
|
821
918
|
//# sourceMappingURL=executor.js.map
|