@opengsd/gsd-core 1.7.0-rc.2 → 1.7.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 (184) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/GEMINI.md +25 -23
  4. package/README.ja-JP.md +4 -3
  5. package/README.ko-KR.md +4 -3
  6. package/README.md +7 -6
  7. package/README.pt-BR.md +4 -3
  8. package/README.zh-CN.md +4 -3
  9. package/agents/gsd-advisor-researcher.md +1 -1
  10. package/agents/gsd-ai-researcher.md +1 -1
  11. package/agents/gsd-code-fixer.md +1 -1
  12. package/agents/gsd-debug-session-manager.md +1 -1
  13. package/agents/gsd-debugger.md +1 -1
  14. package/agents/gsd-domain-researcher.md +1 -1
  15. package/agents/gsd-eval-auditor.md +1 -1
  16. package/agents/gsd-executor.md +4 -4
  17. package/agents/gsd-intel-updater.md +1 -1
  18. package/agents/gsd-mempalace-curator.md +1 -1
  19. package/agents/gsd-phase-researcher.md +2 -2
  20. package/agents/gsd-plan-checker.md +1 -1
  21. package/agents/gsd-planner.md +2 -2
  22. package/agents/gsd-project-researcher.md +2 -2
  23. package/agents/gsd-research-synthesizer.md +1 -1
  24. package/agents/gsd-ui-researcher.md +2 -2
  25. package/agents/gsd-verifier.md +2 -2
  26. package/bin/install.js +132 -464
  27. package/commands/gsd/map-codebase.md +4 -4
  28. package/commands/gsd/mempalace-capture.md +1 -1
  29. package/commands/gsd/mempalace-recall.md +9 -5
  30. package/commands/gsd/next.md +29 -0
  31. package/commands/gsd/ns-project.md +2 -1
  32. package/commands/gsd/ns-workflow.md +5 -2
  33. package/commands/gsd/onboard.md +46 -0
  34. package/gsd-core/bin/ensure-runtime-build.cjs +246 -0
  35. package/gsd-core/bin/gsd-tools.cjs +72 -3
  36. package/gsd-core/bin/lib/capability-registry.cjs +684 -264
  37. package/gsd-core/bin/lib/capability-state.cjs +117 -18
  38. package/gsd-core/bin/lib/capability-writer.cjs +11 -1
  39. package/gsd-core/bin/lib/check-command-router.cjs +111 -1
  40. package/gsd-core/bin/lib/claude-orchestration-command-router.cjs +136 -0
  41. package/gsd-core/bin/lib/claude-orchestration.cjs +404 -0
  42. package/gsd-core/bin/lib/clusters.cjs +2 -0
  43. package/gsd-core/bin/lib/command-aliases.cjs +8 -0
  44. package/gsd-core/bin/lib/config.cjs +19 -1
  45. package/gsd-core/bin/lib/core-utils.cjs +41 -0
  46. package/gsd-core/bin/lib/external-job.cjs +287 -0
  47. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +151 -0
  48. package/gsd-core/bin/lib/graphify.cjs +41 -9
  49. package/gsd-core/bin/lib/init-command-router.cjs +4 -0
  50. package/gsd-core/bin/lib/init.cjs +25 -69
  51. package/gsd-core/bin/lib/install-engine.cjs +8 -5
  52. package/gsd-core/bin/lib/install-profiles.cjs +2 -0
  53. package/gsd-core/bin/lib/loop-resolver.cjs +7 -1
  54. package/gsd-core/bin/lib/milestone.cjs +7 -1
  55. package/gsd-core/bin/lib/model-resolver.cjs +69 -4
  56. package/gsd-core/bin/lib/onboard-projection.cjs +309 -0
  57. package/gsd-core/bin/lib/phase.cjs +14 -2
  58. package/gsd-core/bin/lib/plan-scan.cjs +9 -1
  59. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  60. package/gsd-core/bin/lib/prohibition-enforcement.cjs +21 -19
  61. package/gsd-core/bin/lib/roadmap.cjs +17 -2
  62. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +18 -13
  63. package/gsd-core/bin/lib/runtime-name-policy.cjs +11 -11
  64. package/gsd-core/bin/lib/shell-command-projection.cjs +12 -8
  65. package/gsd-core/bin/lib/smart-entry.cjs +521 -0
  66. package/gsd-core/bin/lib/surface.cjs +63 -33
  67. package/gsd-core/bin/lib/update-context.cjs +0 -5
  68. package/gsd-core/bin/shared/config-schema.manifest.json +1 -0
  69. package/gsd-core/bin/shared/model-catalog.json +5 -5
  70. package/gsd-core/bin/shared/runtime-aliases.manifest.json +0 -5
  71. package/gsd-core/references/gates.md +1 -1
  72. package/gsd-core/references/gsd-run-resolver.md +8 -0
  73. package/gsd-core/references/planning-config.md +1 -1
  74. package/gsd-core/templates/project.md +1 -1
  75. package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
  76. package/gsd-core/workflows/add-backlog.md +1 -1
  77. package/gsd-core/workflows/add-phase.md +1 -1
  78. package/gsd-core/workflows/add-tests.md +1 -1
  79. package/gsd-core/workflows/add-todo.md +1 -1
  80. package/gsd-core/workflows/ai-integration-phase.md +1 -1
  81. package/gsd-core/workflows/audit-fix.md +1 -1
  82. package/gsd-core/workflows/audit-milestone.md +1 -1
  83. package/gsd-core/workflows/audit-uat.md +1 -1
  84. package/gsd-core/workflows/autonomous.md +1 -1
  85. package/gsd-core/workflows/check-todos.md +1 -1
  86. package/gsd-core/workflows/cleanup.md +1 -1
  87. package/gsd-core/workflows/code-review-fix.md +1 -1
  88. package/gsd-core/workflows/code-review.md +1 -1
  89. package/gsd-core/workflows/complete-milestone.md +1 -1
  90. package/gsd-core/workflows/debug.md +1 -1
  91. package/gsd-core/workflows/diagnose-issues.md +1 -1
  92. package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
  93. package/gsd-core/workflows/discuss-phase/modes/auto.md +1 -1
  94. package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
  95. package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
  96. package/gsd-core/workflows/discuss-phase.md +2 -2
  97. package/gsd-core/workflows/do.md +5 -4
  98. package/gsd-core/workflows/docs-update.md +1 -1
  99. package/gsd-core/workflows/edit-phase.md +1 -1
  100. package/gsd-core/workflows/eval-review.md +1 -1
  101. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
  102. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +1 -1
  103. package/gsd-core/workflows/execute-phase.md +4 -5
  104. package/gsd-core/workflows/execute-plan.md +1 -1
  105. package/gsd-core/workflows/explore.md +1 -1
  106. package/gsd-core/workflows/extract-learnings.md +1 -1
  107. package/gsd-core/workflows/forensics.md +1 -1
  108. package/gsd-core/workflows/graduation.md +1 -1
  109. package/gsd-core/workflows/health.md +1 -1
  110. package/gsd-core/workflows/help/modes/brief.md +2 -1
  111. package/gsd-core/workflows/help/modes/default.md +2 -1
  112. package/gsd-core/workflows/help/modes/full.md +25 -1
  113. package/gsd-core/workflows/help/modes/topic.md +2 -1
  114. package/gsd-core/workflows/import.md +1 -1
  115. package/gsd-core/workflows/ingest-docs.md +1 -1
  116. package/gsd-core/workflows/insert-phase.md +1 -1
  117. package/gsd-core/workflows/list-seeds.md +1 -1
  118. package/gsd-core/workflows/list-workspaces.md +1 -1
  119. package/gsd-core/workflows/manager.md +1 -1
  120. package/gsd-core/workflows/map-codebase.md +1 -1
  121. package/gsd-core/workflows/milestone-summary.md +1 -1
  122. package/gsd-core/workflows/mvp-phase.md +1 -1
  123. package/gsd-core/workflows/new-milestone.md +1 -1
  124. package/gsd-core/workflows/new-project.md +1 -1
  125. package/gsd-core/workflows/new-workspace.md +1 -1
  126. package/gsd-core/workflows/next.md +1 -1
  127. package/gsd-core/workflows/onboard.md +277 -0
  128. package/gsd-core/workflows/pause-work.md +1 -1
  129. package/gsd-core/workflows/plan-milestone-gaps.md +1 -1
  130. package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
  131. package/gsd-core/workflows/plan-phase.md +9 -2
  132. package/gsd-core/workflows/plan-review-convergence.md +1 -1
  133. package/gsd-core/workflows/plant-seed.md +1 -1
  134. package/gsd-core/workflows/pr-branch.md +1 -1
  135. package/gsd-core/workflows/profile-user.md +1 -1
  136. package/gsd-core/workflows/progress.md +1 -1
  137. package/gsd-core/workflows/quick.md +21 -1
  138. package/gsd-core/workflows/reapply-patches.md +1 -1
  139. package/gsd-core/workflows/remove-phase.md +1 -1
  140. package/gsd-core/workflows/remove-workspace.md +1 -1
  141. package/gsd-core/workflows/resume-project.md +1 -1
  142. package/gsd-core/workflows/review.md +43 -7
  143. package/gsd-core/workflows/scan.md +1 -1
  144. package/gsd-core/workflows/secure-phase.md +1 -1
  145. package/gsd-core/workflows/settings-advanced.md +3 -1
  146. package/gsd-core/workflows/settings-integrations.md +1 -1
  147. package/gsd-core/workflows/settings.md +1 -1
  148. package/gsd-core/workflows/ship.md +1 -1
  149. package/gsd-core/workflows/sketch-wrap-up.md +1 -1
  150. package/gsd-core/workflows/sketch.md +1 -1
  151. package/gsd-core/workflows/smart-entry.md +120 -0
  152. package/gsd-core/workflows/spec-phase.md +8 -6
  153. package/gsd-core/workflows/spike-wrap-up.md +1 -1
  154. package/gsd-core/workflows/spike.md +1 -1
  155. package/gsd-core/workflows/stats.md +1 -1
  156. package/gsd-core/workflows/thread.md +1 -1
  157. package/gsd-core/workflows/transition.md +1 -1
  158. package/gsd-core/workflows/ui-phase.md +1 -1
  159. package/gsd-core/workflows/ui-review.md +1 -1
  160. package/gsd-core/workflows/ultraplan-phase.md +1 -1
  161. package/gsd-core/workflows/update.md +3 -6
  162. package/gsd-core/workflows/validate-phase.md +1 -1
  163. package/gsd-core/workflows/verify-phase.md +1 -1
  164. package/gsd-core/workflows/verify-work.md +62 -4
  165. package/package.json +3 -5
  166. package/scripts/ci-test-scope.cjs +19 -1
  167. package/scripts/gen-golden-install-parity-zcode.cjs +77 -0
  168. package/scripts/generate-package-identity.cjs +27 -2
  169. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -148
  170. package/scripts/lint-regression-test-names.allowlist.json +1 -273
  171. package/scripts/lint-test-file-count.allowlist.json +7 -91
  172. package/scripts/research-profiles.cjs +6 -6
  173. package/scripts/run-tests.cjs +18 -3
  174. package/scripts/slurm-adapter.cjs +269 -0
  175. package/scripts/sync-manifest-versions.cjs +3 -2
  176. package/scripts/sync-runtime-launcher.cjs +20 -2
  177. package/skills/gsd-map-codebase/SKILL.md +3 -3
  178. package/skills/gsd-mempalace-capture/SKILL.md +1 -1
  179. package/skills/gsd-mempalace-recall/SKILL.md +9 -5
  180. package/skills/gsd-next/SKILL.md +30 -0
  181. package/skills/gsd-ns-project/SKILL.md +1 -0
  182. package/skills/gsd-ns-workflow/SKILL.md +4 -1
  183. package/skills/gsd-onboard/SKILL.md +46 -0
  184. package/gemini-extension.json +0 -6
