@opengsd/gsd-core 1.6.0-rc.2 → 1.6.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 (157) hide show
  1. package/.claude-plugin/plugin.json +2 -1
  2. package/agents/gsd-advisor-researcher.md +2 -0
  3. package/agents/gsd-ai-researcher.md +2 -0
  4. package/agents/gsd-assumptions-analyzer.md +2 -0
  5. package/agents/gsd-doc-classifier.md +2 -0
  6. package/agents/gsd-doc-synthesizer.md +2 -0
  7. package/agents/gsd-domain-researcher.md +2 -0
  8. package/agents/gsd-eval-auditor.md +6 -9
  9. package/agents/gsd-phase-researcher.md +2 -0
  10. package/agents/gsd-planner.md +8 -57
  11. package/agents/gsd-project-researcher.md +2 -0
  12. package/agents/gsd-research-synthesizer.md +2 -0
  13. package/agents/gsd-security-auditor.md +37 -18
  14. package/agents/gsd-ui-researcher.md +2 -0
  15. package/bin/install.js +370 -18
  16. package/gemini-extension.json +1 -1
  17. package/gsd-core/bin/gsd-tools.cjs +46 -4
  18. package/gsd-core/bin/lib/audit-command-router.cjs +52 -14
  19. package/gsd-core/bin/lib/capability-lifecycle.cjs +30 -7
  20. package/gsd-core/bin/lib/capability-registry.cjs +96 -83
  21. package/gsd-core/bin/lib/capability-validator.cjs +22 -0
  22. package/gsd-core/bin/lib/cjs-command-router-adapter.cjs +40 -2
  23. package/gsd-core/bin/lib/command-aliases.cjs +10 -1
  24. package/gsd-core/bin/lib/command-routing-hub.cjs +10 -3
  25. package/gsd-core/bin/lib/config-schema.cjs +1 -0
  26. package/gsd-core/bin/lib/config.cjs +67 -24
  27. package/gsd-core/bin/lib/coverage.cjs +464 -0
  28. package/gsd-core/bin/lib/decisions.cjs +27 -0
  29. package/gsd-core/bin/lib/eval-command-router.cjs +21 -0
  30. package/gsd-core/bin/lib/eval.cjs +60 -0
  31. package/gsd-core/bin/lib/frontmatter.cjs +132 -13
  32. package/gsd-core/bin/lib/graphify-command-router.cjs +53 -36
  33. package/gsd-core/bin/lib/init.cjs +139 -30
  34. package/gsd-core/bin/lib/install-profiles.cjs +6 -3
  35. package/gsd-core/bin/lib/intel-command-router.cjs +79 -60
  36. package/gsd-core/bin/lib/io.cjs +1 -0
  37. package/gsd-core/bin/lib/phase.cjs +16 -2
  38. package/gsd-core/bin/lib/plan-scan.cjs +2 -2
  39. package/gsd-core/bin/lib/planning-workspace.cjs +157 -13
  40. package/gsd-core/bin/lib/profile-output.cjs +18 -6
  41. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +53 -16
  42. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +21 -3
  43. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +15 -0
  44. package/gsd-core/bin/lib/runtime-name-policy.cjs +47 -2
  45. package/gsd-core/bin/lib/shell-command-projection.cjs +10 -0
  46. package/gsd-core/bin/lib/state.cjs +398 -60
  47. package/gsd-core/bin/lib/surface.cjs +42 -10
  48. package/gsd-core/bin/lib/uat-predicate.cjs +13 -6
  49. package/gsd-core/bin/lib/update-context.cjs +2 -2
  50. package/gsd-core/bin/lib/verification.cjs +67 -6
  51. package/gsd-core/bin/lib/verify.cjs +8 -1
  52. package/gsd-core/bin/shared/config-defaults.manifest.json +3 -0
  53. package/gsd-core/bin/shared/config-schema.manifest.json +2 -1
  54. package/gsd-core/references/planner-guidance.md +66 -0
  55. package/gsd-core/references/planning-config.md +2 -2
  56. package/gsd-core/references/security-asvs-levels.md +27 -0
  57. package/gsd-core/references/untrusted-input-boundary.md +13 -0
  58. package/gsd-core/templates/SECURITY.md +6 -4
  59. package/gsd-core/templates/summary-complex.md +4 -0
  60. package/gsd-core/templates/summary-minimal.md +3 -0
  61. package/gsd-core/templates/summary-standard.md +4 -0
  62. package/gsd-core/templates/summary.md +41 -0
  63. package/gsd-core/workflows/autonomous.md +53 -46
  64. package/gsd-core/workflows/complete-milestone.md +27 -8
  65. package/gsd-core/workflows/execute-phase.md +1 -1
  66. package/gsd-core/workflows/execute-plan.md +5 -0
  67. package/gsd-core/workflows/manager.md +17 -7
  68. package/gsd-core/workflows/new-project.md +82 -16
  69. package/gsd-core/workflows/plan-phase.md +15 -0
  70. package/gsd-core/workflows/profile-user.md +6 -2
  71. package/gsd-core/workflows/progress.md +37 -4
  72. package/gsd-core/workflows/quick.md +3 -1
  73. package/gsd-core/workflows/secure-phase.md +13 -7
  74. package/gsd-core/workflows/ship.md +3 -1
  75. package/gsd-core/workflows/spec-phase.md +3 -1
  76. package/gsd-core/workflows/transition.md +14 -12
  77. package/gsd-core/workflows/ui-review.md +2 -6
  78. package/gsd-core/workflows/verify-work.md +74 -1
  79. package/hooks/dist/gsd-read-injection-scanner.js +49 -25
  80. package/hooks/gsd-read-injection-scanner.js +49 -25
  81. package/hooks/hooks.json +1 -1
  82. package/package.json +4 -2
  83. package/scripts/check-alias-drift.cjs +5 -0
  84. package/scripts/gen-plugin-skills.cjs +117 -0
  85. package/scripts/lint-test-file-count.allowlist.json +2 -1
  86. package/scripts/prompt-injection-scan.sh +9 -0
  87. package/scripts/release-notes/conventional-title.cjs +88 -0
  88. package/scripts/release-notes/format-github-release-notes.cjs +4 -3
  89. package/skills/gsd-add-tests/SKILL.md +38 -0
  90. package/skills/gsd-ai-integration-phase/SKILL.md +37 -0
  91. package/skills/gsd-audit-fix/SKILL.md +33 -0
  92. package/skills/gsd-audit-milestone/SKILL.md +37 -0
  93. package/skills/gsd-audit-uat/SKILL.md +25 -0
  94. package/skills/gsd-autonomous/SKILL.md +51 -0
  95. package/skills/gsd-capture/SKILL.md +67 -0
  96. package/skills/gsd-cleanup/SKILL.md +24 -0
  97. package/skills/gsd-code-review/SKILL.md +59 -0
  98. package/skills/gsd-complete-milestone/SKILL.md +142 -0
  99. package/skills/gsd-config/SKILL.md +56 -0
  100. package/skills/gsd-debug/SKILL.md +53 -0
  101. package/skills/gsd-discuss-phase/SKILL.md +77 -0
  102. package/skills/gsd-docs-update/SKILL.md +49 -0
  103. package/skills/gsd-eval-review/SKILL.md +33 -0
  104. package/skills/gsd-execute-phase/SKILL.md +65 -0
  105. package/skills/gsd-explore/SKILL.md +28 -0
  106. package/skills/gsd-extract-learnings/SKILL.md +22 -0
  107. package/skills/gsd-fast/SKILL.md +31 -0
  108. package/skills/gsd-forensics/SKILL.md +56 -0
  109. package/skills/gsd-graphify/SKILL.md +204 -0
  110. package/skills/gsd-health/SKILL.md +31 -0
  111. package/skills/gsd-help/SKILL.md +29 -0
  112. package/skills/gsd-import/SKILL.md +46 -0
  113. package/skills/gsd-inbox/SKILL.md +39 -0
  114. package/skills/gsd-ingest-docs/SKILL.md +43 -0
  115. package/skills/gsd-manager/SKILL.md +45 -0
  116. package/skills/gsd-map-codebase/SKILL.md +83 -0
  117. package/skills/gsd-mempalace-capture/SKILL.md +71 -0
  118. package/skills/gsd-mempalace-recall/SKILL.md +102 -0
  119. package/skills/gsd-milestone-summary/SKILL.md +51 -0
  120. package/skills/gsd-mvp-phase/SKILL.md +45 -0
  121. package/skills/gsd-new-milestone/SKILL.md +45 -0
  122. package/skills/gsd-new-project/SKILL.md +47 -0
  123. package/skills/gsd-ns-context/SKILL.md +24 -0
  124. package/skills/gsd-ns-ideate/SKILL.md +23 -0
  125. package/skills/gsd-ns-manage/SKILL.md +35 -0
  126. package/skills/gsd-ns-project/SKILL.md +26 -0
  127. package/skills/gsd-ns-review/SKILL.md +28 -0
  128. package/skills/gsd-ns-workflow/SKILL.md +33 -0
  129. package/skills/gsd-pause-work/SKILL.md +43 -0
  130. package/skills/gsd-phase/SKILL.md +57 -0
  131. package/skills/gsd-plan-phase/SKILL.md +63 -0
  132. package/skills/gsd-plan-review-convergence/SKILL.md +60 -0
  133. package/skills/gsd-pr-branch/SKILL.md +26 -0
  134. package/skills/gsd-profile-user/SKILL.md +47 -0
  135. package/skills/gsd-progress/SKILL.md +49 -0
  136. package/skills/gsd-quick/SKILL.md +174 -0
  137. package/skills/gsd-resume-work/SKILL.md +31 -0
  138. package/skills/gsd-review/SKILL.md +42 -0
  139. package/skills/gsd-review-backlog/SKILL.md +63 -0
  140. package/skills/gsd-secure-phase/SKILL.md +36 -0
  141. package/skills/gsd-settings/SKILL.md +29 -0
  142. package/skills/gsd-ship/SKILL.md +24 -0
  143. package/skills/gsd-sketch/SKILL.md +60 -0
  144. package/skills/gsd-spec-phase/SKILL.md +63 -0
  145. package/skills/gsd-spike/SKILL.md +57 -0
  146. package/skills/gsd-stats/SKILL.md +20 -0
  147. package/skills/gsd-surface/SKILL.md +162 -0
  148. package/skills/gsd-thread/SKILL.md +24 -0
  149. package/skills/gsd-ui-phase/SKILL.md +35 -0
  150. package/skills/gsd-ui-review/SKILL.md +33 -0
  151. package/skills/gsd-ultraplan-phase/SKILL.md +34 -0
  152. package/skills/gsd-undo/SKILL.md +35 -0
  153. package/skills/gsd-update/SKILL.md +50 -0
  154. package/skills/gsd-validate-phase/SKILL.md +36 -0
  155. package/skills/gsd-verify-work/SKILL.md +39 -0
  156. package/skills/gsd-workspace/SKILL.md +53 -0
  157. package/skills/gsd-workstreams/SKILL.md +70 -0
