flowbook 0.2.1 → 0.2.3
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 +0 -1
- package/dist/cli.js +3 -29
- package/package.json +1 -1
- package/src/node/init.ts +1 -32
- package/src/skills/flowbook/SKILL.md +48 -1
package/README.md
CHANGED
package/dist/cli.js
CHANGED
|
@@ -1,26 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/node/init.ts
|
|
4
|
-
import { readFileSync, writeFileSync, existsSync
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
5
5
|
import { resolve } from "path";
|
|
6
6
|
import { execSync } from "child_process";
|
|
7
|
-
var EXAMPLE_FLOW = `---
|
|
8
|
-
title: Example Flow
|
|
9
|
-
category: Getting Started
|
|
10
|
-
tags: [example]
|
|
11
|
-
order: 1
|
|
12
|
-
description: An example flowchart to get you started
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
\`\`\`mermaid
|
|
16
|
-
flowchart TD
|
|
17
|
-
A[Start] --> B{Decision}
|
|
18
|
-
B -->|Yes| C[Action A]
|
|
19
|
-
B -->|No| D[Action B]
|
|
20
|
-
C --> E[End]
|
|
21
|
-
D --> E
|
|
22
|
-
\`\`\`
|
|
23
|
-
`;
|
|
24
7
|
async function initFlowbook() {
|
|
25
8
|
const cwd = process.cwd();
|
|
26
9
|
const pkgPath = resolve(cwd, "package.json");
|
|
@@ -55,15 +38,6 @@ async function initFlowbook() {
|
|
|
55
38
|
} else {
|
|
56
39
|
console.log(" \u2713 Scripts already exist in package.json");
|
|
57
40
|
}
|
|
58
|
-
const flowsDir = resolve(cwd, "flows");
|
|
59
|
-
const examplePath = resolve(flowsDir, "example.flow.md");
|
|
60
|
-
if (!existsSync(examplePath)) {
|
|
61
|
-
mkdirSync(flowsDir, { recursive: true });
|
|
62
|
-
writeFileSync(examplePath, EXAMPLE_FLOW);
|
|
63
|
-
console.log(" \u2713 Created flows/example.flow.md");
|
|
64
|
-
} else {
|
|
65
|
-
console.log(" \u2713 Example flow already exists");
|
|
66
|
-
}
|
|
67
41
|
const gitignorePath = resolve(cwd, ".gitignore");
|
|
68
42
|
if (existsSync(gitignorePath)) {
|
|
69
43
|
const gitignore = readFileSync(gitignorePath, "utf-8");
|
|
@@ -235,7 +209,7 @@ async function buildStatic(options) {
|
|
|
235
209
|
}
|
|
236
210
|
|
|
237
211
|
// src/node/skill.ts
|
|
238
|
-
import { existsSync as existsSync2, mkdirSync
|
|
212
|
+
import { existsSync as existsSync2, mkdirSync, copyFileSync } from "fs";
|
|
239
213
|
import { resolve as resolve3, dirname as dirname2 } from "path";
|
|
240
214
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
241
215
|
import { homedir } from "os";
|
|
@@ -357,7 +331,7 @@ function resolveAgents(agentArg) {
|
|
|
357
331
|
function installFile(src, destDir, destFilename) {
|
|
358
332
|
const dest = resolve3(destDir, destFilename);
|
|
359
333
|
if (existsSync2(dest)) return false;
|
|
360
|
-
|
|
334
|
+
mkdirSync(destDir, { recursive: true });
|
|
361
335
|
copyFileSync(src, dest);
|
|
362
336
|
return true;
|
|
363
337
|
}
|
package/package.json
CHANGED
package/src/node/init.ts
CHANGED
|
@@ -1,26 +1,7 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, existsSync
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { execSync } from "node:child_process";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
const EXAMPLE_FLOW = `---
|
|
7
|
-
title: Example Flow
|
|
8
|
-
category: Getting Started
|
|
9
|
-
tags: [example]
|
|
10
|
-
order: 1
|
|
11
|
-
description: An example flowchart to get you started
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
\`\`\`mermaid
|
|
15
|
-
flowchart TD
|
|
16
|
-
A[Start] --> B{Decision}
|
|
17
|
-
B -->|Yes| C[Action A]
|
|
18
|
-
B -->|No| D[Action B]
|
|
19
|
-
C --> E[End]
|
|
20
|
-
D --> E
|
|
21
|
-
\`\`\`
|
|
22
|
-
`;
|
|
23
|
-
|
|
24
5
|
export async function initFlowbook() {
|
|
25
6
|
const cwd = process.cwd();
|
|
26
7
|
const pkgPath = resolve(cwd, "package.json");
|
|
@@ -64,18 +45,6 @@ export async function initFlowbook() {
|
|
|
64
45
|
console.log(" ✓ Scripts already exist in package.json");
|
|
65
46
|
}
|
|
66
47
|
|
|
67
|
-
// 3. Create example flow file
|
|
68
|
-
const flowsDir = resolve(cwd, "flows");
|
|
69
|
-
const examplePath = resolve(flowsDir, "example.flow.md");
|
|
70
|
-
|
|
71
|
-
if (!existsSync(examplePath)) {
|
|
72
|
-
mkdirSync(flowsDir, { recursive: true });
|
|
73
|
-
writeFileSync(examplePath, EXAMPLE_FLOW);
|
|
74
|
-
console.log(" ✓ Created flows/example.flow.md");
|
|
75
|
-
} else {
|
|
76
|
-
console.log(" ✓ Example flow already exists");
|
|
77
|
-
}
|
|
78
|
-
|
|
79
48
|
// 4. Add flowbook-static to .gitignore
|
|
80
49
|
const gitignorePath = resolve(cwd, ".gitignore");
|
|
81
50
|
if (existsSync(gitignorePath)) {
|
|
@@ -275,6 +275,37 @@ flowchart TD
|
|
|
275
275
|
I[\Output\] %% Reverse parallelogram: response
|
|
276
276
|
```
|
|
277
277
|
|
|
278
|
+
#### Label Quoting Rules (MANDATORY)
|
|
279
|
+
|
|
280
|
+
Node labels containing special characters **MUST** be wrapped in double quotes to prevent Mermaid parse errors.
|
|
281
|
+
|
|
282
|
+
**Characters that REQUIRE quoting:**
|
|
283
|
+
|
|
284
|
+
| Character | Why it breaks | Unquoted (BROKEN) | Quoted (CORRECT) |
|
|
285
|
+
|-----------|--------------|-------------------|------------------|
|
|
286
|
+
| `()` | Conflicts with `([...])` stadium and `(...)` rounded shapes | `A([Agent run() Start])` | `A(["Agent run() Start"])` |
|
|
287
|
+
| `{}` | Conflicts with `{...}` diamond shape | `B{tokio::select!{}}` | `B{"tokio::select!{}"}` |
|
|
288
|
+
| `[]` | Conflicts with `[...]` rectangle shape | `C[arr[0] value]` | `C["arr[0] value"]` |
|
|
289
|
+
| `::` | Interpreted as Mermaid class/namespace syntax | `D[std::io::Error]` | `D["std::io::Error"]` |
|
|
290
|
+
| `#` | Interpreted as Unicode escape or comment | `E[Issue #42]` | `E["Issue #42"]` |
|
|
291
|
+
| `&` | Interpreted as HTML entity start | `F[A & B]` | `F["A & B"]` |
|
|
292
|
+
|
|
293
|
+
**Rule: When in doubt, quote it.** Quoting a label that doesn't need it causes no harm. Unquoted special characters WILL break rendering.
|
|
294
|
+
|
|
295
|
+
**Examples of correct quoting by node shape:**
|
|
296
|
+
|
|
297
|
+
```mermaid
|
|
298
|
+
flowchart TD
|
|
299
|
+
A(["fn main() entry"]) %% Stadium with parens
|
|
300
|
+
B["process_data(input)"] %% Rectangle with parens
|
|
301
|
+
C{"is_valid(x)?"} %% Diamond with parens
|
|
302
|
+
D[["handle_error(err)"]] %% Subroutine with parens
|
|
303
|
+
E{{"validate(req)"}} %% Hexagon with parens
|
|
304
|
+
F["Config::new()"] %% Rectangle with double colon
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**NEVER generate unquoted labels containing `()`, `{}`, `[]`, `::`, `#`, or `&`.**
|
|
308
|
+
|
|
278
309
|
#### Edge Labels
|
|
279
310
|
|
|
280
311
|
```mermaid
|
|
@@ -369,7 +400,7 @@ description: POST /api/auth/login — validates credentials and returns JWT toke
|
|
|
369
400
|
```mermaid
|
|
370
401
|
flowchart TD
|
|
371
402
|
A([POST /api/auth/login]) --> B[/Parse Request Body/]
|
|
372
|
-
B --> C{{Validate Email & Password}}
|
|
403
|
+
B --> C{{"Validate Email & Password"}}
|
|
373
404
|
C -->|Invalid| D[\400 Bad Request/]
|
|
374
405
|
C -->|Valid| E[(Find User by Email)]
|
|
375
406
|
E -->|Not Found| F[\401 Unauthorized/]
|
|
@@ -402,6 +433,16 @@ For each generated `.flow.md` file:
|
|
|
402
433
|
1. Verify YAML frontmatter is valid (title, category present)
|
|
403
434
|
2. Verify mermaid code block is properly fenced (``` mermaid ```)
|
|
404
435
|
3. Verify mermaid syntax has no obvious errors (matched brackets, valid node IDs)
|
|
436
|
+
4. **Special Character Validation (CRITICAL)**: Scan ALL node labels for unquoted special characters:
|
|
437
|
+
- `()` inside any node shape → MUST be quoted: `A(["label()"])` not `A([label()])`
|
|
438
|
+
- `{}` inside any node shape → MUST be quoted: `A{"label{}"}` not `A{label{}}`
|
|
439
|
+
- `[]` inside any node shape → MUST be quoted: `A["label[]"]` not `A[label[]]`
|
|
440
|
+
- `::` anywhere in labels → MUST be quoted: `A["std::io"]` not `A[std::io]`
|
|
441
|
+
- `#` anywhere in labels → MUST be quoted: `A["Issue #1"]` not `A[Issue #1]`
|
|
442
|
+
- `&` anywhere in labels → MUST be quoted: `A["A & B"]` not `A[A & B]`
|
|
443
|
+
- If ANY unquoted special characters are found, fix them BEFORE proceeding to build
|
|
444
|
+
5. Verify all node IDs are unique within each diagram
|
|
445
|
+
6. Verify subgraph labels don't contain special characters
|
|
405
446
|
|
|
406
447
|
### 5.2 Build Verification
|
|
407
448
|
|
|
@@ -483,6 +524,12 @@ Build: ✅ / ❌
|
|
|
483
524
|
### Mermaid syntax errors
|
|
484
525
|
- **Brackets**: Every `[`, `{`, `(` must be closed
|
|
485
526
|
- **Special characters in labels**: Wrap in double quotes: `A["User's Input"]`
|
|
527
|
+
- **Parentheses in labels** (MOST COMMON): `A([run() Start])` → Parse error. Fix: `A(["run() Start"])`
|
|
528
|
+
- **Double colons in labels**: `A[std::io::Error]` → Interpreted as class syntax. Fix: `A["std::io::Error"]`
|
|
529
|
+
- **Curly braces in labels**: `B{select!{}}` → Conflicts with diamond shape. Fix: `B{"select!{}"}`
|
|
530
|
+
- **Square brackets in labels**: `C[arr[0]]` → Conflicts with rectangle shape. Fix: `C["arr[0]"]`
|
|
531
|
+
- **Hash in labels**: `D[Issue #42]` → Unicode escape. Fix: `D["Issue #42"]`
|
|
532
|
+
- **Ampersand in labels**: `E[A & B]` → HTML entity. Fix: `E["A & B"]`
|
|
486
533
|
- **Arrow syntax**: Use `-->` for solid, `-.->` for dotted, `==>` for thick
|
|
487
534
|
- **Node ID reuse**: Each node ID must be unique per diagram. Reuse ID to reference same node.
|
|
488
535
|
- **Subgraph naming**: Subgraph labels cannot contain special characters
|