@@ -0,0 +1,269 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * slurm-adapter.cjs — SLURM scheduler-adapter helper for the external-job
6
+ * capability (#1164 / #1105).
7
+ *
8
+ * Thin CLI: runs bounded sbatch / squeue / sacct subprocesses and delegates
9
+ * all parsing, manifest build/validate, and fail-closed writing to the pure
10
+ * module (gsd-core/bin/lib/external-job.cjs). The pure module is fully unit-
11
+ * tested; this script is the operator surface that needs a real cluster.
12
+ *
13
+ * Subcommands:
14
+ * submit --plan <plan_id> --phase <phase> --expected <path>[,<path>] \
15
+ * --verify <cmd> --resume <cmd> -- <sbatch...>
16
+ * poll --job <job_id> [--plan <plan_id>]
17
+ * show --job <job_id> (surface manifest status + commands; no auto-run)
18
+ *
19
+ * Trust boundary: this script never auto-runs verification_command or
20
+ * resume_command from a manifest (planning-artifacts.md). `show` prints them
21
+ * for explicit operator confirmation.
22
+ */
23
+
24
+ const { execFileSync } = require('node:child_process');
25
+ const fs = require('node:fs');
26
+ const path = require('node:path');
27
+
28
+ const { ExitError, runMain } = require('./lib/cli-exit.cjs');
29
+ const m = require('../gsd-core/bin/lib/external-job.cjs');
30
+
31
+ // #1164 refinements B + C: the adapter now resolves external_job.* settings
32
+ // through the canonical capability-config seam (resolveConfigKey in
33
+ // capability-activation.cjs), which walks loadConfig -> workstream config.json
34
+ // -> root config.json -> registry configSchema default. Env vars remain the
35
+ // top-precedence override so cluster operators can tune without editing config.
36
+ const { resolveConfigKey } = require('../gsd-core/bin/lib/capability-activation.cjs');
37
+ const FALLBACK_SUBMIT_TIMEOUT_MS = 30000;
38
+ const FALLBACK_POLL_TIMEOUT_MS = 15000;
39
+ const FALLBACK_ARTIFACT_DIR = 'Artifacts/jobs';
40
+
41
+ /**
42
+ * Resolve the external_job.* runtime settings. Pure given {config, env,
43
+ * registry}; degrades to hardcoded fallbacks if the registry/config are absent
44
+ * so the adapter never unbounds a subprocess (CLAUDE.md bounded-subprocess).
45
+ *
46
+ * Precedence: env override > nested config value > registry default > fallback.
47
+ */
48
+ function resolveExternalJobSettings({ cwd, env, config, registry } = {}) {
49
+ const reg = registry || {};
50
+ let cfg = config;
51
+ if (cfg === undefined) {
52
+ try {
53
+ cfg = require('../gsd-core/bin/lib/config-loader.cjs').loadConfig(cwd);
54
+ } catch {
55
+ cfg = {}; // resolveConfigKey still falls back to the registry default
56
+ }
57
+ }
58
+ const e = env || {};
59
+ const submitEnv = e.GSD_SLURM_SUBMIT_TIMEOUT_MS;
60
+ const pollEnv = e.GSD_SLURM_POLL_TIMEOUT_MS;
61
+ const artifactEnv = e.GSD_EXTERNAL_JOB_ARTIFACT_DIR;
62
+ const submit = submitEnv ? Number(submitEnv)
63
+ : _num(resolveConfigKey('external_job.submit_timeout_ms', { config: cfg, cwd, registry: reg }), FALLBACK_SUBMIT_TIMEOUT_MS);
64
+ const poll = pollEnv ? Number(pollEnv)
65
+ : _num(resolveConfigKey('external_job.poll_timeout_ms', { config: cfg, cwd, registry: reg }), FALLBACK_POLL_TIMEOUT_MS);
66
+ const artifactDir = artifactEnv
67
+ || _str(resolveConfigKey('external_job.artifact_dir', { config: cfg, cwd, registry: reg }), FALLBACK_ARTIFACT_DIR);
68
+ return { submitTimeoutMs: submit, pollTimeoutMs: poll, artifactDir };
69
+ }
70
+
71
+ function _num(res, fallback) {
72
+ const v = res && res.found ? res.value : undefined;
73
+ return typeof v === 'number' && Number.isFinite(v) ? v : fallback;
74
+ }
75
+ function _str(res, fallback) {
76
+ const v = res && res.found ? res.value : undefined;
77
+ return typeof v === 'string' && v.length > 0 ? v : fallback;
78
+ }
79
+
80
+ function usage() {
81
+ return [
82
+ 'usage: slurm-adapter.cjs <submit|poll|show> ...',
83
+ ' submit --plan <id> --phase <n> --expected <p1,p2> --verify <cmd> --resume <cmd> -- sbatch --parsable ...',
84
+ ' poll --job <job_id> [--plan <plan_id>]',
85
+ ' show --job <job_id>',
86
+ ].join('\n');
87
+ }
88
+
89
+ function parseFlags(argv) {
90
+ const out = {};
91
+ const rest = [];
92
+ for (let i = 0; i < argv.length; i++) {
93
+ const a = argv[i];
94
+ if (a === '--') { out['--'] = argv.slice(i + 1); break; }
95
+ if (a.startsWith('--')) {
96
+ const v = argv[i + 1];
97
+ out[a.slice(2)] = v;
98
+ i++;
99
+ } else {
100
+ rest.push(a);
101
+ }
102
+ }
103
+ out._ = rest;
104
+ return out;
105
+ }
106
+
107
+ function findPlanningDir(start) {
108
+ let dir = path.resolve(start || process.cwd());
109
+ for (let i = 0; i < 10; i++) {
110
+ if (fs.existsSync(path.join(dir, '.planning'))) return path.join(dir, '.planning');
111
+ const parent = path.dirname(dir);
112
+ if (parent === dir) break;
113
+ dir = parent;
114
+ }
115
+ throw new ExitError(1, 'could not locate a .planning directory (walked up 10 levels)');
116
+ }
117
+
118
+ function cmdSubmit(flags) {
119
+ const plan = flags.plan;
120
+ const phase = flags.phase;
121
+ const sbatchCmd = flags['--'];
122
+ if (!plan || phase === undefined || !Array.isArray(sbatchCmd) || sbatchCmd.length === 0) {
123
+ throw new ExitError(1, 'submit requires --plan, --phase, and an sbatch command after --\n' + usage());
124
+ }
125
+ const expected = (flags.expected || '').split(',').map((s) => s.trim()).filter(Boolean);
126
+ if (expected.length === 0) throw new ExitError(1, 'submit requires --expected (comma-separated artifact paths)');
127
+ const verify = flags.verify;
128
+ const resume = flags.resume || ('/gsd:execute-phase ' + phase);
129
+ if (!verify) throw new ExitError(1, 'submit requires --verify (the command that verifies job output)');
130
+
131
+ // Resolve settings from config/env before any subprocess (env > config > default).
132
+ const planningDir = findPlanningDir();
133
+ const settings = resolveExternalJobSettings({
134
+ cwd: path.dirname(planningDir),
135
+ env: process.env,
136
+ });
137
+
138
+ let stdout;
139
+ try {
140
+ stdout = execFileSync(sbatchCmd[0], sbatchCmd.slice(1), {
141
+ encoding: 'utf8',
142
+ timeout: settings.submitTimeoutMs,
143
+ maxBuffer: 1024 * 1024,
144
+ });
145
+ } catch (e) {
146
+ throw new ExitError(1, 'sbatch failed: ' + (e.message || String(e)));
147
+ }
148
+ const parsed = m.parseSbatchParsable(stdout);
149
+ if (!parsed.ok) {
150
+ throw new ExitError(1, 'could not parse sbatch --parsable output (kind=' + parsed.kind + '): ' + parsed.raw);
151
+ }
152
+ const manifest = m.buildManifest({
153
+ plan_id: plan,
154
+ phase,
155
+ job_id: parsed.job_id,
156
+ backend: 'slurm',
157
+ submit_command: sbatchCmd.join(' '),
158
+ status: 'submitted',
159
+ expected_artifacts: expected,
160
+ verification_command: verify,
161
+ resume_command: resume,
162
+ });
163
+ const res = m.writeManifest(manifest, planningDir);
164
+ if (!res.ok) {
165
+ throw new ExitError(1, 'writeManifest refused (' + res.kind + '): ' + res.message);
166
+ }
167
+ process.stdout.write('submitted job ' + parsed.job_id + ' for plan ' + plan + '\n');
168
+ process.stdout.write('manifest: ' + res.path + '\n');
169
+ process.stdout.write('artifact_dir: ' + settings.artifactDir + '\n');
170
+ process.stdout.write('state: external_job_waiting (SUMMARY deferred)\n');
171
+ }
172
+
173
+ function cmdPoll(flags) {
174
+ const jobId = flags.job;
175
+ if (!jobId) throw new ExitError(1, 'poll requires --job <job_id>\n' + usage());
176
+ const planningDir = findPlanningDir();
177
+ const settings = resolveExternalJobSettings({
178
+ cwd: path.dirname(planningDir),
179
+ env: process.env,
180
+ });
181
+ const manifestFile = m.manifestPath(planningDir, jobId);
182
+ if (!fs.existsSync(manifestFile)) {
183
+ throw new ExitError(1, 'no manifest for job ' + jobId + ' at ' + manifestFile);
184
+ }
185
+ const existing = JSON.parse(fs.readFileSync(manifestFile, 'utf8'));
186
+
187
+ let rawState = null;
188
+ try {
189
+ const out = execFileSync('squeue', ['-h', '-j', jobId, '-o', '%i %T'], {
190
+ encoding: 'utf8', timeout: settings.pollTimeoutMs, maxBuffer: 1024 * 1024,
191
+ }).trim();
192
+ const line = out.split('\n')[0];
193
+ const parsed = m.parseSqueueLine(line || '');
194
+ if (parsed) rawState = parsed.state;
195
+ } catch (_e) { /* squeue empty/failed — fall back to sacct */ }
196
+ if (!rawState) {
197
+ try {
198
+ const out = execFileSync('sacct', ['-X', '-P', '-j', jobId, '-o', 'JobID,State'], {
199
+ encoding: 'utf8', timeout: settings.pollTimeoutMs, maxBuffer: 1024 * 1024,
200
+ }).trim();
201
+ for (const line of out.split('\n').slice(1)) {
202
+ const parsed = m.parseSacctRow(line.split('|'));
203
+ if (parsed) { rawState = parsed.state; break; }
204
+ }
205
+ } catch (e) {
206
+ throw new ExitError(1, 'both squeue and sacct failed: ' + (e.message || String(e)));
207
+ }
208
+ }
209
+ const mapped = m.mapSlurmState(rawState || '');
210
+ if (!mapped) throw new ExitError(1, 'unmapped SLURM state "' + rawState + '" — not guessing; inspect manually');
211
+
212
+ const updated = m.buildManifest(
213
+ Object.assign({}, existing, { status: mapped, terminal_details: existing.terminal_details || null }),
214
+ { clock: { nowIso: () => existing.submitted_at } },
215
+ );
216
+ const res = m.writeManifest(updated, planningDir);
217
+ if (!res.ok) throw new ExitError(1, 'writeManifest refused (' + res.kind + '): ' + res.message);
218
+ process.stdout.write(JSON.stringify({ job_id: jobId, slurm_state: rawState, manifest_status: mapped, path: res.path }) + '\n');
219
+ }
220
+
221
+ function formatShowReport(manifest) {
222
+ const lines = [];
223
+ lines.push('job ' + manifest.job_id + ' (plan ' + manifest.plan_id + ', backend ' + manifest.backend + ')');
224
+ lines.push('status: ' + manifest.status);
225
+ if (manifest.terminal_details) {
226
+ lines.push('terminal_details: ' + JSON.stringify(manifest.terminal_details));
227
+ }
228
+ // Trust boundary: surface commands for confirmation, never auto-run.
229
+ lines.push('');
230
+ lines.push('Manifest commands (UNTRUSTED — confirm before running):');
231
+ lines.push(' submit_command: ' + manifest.submit_command);
232
+ lines.push(' verification_command: ' + manifest.verification_command);
233
+ lines.push(' resume_command: ' + manifest.resume_command);
234
+ return lines.join('\n') + '\n';
235
+ }
236
+
237
+ function cmdShow(flags) {
238
+ const jobId = flags.job;
239
+ if (!jobId) throw new ExitError(1, 'show requires --job <job_id>\n' + usage());
240
+ const planningDir = findPlanningDir();
241
+ const manifestFile = m.manifestPath(planningDir, jobId);
242
+ if (!fs.existsSync(manifestFile)) {
243
+ throw new ExitError(1, 'no manifest for job ' + jobId + ' at ' + manifestFile);
244
+ }
245
+ const manifest = JSON.parse(fs.readFileSync(manifestFile, 'utf8'));
246
+ process.stdout.write(formatShowReport(manifest));
247
+ }
248
+
249
+ function main() {
250
+ const [, , sub, ...rest] = process.argv;
251
+ const flags = parseFlags(rest);
252
+ if (sub === 'submit') cmdSubmit(flags);
253
+ else if (sub === 'poll') cmdPoll(flags);
254
+ else if (sub === 'show') cmdShow(flags);
255
+ else throw new ExitError(1, usage());
256
+ return 0;
257
+ }
258
+
259
+ if (require.main === module) {
260
+ runMain(main);
261
+ }
262
+
263
+ module.exports = {
264
+ parseFlags,
265
+ findPlanningDir,
266
+ resolveExternalJobSettings,
267
+ formatShowReport,
268
+ ExitError,
269
+ };
@@ -24,15 +24,16 @@ const ROOT = path.resolve(__dirname, '..');
24
24
  // Single source of truth: runtime-integration manifests whose `version` field
25
25
  // MUST track package.json. Each entry names the manifest path plus the dotted
26
26
  // path to the version field inside that JSON document. Top-level `version` is
27
- // the default (plugin.json, gemini-extension.json); the Claude plugin
27
+ // the default (plugin.json); the Claude plugin
28
28
  // marketplace manifest carries its canonical version at plugins[0].version
29
29
  // (the schema-canonical location runtimes read — issue #1855).
30
30
  //
31
31
  // Add a new manifest here so `npm version` keeps it in sync — the regression
32
32
  // guard test (issue 844) fails if you forget.
33
+ // #1928: gemini-extension.json was removed with the gemini runtime (Google
34
+ // sunset Gemini CLI 2026-06-18); it is no longer a registered manifest.
33
35
  const VERSIONED_MANIFESTS = [
34
36
  { path: '.claude-plugin/plugin.json', versionKey: 'version' },
35
- { path: 'gemini-extension.json', versionKey: 'version' },
36
37
  { path: '.claude-plugin/marketplace.json', versionKey: 'plugins.0.version' },
37
38
  { path: 'vscode/package.json', versionKey: 'version' },
38
39
  ];
@@ -343,9 +343,12 @@ function transformFile(content, preamble) {
343
343
  }
344
344
  }
