opencode-swarm 6.45.0 → 6.45.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.
@@ -1,5 +1,5 @@
1
1
  import type { AgentDefinition } from './architect';
2
2
  export declare const CURATOR_INIT_PROMPT = "## IDENTITY\nYou are Explorer in CURATOR_INIT mode. You consolidate prior session knowledge into an architect briefing.\nDO NOT use the Task tool to delegate. You ARE the agent that does the work.\n\nINPUT FORMAT:\nTASK: CURATOR_INIT\nPRIOR_SUMMARY: [JSON or \"none\"]\nKNOWLEDGE_ENTRIES: [JSON array of high-confidence entries]\nPROJECT_CONTEXT: [context.md excerpt]\n\nACTIONS:\n- Read the prior summary to understand session history\n- Cross-reference knowledge entries against project context\n- Identify contradictions (knowledge says X, project state shows Y)\n- Produce a concise briefing for the architect\n\nRULES:\n- Output under 2000 chars\n- No code modifications\n- Flag contradictions explicitly with CONTRADICTION: prefix\n- If no prior summary exists, state \"First session \u2014 no prior context\"\n\nOUTPUT FORMAT:\nBRIEFING:\n[concise summary of prior session state, key decisions, active blockers]\n\nCONTRADICTIONS:\n- [entry_id]: [description] (or \"None detected\")\n\nKNOWLEDGE_STATS:\n- Entries reviewed: [N]\n- Prior phases covered: [N]\n";
3
- export declare const CURATOR_PHASE_PROMPT = "## IDENTITY\nYou are Explorer in CURATOR_PHASE mode. You consolidate a completed phase into a digest.\nDO NOT use the Task tool to delegate. You ARE the agent that does the work.\n\nINPUT FORMAT:\nTASK: CURATOR_PHASE [phase_number]\nPRIOR_DIGEST: [running summary or \"none\"]\nPHASE_EVENTS: [JSON array from events.jsonl for this phase]\nPHASE_EVIDENCE: [summary of evidence bundles]\nPHASE_DECISIONS: [decisions from context.md]\nAGENTS_DISPATCHED: [list]\nAGENTS_EXPECTED: [list from config]\n\nACTIONS:\n- Extend the prior digest with this phase's outcomes (do NOT regenerate from scratch)\n- Identify workflow deviations: missing reviewer, missing retro, skipped test_engineer\n- Recommend knowledge updates: entries to promote, archive, or flag as contradicted\n- Summarize key decisions and blockers resolved\n\nRULES:\n- Output under 2000 chars\n- No code modifications\n- Compliance observations are READ-ONLY \u2014 report, do not enforce\n- Extend the digest, never replace it\n\nOUTPUT FORMAT:\nPHASE_DIGEST:\nphase: [N]\nsummary: [what was accomplished]\nagents_used: [list]\ntasks_completed: [N]/[total]\nkey_decisions: [list]\nblockers_resolved: [list]\n\nCOMPLIANCE:\n- [type]: [description] (or \"No deviations observed\")\n\nKNOWLEDGE_UPDATES:\n- [action] [entry_id or \"new\"]: [reason] (or \"No recommendations\")\n\nEXTENDED_DIGEST:\n[the full running digest with this phase appended]\n";
3
+ export declare const CURATOR_PHASE_PROMPT = "## IDENTITY\nYou are Explorer in CURATOR_PHASE mode. You consolidate a completed phase into a digest.\nDO NOT use the Task tool to delegate. You ARE the agent that does the work.\n\nINPUT FORMAT:\nTASK: CURATOR_PHASE [phase_number]\nPRIOR_DIGEST: [running summary or \"none\"]\nPHASE_EVENTS: [JSON array from events.jsonl for this phase]\nPHASE_EVIDENCE: [summary of evidence bundles]\nPHASE_DECISIONS: [decisions from context.md]\nAGENTS_DISPATCHED: [list]\nAGENTS_EXPECTED: [list from config]\n\nACTIONS:\n- Extend the prior digest with this phase's outcomes (do NOT regenerate from scratch)\n- Identify workflow deviations: missing reviewer, missing retro, skipped test_engineer\n- Recommend knowledge updates: entries to promote, archive, or flag as contradicted\n- Summarize key decisions and blockers resolved\n\nRULES:\n- Output under 2000 chars\n- No code modifications\n- Compliance observations are READ-ONLY \u2014 report, do not enforce\n- Extend the digest, never replace it\n\nOUTPUT FORMAT:\nPHASE_DIGEST:\nphase: [N]\nsummary: [what was accomplished]\nagents_used: [list]\ntasks_completed: [N]/[total]\nkey_decisions: [list]\nblockers_resolved: [list]\n\nCOMPLIANCE:\n- [type]: [description] (or \"No deviations observed\")\n\nKNOWLEDGE_UPDATES:\n- [action] new: [reason] (or \"No recommendations\")\nNOTE: Always use \"new\" as the token \u2014 existing entry IDs (UUID v4) are not available in this context. Any non-UUID token is treated as \"new\" by the parser. Only \"promote new:\" creates a new entry; \"archive new:\" and \"flag_contradiction new:\" are silently skipped because those actions require an existing entry to operate on.\n\nEXTENDED_DIGEST:\n[the full running digest with this phase appended]\n";
4
4
  export declare function createExplorerAgent(model: string, customPrompt?: string, customAppendPrompt?: string): AgentDefinition;
