@opengsd/gsd-core 1.11.0 → 1.12.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/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-debug-session-manager.md +1 -1
- package/agents/gsd-debugger.md +1 -1
- package/agents/gsd-dom-verifier.md +169 -0
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +17 -9
- package/agents/gsd-framework-selector.md +1 -3
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +0 -1
- package/agents/gsd-pattern-mapper.md +11 -0
- package/agents/gsd-phase-researcher.md +3 -1
- package/agents/gsd-plan-checker.md +15 -55
- package/agents/gsd-planner.md +6 -4
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.md +2 -2
- package/agents/gsd-roadmapper.md +15 -11
- package/agents/gsd-ui-checker.md +63 -4
- package/agents/gsd-ui-researcher.md +41 -3
- package/agents/gsd-verifier.md +1 -1
- package/bin/install.js +609 -134
- package/commands/gsd/discuss-phase.md +1 -1
- package/commands/gsd/import.md +1 -1
- package/commands/gsd/quick.md +8 -4
- package/gsd-core/bin/gsd-tools.cjs +567 -51
- package/gsd-core/bin/lib/active-workstream-store.cjs +8 -0
- package/gsd-core/bin/lib/adr-parser.cjs +13 -7
- package/gsd-core/bin/lib/agent-install-check.cjs +162 -0
- package/gsd-core/bin/lib/api-coverage.cjs +30 -9
- package/gsd-core/bin/lib/artifacts.cjs +2 -0
- package/gsd-core/bin/lib/assumption-delta.cjs +30 -11
- package/gsd-core/bin/lib/audit.cjs +163 -41
- package/gsd-core/bin/lib/broken-windows.cjs +306 -28
- package/gsd-core/bin/lib/capability-lock.cjs +10 -4
- package/gsd-core/bin/lib/capability-registry.cjs +336 -95
- package/gsd-core/bin/lib/capability-state.cjs +18 -3
- package/gsd-core/bin/lib/capability-validator.cjs +205 -18
- package/gsd-core/bin/lib/check-command-router.cjs +145 -5
- package/gsd-core/bin/lib/cli-exit.cjs +496 -10
- package/gsd-core/bin/lib/code-review-depth.cjs +288 -0
- package/gsd-core/bin/lib/codex-agent-toml.cjs +410 -4
- package/gsd-core/bin/lib/command-arg-projection.cjs +144 -14
- package/gsd-core/bin/lib/command-routing-hub.cjs +31 -2
- package/gsd-core/bin/lib/commands.cjs +543 -44
- package/gsd-core/bin/lib/complexity-trigger.cjs +26 -6
- package/gsd-core/bin/lib/config-loader.cjs +118 -29
- package/gsd-core/bin/lib/config.cjs +92 -2
- package/gsd-core/bin/lib/configuration.cjs +129 -37
- package/gsd-core/bin/lib/core-utils.cjs +84 -7
- package/gsd-core/bin/lib/edge-probe.cjs +9 -1
- package/gsd-core/bin/lib/estimate-cli.cjs +55 -11
- package/gsd-core/bin/lib/exit-code-registry.cjs +98 -0
- package/gsd-core/bin/lib/frontmatter.cjs +840 -305
- package/gsd-core/bin/lib/gap-checker.cjs +27 -3
- package/gsd-core/bin/lib/git-base-branch.cjs +174 -39
- package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +7 -3
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +6 -3
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +22 -8
- package/gsd-core/bin/lib/health-diagnostic.cjs +23 -3
- package/gsd-core/bin/lib/host-integration.cjs +39 -6
- package/gsd-core/bin/lib/init-command-router.cjs +118 -21
- package/gsd-core/bin/lib/init.cjs +120 -41
- package/gsd-core/bin/lib/install-engine.cjs +68 -3
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +33 -1
- package/gsd-core/bin/lib/install-profiles.cjs +78 -4
- package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
- package/gsd-core/bin/lib/installer-migrations/010-antigravity-retire-confighome-artifacts.cjs +169 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +10 -7
- package/gsd-core/bin/lib/intel.cjs +101 -26
- package/gsd-core/bin/lib/io.cjs +160 -15
- package/gsd-core/bin/lib/learnings.cjs +85 -14
- package/gsd-core/bin/lib/legacy-cleanup.cjs +8 -2
- package/gsd-core/bin/lib/markdown-table.cjs +52 -4
- package/gsd-core/bin/lib/milestone.cjs +90 -5
- package/gsd-core/bin/lib/model-catalog.cjs +177 -19
- package/gsd-core/bin/lib/model-resolver.cjs +10 -28
- package/gsd-core/bin/lib/onboard-projection.cjs +5 -1
- package/gsd-core/bin/lib/phase-estimation.cjs +17 -8
- package/gsd-core/bin/lib/phase-id.cjs +70 -4
- package/gsd-core/bin/lib/phase-lifecycle.cjs +24 -16
- package/gsd-core/bin/lib/phase-locator.cjs +138 -17
- package/gsd-core/bin/lib/phase.cjs +405 -84
- package/gsd-core/bin/lib/plan-document.cjs +263 -0
- package/gsd-core/bin/lib/plan-scan.cjs +13 -2
- package/gsd-core/bin/lib/planning-command-router.cjs +61 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +1168 -0
- package/gsd-core/bin/lib/planning-snapshot.cjs +18 -14
- package/gsd-core/bin/lib/planning-workspace.cjs +56 -0
- package/gsd-core/bin/lib/probe-core.cjs +4 -1
- package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +50 -7
- package/gsd-core/bin/lib/profile-pipeline.cjs +6 -3
- package/gsd-core/bin/lib/real-home-guard.cjs +419 -0
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +71 -45
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +9 -9
- package/gsd-core/bin/lib/roadmap-command-router.cjs +45 -31
- package/gsd-core/bin/lib/roadmap-parser.cjs +79 -16
- package/gsd-core/bin/lib/roadmap.cjs +74 -19
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +96 -8
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +34 -1
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +287 -55
- package/gsd-core/bin/lib/runtime-identity.cjs +234 -0
- package/gsd-core/bin/lib/runtime-slash.cjs +72 -2
- package/gsd-core/bin/lib/shell-command-projection.cjs +71 -8
- package/gsd-core/bin/lib/smart-entry.cjs +12 -22
- package/gsd-core/bin/lib/spec-section.cjs +12 -7
- package/gsd-core/bin/lib/state-command-router.cjs +47 -18
- package/gsd-core/bin/lib/state-contract.cjs +359 -0
- package/gsd-core/bin/lib/state-document.cjs +186 -0
- package/gsd-core/bin/lib/state-md-schema.cjs +221 -0
- package/gsd-core/bin/lib/state-transition.cjs +517 -101
- package/gsd-core/bin/lib/state.cjs +946 -163
- package/gsd-core/bin/lib/surface.cjs +10 -2
- package/gsd-core/bin/lib/task-command-router.cjs +111 -1
- package/gsd-core/bin/lib/task-content-resolution.cjs +368 -0
- package/gsd-core/bin/lib/teams-status.cjs +4 -1
- package/gsd-core/bin/lib/uat-predicate.cjs +58 -20
- package/gsd-core/bin/lib/uat.cjs +1376 -125
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +9 -1
- package/gsd-core/bin/lib/ui-safety-gate.cjs +37 -7
- package/gsd-core/bin/lib/unusable-input.cjs +13 -0
- package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
- package/gsd-core/bin/lib/vendor/README.md +43 -5
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +3014 -0
- package/gsd-core/bin/lib/verification.cjs +14 -1
- package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
- package/gsd-core/bin/lib/verify.cjs +95 -40
- package/gsd-core/bin/lib/workstream-name-policy.cjs +25 -4
- package/gsd-core/bin/lib/worktree-base-ref.cjs +66 -12
- package/gsd-core/bin/lib/worktree-safety.cjs +177 -21
- package/gsd-core/bin/shared/config-defaults.manifest.json +7 -1
- package/gsd-core/bin/shared/config-schema.manifest.json +5 -0
- package/gsd-core/bin/shared/exit-codes.json +8 -0
- package/gsd-core/bin/shared/exit-codes.sh +20 -0
- package/gsd-core/bin/shared/model-catalog.json +8 -1
- package/gsd-core/references/agent-contracts.md +3 -2
- package/gsd-core/references/api-coverage.md +24 -2
- package/gsd-core/references/autonomous-smart-discuss.md +3 -3
- package/gsd-core/references/checkpoints.md +37 -19
- package/gsd-core/references/decimal-phase-calculation.md +5 -5
- package/gsd-core/references/edge-probe.md +8 -0
- package/gsd-core/references/execute-mvp-tdd.md +1 -3
- package/gsd-core/references/execute-phase-between-wave-reset.md +9 -12
- package/gsd-core/references/execute-phase-wave-guard.md +11 -9
- package/gsd-core/references/failing-direction.md +78 -0
- package/gsd-core/references/gate-prompts.md +1 -1
- package/gsd-core/references/git-integration.md +5 -5
- package/gsd-core/references/git-planning-commit.md +3 -3
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +22 -0
- package/gsd-core/references/model-profiles.md +1 -1
- package/gsd-core/references/nyquist-compliance.md +74 -0
- package/gsd-core/references/offer-next.md +3 -5
- package/gsd-core/references/phase-argument-parsing.md +3 -3
- package/gsd-core/references/planner-failing-direction.md +53 -0
- package/gsd-core/references/planner-human-verify-mode.md +15 -1
- package/gsd-core/references/planner-revision.md +1 -1
- package/gsd-core/references/planner-verify-command-grounding.md +17 -0
- package/gsd-core/references/planning-config.md +37 -8
- package/gsd-core/references/reviewer-instances.md +31 -0
- package/gsd-core/references/runtime-aware-dispatch.md +1 -1
- package/gsd-core/references/tdd.md +1 -3
- package/gsd-core/references/ui-brand.md +65 -21
- package/gsd-core/references/ui-consideration-probe.md +1 -1
- package/gsd-core/references/universal-anti-patterns.md +2 -2
- package/gsd-core/references/verify-command-path-resolvability.md +42 -0
- package/gsd-core/references/verify-mvp-mode.md +1 -1
- package/gsd-core/references/workstream-flag.md +11 -11
- package/gsd-core/templates/README.md +1 -1
- package/gsd-core/templates/SECURITY.md +3 -3
- package/gsd-core/templates/UI-SPEC.md +25 -3
- package/gsd-core/templates/VALIDATION.md +3 -3
- package/gsd-core/templates/phase-prompt.md +3 -0
- package/gsd-core/templates/state.md +7 -0
- 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 +3 -3
- package/gsd-core/workflows/add-tests.md +3 -8
- package/gsd-core/workflows/add-todo.md +1 -1
- package/gsd-core/workflows/ai-integration-phase.md +4 -9
- package/gsd-core/workflows/audit-fix.md +12 -3
- package/gsd-core/workflows/audit-milestone.md +9 -9
- package/gsd-core/workflows/audit-uat.md +17 -2
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
- package/gsd-core/workflows/autonomous.md +10 -26
- package/gsd-core/workflows/check-todos.md +1 -1
- package/gsd-core/workflows/cleanup.md +2 -2
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +1 -1
- package/gsd-core/workflows/code-review-fix.md +1 -1
- package/gsd-core/workflows/code-review.md +121 -40
- package/gsd-core/workflows/complete-milestone.md +15 -10
- package/gsd-core/workflows/debug.md +5 -3
- package/gsd-core/workflows/diagnose-issues.md +12 -6
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +3 -7
- package/gsd-core/workflows/discuss-phase/modes/text.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
- package/gsd-core/workflows/discuss-phase-assumptions.md +2 -2
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +3 -6
- package/gsd-core/workflows/docs-update.md +5 -4
- package/gsd-core/workflows/edit-phase.md +1 -1
- package/gsd-core/workflows/eval-review.md +4 -9
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +113 -11
- 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 +22 -4
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +21 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -2
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
- package/gsd-core/workflows/execute-phase.md +38 -54
- package/gsd-core/workflows/execute-plan.md +17 -12
- package/gsd-core/workflows/explore.md +1 -1
- package/gsd-core/workflows/extract-learnings.md +1 -1
- package/gsd-core/workflows/fast.md +2 -2
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +5 -5
- package/gsd-core/workflows/health.md +3 -6
- package/gsd-core/workflows/import.md +14 -11
- package/gsd-core/workflows/inbox.md +4 -5
- package/gsd-core/workflows/ingest-docs.md +44 -11
- package/gsd-core/workflows/insert-phase.md +5 -5
- package/gsd-core/workflows/list-seeds.md +5 -3
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +12 -23
- package/gsd-core/workflows/map-codebase.md +1 -1
- package/gsd-core/workflows/milestone-summary.md +1 -1
- package/gsd-core/workflows/mvp-phase.md +2 -2
- package/gsd-core/workflows/new-milestone.md +9 -21
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +12 -26
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +2 -2
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/adr-ingest-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -4
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +3 -3
- package/gsd-core/workflows/plan-phase.md +121 -42
- package/gsd-core/workflows/plan-review-convergence.md +46 -9
- package/gsd-core/workflows/plant-seed.md +2 -2
- package/gsd-core/workflows/pr-branch.md +187 -51
- package/gsd-core/workflows/profile-user.md +16 -14
- package/gsd-core/workflows/progress.md +27 -12
- package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +1 -3
- package/gsd-core/workflows/quick/steps/quick-verification.md +2 -4
- package/gsd-core/workflows/quick/steps/research-phase.md +2 -4
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
- package/gsd-core/workflows/quick.md +20 -29
- package/gsd-core/workflows/remove-phase.md +4 -4
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +8 -12
- package/gsd-core/workflows/review.md +193 -15
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +2 -2
- package/gsd-core/workflows/settings-advanced.md +7 -9
- package/gsd-core/workflows/settings-integrations.md +64 -31
- package/gsd-core/workflows/settings.md +3 -5
- package/gsd-core/workflows/ship.md +12 -6
- package/gsd-core/workflows/sketch-wrap-up.md +11 -17
- package/gsd-core/workflows/sketch.md +12 -18
- package/gsd-core/workflows/smart-entry.md +3 -5
- package/gsd-core/workflows/spec-phase.md +23 -1
- package/gsd-core/workflows/spike-wrap-up.md +7 -11
- package/gsd-core/workflows/spike.md +20 -31
- package/gsd-core/workflows/stats.md +2 -2
- package/gsd-core/workflows/sync-skills.md +1 -1
- package/gsd-core/workflows/thread.md +11 -7
- package/gsd-core/workflows/transition.md +5 -5
- package/gsd-core/workflows/ui-phase.md +10 -16
- package/gsd-core/workflows/ui-review.md +6 -10
- package/gsd-core/workflows/ultraplan-phase.md +5 -13
- package/gsd-core/workflows/undo.md +8 -16
- package/gsd-core/workflows/update.md +6 -10
- package/gsd-core/workflows/validate-phase.md +2 -2
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +25 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
- package/gsd-core/workflows/verify-work.md +57 -18
- package/hooks/dist/gsd-agent-isolation-guard.js +77 -38
- package/hooks/dist/gsd-config-reload.js +18 -12
- package/hooks/dist/gsd-context-monitor.js +19 -10
- package/hooks/dist/gsd-cursor-post-tool.js +3 -1
- package/hooks/dist/gsd-cursor-pre-tool.js +3 -1
- package/hooks/dist/gsd-cursor-session-start.js +2 -1
- package/hooks/dist/gsd-cursor-stop.js +2 -1
- package/hooks/dist/gsd-cursor-subagent-start.js +28 -23
- package/hooks/dist/gsd-cursor-subagent-stop.js +3 -1
- package/hooks/dist/gsd-ensure-canonical-path.js +2 -1
- package/hooks/dist/gsd-graphify-update.sh +22 -18
- package/hooks/dist/gsd-node-runner.sh +76 -0
- package/hooks/dist/gsd-phase-boundary.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +16 -7
- package/hooks/dist/gsd-read-guard.js +16 -7
- package/hooks/dist/gsd-read-injection-scanner.js +17 -8
- package/hooks/dist/gsd-session-state.sh +1 -0
- package/hooks/dist/gsd-statusline.js +215 -26
- package/hooks/dist/gsd-validate-commit.sh +80 -6
- package/hooks/dist/gsd-windsurf-pre-command.js +16 -11
- package/hooks/dist/gsd-windsurf-pre-write.js +22 -13
- package/hooks/dist/gsd-workflow-guard.js +34 -16
- package/hooks/dist/gsd-worktree-path-guard.js +36 -21
- package/hooks/dist/gsd-write-guard.js +35 -25
- package/hooks/dist/lib/cli-exit.js +560 -0
- package/hooks/dist/lib/exit-code-registry.js +98 -0
- package/hooks/dist/lib/git-probe.js +84 -0
- package/hooks/dist/lib/hook-exit.js +81 -0
- package/hooks/dist/managed-hooks-registry.cjs +3 -0
- package/hooks/gsd-agent-isolation-guard.js +77 -38
- package/hooks/gsd-config-reload.js +18 -12
- package/hooks/gsd-context-monitor.js +19 -10
- package/hooks/gsd-cursor-post-tool.js +3 -1
- package/hooks/gsd-cursor-pre-tool.js +3 -1
- package/hooks/gsd-cursor-session-start.js +2 -1
- package/hooks/gsd-cursor-stop.js +2 -1
- package/hooks/gsd-cursor-subagent-start.js +28 -23
- package/hooks/gsd-cursor-subagent-stop.js +3 -1
- package/hooks/gsd-ensure-canonical-path.js +2 -1
- package/hooks/gsd-graphify-update.sh +22 -18
- package/hooks/gsd-node-runner.sh +76 -0
- package/hooks/gsd-phase-boundary.sh +1 -0
- package/hooks/gsd-prompt-guard.js +16 -7
- package/hooks/gsd-read-guard.js +16 -7
- package/hooks/gsd-read-injection-scanner.js +17 -8
- package/hooks/gsd-session-state.sh +1 -0
- package/hooks/gsd-statusline.js +215 -26
- package/hooks/gsd-validate-commit.sh +80 -6
- package/hooks/gsd-windsurf-pre-command.js +16 -11
- package/hooks/gsd-windsurf-pre-write.js +22 -13
- package/hooks/gsd-workflow-guard.js +34 -16
- package/hooks/gsd-worktree-path-guard.js +36 -21
- package/hooks/gsd-write-guard.js +35 -25
- package/hooks/lib/cli-exit.js +560 -0
- package/hooks/lib/exit-code-registry.js +98 -0
- package/hooks/lib/git-probe.js +84 -0
- package/hooks/lib/hook-exit.js +81 -0
- package/hooks/managed-hooks-registry.cjs +3 -0
- package/package.json +12 -7
- package/scripts/base64-scan.sh +74 -12
- package/scripts/build-hooks.js +5 -0
- package/scripts/check-glossary-refs.cjs +77 -15
- package/scripts/check-mutation-score-ratchet.cjs +156 -0
- package/scripts/ci-check-job-near-cap.cjs +49 -0
- package/scripts/ci-pr-mergeability.cjs +262 -0
- package/scripts/ci-test-scope.cjs +45 -12
- package/scripts/ci-timeout-report.cjs +230 -0
- package/scripts/docs-guard-registry.cjs +396 -0
- package/scripts/gen-capability-registry.cjs +8 -6
- package/scripts/gen-exit-code-docs.cjs +318 -0
- package/scripts/gen-exit-code-registry.cjs +891 -0
- package/scripts/gen-features.cjs +836 -0
- package/scripts/gen-hooks-cli-exit.cjs +239 -0
- package/scripts/gen-install-tree-fixtures.cjs +2 -2
- package/scripts/gen-loop-host-contract.cjs +134 -1
- package/scripts/gen-scripts-cli-exit.cjs +185 -0
- package/scripts/gen-state-md-docs.cjs +727 -0
- package/scripts/{test-failure-reasons.cjs → gsd-test-gate-reasons.cjs} +6 -0
- package/scripts/lib/ci-job-timing.cjs +72 -0
- package/scripts/lib/cli-exit.cjs +546 -44
- package/scripts/lib/drift-scan.cjs +32 -2
- package/scripts/lib/exit-code-registry.cjs +98 -0
- package/scripts/lib/ndjson-reporter.cjs +119 -0
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- package/scripts/lint-docs-guard-registration.cjs +495 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +193 -0
- package/scripts/lint-eslint-glob-coverage.allowlist.json +4 -0
- package/scripts/{lint-fix-has-regression-test.cjs → lint-fix-has-regression-tests.cjs} +12 -6
- package/scripts/lint-health-diagnostic-rule-table.cjs +65 -8
- package/scripts/lint-mutation-test-derivation-drift.cjs +86 -0
- package/scripts/lint-phase-enumeration-drift.cjs +21 -8
- package/scripts/lint-planning-prompt-drift.cjs +38 -1
- package/scripts/lint-removed-but-needed.cjs +184 -16
- package/scripts/lint-seam-enforcement.cjs +182 -0
- package/scripts/lint-slug-derivation-drift.cjs +921 -0
- package/scripts/lint-source-test-name-collision.cjs +241 -0
- package/scripts/lint-state-write-path-drift.cjs +337 -432
- package/scripts/lint-test-file-count.allowlist.json +122 -4
- package/scripts/lint-test-file-count.cjs +25 -3
- package/scripts/lint-unreachable-guard-drift.cjs +51 -64
- package/scripts/lint-vendored-deps.cjs +208 -35
- package/scripts/mutation-matrix.cjs +599 -50
- package/scripts/prompt-injection-scan.sh +75 -14
- package/scripts/secret-scan.sh +75 -13
- package/scripts/select-docs-guards.cjs +56 -0
- package/scripts/sync-runtime-launcher.cjs +22 -3
- package/skills/gsd-discuss-phase/SKILL.md +1 -1
- package/skills/gsd-import/SKILL.md +1 -1
- package/skills/gsd-quick/SKILL.md +8 -4
- package/vscode/package.json +1 -1
- package/bin/lib/ui-safety-gate.cjs +0 -109
- package/scripts/lint-emitted-drift-ack.cjs +0 -344
- package/scripts/state-write-path-drift-baseline.json +0 -19
|
@@ -6,12 +6,29 @@
|
|
|
6
6
|
# scripts/prompt-injection-scan.sh --file path/to/file # Scan a single file
|
|
7
7
|
# scripts/prompt-injection-scan.sh --dir agents/ # Scan all files in a directory
|
|
8
8
|
#
|
|
9
|
-
# Exit codes:
|
|
10
|
-
# 0
|
|
11
|
-
# 1
|
|
12
|
-
#
|
|
9
|
+
# Exit codes (ADR-3889, #3908 — registered in gsd-core/bin/shared/exit-codes.json):
|
|
10
|
+
# 0 = clean
|
|
11
|
+
# 1 = findings detected
|
|
12
|
+
# $EXIT_USAGE (64) = usage error (bad argv, missing --file/--dir target)
|
|
13
|
+
# $EXIT_NO_INPUT (66) = ran; scope established; zero files in scope (genuinely empty)
|
|
14
|
+
# $EXIT_UNAVAILABLE (69) = could not establish scope (bad ref, not a repo, unreadable dir)
|
|
13
15
|
set -euo pipefail
|
|
14
16
|
|
|
17
|
+
# ─── Exit-code registry (ADR-3889, #3908) ────────────────────────────────────
|
|
18
|
+
# Resolved relative to THIS script's location, not the caller's cwd. Loud,
|
|
19
|
+
# non-zero failure if the fragment is missing — never fall back to a guessed
|
|
20
|
+
# literal integer, and never let a missing registry silently degrade to
|
|
21
|
+
# exit 0.
|
|
22
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
23
|
+
EXIT_CODES_SH="$SCRIPT_DIR/../gsd-core/bin/shared/exit-codes.sh"
|
|
24
|
+
if [[ ! -f "$EXIT_CODES_SH" ]]; then
|
|
25
|
+
echo "prompt-injection-scan: FATAL: exit-code registry not found at $EXIT_CODES_SH" >&2
|
|
26
|
+
echo " Regenerate with: node scripts/gen-exit-code-registry.cjs --write" >&2
|
|
27
|
+
exit 1
|
|
28
|
+
fi
|
|
29
|
+
# shellcheck disable=SC1090
|
|
30
|
+
. "$EXIT_CODES_SH"
|
|
31
|
+
|
|
15
32
|
# ─── Patterns ────────────────────────────────────────────────────────────────
|
|
16
33
|
# Each pattern is a POSIX extended regex. Keep alphabetized by category.
|
|
17
34
|
#
|
|
@@ -175,33 +192,73 @@ collect_files() {
|
|
|
175
192
|
case "$mode" in
|
|
176
193
|
--diff)
|
|
177
194
|
local base="${1:-origin/main}"
|
|
178
|
-
#
|
|
179
|
-
|
|
180
|
-
|
|
195
|
+
# Run git separately from the filter pipe so its OWN exit status (not
|
|
196
|
+
# grep's) decides whether the diff could be established. stdout and
|
|
197
|
+
# stderr are captured SEPARATELY (never merged with `2>&1`) so that a
|
|
198
|
+
# warning git writes to stderr on an otherwise successful diff can
|
|
199
|
+
# never be mistaken for a filename in the file list. On failure the
|
|
200
|
+
# captured stderr is emitted as the diagnostic; on success it is
|
|
201
|
+
# forwarded as a warning, never folded into the file list.
|
|
202
|
+
# `|| true` on the filter below is CORRECT (not gratuitous): `grep -E`
|
|
203
|
+
# exits 1 when nothing matches the scannable extensions (e.g. a diff
|
|
204
|
+
# touching only non-scannable file types), which is a legitimate empty
|
|
205
|
+
# result, not a failure to run.
|
|
206
|
+
local raw status err_file
|
|
207
|
+
err_file=$(mktemp)
|
|
208
|
+
raw=$(git diff --name-only --diff-filter=ACMR "$base"...HEAD 2>"$err_file")
|
|
209
|
+
status=$?
|
|
210
|
+
if (( status != 0 )); then
|
|
211
|
+
cat "$err_file" >&2
|
|
212
|
+
rm -f "$err_file"
|
|
213
|
+
exit "$EXIT_UNAVAILABLE"
|
|
214
|
+
fi
|
|
215
|
+
if [[ -s "$err_file" ]]; then
|
|
216
|
+
echo "Warning: git diff emitted stderr output:" >&2
|
|
217
|
+
cat "$err_file" >&2
|
|
218
|
+
fi
|
|
219
|
+
rm -f "$err_file"
|
|
220
|
+
printf '%s\n' "$raw" | grep -E '\.(md|cjs|js|json|yml|yaml|sh)$' || true
|
|
181
221
|
;;
|
|
182
222
|
--file)
|
|
183
223
|
if [[ -f "$1" ]]; then
|
|
184
224
|
echo "$1"
|
|
185
225
|
else
|
|
186
226
|
echo "Error: file not found: $1" >&2
|
|
187
|
-
exit
|
|
227
|
+
exit "$EXIT_USAGE"
|
|
188
228
|
fi
|
|
189
229
|
;;
|
|
190
230
|
--dir)
|
|
191
231
|
local dir="$1"
|
|
192
232
|
if [[ ! -d "$dir" ]]; then
|
|
193
233
|
echo "Error: directory not found: $dir" >&2
|
|
194
|
-
exit
|
|
234
|
+
exit "$EXIT_USAGE"
|
|
235
|
+
fi
|
|
236
|
+
# Same treatment as --diff: a `find` that fails (e.g. permission
|
|
237
|
+
# denied) must not be reported as an empty directory, and stdout/stderr
|
|
238
|
+
# are captured separately so a stderr warning never enters the file list.
|
|
239
|
+
local raw status err_file
|
|
240
|
+
err_file=$(mktemp)
|
|
241
|
+
raw=$(find "$dir" -type f \( -name '*.md' -o -name '*.cjs' -o -name '*.js' -o -name '*.json' -o -name '*.yml' -o -name '*.yaml' -o -name '*.sh' \) \
|
|
242
|
+
! -path '*/node_modules/*' ! -path '*/.git/*' ! -path '*/dist/*' 2>"$err_file")
|
|
243
|
+
status=$?
|
|
244
|
+
if (( status != 0 )); then
|
|
245
|
+
cat "$err_file" >&2
|
|
246
|
+
rm -f "$err_file"
|
|
247
|
+
exit "$EXIT_UNAVAILABLE"
|
|
248
|
+
fi
|
|
249
|
+
if [[ -s "$err_file" ]]; then
|
|
250
|
+
echo "Warning: find emitted stderr output:" >&2
|
|
251
|
+
cat "$err_file" >&2
|
|
195
252
|
fi
|
|
196
|
-
|
|
197
|
-
|
|
253
|
+
rm -f "$err_file"
|
|
254
|
+
printf '%s\n' "$raw"
|
|
198
255
|
;;
|
|
199
256
|
--stdin)
|
|
200
257
|
cat
|
|
201
258
|
;;
|
|
202
259
|
*)
|
|
203
260
|
echo "Usage: $0 --diff [base] | --file <path> | --dir <path> | --stdin" >&2
|
|
204
|
-
exit
|
|
261
|
+
exit "$EXIT_USAGE"
|
|
205
262
|
;;
|
|
206
263
|
esac
|
|
207
264
|
}
|
|
@@ -240,7 +297,7 @@ scan_file() {
|
|
|
240
297
|
main() {
|
|
241
298
|
if [[ $# -eq 0 ]]; then
|
|
242
299
|
echo "Usage: $0 --diff [base] | --file <path> | --dir <path>" >&2
|
|
243
|
-
exit
|
|
300
|
+
exit "$EXIT_USAGE"
|
|
244
301
|
fi
|
|
245
302
|
|
|
246
303
|
local mode="$1"
|
|
@@ -250,8 +307,12 @@ main() {
|
|
|
250
307
|
files=$(collect_files "$mode" "$@")
|
|
251
308
|
|
|
252
309
|
if [[ -z "$files" ]]; then
|
|
310
|
+
# collect_files already exited (UNAVAILABLE/USAGE) for anything that
|
|
311
|
+
# could not establish scope. Reaching here with an empty result means
|
|
312
|
+
# scope WAS established and is genuinely empty — that is NO_INPUT, not a
|
|
313
|
+
# silent clean pass.
|
|
253
314
|
echo "prompt-injection-scan: no files to scan"
|
|
254
|
-
exit
|
|
315
|
+
exit "$EXIT_NO_INPUT"
|
|
255
316
|
fi
|
|
256
317
|
|
|
257
318
|
local total=0
|
package/scripts/secret-scan.sh
CHANGED
|
@@ -17,10 +17,12 @@
|
|
|
17
17
|
# This flag does not change secret-detection logic — only which
|
|
18
18
|
# exclusions are applied.
|
|
19
19
|
#
|
|
20
|
-
# Exit codes:
|
|
21
|
-
# 0
|
|
22
|
-
# 1
|
|
23
|
-
#
|
|
20
|
+
# Exit codes (ADR-3889, #3908 — registered in gsd-core/bin/shared/exit-codes.json):
|
|
21
|
+
# 0 = clean
|
|
22
|
+
# 1 = findings detected
|
|
23
|
+
# $EXIT_USAGE (64) = usage error (bad argv, missing --file/--dir target)
|
|
24
|
+
# $EXIT_NO_INPUT (66) = ran; scope established; zero files in scope (genuinely empty)
|
|
25
|
+
# $EXIT_UNAVAILABLE (69) = could not establish scope (bad ref, not a repo, unreadable dir)
|
|
24
26
|
#
|
|
25
27
|
# Annotation format for .secretscanignore (required for --strict compliance):
|
|
26
28
|
# # allow: <pattern> reason="..." owner="..." expires="YYYY-MM-DD" [rule-id="..."]
|
|
@@ -39,6 +41,21 @@
|
|
|
39
41
|
# cannot permanently hide secrets. See SECURITY.md for the audit runbook.
|
|
40
42
|
set -euo pipefail
|
|
41
43
|
|
|
44
|
+
# ─── Exit-code registry (ADR-3889, #3908) ────────────────────────────────────
|
|
45
|
+
# Resolved relative to THIS script's location, not the caller's cwd, so this
|
|
46
|
+
# works regardless of where the scanner is invoked from. Loud, non-zero
|
|
47
|
+
# failure if the fragment is missing — never fall back to a guessed literal
|
|
48
|
+
# integer, and never let a missing registry silently degrade to exit 0.
|
|
49
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
50
|
+
EXIT_CODES_SH="$SCRIPT_DIR/../gsd-core/bin/shared/exit-codes.sh"
|
|
51
|
+
if [[ ! -f "$EXIT_CODES_SH" ]]; then
|
|
52
|
+
echo "secret-scan: FATAL: exit-code registry not found at $EXIT_CODES_SH" >&2
|
|
53
|
+
echo " Regenerate with: node scripts/gen-exit-code-registry.cjs --write" >&2
|
|
54
|
+
exit 1
|
|
55
|
+
fi
|
|
56
|
+
# shellcheck disable=SC1090
|
|
57
|
+
. "$EXIT_CODES_SH"
|
|
58
|
+
|
|
42
59
|
# ─── Global mode flag ─────────────────────────────────────────────────────────
|
|
43
60
|
STRICT_MODE=false
|
|
44
61
|
|
|
@@ -235,7 +252,31 @@ collect_files() {
|
|
|
235
252
|
case "$mode" in
|
|
236
253
|
--diff)
|
|
237
254
|
local base="${1:-origin/main}"
|
|
238
|
-
git
|
|
255
|
+
# Run git separately from the filter pipe so its OWN exit status (not
|
|
256
|
+
# grep's) decides whether the diff could be established. stdout and
|
|
257
|
+
# stderr are captured SEPARATELY (never merged with `2>&1`) so that a
|
|
258
|
+
# warning git writes to stderr on an otherwise successful diff can
|
|
259
|
+
# never be mistaken for a filename in the file list. On failure the
|
|
260
|
+
# captured stderr is emitted as the diagnostic; on success it is
|
|
261
|
+
# forwarded as a warning, never folded into the file list.
|
|
262
|
+
# `|| true` on the filter below is CORRECT (not gratuitous): `grep -v`
|
|
263
|
+
# exits 1 when every line is filtered out (e.g. an all-images diff),
|
|
264
|
+
# which is a legitimate empty result, not a failure to run.
|
|
265
|
+
local raw status err_file
|
|
266
|
+
err_file=$(mktemp)
|
|
267
|
+
raw=$(git diff --name-only --diff-filter=ACMR "$base"...HEAD 2>"$err_file")
|
|
268
|
+
status=$?
|
|
269
|
+
if (( status != 0 )); then
|
|
270
|
+
cat "$err_file" >&2
|
|
271
|
+
rm -f "$err_file"
|
|
272
|
+
exit "$EXIT_UNAVAILABLE"
|
|
273
|
+
fi
|
|
274
|
+
if [[ -s "$err_file" ]]; then
|
|
275
|
+
echo "Warning: git diff emitted stderr output:" >&2
|
|
276
|
+
cat "$err_file" >&2
|
|
277
|
+
fi
|
|
278
|
+
rm -f "$err_file"
|
|
279
|
+
printf '%s\n' "$raw" \
|
|
239
280
|
| grep -vE '\.(png|jpg|jpeg|gif|ico|woff|woff2|ttf|eot|otf|zip|tar|gz|pdf)$' || true
|
|
240
281
|
;;
|
|
241
282
|
--file)
|
|
@@ -243,24 +284,41 @@ collect_files() {
|
|
|
243
284
|
echo "$1"
|
|
244
285
|
else
|
|
245
286
|
echo "Error: file not found: $1" >&2
|
|
246
|
-
exit
|
|
287
|
+
exit "$EXIT_USAGE"
|
|
247
288
|
fi
|
|
248
289
|
;;
|
|
249
290
|
--dir)
|
|
250
291
|
local dir="$1"
|
|
251
292
|
if [[ ! -d "$dir" ]]; then
|
|
252
293
|
echo "Error: directory not found: $dir" >&2
|
|
253
|
-
exit
|
|
294
|
+
exit "$EXIT_USAGE"
|
|
295
|
+
fi
|
|
296
|
+
# Same treatment as --diff: a `find` that fails (e.g. permission
|
|
297
|
+
# denied) must not be reported as an empty directory, and stdout/stderr
|
|
298
|
+
# are captured separately so a stderr warning never enters the file list.
|
|
299
|
+
local raw status err_file
|
|
300
|
+
err_file=$(mktemp)
|
|
301
|
+
raw=$(find "$dir" -type f ! -path '*/node_modules/*' ! -path '*/.git/*' ! -path '*/dist/*' \
|
|
302
|
+
! -name '*.png' ! -name '*.jpg' ! -name '*.gif' ! -name '*.woff*' 2>"$err_file")
|
|
303
|
+
status=$?
|
|
304
|
+
if (( status != 0 )); then
|
|
305
|
+
cat "$err_file" >&2
|
|
306
|
+
rm -f "$err_file"
|
|
307
|
+
exit "$EXIT_UNAVAILABLE"
|
|
308
|
+
fi
|
|
309
|
+
if [[ -s "$err_file" ]]; then
|
|
310
|
+
echo "Warning: find emitted stderr output:" >&2
|
|
311
|
+
cat "$err_file" >&2
|
|
254
312
|
fi
|
|
255
|
-
|
|
256
|
-
|
|
313
|
+
rm -f "$err_file"
|
|
314
|
+
printf '%s\n' "$raw"
|
|
257
315
|
;;
|
|
258
316
|
--stdin)
|
|
259
317
|
cat
|
|
260
318
|
;;
|
|
261
319
|
*)
|
|
262
320
|
echo "Usage: $0 --diff [base] | --file <path> | --dir <path> | --stdin" >&2
|
|
263
|
-
exit
|
|
321
|
+
exit "$EXIT_USAGE"
|
|
264
322
|
;;
|
|
265
323
|
esac
|
|
266
324
|
}
|
|
@@ -300,7 +358,7 @@ scan_file() {
|
|
|
300
358
|
main() {
|
|
301
359
|
if [[ $# -eq 0 ]]; then
|
|
302
360
|
echo "Usage: $0 --diff [base] | --file <path> | --dir <path> [--strict]" >&2
|
|
303
|
-
exit
|
|
361
|
+
exit "$EXIT_USAGE"
|
|
304
362
|
fi
|
|
305
363
|
|
|
306
364
|
# Parse --strict flag first (may appear anywhere in argv)
|
|
@@ -316,7 +374,7 @@ main() {
|
|
|
316
374
|
|
|
317
375
|
if [[ $# -eq 0 ]]; then
|
|
318
376
|
echo "Usage: $0 --diff [base] | --file <path> | --dir <path> [--strict]" >&2
|
|
319
|
-
exit
|
|
377
|
+
exit "$EXIT_USAGE"
|
|
320
378
|
fi
|
|
321
379
|
|
|
322
380
|
load_ignorelist
|
|
@@ -328,8 +386,12 @@ main() {
|
|
|
328
386
|
files=$(collect_files "$mode" "$@")
|
|
329
387
|
|
|
330
388
|
if [[ -z "$files" ]]; then
|
|
389
|
+
# collect_files already exited (UNAVAILABLE/USAGE) for anything that
|
|
390
|
+
# could not establish scope. Reaching here with an empty result means
|
|
391
|
+
# scope WAS established and is genuinely empty (e.g. an all-images
|
|
392
|
+
# diff) — that is NO_INPUT, not a silent clean pass.
|
|
331
393
|
echo "secret-scan: no files to scan"
|
|
332
|
-
exit
|
|
394
|
+
exit "$EXIT_NO_INPUT"
|
|
333
395
|
fi
|
|
334
396
|
|
|
335
397
|
local total=0
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* select-docs-guards.cjs — pure selector mapping a PR's changed docs/ paths
|
|
6
|
+
* to the subset of scripts/docs-guard-registry.cjs's DOCS_GUARD_TESTS that
|
|
7
|
+
* actually reads any of them (#3753 follow-up).
|
|
8
|
+
*
|
|
9
|
+
* Deliberately dependency-free: no fs, no git, no process. Callers (the
|
|
10
|
+
* docs-required.yml workflow, tests) are responsible for producing the
|
|
11
|
+
* changed-paths list and reading the registry; this module only implements
|
|
12
|
+
* the matching semantics so they are independently unit-testable.
|
|
13
|
+
*
|
|
14
|
+
* Pattern semantics (mirrors scripts/docs-guard-registry.cjs's header doc):
|
|
15
|
+
* - a plain path matches an exact changed path;
|
|
16
|
+
* - a trailing-slash path is a DIRECTORY PREFIX match — 'docs/adr/'
|
|
17
|
+
* matches 'docs/adr/README.md' but must NOT match 'docs/adrenaline.md'
|
|
18
|
+
* (a naive `startsWith('docs/adr')` without the trailing slash would
|
|
19
|
+
* wrongly match the latter; matching against the full prefix INCLUDING
|
|
20
|
+
* the trailing slash is what keeps this boundary correct);
|
|
21
|
+
* - the sentinel '*' matches any non-empty changedDocsPaths.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {string} changedPath - a single changed docs/ path (e.g. 'docs/AGENTS.md').
|
|
26
|
+
* @param {string} pattern - one entry from a registry value array.
|
|
27
|
+
* @returns {boolean}
|
|
28
|
+
*/
|
|
29
|
+
function patternMatches(changedPath, pattern) {
|
|
30
|
+
if (pattern === '*') return true;
|
|
31
|
+
if (pattern.endsWith('/')) return changedPath.startsWith(pattern);
|
|
32
|
+
return changedPath === pattern;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {string[]} changedDocsPaths - repo-relative paths under docs/ that
|
|
37
|
+
* changed in this PR. An empty array always yields an empty selection.
|
|
38
|
+
* @param {Record<string, string[]>} registry - DOCS_GUARD_TESTS shape: test
|
|
39
|
+
* file -> array of patterns it reads.
|
|
40
|
+
* @returns {string[]} sorted, deduped list of selected test file paths.
|
|
41
|
+
*/
|
|
42
|
+
function selectDocsGuards(changedDocsPaths, registry) {
|
|
43
|
+
if (!Array.isArray(changedDocsPaths) || changedDocsPaths.length === 0) return [];
|
|
44
|
+
|
|
45
|
+
const selected = new Set();
|
|
46
|
+
for (const [testFile, patterns] of Object.entries(registry)) {
|
|
47
|
+
const hit = patterns.some((pattern) =>
|
|
48
|
+
changedDocsPaths.some((changedPath) => patternMatches(changedPath, pattern)),
|
|
49
|
+
);
|
|
50
|
+
if (hit) selected.add(testFile);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return [...selected].sort();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = { selectDocsGuards, patternMatches };
|
|
@@ -330,6 +330,16 @@ function transformFile(content, preamble) {
|
|
|
330
330
|
let changed = false;
|
|
331
331
|
let firstGsdRunBlockIdx = -1; // index into shellBlockRanges of the first gsd_run block (after strip)
|
|
332
332
|
|
|
333
|
+
// A file may place the preamble in a bootstrap-only block that defines
|
|
334
|
+
// gsd_run without calling it (gsd-core/workflows/explore.md Step 1, which
|
|
335
|
+
// documents exactly why). Stripping empties that block of gsd_run calls, so
|
|
336
|
+
// a pure "first block that CALLS gsd_run" target silently relocates the
|
|
337
|
+
// preamble forward and breaks define-before-use. Honour where it already is.
|
|
338
|
+
const existingPreambleBlockIdx = shellBlockRanges.findIndex((range) =>
|
|
339
|
+
allLines
|
|
340
|
+
.slice(range.contentStart, range.contentEnd)
|
|
341
|
+
.some((l) => /^\s*_GSD_SHIM_NAME=/.test(l)));
|
|
342
|
+
|
|
333
343
|
// First: strip + replace in all blocks, find first gsd_run block
|
|
334
344
|
const strippedBlocks = shellBlockRanges.map((range) => {
|
|
335
345
|
const blockLines = outputLines.slice(range.contentStart, range.contentEnd);
|
|
@@ -345,12 +355,17 @@ function transformFile(content, preamble) {
|
|
|
345
355
|
}
|
|
346
356
|
}
|
|
347
357
|
|
|
348
|
-
//
|
|
358
|
+
// If the preamble already existed in a specific block before stripping,
|
|
359
|
+
// keep it there (even if that block no longer calls gsd_run after
|
|
360
|
+
// stripping). Otherwise fall back to the first gsd_run-calling block.
|
|
361
|
+
const preambleTargetIdx = existingPreambleBlockIdx >= 0 ? existingPreambleBlockIdx : firstGsdRunBlockIdx;
|
|
362
|
+
|
|
363
|
+
// Insert preamble into the target block only — UNLESS this file
|
|
349
364
|
// delegates to the shared resolver reference (@-include). Delegating files keep
|
|
350
365
|
// the stripped blocks (any inline preamble removed) but never get one inserted.
|
|
351
366
|
const delegates = delegatesToResolverReference(content);
|
|
352
367
|
const finalBlocks = strippedBlocks.map((stripped, bi) => {
|
|
353
|
-
if (!delegates && bi ===
|
|
368
|
+
if (!delegates && bi === preambleTargetIdx) {
|
|
354
369
|
return insertPreamble(stripped, preamble);
|
|
355
370
|
}
|
|
356
371
|
return stripped;
|
|
@@ -428,4 +443,8 @@ function main() {
|
|
|
428
443
|
console.log(`\nDone. ${transformedCount} files transformed, ${unchangedCount} unchanged.`);
|
|
429
444
|
}
|
|
430
445
|
|
|
431
|
-
main
|
|
446
|
+
if (require.main === module) {
|
|
447
|
+
main();
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
module.exports = { transformFile };
|
|
@@ -48,7 +48,7 @@ Context files are resolved in-workflow using `init phase-op` and roadmap/state t
|
|
|
48
48
|
**Mode routing:**
|
|
49
49
|
```bash
|
|
50
50
|
_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi
|
|
51
|
-
DISCUSS_MODE=$(gsd_run query config-get workflow.discuss_mode 2>/dev/null || echo "discuss")
|
|
51
|
+
DISCUSS_MODE=$(gsd_run query config-get workflow.discuss_mode --raw 2>/dev/null || echo "discuss")
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
If `--assumptions` is in $ARGUMENTS:
|
|
@@ -18,7 +18,7 @@ allowed-tools:
|
|
|
18
18
|
Import external plan files into the GSD planning system with conflict detection against PROJECT.md decisions.
|
|
19
19
|
|
|
20
20
|
- **--from**: Import an external plan file, detect conflicts, write as GSD PLAN.md, validate via gsd-plan-checker.
|
|
21
|
-
- **--from-gsd2**: Reverse-migrate a GSD-2 project (`.gsd/` directory) back to GSD v1 (`.planning/`) format. Runs `
|
|
21
|
+
- **--from-gsd2**: Reverse-migrate a GSD-2 project (`.gsd/` directory) back to GSD v1 (`.planning/`) format. Runs `gsd_run from-gsd2`. Pass `--path <dir>` to migrate a project at a different path.
|
|
22
22
|
</objective>
|
|
23
23
|
|
|
24
24
|
<execution_context>
|
|
@@ -86,12 +86,14 @@ For each directory found:
|
|
|
86
86
|
Display format:
|
|
87
87
|
```
|
|
88
88
|
Quick Tasks
|
|
89
|
-
|
|
89
|
+
|
|
90
|
+
---
|
|
90
91
|
slug date status
|
|
91
92
|
backup-s3-policy 2026-04-10 in-progress
|
|
92
93
|
auth-token-refresh-fix 2026-04-09 complete ✓
|
|
93
94
|
update-node-deps 2026-04-08 abandoned? (>7 days, no summary)
|
|
94
|
-
|
|
95
|
+
|
|
96
|
+
---
|
|
95
97
|
3 tasks (1 complete, 2 incomplete/in-progress)
|
|
96
98
|
```
|
|
97
99
|
|
|
@@ -113,12 +115,14 @@ If no directory found, print `No quick task found with slug: {SLUG}` and stop.
|
|
|
113
115
|
Read PLAN.md and SUMMARY.md (if exists) for the given slug. Display:
|
|
114
116
|
```
|
|
115
117
|
Quick Task: {slug}
|
|
116
|
-
|
|
118
|
+
|
|
119
|
+
---
|
|
117
120
|
Plan file: .planning/quick/{dir}/PLAN.md
|
|
118
121
|
Status: {status from SUMMARY.md frontmatter, or "no summary yet"}
|
|
119
122
|
Description: {first non-empty line from PLAN.md after frontmatter}
|
|
120
123
|
Last action: {last meaningful line of SUMMARY.md, or "none"}
|
|
121
|
-
|
|
124
|
+
|
|
125
|
+
---
|
|
122
126
|
Resume with: /gsd-quick resume {slug}
|
|
123
127
|
```
|
|
124
128
|
|
package/vscode/package.json
CHANGED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* UI Safety Gate — shell-free implementation (#3706, #3718)
|
|
5
|
-
*
|
|
6
|
-
* Replaces the bash shell-based one-liner that silently degraded on Windows
|
|
7
|
-
* PowerShell / cmd.exe because the locale env-var prefix was not recognised.
|
|
8
|
-
* This module runs inside Node.js — no shell dependency, works identically
|
|
9
|
-
* on bash, Git-Bash, PowerShell, and cmd.exe.
|
|
10
|
-
*
|
|
11
|
-
* Word-boundary anchoring:
|
|
12
|
-
* (^|[^a-zA-Z0-9])(TOKEN)([^a-zA-Z0-9]|$)
|
|
13
|
-
* Equivalent to POSIX ERE [^[:alnum:]] — matches tokens only when they are not
|
|
14
|
-
* interior substrings of alphanumeric compound words (e.g. "microfrontend" is NOT
|
|
15
|
-
* matched; "micro-frontend" and "micro frontend" ARE matched).
|
|
16
|
-
*
|
|
17
|
-
* Public API:
|
|
18
|
-
* checkUiPresence(text: string): { hasUI: boolean, tokens: string[] }
|
|
19
|
-
*
|
|
20
|
-
* CLI usage — reads phase-section text from STDIN to avoid ARG_MAX limits:
|
|
21
|
-
* echo "$PHASE_SECTION" | node bin/lib/ui-safety-gate.cjs
|
|
22
|
-
* echo $? → 0 if UI tokens found, 1 if not, 2 on usage error
|
|
23
|
-
*
|
|
24
|
-
* Exit codes mirror grep: 0 = match found, 1 = no match, 2 = usage error.
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
const UI_TOKENS = [
|
|
28
|
-
'UI',
|
|
29
|
-
'interface',
|
|
30
|
-
'frontend',
|
|
31
|
-
'component',
|
|
32
|
-
'layout',
|
|
33
|
-
'page',
|
|
34
|
-
'screen',
|
|
35
|
-
'view',
|
|
36
|
-
'form',
|
|
37
|
-
'dashboard',
|
|
38
|
-
'widget',
|
|
39
|
-
];
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Built once at module load — no per-call compilation overhead.
|
|
43
|
-
* ASCII word boundaries — matches the original ASCII-grep intent of #3706.
|
|
44
|
-
* Note: JS [a-zA-Z0-9] is ASCII-only and NOT equivalent to POSIX [[:alnum:]],
|
|
45
|
-
* which is locale-sensitive and includes accented characters.
|
|
46
|
-
*/
|
|
47
|
-
const UI_GATE_PATTERN = new RegExp(
|
|
48
|
-
'(^|[^a-zA-Z0-9])(' + UI_TOKENS.join('|') + ')([^a-zA-Z0-9]|$)',
|
|
49
|
-
'i'
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
// Global-flagged variant for extracting ALL matches per line (matchAll).
|
|
53
|
-
const UI_GATE_PATTERN_GLOBAL = new RegExp(UI_GATE_PATTERN.source, 'gi');
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Check a roadmap phase section string for frontend UI indicators.
|
|
57
|
-
*
|
|
58
|
-
* @param {string} text - The roadmap phase section content (may be multi-line, CRLF or LF).
|
|
59
|
-
* @returns {{ hasUI: boolean, tokens: string[] }}
|
|
60
|
-
* hasUI — true if any UI token was matched as a standalone word.
|
|
61
|
-
* tokens — matched token strings (lowercased), deduplicated.
|
|
62
|
-
*/
|
|
63
|
-
function checkUiPresence(text) {
|
|
64
|
-
if (typeof text !== 'string') {
|
|
65
|
-
return { hasUI: false, tokens: [] };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Normalise CRLF so the pattern sees consistent line boundaries.
|
|
69
|
-
const normalised = text.replace(/\r\n/g, '\n');
|
|
70
|
-
|
|
71
|
-
const found = new Set();
|
|
72
|
-
for (const line of normalised.split('\n')) {
|
|
73
|
-
// Reset lastIndex before each line so the global pattern restarts from 0.
|
|
74
|
-
UI_GATE_PATTERN_GLOBAL.lastIndex = 0;
|
|
75
|
-
for (const m of line.matchAll(UI_GATE_PATTERN_GLOBAL)) {
|
|
76
|
-
found.add(m[2].toLowerCase());
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return { hasUI: found.size > 0, tokens: [...found] };
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
module.exports = { checkUiPresence, UI_TOKENS };
|
|
84
|
-
|
|
85
|
-
// ── CLI entry point ─────────────────────────────────────────────────────────
|
|
86
|
-
// Reads phase-section text from STDIN (not argv) to avoid OS ARG_MAX limits.
|
|
87
|
-
// Invoked by workflow .md bash blocks as: echo "$PHASE_SECTION" | node bin/lib/ui-safety-gate.cjs
|
|
88
|
-
// Exit 0 = UI found, 1 = no UI, 2 = startup error.
|
|
89
|
-
|
|
90
|
-
if (require.main === module) {
|
|
91
|
-
// Collect stdin chunks asynchronously.
|
|
92
|
-
const chunks = [];
|
|
93
|
-
process.stdin.setEncoding('utf-8');
|
|
94
|
-
|
|
95
|
-
process.stdin.on('data', (chunk) => chunks.push(chunk));
|
|
96
|
-
|
|
97
|
-
process.stdin.on('end', () => {
|
|
98
|
-
const input = chunks.join('');
|
|
99
|
-
const result = checkUiPresence(input);
|
|
100
|
-
// eslint-disable-next-line n/no-process-exit -- CLI entry point (require.main===module): async stdin handler, nothing else terminates the process (#3059)
|
|
101
|
-
process.exit(result.hasUI ? 0 : 1);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
process.stdin.on('error', (err) => {
|
|
105
|
-
process.stderr.write(`ERROR: ui-safety-gate.cjs stdin read failed: ${err.message}\n`);
|
|
106
|
-
// eslint-disable-next-line n/no-process-exit -- CLI entry point (require.main===module): async stdin handler, nothing else terminates the process (#3059)
|
|
107
|
-
process.exit(2);
|
|
108
|
-
});
|
|
109
|
-
}
|