@dewtech/dare-cli 2.1.0 → 2.3.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 (95) hide show
  1. package/README.md +53 -7
  2. package/dist/__tests__/dag-runner/adapters.test.d.ts +2 -0
  3. package/dist/__tests__/dag-runner/adapters.test.d.ts.map +1 -0
  4. package/dist/__tests__/dag-runner/adapters.test.js +134 -0
  5. package/dist/__tests__/dag-runner/adapters.test.js.map +1 -0
  6. package/dist/__tests__/dag-runner/graph-ingest.test.d.ts +2 -0
  7. package/dist/__tests__/dag-runner/graph-ingest.test.d.ts.map +1 -0
  8. package/dist/__tests__/dag-runner/graph-ingest.test.js +105 -0
  9. package/dist/__tests__/dag-runner/graph-ingest.test.js.map +1 -0
  10. package/dist/__tests__/dag-runner/orchestrator.test.d.ts +2 -0
  11. package/dist/__tests__/dag-runner/orchestrator.test.d.ts.map +1 -0
  12. package/dist/__tests__/dag-runner/orchestrator.test.js +107 -0
  13. package/dist/__tests__/dag-runner/orchestrator.test.js.map +1 -0
  14. package/dist/__tests__/dag-runner/utils.test.d.ts +2 -0
  15. package/dist/__tests__/dag-runner/utils.test.d.ts.map +1 -0
  16. package/dist/__tests__/dag-runner/utils.test.js +47 -0
  17. package/dist/__tests__/dag-runner/utils.test.js.map +1 -0
  18. package/dist/__tests__/graphrag/json-graph.test.d.ts +2 -0
  19. package/dist/__tests__/graphrag/json-graph.test.d.ts.map +1 -0
  20. package/dist/__tests__/graphrag/json-graph.test.js +57 -0
  21. package/dist/__tests__/graphrag/json-graph.test.js.map +1 -0
  22. package/dist/bin/dare.js +2 -0
  23. package/dist/bin/dare.js.map +1 -1
  24. package/dist/commands/execute.d.ts.map +1 -1
  25. package/dist/commands/execute.js +172 -45
  26. package/dist/commands/execute.js.map +1 -1
  27. package/dist/commands/graph.d.ts +9 -0
  28. package/dist/commands/graph.d.ts.map +1 -0
  29. package/dist/commands/graph.js +155 -0
  30. package/dist/commands/graph.js.map +1 -0
  31. package/dist/dag-runner/adapters/antigravity.d.ts +6 -0
  32. package/dist/dag-runner/adapters/antigravity.d.ts.map +1 -0
  33. package/dist/dag-runner/adapters/antigravity.js +54 -0
  34. package/dist/dag-runner/adapters/antigravity.js.map +1 -0
  35. package/dist/dag-runner/adapters/claude.d.ts +6 -0
  36. package/dist/dag-runner/adapters/claude.d.ts.map +1 -0
  37. package/dist/dag-runner/adapters/claude.js +48 -0
  38. package/dist/dag-runner/adapters/claude.js.map +1 -0
  39. package/dist/dag-runner/adapters/cursor.d.ts +6 -0
  40. package/dist/dag-runner/adapters/cursor.d.ts.map +1 -0
  41. package/dist/dag-runner/adapters/cursor.js +58 -0
  42. package/dist/dag-runner/adapters/cursor.js.map +1 -0
  43. package/dist/dag-runner/adapters/index.d.ts +46 -0
  44. package/dist/dag-runner/adapters/index.d.ts.map +1 -0
  45. package/dist/dag-runner/adapters/index.js +55 -0
  46. package/dist/dag-runner/adapters/index.js.map +1 -0
  47. package/dist/dag-runner/graph-ingest.d.ts +17 -0
  48. package/dist/dag-runner/graph-ingest.d.ts.map +1 -0
  49. package/dist/dag-runner/graph-ingest.js +149 -0
  50. package/dist/dag-runner/graph-ingest.js.map +1 -0
  51. package/dist/dag-runner/run_dag.d.ts +51 -24
  52. package/dist/dag-runner/run_dag.d.ts.map +1 -1
  53. package/dist/dag-runner/run_dag.js +163 -109
  54. package/dist/dag-runner/run_dag.js.map +1 -1
  55. package/dist/dag-runner/state-store.d.ts +13 -0
  56. package/dist/dag-runner/state-store.d.ts.map +1 -0
  57. package/dist/dag-runner/state-store.js +69 -0
  58. package/dist/dag-runner/state-store.js.map +1 -0
  59. package/dist/dag-runner/utils/cap-output.d.ts +14 -0
  60. package/dist/dag-runner/utils/cap-output.d.ts.map +1 -0
  61. package/dist/dag-runner/utils/cap-output.js +25 -0
  62. package/dist/dag-runner/utils/cap-output.js.map +1 -0
  63. package/dist/dag-runner/utils/stitch-context.d.ts +24 -0
  64. package/dist/dag-runner/utils/stitch-context.d.ts.map +1 -0
  65. package/dist/dag-runner/utils/stitch-context.js +36 -0
  66. package/dist/dag-runner/utils/stitch-context.js.map +1 -0
  67. package/dist/dag-runner/utils/timeout.d.ts +27 -0
  68. package/dist/dag-runner/utils/timeout.d.ts.map +1 -0
  69. package/dist/dag-runner/utils/timeout.js +55 -0
  70. package/dist/dag-runner/utils/timeout.js.map +1 -0
  71. package/dist/graphrag/factory.d.ts +25 -0
  72. package/dist/graphrag/factory.d.ts.map +1 -0
  73. package/dist/graphrag/factory.js +66 -0
  74. package/dist/graphrag/factory.js.map +1 -0
  75. package/dist/graphrag/index.d.ts +4 -0
  76. package/dist/graphrag/index.d.ts.map +1 -1
  77. package/dist/graphrag/index.js +2 -0
  78. package/dist/graphrag/index.js.map +1 -1
  79. package/dist/graphrag/json-graph.d.ts +28 -0
  80. package/dist/graphrag/json-graph.d.ts.map +1 -0
  81. package/dist/graphrag/json-graph.js +168 -0
  82. package/dist/graphrag/json-graph.js.map +1 -0
  83. package/dist/graphrag/knowledge-graph.d.ts +33 -0
  84. package/dist/graphrag/knowledge-graph.d.ts.map +1 -0
  85. package/dist/graphrag/knowledge-graph.js +2 -0
  86. package/dist/graphrag/knowledge-graph.js.map +1 -0
  87. package/dist/index.d.ts +13 -6
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +12 -5
  90. package/dist/index.js.map +1 -1
  91. package/package.json +1 -1
  92. package/templates/ide/antigravity/.agents/skills/dare-dag-runner/SKILL.md +99 -96
  93. package/templates/ide/claude/.claude/commands/dare-dag-run.md +68 -69
  94. package/templates/ide/cursor/.cursor/commands/run-dag.md +67 -44
  95. package/templates/ide/cursor/.cursor/rules/skill-dag-runner.mdc +97 -87
