opencode-swarm 7.88.3 → 7.88.4

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.
Files changed (39) hide show
  1. package/dist/agents/agent-output-schema.d.ts +1 -1
  2. package/dist/agents/curator-agent.d.ts +1 -1
  3. package/dist/agents/explorer.d.ts +1 -0
  4. package/dist/cli/{config-doctor-jzbgpbdh.js → config-doctor-g04wdz19.js} +2 -2
  5. package/dist/cli/{explorer-gz70sm9b.js → explorer-h2fnj343.js} +4 -2
  6. package/dist/cli/{guardrail-explain-eqypvw60.js → guardrail-explain-xe0wjnxz.js} +7 -7
  7. package/dist/cli/{guardrail-log-c7egm5km.js → guardrail-log-m3285thy.js} +3 -3
  8. package/dist/cli/{index-0asbrmdx.js → index-123s7kjc.js} +88 -2
  9. package/dist/cli/{index-0rt5aamg.js → index-5p1gvn98.js} +8 -8
  10. package/dist/cli/{index-g00qm2gf.js → index-6tnmt41c.js} +1 -1
  11. package/dist/cli/{index-yhsmmv2z.js → index-bm4f0nme.js} +25 -1
  12. package/dist/cli/{index-819xp49y.js → index-bywt2171.js} +1 -1
  13. package/dist/cli/{index-ds057q5k.js → index-d4hpgf63.js} +2 -2
  14. package/dist/cli/{index-vjsr9bqt.js → index-gg589mfw.js} +1 -1
  15. package/dist/cli/{index-g6f4tt38.js → index-hs2knbfq.js} +520 -375
  16. package/dist/cli/{index-32axfg6h.js → index-rh53rrpt.js} +82 -12
  17. package/dist/cli/index.js +6 -6
  18. package/dist/cli/{schema-vb6jkxgg.js → schema-t9th7frq.js} +1 -1
  19. package/dist/cli/{skill-generator-kz4q8e49.js → skill-generator-s0spm65v.js} +1 -1
  20. package/dist/commands/memory.d.ts +1 -0
  21. package/dist/commands/registry.d.ts +8 -0
  22. package/dist/config/agent-names.d.ts +2 -2
  23. package/dist/config/schema.d.ts +60 -0
  24. package/dist/hooks/curator-llm-factory.d.ts +1 -1
  25. package/dist/index.js +1971 -1077
  26. package/dist/memory/config.d.ts +35 -0
  27. package/dist/memory/consolidation-log.d.ts +29 -0
  28. package/dist/memory/consolidation.d.ts +124 -0
  29. package/dist/memory/decay.d.ts +24 -0
  30. package/dist/memory/gateway.d.ts +14 -2
  31. package/dist/memory/maintenance.d.ts +18 -0
  32. package/dist/memory/run-log.d.ts +8 -1
  33. package/dist/memory/schema.d.ts +3 -3
  34. package/dist/memory/scoring.d.ts +45 -0
  35. package/dist/memory/sentinel.d.ts +15 -0
  36. package/dist/services/memory-consolidation.d.ts +32 -0
  37. package/dist/services/skill-generator.d.ts +8 -1
  38. package/dist/state.d.ts +4 -2
  39. package/package.json +1 -1
