@opengsd/gsd-core 1.11.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +12 -0
- package/agents/gsd-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 +78 -42
- 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 +91 -112
- package/agents/gsd-planner.md +20 -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 +82 -7
- package/agents/gsd-ui-researcher.md +70 -3
- package/agents/gsd-verifier.md +24 -2
- package/bin/install.js +847 -200
- package/commands/gsd/discuss-phase.md +1 -1
- package/commands/gsd/execute-phase.md +1 -1
- package/commands/gsd/import.md +1 -1
- package/commands/gsd/ns-workflow.md +2 -1
- package/commands/gsd/phase.md +1 -1
- package/commands/gsd/quick-batch.md +105 -0
- package/commands/gsd/quick.md +8 -4
- package/commands/gsd/surface.md +18 -8
- package/gsd-core/bin/gsd-tools.cjs +761 -100
- 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-activation.cjs +27 -0
- package/gsd-core/bin/lib/capability-lock.cjs +10 -4
- package/gsd-core/bin/lib/capability-registry.cjs +785 -144
- package/gsd-core/bin/lib/capability-state.cjs +25 -4
- package/gsd-core/bin/lib/capability-validator.cjs +321 -18
- package/gsd-core/bin/lib/capability-writer.cjs +14 -4
- package/gsd-core/bin/lib/check-command-router.cjs +229 -6
- package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
- package/gsd-core/bin/lib/cli-exit.cjs +496 -10
- package/gsd-core/bin/lib/clusters.cjs +1 -0
- 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-aliases.cjs +16 -0
- 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 +877 -54
- package/gsd-core/bin/lib/complexity-trigger.cjs +26 -6
- package/gsd-core/bin/lib/config-loader.cjs +121 -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 +118 -14
- package/gsd-core/bin/lib/decisions.cjs +213 -1
- package/gsd-core/bin/lib/edge-probe.cjs +23 -2
- 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/file-overlap-partitioner.cjs +74 -0
- package/gsd-core/bin/lib/frontmatter.cjs +975 -326
- package/gsd-core/bin/lib/gap-checker.cjs +41 -8
- package/gsd-core/bin/lib/git-base-branch.cjs +182 -39
- package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +7 -3
- package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +8 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +60 -14
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +75 -22
- 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 +96 -11
- package/gsd-core/bin/lib/init-command-router.cjs +132 -21
- package/gsd-core/bin/lib/init.cjs +252 -56
- package/gsd-core/bin/lib/install-engine.cjs +252 -15
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +78 -1
- package/gsd-core/bin/lib/install-profiles.cjs +100 -18
- package/gsd-core/bin/lib/installer-migration-report.cjs +4 -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 +195 -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/loop-resolver.cjs +14 -8
- package/gsd-core/bin/lib/markdown-table.cjs +175 -4
- package/gsd-core/bin/lib/milestone.cjs +112 -7
- 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-command-router.cjs +13 -6
- package/gsd-core/bin/lib/phase-estimation.cjs +17 -8
- package/gsd-core/bin/lib/phase-id.cjs +321 -13
- 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 +1175 -115
- package/gsd-core/bin/lib/plan-document.cjs +273 -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 +165 -34
- package/gsd-core/bin/lib/planning-workspace.cjs +159 -28
- 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/quick-batch-command-router.cjs +285 -0
- package/gsd-core/bin/lib/quick-batch-dispatch.cjs +250 -0
- package/gsd-core/bin/lib/quick-batch.cjs +840 -0
- package/gsd-core/bin/lib/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 +62 -14
- package/gsd-core/bin/lib/review-lane-invocation.cjs +73 -1
- package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
- package/gsd-core/bin/lib/roadmap-command-router.cjs +45 -31
- package/gsd-core/bin/lib/roadmap-parser.cjs +577 -41
- package/gsd-core/bin/lib/roadmap.cjs +248 -64
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +329 -41
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +16 -17
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +320 -109
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +487 -83
- 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 +75 -8
- package/gsd-core/bin/lib/smart-entry.cjs +19 -31
- 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 +216 -5
- package/gsd-core/bin/lib/state-md-schema.cjs +231 -0
- package/gsd-core/bin/lib/state-transition.cjs +850 -145
- package/gsd-core/bin/lib/state.cjs +1629 -287
- package/gsd-core/bin/lib/surface.cjs +33 -10
- 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/tdd-red-evidence.cjs +133 -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 +2542 -387
- 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/update-context.cjs +6 -2
- package/gsd-core/bin/lib/validate-command-router.cjs +2 -2
- package/gsd-core/bin/lib/validate.cjs +230 -12
- 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-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +287 -13
- package/gsd-core/bin/lib/verify-command-grounding.cjs +846 -0
- package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
- package/gsd-core/bin/lib/verify.cjs +441 -56
- package/gsd-core/bin/lib/workstream-inventory.cjs +20 -2
- 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 +185 -21
- package/gsd-core/bin/shared/config-defaults.manifest.json +7 -1
- package/gsd-core/bin/shared/config-schema.manifest.json +13 -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/bin/verify-reapply-patches.cjs +70 -3
- package/gsd-core/references/agent-contracts.md +6 -5
- 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 +17 -5
- package/gsd-core/references/execute-mvp-tdd.md +18 -18
- package/gsd-core/references/execute-phase-between-wave-reset.md +9 -12
- package/gsd-core/references/execute-phase-response-language.md +6 -0
- package/gsd-core/references/execute-phase-wave-guard.md +11 -9
- package/gsd-core/references/executor-examples.md +42 -0
- package/gsd-core/references/failing-direction.md +78 -0
- package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
- 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/mvp-concepts.md +2 -2
- 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/plan-checker-examples.md +41 -0
- package/gsd-core/references/planner-antipatterns.md +25 -0
- package/gsd-core/references/planner-chunked.md +5 -1
- package/gsd-core/references/planner-coupling.md +42 -0
- package/gsd-core/references/planner-failing-direction.md +53 -0
- package/gsd-core/references/planner-human-verify-mode.md +15 -1
- package/gsd-core/references/planner-quick-batch.md +71 -0
- package/gsd-core/references/planner-reviews.md +47 -0
- package/gsd-core/references/planner-revision.md +76 -3
- package/gsd-core/references/planner-verify-command-grounding.md +17 -0
- package/gsd-core/references/planning-config.md +39 -9
- package/gsd-core/references/response-language-directive.md +9 -0
- package/gsd-core/references/reviewer-instances.md +31 -0
- package/gsd-core/references/revision-loop.md +118 -11
- package/gsd-core/references/runtime-aware-dispatch.md +1 -1
- package/gsd-core/references/tdd.md +15 -12
- 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/verifier-evidence-gate.md +160 -0
- 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 +7 -0
- package/gsd-core/templates/state.md +7 -0
- package/gsd-core/templates/verification-report.md +5 -0
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +3 -1
- package/gsd-core/workflows/add-phase.md +5 -3
- package/gsd-core/workflows/add-tests.md +4 -9
- package/gsd-core/workflows/add-todo.md +2 -2
- package/gsd-core/workflows/ai-integration-phase.md +5 -10
- package/gsd-core/workflows/analyze-dependencies.md +2 -0
- package/gsd-core/workflows/audit-fix.md +14 -3
- package/gsd-core/workflows/audit-milestone.md +11 -9
- package/gsd-core/workflows/audit-uat.md +19 -2
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +2 -2
- package/gsd-core/workflows/autonomous.md +12 -26
- package/gsd-core/workflows/check-todos.md +2 -2
- package/gsd-core/workflows/cleanup.md +3 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +16 -14
- package/gsd-core/workflows/code-review-fix.md +3 -1
- package/gsd-core/workflows/code-review.md +192 -69
- package/gsd-core/workflows/complete-milestone.md +28 -14
- package/gsd-core/workflows/debug.md +6 -4
- package/gsd-core/workflows/diagnose-issues.md +17 -7
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +3 -1
- package/gsd-core/workflows/discuss-phase/modes/all.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/analyze.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/auto.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/batch.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -7
- package/gsd-core/workflows/discuss-phase/modes/default.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/power.md +2 -0
- package/gsd-core/workflows/discuss-phase/modes/text.md +3 -1
- package/gsd-core/workflows/discuss-phase/templates/context.md +2 -0
- package/gsd-core/workflows/discuss-phase/templates/discussion-log.md +2 -0
- package/gsd-core/workflows/discuss-phase-assumptions/steps/auto-advance-dispatch.md +1 -3
- package/gsd-core/workflows/discuss-phase-assumptions.md +3 -3
- package/gsd-core/workflows/discuss-phase-power.md +2 -0
- package/gsd-core/workflows/discuss-phase.md +2 -2
- package/gsd-core/workflows/do.md +46 -19
- package/gsd-core/workflows/docs-update.md +6 -5
- package/gsd-core/workflows/edit-phase.md +3 -1
- package/gsd-core/workflows/eval-review.md +5 -10
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +3 -1
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +129 -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 +29 -5
- 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 +4 -2
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +39 -0
- package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
- package/gsd-core/workflows/execute-phase.md +68 -66
- package/gsd-core/workflows/execute-plan.md +25 -20
- package/gsd-core/workflows/explore.md +3 -1
- package/gsd-core/workflows/extract-learnings.md +3 -1
- package/gsd-core/workflows/fast.md +8 -2
- package/gsd-core/workflows/forensics.md +3 -1
- package/gsd-core/workflows/graduation.md +6 -6
- package/gsd-core/workflows/health.md +4 -7
- package/gsd-core/workflows/help/modes/brief.md +2 -0
- package/gsd-core/workflows/help/modes/default.md +2 -0
- package/gsd-core/workflows/help/modes/full.md +12 -0
- package/gsd-core/workflows/help/modes/topic.md +2 -0
- package/gsd-core/workflows/help.md +2 -0
- package/gsd-core/workflows/import.md +17 -14
- package/gsd-core/workflows/inbox.md +5 -6
- package/gsd-core/workflows/ingest-docs.md +45 -12
- package/gsd-core/workflows/insert-phase.md +7 -5
- package/gsd-core/workflows/list-phase-assumptions.md +2 -0
- package/gsd-core/workflows/list-seeds.md +7 -3
- package/gsd-core/workflows/list-workspaces.md +3 -1
- package/gsd-core/workflows/manager.md +15 -26
- package/gsd-core/workflows/map-codebase.md +3 -1
- package/gsd-core/workflows/milestone-summary.md +3 -1
- package/gsd-core/workflows/mvp-phase.md +3 -3
- package/gsd-core/workflows/new-milestone.md +10 -22
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +1 -1
- package/gsd-core/workflows/new-project.md +17 -29
- package/gsd-core/workflows/new-workspace.md +2 -2
- package/gsd-core/workflows/next.md +4 -2
- package/gsd-core/workflows/node-repair.md +2 -0
- package/gsd-core/workflows/note.md +2 -0
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +20 -5
- 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 +100 -18
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +4 -4
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +12 -3
- package/gsd-core/workflows/plan-phase.md +251 -54
- package/gsd-core/workflows/plan-review-convergence.md +148 -19
- package/gsd-core/workflows/plant-seed.md +3 -3
- package/gsd-core/workflows/pr-branch.md +195 -51
- package/gsd-core/workflows/profile-user.md +17 -15
- package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
- package/gsd-core/workflows/progress.md +52 -15
- package/gsd-core/workflows/quick/steps/discussion-phase.md +1 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +38 -5
- package/gsd-core/workflows/quick/steps/quick-verification.md +2 -4
- package/gsd-core/workflows/quick/steps/research-phase.md +5 -7
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +3 -3
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +55 -0
- package/gsd-core/workflows/quick-batch/steps/completion.md +65 -0
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +100 -0
- package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +147 -0
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +158 -0
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +95 -0
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +49 -0
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +73 -0
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +169 -0
- package/gsd-core/workflows/quick-batch.md +203 -0
- package/gsd-core/workflows/quick.md +33 -32
- package/gsd-core/workflows/reapply-patches.md +2 -0
- package/gsd-core/workflows/remove-phase.md +6 -4
- package/gsd-core/workflows/remove-workspace.md +3 -3
- package/gsd-core/workflows/resume-project.md +14 -14
- package/gsd-core/workflows/review.md +404 -21
- package/gsd-core/workflows/scan.md +3 -1
- package/gsd-core/workflows/section-manifest.json +12 -0
- package/gsd-core/workflows/secure-phase.md +3 -3
- package/gsd-core/workflows/session-report.md +2 -0
- package/gsd-core/workflows/settings-advanced.md +9 -9
- package/gsd-core/workflows/settings-integrations.md +66 -32
- package/gsd-core/workflows/settings.md +4 -6
- package/gsd-core/workflows/ship.md +22 -16
- package/gsd-core/workflows/sketch-wrap-up.md +13 -17
- package/gsd-core/workflows/sketch.md +13 -19
- package/gsd-core/workflows/smart-entry.md +4 -6
- package/gsd-core/workflows/spec-phase.md +31 -4
- package/gsd-core/workflows/spike-wrap-up.md +9 -11
- package/gsd-core/workflows/spike.md +21 -32
- package/gsd-core/workflows/stats.md +4 -2
- package/gsd-core/workflows/sync-skills.md +13 -5
- package/gsd-core/workflows/thread.md +13 -7
- package/gsd-core/workflows/transition.md +7 -5
- package/gsd-core/workflows/ui-phase.md +36 -21
- package/gsd-core/workflows/ui-review.md +7 -11
- package/gsd-core/workflows/ultraplan-phase.md +7 -13
- package/gsd-core/workflows/undo.md +9 -17
- package/gsd-core/workflows/update.md +47 -48
- package/gsd-core/workflows/validate-phase.md +3 -3
- 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 +106 -21
- package/hooks/dist/gsd-agent-isolation-guard.js +77 -38
- package/hooks/dist/gsd-check-update-worker.js +19 -2
- package/hooks/dist/gsd-config-reload.js +18 -12
- package/hooks/dist/gsd-context-monitor.js +302 -22
- 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 +77 -0
- package/hooks/dist/gsd-phase-boundary.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +46 -12
- package/hooks/dist/gsd-read-guard.js +18 -7
- package/hooks/dist/gsd-read-injection-scanner.js +22 -13
- package/hooks/dist/gsd-secret-read-guard.js +1079 -0
- package/hooks/dist/gsd-session-state.sh +1 -0
- package/hooks/dist/gsd-statusline.js +222 -29
- package/hooks/dist/gsd-validate-commit.sh +523 -12
- 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 +36 -17
- 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-cmd.js +210 -1
- package/hooks/dist/lib/git-probe.js +84 -0
- package/hooks/dist/lib/hook-exit.js +81 -0
- package/hooks/dist/lib/injection-patterns.js +36 -6
- package/hooks/dist/managed-hooks-registry.cjs +4 -0
- package/hooks/gsd-agent-isolation-guard.js +77 -38
- package/hooks/gsd-check-update-worker.js +19 -2
- package/hooks/gsd-config-reload.js +18 -12
- package/hooks/gsd-context-monitor.js +302 -22
- 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 +77 -0
- package/hooks/gsd-phase-boundary.sh +1 -0
- package/hooks/gsd-prompt-guard.js +46 -12
- package/hooks/gsd-read-guard.js +18 -7
- package/hooks/gsd-read-injection-scanner.js +22 -13
- package/hooks/gsd-secret-read-guard.js +1079 -0
- package/hooks/gsd-session-state.sh +1 -0
- package/hooks/gsd-statusline.js +222 -29
- package/hooks/gsd-validate-commit.sh +523 -12
- package/hooks/gsd-windsurf-pre-command.js +16 -11
- package/hooks/gsd-windsurf-pre-write.js +22 -13
- package/hooks/gsd-workflow-guard.js +36 -17
- package/hooks/gsd-worktree-path-guard.js +36 -21
- package/hooks/gsd-write-guard.js +35 -25
- package/hooks/hooks.json +6 -0
- package/hooks/lib/cli-exit.js +560 -0
- package/hooks/lib/exit-code-registry.js +98 -0
- package/hooks/lib/git-cmd.js +210 -1
- package/hooks/lib/git-probe.js +84 -0
- package/hooks/lib/hook-exit.js +81 -0
- package/hooks/lib/injection-patterns.js +36 -6
- package/hooks/managed-hooks-registry.cjs +4 -0
- package/package.json +14 -9
- package/scripts/base64-scan.sh +74 -12
- package/scripts/build-hooks.js +12 -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 +52 -12
- package/scripts/ci-timeout-report.cjs +230 -0
- package/scripts/docs-guard-registry.cjs +406 -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 +189 -4
- 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/lib/shellcheck-fetch.cjs +247 -0
- package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -6
- package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +1 -1
- package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +1 -1
- package/scripts/lint-docs-guard-registration.cjs +495 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +198 -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 +45 -14
- package/scripts/lint-phase-id-drift.cjs +133 -8
- package/scripts/lint-planning-prompt-drift.cjs +38 -1
- package/scripts/lint-portable-grep.cjs +176 -0
- package/scripts/lint-removed-but-needed.cjs +184 -16
- package/scripts/lint-response-language-coverage.cjs +524 -0
- 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 +124 -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/lint-workflow-shellcheck-baseline.json +1027 -0
- package/scripts/lint-workflow-shellcheck.cjs +614 -0
- package/scripts/mutation-matrix.cjs +599 -50
- package/scripts/npm-audit-baseline.cjs +376 -0
- package/scripts/prompt-injection-scan.sh +83 -14
- package/scripts/require-issue-link-policy.cjs +16 -1
- 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-execute-phase/SKILL.md +1 -1
- package/skills/gsd-import/SKILL.md +1 -1
- package/skills/gsd-ns-workflow/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +1 -1
- package/skills/gsd-quick/SKILL.md +8 -4
- package/skills/gsd-quick-batch/SKILL.md +105 -0
- package/skills/gsd-surface/SKILL.md +18 -8
- 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
|
@@ -1,8 +1,19 @@
|
|
|
1
|
+
@~/.claude/gsd-core/references/response-language-directive.md
|
|
2
|
+
|
|
1
3
|
<purpose>
|
|
2
|
-
Create a clean branch for pull requests by filtering
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
Create a clean branch for pull requests by filtering .planning/ paths out of the
|
|
5
|
+
cherry-picked history. Two modes, selected by the `planning.pr_strict` config key:
|
|
6
|
+
|
|
7
|
+
- **default** (`planning.pr_strict: false`) — the PR branch contains code changes and
|
|
8
|
+
structural planning state. Reviewers don't see GSD transient artifacts (PLAN.md,
|
|
9
|
+
SUMMARY.md, CONTEXT.md, RESEARCH.md, etc.), but milestone archives, STATE.md,
|
|
10
|
+
ROADMAP.md, and PROJECT.md changes are preserved.
|
|
11
|
+
- **strict** (`planning.pr_strict: true`) — *every* .planning/ path is filtered out,
|
|
12
|
+
structural files included. This is what makes `planning.commit_docs: true` safe for a
|
|
13
|
+
project that versions its planning tree locally but publishes none of it: planning state
|
|
14
|
+
keeps real git history (so `/gsd:undo` and revert paths have something to restore) and
|
|
15
|
+
executor worktrees still find their PLAN.md, while the public PR carries nothing from
|
|
16
|
+
`.planning/`.
|
|
6
17
|
|
|
7
18
|
Uses git cherry-pick with path filtering to rebuild a clean history.
|
|
8
19
|
</purpose>
|
|
@@ -14,7 +25,7 @@ Parse `$ARGUMENTS` for target branch. If no argument is supplied, detect the
|
|
|
14
25
|
default branch via the single resolver (#1146).
|
|
15
26
|
|
|
16
27
|
```bash
|
|
17
|
-
_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 "$
|
|
28
|
+
_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}"; _gsd_at() { for _p; do if [ -f "$_p" ]; then GSD_TOOLS="$_p"; return 0; fi; done; return 1; }; if _gsd_at "${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif unset -f gsd_run; _G="$(command -v gsd_run)"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif _gsd_at "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd_run is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; case "$(gsd_run runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') GSD_IDENTITY_STATUS=ok;; esac; export GSD_IDENTITY_STATUS; [ "$GSD_IDENTITY_STATUS" = ok ] || echo "WARNING: \"$GSD_TOOLS\" did not prove it is @opengsd/gsd-core - it is either a different package or an @opengsd/gsd-core older than the runtime-identity verb. See docs/how-to/diagnose-a-foreign-gsd-tools.md" >&2; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
|
18
29
|
CURRENT_BRANCH=$(git branch --show-current)
|
|
19
30
|
TARGET=${1:-$(gsd_run query git.base-branch)}
|
|
20
31
|
```
|
|
@@ -22,6 +33,7 @@ TARGET=${1:-$(gsd_run query git.base-branch)}
|
|
|
22
33
|
Check preconditions:
|
|
23
34
|
- Must be on a feature branch (not main/master)
|
|
24
35
|
- Must have commits ahead of target
|
|
36
|
+
- Working tree must be clean
|
|
25
37
|
|
|
26
38
|
```bash
|
|
27
39
|
AHEAD=$(git rev-list --count "$TARGET".."$CURRENT_BRANCH" 2>/dev/null)
|
|
@@ -29,17 +41,36 @@ if [ "$AHEAD" = "0" ]; then
|
|
|
29
41
|
echo "No commits ahead of $TARGET — nothing to filter."
|
|
30
42
|
exit 0
|
|
31
43
|
fi
|
|
44
|
+
|
|
45
|
+
# The filter below removes files from the index AND the working tree before each
|
|
46
|
+
# commit lands, and this command switches branches underneath the user's own
|
|
47
|
+
# checkout. An uncommitted edit to a tracked file would be destroyed by that, and
|
|
48
|
+
# git cherry-pick refuses to run against a dirty tree anyway — so fail here, where
|
|
49
|
+
# the message is legible, rather than midway through the cherry-pick loop.
|
|
50
|
+
DIRTY=$(git status --porcelain --untracked-files=no)
|
|
51
|
+
if [ -n "$DIRTY" ]; then
|
|
52
|
+
echo "Working tree has uncommitted changes — commit or stash them first:" >&2
|
|
53
|
+
echo "$DIRTY" >&2
|
|
54
|
+
exit 1
|
|
55
|
+
fi
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Resolve the filter mode from config. A non-zero exit or an unset key means the default
|
|
59
|
+
mode; only the literal string `true` selects strict.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
PR_STRICT=$(gsd_run query config-get planning.pr_strict --raw 2>/dev/null)
|
|
63
|
+
if [ "$PR_STRICT" = "true" ]; then PR_MODE="strict"; else PR_MODE="default"; PR_STRICT="false"; fi
|
|
32
64
|
```
|
|
33
65
|
|
|
34
66
|
Display:
|
|
35
67
|
```
|
|
36
|
-
|
|
37
|
-
GSD ► PR BRANCH
|
|
38
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
68
|
+
### GSD ► PR BRANCH
|
|
39
69
|
|
|
40
70
|
Branch: {CURRENT_BRANCH}
|
|
41
71
|
Target: {TARGET}
|
|
42
72
|
Commits: {AHEAD} ahead
|
|
73
|
+
Mode: {PR_MODE} (planning.pr_strict={PR_STRICT})
|
|
43
74
|
```
|
|
44
75
|
</step>
|
|
45
76
|
|
|
@@ -207,47 +238,65 @@ Classify commits:
|
|
|
207
238
|
git log --oneline "$TARGET".."$CURRENT_BRANCH" --no-merges
|
|
208
239
|
```
|
|
209
240
|
|
|
210
|
-
**
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
241
|
+
**Canonical path declarations.** These two lines are the single source of truth for the
|
|
242
|
+
whole command. `create_pr_branch` derives *which paths it removes* from them, and `verify`
|
|
243
|
+
derives *which paths must not appear* from the same two lines — so the two steps cannot
|
|
244
|
+
disagree about what the filter promised. Declare them exactly once; do not restate either
|
|
245
|
+
list anywhere else in this file.
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
# Transient planning subdirectories — reviewer noise (PLAN.md, SUMMARY.md, CONTEXT.md,
|
|
249
|
+
# RESEARCH.md, and friends). Filtered out in BOTH modes.
|
|
250
|
+
TRANSIENT_DIRS="phases quick research threads todos debug seeds codebase ui-reviews"
|
|
251
|
+
|
|
252
|
+
# Structural planning files — repository planning state. Preserved in default mode,
|
|
253
|
+
# filtered out in strict mode. Anchored on both alternatives so `.planning/STATEX.md`
|
|
254
|
+
# and `.planning/STATE.md.bak` are NOT treated as structural.
|
|
255
|
+
STRUCTURAL_RE="^\.planning/(STATE|ROADMAP|MILESTONES|PROJECT|REQUIREMENTS)\.md$|^\.planning/milestones/"
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Derive the mode's two projections — `FILTER_PATHS` (what `create_pr_branch` removes from
|
|
259
|
+
each cherry-picked commit) and `FORBIDDEN_RE` (what `verify` asserts is absent):
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
if [ "$PR_STRICT" = "true" ]; then
|
|
263
|
+
FILTER_PATHS=".planning/"
|
|
264
|
+
FORBIDDEN_RE="^\.planning/"
|
|
265
|
+
else
|
|
266
|
+
# Rewrapped through unquoted command substitution (gsd-core#4109): a bare
|
|
267
|
+
# `$VAR` word-splits under bash but not zsh, collapsing every element onto
|
|
268
|
+
# one iteration there.
|
|
269
|
+
FILTER_PATHS=$(for d in $(printf '%s' "$TRANSIENT_DIRS"); do printf '.planning/%s/ ' "$d"; done)
|
|
270
|
+
FORBIDDEN_RE="^\.planning/($(echo "$TRANSIENT_DIRS" | tr ' ' '|'))/"
|
|
271
|
+
fi
|
|
272
|
+
```
|
|
228
273
|
|
|
229
274
|
For each commit, check what it touches:
|
|
230
275
|
|
|
231
276
|
```bash
|
|
232
277
|
# For each commit hash
|
|
233
278
|
FILES=$(git diff-tree --no-commit-id --name-only -r $HASH)
|
|
234
|
-
NON_PLANNING=$(echo "$FILES" | grep -v "^\.planning/"
|
|
235
|
-
STRUCTURAL=$(echo "$FILES" | grep -
|
|
236
|
-
TRANSIENT_ONLY=$(echo "$FILES" | grep "^\.planning/" | grep -vE "^\.planning/(STATE|ROADMAP|MILESTONES|PROJECT|REQUIREMENTS)\.md|^\.planning/milestones/" | wc -l)
|
|
279
|
+
NON_PLANNING=$(echo "$FILES" | grep -c -v "^\.planning/" || true)
|
|
280
|
+
STRUCTURAL=$(echo "$FILES" | grep -Ec "$STRUCTURAL_RE" || true)
|
|
237
281
|
```
|
|
238
282
|
|
|
239
283
|
Classify:
|
|
240
|
-
- **Code commits**:
|
|
241
|
-
- **
|
|
242
|
-
|
|
243
|
-
- **
|
|
284
|
+
- **Code commits**: touch at least one non-`.planning/` file → INCLUDE (both modes)
|
|
285
|
+
- **Mixed commits**: touch code + any planning files → INCLUDE (both modes; the planning
|
|
286
|
+
paths are filtered out by `create_pr_branch`, not the commit)
|
|
287
|
+
- **Structural planning commits**: touch only structural `.planning/` files → INCLUDE in
|
|
288
|
+
**default** mode; **EXCLUDE** in strict mode, which has no structural carve-out
|
|
289
|
+
- **Transient planning commits**: touch only `.planning/` paths that are not structural →
|
|
290
|
+
EXCLUDE (both modes)
|
|
291
|
+
|
|
292
|
+
In strict mode this collapses to a single rule: `NON_PLANNING > 0` → INCLUDE, else EXCLUDE.
|
|
244
293
|
|
|
245
294
|
Display analysis:
|
|
246
295
|
```
|
|
247
|
-
Commits to include: {N} (code changes + structural planning)
|
|
248
|
-
Commits to exclude: {N} (
|
|
249
|
-
Mixed commits: {N} (code + planning — included)
|
|
250
|
-
Structural planning commits: {N} (
|
|
296
|
+
Commits to include: {N} (code changes{, + structural planning — default mode only})
|
|
297
|
+
Commits to exclude: {N} (planning-only)
|
|
298
|
+
Mixed commits: {N} (code + planning — included, planning paths filtered)
|
|
299
|
+
Structural planning commits: {N} ({included|excluded — strict mode})
|
|
251
300
|
```
|
|
252
301
|
</step>
|
|
253
302
|
|
|
@@ -259,18 +308,72 @@ PR_BRANCH="${CURRENT_BRANCH}-pr"
|
|
|
259
308
|
git checkout -b "$PR_BRANCH" "$TARGET"
|
|
260
309
|
```
|
|
261
310
|
|
|
262
|
-
Cherry-pick
|
|
311
|
+
Cherry-pick the included commits, in order, filtering `$FILTER_PATHS` out of each one.
|
|
312
|
+
|
|
313
|
+
The filter forces every filtered path back to **exactly what the PR branch's HEAD already
|
|
314
|
+
has**, in both the index and the working tree. That is stricter than simply un-staging, and
|
|
315
|
+
both halves matter:
|
|
316
|
+
|
|
317
|
+
- `git rm -r -f --ignore-unmatch` clears the index entry (including an unmerged one) and
|
|
318
|
+
removes the file the pick just wrote. It only ever touches paths that are in the index, so
|
|
319
|
+
a genuinely untracked planning file of the user's is never harmed.
|
|
320
|
+
- `git checkout HEAD --` then restores whatever the target branch legitimately tracks at
|
|
321
|
+
those paths. **Without this, un-staging a path the target branch already tracks records a
|
|
322
|
+
DELETION** — the generated PR would remove the base branch's planning files. In strict mode
|
|
323
|
+
that would be the base's entire `.planning/` tree.
|
|
324
|
+
|
|
325
|
+
Leaving the filtered file behind in the working tree is not an option either: a later commit
|
|
326
|
+
touching the same planning path makes `git cherry-pick` abort with *"untracked working tree
|
|
327
|
+
files would be overwritten by merge"*, and every remaining commit is silently dropped.
|
|
263
328
|
|
|
264
329
|
```bash
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
#
|
|
270
|
-
|
|
271
|
-
|
|
330
|
+
# Rewrapped through unquoted command substitution (gsd-core#4109): a bare
|
|
331
|
+
# `$VAR` word-splits under bash but not zsh, collapsing every element onto
|
|
332
|
+
# one iteration there.
|
|
333
|
+
for HASH in $(printf '%s' "$INCLUDED_COMMITS"); do
|
|
334
|
+
# A modify/delete conflict on a filtered path is EXPECTED and is resolved below — the
|
|
335
|
+
# filtered path is absent from HEAD by construction. Do not treat it as a failure here.
|
|
336
|
+
git cherry-pick --no-commit "$HASH" || true
|
|
337
|
+
|
|
338
|
+
for P in $(printf '%s' "$FILTER_PATHS"); do
|
|
339
|
+
git rm -r -f -q --ignore-unmatch -- "$P" 2>/dev/null || true
|
|
340
|
+
git checkout HEAD -- "$P" 2>/dev/null || true
|
|
272
341
|
done
|
|
273
|
-
|
|
342
|
+
|
|
343
|
+
# Anything still unmerged is a REAL conflict, outside the filter. Halt — do not
|
|
344
|
+
# improvise a resolution and do not continue, which would drop the rest of the queue.
|
|
345
|
+
# Unwind first: this loop runs in the user's own checkout, so exiting mid-sequence
|
|
346
|
+
# would strand them on a half-built branch with cherry-pick state still live.
|
|
347
|
+
if [ -n "$(git diff --name-only --diff-filter=U)" ]; then
|
|
348
|
+
echo "Conflict outside the .planning/ filter while picking $HASH:" >&2
|
|
349
|
+
git diff --name-only --diff-filter=U >&2
|
|
350
|
+
# Order matters. `--quit` drops the sequencer state but leaves the unmerged index
|
|
351
|
+
# in place, and an unmerged index makes `git checkout` refuse — so reset first.
|
|
352
|
+
# $PR_BRANCH is disposable and every commit on it was cherry-picked, and the
|
|
353
|
+
# clean-tree precondition guarantees the user had nothing uncommitted, so a hard
|
|
354
|
+
# reset here cannot destroy anything of theirs.
|
|
355
|
+
git cherry-pick --quit 2>/dev/null || true
|
|
356
|
+
git reset -q --hard HEAD
|
|
357
|
+
if git checkout -q "$CURRENT_BRANCH"; then
|
|
358
|
+
git branch -q -D "$PR_BRANCH" 2>/dev/null || true
|
|
359
|
+
echo "Restored $CURRENT_BRANCH and removed the partial $PR_BRANCH." >&2
|
|
360
|
+
else
|
|
361
|
+
# Never claim a restore that did not happen — say exactly where they are.
|
|
362
|
+
echo "Could not return to $CURRENT_BRANCH; you are still on $PR_BRANCH." >&2
|
|
363
|
+
echo "Run: git checkout $CURRENT_BRANCH && git branch -D $PR_BRANCH" >&2
|
|
364
|
+
fi
|
|
365
|
+
echo "Resolve the conflict against $TARGET, then re-run /gsd:pr-branch." >&2
|
|
366
|
+
exit 1
|
|
367
|
+
fi
|
|
368
|
+
|
|
369
|
+
# Nothing left after filtering (possible when a pick's only surviving content was
|
|
370
|
+
# planning state): clear the sequencer rather than failing on an empty commit.
|
|
371
|
+
if git diff --cached --quiet; then
|
|
372
|
+
git cherry-pick --quit 2>/dev/null || true
|
|
373
|
+
continue
|
|
374
|
+
fi
|
|
375
|
+
|
|
376
|
+
git commit -q -C "$HASH"
|
|
274
377
|
done
|
|
275
378
|
```
|
|
276
379
|
|
|
@@ -281,20 +384,50 @@ git checkout "$CURRENT_BRANCH"
|
|
|
281
384
|
</step>
|
|
282
385
|
|
|
283
386
|
<step name="verify">
|
|
387
|
+
Assert against the **active mode's** contract — `$FORBIDDEN_RE`, the same declaration
|
|
388
|
+
`create_pr_branch` filtered on. Counting every `.planning/` path unconditionally would
|
|
389
|
+
contradict default mode, which is specified to preserve structural files: a correct run
|
|
390
|
+
would report itself as failed on every phase that touched STATE.md, which is every phase.
|
|
391
|
+
|
|
284
392
|
```bash
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
393
|
+
DIFF_PATHS=$(git diff --name-only "$TARGET".."$PR_BRANCH")
|
|
394
|
+
FORBIDDEN=$(echo "$DIFF_PATHS" | grep -Ec "$FORBIDDEN_RE" || true)
|
|
395
|
+
PLANNING_TOTAL=$(echo "$DIFF_PATHS" | grep -c "^\.planning/" || true)
|
|
396
|
+
ALLOWED=$((PLANNING_TOTAL - FORBIDDEN))
|
|
397
|
+
TOTAL_FILES=$(echo "$DIFF_PATHS" | grep -c . || true)
|
|
288
398
|
PR_COMMITS=$(git rev-list --count "$TARGET".."$PR_BRANCH")
|
|
399
|
+
|
|
400
|
+
# #3679: a DELETED planning path is never legitimate — this workflow only ever
|
|
401
|
+
# excludes content a cherry-picked commit ADDED; pre-existing target-tracked
|
|
402
|
+
# planning files must survive byte-identical. Name-only counting cannot see
|
|
403
|
+
# status (a deleted structural/allowed path verifies clean there), so gate on
|
|
404
|
+
# deletions explicitly, across every planning category.
|
|
405
|
+
PLANNING_DELETIONS=$(git diff --name-status --no-renames "$TARGET".."$PR_BRANCH" | grep "^D" | grep -c "\.planning/" || true)
|
|
406
|
+
|
|
407
|
+
# Default mode preserves anything under .planning/ that is neither transient nor
|
|
408
|
+
# structural — config.json, intel/, workstreams/. That is deliberate and unchanged, but it
|
|
409
|
+
# must not be silent: report it so the user can choose strict mode knowingly.
|
|
410
|
+
OTHER=$(echo "$DIFF_PATHS" | grep "^\.planning/" | grep -Ev "$FORBIDDEN_RE" | grep -Ev "$STRUCTURAL_RE" || true)
|
|
289
411
|
```
|
|
290
412
|
|
|
413
|
+
`$FORBIDDEN` is the pass/fail number — it must be `0`. A non-zero value means the filter
|
|
414
|
+
did not do what this mode promised; report it and do not tell the user to push.
|
|
415
|
+
|
|
416
|
+
`$PLANNING_DELETIONS` is a second hard gate (#3679) — it must also be `0`. A non-zero
|
|
417
|
+
value means the PR branch would DELETE planning files the target branch tracks
|
|
418
|
+
(`git diff --name-status --no-renames "$TARGET".."$PR_BRANCH" | grep "^D" | grep "\.planning/"` lists
|
|
419
|
+
them). That is data loss, not filtering — report it, do not tell the user to push, and
|
|
420
|
+
rebuild the branch.
|
|
421
|
+
|
|
291
422
|
Display results:
|
|
292
423
|
```
|
|
293
424
|
✅ PR branch created: {PR_BRANCH}
|
|
294
425
|
|
|
295
426
|
Original: {AHEAD} commits, {ORIGINAL_FILES} files
|
|
296
427
|
PR branch: {PR_COMMITS} commits, {TOTAL_FILES} files
|
|
297
|
-
|
|
428
|
+
Mode: {PR_MODE}
|
|
429
|
+
Planning paths in diff: {PLANNING_TOTAL} (allowed {ALLOWED}, forbidden {FORBIDDEN} — must be 0)
|
|
430
|
+
Planning deletions: {PLANNING_DELETIONS} (must be 0 — #3679)
|
|
298
431
|
|
|
299
432
|
Next steps:
|
|
300
433
|
git push origin {PR_BRANCH}
|
|
@@ -302,14 +435,25 @@ Next steps:
|
|
|
302
435
|
|
|
303
436
|
Or use /gsd:ship to create the PR automatically.
|
|
304
437
|
```
|
|
438
|
+
|
|
439
|
+
When `$OTHER` is non-empty (default mode only — strict forbids all of it), append:
|
|
440
|
+
```
|
|
441
|
+
ℹ️ These .planning/ paths are neither transient nor structural, so default mode keeps them:
|
|
442
|
+
{OTHER}
|
|
443
|
+
Set `planning.pr_strict: true` to keep every .planning/ path out of the PR branch.
|
|
444
|
+
```
|
|
305
445
|
</step>
|
|
306
446
|
|
|
307
447
|
</process>
|
|
308
448
|
|
|
309
449
|
<success_criteria>
|
|
450
|
+
- [ ] Working tree was clean before the PR branch was created
|
|
310
451
|
- [ ] PR branch created from target
|
|
311
452
|
- [ ] Planning-only commits excluded
|
|
312
|
-
- [ ]
|
|
453
|
+
- [ ] Zero paths matching the active mode's `$FORBIDDEN_RE` in the PR branch diff —
|
|
454
|
+
strict: no `.planning/` path at all; default: none from `$TRANSIENT_DIRS`
|
|
455
|
+
- [ ] No `.planning/` path the target branch already tracked was deleted
|
|
456
|
+
- [ ] Every included commit landed — none dropped by a failed cherry-pick
|
|
313
457
|
- [ ] Commit messages preserved from original
|
|
314
458
|
- [ ] User shown next steps
|
|
315
459
|
</success_criteria>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<purpose>
|
|
2
2
|
Orchestrate the full developer profiling flow: consent, session analysis (or questionnaire fallback), profile generation, result display, and artifact creation.
|
|
3
3
|
|
|
4
|
-
This workflow wires Phase 1 (session pipeline) and Phase 2 (profiling engine) into a cohesive user-facing experience. All heavy lifting is done by existing `
|
|
4
|
+
This workflow wires Phase 1 (session pipeline) and Phase 2 (profiling engine) into a cohesive user-facing experience. All heavy lifting is done by existing `gsd_run query` handlers and the gsd-user-profiler agent -- this workflow orchestrates the sequence, handles branching, and provides the UX.
|
|
5
5
|
</purpose>
|
|
6
6
|
|
|
7
7
|
<required_reading>
|
|
@@ -15,12 +15,11 @@ Key references:
|
|
|
15
15
|
|
|
16
16
|
<process>
|
|
17
17
|
```bash
|
|
18
|
-
_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 "$
|
|
19
|
-
RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --default "" 2>/dev/null || echo "")
|
|
18
|
+
_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}"; _gsd_at() { for _p; do if [ -f "$_p" ]; then GSD_TOOLS="$_p"; return 0; fi; done; return 1; }; if _gsd_at "${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif unset -f gsd_run; _G="$(command -v gsd_run)"; then GSD_TOOLS="$_G"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif _gsd_at "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; then gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd_run is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; GSD_IDENTITY_STATUS=unverified; case "$(gsd_run runtime-identity --raw 2>/dev/null || true)" in '{"packageName":"@opengsd/gsd-core"'*'}') GSD_IDENTITY_STATUS=ok;; esac; export GSD_IDENTITY_STATUS; [ "$GSD_IDENTITY_STATUS" = ok ] || echo "WARNING: \"$GSD_TOOLS\" did not prove it is @opengsd/gsd-core - it is either a different package or an @opengsd/gsd-core older than the runtime-identity verb. See docs/how-to/diagnose-a-foreign-gsd-tools.md" >&2; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
|
19
|
+
RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --raw --default "" 2>/dev/null || echo "")
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
**If `response_language` is set:** All user-facing questions, prompts, and explanations
|
|
23
|
-
|
|
22
|
+
**If `response_language` is set:** All user-facing output of this workflow — narration between tool calls, status updates, progress notes, findings, questions, prompts, and explanations — MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
|
|
24
23
|
|
|
25
24
|
## 1. Initialize
|
|
26
25
|
|
|
@@ -37,7 +36,6 @@ PROFILE_PATH="$HOME/.claude/gsd-core/USER-PROFILE.md"
|
|
|
37
36
|
|
|
38
37
|
**If profile exists AND --refresh NOT set AND --questionnaire NOT set:**
|
|
39
38
|
|
|
40
|
-
|
|
41
39
|
**Text mode (`workflow.text_mode: true` in config or `--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS` OR `text_mode` from init JSON is `true`. When TEXT_MODE is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex, Gemini CLI, etc.) where `AskUserQuestion` is not available.
|
|
42
40
|
Use AskUserQuestion:
|
|
43
41
|
- header: "Existing Profile"
|
|
@@ -72,9 +70,7 @@ Continue to step 2.
|
|
|
72
70
|
Display consent screen:
|
|
73
71
|
|
|
74
72
|
```
|
|
75
|
-
|
|
76
|
-
GSD > PROFILE YOUR CODING STYLE
|
|
77
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
73
|
+
### GSD > PROFILE YOUR CODING STYLE
|
|
78
74
|
|
|
79
75
|
Claude starts every conversation generic. A profile teaches Claude
|
|
80
76
|
how YOU actually work -- not how you think you work.
|
|
@@ -166,9 +162,17 @@ Display: "✓ Sampled N messages from M projects"
|
|
|
166
162
|
|
|
167
163
|
Display: "◆ Analyzing patterns..."
|
|
168
164
|
|
|
165
|
+
```bash
|
|
166
|
+
PROFILER_MODEL=$(gsd_run query resolve-model gsd-user-profiler --raw)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
<!-- #2517 model-omit-on-inherit -->
|
|
170
|
+
|
|
171
|
+
> **Model omission (#2517).** Omit the `model` parameter entirely when the value it would carry (`PROFILER_MODEL`) is `"inherit"` or empty. An empty value 404s on runtimes without native tier aliases — the default on non-Claude runtimes. Omitting it inherits the orchestrator's model. See @gsd-core/references/model-profile-resolution.md.
|
|
172
|
+
|
|
169
173
|
**Spawn gsd-user-profiler agent using Task tool:**
|
|
170
174
|
|
|
171
|
-
Use the Task tool to spawn the `gsd-user-profiler` agent. Provide it with:
|
|
175
|
+
Use the Task tool to spawn the `gsd-user-profiler` agent, passing `model="{PROFILER_MODEL}"` (omit the parameter per the rule above when the value is `"inherit"` or empty). Provide it with:
|
|
172
176
|
- The sampled JSONL file path from profile-sample output
|
|
173
177
|
- The user-profiling reference doc at `$HOME/.claude/gsd-core/references/user-profiling.md`
|
|
174
178
|
|
|
@@ -382,7 +386,7 @@ gsd_run query generate-claude-profile --analysis "$ANALYSIS_PATH" --global --jso
|
|
|
382
386
|
|
|
383
387
|
Display: "✓ Added profile section to $HOME/.claude/CLAUDE.md"
|
|
384
388
|
|
|
385
|
-
**Error handling:** If any `
|
|
389
|
+
**Error handling:** If any `gsd_run query` call fails, display the error message and use AskUserQuestion to offer "Retry" or "Skip this artifact". On retry, re-run the command. On skip, continue to next artifact.
|
|
386
390
|
|
|
387
391
|
---
|
|
388
392
|
|
|
@@ -413,9 +417,7 @@ If nothing changed: Display "No changes detected -- your profile is already up t
|
|
|
413
417
|
**Display final summary:**
|
|
414
418
|
|
|
415
419
|
```
|
|
416
|
-
|
|
417
|
-
GSD > PROFILE COMPLETE ✓
|
|
418
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
420
|
+
### GSD > PROFILE COMPLETE ✓
|
|
419
421
|
|
|
420
422
|
Your profile: $HOME/.claude/gsd-core/USER-PROFILE.md
|
|
421
423
|
```
|
|
@@ -459,7 +461,7 @@ rm -f "$ANALYSIS_PATH" 2>/dev/null
|
|
|
459
461
|
- [ ] Profile written to USER-PROFILE.md via write-profile subcommand
|
|
460
462
|
- [ ] Result display shows report card table and highlight reel with evidence
|
|
461
463
|
- [ ] Artifact selection uses multiSelect with all options pre-selected
|
|
462
|
-
- [ ] Artifacts generated sequentially via
|
|
464
|
+
- [ ] Artifacts generated sequentially via `gsd_run query` subcommands
|
|
463
465
|
- [ ] Refresh diff shows changed dimensions when --refresh was used
|
|
464
466
|
- [ ] Temp files cleaned up on completion
|
|
465
467
|
</success_criteria>
|
|
@@ -89,7 +89,7 @@ Glob every phase directory's SCOPE BOUNDARY log (executor writes out-of-scope di
|
|
|
89
89
|
ls .planning/phases/*/deferred-items.md 2>/dev/null || true
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
For each `deferred-items.md` found, read its entries (bullet list, one entry per top-level
|
|
92
|
+
For each `deferred-items.md` found, read its entries (bullet list, one entry per top-level list item — `-`, `*`, `+` or an ordered marker of one to nine digits terminated by a DOT, where an ordered list counts when it starts at `0.` or `1.` or continues a list already open at its level; `1)` is not a marker and neither is a ten-digit ordinal (`999999999.` counts, `1234567890.` does not) — with continuation lines indented beneath it; fenced code blocks at ANY indent, including deeper than CommonMark's three-space cap, and `* * *`-style separators are not entries; an unclosed fence ends with its own entry and never hides the entries after it; a closed pair of delimiters is a fence whatever sits between them). An entry is RESOLVED only if it carries an explicit `status: resolved` field on one of its lines — the bare key lower-case only, or the bolded `**Status:**` form in any case; the VALUE is case-insensitive in both; every other entry — including one with no `status:` field at all — is UNRESOLVED and must be surfaced (fail-safe: never silently drop a possibly-open item).
|
|
93
93
|
|
|
94
94
|
Emit:
|
|
95
95
|
- ✓ `No unresolved deferred items` — if no `deferred-items.md` files exist, or every entry in every file is `status: resolved`
|