package/README.md CHANGED
@@ -88,17 +88,63 @@ dare blueprint
88
88
 
89
89
  ### `dare execute`
90
90
 
91
- Execute tasks from the DAG with optional parallel execution.
91
+ Orchestrate DAG execution. **The IDE is the executor** (Cursor / Antigravity
92
+ / Claude Code) — `dare execute` only coordinates state, composes prompts
93
+ with parent context, updates the live canvas at `DARE/.canvas.md`, and
94
+ ingests finished tasks into the knowledge graph.
95
+
96
+ > **No API keys, no extra token costs.** You use the plan of the IDE you're
97
+ > already logged into.
98
+
99
+ ```bash
100
+ # Print next executable tasks (with composed prompts)
101
+ dare execute --next
102
+
103
+ # Mark a task DONE after the agent finishes it
104
+ dare execute --complete task-001 --output "Created src/auth.ts and tests/auth.test.ts; all tests green."
105
+
106
+ # Mark a task FAILED — descendants are cascade-skipped automatically
107
+ dare execute --fail task-002 --reason "Schema migration conflict in users table"
108
+
109
+ # Reset a task back to PENDING (for retry)
110
+ dare execute --reset task-002
111
+
112
+ # Show snapshot of canvas + summary (default action)
113
+ dare execute --status
114
+ ```
115
+
116
+ #### Typical flow inside the IDE agent
117
+
118
+ ```bash
119
+ dare execute --next # → tasks ready in current rank
120
+ # (agent executes each task: code, build, test, lint)
121
+ dare execute --complete task-001 --output "…"
122
+ dare execute --complete task-002 --output "…"
123
+ dare execute --next # → next rank
124
+ # (repeat until "✅ All tasks resolved")
125
+ ```
126
+
127
+ The skills shipped by `dare init` (`.cursor/rules/skill-dag-runner.mdc`,
128
+ `.agents/skills/dare-dag-runner/SKILL.md`, `.claude/commands/dare-dag-run.md`)
129
+ guide the IDE agent through this loop.
130
+
131
+ ### `dare graph`
132
+
133
+ Inspect the project's knowledge graph. The graph is populated automatically
134
+ by `dare execute --complete/--fail` (task nodes, file nodes, `depends_on` and
135
+ `implements` edges). Backend is whatever `dare-graph.yml` declares
136
+ (`sqlite` default, `json` available, `neo4j` planned).
92
137
 
