@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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/GEMINI.md +25 -23
- package/README.ja-JP.md +4 -3
- package/README.ko-KR.md +4 -3
- package/README.md +7 -6
- package/README.pt-BR.md +4 -3
- package/README.zh-CN.md +4 -3
- package/agents/gsd-advisor-researcher.md +1 -1
- package/agents/gsd-ai-researcher.md +1 -1
- package/agents/gsd-code-fixer.md +1 -1
- package/agents/gsd-debug-session-manager.md +1 -1
- package/agents/gsd-debugger.md +1 -1
- package/agents/gsd-domain-researcher.md +1 -1
- package/agents/gsd-eval-auditor.md +1 -1
- package/agents/gsd-executor.md +4 -4
- package/agents/gsd-intel-updater.md +1 -1
- package/agents/gsd-mempalace-curator.md +1 -1
- package/agents/gsd-phase-researcher.md +2 -2
- package/agents/gsd-plan-checker.md +1 -1
- package/agents/gsd-planner.md +2 -2
- package/agents/gsd-project-researcher.md +2 -2
- package/agents/gsd-research-synthesizer.md +1 -1
- package/agents/gsd-ui-researcher.md +2 -2
- package/agents/gsd-verifier.md +2 -2
- package/bin/install.js +132 -464
- package/commands/gsd/map-codebase.md +4 -4
- package/commands/gsd/mempalace-capture.md +1 -1
- package/commands/gsd/mempalace-recall.md +9 -5
- package/commands/gsd/next.md +29 -0
- package/commands/gsd/ns-project.md +2 -1
- package/commands/gsd/ns-workflow.md +5 -2
- package/commands/gsd/onboard.md +46 -0
- package/gsd-core/bin/ensure-runtime-build.cjs +246 -0
- package/gsd-core/bin/gsd-tools.cjs +72 -3
- package/gsd-core/bin/lib/capability-registry.cjs +684 -264
- package/gsd-core/bin/lib/capability-state.cjs +117 -18
- package/gsd-core/bin/lib/capability-writer.cjs +11 -1
- package/gsd-core/bin/lib/check-command-router.cjs +111 -1
- package/gsd-core/bin/lib/claude-orchestration-command-router.cjs +136 -0
- package/gsd-core/bin/lib/claude-orchestration.cjs +404 -0
- package/gsd-core/bin/lib/clusters.cjs +2 -0
- package/gsd-core/bin/lib/command-aliases.cjs +8 -0
- package/gsd-core/bin/lib/config.cjs +19 -1
- package/gsd-core/bin/lib/core-utils.cjs +41 -0
- package/gsd-core/bin/lib/external-job.cjs +287 -0
- package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +151 -0
- package/gsd-core/bin/lib/graphify.cjs +41 -9
- package/gsd-core/bin/lib/init-command-router.cjs +4 -0
- package/gsd-core/bin/lib/init.cjs +25 -69
- package/gsd-core/bin/lib/install-engine.cjs +8 -5
- package/gsd-core/bin/lib/install-profiles.cjs +2 -0
- package/gsd-core/bin/lib/loop-resolver.cjs +7 -1
- package/gsd-core/bin/lib/milestone.cjs +7 -1
- package/gsd-core/bin/lib/model-resolver.cjs +69 -4
- package/gsd-core/bin/lib/onboard-projection.cjs +309 -0
- package/gsd-core/bin/lib/phase.cjs +14 -2
- package/gsd-core/bin/lib/plan-scan.cjs +9 -1
- package/gsd-core/bin/lib/profile-output.cjs +1 -1
- package/gsd-core/bin/lib/prohibition-enforcement.cjs +21 -19
- package/gsd-core/bin/lib/roadmap.cjs +17 -2
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +18 -13
- package/gsd-core/bin/lib/runtime-name-policy.cjs +11 -11
- package/gsd-core/bin/lib/shell-command-projection.cjs +12 -8
- package/gsd-core/bin/lib/smart-entry.cjs +521 -0
- package/gsd-core/bin/lib/surface.cjs +63 -33
- package/gsd-core/bin/lib/update-context.cjs +0 -5
- package/gsd-core/bin/shared/config-schema.manifest.json +1 -0
- package/gsd-core/bin/shared/model-catalog.json +5 -5
- package/gsd-core/bin/shared/runtime-aliases.manifest.json +0 -5
- package/gsd-core/references/gates.md +1 -1
- package/gsd-core/references/gsd-run-resolver.md +8 -0
- package/gsd-core/references/planning-config.md +1 -1
- package/gsd-core/templates/project.md +1 -1
- package/gsd-core/workflows/_runtime-launcher.snippet.sh +1 -1
- package/gsd-core/workflows/add-backlog.md +1 -1
- package/gsd-core/workflows/add-phase.md +1 -1
- package/gsd-core/workflows/add-tests.md +1 -1
- package/gsd-core/workflows/add-todo.md +1 -1
- package/gsd-core/workflows/ai-integration-phase.md +1 -1
- package/gsd-core/workflows/audit-fix.md +1 -1
- package/gsd-core/workflows/audit-milestone.md +1 -1
- package/gsd-core/workflows/audit-uat.md +1 -1
- package/gsd-core/workflows/autonomous.md +1 -1
- package/gsd-core/workflows/check-todos.md +1 -1
- package/gsd-core/workflows/cleanup.md +1 -1
- package/gsd-core/workflows/code-review-fix.md +1 -1
- package/gsd-core/workflows/code-review.md +1 -1
- package/gsd-core/workflows/complete-milestone.md +1 -1
- package/gsd-core/workflows/debug.md +1 -1
- package/gsd-core/workflows/diagnose-issues.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/advisor.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/auto.md +1 -1
- package/gsd-core/workflows/discuss-phase/modes/chain.md +1 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +1 -1
- package/gsd-core/workflows/discuss-phase.md +2 -2
- package/gsd-core/workflows/do.md +5 -4
- package/gsd-core/workflows/docs-update.md +1 -1
- package/gsd-core/workflows/edit-phase.md +1 -1
- package/gsd-core/workflows/eval-review.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +1 -1
- package/gsd-core/workflows/execute-phase.md +4 -5
- package/gsd-core/workflows/execute-plan.md +1 -1
- package/gsd-core/workflows/explore.md +1 -1
- package/gsd-core/workflows/extract-learnings.md +1 -1
- package/gsd-core/workflows/forensics.md +1 -1
- package/gsd-core/workflows/graduation.md +1 -1
- package/gsd-core/workflows/health.md +1 -1
- package/gsd-core/workflows/help/modes/brief.md +2 -1
- package/gsd-core/workflows/help/modes/default.md +2 -1
- package/gsd-core/workflows/help/modes/full.md +25 -1
- package/gsd-core/workflows/help/modes/topic.md +2 -1
- package/gsd-core/workflows/import.md +1 -1
- package/gsd-core/workflows/ingest-docs.md +1 -1
- package/gsd-core/workflows/insert-phase.md +1 -1
- package/gsd-core/workflows/list-seeds.md +1 -1
- package/gsd-core/workflows/list-workspaces.md +1 -1
- package/gsd-core/workflows/manager.md +1 -1
- package/gsd-core/workflows/map-codebase.md +1 -1
- package/gsd-core/workflows/milestone-summary.md +1 -1
- package/gsd-core/workflows/mvp-phase.md +1 -1
- package/gsd-core/workflows/new-milestone.md +1 -1
- package/gsd-core/workflows/new-project.md +1 -1
- package/gsd-core/workflows/new-workspace.md +1 -1
- package/gsd-core/workflows/next.md +1 -1
- package/gsd-core/workflows/onboard.md +277 -0
- package/gsd-core/workflows/pause-work.md +1 -1
- package/gsd-core/workflows/plan-milestone-gaps.md +1 -1
- package/gsd-core/workflows/plan-phase/steps/prd-express-path.md +1 -1
- package/gsd-core/workflows/plan-phase.md +9 -2
- package/gsd-core/workflows/plan-review-convergence.md +1 -1
- package/gsd-core/workflows/plant-seed.md +1 -1
- package/gsd-core/workflows/pr-branch.md +1 -1
- package/gsd-core/workflows/profile-user.md +1 -1
- package/gsd-core/workflows/progress.md +1 -1
- package/gsd-core/workflows/quick.md +21 -1
- package/gsd-core/workflows/reapply-patches.md +1 -1
- package/gsd-core/workflows/remove-phase.md +1 -1
- package/gsd-core/workflows/remove-workspace.md +1 -1
- package/gsd-core/workflows/resume-project.md +1 -1
- package/gsd-core/workflows/review.md +43 -7
- package/gsd-core/workflows/scan.md +1 -1
- package/gsd-core/workflows/secure-phase.md +1 -1
- package/gsd-core/workflows/settings-advanced.md +3 -1
- package/gsd-core/workflows/settings-integrations.md +1 -1
- package/gsd-core/workflows/settings.md +1 -1
- package/gsd-core/workflows/ship.md +1 -1
- package/gsd-core/workflows/sketch-wrap-up.md +1 -1
- package/gsd-core/workflows/sketch.md +1 -1
- package/gsd-core/workflows/smart-entry.md +120 -0
- package/gsd-core/workflows/spec-phase.md +8 -6
- package/gsd-core/workflows/spike-wrap-up.md +1 -1
- package/gsd-core/workflows/spike.md +1 -1
- package/gsd-core/workflows/stats.md +1 -1
- package/gsd-core/workflows/thread.md +1 -1
- package/gsd-core/workflows/transition.md +1 -1
- package/gsd-core/workflows/ui-phase.md +1 -1
- package/gsd-core/workflows/ui-review.md +1 -1
- package/gsd-core/workflows/ultraplan-phase.md +1 -1
- package/gsd-core/workflows/update.md +3 -6
- package/gsd-core/workflows/validate-phase.md +1 -1
- package/gsd-core/workflows/verify-phase.md +1 -1
- package/gsd-core/workflows/verify-work.md +62 -4
- package/package.json +3 -5
- package/scripts/ci-test-scope.cjs +19 -1
- package/scripts/gen-golden-install-parity-zcode.cjs +77 -0
- package/scripts/generate-package-identity.cjs +27 -2
- package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -148
- package/scripts/lint-regression-test-names.allowlist.json +1 -273
- package/scripts/lint-test-file-count.allowlist.json +7 -91
- package/scripts/research-profiles.cjs +6 -6
- package/scripts/run-tests.cjs +18 -3
- package/scripts/slurm-adapter.cjs +269 -0
- package/scripts/sync-manifest-versions.cjs +3 -2
- package/scripts/sync-runtime-launcher.cjs +20 -2
- package/skills/gsd-map-codebase/SKILL.md +3 -3
- package/skills/gsd-mempalace-capture/SKILL.md +1 -1
- package/skills/gsd-mempalace-recall/SKILL.md +9 -5
- package/skills/gsd-next/SKILL.md +30 -0
- package/skills/gsd-ns-project/SKILL.md +1 -0
- package/skills/gsd-ns-workflow/SKILL.md +4 -1
- package/skills/gsd-onboard/SKILL.md +46 -0
- 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
|
|
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
|
-
-
|
|
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
|
-
-
|
|
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).
|
|
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`).
|
|
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.
|
|
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 —
|
|
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>
|
package/gemini-extension.json
DELETED
|
@@ -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
|
-
}
|