@acid-cat/cli 0.1.0 → 0.3.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/main.js CHANGED
@@ -1,191 +1,98 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- check,
4
- conform,
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
- // package.json
15
- var package_default = {
16
- name: "@acid-cat/cli",
17
- version: "0.1.0",
18
- description: "The AcidCat command line: check, format and view catalogs, and test implementations.",
19
- keywords: [
20
- "acidcat",
21
- "cli",
22
- "conformance"
23
- ],
24
- license: "MIT",
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
- var fail = Effect.sync(() => {
90
- process.exitCode = 1;
22
+ const fail = Effect.sync(() => {
23
+ process.exitCode = 1;
91
24
  });
92
- var files = Argument.String("catalog").pipe(
93
- Argument.withDescription("A catalog file, such as acidcat.catalog.json"),
94
- Argument.variadic({ min: 1 })
95
- );
96
- var checkCommand = Command.make(
97
- "check",
98
- {
99
- files,
100
- strict: Flag.Boolean("strict").pipe(Flag.withDescription("Fail on warnings too"), Flag.withDefault(false))
101
- },
102
- Effect.fn(function* ({ files: files2, strict }) {
103
- let failed = false;
104
- for (const file of files2) {
105
- const { text, document } = yield* readCatalog(file);
106
- const report = check(document, text);
107
- for (const error of report.errors) yield* Console.error(`${file}: error: ${error}`);
108
- for (const warning of report.warnings) yield* Console.error(`${file}: warning: ${warning}`);
109
- failed ||= report.errors.length > 0 || strict && report.warnings.length > 0;
110
- }
111
- if (failed) return yield* fail;
112
- yield* Console.log(files2.length === 1 ? "The catalog conforms." : "Every catalog conforms.");
113
- })
114
- ).pipe(Command.withDescription("Check that catalogs conform to the specification."));
115
- var formatCommand = Command.make(
116
- "format",
117
- {
118
- files,
119
- write: Flag.Boolean("write").pipe(Flag.withDescription("Rewrite each file instead of printing it"), Flag.withDefault(false))
120
- },
121
- Effect.fn(function* ({ files: files2, write }) {
122
- const fs = yield* FileSystem.FileSystem;
123
- for (const file of files2) {
124
- const { document } = yield* readCatalog(file);
125
- const text = canonicalText(document);
126
- if (write) yield* fs.writeFileString(file, text);
127
- else yield* Effect.sync(() => process.stdout.write(text));
128
- }
129
- })
130
- ).pipe(Command.withDescription("Write catalogs in canonical form."));
131
- var viewCommand = Command.make(
132
- "view",
133
- {
134
- file: Argument.String("catalog").pipe(Argument.withDescription("A catalog file")),
135
- target: Argument.String("target").pipe(Argument.withDescription("The name of a target in the catalog"))
136
- },
137
- Effect.fn(function* ({ file, target }) {
138
- const { document } = yield* readCatalog(file);
139
- const catalog = document;
140
- if (!(target in catalog.targets)) {
141
- yield* Console.error(`${file}: error: there is no target ${target}`);
142
- return yield* fail;
143
- }
144
- yield* Effect.sync(() => process.stdout.write(canonicalText(viewOf(catalog, target))));
145
- })
146
- ).pipe(Command.withDescription("Print the view of one target."));
147
- var url = (name, description) => Flag.String(name).pipe(Flag.withDescription(description), Flag.optional);
148
- var conformCommand = Command.make(
149
- "conform",
150
- {
151
- mcp: url("mcp", "The URL of the MCP server"),
152
- http: url("http", "The base URL of the HTTP API, before /capabilities"),
153
- cli: url("cli", 'The command that starts the command line, for example "node fixture-cli.ts"'),
154
- webmcp: url("webmcp", "The URL of a web page that serves the app target. It runs in Chromium, through Playwright"),
155
- maximumBytes: Flag.Int("max-bytes").pipe(Flag.withDescription("The body limit of the remote bindings"), Flag.withDefault(1048576))
156
- },
157
- Effect.fn(function* (options) {
158
- const value = (option) => Option.isSome(option) ? option.value : void 0;
159
- const command = value(options.cli)?.split(/\s+/).filter((word) => word !== "");
160
- const results = yield* Effect.promise(
161
- () => conform({
162
- mcp: value(options.mcp),
163
- http: value(options.http),
164
- cli: command,
165
- webmcp: value(options.webmcp),
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.1.0",
3
+ "version": "0.3.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.1.0",
41
- "@acid-cat/spec-ts": "0.1.0",
42
- "@effect/platform-node": "4.0.3",
40
+ "@acid-cat/catalog": "0.3.0",
41
+ "@acid-cat/spec-ts": "0.3.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.3",
45
+ "effect": "4.0.4",
45
46
  "fast-check": "4.10.2"
46
47
  },
47
48
  "peerDependencies": {