create-byan-agent 2.19.2 → 2.20.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 (49) hide show
  1. package/CHANGELOG.md +148 -0
  2. package/README.md +4 -4
  3. package/install/src/byan-v2/generation/templates/default-agent.md +1 -1
  4. package/install/templates/.claude/CLAUDE.md +1 -1
  5. package/install/templates/.claude/hooks/fd-phase-guard.js +2 -2
  6. package/install/templates/.claude/hooks/mantra-validate.js +16 -8
  7. package/install/templates/.claude/hooks/strict-scope-guard.js +25 -7
  8. package/install/templates/.claude/rules/native-workflows.md +32 -0
  9. package/install/templates/.claude/skills/byan-byan/SKILL.md +5 -5
  10. package/install/templates/.claude/skills/byan-mantra-audit/SKILL.md +53 -0
  11. package/install/templates/.claude/skills/byan-merise-agile/SKILL.md +2 -2
  12. package/install/templates/.claude/skills/byan-native-dev-story/SKILL.md +83 -0
  13. package/install/templates/.claude/workflows/INDEX.md +35 -0
  14. package/install/templates/.claude/workflows/check-implementation-readiness.js +280 -0
  15. package/install/templates/.claude/workflows/code-review.js +179 -0
  16. package/install/templates/.claude/workflows/create-excalidraw-dataflow.js +214 -0
  17. package/install/templates/.claude/workflows/create-excalidraw-diagram.js +188 -0
  18. package/install/templates/.claude/workflows/create-excalidraw-flowchart.js +225 -0
  19. package/install/templates/.claude/workflows/create-excalidraw-wireframe.js +192 -0
  20. package/install/templates/.claude/workflows/create-story.js +216 -0
  21. package/install/templates/.claude/workflows/dev-story.js +100 -0
  22. package/install/templates/.claude/workflows/document-project.js +455 -0
  23. package/install/templates/.claude/workflows/qa-automate.js +169 -0
  24. package/install/templates/.claude/workflows/quick-dev.js +273 -0
  25. package/install/templates/.claude/workflows/sprint-planning.js +261 -0
  26. package/install/templates/.claude/workflows/testarch-atdd.js +287 -0
  27. package/install/templates/.claude/workflows/testarch-automate.js +229 -0
  28. package/install/templates/.claude/workflows/testarch-ci.js +184 -0
  29. package/install/templates/.claude/workflows/testarch-framework.js +267 -0
  30. package/install/templates/.claude/workflows/testarch-nfr.js +316 -0
  31. package/install/templates/.claude/workflows/testarch-test-design.js +293 -0
  32. package/install/templates/.claude/workflows/testarch-test-review.js +321 -0
  33. package/install/templates/.claude/workflows/testarch-trace.js +316 -0
  34. package/install/templates/.githooks/pre-commit +49 -15
  35. package/install/templates/_byan/config.yaml +15 -5
  36. package/install/templates/_byan/mcp/byan-mcp-server/bin/byan-build-workflows.js +20 -0
  37. package/install/templates/_byan/mcp/byan-mcp-server/bin/byan-lint-workflows.js +57 -0
  38. package/install/templates/_byan/mcp/byan-mcp-server/lib/native-loop.js +39 -0
  39. package/install/templates/_byan/mcp/byan-mcp-server/lib/workflows-generator.js +149 -0
  40. package/install/templates/_byan/mcp/byan-mcp-server/lib/workflows-lint.js +113 -0
  41. package/install/templates/_byan/workflow/simple/byan/feature-workflow.md +14 -11
  42. package/install/templates/docs/native-workflows-contract.md +84 -0
  43. package/package.json +2 -2
  44. package/src/byan-v2/data/agent-scopes.json +46 -0
  45. package/src/byan-v2/data/mantras.json +194 -8
  46. package/src/byan-v2/generation/mantra-audit.js +147 -0
  47. package/src/byan-v2/generation/mantra-validator.js +56 -6
  48. package/src/byan-v2/generation/scope-resolver.js +102 -0
  49. package/src/byan-v2/generation/templates/default-agent.md +1 -1
