@dewtech/dare-cli 2.15.0 → 2.17.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 +659 -561
- package/dist/__tests__/refine.test.d.ts +2 -0
- package/dist/__tests__/refine.test.d.ts.map +1 -0
- package/dist/__tests__/refine.test.js +186 -0
- package/dist/__tests__/refine.test.js.map +1 -0
- package/dist/__tests__/review.test.d.ts +2 -0
- package/dist/__tests__/review.test.d.ts.map +1 -0
- package/dist/__tests__/review.test.js +242 -0
- package/dist/__tests__/review.test.js.map +1 -0
- package/dist/__tests__/update.test.d.ts +2 -0
- package/dist/__tests__/update.test.d.ts.map +1 -0
- package/dist/__tests__/update.test.js +150 -0
- package/dist/__tests__/update.test.js.map +1 -0
- package/dist/bin/dare.js +6 -0
- package/dist/bin/dare.js.map +1 -1
- package/dist/commands/dag.d.ts.map +1 -1
- package/dist/commands/dag.js +27 -9
- package/dist/commands/dag.js.map +1 -1
- package/dist/commands/execute.d.ts.map +1 -1
- package/dist/commands/execute.js +76 -0
- package/dist/commands/execute.js.map +1 -1
- package/dist/commands/refine.d.ts +16 -0
- package/dist/commands/refine.d.ts.map +1 -0
- package/dist/commands/refine.js +167 -0
- package/dist/commands/refine.js.map +1 -0
- package/dist/commands/review.d.ts +16 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +106 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/update.d.ts +13 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +149 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/types/Refine.types.d.ts +96 -0
- package/dist/types/Refine.types.d.ts.map +1 -0
- package/dist/types/Refine.types.js +19 -0
- package/dist/types/Refine.types.js.map +1 -0
- package/dist/types/Review.types.d.ts +86 -0
- package/dist/types/Review.types.d.ts.map +1 -0
- package/dist/types/Review.types.js +15 -0
- package/dist/types/Review.types.js.map +1 -0
- package/dist/types/UpdateManifest.types.d.ts +91 -0
- package/dist/types/UpdateManifest.types.d.ts.map +1 -0
- package/dist/types/UpdateManifest.types.js +13 -0
- package/dist/types/UpdateManifest.types.js.map +1 -0
- package/dist/utils/ReviewRunner.d.ts +42 -0
- package/dist/utils/ReviewRunner.d.ts.map +1 -0
- package/dist/utils/ReviewRunner.js +175 -0
- package/dist/utils/ReviewRunner.js.map +1 -0
- package/dist/utils/UpdateApplier.d.ts +42 -0
- package/dist/utils/UpdateApplier.d.ts.map +1 -0
- package/dist/utils/UpdateApplier.js +207 -0
- package/dist/utils/UpdateApplier.js.map +1 -0
- package/dist/utils/UpdateDetector.d.ts +56 -0
- package/dist/utils/UpdateDetector.d.ts.map +1 -0
- package/dist/utils/UpdateDetector.js +164 -0
- package/dist/utils/UpdateDetector.js.map +1 -0
- package/dist/utils/complexity-analyzer.d.ts +60 -0
- package/dist/utils/complexity-analyzer.d.ts.map +1 -0
- package/dist/utils/complexity-analyzer.js +292 -0
- package/dist/utils/complexity-analyzer.js.map +1 -0
- package/dist/utils/excalidraw-renderer.d.ts +79 -0
- package/dist/utils/excalidraw-renderer.d.ts.map +1 -0
- package/dist/utils/excalidraw-renderer.js +188 -0
- package/dist/utils/excalidraw-renderer.js.map +1 -0
- package/dist/utils/excalidraw-renderer.test.d.ts +2 -0
- package/dist/utils/excalidraw-renderer.test.d.ts.map +1 -0
- package/dist/utils/excalidraw-renderer.test.js +135 -0
- package/dist/utils/excalidraw-renderer.test.js.map +1 -0
- package/dist/utils/project-generator.d.ts.map +1 -1
- package/dist/utils/project-generator.js +21 -2
- package/dist/utils/project-generator.js.map +1 -1
- package/dist/utils/stack-bootstrap.js +3 -1
- package/dist/utils/stack-bootstrap.js.map +1 -1
- package/dist/utils/static-analyzer.d.ts +29 -0
- package/dist/utils/static-analyzer.d.ts.map +1 -0
- package/dist/utils/static-analyzer.js +390 -0
- package/dist/utils/static-analyzer.js.map +1 -0
- package/dist/utils/version-compare.d.ts +27 -0
- package/dist/utils/version-compare.d.ts.map +1 -0
- package/dist/utils/version-compare.js +47 -0
- package/dist/utils/version-compare.js.map +1 -0
- package/package.json +1 -1
- package/templates/DARE-dag-example.yaml +280 -0
- package/templates/UPDATE-MANIFEST.json +48 -0
- package/templates/ide/antigravity/.agents/skills/dare-blueprint/SKILL.md +180 -36
- package/templates/ide/antigravity/.agents/skills/dare-refine/SKILL.md +114 -0
- package/templates/ide/antigravity/.agents/skills/dare-review/SKILL.md +111 -0
- package/templates/ide/antigravity/.agents/skills/dare-tasks/SKILL.md +41 -0
- package/templates/ide/antigravity/templates/TASK-SPEC-template.md +45 -4
- package/templates/ide/claude/.claude/commands/dare-blueprint.md +56 -0
- package/templates/ide/claude/.claude/commands/dare-dag-build.md +41 -0
- package/templates/ide/claude/.claude/commands/dare-dag-viz.md +197 -0
- package/templates/ide/claude/.claude/commands/dare-refine.md +145 -0
- package/templates/ide/claude/.claude/commands/dare-review.md +113 -0
- package/templates/ide/claude/templates/TASK-SPEC-template.md +45 -4
- package/templates/ide/cursor/.cursor/commands/generate-blueprint.md +45 -0
- package/templates/ide/cursor/.cursor/commands/generate-tasks.md +42 -0
- package/templates/ide/cursor/.cursor/commands/refine-task.md +107 -0
- package/templates/ide/cursor/.cursor/commands/review-task.md +91 -0
- package/templates/ide/cursor/templates/TASK-SPEC-template.md +45 -4
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detects what `dare update` needs to do for a given project.
|
|
3
|
+
*
|
|
4
|
+
* Pure planning — it never writes to disk. Loads the manifest, reads the
|
|
5
|
+
* project's `dare.config.json`, and produces an `UpdatePlan` the applier can
|
|
6
|
+
* execute (or the dev can simply preview with `--dry-run`).
|
|
7
|
+
*/
|
|
8
|
+
import fs from 'fs-extra';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import crypto from 'crypto';
|
|
11
|
+
import { createRequire } from 'module';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
import { compareVersions, isNewerThan, sortVersionsAscending, } from './version-compare.js';
|
|
14
|
+
const require = createRequire(import.meta.url);
|
|
15
|
+
/** Path to `templates/UPDATE-MANIFEST.json`, shipped with the CLI. */
|
|
16
|
+
function getManifestPath() {
|
|
17
|
+
// `import.meta.url` resolves to .../dist/utils/UpdateDetector.js once built.
|
|
18
|
+
// The manifest lives at .../templates/UPDATE-MANIFEST.json, two levels up.
|
|
19
|
+
const here = fileURLToPath(import.meta.url);
|
|
20
|
+
return path.resolve(path.dirname(here), '..', '..', 'templates', 'UPDATE-MANIFEST.json');
|
|
21
|
+
}
|
|
22
|
+
export async function loadManifest() {
|
|
23
|
+
const manifestPath = getManifestPath();
|
|
24
|
+
if (!(await fs.pathExists(manifestPath))) {
|
|
25
|
+
throw new Error(`UPDATE-MANIFEST.json not found at ${manifestPath}`);
|
|
26
|
+
}
|
|
27
|
+
const data = (await fs.readJSON(manifestPath));
|
|
28
|
+
if (data.schemaVersion !== 1) {
|
|
29
|
+
throw new Error(`Unsupported manifest schemaVersion ${data.schemaVersion} (this CLI understands 1).`);
|
|
30
|
+
}
|
|
31
|
+
return data;
|
|
32
|
+
}
|
|
33
|
+
/** Read the current CLI version from the bundled `package.json`. */
|
|
34
|
+
export function getCliVersion() {
|
|
35
|
+
const pkg = require('../../package.json');
|
|
36
|
+
return pkg.version;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Legacy `dare init` versions (pre-2.17) wrote a hardcoded `"0.1.0"` placeholder
|
|
40
|
+
* that nothing read. Treat it as "this project was never tracked" — the update
|
|
41
|
+
* flow will assume the project is on 2.16.0 (the last release before this field
|
|
42
|
+
* carried meaning) and run the unification migration.
|
|
43
|
+
*/
|
|
44
|
+
const LEGACY_PLACEHOLDER_VERSION = '0.1.0';
|
|
45
|
+
/** Baseline assumed for projects with the legacy placeholder or no `version`. */
|
|
46
|
+
export const LEGACY_BASELINE_VERSION = '2.16.0';
|
|
47
|
+
/**
|
|
48
|
+
* Resolve the "effective DARE version" of a project, handling the legacy
|
|
49
|
+
* `"0.1.0"` placeholder that was hardcoded by pre-2.17 `dare init`.
|
|
50
|
+
*/
|
|
51
|
+
export function resolveProjectVersion(cfg) {
|
|
52
|
+
const raw = cfg.version;
|
|
53
|
+
if (!raw || raw === LEGACY_PLACEHOLDER_VERSION) {
|
|
54
|
+
return { version: LEGACY_BASELINE_VERSION, isLegacy: true };
|
|
55
|
+
}
|
|
56
|
+
return { version: raw, isLegacy: false };
|
|
57
|
+
}
|
|
58
|
+
/** Load and return `dare.config.json` from the given project root. */
|
|
59
|
+
export async function readProjectConfig(projectRoot) {
|
|
60
|
+
const configPath = path.join(projectRoot, 'dare.config.json');
|
|
61
|
+
if (!(await fs.pathExists(configPath))) {
|
|
62
|
+
throw new Error(`dare.config.json not found in ${projectRoot}. Is this a DARE project? Run \`dare init\` first.`);
|
|
63
|
+
}
|
|
64
|
+
return (await fs.readJSON(configPath));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Filter a single change against the IDE configured for this project. A change
|
|
68
|
+
* with `appliesTo: ['*']` (or no `appliesTo`) is universal.
|
|
69
|
+
*
|
|
70
|
+
* Hybrid setups (`hybrid` = cursor+antigravity, `claude-hybrid` = claude+cursor)
|
|
71
|
+
* accept changes targeted at any of their member IDEs.
|
|
72
|
+
*/
|
|
73
|
+
export function changeAppliesToIde(change, ide) {
|
|
74
|
+
const targets = change.appliesTo ?? ['*'];
|
|
75
|
+
if (targets.includes('*'))
|
|
76
|
+
return true;
|
|
77
|
+
if (!ide)
|
|
78
|
+
return false;
|
|
79
|
+
if (targets.includes(ide))
|
|
80
|
+
return true;
|
|
81
|
+
// Hybrid expansions
|
|
82
|
+
if (ide === 'hybrid') {
|
|
83
|
+
return targets.includes('cursor') || targets.includes('antigravity');
|
|
84
|
+
}
|
|
85
|
+
if (ide === 'claude-hybrid') {
|
|
86
|
+
return targets.includes('claude-code') || targets.includes('cursor');
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Build the update plan: every release between `from` (exclusive) and `to`
|
|
92
|
+
* (inclusive), with its changes filtered down to what applies to this IDE.
|
|
93
|
+
*/
|
|
94
|
+
export function buildUpdatePlan(manifest, fromVersion, toVersion, ide) {
|
|
95
|
+
const allVersions = Object.keys(manifest.releases);
|
|
96
|
+
const sorted = sortVersionsAscending(allVersions);
|
|
97
|
+
const pending = sorted.filter((v) => {
|
|
98
|
+
const newerThanFrom = isNewerThan(v, fromVersion);
|
|
99
|
+
const notNewerThanTo = compareVersions(v, toVersion) !== 1;
|
|
100
|
+
return newerThanFrom && notNewerThanTo;
|
|
101
|
+
});
|
|
102
|
+
const pendingReleases = pending.map((version) => ({
|
|
103
|
+
version,
|
|
104
|
+
release: manifest.releases[version],
|
|
105
|
+
}));
|
|
106
|
+
const applicableChanges = [];
|
|
107
|
+
for (const { release } of pendingReleases) {
|
|
108
|
+
for (const change of release.changes) {
|
|
109
|
+
if (changeAppliesToIde(change, ide)) {
|
|
110
|
+
applicableChanges.push(change);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
fromVersion,
|
|
116
|
+
toVersion,
|
|
117
|
+
pendingReleases,
|
|
118
|
+
applicableChanges,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/** SHA-256 hex digest of file content; returns `null` if the file is absent. */
|
|
122
|
+
export async function hashFile(absPath) {
|
|
123
|
+
if (!(await fs.pathExists(absPath)))
|
|
124
|
+
return null;
|
|
125
|
+
const buf = await fs.readFile(absPath);
|
|
126
|
+
return crypto.createHash('sha256').update(buf).digest('hex');
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Classify what we'd be doing to a single file on disk:
|
|
130
|
+
* - `identical` → new template content already matches what's on disk
|
|
131
|
+
* - `missing` → file absent in the project, safe to create
|
|
132
|
+
* - `apply` → file present and matches `previousHash`, safe to overwrite
|
|
133
|
+
* - `customized` → file present but doesn't match `previousHash`; ask the dev
|
|
134
|
+
*
|
|
135
|
+
* `newContent` is the bytes we'd write; `previousHash` is the manifest's record
|
|
136
|
+
* of what the file looked like in the prior version (optional — without it we
|
|
137
|
+
* can't tell `apply` from `customized` and conservatively return `customized`).
|
|
138
|
+
*/
|
|
139
|
+
export async function classifyChange(projectRoot, change, newContent) {
|
|
140
|
+
// Schema-only changes (path includes `#`) are handled by migrations,
|
|
141
|
+
// not by file copy. Treat them as `apply`.
|
|
142
|
+
if (change.path.includes('#'))
|
|
143
|
+
return 'apply';
|
|
144
|
+
const target = path.join(projectRoot, change.path);
|
|
145
|
+
const currentHash = await hashFile(target);
|
|
146
|
+
if (change.type === 'removed') {
|
|
147
|
+
return currentHash === null ? 'identical' : 'apply';
|
|
148
|
+
}
|
|
149
|
+
if (currentHash === null)
|
|
150
|
+
return 'missing';
|
|
151
|
+
if (newContent !== null) {
|
|
152
|
+
const newHash = crypto
|
|
153
|
+
.createHash('sha256')
|
|
154
|
+
.update(typeof newContent === 'string' ? Buffer.from(newContent) : newContent)
|
|
155
|
+
.digest('hex');
|
|
156
|
+
if (newHash === currentHash)
|
|
157
|
+
return 'identical';
|
|
158
|
+
}
|
|
159
|
+
if (change.previousHash && currentHash === change.previousHash) {
|
|
160
|
+
return 'apply';
|
|
161
|
+
}
|
|
162
|
+
return 'customized';
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=UpdateDetector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UpdateDetector.js","sourceRoot":"","sources":["../../src/utils/UpdateDetector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic complexity heuristic for `dare refine`.
|
|
3
|
+
*
|
|
4
|
+
* Scans a task spec for signals that correlate with implementation effort
|
|
5
|
+
* and aggregates them into a single score → bucket. The breakdown is
|
|
6
|
+
* preserved so the CLI / agent can explain *why* a task scored high.
|
|
7
|
+
*
|
|
8
|
+
* Signals (weights tuned empirically — start conservative; bump as we learn):
|
|
9
|
+
* - Files to create/modify (1 each, cap at 10)
|
|
10
|
+
* - Public functions/endpoints declared in spec (1.5 each, cap at 10)
|
|
11
|
+
* - Test cases listed (0.5 each, cap at 8)
|
|
12
|
+
* - Inbound dependencies in dare-dag.yaml (0.5 each, no cap)
|
|
13
|
+
* - "Heavy" keywords in prompt/spec (+2 each: refactor, migrate, integrate,
|
|
14
|
+
* multiple, audit, replace, rewrite, parallelize, cross-cutting)
|
|
15
|
+
* - HIGH complexity declared by author (+3 baseline)
|
|
16
|
+
*
|
|
17
|
+
* Buckets:
|
|
18
|
+
* 0–5 → LOW
|
|
19
|
+
* 6–12 → MED
|
|
20
|
+
* 13–20 → HIGH ← recommends split
|
|
21
|
+
* 21+ → CRITICAL ← strongly recommends split
|
|
22
|
+
*
|
|
23
|
+
* The thresholds are tunable via `dare.config.json#refine.thresholds` (see
|
|
24
|
+
* Frente 4) — defaults below.
|
|
25
|
+
*/
|
|
26
|
+
import type { ComplexityLevel, ComplexityReport, SplitProposal } from '../types/Refine.types.js';
|
|
27
|
+
export interface ComplexityThresholds {
|
|
28
|
+
low: number;
|
|
29
|
+
med: number;
|
|
30
|
+
high: number;
|
|
31
|
+
}
|
|
32
|
+
export declare const DEFAULT_THRESHOLDS: ComplexityThresholds;
|
|
33
|
+
export declare function levelFromScore(score: number, thresholds?: ComplexityThresholds): ComplexityLevel;
|
|
34
|
+
export interface AnalyzeOptions {
|
|
35
|
+
/** Override default thresholds (e.g. from dare.config.json#refine). */
|
|
36
|
+
thresholds?: ComplexityThresholds;
|
|
37
|
+
/** Extra `depends_on` count from `dare-dag.yaml` (optional — caller resolves). */
|
|
38
|
+
dependsOnCount?: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Build a complexity report for a single task. Returns `null` if the spec
|
|
42
|
+
* can't be found, so the caller can produce a user-friendly error.
|
|
43
|
+
*/
|
|
44
|
+
export declare function analyzeTaskComplexity(taskId: string, projectRoot: string, options?: AnalyzeOptions): Promise<ComplexityReport | null>;
|
|
45
|
+
/**
|
|
46
|
+
* Produce a coarse split proposal. The algorithm:
|
|
47
|
+
* 1. Group files by top-level directory (e.g. `src/auth/*` vs `tests/*`
|
|
48
|
+
* vs `migrations/*`).
|
|
49
|
+
* 2. Each group becomes a candidate sub-task. If a group has more than
|
|
50
|
+
* `maxFilesPerSubtask` files, split it further alphabetically.
|
|
51
|
+
* 3. Generate suffixed ids: `task-034a`, `task-034b`, ...
|
|
52
|
+
*
|
|
53
|
+
* Intentionally not too clever — the IDE agent (via the `dare-refine` skill)
|
|
54
|
+
* is expected to refine this with semantic awareness. The CLI proposal is
|
|
55
|
+
* a sane default that gets it 70% of the way there.
|
|
56
|
+
*/
|
|
57
|
+
export declare function proposeSplit(taskId: string, files: string[], options?: {
|
|
58
|
+
maxFilesPerSubtask?: number;
|
|
59
|
+
}): SplitProposal;
|
|
60
|
+
//# sourceMappingURL=complexity-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"complexity-analyzer.d.ts","sourceRoot":"","sources":["../../src/utils/complexity-analyzer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAGhB,aAAa,EACd,MAAM,0BAA0B,CAAC;AAIlC,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,kBAAkB,EAAE,oBAIhC,CAAC;AA+GF,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,oBAAyC,GACpD,eAAe,CAKjB;AAID,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,kFAAkF;IAClF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAuFlC;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,GAAE;IAAE,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5C,aAAa,CAoDf"}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic complexity heuristic for `dare refine`.
|
|
3
|
+
*
|
|
4
|
+
* Scans a task spec for signals that correlate with implementation effort
|
|
5
|
+
* and aggregates them into a single score → bucket. The breakdown is
|
|
6
|
+
* preserved so the CLI / agent can explain *why* a task scored high.
|
|
7
|
+
*
|
|
8
|
+
* Signals (weights tuned empirically — start conservative; bump as we learn):
|
|
9
|
+
* - Files to create/modify (1 each, cap at 10)
|
|
10
|
+
* - Public functions/endpoints declared in spec (1.5 each, cap at 10)
|
|
11
|
+
* - Test cases listed (0.5 each, cap at 8)
|
|
12
|
+
* - Inbound dependencies in dare-dag.yaml (0.5 each, no cap)
|
|
13
|
+
* - "Heavy" keywords in prompt/spec (+2 each: refactor, migrate, integrate,
|
|
14
|
+
* multiple, audit, replace, rewrite, parallelize, cross-cutting)
|
|
15
|
+
* - HIGH complexity declared by author (+3 baseline)
|
|
16
|
+
*
|
|
17
|
+
* Buckets:
|
|
18
|
+
* 0–5 → LOW
|
|
19
|
+
* 6–12 → MED
|
|
20
|
+
* 13–20 → HIGH ← recommends split
|
|
21
|
+
* 21+ → CRITICAL ← strongly recommends split
|
|
22
|
+
*
|
|
23
|
+
* The thresholds are tunable via `dare.config.json#refine.thresholds` (see
|
|
24
|
+
* Frente 4) — defaults below.
|
|
25
|
+
*/
|
|
26
|
+
import fs from 'fs-extra';
|
|
27
|
+
import path from 'path';
|
|
28
|
+
import { findSpecFile, parseFilesFromSpec } from './ReviewRunner.js';
|
|
29
|
+
export const DEFAULT_THRESHOLDS = {
|
|
30
|
+
low: 5,
|
|
31
|
+
med: 12,
|
|
32
|
+
high: 20,
|
|
33
|
+
};
|
|
34
|
+
/** Maximum contribution from any single signal — keeps the score bounded. */
|
|
35
|
+
const SIGNAL_CAPS = {
|
|
36
|
+
files: 10,
|
|
37
|
+
functions: 10,
|
|
38
|
+
tests: 8,
|
|
39
|
+
};
|
|
40
|
+
/** Weights per occurrence. */
|
|
41
|
+
const WEIGHTS = {
|
|
42
|
+
perFile: 1,
|
|
43
|
+
perFunction: 1.5,
|
|
44
|
+
perTest: 0.5,
|
|
45
|
+
perDependency: 0.5,
|
|
46
|
+
heavyKeyword: 2,
|
|
47
|
+
authorDeclaredHigh: 3,
|
|
48
|
+
};
|
|
49
|
+
/** Keywords that historically correlate with "this is bigger than it looks". */
|
|
50
|
+
const HEAVY_KEYWORDS = [
|
|
51
|
+
'refactor',
|
|
52
|
+
'refatorar',
|
|
53
|
+
'migrate',
|
|
54
|
+
'migrar',
|
|
55
|
+
'migração',
|
|
56
|
+
'integrate',
|
|
57
|
+
'integrar',
|
|
58
|
+
'integração',
|
|
59
|
+
'multiple',
|
|
60
|
+
'múltiplos',
|
|
61
|
+
'audit',
|
|
62
|
+
'auditar',
|
|
63
|
+
'replace',
|
|
64
|
+
'substituir',
|
|
65
|
+
'rewrite',
|
|
66
|
+
'reescrever',
|
|
67
|
+
'parallelize',
|
|
68
|
+
'paralelizar',
|
|
69
|
+
'cross-cutting',
|
|
70
|
+
'orchestrate',
|
|
71
|
+
'orquestrar',
|
|
72
|
+
];
|
|
73
|
+
// ── Signal extractors ────────────────────────────────────────────────────────
|
|
74
|
+
/**
|
|
75
|
+
* Count public functions/endpoints declared in the spec. We look at:
|
|
76
|
+
* - "Implementar `POST /…`" style mentions
|
|
77
|
+
* - "função `name()`" / "function `name()`"
|
|
78
|
+
* - Code-fence assinaturas (`fn x() -> ...`, `function x()`, `def x()`)
|
|
79
|
+
*
|
|
80
|
+
* Imperfect, but consistent — the test for refinement is "does this slope
|
|
81
|
+
* up monotonically with effort?", not "is this exact?".
|
|
82
|
+
*/
|
|
83
|
+
function countDeclaredFunctions(specMarkdown) {
|
|
84
|
+
const patterns = [
|
|
85
|
+
// HTTP verbs inside backticks: `POST /auth/login`, `GET /users/:id`
|
|
86
|
+
/`(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s+\/[^`]+`/gi,
|
|
87
|
+
// Function-like in backticks: `name()`, `name(arg: Type)`
|
|
88
|
+
/`\w+\s*\([^)]*\)`/g,
|
|
89
|
+
// Inline `fn x(...)` / `function x(...)` / `def x(...)` / `func x(...)`
|
|
90
|
+
/\b(function|fn|func|def|method)\s+\w+\s*\(/g,
|
|
91
|
+
];
|
|
92
|
+
let total = 0;
|
|
93
|
+
for (const re of patterns) {
|
|
94
|
+
const matches = specMarkdown.match(re);
|
|
95
|
+
if (matches)
|
|
96
|
+
total += matches.length;
|
|
97
|
+
}
|
|
98
|
+
// Deduplicate-ish: a single endpoint may match both verb pattern and code-block.
|
|
99
|
+
// Halve to avoid double-counting; floor so a single hit still counts as 1.
|
|
100
|
+
return Math.max(1, Math.floor(total / 2));
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Count test cases listed in the spec. We look at checkbox-style entries
|
|
104
|
+
* under the "Testes" / "Testing" section and `should_*` / `it(...)` names.
|
|
105
|
+
*/
|
|
106
|
+
function countDeclaredTests(specMarkdown) {
|
|
107
|
+
const patterns = [
|
|
108
|
+
/^\s*-\s*\[\s*\]\s*(Teste|Test)\b/gim,
|
|
109
|
+
/\bshould_[a-z_]+/g,
|
|
110
|
+
/\bit\(['"]/g,
|
|
111
|
+
];
|
|
112
|
+
let total = 0;
|
|
113
|
+
for (const re of patterns) {
|
|
114
|
+
const matches = specMarkdown.match(re);
|
|
115
|
+
if (matches)
|
|
116
|
+
total += matches.length;
|
|
117
|
+
}
|
|
118
|
+
return total;
|
|
119
|
+
}
|
|
120
|
+
/** Count occurrences of heavy keywords (case-insensitive, word-boundary). */
|
|
121
|
+
function countHeavyKeywords(specMarkdown) {
|
|
122
|
+
const lower = specMarkdown.toLowerCase();
|
|
123
|
+
let total = 0;
|
|
124
|
+
for (const kw of HEAVY_KEYWORDS) {
|
|
125
|
+
const re = new RegExp(`\\b${kw.toLowerCase()}\\b`, 'g');
|
|
126
|
+
const matches = lower.match(re);
|
|
127
|
+
if (matches)
|
|
128
|
+
total += matches.length;
|
|
129
|
+
}
|
|
130
|
+
return total;
|
|
131
|
+
}
|
|
132
|
+
/** Parse `**Complexidade:** HIGH` or similar from the spec header. */
|
|
133
|
+
function authorDeclaredHigh(specMarkdown) {
|
|
134
|
+
return /\*\*Complexidade:\*\*\s*HIGH/i.test(specMarkdown);
|
|
135
|
+
}
|
|
136
|
+
// ── Bucket selection ─────────────────────────────────────────────────────────
|
|
137
|
+
export function levelFromScore(score, thresholds = DEFAULT_THRESHOLDS) {
|
|
138
|
+
if (score <= thresholds.low)
|
|
139
|
+
return 'LOW';
|
|
140
|
+
if (score <= thresholds.med)
|
|
141
|
+
return 'MED';
|
|
142
|
+
if (score <= thresholds.high)
|
|
143
|
+
return 'HIGH';
|
|
144
|
+
return 'CRITICAL';
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Build a complexity report for a single task. Returns `null` if the spec
|
|
148
|
+
* can't be found, so the caller can produce a user-friendly error.
|
|
149
|
+
*/
|
|
150
|
+
export async function analyzeTaskComplexity(taskId, projectRoot, options = {}) {
|
|
151
|
+
const specPath = await findSpecFile(projectRoot, taskId);
|
|
152
|
+
if (!specPath) {
|
|
153
|
+
return {
|
|
154
|
+
taskId,
|
|
155
|
+
specPath: null,
|
|
156
|
+
score: 0,
|
|
157
|
+
level: 'LOW',
|
|
158
|
+
recommendsSplit: false,
|
|
159
|
+
signals: [
|
|
160
|
+
{ kind: 'no-spec', weight: 0, detail: 'Spec não encontrada — refinamento ignorado.' },
|
|
161
|
+
],
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
const md = await fs.readFile(specPath, 'utf-8');
|
|
165
|
+
const projectRelSpec = path.relative(projectRoot, specPath).replace(/\\/g, '/');
|
|
166
|
+
const fileCount = parseFilesFromSpec(md).length;
|
|
167
|
+
const fnCount = countDeclaredFunctions(md);
|
|
168
|
+
const testCount = countDeclaredTests(md);
|
|
169
|
+
const kwCount = countHeavyKeywords(md);
|
|
170
|
+
const deps = options.dependsOnCount ?? 0;
|
|
171
|
+
const high = authorDeclaredHigh(md);
|
|
172
|
+
const signals = [];
|
|
173
|
+
if (fileCount > 0) {
|
|
174
|
+
const w = Math.min(fileCount, SIGNAL_CAPS.files) * WEIGHTS.perFile;
|
|
175
|
+
signals.push({
|
|
176
|
+
kind: 'files',
|
|
177
|
+
weight: w,
|
|
178
|
+
detail: `${fileCount} arquivo(s) a criar/modificar`,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
if (fnCount > 0) {
|
|
182
|
+
const w = Math.min(fnCount, SIGNAL_CAPS.functions) * WEIGHTS.perFunction;
|
|
183
|
+
signals.push({
|
|
184
|
+
kind: 'functions',
|
|
185
|
+
weight: w,
|
|
186
|
+
detail: `${fnCount} função(ões)/endpoint(s) público(s)`,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
if (testCount > 0) {
|
|
190
|
+
const w = Math.min(testCount, SIGNAL_CAPS.tests) * WEIGHTS.perTest;
|
|
191
|
+
signals.push({
|
|
192
|
+
kind: 'tests',
|
|
193
|
+
weight: w,
|
|
194
|
+
detail: `${testCount} teste(s) declarado(s)`,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
if (deps > 0) {
|
|
198
|
+
signals.push({
|
|
199
|
+
kind: 'dependencies',
|
|
200
|
+
weight: deps * WEIGHTS.perDependency,
|
|
201
|
+
detail: `${deps} dependência(s) (depends_on)`,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
if (kwCount > 0) {
|
|
205
|
+
signals.push({
|
|
206
|
+
kind: 'keywords',
|
|
207
|
+
weight: kwCount * WEIGHTS.heavyKeyword,
|
|
208
|
+
detail: `${kwCount} palavra-chave(s) "pesada(s)" (refactor/migrate/integrate/...)`,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
if (high) {
|
|
212
|
+
signals.push({
|
|
213
|
+
kind: 'author-high',
|
|
214
|
+
weight: WEIGHTS.authorDeclaredHigh,
|
|
215
|
+
detail: 'Spec já declarada como HIGH pelo autor',
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
signals.sort((a, b) => b.weight - a.weight);
|
|
219
|
+
const score = signals.reduce((acc, s) => acc + s.weight, 0);
|
|
220
|
+
const level = levelFromScore(score, options.thresholds ?? DEFAULT_THRESHOLDS);
|
|
221
|
+
const recommendsSplit = level === 'HIGH' || level === 'CRITICAL';
|
|
222
|
+
return {
|
|
223
|
+
taskId,
|
|
224
|
+
specPath: projectRelSpec,
|
|
225
|
+
score,
|
|
226
|
+
level,
|
|
227
|
+
recommendsSplit,
|
|
228
|
+
signals,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
// ── Split proposal ───────────────────────────────────────────────────────────
|
|
232
|
+
/**
|
|
233
|
+
* Produce a coarse split proposal. The algorithm:
|
|
234
|
+
* 1. Group files by top-level directory (e.g. `src/auth/*` vs `tests/*`
|
|
235
|
+
* vs `migrations/*`).
|
|
236
|
+
* 2. Each group becomes a candidate sub-task. If a group has more than
|
|
237
|
+
* `maxFilesPerSubtask` files, split it further alphabetically.
|
|
238
|
+
* 3. Generate suffixed ids: `task-034a`, `task-034b`, ...
|
|
239
|
+
*
|
|
240
|
+
* Intentionally not too clever — the IDE agent (via the `dare-refine` skill)
|
|
241
|
+
* is expected to refine this with semantic awareness. The CLI proposal is
|
|
242
|
+
* a sane default that gets it 70% of the way there.
|
|
243
|
+
*/
|
|
244
|
+
export function proposeSplit(taskId, files, options = {}) {
|
|
245
|
+
const maxFiles = options.maxFilesPerSubtask ?? 4;
|
|
246
|
+
if (files.length === 0) {
|
|
247
|
+
return {
|
|
248
|
+
originalTaskId: taskId,
|
|
249
|
+
subtasks: [],
|
|
250
|
+
notes: 'Nenhum arquivo listado na spec — split automático impossível. ' +
|
|
251
|
+
'Adicione a tabela "ARQUIVOS A CRIAR / MODIFICAR" ou rode `/dare-refine <id>` para o agente sugerir.',
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
// Group by top-level directory (or first 2 segments if same root).
|
|
255
|
+
const groups = new Map();
|
|
256
|
+
for (const f of files) {
|
|
257
|
+
const parts = f.split('/');
|
|
258
|
+
const key = parts.length >= 2 ? `${parts[0]}/${parts[1]}` : parts[0];
|
|
259
|
+
if (!groups.has(key))
|
|
260
|
+
groups.set(key, []);
|
|
261
|
+
groups.get(key).push(f);
|
|
262
|
+
}
|
|
263
|
+
const subtasks = [];
|
|
264
|
+
let suffixIdx = 0;
|
|
265
|
+
for (const [groupKey, groupFiles] of groups) {
|
|
266
|
+
// Split overlarge groups alphabetically.
|
|
267
|
+
const sorted = [...groupFiles].sort();
|
|
268
|
+
const chunks = [];
|
|
269
|
+
for (let i = 0; i < sorted.length; i += maxFiles) {
|
|
270
|
+
chunks.push(sorted.slice(i, i + maxFiles));
|
|
271
|
+
}
|
|
272
|
+
for (const chunk of chunks) {
|
|
273
|
+
const suffix = String.fromCharCode(97 + suffixIdx); // a, b, c, ...
|
|
274
|
+
suffixIdx++;
|
|
275
|
+
subtasks.push({
|
|
276
|
+
id: `${taskId}${suffix}`,
|
|
277
|
+
title: `${taskId}${suffix}: ${groupKey}`,
|
|
278
|
+
files: chunk,
|
|
279
|
+
rationale: `Slice de ${groupKey} (${chunk.length} arquivo(s)) — cabe em uma conversa.`,
|
|
280
|
+
estimatedLevel: chunk.length >= maxFiles ? 'MED' : 'LOW',
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return {
|
|
285
|
+
originalTaskId: taskId,
|
|
286
|
+
subtasks,
|
|
287
|
+
notes: `Split proposto em ${subtasks.length} sub-task(s) agrupando por diretório raiz. ` +
|
|
288
|
+
`Cada slice fica ≤ ${maxFiles} arquivos. Revise: o agrupamento por diretório é uma heurística — ` +
|
|
289
|
+
`o agente pode reorganizar se o domínio sugerir slices melhores.`,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=complexity-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"complexity-analyzer.js","sourceRoot":"","sources":["../../src/utils/complexity-analyzer.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"}
|