@opengsd/gsd-core 1.7.0 → 1.9.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.
Files changed (261) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +45 -1
  4. package/README.md +2 -0
  5. package/agents/gsd-code-fixer.md +1 -1
  6. package/agents/gsd-codebase-mapper.md +1 -1
  7. package/agents/gsd-debug-session-manager.md +78 -4
  8. package/agents/gsd-debugger.md +87 -29
  9. package/agents/gsd-executor.md +49 -9
  10. package/agents/gsd-intel-updater.md +3 -3
  11. package/agents/gsd-phase-researcher.md +4 -2
  12. package/agents/gsd-plan-checker.md +20 -0
  13. package/agents/gsd-planner.md +44 -59
  14. package/agents/gsd-project-researcher.md +2 -2
  15. package/agents/gsd-ui-auditor.md +0 -40
  16. package/agents/gsd-verifier.md +2 -2
  17. package/bin/install.js +1338 -135
  18. package/commands/gsd/ai-integration-phase.md +1 -1
  19. package/commands/gsd/mempalace-capture.md +9 -5
  20. package/commands/gsd/new-milestone.md +1 -1
  21. package/commands/gsd/plan-phase.md +5 -3
  22. package/commands/gsd/plan-review-convergence.md +7 -2
  23. package/gsd-core/bin/gsd-tools.cjs +2690 -2472
  24. package/gsd-core/bin/lib/adapter-imperative.cjs +8 -1
  25. package/gsd-core/bin/lib/agent-command-router.cjs +20 -5
  26. package/gsd-core/bin/lib/api-coverage.cjs +360 -53
  27. package/gsd-core/bin/lib/audit.cjs +8 -8
  28. package/gsd-core/bin/lib/broken-windows.cjs +716 -0
  29. package/gsd-core/bin/lib/capability-command-router.cjs +733 -0
  30. package/gsd-core/bin/lib/capability-consent.cjs +40 -1
  31. package/gsd-core/bin/lib/capability-lifecycle.cjs +58 -0
  32. package/gsd-core/bin/lib/capability-loader.cjs +23 -1
  33. package/gsd-core/bin/lib/capability-registry.cjs +1450 -160
  34. package/gsd-core/bin/lib/capability-trust.cjs +468 -33
  35. package/gsd-core/bin/lib/capability-validator.cjs +882 -6
  36. package/gsd-core/bin/lib/capability-writer.cjs +6 -1
  37. package/gsd-core/bin/lib/check-command-router.cjs +140 -27
  38. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +15 -0
  39. package/gsd-core/bin/lib/claude-orchestration-command-router.cjs +209 -31
  40. package/gsd-core/bin/lib/claude-orchestration.cjs +203 -25
  41. package/gsd-core/bin/lib/command-aliases.cjs +14 -0
  42. package/gsd-core/bin/lib/commands.cjs +326 -21
  43. package/gsd-core/bin/lib/config-loader.cjs +214 -30
  44. package/gsd-core/bin/lib/config.cjs +158 -22
  45. package/gsd-core/bin/lib/core-utils.cjs +6 -1
  46. package/gsd-core/bin/lib/decisions.cjs +32 -8
  47. package/gsd-core/bin/lib/docs.cjs +6 -0
  48. package/gsd-core/bin/lib/estimate-cli.cjs +336 -0
  49. package/gsd-core/bin/lib/external-descriptor-trust.cjs +14 -2
  50. package/gsd-core/bin/lib/frontmatter.cjs +125 -15
  51. package/gsd-core/bin/lib/gap-checker.cjs +17 -2
  52. package/gsd-core/bin/lib/host-integration.cjs +215 -8
  53. package/gsd-core/bin/lib/init.cjs +155 -66
  54. package/gsd-core/bin/lib/install-engine.cjs +299 -23
  55. package/gsd-core/bin/lib/install-profiles.cjs +239 -1
  56. package/gsd-core/bin/lib/installer-migrations/005-opencode-baseline-commands-dir.cjs +146 -0
  57. package/gsd-core/bin/lib/installer-migrations/006-pi-extension-cjs-to-js.cjs +91 -0
  58. package/gsd-core/bin/lib/installer-migrations.cjs +44 -5
  59. package/gsd-core/bin/lib/markdown-sectionizer.cjs +107 -0
  60. package/gsd-core/bin/lib/milestone.cjs +248 -14
  61. package/gsd-core/bin/lib/model-catalog.cjs +69 -4
  62. package/gsd-core/bin/lib/model-resolver.cjs +189 -7
  63. package/gsd-core/bin/lib/observability/logger.cjs +7 -2
  64. package/gsd-core/bin/lib/onboard-projection.cjs +11 -8
  65. package/gsd-core/bin/lib/phase-command-router.cjs +10 -1
  66. package/gsd-core/bin/lib/phase-estimation.cjs +398 -0
  67. package/gsd-core/bin/lib/phase-id.cjs +304 -9
  68. package/gsd-core/bin/lib/phase.cjs +258 -17
  69. package/gsd-core/bin/lib/plan-drift-guard.cjs +1 -1
  70. package/gsd-core/bin/lib/plan-scan.cjs +70 -2
  71. package/gsd-core/bin/lib/planning-workspace.cjs +9 -2
  72. package/gsd-core/bin/lib/profile-output.cjs +34 -8
  73. package/gsd-core/bin/lib/review-lane-descriptor.cjs +927 -0
  74. package/gsd-core/bin/lib/review-lane-invocation.cjs +348 -0
  75. package/gsd-core/bin/lib/review-lane-runner.cjs +594 -0
  76. package/gsd-core/bin/lib/review-reviewer-selection.cjs +114 -32
  77. package/gsd-core/bin/lib/roadmap-parser.cjs +61 -10
  78. package/gsd-core/bin/lib/roadmap.cjs +23 -7
  79. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +38 -5
  80. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +23 -9
  81. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +156 -0
  82. package/gsd-core/bin/lib/runtime-name-policy.cjs +15 -2
  83. package/gsd-core/bin/lib/smart-entry.cjs +70 -5
  84. package/gsd-core/bin/lib/state-document.cjs +171 -24
  85. package/gsd-core/bin/lib/state-transition.cjs +50 -11
  86. package/gsd-core/bin/lib/state.cjs +206 -32
  87. package/gsd-core/bin/lib/surface.cjs +51 -9
  88. package/gsd-core/bin/lib/uat-predicate.cjs +6 -4
  89. package/gsd-core/bin/lib/uat.cjs +428 -11
  90. package/gsd-core/bin/lib/ui-consideration-probe.cjs +2 -2
  91. package/gsd-core/bin/lib/unusable-input.cjs +216 -0
  92. package/gsd-core/bin/lib/validate.cjs +44 -8
  93. package/gsd-core/bin/lib/verification.cjs +163 -31
  94. package/gsd-core/bin/lib/verify.cjs +348 -42
  95. package/gsd-core/bin/lib/worktree-safety.cjs +360 -15
  96. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  97. package/gsd-core/bin/shared/config-schema.manifest.json +4 -15
  98. package/gsd-core/bin/shared/model-catalog.json +5 -0
  99. package/gsd-core/bin/shared/runtime-aliases.manifest.json +5 -0
  100. package/gsd-core/references/api-coverage.md +37 -7
  101. package/gsd-core/references/checkpoints.md +1 -1
  102. package/gsd-core/references/common-bug-patterns.md +13 -0
  103. package/gsd-core/references/context-budget.md +40 -0
  104. package/gsd-core/references/debugger-bug-taxonomy.md +111 -0
  105. package/gsd-core/references/debugger-fix-acceptance.md +157 -0
  106. package/gsd-core/references/debugger-philosophy.md +1 -0
  107. package/gsd-core/references/debugger-prevention.md +98 -0
  108. package/gsd-core/references/debugger-rca-branching.md +98 -0
  109. package/gsd-core/references/debugger-repro-hardening.md +130 -0
  110. package/gsd-core/references/debugger-sbfl.md +110 -0
  111. package/gsd-core/references/debugger-semantic-recall.md +81 -0
  112. package/gsd-core/references/execute-phase-quota-recovery.md +55 -0
  113. package/gsd-core/references/execute-phase-requirement-revert.md +8 -0
  114. package/gsd-core/references/execute-phase-response-language.md +7 -0
  115. package/gsd-core/references/gate-prompts.md +6 -3
  116. package/gsd-core/references/model-profile-resolution.md +64 -13
  117. package/gsd-core/references/offer-next.md +88 -0
  118. package/gsd-core/references/planner-antipatterns.md +6 -0
  119. package/gsd-core/references/planner-mvp-mode.md +12 -13
  120. package/gsd-core/references/planner-preconditions.md +156 -0
  121. package/gsd-core/references/planner-reversibility.md +132 -0
  122. package/gsd-core/references/planning-config.md +2 -1
  123. package/gsd-core/references/reviewer-instances.md +28 -19
  124. package/gsd-core/references/runtime-aware-dispatch.md +42 -0
  125. package/gsd-core/references/skeleton-template.md +1 -1
  126. package/gsd-core/references/thinking-models-planning.md +3 -1
  127. package/gsd-core/references/ui-consideration-probe.md +2 -2
  128. package/gsd-core/references/worktree-branch-check.md +4 -4
  129. package/gsd-core/templates/DEBUG.md +5 -3
  130. package/gsd-core/templates/summary-minimal.md +4 -0
  131. package/gsd-core/templates/summary-standard.md +4 -0
  132. package/gsd-core/templates/summary.md +7 -0
  133. package/gsd-core/workflows/add-phase.md +2 -0
  134. package/gsd-core/workflows/add-tests.md +3 -1
  135. package/gsd-core/workflows/add-todo.md +32 -1
  136. package/gsd-core/workflows/ai-integration-phase.md +8 -6
  137. package/gsd-core/workflows/audit-fix.md +6 -2
  138. package/gsd-core/workflows/audit-milestone.md +8 -0
  139. package/gsd-core/workflows/autonomous.md +19 -15
  140. package/gsd-core/workflows/check-todos.md +5 -3
  141. package/gsd-core/workflows/cleanup.md +7 -1
  142. package/gsd-core/workflows/code-review-fix.md +14 -6
  143. package/gsd-core/workflows/code-review.md +93 -24
  144. package/gsd-core/workflows/complete-milestone.md +3 -0
  145. package/gsd-core/workflows/debug.md +35 -7
  146. package/gsd-core/workflows/diagnose-issues.md +5 -1
  147. package/gsd-core/workflows/discovery-phase.md +7 -0
  148. package/gsd-core/workflows/discuss-phase/modes/advisor.md +2 -4
  149. package/gsd-core/workflows/discuss-phase/modes/auto.md +0 -6
  150. package/gsd-core/workflows/discuss-phase/templates/context.md +16 -2
  151. package/gsd-core/workflows/discuss-phase-assumptions.md +18 -9
  152. package/gsd-core/workflows/discuss-phase.md +2 -2
  153. package/gsd-core/workflows/do.md +7 -1
  154. package/gsd-core/workflows/docs-update.md +9 -0
  155. package/gsd-core/workflows/eval-review.md +4 -1
  156. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +4 -0
  157. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +160 -0
  158. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +4 -4
  159. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -2
  160. package/gsd-core/workflows/execute-phase.md +110 -149
  161. package/gsd-core/workflows/execute-plan.md +20 -8
  162. package/gsd-core/workflows/explore.md +4 -0
  163. package/gsd-core/workflows/extract-learnings.md +21 -0
  164. package/gsd-core/workflows/graduation.md +3 -0
  165. package/gsd-core/workflows/health.md +7 -1
  166. package/gsd-core/workflows/help/modes/full.md +9 -5
  167. package/gsd-core/workflows/import.md +11 -2
  168. package/gsd-core/workflows/inbox.md +7 -0
  169. package/gsd-core/workflows/ingest-docs.md +19 -10
  170. package/gsd-core/workflows/manager.md +3 -1
  171. package/gsd-core/workflows/map-codebase.md +17 -10
  172. package/gsd-core/workflows/mvp-phase.md +3 -0
  173. package/gsd-core/workflows/new-milestone.md +79 -23
  174. package/gsd-core/workflows/new-project.md +28 -19
  175. package/gsd-core/workflows/new-workspace.md +3 -1
  176. package/gsd-core/workflows/next.md +5 -2
  177. package/gsd-core/workflows/onboard.md +3 -0
  178. package/gsd-core/workflows/plan-phase.md +56 -51
  179. package/gsd-core/workflows/plan-review-convergence.md +61 -12
  180. package/gsd-core/workflows/plant-seed.md +3 -0
  181. package/gsd-core/workflows/profile-user.md +7 -1
  182. package/gsd-core/workflows/progress.md +31 -3
  183. package/gsd-core/workflows/quick.md +33 -10
  184. package/gsd-core/workflows/remove-workspace.md +3 -0
  185. package/gsd-core/workflows/review.md +172 -585
  186. package/gsd-core/workflows/scan.md +10 -2
  187. package/gsd-core/workflows/secure-phase.md +13 -2
  188. package/gsd-core/workflows/settings-integrations.md +3 -0
  189. package/gsd-core/workflows/settings.md +3 -0
  190. package/gsd-core/workflows/ship.md +88 -11
  191. package/gsd-core/workflows/sketch.md +3 -0
  192. package/gsd-core/workflows/smart-entry.md +4 -1
  193. package/gsd-core/workflows/spike.md +7 -1
  194. package/gsd-core/workflows/ui-phase.md +11 -2
  195. package/gsd-core/workflows/ui-review.md +11 -1
  196. package/gsd-core/workflows/undo.md +7 -0
  197. package/gsd-core/workflows/update.md +106 -5
  198. package/gsd-core/workflows/validate-phase.md +13 -2
  199. package/gsd-core/workflows/verify-phase.md +2 -2
  200. package/gsd-core/workflows/verify-work.md +15 -4
  201. package/hooks/dist/gsd-context-monitor.js +27 -9
  202. package/hooks/dist/gsd-cursor-session-start.js +6 -2
  203. package/hooks/dist/gsd-cursor-stop.js +6 -2
  204. package/hooks/dist/gsd-cursor-subagent-start.js +6 -2
  205. package/hooks/dist/gsd-graphify-update.sh +9 -0
  206. package/hooks/dist/gsd-phase-boundary.sh +14 -2
  207. package/hooks/dist/gsd-prompt-guard.js +101 -2
  208. package/hooks/dist/gsd-read-guard.js +100 -2
  209. package/hooks/dist/gsd-read-injection-scanner.js +109 -2
  210. package/hooks/dist/gsd-statusline.js +97 -9
  211. package/hooks/dist/gsd-workflow-guard.js +110 -6
  212. package/hooks/dist/gsd-worktree-path-guard.js +132 -8
  213. package/hooks/dist/lib/cursor-workspace.js +74 -0
  214. package/hooks/gsd-context-monitor.js +27 -9
  215. package/hooks/gsd-cursor-session-start.js +6 -2
  216. package/hooks/gsd-cursor-stop.js +6 -2
  217. package/hooks/gsd-cursor-subagent-start.js +6 -2
  218. package/hooks/gsd-graphify-update.sh +9 -0
  219. package/hooks/gsd-phase-boundary.sh +14 -2
  220. package/hooks/gsd-prompt-guard.js +101 -2
  221. package/hooks/gsd-read-guard.js +100 -2
  222. package/hooks/gsd-read-injection-scanner.js +109 -2
  223. package/hooks/gsd-statusline.js +97 -9
  224. package/hooks/gsd-workflow-guard.js +110 -6
  225. package/hooks/gsd-worktree-path-guard.js +132 -8
  226. package/hooks/lib/cursor-workspace.js +74 -0
  227. package/package.json +10 -8
  228. package/pi/gsd.cjs +34 -3
  229. package/scripts/changeset/lint.cjs +1 -0
  230. package/scripts/changeset/parse.cjs +26 -0
  231. package/scripts/check-coverage-gate.cjs +51 -0
  232. package/scripts/check-glossary-refs.cjs +244 -0
  233. package/scripts/ci-rebase-check.cjs +48 -4
  234. package/scripts/ci-test-scope.cjs +67 -17
  235. package/scripts/gen-adr-index.cjs +528 -0
  236. package/scripts/gen-capability-matrix.cjs +26 -2
  237. package/scripts/gen-capability-registry.cjs +132 -34
  238. package/scripts/gen-emitted-baseline.cjs +145 -0
  239. package/scripts/gen-test-timings.cjs +201 -0
  240. package/scripts/lint-compiled-artifact-sync.cjs +146 -0
  241. package/scripts/lint-emitted-drift-ack.cjs +149 -0
  242. package/scripts/lint-fix-has-regression-test.cjs +131 -0
  243. package/scripts/lint-portable-timeout.cjs +140 -0
  244. package/scripts/lint-resolution-provenance.cjs +9 -0
  245. package/scripts/lint-test-file-count.allowlist.json +1 -0
  246. package/scripts/mutation-matrix.cjs +4 -0
  247. package/scripts/prompt-injection-scan.sh +6 -0
  248. package/scripts/registry-schema.cjs +57 -8
  249. package/scripts/release-notes/conventional-title.cjs +19 -1
  250. package/scripts/release-notes/format-github-release-notes.cjs +7 -3
  251. package/scripts/release-tarball-smoke.cjs +18 -11
  252. package/scripts/run-tests.cjs +420 -58
  253. package/scripts/workflow-size.cjs +16 -8
  254. package/skills/gsd-ai-integration-phase/SKILL.md +1 -1
  255. package/skills/gsd-mempalace-capture/SKILL.md +9 -5
  256. package/skills/gsd-new-milestone/SKILL.md +1 -1
  257. package/skills/gsd-plan-phase/SKILL.md +5 -3
  258. package/skills/gsd-plan-review-convergence/SKILL.md +7 -2
  259. package/vscode/package.json +1 -1
  260. package/scripts/gen-golden-install-parity-zcode.cjs +0 -77
  261. package/scripts/update-size-baseline.cjs +0 -68
