opencode-swarm 7.64.0 → 7.65.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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.64.0",
55
+ version: "7.65.0",
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",
@@ -18518,7 +18518,8 @@ var init_schema = __esm(() => {
18518
18518
  max_agent_summary_words: exports_external.number().int().min(20).max(500).default(100),
18519
18519
  max_phase_summary_words: exports_external.number().int().min(50).max(1000).default(250),
18520
18520
  allow_concerns_to_complete: exports_external.boolean().default(true),
18521
- persist_knowledge_recommendations: exports_external.boolean().default(false)
18521
+ persist_knowledge_recommendations: exports_external.boolean().default(false),
18522
+ provenance_verify: exports_external.boolean().default(false)
18522
18523
  });
18523
18524
  KnowledgeApplicationConfigSchema = exports_external.object({
18524
18525
  enabled: exports_external.boolean().default(true),
@@ -37126,13 +37127,12 @@ async function enforceKnowledgeCap(filePath, maxEntries) {
37126
37127
  return entries.slice(entries.length - maxEntries);
37127
37128
  });
37128
37129
  }
37129
- async function appendRejectedLesson(directory, lesson) {
37130
+ async function appendRejectedLesson(directory, lesson, maxEntries = 20) {
37130
37131
  const filePath = resolveSwarmRejectedPath(directory);
37131
- const MAX = 20;
37132
37132
  await transactKnowledge(filePath, (existing) => {
37133
37133
  const updated = [...existing, lesson];
37134
- if (updated.length > MAX) {
37135
- return updated.slice(updated.length - MAX);
37134
+ if (updated.length > maxEntries) {
37135
+ return updated.slice(updated.length - maxEntries);
37136
37136
  }
37137
37137
  return updated;
37138
37138
  });
@@ -40697,18 +40697,20 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
40697
40697
  scope: "global",
40698
40698
  confidence: computeConfidence(0, true)
40699
40699
  };
40700
- const result = validateLesson(lesson, snapshotPlusNew.map((e) => e.lesson), meta3);
40701
- if (result.valid === false || result.severity === "error") {
40702
- const rejectedLesson = {
40703
- id: crypto.randomUUID(),
40704
- lesson,
40705
- rejection_reason: result.reason ?? "unknown",
40706
- rejected_at: new Date().toISOString(),
40707
- rejection_layer: result.layer ?? 1
40708
- };
40709
- await appendRejectedLesson(directory, rejectedLesson);
40710
- rejected++;
40711
- continue;
40700
+ if (config3.validation_enabled !== false) {
40701
+ const result = validateLesson(lesson, snapshotPlusNew.map((e) => e.lesson), meta3);
40702
+ if (result.valid === false || result.severity === "error") {
40703
+ const rejectedLesson = {
40704
+ id: crypto.randomUUID(),
40705
+ lesson,
40706
+ rejection_reason: result.reason ?? "unknown",
40707
+ rejected_at: new Date().toISOString(),
40708
+ rejection_layer: result.layer ?? 1
40709
+ };
40710
+ await appendRejectedLesson(directory, rejectedLesson, config3.rejected_max_entries);
40711
+ rejected++;
40712
+ continue;
40713
+ }
40712
40714
  }
40713
40715
  const duplicate = findNearDuplicate(lesson, snapshotPlusNew, config3.dedup_threshold);
40714
40716
  if (duplicate) {
@@ -607,6 +607,7 @@ export declare const ArchitecturalSupervisionConfigSchema: z.ZodObject<{
607
607
  max_phase_summary_words: z.ZodDefault<z.ZodNumber>;
608
608
  allow_concerns_to_complete: z.ZodDefault<z.ZodBoolean>;
609
609
  persist_knowledge_recommendations: z.ZodDefault<z.ZodBoolean>;
610
+ provenance_verify: z.ZodDefault<z.ZodBoolean>;
610
611
  }, z.core.$strip>;
611
612
  export type ArchitecturalSupervisionConfig = z.infer<typeof ArchitecturalSupervisionConfigSchema>;
612
613
  export declare const KnowledgeApplicationConfigSchema: z.ZodObject<{
@@ -1528,6 +1529,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
1528
1529
  max_phase_summary_words: z.ZodDefault<z.ZodNumber>;
1529
1530
  allow_concerns_to_complete: z.ZodDefault<z.ZodBoolean>;
1530
1531
  persist_knowledge_recommendations: z.ZodDefault<z.ZodBoolean>;
1532
+ provenance_verify: z.ZodDefault<z.ZodBoolean>;
1531
1533
  }, z.core.$strip>>;
1532
1534
  knowledge_application: z.ZodOptional<z.ZodObject<{
1533
1535
  enabled: z.ZodDefault<z.ZodBoolean>;
@@ -24,6 +24,7 @@ export declare function appendKnowledge<T>(filePath: string, entry: T): Promise<
24
24
  export declare function rewriteKnowledge<T>(filePath: string, entries: T[]): Promise<void>;
25
25
  export declare function transactFile<T>(filePath: string, read: (filePath: string) => Promise<T>, write: (filePath: string, data: T) => Promise<void>, mutate: (data: T) => T | null): Promise<boolean>;
26
26
  export declare function transactKnowledge<T>(filePath: string, mutate: (entries: T[]) => T[] | null): Promise<boolean>;
27
+ export declare function appendKnowledgeWithCapEnforcement<T>(filePath: string, entry: T, maxEntries: number): Promise<boolean>;
27
28
  export declare function enforceKnowledgeCap<T>(filePath: string, maxEntries: number): Promise<void>;
28
29
  export interface SweepResult {
29
30
  scanned: number;
@@ -34,7 +35,7 @@ export interface SweepResult {
34
35
  }
35
36
  export declare function sweepAgedEntries<T extends KnowledgeEntryBase>(filePath: string, defaultMaxPhases: number): Promise<SweepResult>;
36
37
  export declare function sweepStaleTodos<T extends KnowledgeEntryBase>(filePath: string, todoMaxPhases: number): Promise<SweepResult>;
37
- export declare function appendRejectedLesson(directory: string, lesson: RejectedLesson): Promise<void>;
38
+ export declare function appendRejectedLesson(directory: string, lesson: RejectedLesson, maxEntries?: number): Promise<void>;
38
39
  export declare function normalize(text: string): string;
39
40
  export declare function wordBigrams(text: string): Set<string>;
40
41
  export declare function jaccardBigram(a: Set<string>, b: Set<string>): number;
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.64.0",
72
+ version: "7.65.0",
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",
@@ -15849,7 +15849,8 @@ var init_schema = __esm(() => {
15849
15849
  max_agent_summary_words: exports_external.number().int().min(20).max(500).default(100),
15850
15850
  max_phase_summary_words: exports_external.number().int().min(50).max(1000).default(250),
15851
15851
  allow_concerns_to_complete: exports_external.boolean().default(true),
15852
- persist_knowledge_recommendations: exports_external.boolean().default(false)
15852
+ persist_knowledge_recommendations: exports_external.boolean().default(false),
15853
+ provenance_verify: exports_external.boolean().default(false)
15853
15854
  });
15854
15855
  KnowledgeApplicationConfigSchema = exports_external.object({
15855
15856
  enabled: exports_external.boolean().default(true),
@@ -58633,6 +58634,15 @@ async function transactKnowledge(filePath, mutate) {
58633
58634
  await atomicWriteFile(fp, content);
58634
58635
  }, mutate);
58635
58636
  }
58637
+ async function appendKnowledgeWithCapEnforcement(filePath, entry, maxEntries) {
58638
+ return transactKnowledge(filePath, (entries) => {
58639
+ const updated = [...entries, entry];
58640
+ if (updated.length > maxEntries) {
58641
+ return updated.slice(updated.length - maxEntries);
58642
+ }
58643
+ return updated;
58644
+ });
58645
+ }
58636
58646
  async function enforceKnowledgeCap(filePath, maxEntries) {
58637
58647
  await transactKnowledge(filePath, (entries) => {
58638
58648
  if (entries.length <= maxEntries)
@@ -58701,13 +58711,12 @@ async function sweepStaleTodos(filePath, todoMaxPhases) {
58701
58711
  });
58702
58712
  return result;
58703
58713
  }
58704
- async function appendRejectedLesson(directory, lesson) {
58714
+ async function appendRejectedLesson(directory, lesson, maxEntries = 20) {
58705
58715
  const filePath = resolveSwarmRejectedPath(directory);
58706
- const MAX = 20;
58707
58716
  await transactKnowledge(filePath, (existing) => {
58708
58717
  const updated = [...existing, lesson];
58709
- if (updated.length > MAX) {
58710
- return updated.slice(updated.length - MAX);
58718
+ if (updated.length > maxEntries) {
58719
+ return updated.slice(updated.length - maxEntries);
58711
58720
  }
58712
58721
  return updated;
58713
58722
  });
@@ -63808,18 +63817,20 @@ async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, c
63808
63817
  scope: "global",
63809
63818
  confidence: computeConfidence(0, true)
63810
63819
  };
63811
- const result = validateLesson(lesson, snapshotPlusNew.map((e) => e.lesson), meta3);
63812
- if (result.valid === false || result.severity === "error") {
63813
- const rejectedLesson = {
63814
- id: crypto.randomUUID(),
63815
- lesson,
63816
- rejection_reason: result.reason ?? "unknown",
63817
- rejected_at: new Date().toISOString(),
63818
- rejection_layer: result.layer ?? 1
63819
- };
63820
- await appendRejectedLesson(directory, rejectedLesson);
63821
- rejected++;
63822
- continue;
63820
+ if (config3.validation_enabled !== false) {
63821
+ const result = validateLesson(lesson, snapshotPlusNew.map((e) => e.lesson), meta3);
63822
+ if (result.valid === false || result.severity === "error") {
63823
+ const rejectedLesson = {
63824
+ id: crypto.randomUUID(),
63825
+ lesson,
63826
+ rejection_reason: result.reason ?? "unknown",
63827
+ rejected_at: new Date().toISOString(),
63828
+ rejection_layer: result.layer ?? 1
63829
+ };
63830
+ await appendRejectedLesson(directory, rejectedLesson, config3.rejected_max_entries);
63831
+ rejected++;
63832
+ continue;
63833
+ }
63823
63834
  }
63824
63835
  const duplicate = findNearDuplicate(lesson, snapshotPlusNew, config3.dedup_threshold);
63825
63836
  if (duplicate) {
@@ -92672,7 +92683,7 @@ function normalizeAgentWorkSummary(input, maxSummaryWords = MAX_AGENT_SUMMARY_WO
92672
92683
  };
92673
92684
  return AgentWorkSummarySchema.parse(candidate);
92674
92685
  }
92675
- var SUMMARY_SCHEMA_VERSION = "1.0.0", MAX_AGENT_SUMMARY_WORDS = 100, MAX_PHASE_SUMMARY_WORDS = 250, MAX_LIST_ITEMS = 5, SupervisorVerdictSchema, AgentWorkSummarySchema, PhaseArchitectureSummarySchema, SupervisorFindingSchema, KnowledgeRecommendationSchema, ArchitectureSupervisorReportSchema;
92686
+ var SUMMARY_SCHEMA_VERSION = "1.0.0", MAX_AGENT_SUMMARY_WORDS = 100, MAX_PHASE_SUMMARY_WORDS = 250, MAX_LIST_ITEMS = 5, SupervisorVerdictSchema, AgentWorkSummarySchema, PhaseArchitectureSummarySchema, SupervisorFindingSchema, KnowledgeRecommendationSchema, EvidenceProvenanceSchema, ArchitectureSupervisorReportSchema;
92676
92687
  var init_schema3 = __esm(() => {
92677
92688
  init_zod();
92678
92689
  SupervisorVerdictSchema = exports_external.enum([
@@ -92726,13 +92737,19 @@ var init_schema3 = __esm(() => {
92726
92737
  confidence: exports_external.number().min(0).max(1).default(0.5),
92727
92738
  evidence_refs: exports_external.array(exports_external.string().min(1)).default([])
92728
92739
  });
92740
+ EvidenceProvenanceSchema = exports_external.object({
92741
+ agent_name: exports_external.string().min(1).optional(),
92742
+ session_id: exports_external.string().min(1).optional(),
92743
+ captured_at: exports_external.string().datetime().optional()
92744
+ });
92729
92745
  ArchitectureSupervisorReportSchema = exports_external.object({
92730
92746
  schema_version: exports_external.literal(SUMMARY_SCHEMA_VERSION),
92731
92747
  phase: exports_external.number().int().min(0).max(999),
92732
92748
  verdict: SupervisorVerdictSchema,
92733
92749
  findings: exports_external.array(SupervisorFindingSchema).default([]),
92734
92750
  knowledge_recommendations: exports_external.array(KnowledgeRecommendationSchema).default([]),
92735
- created_at: exports_external.string().datetime()
92751
+ created_at: exports_external.string().datetime(),
92752
+ provenance: EvidenceProvenanceSchema.optional()
92736
92753
  });
92737
92754
  });
92738
92755
 
@@ -92824,7 +92841,8 @@ function writeSupervisorReport(directory, report) {
92824
92841
  timestamp: report.created_at,
92825
92842
  verdict: report.verdict,
92826
92843
  findings: report.findings,
92827
- knowledge_recommendations: report.knowledge_recommendations
92844
+ knowledge_recommendations: report.knowledge_recommendations,
92845
+ ...report.provenance ? { provenance: report.provenance } : {}
92828
92846
  }
92829
92847
  ]
92830
92848
  };
@@ -96961,9 +96979,14 @@ async function readMergedKnowledge(directory, config3, context, opts) {
96961
96979
  } else if (entry.tags.length === 0) {
96962
96980
  keywordsScore = 0.5;
96963
96981
  }
96964
- const tierBoost = entry.tier === "hive" ? HIVE_TIER_BOOST : 0;
96965
- const isSameProjectSource = context?.projectName && entry.tier === "hive" && "source_project" in entry && entry.source_project === context.projectName;
96966
- const sameProjectPenalty = isSameProjectSource ? SAME_PROJECT_PENALTY : 0;
96982
+ let tierBoost = 0;
96983
+ let isSameProject = false;
96984
+ if (entry.tier === "hive" && "source_project" in entry) {
96985
+ const sourceProject = entry.source_project;
96986
+ isSameProject = !!(context?.projectName && sourceProject === context.projectName);
96987
+ tierBoost = HIVE_TIER_BOOST;
96988
+ }
96989
+ const sameProjectPenalty = isSameProject ? DEFAULT_SAME_PROJECT_PENALTY : 0;
96967
96990
  const finalScore = categoryScore * 0.4 + confidenceScore * 0.35 + keywordsScore * 0.25 + tierBoost + sameProjectPenalty;
96968
96991
  const relevanceScore = {
96969
96992
  category: categoryScore,
@@ -97112,7 +97135,7 @@ function scoreDirectiveAgainstContext(entry, ctx) {
97112
97135
  score += 0.1;
97113
97136
  return { triggerHit, actionHit, agentHit, score: Math.min(1, score) };
97114
97137
  }
97115
- var JACCARD_THRESHOLD2 = 0.6, HIVE_TIER_BOOST = 0.05, SAME_PROJECT_PENALTY = -0.05, QUARANTINED_STATUS = "quarantined";
97138
+ var JACCARD_THRESHOLD2 = 0.6, HIVE_TIER_BOOST = 0.05, DEFAULT_SAME_PROJECT_PENALTY = -0.05, QUARANTINED_STATUS = "quarantined";
97116
97139
  var init_knowledge_reader = __esm(() => {
97117
97140
  init_task_file();
97118
97141
  init_logger();
@@ -120704,8 +120727,12 @@ var knowledge_add = createSwarmTool({
120704
120727
  hive_eligible: false,
120705
120728
  ...actionable
120706
120729
  };
120730
+ let config3;
120731
+ let dedupThreshold = 0.6;
120707
120732
  try {
120708
- const { config: config3 } = loadPluginConfigWithMeta(directory);
120733
+ const loaded = loadPluginConfigWithMeta(directory);
120734
+ config3 = loaded.config;
120735
+ dedupThreshold = config3.knowledge?.dedup_threshold ?? 0.6;
120709
120736
  if (config3.knowledge?.validation_enabled !== false) {
120710
120737
  const validation2 = validateLesson(lesson, [], {
120711
120738
  category,
@@ -120722,7 +120749,7 @@ var knowledge_add = createSwarmTool({
120722
120749
  } catch {}
120723
120750
  try {
120724
120751
  const existingEntries = await readKnowledge(resolveSwarmKnowledgePath(directory));
120725
- const duplicate = findNearDuplicate(lesson, existingEntries, 0.6);
120752
+ const duplicate = findNearDuplicate(lesson, existingEntries, dedupThreshold);
120726
120753
  if (duplicate) {
120727
120754
  return JSON.stringify({
120728
120755
  success: false,
@@ -120747,7 +120774,8 @@ var knowledge_add = createSwarmTool({
120747
120774
  });
120748
120775
  }
120749
120776
  try {
120750
- await appendKnowledge(resolveSwarmKnowledgePath(directory), entry);
120777
+ const maxEntries = config3?.knowledge?.swarm_max_entries ?? 100;
120778
+ await appendKnowledgeWithCapEnforcement(resolveSwarmKnowledgePath(directory), entry, maxEntries);
120751
120779
  } catch (err2) {
120752
120780
  const message = err2 instanceof Error ? err2.message : "Unknown error";
120753
120781
  return JSON.stringify({
@@ -121283,7 +121311,7 @@ init_zod();
121283
121311
  init_knowledge_store();
121284
121312
  init_create_tool();
121285
121313
  var knowledge_remove = createSwarmTool({
121286
- description: "Delete an outdated swarm knowledge entry by ID (swarm tier only — does not affect hive). Double-deletion is idempotent — removing a non-existent entry returns a clear message without error.",
121314
+ description: "Delete an outdated swarm knowledge entry by ID (swarm tier only — does not affect hive). Promoted entries cannot be deleted. Double-deletion is idempotent — removing a non-existent entry returns a clear message without error.",
121287
121315
  args: {
121288
121316
  id: exports_external.string().min(1).describe("UUID of the knowledge entry to remove")
121289
121317
  },
@@ -121305,8 +121333,16 @@ var knowledge_remove = createSwarmTool({
121305
121333
  const swarmPath = resolveSwarmKnowledgePath(directory);
121306
121334
  let found = false;
121307
121335
  let remaining = 0;
121336
+ let isPromoted = false;
121308
121337
  try {
121309
121338
  await transactKnowledge(swarmPath, (entries) => {
121339
+ const entryToDelete = entries.find((entry) => entry.id === id);
121340
+ if (!entryToDelete)
121341
+ return null;
121342
+ if (entryToDelete.status === "promoted") {
121343
+ isPromoted = true;
121344
+ return null;
121345
+ }
121310
121346
  const filtered = entries.filter((entry) => entry.id !== id);
121311
121347
  if (filtered.length === entries.length)
121312
121348
  return null;
@@ -121321,6 +121357,12 @@ var knowledge_remove = createSwarmTool({
121321
121357
  error: message
121322
121358
  });
121323
121359
  }
121360
+ if (isPromoted) {
121361
+ return JSON.stringify({
121362
+ success: false,
121363
+ message: "cannot delete promoted entry — this entry has been promoted to cross-project consensus"
121364
+ });
121365
+ }
121324
121366
  if (!found) {
121325
121367
  return JSON.stringify({
121326
121368
  success: false,
@@ -124641,6 +124683,17 @@ Findings: ${details.join("; ")}` : "";
124641
124683
  if (typeof asEntry.phase_number !== "number" || asEntry.phase_number !== phase) {
124642
124684
  return asBlocked("ARCH_SUPERVISOR_PHASE_MISMATCH", `Phase ${phase} cannot be completed: architecture supervisor evidence is for phase ${String(asEntry.phase_number)}, not phase ${phase}.`);
124643
124685
  }
124686
+ const gateWarnings = [];
124687
+ if (asConfig?.provenance_verify === true) {
124688
+ const provenance = asEntry.provenance;
124689
+ if (!provenance || !provenance.agent_name && !provenance.session_id) {
124690
+ return asBlocked("ARCH_SUPERVISOR_MISSING_PROVENANCE", `Phase ${phase} cannot be completed: architecture supervisor evidence lacks provenance (agent_name or session_id). Evidence provenance verification is enabled.`);
124691
+ }
124692
+ } else if (!asEntry.provenance || !asEntry.provenance.agent_name && !asEntry.provenance.session_id) {
124693
+ const msg = `Architecture supervisor evidence lacks provenance for phase ${phase}. Enable 'provenance_verify' in architectural_supervision config to enforce provenance verification.`;
124694
+ gateWarnings.push(msg);
124695
+ safeWarn(`[phase_complete] ${msg}`, undefined);
124696
+ }
124644
124697
  const asVerdict = asEntry.verdict;
124645
124698
  if (asVerdict === "REJECT") {
124646
124699
  return asBlocked("ARCH_SUPERVISOR_REJECTED", `Phase ${phase} cannot be completed: architecture supervisor returned verdict 'REJECT'. Address the system-level findings before completing the phase.${summarizeFindings(asEntry.findings)}`);
@@ -124653,7 +124706,12 @@ Findings: ${details.join("; ")}` : "";
124653
124706
  } else if (asVerdict !== "APPROVE") {
124654
124707
  return asBlocked("ARCH_SUPERVISOR_INVALID", `Phase ${phase} cannot be completed: architecture supervisor evidence contains unrecognized verdict '${String(asVerdict)}'. Expected one of: APPROVE, CONCERNS, REJECT.`);
124655
124708
  }
124656
- return { blocked: false, agentsDispatched, agentsMissing: [], warnings: [] };
124709
+ return {
124710
+ blocked: false,
124711
+ agentsDispatched,
124712
+ agentsMissing: [],
124713
+ warnings: gateWarnings
124714
+ };
124657
124715
  }
124658
124716
  // src/tools/phase-complete/gates/completion-verify-gate.ts
124659
124717
  async function runCompletionVerifyGate(ctx) {
@@ -124698,6 +124756,7 @@ import * as fs106 from "node:fs";
124698
124756
  import * as path153 from "node:path";
124699
124757
  async function runDriftGate(ctx) {
124700
124758
  const { phase, dir, sessionID, agentsDispatched, safeWarn } = ctx;
124759
+ const gateWarnings = [];
124701
124760
  let driftCheckEnabled = true;
124702
124761
  let driftHasEffectiveSpec = false;
124703
124762
  try {
@@ -124757,6 +124816,11 @@ async function runDriftGate(ctx) {
124757
124816
  for (const entry of entries) {
124758
124817
  if (typeof entry.type === "string" && entry.type.includes("drift") && typeof entry.verdict === "string") {
124759
124818
  driftVerdictFound = true;
124819
+ if (!entry.provenance || !entry.provenance.agent_name && !entry.provenance.session_id) {
124820
+ const msg = `Drift verification evidence lacks provenance for phase ${phase}. Evidence should include agent_name or session_id for verification.`;
124821
+ gateWarnings.push(msg);
124822
+ safeWarn(`[phase_complete] ${msg}`, undefined);
124823
+ }
124760
124824
  if (entry.verdict === "approved") {
124761
124825
  driftVerdictApproved = true;
124762
124826
  }
@@ -124847,7 +124911,7 @@ async function runDriftGate(ctx) {
124847
124911
  blocked: false,
124848
124912
  agentsDispatched,
124849
124913
  agentsMissing: [],
124850
- warnings: []
124914
+ warnings: gateWarnings
124851
124915
  };
124852
124916
  } catch (driftError) {
124853
124917
  return {
@@ -125179,6 +125243,7 @@ import * as fs110 from "node:fs";
125179
125243
  import * as path157 from "node:path";
125180
125244
  async function runPhaseCouncilGate(ctx) {
125181
125245
  const { phase, dir, sessionID, pluginConfig, agentsDispatched, safeWarn } = ctx;
125246
+ const gateWarnings = [];
125182
125247
  let councilModeEnabled = false;
125183
125248
  try {
125184
125249
  const plan = await loadPlan(dir);
@@ -125240,6 +125305,11 @@ async function runPhaseCouncilGate(ctx) {
125240
125305
  warnings: []
125241
125306
  };
125242
125307
  }
125308
+ if (!entry.provenance || !entry.provenance.agent_name && !entry.provenance.session_id) {
125309
+ const msg = `Phase council evidence lacks provenance for phase ${phase}. Evidence should include agent_name or session_id for verification.`;
125310
+ gateWarnings.push(msg);
125311
+ safeWarn(`[phase_complete] ${msg}`, undefined);
125312
+ }
125243
125313
  if (entry.verdict === "REJECT" || entry.verdict === "reject") {
125244
125314
  const requiredFixes = entry.requiredFixes ?? entry.required_fixes ?? [];
125245
125315
  const fixesDetail = Array.isArray(requiredFixes) && requiredFixes.length > 0 ? `
@@ -125358,7 +125428,12 @@ Advisory notes: ${advisoryNotes.join("; ")}` : "";
125358
125428
  safeWarn(`[phase_complete] Phase council gate error (non-blocking):`, pcError);
125359
125429
  }
125360
125430
  }
125361
- return { blocked: false, agentsDispatched, agentsMissing: [], warnings: [] };
125431
+ return {
125432
+ blocked: false,
125433
+ agentsDispatched,
125434
+ agentsMissing: [],
125435
+ warnings: gateWarnings
125436
+ };
125362
125437
  }
125363
125438
  // src/tools/phase-complete.ts
125364
125439
  init_resolve_working_directory();
@@ -133737,7 +133812,9 @@ var ArgsSchema4 = exports_external.object({
133737
133812
  phaseSummary: exports_external.string().min(1),
133738
133813
  roundNumber: exports_external.number().int().min(1).max(10).optional(),
133739
133814
  verdicts: exports_external.array(VerdictSchema2).min(1).max(5),
133740
- working_directory: exports_external.string().optional()
133815
+ working_directory: exports_external.string().optional(),
133816
+ provenanceAgentName: exports_external.string().min(1).optional(),
133817
+ provenanceSessionId: exports_external.string().min(1).optional()
133741
133818
  });
133742
133819
  var submit_phase_council_verdicts = createSwarmTool({
133743
133820
  description: "Submit pre-collected council member verdicts for PHASE-LEVEL synthesis. " + "PREREQUISITE — you MUST dispatch each council member (critic, reviewer, sme, " + "test_engineer, explorer) as separate Agent tasks with PHASE-SCOPED context and " + "collect their verdict responses BEFORE calling this tool. This tool performs " + "synthesis only — it does NOT dispatch, invoke, or contact council members. " + "Writes .swarm/evidence/{phase}/phase-council.json which is required by " + "phase_complete Gate 5 when phase_council is enabled. " + "Architect-only. Config-gated via council.enabled.",
@@ -133768,7 +133845,9 @@ var submit_phase_council_verdicts = createSwarmTool({
133768
133845
  criteriaUnmet: exports_external.array(exports_external.string()),
133769
133846
  durationMs: exports_external.number()
133770
133847
  })).min(1).max(5).describe("Collected CouncilMemberVerdict objects from all dispatched council members"),
133771
- working_directory: exports_external.string().optional().describe("Working directory where the plan is located")
133848
+ working_directory: exports_external.string().optional().describe("Working directory where the plan is located"),
133849
+ provenanceAgentName: exports_external.string().min(1).optional().describe("Agent name that produced this evidence (optional provenance)"),
133850
+ provenanceSessionId: exports_external.string().min(1).optional().describe("Session ID of the agent that produced this evidence (optional provenance)")
133772
133851
  },
133773
133852
  async execute(args2, directory) {
133774
133853
  const parsed = ArgsSchema4.safeParse(args2);
@@ -133848,7 +133927,12 @@ var submit_phase_council_verdicts = createSwarmTool({
133848
133927
  message: `Phase council returned CONCERNS with ${synthesis.blockingConcernsCount} HIGH/CRITICAL finding(s) promoted to requiredFixes. These must be resolved before the phase can complete. Do NOT write evidence or proceed — address every requiredFix and resubmit.`
133849
133928
  }, null, 2);
133850
133929
  }
133851
- writePhaseCouncilEvidence(workingDir, synthesis);
133930
+ const provenance = input.provenanceAgentName || input.provenanceSessionId ? {
133931
+ agent_name: input.provenanceAgentName,
133932
+ session_id: input.provenanceSessionId,
133933
+ captured_at: new Date().toISOString()
133934
+ } : undefined;
133935
+ writePhaseCouncilEvidence(workingDir, synthesis, provenance);
133852
133936
  return JSON.stringify({
133853
133937
  success: true,
133854
133938
  overallVerdict: synthesis.overallVerdict,
@@ -133931,7 +134015,7 @@ function getPhaseMutationGapFinding(phaseNumber, workingDir) {
133931
134015
  };
133932
134016
  }
133933
134017
  }
133934
- function writePhaseCouncilEvidence(workingDir, synthesis) {
134018
+ function writePhaseCouncilEvidence(workingDir, synthesis, provenance) {
133935
134019
  const evidenceDir = path173.join(workingDir, ".swarm", "evidence", String(synthesis.phaseNumber));
133936
134020
  mkdirSync42(evidenceDir, { recursive: true });
133937
134021
  const evidenceFile = path173.join(evidenceDir, "phase-council.json");
@@ -133961,7 +134045,8 @@ function writePhaseCouncilEvidence(workingDir, synthesis) {
133961
134045
  evidence: finding.evidence
133962
134046
  })),
133963
134047
  roundNumber: synthesis.roundNumber,
133964
- allCriteriaMet: synthesis.allCriteriaMet
134048
+ allCriteriaMet: synthesis.allCriteriaMet,
134049
+ ...provenance ? { provenance } : {}
133965
134050
  }
133966
134051
  ]
133967
134052
  };
@@ -136791,7 +136876,9 @@ var ArgsSchema7 = exports_external.object({
136791
136876
  verdict: exports_external.enum(["APPROVE", "CONCERNS", "REJECT"]),
136792
136877
  findings: exports_external.array(FindingSchema2).default([]),
136793
136878
  knowledge_recommendations: exports_external.array(KnowledgeRecommendationSchema2).default([]),
136794
- working_directory: exports_external.string().optional()
136879
+ working_directory: exports_external.string().optional(),
136880
+ provenance_agent_name: exports_external.string().min(1).optional(),
136881
+ provenance_session_id: exports_external.string().min(1).optional()
136795
136882
  });
136796
136883
  var write_architecture_supervisor_evidence = createSwarmTool({
136797
136884
  description: "Persist the architecture supervisor verdict for a phase. PREREQUISITE: dispatch " + "critic_architecture_supervisor as an Agent task with the phase + agent summaries, " + "collect its strict-JSON verdict (verdict/findings/knowledge_recommendations), then " + "call this tool with those values. Writes .swarm/evidence/{phase}/" + "architecture-supervisor.json. This tool persists only — it does not contact the " + "supervisor. Architect-only; config-gated via architectural_supervision.enabled.",
@@ -136800,7 +136887,9 @@ var write_architecture_supervisor_evidence = createSwarmTool({
136800
136887
  verdict: exports_external.enum(["APPROVE", "CONCERNS", "REJECT"]).describe("Supervisor verdict."),
136801
136888
  findings: exports_external.array(FindingSchema2).optional().describe("System-level findings from the supervisor."),
136802
136889
  knowledge_recommendations: exports_external.array(KnowledgeRecommendationSchema2).optional().describe("Durable lessons proposed by the supervisor."),
136803
- working_directory: exports_external.string().optional()
136890
+ working_directory: exports_external.string().optional(),
136891
+ provenance_agent_name: exports_external.string().min(1).optional().describe("Agent name that produced this evidence (optional provenance)."),
136892
+ provenance_session_id: exports_external.string().min(1).optional().describe("Session ID of the agent that produced this evidence (optional provenance).")
136804
136893
  },
136805
136894
  execute: async (rawArgs, directory) => {
136806
136895
  const parsed = ArgsSchema7.safeParse(rawArgs);
@@ -136819,13 +136908,19 @@ var write_architecture_supervisor_evidence = createSwarmTool({
136819
136908
  if (!dirResult.success) {
136820
136909
  return JSON.stringify({ success: false, reason: dirResult.message }, null, 2);
136821
136910
  }
136911
+ const provenance = args2.provenance_agent_name || args2.provenance_session_id ? {
136912
+ agent_name: args2.provenance_agent_name,
136913
+ session_id: args2.provenance_session_id,
136914
+ captured_at: new Date().toISOString()
136915
+ } : undefined;
136822
136916
  const report = {
136823
136917
  schema_version: SUMMARY_SCHEMA_VERSION,
136824
136918
  phase: args2.phase,
136825
136919
  verdict: args2.verdict,
136826
136920
  findings: args2.findings,
136827
136921
  knowledge_recommendations: args2.knowledge_recommendations,
136828
- created_at: new Date().toISOString()
136922
+ created_at: new Date().toISOString(),
136923
+ ...provenance ? { provenance } : {}
136829
136924
  };
136830
136925
  const evidencePath = writeSupervisorReport(dirResult.directory, report);
136831
136926
  let knowledgeProposed = 0;
@@ -136918,12 +137013,18 @@ async function executeWriteDriftEvidence(args2, directory) {
136918
137013
  }, null, 2);
136919
137014
  }
136920
137015
  const normalizedVerdict = normalizeVerdict(args2.verdict);
137016
+ const provenance = args2.provenanceAgentName || args2.provenanceSessionId ? {
137017
+ agent_name: args2.provenanceAgentName,
137018
+ session_id: args2.provenanceSessionId,
137019
+ captured_at: new Date().toISOString()
137020
+ } : undefined;
136921
137021
  const evidenceEntry = {
136922
137022
  type: "drift-verification",
136923
137023
  verdict: normalizedVerdict,
136924
137024
  summary: summary.trim(),
136925
137025
  timestamp: new Date().toISOString(),
136926
- requirementCoverage: args2.requirementCoverage
137026
+ requirementCoverage: args2.requirementCoverage,
137027
+ ...provenance ? { provenance } : {}
136927
137028
  };
136928
137029
  const evidenceContent = {
136929
137030
  entries: [evidenceEntry]
@@ -137014,7 +137115,9 @@ var write_drift_evidence = createSwarmTool({
137014
137115
  phase: exports_external.number().int().min(1).describe("The phase number for the drift verification (e.g., 1, 2, 3)"),
137015
137116
  verdict: exports_external.enum(["APPROVED", "NEEDS_REVISION"]).describe("Verdict of the drift verification: 'APPROVED' or 'NEEDS_REVISION'"),
137016
137117
  summary: exports_external.string().describe("Human-readable summary of the drift verification"),
137017
- requirementCoverage: exports_external.string().optional().describe("Requirement coverage report from req_coverage tool (JSON string)")
137118
+ requirementCoverage: exports_external.string().optional().describe("Requirement coverage report from req_coverage tool (JSON string)"),
137119
+ provenanceAgentName: exports_external.string().min(1).optional().describe("Agent name that produced this evidence (optional provenance)"),
137120
+ provenanceSessionId: exports_external.string().min(1).optional().describe("Session ID of the agent that produced this evidence (optional provenance)")
137018
137121
  },
137019
137122
  execute: async (args2, directory) => {
137020
137123
  const rawPhase = args2.phase !== undefined ? Number(args2.phase) : 0;
@@ -137023,7 +137126,9 @@ var write_drift_evidence = createSwarmTool({
137023
137126
  phase: Number(args2.phase),
137024
137127
  verdict: String(args2.verdict),
137025
137128
  summary: String(args2.summary ?? ""),
137026
- requirementCoverage: args2.requirementCoverage !== undefined ? String(args2.requirementCoverage) : undefined
137129
+ requirementCoverage: args2.requirementCoverage !== undefined ? String(args2.requirementCoverage) : undefined,
137130
+ provenanceAgentName: args2.provenanceAgentName !== undefined ? String(args2.provenanceAgentName) : undefined,
137131
+ provenanceSessionId: args2.provenanceSessionId !== undefined ? String(args2.provenanceSessionId) : undefined
137027
137132
  };
137028
137133
  return await executeWriteDriftEvidence(writeDriftEvidenceArgs, directory);
137029
137134
  } catch (error93) {
@@ -137571,9 +137676,22 @@ var TOOL_MANIFEST = defineHandlers({
137571
137676
  });
137572
137677
 
137573
137678
  // src/tools/plugin-registration.ts
137574
- function buildPluginToolObject(agents) {
137679
+ function buildPluginToolObject(agents, config3) {
137575
137680
  const tools = {};
137681
+ const knowledgeEnabled = config3?.knowledge?.enabled !== false;
137682
+ const knowledgeTools = new Set([
137683
+ "knowledge_add",
137684
+ "knowledge_recall",
137685
+ "knowledge_remove",
137686
+ "knowledge_query",
137687
+ "knowledge_ack",
137688
+ "knowledge_receipt",
137689
+ "knowledge_archive"
137690
+ ]);
137576
137691
  for (const [name2, handler] of Object.entries(TOOL_MANIFEST)) {
137692
+ if (!knowledgeEnabled && knowledgeTools.has(name2)) {
137693
+ continue;
137694
+ }
137577
137695
  tools[name2] = handler();
137578
137696
  }
137579
137697
  tools.swarm_command = createSwarmCommandTool(agents);
@@ -137988,7 +138106,7 @@ async function initializeOpenCodeSwarm(ctx) {
137988
138106
  return {
137989
138107
  name: "opencode-swarm",
137990
138108
  agent: agents,
137991
- tool: buildPluginToolObject(agentDefinitionMap),
138109
+ tool: buildPluginToolObject(agentDefinitionMap, config3),
137992
138110
  event: safeHook(backgroundCompletionObserver.event),
137993
138111
  config: async (opencodeConfig) => {
137994
138112
  const isObjectRecord = (value) => typeof value === "object" && value !== null;
@@ -115,6 +115,16 @@ export declare const KnowledgeRecommendationSchema: z.ZodObject<{
115
115
  evidence_refs: z.ZodDefault<z.ZodArray<z.ZodString>>;
116
116
  }, z.core.$strip>;
117
117
  export type KnowledgeRecommendation = z.infer<typeof KnowledgeRecommendationSchema>;
118
+ /**
119
+ * Provenance metadata for evidence: agent identity, session binding, and capture timestamp.
120
+ * Optional for backwards compatibility; when present and in gate mode, gates verify these fields.
121
+ */
122
+ export declare const EvidenceProvenanceSchema: z.ZodObject<{
123
+ agent_name: z.ZodOptional<z.ZodString>;
124
+ session_id: z.ZodOptional<z.ZodString>;
125
+ captured_at: z.ZodOptional<z.ZodString>;
126
+ }, z.core.$strip>;
127
+ export type EvidenceProvenance = z.infer<typeof EvidenceProvenanceSchema>;
118
128
  export declare const ArchitectureSupervisorReportSchema: z.ZodObject<{
119
129
  schema_version: z.ZodLiteral<"1.0.0">;
120
130
  phase: z.ZodNumber;
@@ -144,5 +154,10 @@ export declare const ArchitectureSupervisorReportSchema: z.ZodObject<{
144
154
  evidence_refs: z.ZodDefault<z.ZodArray<z.ZodString>>;
145
155
  }, z.core.$strip>>>;
146
156
  created_at: z.ZodString;
157
+ provenance: z.ZodOptional<z.ZodObject<{
158
+ agent_name: z.ZodOptional<z.ZodString>;
159
+ session_id: z.ZodOptional<z.ZodString>;
160
+ captured_at: z.ZodOptional<z.ZodString>;
161
+ }, z.core.$strip>>;
147
162
  }, z.core.$strip>;
148
163
  export type ArchitectureSupervisorReport = z.infer<typeof ArchitectureSupervisorReportSchema>;
@@ -43,6 +43,11 @@ export interface RawSupervisorEntry {
43
43
  verdict?: string;
44
44
  findings?: unknown[];
45
45
  knowledge_recommendations?: unknown[];
46
+ provenance?: {
47
+ agent_name?: string;
48
+ session_id?: string;
49
+ captured_at?: string;
50
+ };
46
51
  }
47
52
  /**
48
53
  * Read the supervisor report sidecar raw (no zod), returning the supervisor entry or
@@ -10,6 +10,7 @@
10
10
  */
11
11
  import type { ToolDefinition } from '@opencode-ai/plugin/tool';
12
12
  import type { AgentDefinition } from '../agents/index.js';
13
+ import type { PluginConfig } from '../config/index.js';
13
14
  /**
14
15
  * Construct the plugin tool object: one handler per manifest entry, with
15
16
  * `swarm_command` overridden by its dependency-injected instance.
@@ -17,5 +18,7 @@ import type { AgentDefinition } from '../agents/index.js';
17
18
  * The manifest's `swarm_command` handler is the static (no-DI) form used only
18
19
  * for derivation; the real instance needs the agent definition map, which is
19
20
  * only available at plugin-init time.
21
+ *
22
+ * Knowledge tools are conditionally excluded when config.knowledge.enabled = false.
20
23
  */
21
- export declare function buildPluginToolObject(agents: Record<string, AgentDefinition>): Record<string, ToolDefinition>;
24
+ export declare function buildPluginToolObject(agents: Record<string, AgentDefinition>, config?: PluginConfig): Record<string, ToolDefinition>;
@@ -37,5 +37,7 @@ export declare const ArgsSchema: z.ZodObject<{
37
37
  durationMs: z.ZodNumber;
38
38
  }, z.core.$strip>>;
39
39
  working_directory: z.ZodOptional<z.ZodString>;
40
+ provenanceAgentName: z.ZodOptional<z.ZodString>;
41
+ provenanceSessionId: z.ZodOptional<z.ZodString>;
40
42
  }, z.core.$strip>;
41
43
  export declare const submit_phase_council_verdicts: ReturnType<typeof tool>;
@@ -16,6 +16,10 @@ export interface WriteDriftEvidenceArgs {
16
16
  summary: string;
17
17
  /** Requirement coverage report from req_coverage tool */
18
18
  requirementCoverage?: string;
19
+ /** Agent name that produced this evidence (optional provenance) */
20
+ provenanceAgentName?: string;
21
+ /** Session ID of the agent that produced this evidence (optional provenance) */
22
+ provenanceSessionId?: string;
19
23
  }
20
24
  /**
21
25
  * Execute the write_drift_evidence tool.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.64.0",
3
+ "version": "7.65.0",
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",