opencode-swarm 7.87.0 → 7.87.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,8 +1,8 @@
1
1
  // @bun
2
2
  import {
3
3
  handleGuardrailExplain
4
- } from "./index-f13d3b69.js";
5
- import"./index-wv2yj8ka.js";
4
+ } from "./index-ts2j1wjr.js";
5
+ import"./index-gwzpy671.js";
6
6
  import"./index-5hvbw5xh.js";
7
7
  import"./index-yhsmmv2z.js";
8
8
  import"./index-s8bj492g.js";
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  handleGuardrailExplain
4
- } from "./index-f13d3b69.js";
4
+ } from "./index-ts2j1wjr.js";
5
5
  import {
6
6
  handleGuardrailLog
7
7
  } from "./index-5vpe6vq9.js";
@@ -76,7 +76,7 @@ import {
76
76
  handleWriteRetroCommand,
77
77
  normalizeSwarmCommandInput,
78
78
  resolveCommand
79
- } from "./index-wv2yj8ka.js";
79
+ } from "./index-gwzpy671.js";
80
80
  import"./index-5hvbw5xh.js";
81
81
  import"./index-yhsmmv2z.js";
82
82
  import"./index-s8bj492g.js";
@@ -894,7 +894,7 @@ var init_executor = __esm(() => {
894
894
  // package.json
895
895
  var package_default = {
896
896
  name: "opencode-swarm",
897
- version: "7.87.0",
897
+ version: "7.87.1",
898
898
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
899
899
  main: "dist/index.js",
900
900
  types: "dist/index.d.ts",
@@ -18161,7 +18161,26 @@ var SECRET_PATTERNS = [
18161
18161
  },
18162
18162
  {
18163
18163
  type: "env_secret",
18164
- pattern: /\b(?:[A-Z0-9]+_)*(?:KEY|TOKEN|SECRET|PASSWORD)\b\s*=\s*["']?[^\s"'`]{8,}["']?/gi
18164
+ pattern: /\b(?:[A-Z][A-Z0-9]+_)+(?:KEY|TOKEN|SECRET|PASSWORD)\b\s*=\s*["']?[^\s"'`]{8,}["']?/gi
18165
+ },
18166
+ { type: "gitlab_token", pattern: /\bgl(?:pat|ptt)-[A-Za-z0-9_-]{15,}\b/g },
18167
+ { type: "slack_token", pattern: /\bxox[abprs]-[A-Za-z0-9-]{10,}\b/g },
18168
+ {
18169
+ type: "jwt_token",
18170
+ pattern: /\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g
18171
+ },
18172
+ {
18173
+ type: "aws_secret_access_key",
18174
+ pattern: /\b(?:aws_secret_access_key|AWS_SECRET_ACCESS_KEY)\s*[=:]\s*[A-Za-z0-9/+=]{40}\b/g
18175
+ },
18176
+ {
18177
+ type: "stripe_secret_key",
18178
+ pattern: /\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{24,}\b/g
18179
+ },
18180
+ { type: "google_api_key", pattern: /\bAIza[0-9A-Za-z_-]{35}\b/g },
18181
+ {
18182
+ type: "openssh_private_key_block",
18183
+ pattern: /-----BEGIN[ ]OPENSSH[ ]PRIVATE[ ]KEY-----[\s\S]*?-----END[ ]OPENSSH[ ]PRIVATE[ ]KEY-----/g
18165
18184
  }
18166
18185
  ];
18167
18186
  function findSecrets(text) {
@@ -18732,7 +18751,7 @@ function normalizeMemoryAgentRole(agentRole) {
18732
18751
  if (base === "critic" || base === "critic_sounding_board" || base === "critic_drift_verifier" || base === "critic_hallucination_verifier" || base === "critic_architecture_supervisor") {
18733
18752
  return "security";
18734
18753
  }
18735
- if (base === "curator_init" || base === "curator_phase")
18754
+ if (base === "curator_init" || base === "curator_phase" || base === "curator_postmortem")
18736
18755
  return "curator";
18737
18756
  if (base === "docs")
18738
18757
  return "sme";
@@ -18743,6 +18762,17 @@ function normalizeMemoryAgentRole(agentRole) {
18743
18762
  }
18744
18763
 
18745
18764
  // src/memory/scoring.ts
18765
+ var SCORING_WEIGHTS = {
18766
+ textOverlap: 0.38,
18767
+ tagOverlap: 0.16,
18768
+ fileOverlap: 0.12,
18769
+ symbolOverlap: 0.08,
18770
+ taskTermOverlap: 0.08,
18771
+ scopeSpecificityBoost: 0.12,
18772
+ kindProfileBoost: 0.06,
18773
+ roleBoost: 0.05,
18774
+ confidence: 0.08
18775
+ };
18746
18776
  function tokenize(text) {
18747
18777
  return new Set(text.toLowerCase().replace(/[^\w\s-]/g, " ").split(/\s+/).map((token) => token.trim()).filter(Boolean));
18748
18778
  }
@@ -18848,7 +18878,7 @@ function scoreMemoryRecordDetailed(record, request, context) {
18848
18878
  if (request.mode === "injection" && request.requireQuerySignal !== false && !hasQuerySignal) {
18849
18879
  return { item: null, skipReason: "no_signal" };
18850
18880
  }
18851
- const score = textOverlap * 0.38 + tagOverlap * 0.16 + fileOverlap * 0.12 + symbolOverlap * 0.08 + taskTermOverlap * 0.08 + scopeSpecificityBoost(record.scope) * 0.12 + kindProfileBoost(record.kind, request) * 0.06 + roleBoost * 0.05 + record.confidence * 0.08;
18881
+ const score = textOverlap * SCORING_WEIGHTS.textOverlap + tagOverlap * SCORING_WEIGHTS.tagOverlap + fileOverlap * SCORING_WEIGHTS.fileOverlap + symbolOverlap * SCORING_WEIGHTS.symbolOverlap + taskTermOverlap * SCORING_WEIGHTS.taskTermOverlap + scopeSpecificityBoost(record.scope) * SCORING_WEIGHTS.scopeSpecificityBoost + kindProfileBoost(record.kind, request) * SCORING_WEIGHTS.kindProfileBoost + roleBoost * SCORING_WEIGHTS.roleBoost + record.confidence * SCORING_WEIGHTS.confidence;
18852
18882
  const reasonParts = [
18853
18883
  textOverlap > 0 ? `text_overlap=${textOverlap.toFixed(2)}` : null,
18854
18884
  tagOverlap > 0 ? `tag_overlap=${tagOverlap.toFixed(2)}` : null,
@@ -19548,7 +19578,6 @@ function loadDatabaseCtor2() {
19548
19578
  _DatabaseCtor2 = req("bun:sqlite").Database;
19549
19579
  return _DatabaseCtor2;
19550
19580
  }
19551
- var FTS_SCHEMA_MIGRATION_VERSION = 3;
19552
19581
  var FTS_SCHEMA_MIGRATION_NAME = "create_memory_fts5_shadow_index";
19553
19582
  var FTS_TABLE_NAME = "memory_items_fts";
19554
19583
  var FTS_INDEX_COLUMNS = [
@@ -19637,6 +19666,15 @@ var MIGRATIONS2 = [
19637
19666
  CREATE INDEX IF NOT EXISTS idx_memory_recall_usage_bundle
19638
19667
  ON memory_recall_usage(bundle_id);
19639
19668
  `
19669
+ },
19670
+ {
19671
+ version: 3,
19672
+ name: "create_memory_fts5_shadow_index",
19673
+ sql: `
19674
+ CREATE VIRTUAL TABLE IF NOT EXISTS ${FTS_TABLE_NAME} USING fts5(
19675
+ ${ftsCreateColumnsSql()}
19676
+ );
19677
+ `
19640
19678
  }
19641
19679
  ];
19642
19680
 
@@ -19645,6 +19683,7 @@ class SQLiteMemoryProvider {
19645
19683
  rootDirectory;
19646
19684
  config;
19647
19685
  initialized = false;
19686
+ initPromise = null;
19648
19687
  db = null;
19649
19688
  ftsAvailable = false;
19650
19689
  memories = new Map;
@@ -19688,6 +19727,15 @@ class SQLiteMemoryProvider {
19688
19727
  async initialize() {
19689
19728
  if (this.initialized)
19690
19729
  return;
19730
+ if (!this.initPromise) {
19731
+ this.initPromise = this.doInitialize().catch((err) => {
19732
+ this.initPromise = null;
19733
+ throw err;
19734
+ });
19735
+ }
19736
+ return this.initPromise;
19737
+ }
19738
+ async doInitialize() {
19691
19739
  const dbPath = this.databasePath();
19692
19740
  mkdirSync15(path40.dirname(dbPath), { recursive: true });
19693
19741
  const Db = loadDatabaseCtor2();
@@ -19883,6 +19931,7 @@ class SQLiteMemoryProvider {
19883
19931
  this.db = null;
19884
19932
  this.ftsAvailable = false;
19885
19933
  this.initialized = false;
19934
+ this.initPromise = null;
19886
19935
  this.lastAutomaticJsonlMigration = null;
19887
19936
  }
19888
19937
  async importJsonl() {
@@ -20019,8 +20068,6 @@ class SQLiteMemoryProvider {
20019
20068
  try {
20020
20069
  if (!this.hasMigration(FTS_SCHEMA_MIGRATION_NAME)) {
20021
20070
  this.recreateFtsIndex();
20022
- this.markMigration(FTS_SCHEMA_MIGRATION_VERSION, FTS_SCHEMA_MIGRATION_NAME);
20023
- this.insertEvent("migration", String(FTS_SCHEMA_MIGRATION_VERSION), FTS_SCHEMA_MIGRATION_NAME);
20024
20071
  } else {
20025
20072
  db.run(`CREATE VIRTUAL TABLE IF NOT EXISTS ${FTS_TABLE_NAME} USING fts5(
20026
20073
  ${ftsCreateColumnsSql()}
@@ -20353,12 +20400,60 @@ class SQLiteMemoryProvider {
20353
20400
  }
20354
20401
  requireDb() {
20355
20402
  if (!this.db)
20356
- throw new Error("SQLite memory provider is not initialized");
20403
+ throw new MemoryValidationError("SQLite memory provider is not initialized", "provider_not_initialized");
20357
20404
  return this.db;
20358
20405
  }
20359
20406
  }
20360
20407
  function splitSql(sql) {
20361
- return sql.split(";").map((statement) => statement.trim()).filter(Boolean);
20408
+ const statements = [];
20409
+ let current = "";
20410
+ let inSingleQuote = false;
20411
+ let inLineComment = false;
20412
+ for (let i = 0;i < sql.length; i++) {
20413
+ const char = sql[i];
20414
+ const next = sql[i + 1];
20415
+ if (inLineComment) {
20416
+ if (char === `
20417
+ `) {
20418
+ inLineComment = false;
20419
+ }
20420
+ continue;
20421
+ }
20422
+ if (inSingleQuote) {
20423
+ if (char === "'" && next === "'") {
20424
+ current += "''";
20425
+ i++;
20426
+ continue;
20427
+ }
20428
+ current += char;
20429
+ if (char === "'") {
20430
+ inSingleQuote = false;
20431
+ }
20432
+ continue;
20433
+ }
20434
+ if (char === "-" && next === "-") {
20435
+ inLineComment = true;
20436
+ i++;
20437
+ continue;
20438
+ }
20439
+ if (char === "'") {
20440
+ inSingleQuote = true;
20441
+ current += char;
20442
+ continue;
20443
+ }
20444
+ if (char === ";") {
20445
+ const trimmed2 = current.trim();
20446
+ if (trimmed2)
20447
+ statements.push(trimmed2);
20448
+ current = "";
20449
+ continue;
20450
+ }
20451
+ current += char;
20452
+ }
20453
+ const trimmed = current.trim();
20454
+ if (trimmed)
20455
+ statements.push(trimmed);
20456
+ return statements;
20362
20457
  }
20363
20458
  var FTS_STOP_WORDS = new Set([
20364
20459
  "a",
@@ -21087,7 +21182,16 @@ function parseEvaluateArgs(directory, args) {
21087
21182
  error: "Usage: /swarm memory evaluate [--json] [--fixtures <directory>]"
21088
21183
  };
21089
21184
  }
21090
- fixtureDirectory = path42.resolve(directory, next);
21185
+ const resolvedFixtures = path42.resolve(directory, next);
21186
+ const canonical = path42.normalize(resolvedFixtures) + path42.sep;
21187
+ const allowedRootA = path42.normalize(directory) + path42.sep;
21188
+ const allowedRootB = path42.normalize(path42.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall")) + path42.sep;
21189
+ if (!canonical.startsWith(allowedRootA) && !canonical.startsWith(allowedRootB)) {
21190
+ return {
21191
+ error: "--fixtures <directory> must resolve under the project directory or the bundled tests/fixtures/memory-recall directory"
21192
+ };
21193
+ }
21194
+ fixtureDirectory = resolvedFixtures;
21091
21195
  i++;
21092
21196
  continue;
21093
21197
  }
@@ -29151,7 +29255,7 @@ function buildDetailedHelp(commandName, entry) {
29151
29255
  async function handleHelpCommand(ctx) {
29152
29256
  const targetCommand = ctx.args.join(" ");
29153
29257
  if (!targetCommand) {
29154
- const { buildHelpText } = await import("./index-0m44n5qv.js");
29258
+ const { buildHelpText } = await import("./index-dsjyfd3g.js");
29155
29259
  return buildHelpText();
29156
29260
  }
29157
29261
  const tokens = targetCommand.split(/\s+/);
@@ -29160,7 +29264,7 @@ async function handleHelpCommand(ctx) {
29160
29264
  return _internals44.buildDetailedHelp(resolved.key, resolved.entry);
29161
29265
  }
29162
29266
  const similar = _internals44.findSimilarCommands(targetCommand);
29163
- const { buildHelpText: fullHelp } = await import("./index-0m44n5qv.js");
29267
+ const { buildHelpText: fullHelp } = await import("./index-dsjyfd3g.js");
29164
29268
  if (similar.length > 0) {
29165
29269
  return `Command '/swarm ${targetCommand}' not found.
29166
29270
 
@@ -29293,7 +29397,7 @@ var COMMAND_REGISTRY = {
29293
29397
  },
29294
29398
  "guardrail explain": {
29295
29399
  handler: async (ctx) => {
29296
- const { handleGuardrailExplain } = await import("./guardrail-explain-wb1cj312.js");
29400
+ const { handleGuardrailExplain } = await import("./guardrail-explain-scym5r5y.js");
29297
29401
  return handleGuardrailExplain(ctx.directory, ctx.args);
29298
29402
  },
29299
29403
  description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
@@ -12,7 +12,7 @@ import {
12
12
  detectPosixWrites,
13
13
  detectWindowsWrites,
14
14
  resolveWriteTargets
15
- } from "./index-wv2yj8ka.js";
15
+ } from "./index-gwzpy671.js";
16
16
  import {
17
17
  checkFileAuthority,
18
18
  classifyFile,
package/dist/cli/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  getPluginLockFilePaths,
8
8
  package_default,
9
9
  resolveCommand
10
- } from "./index-wv2yj8ka.js";
10
+ } from "./index-gwzpy671.js";
11
11
  import"./index-5hvbw5xh.js";
12
12
  import"./index-yhsmmv2z.js";
13
13
  import"./index-s8bj492g.js";
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.87.0",
72
+ version: "7.87.1",
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",
@@ -82494,7 +82494,26 @@ var init_redaction = __esm(() => {
82494
82494
  },
82495
82495
  {
82496
82496
  type: "env_secret",
82497
- pattern: /\b(?:[A-Z0-9]+_)*(?:KEY|TOKEN|SECRET|PASSWORD)\b\s*=\s*["']?[^\s"'`]{8,}["']?/gi
82497
+ pattern: /\b(?:[A-Z][A-Z0-9]+_)+(?:KEY|TOKEN|SECRET|PASSWORD)\b\s*=\s*["']?[^\s"'`]{8,}["']?/gi
82498
+ },
82499
+ { type: "gitlab_token", pattern: /\bgl(?:pat|ptt)-[A-Za-z0-9_-]{15,}\b/g },
82500
+ { type: "slack_token", pattern: /\bxox[abprs]-[A-Za-z0-9-]{10,}\b/g },
82501
+ {
82502
+ type: "jwt_token",
82503
+ pattern: /\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g
82504
+ },
82505
+ {
82506
+ type: "aws_secret_access_key",
82507
+ pattern: /\b(?:aws_secret_access_key|AWS_SECRET_ACCESS_KEY)\s*[=:]\s*[A-Za-z0-9/+=]{40}\b/g
82508
+ },
82509
+ {
82510
+ type: "stripe_secret_key",
82511
+ pattern: /\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{24,}\b/g
82512
+ },
82513
+ { type: "google_api_key", pattern: /\bAIza[0-9A-Za-z_-]{35}\b/g },
82514
+ {
82515
+ type: "openssh_private_key_block",
82516
+ pattern: /-----BEGIN[ ]OPENSSH[ ]PRIVATE[ ]KEY-----[\s\S]*?-----END[ ]OPENSSH[ ]PRIVATE[ ]KEY-----/g
82498
82517
  }
82499
82518
  ];
82500
82519
  });
@@ -83012,7 +83031,7 @@ function normalizeMemoryAgentRole(agentRole) {
83012
83031
  if (base === "critic" || base === "critic_sounding_board" || base === "critic_drift_verifier" || base === "critic_hallucination_verifier" || base === "critic_architecture_supervisor") {
83013
83032
  return "security";
83014
83033
  }
83015
- if (base === "curator_init" || base === "curator_phase")
83034
+ if (base === "curator_init" || base === "curator_phase" || base === "curator_postmortem")
83016
83035
  return "curator";
83017
83036
  if (base === "docs")
83018
83037
  return "sme";
@@ -83202,7 +83221,7 @@ function scoreMemoryRecordDetailed(record3, request, context) {
83202
83221
  if (request.mode === "injection" && request.requireQuerySignal !== false && !hasQuerySignal) {
83203
83222
  return { item: null, skipReason: "no_signal" };
83204
83223
  }
83205
- const score = textOverlap * 0.38 + tagOverlap * 0.16 + fileOverlap * 0.12 + symbolOverlap * 0.08 + taskTermOverlap * 0.08 + scopeSpecificityBoost(record3.scope) * 0.12 + kindProfileBoost(record3.kind, request) * 0.06 + roleBoost * 0.05 + record3.confidence * 0.08;
83224
+ const score = textOverlap * SCORING_WEIGHTS.textOverlap + tagOverlap * SCORING_WEIGHTS.tagOverlap + fileOverlap * SCORING_WEIGHTS.fileOverlap + symbolOverlap * SCORING_WEIGHTS.symbolOverlap + taskTermOverlap * SCORING_WEIGHTS.taskTermOverlap + scopeSpecificityBoost(record3.scope) * SCORING_WEIGHTS.scopeSpecificityBoost + kindProfileBoost(record3.kind, request) * SCORING_WEIGHTS.kindProfileBoost + roleBoost * SCORING_WEIGHTS.roleBoost + record3.confidence * SCORING_WEIGHTS.confidence;
83206
83225
  const reasonParts = [
83207
83226
  textOverlap > 0 ? `text_overlap=${textOverlap.toFixed(2)}` : null,
83208
83227
  tagOverlap > 0 ? `tag_overlap=${tagOverlap.toFixed(2)}` : null,
@@ -83278,9 +83297,21 @@ function unionTokens(...sets) {
83278
83297
  }
83279
83298
  return union3;
83280
83299
  }
83300
+ var SCORING_WEIGHTS;
83281
83301
  var init_scoring = __esm(() => {
83282
83302
  init_role_profiles();
83283
83303
  init_schema2();
83304
+ SCORING_WEIGHTS = {
83305
+ textOverlap: 0.38,
83306
+ tagOverlap: 0.16,
83307
+ fileOverlap: 0.12,
83308
+ symbolOverlap: 0.08,
83309
+ taskTermOverlap: 0.08,
83310
+ scopeSpecificityBoost: 0.12,
83311
+ kindProfileBoost: 0.06,
83312
+ roleBoost: 0.05,
83313
+ confidence: 0.08
83314
+ };
83284
83315
  });
83285
83316
 
83286
83317
  // src/memory/local-jsonl-provider.ts
@@ -84013,6 +84044,7 @@ class SQLiteMemoryProvider {
84013
84044
  rootDirectory;
84014
84045
  config;
84015
84046
  initialized = false;
84047
+ initPromise = null;
84016
84048
  db = null;
84017
84049
  ftsAvailable = false;
84018
84050
  memories = new Map;
@@ -84056,6 +84088,15 @@ class SQLiteMemoryProvider {
84056
84088
  async initialize() {
84057
84089
  if (this.initialized)
84058
84090
  return;
84091
+ if (!this.initPromise) {
84092
+ this.initPromise = this.doInitialize().catch((err2) => {
84093
+ this.initPromise = null;
84094
+ throw err2;
84095
+ });
84096
+ }
84097
+ return this.initPromise;
84098
+ }
84099
+ async doInitialize() {
84059
84100
  const dbPath = this.databasePath();
84060
84101
  mkdirSync27(path76.dirname(dbPath), { recursive: true });
84061
84102
  const Db = loadDatabaseCtor2();
@@ -84251,6 +84292,7 @@ class SQLiteMemoryProvider {
84251
84292
  this.db = null;
84252
84293
  this.ftsAvailable = false;
84253
84294
  this.initialized = false;
84295
+ this.initPromise = null;
84254
84296
  this.lastAutomaticJsonlMigration = null;
84255
84297
  }
84256
84298
  async importJsonl() {
@@ -84387,8 +84429,6 @@ class SQLiteMemoryProvider {
84387
84429
  try {
84388
84430
  if (!this.hasMigration(FTS_SCHEMA_MIGRATION_NAME)) {
84389
84431
  this.recreateFtsIndex();
84390
- this.markMigration(FTS_SCHEMA_MIGRATION_VERSION, FTS_SCHEMA_MIGRATION_NAME);
84391
- this.insertEvent("migration", String(FTS_SCHEMA_MIGRATION_VERSION), FTS_SCHEMA_MIGRATION_NAME);
84392
84432
  } else {
84393
84433
  db.run(`CREATE VIRTUAL TABLE IF NOT EXISTS ${FTS_TABLE_NAME} USING fts5(
84394
84434
  ${ftsCreateColumnsSql()}
@@ -84721,12 +84761,60 @@ class SQLiteMemoryProvider {
84721
84761
  }
84722
84762
  requireDb() {
84723
84763
  if (!this.db)
84724
- throw new Error("SQLite memory provider is not initialized");
84764
+ throw new MemoryValidationError("SQLite memory provider is not initialized", "provider_not_initialized");
84725
84765
  return this.db;
84726
84766
  }
84727
84767
  }
84728
84768
  function splitSql(sql) {
84729
- return sql.split(";").map((statement) => statement.trim()).filter(Boolean);
84769
+ const statements = [];
84770
+ let current = "";
84771
+ let inSingleQuote = false;
84772
+ let inLineComment = false;
84773
+ for (let i2 = 0;i2 < sql.length; i2++) {
84774
+ const char = sql[i2];
84775
+ const next = sql[i2 + 1];
84776
+ if (inLineComment) {
84777
+ if (char === `
84778
+ `) {
84779
+ inLineComment = false;
84780
+ }
84781
+ continue;
84782
+ }
84783
+ if (inSingleQuote) {
84784
+ if (char === "'" && next === "'") {
84785
+ current += "''";
84786
+ i2++;
84787
+ continue;
84788
+ }
84789
+ current += char;
84790
+ if (char === "'") {
84791
+ inSingleQuote = false;
84792
+ }
84793
+ continue;
84794
+ }
84795
+ if (char === "-" && next === "-") {
84796
+ inLineComment = true;
84797
+ i2++;
84798
+ continue;
84799
+ }
84800
+ if (char === "'") {
84801
+ inSingleQuote = true;
84802
+ current += char;
84803
+ continue;
84804
+ }
84805
+ if (char === ";") {
84806
+ const trimmed2 = current.trim();
84807
+ if (trimmed2)
84808
+ statements.push(trimmed2);
84809
+ current = "";
84810
+ continue;
84811
+ }
84812
+ current += char;
84813
+ }
84814
+ const trimmed = current.trim();
84815
+ if (trimmed)
84816
+ statements.push(trimmed);
84817
+ return statements;
84730
84818
  }
84731
84819
  function buildFtsQuery(request) {
84732
84820
  const text = request.mode === "injection" && request.task ? `${request.task}
@@ -84790,7 +84878,7 @@ function rerankWithFts(items, ftsOrder) {
84790
84878
  };
84791
84879
  }).sort((a, b) => b.score - a.score || a.record.id.localeCompare(b.record.id));
84792
84880
  }
84793
- var _DatabaseCtor2 = null, FTS_SCHEMA_MIGRATION_VERSION = 3, FTS_SCHEMA_MIGRATION_NAME = "create_memory_fts5_shadow_index", FTS_TABLE_NAME = "memory_items_fts", FTS_INDEX_COLUMNS, FTS_INSERT_COLUMNS, MIGRATIONS2, FTS_STOP_WORDS;
84881
+ var _DatabaseCtor2 = null, FTS_SCHEMA_MIGRATION_NAME = "create_memory_fts5_shadow_index", FTS_TABLE_NAME = "memory_items_fts", FTS_INDEX_COLUMNS, FTS_INSERT_COLUMNS, MIGRATIONS2, FTS_STOP_WORDS;
84794
84882
  var init_sqlite_provider = __esm(() => {
84795
84883
  init_utils2();
84796
84884
  init_config3();
@@ -84886,6 +84974,15 @@ var init_sqlite_provider = __esm(() => {
84886
84974
  CREATE INDEX IF NOT EXISTS idx_memory_recall_usage_bundle
84887
84975
  ON memory_recall_usage(bundle_id);
84888
84976
  `
84977
+ },
84978
+ {
84979
+ version: 3,
84980
+ name: "create_memory_fts5_shadow_index",
84981
+ sql: `
84982
+ CREATE VIRTUAL TABLE IF NOT EXISTS ${FTS_TABLE_NAME} USING fts5(
84983
+ ${ftsCreateColumnsSql()}
84984
+ );
84985
+ `
84889
84986
  }
84890
84987
  ];
84891
84988
  FTS_STOP_WORDS = new Set([
@@ -86036,65 +86133,69 @@ async function recallForAgent(input) {
86036
86133
  agentId: input.agentId,
86037
86134
  runId: input.sessionID
86038
86135
  }, { config: input.config });
86039
- const resolvedConfig = resolveMemoryConfig(input.config);
86040
- if (!gateway.isEnabled()) {
86041
- await logInjectionSkipped(input, "disabled");
86042
- return null;
86043
- }
86044
- if (!resolvedConfig.recall.injection.enabled) {
86045
- await logInjectionSkipped(input, "disabled");
86046
- return null;
86047
- }
86048
- const scopes = gateway.deriveAllowedScopes();
86049
- const planInput = {
86050
- userGoal: compactText(input.userGoal),
86051
- runId: input.sessionID ?? "unknown",
86052
- agentRole: input.agentRole,
86053
- agentId: input.agentId,
86054
- agentTask: compactText(input.agentTask),
86055
- touchedFiles: extractTouchedFiles(input.agentTask)
86056
- };
86057
- const plan = buildMemoryRecallPlan(planInput, { scopes });
86058
- plan.maxItems = resolvedConfig.recall.injection.maxItems;
86059
- plan.tokenBudget = resolvedConfig.recall.injection.tokenBudget;
86060
- await input.appendRunLog(input.directory, input.sessionID, {
86061
- event: "recall_requested",
86062
- runId: input.sessionID ?? "unknown",
86063
- agentRole: input.agentRole,
86064
- agentId: input.agentId,
86065
- metadata: {
86136
+ try {
86137
+ const resolvedConfig = resolveMemoryConfig(input.config);
86138
+ if (!gateway.isEnabled()) {
86139
+ await logInjectionSkipped(input, "disabled");
86140
+ return null;
86141
+ }
86142
+ if (!resolvedConfig.recall.injection.enabled) {
86143
+ await logInjectionSkipped(input, "disabled");
86144
+ return null;
86145
+ }
86146
+ const scopes = gateway.deriveAllowedScopes();
86147
+ const planInput = {
86148
+ userGoal: compactText(input.userGoal),
86149
+ runId: input.sessionID ?? "unknown",
86150
+ agentRole: input.agentRole,
86151
+ agentId: input.agentId,
86152
+ agentTask: compactText(input.agentTask),
86153
+ touchedFiles: extractTouchedFiles(input.agentTask)
86154
+ };
86155
+ const plan = buildMemoryRecallPlan(planInput, { scopes });
86156
+ plan.maxItems = resolvedConfig.recall.injection.maxItems;
86157
+ plan.tokenBudget = resolvedConfig.recall.injection.tokenBudget;
86158
+ await input.appendRunLog(input.directory, input.sessionID, {
86159
+ event: "recall_requested",
86160
+ runId: input.sessionID ?? "unknown",
86161
+ agentRole: input.agentRole,
86162
+ agentId: input.agentId,
86163
+ metadata: {
86164
+ kinds: plan.kinds,
86165
+ maxItems: plan.maxItems,
86166
+ tokenBudget: plan.tokenBudget,
86167
+ scopeTypes: plan.scopes.map((scope) => scope.type)
86168
+ }
86169
+ });
86170
+ const recallInput = {
86171
+ query: plan.query,
86172
+ task: planInput.agentTask,
86173
+ mode: "injection",
86174
+ scopes: plan.scopes,
86066
86175
  kinds: plan.kinds,
86067
86176
  maxItems: plan.maxItems,
86068
86177
  tokenBudget: plan.tokenBudget,
86069
- scopeTypes: plan.scopes.map((scope) => scope.type)
86178
+ minScore: resolvedConfig.recall.injection.minScore,
86179
+ requireQuerySignal: resolvedConfig.recall.injection.requireQuerySignal
86180
+ };
86181
+ const bundle = await gateway.recall(recallInput);
86182
+ await input.appendRunLog(input.directory, input.sessionID, {
86183
+ event: "recall_returned",
86184
+ runId: input.sessionID ?? "unknown",
86185
+ agentRole: input.agentRole,
86186
+ agentId: input.agentId,
86187
+ bundleId: bundle.id,
86188
+ memoryIds: bundle.items.map((item) => item.record.id),
86189
+ scores: bundle.items.map((item) => item.score),
86190
+ tokenEstimate: bundle.tokenEstimate
86191
+ });
86192
+ if (bundle.items.length === 0) {
86193
+ await logInjectionSkipped(input, bundle.diagnostics?.injectionSkipReason ?? "no_results", bundle);
86070
86194
  }
86071
- });
86072
- const recallInput = {
86073
- query: plan.query,
86074
- task: planInput.agentTask,
86075
- mode: "injection",
86076
- scopes: plan.scopes,
86077
- kinds: plan.kinds,
86078
- maxItems: plan.maxItems,
86079
- tokenBudget: plan.tokenBudget,
86080
- minScore: resolvedConfig.recall.injection.minScore,
86081
- requireQuerySignal: resolvedConfig.recall.injection.requireQuerySignal
86082
- };
86083
- const bundle = await gateway.recall(recallInput);
86084
- await input.appendRunLog(input.directory, input.sessionID, {
86085
- event: "recall_returned",
86086
- runId: input.sessionID ?? "unknown",
86087
- agentRole: input.agentRole,
86088
- agentId: input.agentId,
86089
- bundleId: bundle.id,
86090
- memoryIds: bundle.items.map((item) => item.record.id),
86091
- scores: bundle.items.map((item) => item.score),
86092
- tokenEstimate: bundle.tokenEstimate
86093
- });
86094
- if (bundle.items.length === 0) {
86095
- await logInjectionSkipped(input, bundle.diagnostics?.injectionSkipReason ?? "no_results", bundle);
86195
+ return { bundle, scopes };
86196
+ } finally {
86197
+ await gateway.dispose?.();
86096
86198
  }
86097
- return { bundle, scopes };
86098
86199
  }
86099
86200
  async function logInjectionSkipped(input, reason, bundle) {
86100
86201
  await input.appendRunLog(input.directory, input.sessionID, {
@@ -86136,7 +86237,7 @@ function parseTaskToolInput(input) {
86136
86237
  };
86137
86238
  }
86138
86239
  function isCuratorAgent(agentRole) {
86139
- return agentRole === "curator" || agentRole === "curator_init" || agentRole === "curator_phase";
86240
+ return agentRole === "curator" || agentRole === "curator_init" || agentRole === "curator_phase" || agentRole === "curator_postmortem";
86140
86241
  }
86141
86242
  function messagesContainRecall(messages) {
86142
86243
  return messages.some((message) => message?.parts?.some((part) => typeof part?.text === "string" && (part.text.includes(MEMORY_SENTINEL) || part.text.includes("Retrieved Swarm Memory"))));
@@ -86509,7 +86610,16 @@ function parseEvaluateArgs(directory, args2) {
86509
86610
  error: "Usage: /swarm memory evaluate [--json] [--fixtures <directory>]"
86510
86611
  };
86511
86612
  }
86512
- fixtureDirectory = path80.resolve(directory, next);
86613
+ const resolvedFixtures = path80.resolve(directory, next);
86614
+ const canonical = path80.normalize(resolvedFixtures) + path80.sep;
86615
+ const allowedRootA = path80.normalize(directory) + path80.sep;
86616
+ const allowedRootB = path80.normalize(path80.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall")) + path80.sep;
86617
+ if (!canonical.startsWith(allowedRootA) && !canonical.startsWith(allowedRootB)) {
86618
+ return {
86619
+ error: "--fixtures <directory> must resolve under the project directory or the bundled tests/fixtures/memory-recall directory"
86620
+ };
86621
+ }
86622
+ fixtureDirectory = resolvedFixtures;
86513
86623
  i2++;
86514
86624
  continue;
86515
86625
  }
@@ -103626,9 +103736,9 @@ function validateFilename(filename) {
103626
103736
  throw new Error("Invalid filename: contains null byte");
103627
103737
  }
103628
103738
  const pathSeparators = ["/", "\\", ".."];
103629
- for (const sep13 of pathSeparators) {
103630
- if (filename.includes(sep13)) {
103631
- throw new Error(`Invalid filename: contains path separator '${sep13}'`);
103739
+ for (const sep14 of pathSeparators) {
103740
+ if (filename.includes(sep14)) {
103741
+ throw new Error(`Invalid filename: contains path separator '${sep14}'`);
103632
103742
  }
103633
103743
  }
103634
103744
  if (filename.startsWith("/") || filename.startsWith("\\") || /^[a-zA-Z]:/.test(filename)) {
@@ -7,6 +7,24 @@ export interface RecallScoringDiagnostics {
7
7
  noSignalCount: number;
8
8
  belowThresholdCount: number;
9
9
  }
10
+ /**
11
+ * Recall scoring weight coefficients. Sum is 1.13 (scores are an unnormalised
12
+ * weighted sum; may exceed 1.0). minScore thresholds in DEFAULT_MEMORY_CONFIG
13
+ * are calibrated against these weights.
14
+ *
15
+ * Pinned by tests/unit/memory/scoring.test.ts to detect drift.
16
+ */
17
+ export declare const SCORING_WEIGHTS: {
18
+ readonly textOverlap: 0.38;
19
+ readonly tagOverlap: 0.16;
20
+ readonly fileOverlap: 0.12;
21
+ readonly symbolOverlap: 0.08;
22
+ readonly taskTermOverlap: 0.08;
23
+ readonly scopeSpecificityBoost: 0.12;
24
+ readonly kindProfileBoost: 0.06;
25
+ readonly roleBoost: 0.05;
26
+ readonly confidence: 0.08;
27
+ };
10
28
  export declare function sameScope(a: MemoryScopeRef, b: MemoryScopeRef): boolean;
11
29
  export declare function scopeAllowed(recordScope: MemoryScopeRef, allowedScopes: MemoryScopeRef[]): boolean;
12
30
  export declare function scoreMemoryRecord(record: MemoryRecord, request: RecallRequest): RecallResultItem | null;
@@ -3,6 +3,12 @@ import { type JsonlMigrationReport } from './jsonl-migration';
3
3
  import type { MemoryCompactOptions, MemoryCompactResult, MemoryProposalStore, MemoryProvider, MemoryRecallUsageEvent, MemoryRecallUsageFilter } from './provider';
4
4
  import type { RecallScoringDiagnostics } from './scoring';
5
5
  import type { AppliedMemoryChange, MemoryListFilter, MemoryProposal, MemoryRecord, RecallRequest, RecallResultItem, ResolvedCuratorMemoryDecision } from './types';
6
+ interface Migration {
7
+ version: number;
8
+ name: string;
9
+ sql: string;
10
+ }
11
+ export declare const MIGRATIONS: Migration[];
6
12
  export interface SQLiteJsonlImportResult {
7
13
  importedMemories: number;
8
14
  importedProposals: number;
@@ -14,6 +20,7 @@ export declare class SQLiteMemoryProvider implements MemoryProvider, MemoryPropo
14
20
  private readonly rootDirectory;
15
21
  private readonly config;
16
22
  private initialized;
23
+ private initPromise;
17
24
  private db;
18
25
  private ftsAvailable;
19
26
  private memories;
@@ -22,6 +29,7 @@ export declare class SQLiteMemoryProvider implements MemoryProvider, MemoryPropo
22
29
  constructor(rootDirectory: string, config?: Partial<MemoryConfig>);
23
30
  private databasePath;
24
31
  initialize(): Promise<void>;
32
+ private doInitialize;
25
33
  upsert(record: MemoryRecord): Promise<MemoryRecord>;
26
34
  get(id: string): Promise<MemoryRecord | null>;
27
35
  delete(id: string, reason?: string): Promise<void>;
@@ -75,9 +83,11 @@ export declare class SQLiteMemoryProvider implements MemoryProvider, MemoryPropo
75
83
  private insertEvent;
76
84
  private requireDb;
77
85
  }
86
+ declare function splitSql(sql: string): string[];
78
87
  declare function buildFtsQuery(request: RecallRequest): string | null;
79
88
  declare function extractFtsTerms(text: string): Set<string>;
80
89
  export declare const _test_exports: {
90
+ splitSql: typeof splitSql;
81
91
  buildFtsQuery: typeof buildFtsQuery;
82
92
  extractFtsTerms: typeof extractFtsTerms;
83
93
  FTS_SCHEMA_MIGRATION_NAME: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.87.0",
3
+ "version": "7.87.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",