opencode-swarm 6.32.4 → 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) {
@@ -48749,6 +48799,47 @@ async function executeWriteRetro(args2, directory) {
48749
48799
  message: "Invalid summary: must be a non-empty string"
48750
48800
  }, null, 2);
48751
48801
  }
48802
+ if (args2.task_id !== undefined) {
48803
+ const tid = args2.task_id;
48804
+ if (!tid || tid.length === 0 || tid.length > 200) {
48805
+ return JSON.stringify({
48806
+ success: false,
48807
+ phase,
48808
+ message: "Invalid task ID: must match pattern"
48809
+ }, null, 2);
48810
+ }
48811
+ if (/\0/.test(tid)) {
48812
+ return JSON.stringify({
48813
+ success: false,
48814
+ phase,
48815
+ message: "Invalid task ID: contains null bytes"
48816
+ }, null, 2);
48817
+ }
48818
+ for (let i2 = 0;i2 < tid.length; i2++) {
48819
+ if (tid.charCodeAt(i2) < 32) {
48820
+ return JSON.stringify({
48821
+ success: false,
48822
+ phase,
48823
+ message: "Invalid task ID: contains control characters"
48824
+ }, null, 2);
48825
+ }
48826
+ }
48827
+ if (tid.includes("..") || tid.includes("/") || tid.includes("\\")) {
48828
+ return JSON.stringify({
48829
+ success: false,
48830
+ phase,
48831
+ message: "Invalid task ID: path traversal detected"
48832
+ }, null, 2);
48833
+ }
48834
+ const VALID_TASK_ID = /^(retro-\d+|\d+\.\d+(\.\d+)*)$/;
48835
+ if (!VALID_TASK_ID.test(tid)) {
48836
+ return JSON.stringify({
48837
+ success: false,
48838
+ phase,
48839
+ message: "Invalid task ID: must match pattern"
48840
+ }, null, 2);
48841
+ }
48842
+ }
48752
48843
  const taskId = args2.task_id ?? `retro-${phase}`;
