@acid-cat/cli 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/catalog.js +111 -0
- package/dist/conform/check.js +51 -0
- package/dist/conform/cli.js +112 -0
- package/dist/conform/http.js +97 -0
- package/dist/conform/index.js +37 -0
- package/dist/conform/mcp.js +127 -0
- package/dist/conform/properties.js +98 -0
- package/dist/conform/serve.js +62 -0
- package/dist/conform/webmcp.js +179 -0
- package/dist/index.js +5 -16
- package/dist/json/catalog.schema.json.js +117 -0
- package/dist/json/fixture.acidcat.json.js +105 -0
- package/dist/json/package.json.js +4 -0
- package/dist/main.js +92 -185
- package/package.json +6 -5
- package/dist/chunks/chunk-VZ6KDZEL.js +0 -1018
package/dist/main.js
CHANGED
|
@@ -1,191 +1,98 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
viewOf
|
|
6
|
-
} from "./chunks/chunk-VZ6KDZEL.js";
|
|
7
|
-
|
|
8
|
-
// src/main.ts
|
|
9
|
-
import { NodeRuntime, NodeServices } from "@effect/platform-node";
|
|
2
|
+
import { check, viewOf } from "./catalog.js";
|
|
3
|
+
import { conform } from "./conform/index.js";
|
|
4
|
+
import { version } from "./json/package.json.js";
|
|
10
5
|
import { canonicalText } from "@acid-cat/catalog";
|
|
11
6
|
import { Console, Effect, FileSystem, Option } from "effect";
|
|
7
|
+
import { NodeRuntime, NodeServices } from "@effect/platform-node";
|
|
12
8
|
import { Argument, Command, Flag } from "effect/cli";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
repository: {
|
|
26
|
-
type: "git",
|
|
27
|
-
url: "git+https://github.com/Hebilicious/acidcat.git",
|
|
28
|
-
directory: "packages/cli"
|
|
29
|
-
},
|
|
30
|
-
homepage: "https://github.com/Hebilicious/acidcat/tree/main/packages/cli#readme",
|
|
31
|
-
bugs: "https://github.com/Hebilicious/acidcat/issues",
|
|
32
|
-
type: "module",
|
|
33
|
-
engines: {
|
|
34
|
-
node: ">=24"
|
|
35
|
-
},
|
|
36
|
-
files: [
|
|
37
|
-
"dist",
|
|
38
|
-
"conformance/fixture.acidcat.json"
|
|
39
|
-
],
|
|
40
|
-
bin: {
|
|
41
|
-
"acid-cat": "./src/main.ts"
|
|
42
|
-
},
|
|
43
|
-
exports: {
|
|
44
|
-
".": "./src/index.ts",
|
|
45
|
-
"./conformance/fixture.acidcat.json": "./conformance/fixture.acidcat.json"
|
|
46
|
-
},
|
|
47
|
-
publishConfig: {
|
|
48
|
-
access: "public",
|
|
49
|
-
exports: {
|
|
50
|
-
".": {
|
|
51
|
-
types: "./dist/index.d.ts",
|
|
52
|
-
default: "./dist/index.js"
|
|
53
|
-
},
|
|
54
|
-
"./conformance/fixture.acidcat.json": "./conformance/fixture.acidcat.json"
|
|
55
|
-
},
|
|
56
|
-
bin: {
|
|
57
|
-
"acid-cat": "./dist/main.js"
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
dependencies: {
|
|
61
|
-
"@acid-cat/catalog": "workspace:*",
|
|
62
|
-
"@acid-cat/spec-ts": "workspace:*",
|
|
63
|
-
"@effect/platform-node": "catalog:",
|
|
64
|
-
"@modelcontextprotocol/client": "catalog:",
|
|
65
|
-
effect: "catalog:",
|
|
66
|
-
"fast-check": "catalog:"
|
|
67
|
-
},
|
|
68
|
-
peerDependencies: {
|
|
69
|
-
playwright: "catalog:peers"
|
|
70
|
-
},
|
|
71
|
-
peerDependenciesMeta: {
|
|
72
|
-
playwright: {
|
|
73
|
-
optional: true
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
devDependencies: {
|
|
77
|
-
"@types/node": "catalog:",
|
|
78
|
-
playwright: "catalog:",
|
|
79
|
-
typescript: "catalog:"
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
// src/main.ts
|
|
84
|
-
var readCatalog = Effect.fn("readCatalog")(function* (file) {
|
|
85
|
-
const fs = yield* FileSystem.FileSystem;
|
|
86
|
-
const text = yield* fs.readFileString(file);
|
|
87
|
-
return { text, document: JSON.parse(text) };
|
|
9
|
+
//#region src/main.ts
|
|
10
|
+
/**
|
|
11
|
+
* `acid-cat`: check, format and view AcidCat catalogs.
|
|
12
|
+
*
|
|
13
|
+
* Exit codes: 0 when the command succeeds, 1 when a catalog does not conform or a file is not found.
|
|
14
|
+
*/
|
|
15
|
+
const readCatalog = Effect.fn("readCatalog")(function* (file) {
|
|
16
|
+
const text = yield* (yield* FileSystem.FileSystem).readFileString(file);
|
|
17
|
+
return {
|
|
18
|
+
text,
|
|
19
|
+
document: JSON.parse(text)
|
|
20
|
+
};
|
|
88
21
|
});
|
|
89
|
-
|
|
90
|
-
|
|
22
|
+
const fail = Effect.sync(() => {
|
|
23
|
+
process.exitCode = 1;
|
|
91
24
|
});
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
maximumBytes: options.maximumBytes
|
|
167
|
-
})
|
|
168
|
-
);
|
|
169
|
-
if (results.length === 0) {
|
|
170
|
-
yield* Console.error("Give at least one binding: --mcp, --http, --cli or --webmcp.");
|
|
171
|
-
return yield* fail;
|
|
172
|
-
}
|
|
173
|
-
for (const result of results) {
|
|
174
|
-
yield* Console.log(`${result.passed ? "\u2713" : "\u2717"} ${result.binding}: ${result.name} (${result.rule})${result.detail ? `
|
|
175
|
-
${result.detail}` : ""}`);
|
|
176
|
-
}
|
|
177
|
-
const failed = results.filter((result) => !result.passed).length;
|
|
178
|
-
yield* Console.log(`
|
|
179
|
-
${results.length - failed} passed, ${failed} failed.`);
|
|
180
|
-
if (failed > 0) return yield* fail;
|
|
181
|
-
})
|
|
182
|
-
).pipe(Command.withDescription("Test a running implementation of the conformance fixture through its bindings."));
|
|
183
|
-
var acidCat = Command.make("acid-cat").pipe(
|
|
184
|
-
Command.withDescription("Check, format and view AcidCat catalogs, and test implementations."),
|
|
185
|
-
Command.withSubcommands([checkCommand, formatCommand, viewCommand, conformCommand])
|
|
186
|
-
);
|
|
187
|
-
acidCat.pipe(
|
|
188
|
-
Command.run({ version: package_default.version }),
|
|
189
|
-
Effect.provide(NodeServices.layer),
|
|
190
|
-
NodeRuntime.runMain
|
|
191
|
-
);
|
|
25
|
+
const files = Argument.String("catalog").pipe(Argument.withDescription("A catalog file, such as acidcat.catalog.json"), Argument.variadic({ min: 1 }));
|
|
26
|
+
const checkCommand = Command.make("check", {
|
|
27
|
+
files,
|
|
28
|
+
strict: Flag.Boolean("strict").pipe(Flag.withDescription("Fail on warnings too"), Flag.withDefault(false))
|
|
29
|
+
}, Effect.fn(function* ({ files, strict }) {
|
|
30
|
+
let failed = false;
|
|
31
|
+
for (const file of files) {
|
|
32
|
+
const { text, document } = yield* readCatalog(file);
|
|
33
|
+
const report = check(document, text);
|
|
34
|
+
for (const error of report.errors) yield* Console.error(`${file}: error: ${error}`);
|
|
35
|
+
for (const warning of report.warnings) yield* Console.error(`${file}: warning: ${warning}`);
|
|
36
|
+
failed ||= report.errors.length > 0 || strict && report.warnings.length > 0;
|
|
37
|
+
}
|
|
38
|
+
if (failed) return yield* fail;
|
|
39
|
+
yield* Console.log(files.length === 1 ? "The catalog conforms." : "Every catalog conforms.");
|
|
40
|
+
})).pipe(Command.withDescription("Check that catalogs conform to the specification."));
|
|
41
|
+
const formatCommand = Command.make("format", {
|
|
42
|
+
files,
|
|
43
|
+
write: Flag.Boolean("write").pipe(Flag.withDescription("Rewrite each file instead of printing it"), Flag.withDefault(false))
|
|
44
|
+
}, Effect.fn(function* ({ files, write }) {
|
|
45
|
+
const fs = yield* FileSystem.FileSystem;
|
|
46
|
+
for (const file of files) {
|
|
47
|
+
const { document } = yield* readCatalog(file);
|
|
48
|
+
const text = canonicalText(document);
|
|
49
|
+
if (write) yield* fs.writeFileString(file, text);
|
|
50
|
+
else yield* Effect.sync(() => process.stdout.write(text));
|
|
51
|
+
}
|
|
52
|
+
})).pipe(Command.withDescription("Write catalogs in canonical form."));
|
|
53
|
+
const viewCommand = Command.make("view", {
|
|
54
|
+
file: Argument.String("catalog").pipe(Argument.withDescription("A catalog file")),
|
|
55
|
+
target: Argument.String("target").pipe(Argument.withDescription("The name of a target in the catalog"))
|
|
56
|
+
}, Effect.fn(function* ({ file, target }) {
|
|
57
|
+
const { document } = yield* readCatalog(file);
|
|
58
|
+
const catalog = document;
|
|
59
|
+
if (!(target in catalog.targets)) {
|
|
60
|
+
yield* Console.error(`${file}: error: there is no target ${target}`);
|
|
61
|
+
return yield* fail;
|
|
62
|
+
}
|
|
63
|
+
yield* Effect.sync(() => process.stdout.write(canonicalText(viewOf(catalog, target))));
|
|
64
|
+
})).pipe(Command.withDescription("Print the view of one target."));
|
|
65
|
+
const url = (name, description) => Flag.String(name).pipe(Flag.withDescription(description), Flag.optional);
|
|
66
|
+
const conformCommand = Command.make("conform", {
|
|
67
|
+
mcp: url("mcp", "The URL of the MCP server"),
|
|
68
|
+
http: url("http", "The base URL of the HTTP API, before /capabilities"),
|
|
69
|
+
cli: url("cli", "The command that starts the command line, for example \"node fixture-cli.ts\""),
|
|
70
|
+
webmcp: url("webmcp", "The URL of a web page that serves the app target. It runs in Chromium, through Playwright"),
|
|
71
|
+
maximumBytes: Flag.Int("max-bytes").pipe(Flag.withDescription("The body limit of the remote bindings"), Flag.withDefault(1048576))
|
|
72
|
+
}, Effect.fn(function* (options) {
|
|
73
|
+
const value = (option) => Option.isSome(option) ? option.value : void 0;
|
|
74
|
+
const command = value(options.cli)?.split(/\s+/).filter((word) => word !== "");
|
|
75
|
+
const results = yield* Effect.promise(() => conform({
|
|
76
|
+
mcp: value(options.mcp),
|
|
77
|
+
http: value(options.http),
|
|
78
|
+
cli: command,
|
|
79
|
+
webmcp: value(options.webmcp),
|
|
80
|
+
maximumBytes: options.maximumBytes
|
|
81
|
+
}));
|
|
82
|
+
if (results.length === 0) {
|
|
83
|
+
yield* Console.error("Give at least one binding: --mcp, --http, --cli or --webmcp.");
|
|
84
|
+
return yield* fail;
|
|
85
|
+
}
|
|
86
|
+
for (const result of results) yield* Console.log(`${result.passed ? "✓" : "✗"} ${result.binding}: ${result.name} (${result.rule})${result.detail ? `\n ${result.detail}` : ""}`);
|
|
87
|
+
const failed = results.filter((result) => !result.passed).length;
|
|
88
|
+
yield* Console.log(`\n${results.length - failed} passed, ${failed} failed.`);
|
|
89
|
+
if (failed > 0) return yield* fail;
|
|
90
|
+
})).pipe(Command.withDescription("Test a running implementation of the conformance fixture through its bindings."));
|
|
91
|
+
Command.make("acid-cat").pipe(Command.withDescription("Check, format and view AcidCat catalogs, and test implementations."), Command.withSubcommands([
|
|
92
|
+
checkCommand,
|
|
93
|
+
formatCommand,
|
|
94
|
+
viewCommand,
|
|
95
|
+
conformCommand
|
|
96
|
+
])).pipe(Command.run({ version }), Effect.provide(NodeServices.layer), NodeRuntime.runMain);
|
|
97
|
+
//#endregion
|
|
98
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acid-cat/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "The AcidCat command line: check, format and view catalogs, and test implementations.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"acidcat",
|
|
@@ -37,11 +37,12 @@
|
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@acid-cat/catalog": "0.
|
|
41
|
-
"@acid-cat/spec-ts": "0.
|
|
42
|
-
"@effect/platform-node": "4.0.
|
|
40
|
+
"@acid-cat/catalog": "0.2.0",
|
|
41
|
+
"@acid-cat/spec-ts": "0.2.0",
|
|
42
|
+
"@effect/platform-node": "4.0.4",
|
|
43
|
+
"@effect/platform-node-shared": "4.0.4",
|
|
43
44
|
"@modelcontextprotocol/client": "2.3.1",
|
|
44
|
-
"effect": "4.0.
|
|
45
|
+
"effect": "4.0.4",
|
|
45
46
|
"fast-check": "4.10.2"
|
|
46
47
|
},
|
|
47
48
|
"peerDependencies": {
|