opencode-swarm 7.73.1 → 7.73.2

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 CHANGED
@@ -52,7 +52,7 @@ var package_default;
52
52
  var init_package = __esm(() => {
53
53
  package_default = {
54
54
  name: "opencode-swarm",
55
- version: "7.73.1",
55
+ version: "7.73.2",
56
56
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
57
57
  main: "dist/index.js",
58
58
  types: "dist/index.d.ts",
@@ -40921,6 +40921,49 @@ var init_synonym_map = __esm(() => {
40921
40921
  MIN_READ_CEILING_BYTES = 64 * 1024;
40922
40922
  });
40923
40923
 
40924
+ // src/hooks/knowledge-reinforcement.ts
40925
+ function isActiveSwarmKnowledgeEntry(entry) {
40926
+ return !INACTIVE_STATUSES.has(entry.status);
40927
+ }
40928
+ function findActiveSwarmNearDuplicate(lesson, entries, threshold) {
40929
+ return findNearDuplicate(lesson, entries.filter(isActiveSwarmKnowledgeEntry), threshold);
40930
+ }
40931
+ function distinctPhaseCount(records) {
40932
+ const phases = new Set;
40933
+ for (const record3 of records ?? []) {
40934
+ if (Number.isInteger(record3.phase_number)) {
40935
+ phases.add(record3.phase_number);
40936
+ }
40937
+ }
40938
+ return phases.size;
40939
+ }
40940
+ function reinforceSwarmKnowledgeEntry(entry, confirmation) {
40941
+ if (!isActiveSwarmKnowledgeEntry(entry)) {
40942
+ return { entryId: entry.id, reinforced: false, reason: "inactive" };
40943
+ }
40944
+ if ((entry.confirmed_by ?? []).some((record3) => record3.phase_number === confirmation.phase_number)) {
40945
+ return {
40946
+ entryId: entry.id,
40947
+ reinforced: false,
40948
+ reason: "already_confirmed_phase"
40949
+ };
40950
+ }
40951
+ entry.confirmed_by = [...entry.confirmed_by ?? [], confirmation];
40952
+ entry.updated_at = confirmation.confirmed_at;
40953
+ entry.phases_alive = 0;
40954
+ entry.confidence = computeConfidence(distinctPhaseCount(entry.confirmed_by), entry.auto_generated ?? false);
40955
+ return { entryId: entry.id, reinforced: true, reason: "reinforced" };
40956
+ }
40957
+ var INACTIVE_STATUSES;
40958
+ var init_knowledge_reinforcement = __esm(() => {
40959
+ init_knowledge_store();
40960
+ INACTIVE_STATUSES = new Set([
40961
+ "archived",
40962
+ "quarantined",
40963
+ "quarantined_unactionable"
40964
+ ]);
40965
+ });
40966
+
40924
40967
  // src/hooks/skill-scoring.ts
40925
40968
  import * as fs10 from "fs";
40926
40969
  import * as path22 from "path";
@@ -42244,6 +42287,7 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
42244
42287
  ]);
42245
42288
  const snapshotPlusNew = [...snapshot];
42246
42289
  const toAdd = [];
42290
+ const pendingReinforcementIds = new Set;
42247
42291
  for (const lesson of lessons) {
42248
42292
  const tags = inferTags(lesson);
42249
42293
  let category = "process";
@@ -42273,8 +42317,9 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
42273
42317
  continue;
42274
42318
  }
42275
42319
  }
42276
- const duplicate = findNearDuplicate(lesson, snapshotPlusNew, config3.dedup_threshold);
42320
+ const duplicate = findActiveSwarmNearDuplicate(lesson, snapshotPlusNew, config3.dedup_threshold);
42277
42321
  if (duplicate) {
42322
+ pendingReinforcementIds.add(duplicate.id);
42278
42323
  skipped++;
42279
42324
  continue;
42280
42325
  }
@@ -42355,7 +42400,9 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
42355
42400
  } catch {}
42356
42401
  continue;
42357
42402
  }
