@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.
- package/bundled-runners/voiden-faker-runner.js +6 -13
- package/bundled-runners/voiden-mcp-tool-runner.js +68 -68
- package/dist/cliPrint.d.ts +7 -0
- package/dist/cliPrint.d.ts.map +1 -0
- package/dist/cliPrint.js +166 -0
- package/dist/cliPrint.js.map +1 -0
- package/dist/envFile.d.ts +12 -1
- package/dist/envFile.d.ts.map +1 -1
- package/dist/envFile.js +77 -19
- package/dist/envFile.js.map +1 -1
- package/dist/index.js +27 -17
- package/dist/index.js.map +1 -1
- package/dist/lib.d.ts +3 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +8 -2
- package/dist/lib.js.map +1 -1
- package/dist/mcpServing.d.ts +1 -1
- package/dist/mcpServing.js +2 -2
- package/dist/mcpServing.js.map +1 -1
- package/dist/mcpToolCapability.d.ts +1 -1
- package/dist/mcpToolCapability.js +2 -2
- package/dist/mcpToolCapability.js.map +1 -1
- package/dist/toolRegistry.d.ts +10 -1
- package/dist/toolRegistry.d.ts.map +1 -1
- package/dist/toolRegistry.js.map +1 -1
- package/package.json +3 -4
|
@@ -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"}
|
package/dist/cliPrint.js
ADDED
|
@@ -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":"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"}
|
package/dist/envFile.d.ts
CHANGED
|
@@ -1,2 +1,13 @@
|
|
|
1
|
-
|
|
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
|
package/dist/envFile.d.ts.map
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
|
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 = (
|
|
33
|
-
for (const [key, value] of Object.entries(
|
|
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
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
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
|
package/dist/envFile.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"envFile.js","sourceRoot":"","sources":["../src/envFile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAC9B,OAAO,IAAI,MAAM,MAAM,CAAA;AAOvB,MAAM,UAAU,WAAW,CAAC,OAAe;
|
|
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
|
|
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
|
|
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
|
|
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 #
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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}`));
|