feat: add status exit code gate

This commit is contained in:
Affaan Mustafa 2026-05-11 12:27:06 -04:00 committed by Affaan Mustafa
parent b1e67788f7
commit 9887ba6123
4 changed files with 40 additions and 2 deletions

View File

@ -94,7 +94,7 @@ This repo is the raw code only. The guides explain everything.
- **Media and launch tooling**`manim-video`, `remotion-video-creation`, and upgraded social publishing surfaces make technical explainers and launch content part of the same system. - **Media and launch tooling**`manim-video`, `remotion-video-creation`, and upgraded social publishing surfaces make technical explainers and launch content part of the same system.
- **Framework and product surface growth**`nestjs-patterns`, richer Codex/OpenCode install surfaces, and expanded cross-harness packaging keep the repo usable beyond Claude Code alone. - **Framework and product surface growth**`nestjs-patterns`, richer Codex/OpenCode install surfaces, and expanded cross-harness packaging keep the repo usable beyond Claude Code alone.
- **ECC 2.0 alpha is in-tree** — the Rust control-plane prototype in `ecc2/` now builds locally and exposes `dashboard`, `start`, `sessions`, `status`, `stop`, `resume`, and `daemon` commands. It is usable as an alpha, not yet a general release. - **ECC 2.0 alpha is in-tree** — the Rust control-plane prototype in `ecc2/` now builds locally and exposes `dashboard`, `start`, `sessions`, `status`, `stop`, `resume`, and `daemon` commands. It is usable as an alpha, not yet a general release.
- **Operator status snapshots**`ecc status --markdown --write status.md` turns the local state store into a portable handoff covering readiness, active sessions, skill-run health, install health, pending governance events, and linked work items from Linear/GitHub/handoffs. Use `ecc work-items upsert ...` to add or update those linked work items from the CLI. - **Operator status snapshots**`ecc status --markdown --write status.md` turns the local state store into a portable handoff covering readiness, active sessions, skill-run health, install health, pending governance events, and linked work items from Linear/GitHub/handoffs. Use `ecc work-items upsert ...` to add or update those linked work items from the CLI, and `ecc status --exit-code` to fail automation when readiness needs attention.
- **Ecosystem hardening** — AgentShield, ECC Tools cost controls, billing portal work, and website refreshes continue to ship around the core plugin instead of drifting into separate silos. - **Ecosystem hardening** — AgentShield, ECC Tools cost controls, billing portal work, and website refreshes continue to ship around the core plugin instead of drifting into separate silos.
### v1.9.0 — Selective Install & Language Expansion (Mar 2026) ### v1.9.0 — Selective Install & Language Expansion (Mar 2026)

View File

@ -113,6 +113,7 @@ Examples:
ecc repair --dry-run ecc repair --dry-run
ecc auto-update --dry-run ecc auto-update --dry-run
ecc status --json ecc status --json
ecc status --exit-code
ecc status --markdown --write status.md ecc status --markdown --write status.md
ecc sessions ecc sessions
ecc sessions session-active --json ecc sessions session-active --json

View File

@ -8,10 +8,12 @@ const { createStateStore } = require('./lib/state-store');
function showHelp(exitCode = 0) { function showHelp(exitCode = 0) {
console.log(` console.log(`
Usage: node scripts/status.js [--db <path>] [--json|--markdown] [--write <path>] [--limit <n>] Usage: node scripts/status.js [--db <path>] [--json|--markdown] [--write <path>] [--limit <n>] [--exit-code]
Query the ECC SQLite state store for active sessions, recent skill runs, Query the ECC SQLite state store for active sessions, recent skill runs,
install health, pending governance events, and linked work items. install health, pending governance events, and linked work items.
Use --exit-code to return 2 when readiness needs attention.
`); `);
process.exit(exitCode); process.exit(exitCode);
} }
@ -23,6 +25,7 @@ function parseArgs(argv) {
json: false, json: false,
markdown: false, markdown: false,
writePath: null, writePath: null,
exitCode: false,
help: false, help: false,
limit: 5, limit: 5,
}; };
@ -37,6 +40,8 @@ function parseArgs(argv) {
parsed.json = true; parsed.json = true;
} else if (arg === '--markdown') { } else if (arg === '--markdown') {
parsed.markdown = true; parsed.markdown = true;
} else if (arg === '--exit-code') {
parsed.exitCode = true;
} else if (arg === '--write') { } else if (arg === '--write') {
parsed.writePath = args[index + 1] || null; parsed.writePath = args[index + 1] || null;
index += 1; index += 1;
@ -364,6 +369,10 @@ async function main() {
} }
printHuman(payload); printHuman(payload);
} }
if (options.exitCode && payload.readiness.status !== 'ok') {
process.exitCode = 2;
}
} catch (error) { } catch (error) {
console.error(`Error: ${error.message}`); console.error(`Error: ${error.message}`);
process.exit(1); process.exit(1);

View File

@ -667,6 +667,34 @@ async function runTests() {
} }
})) passed += 1; else failed += 1; })) passed += 1; else failed += 1;
if (await test('status CLI --exit-code reports attention without suppressing output', async () => {
const attentionDir = createTempDir('ecc-state-attention-');
const okDir = createTempDir('ecc-state-ok-');
const attentionDbPath = path.join(attentionDir, 'state.db');
const okDbPath = path.join(okDir, 'state.db');
try {
await seedStore(attentionDbPath);
const attentionResult = runNode(STATUS_SCRIPT, ['--db', attentionDbPath, '--json', '--exit-code']);
assert.strictEqual(attentionResult.status, 2, attentionResult.stderr);
const attentionPayload = parseJson(attentionResult.stdout);
assert.strictEqual(attentionPayload.readiness.status, 'attention');
assert.strictEqual(attentionPayload.readiness.attentionCount, 2);
const okStore = await createStateStore({ dbPath: okDbPath });
okStore.close();
const okResult = runNode(STATUS_SCRIPT, ['--db', okDbPath, '--json', '--exit-code']);
assert.strictEqual(okResult.status, 0, okResult.stderr);
const okPayload = parseJson(okResult.stdout);
assert.strictEqual(okPayload.readiness.status, 'ok');
} finally {
cleanupTempDir(attentionDir);
cleanupTempDir(okDir);
}
})) passed += 1; else failed += 1;
if (await test('status CLI can emit and write markdown operator snapshots', async () => { if (await test('status CLI can emit and write markdown operator snapshots', async () => {
const testDir = createTempDir('ecc-state-cli-'); const testDir = createTempDir('ecc-state-cli-');
const dbPath = path.join(testDir, 'state.db'); const dbPath = path.join(testDir, 'state.db');