Files
msd-core/tests/claude-orchestration-command-router.test.cjs
Jakub Zych a9a7a328e6 refactor: hard-fork GSD -> MSD (Make Software Done)
Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD
across contents and paths, upstream package/repo coordinates -> @golem15/msd-core
and golem15com/msd-core. Deep links into upstream history, sibling upstream
packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is.

Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line,
package/plugin identity, regenerated lockfile, install-tree fixtures, derived
registries and benchmark baseline; migration checksum baseline re-locked
(MSD keeps its own install state, so no install had applied the old sums);
sort-order and regex-escaped expectations in tests adjusted.
2026-10-06 01:47:40 +02:00

174 lines
6.6 KiB
JavaScript

'use strict';
/**
* claude-orchestration-command-router.test.cjs — end-to-end tests for the
* `msd-tools claude-orchestration` command surface (#1143).
*
* Exercises the full dispatch path: msd-tools → dispatchCapabilityCommand →
* routeClaudeOrchestrationCommand → the pure detect/emitter functions.
*
* NOTE: runMsdTools() returns { success, output, exitCode, error } — it does
* NOT throw on a non-zero exit (helpers.cjs). Tests assert `.success` and parse
* `.output`, and check `.error` on the failure path.
*/
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const { runMsdTools, createTempProject, cleanup } = require('./helpers.cjs');
// ─── Fixtures ─────────────────────────────────────────────────────────────────
const WAVES_MANIFEST = {
waves: [
{
id: 'w1',
plans: [
{ id: 'p1', brief: 'Implement the foo module', files_modified: ['src/foo.cts'] },
{ id: 'p2', brief: 'Wire the bar seam', files_modified: ['src/bar.cts'] },
],
},
],
};
function writeManifest(tmpDir) {
const manifestPath = path.join(tmpDir, 'waves.json');
fs.writeFileSync(manifestPath, JSON.stringify(WAVES_MANIFEST), 'utf8');
return manifestPath;
}
/** Run the command and assert it succeeded, returning the parsed JSON output. */
function runAndParse(args, cwd) {
const res = runMsdTools(args, cwd);
assert.strictEqual(res.success, true, 'command should succeed; stderr: ' + (res.error || ''));
assert.ok(res.output.length > 0, 'command should emit output');
return JSON.parse(res.output);
}
// ─── emit-workflow ────────────────────────────────────────────────────────────
describe('claude-orchestration emit-workflow (CLI)', () => {
test('emits a Workflow script with parallel barriers, msd-executor + worktree, and resumeFromRunId', () => {
const tmp = createTempProject('claw-emit-');
try {
const manifestPath = writeManifest(tmp);
const parsed = runAndParse([
'claude-orchestration', 'emit-workflow',
'--waves', manifestPath,
'--run-id', 'run-cli-1143',
'--phase-dir', '.planning/phases/01-foo',
], tmp);
assert.ok(typeof parsed.script === 'string' && parsed.script.length > 0);
assert.ok(parsed.script.includes('parallel('), 'parallel() barrier emitted');
assert.ok(parsed.script.includes('msd-executor'), 'msd-executor agentType');
assert.ok(parsed.script.includes('worktree'), 'worktree isolation');
// #2590: never CALLED — it is a Workflow tool input, not a script function.
assert.ok(!/^\s*resumeFromRunId\s*\(/m.test(parsed.script), 'must not CALL resumeFromRunId');
assert.ok(parsed.script.includes('run-cli-1143'), 'carries the run id');
assert.strictEqual(parsed.summary.resumeRunId, 'run-cli-1143');
assert.strictEqual(parsed.summary.waves, 1);
assert.strictEqual(parsed.summary.plans, 2);
} finally {
cleanup(tmp);
}
});
test('budget flag threads a shared token pool into the script', () => {
const tmp = createTempProject('claw-budget-');
try {
const manifestPath = writeManifest(tmp);
const parsed = runAndParse([
'claude-orchestration', 'emit-workflow',
'--waves', manifestPath,
'--run-id', 'r',
'--budget', '750000',
], tmp);
// #2590: `budget` is read-only; budget(750000) threw "budget is not a
// function". The intended pool is recorded, not called.
assert.ok(!/^\s*budget\s*\(/m.test(parsed.script), 'must not CALL budget()');
assert.ok(parsed.script.includes('750000'));
assert.strictEqual(parsed.summary.budgetTokens, 750000);
} finally {
cleanup(tmp);
}
});
test('missing --waves -> non-zero exit with a diagnostic', () => {
const tmp = createTempProject('claw-noargs-');
try {
const res = runMsdTools([
'claude-orchestration', 'emit-workflow', '--run-id', 'r',
], tmp);
assert.strictEqual(res.success, false, 'missing --waves must fail');
assert.ok(res.exitCode !== 0, 'non-zero exit');
assert.match(res.error || '', /--waves/);
} finally {
cleanup(tmp);
}
});
});
// ─── detect-backend ───────────────────────────────────────────────────────────
describe('claude-orchestration detect-backend (CLI)', () => {
test('default config (capability off) -> inline, even on Claude', () => {
const tmp = createTempProject('claw-detect-');
try {
const parsed = runAndParse([
'claude-orchestration', 'detect-backend',
'--runtime', 'claude',
'--agent-sdk-version', '1.0.0',
], tmp);
assert.strictEqual(parsed.backend, 'inline');
assert.strictEqual(parsed.available, false);
assert.match(parsed.reason, /disabled/);
} finally {
cleanup(tmp);
}
});
test('enabled + claude + capable + new-enough SDK -> workflow', () => {
const tmp = createTempProject('claw-detect-on-');
try {
fs.mkdirSync(path.join(tmp, '.planning'), { recursive: true });
fs.writeFileSync(
path.join(tmp, '.planning', 'config.json'),
JSON.stringify({ claude_orchestration: { enabled: true, execution_backend: 'auto' } }),
'utf8',
);
const parsed = runAndParse([
'claude-orchestration', 'detect-backend',
'--runtime', 'claude',
'--agent-sdk-version', '1.2.0',
], tmp);
assert.strictEqual(parsed.backend, 'workflow');
assert.strictEqual(parsed.available, true);
} finally {
cleanup(tmp);
}
});
test('non-Claude runtime -> inline (criterion 6)', () => {
const tmp = createTempProject('claw-detect-nonclaude-');
try {
fs.mkdirSync(path.join(tmp, '.planning'), { recursive: true });
fs.writeFileSync(
path.join(tmp, '.planning', 'config.json'),
JSON.stringify({ claude_orchestration: { enabled: true } }),
'utf8',
);
const parsed = runAndParse([
'claude-orchestration', 'detect-backend',
'--runtime', 'codex',
'--agent-sdk-version', '1.0.0',
], tmp);
assert.strictEqual(parsed.backend, 'inline');
assert.match(parsed.reason, /claude/i);
} finally {
cleanup(tmp);
}
});
});