@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.
- package/README.md +53 -7
- package/dist/__tests__/dag-runner/adapters.test.d.ts +2 -0
- package/dist/__tests__/dag-runner/adapters.test.d.ts.map +1 -0
- package/dist/__tests__/dag-runner/adapters.test.js +134 -0
- package/dist/__tests__/dag-runner/adapters.test.js.map +1 -0
- package/dist/__tests__/dag-runner/graph-ingest.test.d.ts +2 -0
- package/dist/__tests__/dag-runner/graph-ingest.test.d.ts.map +1 -0
- package/dist/__tests__/dag-runner/graph-ingest.test.js +105 -0
- package/dist/__tests__/dag-runner/graph-ingest.test.js.map +1 -0
- package/dist/__tests__/dag-runner/orchestrator.test.d.ts +2 -0
- package/dist/__tests__/dag-runner/orchestrator.test.d.ts.map +1 -0
- package/dist/__tests__/dag-runner/orchestrator.test.js +107 -0
- package/dist/__tests__/dag-runner/orchestrator.test.js.map +1 -0
- package/dist/__tests__/dag-runner/utils.test.d.ts +2 -0
- package/dist/__tests__/dag-runner/utils.test.d.ts.map +1 -0
- package/dist/__tests__/dag-runner/utils.test.js +47 -0
- package/dist/__tests__/dag-runner/utils.test.js.map +1 -0
- package/dist/__tests__/graphrag/json-graph.test.d.ts +2 -0
- package/dist/__tests__/graphrag/json-graph.test.d.ts.map +1 -0
- package/dist/__tests__/graphrag/json-graph.test.js +57 -0
- package/dist/__tests__/graphrag/json-graph.test.js.map +1 -0
- package/dist/bin/dare.js +2 -0
- package/dist/bin/dare.js.map +1 -1
- package/dist/commands/execute.d.ts.map +1 -1
- package/dist/commands/execute.js +172 -45
- package/dist/commands/execute.js.map +1 -1
- package/dist/commands/graph.d.ts +9 -0
- package/dist/commands/graph.d.ts.map +1 -0
- package/dist/commands/graph.js +155 -0
- package/dist/commands/graph.js.map +1 -0
- package/dist/dag-runner/adapters/antigravity.d.ts +6 -0
- package/dist/dag-runner/adapters/antigravity.d.ts.map +1 -0
- package/dist/dag-runner/adapters/antigravity.js +54 -0
- package/dist/dag-runner/adapters/antigravity.js.map +1 -0
- package/dist/dag-runner/adapters/claude.d.ts +6 -0
- package/dist/dag-runner/adapters/claude.d.ts.map +1 -0
- package/dist/dag-runner/adapters/claude.js +48 -0
- package/dist/dag-runner/adapters/claude.js.map +1 -0
- package/dist/dag-runner/adapters/cursor.d.ts +6 -0
- package/dist/dag-runner/adapters/cursor.d.ts.map +1 -0
- package/dist/dag-runner/adapters/cursor.js +58 -0
- package/dist/dag-runner/adapters/cursor.js.map +1 -0
- package/dist/dag-runner/adapters/index.d.ts +46 -0
- package/dist/dag-runner/adapters/index.d.ts.map +1 -0
- package/dist/dag-runner/adapters/index.js +55 -0
- package/dist/dag-runner/adapters/index.js.map +1 -0
- package/dist/dag-runner/graph-ingest.d.ts +17 -0
- package/dist/dag-runner/graph-ingest.d.ts.map +1 -0
- package/dist/dag-runner/graph-ingest.js +149 -0
- package/dist/dag-runner/graph-ingest.js.map +1 -0
- package/dist/dag-runner/run_dag.d.ts +51 -24
- package/dist/dag-runner/run_dag.d.ts.map +1 -1
- package/dist/dag-runner/run_dag.js +163 -109
- package/dist/dag-runner/run_dag.js.map +1 -1
- package/dist/dag-runner/state-store.d.ts +13 -0
- package/dist/dag-runner/state-store.d.ts.map +1 -0
- package/dist/dag-runner/state-store.js +69 -0
- package/dist/dag-runner/state-store.js.map +1 -0
- package/dist/dag-runner/utils/cap-output.d.ts +14 -0
- package/dist/dag-runner/utils/cap-output.d.ts.map +1 -0
- package/dist/dag-runner/utils/cap-output.js +25 -0
- package/dist/dag-runner/utils/cap-output.js.map +1 -0
- package/dist/dag-runner/utils/stitch-context.d.ts +24 -0
- package/dist/dag-runner/utils/stitch-context.d.ts.map +1 -0
- package/dist/dag-runner/utils/stitch-context.js +36 -0
- package/dist/dag-runner/utils/stitch-context.js.map +1 -0
- package/dist/dag-runner/utils/timeout.d.ts +27 -0
- package/dist/dag-runner/utils/timeout.d.ts.map +1 -0
- package/dist/dag-runner/utils/timeout.js +55 -0
- package/dist/dag-runner/utils/timeout.js.map +1 -0
- package/dist/graphrag/factory.d.ts +25 -0
- package/dist/graphrag/factory.d.ts.map +1 -0
- package/dist/graphrag/factory.js +66 -0
- package/dist/graphrag/factory.js.map +1 -0
- package/dist/graphrag/index.d.ts +4 -0
- package/dist/graphrag/index.d.ts.map +1 -1
- package/dist/graphrag/index.js +2 -0
- package/dist/graphrag/index.js.map +1 -1
- package/dist/graphrag/json-graph.d.ts +28 -0
- package/dist/graphrag/json-graph.d.ts.map +1 -0
- package/dist/graphrag/json-graph.js +168 -0
- package/dist/graphrag/json-graph.js.map +1 -0
- package/dist/graphrag/knowledge-graph.d.ts +33 -0
- package/dist/graphrag/knowledge-graph.d.ts.map +1 -0
- package/dist/graphrag/knowledge-graph.js +2 -0
- package/dist/graphrag/knowledge-graph.js.map +1 -0
- package/dist/index.d.ts +13 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/ide/antigravity/.agents/skills/dare-dag-runner/SKILL.md +99 -96
- package/templates/ide/claude/.claude/commands/dare-dag-run.md +68 -69
- package/templates/ide/cursor/.cursor/commands/run-dag.md +67 -44
- 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
|
-
|
|
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
|
-
|
|
95
|
-
dare
|
|
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
|
-
#
|
|
98
|
-
dare
|
|
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
|
-
#
|
|
101
|
-
dare execute
|
|
147
|
+
dare graph ingest # re-sync from dare-dag.yaml + state
|
|
102
148
|
```
|
|
103
149
|
|
|
104
150
|
---
|
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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();
|