48753
48844
  const retroEntry = {
48754
48845
  task_id: taskId,
@@ -48988,6 +49079,10 @@ var COMMAND_REGISTRY = {
48988
49079
  handler: (ctx) => handleResetCommand(ctx.directory, ctx.args),
48989
49080
  description: "Clear swarm state files [--confirm]"
48990
49081
  },
49082
+ "reset-session": {
49083
+ handler: (ctx) => handleResetSessionCommand(ctx.directory, ctx.args),
49084
+ description: "Clear session state while preserving plan, evidence, and knowledge"
49085
+ },
48991
49086
  rollback: {
48992
49087
  handler: (ctx) => handleRollbackCommand(ctx.directory, ctx.args),
48993
49088
  description: "Restore swarm state to a checkpoint <phase>"
@@ -49092,7 +49187,7 @@ init_constants();
49092
49187
  init_schema();
49093
49188
 
49094
49189
  // src/hooks/agent-activity.ts
49095
- import { renameSync as renameSync7, unlinkSync as unlinkSync3 } from "fs";
49190
+ import { renameSync as renameSync7, unlinkSync as unlinkSync4 } from "fs";
49096
49191
  init_utils();
49097
49192
  init_utils2();
49098
49193
  function createAgentActivityHooks(config3, directory) {
@@ -49169,7 +49264,7 @@ async function doFlush(directory) {
49169
49264
  renameSync7(tempPath, path29);
49170
49265
  } catch (writeError) {
49171
49266
  try {
49172
- unlinkSync3(tempPath);
49267
+ unlinkSync4(tempPath);
49173
49268
  } catch {}
49174
49269
  throw writeError;
49175
49270
  }
@@ -49215,7 +49310,7 @@ ${content.substring(endIndex + 1)}`;
49215
49310
  }
49216
49311
  // src/hooks/compaction-customizer.ts
49217
49312
  init_manager2();
49218
- import * as fs17 from "fs";
49313
+ import * as fs18 from "fs";
49219
49314
  import { join as join25 } from "path";
49220
49315
  init_utils2();
49221
49316
  function createCompactionCustomizerHook(config3, directory) {
@@ -49263,7 +49358,7 @@ function createCompactionCustomizerHook(config3, directory) {
49263
49358
  }
49264
49359
  try {
49265
49360
  const summariesDir = join25(directory, ".swarm", "summaries");
49266
- const files = await fs17.promises.readdir(summariesDir);
49361
+ const files = await fs18.promises.readdir(summariesDir);
49267
49362
  if (files.length > 0) {
49268
49363
  const count = files.length;
49269
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.`);
@@ -49748,7 +49843,7 @@ function maskToolOutput(msg, _threshold) {
49748
49843
  }
49749
49844
  // src/hooks/delegation-gate.ts
49750
49845
  init_schema();
49751
- import * as fs18 from "fs";
49846
+ import * as fs19 from "fs";
49752
49847
  import * as path31 from "path";
49753
49848
 
49754
49849
  // src/hooks/guardrails.ts
@@ -49809,6 +49904,8 @@ function setStoredInputArgs(callID, args2) {
49809
49904
  function deleteStoredInputArgs(callID) {
49810
49905
  storedInputArgs.delete(callID);
49811
49906
  }
49907
+ var toolCallsSinceLastWrite = new Map;
49908
+ var noOpWarningIssued = new Set;
49812
49909
  function extractPhaseNumber(phaseString) {
49813
49910
  if (!phaseString)
49814
49911
  return 1;
@@ -50326,6 +50423,19 @@ function createGuardrailsHooks(directory, directoryOrConfig, config3) {
50326
50423
  session.modifiedFilesThisCoderTask = [];
50327
50424
  }
50328
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
+ }
50329
50439
  const window2 = getActiveWindow(input.sessionID);
50330
50440
  if (!window2)
50331
50441
  return;
@@ -50611,6 +50721,7 @@ function hashArgs(args2) {
50611
50721
 
50612
50722
  // src/hooks/delegation-gate.ts
50613
50723
  init_utils2();
50724
+ var pendingCoderScopeByTaskId = new Map;
50614
50725
  function extractTaskLine(text) {
50615
50726
  const match = text.match(/TASK:\s*(.+?)(?:\n|$)/i);
50616
50727
  return match ? match[1].trim() : null;
@@ -50646,7 +50757,7 @@ function getEvidenceTaskId(session, directory) {
50646
50757
  if (!resolvedPlanPath.startsWith(resolvedDirectory + path31.sep) && resolvedPlanPath !== resolvedDirectory) {
50647
50758
  return null;
50648
50759
  }
50649
- const planContent = fs18.readFileSync(resolvedPlanPath, "utf-8");
50760
+ const planContent = fs19.readFileSync(resolvedPlanPath, "utf-8");
50650
50761
  const plan = JSON.parse(planContent);
50651
50762
  if (!plan || !Array.isArray(plan.phases)) {
50652
50763
  return null;
@@ -50996,6 +51107,11 @@ ${trimComment}${after}`;
50996
51107
  }
50997
51108
  }
50998
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
+ }
50999
51115
  try {
51000
51116
  advanceTaskState(session, currentTaskId, "coder_delegated");
51001
51117
  } catch (err2) {
@@ -51123,7 +51239,7 @@ ${warningLines.join(`
51123
51239
  }
51124
51240
  // src/hooks/delegation-sanitizer.ts
51125
51241
  init_utils2();
51126
- import * as fs19 from "fs";
51242
+ import * as fs20 from "fs";
51127
51243
  var SANITIZATION_PATTERNS = [
51128
51244
  /\b\d+(st|nd|rd|th)\s+(attempt|try|time)\b/gi,
51129
51245
  /\b(5th|fifth|final|last)\s+attempt\b/gi,
@@ -51194,7 +51310,7 @@ function createDelegationSanitizerHook(directory) {
51194
51310
  stripped_patterns: result.stripped,
51195
51311
  timestamp: new Date().toISOString()
51196
51312
  };
51197
- fs19.appendFileSync(eventsPath, `${JSON.stringify(event)}
51313
+ fs20.appendFileSync(eventsPath, `${JSON.stringify(event)}
51198
51314
  `, "utf-8");
51199
51315
  } catch {}
51200
51316
  }
@@ -51451,12 +51567,12 @@ init_schema();
51451
51567
  init_manager();
51452
51568
  init_detector();
51453
51569
  init_manager2();
51454
- import * as fs21 from "fs";
51570
+ import * as fs22 from "fs";
51455
51571
 
51456
51572
  // src/services/decision-drift-analyzer.ts
51457
51573
  init_utils2();
51458
51574
  init_manager2();
51459
- import * as fs20 from "fs";
51575
+ import * as fs21 from "fs";
51460
51576
  import * as path33 from "path";
51461
51577
  var DEFAULT_DRIFT_CONFIG = {
51462
51578
  staleThresholdPhases: 1,
@@ -51614,8 +51730,8 @@ async function analyzeDecisionDrift(directory, config3 = {}) {
51614
51730
  const contextPath = path33.join(directory, ".swarm", "context.md");
51615
51731
  let contextContent = "";
51616
51732
  try {
51617
- if (fs20.existsSync(contextPath)) {
51618
- contextContent = fs20.readFileSync(contextPath, "utf-8");
51733
+ if (fs21.existsSync(contextPath)) {
51734
+ contextContent = fs21.readFileSync(contextPath, "utf-8");
51619
51735
  }
51620
51736
  } catch {
51621
51737
  return {
@@ -52109,11 +52225,11 @@ function createSystemEnhancerHook(config3, directory) {
52109
52225
  if (handoffContent) {
52110
52226
  const handoffPath = validateSwarmPath(directory, "handoff.md");
52111
52227
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
52112
- if (fs21.existsSync(consumedPath)) {
52228
+ if (fs22.existsSync(consumedPath)) {
52113
52229
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
52114
- fs21.unlinkSync(consumedPath);
52230
+ fs22.unlinkSync(consumedPath);
52115
52231
  }
52116
- fs21.renameSync(handoffPath, consumedPath);
52232
+ fs22.renameSync(handoffPath, consumedPath);
52117
52233
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
52118
52234
  The previous model's session ended. Here is your starting context:
52119
52235
 
@@ -52393,11 +52509,11 @@ ${budgetWarning}`);
52393
52509
  if (handoffContent) {
52394
52510
  const handoffPath = validateSwarmPath(directory, "handoff.md");
52395
52511
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
52396
- if (fs21.existsSync(consumedPath)) {
52512
+ if (fs22.existsSync(consumedPath)) {
52397
52513
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
52398
- fs21.unlinkSync(consumedPath);
52514
+ fs22.unlinkSync(consumedPath);
52399
52515
  }
52400
- fs21.renameSync(handoffPath, consumedPath);
52516
+ fs22.renameSync(handoffPath, consumedPath);
52401
52517
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
52402
52518
  The previous model's session ended. Here is your starting context:
52403
52519
 
@@ -53166,7 +53282,7 @@ function isReadTool(toolName) {
53166
53282
  }
53167
53283
 
53168
53284
  // src/hooks/incremental-verify.ts
53169
- import * as fs22 from "fs";
53285
+ import * as fs23 from "fs";
53170
53286
  import * as path34 from "path";
53171
53287
 
53172
53288
  // src/hooks/spawn-helper.ts
@@ -53242,21 +53358,21 @@ function spawnAsync(command, cwd, timeoutMs) {
53242
53358
  // src/hooks/incremental-verify.ts
53243
53359
  var emittedSkipAdvisories = new Set;
53244
53360
  function detectPackageManager(projectDir) {
53245
- if (fs22.existsSync(path34.join(projectDir, "bun.lockb")))
53361
+ if (fs23.existsSync(path34.join(projectDir, "bun.lockb")))
53246
53362
  return "bun";
53247
- if (fs22.existsSync(path34.join(projectDir, "pnpm-lock.yaml")))
53363
+ if (fs23.existsSync(path34.join(projectDir, "pnpm-lock.yaml")))
53248
53364
  return "pnpm";
53249
- if (fs22.existsSync(path34.join(projectDir, "yarn.lock")))
53365
+ if (fs23.existsSync(path34.join(projectDir, "yarn.lock")))
53250
53366
  return "yarn";
53251
- if (fs22.existsSync(path34.join(projectDir, "package-lock.json")))
53367
+ if (fs23.existsSync(path34.join(projectDir, "package-lock.json")))
53252
53368
  return "npm";
53253
53369
  return "bun";
53254
53370
  }
53255
53371
  function detectTypecheckCommand(projectDir) {
53256
53372
  const pkgPath = path34.join(projectDir, "package.json");
53257
- if (fs22.existsSync(pkgPath)) {
53373
+ if (fs23.existsSync(pkgPath)) {
53258
53374
  try {
53259
- const pkg = JSON.parse(fs22.readFileSync(pkgPath, "utf8"));
53375
+ const pkg = JSON.parse(fs23.readFileSync(pkgPath, "utf8"));
53260
53376
  const scripts = pkg.scripts;
53261
53377
  if (scripts?.typecheck) {
53262
53378
  const pm = detectPackageManager(projectDir);
@@ -53270,8 +53386,8 @@ function detectTypecheckCommand(projectDir) {
53270
53386
  ...pkg.dependencies,
53271
53387
  ...pkg.devDependencies
53272
53388
  };
53273
- if (!deps?.typescript && !fs22.existsSync(path34.join(projectDir, "tsconfig.json"))) {}
53274
- 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"));
53275
53391
  if (hasTSMarkers) {
53276
53392
  return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
53277
53393
  }
@@ -53279,17 +53395,17 @@ function detectTypecheckCommand(projectDir) {
53279
53395
  return null;
53280
53396
  }
53281
53397
  }
53282
- if (fs22.existsSync(path34.join(projectDir, "go.mod"))) {
53398
+ if (fs23.existsSync(path34.join(projectDir, "go.mod"))) {
53283
53399
  return { command: ["go", "vet", "./..."], language: "go" };
53284
53400
  }
53285
- if (fs22.existsSync(path34.join(projectDir, "Cargo.toml"))) {
53401
+ if (fs23.existsSync(path34.join(projectDir, "Cargo.toml"))) {
53286
53402
  return { command: ["cargo", "check"], language: "rust" };
53287
53403
  }
53288
- 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"))) {
53289
53405
  return { command: null, language: "python" };
53290
53406
  }
53291
53407
  try {
53292
- const entries = fs22.readdirSync(projectDir);
53408
+ const entries = fs23.readdirSync(projectDir);
53293
53409
  if (entries.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
53294
53410
  return {
53295
53411
  command: ["dotnet", "build", "--no-restore"],
@@ -53358,7 +53474,7 @@ ${errorSummary}`);
53358
53474
  }
53359
53475
 
53360
53476
  // src/hooks/knowledge-reader.ts
53361
- import { existsSync as existsSync20 } from "fs";
53477
+ import { existsSync as existsSync21 } from "fs";
53362
53478
  import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
53363
53479
  import * as path35 from "path";
53364
53480
  var JACCARD_THRESHOLD = 0.6;
@@ -53411,7 +53527,7 @@ async function recordLessonsShown(directory, lessonIds, currentPhase) {
53411
53527
  const shownFile = path35.join(directory, ".swarm", ".knowledge-shown.json");
53412
53528
  try {
53413
53529
  let shownData = {};
53414
- if (existsSync20(shownFile)) {
53530
+ if (existsSync21(shownFile)) {
53415
53531
  const content = await readFile5(shownFile, "utf-8");
53416
53532
  shownData = JSON.parse(content);
53417
53533
  }
@@ -53513,7 +53629,7 @@ async function readMergedKnowledge(directory, config3, context) {
53513
53629
  async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
53514
53630
  const shownFile = path35.join(directory, ".swarm", ".knowledge-shown.json");
53515
53631
  try {
53516
- if (!existsSync20(shownFile)) {
53632
+ if (!existsSync21(shownFile)) {
53517
53633
  return;
53518
53634
  }
53519
53635
  const content = await readFile5(shownFile, "utf-8");
@@ -53983,12 +54099,12 @@ Use this data to avoid repeating known failure patterns.`;
53983
54099
  // src/hooks/curator-drift.ts
53984
54100
  init_event_bus();
53985
54101
  init_utils2();
53986
- import * as fs23 from "fs";
54102
+ import * as fs24 from "fs";
53987
54103
  import * as path36 from "path";
53988
54104
  var DRIFT_REPORT_PREFIX = "drift-report-phase-";
53989
54105
  async function readPriorDriftReports(directory) {
53990
54106
  const swarmDir = path36.join(directory, ".swarm");
53991
- const entries = await fs23.promises.readdir(swarmDir).catch(() => null);
54107
+ const entries = await fs24.promises.readdir(swarmDir).catch(() => null);
53992
54108
  if (entries === null)
53993
54109
  return [];
53994
54110
  const reportFiles = entries.filter((name2) => name2.startsWith(DRIFT_REPORT_PREFIX) && name2.endsWith(".json")).sort();
@@ -54015,9 +54131,9 @@ async function writeDriftReport(directory, report) {
54015
54131
  const filename = `${DRIFT_REPORT_PREFIX}${report.phase}.json`;
54016
54132
  const filePath = validateSwarmPath(directory, filename);
54017
54133
  const swarmDir = path36.dirname(filePath);
54018
- await fs23.promises.mkdir(swarmDir, { recursive: true });
54134
+ await fs24.promises.mkdir(swarmDir, { recursive: true });
54019
54135
  try {
54020
- 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");
54021
54137
  } catch (err2) {
54022
54138
  throw new Error(`[curator-drift] Failed to write drift report to ${filePath}: ${String(err2)}`);
54023
54139
  }
@@ -54303,7 +54419,7 @@ var WRITE_TOOLS = new Set([
54303
54419
  "append",
54304
54420
  "prepend"
54305
54421
  ]);
54306
- function createScopeGuardHook(config3, _directory, injectAdvisory) {
54422
+ function createScopeGuardHook(config3, directory, injectAdvisory) {
54307
54423
  const enabled = config3.enabled ?? true;
54308
54424
  const _skipInTurbo = config3.skip_in_turbo ?? false;
54309
54425
  return {
@@ -54320,7 +54436,7 @@ function createScopeGuardHook(config3, _directory, injectAdvisory) {
54320
54436
  const isArchitect2 = stripKnownSwarmPrefix(agentName) === ORCHESTRATOR_NAME;
54321
54437
  if (isArchitect2)
54322
54438
  return;
54323
- const declaredScope = session?.declaredCoderScope;
54439
+ const declaredScope = session?.declaredCoderScope ?? (session?.currentTaskId ? pendingCoderScopeByTaskId.get(session.currentTaskId) : null);
54324
54440
  if (!declaredScope || declaredScope.length === 0)
54325
54441
  return;
54326
54442
  const argsObj = output.args;
@@ -54328,7 +54444,7 @@ function createScopeGuardHook(config3, _directory, injectAdvisory) {
54328
54444
  if (typeof rawFilePath !== "string" || !rawFilePath)
54329
54445
  return;
54330
54446
  const filePath = rawFilePath.replace(/[\r\n\t]/g, "_").split(String.fromCharCode(27)).join("_").replace(/\[[\d;]*m/g, "");
54331
- if (!isFileInScope(filePath, declaredScope)) {
54447
+ if (!isFileInScope(filePath, declaredScope, directory)) {
54332
54448
  const taskId = session?.currentTaskId ?? "unknown";
54333
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 ? "..." : ""}]`;
54334
54450
  if (session) {
@@ -54351,10 +54467,11 @@ function createScopeGuardHook(config3, _directory, injectAdvisory) {
54351
54467
  }
54352
54468
  };
54353
54469
  }
54354
- function isFileInScope(filePath, scopeEntries) {
54355
- const resolvedFile = path37.resolve(filePath);
54470
+ function isFileInScope(filePath, scopeEntries, directory) {
54471
+ const dir = directory ?? process.cwd();
54472
+ const resolvedFile = path37.resolve(dir, filePath);
54356
54473
  return scopeEntries.some((scope) => {
54357
- const resolvedScope = path37.resolve(scope);
54474
+ const resolvedScope = path37.resolve(dir, scope);
54358
54475
  if (resolvedFile === resolvedScope)
54359
54476
  return true;
54360
54477
  const rel = path37.relative(resolvedScope, resolvedFile);
@@ -54407,7 +54524,7 @@ function createSelfReviewHook(config3, injectAdvisory) {
54407
54524
  }
54408
54525
 
54409
54526
  // src/hooks/slop-detector.ts
54410
- import * as fs24 from "fs";
54527
+ import * as fs25 from "fs";
54411
54528
  import * as path38 from "path";
54412
54529
  var WRITE_EDIT_TOOLS = new Set([
54413
54530
  "write",
@@ -54453,7 +54570,7 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
54453
54570
  function walkFiles(dir, exts, deadline) {
54454
54571
  const results = [];
54455
54572
  try {
54456
- for (const entry of fs24.readdirSync(dir, { withFileTypes: true })) {
54573
+ for (const entry of fs25.readdirSync(dir, { withFileTypes: true })) {
54457
54574
  if (deadline !== undefined && Date.now() > deadline)
54458
54575
  break;
54459
54576
  if (entry.isSymbolicLink())
@@ -54473,7 +54590,7 @@ function walkFiles(dir, exts, deadline) {
54473
54590
  return results;
54474
54591
  }
54475
54592
  function checkDeadExports(content, projectDir, startTime) {
54476
- const hasPackageJson = fs24.existsSync(path38.join(projectDir, "package.json"));
54593
+ const hasPackageJson = fs25.existsSync(path38.join(projectDir, "package.json"));
54477
54594
  if (!hasPackageJson)
54478
54595
  return null;
54479
54596
  const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
@@ -54496,7 +54613,7 @@ function checkDeadExports(content, projectDir, startTime) {
54496
54613
  if (found || Date.now() - startTime > 480)
54497
54614
  break;
54498
54615
  try {
54499
- const text = fs24.readFileSync(file3, "utf-8");
54616
+ const text = fs25.readFileSync(file3, "utf-8");
54500
54617
  if (importPattern.test(text))
54501
54618
  found = true;
54502
54619
  importPattern.lastIndex = 0;
@@ -54629,7 +54746,7 @@ Review before proceeding.`;
54629
54746
 
54630
54747
  // src/hooks/steering-consumed.ts
54631
54748
  init_utils2();
54632
- import * as fs25 from "fs";
54749
+ import * as fs26 from "fs";
54633
54750
  function recordSteeringConsumed(directory, directiveId) {
54634
54751
  try {
54635
54752
  const eventsPath = validateSwarmPath(directory, "events.jsonl");
@@ -54638,7 +54755,7 @@ function recordSteeringConsumed(directory, directiveId) {
54638
54755
  directiveId,
54639
54756
  timestamp: new Date().toISOString()
54640
54757
  };
54641
- fs25.appendFileSync(eventsPath, `${JSON.stringify(event)}
54758
+ fs26.appendFileSync(eventsPath, `${JSON.stringify(event)}
54642
54759
  `, "utf-8");
54643
54760
  } catch {}
54644
54761
  }
@@ -54804,6 +54921,10 @@ async function rehydrateState(snapshot) {
54804
54921
  }
54805
54922
  if (snapshot.agentSessions) {
54806
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
+ }
54807
54928
  swarmState.agentSessions.set(sessionId, deserializeAgentSession(serializedSession));
54808
54929
  }
54809
54930
  }
@@ -54995,7 +55116,7 @@ var build_check = createSwarmTool({
54995
55116
  // src/tools/check-gate-status.ts
54996
55117
  init_dist();
54997
55118
  init_create_tool();
54998
- import * as fs26 from "fs";
55119
+ import * as fs27 from "fs";
54999
55120
  import * as path39 from "path";
55000
55121
  var EVIDENCE_DIR = ".swarm/evidence";
55001
55122
  var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
@@ -55019,12 +55140,12 @@ function isPathWithinSwarm(filePath, workspaceRoot) {
55019
55140
  return normalizedPath.startsWith(swarmPath);
55020
55141
  }
55021
55142
  function readEvidenceFile(evidencePath) {
55022
- if (!fs26.existsSync(evidencePath)) {
55143
+ if (!fs27.existsSync(evidencePath)) {
55023
55144
  return null;
55024
55145
  }
55025
55146
  let content;
55026
55147
  try {
55027
- content = fs26.readFileSync(evidencePath, "utf-8");
55148
+ content = fs27.readFileSync(evidencePath, "utf-8");
55028
55149
  } catch {
55029
55150
  return null;
55030
55151
  }
@@ -55145,7 +55266,7 @@ init_checkpoint();
55145
55266
  // src/tools/complexity-hotspots.ts
55146
55267
  init_dist();
55147
55268
  init_create_tool();
55148
- import * as fs27 from "fs";
55269
+ import * as fs28 from "fs";
55149
55270
  import * as path40 from "path";
55150
55271
  var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
55151
55272
  var DEFAULT_DAYS = 90;
@@ -55275,11 +55396,11 @@ function estimateComplexity(content) {
55275
55396
  }
55276
55397
  function getComplexityForFile(filePath) {
55277
55398
  try {
55278
- const stat2 = fs27.statSync(filePath);
55399
+ const stat2 = fs28.statSync(filePath);
55279
55400
  if (stat2.size > MAX_FILE_SIZE_BYTES2) {
55280
55401
  return null;
55281
55402
  }
55282
- const content = fs27.readFileSync(filePath, "utf-8");
55403
+ const content = fs28.readFileSync(filePath, "utf-8");
55283
55404
  return estimateComplexity(content);
55284
55405
  } catch {
55285
55406
  return null;
@@ -55300,7 +55421,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
55300
55421
  let analyzedFiles = 0;
55301
55422
  for (const [file3, churnCount] of filteredChurn) {
55302
55423
  let fullPath = file3;
55303
- if (!fs27.existsSync(fullPath)) {
55424
+ if (!fs28.existsSync(fullPath)) {
55304
55425
  fullPath = path40.join(cwd, file3);
55305
55426
  }
55306
55427
  const complexity = getComplexityForFile(fullPath);
@@ -55509,7 +55630,7 @@ var curator_analyze = createSwarmTool({
55509
55630
  });
55510
55631
  // src/tools/declare-scope.ts
55511
55632
  init_tool();
55512
- import * as fs28 from "fs";
55633
+ import * as fs29 from "fs";
55513
55634
  import * as path41 from "path";
55514
55635
  init_create_tool();
55515
55636
  function validateTaskIdFormat(taskId) {
@@ -55602,9 +55723,9 @@ async function executeDeclareScope(args2, fallbackDir) {
55602
55723
  }
55603
55724
  const resolvedDir = path41.resolve(normalizedDir);
55604
55725
  try {
55605
- const realPath = fs28.realpathSync(resolvedDir);
55726
+ const realPath = fs29.realpathSync(resolvedDir);
55606
55727
  const planPath2 = path41.join(realPath, ".swarm", "plan.json");
55607
- if (!fs28.existsSync(planPath2)) {
55728
+ if (!fs29.existsSync(planPath2)) {
55608
55729
  return {
55609
55730
  success: false,
55610
55731
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -55628,7 +55749,7 @@ async function executeDeclareScope(args2, fallbackDir) {
55628
55749
  }
55629
55750
  const directory = normalizedDir || fallbackDir;
55630
55751
  const planPath = path41.resolve(directory, ".swarm", "plan.json");
55631
- if (!fs28.existsSync(planPath)) {
55752
+ if (!fs29.existsSync(planPath)) {
55632
55753
  return {
55633
55754
  success: false,
55634
55755
  message: "No plan found",
@@ -55637,7 +55758,7 @@ async function executeDeclareScope(args2, fallbackDir) {
55637
55758
  }
55638
55759
  let planContent;
55639
55760
  try {
55640
- planContent = JSON.parse(fs28.readFileSync(planPath, "utf-8"));
55761
+ planContent = JSON.parse(fs29.readFileSync(planPath, "utf-8"));
55641
55762
  } catch {
55642
55763
  return {
55643
55764
  success: false,
@@ -56042,7 +56163,7 @@ Use these as DOMAIN values when delegating to @sme.`;
56042
56163
  // src/tools/evidence-check.ts
56043
56164
  init_dist();
56044
56165
  init_create_tool();
56045
- import * as fs29 from "fs";
56166
+ import * as fs30 from "fs";
56046
56167
  import * as path42 from "path";
56047
56168
  var MAX_FILE_SIZE_BYTES3 = 1024 * 1024;
56048
56169
  var MAX_EVIDENCE_FILES = 1000;
@@ -56091,12 +56212,12 @@ function parseCompletedTasks(planContent) {
56091
56212
  }
56092
56213
  function readEvidenceFiles(evidenceDir, _cwd) {
56093
56214
  const evidence = [];
56094
- if (!fs29.existsSync(evidenceDir) || !fs29.statSync(evidenceDir).isDirectory()) {
56215
+ if (!fs30.existsSync(evidenceDir) || !fs30.statSync(evidenceDir).isDirectory()) {
56095
56216
  return evidence;
56096
56217
  }
56097
56218
  let files;
56098
56219
  try {
56099
- files = fs29.readdirSync(evidenceDir);
56220
+ files = fs30.readdirSync(evidenceDir);
56100
56221
  } catch {
56101
56222
  return evidence;
56102
56223
  }
@@ -56112,7 +56233,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
56112
56233
  if (!resolvedPath.startsWith(evidenceDirResolved)) {
56113
56234
  continue;
56114
56235
  }
56115
- const stat2 = fs29.lstatSync(filePath);
56236
+ const stat2 = fs30.lstatSync(filePath);
56116
56237
  if (!stat2.isFile()) {
56117
56238
  continue;
56118
56239
  }
@@ -56121,7 +56242,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
56121
56242
  }
56122
56243
  let fileStat;
56123
56244
  try {
56124
- fileStat = fs29.statSync(filePath);
56245
+ fileStat = fs30.statSync(filePath);
56125
56246
  if (fileStat.size > MAX_FILE_SIZE_BYTES3) {
56126
56247
  continue;
56127
56248
  }
@@ -56130,7 +56251,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
56130
56251
  }
56131
56252
  let content;
56132
56253
  try {
56133
- content = fs29.readFileSync(filePath, "utf-8");
56254
+ content = fs30.readFileSync(filePath, "utf-8");
56134
56255
  } catch {
56135
56256
  continue;
56136
56257
  }
@@ -56240,7 +56361,7 @@ var evidence_check = createSwarmTool({
56240
56361
  }
56241
56362
  let planContent;
56242
56363
  try {
56243
- planContent = fs29.readFileSync(planPath, "utf-8");
56364
+ planContent = fs30.readFileSync(planPath, "utf-8");
56244
56365
  } catch {
56245
56366
  const result2 = {
56246
56367
  message: "No completed tasks found in plan.",
@@ -56275,7 +56396,7 @@ var evidence_check = createSwarmTool({
56275
56396
  // src/tools/file-extractor.ts
56276
56397
  init_tool();
56277
56398
  init_create_tool();
56278
- import * as fs30 from "fs";
56399
+ import * as fs31 from "fs";
56279
56400
  import * as path43 from "path";
56280
56401
  var EXT_MAP = {
56281
56402
  python: ".py",
@@ -56338,8 +56459,8 @@ var extract_code_blocks = createSwarmTool({
56338
56459
  execute: async (args2, directory) => {
56339
56460
  const { content, output_dir, prefix } = args2;
56340
56461
  const targetDir = output_dir || directory;
56341
- if (!fs30.existsSync(targetDir)) {
56342
- fs30.mkdirSync(targetDir, { recursive: true });
56462
+ if (!fs31.existsSync(targetDir)) {
56463
+ fs31.mkdirSync(targetDir, { recursive: true });
56343
56464
  }
56344
56465
  if (!content) {
56345
56466
  return "Error: content is required";
@@ -56361,12 +56482,12 @@ var extract_code_blocks = createSwarmTool({
56361
56482
  const base = path43.basename(filepath, path43.extname(filepath));
56362
56483
  const ext = path43.extname(filepath);
56363
56484
  let counter = 1;
56364
- while (fs30.existsSync(filepath)) {
56485
+ while (fs31.existsSync(filepath)) {
56365
56486
  filepath = path43.join(targetDir, `${base}_${counter}${ext}`);
56366
56487
  counter++;
56367
56488
  }
56368
56489
  try {
56369
- fs30.writeFileSync(filepath, code.trim(), "utf-8");
56490
+ fs31.writeFileSync(filepath, code.trim(), "utf-8");
56370
56491
  savedFiles.push(filepath);
56371
56492
  } catch (error93) {
56372
56493
  errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
@@ -56482,7 +56603,7 @@ var gitingest = createSwarmTool({
56482
56603
  // src/tools/imports.ts
56483
56604
  init_dist();
56484
56605
  init_create_tool();
56485
- import * as fs31 from "fs";
56606
+ import * as fs32 from "fs";
56486
56607
  import * as path44 from "path";
56487
56608
  var MAX_FILE_PATH_LENGTH2 = 500;
56488
56609
  var MAX_SYMBOL_LENGTH = 256;
@@ -56651,7 +56772,7 @@ var SKIP_DIRECTORIES2 = new Set([
56651
56772
  function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
56652
56773
  let entries;
56653
56774
  try {
56654
- entries = fs31.readdirSync(dir);
56775
+ entries = fs32.readdirSync(dir);
56655
56776
  } catch (e) {
56656
56777
  stats.fileErrors.push({
56657
56778
  path: dir,
@@ -56668,7 +56789,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
56668
56789
  const fullPath = path44.join(dir, entry);
56669
56790
  let stat2;
56670
56791
  try {
56671
- stat2 = fs31.statSync(fullPath);
56792
+ stat2 = fs32.statSync(fullPath);
56672
56793
  } catch (e) {
56673
56794
  stats.fileErrors.push({
56674
56795
  path: fullPath,
@@ -56737,7 +56858,7 @@ var imports = createSwarmTool({
56737
56858
  }
56738
56859
  try {
56739
56860
  const targetFile = path44.resolve(file3);
56740
- if (!fs31.existsSync(targetFile)) {
56861
+ if (!fs32.existsSync(targetFile)) {
56741
56862
  const errorResult = {
56742
56863
  error: `target file not found: ${file3}`,
56743
56864
  target: file3,
@@ -56747,7 +56868,7 @@ var imports = createSwarmTool({
56747
56868
  };
56748
56869
  return JSON.stringify(errorResult, null, 2);
56749
56870
  }
56750
- const targetStat = fs31.statSync(targetFile);
56871
+ const targetStat = fs32.statSync(targetFile);
56751
56872
  if (!targetStat.isFile()) {
56752
56873
  const errorResult = {
56753
56874
  error: "target must be a file, not a directory",
@@ -56773,12 +56894,12 @@ var imports = createSwarmTool({
56773
56894
  if (consumers.length >= MAX_CONSUMERS)
56774
56895
  break;
56775
56896
  try {
56776
- const stat2 = fs31.statSync(filePath);
56897
+ const stat2 = fs32.statSync(filePath);
56777
56898
  if (stat2.size > MAX_FILE_SIZE_BYTES4) {
56778
56899
  skippedFileCount++;
56779
56900
  continue;
56780
56901
  }
56781
- const buffer = fs31.readFileSync(filePath);
56902
+ const buffer = fs32.readFileSync(filePath);
56782
56903
  if (isBinaryFile2(filePath, buffer)) {
56783
56904
  skippedFileCount++;
56784
56905
  continue;
@@ -56950,7 +57071,7 @@ var knowledgeAdd = createSwarmTool({
56950
57071
  });
56951
57072
  // src/tools/knowledge-query.ts
56952
57073
  init_dist();
56953
- import { existsSync as existsSync28 } from "fs";
57074
+ import { existsSync as existsSync29 } from "fs";
56954
57075
  init_create_tool();
56955
57076
  var DEFAULT_LIMIT = 10;
56956
57077
  var MAX_LESSON_LENGTH = 200;
@@ -57020,14 +57141,14 @@ function validateLimit(limit) {
57020
57141
  }
57021
57142
  async function readSwarmKnowledge(directory) {
57022
57143
  const swarmPath = resolveSwarmKnowledgePath(directory);
57023
- if (!existsSync28(swarmPath)) {
57144
+ if (!existsSync29(swarmPath)) {
57024
57145
  return [];
57025
57146
  }
57026
57147
  return readKnowledge(swarmPath);
57027
57148
  }
57028
57149
  async function readHiveKnowledge() {
57029
57150
  const hivePath = resolveHiveKnowledgePath();
57030
- if (!existsSync28(hivePath)) {
57151
+ if (!existsSync29(hivePath)) {
57031
57152
  return [];
57032
57153
  }
57033
57154
  return readKnowledge(hivePath);
@@ -57327,7 +57448,7 @@ init_dist();
57327
57448
  init_config();
57328
57449
  init_schema();
57329
57450
  init_manager();
57330
- import * as fs32 from "fs";
57451
+ import * as fs33 from "fs";
57331
57452
  import * as path45 from "path";
57332
57453
  init_utils2();
57333
57454
  init_create_tool();
@@ -57587,7 +57708,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
57587
57708
  if (agentsMissing.length > 0) {
57588
57709
  try {
57589
57710
  const planPath = validateSwarmPath(dir, "plan.json");
57590
- const planRaw = fs32.readFileSync(planPath, "utf-8");
57711
+ const planRaw = fs33.readFileSync(planPath, "utf-8");
57591
57712
  const plan = JSON.parse(planRaw);
57592
57713
  const targetPhase = plan.phases.find((p) => p.id === phase);
57593
57714
  if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
@@ -57618,7 +57739,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
57618
57739
  if (phaseCompleteConfig.regression_sweep?.enforce) {
57619
57740
  try {
57620
57741
  const planPath = validateSwarmPath(dir, "plan.json");
57621
- const planRaw = fs32.readFileSync(planPath, "utf-8");
57742
+ const planRaw = fs33.readFileSync(planPath, "utf-8");
57622
57743
  const plan = JSON.parse(planRaw);
57623
57744
  const targetPhase = plan.phases.find((p) => p.id === phase);
57624
57745
  if (targetPhase) {
@@ -57656,7 +57777,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
57656
57777
  };
57657
57778
  try {
57658
57779
  const eventsPath = validateSwarmPath(dir, "events.jsonl");
57659
- fs32.appendFileSync(eventsPath, `${JSON.stringify(event)}
57780
+ fs33.appendFileSync(eventsPath, `${JSON.stringify(event)}
57660
57781
  `, "utf-8");
57661
57782
  } catch (writeError) {
57662
57783
  warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -57675,12 +57796,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
57675
57796
  }
57676
57797
  try {
57677
57798
  const planPath = validateSwarmPath(dir, "plan.json");
57678
- const planJson = fs32.readFileSync(planPath, "utf-8");
57799
+ const planJson = fs33.readFileSync(planPath, "utf-8");
57679
57800
  const plan = JSON.parse(planJson);
57680
57801
  const phaseObj = plan.phases.find((p) => p.id === phase);
57681
57802
  if (phaseObj) {
57682
57803
  phaseObj.status = "completed";
57683
- fs32.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
57804
+ fs33.writeFileSync(planPath, `${JSON.stringify(plan, null, 2)}
57684
57805
  `, "utf-8");
57685
57806
  }
57686
57807
  } catch (error93) {
@@ -57699,6 +57820,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
57699
57820
  agentsMissing,
57700
57821
  warnings
57701
57822
  };
57823
+ await flushPendingSnapshot(dir);
57702
57824
  return JSON.stringify({ ...result, timestamp: event.timestamp, duration_ms: durationMs }, null, 2);
57703
57825
  }
57704
57826
  var phase_complete = createSwarmTool({
@@ -57733,7 +57855,7 @@ init_dist();
57733
57855
  init_discovery();
57734
57856
  init_utils();
57735
57857
  init_create_tool();
57736
- import * as fs33 from "fs";
57858
+ import * as fs34 from "fs";
57737
57859
  import * as path46 from "path";
57738
57860
  var MAX_OUTPUT_BYTES5 = 52428800;
57739
57861
  var AUDIT_TIMEOUT_MS = 120000;
@@ -57752,28 +57874,28 @@ function validateArgs3(args2) {
57752
57874
  function detectEcosystems(directory) {
57753
57875
  const ecosystems = [];
57754
57876
  const cwd = directory;
57755
- if (fs33.existsSync(path46.join(cwd, "package.json"))) {
57877
+ if (fs34.existsSync(path46.join(cwd, "package.json"))) {
57756
57878
  ecosystems.push("npm");
57757
57879
  }
57758
- 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"))) {
57759
57881
  ecosystems.push("pip");
57760
57882
  }
57761
- if (fs33.existsSync(path46.join(cwd, "Cargo.toml"))) {
57883
+ if (fs34.existsSync(path46.join(cwd, "Cargo.toml"))) {
57762
57884
  ecosystems.push("cargo");
57763
57885
  }
57764
- if (fs33.existsSync(path46.join(cwd, "go.mod"))) {
57886
+ if (fs34.existsSync(path46.join(cwd, "go.mod"))) {
57765
57887
  ecosystems.push("go");
57766
57888
  }
57767
57889
  try {
57768
- const files = fs33.readdirSync(cwd);
57890
+ const files = fs34.readdirSync(cwd);
57769
57891
  if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
57770
57892
  ecosystems.push("dotnet");
57771
57893
  }
57772
57894
  } catch {}
57773
- 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"))) {
57774
57896
  ecosystems.push("ruby");
57775
57897
  }
57776
- if (fs33.existsSync(path46.join(cwd, "pubspec.yaml"))) {
57898
+ if (fs34.existsSync(path46.join(cwd, "pubspec.yaml"))) {
57777
57899
  ecosystems.push("dart");
57778
57900
  }
57779
57901
  return ecosystems;
@@ -58835,7 +58957,7 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
58835
58957
  ]);
58836
58958
  // src/tools/pre-check-batch.ts
58837
58959
  init_dist();
58838
- import * as fs36 from "fs";
58960
+ import * as fs37 from "fs";
58839
58961
  import * as path49 from "path";
58840
58962
 
58841
58963
  // node_modules/yocto-queue/index.js
@@ -59003,7 +59125,7 @@ init_lint();
59003
59125
  init_manager();
59004
59126
 
59005
59127
  // src/quality/metrics.ts
59006
- import * as fs34 from "fs";
59128
+ import * as fs35 from "fs";
59007
59129
  import * as path47 from "path";
59008
59130
  var MAX_FILE_SIZE_BYTES5 = 256 * 1024;
59009
59131
  var MIN_DUPLICATION_LINES = 10;
@@ -59042,11 +59164,11 @@ function estimateCyclomaticComplexity(content) {
59042
59164
  }
59043
59165
  function getComplexityForFile2(filePath) {
59044
59166
  try {
59045
- const stat2 = fs34.statSync(filePath);
59167
+ const stat2 = fs35.statSync(filePath);
59046
59168
  if (stat2.size > MAX_FILE_SIZE_BYTES5) {
59047
59169
  return null;
59048
59170
  }
59049
- const content = fs34.readFileSync(filePath, "utf-8");
59171
+ const content = fs35.readFileSync(filePath, "utf-8");
59050
59172
  return estimateCyclomaticComplexity(content);
59051
59173
  } catch {
59052
59174
  return null;
@@ -59057,7 +59179,7 @@ async function computeComplexityDelta(files, workingDir) {
59057
59179
  const analyzedFiles = [];
59058
59180
  for (const file3 of files) {
59059
59181
  const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
59060
- if (!fs34.existsSync(fullPath)) {
59182
+ if (!fs35.existsSync(fullPath)) {
59061
59183
  continue;
59062
59184
  }
59063
59185
  const complexity = getComplexityForFile2(fullPath);
@@ -59178,7 +59300,7 @@ function countGoExports(content) {
59178
59300
  }
59179
59301
  function getExportCountForFile(filePath) {
59180
59302
  try {
59181
- const content = fs34.readFileSync(filePath, "utf-8");
59303
+ const content = fs35.readFileSync(filePath, "utf-8");
59182
59304
  const ext = path47.extname(filePath).toLowerCase();
59183
59305
  switch (ext) {
59184
59306
  case ".ts":
@@ -59206,7 +59328,7 @@ async function computePublicApiDelta(files, workingDir) {
59206
59328
  const analyzedFiles = [];
59207
59329
  for (const file3 of files) {
59208
59330
  const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
59209
- if (!fs34.existsSync(fullPath)) {
59331
+ if (!fs35.existsSync(fullPath)) {
59210
59332
  continue;
59211
59333
  }
59212
59334
  const exports = getExportCountForFile(fullPath);
@@ -59240,15 +59362,15 @@ async function computeDuplicationRatio(files, workingDir) {
59240
59362
  const analyzedFiles = [];
59241
59363
  for (const file3 of files) {
59242
59364
  const fullPath = path47.isAbsolute(file3) ? file3 : path47.join(workingDir, file3);
59243
- if (!fs34.existsSync(fullPath)) {
59365
+ if (!fs35.existsSync(fullPath)) {
59244
59366
  continue;
59245
59367
  }
59246
59368
  try {
59247
- const stat2 = fs34.statSync(fullPath);
59369
+ const stat2 = fs35.statSync(fullPath);
59248
59370
  if (stat2.size > MAX_FILE_SIZE_BYTES5) {
59249
59371
  continue;
59250
59372
  }
59251
- const content = fs34.readFileSync(fullPath, "utf-8");
59373
+ const content = fs35.readFileSync(fullPath, "utf-8");
59252
59374
  const lines = content.split(`
59253
59375
  `).filter((line) => line.trim().length > 0);
59254
59376
  if (lines.length < MIN_DUPLICATION_LINES) {
@@ -59424,7 +59546,7 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
59424
59546
  let testLines = 0;
59425
59547
  let codeLines = 0;
59426
59548
  const srcDir = path47.join(workingDir, "src");
59427
- if (fs34.existsSync(srcDir)) {
59549
+ if (fs35.existsSync(srcDir)) {
59428
59550
  await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
59429
59551
  codeLines += lines;
59430
59552
  });
@@ -59432,14 +59554,14 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
59432
59554
  const possibleSrcDirs = ["lib", "app", "source", "core"];
59433
59555
  for (const dir of possibleSrcDirs) {
59434
59556
  const dirPath = path47.join(workingDir, dir);
59435
- if (fs34.existsSync(dirPath)) {
59557
+ if (fs35.existsSync(dirPath)) {
59436
59558
  await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
59437
59559
  codeLines += lines;
59438
59560
  });
59439
59561
  }
59440
59562
  }
59441
59563
  const testsDir = path47.join(workingDir, "tests");
59442
- if (fs34.existsSync(testsDir)) {
59564
+ if (fs35.existsSync(testsDir)) {
59443
59565
  await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
59444
59566
  testLines += lines;
59445
59567
  });
@@ -59447,7 +59569,7 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
59447
59569
  const possibleTestDirs = ["test", "__tests__", "specs"];
59448
59570
  for (const dir of possibleTestDirs) {
59449
59571
  const dirPath = path47.join(workingDir, dir);
59450
- if (fs34.existsSync(dirPath) && dirPath !== testsDir) {
59572
+ if (fs35.existsSync(dirPath) && dirPath !== testsDir) {
59451
59573
  await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
59452
59574
  testLines += lines;
59453
59575
  });
@@ -59459,7 +59581,7 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
59459
59581
  }
59460
59582
  async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
59461
59583
  try {
59462
- const entries = fs34.readdirSync(dirPath, { withFileTypes: true });
59584
+ const entries = fs35.readdirSync(dirPath, { withFileTypes: true });
59463
59585
  for (const entry of entries) {
59464
59586
  const fullPath = path47.join(dirPath, entry.name);
59465
59587
  if (entry.isDirectory()) {
@@ -59505,7 +59627,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
59505
59627
  continue;
59506
59628
  }
59507
59629
  try {
59508
- const content = fs34.readFileSync(fullPath, "utf-8");
59630
+ const content = fs35.readFileSync(fullPath, "utf-8");
59509
59631
  const lines = countCodeLines(content);
59510
59632
  callback(lines);
59511
59633
  } catch {}
@@ -59719,7 +59841,7 @@ async function qualityBudget(input, directory) {
59719
59841
  init_dist();
59720
59842
  init_manager();
59721
59843
  init_detector();
59722
- import * as fs35 from "fs";
59844
+ import * as fs36 from "fs";
59723
59845
  import * as path48 from "path";
59724
59846
  import { extname as extname9 } from "path";
59725
59847
 
@@ -60587,17 +60709,17 @@ var SEVERITY_ORDER = {
60587
60709
  };
60588
60710
  function shouldSkipFile(filePath) {
60589
60711
  try {
60590
- const stats = fs35.statSync(filePath);
60712
+ const stats = fs36.statSync(filePath);
60591
60713
  if (stats.size > MAX_FILE_SIZE_BYTES6) {
60592
60714
  return { skip: true, reason: "file too large" };
60593
60715
  }
60594
60716
  if (stats.size === 0) {
60595
60717
  return { skip: true, reason: "empty file" };
60596
60718
  }
60597
- const fd = fs35.openSync(filePath, "r");
60719
+ const fd = fs36.openSync(filePath, "r");
60598
60720
  const buffer = Buffer.alloc(8192);
60599
- const bytesRead = fs35.readSync(fd, buffer, 0, 8192, 0);
60600
- fs35.closeSync(fd);
60721
+ const bytesRead = fs36.readSync(fd, buffer, 0, 8192, 0);
60722
+ fs36.closeSync(fd);
60601
60723
  if (bytesRead > 0) {
60602
60724
  let nullCount = 0;
60603
60725
  for (let i2 = 0;i2 < bytesRead; i2++) {
@@ -60636,7 +60758,7 @@ function countBySeverity(findings) {
60636
60758
  }
60637
60759
  function scanFileWithTierA(filePath, language) {
60638
60760
  try {
60639
- const content = fs35.readFileSync(filePath, "utf-8");
60761
+ const content = fs36.readFileSync(filePath, "utf-8");
60640
60762
  const findings = executeRulesSync(filePath, content, language);
60641
60763
  return findings.map((f) => ({
60642
60764
  rule_id: f.rule_id,
@@ -60684,7 +60806,7 @@ async function sastScan(input, directory, config3) {
60684
60806
  continue;
60685
60807
  }
60686
60808
  const resolvedPath = path48.isAbsolute(filePath) ? filePath : path48.resolve(directory, filePath);
60687
- if (!fs35.existsSync(resolvedPath)) {
60809
+ if (!fs36.existsSync(resolvedPath)) {
60688
60810
  _filesSkipped++;
60689
60811
  continue;
60690
60812
  }
@@ -61143,7 +61265,7 @@ async function runSecretscanWithFiles(files, directory) {
61143
61265
  }
61144
61266
  let stat2;
61145
61267
  try {
61146
- stat2 = fs36.statSync(file3);
61268
+ stat2 = fs37.statSync(file3);
61147
61269
  } catch {
61148
61270
  skippedFiles++;
61149
61271
  continue;
@@ -61154,7 +61276,7 @@ async function runSecretscanWithFiles(files, directory) {
61154
61276
  }
61155
61277
  let content;
61156
61278
  try {
61157
- const buffer = fs36.readFileSync(file3);
61279
+ const buffer = fs37.readFileSync(file3);
61158
61280
  if (buffer.includes(0)) {
61159
61281
  skippedFiles++;
61160
61282
  continue;
@@ -61554,7 +61676,7 @@ ${paginatedContent}`;
61554
61676
  init_tool();
61555
61677
  init_manager2();
61556
61678
  init_create_tool();
61557
- import * as fs37 from "fs";
61679
+ import * as fs38 from "fs";
61558
61680
  import * as path50 from "path";
61559
61681
  function detectPlaceholderContent(args2) {
61560
61682
  const issues = [];
@@ -61666,7 +61788,7 @@ async function executeSavePlan(args2, fallbackDir) {
61666
61788
  phases_count: plan.phases.length,
61667
61789
  tasks_count: tasksCount
61668
61790
  });
61669
- await fs37.promises.writeFile(markerPath, marker, "utf8");
61791
+ await fs38.promises.writeFile(markerPath, marker, "utf8");
61670
61792
  } catch {}
61671
61793
  return {
61672
61794
  success: true,
@@ -61709,7 +61831,7 @@ var save_plan = createSwarmTool({
61709
61831
  // src/tools/sbom-generate.ts
61710
61832
  init_dist();
61711
61833
  init_manager();
61712
- import * as fs38 from "fs";
61834
+ import * as fs39 from "fs";
61713
61835
  import * as path51 from "path";
61714
61836
 
61715
61837
  // src/sbom/detectors/index.ts
@@ -62556,7 +62678,7 @@ function findManifestFiles(rootDir) {
62556
62678
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
62557
62679
  function searchDir(dir) {
62558
62680
  try {
62559
- const entries = fs38.readdirSync(dir, { withFileTypes: true });
62681
+ const entries = fs39.readdirSync(dir, { withFileTypes: true });
62560
62682
  for (const entry of entries) {
62561
62683
  const fullPath = path51.join(dir, entry.name);
62562
62684
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
@@ -62583,7 +62705,7 @@ function findManifestFilesInDirs(directories, workingDir) {
62583
62705
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
62584
62706
  for (const dir of directories) {
62585
62707
  try {
62586
- const entries = fs38.readdirSync(dir, { withFileTypes: true });
62708
+ const entries = fs39.readdirSync(dir, { withFileTypes: true });
62587
62709
  for (const entry of entries) {
62588
62710
  const fullPath = path51.join(dir, entry.name);
62589
62711
  if (entry.isFile()) {
@@ -62620,7 +62742,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
62620
62742
  }
62621
62743
  function ensureOutputDir(outputDir) {
62622
62744
  try {
62623
- fs38.mkdirSync(outputDir, { recursive: true });
62745
+ fs39.mkdirSync(outputDir, { recursive: true });
62624
62746
  } catch (error93) {
62625
62747
  if (!error93 || error93.code !== "EEXIST") {
62626
62748
  throw error93;
@@ -62714,10 +62836,10 @@ var sbom_generate = createSwarmTool({
62714
62836
  for (const manifestFile of manifestFiles) {
62715
62837
  try {
62716
62838
  const fullPath = path51.isAbsolute(manifestFile) ? manifestFile : path51.join(workingDir, manifestFile);
62717
- if (!fs38.existsSync(fullPath)) {
62839
+ if (!fs39.existsSync(fullPath)) {
62718
62840
  continue;
62719
62841
  }
62720
- const content = fs38.readFileSync(fullPath, "utf-8");
62842
+ const content = fs39.readFileSync(fullPath, "utf-8");
62721
62843
  const components = detectComponents(manifestFile, content);
62722
62844
  processedFiles.push(manifestFile);
62723
62845
  if (components.length > 0) {
@@ -62731,7 +62853,7 @@ var sbom_generate = createSwarmTool({
62731
62853
  const bomJson = serializeCycloneDX(bom);
62732
62854
  const filename = generateSbomFilename();
62733
62855
  const outputPath = path51.join(outputDir, filename);
62734
- fs38.writeFileSync(outputPath, bomJson, "utf-8");
62856
+ fs39.writeFileSync(outputPath, bomJson, "utf-8");
62735
62857
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
62736
62858
  try {
62737
62859
  const timestamp = new Date().toISOString();
@@ -62773,7 +62895,7 @@ var sbom_generate = createSwarmTool({
62773
62895
  // src/tools/schema-drift.ts
62774
62896
  init_dist();
62775
62897
  init_create_tool();
62776
- import * as fs39 from "fs";
62898
+ import * as fs40 from "fs";
62777
62899
  import * as path52 from "path";
62778
62900
  var SPEC_CANDIDATES = [
62779
62901
  "openapi.json",
@@ -62815,19 +62937,19 @@ function discoverSpecFile(cwd, specFileArg) {
62815
62937
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
62816
62938
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
62817
62939
  }
62818
- const stats = fs39.statSync(resolvedPath);
62940
+ const stats = fs40.statSync(resolvedPath);
62819
62941
  if (stats.size > MAX_SPEC_SIZE) {
62820
62942
  throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
62821
62943
  }
62822
- if (!fs39.existsSync(resolvedPath)) {
62944
+ if (!fs40.existsSync(resolvedPath)) {
62823
62945
  throw new Error(`Spec file not found: ${resolvedPath}`);
62824
62946
  }
62825
62947
  return resolvedPath;
62826
62948
  }
62827
62949
  for (const candidate of SPEC_CANDIDATES) {
62828
62950
  const candidatePath = path52.resolve(cwd, candidate);
62829
- if (fs39.existsSync(candidatePath)) {
62830
- const stats = fs39.statSync(candidatePath);
62951
+ if (fs40.existsSync(candidatePath)) {
62952
+ const stats = fs40.statSync(candidatePath);
62831
62953
  if (stats.size <= MAX_SPEC_SIZE) {
62832
62954
  return candidatePath;
62833
62955
  }
@@ -62836,7 +62958,7 @@ function discoverSpecFile(cwd, specFileArg) {
62836
62958
  return null;
62837
62959
  }
62838
62960
  function parseSpec(specFile) {
62839
- const content = fs39.readFileSync(specFile, "utf-8");
62961
+ const content = fs40.readFileSync(specFile, "utf-8");
62840
62962
  const ext = path52.extname(specFile).toLowerCase();
62841
62963
  if (ext === ".json") {
62842
62964
  return parseJsonSpec(content);
@@ -62908,7 +63030,7 @@ function extractRoutes(cwd) {
62908
63030
  function walkDir(dir) {
62909
63031
  let entries;
62910
63032
  try {
62911
- entries = fs39.readdirSync(dir, { withFileTypes: true });
63033
+ entries = fs40.readdirSync(dir, { withFileTypes: true });
62912
63034
  } catch {
62913
63035
  return;
62914
63036
  }
@@ -62941,7 +63063,7 @@ function extractRoutes(cwd) {
62941
63063
  }
62942
63064
  function extractRoutesFromFile(filePath) {
62943
63065
  const routes = [];
62944
- const content = fs39.readFileSync(filePath, "utf-8");
63066
+ const content = fs40.readFileSync(filePath, "utf-8");
62945
63067
  const lines = content.split(/\r?\n/);
62946
63068
  const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
62947
63069
  const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
@@ -63092,7 +63214,7 @@ init_secretscan();
63092
63214
  // src/tools/symbols.ts
63093
63215
  init_tool();
63094
63216
  init_create_tool();
63095
- import * as fs40 from "fs";
63217
+ import * as fs41 from "fs";
63096
63218
  import * as path53 from "path";
63097
63219
  var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
63098
63220
  var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
@@ -63123,8 +63245,8 @@ function containsWindowsAttacks(str) {
63123
63245
  function isPathInWorkspace(filePath, workspace) {
63124
63246
  try {
63125
63247
  const resolvedPath = path53.resolve(workspace, filePath);
63126
- const realWorkspace = fs40.realpathSync(workspace);
63127
- const realResolvedPath = fs40.realpathSync(resolvedPath);
63248
+ const realWorkspace = fs41.realpathSync(workspace);
63249
+ const realResolvedPath = fs41.realpathSync(resolvedPath);
63128
63250
  const relativePath = path53.relative(realWorkspace, realResolvedPath);
63129
63251
  if (relativePath.startsWith("..") || path53.isAbsolute(relativePath)) {
63130
63252
  return false;
@@ -63144,11 +63266,11 @@ function extractTSSymbols(filePath, cwd) {
63144
63266
  }
63145
63267
  let content;
63146
63268
  try {
63147
- const stats = fs40.statSync(fullPath);
63269
+ const stats = fs41.statSync(fullPath);
63148
63270
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
63149
63271
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
63150
63272
  }
63151
- content = fs40.readFileSync(fullPath, "utf-8");
63273
+ content = fs41.readFileSync(fullPath, "utf-8");
63152
63274
  } catch {
63153
63275
  return [];
63154
63276
  }
@@ -63296,11 +63418,11 @@ function extractPythonSymbols(filePath, cwd) {
63296
63418
  }
63297
63419
  let content;
63298
63420
  try {
63299
- const stats = fs40.statSync(fullPath);
63421
+ const stats = fs41.statSync(fullPath);
63300
63422
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
63301
63423
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
63302
63424
  }
63303
- content = fs40.readFileSync(fullPath, "utf-8");
63425
+ content = fs41.readFileSync(fullPath, "utf-8");
63304
63426
  } catch {
63305
63427
  return [];
63306
63428
  }
@@ -63444,7 +63566,7 @@ init_test_runner();
63444
63566
  init_dist();
63445
63567
  init_utils();
63446
63568
  init_create_tool();
63447
- import * as fs41 from "fs";
63569
+ import * as fs42 from "fs";
63448
63570
  import * as path54 from "path";
63449
63571
  var MAX_TEXT_LENGTH = 200;
63450
63572
  var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
@@ -63540,7 +63662,7 @@ function isSupportedExtension(filePath) {
63540
63662
  function findSourceFiles2(dir, files = []) {
63541
63663
  let entries;
63542
63664
  try {
63543
- entries = fs41.readdirSync(dir);
63665
+ entries = fs42.readdirSync(dir);
63544
63666
  } catch {
63545
63667
  return files;
63546
63668
  }
@@ -63552,7 +63674,7 @@ function findSourceFiles2(dir, files = []) {
63552
63674
  const fullPath = path54.join(dir, entry);
63553
63675
  let stat2;
63554
63676
  try {
63555
- stat2 = fs41.statSync(fullPath);
63677
+ stat2 = fs42.statSync(fullPath);
63556
63678
  } catch {
63557
63679
  continue;
63558
63680
  }
@@ -63645,7 +63767,7 @@ var todo_extract = createSwarmTool({
63645
63767
  return JSON.stringify(errorResult, null, 2);
63646
63768
  }
63647
63769
  const scanPath = resolvedPath;
63648
- if (!fs41.existsSync(scanPath)) {
63770
+ if (!fs42.existsSync(scanPath)) {
63649
63771
  const errorResult = {
63650
63772
  error: `path not found: ${pathsInput}`,
63651
63773
  total: 0,
@@ -63655,7 +63777,7 @@ var todo_extract = createSwarmTool({
63655
63777
  return JSON.stringify(errorResult, null, 2);
63656
63778
  }
63657
63779
  const filesToScan = [];
63658
- const stat2 = fs41.statSync(scanPath);
63780
+ const stat2 = fs42.statSync(scanPath);
63659
63781
  if (stat2.isFile()) {
63660
63782
  if (isSupportedExtension(scanPath)) {
63661
63783
  filesToScan.push(scanPath);
@@ -63674,11 +63796,11 @@ var todo_extract = createSwarmTool({
63674
63796
  const allEntries = [];
63675
63797
  for (const filePath of filesToScan) {
63676
63798
  try {
63677
- const fileStat = fs41.statSync(filePath);
63799
+ const fileStat = fs42.statSync(filePath);
63678
63800
  if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
63679
63801
  continue;
63680
63802
  }
63681
- const content = fs41.readFileSync(filePath, "utf-8");
63803
+ const content = fs42.readFileSync(filePath, "utf-8");
63682
63804
  const entries = parseTodoComments(content, filePath, tagsSet);
63683
63805
  allEntries.push(...entries);
63684
63806
  } catch {}
@@ -63706,18 +63828,18 @@ var todo_extract = createSwarmTool({
63706
63828
  // src/tools/update-task-status.ts
63707
63829
  init_tool();
63708
63830
  init_schema();
63709
- import * as fs43 from "fs";
63831
+ import * as fs44 from "fs";
63710
63832
  import * as path56 from "path";
63711
63833
 
63712
63834
  // src/hooks/diff-scope.ts
63713
- import * as fs42 from "fs";
63835
+ import * as fs43 from "fs";
63714
63836
  import * as path55 from "path";
63715
63837
  function getDeclaredScope(taskId, directory) {
63716
63838
  try {
63717
63839
  const planPath = path55.join(directory, ".swarm", "plan.json");
63718
- if (!fs42.existsSync(planPath))
63840
+ if (!fs43.existsSync(planPath))
63719
63841
  return null;
63720
- const raw = fs42.readFileSync(planPath, "utf-8");
63842
+ const raw = fs43.readFileSync(planPath, "utf-8");
63721
63843
  const plan = JSON.parse(raw);
63722
63844
  for (const phase of plan.phases ?? []) {
63723
63845
  for (const task of phase.tasks ?? []) {
@@ -63852,7 +63974,7 @@ function checkReviewerGate(taskId, workingDirectory) {
63852
63974
  const resolvedDir2 = workingDirectory;
63853
63975
  try {
63854
63976
  const planPath = path56.join(resolvedDir2, ".swarm", "plan.json");
63855
- const planRaw = fs43.readFileSync(planPath, "utf-8");
63977
+ const planRaw = fs44.readFileSync(planPath, "utf-8");
63856
63978
  const plan = JSON.parse(planRaw);
63857
63979
  for (const planPhase of plan.phases ?? []) {
63858
63980
  for (const task of planPhase.tasks ?? []) {
@@ -63872,7 +63994,7 @@ function checkReviewerGate(taskId, workingDirectory) {
63872
63994
  const resolvedDir = workingDirectory;
63873
63995
  try {
63874
63996
  const evidencePath = path56.join(resolvedDir, ".swarm", "evidence", `${taskId}.json`);
63875
- const raw = fs43.readFileSync(evidencePath, "utf-8");
63997
+ const raw = fs44.readFileSync(evidencePath, "utf-8");
63876
63998
  const evidence = JSON.parse(raw);
63877
63999
  if (evidence?.required_gates && Array.isArray(evidence.required_gates) && evidence?.gates) {
63878
64000
  const allGatesMet = evidence.required_gates.every((gate) => evidence.gates[gate] != null);
@@ -63913,7 +64035,7 @@ function checkReviewerGate(taskId, workingDirectory) {
63913
64035
  try {
63914
64036
  const resolvedDir2 = workingDirectory;
63915
64037
  const planPath = path56.join(resolvedDir2, ".swarm", "plan.json");
63916
- const planRaw = fs43.readFileSync(planPath, "utf-8");
64038
+ const planRaw = fs44.readFileSync(planPath, "utf-8");
63917
64039
  const plan = JSON.parse(planRaw);
63918
64040
  for (const planPhase of plan.phases ?? []) {
63919
64041
  for (const task of planPhase.tasks ?? []) {
@@ -64107,9 +64229,9 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
64107
64229
  }
64108
64230
  const resolvedDir = path56.resolve(normalizedDir);
64109
64231
  try {
64110
- const realPath = fs43.realpathSync(resolvedDir);
64232
+ const realPath = fs44.realpathSync(resolvedDir);
64111
64233
  const planPath = path56.join(realPath, ".swarm", "plan.json");
64112
- if (!fs43.existsSync(planPath)) {
64234
+ if (!fs44.existsSync(planPath)) {
64113
64235
  return {
64114
64236
  success: false,
64115
64237
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -64623,6 +64745,7 @@ var OpenCodeSwarm = async (ctx) => {
64623
64745
  await safeHook(activityHooks.toolBefore)(input, output);
64624
64746
  },
64625
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);
64626
64749
  await activityHooks.toolAfter(input, output);
64627
64750
  await guardrailsHooks.toolAfter(input, output);
64628
64751
  await safeHook(delegationLedgerHook.toolAfter)(input, output);
@@ -64637,12 +64760,15 @@ var OpenCodeSwarm = async (ctx) => {
64637
64760
  await safeHook(darkMatterDetectorHook)(input, output);
64638
64761
  await snapshotWriterHook(input, output);
64639
64762
  await toolSummarizerHook?.(input, output);
64640
- if (slopDetectorHook)
64641
- await slopDetectorHook.toolAfter(input, output);
64642
- if (incrementalVerifyHook)
64643
- await incrementalVerifyHook.toolAfter(input, output);
64644
- if (compactionServiceHook)
64645
- 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
+ }
64646
64772
  const toolOutputConfig = config3.tool_output;
64647
64773
  if (toolOutputConfig && toolOutputConfig.truncation_enabled !== false && typeof output.output === "string") {
64648
64774
  const defaultTruncatableTools = new Set([
@@ -64676,8 +64802,12 @@ var OpenCodeSwarm = async (ctx) => {
64676
64802
  session.lastAgentEventTime = Date.now();
64677
64803
  }
64678
64804
  }
64805
+ deleteStoredInputArgs(input.callID);
64679
64806
  },
64680
- "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
+ }),
64681
64811
  automation: automationManager
64682
64812
  };
64683
64813
  };