opencode-swarm 6.80.2 → 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();
@@ -70563,6 +70648,996 @@ function createSteeringConsumedHook(directory) {
70563
70648
  return safeHook(hook);
70564
70649
  }
70565
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
+
70566
71641
  // src/index.ts
70567
71642
  init_compaction_service();
70568
71643
  init_config_doctor();
@@ -70666,6 +71741,11 @@ function deserializeAgentSession(s) {
70666
71741
  fullAutoInteractionCount: s.fullAutoInteractionCount ?? 0,
70667
71742
  fullAutoDeadlockCount: s.fullAutoDeadlockCount ?? 0,
70668
71743
  fullAutoLastQuestionHash: s.fullAutoLastQuestionHash ?? null,
71744
+ prmPatternCounts: new Map,
71745
+ prmEscalationLevel: 0,
71746
+ prmLastPatternDetected: null,
71747
+ prmTrajectoryStep: 0,
71748
+ prmHardStopPending: false,
70669
71749
  sessionRehydratedAt: s.sessionRehydratedAt ?? 0
70670
71750
  };
70671
71751
  }
@@ -70771,8 +71851,8 @@ init_telemetry();
70771
71851
  // src/tools/batch-symbols.ts
70772
71852
  init_tool();
70773
71853
  init_create_tool();
70774
- import * as fs51 from "fs";
70775
- import * as path65 from "path";
71854
+ import * as fs54 from "fs";
71855
+ import * as path68 from "path";
70776
71856
  init_path_security();
70777
71857
  var WINDOWS_RESERVED_NAMES2 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
