@opengsd/gsd-core 1.12.0 → 1.14.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-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 +458 -0
- package/agents/gsd-code-fixer.md +5 -5
- 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 +345 -0
- 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-planner.compact.md +137 -0
- package/agents/gsd-executor.md +63 -35
- 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-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-plan-checker.md +76 -57
- package/agents/gsd-planner.md +14 -0
- package/agents/gsd-project-researcher.compact.md +587 -0
- package/agents/gsd-research-synthesizer.compact.md +212 -0
- 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-checker.compact.md +277 -0
- package/agents/gsd-ui-checker.md +19 -3
- package/agents/gsd-ui-researcher.compact.md +282 -0
- package/agents/gsd-ui-researcher.md +29 -0
- package/agents/gsd-user-profiler.compact.md +108 -0
- package/agents/gsd-verifier.md +23 -1
- package/bin/install.js +444 -134
- 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/execute-phase.md +1 -1
- package/commands/gsd/graphify.md +1 -0
- package/commands/gsd/health.md +1 -0
- package/commands/gsd/mempalace-capture.md +1 -0
- 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/ns-workflow.md +2 -1
- package/commands/gsd/pause-work.md +1 -0
- package/commands/gsd/phase.md +2 -1
- package/commands/gsd/pr-branch.md +1 -0
- package/commands/gsd/quick-batch.md +105 -0
- package/commands/gsd/resume-work.md +1 -0
- package/commands/gsd/review-backlog.md +1 -0
- package/commands/gsd/settings.md +2 -1
- package/commands/gsd/stats.md +1 -0
- package/commands/gsd/surface.md +18 -8
- 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 +532 -174
- package/gsd-core/bin/lib/adr-parser.cjs +1 -1
- package/gsd-core/bin/lib/artifacts.cjs +2 -1
- package/gsd-core/bin/lib/audit.cjs +39 -22
- package/gsd-core/bin/lib/broken-windows.cjs +168 -49
- package/gsd-core/bin/lib/capability-activation.cjs +27 -0
- 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 +528 -116
- package/gsd-core/bin/lib/capability-source.cjs +19 -2
- package/gsd-core/bin/lib/capability-state.cjs +7 -1
- package/gsd-core/bin/lib/capability-validator.cjs +134 -5
- package/gsd-core/bin/lib/capability-writer.cjs +14 -4
- package/gsd-core/bin/lib/check-command-router.cjs +198 -38
- package/gsd-core/bin/lib/claude-orchestration.cjs +10 -25
- package/gsd-core/bin/lib/clusters.cjs +1 -0
- package/gsd-core/bin/lib/code-review-depth.cjs +2 -2
- package/gsd-core/bin/lib/command-aliases.cjs +16 -0
- package/gsd-core/bin/lib/commands.cjs +981 -79
- package/gsd-core/bin/lib/config-loader.cjs +4 -0
- package/gsd-core/bin/lib/config.cjs +153 -38
- package/gsd-core/bin/lib/core-utils.cjs +34 -7
- package/gsd-core/bin/lib/coverage.cjs +1 -1
- package/gsd-core/bin/lib/decisions.cjs +343 -28
- package/gsd-core/bin/lib/edge-probe.cjs +14 -1
- package/gsd-core/bin/lib/external-descriptor-trust.cjs +29 -14
- package/gsd-core/bin/lib/file-overlap-partitioner.cjs +74 -0
- package/gsd-core/bin/lib/frontmatter.cjs +137 -23
- package/gsd-core/bin/lib/gap-checker.cjs +22 -13
- package/gsd-core/bin/lib/git-base-branch.cjs +10 -2
- package/gsd-core/bin/lib/gsd2-import.cjs +1 -2
- 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 +54 -11
- package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +87 -23
- package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +1 -1
- package/gsd-core/bin/lib/host-integration.cjs +57 -5
- package/gsd-core/bin/lib/init-command-router.cjs +14 -0
- package/gsd-core/bin/lib/init.cjs +539 -60
- package/gsd-core/bin/lib/install-engine.cjs +199 -14
- package/gsd-core/bin/lib/install-model-override-resolver.cjs +45 -0
- package/gsd-core/bin/lib/install-profiles.cjs +36 -14
- package/gsd-core/bin/lib/installer-migration-report.cjs +1 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +33 -4
- package/gsd-core/bin/lib/io.cjs +35 -0
- package/gsd-core/bin/lib/loop-resolver.cjs +64 -39
- package/gsd-core/bin/lib/markdown-table.cjs +123 -0
- package/gsd-core/bin/lib/mcp-catalog.cjs +2 -2
- package/gsd-core/bin/lib/milestone.cjs +41 -10
- package/gsd-core/bin/lib/model-resolver.cjs +101 -10
- package/gsd-core/bin/lib/phase-command-router.cjs +20 -7
- package/gsd-core/bin/lib/phase-id.cjs +412 -31
- package/gsd-core/bin/lib/phase-lifecycle.cjs +61 -0
- package/gsd-core/bin/lib/phase.cjs +941 -98
- package/gsd-core/bin/lib/plan-document.cjs +10 -0
- package/gsd-core/bin/lib/planning-inspect.cjs +34 -18
- package/gsd-core/bin/lib/planning-snapshot.cjs +206 -30
- package/gsd-core/bin/lib/planning-workspace.cjs +153 -29
- package/gsd-core/bin/lib/pristine-baseline.cjs +182 -0
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +91 -4
- 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/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 +53 -5
- package/gsd-core/bin/lib/review-lane-invocation.cjs +96 -1
- package/gsd-core/bin/lib/review-lane-runner.cjs +136 -10
- package/gsd-core/bin/lib/reviewer-step-dispatch.cjs +337 -0
- package/gsd-core/bin/lib/roadmap-parser.cjs +555 -41
- package/gsd-core/bin/lib/roadmap.cjs +292 -69
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +260 -43
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +28 -20
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +294 -108
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +408 -47
- package/gsd-core/bin/lib/security.cjs +126 -7
- package/gsd-core/bin/lib/shell-command-projection.cjs +4 -0
- package/gsd-core/bin/lib/smart-entry.cjs +7 -9
- package/gsd-core/bin/lib/state-document.cjs +159 -32
- package/gsd-core/bin/lib/state-md-schema.cjs +44 -27
- package/gsd-core/bin/lib/state-transition.cjs +465 -62
- package/gsd-core/bin/lib/state.cjs +906 -151
- package/gsd-core/bin/lib/surface.cjs +83 -10
- package/gsd-core/bin/lib/task-command-router.cjs +12 -6
- package/gsd-core/bin/lib/tdd-red-evidence.cjs +133 -0
- package/gsd-core/bin/lib/uat.cjs +1420 -516
- package/gsd-core/bin/lib/update-context.cjs +36 -26
- package/gsd-core/bin/lib/validate.cjs +230 -12
- package/gsd-core/bin/lib/vendor/js-yaml.cjs +11 -3
- package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
- package/gsd-core/bin/lib/verification.cjs +316 -23
- package/gsd-core/bin/lib/verify-command-grounding.cjs +1 -1
- package/gsd-core/bin/lib/verify-command-router.cjs +1 -0
- package/gsd-core/bin/lib/verify.cjs +531 -36
- package/gsd-core/bin/lib/workstream-inventory.cjs +21 -2
- package/gsd-core/bin/lib/worktree-safety.cjs +21 -7
- package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
- package/gsd-core/bin/shared/config-schema.manifest.json +13 -0
- package/gsd-core/bin/verify-reapply-patches.cjs +507 -81
- package/gsd-core/references/agent-contracts.md +3 -3
- package/gsd-core/references/compact-content-gate.md +66 -0
- package/gsd-core/references/edge-probe.md +17 -13
- package/gsd-core/references/execute-mvp-tdd.md +18 -16
- package/gsd-core/references/execute-phase-response-language.md +6 -0
- package/gsd-core/references/executor-examples.md +42 -0
- package/gsd-core/references/few-shot-examples/plan-checker.md +15 -15
- package/gsd-core/references/loop-hook-dispatch.md +18 -0
- package/gsd-core/references/model-profiles.md +12 -3
- package/gsd-core/references/mvp-concepts.md +2 -2
- 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-quick-batch.md +71 -0
- package/gsd-core/references/planner-reviews.md +47 -0
- package/gsd-core/references/planner-revision.md +75 -2
- package/gsd-core/references/planning-config.md +5 -1
- package/gsd-core/references/response-language-directive.md +9 -0
- package/gsd-core/references/revision-loop.md +118 -11
- package/gsd-core/references/tdd.md +17 -9
- package/gsd-core/references/thinking-models-planning.md +18 -2
- package/gsd-core/references/verification-patterns.md +17 -4
- package/gsd-core/references/verifier-evidence-gate.md +160 -0
- package/gsd-core/references/worktree-path-safety.md +112 -2
- package/gsd-core/templates/README.md +7 -1
- package/gsd-core/templates/phase-prompt.md +4 -0
- 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 +5 -0
- package/gsd-core/workflows/add-backlog.md +2 -0
- package/gsd-core/workflows/add-phase.md +2 -0
- package/gsd-core/workflows/add-tests.md +1 -1
- package/gsd-core/workflows/add-todo.md +4 -3
- package/gsd-core/workflows/ai-integration-phase.md +1 -1
- package/gsd-core/workflows/analyze-dependencies.md +2 -0
- package/gsd-core/workflows/audit-fix.md +2 -0
- package/gsd-core/workflows/audit-milestone.md +2 -0
- package/gsd-core/workflows/audit-uat.md +2 -0
- package/gsd-core/workflows/autonomous.md +15 -10
- package/gsd-core/workflows/check-todos.md +5 -3
- package/gsd-core/workflows/cleanup.md +4 -2
- package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +22 -13
- package/gsd-core/workflows/code-review-fix.md +5 -3
- package/gsd-core/workflows/code-review.md +211 -43
- package/gsd-core/workflows/complete-milestone/detail/elaboration.md +274 -0
- package/gsd-core/workflows/complete-milestone.md +40 -254
- package/gsd-core/workflows/debug.md +1 -1
- package/gsd-core/workflows/diagnose-issues.md +5 -1
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +2 -0
- 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 +2 -0
- 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 +2 -0
- 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.md +1 -1
- package/gsd-core/workflows/discuss-phase-power.md +2 -0
- package/gsd-core/workflows/discuss-phase.md +1 -1
- package/gsd-core/workflows/do.md +43 -13
- package/gsd-core/workflows/docs-update/detail/elaboration.md +179 -0
- package/gsd-core/workflows/docs-update.md +15 -156
- package/gsd-core/workflows/edit-phase.md +2 -0
- package/gsd-core/workflows/eval-review.md +1 -1
- package/gsd-core/workflows/execute-phase/detail/elaboration.md +124 -0
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +20 -3
- package/gsd-core/workflows/execute-phase/steps/completion-reconciliation.md +56 -0
- package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +24 -3
- package/gsd-core/workflows/execute-phase/steps/executor-progress-policy.md +43 -0
- package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +8 -2
- package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -0
- package/gsd-core/workflows/execute-phase/steps/sequential-root-pin.md +35 -0
- package/gsd-core/workflows/execute-phase/steps/tdd-applicability-resolution.md +25 -0
- package/gsd-core/workflows/execute-phase/steps/worktree-recovery-policy.md +2 -0
- package/gsd-core/workflows/execute-phase.md +78 -159
- package/gsd-core/workflows/execute-plan.md +28 -15
- package/gsd-core/workflows/explore.md +2 -0
- package/gsd-core/workflows/extract-learnings.md +2 -0
- package/gsd-core/workflows/fast.md +6 -0
- package/gsd-core/workflows/forensics.md +2 -0
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +1 -1
- 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.compact.md +398 -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 +3 -1
- package/gsd-core/workflows/import.md +3 -3
- package/gsd-core/workflows/inbox.md +1 -1
- package/gsd-core/workflows/ingest-docs.md +1 -1
- package/gsd-core/workflows/insert-phase.md +2 -0
- package/gsd-core/workflows/list-phase-assumptions.md +2 -0
- package/gsd-core/workflows/list-seeds.md +2 -0
- package/gsd-core/workflows/list-workspaces.md +2 -0
- package/gsd-core/workflows/manager.md +3 -3
- package/gsd-core/workflows/map-codebase.md +52 -3
- package/gsd-core/workflows/milestone-summary.md +2 -0
- package/gsd-core/workflows/mvp-phase.md +1 -1
- package/gsd-core/workflows/new-milestone.md +55 -13
- package/gsd-core/workflows/new-project/detail/elaboration.md +216 -0
- package/gsd-core/workflows/new-project.md +37 -205
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +2 -0
- 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 +19 -4
- package/gsd-core/workflows/plan-phase/detail/elaboration.md +209 -0
- package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +100 -18
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +2 -0
- package/gsd-core/workflows/plan-phase/steps/stall-detection-helpers.md +9 -0
- package/gsd-core/workflows/plan-phase.md +144 -185
- package/gsd-core/workflows/plan-review-convergence.md +102 -10
- package/gsd-core/workflows/plant-seed.md +1 -1
- package/gsd-core/workflows/pr-branch.md +30 -10
- package/gsd-core/workflows/profile-user.md +1 -1
- package/gsd-core/workflows/progress/steps/forensic-audit.md +1 -1
- package/gsd-core/workflows/progress.md +25 -3
- package/gsd-core/workflows/quick/steps/plan-checker-loop.md +37 -2
- package/gsd-core/workflows/quick/steps/research-phase.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 +21 -4
- package/gsd-core/workflows/reapply-patches.md +79 -3
- package/gsd-core/workflows/remove-phase.md +2 -0
- package/gsd-core/workflows/remove-workspace.md +1 -1
- package/gsd-core/workflows/resume-project.md +6 -2
- package/gsd-core/workflows/review.md +215 -10
- package/gsd-core/workflows/scan.md +2 -0
- package/gsd-core/workflows/section-manifest.json +12 -0
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/session-report.md +2 -0
- package/gsd-core/workflows/settings-advanced.md +2 -0
- package/gsd-core/workflows/settings-integrations.md +9 -8
- package/gsd-core/workflows/settings.md +19 -6
- package/gsd-core/workflows/ship.md +10 -10
- package/gsd-core/workflows/sketch-wrap-up.md +2 -0
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +1 -1
- package/gsd-core/workflows/spec-phase.md +24 -19
- package/gsd-core/workflows/spike-wrap-up.md +2 -0
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +2 -0
- package/gsd-core/workflows/sync-skills.md +12 -4
- package/gsd-core/workflows/thread.md +2 -0
- package/gsd-core/workflows/transition.md +2 -0
- package/gsd-core/workflows/ui-phase.md +26 -5
- package/gsd-core/workflows/ui-review.md +1 -1
- package/gsd-core/workflows/ultraplan-phase.md +2 -0
- package/gsd-core/workflows/undo.md +1 -1
- package/gsd-core/workflows/update.md +48 -43
- package/gsd-core/workflows/validate-phase.md +1 -1
- package/gsd-core/workflows/verify-work/detail/elaboration.md +230 -0
- package/gsd-core/workflows/verify-work.md +68 -182
- package/hooks/dist/gsd-agent-isolation-guard.js +42 -16
- package/hooks/dist/gsd-check-update-worker.js +19 -2
- package/hooks/dist/gsd-context-monitor.js +371 -27
- package/hooks/dist/gsd-cursor-subagent-start.js +34 -14
- package/hooks/dist/gsd-node-runner.sh +1 -0
- package/hooks/dist/gsd-prompt-guard.js +30 -5
- package/hooks/dist/gsd-read-guard.js +2 -0
- package/hooks/dist/gsd-read-injection-scanner.js +5 -5
- package/hooks/dist/gsd-secret-read-guard.js +1105 -0
- package/hooks/dist/gsd-statusline.js +18 -10
- package/hooks/dist/gsd-validate-commit.sh +474 -7
- package/hooks/dist/gsd-workflow-guard.js +2 -1
- 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/git-cmd.js +210 -1
- package/hooks/dist/lib/injection-patterns.js +36 -6
- package/hooks/dist/lib/isolation-deny-reason.js +53 -1
- package/hooks/dist/lib/isolation-sentinel.js +58 -19
- package/hooks/dist/managed-hooks-registry.cjs +1 -0
- package/hooks/gsd-agent-isolation-guard.js +42 -16
- package/hooks/gsd-check-update-worker.js +19 -2
- package/hooks/gsd-context-monitor.js +371 -27
- package/hooks/gsd-cursor-subagent-start.js +34 -14
- package/hooks/gsd-node-runner.sh +1 -0
- package/hooks/gsd-prompt-guard.js +30 -5
- package/hooks/gsd-read-guard.js +2 -0
- package/hooks/gsd-read-injection-scanner.js +5 -5
- package/hooks/gsd-secret-read-guard.js +1105 -0
- package/hooks/gsd-statusline.js +18 -10
- package/hooks/gsd-validate-commit.sh +474 -7
- package/hooks/gsd-workflow-guard.js +2 -1
- package/hooks/gsd-worktree-path-guard.js +25 -14
- package/hooks/gsd-write-guard.js +46 -1
- package/hooks/hooks.json +6 -0
- package/hooks/lib/dispatch-identity.js +187 -0
- package/hooks/lib/filename-classification.js +64 -0
- package/hooks/lib/git-cmd.js +210 -1
- package/hooks/lib/injection-patterns.js +36 -6
- package/hooks/lib/isolation-deny-reason.js +53 -1
- package/hooks/lib/isolation-sentinel.js +58 -19
- package/hooks/managed-hooks-registry.cjs +1 -0
- package/package.json +13 -9
- package/scripts/benchmark-compact-content-variants.cjs +298 -0
- package/scripts/benchmark-compact-content.cjs +368 -0
- package/scripts/build-hooks.js +11 -4
- package/scripts/check-contract-drift.cjs +4 -1
- 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 +133 -20
- package/scripts/ci-timeout-report.cjs +1 -1
- package/scripts/diff-touches-shipped-paths.cjs +1 -1
- package/scripts/docs-guard-registry.cjs +17 -2
- package/scripts/gen-adr-index.cjs +8 -2
- package/scripts/gen-inventory-manifest.cjs +12 -0
- package/scripts/gen-loop-host-contract.cjs +67 -15
- 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 +210 -0
- package/scripts/lib/npm-version-check-diagnosis.cjs +59 -0
- package/scripts/lib/platform-conformance-tier.generated.cjs +276 -0
- package/scripts/lib/shellcheck-fetch.cjs +247 -0
- package/scripts/lib/suite-detection.cjs +32 -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-allowed-tools-parity.cjs +221 -0
- package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +24 -2
- package/scripts/lint-phase-enumeration-drift.cjs +24 -6
- package/scripts/lint-phase-id-drift.cjs +465 -15
- package/scripts/lint-portable-grep.cjs +176 -0
- package/scripts/lint-response-language-coverage.cjs +530 -0
- package/scripts/lint-source-test-name-collision.cjs +1 -1
- package/scripts/lint-test-file-count.allowlist.json +4 -1
- package/scripts/lint-vendored-deps.cjs +128 -17
- package/scripts/lint-workflow-shellcheck-baseline.json +1112 -0
- package/scripts/lint-workflow-shellcheck.cjs +614 -0
- package/scripts/npm-audit-baseline.cjs +376 -0
- package/scripts/prompt-injection-scan.sh +22 -0
- package/scripts/require-issue-link-policy.cjs +16 -1
- package/scripts/workflow-size.cjs +139 -0
- 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-execute-phase/SKILL.md +1 -1
- package/skills/gsd-graphify/SKILL.md +1 -0
- package/skills/gsd-health/SKILL.md +1 -0
- package/skills/gsd-mempalace-capture/SKILL.md +1 -0
- 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-ns-workflow/SKILL.md +1 -0
- package/skills/gsd-pause-work/SKILL.md +1 -0
- package/skills/gsd-phase/SKILL.md +2 -1
- package/skills/gsd-pr-branch/SKILL.md +1 -0
- package/skills/gsd-quick-batch/SKILL.md +105 -0
- package/skills/gsd-resume-work/SKILL.md +1 -0
- 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-surface/SKILL.md +18 -8
- 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
|
@@ -135,6 +135,7 @@ const CONFIG_DEFAULTS = {
|
|
|
135
135
|
firecrawl: _getConfigDefault('firecrawl'),
|
|
136
136
|
exa_search: _getConfigDefault('exa_search'),
|
|
137
137
|
text_mode: _getNestedConfigDefault('workflow', 'text_mode'),
|
|
138
|
+
compact_content: _getNestedConfigDefault('workflow', 'compact_content'),
|
|
138
139
|
sub_repos: _getNestedConfigDefault('planning', 'sub_repos'),
|
|
139
140
|
pr_strict: _getNestedConfigDefault('planning', 'pr_strict'),
|
|
140
141
|
resolve_model_ids: _getConfigDefault('resolve_model_ids'),
|
|
@@ -831,6 +832,7 @@ function loadConfigResolved(cwd, options = {}) {
|
|
|
831
832
|
branching_strategy: get('branching_strategy', { section: 'git', field: 'branching_strategy' }) ?? defaults.branching_strategy,
|
|
832
833
|
base_branch: get('base_branch', { section: 'git', field: 'base_branch' }),
|
|
833
834
|
protected_branches: getNested('git', 'protected_branches'),
|
|
835
|
+
allow_default_branch_commits: getNested('git', 'allow_default_branch_commits'),
|
|
834
836
|
phase_branch_template: get('phase_branch_template', { section: 'git', field: 'phase_branch_template' }) ?? defaults.phase_branch_template,
|
|
835
837
|
milestone_branch_template: get('milestone_branch_template', { section: 'git', field: 'milestone_branch_template' }) ?? defaults.milestone_branch_template,
|
|
836
838
|
quick_branch_template: get('quick_branch_template', { section: 'git', field: 'quick_branch_template' }) ?? defaults.quick_branch_template,
|
|
@@ -844,6 +846,7 @@ function loadConfigResolved(cwd, options = {}) {
|
|
|
844
846
|
firecrawl: get('firecrawl') ?? defaults.firecrawl,
|
|
845
847
|
exa_search: get('exa_search') ?? defaults.exa_search,
|
|
846
848
|
mvp_mode: get('mvp_mode', { section: 'workflow', field: 'mvp_mode' }) ?? false,
|
|
849
|
+
tdd_mode: getNested('workflow', 'tdd_mode') ?? false,
|
|
847
850
|
text_mode: get('text_mode', { section: 'workflow', field: 'text_mode' }) ?? defaults.text_mode,
|
|
848
851
|
auto_advance: get('auto_advance', { section: 'workflow', field: 'auto_advance' }) ?? false,
|
|
849
852
|
_auto_chain_active: get('_auto_chain_active', { section: 'workflow', field: '_auto_chain_active' }) ?? false,
|
|
@@ -856,6 +859,7 @@ function loadConfigResolved(cwd, options = {}) {
|
|
|
856
859
|
project_code: get('project_code') ?? defaults.project_code,
|
|
857
860
|
subagent_timeout: get('subagent_timeout', { section: 'workflow', field: 'subagent_timeout' }) ?? defaults.subagent_timeout,
|
|
858
861
|
model_overrides: (parsed['model_overrides']) || null,
|
|
862
|
+
agent_tools: (parsed['agent_tools']) || null,
|
|
859
863
|
models: (parsed['models']) || null,
|
|
860
864
|
granularity: parsed['granularity'] !== undefined ? parsed['granularity'] : null,
|
|
861
865
|
granularities: (parsed['granularities']) || null,
|
|
@@ -81,6 +81,11 @@ const SCHEMA_DEFAULTS = {
|
|
|
81
81
|
// #1689: per-plan agent_hint executor routing — default-on. A no-op for plans
|
|
82
82
|
// without an agent_hint field, so existing dispatch is byte-identical.
|
|
83
83
|
'workflow.agent_hint_routing': true,
|
|
84
|
+
// #4401: Compact Content mode gate — derived from the defaults manifest via
|
|
85
|
+
// CONFIG_DEFAULTS (added in config-loader.cts) so the manifest stays the
|
|
86
|
+
// single source of truth, matching workflow.smart_zone_tokens /
|
|
87
|
+
// planning.pr_strict / workflow.inline_plan_threshold below.
|
|
88
|
+
'workflow.compact_content': CONFIG_DEFAULTS.compact_content,
|
|
84
89
|
// Derived from the defaults manifest rather than restated, so the manifest
|
|
85
90
|
// stays the single source of truth for the smart-zone budget (#2630).
|
|
86
91
|
'workflow.smart_zone_tokens': CONFIG_DEFAULTS.smart_zone_tokens,
|
|
@@ -93,6 +98,27 @@ const SCHEMA_DEFAULTS = {
|
|
|
93
98
|
// effective default existed only as the workflow's shell fallback and the
|
|
94
99
|
// docs disagreed (settings-advanced said 3). Manifest stays the one owner.
|
|
95
100
|
'workflow.inline_plan_threshold': CONFIG_DEFAULTS.inline_plan_threshold,
|
|
101
|
+
// #4285 review: an absent threshold resolved to "Key not found" while the
|
|
102
|
+
// hook silently used 35/25 — the query surface disagreeing with the reader.
|
|
103
|
+
//
|
|
104
|
+
// Restated here rather than derived: `CONFIG_DEFAULTS` is re-exported with a
|
|
105
|
+
// FLATTENED shape that drops the manifest's nested blocks, so
|
|
106
|
+
// `CONFIG_DEFAULTS.hooks` is undefined at runtime and the manifest cannot
|
|
107
|
+
// feed these two rows the way `workflow.smart_zone_tokens` above is fed.
|
|
108
|
+
//
|
|
109
|
+
// Not added to `buildNewProjectConfig` either, and that one is deliberate
|
|
110
|
+
// rather than incidental: it writes a `hooks` object into every NEW project's
|
|
111
|
+
// config.json, which would freeze today's fire-points as an explicit
|
|
112
|
+
// per-project override everywhere — the opposite of this PR's premise that an
|
|
113
|
+
// absent key tracks the shipped default. (The manifest alone would NOT have
|
|
114
|
+
// that effect; `buildNewProjectConfig` builds its own literal. Correcting an
|
|
115
|
+
// earlier version of this comment that ran the two together.)
|
|
116
|
+
//
|
|
117
|
+
// That leaves ONE copy of 35/25 outside the hook — these two rows — and
|
|
118
|
+
// `tests/config.test.cjs` pins them against the hook's exported
|
|
119
|
+
// WARNING_THRESHOLD/CRITICAL_THRESHOLD so the copies cannot drift.
|
|
120
|
+
'hooks.context_warning_threshold': 35,
|
|
121
|
+
'hooks.context_critical_threshold': 25,
|
|
96
122
|
};
|
|
97
123
|
/**
|
|
98
124
|
* Resolve a schema-level default for an absent key (#2256). Checks the legacy
|
|
@@ -308,6 +334,7 @@ function buildNewProjectConfig(userChoices) {
|
|
|
308
334
|
human_verify_mode: 'end-of-phase',
|
|
309
335
|
context_guard_mode: 'warn',
|
|
310
336
|
text_mode: false,
|
|
337
|
+
compact_content: false,
|
|
311
338
|
research_before_questions: false,
|
|
312
339
|
discuss_mode: 'discuss',
|
|
313
340
|
skip_discuss: false,
|
|
@@ -564,19 +591,35 @@ function _unsetNestedValue(config, keyPath) {
|
|
|
564
591
|
* Does not call `output()`, so can be used as one step in a command without triggering `exit(0)` in
|
|
565
592
|
* the happy path. But note that `error()` will still `exit(1)` out of the process.
|
|
566
593
|
*/
|
|
594
|
+
/**
|
|
595
|
+
* Loads `.planning/config.json` as a plain object, or `{}` if the file does
|
|
596
|
+
* not exist. A parse failure calls `error()` (process-exiting) rather than
|
|
597
|
+
* throwing, matching every caller's existing behavior.
|
|
598
|
+
*
|
|
599
|
+
* Single source for this load+parse step — `setConfigValue`,
|
|
600
|
+
* `unsetConfigValue`, `setConfigValues`, `previewConfigValue`, and
|
|
601
|
+
* `previewUnsetConfigValue` all delegate here instead of each repeating the
|
|
602
|
+
* same try/catch (CLAUDE.md's "Generative Fix Divergence" known-defect
|
|
603
|
+
* pattern: independently-guessed copies of the same logic can silently
|
|
604
|
+
* drift apart).
|
|
605
|
+
*/
|
|
606
|
+
function loadConfigJson(cwd) {
|
|
607
|
+
const configPath = node_path_1.default.join(planningDir(cwd), 'config.json');
|
|
608
|
+
let config = {};
|
|
609
|
+
try {
|
|
610
|
+
if (node_fs_1.default.existsSync(configPath)) {
|
|
611
|
+
config = JSON.parse(node_fs_1.default.readFileSync(configPath, 'utf-8'));
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
catch (err) {
|
|
615
|
+
error('Failed to read config.json: ' + err.message, ERROR_REASON.CONFIG_PARSE_FAILED);
|
|
616
|
+
}
|
|
617
|
+
return config;
|
|
618
|
+
}
|
|
567
619
|
function unsetConfigValue(cwd, keyPath) {
|
|
568
620
|
const configPath = node_path_1.default.join(planningDir(cwd), 'config.json');
|
|
569
621
|
return withPlanningLock(cwd, () => {
|
|
570
|
-
|
|
571
|
-
let config = {};
|
|
572
|
-
try {
|
|
573
|
-
if (node_fs_1.default.existsSync(configPath)) {
|
|
574
|
-
config = JSON.parse(node_fs_1.default.readFileSync(configPath, 'utf-8'));
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
catch (err) {
|
|
578
|
-
error('Failed to read config.json: ' + err.message, ERROR_REASON.CONFIG_PARSE_FAILED);
|
|
579
|
-
}
|
|
622
|
+
const config = loadConfigJson(cwd);
|
|
580
623
|
const { previousValue, existed } = _unsetNestedValue(config, keyPath);
|
|
581
624
|
// Write back
|
|
582
625
|
try {
|
|
@@ -598,16 +641,7 @@ function unsetConfigValue(cwd, keyPath) {
|
|
|
598
641
|
function setConfigValue(cwd, keyPath, parsedValue) {
|
|
599
642
|
const configPath = node_path_1.default.join(planningDir(cwd), 'config.json');
|
|
600
643
|
return withPlanningLock(cwd, () => {
|
|
601
|
-
|
|
602
|
-
let config = {};
|
|
603
|
-
try {
|
|
604
|
-
if (node_fs_1.default.existsSync(configPath)) {
|
|
605
|
-
config = JSON.parse(node_fs_1.default.readFileSync(configPath, 'utf-8'));
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
catch (err) {
|
|
609
|
-
error('Failed to read config.json: ' + err.message, ERROR_REASON.CONFIG_PARSE_FAILED);
|
|
610
|
-
}
|
|
644
|
+
const config = loadConfigJson(cwd);
|
|
611
645
|
const previousValue = _setNestedValue(config, keyPath, parsedValue);
|
|
612
646
|
// Write back
|
|
613
647
|
try {
|
|
@@ -619,6 +653,29 @@ function setConfigValue(cwd, keyPath, parsedValue) {
|
|
|
619
653
|
}
|
|
620
654
|
});
|
|
621
655
|
}
|
|
656
|
+
/**
|
|
657
|
+
* #4444: read-only preview counterpart to `setConfigValue` — loads config
|
|
658
|
+
* exactly like the real setter and reuses `_setNestedValue` (the SAME
|
|
659
|
+
* traversal/creation logic, including its prototype-pollution guards) on a
|
|
660
|
+
* throwaway in-memory copy that is NEVER written back to disk. This is what
|
|
661
|
+
* makes the dry-run preview provably identical to what the real write would
|
|
662
|
+
* compute, rather than a second, hand-maintained traversal that could drift
|
|
663
|
+
* from the real one.
|
|
664
|
+
*/
|
|
665
|
+
function previewConfigValue(cwd, keyPath, parsedValue) {
|
|
666
|
+
const config = loadConfigJson(cwd);
|
|
667
|
+
const previousValue = _setNestedValue(config, keyPath, parsedValue);
|
|
668
|
+
return { key: keyPath, value: parsedValue, previousValue };
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* #4444: read-only preview counterpart to `unsetConfigValue` — same pattern
|
|
672
|
+
* as `previewConfigValue`, reusing `_unsetNestedValue` on a throwaway copy.
|
|
673
|
+
*/
|
|
674
|
+
function previewUnsetConfigValue(cwd, keyPath) {
|
|
675
|
+
const config = loadConfigJson(cwd);
|
|
676
|
+
const { previousValue, existed } = _unsetNestedValue(config, keyPath);
|
|
677
|
+
return { key: keyPath, value: null, previousValue, existed };
|
|
678
|
+
}
|
|
622
679
|
/**
|
|
623
680
|
* Batched sibling of setConfigValue: apply multiple key-path writes in a
|
|
624
681
|
* single load → set-all → write cycle inside ONE withPlanningLock call.
|
|
@@ -635,16 +692,7 @@ function setConfigValues(cwd, entries) {
|
|
|
635
692
|
}
|
|
636
693
|
const configPath = node_path_1.default.join(planningDir(cwd), 'config.json');
|
|
637
694
|
return withPlanningLock(cwd, () => {
|
|
638
|
-
|
|
639
|
-
let config = {};
|
|
640
|
-
try {
|
|
641
|
-
if (node_fs_1.default.existsSync(configPath)) {
|
|
642
|
-
config = JSON.parse(node_fs_1.default.readFileSync(configPath, 'utf-8'));
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
catch (err) {
|
|
646
|
-
error('Failed to read config.json: ' + err.message, ERROR_REASON.CONFIG_PARSE_FAILED);
|
|
647
|
-
}
|
|
695
|
+
const config = loadConfigJson(cwd);
|
|
648
696
|
const results = [];
|
|
649
697
|
for (const entry of entries) {
|
|
650
698
|
const previousValue = _setNestedValue(config, entry.keyPath, entry.value);
|
|
@@ -676,14 +724,8 @@ function assertEnumValue(parsedValue, rawVal, allowed, label) {
|
|
|
676
724
|
error(`Invalid ${label} '${rawVal}'. Valid values: ${allowed.join(', ')}`);
|
|
677
725
|
}
|
|
678
726
|
}
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
* "workflow.research").
|
|
682
|
-
*
|
|
683
|
-
* Note that this exits the process (via `output()`) even in the happy path; use `setConfigValue()`
|
|
684
|
-
* directly if you need to avoid this.
|
|
685
|
-
*/
|
|
686
|
-
function cmdConfigSet(cwd, keyPath, value, raw) {
|
|
727
|
+
function cmdConfigSet(cwd, keyPath, value, raw, options = {}) {
|
|
728
|
+
const dryRun = options.dryRun === true;
|
|
687
729
|
if (!keyPath) {
|
|
688
730
|
error('Usage: config-set <key.path> <value>', ERROR_REASON.USAGE);
|
|
689
731
|
}
|
|
@@ -733,6 +775,18 @@ function cmdConfigSet(cwd, keyPath, value, raw) {
|
|
|
733
775
|
// present, truthy-adjacent value that consumers must special-case — worst for
|
|
734
776
|
// secret keys where a leftover value can be passed as a real credential.
|
|
735
777
|
if (parsedValue === null) {
|
|
778
|
+
if (dryRun) {
|
|
779
|
+
const preview = previewUnsetConfigValue(cwd, kp);
|
|
780
|
+
if ((0, secrets_cjs_1.isSecretKey)(kp)) {
|
|
781
|
+
const maskedPrev = preview.previousValue === undefined
|
|
782
|
+
? undefined
|
|
783
|
+
: (0, secrets_cjs_1.maskSecret)(preview.previousValue);
|
|
784
|
+
output({ dry_run: true, would_unset: true, key: kp, value: null, previousValue: maskedPrev, masked: true }, raw, `${kp} unset (dry run)`);
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
output({ dry_run: true, would_unset: true, key: kp, value: null, previousValue: preview.previousValue }, raw, `${kp} unset (dry run)`);
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
736
790
|
const unsetResult = unsetConfigValue(cwd, kp);
|
|
737
791
|
if ((0, secrets_cjs_1.isSecretKey)(kp)) {
|
|
738
792
|
const maskedPrev = unsetResult.previousValue === undefined
|
|
@@ -787,6 +841,12 @@ function cmdConfigSet(cwd, keyPath, value, raw) {
|
|
|
787
841
|
error(`Invalid workflow.post_planning_gaps '${val}'. Must be a boolean (true or false).`);
|
|
788
842
|
}
|
|
789
843
|
}
|
|
844
|
+
// Compact Content mode gate (#4139)
|
|
845
|
+
if (kp === 'workflow.compact_content') {
|
|
846
|
+
if (typeof parsedValue !== 'boolean') {
|
|
847
|
+
error(`Invalid workflow.compact_content '${val}'. Must be a boolean (true or false).`);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
790
850
|
// Per-plan executor routing via agent_hint frontmatter (#1689)
|
|
791
851
|
if (kp === 'workflow.agent_hint_routing') {
|
|
792
852
|
if (typeof parsedValue !== 'boolean') {
|
|
@@ -835,6 +895,48 @@ function cmdConfigSet(cwd, keyPath, value, raw) {
|
|
|
835
895
|
error(`Invalid statusline.show_git '${val}'. Must be a boolean (true or false).`);
|
|
836
896
|
}
|
|
837
897
|
}
|
|
898
|
+
// Context-monitor fire-points (#4285) — a percentage of the context window
|
|
899
|
+
// REMAINING, so the domain is 0-100 and the hook compares them against
|
|
900
|
+
// `remaining_percentage`. Rejecting an out-of-domain value here keeps accept
|
|
901
|
+
// and honour in agreement ON THE DOMAIN: the hook falls back to its default
|
|
902
|
+
// for a value outside it, so reporting success would be a lie. That agreement
|
|
903
|
+
// is per-key and no wider — a value accepted here can still be superseded at
|
|
904
|
+
// read time by the hook's pair check, and a scoped write (GSD_PROJECT /
|
|
905
|
+
// GSD_WORKSTREAM) lands in a config the hook does not read at all. The PAIR
|
|
906
|
+
// (critical < warning) is deliberately NOT enforced here: config-set writes
|
|
907
|
+
// one key per call, so a two-step retune can be transiently inconsistent on
|
|
908
|
+
// disk and a check here would reject that intermediate write.
|
|
909
|
+
if (kp === 'hooks.context_warning_threshold' || kp === 'hooks.context_critical_threshold') {
|
|
910
|
+
if (typeof parsedValue !== 'number' || !Number.isFinite(parsedValue) || parsedValue < 0 || parsedValue > 100) {
|
|
911
|
+
error(`Invalid ${kp} '${val}'. Must be a number between 0 and 100 (percent of context window remaining).`);
|
|
912
|
+
}
|
|
913
|
+
// The two ENDPOINTS that are in range but can never form a valid pair are
|
|
914
|
+
// refused here rather than stored (#4285 review). `critical < warning` must
|
|
915
|
+
// hold at read time and BOTH sides are clamped to 0-100, so `warning: 0`
|
|
916
|
+
// has no legal partner (nothing is below 0) and `critical: 100` has none
|
|
917
|
+
// either (nothing above 100). Either one is silently discarded by the hook
|
|
918
|
+
// for EVERY value of the other key — verified: both resolve to the 35/25
|
|
919
|
+
// defaults against a present, absent, or extreme partner, while 0.001 and
|
|
920
|
+
// 99.999 are honoured.
|
|
921
|
+
//
|
|
922
|
+
// Storing a value the reader can never honour is exactly the
|
|
923
|
+
// accept-then-discard shape this codebase refuses elsewhere, so this fails
|
|
924
|
+
// at write time where the operator can see it. The pair itself is still NOT
|
|
925
|
+
// checked here — config-set writes one key per call, so a two-step retune
|
|
926
|
+
// is legitimately inconsistent on disk in between.
|
|
927
|
+
if (kp === 'hooks.context_warning_threshold' && parsedValue === 0) {
|
|
928
|
+
error(`Invalid ${kp} '${val}'. 0 is in range but unusable: the monitor requires `
|
|
929
|
+
+ `hooks.context_critical_threshold < hooks.context_warning_threshold, and no valid `
|
|
930
|
+
+ `critical value is below 0, so a warning of 0 would always fall back to the 35/25 `
|
|
931
|
+
+ `defaults. Use a value above 0.`);
|
|
932
|
+
}
|
|
933
|
+
if (kp === 'hooks.context_critical_threshold' && parsedValue === 100) {
|
|
934
|
+
error(`Invalid ${kp} '${val}'. 100 is in range but unusable: the monitor requires `
|
|
935
|
+
+ `hooks.context_critical_threshold < hooks.context_warning_threshold, and no valid `
|
|
936
|
+
+ `warning value is above 100, so a critical of 100 would always fall back to the `
|
|
937
|
+
+ `35/25 defaults. Use a value below 100.`);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
838
940
|
// Fallow scope + profile enum validation (#3424)
|
|
839
941
|
const VALID_FALLOW_SCOPES = ['phase', 'repo'];
|
|
840
942
|
if (kp === 'code_quality.fallow.scope')
|
|
@@ -921,6 +1023,19 @@ function cmdConfigSet(cwd, keyPath, value, raw) {
|
|
|
921
1023
|
}
|
|
922
1024
|
}
|
|
923
1025
|
}
|
|
1026
|
+
if (dryRun) {
|
|
1027
|
+
const preview = previewConfigValue(cwd, kp, parsedValue);
|
|
1028
|
+
if ((0, secrets_cjs_1.isSecretKey)(kp)) {
|
|
1029
|
+
const masked = (0, secrets_cjs_1.maskSecret)(parsedValue);
|
|
1030
|
+
const maskedPrev = preview.previousValue === undefined
|
|
1031
|
+
? undefined
|
|
1032
|
+
: (0, secrets_cjs_1.maskSecret)(preview.previousValue);
|
|
1033
|
+
output({ dry_run: true, would_update: true, key: kp, value: masked, previousValue: maskedPrev, masked: true }, raw, `${kp}=${masked} (dry run)`);
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
output({ dry_run: true, would_update: true, key: kp, value: parsedValue, previousValue: preview.previousValue }, raw, `${kp}=${String(parsedValue)} (dry run)`);
|
|
1037
|
+
return;
|
|
1038
|
+
}
|
|
924
1039
|
const setConfigValueResult = setConfigValue(cwd, kp, parsedValue);
|
|
925
1040
|
// Mask secrets in both JSON and text output. The plaintext is written
|
|
926
1041
|
// to config.json (that's where secrets live on disk); the CLI output
|
|
@@ -43,6 +43,11 @@ const phaseIdModule = require("./phase-id.cjs");
|
|
|
43
43
|
const planningWorkspace = require("./planning-workspace.cjs");
|
|
44
44
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
45
45
|
const shellCommandProjection = require("./shell-command-projection.cjs");
|
|
46
|
+
// planning-scope.cjs is a leaf module (no imports of its own — see its file
|
|
47
|
+
// header), so importing it here directly cannot introduce a cycle.
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
49
|
+
const planningScopeMod = require("./planning-scope.cjs");
|
|
50
|
+
const { SCOPE } = planningScopeMod;
|
|
46
51
|
// ─── Line-ending normalization ─────────────────────────────────────────────────
|
|
47
52
|
/**
|
|
48
53
|
* Normalize every line ending in `content` to a bare `\n`, ONCE — the shared
|
|
@@ -271,16 +276,38 @@ function transliterateForSlug(text) {
|
|
|
271
276
|
* Degrades on an unreadable directory instead of throwing: empty arrays,
|
|
272
277
|
* every flag false, scope UNREADABLE (mirroring scanPhasePlans's own
|
|
273
278
|
* degrade path).
|
|
279
|
+
*
|
|
280
|
+
* #4014 (epic #3473 B4-unreadable): this function's OWN readdirSync used to
|
|
281
|
+
* catch its own failure and then return `scope: scan.scope` — the scope of
|
|
282
|
+
* the UNRELATED, already-successful scanPhasePlans call — silently dropping
|
|
283
|
+
* that THIS read failed. The own-readdirSync is now routed through
|
|
284
|
+
* findContextMdIn's directory-string form (which never throws and reports
|
|
285
|
+
* its own SCOPE.UNREADABLE), and the two independently-scoped answers are
|
|
286
|
+
* combined into the worse of the two below — never letting a successful
|
|
287
|
+
* scan.scope mask this function's own failed read.
|
|
288
|
+
*
|
|
289
|
+
* The combination is written out as a two-value comparison rather than
|
|
290
|
+
* calling planning-snapshot.cts's `worstScope` directly: that module
|
|
291
|
+
* requires core-utils.cjs (for `findOrphanSummaries`) at its own top level,
|
|
292
|
+
* so importing it back here would create a tight, direct
|
|
293
|
+
* core-utils.cjs <-> planning-snapshot.cjs cycle — a materially different
|
|
294
|
+
* (and riskier) shape than this file's existing, documented lazy-access
|
|
295
|
+
* cyclic partners (planning-workspace.cjs, phase-id.cjs), which
|
|
296
|
+
* planning-snapshot.cts sits *above* in the dependency graph, not beside.
|
|
297
|
+
* `findContextMdIn`'s directory-string form can only ever report
|
|
298
|
+
* SCOPE.COMPLETE or SCOPE.UNREADABLE (a single readdirSync is binary — see
|
|
299
|
+
* its own doc comment), so per planning-snapshot.cts's SCOPE_SEVERITY
|
|
300
|
+
* ordering (UNREADABLE is maximal), `worstScope(scan.scope, ownScope)` is
|
|
301
|
+
* exactly `ownScope === UNREADABLE ? UNREADABLE : scan.scope` — the
|
|
302
|
+
* expression below is that identity, not a re-derivation of the ordering.
|
|
274
303
|
*/
|
|
275
304
|
function getPhaseFileStats(phaseDir) {
|
|
276
305
|
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment
|
|
277
306
|
const scanPhasePlans = require('./plan-scan.cjs');
|
|
278
307
|
const scan = scanPhasePlans(phaseDir);
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
catch {
|
|
308
|
+
const { files, scope: ownScope } = planningWorkspace.findContextMdIn(phaseDir);
|
|
309
|
+
const scope = ownScope === SCOPE.UNREADABLE ? SCOPE.UNREADABLE : scan.scope;
|
|
310
|
+
if (ownScope === SCOPE.UNREADABLE) {
|
|
284
311
|
return {
|
|
285
312
|
plans: scan.planFiles,
|
|
286
313
|
summaries: scan.summaryFiles,
|
|
@@ -288,7 +315,7 @@ function getPhaseFileStats(phaseDir) {
|
|
|
288
315
|
hasContext: false,
|
|
289
316
|
hasVerification: false,
|
|
290
317
|
hasReviews: false,
|
|
291
|
-
scope
|
|
318
|
+
scope,
|
|
292
319
|
};
|
|
293
320
|
}
|
|
294
321
|
const scopedFiles = phaseIdModule.scopeToPhase(files, node_path_1.default.basename(phaseDir));
|
|
@@ -299,7 +326,7 @@ function getPhaseFileStats(phaseDir) {
|
|
|
299
326
|
hasContext: planningWorkspace.findContextMdIn(scopedFiles) !== null,
|
|
300
327
|
hasVerification: scopedFiles.some(f => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md'),
|
|
301
328
|
hasReviews: scopedFiles.some(f => f.endsWith('-REVIEWS.md') || f === 'REVIEWS.md'),
|
|
302
|
-
scope
|
|
329
|
+
scope,
|
|
303
330
|
};
|
|
304
331
|
}
|
|
305
332
|
/**
|
|
@@ -435,7 +435,7 @@ function cmdClassify(cwd, options = {}, raw) {
|
|
|
435
435
|
}
|
|
436
436
|
let resolvedPath;
|
|
437
437
|
try {
|
|
438
|
-
resolvedPath = (0, security_cjs_1.requireSafePath)(filePath, cwd, 'SUMMARY file',
|
|
438
|
+
resolvedPath = (0, security_cjs_1.requireSafePath)(filePath, cwd, 'SUMMARY file', security_cjs_1.PathAcceptance.AbsoluteInsideRoot);
|
|
439
439
|
}
|
|
440
440
|
catch (e) {
|
|
441
441
|
// Emit a structured command error instead of leaking a raw stack trace.
|