opencode-swarm 6.17.2 → 6.17.3
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/cli/index.js +31 -25
- package/dist/evidence/index.d.ts +1 -0
- package/dist/evidence/manager.d.ts +17 -2
- package/dist/index.js +88 -47
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -14278,15 +14278,16 @@ async function loadEvidence(directory, taskId) {
|
|
|
14278
14278
|
validateSwarmPath(directory, relativePath);
|
|
14279
14279
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
14280
14280
|
if (content === null) {
|
|
14281
|
-
return
|
|
14281
|
+
return { status: "not_found" };
|
|
14282
14282
|
}
|
|
14283
14283
|
try {
|
|
14284
14284
|
const parsed = JSON.parse(content);
|
|
14285
14285
|
const validated = EvidenceBundleSchema.parse(parsed);
|
|
14286
|
-
return validated;
|
|
14286
|
+
return { status: "found", bundle: validated };
|
|
14287
14287
|
} catch (error49) {
|
|
14288
14288
|
warn(`Evidence bundle validation failed for task ${sanitizedTaskId}: ${error49 instanceof Error ? error49.message : String(error49)}`);
|
|
14289
|
-
|
|
14289
|
+
const errors3 = error49 instanceof ZodError ? error49.issues.map((e) => e.path.join(".") + ": " + e.message) : [String(error49)];
|
|
14290
|
+
return { status: "invalid_schema", errors: errors3 };
|
|
14290
14291
|
}
|
|
14291
14292
|
}
|
|
14292
14293
|
async function listEvidenceTaskIds(directory) {
|
|
@@ -14345,11 +14346,11 @@ async function archiveEvidence(directory, maxAgeDays, maxBundles) {
|
|
|
14345
14346
|
const archived = [];
|
|
14346
14347
|
const remainingBundles = [];
|
|
14347
14348
|
for (const taskId of taskIds) {
|
|
14348
|
-
const
|
|
14349
|
-
if (
|
|
14349
|
+
const result = await loadEvidence(directory, taskId);
|
|
14350
|
+
if (result.status !== "found") {
|
|
14350
14351
|
continue;
|
|
14351
14352
|
}
|
|
14352
|
-
if (bundle.updated_at < cutoffIso) {
|
|
14353
|
+
if (result.bundle.updated_at < cutoffIso) {
|
|
14353
14354
|
const deleted = await deleteEvidence(directory, taskId);
|
|
14354
14355
|
if (deleted) {
|
|
14355
14356
|
archived.push(taskId);
|
|
@@ -14357,7 +14358,7 @@ async function archiveEvidence(directory, maxAgeDays, maxBundles) {
|
|
|
14357
14358
|
} else {
|
|
14358
14359
|
remainingBundles.push({
|
|
14359
14360
|
taskId,
|
|
14360
|
-
updatedAt: bundle.updated_at
|
|
14361
|
+
updatedAt: result.bundle.updated_at
|
|
14361
14362
|
});
|
|
14362
14363
|
}
|
|
14363
14364
|
}
|
|
@@ -14375,6 +14376,7 @@ async function archiveEvidence(directory, maxAgeDays, maxBundles) {
|
|
|
14375
14376
|
}
|
|
14376
14377
|
var VALID_EVIDENCE_TYPES, TASK_ID_REGEX;
|
|
14377
14378
|
var init_manager = __esm(() => {
|
|
14379
|
+
init_zod();
|
|
14378
14380
|
init_evidence_schema();
|
|
14379
14381
|
init_utils2();
|
|
14380
14382
|
init_utils();
|
|
@@ -17091,7 +17093,8 @@ function getTaskBlockers(task, summary, status) {
|
|
|
17091
17093
|
return blockers;
|
|
17092
17094
|
}
|
|
17093
17095
|
async function buildTaskSummary(task, taskId) {
|
|
17094
|
-
const
|
|
17096
|
+
const result = await loadEvidence(".", taskId);
|
|
17097
|
+
const bundle = result.status === "found" ? result.bundle : null;
|
|
17095
17098
|
const phase = task?.phase ?? 0;
|
|
17096
17099
|
const status = getTaskStatus(task, bundle);
|
|
17097
17100
|
const evidenceCheck = isEvidenceComplete(bundle);
|
|
@@ -18040,11 +18043,14 @@ async function handleArchiveCommand(directory, args) {
|
|
|
18040
18043
|
const wouldArchiveAge = [];
|
|
18041
18044
|
const remainingBundles = [];
|
|
18042
18045
|
for (const taskId of beforeTaskIds) {
|
|
18043
|
-
const
|
|
18044
|
-
if (
|
|
18046
|
+
const result = await loadEvidence(directory, taskId);
|
|
18047
|
+
if (result.status !== "found") {
|
|
18048
|
+
continue;
|
|
18049
|
+
}
|
|
18050
|
+
if (result.bundle.updated_at < cutoffIso) {
|
|
18045
18051
|
wouldArchiveAge.push(taskId);
|
|
18046
|
-
} else
|
|
18047
|
-
remainingBundles.push({ taskId, updatedAt: bundle.updated_at });
|
|
18052
|
+
} else {
|
|
18053
|
+
remainingBundles.push({ taskId, updatedAt: result.bundle.updated_at });
|
|
18048
18054
|
}
|
|
18049
18055
|
}
|
|
18050
18056
|
const wouldArchiveMaxBundles = [];
|
|
@@ -18161,10 +18167,10 @@ async function handleBenchmarkCommand(directory, args) {
|
|
|
18161
18167
|
let totalTestToCodeRatio = 0;
|
|
18162
18168
|
let qualityEvidenceCount = 0;
|
|
18163
18169
|
for (const tid of await listEvidenceTaskIds(directory)) {
|
|
18164
|
-
const
|
|
18165
|
-
if (
|
|
18170
|
+
const result = await loadEvidence(directory, tid);
|
|
18171
|
+
if (result.status !== "found")
|
|
18166
18172
|
continue;
|
|
18167
|
-
for (const e of
|
|
18173
|
+
for (const e of result.bundle.entries) {
|
|
18168
18174
|
if (!isValidEvidenceType(e.type)) {
|
|
18169
18175
|
warn(`Unknown evidence type '${e.type}' in task ${tid}, skipping`);
|
|
18170
18176
|
continue;
|
|
@@ -19426,8 +19432,8 @@ function getVerdictEmoji(verdict) {
|
|
|
19426
19432
|
return getVerdictIcon(verdict);
|
|
19427
19433
|
}
|
|
19428
19434
|
async function getTaskEvidenceData(directory, taskId) {
|
|
19429
|
-
const
|
|
19430
|
-
if (
|
|
19435
|
+
const result = await loadEvidence(directory, taskId);
|
|
19436
|
+
if (result.status !== "found") {
|
|
19431
19437
|
return {
|
|
19432
19438
|
hasEvidence: false,
|
|
19433
19439
|
taskId,
|
|
@@ -19437,14 +19443,14 @@ async function getTaskEvidenceData(directory, taskId) {
|
|
|
19437
19443
|
};
|
|
19438
19444
|
}
|
|
19439
19445
|
const entries = [];
|
|
19440
|
-
for (let i = 0;i < bundle.entries.length; i++) {
|
|
19441
|
-
entries.push(formatEvidenceEntry(i + 1, bundle.entries[i]));
|
|
19446
|
+
for (let i = 0;i < result.bundle.entries.length; i++) {
|
|
19447
|
+
entries.push(formatEvidenceEntry(i + 1, result.bundle.entries[i]));
|
|
19442
19448
|
}
|
|
19443
19449
|
return {
|
|
19444
19450
|
hasEvidence: true,
|
|
19445
19451
|
taskId,
|
|
19446
|
-
createdAt: bundle.created_at,
|
|
19447
|
-
updatedAt: bundle.updated_at,
|
|
19452
|
+
createdAt: result.bundle.created_at,
|
|
19453
|
+
updatedAt: result.bundle.updated_at,
|
|
19448
19454
|
entries
|
|
19449
19455
|
};
|
|
19450
19456
|
}
|
|
@@ -19455,12 +19461,12 @@ async function getEvidenceListData(directory) {
|
|
|
19455
19461
|
}
|
|
19456
19462
|
const tasks = [];
|
|
19457
19463
|
for (const taskId of taskIds) {
|
|
19458
|
-
const
|
|
19459
|
-
if (
|
|
19464
|
+
const result = await loadEvidence(directory, taskId);
|
|
19465
|
+
if (result.status === "found") {
|
|
19460
19466
|
tasks.push({
|
|
19461
19467
|
taskId,
|
|
19462
|
-
entryCount: bundle.entries.length,
|
|
19463
|
-
lastUpdated: bundle.updated_at
|
|
19468
|
+
entryCount: result.bundle.entries.length,
|
|
19469
|
+
lastUpdated: result.bundle.updated_at
|
|
19464
19470
|
});
|
|
19465
19471
|
} else {
|
|
19466
19472
|
tasks.push({
|
package/dist/evidence/index.d.ts
CHANGED
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
import { type BuildEvidence, type Evidence, type EvidenceBundle, type PlaceholderEvidence, type QualityBudgetEvidence, type SastEvidence, type SbomEvidence, type SyntaxEvidence } from '../config/evidence-schema';
|
|
2
|
+
/**
|
|
3
|
+
* Discriminated union returned by loadEvidence.
|
|
4
|
+
* - 'found': file exists and passed Zod schema validation
|
|
5
|
+
* - 'not_found': file does not exist on disk
|
|
6
|
+
* - 'invalid_schema': file exists but failed Zod validation; errors contains field names
|
|
7
|
+
*/
|
|
8
|
+
export type LoadEvidenceResult = {
|
|
9
|
+
status: 'found';
|
|
10
|
+
bundle: EvidenceBundle;
|
|
11
|
+
} | {
|
|
12
|
+
status: 'not_found';
|
|
13
|
+
} | {
|
|
14
|
+
status: 'invalid_schema';
|
|
15
|
+
errors: string[];
|
|
16
|
+
};
|
|
2
17
|
/**
|
|
3
18
|
* All valid evidence types (12 total)
|
|
4
19
|
*/
|
|
@@ -33,9 +48,9 @@ export declare function sanitizeTaskId(taskId: string): string;
|
|
|
33
48
|
export declare function saveEvidence(directory: string, taskId: string, evidence: Evidence): Promise<EvidenceBundle>;
|
|
34
49
|
/**
|
|
35
50
|
* Load evidence bundle for a task.
|
|
36
|
-
* Returns
|
|
51
|
+
* Returns a LoadEvidenceResult discriminated union.
|
|
37
52
|
*/
|
|
38
|
-
export declare function loadEvidence(directory: string, taskId: string): Promise<
|
|
53
|
+
export declare function loadEvidence(directory: string, taskId: string): Promise<LoadEvidenceResult>;
|
|
39
54
|
/**
|
|
40
55
|
* List all task IDs that have evidence bundles.
|
|
41
56
|
* Returns sorted array of valid task IDs.
|
package/dist/index.js
CHANGED
|
@@ -14496,15 +14496,16 @@ async function loadEvidence(directory, taskId) {
|
|
|
14496
14496
|
validateSwarmPath(directory, relativePath);
|
|
14497
14497
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
14498
14498
|
if (content === null) {
|
|
14499
|
-
return
|
|
14499
|
+
return { status: "not_found" };
|
|
14500
14500
|
}
|
|
14501
14501
|
try {
|
|
14502
14502
|
const parsed = JSON.parse(content);
|
|
14503
14503
|
const validated = EvidenceBundleSchema.parse(parsed);
|
|
14504
|
-
return validated;
|
|
14504
|
+
return { status: "found", bundle: validated };
|
|
14505
14505
|
} catch (error49) {
|
|
14506
14506
|
warn(`Evidence bundle validation failed for task ${sanitizedTaskId}: ${error49 instanceof Error ? error49.message : String(error49)}`);
|
|
14507
|
-
|
|
14507
|
+
const errors3 = error49 instanceof ZodError ? error49.issues.map((e) => e.path.join(".") + ": " + e.message) : [String(error49)];
|
|
14508
|
+
return { status: "invalid_schema", errors: errors3 };
|
|
14508
14509
|
}
|
|
14509
14510
|
}
|
|
14510
14511
|
async function listEvidenceTaskIds(directory) {
|
|
@@ -14563,11 +14564,11 @@ async function archiveEvidence(directory, maxAgeDays, maxBundles) {
|
|
|
14563
14564
|
const archived = [];
|
|
14564
14565
|
const remainingBundles = [];
|
|
14565
14566
|
for (const taskId of taskIds) {
|
|
14566
|
-
const
|
|
14567
|
-
if (
|
|
14567
|
+
const result = await loadEvidence(directory, taskId);
|
|
14568
|
+
if (result.status !== "found") {
|
|
14568
14569
|
continue;
|
|
14569
14570
|
}
|
|
14570
|
-
if (bundle.updated_at < cutoffIso) {
|
|
14571
|
+
if (result.bundle.updated_at < cutoffIso) {
|
|
14571
14572
|
const deleted = await deleteEvidence(directory, taskId);
|
|
14572
14573
|
if (deleted) {
|
|
14573
14574
|
archived.push(taskId);
|
|
@@ -14575,7 +14576,7 @@ async function archiveEvidence(directory, maxAgeDays, maxBundles) {
|
|
|
14575
14576
|
} else {
|
|
14576
14577
|
remainingBundles.push({
|
|
14577
14578
|
taskId,
|
|
14578
|
-
updatedAt: bundle.updated_at
|
|
14579
|
+
updatedAt: result.bundle.updated_at
|
|
14579
14580
|
});
|
|
14580
14581
|
}
|
|
14581
14582
|
}
|
|
@@ -14593,6 +14594,7 @@ async function archiveEvidence(directory, maxAgeDays, maxBundles) {
|
|
|
14593
14594
|
}
|
|
14594
14595
|
var VALID_EVIDENCE_TYPES, TASK_ID_REGEX;
|
|
14595
14596
|
var init_manager = __esm(() => {
|
|
14597
|
+
init_zod();
|
|
14596
14598
|
init_evidence_schema();
|
|
14597
14599
|
init_utils2();
|
|
14598
14600
|
init_utils();
|
|
@@ -15108,7 +15110,8 @@ function getTaskBlockers(task, summary, status) {
|
|
|
15108
15110
|
return blockers;
|
|
15109
15111
|
}
|
|
15110
15112
|
async function buildTaskSummary(task, taskId) {
|
|
15111
|
-
const
|
|
15113
|
+
const result = await loadEvidence(".", taskId);
|
|
15114
|
+
const bundle = result.status === "found" ? result.bundle : null;
|
|
15112
15115
|
const phase = task?.phase ?? 0;
|
|
15113
15116
|
const status = getTaskStatus(task, bundle);
|
|
15114
15117
|
const evidenceCheck = isEvidenceComplete(bundle);
|
|
@@ -41296,11 +41299,14 @@ async function handleArchiveCommand(directory, args2) {
|
|
|
41296
41299
|
const wouldArchiveAge = [];
|
|
41297
41300
|
const remainingBundles = [];
|
|
41298
41301
|
for (const taskId of beforeTaskIds) {
|
|
41299
|
-
const
|
|
41300
|
-
if (
|
|
41302
|
+
const result = await loadEvidence(directory, taskId);
|
|
41303
|
+
if (result.status !== "found") {
|
|
41304
|
+
continue;
|
|
41305
|
+
}
|
|
41306
|
+
if (result.bundle.updated_at < cutoffIso) {
|
|
41301
41307
|
wouldArchiveAge.push(taskId);
|
|
41302
|
-
} else
|
|
41303
|
-
remainingBundles.push({ taskId, updatedAt: bundle.updated_at });
|
|
41308
|
+
} else {
|
|
41309
|
+
remainingBundles.push({ taskId, updatedAt: result.bundle.updated_at });
|
|
41304
41310
|
}
|
|
41305
41311
|
}
|
|
41306
41312
|
const wouldArchiveMaxBundles = [];
|
|
@@ -41598,10 +41604,10 @@ async function handleBenchmarkCommand(directory, args2) {
|
|
|
41598
41604
|
let totalTestToCodeRatio = 0;
|
|
41599
41605
|
let qualityEvidenceCount = 0;
|
|
41600
41606
|
for (const tid of await listEvidenceTaskIds(directory)) {
|
|
41601
|
-
const
|
|
41602
|
-
if (
|
|
41607
|
+
const result = await loadEvidence(directory, tid);
|
|
41608
|
+
if (result.status !== "found")
|
|
41603
41609
|
continue;
|
|
41604
|
-
for (const e of
|
|
41610
|
+
for (const e of result.bundle.entries) {
|
|
41605
41611
|
if (!isValidEvidenceType(e.type)) {
|
|
41606
41612
|
warn(`Unknown evidence type '${e.type}' in task ${tid}, skipping`);
|
|
41607
41613
|
continue;
|
|
@@ -42906,8 +42912,8 @@ function getVerdictEmoji(verdict) {
|
|
|
42906
42912
|
return getVerdictIcon(verdict);
|
|
42907
42913
|
}
|
|
42908
42914
|
async function getTaskEvidenceData(directory, taskId) {
|
|
42909
|
-
const
|
|
42910
|
-
if (
|
|
42915
|
+
const result = await loadEvidence(directory, taskId);
|
|
42916
|
+
if (result.status !== "found") {
|
|
42911
42917
|
return {
|
|
42912
42918
|
hasEvidence: false,
|
|
42913
42919
|
taskId,
|
|
@@ -42917,14 +42923,14 @@ async function getTaskEvidenceData(directory, taskId) {
|
|
|
42917
42923
|
};
|
|
42918
42924
|
}
|
|
42919
42925
|
const entries = [];
|
|
42920
|
-
for (let i2 = 0;i2 < bundle.entries.length; i2++) {
|
|
42921
|
-
entries.push(formatEvidenceEntry(i2 + 1, bundle.entries[i2]));
|
|
42926
|
+
for (let i2 = 0;i2 < result.bundle.entries.length; i2++) {
|
|
42927
|
+
entries.push(formatEvidenceEntry(i2 + 1, result.bundle.entries[i2]));
|
|
42922
42928
|
}
|
|
42923
42929
|
return {
|
|
42924
42930
|
hasEvidence: true,
|
|
42925
42931
|
taskId,
|
|
42926
|
-
createdAt: bundle.created_at,
|
|
42927
|
-
updatedAt: bundle.updated_at,
|
|
42932
|
+
createdAt: result.bundle.created_at,
|
|
42933
|
+
updatedAt: result.bundle.updated_at,
|
|
42928
42934
|
entries
|
|
42929
42935
|
};
|
|
42930
42936
|
}
|
|
@@ -42935,12 +42941,12 @@ async function getEvidenceListData(directory) {
|
|
|
42935
42941
|
}
|
|
42936
42942
|
const tasks = [];
|
|
42937
42943
|
for (const taskId of taskIds) {
|
|
42938
|
-
const
|
|
42939
|
-
if (
|
|
42944
|
+
const result = await loadEvidence(directory, taskId);
|
|
42945
|
+
if (result.status === "found") {
|
|
42940
42946
|
tasks.push({
|
|
42941
42947
|
taskId,
|
|
42942
|
-
entryCount: bundle.entries.length,
|
|
42943
|
-
lastUpdated: bundle.updated_at
|
|
42948
|
+
entryCount: result.bundle.entries.length,
|
|
42949
|
+
lastUpdated: result.bundle.updated_at
|
|
42944
42950
|
});
|
|
42945
42951
|
} else {
|
|
42946
42952
|
tasks.push({
|
|
@@ -45108,7 +45114,7 @@ function logFirstCall(modelID, providerID, source, limit) {
|
|
|
45108
45114
|
const key = `${modelID || "unknown"}::${providerID || "unknown"}`;
|
|
45109
45115
|
if (!loggedFirstCalls.has(key)) {
|
|
45110
45116
|
loggedFirstCalls.add(key);
|
|
45111
|
-
|
|
45117
|
+
log(`[model-limits] Resolved limit for ${modelID || "(no model)"}@${providerID || "(no provider)"}: ${limit} (source: ${source})`);
|
|
45112
45118
|
}
|
|
45113
45119
|
}
|
|
45114
45120
|
|
|
@@ -45133,7 +45139,7 @@ function createContextBudgetHandler(config3) {
|
|
|
45133
45139
|
const cacheKey = `${modelID || "unknown"}::${providerID || "unknown"}`;
|
|
45134
45140
|
if (!loggedLimits.has(cacheKey)) {
|
|
45135
45141
|
loggedLimits.add(cacheKey);
|
|
45136
|
-
|
|
45142
|
+
log(`[swarm] Context budget: model=${modelID || "unknown"} provider=${providerID || "unknown"} limit=${modelLimit}`);
|
|
45137
45143
|
}
|
|
45138
45144
|
let totalTokens = 0;
|
|
45139
45145
|
for (const message of messages) {
|
|
@@ -46610,9 +46616,9 @@ async function buildRetroInjection(directory, currentPhaseNumber, currentPlanTit
|
|
|
46610
46616
|
try {
|
|
46611
46617
|
const prevPhase = currentPhaseNumber - 1;
|
|
46612
46618
|
if (prevPhase >= 1) {
|
|
46613
|
-
const
|
|
46614
|
-
if (
|
|
46615
|
-
const retroEntry = bundle.entries.find((entry) => entry.type === "retrospective");
|
|
46619
|
+
const result1 = await loadEvidence(directory, `retro-${prevPhase}`);
|
|
46620
|
+
if (result1.status === "found" && result1.bundle.entries.length > 0) {
|
|
46621
|
+
const retroEntry = result1.bundle.entries.find((entry) => entry.type === "retrospective");
|
|
46616
46622
|
if (retroEntry && retroEntry.verdict !== "fail") {
|
|
46617
46623
|
const lessons = retroEntry.lessons_learned ?? [];
|
|
46618
46624
|
const rejections = retroEntry.top_rejection_reasons ?? [];
|
|
@@ -46640,9 +46646,9 @@ ${top5.map((d) => `- [${d.category}] ${d.directive}`).join(`
|
|
|
46640
46646
|
const retroIds = taskIds.filter((id) => id.startsWith("retro-"));
|
|
46641
46647
|
let latestRetro = null;
|
|
46642
46648
|
for (const taskId of retroIds) {
|
|
46643
|
-
const
|
|
46644
|
-
if (
|
|
46645
|
-
for (const entry of
|
|
46649
|
+
const r = await loadEvidence(directory, taskId);
|
|
46650
|
+
if (r.status === "found" && r.bundle.entries.length > 0) {
|
|
46651
|
+
for (const entry of r.bundle.entries) {
|
|
46646
46652
|
if (entry.type === "retrospective") {
|
|
46647
46653
|
const retro = entry;
|
|
46648
46654
|
if (retro.verdict !== "fail") {
|
|
@@ -46689,16 +46695,16 @@ ${top5.map((d) => `- [${d.category}] ${d.directive}`).join(`
|
|
|
46689
46695
|
const now = Date.now();
|
|
46690
46696
|
for (const taskId of allRetroIds) {
|
|
46691
46697
|
const b = await loadEvidence(directory, taskId);
|
|
46692
|
-
if (
|
|
46698
|
+
if (b.status !== "found")
|
|
46693
46699
|
continue;
|
|
46694
|
-
for (const e of b.entries) {
|
|
46700
|
+
for (const e of b.bundle.entries) {
|
|
46695
46701
|
if (e.type === "retrospective") {
|
|
46696
46702
|
const retro = e;
|
|
46697
46703
|
if (retro.verdict === "fail")
|
|
46698
46704
|
continue;
|
|
46699
46705
|
if (currentPlanTitle && typeof retro.metadata === "object" && retro.metadata !== null && "plan_id" in retro.metadata && retro.metadata.plan_id === currentPlanTitle)
|
|
46700
46706
|
continue;
|
|
46701
|
-
const ts = retro.timestamp ?? b.created_at;
|
|
46707
|
+
const ts = retro.timestamp ?? b.bundle.created_at;
|
|
46702
46708
|
const ageMs = now - new Date(ts).getTime();
|
|
46703
46709
|
if (isNaN(ageMs) || ageMs > cutoffMs)
|
|
46704
46710
|
continue;
|
|
@@ -46754,10 +46760,10 @@ async function buildCoderRetroInjection(directory, currentPhaseNumber) {
|
|
|
46754
46760
|
const prevPhase = currentPhaseNumber - 1;
|
|
46755
46761
|
if (prevPhase < 1)
|
|
46756
46762
|
return null;
|
|
46757
|
-
const
|
|
46758
|
-
if (
|
|
46763
|
+
const result = await loadEvidence(directory, `retro-${prevPhase}`);
|
|
46764
|
+
if (result.status !== "found" || result.bundle.entries.length === 0)
|
|
46759
46765
|
return null;
|
|
46760
|
-
const retroEntry = bundle.entries.find((entry) => entry.type === "retrospective");
|
|
46766
|
+
const retroEntry = result.bundle.entries.find((entry) => entry.type === "retrospective");
|
|
46761
46767
|
if (!retroEntry || retroEntry.verdict === "fail")
|
|
46762
46768
|
return null;
|
|
46763
46769
|
const lessons = retroEntry.lessons_learned ?? [];
|
|
@@ -50178,34 +50184,69 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
50178
50184
|
warnings: []
|
|
50179
50185
|
}, null, 2);
|
|
50180
50186
|
}
|
|
50181
|
-
const
|
|
50187
|
+
const retroResult = await loadEvidence(dir, `retro-${phase}`);
|
|
50182
50188
|
let retroFound = false;
|
|
50183
|
-
|
|
50184
|
-
|
|
50189
|
+
let invalidSchemaErrors = [];
|
|
50190
|
+
if (retroResult.status === "found") {
|
|
50191
|
+
retroFound = retroResult.bundle.entries?.some((entry) => isValidRetroEntry(entry, phase)) ?? false;
|
|
50192
|
+
} else if (retroResult.status === "invalid_schema") {
|
|
50193
|
+
invalidSchemaErrors = retroResult.errors;
|
|
50185
50194
|
}
|
|
50186
50195
|
if (!retroFound) {
|
|
50187
50196
|
const allTaskIds = await listEvidenceTaskIds(dir);
|
|
50188
50197
|
const retroTaskIds = allTaskIds.filter((id) => id.startsWith("retro-"));
|
|
50189
50198
|
for (const taskId of retroTaskIds) {
|
|
50190
|
-
const
|
|
50191
|
-
if (
|
|
50199
|
+
const bundleResult = await loadEvidence(dir, taskId);
|
|
50200
|
+
if (bundleResult.status !== "found") {
|
|
50201
|
+
if (bundleResult.status === "invalid_schema") {
|
|
50202
|
+
invalidSchemaErrors.push(...bundleResult.errors);
|
|
50203
|
+
}
|
|
50192
50204
|
continue;
|
|
50193
|
-
|
|
50205
|
+
}
|
|
50206
|
+
retroFound = bundleResult.bundle.entries?.some((entry) => isValidRetroEntry(entry, phase)) ?? false;
|
|
50194
50207
|
if (retroFound)
|
|
50195
50208
|
break;
|
|
50196
50209
|
}
|
|
50197
50210
|
}
|
|
50198
50211
|
if (!retroFound) {
|
|
50212
|
+
const schemaErrorDetail = invalidSchemaErrors.length > 0 ? ` Schema validation failed: ${invalidSchemaErrors.join("; ")}.` : "";
|
|
50199
50213
|
return JSON.stringify({
|
|
50200
50214
|
success: false,
|
|
50201
50215
|
phase,
|
|
50202
50216
|
status: "blocked",
|
|
50203
50217
|
reason: "RETROSPECTIVE_MISSING",
|
|
50204
|
-
message: `Phase ${phase} cannot be completed: no valid retrospective evidence found
|
|
50218
|
+
message: `Phase ${phase} cannot be completed: no valid retrospective evidence found.${schemaErrorDetail} Write a retrospective bundle at .swarm/evidence/retro-${phase}/evidence.json before calling phase_complete.`,
|
|
50205
50219
|
agentsDispatched: [],
|
|
50206
50220
|
agentsMissing: [],
|
|
50207
50221
|
warnings: [
|
|
50208
|
-
`Retrospective missing for phase ${phase}
|
|
50222
|
+
`Retrospective missing for phase ${phase}.${schemaErrorDetail} Use this template:`,
|
|
50223
|
+
JSON.stringify({
|
|
50224
|
+
schema_version: "1.0.0",
|
|
50225
|
+
task_id: `retro-${phase}`,
|
|
50226
|
+
created_at: new Date().toISOString(),
|
|
50227
|
+
updated_at: new Date().toISOString(),
|
|
50228
|
+
entries: [
|
|
50229
|
+
{
|
|
50230
|
+
task_id: `retro-${phase}`,
|
|
50231
|
+
type: "retrospective",
|
|
50232
|
+
timestamp: new Date().toISOString(),
|
|
50233
|
+
agent: "architect",
|
|
50234
|
+
verdict: "pass",
|
|
50235
|
+
summary: `Phase ${phase} completed.`,
|
|
50236
|
+
phase_number: phase,
|
|
50237
|
+
total_tool_calls: 0,
|
|
50238
|
+
coder_revisions: 0,
|
|
50239
|
+
reviewer_rejections: 0,
|
|
50240
|
+
test_failures: 0,
|
|
50241
|
+
security_findings: 0,
|
|
50242
|
+
integration_issues: 0,
|
|
50243
|
+
task_count: 1,
|
|
50244
|
+
task_complexity: "simple",
|
|
50245
|
+
top_rejection_reasons: [],
|
|
50246
|
+
lessons_learned: []
|
|
50247
|
+
}
|
|
50248
|
+
]
|
|
50249
|
+
}, null, 2)
|
|
50209
50250
|
]
|
|
50210
50251
|
}, null, 2);
|
|
50211
50252
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "6.17.
|
|
3
|
+
"version": "6.17.3",
|
|
4
4
|
"description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|