opencode-swarm 7.36.0 → 7.38.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
@@ -34,7 +34,7 @@ var package_default;
34
34
  var init_package = __esm(() => {
35
35
  package_default = {
36
36
  name: "opencode-swarm",
37
- version: "7.36.0",
37
+ version: "7.38.0",
38
38
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
39
39
  main: "dist/index.js",
40
40
  types: "dist/index.d.ts",
@@ -67,6 +67,7 @@ var init_package = __esm(() => {
67
67
  files: [
68
68
  "dist",
69
69
  "dist/lang/grammars",
70
+ "tests/fixtures/memory-recall",
70
71
  "README.md",
71
72
  "LICENSE"
72
73
  ],
@@ -45714,6 +45715,102 @@ var init_curator_decision_helpers = __esm(() => {
45714
45715
  init_schema2();
45715
45716
  });
45716
45717
 
45718
+ // src/memory/role-profiles.ts
45719
+ function resolveMemoryRecallProfile(agentRole) {
45720
+ const role = normalizeMemoryAgentRole(agentRole);
45721
+ return MEMORY_RECALL_PROFILES[role] ?? MEMORY_RECALL_PROFILES.coder;
45722
+ }
45723
+ function normalizeMemoryAgentRole(agentRole) {
45724
+ const base = stripKnownSwarmPrefix(agentRole ?? "architect");
45725
+ if (base === "reviewer" || base === "test_engineer")
45726
+ return "qa";
45727
+ if (base === "critic" || base === "critic_sounding_board" || base === "critic_drift_verifier" || base === "critic_hallucination_verifier") {
45728
+ return "security";
45729
+ }
45730
+ if (base === "curator_init" || base === "curator_phase")
45731
+ return "curator";
45732
+ if (base === "docs")
45733
+ return "sme";
45734
+ if (base === "architect" || base === "sme" || base === "coder" || base === "security" || base === "curator") {
45735
+ return base;
45736
+ }
45737
+ return "coder";
45738
+ }
45739
+ var MEMORY_RECALL_PROFILES;
45740
+ var init_role_profiles = __esm(() => {
45741
+ init_schema();
45742
+ MEMORY_RECALL_PROFILES = {
45743
+ architect: {
45744
+ kinds: [
45745
+ "project_fact",
45746
+ "architecture_decision",
45747
+ "repo_convention",
45748
+ "failure_pattern",
45749
+ "security_note"
45750
+ ],
45751
+ maxItems: 10,
45752
+ tokenBudget: 1600
45753
+ },
45754
+ sme: {
45755
+ kinds: [
45756
+ "api_finding",
45757
+ "code_pattern",
45758
+ "repo_convention",
45759
+ "failure_pattern",
45760
+ "evidence"
45761
+ ],
45762
+ maxItems: 8,
45763
+ tokenBudget: 1200
45764
+ },
45765
+ coder: {
45766
+ kinds: [
45767
+ "architecture_decision",
45768
+ "repo_convention",
45769
+ "code_pattern",
45770
+ "test_pattern",
45771
+ "failure_pattern"
45772
+ ],
45773
+ maxItems: 8,
45774
+ tokenBudget: 1200
45775
+ },
45776
+ qa: {
45777
+ kinds: [
45778
+ "test_pattern",
45779
+ "failure_pattern",
45780
+ "repo_convention",
45781
+ "security_note"
45782
+ ],
45783
+ maxItems: 8,
45784
+ tokenBudget: 1200
45785
+ },
45786
+ security: {
45787
+ kinds: [
45788
+ "security_note",
45789
+ "architecture_decision",
45790
+ "repo_convention",
45791
+ "evidence"
45792
+ ],
45793
+ maxItems: 8,
45794
+ tokenBudget: 1200
45795
+ },
45796
+ curator: {
45797
+ kinds: [
45798
+ "project_fact",
45799
+ "architecture_decision",
45800
+ "repo_convention",
45801
+ "api_finding",
45802
+ "code_pattern",
45803
+ "test_pattern",
45804
+ "failure_pattern",
45805
+ "security_note",
45806
+ "evidence"
45807
+ ],
45808
+ maxItems: 20,
45809
+ tokenBudget: 3000
45810
+ }
45811
+ };
45812
+ });
45813
+
45717
45814
  // src/memory/scoring.ts
45718
45815
  function tokenize(text) {
45719
45816
  return new Set(text.toLowerCase().replace(/[^\w\s-]/g, " ").split(/\s+/).map((token) => token.trim()).filter(Boolean));
@@ -45767,13 +45864,16 @@ function kindProfileBoost(kind, request) {
45767
45864
  return 0.5;
45768
45865
  return request.kinds.includes(kind) ? 1 : 0;
45769
45866
  }
45867
+ function roleProfileBoost(kind, context) {
45868
+ return context.roleProfileKinds?.has(kind) ? 1 : 0;
45869
+ }
45770
45870
  function sameScope(a, b) {
45771
45871
  return stableScopeKey(a) === stableScopeKey(b);
45772
45872
  }
45773
45873
  function scopeAllowed(recordScope, allowedScopes) {
45774
45874
  return allowedScopes.some((scope) => sameScope(recordScope, scope));
45775
45875
  }
45776
- function scoreMemoryRecordDetailed(record3, request) {
45876
+ function scoreMemoryRecordDetailed(record3, request, context) {
45777
45877
  if (!request.includeExpired && isExpired(record3)) {
45778
45878
  return { item: null, skipReason: "filtered" };
45779
45879
  }
@@ -45788,7 +45888,7 @@ function scoreMemoryRecordDetailed(record3, request) {
45788
45888
  if (request.kinds && !request.kinds.includes(record3.kind)) {
45789
45889
  return { item: null, skipReason: "filtered" };
45790
45890
  }
45791
- const queryTokens = request.mode === "injection" && request.task ? tokenize(request.task) : tokenize(request.query);
45891
+ const queryTokens = request.mode === "injection" && context.taskTokens ? context.taskTokens : context.queryTokens;
45792
45892
  const textTokens = tokenize(record3.text);
45793
45893
  const tagTokens = tokenize(record3.tags.join(" "));
45794
45894
  const fileTokens = tokenize([
@@ -45801,24 +45901,31 @@ function scoreMemoryRecordDetailed(record3, request) {
45801
45901
  ])
45802
45902
  ].filter((value) => typeof value === "string").join(" "));
45803
45903
  const symbolTokens = tokenize(collectMetadataStrings(record3.metadata, ["symbol", "symbols"]).join(" "));
45804
- const kindQueryOverlap = overlap(queryTokens, tokenize(normalizeKindText(record3.kind)));
45904
+ const kindTokens = tokenize(normalizeKindText(record3.kind));
45905
+ const sourceRefTokens = tokenize(record3.source.ref ?? "");
45906
+ const taskSearchTokens = unionTokens(textTokens, tagTokens, fileTokens, symbolTokens, kindTokens, sourceRefTokens);
45907
+ const taskTermOverlap = context.taskTokens ? overlap(context.taskTokens, taskSearchTokens) : 0;
45908
+ const kindQueryOverlap = overlap(queryTokens, kindTokens);
45805
45909
  const textOverlap = overlap(queryTokens, textTokens);
45806
45910
  const tagOverlap = overlap(queryTokens, tagTokens);
45807
45911
  const fileOverlap = overlap(queryTokens, fileTokens);
45808
45912
  const symbolOverlap = overlap(queryTokens, symbolTokens);
45809
45913
  const kindMatch = request.kinds?.includes(record3.kind) ?? false;
45810
45914
  const scopeMatch = scopeAllowed(record3.scope, request.scopes);
45915
+ const roleBoost = roleProfileBoost(record3.kind, context);
45811
45916
  const hasQuerySignal = textOverlap > 0 || tagOverlap > 0 || fileOverlap > 0 || symbolOverlap > 0 || kindQueryOverlap > 0;
45812
45917
  if (request.mode === "injection" && request.requireQuerySignal !== false && !hasQuerySignal) {
45813
45918
  return { item: null, skipReason: "no_signal" };
45814
45919
  }
45815
- const score = textOverlap * 0.45 + tagOverlap * 0.2 + fileOverlap * 0.05 + symbolOverlap * 0.05 + scopeSpecificityBoost(record3.scope) * 0.15 + kindProfileBoost(record3.kind, request) * 0.1 + record3.confidence * 0.1;
45920
+ 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;
45816
45921
  const reasonParts = [
45817
45922
  textOverlap > 0 ? `text_overlap=${textOverlap.toFixed(2)}` : null,
45818
45923
  tagOverlap > 0 ? `tag_overlap=${tagOverlap.toFixed(2)}` : null,
45819
45924
  fileOverlap > 0 ? `file_overlap=${fileOverlap.toFixed(2)}` : null,
45820
45925
  symbolOverlap > 0 ? `symbol_overlap=${symbolOverlap.toFixed(2)}` : null,
45926
+ taskTermOverlap > 0 ? `task_terms=${taskTermOverlap.toFixed(2)}` : null,
45821
45927
  kindQueryOverlap > 0 ? `kind_query=${kindQueryOverlap.toFixed(2)}` : null,
45928
+ roleBoost > 0 ? "role_profile" : null,
45822
45929
  `scope=${record3.scope.type}`,
45823
45930
  `confidence=${record3.confidence.toFixed(2)}`
45824
45931
  ].filter(Boolean);
@@ -45840,6 +45947,7 @@ function scoreMemoryRecordDetailed(record3, request) {
45840
45947
  }
45841
45948
  function scoreMemoryRecordsWithDiagnostics(records, request) {
45842
45949
  const minScore = request.minScore ?? 0;
45950
+ const context = createScoringContext(request);
45843
45951
  const diagnostics = {
45844
45952
  candidateCount: records.length,
45845
45953
  preScoredFilteredCount: 0,
@@ -45850,7 +45958,7 @@ function scoreMemoryRecordsWithDiagnostics(records, request) {
45850
45958
  };
45851
45959
  const items = [];
45852
45960
  for (const record3 of records) {
45853
- const result = scoreMemoryRecordDetailed(record3, request);
45961
+ const result = scoreMemoryRecordDetailed(record3, request, context);
45854
45962
  if (!result.item) {
45855
45963
  if (result.skipReason === "filtered")
45856
45964
  diagnostics.preScoredFilteredCount++;
@@ -45869,7 +45977,24 @@ function scoreMemoryRecordsWithDiagnostics(records, request) {
45869
45977
  diagnostics.returnedCount = items.length;
45870
45978
  return { items, diagnostics };
45871
45979
  }
45980
+ function createScoringContext(request) {
45981
+ const taskTokens = request.task ? tokenize(request.task) : undefined;
45982
+ return {
45983
+ taskTokens,
45984
+ queryTokens: tokenize(request.query),
45985
+ roleProfileKinds: request.agentRole ? new Set(resolveMemoryRecallProfile(request.agentRole).kinds) : undefined
45986
+ };
45987
+ }
45988
+ function unionTokens(...sets) {
45989
+ const union3 = new Set;
45990
+ for (const set3 of sets) {
45991
+ for (const token of set3)
45992
+ union3.add(token);
45993
+ }
45994
+ return union3;
45995
+ }
45872
45996
  var init_scoring = __esm(() => {
45997
+ init_role_profiles();
45873
45998
  init_schema2();
45874
45999
  });
45875
46000
 
@@ -46444,6 +46569,7 @@ class SQLiteMemoryProvider {
46444
46569
  config;
46445
46570
  initialized = false;
46446
46571
  db = null;
46572
+ ftsAvailable = false;
46447
46573
  memories = new Map;
46448
46574
  proposals = new Map;
46449
46575
  lastAutomaticJsonlMigration = null;
@@ -46491,6 +46617,7 @@ class SQLiteMemoryProvider {
46491
46617
  this.db.run(`PRAGMA busy_timeout = ${busyTimeoutMs};`);
46492
46618
  this.db.run("PRAGMA foreign_keys = ON;");
46493
46619
  this.runMigrations();
46620
+ this.ftsAvailable = this.initializeFtsIndex();
46494
46621
  this.lastAutomaticJsonlMigration = null;
46495
46622
  await this.migrateLegacyJsonlIfNeeded();
46496
46623
  const memoryLoad = this.loadMemories();
@@ -46532,6 +46659,7 @@ class SQLiteMemoryProvider {
46532
46659
  if (this.config.hardDelete) {
46533
46660
  this.memories.delete(id);
46534
46661
  this.requireDb().run("DELETE FROM memory_items WHERE id = ?", [id]);
46662
+ this.deleteMemoryFts(id);
46535
46663
  } else {
46536
46664
  const tombstone = {
46537
46665
  ...existing,
@@ -46548,17 +46676,19 @@ class SQLiteMemoryProvider {
46548
46676
  }
46549
46677
  async recallWithDiagnostics(request) {
46550
46678
  await this.initialize();
46551
- const records = await this.list({
46679
+ const scopedRecords = await this.list({
46552
46680
  scopes: request.scopes,
46553
46681
  kinds: request.kinds,
46554
46682
  includeExpired: request.includeExpired
46555
46683
  });
46556
- const result = scoreMemoryRecordsWithDiagnostics(records, request);
46684
+ const candidates = this.selectRecallCandidates(request, scopedRecords);
46685
+ const result = scoreMemoryRecordsWithDiagnostics(candidates.records, request);
46686
+ const reranked = candidates.ftsOrder ? rerankWithFts(result.items, candidates.ftsOrder) : result.items;
46557
46687
  return {
46558
- items: result.items.slice(0, request.maxItems),
46688
+ items: reranked.slice(0, request.maxItems),
46559
46689
  diagnostics: {
46560
46690
  ...result.diagnostics,
46561
- returnedCount: Math.min(result.diagnostics.returnedCount, request.maxItems)
46691
+ returnedCount: Math.min(reranked.length, request.maxItems)
46562
46692
  }
46563
46693
  };
46564
46694
  }
@@ -46648,6 +46778,7 @@ class SQLiteMemoryProvider {
46648
46778
  return;
46649
46779
  this.db.close();
46650
46780
  this.db = null;
46781
+ this.ftsAvailable = false;
46651
46782
  this.initialized = false;
46652
46783
  this.lastAutomaticJsonlMigration = null;
46653
46784
  }
@@ -46677,6 +46808,38 @@ class SQLiteMemoryProvider {
46677
46808
  markMigration(version4, name) {
46678
46809
  this.requireDb().run("INSERT OR IGNORE INTO schema_migrations (version, name) VALUES (?, ?)", [version4, name]);
46679
46810
  }
46811
+ selectRecallCandidates(request, scopedRecords) {
46812
+ const ftsQuery = buildFtsQuery(request);
46813
+ if (!this.ftsAvailable || !ftsQuery) {
46814
+ return { records: scopedRecords, usedFts: false };
46815
+ }
46816
+ const scopedIds = new Set(scopedRecords.map((record3) => record3.id));
46817
+ if (scopedIds.size === 0) {
46818
+ return { records: [], usedFts: true, ftsOrder: new Map };
46819
+ }
46820
+ try {
46821
+ const rows = this.requireDb().query(`SELECT id, bm25(${FTS_TABLE_NAME}) AS rank
46822
+ FROM ${FTS_TABLE_NAME}
46823
+ WHERE ${FTS_TABLE_NAME} MATCH ?
46824
+ AND id IN (SELECT value FROM json_each(?))
46825
+ ORDER BY rank ASC
46826
+ LIMIT ?`).all(ftsQuery, JSON.stringify(Array.from(scopedIds)), Math.max(100, request.maxItems * 20));
46827
+ const ftsOrder = new Map;
46828
+ for (const row of rows) {
46829
+ if (!scopedIds.has(row.id))
46830
+ continue;
46831
+ ftsOrder.set(row.id, ftsOrder.size);
46832
+ }
46833
+ if (ftsOrder.size === 0 && (request.mode ?? "manual") === "manual") {
46834
+ return { records: scopedRecords, usedFts: false };
46835
+ }
46836
+ const records = scopedRecords.filter((record3) => ftsOrder.has(record3.id));
46837
+ return { records, usedFts: true, ftsOrder };
46838
+ } catch {
46839
+ this.ftsAvailable = false;
46840
+ return { records: scopedRecords, usedFts: false };
46841
+ }
46842
+ }
46680
46843
  runMigrations() {
46681
46844
  const db = this.requireDb();
46682
46845
  db.run(`CREATE TABLE IF NOT EXISTS schema_migrations (
@@ -46702,16 +46865,82 @@ class SQLiteMemoryProvider {
46702
46865
  apply();
46703
46866
  }
46704
46867
  }
46868
+ initializeFtsIndex() {
46869
+ const db = this.requireDb();
46870
+ try {
46871
+ if (!this.hasMigration(FTS_SCHEMA_MIGRATION_NAME)) {
46872
+ this.recreateFtsIndex();
46873
+ this.markMigration(FTS_SCHEMA_MIGRATION_VERSION, FTS_SCHEMA_MIGRATION_NAME);
46874
+ this.insertEvent("migration", String(FTS_SCHEMA_MIGRATION_VERSION), FTS_SCHEMA_MIGRATION_NAME);
46875
+ } else {
46876
+ db.run(`CREATE VIRTUAL TABLE IF NOT EXISTS ${FTS_TABLE_NAME} USING fts5(
46877
+ ${ftsCreateColumnsSql()}
46878
+ )`);
46879
+ }
46880
+ this.ftsAvailable = true;
46881
+ const validMemoryCount = this.countValidMemoryRows();
46882
+ const ftsCount = db.query(`SELECT COUNT(*) AS count FROM ${FTS_TABLE_NAME}`).get()?.count ?? 0;
46883
+ if (validMemoryCount !== ftsCount) {
46884
+ this.rebuildFtsIndex();
46885
+ }
46886
+ return true;
46887
+ } catch {
46888
+ this.ftsAvailable = false;
46889
+ return false;
46890
+ }
46891
+ }
46892
+ recreateFtsIndex() {
46893
+ const db = this.requireDb();
46894
+ const recreate = db.transaction(() => {
46895
+ db.run(`DROP TABLE IF EXISTS ${FTS_TABLE_NAME}`);
46896
+ db.run(`CREATE VIRTUAL TABLE ${FTS_TABLE_NAME} USING fts5(
46897
+ ${ftsCreateColumnsSql()}
46898
+ )`);
46899
+ });
46900
+ recreate();
46901
+ }
46902
+ rebuildFtsIndex() {
46903
+ const db = this.requireDb();
46904
+ const rebuild = db.transaction(() => {
46905
+ db.run(`DELETE FROM ${FTS_TABLE_NAME}`);
46906
+ for (const row of this.iterateMemoryRows()) {
46907
+ const record3 = this.parseMemoryRow(row);
46908
+ if (record3) {
46909
+ this.writeMemoryFts(record3);
46910
+ }
46911
+ }
46912
+ });
46913
+ rebuild();
46914
+ }
46915
+ countValidMemoryRows() {
46916
+ let count = 0;
46917
+ for (const row of this.iterateMemoryRows()) {
46918
+ if (this.parseMemoryRow(row))
46919
+ count++;
46920
+ }
46921
+ return count;
46922
+ }
46923
+ *iterateMemoryRows() {
46924
+ yield* this.requireDb().query("SELECT id, record_json FROM memory_items").iterate();
46925
+ }
46926
+ parseMemoryRow(row) {
46927
+ try {
46928
+ return validateMemoryRecordRules(JSON.parse(row.record_json), {
46929
+ rejectDurableSecrets: this.config.redaction.rejectDurableSecrets
46930
+ });
46931
+ } catch {
46932
+ return null;
46933
+ }
46934
+ }
46705
46935
  loadMemories() {
46706
46936
  const rows = this.requireDb().query("SELECT id, record_json FROM memory_items ORDER BY updated_at ASC").all();
46707
46937
  const records = [];
46708
46938
  let invalidCount = 0;
46709
46939
  for (const row of rows) {
46710
- try {
46711
- records.push(validateMemoryRecordRules(JSON.parse(row.record_json), {
46712
- rejectDurableSecrets: this.config.redaction.rejectDurableSecrets
46713
- }));
46714
- } catch {
46940
+ const record3 = this.parseMemoryRow(row);
46941
+ if (record3) {
46942
+ records.push(record3);
46943
+ } else {
46715
46944
  invalidCount++;
46716
46945
  }
46717
46946
  }
@@ -46756,6 +46985,29 @@ class SQLiteMemoryProvider {
46756
46985
  record3.metadata.deleted === true ? 1 : 0,
46757
46986
  JSON.stringify(record3)
46758
46987
  ]);
46988
+ this.writeMemoryFts(record3);
46989
+ }
46990
+ writeMemoryFts(record3) {
46991
+ if (!this.ftsAvailable)
46992
+ return;
46993
+ try {
46994
+ const db = this.requireDb();
46995
+ db.run(`DELETE FROM ${FTS_TABLE_NAME} WHERE id = ?`, [record3.id]);
46996
+ db.run(`INSERT INTO ${FTS_TABLE_NAME} (
46997
+ ${FTS_INSERT_COLUMNS.join(", ")}
46998
+ ) VALUES (${FTS_INSERT_COLUMNS.map(() => "?").join(", ")})`, [record3.id, ...ftsColumnValues(record3)]);
46999
+ } catch {
47000
+ this.ftsAvailable = false;
47001
+ }
47002
+ }
47003
+ deleteMemoryFts(id) {
47004
+ if (!this.ftsAvailable)
47005
+ return;
47006
+ try {
47007
+ this.requireDb().run(`DELETE FROM ${FTS_TABLE_NAME} WHERE id = ?`, [id]);
47008
+ } catch {
47009
+ this.ftsAvailable = false;
47010
+ }
46759
47011
  }
46760
47012
  writeProposal(proposal) {
46761
47013
  this.requireDb().run(`INSERT OR REPLACE INTO memory_proposals (
@@ -46956,7 +47208,69 @@ class SQLiteMemoryProvider {
46956
47208
  function splitSql(sql) {
46957
47209
  return sql.split(";").map((statement) => statement.trim()).filter(Boolean);
46958
47210
  }
46959
- var _DatabaseCtor2 = null, MIGRATIONS2;
47211
+ function buildFtsQuery(request) {
47212
+ const text = request.mode === "injection" && request.task ? `${request.task}
47213
+ ${request.query}` : `${request.query}
47214
+ ${request.task ?? ""}`;
47215
+ const terms = Array.from(extractFtsTerms(text)).slice(0, 40);
47216
+ if (terms.length === 0)
47217
+ return null;
47218
+ return terms.map((term) => `"${term}"`).join(" OR ");
47219
+ }
47220
+ function extractFtsTerms(text) {
47221
+ const terms = new Set;
47222
+ for (const match of text.toLowerCase().matchAll(/[a-z0-9_]{2,}/g)) {
47223
+ const term = match[0];
47224
+ if (FTS_STOP_WORDS.has(term))
47225
+ continue;
47226
+ if (term.length < 3 && !/^\d+$/.test(term))
47227
+ continue;
47228
+ terms.add(term);
47229
+ }
47230
+ return terms;
47231
+ }
47232
+ function ftsCreateColumnsSql() {
47233
+ return [
47234
+ "id UNINDEXED",
47235
+ ...FTS_INDEX_COLUMNS.map((column) => column.name)
47236
+ ].join(`,
47237
+ `);
47238
+ }
47239
+ function ftsColumnValues(record3) {
47240
+ return FTS_INDEX_COLUMNS.map((column) => column.value(record3));
47241
+ }
47242
+ function collectMetadataSearchStrings(metadata, keys) {
47243
+ const values = [];
47244
+ for (const key of keys) {
47245
+ const value = metadata[key];
47246
+ if (typeof value === "string") {
47247
+ values.push(value);
47248
+ continue;
47249
+ }
47250
+ if (!Array.isArray(value))
47251
+ continue;
47252
+ for (const item of value) {
47253
+ if (typeof item === "string")
47254
+ values.push(item);
47255
+ }
47256
+ }
47257
+ return values;
47258
+ }
47259
+ function rerankWithFts(items, ftsOrder) {
47260
+ const denominator = Math.max(ftsOrder.size, 1);
47261
+ return items.map((item) => {
47262
+ const order = ftsOrder.get(item.record.id);
47263
+ if (order === undefined)
47264
+ return item;
47265
+ const ftsBoost = (denominator - order) / denominator * 0.08;
47266
+ return {
47267
+ ...item,
47268
+ score: item.score + ftsBoost,
47269
+ reason: `${item.reason}, fts_rank=${order + 1}`
47270
+ };
47271
+ }).sort((a, b) => b.score - a.score || a.record.id.localeCompare(b.record.id));
47272
+ }
47273
+ 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;
46960
47274
  var init_sqlite_provider = __esm(() => {
46961
47275
  init_utils2();
46962
47276
  init_config3();
@@ -46965,6 +47279,45 @@ var init_sqlite_provider = __esm(() => {
46965
47279
  init_jsonl_migration();
46966
47280
  init_schema2();
46967
47281
  init_scoring();
47282
+ FTS_INDEX_COLUMNS = [
47283
+ {
47284
+ name: "text",
47285
+ value: (record3) => record3.text
47286
+ },
47287
+ {
47288
+ name: "tags",
47289
+ value: (record3) => record3.tags.join(" ")
47290
+ },
47291
+ {
47292
+ name: "kind",
47293
+ value: (record3) => record3.kind.replace(/_/g, " ")
47294
+ },
47295
+ {
47296
+ name: "source_file_path",
47297
+ value: (record3) => record3.source.filePath ?? ""
47298
+ },
47299
+ {
47300
+ name: "source_ref",
47301
+ value: (record3) => record3.source.ref ?? ""
47302
+ },
47303
+ {
47304
+ name: "metadata_symbols",
47305
+ value: (record3) => collectMetadataSearchStrings(record3.metadata, ["symbol", "symbols"]).join(" ")
47306
+ },
47307
+ {
47308
+ name: "metadata_files",
47309
+ value: (record3) => collectMetadataSearchStrings(record3.metadata, [
47310
+ "file",
47311
+ "filePath",
47312
+ "files",
47313
+ "touchedFiles"
47314
+ ]).join(" ")
47315
+ }
47316
+ ];
47317
+ FTS_INSERT_COLUMNS = [
47318
+ "id",
47319
+ ...FTS_INDEX_COLUMNS.map((column) => column.name)
47320
+ ];
46968
47321
  MIGRATIONS2 = [
46969
47322
  {
46970
47323
  version: 1,
@@ -47014,6 +47367,37 @@ var init_sqlite_provider = __esm(() => {
47014
47367
  `
47015
47368
  }
47016
47369
  ];
47370
+ FTS_STOP_WORDS = new Set([
47371
+ "a",
47372
+ "an",
47373
+ "and",
47374
+ "are",
47375
+ "as",
47376
+ "at",
47377
+ "be",
47378
+ "by",
47379
+ "for",
47380
+ "from",
47381
+ "goal",
47382
+ "how",
47383
+ "in",
47384
+ "into",
47385
+ "is",
47386
+ "it",
47387
+ "of",
47388
+ "on",
47389
+ "or",
47390
+ "role",
47391
+ "task",
47392
+ "that",
47393
+ "the",
47394
+ "this",
47395
+ "to",
47396
+ "user",
47397
+ "what",
47398
+ "when",
47399
+ "with"
47400
+ ]);
47017
47401
  });
47018
47402
 
47019
47403
  // src/memory/gateway.ts
@@ -47035,6 +47419,332 @@ var init_gateway = __esm(() => {
47035
47419
  gitRemoteUrlCache = new Map;
47036
47420
  });
47037
47421
 
47422
+ // src/memory/evaluation.ts
47423
+ import * as fs12 from "fs/promises";
47424
+ import * as os7 from "os";
47425
+ import * as path32 from "path";
47426
+ async function evaluateMemoryRecallFixtures(options) {
47427
+ const fixtureDirectory = path32.resolve(options.fixtureDirectory);
47428
+ const providers = options.providers ?? DEFAULT_PROVIDERS;
47429
+ const modes = options.modes ?? DEFAULT_MODES;
47430
+ const generatedAt = new Date().toISOString();
47431
+ const fixtures = await loadRecallEvaluationFixtures(fixtureDirectory);
47432
+ const runs = [];
47433
+ for (const fixture of fixtures) {
47434
+ const materialized = materializeFixture(fixture);
47435
+ for (const providerName of providers) {
47436
+ const tempRoot = await fs12.realpath(await fs12.mkdtemp(path32.join(os7.tmpdir(), "swarm-memory-eval-")));
47437
+ const provider = createEvaluationProvider(providerName, tempRoot);
47438
+ try {
47439
+ await provider.initialize?.();
47440
+ for (const record3 of materialized.records) {
47441
+ await provider.upsert(record3);
47442
+ }
47443
+ for (const mode of modes) {
47444
+ const request = buildRecallRequest(fixture, mode);
47445
+ const items = await provider.recall(request);
47446
+ const retrievedIds = items.map((item) => item.record.id);
47447
+ const run = buildRun({
47448
+ fixture,
47449
+ provider: providerName,
47450
+ mode,
47451
+ k: fixture.k ?? request.maxItems,
47452
+ retrievedIds,
47453
+ materialized
47454
+ });
47455
+ runs.push(run);
47456
+ }
47457
+ } finally {
47458
+ await provider.close?.();
47459
+ if (!options.keepTempRoots) {
47460
+ await fs12.rm(tempRoot, { recursive: true, force: true });
47461
+ }
47462
+ }
47463
+ }
47464
+ }
47465
+ return {
47466
+ schema_version: 1,
47467
+ generated_at: generatedAt,
47468
+ fixture_directory: fixtureDirectory,
47469
+ providers,
47470
+ modes,
47471
+ summary: summarizeRuns(fixtures.length, runs),
47472
+ runs
47473
+ };
47474
+ }
47475
+ async function loadRecallEvaluationFixtures(fixtureDirectory) {
47476
+ const entries = await fs12.readdir(fixtureDirectory, { withFileTypes: true });
47477
+ const files = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort((a, b) => a.localeCompare(b));
47478
+ const fixtures = [];
47479
+ for (const file3 of files) {
47480
+ const raw = await fs12.readFile(path32.join(fixtureDirectory, file3), "utf-8");
47481
+ fixtures.push(validateFixture(JSON.parse(raw), file3));
47482
+ }
47483
+ return fixtures;
47484
+ }
47485
+ function createEvaluationProvider(provider, root) {
47486
+ const config3 = {
47487
+ ...DEFAULT_MEMORY_CONFIG,
47488
+ enabled: true,
47489
+ provider
47490
+ };
47491
+ return createConfiguredMemoryProvider(root, config3);
47492
+ }
47493
+ function buildRecallRequest(fixture, mode) {
47494
+ const maxItems = fixture.maxItems ?? fixture.k ?? 5;
47495
+ const base = {
47496
+ query: fixture.query,
47497
+ task: fixture.task,
47498
+ agentRole: mode === "curator" ? "curator" : fixture.agentRole,
47499
+ mode,
47500
+ scopes: fixture.scopes,
47501
+ kinds: fixture.kinds,
47502
+ maxItems,
47503
+ tokenBudget: fixture.tokenBudget ?? 1000,
47504
+ minScore: mode === "injection" ? 0.25 : 0,
47505
+ requireQuerySignal: mode === "injection"
47506
+ };
47507
+ return base;
47508
+ }
47509
+ function materializeFixture(fixture) {
47510
+ const idsByLabel = new Map;
47511
+ const labelsById = new Map;
47512
+ const baseRecords = fixture.records.map((record3) => {
47513
+ const base = {
47514
+ scope: record3.scope,
47515
+ kind: record3.kind,
47516
+ text: record3.text
47517
+ };
47518
+ const id = createMemoryId(base);
47519
+ idsByLabel.set(record3.label, id);
47520
+ labelsById.set(id, record3.label);
47521
+ return { input: record3, id, base };
47522
+ });
47523
+ const expectedIds = new Set(fixture.expectedLabels.map((label) => {
47524
+ const id = idsByLabel.get(label);
47525
+ if (!id) {
47526
+ throw new Error(`fixture ${fixture.name} expected unknown label ${label}`);
47527
+ }
47528
+ return id;
47529
+ }));
47530
+ const allowedScopeKeys = new Set(fixture.scopes.map(stableScopeKey));
47531
+ const staleIds = new Set;
47532
+ const crossScopeIds = new Set;
47533
+ const sameScopeNoiseIds = new Set;
47534
+ const records = baseRecords.map(({ input, id, base }) => {
47535
+ const supersededBy = input.state?.supersededByLabel ? idsByLabel.get(input.state.supersededByLabel) : undefined;
47536
+ if (input.state?.supersededByLabel && !supersededBy) {
47537
+ throw new Error(`fixture ${fixture.name} record ${input.label} supersedes unknown label ${input.state.supersededByLabel}`);
47538
+ }
47539
+ const metadata = {
47540
+ ...input.metadata ?? {},
47541
+ fixture: fixture.name,
47542
+ fixtureLabel: input.label,
47543
+ ...input.state?.deleted ? { deleted: true } : {}
47544
+ };
47545
+ const record3 = {
47546
+ id,
47547
+ ...base,
47548
+ tags: input.tags ?? [],
47549
+ confidence: input.confidence ?? 0.8,
47550
+ stability: input.stability ?? "durable",
47551
+ source: input.source ?? { type: "manual", ref: fixture.name },
47552
+ createdAt: DEFAULT_TIMESTAMP,
47553
+ updatedAt: DEFAULT_TIMESTAMP,
47554
+ expiresAt: input.state?.expiresAt,
47555
+ supersededBy,
47556
+ contentHash: computeMemoryContentHash(base),
47557
+ metadata
47558
+ };
47559
+ if (record3.metadata.deleted === true || record3.supersededBy || record3.expiresAt && Date.parse(record3.expiresAt) <= Date.now()) {
47560
+ staleIds.add(record3.id);
47561
+ }
47562
+ const inScope = allowedScopeKeys.has(stableScopeKey(record3.scope));
47563
+ if (!inScope) {
47564
+ crossScopeIds.add(record3.id);
47565
+ } else if (!expectedIds.has(record3.id) && !staleIds.has(record3.id)) {
47566
+ sameScopeNoiseIds.add(record3.id);
47567
+ }
47568
+ return validateMemoryRecordRules(record3, { rejectDurableSecrets: true });
47569
+ });
47570
+ return {
47571
+ records,
47572
+ idsByLabel,
47573
+ labelsById,
47574
+ expectedIds,
47575
+ staleIds,
47576
+ crossScopeIds,
47577
+ sameScopeNoiseIds
47578
+ };
47579
+ }
47580
+ function buildRun(args) {
47581
+ const { fixture, provider, mode, k, retrievedIds, materialized } = args;
47582
+ const topK = retrievedIds.slice(0, k);
47583
+ const relevantAtK = topK.filter((id) => materialized.expectedIds.has(id)).length;
47584
+ const crossScopeLeakCount = retrievedIds.filter((id) => materialized.crossScopeIds.has(id)).length;
47585
+ const staleMemoryCount = retrievedIds.filter((id) => materialized.staleIds.has(id)).length;
47586
+ const noisyInjectionCount = mode === "injection" ? retrievedIds.filter((id) => materialized.sameScopeNoiseIds.has(id)).length : 0;
47587
+ const sameScopeNoiseCount = retrievedIds.filter((id) => materialized.sameScopeNoiseIds.has(id)).length;
47588
+ const metrics = {
47589
+ "precision@k": relevantAtK / Math.max(k, 1),
47590
+ "recall@k": relevantAtK / Math.max(materialized.expectedIds.size, 1),
47591
+ injection_count: mode === "injection" ? retrievedIds.length : 0,
47592
+ noisy_injection_count: noisyInjectionCount,
47593
+ same_scope_noise_count: sameScopeNoiseCount,
47594
+ cross_scope_leak_count: crossScopeLeakCount,
47595
+ stale_memory_count: staleMemoryCount
47596
+ };
47597
+ return {
47598
+ fixture: fixture.name,
47599
+ provider,
47600
+ mode,
47601
+ k,
47602
+ query: fixture.query,
47603
+ expected_labels: fixture.expectedLabels,
47604
+ expected_ids: fixture.expectedLabels.map((label) => materialized.idsByLabel.get(label) ?? label),
47605
+ retrieved_labels: retrievedIds.map((id) => materialized.labelsById.get(id) ?? id),
47606
+ retrieved_ids: retrievedIds,
47607
+ metrics,
47608
+ passed: metrics["recall@k"] >= 1 && metrics.noisy_injection_count === 0 && metrics.cross_scope_leak_count === 0 && metrics.stale_memory_count === 0
47609
+ };
47610
+ }
47611
+ function summarizeRuns(fixtureCount, runs) {
47612
+ const total = runs.reduce((acc, run) => {
47613
+ acc["precision@k"] += run.metrics["precision@k"];
47614
+ acc["recall@k"] += run.metrics["recall@k"];
47615
+ acc.injection_count += run.metrics.injection_count;
47616
+ acc.noisy_injection_count += run.metrics.noisy_injection_count;
47617
+ acc.same_scope_noise_count += run.metrics.same_scope_noise_count;
47618
+ acc.cross_scope_leak_count += run.metrics.cross_scope_leak_count;
47619
+ acc.stale_memory_count += run.metrics.stale_memory_count;
47620
+ if (run.passed)
47621
+ acc.passed_run_count++;
47622
+ return acc;
47623
+ }, {
47624
+ "precision@k": 0,
47625
+ "recall@k": 0,
47626
+ injection_count: 0,
47627
+ noisy_injection_count: 0,
47628
+ same_scope_noise_count: 0,
47629
+ cross_scope_leak_count: 0,
47630
+ stale_memory_count: 0,
47631
+ passed_run_count: 0
47632
+ });
47633
+ const denominator = Math.max(runs.length, 1);
47634
+ return {
47635
+ fixture_count: fixtureCount,
47636
+ run_count: runs.length,
47637
+ passed_run_count: total.passed_run_count,
47638
+ "precision@k": total["precision@k"] / denominator,
47639
+ "recall@k": total["recall@k"] / denominator,
47640
+ injection_count: total.injection_count,
47641
+ noisy_injection_count: total.noisy_injection_count,
47642
+ same_scope_noise_count: total.same_scope_noise_count,
47643
+ cross_scope_leak_count: total.cross_scope_leak_count,
47644
+ stale_memory_count: total.stale_memory_count
47645
+ };
47646
+ }
47647
+ function validateFixture(value, file3) {
47648
+ if (!value || typeof value !== "object") {
47649
+ throw new Error(`memory recall fixture ${file3} must be an object`);
47650
+ }
47651
+ const fixture = value;
47652
+ if (typeof fixture.name !== "string" || !fixture.name) {
47653
+ throw new Error(`memory recall fixture ${file3} is missing name`);
47654
+ }
47655
+ if (typeof fixture.query !== "string" || fixture.query.length < 3) {
47656
+ throw new Error(`memory recall fixture ${file3} has invalid query`);
47657
+ }
47658
+ if (!Array.isArray(fixture.scopes) || fixture.scopes.length === 0) {
47659
+ throw new Error(`memory recall fixture ${file3} must define scopes`);
47660
+ }
47661
+ const scopes = fixture.scopes.map((scope, index) => validateScope(scope, file3, `scope #${index + 1}`));
47662
+ if (!Array.isArray(fixture.expectedLabels) || fixture.expectedLabels.length === 0) {
47663
+ throw new Error(`memory recall fixture ${file3} must define expectedLabels`);
47664
+ }
47665
+ const expectedLabels = fixture.expectedLabels.map((label, index) => {
47666
+ if (typeof label !== "string" || !label) {
47667
+ throw new Error(`memory recall fixture ${file3} expectedLabels #${index + 1} must be a non-empty string`);
47668
+ }
47669
+ return label;
47670
+ });
47671
+ if (!Array.isArray(fixture.records) || fixture.records.length === 0) {
47672
+ throw new Error(`memory recall fixture ${file3} must define records`);
47673
+ }
47674
+ const records = fixture.records.map((record3, index) => validateFixtureRecord(record3, file3, index));
47675
+ return {
47676
+ ...fixture,
47677
+ name: fixture.name,
47678
+ query: fixture.query,
47679
+ scopes,
47680
+ expectedLabels,
47681
+ records
47682
+ };
47683
+ }
47684
+ function validateFixtureRecord(value, file3, index) {
47685
+ if (!value || typeof value !== "object") {
47686
+ throw new Error(`memory recall fixture ${file3} record #${index + 1} must be an object`);
47687
+ }
47688
+ const record3 = value;
47689
+ const labelForError = typeof record3.label === "string" && record3.label ? record3.label : `#${index + 1}`;
47690
+ if (typeof record3.label !== "string" || !record3.label) {
47691
+ throw new Error(`memory recall fixture ${file3} record ${labelForError} is missing label`);
47692
+ }
47693
+ const scope = validateScope(record3.scope, file3, `record ${record3.label}`);
47694
+ if (!("kind" in record3) || record3.kind === "") {
47695
+ throw new Error(`memory recall fixture ${file3} record ${record3.label} is missing kind`);
47696
+ }
47697
+ if (typeof record3.kind !== "string") {
47698
+ throw new Error(`memory recall fixture ${file3} record ${record3.label} has invalid kind`);
47699
+ }
47700
+ const parsedKind = MemoryKindSchema.safeParse(record3.kind);
47701
+ if (!parsedKind.success) {
47702
+ throw new Error(`memory recall fixture ${file3} record ${record3.label} has invalid kind`);
47703
+ }
47704
+ if (!("text" in record3) || record3.text === "") {
47705
+ throw new Error(`memory recall fixture ${file3} record ${record3.label} is missing text`);
47706
+ }
47707
+ if (typeof record3.text !== "string") {
47708
+ throw new Error(`memory recall fixture ${file3} record ${record3.label} has invalid text`);
47709
+ }
47710
+ return {
47711
+ ...record3,
47712
+ label: record3.label,
47713
+ scope,
47714
+ kind: parsedKind.data,
47715
+ text: record3.text
47716
+ };
47717
+ }
47718
+ function validateScope(value, file3, descriptor) {
47719
+ if (!value || typeof value !== "object") {
47720
+ throw new Error(`memory recall fixture ${file3} ${descriptor} is missing scope`);
47721
+ }
47722
+ const scope = value;
47723
+ if (typeof scope.type !== "string") {
47724
+ throw new Error(`memory recall fixture ${file3} ${descriptor} has invalid scope type`);
47725
+ }
47726
+ const parsed = MemoryScopeRefSchema.safeParse(scope);
47727
+ if (!parsed.success) {
47728
+ throw new Error(`memory recall fixture ${file3} ${descriptor} has invalid scope`);
47729
+ }
47730
+ return parsed.data;
47731
+ }
47732
+ var DEFAULT_PROVIDERS, DEFAULT_MODES, DEFAULT_TIMESTAMP = "2026-05-26T12:00:00.000Z";
47733
+ var init_evaluation = __esm(() => {
47734
+ init_config3();
47735
+ init_gateway();
47736
+ init_schema2();
47737
+ DEFAULT_PROVIDERS = [
47738
+ "local-jsonl",
47739
+ "sqlite"
47740
+ ];
47741
+ DEFAULT_MODES = [
47742
+ "manual",
47743
+ "injection",
47744
+ "curator"
47745
+ ];
47746
+ });
47747
+
47038
47748
  // src/agents/agent-output-schema.ts
47039
47749
  var AgentMemoryProposalSchema, AgentOutputMemorySchema, CuratorOutputMemoryDecisionSchema;
47040
47750
  var init_agent_output_schema = __esm(() => {
@@ -47064,11 +47774,6 @@ var init_agent_output_schema = __esm(() => {
47064
47774
  }).passthrough();
47065
47775
  });
47066
47776
 
47067
- // src/memory/role-profiles.ts
47068
- var init_role_profiles = __esm(() => {
47069
- init_schema();
47070
- });
47071
-
47072
47777
  // src/memory/recall-planner.ts
47073
47778
  var init_recall_planner = __esm(() => {
47074
47779
  init_role_profiles();
@@ -47094,6 +47799,7 @@ var init_injector = __esm(() => {
47094
47799
  var init_memory = __esm(() => {
47095
47800
  init_config3();
47096
47801
  init_errors6();
47802
+ init_evaluation();
47097
47803
  init_gateway();
47098
47804
  init_injector();
47099
47805
  init_jsonl_migration();
@@ -47109,6 +47815,8 @@ var init_memory = __esm(() => {
47109
47815
 
47110
47816
  // src/commands/memory.ts
47111
47817
  import { existsSync as existsSync20 } from "fs";
47818
+ import * as path33 from "path";
47819
+ import { fileURLToPath as fileURLToPath2 } from "url";
47112
47820
  async function handleMemoryCommand(_directory, _args) {
47113
47821
  return [
47114
47822
  "## Swarm Memory",
@@ -47116,7 +47824,8 @@ async function handleMemoryCommand(_directory, _args) {
47116
47824
  "- `/swarm memory status` - show provider, SQLite path, JSONL files, and last migration report",
47117
47825
  "- `/swarm memory export` - export current memory and proposals to `.swarm/memory/export/*.jsonl`",
47118
47826
  "- `/swarm memory import` - import `.swarm/memory/{memories,proposals}.jsonl` into SQLite",
47119
- "- `/swarm memory migrate` - run the one-time legacy JSONL to SQLite migration"
47827
+ "- `/swarm memory migrate` - run the one-time legacy JSONL to SQLite migration",
47828
+ "- `/swarm memory evaluate --json` - run the golden recall evaluation fixtures and emit a JSON report"
47120
47829
  ].join(`
47121
47830
  `);
47122
47831
  }
@@ -47214,10 +47923,75 @@ async function handleMemoryExportCommand(directory, _args) {
47214
47923
  await provider.close?.();
47215
47924
  }
47216
47925
  }
47926
+ async function handleMemoryEvaluateCommand(directory, args) {
47927
+ const parsed = parseEvaluateArgs(directory, args);
47928
+ if ("error" in parsed)
47929
+ return parsed.error;
47930
+ const report = await evaluateMemoryRecallFixtures({
47931
+ fixtureDirectory: parsed.fixtureDirectory
47932
+ });
47933
+ if (parsed.json)
47934
+ return `${JSON.stringify(report, null, 2)}
47935
+ `;
47936
+ return [
47937
+ "## Swarm Memory Recall Evaluation",
47938
+ "",
47939
+ `- Fixtures: \`${report.summary.fixture_count}\``,
47940
+ `- Runs: \`${report.summary.run_count}\``,
47941
+ `- Passed runs: \`${report.summary.passed_run_count}\``,
47942
+ `- Precision@k: \`${report.summary["precision@k"].toFixed(3)}\``,
47943
+ `- Recall@k: \`${report.summary["recall@k"].toFixed(3)}\``,
47944
+ `- Injection count: \`${report.summary.injection_count}\``,
47945
+ `- Noisy injections: \`${report.summary.noisy_injection_count}\``,
47946
+ `- Same-scope noise: \`${report.summary.same_scope_noise_count}\``,
47947
+ `- Cross-scope leaks: \`${report.summary.cross_scope_leak_count}\``,
47948
+ `- Stale memories: \`${report.summary.stale_memory_count}\``,
47949
+ "",
47950
+ "Use `/swarm memory evaluate --json` for the full report."
47951
+ ].join(`
47952
+ `);
47953
+ }
47217
47954
  function resolveCommandMemoryConfig(directory) {
47218
47955
  const loaded = loadPluginConfig(directory).memory;
47219
47956
  return resolveMemoryConfig(loaded ?? DEFAULT_MEMORY_CONFIG);
47220
47957
  }
47958
+ function parseEvaluateArgs(directory, args) {
47959
+ let json3 = false;
47960
+ let fixtureDirectory = path33.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall");
47961
+ for (let i = 0;i < args.length; i++) {
47962
+ const arg = args[i];
47963
+ if (arg === "--json") {
47964
+ json3 = true;
47965
+ continue;
47966
+ }
47967
+ if (arg === "--fixtures") {
47968
+ const next = args[i + 1];
47969
+ if (!next) {
47970
+ return {
47971
+ error: "Usage: /swarm memory evaluate [--json] [--fixtures <directory>]"
47972
+ };
47973
+ }
47974
+ fixtureDirectory = path33.resolve(directory, next);
47975
+ i++;
47976
+ continue;
47977
+ }
47978
+ return {
47979
+ error: "Usage: /swarm memory evaluate [--json] [--fixtures <directory>]"
47980
+ };
47981
+ }
47982
+ return { json: json3, fixtureDirectory };
47983
+ }
47984
+ function resolvePackageRootFromModule(modulePath) {
47985
+ const moduleDir = path33.dirname(modulePath);
47986
+ const leaf = path33.basename(moduleDir);
47987
+ if (leaf === "commands" || leaf === "cli") {
47988
+ return path33.resolve(moduleDir, "..", "..");
47989
+ }
47990
+ if (leaf === "dist") {
47991
+ return path33.resolve(moduleDir, "..");
47992
+ }
47993
+ return path33.resolve(moduleDir, "..");
47994
+ }
47221
47995
  function formatMigrationResult(label, report) {
47222
47996
  if (!report) {
47223
47997
  return [
@@ -47257,9 +48031,11 @@ function appendInvalidRows(lines, invalidRows) {
47257
48031
  lines.push(`- ... ${invalidRows.length - 20} more`);
47258
48032
  }
47259
48033
  }
48034
+ var PACKAGE_ROOT;
47260
48035
  var init_memory2 = __esm(() => {
47261
48036
  init_loader();
47262
48037
  init_memory();
48038
+ PACKAGE_ROOT = path33.resolve(resolvePackageRootFromModule(fileURLToPath2(import.meta.url)));
47263
48039
  });
47264
48040
 
47265
48041
  // src/services/plan-service.ts
@@ -47646,8 +48422,8 @@ function containsControlChars(str) {
47646
48422
  var init_path_security = () => {};
47647
48423
 
47648
48424
  // src/tools/lint.ts
47649
- import * as fs12 from "fs";
47650
- import * as path32 from "path";
48425
+ import * as fs13 from "fs";
48426
+ import * as path34 from "path";
47651
48427
  function validateArgs(args) {
47652
48428
  if (typeof args !== "object" || args === null)
47653
48429
  return false;
@@ -47658,9 +48434,9 @@ function validateArgs(args) {
47658
48434
  }
47659
48435
  function getLinterCommand(linter, mode, projectDir) {
47660
48436
  const isWindows = process.platform === "win32";
47661
- const binDir = path32.join(projectDir, "node_modules", ".bin");
47662
- const biomeBin = isWindows ? path32.join(binDir, "biome.EXE") : path32.join(binDir, "biome");
47663
- const eslintBin = isWindows ? path32.join(binDir, "eslint.cmd") : path32.join(binDir, "eslint");
48437
+ const binDir = path34.join(projectDir, "node_modules", ".bin");
48438
+ const biomeBin = isWindows ? path34.join(binDir, "biome.EXE") : path34.join(binDir, "biome");
48439
+ const eslintBin = isWindows ? path34.join(binDir, "eslint.cmd") : path34.join(binDir, "eslint");
47664
48440
  switch (linter) {
47665
48441
  case "biome":
47666
48442
  if (mode === "fix") {
@@ -47676,7 +48452,7 @@ function getLinterCommand(linter, mode, projectDir) {
47676
48452
  }
47677
48453
  function getAdditionalLinterCommand(linter, mode, cwd) {
47678
48454
  const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
47679
- const gradlew = fs12.existsSync(path32.join(cwd, gradlewName)) ? path32.join(cwd, gradlewName) : null;
48455
+ const gradlew = fs13.existsSync(path34.join(cwd, gradlewName)) ? path34.join(cwd, gradlewName) : null;
47680
48456
  switch (linter) {
47681
48457
  case "ruff":
47682
48458
  return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
@@ -47710,12 +48486,12 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
47710
48486
  }
47711
48487
  }
47712
48488
  function detectRuff(cwd) {
47713
- if (fs12.existsSync(path32.join(cwd, "ruff.toml")))
48489
+ if (fs13.existsSync(path34.join(cwd, "ruff.toml")))
47714
48490
  return isCommandAvailable("ruff");
47715
48491
  try {
47716
- const pyproject = path32.join(cwd, "pyproject.toml");
47717
- if (fs12.existsSync(pyproject)) {
47718
- const content = fs12.readFileSync(pyproject, "utf-8");
48492
+ const pyproject = path34.join(cwd, "pyproject.toml");
48493
+ if (fs13.existsSync(pyproject)) {
48494
+ const content = fs13.readFileSync(pyproject, "utf-8");
47719
48495
  if (content.includes("[tool.ruff]"))
47720
48496
  return isCommandAvailable("ruff");
47721
48497
  }
@@ -47723,21 +48499,21 @@ function detectRuff(cwd) {
47723
48499
  return false;
47724
48500
  }
47725
48501
  function detectClippy(cwd) {
47726
- return fs12.existsSync(path32.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
48502
+ return fs13.existsSync(path34.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
47727
48503
  }
47728
48504
  function detectGolangciLint(cwd) {
47729
- return fs12.existsSync(path32.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
48505
+ return fs13.existsSync(path34.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
47730
48506
  }
47731
48507
  function detectCheckstyle(cwd) {
47732
- const hasMaven = fs12.existsSync(path32.join(cwd, "pom.xml"));
47733
- const hasGradle = fs12.existsSync(path32.join(cwd, "build.gradle")) || fs12.existsSync(path32.join(cwd, "build.gradle.kts"));
47734
- const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs12.existsSync(path32.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
48508
+ const hasMaven = fs13.existsSync(path34.join(cwd, "pom.xml"));
48509
+ const hasGradle = fs13.existsSync(path34.join(cwd, "build.gradle")) || fs13.existsSync(path34.join(cwd, "build.gradle.kts"));
48510
+ const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs13.existsSync(path34.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
47735
48511
  return (hasMaven || hasGradle) && hasBinary;
47736
48512
  }
47737
48513
  function detectKtlint(cwd) {
47738
- const hasKotlin = fs12.existsSync(path32.join(cwd, "build.gradle.kts")) || fs12.existsSync(path32.join(cwd, "build.gradle")) || (() => {
48514
+ const hasKotlin = fs13.existsSync(path34.join(cwd, "build.gradle.kts")) || fs13.existsSync(path34.join(cwd, "build.gradle")) || (() => {
47739
48515
  try {
47740
- return fs12.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
48516
+ return fs13.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
47741
48517
  } catch {
47742
48518
  return false;
47743
48519
  }
@@ -47746,7 +48522,7 @@ function detectKtlint(cwd) {
47746
48522
  }
47747
48523
  function detectDotnetFormat(cwd) {
47748
48524
  try {
47749
- const files = fs12.readdirSync(cwd);
48525
+ const files = fs13.readdirSync(cwd);
47750
48526
  const hasCsproj = files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"));
47751
48527
  return hasCsproj && isCommandAvailable("dotnet");
47752
48528
  } catch {
@@ -47754,14 +48530,14 @@ function detectDotnetFormat(cwd) {
47754
48530
  }
47755
48531
  }
47756
48532
  function detectCppcheck(cwd) {
47757
- if (fs12.existsSync(path32.join(cwd, "CMakeLists.txt"))) {
48533
+ if (fs13.existsSync(path34.join(cwd, "CMakeLists.txt"))) {
47758
48534
  return isCommandAvailable("cppcheck");
47759
48535
  }
47760
48536
  try {
47761
- const dirsToCheck = [cwd, path32.join(cwd, "src")];
48537
+ const dirsToCheck = [cwd, path34.join(cwd, "src")];
47762
48538
  const hasCpp = dirsToCheck.some((dir) => {
47763
48539
  try {
47764
- return fs12.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
48540
+ return fs13.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
47765
48541
  } catch {
47766
48542
  return false;
47767
48543
  }
@@ -47772,13 +48548,13 @@ function detectCppcheck(cwd) {
47772
48548
  }
47773
48549
  }
47774
48550
  function detectSwiftlint(cwd) {
47775
- return fs12.existsSync(path32.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
48551
+ return fs13.existsSync(path34.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
47776
48552
  }
47777
48553
  function detectDartAnalyze(cwd) {
47778
- return fs12.existsSync(path32.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
48554
+ return fs13.existsSync(path34.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
47779
48555
  }
47780
48556
  function detectRubocop(cwd) {
47781
- return (fs12.existsSync(path32.join(cwd, "Gemfile")) || fs12.existsSync(path32.join(cwd, "gems.rb")) || fs12.existsSync(path32.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
48557
+ return (fs13.existsSync(path34.join(cwd, "Gemfile")) || fs13.existsSync(path34.join(cwd, "gems.rb")) || fs13.existsSync(path34.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
47782
48558
  }
47783
48559
  function detectAdditionalLinter(cwd) {
47784
48560
  if (detectRuff(cwd))
@@ -47806,10 +48582,10 @@ function detectAdditionalLinter(cwd) {
47806
48582
  function findBinInAncestors(startDir, binName) {
47807
48583
  let dir = startDir;
47808
48584
  while (true) {
47809
- const candidate = path32.join(dir, "node_modules", ".bin", binName);
47810
- if (fs12.existsSync(candidate))
48585
+ const candidate = path34.join(dir, "node_modules", ".bin", binName);
48586
+ if (fs13.existsSync(candidate))
47811
48587
  return candidate;
47812
- const parent = path32.dirname(dir);
48588
+ const parent = path34.dirname(dir);
47813
48589
  if (parent === dir)
47814
48590
  break;
47815
48591
  dir = parent;
@@ -47818,11 +48594,11 @@ function findBinInAncestors(startDir, binName) {
47818
48594
  }
47819
48595
  function findBinInEnvPath(binName) {
47820
48596
  const searchPath = process.env.PATH ?? "";
47821
- for (const dir of searchPath.split(path32.delimiter)) {
48597
+ for (const dir of searchPath.split(path34.delimiter)) {
47822
48598
  if (!dir)
47823
48599
  continue;
47824
- const candidate = path32.join(dir, binName);
47825
- if (fs12.existsSync(candidate))
48600
+ const candidate = path34.join(dir, binName);
48601
+ if (fs13.existsSync(candidate))
47826
48602
  return candidate;
47827
48603
  }
47828
48604
  return null;
@@ -47830,17 +48606,17 @@ function findBinInEnvPath(binName) {
47830
48606
  async function detectAvailableLinter(directory) {
47831
48607
  if (!directory)
47832
48608
  return null;
47833
- if (!fs12.existsSync(directory))
48609
+ if (!fs13.existsSync(directory))
47834
48610
  return null;
47835
48611
  const projectDir = directory;
47836
48612
  const isWindows = process.platform === "win32";
47837
- const biomeBin = isWindows ? path32.join(projectDir, "node_modules", ".bin", "biome.EXE") : path32.join(projectDir, "node_modules", ".bin", "biome");
47838
- const eslintBin = isWindows ? path32.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path32.join(projectDir, "node_modules", ".bin", "eslint");
48613
+ const biomeBin = isWindows ? path34.join(projectDir, "node_modules", ".bin", "biome.EXE") : path34.join(projectDir, "node_modules", ".bin", "biome");
48614
+ const eslintBin = isWindows ? path34.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path34.join(projectDir, "node_modules", ".bin", "eslint");
47839
48615
  const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
47840
48616
  if (localResult)
47841
48617
  return localResult;
47842
- const biomeAncestor = findBinInAncestors(path32.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
47843
- const eslintAncestor = findBinInAncestors(path32.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
48618
+ const biomeAncestor = findBinInAncestors(path34.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
48619
+ const eslintAncestor = findBinInAncestors(path34.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
47844
48620
  if (biomeAncestor || eslintAncestor) {
47845
48621
  return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
47846
48622
  }
@@ -47859,11 +48635,11 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
47859
48635
  stderr: "pipe"
47860
48636
  });
47861
48637
  const biomeExit = biomeProc.exited;
47862
- const timeout = new Promise((resolve10) => setTimeout(() => resolve10("timeout"), DETECT_TIMEOUT));
48638
+ const timeout = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), DETECT_TIMEOUT));
47863
48639
  const result = await Promise.race([biomeExit, timeout]);
47864
48640
  if (result === "timeout") {
47865
48641
  biomeProc.kill();
47866
- } else if (biomeProc.exitCode === 0 && fs12.existsSync(biomeBin)) {
48642
+ } else if (biomeProc.exitCode === 0 && fs13.existsSync(biomeBin)) {
47867
48643
  return "biome";
47868
48644
  }
47869
48645
  } catch {}
@@ -47873,11 +48649,11 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
47873
48649
  stderr: "pipe"
47874
48650
  });
47875
48651
  const eslintExit = eslintProc.exited;
47876
- const timeout = new Promise((resolve10) => setTimeout(() => resolve10("timeout"), DETECT_TIMEOUT));
48652
+ const timeout = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), DETECT_TIMEOUT));
47877
48653
  const result = await Promise.race([eslintExit, timeout]);
47878
48654
  if (result === "timeout") {
47879
48655
  eslintProc.kill();
47880
- } else if (eslintProc.exitCode === 0 && fs12.existsSync(eslintBin)) {
48656
+ } else if (eslintProc.exitCode === 0 && fs13.existsSync(eslintBin)) {
47881
48657
  return "eslint";
47882
48658
  }
47883
48659
  } catch {}
@@ -48062,8 +48838,8 @@ For Rust: rustup component add clippy`
48062
48838
  });
48063
48839
 
48064
48840
  // src/tools/secretscan.ts
48065
- import * as fs13 from "fs";
48066
- import * as path33 from "path";
48841
+ import * as fs14 from "fs";
48842
+ import * as path35 from "path";
48067
48843
  function calculateShannonEntropy(str) {
48068
48844
  if (str.length === 0)
48069
48845
  return 0;
@@ -48111,11 +48887,11 @@ function isGlobOrPathPattern(pattern) {
48111
48887
  return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
48112
48888
  }
48113
48889
  function loadSecretScanIgnore(scanDir) {
48114
- const ignorePath = path33.join(scanDir, ".secretscanignore");
48890
+ const ignorePath = path35.join(scanDir, ".secretscanignore");
48115
48891
  try {
48116
- if (!fs13.existsSync(ignorePath))
48892
+ if (!fs14.existsSync(ignorePath))
48117
48893
  return [];
48118
- const content = fs13.readFileSync(ignorePath, "utf8");
48894
+ const content = fs14.readFileSync(ignorePath, "utf8");
48119
48895
  const patterns = [];
48120
48896
  for (const rawLine of content.split(/\r?\n/)) {
48121
48897
  const line = rawLine.trim();
@@ -48134,7 +48910,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
48134
48910
  if (exactNames.has(entry))
48135
48911
  return true;
48136
48912
  for (const pattern of globPatterns) {
48137
- if (path33.matchesGlob(relPath, pattern))
48913
+ if (path35.matchesGlob(relPath, pattern))
48138
48914
  return true;
48139
48915
  }
48140
48916
  return false;
@@ -48155,7 +48931,7 @@ function validateDirectoryInput(dir) {
48155
48931
  return null;
48156
48932
  }
48157
48933
  function isBinaryFile(filePath, buffer) {
48158
- const ext = path33.extname(filePath).toLowerCase();
48934
+ const ext = path35.extname(filePath).toLowerCase();
48159
48935
  if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
48160
48936
  return true;
48161
48937
  }
@@ -48233,7 +49009,7 @@ function createRedactedContext(line, findings) {
48233
49009
  function scanFileForSecrets(filePath) {
48234
49010
  const findings = [];
48235
49011
  try {
48236
- const lstat = fs13.lstatSync(filePath);
49012
+ const lstat = fs14.lstatSync(filePath);
48237
49013
  if (lstat.isSymbolicLink()) {
48238
49014
  return findings;
48239
49015
  }
@@ -48242,14 +49018,14 @@ function scanFileForSecrets(filePath) {
48242
49018
  }
48243
49019
  let buffer;
48244
49020
  if (O_NOFOLLOW !== undefined) {
48245
- const fd = fs13.openSync(filePath, "r", O_NOFOLLOW);
49021
+ const fd = fs14.openSync(filePath, "r", O_NOFOLLOW);
48246
49022
  try {
48247
- buffer = fs13.readFileSync(fd);
49023
+ buffer = fs14.readFileSync(fd);
48248
49024
  } finally {
48249
- fs13.closeSync(fd);
49025
+ fs14.closeSync(fd);
48250
49026
  }
48251
49027
  } else {
48252
- buffer = fs13.readFileSync(filePath);
49028
+ buffer = fs14.readFileSync(filePath);
48253
49029
  }
48254
49030
  if (isBinaryFile(filePath, buffer)) {
48255
49031
  return findings;
@@ -48291,9 +49067,9 @@ function isSymlinkLoop(realPath, visited) {
48291
49067
  return false;
48292
49068
  }
48293
49069
  function isPathWithinScope(realPath, scanDir) {
48294
- const resolvedScanDir = path33.resolve(scanDir);
48295
- const resolvedRealPath = path33.resolve(realPath);
48296
- return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path33.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
49070
+ const resolvedScanDir = path35.resolve(scanDir);
49071
+ const resolvedRealPath = path35.resolve(realPath);
49072
+ return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path35.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
48297
49073
  }
48298
49074
  function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
48299
49075
  skippedDirs: 0,
@@ -48304,7 +49080,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
48304
49080
  const files = [];
48305
49081
  let entries;
48306
49082
  try {
48307
- entries = fs13.readdirSync(dir);
49083
+ entries = fs14.readdirSync(dir);
48308
49084
  } catch {
48309
49085
  stats.fileErrors++;
48310
49086
  return files;
@@ -48319,15 +49095,15 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
48319
49095
  return a.localeCompare(b);
48320
49096
  });
48321
49097
  for (const entry of entries) {
48322
- const fullPath = path33.join(dir, entry);
48323
- const relPath = path33.relative(scanDir, fullPath).replace(/\\/g, "/");
49098
+ const fullPath = path35.join(dir, entry);
49099
+ const relPath = path35.relative(scanDir, fullPath).replace(/\\/g, "/");
48324
49100
  if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
48325
49101
  stats.skippedDirs++;
48326
49102
  continue;
48327
49103
  }
48328
49104
  let lstat;
48329
49105
  try {
48330
- lstat = fs13.lstatSync(fullPath);
49106
+ lstat = fs14.lstatSync(fullPath);
48331
49107
  } catch {
48332
49108
  stats.fileErrors++;
48333
49109
  continue;
@@ -48339,7 +49115,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
48339
49115
  if (lstat.isDirectory()) {
48340
49116
  let realPath;
48341
49117
  try {
48342
- realPath = fs13.realpathSync(fullPath);
49118
+ realPath = fs14.realpathSync(fullPath);
48343
49119
  } catch {
48344
49120
  stats.fileErrors++;
48345
49121
  continue;
@@ -48355,7 +49131,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
48355
49131
  const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
48356
49132
  files.push(...subFiles);
48357
49133
  } else if (lstat.isFile()) {
48358
- const ext = path33.extname(fullPath).toLowerCase();
49134
+ const ext = path35.extname(fullPath).toLowerCase();
48359
49135
  if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
48360
49136
  files.push(fullPath);
48361
49137
  } else {
@@ -48558,7 +49334,7 @@ var init_secretscan = __esm(() => {
48558
49334
  redactTemplate: () => "SK[REDACTED]"
48559
49335
  }
48560
49336
  ];
48561
- O_NOFOLLOW = process.platform !== "win32" ? fs13.constants.O_NOFOLLOW : undefined;
49337
+ O_NOFOLLOW = process.platform !== "win32" ? fs14.constants.O_NOFOLLOW : undefined;
48562
49338
  secretscan = createSwarmTool({
48563
49339
  description: "Scan directory for potential secrets (API keys, tokens, passwords) using regex patterns and entropy heuristics. Returns metadata-only findings with redacted previews - NEVER returns raw secrets. Excludes common directories (node_modules, .git, dist, etc.) by default. Supports glob patterns (e.g. **/.svelte-kit/**, **/*.test.ts) and reads .secretscanignore at the scan root.",
48564
49340
  args: {
@@ -48615,15 +49391,15 @@ var init_secretscan = __esm(() => {
48615
49391
  }
48616
49392
  }
48617
49393
  try {
48618
- const _scanDirRaw = path33.resolve(directory);
49394
+ const _scanDirRaw = path35.resolve(directory);
48619
49395
  const scanDir = (() => {
48620
49396
  try {
48621
- return fs13.realpathSync(_scanDirRaw);
49397
+ return fs14.realpathSync(_scanDirRaw);
48622
49398
  } catch {
48623
49399
  return _scanDirRaw;
48624
49400
  }
48625
49401
  })();
48626
- if (!fs13.existsSync(scanDir)) {
49402
+ if (!fs14.existsSync(scanDir)) {
48627
49403
  const errorResult = {
48628
49404
  error: "directory not found",
48629
49405
  scan_dir: directory,
@@ -48634,7 +49410,7 @@ var init_secretscan = __esm(() => {
48634
49410
  };
48635
49411
  return JSON.stringify(errorResult, null, 2);
48636
49412
  }
48637
- const dirStat = fs13.statSync(scanDir);
49413
+ const dirStat = fs14.statSync(scanDir);
48638
49414
  if (!dirStat.isDirectory()) {
48639
49415
  const errorResult = {
48640
49416
  error: "target must be a directory, not a file",
@@ -48685,7 +49461,7 @@ var init_secretscan = __esm(() => {
48685
49461
  break;
48686
49462
  const fileFindings = scanFileForSecrets(filePath);
48687
49463
  try {
48688
- const stat4 = fs13.statSync(filePath);
49464
+ const stat4 = fs14.statSync(filePath);
48689
49465
  if (stat4.size > MAX_FILE_SIZE_BYTES) {
48690
49466
  skippedFiles++;
48691
49467
  continue;
@@ -48761,12 +49537,12 @@ var init_secretscan = __esm(() => {
48761
49537
  });
48762
49538
 
48763
49539
  // src/lang/default-backend.ts
48764
- import * as fs14 from "fs";
48765
- import * as path34 from "path";
49540
+ import * as fs15 from "fs";
49541
+ import * as path36 from "path";
48766
49542
  function detectFileExists(dir, pattern) {
48767
49543
  if (pattern.includes("*") || pattern.includes("?")) {
48768
49544
  try {
48769
- const files = fs14.readdirSync(dir);
49545
+ const files = fs15.readdirSync(dir);
48770
49546
  const regex = new RegExp(`^${pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
48771
49547
  return files.some((f) => regex.test(f));
48772
49548
  } catch {
@@ -48774,7 +49550,7 @@ function detectFileExists(dir, pattern) {
48774
49550
  }
48775
49551
  }
48776
49552
  try {
48777
- fs14.accessSync(path34.join(dir, pattern));
49553
+ fs15.accessSync(path36.join(dir, pattern));
48778
49554
  return true;
48779
49555
  } catch {
48780
49556
  return false;
@@ -48902,8 +49678,8 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
48902
49678
  return ["mvn", "test"];
48903
49679
  case "gradle": {
48904
49680
  const isWindows = process.platform === "win32";
48905
- const hasGradlewBat = fs14.existsSync(path34.join(dir, "gradlew.bat"));
48906
- const hasGradlew = fs14.existsSync(path34.join(dir, "gradlew"));
49681
+ const hasGradlewBat = fs15.existsSync(path36.join(dir, "gradlew.bat"));
49682
+ const hasGradlew = fs15.existsSync(path36.join(dir, "gradlew"));
48907
49683
  if (hasGradlewBat && isWindows)
48908
49684
  return ["gradlew.bat", "test"];
48909
49685
  if (hasGradlew)
@@ -48920,7 +49696,7 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
48920
49696
  "cmake-build-release",
48921
49697
  "out"
48922
49698
  ];
48923
- const actualBuildDir = buildDirCandidates.find((d) => fs14.existsSync(path34.join(dir, d, "CMakeCache.txt"))) ?? "build";
49699
+ const actualBuildDir = buildDirCandidates.find((d) => fs15.existsSync(path36.join(dir, d, "CMakeCache.txt"))) ?? "build";
48924
49700
  return ["ctest", "--test-dir", actualBuildDir];
48925
49701
  }
48926
49702
  case "swift-test":
@@ -49207,23 +49983,23 @@ async function defaultSelectBuildCommand(profile, dir) {
49207
49983
  return null;
49208
49984
  }
49209
49985
  async function defaultTestFilesFor(profile, sourceFile, dir) {
49210
- const ext = path34.extname(sourceFile);
49986
+ const ext = path36.extname(sourceFile);
49211
49987
  if (!profile.extensions.includes(ext))
49212
49988
  return [];
49213
- const base = path34.basename(sourceFile, ext);
49214
- const rel = path34.relative(dir, sourceFile);
49215
- const relDir = path34.dirname(rel);
49989
+ const base = path36.basename(sourceFile, ext);
49990
+ const rel = path36.relative(dir, sourceFile);
49991
+ const relDir = path36.dirname(rel);
49216
49992
  const stripSrc = relDir.replace(/^src(\/|\\)/, "");
49217
49993
  const candidates = new Set;
49218
49994
  for (const tDir of ["tests", "test", "__tests__", "spec"]) {
49219
49995
  for (const suffix of ["", "_test", ".test", "_spec", ".spec"]) {
49220
- candidates.add(path34.join(dir, tDir, stripSrc, `${base}${suffix}${ext}`));
49996
+ candidates.add(path36.join(dir, tDir, stripSrc, `${base}${suffix}${ext}`));
49221
49997
  }
49222
49998
  }
49223
49999
  const existing = [];
49224
50000
  for (const c of candidates) {
49225
50001
  try {
49226
- fs14.accessSync(c);
50002
+ fs15.accessSync(c);
49227
50003
  existing.push(c);
49228
50004
  } catch {}
49229
50005
  }
@@ -49257,8 +50033,8 @@ var init_default_backend = __esm(() => {
49257
50033
  });
49258
50034
 
49259
50035
  // src/lang/backends/go.ts
49260
- import * as fs15 from "fs";
49261
- import * as path35 from "path";
50036
+ import * as fs16 from "fs";
50037
+ import * as path37 from "path";
49262
50038
  function extractImports(_sourceFile, source) {
49263
50039
  const out = new Set;
49264
50040
  IMPORT_REGEX_SINGLE.lastIndex = 0;
@@ -49284,7 +50060,7 @@ function extractImports(_sourceFile, source) {
49284
50060
  async function selectFramework(dir) {
49285
50061
  let content;
49286
50062
  try {
49287
- content = fs15.readFileSync(path35.join(dir, "go.mod"), "utf-8");
50063
+ content = fs16.readFileSync(path37.join(dir, "go.mod"), "utf-8");
49288
50064
  } catch {
49289
50065
  return null;
49290
50066
  }
@@ -49305,16 +50081,16 @@ async function selectFramework(dir) {
49305
50081
  async function selectEntryPoints(dir) {
49306
50082
  const points = [];
49307
50083
  try {
49308
- fs15.accessSync(path35.join(dir, "main.go"));
50084
+ fs16.accessSync(path37.join(dir, "main.go"));
49309
50085
  points.push("main.go");
49310
50086
  } catch {}
49311
50087
  try {
49312
- const cmdDir = path35.join(dir, "cmd");
49313
- const subdirs = fs15.readdirSync(cmdDir, { withFileTypes: true }).filter((d) => d.isDirectory());
50088
+ const cmdDir = path37.join(dir, "cmd");
50089
+ const subdirs = fs16.readdirSync(cmdDir, { withFileTypes: true }).filter((d) => d.isDirectory());
49314
50090
  for (const sub of subdirs) {
49315
- const main = path35.join("cmd", sub.name, "main.go");
50091
+ const main = path37.join("cmd", sub.name, "main.go");
49316
50092
  try {
49317
- fs15.accessSync(path35.join(dir, main));
50093
+ fs16.accessSync(path37.join(dir, main));
49318
50094
  points.push(main);
49319
50095
  } catch {}
49320
50096
  }
@@ -49344,8 +50120,8 @@ var init_go = __esm(() => {
49344
50120
  });
49345
50121
 
49346
50122
  // src/lang/backends/python.ts
49347
- import * as fs16 from "fs";
49348
- import * as path36 from "path";
50123
+ import * as fs17 from "fs";
50124
+ import * as path38 from "path";
49349
50125
  function parseImportTargets(rawTargets) {
49350
50126
  const cleaned = rawTargets.replace(/[()]/g, "").split(`
49351
50127
  `).map((line) => line.replace(/#.*$/, "").replace(/\\\s*$/, "")).join(" ");
@@ -49405,7 +50181,7 @@ async function selectFramework2(dir) {
49405
50181
  ];
49406
50182
  for (const candidate of ["pyproject.toml", "requirements.txt", "setup.py"]) {
49407
50183
  try {
49408
- const content = fs16.readFileSync(path36.join(dir, candidate), "utf-8");
50184
+ const content = fs17.readFileSync(path38.join(dir, candidate), "utf-8");
49409
50185
  const lower = content.toLowerCase();
49410
50186
  for (const [pkg, name] of candidates) {
49411
50187
  if (lower.includes(pkg)) {
@@ -49419,7 +50195,7 @@ async function selectFramework2(dir) {
49419
50195
  async function selectEntryPoints2(dir) {
49420
50196
  const points = new Set;
49421
50197
  try {
49422
- const content = fs16.readFileSync(path36.join(dir, "pyproject.toml"), "utf-8");
50198
+ const content = fs17.readFileSync(path38.join(dir, "pyproject.toml"), "utf-8");
49423
50199
  const scriptsBlock = content.match(/\[project\.scripts\][\s\S]*?(?=\n\[|$)/);
49424
50200
  if (scriptsBlock) {
49425
50201
  for (const line of scriptsBlock[0].split(`
@@ -49434,7 +50210,7 @@ async function selectEntryPoints2(dir) {
49434
50210
  } catch {}
49435
50211
  for (const name of ["manage.py", "main.py", "app.py", "__main__.py"]) {
49436
50212
  try {
49437
- fs16.accessSync(path36.join(dir, name));
50213
+ fs17.accessSync(path38.join(dir, name));
49438
50214
  points.add(name);
49439
50215
  } catch {}
49440
50216
  }
@@ -49462,15 +50238,15 @@ var init_python = __esm(() => {
49462
50238
  });
49463
50239
 
49464
50240
  // src/test-impact/analyzer.ts
49465
- import fs17 from "fs";
49466
- import path37 from "path";
50241
+ import fs18 from "fs";
50242
+ import path39 from "path";
49467
50243
  function normalizePath(p) {
49468
50244
  return p.replace(/\\/g, "/");
49469
50245
  }
49470
50246
  function isCacheStale(impactMap, generatedAtMs) {
49471
50247
  for (const sourcePath of Object.keys(impactMap)) {
49472
50248
  try {
49473
- const stat4 = fs17.statSync(sourcePath);
50249
+ const stat4 = fs18.statSync(sourcePath);
49474
50250
  if (stat4.mtimeMs > generatedAtMs) {
49475
50251
  return true;
49476
50252
  }
@@ -49484,15 +50260,15 @@ function resolveRelativeImport(fromDir, importPath) {
49484
50260
  if (!importPath.startsWith(".")) {
49485
50261
  return null;
49486
50262
  }
49487
- const resolved = path37.resolve(fromDir, importPath);
49488
- if (path37.extname(resolved)) {
49489
- if (fs17.existsSync(resolved) && fs17.statSync(resolved).isFile()) {
50263
+ const resolved = path39.resolve(fromDir, importPath);
50264
+ if (path39.extname(resolved)) {
50265
+ if (fs18.existsSync(resolved) && fs18.statSync(resolved).isFile()) {
49490
50266
  return normalizePath(resolved);
49491
50267
  }
49492
50268
  } else {
49493
50269
  for (const ext of EXTENSIONS_TO_TRY) {
49494
50270
  const withExt = resolved + ext;
49495
- if (fs17.existsSync(withExt) && fs17.statSync(withExt).isFile()) {
50271
+ if (fs18.existsSync(withExt) && fs18.statSync(withExt).isFile()) {
49496
50272
  return normalizePath(withExt);
49497
50273
  }
49498
50274
  }
@@ -49505,29 +50281,29 @@ function resolvePythonImport(fromDir, module) {
49505
50281
  const leadingDots = module.match(/^\.+/)?.[0].length ?? 0;
49506
50282
  let baseDir = fromDir;
49507
50283
  for (let i = 1;i < leadingDots; i++) {
49508
- baseDir = path37.dirname(baseDir);
50284
+ baseDir = path39.dirname(baseDir);
49509
50285
  }
49510
50286
  const rest = module.slice(leadingDots);
49511
50287
  if (rest.length === 0) {
49512
- const initPath = path37.join(baseDir, "__init__.py");
49513
- if (fs17.existsSync(initPath) && fs17.statSync(initPath).isFile()) {
50288
+ const initPath = path39.join(baseDir, "__init__.py");
50289
+ if (fs18.existsSync(initPath) && fs18.statSync(initPath).isFile()) {
49514
50290
  return normalizePath(initPath);
49515
50291
  }
49516
50292
  return null;
49517
50293
  }
49518
- const subpath = rest.replace(/\./g, path37.sep);
50294
+ const subpath = rest.replace(/\./g, path39.sep);
49519
50295
  const candidates = [
49520
- `${path37.join(baseDir, subpath)}.py`,
49521
- path37.join(baseDir, subpath, "__init__.py")
50296
+ `${path39.join(baseDir, subpath)}.py`,
50297
+ path39.join(baseDir, subpath, "__init__.py")
49522
50298
  ];
49523
50299
  for (const c of candidates) {
49524
- if (fs17.existsSync(c) && fs17.statSync(c).isFile())
50300
+ if (fs18.existsSync(c) && fs18.statSync(c).isFile())
49525
50301
  return normalizePath(c);
49526
50302
  }
49527
50303
  return null;
49528
50304
  }
49529
50305
  function findGoModule(fromDir) {
49530
- const resolved = path37.resolve(fromDir);
50306
+ const resolved = path39.resolve(fromDir);
49531
50307
  let cur = resolved;
49532
50308
  const walked = [];
49533
50309
  for (let i = 0;i < 16; i++) {
@@ -49539,8 +50315,8 @@ function findGoModule(fromDir) {
49539
50315
  }
49540
50316
  walked.push(cur);
49541
50317
  try {
49542
- const goMod = path37.join(cur, "go.mod");
49543
- const content = fs17.readFileSync(goMod, "utf-8");
50318
+ const goMod = path39.join(cur, "go.mod");
50319
+ const content = fs18.readFileSync(goMod, "utf-8");
49544
50320
  const moduleMatch = content.match(/^\s*module\s+"?([^"\s/]+(?:\/[^"\s]+)*)"?/m);
49545
50321
  if (moduleMatch) {
49546
50322
  const result = { moduleRoot: cur, modulePath: moduleMatch[1] };
@@ -49550,10 +50326,10 @@ function findGoModule(fromDir) {
49550
50326
  }
49551
50327
  } catch {}
49552
50328
  try {
49553
- fs17.accessSync(path37.join(cur, ".git"));
50329
+ fs18.accessSync(path39.join(cur, ".git"));
49554
50330
  break;
49555
50331
  } catch {}
49556
- const parent = path37.dirname(cur);
50332
+ const parent = path39.dirname(cur);
49557
50333
  if (parent === cur)
49558
50334
  break;
49559
50335
  cur = parent;
@@ -49565,20 +50341,20 @@ function findGoModule(fromDir) {
49565
50341
  function resolveGoImport(fromDir, importPath) {
49566
50342
  let dir = null;
49567
50343
  if (importPath.startsWith(".")) {
49568
- dir = path37.resolve(fromDir, importPath);
50344
+ dir = path39.resolve(fromDir, importPath);
49569
50345
  } else {
49570
50346
  const mod = findGoModule(fromDir);
49571
50347
  if (mod && (importPath === mod.modulePath || importPath.startsWith(`${mod.modulePath}/`))) {
49572
50348
  const subpath = importPath.slice(mod.modulePath.length);
49573
- dir = path37.join(mod.moduleRoot, subpath);
50349
+ dir = path39.join(mod.moduleRoot, subpath);
49574
50350
  }
49575
50351
  }
49576
50352
  if (dir === null)
49577
50353
  return [];
49578
- if (!fs17.existsSync(dir) || !fs17.statSync(dir).isDirectory())
50354
+ if (!fs18.existsSync(dir) || !fs18.statSync(dir).isDirectory())
49579
50355
  return [];
49580
50356
  try {
49581
- return fs17.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath(path37.join(dir, f)));
50357
+ return fs18.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath(path39.join(dir, f)));
49582
50358
  } catch {
49583
50359
  return [];
49584
50360
  }
@@ -49598,13 +50374,13 @@ function findTestFilesSync(cwd) {
49598
50374
  function walk(dir, visitedInodes) {
49599
50375
  let entries;
49600
50376
  try {
49601
- entries = fs17.readdirSync(dir, { withFileTypes: true });
50377
+ entries = fs18.readdirSync(dir, { withFileTypes: true });
49602
50378
  } catch {
49603
50379
  return;
49604
50380
  }
49605
50381
  let dirInode;
49606
50382
  try {
49607
- dirInode = fs17.statSync(dir).ino;
50383
+ dirInode = fs18.statSync(dir).ino;
49608
50384
  } catch {
49609
50385
  return;
49610
50386
  }
@@ -49617,15 +50393,15 @@ function findTestFilesSync(cwd) {
49617
50393
  for (const entry of entries) {
49618
50394
  if (entry.isDirectory()) {
49619
50395
  if (!skipDirs.has(entry.name)) {
49620
- walk(path37.join(dir, entry.name), visitedInodes);
50396
+ walk(path39.join(dir, entry.name), visitedInodes);
49621
50397
  }
49622
50398
  } else if (entry.isFile()) {
49623
50399
  const name = entry.name;
49624
50400
  const isTsTest = /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name);
49625
- const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path37.sep}tests${path37.sep}`) && name.endsWith(".py");
50401
+ const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path39.sep}tests${path39.sep}`) && name.endsWith(".py");
49626
50402
  const isGoTest = /.+_test\.go$/.test(name);
49627
50403
  if (isTsTest || isPyTest || isGoTest) {
49628
- testFiles.push(normalizePath(path37.join(dir, entry.name)));
50404
+ testFiles.push(normalizePath(path39.join(dir, entry.name)));
49629
50405
  }
49630
50406
  }
49631
50407
  }
@@ -49650,8 +50426,8 @@ function extractImports3(content) {
49650
50426
  ];
49651
50427
  }
49652
50428
  function addImpactEdgesForTestFile(testFile, content, impactMap) {
49653
- const ext = path37.extname(testFile).toLowerCase();
49654
- const testDir = path37.dirname(testFile);
50429
+ const ext = path39.extname(testFile).toLowerCase();
50430
+ const testDir = path39.dirname(testFile);
49655
50431
  function addEdge(source) {
49656
50432
  if (!impactMap[source])
49657
50433
  impactMap[source] = [];
@@ -49693,7 +50469,7 @@ async function buildImpactMapInternal(cwd) {
49693
50469
  for (const testFile of testFiles) {
49694
50470
  let content;
49695
50471
  try {
49696
- content = fs17.readFileSync(testFile, "utf-8");
50472
+ content = fs18.readFileSync(testFile, "utf-8");
49697
50473
  } catch {
49698
50474
  continue;
49699
50475
  }
@@ -49710,10 +50486,10 @@ async function buildImpactMap(cwd) {
49710
50486
  return impactMap;
49711
50487
  }
49712
50488
  async function loadImpactMap(cwd, options) {
49713
- const cachePath = path37.join(cwd, ".swarm", "cache", "impact-map.json");
49714
- if (fs17.existsSync(cachePath)) {
50489
+ const cachePath = path39.join(cwd, ".swarm", "cache", "impact-map.json");
50490
+ if (fs18.existsSync(cachePath)) {
49715
50491
  try {
49716
- const content = fs17.readFileSync(cachePath, "utf-8");
50492
+ const content = fs18.readFileSync(cachePath, "utf-8");
49717
50493
  const data = JSON.parse(content);
49718
50494
  if (data.map !== null && typeof data.map === "object" && !Array.isArray(data.map)) {
49719
50495
  const map3 = data.map;
@@ -49743,21 +50519,21 @@ async function loadImpactMap(cwd, options) {
49743
50519
  return _internals23.buildImpactMap(cwd);
49744
50520
  }
49745
50521
  async function saveImpactMap(cwd, impactMap) {
49746
- if (!path37.isAbsolute(cwd)) {
50522
+ if (!path39.isAbsolute(cwd)) {
49747
50523
  throw new Error(`saveImpactMap requires an absolute project root path, got: "${cwd}"`);
49748
50524
  }
49749
50525
  _internals23.validateProjectRoot(cwd);
49750
- const cacheDir2 = path37.join(cwd, ".swarm", "cache");
49751
- const cachePath = path37.join(cacheDir2, "impact-map.json");
49752
- if (!fs17.existsSync(cacheDir2)) {
49753
- fs17.mkdirSync(cacheDir2, { recursive: true });
50526
+ const cacheDir2 = path39.join(cwd, ".swarm", "cache");
50527
+ const cachePath = path39.join(cacheDir2, "impact-map.json");
50528
+ if (!fs18.existsSync(cacheDir2)) {
50529
+ fs18.mkdirSync(cacheDir2, { recursive: true });
49754
50530
  }
49755
50531
  const data = {
49756
50532
  generatedAt: new Date().toISOString(),
49757
50533
  fileCount: Object.keys(impactMap).length,
49758
50534
  map: impactMap
49759
50535
  };
49760
- fs17.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
50536
+ fs18.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
49761
50537
  }
49762
50538
  async function analyzeImpact(changedFiles, cwd, budget) {
49763
50539
  if (!Array.isArray(changedFiles)) {
@@ -49780,7 +50556,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
49780
50556
  budgetExceeded = true;
49781
50557
  break;
49782
50558
  }
49783
- const normalizedChanged = normalizePath(path37.resolve(changedFile));
50559
+ const normalizedChanged = normalizePath(path39.resolve(changedFile));
49784
50560
  const tests = impactMap[normalizedChanged];
49785
50561
  if (tests && tests.length > 0) {
49786
50562
  for (const test of tests) {
@@ -50072,16 +50848,16 @@ function detectFlakyTests(allHistory) {
50072
50848
  var FLAKY_THRESHOLD = 0.3, MIN_RUNS_FOR_QUARANTINE = 5, MAX_HISTORY_RUNS = 20;
50073
50849
 
50074
50850
  // src/test-impact/history-store.ts
50075
- import fs18 from "fs";
50076
- import path38 from "path";
50851
+ import fs19 from "fs";
50852
+ import path40 from "path";
50077
50853
  function getHistoryPath(workingDir) {
50078
50854
  if (!workingDir) {
50079
50855
  throw new Error("getHistoryPath requires a working directory \u2014 project root must be provided by the caller");
50080
50856
  }
50081
- if (!path38.isAbsolute(workingDir)) {
50857
+ if (!path40.isAbsolute(workingDir)) {
50082
50858
  throw new Error(`getHistoryPath requires an absolute project root path, got: "${workingDir}"`);
50083
50859
  }
50084
- return path38.join(workingDir, ".swarm", "cache", "test-history.jsonl");
50860
+ return path40.join(workingDir, ".swarm", "cache", "test-history.jsonl");
50085
50861
  }
50086
50862
  function sanitizeErrorMessage(errorMessage) {
50087
50863
  if (errorMessage === undefined) {
@@ -50168,10 +50944,10 @@ function batchAppendTestRuns(records, workingDir) {
50168
50944
  }
50169
50945
  }
50170
50946
  const historyPath = getHistoryPath(workingDir);
50171
- const historyDir = path38.dirname(historyPath);
50947
+ const historyDir = path40.dirname(historyPath);
50172
50948
  _internals24.validateProjectRoot(workingDir);
50173
- if (!fs18.existsSync(historyDir)) {
50174
- fs18.mkdirSync(historyDir, { recursive: true });
50949
+ if (!fs19.existsSync(historyDir)) {
50950
+ fs19.mkdirSync(historyDir, { recursive: true });
50175
50951
  }
50176
50952
  const existingRecords = readAllRecords(historyPath);
50177
50953
  const sanitizedRecords = records.map((record3) => ({
@@ -50204,24 +50980,24 @@ function batchAppendTestRuns(records, workingDir) {
50204
50980
  `)}
50205
50981
  `;
50206
50982
  const tempPath = `${historyPath}.tmp`;
50207
- fs18.writeFileSync(tempPath, content, "utf-8");
50208
- fs18.renameSync(tempPath, historyPath);
50983
+ fs19.writeFileSync(tempPath, content, "utf-8");
50984
+ fs19.renameSync(tempPath, historyPath);
50209
50985
  } catch (err) {
50210
50986
  try {
50211
50987
  const tempPath = `${historyPath}.tmp`;
50212
- if (fs18.existsSync(tempPath)) {
50213
- fs18.unlinkSync(tempPath);
50988
+ if (fs19.existsSync(tempPath)) {
50989
+ fs19.unlinkSync(tempPath);
50214
50990
  }
50215
50991
  } catch {}
50216
50992
  throw new Error(`Failed to write test history: ${err instanceof Error ? err.message : String(err)}`);
50217
50993
  }
50218
50994
  }
50219
50995
  function readAllRecords(historyPath) {
50220
- if (!fs18.existsSync(historyPath)) {
50996
+ if (!fs19.existsSync(historyPath)) {
50221
50997
  return [];
50222
50998
  }
50223
50999
  try {
50224
- const content = fs18.readFileSync(historyPath, "utf-8");
51000
+ const content = fs19.readFileSync(historyPath, "utf-8");
50225
51001
  const lines = content.split(`
50226
51002
  `);
50227
51003
  const records = [];
@@ -50263,8 +51039,8 @@ var init_history_store = __esm(() => {
50263
51039
  });
50264
51040
 
50265
51041
  // src/tools/resolve-working-directory.ts
50266
- import * as fs19 from "fs";
50267
- import * as path39 from "path";
51042
+ import * as fs20 from "fs";
51043
+ import * as path41 from "path";
50268
51044
  function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
50269
51045
  if (workingDirectory == null || workingDirectory === "") {
50270
51046
  return { success: true, directory: fallbackDirectory };
@@ -50284,18 +51060,18 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
50284
51060
  };
50285
51061
  }
50286
51062
  }
50287
- const normalizedDir = path39.normalize(workingDirectory);
50288
- const pathParts = normalizedDir.split(path39.sep);
51063
+ const normalizedDir = path41.normalize(workingDirectory);
51064
+ const pathParts = normalizedDir.split(path41.sep);
50289
51065
  if (pathParts.includes("..")) {
50290
51066
  return {
50291
51067
  success: false,
50292
51068
  message: "Invalid working_directory: path traversal sequences (..) are not allowed"
50293
51069
  };
50294
51070
  }
50295
- const resolvedDir = path39.resolve(normalizedDir);
51071
+ const resolvedDir = path41.resolve(normalizedDir);
50296
51072
  let statResult;
50297
51073
  try {
50298
- statResult = fs19.statSync(resolvedDir);
51074
+ statResult = fs20.statSync(resolvedDir);
50299
51075
  } catch {
50300
51076
  return {
50301
51077
  success: false,
@@ -50308,17 +51084,17 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
50308
51084
  message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
50309
51085
  };
50310
51086
  }
50311
- const resolvedFallback = path39.resolve(fallbackDirectory);
51087
+ const resolvedFallback = path41.resolve(fallbackDirectory);
50312
51088
  let fallbackExists = false;
50313
51089
  try {
50314
- fs19.statSync(resolvedFallback);
51090
+ fs20.statSync(resolvedFallback);
50315
51091
  fallbackExists = true;
50316
51092
  } catch {
50317
51093
  fallbackExists = false;
50318
51094
  }
50319
51095
  if (workingDirectory != null && workingDirectory !== "") {
50320
51096
  if (fallbackExists) {
50321
- const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path39.sep);
51097
+ const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path41.sep);
50322
51098
  if (isSubdirectory) {
50323
51099
  return {
50324
51100
  success: false,
@@ -50372,11 +51148,11 @@ var init_registry_backend = __esm(() => {
50372
51148
  });
50373
51149
 
50374
51150
  // src/lang/backends/typescript.ts
50375
- import * as fs20 from "fs";
50376
- import * as path40 from "path";
51151
+ import * as fs21 from "fs";
51152
+ import * as path42 from "path";
50377
51153
  function readPackageJsonRaw(dir) {
50378
51154
  try {
50379
- const content = fs20.readFileSync(path40.join(dir, "package.json"), "utf-8");
51155
+ const content = fs21.readFileSync(path42.join(dir, "package.json"), "utf-8");
50380
51156
  return JSON.parse(content);
50381
51157
  } catch {
50382
51158
  return null;
@@ -50595,11 +51371,11 @@ __export(exports_dispatch, {
50595
51371
  clearDispatchCache: () => clearDispatchCache,
50596
51372
  _internals: () => _internals26
50597
51373
  });
50598
- import * as fs21 from "fs";
50599
- import * as path41 from "path";
51374
+ import * as fs22 from "fs";
51375
+ import * as path43 from "path";
50600
51376
  function safeReaddirSet(dir) {
50601
51377
  try {
50602
- return new Set(fs21.readdirSync(dir));
51378
+ return new Set(fs22.readdirSync(dir));
50603
51379
  } catch {
50604
51380
  return new Set;
50605
51381
  }
@@ -50613,14 +51389,14 @@ function manifestHash(dir) {
50613
51389
  if (!entries.has(name))
50614
51390
  continue;
50615
51391
  try {
50616
- const stat4 = fs21.statSync(path41.join(dir, name));
51392
+ const stat4 = fs22.statSync(path43.join(dir, name));
50617
51393
  parts.push(`${name}:${stat4.size}:${stat4.mtimeMs}:${stat4.ino}`);
50618
51394
  } catch {}
50619
51395
  }
50620
51396
  return parts.join("|");
50621
51397
  }
50622
51398
  function findManifestRoot(start) {
50623
- const resolved = path41.resolve(start);
51399
+ const resolved = path43.resolve(start);
50624
51400
  const cached3 = manifestRootCache.get(resolved);
50625
51401
  if (cached3 !== undefined)
50626
51402
  return cached3;
@@ -50639,7 +51415,7 @@ function findManifestRoot(start) {
50639
51415
  return cur;
50640
51416
  }
50641
51417
  }
50642
- const parent = path41.dirname(cur);
51418
+ const parent = path43.dirname(cur);
50643
51419
  if (parent === cur)
50644
51420
  break;
50645
51421
  cur = parent;
@@ -50748,14 +51524,14 @@ var init_dispatch = __esm(() => {
50748
51524
  });
50749
51525
 
50750
51526
  // src/tools/test-runner.ts
50751
- import * as fs22 from "fs";
50752
- import * as path42 from "path";
51527
+ import * as fs23 from "fs";
51528
+ import * as path44 from "path";
50753
51529
  async function estimateFanOut(sourceFiles, cwd) {
50754
51530
  try {
50755
51531
  const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
50756
51532
  const uniqueTestFiles = new Set;
50757
51533
  for (const sourceFile of sourceFiles) {
50758
- const resolvedPath = path42.resolve(cwd, sourceFile);
51534
+ const resolvedPath = path44.resolve(cwd, sourceFile);
50759
51535
  const normalizedPath = resolvedPath.replace(/\\/g, "/");
50760
51536
  const testFiles = impactMap[normalizedPath];
50761
51537
  if (testFiles) {
@@ -50833,19 +51609,19 @@ function hasDevDependency(devDeps, ...patterns) {
50833
51609
  return hasPackageJsonDependency(devDeps, ...patterns);
50834
51610
  }
50835
51611
  function detectGoTest(cwd) {
50836
- return fs22.existsSync(path42.join(cwd, "go.mod")) && isCommandAvailable("go");
51612
+ return fs23.existsSync(path44.join(cwd, "go.mod")) && isCommandAvailable("go");
50837
51613
  }
50838
51614
  function detectJavaMaven(cwd) {
50839
- return fs22.existsSync(path42.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
51615
+ return fs23.existsSync(path44.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
50840
51616
  }
50841
51617
  function detectGradle(cwd) {
50842
- const hasBuildFile = fs22.existsSync(path42.join(cwd, "build.gradle")) || fs22.existsSync(path42.join(cwd, "build.gradle.kts"));
50843
- const hasGradlew = fs22.existsSync(path42.join(cwd, "gradlew")) || fs22.existsSync(path42.join(cwd, "gradlew.bat"));
51618
+ const hasBuildFile = fs23.existsSync(path44.join(cwd, "build.gradle")) || fs23.existsSync(path44.join(cwd, "build.gradle.kts"));
51619
+ const hasGradlew = fs23.existsSync(path44.join(cwd, "gradlew")) || fs23.existsSync(path44.join(cwd, "gradlew.bat"));
50844
51620
  return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
50845
51621
  }
50846
51622
  function detectDotnetTest(cwd) {
50847
51623
  try {
50848
- const files = fs22.readdirSync(cwd);
51624
+ const files = fs23.readdirSync(cwd);
50849
51625
  const hasCsproj = files.some((f) => f.endsWith(".csproj"));
50850
51626
  return hasCsproj && isCommandAvailable("dotnet");
50851
51627
  } catch {
@@ -50853,25 +51629,25 @@ function detectDotnetTest(cwd) {
50853
51629
  }
50854
51630
  }
50855
51631
  function detectCTest(cwd) {
50856
- const hasSource = fs22.existsSync(path42.join(cwd, "CMakeLists.txt"));
50857
- const hasBuildCache = fs22.existsSync(path42.join(cwd, "CMakeCache.txt")) || fs22.existsSync(path42.join(cwd, "build", "CMakeCache.txt"));
51632
+ const hasSource = fs23.existsSync(path44.join(cwd, "CMakeLists.txt"));
51633
+ const hasBuildCache = fs23.existsSync(path44.join(cwd, "CMakeCache.txt")) || fs23.existsSync(path44.join(cwd, "build", "CMakeCache.txt"));
50858
51634
  return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
50859
51635
  }
50860
51636
  function detectSwiftTest(cwd) {
50861
- return fs22.existsSync(path42.join(cwd, "Package.swift")) && isCommandAvailable("swift");
51637
+ return fs23.existsSync(path44.join(cwd, "Package.swift")) && isCommandAvailable("swift");
50862
51638
  }
50863
51639
  function detectDartTest(cwd) {
50864
- return fs22.existsSync(path42.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
51640
+ return fs23.existsSync(path44.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
50865
51641
  }
50866
51642
  function detectRSpec(cwd) {
50867
- const hasRSpecFile = fs22.existsSync(path42.join(cwd, ".rspec"));
50868
- const hasGemfile = fs22.existsSync(path42.join(cwd, "Gemfile"));
50869
- const hasSpecDir = fs22.existsSync(path42.join(cwd, "spec"));
51643
+ const hasRSpecFile = fs23.existsSync(path44.join(cwd, ".rspec"));
51644
+ const hasGemfile = fs23.existsSync(path44.join(cwd, "Gemfile"));
51645
+ const hasSpecDir = fs23.existsSync(path44.join(cwd, "spec"));
50870
51646
  const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
50871
51647
  return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
50872
51648
  }
50873
51649
  function detectMinitest(cwd) {
50874
- return fs22.existsSync(path42.join(cwd, "test")) && (fs22.existsSync(path42.join(cwd, "Gemfile")) || fs22.existsSync(path42.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
51650
+ return fs23.existsSync(path44.join(cwd, "test")) && (fs23.existsSync(path44.join(cwd, "Gemfile")) || fs23.existsSync(path44.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
50875
51651
  }
50876
51652
  async function detectTestFrameworkViaDispatch(cwd) {
50877
51653
  try {
@@ -50933,9 +51709,9 @@ async function parseTestOutputViaDispatch(framework, output, baseDir) {
50933
51709
  async function detectTestFramework(cwd) {
50934
51710
  const baseDir = cwd;
50935
51711
  try {
50936
- const packageJsonPath = path42.join(baseDir, "package.json");
50937
- if (fs22.existsSync(packageJsonPath)) {
50938
- const content = fs22.readFileSync(packageJsonPath, "utf-8");
51712
+ const packageJsonPath = path44.join(baseDir, "package.json");
51713
+ if (fs23.existsSync(packageJsonPath)) {
51714
+ const content = fs23.readFileSync(packageJsonPath, "utf-8");
50939
51715
  const pkg = JSON.parse(content);
50940
51716
  const _deps = pkg.dependencies || {};
50941
51717
  const devDeps = pkg.devDependencies || {};
@@ -50954,38 +51730,38 @@ async function detectTestFramework(cwd) {
50954
51730
  return "jest";
50955
51731
  if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
50956
51732
  return "mocha";
50957
- if (fs22.existsSync(path42.join(baseDir, "bun.lockb")) || fs22.existsSync(path42.join(baseDir, "bun.lock"))) {
51733
+ if (fs23.existsSync(path44.join(baseDir, "bun.lockb")) || fs23.existsSync(path44.join(baseDir, "bun.lock"))) {
50958
51734
  if (scripts.test?.includes("bun"))
50959
51735
  return "bun";
50960
51736
  }
50961
51737
  }
50962
51738
  } catch {}
50963
51739
  try {
50964
- const pyprojectTomlPath = path42.join(baseDir, "pyproject.toml");
50965
- const setupCfgPath = path42.join(baseDir, "setup.cfg");
50966
- const requirementsTxtPath = path42.join(baseDir, "requirements.txt");
50967
- if (fs22.existsSync(pyprojectTomlPath)) {
50968
- const content = fs22.readFileSync(pyprojectTomlPath, "utf-8");
51740
+ const pyprojectTomlPath = path44.join(baseDir, "pyproject.toml");
51741
+ const setupCfgPath = path44.join(baseDir, "setup.cfg");
51742
+ const requirementsTxtPath = path44.join(baseDir, "requirements.txt");
51743
+ if (fs23.existsSync(pyprojectTomlPath)) {
51744
+ const content = fs23.readFileSync(pyprojectTomlPath, "utf-8");
50969
51745
  if (content.includes("[tool.pytest"))
50970
51746
  return "pytest";
50971
51747
  if (content.includes("pytest"))
50972
51748
  return "pytest";
50973
51749
  }
50974
- if (fs22.existsSync(setupCfgPath)) {
50975
- const content = fs22.readFileSync(setupCfgPath, "utf-8");
51750
+ if (fs23.existsSync(setupCfgPath)) {
51751
+ const content = fs23.readFileSync(setupCfgPath, "utf-8");
50976
51752
  if (content.includes("[pytest]"))
50977
51753
  return "pytest";
50978
51754
  }
50979
- if (fs22.existsSync(requirementsTxtPath)) {
50980
- const content = fs22.readFileSync(requirementsTxtPath, "utf-8");
51755
+ if (fs23.existsSync(requirementsTxtPath)) {
51756
+ const content = fs23.readFileSync(requirementsTxtPath, "utf-8");
50981
51757
  if (content.includes("pytest"))
50982
51758
  return "pytest";
50983
51759
  }
50984
51760
  } catch {}
50985
51761
  try {
50986
- const cargoTomlPath = path42.join(baseDir, "Cargo.toml");
50987
- if (fs22.existsSync(cargoTomlPath)) {
50988
- const content = fs22.readFileSync(cargoTomlPath, "utf-8");
51762
+ const cargoTomlPath = path44.join(baseDir, "Cargo.toml");
51763
+ if (fs23.existsSync(cargoTomlPath)) {
51764
+ const content = fs23.readFileSync(cargoTomlPath, "utf-8");
50989
51765
  if (content.includes("[dev-dependencies]")) {
50990
51766
  if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
50991
51767
  return "cargo";
@@ -50994,10 +51770,10 @@ async function detectTestFramework(cwd) {
50994
51770
  }
50995
51771
  } catch {}
50996
51772
  try {
50997
- const pesterConfigPath = path42.join(baseDir, "pester.config.ps1");
50998
- const pesterConfigJsonPath = path42.join(baseDir, "pester.config.ps1.json");
50999
- const pesterPs1Path = path42.join(baseDir, "tests.ps1");
51000
- if (fs22.existsSync(pesterConfigPath) || fs22.existsSync(pesterConfigJsonPath) || fs22.existsSync(pesterPs1Path)) {
51773
+ const pesterConfigPath = path44.join(baseDir, "pester.config.ps1");
51774
+ const pesterConfigJsonPath = path44.join(baseDir, "pester.config.ps1.json");
51775
+ const pesterPs1Path = path44.join(baseDir, "tests.ps1");
51776
+ if (fs23.existsSync(pesterConfigPath) || fs23.existsSync(pesterConfigJsonPath) || fs23.existsSync(pesterPs1Path)) {
51001
51777
  return "pester";
51002
51778
  }
51003
51779
  } catch {}
@@ -51025,12 +51801,12 @@ function isTestDirectoryPath(normalizedPath) {
51025
51801
  return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
51026
51802
  }
51027
51803
  function resolveWorkspacePath(file3, workingDir) {
51028
- return path42.isAbsolute(file3) ? path42.resolve(file3) : path42.resolve(workingDir, file3);
51804
+ return path44.isAbsolute(file3) ? path44.resolve(file3) : path44.resolve(workingDir, file3);
51029
51805
  }
51030
51806
  function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
51031
51807
  if (!preferRelative)
51032
51808
  return absolutePath;
51033
- return path42.relative(workingDir, absolutePath);
51809
+ return path44.relative(workingDir, absolutePath);
51034
51810
  }
51035
51811
  function dedupePush(target, value) {
51036
51812
  if (!target.includes(value)) {
@@ -51067,18 +51843,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
51067
51843
  }
51068
51844
  }
51069
51845
  function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
51070
- const relativeDir = path42.dirname(relativePath);
51846
+ const relativeDir = path44.dirname(relativePath);
51071
51847
  const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
51072
51848
  const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
51073
- const rootDir = path42.join(workingDir, dirName);
51074
- return nestedRelativeDir ? [rootDir, path42.join(rootDir, nestedRelativeDir)] : [rootDir];
51849
+ const rootDir = path44.join(workingDir, dirName);
51850
+ return nestedRelativeDir ? [rootDir, path44.join(rootDir, nestedRelativeDir)] : [rootDir];
51075
51851
  });
51076
51852
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
51077
51853
  if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
51078
- directories.push(path42.join(workingDir, "src/test/java", path42.dirname(normalizedRelativePath.slice("src/main/java/".length))));
51854
+ directories.push(path44.join(workingDir, "src/test/java", path44.dirname(normalizedRelativePath.slice("src/main/java/".length))));
51079
51855
  }
51080
51856
  if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
51081
- directories.push(path42.join(workingDir, "src/test/kotlin", path42.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
51857
+ directories.push(path44.join(workingDir, "src/test/kotlin", path44.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
51082
51858
  }
51083
51859
  return [...new Set(directories)];
51084
51860
  }
@@ -51086,19 +51862,19 @@ function hasCompoundTestExtension(filename) {
51086
51862
  const lower = filename.toLowerCase();
51087
51863
  return COMPOUND_TEST_EXTENSIONS.some((ext) => lower.endsWith(ext));
51088
51864
  }
51089
- function isLanguageSpecificTestFile(basename6) {
51090
- const lower = basename6.toLowerCase();
51865
+ function isLanguageSpecificTestFile(basename7) {
51866
+ const lower = basename7.toLowerCase();
51091
51867
  if (lower.endsWith("_test.go"))
51092
51868
  return true;
51093
51869
  if (lower.endsWith(".py") && (lower.startsWith("test_") || lower.endsWith("_test.py")))
51094
51870
  return true;
51095
51871
  if (lower.endsWith("_spec.rb"))
51096
51872
  return true;
51097
- if (lower.endsWith(".java") && (/^Test[A-Z]/.test(basename6) || basename6.endsWith("Test.java") || basename6.endsWith("Tests.java") || lower.endsWith("it.java")))
51873
+ if (lower.endsWith(".java") && (/^Test[A-Z]/.test(basename7) || basename7.endsWith("Test.java") || basename7.endsWith("Tests.java") || lower.endsWith("it.java")))
51098
51874
  return true;
51099
51875
  if (lower.endsWith(".cs") && (lower.endsWith("test.cs") || lower.endsWith("tests.cs")))
51100
51876
  return true;
51101
- if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(basename6) || lower.endsWith("test.kt") || lower.endsWith("tests.kt")))
51877
+ if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(basename7) || lower.endsWith("test.kt") || lower.endsWith("tests.kt")))
51102
51878
  return true;
51103
51879
  if (lower.endsWith(".tests.ps1"))
51104
51880
  return true;
@@ -51106,23 +51882,23 @@ function isLanguageSpecificTestFile(basename6) {
51106
51882
  }
51107
51883
  function isConventionTestFilePath(filePath) {
51108
51884
  const normalizedPath = filePath.replace(/\\/g, "/");
51109
- const basename6 = path42.basename(filePath);
51110
- return hasCompoundTestExtension(basename6) || basename6.includes(".spec.") || basename6.includes(".test.") || isLanguageSpecificTestFile(basename6) || isTestDirectoryPath(normalizedPath);
51885
+ const basename7 = path44.basename(filePath);
51886
+ return hasCompoundTestExtension(basename7) || basename7.includes(".spec.") || basename7.includes(".test.") || isLanguageSpecificTestFile(basename7) || isTestDirectoryPath(normalizedPath);
51111
51887
  }
51112
51888
  function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
51113
51889
  const testFiles = [];
51114
51890
  for (const file3 of sourceFiles) {
51115
51891
  const absoluteFile = resolveWorkspacePath(file3, workingDir);
51116
- const relativeFile = path42.relative(workingDir, absoluteFile);
51117
- const basename6 = path42.basename(absoluteFile);
51118
- const dirname20 = path42.dirname(absoluteFile);
51119
- const preferRelativeOutput = !path42.isAbsolute(file3);
51892
+ const relativeFile = path44.relative(workingDir, absoluteFile);
51893
+ const basename7 = path44.basename(absoluteFile);
51894
+ const dirname21 = path44.dirname(absoluteFile);
51895
+ const preferRelativeOutput = !path44.isAbsolute(file3);
51120
51896
  if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
51121
51897
  dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
51122
51898
  continue;
51123
51899
  }
51124
- const nameWithoutExt = basename6.replace(/\.[^.]+$/, "");
51125
- const ext = path42.extname(basename6);
51900
+ const nameWithoutExt = basename7.replace(/\.[^.]+$/, "");
51901
+ const ext = path44.extname(basename7);
51126
51902
  const genericTestNames = [
51127
51903
  `${nameWithoutExt}.spec${ext}`,
51128
51904
  `${nameWithoutExt}.test${ext}`
@@ -51131,20 +51907,20 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
51131
51907
  const colocatedCandidates = [
51132
51908
  ...genericTestNames,
51133
51909
  ...languageSpecificTestNames
51134
- ].map((candidateName) => path42.join(dirname20, candidateName));
51910
+ ].map((candidateName) => path44.join(dirname21, candidateName));
51135
51911
  const testDirectoryNames = [
51136
- basename6,
51912
+ basename7,
51137
51913
  ...genericTestNames,
51138
51914
  ...languageSpecificTestNames
51139
51915
  ];
51140
51916
  const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
51141
51917
  const possibleTestFiles = [
51142
51918
  ...colocatedCandidates,
51143
- ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path42.join(dirname20, dirName, candidateName))),
51144
- ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path42.join(candidateDir, candidateName)))
51919
+ ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path44.join(dirname21, dirName, candidateName))),
51920
+ ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path44.join(candidateDir, candidateName)))
51145
51921
  ];
51146
51922
  for (const testFile of possibleTestFiles) {
51147
- if (fs22.existsSync(testFile)) {
51923
+ if (fs23.existsSync(testFile)) {
51148
51924
  dedupePush(testFiles, toWorkspaceOutputPath(testFile, workingDir, preferRelativeOutput));
51149
51925
  }
51150
51926
  }
@@ -51161,8 +51937,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
51161
51937
  for (const testFile of candidateTestFiles) {
51162
51938
  try {
51163
51939
  const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
51164
- const content = fs22.readFileSync(absoluteTestFile, "utf-8");
51165
- const testDir = path42.dirname(absoluteTestFile);
51940
+ const content = fs23.readFileSync(absoluteTestFile, "utf-8");
51941
+ const testDir = path44.dirname(absoluteTestFile);
51166
51942
  const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
51167
51943
  let match;
51168
51944
  match = importRegex.exec(content);
@@ -51170,8 +51946,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
51170
51946
  const importPath = match[1];
51171
51947
  let resolvedImport;
51172
51948
  if (importPath.startsWith(".")) {
51173
- resolvedImport = path42.resolve(testDir, importPath);
51174
- const existingExt = path42.extname(resolvedImport);
51949
+ resolvedImport = path44.resolve(testDir, importPath);
51950
+ const existingExt = path44.extname(resolvedImport);
51175
51951
  if (!existingExt) {
51176
51952
  for (const extToTry of [
51177
51953
  ".ts",
@@ -51182,7 +51958,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
51182
51958
  ".cjs"
51183
51959
  ]) {
51184
51960
  const withExt = resolvedImport + extToTry;
51185
- if (absoluteSourceFiles.includes(withExt) || fs22.existsSync(withExt)) {
51961
+ if (absoluteSourceFiles.includes(withExt) || fs23.existsSync(withExt)) {
51186
51962
  resolvedImport = withExt;
51187
51963
  break;
51188
51964
  }
@@ -51191,12 +51967,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
51191
51967
  } else {
51192
51968
  continue;
51193
51969
  }
51194
- const importBasename = path42.basename(resolvedImport, path42.extname(resolvedImport));
51195
- const importDir = path42.dirname(resolvedImport);
51970
+ const importBasename = path44.basename(resolvedImport, path44.extname(resolvedImport));
51971
+ const importDir = path44.dirname(resolvedImport);
51196
51972
  for (const sourceFile of absoluteSourceFiles) {
51197
- const sourceDir = path42.dirname(sourceFile);
51198
- const sourceBasename = path42.basename(sourceFile, path42.extname(sourceFile));
51199
- const isRelatedDir = importDir === sourceDir || importDir === path42.join(sourceDir, "__tests__") || importDir === path42.join(sourceDir, "tests") || importDir === path42.join(sourceDir, "test") || importDir === path42.join(sourceDir, "spec");
51973
+ const sourceDir = path44.dirname(sourceFile);
51974
+ const sourceBasename = path44.basename(sourceFile, path44.extname(sourceFile));
51975
+ const isRelatedDir = importDir === sourceDir || importDir === path44.join(sourceDir, "__tests__") || importDir === path44.join(sourceDir, "tests") || importDir === path44.join(sourceDir, "test") || importDir === path44.join(sourceDir, "spec");
51200
51976
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
51201
51977
  dedupePush(testFiles, testFile);
51202
51978
  break;
@@ -51209,8 +51985,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
51209
51985
  while (match !== null) {
51210
51986
  const importPath = match[1];
51211
51987
  if (importPath.startsWith(".")) {
51212
- let resolvedImport = path42.resolve(testDir, importPath);
51213
- const existingExt = path42.extname(resolvedImport);
51988
+ let resolvedImport = path44.resolve(testDir, importPath);
51989
+ const existingExt = path44.extname(resolvedImport);
51214
51990
  if (!existingExt) {
51215
51991
  for (const extToTry of [
51216
51992
  ".ts",
@@ -51221,18 +51997,18 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
51221
51997
  ".cjs"
51222
51998
  ]) {
51223
51999
  const withExt = resolvedImport + extToTry;
51224
- if (absoluteSourceFiles.includes(withExt) || fs22.existsSync(withExt)) {
52000
+ if (absoluteSourceFiles.includes(withExt) || fs23.existsSync(withExt)) {
51225
52001
  resolvedImport = withExt;
51226
52002
  break;
51227
52003
  }
51228
52004
  }
51229
52005
  }
51230
- const importDir = path42.dirname(resolvedImport);
51231
- const importBasename = path42.basename(resolvedImport, path42.extname(resolvedImport));
52006
+ const importDir = path44.dirname(resolvedImport);
52007
+ const importBasename = path44.basename(resolvedImport, path44.extname(resolvedImport));
51232
52008
  for (const sourceFile of absoluteSourceFiles) {
51233
- const sourceDir = path42.dirname(sourceFile);
51234
- const sourceBasename = path42.basename(sourceFile, path42.extname(sourceFile));
51235
- const isRelatedDir = importDir === sourceDir || importDir === path42.join(sourceDir, "__tests__") || importDir === path42.join(sourceDir, "tests") || importDir === path42.join(sourceDir, "test") || importDir === path42.join(sourceDir, "spec");
52009
+ const sourceDir = path44.dirname(sourceFile);
52010
+ const sourceBasename = path44.basename(sourceFile, path44.extname(sourceFile));
52011
+ const isRelatedDir = importDir === sourceDir || importDir === path44.join(sourceDir, "__tests__") || importDir === path44.join(sourceDir, "tests") || importDir === path44.join(sourceDir, "test") || importDir === path44.join(sourceDir, "spec");
51236
52012
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
51237
52013
  dedupePush(testFiles, testFile);
51238
52014
  break;
@@ -51342,8 +52118,8 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir) {
51342
52118
  return ["mvn", "test"];
51343
52119
  case "gradle": {
51344
52120
  const isWindows = process.platform === "win32";
51345
- const hasGradlewBat = fs22.existsSync(path42.join(baseDir, "gradlew.bat"));
51346
- const hasGradlew = fs22.existsSync(path42.join(baseDir, "gradlew"));
52121
+ const hasGradlewBat = fs23.existsSync(path44.join(baseDir, "gradlew.bat"));
52122
+ const hasGradlew = fs23.existsSync(path44.join(baseDir, "gradlew"));
51347
52123
  if (hasGradlewBat && isWindows)
51348
52124
  return ["gradlew.bat", "test"];
51349
52125
  if (hasGradlew)
@@ -51360,7 +52136,7 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir) {
51360
52136
  "cmake-build-release",
51361
52137
  "out"
51362
52138
  ];
51363
- const actualBuildDir = buildDirCandidates.find((d) => fs22.existsSync(path42.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
52139
+ const actualBuildDir = buildDirCandidates.find((d) => fs23.existsSync(path44.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
51364
52140
  return ["ctest", "--test-dir", actualBuildDir];
51365
52141
  }
51366
52142
  case "swift-test":
@@ -51792,13 +52568,13 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
51792
52568
  };
51793
52569
  }
51794
52570
  const startTime = Date.now();
51795
- const vitestJsonOutputPath = framework === "vitest" ? path42.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
52571
+ const vitestJsonOutputPath = framework === "vitest" ? path44.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
51796
52572
  try {
51797
52573
  if (vitestJsonOutputPath) {
51798
52574
  try {
51799
- fs22.mkdirSync(path42.dirname(vitestJsonOutputPath), { recursive: true });
51800
- if (fs22.existsSync(vitestJsonOutputPath)) {
51801
- fs22.unlinkSync(vitestJsonOutputPath);
52575
+ fs23.mkdirSync(path44.dirname(vitestJsonOutputPath), { recursive: true });
52576
+ if (fs23.existsSync(vitestJsonOutputPath)) {
52577
+ fs23.unlinkSync(vitestJsonOutputPath);
51802
52578
  }
51803
52579
  } catch {}
51804
52580
  }
@@ -51807,9 +52583,9 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
51807
52583
  stderr: "pipe",
51808
52584
  cwd
51809
52585
  });
51810
- const timeoutPromise = new Promise((resolve14) => setTimeout(() => {
52586
+ const timeoutPromise = new Promise((resolve16) => setTimeout(() => {
51811
52587
  proc.kill();
51812
- resolve14(-1);
52588
+ resolve16(-1);
51813
52589
  }, timeout_ms));
51814
52590
  const [exitCode, stdoutResult, stderrResult] = await Promise.all([
51815
52591
  Promise.race([proc.exited, timeoutPromise]),
@@ -51824,8 +52600,8 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
51824
52600
  }
51825
52601
  if (vitestJsonOutputPath) {
51826
52602
  try {
51827
- if (fs22.existsSync(vitestJsonOutputPath)) {
51828
- const vitestJsonOutput = fs22.readFileSync(vitestJsonOutputPath, "utf-8");
52603
+ if (fs23.existsSync(vitestJsonOutputPath)) {
52604
+ const vitestJsonOutput = fs23.readFileSync(vitestJsonOutputPath, "utf-8");
51829
52605
  if (vitestJsonOutput.trim().length > 0) {
51830
52606
  output += (output ? `
51831
52607
  ` : "") + vitestJsonOutput;
@@ -51912,10 +52688,10 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
51912
52688
  }
51913
52689
  function normalizeHistoryTestFile(testFile, workingDir) {
51914
52690
  const normalized = testFile.replace(/\\/g, "/");
51915
- if (!path42.isAbsolute(testFile))
52691
+ if (!path44.isAbsolute(testFile))
51916
52692
  return normalized;
51917
- const relative9 = path42.relative(workingDir, testFile);
51918
- if (relative9.startsWith("..") || path42.isAbsolute(relative9)) {
52693
+ const relative9 = path44.relative(workingDir, testFile);
52694
+ if (relative9.startsWith("..") || path44.isAbsolute(relative9)) {
51919
52695
  return normalized;
51920
52696
  }
51921
52697
  return relative9.replace(/\\/g, "/");
@@ -52253,7 +53029,7 @@ var init_test_runner = __esm(() => {
52253
53029
  const sourceFiles = args.files.filter((file3) => {
52254
53030
  if (directTestFiles.includes(file3))
52255
53031
  return false;
52256
- const ext = path42.extname(file3).toLowerCase();
53032
+ const ext = path44.extname(file3).toLowerCase();
52257
53033
  return SOURCE_EXTENSIONS.has(ext);
52258
53034
  });
52259
53035
  const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
@@ -52299,7 +53075,7 @@ var init_test_runner = __esm(() => {
52299
53075
  if (isConventionTestFilePath(f)) {
52300
53076
  return false;
52301
53077
  }
52302
- const ext = path42.extname(f).toLowerCase();
53078
+ const ext = path44.extname(f).toLowerCase();
52303
53079
  return SOURCE_EXTENSIONS.has(ext);
52304
53080
  });
52305
53081
  if (sourceFiles.length === 0) {
@@ -52349,7 +53125,7 @@ var init_test_runner = __esm(() => {
52349
53125
  if (isConventionTestFilePath(f)) {
52350
53126
  return false;
52351
53127
  }
52352
- const ext = path42.extname(f).toLowerCase();
53128
+ const ext = path44.extname(f).toLowerCase();
52353
53129
  return SOURCE_EXTENSIONS.has(ext);
52354
53130
  });
52355
53131
  if (sourceFiles.length === 0) {
@@ -52401,8 +53177,8 @@ var init_test_runner = __esm(() => {
52401
53177
  }
52402
53178
  if (impactResult.impactedTests.length > 0) {
52403
53179
  testFiles = impactResult.impactedTests.map((absPath) => {
52404
- const relativePath = path42.relative(workingDir, absPath);
52405
- return path42.isAbsolute(relativePath) ? absPath : relativePath;
53180
+ const relativePath = path44.relative(workingDir, absPath);
53181
+ return path44.isAbsolute(relativePath) ? absPath : relativePath;
52406
53182
  });
52407
53183
  } else {
52408
53184
  graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
@@ -52477,8 +53253,8 @@ var init_test_runner = __esm(() => {
52477
53253
  });
52478
53254
 
52479
53255
  // src/services/preflight-service.ts
52480
- import * as fs23 from "fs";
52481
- import * as path43 from "path";
53256
+ import * as fs24 from "fs";
53257
+ import * as path45 from "path";
52482
53258
  function validateDirectoryPath(dir) {
52483
53259
  if (!dir || typeof dir !== "string") {
52484
53260
  throw new Error("Directory path is required");
@@ -52486,8 +53262,8 @@ function validateDirectoryPath(dir) {
52486
53262
  if (dir.includes("..")) {
52487
53263
  throw new Error("Directory path must not contain path traversal sequences");
52488
53264
  }
52489
- const normalized = path43.normalize(dir);
52490
- const absolutePath = path43.isAbsolute(normalized) ? normalized : path43.resolve(normalized);
53265
+ const normalized = path45.normalize(dir);
53266
+ const absolutePath = path45.isAbsolute(normalized) ? normalized : path45.resolve(normalized);
52491
53267
  return absolutePath;
52492
53268
  }
52493
53269
  function validateTimeout(timeoutMs, defaultValue) {
@@ -52510,9 +53286,9 @@ function validateTimeout(timeoutMs, defaultValue) {
52510
53286
  }
52511
53287
  function getPackageVersion(dir) {
52512
53288
  try {
52513
- const packagePath = path43.join(dir, "package.json");
52514
- if (fs23.existsSync(packagePath)) {
52515
- const content = fs23.readFileSync(packagePath, "utf-8");
53289
+ const packagePath = path45.join(dir, "package.json");
53290
+ if (fs24.existsSync(packagePath)) {
53291
+ const content = fs24.readFileSync(packagePath, "utf-8");
52516
53292
  const pkg = JSON.parse(content);
52517
53293
  return pkg.version ?? null;
52518
53294
  }
@@ -52521,9 +53297,9 @@ function getPackageVersion(dir) {
52521
53297
  }
52522
53298
  function getChangelogVersion(dir) {
52523
53299
  try {
52524
- const changelogPath = path43.join(dir, "CHANGELOG.md");
52525
- if (fs23.existsSync(changelogPath)) {
52526
- const content = fs23.readFileSync(changelogPath, "utf-8");
53300
+ const changelogPath = path45.join(dir, "CHANGELOG.md");
53301
+ if (fs24.existsSync(changelogPath)) {
53302
+ const content = fs24.readFileSync(changelogPath, "utf-8");
52527
53303
  const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
52528
53304
  if (match) {
52529
53305
  return match[1];
@@ -52535,10 +53311,10 @@ function getChangelogVersion(dir) {
52535
53311
  function getVersionFileVersion(dir) {
52536
53312
  const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
52537
53313
  for (const file3 of possibleFiles) {
52538
- const filePath = path43.join(dir, file3);
52539
- if (fs23.existsSync(filePath)) {
53314
+ const filePath = path45.join(dir, file3);
53315
+ if (fs24.existsSync(filePath)) {
52540
53316
  try {
52541
- const content = fs23.readFileSync(filePath, "utf-8").trim();
53317
+ const content = fs24.readFileSync(filePath, "utf-8").trim();
52542
53318
  const match = content.match(/(\d+\.\d+\.\d+)/);
52543
53319
  if (match) {
52544
53320
  return match[1];
@@ -52877,8 +53653,8 @@ async function runEvidenceCheck(dir) {
52877
53653
  async function runRequirementCoverageCheck(dir, currentPhase) {
52878
53654
  const startTime = Date.now();
52879
53655
  try {
52880
- const specPath = path43.join(dir, ".swarm", "spec.md");
52881
- if (!fs23.existsSync(specPath)) {
53656
+ const specPath = path45.join(dir, ".swarm", "spec.md");
53657
+ if (!fs24.existsSync(specPath)) {
52882
53658
  return {
52883
53659
  type: "req_coverage",
52884
53660
  status: "skip",
@@ -53356,13 +54132,13 @@ class CircuitBreaker {
53356
54132
  if (this.config.callTimeoutMs <= 0) {
53357
54133
  return fn();
53358
54134
  }
53359
- return new Promise((resolve15, reject) => {
54135
+ return new Promise((resolve17, reject) => {
53360
54136
  const timeout = setTimeout(() => {
53361
54137
  reject(new Error(`Call timeout after ${this.config.callTimeoutMs}ms`));
53362
54138
  }, this.config.callTimeoutMs);
53363
54139
  fn().then((result) => {
53364
54140
  clearTimeout(timeout);
53365
- resolve15(result);
54141
+ resolve17(result);
53366
54142
  }).catch((error93) => {
53367
54143
  clearTimeout(timeout);
53368
54144
  reject(error93);
@@ -53649,7 +54425,7 @@ var init_queue = __esm(() => {
53649
54425
 
53650
54426
  // src/background/worker.ts
53651
54427
  function sleep(ms) {
53652
- return new Promise((resolve15) => setTimeout(resolve15, ms));
54428
+ return new Promise((resolve17) => setTimeout(resolve17, ms));
53653
54429
  }
53654
54430
 
53655
54431
  class WorkerManager {
@@ -53994,8 +54770,8 @@ var init_manager3 = __esm(() => {
53994
54770
  });
53995
54771
 
53996
54772
  // src/commands/reset.ts
53997
- import * as fs24 from "fs";
53998
- import * as path44 from "path";
54773
+ import * as fs25 from "fs";
54774
+ import * as path46 from "path";
53999
54775
  async function handleResetCommand(directory, args) {
54000
54776
  const hasConfirm = args.includes("--confirm");
54001
54777
  if (!hasConfirm) {
@@ -54023,8 +54799,8 @@ async function handleResetCommand(directory, args) {
54023
54799
  for (const filename of filesToReset) {
54024
54800
  try {
54025
54801
  const resolvedPath = validateSwarmPath(directory, filename);
54026
- if (fs24.existsSync(resolvedPath)) {
54027
- fs24.unlinkSync(resolvedPath);
54802
+ if (fs25.existsSync(resolvedPath)) {
54803
+ fs25.unlinkSync(resolvedPath);
54028
54804
  results.push(`- \u2705 Deleted ${filename}`);
54029
54805
  } else {
54030
54806
  results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
@@ -54035,9 +54811,9 @@ async function handleResetCommand(directory, args) {
54035
54811
  }
54036
54812
  for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
54037
54813
  try {
54038
- const rootPath = path44.join(directory, filename);
54039
- if (fs24.existsSync(rootPath)) {
54040
- fs24.unlinkSync(rootPath);
54814
+ const rootPath = path46.join(directory, filename);
54815
+ if (fs25.existsSync(rootPath)) {
54816
+ fs25.unlinkSync(rootPath);
54041
54817
  results.push(`- \u2705 Deleted ${filename} (root)`);
54042
54818
  }
54043
54819
  } catch {}
@@ -54050,8 +54826,8 @@ async function handleResetCommand(directory, args) {
54050
54826
  }
54051
54827
  try {
54052
54828
  const summariesPath = validateSwarmPath(directory, "summaries");
54053
- if (fs24.existsSync(summariesPath)) {
54054
- fs24.rmSync(summariesPath, { recursive: true, force: true });
54829
+ if (fs25.existsSync(summariesPath)) {
54830
+ fs25.rmSync(summariesPath, { recursive: true, force: true });
54055
54831
  results.push("- \u2705 Deleted summaries/ directory");
54056
54832
  } else {
54057
54833
  results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
@@ -54074,14 +54850,14 @@ var init_reset = __esm(() => {
54074
54850
  });
54075
54851
 
54076
54852
  // src/commands/reset-session.ts
54077
- import * as fs25 from "fs";
54078
- import * as path45 from "path";
54853
+ import * as fs26 from "fs";
54854
+ import * as path47 from "path";
54079
54855
  async function handleResetSessionCommand(directory, _args) {
54080
54856
  const results = [];
54081
54857
  try {
54082
54858
  const statePath = validateSwarmPath(directory, "session/state.json");
54083
- if (fs25.existsSync(statePath)) {
54084
- fs25.unlinkSync(statePath);
54859
+ if (fs26.existsSync(statePath)) {
54860
+ fs26.unlinkSync(statePath);
54085
54861
  results.push("\u2705 Deleted .swarm/session/state.json");
54086
54862
  } else {
54087
54863
  results.push("\u23ED\uFE0F state.json not found (already clean)");
@@ -54090,15 +54866,15 @@ async function handleResetSessionCommand(directory, _args) {
54090
54866
  results.push("\u274C Failed to delete state.json");
54091
54867
  }
54092
54868
  try {
54093
- const sessionDir = path45.dirname(validateSwarmPath(directory, "session/state.json"));
54094
- if (fs25.existsSync(sessionDir)) {
54095
- const files = fs25.readdirSync(sessionDir);
54869
+ const sessionDir = path47.dirname(validateSwarmPath(directory, "session/state.json"));
54870
+ if (fs26.existsSync(sessionDir)) {
54871
+ const files = fs26.readdirSync(sessionDir);
54096
54872
  const otherFiles = files.filter((f) => f !== "state.json");
54097
54873
  let deletedCount = 0;
54098
54874
  for (const file3 of otherFiles) {
54099
- const filePath = path45.join(sessionDir, file3);
54100
- if (fs25.lstatSync(filePath).isFile()) {
54101
- fs25.unlinkSync(filePath);
54875
+ const filePath = path47.join(sessionDir, file3);
54876
+ if (fs26.lstatSync(filePath).isFile()) {
54877
+ fs26.unlinkSync(filePath);
54102
54878
  deletedCount++;
54103
54879
  }
54104
54880
  }
@@ -54128,7 +54904,7 @@ var init_reset_session = __esm(() => {
54128
54904
  });
54129
54905
 
54130
54906
  // src/summaries/manager.ts
54131
- import * as path46 from "path";
54907
+ import * as path48 from "path";
54132
54908
  function sanitizeSummaryId(id) {
54133
54909
  if (!id || id.length === 0) {
54134
54910
  throw new Error("Invalid summary ID: empty string");
@@ -54151,7 +54927,7 @@ function sanitizeSummaryId(id) {
54151
54927
  }
54152
54928
  async function loadFullOutput(directory, id) {
54153
54929
  const sanitizedId = sanitizeSummaryId(id);
54154
- const relativePath = path46.join("summaries", `${sanitizedId}.json`);
54930
+ const relativePath = path48.join("summaries", `${sanitizedId}.json`);
54155
54931
  validateSwarmPath(directory, relativePath);
54156
54932
  const content = await readSwarmFileAsync(directory, relativePath);
54157
54933
  if (content === null) {
@@ -54213,18 +54989,18 @@ var init_retrieve = __esm(() => {
54213
54989
  });
54214
54990
 
54215
54991
  // src/commands/rollback.ts
54216
- import * as fs26 from "fs";
54217
- import * as path47 from "path";
54992
+ import * as fs27 from "fs";
54993
+ import * as path49 from "path";
54218
54994
  async function handleRollbackCommand(directory, args) {
54219
54995
  const phaseArg = args[0];
54220
54996
  if (!phaseArg) {
54221
54997
  const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
54222
- if (!fs26.existsSync(manifestPath2)) {
54998
+ if (!fs27.existsSync(manifestPath2)) {
54223
54999
  return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
54224
55000
  }
54225
55001
  let manifest2;
54226
55002
  try {
54227
- manifest2 = JSON.parse(fs26.readFileSync(manifestPath2, "utf-8"));
55003
+ manifest2 = JSON.parse(fs27.readFileSync(manifestPath2, "utf-8"));
54228
55004
  } catch {
54229
55005
  return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
54230
55006
  }
@@ -54246,12 +55022,12 @@ async function handleRollbackCommand(directory, args) {
54246
55022
  return "Error: Phase number must be a positive integer.";
54247
55023
  }
54248
55024
  const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
54249
- if (!fs26.existsSync(manifestPath)) {
55025
+ if (!fs27.existsSync(manifestPath)) {
54250
55026
  return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
54251
55027
  }
54252
55028
  let manifest;
54253
55029
  try {
54254
- manifest = JSON.parse(fs26.readFileSync(manifestPath, "utf-8"));
55030
+ manifest = JSON.parse(fs27.readFileSync(manifestPath, "utf-8"));
54255
55031
  } catch {
54256
55032
  return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
54257
55033
  }
@@ -54261,10 +55037,10 @@ async function handleRollbackCommand(directory, args) {
54261
55037
  return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
54262
55038
  }
54263
55039
  const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
54264
- if (!fs26.existsSync(checkpointDir)) {
55040
+ if (!fs27.existsSync(checkpointDir)) {
54265
55041
  return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
54266
55042
  }
54267
- const checkpointFiles = fs26.readdirSync(checkpointDir);
55043
+ const checkpointFiles = fs27.readdirSync(checkpointDir);
54268
55044
  if (checkpointFiles.length === 0) {
54269
55045
  return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
54270
55046
  }
@@ -54279,10 +55055,10 @@ async function handleRollbackCommand(directory, args) {
54279
55055
  if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
54280
55056
  continue;
54281
55057
  }
54282
- const src = path47.join(checkpointDir, file3);
54283
- const dest = path47.join(swarmDir, file3);
55058
+ const src = path49.join(checkpointDir, file3);
55059
+ const dest = path49.join(swarmDir, file3);
54284
55060
  try {
54285
- fs26.cpSync(src, dest, { recursive: true, force: true });
55061
+ fs27.cpSync(src, dest, { recursive: true, force: true });
54286
55062
  successes.push(file3);
54287
55063
  } catch (error93) {
54288
55064
  failures.push({ file: file3, error: error93.message });
@@ -54299,14 +55075,14 @@ async function handleRollbackCommand(directory, args) {
54299
55075
  ].join(`
54300
55076
  `);
54301
55077
  }
54302
- const existingLedgerPath = path47.join(swarmDir, "plan-ledger.jsonl");
54303
- if (fs26.existsSync(existingLedgerPath)) {
54304
- fs26.unlinkSync(existingLedgerPath);
55078
+ const existingLedgerPath = path49.join(swarmDir, "plan-ledger.jsonl");
55079
+ if (fs27.existsSync(existingLedgerPath)) {
55080
+ fs27.unlinkSync(existingLedgerPath);
54305
55081
  }
54306
55082
  try {
54307
- const planJsonPath = path47.join(swarmDir, "plan.json");
54308
- if (fs26.existsSync(planJsonPath)) {
54309
- const planRaw = fs26.readFileSync(planJsonPath, "utf-8");
55083
+ const planJsonPath = path49.join(swarmDir, "plan.json");
55084
+ if (fs27.existsSync(planJsonPath)) {
55085
+ const planRaw = fs27.readFileSync(planJsonPath, "utf-8");
54310
55086
  const plan = PlanSchema.parse(JSON.parse(planRaw));
54311
55087
  const planId = derivePlanId(plan);
54312
55088
  const planHash = computePlanHash(plan);
@@ -54333,7 +55109,7 @@ async function handleRollbackCommand(directory, args) {
54333
55109
  timestamp: new Date().toISOString()
54334
55110
  };
54335
55111
  try {
54336
- fs26.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
55112
+ fs27.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
54337
55113
  `);
54338
55114
  } catch (error93) {
54339
55115
  console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
@@ -54394,11 +55170,11 @@ Ensure this is a git repository with commit history.`;
54394
55170
  const report = reportLines.filter(Boolean).join(`
54395
55171
  `);
54396
55172
  try {
54397
- const fs27 = await import("fs/promises");
54398
- const path48 = await import("path");
54399
- const reportPath = path48.join(directory, ".swarm", "simulate-report.md");
54400
- await fs27.mkdir(path48.dirname(reportPath), { recursive: true });
54401
- await fs27.writeFile(reportPath, report, "utf-8");
55173
+ const fs28 = await import("fs/promises");
55174
+ const path50 = await import("path");
55175
+ const reportPath = path50.join(directory, ".swarm", "simulate-report.md");
55176
+ await fs28.mkdir(path50.dirname(reportPath), { recursive: true });
55177
+ await fs28.writeFile(reportPath, report, "utf-8");
54402
55178
  } catch (err) {
54403
55179
  const writeErr = err instanceof Error ? err.message : String(err);
54404
55180
  warn(`simulate: failed to write report to ${directory}/.swarm/simulate-report.md`, writeErr);
@@ -54420,15 +55196,15 @@ async function handleSpecifyCommand(_directory, args) {
54420
55196
  }
54421
55197
 
54422
55198
  // src/turbo/lean/state.ts
54423
- import * as fs27 from "fs";
54424
- import * as path48 from "path";
55199
+ import * as fs28 from "fs";
55200
+ import * as path50 from "path";
54425
55201
  function nowISO2() {
54426
55202
  return new Date().toISOString();
54427
55203
  }
54428
55204
  function ensureSwarmDir2(directory) {
54429
- const swarmDir = path48.resolve(directory, ".swarm");
54430
- if (!fs27.existsSync(swarmDir)) {
54431
- fs27.mkdirSync(swarmDir, { recursive: true });
55205
+ const swarmDir = path50.resolve(directory, ".swarm");
55206
+ if (!fs28.existsSync(swarmDir)) {
55207
+ fs28.mkdirSync(swarmDir, { recursive: true });
54432
55208
  }
54433
55209
  return swarmDir;
54434
55210
  }
@@ -54470,17 +55246,17 @@ function markStateUnreadable2(directory, reason) {
54470
55246
  }
54471
55247
  function readPersisted2(directory) {
54472
55248
  try {
54473
- const filePath = path48.join(directory, ".swarm", STATE_FILE2);
54474
- if (!fs27.existsSync(filePath)) {
55249
+ const filePath = path50.join(directory, ".swarm", STATE_FILE2);
55250
+ if (!fs28.existsSync(filePath)) {
54475
55251
  const seed = emptyPersisted2();
54476
55252
  try {
54477
55253
  ensureSwarmDir2(directory);
54478
- fs27.writeFileSync(filePath, `${JSON.stringify(seed, null, 2)}
55254
+ fs28.writeFileSync(filePath, `${JSON.stringify(seed, null, 2)}
54479
55255
  `, "utf-8");
54480
55256
  } catch {}
54481
55257
  return seed;
54482
55258
  }
54483
- const raw = fs27.readFileSync(filePath, "utf-8");
55259
+ const raw = fs28.readFileSync(filePath, "utf-8");
54484
55260
  const parsed = JSON.parse(raw);
54485
55261
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || parsed.version !== 1 || !parsed.sessions || typeof parsed.sessions !== "object" || Array.isArray(parsed.sessions)) {
54486
55262
  markStateUnreadable2(directory, `malformed shape (version=${parsed?.version}, sessions type=${Array.isArray(parsed?.sessions) ? "array" : typeof parsed?.sessions})`);
@@ -54506,7 +55282,7 @@ function writePersisted2(directory, persisted) {
54506
55282
  let payload;
54507
55283
  try {
54508
55284
  ensureSwarmDir2(directory);
54509
- filePath = path48.join(directory, ".swarm", STATE_FILE2);
55285
+ filePath = path50.join(directory, ".swarm", STATE_FILE2);
54510
55286
  tmpPath = `${filePath}.tmp.${Date.now()}`;
54511
55287
  persisted.updatedAt = nowISO2();
54512
55288
  payload = `${JSON.stringify(persisted, null, 2)}
@@ -54517,14 +55293,14 @@ function writePersisted2(directory, persisted) {
54517
55293
  throw new Error(`Lean Turbo state persistence prepare failed: ${msg}`);
54518
55294
  }
54519
55295
  try {
54520
- fs27.writeFileSync(tmpPath, payload, "utf-8");
54521
- fs27.renameSync(tmpPath, filePath);
55296
+ fs28.writeFileSync(tmpPath, payload, "utf-8");
55297
+ fs28.renameSync(tmpPath, filePath);
54522
55298
  } catch (error93) {
54523
55299
  const msg = error93 instanceof Error ? error93.message : String(error93);
54524
55300
  error(`[turbo/lean/state] Failed to persist ${STATE_FILE2} atomically: ${msg}`);
54525
55301
  try {
54526
- if (fs27.existsSync(tmpPath)) {
54527
- fs27.unlinkSync(tmpPath);
55302
+ if (fs28.existsSync(tmpPath)) {
55303
+ fs28.unlinkSync(tmpPath);
54528
55304
  }
54529
55305
  } catch {}
54530
55306
  throw new Error(`Lean Turbo state persistence failed: ${msg}`);
@@ -54633,10 +55409,10 @@ var init_context_budget_service = __esm(() => {
54633
55409
 
54634
55410
  // src/services/status-service.ts
54635
55411
  import * as fsSync2 from "fs";
54636
- import * as path49 from "path";
55412
+ import * as path51 from "path";
54637
55413
  function readSpecStalenessSnapshot(directory) {
54638
55414
  try {
54639
- const p = path49.join(directory, ".swarm", "spec-staleness.json");
55415
+ const p = path51.join(directory, ".swarm", "spec-staleness.json");
54640
55416
  if (!fsSync2.existsSync(p))
54641
55417
  return { stale: false };
54642
55418
  const raw = fsSync2.readFileSync(p, "utf-8");
@@ -55161,8 +55937,8 @@ var init_write_retro2 = __esm(() => {
55161
55937
  });
55162
55938
 
55163
55939
  // src/commands/command-dispatch.ts
55164
- import fs28 from "fs";
55165
- import path50 from "path";
55940
+ import fs29 from "fs";
55941
+ import path52 from "path";
55166
55942
  function normalizeSwarmCommandInput(command, argumentText) {
55167
55943
  if (command !== "swarm" && !command.startsWith("swarm-")) {
55168
55944
  return { isSwarmCommand: false, tokens: [] };
@@ -55198,11 +55974,11 @@ ${similar.map((cmd) => ` - /swarm ${cmd}`).join(`
55198
55974
  `);
55199
55975
  }
55200
55976
  function maybeMarkFirstRun(directory) {
55201
- const sentinelPath = path50.join(directory, ".swarm", ".first-run-complete");
55977
+ const sentinelPath = path52.join(directory, ".swarm", ".first-run-complete");
55202
55978
  try {
55203
- const swarmDir = path50.join(directory, ".swarm");
55204
- fs28.mkdirSync(swarmDir, { recursive: true });
55205
- fs28.writeFileSync(sentinelPath, `first-run-complete: ${new Date().toISOString()}
55979
+ const swarmDir = path52.join(directory, ".swarm");
55980
+ fs29.mkdirSync(swarmDir, { recursive: true });
55981
+ fs29.writeFileSync(sentinelPath, `first-run-complete: ${new Date().toISOString()}
55206
55982
  `, { flag: "wx" });
55207
55983
  return true;
55208
55984
  } catch {
@@ -55314,7 +56090,17 @@ function classifySwarmCommandToolUse(resolved) {
55314
56090
  return { allowed: true };
55315
56091
  return {
55316
56092
  allowed: false,
55317
- message: "Use `/swarm memory status` or `/swarm memory export` through swarm_command. Memory import and migrate are intentionally excluded from chat-tool execution."
56093
+ message: "Use `/swarm memory status`, `/swarm memory export`, or `/swarm memory evaluate --json` through swarm_command. Memory import and migrate are intentionally excluded from chat-tool execution."
56094
+ };
56095
+ }
56096
+ if (canonicalKey === "memory evaluate") {
56097
+ if (args.length === 0)
56098
+ return { allowed: true };
56099
+ if (args.length === 1 && args[0] === "--json")
56100
+ return { allowed: true };
56101
+ return {
56102
+ allowed: false,
56103
+ message: "Usage through swarm_command: `/swarm memory evaluate --json`. Custom fixture directories are only available through direct user command execution."
55318
56104
  };
55319
56105
  }
55320
56106
  if (canonicalKey === "retrieve") {
@@ -55402,6 +56188,7 @@ var init_tool_policy = __esm(() => {
55402
56188
  "memory",
55403
56189
  "memory status",
55404
56190
  "memory export",
56191
+ "memory evaluate",
55405
56192
  "memory import",
55406
56193
  "memory migrate",
55407
56194
  "sync-plan",
@@ -55427,6 +56214,7 @@ var init_tool_policy = __esm(() => {
55427
56214
  "memory",
55428
56215
  "memory status",
55429
56216
  "memory export",
56217
+ "memory evaluate",
55430
56218
  "sync-plan",
55431
56219
  "export"
55432
56220
  ]);
@@ -55490,6 +56278,7 @@ __export(exports_commands, {
55490
56278
  handleMemoryMigrateCommand: () => handleMemoryMigrateCommand,
55491
56279
  handleMemoryImportCommand: () => handleMemoryImportCommand,
55492
56280
  handleMemoryExportCommand: () => handleMemoryExportCommand,
56281
+ handleMemoryEvaluateCommand: () => handleMemoryEvaluateCommand,
55493
56282
  handleMemoryCommand: () => handleMemoryCommand,
55494
56283
  handleKnowledgeRestoreCommand: () => handleKnowledgeRestoreCommand,
55495
56284
  handleKnowledgeQuarantineCommand: () => handleKnowledgeQuarantineCommand,
@@ -55909,24 +56698,24 @@ function validateAliases() {
55909
56698
  }
55910
56699
  aliasTargets.get(target).push(name);
55911
56700
  const visited = new Set;
55912
- const path51 = [];
56701
+ const path53 = [];
55913
56702
  let current = target;
55914
56703
  while (current) {
55915
56704
  const currentEntry = COMMAND_REGISTRY[current];
55916
56705
  if (!currentEntry)
55917
56706
  break;
55918
56707
  if (visited.has(current)) {
55919
- const cycleStart = path51.indexOf(current);
56708
+ const cycleStart = path53.indexOf(current);
55920
56709
  const fullChain = [
55921
56710
  name,
55922
- ...path51.slice(0, cycleStart > 0 ? cycleStart : path51.length),
56711
+ ...path53.slice(0, cycleStart > 0 ? cycleStart : path53.length),
55923
56712
  current
55924
56713
  ].join(" \u2192 ");
55925
56714
  errors5.push(`Circular alias detected: ${fullChain}`);
55926
56715
  break;
55927
56716
  }
55928
56717
  visited.add(current);
55929
- path51.push(current);
56718
+ path53.push(current);
55930
56719
  current = currentEntry.aliasOf || "";
55931
56720
  }
55932
56721
  }
@@ -56419,6 +57208,13 @@ Subcommands:
56419
57208
  args: "",
56420
57209
  category: "utility"
56421
57210
  },
57211
+ "memory evaluate": {
57212
+ handler: (ctx) => handleMemoryEvaluateCommand(ctx.directory, ctx.args),
57213
+ description: "Run golden Swarm memory recall evaluation fixtures",
57214
+ subcommandOf: "memory",
57215
+ args: "--json, --fixtures <directory>",
57216
+ category: "diagnostics"
57217
+ },
56422
57218
  "memory import": {
56423
57219
  handler: (ctx) => handleMemoryImportCommand(ctx.directory, ctx.args),
56424
57220
  description: "Import legacy JSONL memory into SQLite",
@@ -56469,68 +57265,68 @@ init_package();
56469
57265
  init_registry();
56470
57266
  init_cache_paths();
56471
57267
  init_constants();
56472
- import * as fs29 from "fs";
56473
- import * as os7 from "os";
56474
- import * as path51 from "path";
57268
+ import * as fs30 from "fs";
57269
+ import * as os8 from "os";
57270
+ import * as path53 from "path";
56475
57271
  var { version: version4 } = package_default;
56476
57272
  var CONFIG_DIR = getPluginConfigDir();
56477
- var OPENCODE_CONFIG_PATH = path51.join(CONFIG_DIR, "opencode.json");
56478
- var PLUGIN_CONFIG_PATH = path51.join(CONFIG_DIR, "opencode-swarm.json");
56479
- var PROMPTS_DIR = path51.join(CONFIG_DIR, "opencode-swarm");
57273
+ var OPENCODE_CONFIG_PATH = path53.join(CONFIG_DIR, "opencode.json");
57274
+ var PLUGIN_CONFIG_PATH = path53.join(CONFIG_DIR, "opencode-swarm.json");
57275
+ var PROMPTS_DIR = path53.join(CONFIG_DIR, "opencode-swarm");
56480
57276
  var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
56481
57277
  var OPENCODE_PLUGIN_LOCK_FILE_PATHS = getPluginLockFilePaths();
56482
57278
  function isSafeCachePath(p) {
56483
- const resolved = path51.resolve(p);
56484
- const home = path51.resolve(os7.homedir());
57279
+ const resolved = path53.resolve(p);
57280
+ const home = path53.resolve(os8.homedir());
56485
57281
  if (resolved === "/" || resolved === home || resolved.length <= home.length) {
56486
57282
  return false;
56487
57283
  }
56488
- const segments = resolved.split(path51.sep).filter((s) => s.length > 0);
57284
+ const segments = resolved.split(path53.sep).filter((s) => s.length > 0);
56489
57285
  if (segments.length < 4) {
56490
57286
  return false;
56491
57287
  }
56492
- const leaf = path51.basename(resolved);
57288
+ const leaf = path53.basename(resolved);
56493
57289
  if (leaf !== "opencode-swarm@latest" && leaf !== "opencode-swarm") {
56494
57290
  return false;
56495
57291
  }
56496
- const parent = path51.basename(path51.dirname(resolved));
57292
+ const parent = path53.basename(path53.dirname(resolved));
56497
57293
  if (parent !== "packages" && parent !== "node_modules") {
56498
57294
  return false;
56499
57295
  }
56500
- const grandparent = path51.basename(path51.dirname(path51.dirname(resolved)));
57296
+ const grandparent = path53.basename(path53.dirname(path53.dirname(resolved)));
56501
57297
  if (grandparent !== "opencode") {
56502
57298
  return false;
56503
57299
  }
56504
57300
  return true;
56505
57301
  }
56506
57302
  function isSafeLockFilePath(p) {
56507
- const resolved = path51.resolve(p);
56508
- const home = path51.resolve(os7.homedir());
57303
+ const resolved = path53.resolve(p);
57304
+ const home = path53.resolve(os8.homedir());
56509
57305
  if (resolved === "/" || resolved === home || resolved.length <= home.length) {
56510
57306
  return false;
56511
57307
  }
56512
- const segments = resolved.split(path51.sep).filter((s) => s.length > 0);
57308
+ const segments = resolved.split(path53.sep).filter((s) => s.length > 0);
56513
57309
  if (segments.length < 4) {
56514
57310
  return false;
56515
57311
  }
56516
- const leaf = path51.basename(resolved);
57312
+ const leaf = path53.basename(resolved);
56517
57313
  if (leaf !== "bun.lock" && leaf !== "bun.lockb" && leaf !== "package-lock.json") {
56518
57314
  return false;
56519
57315
  }
56520
- const parent = path51.basename(path51.dirname(resolved));
57316
+ const parent = path53.basename(path53.dirname(resolved));
56521
57317
  if (parent !== "opencode") {
56522
57318
  return false;
56523
57319
  }
56524
57320
  return true;
56525
57321
  }
56526
57322
  function ensureDir(dir) {
56527
- if (!fs29.existsSync(dir)) {
56528
- fs29.mkdirSync(dir, { recursive: true });
57323
+ if (!fs30.existsSync(dir)) {
57324
+ fs30.mkdirSync(dir, { recursive: true });
56529
57325
  }
56530
57326
  }
56531
57327
  function loadJson(filepath) {
56532
57328
  try {
56533
- const content = fs29.readFileSync(filepath, "utf-8");
57329
+ const content = fs30.readFileSync(filepath, "utf-8");
56534
57330
  const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
56535
57331
  return JSON.parse(stripped);
56536
57332
  } catch {
@@ -56538,14 +57334,14 @@ function loadJson(filepath) {
56538
57334
  }
56539
57335
  }
56540
57336
  function saveJson(filepath, data) {
56541
- fs29.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
57337
+ fs30.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
56542
57338
  `, "utf-8");
56543
57339
  }
56544
57340
  function writeProjectConfigIfMissing(cwd) {
56545
57341
  try {
56546
- const opencodeDir = path51.join(cwd, ".opencode");
56547
- const projectConfigPath = path51.join(opencodeDir, "opencode-swarm.json");
56548
- if (fs29.existsSync(projectConfigPath)) {
57342
+ const opencodeDir = path53.join(cwd, ".opencode");
57343
+ const projectConfigPath = path53.join(opencodeDir, "opencode-swarm.json");
57344
+ if (fs30.existsSync(projectConfigPath)) {
56549
57345
  return;
56550
57346
  }
56551
57347
  ensureDir(opencodeDir);
@@ -56561,7 +57357,7 @@ async function install() {
56561
57357
  `);
56562
57358
  ensureDir(CONFIG_DIR);
56563
57359
  ensureDir(PROMPTS_DIR);
56564
- const LEGACY_CONFIG_PATH = path51.join(CONFIG_DIR, "config.json");
57360
+ const LEGACY_CONFIG_PATH = path53.join(CONFIG_DIR, "config.json");
56565
57361
  let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
56566
57362
  if (!opencodeConfig) {
56567
57363
  const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
@@ -56608,7 +57404,7 @@ async function install() {
56608
57404
  console.warn(`\u26A0 Could not clear opencode lock file \u2014 you may need to delete it manually:
56609
57405
  ${failed}`);
56610
57406
  }
56611
- if (!fs29.existsSync(PLUGIN_CONFIG_PATH)) {
57407
+ if (!fs30.existsSync(PLUGIN_CONFIG_PATH)) {
56612
57408
  const defaultConfig = {
56613
57409
  agents: { ...DEFAULT_AGENT_CONFIGS },
56614
57410
  max_iterations: 5
@@ -56687,14 +57483,14 @@ function evictPluginCaches() {
56687
57483
  const cleared = [];
56688
57484
  const failed = [];
56689
57485
  for (const cachePath of OPENCODE_PLUGIN_CACHE_PATHS) {
56690
- if (!fs29.existsSync(cachePath))
57486
+ if (!fs30.existsSync(cachePath))
56691
57487
  continue;
56692
57488
  if (!isSafeCachePath(cachePath)) {
56693
57489
  failed.push(`${cachePath} (refused: failed safety check)`);
56694
57490
  continue;
56695
57491
  }
56696
57492
  try {
56697
- fs29.rmSync(cachePath, { recursive: true, force: true });
57493
+ fs30.rmSync(cachePath, { recursive: true, force: true });
56698
57494
  cleared.push(cachePath);
56699
57495
  } catch (err) {
56700
57496
  failed.push(`${cachePath} (${err instanceof Error ? err.message : String(err)})`);
@@ -56706,14 +57502,14 @@ function evictLockFiles() {
56706
57502
  const cleared = [];
56707
57503
  const failed = [];
56708
57504
  for (const lockPath of OPENCODE_PLUGIN_LOCK_FILE_PATHS) {
56709
- if (!fs29.existsSync(lockPath))
57505
+ if (!fs30.existsSync(lockPath))
56710
57506
  continue;
56711
57507
  if (!isSafeLockFilePath(lockPath)) {
56712
57508
  failed.push(`${lockPath} (refused: failed safety check)`);
56713
57509
  continue;
56714
57510
  }
56715
57511
  try {
56716
- fs29.unlinkSync(lockPath);
57512
+ fs30.unlinkSync(lockPath);
56717
57513
  cleared.push(lockPath);
56718
57514
  } catch (err) {
56719
57515
  const code = err?.code;
@@ -56732,7 +57528,7 @@ async function uninstall() {
56732
57528
  `);
56733
57529
  const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
56734
57530
  if (!opencodeConfig) {
56735
- if (fs29.existsSync(OPENCODE_CONFIG_PATH)) {
57531
+ if (fs30.existsSync(OPENCODE_CONFIG_PATH)) {
56736
57532
  console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
56737
57533
  return 1;
56738
57534
  } else {
@@ -56764,13 +57560,13 @@ async function uninstall() {
56764
57560
  console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
56765
57561
  if (process.argv.includes("--clean")) {
56766
57562
  let cleaned = false;
56767
- if (fs29.existsSync(PLUGIN_CONFIG_PATH)) {
56768
- fs29.unlinkSync(PLUGIN_CONFIG_PATH);
57563
+ if (fs30.existsSync(PLUGIN_CONFIG_PATH)) {
57564
+ fs30.unlinkSync(PLUGIN_CONFIG_PATH);
56769
57565
  console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
56770
57566
  cleaned = true;
56771
57567
  }
56772
- if (fs29.existsSync(PROMPTS_DIR)) {
56773
- fs29.rmSync(PROMPTS_DIR, { recursive: true });
57568
+ if (fs30.existsSync(PROMPTS_DIR)) {
57569
+ fs30.rmSync(PROMPTS_DIR, { recursive: true });
56774
57570
  console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
56775
57571
  cleaned = true;
56776
57572
  }