@voiden/runner 2.3.0-beta.8 → 2.3.0-beta.9

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.
@@ -0,0 +1,7 @@
1
+ import type { RunResult } from './types.js';
2
+ export declare function printRequestResult(result: RunResult, filePath: string, index: number, total: number, showReq: boolean, showRes: boolean, verbose: boolean): void;
3
+ export declare function printRunSummary(results: Array<{
4
+ file: string;
5
+ result: RunResult;
6
+ }>, totalMs: number): void;
7
+ //# sourceMappingURL=cliPrint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cliPrint.d.ts","sourceRoot":"","sources":["../src/cliPrint.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,YAAY,CAAA;AA8E3D,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,GACf,IAAI,CAmEN;AAID,wBAAgB,eAAe,CAC7B,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC,EACnD,OAAO,EAAE,MAAM,GACd,IAAI,CAkBN"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Shared CLI pretty-printing for a single request's RunResult — the
3
+ * per-request "[i/n] file METHOD url status time", --show-req/--show-res
4
+ * detail, and report-entry (assertions/logs/sections) rendering.
5
+ *
6
+ * Lives here (not left private inside index.ts) so both @voiden/runner's
7
+ * own `run`/`mcp serve` CLI and apps/electron's bundled `voiden run` render
8
+ * identical output — one implementation, not two copies that can drift.
9
+ */
10
+ import chalk from 'chalk';
11
+ import { basename } from 'path';
12
+ function formatBytes(bytes) {
13
+ if (bytes < 1024)
14
+ return `${bytes}B`;
15
+ if (bytes < 1024 * 1024)
16
+ return `${(bytes / 1024).toFixed(1)}KB`;
17
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
18
+ }
19
+ function formatDuration(ms) {
20
+ if (ms < 1000)
21
+ return `${ms}ms`;
22
+ return `${(ms / 1000).toFixed(2)}s`;
23
+ }
24
+ function renderReportEntries(entries, verbose) {
25
+ const assertions = entries.filter(e => e.type === 'assertion');
26
+ const logs = entries.filter(e => e.type === 'log');
27
+ const sections = entries.filter(e => e.type === 'section');
28
+ // Assertions — always shown (mirrors the test panel in the app)
29
+ if (assertions.length > 0) {
30
+ const passed = assertions.filter(e => e.type === 'assertion' && e.passed).length;
31
+ const failed = assertions.length - passed;
32
+ console.log(` assertions: ${chalk.green(`${passed} passed`)}` +
33
+ (failed > 0 ? chalk.red(` · ${failed} failed`) : ''));
34
+ for (const e of assertions) {
35
+ if (e.type !== 'assertion')
36
+ continue;
37
+ const icon = e.passed ? chalk.green(' ✓') : chalk.red(' ✗');
38
+ let line = ` ${icon} ${e.message}`;
39
+ if (!e.passed && e.actual !== undefined && e.expected !== undefined) {
40
+ line += chalk.gray(` (got ${JSON.stringify(e.actual)}, expected ${e.operator ?? '=='} ${JSON.stringify(e.expected)})`);
41
+ }
42
+ console.log(line);
43
+ }
44
+ }
45
+ // Script logs — only shown in verbose mode (same as app behaviour: logs visible in console panel)
46
+ if (verbose && logs.length > 0) {
47
+ const levelIcon = {
48
+ info: chalk.blue('ℹ'),
49
+ debug: chalk.gray('•'),
50
+ warn: chalk.yellow('⚠'),
51
+ error: chalk.red('✗'),
52
+ log: chalk.gray('·'),
53
+ };
54
+ for (const e of logs) {
55
+ if (e.type !== 'log')
56
+ continue;
57
+ const icon = (e.level ? levelIcon[e.level] : undefined) ?? chalk.gray('·');
58
+ console.log(chalk.gray(` ${icon} ${e.message}`));
59
+ }
60
+ }
61
+ // Section titles — shown when verbose, useful for grouping named test blocks
62
+ if (verbose) {
63
+ for (const e of sections) {
64
+ if (e.type !== 'section')
65
+ continue;
66
+ console.log(chalk.bold.gray(` ── ${e.title} ──`));
67
+ }
68
+ }
69
+ }
70
+ function printKeyValue(label, obj) {
71
+ if (!obj || Object.keys(obj).length === 0)
72
+ return;
73
+ console.log(chalk.gray(` ${label}:`));
74
+ for (const [k, v] of Object.entries(obj)) {
75
+ console.log(chalk.gray(` ${chalk.dim(k + ':')} ${v}`));
76
+ }
77
+ }
78
+ function printBody(label, body) {
79
+ if (!body)
80
+ return;
81
+ console.log(chalk.gray(` ${label}:`));
82
+ for (const line of body.split('\n')) {
83
+ console.log(chalk.gray(` ${line}`));
84
+ }
85
+ }
86
+ export function printRequestResult(result, filePath, index, total, showReq, showRes, verbose) {
87
+ const icon = result.success ? chalk.green(' ✓') : chalk.red(' ✗');
88
+ const counter = chalk.gray(`[${index}/${total}]`);
89
+ const fileName = chalk.bold(basename(filePath));
90
+ console.log();
91
+ console.log(`${counter} ${fileName}`);
92
+ const proto = chalk.cyan(result.protocol.toUpperCase().padEnd(4));
93
+ const method = result.method ? chalk.bold(result.method.padEnd(6)) + ' ' : ' ';
94
+ const url = chalk.underline(result.url || '—');
95
+ const time = chalk.gray(formatDuration(result.durationMs));
96
+ let statusPart = '';
97
+ if (result.status !== undefined) {
98
+ const statusColor = result.success ? chalk.green : chalk.red;
99
+ statusPart = statusColor(` ${result.status} ${result.statusText ?? ''}`);
100
+ }
101
+ else if (result.connected !== undefined) {
102
+ statusPart = result.connected
103
+ ? chalk.green(' Connected')
104
+ : chalk.red(' Failed to connect');
105
+ }
106
+ let sizePart = '';
107
+ if (result.size !== undefined) {
108
+ sizePart = chalk.gray(` ${formatBytes(result.size)}`);
109
+ }
110
+ console.log(`${icon} ${proto} ${method}${url}${statusPart} ${time}${sizePart}`);
111
+ // ── Always show request details on failure (helps debug "fetch failed") ────
112
+ if (!result.success) {
113
+ if (result.error)
114
+ console.log(chalk.red(` ${result.error}`));
115
+ console.log(chalk.gray(' ↳ request sent:'));
116
+ console.log(chalk.gray(` url: ${result.url || '—'}`));
117
+ if (result.method)
118
+ console.log(chalk.gray(` method: ${result.method}`));
119
+ printKeyValue('headers', result.requestHeaders);
120
+ if (result.requestBody)
121
+ printBody('body', result.requestBody);
122
+ }
123
+ // ── Report entries (emitted by plugins) ───────────────────────────────────
124
+ if (result.reportEntries && result.reportEntries.length > 0) {
125
+ renderReportEntries(result.reportEntries, verbose);
126
+ }
127
+ // ── Legacy assertion fields ───────────────────────────────────────────────
128
+ if (!result.reportEntries && (result.assertionsPassed !== undefined || result.assertionsFailed !== undefined)) {
129
+ const p = result.assertionsPassed ?? 0;
130
+ const f = result.assertionsFailed ?? 0;
131
+ console.log(` assertions: ${chalk.green(`${p} passed`)}${f > 0 ? chalk.red(` · ${f} failed`) : ''}`);
132
+ }
133
+ // ── --show-req ────────────────────────────────────────────────────────────
134
+ if (showReq && result.success) {
135
+ console.log(chalk.gray(' ↳ request:'));
136
+ console.log(chalk.gray(` url: ${result.url || '—'}`));
137
+ if (result.method)
138
+ console.log(chalk.gray(` method: ${result.method}`));
139
+ printKeyValue('headers', result.requestHeaders);
140
+ if (result.requestBody)
141
+ printBody('body', result.requestBody);
142
+ }
143
+ // ── --show-res ────────────────────────────────────────────────────────────
144
+ if (showRes) {
145
+ console.log(chalk.gray(' ↳ response:'));
146
+ printKeyValue('headers', result.responseHeaders);
147
+ if (result.body)
148
+ printBody('body', result.body);
149
+ }
150
+ }
151
+ const DIVIDER = chalk.gray('─'.repeat(64));
152
+ export function printRunSummary(results, totalMs) {
153
+ const passed = results.filter(r => r.result.success).length;
154
+ const failed = results.length - passed;
155
+ console.log();
156
+ console.log(DIVIDER);
157
+ const passedStr = passed > 0 ? chalk.green(`${passed} passed`) : chalk.gray('0 passed');
158
+ const failedStr = failed > 0 ? chalk.red(`${failed} failed`) : chalk.gray('0 failed');
159
+ console.log(` ${chalk.bold('Summary')} ` +
160
+ `${results.length} request${results.length !== 1 ? 's' : ''} · ` +
161
+ `${passedStr} · ${failedStr} · ` +
162
+ chalk.gray(formatDuration(totalMs) + ' total'));
163
+ console.log(DIVIDER);
164
+ console.log();
165
+ }
166
+ //# sourceMappingURL=cliPrint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cliPrint.js","sourceRoot":"","sources":["../src/cliPrint.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAA;AAG/B,SAAS,WAAW,CAAC,KAAa;IAChC,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,GAAG,KAAK,GAAG,CAAA;IACpC,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA;IAChE,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA;AAClD,CAAC;AAED,SAAS,cAAc,CAAC,EAAU;IAChC,IAAI,EAAE,GAAG,IAAI;QAAE,OAAO,GAAG,EAAE,IAAI,CAAA;IAC/B,OAAO,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAA;AACrC,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAyB,EAAE,OAAgB;IACtE,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAA;IAC9D,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAA;IAClD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAA;IAE1D,gEAAgE;IAChE,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAA;QAChF,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,GAAG,MAAM,CAAA;QACzC,OAAO,CAAC,GAAG,CACT,sBAAsB,KAAK,CAAC,KAAK,CAAC,GAAG,MAAM,SAAS,CAAC,EAAE;YACvD,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,MAAM,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CACrD,CAAA;QACD,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;YAC3B,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW;gBAAE,SAAQ;YACpC,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YAC7D,IAAI,IAAI,GAAG,UAAU,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAA;YACzC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBACpE,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,QAAQ,IAAI,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAA;YACzH,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACnB,CAAC;IACH,CAAC;IAED,kGAAkG;IAClG,IAAI,OAAO,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,SAAS,GAA2B;YACxC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;YACrB,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;YACtB,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC;YACvB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;YACrB,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;SACrB,CAAA;QACD,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,IAAI,CAAC,CAAC,IAAI,KAAK,KAAK;gBAAE,SAAQ;YAC9B,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAC1E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;QACzD,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS;gBAAE,SAAQ;YAClC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAA;QACzD,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAa,EAAE,GAAuC;IAC3E,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAM;IACjD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,KAAK,GAAG,CAAC,CAAC,CAAA;IAC7C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;IAClE,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,KAAa,EAAE,IAAwB;IACxD,IAAI,CAAC,IAAI;QAAE,OAAM;IACjB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,KAAK,GAAG,CAAC,CAAC,CAAA;IAC7C,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC,CAAA;IAC/C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,MAAiB,EACjB,QAAgB,EAChB,KAAa,EACb,KAAa,EACb,OAAgB,EAChB,OAAgB,EAChB,OAAgB;IAEhB,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACnE,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,KAAK,GAAG,CAAC,CAAA;IACjD,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAA;IAE/C,OAAO,CAAC,GAAG,EAAE,CAAA;IACb,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,IAAI,QAAQ,EAAE,CAAC,CAAA;IAErC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;IACjE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAA;IACpF,MAAM,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,CAAA;IAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAA;IAE1D,IAAI,UAAU,GAAG,EAAE,CAAA;IACnB,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAA;QAC5D,UAAU,GAAG,WAAW,CAAC,KAAK,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC,CAAA;IAC3E,CAAC;SAAM,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAC1C,UAAU,GAAG,MAAM,CAAC,SAAS;YAC3B,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC;YAC5B,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAA;IACtC,CAAC;IAED,IAAI,QAAQ,GAAG,EAAE,CAAA;IACjB,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACxD,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,KAAK,KAAK,IAAI,MAAM,GAAG,GAAG,GAAG,UAAU,KAAK,IAAI,GAAG,QAAQ,EAAE,CAAC,CAAA;IAEjF,8EAA8E;IAC9E,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,IAAI,MAAM,CAAC,KAAK;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;QAClE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAA;QACjD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,MAAM,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAA;QAClE,IAAI,MAAM,CAAC,MAAM;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QACjF,aAAa,CAAC,SAAS,EAAE,MAAM,CAAC,cAAc,CAAC,CAAA;QAC/C,IAAI,MAAM,CAAC,WAAW;YAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;IAC/D,CAAC;IAED,6EAA6E;IAC7E,IAAI,MAAM,CAAC,aAAa,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5D,mBAAmB,CAAC,MAAM,CAAC,aAAa,EAAE,OAAO,CAAC,CAAA;IACpD,CAAC;IAED,6EAA6E;IAC7E,IAAI,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,MAAM,CAAC,gBAAgB,KAAK,SAAS,IAAI,MAAM,CAAC,gBAAgB,KAAK,SAAS,CAAC,EAAE,CAAC;QAC9G,MAAM,CAAC,GAAG,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAA;QACtC,MAAM,CAAC,GAAG,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAA;QACtC,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAC5G,CAAC;IAED,6EAA6E;IAC7E,IAAI,OAAO,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAA;QAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,MAAM,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAA;QAClE,IAAI,MAAM,CAAC,MAAM;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;QACjF,aAAa,CAAC,SAAS,EAAE,MAAM,CAAC,cAAc,CAAC,CAAA;QAC/C,IAAI,MAAM,CAAC,WAAW;YAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;IAC/D,CAAC;IAED,6EAA6E;IAC7E,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAA;QAC7C,aAAa,CAAC,SAAS,EAAE,MAAM,CAAC,eAAe,CAAC,CAAA;QAChD,IAAI,MAAM,CAAC,IAAI;YAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAA;IACjD,CAAC;AACH,CAAC;AAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAA;AAE1C,MAAM,UAAU,eAAe,CAC7B,OAAmD,EACnD,OAAe;IAEf,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAA;IAC3D,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,CAAA;IAEtC,OAAO,CAAC,GAAG,EAAE,CAAA;IACb,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAEpB,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,MAAM,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IACvF,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IAErF,OAAO,CAAC,GAAG,CACT,KAAK,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI;QAC9B,GAAG,OAAO,CAAC,MAAM,WAAW,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO;QAClE,GAAG,SAAS,QAAQ,SAAS,OAAO;QACpC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,CAC/C,CAAA;IACD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACpB,OAAO,CAAC,GAAG,EAAE,CAAA;AACf,CAAC"}
package/dist/envFile.d.ts CHANGED
@@ -1,2 +1,13 @@
1
- export declare function loadEnvFile(envPath: string): Record<string, string>;
1
+ /**
2
+ * `environmentName`, when given, scopes YAML loading to exactly one named
3
+ * environment (e.g. "dev") instead of the default "flatten every
4
+ * environment in the file together" behavior — the latter merges every
5
+ * top-level key's `variables:` (and nested `children:`) into one map
6
+ * regardless of name, which silently lets same-named keys from different
7
+ * environments collide (last one processed wins). Meaningless for a plain
8
+ * .env file (nothing named to select) or a flat YAML mapping with no
9
+ * `variables:`/`children:` structure — ignored in both cases rather than
10
+ * treated as an error, since there's genuinely nothing to scope to.
11
+ */
12
+ export declare function loadEnvFile(envPath: string, environmentName?: string): Record<string, string>;
2
13
  //# sourceMappingURL=envFile.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"envFile.d.ts","sourceRoot":"","sources":["../src/envFile.ts"],"names":[],"mappings":"AASA,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASnE"}