@@ -36,6 +36,11 @@
36
36
  * (`{ namedDispatch, nested, maxDepth, background, subagentToolkit }`) —
37
37
  * this registry accepts a free-form human summary string instead, so it
38
38
  * carries the `AXES_FREE_STRING` sentinel rather than an enum array.
39
+ * `OPTIONAL_AXES` adds one further, OPTIONAL key on top of those eight:
40
+ * `effortSurface` (ADR-1239 amendment #2481). An entry may omit it
41
+ * (every entry published before the amendment stays valid) or declare
42
+ * it as `argv` | `none`, mirroring `HOST_INTEGRATION_AXES.effortSurface`
43
+ * in `src/host-integration.cts`.
39
44
  * - `CAPABILITY_REQUIRED` / `EOS_REQUIRED` mirror the required top-level
40
45
  * fields for each entry type, including `enginesGsd` (ADR-1244 D1
41
46
  * "Versioned capability manifest" — the `engines.gsd` semver-range gate,
@@ -90,6 +95,18 @@ const AXES = Object.freeze({
90
95
  runtime: Object.freeze(['node', 'bun', 'sandboxed-web', 'python', 'go', 'rust', 'electron', 'other']),
91
96
  });
92
97
 
98
+ // ─── ADR-1239 amendment #2481 — one additional, OPTIONAL negotiated axis ─────
99
+ // `effortSurface` was added to the runtime-descriptor vocabulary AFTER the
100
+ // original eight (`HOST_INTEGRATION_AXES.effortSurface` in
101
+ // `src/host-integration.cts`). It is kept OPTIONAL here — not folded into
102
+ // `AXES` — because registry entries mirror their upstream
103
+ // `registry/eos-entry.json` byte-for-byte, and requiring it would
104
+ // retroactively invalidate every entry published before the amendment.
105
+ // Values must match `HOST_INTEGRATION_AXES.effortSurface` exactly.
106
+ const OPTIONAL_AXES = Object.freeze({
107
+ effortSurface: Object.freeze(['argv', 'none']),
108
+ });
109
+
93
110
  // ─── Required top-level fields ───────────────────────────────────────────────
94
111
  const CAPABILITY_REQUIRED = Object.freeze([
95
112
  'id',
@@ -246,15 +263,39 @@ function validateEosInteractions(interactions, addError) {
246
263
  if (typeof axes !== 'object' || axes === null || Array.isArray(axes)) {
247
264
  addError('interactions.axes', 'axes must be an object');
248
265
  } else {
249
- const expectedKeys = Object.keys(AXES);
266
+ const requiredKeys = Object.keys(AXES);
267
+ const optionalKeys = Object.keys(OPTIONAL_AXES);
250
268
  const actualKeys = Object.keys(axes);
251
269
  const actualKeySet = new Set(actualKeys);
252
- const keysMatch = expectedKeys.length === actualKeys.length && expectedKeys.every((k) => actualKeySet.has(k));
253
- if (!keysMatch) {
254
- addError('interactions.axes', 'axes key set must exactly match the eight negotiated axes');
255
- } else {
256
- for (const key of expectedKeys) {
257
- const allowedValues = AXES[key];
270
+
271
+ // Every AXES key is mandatory; an extra key is tolerated ONLY when it is
272
+ // a recognized OPTIONAL_AXES key (currently just `effortSurface`) — any
273
+ // other extra key is still rejected as unknown.
274
+ const missingRequiredKeys = requiredKeys.filter((k) => !actualKeySet.has(k));
275
+ const unknownKeys = actualKeys.filter((k) => !requiredKeys.includes(k) && !optionalKeys.includes(k));
276
+
277
+ if (missingRequiredKeys.length > 0) {
278
+ addError('interactions.axes', `axes is missing required key(s): ${missingRequiredKeys.join(', ')}`);
279
+ }
280
+ if (unknownKeys.length > 0) {
281
+ addError('interactions.axes', `axes has unknown key(s): ${unknownKeys.join(', ')}`);
282
+ }
283
+
284
+ // Only validate individual values once the key set itself is sound —
285
+ // mirrors the original gate (values were never checked against a
286
+ // malformed key set either).
287
+ if (missingRequiredKeys.length === 0 && unknownKeys.length === 0) {
288
+ for (const key of actualKeys) {
289
+ // Inline literal guards — CodeQL barrier pattern. Reaching here already
290
+ // implies `key` is one of the nine literal axis names (the unknown-key
291
+ // gate above rejected everything else), so this is unreachable in
292
+ // practice; it is written inline anyway because CodeQL cannot follow
293
+ // that gate across the `.includes()` filter and would otherwise flag
294
+ // the bracket reads below as prototype-pollution sinks.
295
+ if (key === '__proto__') continue;
296
+ if (key === 'constructor') continue;
297
+ if (key === 'prototype') continue;
298
+ const allowedValues = Object.hasOwn(AXES, key) ? AXES[key] : OPTIONAL_AXES[key];
258
299
  const v = axes[key];
259
300
  if (allowedValues === AXES_FREE_STRING) {
260
301
  if (typeof v !== 'string' || v.trim() === '') {
@@ -496,7 +537,14 @@ function renderMarkdown(entries, opts) {
496
537
  lines.push(`- **Author:** ${mdInline(entry.author)}`);
497
538
 
498
539
  if (isEos) {
499
- const axesSummary = Object.keys(AXES)
540
+ // Required AXES keys always render, in their fixed order; an OPTIONAL_AXES
541
+ // key (e.g. `effortSurface`) renders ONLY when the entry actually carries
542
+ // it — an entry that omits it must render byte-identical to before
543
+ // OPTIONAL_AXES existed (no `effortSurface=undefined` noise).
544
+ const presentOptionalKeys = Object.keys(OPTIONAL_AXES).filter(
545
+ (key) => interactions.axes && Object.hasOwn(interactions.axes, key),
546
+ );
547
+ const axesSummary = [...Object.keys(AXES), ...presentOptionalKeys]
500
548
  .map((key) => `${key}=${interactions.axes ? interactions.axes[key] : undefined}`)
501
549
  .join(', ');
502
550
  const summary =
@@ -556,6 +604,7 @@ module.exports = {
556
604
  INTERFACE_POINTS,
557
605
  PROFILES,
558
606
  AXES,
607
+ OPTIONAL_AXES,
559
608
  AXES_FREE_STRING,
560
609
  CAPABILITY_REQUIRED,
561
610
  EOS_REQUIRED,
@@ -30,18 +30,36 @@ const HEADER_RE = /^([a-z]+)(\([^)]*\))?(!)?:/i;
30
30
  // An issue reference inside a scope: `(#123)`, `(#123, core)`, etc.
31
31
  const ISSUE_REF_IN_SCOPE_RE = /#\d+/;
32
32
 
33
+ // #2716: recognized non-user-facing conventional-commit types. A title whose
34
+ // START-anchored type prefix is one of these is internal work (tests, chores,
35
+ // CI, docs, refactors, perf, reverts) and must NOT render under the user-facing
36
+ // "Enhancement" heading in release notes. Only a CLEAN prefix match qualifies —
37
+ // untyped or anchor-defeated titles fall through to the visible Enhancement
38
+ // fallback (a safety net so possibly-user-facing content is never hidden).
39
+ const NON_USER_FACING_TYPES = new Set([
40
+ 'docs', 'refactor', 'test', 'ci', 'chore', 'perf', 'revert',
41
+ ]);
42
+
33
43
  /**
34
44
  * Classify a clean conventional title into a changelog bucket.
35
45
  * Callers that hold a full changelog bullet line (with a `* ` marker and a
36
46
  * ` by @author` suffix) must strip those first; this operates on the title.
37
47
  *
38
48
  * @param {string} title
39
- * @returns {'Feature'|'Fix'|'Enhancement'}
49
+ * @returns {'Feature'|'Fix'|'Enhancement'|'Internal'}
40
50
  */
41
51
  function classifyBucket(title) {
42
52
  const t = String(title == null ? '' : title).trim();
43
53
  if (FEATURE_RE.test(t)) return 'Feature';
44
54
  if (FIX_RE.test(t)) return 'Fix';
55
+ // #2716: a clean non-user-facing type prefix → Internal (omitted from user-facing
56
+ // release-note sections). The HEADER_RE anchor ensures a leading tag/prefix
57
+ // (e.g. `[security] fix(...)`) does NOT match here — those keep falling through
58
+ // to the visible Enhancement fallback.
59
+ const headerMatch = HEADER_RE.exec(t);
60
+ if (headerMatch && NON_USER_FACING_TYPES.has(headerMatch[1].toLowerCase())) {
61
+ return 'Internal';
62
+ }
45
63
  return 'Enhancement';
46
64
  }
47
65
 
@@ -8,9 +8,9 @@ const { runMain, ExitError } = require('../lib/cli-exit.cjs');
8
8
  const { classifyBucket } = require('./conventional-title.cjs');
9
9
 
10
10
  /**
11
- * Classify a What's-Changed bullet line into 'Feature', 'Fix', or 'Enhancement'.
11
+ * Classify a What's-Changed bullet line into 'Feature', 'Fix', 'Enhancement', or 'Internal'.
12
12
  * @param {string} bulletLine - Full bullet line including the leading `* ` or `- ` marker.
13
- * @returns {'Feature'|'Fix'|'Enhancement'}
13
+ * @returns {'Feature'|'Fix'|'Enhancement'|'Internal'}
14
14
  */
15
15
  function classifyTitle(bulletLine) {
16
16
  // Strip leading `* ` or `- ` marker
@@ -83,7 +83,11 @@ function formatReleaseNotes({ generatedBody, version, prerelease, packageName })
83
83
  const category = classifyTitle(trimmed);
84
84
  if (category === 'Feature') featureBullets.push(trimmed);
85
85
  else if (category === 'Fix') fixBullets.push(trimmed);
86
- else enhancementBullets.push(trimmed);
86
+ else if (category === 'Internal') {
87
+ // #2716: non-user-facing work (test/chore/ci/docs/refactor/perf/revert)
88
+ // is omitted from the user-facing "What's Changed" section entirely.
89
+ continue;
90
+ } else enhancementBullets.push(trimmed);
87
91
  continue;
88
92
  }
89
93
 
@@ -47,16 +47,23 @@ const os = require('os');
47
47
  const path = require('path');
48
48
  const { PACKAGE_NAME } = require('../gsd-core/bin/lib/package-identity.cjs');
49
49
  const { ExitError, runMain } = require('./lib/cli-exit.cjs');
50
- // 120 s proved too tight on Windows GitHub-hosted runners: cold-cache
51
- // `npm install -g` with a 1499-file tarball took ~120 s exactly, causing
52
- // spawnSync to fire SIGTERM and return { status: null, stdout: '', stderr: '' }
53
- // (Node docs: status is null when subprocess terminated due to a signal).
54
- // The INSTALL_FAILED branch checks `status !== 0`, which null satisfies, so the
55
- // test saw empty stdout/stderr and a spurious INSTALL_FAILED. Windows runners
56
- // are slower than Linux/macOS for filesystem-heavy operations (
57
- // https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories
58
- // ). Raise to 600 s (the same ceiling the before() helper uses for pack+install).
59
- const CHILD_TIMEOUT_MS = process.platform === 'win32' ? 600_000 : 120_000;
50
+ // 120 s proved too tight for cold-cache `npm install -g` of a 1499-file tarball:
51
+ // spawnSync fires SIGTERM at the deadline and returns { status: null, stdout: '',
52
+ // stderr: '' } (Node docs: status is null when a subprocess is terminated by a
53
+ // signal). The INSTALL_FAILED branch checks `status !== 0`, which null satisfies,
54
+ // so the test sees empty stdout/stderr and a spurious INSTALL_FAILED (surfaced as
55
+ // `installError: spawnSync npm ETIMEDOUT`).
56
+ //
57
+ // First observed on Windows GitHub-hosted runners, which are slower for
58
+ // filesystem-heavy work
59
+ // (https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories),
60
+ // then again on a slow Linux bench (cartographer: cold disk, constrained CPU) —
61
+ // the same failure the before() helper's SLOW_HOST_TIMEOUT already guards for
62
+ // pack+install. The slow-host reality is not platform-specific, so the ceiling is
63
+ // now uniform 600 s across all platforms AND shared with before() via this
64
+ // exported constant, so the two surfaces cannot diverge again. 600 s stays well
65
+ // clear of a real cold install (3–6 min) without masking a genuine hang.
66
+ const CHILD_TIMEOUT_MS = 600_000;
60
67
  const QUIET_NPM_ENV = Object.freeze({
61
68
  npm_config_loglevel: 'error',
62
69
  npm_config_update_notifier: 'false',
@@ -628,7 +635,7 @@ function cleanup(...dirs) {
628
635
  // Exports
629
636
  // ---------------------------------------------------------------------------
630
637
 
631
- module.exports = { SMOKE, runSmoke, binInvocation };
638
+ module.exports = { SMOKE, runSmoke, binInvocation, CHILD_TIMEOUT_MS };
632
639
 
633
640
  if (require.main === module) {
634
641
  runMain(cliMain);