@opengsd/gsd-core 1.13.0 → 1.15.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/README.ja-JP.md +3 -3
- package/README.ko-KR.md +3 -3
- package/README.pt-BR.md +3 -3
- package/README.zh-CN.md +3 -3
- 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 +459 -0
- package/agents/gsd-code-fixer.md +9 -8
- 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 +360 -0
- package/agents/gsd-debug-session-manager.md +17 -2
- package/agents/gsd-debugger.md +2 -2
- 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-auditor.md +1 -1
- package/agents/gsd-eval-planner.compact.md +137 -0
- package/agents/gsd-executor.md +13 -8
- 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-intel-updater.md +1 -1
- 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-phase-researcher.md +19 -11
- package/agents/gsd-plan-checker.md +8 -7
- package/agents/gsd-planner.md +12 -8
- package/agents/gsd-project-researcher.compact.md +587 -0
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +212 -0
- package/agents/gsd-research-synthesizer.md +1 -1
- 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-auditor.md +155 -17
- package/agents/gsd-ui-checker.compact.md +277 -0
- package/agents/gsd-ui-researcher.compact.md +282 -0
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-user-profiler.compact.md +108 -0
- package/agents/gsd-verifier.md +10 -9
- package/bin/install.js +848 -163
- package/commands/gsd/autonomous.md +2 -2
- package/commands/gsd/capture.md +1 -1
- 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/graphify.md +1 -0
- package/commands/gsd/health.md +1 -0
- package/commands/gsd/mempalace-capture.md +8 -3
- 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/pause-work.md +1 -0
- package/commands/gsd/phase.md +1 -0
- package/commands/gsd/plan-review-convergence.md +6 -6
- package/commands/gsd/pr-branch.md +1 -0
- package/commands/gsd/progress.md +1 -1
- package/commands/gsd/quick-batch.md +1 -1
- package/commands/gsd/resume-work.md +1 -0
- package/commands/gsd/review-backlog.md +1 -0
- package/commands/gsd/review.md +2 -3
- package/commands/gsd/settings.md +2 -1
- package/commands/gsd/stats.md +1 -0
- 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 +672 -146
- package/gsd-core/bin/lib/adr-parser.cjs +4 -2
- package/gsd-core/bin/lib/artifacts.cjs +2 -1
- package/gsd-core/bin/lib/audit.cjs +119 -34
- package/gsd-core/bin/lib/broken-windows.cjs +168 -49
- 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 +96 -189
- package/gsd-core/bin/lib/capability-source.cjs +19 -2
- package/gsd-core/bin/lib/capability-validator.cjs +14 -2
- package/gsd-core/bin/lib/check-command-router.cjs +213 -49
- package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
- package/gsd-core/bin/lib/codex-agent-toml.cjs +21 -25
- package/gsd-core/bin/lib/commands.cjs +823 -112
- package/gsd-core/bin/lib/config-loader.cjs +66 -4
- package/gsd-core/bin/lib/config.cjs +186 -45
- package/gsd-core/bin/lib/coverage.cjs +1 -1
- package/gsd-core/bin/lib/decisions.cjs +164 -45
- package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
- package/gsd-core/bin/lib/frontmatter.cjs +13 -0
- package/gsd-core/bin/lib/graphify.cjs +10 -2
- package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +12 -1
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
- package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
- package/gsd-core/bin/lib/init.cjs +614 -86
- package/gsd-core/bin/lib/install-engine.cjs +29 -3
- package/gsd-core/bin/lib/install-profiles.cjs +14 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +41 -5
- package/gsd-core/bin/lib/loop-resolver.cjs +50 -31
- package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
- package/gsd-core/bin/lib/milestone.cjs +37 -13
- package/gsd-core/bin/lib/model-resolver.cjs +253 -53
- package/gsd-core/bin/lib/phase-command-router.cjs +16 -2
- package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
- package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
- package/gsd-core/bin/lib/phase-id.cjs +268 -27
- package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
- package/gsd-core/bin/lib/phase-locator.cjs +29 -10
- package/gsd-core/bin/lib/phase.cjs +393 -88
- package/gsd-core/bin/lib/plan-document.cjs +49 -1
- package/gsd-core/bin/lib/planning-document.cjs +459 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +52 -19
- package/gsd-core/bin/lib/planning-snapshot.cjs +61 -12
- package/gsd-core/bin/lib/planning-workspace.cjs +57 -3
- package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
- package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
- package/gsd-core/bin/lib/probe-core.cjs +7 -1
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
- package/gsd-core/bin/lib/project-root.cjs +41 -2
- package/gsd-core/bin/lib/quick-batch.cjs +1 -1
- 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 +10 -30
- package/gsd-core/bin/lib/review-lane-invocation.cjs +23 -0
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
- package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +12 -4
- package/gsd-core/bin/lib/roadmap-parser.cjs +219 -18
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +1539 -13
- package/gsd-core/bin/lib/roadmap.cjs +356 -42
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +310 -41
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +15 -4
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +13 -5
- package/gsd-core/bin/lib/runtime-homes.cjs +4 -0
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +408 -37
- package/gsd-core/bin/lib/runtime-name-policy.cjs +111 -1
- package/gsd-core/bin/lib/security.cjs +126 -7
- package/gsd-core/bin/lib/shell-command-projection.cjs +10 -6
- package/gsd-core/bin/lib/state-document.cjs +130 -28
- package/gsd-core/bin/lib/state-md-schema.cjs +21 -14
- package/gsd-core/bin/lib/state-transition.cjs +181 -30
- package/gsd-core/bin/lib/state.cjs +265 -27
- package/gsd-core/bin/lib/surface.cjs +77 -3
- package/gsd-core/bin/lib/task-command-router.cjs +12 -6
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +78 -5
- package/gsd-core/bin/lib/uat-predicate.cjs +47 -4
- package/gsd-core/bin/lib/uat.cjs +9 -1
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +100 -9
- package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
- package/gsd-core/bin/lib/update-context.cjs +30 -24
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
- package/gsd-core/bin/lib/verification.cjs +315 -30
- package/gsd-core/bin/lib/verify-command-grounding.cjs +47 -3
- package/gsd-core/bin/lib/verify.cjs +320 -48
- package/gsd-core/bin/lib/workstream-inventory.cjs +1 -0
- package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
- package/gsd-core/bin/lib/worktree-safety.cjs +797 -58
- package/gsd-core/bin/shared/config-defaults.manifest.json +4 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +6 -0
- package/gsd-core/bin/verify-reapply-patches.cjs +439 -80
- package/gsd-core/references/checkpoints.md +5 -3
- package/gsd-core/references/compact-content-gate.md +66 -0
- package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe.md +195 -21
- package/gsd-core/references/execute-phase-between-wave-reset.md +7 -6
- package/gsd-core/references/execute-phase-wave-guard.md +22 -11
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +18 -0
- package/gsd-core/references/model-profiles.md +13 -4
- package/gsd-core/references/phase-argument-parsing.md +9 -7
- package/gsd-core/references/phase-id-convention.md +28 -0
- package/gsd-core/references/planner-gap-closure.md +2 -0
- package/gsd-core/references/planner-load-graph-context.md +24 -13
- package/gsd-core/references/planner-verify-command-grounding.md +14 -0
- package/gsd-core/references/planning-config.md +14 -2
- package/gsd-core/references/tdd.md +30 -4
- package/gsd-core/references/thinking-models-planning.md +18 -2
- package/gsd-core/references/ui-consideration-probe.md +10 -5
- package/gsd-core/references/verification-patterns.md +17 -4
- package/gsd-core/references/verify-command-path-resolvability.md +10 -2
- package/gsd-core/references/worktree-path-safety.md +433 -2
- package/gsd-core/templates/README.md +7 -1
- 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 +1 -1
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +1 -1
- package/gsd-core/workflows/add-phase.md +1 -1
- package/gsd-core/workflows/add-tests.md +2 -2
- package/gsd-core/workflows/add-todo.md +6 -5
- package/gsd-core/workflows/ai-integration-phase.md +11 -3
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +1 -1
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
- package/gsd-core/workflows/autonomous.md +29 -16
- package/gsd-core/workflows/check-todos.md +6 -4
- package/gsd-core/workflows/cleanup.md +5 -3
- package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +8 -1
- package/gsd-core/workflows/code-review-fix.md +108 -22
- package/gsd-core/workflows/code-review.md +216 -73
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
- package/gsd-core/workflows/complete-milestone.md +41 -264
- package/gsd-core/workflows/debug.md +3 -3
- package/gsd-core/workflows/diagnose-issues.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +2 -2
- package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
- package/gsd-core/workflows/docs-update.md +17 -158
- package/gsd-core/workflows/edit-phase.md +1 -1
- package/gsd-core/workflows/eval-review.md +10 -3
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1017 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +19 -4
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +43 -4
- package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
- package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +24 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
- package/gsd-core/workflows/execute-phase.md +83 -172
- package/gsd-core/workflows/execute-plan.md +24 -10
- package/gsd-core/workflows/explore.md +3 -3
- package/gsd-core/workflows/extract-learnings.md +2 -1
- package/gsd-core/workflows/fast.md +1 -1
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +2 -2
- package/gsd-core/workflows/help/modes/full.compact.md +398 -0
- package/gsd-core/workflows/help/modes/full.md +5 -5
- package/gsd-core/workflows/help/modes/topic.md +15 -5
- package/gsd-core/workflows/help.md +1 -1
- package/gsd-core/workflows/import.md +2 -2
- package/gsd-core/workflows/inbox.md +2 -2
- package/gsd-core/workflows/ingest-docs.md +3 -3
- package/gsd-core/workflows/insert-phase.md +1 -1
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +2 -2
- package/gsd-core/workflows/map-codebase.md +52 -5
- package/gsd-core/workflows/milestone-summary.md +1 -1
- package/gsd-core/workflows/mvp-phase.md +1 -1
- package/gsd-core/workflows/new-milestone.md +56 -14
- package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
- package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
- package/gsd-core/workflows/new-project.md +39 -209
- package/gsd-core/workflows/new-workspace.md +2 -2
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/note.md +1 -1
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
- package/gsd-core/workflows/plan-phase.md +45 -187
- package/gsd-core/workflows/plan-review-convergence.md +21 -5
- package/gsd-core/workflows/plant-seed.md +62 -20
- package/gsd-core/workflows/pr-branch.md +132 -20
- package/gsd-core/workflows/profile-user.md +2 -2
- package/gsd-core/workflows/progress.md +1 -1
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +25 -0
- package/gsd-core/workflows/quick/steps/quick-verification.md +1 -1
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +1 -1
- package/gsd-core/workflows/quick.md +29 -10
- package/gsd-core/workflows/reapply-patches.md +86 -6
- package/gsd-core/workflows/remove-phase.md +1 -1
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +1 -1
- package/gsd-core/workflows/review.md +31 -16
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +3 -2
- package/gsd-core/workflows/settings-advanced.md +30 -10
- package/gsd-core/workflows/settings-integrations.md +2 -3
- package/gsd-core/workflows/settings.md +22 -9
- package/gsd-core/workflows/ship.md +3 -2
- package/gsd-core/workflows/sketch-wrap-up.md +1 -1
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +2 -2
- package/gsd-core/workflows/spec-phase.md +15 -5
- package/gsd-core/workflows/spike-wrap-up.md +1 -1
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +1 -1
- package/gsd-core/workflows/sync-skills.md +5 -5
- package/gsd-core/workflows/thread.md +1 -1
- package/gsd-core/workflows/transition.md +1 -1
- package/gsd-core/workflows/ui-phase.md +44 -8
- package/gsd-core/workflows/ui-review.md +18 -4
- package/gsd-core/workflows/ultraplan-phase.md +1 -1
- package/gsd-core/workflows/undo.md +339 -20
- package/gsd-core/workflows/update.md +14 -12
- package/gsd-core/workflows/validate-phase.md +3 -2
- package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
- package/gsd-core/workflows/verify-work.md +101 -196
- package/hooks/dist/gsd-agent-isolation-guard.js +66 -16
- package/hooks/dist/gsd-context-monitor.js +88 -15
- package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
- package/hooks/dist/gsd-secret-read-guard.js +71 -19
- package/hooks/dist/gsd-statusline.js +81 -20
- package/hooks/dist/gsd-validate-commit.sh +97 -8
- 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/isolation-deny-reason.js +53 -1
- package/hooks/dist/lib/isolation-sentinel.js +58 -19
- package/hooks/gsd-agent-isolation-guard.js +66 -16
- package/hooks/gsd-context-monitor.js +88 -15
- package/hooks/gsd-cursor-subagent-start.js +34 -14
- package/hooks/gsd-secret-read-guard.js +71 -19
- package/hooks/gsd-statusline.js +81 -20
- package/hooks/gsd-validate-commit.sh +97 -8
- package/hooks/gsd-worktree-path-guard.js +25 -14
- package/hooks/gsd-write-guard.js +46 -1
- package/hooks/lib/dispatch-identity.js +187 -0
- package/hooks/lib/filename-classification.js +64 -0
- package/hooks/lib/isolation-deny-reason.js +53 -1
- package/hooks/lib/isolation-sentinel.js +58 -19
- package/package.json +11 -6
- package/scripts/benchmark-compact-content-variants.cjs +298 -0
- package/scripts/benchmark-compact-content.cjs +368 -0
- package/scripts/build-hooks.js +15 -6
- package/scripts/check-contract-drift.cjs +131 -12
- 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 +126 -20
- package/scripts/ci-timeout-report.cjs +1 -1
- package/scripts/command-contract-helpers.cjs +3 -0
- package/scripts/diff-touches-shipped-paths.cjs +1 -1
- package/scripts/docs-guard-registry.cjs +35 -2
- package/scripts/gen-adr-index.cjs +8 -2
- package/scripts/gen-inventory-manifest.cjs +12 -0
- package/scripts/gen-loop-host-contract.cjs +69 -0
- 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 +224 -0
- package/scripts/lib/ndjson-reporter.cjs +3 -2
- package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
- package/scripts/lib/platform-conformance-tier.generated.cjs +287 -0
- package/scripts/lib/suite-detection.cjs +32 -0
- package/scripts/lint-allowed-tools-parity.cjs +221 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +47 -3
- package/scripts/lint-phase-arg-assignment.cjs +257 -0
- package/scripts/lint-phase-id-drift.cjs +623 -13
- package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
- package/scripts/lint-response-language-coverage.cjs +9 -3
- package/scripts/lint-retired-runtime-name.cjs +619 -0
- package/scripts/lint-source-test-name-collision.cjs +1 -1
- package/scripts/lint-state-write-path-drift.cjs +93 -0
- package/scripts/lint-test-file-count.allowlist.json +29 -9
- package/scripts/lint-vendored-deps.cjs +128 -17
- package/scripts/lint-workflow-shellcheck-baseline.json +100 -0
- package/scripts/prompt-injection-scan.sh +18 -0
- package/scripts/release-tarball-smoke.cjs +194 -1
- package/scripts/workflow-size.cjs +139 -0
- package/skills/gsd-autonomous/SKILL.md +2 -2
- package/skills/gsd-capture/SKILL.md +1 -1
- 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-graphify/SKILL.md +1 -0
- package/skills/gsd-health/SKILL.md +1 -0
- package/skills/gsd-mempalace-capture/SKILL.md +8 -3
- 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-pause-work/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +1 -0
- package/skills/gsd-plan-review-convergence/SKILL.md +5 -5
- package/skills/gsd-pr-branch/SKILL.md +1 -0
- package/skills/gsd-progress/SKILL.md +1 -1
- package/skills/gsd-quick-batch/SKILL.md +1 -1
- package/skills/gsd-resume-work/SKILL.md +1 -0
- package/skills/gsd-review/SKILL.md +2 -3
- 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-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
|
@@ -52,6 +52,7 @@ const CANONICAL_HEADERS = {
|
|
|
52
52
|
'recommendation',
|
|
53
53
|
'strategy',
|
|
54
54
|
'decision outcome',
|
|
55
|
+
'locked decisions',
|
|
55
56
|
],
|
|
56
57
|
considered_options: [
|
|
57
58
|
'considered options',
|
|
@@ -190,7 +191,8 @@ function normalizeAdrHeader(raw) {
|
|
|
190
191
|
.toLowerCase()
|
|
191
192
|
.replace(/[\s:._-]+/g, ' ')
|
|
192
193
|
.replace(/[^\w\s]/g, '')
|
|
193
|
-
.trim()
|
|
194
|
+
.trim()
|
|
195
|
+
.replace(/^\d+(?:\s+\d+)*\s+/, '');
|
|
194
196
|
}
|
|
195
197
|
// Normalized synonym index (audit M7). classifyHeader receives an ALREADY-normalized
|
|
196
198
|
// header (via normalizeAdrHeader), but historically compared it against the RAW synonym
|
|
@@ -402,7 +404,7 @@ function parseCliArgs(argv) {
|
|
|
402
404
|
}
|
|
403
405
|
function main(argv) {
|
|
404
406
|
const opts = parseCliArgs(argv);
|
|
405
|
-
const safePath = (0, security_cjs_1.requireSafePath)(opts.input, node_path_1.default.resolve(opts.projectDir), 'ADR input path',
|
|
407
|
+
const safePath = (0, security_cjs_1.requireSafePath)(opts.input, node_path_1.default.resolve(opts.projectDir), 'ADR input path', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
406
408
|
const content = node_fs_1.default.readFileSync(safePath, 'utf8');
|
|
407
409
|
const parsed = parseAdrMarkdown(content, { sourcePath: opts.input ?? undefined, format: opts.format });
|
|
408
410
|
process.stdout.write(JSON.stringify(parsed, null, 2));
|
|
@@ -31,7 +31,8 @@ exports.CANONICAL_EXACT = new Set([
|
|
|
31
31
|
'STATE-ARCHIVE.md', // state.cts's cmdStatePrune writes this at the .planning/ root
|
|
32
32
|
'milestone.lock', // #3311: milestone (phase + session) claim (src/milestone-lock.cts); persistent, unlike the transient STATE.md.lock/WAITING.json
|
|
33
33
|
'state.json', // #3227: machine-readable state contract published at step boundaries (src/state-contract.cts)
|
|
34
|
-
'skill-manifest.json', // init.cts
|
|
34
|
+
'skill-manifest.json', // init.cts cmdSkillManifest --write (project-scoped planning root, #3964)
|
|
35
|
+
'PATTERNS.md', // #4282: graduated cross-phase patterns (workflows/graduation.md, `patterns` target) -- distinct from the per-phase NN-PATTERNS.md (templates/README.md)
|
|
35
36
|
]);
|
|
36
37
|
// Pattern-match canonical file names (regex tests on the basename)
|
|
37
38
|
// Each pattern includes the name of the workflow that produces it as a comment.
|
|
@@ -25,10 +25,15 @@ const coreUtils = require("./core-utils.cjs");
|
|
|
25
25
|
const { normalizeLineEndings } = coreUtils;
|
|
26
26
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
27
27
|
const planningWorkspace = require("./planning-workspace.cjs");
|
|
28
|
-
const { planningDir, quickDirFrom } = planningWorkspace;
|
|
28
|
+
const { planningDir, quickDirFrom, todosDir } = planningWorkspace;
|
|
29
29
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
30
30
|
const frontmatter = require("./frontmatter.cjs");
|
|
31
|
-
|
|
31
|
+
// #4378 (roll-in): scanSeeds publishes the SAME canonical seed identity the
|
|
32
|
+
// list-seeds gate derives — one grammar, two surfaces, no drift. commands.cjs
|
|
33
|
+
// does not require this module, so the edge is acyclic.
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
35
|
+
const commandsModule = require("./commands.cjs");
|
|
36
|
+
const { extractFrontmatter, FRONTMATTER_UNPARSEABLE, spliceFrontmatter } = frontmatter;
|
|
32
37
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
33
38
|
const phaseIdMod = require("./phase-id.cjs");
|
|
34
39
|
const { PHASE_NUMBER_TOKEN_SOURCE, scopeToPhase } = phaseIdMod;
|
|
@@ -277,7 +282,7 @@ function scanDebugSessions(planDir) {
|
|
|
277
282
|
const filePath = node_path_1.default.join(debugDir, entry.name);
|
|
278
283
|
let safeFilePath;
|
|
279
284
|
try {
|
|
280
|
-
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'debug session file',
|
|
285
|
+
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'debug session file', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
281
286
|
}
|
|
282
287
|
catch {
|
|
283
288
|
continue;
|
|
@@ -387,7 +392,7 @@ function scanQuickTasks(planDir) {
|
|
|
387
392
|
const taskDir = node_path_1.default.join(quickDir, dirName);
|
|
388
393
|
let safeTaskDir;
|
|
389
394
|
try {
|
|
390
|
-
safeTaskDir = (0, security_cjs_1.requireSafePath)(taskDir, planDir, 'quick task dir',
|
|
395
|
+
safeTaskDir = (0, security_cjs_1.requireSafePath)(taskDir, planDir, 'quick task dir', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
391
396
|
}
|
|
392
397
|
catch {
|
|
393
398
|
continue;
|
|
@@ -399,7 +404,7 @@ function scanQuickTasks(planDir) {
|
|
|
399
404
|
if (summaryPath && node_fs_1.default.existsSync(summaryPath)) {
|
|
400
405
|
let safeSum;
|
|
401
406
|
try {
|
|
402
|
-
safeSum = (0, security_cjs_1.requireSafePath)(summaryPath, planDir, 'quick task summary',
|
|
407
|
+
safeSum = (0, security_cjs_1.requireSafePath)(summaryPath, planDir, 'quick task summary', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
403
408
|
}
|
|
404
409
|
catch {
|
|
405
410
|
continue;
|
|
@@ -475,7 +480,7 @@ function scanThreads(planDir) {
|
|
|
475
480
|
const filePath = node_path_1.default.join(threadsDir, entry.name);
|
|
476
481
|
let safeFilePath;
|
|
477
482
|
try {
|
|
478
|
-
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'thread file',
|
|
483
|
+
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'thread file', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
479
484
|
}
|
|
480
485
|
catch {
|
|
481
486
|
continue;
|
|
@@ -522,9 +527,16 @@ function scanThreads(planDir) {
|
|
|
522
527
|
* Scan .planning/todos/pending/ for pending todos.
|
|
523
528
|
* Returns array of { filename, priority, area, summary }.
|
|
524
529
|
* Display limited to first 5 + count of remainder.
|
|
530
|
+
*
|
|
531
|
+
* #4256: takes the ROOT-scoped todos base (`todosDir(cwd)`), NOT the
|
|
532
|
+
* workstream-scoped planning dir the other scans use — todos are shared
|
|
533
|
+
* project state (the migrateToWorkstreams contract keeps them at
|
|
534
|
+
* .planning/todos/), so the close gate must read the root or it clears
|
|
535
|
+
* vacuously under a workstream. The requireSafePath boundary below moves
|
|
536
|
+
* with the base.
|
|
525
537
|
*/
|
|
526
|
-
function scanTodos(
|
|
527
|
-
const pendingDir = node_path_1.default.join(
|
|
538
|
+
function scanTodos(todosBase) {
|
|
539
|
+
const pendingDir = node_path_1.default.join(todosBase, 'pending');
|
|
528
540
|
if (!node_fs_1.default.existsSync(pendingDir))
|
|
529
541
|
return { items: [], acknowledged: 0 };
|
|
530
542
|
let files;
|
|
@@ -550,7 +562,7 @@ function scanTodos(planDir) {
|
|
|
550
562
|
const filePath = node_path_1.default.join(pendingDir, entry.name);
|
|
551
563
|
let safeFilePath;
|
|
552
564
|
try {
|
|
553
|
-
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath,
|
|
565
|
+
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, todosBase, 'todo file', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
554
566
|
}
|
|
555
567
|
catch {
|
|
556
568
|
continue;
|
|
@@ -595,6 +607,14 @@ function scanTodos(planDir) {
|
|
|
595
607
|
}
|
|
596
608
|
return { items: results, acknowledged };
|
|
597
609
|
}
|
|
610
|
+
// #4378 (roll-in): true when the filename is a well-formed seed name —
|
|
611
|
+
// `SEED-` prefix, `.md` suffix, and no control bytes anywhere in between (the
|
|
612
|
+
// scanSeeds admission filter passes such names through to the identity
|
|
613
|
+
// derivation; a name with an embedded control byte falls back to its raw
|
|
614
|
+
// stem exactly as the pre-canonical code did).
|
|
615
|
+
function seedIdMatchRawName(name) {
|
|
616
|
+
return !/[\u0000-\u001f\u007f]/.test(name);
|
|
617
|
+
}
|
|
598
618
|
// ─── scanSeeds ────────────────────────────────────────────────────────────────
|
|
599
619
|
/**
|
|
600
620
|
* Scan .planning/seeds/SEED-*.md for unimplemented seeds.
|
|
@@ -622,7 +642,7 @@ function scanSeeds(planDir) {
|
|
|
622
642
|
const filePath = node_path_1.default.join(seedsDir, entry.name);
|
|
623
643
|
let safeFilePath;
|
|
624
644
|
try {
|
|
625
|
-
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'seed file',
|
|
645
|
+
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'seed file', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
626
646
|
}
|
|
627
647
|
catch {
|
|
628
648
|
continue;
|
|
@@ -646,16 +666,18 @@ function scanSeeds(planDir) {
|
|
|
646
666
|
acknowledged++;
|
|
647
667
|
continue;
|
|
648
668
|
}
|
|
649
|
-
//
|
|
650
|
-
//
|
|
651
|
-
//
|
|
652
|
-
//
|
|
653
|
-
//
|
|
654
|
-
//
|
|
655
|
-
//
|
|
656
|
-
|
|
657
|
-
const
|
|
658
|
-
const
|
|
669
|
+
// #4378 (roll-in): the canonical identity comes from the SAME derivation
|
|
670
|
+
// the list-seeds surface uses — frontmatter `id:` when it matches a seed
|
|
671
|
+
// grammar (legacy `SEED-NNN` or date-suffixed `SEED-YYMMDD-xxx`), else the
|
|
672
|
+
// filename's id prefix, else the whole stem. The old fused
|
|
673
|
+
// filename-stem id (e.g. `SEED-081-region` for `SEED-081-region.md`)
|
|
674
|
+
// disagreed with list-seeds and misfiled deferrals; publishing the
|
|
675
|
+
// canonical id keeps the two surfaces answering identically. The raw-
|
|
676
|
+
// basename fallback for control-byte-bearing names is preserved.
|
|
677
|
+
const stem = node_path_1.default.basename(entry.name, '.md');
|
|
678
|
+
const derived = commandsModule.deriveSeedIdentity(stem, fm.id);
|
|
679
|
+
const seed_id = seedIdMatchRawName(entry.name) ? derived.seed_id : stem;
|
|
680
|
+
const slug = (0, security_cjs_1.sanitizeLabel)(derived.slug);
|
|
659
681
|
let title = (0, security_cjs_1.sanitizeForDisplay)(fm.title || '');
|
|
660
682
|
if (!title) {
|
|
661
683
|
const headingMatch = content.match(/^#\s*(.+)$/m);
|
|
@@ -785,7 +807,7 @@ function scanUatGaps(planDir, cwd) {
|
|
|
785
807
|
const filePath = node_path_1.default.join(target.fullPath, file);
|
|
786
808
|
let safeFilePath;
|
|
787
809
|
try {
|
|
788
|
-
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'UAT file',
|
|
810
|
+
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'UAT file', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
789
811
|
}
|
|
790
812
|
catch {
|
|
791
813
|
continue;
|
|
@@ -858,7 +880,7 @@ function scanVerificationGaps(planDir, cwd) {
|
|
|
858
880
|
const filePath = node_path_1.default.join(target.fullPath, file);
|
|
859
881
|
let safeFilePath;
|
|
860
882
|
try {
|
|
861
|
-
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'VERIFICATION file',
|
|
883
|
+
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'VERIFICATION file', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
862
884
|
}
|
|
863
885
|
catch {
|
|
864
886
|
continue;
|
|
@@ -920,7 +942,7 @@ function scanContextQuestions(planDir, cwd) {
|
|
|
920
942
|
const filePath = node_path_1.default.join(target.fullPath, file);
|
|
921
943
|
let safeFilePath;
|
|
922
944
|
try {
|
|
923
|
-
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'CONTEXT file',
|
|
945
|
+
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'CONTEXT file', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
924
946
|
}
|
|
925
947
|
catch {
|
|
926
948
|
continue;
|
|
@@ -1008,7 +1030,7 @@ function scanDeferredItems(planDir, cwd) {
|
|
|
1008
1030
|
continue;
|
|
1009
1031
|
let safeFilePath;
|
|
1010
1032
|
try {
|
|
1011
|
-
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'deferred items file',
|
|
1033
|
+
safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'deferred items file', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
1012
1034
|
}
|
|
1013
1035
|
catch {
|
|
1014
1036
|
continue;
|
|
@@ -1076,8 +1098,13 @@ function auditOpenArtifacts(cwd) {
|
|
|
1076
1098
|
}
|
|
1077
1099
|
})();
|
|
1078
1100
|
const todos = (() => {
|
|
1101
|
+
// #4256: the ONE root-scoped category — todos are shared project state,
|
|
1102
|
+
// so the close gate reads todosDir(cwd) (the root), not the workstream-
|
|
1103
|
+
// scoped planDir every other scan below receives. Reading planDir here
|
|
1104
|
+
// made audit-open print "All artifact types clear. Safe to proceed."
|
|
1105
|
+
// with pending todos on disk under a workstream.
|
|
1079
1106
|
try {
|
|
1080
|
-
return scanTodos(
|
|
1107
|
+
return scanTodos(todosDir(cwd));
|
|
1081
1108
|
}
|
|
1082
1109
|
catch {
|
|
1083
1110
|
return { items: [{ scan_error: true, filename: '', priority: '', area: '', summary: '' }], acknowledged: 0 };
|
|
@@ -1421,7 +1448,7 @@ function cmdAuditAcknowledge(cwd, args, raw) {
|
|
|
1421
1448
|
ioError(`no phase directory found for phase "${phase}"${archivedMilestone ? ` (archived-milestone "${archivedMilestone}")` : ''}`);
|
|
1422
1449
|
}
|
|
1423
1450
|
const filePath = node_path_1.default.join(targetDir, file);
|
|
1424
|
-
const safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'audit acknowledge target',
|
|
1451
|
+
const safeFilePath = (0, security_cjs_1.requireSafePath)(filePath, planDir, 'audit acknowledge target', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
1425
1452
|
if (!node_fs_1.default.existsSync(safeFilePath))
|
|
1426
1453
|
ioError(`file not found: ${file}`);
|
|
1427
1454
|
if (category === 'deferred_items') {
|
|
@@ -1452,6 +1479,13 @@ function cmdAuditAcknowledge(cwd, args, raw) {
|
|
|
1452
1479
|
}
|
|
1453
1480
|
const content = node_fs_1.default.readFileSync(safeFilePath, 'utf-8');
|
|
1454
1481
|
const fm = extractFrontmatter(content, safeFilePath);
|
|
1482
|
+
// #4802: an unparseable frontmatter block is NOT an empty one — splicing
|
|
1483
|
+
// the marker-marked object over the file would discard every field the
|
|
1484
|
+
// author actually wrote. Refuse and name the file (the write-path
|
|
1485
|
+
// counterpart of the read-side FRONTMATTER_UNPARSEABLE contract).
|
|
1486
|
+
if (fm[FRONTMATTER_UNPARSEABLE] === true) {
|
|
1487
|
+
ioError(`refusing to acknowledge — the frontmatter of "${file}" is not parseable YAML (splicing would discard every other frontmatter field); fix the YAML syntax error first, then re-run`);
|
|
1488
|
+
}
|
|
1455
1489
|
// Mixed-frame fix (security review, 4th instance on this branch): the
|
|
1456
1490
|
// splice above and below stays keyed to RAW `content` (raw byte offsets
|
|
1457
1491
|
// must not shift), but `scanUatGaps`/`scanContextQuestions` now derive
|
|
@@ -1503,7 +1537,7 @@ function cmdAuditAcknowledge(cwd, args, raw) {
|
|
|
1503
1537
|
if (category === 'debug_sessions') {
|
|
1504
1538
|
if (!slug)
|
|
1505
1539
|
ioError('--slug is required for --category debug_sessions');
|
|
1506
|
-
safeFilePath = (0, security_cjs_1.requireSafePath)(node_path_1.default.join(planDir, 'debug', `${slug}.md`), planDir, 'audit acknowledge target',
|
|
1540
|
+
safeFilePath = (0, security_cjs_1.requireSafePath)(node_path_1.default.join(planDir, 'debug', `${slug}.md`), planDir, 'audit acknowledge target', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
1507
1541
|
if (!node_fs_1.default.existsSync(safeFilePath))
|
|
1508
1542
|
ioError(`file not found: debug/${slug}.md`);
|
|
1509
1543
|
const content = node_fs_1.default.readFileSync(safeFilePath, 'utf-8');
|
|
@@ -1512,7 +1546,7 @@ function cmdAuditAcknowledge(cwd, args, raw) {
|
|
|
1512
1546
|
else if (category === 'threads') {
|
|
1513
1547
|
if (!slug)
|
|
1514
1548
|
ioError('--slug is required for --category threads');
|
|
1515
|
-
safeFilePath = (0, security_cjs_1.requireSafePath)(node_path_1.default.join(planDir, 'threads', `${slug}.md`), planDir, 'audit acknowledge target',
|
|
1549
|
+
safeFilePath = (0, security_cjs_1.requireSafePath)(node_path_1.default.join(planDir, 'threads', `${slug}.md`), planDir, 'audit acknowledge target', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
1516
1550
|
if (!node_fs_1.default.existsSync(safeFilePath))
|
|
1517
1551
|
ioError(`file not found: threads/${slug}.md`);
|
|
1518
1552
|
const content = node_fs_1.default.readFileSync(safeFilePath, 'utf-8');
|
|
@@ -1521,16 +1555,60 @@ function cmdAuditAcknowledge(cwd, args, raw) {
|
|
|
1521
1555
|
else if (category === 'seeds') {
|
|
1522
1556
|
if (!seedId)
|
|
1523
1557
|
ioError('--seed-id is required for --category seeds');
|
|
1524
|
-
|
|
1525
|
-
|
|
1558
|
+
// #4378 (roll-in): `--seed-id` arrives as whichever id an audit/list
|
|
1559
|
+
// surface published — the canonical identity (frontmatter `id:` or the
|
|
1560
|
+
// derived prefix, e.g. `SEED-081`, `SEED-260914-k3x`) or, for callers
|
|
1561
|
+
// scripted against pre-canonical output, the full filename stem. Resolve
|
|
1562
|
+
// by scanning the seeds directory and matching each candidate's derived
|
|
1563
|
+
// identity (falling back to the literal stem), then prove the winner with
|
|
1564
|
+
// requireSafePath exactly like every other acknowledge target. The direct
|
|
1565
|
+
// `seeds/<seedId>.md` build stays as the final fallback so a genuine
|
|
1566
|
+
// miss still reports the same "file not found" error as before.
|
|
1567
|
+
const seedsAckDir = node_path_1.default.join(planDir, 'seeds');
|
|
1568
|
+
let ackCandidate = null;
|
|
1569
|
+
let ackEntries = [];
|
|
1570
|
+
try {
|
|
1571
|
+
ackEntries = node_fs_1.default.readdirSync(seedsAckDir).filter((n) => n.startsWith('SEED-') && n.endsWith('.md'));
|
|
1572
|
+
}
|
|
1573
|
+
catch {
|
|
1574
|
+
ackEntries = [];
|
|
1575
|
+
}
|
|
1576
|
+
for (const name of ackEntries) {
|
|
1577
|
+
const stem = node_path_1.default.basename(name, '.md');
|
|
1578
|
+
let fmId;
|
|
1579
|
+
try {
|
|
1580
|
+
const rawAck = (0, shell_command_projection_cjs_1.platformReadSync)(node_path_1.default.join(seedsAckDir, name));
|
|
1581
|
+
if (rawAck !== null)
|
|
1582
|
+
fmId = extractFrontmatter(normalizeLineEndings(rawAck), node_path_1.default.join(seedsAckDir, name)).id;
|
|
1583
|
+
}
|
|
1584
|
+
catch {
|
|
1585
|
+
fmId = undefined;
|
|
1586
|
+
}
|
|
1587
|
+
const { seed_id: derivedAckId } = commandsModule.deriveSeedIdentity(stem, fmId);
|
|
1588
|
+
if (derivedAckId === seedId || stem === seedId) {
|
|
1589
|
+
ackCandidate = name;
|
|
1590
|
+
break;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
if (ackCandidate !== null) {
|
|
1594
|
+
safeFilePath = (0, security_cjs_1.requireSafePath)(node_path_1.default.join(seedsAckDir, ackCandidate), planDir, 'audit acknowledge target', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
1595
|
+
}
|
|
1596
|
+
else {
|
|
1597
|
+
safeFilePath = (0, security_cjs_1.requireSafePath)(node_path_1.default.join(seedsAckDir, `${seedId}.md`), planDir, 'audit acknowledge target', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
1526
1598
|
ioError(`file not found: seeds/${seedId}.md`);
|
|
1599
|
+
}
|
|
1527
1600
|
const content = node_fs_1.default.readFileSync(safeFilePath, 'utf-8');
|
|
1528
1601
|
currentValue = (extractFrontmatter(content, safeFilePath).status || 'dormant').toLowerCase();
|
|
1529
1602
|
}
|
|
1530
1603
|
else if (category === 'todos') {
|
|
1531
1604
|
if (!filename)
|
|
1532
1605
|
ioError('--filename is required for --category todos');
|
|
1533
|
-
|
|
1606
|
+
// #4256: todos are root-scoped shared state — derive the todos base and
|
|
1607
|
+
// pass it as BOTH the path base and the requireSafePath boundary. The
|
|
1608
|
+
// old workstream-scoped planDir boundary would refuse a root todos file
|
|
1609
|
+
// outright, and even a path fix alone would have thrown here.
|
|
1610
|
+
const rootTodos = todosDir(cwd);
|
|
1611
|
+
safeFilePath = (0, security_cjs_1.requireSafePath)(node_path_1.default.join(rootTodos, 'pending', filename), rootTodos, 'audit acknowledge target', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
1534
1612
|
if (!node_fs_1.default.existsSync(safeFilePath))
|
|
1535
1613
|
ioError(`file not found: todos/pending/${filename}`);
|
|
1536
1614
|
currentValue = ''; // presence-only — see scanTodos
|
|
@@ -1538,14 +1616,14 @@ function cmdAuditAcknowledge(cwd, args, raw) {
|
|
|
1538
1616
|
else if (category === 'quick_tasks') {
|
|
1539
1617
|
if (!quickDir)
|
|
1540
1618
|
ioError('--dir is required for --category quick_tasks');
|
|
1541
|
-
const taskDir = (0, security_cjs_1.requireSafePath)(node_path_1.default.join(planDir, 'quick', quickDir), planDir, 'audit acknowledge target dir',
|
|
1619
|
+
const taskDir = (0, security_cjs_1.requireSafePath)(node_path_1.default.join(planDir, 'quick', quickDir), planDir, 'audit acknowledge target dir', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
1542
1620
|
if (!node_fs_1.default.existsSync(taskDir))
|
|
1543
1621
|
ioError(`directory not found: quick/${quickDir}`);
|
|
1544
1622
|
// Shared with scanQuickTasks (#3458 follow-up) so the reader and this
|
|
1545
1623
|
// writer can never disagree about which file is the task's record.
|
|
1546
1624
|
const resolvedSummaryPath = resolveQuickTaskSummaryFile(taskDir, quickDir);
|
|
1547
1625
|
if (resolvedSummaryPath) {
|
|
1548
|
-
safeFilePath = (0, security_cjs_1.requireSafePath)(resolvedSummaryPath, planDir, 'audit acknowledge target',
|
|
1626
|
+
safeFilePath = (0, security_cjs_1.requireSafePath)(resolvedSummaryPath, planDir, 'audit acknowledge target', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
1549
1627
|
const content = node_fs_1.default.readFileSync(safeFilePath, 'utf-8');
|
|
1550
1628
|
currentValue = (extractFrontmatter(content, safeFilePath).status || 'unknown').toLowerCase();
|
|
1551
1629
|
}
|
|
@@ -1556,7 +1634,7 @@ function cmdAuditAcknowledge(cwd, args, raw) {
|
|
|
1556
1634
|
// acknowledgment's own snapshot of "no summary exists yet", which
|
|
1557
1635
|
// self-invalidates the moment a real SUMMARY.md is written (the
|
|
1558
1636
|
// scanner then reads THAT file's own status instead).
|
|
1559
|
-
safeFilePath = (0, security_cjs_1.requireSafePath)(node_path_1.default.join(taskDir, `${quickDir}-SUMMARY.md`), planDir, 'audit acknowledge target',
|
|
1637
|
+
safeFilePath = (0, security_cjs_1.requireSafePath)(node_path_1.default.join(taskDir, `${quickDir}-SUMMARY.md`), planDir, 'audit acknowledge target', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
1560
1638
|
currentValue = 'missing';
|
|
1561
1639
|
createIfMissing = true;
|
|
1562
1640
|
fmForCreate = { status: 'missing' };
|
|
@@ -1568,6 +1646,13 @@ function cmdAuditAcknowledge(cwd, args, raw) {
|
|
|
1568
1646
|
}
|
|
1569
1647
|
const presenceOnly = category === 'todos';
|
|
1570
1648
|
const fm = createIfMissing ? fmForCreate : extractFrontmatter(node_fs_1.default.readFileSync(safeFilePath, 'utf-8'), safeFilePath);
|
|
1649
|
+
// #4802: same unparseable-frontmatter refusal as the phase-scoped branch —
|
|
1650
|
+
// createIfMissing never reaches this extract (it only fires when the file is
|
|
1651
|
+
// absent), so an existing file with broken YAML refuses instead of splicing
|
|
1652
|
+
// a near-empty object over every field the author wrote.
|
|
1653
|
+
if (!createIfMissing && fm[FRONTMATTER_UNPARSEABLE] === true) {
|
|
1654
|
+
ioError(`refusing to acknowledge — the frontmatter of "${safeFilePath}" is not parseable YAML (splicing would discard every other frontmatter field); fix the YAML syntax error first, then re-run`);
|
|
1655
|
+
}
|
|
1571
1656
|
fm.audit_acknowledged = presenceOnly ? { ...markerBase } : { ...markerBase, [snapshotKey]: currentValue };
|
|
1572
1657
|
const newContent = createIfMissing
|
|
1573
1658
|
? spliceFrontmatter('', fm)
|