@wrongstack/sdd 0.284.1 → 0.286.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/dist/auto-executor.d.ts +89 -0
- package/dist/auto-executor.d.ts.map +1 -0
- package/dist/board-types.d.ts +144 -0
- package/dist/board-types.d.ts.map +1 -0
- package/dist/conflict-resolver.d.ts +45 -0
- package/dist/conflict-resolver.d.ts.map +1 -0
- package/dist/critical-path.d.ts +36 -0
- package/dist/critical-path.d.ts.map +1 -0
- package/dist/decompose-task.d.ts +20 -0
- package/dist/decompose-task.d.ts.map +1 -0
- package/dist/index.d.ts +26 -1864
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +192 -76
- package/dist/index.js.map +7 -1
- package/dist/sdd-board-projector.d.ts +83 -0
- package/dist/sdd-board-projector.d.ts.map +1 -0
- package/dist/sdd-board-store.d.ts +59 -0
- package/dist/sdd-board-store.d.ts.map +1 -0
- package/dist/sdd-interview-driver.d.ts +131 -0
- package/dist/sdd-interview-driver.d.ts.map +1 -0
- package/dist/sdd-lifecycle.d.ts +146 -0
- package/dist/sdd-lifecycle.d.ts.map +1 -0
- package/dist/sdd-parallel-run.d.ts +427 -0
- package/dist/sdd-parallel-run.d.ts.map +1 -0
- package/dist/sdd-run-registry.d.ts +68 -0
- package/dist/sdd-run-registry.d.ts.map +1 -0
- package/dist/sdd-supervisor.d.ts +52 -0
- package/dist/sdd-supervisor.d.ts.map +1 -0
- package/dist/sdd-task-decomposer.d.ts +89 -0
- package/dist/sdd-task-decomposer.d.ts.map +1 -0
- package/dist/spec-builder.d.ts +139 -0
- package/dist/spec-builder.d.ts.map +1 -0
- package/dist/spec-parser.d.ts +14 -0
- package/dist/spec-parser.d.ts.map +1 -0
- package/dist/spec-store.d.ts +36 -0
- package/dist/spec-store.d.ts.map +1 -0
- package/dist/spec-templates.d.ts +22 -0
- package/dist/spec-templates.d.ts.map +1 -0
- package/dist/spec-versioning.d.ts +49 -0
- package/dist/spec-versioning.d.ts.map +1 -0
- package/dist/start-sdd-run.d.ts +67 -0
- package/dist/start-sdd-run.d.ts.map +1 -0
- package/dist/task-flow.d.ts +99 -0
- package/dist/task-flow.d.ts.map +1 -0
- package/dist/task-generator.d.ts +39 -0
- package/dist/task-generator.d.ts.map +1 -0
- package/dist/task-graph-store.d.ts +33 -0
- package/dist/task-graph-store.d.ts.map +1 -0
- package/dist/task-tracker.d.ts +2 -0
- package/dist/task-tracker.d.ts.map +1 -0
- package/dist/task-visualizer.d.ts +26 -0
- package/dist/task-visualizer.d.ts.map +1 -0
- package/dist/verify-task.d.ts +23 -0
- package/dist/verify-task.d.ts.map +1 -0
- package/package.json +4 -5
package/dist/index.js
CHANGED
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
import { SddError, ERROR_CODES, ensureDir, atomicWrite, toErrorMessage, assignNickname, expectDefined, WorktreeManager, truncate, assertNever, parseModelRef, renderInstructionTemplate, readBundledInstructionText } from '@wrongstack/core';
|
|
2
|
-
import { DefaultTaskStore, TaskTracker } from '@wrongstack/core/tasking';
|
|
3
|
-
export { DefaultTaskStore, TaskTracker } from '@wrongstack/core/tasking';
|
|
4
|
-
import * as fsp3 from 'fs/promises';
|
|
5
|
-
import { readFile, writeFile } from 'fs/promises';
|
|
6
|
-
import * as path3 from 'path';
|
|
7
|
-
import { isAbsolute, join } from 'path';
|
|
8
|
-
import { randomUUID } from 'crypto';
|
|
9
|
-
import { computeTaskProgress, topologicalSort } from '@wrongstack/core/types';
|
|
10
|
-
import { DefaultMultiAgentCoordinator, withDisabledToolFiltering, makeAgentSubagentRunner } from '@wrongstack/core/coordination';
|
|
11
|
-
import { spawn } from 'child_process';
|
|
12
|
-
|
|
13
1
|
// src/spec-parser.ts
|
|
14
2
|
var SpecParser = class {
|
|
15
3
|
parse(content) {
|
|
@@ -237,6 +225,8 @@ var SpecParser = class {
|
|
|
237
225
|
};
|
|
238
226
|
}
|
|
239
227
|
};
|
|
228
|
+
|
|
229
|
+
// src/task-generator.ts
|
|
240
230
|
function extractVerificationCommand(criteria) {
|
|
241
231
|
const marker = /^\s*(?:\$\s+|(?:run|verify|cmd)\s*:\s*)(.+\S)\s*$/i;
|
|
242
232
|
for (const c of criteria) {
|
|
@@ -273,6 +263,16 @@ var TaskGenerator = class {
|
|
|
273
263
|
}
|
|
274
264
|
}
|
|
275
265
|
};
|
|
266
|
+
|
|
267
|
+
// src/index.ts
|
|
268
|
+
import {
|
|
269
|
+
TaskTracker as TaskTracker3,
|
|
270
|
+
DefaultTaskStore as DefaultTaskStore3
|
|
271
|
+
} from "@wrongstack/core/tasking";
|
|
272
|
+
|
|
273
|
+
// src/task-flow.ts
|
|
274
|
+
import { SddError, ERROR_CODES } from "@wrongstack/core";
|
|
275
|
+
import { DefaultTaskStore, TaskTracker } from "@wrongstack/core/tasking";
|
|
276
276
|
var TaskFlow = class {
|
|
277
277
|
constructor(opts) {
|
|
278
278
|
this.opts = opts;
|
|
@@ -459,12 +459,18 @@ var SpecDrivenDev = class {
|
|
|
459
459
|
}));
|
|
460
460
|
}
|
|
461
461
|
};
|
|
462
|
+
|
|
463
|
+
// src/spec-store.ts
|
|
464
|
+
import * as fsp from "node:fs/promises";
|
|
465
|
+
import * as path from "node:path";
|
|
466
|
+
import { randomUUID } from "node:crypto";
|
|
467
|
+
import { atomicWrite, ensureDir } from "@wrongstack/core";
|
|
462
468
|
var SpecStore = class {
|
|
463
469
|
baseDir;
|
|
464
470
|
indexPath;
|
|
465
471
|
constructor(opts) {
|
|
466
472
|
this.baseDir = opts.baseDir;
|
|
467
|
-
this.indexPath =
|
|
473
|
+
this.indexPath = path.join(this.baseDir, "_index.json");
|
|
468
474
|
}
|
|
469
475
|
async save(spec) {
|
|
470
476
|
await ensureDir(this.baseDir);
|
|
@@ -474,7 +480,7 @@ var SpecStore = class {
|
|
|
474
480
|
}
|
|
475
481
|
async load(id) {
|
|
476
482
|
try {
|
|
477
|
-
const raw = await
|
|
483
|
+
const raw = await fsp.readFile(this.filePath(id), "utf8");
|
|
478
484
|
return JSON.parse(raw);
|
|
479
485
|
} catch {
|
|
480
486
|
return null;
|
|
@@ -486,7 +492,7 @@ var SpecStore = class {
|
|
|
486
492
|
}
|
|
487
493
|
async delete(id) {
|
|
488
494
|
try {
|
|
489
|
-
await
|
|
495
|
+
await fsp.unlink(this.filePath(id));
|
|
490
496
|
await this.removeFromIndex(id);
|
|
491
497
|
return true;
|
|
492
498
|
} catch {
|
|
@@ -495,7 +501,7 @@ var SpecStore = class {
|
|
|
495
501
|
}
|
|
496
502
|
async exists(id) {
|
|
497
503
|
try {
|
|
498
|
-
await
|
|
504
|
+
await fsp.access(this.filePath(id));
|
|
499
505
|
return true;
|
|
500
506
|
} catch {
|
|
501
507
|
return false;
|
|
@@ -533,11 +539,11 @@ var SpecStore = class {
|
|
|
533
539
|
return updated;
|
|
534
540
|
}
|
|
535
541
|
filePath(id) {
|
|
536
|
-
return
|
|
542
|
+
return path.join(this.baseDir, `${id}.json`);
|
|
537
543
|
}
|
|
538
544
|
async readIndex() {
|
|
539
545
|
try {
|
|
540
|
-
const raw = await
|
|
546
|
+
const raw = await fsp.readFile(this.indexPath, "utf8");
|
|
541
547
|
const parsed = JSON.parse(raw);
|
|
542
548
|
if (parsed?.version === 1) return parsed;
|
|
543
549
|
} catch {
|
|
@@ -568,6 +574,11 @@ var SpecStore = class {
|
|
|
568
574
|
await atomicWrite(this.indexPath, JSON.stringify(index, null, 2), { mode: 384 });
|
|
569
575
|
}
|
|
570
576
|
};
|
|
577
|
+
|
|
578
|
+
// src/task-graph-store.ts
|
|
579
|
+
import * as fsp2 from "node:fs/promises";
|
|
580
|
+
import * as path2 from "node:path";
|
|
581
|
+
import { atomicWrite as atomicWrite2, ensureDir as ensureDir2 } from "@wrongstack/core";
|
|
571
582
|
function graphToJSON(graph) {
|
|
572
583
|
const serialisable = {
|
|
573
584
|
...graph,
|
|
@@ -587,17 +598,17 @@ var TaskGraphStore = class {
|
|
|
587
598
|
indexPath;
|
|
588
599
|
constructor(opts) {
|
|
589
600
|
this.baseDir = opts.baseDir;
|
|
590
|
-
this.indexPath =
|
|
601
|
+
this.indexPath = path2.join(this.baseDir, "_index.json");
|
|
591
602
|
}
|
|
592
603
|
async save(graph) {
|
|
593
|
-
await
|
|
604
|
+
await ensureDir2(this.baseDir);
|
|
594
605
|
const filePath = this.filePath(graph.id);
|
|
595
|
-
await
|
|
606
|
+
await atomicWrite2(filePath, graphToJSON(graph), { mode: 384 });
|
|
596
607
|
await this.updateIndex(graph);
|
|
597
608
|
}
|
|
598
609
|
async load(id) {
|
|
599
610
|
try {
|
|
600
|
-
const raw = await
|
|
611
|
+
const raw = await fsp2.readFile(this.filePath(id), "utf8");
|
|
601
612
|
return graphFromJSON(raw);
|
|
602
613
|
} catch {
|
|
603
614
|
return null;
|
|
@@ -609,7 +620,7 @@ var TaskGraphStore = class {
|
|
|
609
620
|
}
|
|
610
621
|
async delete(id) {
|
|
611
622
|
try {
|
|
612
|
-
await
|
|
623
|
+
await fsp2.unlink(this.filePath(id));
|
|
613
624
|
await this.removeFromIndex(id);
|
|
614
625
|
return true;
|
|
615
626
|
} catch {
|
|
@@ -618,18 +629,18 @@ var TaskGraphStore = class {
|
|
|
618
629
|
}
|
|
619
630
|
async exists(id) {
|
|
620
631
|
try {
|
|
621
|
-
await
|
|
632
|
+
await fsp2.access(this.filePath(id));
|
|
622
633
|
return true;
|
|
623
634
|
} catch {
|
|
624
635
|
return false;
|
|
625
636
|
}
|
|
626
637
|
}
|
|
627
638
|
filePath(id) {
|
|
628
|
-
return
|
|
639
|
+
return path2.join(this.baseDir, `${id}.json`);
|
|
629
640
|
}
|
|
630
641
|
async readIndex() {
|
|
631
642
|
try {
|
|
632
|
-
const raw = await
|
|
643
|
+
const raw = await fsp2.readFile(this.indexPath, "utf8");
|
|
633
644
|
const parsed = JSON.parse(raw);
|
|
634
645
|
if (parsed?.version === 1) return parsed;
|
|
635
646
|
} catch {
|
|
@@ -656,14 +667,17 @@ var TaskGraphStore = class {
|
|
|
656
667
|
} else {
|
|
657
668
|
index.entries.push(entry);
|
|
658
669
|
}
|
|
659
|
-
await
|
|
670
|
+
await atomicWrite2(this.indexPath, JSON.stringify(index, null, 2), { mode: 384 });
|
|
660
671
|
}
|
|
661
672
|
async removeFromIndex(id) {
|
|
662
673
|
const index = await this.readIndex();
|
|
663
674
|
index.entries = index.entries.filter((e) => e.id !== id);
|
|
664
|
-
await
|
|
675
|
+
await atomicWrite2(this.indexPath, JSON.stringify(index, null, 2), { mode: 384 });
|
|
665
676
|
}
|
|
666
677
|
};
|
|
678
|
+
|
|
679
|
+
// src/board-types.ts
|
|
680
|
+
import { computeTaskProgress } from "@wrongstack/core/types";
|
|
667
681
|
function shortIdMap(graph) {
|
|
668
682
|
const nodes = Array.from(graph.nodes.values()).sort((a, b) => a.createdAt - b.createdAt);
|
|
669
683
|
const m = /* @__PURE__ */ new Map();
|
|
@@ -751,6 +765,11 @@ function buildBoardSnapshot(graph, run, now) {
|
|
|
751
765
|
mergedCommits: run.mergedCommits?.length ? run.mergedCommits : void 0
|
|
752
766
|
};
|
|
753
767
|
}
|
|
768
|
+
|
|
769
|
+
// src/sdd-board-store.ts
|
|
770
|
+
import * as fsp3 from "node:fs/promises";
|
|
771
|
+
import * as path3 from "node:path";
|
|
772
|
+
import { atomicWrite as atomicWrite3, ensureDir as ensureDir3 } from "@wrongstack/core";
|
|
754
773
|
var SddBoardStore = class {
|
|
755
774
|
baseDir;
|
|
756
775
|
indexPath;
|
|
@@ -768,8 +787,8 @@ var SddBoardStore = class {
|
|
|
768
787
|
return path3.join(this.baseDir, `${this.safe(runId)}.control.jsonl`);
|
|
769
788
|
}
|
|
770
789
|
async saveSnapshot(snapshot) {
|
|
771
|
-
await
|
|
772
|
-
await
|
|
790
|
+
await ensureDir3(this.baseDir);
|
|
791
|
+
await atomicWrite3(this.snapshotPath(snapshot.runId), JSON.stringify(snapshot, null, 2), {
|
|
773
792
|
mode: 384
|
|
774
793
|
});
|
|
775
794
|
await this.updateIndex(snapshot);
|
|
@@ -793,7 +812,7 @@ var SddBoardStore = class {
|
|
|
793
812
|
/** Append one line to the board's JSONL event log (best-effort, never throws). */
|
|
794
813
|
async appendEvent(runId, event) {
|
|
795
814
|
try {
|
|
796
|
-
await
|
|
815
|
+
await ensureDir3(this.baseDir);
|
|
797
816
|
await fsp3.appendFile(this.eventsPath(runId), `${JSON.stringify(event)}
|
|
798
817
|
`, { mode: 384 });
|
|
799
818
|
} catch {
|
|
@@ -801,7 +820,7 @@ var SddBoardStore = class {
|
|
|
801
820
|
}
|
|
802
821
|
/** Append a control command (used by readers to steer a CLI-owned run). */
|
|
803
822
|
async appendControl(runId, command) {
|
|
804
|
-
await
|
|
823
|
+
await ensureDir3(this.baseDir);
|
|
805
824
|
await fsp3.appendFile(this.controlPath(runId), `${JSON.stringify(command)}
|
|
806
825
|
`, { mode: 384 });
|
|
807
826
|
}
|
|
@@ -861,12 +880,12 @@ var SddBoardStore = class {
|
|
|
861
880
|
const idx = index.entries.findIndex((e) => e.runId === snapshot.runId);
|
|
862
881
|
if (idx >= 0) index.entries[idx] = entry;
|
|
863
882
|
else index.entries.push(entry);
|
|
864
|
-
await
|
|
883
|
+
await atomicWrite3(this.indexPath, JSON.stringify(index, null, 2), { mode: 384 });
|
|
865
884
|
}
|
|
866
885
|
async removeFromIndex(runId) {
|
|
867
886
|
const index = await this.readIndex();
|
|
868
887
|
index.entries = index.entries.filter((e) => e.runId !== runId);
|
|
869
|
-
await
|
|
888
|
+
await atomicWrite3(this.indexPath, JSON.stringify(index, null, 2), { mode: 384 });
|
|
870
889
|
}
|
|
871
890
|
};
|
|
872
891
|
|
|
@@ -1143,6 +1162,11 @@ var SddRunRegistry = class {
|
|
|
1143
1162
|
return this.current;
|
|
1144
1163
|
}
|
|
1145
1164
|
};
|
|
1165
|
+
|
|
1166
|
+
// src/spec-builder.ts
|
|
1167
|
+
import { expectDefined } from "@wrongstack/core";
|
|
1168
|
+
import { toErrorMessage } from "@wrongstack/core";
|
|
1169
|
+
import { SddError as SddError2, ERROR_CODES as ERROR_CODES2 } from "@wrongstack/core";
|
|
1146
1170
|
function buildQuestioningPrompt(session, min, max) {
|
|
1147
1171
|
const answered = session.answers.length;
|
|
1148
1172
|
const remaining = Math.max(0, min - answered);
|
|
@@ -1362,9 +1386,9 @@ var AISpecBuilder = class {
|
|
|
1362
1386
|
async saveSession() {
|
|
1363
1387
|
if (!this.sessionPath) return;
|
|
1364
1388
|
try {
|
|
1365
|
-
const fsp5 = await import(
|
|
1366
|
-
const path4 = await import(
|
|
1367
|
-
const { atomicWrite: atomicWrite4 } = await import(
|
|
1389
|
+
const fsp5 = await import("node:fs/promises");
|
|
1390
|
+
const path4 = await import("node:path");
|
|
1391
|
+
const { atomicWrite: atomicWrite4 } = await import("@wrongstack/core");
|
|
1368
1392
|
await fsp5.mkdir(path4.dirname(this.sessionPath), { recursive: true });
|
|
1369
1393
|
await atomicWrite4(this.sessionPath, JSON.stringify(this.session, null, 2));
|
|
1370
1394
|
} catch {
|
|
@@ -1374,7 +1398,7 @@ var AISpecBuilder = class {
|
|
|
1374
1398
|
async loadSession() {
|
|
1375
1399
|
if (!this.sessionPath) return false;
|
|
1376
1400
|
try {
|
|
1377
|
-
const fsp5 = await import(
|
|
1401
|
+
const fsp5 = await import("node:fs/promises");
|
|
1378
1402
|
const raw = await fsp5.readFile(this.sessionPath, "utf8");
|
|
1379
1403
|
const loaded = JSON.parse(raw);
|
|
1380
1404
|
if (loaded?.id && loaded?.phase && loaded?.title) {
|
|
@@ -1389,7 +1413,7 @@ var AISpecBuilder = class {
|
|
|
1389
1413
|
async deleteSession() {
|
|
1390
1414
|
if (!this.sessionPath) return;
|
|
1391
1415
|
try {
|
|
1392
|
-
const fsp5 = await import(
|
|
1416
|
+
const fsp5 = await import("node:fs/promises");
|
|
1393
1417
|
await fsp5.unlink(this.sessionPath);
|
|
1394
1418
|
} catch {
|
|
1395
1419
|
}
|
|
@@ -1491,9 +1515,9 @@ var AISpecBuilder = class {
|
|
|
1491
1515
|
switch (this.session.phase) {
|
|
1492
1516
|
case "questioning":
|
|
1493
1517
|
if (!this.session.spec) {
|
|
1494
|
-
throw new
|
|
1518
|
+
throw new SddError2({
|
|
1495
1519
|
message: "Cannot approve: no spec generated yet.",
|
|
1496
|
-
code:
|
|
1520
|
+
code: ERROR_CODES2.SDD_INVALID_STATE,
|
|
1497
1521
|
context: { phase: "questioning", sessionId: this.session.id }
|
|
1498
1522
|
});
|
|
1499
1523
|
}
|
|
@@ -1511,6 +1535,8 @@ var AISpecBuilder = class {
|
|
|
1511
1535
|
case "executing":
|
|
1512
1536
|
this.session.phase = "done";
|
|
1513
1537
|
break;
|
|
1538
|
+
case "done":
|
|
1539
|
+
break;
|
|
1514
1540
|
}
|
|
1515
1541
|
this.session.approved = true;
|
|
1516
1542
|
this.session.updatedAt = Date.now();
|
|
@@ -1553,9 +1579,9 @@ var AISpecBuilder = class {
|
|
|
1553
1579
|
*/
|
|
1554
1580
|
async saveSpec() {
|
|
1555
1581
|
if (!this.session.spec) {
|
|
1556
|
-
throw new
|
|
1582
|
+
throw new SddError2({
|
|
1557
1583
|
message: "No spec to save.",
|
|
1558
|
-
code:
|
|
1584
|
+
code: ERROR_CODES2.SDD_NOT_READY,
|
|
1559
1585
|
context: { sessionId: this.session.id }
|
|
1560
1586
|
});
|
|
1561
1587
|
}
|
|
@@ -1572,17 +1598,17 @@ var AISpecBuilder = class {
|
|
|
1572
1598
|
try {
|
|
1573
1599
|
parsed = JSON.parse(jsonStr);
|
|
1574
1600
|
} catch (e) {
|
|
1575
|
-
throw new
|
|
1601
|
+
throw new SddError2({
|
|
1576
1602
|
message: "Invalid JSON for spec",
|
|
1577
|
-
code:
|
|
1603
|
+
code: ERROR_CODES2.SDD_PARSE_FAILED,
|
|
1578
1604
|
cause: e,
|
|
1579
1605
|
context: { detail: e instanceof Error ? e.message : "parse error" }
|
|
1580
1606
|
});
|
|
1581
1607
|
}
|
|
1582
1608
|
if (!parsed || typeof parsed !== "object") {
|
|
1583
|
-
throw new
|
|
1609
|
+
throw new SddError2({
|
|
1584
1610
|
message: "Spec JSON must be an object",
|
|
1585
|
-
code:
|
|
1611
|
+
code: ERROR_CODES2.SDD_VALIDATION_FAILED,
|
|
1586
1612
|
context: { actualType: typeof parsed }
|
|
1587
1613
|
});
|
|
1588
1614
|
}
|
|
@@ -1591,9 +1617,9 @@ var AISpecBuilder = class {
|
|
|
1591
1617
|
const title = String(raw.title ?? this.session.title ?? "Untitled");
|
|
1592
1618
|
const overview = String(raw.overview ?? "");
|
|
1593
1619
|
if (!overview || overview === "undefined") {
|
|
1594
|
-
throw new
|
|
1620
|
+
throw new SddError2({
|
|
1595
1621
|
message: "Spec must have an overview",
|
|
1596
|
-
code:
|
|
1622
|
+
code: ERROR_CODES2.SDD_VALIDATION_FAILED,
|
|
1597
1623
|
context: { field: "overview", title }
|
|
1598
1624
|
});
|
|
1599
1625
|
}
|
|
@@ -1694,6 +1720,9 @@ var AISpecBuilder = class {
|
|
|
1694
1720
|
return null;
|
|
1695
1721
|
}
|
|
1696
1722
|
};
|
|
1723
|
+
|
|
1724
|
+
// src/sdd-interview-driver.ts
|
|
1725
|
+
import { TaskTracker as TaskTracker2, DefaultTaskStore as DefaultTaskStore2 } from "@wrongstack/core/tasking";
|
|
1697
1726
|
var SddInterviewDriver = class {
|
|
1698
1727
|
builder;
|
|
1699
1728
|
o;
|
|
@@ -1732,7 +1761,7 @@ var SddInterviewDriver = class {
|
|
|
1732
1761
|
const graph = await this.o.graphStore.load(graphId);
|
|
1733
1762
|
if (graph) {
|
|
1734
1763
|
this.graph = graph;
|
|
1735
|
-
const tracker = new
|
|
1764
|
+
const tracker = new TaskTracker2({ store: new DefaultTaskStore2() });
|
|
1736
1765
|
tracker.setGraph(graph);
|
|
1737
1766
|
this.tracker = tracker;
|
|
1738
1767
|
}
|
|
@@ -1814,7 +1843,7 @@ var SddInterviewDriver = class {
|
|
|
1814
1843
|
if (this.graph) return this.graph;
|
|
1815
1844
|
const spec = this.builder.getSession().spec;
|
|
1816
1845
|
if (!spec) return null;
|
|
1817
|
-
const tracker = new
|
|
1846
|
+
const tracker = new TaskTracker2({ store: new DefaultTaskStore2() });
|
|
1818
1847
|
const generator = new TaskGenerator({
|
|
1819
1848
|
taskTracker: tracker,
|
|
1820
1849
|
verificationFromAcceptance: process.env["WRONGSTACK_SDD_VERIFY_FROM_ACCEPTANCE"] === "1"
|
|
@@ -1908,7 +1937,7 @@ var SddInterviewDriver = class {
|
|
|
1908
1937
|
const spec = this.builder.getSession().spec;
|
|
1909
1938
|
if (!spec) return void 0;
|
|
1910
1939
|
if (!this.tracker || !this.graph) {
|
|
1911
|
-
const tracker = new
|
|
1940
|
+
const tracker = new TaskTracker2({ store: new DefaultTaskStore2() });
|
|
1912
1941
|
this.graph = await tracker.createGraph(spec.id, spec.title);
|
|
1913
1942
|
this.tracker = tracker;
|
|
1914
1943
|
}
|
|
@@ -1958,6 +1987,13 @@ function isExplanatoryText(text) {
|
|
|
1958
1987
|
return lower.startsWith("i'") || lower.startsWith("i will") || lower.startsWith("let me") || lower.startsWith("here's my") || lower.startsWith("here is my") || lower.startsWith("i'm going to") || lower.startsWith("first, let me") || lower.startsWith("sure") || lower.startsWith("of course") || lower.startsWith("okay") || lower.startsWith("ok,") || lower.startsWith("sounds good") || lower.startsWith("no problem") || text.split("\n").length < 3 && !text.includes(".");
|
|
1959
1988
|
}
|
|
1960
1989
|
|
|
1990
|
+
// src/sdd-parallel-run.ts
|
|
1991
|
+
import { expectDefined as expectDefined2 } from "@wrongstack/core";
|
|
1992
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
1993
|
+
import { makeAgentSubagentRunner, withDisabledToolFiltering, DefaultMultiAgentCoordinator } from "@wrongstack/core/coordination";
|
|
1994
|
+
import { assignNickname } from "@wrongstack/core";
|
|
1995
|
+
import { SddError as SddError3, ERROR_CODES as ERROR_CODES3 } from "@wrongstack/core";
|
|
1996
|
+
|
|
1961
1997
|
// src/sdd-task-decomposer.ts
|
|
1962
1998
|
var SddTaskDecomposer = class {
|
|
1963
1999
|
constructor(tracker, _graph, opts = {}) {
|
|
@@ -2074,7 +2110,7 @@ var SddParallelRun = class {
|
|
|
2074
2110
|
this.maxRetries = Math.max(0, opts.maxRetries ?? 3);
|
|
2075
2111
|
this.maxSupervisorEscalations = Math.max(0, opts.maxSupervisorEscalations ?? 2);
|
|
2076
2112
|
this.maxFailedSweeps = Math.max(0, opts.maxFailedRetrySweeps ?? 2);
|
|
2077
|
-
this.runId = opts.runId ?? `sdd-${
|
|
2113
|
+
this.runId = opts.runId ?? `sdd-${randomUUID2().slice(0, 8)}`;
|
|
2078
2114
|
this.events = opts.events;
|
|
2079
2115
|
this.sessionIdSource = opts.sessionId;
|
|
2080
2116
|
this.maxTotalWaves = opts.maxTotalWaves ?? opts.graph.nodes.size * (this.maxRetries + 2) + 10;
|
|
@@ -2555,7 +2591,7 @@ var SddParallelRun = class {
|
|
|
2555
2591
|
// -------------------------------------------------------------------
|
|
2556
2592
|
buildCoordinator() {
|
|
2557
2593
|
const config = {
|
|
2558
|
-
coordinatorId: `sdd-parallel-${
|
|
2594
|
+
coordinatorId: `sdd-parallel-${randomUUID2().slice(0, 8)}`,
|
|
2559
2595
|
maxConcurrent: this.slots,
|
|
2560
2596
|
doneCondition: { type: "all_tasks_done" },
|
|
2561
2597
|
// Default budget guard for every spawned worker: idle reaper (resets on
|
|
@@ -2619,13 +2655,13 @@ var SddParallelRun = class {
|
|
|
2619
2655
|
}
|
|
2620
2656
|
this.opts.tracker.updateNodeStatus(taskId, "in_progress");
|
|
2621
2657
|
await this.allocateWorktrees([task]);
|
|
2622
|
-
if (!this.coordinator) throw new
|
|
2658
|
+
if (!this.coordinator) throw new SddError3({
|
|
2623
2659
|
message: "SDD parallel runner requires a coordinator",
|
|
2624
|
-
code:
|
|
2660
|
+
code: ERROR_CODES3.SDD_INVALID_STATE
|
|
2625
2661
|
});
|
|
2626
2662
|
const coordinator = this.coordinator;
|
|
2627
2663
|
const subagentId = `sdd-d${this.dispatchSeq++}`;
|
|
2628
|
-
const correlationId =
|
|
2664
|
+
const correlationId = randomUUID2();
|
|
2629
2665
|
const meta = task.metadata ?? {};
|
|
2630
2666
|
const model = (typeof meta.model === "string" ? meta.model : void 0) ?? this.opts.defaultModel;
|
|
2631
2667
|
const provider = (typeof meta.provider === "string" ? meta.provider : void 0) ?? this.opts.defaultProvider;
|
|
@@ -2644,9 +2680,9 @@ var SddParallelRun = class {
|
|
|
2644
2680
|
...fallbackModels?.length ? { fallbackModels } : {}
|
|
2645
2681
|
});
|
|
2646
2682
|
if (!spawnResult.subagentId) {
|
|
2647
|
-
throw new
|
|
2683
|
+
throw new SddError3({
|
|
2648
2684
|
message: "One or more subagent spawns failed",
|
|
2649
|
-
code:
|
|
2685
|
+
code: ERROR_CODES3.SDD_INVALID_STATE
|
|
2650
2686
|
});
|
|
2651
2687
|
}
|
|
2652
2688
|
this.taskSubagents.set(taskId, subagentId);
|
|
@@ -2684,7 +2720,7 @@ var SddParallelRun = class {
|
|
|
2684
2720
|
let result;
|
|
2685
2721
|
try {
|
|
2686
2722
|
const got = await coordinator.awaitTasks([correlationId]);
|
|
2687
|
-
result =
|
|
2723
|
+
result = expectDefined2(got[0]);
|
|
2688
2724
|
} catch (err) {
|
|
2689
2725
|
result = {
|
|
2690
2726
|
subagentId,
|
|
@@ -3083,6 +3119,10 @@ function startSddRun(opts) {
|
|
|
3083
3119
|
stop: () => run.stop()
|
|
3084
3120
|
};
|
|
3085
3121
|
}
|
|
3122
|
+
|
|
3123
|
+
// src/sdd-lifecycle.ts
|
|
3124
|
+
import * as fsp4 from "node:fs/promises";
|
|
3125
|
+
import { WorktreeManager } from "@wrongstack/core";
|
|
3086
3126
|
async function cleanupSddWorktrees(projectRoot) {
|
|
3087
3127
|
const wt = new WorktreeManager({ projectRoot });
|
|
3088
3128
|
return wt.cleanupAllManaged();
|
|
@@ -3149,14 +3189,14 @@ async function destroySddProject(opts) {
|
|
|
3149
3189
|
const deleted = [];
|
|
3150
3190
|
const rmDir = async (dir, label) => {
|
|
3151
3191
|
try {
|
|
3152
|
-
await
|
|
3192
|
+
await fsp4.rm(dir, { recursive: true, force: true });
|
|
3153
3193
|
deleted.push(label);
|
|
3154
3194
|
} catch {
|
|
3155
3195
|
}
|
|
3156
3196
|
};
|
|
3157
3197
|
const rmFile = async (file, label) => {
|
|
3158
3198
|
try {
|
|
3159
|
-
await
|
|
3199
|
+
await fsp4.unlink(file);
|
|
3160
3200
|
deleted.push(label);
|
|
3161
3201
|
} catch {
|
|
3162
3202
|
}
|
|
@@ -3320,6 +3360,10 @@ function templateToMarkdown(template, title) {
|
|
|
3320
3360
|
}
|
|
3321
3361
|
return lines.join("\n");
|
|
3322
3362
|
}
|
|
3363
|
+
|
|
3364
|
+
// src/task-visualizer.ts
|
|
3365
|
+
import { computeTaskProgress as computeTaskProgress2 } from "@wrongstack/core/types";
|
|
3366
|
+
import { truncate } from "@wrongstack/core";
|
|
3323
3367
|
var STATUS_ICON = {
|
|
3324
3368
|
pending: "\u25CB",
|
|
3325
3369
|
in_progress: "\u25D0",
|
|
@@ -3349,7 +3393,7 @@ function renderTaskGraph(graph, opts) {
|
|
|
3349
3393
|
lines.push(`\u2502 Spec: ${graph.specId.slice(0, 8)}... \u2502 Nodes: ${graph.nodes.size} \u2502 Edges: ${graph.edges.length} \u2502`);
|
|
3350
3394
|
lines.push("\u2570" + "\u2500".repeat(Math.max(50, graph.title.length + 30)) + "\u256F");
|
|
3351
3395
|
lines.push("");
|
|
3352
|
-
const progress =
|
|
3396
|
+
const progress = computeTaskProgress2(graph);
|
|
3353
3397
|
lines.push(renderProgress(progress));
|
|
3354
3398
|
lines.push("");
|
|
3355
3399
|
const childrenMap = /* @__PURE__ */ new Map();
|
|
@@ -3469,6 +3513,10 @@ function renderSpecAnalysis(spec, analysis) {
|
|
|
3469
3513
|
}
|
|
3470
3514
|
return lines.join("\n");
|
|
3471
3515
|
}
|
|
3516
|
+
|
|
3517
|
+
// src/critical-path.ts
|
|
3518
|
+
import { expectDefined as expectDefined3 } from "@wrongstack/core";
|
|
3519
|
+
import { topologicalSort } from "@wrongstack/core/types";
|
|
3472
3520
|
function analyzeCriticalPath(graph) {
|
|
3473
3521
|
const nodes = Array.from(graph.nodes.values());
|
|
3474
3522
|
const topoOrder = topologicalSort(graph);
|
|
@@ -3544,7 +3592,7 @@ function getTransitiveBlocked(_graph, taskId, blocksMap) {
|
|
|
3544
3592
|
const visited = /* @__PURE__ */ new Set();
|
|
3545
3593
|
const queue = [taskId];
|
|
3546
3594
|
while (queue.length > 0) {
|
|
3547
|
-
const current =
|
|
3595
|
+
const current = expectDefined3(queue.shift());
|
|
3548
3596
|
const blocked = blocksMap.get(current);
|
|
3549
3597
|
if (!blocked) continue;
|
|
3550
3598
|
for (const id of blocked) {
|
|
@@ -3590,7 +3638,7 @@ function computeCriticalPath(graph, _topoOrder, blockedByMap) {
|
|
|
3590
3638
|
if (!changed) break;
|
|
3591
3639
|
}
|
|
3592
3640
|
let maxDist = 0;
|
|
3593
|
-
let maxId =
|
|
3641
|
+
let maxId = expectDefined3(allIds[0]);
|
|
3594
3642
|
for (const id of allIds) {
|
|
3595
3643
|
const d = dist.get(id) ?? 0;
|
|
3596
3644
|
if (d > maxDist) {
|
|
@@ -3638,6 +3686,9 @@ function computeParallelGroups(graph, blockedByMap) {
|
|
|
3638
3686
|
}
|
|
3639
3687
|
return groups;
|
|
3640
3688
|
}
|
|
3689
|
+
|
|
3690
|
+
// src/spec-versioning.ts
|
|
3691
|
+
import { assertNever } from "@wrongstack/core";
|
|
3641
3692
|
var SpecVersioning = class {
|
|
3642
3693
|
versions = /* @__PURE__ */ new Map();
|
|
3643
3694
|
/** Record a new version of a spec. */
|
|
@@ -3971,6 +4022,9 @@ function createAutoExecutor(opts) {
|
|
|
3971
4022
|
maxRetries: opts.maxRetries
|
|
3972
4023
|
});
|
|
3973
4024
|
}
|
|
4025
|
+
|
|
4026
|
+
// src/sdd-supervisor.ts
|
|
4027
|
+
import { parseModelRef } from "@wrongstack/core";
|
|
3974
4028
|
var SddSupervisor = class {
|
|
3975
4029
|
constructor(opts) {
|
|
3976
4030
|
this.opts = opts;
|
|
@@ -4021,6 +4075,9 @@ Supervisor rescues already used: ${attempts}`,
|
|
|
4021
4075
|
return { action: "retry" };
|
|
4022
4076
|
};
|
|
4023
4077
|
};
|
|
4078
|
+
|
|
4079
|
+
// src/verify-task.ts
|
|
4080
|
+
import { spawn } from "node:child_process";
|
|
4024
4081
|
function makeCommandVerifier(options = {}) {
|
|
4025
4082
|
const metadataKey = options.metadataKey ?? "verificationCommand";
|
|
4026
4083
|
const timeoutMs = options.timeoutMs ?? 18e4;
|
|
@@ -4057,6 +4114,12 @@ function makeCommandVerifier(options = {}) {
|
|
|
4057
4114
|
});
|
|
4058
4115
|
};
|
|
4059
4116
|
}
|
|
4117
|
+
|
|
4118
|
+
// src/decompose-task.ts
|
|
4119
|
+
import {
|
|
4120
|
+
readBundledInstructionText,
|
|
4121
|
+
renderInstructionTemplate
|
|
4122
|
+
} from "@wrongstack/core";
|
|
4060
4123
|
var TASK_TYPES2 = /* @__PURE__ */ new Set(["feature", "bugfix", "refactor", "docs", "test", "chore"]);
|
|
4061
4124
|
var PRIORITIES = /* @__PURE__ */ new Set(["critical", "high", "medium", "low"]);
|
|
4062
4125
|
function extractJsonArray(text) {
|
|
@@ -4114,6 +4177,14 @@ function makeLlmSubtaskGenerator(opts) {
|
|
|
4114
4177
|
return specs.length >= min ? specs : [];
|
|
4115
4178
|
};
|
|
4116
4179
|
}
|
|
4180
|
+
|
|
4181
|
+
// src/conflict-resolver.ts
|
|
4182
|
+
import { readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
|
|
4183
|
+
import { join as join4, isAbsolute } from "node:path";
|
|
4184
|
+
import {
|
|
4185
|
+
readBundledInstructionText as readBundledInstructionText2,
|
|
4186
|
+
renderInstructionTemplate as renderInstructionTemplate2
|
|
4187
|
+
} from "@wrongstack/core";
|
|
4117
4188
|
var START = "<<<<<<<";
|
|
4118
4189
|
var BASE = "|||||||";
|
|
4119
4190
|
var SEP = "=======";
|
|
@@ -4155,17 +4226,17 @@ function makePreferSideConflictResolver(side) {
|
|
|
4155
4226
|
return async function conflictResolver(info) {
|
|
4156
4227
|
if (info.conflictFiles.length === 0) return false;
|
|
4157
4228
|
for (const rel of info.conflictFiles) {
|
|
4158
|
-
const abs = isAbsolute(rel) ? rel :
|
|
4229
|
+
const abs = isAbsolute(rel) ? rel : join4(info.cwd, rel);
|
|
4159
4230
|
let content;
|
|
4160
4231
|
try {
|
|
4161
|
-
content = await
|
|
4232
|
+
content = await readFile4(abs, "utf8");
|
|
4162
4233
|
} catch {
|
|
4163
4234
|
return false;
|
|
4164
4235
|
}
|
|
4165
4236
|
const resolved = resolveConflictText(content, side);
|
|
4166
4237
|
if (hasConflictMarkers(resolved)) return false;
|
|
4167
4238
|
try {
|
|
4168
|
-
await
|
|
4239
|
+
await writeFile2(abs, resolved, "utf8");
|
|
4169
4240
|
} catch {
|
|
4170
4241
|
return false;
|
|
4171
4242
|
}
|
|
@@ -4188,16 +4259,16 @@ function makeLlmConflictResolver(opts) {
|
|
|
4188
4259
|
return async function conflictResolver(info) {
|
|
4189
4260
|
if (info.conflictFiles.length === 0) return false;
|
|
4190
4261
|
for (const rel of info.conflictFiles) {
|
|
4191
|
-
const abs = isAbsolute(rel) ? rel :
|
|
4262
|
+
const abs = isAbsolute(rel) ? rel : join4(info.cwd, rel);
|
|
4192
4263
|
let content;
|
|
4193
4264
|
try {
|
|
4194
|
-
content = await
|
|
4265
|
+
content = await readFile4(abs, "utf8");
|
|
4195
4266
|
} catch {
|
|
4196
4267
|
return false;
|
|
4197
4268
|
}
|
|
4198
4269
|
if (!hasConflictMarkers(content)) continue;
|
|
4199
|
-
const prompt =
|
|
4200
|
-
|
|
4270
|
+
const prompt = renderInstructionTemplate2(
|
|
4271
|
+
readBundledInstructionText2("sdd/merge-conflict-resolver.md"),
|
|
4201
4272
|
{
|
|
4202
4273
|
file: rel,
|
|
4203
4274
|
content
|
|
@@ -4215,7 +4286,7 @@ function makeLlmConflictResolver(opts) {
|
|
|
4215
4286
|
return false;
|
|
4216
4287
|
}
|
|
4217
4288
|
try {
|
|
4218
|
-
await
|
|
4289
|
+
await writeFile2(abs, resolved, "utf8");
|
|
4219
4290
|
} catch {
|
|
4220
4291
|
return false;
|
|
4221
4292
|
}
|
|
@@ -4223,7 +4294,52 @@ function makeLlmConflictResolver(opts) {
|
|
|
4223
4294
|
return true;
|
|
4224
4295
|
};
|
|
4225
4296
|
}
|
|
4226
|
-
|
|
4227
|
-
|
|
4297
|
+
export {
|
|
4298
|
+
AISpecBuilder,
|
|
4299
|
+
AutoExecutor,
|
|
4300
|
+
DefaultTaskStore3 as DefaultTaskStore,
|
|
4301
|
+
SPEC_TEMPLATES,
|
|
4302
|
+
SddBoardProjector,
|
|
4303
|
+
SddBoardStore,
|
|
4304
|
+
SddInterviewDriver,
|
|
4305
|
+
SddParallelRun,
|
|
4306
|
+
SddRunRegistry,
|
|
4307
|
+
SddSupervisor,
|
|
4308
|
+
SddTaskDecomposer,
|
|
4309
|
+
SpecDrivenDev,
|
|
4310
|
+
SpecParser,
|
|
4311
|
+
SpecStore,
|
|
4312
|
+
SpecVersioning,
|
|
4313
|
+
TaskFlow,
|
|
4314
|
+
TaskGenerator,
|
|
4315
|
+
TaskGraphStore,
|
|
4316
|
+
TaskTracker3 as TaskTracker,
|
|
4317
|
+
analyzeCriticalPath,
|
|
4318
|
+
applySddLifecycle,
|
|
4319
|
+
buildBoardSnapshot,
|
|
4320
|
+
buildBoardTasks,
|
|
4321
|
+
cleanupSddWorktrees,
|
|
4322
|
+
cleanupStaleSddWorktrees,
|
|
4323
|
+
cleanupStaleWorktrees,
|
|
4324
|
+
createAutoExecutor,
|
|
4325
|
+
destroySddProject,
|
|
4326
|
+
extractVerificationCommand,
|
|
4327
|
+
getTemplate,
|
|
4328
|
+
hasConflictMarkers,
|
|
4329
|
+
isExplanatoryText,
|
|
4330
|
+
listTemplates,
|
|
4331
|
+
makeCommandVerifier,
|
|
4332
|
+
makeLlmConflictResolver,
|
|
4333
|
+
makeLlmSubtaskGenerator,
|
|
4334
|
+
makePreferSideConflictResolver,
|
|
4335
|
+
renderProgress,
|
|
4336
|
+
renderSpecAnalysis,
|
|
4337
|
+
renderTaskGraph,
|
|
4338
|
+
renderTaskList,
|
|
4339
|
+
resolveConflictText,
|
|
4340
|
+
rollbackSddRunFromDisk,
|
|
4341
|
+
shortIdMap,
|
|
4342
|
+
startSddRun,
|
|
4343
|
+
templateToMarkdown
|
|
4344
|
+
};
|
|
4228
4345
|
//# sourceMappingURL=index.js.map
|
|
4229
|
-
//# sourceMappingURL=index.js.map
|