@clarity-tools/cli 0.1.1 → 0.1.2
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 +27 -0
- package/dist/index.js +47 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,6 +4,16 @@ Generate beautiful, hand-drawn style architecture diagrams from your Infrastruct
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@clarity-tools/cli)
|
|
6
6
|
|
|
7
|
+
## Examples
|
|
8
|
+
|
|
9
|
+
### Temporal
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
### Mastodon
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
7
17
|
## Features
|
|
8
18
|
|
|
9
19
|
- **Auto-detection**: Finds docker-compose.yml, compose.yml, and Helm charts
|
|
@@ -50,6 +60,7 @@ iac-diagrams [path] [options]
|
|
|
50
60
|
- `-o, --output <dir>` - Output directory (default: `./docs/diagrams`)
|
|
51
61
|
- `--no-llm` - Disable LLM enhancement
|
|
52
62
|
- `--no-png` - Skip PNG rendering (output .excalidraw only)
|
|
63
|
+
- `--artifacts` - Save parsed/enhanced/elk JSON artifacts alongside outputs
|
|
53
64
|
- `-v, --verbose` - Show detailed output
|
|
54
65
|
|
|
55
66
|
**Examples:**
|
|
@@ -108,6 +119,16 @@ docs/diagrams/
|
|
|
108
119
|
└── docker-compose.png # Rendered PNG image
|
|
109
120
|
```
|
|
110
121
|
|
|
122
|
+
With `--artifacts`, additional JSON files are saved:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
docs/diagrams/
|
|
126
|
+
├── docker-compose.parsed.json # Parsed InfraGraph
|
|
127
|
+
├── docker-compose.enhanced.json # Enhanced InfraGraph (LLM if enabled)
|
|
128
|
+
├── docker-compose.elk-input.json # ELK input graph
|
|
129
|
+
└── docker-compose.elk-output.json # ELK output graph (with positions)
|
|
130
|
+
```
|
|
131
|
+
|
|
111
132
|
The `.excalidraw` file can be opened at [excalidraw.com](https://excalidraw.com) for editing.
|
|
112
133
|
|
|
113
134
|
## Supported Formats
|
|
@@ -153,6 +174,12 @@ iac-diagrams config show
|
|
|
153
174
|
|
|
154
175
|
The key should start with `sk-or-`.
|
|
155
176
|
|
|
177
|
+
## Appendix: Diagram Conventions
|
|
178
|
+
|
|
179
|
+
- Shapes: rectangles for application services, ellipses for databases/caches, diamonds for message queues
|
|
180
|
+
- Colors: blue=database, red=cache, green=storage, yellow=queue
|
|
181
|
+
- Layering: UI -> API -> worker -> data -> infrastructure
|
|
182
|
+
|
|
156
183
|
## License
|
|
157
184
|
|
|
158
185
|
MIT
|
package/dist/index.js
CHANGED
|
@@ -1596,9 +1596,37 @@ function infraGraphToElk(graph, options = {}) {
|
|
|
1596
1596
|
}
|
|
1597
1597
|
|
|
1598
1598
|
// ../core/src/elk/layout.ts
|
|
1599
|
+
import { createRequire } from "module";
|
|
1599
1600
|
import ELK from "elkjs";
|
|
1601
|
+
var require2 = createRequire(import.meta.url);
|
|
1602
|
+
var loadWorkerModule = () => {
|
|
1603
|
+
const globalSelf = globalThis;
|
|
1604
|
+
const hadSelf = Object.prototype.hasOwnProperty.call(globalSelf, "self");
|
|
1605
|
+
const originalSelf = globalSelf.self;
|
|
1606
|
+
try {
|
|
1607
|
+
globalSelf.self = void 0;
|
|
1608
|
+
return require2("elkjs/lib/elk-worker.js");
|
|
1609
|
+
} finally {
|
|
1610
|
+
if (hadSelf) {
|
|
1611
|
+
globalSelf.self = originalSelf;
|
|
1612
|
+
} else {
|
|
1613
|
+
delete globalSelf.self;
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
};
|
|
1617
|
+
var resolveWorkerConstructor = () => {
|
|
1618
|
+
const workerModule = loadWorkerModule();
|
|
1619
|
+
const maybeWorker = workerModule.Worker ?? workerModule.default ?? workerModule;
|
|
1620
|
+
if (typeof maybeWorker === "function") {
|
|
1621
|
+
return maybeWorker;
|
|
1622
|
+
}
|
|
1623
|
+
throw new Error("ELK worker module not available");
|
|
1624
|
+
};
|
|
1600
1625
|
async function runLayout(graph) {
|
|
1601
|
-
const
|
|
1626
|
+
const WorkerCtor = resolveWorkerConstructor();
|
|
1627
|
+
const elk = new ELK({
|
|
1628
|
+
workerFactory: (url) => new WorkerCtor(url)
|
|
1629
|
+
});
|
|
1602
1630
|
const result = await elk.layout(graph);
|
|
1603
1631
|
return {
|
|
1604
1632
|
graph: result,
|
|
@@ -2507,6 +2535,7 @@ async function generate(inputPath, options = {}) {
|
|
|
2507
2535
|
const verbose = options.verbose ?? false;
|
|
2508
2536
|
const skipPng = options.png === false;
|
|
2509
2537
|
const skipLlm = options.llm === false;
|
|
2538
|
+
const saveArtifacts = options.artifacts ?? false;
|
|
2510
2539
|
if (!skipPng) {
|
|
2511
2540
|
const browserCheck = await checkBrowserAvailability();
|
|
2512
2541
|
if (!browserCheck.available) {
|
|
@@ -2556,12 +2585,21 @@ async function generate(inputPath, options = {}) {
|
|
|
2556
2585
|
for (const file of detected) {
|
|
2557
2586
|
console.log(`
|
|
2558
2587
|
Generating diagram for: ${file.name}`);
|
|
2588
|
+
const baseName = file.name.replace(/\.(yml|yaml)$/i, "");
|
|
2589
|
+
const writeArtifact = async (suffix, data) => {
|
|
2590
|
+
if (!saveArtifacts) return;
|
|
2591
|
+
const artifactPath = join6(outputDir, `${baseName}.${suffix}.json`);
|
|
2592
|
+
await writeFile2(artifactPath, JSON.stringify(data, null, 2));
|
|
2593
|
+
console.log(` \x1B[32m\u2713\x1B[0m Saved: ${artifactPath}`);
|
|
2594
|
+
};
|
|
2559
2595
|
if (verbose) console.log(" Step 1: Parsing...");
|
|
2560
|
-
|
|
2596
|
+
const parsedGraph = await parseIaC(file, verbose);
|
|
2597
|
+
let graph = parsedGraph;
|
|
2561
2598
|
if (verbose) {
|
|
2562
2599
|
console.log(` Found ${graph.nodes.length} services`);
|
|
2563
2600
|
console.log(` Found ${graph.edges.length} dependencies`);
|
|
2564
2601
|
}
|
|
2602
|
+
await writeArtifact("parsed", parsedGraph);
|
|
2565
2603
|
if (llmEnabled && apiKey) {
|
|
2566
2604
|
if (verbose) console.log(" Step 2: Enhancing with LLM...");
|
|
2567
2605
|
try {
|
|
@@ -2574,12 +2612,14 @@ Generating diagram for: ${file.name}`);
|
|
|
2574
2612
|
} else if (verbose) {
|
|
2575
2613
|
console.log(" Step 2: Skipping LLM enhancement");
|
|
2576
2614
|
}
|
|
2615
|
+
await writeArtifact("enhanced", graph);
|
|
2577
2616
|
if (verbose) console.log(" Step 3: Computing layout...");
|
|
2578
2617
|
const elkConversion = infraGraphToElk(graph);
|
|
2579
2618
|
const elkLayoutResult = await runLayout(elkConversion.graph);
|
|
2619
|
+
await writeArtifact("elk-input", elkConversion.graph);
|
|
2620
|
+
await writeArtifact("elk-output", elkLayoutResult.graph);
|
|
2580
2621
|
if (verbose) console.log(" Step 4: Generating Excalidraw...");
|
|
2581
2622
|
const excalidraw = renderWithElkLayout(graph, elkLayoutResult.graph);
|
|
2582
|
-
const baseName = file.name.replace(/\.(yml|yaml)$/i, "");
|
|
2583
2623
|
const excalidrawPath = join6(outputDir, `${baseName}.excalidraw`);
|
|
2584
2624
|
await writeFile2(excalidrawPath, JSON.stringify(excalidraw, null, 2));
|
|
2585
2625
|
console.log(` \x1B[32m\u2713\x1B[0m Saved: ${excalidrawPath}`);
|
|
@@ -2601,7 +2641,10 @@ var program = new Command2().name("iac-diagrams").description(
|
|
|
2601
2641
|
"[path]",
|
|
2602
2642
|
"File or directory to process (default: current directory)",
|
|
2603
2643
|
"."
|
|
2604
|
-
).option("-o, --output <dir>", "Output directory", "./docs/diagrams").option("--no-llm", "Disable LLM enhancement").option("--no-png", "Skip PNG rendering (output .excalidraw only)").option(
|
|
2644
|
+
).option("-o, --output <dir>", "Output directory", "./docs/diagrams").option("--no-llm", "Disable LLM enhancement").option("--no-png", "Skip PNG rendering (output .excalidraw only)").option(
|
|
2645
|
+
"--artifacts",
|
|
2646
|
+
"Save parsed/enhanced/elk JSON artifacts alongside outputs"
|
|
2647
|
+
).option("-v, --verbose", "Show detailed output").action(
|
|
2605
2648
|
async (path, options) => {
|
|
2606
2649
|
await generate(path, options);
|
|
2607
2650
|
}
|