@tscomfy/cli 0.0.0-stage → 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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +22 -2
  3. package/dist/args.d.ts +24 -0
  4. package/dist/args.d.ts.map +1 -0
  5. package/dist/args.js +66 -0
  6. package/dist/args.js.map +1 -0
  7. package/dist/check.d.ts +6 -0
  8. package/dist/check.d.ts.map +1 -0
  9. package/dist/check.js +185 -0
  10. package/dist/check.js.map +1 -0
  11. package/dist/generate.d.ts +17 -0
  12. package/dist/generate.d.ts.map +1 -0
  13. package/dist/generate.js +166 -0
  14. package/dist/generate.js.map +1 -0
  15. package/dist/index.d.ts +12 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +12 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/io.d.ts +26 -0
  20. package/dist/io.d.ts.map +1 -0
  21. package/dist/io.js +80 -0
  22. package/dist/io.js.map +1 -0
  23. package/dist/main.d.ts +3 -0
  24. package/dist/main.d.ts.map +1 -0
  25. package/dist/main.js +6 -0
  26. package/dist/main.js.map +1 -0
  27. package/dist/manifest.d.ts +47 -0
  28. package/dist/manifest.d.ts.map +1 -0
  29. package/dist/manifest.js +66 -0
  30. package/dist/manifest.js.map +1 -0
  31. package/dist/report.d.ts +13 -0
  32. package/dist/report.d.ts.map +1 -0
  33. package/dist/report.js +69 -0
  34. package/dist/report.js.map +1 -0
  35. package/dist/run.d.ts +9 -0
  36. package/dist/run.d.ts.map +1 -0
  37. package/dist/run.js +89 -0
  38. package/dist/run.js.map +1 -0
  39. package/dist/source.d.ts +28 -0
  40. package/dist/source.d.ts.map +1 -0
  41. package/dist/source.js +92 -0
  42. package/dist/source.js.map +1 -0
  43. package/dist/transpile.d.ts +6 -0
  44. package/dist/transpile.d.ts.map +1 -0
  45. package/dist/transpile.js +178 -0
  46. package/dist/transpile.js.map +1 -0
  47. package/dist/util.d.ts +33 -0
  48. package/dist/util.d.ts.map +1 -0
  49. package/dist/util.js +81 -0
  50. package/dist/util.js.map +1 -0
  51. package/package.json +56 -4
  52. package/src/args.ts +78 -0
  53. package/src/check.ts +224 -0
  54. package/src/generate.ts +198 -0
  55. package/src/index.ts +12 -0
  56. package/src/io.ts +99 -0
  57. package/src/main.ts +7 -0
  58. package/src/manifest.ts +105 -0
  59. package/src/report.ts +73 -0
  60. package/src/run.ts +90 -0
  61. package/src/source.ts +114 -0
  62. package/src/transpile.ts +201 -0
  63. package/src/util.ts +87 -0
