@invokable/conformance 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Invokable
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # @invokable/conformance
2
+
3
+ Checks that a CLI honours the [invokable](https://github.com/beinvokable/invokable)
4
+ agent contract.
5
+
6
+ ```console
7
+ $ npx invokable-test node bin/mytool.mjs
8
+
9
+ ✓ `--version --json` returns a valid ok envelope
10
+ ✓ `--help --json` returns a command manifest
11
+ ✓ An unknown command exits 2 with an error envelope
12
+ ✓ A bare invocation does not exit 0
13
+ ✓ `doctor --json` reports auth and config state
14
+ ✓ Every exit code is reserved or in 30-99
15
+ ✓ `--json` puts exactly one JSON document on stdout
16
+ ✓ No credential-shaped strings on stdout
17
+ ✓ Errors carry a `remediation`
18
+
19
+ 9 passed
20
+ ```
21
+
22
+ Exit 0 when everything passes, 1 otherwise. It works on **any** CLI, not just one
23
+ built with `@invokable/core`: the contract is the product, and the library is one
24
+ way of satisfying it.
25
+
26
+ ## What it will not do
27
+
28
+ **It never runs a command from your manifest.** Only `--help`, `--version`,
29
+ `doctor` and deliberately invalid invocations are executed. A runner that
30
+ executed every listed command could deploy something or spend the user's money,
31
+ and tools where that matters are exactly the ones this suite exists for.
32
+
33
+ To include a command you know is safe:
34
+
35
+ ```bash
36
+ invokable-test node bin/mytool.mjs --safe-command "projects list"
37
+ ```
38
+
39
+ **It never reproduces a credential.** The secret-leak check reports the shape and
40
+ the prefix — `a token-shaped string: prefix "mtl_", 36 characters` — never the
41
+ material, because a report gets pasted into issues and CI logs.
42
+
43
+ ## Options
44
+
45
+ | Option | Effect |
46
+ |---|---|
47
+ | `--json` | Emit the report as JSON on stdout instead of text on stderr. |
48
+ | `--safe-command <cmd>` | Also run this command. Repeatable. |
49
+ | `--timeout <ms>` | Per-invocation timeout. Default 30000. |
50
+
51
+ ## In CI
52
+
53
+ ```yaml
54
+ - run: npx invokable-test node bin/mytool.mjs
55
+ ```
56
+
57
+ A failing check prints why an agent depends on it and a command to reproduce it.
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { conformanceMain } from '../dist/index.js';
3
+
4
+ process.exitCode = await conformanceMain({ argv: process.argv.slice(2) });
@@ -0,0 +1,25 @@
1
+ import { type ExecOptions } from './exec.js';
2
+ export type CheckStatus = 'pass' | 'fail' | 'warn' | 'skip';
3
+ export interface CheckResult {
4
+ id: string;
5
+ title: string;
6
+ status: CheckStatus;
7
+ /** What went wrong, or what was observed. */
8
+ detail?: string;
9
+ /** Why an agent depends on this. Shown for failures. */
10
+ rationale: string;
11
+ invocations: string[];
12
+ }
13
+ export interface CheckContext extends ExecOptions {
14
+ /** Commands the runner may execute beyond the always-safe set. */
15
+ extraSafeCommands: readonly string[];
16
+ }
17
+ /**
18
+ * Every check runs the tool for real. Only commands that cannot change anything
19
+ * are executed: `--help`, `--version`, `doctor`, and deliberately invalid
20
+ * invocations. A conformance runner that executed arbitrary commands from the
21
+ * manifest could deploy something or spend the user's money — the tools this
22
+ * suite exists to validate are exactly the ones where that matters.
23
+ */
24
+ export declare function runChecks(ctx: CheckContext): Promise<CheckResult[]>;
25
+ //# sourceMappingURL=checks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"AACA,OAAO,EAAU,KAAK,WAAW,EAAmB,MAAM,WAAW,CAAC;AAEtE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5D,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,CAAC;IACpB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,YAAa,SAAQ,WAAW;IAC/C,kEAAkE;IAClE,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAkFD;;;;;;GAMG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAyLzE"}
package/dist/checks.js ADDED
@@ -0,0 +1,231 @@
1
+ import { EXIT, EXIT_NAME, CUSTOM_EXIT_RANGE } from '@invokable/core';
2
+ import { invoke } from './exec.js';
3
+ const VALID_EXIT_CODES = new Set(Object.values(EXIT));
4
+ function isValidExitCode(code) {
5
+ if (code === null)
6
+ return false;
7
+ if (VALID_EXIT_CODES.has(code))
8
+ return true;
9
+ return code >= CUSTOM_EXIT_RANGE.min && code <= CUSTOM_EXIT_RANGE.max;
10
+ }
11
+ /** Exactly one JSON document, nothing else. */
12
+ function parseSingleDocument(stdout) {
13
+ const trimmed = stdout.trim();
14
+ if (trimmed === '')
15
+ return { ok: false, reason: 'stdout was empty' };
16
+ try {
17
+ return { ok: true, value: JSON.parse(trimmed) };
18
+ }
19
+ catch {
20
+ const lines = trimmed.split('\n').filter((l) => l.trim() !== '');
21
+ if (lines.length > 1) {
22
+ return {
23
+ ok: false,
24
+ reason: `stdout had ${lines.length} lines and is not one JSON document. ` +
25
+ `First line: ${JSON.stringify(lines[0].slice(0, 120))}`,
26
+ };
27
+ }
28
+ return { ok: false, reason: `stdout is not valid JSON: ${JSON.stringify(trimmed.slice(0, 200))}` };
29
+ }
30
+ }
31
+ function isRecord(v) {
32
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
33
+ }
34
+ /**
35
+ * Strings that look like credentials, which must never reach stdout.
36
+ *
37
+ * The finding describes the shape and never quotes the material. A report that
38
+ * reprinted the secret would copy it into CI logs and pasted transcripts — the
39
+ * exact spread this check exists to prevent.
40
+ */
41
+ function looksLikeSecret(text) {
42
+ const patterns = [
43
+ [
44
+ /\b([a-z]{2,10})_[A-Za-z0-9]{24,}\b/,
45
+ (m) => `a token-shaped string: prefix "${m.split('_')[0]}_", ${m.length} characters`,
46
+ ],
47
+ [/\bBearer\s+[A-Za-z0-9._-]{16,}/i, (m) => `a Bearer credential, ${m.length} characters`],
48
+ [/-----BEGIN [A-Z ]*PRIVATE KEY-----/, () => 'a PEM private key block'],
49
+ ];
50
+ for (const [re, describe] of patterns) {
51
+ const m = re.exec(text);
52
+ if (m)
53
+ return describe(m[0]);
54
+ }
55
+ return null;
56
+ }
57
+ function result(id, title, rationale, status, invocations, detail) {
58
+ return {
59
+ id,
60
+ title,
61
+ status,
62
+ rationale,
63
+ invocations: invocations.map((i) => i.commandLine),
64
+ ...(detail !== undefined ? { detail } : {}),
65
+ };
66
+ }
67
+ /**
68
+ * Every check runs the tool for real. Only commands that cannot change anything
69
+ * are executed: `--help`, `--version`, `doctor`, and deliberately invalid
70
+ * invocations. A conformance runner that executed arbitrary commands from the
71
+ * manifest could deploy something or spend the user's money — the tools this
72
+ * suite exists to validate are exactly the ones where that matters.
73
+ */
74
+ export async function runChecks(ctx) {
75
+ const results = [];
76
+ const runs = [];
77
+ const run = async (args) => {
78
+ const inv = await invoke(ctx, args);
79
+ runs.push(inv);
80
+ return inv;
81
+ };
82
+ // ---- 1. --version --------------------------------------------------------
83
+ const version = await run(['--version', '--json']);
84
+ {
85
+ const parsed = parseSingleDocument(version.stdout);
86
+ if (version.timedOut) {
87
+ results.push(result('version', '`--version --json` responds', RATIONALE.responds, 'fail', [version], 'The process timed out.'));
88
+ }
89
+ else if (!parsed.ok) {
90
+ results.push(result('version', '`--version --json` emits one JSON document', RATIONALE.singleDoc, 'fail', [version], parsed.reason));
91
+ }
92
+ else if (!isRecord(parsed.value) || parsed.value['status'] !== 'ok') {
93
+ results.push(result('version', '`--version --json` returns status ok', RATIONALE.envelope, 'fail', [version], `status was ${JSON.stringify(parsed.value?.['status'])}`));
94
+ }
95
+ else {
96
+ results.push(result('version', '`--version --json` returns a valid ok envelope', RATIONALE.envelope, 'pass', [version]));
97
+ }
98
+ }
99
+ // ---- 2. --help --json is a machine-readable manifest ---------------------
100
+ const help = await run(['--help', '--json']);
101
+ {
102
+ const parsed = parseSingleDocument(help.stdout);
103
+ const data = isRecord(parsed.value) ? parsed.value['data'] : undefined;
104
+ const commands = isRecord(data) ? data['commands'] : undefined;
105
+ if (!parsed.ok) {
106
+ results.push(result('help', '`--help --json` emits one JSON document', RATIONALE.singleDoc, 'fail', [help], parsed.reason));
107
+ }
108
+ else if (!Array.isArray(commands) || commands.length === 0) {
109
+ results.push(result('help', '`--help --json` lists commands', RATIONALE.manifest, 'fail', [help], 'data.commands was missing or empty. An agent cannot discover the surface.'));
110
+ }
111
+ else {
112
+ results.push(result('help', '`--help --json` returns a command manifest', RATIONALE.manifest, 'pass', [help], `${commands.length} commands`));
113
+ }
114
+ }
115
+ // ---- 3. An unknown command is a usage error, not a crash ----------------
116
+ const unknown = await run(['definitely-not-a-real-command-xyz', '--json']);
117
+ {
118
+ const parsed = parseSingleDocument(unknown.stdout);
119
+ const env = isRecord(parsed.value) ? parsed.value : undefined;
120
+ const problems = [];
121
+ if (unknown.exitCode !== EXIT.usage) {
122
+ problems.push(`exit was ${unknown.exitCode}, expected ${EXIT.usage} (usage)`);
123
+ }
124
+ if (!parsed.ok)
125
+ problems.push(parsed.reason ?? 'stdout was not one JSON document');
126
+ else {
127
+ if (env?.['status'] !== 'error')
128
+ problems.push(`status was ${JSON.stringify(env?.['status'])}, expected "error"`);
129
+ if (typeof env?.['code'] !== 'string')
130
+ problems.push('error envelope has no string `code`');
131
+ if (typeof env?.['message'] !== 'string')
132
+ problems.push('error envelope has no string `message`');
133
+ if (typeof env?.['retryable'] !== 'boolean')
134
+ problems.push('error envelope has no boolean `retryable`');
135
+ }
136
+ results.push(problems.length
137
+ ? result('unknown-command', 'An unknown command exits 2 with an error envelope', RATIONALE.usage, 'fail', [unknown], problems.join('; '))
138
+ : result('unknown-command', 'An unknown command exits 2 with an error envelope', RATIONALE.usage, 'pass', [unknown]));
139
+ }
140
+ // ---- 4. A bare invocation does not look like success ---------------------
141
+ const bare = await run(['--json']);
142
+ {
143
+ results.push(bare.exitCode === EXIT.ok
144
+ ? result('bare', 'A bare invocation does not exit 0', RATIONALE.bare, 'fail', [bare], 'Exit 0 with no command tells an agent the work succeeded when nothing ran.')
145
+ : result('bare', 'A bare invocation does not exit 0', RATIONALE.bare, 'pass', [bare], `exit ${bare.exitCode}`));
146
+ }
147
+ // ---- 5. doctor -----------------------------------------------------------
148
+ const doctor = await run(['doctor', '--json']);
149
+ {
150
+ const parsed = parseSingleDocument(doctor.stdout);
151
+ const data = isRecord(parsed.value) ? parsed.value['data'] : undefined;
152
+ if (doctor.timedOut) {
153
+ results.push(result('doctor', '`doctor --json` responds', RATIONALE.doctor, 'fail', [doctor], 'The process timed out.'));
154
+ }
155
+ else if (!parsed.ok) {
156
+ results.push(result('doctor', '`doctor --json` emits one JSON document', RATIONALE.singleDoc, 'fail', [doctor], parsed.reason));
157
+ }
158
+ else if (!isRecord(data) || !isRecord(data['auth']) || !isRecord(data['config'])) {
159
+ results.push(result('doctor', '`doctor --json` reports auth and config', RATIONALE.doctor, 'fail', [doctor], 'Expected data.auth and data.config. An agent uses these to tell "not logged in" from "service down".'));
160
+ }
161
+ else {
162
+ results.push(result('doctor', '`doctor --json` reports auth and config state', RATIONALE.doctor, 'pass', [doctor]));
163
+ }
164
+ }
165
+ // ---- 6. Optional user-nominated safe commands ----------------------------
166
+ for (const command of ctx.extraSafeCommands) {
167
+ const args = command.split(/\s+/).filter(Boolean);
168
+ const inv = await run([...args, '--json']);
169
+ const parsed = parseSingleDocument(inv.stdout);
170
+ results.push(parsed.ok
171
+ ? result(`safe:${command}`, `\`${command} --json\` emits one JSON document`, RATIONALE.singleDoc, 'pass', [inv])
172
+ : result(`safe:${command}`, `\`${command} --json\` emits one JSON document`, RATIONALE.singleDoc, 'fail', [inv], parsed.reason));
173
+ }
174
+ // ---- 7. Cross-cutting: exit codes ---------------------------------------
175
+ {
176
+ const bad = runs.filter((r) => !isValidExitCode(r.exitCode));
177
+ results.push(bad.length
178
+ ? result('exit-codes', 'Every exit code is reserved or in 30-99', RATIONALE.exitCodes, 'fail', bad, bad.map((r) => `\`${r.commandLine}\` exited ${r.exitCode ?? 'by signal/timeout'}`).join('; '))
179
+ : result('exit-codes', 'Every exit code is reserved or in 30-99', RATIONALE.exitCodes, 'pass', [], [...new Set(runs.map((r) => r.exitCode))]
180
+ .sort((a, b) => (a ?? 0) - (b ?? 0))
181
+ .map((c) => `${c}${c !== null && EXIT_NAME[c] ? ` (${EXIT_NAME[c]})` : ''}`)
182
+ .join(', ')));
183
+ }
184
+ // ---- 8. Cross-cutting: --json stdout purity ------------------------------
185
+ {
186
+ const impure = runs.filter((r) => {
187
+ if (!r.argv.includes('--json') || r.timedOut)
188
+ return false;
189
+ return !parseSingleDocument(r.stdout).ok;
190
+ });
191
+ results.push(impure.length
192
+ ? result('json-purity', '`--json` puts exactly one JSON document on stdout', RATIONALE.singleDoc, 'fail', impure, impure.map((r) => `\`${r.commandLine}\`: ${parseSingleDocument(r.stdout).reason}`).join('; '))
193
+ : result('json-purity', '`--json` puts exactly one JSON document on stdout', RATIONALE.singleDoc, 'pass', []));
194
+ }
195
+ // ---- 9. Cross-cutting: no credentials on stdout -------------------------
196
+ {
197
+ const leaks = runs
198
+ .map((r) => ({ run: r, found: looksLikeSecret(r.stdout) }))
199
+ .filter((x) => x.found !== null);
200
+ results.push(leaks.length
201
+ ? result('no-secrets', 'No credential-shaped strings on stdout', RATIONALE.secrets, 'fail', leaks.map((l) => l.run), leaks.map((l) => `\`${l.run.commandLine}\` printed ${l.found}`).join('; '))
202
+ : result('no-secrets', 'No credential-shaped strings on stdout', RATIONALE.secrets, 'pass', []));
203
+ }
204
+ // ---- 10. Cross-cutting: errors carry remediation -------------------------
205
+ {
206
+ const errors = runs
207
+ .filter((r) => r.argv.includes('--json'))
208
+ .map((r) => parseSingleDocument(r.stdout).value)
209
+ .filter((v) => isRecord(v) && v['status'] === 'error');
210
+ const missing = errors.filter((e) => typeof e['remediation'] !== 'string');
211
+ results.push(errors.length === 0
212
+ ? result('remediation', 'Errors carry a `remediation`', RATIONALE.remediation, 'skip', [], 'No error envelopes were produced.')
213
+ : missing.length
214
+ ? result('remediation', 'Errors carry a `remediation`', RATIONALE.remediation, 'warn', [], `${missing.length} of ${errors.length} error envelopes had no remediation.`)
215
+ : result('remediation', 'Errors carry a `remediation`', RATIONALE.remediation, 'pass', []));
216
+ }
217
+ return results;
218
+ }
219
+ const RATIONALE = {
220
+ responds: 'An agent that gets no response cannot tell a hang from a failure.',
221
+ singleDoc: 'The agent parses stdout as one JSON document. A stray log line makes the parse fail, and the agent reports a broken tool rather than the real result.',
222
+ envelope: 'The agent reads `status` before anything else.',
223
+ manifest: '`--help --json` is how an agent discovers commands and options instead of guessing them.',
224
+ usage: 'A mistyped command must be distinguishable from a real failure, or the agent retries something that can never work.',
225
+ bare: 'Exit 0 with no command run tells the agent the task is done.',
226
+ doctor: '`doctor` is how an agent tells "not logged in" from "service unreachable" — the two failures that look identical from outside.',
227
+ exitCodes: 'The agent decides what to do next from the exit code alone. An unreserved code means it has no rule to apply.',
228
+ secrets: 'stdout is captured, logged and often echoed back into a transcript.',
229
+ remediation: 'Without it the agent has to invent the next command.',
230
+ };
231
+ //# sourceMappingURL=checks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checks.js","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ export interface MainOptions {
2
+ argv: readonly string[];
3
+ stdout?: (s: string) => void;
4
+ stderr?: (s: string) => void;
5
+ }
6
+ /** Returns the process exit code. */
7
+ export declare function conformanceMain(options: MainOptions): Promise<number>;
8
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAsBD,qCAAqC;AACrC,wBAAsB,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CA0D3E"}
package/dist/cli.js ADDED
@@ -0,0 +1,80 @@
1
+ import { runChecks } from './checks.js';
2
+ import { renderReport, summarise } from './report.js';
3
+ const USAGE = `Usage: invokable-test <command> [args...] [options]
4
+
5
+ Checks that a CLI honours the invokable agent contract.
6
+
7
+ invokable-test ./bin/mytool.mjs
8
+ invokable-test node ./bin/mytool.mjs
9
+ invokable-test npx mytool
10
+
11
+ Options:
12
+ --json Emit the report as JSON on stdout.
13
+ --safe-command <cmd> Additionally run this command (repeatable).
14
+ Only pass commands that change nothing.
15
+ --timeout <ms> Per-invocation timeout. Default 30000.
16
+ -h, --help Show this help.
17
+
18
+ Only commands that cannot change anything are run: --help, --version, doctor,
19
+ and deliberately invalid invocations. Commands from the manifest are never
20
+ executed on their own, because one of them may spend the user's money.
21
+ `;
22
+ /** Returns the process exit code. */
23
+ export async function conformanceMain(options) {
24
+ const stdout = options.stdout ?? ((s) => process.stdout.write(s));
25
+ const stderr = options.stderr ?? ((s) => process.stderr.write(s));
26
+ const argv = [...options.argv];
27
+ let json = false;
28
+ let timeoutMs = 30_000;
29
+ const safeCommands = [];
30
+ const target = [];
31
+ for (let i = 0; i < argv.length; i++) {
32
+ const token = argv[i];
33
+ if (token === '--json') {
34
+ json = true;
35
+ }
36
+ else if (token === '--help' || token === '-h') {
37
+ stderr(USAGE);
38
+ return 0;
39
+ }
40
+ else if (token === '--safe-command') {
41
+ const value = argv[++i];
42
+ if (value === undefined) {
43
+ stderr('error: --safe-command needs a value\n');
44
+ return 2;
45
+ }
46
+ safeCommands.push(value);
47
+ }
48
+ else if (token === '--timeout') {
49
+ const value = Number(argv[++i]);
50
+ if (!Number.isFinite(value) || value <= 0) {
51
+ stderr('error: --timeout must be a positive number of milliseconds\n');
52
+ return 2;
53
+ }
54
+ timeoutMs = value;
55
+ }
56
+ else {
57
+ target.push(token);
58
+ }
59
+ }
60
+ const command = target[0];
61
+ if (command === undefined) {
62
+ stderr(USAGE);
63
+ return 2;
64
+ }
65
+ const checks = await runChecks({
66
+ command,
67
+ baseArgs: target.slice(1),
68
+ timeoutMs,
69
+ extraSafeCommands: safeCommands,
70
+ });
71
+ const report = summarise(target.join(' '), checks);
72
+ if (json) {
73
+ stdout(JSON.stringify(report) + '\n');
74
+ }
75
+ else {
76
+ stderr(renderReport(report));
77
+ }
78
+ return report.ok ? 0 : 1;
79
+ }
80
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/exec.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ export interface Invocation {
2
+ /** Args passed after the base command. */
3
+ argv: readonly string[];
4
+ /** The full command line, for reproducing the run. */
5
+ commandLine: string;
6
+ stdout: string;
7
+ stderr: string;
8
+ /** Null when the process was killed by a signal or timed out. */
9
+ exitCode: number | null;
10
+ timedOut: boolean;
11
+ durationMs: number;
12
+ }
13
+ export interface ExecOptions {
14
+ command: string;
15
+ baseArgs: readonly string[];
16
+ timeoutMs?: number;
17
+ env?: NodeJS.ProcessEnv;
18
+ cwd?: string;
19
+ }
20
+ /**
21
+ * Runs the tool under test as a real subprocess.
22
+ *
23
+ * Everything is measured on actual file descriptors: stdout purity is only
24
+ * meaningful at the process boundary, which is where the agent reads it.
25
+ */
26
+ export declare function invoke(opts: ExecOptions, args: readonly string[]): Promise<Invocation>;
27
+ //# sourceMappingURL=exec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../src/exec.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAoCtF"}
package/dist/exec.js ADDED
@@ -0,0 +1,39 @@
1
+ import { execFile } from 'node:child_process';
2
+ /**
3
+ * Runs the tool under test as a real subprocess.
4
+ *
5
+ * Everything is measured on actual file descriptors: stdout purity is only
6
+ * meaningful at the process boundary, which is where the agent reads it.
7
+ */
8
+ export function invoke(opts, args) {
9
+ const argv = [...opts.baseArgs, ...args];
10
+ const started = Date.now();
11
+ return new Promise((resolve) => {
12
+ execFile(opts.command, argv, {
13
+ timeout: opts.timeoutMs ?? 30_000,
14
+ maxBuffer: 16 * 1024 * 1024,
15
+ ...(opts.cwd !== undefined ? { cwd: opts.cwd } : {}),
16
+ env: {
17
+ ...process.env,
18
+ ...opts.env,
19
+ // Keep the tool from picking up ambient credentials or an interactive
20
+ // path: a conformance run must be reproducible on any machine.
21
+ NO_COLOR: '1',
22
+ CI: '1',
23
+ },
24
+ }, (error, stdout, stderr) => {
25
+ const err = error;
26
+ const timedOut = Boolean(err?.killed) || err?.code === 'ETIMEDOUT';
27
+ resolve({
28
+ argv,
29
+ commandLine: [opts.command, ...argv].join(' '),
30
+ stdout: String(stdout),
31
+ stderr: String(stderr),
32
+ exitCode: timedOut ? null : typeof err?.code === 'number' ? err.code : 0,
33
+ timedOut,
34
+ durationMs: Date.now() - started,
35
+ });
36
+ });
37
+ });
38
+ }
39
+ //# sourceMappingURL=exec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.js","sourceRoot":"","sources":["../src/exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAuB9C;;;;;GAKG;AACH,MAAM,UAAU,MAAM,CAAC,IAAiB,EAAE,IAAuB;IAC/D,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE3B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,QAAQ,CACN,IAAI,CAAC,OAAO,EACZ,IAAI,EACJ;YACE,OAAO,EAAE,IAAI,CAAC,SAAS,IAAI,MAAM;YACjC,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;YAC3B,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACpD,GAAG,EAAE;gBACH,GAAG,OAAO,CAAC,GAAG;gBACd,GAAG,IAAI,CAAC,GAAG;gBACX,sEAAsE;gBACtE,+DAA+D;gBAC/D,QAAQ,EAAE,GAAG;gBACb,EAAE,EAAE,GAAG;aACR;SACF,EACD,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YACxB,MAAM,GAAG,GAAG,KAAsE,CAAC;YACnF,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,GAAG,EAAE,IAAI,KAAK,WAAW,CAAC;YACnE,OAAO,CAAC;gBACN,IAAI;gBACJ,WAAW,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;gBAC9C,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;gBACtB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;gBACtB,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,GAAG,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACxE,QAAQ;gBACR,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO;aACjC,CAAC,CAAC;QACL,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { runChecks } from './checks.js';
2
+ export type { CheckResult, CheckStatus, CheckContext } from './checks.js';
3
+ export { summarise, renderReport } from './report.js';
4
+ export type { Report } from './report.js';
5
+ export { invoke } from './exec.js';
6
+ export type { Invocation, ExecOptions } from './exec.js';
7
+ export { conformanceMain } from './cli.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE1E,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACtD,YAAY,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAEzD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { runChecks } from './checks.js';
2
+ export { summarise, renderReport } from './report.js';
3
+ export { invoke } from './exec.js';
4
+ export { conformanceMain } from './cli.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGxC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGtD,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAGnC,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { CheckResult } from './checks.js';
2
+ export interface Report {
3
+ command: string;
4
+ passed: number;
5
+ failed: number;
6
+ warnings: number;
7
+ skipped: number;
8
+ ok: boolean;
9
+ checks: CheckResult[];
10
+ }
11
+ export declare function summarise(command: string, checks: CheckResult[]): Report;
12
+ export declare function renderReport(report: Report): string;
13
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAe,MAAM,aAAa,CAAC;AAE5D,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAYxE;AASD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAgCnD"}
package/dist/report.js ADDED
@@ -0,0 +1,74 @@
1
+ export function summarise(command, checks) {
2
+ const count = (s) => checks.filter((c) => c.status === s).length;
3
+ const failed = count('fail');
4
+ return {
5
+ command,
6
+ passed: count('pass'),
7
+ failed,
8
+ warnings: count('warn'),
9
+ skipped: count('skip'),
10
+ ok: failed === 0,
11
+ checks,
12
+ };
13
+ }
14
+ const GLYPH = {
15
+ pass: '✓',
16
+ fail: '✗',
17
+ warn: '!',
18
+ skip: '–',
19
+ };
20
+ export function renderReport(report) {
21
+ const lines = [];
22
+ lines.push('');
23
+ lines.push(`invokable conformance — ${report.command}`);
24
+ lines.push('');
25
+ for (const check of report.checks) {
26
+ lines.push(` ${GLYPH[check.status]} ${check.title}`);
27
+ if (check.detail && check.status !== 'pass') {
28
+ for (const line of wrap(check.detail, 70))
29
+ lines.push(` ${line}`);
30
+ }
31
+ else if (check.detail) {
32
+ lines.push(` ${check.detail}`);
33
+ }
34
+ // The rationale is shown only on failure: it is the part that tells someone
35
+ // why the contract cares, which is what they need when deciding to fix it.
36
+ if (check.status === 'fail' || check.status === 'warn') {
37
+ for (const line of wrap(`Why: ${check.rationale}`, 70))
38
+ lines.push(` ${line}`);
39
+ if (check.invocations.length) {
40
+ lines.push(` Reproduce: ${check.invocations[0]}`);
41
+ }
42
+ lines.push('');
43
+ }
44
+ }
45
+ lines.push('');
46
+ const parts = [`${report.passed} passed`];
47
+ if (report.failed)
48
+ parts.push(`${report.failed} failed`);
49
+ if (report.warnings)
50
+ parts.push(`${report.warnings} warning${report.warnings === 1 ? '' : 's'}`);
51
+ if (report.skipped)
52
+ parts.push(`${report.skipped} skipped`);
53
+ lines.push(` ${parts.join(', ')}`);
54
+ lines.push('');
55
+ return lines.join('\n');
56
+ }
57
+ function wrap(text, width) {
58
+ const out = [];
59
+ let line = '';
60
+ for (const word of text.split(/\s+/)) {
61
+ if (line === '')
62
+ line = word;
63
+ else if ((line + ' ' + word).length <= width)
64
+ line += ' ' + word;
65
+ else {
66
+ out.push(line);
67
+ line = word;
68
+ }
69
+ }
70
+ if (line)
71
+ out.push(line);
72
+ return out;
73
+ }
74
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAYA,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,MAAqB;IAC9D,MAAM,KAAK,GAAG,CAAC,CAAc,EAAU,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IACtF,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7B,OAAO;QACL,OAAO;QACP,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;QACrB,MAAM;QACN,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC;QACvB,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC;QACtB,EAAE,EAAE,MAAM,KAAK,CAAC;QAChB,MAAM;KACP,CAAC;AACJ,CAAC;AAED,MAAM,KAAK,GAAgC;IACzC,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;CACV,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,2BAA2B,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IACxD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;QACtD,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC5C,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;QACzE,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACtC,CAAC;QACD,4EAA4E;QAC5E,2EAA2E;QAC3E,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YACvD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;YACpF,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;gBAC7B,KAAK,CAAC,IAAI,CAAC,oBAAoB,KAAK,CAAC,WAAW,CAAC,CAAC,CAAE,EAAE,CAAC,CAAC;YAC1D,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC;IAC1C,IAAI,MAAM,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC;IACzD,IAAI,MAAM,CAAC,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,WAAW,MAAM,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACjG,IAAI,MAAM,CAAC,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;IAC5D,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,IAAI,CAAC,IAAY,EAAE,KAAa;IACvC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACrC,IAAI,IAAI,KAAK,EAAE;YAAE,IAAI,GAAG,IAAI,CAAC;aACxB,IAAI,CAAC,IAAI,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC,MAAM,IAAI,KAAK;YAAE,IAAI,IAAI,GAAG,GAAG,IAAI,CAAC;aAC5D,CAAC;YACJ,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACf,IAAI,GAAG,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,IAAI,IAAI;QAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,OAAO,GAAG,CAAC;AACb,CAAC"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@invokable/conformance",
3
+ "version": "0.1.0",
4
+ "description": "Checks that a CLI honours the invokable agent contract.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=20"
9
+ },
10
+ "bin": {
11
+ "invokable-test": "./bin/invokable-test.mjs"
12
+ },
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js"
17
+ }
18
+ },
19
+ "main": "./dist/index.js",
20
+ "types": "./dist/index.d.ts",
21
+ "files": [
22
+ "dist",
23
+ "bin",
24
+ "LICENSE"
25
+ ],
26
+ "dependencies": {
27
+ "@invokable/core": "^0.1.0"
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/beinvokable/invokable.git",
32
+ "directory": "packages/conformance"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc -b",
39
+ "clean": "rm -rf dist *.tsbuildinfo"
40
+ }
41
+ }