345
345
 
346
- // Insert preamble into the first gsd_run block only
346
+ // Insert preamble into the first gsd_run block only — UNLESS this file
347
+ // delegates to the shared resolver reference (@-include). Delegating files keep
348
+ // the stripped blocks (any inline preamble removed) but never get one inserted.
349
+ const delegates = delegatesToResolverReference(content);
347
350
  const finalBlocks = strippedBlocks.map((stripped, bi) => {
348
- if (bi === firstGsdRunBlockIdx) {
351
+ if (!delegates && bi === firstGsdRunBlockIdx) {
349
352
  return insertPreamble(stripped, preamble);
350
353
  }
351
354
  return stripped;
@@ -374,6 +377,21 @@ function escapeRegExp(str) {
374
377
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
375
378
  }
376
379
 
380
+ /**
381
+ * A file "delegates to the shared resolver" when it pulls the canonical gsd_run
382
+ * preamble in from gsd-core/references/gsd-run-resolver.md via an @-include
383
+ * instead of inlining the snippet (see onboard.md / issue #1990).
384
+ *
385
+ * These files must NOT carry an inline preamble: the resolver reference ships the
386
+ * one canonical copy, and onboard-command.test.cjs asserts the inline form is
387
+ * absent. transformFile still STRIPS any inline preamble from them (so a stray
388
+ * copy is removed) but never re-inserts one — mirroring the exemption in
389
+ * runtime-launcher-parity.test.cjs (subtest B / B2).
390
+ */
391
+ function delegatesToResolverReference(content) {
392
+ return content.includes('references/gsd-run-resolver.md');
393
+ }
394
+
377
395
  // Main
378
396
  function main() {
379
397
  const preamble = loadPreamble();
@@ -42,7 +42,7 @@ Parse the first token of $ARGUMENTS:
42
42
  Check for .planning/STATE.md - loads context if project already initialized
43
43
 
44
44
  **This command can run:**
45
- - Before /gsd-new-project (brownfield codebases) - creates codebase map first
45
+ - Via /gsd-onboard for first-time brownfield setup - creates codebase map first
46
46
  - After /gsd-new-project (greenfield codebases) - updates codebase map as code evolves
47
47
  - Anytime to refresh codebase understanding
48
48
  </context>
@@ -51,7 +51,7 @@ Check for .planning/STATE.md - loads context if project already initialized
51
51
  **Use map-codebase for:**
52
52
  - Brownfield projects before initialization (understand existing code first)
53
53
  - Refreshing codebase map after significant changes
54
- - Onboarding to an unfamiliar codebase
54
+ - Refreshing or deepening an onboarded codebase map
55
55
  - Before major refactoring (understand current state)
56
56
  - When STATE.md references outdated codebase info
57
57
 
@@ -71,7 +71,7 @@ Check for .planning/STATE.md - loads context if project already initialized
71
71
  4. Wait for agents to complete, collect confirmations (NOT document contents)
72
72
  5. Verify all 7 documents exist with line counts
73
73
  6. Commit codebase map
74
- 7. Offer next steps (typically: /gsd-new-project or /gsd-plan-phase)
74
+ 7. Offer next steps (typically: /gsd-onboard, /gsd-new-project, or /gsd-plan-phase)
75
75
  </process>
76
76
 
77
77
  <success_criteria>
@@ -56,7 +56,7 @@ On any error or timeout, stop and let the phase continue -- capture is best-effo
56
56
 
57
57
  1. **Dedup first.** Interactive: `mempalace_check_duplicate` on the artifact's deterministic drawer id. Headless: rely on `mempalace mine`'s content-hash idempotency.
58
58
  2. **Add the drawer (verbatim).** File the exact artifact text into `room: <room>` of `wing: <wing>` with provenance (`source_file`, phase id). Interactive: `mempalace_add_drawer`. Headless: `mempalace mine <path> --wing <wing> --room <room>`.
59
- 3. **Mirror KG facts** when `config.mempalace.mirror_kg` is true: extract decision/delivery facts and `mempalace_kg_add` them with `valid_from` = the phase date (e.g. `(<project>, decided, <decision>)` from CONTEXT; `(<phase>, delivered, <capability>)` from SUMMARY). Only `augment` is currently wired, so these are an *additive* mirror of `.planning/graphs/`. (`kg_backend`/`replace` are forward-declared and behave as `augment` today.)
59
+ 3. **Mirror KG facts** when `config.mempalace.mirror_kg` is true: extract decision/delivery facts and `mempalace_kg_add` them with `valid_from` = the phase date (e.g. `(<project>, decided, <decision>)` from CONTEXT; `(<phase>, delivered, <capability>)` from SUMMARY). Under `augment` these are an *additive* mirror of GSD's native `.planning/graphs/`. Under `kg_backend`/`replace` the palace KG is the *authoritative* fact store — GSD still produces `.planning/graphs/` through its normal graphify, so an unreachable palace never loses a fact.
60
60
  4. Re-running a phase MUST NOT create duplicate drawers (deterministic ids + `check_duplicate`).
61
61
 
62
62
  ## Step 4 -- Report
@@ -48,13 +48,17 @@ This step is `onError: skip` at `plan:pre` -- recall never blocks planning.
48
48
  ## Step 2 -- Resolve wing, mode, and transport
49
49
 
50
50
  1. **Wing.** Use `config.mempalace.wing` if non-empty; otherwise derive from `config.project_code`; otherwise fall back to the repository directory name.
51
- 2. **Mode.** Read `config.mempalace.memory_mode` (`augment` | `kg_backend` | `replace`, default `augment`). Only `augment` is wired today, so recall always treats the palace as additive; `kg_backend`/`replace` are forward-declared and behave as `augment`.
51
+ 2. **Mode.** Read `config.mempalace.memory_mode` (`augment` | `kg_backend` | `replace`, default `augment`). It sets how authoritative the palace is during recall:
52
+ - `augment` — the palace is an *additional* layer; read native memory (`.planning/graphs/`, STATE) too and treat the palace as supplementary.
53
+ - `kg_backend` — for knowledge-graph facts, query the palace's temporal KG *first, as the primary source*; fall back to `.planning/graphs/` when the palace is unreachable. Non-KG drawer recall stays additive.
54
+ - `replace` — resolve recall *through the palace as the source of truth*; consult native artifacts only as a fallback when the palace is unreachable.
55
+ In every mode an unreachable palace degrades to native memory — recall never blocks (`onError: skip`).
52
56
  3. **Transport.** Prefer the **MCP tools** (`mempalace_*`) in interactive runs *when your MemPalace MCP server is registered and your runtime permits those tools*. Otherwise — headless/cron/autonomous runs, or runtimes that don't grant the MemPalace MCP tools — use the **CLI** (`mempalace wake-up`, `mempalace search`), which this skill's `Bash` allow-tool always covers. If neither is reachable, go to Step 4.
53
57
  4. **Topic.** Read the phase `CONTEXT.md` (the consumed artifact). Derive a short search query from its title, goal, and key decisions.
54
58
 
55
59
  ## Step 3 -- Retrieve (read-only)
56
60
 
57
- All calls in this step are side-effect-free. On any error or timeout, stop retrieving and write whatever was gathered (or the stub) -- never raise.
61
+ All calls in this step are side-effect-free. On any error or timeout, stop retrieving and write whatever was gathered (or the stub) -- never raise. This skill reads only the palace; GSD's planner reads native memory (`.planning/graphs/`, STATE) regardless. So under `kg_backend`/`replace` an unreachable palace falls back to that native memory automatically — reflect that in the stub (Step 4) rather than implying memory is gone.
58
62
 
59
63
  1. **Wake up** (cheap, ~600--900 tokens):
60
64
  - Interactive: read the wing identity/summary, then `mempalace_search`.
@@ -62,7 +66,7 @@ All calls in this step are side-effect-free. On any error or timeout, stop retri
62
66
  2. **Targeted search:**
63
67
  - Interactive: `mempalace_search(query=<topic>, wing=<wing>)`.
64
68
  - Headless: `mempalace search "<topic>" --wing <wing>`.
65
- 3. **Knowledge-graph facts** (when `config.mempalace.mirror_kg` is true): `mempalace_kg_query` / `mempalace_kg_timeline` for decisions relevant to the topic and their validity windows. Only `augment` is currently wired, so the palace KG *supplements* GSD's native `.planning/graphs/` — do not treat it as the sole source. (`kg_backend`/`replace` are forward-declared and behave as `augment` today.)
69
+ 3. **Knowledge-graph facts** (when `config.mempalace.mirror_kg` is true): `mempalace_kg_query` / `mempalace_kg_timeline` for decisions relevant to the topic and their validity windows. Under `augment` the palace KG *supplements* GSD's native `.planning/graphs/` — combine both, do not treat the palace as the sole source. Under `kg_backend` or `replace` the palace KG is the *primary* graph source — query it first and use `.planning/graphs/` only as a fallback when the palace is unreachable.
66
70
  4. **Dedup** the returned drawers/facts; keep the top results.
67
71
 
68
72
  ## Step 4 -- Write MEMORY-RECALL.md
@@ -86,12 +90,12 @@ _Wing: <wing> · Mode: <mode> · Transport: <mcp|cli>_
86
90
  - <surprise> — <provenance>
87
91
  ```
88
92
 
89
- When MemPalace is unreachable, write the stub and continue:
93
+ When MemPalace is unreachable, write the stub and continue. Under `kg_backend`/`replace`, name the native fallback so the planner knows memory is not gone — only un-augmented by the palace this run:
90
94
 
91
95
  ```markdown
92
96
  # Memory Recall (MemPalace)
93
97
 
94
- _MemPalace unavailable at recall time — proceeding without recalled memory._
98
+ _MemPalace unavailable at recall time — falling back to GSD native memory (`.planning/graphs/`, STATE). No palace recall this run._
95
99
  ```
96
100
 
97
101
  ## Anti-Patterns
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: gsd-next
3
+ description: "Smart entry — detect project state and route to the right next GSD action."
4
+ effort: low
5
+ allowed-tools:
6
+ - Read
7
+ - Bash
8
+ - Glob
9
+ - SlashCommand
10
+ - AskUserQuestion
11
+ ---
12
+
13
+ <objective>
14
+ GSD smart entry — the state-aware front door. Detect what's going on in this project, then present a short menu of the right next actions and dispatch to one.
15
+
16
+ This is a launcher/router only. It never does the work itself. It reads project + workflow state via `gsd-tools smart-entry --json`, shows a situation-appropriate menu, and hands off to an existing GSD command.
17
+ </objective>
18
+
19
+ <execution_context>
20
+ @~/.claude/gsd-core/workflows/smart-entry.md
21
+ @~/.claude/gsd-core/references/ui-brand.md
22
+ </execution_context>
23
+
24
+ <context>
25
+ Arguments: $ARGUMENTS
26
+ </context>
27
+
28
+ <process>
29
+ Follow ~/.claude/gsd-core/workflows/smart-entry.md. Detect the situation, present the menu, and dispatch exactly one command. Then stop.
30
+ </process>
@@ -14,6 +14,7 @@ inline as part of `gsd-audit-milestone`'s output.
14
14
  | User wants | Invoke |
15
15
  |---|---|
16
16
  | Start a new project | gsd-new-project |
17
+ | Onboard an existing codebase | gsd-onboard |
17
18
  | Create a new milestone | gsd-new-milestone |
18
19
  | Complete the current milestone | gsd-complete-milestone |
19
20
  | Audit a milestone for issues | gsd-audit-milestone |
@@ -10,7 +10,9 @@ allowed-tools:
10
10
  Route to the appropriate phase-pipeline skill based on the user's intent.
11
11
  Sub-skill names below are post-#2790 consolidated targets — `gsd-phase`
12
12
  absorbs the former add/insert/remove/edit-phase commands and `gsd-progress`
13
- absorbs the former next/do commands.
13
+ absorbs the former next/do workflow-advance commands. The reclaimed
14
+ `gsd-next` target is the state-aware smart-entry launcher, not the retired
15
+ workflow-advance command.
14
16
 
15
17
  | User wants | Invoke |
16
18
  |---|---|
@@ -21,6 +23,7 @@ absorbs the former next/do commands.
21
23
  | Verify built features through UAT | gsd-verify-work |
22
24
  | Add / insert / remove / edit a phase | gsd-phase |
23
25
  | Advance to the next logical step | gsd-progress |
26
+ | Open the state-aware smart-entry launcher | gsd-next |
24
27
  | Offload planning to the ultraplan cloud | gsd-ultraplan-phase |
25
28
  | Cross-AI plan review convergence loop | gsd-plan-review-convergence |
26
29
  | Generate tests for a completed phase | gsd-add-tests |
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: gsd-onboard
3
+ description: "Guide existing codebase onboarding through mapping, doc ingest, and planning setup"
4
+ argument-hint: "[--fast] [--text]"
5
+ allowed-tools:
6
+ - Read
7
+ - Bash
8
+ - Write
9
+ - Glob
10
+ - Grep
11
+ - Agent
12
+ - AskUserQuestion
13
+ ---
14
+
15
+ <runtime_note>
16
+ **Copilot (VS Code):** Use `vscode_askquestions` wherever this workflow calls `AskUserQuestion`. They are equivalent — `vscode_askquestions` is the VS Code Copilot implementation of the same interactive question API.
17
+ </runtime_note>
18
+
19
+ <objective>
20
+ Guide brownfield onboarding for an existing codebase by routing through the existing GSD primitives in the safe order: codebase map → docs ingest → project initialization → onboarding summary.
21
+
22
+ **Creates or confirms:**
23
+ - `.planning/codebase/` — evidence-backed codebase map from `/gsd-map-codebase`
24
+ - `.planning/PROJECT.md`, `REQUIREMENTS.md`, `ROADMAP.md`, `STATE.md` — project setup from `/gsd-new-project` or `/gsd-ingest-docs`
25
+ - `.planning/onboarding/SUMMARY.md` — lightweight index of what was learned and the next command
26
+
27
+ **Non-goals:** This command does not execute phases, ship work, or overwrite existing planning artifacts without an explicit gate.
28
+ </objective>
29
+
30
+ <execution_context>
31
+ @~/.claude/gsd-core/workflows/onboard.md
32
+ @~/.claude/gsd-core/references/ui-brand.md
33
+ @~/.claude/gsd-core/references/gate-prompts.md
34
+ </execution_context>
35
+
36
+ <context>
37
+ Arguments: $ARGUMENTS
38
+
39
+ Flags:
40
+ - `--fast` — prefer `/gsd-map-codebase --fast` for the mapping handoff; the complete map is still required before `/gsd-new-project`.
41
+ - `--text` — use plain-text numbered lists instead of TUI menus.
42
+ </context>
43
+
44
+ <process>
45
+ Execute the onboard workflow end-to-end. Preserve all safety gates, text-mode fallbacks, idempotency checks, and top-level handoff rules for nested interactive commands.
46
+ </process>
@@ -1,6 +0,0 @@
1
- {
2
- "name": "gsd-core",
3
- "version": "1.7.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
- }