70778
71858
  function containsWindowsAttacks2(str) {
@@ -70789,14 +71869,14 @@ function containsWindowsAttacks2(str) {
70789
71869
  }
70790
71870
  function isPathInWorkspace2(filePath, workspace) {
70791
71871
  try {
70792
- const resolvedPath = path65.resolve(workspace, filePath);
70793
- if (!fs51.existsSync(resolvedPath)) {
71872
+ const resolvedPath = path68.resolve(workspace, filePath);
71873
+ if (!fs54.existsSync(resolvedPath)) {
70794
71874
  return true;
70795
71875
  }
70796
- const realWorkspace = fs51.realpathSync(workspace);
70797
- const realResolvedPath = fs51.realpathSync(resolvedPath);
70798
- const relativePath = path65.relative(realWorkspace, realResolvedPath);
70799
- 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)) {
70800
71880
  return false;
70801
71881
  }
70802
71882
  return true;
@@ -70805,7 +71885,7 @@ function isPathInWorkspace2(filePath, workspace) {
70805
71885
  }
70806
71886
  }
70807
71887
  function processFile2(file3, cwd, exportedOnly) {
70808
- const ext = path65.extname(file3);
71888
+ const ext = path68.extname(file3);
70809
71889
  if (containsControlChars(file3)) {
70810
71890
  return {
70811
71891
  file: file3,
@@ -70838,8 +71918,8 @@ function processFile2(file3, cwd, exportedOnly) {
70838
71918
  errorType: "path-outside-workspace"
70839
71919
  };
70840
71920
  }
70841
- const fullPath = path65.join(cwd, file3);
70842
- if (!fs51.existsSync(fullPath)) {
71921
+ const fullPath = path68.join(cwd, file3);
71922
+ if (!fs54.existsSync(fullPath)) {
70843
71923
  return {
70844
71924
  file: file3,
70845
71925
  success: false,
@@ -70870,14 +71950,14 @@ function processFile2(file3, cwd, exportedOnly) {
70870
71950
  }
70871
71951
  let isEmptyFile = false;
70872
71952
  try {
70873
- const stats = fs51.statSync(fullPath);
71953
+ const stats = fs54.statSync(fullPath);
70874
71954
  if (stats.size === 0) {
70875
71955
  isEmptyFile = true;
70876
71956
  }
70877
71957
  } catch {}
70878
71958
  if (syms.length === 0) {
70879
71959
  try {
70880
- const content = fs51.readFileSync(fullPath, "utf-8");
71960
+ const content = fs54.readFileSync(fullPath, "utf-8");
70881
71961
  if (content.trim().length === 0) {
70882
71962
  isEmptyFile = true;
70883
71963
  }
@@ -71129,25 +72209,25 @@ init_manager2();
71129
72209
  init_task_id();
71130
72210
  init_create_tool();
71131
72211
  init_resolve_working_directory();
71132
- import * as fs52 from "fs";
71133
- import * as path66 from "path";
72212
+ import * as fs55 from "fs";
72213
+ import * as path69 from "path";
71134
72214
  var EVIDENCE_DIR = ".swarm/evidence";
71135
72215
  function isValidTaskId3(taskId) {
71136
72216
  return isStrictTaskId(taskId);
71137
72217
  }
71138
72218
  function isPathWithinSwarm(filePath, workspaceRoot) {
71139
- const normalizedWorkspace = path66.resolve(workspaceRoot);
71140
- const swarmPath = path66.join(normalizedWorkspace, ".swarm", "evidence");
71141
- 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);
71142
72222
  return normalizedPath.startsWith(swarmPath);
71143
72223
  }
71144
72224
  function readEvidenceFile(evidencePath) {
71145
- if (!fs52.existsSync(evidencePath)) {
72225
+ if (!fs55.existsSync(evidencePath)) {
71146
72226
  return null;
71147
72227
  }
71148
72228
  let content;
71149
72229
  try {
71150
- content = fs52.readFileSync(evidencePath, "utf-8");
72230
+ content = fs55.readFileSync(evidencePath, "utf-8");
71151
72231
  } catch {
71152
72232
  return null;
71153
72233
  }
@@ -71219,7 +72299,7 @@ var check_gate_status = createSwarmTool({
71219
72299
  };
71220
72300
  return JSON.stringify(errorResult, null, 2);
71221
72301
  }
71222
- const evidencePath = path66.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
72302
+ const evidencePath = path69.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
71223
72303
  if (!isPathWithinSwarm(evidencePath, directory)) {
71224
72304
  const errorResult = {
71225
72305
  taskId: taskIdInput,
@@ -71315,8 +72395,8 @@ init_utils2();
71315
72395
  init_state();
71316
72396
  init_create_tool();
71317
72397
  init_resolve_working_directory();
71318
- import * as fs53 from "fs";
71319
- import * as path67 from "path";
72398
+ import * as fs56 from "fs";
72399
+ import * as path70 from "path";
71320
72400
  function extractMatches(regex, text) {
71321
72401
  return Array.from(text.matchAll(regex));
71322
72402
  }
@@ -71410,7 +72490,7 @@ async function executeCompletionVerify(args2, directory) {
71410
72490
  let plan;
71411
72491
  try {
71412
72492
  const planPath = validateSwarmPath(directory, "plan.json");
71413
- const planRaw = fs53.readFileSync(planPath, "utf-8");
72493
+ const planRaw = fs56.readFileSync(planPath, "utf-8");
71414
72494
  plan = JSON.parse(planRaw);
71415
72495
  } catch {
71416
72496
  const result2 = {
@@ -71468,10 +72548,10 @@ async function executeCompletionVerify(args2, directory) {
71468
72548
  let hasFileReadFailure = false;
71469
72549
  for (const filePath of fileTargets) {
71470
72550
  const normalizedPath = filePath.replace(/\\/g, "/");
71471
- const resolvedPath = path67.resolve(directory, normalizedPath);
71472
- const projectRoot = path67.resolve(directory);
71473
- const relative16 = path67.relative(projectRoot, resolvedPath);
71474
- 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);
71475
72555
  if (!withinProject) {
71476
72556
  blockedTasks.push({
71477
72557
  task_id: task.id,
@@ -71484,7 +72564,7 @@ async function executeCompletionVerify(args2, directory) {
71484
72564
  }
71485
72565
  let fileContent;
71486
72566
  try {
71487
- fileContent = fs53.readFileSync(resolvedPath, "utf-8");
72567
+ fileContent = fs56.readFileSync(resolvedPath, "utf-8");
71488
72568
  } catch {
71489
72569
  blockedTasks.push({
71490
72570
  task_id: task.id,
@@ -71526,9 +72606,9 @@ async function executeCompletionVerify(args2, directory) {
71526
72606
  blockedTasks
71527
72607
  };
71528
72608
  try {
71529
- const evidenceDir = path67.join(directory, ".swarm", "evidence", `${phase}`);
71530
- const evidencePath = path67.join(evidenceDir, "completion-verify.json");
71531
- 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 });
71532
72612
  const evidenceBundle = {
71533
72613
  schema_version: "1.0.0",
71534
72614
  task_id: "completion-verify",
@@ -71549,7 +72629,7 @@ async function executeCompletionVerify(args2, directory) {
71549
72629
  }
71550
72630
  ]
71551
72631
  };
71552
- fs53.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
72632
+ fs56.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
71553
72633
  } catch {}
71554
72634
  return JSON.stringify(result, null, 2);
71555
72635
  }
@@ -71603,12 +72683,12 @@ var completion_verify = createSwarmTool({
71603
72683
  });
71604
72684
  // src/tools/complexity-hotspots.ts
71605
72685
  init_dist();
71606
- import * as fs55 from "fs";
71607
- import * as path69 from "path";
72686
+ import * as fs58 from "fs";
72687
+ import * as path72 from "path";
71608
72688
 
71609
72689
  // src/quality/metrics.ts
71610
- import * as fs54 from "fs";
71611
- import * as path68 from "path";
72690
+ import * as fs57 from "fs";
72691
+ import * as path71 from "path";
71612
72692
  var MAX_FILE_SIZE_BYTES4 = 256 * 1024;
71613
72693
  var MIN_DUPLICATION_LINES = 10;
71614
72694
  function estimateCyclomaticComplexity(content) {
@@ -71646,11 +72726,11 @@ function estimateCyclomaticComplexity(content) {
71646
72726
  }
71647
72727
  function getComplexityForFile(filePath) {
71648
72728
  try {
71649
- const stat3 = fs54.statSync(filePath);
71650
- if (stat3.size > MAX_FILE_SIZE_BYTES4) {
72729
+ const stat4 = fs57.statSync(filePath);
72730
+ if (stat4.size > MAX_FILE_SIZE_BYTES4) {
71651
72731
  return null;
71652
72732
  }
71653
- const content = fs54.readFileSync(filePath, "utf-8");
72733
+ const content = fs57.readFileSync(filePath, "utf-8");
71654
72734
  return estimateCyclomaticComplexity(content);
71655
72735
  } catch {
71656
72736
  return null;
@@ -71660,8 +72740,8 @@ async function computeComplexityDelta(files, workingDir) {
71660
72740
  let totalComplexity = 0;
71661
72741
  const analyzedFiles = [];
71662
72742
  for (const file3 of files) {
71663
- const fullPath = path68.isAbsolute(file3) ? file3 : path68.join(workingDir, file3);
71664
- if (!fs54.existsSync(fullPath)) {
72743
+ const fullPath = path71.isAbsolute(file3) ? file3 : path71.join(workingDir, file3);
72744
+ if (!fs57.existsSync(fullPath)) {
71665
72745
  continue;
71666
72746
  }
71667
72747
  const complexity = getComplexityForFile(fullPath);
@@ -71782,8 +72862,8 @@ function countGoExports(content) {
71782
72862
  }
71783
72863
  function getExportCountForFile(filePath) {
71784
72864
  try {
71785
- const content = fs54.readFileSync(filePath, "utf-8");
71786
- const ext = path68.extname(filePath).toLowerCase();
72865
+ const content = fs57.readFileSync(filePath, "utf-8");
72866
+ const ext = path71.extname(filePath).toLowerCase();
71787
72867
  switch (ext) {
71788
72868
  case ".ts":
71789
72869
  case ".tsx":
@@ -71809,8 +72889,8 @@ async function computePublicApiDelta(files, workingDir) {
71809
72889
  let totalExports = 0;
71810
72890
  const analyzedFiles = [];
71811
72891
  for (const file3 of files) {
71812
- const fullPath = path68.isAbsolute(file3) ? file3 : path68.join(workingDir, file3);
71813
- if (!fs54.existsSync(fullPath)) {
72892
+ const fullPath = path71.isAbsolute(file3) ? file3 : path71.join(workingDir, file3);
72893
+ if (!fs57.existsSync(fullPath)) {
71814
72894
  continue;
71815
72895
  }
71816
72896
  const exports = getExportCountForFile(fullPath);
@@ -71843,16 +72923,16 @@ async function computeDuplicationRatio(files, workingDir) {
71843
72923
  let duplicateLines = 0;
71844
72924
  const analyzedFiles = [];
71845
72925
  for (const file3 of files) {
71846
- const fullPath = path68.isAbsolute(file3) ? file3 : path68.join(workingDir, file3);
71847
- if (!fs54.existsSync(fullPath)) {
72926
+ const fullPath = path71.isAbsolute(file3) ? file3 : path71.join(workingDir, file3);
72927
+ if (!fs57.existsSync(fullPath)) {
71848
72928
  continue;
71849
72929
  }
71850
72930
  try {
71851
- const stat3 = fs54.statSync(fullPath);
71852
- if (stat3.size > MAX_FILE_SIZE_BYTES4) {
72931
+ const stat4 = fs57.statSync(fullPath);
72932
+ if (stat4.size > MAX_FILE_SIZE_BYTES4) {
71853
72933
  continue;
71854
72934
  }
71855
- const content = fs54.readFileSync(fullPath, "utf-8");
72935
+ const content = fs57.readFileSync(fullPath, "utf-8");
71856
72936
  const lines = content.split(`
71857
72937
  `).filter((line) => line.trim().length > 0);
71858
72938
  if (lines.length < MIN_DUPLICATION_LINES) {
@@ -71876,8 +72956,8 @@ function countCodeLines(content) {
71876
72956
  return lines.length;
71877
72957
  }
71878
72958
  function isTestFile(filePath) {
71879
- const basename10 = path68.basename(filePath);
71880
- const _ext = path68.extname(filePath).toLowerCase();
72959
+ const basename10 = path71.basename(filePath);
72960
+ const _ext = path71.extname(filePath).toLowerCase();
71881
72961
  const testPatterns = [
71882
72962
  ".test.",
71883
72963
  ".spec.",
@@ -71958,8 +73038,8 @@ function matchGlobSegment(globSegments, pathSegments) {
71958
73038
  }
71959
73039
  return gIndex === globSegments.length && pIndex === pathSegments.length;
71960
73040
  }
71961
- function matchesGlobSegment(path69, glob) {
71962
- const normalizedPath = path69.replace(/\\/g, "/");
73041
+ function matchesGlobSegment(path72, glob) {
73042
+ const normalizedPath = path72.replace(/\\/g, "/");
71963
73043
  const normalizedGlob = glob.replace(/\\/g, "/");
71964
73044
  if (normalizedPath.includes("//")) {
71965
73045
  return false;
@@ -71990,8 +73070,8 @@ function simpleGlobToRegex2(glob) {
71990
73070
  function hasGlobstar(glob) {
71991
73071
  return glob.includes("**");
71992
73072
  }
71993
- function globMatches(path69, glob) {
71994
- const normalizedPath = path69.replace(/\\/g, "/");
73073
+ function globMatches(path72, glob) {
73074
+ const normalizedPath = path72.replace(/\\/g, "/");
71995
73075
  if (!glob || glob === "") {
71996
73076
  if (normalizedPath.includes("//")) {
71997
73077
  return false;
@@ -72027,31 +73107,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
72027
73107
  async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
72028
73108
  let testLines = 0;
72029
73109
  let codeLines = 0;
72030
- const srcDir = path68.join(workingDir, "src");
72031
- if (fs54.existsSync(srcDir)) {
73110
+ const srcDir = path71.join(workingDir, "src");
73111
+ if (fs57.existsSync(srcDir)) {
72032
73112
  await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
72033
73113
  codeLines += lines;
72034
73114
  });
72035
73115
  }
72036
73116
  const possibleSrcDirs = ["lib", "app", "source", "core"];
72037
73117
  for (const dir of possibleSrcDirs) {
72038
- const dirPath = path68.join(workingDir, dir);
72039
- if (fs54.existsSync(dirPath)) {
73118
+ const dirPath = path71.join(workingDir, dir);
73119
+ if (fs57.existsSync(dirPath)) {
72040
73120
  await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
72041
73121
  codeLines += lines;
72042
73122
  });
72043
73123
  }
72044
73124
  }
72045
- const testsDir = path68.join(workingDir, "tests");
72046
- if (fs54.existsSync(testsDir)) {
73125
+ const testsDir = path71.join(workingDir, "tests");
73126
+ if (fs57.existsSync(testsDir)) {
72047
73127
  await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
72048
73128
  testLines += lines;
72049
73129
  });
72050
73130
  }
72051
73131
  const possibleTestDirs = ["test", "__tests__", "specs"];
72052
73132
  for (const dir of possibleTestDirs) {
72053
- const dirPath = path68.join(workingDir, dir);
72054
- if (fs54.existsSync(dirPath) && dirPath !== testsDir) {
73133
+ const dirPath = path71.join(workingDir, dir);
73134
+ if (fs57.existsSync(dirPath) && dirPath !== testsDir) {
72055
73135
  await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
72056
73136
  testLines += lines;
72057
73137
  });
@@ -72063,9 +73143,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
72063
73143
  }
72064
73144
  async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
72065
73145
  try {
72066
- const entries = fs54.readdirSync(dirPath, { withFileTypes: true });
73146
+ const entries = fs57.readdirSync(dirPath, { withFileTypes: true });
72067
73147
  for (const entry of entries) {
72068
- const fullPath = path68.join(dirPath, entry.name);
73148
+ const fullPath = path71.join(dirPath, entry.name);
72069
73149
  if (entry.isDirectory()) {
72070
73150
  if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
72071
73151
  continue;
@@ -72073,7 +73153,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
72073
73153
  await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
72074
73154
  } else if (entry.isFile()) {
72075
73155
  const relativePath = fullPath.replace(`${dirPath}/`, "");
72076
- const ext = path68.extname(entry.name).toLowerCase();
73156
+ const ext = path71.extname(entry.name).toLowerCase();
72077
73157
  const validExts = [
72078
73158
  ".ts",
72079
73159
  ".tsx",
@@ -72109,7 +73189,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
72109
73189
  continue;
72110
73190
  }
72111
73191
  try {
72112
- const content = fs54.readFileSync(fullPath, "utf-8");
73192
+ const content = fs57.readFileSync(fullPath, "utf-8");
72113
73193
  const lines = countCodeLines(content);
72114
73194
  callback(lines);
72115
73195
  } catch {}
@@ -72311,11 +73391,11 @@ async function getGitChurn(days, directory) {
72311
73391
  }
72312
73392
  function getComplexityForFile2(filePath) {
72313
73393
  try {
72314
- const stat3 = fs55.statSync(filePath);
72315
- if (stat3.size > MAX_FILE_SIZE_BYTES5) {
73394
+ const stat4 = fs58.statSync(filePath);
73395
+ if (stat4.size > MAX_FILE_SIZE_BYTES5) {
72316
73396
  return null;
72317
73397
  }
72318
- const content = fs55.readFileSync(filePath, "utf-8");
73398
+ const content = fs58.readFileSync(filePath, "utf-8");
72319
73399
  return estimateCyclomaticComplexity(content);
72320
73400
  } catch {
72321
73401
  return null;
@@ -72326,7 +73406,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
72326
73406
  const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
72327
73407
  const filteredChurn = new Map;
72328
73408
  for (const [file3, count] of churnMap) {
72329
- const ext = path69.extname(file3).toLowerCase();
73409
+ const ext = path72.extname(file3).toLowerCase();
72330
73410
  if (extSet.has(ext)) {
72331
73411
  filteredChurn.set(file3, count);
72332
73412
  }
@@ -72336,8 +73416,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
72336
73416
  let analyzedFiles = 0;
72337
73417
  for (const [file3, churnCount] of filteredChurn) {
72338
73418
  let fullPath = file3;
72339
- if (!fs55.existsSync(fullPath)) {
72340
- fullPath = path69.join(cwd, file3);
73419
+ if (!fs58.existsSync(fullPath)) {
73420
+ fullPath = path72.join(cwd, file3);
72341
73421
  }
72342
73422
  const complexity = getComplexityForFile2(fullPath);
72343
73423
  if (complexity !== null) {
@@ -72512,7 +73592,7 @@ import {
72512
73592
  readFileSync as readFileSync37,
72513
73593
  writeFileSync as writeFileSync11
72514
73594
  } from "fs";
72515
- import { join as join63 } from "path";
73595
+ import { join as join65 } from "path";
72516
73596
  var EVIDENCE_DIR2 = ".swarm/evidence";
72517
73597
  var VALID_TASK_ID = /^\d+\.\d+(\.\d+)*$/;
72518
73598
  var COUNCIL_GATE_NAME = "council";
@@ -72546,9 +73626,9 @@ function writeCouncilEvidence(workingDir, synthesis) {
72546
73626
  if (!VALID_TASK_ID.test(synthesis.taskId)) {
72547
73627
  throw new Error(`writeCouncilEvidence: invalid taskId "${synthesis.taskId}" \u2014 must match N.M or N.M.P format`);
72548
73628
  }
72549
- const dir = join63(workingDir, EVIDENCE_DIR2);
73629
+ const dir = join65(workingDir, EVIDENCE_DIR2);
72550
73630
  mkdirSync18(dir, { recursive: true });
72551
- const filePath = join63(dir, `${synthesis.taskId}.json`);
73631
+ const filePath = join65(dir, `${synthesis.taskId}.json`);
72552
73632
  const existingRoot = Object.create(null);
72553
73633
  if (existsSync37(filePath)) {
72554
73634
  try {
@@ -72581,7 +73661,7 @@ function writeCouncilEvidence(workingDir, synthesis) {
72581
73661
  updated.required_gates = [];
72582
73662
  writeFileSync11(filePath, JSON.stringify(updated, null, 2));
72583
73663
  try {
72584
- const councilDir = join63(workingDir, ".swarm", "council");
73664
+ const councilDir = join65(workingDir, ".swarm", "council");
72585
73665
  mkdirSync18(councilDir, { recursive: true });
72586
73666
  const auditLine = JSON.stringify({
72587
73667
  round: synthesis.roundNumber,
@@ -72589,7 +73669,7 @@ function writeCouncilEvidence(workingDir, synthesis) {
72589
73669
  timestamp: synthesis.timestamp,
72590
73670
  vetoedBy: synthesis.vetoedBy
72591
73671
  });
72592
- appendFileSync7(join63(councilDir, `${synthesis.taskId}.rounds.jsonl`), `${auditLine}
73672
+ appendFileSync7(join65(councilDir, `${synthesis.taskId}.rounds.jsonl`), `${auditLine}
72593
73673
  `);
72594
73674
  } catch (auditError) {
72595
73675
  console.warn(`writeCouncilEvidence: failed to append round-history audit log: ${auditError instanceof Error ? auditError.message : String(auditError)}`);
@@ -72719,20 +73799,20 @@ function buildUnifiedFeedback(taskId, verdict, vetoedBy, requiredFixes, advisory
72719
73799
 
72720
73800
  // src/council/criteria-store.ts
72721
73801
  import { existsSync as existsSync38, mkdirSync as mkdirSync19, readFileSync as readFileSync38, writeFileSync as writeFileSync12 } from "fs";
72722
- import { join as join64 } from "path";
73802
+ import { join as join66 } from "path";
72723
73803
  var COUNCIL_DIR = ".swarm/council";
72724
73804
  function writeCriteria(workingDir, taskId, criteria) {
72725
- const dir = join64(workingDir, COUNCIL_DIR);
73805
+ const dir = join66(workingDir, COUNCIL_DIR);
72726
73806
  mkdirSync19(dir, { recursive: true });
72727
73807
  const payload = {
72728
73808
  taskId,
72729
73809
  criteria,
72730
73810
  declaredAt: new Date().toISOString()
72731
73811
  };
72732
- writeFileSync12(join64(dir, `${safeId(taskId)}.json`), JSON.stringify(payload, null, 2));
73812
+ writeFileSync12(join66(dir, `${safeId(taskId)}.json`), JSON.stringify(payload, null, 2));
72733
73813
  }
72734
73814
  function readCriteria(workingDir, taskId) {
72735
- const filePath = join64(workingDir, COUNCIL_DIR, `${safeId(taskId)}.json`);
73815
+ const filePath = join66(workingDir, COUNCIL_DIR, `${safeId(taskId)}.json`);
72736
73816
  if (!existsSync38(filePath))
72737
73817
  return null;
72738
73818
  try {
@@ -73069,8 +74149,8 @@ init_scope_persistence();
73069
74149
  init_state();
73070
74150
  init_task_id();
73071
74151
  init_create_tool();
73072
- import * as fs56 from "fs";
73073
- import * as path70 from "path";
74152
+ import * as fs59 from "fs";
74153
+ import * as path73 from "path";
73074
74154
  function validateTaskIdFormat2(taskId) {
73075
74155
  return validateTaskIdFormat(taskId);
73076
74156
  }
@@ -73144,8 +74224,8 @@ async function executeDeclareScope(args2, fallbackDir) {
73144
74224
  };
73145
74225
  }
73146
74226
  }
73147
- normalizedDir = path70.normalize(args2.working_directory);
73148
- const pathParts = normalizedDir.split(path70.sep);
74227
+ normalizedDir = path73.normalize(args2.working_directory);
74228
+ const pathParts = normalizedDir.split(path73.sep);
73149
74229
  if (pathParts.includes("..")) {
73150
74230
  return {
73151
74231
  success: false,
@@ -73155,11 +74235,11 @@ async function executeDeclareScope(args2, fallbackDir) {
73155
74235
  ]
73156
74236
  };
73157
74237
  }
73158
- const resolvedDir = path70.resolve(normalizedDir);
74238
+ const resolvedDir = path73.resolve(normalizedDir);
73159
74239
  try {
73160
- const realPath = fs56.realpathSync(resolvedDir);
73161
- const planPath2 = path70.join(realPath, ".swarm", "plan.json");
73162
- if (!fs56.existsSync(planPath2)) {
74240
+ const realPath = fs59.realpathSync(resolvedDir);
74241
+ const planPath2 = path73.join(realPath, ".swarm", "plan.json");
74242
+ if (!fs59.existsSync(planPath2)) {
73163
74243
  return {
73164
74244
  success: false,
73165
74245
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -73182,8 +74262,8 @@ async function executeDeclareScope(args2, fallbackDir) {
73182
74262
  console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
73183
74263
  }
73184
74264
  const directory = normalizedDir || fallbackDir;
73185
- const planPath = path70.resolve(directory, ".swarm", "plan.json");
73186
- if (!fs56.existsSync(planPath)) {
74265
+ const planPath = path73.resolve(directory, ".swarm", "plan.json");
74266
+ if (!fs59.existsSync(planPath)) {
73187
74267
  return {
73188
74268
  success: false,
73189
74269
  message: "No plan found",
@@ -73192,7 +74272,7 @@ async function executeDeclareScope(args2, fallbackDir) {
73192
74272
  }
73193
74273
  let planContent;
73194
74274
  try {
73195
- planContent = JSON.parse(fs56.readFileSync(planPath, "utf-8"));
74275
+ planContent = JSON.parse(fs59.readFileSync(planPath, "utf-8"));
73196
74276
  } catch {
73197
74277
  return {
73198
74278
  success: false,
@@ -73222,8 +74302,8 @@ async function executeDeclareScope(args2, fallbackDir) {
73222
74302
  const normalizeErrors = [];
73223
74303
  const dir = normalizedDir || fallbackDir || process.cwd();
73224
74304
  const mergedFiles = rawMergedFiles.map((file3) => {
73225
- if (path70.isAbsolute(file3)) {
73226
- const relativePath = path70.relative(dir, file3).replace(/\\/g, "/");
74305
+ if (path73.isAbsolute(file3)) {
74306
+ const relativePath = path73.relative(dir, file3).replace(/\\/g, "/");
73227
74307
  if (relativePath.startsWith("..")) {
73228
74308
  normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
73229
74309
  return file3;
@@ -73283,8 +74363,8 @@ var declare_scope = createSwarmTool({
73283
74363
  // src/tools/diff.ts
73284
74364
  init_dist();
73285
74365
  import * as child_process7 from "child_process";
73286
- import * as fs57 from "fs";
73287
- import * as path71 from "path";
74366
+ import * as fs60 from "fs";
74367
+ import * as path74 from "path";
73288
74368
  init_create_tool();
73289
74369
  var MAX_DIFF_LINES = 500;
73290
74370
  var DIFF_TIMEOUT_MS = 30000;
@@ -73313,20 +74393,20 @@ function validateBase(base) {
73313
74393
  function validatePaths(paths) {
73314
74394
  if (!paths)
73315
74395
  return null;
73316
- for (const path72 of paths) {
73317
- if (!path72 || path72.length === 0) {
74396
+ for (const path75 of paths) {
74397
+ if (!path75 || path75.length === 0) {
73318
74398
  return "empty path not allowed";
73319
74399
  }
73320
- if (path72.length > MAX_PATH_LENGTH) {
74400
+ if (path75.length > MAX_PATH_LENGTH) {
73321
74401
  return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
73322
74402
  }
73323
- if (SHELL_METACHARACTERS2.test(path72)) {
74403
+ if (SHELL_METACHARACTERS2.test(path75)) {
73324
74404
  return "path contains shell metacharacters";
73325
74405
  }
73326
- if (path72.startsWith("-")) {
74406
+ if (path75.startsWith("-")) {
73327
74407
  return 'path cannot start with "-" (option-like arguments not allowed)';
73328
74408
  }
73329
- if (CONTROL_CHAR_PATTERN2.test(path72)) {
74409
+ if (CONTROL_CHAR_PATTERN2.test(path75)) {
73330
74410
  return "path contains control characters";
73331
74411
  }
73332
74412
  }
@@ -73432,8 +74512,8 @@ var diff = createSwarmTool({
73432
74512
  if (parts2.length >= 3) {
73433
74513
  const additions = parseInt(parts2[0], 10) || 0;
73434
74514
  const deletions = parseInt(parts2[1], 10) || 0;
73435
- const path72 = parts2[2];
73436
- files.push({ path: path72, additions, deletions });
74515
+ const path75 = parts2[2];
74516
+ files.push({ path: path75, additions, deletions });
73437
74517
  }
73438
74518
  }
73439
74519
  const contractChanges = [];
@@ -73473,7 +74553,7 @@ var diff = createSwarmTool({
73473
74553
  } else if (base === "unstaged") {
73474
74554
  const oldRef = `:${file3.path}`;
73475
74555
  oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
73476
- newContent = fs57.readFileSync(path71.join(directory, file3.path), "utf-8");
74556
+ newContent = fs60.readFileSync(path74.join(directory, file3.path), "utf-8");
73477
74557
  } else {
73478
74558
  const oldRef = `${base}:${file3.path}`;
73479
74559
  oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
@@ -73547,8 +74627,8 @@ var diff = createSwarmTool({
73547
74627
  // src/tools/diff-summary.ts
73548
74628
  init_dist();
73549
74629
  import * as child_process8 from "child_process";
73550
- import * as fs58 from "fs";
73551
- import * as path72 from "path";
74630
+ import * as fs61 from "fs";
74631
+ import * as path75 from "path";
73552
74632
  init_create_tool();
73553
74633
  var diff_summary = createSwarmTool({
73554
74634
  description: "Generate a filtered semantic diff summary from AST analysis. Returns SemanticDiffSummary with optional filtering by classification or riskLevel.",
@@ -73596,7 +74676,7 @@ var diff_summary = createSwarmTool({
73596
74676
  }
73597
74677
  try {
73598
74678
  let oldContent;
73599
- const newContent = fs58.readFileSync(path72.join(workingDir, filePath), "utf-8");
74679
+ const newContent = fs61.readFileSync(path75.join(workingDir, filePath), "utf-8");
73600
74680
  if (fileExistsInHead) {
73601
74681
  oldContent = child_process8.execFileSync("git", ["show", `HEAD:${filePath}`], {
73602
74682
  encoding: "utf-8",
@@ -73823,8 +74903,8 @@ Use these as DOMAIN values when delegating to @sme.`;
73823
74903
  init_dist();
73824
74904
  init_create_tool();
73825
74905
  init_path_security();
73826
- import * as fs59 from "fs";
73827
- import * as path73 from "path";
74906
+ import * as fs62 from "fs";
74907
+ import * as path76 from "path";
73828
74908
  var MAX_FILE_SIZE_BYTES6 = 1024 * 1024;
73829
74909
  var MAX_EVIDENCE_FILES = 1000;
73830
74910
  var EVIDENCE_DIR3 = ".swarm/evidence";
@@ -73851,9 +74931,9 @@ function validateRequiredTypes(input) {
73851
74931
  return null;
73852
74932
  }
73853
74933
  function isPathWithinSwarm2(filePath, cwd) {
73854
- const normalizedCwd = path73.resolve(cwd);
73855
- const swarmPath = path73.join(normalizedCwd, ".swarm");
73856
- const normalizedPath = path73.resolve(filePath);
74934
+ const normalizedCwd = path76.resolve(cwd);
74935
+ const swarmPath = path76.join(normalizedCwd, ".swarm");
74936
+ const normalizedPath = path76.resolve(filePath);
73857
74937
  return normalizedPath.startsWith(swarmPath);
73858
74938
  }
73859
74939
  function parseCompletedTasks(planContent) {
@@ -73869,12 +74949,12 @@ function parseCompletedTasks(planContent) {
73869
74949
  }
73870
74950
  function readEvidenceFiles(evidenceDir, _cwd) {
73871
74951
  const evidence = [];
73872
- if (!fs59.existsSync(evidenceDir) || !fs59.statSync(evidenceDir).isDirectory()) {
74952
+ if (!fs62.existsSync(evidenceDir) || !fs62.statSync(evidenceDir).isDirectory()) {
73873
74953
  return evidence;
73874
74954
  }
73875
74955
  let files;
73876
74956
  try {
73877
- files = fs59.readdirSync(evidenceDir);
74957
+ files = fs62.readdirSync(evidenceDir);
73878
74958
  } catch {
73879
74959
  return evidence;
73880
74960
  }
@@ -73883,15 +74963,15 @@ function readEvidenceFiles(evidenceDir, _cwd) {
73883
74963
  if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
73884
74964
  continue;
73885
74965
  }
73886
- const filePath = path73.join(evidenceDir, filename);
74966
+ const filePath = path76.join(evidenceDir, filename);
73887
74967
  try {
73888
- const resolvedPath = path73.resolve(filePath);
73889
- const evidenceDirResolved = path73.resolve(evidenceDir);
74968
+ const resolvedPath = path76.resolve(filePath);
74969
+ const evidenceDirResolved = path76.resolve(evidenceDir);
73890
74970
  if (!resolvedPath.startsWith(evidenceDirResolved)) {
73891
74971
  continue;
73892
74972
  }
73893
- const stat3 = fs59.lstatSync(filePath);
73894
- if (!stat3.isFile()) {
74973
+ const stat4 = fs62.lstatSync(filePath);
74974
+ if (!stat4.isFile()) {
73895
74975
  continue;
73896
74976
  }
73897
74977
  } catch {
@@ -73899,7 +74979,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
73899
74979
  }
73900
74980
  let fileStat;
73901
74981
  try {
73902
- fileStat = fs59.statSync(filePath);
74982
+ fileStat = fs62.statSync(filePath);
73903
74983
  if (fileStat.size > MAX_FILE_SIZE_BYTES6) {
73904
74984
  continue;
73905
74985
  }
@@ -73908,7 +74988,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
73908
74988
  }
73909
74989
  let content;
73910
74990
  try {
73911
- content = fs59.readFileSync(filePath, "utf-8");
74991
+ content = fs62.readFileSync(filePath, "utf-8");
73912
74992
  } catch {
73913
74993
  continue;
73914
74994
  }
@@ -74004,7 +75084,7 @@ var evidence_check = createSwarmTool({
74004
75084
  return JSON.stringify(errorResult, null, 2);
74005
75085
  }
74006
75086
  const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
74007
- const planPath = path73.join(cwd, PLAN_FILE);
75087
+ const planPath = path76.join(cwd, PLAN_FILE);
74008
75088
  if (!isPathWithinSwarm2(planPath, cwd)) {
74009
75089
  const errorResult = {
74010
75090
  error: "plan file path validation failed",
@@ -74018,7 +75098,7 @@ var evidence_check = createSwarmTool({
74018
75098
  }
74019
75099
  let planContent;
74020
75100
  try {
74021
- planContent = fs59.readFileSync(planPath, "utf-8");
75101
+ planContent = fs62.readFileSync(planPath, "utf-8");
74022
75102
  } catch {
74023
75103
  const result2 = {
74024
75104
  message: "No completed tasks found in plan.",
@@ -74036,7 +75116,7 @@ var evidence_check = createSwarmTool({
74036
75116
  };
74037
75117
  return JSON.stringify(result2, null, 2);
74038
75118
  }
74039
- const evidenceDir = path73.join(cwd, EVIDENCE_DIR3);
75119
+ const evidenceDir = path76.join(cwd, EVIDENCE_DIR3);
74040
75120
  const evidence = readEvidenceFiles(evidenceDir, cwd);
74041
75121
  const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
74042
75122
  const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
@@ -74053,8 +75133,8 @@ var evidence_check = createSwarmTool({
74053
75133
  // src/tools/file-extractor.ts
74054
75134
  init_tool();
74055
75135
  init_create_tool();
74056
- import * as fs60 from "fs";
74057
- import * as path74 from "path";
75136
+ import * as fs63 from "fs";
75137
+ import * as path77 from "path";
74058
75138
  var EXT_MAP = {
74059
75139
  python: ".py",
74060
75140
  py: ".py",
@@ -74116,8 +75196,8 @@ var extract_code_blocks = createSwarmTool({
74116
75196
  execute: async (args2, directory) => {
74117
75197
  const { content, output_dir, prefix } = args2;
74118
75198
  const targetDir = output_dir || directory;
74119
- if (!fs60.existsSync(targetDir)) {
74120
- fs60.mkdirSync(targetDir, { recursive: true });
75199
+ if (!fs63.existsSync(targetDir)) {
75200
+ fs63.mkdirSync(targetDir, { recursive: true });
74121
75201
  }
74122
75202
  if (!content) {
74123
75203
  return "Error: content is required";
@@ -74135,16 +75215,16 @@ var extract_code_blocks = createSwarmTool({
74135
75215
  if (prefix) {
74136
75216
  filename = `${prefix}_${filename}`;
74137
75217
  }
74138
- let filepath = path74.join(targetDir, filename);
74139
- const base = path74.basename(filepath, path74.extname(filepath));
74140
- 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);
74141
75221
  let counter = 1;
74142
- while (fs60.existsSync(filepath)) {
74143
- filepath = path74.join(targetDir, `${base}_${counter}${ext}`);
75222
+ while (fs63.existsSync(filepath)) {
75223
+ filepath = path77.join(targetDir, `${base}_${counter}${ext}`);
74144
75224
  counter++;
74145
75225
  }
74146
75226
  try {
74147
- fs60.writeFileSync(filepath, code.trim(), "utf-8");
75227
+ fs63.writeFileSync(filepath, code.trim(), "utf-8");
74148
75228
  savedFiles.push(filepath);
74149
75229
  } catch (error93) {
74150
75230
  errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
@@ -74403,8 +75483,8 @@ var gitingest = createSwarmTool({
74403
75483
  init_dist();
74404
75484
  init_create_tool();
74405
75485
  init_path_security();
74406
- import * as fs61 from "fs";
74407
- import * as path75 from "path";
75486
+ import * as fs64 from "fs";
75487
+ import * as path78 from "path";
74408
75488
  var MAX_FILE_PATH_LENGTH2 = 500;
74409
75489
  var MAX_SYMBOL_LENGTH = 256;
74410
75490
  var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
@@ -74452,7 +75532,7 @@ function validateSymbolInput(symbol3) {
74452
75532
  return null;
74453
75533
  }
74454
75534
  function isBinaryFile2(filePath, buffer) {
74455
- const ext = path75.extname(filePath).toLowerCase();
75535
+ const ext = path78.extname(filePath).toLowerCase();
74456
75536
  if (ext === ".json" || ext === ".md" || ext === ".txt") {
74457
75537
  return false;
74458
75538
  }
@@ -74476,15 +75556,15 @@ function parseImports(content, targetFile, targetSymbol) {
74476
75556
  const imports = [];
74477
75557
  let _resolvedTarget;
74478
75558
  try {
74479
- _resolvedTarget = path75.resolve(targetFile);
75559
+ _resolvedTarget = path78.resolve(targetFile);
74480
75560
  } catch {
74481
75561
  _resolvedTarget = targetFile;
74482
75562
  }
74483
- const targetBasename = path75.basename(targetFile, path75.extname(targetFile));
75563
+ const targetBasename = path78.basename(targetFile, path78.extname(targetFile));
74484
75564
  const targetWithExt = targetFile;
74485
75565
  const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
74486
- const normalizedTargetWithExt = path75.normalize(targetWithExt).replace(/\\/g, "/");
74487
- const normalizedTargetWithoutExt = path75.normalize(targetWithoutExt).replace(/\\/g, "/");
75566
+ const normalizedTargetWithExt = path78.normalize(targetWithExt).replace(/\\/g, "/");
75567
+ const normalizedTargetWithoutExt = path78.normalize(targetWithoutExt).replace(/\\/g, "/");
74488
75568
  const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
74489
75569
  for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
74490
75570
  const modulePath = match[1] || match[2] || match[3];
@@ -74507,9 +75587,9 @@ function parseImports(content, targetFile, targetSymbol) {
74507
75587
  }
74508
75588
  const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
74509
75589
  let isMatch = false;
74510
- const _targetDir = path75.dirname(targetFile);
74511
- const targetExt = path75.extname(targetFile);
74512
- 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);
74513
75593
  const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
74514
75594
  const moduleName = modulePath.split(/[/\\]/).pop() || "";
74515
75595
  const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
@@ -74566,7 +75646,7 @@ var SKIP_DIRECTORIES4 = new Set([
74566
75646
  function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
74567
75647
  let entries;
74568
75648
  try {
74569
- entries = fs61.readdirSync(dir);
75649
+ entries = fs64.readdirSync(dir);
74570
75650
  } catch (e) {
74571
75651
  stats.fileErrors.push({
74572
75652
  path: dir,
@@ -74577,13 +75657,13 @@ function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFil
74577
75657
  entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
74578
75658
  for (const entry of entries) {
74579
75659
  if (SKIP_DIRECTORIES4.has(entry)) {
74580
- stats.skippedDirs.push(path75.join(dir, entry));
75660
+ stats.skippedDirs.push(path78.join(dir, entry));
74581
75661
  continue;
74582
75662
  }
74583
- const fullPath = path75.join(dir, entry);
74584
- let stat3;
75663
+ const fullPath = path78.join(dir, entry);
75664
+ let stat4;
74585
75665
  try {
74586
- stat3 = fs61.statSync(fullPath);
75666
+ stat4 = fs64.statSync(fullPath);
74587
75667
  } catch (e) {
74588
75668
  stats.fileErrors.push({
74589
75669
  path: fullPath,
@@ -74591,10 +75671,10 @@ function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFil
74591
75671
  });
74592
75672
  continue;
74593
75673
  }
74594
- if (stat3.isDirectory()) {
75674
+ if (stat4.isDirectory()) {
74595
75675
  findSourceFiles3(fullPath, files, stats);
74596
- } else if (stat3.isFile()) {
74597
- const ext = path75.extname(fullPath).toLowerCase();
75676
+ } else if (stat4.isFile()) {
75677
+ const ext = path78.extname(fullPath).toLowerCase();
74598
75678
  if (SUPPORTED_EXTENSIONS3.includes(ext)) {
74599
75679
  files.push(fullPath);
74600
75680
  }
@@ -74651,8 +75731,8 @@ var imports = createSwarmTool({
74651
75731
  return JSON.stringify(errorResult, null, 2);
74652
75732
  }
74653
75733
  try {
74654
- const targetFile = path75.resolve(file3);
74655
- if (!fs61.existsSync(targetFile)) {
75734
+ const targetFile = path78.resolve(file3);
75735
+ if (!fs64.existsSync(targetFile)) {
74656
75736
  const errorResult = {
74657
75737
  error: `target file not found: ${file3}`,
74658
75738
  target: file3,
@@ -74662,7 +75742,7 @@ var imports = createSwarmTool({
74662
75742
  };
74663
75743
  return JSON.stringify(errorResult, null, 2);
74664
75744
  }
74665
- const targetStat = fs61.statSync(targetFile);
75745
+ const targetStat = fs64.statSync(targetFile);
74666
75746
  if (!targetStat.isFile()) {
74667
75747
  const errorResult = {
74668
75748
  error: "target must be a file, not a directory",
@@ -74673,7 +75753,7 @@ var imports = createSwarmTool({
74673
75753
  };
74674
75754
  return JSON.stringify(errorResult, null, 2);
74675
75755
  }
74676
- const baseDir = path75.dirname(targetFile);
75756
+ const baseDir = path78.dirname(targetFile);
74677
75757
  const scanStats = {
74678
75758
  skippedDirs: [],
74679
75759
  skippedFiles: 0,
@@ -74688,12 +75768,12 @@ var imports = createSwarmTool({
74688
75768
  if (consumers.length >= MAX_CONSUMERS)
74689
75769
  break;
74690
75770
  try {
74691
- const stat3 = fs61.statSync(filePath);
74692
- if (stat3.size > MAX_FILE_SIZE_BYTES7) {
75771
+ const stat4 = fs64.statSync(filePath);
75772
+ if (stat4.size > MAX_FILE_SIZE_BYTES7) {
74693
75773
  skippedFileCount++;
74694
75774
  continue;
74695
75775
  }
74696
- const buffer = fs61.readFileSync(filePath);
75776
+ const buffer = fs64.readFileSync(filePath);
74697
75777
  if (isBinaryFile2(filePath, buffer)) {
74698
75778
  skippedFileCount++;
74699
75779
  continue;
@@ -75205,8 +76285,8 @@ init_schema();
75205
76285
  init_qa_gate_profile();
75206
76286
  init_manager2();
75207
76287
  init_curator();
75208
- import * as fs62 from "fs";
75209
- import * as path76 from "path";
76288
+ import * as fs65 from "fs";
76289
+ import * as path79 from "path";
75210
76290
  init_knowledge_curator();
75211
76291
  init_knowledge_reader();
75212
76292
  init_knowledge_store();
@@ -75437,11 +76517,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75437
76517
  safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
75438
76518
  }
75439
76519
  try {
75440
- 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");
75441
76521
  let driftVerdictFound = false;
75442
76522
  let driftVerdictApproved = false;
75443
76523
  try {
75444
- const driftEvidenceContent = fs62.readFileSync(driftEvidencePath, "utf-8");
76524
+ const driftEvidenceContent = fs65.readFileSync(driftEvidencePath, "utf-8");
75445
76525
  const driftEvidence = JSON.parse(driftEvidenceContent);
75446
76526
  const entries = driftEvidence.entries ?? [];
75447
76527
  for (const entry of entries) {
@@ -75471,14 +76551,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75471
76551
  driftVerdictFound = false;
75472
76552
  }
75473
76553
  if (!driftVerdictFound) {
75474
- const specPath = path76.join(dir, ".swarm", "spec.md");
75475
- const specExists = fs62.existsSync(specPath);
76554
+ const specPath = path79.join(dir, ".swarm", "spec.md");
76555
+ const specExists = fs65.existsSync(specPath);
75476
76556
  if (!specExists) {
75477
76557
  let incompleteTaskCount = 0;
75478
76558
  let planPhaseFound = false;
75479
76559
  try {
75480
76560
  const planPath = validateSwarmPath(dir, "plan.json");
75481
- const planRaw = fs62.readFileSync(planPath, "utf-8");
76561
+ const planRaw = fs65.readFileSync(planPath, "utf-8");
75482
76562
  const plan = JSON.parse(planRaw);
75483
76563
  const targetPhase = plan.phases.find((p) => p.id === phase);
75484
76564
  if (targetPhase) {
@@ -75529,11 +76609,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75529
76609
  const overrides = session2?.qaGateSessionOverrides ?? {};
75530
76610
  const effective = getEffectiveGates(profile, overrides);
75531
76611
  if (effective.hallucination_guard === true) {
75532
- 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");
75533
76613
  let hgVerdictFound = false;
75534
76614
  let hgVerdictApproved = false;
75535
76615
  try {
75536
- const hgContent = fs62.readFileSync(hgPath, "utf-8");
76616
+ const hgContent = fs65.readFileSync(hgPath, "utf-8");
75537
76617
  const hgBundle = JSON.parse(hgContent);
75538
76618
  for (const entry of hgBundle.entries ?? []) {
75539
76619
  if (typeof entry.type === "string" && entry.type.includes("hallucination") && typeof entry.verdict === "string") {
@@ -75601,7 +76681,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75601
76681
  }
75602
76682
  if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
75603
76683
  try {
75604
- const projectName = path76.basename(dir);
76684
+ const projectName = path79.basename(dir);
75605
76685
  const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
75606
76686
  if (curationResult) {
75607
76687
  const sessionState = swarmState.agentSessions.get(sessionID);
@@ -75681,7 +76761,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75681
76761
  let phaseRequiredAgents;
75682
76762
  try {
75683
76763
  const planPath = validateSwarmPath(dir, "plan.json");
75684
- const planRaw = fs62.readFileSync(planPath, "utf-8");
76764
+ const planRaw = fs65.readFileSync(planPath, "utf-8");
75685
76765
  const plan = JSON.parse(planRaw);
75686
76766
  const phaseObj = plan.phases.find((p) => p.id === phase);
75687
76767
  phaseRequiredAgents = phaseObj?.required_agents;
@@ -75696,7 +76776,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75696
76776
  if (agentsMissing.length > 0) {
75697
76777
  try {
75698
76778
  const planPath = validateSwarmPath(dir, "plan.json");
75699
- const planRaw = fs62.readFileSync(planPath, "utf-8");
76779
+ const planRaw = fs65.readFileSync(planPath, "utf-8");
75700
76780
  const plan = JSON.parse(planRaw);
75701
76781
  const targetPhase = plan.phases.find((p) => p.id === phase);
75702
76782
  if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
@@ -75736,7 +76816,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75736
76816
  if (phaseCompleteConfig.regression_sweep?.enforce) {
75737
76817
  try {
75738
76818
  const planPath = validateSwarmPath(dir, "plan.json");
75739
- const planRaw = fs62.readFileSync(planPath, "utf-8");
76819
+ const planRaw = fs65.readFileSync(planPath, "utf-8");
75740
76820
  const plan = JSON.parse(planRaw);
75741
76821
  const targetPhase = plan.phases.find((p) => p.id === phase);
75742
76822
  if (targetPhase) {
@@ -75790,7 +76870,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75790
76870
  }
75791
76871
  try {
75792
76872
  const eventsPath = validateSwarmPath(dir, "events.jsonl");
75793
- fs62.appendFileSync(eventsPath, `${JSON.stringify(event)}
76873
+ fs65.appendFileSync(eventsPath, `${JSON.stringify(event)}
75794
76874
  `, "utf-8");
75795
76875
  } catch (writeError) {
75796
76876
  warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -75865,12 +76945,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75865
76945
  warnings.push(`Warning: failed to update plan.json phase status`);
75866
76946
  try {
75867
76947
  const planPath = validateSwarmPath(dir, "plan.json");
75868
- const planRaw = fs62.readFileSync(planPath, "utf-8");
76948
+ const planRaw = fs65.readFileSync(planPath, "utf-8");
75869
76949
  const plan2 = JSON.parse(planRaw);
75870
76950
  const phaseObj = plan2.phases.find((p) => p.id === phase);
75871
76951
  if (phaseObj) {
75872
76952
  phaseObj.status = "complete";
75873
- fs62.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
76953
+ fs65.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
75874
76954
  }
75875
76955
  } catch {}
75876
76956
  } else if (plan) {
@@ -75907,12 +76987,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
75907
76987
  warnings.push(`Warning: failed to update plan.json phase status`);
75908
76988
  try {
75909
76989
  const planPath = validateSwarmPath(dir, "plan.json");
75910
- const planRaw = fs62.readFileSync(planPath, "utf-8");
76990
+ const planRaw = fs65.readFileSync(planPath, "utf-8");
75911
76991
  const plan = JSON.parse(planRaw);
75912
76992
  const phaseObj = plan.phases.find((p) => p.id === phase);
75913
76993
  if (phaseObj) {
75914
76994
  phaseObj.status = "complete";
75915
- fs62.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
76995
+ fs65.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
75916
76996
  }
75917
76997
  } catch {}
75918
76998
  }
@@ -75969,8 +77049,8 @@ init_dist();
75969
77049
  init_discovery();
75970
77050
  init_utils();
75971
77051
  init_create_tool();
75972
- import * as fs63 from "fs";
75973
- import * as path77 from "path";
77052
+ import * as fs66 from "fs";
77053
+ import * as path80 from "path";
75974
77054
  var MAX_OUTPUT_BYTES5 = 52428800;
75975
77055
  var AUDIT_TIMEOUT_MS = 120000;
75976
77056
  function isValidEcosystem(value) {
@@ -75998,31 +77078,31 @@ function validateArgs3(args2) {
75998
77078
  function detectEcosystems(directory) {
75999
77079
  const ecosystems = [];
76000
77080
  const cwd = directory;
76001
- if (fs63.existsSync(path77.join(cwd, "package.json"))) {
77081
+ if (fs66.existsSync(path80.join(cwd, "package.json"))) {
76002
77082
  ecosystems.push("npm");
76003
77083
  }
76004
- 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"))) {
76005
77085
  ecosystems.push("pip");
76006
77086
  }
76007
- if (fs63.existsSync(path77.join(cwd, "Cargo.toml"))) {
77087
+ if (fs66.existsSync(path80.join(cwd, "Cargo.toml"))) {
76008
77088
  ecosystems.push("cargo");
76009
77089
  }
76010
- if (fs63.existsSync(path77.join(cwd, "go.mod"))) {
77090
+ if (fs66.existsSync(path80.join(cwd, "go.mod"))) {
76011
77091
  ecosystems.push("go");
76012
77092
  }
76013
77093
  try {
76014
- const files = fs63.readdirSync(cwd);
77094
+ const files = fs66.readdirSync(cwd);
76015
77095
  if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
76016
77096
  ecosystems.push("dotnet");
76017
77097
  }
76018
77098
  } catch {}
76019
- 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"))) {
76020
77100
  ecosystems.push("ruby");
76021
77101
  }
76022
- if (fs63.existsSync(path77.join(cwd, "pubspec.yaml"))) {
77102
+ if (fs66.existsSync(path80.join(cwd, "pubspec.yaml"))) {
76023
77103
  ecosystems.push("dart");
76024
77104
  }
76025
- if (fs63.existsSync(path77.join(cwd, "composer.lock"))) {
77105
+ if (fs66.existsSync(path80.join(cwd, "composer.lock"))) {
76026
77106
  ecosystems.push("composer");
76027
77107
  }
76028
77108
  return ecosystems;
@@ -77181,8 +78261,8 @@ var pkg_audit = createSwarmTool({
77181
78261
  // src/tools/placeholder-scan.ts
77182
78262
  init_dist();
77183
78263
  init_manager2();
77184
- import * as fs64 from "fs";
77185
- import * as path78 from "path";
78264
+ import * as fs67 from "fs";
78265
+ import * as path81 from "path";
77186
78266
  init_utils();
77187
78267
  init_create_tool();
77188
78268
  var MAX_FILE_SIZE = 1024 * 1024;
@@ -77305,7 +78385,7 @@ function isScaffoldFile(filePath) {
77305
78385
  if (SCAFFOLD_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath))) {
77306
78386
  return true;
77307
78387
  }
77308
- const filename = path78.basename(filePath);
78388
+ const filename = path81.basename(filePath);
77309
78389
  if (SCAFFOLD_FILENAME_PATTERNS.some((pattern) => pattern.test(filename))) {
77310
78390
  return true;
77311
78391
  }
@@ -77322,7 +78402,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
77322
78402
  if (regex.test(normalizedPath)) {
77323
78403
  return true;
77324
78404
  }
77325
- const filename = path78.basename(filePath);
78405
+ const filename = path81.basename(filePath);
77326
78406
  const filenameRegex = new RegExp(`^${regexPattern}$`, "i");
77327
78407
  if (filenameRegex.test(filename)) {
77328
78408
  return true;
@@ -77331,7 +78411,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
77331
78411
  return false;
77332
78412
  }
77333
78413
  function isParserSupported(filePath) {
77334
- const ext = path78.extname(filePath).toLowerCase();
78414
+ const ext = path81.extname(filePath).toLowerCase();
77335
78415
  return SUPPORTED_PARSER_EXTENSIONS.has(ext);
77336
78416
  }
77337
78417
  function isPlanFile(filePath) {
@@ -77578,28 +78658,28 @@ async function placeholderScan(input, directory) {
77578
78658
  let filesScanned = 0;
77579
78659
  const filesWithFindings = new Set;
77580
78660
  for (const filePath of changed_files) {
77581
- const fullPath = path78.isAbsolute(filePath) ? filePath : path78.resolve(directory, filePath);
77582
- const resolvedDirectory = path78.resolve(directory);
77583
- 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) {
77584
78664
  continue;
77585
78665
  }
77586
- if (!fs64.existsSync(fullPath)) {
78666
+ if (!fs67.existsSync(fullPath)) {
77587
78667
  continue;
77588
78668
  }
77589
78669
  if (isAllowedByGlobs(filePath, allow_globs)) {
77590
78670
  continue;
77591
78671
  }
77592
- const relativeFilePath = path78.relative(directory, fullPath).replace(/\\/g, "/");
78672
+ const relativeFilePath = path81.relative(directory, fullPath).replace(/\\/g, "/");
77593
78673
  if (FILE_ALLOWLIST.some((allowed) => relativeFilePath.endsWith(allowed))) {
77594
78674
  continue;
77595
78675
  }
77596
78676
  let content;
77597
78677
  try {
77598
- const stat3 = fs64.statSync(fullPath);
77599
- if (stat3.size > MAX_FILE_SIZE) {
78678
+ const stat4 = fs67.statSync(fullPath);
78679
+ if (stat4.size > MAX_FILE_SIZE) {
77600
78680
  continue;
77601
78681
  }
77602
- content = fs64.readFileSync(fullPath, "utf-8");
78682
+ content = fs67.readFileSync(fullPath, "utf-8");
77603
78683
  } catch {
77604
78684
  continue;
77605
78685
  }
@@ -77661,8 +78741,8 @@ var placeholder_scan = createSwarmTool({
77661
78741
  });
77662
78742
  // src/tools/pre-check-batch.ts
77663
78743
  init_dist();
77664
- import * as fs67 from "fs";
77665
- import * as path81 from "path";
78744
+ import * as fs70 from "fs";
78745
+ import * as path84 from "path";
77666
78746
  init_manager2();
77667
78747
  init_utils();
77668
78748
  init_create_tool();
@@ -77797,8 +78877,8 @@ var quality_budget = createSwarmTool({
77797
78877
  init_dist();
77798
78878
  init_manager2();
77799
78879
  init_detector();
77800
- import * as fs66 from "fs";
77801
- import * as path80 from "path";
78880
+ import * as fs69 from "fs";
78881
+ import * as path83 from "path";
77802
78882
  import { extname as extname18 } from "path";
77803
78883
 
77804
78884
  // src/sast/rules/c.ts
@@ -78691,25 +79771,25 @@ init_create_tool();
78691
79771
  // src/tools/sast-baseline.ts
78692
79772
  init_utils2();
78693
79773
  import * as crypto8 from "crypto";
78694
- import * as fs65 from "fs";
78695
- import * as path79 from "path";
79774
+ import * as fs68 from "fs";
79775
+ import * as path82 from "path";
78696
79776
  var BASELINE_SCHEMA_VERSION = "1.0.0";
78697
79777
  var MAX_BASELINE_FINDINGS = 2000;
78698
79778
  var MAX_BASELINE_BYTES = 2 * 1048576;
78699
79779
  var LOCK_RETRY_DELAYS_MS = [50, 100, 200, 400, 800];
78700
79780
  function normalizeFindingPath(directory, file3) {
78701
- const resolved = path79.isAbsolute(file3) ? file3 : path79.resolve(directory, file3);
78702
- 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);
78703
79783
  return rel.replace(/\\/g, "/");
78704
79784
  }
78705
79785
  function baselineRelPath(phase) {
78706
- return path79.join("evidence", String(phase), "sast-baseline.json");
79786
+ return path82.join("evidence", String(phase), "sast-baseline.json");
78707
79787
  }
78708
79788
  function tempRelPath(phase) {
78709
- 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}`);
78710
79790
  }
78711
79791
  function lockRelPath(phase) {
78712
- return path79.join("evidence", String(phase), "sast-baseline.json.lock");
79792
+ return path82.join("evidence", String(phase), "sast-baseline.json.lock");
78713
79793
  }
78714
79794
  function getLine(lines, idx) {
78715
79795
  if (idx < 0 || idx >= lines.length)
@@ -78726,7 +79806,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
78726
79806
  }
78727
79807
  const lineNum = finding.location.line;
78728
79808
  try {
78729
- const content = fs65.readFileSync(finding.location.file, "utf-8");
79809
+ const content = fs68.readFileSync(finding.location.file, "utf-8");
78730
79810
  const lines = content.split(`
78731
79811
  `);
78732
79812
  const idx = lineNum - 1;
@@ -78757,7 +79837,7 @@ function assignOccurrenceIndices(findings, directory) {
78757
79837
  try {
78758
79838
  if (relFile.startsWith(".."))
78759
79839
  throw new Error("escapes workspace");
78760
- const content = fs65.readFileSync(finding.location.file, "utf-8");
79840
+ const content = fs68.readFileSync(finding.location.file, "utf-8");
78761
79841
  const lines = content.split(`
78762
79842
  `);
78763
79843
  const idx = lineNum - 1;
@@ -78786,11 +79866,11 @@ function assignOccurrenceIndices(findings, directory) {
78786
79866
  async function acquireLock(lockPath) {
78787
79867
  for (let attempt = 0;attempt <= LOCK_RETRY_DELAYS_MS.length; attempt++) {
78788
79868
  try {
78789
- const fd = fs65.openSync(lockPath, "wx");
78790
- fs65.closeSync(fd);
79869
+ const fd = fs68.openSync(lockPath, "wx");
79870
+ fs68.closeSync(fd);
78791
79871
  return () => {
78792
79872
  try {
78793
- fs65.unlinkSync(lockPath);
79873
+ fs68.unlinkSync(lockPath);
78794
79874
  } catch {}
78795
79875
  };
78796
79876
  } catch {
@@ -78830,12 +79910,12 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
78830
79910
  message: e instanceof Error ? e.message : "Path validation failed"
78831
79911
  };
78832
79912
  }
78833
- fs65.mkdirSync(path79.dirname(baselinePath), { recursive: true });
79913
+ fs68.mkdirSync(path82.dirname(baselinePath), { recursive: true });
78834
79914
  const releaseLock = await acquireLock(lockPath);
78835
79915
  try {
78836
79916
  let existing = null;
78837
79917
  try {
78838
- const raw = fs65.readFileSync(baselinePath, "utf-8");
79918
+ const raw = fs68.readFileSync(baselinePath, "utf-8");
78839
79919
  const parsed = JSON.parse(raw);
78840
79920
  if (parsed.schema_version === BASELINE_SCHEMA_VERSION) {
78841
79921
  existing = parsed;
@@ -78895,8 +79975,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
78895
79975
  message: `Baseline would exceed size cap (${json4.length} bytes > ${MAX_BASELINE_BYTES})`
78896
79976
  };
78897
79977
  }
78898
- fs65.writeFileSync(tempPath, json4, "utf-8");
78899
- fs65.renameSync(tempPath, baselinePath);
79978
+ fs68.writeFileSync(tempPath, json4, "utf-8");
79979
+ fs68.renameSync(tempPath, baselinePath);
78900
79980
  return {
78901
79981
  status: "merged",
78902
79982
  path: baselinePath,
@@ -78927,8 +80007,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
78927
80007
  message: `Baseline would exceed size cap (${json3.length} bytes > ${MAX_BASELINE_BYTES})`
78928
80008
  };
78929
80009
  }
78930
- fs65.writeFileSync(tempPath, json3, "utf-8");
78931
- fs65.renameSync(tempPath, baselinePath);
80010
+ fs68.writeFileSync(tempPath, json3, "utf-8");
80011
+ fs68.renameSync(tempPath, baselinePath);
78932
80012
  return {
78933
80013
  status: "written",
78934
80014
  path: baselinePath,
@@ -78953,7 +80033,7 @@ function loadBaseline(directory, phase) {
78953
80033
  };
78954
80034
  }
78955
80035
  try {
78956
- const raw = fs65.readFileSync(baselinePath, "utf-8");
80036
+ const raw = fs68.readFileSync(baselinePath, "utf-8");
78957
80037
  const parsed = JSON.parse(raw);
78958
80038
  if (parsed.schema_version !== BASELINE_SCHEMA_VERSION) {
78959
80039
  return {
@@ -78995,17 +80075,17 @@ var SEVERITY_ORDER = {
78995
80075
  };
78996
80076
  function shouldSkipFile(filePath) {
78997
80077
  try {
78998
- const stats = fs66.statSync(filePath);
80078
+ const stats = fs69.statSync(filePath);
78999
80079
  if (stats.size > MAX_FILE_SIZE_BYTES8) {
79000
80080
  return { skip: true, reason: "file too large" };
79001
80081
  }
79002
80082
  if (stats.size === 0) {
79003
80083
  return { skip: true, reason: "empty file" };
79004
80084
  }
79005
- const fd = fs66.openSync(filePath, "r");
80085
+ const fd = fs69.openSync(filePath, "r");
79006
80086
  const buffer = Buffer.alloc(8192);
79007
- const bytesRead = fs66.readSync(fd, buffer, 0, 8192, 0);
79008
- fs66.closeSync(fd);
80087
+ const bytesRead = fs69.readSync(fd, buffer, 0, 8192, 0);
80088
+ fs69.closeSync(fd);
79009
80089
  if (bytesRead > 0) {
79010
80090
  let nullCount = 0;
79011
80091
  for (let i2 = 0;i2 < bytesRead; i2++) {
@@ -79044,7 +80124,7 @@ function countBySeverity(findings) {
79044
80124
  }
79045
80125
  function scanFileWithTierA(filePath, language) {
79046
80126
  try {
79047
- const content = fs66.readFileSync(filePath, "utf-8");
80127
+ const content = fs69.readFileSync(filePath, "utf-8");
79048
80128
  const findings = executeRulesSync(filePath, content, language);
79049
80129
  return findings.map((f) => ({
79050
80130
  rule_id: f.rule_id,
@@ -79097,13 +80177,13 @@ async function sastScan(input, directory, config3) {
79097
80177
  _filesSkipped++;
79098
80178
  continue;
79099
80179
  }
79100
- const resolvedPath = path80.isAbsolute(filePath) ? filePath : path80.resolve(directory, filePath);
79101
- const resolvedDirectory = path80.resolve(directory);
79102
- 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) {
79103
80183
  _filesSkipped++;
79104
80184
  continue;
79105
80185
  }
79106
- if (!fs66.existsSync(resolvedPath)) {
80186
+ if (!fs69.existsSync(resolvedPath)) {
79107
80187
  _filesSkipped++;
79108
80188
  continue;
79109
80189
  }
@@ -79410,18 +80490,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
79410
80490
  let resolved;
79411
80491
  const isWinAbs = isWindowsAbsolutePath(inputPath);
79412
80492
  if (isWinAbs) {
79413
- resolved = path81.win32.resolve(inputPath);
79414
- } else if (path81.isAbsolute(inputPath)) {
79415
- resolved = path81.resolve(inputPath);
80493
+ resolved = path84.win32.resolve(inputPath);
80494
+ } else if (path84.isAbsolute(inputPath)) {
80495
+ resolved = path84.resolve(inputPath);
79416
80496
  } else {
79417
- resolved = path81.resolve(baseDir, inputPath);
80497
+ resolved = path84.resolve(baseDir, inputPath);
79418
80498
  }
79419
- const workspaceResolved = path81.resolve(workspaceDir);
80499
+ const workspaceResolved = path84.resolve(workspaceDir);
79420
80500
  let relative20;
79421
80501
  if (isWinAbs) {
79422
- relative20 = path81.win32.relative(workspaceResolved, resolved);
80502
+ relative20 = path84.win32.relative(workspaceResolved, resolved);
79423
80503
  } else {
79424
- relative20 = path81.relative(workspaceResolved, resolved);
80504
+ relative20 = path84.relative(workspaceResolved, resolved);
79425
80505
  }
79426
80506
  if (relative20.startsWith("..")) {
79427
80507
  return "path traversal detected";
@@ -79486,7 +80566,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
79486
80566
  if (typeof file3 !== "string") {
79487
80567
  continue;
79488
80568
  }
79489
- const resolvedPath = path81.resolve(file3);
80569
+ const resolvedPath = path84.resolve(file3);
79490
80570
  const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
79491
80571
  if (validationError) {
79492
80572
  continue;
@@ -79643,7 +80723,7 @@ async function runSecretscanWithFiles(files, directory) {
79643
80723
  skippedFiles++;
79644
80724
  continue;
79645
80725
  }
79646
- const resolvedPath = path81.resolve(file3);
80726
+ const resolvedPath = path84.resolve(file3);
79647
80727
  const validationError = validatePath(resolvedPath, directory, directory);
79648
80728
  if (validationError) {
79649
80729
  skippedFiles++;
@@ -79661,25 +80741,25 @@ async function runSecretscanWithFiles(files, directory) {
79661
80741
  };
79662
80742
  }
79663
80743
  for (const file3 of validatedFiles) {
79664
- const ext = path81.extname(file3).toLowerCase();
80744
+ const ext = path84.extname(file3).toLowerCase();
79665
80745
  if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
79666
80746
  skippedFiles++;
79667
80747
  continue;
79668
80748
  }
79669
- let stat3;
80749
+ let stat4;
79670
80750
  try {
79671
- stat3 = fs67.statSync(file3);
80751
+ stat4 = fs70.statSync(file3);
79672
80752
  } catch {
79673
80753
  skippedFiles++;
79674
80754
  continue;
79675
80755
  }
79676
- if (stat3.size > MAX_FILE_SIZE_BYTES9) {
80756
+ if (stat4.size > MAX_FILE_SIZE_BYTES9) {
79677
80757
  skippedFiles++;
79678
80758
  continue;
79679
80759
  }
79680
80760
  let content;
79681
80761
  try {
79682
- const buffer = fs67.readFileSync(file3);
80762
+ const buffer = fs70.readFileSync(file3);
79683
80763
  if (buffer.includes(0)) {
79684
80764
  skippedFiles++;
79685
80765
  continue;
@@ -79880,7 +80960,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
79880
80960
  const preexistingFindings = [];
79881
80961
  for (const finding of findings) {
79882
80962
  const filePath = finding.location.file;
79883
- const normalised = path81.relative(directory, filePath).replace(/\\/g, "/");
80963
+ const normalised = path84.relative(directory, filePath).replace(/\\/g, "/");
79884
80964
  const changedLines = changedLineRanges.get(normalised);
79885
80965
  if (changedLines?.has(finding.location.line)) {
79886
80966
  newFindings.push(finding);
@@ -79931,7 +81011,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
79931
81011
  warn(`pre_check_batch: Invalid file path: ${file3}`);
79932
81012
  continue;
79933
81013
  }
79934
- changedFiles.push(path81.resolve(directory, file3));
81014
+ changedFiles.push(path84.resolve(directory, file3));
79935
81015
  }
79936
81016
  if (changedFiles.length === 0) {
79937
81017
  warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
@@ -80132,7 +81212,7 @@ var pre_check_batch = createSwarmTool({
80132
81212
  };
80133
81213
  return JSON.stringify(errorResult, null, 2);
80134
81214
  }
80135
- const resolvedDirectory = path81.resolve(typedArgs.directory);
81215
+ const resolvedDirectory = path84.resolve(typedArgs.directory);
80136
81216
  const workspaceAnchor = resolvedDirectory;
80137
81217
  const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
80138
81218
  if (dirError) {
@@ -80173,7 +81253,7 @@ var pre_check_batch = createSwarmTool({
80173
81253
  });
80174
81254
  // src/tools/repo-map.ts
80175
81255
  init_dist();
80176
- import * as path82 from "path";
81256
+ import * as path85 from "path";
80177
81257
  init_path_security();
80178
81258
  init_create_tool();
80179
81259
  var VALID_ACTIONS = [
@@ -80198,7 +81278,7 @@ function validateFile(p) {
80198
81278
  return "file contains control characters";
80199
81279
  if (containsPathTraversal(p))
80200
81280
  return "file contains path traversal";
80201
- if (path82.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
81281
+ if (path85.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
80202
81282
  return "file must be a workspace-relative path, not absolute";
80203
81283
  }
80204
81284
  return null;
@@ -80221,8 +81301,8 @@ function ok(action, payload) {
80221
81301
  }
80222
81302
  function toRelativeGraphPath(input, workspaceRoot) {
80223
81303
  const normalized = input.replace(/\\/g, "/");
80224
- if (path82.isAbsolute(normalized)) {
80225
- const rel = path82.relative(workspaceRoot, normalized).replace(/\\/g, "/");
81304
+ if (path85.isAbsolute(normalized)) {
81305
+ const rel = path85.relative(workspaceRoot, normalized).replace(/\\/g, "/");
80226
81306
  return normalizeGraphPath2(rel);
80227
81307
  }
80228
81308
  return normalizeGraphPath2(normalized);
@@ -80366,8 +81446,8 @@ var repo_map = createSwarmTool({
80366
81446
  // src/tools/req-coverage.ts
80367
81447
  init_dist();
80368
81448
  init_create_tool();
80369
- import * as fs68 from "fs";
80370
- import * as path83 from "path";
81449
+ import * as fs71 from "fs";
81450
+ import * as path86 from "path";
80371
81451
  var SPEC_FILE = ".swarm/spec.md";
80372
81452
  var EVIDENCE_DIR4 = ".swarm/evidence";
80373
81453
  var OBLIGATION_KEYWORDS = ["MUST", "SHOULD", "SHALL"];
@@ -80426,20 +81506,20 @@ function extractObligationAndText(id, lineText) {
80426
81506
  var PHASE_TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
80427
81507
  function readTouchedFiles(evidenceDir, phase, cwd) {
80428
81508
  const touchedFiles = new Set;
80429
- if (!fs68.existsSync(evidenceDir) || !fs68.statSync(evidenceDir).isDirectory()) {
81509
+ if (!fs71.existsSync(evidenceDir) || !fs71.statSync(evidenceDir).isDirectory()) {
80430
81510
  return [];
80431
81511
  }
80432
81512
  let entries;
80433
81513
  try {
80434
- entries = fs68.readdirSync(evidenceDir);
81514
+ entries = fs71.readdirSync(evidenceDir);
80435
81515
  } catch {
80436
81516
  return [];
80437
81517
  }
80438
81518
  for (const entry of entries) {
80439
- const entryPath = path83.join(evidenceDir, entry);
81519
+ const entryPath = path86.join(evidenceDir, entry);
80440
81520
  try {
80441
- const stat3 = fs68.statSync(entryPath);
80442
- if (!stat3.isDirectory()) {
81521
+ const stat4 = fs71.statSync(entryPath);
81522
+ if (!stat4.isDirectory()) {
80443
81523
  continue;
80444
81524
  }
80445
81525
  } catch {
@@ -80452,18 +81532,18 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
80452
81532
  if (entryPhase !== String(phase)) {
80453
81533
  continue;
80454
81534
  }
80455
- const evidenceFilePath = path83.join(entryPath, "evidence.json");
81535
+ const evidenceFilePath = path86.join(entryPath, "evidence.json");
80456
81536
  try {
80457
- const resolvedPath = path83.resolve(evidenceFilePath);
80458
- const evidenceDirResolved = path83.resolve(evidenceDir);
80459
- 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)) {
80460
81540
  continue;
80461
81541
  }
80462
- const stat3 = fs68.lstatSync(evidenceFilePath);
80463
- if (!stat3.isFile()) {
81542
+ const stat4 = fs71.lstatSync(evidenceFilePath);
81543
+ if (!stat4.isFile()) {
80464
81544
  continue;
80465
81545
  }
80466
- if (stat3.size > MAX_FILE_SIZE_BYTES9) {
81546
+ if (stat4.size > MAX_FILE_SIZE_BYTES9) {
80467
81547
  continue;
80468
81548
  }
80469
81549
  } catch {
@@ -80471,7 +81551,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
80471
81551
  }
80472
81552
  let content;
80473
81553
  try {
80474
- content = fs68.readFileSync(evidenceFilePath, "utf-8");
81554
+ content = fs71.readFileSync(evidenceFilePath, "utf-8");
80475
81555
  } catch {
80476
81556
  continue;
80477
81557
  }
@@ -80490,7 +81570,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
80490
81570
  if (Array.isArray(diffEntry.files_changed)) {
80491
81571
  for (const file3 of diffEntry.files_changed) {
80492
81572
  if (typeof file3 === "string") {
80493
- touchedFiles.add(path83.resolve(cwd, file3));
81573
+ touchedFiles.add(path86.resolve(cwd, file3));
80494
81574
  }
80495
81575
  }
80496
81576
  }
@@ -80503,12 +81583,12 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
80503
81583
  }
80504
81584
  function searchFileForKeywords(filePath, keywords, cwd) {
80505
81585
  try {
80506
- const resolvedPath = path83.resolve(filePath);
80507
- const cwdResolved = path83.resolve(cwd);
81586
+ const resolvedPath = path86.resolve(filePath);
81587
+ const cwdResolved = path86.resolve(cwd);
80508
81588
  if (!resolvedPath.startsWith(cwdResolved)) {
80509
81589
  return false;
80510
81590
  }
80511
- const content = fs68.readFileSync(resolvedPath, "utf-8");
81591
+ const content = fs71.readFileSync(resolvedPath, "utf-8");
80512
81592
  for (const keyword of keywords) {
80513
81593
  const regex = new RegExp(`\\b${keyword}\\b`, "i");
80514
81594
  if (regex.test(content)) {
@@ -80638,10 +81718,10 @@ var req_coverage = createSwarmTool({
80638
81718
  }, null, 2);
80639
81719
  }
80640
81720
  const cwd = inputDirectory || directory;
80641
- const specPath = path83.join(cwd, SPEC_FILE);
81721
+ const specPath = path86.join(cwd, SPEC_FILE);
80642
81722
  let specContent;
80643
81723
  try {
80644
- specContent = fs68.readFileSync(specPath, "utf-8");
81724
+ specContent = fs71.readFileSync(specPath, "utf-8");
80645
81725
  } catch (readError) {
80646
81726
  return JSON.stringify({
80647
81727
  success: false,
@@ -80665,7 +81745,7 @@ var req_coverage = createSwarmTool({
80665
81745
  message: "No FR requirements found in spec.md"
80666
81746
  }, null, 2);
80667
81747
  }
80668
- const evidenceDir = path83.join(cwd, EVIDENCE_DIR4);
81748
+ const evidenceDir = path86.join(cwd, EVIDENCE_DIR4);
80669
81749
  const touchedFiles = readTouchedFiles(evidenceDir, phase, cwd);
80670
81750
  const analyzedRequirements = [];
80671
81751
  let coveredCount = 0;
@@ -80691,12 +81771,12 @@ var req_coverage = createSwarmTool({
80691
81771
  requirements: analyzedRequirements
80692
81772
  };
80693
81773
  const reportFilename = `req-coverage-phase-${phase}.json`;
80694
- const reportPath = path83.join(evidenceDir, reportFilename);
81774
+ const reportPath = path86.join(evidenceDir, reportFilename);
80695
81775
  try {
80696
- if (!fs68.existsSync(evidenceDir)) {
80697
- fs68.mkdirSync(evidenceDir, { recursive: true });
81776
+ if (!fs71.existsSync(evidenceDir)) {
81777
+ fs71.mkdirSync(evidenceDir, { recursive: true });
80698
81778
  }
80699
- fs68.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
81779
+ fs71.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
80700
81780
  } catch (writeError) {
80701
81781
  console.warn(`Failed to write coverage report: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
80702
81782
  }
@@ -80782,8 +81862,8 @@ init_manager();
80782
81862
  init_state();
80783
81863
  init_create_tool();
80784
81864
  import * as crypto9 from "crypto";
80785
- import * as fs69 from "fs";
80786
- import * as path84 from "path";
81865
+ import * as fs72 from "fs";
81866
+ import * as path87 from "path";
80787
81867
  function detectPlaceholderContent(args2) {
80788
81868
  const issues = [];
80789
81869
  const placeholderPattern = /^\[\w[\w\s]*\]$/;
@@ -80859,11 +81939,11 @@ async function executeSavePlan(args2, fallbackDir) {
80859
81939
  let specMtime;
80860
81940
  let specHash;
80861
81941
  if (process.env.SWARM_SKIP_SPEC_GATE !== "1") {
80862
- const specPath = path84.join(targetWorkspace, ".swarm", "spec.md");
81942
+ const specPath = path87.join(targetWorkspace, ".swarm", "spec.md");
80863
81943
  try {
80864
- const stat3 = await fs69.promises.stat(specPath);
80865
- specMtime = stat3.mtime.toISOString();
80866
- 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");
80867
81947
  specHash = crypto9.createHash("sha256").update(content).digest("hex");
80868
81948
  } catch {
80869
81949
  return {
@@ -80999,14 +82079,14 @@ async function executeSavePlan(args2, fallbackDir) {
80999
82079
  }
81000
82080
  await writeCheckpoint(dir).catch(() => {});
81001
82081
  try {
81002
- const markerPath = path84.join(dir, ".swarm", ".plan-write-marker");
82082
+ const markerPath = path87.join(dir, ".swarm", ".plan-write-marker");
81003
82083
  const marker = JSON.stringify({
81004
82084
  source: "save_plan",
81005
82085
  timestamp: new Date().toISOString(),
81006
82086
  phases_count: plan.phases.length,
81007
82087
  tasks_count: tasksCount
81008
82088
  });
81009
- await fs69.promises.writeFile(markerPath, marker, "utf8");
82089
+ await fs72.promises.writeFile(markerPath, marker, "utf8");
81010
82090
  } catch {}
81011
82091
  const warnings = [];
81012
82092
  let criticReviewFound = false;
@@ -81022,7 +82102,7 @@ async function executeSavePlan(args2, fallbackDir) {
81022
82102
  return {
81023
82103
  success: true,
81024
82104
  message: "Plan saved successfully",
81025
- plan_path: path84.join(dir, ".swarm", "plan.json"),
82105
+ plan_path: path87.join(dir, ".swarm", "plan.json"),
81026
82106
  phases_count: plan.phases.length,
81027
82107
  tasks_count: tasksCount,
81028
82108
  ...resolvedProfile !== undefined ? { execution_profile: resolvedProfile } : {},
@@ -81074,8 +82154,8 @@ var save_plan = createSwarmTool({
81074
82154
  // src/tools/sbom-generate.ts
81075
82155
  init_dist();
81076
82156
  init_manager2();
81077
- import * as fs70 from "fs";
81078
- import * as path85 from "path";
82157
+ import * as fs73 from "fs";
82158
+ import * as path88 from "path";
81079
82159
 
81080
82160
  // src/sbom/detectors/index.ts
81081
82161
  init_utils();
@@ -81923,9 +83003,9 @@ function findManifestFiles(rootDir) {
81923
83003
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
81924
83004
  function searchDir(dir) {
81925
83005
  try {
81926
- const entries = fs70.readdirSync(dir, { withFileTypes: true });
83006
+ const entries = fs73.readdirSync(dir, { withFileTypes: true });
81927
83007
  for (const entry of entries) {
81928
- const fullPath = path85.join(dir, entry.name);
83008
+ const fullPath = path88.join(dir, entry.name);
81929
83009
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
81930
83010
  continue;
81931
83011
  }
@@ -81934,7 +83014,7 @@ function findManifestFiles(rootDir) {
81934
83014
  } else if (entry.isFile()) {
81935
83015
  for (const pattern of patterns) {
81936
83016
  if (simpleGlobToRegex(pattern).test(entry.name)) {
81937
- manifestFiles.push(path85.relative(rootDir, fullPath));
83017
+ manifestFiles.push(path88.relative(rootDir, fullPath));
81938
83018
  break;
81939
83019
  }
81940
83020
  }
@@ -81950,13 +83030,13 @@ function findManifestFilesInDirs(directories, workingDir) {
81950
83030
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
81951
83031
  for (const dir of directories) {
81952
83032
  try {
81953
- const entries = fs70.readdirSync(dir, { withFileTypes: true });
83033
+ const entries = fs73.readdirSync(dir, { withFileTypes: true });
81954
83034
  for (const entry of entries) {
81955
- const fullPath = path85.join(dir, entry.name);
83035
+ const fullPath = path88.join(dir, entry.name);
81956
83036
  if (entry.isFile()) {
81957
83037
  for (const pattern of patterns) {
81958
83038
  if (simpleGlobToRegex(pattern).test(entry.name)) {
81959
- found.push(path85.relative(workingDir, fullPath));
83039
+ found.push(path88.relative(workingDir, fullPath));
81960
83040
  break;
81961
83041
  }
81962
83042
  }
@@ -81969,11 +83049,11 @@ function findManifestFilesInDirs(directories, workingDir) {
81969
83049
  function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
81970
83050
  const dirs = new Set;
81971
83051
  for (const file3 of changedFiles) {
81972
- let currentDir = path85.dirname(file3);
83052
+ let currentDir = path88.dirname(file3);
81973
83053
  while (true) {
81974
- if (currentDir && currentDir !== "." && currentDir !== path85.sep) {
81975
- dirs.add(path85.join(workingDir, currentDir));
81976
- 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);
81977
83057
  if (parent === currentDir)
81978
83058
  break;
81979
83059
  currentDir = parent;
@@ -81987,7 +83067,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
81987
83067
  }
81988
83068
  function ensureOutputDir(outputDir) {
81989
83069
  try {
81990
- fs70.mkdirSync(outputDir, { recursive: true });
83070
+ fs73.mkdirSync(outputDir, { recursive: true });
81991
83071
  } catch (error93) {
81992
83072
  if (!error93 || error93.code !== "EEXIST") {
81993
83073
  throw error93;
@@ -82057,7 +83137,7 @@ var sbom_generate = createSwarmTool({
82057
83137
  const changedFiles = obj.changed_files;
82058
83138
  const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
82059
83139
  const workingDir = directory;
82060
- const outputDir = path85.isAbsolute(relativeOutputDir) ? relativeOutputDir : path85.join(workingDir, relativeOutputDir);
83140
+ const outputDir = path88.isAbsolute(relativeOutputDir) ? relativeOutputDir : path88.join(workingDir, relativeOutputDir);
82061
83141
  let manifestFiles = [];
82062
83142
  if (scope === "all") {
82063
83143
  manifestFiles = findManifestFiles(workingDir);
@@ -82080,11 +83160,11 @@ var sbom_generate = createSwarmTool({
82080
83160
  const processedFiles = [];
82081
83161
  for (const manifestFile of manifestFiles) {
82082
83162
  try {
82083
- const fullPath = path85.isAbsolute(manifestFile) ? manifestFile : path85.join(workingDir, manifestFile);
82084
- if (!fs70.existsSync(fullPath)) {
83163
+ const fullPath = path88.isAbsolute(manifestFile) ? manifestFile : path88.join(workingDir, manifestFile);
83164
+ if (!fs73.existsSync(fullPath)) {
82085
83165
  continue;
82086
83166
  }
82087
- const content = fs70.readFileSync(fullPath, "utf-8");
83167
+ const content = fs73.readFileSync(fullPath, "utf-8");
82088
83168
  const components = detectComponents(manifestFile, content);
82089
83169
  processedFiles.push(manifestFile);
82090
83170
  if (components.length > 0) {
@@ -82097,8 +83177,8 @@ var sbom_generate = createSwarmTool({
82097
83177
  const bom = generateCycloneDX(allComponents);
82098
83178
  const bomJson = serializeCycloneDX(bom);
82099
83179
  const filename = generateSbomFilename();
82100
- const outputPath = path85.join(outputDir, filename);
82101
- fs70.writeFileSync(outputPath, bomJson, "utf-8");
83180
+ const outputPath = path88.join(outputDir, filename);
83181
+ fs73.writeFileSync(outputPath, bomJson, "utf-8");
82102
83182
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
82103
83183
  try {
82104
83184
  const timestamp = new Date().toISOString();
@@ -82140,8 +83220,8 @@ var sbom_generate = createSwarmTool({
82140
83220
  // src/tools/schema-drift.ts
82141
83221
  init_dist();
82142
83222
  init_create_tool();
82143
- import * as fs71 from "fs";
82144
- import * as path86 from "path";
83223
+ import * as fs74 from "fs";
83224
+ import * as path89 from "path";
82145
83225
  var SPEC_CANDIDATES = [
82146
83226
  "openapi.json",
82147
83227
  "openapi.yaml",
@@ -82173,28 +83253,28 @@ function normalizePath3(p) {
82173
83253
  }
82174
83254
  function discoverSpecFile(cwd, specFileArg) {
82175
83255
  if (specFileArg) {
82176
- const resolvedPath = path86.resolve(cwd, specFileArg);
82177
- 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;
82178
83258
  if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
82179
83259
  throw new Error("Invalid spec_file: path traversal detected");
82180
83260
  }
82181
- const ext = path86.extname(resolvedPath).toLowerCase();
83261
+ const ext = path89.extname(resolvedPath).toLowerCase();
82182
83262
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
82183
83263
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
82184
83264
  }
82185
- const stats = fs71.statSync(resolvedPath);
83265
+ const stats = fs74.statSync(resolvedPath);
82186
83266
  if (stats.size > MAX_SPEC_SIZE) {
82187
83267
  throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
82188
83268
  }
82189
- if (!fs71.existsSync(resolvedPath)) {
83269
+ if (!fs74.existsSync(resolvedPath)) {
82190
83270
  throw new Error(`Spec file not found: ${resolvedPath}`);
82191
83271
  }
82192
83272
  return resolvedPath;
82193
83273
  }
82194
83274
  for (const candidate of SPEC_CANDIDATES) {
82195
- const candidatePath = path86.resolve(cwd, candidate);
82196
- if (fs71.existsSync(candidatePath)) {
82197
- const stats = fs71.statSync(candidatePath);
83275
+ const candidatePath = path89.resolve(cwd, candidate);
83276
+ if (fs74.existsSync(candidatePath)) {
83277
+ const stats = fs74.statSync(candidatePath);
82198
83278
  if (stats.size <= MAX_SPEC_SIZE) {
82199
83279
  return candidatePath;
82200
83280
  }
@@ -82203,8 +83283,8 @@ function discoverSpecFile(cwd, specFileArg) {
82203
83283
  return null;
82204
83284
  }
82205
83285
  function parseSpec(specFile) {
82206
- const content = fs71.readFileSync(specFile, "utf-8");
82207
- const ext = path86.extname(specFile).toLowerCase();
83286
+ const content = fs74.readFileSync(specFile, "utf-8");
83287
+ const ext = path89.extname(specFile).toLowerCase();
82208
83288
  if (ext === ".json") {
82209
83289
  return parseJsonSpec(content);
82210
83290
  }
@@ -82275,12 +83355,12 @@ function extractRoutes(cwd) {
82275
83355
  function walkDir(dir) {
82276
83356
  let entries;
82277
83357
  try {
82278
- entries = fs71.readdirSync(dir, { withFileTypes: true });
83358
+ entries = fs74.readdirSync(dir, { withFileTypes: true });
82279
83359
  } catch {
82280
83360
  return;
82281
83361
  }
82282
83362
  for (const entry of entries) {
82283
- const fullPath = path86.join(dir, entry.name);
83363
+ const fullPath = path89.join(dir, entry.name);
82284
83364
  if (entry.isSymbolicLink()) {
82285
83365
  continue;
82286
83366
  }
@@ -82290,7 +83370,7 @@ function extractRoutes(cwd) {
82290
83370
  }
82291
83371
  walkDir(fullPath);
82292
83372
  } else if (entry.isFile()) {
82293
- const ext = path86.extname(entry.name).toLowerCase();
83373
+ const ext = path89.extname(entry.name).toLowerCase();
82294
83374
  const baseName = entry.name.toLowerCase();
82295
83375
  if (![".ts", ".js", ".mjs"].includes(ext)) {
82296
83376
  continue;
@@ -82308,7 +83388,7 @@ function extractRoutes(cwd) {
82308
83388
  }
82309
83389
  function extractRoutesFromFile(filePath) {
82310
83390
  const routes = [];
82311
- const content = fs71.readFileSync(filePath, "utf-8");
83391
+ const content = fs74.readFileSync(filePath, "utf-8");
82312
83392
  const lines = content.split(/\r?\n/);
82313
83393
  const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
82314
83394
  const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
@@ -82456,8 +83536,8 @@ var schema_drift = createSwarmTool({
82456
83536
  init_tool();
82457
83537
  init_path_security();
82458
83538
  init_create_tool();
82459
- import * as fs72 from "fs";
82460
- import * as path87 from "path";
83539
+ import * as fs75 from "fs";
83540
+ import * as path90 from "path";
82461
83541
  var DEFAULT_MAX_RESULTS = 100;
82462
83542
  var DEFAULT_MAX_LINES = 200;
82463
83543
  var REGEX_TIMEOUT_MS = 5000;
@@ -82493,11 +83573,11 @@ function containsWindowsAttacks3(str) {
82493
83573
  }
82494
83574
  function isPathInWorkspace3(filePath, workspace) {
82495
83575
  try {
82496
- const resolvedPath = path87.resolve(workspace, filePath);
82497
- const realWorkspace = fs72.realpathSync(workspace);
82498
- const realResolvedPath = fs72.realpathSync(resolvedPath);
82499
- const relativePath = path87.relative(realWorkspace, realResolvedPath);
82500
- 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)) {
82501
83581
  return false;
82502
83582
  }
82503
83583
  return true;
@@ -82510,12 +83590,12 @@ function validatePathForRead2(filePath, workspace) {
82510
83590
  }
82511
83591
  function findRgInEnvPath() {
82512
83592
  const searchPath = process.env.PATH ?? "";
82513
- for (const dir of searchPath.split(path87.delimiter)) {
83593
+ for (const dir of searchPath.split(path90.delimiter)) {
82514
83594
  if (!dir)
82515
83595
  continue;
82516
83596
  const isWindows = process.platform === "win32";
82517
- const candidate = path87.join(dir, isWindows ? "rg.exe" : "rg");
82518
- if (fs72.existsSync(candidate))
83597
+ const candidate = path90.join(dir, isWindows ? "rg.exe" : "rg");
83598
+ if (fs75.existsSync(candidate))
82519
83599
  return candidate;
82520
83600
  }
82521
83601
  return null;
@@ -82642,10 +83722,10 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
82642
83722
  return files;
82643
83723
  }
82644
83724
  try {
82645
- const entries = fs72.readdirSync(dir, { withFileTypes: true });
83725
+ const entries = fs75.readdirSync(dir, { withFileTypes: true });
82646
83726
  for (const entry of entries) {
82647
- const fullPath = path87.join(dir, entry.name);
82648
- const relativePath = path87.relative(workspace, fullPath);
83727
+ const fullPath = path90.join(dir, entry.name);
83728
+ const relativePath = path90.relative(workspace, fullPath);
82649
83729
  if (!validatePathForRead2(fullPath, workspace)) {
82650
83730
  continue;
82651
83731
  }
@@ -82686,13 +83766,13 @@ async function fallbackSearch(opts) {
82686
83766
  const matches = [];
82687
83767
  let total = 0;
82688
83768
  for (const file3 of files) {
82689
- const fullPath = path87.join(opts.workspace, file3);
83769
+ const fullPath = path90.join(opts.workspace, file3);
82690
83770
  if (!validatePathForRead2(fullPath, opts.workspace)) {
82691
83771
  continue;
82692
83772
  }
82693
83773
  let stats;
82694
83774
  try {
82695
- stats = fs72.statSync(fullPath);
83775
+ stats = fs75.statSync(fullPath);
82696
83776
  if (stats.size > MAX_FILE_SIZE_BYTES10) {
82697
83777
  continue;
82698
83778
  }
@@ -82701,7 +83781,7 @@ async function fallbackSearch(opts) {
82701
83781
  }
82702
83782
  let content;
82703
83783
  try {
82704
- content = fs72.readFileSync(fullPath, "utf-8");
83784
+ content = fs75.readFileSync(fullPath, "utf-8");
82705
83785
  } catch {
82706
83786
  continue;
82707
83787
  }
@@ -82813,7 +83893,7 @@ var search = createSwarmTool({
82813
83893
  message: "Exclude pattern contains invalid Windows-specific sequence"
82814
83894
  }, null, 2);
82815
83895
  }
82816
- if (!fs72.existsSync(directory)) {
83896
+ if (!fs75.existsSync(directory)) {
82817
83897
  return JSON.stringify({
82818
83898
  error: true,
82819
83899
  type: "unknown",
@@ -82936,8 +84016,8 @@ var set_qa_gates = createSwarmTool({
82936
84016
  init_tool();
82937
84017
  init_path_security();
82938
84018
  init_create_tool();
82939
- import * as fs73 from "fs";
82940
- import * as path88 from "path";
84019
+ import * as fs76 from "fs";
84020
+ import * as path91 from "path";
82941
84021
  var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
82942
84022
  function containsWindowsAttacks4(str) {
82943
84023
  if (/:[^\\/]/.test(str))
@@ -82951,14 +84031,14 @@ function containsWindowsAttacks4(str) {
82951
84031
  }
82952
84032
  function isPathInWorkspace4(filePath, workspace) {
82953
84033
  try {
82954
- const resolvedPath = path88.resolve(workspace, filePath);
82955
- if (!fs73.existsSync(resolvedPath)) {
84034
+ const resolvedPath = path91.resolve(workspace, filePath);
84035
+ if (!fs76.existsSync(resolvedPath)) {
82956
84036
  return true;
82957
84037
  }
82958
- const realWorkspace = fs73.realpathSync(workspace);
82959
- const realResolvedPath = fs73.realpathSync(resolvedPath);
82960
- const relativePath = path88.relative(realWorkspace, realResolvedPath);
82961
- 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)) {
82962
84042
  return false;
82963
84043
  }
82964
84044
  return true;
@@ -83130,7 +84210,7 @@ var suggestPatch = createSwarmTool({
83130
84210
  message: "changes cannot be empty"
83131
84211
  }, null, 2);
83132
84212
  }
83133
- if (!fs73.existsSync(directory)) {
84213
+ if (!fs76.existsSync(directory)) {
83134
84214
  return JSON.stringify({
83135
84215
  success: false,
83136
84216
  error: true,
@@ -83166,8 +84246,8 @@ var suggestPatch = createSwarmTool({
83166
84246
  });
83167
84247
  continue;
83168
84248
  }
83169
- const fullPath = path88.resolve(directory, change.file);
83170
- if (!fs73.existsSync(fullPath)) {
84249
+ const fullPath = path91.resolve(directory, change.file);
84250
+ if (!fs76.existsSync(fullPath)) {
83171
84251
  errors5.push({
83172
84252
  success: false,
83173
84253
  error: true,
@@ -83181,7 +84261,7 @@ var suggestPatch = createSwarmTool({
83181
84261
  }
83182
84262
  let content;
83183
84263
  try {
83184
- content = fs73.readFileSync(fullPath, "utf-8");
84264
+ content = fs76.readFileSync(fullPath, "utf-8");
83185
84265
  } catch (err3) {
83186
84266
  errors5.push({
83187
84267
  success: false,
@@ -83260,8 +84340,8 @@ var suggestPatch = createSwarmTool({
83260
84340
  // src/tools/lint-spec.ts
83261
84341
  init_spec_schema();
83262
84342
  init_create_tool();
83263
- import * as fs74 from "fs";
83264
- import * as path89 from "path";
84343
+ import * as fs77 from "fs";
84344
+ import * as path92 from "path";
83265
84345
  var SPEC_FILE_NAME = "spec.md";
83266
84346
  var SWARM_DIR2 = ".swarm";
83267
84347
  var OBLIGATION_KEYWORDS2 = ["MUST", "SHALL", "SHOULD", "MAY"];
@@ -83314,8 +84394,8 @@ var lint_spec = createSwarmTool({
83314
84394
  async execute(_args, directory) {
83315
84395
  const errors5 = [];
83316
84396
  const warnings = [];
83317
- const specPath = path89.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
83318
- if (!fs74.existsSync(specPath)) {
84397
+ const specPath = path92.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
84398
+ if (!fs77.existsSync(specPath)) {
83319
84399
  const result2 = {
83320
84400
  valid: false,
83321
84401
  specMtime: null,
@@ -83334,12 +84414,12 @@ var lint_spec = createSwarmTool({
83334
84414
  }
83335
84415
  let specMtime = null;
83336
84416
  try {
83337
- const stats = fs74.statSync(specPath);
84417
+ const stats = fs77.statSync(specPath);
83338
84418
  specMtime = stats.mtime.toISOString();
83339
84419
  } catch {}
83340
84420
  let content;
83341
84421
  try {
83342
- content = fs74.readFileSync(specPath, "utf-8");
84422
+ content = fs77.readFileSync(specPath, "utf-8");
83343
84423
  } catch (e) {
83344
84424
  const result2 = {
83345
84425
  valid: false,
@@ -83384,13 +84464,13 @@ var lint_spec = createSwarmTool({
83384
84464
  });
83385
84465
  // src/tools/mutation-test.ts
83386
84466
  init_dist();
83387
- import * as fs75 from "fs";
83388
- import * as path91 from "path";
84467
+ import * as fs78 from "fs";
84468
+ import * as path94 from "path";
83389
84469
 
83390
84470
  // src/mutation/engine.ts
83391
84471
  import { spawnSync as spawnSync3 } from "child_process";
83392
84472
  import { unlinkSync as unlinkSync12, writeFileSync as writeFileSync18 } from "fs";
83393
- import * as path90 from "path";
84473
+ import * as path93 from "path";
83394
84474
 
83395
84475
  // src/mutation/equivalence.ts
83396
84476
  function isStaticallyEquivalent(originalCode, mutatedCode) {
@@ -83525,7 +84605,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
83525
84605
  let patchFile;
83526
84606
  try {
83527
84607
  const safeId2 = patch.id.replace(/[^a-zA-Z0-9_-]/g, "_");
83528
- patchFile = path90.join(workingDir, `.mutation_patch_${safeId2}.diff`);
84608
+ patchFile = path93.join(workingDir, `.mutation_patch_${safeId2}.diff`);
83529
84609
  try {
83530
84610
  writeFileSync18(patchFile, patch.patch);
83531
84611
  } catch (writeErr) {
@@ -83919,8 +84999,8 @@ var mutation_test = createSwarmTool({
83919
84999
  ];
83920
85000
  for (const filePath of uniquePaths) {
83921
85001
  try {
83922
- const resolvedPath = path91.resolve(cwd, filePath);
83923
- sourceFiles.set(filePath, fs75.readFileSync(resolvedPath, "utf-8"));
85002
+ const resolvedPath = path94.resolve(cwd, filePath);
85003
+ sourceFiles.set(filePath, fs78.readFileSync(resolvedPath, "utf-8"));
83924
85004
  } catch {}
83925
85005
  }
83926
85006
  const report = await executeMutationSuite(typedArgs.patches, typedArgs.test_command, typedArgs.files, cwd, undefined, undefined, sourceFiles.size > 0 ? sourceFiles : undefined);
@@ -83938,8 +85018,8 @@ var mutation_test = createSwarmTool({
83938
85018
  init_dist();
83939
85019
  init_manager2();
83940
85020
  init_detector();
83941
- import * as fs76 from "fs";
83942
- import * as path92 from "path";
85021
+ import * as fs79 from "fs";
85022
+ import * as path95 from "path";
83943
85023
  init_create_tool();
83944
85024
  var MAX_FILE_SIZE2 = 2 * 1024 * 1024;
83945
85025
  var BINARY_CHECK_BYTES = 8192;
@@ -84005,7 +85085,7 @@ async function syntaxCheck(input, directory, config3) {
84005
85085
  if (languages?.length) {
84006
85086
  const lowerLangs = languages.map((l) => l.toLowerCase());
84007
85087
  filesToCheck = filesToCheck.filter((file3) => {
84008
- const ext = path92.extname(file3.path).toLowerCase();
85088
+ const ext = path95.extname(file3.path).toLowerCase();
84009
85089
  const langDef = getLanguageForExtension(ext);
84010
85090
  const fileProfile = getProfileForFile(file3.path);
84011
85091
  const langId = fileProfile?.id || langDef?.id;
@@ -84018,7 +85098,7 @@ async function syntaxCheck(input, directory, config3) {
84018
85098
  let skippedCount = 0;
84019
85099
  for (const fileInfo of filesToCheck) {
84020
85100
  const { path: filePath } = fileInfo;
84021
- const fullPath = path92.isAbsolute(filePath) ? filePath : path92.join(directory, filePath);
85101
+ const fullPath = path95.isAbsolute(filePath) ? filePath : path95.join(directory, filePath);
84022
85102
  const result = {
84023
85103
  path: filePath,
84024
85104
  language: "",
@@ -84048,7 +85128,7 @@ async function syntaxCheck(input, directory, config3) {
84048
85128
  }
84049
85129
  let content;
84050
85130
  try {
84051
- content = fs76.readFileSync(fullPath, "utf8");
85131
+ content = fs79.readFileSync(fullPath, "utf8");
84052
85132
  } catch {
84053
85133
  result.skipped_reason = "file_read_error";
84054
85134
  skippedCount++;
@@ -84067,7 +85147,7 @@ async function syntaxCheck(input, directory, config3) {
84067
85147
  results.push(result);
84068
85148
  continue;
84069
85149
  }
84070
- const ext = path92.extname(filePath).toLowerCase();
85150
+ const ext = path95.extname(filePath).toLowerCase();
84071
85151
  const langDef = getLanguageForExtension(ext);
84072
85152
  result.language = profile?.id || langDef?.id || "unknown";
84073
85153
  const errors5 = extractSyntaxErrors(parser, content);
@@ -84159,8 +85239,8 @@ init_dist();
84159
85239
  init_utils();
84160
85240
  init_create_tool();
84161
85241
  init_path_security();
84162
- import * as fs77 from "fs";
84163
- import * as path93 from "path";
85242
+ import * as fs80 from "fs";
85243
+ import * as path96 from "path";
84164
85244
  var MAX_TEXT_LENGTH = 200;
84165
85245
  var MAX_FILE_SIZE_BYTES11 = 1024 * 1024;
84166
85246
  var SUPPORTED_EXTENSIONS4 = new Set([
@@ -84226,9 +85306,9 @@ function validatePathsInput(paths, cwd) {
84226
85306
  return { error: "paths contains path traversal", resolvedPath: null };
84227
85307
  }
84228
85308
  try {
84229
- const resolvedPath = path93.resolve(paths);
84230
- const normalizedCwd = path93.resolve(cwd);
84231
- const normalizedResolved = path93.resolve(resolvedPath);
85309
+ const resolvedPath = path96.resolve(paths);
85310
+ const normalizedCwd = path96.resolve(cwd);
85311
+ const normalizedResolved = path96.resolve(resolvedPath);
84232
85312
  if (!normalizedResolved.startsWith(normalizedCwd)) {
84233
85313
  return {
84234
85314
  error: "paths must be within the current working directory",
@@ -84244,13 +85324,13 @@ function validatePathsInput(paths, cwd) {
84244
85324
  }
84245
85325
  }
84246
85326
  function isSupportedExtension(filePath) {
84247
- const ext = path93.extname(filePath).toLowerCase();
85327
+ const ext = path96.extname(filePath).toLowerCase();
84248
85328
  return SUPPORTED_EXTENSIONS4.has(ext);
84249
85329
  }
84250
85330
  function findSourceFiles4(dir, files = []) {
84251
85331
  let entries;
84252
85332
  try {
84253
- entries = fs77.readdirSync(dir);
85333
+ entries = fs80.readdirSync(dir);
84254
85334
  } catch {
84255
85335
  return files;
84256
85336
  }
@@ -84259,16 +85339,16 @@ function findSourceFiles4(dir, files = []) {
84259
85339
  if (SKIP_DIRECTORIES5.has(entry)) {
84260
85340
  continue;
84261
85341
  }
84262
- const fullPath = path93.join(dir, entry);
84263
- let stat3;
85342
+ const fullPath = path96.join(dir, entry);
85343
+ let stat4;
84264
85344
  try {
84265
- stat3 = fs77.statSync(fullPath);
85345
+ stat4 = fs80.statSync(fullPath);
84266
85346
  } catch {
84267
85347
  continue;
84268
85348
  }
84269
- if (stat3.isDirectory()) {
85349
+ if (stat4.isDirectory()) {
84270
85350
  findSourceFiles4(fullPath, files);
84271
- } else if (stat3.isFile()) {
85351
+ } else if (stat4.isFile()) {
84272
85352
  if (isSupportedExtension(fullPath)) {
84273
85353
  files.push(fullPath);
84274
85354
  }
@@ -84355,7 +85435,7 @@ var todo_extract = createSwarmTool({
84355
85435
  return JSON.stringify(errorResult, null, 2);
84356
85436
  }
84357
85437
  const scanPath = resolvedPath;
84358
- if (!fs77.existsSync(scanPath)) {
85438
+ if (!fs80.existsSync(scanPath)) {
84359
85439
  const errorResult = {
84360
85440
  error: `path not found: ${pathsInput}`,
84361
85441
  total: 0,
@@ -84365,13 +85445,13 @@ var todo_extract = createSwarmTool({
84365
85445
  return JSON.stringify(errorResult, null, 2);
84366
85446
  }
84367
85447
  const filesToScan = [];
84368
- const stat3 = fs77.statSync(scanPath);
84369
- if (stat3.isFile()) {
85448
+ const stat4 = fs80.statSync(scanPath);
85449
+ if (stat4.isFile()) {
84370
85450
  if (isSupportedExtension(scanPath)) {
84371
85451
  filesToScan.push(scanPath);
84372
85452
  } else {
84373
85453
  const errorResult = {
84374
- error: `unsupported file extension: ${path93.extname(scanPath)}`,
85454
+ error: `unsupported file extension: ${path96.extname(scanPath)}`,
84375
85455
  total: 0,
84376
85456
  byPriority: { high: 0, medium: 0, low: 0 },
84377
85457
  entries: []
@@ -84384,11 +85464,11 @@ var todo_extract = createSwarmTool({
84384
85464
  const allEntries = [];
84385
85465
  for (const filePath of filesToScan) {
84386
85466
  try {
84387
- const fileStat = fs77.statSync(filePath);
85467
+ const fileStat = fs80.statSync(filePath);
84388
85468
  if (fileStat.size > MAX_FILE_SIZE_BYTES11) {
84389
85469
  continue;
84390
85470
  }
84391
- const content = fs77.readFileSync(filePath, "utf-8");
85471
+ const content = fs80.readFileSync(filePath, "utf-8");
84392
85472
  const entries = parseTodoComments(content, filePath, tagsSet);
84393
85473
  allEntries.push(...entries);
84394
85474
  } catch {}
@@ -84418,18 +85498,18 @@ init_tool();
84418
85498
  init_loader();
84419
85499
  init_schema();
84420
85500
  init_gate_evidence();
84421
- import * as fs79 from "fs";
84422
- import * as path95 from "path";
85501
+ import * as fs82 from "fs";
85502
+ import * as path98 from "path";
84423
85503
 
84424
85504
  // src/hooks/diff-scope.ts
84425
- import * as fs78 from "fs";
84426
- import * as path94 from "path";
85505
+ import * as fs81 from "fs";
85506
+ import * as path97 from "path";
84427
85507
  function getDeclaredScope(taskId, directory) {
84428
85508
  try {
84429
- const planPath = path94.join(directory, ".swarm", "plan.json");
84430
- if (!fs78.existsSync(planPath))
85509
+ const planPath = path97.join(directory, ".swarm", "plan.json");
85510
+ if (!fs81.existsSync(planPath))
84431
85511
  return null;
84432
- const raw = fs78.readFileSync(planPath, "utf-8");
85512
+ const raw = fs81.readFileSync(planPath, "utf-8");
84433
85513
  const plan = JSON.parse(raw);
84434
85514
  for (const phase of plan.phases ?? []) {
84435
85515
  for (const task of phase.tasks ?? []) {
@@ -84545,7 +85625,7 @@ var TIER_3_PATTERNS = [
84545
85625
  ];
84546
85626
  function matchesTier3Pattern(files) {
84547
85627
  for (const file3 of files) {
84548
- const fileName = path95.basename(file3);
85628
+ const fileName = path98.basename(file3);
84549
85629
  for (const pattern of TIER_3_PATTERNS) {
84550
85630
  if (pattern.test(fileName)) {
84551
85631
  return true;
@@ -84559,8 +85639,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
84559
85639
  if (hasActiveTurboMode()) {
84560
85640
  const resolvedDir2 = workingDirectory;
84561
85641
  try {
84562
- const planPath = path95.join(resolvedDir2, ".swarm", "plan.json");
84563
- const planRaw = fs79.readFileSync(planPath, "utf-8");
85642
+ const planPath = path98.join(resolvedDir2, ".swarm", "plan.json");
85643
+ const planRaw = fs82.readFileSync(planPath, "utf-8");
84564
85644
  const plan = JSON.parse(planRaw);
84565
85645
  for (const planPhase of plan.phases ?? []) {
84566
85646
  for (const task of planPhase.tasks ?? []) {
@@ -84629,8 +85709,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
84629
85709
  }
84630
85710
  try {
84631
85711
  const resolvedDir2 = workingDirectory;
84632
- const planPath = path95.join(resolvedDir2, ".swarm", "plan.json");
84633
- const planRaw = fs79.readFileSync(planPath, "utf-8");
85712
+ const planPath = path98.join(resolvedDir2, ".swarm", "plan.json");
85713
+ const planRaw = fs82.readFileSync(planPath, "utf-8");
84634
85714
  const plan = JSON.parse(planRaw);
84635
85715
  for (const planPhase of plan.phases ?? []) {
84636
85716
  for (const task of planPhase.tasks ?? []) {
@@ -84854,8 +85934,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
84854
85934
  };
84855
85935
  }
84856
85936
  }
84857
- normalizedDir = path95.normalize(args2.working_directory);
84858
- const pathParts = normalizedDir.split(path95.sep);
85937
+ normalizedDir = path98.normalize(args2.working_directory);
85938
+ const pathParts = normalizedDir.split(path98.sep);
84859
85939
  if (pathParts.includes("..")) {
84860
85940
  return {
84861
85941
  success: false,
@@ -84865,11 +85945,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
84865
85945
  ]
84866
85946
  };
84867
85947
  }
84868
- const resolvedDir = path95.resolve(normalizedDir);
85948
+ const resolvedDir = path98.resolve(normalizedDir);
84869
85949
  try {
84870
- const realPath = fs79.realpathSync(resolvedDir);
84871
- const planPath = path95.join(realPath, ".swarm", "plan.json");
84872
- if (!fs79.existsSync(planPath)) {
85950
+ const realPath = fs82.realpathSync(resolvedDir);
85951
+ const planPath = path98.join(realPath, ".swarm", "plan.json");
85952
+ if (!fs82.existsSync(planPath)) {
84873
85953
  return {
84874
85954
  success: false,
84875
85955
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -84900,22 +85980,22 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
84900
85980
  }
84901
85981
  if (args2.status === "in_progress") {
84902
85982
  try {
84903
- const evidencePath = path95.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
84904
- fs79.mkdirSync(path95.dirname(evidencePath), { recursive: true });
84905
- 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");
84906
85986
  let writeOk = false;
84907
85987
  try {
84908
- fs79.writeSync(fd, JSON.stringify({
85988
+ fs82.writeSync(fd, JSON.stringify({
84909
85989
  taskId: args2.task_id,
84910
85990
  required_gates: ["reviewer", "test_engineer"],
84911
85991
  gates: {}
84912
85992
  }, null, 2));
84913
85993
  writeOk = true;
84914
85994
  } finally {
84915
- fs79.closeSync(fd);
85995
+ fs82.closeSync(fd);
84916
85996
  if (!writeOk) {
84917
85997
  try {
84918
- fs79.unlinkSync(evidencePath);
85998
+ fs82.unlinkSync(evidencePath);
84919
85999
  } catch {}
84920
86000
  }
84921
86001
  }
@@ -84925,8 +86005,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
84925
86005
  recoverTaskStateFromDelegations(args2.task_id);
84926
86006
  let phaseRequiresReviewer = true;
84927
86007
  try {
84928
- const planPath = path95.join(directory, ".swarm", "plan.json");
84929
- const planRaw = fs79.readFileSync(planPath, "utf-8");
86008
+ const planPath = path98.join(directory, ".swarm", "plan.json");
86009
+ const planRaw = fs82.readFileSync(planPath, "utf-8");
84930
86010
  const plan = JSON.parse(planRaw);
84931
86011
  const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
84932
86012
  if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
@@ -85035,8 +86115,8 @@ init_utils2();
85035
86115
  init_ledger();
85036
86116
  init_manager();
85037
86117
  init_create_tool();
85038
- import fs80 from "fs";
85039
- import path96 from "path";
86118
+ import fs83 from "fs";
86119
+ import path99 from "path";
85040
86120
  function derivePlanId5(plan) {
85041
86121
  return `${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
85042
86122
  }
@@ -85087,7 +86167,7 @@ async function executeWriteDriftEvidence(args2, directory) {
85087
86167
  entries: [evidenceEntry]
85088
86168
  };
85089
86169
  const filename = "drift-verifier.json";
85090
- const relativePath = path96.join("evidence", String(phase), filename);
86170
+ const relativePath = path99.join("evidence", String(phase), filename);
85091
86171
  let validatedPath;
85092
86172
  try {
85093
86173
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -85098,12 +86178,12 @@ async function executeWriteDriftEvidence(args2, directory) {
85098
86178
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
85099
86179
  }, null, 2);
85100
86180
  }
85101
- const evidenceDir = path96.dirname(validatedPath);
86181
+ const evidenceDir = path99.dirname(validatedPath);
85102
86182
  try {
85103
- await fs80.promises.mkdir(evidenceDir, { recursive: true });
85104
- const tempPath = path96.join(evidenceDir, `.${filename}.tmp`);
85105
- await fs80.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
85106
- 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);
85107
86187
  let snapshotInfo;
85108
86188
  let snapshotError;
85109
86189
  let qaProfileLocked;
@@ -85197,8 +86277,8 @@ var write_drift_evidence = createSwarmTool({
85197
86277
  init_tool();
85198
86278
  init_utils2();
85199
86279
  init_create_tool();
85200
- import fs81 from "fs";
85201
- import path97 from "path";
86280
+ import fs84 from "fs";
86281
+ import path100 from "path";
85202
86282
  function normalizeVerdict2(verdict) {
85203
86283
  switch (verdict) {
85204
86284
  case "APPROVED":
@@ -85246,7 +86326,7 @@ async function executeWriteHallucinationEvidence(args2, directory) {
85246
86326
  entries: [evidenceEntry]
85247
86327
  };
85248
86328
  const filename = "hallucination-guard.json";
85249
- const relativePath = path97.join("evidence", String(phase), filename);
86329
+ const relativePath = path100.join("evidence", String(phase), filename);
85250
86330
  let validatedPath;
85251
86331
  try {
85252
86332
  validatedPath = validateSwarmPath(directory, relativePath);
@@ -85257,12 +86337,12 @@ async function executeWriteHallucinationEvidence(args2, directory) {
85257
86337
  message: error93 instanceof Error ? error93.message : "Failed to validate path"
85258
86338
  }, null, 2);
85259
86339
  }
85260
- const evidenceDir = path97.dirname(validatedPath);
86340
+ const evidenceDir = path100.dirname(validatedPath);
85261
86341
  try {
85262
- await fs81.promises.mkdir(evidenceDir, { recursive: true });
85263
- const tempPath = path97.join(evidenceDir, `.${filename}.tmp`);
85264
- await fs81.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
85265
- 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);
85266
86346
  return JSON.stringify({
85267
86347
  success: true,
85268
86348
  phase,
@@ -85369,6 +86449,11 @@ var OpenCodeSwarm = async (ctx) => {
85369
86449
  const contextBudgetHandler = createContextBudgetHandler(config3);
85370
86450
  const commandHandler = createSwarmCommandHandler(ctx.directory, Object.fromEntries(agentDefinitions.map((agent) => [agent.name, agent])));
85371
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);
85372
86457
  const delegationGateHooks = createDelegationGateHook(config3, ctx.directory);
85373
86458
  const delegationSanitizerHook = createDelegationSanitizerHook(ctx.directory);
85374
86459
  const guardrailsFallback = config3.guardrails?.enabled === false ? { ...config3.guardrails, enabled: false } : config3.guardrails ?? {};
@@ -85471,7 +86556,7 @@ var OpenCodeSwarm = async (ctx) => {
85471
86556
  const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
85472
86557
  preflightTriggerManager = new PTM(automationConfig);
85473
86558
  const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
85474
- const swarmDir = path98.resolve(ctx.directory, ".swarm");
86559
+ const swarmDir = path101.resolve(ctx.directory, ".swarm");
85475
86560
  statusArtifact = new ASA(swarmDir);
85476
86561
  statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
85477
86562
  if (automationConfig.capabilities?.evidence_auto_summaries === true) {
@@ -85891,6 +86976,10 @@ var OpenCodeSwarm = async (ctx) => {
85891
86976
  await activityHooks.toolAfter(input, output);
85892
86977
  if (_dbg)
85893
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);
85894
86983
  await guardrailsHooks.toolAfter(input, output);
85895
86984
  if (_dbg)
85896
86985
  console.error(`[DIAG] toolAfter guardrails done tool=${_toolName}`);