opencode-swarm 6.80.1 → 6.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -14685,7 +14685,7 @@ function resolveGuardrailsConfig(config2, agentName) {
14685
14685
  };
14686
14686
  return resolved;
14687
14687
  }
14688
- var KNOWN_SWARM_PREFIXES, SEPARATORS, AgentOverrideConfigSchema, SwarmConfigSchema, HooksConfigSchema, ScoringWeightsSchema, DecisionDecaySchema, TokenRatiosSchema, ScoringConfigSchema, ContextBudgetConfigSchema, EvidenceConfigSchema, GateFeatureSchema, PlaceholderScanConfigSchema, QualityBudgetConfigSchema, GateConfigSchema, PipelineConfigSchema, PhaseCompleteConfigSchema, SummaryConfigSchema, ReviewPassesConfigSchema, AdversarialDetectionConfigSchema, AdversarialTestingConfigSchemaBase, AdversarialTestingConfigSchema, IntegrationAnalysisConfigSchema, DocsConfigSchema, UIReviewConfigSchema, CompactionAdvisoryConfigSchema, LintConfigSchema, SecretscanConfigSchema, GuardrailsProfileSchema, DEFAULT_AGENT_PROFILES, DEFAULT_ARCHITECT_PROFILE, GuardrailsConfigSchema, WatchdogConfigSchema, SelfReviewConfigSchema, ToolFilterConfigSchema, PlanCursorConfigSchema, CheckpointConfigSchema, AutomationModeSchema, AutomationCapabilitiesSchema, AutomationConfigSchemaBase, AutomationConfigSchema, KnowledgeConfigSchema, CuratorConfigSchema, SlopDetectorConfigSchema, IncrementalVerifyConfigSchema, CompactionConfigSchema, AgentAuthorityRuleSchema, AuthorityConfigSchema, CouncilConfigSchema, ParallelizationConfigSchema, PluginConfigSchema;
14688
+ var KNOWN_SWARM_PREFIXES, SEPARATORS, AgentOverrideConfigSchema, SwarmConfigSchema, HooksConfigSchema, ScoringWeightsSchema, DecisionDecaySchema, TokenRatiosSchema, ScoringConfigSchema, ContextBudgetConfigSchema, EvidenceConfigSchema, GateFeatureSchema, PlaceholderScanConfigSchema, QualityBudgetConfigSchema, GateConfigSchema, PipelineConfigSchema, PhaseCompleteConfigSchema, SummaryConfigSchema, ReviewPassesConfigSchema, AdversarialDetectionConfigSchema, AdversarialTestingConfigSchemaBase, AdversarialTestingConfigSchema, IntegrationAnalysisConfigSchema, DocsConfigSchema, UIReviewConfigSchema, CompactionAdvisoryConfigSchema, LintConfigSchema, SecretscanConfigSchema, GuardrailsProfileSchema, DEFAULT_AGENT_PROFILES, DEFAULT_ARCHITECT_PROFILE, GuardrailsConfigSchema, WatchdogConfigSchema, SelfReviewConfigSchema, ToolFilterConfigSchema, PlanCursorConfigSchema, CheckpointConfigSchema, AutomationModeSchema, AutomationCapabilitiesSchema, AutomationConfigSchemaBase, AutomationConfigSchema, KnowledgeConfigSchema, CuratorConfigSchema, SlopDetectorConfigSchema, IncrementalVerifyConfigSchema, CompactionConfigSchema, PrmConfigSchema, AgentAuthorityRuleSchema, AuthorityConfigSchema, CouncilConfigSchema, ParallelizationConfigSchema, PluginConfigSchema;
14689
14689
  var init_schema = __esm(() => {
14690
14690
  init_zod();
14691
14691
  init_constants();
@@ -15168,6 +15168,25 @@ var init_schema = __esm(() => {
15168
15168
  emergencyThreshold: exports_external.number().min(1).max(99).default(80),
15169
15169
  preserveLastNTurns: exports_external.number().int().min(1).default(5)
15170
15170
  });
15171
+ PrmConfigSchema = exports_external.object({
15172
+ enabled: exports_external.boolean().default(true),
15173
+ pattern_thresholds: exports_external.object({
15174
+ repetition_loop: exports_external.number().min(1).default(2),
15175
+ ping_pong: exports_external.number().min(1).default(2),
15176
+ expansion_drift: exports_external.number().min(1).default(3),
15177
+ stuck_on_test: exports_external.number().min(1).default(3),
15178
+ context_thrash: exports_external.number().min(1).default(3)
15179
+ }).default(() => ({
15180
+ repetition_loop: 2,
15181
+ ping_pong: 2,
15182
+ expansion_drift: 3,
15183
+ stuck_on_test: 3,
15184
+ context_thrash: 3
15185
+ })),
15186
+ max_trajectory_lines: exports_external.number().min(10).default(1000),
15187
+ escalation_enabled: exports_external.boolean().default(true),
15188
+ detection_timeout_ms: exports_external.number().min(10).default(100)
15189
+ });
15171
15190
  AgentAuthorityRuleSchema = exports_external.object({
15172
15191
  readOnly: exports_external.boolean().optional(),
15173
15192
  blockedExact: exports_external.array(exports_external.string()).optional(),
@@ -15248,6 +15267,7 @@ var init_schema = __esm(() => {
15248
15267
  }).optional(),
15249
15268
  incremental_verify: IncrementalVerifyConfigSchema.optional(),
15250
15269
  compaction_service: CompactionConfigSchema.optional(),
15270
+ prm: PrmConfigSchema.optional(),
15251
15271
  council: CouncilConfigSchema.optional(),
15252
15272
  parallelization: ParallelizationConfigSchema.optional(),
15253
15273
  turbo_mode: exports_external.boolean().default(false).optional(),
@@ -15921,6 +15941,29 @@ var init_telemetry = __esm(() => {
15921
15941
  shellFamily,
15922
15942
  executionMode
15923
15943
  });
15944
+ },
15945
+ prmPatternDetected(sessionId, pattern, severity, category, stepRange) {
15946
+ emit("prm_pattern_detected", {
15947
+ sessionId,
15948
+ pattern,
15949
+ severity,
15950
+ category,
15951
+ stepRange
15952
+ });
15953
+ },
15954
+ prmCourseCorrectionInjected(sessionId, pattern, level) {
15955
+ emit("prm_course_correction_injected", { sessionId, pattern, level });
15956
+ },
15957
+ prmEscalationTriggered(sessionId, pattern, level, occurrenceCount) {
15958
+ emit("prm_escalation_triggered", {
15959
+ sessionId,
15960
+ pattern,
15961
+ level,
15962
+ occurrenceCount
15963
+ });
15964
+ },
15965
+ prmHardStop(sessionId, pattern, level, occurrenceCount) {
15966
+ emit("prm_hard_stop", { sessionId, pattern, level, occurrenceCount });
15924
15967
  }
15925
15968
  };
15926
15969
  });
@@ -23676,6 +23719,12 @@ function createGuardrailsHooks(directory, directoryOrConfig, config2, authorityC
23676
23719
  }
23677
23720
  }
23678
23721
  }
23722
+ {
23723
+ const prmSession = swarmState.agentSessions.get(input.sessionID);
23724
+ if (prmSession?.prmHardStopPending) {
23725
+ throw new Error("\uD83D\uDED1 PRM HARD STOP: Pattern escalation maximum reached. Stop tool calls and return progress summary.");
23726
+ }
23727
+ }
23679
23728
  const resolved = resolveSessionAndWindow(input.sessionID);
23680
23729
  if (!resolved)
23681
23730
  return;
@@ -23989,6 +24038,22 @@ ${textPart2.text}`;
23989
24038
  } else if (!isArchitectSession && session && (session.pendingAdvisoryMessages?.length ?? 0) > 0) {
23990
24039
  session.pendingAdvisoryMessages = [];
23991
24040
  }
24041
+ if (isArchitectSession && session?.prmHardStopPending) {
24042
+ session.prmHardStopPending = false;
24043
+ const lastPattern = session.prmLastPatternDetected;
24044
+ const patternType = lastPattern?.pattern ?? "unknown";
24045
+ const occurrenceCount = session.prmPatternCounts.get(patternType) ?? 0;
24046
+ telemetry.prmHardStop(_input.sessionID, patternType, session.prmEscalationLevel, occurrenceCount);
24047
+ const hardStopMsg = systemMessages[0];
24048
+ if (hardStopMsg) {
24049
+ const hardStopTextPart = (hardStopMsg.parts ?? []).find((part) => part.type === "text" && typeof part.text === "string");
24050
+ if (hardStopTextPart && !hardStopTextPart.text.includes("[HARD STOP]")) {
24051
+ hardStopTextPart.text = `[HARD STOP] PRM has detected repeated pattern violations. STOP all tool calls and return a summary of your progress. [/HARD STOP]
24052
+
24053
+ ` + hardStopTextPart.text;
24054
+ }
24055
+ }
24056
+ }
23992
24057
  if (isArchitectSession && session && session.architectWriteCount > session.selfCodingWarnedAtCount) {
23993
24058
  let targetSystemMessage = systemMessages[0];
23994
24059
  if (!targetSystemMessage) {
@@ -25512,7 +25577,12 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000, dire
25512
25577
  revisionLimitHit: false,
25513
25578
  loopDetectionWindow: [],
25514
25579
  pendingAdvisoryMessages: [],
25515
- sessionRehydratedAt: 0
25580
+ sessionRehydratedAt: 0,
25581
+ prmPatternCounts: new Map,
25582
+ prmEscalationLevel: 0,
25583
+ prmLastPatternDetected: null,
25584
+ prmTrajectoryStep: 0,
25585
+ prmHardStopPending: false
25516
25586
  };
25517
25587
  swarmState.agentSessions.set(sessionId, sessionState);
25518
25588
  telemetry.sessionStarted(sessionId, agentName);
@@ -25657,6 +25727,21 @@ function ensureAgentSession(sessionId, agentName, directory) {
25657
25727
  if (session.sessionRehydratedAt === undefined) {
25658
25728
  session.sessionRehydratedAt = 0;
25659
25729
  }
25730
+ if (session.prmPatternCounts === undefined) {
25731
+ session.prmPatternCounts = new Map;
25732
+ }
25733
+ if (session.prmEscalationLevel === undefined) {
25734
+ session.prmEscalationLevel = 0;
25735
+ }
25736
+ if (session.prmLastPatternDetected === undefined) {
25737
+ session.prmLastPatternDetected = null;
25738
+ }
25739
+ if (session.prmTrajectoryStep === undefined) {
25740
+ session.prmTrajectoryStep = 0;
25741
+ }
25742
+ if (session.prmHardStopPending === undefined) {
25743
+ session.prmHardStopPending = false;
25744
+ }
25660
25745
  session.lastToolCallTime = now;
25661
25746
  return session;
25662
25747
  }
@@ -62200,7 +62285,7 @@ var init_curator_drift = __esm(() => {
62200
62285
 
62201
62286
  // src/index.ts
62202
62287
  init_agents();
62203
- import * as path98 from "path";
62288
+ import * as path101 from "path";
62204
62289
 
62205
62290
  // src/background/index.ts
62206
62291
  init_event_bus();
@@ -65906,20 +65991,32 @@ Recommendation: Consider escalating to user or taking a different approach
65906
65991
  The current fix strategy appears to be cycling without progress`;
65907
65992
  return { eventLogged, checkpointCreated, message };
65908
65993
  }
65909
- var recentToolCalls = [];
65994
+ var recentToolCallsBySession = new Map;
65995
+ var lastSpiralTimestampBySession = new Map;
65910
65996
  var MAX_RECENT_CALLS = 20;
65911
65997
  var SPIRAL_THRESHOLD = 5;
65912
65998
  var SPIRAL_WINDOW_MS = 300000;
