@opengsd/gsd-core 1.15.0 โ 1.16.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 +85 -5
- package/agents/gsd-code-fixer.compact.md +1 -1
- package/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-code-reviewer.compact.md +5 -3
- package/agents/gsd-code-reviewer.md +8 -6
- package/agents/gsd-debug-session-manager.compact.md +1 -1
- package/agents/gsd-debug-session-manager.md +1 -1
- package/agents/gsd-debugger.md +2 -2
- package/agents/gsd-eval-auditor.compact.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +4 -4
- package/agents/gsd-intel-updater.compact.md +1 -1
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +2 -2
- package/agents/gsd-phase-researcher.md +1 -1
- package/agents/gsd-plan-checker.md +7 -2
- package/agents/gsd-planner.md +3 -3
- package/agents/gsd-project-researcher.compact.md +1 -1
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +1 -1
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-ui-auditor.compact.md +21 -30
- package/agents/gsd-ui-auditor.md +42 -51
- package/agents/gsd-ui-researcher.compact.md +1 -1
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-verifier.md +31 -9
- package/bin/install.js +126 -196
- package/commands/gsd/add-tests.md +6 -1
- package/commands/gsd/ai-integration-phase.md +6 -1
- package/commands/gsd/audit-fix.md +5 -0
- package/commands/gsd/audit-milestone.md +6 -1
- package/commands/gsd/autonomous.md +5 -0
- package/commands/gsd/capture.md +8 -4
- package/commands/gsd/code-review.md +7 -2
- package/commands/gsd/complete-milestone.md +4 -0
- package/commands/gsd/config.md +7 -3
- package/commands/gsd/debug.md +11 -7
- package/commands/gsd/discuss-phase.md +7 -3
- package/commands/gsd/docs-update.md +12 -7
- package/commands/gsd/eval-review.md +6 -1
- package/commands/gsd/execute-phase.md +12 -7
- package/commands/gsd/extract-learnings.md +5 -0
- package/commands/gsd/fast.md +4 -0
- package/commands/gsd/forensics.md +5 -1
- package/commands/gsd/graphify.md +10 -6
- package/commands/gsd/health.md +5 -0
- package/commands/gsd/help.md +7 -2
- package/commands/gsd/import.md +7 -3
- package/commands/gsd/inbox.md +5 -0
- package/commands/gsd/ingest-docs.md +5 -1
- package/commands/gsd/manager.md +6 -1
- package/commands/gsd/map-codebase.md +7 -3
- package/commands/gsd/mempalace-capture.md +5 -1
- package/commands/gsd/mempalace-recall.md +5 -1
- package/commands/gsd/milestone-summary.md +5 -1
- package/commands/gsd/mvp-phase.md +8 -3
- package/commands/gsd/new-milestone.md +6 -1
- package/commands/gsd/new-project.md +5 -0
- package/commands/gsd/next.md +6 -1
- package/commands/gsd/ns-context.md +4 -0
- package/commands/gsd/ns-ideate.md +4 -0
- package/commands/gsd/ns-manage.md +4 -0
- package/commands/gsd/ns-project.md +4 -0
- package/commands/gsd/ns-review.md +4 -0
- package/commands/gsd/ns-workflow.md +4 -0
- package/commands/gsd/onboard.md +6 -1
- package/commands/gsd/pause-work.md +5 -1
- package/commands/gsd/phase.md +8 -4
- package/commands/gsd/plan-phase.md +6 -1
- package/commands/gsd/plan-review-convergence.md +5 -1
- package/commands/gsd/pr-branch.md +4 -0
- package/commands/gsd/profile-user.md +5 -1
- package/commands/gsd/progress.md +6 -1
- package/commands/gsd/quick-batch.md +20 -8
- package/commands/gsd/quick.md +12 -7
- package/commands/gsd/review.md +5 -1
- package/commands/gsd/secure-phase.md +6 -1
- package/commands/gsd/ship.md +5 -0
- package/commands/gsd/sketch.md +7 -2
- package/commands/gsd/spec-phase.md +5 -1
- package/commands/gsd/spike.md +8 -3
- package/commands/gsd/surface.md +5 -1
- package/commands/gsd/thread.md +4 -0
- package/commands/gsd/ui-phase.md +6 -1
- package/commands/gsd/ui-review.md +6 -1
- package/commands/gsd/ultraplan-phase.md +5 -1
- package/commands/gsd/undo.md +5 -1
- package/commands/gsd/update.md +6 -2
- package/commands/gsd/validate-phase.md +6 -1
- package/commands/gsd/verify-work.md +6 -1
- package/commands/gsd/workspace.md +7 -3
- package/gsd-core/bin/gsd-tools.cjs +142 -56
- package/gsd-core/bin/lib/active-workstream-store.cjs +15 -0
- package/gsd-core/bin/lib/agent-install-check.cjs +4 -1
- package/gsd-core/bin/lib/audit.cjs +78 -44
- package/gsd-core/bin/lib/broken-windows.cjs +13 -13
- package/gsd-core/bin/lib/capability-activation.cjs +9 -4
- package/gsd-core/bin/lib/capability-registry.cjs +183 -103
- package/gsd-core/bin/lib/capability-validator.cjs +16 -0
- package/gsd-core/bin/lib/check-auto-mode.cjs +35 -0
- package/gsd-core/bin/lib/check-command-router.cjs +164 -1712
- package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +13 -2
- package/gsd-core/bin/lib/cli-exit.cjs +12 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +11 -8
- package/gsd-core/bin/lib/command-aliases.cjs +7 -0
- package/gsd-core/bin/lib/command-routing-hub.cjs +48 -1
- package/gsd-core/bin/lib/commands.cjs +173 -170
- package/gsd-core/bin/lib/complexity-trigger.cjs +8 -7
- package/gsd-core/bin/lib/config.cjs +43 -12
- package/gsd-core/bin/lib/core-utils.cjs +6 -1
- package/gsd-core/bin/lib/coverage.cjs +4 -8
- package/gsd-core/bin/lib/decision-coverage-support.cjs +259 -0
- package/gsd-core/bin/lib/drift.cjs +177 -42
- package/gsd-core/bin/lib/frontmatter-fence.cjs +90 -0
- package/gsd-core/bin/lib/frontmatter-splice.cjs +494 -0
- package/gsd-core/bin/lib/frontmatter.cjs +413 -234
- package/gsd-core/bin/lib/gap-checker.cjs +72 -29
- package/gsd-core/bin/lib/gate-api-coverage-verify-pre.cjs +381 -0
- package/gsd-core/bin/lib/gate-args.cjs +53 -0
- package/gsd-core/bin/lib/gate-codebase-drift.cjs +285 -0
- package/gsd-core/bin/lib/gate-config.cjs +46 -0
- package/gsd-core/bin/lib/gate-context-drift.cjs +141 -0
- package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +169 -0
- package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +126 -0
- package/gsd-core/bin/lib/gate-evaluation-scope.cjs +555 -0
- package/gsd-core/bin/lib/gate-evidence.cjs +138 -0
- package/gsd-core/bin/lib/gate-exit.cjs +27 -0
- package/gsd-core/bin/lib/gate-gap-analysis-plan-post.cjs +61 -0
- package/gsd-core/bin/lib/gate-phase-context.cjs +170 -0
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +1 -1
- package/gsd-core/bin/lib/gate-predicate.cjs +165 -0
- package/gsd-core/bin/lib/gate-prohibition-enforcement.cjs +94 -0
- package/gsd-core/bin/lib/gate-schema-drift.cjs +165 -0
- package/gsd-core/bin/lib/gate-tdd-red-evidence.cjs +100 -0
- package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +182 -0
- package/gsd-core/bin/lib/gate-ui-plan.cjs +86 -0
- package/gsd-core/bin/lib/gate-ui-safety.cjs +80 -0
- package/gsd-core/bin/lib/gate-verdict.cjs +64 -0
- package/gsd-core/bin/lib/gate-verify-command-paths.cjs +78 -0
- package/gsd-core/bin/lib/gate-verify-failure-directions.cjs +41 -0
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +43 -47
- package/gsd-core/bin/lib/health-diagnostic.cjs +45 -8
- package/gsd-core/bin/lib/init.cjs +162 -96
- package/gsd-core/bin/lib/install-engine.cjs +19 -35
- package/gsd-core/bin/lib/install-profiles.cjs +7 -4
- package/gsd-core/bin/lib/io.cjs +122 -3
- package/gsd-core/bin/lib/loop-resolver.cjs +95 -0
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +75 -1
- package/gsd-core/bin/lib/milestone.cjs +19 -1
- package/gsd-core/bin/lib/model-resolver.cjs +18 -18
- package/gsd-core/bin/lib/observability/event.cjs +1 -1
- package/gsd-core/bin/lib/observability/logger.cjs +46 -1
- package/gsd-core/bin/lib/pattern.cjs +10 -0
- package/gsd-core/bin/lib/phase-command-router.cjs +11 -4
- package/gsd-core/bin/lib/phase-estimation.cjs +5 -4
- package/gsd-core/bin/lib/phase-id.cjs +1 -1
- package/gsd-core/bin/lib/phase-lifecycle.cjs +9 -2
- package/gsd-core/bin/lib/phase-status.cjs +360 -0
- package/gsd-core/bin/lib/phase.cjs +280 -80
- package/gsd-core/bin/lib/plan-document.cjs +93 -19
- package/gsd-core/bin/lib/plan-drift-guard.cjs +5 -0
- package/gsd-core/bin/lib/planning-document.cjs +273 -40
- package/gsd-core/bin/lib/planning-inspect.cjs +42 -8
- package/gsd-core/bin/lib/planning-snapshot.cjs +18 -0
- package/gsd-core/bin/lib/planning-workspace.cjs +76 -53
- package/gsd-core/bin/lib/pristine-baseline.cjs +10 -0
- package/gsd-core/bin/lib/profile-output.cjs +6 -3
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +0 -55
- package/gsd-core/bin/lib/quick-batch-command-router.cjs +35 -9
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +11 -8
- package/gsd-core/bin/lib/real-home-guard.cjs +9 -1
- package/gsd-core/bin/lib/report-parser.cjs +269 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +13 -15
- package/gsd-core/bin/lib/roadmap-parser.cjs +82 -15
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +127 -65
- package/gsd-core/bin/lib/roadmap.cjs +169 -72
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +91 -157
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +2 -1
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +57 -1
- package/gsd-core/bin/lib/runtime-homes.cjs +13 -10
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +307 -591
- package/gsd-core/bin/lib/runtime-name-policy.cjs +142 -27
- package/gsd-core/bin/lib/runtime-slash.cjs +47 -30
- package/gsd-core/bin/lib/shell-command-projection.cjs +37 -2
- package/gsd-core/bin/lib/smart-entry.cjs +19 -3
- package/gsd-core/bin/lib/stale-bake-guard.cjs +32 -48
- package/gsd-core/bin/lib/state-contract.cjs +15 -18
- package/gsd-core/bin/lib/state-document.cjs +100 -22
- package/gsd-core/bin/lib/state.cjs +214 -105
- package/gsd-core/bin/lib/surface.cjs +2 -1
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +48 -152
- package/gsd-core/bin/lib/uat-predicate.cjs +313 -35
- package/gsd-core/bin/lib/uat.cjs +424 -7
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +94 -58
- package/gsd-core/bin/lib/vendor/README.md +31 -9
- package/gsd-core/bin/lib/vendor/saxes.cjs +1934 -0
- package/gsd-core/bin/lib/vendor/saxes.cjs.LICENSE.txt +92 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs +8927 -0
- package/gsd-core/bin/lib/vendor/tap-parser.cjs.LICENSE.txt +152 -0
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +1165 -314
- package/gsd-core/bin/lib/verify-command-router.cjs +18 -7
- package/gsd-core/bin/lib/verify.cjs +286 -567
- package/gsd-core/bin/lib/workstream-inventory-builder.cjs +14 -6
- package/gsd-core/bin/lib/workstream-inventory.cjs +31 -21
- package/gsd-core/bin/lib/workstream-name-policy.cjs +31 -1
- package/gsd-core/bin/lib/workstream.cjs +11 -2
- package/gsd-core/bin/shared/config-defaults.manifest.json +5 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +4 -0
- package/gsd-core/references/autonomous-smart-discuss.md +2 -1
- package/gsd-core/references/autonomous-ui-design-contract.md +3 -3
- package/gsd-core/references/execute-mvp-tdd.md +5 -10
- package/gsd-core/references/execute-phase-between-wave-reset.md +3 -0
- package/gsd-core/references/execute-phase-response-language.md +1 -1
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +7 -1
- package/gsd-core/references/offer-next.md +1 -1
- package/gsd-core/references/planning-config.md +1 -1
- package/gsd-core/references/spidr-splitting.md +1 -1
- package/gsd-core/references/tdd.md +10 -4
- package/gsd-core/references/verifier-phase-gates.md +5 -2
- package/gsd-core/references/verify-mvp-mode.md +2 -2
- package/gsd-core/references/workstream-flag.md +33 -3
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/UAT.md +17 -1
- package/gsd-core/templates/config.json +2 -11
- 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 +8 -7
- package/gsd-core/workflows/add-tests.md +3 -2
- package/gsd-core/workflows/add-todo.md +4 -3
- package/gsd-core/workflows/ai-integration-phase.md +3 -2
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +4 -3
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous.md +28 -18
- package/gsd-core/workflows/check-todos.md +6 -5
- package/gsd-core/workflows/cleanup.md +1 -1
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +20 -13
- package/gsd-core/workflows/code-review-fix.md +5 -4
- package/gsd-core/workflows/code-review.md +84 -90
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +4 -3
- package/gsd-core/workflows/complete-milestone.md +12 -7
- package/gsd-core/workflows/debug.md +30 -5
- package/gsd-core/workflows/diagnose-issues.md +3 -2
- 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 +4 -3
- package/gsd-core/workflows/discuss-phase.md +4 -3
- package/gsd-core/workflows/do.md +1 -1
- package/gsd-core/workflows/docs-update.md +4 -3
- package/gsd-core/workflows/edit-phase.md +4 -3
- package/gsd-core/workflows/eval-review.md +5 -3
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +4 -2
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +15 -4
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +10 -7
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +3 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +2 -2
- 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 +1 -1
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +187 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +2 -3
- package/gsd-core/workflows/execute-phase.md +78 -170
- package/gsd-core/workflows/execute-plan.md +13 -19
- package/gsd-core/workflows/explore.md +2 -2
- package/gsd-core/workflows/extract-learnings.md +3 -2
- 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 -1
- package/gsd-core/workflows/import.md +3 -2
- package/gsd-core/workflows/inbox.md +1 -1
- package/gsd-core/workflows/ingest-docs.md +1 -1
- package/gsd-core/workflows/insert-phase.md +4 -3
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +5 -3
- package/gsd-core/workflows/map-codebase.md +4 -3
- package/gsd-core/workflows/milestone-summary.md +3 -2
- package/gsd-core/workflows/mvp-phase.md +14 -14
- package/gsd-core/workflows/new-milestone.md +10 -10
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +1 -1
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/pause-work.md +2 -2
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +1 -1
- package/gsd-core/workflows/plan-phase.md +27 -18
- package/gsd-core/workflows/plan-review-convergence.md +1 -1
- package/gsd-core/workflows/plant-seed.md +1 -1
- package/gsd-core/workflows/pr-branch.md +1 -1
- package/gsd-core/workflows/profile-user.md +1 -1
- package/gsd-core/workflows/progress.md +19 -49
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -2
- package/gsd-core/workflows/quick/steps/quick-verification.md +4 -4
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +30 -11
- 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 +9 -3
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +15 -10
- package/gsd-core/workflows/quick.md +42 -31
- package/gsd-core/workflows/remove-phase.md +3 -2
- package/gsd-core/workflows/remove-workspace.md +1 -1
- package/gsd-core/workflows/resume-project.md +3 -2
- package/gsd-core/workflows/review.md +3 -2
- package/gsd-core/workflows/scan.md +3 -2
- package/gsd-core/workflows/secure-phase.md +11 -12
- package/gsd-core/workflows/settings-advanced.md +1 -1
- package/gsd-core/workflows/settings-integrations.md +1 -1
- package/gsd-core/workflows/settings.md +1 -1
- package/gsd-core/workflows/ship.md +12 -12
- 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 +1 -1
- package/gsd-core/workflows/spec-phase.md +1 -1
- 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 +1 -1
- package/gsd-core/workflows/thread.md +2 -2
- package/gsd-core/workflows/transition.md +13 -23
- package/gsd-core/workflows/ui-phase.md +5 -4
- package/gsd-core/workflows/ui-review.md +4 -3
- package/gsd-core/workflows/ultraplan-phase.md +3 -2
- package/gsd-core/workflows/undo.md +1 -1
- package/gsd-core/workflows/validate-phase.md +10 -12
- package/gsd-core/workflows/verify-work/detail/elaboration.md +43 -3
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -3
- package/gsd-core/workflows/verify-work.md +68 -59
- package/hooks/dist/gsd-agent-isolation-guard.js +8 -0
- package/hooks/dist/gsd-check-update-worker.js +8 -0
- package/hooks/dist/gsd-check-update.js +8 -0
- package/hooks/dist/gsd-context-monitor.js +31 -8
- package/hooks/dist/gsd-cursor-subagent-start.js +8 -0
- package/hooks/dist/gsd-secret-read-guard.js +147 -16
- package/hooks/dist/gsd-statusline.js +15 -7
- package/hooks/dist/gsd-update-banner.js +8 -0
- package/hooks/dist/gsd-windsurf-pre-write.js +11 -2
- package/hooks/dist/gsd-workflow-guard.js +5 -4
- package/hooks/dist/gsd-worktree-path-guard.js +6 -2
- package/hooks/dist/lib/cli-exit.js +12 -0
- package/hooks/dist/lib/git-probe.js +17 -1
- package/hooks/dist/lib/isolation-sentinel.js +2 -2
- package/hooks/gsd-agent-isolation-guard.js +8 -0
- package/hooks/gsd-check-update-worker.js +8 -0
- package/hooks/gsd-check-update.js +8 -0
- package/hooks/gsd-context-monitor.js +31 -8
- package/hooks/gsd-cursor-subagent-start.js +8 -0
- package/hooks/gsd-secret-read-guard.js +147 -16
- package/hooks/gsd-statusline.js +15 -7
- package/hooks/gsd-update-banner.js +8 -0
- package/hooks/gsd-windsurf-pre-write.js +11 -2
- package/hooks/gsd-workflow-guard.js +5 -4
- package/hooks/gsd-worktree-path-guard.js +6 -2
- package/hooks/hooks.json +5 -5
- package/hooks/lib/cli-exit.js +12 -0
- package/hooks/lib/git-probe.js +17 -1
- package/hooks/lib/isolation-sentinel.js +2 -2
- package/package.json +21 -4
- package/scripts/changeset/parse.cjs +52 -4
- package/scripts/ci-timeout-report.cjs +770 -4
- package/scripts/command-contract-helpers.cjs +12 -8
- package/scripts/docs-guard-registry.cjs +6 -0
- package/scripts/gen-features.cjs +13 -8
- package/scripts/gen-hooks-cli-exit.cjs +12 -28
- package/scripts/gen-loop-host-contract.cjs +10 -1
- package/scripts/gen-platform-conformance-tier.cjs +187 -1
- package/scripts/gen-plugin-skills.cjs +87 -1
- package/scripts/gen-research-agents.cjs +24 -31
- package/scripts/gen-scripts-cli-exit.cjs +30 -3
- package/scripts/gen-test-timings.cjs +32 -7
- package/scripts/lib/cli-exit.cjs +12 -0
- package/scripts/lib/macos-conformance-tier.generated.cjs +20 -2
- package/scripts/lib/ndjson-reporter.cjs +28 -3
- package/scripts/lib/platform-conformance-tier.generated.cjs +34 -5
- package/scripts/lib/registration-ledger-preload.cjs +155 -0
- package/scripts/lib/vendor-bundle.cjs +59 -0
- package/scripts/lib/vendor-licenses/saxes-6.0.0.txt +64 -0
- 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-completion-predicate-drift.cjs +18 -19
- package/scripts/lint-descriptions.cjs +7 -3
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +10 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +20 -0
- package/scripts/lint-frontmatter-fence-drift.cjs +313 -0
- package/scripts/lint-frontmatter-scalar-broad-grep.cjs +122 -16
- package/scripts/lint-phase-enumeration-drift.cjs +12 -8
- package/scripts/lint-phase-id-drift.cjs +29 -0
- package/scripts/lint-planning-document-positive-control.cjs +329 -0
- package/scripts/lint-response-language-coverage.cjs +3 -0
- package/scripts/lint-skill-deps.cjs +7 -3
- package/scripts/lint-test-file-count.allowlist.json +11 -1
- package/scripts/lint-test-file-count.cjs +34 -1
- package/scripts/lint-vendored-deps.cjs +41 -5
- package/scripts/lint-workflow-shellcheck-baseline.json +10 -10
- package/scripts/mutation-matrix.cjs +50 -5
- package/scripts/require-issue-link-policy.cjs +6 -2
- package/scripts/sync-runtime-launcher.cjs +184 -2
- package/scripts/verify-npm-publish.cjs +76 -20
- package/skills/gsd-add-tests/SKILL.md +6 -1
- package/skills/gsd-ai-integration-phase/SKILL.md +6 -1
- package/skills/gsd-audit-fix/SKILL.md +5 -0
- package/skills/gsd-audit-milestone/SKILL.md +6 -1
- package/skills/gsd-autonomous/SKILL.md +5 -0
- package/skills/gsd-capture/SKILL.md +8 -4
- package/skills/gsd-code-review/SKILL.md +7 -2
- package/skills/gsd-complete-milestone/SKILL.md +4 -0
- package/skills/gsd-config/SKILL.md +8 -4
- package/skills/gsd-debug/SKILL.md +11 -7
- package/skills/gsd-discuss-phase/SKILL.md +7 -3
- package/skills/gsd-docs-update/SKILL.md +12 -7
- package/skills/gsd-eval-review/SKILL.md +6 -1
- package/skills/gsd-execute-phase/SKILL.md +12 -7
- package/skills/gsd-extract-learnings/SKILL.md +5 -0
- package/skills/gsd-fast/SKILL.md +4 -0
- package/skills/gsd-forensics/SKILL.md +5 -1
- package/skills/gsd-graphify/SKILL.md +10 -6
- package/skills/gsd-health/SKILL.md +5 -0
- package/skills/gsd-help/SKILL.md +7 -2
- package/skills/gsd-import/SKILL.md +7 -3
- package/skills/gsd-inbox/SKILL.md +5 -0
- package/skills/gsd-ingest-docs/SKILL.md +5 -1
- package/skills/gsd-manager/SKILL.md +6 -1
- package/skills/gsd-map-codebase/SKILL.md +7 -3
- package/skills/gsd-mempalace-capture/SKILL.md +5 -1
- package/skills/gsd-mempalace-recall/SKILL.md +5 -1
- package/skills/gsd-milestone-summary/SKILL.md +5 -1
- package/skills/gsd-mvp-phase/SKILL.md +8 -3
- package/skills/gsd-new-milestone/SKILL.md +6 -1
- package/skills/gsd-new-project/SKILL.md +5 -0
- package/skills/gsd-next/SKILL.md +6 -1
- package/skills/gsd-ns-context/SKILL.md +4 -0
- package/skills/gsd-ns-ideate/SKILL.md +4 -0
- package/skills/gsd-ns-manage/SKILL.md +4 -0
- package/skills/gsd-ns-project/SKILL.md +4 -0
- package/skills/gsd-ns-review/SKILL.md +4 -0
- package/skills/gsd-ns-workflow/SKILL.md +4 -0
- package/skills/gsd-onboard/SKILL.md +6 -1
- package/skills/gsd-pause-work/SKILL.md +5 -1
- package/skills/gsd-phase/SKILL.md +8 -4
- package/skills/gsd-plan-phase/SKILL.md +6 -1
- package/skills/gsd-plan-review-convergence/SKILL.md +5 -1
- package/skills/gsd-pr-branch/SKILL.md +4 -0
- package/skills/gsd-profile-user/SKILL.md +5 -1
- package/skills/gsd-progress/SKILL.md +6 -1
- package/skills/gsd-quick/SKILL.md +16 -10
- package/skills/gsd-quick-batch/SKILL.md +20 -8
- package/skills/gsd-review/SKILL.md +5 -1
- package/skills/gsd-review-backlog/SKILL.md +3 -2
- package/skills/gsd-secure-phase/SKILL.md +6 -1
- package/skills/gsd-ship/SKILL.md +5 -0
- package/skills/gsd-sketch/SKILL.md +7 -2
- package/skills/gsd-spec-phase/SKILL.md +5 -1
- package/skills/gsd-spike/SKILL.md +8 -3
- package/skills/gsd-surface/SKILL.md +5 -1
- package/skills/gsd-thread/SKILL.md +4 -0
- package/skills/gsd-ui-phase/SKILL.md +6 -1
- package/skills/gsd-ui-review/SKILL.md +6 -1
- package/skills/gsd-ultraplan-phase/SKILL.md +5 -1
- package/skills/gsd-undo/SKILL.md +5 -1
- package/skills/gsd-update/SKILL.md +6 -2
- package/skills/gsd-validate-phase/SKILL.md +6 -1
- package/skills/gsd-verify-work/SKILL.md +6 -1
- package/skills/gsd-workspace/SKILL.md +7 -3
- package/skills/gsd-workstreams/SKILL.md +6 -6
- package/vscode/package.json +1 -1
- package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +0 -24
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TestStatus = exports.ReportFormat = void 0;
|
|
4
|
+
exports.parseTestReport = parseTestReport;
|
|
5
|
+
/** Format adapters for RED evidence. Parsing never depends on the runner command. */
|
|
6
|
+
const tap_parser_cjs_1 = require("./vendor/tap-parser.cjs");
|
|
7
|
+
const saxes_cjs_1 = require("./vendor/saxes.cjs");
|
|
8
|
+
exports.ReportFormat = {
|
|
9
|
+
Tap: 'tap', Junit: 'junit', SwiftTesting: 'swift-testing', Unittest: 'unittest', Unknown: 'unknown',
|
|
10
|
+
};
|
|
11
|
+
exports.TestStatus = { Passed: 'passed', Failed: 'failed', Skipped: 'skipped', Todo: 'todo' };
|
|
12
|
+
function parseTap(output) {
|
|
13
|
+
const report = { format: exports.ReportFormat.Tap, valid: true, tests: [], issues: [] };
|
|
14
|
+
const parser = new tap_parser_cjs_1.Parser({ strict: true });
|
|
15
|
+
const assertions = [];
|
|
16
|
+
const openBuffered = new Map();
|
|
17
|
+
let completed = false;
|
|
18
|
+
const watch = (p) => {
|
|
19
|
+
p.on('child', (child) => {
|
|
20
|
+
if (child.buffered)
|
|
21
|
+
openBuffered.set(p, (openBuffered.get(p) ?? 0) + 1);
|
|
22
|
+
watch(child);
|
|
23
|
+
});
|
|
24
|
+
// tap-parser finalizes buffered children at EOF even without their closing
|
|
25
|
+
// brace. Track its child/line events so that truncation cannot prove RED.
|
|
26
|
+
p.on('line', (line) => {
|
|
27
|
+
if (line === '}\n')
|
|
28
|
+
openBuffered.set(p, (openBuffered.get(p) ?? 0) - 1);
|
|
29
|
+
});
|
|
30
|
+
p.on('assert', (result) => {
|
|
31
|
+
if (!result.closingTestPoint)
|
|
32
|
+
assertions.push({ result, owner: p });
|
|
33
|
+
if (result.buffered && !result.closingTestPoint)
|
|
34
|
+
report.issues.push('Missing buffered TAP subtest');
|
|
35
|
+
const diag = result.diag;
|
|
36
|
+
if (diag && ['cancelledByParent', 'hookFailed', 'testTimeoutFailure'].includes(String(diag['failureType']))) {
|
|
37
|
+
report.issues.push('Test run interrupted by cancellation, hook failure, or timeout');
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
p.on('extra', (extra) => { if (extra.trim())
|
|
41
|
+
report.issues.push('Non-TAP data in report'); });
|
|
42
|
+
p.on('complete', (summary) => {
|
|
43
|
+
if (p === parser)
|
|
44
|
+
completed = true;
|
|
45
|
+
const { start, end } = summary.plan;
|
|
46
|
+
if (start !== 1 || end === null || summary.count !== end)
|
|
47
|
+
report.issues.push('Missing or incomplete TAP plan');
|
|
48
|
+
if (summary.bailout)
|
|
49
|
+
report.issues.push('TAP bailout');
|
|
50
|
+
if (summary.failures.some((failure) => failure.tapError))
|
|
51
|
+
report.issues.push('Malformed TAP');
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
watch(parser);
|
|
55
|
+
parser.end(output);
|
|
56
|
+
if ([...openBuffered.values()].some((count) => count !== 0))
|
|
57
|
+
report.issues.push('Unclosed buffered TAP subtest');
|
|
58
|
+
for (const { result, owner } of assertions) {
|
|
59
|
+
let skipped = Boolean(result.skip);
|
|
60
|
+
let todo = Boolean(result.todo);
|
|
61
|
+
for (let parent = owner; parent; parent = parent.parent) {
|
|
62
|
+
skipped ||= Boolean(parent.closingTestPoint?.skip);
|
|
63
|
+
todo ||= Boolean(parent.closingTestPoint?.todo);
|
|
64
|
+
}
|
|
65
|
+
report.tests.push({
|
|
66
|
+
name: result.name,
|
|
67
|
+
identities: [...new Set([result.name, result.fullname])],
|
|
68
|
+
group: null,
|
|
69
|
+
groupIdentities: [],
|
|
70
|
+
status: skipped ? exports.TestStatus.Skipped : todo ? exports.TestStatus.Todo : result.ok ? exports.TestStatus.Passed : exports.TestStatus.Failed,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
if (!completed)
|
|
74
|
+
report.issues.push('Incomplete TAP stream');
|
|
75
|
+
report.valid = report.issues.length === 0;
|
|
76
|
+
return report;
|
|
77
|
+
}
|
|
78
|
+
/** Surefire and Failsafe share the JUnit XML report shape. */
|
|
79
|
+
function parseJunit(output) {
|
|
80
|
+
const report = { format: exports.ReportFormat.Junit, valid: true, tests: [], issues: [] };
|
|
81
|
+
const parser = new saxes_cjs_1.SaxesParser({ xmlns: false });
|
|
82
|
+
const elements = [];
|
|
83
|
+
const suites = [];
|
|
84
|
+
let current = null;
|
|
85
|
+
parser.on('error', () => { report.issues.push('Malformed XML'); });
|
|
86
|
+
parser.on('doctype', () => { report.issues.push('JUnit reports must not declare a DTD'); });
|
|
87
|
+
parser.on('opentag', (tag) => {
|
|
88
|
+
const parent = elements.at(-1);
|
|
89
|
+
if (!parent && tag.name !== 'testsuite' && tag.name !== 'testsuites')
|
|
90
|
+
report.issues.push('Not a JUnit report');
|
|
91
|
+
if (tag.name === 'testsuite' || tag.name === 'testsuites') {
|
|
92
|
+
if (parent && parent !== 'testsuite' && parent !== 'testsuites')
|
|
93
|
+
report.issues.push('Misplaced test suite');
|
|
94
|
+
const count = tag.attributes['tests'];
|
|
95
|
+
const planned = count === undefined ? null : Number(count);
|
|
96
|
+
if (count !== undefined && (!/^\d+$/.test(count) || !Number.isSafeInteger(planned)))
|
|
97
|
+
report.issues.push('Invalid JUnit test count');
|
|
98
|
+
suites.push({ firstTest: report.tests.length, planned });
|
|
99
|
+
}
|
|
100
|
+
else if (tag.name === 'testcase') {
|
|
101
|
+
if (parent !== 'testsuite' || current)
|
|
102
|
+
report.issues.push('Misplaced test case');
|
|
103
|
+
const name = tag.attributes['name'] ?? '';
|
|
104
|
+
const className = tag.attributes['classname'] ?? '';
|
|
105
|
+
const qualified = className ? `${className}#${name}` : name;
|
|
106
|
+
if (!name)
|
|
107
|
+
report.issues.push('Unnamed test case');
|
|
108
|
+
current = {
|
|
109
|
+
name: qualified,
|
|
110
|
+
identities: [...new Set([name, qualified])],
|
|
111
|
+
group: className || null,
|
|
112
|
+
groupIdentities: className ? [className, className.split('.').at(-1)] : [],
|
|
113
|
+
status: exports.TestStatus.Passed,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
else if (current && parent === 'testcase') {
|
|
117
|
+
if (tag.name === 'failure' || tag.name === 'error') {
|
|
118
|
+
if (current.status === exports.TestStatus.Skipped)
|
|
119
|
+
report.issues.push('Contradictory JUnit status');
|
|
120
|
+
current.status = exports.TestStatus.Failed;
|
|
121
|
+
}
|
|
122
|
+
if (tag.name === 'skipped') {
|
|
123
|
+
if (current.status === exports.TestStatus.Failed)
|
|
124
|
+
report.issues.push('Contradictory JUnit status');
|
|
125
|
+
current.status = exports.TestStatus.Skipped;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
elements.push(tag.name);
|
|
129
|
+
});
|
|
130
|
+
parser.on('closetag', (tag) => {
|
|
131
|
+
if (tag.name === 'testcase' && current) {
|
|
132
|
+
report.tests.push(current);
|
|
133
|
+
current = null;
|
|
134
|
+
}
|
|
135
|
+
else if (tag.name === 'testsuite' || tag.name === 'testsuites') {
|
|
136
|
+
const suite = suites.pop();
|
|
137
|
+
if (!suite || (suite.planned !== null && suite.planned !== report.tests.length - suite.firstTest)) {
|
|
138
|
+
report.issues.push('Incomplete JUnit test suite');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
elements.pop();
|
|
142
|
+
});
|
|
143
|
+
parser.write(output).close();
|
|
144
|
+
report.valid = report.issues.length === 0;
|
|
145
|
+
return report;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* swift-testing console output (#4957). Only the anchored aggregate line marks
|
|
149
|
+
* the format; every declared test must have its own result line. The aggregate
|
|
150
|
+
* counts skipped tests too, and a parameterized test names its case count.
|
|
151
|
+
* A test is named by its quoted display name (with `(aka 'function()')` under
|
|
152
|
+
* --verbose) or, without one, by its bare function name. Windows consoles
|
|
153
|
+
* print โ ร - in place of โ โ โ. swift-testing 6.1 omits the suite count from
|
|
154
|
+
* the aggregate and marks skipped tests with โ (later sources add the count
|
|
155
|
+
* and use โ).
|
|
156
|
+
*/
|
|
157
|
+
const SWIFT_AGGREGATE = /^[ \t]*[โโโรโ-][ \t]*Test run with (\d+) tests?(?: in \d+ suites?)? (passed|failed)\b/gm;
|
|
158
|
+
const SWIFT_RESULT = /^[ \t]*[โโโโรโ-][ \t]*Test (?:"([^"]+)"(?: \(aka '([^']+)'\))?|([^\s"]\S*\)))(?: with \d+ test cases?)? (?:(failed|passed|was cancelled) after [\d.]+ seconds?(?: with \d+ [^\n]*?)?(?:\.|: "[^\n]*")|(skipped)(?:\.|: "[^\n]*"))$/gm;
|
|
159
|
+
function parseSwiftTesting(output) {
|
|
160
|
+
const report = { format: exports.ReportFormat.SwiftTesting, valid: true, tests: [], issues: [] };
|
|
161
|
+
let declared = 0;
|
|
162
|
+
let runPassed = true;
|
|
163
|
+
for (const match of output.matchAll(SWIFT_AGGREGATE)) {
|
|
164
|
+
declared += Number(match[1]);
|
|
165
|
+
runPassed &&= match[2] === 'passed';
|
|
166
|
+
}
|
|
167
|
+
for (const match of output.matchAll(SWIFT_RESULT)) {
|
|
168
|
+
const fn = match[2] ?? match[3];
|
|
169
|
+
report.tests.push({
|
|
170
|
+
name: match[1] ?? match[3],
|
|
171
|
+
identities: [...new Set([match[1], fn, fn?.replace(/\(.*\)$/, '')].filter((id) => Boolean(id)))],
|
|
172
|
+
group: null,
|
|
173
|
+
groupIdentities: [],
|
|
174
|
+
status: match[4] === 'failed' ? exports.TestStatus.Failed : match[4] === 'passed' ? exports.TestStatus.Passed : exports.TestStatus.Skipped,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (report.tests.length !== declared)
|
|
178
|
+
report.issues.push('Incomplete swift-testing report');
|
|
179
|
+
if (runPassed && report.tests.some((test) => test.status === exports.TestStatus.Failed)) {
|
|
180
|
+
report.issues.push('Contradictory swift-testing status');
|
|
181
|
+
}
|
|
182
|
+
report.valid = report.issues.length === 0;
|
|
183
|
+
return report;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Python stdlib unittest text output (#4970). Passing tests are unnamed unless
|
|
187
|
+
* verbose, so they are counted from the summary; failures are named by their
|
|
188
|
+
* FAIL:/ERROR: headers, which must account for every counted failure. Each
|
|
189
|
+
* failing subTest repeats its method's header and counts as a failure, while
|
|
190
|
+
* Ran counts methods, so identical headers collapse into one failed test. An
|
|
191
|
+
* unexpected success fails the run but is a test that passed.
|
|
192
|
+
*/
|
|
193
|
+
const UNITTEST_RAN = /^Ran (\d+) tests? in [\d.]+s$/gm;
|
|
194
|
+
const UNITTEST_HEADER = /^(?:FAIL|ERROR): (\S+)(?: \(([^)]*)\))?/gm;
|
|
195
|
+
function parseUnittest(output) {
|
|
196
|
+
const report = { format: exports.ReportFormat.Unittest, valid: true, tests: [], issues: [] };
|
|
197
|
+
const runs = [...output.matchAll(UNITTEST_RAN)];
|
|
198
|
+
if (runs.length !== 1) {
|
|
199
|
+
report.issues.push('Expected exactly one unittest summary');
|
|
200
|
+
report.valid = false;
|
|
201
|
+
return report;
|
|
202
|
+
}
|
|
203
|
+
const ran = Number(runs[0][1]);
|
|
204
|
+
const outcome = /^(OK|FAILED)(?: \(([^)]*)\))?$/m.exec(output.slice(runs[0].index + runs[0][0].length));
|
|
205
|
+
const counts = {};
|
|
206
|
+
for (const part of outcome?.[2]?.split(', ') ?? []) {
|
|
207
|
+
const [key, value] = part.split('=');
|
|
208
|
+
counts[key] = Number(value);
|
|
209
|
+
}
|
|
210
|
+
if (!outcome || Object.keys(counts).some((key) => !['failures', 'errors', 'skipped', 'expected failures', 'unexpected successes'].includes(key))) {
|
|
211
|
+
report.issues.push('Unsupported unittest outcome');
|
|
212
|
+
}
|
|
213
|
+
let headers = 0;
|
|
214
|
+
const failedIds = new Set();
|
|
215
|
+
for (const match of output.matchAll(UNITTEST_HEADER)) {
|
|
216
|
+
headers++;
|
|
217
|
+
const id = match[2] ?? '';
|
|
218
|
+
const key = `${match[1]} ${id}`;
|
|
219
|
+
if (failedIds.has(key))
|
|
220
|
+
continue;
|
|
221
|
+
failedIds.add(key);
|
|
222
|
+
// unittest synthesizes _FailedTest for an import/collection crash; its
|
|
223
|
+
// method name can equal the target, so it is a load failure, never RED.
|
|
224
|
+
if (id.includes('_FailedTest')) {
|
|
225
|
+
report.issues.push('unittest module failed to load');
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
report.tests.push({
|
|
229
|
+
name: match[1],
|
|
230
|
+
identities: [...new Set([match[1], id].filter(Boolean))],
|
|
231
|
+
group: null,
|
|
232
|
+
groupIdentities: [],
|
|
233
|
+
status: exports.TestStatus.Failed,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
const failed = (counts['failures'] ?? 0) + (counts['errors'] ?? 0);
|
|
237
|
+
const skipped = counts['skipped'] ?? 0;
|
|
238
|
+
const runFailed = failed > 0 || (counts['unexpected successes'] ?? 0) > 0;
|
|
239
|
+
if (headers !== failed || (outcome?.[1] === 'FAILED') !== runFailed || failedIds.size + skipped > ran) {
|
|
240
|
+
report.issues.push('Incomplete unittest report');
|
|
241
|
+
}
|
|
242
|
+
const unnamed = (status) => ({ name: '', identities: [], group: null, groupIdentities: [], status });
|
|
243
|
+
for (let i = 0; i < skipped; i++)
|
|
244
|
+
report.tests.push(unnamed(exports.TestStatus.Skipped));
|
|
245
|
+
for (let i = Math.max(ran - failedIds.size - skipped, 0); i > 0; i--)
|
|
246
|
+
report.tests.push(unnamed(exports.TestStatus.Passed));
|
|
247
|
+
report.valid = report.issues.length === 0;
|
|
248
|
+
return report;
|
|
249
|
+
}
|
|
250
|
+
const adapters = [
|
|
251
|
+
{ matches: (output) => /^(?:TAP version \d+|(?:not )?ok\b|1\.\.\d+|#)/.test(output.trimStart()), parse: parseTap },
|
|
252
|
+
{ matches: (output) => output.trimStart().startsWith('<'), parse: parseJunit },
|
|
253
|
+
{ matches: (output) => new RegExp(SWIFT_AGGREGATE.source, 'm').test(output), parse: parseSwiftTesting },
|
|
254
|
+
{ matches: (output) => new RegExp(UNITTEST_RAN.source, 'm').test(output), parse: parseUnittest },
|
|
255
|
+
];
|
|
256
|
+
/** Parse supported reports into one result contract; unknown/malformed input fails closed. */
|
|
257
|
+
function parseTestReport(output) {
|
|
258
|
+
const adapter = adapters.find((candidate) => candidate.matches(output));
|
|
259
|
+
if (!adapter)
|
|
260
|
+
return { format: exports.ReportFormat.Unknown, valid: false, tests: [], issues: ['Unsupported report format'] };
|
|
261
|
+
try {
|
|
262
|
+
const report = adapter.parse(output);
|
|
263
|
+
// One entry per problem: a long run of bad lines must not amplify the payload.
|
|
264
|
+
return { ...report, issues: [...new Set(report.issues)] };
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
return { format: exports.ReportFormat.Unknown, valid: false, tests: [], issues: ['Malformed report'] };
|
|
268
|
+
}
|
|
269
|
+
}
|
|
@@ -13,6 +13,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
13
13
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
14
14
|
const node_path_1 = __importDefault(require("node:path"));
|
|
15
15
|
const command_aliases_cjs_1 = require("./command-aliases.cjs");
|
|
16
|
+
const frontmatter_fence_cjs_1 = require("./frontmatter-fence.cjs");
|
|
16
17
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
17
18
|
const cjsCommandRouterAdapter = require("./cjs-command-router-adapter.cjs");
|
|
18
19
|
const { routeCjsCommandFamily } = cjsCommandRouterAdapter;
|
|
@@ -145,14 +146,13 @@ function routeRoadmapCommand({ roadmap, args, cwd, raw, error }) {
|
|
|
145
146
|
if (roadmapContent.trim() === '') {
|
|
146
147
|
warnings.push({ code: 'V002', message: 'ROADMAP.md is empty' });
|
|
147
148
|
}
|
|
148
|
-
// Malformed frontmatter โ a `---` opener with no matching closer
|
|
149
|
-
//
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
149
|
+
// Malformed frontmatter โ a `---` opener with no matching closer, as the one fence
|
|
150
|
+
// owner reads it (a leading BOM, #3057, is tolerated there).
|
|
151
|
+
const roadmapFence = (0, frontmatter_fence_cjs_1.locateFrontmatterFence)(roadmapContent);
|
|
152
|
+
// The milestone-window read below sees the document without its leading BOM (#3057).
|
|
153
|
+
const contentAfterBom = roadmapContent.charCodeAt(0) === 0xFEFF ? roadmapContent.slice(1) : roadmapContent;
|
|
154
|
+
if (roadmapFence && !roadmapFence.closed) {
|
|
155
|
+
warnings.push({ code: 'V003', message: 'ROADMAP.md frontmatter is malformed (unterminated --- fence)' });
|
|
156
156
|
}
|
|
157
157
|
// #3641: resolve phase_id_convention ONCE, ahead of every consumer in
|
|
158
158
|
// this validate pass โ V004's entry check and V005's scope classifier
|
|
@@ -169,13 +169,11 @@ function routeRoadmapCommand({ roadmap, args, cwd, raw, error }) {
|
|
|
169
169
|
convention = undefined;
|
|
170
170
|
}
|
|
171
171
|
if (convention === undefined || convention === null) {
|
|
172
|
-
// Fallback: read from ROADMAP.md frontmatter
|
|
173
|
-
// cmdRoadmapMilestoneScope
|
|
174
|
-
//
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (fmMatch) {
|
|
178
|
-
const kvMatch = fmMatch[1].match(/^phase_id_convention:\s*(.*)$/m);
|
|
172
|
+
// Fallback: read from ROADMAP.md frontmatter โ the block the one fence owner finds,
|
|
173
|
+
// exactly as cmdRoadmapMilestoneScope reads it (#3641 review NEW-1: two copies of
|
|
174
|
+
// this read disagreed on long frontmatter, diverging validate from the probe).
|
|
175
|
+
if (roadmapFence?.closed) {
|
|
176
|
+
const kvMatch = roadmapContent.slice(roadmapFence.openEnd, roadmapFence.bodyEnd).match(/^phase_id_convention:\s*(.*)$/m);
|
|
179
177
|
if (kvMatch) {
|
|
180
178
|
const val = kvMatch[1].trim();
|
|
181
179
|
if (val !== 'null' && val !== '') {
|
|
@@ -926,6 +926,44 @@ function classifyMilestoneWindow(input) {
|
|
|
926
926
|
SCOPE.COMPLETE // rows 6, 7
|
|
927
927
|
);
|
|
928
928
|
}
|
|
929
|
+
// #5007 (Phase 6 / ADR-4910 ยง8): the bulk phase-heading-block strip (heading
|
|
930
|
+
// line + body through to the next heading of any level) used by BOTH the
|
|
931
|
+
// <details>-fallback branch and preambleWithoutPhaseDetails inside
|
|
932
|
+
// extractCurrentMilestoneScoped below โ literally the same regex, previously
|
|
933
|
+
// duplicated verbatim at both call sites. Composed from
|
|
934
|
+
// phaseHeadingPrefixSrcFor (LABEL_ONLY, no convention argument โ reproduces
|
|
935
|
+
// the prior bare `Phase\s+` literal byte-for-byte, same non-widening
|
|
936
|
+
// discipline as the phase.cts counter sites) rather than routed through
|
|
937
|
+
// buildPhaseHeadingScanRegex, since this site needs the whole matched block
|
|
938
|
+
// (heading + body), not a phase-number/title capture. The one real behavior
|
|
939
|
+
// change here is the phase-number token itself: the prior literal admitted
|
|
940
|
+
// any `[\w][\w.-]*` (including non-numeric garbage); PHASE_NUMBER_TOKEN_SOURCE
|
|
941
|
+
// tightens it to the real phase-number grammar (digits, optional trailing
|
|
942
|
+
// letter, dotted subphases) โ verified against real phase-number fixtures
|
|
943
|
+
// (plain, decimal, and bracket-tag-bearing) in tests/roadmap-parser.test.cjs.
|
|
944
|
+
const PHASE_HEADING_BLOCK_STRIP_RE = new RegExp(
|
|
945
|
+
// #1729: `(?:\s*\([^)\n]{0,200}\))?` (OPTIONAL_PHASE_TAG_SOURCE) tolerates a pre-colon ( ) tag.
|
|
946
|
+
`^#{2,4}\\s*${phaseHeadingPrefixSrcFor(PHASE_HEADING_BASELINE.LABEL_ONLY)}${PHASE_NUMBER_TOKEN_SOURCE}${OPTIONAL_PHASE_TAG_SOURCE}\\s*:[^\\n]*(?:\\n(?!#{1,6}\\s)[^\\n]*)*\\n?`, 'gim');
|
|
947
|
+
/**
|
|
948
|
+
* #5038: single owner for classifying a `milestone:` scalar as STATE.md spells
|
|
949
|
+
* it. The frontmatter parser (FAILSAFE_SCHEMA) and the raw-regex readers both
|
|
950
|
+
* see YAML null as text, so every reader classifies it here. Recognizes the
|
|
951
|
+
* YAML 1.2 core-schema null spellings (`null`, `Null`, `NULL`, `~`) with an
|
|
952
|
+
* optional trailing ` # comment` and optional surrounding quotes (the
|
|
953
|
+
* frontmatter parser has already stripped them, so the raw readers must agree);
|
|
954
|
+
* a blank value is absent, not null.
|
|
955
|
+
*/
|
|
956
|
+
function classifyMilestoneScalar(raw) {
|
|
957
|
+
if (typeof raw !== 'string')
|
|
958
|
+
return { explicitNull: false, version: null };
|
|
959
|
+
const trimmed = raw.trim();
|
|
960
|
+
if (trimmed === '')
|
|
961
|
+
return { explicitNull: false, version: null };
|
|
962
|
+
const bare = trimmed.replace(/\s+#.*$/, '').trim().replace(/^(['"])(.*)\1$/, '$2');
|
|
963
|
+
if (/^(?:null|Null|NULL|~)$/.test(bare))
|
|
964
|
+
return { explicitNull: true, version: null };
|
|
965
|
+
return { explicitNull: false, version: trimmed };
|
|
966
|
+
}
|
|
929
967
|
/**
|
|
930
968
|
* Extract the current milestone section from ROADMAP.md by positive lookup,
|
|
931
969
|
* carrying a `scope` discriminator (ADR-3180 Decision 2) alongside the value.
|
|
@@ -960,18 +998,23 @@ function extractCurrentMilestoneScoped(content, cwd, ws, phaseIdConvention) {
|
|
|
960
998
|
return { value: stripShippedMilestones(content), scope: SCOPE.COMPLETE };
|
|
961
999
|
}
|
|
962
1000
|
let version = null;
|
|
1001
|
+
let stateAssertsNoMilestone = false;
|
|
963
1002
|
try {
|
|
964
1003
|
const statePath = node_path_1.default.join(planningDir(cwd, ws), 'STATE.md');
|
|
965
1004
|
const stateRaw = (0, shell_command_projection_cjs_1.platformReadSync)(statePath);
|
|
966
1005
|
if (stateRaw !== null) {
|
|
967
1006
|
const milestoneMatch = stateRaw.match(/^milestone:\s*(.+)/m);
|
|
968
1007
|
if (milestoneMatch) {
|
|
969
|
-
|
|
1008
|
+
const classified = classifyMilestoneScalar(milestoneMatch[1]);
|
|
1009
|
+
version = classified.version;
|
|
1010
|
+
stateAssertsNoMilestone = classified.explicitNull;
|
|
970
1011
|
}
|
|
971
1012
|
}
|
|
972
1013
|
}
|
|
973
1014
|
catch { /* ignore */ }
|
|
974
|
-
|
|
1015
|
+
// #5038: an explicit `milestone: null` is a deliberate "no milestone" โ do
|
|
1016
|
+
// not let the in-progress bullet guess one (same stance as getMilestoneInfo).
|
|
1017
|
+
if (!version && !stateAssertsNoMilestone) {
|
|
975
1018
|
const inProgressMatch = content.match(/(?:๐ง|๐)\s*\*\*v(\d+\.\d+)\s/);
|
|
976
1019
|
if (inProgressMatch) {
|
|
977
1020
|
version = 'v' + inProgressMatch[1];
|
|
@@ -1050,9 +1093,9 @@ function extractCurrentMilestoneScoped(content, cwd, ws, phaseIdConvention) {
|
|
|
1050
1093
|
const firstMilestoneMatch = content.match(anyMilestoneOrDetails);
|
|
1051
1094
|
const preambleCutoff = firstMilestoneMatch ? firstMilestoneMatch.index : detailsOpenIdx;
|
|
1052
1095
|
const preamble = (0, markdown_sectionizer_cjs_1.stripTaggedBlocks)(content.slice(0, preambleCutoff), 'details')
|
|
1053
|
-
// #
|
|
1054
|
-
//
|
|
1055
|
-
.replace(
|
|
1096
|
+
// #5007 (Phase 6 / ADR-4910 ยง8): shared owner, see
|
|
1097
|
+
// PHASE_HEADING_BLOCK_STRIP_RE above.
|
|
1098
|
+
.replace(PHASE_HEADING_BLOCK_STRIP_RE, '')
|
|
1056
1099
|
.replace(/^#{1,4}\s*Phase Details\b[^\n]*\n?/gim, '');
|
|
1057
1100
|
const value = preamble + content.slice(detailsOpenIdx, detailsEnd);
|
|
1058
1101
|
return {
|
|
@@ -1287,17 +1330,23 @@ function extractCurrentMilestoneScoped(content, cwd, ws, phaseIdConvention) {
|
|
|
1287
1330
|
// every phase (phase_count: 0, exit 0). Only strip preamble phase details when
|
|
1288
1331
|
// the selected milestone section actually contains its own โ otherwise the
|
|
1289
1332
|
// preamble phases ARE this milestone's phases and must be preserved.
|
|
1290
|
-
//
|
|
1291
|
-
|
|
1333
|
+
// #5007 (Phase 6 / ADR-4910 ยง8): a pure "does this section have ANY phase
|
|
1334
|
+
// heading" boolean โ same shape as phase.cts:1691's anyHeadingPattern
|
|
1335
|
+
// (composed directly from phaseHeadingPrefixSrcFor, no shared owner exposes
|
|
1336
|
+
// a captureless existence check), but this site's terminal token is `\S`
|
|
1337
|
+
// (any non-whitespace), not phase.cts:1691's `\d` โ kept as `\S` to
|
|
1338
|
+
// reproduce this site's own prior behavior byte-for-byte rather than
|
|
1339
|
+
// forcing the two sites onto an identical terminal token that would be a
|
|
1340
|
+
// behavior change here.
|
|
1341
|
+
const currentSectionHasPhaseDetails = new RegExp(`^#{2,4}\\s*${phaseHeadingPrefixSrcFor(PHASE_HEADING_BASELINE.LABEL_ONLY)}\\S`, 'im').test(currentSection);
|
|
1292
1342
|
const preambleBase = (0, markdown_sectionizer_cjs_1.stripTaggedBlocks)(beforeMilestones, 'details');
|
|
1293
1343
|
// #3235: the conditional wraps the REPLACE, not the pattern. This used to select between the
|
|
1294
1344
|
// strip regex and a `/$/` sentinel, which made the do-not-strip branch an identity replacement
|
|
1295
1345
|
// (CodeQL js/identity-replacement, alert 53) -- correct, but it left both branches sharing one
|
|
1296
1346
|
// replacement argument, so changing `''` would silently give the no-op branch a real effect.
|
|
1297
|
-
// #
|
|
1347
|
+
// #5007 (Phase 6 / ADR-4910 ยง8): shared owner, see PHASE_HEADING_BLOCK_STRIP_RE above.
|
|
1298
1348
|
const preambleWithoutPhaseDetails = currentSectionHasPhaseDetails
|
|
1299
|
-
|
|
1300
|
-
? preambleBase.replace(/^#{2,4}\s*Phase\s+[\w][\w.-]*(?:\s*\([^)\n]{0,200}\))?\s*:[^\n]*(?:\n(?!#{1,6}\s)[^\n]*)*\n?/gim, '')
|
|
1349
|
+
? preambleBase.replace(PHASE_HEADING_BLOCK_STRIP_RE, '')
|
|
1301
1350
|
: preambleBase;
|
|
1302
1351
|
// Unconditional in BOTH branches -- the #730 `Phase Details` heading strip is independent of
|
|
1303
1352
|
// whether the selected milestone section carries phase details of its own.
|
|
@@ -1707,14 +1756,22 @@ function getMilestoneInfo(cwd) {
|
|
|
1707
1756
|
if (roadmap === null)
|
|
1708
1757
|
throw new Error('missing');
|
|
1709
1758
|
let stateVersion = null;
|
|
1759
|
+
// #5038: true only when the `milestone:` key is PRESENT and classifies as
|
|
1760
|
+
// an explicit null (any spelling classifyMilestoneScalar accepts), as
|
|
1761
|
+
// opposed to ABSENT. Gates the ROADMAP auto-derivation fallback, which
|
|
1762
|
+
// only bootstraps a milestone for a project that never mentioned one.
|
|
1763
|
+
let explicitlyNoMilestone = false;
|
|
1710
1764
|
if (cwd) {
|
|
1711
1765
|
try {
|
|
1712
1766
|
const statePath = node_path_1.default.join(planningDir(cwd), 'STATE.md');
|
|
1713
1767
|
const stateRaw = (0, shell_command_projection_cjs_1.platformReadSync)(statePath);
|
|
1714
1768
|
if (stateRaw !== null) {
|
|
1715
1769
|
const m = stateRaw.match(/^milestone:\s*(.+)/m);
|
|
1716
|
-
if (m)
|
|
1717
|
-
|
|
1770
|
+
if (m) {
|
|
1771
|
+
const classified = classifyMilestoneScalar(m[1]);
|
|
1772
|
+
explicitlyNoMilestone = classified.explicitNull;
|
|
1773
|
+
stateVersion = classified.version;
|
|
1774
|
+
}
|
|
1718
1775
|
}
|
|
1719
1776
|
}
|
|
1720
1777
|
catch {
|
|
@@ -1771,6 +1828,11 @@ function getMilestoneInfo(cwd) {
|
|
|
1771
1828
|
// or heading-but-nameless). ยง7.2 rule 4 โ never fabricate a name.
|
|
1772
1829
|
return scoped({ version: stateVersion, name: null }, SCOPE.TRUNCATED);
|
|
1773
1830
|
}
|
|
1831
|
+
// #5038: an explicit null is a deliberate "no milestone"; do not let the
|
|
1832
|
+
// auto-derivation fallback below replace it with a guessed version.
|
|
1833
|
+
if (explicitlyNoMilestone) {
|
|
1834
|
+
return scoped(null, SCOPE.UNSCOPED);
|
|
1835
|
+
}
|
|
1774
1836
|
// No STATE.md version. The ๐ง in-progress bullet is still consulted first
|
|
1775
1837
|
// (unchanged from the pre-#3216 fallback).
|
|
1776
1838
|
const inProgressMatch = roadmap.match(/๐ง\s*\*\*v(\d+(?:\.\d+)+)\s+([^*]+)\*\*/);
|
|
@@ -2104,17 +2166,21 @@ function currentMilestoneRawRanges(content, cwd) {
|
|
|
2104
2166
|
if (!cwd)
|
|
2105
2167
|
return null;
|
|
2106
2168
|
let version = null;
|
|
2169
|
+
let stateAssertsNoMilestone = false;
|
|
2107
2170
|
try {
|
|
2108
2171
|
const statePath = node_path_1.default.join(planningDir(cwd), 'STATE.md');
|
|
2109
2172
|
const stateRaw = (0, shell_command_projection_cjs_1.platformReadSync)(statePath);
|
|
2110
2173
|
if (stateRaw !== null) {
|
|
2111
2174
|
const milestoneMatch = stateRaw.match(/^milestone:\s*(.+)/m);
|
|
2112
|
-
if (milestoneMatch)
|
|
2113
|
-
|
|
2175
|
+
if (milestoneMatch) {
|
|
2176
|
+
const classified = classifyMilestoneScalar(milestoneMatch[1]);
|
|
2177
|
+
version = classified.version;
|
|
2178
|
+
stateAssertsNoMilestone = classified.explicitNull;
|
|
2179
|
+
}
|
|
2114
2180
|
}
|
|
2115
2181
|
}
|
|
2116
2182
|
catch { /* ignore */ }
|
|
2117
|
-
if (!version) {
|
|
2183
|
+
if (!version && !stateAssertsNoMilestone) {
|
|
2118
2184
|
const inProgressMatch = content.match(/(?:๐ง|๐)\s*\*\*v(\d+\.\d+)\s/);
|
|
2119
2185
|
if (inProgressMatch)
|
|
2120
2186
|
version = 'v' + inProgressMatch[1];
|
|
@@ -2217,6 +2283,7 @@ module.exports = {
|
|
|
2217
2283
|
replaceInCurrentMilestone,
|
|
2218
2284
|
getRoadmapPhaseInternal,
|
|
2219
2285
|
getMilestoneInfo,
|
|
2286
|
+
classifyMilestoneScalar,
|
|
2220
2287
|
getMilestonePhaseFilter,
|
|
2221
2288
|
currentMilestoneRawRanges,
|
|
2222
2289
|
withPhaseSection,
|