1
+ {"version":3,"file":"envFile.d.ts","sourceRoot":"","sources":["../src/envFile.ts"],"names":[],"mappings":"AASA;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAS7F"}
package/dist/envFile.js CHANGED
@@ -1,11 +1,22 @@
1
1
  import { readFileSync } from 'fs';
2
2
  import { extname } from 'path';
3
3
  import YAML from 'yaml';
4
- export function loadEnvFile(envPath) {
4
+ /**
5
+ * `environmentName`, when given, scopes YAML loading to exactly one named
6
+ * environment (e.g. "dev") instead of the default "flatten every
7
+ * environment in the file together" behavior — the latter merges every
8
+ * top-level key's `variables:` (and nested `children:`) into one map
9
+ * regardless of name, which silently lets same-named keys from different
10
+ * environments collide (last one processed wins). Meaningless for a plain
11
+ * .env file (nothing named to select) or a flat YAML mapping with no
12
+ * `variables:`/`children:` structure — ignored in both cases rather than
13
+ * treated as an error, since there's genuinely nothing to scope to.
14
+ */
15
+ export function loadEnvFile(envPath, environmentName) {
5
16
  const content = readFileSync(envPath, 'utf-8');
6
17
  const ext = extname(envPath).toLowerCase();
7
18
  if (ext === '.yaml' || ext === '.yml') {
8
- return parseYamlEnv(content);
19
+ return parseYamlEnv(content, environmentName);
9
20
  }
10
21
  return parseDotEnv(content);
11
22
  }
@@ -27,33 +38,80 @@ function parseDotEnv(content) {
27
38
  }
28
39
  return env;
29
40
  }