42358
- if (findNearDuplicate(entry.lesson, snapshotPlusNew, config3.dedup_threshold)) {
42403
+ const duplicate = findActiveSwarmNearDuplicate(entry.lesson, snapshotPlusNew, config3.dedup_threshold);
42404
+ if (duplicate) {
42405
+ pendingReinforcementIds.add(duplicate.id);
42359
42406
  skipped++;
42360
42407
  continue;
42361
42408
  }
@@ -42364,15 +42411,48 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
42364
42411
  }
42365
42412
  } catch {}
42366
42413
  let stored = 0;
42367
- if (toAdd.length > 0) {
42414
+ let reinforced = 0;
42415
+ if (toAdd.length > 0 || pendingReinforcementIds.size > 0) {
42368
42416
  await transactKnowledge(knowledgePath, (current) => {
42369
- const trulyNew = toAdd.filter((e) => !findNearDuplicate(e.lesson, current, config3.dedup_threshold));
42370
- const extraDups = toAdd.length - trulyNew.length;
42371
- skipped += extraDups;
42372
- if (trulyNew.length === 0)
42373
- return null;
42374
- stored = trulyNew.length;
42375
- return [...current, ...trulyNew];
42417
+ let changed = false;
42418
+ for (const id of pendingReinforcementIds) {
42419
+ const existing = current.find((entry) => entry.id === id);
42420
+ if (!existing)
42421
+ continue;
42422
+ const result = reinforceSwarmKnowledgeEntry(existing, {
42423
+ phase_number: phaseInfo.phase_number,
42424
+ confirmed_at: new Date().toISOString(),
42425
+ project_name: projectName
42426
+ });
42427
+ if (result.reinforced) {
42428
+ reinforced++;
42429
+ changed = true;
42430
+ }
42431
+ }
42432
+ const trulyNew = [];
42433
+ for (const entry of toAdd) {
42434
+ const duplicate = findActiveSwarmNearDuplicate(entry.lesson, current, config3.dedup_threshold);
42435
+ if (duplicate) {
42436
+ skipped++;
42437
+ const result = reinforceSwarmKnowledgeEntry(duplicate, {
42438
+ phase_number: phaseInfo.phase_number,
42439
+ confirmed_at: new Date().toISOString(),
42440
+ project_name: projectName
42441
+ });
42442
+ if (result.reinforced) {
42443
+ reinforced++;
42444
+ changed = true;
42445
+ }
42446
+ continue;
42447
+ }
42448
+ trulyNew.push(entry);
42449
+ }
42450
+ if (trulyNew.length > 0) {
42451
+ current.push(...trulyNew);
42452
+ stored = trulyNew.length;
42453
+ changed = true;
42454
+ }
42455
+ return changed ? current : null;
42376
42456
  });
42377
42457
  }
42378
42458
  await enforceKnowledgeCap(knowledgePath, config3.swarm_max_entries);
@@ -42390,7 +42470,7 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
42390
42470
  if (!options?.skipAutoPromotion) {
42391
42471
  await _internals19.runAutoPromotion(directory, config3);
42392
42472
  }
42393
- return { stored, skipped, rejected, quarantined };
42473
+ return { stored, reinforced, skipped, rejected, quarantined };
42394
42474
  }
