@opengsd/gsd-core 1.3.1 → 1.4.0-rc.2

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.
Files changed (136) hide show
  1. package/.claude-plugin/plugin.json +23 -0
  2. package/GEMINI.md +53 -0
  3. package/agents/gsd-advisor-researcher.md +1 -20
  4. package/agents/gsd-ai-researcher.md +2 -21
  5. package/agents/gsd-code-fixer.md +1 -1
  6. package/agents/gsd-code-reviewer.md +1 -1
  7. package/agents/gsd-domain-researcher.md +2 -21
  8. package/agents/gsd-eval-auditor.md +1 -1
  9. package/agents/gsd-eval-planner.md +1 -1
  10. package/agents/gsd-executor.md +1 -1
  11. package/agents/gsd-framework-selector.md +1 -1
  12. package/agents/gsd-nyquist-auditor.md +1 -1
  13. package/agents/gsd-pattern-mapper.md +1 -1
  14. package/agents/gsd-phase-researcher.md +92 -166
  15. package/agents/gsd-planner.md +9 -36
  16. package/agents/gsd-project-researcher.md +62 -141
  17. package/agents/gsd-security-auditor.md +1 -1
  18. package/agents/gsd-ui-auditor.md +1 -1
  19. package/agents/gsd-ui-checker.md +1 -1
  20. package/agents/gsd-ui-researcher.md +3 -22
  21. package/agents/gsd-user-profiler.md +1 -1
  22. package/agents/gsd-verifier.md +8 -2
  23. package/bin/install.js +1977 -339
  24. package/commands/gsd/autonomous.md +2 -0
  25. package/commands/gsd/execute-phase.md +2 -0
  26. package/commands/gsd/graphify.md +11 -6
  27. package/commands/gsd/import.md +6 -2
  28. package/commands/gsd/plan-phase.md +4 -2
  29. package/commands/gsd/progress.md +1 -0
  30. package/commands/gsd/stats.md +1 -0
  31. package/commands/gsd/update.md +3 -2
  32. package/gemini-extension.json +6 -0
  33. package/gsd-core/bin/check-latest-version.cjs +61 -6
  34. package/gsd-core/bin/gsd-tools.cjs +238 -32
  35. package/gsd-core/bin/lib/check-command-router.cjs +1 -0
  36. package/gsd-core/bin/lib/cli-exit.cjs +42 -0
  37. package/gsd-core/bin/lib/command-routing-hub.cjs +1 -1
  38. package/gsd-core/bin/lib/commands.cjs +5 -4
  39. package/gsd-core/bin/lib/config.cjs +28 -4
  40. package/gsd-core/bin/lib/core.cjs +72 -28
  41. package/gsd-core/bin/lib/graphify.cjs +2 -2
  42. package/gsd-core/bin/lib/init-command-router.cjs +2 -2
  43. package/gsd-core/bin/lib/init.cjs +19 -3
  44. package/gsd-core/bin/lib/install-profiles.cjs +58 -0
  45. package/gsd-core/bin/lib/installer-migration-report.cjs +3 -0
  46. package/gsd-core/bin/lib/installer-migrations/000-first-time-baseline.cjs +1 -1
  47. package/gsd-core/bin/lib/intel.cjs +3 -20
  48. package/gsd-core/bin/lib/package-legitimacy.cjs +368 -0
  49. package/gsd-core/bin/lib/phase.cjs +3 -3
  50. package/gsd-core/bin/lib/research-provider.cjs +137 -0
  51. package/gsd-core/bin/lib/research-store.cjs +167 -0
  52. package/gsd-core/bin/lib/roadmap-upgrade.cjs +4 -19
  53. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +67 -9
  54. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +56 -0
  55. package/gsd-core/bin/lib/runtime-homes.cjs +32 -11
  56. package/gsd-core/bin/lib/security.cjs +73 -0
  57. package/gsd-core/bin/lib/shell-command-projection.cjs +9 -0
  58. package/gsd-core/bin/lib/surface.cjs +54 -11
  59. package/gsd-core/bin/lib/validate.cjs +2 -2
  60. package/gsd-core/bin/lib/verification-command-router.cjs +31 -0
  61. package/gsd-core/bin/lib/verification.cjs +193 -0
  62. package/gsd-core/bin/lib/verify.cjs +2 -2
  63. package/gsd-core/bin/lib/workstream-inventory.cjs +1 -1
  64. package/gsd-core/bin/lib/worktree-base-ref.cjs +325 -0
  65. package/gsd-core/bin/lib/worktree-safety.cjs +31 -0
  66. package/gsd-core/bin/shared/config-schema.manifest.json +2 -1
  67. package/gsd-core/bin/verify-reapply-patches.cjs +8 -11
  68. package/gsd-core/references/planner-load-graph-context.md +36 -0
  69. package/gsd-core/references/planning-config.md +3 -1
  70. package/gsd-core/references/research-documentation-lookup.md +29 -0
  71. package/gsd-core/references/research-philosophy.md +29 -0
  72. package/gsd-core/references/research-verification-protocol.md +27 -0
  73. package/gsd-core/workflows/execute-phase.md +19 -8
  74. package/gsd-core/workflows/help/modes/full.md +4 -3
  75. package/gsd-core/workflows/ingest-docs.md +3 -2
  76. package/gsd-core/workflows/plan-phase.md +14 -10
  77. package/gsd-core/workflows/plan-review-convergence.md +3 -3
  78. package/gsd-core/workflows/review.md +24 -7
  79. package/gsd-core/workflows/ship.md +5 -8
  80. package/gsd-core/workflows/spec-phase.md +2 -1
  81. package/gsd-core/workflows/update.md +34 -6
  82. package/hooks/dist/gsd-config-reload.js +133 -0
  83. package/hooks/dist/gsd-context-monitor.js +1 -1
  84. package/hooks/dist/gsd-cursor-post-tool.js +75 -0
  85. package/hooks/dist/gsd-cursor-session-start.js +52 -0
  86. package/hooks/dist/gsd-workflow-guard.js +1 -0
  87. package/hooks/dist/gsd-worktree-path-guard.js +1 -1
  88. package/hooks/dist/managed-hooks-registry.cjs +3 -0
  89. package/hooks/gsd-config-reload.js +133 -0
  90. package/hooks/gsd-context-monitor.js +1 -1
  91. package/hooks/gsd-cursor-post-tool.js +75 -0
  92. package/hooks/gsd-cursor-session-start.js +52 -0
  93. package/hooks/gsd-workflow-guard.js +1 -0
  94. package/hooks/gsd-worktree-path-guard.js +1 -1
  95. package/hooks/hooks.json +69 -0
  96. package/hooks/managed-hooks-registry.cjs +3 -0
  97. package/package.json +8 -1
  98. package/scripts/affected-tests-lib.cjs +3 -2
  99. package/scripts/build-hooks.js +7 -0
  100. package/scripts/changeset/cli.cjs +226 -28
  101. package/scripts/changeset/lint.cjs +5 -4
  102. package/scripts/changeset/new.cjs +4 -4
  103. package/scripts/check-alias-drift.cjs +77 -71
  104. package/scripts/check-env.cjs +185 -179
  105. package/scripts/check-npm-integrity.cjs +115 -109
  106. package/scripts/ci-guard-runner.cjs +11 -5
  107. package/scripts/ci-prepare-test-scope.cjs +27 -22
  108. package/scripts/ci-rebase-check.cjs +46 -45
  109. package/scripts/ci-test-scope.cjs +126 -22
  110. package/scripts/diff-touches-shipped-paths.cjs +52 -44
  111. package/scripts/gen-inventory-manifest.cjs +38 -32
  112. package/scripts/gen-research-agents.cjs +276 -0
  113. package/scripts/issue-dedupe.cjs +278 -0
  114. package/scripts/lib/cli-exit.cjs +56 -0
  115. package/scripts/lint-command-contract.cjs +28 -22
  116. package/scripts/lint-descriptions.cjs +32 -28
  117. package/scripts/lint-docs-required.cjs +4 -4
  118. package/scripts/lint-legacy-dir-name.cjs +56 -52
  119. package/scripts/lint-pr-check-project-dir.cjs +3 -1
  120. package/scripts/lint-shell-command-projection-drift.cjs +27 -22
  121. package/scripts/lint-skill-deps.cjs +31 -26
  122. package/scripts/lint-test-file-count.allowlist.json +2 -0
  123. package/scripts/lint-test-file-count.cjs +5 -4
  124. package/scripts/mutation-matrix.cjs +6 -3
  125. package/scripts/prompt-injection-scan.sh +1 -1
  126. package/scripts/release-notes/discord-release-summary.cjs +373 -0
  127. package/scripts/release-notes/format-github-release-notes.cjs +8 -3
  128. package/scripts/release-tarball-smoke.cjs +6 -4
  129. package/scripts/research-profiles.cjs +149 -0
  130. package/scripts/run-affected-tests.cjs +2 -1
  131. package/scripts/run-cross-platform-tests.cjs +11 -7
  132. package/scripts/run-tests.cjs +8 -7
  133. package/scripts/strip-prose-atrefs.cjs +1 -1
  134. package/scripts/sync-manifest-versions.cjs +119 -0
  135. package/scripts/sync-runtime-launcher.cjs +0 -3
  136. package/scripts/verify-npm-publish.cjs +14 -26