30
- function parseYamlEnv(content) {
41
+ function ownVariables(node) {
42
+ const vars = {};
43
+ if (node.variables != null && typeof node.variables === 'object') {
44
+ for (const [k, v] of Object.entries(node.variables)) {
45
+ if (v != null && typeof v !== 'object')
46
+ vars[k] = String(v);
47
+ }
48
+ }
49
+ return vars;
50
+ }
51
+ /** Depth-first search for a named environment node anywhere in the tree
52
+ * (top-level or nested under some ancestor's `children:`), returning its
53
+ * resolved variables — its own `variables:` merged on top of every
54
+ * ancestor's, same inheritance order `collect()` below already produces
55
+ * implicitly for the whole-tree case, just scoped to one branch instead
56
+ * of every branch at once. */
57
+ function findEnvironment(tree, name, inherited = {}) {
58
+ for (const [key, value] of Object.entries(tree)) {
59
+ if (value === null || value === undefined || Array.isArray(value) || typeof value !== 'object')
60
+ continue;
61
+ const node = value;
62
+ const resolved = { ...inherited, ...ownVariables(node) };
63
+ if (key === name)
64
+ return resolved;
65
+ if (node.children != null && typeof node.children === 'object') {
66
+ const found = findEnvironment(node.children, name, resolved);
67
+ if (found)
68
+ return found;
69
+ }
70
+ }
71
+ return null;
72
+ }
73
+ /** Top-level environment names only (for an error message listing what IS
74
+ * available) — deliberately not the full nested tree, to keep that
75
+ * message short and scannable. */
76
+ function topLevelEnvironmentNames(tree) {
77
+ return Object.entries(tree)
78
+ .filter(([, value]) => value != null && typeof value === 'object' && !Array.isArray(value))
79
+ .map(([key]) => key);
80
+ }
81
+ function parseYamlEnv(content, environmentName) {
82
+ const parsed = YAML.parse(content);
83
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
84
+ return {};
85
+ const tree = parsed;
86
+ if (environmentName) {
87
+ const found = findEnvironment(tree, environmentName);
88
+ if (found)
89
+ return found;
90
+ // No named-environment structure at all (a flat mapping) means nothing
91
+ // to scope to — fall through to the flatten-everything behavior below
92
+ // rather than erroring on a flag that's simply inapplicable to this file.
93
+ const available = topLevelEnvironmentNames(tree);
94
+ if (available.length > 0) {
95
+ throw new Error(`Environment "${environmentName}" not found in this file. Available: ${available.join(', ')}`);
96
+ }
97
+ }
31
98
  const env = {};
32
- const collect = (tree) => {
33
- for (const [key, value] of Object.entries(tree)) {
99
+ const collect = (node) => {
100
+ for (const [key, value] of Object.entries(node)) {
34
101
  if (value === null || value === undefined || Array.isArray(value))
35
102
  continue;
36
103
  if (typeof value !== 'object') {
37
104
  env[key] = String(value);
38
105
  continue;
39
106
  }
40
- const node = value;
41
- const hasVariables = node.variables != null && typeof node.variables === 'object';
42
- const hasChildren = node.children != null && typeof node.children === 'object';
43
- if (hasVariables) {
44
- for (const [k, v] of Object.entries(node.variables)) {
45
- if (v != null && typeof v !== 'object')
46
- env[k] = String(v);
47
- }
107
+ const envNode = value;
108
+ Object.assign(env, ownVariables(envNode));
109
+ if (envNode.children != null && typeof envNode.children === 'object') {
110
+ collect(envNode.children);
48
111
  }
49
- if (hasChildren)
50
- collect(node.children);
51
112
  }
52
113
  };
53
- const parsed = YAML.parse(content);
54
- if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
55
- collect(parsed);
56
- }
114
+ collect(tree);
57
115
  return env;
58
116
  }
59
117
  //# sourceMappingURL=envFile.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"envFile.js","sourceRoot":"","sources":["../src/envFile.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"envFile.js","sourceRoot":"","sources":["../src/envFile.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -435,8 +435,10 @@ program
435
435
  ' voiden-runner run auth.void\n' +
436
436
  ' voiden-runner run ./requests/\n' +
437
437
  ' voiden-runner run auth.void users.void ./smoke/\n' +
438
- ' voiden-runner run ./ --env .env.staging --bail\n')
438
+ ' voiden-runner run ./ --env .env.staging --bail\n' +
439
+ ' voiden-runner run ./ --env .voiden/env-public.yaml --environment staging\n')
439
440
  .option('-e, --env <path>', 'Path to .env or .yaml file for variable substitution')
441
+ .option('--environment <name>', 'Scope --env to one named environment in a multi-environment YAML file (e.g. "dev") instead of merging every environment in it together')
440
442
  .option('--env-var <key=value>', 'Individual environment variable override (can be used multiple times)', (val, memo) => {
441
443
  memo.push(val);
442
444
  return memo;
@@ -476,7 +478,7 @@ program
476
478
  process.exit(EXIT_USAGE_ERROR);
477
479
  }
478
480
  try {
479
- Object.assign(env, loadEnvFile(envPath));
481
+ Object.assign(env, loadEnvFile(envPath, opts.environment));
480
482
  }
481
483
  catch (err) {
482
484
  console.error(chalk.red(` ✗ ${err.message}`));
@@ -1269,7 +1271,7 @@ pluginCmd
1269
1271
  // ── voiden-runner mcp ─────────────────────────────────────────────────────────
1270
1272
  //
1271
1273
  // Enables the AI-agent loop for CLI-only users (no Voiden app installed):
1272
- // registers @voiden/mcp-server with Claude Code / Codex, and installs a
1274
+ // registers @voiden/mcp with Claude Code / Codex, and installs a
1273
1275
  // standalone skill teaching the run/verify/write-back workflow. The Voiden
1274
1276
  // app's own Settings toggle does the equivalent for desktop users, reusing
1275
1277
  // the same registration helpers from mcpInstall.ts.
@@ -1282,23 +1284,25 @@ function resolveMcpTargets(opts) {
1282
1284
  }
1283
1285
  const mcpCmd = program
1284
1286
  .command('mcp')
1285
- .description('Enable AI-agent integration — registers @voiden/mcp-server and installs a run/verify skill');
1287
+ .description('Enable AI-agent integration — registers this project\'s fixed-tools MCP server and installs a run/verify skill');
1286
1288
  mcpCmd
1287
1289
  .command('install')
1288
- .description('Register @voiden/mcp-server with Claude Code and/or Codex, and install a skill teaching the run/verify/write-back loop.\n\n' +
1290
+ .description('Register this project with Claude Code and/or Codex points .mcp.json / config.toml at ' +
1291
+ '`voiden-runner mcp serve` (the same 4 fixed tools, standalone, no other Voiden package ' +
1292
+ 'required), and installs a skill teaching the run/verify/write-back loop.\n\n' +
1289
1293
  ' Examples:\n' +
1290
1294
  ' voiden-runner mcp install # both Claude Code and Codex\n' +
1291
1295
  ' voiden-runner mcp install --claude # Claude Code only\n' +
1292
1296
  ' voiden-runner mcp install -p ./my-project # register against a specific project dir (default: cwd)\n' +
1293
- ' voiden-runner mcp install --local-server ./dist/index.js # before publishing: point at a local build instead of npx\n')
1297
+ ' voiden-runner mcp install --local-server ./dist/index.js # point at a local build instead of npx\n')
1294
1298
  .option('--claude', 'Install for Claude Code only')
1295
1299
  .option('--codex', 'Install for Codex only')
1296
1300
  .option('-p, --project <path>', 'Project directory to register the MCP server against', '.')
1297
- .option('--local-server <path>', 'Use `node <path>` instead of `npx -y @voiden/mcp-server` — for testing against a local build before it\'s published')
1301
+ .option('--local-server <path>', 'Use `node <path> mcp serve` instead of `npx -y @voiden/runner mcp serve` — for testing against a local build')
1298
1302
  .action((opts) => {
1299
1303
  const targets = resolveMcpTargets(opts);
1300
1304
  const serverCommand = opts.localServer
1301
- ? { command: 'node', args: [resolve(opts.localServer), resolve(opts.project)] }
1305
+ ? { command: 'node', args: [resolve(opts.localServer), 'mcp', 'serve', resolve(opts.project)] }
1302
1306
  : undefined;
1303
1307
  const installed = installMcpIntegration(opts.project, targets, MCP_SKILL_MARKDOWN, serverCommand);
1304
1308
  if (installed.length === 0) {
@@ -1307,7 +1311,7 @@ mcpCmd
1307
1311
  }
1308
1312
  console.log();
1309
1313
  for (const target of installed) {
1310
- console.log(chalk.green(` ✓ ${target === 'claude' ? 'Claude Code' : 'Codex'}`) + chalk.gray(` — skill installed, @voiden/mcp-server registered for ${resolve(opts.project)}`));
1314
+ console.log(chalk.green(` ✓ ${target === 'claude' ? 'Claude Code' : 'Codex'}`) + chalk.gray(` — skill installed, fixed-tools MCP server registered for ${resolve(opts.project)}`));
1311
1315
  }
1312
1316
  if (serverCommand) {
1313
1317
  console.log(chalk.gray(` Using local build: node ${serverCommand.args[0]}`));
@@ -1350,7 +1354,7 @@ mcpCmd
1350
1354
  });
1351
1355
  mcpCmd
1352
1356
  .command('serve [path]')
1353
- .description('Serve this project as an MCP server — the same tools @voiden/mcp-server exposes ' +
1357
+ .description('Serve this project as an MCP server — the same tools @voiden/mcp exposes ' +
1354
1358
  '(list/run/write plus declared /tool capabilities), over stdio (default) or HTTP.\n\n' +
1355
1359
  ' Examples:\n' +
1356
1360
  ' voiden-runner mcp serve # stdio, current directory\n' +
@@ -1360,7 +1364,8 @@ mcpCmd
1360
1364
  .option('--http', 'Serve over streamable HTTP instead of stdio')
1361
1365
  .option('-p, --port <port>', 'HTTP port (only with --http)', '3000')
1362
1366
  .option('--host <host>', 'HTTP bind address (only with --http) — binding beyond 127.0.0.1 is a real exposure risk', '127.0.0.1')
1363
- .option('-e, --env <path>', 'Path to .env file for variable substitution')
1367
+ .option('-e, --env <path>', 'Path to .env or .yaml file for variable substitution')
1368
+ .option('--environment <name>', 'Scope --env to one named environment in a multi-environment YAML file (e.g. "dev") instead of merging every environment in it together')
1364
1369
  .option('--check', 'Print what would be served and exit, without starting a live server')
1365
1370
  .action(async (path, opts) => {
1366
1371
  const projectRoot = resolve(path ?? '.');
@@ -1372,7 +1377,7 @@ mcpCmd
1372
1377
  process.exit(EXIT_USAGE_ERROR);
1373
1378
  }
1374
1379
  try {
1375
- Object.assign(env, loadEnvFile(envPath));
1380
+ Object.assign(env, loadEnvFile(envPath, opts.environment));
1376
1381
  }
1377
1382
  catch (err) {
1378
1383
  console.error(chalk.red(` ✗ ${err.message}`));
@@ -1408,7 +1413,7 @@ mcpCmd
1408
1413
  const commitSha = getCommitSha(projectRoot);
1409
1414
  const servedCount = decisions.filter((d) => d.served).length;
1410
1415
  // Shared across calls so {{process.xxx}} runtime variables chain the
1411
- // same way they do for the stdio path and for @voiden/mcp-server.
1416
+ // same way they do for the stdio path and for @voiden/mcp.
1412
1417
  const runtimeVars = {};
1413
1418
  if (opts.http) {
1414
1419
  const port = Number(opts.port);
@@ -1452,7 +1457,7 @@ mcpCmd
1452
1457
  else {
1453
1458
  // stdio: one persistent server for the process lifetime — stdout is
1454
1459
  // reserved for the JSON-RPC stream, so nothing gets printed there.
1455
- // Startup info goes to stderr only, same discipline @voiden/mcp-server's
1460
+ // Startup info goes to stderr only, same discipline @voiden/mcp's
1456
1461
  // own entrypoint already follows (it prints nothing).
1457
1462
  const server = new McpServer({ name: 'voiden-runner', version: '1.0.0' });
1458
1463
  registerFixedTools(server, projectRoot, runtimeVars, activePlugins);
@@ -1464,7 +1469,7 @@ mcpCmd
1464
1469
  //
1465
1470
  // Discovery + verification for /tool blocks (voiden-mcp-tool plugin) — the
1466
1471
  // standalone CLI surface for the same discoverTools/verifyTools functions
1467
- // @voiden/mcp-server will use for live agent-serving. No scheduling here:
1472
+ // @voiden/mcp will use for live agent-serving. No scheduling here:
1468
1473
  // `cadence` on a verify entry is a tag `--cadence` filters by, not something
1469
1474
  // this command enforces timing for — that's a human/CI decision, same as
1470
1475
  // deciding when to run `voiden-runner run` at all.
@@ -1495,7 +1500,11 @@ toolCmd
1495
1500
  console.log(chalk.bold(` ${tool.name}`) + chalk.gray(` — ${relative(process.cwd(), tool.filePath)}${tool.sectionLabel ? ` [${tool.sectionLabel}]` : ''}`));
1496
1501
  if (tool.description)
1497
1502
  console.log(chalk.gray(` ${tool.description}`));
1498
- console.log(chalk.gray(` params: ${tool.params.length} verifies: ${tool.verifies.length} on-failure: ${tool.onFailure}`));
1503
+ // onFailure is per verify-entry now, not one tool-wide setting —
1504
+ // summarize instead of showing a single (no-longer-existing) value.
1505
+ const onFailureValues = new Set(tool.verifies.map((v) => v.onFailure || 'withdraw'));
1506
+ const onFailureSummary = tool.verifies.length === 0 ? '—' : onFailureValues.size === 1 ? [...onFailureValues][0] : 'mixed';
1507
+ console.log(chalk.gray(` params: ${tool.params.length} verifies: ${tool.verifies.length} on-failure: ${onFailureSummary}`));
1499
1508
  console.log();
1500
1509
  }
1501
1510
  });
@@ -1510,6 +1519,7 @@ toolCmd
1510
1519
  .option('--json', 'Output as JSON (suppresses normal output — useful for CI)')
1511
1520
  .option('--write', 'Write the computed status back into each /tool block. Off by default — verification always recomputes fresh and never trusts a stale write-back')
1512
1521
  .option('-e, --env <path>', 'Path to .env or .yaml file for variable substitution')
1522
+ .option('--environment <name>', 'Scope --env to one named environment in a multi-environment YAML file (e.g. "dev") instead of merging every environment in it together')
1513
1523
  .action(async (paths, opts) => {
1514
1524
  const targets = paths.length > 0 ? paths : ['.'];
1515
1525
  const env = Object.fromEntries(Object.entries(process.env).filter(([, v]) => v !== undefined));
@@ -1520,7 +1530,7 @@ toolCmd
1520
1530
  process.exit(EXIT_USAGE_ERROR);
1521
1531
  }
1522
1532
  try {
1523
- Object.assign(env, loadEnvFile(envPath));
1533
+ Object.assign(env, loadEnvFile(envPath, opts.environment));
1524
1534
  }
1525
1535
  catch (err) {
1526
1536
  console.error(chalk.red(` ✗ ${err.message}`));