42395
42475
  async function runAutoPromotion(directory, config3) {
42396
42476
  const knowledgePath = resolveSwarmKnowledgePath(directory);
@@ -42503,6 +42583,7 @@ var init_knowledge_curator = __esm(() => {
42503
42583
  init_synonym_map();
42504
42584
  init_logger();
42505
42585
  init_knowledge_events();
42586
+ init_knowledge_reinforcement();
42506
42587
  init_knowledge_store();
42507
42588
  init_knowledge_validator();
42508
42589
  init_micro_reflector();
@@ -81,6 +81,7 @@ export declare function curateAndStoreSwarm(lessons: string[], projectName: stri
81
81
  enrichmentQuota?: EnrichmentQuotaOptions;
82
82
  }): Promise<{
83
83
  stored: number;
84
+ reinforced: number;
84
85
  skipped: number;
85
86
  rejected: number;
86
87
  quarantined: number;
@@ -0,0 +1,10 @@
1
+ import type { PhaseConfirmationRecord, SwarmKnowledgeEntry } from './knowledge-types.js';
2
+ export type ReinforcementReason = 'reinforced' | 'already_confirmed_phase' | 'inactive';
3
+ export interface ReinforcementResult {
4
+ entryId: string;
5
+ reinforced: boolean;
6
+ reason: ReinforcementReason;
7
+ }
8
+ export declare function isActiveSwarmKnowledgeEntry(entry: SwarmKnowledgeEntry): boolean;
9
+ export declare function findActiveSwarmNearDuplicate(lesson: string, entries: SwarmKnowledgeEntry[], threshold: number): SwarmKnowledgeEntry | undefined;
10
+ export declare function reinforceSwarmKnowledgeEntry(entry: SwarmKnowledgeEntry, confirmation: PhaseConfirmationRecord): ReinforcementResult;
package/dist/index.js CHANGED
@@ -69,7 +69,7 @@ var package_default;
69
69
  var init_package = __esm(() => {
70
70
  package_default = {
71
71
  name: "opencode-swarm",
72
- version: "7.73.1",
72
+ version: "7.73.2",
73
73
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
74
74
  main: "dist/index.js",
75
75
  types: "dist/index.d.ts",
@@ -64285,6 +64285,49 @@ var init_synonym_map = __esm(() => {
64285
64285
  MIN_READ_CEILING_BYTES = 64 * 1024;
64286
64286
  });
64287
64287
 
64288
+ // src/hooks/knowledge-reinforcement.ts
64289
+ function isActiveSwarmKnowledgeEntry(entry) {
64290
+ return !INACTIVE_STATUSES.has(entry.status);
64291
+ }
64292
+ function findActiveSwarmNearDuplicate(lesson, entries, threshold) {
64293
+ return findNearDuplicate(lesson, entries.filter(isActiveSwarmKnowledgeEntry), threshold);
64294
+ }
64295
+ function distinctPhaseCount(records) {
64296
+ const phases = new Set;
64297
+ for (const record3 of records ?? []) {
64298
+ if (Number.isInteger(record3.phase_number)) {
64299
+ phases.add(record3.phase_number);
64300
+ }
64301
+ }
64302
+ return phases.size;
64303
+ }
64304
+ function reinforceSwarmKnowledgeEntry(entry, confirmation) {
64305
+ if (!isActiveSwarmKnowledgeEntry(entry)) {
64306
+ return { entryId: entry.id, reinforced: false, reason: "inactive" };
64307
+ }
64308
+ if ((entry.confirmed_by ?? []).some((record3) => record3.phase_number === confirmation.phase_number)) {
64309
+ return {
64310
+ entryId: entry.id,
64311
+ reinforced: false,
64312
+ reason: "already_confirmed_phase"
64313
+ };
64314
+ }
64315
+ entry.confirmed_by = [...entry.confirmed_by ?? [], confirmation];
64316
+ entry.updated_at = confirmation.confirmed_at;
64317
+ entry.phases_alive = 0;
64318
+ entry.confidence = computeConfidence(distinctPhaseCount(entry.confirmed_by), entry.auto_generated ?? false);
64319
+ return { entryId: entry.id, reinforced: true, reason: "reinforced" };
64320
+ }
64321
+ var INACTIVE_STATUSES;
64322
+ var init_knowledge_reinforcement = __esm(() => {
64323
+ init_knowledge_store();
64324
+ INACTIVE_STATUSES = new Set([
64325
+ "archived",
64326
+ "quarantined",
64327
+ "quarantined_unactionable"
64328
+ ]);
64329
+ });
64330
+
64288
64331
  // src/hooks/skill-scoring.ts
64289
64332
  import * as fs21 from "node:fs";
64290
64333
  import * as path41 from "node:path";
@@ -65838,6 +65881,7 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
65838
65881
  ]);
65839
65882
  const snapshotPlusNew = [...snapshot];
65840
65883
  const toAdd = [];
65884
+ const pendingReinforcementIds = new Set;
65841
65885
  for (const lesson of lessons) {
65842
65886
  const tags = inferTags(lesson);
65843
65887
  let category = "process";
@@ -65867,8 +65911,9 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
65867
65911
  continue;
65868
65912
  }
65869
65913
  }
65870
- const duplicate = findNearDuplicate(lesson, snapshotPlusNew, config3.dedup_threshold);
65914
+ const duplicate = findActiveSwarmNearDuplicate(lesson, snapshotPlusNew, config3.dedup_threshold);
65871
65915
  if (duplicate) {
65916
+ pendingReinforcementIds.add(duplicate.id);
65872
65917
  skipped++;
65873
65918
  continue;
65874
65919
  }
@@ -65949,7 +65994,9 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
65949
65994
  } catch {}
65950
65995
  continue;
65951
65996
  }
65952
- if (findNearDuplicate(entry.lesson, snapshotPlusNew, config3.dedup_threshold)) {
65997
+ const duplicate = findActiveSwarmNearDuplicate(entry.lesson, snapshotPlusNew, config3.dedup_threshold);
65998
+ if (duplicate) {
65999
+ pendingReinforcementIds.add(duplicate.id);
65953
66000
  skipped++;
65954
66001
  continue;
65955
66002
  }
@@ -65958,15 +66005,48 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
65958
66005
  }
65959
66006
  } catch {}
