@opengsd/gsd-core 1.5.0-rc.2 → 1.5.0-rc.4

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 (131) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/agents/gsd-advisor-researcher.md +1 -1
  3. package/agents/gsd-assumptions-analyzer.md +1 -1
  4. package/agents/gsd-code-fixer.md +1 -1
  5. package/agents/gsd-code-reviewer.md +1 -1
  6. package/agents/gsd-codebase-mapper.md +1 -1
  7. package/agents/gsd-debugger.md +1 -1
  8. package/agents/gsd-doc-writer.md +1 -1
  9. package/agents/gsd-eval-auditor.md +1 -1
  10. package/agents/gsd-executor.md +1 -1
  11. package/agents/gsd-integration-checker.md +1 -1
  12. package/agents/gsd-mempalace-curator.md +47 -0
  13. package/agents/gsd-nyquist-auditor.md +1 -0
  14. package/agents/gsd-phase-researcher.md +1 -1
  15. package/agents/gsd-plan-checker.md +1 -1
  16. package/agents/gsd-planner.md +1 -1
  17. package/agents/gsd-project-researcher.md +1 -1
  18. package/agents/gsd-research-synthesizer.md +1 -1
  19. package/agents/gsd-roadmapper.md +55 -2
  20. package/agents/gsd-security-auditor.md +1 -0
  21. package/agents/gsd-ui-auditor.md +1 -1
  22. package/agents/gsd-ui-checker.md +1 -1
  23. package/agents/gsd-ui-researcher.md +1 -1
  24. package/agents/gsd-verifier.md +13 -2
  25. package/bin/install.js +61 -64
  26. package/commands/gsd/mempalace-capture.md +71 -0
  27. package/commands/gsd/mempalace-recall.md +102 -0
  28. package/commands/gsd/ns-context.md +4 -2
  29. package/commands/gsd/progress.md +2 -1
  30. package/gemini-extension.json +1 -1
  31. package/gsd-core/bin/gsd-tools.cjs +277 -95
  32. package/gsd-core/bin/lib/active-workstream-store.cjs +6 -0
  33. package/gsd-core/bin/lib/capability-activation.cjs +86 -0
  34. package/gsd-core/bin/lib/capability-registry.cjs +1468 -11
  35. package/gsd-core/bin/lib/capability-state.cjs +128 -21
  36. package/gsd-core/bin/lib/capability-writer.cjs +354 -0
  37. package/gsd-core/bin/lib/check-command-router.cjs +328 -1
  38. package/gsd-core/bin/lib/clusters.cjs +2 -0
  39. package/gsd-core/bin/lib/command-roster.cjs +19 -0
  40. package/gsd-core/bin/lib/commands.cjs +33 -10
  41. package/gsd-core/bin/lib/config-loader.cjs +7 -8
  42. package/gsd-core/bin/lib/config-schema.cjs +32 -3
  43. package/gsd-core/bin/lib/config.cjs +81 -26
  44. package/gsd-core/bin/lib/core.cjs +5 -2
  45. package/gsd-core/bin/lib/edge-probe.cjs +25 -2
  46. package/gsd-core/bin/lib/frontmatter.cjs +53 -1
  47. package/gsd-core/bin/lib/git-base-branch.cjs +194 -0
  48. package/gsd-core/bin/lib/init.cjs +36 -11
  49. package/gsd-core/bin/lib/install-profiles.cjs +57 -1
  50. package/gsd-core/bin/lib/installer-migration-report.cjs +1 -0
  51. package/gsd-core/bin/lib/loop-resolver.cjs +157 -16
  52. package/gsd-core/bin/lib/model-resolver.cjs +47 -5
  53. package/gsd-core/bin/lib/phase.cjs +99 -23
  54. package/gsd-core/bin/lib/plan-drift-guard.cjs +117 -0
  55. package/gsd-core/bin/lib/probe-core.cjs +117 -1
  56. package/gsd-core/bin/lib/profile-output.cjs +45 -4
  57. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +138 -0
  58. package/gsd-core/bin/lib/roadmap-parser.cjs +13 -3
  59. package/gsd-core/bin/lib/roadmap.cjs +97 -7
  60. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +1946 -0
  61. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +54 -30
  62. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +27 -19
  63. package/gsd-core/bin/lib/runtime-homes.cjs +26 -20
  64. package/gsd-core/bin/lib/state-command-router.cjs +15 -3
  65. package/gsd-core/bin/lib/state-document.cjs +46 -1
  66. package/gsd-core/bin/lib/state.cjs +461 -94
  67. package/gsd-core/bin/lib/verify.cjs +92 -8
  68. package/gsd-core/bin/lib/worktree-safety.cjs +2 -1
  69. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -2
  70. package/gsd-core/bin/shared/config-schema.manifest.json +0 -18
  71. package/gsd-core/bin/shared/model-catalog.json +1 -0
  72. package/gsd-core/references/edge-probe.md +11 -0
  73. package/gsd-core/references/loop-hook-dispatch.md +61 -0
  74. package/gsd-core/references/prohibition-probe-fixtures/01-streak-reminder/expected.json +14 -0
  75. package/gsd-core/references/prohibition-probe-fixtures/02-clean-utility/expected.json +4 -0
  76. package/gsd-core/references/prohibition-probe-fixtures/03-multi-prohibition/expected.json +32 -0
  77. package/gsd-core/references/prohibition-probe.md +248 -0
  78. package/gsd-core/templates/config.json +1 -1
  79. package/gsd-core/templates/spec.md +14 -0
  80. package/gsd-core/workflows/audit-milestone.md +5 -3
  81. package/gsd-core/workflows/autonomous.md +10 -5
  82. package/gsd-core/workflows/code-review-fix.md +9 -7
  83. package/gsd-core/workflows/code-review.md +8 -6
  84. package/gsd-core/workflows/complete-milestone.md +1 -5
  85. package/gsd-core/workflows/discuss-phase.md +14 -0
  86. package/gsd-core/workflows/execute-phase.md +86 -146
  87. package/gsd-core/workflows/execute-plan.md +21 -6
  88. package/gsd-core/workflows/help/modes/full.md +7 -1
  89. package/gsd-core/workflows/new-project.md +3 -3
  90. package/gsd-core/workflows/next.md +50 -2
  91. package/gsd-core/workflows/pause-work.md +7 -1
  92. package/gsd-core/workflows/plan-phase.md +91 -221
  93. package/gsd-core/workflows/plan-review-convergence.md +14 -4
  94. package/gsd-core/workflows/pr-branch.md +4 -2
  95. package/gsd-core/workflows/profile-user.md +3 -1
  96. package/gsd-core/workflows/progress.md +58 -1
  97. package/gsd-core/workflows/quick.md +12 -8
  98. package/gsd-core/workflows/resume-project.md +17 -1
  99. package/gsd-core/workflows/review.md +19 -2
  100. package/gsd-core/workflows/secure-phase.md +4 -2
  101. package/gsd-core/workflows/settings-advanced.md +2 -0
  102. package/gsd-core/workflows/settings.md +27 -1
  103. package/gsd-core/workflows/ship.md +58 -5
  104. package/gsd-core/workflows/spec-phase.md +75 -0
  105. package/gsd-core/workflows/validate-phase.md +4 -2
  106. package/gsd-core/workflows/verify-phase.md +14 -4
  107. package/gsd-core/workflows/verify-work.md +27 -11
  108. package/hooks/dist/gsd-ensure-canonical-path.js +305 -0
  109. package/hooks/dist/gsd-statusline.js +1 -1
  110. package/hooks/dist/managed-hooks-registry.cjs +1 -0
  111. package/hooks/gsd-ensure-canonical-path.js +305 -0
  112. package/hooks/gsd-statusline.js +1 -1
  113. package/hooks/hooks.json +1 -0
  114. package/hooks/managed-hooks-registry.cjs +1 -0
  115. package/package.json +5 -4
  116. package/scripts/affected-tests-lib.cjs +16 -4
  117. package/scripts/build-hooks.js +7 -0
  118. package/scripts/changeset/new.cjs +17 -3
  119. package/scripts/fix-slash-commands.cjs +15 -3
  120. package/scripts/gen-capability-registry.cjs +373 -49
  121. package/scripts/gen-inventory-manifest.cjs +1 -4
  122. package/scripts/gen-loop-host-contract.cjs +55 -0
  123. package/scripts/issue-version-gate.cjs +140 -0
  124. package/scripts/lint-allow-test-rule-refs.allowlist.json +327 -0
  125. package/scripts/lint-allow-test-rule-refs.cjs +162 -0
  126. package/scripts/lint-test-file-count.allowlist.json +14 -0
  127. package/scripts/mutation-matrix.cjs +108 -7
  128. package/scripts/pr-target-policy.cjs +63 -0
  129. package/scripts/release-tarball-smoke.cjs +7 -1
  130. package/scripts/research-profiles.cjs +5 -5
  131. package/scripts/run-tests.cjs +178 -17
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengsd/gsd-core",
3
- "version": "1.5.0-rc.2",
3
+ "version": "1.5.0-rc.4",
4
4
  "description": "GSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
