feat(install): validate agent CLI runtime registries

This commit is contained in:
2026-09-18 16:42:09 +08:00
parent 867a23497f
commit 5a259a95af
11 changed files with 350 additions and 23 deletions
+77
View File
@@ -0,0 +1,77 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { existsSync, mkdirSync, rmSync } from 'node:fs';
import { join } from 'node:path';
import { fakePrompt, makeFakePlugin } from './helpers/fake-plugin.js';
import { tmpRoot } from './helpers/run-script.js';
const PROMPTS = {
'sdlc-analyze': fakePrompt('sdlc-analyze'),
'sdlc-plan': fakePrompt('sdlc-plan'),
};
function homeWith(t, platform) {
mkdirSync(tmpRoot, { recursive: true });
const home = join(tmpRoot, `runtime-home-${platform}`);
rmSync(home, { recursive: true, force: true });
mkdirSync(join(home, 'work'), { recursive: true });
const roots = {
'oh-my-pi': ['.omp'],
claude: ['.claude'],
codex: ['.codex'],
kiro: ['.kiro'],
};
mkdirSync(join(home, ...roots[platform]), { recursive: true });
t.after(() => rmSync(home, { recursive: true, force: true }));
return home;
}
const runInHome = (plugin, home) => (args) =>
plugin.run(args, { env: { HOME: home }, cwd: join(home, 'work') });
test('sdlc-version 回報版本、實際 tea-sdlc executable 與六個流程', async (t) => {
const plugin = makeFakePlugin(t, { prompts: PROMPTS });
const { json } = await plugin.run(['sdlc-version']);
assert.equal(json.ok, true);
assert.equal(json.data.name, 'tea-sdlc');
assert.equal(json.data.version, '0.0.1');
assert.equal(json.data.executable, join(plugin.shim, 'tea-sdlc'));
assert.deepEqual(json.data.commands, ['sdlc-analyze', 'sdlc-plan']);
});
test('OMP 使用 ~/.omp/agent/commands 作為 runtime registry,六個 command 全部找到才 pass', async (t) => {
const plugin = makeFakePlugin(t, { prompts: PROMPTS });
const home = homeWith(t, 'oh-my-pi');
const run = runInHome(plugin, home);
const installed = await run(['install']);
assert.equal(installed.code, 0);
assert.ok(existsSync(join(home, '.omp', 'agent', 'commands', 'sdlc-analyze.md')));
assert.equal(installed.json.data.verify.platforms[0].runtime.status, 'pass');
assert.deepEqual(installed.json.data.verify.platforms[0].runtime.commands, ['sdlc-analyze', 'sdlc-plan']);
});
test('runtime registry 缺少 command 時 verify exit 1 並列出 missing', async (t) => {
const plugin = makeFakePlugin(t, { prompts: PROMPTS });
const home = homeWith(t, 'claude');
const run = runInHome(plugin, home);
await run(['install']);
rmSync(join(home, '.claude', 'commands', 'sdlc-plan.md'));
const result = await run(['verify', '--platform', 'claude']);
assert.equal(result.code, 1);
assert.equal(result.json.error.code, 'RUNTIME_VERIFY_FAILED');
assert.deepEqual(result.json.data.platforms[0].runtime.missing, ['sdlc-plan']);
assert.equal(result.json.data.platforms[0].runtime.status, 'fail');
});
test('沒有安全 registry probe 的平台回報 not-supported 而不阻止 install', async (t) => {
const plugin = makeFakePlugin(t, { prompts: PROMPTS });
const home = homeWith(t, 'kiro');
const result = await runInHome(plugin, home)(['install']);
assert.equal(result.code, 0);
assert.equal(result.json.data.verify.platforms[0].runtime.status, 'not-supported');
assert.deepEqual(result.json.data.verify.platforms[0].runtime.failures, []);
});