65960
66007
  let stored = 0;
65961
- if (toAdd.length > 0) {
66008
+ let reinforced = 0;
66009
+ if (toAdd.length > 0 || pendingReinforcementIds.size > 0) {
65962
66010
  await transactKnowledge(knowledgePath, (current) => {
65963
- const trulyNew = toAdd.filter((e) => !findNearDuplicate(e.lesson, current, config3.dedup_threshold));
65964
- const extraDups = toAdd.length - trulyNew.length;
65965
- skipped += extraDups;
65966
- if (trulyNew.length === 0)
65967
- return null;
65968
- stored = trulyNew.length;
65969
- return [...current, ...trulyNew];
66011
+ let changed = false;
66012
+ for (const id of pendingReinforcementIds) {
66013
+ const existing = current.find((entry) => entry.id === id);
66014
+ if (!existing)
66015
+ continue;
66016
+ const result = reinforceSwarmKnowledgeEntry(existing, {
66017
+ phase_number: phaseInfo.phase_number,
66018
+ confirmed_at: new Date().toISOString(),
66019
+ project_name: projectName
66020
+ });
66021
+ if (result.reinforced) {
66022
+ reinforced++;
66023
+ changed = true;
66024
+ }
66025
+ }
66026
+ const trulyNew = [];
66027
+ for (const entry of toAdd) {
66028
+ const duplicate = findActiveSwarmNearDuplicate(entry.lesson, current, config3.dedup_threshold);
66029
+ if (duplicate) {
66030
+ skipped++;
66031
+ const result = reinforceSwarmKnowledgeEntry(duplicate, {
66032
+ phase_number: phaseInfo.phase_number,
66033
+ confirmed_at: new Date().toISOString(),
66034
+ project_name: projectName
66035
+ });
66036
+ if (result.reinforced) {
66037
+ reinforced++;
66038
+ changed = true;
66039
+ }
66040
+ continue;
66041
+ }
66042
+ trulyNew.push(entry);
66043
+ }
66044
+ if (trulyNew.length > 0) {
66045
+ current.push(...trulyNew);
66046
+ stored = trulyNew.length;
66047
+ changed = true;
66048
+ }
66049
+ return changed ? current : null;
65970
66050
  });
65971
66051
  }
65972
66052
  await enforceKnowledgeCap(knowledgePath, config3.swarm_max_entries);
@@ -65984,7 +66064,7 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
65984
66064
  if (!options?.skipAutoPromotion) {
65985
66065
  await _internals30.runAutoPromotion(directory, config3);
65986
66066
  }
65987
- return { stored, skipped, rejected, quarantined };
66067
+ return { stored, reinforced, skipped, rejected, quarantined };
65988
66068
  }
