loom-spec 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 (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +181 -0
  3. package/dist/cli/index.d.ts +2 -0
  4. package/dist/cli/index.js +96 -0
  5. package/dist/cli/index.js.map +1 -0
  6. package/dist/cli/init.d.ts +5 -0
  7. package/dist/cli/init.js +69 -0
  8. package/dist/cli/init.js.map +1 -0
  9. package/dist/cli/mcp.d.ts +4 -0
  10. package/dist/cli/mcp.js +17 -0
  11. package/dist/cli/mcp.js.map +1 -0
  12. package/dist/cli/validate.d.ts +5 -0
  13. package/dist/cli/validate.js +77 -0
  14. package/dist/cli/validate.js.map +1 -0
  15. package/dist/cli/view.d.ts +6 -0
  16. package/dist/cli/view.js +37 -0
  17. package/dist/cli/view.js.map +1 -0
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.js +2 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/mcp/server.d.ts +4 -0
  22. package/dist/mcp/server.js +293 -0
  23. package/dist/mcp/server.js.map +1 -0
  24. package/dist/server/app.d.ts +9 -0
  25. package/dist/server/app.js +135 -0
  26. package/dist/server/app.js.map +1 -0
  27. package/dist/server/drift.d.ts +29 -0
  28. package/dist/server/drift.js +128 -0
  29. package/dist/server/drift.js.map +1 -0
  30. package/dist/server/fileOps.d.ts +13 -0
  31. package/dist/server/fileOps.js +56 -0
  32. package/dist/server/fileOps.js.map +1 -0
  33. package/dist/server/findLoomRoot.d.ts +9 -0
  34. package/dist/server/findLoomRoot.js +28 -0
  35. package/dist/server/findLoomRoot.js.map +1 -0
  36. package/dist/server/watch.d.ts +29 -0
  37. package/dist/server/watch.js +83 -0
  38. package/dist/server/watch.js.map +1 -0
  39. package/dist/types/diagram.d.ts +99 -0
  40. package/dist/types/diagram.js +7 -0
  41. package/dist/types/diagram.js.map +1 -0
  42. package/dist/types/node-types.d.ts +55 -0
  43. package/dist/types/node-types.js +7 -0
  44. package/dist/types/node-types.js.map +1 -0
  45. package/dist/validate.d.ts +11 -0
  46. package/dist/validate.js +47 -0
  47. package/dist/validate.js.map +1 -0
  48. package/dist/view/assets/index-Cst6HUW5.css +1 -0
  49. package/dist/view/assets/index-jlp2cU4j.js +205 -0
  50. package/dist/view/index.html +24 -0
  51. package/package.json +83 -0
  52. package/schema/diagram.schema.json +173 -0
  53. package/schema/node-types.schema.json +116 -0
  54. package/templates/.claude/skills/loom-spec/SKILL.md +278 -0
  55. package/templates/.loom/README.md +25 -0
  56. package/templates/.loom/diagrams/overview.flow.json +8 -0
  57. package/templates/.loom/node-types.json +56 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 René Jesser
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,181 @@
1
+ # loom-spec
2
+
3
+ > A node-based architecture spec that lives in your repo. AI-readable, AI-writable, git-diffable.
4
+
5
+ `loom-spec` keeps a structured visual spec of your application's architecture **inside your repo**, designed to be edited by both humans (in a browser-based node editor) and AI coding agents (directly via JSON files).
6
+
7
+ It's a spec layer, not an execution layer. The nodes don't run — they describe.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ # No global install needed — use via npx
13
+ npx loom-spec init
14
+ npx loom-spec view
15
+ ```
16
+
17
+ Or as a dev dependency:
18
+
19
+ ```bash
20
+ npm install --save-dev loom-spec
21
+ ```
22
+
23
+ Then in `package.json`:
24
+
25
+ ```json
26
+ {
27
+ "scripts": {
28
+ "loom": "loom-spec view"
29
+ }
30
+ }
31
+ ```
32
+
33
+ ## Commands
34
+
35
+ ### `loom-spec init [--path <dir>] [--force]`
36
+
37
+ Scaffolds the spec directory and the agent skill in the target project (defaults to current working directory).
38
+
39
+ Writes:
40
+
41
+ - `.loom/README.md` — explains the directory to humans
42
+ - `.loom/node-types.json` — five default types (`ui`, `service`, `data`, `event`, `external`)
43
+ - `.loom/diagrams/overview.flow.json` — empty starter diagram
44
+ - `.claude/skills/loom-spec/SKILL.md` — tells Claude Code (and any tool following the Agent Skills standard) when and how to maintain the spec
45
+
46
+ Refuses to overwrite an existing `.loom/` unless `--force`.
47
+
48
+ ### `loom-spec view [--root <dir>] [--port <n>]`
49
+
50
+ Starts a local browser editor. Walks up from `--root` (default: cwd) to find the nearest `.loom/`. Opens on port 7777 by default.
51
+
52
+ ### `loom-spec validate [--root <dir>] [--json]`
53
+
54
+ Checks every diagram for schema validity plus **code-ref drift**: missing files, missing symbols, out-of-range line ranges. Skips nodes marked `planned` or `deprecated` (their code may legitimately not exist). Exit code is non-zero if any issue is found — useful as a CI step or pre-commit hook.
55
+
56
+ ```bash
57
+ loom-spec validate
58
+ # ✗ overview.flow.json — Todo App
59
+ # 5 nodes, 5 edges, 3 code refs checked
60
+ # ✗ todo-api → src/server/routes/todos.ts#todoRouter: symbol 'todoRouter' not found
61
+ ```
62
+
63
+ ### `loom-spec mcp [--root <dir>]`
64
+
65
+ Starts a **Model Context Protocol** server on stdio. Wire it into Claude Code (or any MCP-capable agent) via the host's `mcp.json`:
66
+
67
+ ```json
68
+ {
69
+ "mcpServers": {
70
+ "loom-spec": {
71
+ "command": "npx",
72
+ "args": ["loom-spec", "mcp"]
73
+ }
74
+ }
75
+ }
76
+ ```
77
+
78
+ The server exposes semantic tools that validate against the schema before writing, more token-efficient than re-reading and re-writing the JSON on every change:
79
+
80
+ - `loom_list_diagrams`, `loom_read_diagram`, `loom_read_node_types`
81
+ - `loom_add_node`, `loom_update_node`, `loom_mark_stale`, `loom_delete_node`
82
+ - `loom_add_edge`, `loom_delete_edge`
83
+ - `loom_validate` (same drift check as the CLI)
84
+
85
+ In the editor you can:
86
+
87
+ - Drag nodes; edits debounce and write to disk within ~500ms
88
+ - Click a node or edge to inspect and edit fields, code refs, tags, type-specific properties
89
+ - Drag from a node's right handle to another node to create an edge
90
+ - Use the "+ Add" menu in the top bar to add a new node by type
91
+ - Use the diagram switcher (top-left dropdown) to navigate between diagrams or create new ones
92
+ - Use the "Drill into" chevron on any node or group with `drill_down` set to jump to a sub-diagram
93
+ - Toggle light/dark theme; preference is persisted
94
+
95
+ External edits to the JSON files (e.g. by an AI agent) propagate to the open UI live via Server-Sent Events — no reload needed.
96
+
97
+ ## File format
98
+
99
+ ### `.loom/node-types.json`
100
+
101
+ Defines the available types for nodes in this project. Each type has a label, color, lucide icon name, optional typed fields (string / number / boolean / enum / markdown / code-ref / array), and optional named ports for typed connections.
102
+
103
+ ```json
104
+ {
105
+ "types": {
106
+ "service": {
107
+ "label": "Service",
108
+ "color": "#34d399",
109
+ "icon": "server",
110
+ "fields": [
111
+ { "name": "language", "type": "string" },
112
+ { "name": "runtime", "type": "string" }
113
+ ]
114
+ }
115
+ }
116
+ }
117
+ ```
118
+
119
+ ### `.loom/diagrams/*.flow.json`
120
+
121
+ Each diagram is `{ nodes, edges, groups }`. Nodes:
122
+
123
+ ```json
124
+ {
125
+ "id": "todo-api",
126
+ "type": "service",
127
+ "label": "Todo API",
128
+ "description": "REST endpoints for todos.",
129
+ "position": { "x": 400, "y": 160 },
130
+ "status": "implemented",
131
+ "code_refs": [
132
+ { "path": "src/server/routes/todos.ts", "symbol": "todoRouter" }
133
+ ],
134
+ "properties": { "language": "typescript", "runtime": "node" },
135
+ "tags": ["public"]
136
+ }
137
+ ```
138
+
139
+ Edges:
140
+
141
+ ```json
142
+ {
143
+ "id": "e1",
144
+ "from": "todo-list-view",
145
+ "to": "todo-api",
146
+ "kind": "request",
147
+ "label": "fetch / mutate"
148
+ }
149
+ ```
150
+
151
+ Status enum: `planned`, `implemented`, `stale`, `deprecated`.
152
+ Edge kinds: `request`, `event`, `data-read`, `data-write`, `signal`, `dependency`, `control`.
153
+
154
+ Full JSON Schemas ship with the package — see `schema/diagram.schema.json` and `schema/node-types.schema.json`.
155
+
156
+ ## How AI agents use it
157
+
158
+ `loom-spec init` writes a `SKILL.md` to `.claude/skills/loom-spec/` following the [Agent Skills open standard](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview). Claude Code (and other tools that adopt the convention) auto-discovers it.
159
+
160
+ The skill tells the agent to:
161
+
162
+ 1. Read the relevant diagram before implementing.
163
+ 2. Add new components as `status: planned`, flip to `implemented` after the code lands.
164
+ 3. Always populate `code_refs` — prefer `symbol` over `lines` because symbols survive refactors.
165
+ 4. On code deletion, set `status: stale` rather than removing the node — humans review.
166
+ 5. Don't invent node types — extend `node-types.json` first.
167
+
168
+ You can extend the skill with project-specific rules; it's committed in your repo.
169
+
170
+ ## Tech
171
+
172
+ - TypeScript end-to-end
173
+ - [Hono](https://hono.dev/) server (Node), serves the SPA and the REST/SSE API on a single port
174
+ - [React Flow / xyflow](https://reactflow.dev/) for the canvas
175
+ - [Vite](https://vitejs.dev/) for the SPA build
176
+ - [Ajv](https://ajv.js.org/) for runtime schema validation
177
+ - [Chokidar](https://github.com/paulmillr/chokidar) for filesystem watching
178
+
179
+ ## License
180
+
181
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+ import { runInit } from "./init.js";
3
+ import { runView } from "./view.js";
4
+ import { runValidate } from "./validate.js";
5
+ import { runMcp } from "./mcp.js";
6
+ const HELP = `loom-spec — node-based architecture spec for your repo
7
+
8
+ Usage:
9
+ loom-spec init [--path <dir>] [--force]
10
+ Scaffold .loom/ and .claude/skills/loom-spec/ in the target directory.
11
+ Defaults to current working directory.
12
+
13
+ loom-spec view [--root <dir>] [--port <n>] [--dev]
14
+ Start the local browser editor. Walks up from --root (default: cwd)
15
+ to find the nearest .loom/ directory.
16
+
17
+ loom-spec validate [--root <dir>] [--json]
18
+ Check every diagram for schema validity and code-ref drift
19
+ (missing files, missing symbols, out-of-range line refs).
20
+ Exits non-zero if any issue is found. Use as a CI step or
21
+ pre-commit hook.
22
+
23
+ loom-spec mcp [--root <dir>]
24
+ Start a Model Context Protocol server on stdio. Exposes
25
+ loom_list_diagrams, loom_read_diagram, loom_add_node,
26
+ loom_update_node, loom_mark_stale, loom_delete_node,
27
+ loom_add_edge, loom_delete_edge, loom_validate as MCP tools.
28
+ Wire it into Claude Code's mcp.json (or any MCP-capable client).
29
+
30
+ loom-spec --help
31
+ Print this help.
32
+ `;
33
+ function parseFlags(argv) {
34
+ const flags = {};
35
+ for (let i = 0; i < argv.length; i++) {
36
+ const a = argv[i];
37
+ if (!a)
38
+ continue;
39
+ if (a.startsWith("--")) {
40
+ const key = a.slice(2);
41
+ const next = argv[i + 1];
42
+ if (next && !next.startsWith("--")) {
43
+ flags[key] = next;
44
+ i++;
45
+ }
46
+ else {
47
+ flags[key] = true;
48
+ }
49
+ }
50
+ }
51
+ return flags;
52
+ }
53
+ async function main() {
54
+ const [, , subcommand, ...rest] = process.argv;
55
+ const flags = parseFlags(rest);
56
+ if (!subcommand || subcommand === "--help" || subcommand === "-h") {
57
+ console.log(HELP);
58
+ return;
59
+ }
60
+ if (subcommand === "init") {
61
+ await runInit({
62
+ path: flags.path ?? process.cwd(),
63
+ force: Boolean(flags.force),
64
+ });
65
+ return;
66
+ }
67
+ if (subcommand === "view") {
68
+ await runView({
69
+ root: flags.root ?? process.cwd(),
70
+ port: flags.port ? Number(flags.port) : 7777,
71
+ dev: Boolean(flags.dev),
72
+ });
73
+ return;
74
+ }
75
+ if (subcommand === "validate") {
76
+ await runValidate({
77
+ root: flags.root ?? process.cwd(),
78
+ json: Boolean(flags.json),
79
+ });
80
+ return;
81
+ }
82
+ if (subcommand === "mcp") {
83
+ await runMcp({
84
+ root: flags.root ?? process.cwd(),
85
+ });
86
+ return;
87
+ }
88
+ console.error(`unknown subcommand: ${subcommand}\n`);
89
+ console.log(HELP);
90
+ process.exit(1);
91
+ }
92
+ main().catch((e) => {
93
+ console.error(e);
94
+ process.exit(1);
95
+ });
96
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export interface InitArgs {
2
+ path: string;
3
+ force: boolean;
4
+ }
5
+ export declare function runInit(args: InitArgs): Promise<void>;
@@ -0,0 +1,69 @@
1
+ import { mkdir, readFile, writeFile, readdir, stat } from "node:fs/promises";
2
+ import { resolve, dirname, join, relative } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const here = dirname(fileURLToPath(import.meta.url));
5
+ // Templates ship alongside dist/ in the package: dist/cli/init.js → ../../templates/
6
+ const templatesRoot = resolve(here, "../../templates");
7
+ async function copyDir(srcDir, destDir, force) {
8
+ const written = [];
9
+ await mkdir(destDir, { recursive: true });
10
+ const entries = await readdir(srcDir, { withFileTypes: true });
11
+ for (const entry of entries) {
12
+ const src = join(srcDir, entry.name);
13
+ const dest = join(destDir, entry.name);
14
+ if (entry.isDirectory()) {
15
+ written.push(...(await copyDir(src, dest, force)));
16
+ }
17
+ else {
18
+ let exists = false;
19
+ try {
20
+ await stat(dest);
21
+ exists = true;
22
+ }
23
+ catch {
24
+ // doesn't exist
25
+ }
26
+ if (exists && !force) {
27
+ console.log(` skip (exists): ${dest}`);
28
+ continue;
29
+ }
30
+ const contents = await readFile(src);
31
+ await writeFile(dest, contents);
32
+ written.push(dest);
33
+ }
34
+ }
35
+ return written;
36
+ }
37
+ export async function runInit(args) {
38
+ const target = resolve(args.path);
39
+ console.log(`Initializing loom-spec in ${target}`);
40
+ // Pre-flight: warn if .loom already exists
41
+ let existing = false;
42
+ try {
43
+ await stat(resolve(target, ".loom"));
44
+ existing = true;
45
+ }
46
+ catch {
47
+ // fresh install
48
+ }
49
+ if (existing && !args.force) {
50
+ console.error("error: .loom/ already exists. Use --force to overwrite specific files (existing files are preserved unless overwritten).");
51
+ process.exit(1);
52
+ }
53
+ const written = await copyDir(templatesRoot, target, args.force);
54
+ console.log();
55
+ if (written.length === 0) {
56
+ console.log("Nothing to write. Use --force to overwrite existing files.");
57
+ return;
58
+ }
59
+ console.log(`Created ${written.length} file(s):`);
60
+ for (const f of written) {
61
+ console.log(` ${relative(target, f)}`);
62
+ }
63
+ console.log();
64
+ console.log("Next steps:");
65
+ console.log(" 1. Run `npx loom-spec view` to open the editor.");
66
+ console.log(" 2. Edit `.loom/node-types.json` to add project-specific node types.");
67
+ console.log(" 3. Start populating `.loom/diagrams/overview.flow.json`.");
68
+ }
69
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export interface McpArgs {
2
+ root: string;
3
+ }
4
+ export declare function runMcp(args: McpArgs): Promise<void>;
@@ -0,0 +1,17 @@
1
+ import { findLoomRoot } from "../server/findLoomRoot.js";
2
+ import { startMcpServer } from "../mcp/server.js";
3
+ export async function runMcp(args) {
4
+ let loomRoot;
5
+ try {
6
+ loomRoot = await findLoomRoot(args.root);
7
+ }
8
+ catch (e) {
9
+ // MCP servers communicate over stdio — print errors to stderr only.
10
+ console.error(`loom-spec mcp: ${e.message}`);
11
+ process.exit(1);
12
+ }
13
+ // Hint goes to stderr (stdout is the MCP transport)
14
+ console.error(`loom-spec mcp: serving ${loomRoot.loomPath}`);
15
+ await startMcpServer(loomRoot);
16
+ }
17
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/cli/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAMlD,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAa;IACxC,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,oEAAoE;QACpE,OAAO,CAAC,KAAK,CAAC,kBAAmB,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,oDAAoD;IACpD,OAAO,CAAC,KAAK,CAAC,0BAA0B,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC7D,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export interface ValidateArgs {
2
+ root: string;
3
+ json: boolean;
4
+ }
5
+ export declare function runValidate(args: ValidateArgs): Promise<void>;
@@ -0,0 +1,77 @@
1
+ import { findLoomRoot } from "../server/findLoomRoot.js";
2
+ import { runDriftCheck } from "../server/drift.js";
3
+ const ICON_OK = "✓";
4
+ const ICON_BAD = "✗";
5
+ const ICON_WARN = "⚠";
6
+ const ICON_INFO = "·";
7
+ function formatIssue(detail, issue) {
8
+ switch (issue) {
9
+ case "missing-file":
10
+ return `file not found`;
11
+ case "missing-symbol":
12
+ return detail ?? "symbol not found";
13
+ case "lines-out-of-range":
14
+ return `lines ${detail}`;
15
+ case "invalid-lines":
16
+ return `invalid line range ${detail}`;
17
+ default:
18
+ return issue;
19
+ }
20
+ }
21
+ function printDiagram(d) {
22
+ const status = d.schemaErrors.length > 0
23
+ ? ICON_BAD
24
+ : d.drift.length > 0
25
+ ? ICON_WARN
26
+ : ICON_OK;
27
+ console.log(`${status} ${d.diagramId}.flow.json — ${d.title}`);
28
+ console.log(` ${d.nodeCount} nodes, ${d.edgeCount} edges, ${d.refsChecked} code refs checked${d.staleNodes > 0 ? `, ${d.staleNodes} stale` : ""}`);
29
+ for (const err of d.schemaErrors) {
30
+ console.log(` ${ICON_BAD} schema: ${err}`);
31
+ }
32
+ for (const f of d.drift) {
33
+ console.log(` ${ICON_BAD} ${f.nodeId} → ${f.ref.path}${f.ref.symbol ? `#${f.ref.symbol}` : ""}: ${formatIssue(f.detail, f.issue)}`);
34
+ }
35
+ if (d.schemaErrors.length === 0 && d.drift.length === 0) {
36
+ console.log(` ${ICON_INFO} no issues`);
37
+ }
38
+ }
39
+ export async function runValidate(args) {
40
+ let loomRoot;
41
+ try {
42
+ loomRoot = await findLoomRoot(args.root);
43
+ }
44
+ catch (e) {
45
+ console.error(`error: ${e.message}`);
46
+ process.exit(1);
47
+ }
48
+ const report = await runDriftCheck(loomRoot.rootPath, loomRoot.loomPath);
49
+ if (args.json) {
50
+ console.log(JSON.stringify(report, null, 2));
51
+ process.exit(report.totalDrift + report.totalSchemaErrors > 0 ? 1 : 0);
52
+ return;
53
+ }
54
+ console.log(`loom-spec validate`);
55
+ console.log(` root: ${loomRoot.rootPath}`);
56
+ console.log();
57
+ for (const d of report.perDiagram) {
58
+ printDiagram(d);
59
+ console.log();
60
+ }
61
+ const summary = [];
62
+ if (report.totalSchemaErrors > 0) {
63
+ summary.push(`${report.totalSchemaErrors} schema error(s)`);
64
+ }
65
+ if (report.totalDrift > 0) {
66
+ summary.push(`${report.totalDrift} drift finding(s)`);
67
+ }
68
+ if (summary.length === 0) {
69
+ console.log(`${ICON_OK} All ${report.perDiagram.length} diagram(s) clean.`);
70
+ process.exit(0);
71
+ }
72
+ else {
73
+ console.log(`${ICON_BAD} ${summary.join(", ")} across ${report.perDiagram.length} diagram(s).`);
74
+ process.exit(1);
75
+ }
76
+ }
77
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/cli/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export interface ViewArgs {
2
+ root: string;
3
+ port: number;
4
+ dev: boolean;
5
+ }
6
+ export declare function runView(args: ViewArgs): Promise<void>;
@@ -0,0 +1,37 @@
1
+ import { serve } from "@hono/node-server";
2
+ import { resolve, dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { findLoomRoot } from "../server/findLoomRoot.js";
5
+ import { createApp } from "../server/app.js";
6
+ import { LoomWatcher } from "../server/watch.js";
7
+ const here = dirname(fileURLToPath(import.meta.url));
8
+ export async function runView(args) {
9
+ let loomRoot;
10
+ try {
11
+ loomRoot = await findLoomRoot(args.root);
12
+ }
13
+ catch (e) {
14
+ console.error(`error: ${e.message}`);
15
+ process.exit(1);
16
+ }
17
+ const watcher = new LoomWatcher(loomRoot.loomPath);
18
+ const app = createApp({
19
+ loomRoot,
20
+ watcher,
21
+ // In dev, Vite serves the SPA. Otherwise we serve the built bundle.
22
+ serveSpaFrom: args.dev ? undefined : resolve(here, "../view"),
23
+ });
24
+ const server = serve({ fetch: app.fetch, port: args.port }, (info) => {
25
+ console.log(`loom-spec: http://localhost:${info.port}`);
26
+ console.log(` root: ${loomRoot.rootPath}`);
27
+ console.log(` .loom: ${loomRoot.loomPath}`);
28
+ });
29
+ const shutdown = async () => {
30
+ await watcher.close();
31
+ server.close();
32
+ process.exit(0);
33
+ };
34
+ process.on("SIGINT", shutdown);
35
+ process.on("SIGTERM", shutdown);
36
+ }
37
+ //# sourceMappingURL=view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.js","sourceRoot":"","sources":["../../src/cli/view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAQjD,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAc;IAC1C,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,UAAW,CAAW,CAAC,OAAO,EAAE,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAEnD,MAAM,GAAG,GAAG,SAAS,CAAC;QACpB,QAAQ;QACR,OAAO;QACP,oEAAoE;QACpE,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC;KAC9D,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE;QACnE,OAAO,CAAC,GAAG,CAAC,+BAA+B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,YAAY,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,YAAY,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;QACtB,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAClC,CAAC"}
@@ -0,0 +1 @@
1
+ export declare const VERSION = "0.0.1";
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export const VERSION = "0.0.1";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { LoomRoot } from "../server/findLoomRoot.js";
3
+ export declare function createMcpServer(loomRoot: LoomRoot): McpServer;
4
+ export declare function startMcpServer(loomRoot: LoomRoot): Promise<void>;