feat: add work items CLI

This commit is contained in:
Affaan Mustafa
2026-05-11 12:13:30 -04:00
committed by Affaan Mustafa
parent 8926ea925e
commit b1e67788f7
8 changed files with 421 additions and 2 deletions

View File

@@ -16,6 +16,7 @@ const {
const ECC_SCRIPT = path.join(__dirname, '..', '..', 'scripts', 'ecc.js');
const STATUS_SCRIPT = path.join(__dirname, '..', '..', 'scripts', 'status.js');
const SESSIONS_SCRIPT = path.join(__dirname, '..', '..', 'scripts', 'sessions-cli.js');
const WORK_ITEMS_SCRIPT = path.join(__dirname, '..', '..', 'scripts', 'work-items.js');
async function test(name, fn) {
try {
@@ -697,6 +698,76 @@ async function runTests() {
}
})) passed += 1; else failed += 1;
if (await test('work-items CLI supports upsert, list, show, and close', async () => {
const testDir = createTempDir('ecc-work-items-cli-');
const dbPath = path.join(testDir, 'state.db');
try {
const upsertResult = runNode(WORK_ITEMS_SCRIPT, [
'upsert',
'linear-ecc-99',
'--db',
dbPath,
'--source',
'linear',
'--source-id',
'ECC-99',
'--title',
'Ship work item CLI',
'--status',
'blocked',
'--priority',
'high',
'--url',
'https://linear.app/example/issue/ECC-99',
'--owner',
'control-plane',
'--metadata-json',
'{"project":"ECC 2.0"}',
'--json',
], { cwd: testDir });
assert.strictEqual(upsertResult.status, 0, upsertResult.stderr);
const upsertPayload = parseJson(upsertResult.stdout);
assert.strictEqual(upsertPayload.id, 'linear-ecc-99');
assert.strictEqual(upsertPayload.status, 'blocked');
assert.strictEqual(upsertPayload.repoRoot, fs.realpathSync(testDir));
assert.strictEqual(upsertPayload.metadata.project, 'ECC 2.0');
const updateResult = runNode(WORK_ITEMS_SCRIPT, [
'upsert',
'linear-ecc-99',
'--db',
dbPath,
'--status',
'in-progress',
'--json',
]);
assert.strictEqual(updateResult.status, 0, updateResult.stderr);
const updatePayload = parseJson(updateResult.stdout);
assert.strictEqual(updatePayload.title, 'Ship work item CLI');
assert.strictEqual(updatePayload.source, 'linear');
assert.strictEqual(updatePayload.status, 'in-progress');
const listResult = runNode(WORK_ITEMS_SCRIPT, ['list', '--db', dbPath, '--json']);
assert.strictEqual(listResult.status, 0, listResult.stderr);
const listPayload = parseJson(listResult.stdout);
assert.strictEqual(listPayload.totalCount, 1);
assert.strictEqual(listPayload.items[0].id, 'linear-ecc-99');
const showResult = runNode(WORK_ITEMS_SCRIPT, ['show', 'linear-ecc-99', '--db', dbPath]);
assert.strictEqual(showResult.status, 0, showResult.stderr);
assert.match(showResult.stdout, /linear\/#ECC-99 in-progress: Ship work item CLI/);
const closeResult = runNode(WORK_ITEMS_SCRIPT, ['close', 'linear-ecc-99', '--db', dbPath, '--json']);
assert.strictEqual(closeResult.status, 0, closeResult.stderr);
const closePayload = parseJson(closeResult.stdout);
assert.strictEqual(closePayload.status, 'done');
assert.strictEqual(closePayload.title, 'Ship work item CLI');
} finally {
cleanupTempDir(testDir);
}
})) passed += 1; else failed += 1;
if (await test('sessions CLI supports list and detail views in human-readable and --json output', async () => {
const testDir = createTempDir('ecc-state-cli-');
const dbPath = path.join(testDir, 'state.db');
@@ -729,7 +800,7 @@ async function runTests() {
}
})) passed += 1; else failed += 1;
if (await test('ecc CLI delegates the new status and sessions subcommands', async () => {
if (await test('ecc CLI delegates the new status, sessions, and work-items subcommands', async () => {
const testDir = createTempDir('ecc-state-cli-');
const dbPath = path.join(testDir, 'state.db');
@@ -746,6 +817,29 @@ async function runTests() {
const sessionsPayload = parseJson(sessionsResult.stdout);
assert.strictEqual(sessionsPayload.session.id, 'session-active');
assert.strictEqual(sessionsPayload.skillRuns.length, 2);
const workItemResult = runNode(ECC_SCRIPT, [
'work-items',
'upsert',
'handoff-roadmap',
'--db',
dbPath,
'--source',
'handoff',
'--title',
'Track roadmap handoff',
'--status',
'blocked',
'--json',
], { cwd: testDir });
assert.strictEqual(workItemResult.status, 0, workItemResult.stderr);
const workItemPayload = parseJson(workItemResult.stdout);
assert.strictEqual(workItemPayload.id, 'handoff-roadmap');
const delegatedStatusResult = runNode(ECC_SCRIPT, ['status', '--db', dbPath, '--json']);
assert.strictEqual(delegatedStatusResult.status, 0, delegatedStatusResult.stderr);
const delegatedStatusPayload = parseJson(delegatedStatusResult.stdout);
assert.strictEqual(delegatedStatusPayload.readiness.blockedWorkItems, 1);
} finally {
cleanupTempDir(testDir);
}

View File

@@ -71,6 +71,7 @@ function main() {
assert.match(result.stdout, /auto-update/);
assert.match(result.stdout, /consult/);
assert.match(result.stdout, /loop-status/);
assert.match(result.stdout, /work-items/);
}],
['delegates explicit install command', () => {
const result = runCli(['install', '--dry-run', '--json', 'typescript']);
@@ -201,6 +202,11 @@ function main() {
assert.strictEqual(result.status, 0, result.stderr);
assert.match(result.stdout, /node scripts\/consult\.js "security reviews"/);
}],
['supports help for the work-items subcommand', () => {
const result = runCli(['help', 'work-items']);
assert.strictEqual(result.status, 0, result.stderr);
assert.match(result.stdout, /node scripts\/work-items\.js upsert/);
}],
['fails on unknown commands instead of treating them as installs', () => {
const result = runCli(['bogus']);
assert.strictEqual(result.status, 1);

View File

@@ -48,6 +48,7 @@ function buildExpectedPublishPaths(repoRoot) {
"scripts/doctor.js",
"scripts/status.js",
"scripts/sessions-cli.js",
"scripts/work-items.js",
"scripts/install-apply.js",
"scripts/install-plan.js",
"scripts/list-installed.js",
@@ -110,6 +111,7 @@ function main() {
for (const requiredPath of [
"scripts/catalog.js",
"scripts/consult.js",
"scripts/work-items.js",
".gemini/GEMINI.md",
".qwen/QWEN.md",
".claude-plugin/plugin.json",