@@ -25,6 +25,10 @@
25
25
  */
26
26
  // eslint-disable-next-line @typescript-eslint/no-require-imports
27
27
  const io = require("./io.cjs");
28
+ // Phase 2 (#1646): route through the Hub per ADR-959 §III(B) line 75.
29
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
30
+ const cjsCommandRouterAdapter = require("./cjs-command-router-adapter.cjs");
31
+ const { routeHubCommandFamily } = cjsCommandRouterAdapter;
28
32
  // ─── routeAuditUat ────────────────────────────────────────────────────────────
29
33
  function routeAuditUat({ args, cwd, raw, error, _uat }) {
30
34
  // Suppress unused-variable warnings for args/error — this command has no
@@ -33,27 +37,61 @@ function routeAuditUat({ args, cwd, raw, error, _uat }) {
33
37
  void error;
34
38
  // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment
35
39
  const u = _uat ?? require('./uat.cjs');
36
- u.cmdAuditUat(cwd, raw);
40
+ // Phase 2 (#1646): routes through the Hub for uniform observability and
41
+ // HandlerFailure taxonomy. audit-uat has no subcommands — a synthetic 'run'
42
+ // defaultSubcommand gives the Hub a single-handler manifest. The dispatch is
43
+ // trivial but the observability seam (DispatchEvent, GSD_AUDIT=1 trace) is
44
+ // now consistent with graphify/intel/host routers.
45
+ routeHubCommandFamily({
46
+ family: 'audit-uat',
47
+ args,
48
+ subcommands: ['run'],
49
+ defaultSubcommand: 'run',
50
+ handlers: {
51
+ run: () => u.cmdAuditUat(cwd, raw),
52
+ },
53
+ unknownMessage: (subcommand) => `Unknown audit-uat subcommand: "${subcommand}". audit-uat takes no subcommands.`,
54
+ error,
55
+ cwd,
56
+ raw,
57
+ });
37
58
  }
38
59
  // ─── routeAuditOpen ──────────────────────────────────────────────────────────
39
60
  function routeAuditOpen({ args, cwd, raw, error, _audit, _core }) {
40
- // Suppress unused-variable warning for error — audit-open has no subcommand
41
- // dispatch that would call error(); only flag parsing occurs here.
42
- void error;
43
61
  // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment
44
62
  const a = _audit ?? require('./audit.cjs');
45
63
  const c = _core ?? io;
64
+ // Phase 2 (#1646): routes through the Hub for uniform observability.
65
+ // `--json` is a flag, not a subcommand — capture it in the closure and strip
66
+ // it from args before Hub dispatch so it isn't mistaken for a subcommand by
67
+ // the manifest check. The handler then branches on wantJson for the two
68
+ // output shapes (JSON object vs human-readable formatted report).
46
69
  const wantJson = args.includes('--json');
47
- const result = a.auditOpenArtifacts(cwd);
48
- if (wantJson) {
49
- // io.output JSON-stringifies its first arg; pass the object directly.
50
- c.output(result, raw);
51
- }
52
- else {
53
- // Human-readable report must bypass JSON encoding — use the rawValue
54
- // form (third arg) which io.output emits verbatim.
55
- c.output(null, true, a.formatAuditReport(result));
56
- }
70
+ const hubArgs = wantJson ? args.filter((arg) => arg !== '--json') : args;
71
+ routeHubCommandFamily({
72
+ family: 'audit-open',
73
+ args: hubArgs,
74
+ subcommands: ['run'],
75
+ defaultSubcommand: 'run',
76
+ handlers: {
77
+ run: () => {
78
+ const result = a.auditOpenArtifacts(cwd);
79
+ if (wantJson) {
80
+ // io.output JSON-stringifies its first arg; pass the object directly.
81
+ c.output(result, raw);
82
+ }
83
+ else {
84
+ // Human-readable report must bypass JSON encoding — use the rawValue
85
+ // form (third arg) which io.output emits verbatim.
86
+ c.output(null, true, a.formatAuditReport(result));
87
+ }
88
+ },
89
+ },
90
+ unknownMessage: (subcommand) => `Unknown audit-open subcommand: "${subcommand}". audit-open takes no subcommands (use --json for JSON output).`,
91
+ error,
92
+ cwd,
93
+ raw,
94
+ });
57
95
  }
58
96
  module.exports = {
59
97
  routeAuditUat,
@@ -280,6 +280,20 @@ function isSafeHookScriptPath(script) {
280
280
  function shellSingleQuote(value) {
281
281
  return "'" + value.replace(/'/g, "'\\''") + "'";
282
282
  }
283
+ /**
284
+ * #1634: build the emitted hook `command` for an ABSOLUTE confined script path. For `.js`-family
285
+ * hooks (`.js`/`.cjs`/`.mjs`) prefix with `node` so the hook runs regardless of the source's
286
+ * executable bit — a `git`/tarball source that lost `+x` would otherwise yield
287
+ * `/bin/sh: Permission denied` on every matching call (defect #2). This mirrors first-party hooks
288
+ * (`node "${CLAUDE_PLUGIN_ROOT}/hooks/x.js"`). The path stays POSIX single-quoted (#1460 (R) HIGH)
289
+ * so a space-containing install prefix cannot word-split or inject. Non-JS scripts (e.g. `.sh`)
290
+ * keep the bare single-quoted absolute path (unchanged) — they remain responsible for their own
291
+ * executability, exactly as before; per-runtime command projection is a separate concern (ADR-857 D8).
292
+ */
293
+ const JS_HOOK_EXT_RE = /\.(?:js|cjs|mjs)$/;
294
+ function runnableHookCommand(absScript) {
295
+ return JS_HOOK_EXT_RE.test(absScript) ? 'node ' + shellSingleQuote(absScript) : shellSingleQuote(absScript);
296
+ }
283
297
  /**
284
298
  * #1460 CONF-1: resolve a hook `script` (declared RELATIVE to the bundle) against the capability's
285
299
  * own install dir and CONFINE it via realpath, returning the ABSOLUTE confined path or null when it
@@ -459,6 +473,11 @@ function applyCapabilitySharedEdits(args) {
459
473
  const script = typeof rec['script'] === 'string' ? rec['script'] : '';
460
474
  if (!event || !script || isUnsafeKey(event))
461
475
  continue;
476
+ // #1634: optional tool-scoping `matcher` (a settings.json concept — entry-level sibling of
477
+ // `hooks`). Absent => match-all (field OMITTED so the existing shipped capabilities' wiring
478
+ // is byte-for-byte unchanged, Hyrum's Law). The validator gates this to a non-empty string.
479
+ const matcherRaw = rec['matcher'];
480
+ const matcher = typeof matcherRaw === 'string' && matcherRaw.length > 0 ? matcherRaw : null;
462
481
  // #1460 CONF-1: resolve the declared (relative) script against the capability's OWN install
463
482
  // dir and CONFINE via realpath, then write the ABSOLUTE confined path as the hook command —
464
483
  // never the raw relative path (which would resolve against the CWD at hook-exec time and could
@@ -467,14 +486,18 @@ function applyCapabilitySharedEdits(args) {
467
486
  const absScript = confinedBundleScript(capDir(runtimeDir, capId), script);
468
487
  if (absScript === null)
469
488
  continue;
470
- // #1460 (R) HIGH: the hook `command` is consumed by a shell (first-party hooks emit
471
- // `node "${CLAUDE_PLUGIN_ROOT}/hooks/x.js"`). The absolute path begins with the
472
- // (non-manifest) install-prefix, which commonly contains spaces — emit it POSIX
473
- // single-quoted so the prefix cannot word-split or inject. The script BASENAME is
474
- // already restricted to a shell-safe allowlist by isSafeHookScriptPath above.
475
- const command = shellSingleQuote(absScript);
489
+ // #1460 (R) HIGH + #1634: the hook `command` is consumed by a shell. `runnableHookCommand`
490
+ // emits a `node`-prefixed POSIX-single-quoted absolute path for `.js`-family hooks (runs
491
+ // without `+x`; mirrors first-party) and a bare single-quoted path otherwise. Single-quoting
492
+ // keeps a space-containing install prefix as one shell token (cannot word-split or inject).
493
+ const command = runnableHookCommand(absScript);
476
494
  const arr = Array.isArray(hooksObj[event]) ? hooksObj[event] : [];
477
- arr.push({ [CAP_MARKER]: capId, hooks: [{ type: 'command', command }] });
495
+ // #1634: stamp the marker so the entry is surgically strippable, and carry the declared
496
+ // `matcher` (entry-level sibling of `hooks`) only when the author declared one.
497
+ const entry = { [CAP_MARKER]: capId, hooks: [{ type: 'command', command }] };
498
+ if (matcher !== null)
499
+ entry['matcher'] = matcher;
500
+ arr.push(entry);
478
501
  hooksObj[event] = arr;
479
502
  touched = true;
480
503
  }