@opengsd/gsd-core 1.12.0 → 1.14.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +12 -0
- package/agents/gsd-advisor-researcher.compact.md +85 -0
- package/agents/gsd-ai-researcher.compact.md +96 -0
- package/agents/gsd-assumptions-analyzer.compact.md +81 -0
- package/agents/gsd-code-fixer.compact.md +458 -0
- package/agents/gsd-code-fixer.md +5 -5
- package/agents/gsd-code-reviewer.compact.md +269 -0
- package/agents/gsd-code-reviewer.md +15 -3
- package/agents/gsd-codebase-mapper.compact.md +760 -0
- package/agents/gsd-debug-session-manager.compact.md +345 -0
- package/agents/gsd-doc-classifier.compact.md +192 -0
- package/agents/gsd-doc-synthesizer.compact.md +200 -0
- package/agents/gsd-doc-verifier.compact.md +143 -0
- package/agents/gsd-doc-writer.compact.md +440 -0
- package/agents/gsd-dom-verifier.compact.md +138 -0
- package/agents/gsd-domain-researcher.compact.md +141 -0
- package/agents/gsd-eval-auditor.compact.md +160 -0
- package/agents/gsd-eval-planner.compact.md +137 -0
- package/agents/gsd-executor.md +63 -35
- package/agents/gsd-framework-selector.compact.md +82 -0
- package/agents/gsd-integration-checker.compact.md +245 -0
- package/agents/gsd-intel-updater.compact.md +226 -0
- package/agents/gsd-mempalace-curator.compact.md +45 -0
- package/agents/gsd-nyquist-auditor.compact.md +179 -0
- package/agents/gsd-pattern-mapper.compact.md +275 -0
- package/agents/gsd-plan-checker.md +76 -57
- package/agents/gsd-planner.md +14 -0
- package/agents/gsd-project-researcher.compact.md +587 -0
- package/agents/gsd-research-synthesizer.compact.md +212 -0
- package/agents/gsd-roadmapper.compact.md +454 -0
- package/agents/gsd-roadmapper.md +13 -0
- package/agents/gsd-security-auditor.compact.md +162 -0
- package/agents/gsd-ui-auditor.compact.md +404 -0
- package/agents/gsd-ui-checker.compact.md +277 -0
- package/agents/gsd-ui-checker.md +19 -3
- package/agents/gsd-ui-researcher.compact.md +282 -0
- package/agents/gsd-ui-researcher.md +29 -0
- package/agents/gsd-user-profiler.compact.md +108 -0
- package/agents/gsd-verifier.md +23 -1
- package/bin/install.js +444 -134
- package/commands/gsd/cleanup.md +1 -0
- package/commands/gsd/code-review.md +2 -1
- package/commands/gsd/complete-milestone.md +1 -0
- package/commands/gsd/config.md +1 -0
- package/commands/gsd/debug.md +1 -0
- package/commands/gsd/execute-phase.md +1 -1
- package/commands/gsd/graphify.md +1 -0
- package/commands/gsd/health.md +1 -0
- package/commands/gsd/mempalace-capture.md +1 -0
- package/commands/gsd/mempalace-recall.md +1 -0
- package/commands/gsd/new-milestone.md +1 -0
- package/commands/gsd/new-project.md +1 -0
- package/commands/gsd/next.md +1 -0
- package/commands/gsd/ns-workflow.md +2 -1
- package/commands/gsd/pause-work.md +1 -0
- package/commands/gsd/phase.md +2 -1
- package/commands/gsd/pr-branch.md +1 -0
- package/commands/gsd/quick-batch.md +105 -0
- package/commands/gsd/resume-work.md +1 -0
- package/commands/gsd/review-backlog.md +1 -0
- package/commands/gsd/settings.md +2 -1
- package/commands/gsd/stats.md +1 -0
- package/commands/gsd/surface.md +18 -8
- package/commands/gsd/thread.md +1 -0
- package/commands/gsd/workspace.md +1 -0
- package/commands/gsd/workstreams.md +1 -0
- package/gsd-core/bin/check-latest-version.cjs +8 -3
- package/gsd-core/bin/gsd-tools.cjs +532 -174
- package/gsd-core/bin/lib/adr-parser.cjs +1 -1
- package/gsd-core/bin/lib/artifacts.cjs +2 -1
- package/gsd-core/bin/lib/audit.cjs +39 -22
- package/gsd-core/bin/lib/broken-windows.cjs +168 -49
- package/gsd-core/bin/lib/capability-activation.cjs +27 -0
- package/gsd-core/bin/lib/capability-lifecycle.cjs +10 -6
- package/gsd-core/bin/lib/capability-loader.cjs +135 -1
- package/gsd-core/bin/lib/capability-registry.cjs +528 -116
- package/gsd-core/bin/lib/capability-source.cjs +19 -2
- package/gsd-core/bin/lib/capability-state.cjs +7 -1
- package/gsd-core/bin/lib/capability-validator.cjs +134 -5
- package/gsd-core/bin/lib/capability-writer.cjs +14 -4
- package/gsd-core/bin/lib/check-command-router.cjs +198 -38
- package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
- package/gsd-core/bin/lib/clusters.cjs +1 -0
- package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
- package/gsd-core/bin/lib/command-aliases.cjs +16 -0
- package/gsd-core/bin/lib/commands.cjs +981 -79
- package/gsd-core/bin/lib/config-loader.cjs +4 -0
- package/gsd-core/bin/lib/config.cjs +153 -38
- package/gsd-core/bin/lib/core-utils.cjs +34 -7
- package/gsd-core/bin/lib/coverage.cjs +1 -1
- package/gsd-core/bin/lib/decisions.cjs +343 -28
- package/gsd-core/bin/lib/edge-probe.cjs +14 -1
- package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
- package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
- package/gsd-core/bin/lib/frontmatter.cjs +137 -23
- package/gsd-core/bin/lib/gap-checker.cjs +22 -13
- package/gsd-core/bin/lib/git-base-branch.cjs +10 -2
- package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +54 -11
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +87 -23
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
- package/gsd-core/bin/lib/host-integration.cjs +57 -5
- package/gsd-core/bin/lib/init-command-router.cjs +14 -0
- package/gsd-core/bin/lib/init.cjs +539 -60
- package/gsd-core/bin/lib/install-engine.cjs +199 -14
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +45 -0
- package/gsd-core/bin/lib/install-profiles.cjs +36 -14
- package/gsd-core/bin/lib/installer-migration-report.cjs +1 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +33 -4
- package/gsd-core/bin/lib/io.cjs +35 -0
- package/gsd-core/bin/lib/loop-resolver.cjs +64 -39
- package/gsd-core/bin/lib/markdown-table.cjs +123 -0
- package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
- package/gsd-core/bin/lib/milestone.cjs +41 -10
- package/gsd-core/bin/lib/model-resolver.cjs +101 -10
- package/gsd-core/bin/lib/phase-command-router.cjs +20 -7
- package/gsd-core/bin/lib/phase-id.cjs +412 -31
- package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
- package/gsd-core/bin/lib/phase.cjs +941 -98
- package/gsd-core/bin/lib/plan-document.cjs +10 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +34 -18
- package/gsd-core/bin/lib/planning-snapshot.cjs +206 -30
- package/gsd-core/bin/lib/planning-workspace.cjs +153 -29
- package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
- package/gsd-core/bin/lib/quick-batch-command-router.cjs +285 -0
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
- package/gsd-core/bin/lib/quick-batch.cjs +840 -0
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +61 -2
- package/gsd-core/bin/lib/research-store.cjs +11 -12
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +53 -5
- package/gsd-core/bin/lib/review-lane-invocation.cjs +96 -1
- package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
- package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
- package/gsd-core/bin/lib/roadmap-parser.cjs +555 -41
- package/gsd-core/bin/lib/roadmap.cjs +292 -69
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +260 -43
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +28 -20
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +294 -108
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +408 -47
- package/gsd-core/bin/lib/security.cjs +126 -7
- package/gsd-core/bin/lib/shell-command-projection.cjs +4 -0
- package/gsd-core/bin/lib/smart-entry.cjs +7 -9
- package/gsd-core/bin/lib/state-document.cjs +159 -32
- package/gsd-core/bin/lib/state-md-schema.cjs +44 -27
- package/gsd-core/bin/lib/state-transition.cjs +465 -62
- package/gsd-core/bin/lib/state.cjs +906 -151
- package/gsd-core/bin/lib/surface.cjs +83 -10
- package/gsd-core/bin/lib/task-command-router.cjs +12 -6
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
- package/gsd-core/bin/lib/uat.cjs +1420 -516
- package/gsd-core/bin/lib/update-context.cjs +36 -26
- package/gsd-core/bin/lib/validate.cjs +230 -12
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +316 -23
- package/gsd-core/bin/lib/verify-command-grounding.cjs +1 -1
- package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
- package/gsd-core/bin/lib/verify.cjs +531 -36
- package/gsd-core/bin/lib/workstream-inventory.cjs +21 -2
- package/gsd-core/bin/lib/worktree-safety.cjs +21 -7
- package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +13 -0
- package/gsd-core/bin/verify-reapply-patches.cjs +507 -81
- package/gsd-core/references/agent-contracts.md +3 -3
- package/gsd-core/references/compact-content-gate.md +66 -0
- package/gsd-core/references/edge-probe.md +17 -13
- package/gsd-core/references/execute-mvp-tdd.md +18 -16
- package/gsd-core/references/execute-phase-response-language.md +6 -0
- package/gsd-core/references/executor-examples.md +42 -0
- package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
- package/gsd-core/references/loop-hook-dispatch.md +18 -0
- package/gsd-core/references/model-profiles.md +12 -3
- package/gsd-core/references/mvp-concepts.md +2 -2
- package/gsd-core/references/plan-checker-examples.md +41 -0
- package/gsd-core/references/planner-antipatterns.md +25 -0
- package/gsd-core/references/planner-chunked.md +5 -1
- package/gsd-core/references/planner-coupling.md +42 -0
- package/gsd-core/references/planner-quick-batch.md +71 -0
- package/gsd-core/references/planner-reviews.md +47 -0
- package/gsd-core/references/planner-revision.md +75 -2
- package/gsd-core/references/planning-config.md +5 -1
- package/gsd-core/references/response-language-directive.md +9 -0
- package/gsd-core/references/revision-loop.md +118 -11
- package/gsd-core/references/tdd.md +17 -9
- package/gsd-core/references/thinking-models-planning.md +18 -2
- package/gsd-core/references/verification-patterns.md +17 -4
- package/gsd-core/references/verifier-evidence-gate.md +160 -0
- package/gsd-core/references/worktree-path-safety.md +112 -2
- package/gsd-core/templates/README.md +7 -1
- package/gsd-core/templates/phase-prompt.md +4 -0
- package/gsd-core/templates/state.md +6 -3
- package/gsd-core/templates/summary.compact.md +212 -0
- package/gsd-core/templates/user-setup.compact.md +199 -0
- package/gsd-core/templates/user-setup.md +0 -9
- package/gsd-core/templates/verification-report.md +5 -0
- package/gsd-core/workflows/add-backlog.md +2 -0
- package/gsd-core/workflows/add-phase.md +2 -0
- package/gsd-core/workflows/add-tests.md +1 -1
- package/gsd-core/workflows/add-todo.md +4 -3
- package/gsd-core/workflows/ai-integration-phase.md +1 -1
- package/gsd-core/workflows/analyze-dependencies.md +2 -0
- package/gsd-core/workflows/audit-fix.md +2 -0
- package/gsd-core/workflows/audit-milestone.md +2 -0
- package/gsd-core/workflows/audit-uat.md +2 -0
- package/gsd-core/workflows/autonomous.md +15 -10
- package/gsd-core/workflows/check-todos.md +5 -3
- package/gsd-core/workflows/cleanup.md +4 -2
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +22 -13
- package/gsd-core/workflows/code-review-fix.md +5 -3
- package/gsd-core/workflows/code-review.md +211 -43
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
- package/gsd-core/workflows/complete-milestone.md +40 -254
- package/gsd-core/workflows/debug.md +1 -1
- package/gsd-core/workflows/diagnose-issues.md +5 -1
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/text.md +2 -0
- package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
- package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
- package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
- package/gsd-core/workflows/discuss-phase-power.md +2 -0
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +43 -13
- package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
- package/gsd-core/workflows/docs-update.md +15 -156
- package/gsd-core/workflows/edit-phase.md +2 -0
- package/gsd-core/workflows/eval-review.md +1 -1
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +20 -3
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +24 -3
- package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +8 -2
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
- package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
- package/gsd-core/workflows/execute-phase.md +78 -159
- package/gsd-core/workflows/execute-plan.md +28 -15
- package/gsd-core/workflows/explore.md +2 -0
- package/gsd-core/workflows/extract-learnings.md +2 -0
- package/gsd-core/workflows/fast.md +6 -0
- package/gsd-core/workflows/forensics.md +2 -0
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +1 -1
- package/gsd-core/workflows/help/modes/brief.md +2 -0
- package/gsd-core/workflows/help/modes/default.md +2 -0
- package/gsd-core/workflows/help/modes/full.compact.md +398 -0
- package/gsd-core/workflows/help/modes/full.md +12 -0
- package/gsd-core/workflows/help/modes/topic.md +2 -0
- package/gsd-core/workflows/help.md +3 -1
- package/gsd-core/workflows/import.md +3 -3
- package/gsd-core/workflows/inbox.md +1 -1
- package/gsd-core/workflows/ingest-docs.md +1 -1
- package/gsd-core/workflows/insert-phase.md +2 -0
- package/gsd-core/workflows/list-phase-assumptions.md +2 -0
- package/gsd-core/workflows/list-seeds.md +2 -0
- package/gsd-core/workflows/list-workspaces.md +2 -0
- package/gsd-core/workflows/manager.md +3 -3
- package/gsd-core/workflows/map-codebase.md +52 -3
- package/gsd-core/workflows/milestone-summary.md +2 -0
- package/gsd-core/workflows/mvp-phase.md +1 -1
- package/gsd-core/workflows/new-milestone.md +55 -13
- package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
- package/gsd-core/workflows/new-project.md +37 -205
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +2 -0
- package/gsd-core/workflows/node-repair.md +2 -0
- package/gsd-core/workflows/note.md +2 -0
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +19 -4
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -0
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +9 -0
- package/gsd-core/workflows/plan-phase.md +144 -185
- package/gsd-core/workflows/plan-review-convergence.md +102 -10
- package/gsd-core/workflows/plant-seed.md +1 -1
- package/gsd-core/workflows/pr-branch.md +30 -10
- package/gsd-core/workflows/profile-user.md +1 -1
- package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
- package/gsd-core/workflows/progress.md +25 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +37 -2
- package/gsd-core/workflows/quick/steps/research-phase.md +3 -3
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
- package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
- package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
- package/gsd-core/workflows/quick-batch.md +203 -0
- package/gsd-core/workflows/quick.md +21 -4
- package/gsd-core/workflows/reapply-patches.md +79 -3
- package/gsd-core/workflows/remove-phase.md +2 -0
- package/gsd-core/workflows/remove-workspace.md +1 -1
- package/gsd-core/workflows/resume-project.md +6 -2
- package/gsd-core/workflows/review.md +215 -10
- package/gsd-core/workflows/scan.md +2 -0
- package/gsd-core/workflows/section-manifest.json +12 -0
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/session-report.md +2 -0
- package/gsd-core/workflows/settings-advanced.md +2 -0
- package/gsd-core/workflows/settings-integrations.md +9 -8
- package/gsd-core/workflows/settings.md +19 -6
- package/gsd-core/workflows/ship.md +10 -10
- package/gsd-core/workflows/sketch-wrap-up.md +2 -0
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +1 -1
- package/gsd-core/workflows/spec-phase.md +24 -19
- package/gsd-core/workflows/spike-wrap-up.md +2 -0
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +2 -0
- package/gsd-core/workflows/sync-skills.md +12 -4
- package/gsd-core/workflows/thread.md +2 -0
- package/gsd-core/workflows/transition.md +2 -0
- package/gsd-core/workflows/ui-phase.md +26 -5
- package/gsd-core/workflows/ui-review.md +1 -1
- package/gsd-core/workflows/ultraplan-phase.md +2 -0
- package/gsd-core/workflows/undo.md +1 -1
- package/gsd-core/workflows/update.md +48 -43
- package/gsd-core/workflows/validate-phase.md +1 -1
- package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
- package/gsd-core/workflows/verify-work.md +68 -182
- package/hooks/dist/gsd-agent-isolation-guard.js +42 -16
- package/hooks/dist/gsd-check-update-worker.js +19 -2
- package/hooks/dist/gsd-context-monitor.js +371 -27
- package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
- package/hooks/dist/gsd-node-runner.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +30 -5
- package/hooks/dist/gsd-read-guard.js +2 -0
- package/hooks/dist/gsd-read-injection-scanner.js +5 -5
- package/hooks/dist/gsd-secret-read-guard.js +1105 -0
- package/hooks/dist/gsd-statusline.js +18 -10
- package/hooks/dist/gsd-validate-commit.sh +474 -7
- package/hooks/dist/gsd-workflow-guard.js +2 -1
- package/hooks/dist/gsd-worktree-path-guard.js +25 -14
- package/hooks/dist/gsd-write-guard.js +46 -1
- package/hooks/dist/lib/dispatch-identity.js +187 -0
- package/hooks/dist/lib/filename-classification.js +64 -0
- package/hooks/dist/lib/git-cmd.js +210 -1
- package/hooks/dist/lib/injection-patterns.js +36 -6
- package/hooks/dist/lib/isolation-deny-reason.js +53 -1
- package/hooks/dist/lib/isolation-sentinel.js +58 -19
- package/hooks/dist/managed-hooks-registry.cjs +1 -0
- package/hooks/gsd-agent-isolation-guard.js +42 -16
- package/hooks/gsd-check-update-worker.js +19 -2
- package/hooks/gsd-context-monitor.js +371 -27
- package/hooks/gsd-cursor-subagent-start.js +34 -14
- package/hooks/gsd-node-runner.sh +1 -0
- package/hooks/gsd-prompt-guard.js +30 -5
- package/hooks/gsd-read-guard.js +2 -0
- package/hooks/gsd-read-injection-scanner.js +5 -5
- package/hooks/gsd-secret-read-guard.js +1105 -0
- package/hooks/gsd-statusline.js +18 -10
- package/hooks/gsd-validate-commit.sh +474 -7
- package/hooks/gsd-workflow-guard.js +2 -1
- package/hooks/gsd-worktree-path-guard.js +25 -14
- package/hooks/gsd-write-guard.js +46 -1
- package/hooks/hooks.json +6 -0
- package/hooks/lib/dispatch-identity.js +187 -0
- package/hooks/lib/filename-classification.js +64 -0
- package/hooks/lib/git-cmd.js +210 -1
- package/hooks/lib/injection-patterns.js +36 -6
- package/hooks/lib/isolation-deny-reason.js +53 -1
- package/hooks/lib/isolation-sentinel.js +58 -19
- package/hooks/managed-hooks-registry.cjs +1 -0
- package/package.json +13 -9
- package/scripts/benchmark-compact-content-variants.cjs +298 -0
- package/scripts/benchmark-compact-content.cjs +368 -0
- package/scripts/build-hooks.js +11 -4
- package/scripts/check-contract-drift.cjs +4 -1
- package/scripts/check-env.cjs +36 -8
- package/scripts/check-glossary-refs.cjs +25 -21
- package/scripts/ci-next-health.cjs +271 -0
- package/scripts/ci-prepare-test-scope.cjs +7 -7
- package/scripts/ci-test-scope.cjs +133 -20
- package/scripts/ci-timeout-report.cjs +1 -1
- package/scripts/diff-touches-shipped-paths.cjs +1 -1
- package/scripts/docs-guard-registry.cjs +17 -2
- package/scripts/gen-adr-index.cjs +8 -2
- package/scripts/gen-inventory-manifest.cjs +12 -0
- package/scripts/gen-loop-host-contract.cjs +67 -15
- package/scripts/gen-platform-conformance-tier.cjs +557 -0
- package/scripts/lib/drift-scan.cjs +1 -1
- package/scripts/lib/macos-conformance-tier.generated.cjs +210 -0
- package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
- package/scripts/lib/platform-conformance-tier.generated.cjs +276 -0
- package/scripts/lib/shellcheck-fetch.cjs +247 -0
- package/scripts/lib/suite-detection.cjs +32 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- package/scripts/lint-allowed-tools-parity.cjs +221 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +24 -2
- package/scripts/lint-phase-enumeration-drift.cjs +24 -6
- package/scripts/lint-phase-id-drift.cjs +465 -15
- package/scripts/lint-portable-grep.cjs +176 -0
- package/scripts/lint-response-language-coverage.cjs +530 -0
- package/scripts/lint-source-test-name-collision.cjs +1 -1
- package/scripts/lint-test-file-count.allowlist.json +4 -1
- package/scripts/lint-vendored-deps.cjs +128 -17
- package/scripts/lint-workflow-shellcheck-baseline.json +1112 -0
- package/scripts/lint-workflow-shellcheck.cjs +614 -0
- package/scripts/npm-audit-baseline.cjs +376 -0
- package/scripts/prompt-injection-scan.sh +22 -0
- package/scripts/require-issue-link-policy.cjs +16 -1
- package/scripts/workflow-size.cjs +139 -0
- package/skills/gsd-cleanup/SKILL.md +1 -0
- package/skills/gsd-code-review/SKILL.md +2 -1
- package/skills/gsd-complete-milestone/SKILL.md +1 -0
- package/skills/gsd-config/SKILL.md +1 -0
- package/skills/gsd-debug/SKILL.md +1 -0
- package/skills/gsd-execute-phase/SKILL.md +1 -1
- package/skills/gsd-graphify/SKILL.md +1 -0
- package/skills/gsd-health/SKILL.md +1 -0
- package/skills/gsd-mempalace-capture/SKILL.md +1 -0
- package/skills/gsd-mempalace-recall/SKILL.md +1 -0
- package/skills/gsd-new-milestone/SKILL.md +1 -0
- package/skills/gsd-new-project/SKILL.md +1 -0
- package/skills/gsd-next/SKILL.md +1 -0
- package/skills/gsd-ns-workflow/SKILL.md +1 -0
- package/skills/gsd-pause-work/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +2 -1
- package/skills/gsd-pr-branch/SKILL.md +1 -0
- package/skills/gsd-quick-batch/SKILL.md +105 -0
- package/skills/gsd-resume-work/SKILL.md +1 -0
- package/skills/gsd-review-backlog/SKILL.md +1 -0
- package/skills/gsd-settings/SKILL.md +2 -1
- package/skills/gsd-stats/SKILL.md +1 -0
- package/skills/gsd-surface/SKILL.md +18 -8
- package/skills/gsd-thread/SKILL.md +1 -0
- package/skills/gsd-workspace/SKILL.md +1 -0
- package/skills/gsd-workstreams/SKILL.md +1 -0
- package/vscode/package.json +1 -1
- package/gsd-core/templates/claude-md.md +0 -145
- package/gsd-core/templates/codebase/concerns.md +0 -310
- package/gsd-core/templates/codebase/conventions.md +0 -307
- package/gsd-core/templates/codebase/integrations.md +0 -280
- package/gsd-core/templates/codebase/structure.md +0 -285
- package/gsd-core/templates/codebase/testing.md +0 -480
- package/gsd-core/templates/debug-subagent-prompt.md +0 -91
- package/gsd-core/templates/discovery.md +0 -146
|
@@ -14,7 +14,13 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
14
14
|
const node_child_process_1 = require("node:child_process");
|
|
15
15
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
16
16
|
const io = require("./io.cjs");
|
|
17
|
-
const { output,
|
|
17
|
+
const { output, ERROR_REASON } = io;
|
|
18
|
+
// Explicitly annotated so TypeScript applies never-return control-flow narrowing.
|
|
19
|
+
// A destructured `const { error } = io` is a const WITHOUT a type annotation, and TS
|
|
20
|
+
// only narrows after a never-returning call when the callee is a function declaration
|
|
21
|
+
// or an annotated const. Without the annotation every `error(...)` guard below would
|
|
22
|
+
// need a dead `throw` after it to convince the checker that the value is non-null.
|
|
23
|
+
const error = io.error;
|
|
18
24
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
19
25
|
const planningWorkspaceMod = require("./planning-workspace.cjs");
|
|
20
26
|
const { planningDir } = planningWorkspaceMod;
|
|
@@ -31,7 +37,7 @@ const ui_safety_gate_cjs_1 = require("./ui-safety-gate.cjs");
|
|
|
31
37
|
const ui_frontend_evidence_cjs_1 = require("./ui-frontend-evidence.cjs");
|
|
32
38
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
33
39
|
const verifyModule = require("./verify.cjs");
|
|
34
|
-
const { cmdVerifySchemaDrift, cmdVerifyCodebaseDrift } = verifyModule;
|
|
40
|
+
const { cmdVerifySchemaDrift, cmdVerifyCodebaseDrift, cmdVerifyContextDrift } = verifyModule;
|
|
35
41
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
36
42
|
const roadmapModule = require("./roadmap.cjs");
|
|
37
43
|
const { getRoadmapPhaseWithFallback } = roadmapModule;
|
|
@@ -39,6 +45,7 @@ const { getRoadmapPhaseWithFallback } = roadmapModule;
|
|
|
39
45
|
const gapCheckerModule = require("./gap-checker.cjs");
|
|
40
46
|
const { runGapAnalysis } = gapCheckerModule;
|
|
41
47
|
const prohibition_enforcement_cjs_1 = require("./prohibition-enforcement.cjs");
|
|
48
|
+
const tdd_red_evidence_cjs_1 = require("./tdd-red-evidence.cjs");
|
|
42
49
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
43
50
|
const gatePredicateEval = require("./gate-predicate-evaluator.cjs");
|
|
44
51
|
const { evaluatePredicate } = gatePredicateEval;
|
|
@@ -88,7 +95,12 @@ function readIfExists(filePath) {
|
|
|
88
95
|
}
|
|
89
96
|
}
|
|
90
97
|
function resolvePath(inputPath, projectDir) {
|
|
91
|
-
|
|
98
|
+
const candidate = node_path_1.default.isAbsolute(inputPath) ? inputPath : node_path_1.default.join(projectDir, inputPath);
|
|
99
|
+
const contained = (0, security_cjs_1.tryWithinRoot)(candidate, projectDir, security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
100
|
+
if (contained === null) {
|
|
101
|
+
error(`path escapes its allowed directory: ${inputPath}`, ERROR_REASON.USAGE);
|
|
102
|
+
}
|
|
103
|
+
return contained;
|
|
92
104
|
}
|
|
93
105
|
function readWorkflowConfig(projectDir) {
|
|
94
106
|
const configPath = node_path_1.default.join(projectDir, '.planning', 'config.json');
|
|
@@ -271,9 +283,34 @@ function loadDecisionExtraction(contextPath) {
|
|
|
271
283
|
outcome: extraction.outcome,
|
|
272
284
|
};
|
|
273
285
|
}
|
|
286
|
+
/**
|
|
287
|
+
* `check decision-coverage-plan` — blocking plan-phase decision-coverage gate
|
|
288
|
+
* (#2492, #1365 fail-loud, #2770 empty-arg fail-closed).
|
|
289
|
+
*
|
|
290
|
+
* Invocation (the context path may be supplied EITHER way; #4130 follow-up):
|
|
291
|
+
* gsd_run check decision-coverage-plan <phase-dir> <context-path> (positional, the workflow caller's form)
|
|
292
|
+
* gsd_run check decision-coverage-plan --context <path> [<phase-dir>]
|
|
293
|
+
*
|
|
294
|
+
* `--context <path>` follows the sibling flag convention (`check predicate`,
|
|
295
|
+
* #2008): `--flag value` pairs parsed by the shared partitionPredicateArgs
|
|
296
|
+
* pass, the flag WINNING over a same-purpose positional when both appear,
|
|
297
|
+
* and a valueless `--context` counting as no context at all (it falls
|
|
298
|
+
* through to the #2770 caller-error branch, not to the "CONTEXT.md missing"
|
|
299
|
+
* green skip). The positional form keeps working unchanged — no sibling
|
|
300
|
+
* check verb deprecates positionals and the plan-phase workflow passes them.
|
|
301
|
+
*/
|
|
274
302
|
function cmdDecisionCoveragePlan(projectDir, args, raw) {
|
|
275
|
-
|
|
276
|
-
|
|
303
|
+
// args[0]='check', args[1]=subcommand — partition the REST so flag tokens
|
|
304
|
+
// and their values never land in a positional slot.
|
|
305
|
+
const { flags, positionals } = partitionPredicateArgs(args.slice(2));
|
|
306
|
+
const phaseDir = positionals[0] ? resolvePath(positionals[0], projectDir) : '';
|
|
307
|
+
// A VALUELESS `--context` stays a bare token in the positionals (sibling
|
|
308
|
+
// parser semantics); it must not then be read as the context PATH — a
|
|
309
|
+
// `--`-prefixed "path" is a caller mistake, and #2770's law says a missing
|
|
310
|
+
// context argument fails CLOSED, never a silent "CONTEXT.md missing" green
|
|
311
|
+
// skip. So only a non-flag positional may serve as the context.
|
|
312
|
+
const positionalContext = positionals[1] && !positionals[1].startsWith('--') ? positionals[1] : '';
|
|
313
|
+
const contextArg = flags['context'] ?? positionalContext ?? '';
|
|
277
314
|
const contextPath = contextArg ? resolvePath(contextArg, projectDir) : '';
|
|
278
315
|
if (!gateEnabled(projectDir)) {
|
|
279
316
|
output({ passed: true, skipped: true, reason: 'workflow.context_coverage_gate is false', total: 0, covered: 0, uncovered: [], message: 'Decision coverage gate disabled by config.' }, raw, undefined);
|
|
@@ -308,12 +345,15 @@ function cmdDecisionCoveragePlan(projectDir, args, raw) {
|
|
|
308
345
|
uncovered: [],
|
|
309
346
|
message: partialParse
|
|
310
347
|
? 'Decision coverage gate: decisions could not be fully parsed — one or more ' +
|
|
311
|
-
'`- **D-NN ...**` bullets appear malformed (missing `:` or ` — ` separator
|
|
312
|
-
'
|
|
348
|
+
'`- **D-NN ...**` bullets appear malformed (missing `:` or ` — ` separator, or a phase ' +
|
|
349
|
+
'prefix that is not a digit run, e.g. `D4x-01`). Fix the bullet format so all decisions ' +
|
|
350
|
+
'can be read before re-running the gate.'
|
|
313
351
|
: 'Decision coverage gate: could not parse decisions — possible format mismatch. ' +
|
|
314
352
|
'The CONTEXT.md appears to be decision-shaped (has a <decisions> block, a decisions heading, ' +
|
|
315
|
-
'or D- tokens) but no
|
|
316
|
-
'block and ensure bullets follow the `- **D-NN:** text
|
|
353
|
+
'or D- tokens) but no decision bullets could be extracted. Check the formatting of the decisions ' +
|
|
354
|
+
'block and ensure bullets follow the `- **D-NN:** text`, `- **D4-NN:** text` (phase-prefixed), ' +
|
|
355
|
+
'or `- **D-NN — title** body` form. An ID grammar the parser does not support (e.g. `DEC-01`) ' +
|
|
356
|
+
'also lands here.',
|
|
317
357
|
}, raw, undefined);
|
|
318
358
|
return;
|
|
319
359
|
}
|
|
@@ -353,11 +393,6 @@ function recentCommitMessages(projectDir) {
|
|
|
353
393
|
return '';
|
|
354
394
|
}
|
|
355
395
|
}
|
|
356
|
-
function isInsideRoot(candidatePath, rootDir) {
|
|
357
|
-
const root = node_path_1.default.resolve(rootDir);
|
|
358
|
-
const target = node_path_1.default.resolve(root, candidatePath);
|
|
359
|
-
return target === root || target.startsWith(`${root}${node_path_1.default.sep}`);
|
|
360
|
-
}
|
|
361
396
|
function readModifiedFilesContent(projectDir, summaries) {
|
|
362
397
|
const out = [];
|
|
363
398
|
let total = 0;
|
|
@@ -370,9 +405,17 @@ function readModifiedFilesContent(projectDir, summaries) {
|
|
|
370
405
|
for (const file of files) {
|
|
371
406
|
if (total >= 50)
|
|
372
407
|
break;
|
|
373
|
-
if (!file
|
|
408
|
+
if (!file)
|
|
409
|
+
continue;
|
|
410
|
+
// Migrated off the hand-rolled prefix check (ADR-4650): resolve+contain in one
|
|
411
|
+
// step via the canonical realpath predicate — the eventual read below follows
|
|
412
|
+
// symlinks, so containment must be decided on the resolved target, not a lexical
|
|
413
|
+
// prefix. Read the value the predicate RETURNED; do not re-derive the path.
|
|
414
|
+
const candidate = node_path_1.default.isAbsolute(file) ? file : node_path_1.default.join(projectDir, file);
|
|
415
|
+
const contained = (0, security_cjs_1.tryWithinRoot)(candidate, projectDir, security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
416
|
+
if (contained === null)
|
|
374
417
|
continue;
|
|
375
|
-
const raw = readIfExists(
|
|
418
|
+
const raw = readIfExists(contained);
|
|
376
419
|
out.push(raw.length > 256 * 1024 ? raw.slice(0, 256 * 1024) : raw);
|
|
377
420
|
total++;
|
|
378
421
|
}
|
|
@@ -410,9 +453,11 @@ function cmdDecisionCoverageVerify(projectDir, args, raw) {
|
|
|
410
453
|
not_honored: [],
|
|
411
454
|
message: partialParse
|
|
412
455
|
? 'Decision coverage verify (warning): decisions could not be fully parsed — one or more ' +
|
|
413
|
-
'`- **D-NN ...**` bullets appear malformed
|
|
456
|
+
'`- **D-NN ...**` bullets appear malformed (missing `:` or ` — ` separator, or a phase ' +
|
|
457
|
+
'prefix that is not a digit run). Fix the bullet format in the CONTEXT.md decisions block.'
|
|
414
458
|
: 'Decision coverage verify (warning): could not parse decisions — possible format mismatch. ' +
|
|
415
|
-
'Check the formatting of the CONTEXT.md decisions block
|
|
459
|
+
'Check the formatting of the CONTEXT.md decisions block (accepted forms: `- **D-NN:** text`, ' +
|
|
460
|
+
'`- **D4-NN:** text` (phase-prefixed), `- **D-NN — title** body`).',
|
|
416
461
|
}, raw, undefined);
|
|
417
462
|
return;
|
|
418
463
|
}
|
|
@@ -825,6 +870,74 @@ function cmdTddReviewCheckpoint(projectDir, args, raw) {
|
|
|
825
870
|
// the host-loop dispatch's advisory branch can surface it.
|
|
826
871
|
output(result, raw, undefined);
|
|
827
872
|
}
|
|
873
|
+
// ─── tdd-red-evidence (#3770) ──────────────────────────────────────────────────
|
|
874
|
+
/**
|
|
875
|
+
* tdd-red-evidence: validates a persisted RED-phase test-run record for a
|
|
876
|
+
* `type: tdd` plan (#3770). Only an INTENTIONAL failure of the target test
|
|
877
|
+
* (verdict RED_EVIDENCE_OK) may authorize GREEN; zero-test discovery, fixture/
|
|
878
|
+
* load crashes, nonzero exits without a failing test, unrelated failures, and
|
|
879
|
+
* unexpected greens are INVALID_RED and block GREEN.
|
|
880
|
+
*
|
|
881
|
+
* The record is the JSON the executor persists after running the RED command:
|
|
882
|
+
* { command, exitCode, output, targetTest, targetFile?, expected?, actual? }
|
|
883
|
+
* Fail-closed: a missing/unreadable/unparseable record is INVALID_RED
|
|
884
|
+
* (reason unreadable_record), never a pass.
|
|
885
|
+
*
|
|
886
|
+
* Args: check tdd-red-evidence <record.json>
|
|
887
|
+
*/
|
|
888
|
+
function cmdTddRedEvidence(_projectDir, args, raw) {
|
|
889
|
+
const recordPath = typeof args[2] === 'string' ? args[2] : '';
|
|
890
|
+
if (!recordPath) {
|
|
891
|
+
error('tdd-red-evidence requires a record path: check tdd-red-evidence <record.json>', ERROR_REASON.SDK_MISSING_ARG);
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
const resolved = node_path_1.default.resolve(recordPath);
|
|
895
|
+
const text = readIfExists(resolved);
|
|
896
|
+
const input = (() => {
|
|
897
|
+
if (!text)
|
|
898
|
+
return null;
|
|
899
|
+
try {
|
|
900
|
+
return (JSON.parse(text) ?? {});
|
|
901
|
+
}
|
|
902
|
+
catch {
|
|
903
|
+
return null;
|
|
904
|
+
}
|
|
905
|
+
})();
|
|
906
|
+
if (!input) {
|
|
907
|
+
output({
|
|
908
|
+
passed: false,
|
|
909
|
+
block: true,
|
|
910
|
+
verdict: 'INVALID_RED',
|
|
911
|
+
reason: 'unreadable_record',
|
|
912
|
+
record: resolved,
|
|
913
|
+
readError: text ? `record is not valid JSON: ${resolved}` : `record not found or unreadable: ${resolved}`,
|
|
914
|
+
}, raw, undefined);
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
const evidenceInput = {
|
|
918
|
+
command: input['command'],
|
|
919
|
+
exitCode: input['exitCode'],
|
|
920
|
+
output: input['output'],
|
|
921
|
+
targetTest: input['targetTest'],
|
|
922
|
+
targetFile: input['targetFile'],
|
|
923
|
+
expected: input['expected'],
|
|
924
|
+
actual: input['actual'],
|
|
925
|
+
};
|
|
926
|
+
const result = (0, tdd_red_evidence_cjs_1.classifyRedEvidence)(evidenceInput);
|
|
927
|
+
const record = (0, tdd_red_evidence_cjs_1.buildRedEvidenceRecord)(evidenceInput, result);
|
|
928
|
+
output({
|
|
929
|
+
// Uniform gate contract: block = !passed. INVALID_RED blocks GREEN.
|
|
930
|
+
passed: result.verdict === 'RED_EVIDENCE_OK',
|
|
931
|
+
block: result.verdict !== 'RED_EVIDENCE_OK',
|
|
932
|
+
verdict: result.verdict,
|
|
933
|
+
reason: result.reason,
|
|
934
|
+
evidence: result.evidence,
|
|
935
|
+
record,
|
|
936
|
+
message: result.verdict === 'RED_EVIDENCE_OK'
|
|
937
|
+
? `RED evidence verified: target test "${result.evidence.target_test}" failed as expected (exit ${result.evidence.exit_code}). GREEN authorized.`
|
|
938
|
+
: `INVALID_RED (${result.reason}): GREEN blocked. Fix the RED phase — only an intentional failure of target test "${result.evidence.target_test}" authorizes production edits.`,
|
|
939
|
+
}, raw, undefined);
|
|
940
|
+
}
|
|
828
941
|
/**
|
|
829
942
|
* Resolve a phase argument to an absolute phase directory, or '' when it
|
|
830
943
|
* cannot be resolved. Shared by every `check` arm that probes a phase's
|
|
@@ -950,8 +1063,9 @@ function cmdGapAnalysisPlanPost(projectDir, args, raw) {
|
|
|
950
1063
|
error('gap-analysis.plan-post requires a phase-dir argument: check gap-analysis.plan-post <phase-dir> [phase-req-ids]', ERROR_REASON.SDK_MISSING_ARG);
|
|
951
1064
|
return;
|
|
952
1065
|
}
|
|
1066
|
+
const resolvedPhaseDir = resolvePath(phaseDir, projectDir);
|
|
953
1067
|
const phaseReqIds = args[3] ?? undefined;
|
|
954
|
-
const result = runGapAnalysis(projectDir,
|
|
1068
|
+
const result = runGapAnalysis(projectDir, resolvedPhaseDir, { phaseReqIds });
|
|
955
1069
|
// Uniform gate contract: block = false (gap-analysis is always advisory, never blocks).
|
|
956
1070
|
// `message` carries the human-readable gap analysis report so the dispatch's
|
|
957
1071
|
// advisory branch can surface it. --raw emits JSON (rawValue=undefined), not
|
|
@@ -1002,21 +1116,21 @@ function buildPredicateDeps() {
|
|
|
1002
1116
|
node_path_1.default.win32.basename(artifactSuffix) !== artifactSuffix) {
|
|
1003
1117
|
return null;
|
|
1004
1118
|
}
|
|
1005
|
-
const
|
|
1006
|
-
if (
|
|
1007
|
-
return
|
|
1119
|
+
const directContained = (0, security_cjs_1.tryWithinRoot)(artifactSuffix, phaseDir);
|
|
1120
|
+
if (directContained !== null && node_fs_1.default.existsSync(directContained) && node_fs_1.default.statSync(directContained).isFile()) {
|
|
1121
|
+
return directContained;
|
|
1008
1122
|
}
|
|
1009
|
-
const
|
|
1010
|
-
if (
|
|
1011
|
-
return
|
|
1123
|
+
const planningContained = (0, security_cjs_1.tryWithinRoot)(node_path_1.default.join('.planning', artifactSuffix), phaseDir);
|
|
1124
|
+
if (planningContained !== null && node_fs_1.default.existsSync(planningContained) && node_fs_1.default.statSync(planningContained).isFile()) {
|
|
1125
|
+
return planningContained;
|
|
1012
1126
|
}
|
|
1013
1127
|
try {
|
|
1014
1128
|
const files = node_fs_1.default.readdirSync(phaseDir);
|
|
1015
1129
|
for (const f of files) {
|
|
1016
1130
|
if (f.endsWith('-' + artifactSuffix) || f === artifactSuffix) {
|
|
1017
|
-
const
|
|
1018
|
-
if (
|
|
1019
|
-
return
|
|
1131
|
+
const candidateContained = (0, security_cjs_1.tryWithinRoot)(f, phaseDir);
|
|
1132
|
+
if (candidateContained !== null && node_fs_1.default.statSync(candidateContained).isFile())
|
|
1133
|
+
return candidateContained;
|
|
1020
1134
|
}
|
|
1021
1135
|
}
|
|
1022
1136
|
}
|
|
@@ -1032,23 +1146,42 @@ function buildPredicateDeps() {
|
|
|
1032
1146
|
}
|
|
1033
1147
|
};
|
|
1034
1148
|
}
|
|
1035
|
-
/**
|
|
1036
|
-
|
|
1037
|
-
|
|
1149
|
+
/**
|
|
1150
|
+
* Split an args array into `--flag value` pairs and the leftover positional
|
|
1151
|
+
* tokens, in ONE pass, with the semantics `check predicate` established
|
|
1152
|
+
* (#2008): a `--flag` followed by a non-`--` token consumes it as the value
|
|
1153
|
+
* (last write wins); a `--flag` with no value stays a bare token and moves to
|
|
1154
|
+
* the positionals; everything else is positional. `parsePredicateFlags` is
|
|
1155
|
+
* the flags half of this same pass — there is exactly one parser, so the
|
|
1156
|
+
* flag-taking check verbs cannot drift apart (#4130 follow-up: `check
|
|
1157
|
+
* decision-coverage-plan --context <path>` shares it).
|
|
1158
|
+
*/
|
|
1159
|
+
function partitionPredicateArgs(args) {
|
|
1160
|
+
const flags = {};
|
|
1161
|
+
const positionals = [];
|
|
1038
1162
|
for (let i = 0; i < args.length; i++) {
|
|
1039
1163
|
const a = args[i];
|
|
1040
1164
|
if (typeof a !== 'string')
|
|
1041
1165
|
continue;
|
|
1042
|
-
if (!a.startsWith('--'))
|
|
1166
|
+
if (!a.startsWith('--')) {
|
|
1167
|
+
positionals.push(a);
|
|
1043
1168
|
continue;
|
|
1169
|
+
}
|
|
1044
1170
|
const key = a.slice(2);
|
|
1045
1171
|
const next = args[i + 1];
|
|
1046
1172
|
if (key.length > 0 && typeof next === 'string' && !next.startsWith('--')) {
|
|
1047
|
-
|
|
1173
|
+
flags[key] = next;
|
|
1048
1174
|
i++;
|
|
1049
1175
|
}
|
|
1176
|
+
else {
|
|
1177
|
+
positionals.push(a);
|
|
1178
|
+
}
|
|
1050
1179
|
}
|
|
1051
|
-
return
|
|
1180
|
+
return { flags, positionals };
|
|
1181
|
+
}
|
|
1182
|
+
/** Parse `--flag value` pairs from an args array into a map (last write wins). */
|
|
1183
|
+
function parsePredicateFlags(args) {
|
|
1184
|
+
return partitionPredicateArgs(args).flags;
|
|
1052
1185
|
}
|
|
1053
1186
|
/**
|
|
1054
1187
|
* `check predicate` — generic evaluator for capability gate `check.predicate`
|
|
@@ -1083,10 +1216,15 @@ function cmdCheckPredicate(projectDir, args, raw) {
|
|
|
1083
1216
|
error('predicate --predicate value must be valid JSON', ERROR_REASON.USAGE);
|
|
1084
1217
|
return;
|
|
1085
1218
|
}
|
|
1219
|
+
const rawPhaseDir = flags['phase-dir'];
|
|
1220
|
+
let resolvedPhaseDir = rawPhaseDir;
|
|
1221
|
+
if (typeof rawPhaseDir === 'string' && rawPhaseDir !== '') {
|
|
1222
|
+
resolvedPhaseDir = resolvePath(rawPhaseDir, projectDir);
|
|
1223
|
+
}
|
|
1086
1224
|
const ctx = {
|
|
1087
1225
|
cwd: projectDir,
|
|
1088
1226
|
phaseNumber: flags['phase-number'],
|
|
1089
|
-
phaseDir:
|
|
1227
|
+
phaseDir: resolvedPhaseDir,
|
|
1090
1228
|
phaseReqIds: flags['phase-req-ids'],
|
|
1091
1229
|
};
|
|
1092
1230
|
let result;
|
|
@@ -1180,7 +1318,12 @@ function cmdApiCoverageVerifyPre(projectDir, args, raw) {
|
|
|
1180
1318
|
// Defense-in-depth: the resolved dir must be inside the phases root (or a
|
|
1181
1319
|
// milestone archive under .planning/milestones).
|
|
1182
1320
|
const milestonesRoot = node_path_1.default.join(pDir, 'milestones');
|
|
1183
|
-
|
|
1321
|
+
// Lexical containment (ADR-4650): resolvedDir is a directory path, not read
|
|
1322
|
+
// through here — mirrors the prior path.resolve(root, candidate)-based check
|
|
1323
|
+
// without introducing a filesystem/realpath dependency this defense-in-depth
|
|
1324
|
+
// recheck never had.
|
|
1325
|
+
if ((0, security_cjs_1.tryWithinRootLexical)(resolvedDir, phasesRoot) === null &&
|
|
1326
|
+
(0, security_cjs_1.tryWithinRootLexical)(resolvedDir, milestonesRoot) === null) {
|
|
1184
1327
|
output({
|
|
1185
1328
|
block: true,
|
|
1186
1329
|
passed: false,
|
|
@@ -1472,6 +1615,12 @@ function routeCheckCommand({ args, cwd, raw }) {
|
|
|
1472
1615
|
cmdTddReviewCheckpoint(cwd, args, raw);
|
|
1473
1616
|
return;
|
|
1474
1617
|
}
|
|
1618
|
+
if (subcommand === 'tdd-red-evidence') {
|
|
1619
|
+
// #3770: intentional-RED evidence gate — only a target-test failure may
|
|
1620
|
+
// authorize GREEN. Validates the persisted record; never executes anything.
|
|
1621
|
+
cmdTddRedEvidence(cwd, args, raw);
|
|
1622
|
+
return;
|
|
1623
|
+
}
|
|
1475
1624
|
if (subcommand === 'ui-safety-gate') {
|
|
1476
1625
|
cmdUiSafetyGate(cwd, args, raw);
|
|
1477
1626
|
return;
|
|
@@ -1491,12 +1640,21 @@ function routeCheckCommand({ args, cwd, raw }) {
|
|
|
1491
1640
|
cmdVerifyCodebaseDrift(cwd, raw);
|
|
1492
1641
|
return;
|
|
1493
1642
|
}
|
|
1643
|
+
if (subcommand === 'verify-context-drift') {
|
|
1644
|
+
// Delegates to verify.context-drift — drift capability gate at plan:pre (non-blocking).
|
|
1645
|
+
// Dot-to-hyphen normalization means query "verify.context-drift" routes here.
|
|
1646
|
+
const phaseArg = typeof args[2] === 'string' ? args[2] : '';
|
|
1647
|
+
cmdVerifyContextDrift(cwd, phaseArg, raw);
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1494
1650
|
if (subcommand === 'predicate') {
|
|
1495
1651
|
// Generic gate-predicate evaluator (#2008). The workflow gate-dispatch calls
|
|
1496
1652
|
// this for any gate whose `check` carries a `predicate` (instead of a `query`),
|
|
1497
1653
|
// passing the predicate object as --predicate '<json>'. NOTE: unlike the
|
|
1498
1654
|
// `check.query` subcommands above (which take positional phase args), this
|
|
1499
|
-
// subcommand
|
|
1655
|
+
// subcommand is flag-driven. `decision-coverage-plan` above now ALSO accepts
|
|
1656
|
+
// `--context <path>` (its positionals still work) — both share
|
|
1657
|
+
// partitionPredicateArgs, the one flag parser.
|
|
1500
1658
|
cmdCheckPredicate(cwd, args, raw);
|
|
1501
1659
|
return;
|
|
1502
1660
|
}
|
|
@@ -1508,7 +1666,7 @@ function routeCheckCommand({ args, cwd, raw }) {
|
|
|
1508
1666
|
(0, prohibition_enforcement_cjs_1.routeProhibitionEnforcement)(args, raw);
|
|
1509
1667
|
return;
|
|
1510
1668
|
}
|
|
1511
|
-
error('Unknown check subcommand. Available: api-coverage-verify-pre, auto-mode, decision-coverage-plan, decision-coverage-verify, gap-analysis-plan-post, predicate, prohibition-enforcement, tdd-review-checkpoint, ui-plan-gate, ui-safety-gate, verify-command-paths, verify-failure-directions, verify-schema-drift, verify-codebase-drift', ERROR_REASON.SDK_UNKNOWN_COMMAND);
|
|
1669
|
+
error('Unknown check subcommand. Available: api-coverage-verify-pre, auto-mode, decision-coverage-plan, decision-coverage-verify, gap-analysis-plan-post, predicate, prohibition-enforcement, tdd-red-evidence, tdd-review-checkpoint, ui-plan-gate, ui-safety-gate, verify-command-paths, verify-failure-directions, verify-schema-drift, verify-codebase-drift, verify-context-drift', ERROR_REASON.SDK_UNKNOWN_COMMAND);
|
|
1512
1670
|
}
|
|
1513
1671
|
module.exports = {
|
|
1514
1672
|
routeCheckCommand,
|
|
@@ -1520,9 +1678,11 @@ module.exports = {
|
|
|
1520
1678
|
cmdVerifyCommandPaths,
|
|
1521
1679
|
cmdVerifyFailureDirections,
|
|
1522
1680
|
cmdTddReviewCheckpoint,
|
|
1681
|
+
cmdTddRedEvidence,
|
|
1523
1682
|
cmdCheckPredicate,
|
|
1524
1683
|
buildPredicateDeps,
|
|
1525
1684
|
parsePredicateFlags,
|
|
1685
|
+
partitionPredicateArgs,
|
|
1526
1686
|
// Fail-closed phase-scope reader for the api-coverage gate — exported for
|
|
1527
1687
|
// in-process failure-injection tests (#2365 review).
|
|
1528
1688
|
readPhaseScope,
|
|
@@ -43,6 +43,9 @@
|
|
|
43
43
|
*
|
|
44
44
|
* Zero external dependencies. Pure functions. Never throws on bad input.
|
|
45
45
|
*/
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports -- file-overlap-partitioner.cjs is an export= CommonJS module
|
|
47
|
+
const fileOverlapPartitionerMod = require("./file-overlap-partitioner.cjs");
|
|
48
|
+
const { partitionByFileOverlap } = fileOverlapPartitionerMod;
|
|
46
49
|
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
47
50
|
/**
|
|
48
51
|
* The Agent SDK version that introduced the Workflow tool (#1143 prior art).
|
|
@@ -226,33 +229,15 @@ function detectWorkflowBackend(input) {
|
|
|
226
229
|
*
|
|
227
230
|
* This is the same overlap rule execute-phase applies inline — the only difference
|
|
228
231
|
* is the execution vehicle (Workflow `parallel()` vs one-agent-per-message).
|
|
232
|
+
*
|
|
233
|
+
* #3674: the algorithm itself now lives in the generic, dependency-free
|
|
234
|
+
* `file-overlap-partitioner.cts` module (`partitionByFileOverlap`) — this is a
|
|
235
|
+
* thin adapter mapping this module's own `Plan[]` shape onto that module's
|
|
236
|
+
* generic `{ id, files }[]` input and back. Behavior-preserving extraction:
|
|
237
|
+
* same greedy first-fit algorithm, same output, only the implementation moved.
|
|
229
238
|
*/
|
|
230
239
|
function partitionStages(plans) {
|
|
231
|
-
|
|
232
|
-
for (const plan of plans) {
|
|
233
|
-
const fileSet = new Set(plan.files_modified);
|
|
234
|
-
let placed = false;
|
|
235
|
-
for (const stage of stages) {
|
|
236
|
-
let overlap = false;
|
|
237
|
-
for (const f of fileSet) {
|
|
238
|
-
if (stage.files.has(f)) {
|
|
239
|
-
overlap = true;
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
if (!overlap) {
|
|
244
|
-
stage.plans.push(plan);
|
|
245
|
-
for (const f of fileSet)
|
|
246
|
-
stage.files.add(f);
|
|
247
|
-
placed = true;
|
|
248
|
-
break;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
if (!placed) {
|
|
252
|
-
stages.push({ plans: [plan], files: new Set(fileSet) });
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return stages.map((s) => s.plans.map((p) => p.id));
|
|
240
|
+
return partitionByFileOverlap(plans.map((p) => ({ id: p.id, files: p.files_modified })));
|
|
256
241
|
}
|
|
257
242
|
/**
|
|
258
243
|
* Quote a free-text value for safe embedding as a JavaScript/Workflow double-quoted
|
|
@@ -61,7 +61,7 @@ function normalizeRelPath(p, repoRoot) {
|
|
|
61
61
|
let relativized = false;
|
|
62
62
|
if (typeof repoRoot === 'string' && repoRoot !== '') {
|
|
63
63
|
const rootNormalized = repoRoot.trim().replace(/\\/g, '/').replace(/\/+$/, '');
|
|
64
|
-
if (rootNormalized !== '' && value.startsWith(`${rootNormalized}/`)) {
|
|
64
|
+
if (rootNormalized !== '' && value.startsWith(`${rootNormalized}/`)) { // allow-handrolled-containment: display-path normalization — strips a caller-declared repoRoot prefix so a path renders repo-relative, not a security root-confinement decision
|
|
65
65
|
value = value.slice(rootNormalized.length + 1);
|
|
66
66
|
relativized = true;
|
|
67
67
|
}
|
|
@@ -86,7 +86,7 @@ function normalizeRelPath(p, repoRoot) {
|
|
|
86
86
|
* with `rulePath + '/'`. Both arguments must already be normalized. Case-sensitive.
|
|
87
87
|
*/
|
|
88
88
|
function ruleMatchesFile(rulePath, filePath) {
|
|
89
|
-
return filePath === rulePath || filePath.startsWith(`${rulePath}/`);
|
|
89
|
+
return filePath === rulePath || filePath.startsWith(`${rulePath}/`); // allow-handrolled-containment: rule-to-file segment match for selecting which review-depth rule applies — not a filesystem root-confinement gate
|
|
90
90
|
}
|
|
91
91
|
/**
|
|
92
92
|
* Validate + normalize a single rule path (not yet matched against files).
|
|
@@ -248,6 +248,14 @@ exports.VERIFY_COMMAND_ALIASES = [
|
|
|
248
248
|
],
|
|
249
249
|
"subcommand": "codebase-drift",
|
|
250
250
|
"mutation": false
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
"canonical": "verify.context-drift",
|
|
254
|
+
"aliases": [
|
|
255
|
+
"verify context-drift"
|
|
256
|
+
],
|
|
257
|
+
"subcommand": "context-drift",
|
|
258
|
+
"mutation": false
|
|
251
259
|
}
|
|
252
260
|
];
|
|
253
261
|
exports.INIT_COMMAND_ALIASES = [
|
|
@@ -299,6 +307,14 @@ exports.INIT_COMMAND_ALIASES = [
|
|
|
299
307
|
"subcommand": "quick",
|
|
300
308
|
"mutation": false
|
|
301
309
|
},
|
|
310
|
+
{
|
|
311
|
+
"canonical": "init.quick-batch",
|
|
312
|
+
"aliases": [
|
|
313
|
+
"init quick-batch"
|
|
314
|
+
],
|
|
315
|
+
"subcommand": "quick-batch",
|
|
316
|
+
"mutation": false
|
|
317
|
+
},
|
|
302
318
|
{
|
|
303
319
|
"canonical": "init.ingest-docs",
|
|
304
320
|
"aliases": [
|