65989
66069
  async function runAutoPromotion(directory, config3) {
65990
66070
  const knowledgePath = resolveSwarmKnowledgePath(directory);
@@ -66097,6 +66177,7 @@ var init_knowledge_curator = __esm(() => {
66097
66177
  init_synonym_map();
66098
66178
  init_logger();
66099
66179
  init_knowledge_events();
66180
+ init_knowledge_reinforcement();
66100
66181
  init_knowledge_store();
66101
66182
  init_knowledge_validator();
66102
66183
  init_micro_reflector();
@@ -124942,10 +125023,10 @@ var knowledge_ack = createSwarmTool({
124942
125023
  // src/tools/knowledge-add.ts
124943
125024
  init_zod();
124944
125025
  init_config();
125026
+ init_knowledge_reinforcement();
124945
125027
  init_knowledge_store();
124946
125028
  init_knowledge_validator();
124947
125029
  init_manager();
124948
- init_utils();
124949
125030
  init_create_tool();
124950
125031
  import { randomUUID as randomUUID15 } from "node:crypto";
124951
125032
  var VALID_CATEGORIES2 = [
@@ -125037,9 +125118,13 @@ var knowledge_add = createSwarmTool({
125037
125118
  });
125038
125119
  }
125039
125120
  let project_name = "";
125121
+ let phase_number = 1;
125040
125122
  try {
125041
125123
  const plan = await loadPlan(directory);
125042
125124
  project_name = plan?.title ?? "";
125125
+ if (typeof plan?.current_phase === "number") {
125126
+ phase_number = plan.current_phase;
125127
+ }
125043
125128
  } catch {}
125044
125129
  const entry = {
125045
125130
  id: randomUUID15(),
@@ -125084,19 +125169,6 @@ var knowledge_add = createSwarmTool({
125084
125169
  }
125085
125170
  }
125086
125171
  } catch {}
125087
- try {
125088
- const existingEntries = await readKnowledge(resolveSwarmKnowledgePath(directory));
125089
- const duplicate = findNearDuplicate(lesson, existingEntries, dedupThreshold);
125090
- if (duplicate) {
125091
- return JSON.stringify({
125092
- success: false,
125093
- id: duplicate.id,
125094
- message: "near-duplicate of existing entry"
125095
- });
125096
- }
125097
- } catch (err2) {
125098
- warn("knowledge_add: dedup check failed — skipping near-duplicate detection", err2);
125099
- }
125100
125172
  const actionability = validateActionability(entry);
125101
125173
  if (!actionability.actionable) {
125102
125174
  try {
@@ -125112,7 +125184,55 @@ var knowledge_add = createSwarmTool({
125112
125184
  }
125113
125185
  try {
125114
125186
  const maxEntries = config3?.knowledge?.swarm_max_entries ?? 100;
125115
- await appendKnowledgeWithCapEnforcement(resolveSwarmKnowledgePath(directory), entry, maxEntries);
125187
+ let duplicateResponse;
125188
+ await transactKnowledge(resolveSwarmKnowledgePath(directory), (existingEntries) => {
125189
+ const activeDuplicate = findActiveSwarmNearDuplicate(lesson, existingEntries, dedupThreshold);
125190
+ if (activeDuplicate) {
125191
+ const result = reinforceSwarmKnowledgeEntry(activeDuplicate, {
125192
+ phase_number,
125193
+ confirmed_at: new Date().toISOString(),
125194
+ project_name
125195
+ });
125196
+ duplicateResponse = {
125197
+ id: activeDuplicate.id,
125198
+ reinforced: result.reinforced,
125199
+ idempotent: result.reason === "already_confirmed_phase",
125200
+ inactive: false
125201
+ };
125202
+ return result.reinforced ? existingEntries : null;
125203
+ }
125204
+ const inactiveDuplicate = findNearDuplicate(lesson, existingEntries, dedupThreshold);
125205
+ if (inactiveDuplicate) {
125206
+ duplicateResponse = {
125207
+ id: inactiveDuplicate.id,
125208
+ reinforced: false,
125209
+ idempotent: false,
125210
+ inactive: true
125211
+ };
125212
+ return null;
125213
+ }
125214
+ const updated = [...existingEntries, entry];
125215
+ if (updated.length > maxEntries) {
125216
+ return updated.slice(updated.length - maxEntries);
125217
+ }
125218
+ return updated;
125219
+ });
125220
+ if (duplicateResponse) {
125221
+ if (duplicateResponse.inactive) {
125222
+ return JSON.stringify({
125223
+ success: false,
125224
+ id: duplicateResponse.id,
125225
+ message: "near-duplicate of inactive existing entry"
125226
+ });
125227
+ }
125228
+ return JSON.stringify({
125229
+ success: true,
125230
+ id: duplicateResponse.id,
125231
+ reinforced: duplicateResponse.reinforced,
125232
+ idempotent: duplicateResponse.idempotent,
125233
+ message: duplicateResponse.reinforced ? "near-duplicate reinforced existing entry" : "near-duplicate already confirmed for this phase"
125234
+ });
125235
+ }
125116
125236
  } catch (err2) {
125117
125237
  const message = err2 instanceof Error ? err2.message : "Unknown error";
125118
125238
  return JSON.stringify({
@@ -130197,7 +130317,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
130197
130317
  const sessionState = swarmState.agentSessions.get(sessionID);
130198
130318
  if (sessionState) {
130199
130319
  sessionState.pendingAdvisoryMessages ??= [];
130200
- sessionState.pendingAdvisoryMessages.push(`[CURATOR] Knowledge curation: ${curationResult.stored} stored, ${curationResult.skipped} skipped, ${curationResult.rejected} rejected, ${curationResult.quarantined} quarantined (unactionable).`);
130320
+ sessionState.pendingAdvisoryMessages.push(`[CURATOR] Knowledge curation: ${curationResult.stored} stored, ${curationResult.reinforced} reinforced, ${curationResult.skipped} skipped, ${curationResult.rejected} rejected, ${curationResult.quarantined} quarantined (unactionable).`);
130201
130321
  }
130202
130322
  }
130203
130323
  await updateRetrievalOutcome(dir, `Phase ${phase}`, true);
@@ -141956,6 +142076,7 @@ var write_architecture_supervisor_evidence = createSwarmTool({
141956
142076
  };
141957
142077
  const evidencePath = writeSupervisorReport(dirResult.directory, report);
141958
142078
  let knowledgeProposed = 0;
142079
+ let knowledgeReinforced = 0;
141959
142080
  let knowledgeQuarantined = 0;
141960
142081
  try {
141961
142082
  const config3 = loadPluginConfig(dirResult.directory);
@@ -141972,6 +142093,7 @@ var write_architecture_supervisor_evidence = createSwarmTool({
141972
142093
  }
141973
142094
  });
141974
142095
  knowledgeProposed = result.stored;
142096
+ knowledgeReinforced = result.reinforced;
141975
142097
  knowledgeQuarantined = result.quarantined;
141976
142098
  }
141977
142099
  } catch {}
@@ -141993,6 +142115,7 @@ var write_architecture_supervisor_evidence = createSwarmTool({
141993
142115
  verdict: args2.verdict,
141994
142116
  findings_count: args2.findings.length,
141995
142117
  knowledge_proposed: knowledgeProposed,
142118
+ knowledge_reinforced: knowledgeReinforced,
141996
142119
  knowledge_quarantined: knowledgeQuarantined,
141997
142120
  skills_proposed: skillsProposed,
141998
142121
  evidence_path: evidencePath
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.73.1",
3
+ "version": "7.73.2",
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",