@executablemd/cli 0.3.1 → 0.4.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/esm/deno.js +16 -12
- package/esm/src/cli.js +55 -29
- package/package.json +4 -3
- package/types/deno.d.ts +4 -0
package/esm/deno.js
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
"name": "@executablemd/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"exports": "./src/cli.ts",
|
|
5
5
|
"imports": {
|
|
6
6
|
"@types/node": "npm:@types/node@^24.5.2",
|
|
7
7
|
"@durable-streams/client": "npm:@durable-streams/client@^0.2.2",
|
|
8
|
-
"@effectionx/bdd/node": "file:///
|
|
9
|
-
"@effectionx/bdd/expect": "file:///
|
|
8
|
+
"@effectionx/bdd/node": "file:///Users/tarasmankovski/Repositories/taras/executable-markdown-agents/.claude/worktrees/fix-dnt-jsr-registry/test-support/bdd.ts",
|
|
9
|
+
"@effectionx/bdd/expect": "file:///Users/tarasmankovski/Repositories/taras/executable-markdown-agents/.claude/worktrees/fix-dnt-jsr-registry/test-support/expect.ts",
|
|
10
10
|
"@effectionx/test-adapter": "npm:@effectionx/test-adapter@0.7.4",
|
|
11
11
|
"effection": "npm:effection@4.1.0-alpha.7",
|
|
12
12
|
"effection/experimental": "npm:effection@4.1.0-alpha.7/experimental",
|
|
13
|
-
"@executablemd/durable-streams": "npm:@executablemd/durable-streams@^0.
|
|
14
|
-
"@executablemd/runtime": "npm:@executablemd/runtime@^0.
|
|
15
|
-
"@executablemd/
|
|
16
|
-
"@
|
|
13
|
+
"@executablemd/durable-streams": "npm:@executablemd/durable-streams@^0.4.0",
|
|
14
|
+
"@executablemd/runtime": "npm:@executablemd/runtime@^0.4.0",
|
|
15
|
+
"@executablemd/testing": "npm:@executablemd/testing@^0.4.0",
|
|
16
|
+
"@std/assert": "jsr:@std/assert@^1.0.17",
|
|
17
|
+
"ajv": "npm:ajv@^8.17.1",
|
|
18
|
+
"@executablemd/runtime/test": "file:///Users/tarasmankovski/Repositories/taras/executable-markdown-agents/.claude/worktrees/fix-dnt-jsr-registry/runtime/test/mod.ts",
|
|
19
|
+
"@executablemd/code-review-agent": "npm:@executablemd/code-review-agent@^0.4.0",
|
|
17
20
|
"@effectionx/context-api": "npm:@effectionx/context-api@0.6.0",
|
|
18
21
|
"@effectionx/converge": "npm:@effectionx/converge@0.1.4",
|
|
19
22
|
"@effectionx/fetch": "npm:@effectionx/fetch@0.2.0",
|
|
@@ -32,10 +35,11 @@ export default {
|
|
|
32
35
|
"oxlint-tsgolint": "npm:oxlint-tsgolint@^0.17",
|
|
33
36
|
"unist-util-select": "npm:unist-util-select@^5",
|
|
34
37
|
"mdast-util-to-string": "npm:mdast-util-to-string@^4",
|
|
35
|
-
"@executablemd/core": "npm:@executablemd/core@^0.
|
|
36
|
-
"@executablemd/core/": "npm:@executablemd/core@^0.
|
|
37
|
-
"@executablemd/durable-streams/": "npm:@executablemd/durable-streams@^0.
|
|
38
|
-
"@executablemd/runtime/": "npm:@executablemd/runtime@^0.
|
|
39
|
-
"@executablemd/
|
|
38
|
+
"@executablemd/core": "npm:@executablemd/core@^0.4.0",
|
|
39
|
+
"@executablemd/core/": "npm:@executablemd/core@^0.4.0/",
|
|
40
|
+
"@executablemd/durable-streams/": "npm:@executablemd/durable-streams@^0.4.0/",
|
|
41
|
+
"@executablemd/runtime/": "npm:@executablemd/runtime@^0.4.0/",
|
|
42
|
+
"@executablemd/testing/": "npm:@executablemd/testing@^0.4.0/",
|
|
43
|
+
"@executablemd/code-review-agent/": "npm:@executablemd/code-review-agent@^0.4.0/"
|
|
40
44
|
}
|
|
41
45
|
};
|
package/esm/src/cli.js
CHANGED
|
@@ -19,16 +19,11 @@ import { inspect } from "node:util";
|
|
|
19
19
|
import process from "node:process";
|
|
20
20
|
import { program, object, field, cli, commands } from "configliere";
|
|
21
21
|
import { z } from "zod";
|
|
22
|
-
import {
|
|
22
|
+
import { execute, useNormalizedOutput, useTerminalOutput } from "@executablemd/core";
|
|
23
|
+
import { installTestingVocabulary, TestFailureError, useTesting } from "@executablemd/testing";
|
|
23
24
|
import { FileStream } from "./file-stream.js";
|
|
24
25
|
import denoJson from "../deno.js";
|
|
25
|
-
// ---------------------------------------------------------------------------
|
|
26
|
-
// Workaround: field.default exists at runtime but is missing from the .d.ts
|
|
27
|
-
// ---------------------------------------------------------------------------
|
|
28
26
|
const defaults = (value) => (mods) => ({ ...mods, default: value });
|
|
29
|
-
// ---------------------------------------------------------------------------
|
|
30
|
-
// Program schema
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
27
|
const runConfig = object({
|
|
33
28
|
docPath: {
|
|
34
29
|
description: "markdown document to execute",
|
|
@@ -53,14 +48,35 @@ const runConfig = object({
|
|
|
53
48
|
...field(z.boolean(), defaults(false)),
|
|
54
49
|
},
|
|
55
50
|
});
|
|
51
|
+
const testConfig = object({
|
|
52
|
+
docPath: {
|
|
53
|
+
description: "markdown document to test",
|
|
54
|
+
...field(z.string(), cli.argument()),
|
|
55
|
+
},
|
|
56
|
+
componentDir: {
|
|
57
|
+
description: "component search directory",
|
|
58
|
+
...field(z.array(z.string()), defaults(["components", "."]), field.array()),
|
|
59
|
+
},
|
|
60
|
+
verbose: {
|
|
61
|
+
description: "log journal entries to stderr",
|
|
62
|
+
aliases: ["-V"],
|
|
63
|
+
...field(z.boolean(), defaults(false)),
|
|
64
|
+
},
|
|
65
|
+
journal: {
|
|
66
|
+
description: "write a diagnostic JSONL trace (path must not exist)",
|
|
67
|
+
aliases: ["-j"],
|
|
68
|
+
...field(z.string().optional()),
|
|
69
|
+
},
|
|
70
|
+
raw: {
|
|
71
|
+
description: "output raw markdown without normalization or terminal formatting",
|
|
72
|
+
...field(z.boolean(), defaults(false)),
|
|
73
|
+
},
|
|
74
|
+
});
|
|
56
75
|
const xmd = program({
|
|
57
76
|
name: "xmd",
|
|
58
77
|
version: denoJson.version,
|
|
59
|
-
config: commands({ run: runConfig }, { default: "run" }),
|
|
78
|
+
config: commands({ run: runConfig, test: testConfig }, { default: "run" }),
|
|
60
79
|
});
|
|
61
|
-
// ---------------------------------------------------------------------------
|
|
62
|
-
// Journal entry formatting
|
|
63
|
-
// ---------------------------------------------------------------------------
|
|
64
80
|
const pretty = (value) => inspect(value, {
|
|
65
81
|
colors: true,
|
|
66
82
|
compact: true,
|
|
@@ -97,9 +113,6 @@ function summarizeEvent(event) {
|
|
|
97
113
|
const detail = status === "err" && "error" in event.result ? ` (${event.result.error.message})` : "";
|
|
98
114
|
return `[close] ${event.coroutineId} → ${status}${detail}`;
|
|
99
115
|
}
|
|
100
|
-
// ---------------------------------------------------------------------------
|
|
101
|
-
// Document runner
|
|
102
|
-
// ---------------------------------------------------------------------------
|
|
103
116
|
function* createJournalFile(filePath) {
|
|
104
117
|
let handle;
|
|
105
118
|
try {
|
|
@@ -115,7 +128,7 @@ function* createJournalFile(filePath) {
|
|
|
115
128
|
}
|
|
116
129
|
yield* until(handle.close());
|
|
117
130
|
}
|
|
118
|
-
function* run(config) {
|
|
131
|
+
function* run(config, mode) {
|
|
119
132
|
const { docPath, componentDir, verbose, journal, raw } = config;
|
|
120
133
|
// Every CLI invocation starts from an empty stream. --journal writes
|
|
121
134
|
// current-run diagnostics only; existing traces are never loaded.
|
|
@@ -147,22 +160,23 @@ function* run(config) {
|
|
|
147
160
|
}
|
|
148
161
|
})
|
|
149
162
|
: spawn(function* () { });
|
|
150
|
-
// ---------------------------------------------------------------------------
|
|
151
|
-
// Output middleware (spec §9).
|
|
152
|
-
//
|
|
153
|
-
// Middleware is installed on the DocumentOutput Api via Api.around() before
|
|
154
|
-
// runDocument is called. runDocument owns the channel internally —
|
|
155
|
-
// the CLI just installs transformations and consumes the returned stream.
|
|
156
|
-
// ---------------------------------------------------------------------------
|
|
157
163
|
if (!raw) {
|
|
158
164
|
yield* useNormalizedOutput();
|
|
159
165
|
}
|
|
160
166
|
if (process.stdout.isTTY && !raw) {
|
|
161
167
|
yield* useTerminalOutput();
|
|
162
168
|
}
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
|
|
169
|
+
// Compose testing around the single core execution entrypoint: both
|
|
170
|
+
// commands register the vocabulary (assertions work in regular documents,
|
|
171
|
+
// explicit <Testing> boundaries affect the outcome), while `xmd test`
|
|
172
|
+
// additionally activates root testing through a useTesting() session.
|
|
173
|
+
if (mode.testing) {
|
|
174
|
+
yield* useTesting({ verbose });
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
yield* installTestingVocabulary({ verbose });
|
|
178
|
+
}
|
|
179
|
+
const execution = yield* execute({
|
|
166
180
|
docPath,
|
|
167
181
|
stream,
|
|
168
182
|
componentDirs: componentDir,
|
|
@@ -184,10 +198,19 @@ function* run(config) {
|
|
|
184
198
|
signal.close();
|
|
185
199
|
yield* writer;
|
|
186
200
|
}
|
|
201
|
+
// Inspect the completion Result AFTER the report finished streaming:
|
|
202
|
+
// test failures, assertion aborts, and any document abort exit nonzero.
|
|
203
|
+
const result = yield* execution;
|
|
204
|
+
if (!result.ok) {
|
|
205
|
+
if (result.error instanceof TestFailureError) {
|
|
206
|
+
console.error(`\ntests failed: ${result.error.message}`);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
console.error(result.error.message);
|
|
210
|
+
}
|
|
211
|
+
yield* exit(1);
|
|
212
|
+
}
|
|
187
213
|
}
|
|
188
|
-
// ---------------------------------------------------------------------------
|
|
189
|
-
// Entry point
|
|
190
|
-
// ---------------------------------------------------------------------------
|
|
191
214
|
await main(function* (args) {
|
|
192
215
|
const parser = xmd.createParser({ args });
|
|
193
216
|
switch (parser.type) {
|
|
@@ -208,7 +231,10 @@ await main(function* (args) {
|
|
|
208
231
|
}
|
|
209
232
|
switch (parsed.value.name) {
|
|
210
233
|
case "run":
|
|
211
|
-
yield* run(parsed.value.config);
|
|
234
|
+
yield* run(parsed.value.config, { testing: false });
|
|
235
|
+
break;
|
|
236
|
+
case "test":
|
|
237
|
+
yield* run(parsed.value.config, { testing: true });
|
|
212
238
|
break;
|
|
213
239
|
}
|
|
214
240
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@executablemd/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "The xmd command-line interface for executable.md.",
|
|
5
5
|
"homepage": "https://executable.md",
|
|
6
6
|
"repository": {
|
|
@@ -17,8 +17,9 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@effectionx/stream-helpers": "0.8.3",
|
|
20
|
-
"@executablemd/core": "^0.
|
|
21
|
-
"@executablemd/durable-streams": "^0.
|
|
20
|
+
"@executablemd/core": "^0.4.0",
|
|
21
|
+
"@executablemd/durable-streams": "^0.4.0",
|
|
22
|
+
"@executablemd/testing": "^0.4.0",
|
|
22
23
|
"configliere": "^0.2.3",
|
|
23
24
|
"effection": "4.1.0-alpha.7",
|
|
24
25
|
"zod": "^4.3.6"
|
package/types/deno.d.ts
CHANGED
|
@@ -12,6 +12,9 @@ declare namespace _default {
|
|
|
12
12
|
"effection/experimental": string;
|
|
13
13
|
"@executablemd/durable-streams": string;
|
|
14
14
|
"@executablemd/runtime": string;
|
|
15
|
+
"@executablemd/testing": string;
|
|
16
|
+
"@std/assert": string;
|
|
17
|
+
ajv: string;
|
|
15
18
|
"@executablemd/runtime/test": string;
|
|
16
19
|
"@executablemd/code-review-agent": string;
|
|
17
20
|
"@effectionx/context-api": string;
|
|
@@ -36,6 +39,7 @@ declare namespace _default {
|
|
|
36
39
|
"@executablemd/core/": string;
|
|
37
40
|
"@executablemd/durable-streams/": string;
|
|
38
41
|
"@executablemd/runtime/": string;
|
|
42
|
+
"@executablemd/testing/": string;
|
|
39
43
|
"@executablemd/code-review-agent/": string;
|
|
40
44
|
};
|
|
41
45
|
}
|