65913
- function recordToolCall(tool3, args2) {
65999
+ var SPIRAL_COOLDOWN_MS = 60000;
66000
+ var MAX_TRACKED_SESSIONS = 500;
66001
+ function recordToolCall(tool3, args2, sessionId) {
65914
66002
  const argsHash = typeof args2 === "string" ? args2.slice(0, 100) : JSON.stringify(args2 ?? "").slice(0, 100);
65915
- recentToolCalls.push({ tool: tool3, argsHash, timestamp: Date.now() });
65916
- if (recentToolCalls.length > MAX_RECENT_CALLS) {
65917
- recentToolCalls.shift();
66003
+ let calls = recentToolCallsBySession.get(sessionId);
66004
+ if (!calls) {
66005
+ calls = [];
66006
+ recentToolCallsBySession.set(sessionId, calls);
66007
+ }
66008
+ calls.push({ tool: tool3, argsHash, timestamp: Date.now() });
66009
+ if (calls.length > MAX_RECENT_CALLS) {
66010
+ calls.shift();
65918
66011
  }
65919
66012
  }
65920
- async function detectDebuggingSpiral(_directory) {
66013
+ async function detectDebuggingSpiral(_directory, sessionId) {
65921
66014
  const now = Date.now();
65922
- const windowCalls = recentToolCalls.filter((c) => now - c.timestamp < SPIRAL_WINDOW_MS);
66015
+ const lastTrigger = lastSpiralTimestampBySession.get(sessionId) ?? 0;
66016
+ if (now - lastTrigger < SPIRAL_COOLDOWN_MS)
66017
+ return null;
66018
+ const calls = recentToolCallsBySession.get(sessionId) ?? [];
66019
+ const windowCalls = calls.filter((c) => now - c.timestamp < SPIRAL_WINDOW_MS);
65923
66020
  if (windowCalls.length < SPIRAL_THRESHOLD)
65924
66021
  return null;
65925
66022
  const lastN = windowCalls.slice(-SPIRAL_THRESHOLD);
@@ -65928,6 +66025,17 @@ async function detectDebuggingSpiral(_directory) {
65928
66025
  const allSameTool = lastN.every((c) => c.tool === firstTool);
65929
66026
  const allSimilarArgs = lastN.every((c) => c.argsHash === firstArgs);
65930
66027
  if (allSameTool && allSimilarArgs) {
66028
+ lastSpiralTimestampBySession.set(sessionId, now);
66029
+ recentToolCallsBySession.delete(sessionId);
66030
+ if (lastSpiralTimestampBySession.size > MAX_TRACKED_SESSIONS) {
66031
+ for (const oldest of lastSpiralTimestampBySession.keys()) {
66032
+ if (oldest !== sessionId) {
66033
+ lastSpiralTimestampBySession.delete(oldest);
66034
+ recentToolCallsBySession.delete(oldest);
66035
+ break;
66036
+ }
66037
+ }
66038
+ }
65931
66039
  return {
65932
66040
  pattern: "VELOCITY_RATIONALIZATION",
65933
66041
  severity: "HIGH",
@@ -70540,6 +70648,996 @@ function createSteeringConsumedHook(directory) {
70540
70648
  return safeHook(hook);
70541
70649
  }
70542
70650
 
70651
+ // src/hooks/trajectory-logger.ts
70652
+ init_manager2();
70653
+ import * as fs52 from "fs/promises";
70654
+ import * as path66 from "path";
70655
+
70656
+ // src/prm/trajectory-store.ts
70657
+ init_utils2();
70658
+ import * as fs51 from "fs/promises";
70659
+ import * as path65 from "path";
70660
+ function getTrajectoryPath(sessionId, directory) {
70661
+ const relativePath = path65.join("trajectories", `${sessionId}.jsonl`);
70662
+ return validateSwarmPath(directory, relativePath);
70663
+ }
70664
+ var _inMemoryTrajectoryCache = new Map;
70665
+ function getInMemoryTrajectory(sessionId) {
70666
+ const cached3 = _inMemoryTrajectoryCache.get(sessionId);
70667
+ return cached3 ? [...cached3] : [];
70668
+ }
70669
+ async function appendTrajectoryEntry(sessionId, entry, directory, maxLines = 1000) {
70670
+ try {
70671
+ const cached3 = _inMemoryTrajectoryCache.get(sessionId) ?? [];
70672
+ cached3.push(entry);
70673
+ if (cached3.length > maxLines) {
70674
+ const keepCount = Math.max(1, Math.floor(maxLines / 2));
70675
+ _inMemoryTrajectoryCache.set(sessionId, cached3.slice(-keepCount));
70676
+ } else {
70677
+ _inMemoryTrajectoryCache.set(sessionId, cached3);
70678
+ }
70679
+ const trajectoryPath = getTrajectoryPath(sessionId, directory);
70680
+ await fs51.mkdir(path65.dirname(trajectoryPath), { recursive: true });
70681
+ const line = `${JSON.stringify(entry)}
70682
+ `;
70683
+ await fs51.appendFile(trajectoryPath, line, "utf-8");
70684
+ } catch (err2) {
70685
+ console.warn(`[trajectory-store] Failed to append trajectory entry: ${err2}`);
70686
+ }
70687
+ }
70688
+ async function readTrajectory(sessionId, directory) {
70689
+ try {
70690
+ const trajectoryPath = getTrajectoryPath(sessionId, directory);
70691
+ const content = await fs51.readFile(trajectoryPath, "utf-8");
70692
+ const lines = content.split(`
70693
+ `).filter((line) => line.trim().length > 0);
70694
+ const entries = [];
70695
+ for (const line of lines) {
70696
+ try {
70697
+ entries.push(JSON.parse(line));
70698
+ } catch {}
70699
+ }
70700
+ return entries;
70701
+ } catch (err2) {
70702
+ if (err2.code === "ENOENT") {
70703
+ return [];
70704
+ }
70705
+ console.warn(`[trajectory-store] Failed to read trajectory: ${err2}`);
70706
+ return [];
70707
+ }
70708
+ }
70709
+ async function cleanupOldTrajectoryFiles(directory, maxAgeDays = 7) {
70710
+ const cutoffMs = maxAgeDays * 24 * 60 * 60 * 1000;
70711
+ const now = Date.now();
70712
+ for (const subdir of ["trajectories", "replays"]) {
70713
+ try {
70714
+ const dirPath = validateSwarmPath(directory, subdir);
70715
+ const entries = await fs51.readdir(dirPath, { withFileTypes: true });
70716
+ for (const entry of entries) {
70717
+ if (!entry.isFile())
70718
+ continue;
70719
+ const filePath = path65.join(dirPath, entry.name);
70720
+ try {
70721
+ const stat4 = await fs51.stat(filePath);
70722
+ if (now - stat4.mtimeMs > cutoffMs) {
70723
+ await fs51.unlink(filePath);
70724
+ }
70725
+ } catch {}
70726
+ }
70727
+ } catch {}
70728
+ }
70729
+ }
70730
+
70731
+ // src/hooks/trajectory-logger.ts
70732
+ init_state();
70733
+ init_utils2();
70734
+ var callStartTimes2 = new Map;
70735
+ var sessionStepCounters = new Map;
70736
+ var SENSITIVE_FIELDS = new Set([
70737
+ "password",
70738
+ "token",
70739
+ "secret",
70740
+ "api_key",
70741
+ "apikey",
70742
+ "authorization",
70743
+ "access_token",
70744
+ "refresh_token",
70745
+ "private_key",
70746
+ "secret_key",
70747
+ "credential",
70748
+ "auth",
70749
+ "bearer",
70750
+ "x-api-key",
70751
+ "session_id",
70752
+ "cookie"
70753
+ ]);
70754
+ var SENSITIVE_SUBSTRINGS = [
70755
+ "key",
70756
+ "secret",
70757
+ "token",
70758
+ "password",
70759
+ "auth",
70760
+ "credential",
70761
+ "private",
70762
+ "certificate",
70763
+ "bearer",
70764
+ "session",
70765
+ "cookie"
70766
+ ];
70767
+ function isSensitiveKey(key) {
70768
+ const lower = key.toLowerCase();
70769
+ return SENSITIVE_SUBSTRINGS.some((substr) => lower.includes(substr));
70770
+ }
70771
+ async function truncateTrajectoryFile(filePath, maxLines) {
70772
+ try {
70773
+ const content = await fs52.readFile(filePath, "utf-8");
70774
+ const lines = content.split(`
70775
+ `).filter((line) => line.trim().length > 0);
70776
+ if (lines.length <= maxLines) {
70777
+ return;
70778
+ }
70779
+ const keepCount = Math.floor(maxLines / 2);
70780
+ const keptLines = lines.slice(-keepCount);
70781
+ await fs52.writeFile(filePath, `${keptLines.join(`
70782
+ `)}
70783
+ `, "utf-8");
70784
+ } catch {}
70785
+ }
70786
+ function deriveAction(tool3) {
70787
+ const toolLower = tool3.toLowerCase();
70788
+ if (toolLower === "task")
70789
+ return "delegate";
70790
+ if (["write", "edit", "apply_patch"].includes(toolLower))
70791
+ return "edit";
70792
+ if (["read", "glob", "search"].includes(toolLower))
70793
+ return "read";
70794
+ if (["bash", "shell"].includes(toolLower))
70795
+ return "execute";
70796
+ if (toolLower === "test_runner")
70797
+ return "test";
70798
+ return "tool_use";
70799
+ }
70800
+ function extractTarget(tool3, args2) {
70801
+ if (!args2)
70802
+ return "";
70803
+ if (tool3.toLowerCase() === "task") {
70804
+ const subagentType = args2.subagent_type;
70805
+ if (typeof subagentType === "string" && subagentType.length > 0) {
70806
+ return subagentType;
70807
+ }
70808
+ }
70809
+ const targetFields = ["filePath", "path", "file", "target"];
70810
+ for (const field of targetFields) {
70811
+ const value = args2[field];
70812
+ if (typeof value === "string" && value.length > 0) {
70813
+ return value;
70814
+ }
70815
+ }
70816
+ const toolLower = tool3.toLowerCase();
70817
+ if (toolLower === "bash" || toolLower === "shell" || toolLower === "execute" || toolLower === "command") {
70818
+ const command = args2.command;
70819
+ if (typeof command === "string" && command.length > 0) {
70820
+ const firstWord = command.split(/\s+/)[0] || "";
70821
+ if (firstWord.length > 0) {
70822
+ return firstWord;
70823
+ }
70824
+ }
70825
+ const description = args2.description;
70826
+ if (typeof description === "string" && description.length > 0) {
70827
+ return description.length > 30 ? `${description.slice(0, 27)}...` : description;
70828
+ }
70829
+ const argsStr = args2.args;
70830
+ if (typeof argsStr === "string" && argsStr.length > 0) {
70831
+ const firstWord = argsStr.split(/\s+/)[0] || "";
70832
+ if (firstWord.length > 0) {
70833
+ return firstWord;
70834
+ }
70835
+ }
70836
+ }
70837
+ return "";
70838
+ }
70839
+ function extractIntent(tool3, args2) {
70840
+ if (!args2)
70841
+ return "";
70842
+ if (tool3.toLowerCase() === "task") {
70843
+ const prompt = args2.prompt;
70844
+ const description = args2.description;
70845
+ const text = typeof prompt === "string" ? prompt : typeof description === "string" ? description : "";
70846
+ if (text.length > 100) {
70847
+ return `${text.slice(0, 97)}...`;
70848
+ }
70849
+ return text;
70850
+ }
70851
+ const intentFields = ["description", "task"];
70852
+ for (const field of intentFields) {
70853
+ const value = args2[field];
70854
+ if (typeof value === "string" && value.length > 0) {
70855
+ return value.length > 200 ? `${value.slice(0, 197)}...` : value;
70856
+ }
70857
+ }
70858
+ return "";
70859
+ }
70860
+ function mapResult(verdict) {
70861
+ if (verdict === "success")
70862
+ return "success";
70863
+ if (verdict === "failure")
70864
+ return "failure";
70865
+ return "pending";
70866
+ }
70867
+ function createTrajectoryLoggerHook(config3, _directory) {
70868
+ const enabled = config3.enabled ?? true;
70869
+ const maxLines = config3.max_lines ?? 500;
70870
+ return {
70871
+ toolAfter: async (input, output) => {
70872
+ if (!enabled)
70873
+ return;
70874
+ const sessionId = input.sessionID;
70875
+ const session = swarmState.agentSessions.get(sessionId);
70876
+ if (!session?.delegationActive) {
70877
+ return;
70878
+ }
70879
+ const taskId = session.currentTaskId;
70880
+ if (!taskId) {
70881
+ return;
70882
+ }
70883
+ const startKey = `${sessionId}:${input.callID}`;
70884
+ const startTime = callStartTimes2.get(startKey) ?? Date.now();
70885
+ callStartTimes2.delete(startKey);
70886
+ const elapsed_ms = Date.now() - startTime;
70887
+ const agentName = swarmState.activeAgent.get(sessionId) ?? session?.agentName ?? "unknown";
70888
+ const args_summary = summarizeArgs(input.args, 200);
70889
+ const verdict = deriveVerdict(output);
70890
+ const currentStep = sessionStepCounters.get(sessionId) ?? 0;
70891
+ const step = currentStep + 1;
70892
+ sessionStepCounters.set(sessionId, step);
70893
+ const action = deriveAction(input.tool);
70894
+ const target = extractTarget(input.tool, input.args);
70895
+ const intent = extractIntent(input.tool, input.args);
70896
+ const result = mapResult(verdict);
70897
+ const entry = {
70898
+ step,
70899
+ agent: agentName,
70900
+ action,
70901
+ target,
70902
+ intent,
70903
+ timestamp: new Date().toISOString(),
70904
+ result,
70905
+ tool: input.tool,
70906
+ args_summary,
70907
+ verdict,
70908
+ elapsed_ms
70909
+ };
70910
+ const sanitized = sanitizeTaskId2(taskId);
70911
+ const relativePath = path66.join("evidence", sanitized, "trajectory.jsonl");
70912
+ const trajectoryPath = validateSwarmPath(_directory, relativePath);
70913
+ try {
70914
+ await fs52.mkdir(path66.dirname(trajectoryPath), { recursive: true });
70915
+ const line = `${JSON.stringify(entry)}
70916
+ `;
70917
+ await fs52.appendFile(trajectoryPath, line, "utf-8");
70918
+ await truncateTrajectoryFile(trajectoryPath, maxLines);
70919
+ } catch {}
70920
+ try {
70921
+ await appendTrajectoryEntry(sessionId, entry, _directory, maxLines);
70922
+ } catch {}
70923
+ }
70924
+ };
70925
+ }
70926
+ function summarizeArgs(args2, maxLength) {
70927
+ if (!args2 || Object.keys(args2).length === 0) {
70928
+ return "";
70929
+ }
70930
+ const summaries = [];
70931
+ for (const [key, value] of Object.entries(args2)) {
70932
+ if (SENSITIVE_FIELDS.has(key) || isSensitiveKey(key)) {
70933
+ summaries.push(`${key}:[REDACTED]`);
70934
+ continue;
70935
+ }
70936
+ if (value === null || value === undefined) {
70937
+ summaries.push(`${key}:null`);
70938
+ } else if (typeof value === "string") {
70939
+ const truncated = value.length > 50 ? `${value.slice(0, 50)}...` : value;
70940
+ summaries.push(`${key}:"${truncated}"`);
70941
+ } else if (typeof value === "number" || typeof value === "boolean") {
70942
+ summaries.push(`${key}:${String(value)}`);
70943
+ } else if (Array.isArray(value)) {
70944
+ const itemSummary = value.length > 3 ? `${value.slice(0, 3).map(String).join(",")},...(+${value.length - 3})` : value.map(String).join(",");
70945
+ summaries.push(`${key}:[${itemSummary}]`);
70946
+ } else if (typeof value === "object") {
70947
+ const keys = Object.keys(value);
70948
+ summaries.push(`${key}:{${keys.join(",")}}`);
70949
+ } else {
70950
+ summaries.push(`${key}:${typeof value}`);
70951
+ }
70952
+ }
70953
+ const summary = summaries.join(" ");
70954
+ return summary.length > maxLength ? `${summary.slice(0, maxLength - 3)}...` : summary;
70955
+ }
70956
+ function deriveVerdict(output) {
70957
+ if (output.metadata && typeof output.metadata === "object" && !Array.isArray(output.metadata)) {
70958
+ const meta3 = output.metadata;
70959
+ if (typeof meta3.verdict === "string" && meta3.verdict.length > 0) {
70960
+ return meta3.verdict;
70961
+ }
70962
+ if (meta3.success === false || meta3.passed === false) {
70963
+ return "failure";
70964
+ }
70965
+ if (meta3.success === true || meta3.passed === true) {
70966
+ return "success";
70967
+ }
70968
+ }
70969
+ const outputStr = String(output.output ?? "");
70970
+ if (outputStr.startsWith("Error:") || outputStr.startsWith("error:") || outputStr.startsWith("Error: ")) {
70971
+ return "failure";
70972
+ }
70973
+ return "success";
70974
+ }
70975
+
70976
+ // src/prm/course-correction.ts
70977
+ var GUIDANCE_TEMPLATES = {
70978
+ repetition_loop: "Agent is repeating the same action on the same target. Consider consolidating changes, stepping back to review the approach, or delegating to a different agent.",
70979
+ ping_pong: "Agents are delegating back and forth without making progress. Consider having the architect take direct control or redefining the task boundaries.",
70980
+ expansion_drift: "Scope is expanding beyond the original task. Consider creating a follow-up task, reducing the current scope, or updating the spec.",
70981
+ stuck_on_test: "Repeated edit-test cycles detected. Consider reviewing the test expectations, checking for environmental issues, or seeking SME consultation.",
70982
+ context_thrash: "Agent is requesting increasingly large file sets. Consider focusing on the specific files needed for the current task or compacting context."
70983
+ };
70984
+ var ACTION_TEMPLATES = {
70985
+ repetition_loop: (match) => {
70986
+ const agents = match.affectedAgents.length > 0 ? match.affectedAgents.join(", ") : "current agent";
70987
+ const targets = match.affectedTargets.length > 0 ? match.affectedTargets.join(", ") : "current target";
70988
+ return `Stop repetitive edits to ${targets} by ${agents}. Take a step back and consolidate the changes made so far before proceeding.`;
70989
+ },
70990
+ ping_pong: () => {
70991
+ return `Interrupt the delegation cycle. Architect should take direct control of the task or explicitly redefine which agent owns which subtask.`;
70992
+ },
70993
+ expansion_drift: () => {
70994
+ return `Freeze current scope. Document what's been attempted and create a follow-up issue for additional work. Complete current task before expanding further.`;
70995
+ },
70996
+ stuck_on_test: (match) => {
70997
+ const agents = match.affectedAgents.length > 0 ? match.affectedAgents.join(", ") : "the agent";
70998
+ return `Pause edit-test cycle. ${agents} should review test expectations, verify environment is clean, and consult SME if root cause is unclear.`;
70999
+ },
71000
+ context_thrash: (match) => {
71001
+ const targets = match.affectedTargets.length > 0 ? match.affectedTargets.slice(0, 3).join(", ") : "requested files";
71002
+ return `Restrict file access to only ${targets}. Use targeted file selection instead of broad context requests.`;
71003
+ }
71004
+ };
71005
+ function generateCourseCorrection(match, trajectory) {
71006
+ const alert = `TRAJECTORY ALERT: ${match.pattern} detected (severity: ${match.severity}) at steps ${match.stepRange[0]}-${match.stepRange[1]}`;
71007
+ const guidance = GUIDANCE_TEMPLATES[match.pattern];
71008
+ const action = ACTION_TEMPLATES[match.pattern](match, trajectory);
71009
+ return {
71010
+ alert,
71011
+ category: match.category,
71012
+ guidance,
71013
+ action,
71014
+ pattern: match.pattern,
71015
+ stepRange: match.stepRange
71016
+ };
71017
+ }
71018
+ function formatCourseCorrectionForInjection(correction) {
71019
+ return `${correction.alert}
71020
+ CATEGORY: ${correction.category}
71021
+ GUIDANCE: ${correction.guidance}
71022
+ ACTION: ${correction.action}`;
71023
+ }
71024
+ // src/prm/escalation.ts
71025
+ init_telemetry();
71026
+ function createDefaultEscalationState() {
71027
+ return {
71028
+ patternCounts: new Map,
71029
+ escalationLevel: 0,
71030
+ lastPatternDetected: null,
71031
+ hardStopPending: false,
71032
+ correctionsPending: []
71033
+ };
71034
+ }
71035
+ function generateCorrection(match, level) {
71036
+ const levelPrefix = level === 1 ? "GUIDANCE" : level === 2 ? "STRONG GUIDANCE" : "HARD STOP";
71037
+ const alertTemplates = {
71038
+ repetition_loop: `${levelPrefix}: Repetitive action loop detected`,
71039
+ ping_pong: `${levelPrefix}: Delegation ping-pong detected`,
71040
+ expansion_drift: `${levelPrefix}: Scope expansion drift detected`,
71041
+ stuck_on_test: `${levelPrefix}: Stuck in edit-test cycle`,
71042
+ context_thrash: `${levelPrefix}: Excessive context requests detected`
71043
+ };
71044
+ const guidanceTemplates = {
71045
+ repetition_loop: "Stop the repetitive loop. Consolidate changes and take a different approach.",
71046
+ ping_pong: "Interrupt the delegation cycle. Architect should take direct control.",
71047
+ expansion_drift: "Freeze scope expansion. Complete current task before adding more work.",
71048
+ stuck_on_test: "Pause edit-test cycle. Review test expectations and verify environment.",
71049
+ context_thrash: "Restrict file access. Use targeted selection instead of broad context requests."
71050
+ };
71051
+ const actionTemplates = {
71052
+ repetition_loop: "Consolidate changes and change approach immediately.",
71053
+ ping_pong: "Architect take direct control or redefine agent task boundaries.",
71054
+ expansion_drift: "Document progress and create follow-up issue for additional work.",
71055
+ stuck_on_test: "Review test expectations, verify environment, consult SME if needed.",
71056
+ context_thrash: "Restrict to only the specific files needed for the current task."
71057
+ };
71058
+ return {
71059
+ alert: alertTemplates[match.pattern],
71060
+ category: match.category,
71061
+ guidance: guidanceTemplates[match.pattern],
71062
+ action: actionTemplates[match.pattern],
71063
+ pattern: match.pattern,
71064
+ stepRange: match.stepRange
71065
+ };
71066
+ }
71067
+
71068
+ class EscalationTracker {
71069
+ _sessionId;
71070
+ _state;
71071
+ constructor(sessionId, initialState) {
71072
+ this._sessionId = sessionId;
71073
+ this._state = initialState ?? createDefaultEscalationState();
71074
+ }
71075
+ recordDetection(match) {
71076
+ const currentCount = this._state.patternCounts.get(match.pattern) ?? 0;
71077
+ const newCount = currentCount + 1;
71078
+ this._state.patternCounts.set(match.pattern, newCount);
71079
+ this._state.lastPatternDetected = match;
71080
+ if (newCount === 1) {
71081
+ const correction = generateCorrection(match, 1);
71082
+ this._state.correctionsPending.push(correction);
71083
+ this._state.escalationLevel = 1;
71084
+ return {
71085
+ level: 1,
71086
+ correction,
71087
+ hardStop: false
71088
+ };
71089
+ } else if (newCount === 2) {
71090
+ const correction = generateCorrection(match, 2);
71091
+ this._state.correctionsPending.push(correction);
71092
+ this._state.escalationLevel = 2;
71093
+ telemetry.prmEscalationTriggered(this._sessionId, match.pattern, 2, newCount);
71094
+ return {
71095
+ level: 2,
71096
+ correction,
71097
+ hardStop: false
71098
+ };
71099
+ } else {
71100
+ const correction = generateCorrection(match, 3);
71101
+ this._state.correctionsPending.push(correction);
71102
+ this._state.escalationLevel = 3;
71103
+ this._state.hardStopPending = true;
71104
+ telemetry.prmHardStop(this._sessionId, match.pattern, 3, newCount);
71105
+ return {
71106
+ level: 3,
71107
+ correction,
71108
+ hardStop: true
71109
+ };
71110
+ }
71111
+ }
71112
+ getState() {
71113
+ return this._state;
71114
+ }
71115
+ reset() {
71116
+ this._state = createDefaultEscalationState();
71117
+ }
71118
+ getPendingCorrections() {
71119
+ return this._state.correctionsPending;
71120
+ }
71121
+ clearPendingCorrections() {
71122
+ this._state.correctionsPending = [];
71123
+ }
71124
+ isHardStopPending() {
71125
+ return this._state.hardStopPending;
71126
+ }
71127
+ }
71128
+ // src/prm/pattern-detector.ts
71129
+ var MAX_SANITIZED_LENGTH = 200;
71130
+ var INJECTION_PATTERNS2 = [
71131
+ /\[SYSTEM\]/gi,
71132
+ /SYSTEM\s*OVERRIDE/gi,
71133
+ /IGNORE\s*PREVIOUS/gi,
71134
+ /IGNORE\s*ALL/gi,
71135
+ /NEW\s*INSTRUCTION/gi,
71136
+ /Override\s*instructions/gi,
71137
+ /\bJAILBREAK/gi,
71138
+ /\bDAN\s*MODE/gi,
71139
+ /\bBYPASS/gi
71140
+ ];
71141
+ function sanitizeString2(input) {
71142
+ if (!input || typeof input !== "string") {
71143
+ return "";
71144
+ }
71145
+ let result = input;
71146
+ result = result.replace(/[\n\r]/g, "");
71147
+ result = result.replace(/`/g, "");
71148
+ for (const pattern of INJECTION_PATTERNS2) {
71149
+ result = result.replace(pattern, "[REDACTED]");
71150
+ }
71151
+ result = result.trim();
71152
+ if (result.length > MAX_SANITIZED_LENGTH) {
71153
+ result = `${result.slice(0, MAX_SANITIZED_LENGTH - 3)}...`;
71154
+ }
71155
+ return result;
71156
+ }
71157
+ var DEFAULT_THRESHOLDS = {
71158
+ repetition_loop: 2,
71159
+ ping_pong: 2,
71160
+ expansion_drift: 3,
71161
+ stuck_on_test: 3,
71162
+ context_thrash: 3
71163
+ };
71164
+ function detectRepetitionLoop(trajectory, config3) {
71165
+ const matches = [];
71166
+ if (trajectory.length < 2) {
71167
+ return matches;
71168
+ }
71169
+ const windowSize = 10;
71170
+ const threshold = config3.pattern_thresholds?.repetition_loop ?? DEFAULT_THRESHOLDS.repetition_loop;
71171
+ for (let i2 = 0;i2 < trajectory.length; i2++) {
71172
+ const windowStart = Math.max(0, i2 - windowSize + 1);
71173
+ const window2 = trajectory.slice(windowStart, i2 + 1);
71174
+ const counts = new Map;
71175
+ for (const entry of window2) {
71176
+ const key = `${entry.agent}|${entry.action}|${entry.target}`;
71177
+ const existing = counts.get(key);
71178
+ if (existing) {
71179
+ existing.count++;
71180
+ existing.endStep = entry.step;
71181
+ } else {
71182
+ counts.set(key, {
71183
+ count: 1,
71184
+ startStep: entry.step,
71185
+ endStep: entry.step
71186
+ });
71187
+ }
71188
+ }
71189
+ for (const [key, data] of counts) {
71190
+ if (data.count >= threshold) {
71191
+ const [agent, action, target] = key.split("|");
71192
+ const severity = data.count >= 3 ? "high" : "medium";
71193
+ matches.push({
71194
+ pattern: "repetition_loop",
71195
+ severity,
71196
+ category: "coordination_error",
71197
+ stepRange: [data.startStep, data.endStep],
71198
+ description: `Agent "${sanitizeString2(agent)}" performed "${sanitizeString2(action)}" on "${sanitizeString2(target)}" ${data.count} times within ${windowSize} steps`,
71199
+ affectedAgents: [sanitizeString2(agent)],
71200
+ affectedTargets: [sanitizeString2(target)],
71201
+ occurrenceCount: data.count
71202
+ });
71203
+ }
71204
+ }
71205
+ }
71206
+ return matches;
71207
+ }
71208
+ function detectPingPong(trajectory, config3) {
71209
+ const matches = [];
71210
+ const threshold = config3.pattern_thresholds?.ping_pong ?? DEFAULT_THRESHOLDS.ping_pong;
71211
+ const minThreshold = 3;
71212
+ const effectiveThreshold = Math.max(threshold, minThreshold);
71213
+ const delegateEntries = trajectory.filter((e) => e.action === "delegate");
71214
+ if (delegateEntries.length < effectiveThreshold) {
71215
+ return matches;
71216
+ }
71217
+ const detectedPairs = new Set;
71218
+ let i2 = 0;
71219
+ while (i2 < delegateEntries.length) {
71220
+ if (i2 + 1 >= delegateEntries.length)
71221
+ break;
71222
+ const firstAgent = delegateEntries[i2].agent;
71223
+ const secondAgent = delegateEntries[i2 + 1].agent;
71224
+ const target = delegateEntries[i2].target;
71225
+ if (firstAgent === secondAgent) {
71226
+ i2++;
71227
+ continue;
71228
+ }
71229
+ let endIndex = i2 + 1;
71230
+ for (let j = i2 + 2;j < delegateEntries.length; j++) {
71231
+ const expectedAgent = (j - i2) % 2 === 0 ? firstAgent : secondAgent;
71232
+ if (delegateEntries[j].agent !== expectedAgent || delegateEntries[j].target !== target) {
71233
+ break;
71234
+ }
71235
+ endIndex = j;
71236
+ }
71237
+ const patternLength = endIndex - i2 + 1;
71238
+ if (patternLength >= effectiveThreshold) {
71239
+ const pairKey = `${[firstAgent, secondAgent].sort().join(",")}-${target}`;
71240
+ if (!detectedPairs.has(pairKey)) {
71241
+ detectedPairs.add(pairKey);
71242
+ const roundTrips = Math.floor(patternLength / 2);
71243
+ matches.push({
71244
+ pattern: "ping_pong",
71245
+ severity: "high",
71246
+ category: "coordination_error",
71247
+ stepRange: [delegateEntries[i2].step, delegateEntries[endIndex].step],
71248
+ description: `Ping-pong delegation detected: "${sanitizeString2(firstAgent)}" and "${sanitizeString2(secondAgent)}" alternating on "${sanitizeString2(target)}"`,
71249
+ affectedAgents: [
71250
+ sanitizeString2(firstAgent),
71251
+ sanitizeString2(secondAgent)
71252
+ ],
71253
+ affectedTargets: [sanitizeString2(target)],
71254
+ occurrenceCount: roundTrips
71255
+ });
71256
+ }
71257
+ i2 = endIndex + 1;
71258
+ } else {
71259
+ i2++;
71260
+ }
71261
+ }
71262
+ return matches;
71263
+ }
71264
+ function detectExpansionDrift(trajectory, config3) {
71265
+ const matches = [];
71266
+ const threshold = config3.pattern_thresholds?.expansion_drift ?? DEFAULT_THRESHOLDS.expansion_drift;
71267
+ const windowSize = Math.max(threshold, 5);
71268
+ const minTrajectoryLength = windowSize * 2;
71269
+ if (trajectory.length < minTrajectoryLength) {
71270
+ return matches;
71271
+ }
71272
+ for (let i2 = windowSize * 2;i2 <= trajectory.length; i2 += windowSize) {
71273
+ const recentWindow = trajectory.slice(i2 - windowSize, i2);
71274
+ const previousWindow = trajectory.slice(i2 - windowSize * 2, i2 - windowSize);
71275
+ const recentTargets = new Set(recentWindow.map((e) => e.target));
71276
+ const previousTargets = new Set(previousWindow.map((e) => e.target));
71277
+ if (previousTargets.size > 0) {
71278
+ const expansionRatio = recentTargets.size / previousTargets.size;
71279
+ if (expansionRatio > 1.5) {
71280
+ matches.push({
71281
+ pattern: "expansion_drift",
71282
+ severity: "medium",
71283
+ category: "specification_error",
71284
+ stepRange: [
71285
+ previousWindow[0].step,
71286
+ recentWindow[recentWindow.length - 1].step
71287
+ ],
71288
+ description: `Scope expansion detected: ${previousTargets.size} unique targets \u2192 ${recentTargets.size} unique targets (${expansionRatio.toFixed(1)}x increase)`,
71289
+ affectedAgents: [
71290
+ ...new Set(recentWindow.map((e) => sanitizeString2(e.agent)))
71291
+ ],
71292
+ affectedTargets: [...recentTargets].map((t) => sanitizeString2(t)),
71293
+ occurrenceCount: Math.floor(expansionRatio * 10) / 10
71294
+ });
71295
+ }
71296
+ }
71297
+ }
71298
+ return matches;
71299
+ }
71300
+ function detectStuckOnTest(trajectory, config3) {
71301
+ const matches = [];
71302
+ if (trajectory.length < 3) {
71303
+ return matches;
71304
+ }
71305
+ const threshold = config3.pattern_thresholds?.stuck_on_test ?? DEFAULT_THRESHOLDS.stuck_on_test;
71306
+ const fileCycles = new Map;
71307
+ for (let i2 = 0;i2 < trajectory.length; i2++) {
71308
+ const entry = trajectory[i2];
71309
+ if (entry.action === "edit") {
71310
+ const existing = fileCycles.get(entry.target);
71311
+ if (existing) {
71312
+ existing.edits++;
71313
+ existing.steps.push(entry.step);
71314
+ if (!existing.agents.includes(entry.agent)) {
71315
+ existing.agents.push(entry.agent);
71316
+ }
71317
+ } else {
71318
+ fileCycles.set(entry.target, {
71319
+ edits: 1,
71320
+ tests: 0,
71321
+ steps: [entry.step],
71322
+ agents: [entry.agent]
71323
+ });
71324
+ }
71325
+ } else if (entry.action === "test") {
71326
+ const existing = fileCycles.get(entry.target);
71327
+ if (existing) {
71328
+ existing.tests++;
71329
+ }
71330
+ }
71331
+ }
71332
+ for (const [file3, data] of fileCycles) {
71333
+ if (data.edits >= threshold && data.tests >= 1) {
71334
+ let cycleCount = 0;
71335
+ let lastEditStep = -1;
71336
+ let lastTestStep = -1;
71337
+ let cycleStart = -1;
71338
+ let cycleEnd = -1;
71339
+ for (let i2 = 0;i2 < trajectory.length; i2++) {
71340
+ const entry = trajectory[i2];
71341
+ if (entry.target === file3) {
71342
+ if (entry.action === "edit") {
71343
+ if (lastTestStep > lastEditStep && lastEditStep > 0) {
71344
+ cycleCount++;
71345
+ if (cycleStart === -1)
71346
+ cycleStart = lastEditStep;
71347
+ cycleEnd = entry.step;
71348
+ }
71349
+ lastEditStep = entry.step;
71350
+ } else if (entry.action === "test" && entry.result === "failure") {
71351
+ lastTestStep = entry.step;
71352
+ }
71353
+ }
71354
+ }
71355
+ if (cycleCount >= threshold) {
71356
+ matches.push({
71357
+ pattern: "stuck_on_test",
71358
+ severity: "high",
71359
+ category: "reasoning_error",
71360
+ stepRange: [cycleStart, cycleEnd],
71361
+ description: `Stuck on test detected: ${cycleCount} edit-test cycles on "${sanitizeString2(file3)}"`,
71362
+ affectedAgents: data.agents.map((a) => sanitizeString2(a)),
71363
+ affectedTargets: [sanitizeString2(file3)],
71364
+ occurrenceCount: cycleCount
71365
+ });
71366
+ }
71367
+ }
71368
+ }
71369
+ return matches;
71370
+ }
71371
+ function detectContextThrash(trajectory, config3) {
71372
+ const matches = [];
71373
+ if (trajectory.length < 2) {
71374
+ return matches;
71375
+ }
71376
+ const threshold = config3.pattern_thresholds?.context_thrash ?? DEFAULT_THRESHOLDS.context_thrash;
71377
+ const seenTargets = new Set;
71378
+ const cumulativeCounts = [];
71379
+ for (const entry of trajectory) {
71380
+ seenTargets.add(entry.target);
71381
+ cumulativeCounts.push(seenTargets.size);
71382
+ }
71383
+ let runStart = 0;
71384
+ let runLength = 1;
71385
+ for (let i2 = 1;i2 <= cumulativeCounts.length; i2++) {
71386
+ const extending = i2 < cumulativeCounts.length && cumulativeCounts[i2] > cumulativeCounts[i2 - 1];
71387
+ if (extending) {
71388
+ runLength++;
71389
+ } else {
71390
+ if (runLength >= threshold) {
71391
+ const runEnd = i2 - 1;
71392
+ const priorCount = runStart > 0 ? cumulativeCounts[runStart - 1] : 0;
71393
+ const finalCount = cumulativeCounts[runEnd];
71394
+ matches.push({
71395
+ pattern: "context_thrash",
71396
+ severity: "medium",
71397
+ category: "coordination_error",
71398
+ stepRange: [trajectory[runStart].step, trajectory[runEnd].step],
71399
+ description: `Context thrash detected: unique targets grew monotonically from ${priorCount} to ${finalCount} over ${runLength} steps`,
71400
+ affectedAgents: [
71401
+ ...new Set(trajectory.slice(runStart, runEnd + 1).map((e) => sanitizeString2(e.agent)))
71402
+ ],
71403
+ affectedTargets: [
71404
+ ...new Set(trajectory.slice(runStart, runEnd + 1).map((e) => sanitizeString2(e.target)))
71405
+ ],
71406
+ occurrenceCount: runLength
71407
+ });
71408
+ }
71409
+ runStart = i2;
71410
+ runLength = 1;
71411
+ }
71412
+ }
71413
+ return matches;
71414
+ }
71415
+ function detectPatterns(trajectory, config3, lastProcessedStep = 0) {
71416
+ const startTime = Date.now();
71417
+ if (config3.enabled === false) {
71418
+ return {
71419
+ matches: [],
71420
+ detectionTimeMs: 0,
71421
+ patternsChecked: 5
71422
+ };
71423
+ }
71424
+ const allMatches = [];
71425
+ allMatches.push(...detectRepetitionLoop(trajectory, config3));
71426
+ allMatches.push(...detectPingPong(trajectory, config3));
71427
+ allMatches.push(...detectExpansionDrift(trajectory, config3));
71428
+ allMatches.push(...detectStuckOnTest(trajectory, config3));
71429
+ allMatches.push(...detectContextThrash(trajectory, config3));
71430
+ const detectionTimeMs = Date.now() - startTime;
71431
+ const severityRank = {
71432
+ critical: 4,
71433
+ high: 3,
71434
+ medium: 2,
71435
+ low: 1
71436
+ };
71437
+ const dedupedMatches = new Map;
71438
+ for (const match of allMatches) {
71439
+ const key = `${match.pattern}-${match.affectedAgents.join(",")}-${match.affectedTargets.join(",")}-${match.stepRange[0]}-${match.stepRange[1]}`;
71440
+ const existing = dedupedMatches.get(key);
71441
+ if (!existing) {
71442
+ dedupedMatches.set(key, match);
71443
+ } else {
71444
+ const existingRank = severityRank[existing.severity] ?? 0;
71445
+ const newRank = severityRank[match.severity] ?? 0;
71446
+ if (newRank > existingRank) {
71447
+ dedupedMatches.set(key, match);
71448
+ }
71449
+ }
71450
+ }
71451
+ const newMatches = Array.from(dedupedMatches.values()).filter((match) => match.stepRange[1] > lastProcessedStep);
71452
+ return {
71453
+ matches: newMatches,
71454
+ detectionTimeMs,
71455
+ patternsChecked: 5
71456
+ };
71457
+ }
71458
+
71459
+ // src/prm/index.ts
71460
+ init_state();
71461
+ init_telemetry();
71462
+
71463
+ // src/prm/replay.ts
71464
+ import { promises as fs53 } from "fs";
71465
+ import path67 from "path";
71466
+ function isPathSafe2(targetPath, basePath) {
71467
+ const resolvedTarget = path67.resolve(targetPath);
71468
+ const resolvedBase = path67.resolve(basePath);
71469
+ const rel = path67.relative(resolvedBase, resolvedTarget);
71470
+ return !rel.startsWith("..") && !path67.isAbsolute(rel);
71471
+ }
71472
+ function isWithinReplaysDir(targetPath) {
71473
+ const resolved = path67.resolve(targetPath);
71474
+ const parts2 = resolved.split(path67.sep);
71475
+ for (let i2 = 0;i2 < parts2.length - 1; i2++) {
71476
+ if (parts2[i2] === ".swarm" && parts2[i2 + 1] === "replays") {
71477
+ return true;
71478
+ }
71479
+ }
71480
+ return false;
71481
+ }
71482
+ function sanitizeFilename(input) {
71483
+ return input.replace(/[^a-zA-Z0-9_-]/g, "_");
71484
+ }
71485
+ async function startReplayRecording(sessionID, directory) {
71486
+ try {
71487
+ const replayDir = path67.join(directory, ".swarm", "replays");
71488
+ const safeSessionID = sanitizeFilename(sessionID);
71489
+ const filename = `${safeSessionID}-${Date.now()}.jsonl`;
71490
+ const filepath = path67.join(replayDir, filename);
71491
+ if (!isPathSafe2(filepath, replayDir)) {
71492
+ console.warn(`[replay] Invalid path detected - path traversal attempt blocked for session ${sessionID}`);
71493
+ return null;
71494
+ }
71495
+ await fs53.mkdir(replayDir, { recursive: true });
71496
+ return filepath;
71497
+ } catch (err2) {
71498
+ console.warn(`[replay] Failed to start recording for session ${sessionID}: ${err2}`);
71499
+ return null;
71500
+ }
71501
+ }
71502
+ async function recordReplayEntry(artifactPath, sessionID, entry) {
71503
+ try {
71504
+ if (!isWithinReplaysDir(artifactPath)) {
71505
+ console.warn(`[replay] Invalid artifact path - not within .swarm/replays/: ${artifactPath}`);
71506
+ return;
71507
+ }
71508
+ const fullEntry = {
71509
+ timestamp: new Date().toISOString(),
71510
+ sessionID,
71511
+ ...entry
71512
+ };
71513
+ const line = `${JSON.stringify(fullEntry)}
71514
+ `;
71515
+ await fs53.appendFile(artifactPath, line, "utf-8");
71516
+ } catch (err2) {
71517
+ console.warn(`[replay] Failed to record entry: ${err2}`);
71518
+ }
71519
+ }
71520
+
71521
+ // src/prm/index.ts
71522
+ function createPrmHook(config3, directory) {
71523
+ async function toolAfter(context) {
71524
+ if (!config3.enabled) {
71525
+ return;
71526
+ }
71527
+ const { sessionID } = context;
71528
+ const session = getAgentSession(sessionID);
71529
+ if (!session || !session.delegationActive) {
71530
+ return;
71531
+ }
71532
+ try {
71533
+ const cachedTrajectory = getInMemoryTrajectory(sessionID);
71534
+ const trajectory = cachedTrajectory.length > 0 ? cachedTrajectory : await readTrajectory(sessionID, directory);
71535
+ const detectionResult = detectPatterns(trajectory, config3, session.prmTrajectoryStep);
71536
+ if (detectionResult.matches.length === 0) {
71537
+ return;
71538
+ }
71539
+ const sessionPrmState = session;
71540
+ let escalationTracker = sessionPrmState.prmEscalationTracker;
71541
+ if (!sessionPrmState.replayArtifactPath) {
71542
+ sessionPrmState.replayArtifactPath = await startReplayRecording(sessionID, directory);
71543
+ }
71544
+ const artifactPath = sessionPrmState.replayArtifactPath;
71545
+ if (!sessionPrmState.prmInitialized) {
71546
+ sessionPrmState.prmInitialized = true;
71547
+ cleanupOldTrajectoryFiles(directory).catch(() => {});
71548
+ }
71549
+ if (!escalationTracker) {
71550
+ const initialState = session.prmLastPatternDetected ? {
71551
+ patternCounts: new Map(session.prmPatternCounts.entries()),
71552
+ escalationLevel: session.prmEscalationLevel,
71553
+ lastPatternDetected: session.prmLastPatternDetected,
71554
+ hardStopPending: session.prmHardStopPending,
71555
+ correctionsPending: []
71556
+ } : undefined;
71557
+ escalationTracker = new EscalationTracker(sessionID, initialState);
71558
+ sessionPrmState.prmEscalationTracker = escalationTracker;
71559
+ }
71560
+ const previousEscalationLevel = session.prmEscalationLevel;
71561
+ for (const match of detectionResult.matches) {
71562
+ const correction = generateCourseCorrection(match, trajectory);
71563
+ const formattedCorrection = formatCourseCorrectionForInjection(correction);
71564
+ if (!session.pendingAdvisoryMessages) {
71565
+ session.pendingAdvisoryMessages = [];
71566
+ }
71567
+ session.pendingAdvisoryMessages.push(formattedCorrection);
71568
+ let escalationLevel = 0;
71569
+ let hardStopPending = false;
71570
+ if (config3.escalation_enabled !== false) {
71571
+ const escalationResult = escalationTracker.recordDetection(match);
71572
+ escalationLevel = escalationResult.level;
71573
+ hardStopPending = escalationResult.hardStop;
71574
+ }
71575
+ escalationTracker.clearPendingCorrections();
71576
+ session.prmPatternCounts.set(match.pattern, (session.prmPatternCounts.get(match.pattern) ?? 0) + 1);
71577
+ session.prmEscalationLevel = escalationLevel;
71578
+ session.prmLastPatternDetected = match;
71579
+ session.prmHardStopPending = hardStopPending;
71580
+ telemetry.prmPatternDetected(sessionID, match.pattern, match.severity, match.category, match.stepRange);
71581
+ telemetry.prmCourseCorrectionInjected(sessionID, match.pattern, escalationLevel);
71582
+ if (artifactPath) {
71583
+ await recordReplayEntry(artifactPath, sessionID, {
71584
+ type: "pattern_detected",
71585
+ data: {
71586
+ pattern: match.pattern,
71587
+ severity: match.severity,
71588
+ category: match.category,
71589
+ stepRange: match.stepRange,
71590
+ description: match.description,
71591
+ affectedAgents: match.affectedAgents,
71592
+ affectedTargets: match.affectedTargets,
71593
+ occurrenceCount: match.occurrenceCount
71594
+ }
71595
+ });
71596
+ }
71597
+ if (artifactPath) {
71598
+ await recordReplayEntry(artifactPath, sessionID, {
71599
+ type: "course_correction",
71600
+ data: {
71601
+ pattern: correction.pattern,
71602
+ alert: correction.alert,
71603
+ category: correction.category,
71604
+ guidance: correction.guidance,
71605
+ action: correction.action,
71606
+ stepRange: correction.stepRange,
71607
+ escalationLevel
71608
+ }
71609
+ });
71610
+ }
71611
+ }
71612
+ if (artifactPath && session.prmEscalationLevel > previousEscalationLevel) {
71613
+ await recordReplayEntry(artifactPath, sessionID, {
71614
+ type: "escalation",
71615
+ data: {
71616
+ previousLevel: previousEscalationLevel,
71617
+ newLevel: session.prmEscalationLevel,
71618
+ hardStopPending: session.prmHardStopPending
71619
+ }
71620
+ });
71621
+ }
71622
+ if (artifactPath && session.prmHardStopPending && previousEscalationLevel < 3) {
71623
+ await recordReplayEntry(artifactPath, sessionID, {
71624
+ type: "hard_stop",
71625
+ data: {
71626
+ escalationLevel: session.prmEscalationLevel,
71627
+ triggeredAt: new Date().toISOString()
71628
+ }
71629
+ });
71630
+ }
71631
+ if (trajectory.length > 0) {
71632
+ session.prmTrajectoryStep = trajectory[trajectory.length - 1].step;
71633
+ }
71634
+ } catch (err2) {
71635
+ console.warn(`[prm] toolAfter error for session ${sessionID}: ${err2}`);
71636
+ }
71637
+ }
71638
+ return { toolAfter };
71639
+ }
71640
+
70543
71641
  // src/index.ts
70544
71642
  init_compaction_service();
70545
71643
  init_config_doctor();
@@ -70643,6 +71741,11 @@ function deserializeAgentSession(s) {
70643
71741
  fullAutoInteractionCount: s.fullAutoInteractionCount ?? 0,
70644
71742
  fullAutoDeadlockCount: s.fullAutoDeadlockCount ?? 0,
70645
71743
  fullAutoLastQuestionHash: s.fullAutoLastQuestionHash ?? null,
71744
+ prmPatternCounts: new Map,
71745
+ prmEscalationLevel: 0,
71746
+ prmLastPatternDetected: null,
71747
+ prmTrajectoryStep: 0,
71748
+ prmHardStopPending: false,
70646
71749
  sessionRehydratedAt: s.sessionRehydratedAt ?? 0
70647
71750
  };
70648
71751
  }
@@ -70748,8 +71851,8 @@ init_telemetry();
70748
71851
  // src/tools/batch-symbols.ts
70749
71852
  init_tool();
70750
71853
  init_create_tool();
70751
- import * as fs51 from "fs";
70752
- import * as path65 from "path";
71854
+ import * as fs54 from "fs";
71855
+ import * as path68 from "path";
70753
71856
  init_path_security();
70754
71857
  var WINDOWS_RESERVED_NAMES2 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
70755
71858
  function containsWindowsAttacks2(str) {
@@ -70766,14 +71869,14 @@ function containsWindowsAttacks2(str) {
70766
71869
  }
70767
71870
  function isPathInWorkspace2(filePath, workspace) {
70768
71871
  try {
70769
- const resolvedPath = path65.resolve(workspace, filePath);
70770
- if (!fs51.existsSync(resolvedPath)) {
71872
+ const resolvedPath = path68.resolve(workspace, filePath);
71873
+ if (!fs54.existsSync(resolvedPath)) {
70771
71874
  return true;
70772
71875
  }
70773
- const realWorkspace = fs51.realpathSync(workspace);
70774
- const realResolvedPath = fs51.realpathSync(resolvedPath);
70775
- const relativePath = path65.relative(realWorkspace, realResolvedPath);
70776
- if (relativePath.startsWith("..") || path65.isAbsolute(relativePath)) {
71876
+ const realWorkspace = fs54.realpathSync(workspace);
71877
+ const realResolvedPath = fs54.realpathSync(resolvedPath);
71878
+ const relativePath = path68.relative(realWorkspace, realResolvedPath);
71879
+ if (relativePath.startsWith("..") || path68.isAbsolute(relativePath)) {
70777
71880
  return false;
70778
71881
  }
70779
71882
  return true;
@@ -70782,7 +71885,7 @@ function isPathInWorkspace2(filePath, workspace) {
70782
71885
  }
70783
71886
  }
70784
71887
  function processFile2(file3, cwd, exportedOnly) {
70785
- const ext = path65.extname(file3);
71888
+ const ext = path68.extname(file3);
70786
71889
  if (containsControlChars(file3)) {
70787
71890
  return {
70788
71891
  file: file3,
@@ -70815,8 +71918,8 @@ function processFile2(file3, cwd, exportedOnly) {
70815
71918
  errorType: "path-outside-workspace"
70816
71919
  };
70817
71920
  }
70818
- const fullPath = path65.join(cwd, file3);
70819
- if (!fs51.existsSync(fullPath)) {
71921
+ const fullPath = path68.join(cwd, file3);
71922
+ if (!fs54.existsSync(fullPath)) {
70820
71923
  return {
70821
71924
  file: file3,
70822
71925
  success: false,
@@ -70847,14 +71950,14 @@ function processFile2(file3, cwd, exportedOnly) {
70847
71950
  }
70848
71951
  let isEmptyFile = false;
70849
71952
  try {
70850
- const stats = fs51.statSync(fullPath);
71953
+ const stats = fs54.statSync(fullPath);
70851
71954
  if (stats.size === 0) {
70852
71955
  isEmptyFile = true;
70853
71956
  }
70854
71957
  } catch {}
70855
71958
  if (syms.length === 0) {
70856
71959
  try {
70857
- const content = fs51.readFileSync(fullPath, "utf-8");
71960
+ const content = fs54.readFileSync(fullPath, "utf-8");
70858
71961
  if (content.trim().length === 0) {
70859
71962
  isEmptyFile = true;
70860
71963
  }
@@ -71106,25 +72209,25 @@ init_manager2();
71106
72209
  init_task_id();
71107
72210
  init_create_tool();
71108
72211
  init_resolve_working_directory();
71109
- import * as fs52 from "fs";
71110
- import * as path66 from "path";
72212
+ import * as fs55 from "fs";
72213
+ import * as path69 from "path";
71111
72214
  var EVIDENCE_DIR = ".swarm/evidence";
71112
72215
  function isValidTaskId3(taskId) {
71113
72216
  return isStrictTaskId(taskId);
71114
72217
  }
71115
72218
  function isPathWithinSwarm(filePath, workspaceRoot) {
71116
- const normalizedWorkspace = path66.resolve(workspaceRoot);
71117
- const swarmPath = path66.join(normalizedWorkspace, ".swarm", "evidence");
71118
- const normalizedPath = path66.resolve(filePath);
72219
+ const normalizedWorkspace = path69.resolve(workspaceRoot);
72220
+ const swarmPath = path69.join(normalizedWorkspace, ".swarm", "evidence");
72221
+ const normalizedPath = path69.resolve(filePath);
71119
72222
  return normalizedPath.startsWith(swarmPath);
71120
72223
  }
71121
72224
  function readEvidenceFile(evidencePath) {
71122
- if (!fs52.existsSync(evidencePath)) {
72225
+ if (!fs55.existsSync(evidencePath)) {
71123
72226
  return null;
71124
72227
  }
71125
72228
  let content;
71126
72229
  try {
71127
- content = fs52.readFileSync(evidencePath, "utf-8");
72230
+ content = fs55.readFileSync(evidencePath, "utf-8");
71128
72231
  } catch {
71129
72232
  return null;
71130
72233
  }
@@ -71196,7 +72299,7 @@ var check_gate_status = createSwarmTool({
71196
72299
  };
71197
72300
  return JSON.stringify(errorResult, null, 2);
71198
72301
  }
71199
- const evidencePath = path66.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
72302
+ const evidencePath = path69.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
71200
72303
  if (!isPathWithinSwarm(evidencePath, directory)) {
71201
72304
  const errorResult = {
71202
72305
  taskId: taskIdInput,
@@ -71292,8 +72395,8 @@ init_utils2();
71292
72395
  init_state();
71293
72396
  init_create_tool();
71294
72397
  init_resolve_working_directory();
71295
- import * as fs53 from "fs";
71296
- import * as path67 from "path";
72398
+ import * as fs56 from "fs";
72399
+ import * as path70 from "path";
71297
72400
  function extractMatches(regex, text) {
71298
72401
  return Array.from(text.matchAll(regex));
71299
72402
  }
@@ -71387,7 +72490,7 @@ async function executeCompletionVerify(args2, directory) {
71387
72490
  let plan;
71388
72491
  try {
71389
72492
  const planPath = validateSwarmPath(directory, "plan.json");
71390
- const planRaw = fs53.readFileSync(planPath, "utf-8");
72493
+ const planRaw = fs56.readFileSync(planPath, "utf-8");
71391
72494
  plan = JSON.parse(planRaw);
71392
72495
  } catch {
71393
72496
  const result2 = {
@@ -71445,10 +72548,10 @@ async function executeCompletionVerify(args2, directory) {
71445
72548
  let hasFileReadFailure = false;
71446
72549
  for (const filePath of fileTargets) {
71447
72550
  const normalizedPath = filePath.replace(/\\/g, "/");
71448
- const resolvedPath = path67.resolve(directory, normalizedPath);
71449
- const projectRoot = path67.resolve(directory);
71450
- const relative16 = path67.relative(projectRoot, resolvedPath);
71451
- const withinProject = relative16 === "" || !relative16.startsWith("..") && !path67.isAbsolute(relative16);
72551
+ const resolvedPath = path70.resolve(directory, normalizedPath);
72552
+ const projectRoot = path70.resolve(directory);
72553
+ const relative16 = path70.relative(projectRoot, resolvedPath);
72554
+ const withinProject = relative16 === "" || !relative16.startsWith("..") && !path70.isAbsolute(relative16);
71452
72555
  if (!withinProject) {
71453
72556
  blockedTasks.push({
71454
72557
  task_id: task.id,
@@ -71461,7 +72564,7 @@ async function executeCompletionVerify(args2, directory) {
71461
72564
  }
71462
72565
  let fileContent;
71463
72566
  try {
71464
- fileContent = fs53.readFileSync(resolvedPath, "utf-8");
72567
+ fileContent = fs56.readFileSync(resolvedPath, "utf-8");
71465
72568
  } catch {
71466
72569
  blockedTasks.push({
71467
72570
  task_id: task.id,
@@ -71503,9 +72606,9 @@ async function executeCompletionVerify(args2, directory) {
71503
72606
  blockedTasks
71504
72607
  };
71505
72608
  try {
71506
- const evidenceDir = path67.join(directory, ".swarm", "evidence", `${phase}`);
71507
- const evidencePath = path67.join(evidenceDir, "completion-verify.json");
71508
- fs53.mkdirSync(evidenceDir, { recursive: true });
72609
+ const evidenceDir = path70.join(directory, ".swarm", "evidence", `${phase}`);
72610
+ const evidencePath = path70.join(evidenceDir, "completion-verify.json");
72611
+ fs56.mkdirSync(evidenceDir, { recursive: true });
71509
72612
  const evidenceBundle = {
71510
72613
  schema_version: "1.0.0",
71511
72614
  task_id: "completion-verify",
@@ -71526,7 +72629,7 @@ async function executeCompletionVerify(args2, directory) {
71526
72629
  }
71527
72630
  ]
71528
72631
  };
71529
- fs53.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
72632
+ fs56.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
71530
72633
  } catch {}
71531
72634
  return JSON.stringify(result, null, 2);
71532
72635
  }
@@ -71580,12 +72683,12 @@ var completion_verify = createSwarmTool({
71580
72683
  });
71581
72684
  // src/tools/complexity-hotspots.ts
71582
72685
  init_dist();
71583
- import * as fs55 from "fs";
71584
- import * as path69 from "path";
72686
+ import * as fs58 from "fs";
72687
+ import * as path72 from "path";
71585
72688
 
71586
72689
  // src/quality/metrics.ts
71587
- import * as fs54 from "fs";
71588
- import * as path68 from "path";
72690
+ import * as fs57 from "fs";
72691
+ import * as path71 from "path";
71589
72692
  var MAX_FILE_SIZE_BYTES4 = 256 * 1024;
71590
72693
  var MIN_DUPLICATION_LINES = 10;
71591
72694
  function estimateCyclomaticComplexity(content) {
@@ -71623,11 +72726,11 @@ function estimateCyclomaticComplexity(content) {
71623
72726
  }
71624
72727
  function getComplexityForFile(filePath) {
71625
72728
  try {
71626
- const stat3 = fs54.statSync(filePath);
71627
- if (stat3.size > MAX_FILE_SIZE_BYTES4) {
72729
+ const stat4 = fs57.statSync(filePath);
72730
+ if (stat4.size > MAX_FILE_SIZE_BYTES4) {
71628
72731
  return null;
71629
72732
  }
71630
- const content = fs54.readFileSync(filePath, "utf-8");
72733
+ const content = fs57.readFileSync(filePath, "utf-8");
71631
72734
  return estimateCyclomaticComplexity(content);
71632
72735
  } catch {
71633
72736
  return null;
@@ -71637,8 +72740,8 @@ async function computeComplexityDelta(files, workingDir) {
71637
72740
  let totalComplexity = 0;
71638
72741
  const analyzedFiles = [];
71639
72742
  for (const file3 of files) {
71640
- const fullPath = path68.isAbsolute(file3) ? file3 : path68.join(workingDir, file3);
71641
- if (!fs54.existsSync(fullPath)) {
72743
+ const fullPath = path71.isAbsolute(file3) ? file3 : path71.join(workingDir, file3);
72744
+ if (!fs57.existsSync(fullPath)) {
71642
72745
  continue;
71643
72746
  }
71644
72747
  const complexity = getComplexityForFile(fullPath);
@@ -71759,8 +72862,8 @@ function countGoExports(content) {
71759
72862
  }
71760
72863
  function getExportCountForFile(filePath) {
71761
72864
  try {
71762
- const content = fs54.readFileSync(filePath, "utf-8");
71763
- const ext = path68.extname(filePath).toLowerCase();
72865
+ const content = fs57.readFileSync(filePath, "utf-8");
72866
+ const ext = path71.extname(filePath).toLowerCase();
71764
72867
  switch (ext) {
71765
72868
  case ".ts":
71766
72869
  case ".tsx":
@@ -71786,8 +72889,8 @@ async function computePublicApiDelta(files, workingDir) {
71786
72889
  let totalExports = 0;
71787
72890
  const analyzedFiles = [];
71788
72891
  for (const file3 of files) {
71789
- const fullPath = path68.isAbsolute(file3) ? file3 : path68.join(workingDir, file3);
71790
- if (!fs54.existsSync(fullPath)) {
72892
+ const fullPath = path71.isAbsolute(file3) ? file3 : path71.join(workingDir, file3);
72893
+ if (!fs57.existsSync(fullPath)) {
71791
72894
  continue;
71792
72895
  }
71793
72896
  const exports = getExportCountForFile(fullPath);
@@ -71820,16 +72923,16 @@ async function computeDuplicationRatio(files, workingDir) {
71820
72923
  let duplicateLines = 0;
71821
72924
  const analyzedFiles = [];
71822
72925
  for (const file3 of files) {
71823
- const fullPath = path68.isAbsolute(file3) ? file3 : path68.join(workingDir, file3);
71824
- if (!fs54.existsSync(fullPath)) {
72926
+ const fullPath = path71.isAbsolute(file3) ? file3 : path71.join(workingDir, file3);
72927
+ if (!fs57.existsSync(fullPath)) {
71825
72928
  continue;
71826
72929
  }
71827
72930
  try {
71828
- const stat3 = fs54.statSync(fullPath);
71829
- if (stat3.size > MAX_FILE_SIZE_BYTES4) {
72931
+ const stat4 = fs57.statSync(fullPath);
72932
+ if (stat4.size > MAX_FILE_SIZE_BYTES4) {
71830
72933
  continue;
71831
72934
  }
71832
- const content = fs54.readFileSync(fullPath, "utf-8");
72935
+ const content = fs57.readFileSync(fullPath, "utf-8");
71833
72936
  const lines = content.split(`
71834
72937
  `).filter((line) => line.trim().length > 0);
71835
72938
  if (lines.length < MIN_DUPLICATION_LINES) {
@@ -71853,8 +72956,8 @@ function countCodeLines(content) {
71853
72956
  return lines.length;
71854
72957
  }
71855
72958
  function isTestFile(filePath) {
71856
- const basename10 = path68.basename(filePath);
71857
- const _ext = path68.extname(filePath).toLowerCase();
72959
+ const basename10 = path71.basename(filePath);
72960
+ const _ext = path71.extname(filePath).toLowerCase();
71858
72961
  const testPatterns = [
71859
72962
  ".test.",
71860
72963
  ".spec.",
@@ -71935,8 +73038,8 @@ function matchGlobSegment(globSegments, pathSegments) {
71935
73038
  }
71936
73039
  return gIndex === globSegments.length && pIndex === pathSegments.length;
71937
73040
  }
71938
- function matchesGlobSegment(path69, glob) {
71939
- const normalizedPath = path69.replace(/\\/g, "/");
73041
+ function matchesGlobSegment(path72, glob) {
73042
+ const normalizedPath = path72.replace(/\\/g, "/");
71940
73043
  const normalizedGlob = glob.replace(/\\/g, "/");
71941
73044
  if (normalizedPath.includes("//")) {
71942
73045
  return false;
@@ -71967,8 +73070,8 @@ function simpleGlobToRegex2(glob) {
71967
73070
  function hasGlobstar(glob) {
71968
73071
  return glob.includes("**");
71969
73072
  }
71970
- function globMatches(path69, glob) {
71971
- const normalizedPath = path69.replace(/\\/g, "/");
73073
+ function globMatches(path72, glob) {
73074
+ const normalizedPath = path72.replace(/\\/g, "/");
71972
73075
  if (!glob || glob === "") {
71973
73076
  if (normalizedPath.includes("//")) {
71974
73077
  return false;
@@ -72004,31 +73107,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
72004
73107
  async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
72005
73108
  let testLines = 0;
72006
73109
  let codeLines = 0;
72007
- const srcDir = path68.join(workingDir, "src");
72008
- if (fs54.existsSync(srcDir)) {
73110
+ const srcDir = path71.join(workingDir, "src");
73111
+ if (fs57.existsSync(srcDir)) {
72009
73112
  await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
72010
73113
  codeLines += lines;
72011
73114
  });
72012
73115
  }
72013
73116
  const possibleSrcDirs = ["lib", "app", "source", "core"];
72014
73117
  for (const dir of possibleSrcDirs) {
72015
- const dirPath = path68.join(workingDir, dir);
72016
- if (fs54.existsSync(dirPath)) {
73118
+ const dirPath = path71.join(workingDir, dir);
73119
+ if (fs57.existsSync(dirPath)) {
72017
73120
  await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
72018
73121
  codeLines += lines;
72019
73122
  });
72020
73123
  }
72021
73124
  }
72022
- const testsDir = path68.join(workingDir, "tests");
72023
- if (fs54.existsSync(testsDir)) {
73125
+ const testsDir = path71.join(workingDir, "tests");
73126
+ if (fs57.existsSync(testsDir)) {
72024
73127
  await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
72025
73128
  testLines += lines;
72026
73129
  });
72027
73130
  }
72028
73131
  const possibleTestDirs = ["test", "__tests__", "specs"];
72029
73132
  for (const dir of possibleTestDirs) {
72030
- const dirPath = path68.join(workingDir, dir);
72031
- if (fs54.existsSync(dirPath) && dirPath !== testsDir) {
73133
+ const dirPath = path71.join(workingDir, dir);
73134
+ if (fs57.existsSync(dirPath) && dirPath !== testsDir) {
72032
73135
  await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
72033
73136
  testLines += lines;
72034
73137
  });
@@ -72040,9 +73143,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
72040
73143
  }
72041
73144
  async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
72042
73145
  try {
72043
- const entries = fs54.readdirSync(dirPath, { withFileTypes: true });
73146
+ const entries = fs57.readdirSync(dirPath, { withFileTypes: true });
72044
73147
  for (const entry of entries) {
72045
- const fullPath = path68.join(dirPath, entry.name);
73148
+ const fullPath = path71.join(dirPath, entry.name);
72046
73149
  if (entry.isDirectory()) {
72047
73150
  if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
72048
73151
  continue;
@@ -72050,7 +73153,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
72050
73153
  await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
72051
73154
  } else if (entry.isFile()) {
72052
73155
  const relativePath = fullPath.replace(`${dirPath}/`, "");
72053
- const ext = path68.extname(entry.name).toLowerCase();
73156
+ const ext = path71.extname(entry.name).toLowerCase();
72054
73157
  const validExts = [
72055
73158
  ".ts",
72056
73159
  ".tsx",
@@ -72086,7 +73189,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
72086
73189
  continue;
72087
73190
  }
72088
73191
  try {
72089
- const content = fs54.readFileSync(fullPath, "utf-8");
73192
+ const content = fs57.readFileSync(fullPath, "utf-8");
72090
73193
  const lines = countCodeLines(content);
72091
73194
  callback(lines);
72092
73195
  } catch {}
@@ -72288,11 +73391,11 @@ async function getGitChurn(days, directory) {
72288
73391
  }
72289
73392
  function getComplexityForFile2(filePath) {
72290
73393
  try {
72291
- const stat3 = fs55.statSync(filePath);
72292
- if (stat3.size > MAX_FILE_SIZE_BYTES5) {
73394
+ const stat4 = fs58.statSync(filePath);
73395
+ if (stat4.size > MAX_FILE_SIZE_BYTES5) {
72293
73396
  return null;
72294
73397
  }
72295
- const content = fs55.readFileSync(filePath, "utf-8");
73398
+ const content = fs58.readFileSync(filePath, "utf-8");
72296
73399
  return estimateCyclomaticComplexity(content);
72297
73400
  } catch {
72298
73401
  return null;
@@ -72303,7 +73406,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
72303
73406
  const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
72304
73407
  const filteredChurn = new Map;
72305
73408
  for (const [file3, count] of churnMap) {
72306
- const ext = path69.extname(file3).toLowerCase();
73409
+ const ext = path72.extname(file3).toLowerCase();
72307
73410
  if (extSet.has(ext)) {
72308
73411
  filteredChurn.set(file3, count);
72309
73412
  }
@@ -72313,8 +73416,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
72313
73416
  let analyzedFiles = 0;
72314
73417
  for (const [file3, churnCount] of filteredChurn) {
72315
73418
  let fullPath = file3;
72316
- if (!fs55.existsSync(fullPath)) {
72317
- fullPath = path69.join(cwd, file3);
73419
+ if (!fs58.existsSync(fullPath)) {
73420
+ fullPath = path72.join(cwd, file3);
72318
73421
  }
72319
73422
  const complexity = getComplexityForFile2(fullPath);
72320
73423
  if (complexity !== null) {
@@ -72489,7 +73592,7 @@ import {
72489
73592
  readFileSync as readFileSync37,
72490
73593
  writeFileSync as writeFileSync11
72491
73594
  } from "fs";
72492
- import { join as join63 } from "path";
73595
+ import { join as join65 } from "path";
72493
73596
  var EVIDENCE_DIR2 = ".swarm/evidence";
72494
73597
  var VALID_TASK_ID = /^\d+\.\d+(\.\d+)*$/;
72495
73598
  var COUNCIL_GATE_NAME = "council";
@@ -72523,9 +73626,9 @@ function writeCouncilEvidence(workingDir, synthesis) {
72523
73626
  if (!VALID_TASK_ID.test(synthesis.taskId)) {
72524
73627
  throw new Error(`writeCouncilEvidence: invalid taskId "${synthesis.taskId}" \u2014 must match N.M or N.M.P format`);
72525
73628
  }
72526
- const dir = join63(workingDir, EVIDENCE_DIR2);
73629
+ const dir = join65(workingDir, EVIDENCE_DIR2);
72527
73630
  mkdirSync18(dir, { recursive: true });
72528
- const filePath = join63(dir, `${synthesis.taskId}.json`);
73631
+ const filePath = join65(dir, `${synthesis.taskId}.json`);
72529
73632
  const existingRoot = Object.create(null);
72530
73633
  if (existsSync37(filePath)) {
72531
73634
  try {
@@ -72558,7 +73661,7 @@ function writeCouncilEvidence(workingDir, synthesis) {
72558
73661
  updated.required_gates = [];
72559
73662
  writeFileSync11(filePath, JSON.stringify(updated, null, 2));
72560
73663
  try {
72561
- const councilDir = join63(workingDir, ".swarm", "council");
73664
+ const councilDir = join65(workingDir, ".swarm", "council");
72562
73665
  mkdirSync18(councilDir, { recursive: true });
72563
73666
  const auditLine = JSON.stringify({
72564
73667
  round: synthesis.roundNumber,
@@ -72566,7 +73669,7 @@ function writeCouncilEvidence(workingDir, synthesis) {
72566
73669
  timestamp: synthesis.timestamp,
72567
73670
  vetoedBy: synthesis.vetoedBy
72568
73671
  });
72569
- appendFileSync7(join63(councilDir, `${synthesis.taskId}.rounds.jsonl`), `${auditLine}
73672
+ appendFileSync7(join65(councilDir, `${synthesis.taskId}.rounds.jsonl`), `${auditLine}
72570
73673
  `);
72571
73674
  } catch (auditError) {
72572
73675
  console.warn(`writeCouncilEvidence: failed to append round-history audit log: ${auditError instanceof Error ? auditError.message : String(auditError)}`);
@@ -72696,20 +73799,20 @@ function buildUnifiedFeedback(taskId, verdict, vetoedBy, requiredFixes, advisory
72696
73799
 
72697
73800
  // src/council/criteria-store.ts
72698
73801
  import { existsSync as existsSync38, mkdirSync as mkdirSync19, readFileSync as readFileSync38, writeFileSync as writeFileSync12 } from "fs";
72699
- import { join as join64 } from "path";
73802
+ import { join as join66 } from "path";
72700
73803
  var COUNCIL_DIR = ".swarm/council";
72701
73804
  function writeCriteria(workingDir, taskId, criteria) {
72702
- const dir = join64(workingDir, COUNCIL_DIR);
73805
+ const dir = join66(workingDir, COUNCIL_DIR);
72703
73806
  mkdirSync19(dir, { recursive: true });
72704
73807
  const payload = {
72705
73808
  taskId,
72706
73809
  criteria,
72707
73810
  declaredAt: new Date().toISOString()
72708
73811
  };
72709
- writeFileSync12(join64(dir, `${safeId(taskId)}.json`), JSON.stringify(payload, null, 2));
73812
+ writeFileSync12(join66(dir, `${safeId(taskId)}.json`), JSON.stringify(payload, null, 2));
72710
73813
  }
72711
73814
  function readCriteria(workingDir, taskId) {
72712
- const filePath = join64(workingDir, COUNCIL_DIR, `${safeId(taskId)}.json`);
73815
+ const filePath = join66(workingDir, COUNCIL_DIR, `${safeId(taskId)}.json`);
72713
73816
  if (!existsSync38(filePath))
72714
73817
  return null;
72715
73818
  try {
@@ -73046,8 +74149,8 @@ init_scope_persistence();
73046
74149
  init_state();
73047
74150
  init_task_id();
73048
74151
  init_create_tool();
73049
- import * as fs56 from "fs";
73050
- import * as path70 from "path";
74152
+ import * as fs59 from "fs";
74153
+ import * as path73 from "path";
73051
74154
  function validateTaskIdFormat2(taskId) {
73052
74155
  return validateTaskIdFormat(taskId);
73053
74156
  }
@@ -73121,8 +74224,8 @@ async function executeDeclareScope(args2, fallbackDir) {
73121
74224
  };
73122
74225
  }
73123
74226
  }
73124
- normalizedDir = path70.normalize(args2.working_directory);
73125
- const pathParts = normalizedDir.split(path70.sep);
74227
+ normalizedDir = path73.normalize(args2.working_directory);
74228
+ const pathParts = normalizedDir.split(path73.sep);
73126
74229
  if (pathParts.includes("..")) {
73127
74230
  return {
73128
74231
  success: false,
@@ -73132,11 +74235,11 @@ async function executeDeclareScope(args2, fallbackDir) {
73132
74235
  ]
73133
74236
  };
73134
74237
  }
73135
- const resolvedDir = path70.resolve(normalizedDir);
74238
+ const resolvedDir = path73.resolve(normalizedDir);
73136
74239
  try {
73137
- const realPath = fs56.realpathSync(resolvedDir);
73138
- const planPath2 = path70.join(realPath, ".swarm", "plan.json");
73139
- if (!fs56.existsSync(planPath2)) {
74240
+ const realPath = fs59.realpathSync(resolvedDir);
74241
+ const planPath2 = path73.join(realPath, ".swarm", "plan.json");
74242
+ if (!fs59.existsSync(planPath2)) {
73140
74243
  return {
73141
74244
  success: false,
73142
74245
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -73159,8 +74262,8 @@ async function executeDeclareScope(args2, fallbackDir) {
73159
74262
  console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
73160
74263
  }
73161
74264
  const directory = normalizedDir || fallbackDir;
73162
- const planPath = path70.resolve(directory, ".swarm", "plan.json");
73163
- if (!fs56.existsSync(planPath)) {
74265
+ const planPath = path73.resolve(directory, ".swarm", "plan.json");
74266
+ if (!fs59.existsSync(planPath)) {
73164
74267
  return {
73165
74268
  success: false,
73166
74269
  message: "No plan found",
@@ -73169,7 +74272,7 @@ async function executeDeclareScope(args2, fallbackDir) {
73169
74272
  }
73170
74273
  let planContent;
73171
74274
  try {
73172
- planContent = JSON.parse(fs56.readFileSync(planPath, "utf-8"));
74275
+ planContent = JSON.parse(fs59.readFileSync(planPath, "utf-8"));
73173
74276
  } catch {
73174
74277
  return {
73175
74278
  success: false,
@@ -73199,8 +74302,8 @@ async function executeDeclareScope(args2, fallbackDir) {
73199
74302
  const normalizeErrors = [];
73200
74303
  const dir = normalizedDir || fallbackDir || process.cwd();
73201
74304
  const mergedFiles = rawMergedFiles.map((file3) => {
73202
- if (path70.isAbsolute(file3)) {
73203
- const relativePath = path70.relative(dir, file3).replace(/\\/g, "/");
74305
+ if (path73.isAbsolute(file3)) {
74306
+ const relativePath = path73.relative(dir, file3).replace(/\\/g, "/");
73204
74307
  if (relativePath.startsWith("..")) {
73205
74308
  normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
73206
74309
  return file3;
@@ -73260,8 +74363,8 @@ var declare_scope = createSwarmTool({
73260
74363
  // src/tools/diff.ts
73261
74364
  init_dist();
73262
74365
  import * as child_process7 from "child_process";
73263
- import * as fs57 from "fs";
73264
- import * as path71 from "path";
74366
+ import * as fs60 from "fs";
74367
+ import * as path74 from "path";
73265
74368
  init_create_tool();
73266
74369
  var MAX_DIFF_LINES = 500;
73267
74370
  var DIFF_TIMEOUT_MS = 30000;
@@ -73290,20 +74393,20 @@ function validateBase(base) {
73290
74393
  function validatePaths(paths) {
73291
74394
  if (!paths)
73292
74395
  return null;
73293
- for (const path72 of paths) {
73294
- if (!path72 || path72.length === 0) {
74396
+ for (const path75 of paths) {
74397
+ if (!path75 || path75.length === 0) {
73295
74398
  return "empty path not allowed";
73296
74399
  }
73297
- if (path72.length > MAX_PATH_LENGTH) {
74400
+ if (path75.length > MAX_PATH_LENGTH) {
73298
74401
  return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
73299
74402
  }
73300
- if (SHELL_METACHARACTERS2.test(path72)) {
74403
+ if (SHELL_METACHARACTERS2.test(path75)) {
73301
74404
  return "path contains shell metacharacters";
73302
74405
  }
73303
- if (path72.startsWith("-")) {
74406
+ if (path75.startsWith("-")) {
73304
74407
  return 'path cannot start with "-" (option-like arguments not allowed)';
73305
74408
  }
73306
- if (CONTROL_CHAR_PATTERN2.test(path72)) {
74409
+ if (CONTROL_CHAR_PATTERN2.test(path75)) {
73307
74410
  return "path contains control characters";
73308
74411
  }
73309
74412
  }
@@ -73409,8 +74512,8 @@ var diff = createSwarmTool({
73409
74512
  if (parts2.length >= 3) {
73410
74513
  const additions = parseInt(parts2[0], 10) || 0;
73411
74514
  const deletions = parseInt(parts2[1], 10) || 0;
73412
- const path72 = parts2[2];
73413
- files.push({ path: path72, additions, deletions });
74515
+ const path75 = parts2[2];
74516
+ files.push({ path: path75, additions, deletions });
73414
74517
  }
73415
74518
  }
73416
74519
  const contractChanges = [];
@@ -73450,7 +74553,7 @@ var diff = createSwarmTool({
73450
74553
  } else if (base === "unstaged") {
73451
74554
  const oldRef = `:${file3.path}`;
73452
74555
  oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
73453
- newContent = fs57.readFileSync(path71.join(directory, file3.path), "utf-8");
74556
+ newContent = fs60.readFileSync(path74.join(directory, file3.path), "utf-8");
73454
74557
  } else {
73455
74558
  const oldRef = `${base}:${file3.path}`;
73456
74559
  oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
@@ -73524,8 +74627,8 @@ var diff = createSwarmTool({
73524
74627
  // src/tools/diff-summary.ts
73525
74628
  init_dist();
73526
74629
  import * as child_process8 from "child_process";
73527
- import * as fs58 from "fs";
73528
- import * as path72 from "path";
74630
+ import * as fs61 from "fs";
74631
+ import * as path75 from "path";
73529
74632
  init_create_tool();
73530
74633
  var diff_summary = createSwarmTool({
73531
74634
  description: "Generate a filtered semantic diff summary from AST analysis. Returns SemanticDiffSummary with optional filtering by classification or riskLevel.",
@@ -73573,7 +74676,7 @@ var diff_summary = createSwarmTool({
73573
74676
  }
73574
74677
  try {
73575
74678
  let oldContent;
73576
- const newContent = fs58.readFileSync(path72.join(workingDir, filePath), "utf-8");
74679
+ const newContent = fs61.readFileSync(path75.join(workingDir, filePath), "utf-8");
73577
74680
  if (fileExistsInHead) {
73578
74681
  oldContent = child_process8.execFileSync("git", ["show", `HEAD:${filePath}`], {
73579
74682
  encoding: "utf-8",
@@ -73800,8 +74903,8 @@ Use these as DOMAIN values when delegating to @sme.`;
73800
74903
  init_dist();
73801
74904
  init_create_tool();
73802
74905
  init_path_security();
73803
- import * as fs59 from "fs";
73804
- import * as path73 from "path";
74906
+ import * as fs62 from "fs";
74907
+ import * as path76 from "path";
73805
74908
  var MAX_FILE_SIZE_BYTES6 = 1024 * 1024;
73806
74909
  var MAX_EVIDENCE_FILES = 1000;
73807
74910
  var EVIDENCE_DIR3 = ".swarm/evidence";
@@ -73828,9 +74931,9 @@ function validateRequiredTypes(input) {
73828
74931
  return null;
73829
74932
  }
73830
74933
  function isPathWithinSwarm2(filePath, cwd) {
73831
- const normalizedCwd = path73.resolve(cwd);
73832
- const swarmPath = path73.join(normalizedCwd, ".swarm");
73833
- const normalizedPath = path73.resolve(filePath);
74934
+ const normalizedCwd = path76.resolve(cwd);
74935
+ const swarmPath = path76.join(normalizedCwd, ".swarm");
74936
+ const normalizedPath = path76.resolve(filePath);
73834
74937
  return normalizedPath.startsWith(swarmPath);
73835
74938
  }
73836
74939
  function parseCompletedTasks(planContent) {
@@ -73846,12 +74949,12 @@ function parseCompletedTasks(planContent) {
73846
74949
  }
73847
74950
  function readEvidenceFiles(evidenceDir, _cwd) {
73848
74951
  const evidence = [];
73849
- if (!fs59.existsSync(evidenceDir) || !fs59.statSync(evidenceDir).isDirectory()) {
74952
+ if (!fs62.existsSync(evidenceDir) || !fs62.statSync(evidenceDir).isDirectory()) {
73850
74953
  return evidence;
73851
74954
  }
73852
74955
  let files;
73853
74956
  try {
73854
- files = fs59.readdirSync(evidenceDir);
74957
+ files = fs62.readdirSync(evidenceDir);
73855
74958
  } catch {
73856
74959
  return evidence;
73857
74960
  }
@@ -73860,15 +74963,15 @@ function readEvidenceFiles(evidenceDir, _cwd) {
73860
74963
  if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
73861
74964
  continue;
73862
74965
  }
73863
- const filePath = path73.join(evidenceDir, filename);
74966
+ const filePath = path76.join(evidenceDir, filename);
73864
74967
  try {
73865
- const resolvedPath = path73.resolve(filePath);
73866
- const evidenceDirResolved = path73.resolve(evidenceDir);
74968
+ const resolvedPath = path76.resolve(filePath);
74969
+ const evidenceDirResolved = path76.resolve(evidenceDir);
73867
74970
  if (!resolvedPath.startsWith(evidenceDirResolved)) {
73868
74971
  continue;
73869
74972
  }
73870
- const stat3 = fs59.lstatSync(filePath);
73871
- if (!stat3.isFile()) {
74973
+ const stat4 = fs62.lstatSync(filePath);
74974
+ if (!stat4.isFile()) {
73872
74975
  continue;
73873
74976
  }
73874
74977
  } catch {
@@ -73876,7 +74979,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
73876
74979
  }
73877
74980
  let fileStat;
73878
74981
  try {
73879
- fileStat = fs59.statSync(filePath);
74982
+ fileStat = fs62.statSync(filePath);
73880
74983
  if (fileStat.size > MAX_FILE_SIZE_BYTES6) {
73881
74984
  continue;
73882
74985
  }
@@ -73885,7 +74988,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
73885
74988
  }
73886
74989
  let content;
73887
74990
  try {
73888
- content = fs59.readFileSync(filePath, "utf-8");
74991
+ content = fs62.readFileSync(filePath, "utf-8");
73889
74992
  } catch {
73890
74993
  continue;
73891
74994
  }
@@ -73981,7 +75084,7 @@ var evidence_check = createSwarmTool({
73981
75084
  return JSON.stringify(errorResult, null, 2);
73982
75085
  }
73983
75086
  const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
73984
- const planPath = path73.join(cwd, PLAN_FILE);
75087
+ const planPath = path76.join(cwd, PLAN_FILE);
73985
75088
  if (!isPathWithinSwarm2(planPath, cwd)) {
73986
75089
  const errorResult = {
73987
75090
  error: "plan file path validation failed",
@@ -73995,7 +75098,7 @@ var evidence_check = createSwarmTool({
73995
75098
  }
73996
75099
  let planContent;
73997
75100
  try {
73998
- planContent = fs59.readFileSync(planPath, "utf-8");
75101
+ planContent = fs62.readFileSync(planPath, "utf-8");
73999
75102
  } catch {
74000
75103
  const result2 = {
74001
75104
  message: "No completed tasks found in plan.",
@@ -74013,7 +75116,7 @@ var evidence_check = createSwarmTool({
74013
75116
  };
74014
75117
  return JSON.stringify(result2, null, 2);
74015
75118
  }
74016
- const evidenceDir = path73.join(cwd, EVIDENCE_DIR3);
75119
+ const evidenceDir = path76.join(cwd, EVIDENCE_DIR3);
74017
75120
  const evidence = readEvidenceFiles(evidenceDir, cwd);
74018
75121
  const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
74019
75122
  const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
@@ -74030,8 +75133,8 @@ var evidence_check = createSwarmTool({
74030
75133
  // src/tools/file-extractor.ts
74031
75134
  init_tool();
74032
75135
  init_create_tool();
74033
- import * as fs60 from "fs";
74034
- import * as path74 from "path";
75136
+ import * as fs63 from "fs";
75137
+ import * as path77 from "path";
74035
75138
  var EXT_MAP = {
74036
75139
  python: ".py",
74037
75140
  py: ".py",
@@ -74093,8 +75196,8 @@ var extract_code_blocks = createSwarmTool({
74093
75196
  execute: async (args2, directory) => {
74094
75197
  const { content, output_dir, prefix } = args2;
74095
75198
  const targetDir = output_dir || directory;
74096
- if (!fs60.existsSync(targetDir)) {
74097
- fs60.mkdirSync(targetDir, { recursive: true });
75199
+ if (!fs63.existsSync(targetDir)) {
75200
+ fs63.mkdirSync(targetDir, { recursive: true });
74098
75201
  }
74099
75202
  if (!content) {
74100
75203
  return "Error: content is required";
@@ -74112,16 +75215,16 @@ var extract_code_blocks = createSwarmTool({
74112
75215
  if (prefix) {
74113
75216
  filename = `${prefix}_${filename}`;
74114
75217
  }
74115
- let filepath = path74.join(targetDir, filename);
74116
- const base = path74.basename(filepath, path74.extname(filepath));
74117
- const ext = path74.extname(filepath);
75218
+ let filepath = path77.join(targetDir, filename);
75219
+ const base = path77.basename(filepath, path77.extname(filepath));
75220
+ const ext = path77.extname(filepath);
74118
75221
  let counter = 1;
74119
- while (fs60.existsSync(filepath)) {
74120
- filepath = path74.join(targetDir, `${base}_${counter}${ext}`);
75222
+ while (fs63.existsSync(filepath)) {
75223
+ filepath = path77.join(targetDir, `${base}_${counter}${ext}`);
74121
75224
  counter++;
74122
75225
  }
74123
75226
  try {
74124
- fs60.writeFileSync(filepath, code.trim(), "utf-8");
75227
+ fs63.writeFileSync(filepath, code.trim(), "utf-8");
74125
75228
  savedFiles.push(filepath);
74126
75229
  } catch (error93) {
74127
75230
  errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
@@ -74380,8 +75483,8 @@ var gitingest = createSwarmTool({
74380
75483
  init_dist();
74381
75484
  init_create_tool();
74382
75485
  init_path_security();
74383
- import * as fs61 from "fs";
74384
- import * as path75 from "path";
75486
+ import * as fs64 from "fs";
75487
+ import * as path78 from "path";
74385
75488
  var MAX_FILE_PATH_LENGTH2 = 500;
74386
75489
  var MAX_SYMBOL_LENGTH = 256;
74387
75490
  var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
@@ -74429,7 +75532,7 @@ function validateSymbolInput(symbol3) {
74429
75532
  return null;
74430
75533
  }
74431
75534
  function isBinaryFile2(filePath, buffer) {
74432
- const ext = path75.extname(filePath).toLowerCase();
75535
+ const ext = path78.extname(filePath).toLowerCase();
74433
75536
  if (ext === ".json" || ext === ".md" || ext === ".txt") {
74434
75537
  return false;
74435
75538
  }
@@ -74453,15 +75556,15 @@ function parseImports(content, targetFile, targetSymbol) {
74453
75556
  const imports = [];
74454
75557
  let _resolvedTarget;
74455
75558
  try {
74456
- _resolvedTarget = path75.resolve(targetFile);
75559
+ _resolvedTarget = path78.resolve(targetFile);
74457
75560
  } catch {
74458
75561
  _resolvedTarget = targetFile;
74459
75562
  }
74460
- const targetBasename = path75.basename(targetFile, path75.extname(targetFile));
75563
+ const targetBasename = path78.basename(targetFile, path78.extname(targetFile));
74461
75564
  const targetWithExt = targetFile;
74462
75565
  const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
74463
- const normalizedTargetWithExt = path75.normalize(targetWithExt).replace(/\\/g, "/");
74464
- const normalizedTargetWithoutExt = path75.normalize(targetWithoutExt).replace(/\\/g, "/");
75566
+ const normalizedTargetWithExt = path78.normalize(targetWithExt).replace(/\\/g, "/");
75567
+ const normalizedTargetWithoutExt = path78.normalize(targetWithoutExt).replace(/\\/g, "/");
74465
75568
  const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
74466
75569
  for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
74467
75570
  const modulePath = match[1] || match[2] || match[3];
@@ -74484,9 +75587,9 @@ function parseImports(content, targetFile, targetSymbol) {
74484
75587
  }
74485
75588
  const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
74486
75589
  let isMatch = false;
74487
- const _targetDir = path75.dirname(targetFile);
74488
- const targetExt = path75.extname(targetFile);
74489
- const targetBasenameNoExt = path75.basename(targetFile, targetExt);
75590
+ const _targetDir = path78.dirname(targetFile);
75591
+ const targetExt = path78.extname(targetFile);
75592
+ const targetBasenameNoExt = path78.basename(targetFile, targetExt);
74490
75593
  const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
74491
75594
  const moduleName = modulePath.split(/[/\\]/).pop() || "";
74492
75595
  const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
@@ -74543,7 +75646,7 @@ var SKIP_DIRECTORIES4 = new Set([
74543
75646
  function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
74544
75647
  let entries;
74545
75648
  try {
74546
- entries = fs61.readdirSync(dir);
75649
+ entries = fs64.readdirSync(dir);
74547
75650
  } catch (e) {
74548
75651
  stats.fileErrors.push({
74549
75652
  path: dir,
@@ -74554,13 +75657,13 @@ function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFil
74554
75657
  entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
74555
75658
  for (const entry of entries) {
74556
75659
  if (SKIP_DIRECTORIES4.has(entry)) {
74557
- stats.skippedDirs.push(path75.join(dir, entry));
75660
+ stats.skippedDirs.push(path78.join(dir, entry));
74558
75661
  continue;
74559
75662
  }
74560
- const fullPath = path75.join(dir, entry);
74561
- let stat3;
75663
+ const fullPath = path78.join(dir, entry);
75664
+ let stat4;
74562
75665
  try {
74563
- stat3 = fs61.statSync(fullPath);
75666
+ stat4 = fs64.statSync(fullPath);
74564
75667
  } catch (e) {
74565
75668
  stats.fileErrors.push({
74566
75669
  path: fullPath,
@@ -74568,10 +75671,10 @@ function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFil
74568
75671
  });
74569
75672
  continue;
74570
75673
  }
74571
- if (stat3.isDirectory()) {
75674
+ if (stat4.isDirectory()) {
74572
75675
  findSourceFiles3(fullPath, files, stats);
74573
- } else if (stat3.isFile()) {
74574
- const ext = path75.extname(fullPath).toLowerCase();
75676
+ } else if (stat4.isFile()) {
75677
+ const ext = path78.extname(fullPath).toLowerCase();
74575
75678
  if (SUPPORTED_EXTENSIONS3.includes(ext)) {
74576
75679
  files.push(fullPath);
74577
75680
  }
@@ -74628,8 +75731,8 @@ var imports = createSwarmTool({
74628
75731
  return JSON.stringify(errorResult, null, 2);
74629
75732
  }
74630
75733
  try {
74631
- const targetFile = path75.resolve(file3);
74632
- if (!fs61.existsSync(targetFile)) {
75734
+ const targetFile = path78.resolve(file3);
75735
+ if (!fs64.existsSync(targetFile)) {
74633
75736
  const errorResult = {
74634
75737
  error: `target file not found: ${file3}`,
74635
75738
  target: file3,
@@ -74639,7 +75742,7 @@ var imports = createSwarmTool({
74639
75742
  };
74640
75743
  return JSON.stringify(errorResult, null, 2);
74641
75744
  }
74642
- const targetStat = fs61.statSync(targetFile);
75745
+ const targetStat = fs64.statSync(targetFile);
74643
75746
  if (!targetStat.isFile()) {
74644
75747
  const errorResult = {
74645
75748
  error: "target must be a file, not a directory",
@@ -74650,7 +75753,7 @@ var imports = createSwarmTool({
74650
75753
  };
74651
75754
  return JSON.stringify(errorResult, null, 2);
74652
75755
  }
74653
- const baseDir = path75.dirname(targetFile);
75756
+ const baseDir = path78.dirname(targetFile);
74654
75757
  const scanStats = {
74655
75758
  skippedDirs: [],
74656
75759
  skippedFiles: 0,
@@ -74665,12 +75768,12 @@ var imports = createSwarmTool({
74665
75768
  if (consumers.length >= MAX_CONSUMERS)
74666
75769
  break;
74667
75770
  try {
74668
- const stat3 = fs61.statSync(filePath);
74669
- if (stat3.size > MAX_FILE_SIZE_BYTES7) {
75771
+ const stat4 = fs64.statSync(filePath);
75772
+ if (stat4.size > MAX_FILE_SIZE_BYTES7) {
74670
75773
  skippedFileCount++;
74671
75774
  continue;
74672
75775
  }
74673
- const buffer = fs61.readFileSync(filePath);
75776
+ const buffer = fs64.readFileSync(filePath);
74674
75777
  if (isBinaryFile2(filePath, buffer)) {
74675
75778
  skippedFileCount++;
74676
75779
  continue;
@@ -75182,8 +76285,8 @@ init_schema();
75182
76285
  init_qa_gate_profile();
75183
76286
  init_manager2();
75184
76287
  init_curator();
75185
- import * as fs62 from "fs";
75186
- import * as path76 from "path";
76288
+ import * as fs65 from "fs";
76289
+ import * as path79 from "path";
75187
76290
  init_knowledge_curator();
75188
76291
  init_knowledge_reader();
75189
76292
  init_knowledge_store();
@@ -75414,11 +76517,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75414
76517
  safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
75415
76518
  }
75416
76519
  try {
75417
- const driftEvidencePath = path76.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
76520
+ const driftEvidencePath = path79.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
75418
76521
  let driftVerdictFound = false;
75419
76522
  let driftVerdictApproved = false;
75420
76523
  try {
75421
- const driftEvidenceContent = fs62.readFileSync(driftEvidencePath, "utf-8");
76524
+ const driftEvidenceContent = fs65.readFileSync(driftEvidencePath, "utf-8");
75422
76525
  const driftEvidence = JSON.parse(driftEvidenceContent);
75423
76526
  const entries = driftEvidence.entries ?? [];
75424
76527
  for (const entry of entries) {
@@ -75448,14 +76551,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75448
76551
  driftVerdictFound = false;
75449
76552
  }
75450
76553
  if (!driftVerdictFound) {
75451
- const specPath = path76.join(dir, ".swarm", "spec.md");
75452
- const specExists = fs62.existsSync(specPath);
76554
+ const specPath = path79.join(dir, ".swarm", "spec.md");
76555
+ const specExists = fs65.existsSync(specPath);
75453
76556
  if (!specExists) {
75454
76557
  let incompleteTaskCount = 0;
75455
76558
  let planPhaseFound = false;
75456
76559
  try {
75457
76560
  const planPath = validateSwarmPath(dir, "plan.json");
75458
- const planRaw = fs62.readFileSync(planPath, "utf-8");
76561
+ const planRaw = fs65.readFileSync(planPath, "utf-8");
75459
76562
  const plan = JSON.parse(planRaw);
75460
76563
  const targetPhase = plan.phases.find((p) => p.id === phase);
75461
76564
  if (targetPhase) {
@@ -75506,11 +76609,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75506
76609
  const overrides = session2?.qaGateSessionOverrides ?? {};
75507
76610
  const effective = getEffectiveGates(profile, overrides);
75508
76611
  if (effective.hallucination_guard === true) {
75509
- const hgPath = path76.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
76612
+ const hgPath = path79.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
75510
76613
  let hgVerdictFound = false;
75511
76614
  let hgVerdictApproved = false;
75512
76615
  try {
75513
- const hgContent = fs62.readFileSync(hgPath, "utf-8");
76616
+ const hgContent = fs65.readFileSync(hgPath, "utf-8");
75514
76617
  const hgBundle = JSON.parse(hgContent);
75515
76618
  for (const entry of hgBundle.entries ?? []) {
75516
76619
  if (typeof entry.type === "string" && entry.type.includes("hallucination") && typeof entry.verdict === "string") {
@@ -75578,7 +76681,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75578
76681
  }
75579
76682
  if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
75580
76683
  try {
75581
- const projectName = path76.basename(dir);
76684
+ const projectName = path79.basename(dir);
75582
76685
  const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
75583
76686
  if (curationResult) {
75584
76687
  const sessionState = swarmState.agentSessions.get(sessionID);
@@ -75658,7 +76761,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75658
76761
  let phaseRequiredAgents;
75659
76762
  try {
75660
76763
  const planPath = validateSwarmPath(dir, "plan.json");
75661
- const planRaw = fs62.readFileSync(planPath, "utf-8");
76764
+ const planRaw = fs65.readFileSync(planPath, "utf-8");
75662
76765
  const plan = JSON.parse(planRaw);
75663
76766
  const phaseObj = plan.phases.find((p) => p.id === phase);
75664
76767
  phaseRequiredAgents = phaseObj?.required_agents;
@@ -75673,7 +76776,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75673
76776
  if (agentsMissing.length > 0) {
75674
76777
  try {
75675
76778
  const planPath = validateSwarmPath(dir, "plan.json");
75676
- const planRaw = fs62.readFileSync(planPath, "utf-8");
76779
+ const planRaw = fs65.readFileSync(planPath, "utf-8");
75677
76780
  const plan = JSON.parse(planRaw);
75678
76781
  const targetPhase = plan.phases.find((p) => p.id === phase);
75679
76782
  if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
@@ -75713,7 +76816,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75713
76816
  if (phaseCompleteConfig.regression_sweep?.enforce) {
75714
76817
  try {
75715
76818
  const planPath = validateSwarmPath(dir, "plan.json");
75716
- const planRaw = fs62.readFileSync(planPath, "utf-8");
76819
+ const planRaw = fs65.readFileSync(planPath, "utf-8");
75717
76820
  const plan = JSON.parse(planRaw);
75718
76821
  const targetPhase = plan.phases.find((p) => p.id === phase);
75719
76822
  if (targetPhase) {
@@ -75767,7 +76870,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75767
76870
  }
75768
76871
  try {
75769
76872
  const eventsPath = validateSwarmPath(dir, "events.jsonl");
75770
- fs62.appendFileSync(eventsPath, `${JSON.stringify(event)}
76873
+ fs65.appendFileSync(eventsPath, `${JSON.stringify(event)}
75771
76874
  `, "utf-8");
75772
76875
  } catch (writeError) {
75773
76876
  warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -75842,12 +76945,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75842
76945
  warnings.push(`Warning: failed to update plan.json phase status`);
75843
76946
  try {
75844
76947
  const planPath = validateSwarmPath(dir, "plan.json");
75845
- const planRaw = fs62.readFileSync(planPath, "utf-8");
76948
+ const planRaw = fs65.readFileSync(planPath, "utf-8");
75846
76949
  const plan2 = JSON.parse(planRaw);
75847
76950
  const phaseObj = plan2.phases.find((p) => p.id === phase);
75848
76951
  if (phaseObj) {
75849
76952
  phaseObj.status = "complete";
75850
- fs62.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
76953
+ fs65.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
75851
76954
  }
75852
76955
  } catch {}
75853
76956
  } else if (plan) {
@@ -75884,12 +76987,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75884
76987
  warnings.push(`Warning: failed to update plan.json phase status`);
75885
76988
  try {
75886
76989
  const planPath = validateSwarmPath(dir, "plan.json");
75887
- const planRaw = fs62.readFileSync(planPath, "utf-8");
76990
+ const planRaw = fs65.readFileSync(planPath, "utf-8");
75888
76991
  const plan = JSON.parse(planRaw);
75889
76992
  const phaseObj = plan.phases.find((p) => p.id === phase);
75890
76993
  if (phaseObj) {
75891
76994
  phaseObj.status = "complete";
75892
- fs62.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
76995
+ fs65.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
75893
76996
  }
75894
76997
  } catch {}
75895
76998
  }
@@ -75946,8 +77049,8 @@ init_dist();
75946
77049
  init_discovery();
75947
77050
  init_utils();
75948
77051
  init_create_tool();
75949
- import * as fs63 from "fs";
75950
- import * as path77 from "path";
77052
+ import * as fs66 from "fs";
77053
+ import * as path80 from "path";
75951
77054
  var MAX_OUTPUT_BYTES5 = 52428800;
75952
77055
  var AUDIT_TIMEOUT_MS = 120000;
75953
77056
  function isValidEcosystem(value) {
@@ -75975,31 +77078,31 @@ function validateArgs3(args2) {
75975
77078
  function detectEcosystems(directory) {
75976
77079
  const ecosystems = [];
75977
77080
  const cwd = directory;
75978
- if (fs63.existsSync(path77.join(cwd, "package.json"))) {
77081
+ if (fs66.existsSync(path80.join(cwd, "package.json"))) {
75979
77082
  ecosystems.push("npm");
75980
77083
  }
75981
- if (fs63.existsSync(path77.join(cwd, "pyproject.toml")) || fs63.existsSync(path77.join(cwd, "requirements.txt"))) {
77084
+ if (fs66.existsSync(path80.join(cwd, "pyproject.toml")) || fs66.existsSync(path80.join(cwd, "requirements.txt"))) {
75982
77085
  ecosystems.push("pip");
75983
77086
  }
75984
- if (fs63.existsSync(path77.join(cwd, "Cargo.toml"))) {
77087
+ if (fs66.existsSync(path80.join(cwd, "Cargo.toml"))) {
75985
77088
  ecosystems.push("cargo");
75986
77089
  }
75987
- if (fs63.existsSync(path77.join(cwd, "go.mod"))) {
77090
+ if (fs66.existsSync(path80.join(cwd, "go.mod"))) {
75988
77091
  ecosystems.push("go");
75989
77092
  }
75990
77093
  try {
75991
- const files = fs63.readdirSync(cwd);
77094
+ const files = fs66.readdirSync(cwd);
75992
77095
  if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
75993
77096
  ecosystems.push("dotnet");
75994
77097
  }
75995
77098
  } catch {}
75996
- if (fs63.existsSync(path77.join(cwd, "Gemfile")) || fs63.existsSync(path77.join(cwd, "Gemfile.lock"))) {
77099
+ if (fs66.existsSync(path80.join(cwd, "Gemfile")) || fs66.existsSync(path80.join(cwd, "Gemfile.lock"))) {
75997
77100
  ecosystems.push("ruby");
75998
77101
  }
75999
- if (fs63.existsSync(path77.join(cwd, "pubspec.yaml"))) {
77102
+ if (fs66.existsSync(path80.join(cwd, "pubspec.yaml"))) {
76000
77103
  ecosystems.push("dart");
76001
77104
  }
76002
- if (fs63.existsSync(path77.join(cwd, "composer.lock"))) {
77105
+ if (fs66.existsSync(path80.join(cwd, "composer.lock"))) {
76003
77106
  ecosystems.push("composer");
76004
77107
  }
76005
77108
  return ecosystems;
@@ -77158,8 +78261,8 @@ var pkg_audit = createSwarmTool({
77158
78261
  // src/tools/placeholder-scan.ts
77159
78262
  init_dist();
77160
78263
  init_manager2();
77161
- import * as fs64 from "fs";
77162
- import * as path78 from "path";
78264
+ import * as fs67 from "fs";
78265
+ import * as path81 from "path";
77163
78266
  init_utils();
77164
78267
  init_create_tool();
77165
78268
  var MAX_FILE_SIZE = 1024 * 1024;
@@ -77282,7 +78385,7 @@ function isScaffoldFile(filePath) {
77282
78385
  if (SCAFFOLD_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath))) {
77283
78386
  return true;
77284
78387
  }
77285
- const filename = path78.basename(filePath);
78388
+ const filename = path81.basename(filePath);
77286
78389
  if (SCAFFOLD_FILENAME_PATTERNS.some((pattern) => pattern.test(filename))) {
77287
78390
  return true;
77288
78391
  }
@@ -77299,7 +78402,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
77299
78402
  if (regex.test(normalizedPath)) {
77300
78403
  return true;
77301
78404
  }
77302
- const filename = path78.basename(filePath);
78405
+ const filename = path81.basename(filePath);
77303
78406
  const filenameRegex = new RegExp(`^${regexPattern}$`, "i");
77304
78407
  if (filenameRegex.test(filename)) {
77305
78408
  return true;
@@ -77308,7 +78411,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
77308
78411
  return false;
77309
78412
  }
77310
78413
  function isParserSupported(filePath) {
77311
- const ext = path78.extname(filePath).toLowerCase();
78414
+ const ext = path81.extname(filePath).toLowerCase();
77312
78415
  return SUPPORTED_PARSER_EXTENSIONS.has(ext);
77313
78416
  }
77314
78417
  function isPlanFile(filePath) {
@@ -77555,28 +78658,28 @@ async function placeholderScan(input, directory) {
77555
78658
  let filesScanned = 0;
77556
78659
  const filesWithFindings = new Set;
77557
78660
  for (const filePath of changed_files) {
77558
- const fullPath = path78.isAbsolute(filePath) ? filePath : path78.resolve(directory, filePath);
77559
- const resolvedDirectory = path78.resolve(directory);
77560
- if (!fullPath.startsWith(resolvedDirectory + path78.sep) && fullPath !== resolvedDirectory) {
78661
+ const fullPath = path81.isAbsolute(filePath) ? filePath : path81.resolve(directory, filePath);
78662
+ const resolvedDirectory = path81.resolve(directory);
78663
+ if (!fullPath.startsWith(resolvedDirectory + path81.sep) && fullPath !== resolvedDirectory) {
77561
78664
  continue;
77562
78665
  }
77563
- if (!fs64.existsSync(fullPath)) {
78666
+ if (!fs67.existsSync(fullPath)) {
77564
78667
  continue;
77565
78668
  }
77566
78669
  if (isAllowedByGlobs(filePath, allow_globs)) {
77567
78670
  continue;
77568
78671
  }
77569
- const relativeFilePath = path78.relative(directory, fullPath).replace(/\\/g, "/");
78672
+ const relativeFilePath = path81.relative(directory, fullPath).replace(/\\/g, "/");
77570
78673
  if (FILE_ALLOWLIST.some((allowed) => relativeFilePath.endsWith(allowed))) {
77571
78674
  continue;
77572
78675
  }
77573
78676
  let content;
77574
78677
  try {
77575
- const stat3 = fs64.statSync(fullPath);
77576
- if (stat3.size > MAX_FILE_SIZE) {
78678
+ const stat4 = fs67.statSync(fullPath);
78679
+ if (stat4.size > MAX_FILE_SIZE) {
77577
78680
  continue;
77578
78681
  }
77579
- content = fs64.readFileSync(fullPath, "utf-8");
78682
+ content = fs67.readFileSync(fullPath, "utf-8");
77580
78683
  } catch {
77581
78684
  continue;
77582
78685
  }
@@ -77638,8 +78741,8 @@ var placeholder_scan = createSwarmTool({
77638
78741
  });
77639
78742
  // src/tools/pre-check-batch.ts
77640
78743
  init_dist();
77641
- import * as fs67 from "fs";
77642
- import * as path81 from "path";
78744
+ import * as fs70 from "fs";
78745
+ import * as path84 from "path";
77643
78746
  init_manager2();
77644
78747
  init_utils();
77645
78748
  init_create_tool();
@@ -77774,8 +78877,8 @@ var quality_budget = createSwarmTool({
77774
78877
  init_dist();
77775
78878
  init_manager2();
77776
78879
  init_detector();
77777
- import * as fs66 from "fs";
77778
- import * as path80 from "path";
78880
+ import * as fs69 from "fs";
78881
+ import * as path83 from "path";
77779
78882
  import { extname as extname18 } from "path";
77780
78883
 
77781
78884
  // src/sast/rules/c.ts
@@ -78668,25 +79771,25 @@ init_create_tool();
78668
79771
  // src/tools/sast-baseline.ts
78669
79772
  init_utils2();
78670
79773
  import * as crypto8 from "crypto";
78671
- import * as fs65 from "fs";
78672
- import * as path79 from "path";
79774
+ import * as fs68 from "fs";
79775
+ import * as path82 from "path";
78673
79776
  var BASELINE_SCHEMA_VERSION = "1.0.0";
78674
79777
  var MAX_BASELINE_FINDINGS = 2000;
78675
79778
  var MAX_BASELINE_BYTES = 2 * 1048576;
78676
79779
  var LOCK_RETRY_DELAYS_MS = [50, 100, 200, 400, 800];
78677
79780
  function normalizeFindingPath(directory, file3) {
78678
- const resolved = path79.isAbsolute(file3) ? file3 : path79.resolve(directory, file3);
78679
- const rel = path79.relative(path79.resolve(directory), resolved);
79781
+ const resolved = path82.isAbsolute(file3) ? file3 : path82.resolve(directory, file3);
79782
+ const rel = path82.relative(path82.resolve(directory), resolved);
78680
79783
  return rel.replace(/\\/g, "/");
78681
79784
  }
78682
79785
  function baselineRelPath(phase) {
78683
- return path79.join("evidence", String(phase), "sast-baseline.json");
79786
+ return path82.join("evidence", String(phase), "sast-baseline.json");
78684
79787
  }
78685
79788
  function tempRelPath(phase) {
78686
- return path79.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
79789
+ return path82.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
78687
79790
  }
78688
79791
  function lockRelPath(phase) {
78689
- return path79.join("evidence", String(phase), "sast-baseline.json.lock");
79792
+ return path82.join("evidence", String(phase), "sast-baseline.json.lock");
78690
79793
  }
78691
79794
  function getLine(lines, idx) {
78692
79795
  if (idx < 0 || idx >= lines.length)
@@ -78703,7 +79806,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
78703
79806
  }
78704
79807
  const lineNum = finding.location.line;
78705
79808
  try {
78706
- const content = fs65.readFileSync(finding.location.file, "utf-8");
79809
+ const content = fs68.readFileSync(finding.location.file, "utf-8");
78707
79810
  const lines = content.split(`
78708
79811
  `);
78709
79812
  const idx = lineNum - 1;
@@ -78734,7 +79837,7 @@ function assignOccurrenceIndices(findings, directory) {
78734
79837
  try {
78735
79838
  if (relFile.startsWith(".."))
78736
79839
  throw new Error("escapes workspace");
78737
- const content = fs65.readFileSync(finding.location.file, "utf-8");
79840
+ const content = fs68.readFileSync(finding.location.file, "utf-8");
78738
79841
  const lines = content.split(`
78739
79842
  `);
78740
79843
  const idx = lineNum - 1;
@@ -78763,11 +79866,11 @@ function assignOccurrenceIndices(findings, directory) {
78763
79866
  async function acquireLock(lockPath) {
78764
79867
  for (let attempt = 0;attempt <= LOCK_RETRY_DELAYS_MS.length; attempt++) {
78765
79868
  try {
78766
- const fd = fs65.openSync(lockPath, "wx");
78767
- fs65.closeSync(fd);
79869
+ const fd = fs68.openSync(lockPath, "wx");
79870
+ fs68.closeSync(fd);
78768
79871
  return () => {
78769
79872
  try {
78770
- fs65.unlinkSync(lockPath);
79873
+ fs68.unlinkSync(lockPath);
78771
79874
  } catch {}
78772
79875
  };
78773
79876
  } catch {
@@ -78807,12 +79910,12 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
78807
79910
  message: e instanceof Error ? e.message : "Path validation failed"
78808
79911
  };
78809
79912
  }
78810
- fs65.mkdirSync(path79.dirname(baselinePath), { recursive: true });
79913
+ fs68.mkdirSync(path82.dirname(baselinePath), { recursive: true });
78811
79914
  const releaseLock = await acquireLock(lockPath);
78812
79915
  try {
78813
79916
  let existing = null;
78814
79917
  try {
78815
- const raw = fs65.readFileSync(baselinePath, "utf-8");
79918
+ const raw = fs68.readFileSync(baselinePath, "utf-8");
78816
79919
  const parsed = JSON.parse(raw);
78817
79920
  if (parsed.schema_version === BASELINE_SCHEMA_VERSION) {
78818
79921
  existing = parsed;
@@ -78872,8 +79975,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
78872
79975
  message: `Baseline would exceed size cap (${json4.length} bytes > ${MAX_BASELINE_BYTES})`
78873
79976
  };
78874
79977
  }
78875
- fs65.writeFileSync(tempPath, json4, "utf-8");
78876
- fs65.renameSync(tempPath, baselinePath);
79978
+ fs68.writeFileSync(tempPath, json4, "utf-8");
79979
+ fs68.renameSync(tempPath, baselinePath);
78877
79980
  return {
78878
79981
  status: "merged",
78879
79982
  path: baselinePath,
@@ -78904,8 +80007,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
78904
80007
  message: `Baseline would exceed size cap (${json3.length} bytes > ${MAX_BASELINE_BYTES})`
78905
80008
  };
78906
80009
  }
78907
- fs65.writeFileSync(tempPath, json3, "utf-8");
78908
- fs65.renameSync(tempPath, baselinePath);
80010
+ fs68.writeFileSync(tempPath, json3, "utf-8");
80011
+ fs68.renameSync(tempPath, baselinePath);
78909
80012
  return {
78910
80013
  status: "written",
78911
80014
  path: baselinePath,
@@ -78930,7 +80033,7 @@ function loadBaseline(directory, phase) {
78930
80033
  };
78931
80034
  }
78932
80035
  try {
78933
- const raw = fs65.readFileSync(baselinePath, "utf-8");
80036
+ const raw = fs68.readFileSync(baselinePath, "utf-8");
78934
80037
  const parsed = JSON.parse(raw);
78935
80038
  if (parsed.schema_version !== BASELINE_SCHEMA_VERSION) {
78936
80039
  return {
@@ -78972,17 +80075,17 @@ var SEVERITY_ORDER = {
78972
80075
  };
78973
80076
  function shouldSkipFile(filePath) {
78974
80077
  try {
78975
- const stats = fs66.statSync(filePath);
80078
+ const stats = fs69.statSync(filePath);
78976
80079
  if (stats.size > MAX_FILE_SIZE_BYTES8) {
78977
80080
  return { skip: true, reason: "file too large" };
78978
80081
  }
78979
80082
  if (stats.size === 0) {
78980
80083
  return { skip: true, reason: "empty file" };
78981
80084
  }
78982
- const fd = fs66.openSync(filePath, "r");
80085
+ const fd = fs69.openSync(filePath, "r");
78983
80086
  const buffer = Buffer.alloc(8192);
78984
- const bytesRead = fs66.readSync(fd, buffer, 0, 8192, 0);
78985
- fs66.closeSync(fd);
80087
+ const bytesRead = fs69.readSync(fd, buffer, 0, 8192, 0);
80088
+ fs69.closeSync(fd);
78986
80089
  if (bytesRead > 0) {
78987
80090
  let nullCount = 0;
78988
80091
  for (let i2 = 0;i2 < bytesRead; i2++) {
@@ -79021,7 +80124,7 @@ function countBySeverity(findings) {
79021
80124
  }
79022
80125
  function scanFileWithTierA(filePath, language) {
79023
80126
  try {
79024
- const content = fs66.readFileSync(filePath, "utf-8");
80127
+ const content = fs69.readFileSync(filePath, "utf-8");
79025
80128
  const findings = executeRulesSync(filePath, content, language);
79026
80129
  return findings.map((f) => ({
79027
80130
  rule_id: f.rule_id,
@@ -79074,13 +80177,13 @@ async function sastScan(input, directory, config3) {
79074
80177
  _filesSkipped++;
79075
80178
  continue;
79076
80179
  }
79077
- const resolvedPath = path80.isAbsolute(filePath) ? filePath : path80.resolve(directory, filePath);
79078
- const resolvedDirectory = path80.resolve(directory);
79079
- if (!resolvedPath.startsWith(resolvedDirectory + path80.sep) && resolvedPath !== resolvedDirectory) {
80180
+ const resolvedPath = path83.isAbsolute(filePath) ? filePath : path83.resolve(directory, filePath);
80181
+ const resolvedDirectory = path83.resolve(directory);
80182
+ if (!resolvedPath.startsWith(resolvedDirectory + path83.sep) && resolvedPath !== resolvedDirectory) {
79080
80183
  _filesSkipped++;
79081
80184
  continue;
79082
80185
  }
79083
- if (!fs66.existsSync(resolvedPath)) {
80186
+ if (!fs69.existsSync(resolvedPath)) {
79084
80187
  _filesSkipped++;
79085
80188
  continue;
79086
80189
  }
@@ -79387,18 +80490,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
79387
80490
  let resolved;
79388
80491
  const isWinAbs = isWindowsAbsolutePath(inputPath);
79389
80492
  if (isWinAbs) {
79390
- resolved = path81.win32.resolve(inputPath);
79391
- } else if (path81.isAbsolute(inputPath)) {
79392
- resolved = path81.resolve(inputPath);
80493
+ resolved = path84.win32.resolve(inputPath);
80494
+ } else if (path84.isAbsolute(inputPath)) {
80495
+ resolved = path84.resolve(inputPath);
79393
80496
  } else {
79394
- resolved = path81.resolve(baseDir, inputPath);
80497
+ resolved = path84.resolve(baseDir, inputPath);
79395
80498
  }
79396
- const workspaceResolved = path81.resolve(workspaceDir);
80499
+ const workspaceResolved = path84.resolve(workspaceDir);
79397
80500
  let relative20;
79398
80501
  if (isWinAbs) {
79399
- relative20 = path81.win32.relative(workspaceResolved, resolved);
80502
+ relative20 = path84.win32.relative(workspaceResolved, resolved);
79400
80503
  } else {
79401
- relative20 = path81.relative(workspaceResolved, resolved);
80504
+ relative20 = path84.relative(workspaceResolved, resolved);
79402
80505
  }
79403
80506
  if (relative20.startsWith("..")) {
79404
80507
  return "path traversal detected";
@@ -79463,7 +80566,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
79463
80566
  if (typeof file3 !== "string") {
79464
80567
  continue;
79465
80568
  }
79466
- const resolvedPath = path81.resolve(file3);
80569
+ const resolvedPath = path84.resolve(file3);
79467
80570
  const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
79468
80571
  if (validationError) {
79469
80572
  continue;
@@ -79620,7 +80723,7 @@ async function runSecretscanWithFiles(files, directory) {
79620
80723
  skippedFiles++;
79621
80724
  continue;
79622
80725
  }
79623
- const resolvedPath = path81.resolve(file3);
80726
+ const resolvedPath = path84.resolve(file3);
79624
80727
  const validationError = validatePath(resolvedPath, directory, directory);
79625
80728
  if (validationError) {
79626
80729
  skippedFiles++;
@@ -79638,25 +80741,25 @@ async function runSecretscanWithFiles(files, directory) {
79638
80741
  };
79639
80742
  }
79640
80743
  for (const file3 of validatedFiles) {
79641
- const ext = path81.extname(file3).toLowerCase();
80744
+ const ext = path84.extname(file3).toLowerCase();
79642
80745
  if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
79643
80746
  skippedFiles++;
79644
80747
  continue;
79645
80748
  }
79646
- let stat3;
80749
+ let stat4;
79647
80750
  try {
79648
- stat3 = fs67.statSync(file3);
80751
+ stat4 = fs70.statSync(file3);
79649
80752
  } catch {
79650
80753
  skippedFiles++;
79651
80754
  continue;
79652
80755
  }
79653
- if (stat3.size > MAX_FILE_SIZE_BYTES9) {
80756
+ if (stat4.size > MAX_FILE_SIZE_BYTES9) {
79654
80757
  skippedFiles++;
79655
80758
  continue;
79656
80759
  }
79657
80760
  let content;
79658
80761
  try {
79659
- const buffer = fs67.readFileSync(file3);
80762
+ const buffer = fs70.readFileSync(file3);
79660
80763
  if (buffer.includes(0)) {
79661
80764
  skippedFiles++;
79662
80765
  continue;
@@ -79857,7 +80960,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
79857
80960
  const preexistingFindings = [];
79858
80961
  for (const finding of findings) {
79859
80962
  const filePath = finding.location.file;
79860
- const normalised = path81.relative(directory, filePath).replace(/\\/g, "/");
80963
+ const normalised = path84.relative(directory, filePath).replace(/\\/g, "/");
79861
80964
  const changedLines = changedLineRanges.get(normalised);
79862
80965
  if (changedLines?.has(finding.location.line)) {
79863
80966
  newFindings.push(finding);
@@ -79908,7 +81011,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
79908
81011
  warn(`pre_check_batch: Invalid file path: ${file3}`);
79909
81012
  continue;
79910
81013
  }
79911
- changedFiles.push(path81.resolve(directory, file3));
81014
+ changedFiles.push(path84.resolve(directory, file3));
79912
81015
  }
79913
81016
  if (changedFiles.length === 0) {
79914
81017
  warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
@@ -80109,7 +81212,7 @@ var pre_check_batch = createSwarmTool({
80109
81212
  };
80110
81213
  return JSON.stringify(errorResult, null, 2);
80111
81214
  }
80112
- const resolvedDirectory = path81.resolve(typedArgs.directory);
81215
+ const resolvedDirectory = path84.resolve(typedArgs.directory);
80113
81216
  const workspaceAnchor = resolvedDirectory;
80114
81217
  const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
80115
81218
  if (dirError) {
@@ -80150,7 +81253,7 @@ var pre_check_batch = createSwarmTool({
80150
81253
  });
80151
81254
  // src/tools/repo-map.ts
80152
81255
  init_dist();
80153
- import * as path82 from "path";
81256
+ import * as path85 from "path";
80154
81257
  init_path_security();
80155
81258
  init_create_tool();
80156
81259
  var VALID_ACTIONS = [
@@ -80175,7 +81278,7 @@ function validateFile(p) {
80175
81278
  return "file contains control characters";
80176
81279
  if (containsPathTraversal(p))
80177
81280
  return "file contains path traversal";
80178
- if (path82.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
81281
+ if (path85.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
80179
81282
  return "file must be a workspace-relative path, not absolute";
80180
81283
  }
80181
81284
  return null;
@@ -80198,8 +81301,8 @@ function ok(action, payload) {
80198
81301
  }
80199
81302
  function toRelativeGraphPath(input, workspaceRoot) {
80200
81303
  const normalized = input.replace(/\\/g, "/");
80201
- if (path82.isAbsolute(normalized)) {
80202
- const rel = path82.relative(workspaceRoot, normalized).replace(/\\/g, "/");
81304
+ if (path85.isAbsolute(normalized)) {
81305
+ const rel = path85.relative(workspaceRoot, normalized).replace(/\\/g, "/");
80203
81306
  return normalizeGraphPath2(rel);
80204
81307
  }
80205
81308
  return normalizeGraphPath2(normalized);
@@ -80343,8 +81446,8 @@ var repo_map = createSwarmTool({
80343
81446
  // src/tools/req-coverage.ts
80344
81447
  init_dist();
80345
81448
  init_create_tool();
80346
- import * as fs68 from "fs";
80347
- import * as path83 from "path";
81449
+ import * as fs71 from "fs";
81450
+ import * as path86 from "path";
80348
81451
  var SPEC_FILE = ".swarm/spec.md";
80349
81452
  var EVIDENCE_DIR4 = ".swarm/evidence";
80350
81453
  var OBLIGATION_KEYWORDS = ["MUST", "SHOULD", "SHALL"];
@@ -80403,20 +81506,20 @@ function extractObligationAndText(id, lineText) {
80403
81506
  var PHASE_TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
80404
81507
  function readTouchedFiles(evidenceDir, phase, cwd) {
80405
81508
  const touchedFiles = new Set;
80406
- if (!fs68.existsSync(evidenceDir) || !fs68.statSync(evidenceDir).isDirectory()) {
81509
+ if (!fs71.existsSync(evidenceDir) || !fs71.statSync(evidenceDir).isDirectory()) {
80407
81510
  return [];
80408
81511
  }
80409
81512
  let entries;
80410
81513
  try {
80411
- entries = fs68.readdirSync(evidenceDir);
81514
+ entries = fs71.readdirSync(evidenceDir);
80412
81515
  } catch {
80413
81516
  return [];
80414
81517
  }
80415
81518
  for (const entry of entries) {
80416
- const entryPath = path83.join(evidenceDir, entry);
81519
+ const entryPath = path86.join(evidenceDir, entry);
80417
81520
  try {
80418
- const stat3 = fs68.statSync(entryPath);
80419
- if (!stat3.isDirectory()) {
81521
+ const stat4 = fs71.statSync(entryPath);
81522
+ if (!stat4.isDirectory()) {
80420
81523
  continue;
80421
81524
  }
80422
81525
  } catch {
@@ -80429,18 +81532,18 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
80429
81532
  if (entryPhase !== String(phase)) {
80430
81533
  continue;
80431
81534
  }
80432
- const evidenceFilePath = path83.join(entryPath, "evidence.json");
81535
+ const evidenceFilePath = path86.join(entryPath, "evidence.json");
80433
81536
  try {
80434
- const resolvedPath = path83.resolve(evidenceFilePath);
80435
- const evidenceDirResolved = path83.resolve(evidenceDir);
80436
- if (!resolvedPath.startsWith(evidenceDirResolved + path83.sep)) {
81537
+ const resolvedPath = path86.resolve(evidenceFilePath);
81538
+ const evidenceDirResolved = path86.resolve(evidenceDir);
81539
+ if (!resolvedPath.startsWith(evidenceDirResolved + path86.sep)) {
80437
81540
  continue;
80438
81541
  }
80439
- const stat3 = fs68.lstatSync(evidenceFilePath);
80440
- if (!stat3.isFile()) {
81542
+ const stat4 = fs71.lstatSync(evidenceFilePath);
81543
+ if (!stat4.isFile()) {
80441
81544
  continue;
80442
81545
  }
80443
- if (stat3.size > MAX_FILE_SIZE_BYTES9) {
81546
+ if (stat4.size > MAX_FILE_SIZE_BYTES9) {
80444
81547
  continue;
80445
81548
  }
80446
81549
  } catch {
@@ -80448,7 +81551,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
80448
81551
  }
80449
81552
  let content;
80450
81553
  try {
80451
- content = fs68.readFileSync(evidenceFilePath, "utf-8");
81554
+ content = fs71.readFileSync(evidenceFilePath, "utf-8");
80452
81555
  } catch {
80453
81556
  continue;
80454
81557
  }
@@ -80467,7 +81570,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
80467
81570
  if (Array.isArray(diffEntry.files_changed)) {
80468
81571
  for (const file3 of diffEntry.files_changed) {
80469
81572
  if (typeof file3 === "string") {
80470
- touchedFiles.add(path83.resolve(cwd, file3));
81573
+ touchedFiles.add(path86.resolve(cwd, file3));
80471
81574
  }
80472
81575
  }
80473
81576
  }
@@ -80480,12 +81583,12 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
80480
81583
  }
80481
81584
  function searchFileForKeywords(filePath, keywords, cwd) {
80482
81585
  try {
80483
- const resolvedPath = path83.resolve(filePath);
80484
- const cwdResolved = path83.resolve(cwd);
81586
+ const resolvedPath = path86.resolve(filePath);
81587
+ const cwdResolved = path86.resolve(cwd);
80485
81588
  if (!resolvedPath.startsWith(cwdResolved)) {
80486
81589
  return false;
80487
81590
  }
80488
- const content = fs68.readFileSync(resolvedPath, "utf-8");
81591
+ const content = fs71.readFileSync(resolvedPath, "utf-8");
80489
81592
  for (const keyword of keywords) {
80490
81593
  const regex = new RegExp(`\\b${keyword}\\b`, "i");
80491
81594
  if (regex.test(content)) {
@@ -80615,10 +81718,10 @@ var req_coverage = createSwarmTool({
80615
81718
  }, null, 2);
80616
81719
  }
80617
81720
  const cwd = inputDirectory || directory;
80618
- const specPath = path83.join(cwd, SPEC_FILE);
81721
+ const specPath = path86.join(cwd, SPEC_FILE);
80619
81722
  let specContent;
80620
81723
  try {
80621
- specContent = fs68.readFileSync(specPath, "utf-8");
81724
+ specContent = fs71.readFileSync(specPath, "utf-8");
80622
81725
  } catch (readError) {
80623
81726
  return JSON.stringify({
80624
81727
  success: false,
@@ -80642,7 +81745,7 @@ var req_coverage = createSwarmTool({
80642
81745
  message: "No FR requirements found in spec.md"
80643
81746
  }, null, 2);
80644
81747
  }
80645
- const evidenceDir = path83.join(cwd, EVIDENCE_DIR4);
81748
+ const evidenceDir = path86.join(cwd, EVIDENCE_DIR4);
80646
81749
  const touchedFiles = readTouchedFiles(evidenceDir, phase, cwd);
80647
81750
  const analyzedRequirements = [];
80648
81751
  let coveredCount = 0;
@@ -80668,12 +81771,12 @@ var req_coverage = createSwarmTool({
80668
81771
  requirements: analyzedRequirements
80669
81772
  };
80670
81773
  const reportFilename = `req-coverage-phase-${phase}.json`;
80671
- const reportPath = path83.join(evidenceDir, reportFilename);
81774
+ const reportPath = path86.join(evidenceDir, reportFilename);
80672
81775
  try {
80673
- if (!fs68.existsSync(evidenceDir)) {
80674
- fs68.mkdirSync(evidenceDir, { recursive: true });
81776
+ if (!fs71.existsSync(evidenceDir)) {
81777
+ fs71.mkdirSync(evidenceDir, { recursive: true });
80675
81778
  }
80676
- fs68.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
81779
+ fs71.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
80677
81780
  } catch (writeError) {
80678
81781
  console.warn(`Failed to write coverage report: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
80679
81782
  }
@@ -80759,8 +81862,8 @@ init_manager();
80759
81862
  init_state();
80760
81863
  init_create_tool();
80761
81864
  import * as crypto9 from "crypto";
80762
- import * as fs69 from "fs";
80763
- import * as path84 from "path";
81865
+ import * as fs72 from "fs";
81866
+ import * as path87 from "path";
80764
81867
  function detectPlaceholderContent(args2) {
80765
81868
  const issues = [];
80766
81869
  const placeholderPattern = /^\[\w[\w\s]*\]$/;
@@ -80836,11 +81939,11 @@ async function executeSavePlan(args2, fallbackDir) {
80836
81939
  let specMtime;
80837
81940
  let specHash;
80838
81941
  if (process.env.SWARM_SKIP_SPEC_GATE !== "1") {
80839
- const specPath = path84.join(targetWorkspace, ".swarm", "spec.md");
81942
+ const specPath = path87.join(targetWorkspace, ".swarm", "spec.md");
80840
81943
  try {
80841
- const stat3 = await fs69.promises.stat(specPath);
80842
- specMtime = stat3.mtime.toISOString();
80843
- const content = await fs69.promises.readFile(specPath, "utf8");
81944
+ const stat4 = await fs72.promises.stat(specPath);
81945
+ specMtime = stat4.mtime.toISOString();
81946
+ const content = await fs72.promises.readFile(specPath, "utf8");
80844
81947
  specHash = crypto9.createHash("sha256").update(content).digest("hex");
80845
81948
  } catch {
80846
81949
  return {
@@ -80976,14 +82079,14 @@ async function executeSavePlan(args2, fallbackDir) {
80976
82079
  }
80977
82080
  await writeCheckpoint(dir).catch(() => {});
80978
82081
  try {
80979
- const markerPath = path84.join(dir, ".swarm", ".plan-write-marker");
82082
+ const markerPath = path87.join(dir, ".swarm", ".plan-write-marker");
80980
82083
  const marker = JSON.stringify({
80981
82084
  source: "save_plan",
80982
82085
  timestamp: new Date().toISOString(),
80983
82086
  phases_count: plan.phases.length,
80984
82087
  tasks_count: tasksCount
80985
82088
  });
80986
- await fs69.promises.writeFile(markerPath, marker, "utf8");
82089
+ await fs72.promises.writeFile(markerPath, marker, "utf8");
80987
82090
  } catch {}
80988
82091
  const warnings = [];
80989
82092
  let criticReviewFound = false;
@@ -80999,7 +82102,7 @@ async function executeSavePlan(args2, fallbackDir) {
80999
82102
  return {
81000
82103
  success: true,
81001
82104
  message: "Plan saved successfully",
81002
- plan_path: path84.join(dir, ".swarm", "plan.json"),
82105
+ plan_path: path87.join(dir, ".swarm", "plan.json"),
81003
82106
  phases_count: plan.phases.length,
81004
82107
  tasks_count: tasksCount,
81005
82108
  ...resolvedProfile !== undefined ? { execution_profile: resolvedProfile } : {},
@@ -81051,8 +82154,8 @@ var save_plan = createSwarmTool({
81051
82154
  // src/tools/sbom-generate.ts
81052
82155
  init_dist();
81053
82156
  init_manager2();
81054
- import * as fs70 from "fs";
81055
- import * as path85 from "path";
82157
+ import * as fs73 from "fs";
82158
+ import * as path88 from "path";
81056
82159
 
81057
82160
  // src/sbom/detectors/index.ts
81058
82161
  init_utils();
@@ -81900,9 +83003,9 @@ function findManifestFiles(rootDir) {
81900
83003
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
81901
83004
  function searchDir(dir) {
81902
83005
  try {
81903
- const entries = fs70.readdirSync(dir, { withFileTypes: true });
83006
+ const entries = fs73.readdirSync(dir, { withFileTypes: true });
81904
83007
  for (const entry of entries) {
81905
- const fullPath = path85.join(dir, entry.name);
83008
+ const fullPath = path88.join(dir, entry.name);
81906
83009
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
81907
83010
  continue;
81908
83011
  }
@@ -81911,7 +83014,7 @@ function findManifestFiles(rootDir) {
81911
83014
  } else if (entry.isFile()) {
81912
83015
  for (const pattern of patterns) {
81913
83016
  if (simpleGlobToRegex(pattern).test(entry.name)) {
81914
- manifestFiles.push(path85.relative(rootDir, fullPath));
83017
+ manifestFiles.push(path88.relative(rootDir, fullPath));
81915
83018
  break;
81916
83019
  }
81917
83020
  }
@@ -81927,13 +83030,13 @@ function findManifestFilesInDirs(directories, workingDir) {
81927
83030
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
81928
83031
  for (const dir of directories) {
81929
83032
  try {
81930
- const entries = fs70.readdirSync(dir, { withFileTypes: true });
83033
+ const entries = fs73.readdirSync(dir, { withFileTypes: true });
81931
83034
  for (const entry of entries) {
81932
- const fullPath = path85.join(dir, entry.name);
83035
+ const fullPath = path88.join(dir, entry.name);
81933
83036
  if (entry.isFile()) {
81934
83037
  for (const pattern of patterns) {
81935
83038
  if (simpleGlobToRegex(pattern).test(entry.name)) {
81936
- found.push(path85.relative(workingDir, fullPath));
83039
+ found.push(path88.relative(workingDir, fullPath));
81937
83040
  break;
81938
83041
  }
81939
83042
  }
@@ -81946,11 +83049,11 @@ function findManifestFilesInDirs(directories, workingDir) {
81946
83049
  function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
81947
83050
  const dirs = new Set;
81948
83051
  for (const file3 of changedFiles) {
81949
- let currentDir = path85.dirname(file3);
83052
+ let currentDir = path88.dirname(file3);
81950
83053
  while (true) {
81951
- if (currentDir && currentDir !== "." && currentDir !== path85.sep) {
81952
- dirs.add(path85.join(workingDir, currentDir));
81953
- const parent = path85.dirname(currentDir);
83054
+ if (currentDir && currentDir !== "." && currentDir !== path88.sep) {
83055
+ dirs.add(path88.join(workingDir, currentDir));
83056
+ const parent = path88.dirname(currentDir);
81954
83057
  if (parent === currentDir)
81955
83058
  break;
81956
83059
  currentDir = parent;
@@ -81964,7 +83067,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
81964
83067
  }
81965
83068
  function ensureOutputDir(outputDir) {
81966
83069
  try {
81967
- fs70.mkdirSync(outputDir, { recursive: true });
83070
+ fs73.mkdirSync(outputDir, { recursive: true });
81968
83071
  } catch (error93) {
81969
83072
  if (!error93 || error93.code !== "EEXIST") {
81970
83073
  throw error93;
@@ -82034,7 +83137,7 @@ var sbom_generate = createSwarmTool({
82034
83137
  const changedFiles = obj.changed_files;
82035
83138
  const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
82036
83139
  const workingDir = directory;
82037
- const outputDir = path85.isAbsolute(relativeOutputDir) ? relativeOutputDir : path85.join(workingDir, relativeOutputDir);
83140
+ const outputDir = path88.isAbsolute(relativeOutputDir) ? relativeOutputDir : path88.join(workingDir, relativeOutputDir);
82038
83141
  let manifestFiles = [];
82039
83142
  if (scope === "all") {
82040
83143
  manifestFiles = findManifestFiles(workingDir);
@@ -82057,11 +83160,11 @@ var sbom_generate = createSwarmTool({
82057
83160
  const processedFiles = [];
82058
83161
  for (const manifestFile of manifestFiles) {
82059
83162
  try {
82060
- const fullPath = path85.isAbsolute(manifestFile) ? manifestFile : path85.join(workingDir, manifestFile);
82061
- if (!fs70.existsSync(fullPath)) {
83163
+ const fullPath = path88.isAbsolute(manifestFile) ? manifestFile : path88.join(workingDir, manifestFile);
83164
+ if (!fs73.existsSync(fullPath)) {
82062
83165
  continue;
82063
83166
  }
82064
- const content = fs70.readFileSync(fullPath, "utf-8");
83167
+ const content = fs73.readFileSync(fullPath, "utf-8");
82065
83168
  const components = detectComponents(manifestFile, content);
82066
83169
  processedFiles.push(manifestFile);
82067
83170
  if (components.length > 0) {
@@ -82074,8 +83177,8 @@ var sbom_generate = createSwarmTool({
82074
83177
  const bom = generateCycloneDX(allComponents);
82075
83178
  const bomJson = serializeCycloneDX(bom);
82076
83179
  const filename = generateSbomFilename();
82077
- const outputPath = path85.join(outputDir, filename);
82078
- fs70.writeFileSync(outputPath, bomJson, "utf-8");
83180
+ const outputPath = path88.join(outputDir, filename);
83181
+ fs73.writeFileSync(outputPath, bomJson, "utf-8");
82079
83182
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
82080
83183
  try {
82081
83184
  const timestamp = new Date().toISOString();
@@ -82117,8 +83220,8 @@ var sbom_generate = createSwarmTool({
82117
83220
  // src/tools/schema-drift.ts
82118
83221
  init_dist();
82119
83222
  init_create_tool();
82120
- import * as fs71 from "fs";
82121
- import * as path86 from "path";
83223
+ import * as fs74 from "fs";
83224
+ import * as path89 from "path";
82122
83225
  var SPEC_CANDIDATES = [
82123
83226
  "openapi.json",
82124
83227
  "openapi.yaml",
@@ -82150,28 +83253,28 @@ function normalizePath3(p) {
82150
83253
  }
82151
83254
  function discoverSpecFile(cwd, specFileArg) {
82152
83255
  if (specFileArg) {
82153
- const resolvedPath = path86.resolve(cwd, specFileArg);
82154
- const normalizedCwd = cwd.endsWith(path86.sep) ? cwd : cwd + path86.sep;
83256
+ const resolvedPath = path89.resolve(cwd, specFileArg);
83257
+ const normalizedCwd = cwd.endsWith(path89.sep) ? cwd : cwd + path89.sep;
82155
83258
  if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
82156
83259
  throw new Error("Invalid spec_file: path traversal detected");
82157
83260
  }
82158
- const ext = path86.extname(resolvedPath).toLowerCase();
83261
+ const ext = path89.extname(resolvedPath).toLowerCase();
82159
83262
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
82160
83263
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
82161
83264
  }
82162
- const stats = fs71.statSync(resolvedPath);
83265
+ const stats = fs74.statSync(resolvedPath);
82163
83266
  if (stats.size > MAX_SPEC_SIZE) {
82164
83267
  throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
82165
83268
  }
82166
- if (!fs71.existsSync(resolvedPath)) {
83269
+ if (!fs74.existsSync(resolvedPath)) {
82167
83270
  throw new Error(`Spec file not found: ${resolvedPath}`);
82168
83271
  }
82169
83272
  return resolvedPath;
82170
83273
  }
82171
83274
  for (const candidate of SPEC_CANDIDATES) {
82172
- const candidatePath = path86.resolve(cwd, candidate);
82173
- if (fs71.existsSync(candidatePath)) {
82174
- const stats = fs71.statSync(candidatePath);
83275
+ const candidatePath = path89.resolve(cwd, candidate);
83276
+ if (fs74.existsSync(candidatePath)) {
83277
+ const stats = fs74.statSync(candidatePath);
82175
83278
  if (stats.size <= MAX_SPEC_SIZE) {
82176
83279
  return candidatePath;
82177
83280
  }
@@ -82180,8 +83283,8 @@ function discoverSpecFile(cwd, specFileArg) {
82180
83283
  return null;
82181
83284
  }
82182
83285
  function parseSpec(specFile) {
82183
- const content = fs71.readFileSync(specFile, "utf-8");
82184
- const ext = path86.extname(specFile).toLowerCase();
83286
+ const content = fs74.readFileSync(specFile, "utf-8");
83287
+ const ext = path89.extname(specFile).toLowerCase();
82185
83288
  if (ext === ".json") {
82186
83289
  return parseJsonSpec(content);
82187
83290
  }
@@ -82252,12 +83355,12 @@ function extractRoutes(cwd) {
82252
83355
  function walkDir(dir) {
82253
83356
  let entries;
82254
83357
  try {
82255
- entries = fs71.readdirSync(dir, { withFileTypes: true });
83358
+ entries = fs74.readdirSync(dir, { withFileTypes: true });
82256
83359
  } catch {
82257
83360
  return;
82258
83361
  }
82259
83362
  for (const entry of entries) {
82260
- const fullPath = path86.join(dir, entry.name);
83363
+ const fullPath = path89.join(dir, entry.name);
82261
83364
  if (entry.isSymbolicLink()) {
82262
83365
  continue;
82263
83366
  }
@@ -82267,7 +83370,7 @@ function extractRoutes(cwd) {
82267
83370
  }
82268
83371
  walkDir(fullPath);
82269
83372
  } else if (entry.isFile()) {
82270
- const ext = path86.extname(entry.name).toLowerCase();
83373
+ const ext = path89.extname(entry.name).toLowerCase();
82271
83374
  const baseName = entry.name.toLowerCase();
82272
83375
  if (![".ts", ".js", ".mjs"].includes(ext)) {
82273
83376
  continue;
@@ -82285,7 +83388,7 @@ function extractRoutes(cwd) {
82285
83388
  }
82286
83389
  function extractRoutesFromFile(filePath) {
82287
83390
  const routes = [];
82288
- const content = fs71.readFileSync(filePath, "utf-8");
83391
+ const content = fs74.readFileSync(filePath, "utf-8");
82289
83392
  const lines = content.split(/\r?\n/);
82290
83393
  const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
82291
83394
  const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
@@ -82433,8 +83536,8 @@ var schema_drift = createSwarmTool({
82433
83536
  init_tool();
82434
83537
  init_path_security();
82435
83538
  init_create_tool();
82436
- import * as fs72 from "fs";
82437
- import * as path87 from "path";
83539
+ import * as fs75 from "fs";
83540
+ import * as path90 from "path";
82438
83541
  var DEFAULT_MAX_RESULTS = 100;
82439
83542
  var DEFAULT_MAX_LINES = 200;
82440
83543
  var REGEX_TIMEOUT_MS = 5000;
@@ -82470,11 +83573,11 @@ function containsWindowsAttacks3(str) {
82470
83573
  }
82471
83574
  function isPathInWorkspace3(filePath, workspace) {
82472
83575
  try {
82473
- const resolvedPath = path87.resolve(workspace, filePath);
82474
- const realWorkspace = fs72.realpathSync(workspace);
82475
- const realResolvedPath = fs72.realpathSync(resolvedPath);
82476
- const relativePath = path87.relative(realWorkspace, realResolvedPath);
82477
- if (relativePath.startsWith("..") || path87.isAbsolute(relativePath)) {
83576
+ const resolvedPath = path90.resolve(workspace, filePath);
83577
+ const realWorkspace = fs75.realpathSync(workspace);
83578
+ const realResolvedPath = fs75.realpathSync(resolvedPath);
83579
+ const relativePath = path90.relative(realWorkspace, realResolvedPath);
83580
+ if (relativePath.startsWith("..") || path90.isAbsolute(relativePath)) {
82478
83581
  return false;
82479
83582
  }
82480
83583
  return true;
@@ -82487,12 +83590,12 @@ function validatePathForRead2(filePath, workspace) {
82487
83590
  }
82488
83591
  function findRgInEnvPath() {
82489
83592
  const searchPath = process.env.PATH ?? "";
82490
- for (const dir of searchPath.split(path87.delimiter)) {
83593
+ for (const dir of searchPath.split(path90.delimiter)) {
82491
83594
  if (!dir)
82492
83595
  continue;
82493
83596
  const isWindows = process.platform === "win32";
82494
- const candidate = path87.join(dir, isWindows ? "rg.exe" : "rg");
82495
- if (fs72.existsSync(candidate))
83597
+ const candidate = path90.join(dir, isWindows ? "rg.exe" : "rg");
83598
+ if (fs75.existsSync(candidate))
82496
83599
  return candidate;
82497
83600
  }
82498
83601
  return null;
@@ -82619,10 +83722,10 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
82619
83722
  return files;
82620
83723
  }
82621
83724
  try {
82622
- const entries = fs72.readdirSync(dir, { withFileTypes: true });
83725
+ const entries = fs75.readdirSync(dir, { withFileTypes: true });
82623
83726
  for (const entry of entries) {
82624
- const fullPath = path87.join(dir, entry.name);
82625
- const relativePath = path87.relative(workspace, fullPath);
83727
+ const fullPath = path90.join(dir, entry.name);
83728
+ const relativePath = path90.relative(workspace, fullPath);
82626
83729
  if (!validatePathForRead2(fullPath, workspace)) {
82627
83730
  continue;
82628
83731
  }
@@ -82663,13 +83766,13 @@ async function fallbackSearch(opts) {
82663
83766
  const matches = [];
82664
83767
  let total = 0;
82665
83768
  for (const file3 of files) {
82666
- const fullPath = path87.join(opts.workspace, file3);
83769
+ const fullPath = path90.join(opts.workspace, file3);
82667
83770
  if (!validatePathForRead2(fullPath, opts.workspace)) {
82668
83771
  continue;
82669
83772
  }
82670
83773
  let stats;
82671
83774
  try {
82672
- stats = fs72.statSync(fullPath);
83775
+ stats = fs75.statSync(fullPath);
82673
83776
  if (stats.size > MAX_FILE_SIZE_BYTES10) {
82674
83777
  continue;
82675
83778
  }
@@ -82678,7 +83781,7 @@ async function fallbackSearch(opts) {
82678
83781
  }
82679
83782
  let content;
82680
83783
  try {
82681
- content = fs72.readFileSync(fullPath, "utf-8");
83784
+ content = fs75.readFileSync(fullPath, "utf-8");
82682
83785
  } catch {
82683
83786
  continue;
82684
83787
  }
@@ -82790,7 +83893,7 @@ var search = createSwarmTool({
82790
83893
  message: "Exclude pattern contains invalid Windows-specific sequence"
82791
83894
  }, null, 2);
82792
83895
  }
82793
- if (!fs72.existsSync(directory)) {
83896
+ if (!fs75.existsSync(directory)) {
82794
83897
  return JSON.stringify({
82795
83898
  error: true,
82796
83899
  type: "unknown",
@@ -82913,8 +84016,8 @@ var set_qa_gates = createSwarmTool({
82913
84016
  init_tool();
82914
84017
  init_path_security();
82915
84018
  init_create_tool();
82916
- import * as fs73 from "fs";
82917
- import * as path88 from "path";
84019
+ import * as fs76 from "fs";
84020
+ import * as path91 from "path";
82918
84021
  var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
82919
84022
  function containsWindowsAttacks4(str) {
82920
84023
  if (/:[^\\/]/.test(str))
@@ -82928,14 +84031,14 @@ function containsWindowsAttacks4(str) {
82928
84031
  }
82929
84032
  function isPathInWorkspace4(filePath, workspace) {
82930
84033
  try {
82931
- const resolvedPath = path88.resolve(workspace, filePath);
82932
- if (!fs73.existsSync(resolvedPath)) {
84034
+ const resolvedPath = path91.resolve(workspace, filePath);
84035
+ if (!fs76.existsSync(resolvedPath)) {
82933
84036
  return true;
82934
84037
  }
82935
- const realWorkspace = fs73.realpathSync(workspace);
82936
- const realResolvedPath = fs73.realpathSync(resolvedPath);
82937
- const relativePath = path88.relative(realWorkspace, realResolvedPath);
82938
- if (relativePath.startsWith("..") || path88.isAbsolute(relativePath)) {
84038
+ const realWorkspace = fs76.realpathSync(workspace);
84039
+ const realResolvedPath = fs76.realpathSync(resolvedPath);
84040
+ const relativePath = path91.relative(realWorkspace, realResolvedPath);
84041
+ if (relativePath.startsWith("..") || path91.isAbsolute(relativePath)) {
82939
84042
  return false;
82940
84043
  }
82941
84044
  return true;
@@ -83107,7 +84210,7 @@ var suggestPatch = createSwarmTool({
83107
84210
  message: "changes cannot be empty"
83108
84211
  }, null, 2);
83109
84212
  }
83110
- if (!fs73.existsSync(directory)) {
84213
+ if (!fs76.existsSync(directory)) {
83111
84214
  return JSON.stringify({
83112
84215
  success: false,
83113
84216
  error: true,
@@ -83143,8 +84246,8 @@ var suggestPatch = createSwarmTool({
83143
84246
  });
83144
84247
  continue;
83145
84248
  }
83146
- const fullPath = path88.resolve(directory, change.file);
83147
- if (!fs73.existsSync(fullPath)) {
84249
+ const fullPath = path91.resolve(directory, change.file);
84250
+ if (!fs76.existsSync(fullPath)) {
83148
84251
  errors5.push({
83149
84252
  success: false,
83150
84253
  error: true,
@@ -83158,7 +84261,7 @@ var suggestPatch = createSwarmTool({
83158
84261
  }
83159
84262
  let content;
83160
84263
  try {
83161
- content = fs73.readFileSync(fullPath, "utf-8");
84264
+ content = fs76.readFileSync(fullPath, "utf-8");
83162
84265
  } catch (err3) {
83163
84266
  errors5.push({
83164
84267
  success: false,
@@ -83237,8 +84340,8 @@ var suggestPatch = createSwarmTool({
83237
84340
  // src/tools/lint-spec.ts
83238
84341
  init_spec_schema();
83239
84342
  init_create_tool();
83240
- import * as fs74 from "fs";
83241
- import * as path89 from "path";
84343
+ import * as fs77 from "fs";
84344
+ import * as path92 from "path";
83242
84345
  var SPEC_FILE_NAME = "spec.md";
83243
84346
  var SWARM_DIR2 = ".swarm";
83244
84347
  var OBLIGATION_KEYWORDS2 = ["MUST", "SHALL", "SHOULD", "MAY"];
@@ -83291,8 +84394,8 @@ var lint_spec = createSwarmTool({
83291
84394
  async execute(_args, directory) {
83292
84395
  const errors5 = [];
83293
84396
  const warnings = [];
83294
- const specPath = path89.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
83295
- if (!fs74.existsSync(specPath)) {
84397
+ const specPath = path92.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
84398
+ if (!fs77.existsSync(specPath)) {
83296
84399
  const result2 = {
83297
84400
  valid: false,
83298
84401
  specMtime: null,
@@ -83311,12 +84414,12 @@ var lint_spec = createSwarmTool({
83311
84414
  }
83312
84415
  let specMtime = null;
83313
84416
  try {
83314
- const stats = fs74.statSync(specPath);
84417
+ const stats = fs77.statSync(specPath);
83315
84418
  specMtime = stats.mtime.toISOString();
83316
84419
  } catch {}
83317
84420
  let content;
83318
84421
  try {
83319
- content = fs74.readFileSync(specPath, "utf-8");
84422
+ content = fs77.readFileSync(specPath, "utf-8");
83320
84423
  } catch (e) {
83321
84424
  const result2 = {
83322
84425
  valid: false,
@@ -83361,13 +84464,13 @@ var lint_spec = createSwarmTool({
83361
84464
  });
83362
84465
  // src/tools/mutation-test.ts
83363
84466
  init_dist();
83364
- import * as fs75 from "fs";
83365
- import * as path91 from "path";
84467
+ import * as fs78 from "fs";
84468
+ import * as path94 from "path";
83366
84469
 
83367
84470
  // src/mutation/engine.ts
83368
84471
  import { spawnSync as spawnSync3 } from "child_process";
83369
84472
  import { unlinkSync as unlinkSync12, writeFileSync as writeFileSync18 } from "fs";
83370
- import * as path90 from "path";
84473
+ import * as path93 from "path";
83371
84474
 
83372
84475
  // src/mutation/equivalence.ts
83373
84476
  function isStaticallyEquivalent(originalCode, mutatedCode) {
@@ -83502,7 +84605,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
83502
84605
  let patchFile;
83503
84606
  try {
83504
84607
  const safeId2 = patch.id.replace(/[^a-zA-Z0-9_-]/g, "_");
83505
- patchFile = path90.join(workingDir, `.mutation_patch_${safeId2}.diff`);
84608
+ patchFile = path93.join(workingDir, `.mutation_patch_${safeId2}.diff`);
83506
84609
  try {
83507
84610
  writeFileSync18(patchFile, patch.patch);
83508
84611
  } catch (writeErr) {
@@ -83896,8 +84999,8 @@ var mutation_test = createSwarmTool({
83896
84999
  ];
83897
85000
  for (const filePath of uniquePaths) {
83898
85001
  try {
83899
- const resolvedPath = path91.resolve(cwd, filePath);
83900
- sourceFiles.set(filePath, fs75.readFileSync(resolvedPath, "utf-8"));
85002
+ const resolvedPath = path94.resolve(cwd, filePath);
85003
+ sourceFiles.set(filePath, fs78.readFileSync(resolvedPath, "utf-8"));
83901
85004
  } catch {}
83902
85005
  }
83903
85006
  const report = await executeMutationSuite(typedArgs.patches, typedArgs.test_command, typedArgs.files, cwd, undefined, undefined, sourceFiles.size > 0 ? sourceFiles : undefined);
@@ -83915,8 +85018,8 @@ var mutation_test = createSwarmTool({
83915
85018
  init_dist();
83916
85019
  init_manager2();
83917
85020
  init_detector();
83918
- import * as fs76 from "fs";
83919
- import * as path92 from "path";
85021
+ import * as fs79 from "fs";
85022
+ import * as path95 from "path";
83920
85023
  init_create_tool();
83921
85024
  var MAX_FILE_SIZE2 = 2 * 1024 * 1024;
83922
85025
  var BINARY_CHECK_BYTES = 8192;
@@ -83982,7 +85085,7 @@ async function syntaxCheck(input, directory, config3) {
83982
85085
  if (languages?.length) {
83983
85086
  const lowerLangs = languages.map((l) => l.toLowerCase());
83984
85087
  filesToCheck = filesToCheck.filter((file3) => {
83985
- const ext = path92.extname(file3.path).toLowerCase();
85088
+ const ext = path95.extname(file3.path).toLowerCase();
83986
85089
  const langDef = getLanguageForExtension(ext);
83987
85090
  const fileProfile = getProfileForFile(file3.path);
83988
85091
  const langId = fileProfile?.id || langDef?.id;
@@ -83995,7 +85098,7 @@ async function syntaxCheck(input, directory, config3) {
83995
85098
  let skippedCount = 0;
83996
85099
  for (const fileInfo of filesToCheck) {
83997
85100
  const { path: filePath } = fileInfo;
83998
- const fullPath = path92.isAbsolute(filePath) ? filePath : path92.join(directory, filePath);
85101
+ const fullPath = path95.isAbsolute(filePath) ? filePath : path95.join(directory, filePath);
83999
85102
  const result = {
84000
85103
  path: filePath,
84001
85104
  language: "",
@@ -84025,7 +85128,7 @@ async function syntaxCheck(input, directory, config3) {
84025
85128
  }
84026
85129
  let content;
84027
85130
  try {
84028
- content = fs76.readFileSync(fullPath, "utf8");
85131
+ content = fs79.readFileSync(fullPath, "utf8");
84029
85132
  } catch {
84030
85133
  result.skipped_reason = "file_read_error";
84031
85134
  skippedCount++;
@@ -84044,7 +85147,7 @@ async function syntaxCheck(input, directory, config3) {
84044
85147
  results.push(result);
84045
85148
  continue;
84046
85149
  }
84047
- const ext = path92.extname(filePath).toLowerCase();
85150
+ const ext = path95.extname(filePath).toLowerCase();
84048
85151
  const langDef = getLanguageForExtension(ext);
84049
85152
  result.language = profile?.id || langDef?.id || "unknown";
84050
85153
  const errors5 = extractSyntaxErrors(parser, content);
@@ -84136,8 +85239,8 @@ init_dist();
84136
85239
  init_utils();
84137
85240
  init_create_tool();
84138
85241
  init_path_security();
84139
- import * as fs77 from "fs";
84140
- import * as path93 from "path";
85242
+ import * as fs80 from "fs";
85243
+ import * as path96 from "path";
84141
85244
  var MAX_TEXT_LENGTH = 200;
84142
85245
  var MAX_FILE_SIZE_BYTES11 = 1024 * 1024;
84143
85246
  var SUPPORTED_EXTENSIONS4 = new Set([
@@ -84203,9 +85306,9 @@ function validatePathsInput(paths, cwd) {
84203
85306
  return { error: "paths contains path traversal", resolvedPath: null };
84204
85307
  }
84205
85308
  try {
84206
- const resolvedPath = path93.resolve(paths);
84207
- const normalizedCwd = path93.resolve(cwd);
84208
- const normalizedResolved = path93.resolve(resolvedPath);
85309
+ const resolvedPath = path96.resolve(paths);
85310
+ const normalizedCwd = path96.resolve(cwd);
85311
+ const normalizedResolved = path96.resolve(resolvedPath);
84209
85312
  if (!normalizedResolved.startsWith(normalizedCwd)) {
84210
85313
  return {
84211
85314
  error: "paths must be within the current working directory",
@@ -84221,13 +85324,13 @@ function validatePathsInput(paths, cwd) {
84221
85324
  }
84222
85325
  }
84223
85326
  function isSupportedExtension(filePath) {
84224
- const ext = path93.extname(filePath).toLowerCase();
85327
+ const ext = path96.extname(filePath).toLowerCase();
84225
85328
  return SUPPORTED_EXTENSIONS4.has(ext);
84226
85329
  }
84227
85330
  function findSourceFiles4(dir, files = []) {
84228
85331
  let entries;
84229
85332
  try {
84230
- entries = fs77.readdirSync(dir);
85333
+ entries = fs80.readdirSync(dir);
84231
85334
  } catch {
84232
85335
  return files;
84233
85336
  }
@@ -84236,16 +85339,16 @@ function findSourceFiles4(dir, files = []) {
84236
85339
  if (SKIP_DIRECTORIES5.has(entry)) {
84237
85340
  continue;
84238
85341
  }
84239
- const fullPath = path93.join(dir, entry);
84240
- let stat3;
85342
+ const fullPath = path96.join(dir, entry);
85343
+ let stat4;
84241
85344
  try {
84242
- stat3 = fs77.statSync(fullPath);
85345
+ stat4 = fs80.statSync(fullPath);
84243
85346
  } catch {
84244
85347
  continue;
84245
85348
  }
84246
- if (stat3.isDirectory()) {
85349
+ if (stat4.isDirectory()) {
84247
85350
  findSourceFiles4(fullPath, files);
84248
- } else if (stat3.isFile()) {
85351
+ } else if (stat4.isFile()) {
84249
85352
  if (isSupportedExtension(fullPath)) {
84250
85353
  files.push(fullPath);
84251
85354
  }
@@ -84332,7 +85435,7 @@ var todo_extract = createSwarmTool({
84332
85435
  return JSON.stringify(errorResult, null, 2);
84333
85436
  }
84334
85437
  const scanPath = resolvedPath;
84335
- if (!fs77.existsSync(scanPath)) {
85438
+ if (!fs80.existsSync(scanPath)) {
84336
85439
  const errorResult = {
84337
85440
  error: `path not found: ${pathsInput}`,
84338
85441
  total: 0,
@@ -84342,13 +85445,13 @@ var todo_extract = createSwarmTool({
84342
85445
  return JSON.stringify(errorResult, null, 2);
84343
85446
  }
84344
85447
  const filesToScan = [];
84345
- const stat3 = fs77.statSync(scanPath);
84346
- if (stat3.isFile()) {
85448
+ const stat4 = fs80.statSync(scanPath);
85449
+ if (stat4.isFile()) {
84347
85450
  if (isSupportedExtension(scanPath)) {
84348
85451
  filesToScan.push(scanPath);
84349
85452
  } else {
84350
85453
  const errorResult = {
84351
- error: `unsupported file extension: ${path93.extname(scanPath)}`,
85454
+ error: `unsupported file extension: ${path96.extname(scanPath)}`,
84352
85455
  total: 0,
84353
85456
  byPriority: { high: 0, medium: 0, low: 0 },
84354
85457
  entries: []
@@ -84361,11 +85464,11 @@ var todo_extract = createSwarmTool({
84361
85464
  const allEntries = [];
84362
85465
  for (const filePath of filesToScan) {
84363
85466
  try {
84364
- const fileStat = fs77.statSync(filePath);
85467
+ const fileStat = fs80.statSync(filePath);
84365
85468
  if (fileStat.size > MAX_FILE_SIZE_BYTES11) {
84366
85469
  continue;
84367
85470
  }
84368
- const content = fs77.readFileSync(filePath, "utf-8");
85471
+ const content = fs80.readFileSync(filePath, "utf-8");
84369
85472
  const entries = parseTodoComments(content, filePath, tagsSet);
84370
85473
  allEntries.push(...entries);
84371
85474
  } catch {}
@@ -84395,18 +85498,18 @@ init_tool();
84395
85498
  init_loader();
84396
85499
  init_schema();
84397
85500
  init_gate_evidence();
84398
- import * as fs79 from "fs";
84399
- import * as path95 from "path";
85501
+ import * as fs82 from "fs";
85502
+ import * as path98 from "path";
84400
85503
 
84401
85504
  // src/hooks/diff-scope.ts
84402
- import * as fs78 from "fs";
84403
- import * as path94 from "path";
85505
+ import * as fs81 from "fs";
85506
+ import * as path97 from "path";
84404
85507
  function getDeclaredScope(taskId, directory) {
84405
85508
  try {
84406
- const planPath = path94.join(directory, ".swarm", "plan.json");
84407
- if (!fs78.existsSync(planPath))
85509
+ const planPath = path97.join(directory, ".swarm", "plan.json");
85510
+ if (!fs81.existsSync(planPath))
84408
85511
  return null;
84409
- const raw = fs78.readFileSync(planPath, "utf-8");
85512
+ const raw = fs81.readFileSync(planPath, "utf-8");
84410
85513
  const plan = JSON.parse(raw);
84411
85514
  for (const phase of plan.phases ?? []) {
84412
85515
  for (const task of phase.tasks ?? []) {
@@ -84522,7 +85625,7 @@ var TIER_3_PATTERNS = [
84522
85625
  ];
84523
85626
  function matchesTier3Pattern(files) {
84524
85627
  for (const file3 of files) {
84525
- const fileName = path95.basename(file3);
85628
+ const fileName = path98.basename(file3);
84526
85629
  for (const pattern of TIER_3_PATTERNS) {
84527
85630
  if (pattern.test(fileName)) {
84528
85631
  return true;
@@ -84536,8 +85639,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
84536
85639
  if (hasActiveTurboMode()) {
84537
85640
  const resolvedDir2 = workingDirectory;
84538
85641
  try {
84539
- const planPath = path95.join(resolvedDir2, ".swarm", "plan.json");
84540
- const planRaw = fs79.readFileSync(planPath, "utf-8");
85642
+ const planPath = path98.join(resolvedDir2, ".swarm", "plan.json");
85643
+ const planRaw = fs82.readFileSync(planPath, "utf-8");
84541
85644
  const plan = JSON.parse(planRaw);
84542
85645
  for (const planPhase of plan.phases ?? []) {
84543
85646
  for (const task of planPhase.tasks ?? []) {
@@ -84606,8 +85709,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
84606
85709
  }
84607
85710
  try {
84608
85711
  const resolvedDir2 = workingDirectory;
84609
- const planPath = path95.join(resolvedDir2, ".swarm", "plan.json");
84610
- const planRaw = fs79.readFileSync(planPath, "utf-8");
85712
+ const planPath = path98.join(resolvedDir2, ".swarm", "plan.json");
85713
+ const planRaw = fs82.readFileSync(planPath, "utf-8");
84611
85714
  const plan = JSON.parse(planRaw);
84612
85715
  for (const planPhase of plan.phases ?? []) {
84613
85716
  for (const task of planPhase.tasks ?? []) {
@@ -84831,8 +85934,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
84831
85934
  };
84832
85935
  }
84833
85936
  }
84834
- normalizedDir = path95.normalize(args2.working_directory);
84835
- const pathParts = normalizedDir.split(path95.sep);
85937
+ normalizedDir = path98.normalize(args2.working_directory);
85938
+ const pathParts = normalizedDir.split(path98.sep);
84836
85939
  if (pathParts.includes("..")) {
84837
85940
  return {
84838
85941
  success: false,
@@ -84842,11 +85945,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
84842
85945
  ]
84843
85946
  };
84844
85947
  }
84845
- const resolvedDir = path95.resolve(normalizedDir);
85948
+ const resolvedDir = path98.resolve(normalizedDir);
84846
85949
  try {
84847
- const realPath = fs79.realpathSync(resolvedDir);
84848
- const planPath = path95.join(realPath, ".swarm", "plan.json");
84849
- if (!fs79.existsSync(planPath)) {
85950
+ const realPath = fs82.realpathSync(resolvedDir);
85951
+ const planPath = path98.join(realPath, ".swarm", "plan.json");
85952
+ if (!fs82.existsSync(planPath)) {
84850
85953
  return {
84851
85954
  success: false,
84852
85955
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -84877,22 +85980,22 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
84877
85980
  }
84878
85981
  if (args2.status === "in_progress") {
84879
85982
  try {
84880
- const evidencePath = path95.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
84881
- fs79.mkdirSync(path95.dirname(evidencePath), { recursive: true });
84882
- const fd = fs79.openSync(evidencePath, "wx");
85983
+ const evidencePath = path98.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
85984
+ fs82.mkdirSync(path98.dirname(evidencePath), { recursive: true });
85985
+ const fd = fs82.openSync(evidencePath, "wx");
84883
85986
  let writeOk = false;
84884
85987
  try {
84885
- fs79.writeSync(fd, JSON.stringify({
85988
+ fs82.writeSync(fd, JSON.stringify({
84886
85989
  taskId: args2.task_id,
84887
85990
  required_gates: ["reviewer", "test_engineer"],
84888
85991
  gates: {}
84889
85992
  }, null, 2));
84890
85993
  writeOk = true;
84891
85994
  } finally {
84892
- fs79.closeSync(fd);
85995
+ fs82.closeSync(fd);
84893
85996
  if (!writeOk) {
84894
85997
  try {
84895
- fs79.unlinkSync(evidencePath);
85998
+ fs82.unlinkSync(evidencePath);
84896
85999
  } catch {}
84897
86000
  }
84898
86001
  }
@@ -84902,8 +86005,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
84902
86005
  recoverTaskStateFromDelegations(args2.task_id);
84903
86006
  let phaseRequiresReviewer = true;
84904
86007
  try {
84905
- const planPath = path95.join(directory, ".swarm", "plan.json");
84906
- const planRaw = fs79.readFileSync(planPath, "utf-8");
86008
+ const planPath = path98.join(directory, ".swarm", "plan.json");
86009
+ const planRaw = fs82.readFileSync(planPath, "utf-8");
84907
86010
  const plan = JSON.parse(planRaw);
84908
86011
  const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
84909
86012
  if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
@@ -85012,8 +86115,8 @@ init_utils2();
85012
86115
  init_ledger();
85013
86116
  init_manager();
85014
86117
  init_create_tool();
85015
- import fs80 from "fs";
85016
- import path96 from "path";
86118
+ import fs83 from "fs";
86119
+ import path99 from "path";
85017
86120
  function derivePlanId5(plan) {
85018
86121
  return `${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
85019
86122
  }
@@ -85064,7 +86167,7 @@ async function executeWriteDriftEvidence(args2, directory) {
85064
86167
  entries: [evidenceEntry]
85065
86168
  };
85066
86169
  const filename = "drift-verifier.json";
85067
- const relativePath = path96.join("evidence", String(phase), filename);
86170
+ const relativePath = path99.join("evidence", String(phase), filename);
85068
86171
  let validatedPath;
85069
86172
  try {
85070
86173
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -85075,12 +86178,12 @@ async function executeWriteDriftEvidence(args2, directory) {
85075
86178
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
85076
86179
  }, null, 2);
85077
86180
  }
85078
- const evidenceDir = path96.dirname(validatedPath);
86181
+ const evidenceDir = path99.dirname(validatedPath);
85079
86182
  try {
85080
- await fs80.promises.mkdir(evidenceDir, { recursive: true });
85081
- const tempPath = path96.join(evidenceDir, `.${filename}.tmp`);
85082
- await fs80.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
85083
- await fs80.promises.rename(tempPath, validatedPath);
86183
+ await fs83.promises.mkdir(evidenceDir, { recursive: true });
86184
+ const tempPath = path99.join(evidenceDir, `.${filename}.tmp`);
86185
+ await fs83.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
86186
+ await fs83.promises.rename(tempPath, validatedPath);
85084
86187
  let snapshotInfo;
85085
86188
  let snapshotError;
85086
86189
  let qaProfileLocked;
@@ -85174,8 +86277,8 @@ var write_drift_evidence = createSwarmTool({
85174
86277
  init_tool();
85175
86278
  init_utils2();
85176
86279
  init_create_tool();
85177
- import fs81 from "fs";
85178
- import path97 from "path";
86280
+ import fs84 from "fs";
86281
+ import path100 from "path";
85179
86282
  function normalizeVerdict2(verdict) {
85180
86283
  switch (verdict) {
85181
86284
  case "APPROVED":
@@ -85223,7 +86326,7 @@ async function executeWriteHallucinationEvidence(args2, directory) {
85223
86326
  entries: [evidenceEntry]
85224
86327
  };
85225
86328
  const filename = "hallucination-guard.json";
85226
- const relativePath = path97.join("evidence", String(phase), filename);
86329
+ const relativePath = path100.join("evidence", String(phase), filename);
85227
86330
  let validatedPath;
85228
86331
  try {
85229
86332
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -85234,12 +86337,12 @@ async function executeWriteHallucinationEvidence(args2, directory) {
85234
86337
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
85235
86338
  }, null, 2);
85236
86339
  }
85237
- const evidenceDir = path97.dirname(validatedPath);
86340
+ const evidenceDir = path100.dirname(validatedPath);
85238
86341
  try {
85239
- await fs81.promises.mkdir(evidenceDir, { recursive: true });
85240
- const tempPath = path97.join(evidenceDir, `.${filename}.tmp`);
85241
- await fs81.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
85242
- await fs81.promises.rename(tempPath, validatedPath);
86342
+ await fs84.promises.mkdir(evidenceDir, { recursive: true });
86343
+ const tempPath = path100.join(evidenceDir, `.${filename}.tmp`);
86344
+ await fs84.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
86345
+ await fs84.promises.rename(tempPath, validatedPath);
85243
86346
  return JSON.stringify({
85244
86347
  success: true,
85245
86348
  phase,
@@ -85346,6 +86449,11 @@ var OpenCodeSwarm = async (ctx) => {
85346
86449
  const contextBudgetHandler = createContextBudgetHandler(config3);
85347
86450
  const commandHandler = createSwarmCommandHandler(ctx.directory, Object.fromEntries(agentDefinitions.map((agent) => [agent.name, agent])));
85348
86451
  const activityHooks = createAgentActivityHooks(config3, ctx.directory);
86452
+ const prmHook = createPrmHook(config3.prm ?? PrmConfigSchema.parse({}), ctx.directory);
86453
+ const trajectoryLoggerHook = createTrajectoryLoggerHook({
86454
+ enabled: true,
86455
+ max_lines: 1000
86456
+ }, ctx.directory);
85349
86457
  const delegationGateHooks = createDelegationGateHook(config3, ctx.directory);
85350
86458
  const delegationSanitizerHook = createDelegationSanitizerHook(ctx.directory);
85351
86459
  const guardrailsFallback = config3.guardrails?.enabled === false ? { ...config3.guardrails, enabled: false } : config3.guardrails ?? {};
@@ -85448,7 +86556,7 @@ var OpenCodeSwarm = async (ctx) => {
85448
86556
  const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
85449
86557
  preflightTriggerManager = new PTM(automationConfig);
85450
86558
  const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
85451
- const swarmDir = path98.resolve(ctx.directory, ".swarm");
86559
+ const swarmDir = path101.resolve(ctx.directory, ".swarm");
85452
86560
  statusArtifact = new ASA(swarmDir);
85453
86561
  statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
85454
86562
  if (automationConfig.capabilities?.evidence_auto_summaries === true) {
@@ -85868,6 +86976,10 @@ var OpenCodeSwarm = async (ctx) => {
85868
86976
  await activityHooks.toolAfter(input, output);
85869
86977
  if (_dbg)
85870
86978
  console.error(`[DIAG] toolAfter activity done tool=${_toolName}`);
86979
+ await safeHook(trajectoryLoggerHook.toolAfter)(input, output);
86980
+ if (_dbg)
86981
+ console.error(`[DIAG] toolAfter trajectoryLogger done tool=${_toolName}`);
86982
+ await safeHook(prmHook.toolAfter)(input, output);
85871
86983
  await guardrailsHooks.toolAfter(input, output);
85872
86984
  if (_dbg)
85873
86985
  console.error(`[DIAG] toolAfter guardrails done tool=${_toolName}`);
@@ -85897,12 +87009,12 @@ var OpenCodeSwarm = async (ctx) => {
85897
87009
  } catch {}
85898
87010
  }
85899
87011
  try {
85900
- recordToolCall(normalizedTool, input.args);
87012
+ recordToolCall(normalizedTool, input.args, input.sessionID);
85901
87013
  } catch {}
85902
87014
  try {
85903
- const spiralMatch = await detectDebuggingSpiral(ctx.directory);
87015
+ const spiralMatch = await detectDebuggingSpiral(ctx.directory, input.sessionID);
85904
87016
  if (spiralMatch) {
85905
- const taskId = swarmState.agentSessions.get(input.sessionID)?.currentTaskId ?? "unknown";
87017
+ const taskId = swarmState.agentSessions.get(input.sessionID)?.currentTaskId ?? `session-${input.sessionID.slice(0, 12)}`;
85906
87018
  const spiralResult = await handleDebuggingSpiral(spiralMatch, taskId, ctx.directory);
85907
87019
  const session = swarmState.agentSessions.get(input.sessionID);
85908
87020
  if (session) {