opencode-swarm 6.33.0 → 6.33.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -14798,6 +14798,7 @@ var init_schema = __esm(() => {
14798
14798
  max_consecutive_errors: exports_external.number().min(2).max(20).default(5),
14799
14799
  warning_threshold: exports_external.number().min(0.1).max(0.9).default(0.75),
14800
14800
  idle_timeout_minutes: exports_external.number().min(5).max(240).default(60),
14801
+ no_op_warning_threshold: exports_external.number().min(1).max(100).default(15),
14801
14802
  qa_gates: exports_external.object({
14802
14803
  required_tools: exports_external.array(exports_external.string().min(1)).default([
14803
14804
  "diff",
@@ -14913,6 +14914,7 @@ var init_schema = __esm(() => {
14913
14914
  pipeline: PipelineConfigSchema.optional(),
14914
14915
  phase_complete: PhaseCompleteConfigSchema.optional(),
14915
14916
  qa_retry_limit: exports_external.number().min(1).max(10).default(3),
14917
+ execution_mode: exports_external.enum(["strict", "balanced", "fast"]).default("balanced"),
14916
14918
  inject_phase_reminders: exports_external.boolean().default(true),
14917
14919
  hooks: HooksConfigSchema.optional(),
14918
14920
  gates: GateConfigSchema.optional(),
@@ -36248,7 +36250,7 @@ __export(exports_gate_evidence, {
36248
36250
  deriveRequiredGates: () => deriveRequiredGates,
36249
36251
  DEFAULT_REQUIRED_GATES: () => DEFAULT_REQUIRED_GATES
36250
36252
  });
36251
- import { mkdirSync as mkdirSync9, readFileSync as readFileSync14, renameSync as renameSync8, unlinkSync as unlinkSync4 } from "fs";
36253
+ import { mkdirSync as mkdirSync9, readFileSync as readFileSync14, renameSync as renameSync8, unlinkSync as unlinkSync5 } from "fs";
36252
36254
  import * as path30 from "path";
36253
36255
  function isValidTaskId2(taskId) {
36254
36256
  if (!taskId)
@@ -36316,7 +36318,7 @@ async function atomicWrite(targetPath, content) {
36316
36318
  renameSync8(tempPath, targetPath);
36317
36319
  } finally {
36318
36320
  try {
36319
- unlinkSync4(tempPath);
36321
+ unlinkSync5(tempPath);
36320
36322
  } catch {}
36321
36323
  }
36322
36324
  }
@@ -46774,6 +46776,8 @@ function formatHandoffMarkdown(data) {
46774
46776
  init_utils2();
46775
46777
  import { mkdirSync as mkdirSync7, renameSync as renameSync4 } from "fs";
46776
46778
  import * as path19 from "path";
46779
+ var pendingWrite = null;
46780
+ var lastWritePromise = Promise.resolve();
46777
46781
  function serializeAgentSession(s) {
46778
46782
  const gateLog = {};
46779
46783
  const rawGateLog = s.gateLog ?? new Map;
@@ -46858,14 +46862,28 @@ async function writeSnapshot(directory, state) {
46858
46862
  const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
46859
46863
  await Bun.write(tempPath, content);
46860
46864
  renameSync4(tempPath, resolvedPath);
46861
- } catch {}
46865
+ } catch (error93) {
46866
+ console.warn("[snapshot-writer] write failed:", error93 instanceof Error ? error93.message : String(error93));
46867
+ }
46862
46868
  }
46863
46869
  function createSnapshotWriterHook(directory) {
46864
46870
  return async (_input, _output) => {
46865
- try {
46866
- await writeSnapshot(directory, swarmState);
46867
- } catch {}
46868
- };
46871
+ if (pendingWrite)
46872
+ clearTimeout(pendingWrite);
46873
+ pendingWrite = setTimeout(() => {
46874
+ pendingWrite = null;
46875
+ lastWritePromise = writeSnapshot(directory, swarmState).catch(() => {});
46876
+ }, 2000);
46877
+ };
46878
+ }
46879
+ async function flushPendingSnapshot(directory) {
46880
+ if (pendingWrite) {
46881
+ clearTimeout(pendingWrite);
46882
+ pendingWrite = null;
46883
+ await writeSnapshot(directory, swarmState).catch(() => {});
46884
+ } else {
46885
+ await lastWritePromise;
46886
+ }
46869
46887
  }
46870
46888
 
46871
46889
  // src/commands/handoff.ts
@@ -46877,6 +46895,7 @@ async function handleHandoffCommand(directory, _args) {
46877
46895
  await Bun.write(tempPath, markdown);
46878
46896
  renameSync5(tempPath, resolvedPath);
46879
46897
  await writeSnapshot(directory, swarmState);
46898
+ await flushPendingSnapshot(directory);
46880
46899
  return `## Handoff Brief Written
46881
46900
 
46882
46901
  Brief written to \`.swarm/handoff.md\`.
@@ -47586,6 +47605,37 @@ async function handleResetCommand(directory, args2) {
47586
47605
  `);
47587
47606
  }
47588
47607
 
47608
+ // src/commands/reset-session.ts
47609
+ init_utils2();
47610
+ import * as fs15 from "fs";
47611
+ async function handleResetSessionCommand(directory, _args) {
47612
+ const results = [];
47613
+ try {
47614
+ const statePath = validateSwarmPath(directory, "session/state.json");
47615
+ if (fs15.existsSync(statePath)) {
47616
+ fs15.unlinkSync(statePath);
47617
+ results.push("\u2705 Deleted .swarm/session/state.json");
47618
+ } else {
47619
+ results.push("\u23ED\uFE0F state.json not found (already clean)");
47620
+ }
47621
+ } catch {
47622
+ results.push("\u274C Failed to delete state.json");
47623
+ }
47624
+ const sessionCount = swarmState.agentSessions.size;
47625
+ swarmState.agentSessions.clear();
47626
+ results.push(`\u2705 Cleared ${sessionCount} in-memory agent session(s)`);
47627
+ return [
47628
+ "## Session State Reset",
47629
+ "",
47630
+ ...results,
47631
+ "",
47632
+ "Session state cleared. Plan, evidence, and knowledge preserved.",
47633
+ "",
47634
+ "**Next step:** Start a new OpenCode session. The plugin will initialize fresh session state on startup."
47635
+ ].join(`
47636
+ `);
47637
+ }
47638
+
47589
47639
  // src/summaries/manager.ts
47590
47640
  init_utils2();
47591
47641
  init_utils();
@@ -47696,18 +47746,18 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
47696
47746
 
47697
47747
  // src/commands/rollback.ts
47698
47748
  init_utils2();
47699
- import * as fs15 from "fs";
47749
+ import * as fs16 from "fs";
47700
47750
  import * as path27 from "path";
47701
47751
  async function handleRollbackCommand(directory, args2) {
47702
47752
  const phaseArg = args2[0];
47703
47753
  if (!phaseArg) {
47704
47754
  const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
47705
- if (!fs15.existsSync(manifestPath2)) {
47755
+ if (!fs16.existsSync(manifestPath2)) {
47706
47756
  return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
47707
47757
  }
47708
47758
  let manifest2;
47709
47759
  try {
47710
- manifest2 = JSON.parse(fs15.readFileSync(manifestPath2, "utf-8"));
47760
+ manifest2 = JSON.parse(fs16.readFileSync(manifestPath2, "utf-8"));
47711
47761
  } catch {
47712
47762
  return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
47713
47763
  }
@@ -47729,12 +47779,12 @@ async function handleRollbackCommand(directory, args2) {
47729
47779
  return "Error: Phase number must be a positive integer.";
47730
47780
  }
47731
47781
  const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
47732
- if (!fs15.existsSync(manifestPath)) {
47782
+ if (!fs16.existsSync(manifestPath)) {
47733
47783
  return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
47734
47784
  }
47735
47785
  let manifest;
47736
47786
  try {
47737
- manifest = JSON.parse(fs15.readFileSync(manifestPath, "utf-8"));
47787
+ manifest = JSON.parse(fs16.readFileSync(manifestPath, "utf-8"));
47738
47788
  } catch {
47739
47789
  return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
47740
47790
  }
@@ -47744,10 +47794,10 @@ async function handleRollbackCommand(directory, args2) {
47744
47794
  return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
47745
47795
  }
47746
47796
  const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
47747
- if (!fs15.existsSync(checkpointDir)) {
47797
+ if (!fs16.existsSync(checkpointDir)) {
47748
47798
  return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
47749
47799
  }
47750
- const checkpointFiles = fs15.readdirSync(checkpointDir);
47800
+ const checkpointFiles = fs16.readdirSync(checkpointDir);
47751
47801
  if (checkpointFiles.length === 0) {
47752
47802
  return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
47753
47803
  }
@@ -47758,7 +47808,7 @@ async function handleRollbackCommand(directory, args2) {
47758
47808
  const src = path27.join(checkpointDir, file3);
47759
47809
  const dest = path27.join(swarmDir, file3);
47760
47810
  try {
47761
- fs15.cpSync(src, dest, { recursive: true, force: true });
47811
+ fs16.cpSync(src, dest, { recursive: true, force: true });
47762
47812
  successes.push(file3);
47763
47813
  } catch (error93) {
47764
47814
  failures.push({ file: file3, error: error93.message });
@@ -47775,7 +47825,7 @@ async function handleRollbackCommand(directory, args2) {
47775
47825
  timestamp: new Date().toISOString()
47776
47826
  };
47777
47827
  try {
47778
- fs15.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
47828
+ fs16.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
47779
47829
  `);
47780
47830
  } catch (error93) {
47781
47831
  console.error("Failed to write rollback event:", error93);
@@ -47818,11 +47868,11 @@ async function handleSimulateCommand(directory, args2) {
47818
47868
  ];
47819
47869
  const report = reportLines.filter(Boolean).join(`
47820
47870
  `);
47821
- const fs16 = await import("fs/promises");
47871
+ const fs17 = await import("fs/promises");
47822
47872
  const path28 = await import("path");
47823
47873
  const reportPath = path28.join(directory, ".swarm", "simulate-report.md");
47824
- await fs16.mkdir(path28.dirname(reportPath), { recursive: true });
47825
- await fs16.writeFile(reportPath, report, "utf-8");
47874
+ await fs17.mkdir(path28.dirname(reportPath), { recursive: true });
47875
+ await fs17.writeFile(reportPath, report, "utf-8");
47826
47876
  return `${darkMatterPairs.length} hidden coupling pairs detected`;
47827
47877
  }
47828
47878
 
@@ -48179,7 +48229,7 @@ init_utils2();
48179
48229
  init_manager2();
48180
48230
 
48181
48231
  // src/services/compaction-service.ts
48182
- import * as fs16 from "fs";
48232
+ import * as fs17 from "fs";
48183
48233
  import * as path28 from "path";
48184
48234
  function makeInitialState() {
48185
48235
  return {
@@ -48201,7 +48251,7 @@ function appendSnapshot(directory, tier, budgetPct, message) {
48201
48251
  ## [${tier.toUpperCase()}] ${timestamp} \u2014 ${budgetPct.toFixed(1)}% used
48202
48252
  ${message}
48203
48253
  `;
48204
- fs16.appendFileSync(snapshotPath, entry, "utf-8");
48254
+ fs17.appendFileSync(snapshotPath, entry, "utf-8");
48205
48255
  } catch {}
48206
48256
  }
48207
48257
  function buildObservationMessage(budgetPct) {
@@ -49029,6 +49079,10 @@ var COMMAND_REGISTRY = {
49029
49079
  handler: (ctx) => handleResetCommand(ctx.directory, ctx.args),
49030
49080
  description: "Clear swarm state files [--confirm]"
49031
49081
  },
49082
+ "reset-session": {
49083
+ handler: (ctx) => handleResetSessionCommand(ctx.directory, ctx.args),
49084
+ description: "Clear session state while preserving plan, evidence, and knowledge"
49085
+ },
49032
49086
  rollback: {
49033
49087
  handler: (ctx) => handleRollbackCommand(ctx.directory, ctx.args),
49034
49088
  description: "Restore swarm state to a checkpoint <phase>"
@@ -49133,7 +49187,7 @@ init_constants();
49133
49187
  init_schema();
49134
49188
 
49135
49189
  // src/hooks/agent-activity.ts
49136
- import { renameSync as renameSync7, unlinkSync as unlinkSync3 } from "fs";
49190
+ import { renameSync as renameSync7, unlinkSync as unlinkSync4 } from "fs";
49137
49191
  init_utils();
49138
49192
  init_utils2();
49139
49193
  function createAgentActivityHooks(config3, directory) {
@@ -49210,7 +49264,7 @@ async function doFlush(directory) {
49210
49264
  renameSync7(tempPath, path29);
49211
49265
  } catch (writeError) {
49212
49266
  try {
49213
- unlinkSync3(tempPath);
49267
+ unlinkSync4(tempPath);
49214
49268
  } catch {}
49215
49269
  throw writeError;
49216
49270
  }
@@ -49256,7 +49310,7 @@ ${content.substring(endIndex + 1)}`;
49256
49310
  }
49257
49311
  // src/hooks/compaction-customizer.ts
49258
49312
  init_manager2();
49259
- import * as fs17 from "fs";
49313
+ import * as fs18 from "fs";
49260
49314
  import { join as join25 } from "path";
49261
49315
  init_utils2();
49262
49316
  function createCompactionCustomizerHook(config3, directory) {
@@ -49304,7 +49358,7 @@ function createCompactionCustomizerHook(config3, directory) {
49304
49358
  }
49305
49359
  try {
49306
49360
  const summariesDir = join25(directory, ".swarm", "summaries");
49307
- const files = await fs17.promises.readdir(summariesDir);
49361
+ const files = await fs18.promises.readdir(summariesDir);
49308
49362
  if (files.length > 0) {
49309
49363
  const count = files.length;
49310
49364
  output.context.push(`[CONTEXT OPTIMIZATION] Tool outputs from earlier in this session have been stored to disk. When compacting, replace any large tool output blocks (bash, test_runner, lint, diff results) with a one-line reference: "[Output stored \u2014 use /swarm retrieve to access full content]". Preserve the tool name, exit status, and any error messages. Discard raw output lines.`);
@@ -49789,7 +49843,7 @@ function maskToolOutput(msg, _threshold) {
49789
49843
  }
49790
49844
  // src/hooks/delegation-gate.ts
49791
49845
  init_schema();
49792
- import * as fs18 from "fs";
49846
+ import * as fs19 from "fs";
49793
49847
  import * as path31 from "path";
49794
49848
 
49795
49849
  // src/hooks/guardrails.ts
@@ -49850,6 +49904,8 @@ function setStoredInputArgs(callID, args2) {
49850
49904
  function deleteStoredInputArgs(callID) {
49851
49905
  storedInputArgs.delete(callID);
49852
49906
  }
49907
+ var toolCallsSinceLastWrite = new Map;
49908
+ var noOpWarningIssued = new Set;
49853
49909
  function extractPhaseNumber(phaseString) {
49854
49910
  if (!phaseString)
49855
49911
  return 1;
@@ -50367,6 +50423,19 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
50367
50423
  session.modifiedFilesThisCoderTask = [];
50368
50424
  }
50369
50425
  }
50426
+ const sessionId = input.sessionID;
50427
+ const normalizedToolName = input.tool.replace(/^[^:]+[:.]/, "");
50428
+ if (isWriteTool(normalizedToolName)) {
50429
+ toolCallsSinceLastWrite.set(sessionId, 0);
50430
+ } else {
50431
+ const count = (toolCallsSinceLastWrite.get(sessionId) ?? 0) + 1;
50432
+ toolCallsSinceLastWrite.set(sessionId, count);
50433
+ const threshold = cfg.no_op_warning_threshold ?? 15;
50434
+ if (count >= threshold && !noOpWarningIssued.has(sessionId) && session?.pendingAdvisoryMessages) {
50435
+ noOpWarningIssued.add(sessionId);
50436
+ session.pendingAdvisoryMessages.push(`WARNING: Agent has made ${count} tool calls with no file modifications. If you are stuck, use /swarm handoff to reset or /swarm turbo to reduce overhead.`);
50437
+ }
50438
+ }
50370
50439
  const window2 = getActiveWindow(input.sessionID);
50371
50440
  if (!window2)
50372
50441
  return;
@@ -50652,6 +50721,7 @@ function hashArgs(args2) {
50652
50721
 
50653
50722
  // src/hooks/delegation-gate.ts
50654
50723
  init_utils2();
50724
+ var pendingCoderScopeByTaskId = new Map;
50655
50725
  function extractTaskLine(text) {
50656
50726
  const match = text.match(/TASK:\s*(.+?)(?:\n|$)/i);
50657
50727
  return match ? match[1].trim() : null;
@@ -50687,7 +50757,7 @@ function getEvidenceTaskId(session, directory) {
50687
50757
  if (!resolvedPlanPath.startsWith(resolvedDirectory + path31.sep) && resolvedPlanPath !== resolvedDirectory) {
50688
50758
  return null;
50689
50759
  }
50690
- const planContent = fs18.readFileSync(resolvedPlanPath, "utf-8");
50760
+ const planContent = fs19.readFileSync(resolvedPlanPath, "utf-8");
50691
50761
  const plan = JSON.parse(planContent);
50692
50762
  if (!plan || !Array.isArray(plan.phases)) {
50693
50763
  return null;
@@ -51037,6 +51107,11 @@ ${trimComment}${after}`;
51037
51107
  }
51038
51108
  }
51039
51109
  session.declaredCoderScope = declaredFiles.length > 0 ? declaredFiles : null;
51110
+ if (declaredFiles.length > 0 && currentTaskId) {
51111
+ pendingCoderScopeByTaskId.set(currentTaskId, declaredFiles);
51112
+ } else {
51113
+ pendingCoderScopeByTaskId.delete(currentTaskId);
51114
+ }
51040
51115
  try {
51041
51116
  advanceTaskState(session, currentTaskId, "coder_delegated");
51042
51117
  } catch (err2) {
@@ -51164,7 +51239,7 @@ ${warningLines.join(`
51164
51239
  }
51165
51240
  // src/hooks/delegation-sanitizer.ts
51166
51241
  init_utils2();
51167
- import * as fs19 from "fs";
51242
+ import * as fs20 from "fs";
51168
51243
  var SANITIZATION_PATTERNS = [
51169
51244
  /\b\d+(st|nd|rd|th)\s+(attempt|try|time)\b/gi,
51170
51245
  /\b(5th|fifth|final|last)\s+attempt\b/gi,
@@ -51235,7 +51310,7 @@ function createDelegationSanitizerHook(directory) {
51235
51310
  stripped_patterns: result.stripped,
51236
51311
  timestamp: new Date().toISOString()
51237
51312
  };
51238
- fs19.appendFileSync(eventsPath, `${JSON.stringify(event)}
51313
+ fs20.appendFileSync(eventsPath, `${JSON.stringify(event)}
51239
51314
  `, "utf-8");
51240
51315
  } catch {}
51241
51316
  }
@@ -51492,12 +51567,12 @@ init_schema();
51492
51567
  init_manager();
51493
51568
  init_detector();
51494
51569
  init_manager2();
51495
- import * as fs21 from "fs";
51570
+ import * as fs22 from "fs";
51496
51571
 
51497
51572
  // src/services/decision-drift-analyzer.ts
51498
51573
  init_utils2();
51499
51574
  init_manager2();
51500
- import * as fs20 from "fs";
51575
+ import * as fs21 from "fs";
51501
51576
  import * as path33 from "path";
51502
51577
  var DEFAULT_DRIFT_CONFIG = {
51503
51578
  staleThresholdPhases: 1,
@@ -51655,8 +51730,8 @@ async function analyzeDecisionDrift(directory, config3 = {}) {
51655
51730
  const contextPath = path33.join(directory, ".swarm", "context.md");
51656
51731
  let contextContent = "";
51657
51732
  try {
51658
- if (fs20.existsSync(contextPath)) {
51659
- contextContent = fs20.readFileSync(contextPath, "utf-8");
51733
+ if (fs21.existsSync(contextPath)) {
51734
+ contextContent = fs21.readFileSync(contextPath, "utf-8");
51660
51735
  }
51661
51736
  } catch {
51662
51737
  return {
@@ -52150,11 +52225,11 @@ function createSystemEnhancerHook(config3, directory) {
52150
52225
  if (handoffContent) {
52151
52226
  const handoffPath = validateSwarmPath(directory, "handoff.md");
52152
52227
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
52153
- if (fs21.existsSync(consumedPath)) {
52228
+ if (fs22.existsSync(consumedPath)) {
52154
52229
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
52155
- fs21.unlinkSync(consumedPath);
52230
+ fs22.unlinkSync(consumedPath);
52156
52231
  }
52157
- fs21.renameSync(handoffPath, consumedPath);
52232
+ fs22.renameSync(handoffPath, consumedPath);
52158
52233
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
52159
52234
  The previous model's session ended. Here is your starting context:
52160
52235
 
@@ -52434,11 +52509,11 @@ ${budgetWarning}`);
52434
52509
  if (handoffContent) {
52435
52510
  const handoffPath = validateSwarmPath(directory, "handoff.md");
52436
52511
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
52437
- if (fs21.existsSync(consumedPath)) {
52512
+ if (fs22.existsSync(consumedPath)) {
52438
52513
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
52439
- fs21.unlinkSync(consumedPath);
52514
+ fs22.unlinkSync(consumedPath);
52440
52515
  }
52441
- fs21.renameSync(handoffPath, consumedPath);
52516
+ fs22.renameSync(handoffPath, consumedPath);
52442
52517
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
52443
52518
  The previous model's session ended. Here is your starting context:
52444
52519
 
@@ -53207,7 +53282,7 @@ function isReadTool(toolName) {
53207
53282
  }
53208
53283
 
53209
53284
  // src/hooks/incremental-verify.ts
53210
- import * as fs22 from "fs";
53285
+ import * as fs23 from "fs";
53211
53286
  import * as path34 from "path";
53212
53287
 
53213
53288
  // src/hooks/spawn-helper.ts
@@ -53283,21 +53358,21 @@ function spawnAsync(command, cwd, timeoutMs) {
53283
53358
  // src/hooks/incremental-verify.ts
53284
53359
  var emittedSkipAdvisories = new Set;
53285
53360
  function detectPackageManager(projectDir) {
53286
- if (fs22.existsSync(path34.join(projectDir, "bun.lockb")))
53361
+ if (fs23.existsSync(path34.join(projectDir, "bun.lockb")))
53287
53362
  return "bun";
53288
- if (fs22.existsSync(path34.join(projectDir, "pnpm-lock.yaml")))
53363
+ if (fs23.existsSync(path34.join(projectDir, "pnpm-lock.yaml")))
53289
53364
  return "pnpm";
53290
- if (fs22.existsSync(path34.join(projectDir, "yarn.lock")))
53365
+ if (fs23.existsSync(path34.join(projectDir, "yarn.lock")))
53291
53366
  return "yarn";
53292
- if (fs22.existsSync(path34.join(projectDir, "package-lock.json")))
53367
+ if (fs23.existsSync(path34.join(projectDir, "package-lock.json")))
53293
53368
  return "npm";
53294
53369
  return "bun";
53295
53370
  }
53296
53371
  function detectTypecheckCommand(projectDir) {
53297
53372
  const pkgPath = path34.join(projectDir, "package.json");
53298
- if (fs22.existsSync(pkgPath)) {
53373
+ if (fs23.existsSync(pkgPath)) {
53299
53374
  try {
53300
- const pkg = JSON.parse(fs22.readFileSync(pkgPath, "utf8"));
53375
+ const pkg = JSON.parse(fs23.readFileSync(pkgPath, "utf8"));
53301
53376
  const scripts = pkg.scripts;
53302
53377
  if (scripts?.typecheck) {
53303
53378
  const pm = detectPackageManager(projectDir);
@@ -53311,8 +53386,8 @@ function detectTypecheckCommand(projectDir) {
53311
53386
  ...pkg.dependencies,
53312
53387
  ...pkg.devDependencies
53313
53388
  };
53314
- if (!deps?.typescript && !fs22.existsSync(path34.join(projectDir, "tsconfig.json"))) {}
53315
- const hasTSMarkers = deps?.typescript || fs22.existsSync(path34.join(projectDir, "tsconfig.json"));
53389
+ if (!deps?.typescript && !fs23.existsSync(path34.join(projectDir, "tsconfig.json"))) {}
53390
+ const hasTSMarkers = deps?.typescript || fs23.existsSync(path34.join(projectDir, "tsconfig.json"));
53316
53391
  if (hasTSMarkers) {
53317
53392
  return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
53318
53393
  }
@@ -53320,17 +53395,17 @@ function detectTypecheckCommand(projectDir) {
53320
53395
  return null;
53321
53396
  }
53322
53397
  }
53323
- if (fs22.existsSync(path34.join(projectDir, "go.mod"))) {
53398
+ if (fs23.existsSync(path34.join(projectDir, "go.mod"))) {
53324
53399
  return { command: ["go", "vet", "./..."], language: "go" };
53325
53400
  }
53326
- if (fs22.existsSync(path34.join(projectDir, "Cargo.toml"))) {
53401
+ if (fs23.existsSync(path34.join(projectDir, "Cargo.toml"))) {
53327
53402
  return { command: ["cargo", "check"], language: "rust" };
53328
53403
  }
53329
- if (fs22.existsSync(path34.join(projectDir, "pyproject.toml")) || fs22.existsSync(path34.join(projectDir, "requirements.txt")) || fs22.existsSync(path34.join(projectDir, "setup.py"))) {
53404
+ if (fs23.existsSync(path34.join(projectDir, "pyproject.toml")) || fs23.existsSync(path34.join(projectDir, "requirements.txt")) || fs23.existsSync(path34.join(projectDir, "setup.py"))) {
53330
53405
  return { command: null, language: "python" };
53331
53406
  }
53332
53407
  try {
53333
- const entries = fs22.readdirSync(projectDir);
53408
+ const entries = fs23.readdirSync(projectDir);
53334
53409
  if (entries.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
53335
53410
  return {
53336
53411
  command: ["dotnet", "build", "--no-restore"],
@@ -53399,7 +53474,7 @@ ${errorSummary}`);
53399
53474
  }
53400
53475
 
53401
53476
  // src/hooks/knowledge-reader.ts
53402
- import { existsSync as existsSync20 } from "fs";
53477
+ import { existsSync as existsSync21 } from "fs";
53403
53478
  import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
53404
53479
  import * as path35 from "path";
53405
53480
  var JACCARD_THRESHOLD = 0.6;
@@ -53452,7 +53527,7 @@ async function recordLessonsShown(directory, lessonIds, currentPhase) {
53452
53527
  const shownFile = path35.join(directory, ".swarm", ".knowledge-shown.json");
53453
53528
  try {
53454
53529
  let shownData = {};
53455
- if (existsSync20(shownFile)) {
53530
+ if (existsSync21(shownFile)) {
53456
53531
  const content = await readFile5(shownFile, "utf-8");
53457
53532
  shownData = JSON.parse(content);
53458
53533
  }
@@ -53554,7 +53629,7 @@ async function readMergedKnowledge(directory, config3, context) {
53554
53629
  async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
53555
53630
  const shownFile = path35.join(directory, ".swarm", ".knowledge-shown.json");
53556
53631
  try {
53557
- if (!existsSync20(shownFile)) {
53632
+ if (!existsSync21(shownFile)) {
53558
53633
  return;
53559
53634
  }
53560
53635
  const content = await readFile5(shownFile, "utf-8");
@@ -54024,12 +54099,12 @@ Use this data to avoid repeating known failure patterns.`;
54024
54099
  // src/hooks/curator-drift.ts
54025
54100
  init_event_bus();
54026
54101
  init_utils2();
54027
- import * as fs23 from "fs";
54102
+ import * as fs24 from "fs";
54028
54103
  import * as path36 from "path";
54029
54104
  var DRIFT_REPORT_PREFIX = "drift-report-phase-";
54030
54105
  async function readPriorDriftReports(directory) {
54031
54106
  const swarmDir = path36.join(directory, ".swarm");
54032
- const entries = await fs23.promises.readdir(swarmDir).catch(() => null);
54107
+ const entries = await fs24.promises.readdir(swarmDir).catch(() => null);
54033
54108
  if (entries === null)
54034
54109
  return [];
54035
54110
  const reportFiles = entries.filter((name2) => name2.startsWith(DRIFT_REPORT_PREFIX) && name2.endsWith(".json")).sort();
@@ -54056,9 +54131,9 @@ async function writeDriftReport(directory, report) {
54056
54131
  const filename = `${DRIFT_REPORT_PREFIX}${report.phase}.json`;
54057
54132
  const filePath = validateSwarmPath(directory, filename);
54058
54133
  const swarmDir = path36.dirname(filePath);
54059
- await fs23.promises.mkdir(swarmDir, { recursive: true });
54134
+ await fs24.promises.mkdir(swarmDir, { recursive: true });
54060
54135
  try {
54061
- await fs23.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
54136
+ await fs24.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
54062
54137
  } catch (err2) {
54063
54138
  throw new Error(`[curator-drift] Failed to write drift report to ${filePath}: ${String(err2)}`);
54064
54139
  }
@@ -54344,7 +54419,7 @@ var WRITE_TOOLS = new Set([
54344
54419
  "append",
54345
54420
  "prepend"
54346
54421
  ]);
54347
- function createScopeGuardHook(config3, _directory, injectAdvisory) {
54422
+ function createScopeGuardHook(config3, directory, injectAdvisory) {
54348
54423
  const enabled = config3.enabled ?? true;
54349
54424
  const _skipInTurbo = config3.skip_in_turbo ?? false;
54350
54425
  return {
@@ -54361,7 +54436,7 @@ function createScopeGuardHook(config3, _directory, injectAdvisory) {
54361
54436
  const isArchitect2 = stripKnownSwarmPrefix(agentName) === ORCHESTRATOR_NAME;
54362
54437
  if (isArchitect2)
54363
54438
  return;
54364
- const declaredScope = session?.declaredCoderScope;
54439
+ const declaredScope = session?.declaredCoderScope ?? (session?.currentTaskId ? pendingCoderScopeByTaskId.get(session.currentTaskId) : null);
54365
54440
  if (!declaredScope || declaredScope.length === 0)
54366
54441
  return;
54367
54442
  const argsObj = output.args;
@@ -54369,7 +54444,7 @@ function createScopeGuardHook(config3, _directory, injectAdvisory) {
54369
54444
  if (typeof rawFilePath !== "string" || !rawFilePath)
54370
54445
  return;
54371
54446
  const filePath = rawFilePath.replace(/[\r\n\t]/g, "_").split(String.fromCharCode(27)).join("_").replace(/\[[\d;]*m/g, "");
54372
- if (!isFileInScope(filePath, declaredScope)) {
54447
+ if (!isFileInScope(filePath, declaredScope, directory)) {
54373
54448
  const taskId = session?.currentTaskId ?? "unknown";
54374
54449
  const violationMessage = `SCOPE VIOLATION: ${agentName} attempted to modify '${filePath}' which is not in declared scope for task ${taskId}. Declared scope: [${declaredScope.slice(0, 3).join(", ")}${declaredScope.length > 3 ? "..." : ""}]`;
54375
54450
  if (session) {
@@ -54392,10 +54467,11 @@ function createScopeGuardHook(config3, _directory, injectAdvisory) {
54392
54467
  }
54393
54468
  };
54394
54469
  }
54395
- function isFileInScope(filePath, scopeEntries) {
54396
- const resolvedFile = path37.resolve(filePath);
54470
+ function isFileInScope(filePath, scopeEntries, directory) {
54471
+ const dir = directory ?? process.cwd();
54472
+ const resolvedFile = path37.resolve(dir, filePath);
54397
54473
  return scopeEntries.some((scope) => {
54398
- const resolvedScope = path37.resolve(scope);
54474
+ const resolvedScope = path37.resolve(dir, scope);
54399
54475
  if (resolvedFile === resolvedScope)
54400
54476
  return true;
54401
54477
  const rel = path37.relative(resolvedScope, resolvedFile);
@@ -54448,7 +54524,7 @@ function createSelfReviewHook(config3, injectAdvisory) {
54448
54524
  }
54449
54525
 
54450
54526
  // src/hooks/slop-detector.ts
54451
- import * as fs24 from "fs";
54527
+ import * as fs25 from "fs";
54452
54528
  import * as path38 from "path";
54453
54529
  var WRITE_EDIT_TOOLS = new Set([
54454
54530
  "write",
@@ -54494,7 +54570,7 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
54494
54570
  function walkFiles(dir, exts, deadline) {
54495
54571
  const results = [];
54496
54572
  try {
54497
- for (const entry of fs24.readdirSync(dir, { withFileTypes: true })) {
54573
+ for (const entry of fs25.readdirSync(dir, { withFileTypes: true })) {
54498
54574
  if (deadline !== undefined && Date.now() > deadline)
54499
54575
  break;
54500
54576
  if (entry.isSymbolicLink())
@@ -54514,7 +54590,7 @@ function walkFiles(dir, exts, deadline) {
54514
54590
  return results;
54515
54591
  }
54516
54592
  function checkDeadExports(content, projectDir, startTime) {
54517
- const hasPackageJson = fs24.existsSync(path38.join(projectDir, "package.json"));
54593
+ const hasPackageJson = fs25.existsSync(path38.join(projectDir, "package.json"));
54518
54594
  if (!hasPackageJson)
54519
54595
  return null;
54520
54596
  const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
@@ -54537,7 +54613,7 @@ function checkDeadExports(content, projectDir, startTime) {
54537
54613
  if (found || Date.now() - startTime > 480)
54538
54614
  break;
54539
54615
  try {
54540
- const text = fs24.readFileSync(file3, "utf-8");
54616
+ const text = fs25.readFileSync(file3, "utf-8");
54541
54617
  if (importPattern.test(text))
54542
54618
  found = true;
54543
54619
  importPattern.lastIndex = 0;
@@ -54670,7 +54746,7 @@ Review before proceeding.`;
54670
54746
 
54671
54747
  // src/hooks/steering-consumed.ts
54672
54748
  init_utils2();
54673
- import * as fs25 from "fs";
54749
+ import * as fs26 from "fs";
54674
54750
  function recordSteeringConsumed(directory, directiveId) {
54675
54751
  try {
54676
54752
  const eventsPath = validateSwarmPath(directory, "events.jsonl");
@@ -54679,7 +54755,7 @@ function recordSteeringConsumed(directory, directiveId) {
54679
54755
  directiveId,
54680
54756
  timestamp: new Date().toISOString()
54681
54757
  };
54682
- fs25.appendFileSync(eventsPath, `${JSON.stringify(event)}
54758
+ fs26.appendFileSync(eventsPath, `${JSON.stringify(event)}
54683
54759
  `, "utf-8");
54684
54760
  } catch {}
54685
54761
  }
@@ -54845,6 +54921,10 @@ async function rehydrateState(snapshot) {
54845
54921
  }
54846
54922
  if (snapshot.agentSessions) {
54847
54923
  for (const [sessionId, serializedSession] of Object.entries(snapshot.agentSessions)) {
54924
+ if (!serializedSession || typeof serializedSession !== "object" || typeof serializedSession.agentName !== "string" || typeof serializedSession.lastToolCallTime !== "number" || typeof serializedSession.delegationActive !== "boolean") {
54925
+ console.warn("[snapshot-reader] Skipping malformed session %s: missing required fields (agentName, lastToolCallTime, delegationActive)", sessionId);
54926
+ continue;
54927
+ }
54848
54928
  swarmState.agentSessions.set(sessionId, deserializeAgentSession(serializedSession));
54849
54929
  }
54850
54930
  }
@@ -55036,7 +55116,7 @@ var build_check = createSwarmTool({
55036
55116
  // src/tools/check-gate-status.ts
55037
55117
  init_dist();
55038
55118
  init_create_tool();
55039
- import * as fs26 from "fs";
55119
+ import * as fs27 from "fs";
55040
55120
  import * as path39 from "path";
55041
55121
  var EVIDENCE_DIR = ".swarm/evidence";
55042
55122
  var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
@@ -55060,12 +55140,12 @@ function isPathWithinSwarm(filePath, workspaceRoot) {
55060
55140
  return normalizedPath.startsWith(swarmPath);
55061
55141
  }
55062
55142
  function readEvidenceFile(evidencePath) {
55063
- if (!fs26.existsSync(evidencePath)) {
55143
+ if (!fs27.existsSync(evidencePath)) {
55064
55144
  return null;
55065
55145
  }
55066
55146
  let content;
55067
55147
  try {
55068
- content = fs26.readFileSync(evidencePath, "utf-8");
55148
+ content = fs27.readFileSync(evidencePath, "utf-8");
55069
55149
  } catch {
55070
55150
  return null;
55071
55151
  }
@@ -55186,7 +55266,7 @@ init_checkpoint();
55186
55266
  // src/tools/complexity-hotspots.ts
55187
55267
  init_dist();
55188
55268
  init_create_tool();
55189
- import * as fs27 from "fs";
55269
+ import * as fs28 from "fs";
55190
55270
  import * as path40 from "path";
55191
55271
  var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
55192
55272
  var DEFAULT_DAYS = 90;
@@ -55316,11 +55396,11 @@ function estimateComplexity(content) {
55316
55396
  }
55317
55397
  function getComplexityForFile(filePath) {
55318
55398
  try {
55319
- const stat2 = fs27.statSync(filePath);
55399
+ const stat2 = fs28.statSync(filePath);
55320
55400
  if (stat2.size > MAX_FILE_SIZE_BYTES2) {
55321
55401
  return null;
55322
55402
  }
55323
- const content = fs27.readFileSync(filePath, "utf-8");
55403
+ const content = fs28.readFileSync(filePath, "utf-8");
55324
55404
  return estimateComplexity(content);
55325
55405
  } catch {
55326
55406
  return null;
@@ -55341,7 +55421,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
55341
55421
  let analyzedFiles = 0;
55342
55422
  for (const [file3, churnCount] of filteredChurn) {
55343
55423
  let fullPath = file3;
55344
- if (!fs27.existsSync(fullPath)) {
55424
+ if (!fs28.existsSync(fullPath)) {
55345
55425
  fullPath = path40.join(cwd, file3);
55346
55426
  }
55347
55427
  const complexity = getComplexityForFile(fullPath);
@@ -55550,7 +55630,7 @@ var curator_analyze = createSwarmTool({
55550
55630
  });
55551
55631
  // src/tools/declare-scope.ts
55552
55632
  init_tool();
55553
- import * as fs28 from "fs";
55633
+ import * as fs29 from "fs";
55554
55634
  import * as path41 from "path";
55555
55635
  init_create_tool();
55556
55636
  function validateTaskIdFormat(taskId) {
@@ -55643,9 +55723,9 @@ async function executeDeclareScope(args2, fallbackDir) {
55643
55723
  }
55644
55724
  const resolvedDir = path41.resolve(normalizedDir);
55645
55725
  try {
55646
- const realPath = fs28.realpathSync(resolvedDir);
55726
+ const realPath = fs29.realpathSync(resolvedDir);
55647
55727
  const planPath2 = path41.join(realPath, ".swarm", "plan.json");
55648
- if (!fs28.existsSync(planPath2)) {
55728
+ if (!fs29.existsSync(planPath2)) {
55649
55729
  return {
55650
55730
  success: false,
55651
55731
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -55669,7 +55749,7 @@ async function executeDeclareScope(args2, fallbackDir) {
55669
55749
  }
55670
55750
  const directory = normalizedDir || fallbackDir;
55671
55751
  const planPath = path41.resolve(directory, ".swarm", "plan.json");
55672
- if (!fs28.existsSync(planPath)) {
55752
+ if (!fs29.existsSync(planPath)) {
55673
55753
  return {
55674
55754
  success: false,
55675
55755
  message: "No plan found",
@@ -55678,7 +55758,7 @@ async function executeDeclareScope(args2, fallbackDir) {
55678
55758
  }
55679
55759
  let planContent;
55680
55760
  try {
55681
- planContent = JSON.parse(fs28.readFileSync(planPath, "utf-8"));
55761
+ planContent = JSON.parse(fs29.readFileSync(planPath, "utf-8"));
55682
55762
  } catch {
55683
55763
  return {
55684
55764
  success: false,
@@ -56083,7 +56163,7 @@ Use these as DOMAIN values when delegating to @sme.`;
56083
56163
  // src/tools/evidence-check.ts
56084
56164
  init_dist();
56085
56165
  init_create_tool();
56086
- import * as fs29 from "fs";
56166
+ import * as fs30 from "fs";
56087
56167
  import * as path42 from "path";
56088
56168
  var MAX_FILE_SIZE_BYTES3 = 1024 * 1024;
56089
56169
  var MAX_EVIDENCE_FILES = 1000;
@@ -56132,12 +56212,12 @@ function parseCompletedTasks(planContent) {
56132
56212
  }
56133
56213
  function readEvidenceFiles(evidenceDir, _cwd) {
56134
56214
  const evidence = [];
56135
- if (!fs29.existsSync(evidenceDir) || !fs29.statSync(evidenceDir).isDirectory()) {
56215
+ if (!fs30.existsSync(evidenceDir) || !fs30.statSync(evidenceDir).isDirectory()) {
56136
56216
  return evidence;
56137
56217
  }
56138
56218
  let files;
56139
56219
  try {
56140
- files = fs29.readdirSync(evidenceDir);
56220
+ files = fs30.readdirSync(evidenceDir);
56141
56221
  } catch {
56142
56222
  return evidence;
56143
56223
  }
@@ -56153,7 +56233,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
56153
56233
  if (!resolvedPath.startsWith(evidenceDirResolved)) {
56154
56234
  continue;
56155
56235
  }
56156
- const stat2 = fs29.lstatSync(filePath);
56236
+ const stat2 = fs30.lstatSync(filePath);
56157
56237
  if (!stat2.isFile()) {
56158
56238
  continue;
56159
56239
  }
@@ -56162,7 +56242,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
56162
56242
  }
56163
56243
  let fileStat;
56164
56244
  try {
56165
- fileStat = fs29.statSync(filePath);
56245
+ fileStat = fs30.statSync(filePath);
56166
56246
  if (fileStat.size > MAX_FILE_SIZE_BYTES3) {
56167
56247
  continue;
56168
56248
  }
@@ -56171,7 +56251,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
56171
56251
  }
56172
56252
  let content;
56173
56253
  try {
56174
- content = fs29.readFileSync(filePath, "utf-8");
56254
+ content = fs30.readFileSync(filePath, "utf-8");
56175
56255
  } catch {
56176
56256
  continue;
56177
56257
  }
@@ -56281,7 +56361,7 @@ var evidence_check = createSwarmTool({
56281
56361
  }
56282
56362
  let planContent;
56283
56363
  try {
56284
- planContent = fs29.readFileSync(planPath, "utf-8");
56364
+ planContent = fs30.readFileSync(planPath, "utf-8");
56285
56365
  } catch {
56286
56366
  const result2 = {
56287
56367
  message: "No completed tasks found in plan.",
@@ -56316,7 +56396,7 @@ var evidence_check = createSwarmTool({
56316
56396
  // src/tools/file-extractor.ts
56317
56397
  init_tool();
56318
56398
  init_create_tool();
56319
- import * as fs30 from "fs";
56399
+ import * as fs31 from "fs";
56320
56400
  import * as path43 from "path";
56321
56401
  var EXT_MAP = {
56322
56402
  python: ".py",
@@ -56379,8 +56459,8 @@ var extract_code_blocks = createSwarmTool({
56379
56459
  execute: async (args2, directory) => {
56380
56460
  const { content, output_dir, prefix } = args2;
56381
56461
  const targetDir = output_dir || directory;
56382
- if (!fs30.existsSync(targetDir)) {
56383
- fs30.mkdirSync(targetDir, { recursive: true });
56462
+ if (!fs31.existsSync(targetDir)) {
56463
+ fs31.mkdirSync(targetDir, { recursive: true });
56384
56464
  }
56385
56465
  if (!content) {
56386
56466
  return "Error: content is required";
@@ -56402,12 +56482,12 @@ var extract_code_blocks = createSwarmTool({
56402
56482
  const base = path43.basename(filepath, path43.extname(filepath));
56403
56483
  const ext = path43.extname(filepath);
56404
56484
  let counter = 1;
56405
- while (fs30.existsSync(filepath)) {
56485
+ while (fs31.existsSync(filepath)) {
56406
56486
  filepath = path43.join(targetDir, `${base}_${counter}${ext}`);
56407
56487
  counter++;
56408
56488
  }
56409
56489
  try {
56410
- fs30.writeFileSync(filepath, code.trim(), "utf-8");
56490
+ fs31.writeFileSync(filepath, code.trim(), "utf-8");
56411
56491
  savedFiles.push(filepath);
56412
56492
  } catch (error93) {
56413
56493
  errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
@@ -56523,7 +56603,7 @@ var gitingest = createSwarmTool({
56523
56603
  // src/tools/imports.ts
56524
56604
  init_dist();
56525
56605
  init_create_tool();
56526
- import * as fs31 from "fs";
56606
+ import * as fs32 from "fs";
56527
56607
  import * as path44 from "path";
56528
56608
  var MAX_FILE_PATH_LENGTH2 = 500;
56529
56609
  var MAX_SYMBOL_LENGTH = 256;
@@ -56692,7 +56772,7 @@ var SKIP_DIRECTORIES2 = new Set([
56692
56772
  function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
56693
56773
  let entries;
56694
56774
  try {
56695
- entries = fs31.readdirSync(dir);
56775
+ entries = fs32.readdirSync(dir);
56696
56776
  } catch (e) {
56697
56777
  stats.fileErrors.push({
56698
56778
  path: dir,
@@ -56709,7 +56789,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
56709
56789
  const fullPath = path44.join(dir, entry);
56710
56790
  let stat2;
56711
56791
  try {
56712
- stat2 = fs31.statSync(fullPath);
56792
+ stat2 = fs32.statSync(fullPath);
56713
56793
  } catch (e) {
56714
56794
  stats.fileErrors.push({
56715
56795
  path: fullPath,
@@ -56778,7 +56858,7 @@ var imports = createSwarmTool({
56778
56858
  }
56779
56859
  try {
56780
56860
  const targetFile = path44.resolve(file3);
56781
- if (!fs31.existsSync(targetFile)) {
56861
+ if (!fs32.existsSync(targetFile)) {
56782
56862
  const errorResult = {
56783
56863
  error: `target file not found: ${file3}`,
56784
56864
  target: file3,
@@ -56788,7 +56868,7 @@ var imports = createSwarmTool({
56788
56868
  };
56789
56869
  return JSON.stringify(errorResult, null, 2);
56790
56870
  }
56791
- const targetStat = fs31.statSync(targetFile);
56871
+ const targetStat = fs32.statSync(targetFile);
56792
56872
  if (!targetStat.isFile()) {
56793
56873
  const errorResult = {
56794
56874
  error: "target must be a file, not a directory",
@@ -56814,12 +56894,12 @@ var imports = createSwarmTool({
56814
56894
  if (consumers.length >= MAX_CONSUMERS)
56815
56895
  break;
56816
56896
  try {
56817
- const stat2 = fs31.statSync(filePath);
56897
+ const stat2 = fs32.statSync(filePath);
56818
56898
  if (stat2.size > MAX_FILE_SIZE_BYTES4) {
56819
56899
  skippedFileCount++;
56820
56900
  continue;
56821
56901
  }
56822
- const buffer = fs31.readFileSync(filePath);
56902
+ const buffer = fs32.readFileSync(filePath);
56823
56903
  if (isBinaryFile2(filePath, buffer)) {
56824
56904
  skippedFileCount++;
56825
56905
  continue;
@@ -56991,7 +57071,7 @@ var knowledgeAdd = createSwarmTool({
56991
57071
  });
56992
57072
  // src/tools/knowledge-query.ts
56993
57073
  init_dist();
56994
- import { existsSync as existsSync28 } from "fs";
57074
+ import { existsSync as existsSync29 } from "fs";
56995
57075
  init_create_tool();
56996
57076
  var DEFAULT_LIMIT = 10;
56997
57077
  var MAX_LESSON_LENGTH = 200;
@@ -57061,14 +57141,14 @@ function validateLimit(limit) {
57061
57141
  }
57062
57142
  async function readSwarmKnowledge(directory) {
57063
57143
  const swarmPath = resolveSwarmKnowledgePath(directory);
57064
- if (!existsSync28(swarmPath)) {
57144
+ if (!existsSync29(swarmPath)) {
57065
57145
  return [];
57066
57146
  }
57067
57147
  return readKnowledge(swarmPath);
57068
57148
  }
57069
57149
  async function readHiveKnowledge() {
57070
57150
  const hivePath = resolveHiveKnowledgePath();
57071
- if (!existsSync28(hivePath)) {
57151
+ if (!existsSync29(hivePath)) {
57072
57152
  return [];
57073
57153
  }
57074
57154
  return readKnowledge(hivePath);
@@ -57368,7 +57448,7 @@ init_dist();
57368
57448
  init_config();
57369
57449
  init_schema();
57370
57450
  init_manager();
57371
- import * as fs32 from "fs";
57451
+ import * as fs33 from "fs";
57372
57452
  import * as path45 from "path";
57373
57453
  init_utils2();
57374
57454
  init_create_tool();
@@ -57628,7 +57708,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
57628
57708
  if (agentsMissing.length > 0) {
57629
57709
  try {
57630
57710
  const planPath = validateSwarmPath(dir, "plan.json");
57631
- const planRaw = fs32.readFileSync(planPath, "utf-8");
57711
+ const planRaw = fs33.readFileSync(planPath, "utf-8");
57632
57712
  const plan = JSON.parse(planRaw);
57633
57713
  const targetPhase = plan.phases.find((p) => p.id === phase);
57634
57714
  if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
@@ -57659,7 +57739,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
57659
57739
  if (phaseCompleteConfig.regression_sweep?.enforce) {
57660
57740
  try {
57661
57741
  const planPath = validateSwarmPath(dir, "plan.json");
57662
- const planRaw = fs32.readFileSync(planPath, "utf-8");
57742
+ const planRaw = fs33.readFileSync(planPath, "utf-8");
57663
57743
  const plan = JSON.parse(planRaw);
57664
57744
  const targetPhase = plan.phases.find((p) => p.id === phase);
57665
57745
  if (targetPhase) {
@@ -57697,7 +57777,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
57697
57777
  };
57698
57778
  try {
57699
57779
  const eventsPath = validateSwarmPath(dir, "events.jsonl");
57700
- fs32.appendFileSync(eventsPath, `${JSON.stringify(event)}
57780
+ fs33.appendFileSync(eventsPath, `${JSON.stringify(event)}
57701
57781
  `, "utf-8");
57702
57782
  } catch (writeError) {
57703
57783
  warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -57716,12 +57796,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
57716
57796
  }
57717
57797
  try {
57718
57798
  const planPath = validateSwarmPath(dir, "plan.json");
57719
- const planJson = fs32.readFileSync(planPath, "utf-8");
57799
+ const planJson = fs33.readFileSync(planPath, "utf-8");
57720
57800
  const plan = JSON.parse(planJson);
57721
57801
  const phaseObj = plan.phases.find((p) => p.id === phase);
57722
57802
  if (phaseObj) {
57723
57803
  phaseObj.status = "completed";
57724
- fs32.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
57804
+ fs33.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
57725
57805
  `, "utf-8");
57726
57806
  }
57727
57807
  } catch (error93) {
@@ -57740,6 +57820,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
57740
57820
  agentsMissing,
57741
57821
  warnings
57742
57822
  };
57823
+ await flushPendingSnapshot(dir);
57743
57824
  return JSON.stringify({ ...result, timestamp: event.timestamp, duration_ms: durationMs }, null, 2);
57744
57825
  }
57745
57826
  var phase_complete = createSwarmTool({
@@ -57774,7 +57855,7 @@ init_dist();
57774
57855
  init_discovery();
57775
57856
  init_utils();
57776
57857
  init_create_tool();
57777
- import * as fs33 from "fs";
57858
+ import * as fs34 from "fs";
57778
57859
  import * as path46 from "path";
57779
57860
  var MAX_OUTPUT_BYTES5 = 52428800;
57780
57861
  var AUDIT_TIMEOUT_MS = 120000;
@@ -57793,28 +57874,28 @@ function validateArgs3(args2) {
57793
57874
  function detectEcosystems(directory) {
57794
57875
  const ecosystems = [];
57795
57876
  const cwd = directory;
57796
- if (fs33.existsSync(path46.join(cwd, "package.json"))) {
57877
+ if (fs34.existsSync(path46.join(cwd, "package.json"))) {
57797
57878
  ecosystems.push("npm");
57798
57879
  }
57799
- if (fs33.existsSync(path46.join(cwd, "pyproject.toml")) || fs33.existsSync(path46.join(cwd, "requirements.txt"))) {
57880
+ if (fs34.existsSync(path46.join(cwd, "pyproject.toml")) || fs34.existsSync(path46.join(cwd, "requirements.txt"))) {
57800
57881
  ecosystems.push("pip");
57801
57882
  }
57802
- if (fs33.existsSync(path46.join(cwd, "Cargo.toml"))) {
57883
+ if (fs34.existsSync(path46.join(cwd, "Cargo.toml"))) {
57803
57884
  ecosystems.push("cargo");
57804
57885
  }
57805
- if (fs33.existsSync(path46.join(cwd, "go.mod"))) {
57886
+ if (fs34.existsSync(path46.join(cwd, "go.mod"))) {
57806
57887
  ecosystems.push("go");
57807
57888
  }
57808
57889
  try {
57809
- const files = fs33.readdirSync(cwd);
57890
+ const files = fs34.readdirSync(cwd);
57810
57891
  if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
57811
57892
  ecosystems.push("dotnet");
57812
57893
  }
57813
57894
  } catch {}
57814
- if (fs33.existsSync(path46.join(cwd, "Gemfile")) || fs33.existsSync(path46.join(cwd, "Gemfile.lock"))) {
57895
+ if (fs34.existsSync(path46.join(cwd, "Gemfile")) || fs34.existsSync(path46.join(cwd, "Gemfile.lock"))) {
57815
57896
  ecosystems.push("ruby");
57816
57897
  }
57817
- if (fs33.existsSync(path46.join(cwd, "pubspec.yaml"))) {
57898
+ if (fs34.existsSync(path46.join(cwd, "pubspec.yaml"))) {
57818
57899
  ecosystems.push("dart");
57819
57900
  }
57820
57901
  return ecosystems;
@@ -58876,7 +58957,7 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
58876
58957
  ]);
58877
58958
  // src/tools/pre-check-batch.ts
58878
58959
  init_dist();
58879
- import * as fs36 from "fs";
58960
+ import * as fs37 from "fs";
58880
58961
  import * as path49 from "path";
58881
58962
 
58882
58963
  // node_modules/yocto-queue/index.js
@@ -59044,7 +59125,7 @@ init_lint();
59044
59125
  init_manager();
59045
59126
 
59046
59127
  // src/quality/metrics.ts
59047
- import * as fs34 from "fs";
59128
+ import * as fs35 from "fs";
59048
59129
  import * as path47 from "path";
59049
59130
  var MAX_FILE_SIZE_BYTES5 = 256 * 1024;
59050
59131
  var MIN_DUPLICATION_LINES = 10;
@@ -59083,11 +59164,11 @@ function estimateCyclomaticComplexity(content) {
59083
59164
  }
59084
59165
  function getComplexityForFile2(filePath) {
59085
59166
  try {
59086
- const stat2 = fs34.statSync(filePath);
59167
+ const stat2 = fs35.statSync(filePath);
59087
59168
  if (stat2.size > MAX_FILE_SIZE_BYTES5) {
59088
59169
  return null;
59089
59170
  }
59090
- const content = fs34.readFileSync(filePath, "utf-8");
59171
+ const content = fs35.readFileSync(filePath, "utf-8");
59091
59172
  return estimateCyclomaticComplexity(content);
59092
59173
  } catch {
59093
59174
  return null;
@@ -59098,7 +59179,7 @@ async function computeComplexityDelta(files, workingDir) {
59098
59179
  const analyzedFiles = [];
59099
59180
  for (const file3 of files) {
59100
59181
  const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
59101
- if (!fs34.existsSync(fullPath)) {
59182
+ if (!fs35.existsSync(fullPath)) {
59102
59183
  continue;
59103
59184
  }
59104
59185
  const complexity = getComplexityForFile2(fullPath);
@@ -59219,7 +59300,7 @@ function countGoExports(content) {
59219
59300
  }
59220
59301
  function getExportCountForFile(filePath) {
59221
59302
  try {
59222
- const content = fs34.readFileSync(filePath, "utf-8");
59303
+ const content = fs35.readFileSync(filePath, "utf-8");
59223
59304
  const ext = path47.extname(filePath).toLowerCase();
59224
59305
  switch (ext) {
59225
59306
  case ".ts":
@@ -59247,7 +59328,7 @@ async function computePublicApiDelta(files, workingDir) {
59247
59328
  const analyzedFiles = [];
59248
59329
  for (const file3 of files) {
59249
59330
  const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
59250
- if (!fs34.existsSync(fullPath)) {
59331
+ if (!fs35.existsSync(fullPath)) {
59251
59332
  continue;
59252
59333
  }
59253
59334
  const exports = getExportCountForFile(fullPath);
@@ -59281,15 +59362,15 @@ async function computeDuplicationRatio(files, workingDir) {
59281
59362
  const analyzedFiles = [];
59282
59363
  for (const file3 of files) {
59283
59364
  const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
59284
- if (!fs34.existsSync(fullPath)) {
59365
+ if (!fs35.existsSync(fullPath)) {
59285
59366
  continue;
59286
59367
  }
59287
59368
  try {
59288
- const stat2 = fs34.statSync(fullPath);
59369
+ const stat2 = fs35.statSync(fullPath);
59289
59370
  if (stat2.size > MAX_FILE_SIZE_BYTES5) {
59290
59371
  continue;
59291
59372
  }
59292
- const content = fs34.readFileSync(fullPath, "utf-8");
59373
+ const content = fs35.readFileSync(fullPath, "utf-8");
59293
59374
  const lines = content.split(`
59294
59375
  `).filter((line) => line.trim().length > 0);
59295
59376
  if (lines.length < MIN_DUPLICATION_LINES) {
@@ -59465,7 +59546,7 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
59465
59546
  let testLines = 0;
59466
59547
  let codeLines = 0;
59467
59548
  const srcDir = path47.join(workingDir, "src");
59468
- if (fs34.existsSync(srcDir)) {
59549
+ if (fs35.existsSync(srcDir)) {
59469
59550
  await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
59470
59551
  codeLines += lines;
59471
59552
  });
@@ -59473,14 +59554,14 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
59473
59554
  const possibleSrcDirs = ["lib", "app", "source", "core"];
59474
59555
  for (const dir of possibleSrcDirs) {
59475
59556
  const dirPath = path47.join(workingDir, dir);
59476
- if (fs34.existsSync(dirPath)) {
59557
+ if (fs35.existsSync(dirPath)) {
59477
59558
  await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
59478
59559
  codeLines += lines;
59479
59560
  });
59480
59561
  }
59481
59562
  }
59482
59563
  const testsDir = path47.join(workingDir, "tests");
59483
- if (fs34.existsSync(testsDir)) {
59564
+ if (fs35.existsSync(testsDir)) {
59484
59565
  await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
59485
59566
  testLines += lines;
59486
59567
  });
@@ -59488,7 +59569,7 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
59488
59569
  const possibleTestDirs = ["test", "__tests__", "specs"];
59489
59570
  for (const dir of possibleTestDirs) {
59490
59571
  const dirPath = path47.join(workingDir, dir);
59491
- if (fs34.existsSync(dirPath) && dirPath !== testsDir) {
59572
+ if (fs35.existsSync(dirPath) && dirPath !== testsDir) {
59492
59573
  await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
59493
59574
  testLines += lines;
59494
59575
  });
@@ -59500,7 +59581,7 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
59500
59581
  }
59501
59582
  async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
59502
59583
  try {
59503
- const entries = fs34.readdirSync(dirPath, { withFileTypes: true });
59584
+ const entries = fs35.readdirSync(dirPath, { withFileTypes: true });
59504
59585
  for (const entry of entries) {
59505
59586
  const fullPath = path47.join(dirPath, entry.name);
59506
59587
  if (entry.isDirectory()) {
@@ -59546,7 +59627,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
59546
59627
  continue;
59547
59628
  }
59548
59629
  try {
59549
- const content = fs34.readFileSync(fullPath, "utf-8");
59630
+ const content = fs35.readFileSync(fullPath, "utf-8");
59550
59631
  const lines = countCodeLines(content);
59551
59632
  callback(lines);
59552
59633
  } catch {}
@@ -59760,7 +59841,7 @@ async function qualityBudget(input, directory) {
59760
59841
  init_dist();
59761
59842
  init_manager();
59762
59843
  init_detector();
59763
- import * as fs35 from "fs";
59844
+ import * as fs36 from "fs";
59764
59845
  import * as path48 from "path";
59765
59846
  import { extname as extname9 } from "path";
59766
59847
 
@@ -60628,17 +60709,17 @@ var SEVERITY_ORDER = {
60628
60709
  };
60629
60710
  function shouldSkipFile(filePath) {
60630
60711
  try {
60631
- const stats = fs35.statSync(filePath);
60712
+ const stats = fs36.statSync(filePath);
60632
60713
  if (stats.size > MAX_FILE_SIZE_BYTES6) {
60633
60714
  return { skip: true, reason: "file too large" };
60634
60715
  }
60635
60716
  if (stats.size === 0) {
60636
60717
  return { skip: true, reason: "empty file" };
60637
60718
  }
60638
- const fd = fs35.openSync(filePath, "r");
60719
+ const fd = fs36.openSync(filePath, "r");
60639
60720
  const buffer = Buffer.alloc(8192);
60640
- const bytesRead = fs35.readSync(fd, buffer, 0, 8192, 0);
60641
- fs35.closeSync(fd);
60721
+ const bytesRead = fs36.readSync(fd, buffer, 0, 8192, 0);
60722
+ fs36.closeSync(fd);
60642
60723
  if (bytesRead > 0) {
60643
60724
  let nullCount = 0;
60644
60725
  for (let i2 = 0;i2 < bytesRead; i2++) {
@@ -60677,7 +60758,7 @@ function countBySeverity(findings) {
60677
60758
  }
60678
60759
  function scanFileWithTierA(filePath, language) {
60679
60760
  try {
60680
- const content = fs35.readFileSync(filePath, "utf-8");
60761
+ const content = fs36.readFileSync(filePath, "utf-8");
60681
60762
  const findings = executeRulesSync(filePath, content, language);
60682
60763
  return findings.map((f) => ({
60683
60764
  rule_id: f.rule_id,
@@ -60725,7 +60806,7 @@ async function sastScan(input, directory, config3) {
60725
60806
  continue;
60726
60807
  }
60727
60808
  const resolvedPath = path48.isAbsolute(filePath) ? filePath : path48.resolve(directory, filePath);
60728
- if (!fs35.existsSync(resolvedPath)) {
60809
+ if (!fs36.existsSync(resolvedPath)) {
60729
60810
  _filesSkipped++;
60730
60811
  continue;
60731
60812
  }
@@ -61184,7 +61265,7 @@ async function runSecretscanWithFiles(files, directory) {
61184
61265
  }
61185
61266
  let stat2;
61186
61267
  try {
61187
- stat2 = fs36.statSync(file3);
61268
+ stat2 = fs37.statSync(file3);
61188
61269
  } catch {
61189
61270
  skippedFiles++;
61190
61271
  continue;
@@ -61195,7 +61276,7 @@ async function runSecretscanWithFiles(files, directory) {
61195
61276
  }
61196
61277
  let content;
61197
61278
  try {
61198
- const buffer = fs36.readFileSync(file3);
61279
+ const buffer = fs37.readFileSync(file3);
61199
61280
  if (buffer.includes(0)) {
61200
61281
  skippedFiles++;
61201
61282
  continue;
@@ -61595,7 +61676,7 @@ ${paginatedContent}`;
61595
61676
  init_tool();
61596
61677
  init_manager2();
61597
61678
  init_create_tool();
61598
- import * as fs37 from "fs";
61679
+ import * as fs38 from "fs";
61599
61680
  import * as path50 from "path";
61600
61681
  function detectPlaceholderContent(args2) {
61601
61682
  const issues = [];
@@ -61707,7 +61788,7 @@ async function executeSavePlan(args2, fallbackDir) {
61707
61788
  phases_count: plan.phases.length,
61708
61789
  tasks_count: tasksCount
61709
61790
  });
61710
- await fs37.promises.writeFile(markerPath, marker, "utf8");
61791
+ await fs38.promises.writeFile(markerPath, marker, "utf8");
61711
61792
  } catch {}
61712
61793
  return {
61713
61794
  success: true,
@@ -61750,7 +61831,7 @@ var save_plan = createSwarmTool({
61750
61831
  // src/tools/sbom-generate.ts
61751
61832
  init_dist();
61752
61833
  init_manager();
61753
- import * as fs38 from "fs";
61834
+ import * as fs39 from "fs";
61754
61835
  import * as path51 from "path";
61755
61836
 
61756
61837
  // src/sbom/detectors/index.ts
@@ -62597,7 +62678,7 @@ function findManifestFiles(rootDir) {
62597
62678
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
62598
62679
  function searchDir(dir) {
62599
62680
  try {
62600
- const entries = fs38.readdirSync(dir, { withFileTypes: true });
62681
+ const entries = fs39.readdirSync(dir, { withFileTypes: true });
62601
62682
  for (const entry of entries) {
62602
62683
  const fullPath = path51.join(dir, entry.name);
62603
62684
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
@@ -62624,7 +62705,7 @@ function findManifestFilesInDirs(directories, workingDir) {
62624
62705
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
62625
62706
  for (const dir of directories) {
62626
62707
  try {
62627
- const entries = fs38.readdirSync(dir, { withFileTypes: true });
62708
+ const entries = fs39.readdirSync(dir, { withFileTypes: true });
62628
62709
  for (const entry of entries) {
62629
62710
  const fullPath = path51.join(dir, entry.name);
62630
62711
  if (entry.isFile()) {
@@ -62661,7 +62742,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
62661
62742
  }
62662
62743
  function ensureOutputDir(outputDir) {
62663
62744
  try {
62664
- fs38.mkdirSync(outputDir, { recursive: true });
62745
+ fs39.mkdirSync(outputDir, { recursive: true });
62665
62746
  } catch (error93) {
62666
62747
  if (!error93 || error93.code !== "EEXIST") {
62667
62748
  throw error93;
@@ -62755,10 +62836,10 @@ var sbom_generate = createSwarmTool({
62755
62836
  for (const manifestFile of manifestFiles) {
62756
62837
  try {
62757
62838
  const fullPath = path51.isAbsolute(manifestFile) ? manifestFile : path51.join(workingDir, manifestFile);
62758
- if (!fs38.existsSync(fullPath)) {
62839
+ if (!fs39.existsSync(fullPath)) {
62759
62840
  continue;
62760
62841
  }
62761
- const content = fs38.readFileSync(fullPath, "utf-8");
62842
+ const content = fs39.readFileSync(fullPath, "utf-8");
62762
62843
  const components = detectComponents(manifestFile, content);
62763
62844
  processedFiles.push(manifestFile);
62764
62845
  if (components.length > 0) {
@@ -62772,7 +62853,7 @@ var sbom_generate = createSwarmTool({
62772
62853
  const bomJson = serializeCycloneDX(bom);
62773
62854
  const filename = generateSbomFilename();
62774
62855
  const outputPath = path51.join(outputDir, filename);
62775
- fs38.writeFileSync(outputPath, bomJson, "utf-8");
62856
+ fs39.writeFileSync(outputPath, bomJson, "utf-8");
62776
62857
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
62777
62858
  try {
62778
62859
  const timestamp = new Date().toISOString();
@@ -62814,7 +62895,7 @@ var sbom_generate = createSwarmTool({
62814
62895
  // src/tools/schema-drift.ts
62815
62896
  init_dist();
62816
62897
  init_create_tool();
62817
- import * as fs39 from "fs";
62898
+ import * as fs40 from "fs";
62818
62899
  import * as path52 from "path";
62819
62900
  var SPEC_CANDIDATES = [
62820
62901
  "openapi.json",
@@ -62856,19 +62937,19 @@ function discoverSpecFile(cwd, specFileArg) {
62856
62937
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
62857
62938
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
62858
62939
  }
62859
- const stats = fs39.statSync(resolvedPath);
62940
+ const stats = fs40.statSync(resolvedPath);
62860
62941
  if (stats.size > MAX_SPEC_SIZE) {
62861
62942
  throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
62862
62943
  }
62863
- if (!fs39.existsSync(resolvedPath)) {
62944
+ if (!fs40.existsSync(resolvedPath)) {
62864
62945
  throw new Error(`Spec file not found: ${resolvedPath}`);
62865
62946
  }
62866
62947
  return resolvedPath;
62867
62948
  }
62868
62949
  for (const candidate of SPEC_CANDIDATES) {
62869
62950
  const candidatePath = path52.resolve(cwd, candidate);
62870
- if (fs39.existsSync(candidatePath)) {
62871
- const stats = fs39.statSync(candidatePath);
62951
+ if (fs40.existsSync(candidatePath)) {
62952
+ const stats = fs40.statSync(candidatePath);
62872
62953
  if (stats.size <= MAX_SPEC_SIZE) {
62873
62954
  return candidatePath;
62874
62955
  }
@@ -62877,7 +62958,7 @@ function discoverSpecFile(cwd, specFileArg) {
62877
62958
  return null;
62878
62959
  }
62879
62960
  function parseSpec(specFile) {
62880
- const content = fs39.readFileSync(specFile, "utf-8");
62961
+ const content = fs40.readFileSync(specFile, "utf-8");
62881
62962
  const ext = path52.extname(specFile).toLowerCase();
62882
62963
  if (ext === ".json") {
62883
62964
  return parseJsonSpec(content);
@@ -62949,7 +63030,7 @@ function extractRoutes(cwd) {
62949
63030
  function walkDir(dir) {
62950
63031
  let entries;
62951
63032
  try {
62952
- entries = fs39.readdirSync(dir, { withFileTypes: true });
63033
+ entries = fs40.readdirSync(dir, { withFileTypes: true });
62953
63034
  } catch {
62954
63035
  return;
62955
63036
  }
@@ -62982,7 +63063,7 @@ function extractRoutes(cwd) {
62982
63063
  }
62983
63064
  function extractRoutesFromFile(filePath) {
62984
63065
  const routes = [];
62985
- const content = fs39.readFileSync(filePath, "utf-8");
63066
+ const content = fs40.readFileSync(filePath, "utf-8");
62986
63067
  const lines = content.split(/\r?\n/);
62987
63068
  const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
62988
63069
  const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
@@ -63133,7 +63214,7 @@ init_secretscan();
63133
63214
  // src/tools/symbols.ts
63134
63215
  init_tool();
63135
63216
  init_create_tool();
63136
- import * as fs40 from "fs";
63217
+ import * as fs41 from "fs";
63137
63218
  import * as path53 from "path";
63138
63219
  var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
63139
63220
  var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
@@ -63164,8 +63245,8 @@ function containsWindowsAttacks(str) {
63164
63245
  function isPathInWorkspace(filePath, workspace) {
63165
63246
  try {
63166
63247
  const resolvedPath = path53.resolve(workspace, filePath);
63167
- const realWorkspace = fs40.realpathSync(workspace);
63168
- const realResolvedPath = fs40.realpathSync(resolvedPath);
63248
+ const realWorkspace = fs41.realpathSync(workspace);
63249
+ const realResolvedPath = fs41.realpathSync(resolvedPath);
63169
63250
  const relativePath = path53.relative(realWorkspace, realResolvedPath);
63170
63251
  if (relativePath.startsWith("..") || path53.isAbsolute(relativePath)) {
63171
63252
  return false;
@@ -63185,11 +63266,11 @@ function extractTSSymbols(filePath, cwd) {
63185
63266
  }
63186
63267
  let content;
63187
63268
  try {
63188
- const stats = fs40.statSync(fullPath);
63269
+ const stats = fs41.statSync(fullPath);
63189
63270
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
63190
63271
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
63191
63272
  }
63192
- content = fs40.readFileSync(fullPath, "utf-8");
63273
+ content = fs41.readFileSync(fullPath, "utf-8");
63193
63274
  } catch {
63194
63275
  return [];
63195
63276
  }
@@ -63337,11 +63418,11 @@ function extractPythonSymbols(filePath, cwd) {
63337
63418
  }
63338
63419
  let content;
63339
63420
  try {
63340
- const stats = fs40.statSync(fullPath);
63421
+ const stats = fs41.statSync(fullPath);
63341
63422
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
63342
63423
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
63343
63424
  }
63344
- content = fs40.readFileSync(fullPath, "utf-8");
63425
+ content = fs41.readFileSync(fullPath, "utf-8");
63345
63426
  } catch {
63346
63427
  return [];
63347
63428
  }
@@ -63485,7 +63566,7 @@ init_test_runner();
63485
63566
  init_dist();
63486
63567
  init_utils();
63487
63568
  init_create_tool();
63488
- import * as fs41 from "fs";
63569
+ import * as fs42 from "fs";
63489
63570
  import * as path54 from "path";
63490
63571
  var MAX_TEXT_LENGTH = 200;
63491
63572
  var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
@@ -63581,7 +63662,7 @@ function isSupportedExtension(filePath) {
63581
63662
  function findSourceFiles2(dir, files = []) {
63582
63663
  let entries;
63583
63664
  try {
63584
- entries = fs41.readdirSync(dir);
63665
+ entries = fs42.readdirSync(dir);
63585
63666
  } catch {
63586
63667
  return files;
63587
63668
  }
@@ -63593,7 +63674,7 @@ function findSourceFiles2(dir, files = []) {
63593
63674
  const fullPath = path54.join(dir, entry);
63594
63675
  let stat2;
63595
63676
  try {
63596
- stat2 = fs41.statSync(fullPath);
63677
+ stat2 = fs42.statSync(fullPath);
63597
63678
  } catch {
63598
63679
  continue;
63599
63680
  }
@@ -63686,7 +63767,7 @@ var todo_extract = createSwarmTool({
63686
63767
  return JSON.stringify(errorResult, null, 2);
63687
63768
  }
63688
63769
  const scanPath = resolvedPath;
63689
- if (!fs41.existsSync(scanPath)) {
63770
+ if (!fs42.existsSync(scanPath)) {
63690
63771
  const errorResult = {
63691
63772
  error: `path not found: ${pathsInput}`,
63692
63773
  total: 0,
@@ -63696,7 +63777,7 @@ var todo_extract = createSwarmTool({
63696
63777
  return JSON.stringify(errorResult, null, 2);
63697
63778
  }
63698
63779
  const filesToScan = [];
63699
- const stat2 = fs41.statSync(scanPath);
63780
+ const stat2 = fs42.statSync(scanPath);
63700
63781
  if (stat2.isFile()) {
63701
63782
  if (isSupportedExtension(scanPath)) {
63702
63783
  filesToScan.push(scanPath);
@@ -63715,11 +63796,11 @@ var todo_extract = createSwarmTool({
63715
63796
  const allEntries = [];
63716
63797
  for (const filePath of filesToScan) {
63717
63798
  try {
63718
- const fileStat = fs41.statSync(filePath);
63799
+ const fileStat = fs42.statSync(filePath);
63719
63800
  if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
63720
63801
  continue;
63721
63802
  }
63722
- const content = fs41.readFileSync(filePath, "utf-8");
63803
+ const content = fs42.readFileSync(filePath, "utf-8");
63723
63804
  const entries = parseTodoComments(content, filePath, tagsSet);
63724
63805
  allEntries.push(...entries);
63725
63806
  } catch {}
@@ -63747,18 +63828,18 @@ var todo_extract = createSwarmTool({
63747
63828
  // src/tools/update-task-status.ts
63748
63829
  init_tool();
63749
63830
  init_schema();
63750
- import * as fs43 from "fs";
63831
+ import * as fs44 from "fs";
63751
63832
  import * as path56 from "path";
63752
63833
 
63753
63834
  // src/hooks/diff-scope.ts
63754
- import * as fs42 from "fs";
63835
+ import * as fs43 from "fs";
63755
63836
  import * as path55 from "path";
63756
63837
  function getDeclaredScope(taskId, directory) {
63757
63838
  try {
63758
63839
  const planPath = path55.join(directory, ".swarm", "plan.json");
63759
- if (!fs42.existsSync(planPath))
63840
+ if (!fs43.existsSync(planPath))
63760
63841
  return null;
63761
- const raw = fs42.readFileSync(planPath, "utf-8");
63842
+ const raw = fs43.readFileSync(planPath, "utf-8");
63762
63843
  const plan = JSON.parse(raw);
63763
63844
  for (const phase of plan.phases ?? []) {
63764
63845
  for (const task of phase.tasks ?? []) {
@@ -63893,7 +63974,7 @@ function checkReviewerGate(taskId, workingDirectory) {
63893
63974
  const resolvedDir2 = workingDirectory;
63894
63975
  try {
63895
63976
  const planPath = path56.join(resolvedDir2, ".swarm", "plan.json");
63896
- const planRaw = fs43.readFileSync(planPath, "utf-8");
63977
+ const planRaw = fs44.readFileSync(planPath, "utf-8");
63897
63978
  const plan = JSON.parse(planRaw);
63898
63979
  for (const planPhase of plan.phases ?? []) {
63899
63980
  for (const task of planPhase.tasks ?? []) {
@@ -63913,7 +63994,7 @@ function checkReviewerGate(taskId, workingDirectory) {
63913
63994
  const resolvedDir = workingDirectory;
63914
63995
  try {
63915
63996
  const evidencePath = path56.join(resolvedDir, ".swarm", "evidence", `${taskId}.json`);
63916
- const raw = fs43.readFileSync(evidencePath, "utf-8");
63997
+ const raw = fs44.readFileSync(evidencePath, "utf-8");
63917
63998
  const evidence = JSON.parse(raw);
63918
63999
  if (evidence?.required_gates && Array.isArray(evidence.required_gates) && evidence?.gates) {
63919
64000
  const allGatesMet = evidence.required_gates.every((gate) => evidence.gates[gate] != null);
@@ -63954,7 +64035,7 @@ function checkReviewerGate(taskId, workingDirectory) {
63954
64035
  try {
63955
64036
  const resolvedDir2 = workingDirectory;
63956
64037
  const planPath = path56.join(resolvedDir2, ".swarm", "plan.json");
63957
- const planRaw = fs43.readFileSync(planPath, "utf-8");
64038
+ const planRaw = fs44.readFileSync(planPath, "utf-8");
63958
64039
  const plan = JSON.parse(planRaw);
63959
64040
  for (const planPhase of plan.phases ?? []) {
63960
64041
  for (const task of planPhase.tasks ?? []) {
@@ -64148,9 +64229,9 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
64148
64229
  }
64149
64230
  const resolvedDir = path56.resolve(normalizedDir);
64150
64231
  try {
64151
- const realPath = fs43.realpathSync(resolvedDir);
64232
+ const realPath = fs44.realpathSync(resolvedDir);
64152
64233
  const planPath = path56.join(realPath, ".swarm", "plan.json");
64153
- if (!fs43.existsSync(planPath)) {
64234
+ if (!fs44.existsSync(planPath)) {
64154
64235
  return {
64155
64236
  success: false,
64156
64237
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -64664,6 +64745,7 @@ var OpenCodeSwarm = async (ctx) => {
64664
64745
  await safeHook(activityHooks.toolBefore)(input, output);
64665
64746
  },
64666
64747
  "tool.execute.after": async (input, output) => {
64748
+ console.debug("[hook-chain] toolAfter start sessionID=%s agent=%s tool=%s", input.sessionID, input.agent, input.tool?.name);
64667
64749
  await activityHooks.toolAfter(input, output);
64668
64750
  await guardrailsHooks.toolAfter(input, output);
64669
64751
  await safeHook(delegationLedgerHook.toolAfter)(input, output);
@@ -64678,12 +64760,15 @@ var OpenCodeSwarm = async (ctx) => {
64678
64760
  await safeHook(darkMatterDetectorHook)(input, output);
64679
64761
  await snapshotWriterHook(input, output);
64680
64762
  await toolSummarizerHook?.(input, output);
64681
- if (slopDetectorHook)
64682
- await slopDetectorHook.toolAfter(input, output);
64683
- if (incrementalVerifyHook)
64684
- await incrementalVerifyHook.toolAfter(input, output);
64685
- if (compactionServiceHook)
64686
- await compactionServiceHook.toolAfter(input, output);
64763
+ const execMode = config3.execution_mode ?? "balanced";
64764
+ if (execMode === "strict") {
64765
+ if (slopDetectorHook)
64766
+ await slopDetectorHook.toolAfter(input, output);
64767
+ if (incrementalVerifyHook)
64768
+ await incrementalVerifyHook.toolAfter(input, output);
64769
+ if (compactionServiceHook)
64770
+ await compactionServiceHook.toolAfter(input, output);
64771
+ }
64687
64772
  const toolOutputConfig = config3.tool_output;
64688
64773
  if (toolOutputConfig && toolOutputConfig.truncation_enabled !== false && typeof output.output === "string") {
64689
64774
  const defaultTruncatableTools = new Set([
@@ -64717,8 +64802,12 @@ var OpenCodeSwarm = async (ctx) => {
64717
64802
  session.lastAgentEventTime = Date.now();
64718
64803
  }
64719
64804
  }
64805
+ deleteStoredInputArgs(input.callID);
64720
64806
  },
64721
- "chat.message": safeHook(delegationHandler),
64807
+ "chat.message": safeHook(async (input, output) => {
64808
+ console.debug("[session] chat.message sessionID=%s agent=%s", input.sessionID, input.agent);
64809
+ await delegationHandler(input, output);
64810
+ }),
64722
64811
  automation: automationManager
64723
64812
  };
64724
64813
  };