@dewtech/dare-cli 2.15.0 → 2.16.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.
@@ -1 +1 @@
1
- {"version":3,"file":"dag.d.ts","sourceRoot":"","sources":["../../src/commands/dag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,OAAO,EAEL,KAAK,GAAG,EAGT,MAAM,0BAA0B,CAAC;AAMlC;;;;GAIG;AACH,eAAO,MAAM,UAAU,SAEtB,CAAC;AA2EF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CA6CjD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAyC7C"}
1
+ {"version":3,"file":"dag.d.ts","sourceRoot":"","sources":["../../src/commands/dag.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,OAAO,EAEL,KAAK,GAAG,EAGT,MAAM,0BAA0B,CAAC;AAUlC;;;;GAIG;AACH,eAAO,MAAM,UAAU,SAEtB,CAAC;AA6FF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CA6CjD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAyC7C"}
@@ -5,6 +5,7 @@ import path from 'path';
5
5
  import { convertYamlToDag } from '../utils/dag-converter.js';
6
6
  import { computeRanks, } from '../dag-runner/run_dag.js';
7
7
  import { DEFAULT_STATE_PATH, loadAndApplyState, } from '../dag-runner/state-store.js';
8
+ import { renderDagExcalidraw, serializeExcalidraw, } from '../utils/excalidraw-renderer.js';
8
9
  /**
9
10
  * `dare dag` — inspect and visualize the static task DAG declared in
10
11
  * `dare-dag.yaml`. Distinct from `dare graph`, which inspects the populated
@@ -13,10 +14,10 @@ import { DEFAULT_STATE_PATH, loadAndApplyState, } from '../dag-runner/state-stor
13
14
  export const dagCommand = new Command('dag').description('Inspect and visualize the static task DAG (dare-dag.yaml)');
14
15
  dagCommand
15
16
  .command('viz')
16
- .description('Render dare-dag.yaml as a Mermaid or DOT diagram with status colors')
17
+ .description('Render dare-dag.yaml as a Mermaid, DOT, or Excalidraw diagram with status colors')
17
18
  .option('--dag <file>', 'Path to dare-dag.yaml', 'DARE/dare-dag.yaml')
18
- .option('-f, --format <fmt>', 'Output format: mermaid | dot', 'mermaid')
19
- .option('-o, --output <file>', 'Write to file (defaults to stdout)')
19
+ .option('-f, --format <fmt>', 'Output format: mermaid | dot | excalidraw', 'mermaid')
20
+ .option('-o, --output <file>', 'Write to file (defaults to stdout or DARE/dag-graph.{fmt} for excalidraw)')
20
21
  .action(async (options) => {
21
22
  const cwd = process.cwd();
22
23
  const dagPath = path.resolve(cwd, options.dag);
@@ -26,18 +27,35 @@ dagCommand
26
27
  process.exit(1);
27
28
  }
28
29
  const format = options.format.toLowerCase();
29
- if (format !== 'mermaid' && format !== 'dot') {
30
- console.error(chalk.red(`Unsupported format "${options.format}". Use: mermaid | dot.`));
30
+ if (format !== 'mermaid' && format !== 'dot' && format !== 'excalidraw') {
31
+ console.error(chalk.red(`Unsupported format "${options.format}". Use: mermaid | dot | excalidraw.`));
31
32
  process.exit(1);
32
33
  }
33
34
  const dag = convertYamlToDag(await fs.readFile(dagPath, 'utf-8'));
34
35
  await loadAndApplyState(dag, path.resolve(cwd, DEFAULT_STATE_PATH));
35
- const rendered = format === 'mermaid' ? renderDagMermaid(dag) : renderDagDot(dag);
36
- if (options.output) {
37
- const out = path.resolve(cwd, options.output);
36
+ let rendered;
37
+ let outputPath = options.output;
38
+ if (format === 'excalidraw') {
39
+ const excalidrawData = renderDagExcalidraw(dag);
40
+ rendered = serializeExcalidraw(excalidrawData);
41
+ // Default output for Excalidraw
42
+ if (!outputPath) {
43
+ outputPath = 'DARE/dag-graph.excalidraw';
44
+ }
45
+ }
46
+ else {
47
+ rendered =
48
+ format === 'mermaid' ? renderDagMermaid(dag) : renderDagDot(dag);
49
+ }
50
+ if (outputPath) {
51
+ const out = path.resolve(cwd, outputPath);
38
52
  await fs.ensureDir(path.dirname(out));
39
53
  await fs.writeFile(out, rendered);
40
- console.log(chalk.green(`✅ Wrote ${dag.tasks.length} task(s) and ${countEdges(dag)} dependency arrow(s) to ${options.output}`));
54
+ const formatLabel = format === 'excalidraw' ? 'Excalidraw diagram' : `${format} diagram`;
55
+ console.log(chalk.green(`✅ Generated ${formatLabel} with ${dag.tasks.length} task(s) and ${countEdges(dag)} dependency arrow(s) → ${outputPath}`));
56
+ if (format === 'excalidraw') {
57
+ console.log(chalk.cyan(' Open in https://excalidraw.com or via File → Open'));
58
+ }
41
59
  }
42
60
  else {
43
61
  console.log(rendered);
@@ -1 +1 @@
1
- {"version":3,"file":"dag.js","sourceRoot":"","sources":["../../src/commands/dag.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dag.js","sourceRoot":"","sources":["../../src/commands/dag.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Excalidraw Renderer for DARE DAG Visualization
3
+ *
4
+ * Converts a DARE DAG (task graph) to an Excalidraw JSON file.
5
+ * - Tasks are rendered as colored rectangles based on complexity
6
+ * - Dependencies are rendered as arrows
7
+ * - Tasks are grouped by rank in swim lanes
8
+ *
9
+ * Design tokens: /docs/DESIGN-TOKENS-EXCALIDRAW.md
10
+ * License: AGPL v3 (part of DARE CLI)
11
+ */
12
+ import { Dag } from '../dag-runner/run_dag.js';
13
+ /**
14
+ * Excalidraw element types
15
+ */
16
+ interface ExcalidrawElement {
17
+ id: string;
18
+ type: string;
19
+ x: number;
20
+ y: number;
21
+ width?: number;
22
+ height?: number;
23
+ angle?: number;
24
+ strokeColor?: string;
25
+ backgroundColor?: string;
26
+ fillStyle?: string;
27
+ strokeWidth?: number;
28
+ strokeStyle?: string;
29
+ roughness?: number;
30
+ opacity?: number;
31
+ roundness?: {
32
+ type: number;
33
+ value: number;
34
+ };
35
+ text?: string;
36
+ fontSize?: number;
37
+ fontFamily?: number;
38
+ textAlign?: string;
39
+ verticalAlign?: string;
40
+ startBinding?: {
41
+ elementId: string;
42
+ };
43
+ endBinding?: {
44
+ elementId: string;
45
+ };
46
+ startArrowType?: string;
47
+ endArrowType?: string;
48
+ boundElements?: Array<{
49
+ id: string;
50
+ type: string;
51
+ }>;
52
+ updated?: number;
53
+ link?: null;
54
+ locked?: boolean;
55
+ seed?: number;
56
+ versionNonce?: number;
57
+ }
58
+ interface ExcalidrawData {
59
+ type: string;
60
+ version: number;
61
+ source: string;
62
+ elements: ExcalidrawElement[];
63
+ appState: {
64
+ gridMode: string;
65
+ gridSize: number;
66
+ viewBackgroundColor?: string;
67
+ };
68
+ files: Record<string, unknown>;
69
+ }
70
+ /**
71
+ * Render DAG to Excalidraw JSON
72
+ */
73
+ export declare function renderDagExcalidraw(dag: Dag): ExcalidrawData;
74
+ /**
75
+ * Serialize Excalidraw data to JSON string
76
+ */
77
+ export declare function serializeExcalidraw(data: ExcalidrawData): string;
78
+ export {};
79
+ //# sourceMappingURL=excalidraw-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"excalidraw-renderer.d.ts","sourceRoot":"","sources":["../../src/utils/excalidraw-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,GAAG,EAAqC,MAAM,0BAA0B,CAAC;AAElF;;GAEG;AACH,UAAU,iBAAiB;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,UAAU,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,QAAQ,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;KAC9B,CAAC;IACF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAyID;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,GAAG,GAAG,cAAc,CAyD5D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAEhE"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Excalidraw Renderer for DARE DAG Visualization
3
+ *
4
+ * Converts a DARE DAG (task graph) to an Excalidraw JSON file.
5
+ * - Tasks are rendered as colored rectangles based on complexity
6
+ * - Dependencies are rendered as arrows
7
+ * - Tasks are grouped by rank in swim lanes
8
+ *
9
+ * Design tokens: /docs/DESIGN-TOKENS-EXCALIDRAW.md
10
+ * License: AGPL v3 (part of DARE CLI)
11
+ */
12
+ import { computeRanks } from '../dag-runner/run_dag.js';
13
+ /**
14
+ * Color palette based on DARE Design Tokens
15
+ */
16
+ const COLOR_BY_COMPLEXITY = {
17
+ LOW: {
18
+ bg: '#e3f2fd', // Azure blue
19
+ stroke: '#1976d2', // Dark blue
20
+ },
21
+ MED: {
22
+ bg: '#fff3e0', // Orange
23
+ stroke: '#e65100', // Dark orange
24
+ },
25
+ HIGH: {
26
+ bg: '#fce4ec', // Pink/Magenta
27
+ stroke: '#c2185b', // Dark pink
28
+ },
29
+ };
30
+ const COLOR_BY_STATUS = {
31
+ PENDING: {
32
+ bg: '#f5f5f5', // Light gray
33
+ stroke: '#999999', // Medium gray
34
+ },
35
+ RUNNING: {
36
+ bg: '#e3f2fd', // Azure blue
37
+ stroke: '#1976d2', // Dark blue
38
+ dashed: true,
39
+ },
40
+ DONE: {
41
+ bg: '#e8f5e9', // Light green
42
+ stroke: '#388e3c', // Dark green
43
+ },
44
+ FAILED: {
45
+ bg: '#ffebee', // Light red
46
+ stroke: '#d32f2f', // Dark red
47
+ },
48
+ SKIPPED: {
49
+ bg: '#e5e7eb', // Gray
50
+ stroke: '#6b7280', // Dark gray
51
+ },
52
+ };
53
+ /**
54
+ * Generate unique ID for Excalidraw elements
55
+ */
56
+ function generateId() {
57
+ return Math.random().toString(36).substr(2, 9);
58
+ }
59
+ /**
60
+ * Get status color, preferring status over complexity
61
+ */
62
+ function getTaskColors(task) {
63
+ const status = task.status ?? 'PENDING';
64
+ // Status takes precedence, but if PENDING, use complexity for better visualization
65
+ if (status === 'PENDING' && task.complexity) {
66
+ return COLOR_BY_COMPLEXITY[task.complexity] || COLOR_BY_COMPLEXITY.MED;
67
+ }
68
+ return COLOR_BY_STATUS[status] || COLOR_BY_STATUS.PENDING;
69
+ }
70
+ /**
71
+ * Create rectangle element for a task
72
+ */
73
+ function createTaskElement(task, x, y) {
74
+ const colors = getTaskColors(task);
75
+ const complexity = task.complexity || 'MED';
76
+ const text = `${task.id}\n${task.title}\n[${complexity}]`;
77
+ return {
78
+ id: task.id,
79
+ type: 'rectangle',
80
+ x,
81
+ y,
82
+ width: 120,
83
+ height: 60,
84
+ angle: 0,
85
+ strokeColor: colors.stroke,
86
+ backgroundColor: colors.bg,
87
+ fillStyle: 'hachure',
88
+ strokeWidth: 2,
89
+ strokeStyle: colors.dashed ? 'dashed' : 'solid',
90
+ roughness: 0,
91
+ opacity: 100,
92
+ roundness: { type: 2, value: 6 },
93
+ text,
94
+ fontSize: 12,
95
+ fontFamily: 1, // Virgil (default Excalidraw font)
96
+ textAlign: 'center',
97
+ verticalAlign: 'middle',
98
+ boundElements: [],
99
+ updated: Date.now(),
100
+ link: null,
101
+ locked: false,
102
+ seed: Math.floor(Math.random() * 2147483647),
103
+ versionNonce: Math.floor(Math.random() * 2147483647),
104
+ };
105
+ }
106
+ /**
107
+ * Create arrow element for a dependency
108
+ */
109
+ function createArrowElement(fromTaskId, toTaskId) {
110
+ return {
111
+ id: generateId(),
112
+ type: 'arrow',
113
+ x: 0, // Will be computed from start/end binding
114
+ y: 0,
115
+ startBinding: { elementId: fromTaskId },
116
+ endBinding: { elementId: toTaskId },
117
+ startArrowType: 'dot',
118
+ endArrowType: 'arrow',
119
+ strokeColor: '#999999',
120
+ strokeWidth: 2,
121
+ strokeStyle: 'solid',
122
+ roughness: 0,
123
+ opacity: 100,
124
+ updated: Date.now(),
125
+ link: null,
126
+ locked: false,
127
+ seed: Math.floor(Math.random() * 2147483647),
128
+ versionNonce: Math.floor(Math.random() * 2147483647),
129
+ };
130
+ }
131
+ /**
132
+ * Render DAG to Excalidraw JSON
133
+ */
134
+ export function renderDagExcalidraw(dag) {
135
+ const elements = [];
136
+ const ranks = computeRanks(dag.tasks);
137
+ // Group tasks by rank
138
+ const byRank = new Map();
139
+ for (const task of dag.tasks) {
140
+ const r = ranks.get(task.id) ?? 1;
141
+ if (!byRank.has(r))
142
+ byRank.set(r, []);
143
+ byRank.get(r).push(task);
144
+ }
145
+ // Position elements
146
+ const taskPositions = new Map();
147
+ const sortedRanks = [...byRank.keys()].sort((a, b) => a - b);
148
+ for (const rank of sortedRanks) {
149
+ const tasksInRank = byRank.get(rank);
150
+ for (let i = 0; i < tasksInRank.length; i++) {
151
+ const task = tasksInRank[i];
152
+ // Position: X based on task index in rank, Y based on rank
153
+ const x = 20 + i * 140;
154
+ const y = 20 + rank * 160;
155
+ taskPositions.set(task.id, { x, y });
156
+ // Create rectangle for this task
157
+ const taskElement = createTaskElement(task, x, y);
158
+ elements.push(taskElement);
159
+ }
160
+ }
161
+ // Create arrows for dependencies
162
+ for (const task of dag.tasks) {
163
+ for (const depId of task.depends_on) {
164
+ const arrow = createArrowElement(depId, task.id);
165
+ elements.push(arrow);
166
+ }
167
+ }
168
+ const data = {
169
+ type: 'excalidraw',
170
+ version: 2,
171
+ source: 'dare-dag-viz',
172
+ elements,
173
+ appState: {
174
+ gridMode: 'grid',
175
+ gridSize: 20,
176
+ viewBackgroundColor: '#ffffff',
177
+ },
178
+ files: {},
179
+ };
180
+ return data;
181
+ }
182
+ /**
183
+ * Serialize Excalidraw data to JSON string
184
+ */
185
+ export function serializeExcalidraw(data) {
186
+ return JSON.stringify(data, null, 2);
187
+ }
188
+ //# sourceMappingURL=excalidraw-renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"excalidraw-renderer.js","sourceRoot":"","sources":["../../src/utils/excalidraw-renderer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=excalidraw-renderer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"excalidraw-renderer.test.d.ts","sourceRoot":"","sources":["../../src/utils/excalidraw-renderer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,135 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { renderDagExcalidraw, serializeExcalidraw } from './excalidraw-renderer.js';
3
+ describe('ExcalidrawRenderer', () => {
4
+ const mockDag = {
5
+ title: 'Test DAG',
6
+ version: '1.0.0',
7
+ models: {},
8
+ tasks: [
9
+ {
10
+ id: 'task-001',
11
+ title: 'Setup',
12
+ complexity: 'LOW',
13
+ depends_on: [],
14
+ status: 'DONE',
15
+ subtask_prompt: 'Setup task',
16
+ },
17
+ {
18
+ id: 'task-002',
19
+ title: 'Build',
20
+ complexity: 'MED',
21
+ depends_on: ['task-001'],
22
+ status: 'RUNNING',
23
+ subtask_prompt: 'Build task',
24
+ },
25
+ {
26
+ id: 'task-003',
27
+ title: 'Test',
28
+ complexity: 'HIGH',
29
+ depends_on: ['task-002'],
30
+ status: 'PENDING',
31
+ subtask_prompt: 'Test task',
32
+ },
33
+ ],
34
+ };
35
+ it('renders DAG to Excalidraw JSON', () => {
36
+ const data = renderDagExcalidraw(mockDag);
37
+ expect(data.type).toBe('excalidraw');
38
+ expect(data.version).toBe(2);
39
+ expect(data.source).toBe('dare-dag-viz');
40
+ expect(data.elements).toHaveLength(5); // 3 tasks + 2 arrows
41
+ });
42
+ it('creates rectangle elements for tasks', () => {
43
+ const data = renderDagExcalidraw(mockDag);
44
+ const taskElements = data.elements.filter((e) => e.type === 'rectangle');
45
+ expect(taskElements).toHaveLength(3);
46
+ expect(taskElements[0].id).toBe('task-001');
47
+ expect(taskElements[0].width).toBe(120);
48
+ expect(taskElements[0].height).toBe(60);
49
+ });
50
+ it('applies correct colors by complexity when PENDING', () => {
51
+ const data = renderDagExcalidraw(mockDag);
52
+ const task003 = data.elements.find((e) => e.id === 'task-003');
53
+ // PENDING + HIGH complexity should use HIGH complexity colors
54
+ expect(task003?.backgroundColor).toBe('#fce4ec'); // HIGH pink
55
+ expect(task003?.strokeColor).toBe('#c2185b');
56
+ });
57
+ it('applies correct colors by status when not PENDING', () => {
58
+ const data = renderDagExcalidraw(mockDag);
59
+ const task001 = data.elements.find((e) => e.id === 'task-001');
60
+ expect(task001?.backgroundColor).toBe('#e8f5e9'); // DONE green
61
+ expect(task001?.strokeColor).toBe('#388e3c');
62
+ const task002 = data.elements.find((e) => e.id === 'task-002');
63
+ expect(task002?.backgroundColor).toBe('#e3f2fd'); // RUNNING blue
64
+ expect(task002?.strokeColor).toBe('#1976d2');
65
+ expect(task002?.strokeStyle).toBe('dashed'); // RUNNING is dashed
66
+ });
67
+ it('creates arrow elements for dependencies', () => {
68
+ const data = renderDagExcalidraw(mockDag);
69
+ const arrows = data.elements.filter((e) => e.type === 'arrow');
70
+ expect(arrows).toHaveLength(2);
71
+ expect(arrows[0].startBinding?.elementId).toBe('task-001');
72
+ expect(arrows[0].endBinding?.elementId).toBe('task-002');
73
+ expect(arrows[1].startBinding?.elementId).toBe('task-002');
74
+ expect(arrows[1].endBinding?.elementId).toBe('task-003');
75
+ });
76
+ it('positions tasks correctly by rank', () => {
77
+ const data = renderDagExcalidraw(mockDag);
78
+ const task001 = data.elements.find((e) => e.id === 'task-001');
79
+ const task002 = data.elements.find((e) => e.id === 'task-002');
80
+ const task003 = data.elements.find((e) => e.id === 'task-003');
81
+ // Rank 0: y = 20 + 0 * 160 = 20
82
+ expect(task001?.y).toBe(20);
83
+ // Rank 1: y = 20 + 1 * 160 = 180
84
+ expect(task002?.y).toBe(180);
85
+ // Rank 2: y = 20 + 2 * 160 = 340
86
+ expect(task003?.y).toBe(340);
87
+ });
88
+ it('serializes to valid JSON', () => {
89
+ const data = renderDagExcalidraw(mockDag);
90
+ const json = serializeExcalidraw(data);
91
+ expect(() => JSON.parse(json)).not.toThrow();
92
+ const parsed = JSON.parse(json);
93
+ expect(parsed.type).toBe('excalidraw');
94
+ expect(parsed.elements).toHaveLength(5);
95
+ });
96
+ it('includes task title and complexity in text', () => {
97
+ const data = renderDagExcalidraw(mockDag);
98
+ const task001 = data.elements.find((e) => e.id === 'task-001');
99
+ expect(task001?.text).toContain('task-001');
100
+ expect(task001?.text).toContain('Setup');
101
+ expect(task001?.text).toContain('[LOW]');
102
+ });
103
+ it('handles parallel tasks (same rank)', () => {
104
+ const parallelDag = {
105
+ title: 'Parallel DAG',
106
+ version: '1.0.0',
107
+ models: {},
108
+ tasks: [
109
+ {
110
+ id: 'task-a',
111
+ title: 'Task A',
112
+ complexity: 'LOW',
113
+ depends_on: [],
114
+ status: 'PENDING',
115
+ subtask_prompt: '',
116
+ },
117
+ {
118
+ id: 'task-b',
119
+ title: 'Task B',
120
+ complexity: 'LOW',
121
+ depends_on: [],
122
+ status: 'PENDING',
123
+ subtask_prompt: '',
124
+ },
125
+ ],
126
+ };
127
+ const data = renderDagExcalidraw(parallelDag);
128
+ const taskA = data.elements.find((e) => e.id === 'task-a');
129
+ const taskB = data.elements.find((e) => e.id === 'task-b');
130
+ // Both should be at same Y (rank 1), different X
131
+ expect(taskA?.y).toBe(taskB?.y);
132
+ expect(taskA?.x).not.toBe(taskB?.x);
133
+ });
134
+ });
135
+ //# sourceMappingURL=excalidraw-renderer.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"excalidraw-renderer.test.js","sourceRoot":"","sources":["../../src/utils/excalidraw-renderer.test.ts"],"names":[],"mappings":"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"}
@@ -1012,7 +1012,9 @@ function dockerizePath(p) {
1012
1012
  return p.replace(/\\/g, '/');
1013
1013
  }
1014
1014
  function sanitizeCrateName(name) {
1015
- return name.toLowerCase().replace(/[^a-z0-9_]+/g, '_').replace(/^_+|_+$/g, '') || 'app';
1015
+ // Cargo package names use hyphens (idiomatic). Rust identifiers derived from
1016
+ // them replace hyphens with underscores — see crateIdent usages in this file.
1017
+ return name.toLowerCase().replace(/[^a-z0-9-]+/g, '-').replace(/^-+|-+$/g, '') || 'app';
1016
1018
  }
1017
1019
  function sanitizeGoModule(name) {
1018
1020
  return name.toLowerCase().replace(/[^a-z0-9-]+/g, '-').replace(/^-+|-+$/g, '') || 'app';