@opengsd/gsd-core 1.2.0 → 1.3.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/README.ja-JP.md +46 -791
- package/README.ko-KR.md +44 -780
- package/README.md +42 -218
- package/README.pt-BR.md +47 -414
- package/README.zh-CN.md +46 -763
- package/agents/gsd-ai-researcher.md +2 -2
- package/agents/gsd-debug-session-manager.md +1 -1
- package/agents/gsd-debugger.md +8 -8
- package/agents/gsd-doc-writer.md +7 -6
- package/agents/gsd-domain-researcher.md +15 -2
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-eval-planner.md +2 -2
- package/agents/gsd-executor.md +21 -8
- package/agents/gsd-framework-selector.md +1 -1
- package/agents/gsd-intel-updater.md +4 -4
- package/agents/gsd-phase-researcher.md +19 -6
- package/agents/gsd-plan-checker.md +3 -3
- package/agents/gsd-planner.md +36 -23
- package/agents/gsd-project-researcher.md +13 -0
- package/agents/gsd-research-synthesizer.md +6 -2
- package/agents/gsd-roadmapper.md +6 -6
- package/agents/gsd-ui-researcher.md +16 -3
- package/agents/gsd-user-profiler.md +2 -2
- package/agents/gsd-verifier.md +8 -8
- package/assets/gsd-logo-2000-transparent.png +0 -0
- package/assets/gsd-logo-2000-transparent.svg +17 -0
- package/assets/gsd-logo-2000.png +0 -0
- package/assets/gsd-logo-2000.svg +21 -0
- package/assets/terminal.svg +68 -0
- package/bin/install.js +255 -103
- package/commands/gsd/add-tests.md +1 -1
- package/commands/gsd/ai-integration-phase.md +3 -3
- package/commands/gsd/audit-fix.md +1 -1
- package/commands/gsd/audit-milestone.md +1 -1
- package/commands/gsd/audit-uat.md +1 -1
- package/commands/gsd/autonomous.md +2 -2
- package/commands/gsd/capture.md +6 -6
- package/commands/gsd/cleanup.md +1 -1
- package/commands/gsd/code-review.md +1 -1
- package/commands/gsd/complete-milestone.md +2 -2
- package/commands/gsd/config.md +3 -3
- package/commands/gsd/debug.md +1 -1
- package/commands/gsd/discuss-phase.md +5 -4
- package/commands/gsd/docs-update.md +1 -1
- package/commands/gsd/eval-review.md +2 -2
- package/commands/gsd/execute-phase.md +2 -2
- package/commands/gsd/explore.md +1 -1
- package/commands/gsd/extract-learnings.md +2 -2
- package/commands/gsd/fast.md +1 -1
- package/commands/gsd/forensics.md +1 -1
- package/commands/gsd/graphify.md +9 -9
- package/commands/gsd/health.md +1 -1
- package/commands/gsd/help.md +2 -2
- package/commands/gsd/import.md +5 -5
- package/commands/gsd/inbox.md +1 -1
- package/commands/gsd/ingest-docs.md +4 -4
- package/commands/gsd/manager.md +3 -3
- package/commands/gsd/map-codebase.md +1 -1
- package/commands/gsd/milestone-summary.md +1 -1
- package/commands/gsd/mvp-phase.md +4 -4
- package/commands/gsd/new-milestone.md +5 -5
- package/commands/gsd/new-project.md +5 -5
- package/commands/gsd/pause-work.md +2 -2
- package/commands/gsd/phase.md +4 -4
- package/commands/gsd/plan-phase.md +2 -2
- package/commands/gsd/plan-review-convergence.md +4 -4
- package/commands/gsd/pr-branch.md +1 -1
- package/commands/gsd/profile-user.md +2 -2
- package/commands/gsd/progress.md +4 -4
- package/commands/gsd/quick.md +1 -1
- package/commands/gsd/resume-work.md +1 -1
- package/commands/gsd/review.md +3 -2
- package/commands/gsd/secure-phase.md +1 -1
- package/commands/gsd/settings.md +1 -1
- package/commands/gsd/ship.md +2 -2
- package/commands/gsd/sketch.md +7 -7
- package/commands/gsd/spec-phase.md +2 -2
- package/commands/gsd/spike.md +3 -3
- package/commands/gsd/stats.md +1 -1
- package/commands/gsd/surface.md +4 -4
- package/commands/gsd/thread.md +1 -1
- package/commands/gsd/ui-phase.md +2 -2
- package/commands/gsd/ui-review.md +2 -2
- package/commands/gsd/ultraplan-phase.md +2 -2
- package/commands/gsd/undo.md +3 -3
- package/commands/gsd/update.md +3 -3
- package/commands/gsd/validate-phase.md +1 -1
- package/commands/gsd/verify-work.md +2 -2
- package/commands/gsd/workspace.md +4 -4
- package/{get-shit-done → gsd-core}/bin/check-latest-version.cjs +1 -1
- package/{get-shit-done → gsd-core}/bin/gsd-tools.cjs +50 -4
- package/gsd-core/bin/lib/active-workstream-store.cjs +291 -0
- package/gsd-core/bin/lib/adr-parser.cjs +399 -0
- package/gsd-core/bin/lib/agent-command-router.cjs +68 -0
- package/gsd-core/bin/lib/artifacts.cjs +51 -0
- package/gsd-core/bin/lib/audit.cjs +743 -0
- package/gsd-core/bin/lib/check-command-router.cjs +342 -0
- package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +81 -0
- package/gsd-core/bin/lib/clock.cjs +95 -0
- package/gsd-core/bin/lib/clusters.cjs +128 -0
- package/gsd-core/bin/lib/code-review-flags.cjs +59 -0
- package/gsd-core/bin/lib/command-aliases.cjs +809 -0
- package/gsd-core/bin/lib/command-arg-projection.cjs +55 -0
- package/gsd-core/bin/lib/command-routing-hub.cjs +300 -0
- package/gsd-core/bin/lib/commands.cjs +1202 -0
- package/gsd-core/bin/lib/config-schema.cjs +29 -0
- package/gsd-core/bin/lib/config-types.cjs +19 -0
- package/gsd-core/bin/lib/config.cjs +714 -0
- package/{get-shit-done → gsd-core}/bin/lib/configuration.cjs +76 -85
- package/gsd-core/bin/lib/context-utilization.cjs +48 -0
- package/gsd-core/bin/lib/core.cjs +2007 -0
- package/{get-shit-done → gsd-core}/bin/lib/decisions.cjs +9 -7
- package/gsd-core/bin/lib/docs.cjs +252 -0
- package/gsd-core/bin/lib/drift.cjs +364 -0
- package/gsd-core/bin/lib/fallow-runner.cjs +115 -0
- package/gsd-core/bin/lib/frontmatter.cjs +442 -0
- package/gsd-core/bin/lib/gap-checker.cjs +257 -0
- package/gsd-core/bin/lib/graphify.cjs +496 -0
- package/gsd-core/bin/lib/gsd2-import.cjs +456 -0
- package/gsd-core/bin/lib/init-command-router.cjs +62 -0
- package/gsd-core/bin/lib/init.cjs +1799 -0
- package/gsd-core/bin/lib/install-profiles.cjs +526 -0
- package/gsd-core/bin/lib/installer-migration-authoring.cjs +122 -0
- package/gsd-core/bin/lib/installer-migration-report.cjs +347 -0
- package/gsd-core/bin/lib/installer-migrations/000-first-time-baseline.cjs +218 -0
- package/gsd-core/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +48 -0
- package/gsd-core/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +94 -0
- package/gsd-core/bin/lib/installer-migrations/003-rename-get-shit-done-to-gsd-core.cjs +108 -0
- package/gsd-core/bin/lib/installer-migrations.cjs +784 -0
- package/gsd-core/bin/lib/intel.cjs +607 -0
- package/gsd-core/bin/lib/learnings.cjs +270 -0
- package/gsd-core/bin/lib/legacy-cleanup.cjs +253 -0
- package/gsd-core/bin/lib/milestone.cjs +373 -0
- package/gsd-core/bin/lib/model-catalog.cjs +154 -0
- package/gsd-core/bin/lib/model-profiles.cjs +24 -0
- package/gsd-core/bin/lib/observability/event.cjs +51 -0
- package/gsd-core/bin/lib/observability/logger.cjs +146 -0
- package/{get-shit-done → gsd-core}/bin/lib/observability/redaction.cjs +19 -21
- package/{get-shit-done → gsd-core}/bin/lib/package-identity.cjs +5 -1
- package/gsd-core/bin/lib/phase-command-router.cjs +189 -0
- package/gsd-core/bin/lib/phase-lifecycle.cjs +74 -0
- package/gsd-core/bin/lib/phase.cjs +1307 -0
- package/gsd-core/bin/lib/phases-command-router.cjs +43 -0
- package/{get-shit-done → gsd-core}/bin/lib/plan-scan.cjs +18 -24
- package/gsd-core/bin/lib/planning-workspace.cjs +245 -0
- package/gsd-core/bin/lib/profile-output.cjs +1120 -0
- package/gsd-core/bin/lib/profile-pipeline.cjs +517 -0
- package/gsd-core/bin/lib/project-root.cjs +119 -0
- package/gsd-core/bin/lib/prompt-budget.cjs +305 -0
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +121 -0
- package/gsd-core/bin/lib/roadmap-command-router.cjs +166 -0
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +491 -0
- package/gsd-core/bin/lib/roadmap.cjs +600 -0
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +254 -0
- package/gsd-core/bin/lib/runtime-homes.cjs +169 -0
- package/gsd-core/bin/lib/runtime-name-policy.cjs +96 -0
- package/gsd-core/bin/lib/runtime-slash.cjs +119 -0
- package/{get-shit-done → gsd-core}/bin/lib/schema-detect.cjs +20 -26
- package/gsd-core/bin/lib/secrets.cjs +34 -0
- package/gsd-core/bin/lib/security.cjs +407 -0
- package/gsd-core/bin/lib/semver-compare.cjs +42 -0
- package/gsd-core/bin/lib/shell-command-projection.cjs +524 -0
- package/gsd-core/bin/lib/state-command-router.cjs +160 -0
- package/{get-shit-done → gsd-core}/bin/lib/state-document.cjs +78 -82
- package/gsd-core/bin/lib/state.cjs +2010 -0
- package/gsd-core/bin/lib/surface.cjs +406 -0
- package/gsd-core/bin/lib/task-command-router.cjs +85 -0
- package/gsd-core/bin/lib/template.cjs +237 -0
- package/gsd-core/bin/lib/uat.cjs +297 -0
- package/gsd-core/bin/lib/ui-safety-gate.cjs +98 -0
- package/gsd-core/bin/lib/update-context.cjs +218 -0
- package/gsd-core/bin/lib/validate-command-router.cjs +91 -0
- package/gsd-core/bin/lib/validate.cjs +112 -0
- package/gsd-core/bin/lib/verify-command-router.cjs +44 -0
- package/gsd-core/bin/lib/verify.cjs +1451 -0
- package/{get-shit-done → gsd-core}/bin/lib/workstream-inventory-builder.cjs +19 -12
- package/gsd-core/bin/lib/workstream-inventory.cjs +147 -0
- package/{get-shit-done → gsd-core}/bin/lib/workstream-name-policy.cjs +28 -31
- package/gsd-core/bin/lib/workstream.cjs +380 -0
- package/gsd-core/bin/lib/worktree-safety.cjs +912 -0
- package/{get-shit-done → gsd-core}/bin/shared/config-defaults.manifest.json +1 -0
- package/{get-shit-done → gsd-core}/bin/shared/config-schema.manifest.json +17 -1
- package/{get-shit-done → gsd-core}/bin/shared/model-catalog.json +27 -0
- package/{get-shit-done → gsd-core}/references/artifact-types.md +1 -1
- package/{get-shit-done → gsd-core}/references/checkpoints.md +1 -1
- package/{get-shit-done → gsd-core}/references/few-shot-examples/plan-checker.md +2 -2
- package/{get-shit-done → gsd-core}/references/few-shot-examples/verifier.md +12 -12
- package/{get-shit-done → gsd-core}/references/model-profile-resolution.md +1 -1
- package/{get-shit-done → gsd-core}/references/mvp-concepts.md +1 -1
- package/{get-shit-done → gsd-core}/references/planner-graphify-auto-update.md +2 -2
- package/{get-shit-done → gsd-core}/references/planner-human-verify-mode.md +1 -1
- package/{get-shit-done → gsd-core}/references/planner-mvp-mode.md +1 -1
- package/{get-shit-done → gsd-core}/references/ui-brand.md +4 -2
- package/{get-shit-done → gsd-core}/references/verification-patterns.md +1 -1
- package/gsd-core/references/worktree-branch-check.md +38 -0
- package/{get-shit-done → gsd-core}/references/worktree-path-safety.md +4 -26
- package/{get-shit-done → gsd-core}/templates/README.md +2 -2
- package/{get-shit-done → gsd-core}/templates/codebase/structure.md +10 -10
- package/{get-shit-done → gsd-core}/templates/copilot-instructions.md +1 -1
- package/{get-shit-done → gsd-core}/templates/phase-prompt.md +10 -10
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -0
- package/{get-shit-done → gsd-core}/workflows/add-backlog.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/add-phase.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/add-tests.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/add-todo.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/ai-integration-phase.md +4 -4
- package/{get-shit-done → gsd-core}/workflows/audit-fix.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/audit-milestone.md +3 -1
- package/{get-shit-done → gsd-core}/workflows/audit-uat.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/autonomous.md +10 -8
- package/{get-shit-done → gsd-core}/workflows/check-todos.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/cleanup.md +44 -4
- package/{get-shit-done → gsd-core}/workflows/code-review-fix.md +4 -4
- package/{get-shit-done → gsd-core}/workflows/code-review.md +6 -4
- package/{get-shit-done → gsd-core}/workflows/complete-milestone.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/debug.md +7 -2
- package/{get-shit-done → gsd-core}/workflows/diagnose-issues.md +6 -2
- package/{get-shit-done → gsd-core}/workflows/discovery-phase.md +5 -5
- package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/advisor.md +5 -5
- package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/auto.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/chain.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/power.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/discuss-phase-assumptions.md +4 -4
- package/{get-shit-done → gsd-core}/workflows/discuss-phase.md +6 -6
- package/{get-shit-done → gsd-core}/workflows/do.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/docs-update.md +19 -5
- package/{get-shit-done → gsd-core}/workflows/edit-phase.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/eval-review.md +3 -3
- package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/codebase-drift-gate.md +16 -3
- package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/post-merge-gate.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/execute-phase.md +89 -57
- package/{get-shit-done → gsd-core}/workflows/execute-plan.md +8 -8
- package/{get-shit-done → gsd-core}/workflows/explore.md +5 -3
- package/{get-shit-done → gsd-core}/workflows/extract-learnings.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/forensics.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/graduation.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/health.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/help/modes/default.md +3 -3
- package/{get-shit-done → gsd-core}/workflows/help/modes/full.md +6 -6
- package/{get-shit-done → gsd-core}/workflows/import.md +3 -1
- package/{get-shit-done → gsd-core}/workflows/ingest-docs.md +5 -5
- package/{get-shit-done → gsd-core}/workflows/insert-phase.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/list-workspaces.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/manager.md +3 -3
- package/{get-shit-done → gsd-core}/workflows/map-codebase.md +3 -1
- package/{get-shit-done → gsd-core}/workflows/milestone-summary.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/mvp-phase.md +7 -7
- package/{get-shit-done → gsd-core}/workflows/new-milestone.md +5 -5
- package/{get-shit-done → gsd-core}/workflows/new-project.md +8 -8
- package/{get-shit-done → gsd-core}/workflows/new-workspace.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/next.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/pause-work.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/plan-milestone-gaps.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/plan-phase.md +29 -28
- package/{get-shit-done → gsd-core}/workflows/plan-review-convergence.md +10 -10
- package/{get-shit-done → gsd-core}/workflows/plant-seed.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/profile-user.md +11 -11
- package/{get-shit-done → gsd-core}/workflows/progress.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/quick.md +7 -29
- package/{get-shit-done → gsd-core}/workflows/reapply-patches.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/remove-phase.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/remove-workspace.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/resume-project.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/review.md +110 -2
- package/{get-shit-done → gsd-core}/workflows/scan.md +3 -1
- package/{get-shit-done → gsd-core}/workflows/secure-phase.md +5 -3
- package/{get-shit-done → gsd-core}/workflows/settings-advanced.md +196 -6
- package/{get-shit-done → gsd-core}/workflows/settings-integrations.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/settings.md +16 -2
- package/{get-shit-done → gsd-core}/workflows/ship.md +56 -4
- package/{get-shit-done → gsd-core}/workflows/sketch-wrap-up.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/sketch.md +5 -5
- package/{get-shit-done → gsd-core}/workflows/spec-phase.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/spike-wrap-up.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/spike.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/stats.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/sync-skills.md +3 -3
- package/{get-shit-done → gsd-core}/workflows/thread.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/transition.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/ui-phase.md +5 -5
- package/{get-shit-done → gsd-core}/workflows/ui-review.md +3 -3
- package/{get-shit-done → gsd-core}/workflows/ultraplan-phase.md +1 -1
- package/{get-shit-done → gsd-core}/workflows/undo.md +2 -2
- package/{get-shit-done → gsd-core}/workflows/update.md +41 -16
- package/{get-shit-done → gsd-core}/workflows/validate-phase.md +5 -3
- package/{get-shit-done → gsd-core}/workflows/verify-phase.md +4 -4
- package/{get-shit-done → gsd-core}/workflows/verify-work.md +7 -7
- package/hooks/dist/gsd-check-update-worker.js +16 -3
- package/hooks/dist/gsd-check-update.js +7 -5
- package/hooks/dist/gsd-context-monitor.js +2 -2
- package/hooks/dist/gsd-statusline.js +39 -21
- package/hooks/dist/gsd-update-banner.js +6 -2
- package/hooks/dist/gsd-worktree-path-guard.js +169 -0
- package/hooks/dist/managed-hooks-registry.cjs +35 -0
- package/hooks/gsd-check-update-worker.js +16 -3
- package/hooks/gsd-check-update.js +7 -5
- package/hooks/gsd-context-monitor.js +2 -2
- package/hooks/gsd-statusline.js +39 -21
- package/hooks/gsd-update-banner.js +6 -2
- package/hooks/gsd-worktree-path-guard.js +169 -0
- package/hooks/managed-hooks-registry.cjs +1 -0
- package/package.json +17 -11
- package/scripts/affected-tests-lib.cjs +1 -1
- package/scripts/base64-scan.sh +12 -0
- package/scripts/build-hooks.js +5 -1
- package/scripts/changeset/cli.cjs +2 -2
- package/scripts/changeset/github-release-notes.cjs +1 -1
- package/scripts/changeset/lint.cjs +1 -1
- package/scripts/check-alias-drift.cjs +8 -8
- package/scripts/check-env.cjs +5 -1
- package/scripts/ci-test-scope.cjs +34 -9
- package/scripts/command-contract-helpers.cjs +1 -1
- package/scripts/fix-slash-commands.cjs +5 -5
- package/scripts/gen-inventory-manifest.cjs +3 -3
- package/scripts/generate-package-identity.cjs +28 -7
- package/scripts/lib/allowlist-ratchet.cjs +136 -0
- package/scripts/lint-command-contract.cjs +1 -1
- package/scripts/lint-legacy-dir-name.cjs +156 -0
- package/scripts/lint-package-identity-drift.cjs +8 -8
- package/scripts/lint-pr-check-project-dir.cjs +0 -1
- package/scripts/lint-shell-command-projection-drift.cjs +1 -1
- package/scripts/lint-skill-deps.cjs +1 -1
- package/scripts/lint-test-file-count.allowlist.json +129 -32
- package/scripts/lint-test-file-count.cjs +85 -30
- package/scripts/mutation-matrix.cjs +219 -0
- package/scripts/prompt-injection-scan.sh +5 -1
- package/scripts/release-notes/format-github-release-notes.cjs +256 -0
- package/scripts/release-tarball-smoke.cjs +9 -9
- package/scripts/run-tests.cjs +34 -2
- package/scripts/strip-prose-atrefs.cjs +2 -2
- package/scripts/sync-runtime-launcher.cjs +2 -2
- package/scripts/verify-npm-publish.cjs +252 -0
- package/get-shit-done/bin/lib/active-workstream-store.cjs +0 -302
- package/get-shit-done/bin/lib/adr-parser.cjs +0 -394
- package/get-shit-done/bin/lib/agent-command-router.cjs +0 -65
- package/get-shit-done/bin/lib/artifacts.cjs +0 -53
- package/get-shit-done/bin/lib/audit.cjs +0 -755
- package/get-shit-done/bin/lib/check-command-router.cjs +0 -333
- package/get-shit-done/bin/lib/cjs-command-router-adapter.cjs +0 -118
- package/get-shit-done/bin/lib/clock.cjs +0 -96
- package/get-shit-done/bin/lib/clusters.cjs +0 -135
- package/get-shit-done/bin/lib/code-review-flags.cjs +0 -74
- package/get-shit-done/bin/lib/command-aliases.cjs +0 -815
- package/get-shit-done/bin/lib/command-arg-projection.cjs +0 -62
- package/get-shit-done/bin/lib/command-routing-hub.cjs +0 -388
- package/get-shit-done/bin/lib/commands.cjs +0 -1188
- package/get-shit-done/bin/lib/config-schema.cjs +0 -31
- package/get-shit-done/bin/lib/config.cjs +0 -728
- package/get-shit-done/bin/lib/context-utilization.cjs +0 -47
- package/get-shit-done/bin/lib/core.cjs +0 -2121
- package/get-shit-done/bin/lib/docs.cjs +0 -270
- package/get-shit-done/bin/lib/drift.cjs +0 -388
- package/get-shit-done/bin/lib/fallow-runner.cjs +0 -109
- package/get-shit-done/bin/lib/frontmatter.cjs +0 -389
- package/get-shit-done/bin/lib/gap-checker.cjs +0 -205
- package/get-shit-done/bin/lib/graphify.cjs +0 -592
- package/get-shit-done/bin/lib/gsd2-import.cjs +0 -514
- package/get-shit-done/bin/lib/init-command-router.cjs +0 -58
- package/get-shit-done/bin/lib/init.cjs +0 -2112
- package/get-shit-done/bin/lib/install-profiles.cjs +0 -603
- package/get-shit-done/bin/lib/installer-migration-authoring.cjs +0 -117
- package/get-shit-done/bin/lib/installer-migration-report.cjs +0 -354
- package/get-shit-done/bin/lib/installer-migrations/000-first-time-baseline.cjs +0 -220
- package/get-shit-done/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +0 -41
- package/get-shit-done/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +0 -80
- package/get-shit-done/bin/lib/installer-migrations.cjs +0 -778
- package/get-shit-done/bin/lib/intel.cjs +0 -708
- package/get-shit-done/bin/lib/learnings.cjs +0 -421
- package/get-shit-done/bin/lib/milestone.cjs +0 -314
- package/get-shit-done/bin/lib/model-catalog.cjs +0 -212
- package/get-shit-done/bin/lib/model-profiles.cjs +0 -31
- package/get-shit-done/bin/lib/observability/event.cjs +0 -82
- package/get-shit-done/bin/lib/observability/logger.cjs +0 -174
- package/get-shit-done/bin/lib/phase-command-router.cjs +0 -191
- package/get-shit-done/bin/lib/phase-lifecycle.cjs +0 -80
- package/get-shit-done/bin/lib/phase.cjs +0 -1607
- package/get-shit-done/bin/lib/phases-command-router.cjs +0 -39
- package/get-shit-done/bin/lib/planning-workspace.cjs +0 -238
- package/get-shit-done/bin/lib/profile-output.cjs +0 -1141
- package/get-shit-done/bin/lib/profile-pipeline.cjs +0 -539
- package/get-shit-done/bin/lib/project-root.cjs +0 -112
- package/get-shit-done/bin/lib/prompt-budget.cjs +0 -399
- package/get-shit-done/bin/lib/review-reviewer-selection.cjs +0 -125
- package/get-shit-done/bin/lib/roadmap-command-router.cjs +0 -28
- package/get-shit-done/bin/lib/roadmap.cjs +0 -650
- package/get-shit-done/bin/lib/runtime-artifact-layout.cjs +0 -301
- package/get-shit-done/bin/lib/runtime-homes.cjs +0 -222
- package/get-shit-done/bin/lib/runtime-name-policy.cjs +0 -83
- package/get-shit-done/bin/lib/runtime-slash.cjs +0 -112
- package/get-shit-done/bin/lib/secrets.cjs +0 -32
- package/get-shit-done/bin/lib/security.cjs +0 -600
- package/get-shit-done/bin/lib/semver-compare.cjs +0 -35
- package/get-shit-done/bin/lib/shell-command-projection.cjs +0 -500
- package/get-shit-done/bin/lib/state-command-router.cjs +0 -252
- package/get-shit-done/bin/lib/state.cjs +0 -2038
- package/get-shit-done/bin/lib/surface.cjs +0 -470
- package/get-shit-done/bin/lib/task-command-router.cjs +0 -81
- package/get-shit-done/bin/lib/template.cjs +0 -228
- package/get-shit-done/bin/lib/uat.cjs +0 -289
- package/get-shit-done/bin/lib/update-context.cjs +0 -209
- package/get-shit-done/bin/lib/validate-command-router.cjs +0 -83
- package/get-shit-done/bin/lib/validate.cjs +0 -92
- package/get-shit-done/bin/lib/verify-command-router.cjs +0 -40
- package/get-shit-done/bin/lib/verify.cjs +0 -1511
- package/get-shit-done/bin/lib/workstream-inventory.cjs +0 -146
- package/get-shit-done/bin/lib/workstream.cjs +0 -389
- package/get-shit-done/bin/lib/worktree-safety.cjs +0 -985
- package/get-shit-done/workflows/_runtime-launcher.snippet.sh +0 -1
- package/scripts/lint-no-source-grep-extras.cjs +0 -81
- package/scripts/lint-no-source-grep.cjs +0 -174
- package/scripts/lint-shared-module-handsync.cjs +0 -388
- package/scripts/shared-module-handsync-allowlist.json +0 -183
- /package/{get-shit-done → gsd-core}/bin/shared/runtime-aliases.manifest.json +0 -0
- /package/{get-shit-done → gsd-core}/bin/verify-reapply-patches.cjs +0 -0
- /package/{get-shit-done → gsd-core}/contexts/dev.md +0 -0
- /package/{get-shit-done → gsd-core}/contexts/research.md +0 -0
- /package/{get-shit-done → gsd-core}/contexts/review.md +0 -0
- /package/{get-shit-done → gsd-core}/references/agent-contracts.md +0 -0
- /package/{get-shit-done → gsd-core}/references/ai-evals.md +0 -0
- /package/{get-shit-done → gsd-core}/references/ai-frameworks.md +0 -0
- /package/{get-shit-done → gsd-core}/references/autonomous-smart-discuss.md +0 -0
- /package/{get-shit-done → gsd-core}/references/common-bug-patterns.md +0 -0
- /package/{get-shit-done → gsd-core}/references/context-budget.md +0 -0
- /package/{get-shit-done → gsd-core}/references/continuation-format.md +0 -0
- /package/{get-shit-done → gsd-core}/references/debugger-philosophy.md +0 -0
- /package/{get-shit-done → gsd-core}/references/decimal-phase-calculation.md +0 -0
- /package/{get-shit-done → gsd-core}/references/doc-conflict-engine.md +0 -0
- /package/{get-shit-done → gsd-core}/references/domain-probes.md +0 -0
- /package/{get-shit-done → gsd-core}/references/execute-mvp-tdd.md +0 -0
- /package/{get-shit-done → gsd-core}/references/executor-examples.md +0 -0
- /package/{get-shit-done → gsd-core}/references/gate-prompts.md +0 -0
- /package/{get-shit-done → gsd-core}/references/gates.md +0 -0
- /package/{get-shit-done → gsd-core}/references/git-integration.md +0 -0
- /package/{get-shit-done → gsd-core}/references/git-planning-commit.md +0 -0
- /package/{get-shit-done → gsd-core}/references/ios-scaffold.md +0 -0
- /package/{get-shit-done → gsd-core}/references/mandatory-initial-read.md +0 -0
- /package/{get-shit-done → gsd-core}/references/model-profiles.md +0 -0
- /package/{get-shit-done → gsd-core}/references/phase-argument-parsing.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planner-antipatterns.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planner-chunked.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planner-gap-closure.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planner-interface-context.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planner-reviews.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planner-revision.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planner-source-audit.md +0 -0
- /package/{get-shit-done → gsd-core}/references/planning-config.md +0 -0
- /package/{get-shit-done → gsd-core}/references/project-skills-discovery.md +0 -0
- /package/{get-shit-done → gsd-core}/references/questioning.md +0 -0
- /package/{get-shit-done → gsd-core}/references/revision-loop.md +0 -0
- /package/{get-shit-done → gsd-core}/references/scout-codebase.md +0 -0
- /package/{get-shit-done → gsd-core}/references/skeleton-template.md +0 -0
- /package/{get-shit-done → gsd-core}/references/sketch-interactivity.md +0 -0
- /package/{get-shit-done → gsd-core}/references/sketch-theme-system.md +0 -0
- /package/{get-shit-done → gsd-core}/references/sketch-tooling.md +0 -0
- /package/{get-shit-done → gsd-core}/references/sketch-variant-patterns.md +0 -0
- /package/{get-shit-done → gsd-core}/references/spidr-splitting.md +0 -0
- /package/{get-shit-done → gsd-core}/references/tdd.md +0 -0
- /package/{get-shit-done → gsd-core}/references/thinking-models-debug.md +0 -0
- /package/{get-shit-done → gsd-core}/references/thinking-models-execution.md +0 -0
- /package/{get-shit-done → gsd-core}/references/thinking-models-planning.md +0 -0
- /package/{get-shit-done → gsd-core}/references/thinking-models-research.md +0 -0
- /package/{get-shit-done → gsd-core}/references/thinking-models-verification.md +0 -0
- /package/{get-shit-done → gsd-core}/references/thinking-partner.md +0 -0
- /package/{get-shit-done → gsd-core}/references/universal-anti-patterns.md +0 -0
- /package/{get-shit-done → gsd-core}/references/user-profiling.md +0 -0
- /package/{get-shit-done → gsd-core}/references/user-story-template.md +0 -0
- /package/{get-shit-done → gsd-core}/references/verification-overrides.md +0 -0
- /package/{get-shit-done → gsd-core}/references/verify-mvp-mode.md +0 -0
- /package/{get-shit-done → gsd-core}/references/workstream-flag.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/AI-SPEC.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/DEBUG.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/SECURITY.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/UAT.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/UI-SPEC.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/VALIDATION.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/claude-md.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/codebase/architecture.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/codebase/concerns.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/codebase/conventions.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/codebase/integrations.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/codebase/stack.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/codebase/testing.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/config.json +0 -0
- /package/{get-shit-done → gsd-core}/templates/context.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/continue-here.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/debug-subagent-prompt.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/dev-preferences.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/discovery.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/discussion-log.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/milestone-archive.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/milestone.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/planner-subagent-prompt.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/project.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/requirements.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/research-project/ARCHITECTURE.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/research-project/FEATURES.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/research-project/PITFALLS.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/research-project/STACK.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/research-project/SUMMARY.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/research.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/retrospective.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/roadmap.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/spec.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/state.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/summary-complex.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/summary-minimal.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/summary-standard.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/summary.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/user-profile.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/user-setup.md +0 -0
- /package/{get-shit-done → gsd-core}/templates/verification-report.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/analyze-dependencies.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/all.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/analyze.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/batch.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/default.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/modes/text.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/checkpoint.json +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/context.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase/templates/discussion-log.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/discuss-phase-power.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/execute-phase/steps/per-plan-worktree-gate.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/fast.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/help/modes/brief.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/help/modes/topic.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/help.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/inbox.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/list-phase-assumptions.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/node-repair.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/note.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/pr-branch.md +0 -0
- /package/{get-shit-done → gsd-core}/workflows/session-report.md +0 -0
|
@@ -11,17 +11,29 @@
|
|
|
11
11
|
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const path = require('path');
|
|
14
|
-
const { isSemverNewer } = require('../
|
|
14
|
+
const { isSemverNewer } = require('../gsd-core/bin/lib/semver-compare.cjs');
|
|
15
15
|
// Latest-version lookup is delegated to the single deterministic adapter
|
|
16
16
|
// (#498). checkLatestVersion() owns the npm-view call, the timeout/semver
|
|
17
17
|
// policy, and the package name — sourced from the baked Package Identity seam.
|
|
18
18
|
// The previous `require('../package.json').name` (#378) resolved to undefined
|
|
19
19
|
// in the installed tree (only a {"type":"commonjs"} marker ships), so the
|
|
20
20
|
// background check never reported updates.
|
|
21
|
-
const { checkLatestVersion } = require('../
|
|
21
|
+
const { checkLatestVersion } = require('../gsd-core/bin/check-latest-version.cjs');
|
|
22
|
+
const { PACKAGE_NAME } = require('../gsd-core/bin/lib/package-identity.cjs');
|
|
22
23
|
// Authoritative list of managed hooks — shared with tests to retire source-grep
|
|
23
24
|
// assertions (pending-migration-to-typed-ir [#455]).
|
|
24
|
-
|
|
25
|
+
// NOTE: managed-hooks-registry.cjs must be in HOOKS_TO_COPY (scripts/build-hooks.js)
|
|
26
|
+
// so it is present in hooks/dist/ and ships to the installed runtime hooks/ dir.
|
|
27
|
+
// If it is missing (e.g., installed from an older dist), catch and degrade gracefully
|
|
28
|
+
// so the worker always proceeds to compute and write the result cache record.
|
|
29
|
+
let MANAGED_HOOKS = [];
|
|
30
|
+
try {
|
|
31
|
+
({ MANAGED_HOOKS } = require('./managed-hooks-registry.cjs'));
|
|
32
|
+
} catch (e) {
|
|
33
|
+
// Module not found in installed runtime — stale-hook detection degrades to
|
|
34
|
+
// no-op (empty list means no hooks are checked for staleness). The worker
|
|
35
|
+
// still runs and writes package_name / installed / latest / update_available.
|
|
36
|
+
}
|
|
25
37
|
|
|
26
38
|
const cacheFile = process.env.GSD_CACHE_FILE;
|
|
27
39
|
const projectVersionFile = process.env.GSD_PROJECT_VERSION_FILE;
|
|
@@ -88,6 +100,7 @@ const result = {
|
|
|
88
100
|
latest: latest || 'unknown',
|
|
89
101
|
checked: Math.floor(Date.now() / 1000),
|
|
90
102
|
stale_hooks: staleHooks.length > 0 ? staleHooks : undefined,
|
|
103
|
+
package_name: PACKAGE_NAME,
|
|
91
104
|
};
|
|
92
105
|
|
|
93
106
|
if (cacheFile) {
|
|
@@ -8,6 +8,8 @@ const path = require('path');
|
|
|
8
8
|
const os = require('os');
|
|
9
9
|
const { spawn } = require('child_process');
|
|
10
10
|
|
|
11
|
+
const { updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs');
|
|
12
|
+
|
|
11
13
|
const homeDir = os.homedir();
|
|
12
14
|
const cwd = process.cwd();
|
|
13
15
|
|
|
@@ -16,11 +18,11 @@ const cwd = process.cwd();
|
|
|
16
18
|
function detectConfigDir(baseDir) {
|
|
17
19
|
// Check env override first (supports multi-account setups)
|
|
18
20
|
const envDir = process.env.CLAUDE_CONFIG_DIR;
|
|
19
|
-
if (envDir && fs.existsSync(path.join(envDir, '
|
|
21
|
+
if (envDir && fs.existsSync(path.join(envDir, 'gsd-core', 'VERSION'))) {
|
|
20
22
|
return envDir;
|
|
21
23
|
}
|
|
22
24
|
for (const dir of ['.claude', '.gemini', '.config/kilo', '.kilo', '.config/opencode', '.opencode']) {
|
|
23
|
-
if (fs.existsSync(path.join(baseDir, dir, '
|
|
25
|
+
if (fs.existsSync(path.join(baseDir, dir, 'gsd-core', 'VERSION'))) {
|
|
24
26
|
return path.join(baseDir, dir);
|
|
25
27
|
}
|
|
26
28
|
}
|
|
@@ -33,11 +35,11 @@ const projectConfigDir = detectConfigDir(cwd);
|
|
|
33
35
|
// resolution mismatches where check-update writes to one runtime's cache
|
|
34
36
|
// but statusline reads from another (#1421).
|
|
35
37
|
const cacheDir = path.join(homeDir, '.cache', 'gsd');
|
|
36
|
-
const cacheFile = path.join(cacheDir,
|
|
38
|
+
const cacheFile = path.join(cacheDir, updateCacheFileName);
|
|
37
39
|
|
|
38
40
|
// VERSION file locations (check project first, then global)
|
|
39
|
-
const projectVersionFile = path.join(projectConfigDir, '
|
|
40
|
-
const globalVersionFile = path.join(globalConfigDir, '
|
|
41
|
+
const projectVersionFile = path.join(projectConfigDir, 'gsd-core', 'VERSION');
|
|
42
|
+
const globalVersionFile = path.join(globalConfigDir, 'gsd-core', 'VERSION');
|
|
41
43
|
|
|
42
44
|
// Ensure cache directory exists
|
|
43
45
|
if (!fs.existsSync(cacheDir)) {
|
|
@@ -140,10 +140,10 @@ process.stdin.on('end', () => {
|
|
|
140
140
|
if (isCritical && isGsdActive && !warnData.criticalRecorded) {
|
|
141
141
|
try {
|
|
142
142
|
// Runtime-agnostic path: this hook lives at <runtime-config>/hooks/
|
|
143
|
-
// and gsd-tools.cjs lives at <runtime-config>/
|
|
143
|
+
// and gsd-tools.cjs lives at <runtime-config>/gsd-core/bin/.
|
|
144
144
|
// Using __dirname makes this work on Claude Code, OpenCode, Gemini,
|
|
145
145
|
// Kilo, etc. without hardcoding ~/.claude/.
|
|
146
|
-
const gsdTools = path.join(__dirname, '..', '
|
|
146
|
+
const gsdTools = path.join(__dirname, '..', 'gsd-core', 'bin', 'gsd-tools.cjs');
|
|
147
147
|
// Coerce usedPct to a safe number in case bridge file is malformed
|
|
148
148
|
const safeUsedPct = Number(usedPct) || 0;
|
|
149
149
|
const stoppedAt = `context exhaustion at ${safeUsedPct}% (${new Date().toISOString().split('T')[0]})`;
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
8
|
const os = require('os');
|
|
9
|
-
const { isSemverNewer } = require('../
|
|
9
|
+
const { isSemverNewer } = require('../gsd-core/bin/lib/semver-compare.cjs');
|
|
10
|
+
const { PACKAGE_NAME, updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs');
|
|
10
11
|
|
|
11
12
|
// --- Config + last-command readers ------------------------------------------
|
|
12
13
|
|
|
@@ -395,32 +396,22 @@ function runStatusline() {
|
|
|
395
396
|
const gsdStateStr = task ? '' : formatGsdState(readGsdState(dir) || {});
|
|
396
397
|
|
|
397
398
|
// GSD update available?
|
|
398
|
-
//
|
|
399
|
-
//
|
|
399
|
+
// Read only the per-package shared cache file (#607). The legacy
|
|
400
|
+
// runtime-specific fallback has been removed — the per-package filename
|
|
401
|
+
// carries lineage and avoids multi-runtime resolution mismatches (#1421).
|
|
400
402
|
let gsdUpdate = '';
|
|
401
|
-
const
|
|
402
|
-
const legacyCacheFile = path.join(claudeDir, 'cache', 'gsd-update-check.json');
|
|
403
|
-
const cacheFile = fs.existsSync(sharedCacheFile) ? sharedCacheFile : legacyCacheFile;
|
|
403
|
+
const cacheFile = path.join(homeDir, '.cache', 'gsd', updateCacheFileName);
|
|
404
404
|
if (fs.existsSync(cacheFile)) {
|
|
405
405
|
try {
|
|
406
406
|
const cache = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
|
|
407
|
-
|
|
407
|
+
const { showUpdate, staleWarning } = evaluateUpdateCache(cache);
|
|
408
|
+
if (showUpdate) {
|
|
408
409
|
gsdUpdate = '\x1b[33m⬆ /gsd:update\x1b[0m │ ';
|
|
409
410
|
}
|
|
410
|
-
if (
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
cache.installed &&
|
|
415
|
-
cache.latest &&
|
|
416
|
-
cache.latest !== 'unknown' &&
|
|
417
|
-
isInstalledAheadOfLatest(cache.installed, cache.latest)
|
|
418
|
-
);
|
|
419
|
-
if (isDevInstall) {
|
|
420
|
-
gsdUpdate += '\x1b[33m⚠ dev install — re-run installer to sync hooks\x1b[0m │ ';
|
|
421
|
-
} else {
|
|
422
|
-
gsdUpdate += '\x1b[31m⚠ stale hooks — run /gsd:update\x1b[0m │ ';
|
|
423
|
-
}
|
|
411
|
+
if (staleWarning === 'dev') {
|
|
412
|
+
gsdUpdate += '\x1b[33m⚠ dev install — re-run installer to sync hooks\x1b[0m │ ';
|
|
413
|
+
} else if (staleWarning === 'stale') {
|
|
414
|
+
gsdUpdate += '\x1b[31m⚠ stale hooks — run /gsd:update\x1b[0m │ ';
|
|
424
415
|
}
|
|
425
416
|
} catch (e) {}
|
|
426
417
|
}
|
|
@@ -507,12 +498,39 @@ function isInstalledAheadOfLatest(installed, latest) {
|
|
|
507
498
|
return isSemverNewer(installed, latest);
|
|
508
499
|
}
|
|
509
500
|
|
|
501
|
+
/**
|
|
502
|
+
* Pure function: evaluate an update-check cache object and return display flags.
|
|
503
|
+
* Applies lineage guard — if package_name is absent or foreign, treats cache as absent.
|
|
504
|
+
*
|
|
505
|
+
* @param {object|null} cache Parsed cache object, or null.
|
|
506
|
+
* @returns {{ showUpdate: boolean, staleWarning: 'none'|'dev'|'stale' }}
|
|
507
|
+
*/
|
|
508
|
+
function evaluateUpdateCache(cache) {
|
|
509
|
+
const none = { showUpdate: false, staleWarning: 'none' };
|
|
510
|
+
if (!cache) return none;
|
|
511
|
+
// Lineage guard: package_name must be present and match this package.
|
|
512
|
+
if (!cache.package_name || cache.package_name !== PACKAGE_NAME) return none;
|
|
513
|
+
const showUpdate = Boolean(cache.update_available);
|
|
514
|
+
let staleWarning = 'none';
|
|
515
|
+
if (cache.stale_hooks && cache.stale_hooks.length > 0) {
|
|
516
|
+
const isDevInstall = (
|
|
517
|
+
cache.installed &&
|
|
518
|
+
cache.latest &&
|
|
519
|
+
cache.latest !== 'unknown' &&
|
|
520
|
+
isInstalledAheadOfLatest(cache.installed, cache.latest)
|
|
521
|
+
);
|
|
522
|
+
staleWarning = isDevInstall ? 'dev' : 'stale';
|
|
523
|
+
}
|
|
524
|
+
return { showUpdate, staleWarning };
|
|
525
|
+
}
|
|
526
|
+
|
|
510
527
|
// Export helpers for unit tests. Harmless when run as a script.
|
|
511
528
|
module.exports = {
|
|
512
529
|
readGsdState, parseStateMd, formatGsdState,
|
|
513
530
|
readGsdConfig, getConfigValue, readLastSlashCommand,
|
|
514
531
|
composeStatusline,
|
|
515
532
|
isInstalledAheadOfLatest,
|
|
533
|
+
evaluateUpdateCache,
|
|
516
534
|
};
|
|
517
535
|
|
|
518
536
|
/**
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// gsd-hook-version: {{GSD_VERSION}}
|
|
3
3
|
// SessionStart banner that surfaces GSD update availability when GSD's
|
|
4
4
|
// statusline isn't installed. Reads the cache that
|
|
5
|
-
// gsd-check-update-worker.js writes to ~/.cache/gsd
|
|
5
|
+
// gsd-check-update-worker.js writes to ~/.cache/gsd/<updateCacheFileName> (per-package).
|
|
6
6
|
//
|
|
7
7
|
// Opt-in by design: bin/install.js only registers this hook when the user
|
|
8
8
|
// declines to install (or replace) the GSD statusline. The presence of the
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
const fs = require('fs');
|
|
16
16
|
const path = require('path');
|
|
17
17
|
const os = require('os');
|
|
18
|
+
const { PACKAGE_NAME, updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs');
|
|
18
19
|
|
|
19
20
|
// Suppress repeat parse-error banners for 24 hours so a genuinely broken
|
|
20
21
|
// cache file doesn't nag the user every session.
|
|
@@ -37,6 +38,9 @@ function buildBannerOutput(state) {
|
|
|
37
38
|
return { systemMessage: 'GSD update check failed.' };
|
|
38
39
|
}
|
|
39
40
|
if (!cache) return null;
|
|
41
|
+
// Lineage guard: package_name must be present and match this package.
|
|
42
|
+
// Absent package_name means the cache predates lineage tracking — treat as untrusted.
|
|
43
|
+
if (!cache.package_name || cache.package_name !== PACKAGE_NAME) return null;
|
|
40
44
|
if (!cache.update_available) return null;
|
|
41
45
|
const installed = cache.installed || 'unknown';
|
|
42
46
|
const latest = cache.latest || 'unknown';
|
|
@@ -96,7 +100,7 @@ function recordFailureWarning(sentinelFile, nowSeconds) {
|
|
|
96
100
|
|
|
97
101
|
function main() {
|
|
98
102
|
const cacheDir = path.join(os.homedir(), '.cache', 'gsd');
|
|
99
|
-
const cacheFile = path.join(cacheDir,
|
|
103
|
+
const cacheFile = path.join(cacheDir, updateCacheFileName);
|
|
100
104
|
const sentinelFile = path.join(cacheDir, 'banner-failure-warned-at');
|
|
101
105
|
const now = Math.floor(Date.now() / 1000);
|
|
102
106
|
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// gsd-hook-version: {{GSD_VERSION}}
|
|
3
|
+
// GSD Worktree Path Guard — PreToolUse hook
|
|
4
|
+
// Blocks Edit/Write/MultiEdit tool calls that target absolute paths outside the worktree root.
|
|
5
|
+
//
|
|
6
|
+
// Problem: gsd-executor agents spawned with isolation="worktree" sometimes issue
|
|
7
|
+
// Edit/Write calls with absolute paths rooted at the MAIN repository instead of
|
|
8
|
+
// the worktree (issue #260). The prose guard in agents/gsd-executor.md step 0b
|
|
9
|
+
// is never enforced because the model under load skips it.
|
|
10
|
+
//
|
|
11
|
+
// This hook enforces the constraint at the tooling layer, making it HARD-BLOCKING.
|
|
12
|
+
//
|
|
13
|
+
// Triggers on: Edit, Write, and MultiEdit tool calls
|
|
14
|
+
// Action: BLOCK (exit 2) if file_path is absolute and outside the worktree root
|
|
15
|
+
// No-op: relative paths, non-worktree CWDs, hook errors (silent fail)
|
|
16
|
+
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const { spawnSync } = require('child_process');
|
|
20
|
+
|
|
21
|
+
const SPAWNOPT = { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: 2000 };
|
|
22
|
+
|
|
23
|
+
function git(args, cwd) {
|
|
24
|
+
return spawnSync('git', args, { ...SPAWNOPT, cwd });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Walk up from `start` to find the nearest existing directory.
|
|
28
|
+
// Returns null if we reach the filesystem root without finding one.
|
|
29
|
+
function nearestExistingDir(start) {
|
|
30
|
+
let dir = start;
|
|
31
|
+
let prev;
|
|
32
|
+
do {
|
|
33
|
+
prev = dir;
|
|
34
|
+
try { fs.accessSync(dir, fs.constants.F_OK); return dir; } catch { /* keep walking */ }
|
|
35
|
+
dir = path.dirname(dir);
|
|
36
|
+
} while (dir !== prev);
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let input = '';
|
|
41
|
+
const stdinTimeout = setTimeout(() => process.exit(0), 3000);
|
|
42
|
+
process.stdin.setEncoding('utf8');
|
|
43
|
+
process.stdin.on('data', chunk => input += chunk);
|
|
44
|
+
process.stdin.on('end', () => {
|
|
45
|
+
clearTimeout(stdinTimeout);
|
|
46
|
+
try {
|
|
47
|
+
const data = JSON.parse(input);
|
|
48
|
+
const toolName = data.tool_name;
|
|
49
|
+
|
|
50
|
+
// Only guard Edit, Write, and MultiEdit tool calls
|
|
51
|
+
if (toolName !== 'Edit' && toolName !== 'Write' && toolName !== 'MultiEdit') {
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const cwd = data.cwd || process.cwd();
|
|
56
|
+
|
|
57
|
+
// Detect whether CWD is inside a linked git worktree by inspecting
|
|
58
|
+
// the git-dir path. In a linked worktree, git rev-parse --git-dir
|
|
59
|
+
// returns a path containing .git/worktrees/ as a component.
|
|
60
|
+
// In the main repo or a submodule it returns .git (or a path without /worktrees/).
|
|
61
|
+
// This approach works even when cwd is a subdirectory of the worktree.
|
|
62
|
+
const gitDirResult = git(['rev-parse', '--git-dir'], cwd);
|
|
63
|
+
if (gitDirResult.status !== 0 || !gitDirResult.stdout) {
|
|
64
|
+
process.exit(0); // not a git repo — pass through
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const gitDir = gitDirResult.stdout.trim();
|
|
68
|
+
// A linked worktree's --git-dir contains .git/worktrees/ as a path component
|
|
69
|
+
const isLinkedWorktree = /[/\\]\.git[/\\]worktrees[/\\]/.test(gitDir);
|
|
70
|
+
if (!isLinkedWorktree) {
|
|
71
|
+
process.exit(0); // main repo, submodule, or separate-git-dir — no-op
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Get the raw --show-toplevel output for the worktree (cwd).
|
|
75
|
+
// We keep it raw (not path.resolve'd) to compare directly with the
|
|
76
|
+
// file's toplevel — same git binary, same format, no normalization needed.
|
|
77
|
+
const wtTopResult = git(['rev-parse', '--show-toplevel'], cwd);
|
|
78
|
+
if (wtTopResult.status !== 0 || !wtTopResult.stdout) {
|
|
79
|
+
process.exit(0); // can't determine root — fail open
|
|
80
|
+
}
|
|
81
|
+
const wtTopRaw = wtTopResult.stdout.trim();
|
|
82
|
+
|
|
83
|
+
const rawFilePath = data.tool_input?.file_path || '';
|
|
84
|
+
if (!rawFilePath) {
|
|
85
|
+
process.exit(0);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Relative paths are always safe — they resolve relative to CWD inside the worktree
|
|
89
|
+
if (!path.isAbsolute(rawFilePath)) {
|
|
90
|
+
process.exit(0);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Normalise .. traversal so /worktree/src/../../../main/file
|
|
94
|
+
// resolves to its true location before we check containment.
|
|
95
|
+
const filePath = path.resolve(rawFilePath);
|
|
96
|
+
|
|
97
|
+
// Find the nearest existing ancestor of filePath so we can ask git
|
|
98
|
+
// for its toplevel. The file itself may not exist yet (Write creates
|
|
99
|
+
// new files), but at least one ancestor directory must exist.
|
|
100
|
+
// We check the file itself first in case it already exists.
|
|
101
|
+
const checkDir = nearestExistingDir(
|
|
102
|
+
(() => {
|
|
103
|
+
try {
|
|
104
|
+
return fs.statSync(filePath).isDirectory() ? filePath : path.dirname(filePath);
|
|
105
|
+
} catch {
|
|
106
|
+
return path.dirname(filePath);
|
|
107
|
+
}
|
|
108
|
+
})()
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
if (!checkDir) {
|
|
112
|
+
// Walked to root without finding any directory — path is synthetic.
|
|
113
|
+
// Block conservatively.
|
|
114
|
+
const output = {
|
|
115
|
+
decision: 'block',
|
|
116
|
+
reason:
|
|
117
|
+
`Worktree path guard: '${filePath}' has no existing ancestor directory — ` +
|
|
118
|
+
`cannot verify it is inside the worktree '${wtTopRaw}'. Use a relative path instead.`,
|
|
119
|
+
};
|
|
120
|
+
process.stdout.write(JSON.stringify(output));
|
|
121
|
+
process.exit(2);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Ask git for the toplevel of the file's location.
|
|
125
|
+
// Comparing two raw git --show-toplevel outputs avoids every
|
|
126
|
+
// platform-specific path normalisation pitfall (Windows 8.3 short names,
|
|
127
|
+
// case differences between realpathSync and path.resolve, forward- vs
|
|
128
|
+
// back-slash inconsistencies) — both values come from the same git binary
|
|
129
|
+
// in the same format by definition.
|
|
130
|
+
const fileTopResult = git(['rev-parse', '--show-toplevel'], checkDir);
|
|
131
|
+
|
|
132
|
+
if (fileTopResult.status !== 0 || !fileTopResult.stdout) {
|
|
133
|
+
// checkDir is not inside any git repo → cannot be inside the worktree.
|
|
134
|
+
const output = {
|
|
135
|
+
decision: 'block',
|
|
136
|
+
reason:
|
|
137
|
+
`Worktree path guard: '${filePath}' is not inside any git repository — ` +
|
|
138
|
+
`it cannot be inside the worktree at '${wtTopRaw}'. Use a relative path instead.`,
|
|
139
|
+
};
|
|
140
|
+
process.stdout.write(JSON.stringify(output));
|
|
141
|
+
process.exit(2);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const fileTopRaw = fileTopResult.stdout.trim();
|
|
145
|
+
|
|
146
|
+
// Same git toplevel → file is inside the worktree → allow
|
|
147
|
+
if (fileTopRaw === wtTopRaw) {
|
|
148
|
+
process.exit(0);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// BLOCK: file resolves to a different git root than the active worktree
|
|
152
|
+
const output = {
|
|
153
|
+
decision: 'block',
|
|
154
|
+
reason:
|
|
155
|
+
`Worktree path guard: '${filePath}' resolves to git root '${fileTopRaw}' which ` +
|
|
156
|
+
`differs from the active worktree root '${wtTopRaw}'. This likely means an ` +
|
|
157
|
+
`absolute path was derived from the orchestrator's main repository instead of ` +
|
|
158
|
+
`the active worktree. To fix: use a relative path, or re-derive the base ` +
|
|
159
|
+
`directory with \`git rev-parse --show-toplevel\` from within the worktree ` +
|
|
160
|
+
`(hook cwd: '${cwd}').`,
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
process.stdout.write(JSON.stringify(output));
|
|
164
|
+
process.exit(2);
|
|
165
|
+
} catch {
|
|
166
|
+
// Silent fail — never block valid tool calls due to hook errors
|
|
167
|
+
process.exit(0);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Authoritative list of GSD-managed hook files.
|
|
5
|
+
*
|
|
6
|
+
* Extracted from the worker script into a shared CJS module so that:
|
|
7
|
+
* 1. gsd-check-update-worker.js can require() it directly (no source-level
|
|
8
|
+
* duplication).
|
|
9
|
+
* 2. Tests can assert against the exported array instead of regex-parsing
|
|
10
|
+
* the worker source (retiring the pending-migration-to-typed-ir token
|
|
11
|
+
* on managed-hooks.test.cjs and orphaned-hooks.test.cjs, per #455).
|
|
12
|
+
*
|
|
13
|
+
* These are the files GSD ships into ~/.claude/hooks/ (or equivalent) and
|
|
14
|
+
* checks for staleness after an update. Orphaned files from removed features
|
|
15
|
+
* (e.g., gsd-intel-*.js) must NOT be listed here — that would cause permanent
|
|
16
|
+
* stale warnings for users who haven't cleaned up manually (#1750).
|
|
17
|
+
*/
|
|
18
|
+
const MANAGED_HOOKS = [
|
|
19
|
+
'gsd-check-update-worker.js',
|
|
20
|
+
'gsd-check-update.js',
|
|
21
|
+
'gsd-context-monitor.js',
|
|
22
|
+
'gsd-graphify-update.sh',
|
|
23
|
+
'gsd-phase-boundary.sh',
|
|
24
|
+
'gsd-prompt-guard.js',
|
|
25
|
+
'gsd-read-guard.js',
|
|
26
|
+
'gsd-read-injection-scanner.js',
|
|
27
|
+
'gsd-session-state.sh',
|
|
28
|
+
'gsd-statusline.js',
|
|
29
|
+
'gsd-update-banner.js',
|
|
30
|
+
'gsd-validate-commit.sh',
|
|
31
|
+
'gsd-workflow-guard.js',
|
|
32
|
+
'gsd-worktree-path-guard.js',
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
module.exports = { MANAGED_HOOKS };
|
|
@@ -11,17 +11,29 @@
|
|
|
11
11
|
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const path = require('path');
|
|
14
|
-
const { isSemverNewer } = require('../
|
|
14
|
+
const { isSemverNewer } = require('../gsd-core/bin/lib/semver-compare.cjs');
|
|
15
15
|
// Latest-version lookup is delegated to the single deterministic adapter
|
|
16
16
|
// (#498). checkLatestVersion() owns the npm-view call, the timeout/semver
|
|
17
17
|
// policy, and the package name — sourced from the baked Package Identity seam.
|
|
18
18
|
// The previous `require('../package.json').name` (#378) resolved to undefined
|
|
19
19
|
// in the installed tree (only a {"type":"commonjs"} marker ships), so the
|
|
20
20
|
// background check never reported updates.
|
|
21
|
-
const { checkLatestVersion } = require('../
|
|
21
|
+
const { checkLatestVersion } = require('../gsd-core/bin/check-latest-version.cjs');
|
|
22
|
+
const { PACKAGE_NAME } = require('../gsd-core/bin/lib/package-identity.cjs');
|
|
22
23
|
// Authoritative list of managed hooks — shared with tests to retire source-grep
|
|
23
24
|
// assertions (pending-migration-to-typed-ir [#455]).
|
|
24
|
-
|
|
25
|
+
// NOTE: managed-hooks-registry.cjs must be in HOOKS_TO_COPY (scripts/build-hooks.js)
|
|
26
|
+
// so it is present in hooks/dist/ and ships to the installed runtime hooks/ dir.
|
|
27
|
+
// If it is missing (e.g., installed from an older dist), catch and degrade gracefully
|
|
28
|
+
// so the worker always proceeds to compute and write the result cache record.
|
|
29
|
+
let MANAGED_HOOKS = [];
|
|
30
|
+
try {
|
|
31
|
+
({ MANAGED_HOOKS } = require('./managed-hooks-registry.cjs'));
|
|
32
|
+
} catch (e) {
|
|
33
|
+
// Module not found in installed runtime — stale-hook detection degrades to
|
|
34
|
+
// no-op (empty list means no hooks are checked for staleness). The worker
|
|
35
|
+
// still runs and writes package_name / installed / latest / update_available.
|
|
36
|
+
}
|
|
25
37
|
|
|
26
38
|
const cacheFile = process.env.GSD_CACHE_FILE;
|
|
27
39
|
const projectVersionFile = process.env.GSD_PROJECT_VERSION_FILE;
|
|
@@ -88,6 +100,7 @@ const result = {
|
|
|
88
100
|
latest: latest || 'unknown',
|
|
89
101
|
checked: Math.floor(Date.now() / 1000),
|
|
90
102
|
stale_hooks: staleHooks.length > 0 ? staleHooks : undefined,
|
|
103
|
+
package_name: PACKAGE_NAME,
|
|
91
104
|
};
|
|
92
105
|
|
|
93
106
|
if (cacheFile) {
|
|
@@ -8,6 +8,8 @@ const path = require('path');
|
|
|
8
8
|
const os = require('os');
|
|
9
9
|
const { spawn } = require('child_process');
|
|
10
10
|
|
|
11
|
+
const { updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs');
|
|
12
|
+
|
|
11
13
|
const homeDir = os.homedir();
|
|
12
14
|
const cwd = process.cwd();
|
|
13
15
|
|
|
@@ -16,11 +18,11 @@ const cwd = process.cwd();
|
|
|
16
18
|
function detectConfigDir(baseDir) {
|
|
17
19
|
// Check env override first (supports multi-account setups)
|
|
18
20
|
const envDir = process.env.CLAUDE_CONFIG_DIR;
|
|
19
|
-
if (envDir && fs.existsSync(path.join(envDir, '
|
|
21
|
+
if (envDir && fs.existsSync(path.join(envDir, 'gsd-core', 'VERSION'))) {
|
|
20
22
|
return envDir;
|
|
21
23
|
}
|
|
22
24
|
for (const dir of ['.claude', '.gemini', '.config/kilo', '.kilo', '.config/opencode', '.opencode']) {
|
|
23
|
-
if (fs.existsSync(path.join(baseDir, dir, '
|
|
25
|
+
if (fs.existsSync(path.join(baseDir, dir, 'gsd-core', 'VERSION'))) {
|
|
24
26
|
return path.join(baseDir, dir);
|
|
25
27
|
}
|
|
26
28
|
}
|
|
@@ -33,11 +35,11 @@ const projectConfigDir = detectConfigDir(cwd);
|
|
|
33
35
|
// resolution mismatches where check-update writes to one runtime's cache
|
|
34
36
|
// but statusline reads from another (#1421).
|
|
35
37
|
const cacheDir = path.join(homeDir, '.cache', 'gsd');
|
|
36
|
-
const cacheFile = path.join(cacheDir,
|
|
38
|
+
const cacheFile = path.join(cacheDir, updateCacheFileName);
|
|
37
39
|
|
|
38
40
|
// VERSION file locations (check project first, then global)
|
|
39
|
-
const projectVersionFile = path.join(projectConfigDir, '
|
|
40
|
-
const globalVersionFile = path.join(globalConfigDir, '
|
|
41
|
+
const projectVersionFile = path.join(projectConfigDir, 'gsd-core', 'VERSION');
|
|
42
|
+
const globalVersionFile = path.join(globalConfigDir, 'gsd-core', 'VERSION');
|
|
41
43
|
|
|
42
44
|
// Ensure cache directory exists
|
|
43
45
|
if (!fs.existsSync(cacheDir)) {
|
|
@@ -140,10 +140,10 @@ process.stdin.on('end', () => {
|
|
|
140
140
|
if (isCritical && isGsdActive && !warnData.criticalRecorded) {
|
|
141
141
|
try {
|
|
142
142
|
// Runtime-agnostic path: this hook lives at <runtime-config>/hooks/
|
|
143
|
-
// and gsd-tools.cjs lives at <runtime-config>/
|
|
143
|
+
// and gsd-tools.cjs lives at <runtime-config>/gsd-core/bin/.
|
|
144
144
|
// Using __dirname makes this work on Claude Code, OpenCode, Gemini,
|
|
145
145
|
// Kilo, etc. without hardcoding ~/.claude/.
|
|
146
|
-
const gsdTools = path.join(__dirname, '..', '
|
|
146
|
+
const gsdTools = path.join(__dirname, '..', 'gsd-core', 'bin', 'gsd-tools.cjs');
|
|
147
147
|
// Coerce usedPct to a safe number in case bridge file is malformed
|
|
148
148
|
const safeUsedPct = Number(usedPct) || 0;
|
|
149
149
|
const stoppedAt = `context exhaustion at ${safeUsedPct}% (${new Date().toISOString().split('T')[0]})`;
|
package/hooks/gsd-statusline.js
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
8
|
const os = require('os');
|
|
9
|
-
const { isSemverNewer } = require('../
|
|
9
|
+
const { isSemverNewer } = require('../gsd-core/bin/lib/semver-compare.cjs');
|
|
10
|
+
const { PACKAGE_NAME, updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs');
|
|
10
11
|
|
|
11
12
|
// --- Config + last-command readers ------------------------------------------
|
|
12
13
|
|
|
@@ -395,32 +396,22 @@ function runStatusline() {
|
|
|
395
396
|
const gsdStateStr = task ? '' : formatGsdState(readGsdState(dir) || {});
|
|
396
397
|
|
|
397
398
|
// GSD update available?
|
|
398
|
-
//
|
|
399
|
-
//
|
|
399
|
+
// Read only the per-package shared cache file (#607). The legacy
|
|
400
|
+
// runtime-specific fallback has been removed — the per-package filename
|
|
401
|
+
// carries lineage and avoids multi-runtime resolution mismatches (#1421).
|
|
400
402
|
let gsdUpdate = '';
|
|
401
|
-
const
|
|
402
|
-
const legacyCacheFile = path.join(claudeDir, 'cache', 'gsd-update-check.json');
|
|
403
|
-
const cacheFile = fs.existsSync(sharedCacheFile) ? sharedCacheFile : legacyCacheFile;
|
|
403
|
+
const cacheFile = path.join(homeDir, '.cache', 'gsd', updateCacheFileName);
|
|
404
404
|
if (fs.existsSync(cacheFile)) {
|
|
405
405
|
try {
|
|
406
406
|
const cache = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
|
|
407
|
-
|
|
407
|
+
const { showUpdate, staleWarning } = evaluateUpdateCache(cache);
|
|
408
|
+
if (showUpdate) {
|
|
408
409
|
gsdUpdate = '\x1b[33m⬆ /gsd:update\x1b[0m │ ';
|
|
409
410
|
}
|
|
410
|
-
if (
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
cache.installed &&
|
|
415
|
-
cache.latest &&
|
|
416
|
-
cache.latest !== 'unknown' &&
|
|
417
|
-
isInstalledAheadOfLatest(cache.installed, cache.latest)
|
|
418
|
-
);
|
|
419
|
-
if (isDevInstall) {
|
|
420
|
-
gsdUpdate += '\x1b[33m⚠ dev install — re-run installer to sync hooks\x1b[0m │ ';
|
|
421
|
-
} else {
|
|
422
|
-
gsdUpdate += '\x1b[31m⚠ stale hooks — run /gsd:update\x1b[0m │ ';
|
|
423
|
-
}
|
|
411
|
+
if (staleWarning === 'dev') {
|
|
412
|
+
gsdUpdate += '\x1b[33m⚠ dev install — re-run installer to sync hooks\x1b[0m │ ';
|
|
413
|
+
} else if (staleWarning === 'stale') {
|
|
414
|
+
gsdUpdate += '\x1b[31m⚠ stale hooks — run /gsd:update\x1b[0m │ ';
|
|
424
415
|
}
|
|
425
416
|
} catch (e) {}
|
|
426
417
|
}
|
|
@@ -507,12 +498,39 @@ function isInstalledAheadOfLatest(installed, latest) {
|
|
|
507
498
|
return isSemverNewer(installed, latest);
|
|
508
499
|
}
|
|
509
500
|
|
|
501
|
+
/**
|
|
502
|
+
* Pure function: evaluate an update-check cache object and return display flags.
|
|
503
|
+
* Applies lineage guard — if package_name is absent or foreign, treats cache as absent.
|
|
504
|
+
*
|
|
505
|
+
* @param {object|null} cache Parsed cache object, or null.
|
|
506
|
+
* @returns {{ showUpdate: boolean, staleWarning: 'none'|'dev'|'stale' }}
|
|
507
|
+
*/
|
|
508
|
+
function evaluateUpdateCache(cache) {
|
|
509
|
+
const none = { showUpdate: false, staleWarning: 'none' };
|
|
510
|
+
if (!cache) return none;
|
|
511
|
+
// Lineage guard: package_name must be present and match this package.
|
|
512
|
+
if (!cache.package_name || cache.package_name !== PACKAGE_NAME) return none;
|
|
513
|
+
const showUpdate = Boolean(cache.update_available);
|
|
514
|
+
let staleWarning = 'none';
|
|
515
|
+
if (cache.stale_hooks && cache.stale_hooks.length > 0) {
|
|
516
|
+
const isDevInstall = (
|
|
517
|
+
cache.installed &&
|
|
518
|
+
cache.latest &&
|
|
519
|
+
cache.latest !== 'unknown' &&
|
|
520
|
+
isInstalledAheadOfLatest(cache.installed, cache.latest)
|
|
521
|
+
);
|
|
522
|
+
staleWarning = isDevInstall ? 'dev' : 'stale';
|
|
523
|
+
}
|
|
524
|
+
return { showUpdate, staleWarning };
|
|
525
|
+
}
|
|
526
|
+
|
|
510
527
|
// Export helpers for unit tests. Harmless when run as a script.
|
|
511
528
|
module.exports = {
|
|
512
529
|
readGsdState, parseStateMd, formatGsdState,
|
|
513
530
|
readGsdConfig, getConfigValue, readLastSlashCommand,
|
|
514
531
|
composeStatusline,
|
|
515
532
|
isInstalledAheadOfLatest,
|
|
533
|
+
evaluateUpdateCache,
|
|
516
534
|
};
|
|
517
535
|
|
|
518
536
|
/**
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// gsd-hook-version: {{GSD_VERSION}}
|
|
3
3
|
// SessionStart banner that surfaces GSD update availability when GSD's
|
|
4
4
|
// statusline isn't installed. Reads the cache that
|
|
5
|
-
// gsd-check-update-worker.js writes to ~/.cache/gsd
|
|
5
|
+
// gsd-check-update-worker.js writes to ~/.cache/gsd/<updateCacheFileName> (per-package).
|
|
6
6
|
//
|
|
7
7
|
// Opt-in by design: bin/install.js only registers this hook when the user
|
|
8
8
|
// declines to install (or replace) the GSD statusline. The presence of the
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
const fs = require('fs');
|
|
16
16
|
const path = require('path');
|
|
17
17
|
const os = require('os');
|
|
18
|
+
const { PACKAGE_NAME, updateCacheFileName } = require('../gsd-core/bin/lib/package-identity.cjs');
|
|
18
19
|
|
|
19
20
|
// Suppress repeat parse-error banners for 24 hours so a genuinely broken
|
|
20
21
|
// cache file doesn't nag the user every session.
|
|
@@ -37,6 +38,9 @@ function buildBannerOutput(state) {
|
|
|
37
38
|
return { systemMessage: 'GSD update check failed.' };
|
|
38
39
|
}
|
|
39
40
|
if (!cache) return null;
|
|
41
|
+
// Lineage guard: package_name must be present and match this package.
|
|
42
|
+
// Absent package_name means the cache predates lineage tracking — treat as untrusted.
|
|
43
|
+
if (!cache.package_name || cache.package_name !== PACKAGE_NAME) return null;
|
|
40
44
|
if (!cache.update_available) return null;
|
|
41
45
|
const installed = cache.installed || 'unknown';
|
|
42
46
|
const latest = cache.latest || 'unknown';
|
|
@@ -96,7 +100,7 @@ function recordFailureWarning(sentinelFile, nowSeconds) {
|
|
|
96
100
|
|
|
97
101
|
function main() {
|
|
98
102
|
const cacheDir = path.join(os.homedir(), '.cache', 'gsd');
|
|
99
|
-
const cacheFile = path.join(cacheDir,
|
|
103
|
+
const cacheFile = path.join(cacheDir, updateCacheFileName);
|
|
100
104
|
const sentinelFile = path.join(cacheDir, 'banner-failure-warned-at');
|
|
101
105
|
const now = Math.floor(Date.now() / 1000);
|
|
102
106
|
|