5
5
  "bin": {
6
6
  "gsd-core": "bin/install.js",
@@ -92,7 +92,8 @@
92
92
  "pretest:coverage": "npm run build:lib && npm run lint:skill-deps",
93
93
  "lint": "eslint . --cache --cache-location node_modules/.cache/eslint/",
94
94
  "lint:fix": "eslint . --fix",
95
- "lint:ci": "npm run lint && npm run lint:skill-deps && node scripts/lint-test-file-count.cjs && node scripts/lint-command-contract.cjs && node scripts/lint-pr-check-project-dir.cjs && npm run lint:legacy-name && node scripts/lint-regression-test-names.cjs && node scripts/lint-windows-test-portability.cjs",
95
+ "lint:ci": "npm run lint && npm run lint:skill-deps && node scripts/lint-test-file-count.cjs && node scripts/lint-command-contract.cjs && node scripts/lint-pr-check-project-dir.cjs && npm run lint:legacy-name && node scripts/lint-regression-test-names.cjs && node scripts/lint-windows-test-portability.cjs && node scripts/lint-allow-test-rule-refs.cjs",
96
+ "lint:allow-test-rule-refs": "node scripts/lint-allow-test-rule-refs.cjs",
96
97
  "lint:windows-test-portability": "node scripts/lint-windows-test-portability.cjs",
97
98
  "lint:regression-names": "node scripts/lint-regression-test-names.cjs",
98
99
  "lint:descriptions": "node scripts/lint-descriptions.cjs",
@@ -113,9 +114,9 @@
113
114
  "test:security": "node scripts/run-tests.cjs --suite security",
114
115
  "test:slow": "node scripts/run-tests.cjs --suite slow",
115
116
  "test:affected": "node scripts/run-affected-tests.cjs",
116
- "test:coverage": "c8 --check-coverage --lines 70 --reporter text --include 'gsd-core/bin/lib/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs",
117
+ "test:coverage": "c8 --check-coverage --lines 70 --branches 60 --reporter text --include 'gsd-core/bin/lib/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs",
117
118
  "test:coverage:scripts-floor": "c8 check-coverage --lines 55 --include 'scripts/**/*.cjs' --exclude 'tests/**' --all",
118
- "test:coverage:unit": "c8 --check-coverage --lines 70 --reporter text --include 'gsd-core/bin/lib/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs --suite unit",
119
+ "test:coverage:unit": "c8 --check-coverage --lines 70 --branches 60 --reporter text --include 'gsd-core/bin/lib/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs --suite unit && c8 check-coverage --per-file --lines 0 --functions 0 --statements 0 --branches 70 --include 'gsd-core/bin/lib/state.cjs' --include 'gsd-core/bin/lib/phase.cjs' --include 'gsd-core/bin/lib/verify.cjs' --include 'gsd-core/bin/lib/init.cjs' --exclude 'tests/**'",
119
120
  "test:coverage:all": "npm run test:coverage",
120
121
  "test:mutation": "stryker run",
121
122
  "test:mutation:since": "stryker run --incremental --since origin/next"
@@ -259,10 +259,21 @@ function shouldRunFullSuite(changedFiles) {
259
259
  }
260
260
 
261
261
  function listTestFiles(repoRoot) {
262
- return readdirSync(path.join(repoRoot, 'tests'))
263
- .filter(file => file.endsWith('.test.cjs'))
264
- .map(file => `tests/${file}`)
265
- .sort();
262
+ const results = [];
263
+ function walk(dir, relBase) {
264
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
265
+ if (entry.isDirectory()) {
266
+ if (entry.name === 'node_modules') continue;
267
+ const nextRel = relBase ? `${relBase}/${entry.name}` : entry.name;
268
+ walk(path.join(dir, entry.name), nextRel);
269
+ } else if (entry.name.endsWith('.test.cjs')) {
270
+ const rel = relBase ? `${relBase}/${entry.name}` : entry.name;
271
+ results.push(`tests/${rel}`);
272
+ }
273
+ }
274
+ }
275
+ walk(path.join(repoRoot, 'tests'), '');
276
+ return results.sort();
266
277
  }