93
138
  ```bash
94
- # Execute all tasks in parallel (75% faster)
95
- dare execute --parallel --runner cursor
139
+ dare graph stats # totals + breakdown by type
140
+ dare graph query auth # search nodes by label/description
141
+ dare graph query auth --limit 20
96
142
 
97
- # Execute a specific task
98
- dare execute task-001
143
+ dare graph viz # Mermaid to stdout
144
+ dare graph viz -f dot # DOT for Graphviz
145
+ dare graph viz -o docs/graph.mmd # write to file
99
146
 
100
- # Sequential execution
101
- dare execute
147
+ dare graph ingest # re-sync from dare-dag.yaml + state
102
148
  ```
103
149
 
104
150
  ---
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=adapters.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapters.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/dag-runner/adapters.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,134 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { getAdapter, MissingApiKeyError, pickModel, } from '../../dag-runner/adapters/index.js';
3
+ const sampleModels = { HIGH: 'big', MED: 'mid', LOW: 'small' };
4
+ // ─── Anthropic SDK mock ──────────────────────────────────────────────────────
5
+ vi.mock('@anthropic-ai/sdk', () => {
6
+ var _a;
7
+ const create = vi.fn(async () => ({
8
+ content: [{ type: 'text', text: 'mocked claude response' }],
9
+ usage: { input_tokens: 10, output_tokens: 20 },
10
+ }));
11
+ // Default export is the client class.
12
+ return {
13
+ default: (_a = class MockAnthropic {
14
+ constructor() {
15
+ this.messages = { create };
16
+ }
17
+ },
18
+ _a.__spy = create,
19
+ _a),
20
+ };
21
+ });
22
+ // ─── Cursor SDK mock ─────────────────────────────────────────────────────────
23
+ vi.mock('@cursor/sdk', () => ({
24
+ Agent: {
25
+ create: vi.fn(async () => ({
26
+ send: vi.fn(async () => ({
27
+ cancel: vi.fn(async () => undefined),
28
+ wait: vi.fn(async () => ({ result: 'mocked cursor response' })),
29
+ })),
30
+ close: vi.fn(async () => undefined),
31
+ })),
32
+ },
33
+ }));
34
+ // ─── Google Generative AI mock ───────────────────────────────────────────────
35
+ vi.mock('@google/generative-ai', () => ({
36
+ GoogleGenerativeAI: class {
37
+ getGenerativeModel() {
38
+ return {
39
+ generateContent: async () => ({
40
+ response: {
41
+ text: () => 'mocked antigravity response',
42
+ usageMetadata: { promptTokenCount: 5, candidatesTokenCount: 7 },
43
+ },
44
+ }),
45
+ };
46
+ }
47
+ },
48
+ }));
49
+ describe('pickModel', () => {
50
+ it('returns the model id for the given complexity', () => {
51
+ expect(pickModel(sampleModels, 'HIGH')).toBe('big');
52
+ expect(pickModel(sampleModels, 'MED')).toBe('mid');
53
+ expect(pickModel(sampleModels, 'LOW')).toBe('small');
54
+ });
55
+ it('throws when models block is missing', () => {
56
+ expect(() => pickModel(undefined, 'HIGH')).toThrow();
57
+ });
58
+ });
59
+ describe('Adapters — happy path with mocked SDKs', () => {
60
+ beforeEach(() => {
61
+ process.env.ANTHROPIC_API_KEY = 'test-key';
62
+ process.env.CURSOR_API_KEY = 'test-key';
63
+ process.env.ANTIGRAVITY_API_KEY = 'test-key';
64
+ });
65
+ it('claude adapter calls SDK and returns text + tokens', async () => {
66
+ const adapter = await getAdapter('claude');
67
+ const ctrl = new AbortController();
68
+ const res = await adapter.call({
69
+ prompt: 'hi',
70
+ complexity: 'MED',
71
+ models: sampleModels,
72
+ signal: ctrl.signal,
73
+ });
74
+ expect(res.output).toBe('mocked claude response');
75
+ expect(res.tokens).toBe(30);
76
+ });
77
+ it('cursor adapter calls SDK and returns result', async () => {
78
+ const adapter = await getAdapter('cursor');
79
+ const ctrl = new AbortController();
80
+ const res = await adapter.call({
81
+ prompt: 'hi',
82
+ complexity: 'LOW',
83
+ models: sampleModels,
84
+ signal: ctrl.signal,
85
+ });
86
+ expect(res.output).toBe('mocked cursor response');
87
+ });
88
+ it('antigravity adapter calls SDK and returns text + tokens', async () => {
89
+ const adapter = await getAdapter('antigravity');
90
+ const ctrl = new AbortController();
91
+ const res = await adapter.call({
92
+ prompt: 'hi',
93
+ complexity: 'HIGH',
94
+ models: sampleModels,
95
+ signal: ctrl.signal,
96
+ });
97
+ expect(res.output).toBe('mocked antigravity response');
98
+ expect(res.tokens).toBe(12);
99
+ });
100
+ });
101
+ describe('Adapters — missing API keys', () => {
102
+ it('claude adapter throws MissingApiKeyError when ANTHROPIC_API_KEY is unset', async () => {
103
+ delete process.env.ANTHROPIC_API_KEY;
104
+ const adapter = await getAdapter('claude');
105
+ await expect(adapter.call({
106
+ prompt: 'hi',
107
+ complexity: 'MED',
108
+ models: sampleModels,
109
+ signal: new AbortController().signal,
110
+ })).rejects.toBeInstanceOf(MissingApiKeyError);
111
+ });
112
+ it('cursor adapter throws MissingApiKeyError when CURSOR_API_KEY is unset', async () => {
113
+ delete process.env.CURSOR_API_KEY;
114
+ const adapter = await getAdapter('cursor');
115
+ await expect(adapter.call({
116
+ prompt: 'hi',
117
+ complexity: 'MED',
118
+ models: sampleModels,
119
+ signal: new AbortController().signal,
120
+ })).rejects.toBeInstanceOf(MissingApiKeyError);
121
+ });
122
+ it('antigravity adapter throws MissingApiKeyError when both env vars are unset', async () => {
123
+ delete process.env.ANTIGRAVITY_API_KEY;
124
+ delete process.env.GOOGLE_API_KEY;
125
+ const adapter = await getAdapter('antigravity');
126
+ await expect(adapter.call({
127
+ prompt: 'hi',
128
+ complexity: 'MED',
129
+ models: sampleModels,
130
+ signal: new AbortController().signal,
131
+ })).rejects.toBeInstanceOf(MissingApiKeyError);
132
+ });
133
+ });
134
+ //# sourceMappingURL=adapters.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapters.test.js","sourceRoot":"","sources":["../../../src/__tests__/dag-runner/adapters.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=graph-ingest.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-ingest.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/dag-runner/graph-ingest.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,105 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { extractFilePaths, ingestTask } from '../../dag-runner/graph-ingest.js';
3
+ import { JsonGraph } from '../../graphrag/json-graph.js';
4
+ import path from 'path';
5
+ import os from 'os';
6
+ import fs from 'fs-extra';
7
+ describe('extractFilePaths', () => {
8
+ it('finds bare path-like tokens with extensions', () => {
9
+ const text = 'I created src/auth/login.ts and tests/auth.test.ts.';
10
+ const paths = extractFilePaths(text);
11
+ expect(paths).toContain('src/auth/login.ts');
12
+ expect(paths).toContain('tests/auth.test.ts');
13
+ });
14
+ it('extracts paths from explicit markers', () => {
15
+ const text = 'Created: src/main.rs\nModified: tests/integration.rs';
16
+ const paths = extractFilePaths(text);
17
+ expect(paths).toContain('src/main.rs');
18
+ expect(paths).toContain('tests/integration.rs');
19
+ });
20
+ it('ignores http(s) URLs and bare words', () => {
21
+ const text = 'See https://example.com/a.ts for context. The word ts appears alone.';
22
+ const paths = extractFilePaths(text);
23
+ expect(paths).not.toContain('https://example.com/a.ts');
24
+ expect(paths.length).toBe(0);
25
+ });
26
+ it('deduplicates equal paths found by different patterns', () => {
27
+ const text = 'Created: src/x.ts\nThe file src/x.ts has been updated.';
28
+ const paths = extractFilePaths(text);
29
+ const occurrences = paths.filter((p) => p === 'src/x.ts').length;
30
+ expect(occurrences).toBe(1);
31
+ });
32
+ });
33
+ describe('ingestTask', () => {
34
+ let graph;
35
+ let filePath;
36
+ beforeEach(async () => {
37
+ filePath = path.join(os.tmpdir(), `dare-ingest-test-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
38
+ graph = new JsonGraph(filePath);
39
+ await graph.init();
40
+ });
41
+ afterEach(async () => {
42
+ await fs.remove(filePath).catch(() => undefined);
43
+ });
44
+ const sampleDag = () => ({
45
+ title: 'sample',
46
+ version: '1.0.0',
47
+ models: { cursor: { HIGH: 'h', MED: 'm', LOW: 'l' } },
48
+ tasks: [
49
+ { id: 't1', title: 'one', depends_on: [], complexity: 'LOW', subtask_prompt: 'p1', status: 'PENDING' },
50
+ { id: 't2', title: 'two', depends_on: ['t1'], complexity: 'MED', subtask_prompt: 'p2', status: 'PENDING' },
51
+ ],
52
+ });
53
+ it('creates a task node with status metadata', () => {
54
+ const dag = sampleDag();
55
+ dag.tasks[0].status = 'DONE';
56
+ dag.tasks[0].duration = 500;
57
+ dag.tasks[0].tokens = 1234;
58
+ ingestTask(graph, dag.tasks[0], dag);
59
+ const node = graph.getNode('task:t1');
60
+ expect(node).toBeDefined();
61
+ expect(node?.type).toBe('task');
62
+ expect(node?.metadata?.status).toBe('DONE');
63
+ expect(node?.metadata?.tokens).toBe(1234);
64
+ expect(node?.metadata?.duration_ms).toBe(500);
65
+ });
66
+ it('mirrors depends_on edges from the DAG', () => {
67
+ const dag = sampleDag();
68
+ dag.tasks[0].status = 'DONE';
69
+ dag.tasks[1].status = 'DONE';
70
+ ingestTask(graph, dag.tasks[0], dag);
71
+ ingestTask(graph, dag.tasks[1], dag);
72
+ const edges = graph.getEdges('task:t2', 'out').filter((e) => e.type === 'depends_on');
73
+ expect(edges).toHaveLength(1);
74
+ expect(edges[0].targetId).toBe('task:t1');
75
+ });
76
+ it('creates file nodes + implements edges for DONE tasks with paths in output', () => {
77
+ const dag = sampleDag();
78
+ const task = dag.tasks[0];
79
+ task.status = 'DONE';
80
+ task.output = 'Created src/auth.ts and tests/auth.test.ts.';
81
+ ingestTask(graph, task, dag);
82
+ expect(graph.getNode('file:src/auth.ts')).toBeDefined();
83
+ expect(graph.getNode('file:tests/auth.test.ts')).toBeDefined();
84
+ const implementsEdges = graph
85
+ .getEdges('task:t1', 'out')
86
+ .filter((e) => e.type === 'implements');
87
+ expect(implementsEdges.length).toBe(2);
88
+ });
89
+ it('does not create file nodes when status is FAILED', () => {
90
+ const dag = sampleDag();
91
+ const task = dag.tasks[0];
92
+ task.status = 'FAILED';
93
+ task.output = 'Tried to create src/auth.ts but compile failed.';
94
+ task.error = 'compile error';
95
+ ingestTask(graph, task, dag);
96
+ expect(graph.getNode('task:t1')).toBeDefined();
97
+ expect(graph.getNode('file:src/auth.ts')).toBeNull();
98
+ });
99
+ it('skips PENDING/RUNNING tasks entirely', () => {
100
+ const dag = sampleDag();
101
+ ingestTask(graph, dag.tasks[0], dag); // status PENDING
102
+ expect(graph.getNode('task:t1')).toBeNull();
103
+ });
104
+ });
105
+ //# sourceMappingURL=graph-ingest.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-ingest.test.js","sourceRoot":"","sources":["../../../src/__tests__/dag-runner/graph-ingest.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=orchestrator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/dag-runner/orchestrator.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,107 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { applyCascadingSkip, buildTaskPrompt, computeRanks, markDone, markFailed, markRunning, nextExecutableTasks, } from '../../dag-runner/run_dag.js';
3
+ const sampleDag = () => ({
4
+ title: 'sample',
5
+ version: '1.0.0',
6
+ models: { cursor: { HIGH: 'h', MED: 'm', LOW: 'l' } },
7
+ tasks: [
8
+ { id: 't1', title: 'one', depends_on: [], complexity: 'LOW', subtask_prompt: 'p1', status: 'PENDING' },
9
+ { id: 't2', title: 'two', depends_on: [], complexity: 'LOW', subtask_prompt: 'p2', status: 'PENDING' },
10
+ { id: 't3', title: 'three', depends_on: ['t1', 't2'], complexity: 'MED', subtask_prompt: 'p3', status: 'PENDING' },
11
+ { id: 't4', title: 'four', depends_on: ['t3'], complexity: 'HIGH', subtask_prompt: 'p4', status: 'PENDING' },
12
+ ],
13
+ });
14
+ describe('computeRanks', () => {
15
+ it('groups parallelizable tasks at the same rank', () => {
16
+ const ranks = computeRanks(sampleDag().tasks);
17
+ expect(ranks.get('t1')).toBe(0);
18
+ expect(ranks.get('t2')).toBe(0);
19
+ expect(ranks.get('t3')).toBe(1);
20
+ expect(ranks.get('t4')).toBe(2);
21
+ });
22
+ it('throws on cycles', () => {
23
+ const dag = sampleDag();
24
+ dag.tasks[0].depends_on = ['t4']; // t1 → t4 → t3 → t1
25
+ expect(() => computeRanks(dag.tasks)).toThrow(/Circular dependency/);
26
+ });
27
+ });
28
+ describe('nextExecutableTasks', () => {
29
+ it('returns rank-0 tasks at the start', () => {
30
+ const dag = sampleDag();
31
+ const ready = nextExecutableTasks(dag);
32
+ expect(ready.map((t) => t.id).sort()).toEqual(['t1', 't2']);
33
+ });
34
+ it('advances to next rank when current rank is DONE', () => {
35
+ const dag = sampleDag();
36
+ markDone(dag, 't1', { output: 'x' });
37
+ markDone(dag, 't2', { output: 'y' });
38
+ const ready = nextExecutableTasks(dag);
39
+ expect(ready.map((t) => t.id)).toEqual(['t3']);
40
+ });
41
+ it('skips RUNNING tasks (already picked up by the agent)', () => {
42
+ const dag = sampleDag();
43
+ markRunning(dag, 't1');
44
+ const ready = nextExecutableTasks(dag);
45
+ // t1 is RUNNING; only t2 remains in rank 0
46
+ expect(ready.map((t) => t.id)).toEqual(['t2']);
47
+ });
48
+ });
49
+ describe('markFailed + applyCascadingSkip', () => {
50
+ it('cascades SKIPPED through descendants when a parent fails', () => {
51
+ const dag = sampleDag();
52
+ markDone(dag, 't1', { output: 'x' });
53
+ markFailed(dag, 't2', { error: 'boom' });
54
+ expect(byId(dag, 't2').status).toBe('FAILED');
55
+ expect(byId(dag, 't3').status).toBe('SKIPPED'); // depends on t2
56
+ expect(byId(dag, 't4').status).toBe('SKIPPED'); // depends on t3
57
+ });
58
+ it('applyCascadingSkip is idempotent and only re-skips PENDING', () => {
59
+ const dag = sampleDag();
60
+ markFailed(dag, 't1', { error: 'x' });
61
+ const firstPass = applyCascadingSkip(dag);
62
+ const secondPass = applyCascadingSkip(dag);
63
+ expect(secondPass).toHaveLength(0);
64
+ // t3 + t4 transitively skipped from t1's failure (t3 also depends on t2 still PENDING — but cascade only triggers on FAILED/SKIPPED parents)
65
+ expect(byId(dag, 't1').status).toBe('FAILED');
66
+ expect(firstPass.length).toBeGreaterThanOrEqual(0); // depending on cascade ordering
67
+ });
68
+ });
69
+ describe('markDone', () => {
70
+ it('caps output to limits.task_output_chars (with truncation notice when room allows)', () => {
71
+ const dag = sampleDag();
72
+ dag.limits = { parent_context_chars: 100, task_output_chars: 80, timeout_seconds: 60 };
73
+ markDone(dag, 't1', { output: 'x'.repeat(500) });
74
+ expect(byId(dag, 't1').output?.length).toBe(80);
75
+ expect(byId(dag, 't1').output).toMatch(/truncated by DARE/);
76
+ });
77
+ it('records tokens and duration when provided', () => {
78
+ const dag = sampleDag();
79
+ markDone(dag, 't1', { tokens: 1234, durationMs: 500 });
80
+ expect(byId(dag, 't1').tokens).toBe(1234);
81
+ expect(byId(dag, 't1').duration).toBe(500);
82
+ });
83
+ });
84
+ describe('buildTaskPrompt', () => {
85
+ it('returns the bare prompt when no parents have output', () => {
86
+ const dag = sampleDag();
87
+ const prompt = buildTaskPrompt(dag, byId(dag, 't1'));
88
+ expect(prompt).toBe('p1');
89
+ });
90
+ it('appends parent outputs as Upstream context', () => {
91
+ const dag = sampleDag();
92
+ markDone(dag, 't1', { output: 'parent one done' });
93
+ markDone(dag, 't2', { output: 'parent two done' });
94
+ const prompt = buildTaskPrompt(dag, byId(dag, 't3'));
95
+ expect(prompt).toMatch(/^p3/);
96
+ expect(prompt).toMatch(/Upstream context/);
97
+ expect(prompt).toMatch(/parent one done/);
98
+ expect(prompt).toMatch(/parent two done/);
99
+ });
100
+ });
101
+ function byId(dag, id) {
102
+ const t = dag.tasks.find((task) => task.id === id);
103
+ if (!t)
104
+ throw new Error(`missing task ${id}`);
105
+ return t;
106
+ }
107
+ //# sourceMappingURL=orchestrator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.test.js","sourceRoot":"","sources":["../../../src/__tests__/dag-runner/orchestrator.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=utils.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/dag-runner/utils.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,47 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { capOutput } from '../../dag-runner/utils/cap-output.js';
3
+ import { composePrompt, stitchParentContext, } from '../../dag-runner/utils/stitch-context.js';
4
+ const makeTask = (over) => ({
5
+ id: 't',
6
+ title: 't',
7
+ depends_on: [],
8
+ complexity: 'MED',
9
+ subtask_prompt: '',
10
+ ...over,
11
+ });
12
+ describe('capOutput', () => {
13
+ it('passes through when below the cap', () => {
14
+ expect(capOutput('hello', 100)).toBe('hello');
15
+ });
16
+ it('truncates with notice when above the cap', () => {
17
+ const out = capOutput('a'.repeat(200), 50);
18
+ expect(out.length).toBe(50);
19
+ expect(out).toMatch(/truncated by DARE/);
20
+ });
21
+ it('returns empty when cap is 0', () => {
22
+ expect(capOutput('anything', 0)).toBe('');
23
+ });
24
+ });
25
+ describe('stitchParentContext / composePrompt', () => {
26
+ it('returns empty string when no parents', () => {
27
+ const task = makeTask({ id: 'child', subtask_prompt: 'do x' });
28
+ expect(stitchParentContext({ task, parents: [], parentContextChars: 2000 })).toBe('');
29
+ });
30
+ it('appends a tail snippet for each parent capped to N chars', () => {
31
+ const parent = makeTask({ id: 'p1', output: 'A'.repeat(5000) });
32
+ const task = makeTask({ id: 'c', subtask_prompt: 'work' });
33
+ const ctx = stitchParentContext({ task, parents: [parent], parentContextChars: 100 });
34
+ expect(ctx).toMatch(/From parent: p1/);
35
+ const snippetLine = ctx.split('\n').find((l) => l.startsWith('…')) ?? '';
36
+ expect(snippetLine.length).toBe(100);
37
+ });
38
+ it('composePrompt prepends prompt and appends context', () => {
39
+ const parent = makeTask({ id: 'p', output: 'parent says hi' });
40
+ const task = makeTask({ subtask_prompt: 'go' });
41
+ const out = composePrompt({ task, parents: [parent], parentContextChars: 2000 });
42
+ expect(out.startsWith('go')).toBe(true);
43
+ expect(out).toMatch(/Upstream context/);
44
+ expect(out).toMatch(/parent says hi/);
45
+ });
46
+ });
47
+ //# sourceMappingURL=utils.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.test.js","sourceRoot":"","sources":["../../../src/__tests__/dag-runner/utils.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=json-graph.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-graph.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/graphrag/json-graph.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,57 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import fs from 'fs-extra';
5
+ import { JsonGraph } from '../../graphrag/json-graph.js';
6
+ describe('JsonGraph', () => {
7
+ let filePath;
8
+ let graph;
9
+ beforeEach(async () => {
10
+ filePath = path.join(os.tmpdir(), `dare-json-graph-test-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
11
+ graph = new JsonGraph(filePath);
12
+ await graph.init();
13
+ });
14
+ afterEach(async () => {
15
+ await fs.remove(filePath).catch(() => undefined);
16
+ });
17
+ it('upserts nodes by id', async () => {
18
+ graph.addNode({ id: 'n1', type: 'task', label: 'first' });
19
+ graph.addNode({ id: 'n1', type: 'task', label: 'updated' });
20
+ expect(graph.getNode('n1')?.label).toBe('updated');
21
+ });
22
+ it('searches nodes by label substring', () => {
23
+ graph.addNode({ id: 'a', type: 'task', label: 'authentication module' });
24
+ graph.addNode({ id: 'b', type: 'file', label: 'README.md' });
25
+ const results = graph.searchNodes('auth');
26
+ expect(results.length).toBe(1);
27
+ expect(results[0].node.id).toBe('a');
28
+ });
29
+ it('cascades edge cleanup when a node is deleted', () => {
30
+ graph.addNode({ id: 'a', type: 'task', label: 'a' });
31
+ graph.addNode({ id: 'b', type: 'task', label: 'b' });
32
+ graph.addEdge({ id: 'e1', sourceId: 'a', targetId: 'b', type: 'depends_on' });
33
+ graph.deleteNode('a');
34
+ expect(graph.getEdges('b')).toHaveLength(0);
35
+ });
36
+ it('persists state across instances', async () => {
37
+ graph.addNode({ id: 'a', type: 'task', label: 'persisted' });
38
+ graph.addEdge({ id: 'e', sourceId: 'a', targetId: 'a', type: 'related_to' });
39
+ const reloaded = new JsonGraph(filePath);
40
+ await reloaded.init();
41
+ expect(reloaded.getNode('a')?.label).toBe('persisted');
42
+ expect(reloaded.getEdges('a')).toHaveLength(1);
43
+ });
44
+ it('reports stats by type', () => {
45
+ graph.addNode({ id: 'a', type: 'task', label: 'A' });
46
+ graph.addNode({ id: 'b', type: 'task', label: 'B' });
47
+ graph.addNode({ id: 'c', type: 'file', label: 'C' });
48
+ graph.addEdge({ id: 'e1', sourceId: 'a', targetId: 'c', type: 'implements' });
49
+ const stats = graph.getStatistics();
50
+ expect(stats.totalNodes).toBe(3);
51
+ expect(stats.totalEdges).toBe(1);
52
+ expect(stats.nodesByType.task).toBe(2);
53
+ expect(stats.nodesByType.file).toBe(1);
54
+ expect(stats.edgesByType.implements).toBe(1);
55
+ });
56
+ });
57
+ //# sourceMappingURL=json-graph.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-graph.test.js","sourceRoot":"","sources":["../../../src/__tests__/graphrag/json-graph.test.ts"],"names":[],"mappings":"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"}
package/dist/bin/dare.js CHANGED
@@ -6,6 +6,7 @@ import { designCommand } from '../commands/design.js';
6
6
  import { blueprintCommand } from '../commands/blueprint.js';
7
7
  import { executeCommand } from '../commands/execute.js';
8
8
  import { discoverCommand } from '../commands/discover.js';
9
+ import { graphCommand } from '../commands/graph.js';
9
10
  const require = createRequire(import.meta.url);
10
11
  const { version } = require('../../package.json');
11
12
  const program = new Command();
@@ -18,6 +19,7 @@ program.addCommand(discoverCommand);
18
19
  program.addCommand(designCommand);
19
20
  program.addCommand(blueprintCommand);
20
21
  program.addCommand(executeCommand);
22
+ program.addCommand(graphCommand);
21
23
  program.parse(process.argv);
22
24
  if (!process.argv.slice(2).length) {
23
25
  program.outputHelp();