@llm-dev-ops/agentics-cli 2.5.3 → 2.6.0
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/dist/cli/index.js +334 -31
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/agents.d.ts +7 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +130 -23
- package/dist/commands/agents.js.map +1 -1
- package/dist/contracts/adr-command-semantics.d.ts.map +1 -1
- package/dist/contracts/adr-command-semantics.js +12 -0
- package/dist/contracts/adr-command-semantics.js.map +1 -1
- package/dist/errors/transient.d.ts +67 -0
- package/dist/errors/transient.d.ts.map +1 -0
- package/dist/errors/transient.js +260 -0
- package/dist/errors/transient.js.map +1 -0
- package/dist/gates/execution-gate.d.ts.map +1 -1
- package/dist/gates/execution-gate.js +11 -0
- package/dist/gates/execution-gate.js.map +1 -1
- package/dist/mcp/mcp-server.js +13 -1
- package/dist/mcp/mcp-server.js.map +1 -1
- package/dist/modules/command-parser.d.ts +1 -1
- package/dist/modules/command-parser.d.ts.map +1 -1
- package/dist/modules/command-parser.js +5 -0
- package/dist/modules/command-parser.js.map +1 -1
- package/dist/observability/degradations.d.ts +58 -0
- package/dist/observability/degradations.d.ts.map +1 -0
- package/dist/observability/degradations.js +74 -0
- package/dist/observability/degradations.js.map +1 -0
- package/dist/pipeline/phase1-verdict.d.ts +55 -0
- package/dist/pipeline/phase1-verdict.d.ts.map +1 -0
- package/dist/pipeline/phase1-verdict.js +186 -0
- package/dist/pipeline/phase1-verdict.js.map +1 -0
- package/dist/pipeline/phase2-preflight.d.ts +44 -0
- package/dist/pipeline/phase2-preflight.d.ts.map +1 -0
- package/dist/pipeline/phase2-preflight.js +120 -0
- package/dist/pipeline/phase2-preflight.js.map +1 -0
- package/dist/pipeline/swarm-orchestrator.d.ts.map +1 -1
- package/dist/pipeline/swarm-orchestrator.js +67 -5
- package/dist/pipeline/swarm-orchestrator.js.map +1 -1
- package/dist/synthesis/financial-claim-extractor.d.ts +11 -0
- package/dist/synthesis/financial-claim-extractor.d.ts.map +1 -1
- package/dist/synthesis/financial-claim-extractor.js +24 -0
- package/dist/synthesis/financial-claim-extractor.js.map +1 -1
- package/dist/synthesis/simulation-artifact-generator.d.ts.map +1 -1
- package/dist/synthesis/simulation-artifact-generator.js +28 -3
- package/dist/synthesis/simulation-artifact-generator.js.map +1 -1
- package/dist/synthesis/simulation-renderers.d.ts +1 -1
- package/dist/synthesis/simulation-renderers.d.ts.map +1 -1
- package/dist/synthesis/simulation-renderers.js +39 -13
- package/dist/synthesis/simulation-renderers.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1842,51 +1842,173 @@ async function main() {
|
|
|
1842
1842
|
// Auto-chain Phases 2-6: each phase builds on the previous phase's output
|
|
1843
1843
|
let chainResult = null;
|
|
1844
1844
|
if (routeResult.kind === 'multi') {
|
|
1845
|
-
//
|
|
1846
|
-
//
|
|
1847
|
-
//
|
|
1848
|
-
|
|
1845
|
+
// ADR-PIPELINE-089 §3: gate auto-chain on the Phase 1 Health
|
|
1846
|
+
// Gate verdict, not just whether the simulator intent returned
|
|
1847
|
+
// without an error field. The verdict classifier looks at the
|
|
1848
|
+
// simulator outcome AND agent error ratio AND artifact presence
|
|
1849
|
+
// AND degradation sink entries (tag-survival, consensus, sector,
|
|
1850
|
+
// local fallbacks), so we catch "it technically succeeded but
|
|
1851
|
+
// produced nothing useful" — the user's actual symptom.
|
|
1852
|
+
const verdict = routeResult.result.phase1Verdict;
|
|
1853
|
+
const verdictKind = verdict?.verdict ?? 'healthy'; // default healthy if older caller path
|
|
1849
1854
|
const hasSimIntent = routeResult.result.intents.some((i) => i.domain === 'simulator' && i.agent === 'enterprise');
|
|
1850
|
-
if (
|
|
1851
|
-
// Simulation was dispatched but failed — surface the error prominently
|
|
1852
|
-
const simError = routeResult.result.invocations.find((i) => i.intent.domain === 'simulator' && i.intent.agent === 'enterprise');
|
|
1853
|
-
const errDetail = simError ? simError.result.error ?? 'unknown error' : 'not dispatched';
|
|
1855
|
+
if (verdictKind === 'failed' && hasSimIntent) {
|
|
1854
1856
|
console.error('');
|
|
1855
1857
|
console.error('='.repeat(72));
|
|
1856
|
-
console.error('
|
|
1858
|
+
console.error(' PHASE 1 FAILED — Phases 2-6 skipped');
|
|
1857
1859
|
console.error('='.repeat(72));
|
|
1858
|
-
console.error(`
|
|
1860
|
+
console.error(` Reason: ${verdict?.reason ?? 'unknown failure'}`);
|
|
1861
|
+
if (verdict && verdict.degradations.length > 0) {
|
|
1862
|
+
console.error('');
|
|
1863
|
+
console.error(' Degradations:');
|
|
1864
|
+
for (const d of verdict.degradations) {
|
|
1865
|
+
console.error(` · [${d.code}] ${d.message}`);
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1859
1868
|
console.error('');
|
|
1860
|
-
console.error('
|
|
1861
|
-
console.error(' Phases 2-6 require simulation artifacts to build on.');
|
|
1869
|
+
console.error(' Phases 2-6 require a healthy Phase 1 to build on.');
|
|
1862
1870
|
console.error('');
|
|
1863
1871
|
console.error(' To retry:');
|
|
1864
1872
|
console.error(` agentics ask "${nlQuery}"`);
|
|
1865
1873
|
console.error('');
|
|
1866
1874
|
}
|
|
1867
|
-
if (
|
|
1875
|
+
if (verdictKind === 'degraded') {
|
|
1876
|
+
// Auto-chain still proceeds on degraded — the user may want
|
|
1877
|
+
// partial output — but we surface the specific degradations
|
|
1878
|
+
// prominently so they can judge whether to re-run instead.
|
|
1868
1879
|
console.error('');
|
|
1869
|
-
console.error('
|
|
1870
|
-
console.error('
|
|
1871
|
-
console.error('
|
|
1880
|
+
console.error('='.repeat(72));
|
|
1881
|
+
console.error(' PHASE 1 DEGRADED — proceeding to Phases 2-6 with caveats');
|
|
1882
|
+
console.error('='.repeat(72));
|
|
1883
|
+
console.error(` ${verdict?.reason ?? 'partial success'}`);
|
|
1884
|
+
if (verdict && verdict.degradations.length > 0) {
|
|
1885
|
+
for (const d of verdict.degradations) {
|
|
1886
|
+
console.error(` · [${d.code}] ${d.message}`);
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1872
1889
|
console.error('');
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1890
|
+
}
|
|
1891
|
+
if (verdictKind !== 'failed') {
|
|
1892
|
+
// ADR-PIPELINE-088: under MCP mode, detach the auto-chain into a
|
|
1893
|
+
// background subprocess so the tool call returns within Claude
|
|
1894
|
+
// Code's MCP client-side timeout. Auto-chain phases can take
|
|
1895
|
+
// 30-60 minutes (ruflo swarm start has a 15-minute per-phase
|
|
1896
|
+
// budget) which is far longer than the MCP client will wait.
|
|
1897
|
+
// Shell invocations keep the original inline behaviour.
|
|
1898
|
+
const mcpMode = process.env['MCP_SERVER_MODE'] === '1';
|
|
1899
|
+
const traceId = options.trace_id;
|
|
1900
|
+
if (mcpMode) {
|
|
1901
|
+
try {
|
|
1902
|
+
const { spawn } = await import('node:child_process');
|
|
1903
|
+
const fsMod = await import('node:fs');
|
|
1904
|
+
const pathMod = await import('node:path');
|
|
1905
|
+
const os = await import('node:os');
|
|
1906
|
+
const runDir = pathMod.join(os.homedir(), '.agentics', 'runs', traceId);
|
|
1907
|
+
fsMod.mkdirSync(runDir, { recursive: true, mode: 0o700 });
|
|
1908
|
+
const logPath = pathMod.join(runDir, 'autochain.log');
|
|
1909
|
+
const statusPath = pathMod.join(runDir, 'status.json');
|
|
1910
|
+
const plansDir = pathMod.join(process.cwd(), '.agentics', 'plans');
|
|
1911
|
+
// CLI_ENTRY must be the same dist/cli/index.js that is
|
|
1912
|
+
// running us — __filename-equivalent in ESM.
|
|
1913
|
+
const selfPath = new URL(import.meta.url).pathname;
|
|
1914
|
+
const logFd = fsMod.openSync(logPath, 'a');
|
|
1915
|
+
const child = spawn(process.execPath, [selfPath, '_autochain', traceId], {
|
|
1916
|
+
detached: true,
|
|
1917
|
+
stdio: ['ignore', logFd, logFd],
|
|
1918
|
+
// Clear MCP_SERVER_MODE on the child so it uses the inline
|
|
1919
|
+
// auto-chain path (the whole point of spawning it is to
|
|
1920
|
+
// let it run the full pipeline without timing out).
|
|
1921
|
+
env: { ...process.env, MCP_SERVER_MODE: '', AGENTICS_AUTOCHAIN_TRACE: traceId },
|
|
1922
|
+
cwd: process.cwd(),
|
|
1923
|
+
});
|
|
1924
|
+
child.unref();
|
|
1925
|
+
fsMod.closeSync(logFd);
|
|
1926
|
+
// Write an initial status record so `agentics status <id>`
|
|
1927
|
+
// has something to read before the child updates it.
|
|
1928
|
+
// ADR-PIPELINE-089 §6: seed Phase 1 verdict fields so the
|
|
1929
|
+
// status tool can surface HEALTHY / DEGRADED / FAILED plus
|
|
1930
|
+
// the specific degradation list on the very first poll.
|
|
1931
|
+
const phase1V = routeResult.result.phase1Verdict;
|
|
1932
|
+
const initialStatus = {
|
|
1933
|
+
traceId,
|
|
1934
|
+
pid: child.pid ?? null,
|
|
1935
|
+
startedAt: new Date().toISOString(),
|
|
1936
|
+
mode: 'mcp-fast-return',
|
|
1937
|
+
phase: 0,
|
|
1938
|
+
inProgress: true,
|
|
1939
|
+
completedPhases: [],
|
|
1940
|
+
logPath,
|
|
1941
|
+
plansDir,
|
|
1942
|
+
artifacts: {},
|
|
1943
|
+
phase1_verdict: phase1V?.verdict ?? null,
|
|
1944
|
+
phase1_reason: phase1V?.reason ?? null,
|
|
1945
|
+
phase1_degradations: phase1V?.degradations ?? [],
|
|
1946
|
+
phase1_stats: phase1V?.stats ?? null,
|
|
1947
|
+
};
|
|
1948
|
+
fsMod.writeFileSync(statusPath, JSON.stringify(initialStatus, null, 2), { encoding: 'utf-8', mode: 0o600 });
|
|
1949
|
+
// Emit structured markers so the MCP tool handler (and
|
|
1950
|
+
// downstream Claude Code consumers) can parse them out of
|
|
1951
|
+
// stdout without needing a second JSON-RPC round-trip.
|
|
1952
|
+
console.log('');
|
|
1953
|
+
console.log(`AGENTICS_TRACE_ID=${traceId}`);
|
|
1954
|
+
console.log('AGENTICS_AUTOCHAIN_STATUS=background');
|
|
1955
|
+
console.log(`AGENTICS_AUTOCHAIN_PID=${child.pid ?? ''}`);
|
|
1956
|
+
console.log(`AGENTICS_AUTOCHAIN_LOG=${logPath}`);
|
|
1957
|
+
console.log(`AGENTICS_AUTOCHAIN_STATUS_FILE=${statusPath}`);
|
|
1958
|
+
console.log(`AGENTICS_PLANS_DIR=${plansDir}`);
|
|
1959
|
+
// ADR-PIPELINE-089 §2: surface Phase 1 verdict as a
|
|
1960
|
+
// structured marker so the MCP tool wrapper (and any
|
|
1961
|
+
// log-grepping relay) can read it without parsing the
|
|
1962
|
+
// status file. Count only — the full degradation list is
|
|
1963
|
+
// in status.json.
|
|
1964
|
+
if (phase1V) {
|
|
1965
|
+
console.log(`AGENTICS_PHASE1_VERDICT=${phase1V.verdict}`);
|
|
1966
|
+
console.log(`AGENTICS_PHASE1_DEGRADATIONS=${phase1V.degradations.length}`);
|
|
1967
|
+
}
|
|
1968
|
+
console.log('');
|
|
1969
|
+
console.log('Phases 2-6 are running in the background. Poll with:');
|
|
1970
|
+
console.log(` agentics status ${traceId}`);
|
|
1971
|
+
console.log('ADR-PIPELINE-088.');
|
|
1972
|
+
}
|
|
1973
|
+
catch (detachErr) {
|
|
1974
|
+
const errMsg = detachErr instanceof Error ? detachErr.message : String(detachErr);
|
|
1975
|
+
console.error(`[WARN] MCP fast-return detach failed: ${errMsg}. Falling back to inline auto-chain.`);
|
|
1976
|
+
// Fall through to the inline path below by setting a flag.
|
|
1977
|
+
// We intentionally do not throw — better to block the MCP
|
|
1978
|
+
// call than to lose auto-chain entirely.
|
|
1979
|
+
try {
|
|
1980
|
+
const { executeAutoChain, formatAutoChainForDisplay } = await import('../pipeline/auto-chain.js');
|
|
1981
|
+
chainResult = await executeAutoChain(traceId, { verbose: options.verbose });
|
|
1982
|
+
if (chainResult && options.format !== 'json') {
|
|
1983
|
+
console.log(formatAutoChainForDisplay(chainResult));
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
catch (chainErr) {
|
|
1987
|
+
console.error(`\nAuto-chain pipeline error: ${chainErr instanceof Error ? chainErr.message : String(chainErr)}`);
|
|
1988
|
+
}
|
|
1882
1989
|
}
|
|
1883
1990
|
}
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
console.error(
|
|
1888
|
-
|
|
1889
|
-
|
|
1991
|
+
else {
|
|
1992
|
+
console.error('');
|
|
1993
|
+
console.error('Auto-chaining Phases 2-6 (each phase builds on the previous)...');
|
|
1994
|
+
console.error(' Phase 1 (109 agents + ruvector simulation) complete. Starting sequential pipeline:');
|
|
1995
|
+
console.error(' Phase 2: Deep Research → Phase 3: SPARC+TDD → Phase 4: ADRs/DDDs → Phase 5: Build (ruflo) → Phase 6: ERP Push');
|
|
1996
|
+
console.error('');
|
|
1997
|
+
try {
|
|
1998
|
+
const { executeAutoChain, formatAutoChainForDisplay } = await import('../pipeline/auto-chain.js');
|
|
1999
|
+
chainResult = await executeAutoChain(traceId, {
|
|
2000
|
+
verbose: options.verbose,
|
|
2001
|
+
});
|
|
2002
|
+
if (chainResult && options.format !== 'json') {
|
|
2003
|
+
console.log(formatAutoChainForDisplay(chainResult));
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
catch (chainErr) {
|
|
2007
|
+
const errMsg = chainErr instanceof Error ? chainErr.message : String(chainErr);
|
|
2008
|
+
console.error(`\nAuto-chain pipeline error: ${errMsg}`);
|
|
2009
|
+
if (chainErr instanceof Error && chainErr.stack) {
|
|
2010
|
+
console.error(chainErr.stack);
|
|
2011
|
+
}
|
|
1890
2012
|
}
|
|
1891
2013
|
}
|
|
1892
2014
|
}
|
|
@@ -1944,6 +2066,187 @@ async function main() {
|
|
|
1944
2066
|
throw error;
|
|
1945
2067
|
}
|
|
1946
2068
|
}
|
|
2069
|
+
// ADR-PIPELINE-088 §3: hidden helper command invoked by the MCP
|
|
2070
|
+
// fast-return path. Runs executeAutoChain for an existing trace id
|
|
2071
|
+
// (phase 1 artifacts already on disk) with stdio attached to the log
|
|
2072
|
+
// file the parent opened. NOT listed in help.
|
|
2073
|
+
case '_autochain': {
|
|
2074
|
+
const traceId = parsed.subcommand ?? parsed.positionalArgs[0];
|
|
2075
|
+
if (!traceId) {
|
|
2076
|
+
console.error('Usage (internal): agentics _autochain <traceId>');
|
|
2077
|
+
process.exit(EXIT_CODES.USAGE_ERROR);
|
|
2078
|
+
}
|
|
2079
|
+
try {
|
|
2080
|
+
const fsMod = await import('node:fs');
|
|
2081
|
+
const pathMod = await import('node:path');
|
|
2082
|
+
const os = await import('node:os');
|
|
2083
|
+
const runDir = pathMod.join(os.homedir(), '.agentics', 'runs', traceId);
|
|
2084
|
+
const statusPath = pathMod.join(runDir, 'status.json');
|
|
2085
|
+
const updateStatus = (patch) => {
|
|
2086
|
+
try {
|
|
2087
|
+
const current = fsMod.existsSync(statusPath)
|
|
2088
|
+
? JSON.parse(fsMod.readFileSync(statusPath, 'utf-8'))
|
|
2089
|
+
: {};
|
|
2090
|
+
const merged = { ...current, ...patch, updatedAt: new Date().toISOString() };
|
|
2091
|
+
const tmp = statusPath + '.tmp';
|
|
2092
|
+
fsMod.writeFileSync(tmp, JSON.stringify(merged, null, 2), { encoding: 'utf-8', mode: 0o600 });
|
|
2093
|
+
fsMod.renameSync(tmp, statusPath);
|
|
2094
|
+
}
|
|
2095
|
+
catch { /* non-fatal */ }
|
|
2096
|
+
};
|
|
2097
|
+
updateStatus({ phase: 2, inProgress: true, startedAutoChainAt: new Date().toISOString() });
|
|
2098
|
+
const { executeAutoChain } = await import('../pipeline/auto-chain.js');
|
|
2099
|
+
const chainResult = await executeAutoChain(traceId, { verbose: false });
|
|
2100
|
+
updateStatus({
|
|
2101
|
+
phase: 6,
|
|
2102
|
+
inProgress: false,
|
|
2103
|
+
completedAt: new Date().toISOString(),
|
|
2104
|
+
exitCode: 0,
|
|
2105
|
+
chainResult: chainResult ?? null,
|
|
2106
|
+
});
|
|
2107
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
2108
|
+
}
|
|
2109
|
+
catch (err) {
|
|
2110
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
2111
|
+
console.error(`_autochain failed for ${traceId}: ${errMsg}`);
|
|
2112
|
+
try {
|
|
2113
|
+
const fsMod = await import('node:fs');
|
|
2114
|
+
const pathMod = await import('node:path');
|
|
2115
|
+
const os = await import('node:os');
|
|
2116
|
+
const statusPath = pathMod.join(os.homedir(), '.agentics', 'runs', traceId, 'status.json');
|
|
2117
|
+
const current = fsMod.existsSync(statusPath)
|
|
2118
|
+
? JSON.parse(fsMod.readFileSync(statusPath, 'utf-8'))
|
|
2119
|
+
: {};
|
|
2120
|
+
const merged = { ...current, inProgress: false, failedAt: new Date().toISOString(), error: errMsg };
|
|
2121
|
+
fsMod.writeFileSync(statusPath, JSON.stringify(merged, null, 2), { encoding: 'utf-8', mode: 0o600 });
|
|
2122
|
+
}
|
|
2123
|
+
catch { /* ignore */ }
|
|
2124
|
+
process.exit(EXIT_CODES.INTERNAL_CLI_ERROR);
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
// ADR-PIPELINE-088 §4: public status command. Reports phase completion
|
|
2128
|
+
// of a running or completed agentics-ask background pipeline.
|
|
2129
|
+
case 'status': {
|
|
2130
|
+
const traceId = parsed.subcommand ?? parsed.positionalArgs[0];
|
|
2131
|
+
if (!traceId) {
|
|
2132
|
+
console.error('Usage: agentics status <traceId>');
|
|
2133
|
+
console.error('');
|
|
2134
|
+
console.error('The trace id is emitted as AGENTICS_TRACE_ID=... by agentics-ask under MCP.');
|
|
2135
|
+
process.exit(EXIT_CODES.USAGE_ERROR);
|
|
2136
|
+
}
|
|
2137
|
+
try {
|
|
2138
|
+
const fsMod = await import('node:fs');
|
|
2139
|
+
const pathMod = await import('node:path');
|
|
2140
|
+
const os = await import('node:os');
|
|
2141
|
+
const runDir = pathMod.join(os.homedir(), '.agentics', 'runs', traceId);
|
|
2142
|
+
const statusPath = pathMod.join(runDir, 'status.json');
|
|
2143
|
+
if (!fsMod.existsSync(statusPath)) {
|
|
2144
|
+
console.error(`No status file for trace id ${traceId} at ${statusPath}`);
|
|
2145
|
+
process.exit(EXIT_CODES.CANNOT_OPEN_INPUT);
|
|
2146
|
+
}
|
|
2147
|
+
const status = JSON.parse(fsMod.readFileSync(statusPath, 'utf-8'));
|
|
2148
|
+
// Liveness: if status claims in-progress but the pid is dead, mark crashed.
|
|
2149
|
+
let liveness = 'unknown';
|
|
2150
|
+
const pid = status['pid'];
|
|
2151
|
+
const inProgress = status['inProgress'] === true;
|
|
2152
|
+
if (!inProgress) {
|
|
2153
|
+
liveness = status['failedAt'] ? 'crashed' : 'done';
|
|
2154
|
+
}
|
|
2155
|
+
else if (pid) {
|
|
2156
|
+
try {
|
|
2157
|
+
process.kill(pid, 0); // signal 0 = liveness probe, no kill
|
|
2158
|
+
liveness = 'running';
|
|
2159
|
+
}
|
|
2160
|
+
catch {
|
|
2161
|
+
liveness = 'crashed';
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
// Artifact paths on disk — authoritative completion signal per the ADR.
|
|
2165
|
+
const plansDir = status['plansDir']
|
|
2166
|
+
?? pathMod.join(process.cwd(), '.agentics', 'plans');
|
|
2167
|
+
const artifactSummary = {};
|
|
2168
|
+
for (const sub of ['adrs', 'ddd', 'sparc', 'tdd', 'prompts']) {
|
|
2169
|
+
const subDir = pathMod.join(plansDir, sub);
|
|
2170
|
+
try {
|
|
2171
|
+
artifactSummary[sub] = fsMod.existsSync(subDir)
|
|
2172
|
+
? fsMod.readdirSync(subDir).length
|
|
2173
|
+
: 0;
|
|
2174
|
+
}
|
|
2175
|
+
catch {
|
|
2176
|
+
artifactSummary[sub] = 0;
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
const report = {
|
|
2180
|
+
traceId,
|
|
2181
|
+
liveness,
|
|
2182
|
+
phase: status['phase'] ?? 0,
|
|
2183
|
+
inProgress,
|
|
2184
|
+
startedAt: status['startedAt'] ?? null,
|
|
2185
|
+
updatedAt: status['updatedAt'] ?? null,
|
|
2186
|
+
completedAt: status['completedAt'] ?? null,
|
|
2187
|
+
failedAt: status['failedAt'] ?? null,
|
|
2188
|
+
error: status['error'] ?? null,
|
|
2189
|
+
logPath: status['logPath'] ?? null,
|
|
2190
|
+
plansDir,
|
|
2191
|
+
artifacts: artifactSummary,
|
|
2192
|
+
// ADR-PIPELINE-089 §6: pass Phase 1 verdict + Phase 2 preflight
|
|
2193
|
+
// through verbatim. Null-safe so runs predating 089 still report.
|
|
2194
|
+
phase1_verdict: status['phase1_verdict'] ?? null,
|
|
2195
|
+
phase1_reason: status['phase1_reason'] ?? null,
|
|
2196
|
+
phase1_degradations: status['phase1_degradations'] ?? [],
|
|
2197
|
+
phase1_stats: status['phase1_stats'] ?? null,
|
|
2198
|
+
phase2_preflight: status['phase2_preflight'] ?? null,
|
|
2199
|
+
};
|
|
2200
|
+
if (options.format === 'json') {
|
|
2201
|
+
console.log(JSON.stringify(report, null, parsed.flags['pretty'] ? 2 : 0));
|
|
2202
|
+
}
|
|
2203
|
+
else {
|
|
2204
|
+
console.log(`Trace id: ${report.traceId}`);
|
|
2205
|
+
console.log(`Liveness: ${report.liveness}`);
|
|
2206
|
+
console.log(`Phase: ${report.phase}${report.inProgress ? ' (in progress)' : ' (done)'}`);
|
|
2207
|
+
if (report.startedAt)
|
|
2208
|
+
console.log(`Started: ${report.startedAt}`);
|
|
2209
|
+
if (report.updatedAt)
|
|
2210
|
+
console.log(`Updated: ${report.updatedAt}`);
|
|
2211
|
+
if (report.completedAt)
|
|
2212
|
+
console.log(`Completed: ${report.completedAt}`);
|
|
2213
|
+
if (report.failedAt)
|
|
2214
|
+
console.log(`Failed: ${report.failedAt}`);
|
|
2215
|
+
if (report.error)
|
|
2216
|
+
console.log(`Error: ${report.error}`);
|
|
2217
|
+
console.log(`Logs: ${report.logPath ?? '(none)'}`);
|
|
2218
|
+
console.log(`Plans dir: ${report.plansDir}`);
|
|
2219
|
+
// ADR-PIPELINE-089 §6: verdict + preflight in the text report.
|
|
2220
|
+
if (report.phase1_verdict) {
|
|
2221
|
+
const v = String(report.phase1_verdict).toUpperCase();
|
|
2222
|
+
console.log(`Phase 1: ${v}${report.phase1_reason ? ' — ' + report.phase1_reason : ''}`);
|
|
2223
|
+
const degs = report.phase1_degradations;
|
|
2224
|
+
for (const d of degs) {
|
|
2225
|
+
console.log(` · [${d.code}] ${d.message}`);
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
const pf = report.phase2_preflight;
|
|
2229
|
+
if (pf) {
|
|
2230
|
+
console.log(`Phase 2 pre: ${pf.healthy.length}/${pf.probed} backends healthy (${pf.verdict})`);
|
|
2231
|
+
if (pf.unhealthy.length > 0) {
|
|
2232
|
+
console.log(` unhealthy: ${pf.unhealthy.join(', ')}`);
|
|
2233
|
+
}
|
|
2234
|
+
if (pf.skipped.length > 0) {
|
|
2235
|
+
console.log(` skipped: ${pf.skipped.join(', ')}`);
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
console.log('Artifacts:');
|
|
2239
|
+
for (const [k, n] of Object.entries(artifactSummary)) {
|
|
2240
|
+
console.log(` ${k.padEnd(8)} ${n} files`);
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2243
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
2244
|
+
}
|
|
2245
|
+
catch (err) {
|
|
2246
|
+
console.error(`status failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2247
|
+
process.exit(EXIT_CODES.INTERNAL_CLI_ERROR);
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
1947
2250
|
default: {
|
|
1948
2251
|
// Before failing, attempt NL routing for unrecognized multi-word input
|
|
1949
2252
|
const nlParts = [parsed.command];
|