267
278
 
268
279
  /**
@@ -531,6 +542,7 @@ module.exports = {
531
542
  buildForwardGraph,
532
543
  buildReverseIndex,
533
544
  buildTransitiveReverseIndex,
545
+ listTestFiles,
534
546
  parseRelativeSpecifiers,
535
547
  pickAffectedTests,
536
548
  resolveBaseRef,
@@ -26,6 +26,13 @@ const STAGE_DIR = path.join(HOOKS_DIR, `.dist-staging-${process.pid}`);
26
26
  const HOOKS_TO_COPY = [
27
27
  'gsd-check-update-worker.js',
28
28
  'gsd-check-update.js',
29
+ // SessionStart canonical-path bootstrap (#997). In a Claude Code marketplace
30
+ // plugin install, ~/.claude/gsd-core is never created, so every
31
+ // `@~/.claude/gsd-core/...` include in agents/commands/templates resolves to
32
+ // nothing. This hook symlinks the canonical path's immutable subdirs to the
33
+ // plugin's bundled gsd-core/ tree; no-op in classic installs. Must ship to
34
+ // dist so the installer copies it into the target hooks/ dir.
35
+ 'gsd-ensure-canonical-path.js',
29
36
  // Required by gsd-check-update-worker.js at runtime — must ship alongside it
30
37
  // so require('./managed-hooks-registry.cjs') resolves in the installed hooks/ dir.
31
38
  'managed-hooks-registry.cjs',
@@ -106,8 +106,14 @@ function parseArgs(argv) {
106
106
  const r = requireValue(a, i);
107
107
  if (!r.ok) return { ok: false, error: r.error };
108
108
  if (a === '--type') opts.type = r.value;
109
- else if (a === '--pr') opts.pr = Number(r.value);
110
- else if (a === '--body') opts.body = r.value;
109
+ else if (a === '--pr') {
110
+ // Accept only decimal-integer strings (digits only, no sign, no dot,
111
+ // no hex prefix, no scientific notation). Non-integer input — including
112
+ // empty string and whitespace — is normalized to NaN so the prNaN
113
+ // guard below rejects it with the usage error.
114
+ const trimmed = r.value.trim();
115
+ opts.pr = /^\d+$/.test(trimmed) ? Number(trimmed) : NaN;
116
+ } else if (a === '--body') opts.body = r.value;
111
117
  else if (a === '--repo') opts.repo = r.value;
112
118
  i++;
113
119
  continue;
@@ -125,7 +131,15 @@ function main() {
125
131
  throw new ExitError(2);
126
132
  }
127
133
  const { opts } = parsed;
128
- if (!opts.type || !opts.pr || !opts.body) {
134
+ // opts.pr starts as null (missing flag) and is set by parseArgs to a Number when
135
+ // the raw value is a pure decimal-integer string (digits only), or to NaN for any
136
+ // other input (empty, whitespace, floats, hex, negatives, scientific notation, etc.).
137
+ // Accept integer 0 (the documented pr:0 placeholder); reject a missing flag (null)
138
+ // and any non-decimal-integer value (NaN). The merge/lint gate separately
139
+ // enforces pr > 0 before a fragment can land, so 0 still cannot be merged.
140
+ const prMissing = opts.pr === null;
141
+ const prNaN = typeof opts.pr === 'number' && Number.isNaN(opts.pr);
142
+ if (!opts.type || prMissing || prNaN || !opts.body) {
129
143
  throw new ExitError(2, 'usage: changeset/new.cjs --type <Fixed|Added|...> --pr NNNN --body "..."');
130
144
  }
131
145
  const file = scaffoldFragment(opts);
@@ -92,9 +92,21 @@ function transformContentToHyphen(src, cmdNames) {
92
92
  }
93
93
 
94
94
  function readCmdNames() {
95
- return fs.readdirSync(COMMANDS_DIR)
96
- .filter(f => f.endsWith('.md'))
97
- .map(f => f.replace(/\.md$/, ''));
95
+ try {
96
+ return fs.readdirSync(COMMANDS_DIR)
97
+ .filter(f => f.endsWith('.md'))
98
+ .map(f => f.replace(/\.md$/, ''));
99
+ } catch (err) {
100
+ // Only swallow the missing-directory case. Any other error (EACCES, ENOTDIR,
101
+ // etc.) indicates a real misconfiguration and must propagate so callers are
102
+ // not silently handed an empty registry while the real problem goes undetected.
103
+ if (err.code !== 'ENOENT') throw err;
104
+ // COMMANDS_DIR may not exist on installs that use skill-based runtimes or
105
+ // global Claude installs (no local commands/gsd/ directory). Return [] so
106
+ // callers that handle an empty array gracefully (buildPattern returns null,
107
+ // transformContent is a no-op) are not broken by a missing directory.
108
+ return [];
109
+ }
98
110
  }
99
111
 
100
112
  function processFile(file, cmdNames) {