@@ -2,6 +2,8 @@
2
2
  name: gsd:autonomous
3
3
  description: Run all remaining phases autonomously — discuss→plan→execute per phase
4
4
  argument-hint: "[--from N] [--to N] [--only N] [--interactive]"
5
+ context: fork
6
+ effort: xhigh
5
7
  allowed-tools:
6
8
  - Read
7
9
  - Write
@@ -2,6 +2,8 @@
2
2
  name: gsd:execute-phase
3
3
  description: Execute all plans in a phase with wave-based parallelization
4
4
  argument-hint: "<phase-number> [--wave N] [--gaps-only] [--interactive] [--tdd]"
5
+ context: fork
6
+ effort: xhigh
5
7
  allowed-tools:
6
8
  - Read
7
9
  - Write
@@ -79,7 +79,8 @@ Modes:
79
79
  Run:
80
80
 
81
81
  ```bash
82
- node $HOME/.claude/gsd-core/bin/gsd-tools.cjs graphify query <term>
82
+ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi
83
+ gsd_run graphify query <term>
83
84
  ```
84
85
 
85
86
  Parse the JSON output and display results:
@@ -95,7 +96,8 @@ Parse the JSON output and display results:
95
96
  Run:
96
97
 
97
98
  ```bash
98
- node $HOME/.claude/gsd-core/bin/gsd-tools.cjs graphify status
99
+ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi
100
+ gsd_run graphify status
99
101
  ```
