@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
|
@@ -459,9 +459,18 @@ function normalizeNodePath(execPath, opts) {
|
|
|
459
459
|
// survives the upgrade. Derive <prefix> from the path itself (more reliable
|
|
460
460
|
// than HOMEBREW_PREFIX env — the path IS the install location) so every layout
|
|
461
461
|
// is covered by one branch instead of one per known prefix (#2185).
|
|
462
|
+
//
|
|
463
|
+
// #4137: rewrite only when the symlink exists; otherwise fall through to the
|
|
464
|
+
// raw execPath, exactly like the mise and volta branches. A keg-only/versioned
|
|
465
|
+
// formula (node@24 installed but never `brew link`ed) has no <prefix>/bin/node
|
|
466
|
+
// at all, so the unconditional rewrite handed every managed hook a path that
|
|
467
|
+
// fails at invocation — a rewrite must never turn a working keg path into an
|
|
468
|
+
// immediately broken one.
|
|
462
469
|
const homebrewMatch = normalizedForMatch.match(/^(.+)\/Cellar\/node(@\d+)?\/[^/]+\/bin\/node(\.exe)?$/i);
|
|
463
470
|
if (homebrewMatch) {
|
|
464
|
-
|
|
471
|
+
const homebrewStable = `${homebrewMatch[1]}/bin/node${homebrewMatch[3] || ''}`;
|
|
472
|
+
if (existsSync(homebrewStable))
|
|
473
|
+
return homebrewStable;
|
|
465
474
|
}
|
|
466
475
|
// mise pins a concrete node version at <data>/installs/node/<ver>/bin/node
|
|
467
476
|
// (Windows: <data>/installs/node/<ver>/node.exe). Node realpaths
|
|
@@ -802,16 +811,52 @@ function rewriteLegacyCodexHookBlock(content, absoluteRunner, opts) {
|
|
|
802
811
|
});
|
|
803
812
|
return { content: updated, changed };
|
|
804
813
|
}
|
|
814
|
+
function _installEngineSymlinkGuard() {
|
|
815
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment
|
|
816
|
+
const mod = require('./install-engine.cjs');
|
|
817
|
+
return mod;
|
|
818
|
+
}
|
|
805
819
|
function reconcileCodexHooksJsonEvent(targetDir, eventName, opts = {}) {
|
|
806
820
|
const hooksJsonPath = node_path_1.default.join(targetDir, 'hooks.json');
|
|
807
821
|
const managedCommand = typeof opts.managedCommand === 'string' ? opts.managedCommand : null;
|
|
808
822
|
const commandWindows = typeof opts.commandWindows === 'string' ? opts.commandWindows : null;
|
|
809
823
|
const matcher = typeof opts.matcher === 'string' ? opts.matcher : undefined;
|
|
810
824
|
const timeout = typeof opts.timeout === 'number' ? opts.timeout : undefined;
|
|
825
|
+
// #2586 Major 2: every Codex hooks.json writer funnels through this one
|
|
826
|
+
// function, and atomicWriteFileSync's final step is a rename(2) onto
|
|
827
|
+
// `hooksJsonPath` — which, when that path is a symlink, REPLACES the
|
|
828
|
+
// symlink with a plain file rather than writing through it. Refuse (with
|
|
829
|
+
// the same GSD_ALLOW_SYMLINKED_DEST opt-in every other install call site
|
|
830
|
+
// honors) before reading or writing, so a symlinked hooks.json is neither
|
|
831
|
+
// silently destroyed nor left the caller no escape hatch.
|
|
832
|
+
const symlinkGuard = _installEngineSymlinkGuard();
|
|
833
|
+
// The path this function actually reads/writes. Defaults to the nominal
|
|
834
|
+
// hooks.json path; reassigned below to the symlink's real target when the
|
|
835
|
+
// opt-in is active, so the write lands on the file the user's symlink
|
|
836
|
+
// points at instead of clobbering the symlink itself (see note below).
|
|
837
|
+
let effectiveHooksJsonPath = hooksJsonPath;
|
|
838
|
+
if (node_fs_1.default.existsSync(hooksJsonPath) && node_fs_1.default.lstatSync(hooksJsonPath).isSymbolicLink()) {
|
|
839
|
+
if (symlinkGuard.hasExistingSymlinkBetween(targetDir, hooksJsonPath, {
|
|
840
|
+
allowOptInFollow: symlinkGuard.isSymlinkedDestOptIn(),
|
|
841
|
+
})) {
|
|
842
|
+
throw new Error(`hooks.json at "${hooksJsonPath}" contains a symlink the install root "${targetDir}" does not trust — ` +
|
|
843
|
+
'refusing to read or write it. If this is an intentional user-owned symlink layout, re-run with ' +
|
|
844
|
+
'GSD_ALLOW_SYMLINKED_DEST=1.');
|
|
845
|
+
}
|
|
846
|
+
// hasExistingSymlinkBetween returned false only because the opt-in is
|
|
847
|
+
// active (a symlinked leaf always trips it otherwise) — so this IS a
|
|
848
|
+
// symlink and we are cleared to follow it. atomicWriteFileSync's final
|
|
849
|
+
// step is a rename(2) onto its target, which REPLACES an existing
|
|
850
|
+
// symlink at that path rather than writing through it; resolving to the
|
|
851
|
+
// real path here makes the read AND the write operate on the symlink's
|
|
852
|
+
// target, leaving the symlink itself untouched, matching what "follow"
|
|
853
|
+
// is supposed to mean.
|
|
854
|
+
effectiveHooksJsonPath = node_fs_1.default.realpathSync(hooksJsonPath);
|
|
855
|
+
}
|
|
811
856
|
let parsed = {};
|
|
812
857
|
let currentContent = null;
|
|
813
|
-
if (node_fs_1.default.existsSync(
|
|
814
|
-
const raw = node_fs_1.default.readFileSync(
|
|
858
|
+
if (node_fs_1.default.existsSync(effectiveHooksJsonPath)) {
|
|
859
|
+
const raw = node_fs_1.default.readFileSync(effectiveHooksJsonPath, 'utf8');
|
|
815
860
|
currentContent = raw;
|
|
816
861
|
if (raw.trim()) {
|
|
817
862
|
try {
|
|
@@ -845,6 +890,12 @@ function reconcileCodexHooksJsonEvent(targetDir, eventName, opts = {}) {
|
|
|
845
890
|
}
|
|
846
891
|
parsed['hooks'] = hookTable;
|
|
847
892
|
const eventEntries = Array.isArray(hookTable[eventName]) ? hookTable[eventName] : [];
|
|
893
|
+
// Minor 5 (#2586 review): an event key the user already had, already
|
|
894
|
+
// holding an empty array, must survive removal as an empty array — not be
|
|
895
|
+
// deleted outright. Deleting is only correct when OUR removal is what
|
|
896
|
+
// emptied a previously non-empty array. Tracked before the loop below can
|
|
897
|
+
// mutate anything.
|
|
898
|
+
const wasArrayEmpty = Array.isArray(hookTable[eventName]) && eventEntries.length === 0;
|
|
848
899
|
let removedLegacy = false;
|
|
849
900
|
const sanitizedEntries = [];
|
|
850
901
|
for (const entry of eventEntries) {
|
|
@@ -886,6 +937,11 @@ function reconcileCodexHooksJsonEvent(targetDir, eventName, opts = {}) {
|
|
|
886
937
|
if (sanitizedEntries.length > 0) {
|
|
887
938
|
hookTable[eventName] = sanitizedEntries;
|
|
888
939
|
}
|
|
940
|
+
else if (wasArrayEmpty) {
|
|
941
|
+
// Nothing of ours was ever here to remove — preserve the user's own
|
|
942
|
+
// empty array exactly as found (Minor 5).
|
|
943
|
+
hookTable[eventName] = [];
|
|
944
|
+
}
|
|
889
945
|
else {
|
|
890
946
|
delete hookTable[eventName];
|
|
891
947
|
}
|
|
@@ -898,7 +954,7 @@ function reconcileCodexHooksJsonEvent(targetDir, eventName, opts = {}) {
|
|
|
898
954
|
const changed = currentContent !== nextContent;
|
|
899
955
|
const shouldWrite = changed && (currentContent !== null || Object.keys(parsed).length > 0);
|
|
900
956
|
if (shouldWrite) {
|
|
901
|
-
atomicWriteFileSync(
|
|
957
|
+
atomicWriteFileSync(effectiveHooksJsonPath, nextContent, 'utf8');
|
|
902
958
|
}
|
|
903
959
|
return { changed: changed || removedLegacy, wrote: shouldWrite, path: hooksJsonPath };
|
|
904
960
|
}
|
|
@@ -1015,6 +1071,136 @@ function removeCodexHooksJsonEvent(targetDir, eventName) {
|
|
|
1015
1071
|
function removeCodexHooksJsonSessionStart(targetDir) {
|
|
1016
1072
|
return reconcileCodexHooksJsonSessionStart(targetDir, { managedCommand: null });
|
|
1017
1073
|
}
|
|
1074
|
+
// Literal, version-stable markers every shipped gsd-context-monitor.js
|
|
1075
|
+
// carries. Stable across the {{GSD_VERSION}} and runtime-path substitutions
|
|
1076
|
+
// the Codex copy step applies (#2586 design doc "Ownership check" — a raw
|
|
1077
|
+
// content hash would differ per runtime/version by construction, so a marker
|
|
1078
|
+
// check is used instead of manifest-membership, which has a bootstrap gap on
|
|
1079
|
+
// the exact case that matters most: a pre-#2586 install's manifest never
|
|
1080
|
+
// recorded this file at all).
|
|
1081
|
+
const CODEX_CONTEXT_MONITOR_OWNERSHIP_MARKERS = [
|
|
1082
|
+
'#!/usr/bin/env node',
|
|
1083
|
+
'// gsd-hook-version:',
|
|
1084
|
+
'// Context Monitor - PostToolUse/AfterTool hook',
|
|
1085
|
+
];
|
|
1086
|
+
function isGsdOwnedCodexContextMonitorScript(filePath) {
|
|
1087
|
+
let content;
|
|
1088
|
+
try {
|
|
1089
|
+
content = node_fs_1.default.readFileSync(filePath, 'utf8');
|
|
1090
|
+
}
|
|
1091
|
+
catch {
|
|
1092
|
+
return false;
|
|
1093
|
+
}
|
|
1094
|
+
// The .cmd shim (buildCodexHookWindowsShimIR) is a tiny generated batch
|
|
1095
|
+
// wrapper, not the JS file itself — it never carries the JS markers above,
|
|
1096
|
+
// so it gets its own narrower, still-specific signature: the exact
|
|
1097
|
+
// "@ECHO OFF" / "@SETLOCAL" preamble the shim generator emits, invoking a
|
|
1098
|
+
// script path that ends in gsd-context-monitor.js.
|
|
1099
|
+
if (filePath.endsWith('.cmd')) {
|
|
1100
|
+
return content.startsWith('@ECHO OFF') && content.includes('@SETLOCAL')
|
|
1101
|
+
&& /gsd-context-monitor\.js/.test(content);
|
|
1102
|
+
}
|
|
1103
|
+
return CODEX_CONTEXT_MONITOR_OWNERSHIP_MARKERS.every((marker) => content.includes(marker));
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Scan every event in hooks.json for a surviving reference to the
|
|
1107
|
+
* context-monitor script or its Windows .cmd shim, by basename — not scoped
|
|
1108
|
+
* to CODEX_EXTENDED_HOOK_EVENTS, so a user who hand-registered it under an
|
|
1109
|
+
* unrelated event key is still detected as "referenced" and the script is
|
|
1110
|
+
* preserved.
|
|
1111
|
+
*/
|
|
1112
|
+
function hooksJsonReferencesCodexContextMonitor(targetDir) {
|
|
1113
|
+
const hooksJsonPath = node_path_1.default.join(targetDir, 'hooks.json');
|
|
1114
|
+
if (!node_fs_1.default.existsSync(hooksJsonPath))
|
|
1115
|
+
return false;
|
|
1116
|
+
let raw;
|
|
1117
|
+
try {
|
|
1118
|
+
raw = node_fs_1.default.readFileSync(hooksJsonPath, 'utf8');
|
|
1119
|
+
}
|
|
1120
|
+
catch {
|
|
1121
|
+
return true; // unreadable — conservatively assume referenced, never delete
|
|
1122
|
+
}
|
|
1123
|
+
if (!raw.trim())
|
|
1124
|
+
return false;
|
|
1125
|
+
let parsed;
|
|
1126
|
+
try {
|
|
1127
|
+
parsed = JSON.parse(raw);
|
|
1128
|
+
}
|
|
1129
|
+
catch {
|
|
1130
|
+
return true; // unparseable — conservatively assume referenced
|
|
1131
|
+
}
|
|
1132
|
+
if (!parsed || typeof parsed !== 'object')
|
|
1133
|
+
return false;
|
|
1134
|
+
const hooks = parsed['hooks'];
|
|
1135
|
+
const table = hooks && typeof hooks === 'object' && !Array.isArray(hooks)
|
|
1136
|
+
? hooks
|
|
1137
|
+
: parsed;
|
|
1138
|
+
for (const key of Object.keys(table)) {
|
|
1139
|
+
const entries = table[key];
|
|
1140
|
+
if (!Array.isArray(entries))
|
|
1141
|
+
continue;
|
|
1142
|
+
for (const entry of entries) {
|
|
1143
|
+
if (!entry || typeof entry !== 'object')
|
|
1144
|
+
continue;
|
|
1145
|
+
const entryHooks = entry['hooks'];
|
|
1146
|
+
const hookList = Array.isArray(entryHooks) ? entryHooks : [entry];
|
|
1147
|
+
for (const hook of hookList) {
|
|
1148
|
+
if (!hook || typeof hook !== 'object')
|
|
1149
|
+
continue;
|
|
1150
|
+
const values = [
|
|
1151
|
+
hook['command'],
|
|
1152
|
+
hook['commandWindows'],
|
|
1153
|
+
];
|
|
1154
|
+
for (const value of values) {
|
|
1155
|
+
if (typeof value === 'string' && /gsd-context-monitor(\.js|\.cmd)?/.test(value)) {
|
|
1156
|
+
return true;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
return false;
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* #2586 must-have #4/#8: after hooks.json registrations for
|
|
1166
|
+
* CODEX_EXTENDED_HOOK_EVENTS have been reconciled away (by the caller, via
|
|
1167
|
+
* removeCodexHooksJsonEvent), delete `hooks/gsd-context-monitor.js` and its
|
|
1168
|
+
* `.cmd` shim ONLY when (a) no surviving hooks.json registration under ANY
|
|
1169
|
+
* event still references either basename, and (b) the on-disk file carries
|
|
1170
|
+
* GSD's own ownership markers (a user's hand-edited or unrelated file at that
|
|
1171
|
+
* path is left alone). Each file is deleted independently — a failure
|
|
1172
|
+
* deleting one is reported as a warning and never rolls back the (already
|
|
1173
|
+
* safe, already-written) hooks.json deregistration the caller performed
|
|
1174
|
+
* first.
|
|
1175
|
+
*/
|
|
1176
|
+
function cleanupOrphanedCodexContextMonitorScript(targetDir) {
|
|
1177
|
+
const result = { deleted: [], warnings: [], stillReferenced: false };
|
|
1178
|
+
if (hooksJsonReferencesCodexContextMonitor(targetDir)) {
|
|
1179
|
+
result.stillReferenced = true;
|
|
1180
|
+
return result;
|
|
1181
|
+
}
|
|
1182
|
+
const candidates = [
|
|
1183
|
+
node_path_1.default.join(targetDir, 'hooks', 'gsd-context-monitor.js'),
|
|
1184
|
+
node_path_1.default.join(targetDir, 'hooks', 'gsd-context-monitor.cmd'),
|
|
1185
|
+
];
|
|
1186
|
+
for (const candidate of candidates) {
|
|
1187
|
+
if (!node_fs_1.default.existsSync(candidate))
|
|
1188
|
+
continue;
|
|
1189
|
+
if (!isGsdOwnedCodexContextMonitorScript(candidate))
|
|
1190
|
+
continue;
|
|
1191
|
+
try {
|
|
1192
|
+
node_fs_1.default.unlinkSync(candidate);
|
|
1193
|
+
result.deleted.push(candidate);
|
|
1194
|
+
}
|
|
1195
|
+
catch (err) {
|
|
1196
|
+
result.warnings.push({
|
|
1197
|
+
path: candidate,
|
|
1198
|
+
reason: err && err.message ? err.message : String(err),
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
return result;
|
|
1203
|
+
}
|
|
1018
1204
|
function buildHookCommand(configDir, hookName, opts) {
|
|
1019
1205
|
if (!opts)
|
|
1020
1206
|
opts = {};
|
|
@@ -1311,6 +1497,128 @@ function reconcileCursorHooksJson(hooksJsonPath, managedEntries) {
|
|
|
1311
1497
|
}
|
|
1312
1498
|
return { changed: changed, wrote: shouldWrite, path: hooksJsonPath };
|
|
1313
1499
|
}
|
|
1500
|
+
/**
|
|
1501
|
+
* Stage the `hooks/lib/` helpers a set of staged hook scripts require, walking
|
|
1502
|
+
* the require graph TRANSITIVELY to a fixed point.
|
|
1503
|
+
*
|
|
1504
|
+
* Extracted from writeCursorHooksJson (#3911 review, commit 704859e9c) so the
|
|
1505
|
+
* reduced Codex hook bundle can share one implementation instead of growing a
|
|
1506
|
+
* second, divergent copy (#4087 / #4098). Both reduced bundles hand-pick which
|
|
1507
|
+
* hook SCRIPTS they ship, and neither can hand-pick their helpers correctly for
|
|
1508
|
+
* long: `hooks/lib/hook-exit.js` requires `./cli-exit.js`, which requires
|
|
1509
|
+
* `./exit-code-registry.js` — with NO `./lib/` prefix, because from inside
|
|
1510
|
+
* `lib/` the sibling is already local. A single-pass scan for the `./lib/…`
|
|
1511
|
+
* spelling used FROM a hook script stages hook-exit.js and stops, and the
|
|
1512
|
+
* installed hook then dies on MODULE_NOT_FOUND at load, before its own
|
|
1513
|
+
* try/catch, on every event it is registered for.
|
|
1514
|
+
*
|
|
1515
|
+
* Scans CONTENT rather than paths so a caller can seed from whatever it staged,
|
|
1516
|
+
* transformed or not, without this helper knowing the caller's layout.
|
|
1517
|
+
*
|
|
1518
|
+
* @returns the lib filenames actually staged, in staging order.
|
|
1519
|
+
*/
|
|
1520
|
+
function stageTransitiveHookLibs(opts) {
|
|
1521
|
+
const { seedSources, srcLibDir, destLibDir, runtimeLabel, transform } = opts;
|
|
1522
|
+
const requiredLibFiles = new Set();
|
|
1523
|
+
const scannedLibFiles = new Set();
|
|
1524
|
+
const staged = [];
|
|
1525
|
+
// `./X` means DIFFERENT things depending on where the scanned file lives, and
|
|
1526
|
+
// conflating them stages the wrong file. From a hook SCRIPT in hooks/, a bare
|
|
1527
|
+
// `./X` is a sibling hook-level artifact — Codex's gsd-check-update-worker.js
|
|
1528
|
+
// requires `./managed-hooks-registry.cjs`, which lives in hooks/, not
|
|
1529
|
+
// hooks/lib/ — so only the explicit `./lib/X` spelling is a lib requirement.
|
|
1530
|
+
// From inside a LIB file, the sibling is already local, so `./X` IS a lib
|
|
1531
|
+
// requirement (hook-exit.js -> ./cli-exit.js -> ./exit-code-registry.js); that
|
|
1532
|
+
// is the case 704859e9c added and it must keep working. Cursor never exposed
|
|
1533
|
+
// the difference because none of its staged scripts has a bare sibling
|
|
1534
|
+
// require; Codex's does, and the fail-loud guard below caught it immediately
|
|
1535
|
+
// by demanding managed-hooks-registry.cjs out of hooks/dist/lib.
|
|
1536
|
+
// Fresh per call: a module-level /g regex carries lastIndex across calls and
|
|
1537
|
+
// would silently skip matches on the second install in one process.
|
|
1538
|
+
const seedRequireRe = /require\(\s*['"]\.\/lib\/([A-Za-z0-9._-]+)['"]\s*\)/g;
|
|
1539
|
+
const libRequireRe = /require\(\s*['"]\.\/(?:lib\/)?([A-Za-z0-9._-]+)['"]\s*\)/g;
|
|
1540
|
+
// A NESTED helper path is outside the flat layout hooks/lib/ has and the
|
|
1541
|
+
// build emits, and the character classes above cannot express it — so it
|
|
1542
|
+
// would be a SILENT miss, staging nothing and shipping a hook that dies at
|
|
1543
|
+
// load. Detected separately and refused loudly instead: a silent miss is the
|
|
1544
|
+
// failure mode this whole function exists to remove (review of #4087).
|
|
1545
|
+
const nestedRequireRe = /require\(\s*['"]\.\/lib\/[A-Za-z0-9._-]+\/[^'"]*['"]\s*\)/;
|
|
1546
|
+
const scanForLibRequires = (source, fromLib) => {
|
|
1547
|
+
if (nestedRequireRe.test(source)) {
|
|
1548
|
+
throw new Error(`A staged ${runtimeLabel} hook requires a NESTED hooks/lib path. hooks/lib/ is flat and `
|
|
1549
|
+
+ 'this stager only resolves flat helper names, so the nested helper would never be '
|
|
1550
|
+
+ 'staged and the hook would throw MODULE_NOT_FOUND at load. Flatten the helper or '
|
|
1551
|
+
+ 'extend this stager deliberately.');
|
|
1552
|
+
}
|
|
1553
|
+
const re = fromLib ? libRequireRe : seedRequireRe;
|
|
1554
|
+
re.lastIndex = 0;
|
|
1555
|
+
let m;
|
|
1556
|
+
while ((m = re.exec(source)) !== null) {
|
|
1557
|
+
const candidate = m[1];
|
|
1558
|
+
// A capture with no alphanumeric character is not a module name — it is
|
|
1559
|
+
// prose. This scan reads whole file text, comments included, and
|
|
1560
|
+
// hooks/lib/injection-patterns.js's own header documents this mechanism
|
|
1561
|
+
// with the literal string `require('./lib/...')`, which captures `...`
|
|
1562
|
+
// and would send the resolver hunting for `hooks/lib/...` and fail the
|
|
1563
|
+
// install (measured; that helper is not staged for either reduced bundle
|
|
1564
|
+
// today, so it is latent rather than live).
|
|
1565
|
+
//
|
|
1566
|
+
// KNOWN LIMIT, disclosed rather than papered over: this does NOT make the
|
|
1567
|
+
// scan comment-aware. A comment naming a REAL helper — `require(
|
|
1568
|
+
// './lib/git-cmd.js')` in prose — still registers it and would over-stage
|
|
1569
|
+
// that helper. Closing that needs a comment-stripping pass; the
|
|
1570
|
+
// line-based stripper in scripts/lint-hooks-runtime-build-seam.cjs is the
|
|
1571
|
+
// precedent (its header explains why the naive two-regex strip corrupts
|
|
1572
|
+
// these very files), but promoting a lint-script helper into installer
|
|
1573
|
+
// runtime code is a larger change than this fix.
|
|
1574
|
+
if (!/[A-Za-z0-9]/.test(candidate))
|
|
1575
|
+
continue;
|
|
1576
|
+
requiredLibFiles.add(candidate);
|
|
1577
|
+
}
|
|
1578
|
+
};
|
|
1579
|
+
for (const source of seedSources)
|
|
1580
|
+
scanForLibRequires(source, false);
|
|
1581
|
+
if (requiredLibFiles.size === 0)
|
|
1582
|
+
return staged;
|
|
1583
|
+
node_fs_1.default.mkdirSync(destLibDir, { recursive: true });
|
|
1584
|
+
// Iterate to a fixed point: staging a lib file can add MORE required lib
|
|
1585
|
+
// files (its own requires), which must themselves be staged and scanned.
|
|
1586
|
+
let libFile = [...requiredLibFiles].find((f) => !scannedLibFiles.has(f));
|
|
1587
|
+
while (libFile !== undefined) {
|
|
1588
|
+
scannedLibFiles.add(libFile);
|
|
1589
|
+
// Node's own extension resolution: `require('./lib/x')` is a valid, working
|
|
1590
|
+
// CommonJS spelling today, and matching only the extension-bearing form
|
|
1591
|
+
// resolved `x` literally, found nothing, and failed the install on a
|
|
1592
|
+
// legitimate require (review of #4087). Try the bare name first so an
|
|
1593
|
+
// extension-bearing capture still wins, then .js/.cjs.
|
|
1594
|
+
let resolvedName;
|
|
1595
|
+
for (const candidate of [libFile, `${libFile}.js`, `${libFile}.cjs`]) {
|
|
1596
|
+
if (node_fs_1.default.existsSync(node_path_1.default.join(srcLibDir, candidate))) {
|
|
1597
|
+
resolvedName = candidate;
|
|
1598
|
+
break;
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
const libSrc = node_path_1.default.join(srcLibDir, resolvedName ?? libFile);
|
|
1602
|
+
if (resolvedName === undefined) {
|
|
1603
|
+
// FAIL LOUD. Skipping here would ship hook scripts whose top-level
|
|
1604
|
+
// require() throws before their own try/catch, wedging every session —
|
|
1605
|
+
// and the install would still exit 0, so nobody would know until a user
|
|
1606
|
+
// hit it. A missing helper source is a packaging bug; surface it.
|
|
1607
|
+
throw new Error(`hooks/lib/${libFile} is required by a staged ${runtimeLabel} hook but is missing from ${srcLibDir}. `
|
|
1608
|
+
+ 'Installing would ship a hook that throws MODULE_NOT_FOUND at load.');
|
|
1609
|
+
}
|
|
1610
|
+
let libContent = node_fs_1.default.readFileSync(libSrc, 'utf8');
|
|
1611
|
+
if (transform)
|
|
1612
|
+
libContent = transform(libContent);
|
|
1613
|
+
// Written under its RESOLVED name so an extensionless require still lands a
|
|
1614
|
+
// file Node can resolve at the destination.
|
|
1615
|
+
node_fs_1.default.writeFileSync(node_path_1.default.join(destLibDir, resolvedName), libContent);
|
|
1616
|
+
staged.push(resolvedName);
|
|
1617
|
+
scanForLibRequires(libContent, true);
|
|
1618
|
+
libFile = [...requiredLibFiles].find((f) => !scannedLibFiles.has(f));
|
|
1619
|
+
}
|
|
1620
|
+
return staged;
|
|
1621
|
+
}
|
|
1314
1622
|
function writeCursorHooksJson(targetDir, src, opts) {
|
|
1315
1623
|
opts = opts || {};
|
|
1316
1624
|
const hooksDir = node_path_1.default.join(targetDir, 'hooks');
|
|
@@ -1348,43 +1656,13 @@ function writeCursorHooksJson(targetDir, src, opts) {
|
|
|
1348
1656
|
// "./lib/X" requires, and every lib file staged is itself scanned for further
|
|
1349
1657
|
// "./lib/X" OR bare "./X" (sibling-within-lib) requires, so the requirement
|
|
1350
1658
|
// graph is derived to a fixed point instead of one hand-tuned level deep.
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
requiredLibFiles.add(m[1]);
|
|
1359
|
-
}
|
|
1360
|
-
for (const script of installedScripts) {
|
|
1361
|
-
scanForLibRequires(node_fs_1.default.readFileSync(node_path_1.default.join(hooksDir, script), 'utf8'));
|
|
1362
|
-
}
|
|
1363
|
-
if (requiredLibFiles.size > 0) {
|
|
1364
|
-
const srcLibDir = node_path_1.default.join(srcHooksDir, 'lib');
|
|
1365
|
-
const destLibDir = node_path_1.default.join(hooksDir, 'lib');
|
|
1366
|
-
node_fs_1.default.mkdirSync(destLibDir, { recursive: true });
|
|
1367
|
-
// Iterate to a fixed point: staging a lib file can add MORE required lib
|
|
1368
|
-
// files (its own requires), which must themselves be staged and scanned.
|
|
1369
|
-
let libFile = [...requiredLibFiles].find((f) => !scannedLibFiles.has(f));
|
|
1370
|
-
while (libFile !== undefined) {
|
|
1371
|
-
scannedLibFiles.add(libFile);
|
|
1372
|
-
const libSrc = node_path_1.default.join(srcLibDir, libFile);
|
|
1373
|
-
if (!node_fs_1.default.existsSync(libSrc)) {
|
|
1374
|
-
// FAIL LOUD. Skipping here would ship hook scripts whose top-level
|
|
1375
|
-
// require() throws before their own try/catch, wedging every session —
|
|
1376
|
-
// and the install would still exit 0, so nobody would know until a user
|
|
1377
|
-
// hit it. A missing helper source is a packaging bug; surface it.
|
|
1378
|
-
throw new Error(`hooks/lib/${libFile} is required by a staged Cursor hook but is missing from ${srcLibDir}. `
|
|
1379
|
-
+ 'Installing would ship a hook that throws MODULE_NOT_FOUND at load.');
|
|
1380
|
-
}
|
|
1381
|
-
let libContent = node_fs_1.default.readFileSync(libSrc, 'utf8');
|
|
1382
|
-
libContent = libContent.replace(/gsd:/gi, 'gsd-');
|
|
1383
|
-
node_fs_1.default.writeFileSync(node_path_1.default.join(destLibDir, libFile), libContent);
|
|
1384
|
-
scanForLibRequires(libContent);
|
|
1385
|
-
libFile = [...requiredLibFiles].find((f) => !scannedLibFiles.has(f));
|
|
1386
|
-
}
|
|
1387
|
-
}
|
|
1659
|
+
stageTransitiveHookLibs({
|
|
1660
|
+
seedSources: [...installedScripts].map((script) => node_fs_1.default.readFileSync(node_path_1.default.join(hooksDir, script), 'utf8')),
|
|
1661
|
+
srcLibDir: node_path_1.default.join(srcHooksDir, 'lib'),
|
|
1662
|
+
destLibDir: node_path_1.default.join(hooksDir, 'lib'),
|
|
1663
|
+
runtimeLabel: 'Cursor',
|
|
1664
|
+
transform: (content) => content.replace(/gsd:/gi, 'gsd-'),
|
|
1665
|
+
});
|
|
1388
1666
|
// #2717: write the CommonJS marker into hooks/ alongside the staged .js
|
|
1389
1667
|
// scripts. Cursor sets skipSharedHooksInstall, so it never reaches
|
|
1390
1668
|
// installSharedHooksBundle (the only other writer of this marker); without
|
|
@@ -1587,6 +1865,26 @@ function writeWindsurfHooksJson(targetDir, src, opts) {
|
|
|
1587
1865
|
installedScripts.add(script);
|
|
1588
1866
|
}
|
|
1589
1867
|
}
|
|
1868
|
+
// Stage the hooks/lib/ helpers these scripts require (#4087 review). Windsurf
|
|
1869
|
+
// sets hostBehaviors.skipSharedHooksInstall, so like Cursor it never reaches
|
|
1870
|
+
// installSharedHooksBundle — the only other stager of hooks/lib — and it was
|
|
1871
|
+
// staging neither. Both Cascade guards require helpers at module load:
|
|
1872
|
+
// gsd-windsurf-pre-write.js requires ./lib/hook-exit.js and ./lib/git-probe.js,
|
|
1873
|
+
// gsd-windsurf-pre-command.js requires ./lib/hook-exit.js. Measured against a
|
|
1874
|
+
// real `--windsurf --global` install before this call existed: the installer
|
|
1875
|
+
// exited 0, hooks/ held only the two scripts, and running either one exited 1
|
|
1876
|
+
// with "Cannot find module './lib/hook-exit.js'" — the same failure #4087
|
|
1877
|
+
// reports for Codex, on every pre_write_code / pre_run_command event.
|
|
1878
|
+
//
|
|
1879
|
+
// The transform matches the one applied to the scripts above: a helper must be
|
|
1880
|
+
// rewritten the same way as its caller or the two disagree on the spelling.
|
|
1881
|
+
stageTransitiveHookLibs({
|
|
1882
|
+
seedSources: [...installedScripts].map((script) => node_fs_1.default.readFileSync(node_path_1.default.join(hooksDir, script), 'utf8')),
|
|
1883
|
+
srcLibDir: node_path_1.default.join(srcHooksDir, 'lib'),
|
|
1884
|
+
destLibDir: node_path_1.default.join(hooksDir, 'lib'),
|
|
1885
|
+
runtimeLabel: 'Windsurf',
|
|
1886
|
+
transform: (content) => content.replace(/gsd:/gi, 'gsd-'),
|
|
1887
|
+
});
|
|
1590
1888
|
// #2717: write the CommonJS marker into hooks/ alongside the staged .js
|
|
1591
1889
|
// scripts. Windsurf sets skipSharedHooksInstall, so it never reaches
|
|
1592
1890
|
// installSharedHooksBundle (the only other writer of this marker); without
|
|
@@ -1737,6 +2035,37 @@ function applySettingsJsonHooks(settings, opts) {
|
|
|
1737
2035
|
if (!settings.hooks.SessionStart) {
|
|
1738
2036
|
settings.hooks.SessionStart = [];
|
|
1739
2037
|
}
|
|
2038
|
+
// #3981: Claude Code treats a timed-out hook as NON-blocking — the tool
|
|
2039
|
+
// call continues through the normal permission flow. The blocking
|
|
2040
|
+
// PreToolUse guards therefore need a budget a host stall cannot exceed,
|
|
2041
|
+
// not one sized to the hook's own ~0.1 s runtime. Observed stalls reached
|
|
2042
|
+
// 84.3 s; 120 s is the top of the issue's prescribed 60–120 range and
|
|
2043
|
+
// returns every observed verdict. Registration below uses this constant,
|
|
2044
|
+
// and the migration pass right here raises existing managed entries.
|
|
2045
|
+
const BLOCKING_GUARD_TIMEOUT_S = 120;
|
|
2046
|
+
const blockingGuardNames = [
|
|
2047
|
+
'gsd-prompt-guard',
|
|
2048
|
+
'gsd-workflow-guard',
|
|
2049
|
+
'gsd-worktree-path-guard',
|
|
2050
|
+
'gsd-agent-isolation-guard',
|
|
2051
|
+
'gsd-write-guard',
|
|
2052
|
+
'gsd-secret-read-guard',
|
|
2053
|
+
'gsd-validate-commit',
|
|
2054
|
+
];
|
|
2055
|
+
for (const entries of Object.values(settings.hooks)) {
|
|
2056
|
+
if (!Array.isArray(entries))
|
|
2057
|
+
continue;
|
|
2058
|
+
for (const entry of entries) {
|
|
2059
|
+
if (!entry || !Array.isArray(entry.hooks))
|
|
2060
|
+
continue;
|
|
2061
|
+
for (const h of entry.hooks) {
|
|
2062
|
+
if (blockingGuardNames.some((name) => referencesHook(h, name)) &&
|
|
2063
|
+
h.timeout === 5) {
|
|
2064
|
+
h.timeout = BLOCKING_GUARD_TIMEOUT_S;
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
1740
2069
|
const hasGsdUpdateHook = settings.hooks.SessionStart.some((entry) => entry.hooks && entry.hooks.some((h) => referencesHook(h, 'gsd-check-update')));
|
|
1741
2070
|
// Guard: only register if the hook file was actually installed (#1754).
|
|
1742
2071
|
// When hooks/dist/ is missing from the npm package (as in v1.32.0), the
|
|
@@ -1817,7 +2146,7 @@ function applySettingsJsonHooks(settings, opts) {
|
|
|
1817
2146
|
{
|
|
1818
2147
|
type: 'command',
|
|
1819
2148
|
command: promptGuardCommand,
|
|
1820
|
-
timeout:
|
|
2149
|
+
timeout: BLOCKING_GUARD_TIMEOUT_S
|
|
1821
2150
|
}
|
|
1822
2151
|
]
|
|
1823
2152
|
});
|
|
@@ -1894,7 +2223,7 @@ function applySettingsJsonHooks(settings, opts) {
|
|
|
1894
2223
|
{
|
|
1895
2224
|
type: 'command',
|
|
1896
2225
|
command: workflowGuardCommand,
|
|
1897
|
-
timeout:
|
|
2226
|
+
timeout: BLOCKING_GUARD_TIMEOUT_S
|
|
1898
2227
|
}
|
|
1899
2228
|
]
|
|
1900
2229
|
});
|
|
@@ -1919,7 +2248,7 @@ function applySettingsJsonHooks(settings, opts) {
|
|
|
1919
2248
|
{
|
|
1920
2249
|
type: 'command',
|
|
1921
2250
|
command: worktreePathGuardCommand,
|
|
1922
|
-
timeout:
|
|
2251
|
+
timeout: BLOCKING_GUARD_TIMEOUT_S
|
|
1923
2252
|
}
|
|
1924
2253
|
]
|
|
1925
2254
|
});
|
|
@@ -1949,7 +2278,7 @@ function applySettingsJsonHooks(settings, opts) {
|
|
|
1949
2278
|
{
|
|
1950
2279
|
type: 'command',
|
|
1951
2280
|
command: agentIsolationGuardCommand,
|
|
1952
|
-
timeout:
|
|
2281
|
+
timeout: BLOCKING_GUARD_TIMEOUT_S
|
|
1953
2282
|
}
|
|
1954
2283
|
]
|
|
1955
2284
|
});
|
|
@@ -1976,7 +2305,7 @@ function applySettingsJsonHooks(settings, opts) {
|
|
|
1976
2305
|
{
|
|
1977
2306
|
type: 'command',
|
|
1978
2307
|
command: writeGuardCommand,
|
|
1979
|
-
timeout:
|
|
2308
|
+
timeout: BLOCKING_GUARD_TIMEOUT_S
|
|
1980
2309
|
}
|
|
1981
2310
|
]
|
|
1982
2311
|
});
|
|
@@ -1985,6 +2314,33 @@ function applySettingsJsonHooks(settings, opts) {
|
|
|
1985
2314
|
else if (!hasWriteGuardHook && !node_fs_1.default.existsSync(writeGuardFile)) {
|
|
1986
2315
|
console.warn(` ${yellow}⚠${reset} Skipped write guard hook — gsd-write-guard.js not found at target`);
|
|
1987
2316
|
}
|
|
2317
|
+
// Configure PreToolUse hook for secret-file read protection (#4221).
|
|
2318
|
+
// Hard-blocks Read/Grep/Bash reads of .env, .env.<suffix> and .secrets.
|
|
2319
|
+
// Replaces the Read(.env*) permission deny rules the installer used to
|
|
2320
|
+
// write (#768): on Claude Code >= 2.1.259 ANY Read() deny rule makes every
|
|
2321
|
+
// `cd DIR && grep …` compound prompt for approval, even in auto mode; a
|
|
2322
|
+
// hook denial is not a permission rule and never arms that check.
|
|
2323
|
+
const secretReadGuardCommand = isGlobal
|
|
2324
|
+
? buildHookCommand(targetDir, 'gsd-secret-read-guard.js', hookOpts)
|
|
2325
|
+
: localCmd('gsd-secret-read-guard.js');
|
|
2326
|
+
const hasSecretReadGuardHook = settings.hooks[preToolEvent].some((entry) => entry.hooks && entry.hooks.some((h) => referencesHook(h, 'gsd-secret-read-guard')));
|
|
2327
|
+
const secretReadGuardFile = node_path_1.default.join(targetDir, 'hooks', 'gsd-secret-read-guard.js');
|
|
2328
|
+
if (!hasSecretReadGuardHook && node_fs_1.default.existsSync(secretReadGuardFile) && secretReadGuardCommand) {
|
|
2329
|
+
settings.hooks[preToolEvent].push({
|
|
2330
|
+
matcher: 'Read|Grep|Bash',
|
|
2331
|
+
hooks: [
|
|
2332
|
+
{
|
|
2333
|
+
type: 'command',
|
|
2334
|
+
command: secretReadGuardCommand,
|
|
2335
|
+
timeout: BLOCKING_GUARD_TIMEOUT_S
|
|
2336
|
+
}
|
|
2337
|
+
]
|
|
2338
|
+
});
|
|
2339
|
+
console.log(` ${green}✓${reset} Configured secret read guard hook (.env / .secrets read protection)`);
|
|
2340
|
+
}
|
|
2341
|
+
else if (!hasSecretReadGuardHook && !node_fs_1.default.existsSync(secretReadGuardFile)) {
|
|
2342
|
+
console.warn(` ${yellow}⚠${reset} Skipped secret read guard hook — gsd-secret-read-guard.js not found at target`);
|
|
2343
|
+
}
|
|
1988
2344
|
// Configure commit validation hook (Conventional Commits enforcement, opt-in)
|
|
1989
2345
|
const validateCommitCommand = isGlobal
|
|
1990
2346
|
? buildHookCommand(targetDir, 'gsd-validate-commit.sh', hookOpts)
|
|
@@ -2001,7 +2357,7 @@ function applySettingsJsonHooks(settings, opts) {
|
|
|
2001
2357
|
{
|
|
2002
2358
|
type: 'command',
|
|
2003
2359
|
command: validateCommitCommand,
|
|
2004
|
-
timeout:
|
|
2360
|
+
timeout: BLOCKING_GUARD_TIMEOUT_S
|
|
2005
2361
|
}
|
|
2006
2362
|
]
|
|
2007
2363
|
});
|
|
@@ -2330,6 +2686,7 @@ function buildKimiHooksTomlBlock(targetDir, opts) {
|
|
|
2330
2686
|
{ event: 'PreToolUse', command: cmd('gsd-read-guard.js'), matcher: 'WriteFile|StrReplaceFile', timeout: 5 },
|
|
2331
2687
|
{ event: 'PreToolUse', command: cmd('gsd-worktree-path-guard.js'), matcher: 'WriteFile|StrReplaceFile', timeout: 5 },
|
|
2332
2688
|
{ event: 'PreToolUse', command: cmd('gsd-write-guard.js'), matcher: 'WriteFile', timeout: 5 },
|
|
2689
|
+
{ event: 'PreToolUse', command: cmd('gsd-secret-read-guard.js'), matcher: 'ReadFile|Grep|Shell', timeout: 5 },
|
|
2333
2690
|
{ event: 'PreToolUse', command: cmd('gsd-workflow-guard.js'), matcher: 'Shell|WriteFile|StrReplaceFile', timeout: 5 },
|
|
2334
2691
|
{ event: 'PreToolUse', command: cmd('gsd-validate-commit.sh'), matcher: 'Shell', timeout: 5 },
|
|
2335
2692
|
// PostToolUse
|
|
@@ -2521,6 +2878,9 @@ module.exports = {
|
|
|
2521
2878
|
removeCodexHooksJsonEvent,
|
|
2522
2879
|
removeCodexHooksJsonSessionStart,
|
|
2523
2880
|
buildCodexHookWindowsShimIR,
|
|
2881
|
+
cleanupOrphanedCodexContextMonitorScript,
|
|
2882
|
+
isGsdOwnedCodexContextMonitorScript,
|
|
2883
|
+
hooksJsonReferencesCodexContextMonitor,
|
|
2524
2884
|
// Codex TOML
|
|
2525
2885
|
buildCodexHookBlock,
|
|
2526
2886
|
rewriteLegacyCodexHookBlock,
|
|
@@ -2532,6 +2892,7 @@ module.exports = {
|
|
|
2532
2892
|
KIMI_HOOKS_TOML_MARKER_BEGIN,
|
|
2533
2893
|
KIMI_HOOKS_TOML_MARKER_END,
|
|
2534
2894
|
// Shared
|
|
2895
|
+
stageTransitiveHookLibs,
|
|
2535
2896
|
buildHookCommand,
|
|
2536
2897
|
applySettingsJsonHooks,
|
|
2537
2898
|
referencesHook,
|