@opengsd/gsd-core 1.13.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.ja-JP.md +3 -3
- package/README.ko-KR.md +3 -3
- package/README.pt-BR.md +3 -3
- package/README.zh-CN.md +3 -3
- package/agents/gsd-advisor-researcher.compact.md +85 -0
- package/agents/gsd-ai-researcher.compact.md +96 -0
- package/agents/gsd-assumptions-analyzer.compact.md +81 -0
- package/agents/gsd-code-fixer.compact.md +459 -0
- package/agents/gsd-code-fixer.md +9 -8
- package/agents/gsd-code-reviewer.compact.md +269 -0
- package/agents/gsd-code-reviewer.md +15 -3
- package/agents/gsd-codebase-mapper.compact.md +760 -0
- package/agents/gsd-debug-session-manager.compact.md +360 -0
- package/agents/gsd-debug-session-manager.md +17 -2
- package/agents/gsd-debugger.md +2 -2
- package/agents/gsd-doc-classifier.compact.md +192 -0
- package/agents/gsd-doc-synthesizer.compact.md +200 -0
- package/agents/gsd-doc-verifier.compact.md +143 -0
- package/agents/gsd-doc-writer.compact.md +440 -0
- package/agents/gsd-dom-verifier.compact.md +138 -0
- package/agents/gsd-domain-researcher.compact.md +141 -0
- package/agents/gsd-eval-auditor.compact.md +160 -0
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-eval-planner.compact.md +137 -0
- package/agents/gsd-executor.md +13 -8
- package/agents/gsd-framework-selector.compact.md +82 -0
- package/agents/gsd-integration-checker.compact.md +245 -0
- package/agents/gsd-intel-updater.compact.md +226 -0
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.compact.md +45 -0
- package/agents/gsd-nyquist-auditor.compact.md +179 -0
- package/agents/gsd-pattern-mapper.compact.md +275 -0
- package/agents/gsd-phase-researcher.md +19 -11
- package/agents/gsd-plan-checker.md +8 -7
- package/agents/gsd-planner.md +12 -8
- package/agents/gsd-project-researcher.compact.md +587 -0
- package/agents/gsd-project-researcher.md +1 -1
- package/agents/gsd-research-synthesizer.compact.md +212 -0
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-roadmapper.compact.md +454 -0
- package/agents/gsd-roadmapper.md +13 -0
- package/agents/gsd-security-auditor.compact.md +162 -0
- package/agents/gsd-ui-auditor.compact.md +404 -0
- package/agents/gsd-ui-auditor.md +155 -17
- package/agents/gsd-ui-checker.compact.md +277 -0
- package/agents/gsd-ui-researcher.compact.md +282 -0
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-user-profiler.compact.md +108 -0
- package/agents/gsd-verifier.md +10 -9
- package/bin/install.js +848 -163
- package/commands/gsd/autonomous.md +2 -2
- package/commands/gsd/capture.md +1 -1
- package/commands/gsd/cleanup.md +1 -0
- package/commands/gsd/code-review.md +2 -1
- package/commands/gsd/complete-milestone.md +1 -0
- package/commands/gsd/config.md +1 -0
- package/commands/gsd/debug.md +1 -0
- package/commands/gsd/graphify.md +1 -0
- package/commands/gsd/health.md +1 -0
- package/commands/gsd/mempalace-capture.md +8 -3
- package/commands/gsd/mempalace-recall.md +1 -0
- package/commands/gsd/new-milestone.md +1 -0
- package/commands/gsd/new-project.md +1 -0
- package/commands/gsd/next.md +1 -0
- package/commands/gsd/pause-work.md +1 -0
- package/commands/gsd/phase.md +1 -0
- package/commands/gsd/plan-review-convergence.md +6 -6
- package/commands/gsd/pr-branch.md +1 -0
- package/commands/gsd/progress.md +1 -1
- package/commands/gsd/quick-batch.md +1 -1
- package/commands/gsd/resume-work.md +1 -0
- package/commands/gsd/review-backlog.md +1 -0
- package/commands/gsd/review.md +2 -3
- package/commands/gsd/settings.md +2 -1
- package/commands/gsd/stats.md +1 -0
- package/commands/gsd/thread.md +1 -0
- package/commands/gsd/workspace.md +1 -0
- package/commands/gsd/workstreams.md +1 -0
- package/gsd-core/bin/check-latest-version.cjs +8 -3
- package/gsd-core/bin/gsd-tools.cjs +672 -146
- package/gsd-core/bin/lib/adr-parser.cjs +4 -2
- package/gsd-core/bin/lib/artifacts.cjs +2 -1
- package/gsd-core/bin/lib/audit.cjs +119 -34
- package/gsd-core/bin/lib/broken-windows.cjs +168 -49
- package/gsd-core/bin/lib/capability-lifecycle.cjs +10 -6
- package/gsd-core/bin/lib/capability-loader.cjs +135 -1
- package/gsd-core/bin/lib/capability-registry.cjs +96 -189
- package/gsd-core/bin/lib/capability-source.cjs +19 -2
- package/gsd-core/bin/lib/capability-validator.cjs +14 -2
- package/gsd-core/bin/lib/check-command-router.cjs +213 -49
- package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
- package/gsd-core/bin/lib/codex-agent-toml.cjs +21 -25
- package/gsd-core/bin/lib/commands.cjs +823 -112
- package/gsd-core/bin/lib/config-loader.cjs +66 -4
- package/gsd-core/bin/lib/config.cjs +186 -45
- package/gsd-core/bin/lib/coverage.cjs +1 -1
- package/gsd-core/bin/lib/decisions.cjs +164 -45
- package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
- package/gsd-core/bin/lib/frontmatter.cjs +13 -0
- package/gsd-core/bin/lib/graphify.cjs +10 -2
- package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +12 -1
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
- package/gsd-core/bin/lib/host-runtime-detection.cjs +9 -0
- package/gsd-core/bin/lib/init.cjs +614 -86
- package/gsd-core/bin/lib/install-engine.cjs +29 -3
- package/gsd-core/bin/lib/install-profiles.cjs +14 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +41 -5
- package/gsd-core/bin/lib/loop-resolver.cjs +50 -31
- package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
- package/gsd-core/bin/lib/milestone.cjs +37 -13
- package/gsd-core/bin/lib/model-resolver.cjs +253 -53
- package/gsd-core/bin/lib/phase-command-router.cjs +16 -2
- package/gsd-core/bin/lib/phase-id-card.cjs +32 -0
- package/gsd-core/bin/lib/phase-id-display.cjs +78 -0
- package/gsd-core/bin/lib/phase-id.cjs +268 -27
- package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
- package/gsd-core/bin/lib/phase-locator.cjs +29 -10
- package/gsd-core/bin/lib/phase.cjs +393 -88
- package/gsd-core/bin/lib/plan-document.cjs +49 -1
- package/gsd-core/bin/lib/planning-document.cjs +459 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +52 -19
- package/gsd-core/bin/lib/planning-snapshot.cjs +61 -12
- package/gsd-core/bin/lib/planning-workspace.cjs +57 -3
- package/gsd-core/bin/lib/pr-branch-patterns.cjs +57 -0
- package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
- package/gsd-core/bin/lib/probe-core.cjs +7 -1
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
- package/gsd-core/bin/lib/project-root.cjs +41 -2
- package/gsd-core/bin/lib/quick-batch.cjs +1 -1
- package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +61 -2
- package/gsd-core/bin/lib/research-store.cjs +11 -12
- package/gsd-core/bin/lib/review-lane-descriptor.cjs +10 -30
- package/gsd-core/bin/lib/review-lane-invocation.cjs +23 -0
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +2 -2
- package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +12 -4
- package/gsd-core/bin/lib/roadmap-parser.cjs +219 -18
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +1539 -13
- package/gsd-core/bin/lib/roadmap.cjs +356 -42
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +310 -41
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +15 -4
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +13 -5
- package/gsd-core/bin/lib/runtime-homes.cjs +4 -0
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +408 -37
- package/gsd-core/bin/lib/runtime-name-policy.cjs +111 -1
- package/gsd-core/bin/lib/security.cjs +126 -7
- package/gsd-core/bin/lib/shell-command-projection.cjs +10 -6
- package/gsd-core/bin/lib/state-document.cjs +130 -28
- package/gsd-core/bin/lib/state-md-schema.cjs +21 -14
- package/gsd-core/bin/lib/state-transition.cjs +181 -30
- package/gsd-core/bin/lib/state.cjs +265 -27
- package/gsd-core/bin/lib/surface.cjs +77 -3
- package/gsd-core/bin/lib/task-command-router.cjs +12 -6
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +78 -5
- package/gsd-core/bin/lib/uat-predicate.cjs +47 -4
- package/gsd-core/bin/lib/uat.cjs +9 -1
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +15 -2
- package/gsd-core/bin/lib/ui-frontend-evidence.cjs +100 -9
- package/gsd-core/bin/lib/undo-commit-selection.cjs +131 -0
- package/gsd-core/bin/lib/update-context.cjs +30 -24
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
- package/gsd-core/bin/lib/verification.cjs +315 -30
- package/gsd-core/bin/lib/verify-command-grounding.cjs +47 -3
- package/gsd-core/bin/lib/verify.cjs +320 -48
- package/gsd-core/bin/lib/workstream-inventory.cjs +1 -0
- package/gsd-core/bin/lib/worktree-base-ref.cjs +482 -73
- package/gsd-core/bin/lib/worktree-safety.cjs +797 -58
- package/gsd-core/bin/shared/config-defaults.manifest.json +4 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +6 -0
- package/gsd-core/bin/verify-reapply-patches.cjs +439 -80
- package/gsd-core/references/checkpoints.md +5 -3
- package/gsd-core/references/compact-content-gate.md +66 -0
- package/gsd-core/references/edge-probe-fixtures/01-round-half-even/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/02-merge-intervals/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/03-truncate-graphemes/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/04-money-rounding/expected-coverage.json +28 -3
- package/gsd-core/references/edge-probe-fixtures/05-list-dedupe/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe-fixtures/06-resolved-mixed/expected-coverage.json +37 -4
- package/gsd-core/references/edge-probe.md +195 -21
- package/gsd-core/references/execute-phase-between-wave-reset.md +7 -6
- package/gsd-core/references/execute-phase-wave-guard.md +22 -11
- package/gsd-core/references/gsd-run-resolver.md +1 -1
- package/gsd-core/references/loop-hook-dispatch.md +18 -0
- package/gsd-core/references/model-profiles.md +13 -4
- package/gsd-core/references/phase-argument-parsing.md +9 -7
- package/gsd-core/references/phase-id-convention.md +28 -0
- package/gsd-core/references/planner-gap-closure.md +2 -0
- package/gsd-core/references/planner-load-graph-context.md +24 -13
- package/gsd-core/references/planner-verify-command-grounding.md +14 -0
- package/gsd-core/references/planning-config.md +14 -2
- package/gsd-core/references/tdd.md +30 -4
- package/gsd-core/references/thinking-models-planning.md +18 -2
- package/gsd-core/references/ui-consideration-probe.md +10 -5
- package/gsd-core/references/verification-patterns.md +17 -4
- package/gsd-core/references/verify-command-path-resolvability.md +10 -2
- package/gsd-core/references/worktree-path-safety.md +433 -2
- package/gsd-core/templates/README.md +7 -1
- package/gsd-core/templates/state.md +6 -3
- package/gsd-core/templates/summary.compact.md +212 -0
- package/gsd-core/templates/user-setup.compact.md +199 -0
- package/gsd-core/templates/user-setup.md +0 -9
- package/gsd-core/templates/verification-report.md +1 -1
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +1 -1
- package/gsd-core/workflows/add-phase.md +1 -1
- package/gsd-core/workflows/add-tests.md +2 -2
- package/gsd-core/workflows/add-todo.md +6 -5
- package/gsd-core/workflows/ai-integration-phase.md +11 -3
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +1 -1
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous/steps/converge-fail-fast.md +9 -18
- package/gsd-core/workflows/autonomous.md +29 -16
- package/gsd-core/workflows/check-todos.md +6 -4
- package/gsd-core/workflows/cleanup.md +5 -3
- package/gsd-core/workflows/code-review/steps/dispatch-fix.md +4 -3
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +8 -1
- package/gsd-core/workflows/code-review-fix.md +108 -22
- package/gsd-core/workflows/code-review.md +216 -73
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
- package/gsd-core/workflows/complete-milestone.md +41 -264
- package/gsd-core/workflows/debug.md +3 -3
- package/gsd-core/workflows/diagnose-issues.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +2 -2
- package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
- package/gsd-core/workflows/docs-update.md +17 -158
- package/gsd-core/workflows/edit-phase.md +1 -1
- package/gsd-core/workflows/eval-review.md +10 -3
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
- package/gsd-core/workflows/execute-phase/steps/code-review-disposition.md +1017 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +19 -4
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +43 -4
- package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
- package/gsd-core/workflows/execute-phase/steps/gap-closure-artifacts.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/partial-wave.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +46 -9
- package/gsd-core/workflows/execute-phase/steps/protected-branch.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/ready-wave-gate.md +37 -0
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
- package/gsd-core/workflows/execute-phase/steps/stale-reverification.md +24 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/threat-id-gate.md +28 -0
- package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/worktree-base-check.md +25 -0
- package/gsd-core/workflows/execute-phase.md +83 -172
- package/gsd-core/workflows/execute-plan.md +24 -10
- package/gsd-core/workflows/explore.md +3 -3
- package/gsd-core/workflows/extract-learnings.md +2 -1
- package/gsd-core/workflows/fast.md +1 -1
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +2 -2
- package/gsd-core/workflows/help/modes/full.compact.md +398 -0
- package/gsd-core/workflows/help/modes/full.md +5 -5
- package/gsd-core/workflows/help/modes/topic.md +15 -5
- package/gsd-core/workflows/help.md +1 -1
- package/gsd-core/workflows/import.md +2 -2
- package/gsd-core/workflows/inbox.md +2 -2
- package/gsd-core/workflows/ingest-docs.md +3 -3
- package/gsd-core/workflows/insert-phase.md +1 -1
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +2 -2
- package/gsd-core/workflows/map-codebase.md +52 -5
- package/gsd-core/workflows/milestone-summary.md +1 -1
- package/gsd-core/workflows/mvp-phase.md +1 -1
- package/gsd-core/workflows/new-milestone.md +56 -14
- package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
- package/gsd-core/workflows/new-project/steps/auto-mode-config.md +3 -3
- package/gsd-core/workflows/new-project/steps/codebase-map-offer.md +1 -1
- package/gsd-core/workflows/new-project.md +39 -209
- package/gsd-core/workflows/new-workspace.md +2 -2
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/note.md +1 -1
- package/gsd-core/workflows/onboard.md +1 -1
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +17 -5
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +23 -5
- package/gsd-core/workflows/plan-phase.md +45 -187
- package/gsd-core/workflows/plan-review-convergence.md +21 -5
- package/gsd-core/workflows/plant-seed.md +62 -20
- package/gsd-core/workflows/pr-branch.md +132 -20
- package/gsd-core/workflows/profile-user.md +2 -2
- package/gsd-core/workflows/progress.md +1 -1
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +25 -0
- package/gsd-core/workflows/quick/steps/quick-verification.md +1 -1
- package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/batch-init.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/completion.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/merge-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/planner-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/research-phase.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/resume-mode.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/verification-wave.md +1 -1
- package/gsd-core/workflows/quick-batch/steps/worktree-dispatch.md +1 -1
- package/gsd-core/workflows/quick-batch.md +1 -1
- package/gsd-core/workflows/quick.md +29 -10
- package/gsd-core/workflows/reapply-patches.md +86 -6
- package/gsd-core/workflows/remove-phase.md +1 -1
- package/gsd-core/workflows/remove-workspace.md +2 -2
- package/gsd-core/workflows/resume-project.md +1 -1
- package/gsd-core/workflows/review.md +31 -16
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +3 -2
- package/gsd-core/workflows/settings-advanced.md +30 -10
- package/gsd-core/workflows/settings-integrations.md +2 -3
- package/gsd-core/workflows/settings.md +22 -9
- package/gsd-core/workflows/ship.md +3 -2
- package/gsd-core/workflows/sketch-wrap-up.md +1 -1
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +2 -2
- package/gsd-core/workflows/spec-phase.md +15 -5
- package/gsd-core/workflows/spike-wrap-up.md +1 -1
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +1 -1
- package/gsd-core/workflows/sync-skills.md +5 -5
- package/gsd-core/workflows/thread.md +1 -1
- package/gsd-core/workflows/transition.md +1 -1
- package/gsd-core/workflows/ui-phase.md +44 -8
- package/gsd-core/workflows/ui-review.md +18 -4
- package/gsd-core/workflows/ultraplan-phase.md +1 -1
- package/gsd-core/workflows/undo.md +339 -20
- package/gsd-core/workflows/update.md +14 -12
- package/gsd-core/workflows/validate-phase.md +3 -2
- package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
- package/gsd-core/workflows/verify-work/steps/automated-ui-verification.md +1 -1
- package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +1 -1
- package/gsd-core/workflows/verify-work.md +101 -196
- package/hooks/dist/gsd-agent-isolation-guard.js +66 -16
- package/hooks/dist/gsd-context-monitor.js +88 -15
- package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
- package/hooks/dist/gsd-secret-read-guard.js +71 -19
- package/hooks/dist/gsd-statusline.js +81 -20
- package/hooks/dist/gsd-validate-commit.sh +97 -8
- package/hooks/dist/gsd-worktree-path-guard.js +25 -14
- package/hooks/dist/gsd-write-guard.js +46 -1
- package/hooks/dist/lib/dispatch-identity.js +187 -0
- package/hooks/dist/lib/filename-classification.js +64 -0
- package/hooks/dist/lib/isolation-deny-reason.js +53 -1
- package/hooks/dist/lib/isolation-sentinel.js +58 -19
- package/hooks/gsd-agent-isolation-guard.js +66 -16
- package/hooks/gsd-context-monitor.js +88 -15
- package/hooks/gsd-cursor-subagent-start.js +34 -14
- package/hooks/gsd-secret-read-guard.js +71 -19
- package/hooks/gsd-statusline.js +81 -20
- package/hooks/gsd-validate-commit.sh +97 -8
- package/hooks/gsd-worktree-path-guard.js +25 -14
- package/hooks/gsd-write-guard.js +46 -1
- package/hooks/lib/dispatch-identity.js +187 -0
- package/hooks/lib/filename-classification.js +64 -0
- package/hooks/lib/isolation-deny-reason.js +53 -1
- package/hooks/lib/isolation-sentinel.js +58 -19
- package/package.json +11 -6
- package/scripts/benchmark-compact-content-variants.cjs +298 -0
- package/scripts/benchmark-compact-content.cjs +368 -0
- package/scripts/build-hooks.js +15 -6
- package/scripts/check-contract-drift.cjs +131 -12
- package/scripts/check-env.cjs +36 -8
- package/scripts/check-glossary-refs.cjs +25 -21
- package/scripts/ci-next-health.cjs +271 -0
- package/scripts/ci-prepare-test-scope.cjs +7 -7
- package/scripts/ci-test-scope.cjs +126 -20
- package/scripts/ci-timeout-report.cjs +1 -1
- package/scripts/command-contract-helpers.cjs +3 -0
- package/scripts/diff-touches-shipped-paths.cjs +1 -1
- package/scripts/docs-guard-registry.cjs +35 -2
- package/scripts/gen-adr-index.cjs +8 -2
- package/scripts/gen-inventory-manifest.cjs +12 -0
- package/scripts/gen-loop-host-contract.cjs +69 -0
- package/scripts/gen-platform-conformance-tier.cjs +557 -0
- package/scripts/lib/drift-scan.cjs +1 -1
- package/scripts/lib/macos-conformance-tier.generated.cjs +224 -0
- package/scripts/lib/ndjson-reporter.cjs +3 -2
- package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
- package/scripts/lib/platform-conformance-tier.generated.cjs +287 -0
- package/scripts/lib/suite-detection.cjs +32 -0
- package/scripts/lint-allowed-tools-parity.cjs +221 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +47 -3
- package/scripts/lint-phase-arg-assignment.cjs +257 -0
- package/scripts/lint-phase-id-drift.cjs +623 -13
- package/scripts/lint-pr-branch-pattern-drift.cjs +148 -0
- package/scripts/lint-response-language-coverage.cjs +9 -3
- package/scripts/lint-retired-runtime-name.cjs +619 -0
- package/scripts/lint-source-test-name-collision.cjs +1 -1
- package/scripts/lint-state-write-path-drift.cjs +93 -0
- package/scripts/lint-test-file-count.allowlist.json +29 -9
- package/scripts/lint-vendored-deps.cjs +128 -17
- package/scripts/lint-workflow-shellcheck-baseline.json +100 -0
- package/scripts/prompt-injection-scan.sh +18 -0
- package/scripts/release-tarball-smoke.cjs +194 -1
- package/scripts/workflow-size.cjs +139 -0
- package/skills/gsd-autonomous/SKILL.md +2 -2
- package/skills/gsd-capture/SKILL.md +1 -1
- package/skills/gsd-cleanup/SKILL.md +1 -0
- package/skills/gsd-code-review/SKILL.md +2 -1
- package/skills/gsd-complete-milestone/SKILL.md +1 -0
- package/skills/gsd-config/SKILL.md +1 -0
- package/skills/gsd-debug/SKILL.md +1 -0
- package/skills/gsd-graphify/SKILL.md +1 -0
- package/skills/gsd-health/SKILL.md +1 -0
- package/skills/gsd-mempalace-capture/SKILL.md +8 -3
- package/skills/gsd-mempalace-recall/SKILL.md +1 -0
- package/skills/gsd-new-milestone/SKILL.md +1 -0
- package/skills/gsd-new-project/SKILL.md +1 -0
- package/skills/gsd-next/SKILL.md +1 -0
- package/skills/gsd-pause-work/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +1 -0
- package/skills/gsd-plan-review-convergence/SKILL.md +5 -5
- package/skills/gsd-pr-branch/SKILL.md +1 -0
- package/skills/gsd-progress/SKILL.md +1 -1
- package/skills/gsd-quick-batch/SKILL.md +1 -1
- package/skills/gsd-resume-work/SKILL.md +1 -0
- package/skills/gsd-review/SKILL.md +2 -3
- package/skills/gsd-review-backlog/SKILL.md +1 -0
- package/skills/gsd-settings/SKILL.md +2 -1
- package/skills/gsd-stats/SKILL.md +1 -0
- package/skills/gsd-thread/SKILL.md +1 -0
- package/skills/gsd-workspace/SKILL.md +1 -0
- package/skills/gsd-workstreams/SKILL.md +1 -0
- package/vscode/package.json +1 -1
- package/gsd-core/templates/claude-md.md +0 -145
- package/gsd-core/templates/codebase/concerns.md +0 -310
- package/gsd-core/templates/codebase/conventions.md +0 -307
- package/gsd-core/templates/codebase/integrations.md +0 -280
- package/gsd-core/templates/codebase/structure.md +0 -285
- package/gsd-core/templates/codebase/testing.md +0 -480
- package/gsd-core/templates/debug-subagent-prompt.md +0 -91
- package/gsd-core/templates/discovery.md +0 -146
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* truth). Behaviour is preserved byte-for-behaviour from the prior hand-written
|
|
6
6
|
* .cjs; only types are added.
|
|
7
7
|
*
|
|
8
|
-
* Accepts
|
|
8
|
+
* Accepts numeric (D-42), alphanumeric (D-INFRA-01), and phase-prefixed
|
|
9
|
+
* (D4-01 — an optional digit-run between the leading letter and the hyphen,
|
|
10
|
+
* #4130) IDs.
|
|
9
11
|
* Returns {id, text, category, tags, trackable} per decision.
|
|
10
12
|
* CJS callers that only use {id, text} safely ignore the extra fields.
|
|
11
13
|
*
|
|
@@ -16,6 +18,11 @@
|
|
|
16
18
|
* - Outer bullet loop → seam's `iterateBullets` (for the header-fallback path)
|
|
17
19
|
*
|
|
18
20
|
* Resolves #1364 (markdown-header + em-dash recall) and #1365 (fail-loud gate).
|
|
21
|
+
*
|
|
22
|
+
* #4130 follow-up (hardening): the three bullet grammars below consume the
|
|
23
|
+
* decision ID atomically and narrow the em-dash first separator, eliminating
|
|
24
|
+
* the quadratic-backtracking cliff on pathological single bullets. Output is
|
|
25
|
+
* byte-identical on all legal inputs — see the notes at DECISION_ID_SOURCE.
|
|
19
26
|
*/
|
|
20
27
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
28
|
exports.extractDecisions = extractDecisions;
|
|
@@ -30,39 +37,130 @@ const DISCRETION_HEADINGS = new Set([
|
|
|
30
37
|
const NON_TRACKABLE_TAGS = new Set(['informational', 'folded', 'deferred']);
|
|
31
38
|
// ─── Bullet parsers (decisions-specific grammar) ─────────────────────────────
|
|
32
39
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
40
|
+
* #4130: the ID grammar every extractor regex below shares, as ONE source.
|
|
41
|
+
* `D`, an OPTIONAL digit-run phase prefix, a hyphen, then the pre-existing
|
|
42
|
+
* alphanumeric tail — so `D-01` (bare), `D4-01`/`D12-01` (phase-prefixed,
|
|
43
|
+
* the reporter's multi-phase convention where bare D-01 collides across
|
|
44
|
+
* phases), and `D-INFRA-01` (alnum tail) are all the same grammar now.
|
|
45
|
+
* #2347 had already taught the shape DETECTOR to call `D4-01` decision-shaped
|
|
46
|
+
* while the EXTRACTOR still anchored on the literal `**D-` — the disagreement
|
|
47
|
+
* that made a whole phase-prefixed CONTEXT.md report could-not-parse. Deriving
|
|
48
|
+
* the three grammars (and the token evidence below) from this one constant is
|
|
49
|
+
* the parity pin: the extractor's ID universe cannot drift from the declared
|
|
50
|
+
* grammar again without editing this line, which the #4130 property tests
|
|
51
|
+
* watch from the other side.
|
|
52
|
+
*/
|
|
53
|
+
const DECISION_ID_SOURCE = 'D[0-9]*-[A-Za-z0-9][A-Za-z0-9_-]*';
|
|
54
|
+
/**
|
|
55
|
+
* #4130 follow-up (hardening): how the three grammars below CONSUME the ID —
|
|
56
|
+
* atomically, via the `(?=(X))\1` lookahead emulation (lookarounds are atomic
|
|
57
|
+
* in ECMAScript; the backreference must replay exactly what the lookahead
|
|
58
|
+
* captured, so the engine can never give the ID tail back one character at a
|
|
59
|
+
* time). That give-back was quadratic driver #1: the tail class
|
|
60
|
+
* `[A-Za-z0-9_-]*` overlaps the pre-separator class `[^:*]*` (every id char
|
|
61
|
+
* is also `[^:*]`), so on a FAILING bullet the base regex re-split the tail
|
|
62
|
+
* O(n) times with an O(n) scan after each — measured ~1.1s @ 40k chars on
|
|
63
|
+
* `- **D-` + `a-`×20k (the #4357 review's deferred cliff).
|
|
64
|
+
*
|
|
65
|
+
* Byte-identical on all legal inputs: a successful match always consumes the
|
|
66
|
+
* MAXIMAL id run (the lookahead's own match is exactly that maximal run), and
|
|
67
|
+
* the continuation's success depends only on the position of the first
|
|
68
|
+
* `:`/`*` (or `*` for the em-dash form) after the id boundary — id chars
|
|
69
|
+
* contain neither, so moving the boundary inside the run cannot change
|
|
70
|
+
* success or any capture. Group 1 stays the full id (the lookahead's capture
|
|
71
|
+
* IS group 1), so handlers keep reading match[1]/[2]/[3] untouched. Pinned by
|
|
72
|
+
* the differential property test against a frozen copy of the pre-hardening
|
|
73
|
+
* grammars and by the regex-lattice test in tests/decisions.test.cjs.
|
|
74
|
+
*/
|
|
75
|
+
/**
|
|
76
|
+
* #4130: the bold lead-in that ATTEMPTS the ID grammar above — used by the
|
|
77
|
+
* parse-miss guard and the #3939 join regexes, where recognising MORE shapes
|
|
78
|
+
* is the conservative direction (an over-broad match can only make a
|
|
79
|
+
* malformed bullet fail loud). The prefix run is either empty (bare `D-`) or
|
|
80
|
+
* DIGIT-INITIAL (`4`, `4x` — a phase prefix with a typo still counts as an
|
|
81
|
+
* attempted ID, so `D4x-01` reaches the guard and fails loud instead of
|
|
82
|
+
* vanishing), but never letter-initial: `D` + letters + `-` (`Deferred-until`)
|
|
83
|
+
* is a prose word, and prose must stay `none-present` (#2347's law).
|
|
84
|
+
*/
|
|
85
|
+
const ID_ATTEMPT_SOURCE = 'D(?:[0-9][A-Za-z0-9]*)?-';
|
|
86
|
+
/**
|
|
87
|
+
* Colon form: `- **D[phase]-NN[ [tags]]:** text`
|
|
88
|
+
* (#1343: the pre-colon run subsumes any pre-colon prose, stops at `:**`; #4788: the run is code-span-aware — a backticked span is consumed whole, so a `:` or `*` INSIDE it is data, never grammar)
|
|
89
|
+
* Group 1 captures the FULL id including any phase prefix (#4130).
|
|
90
|
+
* The ID is consumed atomically `(?=(…))\1` — see the hardening note above
|
|
91
|
+
* the constants (#4130 follow-up); with the tail unable to give back, the
|
|
92
|
+
* remaining `[^:*]*:` scan has a single viable split and the whole match is
|
|
93
|
+
* linear in line length.
|
|
35
94
|
*/
|
|
36
|
-
const bulletColonRe =
|
|
95
|
+
const bulletColonRe = new RegExp(`^\\s*-\\s+\\*\\*(?=(${DECISION_ID_SOURCE}))\\1(?:\\s*\\[([^\\]]+)\\])?(?:\\u0060[^\\u0060]*\\u0060|[^:*\\u0060])*:\\*\\*\\s*(.*)$`);
|
|
37
96
|
/**
|
|
38
|
-
* Em-dash form: `- **D-NN[ [tags]] — title** body`
|
|
97
|
+
* Em-dash form: `- **D[phase]-NN[ [tags]] — title** body`
|
|
39
98
|
* The em-dash (U+2014) or its lookalike separates the ID+tags group from a title
|
|
40
99
|
* that lives inside the bold markers; the body (which may be empty) follows
|
|
41
100
|
* outside the closing `**`. This form was not handled pre-T1 (bug #1364).
|
|
42
101
|
*
|
|
43
102
|
* Accepts both U+2014 em-dash (—) and U+2013 en-dash (–) for robustness.
|
|
103
|
+
*
|
|
104
|
+
* #4130 follow-up (hardening), quadratic driver #2: the first separator was
|
|
105
|
+
* `[^*]*[—–]`, whose leading class ALSO accepts the dash — on a failing
|
|
106
|
+
* dash-laden title the engine retried the separator at every dash position
|
|
107
|
+
* with an O(n) scan after each (~1.7s @ 40k). Narrowed to `[^*—–]*[—–]`:
|
|
108
|
+
* the leading class now excludes the dash, so the separator is the FIRST
|
|
109
|
+
* dash — one viable split, single pass. Behavior-preserving because every
|
|
110
|
+
* candidate dash lies before the first `*` (the leading class cannot cross
|
|
111
|
+
* a star), so the trailing `[^*]*` reaches that same first star from any
|
|
112
|
+
* candidate and `**` succeeds or fails identically; no capture involves the
|
|
113
|
+
* dash position. The ID is atomic like the other forms (driver #1).
|
|
44
114
|
*/
|
|
45
|
-
const bulletEmDashRe =
|
|
115
|
+
const bulletEmDashRe = new RegExp(`^\\s*-\\s+\\*\\*(?=(${DECISION_ID_SOURCE}))\\1(?:\\s*\\[([^\\]]+)\\])?(?:\\u0060[^\\u0060]*\\u0060|[^*—–\\u0060])*[—–](?:\\u0060[^\\u0060]*\\u0060|[^*\\u0060])*\\*\\*\\s*(.*)$`);
|
|
46
116
|
/**
|
|
47
|
-
* Titled-colon form: `- **D-NN[ [tags]]: Title.** body`
|
|
117
|
+
* Titled-colon form: `- **D[phase]-NN[ [tags]]: Title.** body`
|
|
48
118
|
* A title sits between the colon and the closing `**` (so the `:**` anchor of
|
|
49
119
|
* bulletColonRe fails, and there is no em-dash for bulletEmDashRe). This is a strict
|
|
50
120
|
* superset of the colon-immediate form, so it MUST be checked AFTER bulletColonRe and
|
|
51
|
-
* bulletEmDashRe — it only catches bullets those two miss. The title
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
121
|
+
* bulletEmDashRe — it only catches bullets those two miss. The title runs are code-span-aware
|
|
122
|
+
* (#4788) but still exclude `*`, so a genuinely-malformed bullet with no bare colon at all
|
|
123
|
+
* before `**` still fails the anchor and falls through to the parse-miss guard — the #1639
|
|
124
|
+
* fail-loud discipline: the separator must be a BARE colon before `**`. A code span's
|
|
125
|
+
* `:`/`*` is data, never grammar; an UNTERMINATED backtick now fails loud (previously it was
|
|
126
|
+
* an ordinary character) — the deliberate cost of span opacity.
|
|
127
|
+
*
|
|
128
|
+
* #4793/#4958: the pre-separator run tolerates a bare colon as prose ONLY when it is
|
|
129
|
+
* immediately followed by whitespace (`:(?=\s)`), e.g. a natural sentence colon in
|
|
130
|
+
* `D-02: Two managers … same pair: the second is rejected.`. A colon with no following
|
|
131
|
+
* whitespace (a compact/ratio-style colon like `3:1`) is never consumed by this branch, so
|
|
132
|
+
* it still hard-caps the pre-separator run and the #1639/#4130/#1343 negative-space fixtures
|
|
133
|
+
* (e.g. `D-07 ratio 3:1:**`) still fail loud. The post-separator branch is unchanged and
|
|
134
|
+
* still excludes colons, so normal greedy backtracking selects the LAST valid split (a bare
|
|
135
|
+
* colon followed by whitespace, or the anchor colon itself) before the closing `**`.
|
|
136
|
+
*
|
|
137
|
+
* The ID is consumed atomically `(?=(…))\1` like the other forms — the
|
|
138
|
+
* hardening note above the constants explains why (#4130 follow-up).
|
|
139
|
+
*/
|
|
140
|
+
const bulletTitledColonRe = new RegExp(`^\\s*-\\s+\\*\\*(?=(${DECISION_ID_SOURCE}))\\1(?:\\s*\\[([^\\]]+)\\])?(?:\\u0060[^\\u0060]*\\u0060|:(?=\\s)|[^:*\\u0060])*:(?:\\u0060[^\\u0060]*\\u0060|[^:*\\u0060])*\\*\\*\\s*(.*)$`);
|
|
141
|
+
/**
|
|
142
|
+
* #4130: the parse-miss guard's probe — a line whose bold lead-in ATTEMPTS the
|
|
143
|
+
* ID grammar (see `ID_ATTEMPT_SOURCE`) but failed all three bullet patterns
|
|
144
|
+
* above. Bare `D-` attempts behave exactly as before #4130; a digit-initial
|
|
145
|
+
* prefix run (`D4-`… including a typo'd `D4x-`) is new evidence of an attempt,
|
|
146
|
+
* so the malformed-prefixed bullet fails loud instead of silently vanishing.
|
|
147
|
+
*/
|
|
148
|
+
const parseMissGuardRe = new RegExp(`^\\s*-\\s+\\*\\*${ID_ATTEMPT_SOURCE}`);
|
|
149
|
+
/**
|
|
150
|
+
* #4130: bare-token evidence of decision-shaped content — a `D…-<alnum>` token
|
|
151
|
+
* in running text. `D-01` matched before; the digit-run phase prefix (`D4-01`)
|
|
152
|
+
* is added so token evidence agrees with the extractor's ID grammar
|
|
153
|
+
* (DECISION_ID_SOURCE) instead of silently ignoring prefixed mentions.
|
|
56
154
|
*/
|
|
57
|
-
const
|
|
155
|
+
const decisionTokenRe = new RegExp(`\\bD[0-9]*-[A-Za-z0-9]`, 'm');
|
|
58
156
|
/**
|
|
59
157
|
* #2347: format-agnostic evidence that a block/section holds real decision
|
|
60
158
|
* ENTRIES the parser could not read — a bullet whose bold lead-in is an
|
|
61
159
|
* ID-SHAPED token (uppercase prefix, optional digits, hyphen, alnum), whatever
|
|
62
|
-
* the exact ID grammar.
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
160
|
+
* the exact ID grammar. #1365's fail-loud guard originally reused the parser's
|
|
161
|
+
* own `\bD-` test as its "is this decision-shaped?" evidence, so any prefix the
|
|
162
|
+
* parser could not read (e.g. `D5-01` then, `DEC-01` now) was invisible to
|
|
163
|
+
* BOTH parser and guard, collapsing `could-not-parse` into a clean
|
|
66
164
|
* `none-present` pass.
|
|
67
165
|
*
|
|
68
166
|
* The ID-shape requirement (not "any bold bullet") is deliberate: a decisions
|
|
@@ -70,25 +168,35 @@ const bulletTitledColonRe = /^\s*-\s+\*\*D-([A-Za-z0-9][A-Za-z0-9_-]*)(?:\s*\[([
|
|
|
70
168
|
* bullets with bold labels (`- **Scope:** …`, `- **Why:** …`, `- **Note:** …`).
|
|
71
169
|
* Those are NOT decision entries and must stay `none-present` — a false
|
|
72
170
|
* `could-not-parse` hard-blocks the plan gate. `[A-Z]+[0-9]*-[A-Za-z0-9]` matches
|
|
73
|
-
* `D-01` / `
|
|
171
|
+
* `D-01` / `D4-01` / `DEC-01` but not `Scope:` / `Why:` / `Follow-up:` (mixed
|
|
74
172
|
* case) / `TODO:` (no `-<alnum>` id) — mirroring the parser's own `D-<alnum>`
|
|
75
173
|
* shape without hardcoding the `D`.
|
|
174
|
+
*
|
|
175
|
+
* #4130 parity note: for the D-prefixed universe this detector's grammar
|
|
176
|
+
* (`D` + digit-run + `-` + alnum) is exactly `DECISION_ID_SOURCE` above, so a
|
|
177
|
+
* well-formed bullet the detector calls decision-shaped is now always one the
|
|
178
|
+
* extractor can read. The detector stays WIDER on purpose (`DEC-01` is still
|
|
179
|
+
* evidence): an ID grammar outside the parser's universe must keep failing
|
|
180
|
+
* loud, never silently passing. The #4130 property tests pin both directions.
|
|
76
181
|
*/
|
|
77
182
|
const boldLeadInBulletRe = /^\s*-\s+\*\*[A-Z]+[0-9]*-[A-Za-z0-9]/m;
|
|
78
183
|
/**
|
|
79
|
-
* #3939: a decision bullet's DECLARATION line — the `- **D-NN … **` bold
|
|
80
|
-
* the three grammars above anchor on — may wrap across a line break.
|
|
81
|
-
* line breaks inside a bullet are markdown-insignificant, and GSD's own
|
|
184
|
+
* #3939: a decision bullet's DECLARATION line — the `- **D[phase]-NN … **` bold
|
|
185
|
+
* lead-in the three grammars above anchor on — may wrap across a line break.
|
|
186
|
+
* Physical line breaks inside a bullet are markdown-insignificant, and GSD's own
|
|
82
187
|
* discuss-phase writer emits the wrapped shape whenever a decision title runs
|
|
83
188
|
* past the wrap column. All three grammars require the closing `**` in the same
|
|
84
|
-
* string as the `- **D
|
|
189
|
+
* string as the `- **D…-` anchor, so a wrapped declaration matched none of them
|
|
85
190
|
* and fell to the #1365 parse-miss guard, forcing `could-not-parse` (which
|
|
86
191
|
* hard-blocks `check.decision-coverage-plan`) on a well-formed CONTEXT.md.
|
|
87
192
|
*
|
|
88
193
|
* The repair is confined to how the LOGICAL bullet is assembled — the grammars
|
|
89
194
|
* themselves are untouched, so every single-line form parses exactly as before.
|
|
195
|
+
* #4130: the anchor uses `ID_ATTEMPT_SOURCE` (digit-run phase prefixes join
|
|
196
|
+
* like bare ones; recognising more start shapes only reassembles the logical
|
|
197
|
+
* bullet, which then parses or fails loud as itself).
|
|
90
198
|
*/
|
|
91
|
-
const decisionBulletStartRe =
|
|
199
|
+
const decisionBulletStartRe = new RegExp(`^\\s*-\\s+\\*\\*${ID_ATTEMPT_SOURCE}`);
|
|
92
200
|
/**
|
|
93
201
|
* A line that opens a new BLOCK-LEVEL construct, and therefore terminates the
|
|
94
202
|
* bullet above it: a list marker of any family (`-`, `*`, `+`, `1.`, `1)`), an
|
|
@@ -136,7 +244,8 @@ const blockConstructRe = /^(?:[-*+]\s|\d+[.)]\s|#{1,6}\s|>\s|\|)/;
|
|
|
136
244
|
* to watch for a splice.
|
|
137
245
|
*
|
|
138
246
|
* The id character class is deliberately looser than the grammars' (it admits
|
|
139
|
-
* an empty id, so a bare `- **D-` still counts as unsettled
|
|
247
|
+
* an empty id, so a bare `- **D-` still counts as unsettled, and — #4130 — a
|
|
248
|
+
* digit-run phase prefix between the `D` and the first hyphen). This regex only
|
|
140
249
|
* answers "may an id-adjacent bracket still open here?", where recognising MORE
|
|
141
250
|
* shapes is the conservative direction: an over-broad match can only make a
|
|
142
251
|
* malformed bullet fail loud, while a missed one silently re-classifies.
|
|
@@ -145,7 +254,7 @@ const blockConstructRe = /^(?:[-*+]\s|\d+[.)]\s|#{1,6}\s|>\s|\|)/;
|
|
|
145
254
|
* into `tags` (and therefore into `trackable`). A `[` further along the title is
|
|
146
255
|
* ordinary text and does not restrict the join.
|
|
147
256
|
*/
|
|
148
|
-
const tagRegionRe =
|
|
257
|
+
const tagRegionRe = new RegExp(`^\\s*-\\s+\\*\\*D[0-9]*-[A-Za-z0-9_-]*\\s*(?:\\[([^\\]]*))?$`);
|
|
149
258
|
/**
|
|
150
259
|
* #3939 (review): would folding `next` onto a lead-in whose `[tags]` bracket is
|
|
151
260
|
* still open splice the inserted space INTO a tag token?
|
|
@@ -304,6 +413,7 @@ function parseDecisionLines(block) {
|
|
|
304
413
|
let current = null;
|
|
305
414
|
let openIndent = null;
|
|
306
415
|
let parseMisses = 0;
|
|
416
|
+
const unreadableIds = [];
|
|
307
417
|
const flush = () => {
|
|
308
418
|
if (current) {
|
|
309
419
|
current.text = current.text.trim();
|
|
@@ -347,11 +457,11 @@ function parseDecisionLines(block) {
|
|
|
347
457
|
current.text += ' ' + trimmed;
|
|
348
458
|
continue;
|
|
349
459
|
}
|
|
350
|
-
// Colon form: `- **D-NN[ [tags]]:** text`
|
|
460
|
+
// Colon form: `- **D[phase]-NN[ [tags]]:** text`
|
|
351
461
|
const colonMatch = line.match(bulletColonRe);
|
|
352
462
|
if (colonMatch) {
|
|
353
463
|
flush();
|
|
354
|
-
const id =
|
|
464
|
+
const id = colonMatch[1];
|
|
355
465
|
const tags = colonMatch[2]
|
|
356
466
|
? colonMatch[2].split(',').map((t) => t.trim().toLowerCase()).filter(Boolean)
|
|
357
467
|
: [];
|
|
@@ -360,11 +470,11 @@ function parseDecisionLines(block) {
|
|
|
360
470
|
openIndent = (0, token_scanner_cjs_1.indentWidth)(line);
|
|
361
471
|
continue;
|
|
362
472
|
}
|
|
363
|
-
// Em-dash form: `- **D-NN[ [tags]] — title** body`
|
|
473
|
+
// Em-dash form: `- **D[phase]-NN[ [tags]] — title** body`
|
|
364
474
|
const emDashMatch = line.match(bulletEmDashRe);
|
|
365
475
|
if (emDashMatch) {
|
|
366
476
|
flush();
|
|
367
|
-
const id =
|
|
477
|
+
const id = emDashMatch[1];
|
|
368
478
|
const tags = emDashMatch[2]
|
|
369
479
|
? emDashMatch[2].split(',').map((t) => t.trim().toLowerCase()).filter(Boolean)
|
|
370
480
|
: [];
|
|
@@ -376,14 +486,14 @@ function parseDecisionLines(block) {
|
|
|
376
486
|
openIndent = (0, token_scanner_cjs_1.indentWidth)(line);
|
|
377
487
|
continue;
|
|
378
488
|
}
|
|
379
|
-
// Titled-colon form: `- **D-NN[ [tags]]: Title.** body` (#1639). Checked LAST — it is
|
|
489
|
+
// Titled-colon form: `- **D[phase]-NN[ [tags]]: Title.** body` (#1639). Checked LAST — it is
|
|
380
490
|
// a strict superset of bulletColonRe, so it only catches bullets the colon-immediate
|
|
381
491
|
// and em-dash forms missed (minimal blast radius). id + [tags] trackability honored;
|
|
382
492
|
// the body after the closing bold run is reported as text.
|
|
383
493
|
const titledColonMatch = line.match(bulletTitledColonRe);
|
|
384
494
|
if (titledColonMatch) {
|
|
385
495
|
flush();
|
|
386
|
-
const id =
|
|
496
|
+
const id = titledColonMatch[1];
|
|
387
497
|
const tags = titledColonMatch[2]
|
|
388
498
|
? titledColonMatch[2].split(',').map((t) => t.trim().toLowerCase()).filter(Boolean)
|
|
389
499
|
: [];
|
|
@@ -392,12 +502,21 @@ function parseDecisionLines(block) {
|
|
|
392
502
|
openIndent = (0, token_scanner_cjs_1.indentWidth)(line);
|
|
393
503
|
continue;
|
|
394
504
|
}
|
|
395
|
-
// Parse-miss guard (FIX B + #1343): a line
|
|
396
|
-
//
|
|
505
|
+
// Parse-miss guard (FIX B + #1343, grammar widened #4130): a line whose bold
|
|
506
|
+
// lead-in ATTEMPTS the ID grammar but failed all three patterns — flush,
|
|
507
|
+
// warn, and record the miss. `ID_ATTEMPT_SOURCE` accepts the bare `D-` form
|
|
508
|
+
// (as before) plus a digit-initial prefix run, so a typo'd phase prefix
|
|
509
|
+
// (`D4x-01`) fails loud instead of silently vanishing, while a letter-initial
|
|
510
|
+
// run (`Deferred-until`) stays prose and stays invisible.
|
|
397
511
|
// parseMisses > 0 forces could-not-parse even when other decisions parsed.
|
|
398
|
-
if (
|
|
512
|
+
if (parseMissGuardRe.test(line)) {
|
|
399
513
|
flush();
|
|
400
514
|
parseMisses += 1;
|
|
515
|
+
// #4794: carry the attempted id so a caller capturing stdout (a JSON gate)
|
|
516
|
+
// can name the decision to fix — today it exists only in this stderr warn.
|
|
517
|
+
const attempted = line.match(/\*\*\s*(D(?:[0-9][A-Za-z0-9]*)?-[A-Za-z0-9_-]*)/);
|
|
518
|
+
if (attempted && !unreadableIds.includes(attempted[1]))
|
|
519
|
+
unreadableIds.push(attempted[1]);
|
|
401
520
|
console.warn(`parseDecisions: ignored unparseable decision bullet: ${trimmed}`);
|
|
402
521
|
continue;
|
|
403
522
|
}
|
|
@@ -413,7 +532,7 @@ function parseDecisionLines(block) {
|
|
|
413
532
|
}
|
|
414
533
|
}
|
|
415
534
|
flush();
|
|
416
|
-
return { decisions: out, parseMisses };
|
|
535
|
+
return { decisions: out, parseMisses, unreadableIds };
|
|
417
536
|
}
|
|
418
537
|
// ─── Primary entry point: extractDecisions ────────────────────────────────────
|
|
419
538
|
/**
|
|
@@ -438,21 +557,21 @@ function extractDecisions(content) {
|
|
|
438
557
|
const taggedBlocks = (0, markdown_sectionizer_cjs_1.extractTaggedBlocks)(stripped, 'decisions');
|
|
439
558
|
if (taggedBlocks.length > 0) {
|
|
440
559
|
const combined = taggedBlocks.join('\n\n');
|
|
441
|
-
const { decisions, parseMisses } = parseDecisionLines(combined);
|
|
560
|
+
const { decisions, parseMisses, unreadableIds } = parseDecisionLines(combined);
|
|
442
561
|
if (decisions.length > 0 && parseMisses === 0) {
|
|
443
562
|
return { decisions, outcome: 'parsed' };
|
|
444
563
|
}
|
|
445
564
|
// FIX B: parse-misses present — could-not-parse even if some decisions extracted.
|
|
446
565
|
if (parseMisses > 0) {
|
|
447
|
-
return { decisions, outcome: 'could-not-parse' };
|
|
566
|
+
return { decisions, outcome: 'could-not-parse', unreadableIds };
|
|
448
567
|
}
|
|
449
568
|
// FIX A: Block present but 0 extracted and no parse-misses.
|
|
450
569
|
// Only report could-not-parse when there is genuine evidence of real decisions
|
|
451
570
|
// that failed to parse: a bold-lead-in bullet (`- **…**`, any ID grammar — #2347),
|
|
452
|
-
// a
|
|
571
|
+
// a bare `D[phase]-<alnum>` token (#4130) in the block text, or an unterminated fence. An empty scaffold
|
|
453
572
|
// (<decisions></decisions>) or an all-prose block has no such evidence — treat
|
|
454
573
|
// as none-present so the gate passes cleanly.
|
|
455
|
-
const hasDecisionTokenInBlock =
|
|
574
|
+
const hasDecisionTokenInBlock = decisionTokenRe.test(combined);
|
|
456
575
|
const hasBoldLeadInBullet = boldLeadInBulletRe.test(combined);
|
|
457
576
|
if (hasDecisionTokenInBlock || hasBoldLeadInBullet || unterminatedFence) {
|
|
458
577
|
return { decisions: [], outcome: 'could-not-parse' };
|
|
@@ -465,20 +584,20 @@ function extractDecisions(content) {
|
|
|
465
584
|
// stripFences:true → inner fences inside the section body are stripped.
|
|
466
585
|
const section = (0, markdown_sectionizer_cjs_1.collectSection)(content, (h) => /decisions?\b/i.test(h.text), { levelBounded: true, stripFences: true });
|
|
467
586
|
if (section !== null) {
|
|
468
|
-
const { decisions, parseMisses } = parseDecisionLines(section.body);
|
|
587
|
+
const { decisions, parseMisses, unreadableIds } = parseDecisionLines(section.body);
|
|
469
588
|
if (decisions.length > 0 && parseMisses === 0) {
|
|
470
589
|
return { decisions, outcome: 'parsed' };
|
|
471
590
|
}
|
|
472
591
|
// FIX B: parse-misses present — could-not-parse even if some decisions extracted.
|
|
473
592
|
if (parseMisses > 0) {
|
|
474
|
-
return { decisions, outcome: 'could-not-parse' };
|
|
593
|
+
return { decisions, outcome: 'could-not-parse', unreadableIds };
|
|
475
594
|
}
|
|
476
595
|
// FIX A: Heading found but 0 extracted and no parse-misses.
|
|
477
596
|
// Report could-not-parse when the section body holds a decision-entry-shaped
|
|
478
|
-
// bold-lead-in bullet (`- **…**`, any ID grammar — #2347) or a D
|
|
597
|
+
// bold-lead-in bullet (`- **…**`, any ID grammar — #2347) or a `D[phase]-<alnum>` token (#4130). A
|
|
479
598
|
// heading with only prose, sub-headings, or all-discretion content (no such
|
|
480
599
|
// evidence) is a legitimate empty/discretion section → none-present.
|
|
481
|
-
const hasDecisionTokenInSection =
|
|
600
|
+
const hasDecisionTokenInSection = decisionTokenRe.test(section.body);
|
|
482
601
|
const hasBoldLeadInBulletInSection = boldLeadInBulletRe.test(section.body);
|
|
483
602
|
if (hasDecisionTokenInSection || hasBoldLeadInBulletInSection) {
|
|
484
603
|
return { decisions: [], outcome: 'could-not-parse' };
|
|
@@ -487,8 +606,8 @@ function extractDecisions(content) {
|
|
|
487
606
|
}
|
|
488
607
|
// ── Path 3: no blocks, no heading ────────────────────────────────────────────
|
|
489
608
|
// Apply shape heuristics to distinguish none-present from could-not-parse.
|
|
490
|
-
// We re-use the already-computed unterminatedFence and check for
|
|
491
|
-
const hasDecisionToken =
|
|
609
|
+
// We re-use the already-computed unterminatedFence and check for decision tokens.
|
|
610
|
+
const hasDecisionToken = decisionTokenRe.test(stripped);
|
|
492
611
|
if (unterminatedFence || hasDecisionToken) {
|
|
493
612
|
return { decisions: [], outcome: 'could-not-parse' };
|
|
494
613
|
}
|
|
@@ -18,13 +18,10 @@
|
|
|
18
18
|
* concern sharing the word "trust".
|
|
19
19
|
*/
|
|
20
20
|
'use strict';
|
|
21
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
22
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
|
-
};
|
|
24
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
22
|
exports.isPathConfined = isPathConfined;
|
|
26
23
|
exports.assertDescriptorConfined = assertDescriptorConfined;
|
|
27
|
-
const
|
|
24
|
+
const security_cjs_1 = require("./security.cjs");
|
|
28
25
|
/**
|
|
29
26
|
* Pure LEXICAL path-containment check (cross-platform). `target` is confined
|
|
30
27
|
* to `root` iff resolving it relative to `root` (via `path.resolve` — string
|
|
@@ -36,20 +33,38 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
36
33
|
* `root`) that would redirect the LEXICALLY-confined path to a physically
|
|
37
34
|
* different, unconfined location on disk. A caller relying on this for a
|
|
38
35
|
* write-confinement guarantee against a symlink-planting attacker must pair
|
|
39
|
-
* it with a symlink check (or refuse to follow symlinks at write time)
|
|
40
|
-
* capability-
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
36
|
+
* it with a symlink check (or refuse to follow symlinks at write time). Only
|
|
37
|
+
* the capability-loader.cts route into assertDescriptorConfined gets this for
|
|
38
|
+
* free today: capability-source.cts's staging path rejects symlinks upstream,
|
|
39
|
+
* before a target ever reaches a lexical-only check like this one — see
|
|
40
|
+
* copyDirRecursive's `entry.isSymbolicLink()` throw (capability-source.cts:585-586)
|
|
41
|
+
* and the post-copy budget-walk re-check (capability-source.cts:671-674). This
|
|
42
|
+
* does NOT extend to isPathConfined's other callers: install-engine.cts:1608
|
|
43
|
+
* and install-profiles.cts:755,880 do not go through capability-source.cts's
|
|
44
|
+
* adapters at all and have no symlink guard of their own here. Of the
|
|
45
|
+
* remaining callers, only retired-artifact-cleanup.cts:69 carries its own
|
|
46
|
+
* defense, via a local `lstatSync(destDir).isSymbolicLink()` check at line 77.
|
|
47
|
+
*
|
|
48
|
+
* `opts.pathImpl` (default: the ambient `path` module) lets a caller inject
|
|
49
|
+
* `path.win32` or `path.posix`. This is security-relevant: the win32 branch
|
|
50
|
+
* (drive letters, UNC paths, `\` separator) is otherwise only reachable by
|
|
51
|
+
* actually running this process on a Windows host, so without injection a
|
|
52
|
+
* win32-specific confinement escape would be unverified on every other
|
|
53
|
+
* platform. This mirrors the platform-injection seam already used elsewhere
|
|
54
|
+
* in this repo, e.g. src/shell-command-projection.cts's `opts.platform`
|
|
55
|
+
* (#4641). All existing 2-arg callers are unaffected: the default resolves to
|
|
56
|
+
* the ambient `path`, preserving byte-identical behaviour.
|
|
57
|
+
*
|
|
58
|
+
* The containment DECISION here now comes from the canonical predicate in
|
|
59
|
+
* src/security.cts (`tryWithinRootLexical`, ADR-4650 decision 6) — this
|
|
60
|
+
* function keeps only the lexical RESOLUTION policy (no realpath, no
|
|
61
|
+
* filesystem access) as its own choice; the comparison itself is shared.
|
|
44
62
|
*/
|
|
45
|
-
function isPathConfined(target, root) {
|
|
63
|
+
function isPathConfined(target, root, opts = {}) {
|
|
46
64
|
if (typeof target !== 'string' || typeof root !== 'string' || target.length === 0 || root.length === 0) {
|
|
47
65
|
return false;
|
|
48
66
|
}
|
|
49
|
-
|
|
50
|
-
const targetResolved = node_path_1.default.resolve(root, target);
|
|
51
|
-
const prefix = rootResolved + node_path_1.default.sep;
|
|
52
|
-
return targetResolved === rootResolved || targetResolved.startsWith(prefix);
|
|
67
|
+
return (0, security_cjs_1.tryWithinRootLexical)(target, root, { pathImpl: opts.pathImpl }) !== null;
|
|
53
68
|
}
|
|
54
69
|
/**
|
|
55
70
|
* Assert every destSubpath the descriptor declares (global + local artifact
|
|
@@ -1394,6 +1394,14 @@ function cmdFrontmatterGet(cwd, filePath, field, raw) {
|
|
|
1394
1394
|
// Pass the resolved path so a truncated file is named in the diagnostic and deduplicated
|
|
1395
1395
|
// per file rather than per content digest (#1882, ADR-1411 wiring clause).
|
|
1396
1396
|
const fm = extractFrontmatter(content, fullPath);
|
|
1397
|
+
// #4806: an unparseable frontmatter block is a distinct outcome — the file
|
|
1398
|
+
// HAS a frontmatter block but its YAML failed to parse. Reporting
|
|
1399
|
+
// "Field not found" tells the caller the key is absent, which is
|
|
1400
|
+
// indistinguishable from a file that genuinely lacks it.
|
|
1401
|
+
if (fm[FRONTMATTER_UNPARSEABLE] === true) {
|
|
1402
|
+
output({ error: 'Frontmatter is not parseable YAML — fix the syntax error in the frontmatter block', path: filePath }, raw, undefined);
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1397
1405
|
if (field) {
|
|
1398
1406
|
const value = fm[field];
|
|
1399
1407
|
if (value === undefined) {
|
|
@@ -1649,4 +1657,9 @@ module.exports = {
|
|
|
1649
1657
|
cmdFrontmatterMerge,
|
|
1650
1658
|
cmdFrontmatterValidate,
|
|
1651
1659
|
propagateCommentChannel,
|
|
1660
|
+
// #4917 / ADR-4910 Decision 1: additive-only export so `planning-document.cts`
|
|
1661
|
+
// can COMPOSE this seam's fence-detection grammar (byte-0 rule, BOM strip,
|
|
1662
|
+
// CR handling) instead of reimplementing it. No behavior change — same
|
|
1663
|
+
// function `extractFrontmatter`/`frontmatterListEntries` already call.
|
|
1664
|
+
frontmatterRegion,
|
|
1652
1665
|
};
|
|
@@ -445,14 +445,17 @@ function graphifyStatus(cwd) {
|
|
|
445
445
|
return disabledResponse();
|
|
446
446
|
const { graphPath, configured } = resolveGraphLocation(cwd, planningDir);
|
|
447
447
|
if (!node_fs_1.default.existsSync(graphPath)) {
|
|
448
|
-
return { exists: false, message: configured
|
|
448
|
+
return { exists: false, graph_path: graphPath, message: configured
|
|
449
449
|
? `Configured graph not found at ${graphPath}. Set graphify.graph_path or run /gsd:graphify build.`
|
|
450
450
|
: 'No graph built yet. Run graphify build to create one.' };
|
|
451
451
|
}
|
|
452
452
|
const stat = node_fs_1.default.statSync(graphPath);
|
|
453
453
|
const graph = safeReadJson(graphPath);
|
|
454
454
|
if (!graph) {
|
|
455
|
-
|
|
455
|
+
// Still surface graph_path (#4836 Minor 1): callers gate on `exists`, not
|
|
456
|
+
// on this outcome, so without it they'd fall through to the CLI-first
|
|
457
|
+
// branch with no --graph value to substitute for the <graph> placeholder.
|
|
458
|
+
return { error: 'Failed to parse graph.json', graph_path: graphPath };
|
|
456
459
|
}
|
|
457
460
|
const STALE_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
458
461
|
const age = Date.now() - stat.mtimeMs;
|
|
@@ -482,6 +485,11 @@ function graphifyStatus(cwd) {
|
|
|
482
485
|
(lastBuildAutoUpdate.status === 'failed' || lastBuildAutoUpdate.status === 'running');
|
|
483
486
|
return {
|
|
484
487
|
exists: true,
|
|
488
|
+
// The absolute location the whole graphify surface reads, already resolved
|
|
489
|
+
// through `graphify.graph_path` (#1825). Callers that shell out to the
|
|
490
|
+
// graphify CLI pass this as `--graph` so the umbrella override is honoured
|
|
491
|
+
// there too, instead of re-deriving `.planning/graphs/graph.json` (#4836).
|
|
492
|
+
graph_path: graphPath,
|
|
485
493
|
last_build: stat.mtime.toISOString(),
|
|
486
494
|
node_count: (graph.nodes || []).length,
|
|
487
495
|
edge_count: (graph.edges || graph.links || []).length,
|
|
@@ -307,8 +307,7 @@ function buildStateMd(phaseMap) {
|
|
|
307
307
|
const currentPhaseNum = currentEntry ? zeroPad(currentEntry.phaseNum) : zeroPad(totalPhases);
|
|
308
308
|
const currentSlug = currentEntry ? slugify(currentEntry.slice.title) : 'complete';
|
|
309
309
|
const status = currentEntry ? 'Ready to plan' : 'All phases complete';
|
|
310
|
-
const
|
|
311
|
-
const bar = `[${'█'.repeat(filled)}${'░'.repeat(10 - filled)}]`;
|
|
310
|
+
const bar = `[${(0, phase_lifecycle_cjs_1.renderProgressBar)(pct, 10)}]`;
|
|
312
311
|
const today = clock_cjs_1.realClock.localToday();
|
|
313
312
|
return [
|
|
314
313
|
'# Project State',
|
|
@@ -158,6 +158,17 @@ const RULE_W002 = {
|
|
|
158
158
|
const normalizedValid = normalizePhaseTokenSet(validPhases);
|
|
159
159
|
const sortedValid = [...validPhases].sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
160
160
|
const diagnostics = [];
|
|
161
|
+
// #4257: the valid set above is WORKSTREAM-scoped by construction (every
|
|
162
|
+
// source field is read from `planningPaths(cwd)`'s base, which resolves
|
|
163
|
+
// under `.planning/workstreams/<active-ws>/`), and per-workstream phase
|
|
164
|
+
// numbering is deliberate — so under a workstream the message must NAME
|
|
165
|
+
// that scope rather than make an unqualified project-wide claim (a
|
|
166
|
+
// reference to a phase declared only in a SIBLING workstream reads as
|
|
167
|
+
// "undeclared" against this list; that is the scope speaking, not drift).
|
|
168
|
+
// Root scope (`workstream === null`, flat or root-planning projects)
|
|
169
|
+
// keeps the byte-identical message — no clause is appended when none
|
|
170
|
+
// applies.
|
|
171
|
+
const scopeClause = snapshot.workstream ? ` in workstream ${snapshot.workstream}` : '';
|
|
161
172
|
for (const ref of snapshot.statePhaseTokens.value) {
|
|
162
173
|
const dotIdx = ref.indexOf('.');
|
|
163
174
|
const head = dotIdx === -1 ? ref : ref.slice(0, dotIdx);
|
|
@@ -168,7 +179,7 @@ const RULE_W002 = {
|
|
|
168
179
|
diagnostics.push({
|
|
169
180
|
code: 'W002',
|
|
170
181
|
severity: SEVERITY.WARNING,
|
|
171
|
-
message: `STATE.md references phase ${ref}, but only phases ${sortedValid.join(', ')} are declared`,
|
|
182
|
+
message: `STATE.md references phase ${ref}, but only phases ${sortedValid.join(', ')} are declared${scopeClause}`,
|
|
172
183
|
remedy: adviseRemedy('Review STATE.md manually before changing it; /gsd-health --repair will not overwrite an existing STATE.md for phase mismatches'),
|
|
173
184
|
});
|
|
174
185
|
}
|
|
@@ -135,7 +135,7 @@ function checkW017(snapshot) {
|
|
|
135
135
|
function isActiveWorktreePath(activeCwd, worktreePath, platform = process.platform) {
|
|
136
136
|
const active = shellCmdProjection.toComparablePathKey(activeCwd, platform);
|
|
137
137
|
const worktree = shellCmdProjection.toComparablePathKey(worktreePath, platform);
|
|
138
|
-
return active === worktree || active.startsWith(worktree + '/');
|
|
138
|
+
return active === worktree || active.startsWith(worktree + '/'); // allow-handrolled-containment: worktree identity matching, not a containment gate
|
|
139
139
|
}
|
|
140
140
|
function checkW027(snapshot) {
|
|
141
141
|
const diagnostics = [];
|
|
@@ -24,6 +24,7 @@ exports.resolveReportedRuntime = resolveReportedRuntime;
|
|
|
24
24
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
25
25
|
const node_path_1 = __importDefault(require("node:path"));
|
|
26
26
|
const runtime_slash_cjs_1 = require("./runtime-slash.cjs");
|
|
27
|
+
const runtime_name_policy_cjs_1 = require("./runtime-name-policy.cjs");
|
|
27
28
|
const update_context_cjs_1 = require("./update-context.cjs");
|
|
28
29
|
Object.defineProperty(exports, "CODEX_CONFIG_MARKER", { enumerable: true, get: function () { return update_context_cjs_1.CODEX_CONFIG_MARKER; } });
|
|
29
30
|
// Codex sandbox env vars set by the shell tool / Seatbelt child-process spawn.
|
|
@@ -127,6 +128,14 @@ function resolveReportedRuntimeUnsafe(projectDir, deps) {
|
|
|
127
128
|
const explicit = (0, runtime_slash_cjs_1.resolveExplicitRuntime)(projectDir, deps?.env ?? process.env);
|
|
128
129
|
if (explicit)
|
|
129
130
|
return explicit;
|
|
131
|
+
// #4717: the per-install marker names the runtime that owns THIS tree — a
|
|
132
|
+
// stronger signal than host sniffing, which misreports every session on a
|
|
133
|
+
// multi-runtime machine (e.g. a globally exported CODEX_HOME makes a Claude
|
|
134
|
+
// Code session read as codex). Marker-less trees (dev/source, pre-#2297
|
|
135
|
+
// installs) fall through to host detection unchanged.
|
|
136
|
+
const marker = (0, runtime_name_policy_cjs_1.resolveRuntimeNameFromCandidates)((0, runtime_slash_cjs_1.readInstallRuntimeMarker)());
|
|
137
|
+
if (marker)
|
|
138
|
+
return marker;
|
|
130
139
|
const detected = detectHostRuntime(deps);
|
|
131
140
|
if (detected.runtime)
|
|
132
141
|
return detected.runtime;
|