@@ -0,0 +1,214 @@
1
+ export const meta = {
2
+ name: 'create-excalidraw-dataflow',
3
+ description: 'Native port of the BYAN create-excalidraw-dataflow workflow: build a Data Flow Diagram (DFD) in Excalidraw .excalidraw JSON format. Mirrors the 10 source steps (contextual analysis -> level -> requirements -> theme -> plan -> load resources -> build elements -> optimize/save -> validate JSON -> validate content) and returns a structured verdict for the orchestrating skill to present at the human gate.',
4
+ phases: [
5
+ { title: 'CONTEXT', detail: 'step 0 - contextual analysis of the DFD request' },
6
+ { title: 'PLAN', detail: 'steps 1-4 - resolve level, requirements, theme, and plan the DFD structure' },
7
+ { title: 'RESOURCES', detail: 'step 5 - load templates, library, theme, helpers' },
8
+ { title: 'BUILD', detail: 'step 6 - build DFD elements per standard notation' },
9
+ { title: 'SAVE', detail: 'step 7 - optimize, strip deleted, save the .excalidraw file' },
10
+ { title: 'VALIDATE_JSON', detail: 'step 8 - JSON.parse validation loop (fix-and-retry, never delete)' },
11
+ { title: 'VALIDATE_CONTENT', detail: 'step 9 - validate against checklist.md, return verdict' },
12
+ ],
13
+ }
14
+
15
+ // ---------------------------------------------------------------------------
16
+ // FD / STRICT STATE CONTRACT (re-asserted inline).
17
+ //
18
+ // The in-CLI Workflow tool runs this script OUTSIDE the conversation turn, so
19
+ // BYAN's main-thread hooks (fd-phase-guard, strict-scope-guard, strict-stop-
20
+ // guard) DO NOT fire here. This script therefore:
21
+ // - NEVER imports/requires _byan/.../lib/fd-state.js and NEVER writes
22
+ // fd-state.json directly (forbidden by byan-lint-workflows.js).
23
+ // - uses NO wall-clock and NO randomness primitive (Date/RNG would
24
+ // break resume). Any timestamp/id is passed in via `args`.
25
+ // - returns DATA only. The orchestrating skill is the human-gated conductor;
26
+ // IT records FD/strict state via the byan_fd_* / byan_strict_* MCP tools
27
+ // AT the gate, and it owns the elicit="true" human decisions (DFD level,
28
+ // requirements, theme) that the source steps 1-3 prompt for.
29
+ // The .excalidraw FILE is the workflow's product, written by the BUILD/SAVE
30
+ // leaves — that is the artifact, not BYAN platform state.
31
+ // ---------------------------------------------------------------------------
32
+
33
+ // Source paths (workflow.yaml). The leaf agents read these real files; the
34
+ // script never touches the filesystem itself.
35
+ const ROOT = '/home/yan/BYAN'
36
+ const INSTALLED = `${ROOT}/_byan/workflow/simple/excalidraw-diagrams/create-dataflow`
37
+ const SHARED = `${ROOT}/_byan/workflow/simple/excalidraw-diagrams/_shared`
38
+ const HELPERS = `${ROOT}/_byan/connaissance/excalidraw/excalidraw-helpers.md`
39
+ const JSON_VALIDATION = `${ROOT}/_byan/connaissance/excalidraw/validate-json-instructions.md`
40
+ const TEMPLATES = `${SHARED}/excalidraw-templates.yaml`
41
+ const LIBRARY = `${SHARED}/excalidraw-library.json`
42
+ const CHECKLIST = `${INSTALLED}/checklist.md`
43
+
44
+ // Human-elicited inputs (source steps 1-3). Defaults keep the engine runnable
45
+ // when the orchestrating skill has not yet resolved the gate; the skill should
46
+ // pass these in args once the user has answered.
47
+ const level = (args && args.level) || 'unspecified (resolve at human gate: context/level-0/level-1/level-2/custom)'
48
+ const requirements = (args && args.requirements) || 'unspecified (resolve at human gate: processes, data stores, external entities)'
49
+ const theme = (args && args.theme) || 'Standard DFD (process #e3f2fd, data store #e8f5e9, external entity #f3e5f5, border #1976d2)'
50
+ // Timestamp MUST come from args (no Date in the sandbox). Source default_output_file
51
+ // is dataflow-{timestamp}.excalidraw under {output_folder}/excalidraw-diagrams/.
52
+ const stamp = (args && args.timestamp) || 'TIMESTAMP'
53
+ const outputFile = (args && args.outputFile) ||
54
+ `${ROOT}/_byan-output/excalidraw-diagrams/dataflow-${stamp}.excalidraw`
55
+
56
+ // JSON validation convergence guard (source step 8: re-run until pass, NEVER
57
+ // delete the file). Bounded retry cap so the script cannot loop forever.
58
+ const MAX_FIX_ATTEMPTS = 3
59
+
60
+ const PLAN_SCHEMA = {
61
+ type: 'object',
62
+ required: ['processes', 'dataStores', 'externalEntities', 'dataFlows'],
63
+ properties: {
64
+ processes: { type: 'array', items: { type: 'string' }, description: 'numbered processes (1.0, 2.0, ...), verb phrases' },
65
+ dataStores: { type: 'array', items: { type: 'string' }, description: 'named data stores (D1, D2, ...), noun phrases' },
66
+ externalEntities: { type: 'array', items: { type: 'string' }, description: 'named external entities, noun phrases' },
67
+ dataFlows: { type: 'array', items: { type: 'string' }, description: 'labeled flows, source -> target with data name' },
68
+ notes: { type: 'string', description: 'layout / level notes' },
69
+ },
70
+ }
71
+
72
+ const JSON_VALIDATION_SCHEMA = {
73
+ type: 'object',
74
+ required: ['valid'],
75
+ properties: {
76
+ valid: { type: 'boolean', description: 'true ONLY if JSON.parse of the saved .excalidraw file succeeds' },
77
+ error: { type: 'string', description: 'parser error message and position when invalid' },
78
+ },
79
+ }
80
+
81
+ const CONTENT_SCHEMA = {
82
+ type: 'object',
83
+ required: ['pass', 'failedItems'],
84
+ properties: {
85
+ pass: { type: 'boolean', description: 'true only if every checklist.md item is satisfied' },
86
+ failedItems: { type: 'array', items: { type: 'string' }, description: 'checklist items not satisfied' },
87
+ summary: { type: 'string', description: 'one-line content-validation status' },
88
+ },
89
+ }
90
+
91
+ // --- Step 0: Contextual Analysis -------------------------------------------
92
+ phase('CONTEXT')
93
+ const context = await agent(
94
+ `You are the create-excalidraw-dataflow workflow (BMad). Read the source spec at ` +
95
+ `${INSTALLED}/instructions.md and ${INSTALLED}/workflow.yaml.\n` +
96
+ `STEP 0 (Contextual Analysis): from the request, extract what is already known about the DFD: ` +
97
+ `level, processes, data stores, external entities, data flows. ` +
98
+ `Request level=${JSON.stringify(level)}; requirements=${JSON.stringify(requirements)}. ` +
99
+ `Report which of (level, processes, data stores, external entities) are clear and which are missing. ` +
100
+ `Per the source, if ALL requirements are clear we may skip directly to structure planning.`,
101
+ { label: 'context-analysis', phase: 'CONTEXT' }
102
+ )
103
+
104
+ // --- Steps 1-4: Level, Requirements, Theme, Plan structure -----------------
105
+ // Source steps 1-3 are elicit="true" (human input). The orchestrating skill
106
+ // owns those decisions and passes the answers via args; here we consolidate
107
+ // the resolved inputs and produce the concrete DFD structure (step 4).
108
+ phase('PLAN')
109
+ const plan = await agent(
110
+ `STEP 1-4 of create-excalidraw-dataflow. Context analysis: ${context}\n` +
111
+ `Resolved human inputs (source steps 1-3 elicit): level=${JSON.stringify(level)}; ` +
112
+ `requirements=${JSON.stringify(requirements)}; theme=${JSON.stringify(theme)}.\n` +
113
+ `STEP 4 (Plan DFD Structure): produce the concrete plan. ` +
114
+ `List processes numbered 1.0/2.0..., data stores D1/D2..., external entities, and every data flow ` +
115
+ `(source -> target, labeled with the data name). Respect DFD rules: no direct flow between two external ` +
116
+ `entities, no direct flow between two data stores. Match the chosen DFD level. ` +
117
+ `Read ${HELPERS} for standard DFD notation if needed.`,
118
+ { label: 'plan-structure', phase: 'PLAN', schema: PLAN_SCHEMA }
119
+ )
120
+
121
+ // --- Step 5: Load Resources -------------------------------------------------
122
+ phase('RESOURCES')
123
+ const resources = await agent(
124
+ `STEP 5 (Load Resources) of create-excalidraw-dataflow. ` +
125
+ `Load and summarize the materials needed to build the diagram:\n` +
126
+ `- templates: ${TEMPLATES} (extract the \`dataflow\` section)\n` +
127
+ `- library: ${LIBRARY}\n` +
128
+ `- theme: ${JSON.stringify(theme)} (use existing theme.json if present, else this scheme)\n` +
129
+ `- helpers: ${HELPERS} (standard DFD notation + Excalidraw element shapes)\n` +
130
+ `Report the element templates (process ellipse, data-store rectangle/parallel-lines, external-entity ` +
131
+ `rectangle, labeled-arrow) and the color/stroke values you will apply. Plan structure: ${JSON.stringify(plan)}`,
132
+ { label: 'load-resources', phase: 'RESOURCES' }
133
+ )
134
+
135
+ // --- Step 6: Build DFD Elements --------------------------------------------
136
+ phase('BUILD')
137
+ const built = await agent(
138
+ `STEP 6 (Build DFD Elements) of create-excalidraw-dataflow. Resources: ${resources}\n` +
139
+ `Build the full Excalidraw element set following standard DFD notation, in this build order: ` +
140
+ `(1) external entities as rectangles with bold border; (2) processes as circles/ellipses carrying their ` +
141
+ `number (1.0, 2.0, verb phrases); (3) data stores as parallel lines or rectangles (D1, D2, noun phrases); ` +
142
+ `(4) data flows as labeled arrows showing direction. ` +
143
+ `Layout: external entities at the edges, processes in the center, data stores between processes, ` +
144
+ `minimize crossing flows, left-to-right or top-to-bottom. ` +
145
+ `Apply the theme colors. Bind arrows to their endpoints and group related elements. ` +
146
+ `Produce a complete Excalidraw scene object (type "excalidraw", version, source, elements[], appState, files{}).`,
147
+ { label: 'build-elements', phase: 'BUILD' }
148
+ )
149
+
150
+ // --- Step 7: Optimize and Save ---------------------------------------------
151
+ phase('SAVE')
152
+ const saved = await agent(
153
+ `STEP 7 (Optimize and Save) of create-excalidraw-dataflow. Built scene: ${built}\n` +
154
+ `Verify DFD-rule compliance (numbered processes, labeled flows, no entity->entity or store->store direct flow). ` +
155
+ `Strip unused elements and any element with isDeleted: true. ` +
156
+ `Write the final .excalidraw JSON to: ${outputFile}. Confirm the file was written.`,
157
+ { label: 'optimize-save', phase: 'SAVE' }
158
+ )
159
+
160
+ // --- Step 8: Validate JSON Syntax (bounded fix-and-retry, never delete) -----
161
+ phase('VALIDATE_JSON')
162
+ let jsonCheck = { valid: false, error: 'not yet validated' }
163
+ let fixAttempts = 0
164
+ while (true) {
165
+ jsonCheck = await agent(
166
+ `STEP 8 (Validate JSON Syntax) of create-excalidraw-dataflow. Attempt ${fixAttempts + 1}/${MAX_FIX_ATTEMPTS + 1}.\n` +
167
+ `Validate the saved file with: node -e "JSON.parse(require('fs').readFileSync('${outputFile}','utf8')); console.log('valid')". ` +
168
+ `Guidance: ${JSON_VALIDATION}. ` +
169
+ `CRITICAL: NEVER delete the file on failure. If JSON.parse fails, read the error position, open the file, ` +
170
+ `fix the exact syntax error (missing comma/bracket/quote), save, and report valid=false with the error. ` +
171
+ `If it parses, report valid=true. Save context: ${saved}`,
172
+ { label: `validate-json-${fixAttempts + 1}`, phase: 'VALIDATE_JSON', schema: JSON_VALIDATION_SCHEMA }
173
+ )
174
+ log(`json validation attempt ${fixAttempts + 1}: valid=${Boolean(jsonCheck && jsonCheck.valid)}`)
175
+ if (jsonCheck && jsonCheck.valid) break
176
+ fixAttempts += 1
177
+ if (fixAttempts > MAX_FIX_ATTEMPTS) break
178
+ }
179
+
180
+ // --- Step 9: Validate Content (against checklist.md) ------------------------
181
+ phase('VALIDATE_CONTENT')
182
+ const contentCheck = await agent(
183
+ `STEP 9 (Validate Content) of create-excalidraw-dataflow. ` +
184
+ `JSON valid=${Boolean(jsonCheck && jsonCheck.valid)}. ` +
185
+ `Validate the saved diagram (${outputFile}) against EVERY item in the checklist at ${CHECKLIST}: ` +
186
+ `DFD notation (process ellipses, data-store parallel-lines/rectangles, external-entity rectangles, labeled ` +
187
+ `arrows), structure (numbered processes, labeled flows, named stores/entities), completeness (all I/O accounted, ` +
188
+ `no orphaned processes, data conservation, level appropriate), layout (logical direction, minimal crossings, ` +
189
+ `balanced, grid-aligned), and technical quality (grouped, bound arrows, readable text, no isDeleted:true, valid JSON, ` +
190
+ `saved to correct location). List any item not satisfied.`,
191
+ { label: 'validate-content', phase: 'VALIDATE_CONTENT', schema: CONTENT_SCHEMA }
192
+ )
193
+
194
+ // Return DATA only. The orchestrating skill presents this verdict at the human
195
+ // gate and records FD/strict state via MCP.
196
+ const jsonValid = Boolean(jsonCheck && jsonCheck.valid)
197
+ const contentPass = Boolean(contentCheck && contentCheck.pass)
198
+ return {
199
+ workflow: 'create-excalidraw-dataflow',
200
+ summary: jsonValid && contentPass
201
+ ? 'DFD built, saved, JSON-valid, and checklist-compliant'
202
+ : 'DFD produced but validation incomplete - see jsonValid/contentCheck',
203
+ outputFile,
204
+ level,
205
+ steps: 10,
206
+ plan,
207
+ jsonValid,
208
+ jsonFixAttempts: fixAttempts,
209
+ maxFixAttempts: MAX_FIX_ATTEMPTS,
210
+ contentPass,
211
+ failedChecklistItems: (contentCheck && contentCheck.failedItems) || [],
212
+ needsHumanGate: true,
213
+ result: contentCheck,
214
+ }
@@ -0,0 +1,188 @@
1
+ export const meta = {
2
+ name: 'create-excalidraw-diagram',
3
+ description: 'Native port of the BYAN create-diagram (excalidraw) pipeline workflow: turn a confirmed diagram spec (type, components, relationships, notation, theme) into a valid .excalidraw file via plan -> load-resources -> build elements -> optimize/save -> validate-JSON (bounded fix loop) -> validate-content. Elicitation gates (steps 1-4: diagram type, requirements, theme choice) stay OUTSIDE the script and arrive via args; the script returns a structured verdict for the orchestrating skill to present at the human gate.',
4
+ phases: [
5
+ { title: 'ANALYZE', detail: 'source step 0 - extract diagram type, components, relationships, notation from the confirmed spec' },
6
+ { title: 'PLAN', detail: 'source step 5 - list components/entities, map relationships, lay out the structure' },
7
+ { title: 'LOAD-RESOURCES', detail: 'source step 6 - load excalidraw templates/library/helpers and merge the chosen theme' },
8
+ { title: 'BUILD', detail: 'source step 7 - build shapes+labels (groupIds/containerId) and connections (start/endBinding) in the per-type build order on a 20px grid' },
9
+ { title: 'SAVE', detail: 'source step 8 - strip appState/files/isDeleted elements and write the .excalidraw file' },
10
+ { title: 'VALIDATE-JSON', detail: 'source step 9 - JSON.parse the saved file, fix syntax errors in place, re-validate up to a hard cap (NEVER delete the file)' },
11
+ { title: 'VALIDATE-CONTENT', detail: 'source step 10 - validate the diagram against the create-diagram checklist.md' },
12
+ ],
13
+ }
14
+
15
+ // ---------------------------------------------------------------------------
16
+ // FD / STRICT STATE CONTRACT (re-asserted inline — byan-lint-workflows).
17
+ //
18
+ // The in-CLI Workflow tool runs this script OUTSIDE the conversation turn, so
19
+ // BYAN's main-thread hooks (fd-phase-guard, strict-scope-guard, strict-stop-
20
+ // guard, mantra-validate) DO NOT fire here. This script therefore:
21
+ // - NEVER imports/requires _byan/.../lib/fd-state.js and NEVER writes
22
+ // fd-state.json directly (enforced by byan-lint-workflows.js).
23
+ // - uses NO wall-clock and NO randomness primitive (wall-clock/RNG/
24
+ // crypto) — those break resume; any timestamp/id is passed via args.
25
+ // - returns DATA only. The orchestrating skill is the human-gated conductor;
26
+ // IT records FD/strict state via the byan_fd_* / byan_strict_* MCP tools
27
+ // AT the gate, and it owns the human decisions (steps 1-4 elicitation:
28
+ // diagram type, requirements, notation, theme choice).
29
+ // The .excalidraw FILE is the workflow's product, written by the SAVE leaf —
30
+ // that is the artifact, not BYAN platform state.
31
+ // ---------------------------------------------------------------------------
32
+
33
+ // Bounded JSON-fix loop guard — mirrors source step 9 ("repeat until validation
34
+ // passes") but with a HARD cap so the sandbox cannot loop forever. The sandbox
35
+ // forbids unbounded loops; this turns the prose rule into a real integer cap.
36
+ const MAX_JSON_FIX_CYCLES = 5
37
+
38
+ // Spec arrives pre-confirmed from the human gate (source steps 0-4). The script
39
+ // never elicits; it consumes what the orchestrating skill collected.
40
+ const diagramType = (args && args.diagramType) || 'system architecture'
41
+ const spec = (args && args.spec) || 'components, relationships and notation as described by the user'
42
+ const notation = (args && args.notation) || 'Standard'
43
+ const theme = (args && args.theme) || 'Professional (Component #e3f2fd / Database #e8f5e9 / Service #fff3e0 / Border #1976d2)'
44
+ // Timestamp/output path are passed in (no wall-clock in the sandbox).
45
+ const outputFile =
46
+ (args && args.outputFile) ||
47
+ `_byan-output/excalidraw-diagrams/diagram-${(args && args.timestamp) || 'GATE-TIMESTAMP'}.excalidraw`
48
+
49
+ const helpers = '_byan/connaissance/excalidraw/excalidraw-helpers.md'
50
+ const jsonValidation = '_byan/connaissance/excalidraw/validate-json-instructions.md'
51
+ const templates = '_byan/workflow/simple/excalidraw-diagrams/_shared/excalidraw-templates.yaml'
52
+ const library = '_byan/workflow/simple/excalidraw-diagrams/_shared/excalidraw-library.json'
53
+ const checklist = '_byan/workflow/simple/excalidraw-diagrams/create-diagram/checklist.md'
54
+
55
+ // --- Source step 0: Contextual Analysis ------------------------------------
56
+ phase('ANALYZE')
57
+ const analysis = await agent(
58
+ `You are the create-excalidraw-diagram engine (BMad excalidraw pipeline), executing step 0 "Contextual Analysis".\n` +
59
+ `The diagram spec is ALREADY confirmed by the user at the human gate — do NOT re-ask anything.\n` +
60
+ `Diagram type: ${JSON.stringify(diagramType)}\n` +
61
+ `Spec (components/entities + relationships): ${JSON.stringify(spec)}\n` +
62
+ `Notation standard: ${JSON.stringify(notation)}\n` +
63
+ `From this, extract and report a normalized structured intent: the resolved diagram type, the exhaustive list of ` +
64
+ `components/entities, the exhaustive list of relationships (with direction), and the notation rules that apply ` +
65
+ `for that type. If the spec is contradictory or missing a relationship endpoint, flag it explicitly (do not invent).`,
66
+ { label: 'contextual-analysis', phase: 'ANALYZE' }
67
+ )
68
+
69
+ // --- Source step 5: Plan Diagram Structure ---------------------------------
70
+ phase('PLAN')
71
+ const plan = await agent(
72
+ `Step 5 "Plan Diagram Structure". Confirmed intent:\n${analysis}\n\n` +
73
+ `List ALL components/entities and map ALL relationships. Produce a concrete planned layout for a ${JSON.stringify(diagramType)}: ` +
74
+ `assign each element an (x,y) snapped to a 20px grid, keep 40px spacing between components and 60px between sections, ` +
75
+ `and pick the build order appropriate to the type (Architecture: Services -> Databases -> Connections -> Labels; ` +
76
+ `ERD: Entities -> Attributes -> Relationships -> Cardinality; UML Class: Classes -> Attributes -> Methods -> Relationships; ` +
77
+ `UML Sequence: Actors -> Lifelines -> Messages -> Returns; UML Use Case: Actors -> Use Cases -> Relationships). ` +
78
+ `Report the layout and the chosen build order. Do NOT draw yet.`,
79
+ { label: 'plan-structure', phase: 'PLAN' }
80
+ )
81
+
82
+ // --- Source step 6: Load Resources -----------------------------------------
83
+ phase('LOAD-RESOURCES')
84
+ const resources = await agent(
85
+ `Step 6 "Load Resources". Read these files and report what you will reuse:\n` +
86
+ `- templates: ${templates} (extract the \`diagram\` section)\n` +
87
+ `- library: ${library}\n` +
88
+ `- helpers (element-creation guidelines): ${helpers}\n` +
89
+ `Merge the chosen theme into the template. Theme = ${JSON.stringify(theme)}.\n` +
90
+ `Report the resolved template skeleton, the available library items, and the merged theme color map ` +
91
+ `(component fill, database fill, service fill, border/accent stroke, text stroke #1e1e1e, arrow stroke).`,
92
+ { label: 'load-resources', phase: 'LOAD-RESOURCES' }
93
+ )
94
+
95
+ // --- Source step 7: Build Diagram Elements ---------------------------------
96
+ phase('BUILD')
97
+ const built = await agent(
98
+ `Step 7 "Build Diagram Elements". CRITICAL: follow the helpers (${helpers}) exactly.\n` +
99
+ `Planned layout & build order:\n${plan}\n\nResources & merged theme:\n${resources}\n\n` +
100
+ `For EACH component: generate unique shape-id/text-id/group-id; create the shape with groupIds and ` +
101
+ `boundElements; compute text width = (text.length * fontSize * 0.6) + 20 rounded to 10; create the text with ` +
102
+ `containerId=shape-id, the SAME groupIds, textAlign=center, verticalAlign=middle. For EACH connection: choose ` +
103
+ `straight (forward flow) or elbow (upward/backward/complex) arrow, set startBinding and endBinding, and update ` +
104
+ `boundElements on BOTH connected shapes. Follow the build order from the plan, snap every (x,y) to the 20px grid, ` +
105
+ `apply theme colors consistently, and keep IDs unique. Report the full in-memory excalidraw element array.`,
106
+ { label: 'build-elements', phase: 'BUILD' }
107
+ )
108
+
109
+ // --- Source step 8: Optimize and Save --------------------------------------
110
+ phase('SAVE')
111
+ const saved = await agent(
112
+ `Step 8 "Optimize and Save". Element array:\n${built}\n\n` +
113
+ `Strip from the final output: the appState object, the files object (unless images are used), every element with ` +
114
+ `isDeleted:true, unused library items, and any version history. Then WRITE the optimized excalidraw document to ` +
115
+ `${JSON.stringify(outputFile)} (type "excalidraw", a valid version/source header, and the elements array). ` +
116
+ `Report the saved path and the final element count.`,
117
+ { label: 'optimize-save', phase: 'SAVE' }
118
+ )
119
+
120
+ // --- Source step 9: Validate JSON Syntax (bounded fix loop) -----------------
121
+ phase('VALIDATE-JSON')
122
+ const JSON_SCHEMA = {
123
+ type: 'object',
124
+ required: ['valid'],
125
+ properties: {
126
+ valid: { type: 'boolean', description: 'true ONLY if node -e JSON.parse on the saved file exits 0' },
127
+ error: { type: 'string', description: 'the syntax error message + position when not valid' },
128
+ fixed: { type: 'boolean', description: 'true if a syntax error was found and fixed this pass' },
129
+ },
130
+ }
131
+ let jsonCycles = 0
132
+ let jsonResult = { valid: false, error: 'not started' }
133
+ while (true) {
134
+ jsonCycles += 1
135
+ jsonResult = await agent(
136
+ `Step 9 "Validate JSON Syntax", pass ${jsonCycles}. CRITICAL: NEVER delete the file if validation fails — fix it.\n` +
137
+ `Follow ${jsonValidation}. Run exactly:\n` +
138
+ ` node -e "JSON.parse(require('fs').readFileSync('${outputFile}', 'utf8')); console.log('valid')"\n` +
139
+ `If it exits 0, set valid=true. If it exits 1, read the error message/position, open ${JSON.stringify(outputFile)} at ` +
140
+ `that location, fix the single syntax error indicated (missing/extra comma, bracket, brace or quote), SAVE, set ` +
141
+ `fixed=true and valid=false, and report the error. Do not re-run here; the loop re-invokes you.`,
142
+ { label: `validate-json-${jsonCycles}`, phase: 'VALIDATE-JSON', schema: JSON_SCHEMA }
143
+ )
144
+ log(`json pass ${jsonCycles}: valid=${Boolean(jsonResult && jsonResult.valid)}`)
145
+ if (jsonResult && jsonResult.valid) break
146
+ if (jsonCycles >= MAX_JSON_FIX_CYCLES) break
147
+ }
148
+
149
+ // --- Source step 10: Validate Content (checklist) --------------------------
150
+ phase('VALIDATE-CONTENT')
151
+ const CONTENT_SCHEMA = {
152
+ type: 'object',
153
+ required: ['pass'],
154
+ properties: {
155
+ pass: { type: 'boolean', description: 'true only if every checklist item is satisfied' },
156
+ failedItems: { type: 'array', items: { type: 'string' }, description: 'checklist items that are not satisfied' },
157
+ elementCount: { type: 'integer', description: 'final element count (must be under 80)' },
158
+ notes: { type: 'string' },
159
+ },
160
+ }
161
+ const content = await agent(
162
+ `Step 10 "Validate Content". Validate the saved diagram ${JSON.stringify(outputFile)} against the checklist at ${checklist}.\n` +
163
+ `Check element structure (matching groupIds, containerId on text, text width, alignment), layout (20px grid, 40/60px ` +
164
+ `spacing, no overlaps), connections (start/endBinding on every arrow, boundElements updated, clear relationship types), ` +
165
+ `notation/standards for ${JSON.stringify(diagramType)} (${JSON.stringify(notation)}), theme consistency, and output ` +
166
+ `quality (element count under 80, no isDeleted elements, valid JSON, correct save location). ` +
167
+ `Set pass=true only if EVERY item holds; otherwise list the failed items precisely.`,
168
+ { label: 'validate-content', phase: 'VALIDATE-CONTENT', schema: CONTENT_SCHEMA }
169
+ )
170
+
171
+ // Return DATA only. The orchestrating skill presents this at the human gate
172
+ // ("Diagram created ... Open to view?") and records FD/strict state via MCP.
173
+ return {
174
+ workflow: 'create-excalidraw-diagram',
175
+ diagramType,
176
+ notation,
177
+ theme,
178
+ outputFile,
179
+ jsonValid: Boolean(jsonResult && jsonResult.valid),
180
+ jsonFixCycles: jsonCycles,
181
+ maxJsonFixCycles: MAX_JSON_FIX_CYCLES,
182
+ contentPass: Boolean(content && content.pass),
183
+ failedChecklistItems: (content && content.failedItems) || [],
184
+ elementCount: content && content.elementCount,
185
+ steps: 7,
186
+ needsHumanGate: true,
187
+ result: { analysis, plan, resources, built, saved, json: jsonResult, content },
188
+ }
@@ -0,0 +1,225 @@
1
+ export const meta = {
2
+ name: 'create-excalidraw-flowchart',
3
+ description: 'Native port of the BYAN create-excalidraw-flowchart workflow: turn gathered flowchart requirements + theme into a valid .excalidraw file via a deterministic pipeline (plan layout -> load template/library/helpers -> build bound elements -> optimize & save -> JSON-validate with a bounded retry loop -> content-validate against the checklist), returning a verdict for the orchestrating skill to present at the human gate.',
4
+ phases: [
5
+ { title: 'CONTEXT', detail: 'mirror step 0/1: restate gathered requirements (type, complexity, decisions, output path)' },
6
+ { title: 'PLAN', detail: 'mirror step 4: plan the flowchart layout (steps + decision points)' },
7
+ { title: 'RESOURCES', detail: 'mirror step 5: load template flowchart section, library, helpers, merge theme colors' },
8
+ { title: 'BUILD', detail: 'mirror step 6: build shapes/diamonds/circles with labels and bound arrows' },
9
+ { title: 'SAVE', detail: 'mirror step 7: strip deleted elements and save to the output file' },
10
+ { title: 'VALIDATE_JSON', detail: 'mirror step 8: JSON.parse the file, fix syntax, re-validate (bounded retry)' },
11
+ { title: 'VALIDATE_CONTENT', detail: 'mirror step 9: validate against checklist.md' },
12
+ { title: 'VERDICT', detail: 'return a structured verdict to the orchestrating skill' },
13
+ ],
14
+ }
15
+
16
+ // ---------------------------------------------------------------------------
17
+ // FD / STRICT STATE CONTRACT (re-asserted inline — byan-lint-workflows).
18
+ //
19
+ // The in-CLI Workflow tool runs this script OUTSIDE the conversation turn, so
20
+ // BYAN's main-thread hooks (fd-phase-guard, strict-scope-guard, strict-stop-
21
+ // guard, mantra-validate) DO NOT fire here. This script therefore:
22
+ // - NEVER imports/requires _byan/.../lib/fd-state.js and NEVER writes
23
+ // fd-state.json directly (forbidden by the linter; no import/require/fs).
24
+ // - uses NO wall-clock and NO randomness primitive (wall-clock / RNG
25
+ // break resume); any timestamp/id arrives via `args`.
26
+ // - returns DATA only. The orchestrating skill is the human-gated conductor;
27
+ // IT records FD/strict state via the byan_fd_* / byan_strict_* MCP tools.
28
+ // The .excalidraw FILE is this workflow's product (written by the BUILD/SAVE
29
+ // leaves) — that is the artifact, not BYAN platform state.
30
+ //
31
+ // The interactive elicitation of the source (step 1 gather-requirements, step 2
32
+ // reuse-theme, step 3 create-theme, step 4 structure-approval, step 8 "open to
33
+ // view?") are HUMAN GATES. They stay OUT of the script: their answers arrive as
34
+ // `args`, and the final open/approve decision is returned as a verdict.
35
+ // ---------------------------------------------------------------------------
36
+
37
+ // Convergence guard for step 8's JSON-validation retry. The source prose says
38
+ // "Repeat until validation passes" (unbounded). Turn it into a real counter
39
+ // with a hard cap so the loop cannot run forever in the sandbox.
40
+ const MAX_FIX_CYCLES = 3
41
+ function jsonFixGuard({ cycles, valid, maxCycles = MAX_FIX_CYCLES }) {
42
+ if (valid) return { done: true, abort: false, reason: 'valid-json' }
43
+ if (cycles >= maxCycles) return { done: true, abort: true, reason: `JSON still invalid after ${maxCycles} fix attempts` }
44
+ return { done: false, abort: false, reason: 'continue' }
45
+ }
46
+
47
+ // --- args (all gathered at the human gate by the orchestrating skill) --------
48
+ // flowType : "Business Process" | "Algorithm/Logic" | "User Journey" | "Data Pipeline" | "Other"
49
+ // complexity : "simple(3-5)" | "medium(6-10)" | "complex(11-20)" | "very-complex(20+)"
50
+ // decisionPoints : "none" | "few(1-2)" | "multiple(3-5)" | "complex(6+)"
51
+ // outputFile : absolute/relative path to the .excalidraw file to write
52
+ // theme : a theme.json-shaped object (primaryFill/accent/decision/text) or null
53
+ const flowType = (args && args.flowType) || 'Business Process Flow'
54
+ const complexity = (args && args.complexity) || 'medium(6-10)'
55
+ const decisionPoints = (args && args.decisionPoints) || 'few(1-2)'
56
+ const outputFile = (args && args.outputFile) || '_byan-output/excalidraw-diagrams/flowchart.excalidraw'
57
+ const theme = (args && args.theme) || null
58
+
59
+ const ELEMENTS_SCHEMA = {
60
+ type: 'object',
61
+ required: ['shapeCount', 'arrowCount', 'hasStart', 'hasEnd'],
62
+ properties: {
63
+ shapeCount: { type: 'number', description: 'number of labelled shapes built (circles/rectangles/diamonds)' },
64
+ arrowCount: { type: 'number', description: 'number of bound arrows built' },
65
+ diamondCount: { type: 'number', description: 'number of decision diamonds (should match decisionPoints)' },
66
+ hasStart: { type: 'boolean', description: 'true if a start circle with a label exists' },
67
+ hasEnd: { type: 'boolean', description: 'true if an end circle with a label exists' },
68
+ notes: { type: 'string' },
69
+ },
70
+ }
71
+
72
+ const JSON_SCHEMA = {
73
+ type: 'object',
74
+ required: ['valid'],
75
+ properties: {
76
+ valid: { type: 'boolean', description: 'true ONLY if `node -e JSON.parse(...)` on the saved file exits 0' },
77
+ error: { type: 'string', description: 'the parser error message + position when invalid' },
78
+ },
79
+ }
80
+
81
+ const CHECKLIST_SCHEMA = {
82
+ type: 'object',
83
+ required: ['pass', 'failedItems'],
84
+ properties: {
85
+ pass: { type: 'boolean', description: 'true if every applicable checklist item is satisfied' },
86
+ failedItems: { type: 'array', items: { type: 'string' }, description: 'checklist items that failed, verbatim' },
87
+ summary: { type: 'string' },
88
+ },
89
+ }
90
+
91
+ const SRC = '_byan/workflow/simple/excalidraw-diagrams/create-flowchart'
92
+ const SHARED = '_byan/workflow/simple/excalidraw-diagrams/_shared'
93
+
94
+ // === STEP 0 + 1 (CONTEXT) ===================================================
95
+ // Source step 0 (Contextual Analysis) + step 1 (Gather Requirements) are the
96
+ // elicitation gate; here we just restate the locked requirements that the skill
97
+ // already collected, so every downstream leaf shares one understanding.
98
+ phase('CONTEXT')
99
+ const context = await agent(
100
+ `You are the BYAN create-flowchart workflow. Restate the LOCKED flowchart requirements as a short brief.\n` +
101
+ `flowType=${JSON.stringify(flowType)} complexity=${JSON.stringify(complexity)} ` +
102
+ `decisionPoints=${JSON.stringify(decisionPoints)} outputFile=${JSON.stringify(outputFile)} ` +
103
+ `theme=${theme ? 'provided' : 'none (will default to Professional Blue palette)'}.\n` +
104
+ `Do NOT ask questions — those were answered at the human gate. Just confirm the understanding in 2-3 lines.`,
105
+ { label: 'context-restate', phase: 'CONTEXT' }
106
+ )
107
+
108
+ // === STEP 4 (PLAN) ==========================================================
109
+ phase('PLAN')
110
+ const plan = await agent(
111
+ `Mirror create-flowchart step 4 (Plan Flowchart Layout). Brief: ${context}\n` +
112
+ `Enumerate the concrete nodes: ONE start circle, the process rectangles, exactly the decision diamonds implied ` +
113
+ `by decisionPoints=${JSON.stringify(decisionPoints)}, and ONE end circle. List the directed edges (including the ` +
114
+ `yes/no branches off each diamond). Keep total elements under 50 (checklist: Composition). ` +
115
+ `Output the ordered node list and the edge list — this is the structure the user approved at the gate.`,
116
+ { label: 'plan-layout', phase: 'PLAN' }
117
+ )
118
+
119
+ // === STEP 5 (RESOURCES) =====================================================
120
+ phase('RESOURCES')
121
+ const resources = await agent(
122
+ `Mirror create-flowchart step 5 (Load Template and Resources). Read these real files:\n` +
123
+ `- template: ${SHARED}/excalidraw-templates.yaml -> extract the \`flowchart\` section\n` +
124
+ `- library: ${SHARED}/excalidraw-library.json\n` +
125
+ `- helpers: _byan/connaissance/excalidraw/excalidraw-helpers.md (element-creation guidelines)\n` +
126
+ `- json-validation guide: _byan/connaissance/excalidraw/validate-json-instructions.md\n` +
127
+ `Merge the theme colors (${theme ? JSON.stringify(theme) : 'Professional Blue default: fill #e3f2fd, accent #1976d2, decision #fff3e0, text #1e1e1e'}) ` +
128
+ `onto the template. Report which template fields the flowchart will use and the resolved color palette. ` +
129
+ `If a file is missing, say so explicitly — do not invent its contents.`,
130
+ { label: 'load-resources', phase: 'RESOURCES' }
131
+ )
132
+
133
+ // === STEP 6 (BUILD) =========================================================
134
+ phase('BUILD')
135
+ const elements = await agent(
136
+ `Mirror create-flowchart step 6 (Build Flowchart Elements), following the helpers guidelines from RESOURCES.\n` +
137
+ `Plan: ${plan}\nResolved resources/palette: ${resources}\n` +
138
+ `Build ONE section at a time, in this order: start circle -> process rectangles -> decision diamonds -> end circle -> arrows.\n` +
139
+ `Per shape-with-label: unique shape-id/text-id/group-id; shape and its text share the SAME groupIds; ` +
140
+ `text width = round((text.length * fontSize * 0.6) + 20) to nearest 10; text has containerId=shape-id, ` +
141
+ `textAlign=center, verticalAlign=middle; add boundElements on the shape referencing the text.\n` +
142
+ `Per arrow: startBinding/endBinding with gap=10 to source/target shape ids; straight for forward flow, ` +
143
+ `elbow (with intermediate points) for upward/backward/complex routing; update boundElements on BOTH endpoints.\n` +
144
+ `Alignment: snap every x,y to a 20px grid; same x for vertical flow; 60px spacing between shapes.\n` +
145
+ `Produce the in-memory Excalidraw elements array (do not write the file yet) and report the counts.`,
146
+ { label: 'build-elements', phase: 'BUILD', schema: ELEMENTS_SCHEMA }
147
+ )
148
+
149
+ // === STEP 7 (SAVE) ==========================================================
150
+ phase('SAVE')
151
+ const saved = await agent(
152
+ `Mirror create-flowchart step 7 (Optimize and Save). Built elements: ${JSON.stringify(elements)}.\n` +
153
+ `Strip any element with isDeleted:true and any unused/orphan element. Wrap the array in a valid ` +
154
+ `Excalidraw document ({ type:"excalidraw", version:2, source, elements, appState, files }). ` +
155
+ `Write the file to ${JSON.stringify(outputFile)} (creating parent dirs as needed). ` +
156
+ `Confirm the byte path written and the final element count (must stay under 50).`,
157
+ { label: 'optimize-save', phase: 'SAVE' }
158
+ )
159
+
160
+ // === STEP 8 (VALIDATE_JSON) — bounded fix/re-validate loop ==================
161
+ phase('VALIDATE_JSON')
162
+ let fixCycles = 0
163
+ let jsonRes = { valid: false, error: 'not yet validated' }
164
+ let jsonGuard = { done: false, abort: false, reason: 'init' }
165
+ while (true) {
166
+ fixCycles += 1
167
+ jsonRes = await agent(
168
+ `Mirror create-flowchart step 8 (Validate JSON Syntax), attempt ${fixCycles}. Save context: ${saved}\n` +
169
+ `CRITICAL: NEVER delete the file if validation fails — always FIX it.\n` +
170
+ `Run exactly: node -e "JSON.parse(require('fs').readFileSync('${outputFile}', 'utf8')); console.log('valid')"\n` +
171
+ (fixCycles > 1
172
+ ? `Previous error: ${jsonRes.error || 'unknown'}. Open the file at the error position, fix the missing comma/bracket/quote, save, then re-run the same command.\n`
173
+ : ``) +
174
+ `Set valid=true ONLY if that node command exits 0; otherwise valid=false and copy the parser error + position into \`error\`.`,
175
+ { label: `validate-json-${fixCycles}`, phase: 'VALIDATE_JSON', schema: JSON_SCHEMA }
176
+ )
177
+ jsonGuard = jsonFixGuard({ cycles: fixCycles, valid: Boolean(jsonRes && jsonRes.valid) })
178
+ log(`json-validate attempt ${fixCycles}: valid=${Boolean(jsonRes && jsonRes.valid)} -> ${jsonGuard.reason}`)
179
+ if (jsonGuard.done) break
180
+ }
181
+
182
+ // === STEP 9 (VALIDATE_CONTENT) ==============================================
183
+ phase('VALIDATE_CONTENT')
184
+ let checklist = { pass: false, failedItems: ['skipped — JSON never validated'], summary: 'skipped' }
185
+ if (jsonRes.valid) {
186
+ checklist = await agent(
187
+ `Mirror create-flowchart step 9 (Validate Content). Validate the saved file ${JSON.stringify(outputFile)} ` +
188
+ `against the checklist at ${SRC}/checklist.md (Element Structure, Layout/Alignment, Connections, ` +
189
+ `Theme/Styling, Composition, Output Quality, Functional Requirements). ` +
190
+ `Read the checklist file, evaluate EACH applicable item against the actual file content, and report pass/fail per item.`,
191
+ { label: 'validate-content', phase: 'VALIDATE_CONTENT', schema: CHECKLIST_SCHEMA }
192
+ )
193
+ }
194
+
195
+ // === VERDICT — DATA ONLY ====================================================
196
+ // The orchestrating skill presents this at the human gate (step 8 "Open to
197
+ // view?" / step 3 theme-approval are human decisions) and records FD/strict
198
+ // state via MCP. The script writes only the .excalidraw artifact, never state.
199
+ phase('VERDICT')
200
+ const jsonValid = Boolean(jsonRes && jsonRes.valid)
201
+ const contentPass = Boolean(checklist && checklist.pass)
202
+ return {
203
+ workflow: 'create-excalidraw-flowchart',
204
+ outputFile,
205
+ requirements: { flowType, complexity, decisionPoints, themedFromArgs: Boolean(theme) },
206
+ elements: {
207
+ shapeCount: (elements && elements.shapeCount) || 0,
208
+ arrowCount: (elements && elements.arrowCount) || 0,
209
+ diamondCount: (elements && elements.diamondCount) || 0,
210
+ hasStart: Boolean(elements && elements.hasStart),
211
+ hasEnd: Boolean(elements && elements.hasEnd),
212
+ },
213
+ jsonValid,
214
+ jsonFixCycles: fixCycles,
215
+ maxFixCycles: MAX_FIX_CYCLES,
216
+ jsonAbort: jsonGuard.abort,
217
+ contentValidationPass: contentPass,
218
+ failedChecklistItems: (checklist && checklist.failedItems) || [],
219
+ status: jsonValid && contentPass ? 'ready-to-open' : jsonGuard.abort ? 'aborted-invalid-json' : 'needs-attention',
220
+ summary:
221
+ jsonValid && contentPass
222
+ ? `Flowchart written to ${outputFile}; JSON valid and checklist passed.`
223
+ : `Flowchart at ${outputFile} needs attention: jsonValid=${jsonValid}, contentPass=${contentPass}.`,
224
+ needsHumanGate: true,
225
+ }