@@ -20,7 +20,7 @@ import {
20
20
  validateActionability,
21
21
  validateActionableFields,
22
22
  validateLesson
23
- } from "./index-32axfg6h.js";
23
+ } from "./index-rh53rrpt.js";
24
24
  import {
25
25
  appendKnowledge,
26
26
  appendRejectedLesson,
@@ -47,7 +47,7 @@ import {
47
47
  readDoctorArtifact,
48
48
  removeStraySwarmDir,
49
49
  runConfigDoctor
50
- } from "./index-819xp49y.js";
50
+ } from "./index-bywt2171.js";
51
51
  import {
52
52
  AGENT_TOOL_MAP,
53
53
  ALL_SUBAGENT_NAMES,
@@ -60,7 +60,7 @@ import {
60
60
  TOOL_NAME_SET,
61
61
  resolveExternalSkillsConfig,
62
62
  stripKnownSwarmPrefix
63
- } from "./index-0asbrmdx.js";
63
+ } from "./index-123s7kjc.js";
64
64
  import {
65
65
  MAX_TRANSIENT_RETRIES,
66
66
  PlanSchema,
@@ -899,7 +899,7 @@ var init_executor = __esm(() => {
899
899
  // package.json
900
900
  var package_default = {
901
901
  name: "opencode-swarm",
902
- version: "7.88.3",
902
+ version: "7.88.4",
903
903
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
904
904
  main: "dist/index.js",
905
905
  types: "dist/index.d.ts",
@@ -4119,6 +4119,7 @@ var swarmState = {
4119
4119
  curatorInitAgentNames: [],
4120
4120
  curatorPhaseAgentNames: [],
4121
4121
  curatorPostmortemAgentNames: [],
4122
+ curatorConsolidationAgentNames: [],
4122
4123
  skillImproverAgentNames: [],
4123
4124
  specWriterAgentNames: [],
4124
4125
  currentCriticalShownIds: new Map,
@@ -4145,6 +4146,7 @@ function resetSwarmState() {
4145
4146
  swarmState.curatorInitAgentNames = [];
4146
4147
  swarmState.curatorPhaseAgentNames = [];
4147
4148
  swarmState.curatorPostmortemAgentNames = [];
4149
+ swarmState.curatorConsolidationAgentNames = [];
4148
4150
  swarmState.skillImproverAgentNames = [];
4149
4151
  swarmState.specWriterAgentNames = [];
4150
4152
  swarmState.currentCriticalShownIds.clear();
@@ -4163,6 +4165,7 @@ function resetSwarmStatePreservingSingletons() {
4163
4165
  const preservedCuratorInitAgentNames = swarmState.curatorInitAgentNames;
4164
4166
  const preservedCuratorPhaseAgentNames = swarmState.curatorPhaseAgentNames;
4165
4167
  const preservedCuratorPostmortemAgentNames = swarmState.curatorPostmortemAgentNames;
4168
+ const preservedCuratorConsolidationAgentNames = swarmState.curatorConsolidationAgentNames;
4166
4169
  const preservedSkillImproverAgentNames = swarmState.skillImproverAgentNames;
4167
4170
  const preservedSpecWriterAgentNames = swarmState.specWriterAgentNames;
4168
4171
  const preservedGeneratedAgentNames = swarmState.generatedAgentNames;
@@ -4172,6 +4175,7 @@ function resetSwarmStatePreservingSingletons() {
4172
4175
  swarmState.curatorInitAgentNames = preservedCuratorInitAgentNames;
4173
4176
  swarmState.curatorPhaseAgentNames = preservedCuratorPhaseAgentNames;
4174
4177
  swarmState.curatorPostmortemAgentNames = preservedCuratorPostmortemAgentNames;
4178
+ swarmState.curatorConsolidationAgentNames = preservedCuratorConsolidationAgentNames;
4175
4179
  swarmState.skillImproverAgentNames = preservedSkillImproverAgentNames;
4176
4180
  swarmState.specWriterAgentNames = preservedSpecWriterAgentNames;
4177
4181
  swarmState.generatedAgentNames = preservedGeneratedAgentNames;
@@ -5720,13 +5724,15 @@ function resolveCuratorAgentName(mode, sessionId) {
5720
5724
  const suffixMap = {
5721
5725
  init: "curator_init",
5722
5726
  phase: "curator_phase",
5723
- postmortem: "curator_postmortem"
5727
+ postmortem: "curator_postmortem",
5728
+ consolidation: "curator_consolidation"
5724
5729
  };
5725
5730
  const suffix = suffixMap[mode];
5726
5731
  const registeredNamesMap = {
5727
5732
  init: swarmState.curatorInitAgentNames,
5728
5733
  phase: swarmState.curatorPhaseAgentNames,
5729
- postmortem: swarmState.curatorPostmortemAgentNames
5734
+ postmortem: swarmState.curatorPostmortemAgentNames,
5735
+ consolidation: swarmState.curatorConsolidationAgentNames
5730
5736
  };
5731
5737
  const registeredNames = registeredNamesMap[mode];
5732
5738
  if (registeredNames.length === 1)
@@ -6190,7 +6196,7 @@ async function runCuratorPostMortem(directory, options = {}) {
6190
6196
  let reportContent;
6191
6197
  if (options.llmDelegate) {
6192
6198
  try {
6193
- const { CURATOR_POSTMORTEM_PROMPT: CURATOR_POSTMORTEM_PROMPT2 } = await import("./explorer-gz70sm9b.js");
6199
+ const { CURATOR_POSTMORTEM_PROMPT: CURATOR_POSTMORTEM_PROMPT2 } = await import("./explorer-h2fnj343.js");
6194
6200
  const userInput = assembleLLMInput(effectivePlanId, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports);
6195
6201
  const ac = new AbortController;
6196
6202
  const timer = setTimeout(() => ac.abort(), 300000);
@@ -11539,7 +11545,7 @@ async function runFinalizeStage(ctx) {
11539
11545
  }
11540
11546
  }
11541
11547
  try {
11542
- const { CuratorConfigSchema: CCS } = await import("./schema-vb6jkxgg.js");
11548
+ const { CuratorConfigSchema: CCS } = await import("./schema-t9th7frq.js");
11543
11549
  const { config: pmLoadedConfig } = _internals20.loadPluginConfigWithMeta(ctx.directory);
11544
11550
  const curatorCfg = CCS.parse(pmLoadedConfig.curator ?? {});
11545
11551
  if (curatorCfg.enabled && curatorCfg.postmortem_enabled) {
@@ -15220,7 +15226,7 @@ async function handleDoctorCommand(directory, args) {
15220
15226
  const result = runConfigDoctor(config, directory);
15221
15227
  let output;
15222
15228
  if (enableAutoFix && result.hasAutoFixableIssues) {
15223
- const { runConfigDoctorWithFixes } = await import("./config-doctor-jzbgpbdh.js");
15229
+ const { runConfigDoctorWithFixes } = await import("./config-doctor-g04wdz19.js");
15224
15230
  const fixResult = await runConfigDoctorWithFixes(directory, config, true);
15225
15231
  output = formatDoctorMarkdown(fixResult.result);
15226
15232
  } else {
@@ -18335,10 +18341,41 @@ ${USAGE7}`;
18335
18341
 
18336
18342
  // src/commands/memory.ts
18337
18343
  import { existsSync as existsSync25 } from "fs";
18338
- import * as path43 from "path";
18344
+ import * as path44 from "path";
18339
18345
  import { fileURLToPath as fileURLToPath2 } from "url";
18340
18346
 
18341
18347
  // src/memory/config.ts
18348
+ var DEFAULT_DECAY_HALF_LIFE_DAYS = {
18349
+ scratch: 7,
18350
+ todo: 30,
18351
+ code_pattern: 90,
18352
+ test_pattern: 90,
18353
+ failure_pattern: 90,
18354
+ api_finding: 180,
18355
+ evidence: 180,
18356
+ architecture_decision: 0,
18357
+ repo_convention: 0,
18358
+ project_fact: 0,
18359
+ security_note: 0,
18360
+ user_preference: 0
18361
+ };
18362
+ var DEFAULT_IMPORTANCE_CONFIG = {
18363
+ wRecency: 0.2,
18364
+ wFrequency: 0.2,
18365
+ wFreshness: 0.15,
18366
+ wConfidence: 0.25,
18367
+ lambda: 0.05,
18368
+ mu: 0.01,
18369
+ n: 50,
18370
+ threshold: 0.2
18371
+ };
18372
+ var DEFAULT_CONSOLIDATION_CONFIG = {
18373
+ enabled: false,
18374
+ maxClustersPerPass: 10,
18375
+ jaccardThreshold: 0.3,
18376
+ autoApplyMinConfidence: 0.6,
18377
+ decayHalfLifeDays: { ...DEFAULT_DECAY_HALF_LIFE_DAYS }
18378
+ };
18342
18379
  var DEFAULT_MEMORY_CONFIG = {
18343
18380
  enabled: false,
18344
18381
  provider: "sqlite",
@@ -18368,7 +18405,12 @@ var DEFAULT_MEMORY_CONFIG = {
18368
18405
  maintenance: {
18369
18406
  lowUtilityMaxConfidence: 0.45,
18370
18407
  lowUtilityMinAgeDays: 30,
18371
- autoCompactEveryNRecalls: 50
18408
+ autoCompactEveryNRecalls: 50,
18409
+ importance: { ...DEFAULT_IMPORTANCE_CONFIG }
18410
+ },
18411
+ consolidation: {
18412
+ ...DEFAULT_CONSOLIDATION_CONFIG,
18413
+ decayHalfLifeDays: { ...DEFAULT_DECAY_HALF_LIFE_DAYS }
18372
18414
  },
18373
18415
  hardDelete: false
18374
18416
  };
@@ -18413,7 +18455,19 @@ function resolveMemoryConfig(input) {
18413
18455
  },
18414
18456
  maintenance: {
18415
18457
  ...DEFAULT_MEMORY_CONFIG.maintenance,
18416
- ...input?.maintenance ?? {}
18458
+ ...input?.maintenance ?? {},
18459
+ importance: {
18460
+ ...DEFAULT_MEMORY_CONFIG.maintenance.importance,
18461
+ ...input?.maintenance?.importance ?? {}
18462
+ }
18463
+ },
18464
+ consolidation: {
18465
+ ...DEFAULT_MEMORY_CONFIG.consolidation,
18466
+ ...input?.consolidation ?? {},
18467
+ decayHalfLifeDays: {
18468
+ ...DEFAULT_MEMORY_CONFIG.consolidation.decayHalfLifeDays,
18469
+ ...input?.consolidation?.decayHalfLifeDays ?? {}
18470
+ }
18417
18471
  }
18418
18472
  };
18419
18473
  }
@@ -18501,6 +18555,9 @@ function containsSecret(text) {
18501
18555
  return findSecrets(text).length > 0;
18502
18556
  }
18503
18557
 
18558
+ // src/memory/sentinel.ts
18559
+ var MEMORY_RECALL_SENTINEL = "## Retrieved Swarm Memory";
18560
+
18504
18561
  // src/memory/schema.ts
18505
18562
  var MemoryScopeTypeSchema = exports_external.enum([
18506
18563
  "global_user",
@@ -18702,6 +18759,9 @@ function hasEvidenceSource(record) {
18702
18759
  }
18703
18760
  function validateMemoryRecordRules(record, options) {
18704
18761
  const parsed = MemoryRecordSchema.parse(record);
18762
+ if (parsed.text.includes(MEMORY_RECALL_SENTINEL)) {
18763
+ throw new MemoryValidationError("memory text cannot contain the recall sentinel header");
18764
+ }
18705
18765
  const expectedHash = computeMemoryContentHash(parsed);
18706
18766
  const expectedId = createMemoryId(parsed);
18707
18767
  if (parsed.contentHash !== expectedHash) {
@@ -18813,165 +18873,6 @@ function normalizeTags(tags) {
18813
18873
  return Array.from(new Set(tags.map((tag) => tag.toLowerCase().replace(/[^\w-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "")).filter(Boolean))).slice(0, 32);
18814
18874
  }
18815
18875
 
18816
- // src/memory/maintenance.ts
18817
- var DEFAULT_LOW_UTILITY_MAX_CONFIDENCE = 0.45;
18818
- var DEFAULT_LOW_UTILITY_MIN_AGE_DAYS = 30;
18819
- async function buildMemoryMaintenanceReport(provider, options = {}) {
18820
- const now = options.now ?? new Date;
18821
- const limit = Math.max(1, Math.trunc(options.limit ?? 20));
18822
- const memories = await provider.list({
18823
- includeExpired: true,
18824
- includeInactive: true
18825
- });
18826
- const proposals = await loadMaintenanceProposals(provider, limit);
18827
- const recallUsage = provider.listRecallUsage ? await provider.listRecallUsage() : [];
18828
- const usageByMemory = summarizeRecallByMemory(recallUsage);
18829
- const usageByRole = summarizeRecallByRole(recallUsage);
18830
- const activeMemories = memories.filter((memory) => isActiveMemory(memory, now));
18831
- const deletedMemories = memories.filter((memory) => memory.metadata.deleted === true);
18832
- const expiredScratchMemories = memories.filter((memory) => memory.kind === "scratch" && isExpired(memory, now));
18833
- const supersededMemories = memories.filter((memory) => Boolean(memory.supersededBy));
18834
- const lowUtilityMemories = activeMemories.filter((memory) => isLowUtility(memory, usageByMemory, now, {
18835
- maxConfidence: options.lowUtilityMaxConfidence ?? DEFAULT_LOW_UTILITY_MAX_CONFIDENCE,
18836
- minAgeDays: options.lowUtilityMinAgeDays ?? DEFAULT_LOW_UTILITY_MIN_AGE_DAYS
18837
- })).sort(memorySort);
18838
- const neverRecalledMemories = activeMemories.filter((memory) => !usageByMemory.has(memory.id)).sort(memorySort);
18839
- const rejectedProposalReasons = proposals.filter((proposal) => proposal.status === "rejected").sort(proposalSort);
18840
- const pendingProposals = proposals.filter((proposal) => proposal.status === "pending").sort(proposalSort);
18841
- return {
18842
- generatedAt: now.toISOString(),
18843
- totalMemories: memories.length,
18844
- activeMemories: activeMemories.length,
18845
- deletedMemories: deletedMemories.slice(0, limit),
18846
- expiredScratchMemories: expiredScratchMemories.slice(0, limit),
18847
- supersededMemories: supersededMemories.slice(0, limit),
18848
- supersededChains: buildSupersededChains(memories).slice(0, limit),
18849
- lowUtilityMemories: lowUtilityMemories.slice(0, limit),
18850
- neverRecalledMemories: neverRecalledMemories.slice(0, limit),
18851
- mostRecalledMemories: Array.from(usageByMemory.values()).sort((a, b) => b.count - a.count || b.lastRecalledAt.localeCompare(a.lastRecalledAt) || a.memoryId.localeCompare(b.memoryId)).slice(0, limit),
18852
- recallByAgentRole: Array.from(usageByRole.values()).sort((a, b) => b.count - a.count || a.agentRole.localeCompare(b.agentRole)).slice(0, limit),
18853
- rejectedProposalReasons: rejectedProposalReasons.slice(0, limit),
18854
- pendingProposals: pendingProposals.slice(0, limit),
18855
- recallEventCount: recallUsage.length
18856
- };
18857
- }
18858
- function shouldCompactMemory(memory, now = new Date) {
18859
- if (memory.metadata.deleted === true)
18860
- return "deleted";
18861
- if (memory.supersededBy)
18862
- return "superseded";
18863
- if (memory.kind === "scratch" && isExpired(memory, now)) {
18864
- return "expired_scratch";
18865
- }
18866
- return null;
18867
- }
18868
- function isActiveMemory(memory, now) {
18869
- return memory.metadata.deleted !== true && !memory.supersededBy && !isExpired(memory, now);
18870
- }
18871
- function isLowUtility(memory, usageByMemory, now, options) {
18872
- if (usageByMemory.has(memory.id))
18873
- return false;
18874
- const updated = Date.parse(memory.updatedAt);
18875
- const ageDays = Number.isFinite(updated) ? (now.getTime() - updated) / (24 * 60 * 60 * 1000) : 0;
18876
- return memory.confidence <= options.maxConfidence || ageDays >= options.minAgeDays;
18877
- }
18878
- function summarizeRecallByMemory(usageEvents) {
18879
- const byMemory = new Map;
18880
- for (const event of usageEvents) {
18881
- event.memoryIds.forEach((memoryId, index) => {
18882
- const role = event.agentRole ?? "unknown";
18883
- const existing = byMemory.get(memoryId) ?? {
18884
- memoryId,
18885
- count: 0,
18886
- lastRecalledAt: event.timestamp,
18887
- agentRoles: {},
18888
- averageScore: 0,
18889
- scoreTotal: 0,
18890
- scoreCount: 0
18891
- };
18892
- existing.count++;
18893
- existing.lastRecalledAt = event.timestamp > existing.lastRecalledAt ? event.timestamp : existing.lastRecalledAt;
18894
- existing.agentRoles[role] = (existing.agentRoles[role] ?? 0) + 1;
18895
- const score = event.scores[index];
18896
- if (typeof score === "number" && Number.isFinite(score)) {
18897
- existing.scoreTotal += score;
18898
- existing.scoreCount++;
18899
- existing.averageScore = existing.scoreTotal / existing.scoreCount;
18900
- }
18901
- byMemory.set(memoryId, existing);
18902
- });
18903
- }
18904
- return new Map(Array.from(byMemory, ([memoryId, value]) => [
18905
- memoryId,
18906
- {
18907
- memoryId,
18908
- count: value.count,
18909
- lastRecalledAt: value.lastRecalledAt,
18910
- agentRoles: value.agentRoles,
18911
- averageScore: value.averageScore
18912
- }
18913
- ]));
18914
- }
18915
- async function loadMaintenanceProposals(provider, limit) {
18916
- if (!provider.listProposals)
18917
- return [];
18918
- const [pending, rejected, recent] = await Promise.all([
18919
- provider.listProposals({ status: "pending", limit }),
18920
- provider.listProposals({ status: "rejected", limit }),
18921
- provider.listProposals({ limit: Math.max(limit * 4, 100) })
18922
- ]);
18923
- const byId = new Map;
18924
- for (const proposal of [...pending, ...rejected, ...recent]) {
18925
- byId.set(proposal.id, proposal);
18926
- }
18927
- return Array.from(byId.values());
18928
- }
18929
- function summarizeRecallByRole(usageEvents) {
18930
- const byRole = new Map;
18931
- for (const event of usageEvents) {
18932
- const role = event.agentRole ?? "unknown";
18933
- const existing = byRole.get(role) ?? {
18934
- agentRole: role,
18935
- count: 0,
18936
- memoryIds: {}
18937
- };
18938
- existing.count++;
18939
- for (const memoryId of event.memoryIds) {
18940
- existing.memoryIds[memoryId] = (existing.memoryIds[memoryId] ?? 0) + 1;
18941
- }
18942
- byRole.set(role, existing);
18943
- }
18944
- return byRole;
18945
- }
18946
- function buildSupersededChains(memories) {
18947
- const byId = new Map(memories.map((memory) => [memory.id, memory]));
18948
- const supersededIds = new Set(memories.filter((memory) => memory.supersededBy).map((memory) => memory.id));
18949
- const roots = memories.filter((memory) => memory.supersededBy && !(memory.supersedes ?? []).some((id) => supersededIds.has(id)));
18950
- return roots.map((root) => {
18951
- const chain = [root.id];
18952
- const seen = new Set(chain);
18953
- let cursor = root;
18954
- while (cursor?.supersededBy && !seen.has(cursor.supersededBy)) {
18955
- chain.push(cursor.supersededBy);
18956
- seen.add(cursor.supersededBy);
18957
- cursor = byId.get(cursor.supersededBy);
18958
- }
18959
- return {
18960
- rootId: root.id,
18961
- chain,
18962
- reason: typeof root.metadata.supersedeReason === "string" ? root.metadata.supersedeReason : undefined
18963
- };
18964
- });
18965
- }
18966
- function memorySort(a, b) {
18967
- return b.updatedAt.localeCompare(a.updatedAt) || a.id.localeCompare(b.id);
18968
- }
18969
- function proposalSort(a, b) {
18970
- const aTime = a.reviewedAt ?? a.createdAt;
18971
- const bTime = b.reviewedAt ?? b.createdAt;
18972
- return bTime.localeCompare(aTime) || a.id.localeCompare(b.id);
18973
- }
18974
-
18975
18876
  // src/memory/role-profiles.ts
18976
18877
  var MEMORY_RECALL_PROFILES = {
18977
18878
  architect: {
@@ -19079,6 +18980,14 @@ var SCORING_WEIGHTS = {
19079
18980
  function tokenize(text) {
19080
18981
  return new Set(text.toLowerCase().replace(/[^\w\s-]/g, " ").split(/\s+/).map((token) => token.trim()).filter(Boolean));
19081
18982
  }
18983
+ function importanceScore(input, weights) {
18984
+ const recency = input.daysSinceLastRecall === null ? 0 : Math.exp(-weights.lambda * Math.max(0, input.daysSinceLastRecall));
18985
+ const denom = Math.log1p(Math.max(1, weights.n));
18986
+ const frequency = denom === 0 ? 0 : Math.log1p(Math.max(0, input.retrievalCount)) / denom;
18987
+ const freshness = Math.exp(-weights.mu * Math.max(0, input.daysSinceCreated));
18988
+ const confidence = Math.min(1, Math.max(0, input.confidence));
18989
+ return weights.wRecency * recency + weights.wFrequency * frequency + weights.wFreshness * freshness + weights.wConfidence * confidence;
18990
+ }
19082
18991
  function normalizeKindText(kind) {
19083
18992
  return kind.replace(/_/g, " ");
19084
18993
  }
@@ -19258,6 +19167,180 @@ function unionTokens(...sets) {
19258
19167
  return union;
19259
19168
  }
19260
19169
 
19170
+ // src/memory/maintenance.ts
19171
+ var DEFAULT_IMPORTANCE_WEIGHTS = {
19172
+ wRecency: 0.2,
19173
+ wFrequency: 0.2,
19174
+ wFreshness: 0.15,
19175
+ wConfidence: 0.25,
19176
+ lambda: 0.05,
19177
+ mu: 0.01,
19178
+ n: 50
19179
+ };
19180
+ var DEFAULT_IMPORTANCE_THRESHOLD = 0.2;
19181
+ var MS_PER_DAY2 = 24 * 60 * 60 * 1000;
19182
+ async function buildMemoryMaintenanceReport(provider, options = {}) {
19183
+ const now = options.now ?? new Date;
19184
+ const limit = Math.max(1, Math.trunc(options.limit ?? 20));
19185
+ const memories = await provider.list({
19186
+ includeExpired: true,
19187
+ includeInactive: true
19188
+ });
19189
+ const proposals = await loadMaintenanceProposals(provider, limit);
19190
+ const recallUsage = provider.listRecallUsage ? await provider.listRecallUsage() : [];
19191
+ const usageByMemory = summarizeRecallByMemory(recallUsage);
19192
+ const usageByRole = summarizeRecallByRole(recallUsage);
19193
+ const activeMemories = memories.filter((memory) => isActiveMemory(memory, now));
19194
+ const deletedMemories = memories.filter((memory) => memory.metadata.deleted === true);
19195
+ const expiredScratchMemories = memories.filter((memory) => memory.kind === "scratch" && isExpired(memory, now));
19196
+ const supersededMemories = memories.filter((memory) => Boolean(memory.supersededBy));
19197
+ const lowUtilityMemories = activeMemories.filter((memory) => isLowUtility(memory, usageByMemory, now, {
19198
+ weights: options.importanceWeights ?? DEFAULT_IMPORTANCE_WEIGHTS,
19199
+ threshold: options.importanceThreshold ?? DEFAULT_IMPORTANCE_THRESHOLD
19200
+ })).sort(memorySort);
19201
+ const neverRecalledMemories = activeMemories.filter((memory) => !usageByMemory.has(memory.id)).sort(memorySort);
19202
+ const rejectedProposalReasons = proposals.filter((proposal) => proposal.status === "rejected").sort(proposalSort);
19203
+ const pendingProposals = proposals.filter((proposal) => proposal.status === "pending").sort(proposalSort);
19204
+ return {
19205
+ generatedAt: now.toISOString(),
19206
+ totalMemories: memories.length,
19207
+ activeMemories: activeMemories.length,
19208
+ deletedMemories: deletedMemories.slice(0, limit),
19209
+ expiredScratchMemories: expiredScratchMemories.slice(0, limit),
19210
+ supersededMemories: supersededMemories.slice(0, limit),
19211
+ supersededChains: buildSupersededChains(memories).slice(0, limit),
19212
+ lowUtilityMemories: lowUtilityMemories.slice(0, limit),
19213
+ neverRecalledMemories: neverRecalledMemories.slice(0, limit),
19214
+ mostRecalledMemories: Array.from(usageByMemory.values()).sort((a, b) => b.count - a.count || b.lastRecalledAt.localeCompare(a.lastRecalledAt) || a.memoryId.localeCompare(b.memoryId)).slice(0, limit),
19215
+ recallByAgentRole: Array.from(usageByRole.values()).sort((a, b) => b.count - a.count || a.agentRole.localeCompare(b.agentRole)).slice(0, limit),
19216
+ rejectedProposalReasons: rejectedProposalReasons.slice(0, limit),
19217
+ pendingProposals: pendingProposals.slice(0, limit),
19218
+ recallEventCount: recallUsage.length
19219
+ };
19220
+ }
19221
+ function shouldCompactMemory(memory, now = new Date) {
19222
+ if (memory.metadata.deleted === true)
19223
+ return "deleted";
19224
+ if (memory.supersededBy)
19225
+ return "superseded";
19226
+ if (memory.kind === "scratch" && isExpired(memory, now)) {
19227
+ return "expired_scratch";
19228
+ }
19229
+ return null;
19230
+ }
19231
+ function isActiveMemory(memory, now) {
19232
+ return memory.metadata.deleted !== true && !memory.supersededBy && !isExpired(memory, now);
19233
+ }
19234
+ function isLowUtility(memory, usageByMemory, now, options) {
19235
+ if (usageByMemory.has(memory.id))
19236
+ return false;
19237
+ const created = Date.parse(memory.createdAt);
19238
+ const daysSinceCreated = Number.isFinite(created) ? Math.max(0, (now.getTime() - created) / MS_PER_DAY2) : 0;
19239
+ const importance = importanceScore({
19240
+ confidence: memory.confidence,
19241
+ retrievalCount: 0,
19242
+ daysSinceLastRecall: null,
19243
+ daysSinceCreated
19244
+ }, options.weights);
19245
+ return importance < options.threshold;
19246
+ }
19247
+ function summarizeRecallByMemory(usageEvents) {
19248
+ const byMemory = new Map;
19249
+ for (const event of usageEvents) {
19250
+ event.memoryIds.forEach((memoryId, index) => {
19251
+ const role = event.agentRole ?? "unknown";
19252
+ const existing = byMemory.get(memoryId) ?? {
19253
+ memoryId,
19254
+ count: 0,
19255
+ lastRecalledAt: event.timestamp,
19256
+ agentRoles: {},
19257
+ averageScore: 0,
19258
+ scoreTotal: 0,
19259
+ scoreCount: 0
19260
+ };
19261
+ existing.count++;
19262
+ existing.lastRecalledAt = event.timestamp > existing.lastRecalledAt ? event.timestamp : existing.lastRecalledAt;
19263
+ existing.agentRoles[role] = (existing.agentRoles[role] ?? 0) + 1;
19264
+ const score = event.scores[index];
19265
+ if (typeof score === "number" && Number.isFinite(score)) {
19266
+ existing.scoreTotal += score;
19267
+ existing.scoreCount++;
19268
+ existing.averageScore = existing.scoreTotal / existing.scoreCount;
19269
+ }
19270
+ byMemory.set(memoryId, existing);
19271
+ });
19272
+ }
19273
+ return new Map(Array.from(byMemory, ([memoryId, value]) => [
19274
+ memoryId,
19275
+ {
19276
+ memoryId,
19277
+ count: value.count,
19278
+ lastRecalledAt: value.lastRecalledAt,
19279
+ agentRoles: value.agentRoles,
19280
+ averageScore: value.averageScore
19281
+ }
19282
+ ]));
19283
+ }
19284
+ async function loadMaintenanceProposals(provider, limit) {
19285
+ if (!provider.listProposals)
19286
+ return [];
19287
+ const [pending, rejected, recent] = await Promise.all([
19288
+ provider.listProposals({ status: "pending", limit }),
19289
+ provider.listProposals({ status: "rejected", limit }),
19290
+ provider.listProposals({ limit: Math.max(limit * 4, 100) })
19291
+ ]);
19292
+ const byId = new Map;
19293
+ for (const proposal of [...pending, ...rejected, ...recent]) {
19294
+ byId.set(proposal.id, proposal);
19295
+ }
19296
+ return Array.from(byId.values());
19297
+ }
19298
+ function summarizeRecallByRole(usageEvents) {
19299
+ const byRole = new Map;
19300
+ for (const event of usageEvents) {
19301
+ const role = event.agentRole ?? "unknown";
19302
+ const existing = byRole.get(role) ?? {
19303
+ agentRole: role,
19304
+ count: 0,
19305
+ memoryIds: {}
19306
+ };
19307
+ existing.count++;
19308
+ for (const memoryId of event.memoryIds) {
19309
+ existing.memoryIds[memoryId] = (existing.memoryIds[memoryId] ?? 0) + 1;
19310
+ }
19311
+ byRole.set(role, existing);
19312
+ }
19313
+ return byRole;
19314
+ }
19315
+ function buildSupersededChains(memories) {
19316
+ const byId = new Map(memories.map((memory) => [memory.id, memory]));
19317
+ const supersededIds = new Set(memories.filter((memory) => memory.supersededBy).map((memory) => memory.id));
19318
+ const roots = memories.filter((memory) => memory.supersededBy && !(memory.supersedes ?? []).some((id) => supersededIds.has(id)));
19319
+ return roots.map((root) => {
19320
+ const chain = [root.id];
19321
+ const seen = new Set(chain);
19322
+ let cursor = root;
19323
+ while (cursor?.supersededBy && !seen.has(cursor.supersededBy)) {
19324
+ chain.push(cursor.supersededBy);
19325
+ seen.add(cursor.supersededBy);
19326
+ cursor = byId.get(cursor.supersededBy);
19327
+ }
19328
+ return {
19329
+ rootId: root.id,
19330
+ chain,
19331
+ reason: typeof root.metadata.supersedeReason === "string" ? root.metadata.supersedeReason : undefined
19332
+ };
19333
+ });
19334
+ }
19335
+ function memorySort(a, b) {
19336
+ return b.updatedAt.localeCompare(a.updatedAt) || a.id.localeCompare(b.id);
19337
+ }
19338
+ function proposalSort(a, b) {
19339
+ const aTime = a.reviewedAt ?? a.createdAt;
19340
+ const bTime = b.reviewedAt ?? b.createdAt;
19341
+ return bTime.localeCompare(aTime) || a.id.localeCompare(b.id);
19342
+ }
19343
+
19261
19344
  // src/memory/local-jsonl-provider.ts
19262
19345
  class LocalJsonlMemoryProvider {
19263
19346
  name = "local-jsonl";
@@ -21521,8 +21604,33 @@ var AgentOutputMemorySchema = exports_external.object({
21521
21604
  var CuratorOutputMemoryDecisionSchema = exports_external.object({
21522
21605
  curatorMemoryDecisions: exports_external.array(CuratorMemoryDecisionSchema).max(20).optional()
21523
21606
  }).passthrough();
21607
+ // src/memory/consolidation-log.ts
21608
+ import { appendFile as appendFile4, mkdir as mkdir12, readFile as readFile15 } from "fs/promises";
21609
+ import * as path43 from "path";
21610
+ var LOG_RELATIVE_PATH = path43.join("memory", "consolidation-log.jsonl");
21611
+ async function readConsolidationLog(directory) {
21612
+ const filePath = validateSwarmPath(directory, LOG_RELATIVE_PATH);
21613
+ let raw;
21614
+ try {
21615
+ raw = await readFile15(filePath, "utf-8");
21616
+ } catch {
21617
+ return [];
21618
+ }
21619
+ const records = [];
21620
+ for (const line of raw.split(`
21621
+ `)) {
21622
+ const trimmed = line.trim();
21623
+ if (!trimmed)
21624
+ continue;
21625
+ try {
21626
+ records.push(JSON.parse(trimmed));
21627
+ } catch {}
21628
+ }
21629
+ return records;
21630
+ }
21631
+
21524
21632
  // src/commands/memory.ts
21525
- var PACKAGE_ROOT = path43.resolve(resolvePackageRootFromModule(fileURLToPath2(import.meta.url)));
21633
+ var PACKAGE_ROOT = path44.resolve(resolvePackageRootFromModule(fileURLToPath2(import.meta.url)));
21526
21634
  async function handleMemoryCommand(_directory, _args) {
21527
21635
  return [
21528
21636
  "## Swarm Memory",
@@ -21535,10 +21643,38 @@ async function handleMemoryCommand(_directory, _args) {
21535
21643
  "- `/swarm memory export` - export current memory and proposals to `.swarm/memory/export/*.jsonl`",
21536
21644
  "- `/swarm memory import` - import `.swarm/memory/{memories,proposals}.jsonl` into SQLite",
21537
21645
  "- `/swarm memory migrate` - run the one-time legacy JSONL to SQLite migration",
21538
- "- `/swarm memory evaluate --json` - run the golden recall evaluation fixtures and emit a JSON report"
21646
+ "- `/swarm memory evaluate --json` - run the golden recall evaluation fixtures and emit a JSON report",
21647
+ "- `/swarm memory consolidation-log [--limit <n>]` - summarize recent episodic\u2192semantic consolidation passes (max 50 per query)"
21539
21648
  ].join(`
21540
21649
  `);
21541
21650
  }
21651
+ async function handleMemoryConsolidationLogCommand(directory, args) {
21652
+ const parsed = parseMaintenanceArgs(args, {
21653
+ usage: "Usage: /swarm memory consolidation-log [--limit <n>] (max 50 records per query)",
21654
+ allowConfirm: false
21655
+ });
21656
+ if ("error" in parsed)
21657
+ return parsed.error;
21658
+ const limit = Math.min(parsed.limit, 50);
21659
+ const records = await readConsolidationLog(directory);
21660
+ const recent = records.slice(-limit).reverse();
21661
+ const lines = [
21662
+ "## Swarm Memory Consolidation Log",
21663
+ "",
21664
+ `- Total recorded passes: \`${records.length}\``,
21665
+ `- Showing: \`${recent.length}\``
21666
+ ];
21667
+ if (recent.length === 0) {
21668
+ lines.push("", "No consolidation passes have been recorded yet.");
21669
+ return lines.join(`
21670
+ `);
21671
+ }
21672
+ for (const record of recent) {
21673
+ lines.push("", `### Phase ${record.phaseNumber} \u2014 ${record.completedAt}`, `- Run: \`${record.runId ?? "unknown"}\``, `- Clusters: \`${record.clusterCount}\` (deferred \`${record.clustersDeferred}\`)`, `- Decisions applied: \`${record.decisionsEmitted}\` (added \`${record.added}\`, superseded \`${record.superseded}\`)`, `- Contradictions: \`${record.contradictionsDetected}\` | Deduped: \`${record.deduped}\` | Proposed: \`${record.proposed}\``, `- Memories decayed: \`${record.memoriesDecayed}\` | Errored: \`${record.errored}\``, `- Processed proposals: \`${record.processedProposalIds.length}\``);
21674
+ }
21675
+ return lines.join(`
21676
+ `);
21677
+ }
21542
21678
  async function handleMemoryStatusCommand(directory, _args) {
21543
21679
  const config = resolveCommandMemoryConfig(directory);
21544
21680
  const storageDir = resolveMemoryStorageDir(directory, config);
@@ -21751,10 +21887,11 @@ function createMaintenanceProvider(directory, config) {
21751
21887
  return createConfiguredMemoryProvider(directory, config);
21752
21888
  }
21753
21889
  function maintenanceReportOptions(config, limit) {
21890
+ const { threshold, ...weights } = config.maintenance.importance;
21754
21891
  return {
21755
21892
  limit,
21756
- lowUtilityMaxConfidence: config.maintenance.lowUtilityMaxConfidence,
21757
- lowUtilityMinAgeDays: config.maintenance.lowUtilityMinAgeDays
21893
+ importanceWeights: weights,
21894
+ importanceThreshold: threshold
21758
21895
  };
21759
21896
  }
21760
21897
  async function handleMemoryEvaluateCommand(directory, args) {
@@ -21791,7 +21928,7 @@ function resolveCommandMemoryConfig(directory) {
21791
21928
  }
21792
21929
  function parseEvaluateArgs(directory, args) {
21793
21930
  let json = false;
21794
- let fixtureDirectory = path43.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall");
21931
+ let fixtureDirectory = path44.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall");
21795
21932
  for (let i = 0;i < args.length; i++) {
21796
21933
  const arg = args[i];
21797
21934
  if (arg === "--json") {
@@ -21805,10 +21942,10 @@ function parseEvaluateArgs(directory, args) {
21805
21942
  error: "Usage: /swarm memory evaluate [--json] [--fixtures <directory>]"
21806
21943
  };
21807
21944
  }
21808
- const resolvedFixtures = path43.resolve(directory, next);
21809
- const canonical = path43.normalize(resolvedFixtures) + path43.sep;
21810
- const allowedRootA = path43.normalize(directory) + path43.sep;
21811
- const allowedRootB = path43.normalize(path43.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall")) + path43.sep;
21945
+ const resolvedFixtures = path44.resolve(directory, next);
21946
+ const canonical = path44.normalize(resolvedFixtures) + path44.sep;
21947
+ const allowedRootA = path44.normalize(directory) + path44.sep;
21948
+ const allowedRootB = path44.normalize(path44.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall")) + path44.sep;
21812
21949
  if (!canonical.startsWith(allowedRootA) && !canonical.startsWith(allowedRootB)) {
21813
21950
  return {
21814
21951
  error: "--fixtures <directory> must resolve under the project directory or the bundled tests/fixtures/memory-recall directory"
@@ -21847,15 +21984,15 @@ function parseMaintenanceArgs(args, options) {
21847
21984
  return { limit, confirm };
21848
21985
  }
21849
21986
  function resolvePackageRootFromModule(modulePath) {
21850
- const moduleDir = path43.dirname(modulePath);
21851
- const leaf = path43.basename(moduleDir);
21987
+ const moduleDir = path44.dirname(modulePath);
21988
+ const leaf = path44.basename(moduleDir);
21852
21989
  if (leaf === "commands" || leaf === "cli") {
21853
- return path43.resolve(moduleDir, "..", "..");
21990
+ return path44.resolve(moduleDir, "..", "..");
21854
21991
  }
21855
21992
  if (leaf === "dist") {
21856
- return path43.resolve(moduleDir, "..");
21993
+ return path44.resolve(moduleDir, "..");
21857
21994
  }
21858
- return path43.resolve(moduleDir, "..");
21995
+ return path44.resolve(moduleDir, "..");
21859
21996
  }
21860
21997
  function formatMigrationResult(label, report) {
21861
21998
  if (!report) {
@@ -22550,11 +22687,11 @@ var _internals36 = {
22550
22687
 
22551
22688
  // src/services/preflight-service.ts
22552
22689
  import * as fs24 from "fs";
22553
- import * as path50 from "path";
22690
+ import * as path51 from "path";
22554
22691
 
22555
22692
  // src/tools/lint.ts
22556
22693
  import * as fs18 from "fs";
22557
- import * as path44 from "path";
22694
+ import * as path45 from "path";
22558
22695
 
22559
22696
  // src/utils/path-security.ts
22560
22697
  function containsPathTraversal(str) {
@@ -22610,9 +22747,9 @@ function validateArgs(args) {
22610
22747
  }
22611
22748
  function getLinterCommand(linter, mode, projectDir) {
22612
22749
  const isWindows = process.platform === "win32";
22613
- const binDir = path44.join(projectDir, "node_modules", ".bin");
22614
- const biomeBin = isWindows ? path44.join(binDir, "biome.EXE") : path44.join(binDir, "biome");
22615
- const eslintBin = isWindows ? path44.join(binDir, "eslint.cmd") : path44.join(binDir, "eslint");
22750
+ const binDir = path45.join(projectDir, "node_modules", ".bin");
22751
+ const biomeBin = isWindows ? path45.join(binDir, "biome.EXE") : path45.join(binDir, "biome");
22752
+ const eslintBin = isWindows ? path45.join(binDir, "eslint.cmd") : path45.join(binDir, "eslint");
22616
22753
  switch (linter) {
22617
22754
  case "biome":
22618
22755
  if (mode === "fix") {
@@ -22628,7 +22765,7 @@ function getLinterCommand(linter, mode, projectDir) {
22628
22765
  }
22629
22766
  function getAdditionalLinterCommand(linter, mode, cwd) {
22630
22767
  const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
22631
- const gradlew = fs18.existsSync(path44.join(cwd, gradlewName)) ? path44.join(cwd, gradlewName) : null;
22768
+ const gradlew = fs18.existsSync(path45.join(cwd, gradlewName)) ? path45.join(cwd, gradlewName) : null;
22632
22769
  switch (linter) {
22633
22770
  case "ruff":
22634
22771
  return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
@@ -22662,10 +22799,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
22662
22799
  }
22663
22800
  }
22664
22801
  function detectRuff(cwd) {
22665
- if (fs18.existsSync(path44.join(cwd, "ruff.toml")))
22802
+ if (fs18.existsSync(path45.join(cwd, "ruff.toml")))
22666
22803
  return isCommandAvailable("ruff");
22667
22804
  try {
22668
- const pyproject = path44.join(cwd, "pyproject.toml");
22805
+ const pyproject = path45.join(cwd, "pyproject.toml");
22669
22806
  if (fs18.existsSync(pyproject)) {
22670
22807
  const content = fs18.readFileSync(pyproject, "utf-8");
22671
22808
  if (content.includes("[tool.ruff]"))
@@ -22675,19 +22812,19 @@ function detectRuff(cwd) {
22675
22812
  return false;
22676
22813
  }
22677
22814
  function detectClippy(cwd) {
22678
- return fs18.existsSync(path44.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
22815
+ return fs18.existsSync(path45.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
22679
22816
  }
22680
22817
  function detectGolangciLint(cwd) {
22681
- return fs18.existsSync(path44.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
22818
+ return fs18.existsSync(path45.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
22682
22819
  }
22683
22820
  function detectCheckstyle(cwd) {
22684
- const hasMaven = fs18.existsSync(path44.join(cwd, "pom.xml"));
22685
- const hasGradle = fs18.existsSync(path44.join(cwd, "build.gradle")) || fs18.existsSync(path44.join(cwd, "build.gradle.kts"));
22686
- const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs18.existsSync(path44.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
22821
+ const hasMaven = fs18.existsSync(path45.join(cwd, "pom.xml"));
22822
+ const hasGradle = fs18.existsSync(path45.join(cwd, "build.gradle")) || fs18.existsSync(path45.join(cwd, "build.gradle.kts"));
22823
+ const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs18.existsSync(path45.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
22687
22824
  return (hasMaven || hasGradle) && hasBinary;
22688
22825
  }
22689
22826
  function detectKtlint(cwd) {
22690
- const hasKotlin = fs18.existsSync(path44.join(cwd, "build.gradle.kts")) || fs18.existsSync(path44.join(cwd, "build.gradle")) || (() => {
22827
+ const hasKotlin = fs18.existsSync(path45.join(cwd, "build.gradle.kts")) || fs18.existsSync(path45.join(cwd, "build.gradle")) || (() => {
22691
22828
  try {
22692
22829
  return fs18.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
22693
22830
  } catch {
@@ -22706,11 +22843,11 @@ function detectDotnetFormat(cwd) {
22706
22843
  }
22707
22844
  }
22708
22845
  function detectCppcheck(cwd) {
22709
- if (fs18.existsSync(path44.join(cwd, "CMakeLists.txt"))) {
22846
+ if (fs18.existsSync(path45.join(cwd, "CMakeLists.txt"))) {
22710
22847
  return isCommandAvailable("cppcheck");
22711
22848
  }
22712
22849
  try {
22713
- const dirsToCheck = [cwd, path44.join(cwd, "src")];
22850
+ const dirsToCheck = [cwd, path45.join(cwd, "src")];
22714
22851
  const hasCpp = dirsToCheck.some((dir) => {
22715
22852
  try {
22716
22853
  return fs18.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
@@ -22724,13 +22861,13 @@ function detectCppcheck(cwd) {
22724
22861
  }
22725
22862
  }
22726
22863
  function detectSwiftlint(cwd) {
22727
- return fs18.existsSync(path44.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
22864
+ return fs18.existsSync(path45.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
22728
22865
  }
22729
22866
  function detectDartAnalyze(cwd) {
22730
- return fs18.existsSync(path44.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
22867
+ return fs18.existsSync(path45.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
22731
22868
  }
22732
22869
  function detectRubocop(cwd) {
22733
- return (fs18.existsSync(path44.join(cwd, "Gemfile")) || fs18.existsSync(path44.join(cwd, "gems.rb")) || fs18.existsSync(path44.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
22870
+ return (fs18.existsSync(path45.join(cwd, "Gemfile")) || fs18.existsSync(path45.join(cwd, "gems.rb")) || fs18.existsSync(path45.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
22734
22871
  }
22735
22872
  function detectAdditionalLinter(cwd) {
22736
22873
  if (detectRuff(cwd))
@@ -22758,10 +22895,10 @@ function detectAdditionalLinter(cwd) {
22758
22895
  function findBinInAncestors(startDir, binName) {
22759
22896
  let dir = startDir;
22760
22897
  while (true) {
22761
- const candidate = path44.join(dir, "node_modules", ".bin", binName);
22898
+ const candidate = path45.join(dir, "node_modules", ".bin", binName);
22762
22899
  if (fs18.existsSync(candidate))
22763
22900
  return candidate;
22764
- const parent = path44.dirname(dir);
22901
+ const parent = path45.dirname(dir);
22765
22902
  if (parent === dir)
22766
22903
  break;
22767
22904
  dir = parent;
@@ -22770,10 +22907,10 @@ function findBinInAncestors(startDir, binName) {
22770
22907
  }
22771
22908
  function findBinInEnvPath(binName) {
22772
22909
  const searchPath = process.env.PATH ?? "";
22773
- for (const dir of searchPath.split(path44.delimiter)) {
22910
+ for (const dir of searchPath.split(path45.delimiter)) {
22774
22911
  if (!dir)
22775
22912
  continue;
22776
- const candidate = path44.join(dir, binName);
22913
+ const candidate = path45.join(dir, binName);
22777
22914
  if (fs18.existsSync(candidate))
22778
22915
  return candidate;
22779
22916
  }
@@ -22786,13 +22923,13 @@ async function detectAvailableLinter(directory) {
22786
22923
  return null;
22787
22924
  const projectDir = directory;
22788
22925
  const isWindows = process.platform === "win32";
22789
- const biomeBin = isWindows ? path44.join(projectDir, "node_modules", ".bin", "biome.EXE") : path44.join(projectDir, "node_modules", ".bin", "biome");
22790
- const eslintBin = isWindows ? path44.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path44.join(projectDir, "node_modules", ".bin", "eslint");
22926
+ const biomeBin = isWindows ? path45.join(projectDir, "node_modules", ".bin", "biome.EXE") : path45.join(projectDir, "node_modules", ".bin", "biome");
22927
+ const eslintBin = isWindows ? path45.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path45.join(projectDir, "node_modules", ".bin", "eslint");
22791
22928
  const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
22792
22929
  if (localResult)
22793
22930
  return localResult;
22794
- const biomeAncestor = findBinInAncestors(path44.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
22795
- const eslintAncestor = findBinInAncestors(path44.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
22931
+ const biomeAncestor = findBinInAncestors(path45.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
22932
+ const eslintAncestor = findBinInAncestors(path45.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
22796
22933
  if (biomeAncestor || eslintAncestor) {
22797
22934
  return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
22798
22935
  }
@@ -23006,7 +23143,7 @@ var _internals37 = {
23006
23143
 
23007
23144
  // src/tools/secretscan.ts
23008
23145
  import * as fs19 from "fs";
23009
- import * as path45 from "path";
23146
+ import * as path46 from "path";
23010
23147
  var MAX_FILE_PATH_LENGTH = 500;
23011
23148
  var MAX_FILE_SIZE_BYTES = 512 * 1024;
23012
23149
  var MAX_FILES_SCANNED = 1000;
@@ -23233,7 +23370,7 @@ function isGlobOrPathPattern(pattern) {
23233
23370
  return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
23234
23371
  }
23235
23372
  function loadSecretScanIgnore(scanDir) {
23236
- const ignorePath = path45.join(scanDir, ".secretscanignore");
23373
+ const ignorePath = path46.join(scanDir, ".secretscanignore");
23237
23374
  try {
23238
23375
  if (!fs19.existsSync(ignorePath))
23239
23376
  return [];
@@ -23256,7 +23393,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
23256
23393
  if (exactNames.has(entry))
23257
23394
  return true;
23258
23395
  for (const pattern of globPatterns) {
23259
- if (path45.matchesGlob(relPath, pattern))
23396
+ if (path46.matchesGlob(relPath, pattern))
23260
23397
  return true;
23261
23398
  }
23262
23399
  return false;
@@ -23277,7 +23414,7 @@ function validateDirectoryInput(dir) {
23277
23414
  return null;
23278
23415
  }
23279
23416
  function isBinaryFile(filePath, buffer) {
23280
- const ext = path45.extname(filePath).toLowerCase();
23417
+ const ext = path46.extname(filePath).toLowerCase();
23281
23418
  if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
23282
23419
  return true;
23283
23420
  }
@@ -23414,9 +23551,9 @@ function isSymlinkLoop(realPath, visited) {
23414
23551
  return false;
23415
23552
  }
23416
23553
  function isPathWithinScope(realPath, scanDir) {
23417
- const resolvedScanDir = path45.resolve(scanDir);
23418
- const resolvedRealPath = path45.resolve(realPath);
23419
- return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path45.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
23554
+ const resolvedScanDir = path46.resolve(scanDir);
23555
+ const resolvedRealPath = path46.resolve(realPath);
23556
+ return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path46.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
23420
23557
  }
23421
23558
  function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
23422
23559
  skippedDirs: 0,
@@ -23442,8 +23579,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
23442
23579
  return a.localeCompare(b);
23443
23580
  });
23444
23581
  for (const entry of entries) {
23445
- const fullPath = path45.join(dir, entry);
23446
- const relPath = path45.relative(scanDir, fullPath).replace(/\\/g, "/");
23582
+ const fullPath = path46.join(dir, entry);
23583
+ const relPath = path46.relative(scanDir, fullPath).replace(/\\/g, "/");
23447
23584
  if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
23448
23585
  stats.skippedDirs++;
23449
23586
  continue;
@@ -23478,7 +23615,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
23478
23615
  const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
23479
23616
  files.push(...subFiles);
23480
23617
  } else if (lstat2.isFile()) {
23481
- const ext = path45.extname(fullPath).toLowerCase();
23618
+ const ext = path46.extname(fullPath).toLowerCase();
23482
23619
  if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
23483
23620
  files.push(fullPath);
23484
23621
  } else {
@@ -23544,7 +23681,7 @@ var secretscan = createSwarmTool({
23544
23681
  }
23545
23682
  }
23546
23683
  try {
23547
- const _scanDirRaw = path45.resolve(directory);
23684
+ const _scanDirRaw = path46.resolve(directory);
23548
23685
  const scanDir = (() => {
23549
23686
  try {
23550
23687
  return fs19.realpathSync(_scanDirRaw);
@@ -23707,11 +23844,11 @@ var _internals38 = {
23707
23844
 
23708
23845
  // src/tools/test-runner.ts
23709
23846
  import * as fs23 from "fs";
23710
- import * as path49 from "path";
23847
+ import * as path50 from "path";
23711
23848
 
23712
23849
  // src/test-impact/analyzer.ts
23713
23850
  import fs20 from "fs";
23714
- import path46 from "path";
23851
+ import path47 from "path";
23715
23852
  var IMPORT_REGEX_ES = /import\s+[\s\S]*?\s+from\s+['"]([^'"]+)['"]/g;
23716
23853
  var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
23717
23854
  var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
@@ -23752,8 +23889,8 @@ function resolveRelativeImport(fromDir, importPath) {
23752
23889
  if (!importPath.startsWith(".")) {
23753
23890
  return null;
23754
23891
  }
23755
- const resolved = path46.resolve(fromDir, importPath);
23756
- if (path46.extname(resolved)) {
23892
+ const resolved = path47.resolve(fromDir, importPath);
23893
+ if (path47.extname(resolved)) {
23757
23894
  if (fs20.existsSync(resolved) && fs20.statSync(resolved).isFile()) {
23758
23895
  return normalizePath2(resolved);
23759
23896
  }
@@ -23773,20 +23910,20 @@ function resolvePythonImport(fromDir, module) {
23773
23910
  const leadingDots = module.match(/^\.+/)?.[0].length ?? 0;
23774
23911
  let baseDir = fromDir;
23775
23912
  for (let i = 1;i < leadingDots; i++) {
23776
- baseDir = path46.dirname(baseDir);
23913
+ baseDir = path47.dirname(baseDir);
23777
23914
  }
23778
23915
  const rest = module.slice(leadingDots);
23779
23916
  if (rest.length === 0) {
23780
- const initPath = path46.join(baseDir, "__init__.py");
23917
+ const initPath = path47.join(baseDir, "__init__.py");
23781
23918
  if (fs20.existsSync(initPath) && fs20.statSync(initPath).isFile()) {
23782
23919
  return normalizePath2(initPath);
23783
23920
  }
23784
23921
  return null;
23785
23922
  }
23786
- const subpath = rest.replace(/\./g, path46.sep);
23923
+ const subpath = rest.replace(/\./g, path47.sep);
23787
23924
  const candidates = [
23788
- `${path46.join(baseDir, subpath)}.py`,
23789
- path46.join(baseDir, subpath, "__init__.py")
23925
+ `${path47.join(baseDir, subpath)}.py`,
23926
+ path47.join(baseDir, subpath, "__init__.py")
23790
23927
  ];
23791
23928
  for (const c of candidates) {
23792
23929
  if (fs20.existsSync(c) && fs20.statSync(c).isFile())
@@ -23796,7 +23933,7 @@ function resolvePythonImport(fromDir, module) {
23796
23933
  }
23797
23934
  var goModuleCache = new Map;
23798
23935
  function findGoModule(fromDir) {
23799
- const resolved = path46.resolve(fromDir);
23936
+ const resolved = path47.resolve(fromDir);
23800
23937
  let cur = resolved;
23801
23938
  const walked = [];
23802
23939
  for (let i = 0;i < 16; i++) {
@@ -23808,7 +23945,7 @@ function findGoModule(fromDir) {
23808
23945
  }
23809
23946
  walked.push(cur);
23810
23947
  try {
23811
- const goMod = path46.join(cur, "go.mod");
23948
+ const goMod = path47.join(cur, "go.mod");
23812
23949
  const content = fs20.readFileSync(goMod, "utf-8");
23813
23950
  const moduleMatch = content.match(/^\s*module\s+"?([^"\s/]+(?:\/[^"\s]+)*)"?/m);
23814
23951
  if (moduleMatch) {
@@ -23819,10 +23956,10 @@ function findGoModule(fromDir) {
23819
23956
  }
23820
23957
  } catch {}
23821
23958
  try {
23822
- fs20.accessSync(path46.join(cur, ".git"));
23959
+ fs20.accessSync(path47.join(cur, ".git"));
23823
23960
  break;
23824
23961
  } catch {}
23825
- const parent = path46.dirname(cur);
23962
+ const parent = path47.dirname(cur);
23826
23963
  if (parent === cur)
23827
23964
  break;
23828
23965
  cur = parent;
@@ -23834,12 +23971,12 @@ function findGoModule(fromDir) {
23834
23971
  function resolveGoImport(fromDir, importPath) {
23835
23972
  let dir = null;
23836
23973
  if (importPath.startsWith(".")) {
23837
- dir = path46.resolve(fromDir, importPath);
23974
+ dir = path47.resolve(fromDir, importPath);
23838
23975
  } else {
23839
23976
  const mod = findGoModule(fromDir);
23840
23977
  if (mod && (importPath === mod.modulePath || importPath.startsWith(`${mod.modulePath}/`))) {
23841
23978
  const subpath = importPath.slice(mod.modulePath.length);
23842
- dir = path46.join(mod.moduleRoot, subpath);
23979
+ dir = path47.join(mod.moduleRoot, subpath);
23843
23980
  }
23844
23981
  }
23845
23982
  if (dir === null)
@@ -23847,7 +23984,7 @@ function resolveGoImport(fromDir, importPath) {
23847
23984
  if (!fs20.existsSync(dir) || !fs20.statSync(dir).isDirectory())
23848
23985
  return [];
23849
23986
  try {
23850
- return fs20.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(path46.join(dir, f)));
23987
+ return fs20.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(path47.join(dir, f)));
23851
23988
  } catch {
23852
23989
  return [];
23853
23990
  }
@@ -23886,15 +24023,15 @@ function findTestFilesSync(cwd) {
23886
24023
  for (const entry of entries) {
23887
24024
  if (entry.isDirectory()) {
23888
24025
  if (!skipDirs.has(entry.name)) {
23889
- walk(path46.join(dir, entry.name), visitedInodes);
24026
+ walk(path47.join(dir, entry.name), visitedInodes);
23890
24027
  }
23891
24028
  } else if (entry.isFile()) {
23892
24029
  const name = entry.name;
23893
24030
  const isTsTest = /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name);
23894
- const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path46.sep}tests${path46.sep}`) && name.endsWith(".py");
24031
+ const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path47.sep}tests${path47.sep}`) && name.endsWith(".py");
23895
24032
  const isGoTest = /.+_test\.go$/.test(name);
23896
24033
  if (isTsTest || isPyTest || isGoTest) {
23897
- testFiles.push(normalizePath2(path46.join(dir, entry.name)));
24034
+ testFiles.push(normalizePath2(path47.join(dir, entry.name)));
23898
24035
  }
23899
24036
  }
23900
24037
  }
@@ -23919,8 +24056,8 @@ function extractImports(content) {
23919
24056
  ];
23920
24057
  }
23921
24058
  function addImpactEdgesForTestFile(testFile, content, impactMap) {
23922
- const ext = path46.extname(testFile).toLowerCase();
23923
- const testDir = path46.dirname(testFile);
24059
+ const ext = path47.extname(testFile).toLowerCase();
24060
+ const testDir = path47.dirname(testFile);
23924
24061
  function addEdge(source) {
23925
24062
  if (!impactMap[source])
23926
24063
  impactMap[source] = [];
@@ -23993,7 +24130,7 @@ async function buildImpactMap(cwd) {
23993
24130
  return impactMap;
23994
24131
  }
23995
24132
  async function loadImpactMap(cwd, options) {
23996
- const cachePath = path46.join(cwd, ".swarm", "cache", "impact-map.json");
24133
+ const cachePath = path47.join(cwd, ".swarm", "cache", "impact-map.json");
23997
24134
  if (fs20.existsSync(cachePath)) {
23998
24135
  try {
23999
24136
  const content = fs20.readFileSync(cachePath, "utf-8");
@@ -24026,12 +24163,12 @@ async function loadImpactMap(cwd, options) {
24026
24163
  return _internals39.buildImpactMap(cwd);
24027
24164
  }
24028
24165
  async function saveImpactMap(cwd, impactMap) {
24029
- if (!path46.isAbsolute(cwd)) {
24166
+ if (!path47.isAbsolute(cwd)) {
24030
24167
  throw new Error(`saveImpactMap requires an absolute project root path, got: "${cwd}"`);
24031
24168
  }
24032
24169
  _internals39.validateProjectRoot(cwd);
24033
- const cacheDir2 = path46.join(cwd, ".swarm", "cache");
24034
- const cachePath = path46.join(cacheDir2, "impact-map.json");
24170
+ const cacheDir2 = path47.join(cwd, ".swarm", "cache");
24171
+ const cachePath = path47.join(cacheDir2, "impact-map.json");
24035
24172
  if (!fs20.existsSync(cacheDir2)) {
24036
24173
  fs20.mkdirSync(cacheDir2, { recursive: true });
24037
24174
  }
@@ -24063,7 +24200,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
24063
24200
  budgetExceeded = true;
24064
24201
  break;
24065
24202
  }
24066
- const normalizedChanged = normalizePath2(path46.resolve(changedFile));
24203
+ const normalizedChanged = normalizePath2(path47.resolve(changedFile));
24067
24204
  const tests = impactMap[normalizedChanged];
24068
24205
  if (tests && tests.length > 0) {
24069
24206
  for (const test of tests) {
@@ -24077,13 +24214,13 @@ async function analyzeImpact(changedFiles, cwd, budget) {
24077
24214
  if (budgetExceeded)
24078
24215
  break;
24079
24216
  } else {
24080
- const changedDir = normalizePath2(path46.dirname(normalizedChanged));
24081
- const changedInputDir = normalizePath2(path46.dirname(changedFile));
24217
+ const changedDir = normalizePath2(path47.dirname(normalizedChanged));
24218
+ const changedInputDir = normalizePath2(path47.dirname(changedFile));
24082
24219
  const suffixMatches = Object.entries(impactMap).filter(([sourcePath]) => {
24083
24220
  return sourcePath.endsWith(changedFile) || changedFile.endsWith(sourcePath) || sourcePath.endsWith(normalizedChanged) || normalizedChanged.endsWith(sourcePath);
24084
24221
  }).sort(([sourceA], [sourceB]) => {
24085
- const sourceDirA = normalizePath2(path46.dirname(sourceA));
24086
- const sourceDirB = normalizePath2(path46.dirname(sourceB));
24222
+ const sourceDirA = normalizePath2(path47.dirname(sourceA));
24223
+ const sourceDirB = normalizePath2(path47.dirname(sourceB));
24087
24224
  const exactA = sourceDirA === changedDir || changedInputDir !== "." && (sourceDirA === changedInputDir || sourceDirA.endsWith(`/${changedInputDir}`));
24088
24225
  const exactB = sourceDirB === changedDir || changedInputDir !== "." && (sourceDirB === changedInputDir || sourceDirB.endsWith(`/${changedInputDir}`));
24089
24226
  if (exactA !== exactB)
@@ -24410,7 +24547,7 @@ function detectFlakyTests(allHistory) {
24410
24547
 
24411
24548
  // src/test-impact/history-store.ts
24412
24549
  import fs21 from "fs";
24413
- import path47 from "path";
24550
+ import path48 from "path";
24414
24551
  var MAX_HISTORY_PER_TEST = 20;
24415
24552
  var MAX_ERROR_LENGTH = 500;
24416
24553
  var MAX_STACK_LENGTH = 200;
@@ -24422,10 +24559,10 @@ function getHistoryPath(workingDir) {
24422
24559
  if (!workingDir) {
24423
24560
  throw new Error("getHistoryPath requires a working directory \u2014 project root must be provided by the caller");
24424
24561
  }
24425
- if (!path47.isAbsolute(workingDir)) {
24562
+ if (!path48.isAbsolute(workingDir)) {
24426
24563
  throw new Error(`getHistoryPath requires an absolute project root path, got: "${workingDir}"`);
24427
24564
  }
24428
- return path47.join(workingDir, ".swarm", "cache", "test-history.jsonl");
24565
+ return path48.join(workingDir, ".swarm", "cache", "test-history.jsonl");
24429
24566
  }
24430
24567
  function sanitizeErrorMessage(errorMessage) {
24431
24568
  if (errorMessage === undefined) {
@@ -24517,7 +24654,7 @@ function batchAppendTestRuns(records, workingDir) {
24517
24654
  }
24518
24655
  }
24519
24656
  const historyPath = getHistoryPath(workingDir);
24520
- const historyDir = path47.dirname(historyPath);
24657
+ const historyDir = path48.dirname(historyPath);
24521
24658
  _internals40.validateProjectRoot(workingDir);
24522
24659
  if (!fs21.existsSync(historyDir)) {
24523
24660
  fs21.mkdirSync(historyDir, { recursive: true });
@@ -24647,7 +24784,7 @@ var _internals40 = {
24647
24784
 
24648
24785
  // src/tools/resolve-working-directory.ts
24649
24786
  import * as fs22 from "fs";
24650
- import * as path48 from "path";
24787
+ import * as path49 from "path";
24651
24788
  function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
24652
24789
  if (workingDirectory == null || workingDirectory === "") {
24653
24790
  if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
@@ -24679,15 +24816,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
24679
24816
  };
24680
24817
  }
24681
24818
  }
24682
- const rawPathParts = workingDirectory.split(path48.sep);
24819
+ const rawPathParts = workingDirectory.split(path49.sep);
24683
24820
  if (rawPathParts.includes("..")) {
24684
24821
  return {
24685
24822
  success: false,
24686
24823
  message: "Invalid working_directory: path traversal sequences (..) are not allowed"
24687
24824
  };
24688
24825
  }
24689
- const normalizedDir = path48.normalize(workingDirectory);
24690
- const resolvedDir = path48.resolve(normalizedDir);
24826
+ const normalizedDir = path49.normalize(workingDirectory);
24827
+ const resolvedDir = path49.resolve(normalizedDir);
24691
24828
  let statResult;
24692
24829
  try {
24693
24830
  statResult = fs22.statSync(resolvedDir);
@@ -24706,7 +24843,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
24706
24843
  if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
24707
24844
  return { success: true, directory: resolvedDir };
24708
24845
  }
24709
- const resolvedFallback = path48.resolve(fallbackDirectory);
24846
+ const resolvedFallback = path49.resolve(fallbackDirectory);
24710
24847
  let fallbackExists = false;
24711
24848
  try {
24712
24849
  fs22.statSync(resolvedFallback);
@@ -24715,7 +24852,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
24715
24852
  fallbackExists = false;
24716
24853
  }
24717
24854
  if (fallbackExists) {
24718
- const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path48.sep);
24855
+ const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path49.sep);
24719
24856
  if (isSubdirectory) {
24720
24857
  return {
24721
24858
  success: false,
@@ -24738,7 +24875,7 @@ async function estimateFanOut(sourceFiles, cwd) {
24738
24875
  const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
24739
24876
  const uniqueTestFiles = new Set;
24740
24877
  for (const sourceFile of sourceFiles) {
24741
- const resolvedPath = path49.resolve(cwd, sourceFile);
24878
+ const resolvedPath = path50.resolve(cwd, sourceFile);
24742
24879
  const normalizedPath = resolvedPath.replace(/\\/g, "/");
24743
24880
  const testFiles = impactMap[normalizedPath];
24744
24881
  if (testFiles) {
@@ -24823,14 +24960,14 @@ function hasDevDependency(devDeps, ...patterns) {
24823
24960
  return hasPackageJsonDependency(devDeps, ...patterns);
24824
24961
  }
24825
24962
  function detectGoTest(cwd) {
24826
- return fs23.existsSync(path49.join(cwd, "go.mod")) && isCommandAvailable("go");
24963
+ return fs23.existsSync(path50.join(cwd, "go.mod")) && isCommandAvailable("go");
24827
24964
  }
24828
24965
  function detectJavaMaven(cwd) {
24829
- return fs23.existsSync(path49.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
24966
+ return fs23.existsSync(path50.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
24830
24967
  }
24831
24968
  function detectGradle(cwd) {
24832
- const hasBuildFile = fs23.existsSync(path49.join(cwd, "build.gradle")) || fs23.existsSync(path49.join(cwd, "build.gradle.kts"));
24833
- const hasGradlew = fs23.existsSync(path49.join(cwd, "gradlew")) || fs23.existsSync(path49.join(cwd, "gradlew.bat"));
24969
+ const hasBuildFile = fs23.existsSync(path50.join(cwd, "build.gradle")) || fs23.existsSync(path50.join(cwd, "build.gradle.kts"));
24970
+ const hasGradlew = fs23.existsSync(path50.join(cwd, "gradlew")) || fs23.existsSync(path50.join(cwd, "gradlew.bat"));
24834
24971
  return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
24835
24972
  }
24836
24973
  function detectDotnetTest(cwd) {
@@ -24843,25 +24980,25 @@ function detectDotnetTest(cwd) {
24843
24980
  }
24844
24981
  }
24845
24982
  function detectCTest(cwd) {
24846
- const hasSource = fs23.existsSync(path49.join(cwd, "CMakeLists.txt"));
24847
- const hasBuildCache = fs23.existsSync(path49.join(cwd, "CMakeCache.txt")) || fs23.existsSync(path49.join(cwd, "build", "CMakeCache.txt"));
24983
+ const hasSource = fs23.existsSync(path50.join(cwd, "CMakeLists.txt"));
24984
+ const hasBuildCache = fs23.existsSync(path50.join(cwd, "CMakeCache.txt")) || fs23.existsSync(path50.join(cwd, "build", "CMakeCache.txt"));
24848
24985
  return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
24849
24986
  }
24850
24987
  function detectSwiftTest(cwd) {
24851
- return fs23.existsSync(path49.join(cwd, "Package.swift")) && isCommandAvailable("swift");
24988
+ return fs23.existsSync(path50.join(cwd, "Package.swift")) && isCommandAvailable("swift");
24852
24989
  }
24853
24990
  function detectDartTest(cwd) {
24854
- return fs23.existsSync(path49.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
24991
+ return fs23.existsSync(path50.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
24855
24992
  }
24856
24993
  function detectRSpec(cwd) {
24857
- const hasRSpecFile = fs23.existsSync(path49.join(cwd, ".rspec"));
24858
- const hasGemfile = fs23.existsSync(path49.join(cwd, "Gemfile"));
24859
- const hasSpecDir = fs23.existsSync(path49.join(cwd, "spec"));
24994
+ const hasRSpecFile = fs23.existsSync(path50.join(cwd, ".rspec"));
24995
+ const hasGemfile = fs23.existsSync(path50.join(cwd, "Gemfile"));
24996
+ const hasSpecDir = fs23.existsSync(path50.join(cwd, "spec"));
24860
24997
  const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
24861
24998
  return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
24862
24999
  }
24863
25000
  function detectMinitest(cwd) {
24864
- return fs23.existsSync(path49.join(cwd, "test")) && (fs23.existsSync(path49.join(cwd, "Gemfile")) || fs23.existsSync(path49.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
25001
+ return fs23.existsSync(path50.join(cwd, "test")) && (fs23.existsSync(path50.join(cwd, "Gemfile")) || fs23.existsSync(path50.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
24865
25002
  }
24866
25003
  var DISPATCH_FRAMEWORK_MAP = {
24867
25004
  bun: "bun",
@@ -24946,7 +25083,7 @@ async function parseTestOutputViaDispatch(framework, output, baseDir) {
24946
25083
  async function detectTestFramework(cwd) {
24947
25084
  const baseDir = cwd;
24948
25085
  try {
24949
- const packageJsonPath = path49.join(baseDir, "package.json");
25086
+ const packageJsonPath = path50.join(baseDir, "package.json");
24950
25087
  if (fs23.existsSync(packageJsonPath)) {
24951
25088
  const content = fs23.readFileSync(packageJsonPath, "utf-8");
24952
25089
  const pkg = JSON.parse(content);
@@ -24967,16 +25104,16 @@ async function detectTestFramework(cwd) {
24967
25104
  return "jest";
24968
25105
  if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
24969
25106
  return "mocha";
24970
- if (fs23.existsSync(path49.join(baseDir, "bun.lockb")) || fs23.existsSync(path49.join(baseDir, "bun.lock"))) {
25107
+ if (fs23.existsSync(path50.join(baseDir, "bun.lockb")) || fs23.existsSync(path50.join(baseDir, "bun.lock"))) {
24971
25108
  if (scripts.test?.includes("bun"))
24972
25109
  return "bun";
24973
25110
  }
24974
25111
  }
24975
25112
  } catch {}
24976
25113
  try {
24977
- const pyprojectTomlPath = path49.join(baseDir, "pyproject.toml");
24978
- const setupCfgPath = path49.join(baseDir, "setup.cfg");
24979
- const requirementsTxtPath = path49.join(baseDir, "requirements.txt");
25114
+ const pyprojectTomlPath = path50.join(baseDir, "pyproject.toml");
25115
+ const setupCfgPath = path50.join(baseDir, "setup.cfg");
25116
+ const requirementsTxtPath = path50.join(baseDir, "requirements.txt");
24980
25117
  if (fs23.existsSync(pyprojectTomlPath)) {
24981
25118
  const content = fs23.readFileSync(pyprojectTomlPath, "utf-8");
24982
25119
  if (content.includes("[tool.pytest"))
@@ -24996,7 +25133,7 @@ async function detectTestFramework(cwd) {
24996
25133
  }
24997
25134
  } catch {}
24998
25135
  try {
24999
- const cargoTomlPath = path49.join(baseDir, "Cargo.toml");
25136
+ const cargoTomlPath = path50.join(baseDir, "Cargo.toml");
25000
25137
  if (fs23.existsSync(cargoTomlPath)) {
25001
25138
  const content = fs23.readFileSync(cargoTomlPath, "utf-8");
25002
25139
  if (content.includes("[dev-dependencies]")) {
@@ -25007,9 +25144,9 @@ async function detectTestFramework(cwd) {
25007
25144
  }
25008
25145
  } catch {}
25009
25146
  try {
25010
- const pesterConfigPath = path49.join(baseDir, "pester.config.ps1");
25011
- const pesterConfigJsonPath = path49.join(baseDir, "pester.config.ps1.json");
25012
- const pesterPs1Path = path49.join(baseDir, "tests.ps1");
25147
+ const pesterConfigPath = path50.join(baseDir, "pester.config.ps1");
25148
+ const pesterConfigJsonPath = path50.join(baseDir, "pester.config.ps1.json");
25149
+ const pesterPs1Path = path50.join(baseDir, "tests.ps1");
25013
25150
  if (fs23.existsSync(pesterConfigPath) || fs23.existsSync(pesterConfigJsonPath) || fs23.existsSync(pesterPs1Path)) {
25014
25151
  return "pester";
25015
25152
  }
@@ -25052,12 +25189,12 @@ function isTestDirectoryPath(normalizedPath) {
25052
25189
  return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
25053
25190
  }
25054
25191
  function resolveWorkspacePath(file, workingDir) {
25055
- return path49.isAbsolute(file) ? path49.resolve(file) : path49.resolve(workingDir, file);
25192
+ return path50.isAbsolute(file) ? path50.resolve(file) : path50.resolve(workingDir, file);
25056
25193
  }
25057
25194
  function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
25058
25195
  if (!preferRelative)
25059
25196
  return absolutePath;
25060
- return path49.relative(workingDir, absolutePath);
25197
+ return path50.relative(workingDir, absolutePath);
25061
25198
  }
25062
25199
  function dedupePush(target, value) {
25063
25200
  if (!target.includes(value)) {
@@ -25094,18 +25231,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
25094
25231
  }
25095
25232
  }
25096
25233
  function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
25097
- const relativeDir = path49.dirname(relativePath);
25234
+ const relativeDir = path50.dirname(relativePath);
25098
25235
  const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
25099
25236
  const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
25100
- const rootDir = path49.join(workingDir, dirName);
25101
- return nestedRelativeDir ? [rootDir, path49.join(rootDir, nestedRelativeDir)] : [rootDir];
25237
+ const rootDir = path50.join(workingDir, dirName);
25238
+ return nestedRelativeDir ? [rootDir, path50.join(rootDir, nestedRelativeDir)] : [rootDir];
25102
25239
  });
25103
25240
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
25104
25241
  if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
25105
- directories.push(path49.join(workingDir, "src/test/java", path49.dirname(normalizedRelativePath.slice("src/main/java/".length))));
25242
+ directories.push(path50.join(workingDir, "src/test/java", path50.dirname(normalizedRelativePath.slice("src/main/java/".length))));
25106
25243
  }
25107
25244
  if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
25108
- directories.push(path49.join(workingDir, "src/test/kotlin", path49.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
25245
+ directories.push(path50.join(workingDir, "src/test/kotlin", path50.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
25109
25246
  }
25110
25247
  return [...new Set(directories)];
25111
25248
  }
@@ -25133,23 +25270,23 @@ function isLanguageSpecificTestFile(basename9) {
25133
25270
  }
25134
25271
  function isConventionTestFilePath(filePath) {
25135
25272
  const normalizedPath = filePath.replace(/\\/g, "/");
25136
- const basename9 = path49.basename(filePath);
25273
+ const basename9 = path50.basename(filePath);
25137
25274
  return hasCompoundTestExtension(basename9) || basename9.includes(".spec.") || basename9.includes(".test.") || isLanguageSpecificTestFile(basename9) || isTestDirectoryPath(normalizedPath);
25138
25275
  }
25139
25276
  function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
25140
25277
  const testFiles = [];
25141
25278
  for (const file of sourceFiles) {
25142
25279
  const absoluteFile = resolveWorkspacePath(file, workingDir);
25143
- const relativeFile = path49.relative(workingDir, absoluteFile);
25144
- const basename9 = path49.basename(absoluteFile);
25145
- const dirname23 = path49.dirname(absoluteFile);
25146
- const preferRelativeOutput = !path49.isAbsolute(file);
25280
+ const relativeFile = path50.relative(workingDir, absoluteFile);
25281
+ const basename9 = path50.basename(absoluteFile);
25282
+ const dirname24 = path50.dirname(absoluteFile);
25283
+ const preferRelativeOutput = !path50.isAbsolute(file);
25147
25284
  if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file)) {
25148
25285
  dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
25149
25286
  continue;
25150
25287
  }
25151
25288
  const nameWithoutExt = basename9.replace(/\.[^.]+$/, "");
25152
- const ext = path49.extname(basename9);
25289
+ const ext = path50.extname(basename9);
25153
25290
  const genericTestNames = [
25154
25291
  `${nameWithoutExt}.spec${ext}`,
25155
25292
  `${nameWithoutExt}.test${ext}`
@@ -25158,7 +25295,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
25158
25295
  const colocatedCandidates = [
25159
25296
  ...genericTestNames,
25160
25297
  ...languageSpecificTestNames
25161
- ].map((candidateName) => path49.join(dirname23, candidateName));
25298
+ ].map((candidateName) => path50.join(dirname24, candidateName));
25162
25299
  const testDirectoryNames = [
25163
25300
  basename9,
25164
25301
  ...genericTestNames,
@@ -25167,8 +25304,8 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
25167
25304
  const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
25168
25305
  const possibleTestFiles = [
25169
25306
  ...colocatedCandidates,
25170
- ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path49.join(dirname23, dirName, candidateName))),
25171
- ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path49.join(candidateDir, candidateName)))
25307
+ ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path50.join(dirname24, dirName, candidateName))),
25308
+ ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path50.join(candidateDir, candidateName)))
25172
25309
  ];
25173
25310
  for (const testFile of possibleTestFiles) {
25174
25311
  if (fs23.existsSync(testFile)) {
@@ -25189,7 +25326,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
25189
25326
  try {
25190
25327
  const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
25191
25328
  const content = fs23.readFileSync(absoluteTestFile, "utf-8");
25192
- const testDir = path49.dirname(absoluteTestFile);
25329
+ const testDir = path50.dirname(absoluteTestFile);
25193
25330
  const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
25194
25331
  let match;
25195
25332
  match = importRegex.exec(content);
@@ -25197,8 +25334,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
25197
25334
  const importPath = match[1];
25198
25335
  let resolvedImport;
25199
25336
  if (importPath.startsWith(".")) {
25200
- resolvedImport = path49.resolve(testDir, importPath);
25201
- const existingExt = path49.extname(resolvedImport);
25337
+ resolvedImport = path50.resolve(testDir, importPath);
25338
+ const existingExt = path50.extname(resolvedImport);
25202
25339
  if (!existingExt) {
25203
25340
  for (const extToTry of [
25204
25341
  ".ts",
@@ -25218,12 +25355,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
25218
25355
  } else {
25219
25356
  continue;
25220
25357
  }
25221
- const importBasename = path49.basename(resolvedImport, path49.extname(resolvedImport));
25222
- const importDir = path49.dirname(resolvedImport);
25358
+ const importBasename = path50.basename(resolvedImport, path50.extname(resolvedImport));
25359
+ const importDir = path50.dirname(resolvedImport);
25223
25360
  for (const sourceFile of absoluteSourceFiles) {
25224
- const sourceDir = path49.dirname(sourceFile);
25225
- const sourceBasename = path49.basename(sourceFile, path49.extname(sourceFile));
25226
- const isRelatedDir = importDir === sourceDir || importDir === path49.join(sourceDir, "__tests__") || importDir === path49.join(sourceDir, "tests") || importDir === path49.join(sourceDir, "test") || importDir === path49.join(sourceDir, "spec");
25361
+ const sourceDir = path50.dirname(sourceFile);
25362
+ const sourceBasename = path50.basename(sourceFile, path50.extname(sourceFile));
25363
+ const isRelatedDir = importDir === sourceDir || importDir === path50.join(sourceDir, "__tests__") || importDir === path50.join(sourceDir, "tests") || importDir === path50.join(sourceDir, "test") || importDir === path50.join(sourceDir, "spec");
25227
25364
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
25228
25365
  dedupePush(testFiles, testFile);
25229
25366
  break;
@@ -25236,8 +25373,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
25236
25373
  while (match !== null) {
25237
25374
  const importPath = match[1];
25238
25375
  if (importPath.startsWith(".")) {
25239
- let resolvedImport = path49.resolve(testDir, importPath);
25240
- const existingExt = path49.extname(resolvedImport);
25376
+ let resolvedImport = path50.resolve(testDir, importPath);
25377
+ const existingExt = path50.extname(resolvedImport);
25241
25378
  if (!existingExt) {
25242
25379
  for (const extToTry of [
25243
25380
  ".ts",
@@ -25254,12 +25391,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
25254
25391
  }
25255
25392
  }
25256
25393
  }
25257
- const importDir = path49.dirname(resolvedImport);
25258
- const importBasename = path49.basename(resolvedImport, path49.extname(resolvedImport));
25394
+ const importDir = path50.dirname(resolvedImport);
25395
+ const importBasename = path50.basename(resolvedImport, path50.extname(resolvedImport));
25259
25396
  for (const sourceFile of absoluteSourceFiles) {
25260
- const sourceDir = path49.dirname(sourceFile);
25261
- const sourceBasename = path49.basename(sourceFile, path49.extname(sourceFile));
25262
- const isRelatedDir = importDir === sourceDir || importDir === path49.join(sourceDir, "__tests__") || importDir === path49.join(sourceDir, "tests") || importDir === path49.join(sourceDir, "test") || importDir === path49.join(sourceDir, "spec");
25397
+ const sourceDir = path50.dirname(sourceFile);
25398
+ const sourceBasename = path50.basename(sourceFile, path50.extname(sourceFile));
25399
+ const isRelatedDir = importDir === sourceDir || importDir === path50.join(sourceDir, "__tests__") || importDir === path50.join(sourceDir, "tests") || importDir === path50.join(sourceDir, "test") || importDir === path50.join(sourceDir, "spec");
25263
25400
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
25264
25401
  dedupePush(testFiles, testFile);
25265
25402
  break;
@@ -25379,8 +25516,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
25379
25516
  return ["mvn", "test"];
25380
25517
  case "gradle": {
25381
25518
  const isWindows = process.platform === "win32";
25382
- const hasGradlewBat = fs23.existsSync(path49.join(baseDir, "gradlew.bat"));
25383
- const hasGradlew = fs23.existsSync(path49.join(baseDir, "gradlew"));
25519
+ const hasGradlewBat = fs23.existsSync(path50.join(baseDir, "gradlew.bat"));
25520
+ const hasGradlew = fs23.existsSync(path50.join(baseDir, "gradlew"));
25384
25521
  if (hasGradlewBat && isWindows)
25385
25522
  return ["gradlew.bat", "test"];
25386
25523
  if (hasGradlew)
@@ -25397,7 +25534,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
25397
25534
  "cmake-build-release",
25398
25535
  "out"
25399
25536
  ];
25400
- const actualBuildDir = buildDirCandidates.find((d) => fs23.existsSync(path49.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
25537
+ const actualBuildDir = buildDirCandidates.find((d) => fs23.existsSync(path50.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
25401
25538
  return ["ctest", "--test-dir", actualBuildDir];
25402
25539
  }
25403
25540
  case "swift-test":
@@ -25831,11 +25968,11 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
25831
25968
  };
25832
25969
  }
25833
25970
  const startTime = Date.now();
25834
- const vitestJsonOutputPath = framework === "vitest" ? path49.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
25971
+ const vitestJsonOutputPath = framework === "vitest" ? path50.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
25835
25972
  try {
25836
25973
  if (vitestJsonOutputPath) {
25837
25974
  try {
25838
- fs23.mkdirSync(path49.dirname(vitestJsonOutputPath), { recursive: true });
25975
+ fs23.mkdirSync(path50.dirname(vitestJsonOutputPath), { recursive: true });
25839
25976
  if (fs23.existsSync(vitestJsonOutputPath)) {
25840
25977
  fs23.unlinkSync(vitestJsonOutputPath);
25841
25978
  }
@@ -26003,10 +26140,10 @@ var SKIP_DIRECTORIES = new Set([
26003
26140
  ]);
26004
26141
  function normalizeHistoryTestFile(testFile, workingDir) {
26005
26142
  const normalized = testFile.replace(/\\/g, "/");
26006
- if (!path49.isAbsolute(testFile))
26143
+ if (!path50.isAbsolute(testFile))
26007
26144
  return normalized;
26008
- const relative8 = path49.relative(workingDir, testFile);
26009
- if (relative8.startsWith("..") || path49.isAbsolute(relative8)) {
26145
+ const relative8 = path50.relative(workingDir, testFile);
26146
+ if (relative8.startsWith("..") || path50.isAbsolute(relative8)) {
26010
26147
  return normalized;
26011
26148
  }
26012
26149
  return relative8.replace(/\\/g, "/");
@@ -26245,7 +26382,7 @@ var test_runner = createSwarmTool({
26245
26382
  const sourceFiles = args.files.filter((file) => {
26246
26383
  if (directTestFiles.includes(file))
26247
26384
  return false;
26248
- const ext = path49.extname(file).toLowerCase();
26385
+ const ext = path50.extname(file).toLowerCase();
26249
26386
  return SOURCE_EXTENSIONS.has(ext);
26250
26387
  });
26251
26388
  const invalidFiles = args.files.filter((file) => !directTestFiles.includes(file) && !sourceFiles.includes(file));
@@ -26291,7 +26428,7 @@ var test_runner = createSwarmTool({
26291
26428
  if (isConventionTestFilePath(f)) {
26292
26429
  return false;
26293
26430
  }
26294
- const ext = path49.extname(f).toLowerCase();
26431
+ const ext = path50.extname(f).toLowerCase();
26295
26432
  return SOURCE_EXTENSIONS.has(ext);
26296
26433
  });
26297
26434
  if (sourceFiles.length === 0) {
@@ -26341,7 +26478,7 @@ var test_runner = createSwarmTool({
26341
26478
  if (isConventionTestFilePath(f)) {
26342
26479
  return false;
26343
26480
  }
26344
- const ext = path49.extname(f).toLowerCase();
26481
+ const ext = path50.extname(f).toLowerCase();
26345
26482
  return SOURCE_EXTENSIONS.has(ext);
26346
26483
  });
26347
26484
  if (sourceFiles.length === 0) {
@@ -26393,8 +26530,8 @@ var test_runner = createSwarmTool({
26393
26530
  }
26394
26531
  if (impactResult.impactedTests.length > 0) {
26395
26532
  testFiles = impactResult.impactedTests.map((absPath) => {
26396
- const relativePath = path49.relative(workingDir, absPath);
26397
- return path49.isAbsolute(relativePath) ? absPath : relativePath;
26533
+ const relativePath = path50.relative(workingDir, absPath);
26534
+ return path50.isAbsolute(relativePath) ? absPath : relativePath;
26398
26535
  });
26399
26536
  } else {
26400
26537
  graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
@@ -26489,8 +26626,8 @@ function validateDirectoryPath(dir) {
26489
26626
  if (dir.includes("..")) {
26490
26627
  throw new Error("Directory path must not contain path traversal sequences");
26491
26628
  }
26492
- const normalized = path50.normalize(dir);
26493
- const absolutePath = path50.isAbsolute(normalized) ? normalized : path50.resolve(normalized);
26629
+ const normalized = path51.normalize(dir);
26630
+ const absolutePath = path51.isAbsolute(normalized) ? normalized : path51.resolve(normalized);
26494
26631
  return absolutePath;
26495
26632
  }
26496
26633
  function validateTimeout(timeoutMs, defaultValue) {
@@ -26513,7 +26650,7 @@ function validateTimeout(timeoutMs, defaultValue) {
26513
26650
  }
26514
26651
  function getPackageVersion(dir) {
26515
26652
  try {
26516
- const packagePath = path50.join(dir, "package.json");
26653
+ const packagePath = path51.join(dir, "package.json");
26517
26654
  if (fs24.existsSync(packagePath)) {
26518
26655
  const content = fs24.readFileSync(packagePath, "utf-8");
26519
26656
  const pkg = JSON.parse(content);
@@ -26524,7 +26661,7 @@ function getPackageVersion(dir) {
26524
26661
  }
26525
26662
  function getChangelogVersion(dir) {
26526
26663
  try {
26527
- const changelogPath = path50.join(dir, "CHANGELOG.md");
26664
+ const changelogPath = path51.join(dir, "CHANGELOG.md");
26528
26665
  if (fs24.existsSync(changelogPath)) {
26529
26666
  const content = fs24.readFileSync(changelogPath, "utf-8");
26530
26667
  const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
@@ -26538,7 +26675,7 @@ function getChangelogVersion(dir) {
26538
26675
  function getVersionFileVersion(dir) {
26539
26676
  const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
26540
26677
  for (const file of possibleFiles) {
26541
- const filePath = path50.join(dir, file);
26678
+ const filePath = path51.join(dir, file);
26542
26679
  if (fs24.existsSync(filePath)) {
26543
26680
  try {
26544
26681
  const content = fs24.readFileSync(filePath, "utf-8").trim();
@@ -27276,7 +27413,7 @@ async function handleQaGatesCommand(directory, args, sessionID) {
27276
27413
 
27277
27414
  // src/commands/reset.ts
27278
27415
  import * as fs25 from "fs";
27279
- import * as path51 from "path";
27416
+ import * as path52 from "path";
27280
27417
 
27281
27418
  // src/background/circuit-breaker.ts
27282
27419
  class CircuitBreaker {
@@ -27993,7 +28130,7 @@ async function handleResetCommand(directory, args) {
27993
28130
  }
27994
28131
  for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
27995
28132
  try {
27996
- const rootPath = path51.join(directory, filename);
28133
+ const rootPath = path52.join(directory, filename);
27997
28134
  if (fs25.existsSync(rootPath)) {
27998
28135
  fs25.unlinkSync(rootPath);
27999
28136
  results.push(`- \u2705 Deleted ${filename} (root)`);
@@ -28031,7 +28168,7 @@ async function handleResetCommand(directory, args) {
28031
28168
 
28032
28169
  // src/commands/reset-session.ts
28033
28170
  import * as fs27 from "fs";
28034
- import * as path53 from "path";
28171
+ import * as path54 from "path";
28035
28172
 
28036
28173
  // src/hooks/trajectory-logger.ts
28037
28174
  var callStartTimes = new Map;
@@ -28438,16 +28575,16 @@ function detectPatterns(trajectory, config, lastProcessedStep = 0) {
28438
28575
  }
28439
28576
  // src/prm/replay.ts
28440
28577
  import { promises as fs26 } from "fs";
28441
- import path52 from "path";
28578
+ import path53 from "path";
28442
28579
  function isPathSafe(targetPath, basePath) {
28443
- const resolvedTarget = path52.resolve(targetPath);
28444
- const resolvedBase = path52.resolve(basePath);
28445
- const rel = path52.relative(resolvedBase, resolvedTarget);
28446
- return !rel.startsWith("..") && !path52.isAbsolute(rel);
28580
+ const resolvedTarget = path53.resolve(targetPath);
28581
+ const resolvedBase = path53.resolve(basePath);
28582
+ const rel = path53.relative(resolvedBase, resolvedTarget);
28583
+ return !rel.startsWith("..") && !path53.isAbsolute(rel);
28447
28584
  }
28448
28585
  function isWithinReplaysDir(targetPath) {
28449
- const resolved = path52.resolve(targetPath);
28450
- const parts = resolved.split(path52.sep);
28586
+ const resolved = path53.resolve(targetPath);
28587
+ const parts = resolved.split(path53.sep);
28451
28588
  for (let i = 0;i < parts.length - 1; i++) {
28452
28589
  if (parts[i] === ".swarm" && parts[i + 1] === "replays") {
28453
28590
  return true;
@@ -28460,10 +28597,10 @@ function sanitizeFilename(input) {
28460
28597
  }
28461
28598
  async function startReplayRecording(sessionID, directory) {
28462
28599
  try {
28463
- const replayDir = path52.join(directory, ".swarm", "replays");
28600
+ const replayDir = path53.join(directory, ".swarm", "replays");
28464
28601
  const safeSessionID = sanitizeFilename(sessionID);
28465
28602
  const filename = `${safeSessionID}-${Date.now()}.jsonl`;
28466
- const filepath = path52.join(replayDir, filename);
28603
+ const filepath = path53.join(replayDir, filename);
28467
28604
  if (!isPathSafe(filepath, replayDir)) {
28468
28605
  console.warn(`[replay] Invalid path detected - path traversal attempt blocked for session ${sessionID}`);
28469
28606
  return null;
@@ -28541,7 +28678,7 @@ async function handleResetSessionCommand(directory, _args) {
28541
28678
  } catch {
28542
28679
  results.push("\u274C Failed to delete state.json");
28543
28680
  }
28544
- const sessionDir = path53.dirname(validateSwarmPath(directory, "session/state.json"));
28681
+ const sessionDir = path54.dirname(validateSwarmPath(directory, "session/state.json"));
28545
28682
  let sessionFiles = [];
28546
28683
  if (fs27.existsSync(sessionDir)) {
28547
28684
  try {
@@ -28553,7 +28690,7 @@ async function handleResetSessionCommand(directory, _args) {
28553
28690
  for (const file of sessionFiles) {
28554
28691
  if (file === "state.json")
28555
28692
  continue;
28556
- const filePath = path53.join(sessionDir, file);
28693
+ const filePath = path54.join(sessionDir, file);
28557
28694
  try {
28558
28695
  if (!fs27.existsSync(filePath))
28559
28696
  continue;
@@ -28588,7 +28725,7 @@ async function handleResetSessionCommand(directory, _args) {
28588
28725
  }
28589
28726
 
28590
28727
  // src/summaries/manager.ts
28591
- import * as path54 from "path";
28728
+ import * as path55 from "path";
28592
28729
  var SUMMARY_ID_REGEX = /^S\d+$/;
28593
28730
  function sanitizeSummaryId(id) {
28594
28731
  if (!id || id.length === 0) {
@@ -28612,7 +28749,7 @@ function sanitizeSummaryId(id) {
28612
28749
  }
28613
28750
  async function loadFullOutput(directory, id) {
28614
28751
  const sanitizedId = sanitizeSummaryId(id);
28615
- const relativePath = path54.join("summaries", `${sanitizedId}.json`);
28752
+ const relativePath = path55.join("summaries", `${sanitizedId}.json`);
28616
28753
  validateSwarmPath(directory, relativePath);
28617
28754
  const content = await readSwarmFileAsync(directory, relativePath);
28618
28755
  if (content === null) {
@@ -28665,7 +28802,7 @@ ${error2 instanceof Error ? error2.message : String(error2)}`;
28665
28802
 
28666
28803
  // src/commands/rollback.ts
28667
28804
  import * as fs28 from "fs";
28668
- import * as path55 from "path";
28805
+ import * as path56 from "path";
28669
28806
  async function handleRollbackCommand(directory, args) {
28670
28807
  const phaseArg = args[0];
28671
28808
  if (!phaseArg) {
@@ -28731,8 +28868,8 @@ async function handleRollbackCommand(directory, args) {
28731
28868
  if (EXCLUDE_FILES.has(file) || file.startsWith("plan-ledger.archived-")) {
28732
28869
  continue;
28733
28870
  }
28734
- const src = path55.join(checkpointDir, file);
28735
- const dest = path55.join(swarmDir, file);
28871
+ const src = path56.join(checkpointDir, file);
28872
+ const dest = path56.join(swarmDir, file);
28736
28873
  try {
28737
28874
  fs28.cpSync(src, dest, { recursive: true, force: true });
28738
28875
  successes.push(file);
@@ -28751,7 +28888,7 @@ async function handleRollbackCommand(directory, args) {
28751
28888
  ].join(`
28752
28889
  `);
28753
28890
  }
28754
- const existingLedgerPath = path55.join(swarmDir, "plan-ledger.jsonl");
28891
+ const existingLedgerPath = path56.join(swarmDir, "plan-ledger.jsonl");
28755
28892
  let ledgerDeletionFailed = false;
28756
28893
  if (fs28.existsSync(existingLedgerPath)) {
28757
28894
  try {
@@ -28764,7 +28901,7 @@ async function handleRollbackCommand(directory, args) {
28764
28901
  }
28765
28902
  if (!ledgerDeletionFailed) {
28766
28903
  try {
28767
- const planJsonPath = path55.join(swarmDir, "plan.json");
28904
+ const planJsonPath = path56.join(swarmDir, "plan.json");
28768
28905
  if (fs28.existsSync(planJsonPath)) {
28769
28906
  const planRaw = fs28.readFileSync(planJsonPath, "utf-8");
28770
28907
  const plan = PlanSchema.parse(JSON.parse(planRaw));
@@ -29025,10 +29162,10 @@ Ensure this is a git repository with commit history.`;
29025
29162
  `);
29026
29163
  try {
29027
29164
  const fs29 = await import("fs/promises");
29028
- const path56 = await import("path");
29029
- const reportPath = path56.join(directory, ".swarm", "simulate-report.md");
29030
- await fs29.mkdir(path56.dirname(reportPath), { recursive: true });
29031
- const reportTempPath = path56.join(path56.dirname(reportPath), `${path56.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
29165
+ const path57 = await import("path");
29166
+ const reportPath = path57.join(directory, ".swarm", "simulate-report.md");
29167
+ await fs29.mkdir(path57.dirname(reportPath), { recursive: true });
29168
+ const reportTempPath = path57.join(path57.dirname(reportPath), `${path57.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
29032
29169
  try {
29033
29170
  await fs29.writeFile(reportTempPath, report, "utf-8");
29034
29171
  renameSync11(reportTempPath, reportPath);
@@ -29056,19 +29193,19 @@ async function handleSpecifyCommand(_directory, args) {
29056
29193
 
29057
29194
  // src/services/status-service.ts
29058
29195
  import * as fsSync3 from "fs";
29059
- import { readFile as readFile15 } from "fs/promises";
29060
- import * as path57 from "path";
29196
+ import { readFile as readFile16 } from "fs/promises";
29197
+ import * as path58 from "path";
29061
29198
 
29062
29199
  // src/turbo/lean/state.ts
29063
29200
  init_logger();
29064
29201
  import * as fs29 from "fs";
29065
- import * as path56 from "path";
29202
+ import * as path57 from "path";
29066
29203
  var STATE_FILE3 = "turbo-state.json";
29067
29204
  function nowISO3() {
29068
29205
  return new Date().toISOString();
29069
29206
  }
29070
29207
  function ensureSwarmDir2(directory) {
29071
- const swarmDir = path56.resolve(directory, ".swarm");
29208
+ const swarmDir = path57.resolve(directory, ".swarm");
29072
29209
  if (!fs29.existsSync(swarmDir)) {
29073
29210
  fs29.mkdirSync(swarmDir, { recursive: true });
29074
29211
  }
@@ -29113,7 +29250,7 @@ function markStateUnreadable2(directory, reason) {
29113
29250
  }
29114
29251
  function readPersisted2(directory) {
29115
29252
  try {
29116
- const filePath = path56.join(directory, ".swarm", STATE_FILE3);
29253
+ const filePath = path57.join(directory, ".swarm", STATE_FILE3);
29117
29254
  if (!fs29.existsSync(filePath)) {
29118
29255
  const seed = emptyPersisted2();
29119
29256
  try {
@@ -29149,7 +29286,7 @@ function writePersisted2(directory, persisted) {
29149
29286
  let payload;
29150
29287
  try {
29151
29288
  ensureSwarmDir2(directory);
29152
- filePath = path56.join(directory, ".swarm", STATE_FILE3);
29289
+ filePath = path57.join(directory, ".swarm", STATE_FILE3);
29153
29290
  tmpPath = `${filePath}.tmp.${Date.now()}`;
29154
29291
  persisted.updatedAt = nowISO3();
29155
29292
  payload = `${JSON.stringify(persisted, null, 2)}
@@ -29267,7 +29404,7 @@ var _internals43 = {
29267
29404
  };
29268
29405
  function readSpecStalenessSnapshot(directory) {
29269
29406
  try {
29270
- const p = path57.join(directory, ".swarm", "spec-staleness.json");
29407
+ const p = path58.join(directory, ".swarm", "spec-staleness.json");
29271
29408
  if (!fsSync3.existsSync(p))
29272
29409
  return { stale: false };
29273
29410
  const raw = fsSync3.readFileSync(p, "utf-8");
@@ -29520,7 +29657,7 @@ async function safeLineCount(filePath) {
29520
29657
  try {
29521
29658
  if (!fsSync3.existsSync(filePath))
29522
29659
  return 0;
29523
- const content = await readFile15(filePath, "utf-8");
29660
+ const content = await readFile16(filePath, "utf-8");
29524
29661
  let n = 0;
29525
29662
  for (const line of content.split(`
29526
29663
  `)) {
@@ -29934,7 +30071,7 @@ function buildDetailedHelp(commandName, entry) {
29934
30071
  async function handleHelpCommand(ctx) {
29935
30072
  const targetCommand = ctx.args.join(" ");
29936
30073
  if (!targetCommand) {
29937
- const { buildHelpText } = await import("./index-0rt5aamg.js");
30074
+ const { buildHelpText } = await import("./index-5p1gvn98.js");
29938
30075
  return buildHelpText();
29939
30076
  }
29940
30077
  const tokens = targetCommand.split(/\s+/);
@@ -29943,7 +30080,7 @@ async function handleHelpCommand(ctx) {
29943
30080
  return _internals45.buildDetailedHelp(resolved.key, resolved.entry);
29944
30081
  }
29945
30082
  const similar = _internals45.findSimilarCommands(targetCommand);
29946
- const { buildHelpText: fullHelp } = await import("./index-0rt5aamg.js");
30083
+ const { buildHelpText: fullHelp } = await import("./index-5p1gvn98.js");
29947
30084
  if (similar.length > 0) {
29948
30085
  return `Command '/swarm ${targetCommand}' not found.
29949
30086
 
@@ -30076,7 +30213,7 @@ var COMMAND_REGISTRY = {
30076
30213
  },
30077
30214
  "guardrail explain": {
30078
30215
  handler: async (ctx) => {
30079
- const { handleGuardrailExplain } = await import("./guardrail-explain-eqypvw60.js");
30216
+ const { handleGuardrailExplain } = await import("./guardrail-explain-xe0wjnxz.js");
30080
30217
  return handleGuardrailExplain(ctx.directory, ctx.args);
30081
30218
  },
30082
30219
  description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
@@ -30086,7 +30223,7 @@ var COMMAND_REGISTRY = {
30086
30223
  },
30087
30224
  "guardrail-log": {
30088
30225
  handler: async (ctx) => {
30089
- const { handleGuardrailLog } = await import("./guardrail-log-c7egm5km.js");
30226
+ const { handleGuardrailLog } = await import("./guardrail-log-m3285thy.js");
30090
30227
  return handleGuardrailLog(ctx.directory, ctx.args);
30091
30228
  },
30092
30229
  description: "Read the guardrail decision log (use --blocks-only for blocks)",
@@ -30764,6 +30901,14 @@ Subcommands:
30764
30901
  category: "utility",
30765
30902
  toolPolicy: "human-only"
30766
30903
  },
30904
+ "memory consolidation-log": {
30905
+ handler: (ctx) => handleMemoryConsolidationLogCommand(ctx.directory, ctx.args),
30906
+ description: "Summarize recent memory consolidation passes and metrics",
30907
+ subcommandOf: "memory",
30908
+ args: "--limit <n>",
30909
+ category: "diagnostics",
30910
+ toolPolicy: "agent"
30911
+ },
30767
30912
  "memory-status": {
30768
30913
  handler: (ctx) => handleMemoryStatusCommand(ctx.directory, ctx.args),
30769
30914
  description: "Show Swarm memory provider, JSONL, and migration status",
@@ -30816,24 +30961,24 @@ function validateAliases() {
30816
30961
  }
30817
30962
  aliasTargets.get(target).push(name);
30818
30963
  const visited = new Set;
30819
- const path58 = [];
30964
+ const path59 = [];
30820
30965
  let current = target;
30821
30966
  while (current) {
30822
30967
  const currentEntry = COMMAND_REGISTRY[current];
30823
30968
  if (!currentEntry)
30824
30969
  break;
30825
30970
  if (visited.has(current)) {
30826
- const cycleStart = path58.indexOf(current);
30971
+ const cycleStart = path59.indexOf(current);
30827
30972
  const fullChain = [
30828
30973
  name,
30829
- ...path58.slice(0, cycleStart > 0 ? cycleStart : path58.length),
30974
+ ...path59.slice(0, cycleStart > 0 ? cycleStart : path59.length),
30830
30975
  current
30831
30976
  ].join(" \u2192 ");
30832
30977
  errors.push(`Circular alias detected: ${fullChain}`);
30833
30978
  break;
30834
30979
  }
30835
30980
  visited.add(current);
30836
- path58.push(current);
30981
+ path59.push(current);
30837
30982
  current = currentEntry.aliasOf || "";
30838
30983
  }
30839
30984
  }