package/dist/io.js ADDED
@@ -0,0 +1,80 @@
1
+ import { mkdir, readFile, realpath, rename, rm, writeFile } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+ import { errorBodyMessage, redactUrl } from "./util.js";
4
+ /** A failure to report to the user: a message, and the exit code to end with. */
5
+ export class CliError extends Error {
6
+ /** 1 for a failure, 2 for a usage error. */
7
+ exitCode;
8
+ /** A failure with `message`, ending the process with `exitCode`. */
9
+ constructor(message, exitCode = 1) {
10
+ super(message);
11
+ this.name = "CliError";
12
+ this.exitCode = exitCode;
13
+ }
14
+ }
15
+ const FETCH_TIMEOUT_MS = 60_000;
16
+ /** The real world: the process's streams, `fetch` and `node:fs`, which Node and Bun both have. */
17
+ export function systemIo() {
18
+ return {
19
+ out: (text) => {
20
+ process.stdout.write(text);
21
+ },
22
+ err: (text) => {
23
+ process.stderr.write(text);
24
+ },
25
+ fetchText: async (url) => {
26
+ const shown = redactUrl(new URL(url));
27
+ try {
28
+ const response = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });
29
+ if (!response.ok) {
30
+ const answer = `${String(response.status)} ${response.statusText}`.trimEnd();
31
+ // Best effort: the status says what went wrong; the body may say why.
32
+ const body = await response.text().catch(() => "");
33
+ const detail = errorBodyMessage(body);
34
+ throw new CliError(`${shown} answered ${answer}${detail === undefined ? "" : `: ${detail}`}`);
35
+ }
36
+ return await response.text();
37
+ }
38
+ catch (error) {
39
+ if (error instanceof CliError)
40
+ throw error;
41
+ throw new CliError(`Could not reach ${shown}: ${reason(error)}`);
42
+ }
43
+ },
44
+ readText: async (path) => {
45
+ try {
46
+ // TextDecoder drops a byte order mark, as editors that save one expect.
47
+ return new TextDecoder().decode(await readFile(path));
48
+ }
49
+ catch (error) {
50
+ if (codeOf(error) === "ENOENT")
51
+ return undefined;
52
+ throw new CliError(`Could not read ${path}: ${reason(error)}`);
53
+ }
54
+ },
55
+ writeText: async (path, text) => {
56
+ // Through a temporary file, so an interrupted run never leaves a file half written. One
57
+ // name per file, so a run that was killed leaves nothing a later run doesn't replace; and
58
+ // a symlink is followed, so the file it points to is the one replaced.
59
+ const target = await realpath(path).catch(() => path);
60
+ const temporary = `${target}.tmp`;
61
+ try {
62
+ await mkdir(dirname(target), { recursive: true });
63
+ await writeFile(temporary, text);
64
+ await rename(temporary, target);
65
+ }
66
+ catch (error) {
67
+ // Best effort: when the directory can't be made, there is nothing to remove.
68
+ await rm(temporary, { force: true }).catch(() => undefined);
69
+ throw new CliError(`Could not write ${path}: ${reason(error)}`);
70
+ }
71
+ },
72
+ };
73
+ }
74
+ function reason(error) {
75
+ return error instanceof Error ? error.message : String(error);
76
+ }
77
+ function codeOf(error) {
78
+ return typeof error === "object" && error !== null ? Reflect.get(error, "code") : undefined;
79
+ }
80
+ //# sourceMappingURL=io.js.map
package/dist/io.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"io.js","sourceRoot":"","sources":["../src/io.ts"],"names":[],"mappings":"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"}
package/dist/main.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""}
package/dist/main.js ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ // The `tscomfy` executable.
3
+ import { systemIo } from "./io.js";
4
+ import { run } from "./run.js";
5
+ process.exitCode = await run(process.argv.slice(2), systemIo());
6
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA,4BAA4B;AAE5B,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,OAAO,CAAC,QAAQ,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC"}
@@ -0,0 +1,47 @@
1
+ import type { Schema } from "@tscomfy/core";
2
+ import { type Io } from "./io.ts";
3
+ /** The record `generate` writes last, next to the files, for `check` and `transpile`. */
4
+ export declare const MANIFEST = "tscomfy.json";
5
+ /** The raw snapshot written next to the generated files, for `--from` and `check`. */
6
+ export declare const SNAPSHOT = "object_info.json";
7
+ /**
8
+ * What one `generate` run wrote: the codegen version, the schema hash, the options needed to
9
+ * regenerate, and a content hash of every file, so `check` notices an edited, missing or
10
+ * half-written file and output from another version.
11
+ */
12
+ export interface Manifest {
13
+ readonly codegen: string;
14
+ /** `hashSchema` of the snapshot (D15). */
15
+ readonly schema: string;
16
+ readonly exportName: string;
17
+ readonly importExtension: ".js" | ".ts";
18
+ /**
19
+ * The ComfyUI version of the snapshot, when known: the server's with `--url`, the
20
+ * `--comfy-version` given with `--from`. For regenerating from the snapshot, and for the
21
+ * command `check` suggests with `--from`.
22
+ */
23
+ readonly comfyVersion?: string;
24
+ /** `sha256:<hex>` of each file, by its name in the output directory: exactly {@link FILES}. */
25
+ readonly files: {
26
+ readonly [file: string]: string;
27
+ };
28
+ }
29
+ /** The files a manifest covers, in the order `check` reports them. */
30
+ export declare const FILES: readonly string[];
31
+ /** `sha256:<hex>` of a text's UTF-8 bytes. */
32
+ export declare function contentHash(text: string): string;
33
+ /** The manifest's file contents: stable key order, one trailing newline. */
34
+ export declare function formatManifest(manifest: Manifest): string;
35
+ /** The manifest in `out`, or `undefined` when there is none. Throws for one that isn't ours. */
36
+ export declare function readManifest(io: Io, out: string): Promise<Manifest | undefined>;
37
+ /** A directory `tscomfy generate` wrote: its manifest, and the snapshot normalized. */
38
+ export interface Generated {
39
+ readonly manifest: Manifest;
40
+ readonly snapshotPath: string;
41
+ /** The snapshot's text, exactly as written. */
42
+ readonly snapshotText: string;
43
+ readonly schema: Schema;
44
+ }
45
+ /** The manifest and snapshot in `dir`; fails when either is missing, or isn't ours. */
46
+ export declare function readGenerated(io: Io, dir: string): Promise<Generated>;
47
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAY,KAAK,EAAE,EAAE,MAAM,SAAS,CAAC;AAG5C,yFAAyF;AACzF,eAAO,MAAM,QAAQ,iBAAiB,CAAC;AAEvC,sFAAsF;AACtF,eAAO,MAAM,QAAQ,qBAAqB,CAAC;AAE3C;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,eAAe,EAAE,KAAK,GAAG,KAAK,CAAC;IACxC;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,+FAA+F;IAC/F,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;CACrD;AAED,sEAAsE;AACtE,eAAO,MAAM,KAAK,EAAE,SAAS,MAAM,EAAuC,CAAC;AAE3E,8CAA8C;AAC9C,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAEzD;AAED,gGAAgG;AAChG,wBAAsB,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAcrF;AAsBD,uFAAuF;AACvF,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,+CAA+C;IAC/C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,uFAAuF;AACvF,wBAAsB,aAAa,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAW3E"}
@@ -0,0 +1,66 @@
1
+ import { createHash } from "node:crypto";
2
+ import { join } from "node:path";
3
+ import { CliError } from "./io.js";
4
+ import { loadSchema } from "./source.js";
5
+ /** The record `generate` writes last, next to the files, for `check` and `transpile`. */
6
+ export const MANIFEST = "tscomfy.json";
7
+ /** The raw snapshot written next to the generated files, for `--from` and `check`. */
8
+ export const SNAPSHOT = "object_info.json";
9
+ /** The files a manifest covers, in the order `check` reports them. */
10
+ export const FILES = ["nodes.ts", "index.ts", SNAPSHOT];
11
+ /** `sha256:<hex>` of a text's UTF-8 bytes. */
12
+ export function contentHash(text) {
13
+ return `sha256:${createHash("sha256").update(text, "utf8").digest("hex")}`;
14
+ }
15
+ /** The manifest's file contents: stable key order, one trailing newline. */
16
+ export function formatManifest(manifest) {
17
+ return `${JSON.stringify(manifest, null, 2)}\n`;
18
+ }
19
+ /** The manifest in `out`, or `undefined` when there is none. Throws for one that isn't ours. */
20
+ export async function readManifest(io, out) {
21
+ const path = join(out, MANIFEST);
22
+ const text = await io.readText(path);
23
+ if (text === undefined)
24
+ return undefined;
25
+ let value;
26
+ try {
27
+ value = JSON.parse(text);
28
+ }
29
+ catch {
30
+ throw new CliError(`${path} is not JSON; run tscomfy generate again.`);
31
+ }
32
+ if (!isManifest(value)) {
33
+ throw new CliError(`${path} is not a tscomfy manifest; run tscomfy generate again.`);
34
+ }
35
+ return value;
36
+ }
37
+ function isManifest(value) {
38
+ if (typeof value !== "object" || value === null)
39
+ return false;
40
+ const field = (name) => Reflect.get(value, name);
41
+ const files = field("files");
42
+ const extension = field("importExtension");
43
+ const comfyVersion = field("comfyVersion");
44
+ return (typeof field("codegen") === "string" &&
45
+ typeof field("schema") === "string" &&
46
+ typeof field("exportName") === "string" &&
47
+ (extension === ".js" || extension === ".ts") &&
48
+ (comfyVersion === undefined || typeof comfyVersion === "string") &&
49
+ typeof files === "object" &&
50
+ files !== null &&
51
+ // Exactly our files: a hand-edited list must not hide one, or name a path outside `out`.
52
+ Object.keys(files).toSorted().join("\n") === FILES.toSorted().join("\n") &&
53
+ Object.values(files).every((hash) => typeof hash === "string"));
54
+ }
55
+ /** The manifest and snapshot in `dir`; fails when either is missing, or isn't ours. */
56
+ export async function readGenerated(io, dir) {
57
+ const manifest = await readManifest(io, dir);
58
+ const snapshotPath = join(dir, SNAPSHOT);
59
+ const snapshotText = await io.readText(snapshotPath);
60
+ if (manifest === undefined || snapshotText === undefined) {
61
+ throw new CliError(`There is no ${manifest === undefined ? MANIFEST : SNAPSHOT} in ${dir}; run tscomfy generate first.`);
62
+ }
63
+ const { schema } = loadSchema({ text: snapshotText, label: snapshotPath, flag: "" });
64
+ return { manifest, snapshotPath, snapshotText, schema };
65
+ }
66
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { type Diagnostic, type Schema } from "@tscomfy/core";
2
+ /**
3
+ * Diagnostics grouped by node pack (`python_module`; docs/plan.md §9), errors and warnings
4
+ * counted, at most a few lines per pack unless `verbose`.
5
+ */
6
+ export declare function reportDiagnostics(diagnostics: readonly Diagnostic[], schema: Schema, objectInfo: string, verbose: boolean): string;
7
+ /** One line for a diagnostic: its code, where, and what. */
8
+ export declare function formatDiagnostic(diagnostic: Diagnostic): string;
9
+ /** `1 warning`, `3 errors`. */
10
+ export declare function count(amount: number, noun: string): string;
11
+ /** A byte size for humans. */
12
+ export declare function size(bytes: number): 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,EAAE,KAAK,UAAU,EAAS,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAMpE;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,SAAS,UAAU,EAAE,EAClC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,GACf,MAAM,CAuBR;AAED,4DAA4D;AAC5D,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAE/D;AAED,+BAA+B;AAC/B,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,8BAA8B;AAC9B,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAI1C"}
package/dist/report.js ADDED
@@ -0,0 +1,69 @@
1
+ import { parse } from "@tscomfy/core";
2
+ import { isRecord } from "./util.js";
3
+ /** How many diagnostics a pack shows before the rest are summarized, unless verbose. */
4
+ const SHOWN_PER_PACK = 5;
5
+ /**
6
+ * Diagnostics grouped by node pack (`python_module`; docs/plan.md §9), errors and warnings
7
+ * counted, at most a few lines per pack unless `verbose`.
8
+ */
9
+ export function reportDiagnostics(diagnostics, schema, objectInfo, verbose) {
10
+ if (diagnostics.length === 0)
11
+ return "";
12
+ const packs = packsOf(schema, objectInfo);
13
+ const groups = new Map();
14
+ for (const diagnostic of diagnostics) {
15
+ const classType = String(diagnostic.path[0] ?? "");
16
+ const pack = packs.get(classType) ?? "(no pack)";
17
+ groups.set(pack, [...(groups.get(pack) ?? []), diagnostic]);
18
+ }
19
+ const errors = diagnostics.filter((diagnostic) => diagnostic.severity === "error").length;
20
+ const lines = [
21
+ `${count(errors, "error")} and ${count(diagnostics.length - errors, "warning")} in the node definitions:`,
22
+ ];
23
+ for (const pack of [...groups.keys()].toSorted()) {
24
+ const group = groups.get(pack) ?? [];
25
+ lines.push(` ${pack}: ${String(group.length)}`);
26
+ const shown = verbose ? group : group.slice(0, SHOWN_PER_PACK);
27
+ for (const diagnostic of shown)
28
+ lines.push(` ${formatDiagnostic(diagnostic)}`);
29
+ if (shown.length < group.length) {
30
+ lines.push(` … and ${String(group.length - shown.length)} more (--verbose shows all)`);
31
+ }
32
+ }
33
+ return `${lines.join("\n")}\n`;
34
+ }
35
+ /** One line for a diagnostic: its code, where, and what. */
36
+ export function formatDiagnostic(diagnostic) {
37
+ return `${diagnostic.code} ${diagnostic.path.join(" › ")}: ${diagnostic.message}`;
38
+ }
39
+ /** `1 warning`, `3 errors`. */
40
+ export function count(amount, noun) {
41
+ return `${String(amount)} ${noun}${amount === 1 ? "" : "s"}`;
42
+ }
43
+ /** A byte size for humans. */
44
+ export function size(bytes) {
45
+ if (bytes < 1024)
46
+ return `${String(bytes)} B`;
47
+ if (bytes < 1024 * 1024)
48
+ return `${(bytes / 1024).toFixed(1)} KB`;
49
+ return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
50
+ }
51
+ /**
52
+ * Each class type's pack: from the schema, or from the raw response for nodes the normalizer
53
+ * dropped.
54
+ */
55
+ function packsOf(schema, objectInfo) {
56
+ const packs = new Map();
57
+ const raw = parse(objectInfo).value;
58
+ if (raw !== undefined && isRecord(raw)) {
59
+ for (const [classType, node] of Object.entries(raw)) {
60
+ const module = isRecord(node) ? node["python_module"] : undefined;
61
+ if (typeof module === "string")
62
+ packs.set(classType, module);
63
+ }
64
+ }
65
+ for (const node of Object.values(schema.nodes))
66
+ packs.set(node.classType, node.pythonModule);
67
+ return packs;
68
+ }
69
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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"}
package/dist/run.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { type Io } from "./io.ts";
2
+ /** The CLI's version. A test keeps it equal to package.json. */
3
+ export declare const CLI_VERSION = "0.1.0";
4
+ /**
5
+ * Runs the CLI with `args` (without the program name) and returns the exit code: 0 on success,
6
+ * 1 on a failure or detected drift, 2 on a usage error.
7
+ */
8
+ export declare function run(args: readonly string[], io: Io): Promise<number>;
9
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,EAAE,EAAE,MAAM,SAAS,CAAC;AAG5C,gEAAgE;AAChE,eAAO,MAAM,WAAW,UAAU,CAAC;AAwBnC;;;GAGG;AACH,wBAAsB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAoC1E"}
package/dist/run.js ADDED
@@ -0,0 +1,89 @@
1
+ import { CHECK_USAGE, checkCommand } from "./check.js";
2
+ import { GENERATE_USAGE, generateCommand } from "./generate.js";
3
+ import { CliError } from "./io.js";
4
+ import { TRANSPILE_USAGE, transpileCommand } from "./transpile.js";
5
+ /** The CLI's version. A test keeps it equal to package.json. */
6
+ export const CLI_VERSION = "0.1.0";
7
+ /** `tscomfy --help`. */
8
+ const USAGE = `Usage: tscomfy <command> [options]
9
+
10
+ Commands:
11
+ generate Generate typed node definitions from a ComfyUI server
12
+ check Check that the generated types still match the server
13
+ transpile Turn an API-format prompt or a UI workflow into TypeScript over the generated types
14
+ help Show this help, or a command's: tscomfy help <command>
15
+
16
+ Options:
17
+ -h, --help Show this help.
18
+ -v, --version Print the version.
19
+
20
+ Run tscomfy <command> --help for a command's options.
21
+ `;
22
+ const USAGES = new Map([
23
+ ["generate", GENERATE_USAGE],
24
+ ["check", CHECK_USAGE],
25
+ ["transpile", TRANSPILE_USAGE],
26
+ ]);
27
+ /**
28
+ * Runs the CLI with `args` (without the program name) and returns the exit code: 0 on success,
29
+ * 1 on a failure or detected drift, 2 on a usage error.
30
+ */
31
+ export async function run(args, io) {
32
+ const [command, ...rest] = args;
33
+ try {
34
+ switch (command) {
35
+ case "generate":
36
+ return await generateCommand(io, rest);
37
+ case "check":
38
+ return await checkCommand(io, rest);
39
+ case "transpile":
40
+ return await transpileCommand(io, rest);
41
+ case "-v":
42
+ case "--version":
43
+ noArguments(rest);
44
+ io.out(`${CLI_VERSION}\n`);
45
+ return 0;
46
+ case "-h":
47
+ case "--help":
48
+ noArguments(rest);
49
+ io.out(USAGE);
50
+ return 0;
51
+ case "help":
52
+ return help(io, rest);
53
+ case undefined:
54
+ io.err(USAGE);
55
+ return 2;
56
+ default:
57
+ throw new CliError(`Unknown command ${JSON.stringify(command)}.`, 2);
58
+ }
59
+ }
60
+ catch (error) {
61
+ if (!(error instanceof CliError))
62
+ throw error;
63
+ io.err(`tscomfy: ${error.message}\n`);
64
+ if (error.exitCode === 2) {
65
+ io.err(`\n${USAGES.get(command ?? "") ?? USAGE}`);
66
+ }
67
+ return error.exitCode;
68
+ }
69
+ }
70
+ /** `tscomfy help [<command>]`: the usage, or a command's. */
71
+ function help(io, args) {
72
+ const [topic, ...rest] = args;
73
+ noArguments(rest);
74
+ if (topic === undefined) {
75
+ io.out(USAGE);
76
+ return 0;
77
+ }
78
+ const usage = USAGES.get(topic);
79
+ if (usage === undefined)
80
+ throw new CliError(`Unknown command ${JSON.stringify(topic)}.`, 2);
81
+ io.out(usage);
82
+ return 0;
83
+ }
84
+ function noArguments(args) {
85
+ const [extra] = args;
86
+ if (extra !== undefined)
87
+ throw new CliError(`Unexpected argument ${JSON.stringify(extra)}.`, 2);
88
+ }
89
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { type Diagnostic, type Schema } from "@tscomfy/core";
2
+ import { type Flags } from "./args.ts";
3
+ import { type Io } from "./io.ts";
4
+ /** Where node definitions come from: a server, or a saved `/object_info` response. */
5
+ export interface Source {
6
+ /** The `/object_info` text, exactly as served or saved. */
7
+ readonly text: string;
8
+ readonly comfyVersion?: string;
9
+ /** For messages: the server or the file. */
10
+ readonly label: string;
11
+ /** For the regenerate command in headers: `--url <server>` or `--from <file>`. */
12
+ readonly flag: string;
13
+ }
14
+ /**
15
+ * Reads `--url` (GET `/object_info`, and `/system_stats` for the version) or `--from`. Exactly
16
+ * one must be given. Only read-only GETs: tscomfy never queues anything.
17
+ */
18
+ export declare function readSource(io: Io, flags: Flags): Promise<Source>;
19
+ /**
20
+ * The normalized schema of a source. A response that holds no usable node at all (not JSON, not
21
+ * an object, an error body such as `{"detail": "Not authenticated"}`, or `{}`) is fatal, so it
22
+ * can't replace good types; anything less is reported and the rest generated.
23
+ */
24
+ export declare function loadSchema(source: Source): {
25
+ readonly schema: Schema;
26
+ readonly diagnostics: readonly Diagnostic[];
27
+ };
28
+ //# sourceMappingURL=source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../src/source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAuB,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,KAAK,KAAK,EAAS,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,EAAY,MAAM,SAAS,CAAC;AAG5C,sFAAsF;AACtF,MAAM,WAAW,MAAM;IACrB,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,4CAA4C;IAC5C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,kFAAkF;IAClF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BtE;AA0CD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,SAAS,UAAU,EAAE,CAAC;CAC7C,CAgBA"}
package/dist/source.js ADDED
@@ -0,0 +1,92 @@
1
+ import { normalizeObjectInfo } from "@tscomfy/core";
2
+ import { value } from "./args.js";
3
+ import { CliError } from "./io.js";
4
+ import { errorBodyMessage, flagWords, redactUrl } from "./util.js";
5
+ /**
6
+ * Reads `--url` (GET `/object_info`, and `/system_stats` for the version) or `--from`. Exactly
7
+ * one must be given. Only read-only GETs: tscomfy never queues anything.
8
+ */
9
+ export async function readSource(io, flags) {
10
+ const url = value(flags, "url");
11
+ const from = value(flags, "from");
12
+ if ((url === undefined) === (from === undefined)) {
13
+ throw new CliError("Give either --url <server> or --from <object_info.json>.", 2);
14
+ }
15
+ if (from !== undefined) {
16
+ const text = await io.readText(from);
17
+ if (text === undefined)
18
+ throw new CliError(`There is no file at ${from}.`);
19
+ const comfyVersion = value(flags, "comfy-version");
20
+ return {
21
+ text,
22
+ ...(comfyVersion === undefined ? {} : { comfyVersion }),
23
+ label: from,
24
+ flag: flagWords("from", from),
25
+ };
26
+ }
27
+ const base = serverBase(url ?? "");
28
+ const shown = redactUrl(base).replace(/\/+$/, "");
29
+ const text = await io.fetchText(endpoint(base, "object_info"));
30
+ const comfyVersion = await readComfyVersion(io, endpoint(base, "system_stats"));
31
+ return {
32
+ text,
33
+ ...(comfyVersion === undefined ? {} : { comfyVersion }),
34
+ label: shown,
35
+ flag: flagWords("url", shown),
36
+ };
37
+ }
38
+ /**
39
+ * The server URL. Credentials and the query (which often carries a token) are sent with each
40
+ * request but never shown: messages and generated headers use {@link redactUrl}.
41
+ */
42
+ function serverBase(url) {
43
+ // Not echoed: an unparseable URL may still hold a password.
44
+ if (!URL.canParse(url))
45
+ throw new CliError("--url is not a valid URL.", 2);
46
+ const parsed = new URL(url);
47
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
48
+ throw new CliError(`${redactUrl(parsed)} is not an http(s) URL.`, 2);
49
+ }
50
+ if (parsed.hash !== "") {
51
+ throw new CliError("--url can't have a #fragment: it never reaches the server.", 2);
52
+ }
53
+ return parsed;
54
+ }
55
+ /** An endpoint under the server's path, keeping its query: `http://h/api/?t=1` → `…/api/x?t=1`. */
56
+ function endpoint(base, name) {
57
+ const url = new URL(base.href);
58
+ url.pathname = `${url.pathname.replace(/\/+$/, "")}/${name}`;
59
+ return url.href;
60
+ }
61
+ /** The ComfyUI version from `/system_stats`; optional, so a failure only loses the version. */
62
+ async function readComfyVersion(io, url) {
63
+ try {
64
+ const stats = JSON.parse(await io.fetchText(url));
65
+ const system = typeof stats === "object" && stats !== null ? Reflect.get(stats, "system") : undefined;
66
+ const version = typeof system === "object" && system !== null
67
+ ? Reflect.get(system, "comfyui_version")
68
+ : undefined;
69
+ return typeof version === "string" ? version : undefined;
70
+ }
71
+ catch {
72
+ return undefined;
73
+ }
74
+ }
75
+ /**
76
+ * The normalized schema of a source. A response that holds no usable node at all (not JSON, not
77
+ * an object, an error body such as `{"detail": "Not authenticated"}`, or `{}`) is fatal, so it
78
+ * can't replace good types; anything less is reported and the rest generated.
79
+ */
80
+ export function loadSchema(source) {
81
+ const result = normalizeObjectInfo(source.text, source.comfyVersion === undefined ? {} : { comfyVersion: source.comfyVersion });
82
+ if (Object.keys(result.schema.nodes).length === 0) {
83
+ const detail = errorBodyMessage(source.text);
84
+ if (detail !== undefined) {
85
+ throw new CliError(`${source.label} is an error response, not node definitions: ${detail}.`);
86
+ }
87
+ const error = result.diagnostics.find((diagnostic) => diagnostic.severity === "error");
88
+ throw new CliError(`${source.label} doesn't hold node definitions${error === undefined ? "" : `: ${error.message}`}`);
89
+ }
90
+ return result;
91
+ }
92
+ //# sourceMappingURL=source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.js","sourceRoot":"","sources":["../src/source.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { type Io } from "./io.ts";
2
+ /** `tscomfy transpile --help`. */
3
+ export declare const TRANSPILE_USAGE: string;
4
+ /** `tscomfy transpile`. */
5
+ export declare function transpileCommand(io: Io, args: readonly string[]): Promise<number>;
6
+ //# sourceMappingURL=transpile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transpile.d.ts","sourceRoot":"","sources":["../src/transpile.ts"],"names":[],"mappings":"AASA,OAAO,EAAY,KAAK,EAAE,EAAE,MAAM,SAAS,CAAC;AAK5C,kCAAkC;AAClC,eAAO,MAAM,eAAe,EAAE,MAqB7B,CAAC;AAYF,2BAA2B;AAC3B,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAyEvF"}