5
5
  export declare function createExplorerCuratorAgent(model: string, mode: 'CURATOR_INIT' | 'CURATOR_PHASE', customAppendPrompt?: string): AgentDefinition;
package/dist/index.js CHANGED
@@ -32519,7 +32519,7 @@ __export(exports_co_change_analyzer, {
32519
32519
  buildCoChangeMatrix: () => buildCoChangeMatrix
32520
32520
  });
32521
32521
  import * as child_process2 from "child_process";
32522
- import { randomUUID } from "crypto";
32522
+ import { randomUUID as randomUUID2 } from "crypto";
32523
32523
  import { readdir as readdir2, readFile as readFile4, stat } from "fs/promises";
32524
32524
  import * as path19 from "path";
32525
32525
  import { promisify } from "util";
@@ -32779,7 +32779,7 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
32779
32779
  }
32780
32780
  const confidence = Math.min(0.3 + 0.2 * Math.min(pair.coChangeCount / 10, 1), 0.5);
32781
32781
  entries.push({
32782
- id: randomUUID(),
32782
+ id: randomUUID2(),
32783
32783
  tier: "swarm",
32784
32784
  lesson,
32785
32785
  category: "architecture",
@@ -36214,17 +36214,17 @@ function getTestFilesFromConvention(sourceFiles) {
36214
36214
  const testFiles = [];
36215
36215
  for (const file3 of sourceFiles) {
36216
36216
  const normalizedPath = file3.replace(/\\/g, "/");
36217
- const basename4 = path28.basename(file3);
36217
+ const basename5 = path28.basename(file3);
36218
36218
  const dirname12 = path28.dirname(file3);
36219
- if (hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
36219
+ if (hasCompoundTestExtension(basename5) || basename5.includes(".spec.") || basename5.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
36220
36220
  if (!testFiles.includes(file3)) {
36221
36221
  testFiles.push(file3);
36222
36222
  }
36223
36223
  continue;
36224
36224
  }
36225
36225
  for (const _pattern of TEST_PATTERNS) {
36226
- const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
36227
- const ext = path28.extname(basename4);
36226
+ const nameWithoutExt = basename5.replace(/\.[^.]+$/, "");
36227
+ const ext = path28.extname(basename5);
36228
36228
  const possibleTestFiles = [
36229
36229
  path28.join(dirname12, `${nameWithoutExt}.spec${ext}`),
36230
36230
  path28.join(dirname12, `${nameWithoutExt}.test${ext}`),
@@ -38054,17 +38054,17 @@ function normalizeSeparators(filePath) {
38054
38054
  }
38055
38055
  function matchesDocPattern(filePath, patterns) {
38056
38056
  const normalizedPath = normalizeSeparators(filePath);
38057
- const basename5 = path42.basename(filePath);
38057
+ const basename6 = path42.basename(filePath);
38058
38058
  for (const pattern of patterns) {
38059
38059
  if (!pattern.includes("/") && !pattern.includes("\\")) {
38060
- if (basename5 === pattern) {
38060
+ if (basename6 === pattern) {
38061
38061
  return true;
38062
38062
  }
38063
38063
  continue;
38064
38064
  }
38065
38065
  if (pattern.startsWith("**/")) {
38066
38066
  const filenamePattern = pattern.slice(3);
38067
- if (basename5 === filenamePattern) {
38067
+ if (basename6 === filenamePattern) {
38068
38068
  return true;
38069
38069
  }
38070
38070
  continue;
@@ -44118,7 +44118,8 @@ COMPLIANCE:
44118
44118
  - [type]: [description] (or "No deviations observed")
44119
44119
 
44120
44120
  KNOWLEDGE_UPDATES:
44121
- - [action] [entry_id or "new"]: [reason] (or "No recommendations")
44121
+ - [action] new: [reason] (or "No recommendations")
44122
+ NOTE: Always use "new" as the token \u2014 existing entry IDs (UUID v4) are not available in this context. Any non-UUID token is treated as "new" by the parser. Only "promote new:" creates a new entry; "archive new:" and "flag_contradiction new:" are silently skipped because those actions require an existing entry to operate on.
44122
44123
 
44123
44124
  EXTENDED_DIGEST:
44124
44125
  [the full running digest with this phase appended]
@@ -48202,6 +48203,7 @@ async function handleConfigCommand(directory, _args) {
48202
48203
  init_schema();
48203
48204
 
48204
48205
  // src/hooks/curator.ts
48206
+ import { randomUUID } from "crypto";
48205
48207
  import * as fs12 from "fs";
48206
48208
  import * as path18 from "path";
48207
48209
  init_event_bus();
@@ -48223,7 +48225,8 @@ function parseKnowledgeRecommendations(llmOutput) {
48223
48225
  const match = trimmed.match(/^-\s+(promote|archive|flag_contradiction)\s+(\S+):\s+(.+)$/i);
48224
48226
  if (match) {
48225
48227
  const action = match[1].toLowerCase();
48226
- const entryId = match[2] === "new" ? undefined : match[2];
48228
+ const UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
48229
+ const entryId = match[2] === "new" || !UUID_V4.test(match[2]) ? undefined : match[2];
48227
48230
  const reason = match[3].trim();
48228
48231
  recommendations.push({
48229
48232
  action,
@@ -48737,6 +48740,43 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, _knowled
48737
48740
  if (modified) {
48738
48741
  await rewriteKnowledge(knowledgePath, updatedEntries);
48739
48742
  }
48743
+ for (const rec of recommendations) {
48744
+ if (rec.entry_id !== undefined)
48745
+ continue;
48746
+ if (rec.action !== "promote") {
48747
+ skipped++;
48748
+ continue;
48749
+ }
48750
+ const lesson = rec.lesson?.trim() ?? "";
48751
+ if (lesson.length < 15) {
48752
+ skipped++;
48753
+ continue;
48754
+ }
48755
+ const now = new Date().toISOString();
48756
+ const newEntry = {
48757
+ id: randomUUID(),
48758
+ tier: "swarm",
48759
+ lesson: lesson.slice(0, 280),
48760
+ category: "other",
48761
+ tags: [],
48762
+ scope: "global",
48763
+ confidence: 0.5,
48764
+ status: "candidate",
48765
+ confirmed_by: [],
48766
+ retrieval_outcomes: {
48767
+ applied_count: 0,
48768
+ succeeded_after_count: 0,
48769
+ failed_after_count: 0
48770
+ },
48771
+ schema_version: 1,
48772
+ created_at: now,
48773
+ updated_at: now,
48774
+ auto_generated: true,
48775
+ project_name: path18.basename(directory)
48776
+ };
48777
+ await appendKnowledge(knowledgePath, newEntry);
48778
+ applied++;
48779
+ }
48740
48780
  return { applied, skipped };
48741
48781
  }
48742
48782
 
@@ -50416,7 +50456,7 @@ init_schema();
50416
50456
 
50417
50457
  // src/hooks/knowledge-migrator.ts
50418
50458
  init_knowledge_store();
50419
- import { randomUUID as randomUUID2 } from "crypto";
50459
+ import { randomUUID as randomUUID3 } from "crypto";
50420
50460
  import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
50421
50461
  import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
50422
50462
  import * as path23 from "path";
@@ -50486,7 +50526,7 @@ async function migrateContextToKnowledge(directory, config3) {
50486
50526
  }
50487
50527
  const inferredTags = inferTags(raw.text);
50488
50528
  const entry = {
50489
- id: randomUUID2(),
50529
+ id: randomUUID3(),
50490
50530
  tier: "swarm",
50491
50531
  lesson: truncateLesson(raw.text),
50492
50532
  category: raw.categoryHint ?? inferCategoryFromText(raw.text),
@@ -59858,7 +59898,7 @@ function countCodeLines(content) {
59858
59898
  return lines.length;
59859
59899
  }
59860
59900
  function isTestFile(filePath) {
59861
- const basename7 = path52.basename(filePath);
59901
+ const basename8 = path52.basename(filePath);
59862
59902
  const _ext = path52.extname(filePath).toLowerCase();
59863
59903
  const testPatterns = [
59864
59904
  ".test.",
@@ -59874,7 +59914,7 @@ function isTestFile(filePath) {
59874
59914
  ".spec.jsx"
59875
59915
  ];
59876
59916
  for (const pattern of testPatterns) {
59877
- if (basename7.includes(pattern)) {
59917
+ if (basename8.includes(pattern)) {
59878
59918
  return true;
59879
59919
  }
59880
59920
  }
@@ -60540,7 +60580,12 @@ var curator_analyze = createSwarmTool({
60540
60580
  let applied = 0;
60541
60581
  let skipped = 0;
60542
60582
  if (typedArgs.recommendations && typedArgs.recommendations.length > 0) {
60543
- const result = await applyCuratorKnowledgeUpdates(directory, typedArgs.recommendations, knowledgeConfig);
60583
+ const UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
60584
+ const sanitizedRecs = typedArgs.recommendations.map((rec) => ({
60585
+ ...rec,
60586
+ entry_id: rec.entry_id === undefined || UUID_V4.test(rec.entry_id) ? rec.entry_id : undefined
60587
+ }));
60588
+ const result = await applyCuratorKnowledgeUpdates(directory, sanitizedRecs, knowledgeConfig);
60544
60589
  applied = result.applied;
60545
60590
  skipped = result.skipped;
60546
60591
  }
@@ -62218,7 +62263,7 @@ var imports = createSwarmTool({
62218
62263
  init_dist();
62219
62264
  init_config();
62220
62265
  init_knowledge_store();
62221
- import { randomUUID as randomUUID5 } from "crypto";
62266
+ import { randomUUID as randomUUID6 } from "crypto";
62222
62267
  init_manager2();
62223
62268
  init_create_tool();
62224
62269
  var VALID_CATEGORIES2 = [
@@ -62293,7 +62338,7 @@ var knowledgeAdd = createSwarmTool({
62293
62338
  project_name = plan?.title ?? "";
62294
62339
  } catch {}
62295
62340
  const entry = {
62296
- id: randomUUID5(),
62341
+ id: randomUUID6(),
62297
62342
  tier: "swarm",
62298
62343
  lesson,
62299
62344
  category,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "6.45.0",
3
+ "version": "6.45.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",