@wrongstack/core 0.8.2 → 0.8.4
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/defaults/index.js +11 -5
- package/dist/defaults/index.js.map +1 -1
- package/dist/execution/index.d.ts +10 -4
- package/dist/execution/index.js +11 -5
- package/dist/execution/index.js.map +1 -1
- package/dist/index.d.ts +416 -2
- package/dist/index.js +896 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3965,11 +3965,11 @@ function validateAgainstSchema(value, schema) {
|
|
|
3965
3965
|
walk2(value, schema, "", errors);
|
|
3966
3966
|
return { ok: errors.length === 0, errors };
|
|
3967
3967
|
}
|
|
3968
|
-
function walk2(value, schema,
|
|
3968
|
+
function walk2(value, schema, path27, errors) {
|
|
3969
3969
|
if (schema.enum !== void 0) {
|
|
3970
3970
|
if (!schema.enum.some((e) => deepEqual(e, value))) {
|
|
3971
3971
|
errors.push({
|
|
3972
|
-
path:
|
|
3972
|
+
path: path27 || "<root>",
|
|
3973
3973
|
message: `expected one of ${JSON.stringify(schema.enum)}, got ${JSON.stringify(value)}`
|
|
3974
3974
|
});
|
|
3975
3975
|
return;
|
|
@@ -3978,7 +3978,7 @@ function walk2(value, schema, path26, errors) {
|
|
|
3978
3978
|
if (typeof schema.type === "string") {
|
|
3979
3979
|
if (!checkType(value, schema.type)) {
|
|
3980
3980
|
errors.push({
|
|
3981
|
-
path:
|
|
3981
|
+
path: path27 || "<root>",
|
|
3982
3982
|
message: `expected ${schema.type}, got ${describeType(value)}`
|
|
3983
3983
|
});
|
|
3984
3984
|
return;
|
|
@@ -3988,19 +3988,19 @@ function walk2(value, schema, path26, errors) {
|
|
|
3988
3988
|
const obj = value;
|
|
3989
3989
|
for (const req of schema.required ?? []) {
|
|
3990
3990
|
if (!(req in obj)) {
|
|
3991
|
-
errors.push({ path: joinPath(
|
|
3991
|
+
errors.push({ path: joinPath(path27, req), message: "required property missing" });
|
|
3992
3992
|
}
|
|
3993
3993
|
}
|
|
3994
3994
|
if (schema.properties) {
|
|
3995
3995
|
for (const [key, subSchema] of Object.entries(schema.properties)) {
|
|
3996
3996
|
if (key in obj) {
|
|
3997
|
-
walk2(obj[key], subSchema, joinPath(
|
|
3997
|
+
walk2(obj[key], subSchema, joinPath(path27, key), errors);
|
|
3998
3998
|
}
|
|
3999
3999
|
}
|
|
4000
4000
|
}
|
|
4001
4001
|
}
|
|
4002
4002
|
if (schema.type === "array" && Array.isArray(value) && schema.items) {
|
|
4003
|
-
value.forEach((item, i) => walk2(item, schema.items, `${
|
|
4003
|
+
value.forEach((item, i) => walk2(item, schema.items, `${path27}[${i}]`, errors));
|
|
4004
4004
|
}
|
|
4005
4005
|
}
|
|
4006
4006
|
function checkType(value, type) {
|
|
@@ -7303,12 +7303,18 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
|
|
|
7303
7303
|
failureMode;
|
|
7304
7304
|
policyProvider;
|
|
7305
7305
|
/**
|
|
7306
|
-
*
|
|
7307
|
-
*
|
|
7308
|
-
*
|
|
7309
|
-
*
|
|
7306
|
+
* Calibration factor applied to the estimator output. The estimator is now
|
|
7307
|
+
* expected to already include messages + system prompt + tool definitions
|
|
7308
|
+
* (see `estimateRequestTokens.total`), so no overhead boost is needed. Kept
|
|
7309
|
+
* as a constant so a future calibration against real provider tokenization
|
|
7310
|
+
* (BPE vs the chars/3.5 rough estimator) can dial this without touching the
|
|
7311
|
+
* threshold-check math.
|
|
7312
|
+
*
|
|
7313
|
+
* Historical note: was 1.3 when the estimator only counted messages — that
|
|
7314
|
+
* double-counted system+tools once the estimator was upgraded, firing
|
|
7315
|
+
* compaction ~30% earlier than intended (e.g. real 56% load showed as 73%).
|
|
7310
7316
|
*/
|
|
7311
|
-
static OVERHEAD_FACTOR = 1
|
|
7317
|
+
static OVERHEAD_FACTOR = 1;
|
|
7312
7318
|
/**
|
|
7313
7319
|
* Once a compaction attempt reduces nothing (preserveK protects everything,
|
|
7314
7320
|
* no oversized tool_results remain to elide), retrying on every iteration
|
|
@@ -8255,8 +8261,8 @@ ${recentJournal}` : "No prior iterations.",
|
|
|
8255
8261
|
await saveGoal(this.goalPath, abandoned);
|
|
8256
8262
|
}
|
|
8257
8263
|
try {
|
|
8258
|
-
const { unlink:
|
|
8259
|
-
await
|
|
8264
|
+
const { unlink: unlink11 } = await import('fs/promises');
|
|
8265
|
+
await unlink11(this.goalPath);
|
|
8260
8266
|
} catch {
|
|
8261
8267
|
}
|
|
8262
8268
|
this.opts.onEternalStop?.();
|
|
@@ -15508,10 +15514,10 @@ var AISpecBuilder = class {
|
|
|
15508
15514
|
async saveSession() {
|
|
15509
15515
|
if (!this.sessionPath) return;
|
|
15510
15516
|
try {
|
|
15511
|
-
const
|
|
15512
|
-
const
|
|
15517
|
+
const fsp17 = await import('fs/promises');
|
|
15518
|
+
const path27 = await import('path');
|
|
15513
15519
|
const { atomicWrite: atomicWrite2 } = await Promise.resolve().then(() => (init_atomic_write(), atomic_write_exports));
|
|
15514
|
-
await
|
|
15520
|
+
await fsp17.mkdir(path27.dirname(this.sessionPath), { recursive: true });
|
|
15515
15521
|
await atomicWrite2(this.sessionPath, JSON.stringify(this.session, null, 2));
|
|
15516
15522
|
} catch {
|
|
15517
15523
|
}
|
|
@@ -15520,8 +15526,8 @@ var AISpecBuilder = class {
|
|
|
15520
15526
|
async loadSession() {
|
|
15521
15527
|
if (!this.sessionPath) return false;
|
|
15522
15528
|
try {
|
|
15523
|
-
const
|
|
15524
|
-
const raw = await
|
|
15529
|
+
const fsp17 = await import('fs/promises');
|
|
15530
|
+
const raw = await fsp17.readFile(this.sessionPath, "utf8");
|
|
15525
15531
|
const loaded = JSON.parse(raw);
|
|
15526
15532
|
if (loaded?.id && loaded?.phase && loaded?.title) {
|
|
15527
15533
|
this.session = loaded;
|
|
@@ -15535,8 +15541,8 @@ var AISpecBuilder = class {
|
|
|
15535
15541
|
async deleteSession() {
|
|
15536
15542
|
if (!this.sessionPath) return;
|
|
15537
15543
|
try {
|
|
15538
|
-
const
|
|
15539
|
-
await
|
|
15544
|
+
const fsp17 = await import('fs/promises');
|
|
15545
|
+
await fsp17.unlink(this.sessionPath);
|
|
15540
15546
|
} catch {
|
|
15541
15547
|
}
|
|
15542
15548
|
}
|
|
@@ -16221,15 +16227,15 @@ function computeCriticalPath(graph, topoOrder, blockedByMap) {
|
|
|
16221
16227
|
maxId = id;
|
|
16222
16228
|
}
|
|
16223
16229
|
}
|
|
16224
|
-
const
|
|
16230
|
+
const path27 = [];
|
|
16225
16231
|
let current = maxId;
|
|
16226
16232
|
const visited = /* @__PURE__ */ new Set();
|
|
16227
16233
|
while (current && !visited.has(current)) {
|
|
16228
16234
|
visited.add(current);
|
|
16229
|
-
|
|
16235
|
+
path27.unshift(current);
|
|
16230
16236
|
current = prev.get(current) ?? null;
|
|
16231
16237
|
}
|
|
16232
|
-
return
|
|
16238
|
+
return path27;
|
|
16233
16239
|
}
|
|
16234
16240
|
function computeParallelGroups(graph, blockedByMap) {
|
|
16235
16241
|
const groups = [];
|
|
@@ -17209,7 +17215,7 @@ async function startMetricsServer(opts) {
|
|
|
17209
17215
|
const tls = opts.tls;
|
|
17210
17216
|
const useHttps = !!(tls?.cert && tls?.key);
|
|
17211
17217
|
const host = opts.host ?? "127.0.0.1";
|
|
17212
|
-
const
|
|
17218
|
+
const path27 = opts.path ?? "/metrics";
|
|
17213
17219
|
const healthPath = opts.healthPath ?? "/healthz";
|
|
17214
17220
|
const healthRegistry = opts.healthRegistry;
|
|
17215
17221
|
const listener = (req, res) => {
|
|
@@ -17219,7 +17225,7 @@ async function startMetricsServer(opts) {
|
|
|
17219
17225
|
return;
|
|
17220
17226
|
}
|
|
17221
17227
|
const url = req.url.split("?")[0];
|
|
17222
|
-
if (url ===
|
|
17228
|
+
if (url === path27) {
|
|
17223
17229
|
let body;
|
|
17224
17230
|
try {
|
|
17225
17231
|
body = renderPrometheus(opts.sink.snapshot());
|
|
@@ -17283,7 +17289,7 @@ async function startMetricsServer(opts) {
|
|
|
17283
17289
|
const protocol = useHttps ? "https" : "http";
|
|
17284
17290
|
return {
|
|
17285
17291
|
port: boundPort,
|
|
17286
|
-
url: `${protocol}://${host}:${boundPort}${
|
|
17292
|
+
url: `${protocol}://${host}:${boundPort}${path27}`,
|
|
17287
17293
|
close: () => new Promise((resolve6, reject) => {
|
|
17288
17294
|
server.close((err) => err ? reject(err) : resolve6());
|
|
17289
17295
|
})
|
|
@@ -19403,8 +19409,8 @@ var ReportGenerator = class {
|
|
|
19403
19409
|
try {
|
|
19404
19410
|
await stat(this.options.outputDir);
|
|
19405
19411
|
} catch {
|
|
19406
|
-
const { mkdir:
|
|
19407
|
-
await
|
|
19412
|
+
const { mkdir: mkdir12 } = await import('fs/promises');
|
|
19413
|
+
await mkdir12(this.options.outputDir, { recursive: true });
|
|
19408
19414
|
}
|
|
19409
19415
|
}
|
|
19410
19416
|
generateMarkdown(result) {
|
|
@@ -20326,16 +20332,16 @@ Use \`/security report <number>\` to view a specific report.` };
|
|
|
20326
20332
|
}
|
|
20327
20333
|
const index = Number.parseInt(reportId, 10) - 1;
|
|
20328
20334
|
if (!Number.isNaN(index) && reports[index]) {
|
|
20329
|
-
const { readFile:
|
|
20330
|
-
const content = await
|
|
20335
|
+
const { readFile: readFile31 } = await import('fs/promises');
|
|
20336
|
+
const content = await readFile31(join(reportsDir, reports[index]), "utf-8");
|
|
20331
20337
|
return { message: `# Security Report
|
|
20332
20338
|
|
|
20333
20339
|
${content}` };
|
|
20334
20340
|
}
|
|
20335
20341
|
const match = reports.find((r) => r.includes(reportId));
|
|
20336
20342
|
if (match) {
|
|
20337
|
-
const { readFile:
|
|
20338
|
-
const content = await
|
|
20343
|
+
const { readFile: readFile31 } = await import('fs/promises');
|
|
20344
|
+
const content = await readFile31(join(reportsDir, match), "utf-8");
|
|
20339
20345
|
return { message: `# Security Report
|
|
20340
20346
|
|
|
20341
20347
|
${content}` };
|
|
@@ -23261,6 +23267,863 @@ function wrapApiForCapabilityCheck(plugin, api, log, enforce = false) {
|
|
|
23261
23267
|
});
|
|
23262
23268
|
}
|
|
23263
23269
|
|
|
23264
|
-
|
|
23270
|
+
// src/autophase/phase-graph-builder.ts
|
|
23271
|
+
var PhaseGraphBuilder = class _PhaseGraphBuilder {
|
|
23272
|
+
constructor(opts) {
|
|
23273
|
+
this.opts = opts;
|
|
23274
|
+
}
|
|
23275
|
+
opts;
|
|
23276
|
+
async build() {
|
|
23277
|
+
const graphId = crypto.randomUUID();
|
|
23278
|
+
const phases = /* @__PURE__ */ new Map();
|
|
23279
|
+
const phaseIds = [];
|
|
23280
|
+
for (let i = 0; i < this.opts.phases.length; i++) {
|
|
23281
|
+
const tmpl = this.opts.phases[i];
|
|
23282
|
+
const phaseId = crypto.randomUUID();
|
|
23283
|
+
phaseIds.push(phaseId);
|
|
23284
|
+
const store = new DefaultTaskStore();
|
|
23285
|
+
const tracker = new TaskTracker({ store });
|
|
23286
|
+
const taskGraph = await tracker.createGraph(phaseId, `${tmpl.name} Tasks`);
|
|
23287
|
+
if (tmpl.taskTemplates && tmpl.taskTemplates.length > 0) {
|
|
23288
|
+
for (const tt of tmpl.taskTemplates) {
|
|
23289
|
+
tracker.addNode({
|
|
23290
|
+
title: tt.title,
|
|
23291
|
+
description: tt.description,
|
|
23292
|
+
type: tt.type,
|
|
23293
|
+
priority: tt.priority,
|
|
23294
|
+
status: "pending",
|
|
23295
|
+
estimateHours: tt.estimateHours,
|
|
23296
|
+
tags: tt.tags ?? []
|
|
23297
|
+
});
|
|
23298
|
+
}
|
|
23299
|
+
}
|
|
23300
|
+
const phase = {
|
|
23301
|
+
id: phaseId,
|
|
23302
|
+
name: tmpl.name,
|
|
23303
|
+
description: tmpl.description,
|
|
23304
|
+
status: "pending",
|
|
23305
|
+
taskGraph,
|
|
23306
|
+
dependsOn: i > 0 ? [phaseIds[i - 1]] : [],
|
|
23307
|
+
nextPhases: i < this.opts.phases.length - 1 ? [phaseIds[i + 1]] : [],
|
|
23308
|
+
parallelizable: tmpl.parallelizable,
|
|
23309
|
+
priority: tmpl.priority,
|
|
23310
|
+
estimateHours: tmpl.estimateHours,
|
|
23311
|
+
assignedAgents: [],
|
|
23312
|
+
createdAt: Date.now(),
|
|
23313
|
+
updatedAt: Date.now()
|
|
23314
|
+
};
|
|
23315
|
+
phases.set(phaseId, phase);
|
|
23316
|
+
}
|
|
23317
|
+
const phaseArray = Array.from(phases.values());
|
|
23318
|
+
for (let i = 0; i < phaseArray.length; i++) {
|
|
23319
|
+
const phase = phaseArray[i];
|
|
23320
|
+
phase.nextPhases = i < phaseArray.length - 1 ? [phaseArray[i + 1].id] : [];
|
|
23321
|
+
phase.dependsOn = i > 0 ? [phaseArray[i - 1].id] : [];
|
|
23322
|
+
}
|
|
23323
|
+
const graph = {
|
|
23324
|
+
id: graphId,
|
|
23325
|
+
title: this.opts.title,
|
|
23326
|
+
description: this.opts.description ?? "",
|
|
23327
|
+
phases,
|
|
23328
|
+
rootPhaseIds: phaseIds.length > 0 ? [phaseIds[0]] : [],
|
|
23329
|
+
activePhaseIds: [],
|
|
23330
|
+
completedPhaseIds: [],
|
|
23331
|
+
failedPhaseIds: [],
|
|
23332
|
+
autonomous: this.opts.autonomous ?? true,
|
|
23333
|
+
stopOnComplete: true,
|
|
23334
|
+
createdAt: Date.now(),
|
|
23335
|
+
updatedAt: Date.now()
|
|
23336
|
+
};
|
|
23337
|
+
return graph;
|
|
23338
|
+
}
|
|
23339
|
+
/**
|
|
23340
|
+
* Var olan bir TaskGraph'tan fazlar oluştur.
|
|
23341
|
+
* Task'ları priority/type göre gruplayarak fazlara ayırır.
|
|
23342
|
+
*/
|
|
23343
|
+
static fromTaskGraph(taskGraph, options) {
|
|
23344
|
+
const tasksPerPhase = options.tasksPerPhase ?? 5;
|
|
23345
|
+
const nodes = Array.from(taskGraph.nodes.values());
|
|
23346
|
+
const sorted = [...nodes].sort((a, b) => {
|
|
23347
|
+
const prioOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
23348
|
+
return (prioOrder[a.priority] ?? 4) - (prioOrder[b.priority] ?? 4);
|
|
23349
|
+
});
|
|
23350
|
+
const groups = [];
|
|
23351
|
+
for (let i = 0; i < sorted.length; i += tasksPerPhase) {
|
|
23352
|
+
groups.push(sorted.slice(i, i + tasksPerPhase));
|
|
23353
|
+
}
|
|
23354
|
+
const phaseTemplates = groups.map((group, idx) => {
|
|
23355
|
+
const hasCritical = group.some((t2) => t2.priority === "critical");
|
|
23356
|
+
const totalHours = group.reduce((sum, t2) => sum + (t2.estimateHours ?? 2), 0);
|
|
23357
|
+
return {
|
|
23358
|
+
name: `Phase ${idx + 1}: ${group[0]?.title.slice(0, 30) ?? "Tasks"}`,
|
|
23359
|
+
description: group.map((t2) => t2.title).join(", "),
|
|
23360
|
+
priority: hasCritical ? "critical" : "high",
|
|
23361
|
+
estimateHours: totalHours,
|
|
23362
|
+
parallelizable: false,
|
|
23363
|
+
taskTemplates: group.map((t2) => ({
|
|
23364
|
+
title: t2.title,
|
|
23365
|
+
description: t2.description,
|
|
23366
|
+
type: t2.type,
|
|
23367
|
+
priority: t2.priority,
|
|
23368
|
+
estimateHours: t2.estimateHours ?? 2,
|
|
23369
|
+
tags: t2.tags ?? []
|
|
23370
|
+
}))
|
|
23371
|
+
};
|
|
23372
|
+
});
|
|
23373
|
+
const builder = new _PhaseGraphBuilder({
|
|
23374
|
+
...options,
|
|
23375
|
+
phases: phaseTemplates
|
|
23376
|
+
});
|
|
23377
|
+
return builder.build();
|
|
23378
|
+
}
|
|
23379
|
+
};
|
|
23380
|
+
|
|
23381
|
+
// src/autophase/phase-orchestrator.ts
|
|
23382
|
+
var PhaseOrchestrator = class {
|
|
23383
|
+
graph;
|
|
23384
|
+
ctx;
|
|
23385
|
+
opts;
|
|
23386
|
+
events;
|
|
23387
|
+
stopped = false;
|
|
23388
|
+
paused = false;
|
|
23389
|
+
runningPhases = /* @__PURE__ */ new Set();
|
|
23390
|
+
tickInterval = null;
|
|
23391
|
+
constructor(opts) {
|
|
23392
|
+
this.graph = opts.graph;
|
|
23393
|
+
this.ctx = opts.ctx;
|
|
23394
|
+
this.events = opts.events ?? this.createNoopEventBus();
|
|
23395
|
+
this.opts = {
|
|
23396
|
+
maxConcurrentPhases: opts.maxConcurrentPhases ?? 1,
|
|
23397
|
+
maxConcurrentTasks: opts.maxConcurrentTasks ?? 2,
|
|
23398
|
+
maxRetries: opts.maxRetries ?? 2,
|
|
23399
|
+
autonomous: opts.autonomous ?? true,
|
|
23400
|
+
phaseDelayMs: opts.phaseDelayMs ?? 0,
|
|
23401
|
+
stopOnFailure: opts.stopOnFailure ?? true,
|
|
23402
|
+
events: this.events
|
|
23403
|
+
};
|
|
23404
|
+
}
|
|
23405
|
+
// ─── Lifecycle ────────────────────────────────────────────────────────────
|
|
23406
|
+
/**
|
|
23407
|
+
* Tüm faz akışını başlat.
|
|
23408
|
+
* Autonomous mode'da: kök faz(lar)ı başlatır, bitince sonrakini otomatik başlatır.
|
|
23409
|
+
*/
|
|
23410
|
+
async start() {
|
|
23411
|
+
this.stopped = false;
|
|
23412
|
+
this.paused = false;
|
|
23413
|
+
this.graph.startedAt = Date.now();
|
|
23414
|
+
this.graph.updatedAt = Date.now();
|
|
23415
|
+
let readyPhases = this.getReadyPhases();
|
|
23416
|
+
while (readyPhases.length > 0 && !this.stopped) {
|
|
23417
|
+
const batch = readyPhases.slice(0, this.opts.maxConcurrentPhases);
|
|
23418
|
+
await Promise.all(batch.map((p) => this.startPhase(p)));
|
|
23419
|
+
readyPhases = this.getReadyPhases().filter(
|
|
23420
|
+
(p) => !this.runningPhases.has(p.id) && p.status !== "completed" && p.status !== "failed"
|
|
23421
|
+
);
|
|
23422
|
+
}
|
|
23423
|
+
if (this.opts.autonomous) {
|
|
23424
|
+
this.tickInterval = setInterval(() => this.tick(), 1e3);
|
|
23425
|
+
}
|
|
23426
|
+
}
|
|
23427
|
+
/** Duraklat — aktif fazlar çalışmaya devam eder ama yeni faz başlamaz */
|
|
23428
|
+
pause() {
|
|
23429
|
+
this.paused = true;
|
|
23430
|
+
}
|
|
23431
|
+
/** Devam et — yeni fazlar başlayabilir */
|
|
23432
|
+
resume() {
|
|
23433
|
+
this.paused = false;
|
|
23434
|
+
void this.tick();
|
|
23435
|
+
}
|
|
23436
|
+
/** Tamamen durdur — aktif fazlar da durdurulur */
|
|
23437
|
+
stop() {
|
|
23438
|
+
this.stopped = true;
|
|
23439
|
+
if (this.tickInterval) {
|
|
23440
|
+
clearInterval(this.tickInterval);
|
|
23441
|
+
this.tickInterval = null;
|
|
23442
|
+
}
|
|
23443
|
+
for (const phaseId of this.runningPhases) {
|
|
23444
|
+
const phase = this.graph.phases.get(phaseId);
|
|
23445
|
+
if (phase) {
|
|
23446
|
+
this.updatePhaseStatus(phase, "paused");
|
|
23447
|
+
}
|
|
23448
|
+
}
|
|
23449
|
+
}
|
|
23450
|
+
// ─── Tick Loop (Autonomous) ───────────────────────────────────────────────
|
|
23451
|
+
async tick() {
|
|
23452
|
+
if (this.stopped || this.paused) return;
|
|
23453
|
+
const active = this.getActivePhases();
|
|
23454
|
+
const ready = this.getReadyPhases();
|
|
23455
|
+
this.emit("autonomous.tick", {
|
|
23456
|
+
activePhases: active.map((p) => p.id),
|
|
23457
|
+
queuedPhases: ready.map((p) => p.id)
|
|
23458
|
+
});
|
|
23459
|
+
this.ctx.onTick?.({ activePhases: active, readyPhases: ready });
|
|
23460
|
+
const availableSlots = this.opts.maxConcurrentPhases - active.length;
|
|
23461
|
+
if (availableSlots > 0 && ready.length > 0) {
|
|
23462
|
+
for (const phase of ready.slice(0, availableSlots)) {
|
|
23463
|
+
await this.startPhase(phase);
|
|
23464
|
+
}
|
|
23465
|
+
}
|
|
23466
|
+
if (this.isComplete()) {
|
|
23467
|
+
this.onGraphComplete();
|
|
23468
|
+
return;
|
|
23469
|
+
}
|
|
23470
|
+
if (this.opts.stopOnFailure && this.graph.failedPhaseIds.length > 0) {
|
|
23471
|
+
const failedPhase = this.graph.phases.get(this.graph.failedPhaseIds[0]);
|
|
23472
|
+
if (failedPhase) {
|
|
23473
|
+
this.onGraphFailed(failedPhase);
|
|
23474
|
+
}
|
|
23475
|
+
return;
|
|
23476
|
+
}
|
|
23477
|
+
}
|
|
23478
|
+
// ─── Phase Execution ──────────────────────────────────────────────────────
|
|
23479
|
+
async startPhase(phase) {
|
|
23480
|
+
if (phase.status !== "pending" && phase.status !== "ready") return;
|
|
23481
|
+
this.updatePhaseStatus(phase, "running");
|
|
23482
|
+
phase.startedAt = Date.now();
|
|
23483
|
+
this.runningPhases.add(phase.id);
|
|
23484
|
+
this.graph.activePhaseIds.push(phase.id);
|
|
23485
|
+
this.emit("phase.started", { phaseId: phase.id, name: phase.name });
|
|
23486
|
+
try {
|
|
23487
|
+
await this.executePhaseTasks(phase);
|
|
23488
|
+
const failedTasks = this.getFailedTaskCount(phase);
|
|
23489
|
+
const completedTasks = this.getCompletedTaskCount(phase);
|
|
23490
|
+
this.emit("phase.allTasksDone", {
|
|
23491
|
+
phaseId: phase.id,
|
|
23492
|
+
completed: completedTasks,
|
|
23493
|
+
failed: failedTasks
|
|
23494
|
+
});
|
|
23495
|
+
if (failedTasks > 0 && this.opts.stopOnFailure) {
|
|
23496
|
+
this.updatePhaseStatus(phase, "failed");
|
|
23497
|
+
phase.completedAt = Date.now();
|
|
23498
|
+
phase.actualDurationMs = Date.now() - (phase.startedAt ?? Date.now());
|
|
23499
|
+
this.runningPhases.delete(phase.id);
|
|
23500
|
+
this.emit("phase.failed", {
|
|
23501
|
+
phaseId: phase.id,
|
|
23502
|
+
name: phase.name,
|
|
23503
|
+
error: `${failedTasks} task(s) failed`
|
|
23504
|
+
});
|
|
23505
|
+
this.ctx.onPhaseFail?.(phase, new Error(`${failedTasks} task(s) failed`));
|
|
23506
|
+
} else {
|
|
23507
|
+
this.updatePhaseStatus(phase, "completed");
|
|
23508
|
+
phase.completedAt = Date.now();
|
|
23509
|
+
phase.actualDurationMs = Date.now() - (phase.startedAt ?? Date.now());
|
|
23510
|
+
this.runningPhases.delete(phase.id);
|
|
23511
|
+
this.graph.completedPhaseIds.push(phase.id);
|
|
23512
|
+
this.emit("phase.completed", {
|
|
23513
|
+
phaseId: phase.id,
|
|
23514
|
+
name: phase.name,
|
|
23515
|
+
durationMs: phase.actualDurationMs
|
|
23516
|
+
});
|
|
23517
|
+
this.ctx.onPhaseComplete?.(phase);
|
|
23518
|
+
}
|
|
23519
|
+
} catch (error) {
|
|
23520
|
+
this.updatePhaseStatus(phase, "failed");
|
|
23521
|
+
phase.completedAt = Date.now();
|
|
23522
|
+
phase.actualDurationMs = Date.now() - (phase.startedAt ?? Date.now());
|
|
23523
|
+
this.runningPhases.delete(phase.id);
|
|
23524
|
+
this.graph.failedPhaseIds.push(phase.id);
|
|
23525
|
+
this.emit("phase.failed", {
|
|
23526
|
+
phaseId: phase.id,
|
|
23527
|
+
name: phase.name,
|
|
23528
|
+
error: error instanceof Error ? error.message : String(error)
|
|
23529
|
+
});
|
|
23530
|
+
this.ctx.onPhaseFail?.(phase, error instanceof Error ? error : new Error(String(error)));
|
|
23531
|
+
}
|
|
23532
|
+
}
|
|
23533
|
+
async executePhaseTasks(phase) {
|
|
23534
|
+
phase.taskGraph;
|
|
23535
|
+
const pendingTasks = this.getExecutableTasks(phase);
|
|
23536
|
+
while (pendingTasks.length > 0 && !this.stopped) {
|
|
23537
|
+
const batch = pendingTasks.splice(0, this.opts.maxConcurrentTasks);
|
|
23538
|
+
const results = await Promise.allSettled(
|
|
23539
|
+
batch.map((task) => this.executeSingleTask(task, phase))
|
|
23540
|
+
);
|
|
23541
|
+
for (let i = 0; i < results.length; i++) {
|
|
23542
|
+
const result = results[i];
|
|
23543
|
+
const task = batch[i];
|
|
23544
|
+
if (!result || !task) continue;
|
|
23545
|
+
if (result.status === "fulfilled") {
|
|
23546
|
+
this.markTaskCompleted(phase, task);
|
|
23547
|
+
} else {
|
|
23548
|
+
this.markTaskFailed(phase, task, result.reason);
|
|
23549
|
+
}
|
|
23550
|
+
}
|
|
23551
|
+
const newReady = this.getExecutableTasks(phase);
|
|
23552
|
+
pendingTasks.length = 0;
|
|
23553
|
+
pendingTasks.push(...newReady);
|
|
23554
|
+
}
|
|
23555
|
+
}
|
|
23556
|
+
async executeSingleTask(task, phase) {
|
|
23557
|
+
const tracker = this.getTrackerForPhase(phase);
|
|
23558
|
+
tracker.updateNodeStatus(task.id, "in_progress");
|
|
23559
|
+
return this.ctx.executeTask(task, phase.id);
|
|
23560
|
+
}
|
|
23561
|
+
markTaskCompleted(phase, task) {
|
|
23562
|
+
const tracker = this.getTrackerForPhase(phase);
|
|
23563
|
+
tracker.updateNodeStatus(task.id, "completed");
|
|
23564
|
+
this.emit("phase.taskCompleted", {
|
|
23565
|
+
phaseId: phase.id,
|
|
23566
|
+
taskId: task.id,
|
|
23567
|
+
taskTitle: task.title
|
|
23568
|
+
});
|
|
23569
|
+
}
|
|
23570
|
+
markTaskFailed(phase, task, error) {
|
|
23571
|
+
const tracker = this.getTrackerForPhase(phase);
|
|
23572
|
+
tracker.updateNodeStatus(task.id, "failed", error instanceof Error ? error.message : String(error));
|
|
23573
|
+
this.emit("phase.taskFailed", {
|
|
23574
|
+
phaseId: phase.id,
|
|
23575
|
+
taskId: task.id,
|
|
23576
|
+
taskTitle: task.title,
|
|
23577
|
+
error: error instanceof Error ? error.message : String(error)
|
|
23578
|
+
});
|
|
23579
|
+
}
|
|
23580
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────
|
|
23581
|
+
getReadyPhases() {
|
|
23582
|
+
const ready = [];
|
|
23583
|
+
for (const phase of this.graph.phases.values()) {
|
|
23584
|
+
if (phase.status !== "pending") continue;
|
|
23585
|
+
const depsDone = phase.dependsOn.every((depId) => {
|
|
23586
|
+
const dep = this.graph.phases.get(depId);
|
|
23587
|
+
return dep?.status === "completed" || dep?.status === "skipped";
|
|
23588
|
+
});
|
|
23589
|
+
if (depsDone) {
|
|
23590
|
+
ready.push(phase);
|
|
23591
|
+
}
|
|
23592
|
+
}
|
|
23593
|
+
const prioOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
23594
|
+
ready.sort((a, b) => (prioOrder[a.priority] ?? 4) - (prioOrder[b.priority] ?? 4));
|
|
23595
|
+
return ready;
|
|
23596
|
+
}
|
|
23597
|
+
getActivePhases() {
|
|
23598
|
+
return Array.from(this.graph.phases.values()).filter((p) => p.status === "running");
|
|
23599
|
+
}
|
|
23600
|
+
getExecutableTasks(phase) {
|
|
23601
|
+
const tracker = this.getTrackerForPhase(phase);
|
|
23602
|
+
return tracker.getAllNodes({ status: ["pending", "blocked"] }).filter((n) => n.status === "pending" && tracker.canStart(n.id)).sort((a, b) => {
|
|
23603
|
+
const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
23604
|
+
return (priorityOrder[a.priority] ?? 4) - (priorityOrder[b.priority] ?? 4);
|
|
23605
|
+
});
|
|
23606
|
+
}
|
|
23607
|
+
getTrackerForPhase(phase) {
|
|
23608
|
+
const store = new DefaultTaskStore();
|
|
23609
|
+
const tracker = new TaskTracker({ store });
|
|
23610
|
+
tracker.graph = phase.taskGraph;
|
|
23611
|
+
return tracker;
|
|
23612
|
+
}
|
|
23613
|
+
getFailedTaskCount(phase) {
|
|
23614
|
+
const tracker = this.getTrackerForPhase(phase);
|
|
23615
|
+
return tracker.getAllNodes({ status: ["failed"] }).length;
|
|
23616
|
+
}
|
|
23617
|
+
getCompletedTaskCount(phase) {
|
|
23618
|
+
const tracker = this.getTrackerForPhase(phase);
|
|
23619
|
+
return tracker.getAllNodes({ status: ["completed"] }).length;
|
|
23620
|
+
}
|
|
23621
|
+
updatePhaseStatus(phase, status) {
|
|
23622
|
+
const from = phase.status;
|
|
23623
|
+
phase.status = status;
|
|
23624
|
+
phase.updatedAt = Date.now();
|
|
23625
|
+
this.graph.updatedAt = Date.now();
|
|
23626
|
+
this.emit("phase.statusChange", { phaseId: phase.id, from, to: status });
|
|
23627
|
+
}
|
|
23628
|
+
isComplete() {
|
|
23629
|
+
const allPhases = Array.from(this.graph.phases.values());
|
|
23630
|
+
return allPhases.every(
|
|
23631
|
+
(p) => p.status === "completed" || p.status === "skipped" || p.status === "failed"
|
|
23632
|
+
);
|
|
23633
|
+
}
|
|
23634
|
+
onGraphComplete() {
|
|
23635
|
+
this.graph.completedAt = Date.now();
|
|
23636
|
+
const durationMs = this.graph.completedAt - (this.graph.startedAt ?? this.graph.completedAt);
|
|
23637
|
+
this.emit("graph.completed", { graphId: this.graph.id, durationMs });
|
|
23638
|
+
this.stop();
|
|
23639
|
+
}
|
|
23640
|
+
onGraphFailed(failedPhase) {
|
|
23641
|
+
this.emit("graph.failed", {
|
|
23642
|
+
graphId: this.graph.id,
|
|
23643
|
+
failedPhaseId: failedPhase.id,
|
|
23644
|
+
error: `Phase "${failedPhase.name}" failed`
|
|
23645
|
+
});
|
|
23646
|
+
this.stop();
|
|
23647
|
+
}
|
|
23648
|
+
// ─── Progress ─────────────────────────────────────────────────────────────
|
|
23649
|
+
getProgress() {
|
|
23650
|
+
const phases = Array.from(this.graph.phases.values());
|
|
23651
|
+
let pending = 0, ready = 0, running = 0, paused = 0, completed = 0, failed = 0, skipped = 0;
|
|
23652
|
+
let totalTasks = 0, completedTasks = 0, failedTasks = 0, estimatedHours = 0, actualHours = 0;
|
|
23653
|
+
for (const p of phases) {
|
|
23654
|
+
switch (p.status) {
|
|
23655
|
+
case "pending":
|
|
23656
|
+
pending++;
|
|
23657
|
+
break;
|
|
23658
|
+
case "ready":
|
|
23659
|
+
ready++;
|
|
23660
|
+
break;
|
|
23661
|
+
case "running":
|
|
23662
|
+
running++;
|
|
23663
|
+
break;
|
|
23664
|
+
case "paused":
|
|
23665
|
+
paused++;
|
|
23666
|
+
break;
|
|
23667
|
+
case "completed":
|
|
23668
|
+
completed++;
|
|
23669
|
+
break;
|
|
23670
|
+
case "failed":
|
|
23671
|
+
failed++;
|
|
23672
|
+
break;
|
|
23673
|
+
case "skipped":
|
|
23674
|
+
skipped++;
|
|
23675
|
+
break;
|
|
23676
|
+
}
|
|
23677
|
+
estimatedHours += p.estimateHours;
|
|
23678
|
+
if (p.actualDurationMs) actualHours += p.actualDurationMs / 36e5;
|
|
23679
|
+
const tracker = this.getTrackerForPhase(p);
|
|
23680
|
+
const progress = tracker.getProgress();
|
|
23681
|
+
totalTasks += progress.total;
|
|
23682
|
+
completedTasks += progress.completed;
|
|
23683
|
+
failedTasks += progress.failed;
|
|
23684
|
+
}
|
|
23685
|
+
const totalPhases = phases.length;
|
|
23686
|
+
const done = completed + skipped;
|
|
23687
|
+
return {
|
|
23688
|
+
totalPhases,
|
|
23689
|
+
pending,
|
|
23690
|
+
ready,
|
|
23691
|
+
running,
|
|
23692
|
+
paused,
|
|
23693
|
+
completed,
|
|
23694
|
+
failed,
|
|
23695
|
+
skipped,
|
|
23696
|
+
percentComplete: totalPhases > 0 ? Math.round(done / totalPhases * 100) : 0,
|
|
23697
|
+
totalTasks,
|
|
23698
|
+
completedTasks,
|
|
23699
|
+
failedTasks,
|
|
23700
|
+
estimatedHours,
|
|
23701
|
+
actualHours
|
|
23702
|
+
};
|
|
23703
|
+
}
|
|
23704
|
+
getGraph() {
|
|
23705
|
+
return this.graph;
|
|
23706
|
+
}
|
|
23707
|
+
isRunning() {
|
|
23708
|
+
return !this.stopped && this.runningPhases.size > 0;
|
|
23709
|
+
}
|
|
23710
|
+
isPaused() {
|
|
23711
|
+
return this.paused;
|
|
23712
|
+
}
|
|
23713
|
+
// ─── Agent Assignment ─────────────────────────────────────────────────────
|
|
23714
|
+
assignAgent(phaseId, agentId) {
|
|
23715
|
+
const phase = this.graph.phases.get(phaseId);
|
|
23716
|
+
if (!phase) return;
|
|
23717
|
+
if (!phase.assignedAgents.includes(agentId)) {
|
|
23718
|
+
phase.assignedAgents.push(agentId);
|
|
23719
|
+
this.emit("agent.assigned", { phaseId, agentId });
|
|
23720
|
+
}
|
|
23721
|
+
}
|
|
23722
|
+
releaseAgent(phaseId, agentId) {
|
|
23723
|
+
const phase = this.graph.phases.get(phaseId);
|
|
23724
|
+
if (!phase) return;
|
|
23725
|
+
phase.assignedAgents = phase.assignedAgents.filter((id) => id !== agentId);
|
|
23726
|
+
this.emit("agent.released", { phaseId, agentId });
|
|
23727
|
+
}
|
|
23728
|
+
// ─── Events ───────────────────────────────────────────────────────────────
|
|
23729
|
+
emit(event, payload) {
|
|
23730
|
+
this.events.emit(event, payload);
|
|
23731
|
+
}
|
|
23732
|
+
createNoopEventBus() {
|
|
23733
|
+
return {
|
|
23734
|
+
emit: () => {
|
|
23735
|
+
},
|
|
23736
|
+
on: () => {
|
|
23737
|
+
},
|
|
23738
|
+
off: () => {
|
|
23739
|
+
},
|
|
23740
|
+
once: () => {
|
|
23741
|
+
},
|
|
23742
|
+
listeners: /* @__PURE__ */ new Map(),
|
|
23743
|
+
wildcards: /* @__PURE__ */ new Set(),
|
|
23744
|
+
setLogger: () => {
|
|
23745
|
+
},
|
|
23746
|
+
onAny: () => {
|
|
23747
|
+
},
|
|
23748
|
+
offAny: () => {
|
|
23749
|
+
},
|
|
23750
|
+
emitAsync: async () => [],
|
|
23751
|
+
waitFor: async () => {
|
|
23752
|
+
}
|
|
23753
|
+
};
|
|
23754
|
+
}
|
|
23755
|
+
};
|
|
23756
|
+
|
|
23757
|
+
// src/autophase/auto-phase-runner.ts
|
|
23758
|
+
var AutoPhaseRunner = class {
|
|
23759
|
+
graph = null;
|
|
23760
|
+
orchestrator = null;
|
|
23761
|
+
opts;
|
|
23762
|
+
progressInterval = null;
|
|
23763
|
+
constructor(opts) {
|
|
23764
|
+
this.opts = opts;
|
|
23765
|
+
}
|
|
23766
|
+
async start() {
|
|
23767
|
+
const builder = new PhaseGraphBuilder({
|
|
23768
|
+
title: this.opts.title,
|
|
23769
|
+
description: this.opts.description,
|
|
23770
|
+
phases: this.opts.phases,
|
|
23771
|
+
autonomous: this.opts.autonomous,
|
|
23772
|
+
stopOnFailure: this.opts.stopOnFailure
|
|
23773
|
+
});
|
|
23774
|
+
this.graph = await builder.build();
|
|
23775
|
+
const ctx = {
|
|
23776
|
+
executeTask: this.opts.executeTask,
|
|
23777
|
+
onPhaseComplete: (phase) => {
|
|
23778
|
+
this.opts.onPhaseComplete?.(phase);
|
|
23779
|
+
},
|
|
23780
|
+
onPhaseFail: (phase, error) => {
|
|
23781
|
+
this.opts.onPhaseFail?.(phase, error);
|
|
23782
|
+
},
|
|
23783
|
+
onTick: (tickCtx) => {
|
|
23784
|
+
this.opts.onTick?.(tickCtx);
|
|
23785
|
+
}
|
|
23786
|
+
};
|
|
23787
|
+
this.orchestrator = new PhaseOrchestrator({
|
|
23788
|
+
graph: this.graph,
|
|
23789
|
+
ctx,
|
|
23790
|
+
maxConcurrentPhases: this.opts.maxConcurrentPhases,
|
|
23791
|
+
maxConcurrentTasks: this.opts.maxConcurrentTasks,
|
|
23792
|
+
maxRetries: this.opts.maxRetries,
|
|
23793
|
+
autonomous: this.opts.autonomous,
|
|
23794
|
+
phaseDelayMs: this.opts.phaseDelayMs,
|
|
23795
|
+
stopOnFailure: this.opts.stopOnFailure,
|
|
23796
|
+
events: this.opts.events
|
|
23797
|
+
});
|
|
23798
|
+
if (this.opts.onProgress) {
|
|
23799
|
+
this.progressInterval = setInterval(() => {
|
|
23800
|
+
const progress = this.orchestrator.getProgress();
|
|
23801
|
+
this.opts.onProgress(progress);
|
|
23802
|
+
}, 2e3);
|
|
23803
|
+
}
|
|
23804
|
+
const events = this.opts.events;
|
|
23805
|
+
if (events) {
|
|
23806
|
+
events.on(
|
|
23807
|
+
"graph.completed",
|
|
23808
|
+
(payload) => {
|
|
23809
|
+
const p = payload;
|
|
23810
|
+
if (this.graph && p.graphId === this.graph.id) {
|
|
23811
|
+
this.opts.onComplete?.(this.graph);
|
|
23812
|
+
this.cleanup();
|
|
23813
|
+
}
|
|
23814
|
+
}
|
|
23815
|
+
);
|
|
23816
|
+
events.on(
|
|
23817
|
+
"graph.failed",
|
|
23818
|
+
(payload) => {
|
|
23819
|
+
const p = payload;
|
|
23820
|
+
if (this.graph && p.graphId === this.graph.id) {
|
|
23821
|
+
const failedPhase = this.graph.phases.get(p.failedPhaseId);
|
|
23822
|
+
if (failedPhase) {
|
|
23823
|
+
this.opts.onFail?.(this.graph, failedPhase, new Error(p.error));
|
|
23824
|
+
}
|
|
23825
|
+
this.cleanup();
|
|
23826
|
+
}
|
|
23827
|
+
}
|
|
23828
|
+
);
|
|
23829
|
+
}
|
|
23830
|
+
await this.orchestrator.start();
|
|
23831
|
+
return this.graph;
|
|
23832
|
+
}
|
|
23833
|
+
pause() {
|
|
23834
|
+
this.orchestrator?.pause();
|
|
23835
|
+
}
|
|
23836
|
+
resume() {
|
|
23837
|
+
this.orchestrator?.resume();
|
|
23838
|
+
}
|
|
23839
|
+
stop() {
|
|
23840
|
+
this.orchestrator?.stop();
|
|
23841
|
+
this.cleanup();
|
|
23842
|
+
}
|
|
23843
|
+
getProgress() {
|
|
23844
|
+
return this.orchestrator?.getProgress() ?? null;
|
|
23845
|
+
}
|
|
23846
|
+
getGraph() {
|
|
23847
|
+
return this.graph;
|
|
23848
|
+
}
|
|
23849
|
+
isRunning() {
|
|
23850
|
+
return this.orchestrator?.isRunning() ?? false;
|
|
23851
|
+
}
|
|
23852
|
+
isPaused() {
|
|
23853
|
+
return this.orchestrator?.isPaused() ?? false;
|
|
23854
|
+
}
|
|
23855
|
+
assignAgent(phaseId, agentId) {
|
|
23856
|
+
this.orchestrator?.assignAgent(phaseId, agentId);
|
|
23857
|
+
}
|
|
23858
|
+
releaseAgent(phaseId, agentId) {
|
|
23859
|
+
this.orchestrator?.releaseAgent(phaseId, agentId);
|
|
23860
|
+
}
|
|
23861
|
+
cleanup() {
|
|
23862
|
+
if (this.progressInterval) {
|
|
23863
|
+
clearInterval(this.progressInterval);
|
|
23864
|
+
this.progressInterval = null;
|
|
23865
|
+
}
|
|
23866
|
+
}
|
|
23867
|
+
};
|
|
23868
|
+
async function createAutoPhaseFromTaskGraph(taskGraph, options) {
|
|
23869
|
+
const graph = await PhaseGraphBuilder.fromTaskGraph(taskGraph, {
|
|
23870
|
+
title: options.title ?? taskGraph.title,
|
|
23871
|
+
tasksPerPhase: options.tasksPerPhase
|
|
23872
|
+
});
|
|
23873
|
+
const phases = Array.from(graph.phases.values()).map((p) => ({
|
|
23874
|
+
name: p.name,
|
|
23875
|
+
description: p.description,
|
|
23876
|
+
priority: p.priority,
|
|
23877
|
+
estimateHours: p.estimateHours,
|
|
23878
|
+
parallelizable: p.parallelizable
|
|
23879
|
+
}));
|
|
23880
|
+
return new AutoPhaseRunner({
|
|
23881
|
+
...options,
|
|
23882
|
+
title: options.title ?? taskGraph.title,
|
|
23883
|
+
phases
|
|
23884
|
+
});
|
|
23885
|
+
}
|
|
23886
|
+
var PhaseStore = class {
|
|
23887
|
+
baseDir;
|
|
23888
|
+
constructor(opts) {
|
|
23889
|
+
this.baseDir = opts.baseDir;
|
|
23890
|
+
}
|
|
23891
|
+
async save(graph) {
|
|
23892
|
+
const filePath = this.getFilePath(graph.id);
|
|
23893
|
+
await fsp2.mkdir(path6.dirname(filePath), { recursive: true });
|
|
23894
|
+
const serialized = this.serializeGraph(graph);
|
|
23895
|
+
await fsp2.writeFile(filePath, JSON.stringify(serialized, null, 2), "utf8");
|
|
23896
|
+
}
|
|
23897
|
+
async load(graphId) {
|
|
23898
|
+
const filePath = this.getFilePath(graphId);
|
|
23899
|
+
try {
|
|
23900
|
+
const raw = await fsp2.readFile(filePath, "utf8");
|
|
23901
|
+
const serialized = JSON.parse(raw);
|
|
23902
|
+
return this.deserializeGraph(serialized);
|
|
23903
|
+
} catch {
|
|
23904
|
+
return null;
|
|
23905
|
+
}
|
|
23906
|
+
}
|
|
23907
|
+
async delete(graphId) {
|
|
23908
|
+
const filePath = this.getFilePath(graphId);
|
|
23909
|
+
try {
|
|
23910
|
+
await fsp2.unlink(filePath);
|
|
23911
|
+
} catch {
|
|
23912
|
+
}
|
|
23913
|
+
}
|
|
23914
|
+
async list() {
|
|
23915
|
+
try {
|
|
23916
|
+
const entries = await fsp2.readdir(this.baseDir, { withFileTypes: true });
|
|
23917
|
+
const graphs = [];
|
|
23918
|
+
for (const entry of entries) {
|
|
23919
|
+
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
23920
|
+
try {
|
|
23921
|
+
const raw = await fsp2.readFile(path6.join(this.baseDir, entry.name), "utf8");
|
|
23922
|
+
const serialized = JSON.parse(raw);
|
|
23923
|
+
const done = serialized.completedPhaseIds.length;
|
|
23924
|
+
const total = serialized.phases.length;
|
|
23925
|
+
graphs.push({
|
|
23926
|
+
id: serialized.id,
|
|
23927
|
+
title: serialized.title,
|
|
23928
|
+
updatedAt: serialized.updatedAt,
|
|
23929
|
+
status: done === total ? "completed" : done > 0 ? "in_progress" : "pending"
|
|
23930
|
+
});
|
|
23931
|
+
} catch {
|
|
23932
|
+
}
|
|
23933
|
+
}
|
|
23934
|
+
return graphs.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
23935
|
+
} catch {
|
|
23936
|
+
return [];
|
|
23937
|
+
}
|
|
23938
|
+
}
|
|
23939
|
+
getFilePath(graphId) {
|
|
23940
|
+
return path6.join(this.baseDir, `${graphId}.json`);
|
|
23941
|
+
}
|
|
23942
|
+
serializeGraph(graph) {
|
|
23943
|
+
return {
|
|
23944
|
+
id: graph.id,
|
|
23945
|
+
title: graph.title,
|
|
23946
|
+
description: graph.description,
|
|
23947
|
+
phases: Array.from(graph.phases.values()).map((p) => this.serializePhase(p)),
|
|
23948
|
+
rootPhaseIds: graph.rootPhaseIds,
|
|
23949
|
+
activePhaseIds: graph.activePhaseIds,
|
|
23950
|
+
completedPhaseIds: graph.completedPhaseIds,
|
|
23951
|
+
failedPhaseIds: graph.failedPhaseIds,
|
|
23952
|
+
autonomous: graph.autonomous,
|
|
23953
|
+
stopOnComplete: graph.stopOnComplete,
|
|
23954
|
+
createdAt: graph.createdAt,
|
|
23955
|
+
updatedAt: graph.updatedAt,
|
|
23956
|
+
startedAt: graph.startedAt,
|
|
23957
|
+
completedAt: graph.completedAt
|
|
23958
|
+
};
|
|
23959
|
+
}
|
|
23960
|
+
serializePhase(phase) {
|
|
23961
|
+
return {
|
|
23962
|
+
id: phase.id,
|
|
23963
|
+
name: phase.name,
|
|
23964
|
+
description: phase.description,
|
|
23965
|
+
status: phase.status,
|
|
23966
|
+
taskGraph: this.serializeTaskGraph(phase.taskGraph),
|
|
23967
|
+
dependsOn: phase.dependsOn,
|
|
23968
|
+
nextPhases: phase.nextPhases,
|
|
23969
|
+
parallelizable: phase.parallelizable,
|
|
23970
|
+
priority: phase.priority,
|
|
23971
|
+
estimateHours: phase.estimateHours,
|
|
23972
|
+
actualDurationMs: phase.actualDurationMs,
|
|
23973
|
+
startedAt: phase.startedAt,
|
|
23974
|
+
completedAt: phase.completedAt,
|
|
23975
|
+
assignedAgents: phase.assignedAgents,
|
|
23976
|
+
metadata: phase.metadata,
|
|
23977
|
+
createdAt: phase.createdAt,
|
|
23978
|
+
updatedAt: phase.updatedAt
|
|
23979
|
+
};
|
|
23980
|
+
}
|
|
23981
|
+
serializeTaskGraph(graph) {
|
|
23982
|
+
return {
|
|
23983
|
+
id: graph.id,
|
|
23984
|
+
specId: graph.specId,
|
|
23985
|
+
title: graph.title,
|
|
23986
|
+
nodes: Array.from(graph.nodes.values()).map((n) => this.serializeTaskNode(n)),
|
|
23987
|
+
edges: graph.edges,
|
|
23988
|
+
rootNodes: graph.rootNodes,
|
|
23989
|
+
createdAt: graph.createdAt,
|
|
23990
|
+
updatedAt: graph.updatedAt
|
|
23991
|
+
};
|
|
23992
|
+
}
|
|
23993
|
+
serializeTaskNode(node) {
|
|
23994
|
+
return { ...node };
|
|
23995
|
+
}
|
|
23996
|
+
deserializeGraph(serialized) {
|
|
23997
|
+
const phases = /* @__PURE__ */ new Map();
|
|
23998
|
+
for (const sp of serialized.phases) {
|
|
23999
|
+
phases.set(sp.id, this.deserializePhase(sp));
|
|
24000
|
+
}
|
|
24001
|
+
return {
|
|
24002
|
+
id: serialized.id,
|
|
24003
|
+
title: serialized.title,
|
|
24004
|
+
description: serialized.description,
|
|
24005
|
+
phases,
|
|
24006
|
+
rootPhaseIds: serialized.rootPhaseIds,
|
|
24007
|
+
activePhaseIds: serialized.activePhaseIds,
|
|
24008
|
+
completedPhaseIds: serialized.completedPhaseIds,
|
|
24009
|
+
failedPhaseIds: serialized.failedPhaseIds,
|
|
24010
|
+
autonomous: serialized.autonomous,
|
|
24011
|
+
stopOnComplete: serialized.stopOnComplete,
|
|
24012
|
+
createdAt: serialized.createdAt,
|
|
24013
|
+
updatedAt: serialized.updatedAt,
|
|
24014
|
+
startedAt: serialized.startedAt,
|
|
24015
|
+
completedAt: serialized.completedAt
|
|
24016
|
+
};
|
|
24017
|
+
}
|
|
24018
|
+
deserializePhase(serialized) {
|
|
24019
|
+
return {
|
|
24020
|
+
id: serialized.id,
|
|
24021
|
+
name: serialized.name,
|
|
24022
|
+
description: serialized.description,
|
|
24023
|
+
status: serialized.status,
|
|
24024
|
+
taskGraph: this.deserializeTaskGraph(serialized.taskGraph),
|
|
24025
|
+
dependsOn: serialized.dependsOn,
|
|
24026
|
+
nextPhases: serialized.nextPhases,
|
|
24027
|
+
parallelizable: serialized.parallelizable,
|
|
24028
|
+
priority: serialized.priority,
|
|
24029
|
+
estimateHours: serialized.estimateHours,
|
|
24030
|
+
actualDurationMs: serialized.actualDurationMs,
|
|
24031
|
+
startedAt: serialized.startedAt,
|
|
24032
|
+
completedAt: serialized.completedAt,
|
|
24033
|
+
assignedAgents: serialized.assignedAgents,
|
|
24034
|
+
metadata: serialized.metadata,
|
|
24035
|
+
createdAt: serialized.createdAt,
|
|
24036
|
+
updatedAt: serialized.updatedAt
|
|
24037
|
+
};
|
|
24038
|
+
}
|
|
24039
|
+
deserializeTaskGraph(serialized) {
|
|
24040
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
24041
|
+
for (const sn of serialized.nodes) {
|
|
24042
|
+
nodes.set(sn.id, sn);
|
|
24043
|
+
}
|
|
24044
|
+
return {
|
|
24045
|
+
id: serialized.id,
|
|
24046
|
+
specId: serialized.specId,
|
|
24047
|
+
title: serialized.title,
|
|
24048
|
+
nodes,
|
|
24049
|
+
edges: serialized.edges,
|
|
24050
|
+
rootNodes: serialized.rootNodes,
|
|
24051
|
+
createdAt: serialized.createdAt,
|
|
24052
|
+
updatedAt: serialized.updatedAt
|
|
24053
|
+
};
|
|
24054
|
+
}
|
|
24055
|
+
};
|
|
24056
|
+
|
|
24057
|
+
// src/autophase/checkpoint.ts
|
|
24058
|
+
var CheckpointManager = class {
|
|
24059
|
+
store;
|
|
24060
|
+
maxCheckpoints;
|
|
24061
|
+
checkpoints = /* @__PURE__ */ new Map();
|
|
24062
|
+
constructor(opts) {
|
|
24063
|
+
this.store = opts.store;
|
|
24064
|
+
this.maxCheckpoints = opts.maxCheckpoints ?? 10;
|
|
24065
|
+
}
|
|
24066
|
+
async saveCheckpoint(graph, label) {
|
|
24067
|
+
await this.store.save(graph);
|
|
24068
|
+
const activePhase = Array.from(graph.phases.values()).find(
|
|
24069
|
+
(p) => p.status === "running" || p.status === "paused"
|
|
24070
|
+
);
|
|
24071
|
+
const checkpoint = {
|
|
24072
|
+
id: crypto.randomUUID(),
|
|
24073
|
+
graphId: graph.id,
|
|
24074
|
+
phaseId: activePhase?.id ?? graph.rootPhaseIds[0] ?? "",
|
|
24075
|
+
phaseStatus: activePhase?.status ?? "pending",
|
|
24076
|
+
taskStatuses: activePhase ? Array.from(activePhase.taskGraph.nodes.values()).map((t2) => ({
|
|
24077
|
+
taskId: t2.id,
|
|
24078
|
+
status: t2.status,
|
|
24079
|
+
title: t2.title
|
|
24080
|
+
})) : [],
|
|
24081
|
+
timestamp: Date.now(),
|
|
24082
|
+
label
|
|
24083
|
+
};
|
|
24084
|
+
this.checkpoints.set(checkpoint.id, checkpoint);
|
|
24085
|
+
this.pruneCheckpoints();
|
|
24086
|
+
return checkpoint;
|
|
24087
|
+
}
|
|
24088
|
+
async restoreCheckpoint(checkpointId) {
|
|
24089
|
+
const checkpoint = this.checkpoints.get(checkpointId);
|
|
24090
|
+
if (!checkpoint) return null;
|
|
24091
|
+
const graph = await this.store.load(checkpoint.graphId);
|
|
24092
|
+
if (!graph) return null;
|
|
24093
|
+
const phase = graph.phases.get(checkpoint.phaseId);
|
|
24094
|
+
if (phase) {
|
|
24095
|
+
phase.status = checkpoint.phaseStatus;
|
|
24096
|
+
phase.updatedAt = Date.now();
|
|
24097
|
+
for (const ts of checkpoint.taskStatuses) {
|
|
24098
|
+
const task = phase.taskGraph.nodes.get(ts.taskId);
|
|
24099
|
+
if (task) {
|
|
24100
|
+
task.status = ts.status;
|
|
24101
|
+
task.updatedAt = Date.now();
|
|
24102
|
+
}
|
|
24103
|
+
}
|
|
24104
|
+
}
|
|
24105
|
+
graph.updatedAt = Date.now();
|
|
24106
|
+
return graph;
|
|
24107
|
+
}
|
|
24108
|
+
listCheckpoints(graphId) {
|
|
24109
|
+
const all = Array.from(this.checkpoints.values());
|
|
24110
|
+
const filtered = graphId ? all.filter((c) => c.graphId === graphId) : all;
|
|
24111
|
+
return filtered.sort((a, b) => b.timestamp - a.timestamp);
|
|
24112
|
+
}
|
|
24113
|
+
deleteCheckpoint(checkpointId) {
|
|
24114
|
+
return this.checkpoints.delete(checkpointId);
|
|
24115
|
+
}
|
|
24116
|
+
pruneCheckpoints() {
|
|
24117
|
+
const all = Array.from(this.checkpoints.values()).sort(
|
|
24118
|
+
(a, b) => a.timestamp - b.timestamp
|
|
24119
|
+
);
|
|
24120
|
+
while (all.length > this.maxCheckpoints) {
|
|
24121
|
+
const oldest = all.shift();
|
|
24122
|
+
if (oldest) this.checkpoints.delete(oldest.id);
|
|
24123
|
+
}
|
|
24124
|
+
}
|
|
24125
|
+
};
|
|
24126
|
+
|
|
24127
|
+
export { AGENTS_BY_PHASE, AGENT_CATALOG, AISpecBuilder, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, Agent, AgentError, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutoPhaseRunner, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, CONTEXT_WINDOW_MODES, CheckpointManager, ConfigError, ConfigMigrationError, Container, Context, ConversationState, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_CONFIG, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_MAX_ITERATIONS, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SPEC_TEMPLATE, DEFAULT_SUBAGENT_BASELINE, DEFAULT_TOOLS_CONFIG, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPathResolver, DefaultPermissionPolicy, DefaultPluginAPI, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultTaskStore, DefaultTokenCounter, Director, DirectorStateCheckpoint, DoneConditionChecker, ERROR_CODES, EternalAutonomyEngine, EventBus, ExtensionRegistry, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, FsError, GitignoreUpdater, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, InputBuilder, IntelligentCompactor, KERNEL_API_VERSION, LAYER_1_IDENTITY, LLMSelector, MAX_JOURNAL_ENTRIES, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, ParallelEternalEngine, PhaseGraphBuilder, PhaseOrchestrator, PhaseStore, Pipeline, PluginError, ProviderError, ProviderRegistry, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, ReportGenerator, RunController, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, ScopedEventBus, SddParallelRun, SddTaskDecomposer, SecurityScanner, SecurityScannerOrchestrator, SelectiveCompactor, SessionAnalyzer, SessionError, SkillGenerator, SkillInstaller, SkillManifestStore, SlashCommandRegistry, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TOKENS, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, TechStackDetector, ToolError, ToolExecutor, ToolRegistry, WrongStackError, addPlanItem, allServers, analyzeCriticalPath, appendJournal, applyRosterBudget, asBlocks, asText, atomicWrite, attachAutoExtend, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildBtwBlock, buildChildEnv, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, buildRecoveryStrategies, classifyFamily, clearPlan, color, compileGlob, compileUserRegex, composeDirectorPrompt, composeSubagentPrompt, computeTaskProgress, consumeBtwNotes, context7Server, contextManagerTool, createAutoExecutor, createAutoPhaseFromTaskGraph, createContextManagerTool, createDefaultPipelines, createDelegateTool, createMcpControlTool, createMessage, createSecuritySlashCommand, createToolOutputSerializer, decryptConfigSecrets, defaultGitignoreUpdater, defaultOrchestrator, defaultReportGenerator, defaultSecurityScanner, defaultSkillGenerator, defaultTechStackDetector, deriveTodosFromPlanItem, detectNewlineStyle, dispatchAgent, downloadGitHubTarball, emptyGoal, emptyPlan, encryptConfigSecrets, ensureDir, estimateRequestTokens, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, everArtServer, extractRunEnv, filesystemServer, findCriticalPath, formatContextWindowModeList, formatGoal, formatPlan, formatPlanTemplates, formatTodosList, getAgentDefinition, getContextWindowMode, getPlanTemplate, getTemplate, githubServer, goalFilePath, googleMapsServer, isAgentError, isConfigError, isContextWindowModeId, isFsError, isImageBlock, isPluginError, isSessionError, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isWrongStackError, listContextWindowModes, listPlanTemplates, listTemplates, loadDirectorState, loadGoal, loadPlan, loadPlugins, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAutonomyPromptContributor, makeContinueToNextIterationTool, makeDirectorSessionFactory, makeLLMClassifier, matchAny, matchGlob, migratePlaintextSecrets, miniMaxVisionServer, normalizeToLf, parseContinueDirective, parseSkillRef, pendingBtwCount, projectHash, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, repairToolUseAdjacency, resolveContextWindowPolicy, resolveWstackPaths, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, safeParse, safeStringify, sanitizeJsonString, saveGoal, savePlan, saveTodosCheckpoint, scoreAgents, securitySlashCommand, sentinelServer, setBtwNote, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, stripAnsi, summarizeUsage, templateToMarkdown, toStyle, toWrongStackError, topologicalSort, unifiedDiff, unloadPlugins, validateAgainstSchema, wireMetricsToEvents, wrapAsState, zaiVisionServer };
|
|
23265
24128
|
//# sourceMappingURL=index.js.map
|
|
23266
24129
|
//# sourceMappingURL=index.js.map
|