diagram-tool 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.
- package/README.md +64 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +239 -0
- package/dist/cli.js.map +1 -0
- package/dist/context.d.ts +27 -0
- package/dist/context.js +55 -0
- package/dist/context.js.map +1 -0
- package/dist/diagram.d.ts +51 -0
- package/dist/diagram.js +519 -0
- package/dist/diagram.js.map +1 -0
- package/dist/dom-shim.d.ts +1 -0
- package/dist/dom-shim.js +59 -0
- package/dist/dom-shim.js.map +1 -0
- package/dist/guide.d.ts +9 -0
- package/dist/guide.js +99 -0
- package/dist/guide.js.map +1 -0
- package/dist/library.d.ts +76 -0
- package/dist/library.js +364 -0
- package/dist/library.js.map +1 -0
- package/dist/llm.d.ts +23 -0
- package/dist/llm.js +124 -0
- package/dist/llm.js.map +1 -0
- package/dist/mcp-install.d.ts +1 -0
- package/dist/mcp-install.js +68 -0
- package/dist/mcp-install.js.map +1 -0
- package/dist/mcp.d.ts +6 -0
- package/dist/mcp.js +262 -0
- package/dist/mcp.js.map +1 -0
- package/dist/public/Assistant-Bold-ZDZZ6JHA.woff2 +0 -0
- package/dist/public/Assistant-Medium-DZ25RZU3.woff2 +0 -0
- package/dist/public/Assistant-Regular-PLF2XOGW.woff2 +0 -0
- package/dist/public/Assistant-SemiBold-CZ5MX6FK.woff2 +0 -0
- package/dist/public/viewer.css +2 -0
- package/dist/public/viewer.css.map +7 -0
- package/dist/public/viewer.js +3092 -0
- package/dist/public/viewer.js.map +7 -0
- package/dist/server.d.ts +9 -0
- package/dist/server.js +166 -0
- package/dist/server.js.map +1 -0
- package/libraries/UML-ER-library.excalidrawlib +5380 -0
- package/libraries/awesome-icons.excalidrawlib +4081 -0
- package/libraries/dev_ops.excalidrawlib +35468 -0
- package/libraries/network-topology-icons.excalidrawlib +5290 -0
- package/libraries/system-icons.excalidrawlib +4521 -0
- package/libraries/systemdesignicons.excalidrawlib +1307 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Diagram Tool — agent-drawn Excalidraw on localhost, synced via a context file
|
|
2
|
+
|
|
3
|
+
No API key needed. Your coding agent is the LLM — `diagram-tool` only validates Mermaid, renders the scene, and serves the live UI.
|
|
4
|
+
|
|
5
|
+
## Recommended: MCP server (any coding agent)
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{ "mcpServers": { "diagram-tool": { "command": "npx", "args": ["-y", "diagram-tool", "mcp"] } } }
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or auto-write it:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm i -g diagram-tool # or npx -y diagram-tool mcp (no install)
|
|
15
|
+
diagram-tool mcp-install --agent auto # auto|opencode|claude|cursor|vscode
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Then ask your agent to draw something, open the returned `url` once — it live-updates on every render.
|
|
19
|
+
|
|
20
|
+
Tools: `render_diagram(mermaidSource, prompt?, decorations?)` · `get_diagram()` · `list_libraries(query?)` · `list_library_items(library)` · resource `diagram-tool://guide`. Full authoring doc: [GUIDE.md](GUIDE.md) (also served to agents via the guide resource, so no LLM setup is needed).
|
|
21
|
+
|
|
22
|
+
## The context file (source of truth)
|
|
23
|
+
|
|
24
|
+
Everything revolves around `diagram-tool.context.json`:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{ "version": 1, "rev": 3, "prompt": "...", "mermaidSource": "...",
|
|
28
|
+
"scene": { "type": "excalidraw", "version": 2, "elements": [...] } }
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- MCP/CLI writes it on every render (bumps `rev`, writes `.excalidraw.json` + `.mmd` sidecars).
|
|
32
|
+
- UI autosaves canvas edits back to it (`POST /api/scene`, debounced; stale `rev` → 409 + fresh copy).
|
|
33
|
+
- UI subscribes to SSE `GET /api/live` (Hono server watches the file) and refetches on rev bumps, so agent edits appear in the open canvas without reload.
|
|
34
|
+
|
|
35
|
+
## Shell fallback (no MCP)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
diagram-tool render --no-serve # re-derive scene from the context file's mermaidSource
|
|
39
|
+
diagram-tool serve # just the UI (default http://localhost:3000)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Agent loop without MCP: edit `mermaidSource` in the context file, run `diagram-tool render --no-serve`. Structural changes belong in `mermaidSource` + render; small canvas nudges can go straight into `scene.elements`.
|
|
43
|
+
|
|
44
|
+
## Libraries (excalidraw-libs)
|
|
45
|
+
|
|
46
|
+
`libraries/*.excalidrawlib` (v1 + v2) are served at `GET /api/libraries` for hand drag-drop, and composited server-side via `decorations` for agent renders. 6 payloads ship offline (network-topology, dev-ops, systemdesignicons, UML-ER, awesome-icons, system-icons); the full ~100-library catalog is searchable via `list_libraries` and fetched on demand into `~/.cache/diagram-tool/libraries/`.
|
|
47
|
+
|
|
48
|
+
- `diagram-tool library list` — downloaded files + item count
|
|
49
|
+
- `diagram-tool library add <name>` — download from libraries.excalidraw.com (e.g. `diagram-tool library add aws`)
|
|
50
|
+
- Node icon classes also work: `class USER actor,icon_user` (slugs: `icon_user`, `icon_users`, `icon_home`, `icon_lock`, `icon_search`, `icon_chart`, `icon_email`, `icon_calendar`, `icon_location`, `icon_payment`)
|
|
51
|
+
|
|
52
|
+
Rule of thumb: cloud/architecture/network diagrams get ≤6 icons; logic flowcharts and sequence/ER/class diagrams stay pure mermaid.
|
|
53
|
+
|
|
54
|
+
## BYOK fallback (optional, needs a key)
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
cp .env.example .env # OPENROUTER_API_KEY=sk-or-...
|
|
58
|
+
diagram-tool "draw the request lifecycle of a REST API" --provider openrouter
|
|
59
|
+
diagram-tool edit "add a retry step" --provider openrouter
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Flags: `--provider openai|anthropic|google|ollama|openrouter`, `--model`, `--api-key`, `--base-url`, `--port`, `--no-serve`, `--context`.
|
|
63
|
+
|
|
64
|
+
Pipeline: few-shot prompt → strict Mermaid parse → up to 2 self-repairs (parser error fed back) → `mermaid-to-excalidraw`. Server-side geometry is approximated from text length (jsdom `getBBox` shim); browser is truth.
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* diagram-tool — CLI + localhost React canvas around one context file.
|
|
4
|
+
*
|
|
5
|
+
* diagram-tool "draw a login flowchart" # generate -> context file -> serve UI
|
|
6
|
+
* diagram-tool edit "add a payment step" # follow-up via CLI
|
|
7
|
+
* diagram-tool render [file.mmd] # re-derive scene from context (or file) mermaid
|
|
8
|
+
* diagram-tool serve # just serve the UI
|
|
9
|
+
*
|
|
10
|
+
* UI edits autosave to the same context file. OpenCode loop: prompt OpenCode
|
|
11
|
+
* to edit diagram-tool.context.json's mermaidSource, then `diagram-tool render`.
|
|
12
|
+
*/
|
|
13
|
+
import { readFile } from "node:fs/promises";
|
|
14
|
+
import { DEFAULT_CONTEXT, loadContext, saveContext } from "./context.js";
|
|
15
|
+
import { convertToScene, generate } from "./diagram.js";
|
|
16
|
+
import { serve } from "./server.js";
|
|
17
|
+
import { runMcp } from "./mcp.js";
|
|
18
|
+
import { DEFAULT_MODELS } from "./llm.js";
|
|
19
|
+
const PROVIDERS = ["openai", "anthropic", "google", "ollama", "openrouter"];
|
|
20
|
+
function help() {
|
|
21
|
+
return `diagram-tool — Mermaid -> Excalidraw on localhost, synced through a context file.
|
|
22
|
+
No API key needed for MCP / render / serve (the agent is the LLM).
|
|
23
|
+
|
|
24
|
+
Usage:
|
|
25
|
+
diagram-tool mcp [--context <file>] [--port <n>] [--no-serve]
|
|
26
|
+
MCP stdio server for any coding agent (recommended)
|
|
27
|
+
diagram-tool mcp-install [--agent auto|opencode|claude|cursor|vscode]
|
|
28
|
+
write the MCP snippet into your agent config
|
|
29
|
+
diagram-tool render [file.mmd] re-derive scene from context (or given) mermaid, no LLM
|
|
30
|
+
diagram-tool serve serve the UI for the context file
|
|
31
|
+
diagram-tool library list list downloaded libraries
|
|
32
|
+
diagram-tool library add <name> download a library from libraries.excalidraw.com
|
|
33
|
+
diagram-tool "..." [options] generate via BYOK provider (optional fallback, needs key)
|
|
34
|
+
diagram-tool edit "..." [options] follow-up edit via BYOK provider
|
|
35
|
+
|
|
36
|
+
Options:
|
|
37
|
+
--context <file> context file (default ${DEFAULT_CONTEXT})
|
|
38
|
+
--agent <a> mcp-install target (default auto)
|
|
39
|
+
--provider <p> BYOK only: ${PROVIDERS.join("|")} (default $DIAGRAM_TOOL_PROVIDER or openai)
|
|
40
|
+
--model <name> BYOK only (default per provider)
|
|
41
|
+
--api-key <key> BYOK (or $OPENAI_API_KEY / $ANTHROPIC_API_KEY / $GOOGLE_API_KEY / $OPENROUTER_API_KEY)
|
|
42
|
+
--base-url <url> proxy / Ollama host
|
|
43
|
+
--port <n> (default 3000, $DIAGRAM_TOOL_PORT)
|
|
44
|
+
--no-serve don't start the UI after generate/edit/render (mcp: file-only mode)
|
|
45
|
+
|
|
46
|
+
Agent loop (no key): connect diagram-tool mcp, ask the agent to draw, open the
|
|
47
|
+
returned url once — it live-updates. Shell fallback: edit "mermaidSource"
|
|
48
|
+
in ${DEFAULT_CONTEXT}, then \`diagram-tool render --no-serve\`.`;
|
|
49
|
+
}
|
|
50
|
+
function parseFlags(argv) {
|
|
51
|
+
const flags = {
|
|
52
|
+
context: process.env.DIAGRAM_TOOL_CONTEXT || process.env.FORGE_CONTEXT || DEFAULT_CONTEXT,
|
|
53
|
+
provider: (process.env.DIAGRAM_TOOL_PROVIDER || process.env.FORGE_PROVIDER) || "openai",
|
|
54
|
+
model: process.env.DIAGRAM_TOOL_MODEL || process.env.FORGE_MODEL || "gpt-4.1-mini",
|
|
55
|
+
modelSet: !!(process.env.DIAGRAM_TOOL_MODEL || process.env.FORGE_MODEL),
|
|
56
|
+
port: Number(process.env.DIAGRAM_TOOL_PORT || process.env.FORGE_PORT || 3000),
|
|
57
|
+
serveAfter: true,
|
|
58
|
+
agent: "auto",
|
|
59
|
+
};
|
|
60
|
+
if (process.env.DIAGRAM_TOOL_API_KEY || process.env.FORGE_API_KEY) {
|
|
61
|
+
flags.apiKey = process.env.DIAGRAM_TOOL_API_KEY || process.env.FORGE_API_KEY;
|
|
62
|
+
}
|
|
63
|
+
if (process.env.DIAGRAM_TOOL_BASE_URL || process.env.FORGE_BASE_URL) {
|
|
64
|
+
flags.baseUrl = process.env.DIAGRAM_TOOL_BASE_URL || process.env.FORGE_BASE_URL;
|
|
65
|
+
}
|
|
66
|
+
const rest = [];
|
|
67
|
+
for (let i = 0; i < argv.length; i++) {
|
|
68
|
+
const t = argv[i];
|
|
69
|
+
const next = () => {
|
|
70
|
+
const v = argv[++i];
|
|
71
|
+
if (v === undefined)
|
|
72
|
+
throw new Error(`flag ${t} needs a value`);
|
|
73
|
+
return v;
|
|
74
|
+
};
|
|
75
|
+
if (t === "--help" || t === "-h") {
|
|
76
|
+
console.log(help());
|
|
77
|
+
process.exit(0);
|
|
78
|
+
}
|
|
79
|
+
else if (t === "--context")
|
|
80
|
+
flags.context = next();
|
|
81
|
+
else if (t === "--agent")
|
|
82
|
+
flags.agent = next();
|
|
83
|
+
else if (t === "--provider")
|
|
84
|
+
flags.provider = next();
|
|
85
|
+
else if (t === "--model") {
|
|
86
|
+
flags.model = next();
|
|
87
|
+
flags.modelSet = true;
|
|
88
|
+
}
|
|
89
|
+
else if (t === "--api-key")
|
|
90
|
+
flags.apiKey = next();
|
|
91
|
+
else if (t === "--base-url")
|
|
92
|
+
flags.baseUrl = next();
|
|
93
|
+
else if (t === "--port")
|
|
94
|
+
flags.port = Number(next());
|
|
95
|
+
else if (t === "--no-serve")
|
|
96
|
+
flags.serveAfter = false;
|
|
97
|
+
else if (t.startsWith("--"))
|
|
98
|
+
throw new Error(`unknown flag ${t}`);
|
|
99
|
+
else
|
|
100
|
+
rest.push(t);
|
|
101
|
+
}
|
|
102
|
+
if (!flags.modelSet)
|
|
103
|
+
flags.model = DEFAULT_MODELS[flags.provider] ?? flags.model;
|
|
104
|
+
return { flags, rest };
|
|
105
|
+
}
|
|
106
|
+
async function main() {
|
|
107
|
+
try {
|
|
108
|
+
const env = await readFile(".env", "utf8");
|
|
109
|
+
for (const line of env.split("\n")) {
|
|
110
|
+
const m = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/.exec(line.trim());
|
|
111
|
+
if (!m || process.env[m[1]] !== undefined)
|
|
112
|
+
continue;
|
|
113
|
+
let v = m[2].trim();
|
|
114
|
+
if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'")))
|
|
115
|
+
v = v.slice(1, -1);
|
|
116
|
+
process.env[m[1]] = v;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
/* no .env — fine */
|
|
121
|
+
}
|
|
122
|
+
const { flags: f, rest } = parseFlags(process.argv.slice(2));
|
|
123
|
+
if (!PROVIDERS.includes(f.provider))
|
|
124
|
+
throw new Error(`unknown provider "${f.provider}" (${PROVIDERS.join("|")})`);
|
|
125
|
+
const [cmd, ...cmdRest] = rest;
|
|
126
|
+
if (!cmd) {
|
|
127
|
+
console.log(help());
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
if (cmd === "serve") {
|
|
131
|
+
await serve(f.context, f.port);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (cmd === "mcp") {
|
|
135
|
+
await runMcp({ context: f.context, port: f.port, noServe: !f.serveAfter });
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (cmd === "mcp-install") {
|
|
139
|
+
const { installMcp } = await import("./mcp-install.js");
|
|
140
|
+
await installMcp(f.agent);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (cmd === "library") {
|
|
144
|
+
const { readdir } = await import("node:fs/promises");
|
|
145
|
+
const { existsSync } = await import("node:fs");
|
|
146
|
+
const sub = cmdRest[0];
|
|
147
|
+
if (sub === "list" || !sub) {
|
|
148
|
+
const { loadLibraryItems, libraryDir } = await import("./library.js");
|
|
149
|
+
const dir = libraryDir();
|
|
150
|
+
if (!existsSync(dir)) {
|
|
151
|
+
console.log("no libraries/ directory");
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const files = (await readdir(dir)).filter((x) => x.endsWith(".excalidrawlib"));
|
|
155
|
+
const items = await loadLibraryItems(dir);
|
|
156
|
+
console.log(`${files.length} files, ${items.length} items:`);
|
|
157
|
+
for (const x of files)
|
|
158
|
+
console.log(` ${x}`);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (sub === "add") {
|
|
162
|
+
const query = (cmdRest[1] ?? "").toLowerCase();
|
|
163
|
+
if (!query)
|
|
164
|
+
throw new Error("usage: diagram-tool library add <name> (e.g. diagram-tool library add aws)");
|
|
165
|
+
console.error("fetching library index…");
|
|
166
|
+
const res = await fetch("https://raw.githubusercontent.com/excalidraw/excalidraw-libs/main/libraries.json");
|
|
167
|
+
if (!res.ok)
|
|
168
|
+
throw new Error(`index fetch failed: HTTP ${res.status}`);
|
|
169
|
+
const index = (await res.json());
|
|
170
|
+
const hit = index.find((l) => l.name.toLowerCase().includes(query));
|
|
171
|
+
if (!hit)
|
|
172
|
+
throw new Error(`no library matching "${query}" (try a shorter term)`);
|
|
173
|
+
const { mkdir, writeFile } = await import("node:fs/promises");
|
|
174
|
+
await mkdir("libraries", { recursive: true });
|
|
175
|
+
const url = `https://raw.githubusercontent.com/excalidraw/excalidraw-libs/main/libraries/${hit.source}`;
|
|
176
|
+
console.error(`downloading ${hit.name}…`);
|
|
177
|
+
const dl = await fetch(url);
|
|
178
|
+
if (!dl.ok)
|
|
179
|
+
throw new Error(`download failed: HTTP ${dl.status}`);
|
|
180
|
+
const dest = `libraries/${hit.source.split("/").pop()}`;
|
|
181
|
+
await writeFile(dest, Buffer.from(await dl.arrayBuffer()));
|
|
182
|
+
console.log(`added ${hit.name} -> ${dest} (restart diagram-tool serve to load)`);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
throw new Error(`unknown library command "${sub}" (list|add)`);
|
|
186
|
+
}
|
|
187
|
+
if (cmd === "render") {
|
|
188
|
+
const mmdFile = cmdRest[0];
|
|
189
|
+
let mermaidSource;
|
|
190
|
+
if (mmdFile) {
|
|
191
|
+
mermaidSource = (await readFile(mmdFile, "utf8")).trim();
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
mermaidSource = (await loadContext(f.context)).mermaidSource;
|
|
195
|
+
if (!mermaidSource.trim())
|
|
196
|
+
throw new Error(`no mermaidSource in ${f.context} (and no file given)`);
|
|
197
|
+
}
|
|
198
|
+
const scene = await convertToScene(mermaidSource);
|
|
199
|
+
const next = await saveContext(f.context, { mermaidSource, elements: scene.elements });
|
|
200
|
+
console.log(`rendered rev ${next.rev} into ${f.context} (${scene.elements.length} elements)`);
|
|
201
|
+
if (f.serveAfter)
|
|
202
|
+
await serve(f.context, f.port);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const isEdit = cmd === "edit";
|
|
206
|
+
const prompt = (isEdit ? cmdRest : rest).join(" ");
|
|
207
|
+
if (!prompt) {
|
|
208
|
+
console.log(help());
|
|
209
|
+
process.exit(1);
|
|
210
|
+
}
|
|
211
|
+
let existingMermaid;
|
|
212
|
+
if (isEdit) {
|
|
213
|
+
existingMermaid = (await loadContext(f.context)).mermaidSource;
|
|
214
|
+
if (!existingMermaid.trim())
|
|
215
|
+
throw new Error(`${f.context} has no mermaidSource to edit yet — generate first.`);
|
|
216
|
+
}
|
|
217
|
+
console.error(`asking ${f.provider}/${f.model} ...`);
|
|
218
|
+
const t0 = Date.now();
|
|
219
|
+
const r = await generate(prompt, {
|
|
220
|
+
provider: f.provider,
|
|
221
|
+
model: f.model,
|
|
222
|
+
...(f.apiKey ? { apiKey: f.apiKey } : {}),
|
|
223
|
+
...(f.baseUrl ? { baseUrl: f.baseUrl } : {}),
|
|
224
|
+
...(existingMermaid ? { existingMermaid } : {}),
|
|
225
|
+
});
|
|
226
|
+
const next = await saveContext(f.context, {
|
|
227
|
+
prompt,
|
|
228
|
+
mermaidSource: r.mermaidSource,
|
|
229
|
+
elements: r.scene.elements,
|
|
230
|
+
});
|
|
231
|
+
console.error(`done in ${((Date.now() - t0) / 1000).toFixed(1)}s — rev ${next.rev} in ${f.context} (${r.scene.elements.length} elements${r.repaired ? `, repaired after ${r.attempts} attempts` : ""})`);
|
|
232
|
+
if (f.serveAfter)
|
|
233
|
+
await serve(f.context, f.port);
|
|
234
|
+
}
|
|
235
|
+
main().catch((e) => {
|
|
236
|
+
console.error(`error: ${e instanceof Error ? e.message : String(e)}`);
|
|
237
|
+
process.exit(1);
|
|
238
|
+
});
|
|
239
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The context file is the single source of truth shared by CLI, UI and agents.
|
|
3
|
+
* OpenCode workflow: read it, change `mermaidSource` (or `elements`), then run
|
|
4
|
+
* `diagram-tool render` to re-derive the scene — or just edit elements directly.
|
|
5
|
+
*/
|
|
6
|
+
export interface DiagramContext {
|
|
7
|
+
version: 1;
|
|
8
|
+
/** incremented on every write; UI polls this to pick up CLI/agent edits */
|
|
9
|
+
rev: number;
|
|
10
|
+
prompt: string;
|
|
11
|
+
mermaidSource: string;
|
|
12
|
+
scene: {
|
|
13
|
+
type: "excalidraw";
|
|
14
|
+
version: 2;
|
|
15
|
+
elements: unknown[];
|
|
16
|
+
};
|
|
17
|
+
updatedAt: string;
|
|
18
|
+
}
|
|
19
|
+
export declare const DEFAULT_CONTEXT = "diagram-tool.context.json";
|
|
20
|
+
/** Pre-rename default. Read as fallback; first save migrates to DEFAULT_CONTEXT. */
|
|
21
|
+
export declare const LEGACY_CONTEXT = "diagramforge.context.json";
|
|
22
|
+
export declare function blankContext(prompt?: string): DiagramContext;
|
|
23
|
+
export declare function loadContext(path: string): Promise<DiagramContext>;
|
|
24
|
+
/** Applies patch, bumps rev, writes file + sidecars. Returns the new context. */
|
|
25
|
+
export declare function saveContext(path: string, patch: Partial<Pick<DiagramContext, "prompt" | "mermaidSource">> & {
|
|
26
|
+
elements?: unknown[];
|
|
27
|
+
}): Promise<DiagramContext>;
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
export const DEFAULT_CONTEXT = "diagram-tool.context.json";
|
|
4
|
+
/** Pre-rename default. Read as fallback; first save migrates to DEFAULT_CONTEXT. */
|
|
5
|
+
export const LEGACY_CONTEXT = "diagramforge.context.json";
|
|
6
|
+
export function blankContext(prompt = "") {
|
|
7
|
+
return {
|
|
8
|
+
version: 1,
|
|
9
|
+
rev: 0,
|
|
10
|
+
prompt,
|
|
11
|
+
mermaidSource: "",
|
|
12
|
+
scene: { type: "excalidraw", version: 2, elements: [] },
|
|
13
|
+
updatedAt: new Date().toISOString(),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export async function loadContext(path) {
|
|
17
|
+
if (!existsSync(path) && path === DEFAULT_CONTEXT && existsSync(LEGACY_CONTEXT)) {
|
|
18
|
+
path = LEGACY_CONTEXT; // pre-rename file: read it, next save migrates
|
|
19
|
+
}
|
|
20
|
+
if (!existsSync(path))
|
|
21
|
+
return blankContext();
|
|
22
|
+
const raw = await readFile(path, "utf8");
|
|
23
|
+
const c = JSON.parse(raw);
|
|
24
|
+
if (!c.scene)
|
|
25
|
+
c.scene = { type: "excalidraw", version: 2, elements: [] };
|
|
26
|
+
if (typeof c.rev !== "number")
|
|
27
|
+
c.rev = 0;
|
|
28
|
+
if (typeof c.mermaidSource !== "string")
|
|
29
|
+
c.mermaidSource = "";
|
|
30
|
+
return c;
|
|
31
|
+
}
|
|
32
|
+
/** Applies patch, bumps rev, writes file + sidecars. Returns the new context. */
|
|
33
|
+
export async function saveContext(path, patch) {
|
|
34
|
+
const prev = await loadContext(path);
|
|
35
|
+
const next = {
|
|
36
|
+
...prev,
|
|
37
|
+
version: 1,
|
|
38
|
+
rev: prev.rev + 1,
|
|
39
|
+
updatedAt: new Date().toISOString(),
|
|
40
|
+
...(patch.prompt !== undefined ? { prompt: patch.prompt } : {}),
|
|
41
|
+
...(patch.mermaidSource !== undefined ? { mermaidSource: patch.mermaidSource } : {}),
|
|
42
|
+
scene: {
|
|
43
|
+
type: "excalidraw",
|
|
44
|
+
version: 2,
|
|
45
|
+
elements: patch.elements !== undefined ? patch.elements : prev.scene.elements,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
await writeFile(path, JSON.stringify(next, null, 2));
|
|
49
|
+
// sidecars for direct import into excalidraw.com
|
|
50
|
+
const base = path.replace(/\.context\.json$/, "").replace(/\.json$/, "");
|
|
51
|
+
await writeFile(`${base}.excalidraw.json`, JSON.stringify({ ...next.scene, source: "diagram-tool", appState: {} }, null, 2));
|
|
52
|
+
await writeFile(`${base}.mmd`, (next.mermaidSource ? next.mermaidSource + "\n" : ""));
|
|
53
|
+
return next;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import "./dom-shim.js";
|
|
2
|
+
import { type LlmOpts } from "./llm.js";
|
|
3
|
+
export interface Scene {
|
|
4
|
+
type: "excalidraw";
|
|
5
|
+
version: 2;
|
|
6
|
+
source: string;
|
|
7
|
+
elements: unknown[];
|
|
8
|
+
appState: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
export declare function extractMermaid(raw: string): string;
|
|
11
|
+
export declare function validateMermaid(source: string): Promise<string>;
|
|
12
|
+
export declare function convertToScene(mermaidSource: string): Promise<Scene>;
|
|
13
|
+
/** nodeId -> icon slug from `class NODE icon_slug` statements in the source. */
|
|
14
|
+
export declare function parseIconClasses(mermaidSource: string): Map<string, string>;
|
|
15
|
+
/**
|
|
16
|
+
* Dress node cards with library artwork: icon glyph fitted into the top of
|
|
17
|
+
* the box, node caption pinned to the bottom strip, all grouped for UI drag.
|
|
18
|
+
* Unknown slugs / missing libraries degrade to plain boxes (never throw).
|
|
19
|
+
*/
|
|
20
|
+
export declare function applyIcons(elements: Record<string, unknown>[], mermaidSource: string, libraryDir?: string): Promise<Record<string, unknown>[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Merge parallel arrows (same source id -> same target id) into one. The
|
|
23
|
+
* model sometimes emits one edge per action (generate/edit/render/serve),
|
|
24
|
+
* which renders as stacked duplicate arrows. Keeper = first arrow; labels
|
|
25
|
+
* are concatenated with " · " and surplus arrows + labels removed.
|
|
26
|
+
*/
|
|
27
|
+
export declare function dedupeArrows(elements: Record<string, unknown>[]): Record<string, unknown>[];
|
|
28
|
+
/**
|
|
29
|
+
* Breathing space pass. The converter packs nodes per its own (often wrong)
|
|
30
|
+
* measurements, so labels collide. This iteratively pushes overlapping boxes
|
|
31
|
+
* apart and drags attached arrow endpoints + labels along (arrows here are
|
|
32
|
+
* free-floating: start/end are plain id refs, no live bindings).
|
|
33
|
+
*/
|
|
34
|
+
export declare function declutter(elements: Record<string, unknown>[]): Record<string, unknown>[];
|
|
35
|
+
/**
|
|
36
|
+
* @excalidraw/mermaid-to-excalidraw v2 emits node text as a non-standard
|
|
37
|
+
* `label: { text, fontSize }` prop that the canvas ignores. Rewrite each into
|
|
38
|
+
* a real bound `text` element wired via containerId/boundElements.
|
|
39
|
+
*/
|
|
40
|
+
export declare function withBoundLabels(elements: Record<string, unknown>[]): Record<string, unknown>[];
|
|
41
|
+
export interface GenerateOpts extends LlmOpts {
|
|
42
|
+
existingMermaid?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface GenerateResult {
|
|
45
|
+
scene: Scene;
|
|
46
|
+
mermaidSource: string;
|
|
47
|
+
attempts: number;
|
|
48
|
+
repaired: boolean;
|
|
49
|
+
}
|
|
50
|
+
/** Prompt -> Mermaid -> validate (2 repairs, error fed back) -> Excalidraw scene. */
|
|
51
|
+
export declare function generate(prompt: string, opts: GenerateOpts): Promise<GenerateResult>;
|