opencode-swarm 6.22.16 → 6.22.18

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
@@ -14200,6 +14200,15 @@ var init_logger = __esm(() => {
14200
14200
  DEBUG = process.env.OPENCODE_SWARM_DEBUG === "1";
14201
14201
  });
14202
14202
 
14203
+ // src/utils/regex.ts
14204
+ function escapeRegex2(s) {
14205
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
14206
+ }
14207
+ function simpleGlobToRegex(pattern, flags = "i") {
14208
+ const escaped = pattern.split("*").map((starSegment) => starSegment.split("?").map(escapeRegex2).join(".")).join(".*");
14209
+ return new RegExp(`^${escaped}$`, flags);
14210
+ }
14211
+
14203
14212
  // src/utils/index.ts
14204
14213
  var init_utils = __esm(() => {
14205
14214
  init_errors3();
@@ -18522,7 +18531,7 @@ __export(exports_util2, {
18522
18531
  floatSafeRemainder: () => floatSafeRemainder2,
18523
18532
  finalizeIssue: () => finalizeIssue2,
18524
18533
  extend: () => extend2,
18525
- escapeRegex: () => escapeRegex2,
18534
+ escapeRegex: () => escapeRegex3,
18526
18535
  esc: () => esc2,
18527
18536
  defineLazy: () => defineLazy2,
18528
18537
  createTransparentProxy: () => createTransparentProxy2,
@@ -18769,7 +18778,7 @@ var getParsedType2 = (data) => {
18769
18778
  };
18770
18779
  var propertyKeyTypes2 = new Set(["string", "number", "symbol"]);
18771
18780
  var primitiveTypes2 = new Set(["string", "number", "bigint", "boolean", "symbol", "undefined"]);
18772
- function escapeRegex2(str) {
18781
+ function escapeRegex3(str) {
18773
18782
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
18774
18783
  }
18775
18784
  function clone2(inst, def, params) {
@@ -19922,7 +19931,7 @@ var $ZodCheckUpperCase2 = /* @__PURE__ */ $constructor2("$ZodCheckUpperCase", (i
19922
19931
  });
19923
19932
  var $ZodCheckIncludes2 = /* @__PURE__ */ $constructor2("$ZodCheckIncludes", (inst, def) => {
19924
19933
  $ZodCheck2.init(inst, def);
19925
- const escapedRegex = escapeRegex2(def.includes);
19934
+ const escapedRegex = escapeRegex3(def.includes);
19926
19935
  const pattern = new RegExp(typeof def.position === "number" ? `^.{${def.position}}${escapedRegex}` : escapedRegex);
19927
19936
  def.pattern = pattern;
19928
19937
  inst._zod.onattach.push((inst2) => {
@@ -19946,7 +19955,7 @@ var $ZodCheckIncludes2 = /* @__PURE__ */ $constructor2("$ZodCheckIncludes", (ins
19946
19955
  });
19947
19956
  var $ZodCheckStartsWith2 = /* @__PURE__ */ $constructor2("$ZodCheckStartsWith", (inst, def) => {
19948
19957
  $ZodCheck2.init(inst, def);
19949
- const pattern = new RegExp(`^${escapeRegex2(def.prefix)}.*`);
19958
+ const pattern = new RegExp(`^${escapeRegex3(def.prefix)}.*`);
19950
19959
  def.pattern ?? (def.pattern = pattern);
19951
19960
  inst._zod.onattach.push((inst2) => {
19952
19961
  const bag = inst2._zod.bag;
@@ -19969,7 +19978,7 @@ var $ZodCheckStartsWith2 = /* @__PURE__ */ $constructor2("$ZodCheckStartsWith",
19969
19978
  });
19970
19979
  var $ZodCheckEndsWith2 = /* @__PURE__ */ $constructor2("$ZodCheckEndsWith", (inst, def) => {
19971
19980
  $ZodCheck2.init(inst, def);
19972
- const pattern = new RegExp(`.*${escapeRegex2(def.suffix)}$`);
19981
+ const pattern = new RegExp(`.*${escapeRegex3(def.suffix)}$`);
19973
19982
  def.pattern ?? (def.pattern = pattern);
19974
19983
  inst._zod.onattach.push((inst2) => {
19975
19984
  const bag = inst2._zod.bag;
@@ -21378,7 +21387,7 @@ var $ZodEnum2 = /* @__PURE__ */ $constructor2("$ZodEnum", (inst, def) => {
21378
21387
  const values = getEnumValues2(def.entries);
21379
21388
  const valuesSet = new Set(values);
21380
21389
  inst._zod.values = valuesSet;
21381
- inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes2.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex2(o) : o.toString()).join("|")})$`);
21390
+ inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes2.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex3(o) : o.toString()).join("|")})$`);
21382
21391
  inst._zod.parse = (payload, _ctx) => {
21383
21392
  const input = payload.value;
21384
21393
  if (valuesSet.has(input)) {
@@ -21399,7 +21408,7 @@ var $ZodLiteral2 = /* @__PURE__ */ $constructor2("$ZodLiteral", (inst, def) => {
21399
21408
  throw new Error("Cannot create literal schema with no valid values");
21400
21409
  }
21401
21410
  inst._zod.values = new Set(def.values);
21402
- inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex2(o) : o ? escapeRegex2(o.toString()) : String(o)).join("|")})$`);
21411
+ inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex3(o) : o ? escapeRegex3(o.toString()) : String(o)).join("|")})$`);
21403
21412
  inst._zod.parse = (payload, _ctx) => {
21404
21413
  const input = payload.value;
21405
21414
  if (inst._zod.values.has(input)) {
@@ -21747,7 +21756,7 @@ var $ZodTemplateLiteral2 = /* @__PURE__ */ $constructor2("$ZodTemplateLiteral",
21747
21756
  const end = source.endsWith("$") ? source.length - 1 : source.length;
21748
21757
  regexParts.push(source.slice(start, end));
21749
21758
  } else if (part === null || primitiveTypes2.has(typeof part)) {
21750
- regexParts.push(escapeRegex2(`${part}`));
21759
+ regexParts.push(escapeRegex3(`${part}`));
21751
21760
  } else {
21752
21761
  throw new Error(`Invalid template literal part: ${part}`);
21753
21762
  }
@@ -32567,10 +32576,8 @@ function findBuildFiles(workingDir, patterns) {
32567
32576
  const dir = workingDir;
32568
32577
  try {
32569
32578
  const files = fs2.readdirSync(dir);
32570
- const matches = files.filter((f) => {
32571
- const regex = new RegExp(`^${pattern.replace(/\*/g, ".*")}$`);
32572
- return regex.test(f);
32573
- });
32579
+ const regex = simpleGlobToRegex(pattern);
32580
+ const matches = files.filter((f) => regex.test(f));
32574
32581
  if (matches.length > 0) {
32575
32582
  return path10.join(dir, matches[0]);
32576
32583
  }
@@ -32623,7 +32630,7 @@ function findAllBuildFiles(workingDir) {
32623
32630
  for (const ecosystem of ECOSYSTEMS) {
32624
32631
  for (const pattern of ecosystem.buildFiles) {
32625
32632
  if (pattern.includes("*")) {
32626
- const regex = new RegExp(`^${pattern.replace(/\*/g, ".*")}$`);
32633
+ const regex = simpleGlobToRegex(pattern);
32627
32634
  findFilesRecursive(workingDir, regex, allBuildFiles);
32628
32635
  } else {
32629
32636
  const filePath = path10.join(workingDir, pattern);
@@ -31,7 +31,7 @@ interface MessageWithParts {
31
31
  * Creates the experimental.chat.messages.transform hook for pipeline tracking.
32
32
  * Only injects for the architect agent.
33
33
  */
34
- export declare function createPipelineTrackerHook(config: PluginConfig): {
34
+ export declare function createPipelineTrackerHook(config: PluginConfig, directory?: string): {
35
35
  'experimental.chat.messages.transform'?: undefined;
36
36
  } | {
37
37
  'experimental.chat.messages.transform': (input: Record<string, never>, output: {
package/dist/index.js CHANGED
@@ -15186,6 +15186,15 @@ var init_logger = __esm(() => {
15186
15186
  DEBUG = process.env.OPENCODE_SWARM_DEBUG === "1";
15187
15187
  });
15188
15188
 
15189
+ // src/utils/regex.ts
15190
+ function escapeRegex2(s) {
15191
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
15192
+ }
15193
+ function simpleGlobToRegex(pattern, flags2 = "i") {
15194
+ const escaped = pattern.split("*").map((starSegment) => starSegment.split("?").map(escapeRegex2).join(".")).join(".*");
15195
+ return new RegExp(`^${escaped}$`, flags2);
15196
+ }
15197
+
15189
15198
  // src/utils/index.ts
15190
15199
  var init_utils = __esm(() => {
15191
15200
  init_errors3();
@@ -18711,7 +18720,7 @@ __export(exports_util2, {
18711
18720
  floatSafeRemainder: () => floatSafeRemainder2,
18712
18721
  finalizeIssue: () => finalizeIssue2,
18713
18722
  extend: () => extend2,
18714
- escapeRegex: () => escapeRegex2,
18723
+ escapeRegex: () => escapeRegex3,
18715
18724
  esc: () => esc2,
18716
18725
  defineLazy: () => defineLazy2,
18717
18726
  createTransparentProxy: () => createTransparentProxy2,
@@ -18898,7 +18907,7 @@ function numKeys2(data) {
18898
18907
  }
18899
18908
  return keyCount;
18900
18909
  }
18901
- function escapeRegex2(str) {
18910
+ function escapeRegex3(str) {
18902
18911
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
18903
18912
  }
18904
18913
  function clone2(inst, def, params) {
@@ -20121,7 +20130,7 @@ var init_checks3 = __esm(() => {
20121
20130
  });
20122
20131
  $ZodCheckIncludes2 = /* @__PURE__ */ $constructor2("$ZodCheckIncludes", (inst, def) => {
20123
20132
  $ZodCheck2.init(inst, def);
20124
- const escapedRegex = escapeRegex2(def.includes);
20133
+ const escapedRegex = escapeRegex3(def.includes);
20125
20134
  const pattern = new RegExp(typeof def.position === "number" ? `^.{${def.position}}${escapedRegex}` : escapedRegex);
20126
20135
  def.pattern = pattern;
20127
20136
  inst._zod.onattach.push((inst2) => {
@@ -20145,7 +20154,7 @@ var init_checks3 = __esm(() => {
20145
20154
  });
20146
20155
  $ZodCheckStartsWith2 = /* @__PURE__ */ $constructor2("$ZodCheckStartsWith", (inst, def) => {
20147
20156
  $ZodCheck2.init(inst, def);
20148
- const pattern = new RegExp(`^${escapeRegex2(def.prefix)}.*`);
20157
+ const pattern = new RegExp(`^${escapeRegex3(def.prefix)}.*`);
20149
20158
  def.pattern ?? (def.pattern = pattern);
20150
20159
  inst._zod.onattach.push((inst2) => {
20151
20160
  const bag = inst2._zod.bag;
@@ -20168,7 +20177,7 @@ var init_checks3 = __esm(() => {
20168
20177
  });
20169
20178
  $ZodCheckEndsWith2 = /* @__PURE__ */ $constructor2("$ZodCheckEndsWith", (inst, def) => {
20170
20179
  $ZodCheck2.init(inst, def);
20171
- const pattern = new RegExp(`.*${escapeRegex2(def.suffix)}$`);
20180
+ const pattern = new RegExp(`.*${escapeRegex3(def.suffix)}$`);
20172
20181
  def.pattern ?? (def.pattern = pattern);
20173
20182
  inst._zod.onattach.push((inst2) => {
20174
20183
  const bag = inst2._zod.bag;
@@ -21660,7 +21669,7 @@ var init_schemas3 = __esm(() => {
21660
21669
  const values = getEnumValues2(def.entries);
21661
21670
  const valuesSet = new Set(values);
21662
21671
  inst._zod.values = valuesSet;
21663
- inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes2.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex2(o) : o.toString()).join("|")})$`);
21672
+ inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes2.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex3(o) : o.toString()).join("|")})$`);
21664
21673
  inst._zod.parse = (payload, _ctx) => {
21665
21674
  const input = payload.value;
21666
21675
  if (valuesSet.has(input)) {
@@ -21681,7 +21690,7 @@ var init_schemas3 = __esm(() => {
21681
21690
  throw new Error("Cannot create literal schema with no valid values");
21682
21691
  }
21683
21692
  inst._zod.values = new Set(def.values);
21684
- inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex2(o) : o ? escapeRegex2(o.toString()) : String(o)).join("|")})$`);
21693
+ inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex3(o) : o ? escapeRegex3(o.toString()) : String(o)).join("|")})$`);
21685
21694
  inst._zod.parse = (payload, _ctx) => {
21686
21695
  const input = payload.value;
21687
21696
  if (inst._zod.values.has(input)) {
@@ -21968,7 +21977,7 @@ var init_schemas3 = __esm(() => {
21968
21977
  const end = source.endsWith("$") ? source.length - 1 : source.length;
21969
21978
  regexParts.push(source.slice(start2, end));
21970
21979
  } else if (part === null || primitiveTypes2.has(typeof part)) {
21971
- regexParts.push(escapeRegex2(`${part}`));
21980
+ regexParts.push(escapeRegex3(`${part}`));
21972
21981
  } else {
21973
21982
  throw new Error(`Invalid template literal part: ${part}`);
21974
21983
  }
@@ -32859,10 +32868,8 @@ function findBuildFiles(workingDir, patterns) {
32859
32868
  const dir = workingDir;
32860
32869
  try {
32861
32870
  const files = fs7.readdirSync(dir);
32862
- const matches = files.filter((f) => {
32863
- const regex = new RegExp(`^${pattern.replace(/\*/g, ".*")}$`);
32864
- return regex.test(f);
32865
- });
32871
+ const regex = simpleGlobToRegex(pattern);
32872
+ const matches = files.filter((f) => regex.test(f));
32866
32873
  if (matches.length > 0) {
32867
32874
  return path19.join(dir, matches[0]);
32868
32875
  }
@@ -32915,7 +32922,7 @@ function findAllBuildFiles(workingDir) {
32915
32922
  for (const ecosystem of ECOSYSTEMS) {
32916
32923
  for (const pattern of ecosystem.buildFiles) {
32917
32924
  if (pattern.includes("*")) {
32918
- const regex = new RegExp(`^${pattern.replace(/\*/g, ".*")}$`);
32925
+ const regex = simpleGlobToRegex(pattern);
32919
32926
  findFilesRecursive(workingDir, regex, allBuildFiles);
32920
32927
  } else {
32921
32928
  const filePath = path19.join(workingDir, pattern);
@@ -46323,7 +46330,12 @@ async function handleRollbackCommand(directory, args2) {
46323
46330
  if (!fs13.existsSync(manifestPath2)) {
46324
46331
  return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
46325
46332
  }
46326
- const manifest2 = JSON.parse(fs13.readFileSync(manifestPath2, "utf-8"));
46333
+ let manifest2;
46334
+ try {
46335
+ manifest2 = JSON.parse(fs13.readFileSync(manifestPath2, "utf-8"));
46336
+ } catch {
46337
+ return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
46338
+ }
46327
46339
  const checkpoints = manifest2.checkpoints || [];
46328
46340
  if (checkpoints.length === 0) {
46329
46341
  return "No checkpoints found in manifest.";
@@ -46345,7 +46357,12 @@ async function handleRollbackCommand(directory, args2) {
46345
46357
  if (!fs13.existsSync(manifestPath)) {
46346
46358
  return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
46347
46359
  }
46348
- const manifest = JSON.parse(fs13.readFileSync(manifestPath, "utf-8"));
46360
+ let manifest;
46361
+ try {
46362
+ manifest = JSON.parse(fs13.readFileSync(manifestPath, "utf-8"));
46363
+ } catch {
46364
+ return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
46365
+ }
46349
46366
  const checkpoint = manifest.checkpoints?.find((c) => c.phase === targetPhase);
46350
46367
  if (!checkpoint) {
46351
46368
  const available = manifest.checkpoints?.map((c) => c.phase).join(", ") || "none";
@@ -49247,7 +49264,7 @@ ${phaseNumber !== null && phaseNumber >= 4 ? `
49247
49264
  \u26A0\uFE0F You are in Phase ${phaseNumber}. Compliance degrades with time. Do not skip reviewer or test_engineer.` : ""}
49248
49265
  </swarm_reminder>`;
49249
49266
  }
49250
- function createPipelineTrackerHook(config3) {
49267
+ function createPipelineTrackerHook(config3, directory) {
49251
49268
  const enabled = config3.inject_phase_reminders !== false;
49252
49269
  if (!enabled) {
49253
49270
  return {};
@@ -49277,7 +49294,7 @@ function createPipelineTrackerHook(config3) {
49277
49294
  return;
49278
49295
  let phaseNumber = null;
49279
49296
  try {
49280
- const plan = await loadPlan(process.cwd());
49297
+ const plan = await loadPlan(directory ?? process.cwd());
49281
49298
  if (plan) {
49282
49299
  const phaseString = extractCurrentPhaseFromPlan2(plan);
49283
49300
  phaseNumber = parsePhaseNumber(phaseString);
@@ -53873,7 +53890,12 @@ async function fetchGitingest(args2) {
53873
53890
  if (Buffer.byteLength(text) > GITINGEST_MAX_RESPONSE_BYTES) {
53874
53891
  throw new Error("gitingest response too large");
53875
53892
  }
53876
- const data = JSON.parse(text);
53893
+ let data;
53894
+ try {
53895
+ data = JSON.parse(text);
53896
+ } catch {
53897
+ throw new Error(`gitingest API returned non-JSON response (${text.length} chars, starts: ${text.slice(0, 80)})`);
53898
+ }
53877
53899
  return `${data.summary}
53878
53900
 
53879
53901
  ${data.tree}
@@ -54820,7 +54842,7 @@ async function executePhaseComplete(args2, workingDirectory) {
54820
54842
  const phaseObj = plan.phases.find((p) => p.id === phase);
54821
54843
  if (phaseObj) {
54822
54844
  phaseObj.status = "completed";
54823
- fs25.writeFileSync(planPath, JSON.stringify(plan, null, 2) + `
54845
+ fs25.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
54824
54846
  `, "utf-8");
54825
54847
  }
54826
54848
  } catch (error93) {
@@ -55951,6 +55973,7 @@ function getLanguageForExtension(extension) {
55951
55973
  }
55952
55974
 
55953
55975
  // src/tools/placeholder-scan.ts
55976
+ init_utils();
55954
55977
  var MAX_FILE_SIZE = 1024 * 1024;
55955
55978
  var SUPPORTED_PARSER_EXTENSIONS = new Set([
55956
55979
  ".js",
@@ -56509,7 +56532,7 @@ function matchesGlobSegment(path40, glob) {
56509
56532
  }
56510
56533
  return matchGlobSegment(globSegments, pathSegments);
56511
56534
  }
56512
- function simpleGlobToRegex(glob) {
56535
+ function simpleGlobToRegex2(glob) {
56513
56536
  if (!glob) {
56514
56537
  return /.*/;
56515
56538
  }
@@ -56537,7 +56560,7 @@ function globMatches(path40, glob) {
56537
56560
  if (hasGlobstar(normalizedGlob)) {
56538
56561
  return matchesGlobSegment(normalizedPath, normalizedGlob);
56539
56562
  }
56540
- const regex = simpleGlobToRegex(normalizedGlob);
56563
+ const regex = simpleGlobToRegex2(normalizedGlob);
56541
56564
  return regex.test(normalizedPath);
56542
56565
  }
56543
56566
  function shouldExcludeFile(filePath, excludeGlobs) {
@@ -58847,6 +58870,9 @@ init_manager();
58847
58870
  import * as fs31 from "fs";
58848
58871
  import * as path43 from "path";
58849
58872
 
58873
+ // src/sbom/detectors/index.ts
58874
+ init_utils();
58875
+
58850
58876
  // src/sbom/detectors/dart.ts
58851
58877
  function parsePubspecLock(content) {
58852
58878
  const components = [];
@@ -59613,10 +59639,7 @@ var allDetectors = [
59613
59639
  ];
59614
59640
  function findDetectorsForFile(filePath) {
59615
59641
  const fileName = filePath.split(/[/\\]/).pop() || "";
59616
- return allDetectors.filter((detector) => detector.patterns.some((pattern) => {
59617
- const regex = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
59618
- return new RegExp(regex, "i").test(fileName);
59619
- }));
59642
+ return allDetectors.filter((detector) => detector.patterns.some((pattern) => simpleGlobToRegex(pattern).test(fileName)));
59620
59643
  }
59621
59644
  function detectComponents(filePath, content) {
59622
59645
  const detectors = findDetectorsForFile(filePath);
@@ -59683,6 +59706,7 @@ function serializeCycloneDX(bom) {
59683
59706
  }
59684
59707
 
59685
59708
  // src/tools/sbom-generate.ts
59709
+ init_utils();
59686
59710
  init_create_tool();
59687
59711
  var DEFAULT_OUTPUT_DIR = ".swarm/evidence/sbom";
59688
59712
  function findManifestFiles(rootDir) {
@@ -59700,8 +59724,7 @@ function findManifestFiles(rootDir) {
59700
59724
  searchDir(fullPath);
59701
59725
  } else if (entry.isFile()) {
59702
59726
  for (const pattern of patterns) {
59703
- const regex = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
59704
- if (new RegExp(regex, "i").test(entry.name)) {
59727
+ if (simpleGlobToRegex(pattern).test(entry.name)) {
59705
59728
  manifestFiles.push(path43.relative(rootDir, fullPath));
59706
59729
  break;
59707
59730
  }
@@ -59723,8 +59746,7 @@ function findManifestFilesInDirs(directories, workingDir) {
59723
59746
  const fullPath = path43.join(dir, entry.name);
59724
59747
  if (entry.isFile()) {
59725
59748
  for (const pattern of patterns) {
59726
- const regex = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
59727
- if (new RegExp(regex, "i").test(entry.name)) {
59749
+ if (simpleGlobToRegex(pattern).test(entry.name)) {
59728
59750
  found.push(path43.relative(workingDir, fullPath));
59729
59751
  break;
59730
59752
  }
@@ -59980,7 +60002,12 @@ function parseSpec(specFile) {
59980
60002
  return parseYamlSpec(content);
59981
60003
  }
59982
60004
  function parseJsonSpec(content) {
59983
- const spec = JSON.parse(content);
60005
+ let spec;
60006
+ try {
60007
+ spec = JSON.parse(content);
60008
+ } catch {
60009
+ return [];
60010
+ }
59984
60011
  const paths = [];
59985
60012
  if (!spec.paths) {
59986
60013
  return paths;
@@ -60573,6 +60600,7 @@ init_test_runner();
60573
60600
 
60574
60601
  // src/tools/todo-extract.ts
60575
60602
  init_dist();
60603
+ init_utils();
60576
60604
  init_create_tool();
60577
60605
  import * as fs34 from "fs";
60578
60606
  import * as path46 from "path";
@@ -60700,7 +60728,7 @@ function parseTodoComments(content, filePath, tagsSet) {
60700
60728
  const entries = [];
60701
60729
  const lines = content.split(`
60702
60730
  `);
60703
- const tagPattern = Array.from(tagsSet).join("|");
60731
+ const tagPattern = Array.from(tagsSet).map(escapeRegex2).join("|");
60704
60732
  const regex = new RegExp(`\\b(${tagPattern})\\b[:\\s]?`, "i");
60705
60733
  for (let i2 = 0;i2 < lines.length; i2++) {
60706
60734
  const line = lines[i2];
@@ -61062,7 +61090,7 @@ var OpenCodeSwarm = async (ctx) => {
61062
61090
  await loadSnapshot(ctx.directory);
61063
61091
  const agents = getAgentConfigs(config3);
61064
61092
  const agentDefinitions = createAgents(config3);
61065
- const pipelineHook = createPipelineTrackerHook(config3);
61093
+ const pipelineHook = createPipelineTrackerHook(config3, ctx.directory);
61066
61094
  const systemEnhancerHook = createSystemEnhancerHook(config3, ctx.directory);
61067
61095
  const compactionHook = createCompactionCustomizerHook(config3, ctx.directory);
61068
61096
  const contextBudgetHandler = createContextBudgetHandler(config3);
package/dist/state.d.ts CHANGED
@@ -177,6 +177,9 @@ export declare function resetSwarmState(): void;
177
177
  export declare function startAgentSession(sessionId: string, agentName: string, staleDurationMs?: number): void;
178
178
  /**
179
179
  * End an agent session by removing it from the state.
180
+ * NOTE: Currently unused in production — no session lifecycle teardown is wired up.
181
+ * Sessions accumulate for the process lifetime. Callers should integrate this into
182
+ * a session TTL or idle-timeout mechanism to prevent unbounded Map growth.
180
183
  * @param sessionId - The session identifier to remove
181
184
  */
182
185
  export declare function endAgentSession(sessionId: string): void;
@@ -1,3 +1,4 @@
1
1
  export { CLIError, ConfigError, HookError, SwarmError, ToolError, } from './errors';
2
2
  export { error, log, warn } from './logger';
3
3
  export { deepMerge, MAX_MERGE_DEPTH } from './merge';
4
+ export { escapeRegex, simpleGlobToRegex } from './regex';
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Centralized regex safety utilities.
3
+ *
4
+ * Every call-site that builds a RegExp from runtime strings
5
+ * (user config, glob patterns, tool input) MUST go through one of
6
+ * these helpers to prevent ReDoS and broken matching.
7
+ */
8
+ /**
9
+ * Escape all regex metacharacters in a string so it can be
10
+ * safely interpolated into a `new RegExp(...)` call.
11
+ *
12
+ * Covers the full set: . * + ? ^ $ { } ( ) | [ ] \
13
+ */
14
+ export declare function escapeRegex(s: string): string;
15
+ /**
16
+ * Convert a simple glob pattern (supports `*` and `?` wildcards)
17
+ * into an anchored, case-insensitive RegExp.
18
+ *
19
+ * All other regex metacharacters in the pattern are escaped first,
20
+ * so filenames containing `.`, `(`, `[`, etc. match literally.
21
+ *
22
+ * Semantics:
23
+ * `*` → `.*` (zero or more of any character)
24
+ * `?` → `.` (exactly one character)
25
+ *
26
+ * This is intentionally simple — it does NOT handle `**` / globstar.
27
+ * For globstar support see `quality/metrics.ts` which has its own
28
+ * path-aware implementation.
29
+ */
30
+ export declare function simpleGlobToRegex(pattern: string, flags?: string): RegExp;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "6.22.16",
3
+ "version": "6.22.18",
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",