opencode-swarm 7.23.1 → 7.24.1
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 +84 -42
- package/dist/hooks/hive-promoter.d.ts +12 -0
- package/dist/index.js +113 -51
- package/dist/tools/knowledge-query.d.ts +6 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -34,7 +34,7 @@ var package_default;
|
|
|
34
34
|
var init_package = __esm(() => {
|
|
35
35
|
package_default = {
|
|
36
36
|
name: "opencode-swarm",
|
|
37
|
-
version: "7.
|
|
37
|
+
version: "7.24.1",
|
|
38
38
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
39
39
|
main: "dist/index.js",
|
|
40
40
|
types: "dist/index.d.ts",
|
|
@@ -34292,6 +34292,14 @@ function gitExec(args) {
|
|
|
34292
34292
|
}
|
|
34293
34293
|
return result.stdout;
|
|
34294
34294
|
}
|
|
34295
|
+
function appendRetentionEvent(directory, event) {
|
|
34296
|
+
try {
|
|
34297
|
+
const eventsPath = path9.join(directory, ".swarm", "events.jsonl");
|
|
34298
|
+
const line = `${JSON.stringify({ ...event, timestamp: new Date().toISOString() })}
|
|
34299
|
+
`;
|
|
34300
|
+
fs6.appendFileSync(eventsPath, line);
|
|
34301
|
+
} catch {}
|
|
34302
|
+
}
|
|
34295
34303
|
function getCurrentSha() {
|
|
34296
34304
|
const output = gitExec(["rev-parse", "HEAD"]);
|
|
34297
34305
|
return output.trim();
|
|
@@ -34343,6 +34351,17 @@ function handleSave(label, directory) {
|
|
|
34343
34351
|
sha: newSha,
|
|
34344
34352
|
timestamp
|
|
34345
34353
|
});
|
|
34354
|
+
if (log2.checkpoints.length > maxCheckpoints) {
|
|
34355
|
+
const evicted = log2.checkpoints.splice(0, log2.checkpoints.length - maxCheckpoints);
|
|
34356
|
+
try {
|
|
34357
|
+
appendRetentionEvent(directory, {
|
|
34358
|
+
event: "checkpoint_retention_applied",
|
|
34359
|
+
evicted_labels: evicted.map((e) => e.label),
|
|
34360
|
+
evicted_count: evicted.length,
|
|
34361
|
+
remaining_count: log2.checkpoints.length
|
|
34362
|
+
});
|
|
34363
|
+
} catch {}
|
|
34364
|
+
}
|
|
34346
34365
|
writeCheckpointLog(log2, directory);
|
|
34347
34366
|
return JSON.stringify({
|
|
34348
34367
|
action: "save",
|
|
@@ -35248,6 +35267,20 @@ function normalizeEntry(raw) {
|
|
|
35248
35267
|
ro.failed_after_shown_count = typeof ro.failed_after_count === "number" ? ro.failed_after_count : 0;
|
|
35249
35268
|
}
|
|
35250
35269
|
}
|
|
35270
|
+
try {
|
|
35271
|
+
if (typeof obj.encounter_score !== "number" || Number.isNaN(obj.encounter_score)) {
|
|
35272
|
+
obj.encounter_score = 0;
|
|
35273
|
+
}
|
|
35274
|
+
} catch {
|
|
35275
|
+
try {
|
|
35276
|
+
Object.defineProperty(obj, "encounter_score", {
|
|
35277
|
+
value: 0,
|
|
35278
|
+
writable: true,
|
|
35279
|
+
configurable: true,
|
|
35280
|
+
enumerable: true
|
|
35281
|
+
});
|
|
35282
|
+
} catch {}
|
|
35283
|
+
}
|
|
35251
35284
|
const arrayFields = [
|
|
35252
35285
|
"triggers",
|
|
35253
35286
|
"required_actions",
|
|
@@ -35807,12 +35840,26 @@ import path12 from "path";
|
|
|
35807
35840
|
function isAlreadyInHive(entry, hiveEntries, threshold) {
|
|
35808
35841
|
return findNearDuplicate(entry.lesson, hiveEntries, threshold) !== undefined;
|
|
35809
35842
|
}
|
|
35810
|
-
function
|
|
35843
|
+
function isHiveEligible(entry, autoPromoteDays) {
|
|
35811
35844
|
const phaseNumbers = new Set;
|
|
35812
|
-
for (const record3 of
|
|
35813
|
-
|
|
35845
|
+
for (const record3 of entry.confirmed_by ?? []) {
|
|
35846
|
+
if (record3 && typeof record3.phase_number === "number") {
|
|
35847
|
+
phaseNumbers.add(record3.phase_number);
|
|
35848
|
+
}
|
|
35814
35849
|
}
|
|
35815
|
-
|
|
35850
|
+
if (entry.hive_eligible === true && phaseNumbers.size >= 3) {
|
|
35851
|
+
return true;
|
|
35852
|
+
}
|
|
35853
|
+
if ((entry.tags ?? []).includes("hive-fast-track")) {
|
|
35854
|
+
return true;
|
|
35855
|
+
}
|
|
35856
|
+
const createdMs = Date.parse(entry.created_at);
|
|
35857
|
+
const ageMs = Number.isFinite(createdMs) ? Date.now() - createdMs : 0;
|
|
35858
|
+
const ageThresholdMs = autoPromoteDays * 86400000;
|
|
35859
|
+
if (ageMs >= ageThresholdMs) {
|
|
35860
|
+
return true;
|
|
35861
|
+
}
|
|
35862
|
+
return false;
|
|
35816
35863
|
}
|
|
35817
35864
|
function countDistinctProjects(confirmedBy) {
|
|
35818
35865
|
const projectNames = new Set;
|
|
@@ -35830,12 +35877,6 @@ function calculateEncounterScore(currentScore, isSameProject, config3) {
|
|
|
35830
35877
|
const newScore = currentScore + increment;
|
|
35831
35878
|
return Math.min(Math.max(newScore, config3.min_encounter_score), config3.max_encounter_score);
|
|
35832
35879
|
}
|
|
35833
|
-
function getEntryAgeMs(createdAt) {
|
|
35834
|
-
const createdTime = new Date(createdAt).getTime();
|
|
35835
|
-
if (Number.isNaN(createdTime))
|
|
35836
|
-
return 0;
|
|
35837
|
-
return Date.now() - createdTime;
|
|
35838
|
-
}
|
|
35839
35880
|
async function checkHivePromotions(swarmEntries, config3) {
|
|
35840
35881
|
let newPromotions = 0;
|
|
35841
35882
|
let encountersIncremented = 0;
|
|
@@ -35854,19 +35895,7 @@ async function checkHivePromotions(swarmEntries, config3) {
|
|
|
35854
35895
|
if (isAlreadyInHive(swarmEntry, hiveEntries, config3.dedup_threshold)) {
|
|
35855
35896
|
continue;
|
|
35856
35897
|
}
|
|
35857
|
-
|
|
35858
|
-
if (swarmEntry.hive_eligible === true && countDistinctPhases(swarmEntry.confirmed_by) >= 3) {
|
|
35859
|
-
shouldPromote = true;
|
|
35860
|
-
}
|
|
35861
|
-
if (swarmEntry.tags.includes("hive-fast-track")) {
|
|
35862
|
-
shouldPromote = true;
|
|
35863
|
-
}
|
|
35864
|
-
const ageMs = getEntryAgeMs(swarmEntry.created_at);
|
|
35865
|
-
const ageThresholdMs = config3.auto_promote_days * 86400000;
|
|
35866
|
-
if (ageMs >= ageThresholdMs) {
|
|
35867
|
-
shouldPromote = true;
|
|
35868
|
-
}
|
|
35869
|
-
if (!shouldPromote) {
|
|
35898
|
+
if (!isHiveEligible(swarmEntry, config3.auto_promote_days)) {
|
|
35870
35899
|
continue;
|
|
35871
35900
|
}
|
|
35872
35901
|
const validationResult = validateLesson(swarmEntry.lesson, hiveEntries.map((e) => e.lesson), {
|
|
@@ -37784,12 +37813,14 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
37784
37813
|
if (planExists) {
|
|
37785
37814
|
planAlreadyDone = phases.length > 0 && phases.every((p) => p.status === "complete" || p.status === "completed" || p.status === "blocked" || p.status === "closed");
|
|
37786
37815
|
}
|
|
37787
|
-
const
|
|
37816
|
+
const { config: loadedConfig } = loadPluginConfigWithMeta(directory);
|
|
37817
|
+
const config3 = KnowledgeConfigSchema.parse(loadedConfig.knowledge ?? {});
|
|
37788
37818
|
const projectName = planData.title ?? "Unknown Project";
|
|
37789
37819
|
const closedPhases = [];
|
|
37790
37820
|
const closedTasks = [];
|
|
37791
37821
|
const warnings = [];
|
|
37792
37822
|
let hivePromoted = 0;
|
|
37823
|
+
let hiveSkipped = 0;
|
|
37793
37824
|
if (!planAlreadyDone) {
|
|
37794
37825
|
for (const phase of inProgressPhases) {
|
|
37795
37826
|
closedPhases.push(phase.id);
|
|
@@ -37912,23 +37943,35 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
37912
37943
|
await fs7.unlink(lessonsFilePath).catch(() => {});
|
|
37913
37944
|
}
|
|
37914
37945
|
if (curationSucceeded) {
|
|
37915
|
-
|
|
37916
|
-
|
|
37917
|
-
|
|
37918
|
-
|
|
37919
|
-
|
|
37920
|
-
|
|
37921
|
-
|
|
37922
|
-
|
|
37923
|
-
|
|
37924
|
-
|
|
37925
|
-
|
|
37946
|
+
if (config3.hive_enabled === false) {} else {
|
|
37947
|
+
try {
|
|
37948
|
+
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
37949
|
+
const entries = await readKnowledge(knowledgePath);
|
|
37950
|
+
const autoPromoteDays = config3.auto_promote_days;
|
|
37951
|
+
if (entries.length > 0) {
|
|
37952
|
+
for (const entry of entries) {
|
|
37953
|
+
if (!isHiveEligible(entry, autoPromoteDays)) {
|
|
37954
|
+
hiveSkipped++;
|
|
37955
|
+
continue;
|
|
37956
|
+
}
|
|
37957
|
+
try {
|
|
37958
|
+
const result = await promoteToHive(directory, entry.lesson, entry.category);
|
|
37959
|
+
if (!result.includes("already exists")) {
|
|
37960
|
+
hivePromoted++;
|
|
37961
|
+
}
|
|
37962
|
+
} catch (promotionErr) {
|
|
37963
|
+
const msg = promotionErr instanceof Error ? promotionErr.message : String(promotionErr);
|
|
37964
|
+
warnings.push(`Hive promotion skipped for lesson: ${msg}`);
|
|
37965
|
+
}
|
|
37966
|
+
}
|
|
37967
|
+
if (hiveSkipped > 0) {
|
|
37968
|
+
warnings.push(`${hiveSkipped} swarm knowledge entr${hiveSkipped === 1 ? "y" : "ies"} not eligible for hive promotion`);
|
|
37926
37969
|
}
|
|
37927
37970
|
}
|
|
37971
|
+
} catch (hiveErr) {
|
|
37972
|
+
const msg = hiveErr instanceof Error ? hiveErr.message : String(hiveErr);
|
|
37973
|
+
warnings.push(`Hive promotion failed: ${msg}`);
|
|
37928
37974
|
}
|
|
37929
|
-
} catch (hiveErr) {
|
|
37930
|
-
const msg = hiveErr instanceof Error ? hiveErr.message : String(hiveErr);
|
|
37931
|
-
warnings.push(`Hive promotion failed: ${msg}`);
|
|
37932
37975
|
}
|
|
37933
37976
|
}
|
|
37934
37977
|
const fallbackKnowledgeCreated = curationResult?.stored ?? 0;
|
|
@@ -37945,8 +37988,8 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
37945
37988
|
let skillReviewSummary = "";
|
|
37946
37989
|
if (runSkillReview) {
|
|
37947
37990
|
try {
|
|
37948
|
-
const { config:
|
|
37949
|
-
const skillImproverConfig = SkillImproverConfigSchema.parse(
|
|
37991
|
+
const { config: loadedConfig2 } = loadPluginConfigWithMeta(directory);
|
|
37992
|
+
const skillImproverConfig = SkillImproverConfigSchema.parse(loadedConfig2.skill_improver ?? {});
|
|
37950
37993
|
const skillReviewResult = await runAbortableSkillReview({
|
|
37951
37994
|
directory,
|
|
37952
37995
|
config: skillImproverConfig,
|
|
@@ -38311,7 +38354,6 @@ var init_close = __esm(() => {
|
|
|
38311
38354
|
"handoff-prompt.md",
|
|
38312
38355
|
"handoff-consumed.md",
|
|
38313
38356
|
"escalation-report.md",
|
|
38314
|
-
"knowledge.jsonl",
|
|
38315
38357
|
"knowledge-rejected.jsonl",
|
|
38316
38358
|
"repo-graph.json",
|
|
38317
38359
|
"doc-manifest.json",
|
|
@@ -8,6 +8,18 @@ export interface HivePromotionSummary {
|
|
|
8
8
|
advancements: number;
|
|
9
9
|
total_hive_entries: number;
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Check whether a swarm knowledge entry is eligible for hive promotion.
|
|
13
|
+
* Three routes to eligibility:
|
|
14
|
+
* Route 1: hive_eligible flag + 3+ distinct phases
|
|
15
|
+
* Route 2: 'hive-fast-track' tag
|
|
16
|
+
* Route 3: age exceeds auto_promote_days threshold
|
|
17
|
+
*
|
|
18
|
+
* @param entry - The swarm knowledge entry to check
|
|
19
|
+
* @param autoPromoteDays - Number of days before age-based promotion kicks in
|
|
20
|
+
* @returns true if the entry is eligible for hive promotion
|
|
21
|
+
*/
|
|
22
|
+
export declare function isHiveEligible(entry: SwarmKnowledgeEntry, autoPromoteDays: number): boolean;
|
|
11
23
|
/**
|
|
12
24
|
* Main promotion logic: checks swarm entries and promotes eligible ones to hive.
|
|
13
25
|
* Also updates existing hive entries with new project confirmations.
|
package/dist/index.js
CHANGED
|
@@ -33,7 +33,7 @@ var package_default;
|
|
|
33
33
|
var init_package = __esm(() => {
|
|
34
34
|
package_default = {
|
|
35
35
|
name: "opencode-swarm",
|
|
36
|
-
version: "7.
|
|
36
|
+
version: "7.24.1",
|
|
37
37
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
38
38
|
main: "dist/index.js",
|
|
39
39
|
types: "dist/index.d.ts",
|
|
@@ -41417,6 +41417,14 @@ function gitExec(args2) {
|
|
|
41417
41417
|
}
|
|
41418
41418
|
return result.stdout;
|
|
41419
41419
|
}
|
|
41420
|
+
function appendRetentionEvent(directory, event) {
|
|
41421
|
+
try {
|
|
41422
|
+
const eventsPath = path14.join(directory, ".swarm", "events.jsonl");
|
|
41423
|
+
const line = `${JSON.stringify({ ...event, timestamp: new Date().toISOString() })}
|
|
41424
|
+
`;
|
|
41425
|
+
fs11.appendFileSync(eventsPath, line);
|
|
41426
|
+
} catch {}
|
|
41427
|
+
}
|
|
41420
41428
|
function getCurrentSha() {
|
|
41421
41429
|
const output = gitExec(["rev-parse", "HEAD"]);
|
|
41422
41430
|
return output.trim();
|
|
@@ -41468,6 +41476,17 @@ function handleSave(label, directory) {
|
|
|
41468
41476
|
sha: newSha,
|
|
41469
41477
|
timestamp
|
|
41470
41478
|
});
|
|
41479
|
+
if (log2.checkpoints.length > maxCheckpoints) {
|
|
41480
|
+
const evicted = log2.checkpoints.splice(0, log2.checkpoints.length - maxCheckpoints);
|
|
41481
|
+
try {
|
|
41482
|
+
appendRetentionEvent(directory, {
|
|
41483
|
+
event: "checkpoint_retention_applied",
|
|
41484
|
+
evicted_labels: evicted.map((e) => e.label),
|
|
41485
|
+
evicted_count: evicted.length,
|
|
41486
|
+
remaining_count: log2.checkpoints.length
|
|
41487
|
+
});
|
|
41488
|
+
} catch {}
|
|
41489
|
+
}
|
|
41471
41490
|
writeCheckpointLog(log2, directory);
|
|
41472
41491
|
return JSON.stringify({
|
|
41473
41492
|
action: "save",
|
|
@@ -42675,6 +42694,20 @@ function normalizeEntry(raw) {
|
|
|
42675
42694
|
ro.failed_after_shown_count = typeof ro.failed_after_count === "number" ? ro.failed_after_count : 0;
|
|
42676
42695
|
}
|
|
42677
42696
|
}
|
|
42697
|
+
try {
|
|
42698
|
+
if (typeof obj.encounter_score !== "number" || Number.isNaN(obj.encounter_score)) {
|
|
42699
|
+
obj.encounter_score = 0;
|
|
42700
|
+
}
|
|
42701
|
+
} catch {
|
|
42702
|
+
try {
|
|
42703
|
+
Object.defineProperty(obj, "encounter_score", {
|
|
42704
|
+
value: 0,
|
|
42705
|
+
writable: true,
|
|
42706
|
+
configurable: true,
|
|
42707
|
+
enumerable: true
|
|
42708
|
+
});
|
|
42709
|
+
} catch {}
|
|
42710
|
+
}
|
|
42678
42711
|
const arrayFields = [
|
|
42679
42712
|
"triggers",
|
|
42680
42713
|
"required_actions",
|
|
@@ -44599,12 +44632,26 @@ import path19 from "node:path";
|
|
|
44599
44632
|
function isAlreadyInHive(entry, hiveEntries, threshold) {
|
|
44600
44633
|
return findNearDuplicate(entry.lesson, hiveEntries, threshold) !== undefined;
|
|
44601
44634
|
}
|
|
44602
|
-
function
|
|
44635
|
+
function isHiveEligible(entry, autoPromoteDays) {
|
|
44603
44636
|
const phaseNumbers = new Set;
|
|
44604
|
-
for (const record3 of
|
|
44605
|
-
|
|
44637
|
+
for (const record3 of entry.confirmed_by ?? []) {
|
|
44638
|
+
if (record3 && typeof record3.phase_number === "number") {
|
|
44639
|
+
phaseNumbers.add(record3.phase_number);
|
|
44640
|
+
}
|
|
44641
|
+
}
|
|
44642
|
+
if (entry.hive_eligible === true && phaseNumbers.size >= 3) {
|
|
44643
|
+
return true;
|
|
44644
|
+
}
|
|
44645
|
+
if ((entry.tags ?? []).includes("hive-fast-track")) {
|
|
44646
|
+
return true;
|
|
44606
44647
|
}
|
|
44607
|
-
|
|
44648
|
+
const createdMs = Date.parse(entry.created_at);
|
|
44649
|
+
const ageMs = Number.isFinite(createdMs) ? Date.now() - createdMs : 0;
|
|
44650
|
+
const ageThresholdMs = autoPromoteDays * 86400000;
|
|
44651
|
+
if (ageMs >= ageThresholdMs) {
|
|
44652
|
+
return true;
|
|
44653
|
+
}
|
|
44654
|
+
return false;
|
|
44608
44655
|
}
|
|
44609
44656
|
function countDistinctProjects(confirmedBy) {
|
|
44610
44657
|
const projectNames = new Set;
|
|
@@ -44622,12 +44669,6 @@ function calculateEncounterScore(currentScore, isSameProject, config3) {
|
|
|
44622
44669
|
const newScore = currentScore + increment;
|
|
44623
44670
|
return Math.min(Math.max(newScore, config3.min_encounter_score), config3.max_encounter_score);
|
|
44624
44671
|
}
|
|
44625
|
-
function getEntryAgeMs(createdAt) {
|
|
44626
|
-
const createdTime = new Date(createdAt).getTime();
|
|
44627
|
-
if (Number.isNaN(createdTime))
|
|
44628
|
-
return 0;
|
|
44629
|
-
return Date.now() - createdTime;
|
|
44630
|
-
}
|
|
44631
44672
|
async function checkHivePromotions(swarmEntries, config3) {
|
|
44632
44673
|
let newPromotions = 0;
|
|
44633
44674
|
let encountersIncremented = 0;
|
|
@@ -44646,19 +44687,7 @@ async function checkHivePromotions(swarmEntries, config3) {
|
|
|
44646
44687
|
if (isAlreadyInHive(swarmEntry, hiveEntries, config3.dedup_threshold)) {
|
|
44647
44688
|
continue;
|
|
44648
44689
|
}
|
|
44649
|
-
|
|
44650
|
-
if (swarmEntry.hive_eligible === true && countDistinctPhases(swarmEntry.confirmed_by) >= 3) {
|
|
44651
|
-
shouldPromote = true;
|
|
44652
|
-
}
|
|
44653
|
-
if (swarmEntry.tags.includes("hive-fast-track")) {
|
|
44654
|
-
shouldPromote = true;
|
|
44655
|
-
}
|
|
44656
|
-
const ageMs = getEntryAgeMs(swarmEntry.created_at);
|
|
44657
|
-
const ageThresholdMs = config3.auto_promote_days * 86400000;
|
|
44658
|
-
if (ageMs >= ageThresholdMs) {
|
|
44659
|
-
shouldPromote = true;
|
|
44660
|
-
}
|
|
44661
|
-
if (!shouldPromote) {
|
|
44690
|
+
if (!isHiveEligible(swarmEntry, config3.auto_promote_days)) {
|
|
44662
44691
|
continue;
|
|
44663
44692
|
}
|
|
44664
44693
|
const validationResult = validateLesson(swarmEntry.lesson, hiveEntries.map((e) => e.lesson), {
|
|
@@ -46535,12 +46564,14 @@ async function handleCloseCommand(directory, args2, options = {}) {
|
|
|
46535
46564
|
if (planExists) {
|
|
46536
46565
|
planAlreadyDone = phases.length > 0 && phases.every((p) => p.status === "complete" || p.status === "completed" || p.status === "blocked" || p.status === "closed");
|
|
46537
46566
|
}
|
|
46538
|
-
const
|
|
46567
|
+
const { config: loadedConfig } = loadPluginConfigWithMeta(directory);
|
|
46568
|
+
const config3 = KnowledgeConfigSchema.parse(loadedConfig.knowledge ?? {});
|
|
46539
46569
|
const projectName = planData.title ?? "Unknown Project";
|
|
46540
46570
|
const closedPhases = [];
|
|
46541
46571
|
const closedTasks = [];
|
|
46542
46572
|
const warnings = [];
|
|
46543
46573
|
let hivePromoted = 0;
|
|
46574
|
+
let hiveSkipped = 0;
|
|
46544
46575
|
if (!planAlreadyDone) {
|
|
46545
46576
|
for (const phase of inProgressPhases) {
|
|
46546
46577
|
closedPhases.push(phase.id);
|
|
@@ -46663,23 +46694,35 @@ async function handleCloseCommand(directory, args2, options = {}) {
|
|
|
46663
46694
|
await fs13.unlink(lessonsFilePath).catch(() => {});
|
|
46664
46695
|
}
|
|
46665
46696
|
if (curationSucceeded) {
|
|
46666
|
-
|
|
46667
|
-
|
|
46668
|
-
|
|
46669
|
-
|
|
46670
|
-
|
|
46671
|
-
|
|
46672
|
-
|
|
46673
|
-
|
|
46674
|
-
|
|
46675
|
-
|
|
46676
|
-
|
|
46697
|
+
if (config3.hive_enabled === false) {} else {
|
|
46698
|
+
try {
|
|
46699
|
+
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
46700
|
+
const entries = await readKnowledge(knowledgePath);
|
|
46701
|
+
const autoPromoteDays = config3.auto_promote_days;
|
|
46702
|
+
if (entries.length > 0) {
|
|
46703
|
+
for (const entry of entries) {
|
|
46704
|
+
if (!isHiveEligible(entry, autoPromoteDays)) {
|
|
46705
|
+
hiveSkipped++;
|
|
46706
|
+
continue;
|
|
46707
|
+
}
|
|
46708
|
+
try {
|
|
46709
|
+
const result = await promoteToHive(directory, entry.lesson, entry.category);
|
|
46710
|
+
if (!result.includes("already exists")) {
|
|
46711
|
+
hivePromoted++;
|
|
46712
|
+
}
|
|
46713
|
+
} catch (promotionErr) {
|
|
46714
|
+
const msg = promotionErr instanceof Error ? promotionErr.message : String(promotionErr);
|
|
46715
|
+
warnings.push(`Hive promotion skipped for lesson: ${msg}`);
|
|
46716
|
+
}
|
|
46717
|
+
}
|
|
46718
|
+
if (hiveSkipped > 0) {
|
|
46719
|
+
warnings.push(`${hiveSkipped} swarm knowledge entr${hiveSkipped === 1 ? "y" : "ies"} not eligible for hive promotion`);
|
|
46677
46720
|
}
|
|
46678
46721
|
}
|
|
46722
|
+
} catch (hiveErr) {
|
|
46723
|
+
const msg = hiveErr instanceof Error ? hiveErr.message : String(hiveErr);
|
|
46724
|
+
warnings.push(`Hive promotion failed: ${msg}`);
|
|
46679
46725
|
}
|
|
46680
|
-
} catch (hiveErr) {
|
|
46681
|
-
const msg = hiveErr instanceof Error ? hiveErr.message : String(hiveErr);
|
|
46682
|
-
warnings.push(`Hive promotion failed: ${msg}`);
|
|
46683
46726
|
}
|
|
46684
46727
|
}
|
|
46685
46728
|
const fallbackKnowledgeCreated = curationResult?.stored ?? 0;
|
|
@@ -46696,8 +46739,8 @@ async function handleCloseCommand(directory, args2, options = {}) {
|
|
|
46696
46739
|
let skillReviewSummary = "";
|
|
46697
46740
|
if (runSkillReview) {
|
|
46698
46741
|
try {
|
|
46699
|
-
const { config:
|
|
46700
|
-
const skillImproverConfig = SkillImproverConfigSchema.parse(
|
|
46742
|
+
const { config: loadedConfig2 } = loadPluginConfigWithMeta(directory);
|
|
46743
|
+
const skillImproverConfig = SkillImproverConfigSchema.parse(loadedConfig2.skill_improver ?? {});
|
|
46701
46744
|
const skillReviewResult = await runAbortableSkillReview({
|
|
46702
46745
|
directory,
|
|
46703
46746
|
config: skillImproverConfig,
|
|
@@ -47062,7 +47105,6 @@ var init_close = __esm(() => {
|
|
|
47062
47105
|
"handoff-prompt.md",
|
|
47063
47106
|
"handoff-consumed.md",
|
|
47064
47107
|
"escalation-report.md",
|
|
47065
|
-
"knowledge.jsonl",
|
|
47066
47108
|
"knowledge-rejected.jsonl",
|
|
47067
47109
|
"repo-graph.json",
|
|
47068
47110
|
"doc-manifest.json",
|
|
@@ -62633,7 +62675,17 @@ If the user answered the gate question, immediately follow up with ONE more ques
|
|
|
62633
62675
|
- locked: true
|
|
62634
62676
|
- recorded_at: <ISO timestamp>
|
|
62635
62677
|
\`\`\`
|
|
62636
|
-
If the user accepts the default (1), skip writing this section entirely — serial execution is the default and needs no config
|
|
62678
|
+
If the user accepts the default (1), skip writing this section entirely — serial execution is the default and needs no config.
|
|
62679
|
+
|
|
62680
|
+
After asking the parallelization question (regardless of whether the user chose serial or parallel), immediately follow up with ONE more question: "Commit frequency for completed tasks? (default: phase-level only; optional per-task checkpoint commit after each task completion)".
|
|
62681
|
+
|
|
62682
|
+
If the user chooses per-task commits, write this section to \`.swarm/context.md\`:
|
|
62683
|
+
\`\`\`
|
|
62684
|
+
## Task Completion Commit Policy
|
|
62685
|
+
- commit_after_each_completed_task: true
|
|
62686
|
+
- recorded_at: <ISO timestamp>
|
|
62687
|
+
\`\`\`
|
|
62688
|
+
If the user keeps the default phase-level behavior, do not write this section.`;
|
|
62637
62689
|
}
|
|
62638
62690
|
function buildAvailableToolsList(council) {
|
|
62639
62691
|
const tools = AGENT_TOOL_MAP.architect ?? [];
|
|
@@ -64122,7 +64174,10 @@ save_plan({
|
|
|
64122
64174
|
After \`save_plan\` succeeds, read \`.swarm/context.md\`:
|
|
64123
64175
|
- If a \`## Pending QA Gate Selection\` section exists: parse the gate values, call \`set_qa_gates\` with those flags, confirm with the user ("QA gates applied: <list>"), then remove the section from context.md.
|
|
64124
64176
|
- If a \`## Pending Parallelization Config\` section also exists: parse the values and call \`save_plan\` again with \`execution_profile\` set to \`{ parallelization_enabled: <parsed>, max_concurrent_tasks: <parsed>, council_parallel: false, locked: true }\`. Then remove the section from context.md. If the plan already had \`execution_profile.locked: true\`, skip this step — the profile is already locked and immutable.
|
|
64177
|
+
- If a \`## Task Completion Commit Policy\` section exists: preserve it in \`.swarm/context.md\` (do NOT remove). This section is execution-time guidance for optional per-task checkpoint commits after \`update_task_status(status="completed")\`.
|
|
64125
64178
|
- If no pending section exists: {{QA_GATE_DIALOGUE_PLAN}}
|
|
64179
|
+
- If a \`## Task Completion Commit Policy\` section already exists in context.md, honor it as execution-time guidance (do NOT remove).
|
|
64180
|
+
- If no \`## Task Completion Commit Policy\` section exists AND the \`{{QA_GATE_DIALOGUE_PLAN}}\` template was not rendered (pending sections were pre-written), ask the commit-frequency question now. Write the section to context.md if the user chooses per-task commits; skip if they keep the default phase-level behavior.
|
|
64126
64181
|
<!-- BEHAVIORAL_GUIDANCE_START -->
|
|
64127
64182
|
INLINE GATE SELECTION — no pending section found in context.md. You MUST ask now.
|
|
64128
64183
|
✗ "I'll call set_qa_gates with defaults and move on"
|
|
@@ -64407,7 +64462,14 @@ This step supplements (not replaces) the existing regression-sweep and test-drif
|
|
|
64407
64462
|
Any blank "value: ___" field = gate was not run = task is NOT complete.
|
|
64408
64463
|
Filling this checklist from memory ("I think I ran it") is INVALID. Each value must come from actual tool/agent output in this session.
|
|
64409
64464
|
|
|
64410
|
-
|
|
64465
|
+
5p. Call update_task_status with status "completed".
|
|
64466
|
+
5q. OPTIONAL TASK-COMPLETION COMMIT POLICY: read \`.swarm/context.md\`.
|
|
64467
|
+
- If \`## Task Completion Commit Policy\` contains \`commit_after_each_completed_task: true\`, immediately call:
|
|
64468
|
+
\`checkpoint save task-<task-id>-complete\`
|
|
64469
|
+
- If the section is absent or false, skip this step.
|
|
64470
|
+
- This optional commit policy NEVER bypasses PRE-COMMIT RULE checks above.
|
|
64471
|
+
- If checkpoint save fails with "duplicate label", the task was already checkpointed from a prior completion or retry. Silently skip — the existing checkpoint is valid.
|
|
64472
|
+
5r. Proceed to next task.
|
|
64411
64473
|
|
|
64412
64474
|
## ⛔ RETROSPECTIVE GATE
|
|
64413
64475
|
|
|
@@ -83626,8 +83688,8 @@ ${formattedIndex}
|
|
|
83626
83688
|
} else {
|
|
83627
83689
|
if (existingContent.length > 0 && !existingContent.endsWith(`
|
|
83628
83690
|
`)) {
|
|
83629
|
-
updatedContent = existingContent
|
|
83630
|
-
|
|
83691
|
+
updatedContent = `${existingContent}
|
|
83692
|
+
${newSection}`;
|
|
83631
83693
|
} else {
|
|
83632
83694
|
updatedContent = existingContent + newSection;
|
|
83633
83695
|
}
|
|
@@ -87109,7 +87171,7 @@ ${body2}`);
|
|
|
87109
87171
|
|
|
87110
87172
|
// src/council/council-evidence-writer.ts
|
|
87111
87173
|
import {
|
|
87112
|
-
appendFileSync as
|
|
87174
|
+
appendFileSync as appendFileSync12,
|
|
87113
87175
|
existsSync as existsSync53,
|
|
87114
87176
|
mkdirSync as mkdirSync24,
|
|
87115
87177
|
readFileSync as readFileSync44,
|
|
@@ -87193,7 +87255,7 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
87193
87255
|
timestamp: synthesis.timestamp,
|
|
87194
87256
|
vetoedBy: synthesis.vetoedBy
|
|
87195
87257
|
});
|
|
87196
|
-
|
|
87258
|
+
appendFileSync12(join83(councilDir, `${synthesis.taskId}.rounds.jsonl`), `${auditLine}
|
|
87197
87259
|
`);
|
|
87198
87260
|
} catch (auditError) {
|
|
87199
87261
|
console.warn(`writeCouncilEvidence: failed to append round-history audit log: ${auditError instanceof Error ? auditError.message : String(auditError)}`);
|
|
@@ -90390,7 +90452,7 @@ function formatHiveEntry(entry) {
|
|
|
90390
90452
|
lines.push(` Category: ${entry.category}`);
|
|
90391
90453
|
lines.push(` Status: ${entry.status}`);
|
|
90392
90454
|
lines.push(` Confidence: ${entry.confidence.toFixed(2)}`);
|
|
90393
|
-
lines.push(` Encounter Score: ${entry.encounter_score
|
|
90455
|
+
lines.push(` Encounter Score: ${entry.encounter_score?.toFixed(2) ?? "N/A"}`);
|
|
90394
90456
|
lines.push(` Source Project: ${entry.source_project}`);
|
|
90395
90457
|
lines.push(` Confirmed by: ${entry.confirmed_by.length} project(s)`);
|
|
90396
90458
|
return lines.join(`
|
|
@@ -104029,9 +104091,9 @@ function recoverTaskStateFromDelegations(taskId, directory) {
|
|
|
104029
104091
|
try {
|
|
104030
104092
|
const evidence = readTaskEvidenceRaw(directory, taskId);
|
|
104031
104093
|
if (evidence && evidence.gates && Array.isArray(evidence.required_gates)) {
|
|
104032
|
-
if (evidence.gates
|
|
104094
|
+
if (evidence.gates.reviewer != null)
|
|
104033
104095
|
hasReviewer = true;
|
|
104034
|
-
if (evidence.gates
|
|
104096
|
+
if (evidence.gates.test_engineer != null)
|
|
104035
104097
|
hasTestEngineer = true;
|
|
104036
104098
|
}
|
|
104037
104099
|
} catch {}
|
|
@@ -2,4 +2,10 @@
|
|
|
2
2
|
* Provides filtered, formatted text output for knowledge retrieval.
|
|
3
3
|
*/
|
|
4
4
|
import type { tool } from '@opencode-ai/plugin';
|
|
5
|
+
import type { HiveKnowledgeEntry } from '../hooks/knowledge-types.js';
|
|
6
|
+
declare function formatHiveEntry(entry: HiveKnowledgeEntry): string;
|
|
5
7
|
export declare const knowledge_query: ReturnType<typeof tool>;
|
|
8
|
+
export declare const _test_exports: {
|
|
9
|
+
formatHiveEntry: typeof formatHiveEntry;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.24.1",
|
|
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",
|