100
102
 
101
103
  Parse the JSON output and display:
@@ -119,7 +121,8 @@ Surface both so the agent can choose.
119
121
  Run:
120
122
 
121
123
  ```bash
122
- node $HOME/.claude/gsd-core/bin/gsd-tools.cjs graphify diff
124
+ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi
125
+ gsd_run graphify diff
123
126
  ```
124
127
 
125
128
  Parse the JSON output and display:
@@ -137,7 +140,8 @@ If no snapshot exists, suggest running `build` twice (first to create, second to
137
140
  Run the pre-flight check first:
138
141
 
139
142
  ```bash
140
- node "$HOME/.claude/gsd-core/bin/gsd-tools.cjs" graphify build
143
+ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi
144
+ gsd_run graphify build
141
145
  ```
142
146
 
143
147
  Parse the JSON output:
@@ -156,12 +160,13 @@ GSD > Building knowledge graph...
156
160
  Run the build, copy artifacts, write the diff snapshot, and report the summary in a single foreground Bash call so the whole pipeline survives to completion. Use a `timeout` of `600000` ms (10 minutes), which covers the `graphify.build_timeout` ceiling (default 300 s) with margin:
157
161
 
158
162
  ```bash
163
+ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi
159
164
  graphify update . \
160
165
  && cp graphify-out/graph.json .planning/graphs/graph.json \
161
166
  && { [ -f graphify-out/graph.html ] && cp graphify-out/graph.html .planning/graphs/graph.html || true; } \
162
167
  && cp graphify-out/GRAPH_REPORT.md .planning/graphs/GRAPH_REPORT.md \
163
- && node "$HOME/.claude/gsd-core/bin/gsd-tools.cjs" graphify build snapshot \
164
- && node "$HOME/.claude/gsd-core/bin/gsd-tools.cjs" graphify status
168
+ && gsd_run graphify build snapshot \
169
+ && gsd_run graphify status
165
170
  ```
166
171
 
167
172
  Do NOT pass `run_in_background: true`. Typical builds complete in 15-60 seconds and the entire chain must run foreground.
@@ -33,8 +33,12 @@ $ARGUMENTS
33
33
 
34
34
  <process>
35
35
  If `--from-gsd2` is in $ARGUMENTS:
36
- Run: `node "$HOME/.claude/gsd-core/bin/gsd-tools.cjs" from-gsd2`
37
- Pass `--path <dir>` if provided. Present the migration result to the user.
36
+ Run the reverse-migration (append `--path <dir>` if provided):
37
+ ```bash
38
+ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi
39
+ gsd_run from-gsd2
40
+ ```
41
+ Present the migration result to the user.
38
42
  Stop here (do not run the standard import workflow).
39
43
 
40
44
  Otherwise, execute the import workflow end-to-end.
@@ -2,6 +2,8 @@
2
2
  name: gsd:plan-phase
3
3
  description: Create detailed phase plan (PLAN.md) with verification loop
4
4
  argument-hint: "[phase] [--auto] [--research] [--skip-research] [--research-phase <N>] [--view] [--gaps] [--skip-verify] [--prd <file>] [--ingest <path-or-glob>] [--ingest-format <auto|nygard|madr|narrative>] [--reviews] [--text] [--tdd] [--mvp]"
5
+ context: fork
6
+ effort: xhigh
5
7
  allowed-tools:
6
8
  - Read
7
9
  - Write
@@ -22,8 +24,8 @@ Create executable phase prompts (PLAN.md files) for a roadmap phase with integra
22
24
  **Research-only mode (`--research-phase <N>`):** Spawn `gsd-phase-researcher` for phase `N`, write `RESEARCH.md`, then exit before the planner runs. Useful for cross-phase research, doc review before committing to a planning approach, and correction-without-replanning loops where iterating on research alone is dramatically cheaper than re-spawning the planner. Replaces the deleted research-phase command (#3042).
23
25
 
24
26
  **Research-only modifiers:**
25
- - **No flag** — when `RESEARCH.md` already exists, prompt the user to choose `update / view / skip`.
26
- - **`--research`** — force-refresh: re-spawn the researcher unconditionally, no prompt. Skips the existing-RESEARCH.md menu.
27
+ - **No flag** — when `RESEARCH.md` already exists, auto-uses it: emits a one-line notice and exits cleanly, no prompt.
28
+ - **`--research`** — force-refresh: re-spawn the researcher unconditionally, no prompt. Bypasses the existing-RESEARCH.md auto-use path.
27
29
  - **`--view`** — view-only: print existing `RESEARCH.md` to stdout. Does not spawn the researcher. Cheapest mode for the correction-without-replanning loop. If no `RESEARCH.md` exists yet, errors with a hint to drop `--view`.
28
30
 
29
31
  **Orchestrator role:** Parse arguments, validate phase, research domain (unless skipped), spawn gsd-planner, verify with gsd-plan-checker, iterate until pass or max iterations, present results.
@@ -2,6 +2,7 @@
2
2
  name: gsd:progress
3
3
  description: Check progress, advance workflow, or dispatch freeform intent — the unified GSD situational command
4
4
  argument-hint: "[--forensic | --next | --do \"task description\"]"
5
+ effort: low
5
6
  allowed-tools:
6
7
  - Read
7
8
  - Bash
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: gsd:stats
3
3
  description: Display project statistics — phases, plans, requirements, git metrics, and timeline
4
+ effort: low
4
5
  allowed-tools:
5
6
  - Read
6
7
  - Bash
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: gsd:update
3
3
  description: Update GSD to latest version with changelog display
4
- argument-hint: "[--sync | --reapply]"
4
+ argument-hint: "[--sync | --reapply | --next | --rc]"
5
5
  allowed-tools:
6
6
  - Read
7
7
  - Write
@@ -31,6 +31,7 @@ Routes to the update workflow which handles:
31
31
  <flags>
32
32
  - **--sync**: Sync managed GSD skills across runtime roots so multi-runtime users stay aligned after an update. Runs the sync-skills workflow (--from, --to, --dry-run, --apply flags supported).
33
33
  - **--reapply**: Reapply local modifications after a GSD update. Uses three-way comparison (pristine baseline, user-modified backup, newly installed version) to merge user customizations back. Runs the reapply-patches workflow.
34
+ - **--next** (alias **--rc**): Target the `@next` RC dist-tag instead of `@latest` so you can install or refresh a release candidate (e.g. `1.4.0-rc.1`) through the normal update flow — scope/runtime detection, changelog preview, custom-file backup, and cache clearing all still apply. Omitting it keeps targeting `@latest` (no change). See ADR #660 for the RC channel.
34
35
  - **(no flag)**: Standard update — check for new version, show changelog, install.
35
36
  </flags>
36
37
 
@@ -38,7 +39,7 @@ Routes to the update workflow which handles:
38
39
  Parse the first token of $ARGUMENTS:
39
40
  - If it is `--sync`: strip the flag, execute the sync-skills workflow (passing remaining args for --from/--to/--dry-run/--apply).
40
41
  - If it is `--reapply`: strip the flag, execute the reapply-patches workflow.
41
- - Otherwise: execute the update workflow end-to-end.
42
+ - Otherwise (including `--next` / `--rc`): execute the update workflow end-to-end, passing `$ARGUMENTS` through so the workflow's parse_update_channel step can select the release channel.
42
43
 
43
44
  </process>
44
45
 
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "gsd-core",
3
+ "version": "1.4.0-rc.2",
4
+ "description": "GSD Core — a meta-prompting, context engineering, and spec-driven development system for AI coding agents. Loads gsd's operating context into every Gemini CLI session.",
5
+ "contextFileName": "GEMINI.md"
6
+ }
@@ -21,6 +21,7 @@
21
21
  */
22
22
 
23
23
  const { execNpm } = require('./lib/shell-command-projection.cjs');
24
+ const { runMain } = require('./lib/cli-exit.cjs');
24
25
 
25
26
  // Sourced from the single Package Identity seam (#498), not re-typed. The seam
26
27
  // bakes the value from package.json at build time, so it is a code constant —
@@ -36,18 +37,64 @@ const CHECK_REASON = Object.freeze({
36
37
 
37
38
  const SEMVER_RE = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/;
38
39
 
40
+ // #815: the one RC channel ADR #660 sanctions, plus the stable default.
41
+ // An allowlist (not a free string) keeps a typo from silently resolving
42
+ // `npm view` to an empty or foreign dist-tag.
43
+ const ALLOWED_TAGS = Object.freeze(['latest', 'next']);
44
+
45
+ /**
46
+ * Build the `npm view` args for a dist-tag. `latest` keeps the bare package
47
+ * spec so the default invocation is byte-for-byte identical to before tag
48
+ * support existed (#815); any other allowlisted tag appends `@<tag>` so
49
+ * `npm view @opengsd/gsd-core@next version` resolves the RC channel (#660).
50
+ */
51
+ function buildViewArgs(tag = 'latest') {
52
+ if (!ALLOWED_TAGS.includes(tag)) {
53
+ throw new RangeError(`invalid dist-tag '${tag}'; allowed: ${ALLOWED_TAGS.join(', ')}`);
54
+ }
55
+ const spec = tag === 'latest' ? PACKAGE_NAME : `${PACKAGE_NAME}@${tag}`;
56
+ return ['view', spec, 'version'];
57
+ }
58
+
59
+ /**
60
+ * Resolve the requested dist-tag from argv. Defaults to `latest` (no flag =>
61
+ * no behavior change). Restricted to ALLOWED_TAGS so a typo can't silently
62
+ * resolve to an empty/foreign tag (#815 alternative 1).
63
+ */
64
+ function resolveTag(argv) {
65
+ let val;
66
+ const eq = argv.find((a) => typeof a === 'string' && a.startsWith('--tag='));
67
+ if (eq !== undefined) {
68
+ val = eq.slice('--tag='.length);
69
+ } else {
70
+ const i = argv.indexOf('--tag');
71
+ if (i === -1) return 'latest';
72
+ val = argv[i + 1];
73
+ }
74
+ if (!val || !ALLOWED_TAGS.includes(val)) {
75
+ throw new RangeError(
76
+ `invalid --tag '${val || ''}'; allowed: ${ALLOWED_TAGS.join(', ')}`,
77
+ );
78
+ }
79
+ return val;
80
+ }
81
+
39
82
  /**
40
83
  * Pure-ish: takes an injected spawn function so tests don't actually run npm.
41
84
  * In production, defaults to execNpm() from the shell-projection seam.
42
85
  */
43
86
  function checkLatestVersion(opts = {}) {
87
+ const tag = opts.tag || 'latest';
88
+ if (!ALLOWED_TAGS.includes(tag)) {
89
+ throw new RangeError(`invalid dist-tag '${tag}'; allowed: ${ALLOWED_TAGS.join(', ')}`);
90
+ }
44
91
  // Default path routes through the shell-projection seam (execNpm owns the
45
92
  // Windows shell-flag policy and timeout default). The injection point
46
93
  // remains spawnSync-shaped for test compatibility — the adapter below
47
94
  // translates { exitCode } → { status } so the consumer logic is unchanged.
48
95
  // Bounded at 15s so a hung registry doesn't block /gsd-update (#2993 CR).
49
96
  const defaultSpawn = () => {
50
- const r = execNpm(['view', PACKAGE_NAME, 'version'], { timeout: 15_000 });
97
+ const r = execNpm(buildViewArgs(tag), { timeout: 15_000 });
51
98
  return {
52
99
  status: r.exitCode,
53
100
  stdout: r.stdout,
@@ -89,8 +136,16 @@ function checkLatestVersion(opts = {}) {
89
136
  }
90
137
 
91
138
  function main() {
92
- const json = process.argv.includes('--json');
93
- const r = checkLatestVersion();
139
+ const argv = process.argv.slice(2);
140
+ const json = argv.includes('--json');
141
+ let tag;
142
+ try {
143
+ tag = resolveTag(argv);
144
+ } catch (e) {
145
+ process.stderr.write(`check-latest-version: ${e.message}\n`);
146
+ return 2;
147
+ }
148
+ const r = checkLatestVersion({ tag });
94
149
  if (json) {
95
150
  process.stdout.write(JSON.stringify(r) + '\n');
96
151
  } else if (r.ok) {
@@ -98,9 +153,9 @@ function main() {
98
153
  } else {
99
154
  process.stderr.write(`check-latest-version: ${r.reason}: ${r.detail}\n`);
100
155
  }
101
- process.exit(r.ok ? 0 : 1);
156
+ return r.ok ? 0 : 1;
102
157
  }
103
158
 
104
- if (require.main === module) main();
159
+ if (require.main === module) runMain(main);
105
160
 
106
- module.exports = { checkLatestVersion, CHECK_REASON, PACKAGE_NAME };
161
+ module.exports = { checkLatestVersion, CHECK_REASON, PACKAGE_NAME, ALLOWED_TAGS, buildViewArgs, resolveTag };