opencode-swarm 7.7.0 → 7.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -34,7 +34,7 @@ var package_default;
34
34
  var init_package = __esm(() => {
35
35
  package_default = {
36
36
  name: "opencode-swarm",
37
- version: "7.7.0",
37
+ version: "7.8.1",
38
38
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
39
39
  main: "dist/index.js",
40
40
  types: "dist/index.d.ts",
@@ -142,6 +142,14 @@ function warn(message, data) {
142
142
  console.warn(`[opencode-swarm ${timestamp}] WARN: ${message}`);
143
143
  }
144
144
  }
145
+ function error(message, data) {
146
+ const timestamp = new Date().toISOString();
147
+ if (data !== undefined) {
148
+ console.error(`[opencode-swarm ${timestamp}] ERROR: ${message}`, data);
149
+ } else {
150
+ console.error(`[opencode-swarm ${timestamp}] ERROR: ${message}`);
151
+ }
152
+ }
145
153
  var init_logger = () => {};
146
154
 
147
155
  // src/utils/merge.ts
@@ -16410,12 +16418,26 @@ var init_constants = __esm(() => {
16410
16418
  "repo_map"
16411
16419
  ],
16412
16420
  critic_oversight: [
16413
- "complexity_hotspots",
16414
- "detect_domains",
16415
- "imports",
16421
+ "diff",
16422
+ "diff_summary",
16423
+ "evidence_check",
16424
+ "check_gate_status",
16425
+ "completion_verify",
16426
+ "get_approved_plan",
16427
+ "req_coverage",
16428
+ "test_impact",
16429
+ "pkg_audit",
16430
+ "secretscan",
16431
+ "sast_scan",
16432
+ "repo_map",
16416
16433
  "retrieve_summary",
16434
+ "knowledge_recall",
16417
16435
  "symbols",
16418
- "knowledge_recall"
16436
+ "batch_symbols",
16437
+ "search",
16438
+ "imports",
16439
+ "complexity_hotspots",
16440
+ "detect_domains"
16419
16441
  ],
16420
16442
  docs: [
16421
16443
  "detect_domains",
@@ -16509,60 +16531,43 @@ var init_constants = __esm(() => {
16509
16531
  });
16510
16532
 
16511
16533
  // src/config/schema.ts
16512
- function stripKnownSwarmPrefix(agentName) {
16534
+ function getCanonicalAgentRole(agentName, generatedAgentNames) {
16513
16535
  if (!agentName)
16514
16536
  return agentName;
16515
16537
  const normalized = agentName.toLowerCase();
16516
- let stripped = normalized;
16517
- let previous = "";
16518
- while (stripped !== previous) {
16519
- previous = stripped;
16520
- for (const prefix of KNOWN_SWARM_PREFIXES) {
16521
- for (const sep2 of SEPARATORS) {
16522
- const prefixWithSep = prefix + sep2;
16523
- if (stripped.startsWith(prefixWithSep)) {
16524
- stripped = stripped.slice(prefixWithSep.length);
16525
- break;
16526
- }
16527
- }
16528
- if (stripped !== previous)
16529
- break;
16530
- }
16538
+ if (CANONICAL_ROLES_SET.has(normalized)) {
16539
+ return normalized;
16531
16540
  }
16532
- if (ALL_AGENT_NAMES.includes(stripped)) {
16533
- return stripped;
16541
+ if (generatedAgentNames) {
16542
+ const registry2 = new Set;
16543
+ for (const n of generatedAgentNames)
16544
+ registry2.add(n.toLowerCase());
16545
+ if (!registry2.has(normalized)) {
16546
+ return agentName;
16547
+ }
16534
16548
  }
16535
- for (const agent of ALL_AGENT_NAMES) {
16549
+ for (const role of CANONICAL_ROLES_LONGEST_FIRST) {
16536
16550
  for (const sep2 of SEPARATORS) {
16537
- const suffix = sep2 + agent;
16551
+ const suffix = sep2 + role;
16538
16552
  if (normalized.endsWith(suffix)) {
16539
- return agent;
16553
+ return role;
16540
16554
  }
16541
16555
  }
16542
- if (normalized === agent) {
16543
- return agent;
16544
- }
16545
16556
  }
16546
16557
  return agentName;
16547
16558
  }
16548
- 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, GeneralCouncilMemberConfigSchema, GeneralCouncilConfigSchema, CouncilConfigSchema, ParallelizationConfigSchema, PluginConfigSchema;
16559
+ function stripKnownSwarmPrefix(agentName) {
16560
+ return getCanonicalAgentRole(agentName);
16561
+ }
16562
+ var SEPARATORS, CANONICAL_ROLES_LONGEST_FIRST, CANONICAL_ROLES_SET, 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, GeneralCouncilMemberConfigSchema, GeneralCouncilConfigSchema, CouncilConfigSchema, ParallelizationConfigSchema, PluginConfigSchema;
16549
16563
  var init_schema = __esm(() => {
16550
16564
  init_zod();
16551
16565
  init_constants();
16552
- KNOWN_SWARM_PREFIXES = [
16553
- "paid",
16554
- "local",
16555
- "cloud",
16556
- "enterprise",
16557
- "mega",
16558
- "default",
16559
- "custom",
16560
- "team",
16561
- "project",
16562
- "swarm",
16563
- "synthetic"
16564
- ];
16565
16566
  SEPARATORS = ["_", "-", " "];
16567
+ CANONICAL_ROLES_LONGEST_FIRST = [
16568
+ ...ALL_AGENT_NAMES
16569
+ ].sort((a, b) => b.length - a.length);
16570
+ CANONICAL_ROLES_SET = new Set(ALL_AGENT_NAMES);
16566
16571
  AgentOverrideConfigSchema = exports_external.object({
16567
16572
  model: exports_external.string().optional(),
16568
16573
  variant: exports_external.string().min(1).optional(),
@@ -17175,13 +17180,143 @@ var init_schema = __esm(() => {
17175
17180
  critic_model: exports_external.string().optional(),
17176
17181
  max_interactions_per_phase: exports_external.number().int().min(5).max(200).default(50),
17177
17182
  deadlock_threshold: exports_external.number().int().min(2).max(10).default(3),
17178
- escalation_mode: exports_external.enum(["pause", "terminate"]).default("pause")
17179
- }).optional().default({
17183
+ escalation_mode: exports_external.enum(["pause", "terminate"]).default("pause"),
17184
+ mode: exports_external.enum(["assisted", "supervised", "strict"]).default("supervised"),
17185
+ fail_closed: exports_external.boolean().default(true),
17186
+ permission_policy: exports_external.object({
17187
+ enabled: exports_external.boolean().default(true),
17188
+ trusted_roots: exports_external.array(exports_external.string()).default(["."]),
17189
+ trusted_domains: exports_external.array(exports_external.string()).default([]),
17190
+ protected_paths: exports_external.array(exports_external.string()).default([
17191
+ ".git",
17192
+ ".github/workflows",
17193
+ ".swarm",
17194
+ "package.json",
17195
+ "package-lock.json",
17196
+ "bun.lock",
17197
+ "CHANGELOG.md",
17198
+ ".release-please-manifest.json",
17199
+ "release-please-config.json",
17200
+ "src/index.ts",
17201
+ "src/hooks/guardrails.ts",
17202
+ "src/hooks/delegation-gate.ts",
17203
+ "src/hooks/scope-guard.ts",
17204
+ "src/hooks/full-auto-permission.ts",
17205
+ "src/hooks/full-auto-intercept.ts",
17206
+ "src/full-auto",
17207
+ "src/config/schema.ts",
17208
+ "src/config/constants.ts",
17209
+ "src/tools/phase-complete.ts",
17210
+ "dist"
17211
+ ]),
17212
+ allow_defaults: exports_external.boolean().default(true)
17213
+ }).default(() => ({
17214
+ enabled: true,
17215
+ trusted_roots: ["."],
17216
+ trusted_domains: [],
17217
+ protected_paths: [
17218
+ ".git",
17219
+ ".github/workflows",
17220
+ ".swarm",
17221
+ "package.json",
17222
+ "package-lock.json",
17223
+ "bun.lock",
17224
+ "CHANGELOG.md",
17225
+ ".release-please-manifest.json",
17226
+ "release-please-config.json",
17227
+ "src/index.ts",
17228
+ "src/hooks/guardrails.ts",
17229
+ "src/hooks/delegation-gate.ts",
17230
+ "src/hooks/scope-guard.ts",
17231
+ "src/hooks/full-auto-permission.ts",
17232
+ "src/hooks/full-auto-intercept.ts",
17233
+ "src/full-auto",
17234
+ "src/config/schema.ts",
17235
+ "src/config/constants.ts",
17236
+ "src/tools/phase-complete.ts",
17237
+ "dist"
17238
+ ],
17239
+ allow_defaults: true
17240
+ })),
17241
+ denials: exports_external.object({
17242
+ max_consecutive: exports_external.number().int().min(1).max(50).default(3),
17243
+ max_total: exports_external.number().int().min(1).max(500).default(20),
17244
+ on_limit: exports_external.enum(["pause", "terminate"]).default("pause")
17245
+ }).default(() => ({
17246
+ max_consecutive: 3,
17247
+ max_total: 20,
17248
+ on_limit: "pause"
17249
+ })),
17250
+ oversight: exports_external.object({
17251
+ on_plan_change: exports_external.boolean().default(true),
17252
+ on_task_completion: exports_external.boolean().default(false),
17253
+ on_phase_boundary: exports_external.boolean().default(true),
17254
+ on_high_risk_action: exports_external.boolean().default(true),
17255
+ on_subagent_return_warning: exports_external.boolean().default(true),
17256
+ every_tool_calls: exports_external.number().int().min(0).max(1e4).default(25),
17257
+ every_architect_turns: exports_external.number().int().min(0).max(1000).default(5),
17258
+ every_minutes: exports_external.number().int().min(0).max(1440).default(20)
17259
+ }).default(() => ({
17260
+ on_plan_change: true,
17261
+ on_task_completion: false,
17262
+ on_phase_boundary: true,
17263
+ on_high_risk_action: true,
17264
+ on_subagent_return_warning: true,
17265
+ every_tool_calls: 25,
17266
+ every_architect_turns: 5,
17267
+ every_minutes: 20
17268
+ }))
17269
+ }).optional().default(() => ({
17180
17270
  enabled: false,
17181
17271
  max_interactions_per_phase: 50,
17182
17272
  deadlock_threshold: 3,
17183
- escalation_mode: "pause"
17184
- })
17273
+ escalation_mode: "pause",
17274
+ mode: "supervised",
17275
+ fail_closed: true,
17276
+ permission_policy: {
17277
+ enabled: true,
17278
+ trusted_roots: ["."],
17279
+ trusted_domains: [],
17280
+ protected_paths: [
17281
+ ".git",
17282
+ ".github/workflows",
17283
+ ".swarm",
17284
+ "package.json",
17285
+ "package-lock.json",
17286
+ "bun.lock",
17287
+ "CHANGELOG.md",
17288
+ ".release-please-manifest.json",
17289
+ "release-please-config.json",
17290
+ "src/index.ts",
17291
+ "src/hooks/guardrails.ts",
17292
+ "src/hooks/delegation-gate.ts",
17293
+ "src/hooks/scope-guard.ts",
17294
+ "src/hooks/full-auto-permission.ts",
17295
+ "src/hooks/full-auto-intercept.ts",
17296
+ "src/full-auto",
17297
+ "src/config/schema.ts",
17298
+ "src/config/constants.ts",
17299
+ "src/tools/phase-complete.ts",
17300
+ "dist"
17301
+ ],
17302
+ allow_defaults: true
17303
+ },
17304
+ denials: {
17305
+ max_consecutive: 3,
17306
+ max_total: 20,
17307
+ on_limit: "pause"
17308
+ },
17309
+ oversight: {
17310
+ on_plan_change: true,
17311
+ on_task_completion: false,
17312
+ on_phase_boundary: true,
17313
+ on_high_risk_action: true,
17314
+ on_subagent_return_warning: true,
17315
+ every_tool_calls: 25,
17316
+ every_architect_turns: 5,
17317
+ every_minutes: 20
17318
+ }
17319
+ }))
17185
17320
  });
17186
17321
  });
17187
17322
 
@@ -20563,6 +20698,7 @@ function resetSwarmState() {
20563
20698
  swarmState.opencodeClient = null;
20564
20699
  swarmState.curatorInitAgentNames = [];
20565
20700
  swarmState.curatorPhaseAgentNames = [];
20701
+ swarmState.generatedAgentNames = [];
20566
20702
  _rehydrationCache = null;
20567
20703
  swarmState.fullAutoEnabledInConfig = false;
20568
20704
  swarmState.environmentProfiles.clear();
@@ -20607,6 +20743,7 @@ var init_state = __esm(() => {
20607
20743
  opencodeClient: null,
20608
20744
  curatorInitAgentNames: [],
20609
20745
  curatorPhaseAgentNames: [],
20746
+ generatedAgentNames: [],
20610
20747
  lastBudgetPct: 0,
20611
20748
  agentSessions: defaultRunContext.agentSessions,
20612
20749
  pendingRehydrations: new Set,
@@ -40762,8 +40899,254 @@ var init_export = __esm(() => {
40762
40899
  init_export_service();
40763
40900
  });
40764
40901
 
40902
+ // src/full-auto/state.ts
40903
+ import * as fs11 from "fs";
40904
+ import * as path24 from "path";
40905
+ function nowISO() {
40906
+ return new Date().toISOString();
40907
+ }
40908
+ function ensureSwarmDir(directory) {
40909
+ const swarmDir = path24.resolve(directory, ".swarm");
40910
+ if (!fs11.existsSync(swarmDir)) {
40911
+ fs11.mkdirSync(swarmDir, { recursive: true });
40912
+ }
40913
+ return swarmDir;
40914
+ }
40915
+ function emptyCounters() {
40916
+ return {
40917
+ architectTurns: 0,
40918
+ toolCalls: 0,
40919
+ coderDelegations: 0,
40920
+ reviewerRejections: 0,
40921
+ testFailures: 0,
40922
+ oversightChecks: 0,
40923
+ consecutiveNoProgressTurns: 0
40924
+ };
40925
+ }
40926
+ function emptyState(sessionID, mode = "supervised") {
40927
+ const now = nowISO();
40928
+ return {
40929
+ status: "idle",
40930
+ sessionID,
40931
+ mode,
40932
+ startedAt: now,
40933
+ updatedAt: now,
40934
+ denialCounters: { consecutive: 0, total: 0 },
40935
+ denialHistory: [],
40936
+ counters: emptyCounters()
40937
+ };
40938
+ }
40939
+ function withStateLock(directory, fn) {
40940
+ let release;
40941
+ try {
40942
+ const lockTarget = validateSwarmPath(directory, STATE_FILE);
40943
+ if (!fs11.existsSync(lockTarget)) {
40944
+ ensureSwarmDir(directory);
40945
+ const seed = {
40946
+ version: 2,
40947
+ updatedAt: nowISO(),
40948
+ oversightSequence: 0,
40949
+ sessions: {}
40950
+ };
40951
+ fs11.writeFileSync(lockTarget, `${JSON.stringify(seed, null, 2)}
40952
+ `, "utf-8");
40953
+ }
40954
+ release = lockfile5.lockSync(lockTarget, {
40955
+ retries: { retries: 5, minTimeout: 5, maxTimeout: 50 },
40956
+ stale: 5000
40957
+ });
40958
+ } catch (error93) {
40959
+ warn(`[full-auto/state] cross-process lock unavailable; proceeding unlocked: ${error93 instanceof Error ? error93.message : String(error93)}`);
40960
+ }
40961
+ try {
40962
+ return fn();
40963
+ } finally {
40964
+ if (release) {
40965
+ try {
40966
+ release();
40967
+ } catch (releaseError) {
40968
+ warn(`[full-auto/state] lock release failed: ${releaseError instanceof Error ? releaseError.message : String(releaseError)}`);
40969
+ }
40970
+ }
40971
+ }
40972
+ }
40973
+ function emptyPersisted() {
40974
+ return {
40975
+ version: 2,
40976
+ updatedAt: nowISO(),
40977
+ oversightSequence: 0,
40978
+ sessions: {}
40979
+ };
40980
+ }
40981
+ function markStateUnreadable(reason) {
40982
+ stateUnreadable = true;
40983
+ stateUnreadableReason = reason;
40984
+ error(`[full-auto/state] state file unreadable: ${reason} \u2014 failing closed`);
40985
+ }
40986
+ function clearStateUnreadable() {
40987
+ stateUnreadable = false;
40988
+ stateUnreadableReason = "";
40989
+ }
40990
+ function readPersisted(directory) {
40991
+ try {
40992
+ const filePath = validateSwarmPath(directory, STATE_FILE);
40993
+ if (!fs11.existsSync(filePath)) {
40994
+ clearStateUnreadable();
40995
+ return emptyPersisted();
40996
+ }
40997
+ const raw = fs11.readFileSync(filePath, "utf-8");
40998
+ const parsed = JSON.parse(raw);
40999
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || parsed.version !== 2 || !parsed.sessions || typeof parsed.sessions !== "object" || Array.isArray(parsed.sessions)) {
41000
+ markStateUnreadable(`malformed shape (version=${parsed?.version}, sessions type=${Array.isArray(parsed?.sessions) ? "array" : typeof parsed?.sessions})`);
41001
+ return emptyPersisted();
41002
+ }
41003
+ clearStateUnreadable();
41004
+ return {
41005
+ version: 2,
41006
+ updatedAt: parsed.updatedAt ?? nowISO(),
41007
+ oversightSequence: typeof parsed.oversightSequence === "number" ? parsed.oversightSequence : 0,
41008
+ sessions: parsed.sessions
41009
+ };
41010
+ } catch (error93) {
41011
+ const reason = error93 instanceof Error ? error93.message : String(error93);
41012
+ error(`[full-auto/state] Failed to read ${STATE_FILE}: ${reason} \u2014 attempting .bak recovery`);
41013
+ try {
41014
+ const bakPath = validateSwarmPath(directory, `${STATE_FILE}.bak`);
41015
+ if (fs11.existsSync(bakPath)) {
41016
+ const raw = fs11.readFileSync(bakPath, "utf-8");
41017
+ const parsed = JSON.parse(raw);
41018
+ if (parsed?.version === 2 && parsed.sessions && !Array.isArray(parsed.sessions)) {
41019
+ warn(`[full-auto/state] Recovered from ${STATE_FILE}.bak`);
41020
+ clearStateUnreadable();
41021
+ return {
41022
+ version: 2,
41023
+ updatedAt: parsed.updatedAt ?? nowISO(),
41024
+ oversightSequence: typeof parsed.oversightSequence === "number" ? parsed.oversightSequence : 0,
41025
+ sessions: parsed.sessions
41026
+ };
41027
+ }
41028
+ }
41029
+ } catch (bakError) {
41030
+ error(`[full-auto/state] .bak recovery also failed: ${bakError instanceof Error ? bakError.message : String(bakError)}`);
41031
+ }
41032
+ markStateUnreadable(`canonical=${reason}; .bak=missing-or-corrupt`);
41033
+ return emptyPersisted();
41034
+ }
41035
+ }
41036
+ function writePersisted(directory, persisted) {
41037
+ let filePath;
41038
+ let tmpPath;
41039
+ let bakPath;
41040
+ let payload;
41041
+ try {
41042
+ ensureSwarmDir(directory);
41043
+ filePath = validateSwarmPath(directory, STATE_FILE);
41044
+ tmpPath = validateSwarmPath(directory, `${STATE_FILE}.tmp`);
41045
+ bakPath = validateSwarmPath(directory, `${STATE_FILE}.bak`);
41046
+ persisted.updatedAt = nowISO();
41047
+ payload = `${JSON.stringify(persisted, null, 2)}
41048
+ `;
41049
+ } catch (error93) {
41050
+ const msg = error93 instanceof Error ? error93.message : String(error93);
41051
+ error(`[full-auto/state] Failed to prepare ${STATE_FILE} write: ${msg}`);
41052
+ throw new Error(`Full-Auto state persistence prepare failed: ${msg}`);
41053
+ }
41054
+ try {
41055
+ if (fs11.existsSync(filePath)) {
41056
+ fs11.copyFileSync(filePath, bakPath);
41057
+ }
41058
+ } catch {}
41059
+ try {
41060
+ fs11.writeFileSync(tmpPath, payload, "utf-8");
41061
+ try {
41062
+ const fd = fs11.openSync(tmpPath, "r+");
41063
+ try {
41064
+ fs11.fsyncSync(fd);
41065
+ } finally {
41066
+ fs11.closeSync(fd);
41067
+ }
41068
+ } catch {}
41069
+ fs11.renameSync(tmpPath, filePath);
41070
+ const readback = fs11.readFileSync(filePath, "utf-8");
41071
+ const parsed = JSON.parse(readback);
41072
+ if (parsed?.version !== 2) {
41073
+ throw new Error("Round-trip readback returned wrong version");
41074
+ }
41075
+ } catch (error93) {
41076
+ const msg = error93 instanceof Error ? error93.message : String(error93);
41077
+ error(`[full-auto/state] Failed to persist ${STATE_FILE} atomically: ${msg}`);
41078
+ throw new Error(`Full-Auto state persistence failed: ${msg}`);
41079
+ }
41080
+ }
41081
+ function startFullAutoRun(directory, sessionID, config3, options = {}) {
41082
+ return withStateLock(directory, () => {
41083
+ const persisted = readPersisted(directory);
41084
+ const existing = persisted.sessions[sessionID];
41085
+ const mode = config3?.mode ?? existing?.mode ?? "supervised";
41086
+ const state = existing ? {
41087
+ ...existing,
41088
+ status: "running",
41089
+ mode,
41090
+ planID: options.planID ?? existing.planID,
41091
+ currentPhase: options.phase ?? existing.currentPhase,
41092
+ currentTaskID: options.taskID ?? existing.currentTaskID,
41093
+ pauseReason: undefined,
41094
+ terminateReason: undefined,
41095
+ updatedAt: nowISO(),
41096
+ denialCounters: {
41097
+ consecutive: 0,
41098
+ total: existing.denialCounters.total
41099
+ }
41100
+ } : {
41101
+ ...emptyState(sessionID, mode),
41102
+ status: "running",
41103
+ planID: options.planID,
41104
+ currentPhase: options.phase,
41105
+ currentTaskID: options.taskID
41106
+ };
41107
+ persisted.sessions[sessionID] = state;
41108
+ writePersisted(directory, persisted);
41109
+ return state;
41110
+ });
41111
+ }
41112
+ function pauseFullAutoRun(directory, sessionID, reason) {
41113
+ return withStateLock(directory, () => {
41114
+ const persisted = readPersisted(directory);
41115
+ const state = persisted.sessions[sessionID];
41116
+ if (!state)
41117
+ return;
41118
+ state.status = "paused";
41119
+ state.pauseReason = reason;
41120
+ state.updatedAt = nowISO();
41121
+ persisted.sessions[sessionID] = state;
41122
+ writePersisted(directory, persisted);
41123
+ return state;
41124
+ });
41125
+ }
41126
+ function terminateFullAutoRun(directory, sessionID, reason) {
41127
+ return withStateLock(directory, () => {
41128
+ const persisted = readPersisted(directory);
41129
+ const state = persisted.sessions[sessionID];
41130
+ if (!state)
41131
+ return;
41132
+ state.status = "terminated";
41133
+ state.terminateReason = reason;
41134
+ state.updatedAt = nowISO();
41135
+ persisted.sessions[sessionID] = state;
41136
+ writePersisted(directory, persisted);
41137
+ return state;
41138
+ });
41139
+ }
41140
+ var import_proper_lockfile5, lockfile5, STATE_FILE = "full-auto-state.json", stateUnreadable = false, stateUnreadableReason = "";
41141
+ var init_state2 = __esm(() => {
41142
+ init_utils2();
41143
+ init_logger();
41144
+ import_proper_lockfile5 = __toESM(require_proper_lockfile(), 1);
41145
+ lockfile5 = import_proper_lockfile5.default;
41146
+ });
41147
+
40765
41148
  // src/commands/full-auto.ts
40766
- async function handleFullAutoCommand(_directory, args, sessionID) {
41149
+ async function handleFullAutoCommand(directory, args, sessionID) {
40767
41150
  if (!sessionID || sessionID.trim() === "") {
40768
41151
  return "Error: No active session context. Full-Auto Mode requires an active session. Use /swarm-full-auto from within an OpenCode session, or start a session first.";
40769
41152
  }
@@ -40783,16 +41166,63 @@ async function handleFullAutoCommand(_directory, args, sessionID) {
40783
41166
  if (newFullAutoMode && !swarmState.fullAutoEnabledInConfig) {
40784
41167
  return "Error: Full-Auto Mode cannot be enabled because full_auto.enabled is not set to true in the swarm plugin config. The autonomous oversight hook is inactive without config-level enablement. Set full_auto.enabled = true in your opencode-swarm config and restart.";
40785
41168
  }
41169
+ let v2Status = "unavailable";
41170
+ let modeLabel = "supervised";
41171
+ let denialMaxConsecutive = 3;
41172
+ let denialMaxTotal = 20;
41173
+ let failClosed = true;
41174
+ let durableError;
41175
+ try {
41176
+ const { config: config3 } = loadPluginConfigWithMeta(directory);
41177
+ const fullAutoConfig = config3.full_auto;
41178
+ modeLabel = fullAutoConfig?.mode ?? "supervised";
41179
+ denialMaxConsecutive = fullAutoConfig?.denials?.max_consecutive ?? 3;
41180
+ denialMaxTotal = fullAutoConfig?.denials?.max_total ?? 20;
41181
+ failClosed = fullAutoConfig?.fail_closed !== false;
41182
+ if (newFullAutoMode) {
41183
+ startFullAutoRun(directory, sessionID, fullAutoConfig);
41184
+ v2Status = "running";
41185
+ } else {
41186
+ const paused = pauseFullAutoRun(directory, sessionID, "/swarm full-auto off");
41187
+ if (!paused) {
41188
+ terminateFullAutoRun(directory, sessionID, "never started");
41189
+ }
41190
+ v2Status = "paused";
41191
+ }
41192
+ } catch (error93) {
41193
+ durableError = error93 instanceof Error ? error93.message : String(error93);
41194
+ error(`[full-auto] durable run-state write failed: ${durableError}`);
41195
+ }
41196
+ if (newFullAutoMode && durableError) {
41197
+ return [
41198
+ "Error: Full-Auto Mode could NOT be enabled \u2014 durable run-state write failed.",
41199
+ `Reason: ${durableError}.`,
41200
+ "Inspect .swarm/ permissions and disk space, then retry."
41201
+ ].join(" ");
41202
+ }
40786
41203
  session.fullAutoMode = newFullAutoMode;
40787
41204
  if (!newFullAutoMode) {
40788
41205
  session.fullAutoInteractionCount = 0;
40789
41206
  session.fullAutoDeadlockCount = 0;
40790
41207
  session.fullAutoLastQuestionHash = null;
40791
41208
  }
40792
- return newFullAutoMode ? "Full-Auto Mode enabled" : "Full-Auto Mode disabled";
41209
+ if (!newFullAutoMode) {
41210
+ return [
41211
+ "Full-Auto Mode disabled",
41212
+ `(v2 run-state: ${v2Status}; mode=${modeLabel})`
41213
+ ].join(" ");
41214
+ }
41215
+ return [
41216
+ "Full-Auto Mode enabled",
41217
+ `(v2 mode=${modeLabel}, fail_closed=${failClosed},`,
41218
+ `denials max ${denialMaxConsecutive} consecutive / ${denialMaxTotal} total)`
41219
+ ].join(" ");
40793
41220
  }
40794
41221
  var init_full_auto = __esm(() => {
41222
+ init_config();
41223
+ init_state2();
40795
41224
  init_state();
41225
+ init_logger();
40796
41226
  });
40797
41227
 
40798
41228
  // src/services/handoff-service.ts
@@ -41177,19 +41607,19 @@ var init_handoff_service = __esm(() => {
41177
41607
 
41178
41608
  // src/commands/handoff.ts
41179
41609
  import crypto4 from "crypto";
41180
- import { renameSync as renameSync6 } from "fs";
41610
+ import { renameSync as renameSync7 } from "fs";
41181
41611
  async function handleHandoffCommand(directory, _args) {
41182
41612
  const handoffData = await getHandoffData(directory);
41183
41613
  const markdown = formatHandoffMarkdown(handoffData);
41184
41614
  const resolvedPath = validateSwarmPath(directory, "handoff.md");
41185
41615
  const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
41186
41616
  await bunWrite(tempPath, markdown);
41187
- renameSync6(tempPath, resolvedPath);
41617
+ renameSync7(tempPath, resolvedPath);
41188
41618
  const continuationPrompt = formatContinuationPrompt(handoffData);
41189
41619
  const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
41190
41620
  const promptTempPath = `${promptPath}.tmp.${crypto4.randomUUID()}`;
41191
41621
  await bunWrite(promptTempPath, continuationPrompt);
41192
- renameSync6(promptTempPath, promptPath);
41622
+ renameSync7(promptTempPath, promptPath);
41193
41623
  await writeSnapshot(directory, swarmState);
41194
41624
  await flushPendingSnapshot(directory);
41195
41625
  return `## Handoff Brief Written
@@ -41564,9 +41994,9 @@ var init_issue = __esm(() => {
41564
41994
 
41565
41995
  // src/hooks/knowledge-migrator.ts
41566
41996
  import { randomUUID as randomUUID2 } from "crypto";
41567
- import { existsSync as existsSync14, readFileSync as readFileSync10 } from "fs";
41997
+ import { existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
41568
41998
  import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
41569
- import * as path24 from "path";
41999
+ import * as path25 from "path";
41570
42000
  async function migrateKnowledgeToExternal(_directory, _config) {
41571
42001
  return {
41572
42002
  migrated: false,
@@ -41577,10 +42007,10 @@ async function migrateKnowledgeToExternal(_directory, _config) {
41577
42007
  };
41578
42008
  }
41579
42009
  async function migrateContextToKnowledge(directory, config3) {
41580
- const sentinelPath = path24.join(directory, ".swarm", ".knowledge-migrated");
41581
- const contextPath = path24.join(directory, ".swarm", "context.md");
42010
+ const sentinelPath = path25.join(directory, ".swarm", ".knowledge-migrated");
42011
+ const contextPath = path25.join(directory, ".swarm", "context.md");
41582
42012
  const knowledgePath = resolveSwarmKnowledgePath(directory);
41583
- if (existsSync14(sentinelPath)) {
42013
+ if (existsSync15(sentinelPath)) {
41584
42014
  return {
41585
42015
  migrated: false,
41586
42016
  entriesMigrated: 0,
@@ -41589,7 +42019,7 @@ async function migrateContextToKnowledge(directory, config3) {
41589
42019
  skippedReason: "sentinel-exists"
41590
42020
  };
41591
42021
  }
41592
- if (!existsSync14(contextPath)) {
42022
+ if (!existsSync15(contextPath)) {
41593
42023
  return {
41594
42024
  migrated: false,
41595
42025
  entriesMigrated: 0,
@@ -41774,16 +42204,16 @@ function truncateLesson(text) {
41774
42204
  return `${text.slice(0, 277)}...`;
41775
42205
  }
41776
42206
  function inferProjectName(directory) {
41777
- const packageJsonPath = path24.join(directory, "package.json");
41778
- if (existsSync14(packageJsonPath)) {
42207
+ const packageJsonPath = path25.join(directory, "package.json");
42208
+ if (existsSync15(packageJsonPath)) {
41779
42209
  try {
41780
- const pkg = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
42210
+ const pkg = JSON.parse(readFileSync11(packageJsonPath, "utf-8"));
41781
42211
  if (pkg.name && typeof pkg.name === "string") {
41782
42212
  return pkg.name;
41783
42213
  }
41784
42214
  } catch {}
41785
42215
  }
41786
- return path24.basename(directory);
42216
+ return path25.basename(directory);
41787
42217
  }
41788
42218
  async function writeSentinel(sentinelPath, migrated, dropped) {
41789
42219
  const sentinel = {
@@ -41795,7 +42225,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
41795
42225
  schema_version: 1,
41796
42226
  migration_tool: "knowledge-migrator.ts"
41797
42227
  };
41798
- await mkdir5(path24.dirname(sentinelPath), { recursive: true });
42228
+ await mkdir5(path25.dirname(sentinelPath), { recursive: true });
41799
42229
  await writeFile6(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
41800
42230
  }
41801
42231
  var _internals14;
@@ -42316,8 +42746,8 @@ function containsControlChars(str) {
42316
42746
  var init_path_security = () => {};
42317
42747
 
42318
42748
  // src/tools/lint.ts
42319
- import * as fs11 from "fs";
42320
- import * as path25 from "path";
42749
+ import * as fs12 from "fs";
42750
+ import * as path26 from "path";
42321
42751
  function validateArgs(args) {
42322
42752
  if (typeof args !== "object" || args === null)
42323
42753
  return false;
@@ -42328,9 +42758,9 @@ function validateArgs(args) {
42328
42758
  }
42329
42759
  function getLinterCommand(linter, mode, projectDir) {
42330
42760
  const isWindows = process.platform === "win32";
42331
- const binDir = path25.join(projectDir, "node_modules", ".bin");
42332
- const biomeBin = isWindows ? path25.join(binDir, "biome.EXE") : path25.join(binDir, "biome");
42333
- const eslintBin = isWindows ? path25.join(binDir, "eslint.cmd") : path25.join(binDir, "eslint");
42761
+ const binDir = path26.join(projectDir, "node_modules", ".bin");
42762
+ const biomeBin = isWindows ? path26.join(binDir, "biome.EXE") : path26.join(binDir, "biome");
42763
+ const eslintBin = isWindows ? path26.join(binDir, "eslint.cmd") : path26.join(binDir, "eslint");
42334
42764
  switch (linter) {
42335
42765
  case "biome":
42336
42766
  if (mode === "fix") {
@@ -42346,7 +42776,7 @@ function getLinterCommand(linter, mode, projectDir) {
42346
42776
  }
42347
42777
  function getAdditionalLinterCommand(linter, mode, cwd) {
42348
42778
  const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
42349
- const gradlew = fs11.existsSync(path25.join(cwd, gradlewName)) ? path25.join(cwd, gradlewName) : null;
42779
+ const gradlew = fs12.existsSync(path26.join(cwd, gradlewName)) ? path26.join(cwd, gradlewName) : null;
42350
42780
  switch (linter) {
42351
42781
  case "ruff":
42352
42782
  return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
@@ -42380,12 +42810,12 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
42380
42810
  }
42381
42811
  }
42382
42812
  function detectRuff(cwd) {
42383
- if (fs11.existsSync(path25.join(cwd, "ruff.toml")))
42813
+ if (fs12.existsSync(path26.join(cwd, "ruff.toml")))
42384
42814
  return isCommandAvailable("ruff");
42385
42815
  try {
42386
- const pyproject = path25.join(cwd, "pyproject.toml");
42387
- if (fs11.existsSync(pyproject)) {
42388
- const content = fs11.readFileSync(pyproject, "utf-8");
42816
+ const pyproject = path26.join(cwd, "pyproject.toml");
42817
+ if (fs12.existsSync(pyproject)) {
42818
+ const content = fs12.readFileSync(pyproject, "utf-8");
42389
42819
  if (content.includes("[tool.ruff]"))
42390
42820
  return isCommandAvailable("ruff");
42391
42821
  }
@@ -42393,21 +42823,21 @@ function detectRuff(cwd) {
42393
42823
  return false;
42394
42824
  }
42395
42825
  function detectClippy(cwd) {
42396
- return fs11.existsSync(path25.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
42826
+ return fs12.existsSync(path26.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
42397
42827
  }
42398
42828
  function detectGolangciLint(cwd) {
42399
- return fs11.existsSync(path25.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
42829
+ return fs12.existsSync(path26.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
42400
42830
  }
42401
42831
  function detectCheckstyle(cwd) {
42402
- const hasMaven = fs11.existsSync(path25.join(cwd, "pom.xml"));
42403
- const hasGradle = fs11.existsSync(path25.join(cwd, "build.gradle")) || fs11.existsSync(path25.join(cwd, "build.gradle.kts"));
42404
- const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs11.existsSync(path25.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
42832
+ const hasMaven = fs12.existsSync(path26.join(cwd, "pom.xml"));
42833
+ const hasGradle = fs12.existsSync(path26.join(cwd, "build.gradle")) || fs12.existsSync(path26.join(cwd, "build.gradle.kts"));
42834
+ const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs12.existsSync(path26.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
42405
42835
  return (hasMaven || hasGradle) && hasBinary;
42406
42836
  }
42407
42837
  function detectKtlint(cwd) {
42408
- const hasKotlin = fs11.existsSync(path25.join(cwd, "build.gradle.kts")) || fs11.existsSync(path25.join(cwd, "build.gradle")) || (() => {
42838
+ const hasKotlin = fs12.existsSync(path26.join(cwd, "build.gradle.kts")) || fs12.existsSync(path26.join(cwd, "build.gradle")) || (() => {
42409
42839
  try {
42410
- return fs11.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
42840
+ return fs12.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
42411
42841
  } catch {
42412
42842
  return false;
42413
42843
  }
@@ -42416,7 +42846,7 @@ function detectKtlint(cwd) {
42416
42846
  }
42417
42847
  function detectDotnetFormat(cwd) {
42418
42848
  try {
42419
- const files = fs11.readdirSync(cwd);
42849
+ const files = fs12.readdirSync(cwd);
42420
42850
  const hasCsproj = files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"));
42421
42851
  return hasCsproj && isCommandAvailable("dotnet");
42422
42852
  } catch {
@@ -42424,14 +42854,14 @@ function detectDotnetFormat(cwd) {
42424
42854
  }
42425
42855
  }
42426
42856
  function detectCppcheck(cwd) {
42427
- if (fs11.existsSync(path25.join(cwd, "CMakeLists.txt"))) {
42857
+ if (fs12.existsSync(path26.join(cwd, "CMakeLists.txt"))) {
42428
42858
  return isCommandAvailable("cppcheck");
42429
42859
  }
42430
42860
  try {
42431
- const dirsToCheck = [cwd, path25.join(cwd, "src")];
42861
+ const dirsToCheck = [cwd, path26.join(cwd, "src")];
42432
42862
  const hasCpp = dirsToCheck.some((dir) => {
42433
42863
  try {
42434
- return fs11.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
42864
+ return fs12.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
42435
42865
  } catch {
42436
42866
  return false;
42437
42867
  }
@@ -42442,13 +42872,13 @@ function detectCppcheck(cwd) {
42442
42872
  }
42443
42873
  }
42444
42874
  function detectSwiftlint(cwd) {
42445
- return fs11.existsSync(path25.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
42875
+ return fs12.existsSync(path26.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
42446
42876
  }
42447
42877
  function detectDartAnalyze(cwd) {
42448
- return fs11.existsSync(path25.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
42878
+ return fs12.existsSync(path26.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
42449
42879
  }
42450
42880
  function detectRubocop(cwd) {
42451
- return (fs11.existsSync(path25.join(cwd, "Gemfile")) || fs11.existsSync(path25.join(cwd, "gems.rb")) || fs11.existsSync(path25.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
42881
+ return (fs12.existsSync(path26.join(cwd, "Gemfile")) || fs12.existsSync(path26.join(cwd, "gems.rb")) || fs12.existsSync(path26.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
42452
42882
  }
42453
42883
  function detectAdditionalLinter(cwd) {
42454
42884
  if (detectRuff(cwd))
@@ -42476,10 +42906,10 @@ function detectAdditionalLinter(cwd) {
42476
42906
  function findBinInAncestors(startDir, binName) {
42477
42907
  let dir = startDir;
42478
42908
  while (true) {
42479
- const candidate = path25.join(dir, "node_modules", ".bin", binName);
42480
- if (fs11.existsSync(candidate))
42909
+ const candidate = path26.join(dir, "node_modules", ".bin", binName);
42910
+ if (fs12.existsSync(candidate))
42481
42911
  return candidate;
42482
- const parent = path25.dirname(dir);
42912
+ const parent = path26.dirname(dir);
42483
42913
  if (parent === dir)
42484
42914
  break;
42485
42915
  dir = parent;
@@ -42488,11 +42918,11 @@ function findBinInAncestors(startDir, binName) {
42488
42918
  }
42489
42919
  function findBinInEnvPath(binName) {
42490
42920
  const searchPath = process.env.PATH ?? "";
42491
- for (const dir of searchPath.split(path25.delimiter)) {
42921
+ for (const dir of searchPath.split(path26.delimiter)) {
42492
42922
  if (!dir)
42493
42923
  continue;
42494
- const candidate = path25.join(dir, binName);
42495
- if (fs11.existsSync(candidate))
42924
+ const candidate = path26.join(dir, binName);
42925
+ if (fs12.existsSync(candidate))
42496
42926
  return candidate;
42497
42927
  }
42498
42928
  return null;
@@ -42500,17 +42930,17 @@ function findBinInEnvPath(binName) {
42500
42930
  async function detectAvailableLinter(directory) {
42501
42931
  if (!directory)
42502
42932
  return null;
42503
- if (!fs11.existsSync(directory))
42933
+ if (!fs12.existsSync(directory))
42504
42934
  return null;
42505
42935
  const projectDir = directory;
42506
42936
  const isWindows = process.platform === "win32";
42507
- const biomeBin = isWindows ? path25.join(projectDir, "node_modules", ".bin", "biome.EXE") : path25.join(projectDir, "node_modules", ".bin", "biome");
42508
- const eslintBin = isWindows ? path25.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path25.join(projectDir, "node_modules", ".bin", "eslint");
42937
+ const biomeBin = isWindows ? path26.join(projectDir, "node_modules", ".bin", "biome.EXE") : path26.join(projectDir, "node_modules", ".bin", "biome");
42938
+ const eslintBin = isWindows ? path26.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path26.join(projectDir, "node_modules", ".bin", "eslint");
42509
42939
  const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
42510
42940
  if (localResult)
42511
42941
  return localResult;
42512
- const biomeAncestor = findBinInAncestors(path25.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
42513
- const eslintAncestor = findBinInAncestors(path25.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
42942
+ const biomeAncestor = findBinInAncestors(path26.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
42943
+ const eslintAncestor = findBinInAncestors(path26.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
42514
42944
  if (biomeAncestor || eslintAncestor) {
42515
42945
  return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
42516
42946
  }
@@ -42529,11 +42959,11 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
42529
42959
  stderr: "pipe"
42530
42960
  });
42531
42961
  const biomeExit = biomeProc.exited;
42532
- const timeout = new Promise((resolve9) => setTimeout(() => resolve9("timeout"), DETECT_TIMEOUT));
42962
+ const timeout = new Promise((resolve10) => setTimeout(() => resolve10("timeout"), DETECT_TIMEOUT));
42533
42963
  const result = await Promise.race([biomeExit, timeout]);
42534
42964
  if (result === "timeout") {
42535
42965
  biomeProc.kill();
42536
- } else if (biomeProc.exitCode === 0 && fs11.existsSync(biomeBin)) {
42966
+ } else if (biomeProc.exitCode === 0 && fs12.existsSync(biomeBin)) {
42537
42967
  return "biome";
42538
42968
  }
42539
42969
  } catch {}
@@ -42543,11 +42973,11 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
42543
42973
  stderr: "pipe"
42544
42974
  });
42545
42975
  const eslintExit = eslintProc.exited;
42546
- const timeout = new Promise((resolve9) => setTimeout(() => resolve9("timeout"), DETECT_TIMEOUT));
42976
+ const timeout = new Promise((resolve10) => setTimeout(() => resolve10("timeout"), DETECT_TIMEOUT));
42547
42977
  const result = await Promise.race([eslintExit, timeout]);
42548
42978
  if (result === "timeout") {
42549
42979
  eslintProc.kill();
42550
- } else if (eslintProc.exitCode === 0 && fs11.existsSync(eslintBin)) {
42980
+ } else if (eslintProc.exitCode === 0 && fs12.existsSync(eslintBin)) {
42551
42981
  return "eslint";
42552
42982
  }
42553
42983
  } catch {}
@@ -42732,8 +43162,8 @@ For Rust: rustup component add clippy`
42732
43162
  });
42733
43163
 
42734
43164
  // src/tools/secretscan.ts
42735
- import * as fs12 from "fs";
42736
- import * as path26 from "path";
43165
+ import * as fs13 from "fs";
43166
+ import * as path27 from "path";
42737
43167
  function calculateShannonEntropy(str) {
42738
43168
  if (str.length === 0)
42739
43169
  return 0;
@@ -42781,11 +43211,11 @@ function isGlobOrPathPattern(pattern) {
42781
43211
  return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
42782
43212
  }
42783
43213
  function loadSecretScanIgnore(scanDir) {
42784
- const ignorePath = path26.join(scanDir, ".secretscanignore");
43214
+ const ignorePath = path27.join(scanDir, ".secretscanignore");
42785
43215
  try {
42786
- if (!fs12.existsSync(ignorePath))
43216
+ if (!fs13.existsSync(ignorePath))
42787
43217
  return [];
42788
- const content = fs12.readFileSync(ignorePath, "utf8");
43218
+ const content = fs13.readFileSync(ignorePath, "utf8");
42789
43219
  const patterns = [];
42790
43220
  for (const rawLine of content.split(/\r?\n/)) {
42791
43221
  const line = rawLine.trim();
@@ -42804,7 +43234,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
42804
43234
  if (exactNames.has(entry))
42805
43235
  return true;
42806
43236
  for (const pattern of globPatterns) {
42807
- if (path26.matchesGlob(relPath, pattern))
43237
+ if (path27.matchesGlob(relPath, pattern))
42808
43238
  return true;
42809
43239
  }
42810
43240
  return false;
@@ -42825,7 +43255,7 @@ function validateDirectoryInput(dir) {
42825
43255
  return null;
42826
43256
  }
42827
43257
  function isBinaryFile(filePath, buffer) {
42828
- const ext = path26.extname(filePath).toLowerCase();
43258
+ const ext = path27.extname(filePath).toLowerCase();
42829
43259
  if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
42830
43260
  return true;
42831
43261
  }
@@ -42903,7 +43333,7 @@ function createRedactedContext(line, findings) {
42903
43333
  function scanFileForSecrets(filePath) {
42904
43334
  const findings = [];
42905
43335
  try {
42906
- const lstat = fs12.lstatSync(filePath);
43336
+ const lstat = fs13.lstatSync(filePath);
42907
43337
  if (lstat.isSymbolicLink()) {
42908
43338
  return findings;
42909
43339
  }
@@ -42912,14 +43342,14 @@ function scanFileForSecrets(filePath) {
42912
43342
  }
42913
43343
  let buffer;
42914
43344
  if (O_NOFOLLOW !== undefined) {
42915
- const fd = fs12.openSync(filePath, "r", O_NOFOLLOW);
43345
+ const fd = fs13.openSync(filePath, "r", O_NOFOLLOW);
42916
43346
  try {
42917
- buffer = fs12.readFileSync(fd);
43347
+ buffer = fs13.readFileSync(fd);
42918
43348
  } finally {
42919
- fs12.closeSync(fd);
43349
+ fs13.closeSync(fd);
42920
43350
  }
42921
43351
  } else {
42922
- buffer = fs12.readFileSync(filePath);
43352
+ buffer = fs13.readFileSync(filePath);
42923
43353
  }
42924
43354
  if (isBinaryFile(filePath, buffer)) {
42925
43355
  return findings;
@@ -42961,9 +43391,9 @@ function isSymlinkLoop(realPath, visited) {
42961
43391
  return false;
42962
43392
  }
42963
43393
  function isPathWithinScope(realPath, scanDir) {
42964
- const resolvedScanDir = path26.resolve(scanDir);
42965
- const resolvedRealPath = path26.resolve(realPath);
42966
- return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path26.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
43394
+ const resolvedScanDir = path27.resolve(scanDir);
43395
+ const resolvedRealPath = path27.resolve(realPath);
43396
+ return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path27.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
42967
43397
  }
42968
43398
  function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
42969
43399
  skippedDirs: 0,
@@ -42974,7 +43404,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
42974
43404
  const files = [];
42975
43405
  let entries;
42976
43406
  try {
42977
- entries = fs12.readdirSync(dir);
43407
+ entries = fs13.readdirSync(dir);
42978
43408
  } catch {
42979
43409
  stats.fileErrors++;
42980
43410
  return files;
@@ -42989,15 +43419,15 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
42989
43419
  return a.localeCompare(b);
42990
43420
  });
42991
43421
  for (const entry of entries) {
42992
- const fullPath = path26.join(dir, entry);
42993
- const relPath = path26.relative(scanDir, fullPath).replace(/\\/g, "/");
43422
+ const fullPath = path27.join(dir, entry);
43423
+ const relPath = path27.relative(scanDir, fullPath).replace(/\\/g, "/");
42994
43424
  if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
42995
43425
  stats.skippedDirs++;
42996
43426
  continue;
42997
43427
  }
42998
43428
  let lstat;
42999
43429
  try {
43000
- lstat = fs12.lstatSync(fullPath);
43430
+ lstat = fs13.lstatSync(fullPath);
43001
43431
  } catch {
43002
43432
  stats.fileErrors++;
43003
43433
  continue;
@@ -43009,7 +43439,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
43009
43439
  if (lstat.isDirectory()) {
43010
43440
  let realPath;
43011
43441
  try {
43012
- realPath = fs12.realpathSync(fullPath);
43442
+ realPath = fs13.realpathSync(fullPath);
43013
43443
  } catch {
43014
43444
  stats.fileErrors++;
43015
43445
  continue;
@@ -43025,7 +43455,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
43025
43455
  const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
43026
43456
  files.push(...subFiles);
43027
43457
  } else if (lstat.isFile()) {
43028
- const ext = path26.extname(fullPath).toLowerCase();
43458
+ const ext = path27.extname(fullPath).toLowerCase();
43029
43459
  if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
43030
43460
  files.push(fullPath);
43031
43461
  } else {
@@ -43228,7 +43658,7 @@ var init_secretscan = __esm(() => {
43228
43658
  redactTemplate: () => "SK[REDACTED]"
43229
43659
  }
43230
43660
  ];
43231
- O_NOFOLLOW = process.platform !== "win32" ? fs12.constants.O_NOFOLLOW : undefined;
43661
+ O_NOFOLLOW = process.platform !== "win32" ? fs13.constants.O_NOFOLLOW : undefined;
43232
43662
  secretscan = createSwarmTool({
43233
43663
  description: "Scan directory for potential secrets (API keys, tokens, passwords) using regex patterns and entropy heuristics. Returns metadata-only findings with redacted previews - NEVER returns raw secrets. Excludes common directories (node_modules, .git, dist, etc.) by default. Supports glob patterns (e.g. **/.svelte-kit/**, **/*.test.ts) and reads .secretscanignore at the scan root.",
43234
43664
  args: {
@@ -43285,15 +43715,15 @@ var init_secretscan = __esm(() => {
43285
43715
  }
43286
43716
  }
43287
43717
  try {
43288
- const _scanDirRaw = path26.resolve(directory);
43718
+ const _scanDirRaw = path27.resolve(directory);
43289
43719
  const scanDir = (() => {
43290
43720
  try {
43291
- return fs12.realpathSync(_scanDirRaw);
43721
+ return fs13.realpathSync(_scanDirRaw);
43292
43722
  } catch {
43293
43723
  return _scanDirRaw;
43294
43724
  }
43295
43725
  })();
43296
- if (!fs12.existsSync(scanDir)) {
43726
+ if (!fs13.existsSync(scanDir)) {
43297
43727
  const errorResult = {
43298
43728
  error: "directory not found",
43299
43729
  scan_dir: directory,
@@ -43304,7 +43734,7 @@ var init_secretscan = __esm(() => {
43304
43734
  };
43305
43735
  return JSON.stringify(errorResult, null, 2);
43306
43736
  }
43307
- const dirStat = fs12.statSync(scanDir);
43737
+ const dirStat = fs13.statSync(scanDir);
43308
43738
  if (!dirStat.isDirectory()) {
43309
43739
  const errorResult = {
43310
43740
  error: "target must be a directory, not a file",
@@ -43355,7 +43785,7 @@ var init_secretscan = __esm(() => {
43355
43785
  break;
43356
43786
  const fileFindings = scanFileForSecrets(filePath);
43357
43787
  try {
43358
- const stat3 = fs12.statSync(filePath);
43788
+ const stat3 = fs13.statSync(filePath);
43359
43789
  if (stat3.size > MAX_FILE_SIZE_BYTES) {
43360
43790
  skippedFiles++;
43361
43791
  continue;
@@ -43431,15 +43861,15 @@ var init_secretscan = __esm(() => {
43431
43861
  });
43432
43862
 
43433
43863
  // src/test-impact/analyzer.ts
43434
- import fs13 from "fs";
43435
- import path27 from "path";
43864
+ import fs14 from "fs";
43865
+ import path28 from "path";
43436
43866
  function normalizePath(p) {
43437
43867
  return p.replace(/\\/g, "/");
43438
43868
  }
43439
43869
  function isCacheStale(impactMap, generatedAtMs) {
43440
43870
  for (const sourcePath of Object.keys(impactMap)) {
43441
43871
  try {
43442
- const stat3 = fs13.statSync(sourcePath);
43872
+ const stat3 = fs14.statSync(sourcePath);
43443
43873
  if (stat3.mtimeMs > generatedAtMs) {
43444
43874
  return true;
43445
43875
  }
@@ -43453,15 +43883,15 @@ function resolveRelativeImport(fromDir, importPath) {
43453
43883
  if (!importPath.startsWith(".")) {
43454
43884
  return null;
43455
43885
  }
43456
- const resolved = path27.resolve(fromDir, importPath);
43457
- if (path27.extname(resolved)) {
43458
- if (fs13.existsSync(resolved) && fs13.statSync(resolved).isFile()) {
43886
+ const resolved = path28.resolve(fromDir, importPath);
43887
+ if (path28.extname(resolved)) {
43888
+ if (fs14.existsSync(resolved) && fs14.statSync(resolved).isFile()) {
43459
43889
  return normalizePath(resolved);
43460
43890
  }
43461
43891
  } else {
43462
43892
  for (const ext of EXTENSIONS_TO_TRY) {
43463
43893
  const withExt = resolved + ext;
43464
- if (fs13.existsSync(withExt) && fs13.statSync(withExt).isFile()) {
43894
+ if (fs14.existsSync(withExt) && fs14.statSync(withExt).isFile()) {
43465
43895
  return normalizePath(withExt);
43466
43896
  }
43467
43897
  }
@@ -43480,13 +43910,13 @@ function findTestFilesSync(cwd) {
43480
43910
  function walk(dir, visitedInodes) {
43481
43911
  let entries;
43482
43912
  try {
43483
- entries = fs13.readdirSync(dir, { withFileTypes: true });
43913
+ entries = fs14.readdirSync(dir, { withFileTypes: true });
43484
43914
  } catch {
43485
43915
  return;
43486
43916
  }
43487
43917
  let dirInode;
43488
43918
  try {
43489
- dirInode = fs13.statSync(dir).ino;
43919
+ dirInode = fs14.statSync(dir).ino;
43490
43920
  } catch {
43491
43921
  return;
43492
43922
  }
@@ -43499,12 +43929,12 @@ function findTestFilesSync(cwd) {
43499
43929
  for (const entry of entries) {
43500
43930
  if (entry.isDirectory()) {
43501
43931
  if (!skipDirs.has(entry.name)) {
43502
- walk(path27.join(dir, entry.name), visitedInodes);
43932
+ walk(path28.join(dir, entry.name), visitedInodes);
43503
43933
  }
43504
43934
  } else if (entry.isFile()) {
43505
43935
  const name = entry.name;
43506
43936
  if (/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name)) {
43507
- testFiles.push(normalizePath(path27.join(dir, entry.name)));
43937
+ testFiles.push(normalizePath(path28.join(dir, entry.name)));
43508
43938
  }
43509
43939
  }
43510
43940
  }
@@ -43534,7 +43964,7 @@ async function buildImpactMapInternal(cwd) {
43534
43964
  for (const testFile of testFiles) {
43535
43965
  let content;
43536
43966
  try {
43537
- content = fs13.readFileSync(testFile, "utf-8");
43967
+ content = fs14.readFileSync(testFile, "utf-8");
43538
43968
  } catch {
43539
43969
  continue;
43540
43970
  }
@@ -43542,7 +43972,7 @@ async function buildImpactMapInternal(cwd) {
43542
43972
  continue;
43543
43973
  }
43544
43974
  const imports = extractImports(content);
43545
- const testDir = path27.dirname(testFile);
43975
+ const testDir = path28.dirname(testFile);
43546
43976
  for (const importPath of imports) {
43547
43977
  const resolvedSource = resolveRelativeImport(testDir, importPath);
43548
43978
  if (resolvedSource === null) {
@@ -43564,10 +43994,10 @@ async function buildImpactMap(cwd) {
43564
43994
  return impactMap;
43565
43995
  }
43566
43996
  async function loadImpactMap(cwd) {
43567
- const cachePath = path27.join(cwd, ".swarm", "cache", "impact-map.json");
43568
- if (fs13.existsSync(cachePath)) {
43997
+ const cachePath = path28.join(cwd, ".swarm", "cache", "impact-map.json");
43998
+ if (fs14.existsSync(cachePath)) {
43569
43999
  try {
43570
- const content = fs13.readFileSync(cachePath, "utf-8");
44000
+ const content = fs14.readFileSync(cachePath, "utf-8");
43571
44001
  const data = JSON.parse(content);
43572
44002
  const map3 = data.map;
43573
44003
  const generatedAt = new Date(data.generatedAt).getTime();
@@ -43579,17 +44009,17 @@ async function loadImpactMap(cwd) {
43579
44009
  return _internals17.buildImpactMap(cwd);
43580
44010
  }
43581
44011
  async function saveImpactMap(cwd, impactMap) {
43582
- const cacheDir2 = path27.join(cwd, ".swarm", "cache");
43583
- const cachePath = path27.join(cacheDir2, "impact-map.json");
43584
- if (!fs13.existsSync(cacheDir2)) {
43585
- fs13.mkdirSync(cacheDir2, { recursive: true });
44012
+ const cacheDir2 = path28.join(cwd, ".swarm", "cache");
44013
+ const cachePath = path28.join(cacheDir2, "impact-map.json");
44014
+ if (!fs14.existsSync(cacheDir2)) {
44015
+ fs14.mkdirSync(cacheDir2, { recursive: true });
43586
44016
  }
43587
44017
  const data = {
43588
44018
  generatedAt: new Date().toISOString(),
43589
44019
  fileCount: Object.keys(impactMap).length,
43590
44020
  map: impactMap
43591
44021
  };
43592
- fs13.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
44022
+ fs14.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
43593
44023
  }
43594
44024
  async function analyzeImpact(changedFiles, cwd) {
43595
44025
  if (!Array.isArray(changedFiles)) {
@@ -43606,7 +44036,7 @@ async function analyzeImpact(changedFiles, cwd) {
43606
44036
  const impactedTestsSet = new Set;
43607
44037
  const untestedFiles = [];
43608
44038
  for (const changedFile of validFiles) {
43609
- const normalizedChanged = normalizePath(path27.resolve(changedFile));
44039
+ const normalizedChanged = normalizePath(path28.resolve(changedFile));
43610
44040
  const tests = impactMap[normalizedChanged];
43611
44041
  if (tests && tests.length > 0) {
43612
44042
  for (const test of tests) {
@@ -43869,10 +44299,10 @@ function detectFlakyTests(allHistory) {
43869
44299
  var FLAKY_THRESHOLD = 0.3, MIN_RUNS_FOR_QUARANTINE = 5, MAX_HISTORY_RUNS = 20;
43870
44300
 
43871
44301
  // src/test-impact/history-store.ts
43872
- import fs14 from "fs";
43873
- import path28 from "path";
44302
+ import fs15 from "fs";
44303
+ import path29 from "path";
43874
44304
  function getHistoryPath(workingDir) {
43875
- return path28.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
44305
+ return path29.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
43876
44306
  }
43877
44307
  function sanitizeErrorMessage(errorMessage) {
43878
44308
  if (errorMessage === undefined) {
@@ -43927,9 +44357,9 @@ function appendTestRun(record3, workingDir) {
43927
44357
  changedFiles: sanitizeChangedFiles(record3.changedFiles || [])
43928
44358
  };
43929
44359
  const historyPath = getHistoryPath(workingDir);
43930
- const historyDir = path28.dirname(historyPath);
43931
- if (!fs14.existsSync(historyDir)) {
43932
- fs14.mkdirSync(historyDir, { recursive: true });
44360
+ const historyDir = path29.dirname(historyPath);
44361
+ if (!fs15.existsSync(historyDir)) {
44362
+ fs15.mkdirSync(historyDir, { recursive: true });
43933
44363
  }
43934
44364
  const existingRecords = readAllRecords(historyPath);
43935
44365
  existingRecords.push(sanitizedRecord);
@@ -43954,24 +44384,24 @@ function appendTestRun(record3, workingDir) {
43954
44384
  `)}
43955
44385
  `;
43956
44386
  const tempPath = `${historyPath}.tmp`;
43957
- fs14.writeFileSync(tempPath, content, "utf-8");
43958
- fs14.renameSync(tempPath, historyPath);
44387
+ fs15.writeFileSync(tempPath, content, "utf-8");
44388
+ fs15.renameSync(tempPath, historyPath);
43959
44389
  } catch (err) {
43960
44390
  try {
43961
44391
  const tempPath = `${historyPath}.tmp`;
43962
- if (fs14.existsSync(tempPath)) {
43963
- fs14.unlinkSync(tempPath);
44392
+ if (fs15.existsSync(tempPath)) {
44393
+ fs15.unlinkSync(tempPath);
43964
44394
  }
43965
44395
  } catch {}
43966
44396
  throw new Error(`Failed to write test history: ${err instanceof Error ? err.message : String(err)}`);
43967
44397
  }
43968
44398
  }
43969
44399
  function readAllRecords(historyPath) {
43970
- if (!fs14.existsSync(historyPath)) {
44400
+ if (!fs15.existsSync(historyPath)) {
43971
44401
  return [];
43972
44402
  }
43973
44403
  try {
43974
- const content = fs14.readFileSync(historyPath, "utf-8");
44404
+ const content = fs15.readFileSync(historyPath, "utf-8");
43975
44405
  const lines = content.split(`
43976
44406
  `);
43977
44407
  const records = [];
@@ -44008,8 +44438,8 @@ var init_history_store = __esm(() => {
44008
44438
  });
44009
44439
 
44010
44440
  // src/tools/resolve-working-directory.ts
44011
- import * as fs15 from "fs";
44012
- import * as path29 from "path";
44441
+ import * as fs16 from "fs";
44442
+ import * as path30 from "path";
44013
44443
  function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
44014
44444
  if (workingDirectory == null || workingDirectory === "") {
44015
44445
  return { success: true, directory: fallbackDirectory };
@@ -44029,18 +44459,18 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
44029
44459
  };
44030
44460
  }
44031
44461
  }
44032
- const normalizedDir = path29.normalize(workingDirectory);
44033
- const pathParts = normalizedDir.split(path29.sep);
44462
+ const normalizedDir = path30.normalize(workingDirectory);
44463
+ const pathParts = normalizedDir.split(path30.sep);
44034
44464
  if (pathParts.includes("..")) {
44035
44465
  return {
44036
44466
  success: false,
44037
44467
  message: "Invalid working_directory: path traversal sequences (..) are not allowed"
44038
44468
  };
44039
44469
  }
44040
- const resolvedDir = path29.resolve(normalizedDir);
44470
+ const resolvedDir = path30.resolve(normalizedDir);
44041
44471
  let statResult;
44042
44472
  try {
44043
- statResult = fs15.statSync(resolvedDir);
44473
+ statResult = fs16.statSync(resolvedDir);
44044
44474
  } catch {
44045
44475
  return {
44046
44476
  success: false,
@@ -44053,17 +44483,17 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
44053
44483
  message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
44054
44484
  };
44055
44485
  }
44056
- const resolvedFallback = path29.resolve(fallbackDirectory);
44486
+ const resolvedFallback = path30.resolve(fallbackDirectory);
44057
44487
  let fallbackExists = false;
44058
44488
  try {
44059
- fs15.statSync(resolvedFallback);
44489
+ fs16.statSync(resolvedFallback);
44060
44490
  fallbackExists = true;
44061
44491
  } catch {
44062
44492
  fallbackExists = false;
44063
44493
  }
44064
44494
  if (workingDirectory != null && workingDirectory !== "") {
44065
44495
  if (fallbackExists) {
44066
- const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path29.sep);
44496
+ const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path30.sep);
44067
44497
  if (isSubdirectory) {
44068
44498
  return {
44069
44499
  success: false,
@@ -44084,8 +44514,8 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
44084
44514
  var init_resolve_working_directory = () => {};
44085
44515
 
44086
44516
  // src/tools/test-runner.ts
44087
- import * as fs16 from "fs";
44088
- import * as path30 from "path";
44517
+ import * as fs17 from "fs";
44518
+ import * as path31 from "path";
44089
44519
  function isAbsolutePath(str) {
44090
44520
  if (str.startsWith("/"))
44091
44521
  return true;
@@ -44150,19 +44580,19 @@ function hasDevDependency(devDeps, ...patterns) {
44150
44580
  return hasPackageJsonDependency(devDeps, ...patterns);
44151
44581
  }
44152
44582
  function detectGoTest(cwd) {
44153
- return fs16.existsSync(path30.join(cwd, "go.mod")) && isCommandAvailable("go");
44583
+ return fs17.existsSync(path31.join(cwd, "go.mod")) && isCommandAvailable("go");
44154
44584
  }
44155
44585
  function detectJavaMaven(cwd) {
44156
- return fs16.existsSync(path30.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
44586
+ return fs17.existsSync(path31.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
44157
44587
  }
44158
44588
  function detectGradle(cwd) {
44159
- const hasBuildFile = fs16.existsSync(path30.join(cwd, "build.gradle")) || fs16.existsSync(path30.join(cwd, "build.gradle.kts"));
44160
- const hasGradlew = fs16.existsSync(path30.join(cwd, "gradlew")) || fs16.existsSync(path30.join(cwd, "gradlew.bat"));
44589
+ const hasBuildFile = fs17.existsSync(path31.join(cwd, "build.gradle")) || fs17.existsSync(path31.join(cwd, "build.gradle.kts"));
44590
+ const hasGradlew = fs17.existsSync(path31.join(cwd, "gradlew")) || fs17.existsSync(path31.join(cwd, "gradlew.bat"));
44161
44591
  return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
44162
44592
  }
44163
44593
  function detectDotnetTest(cwd) {
44164
44594
  try {
44165
- const files = fs16.readdirSync(cwd);
44595
+ const files = fs17.readdirSync(cwd);
44166
44596
  const hasCsproj = files.some((f) => f.endsWith(".csproj"));
44167
44597
  return hasCsproj && isCommandAvailable("dotnet");
44168
44598
  } catch {
@@ -44170,32 +44600,32 @@ function detectDotnetTest(cwd) {
44170
44600
  }
44171
44601
  }
44172
44602
  function detectCTest(cwd) {
44173
- const hasSource = fs16.existsSync(path30.join(cwd, "CMakeLists.txt"));
44174
- const hasBuildCache = fs16.existsSync(path30.join(cwd, "CMakeCache.txt")) || fs16.existsSync(path30.join(cwd, "build", "CMakeCache.txt"));
44603
+ const hasSource = fs17.existsSync(path31.join(cwd, "CMakeLists.txt"));
44604
+ const hasBuildCache = fs17.existsSync(path31.join(cwd, "CMakeCache.txt")) || fs17.existsSync(path31.join(cwd, "build", "CMakeCache.txt"));
44175
44605
  return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
44176
44606
  }
44177
44607
  function detectSwiftTest(cwd) {
44178
- return fs16.existsSync(path30.join(cwd, "Package.swift")) && isCommandAvailable("swift");
44608
+ return fs17.existsSync(path31.join(cwd, "Package.swift")) && isCommandAvailable("swift");
44179
44609
  }
44180
44610
  function detectDartTest(cwd) {
44181
- return fs16.existsSync(path30.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
44611
+ return fs17.existsSync(path31.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
44182
44612
  }
44183
44613
  function detectRSpec(cwd) {
44184
- const hasRSpecFile = fs16.existsSync(path30.join(cwd, ".rspec"));
44185
- const hasGemfile = fs16.existsSync(path30.join(cwd, "Gemfile"));
44186
- const hasSpecDir = fs16.existsSync(path30.join(cwd, "spec"));
44614
+ const hasRSpecFile = fs17.existsSync(path31.join(cwd, ".rspec"));
44615
+ const hasGemfile = fs17.existsSync(path31.join(cwd, "Gemfile"));
44616
+ const hasSpecDir = fs17.existsSync(path31.join(cwd, "spec"));
44187
44617
  const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
44188
44618
  return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
44189
44619
  }
44190
44620
  function detectMinitest(cwd) {
44191
- return fs16.existsSync(path30.join(cwd, "test")) && (fs16.existsSync(path30.join(cwd, "Gemfile")) || fs16.existsSync(path30.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
44621
+ return fs17.existsSync(path31.join(cwd, "test")) && (fs17.existsSync(path31.join(cwd, "Gemfile")) || fs17.existsSync(path31.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
44192
44622
  }
44193
44623
  async function detectTestFramework(cwd) {
44194
44624
  const baseDir = cwd;
44195
44625
  try {
44196
- const packageJsonPath = path30.join(baseDir, "package.json");
44197
- if (fs16.existsSync(packageJsonPath)) {
44198
- const content = fs16.readFileSync(packageJsonPath, "utf-8");
44626
+ const packageJsonPath = path31.join(baseDir, "package.json");
44627
+ if (fs17.existsSync(packageJsonPath)) {
44628
+ const content = fs17.readFileSync(packageJsonPath, "utf-8");
44199
44629
  const pkg = JSON.parse(content);
44200
44630
  const _deps = pkg.dependencies || {};
44201
44631
  const devDeps = pkg.devDependencies || {};
@@ -44214,38 +44644,38 @@ async function detectTestFramework(cwd) {
44214
44644
  return "jest";
44215
44645
  if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
44216
44646
  return "mocha";
44217
- if (fs16.existsSync(path30.join(baseDir, "bun.lockb")) || fs16.existsSync(path30.join(baseDir, "bun.lock"))) {
44647
+ if (fs17.existsSync(path31.join(baseDir, "bun.lockb")) || fs17.existsSync(path31.join(baseDir, "bun.lock"))) {
44218
44648
  if (scripts.test?.includes("bun"))
44219
44649
  return "bun";
44220
44650
  }
44221
44651
  }
44222
44652
  } catch {}
44223
44653
  try {
44224
- const pyprojectTomlPath = path30.join(baseDir, "pyproject.toml");
44225
- const setupCfgPath = path30.join(baseDir, "setup.cfg");
44226
- const requirementsTxtPath = path30.join(baseDir, "requirements.txt");
44227
- if (fs16.existsSync(pyprojectTomlPath)) {
44228
- const content = fs16.readFileSync(pyprojectTomlPath, "utf-8");
44654
+ const pyprojectTomlPath = path31.join(baseDir, "pyproject.toml");
44655
+ const setupCfgPath = path31.join(baseDir, "setup.cfg");
44656
+ const requirementsTxtPath = path31.join(baseDir, "requirements.txt");
44657
+ if (fs17.existsSync(pyprojectTomlPath)) {
44658
+ const content = fs17.readFileSync(pyprojectTomlPath, "utf-8");
44229
44659
  if (content.includes("[tool.pytest"))
44230
44660
  return "pytest";
44231
44661
  if (content.includes("pytest"))
44232
44662
  return "pytest";
44233
44663
  }
44234
- if (fs16.existsSync(setupCfgPath)) {
44235
- const content = fs16.readFileSync(setupCfgPath, "utf-8");
44664
+ if (fs17.existsSync(setupCfgPath)) {
44665
+ const content = fs17.readFileSync(setupCfgPath, "utf-8");
44236
44666
  if (content.includes("[pytest]"))
44237
44667
  return "pytest";
44238
44668
  }
44239
- if (fs16.existsSync(requirementsTxtPath)) {
44240
- const content = fs16.readFileSync(requirementsTxtPath, "utf-8");
44669
+ if (fs17.existsSync(requirementsTxtPath)) {
44670
+ const content = fs17.readFileSync(requirementsTxtPath, "utf-8");
44241
44671
  if (content.includes("pytest"))
44242
44672
  return "pytest";
44243
44673
  }
44244
44674
  } catch {}
44245
44675
  try {
44246
- const cargoTomlPath = path30.join(baseDir, "Cargo.toml");
44247
- if (fs16.existsSync(cargoTomlPath)) {
44248
- const content = fs16.readFileSync(cargoTomlPath, "utf-8");
44676
+ const cargoTomlPath = path31.join(baseDir, "Cargo.toml");
44677
+ if (fs17.existsSync(cargoTomlPath)) {
44678
+ const content = fs17.readFileSync(cargoTomlPath, "utf-8");
44249
44679
  if (content.includes("[dev-dependencies]")) {
44250
44680
  if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
44251
44681
  return "cargo";
@@ -44254,10 +44684,10 @@ async function detectTestFramework(cwd) {
44254
44684
  }
44255
44685
  } catch {}
44256
44686
  try {
44257
- const pesterConfigPath = path30.join(baseDir, "pester.config.ps1");
44258
- const pesterConfigJsonPath = path30.join(baseDir, "pester.config.ps1.json");
44259
- const pesterPs1Path = path30.join(baseDir, "tests.ps1");
44260
- if (fs16.existsSync(pesterConfigPath) || fs16.existsSync(pesterConfigJsonPath) || fs16.existsSync(pesterPs1Path)) {
44687
+ const pesterConfigPath = path31.join(baseDir, "pester.config.ps1");
44688
+ const pesterConfigJsonPath = path31.join(baseDir, "pester.config.ps1.json");
44689
+ const pesterPs1Path = path31.join(baseDir, "tests.ps1");
44690
+ if (fs17.existsSync(pesterConfigPath) || fs17.existsSync(pesterConfigJsonPath) || fs17.existsSync(pesterPs1Path)) {
44261
44691
  return "pester";
44262
44692
  }
44263
44693
  } catch {}
@@ -44285,12 +44715,12 @@ function isTestDirectoryPath(normalizedPath) {
44285
44715
  return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
44286
44716
  }
44287
44717
  function resolveWorkspacePath(file3, workingDir) {
44288
- return path30.isAbsolute(file3) ? path30.resolve(file3) : path30.resolve(workingDir, file3);
44718
+ return path31.isAbsolute(file3) ? path31.resolve(file3) : path31.resolve(workingDir, file3);
44289
44719
  }
44290
44720
  function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
44291
44721
  if (!preferRelative)
44292
44722
  return absolutePath;
44293
- return path30.relative(workingDir, absolutePath);
44723
+ return path31.relative(workingDir, absolutePath);
44294
44724
  }
44295
44725
  function dedupePush(target, value) {
44296
44726
  if (!target.includes(value)) {
@@ -44327,18 +44757,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
44327
44757
  }
44328
44758
  }
44329
44759
  function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
44330
- const relativeDir = path30.dirname(relativePath);
44760
+ const relativeDir = path31.dirname(relativePath);
44331
44761
  const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
44332
44762
  const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
44333
- const rootDir = path30.join(workingDir, dirName);
44334
- return nestedRelativeDir ? [rootDir, path30.join(rootDir, nestedRelativeDir)] : [rootDir];
44763
+ const rootDir = path31.join(workingDir, dirName);
44764
+ return nestedRelativeDir ? [rootDir, path31.join(rootDir, nestedRelativeDir)] : [rootDir];
44335
44765
  });
44336
44766
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
44337
44767
  if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
44338
- directories.push(path30.join(workingDir, "src/test/java", path30.dirname(normalizedRelativePath.slice("src/main/java/".length))));
44768
+ directories.push(path31.join(workingDir, "src/test/java", path31.dirname(normalizedRelativePath.slice("src/main/java/".length))));
44339
44769
  }
44340
44770
  if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
44341
- directories.push(path30.join(workingDir, "src/test/kotlin", path30.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
44771
+ directories.push(path31.join(workingDir, "src/test/kotlin", path31.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
44342
44772
  }
44343
44773
  return [...new Set(directories)];
44344
44774
  }
@@ -44366,23 +44796,23 @@ function isLanguageSpecificTestFile(basename5) {
44366
44796
  }
44367
44797
  function isConventionTestFilePath(filePath) {
44368
44798
  const normalizedPath = filePath.replace(/\\/g, "/");
44369
- const basename5 = path30.basename(filePath);
44799
+ const basename5 = path31.basename(filePath);
44370
44800
  return hasCompoundTestExtension(basename5) || basename5.includes(".spec.") || basename5.includes(".test.") || isLanguageSpecificTestFile(basename5) || isTestDirectoryPath(normalizedPath);
44371
44801
  }
44372
44802
  function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
44373
44803
  const testFiles = [];
44374
44804
  for (const file3 of sourceFiles) {
44375
44805
  const absoluteFile = resolveWorkspacePath(file3, workingDir);
44376
- const relativeFile = path30.relative(workingDir, absoluteFile);
44377
- const basename5 = path30.basename(absoluteFile);
44378
- const dirname13 = path30.dirname(absoluteFile);
44379
- const preferRelativeOutput = !path30.isAbsolute(file3);
44806
+ const relativeFile = path31.relative(workingDir, absoluteFile);
44807
+ const basename5 = path31.basename(absoluteFile);
44808
+ const dirname13 = path31.dirname(absoluteFile);
44809
+ const preferRelativeOutput = !path31.isAbsolute(file3);
44380
44810
  if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
44381
44811
  dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
44382
44812
  continue;
44383
44813
  }
44384
44814
  const nameWithoutExt = basename5.replace(/\.[^.]+$/, "");
44385
- const ext = path30.extname(basename5);
44815
+ const ext = path31.extname(basename5);
44386
44816
  const genericTestNames = [
44387
44817
  `${nameWithoutExt}.spec${ext}`,
44388
44818
  `${nameWithoutExt}.test${ext}`
@@ -44391,7 +44821,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
44391
44821
  const colocatedCandidates = [
44392
44822
  ...genericTestNames,
44393
44823
  ...languageSpecificTestNames
44394
- ].map((candidateName) => path30.join(dirname13, candidateName));
44824
+ ].map((candidateName) => path31.join(dirname13, candidateName));
44395
44825
  const testDirectoryNames = [
44396
44826
  basename5,
44397
44827
  ...genericTestNames,
@@ -44400,11 +44830,11 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
44400
44830
  const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
44401
44831
  const possibleTestFiles = [
44402
44832
  ...colocatedCandidates,
44403
- ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path30.join(dirname13, dirName, candidateName))),
44404
- ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path30.join(candidateDir, candidateName)))
44833
+ ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path31.join(dirname13, dirName, candidateName))),
44834
+ ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path31.join(candidateDir, candidateName)))
44405
44835
  ];
44406
44836
  for (const testFile of possibleTestFiles) {
44407
- if (fs16.existsSync(testFile)) {
44837
+ if (fs17.existsSync(testFile)) {
44408
44838
  dedupePush(testFiles, toWorkspaceOutputPath(testFile, workingDir, preferRelativeOutput));
44409
44839
  }
44410
44840
  }
@@ -44421,8 +44851,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
44421
44851
  for (const testFile of candidateTestFiles) {
44422
44852
  try {
44423
44853
  const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
44424
- const content = fs16.readFileSync(absoluteTestFile, "utf-8");
44425
- const testDir = path30.dirname(absoluteTestFile);
44854
+ const content = fs17.readFileSync(absoluteTestFile, "utf-8");
44855
+ const testDir = path31.dirname(absoluteTestFile);
44426
44856
  const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
44427
44857
  let match;
44428
44858
  match = importRegex.exec(content);
@@ -44430,8 +44860,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
44430
44860
  const importPath = match[1];
44431
44861
  let resolvedImport;
44432
44862
  if (importPath.startsWith(".")) {
44433
- resolvedImport = path30.resolve(testDir, importPath);
44434
- const existingExt = path30.extname(resolvedImport);
44863
+ resolvedImport = path31.resolve(testDir, importPath);
44864
+ const existingExt = path31.extname(resolvedImport);
44435
44865
  if (!existingExt) {
44436
44866
  for (const extToTry of [
44437
44867
  ".ts",
@@ -44442,7 +44872,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
44442
44872
  ".cjs"
44443
44873
  ]) {
44444
44874
  const withExt = resolvedImport + extToTry;
44445
- if (absoluteSourceFiles.includes(withExt) || fs16.existsSync(withExt)) {
44875
+ if (absoluteSourceFiles.includes(withExt) || fs17.existsSync(withExt)) {
44446
44876
  resolvedImport = withExt;
44447
44877
  break;
44448
44878
  }
@@ -44451,12 +44881,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
44451
44881
  } else {
44452
44882
  continue;
44453
44883
  }
44454
- const importBasename = path30.basename(resolvedImport, path30.extname(resolvedImport));
44455
- const importDir = path30.dirname(resolvedImport);
44884
+ const importBasename = path31.basename(resolvedImport, path31.extname(resolvedImport));
44885
+ const importDir = path31.dirname(resolvedImport);
44456
44886
  for (const sourceFile of absoluteSourceFiles) {
44457
- const sourceDir = path30.dirname(sourceFile);
44458
- const sourceBasename = path30.basename(sourceFile, path30.extname(sourceFile));
44459
- const isRelatedDir = importDir === sourceDir || importDir === path30.join(sourceDir, "__tests__") || importDir === path30.join(sourceDir, "tests") || importDir === path30.join(sourceDir, "test") || importDir === path30.join(sourceDir, "spec");
44887
+ const sourceDir = path31.dirname(sourceFile);
44888
+ const sourceBasename = path31.basename(sourceFile, path31.extname(sourceFile));
44889
+ const isRelatedDir = importDir === sourceDir || importDir === path31.join(sourceDir, "__tests__") || importDir === path31.join(sourceDir, "tests") || importDir === path31.join(sourceDir, "test") || importDir === path31.join(sourceDir, "spec");
44460
44890
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
44461
44891
  dedupePush(testFiles, testFile);
44462
44892
  break;
@@ -44469,8 +44899,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
44469
44899
  while (match !== null) {
44470
44900
  const importPath = match[1];
44471
44901
  if (importPath.startsWith(".")) {
44472
- let resolvedImport = path30.resolve(testDir, importPath);
44473
- const existingExt = path30.extname(resolvedImport);
44902
+ let resolvedImport = path31.resolve(testDir, importPath);
44903
+ const existingExt = path31.extname(resolvedImport);
44474
44904
  if (!existingExt) {
44475
44905
  for (const extToTry of [
44476
44906
  ".ts",
@@ -44481,18 +44911,18 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
44481
44911
  ".cjs"
44482
44912
  ]) {
44483
44913
  const withExt = resolvedImport + extToTry;
44484
- if (absoluteSourceFiles.includes(withExt) || fs16.existsSync(withExt)) {
44914
+ if (absoluteSourceFiles.includes(withExt) || fs17.existsSync(withExt)) {
44485
44915
  resolvedImport = withExt;
44486
44916
  break;
44487
44917
  }
44488
44918
  }
44489
44919
  }
44490
- const importDir = path30.dirname(resolvedImport);
44491
- const importBasename = path30.basename(resolvedImport, path30.extname(resolvedImport));
44920
+ const importDir = path31.dirname(resolvedImport);
44921
+ const importBasename = path31.basename(resolvedImport, path31.extname(resolvedImport));
44492
44922
  for (const sourceFile of absoluteSourceFiles) {
44493
- const sourceDir = path30.dirname(sourceFile);
44494
- const sourceBasename = path30.basename(sourceFile, path30.extname(sourceFile));
44495
- const isRelatedDir = importDir === sourceDir || importDir === path30.join(sourceDir, "__tests__") || importDir === path30.join(sourceDir, "tests") || importDir === path30.join(sourceDir, "test") || importDir === path30.join(sourceDir, "spec");
44923
+ const sourceDir = path31.dirname(sourceFile);
44924
+ const sourceBasename = path31.basename(sourceFile, path31.extname(sourceFile));
44925
+ const isRelatedDir = importDir === sourceDir || importDir === path31.join(sourceDir, "__tests__") || importDir === path31.join(sourceDir, "tests") || importDir === path31.join(sourceDir, "test") || importDir === path31.join(sourceDir, "spec");
44496
44926
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
44497
44927
  dedupePush(testFiles, testFile);
44498
44928
  break;
@@ -44595,8 +45025,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
44595
45025
  return ["mvn", "test"];
44596
45026
  case "gradle": {
44597
45027
  const isWindows = process.platform === "win32";
44598
- const hasGradlewBat = fs16.existsSync(path30.join(baseDir, "gradlew.bat"));
44599
- const hasGradlew = fs16.existsSync(path30.join(baseDir, "gradlew"));
45028
+ const hasGradlewBat = fs17.existsSync(path31.join(baseDir, "gradlew.bat"));
45029
+ const hasGradlew = fs17.existsSync(path31.join(baseDir, "gradlew"));
44600
45030
  if (hasGradlewBat && isWindows)
44601
45031
  return ["gradlew.bat", "test"];
44602
45032
  if (hasGradlew)
@@ -44613,7 +45043,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
44613
45043
  "cmake-build-release",
44614
45044
  "out"
44615
45045
  ];
44616
- const actualBuildDir = buildDirCandidates.find((d) => fs16.existsSync(path30.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
45046
+ const actualBuildDir = buildDirCandidates.find((d) => fs17.existsSync(path31.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
44617
45047
  return ["ctest", "--test-dir", actualBuildDir];
44618
45048
  }
44619
45049
  case "swift-test":
@@ -44934,9 +45364,9 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
44934
45364
  stderr: "pipe",
44935
45365
  cwd
44936
45366
  });
44937
- const timeoutPromise = new Promise((resolve12) => setTimeout(() => {
45367
+ const timeoutPromise = new Promise((resolve13) => setTimeout(() => {
44938
45368
  proc.kill();
44939
- resolve12(-1);
45369
+ resolve13(-1);
44940
45370
  }, timeout_ms));
44941
45371
  const [exitCode, stdoutResult, stderrResult] = await Promise.all([
44942
45372
  Promise.race([proc.exited, timeoutPromise]),
@@ -45266,7 +45696,7 @@ var init_test_runner = __esm(() => {
45266
45696
  const sourceFiles = args.files.filter((file3) => {
45267
45697
  if (directTestFiles.includes(file3))
45268
45698
  return false;
45269
- const ext = path30.extname(file3).toLowerCase();
45699
+ const ext = path31.extname(file3).toLowerCase();
45270
45700
  return SOURCE_EXTENSIONS.has(ext);
45271
45701
  });
45272
45702
  const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
@@ -45301,7 +45731,7 @@ var init_test_runner = __esm(() => {
45301
45731
  if (isConventionTestFilePath(f)) {
45302
45732
  return false;
45303
45733
  }
45304
- const ext = path30.extname(f).toLowerCase();
45734
+ const ext = path31.extname(f).toLowerCase();
45305
45735
  return SOURCE_EXTENSIONS.has(ext);
45306
45736
  });
45307
45737
  if (sourceFiles.length === 0) {
@@ -45328,7 +45758,7 @@ var init_test_runner = __esm(() => {
45328
45758
  if (isConventionTestFilePath(f)) {
45329
45759
  return false;
45330
45760
  }
45331
- const ext = path30.extname(f).toLowerCase();
45761
+ const ext = path31.extname(f).toLowerCase();
45332
45762
  return SOURCE_EXTENSIONS.has(ext);
45333
45763
  });
45334
45764
  if (sourceFiles.length === 0) {
@@ -45346,8 +45776,8 @@ var init_test_runner = __esm(() => {
45346
45776
  const impactResult = await analyzeImpact(sourceFiles, workingDir);
45347
45777
  if (impactResult.impactedTests.length > 0) {
45348
45778
  testFiles = impactResult.impactedTests.map((absPath) => {
45349
- const relativePath = path30.relative(workingDir, absPath);
45350
- return path30.isAbsolute(relativePath) ? absPath : relativePath;
45779
+ const relativePath = path31.relative(workingDir, absPath);
45780
+ return path31.isAbsolute(relativePath) ? absPath : relativePath;
45351
45781
  });
45352
45782
  } else {
45353
45783
  graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
@@ -45422,8 +45852,8 @@ var init_test_runner = __esm(() => {
45422
45852
  });
45423
45853
 
45424
45854
  // src/services/preflight-service.ts
45425
- import * as fs17 from "fs";
45426
- import * as path31 from "path";
45855
+ import * as fs18 from "fs";
45856
+ import * as path32 from "path";
45427
45857
  function validateDirectoryPath(dir) {
45428
45858
  if (!dir || typeof dir !== "string") {
45429
45859
  throw new Error("Directory path is required");
@@ -45431,8 +45861,8 @@ function validateDirectoryPath(dir) {
45431
45861
  if (dir.includes("..")) {
45432
45862
  throw new Error("Directory path must not contain path traversal sequences");
45433
45863
  }
45434
- const normalized = path31.normalize(dir);
45435
- const absolutePath = path31.isAbsolute(normalized) ? normalized : path31.resolve(normalized);
45864
+ const normalized = path32.normalize(dir);
45865
+ const absolutePath = path32.isAbsolute(normalized) ? normalized : path32.resolve(normalized);
45436
45866
  return absolutePath;
45437
45867
  }
45438
45868
  function validateTimeout(timeoutMs, defaultValue) {
@@ -45455,9 +45885,9 @@ function validateTimeout(timeoutMs, defaultValue) {
45455
45885
  }
45456
45886
  function getPackageVersion(dir) {
45457
45887
  try {
45458
- const packagePath = path31.join(dir, "package.json");
45459
- if (fs17.existsSync(packagePath)) {
45460
- const content = fs17.readFileSync(packagePath, "utf-8");
45888
+ const packagePath = path32.join(dir, "package.json");
45889
+ if (fs18.existsSync(packagePath)) {
45890
+ const content = fs18.readFileSync(packagePath, "utf-8");
45461
45891
  const pkg = JSON.parse(content);
45462
45892
  return pkg.version ?? null;
45463
45893
  }
@@ -45466,9 +45896,9 @@ function getPackageVersion(dir) {
45466
45896
  }
45467
45897
  function getChangelogVersion(dir) {
45468
45898
  try {
45469
- const changelogPath = path31.join(dir, "CHANGELOG.md");
45470
- if (fs17.existsSync(changelogPath)) {
45471
- const content = fs17.readFileSync(changelogPath, "utf-8");
45899
+ const changelogPath = path32.join(dir, "CHANGELOG.md");
45900
+ if (fs18.existsSync(changelogPath)) {
45901
+ const content = fs18.readFileSync(changelogPath, "utf-8");
45472
45902
  const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
45473
45903
  if (match) {
45474
45904
  return match[1];
@@ -45480,10 +45910,10 @@ function getChangelogVersion(dir) {
45480
45910
  function getVersionFileVersion(dir) {
45481
45911
  const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
45482
45912
  for (const file3 of possibleFiles) {
45483
- const filePath = path31.join(dir, file3);
45484
- if (fs17.existsSync(filePath)) {
45913
+ const filePath = path32.join(dir, file3);
45914
+ if (fs18.existsSync(filePath)) {
45485
45915
  try {
45486
- const content = fs17.readFileSync(filePath, "utf-8").trim();
45916
+ const content = fs18.readFileSync(filePath, "utf-8").trim();
45487
45917
  const match = content.match(/(\d+\.\d+\.\d+)/);
45488
45918
  if (match) {
45489
45919
  return match[1];
@@ -45807,8 +46237,8 @@ async function runEvidenceCheck(dir) {
45807
46237
  async function runRequirementCoverageCheck(dir, currentPhase) {
45808
46238
  const startTime = Date.now();
45809
46239
  try {
45810
- const specPath = path31.join(dir, ".swarm", "spec.md");
45811
- if (!fs17.existsSync(specPath)) {
46240
+ const specPath = path32.join(dir, ".swarm", "spec.md");
46241
+ if (!fs18.existsSync(specPath)) {
45812
46242
  return {
45813
46243
  type: "req_coverage",
45814
46244
  status: "skip",
@@ -46285,13 +46715,13 @@ class CircuitBreaker {
46285
46715
  if (this.config.callTimeoutMs <= 0) {
46286
46716
  return fn();
46287
46717
  }
46288
- return new Promise((resolve13, reject) => {
46718
+ return new Promise((resolve14, reject) => {
46289
46719
  const timeout = setTimeout(() => {
46290
46720
  reject(new Error(`Call timeout after ${this.config.callTimeoutMs}ms`));
46291
46721
  }, this.config.callTimeoutMs);
46292
46722
  fn().then((result) => {
46293
46723
  clearTimeout(timeout);
46294
- resolve13(result);
46724
+ resolve14(result);
46295
46725
  }).catch((error93) => {
46296
46726
  clearTimeout(timeout);
46297
46727
  reject(error93);
@@ -46578,7 +47008,7 @@ var init_queue = __esm(() => {
46578
47008
 
46579
47009
  // src/background/worker.ts
46580
47010
  function sleep(ms) {
46581
- return new Promise((resolve13) => setTimeout(resolve13, ms));
47011
+ return new Promise((resolve14) => setTimeout(resolve14, ms));
46582
47012
  }
46583
47013
 
46584
47014
  class WorkerManager {
@@ -46923,8 +47353,8 @@ var init_manager3 = __esm(() => {
46923
47353
  });
46924
47354
 
46925
47355
  // src/commands/reset.ts
46926
- import * as fs18 from "fs";
46927
- import * as path32 from "path";
47356
+ import * as fs19 from "fs";
47357
+ import * as path33 from "path";
46928
47358
  async function handleResetCommand(directory, args) {
46929
47359
  const hasConfirm = args.includes("--confirm");
46930
47360
  if (!hasConfirm) {
@@ -46952,8 +47382,8 @@ async function handleResetCommand(directory, args) {
46952
47382
  for (const filename of filesToReset) {
46953
47383
  try {
46954
47384
  const resolvedPath = validateSwarmPath(directory, filename);
46955
- if (fs18.existsSync(resolvedPath)) {
46956
- fs18.unlinkSync(resolvedPath);
47385
+ if (fs19.existsSync(resolvedPath)) {
47386
+ fs19.unlinkSync(resolvedPath);
46957
47387
  results.push(`- \u2705 Deleted ${filename}`);
46958
47388
  } else {
46959
47389
  results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
@@ -46964,9 +47394,9 @@ async function handleResetCommand(directory, args) {
46964
47394
  }
46965
47395
  for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
46966
47396
  try {
46967
- const rootPath = path32.join(directory, filename);
46968
- if (fs18.existsSync(rootPath)) {
46969
- fs18.unlinkSync(rootPath);
47397
+ const rootPath = path33.join(directory, filename);
47398
+ if (fs19.existsSync(rootPath)) {
47399
+ fs19.unlinkSync(rootPath);
46970
47400
  results.push(`- \u2705 Deleted ${filename} (root)`);
46971
47401
  }
46972
47402
  } catch {}
@@ -46979,8 +47409,8 @@ async function handleResetCommand(directory, args) {
46979
47409
  }
46980
47410
  try {
46981
47411
  const summariesPath = validateSwarmPath(directory, "summaries");
46982
- if (fs18.existsSync(summariesPath)) {
46983
- fs18.rmSync(summariesPath, { recursive: true, force: true });
47412
+ if (fs19.existsSync(summariesPath)) {
47413
+ fs19.rmSync(summariesPath, { recursive: true, force: true });
46984
47414
  results.push("- \u2705 Deleted summaries/ directory");
46985
47415
  } else {
46986
47416
  results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
@@ -47003,14 +47433,14 @@ var init_reset = __esm(() => {
47003
47433
  });
47004
47434
 
47005
47435
  // src/commands/reset-session.ts
47006
- import * as fs19 from "fs";
47007
- import * as path33 from "path";
47436
+ import * as fs20 from "fs";
47437
+ import * as path34 from "path";
47008
47438
  async function handleResetSessionCommand(directory, _args) {
47009
47439
  const results = [];
47010
47440
  try {
47011
47441
  const statePath = validateSwarmPath(directory, "session/state.json");
47012
- if (fs19.existsSync(statePath)) {
47013
- fs19.unlinkSync(statePath);
47442
+ if (fs20.existsSync(statePath)) {
47443
+ fs20.unlinkSync(statePath);
47014
47444
  results.push("\u2705 Deleted .swarm/session/state.json");
47015
47445
  } else {
47016
47446
  results.push("\u23ED\uFE0F state.json not found (already clean)");
@@ -47019,15 +47449,15 @@ async function handleResetSessionCommand(directory, _args) {
47019
47449
  results.push("\u274C Failed to delete state.json");
47020
47450
  }
47021
47451
  try {
47022
- const sessionDir = path33.dirname(validateSwarmPath(directory, "session/state.json"));
47023
- if (fs19.existsSync(sessionDir)) {
47024
- const files = fs19.readdirSync(sessionDir);
47452
+ const sessionDir = path34.dirname(validateSwarmPath(directory, "session/state.json"));
47453
+ if (fs20.existsSync(sessionDir)) {
47454
+ const files = fs20.readdirSync(sessionDir);
47025
47455
  const otherFiles = files.filter((f) => f !== "state.json");
47026
47456
  let deletedCount = 0;
47027
47457
  for (const file3 of otherFiles) {
47028
- const filePath = path33.join(sessionDir, file3);
47029
- if (fs19.lstatSync(filePath).isFile()) {
47030
- fs19.unlinkSync(filePath);
47458
+ const filePath = path34.join(sessionDir, file3);
47459
+ if (fs20.lstatSync(filePath).isFile()) {
47460
+ fs20.unlinkSync(filePath);
47031
47461
  deletedCount++;
47032
47462
  }
47033
47463
  }
@@ -47057,7 +47487,7 @@ var init_reset_session = __esm(() => {
47057
47487
  });
47058
47488
 
47059
47489
  // src/summaries/manager.ts
47060
- import * as path34 from "path";
47490
+ import * as path35 from "path";
47061
47491
  function sanitizeSummaryId(id) {
47062
47492
  if (!id || id.length === 0) {
47063
47493
  throw new Error("Invalid summary ID: empty string");
@@ -47080,7 +47510,7 @@ function sanitizeSummaryId(id) {
47080
47510
  }
47081
47511
  async function loadFullOutput(directory, id) {
47082
47512
  const sanitizedId = sanitizeSummaryId(id);
47083
- const relativePath = path34.join("summaries", `${sanitizedId}.json`);
47513
+ const relativePath = path35.join("summaries", `${sanitizedId}.json`);
47084
47514
  validateSwarmPath(directory, relativePath);
47085
47515
  const content = await readSwarmFileAsync(directory, relativePath);
47086
47516
  if (content === null) {
@@ -47142,18 +47572,18 @@ var init_retrieve = __esm(() => {
47142
47572
  });
47143
47573
 
47144
47574
  // src/commands/rollback.ts
47145
- import * as fs20 from "fs";
47146
- import * as path35 from "path";
47575
+ import * as fs21 from "fs";
47576
+ import * as path36 from "path";
47147
47577
  async function handleRollbackCommand(directory, args) {
47148
47578
  const phaseArg = args[0];
47149
47579
  if (!phaseArg) {
47150
47580
  const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
47151
- if (!fs20.existsSync(manifestPath2)) {
47581
+ if (!fs21.existsSync(manifestPath2)) {
47152
47582
  return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
47153
47583
  }
47154
47584
  let manifest2;
47155
47585
  try {
47156
- manifest2 = JSON.parse(fs20.readFileSync(manifestPath2, "utf-8"));
47586
+ manifest2 = JSON.parse(fs21.readFileSync(manifestPath2, "utf-8"));
47157
47587
  } catch {
47158
47588
  return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
47159
47589
  }
@@ -47175,12 +47605,12 @@ async function handleRollbackCommand(directory, args) {
47175
47605
  return "Error: Phase number must be a positive integer.";
47176
47606
  }
47177
47607
  const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
47178
- if (!fs20.existsSync(manifestPath)) {
47608
+ if (!fs21.existsSync(manifestPath)) {
47179
47609
  return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
47180
47610
  }
47181
47611
  let manifest;
47182
47612
  try {
47183
- manifest = JSON.parse(fs20.readFileSync(manifestPath, "utf-8"));
47613
+ manifest = JSON.parse(fs21.readFileSync(manifestPath, "utf-8"));
47184
47614
  } catch {
47185
47615
  return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
47186
47616
  }
@@ -47190,10 +47620,10 @@ async function handleRollbackCommand(directory, args) {
47190
47620
  return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
47191
47621
  }
47192
47622
  const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
47193
- if (!fs20.existsSync(checkpointDir)) {
47623
+ if (!fs21.existsSync(checkpointDir)) {
47194
47624
  return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
47195
47625
  }
47196
- const checkpointFiles = fs20.readdirSync(checkpointDir);
47626
+ const checkpointFiles = fs21.readdirSync(checkpointDir);
47197
47627
  if (checkpointFiles.length === 0) {
47198
47628
  return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
47199
47629
  }
@@ -47208,10 +47638,10 @@ async function handleRollbackCommand(directory, args) {
47208
47638
  if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
47209
47639
  continue;
47210
47640
  }
47211
- const src = path35.join(checkpointDir, file3);
47212
- const dest = path35.join(swarmDir, file3);
47641
+ const src = path36.join(checkpointDir, file3);
47642
+ const dest = path36.join(swarmDir, file3);
47213
47643
  try {
47214
- fs20.cpSync(src, dest, { recursive: true, force: true });
47644
+ fs21.cpSync(src, dest, { recursive: true, force: true });
47215
47645
  successes.push(file3);
47216
47646
  } catch (error93) {
47217
47647
  failures.push({ file: file3, error: error93.message });
@@ -47228,14 +47658,14 @@ async function handleRollbackCommand(directory, args) {
47228
47658
  ].join(`
47229
47659
  `);
47230
47660
  }
47231
- const existingLedgerPath = path35.join(swarmDir, "plan-ledger.jsonl");
47232
- if (fs20.existsSync(existingLedgerPath)) {
47233
- fs20.unlinkSync(existingLedgerPath);
47661
+ const existingLedgerPath = path36.join(swarmDir, "plan-ledger.jsonl");
47662
+ if (fs21.existsSync(existingLedgerPath)) {
47663
+ fs21.unlinkSync(existingLedgerPath);
47234
47664
  }
47235
47665
  try {
47236
- const planJsonPath = path35.join(swarmDir, "plan.json");
47237
- if (fs20.existsSync(planJsonPath)) {
47238
- const planRaw = fs20.readFileSync(planJsonPath, "utf-8");
47666
+ const planJsonPath = path36.join(swarmDir, "plan.json");
47667
+ if (fs21.existsSync(planJsonPath)) {
47668
+ const planRaw = fs21.readFileSync(planJsonPath, "utf-8");
47239
47669
  const plan = PlanSchema.parse(JSON.parse(planRaw));
47240
47670
  const planId = derivePlanId(plan);
47241
47671
  const planHash = computePlanHash(plan);
@@ -47262,7 +47692,7 @@ async function handleRollbackCommand(directory, args) {
47262
47692
  timestamp: new Date().toISOString()
47263
47693
  };
47264
47694
  try {
47265
- fs20.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
47695
+ fs21.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
47266
47696
  `);
47267
47697
  } catch (error93) {
47268
47698
  console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
@@ -47310,11 +47740,11 @@ async function handleSimulateCommand(directory, args) {
47310
47740
  ];
47311
47741
  const report = reportLines.filter(Boolean).join(`
47312
47742
  `);
47313
- const fs21 = await import("fs/promises");
47314
- const path36 = await import("path");
47315
- const reportPath = path36.join(directory, ".swarm", "simulate-report.md");
47316
- await fs21.mkdir(path36.dirname(reportPath), { recursive: true });
47317
- await fs21.writeFile(reportPath, report, "utf-8");
47743
+ const fs22 = await import("fs/promises");
47744
+ const path37 = await import("path");
47745
+ const reportPath = path37.join(directory, ".swarm", "simulate-report.md");
47746
+ await fs22.mkdir(path37.dirname(reportPath), { recursive: true });
47747
+ await fs22.writeFile(reportPath, report, "utf-8");
47318
47748
  return `${darkMatterPairs.length} hidden coupling pairs detected`;
47319
47749
  }
47320
47750
  var init_simulate = __esm(() => {
@@ -47667,8 +48097,8 @@ __export(exports_commands, {
47667
48097
  VALID_COMMANDS: () => VALID_COMMANDS,
47668
48098
  COMMAND_REGISTRY: () => COMMAND_REGISTRY
47669
48099
  });
47670
- import fs21 from "fs";
47671
- import path36 from "path";
48100
+ import fs22 from "fs";
48101
+ import path37 from "path";
47672
48102
  function buildHelpText() {
47673
48103
  const lines = ["## Swarm Commands", ""];
47674
48104
  const CATEGORIES = [
@@ -47777,11 +48207,11 @@ function createSwarmCommandHandler(directory, agents) {
47777
48207
  return;
47778
48208
  }
47779
48209
  let isFirstRun = false;
47780
- const sentinelPath = path36.join(directory, ".swarm", ".first-run-complete");
48210
+ const sentinelPath = path37.join(directory, ".swarm", ".first-run-complete");
47781
48211
  try {
47782
- const swarmDir = path36.join(directory, ".swarm");
47783
- fs21.mkdirSync(swarmDir, { recursive: true });
47784
- fs21.writeFileSync(sentinelPath, `first-run-complete: ${new Date().toISOString()}
48212
+ const swarmDir = path37.join(directory, ".swarm");
48213
+ fs22.mkdirSync(swarmDir, { recursive: true });
48214
+ fs22.writeFileSync(sentinelPath, `first-run-complete: ${new Date().toISOString()}
47785
48215
  `, { flag: "wx" });
47786
48216
  isFirstRun = true;
47787
48217
  } catch (_err) {}
@@ -47964,24 +48394,24 @@ function validateAliases() {
47964
48394
  }
47965
48395
  aliasTargets.get(target).push(name);
47966
48396
  const visited = new Set;
47967
- const path37 = [];
48397
+ const path38 = [];
47968
48398
  let current = target;
47969
48399
  while (current) {
47970
48400
  const currentEntry = COMMAND_REGISTRY[current];
47971
48401
  if (!currentEntry)
47972
48402
  break;
47973
48403
  if (visited.has(current)) {
47974
- const cycleStart = path37.indexOf(current);
48404
+ const cycleStart = path38.indexOf(current);
47975
48405
  const fullChain = [
47976
48406
  name,
47977
- ...path37.slice(0, cycleStart > 0 ? cycleStart : path37.length),
48407
+ ...path38.slice(0, cycleStart > 0 ? cycleStart : path38.length),
47978
48408
  current
47979
48409
  ].join(" \u2192 ");
47980
48410
  errors5.push(`Circular alias detected: ${fullChain}`);
47981
48411
  break;
47982
48412
  }
47983
48413
  visited.add(current);
47984
- path37.push(current);
48414
+ path38.push(current);
47985
48415
  current = currentEntry.aliasOf || "";
47986
48416
  }
47987
48417
  }
@@ -48439,68 +48869,68 @@ init_package();
48439
48869
  init_registry();
48440
48870
  init_cache_paths();
48441
48871
  init_constants();
48442
- import * as fs22 from "fs";
48872
+ import * as fs23 from "fs";
48443
48873
  import * as os7 from "os";
48444
- import * as path37 from "path";
48874
+ import * as path38 from "path";
48445
48875
  var { version: version4 } = package_default;
48446
48876
  var CONFIG_DIR = getPluginConfigDir();
48447
- var OPENCODE_CONFIG_PATH = path37.join(CONFIG_DIR, "opencode.json");
48448
- var PLUGIN_CONFIG_PATH = path37.join(CONFIG_DIR, "opencode-swarm.json");
48449
- var PROMPTS_DIR = path37.join(CONFIG_DIR, "opencode-swarm");
48877
+ var OPENCODE_CONFIG_PATH = path38.join(CONFIG_DIR, "opencode.json");
48878
+ var PLUGIN_CONFIG_PATH = path38.join(CONFIG_DIR, "opencode-swarm.json");
48879
+ var PROMPTS_DIR = path38.join(CONFIG_DIR, "opencode-swarm");
48450
48880
  var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
48451
48881
  var OPENCODE_PLUGIN_LOCK_FILE_PATHS = getPluginLockFilePaths();
48452
48882
  function isSafeCachePath(p) {
48453
- const resolved = path37.resolve(p);
48454
- const home = path37.resolve(os7.homedir());
48883
+ const resolved = path38.resolve(p);
48884
+ const home = path38.resolve(os7.homedir());
48455
48885
  if (resolved === "/" || resolved === home || resolved.length <= home.length) {
48456
48886
  return false;
48457
48887
  }
48458
- const segments = resolved.split(path37.sep).filter((s) => s.length > 0);
48888
+ const segments = resolved.split(path38.sep).filter((s) => s.length > 0);
48459
48889
  if (segments.length < 4) {
48460
48890
  return false;
48461
48891
  }
48462
- const leaf = path37.basename(resolved);
48892
+ const leaf = path38.basename(resolved);
48463
48893
  if (leaf !== "opencode-swarm@latest" && leaf !== "opencode-swarm") {
48464
48894
  return false;
48465
48895
  }
48466
- const parent = path37.basename(path37.dirname(resolved));
48896
+ const parent = path38.basename(path38.dirname(resolved));
48467
48897
  if (parent !== "packages" && parent !== "node_modules") {
48468
48898
  return false;
48469
48899
  }
48470
- const grandparent = path37.basename(path37.dirname(path37.dirname(resolved)));
48900
+ const grandparent = path38.basename(path38.dirname(path38.dirname(resolved)));
48471
48901
  if (grandparent !== "opencode") {
48472
48902
  return false;
48473
48903
  }
48474
48904
  return true;
48475
48905
  }
48476
48906
  function isSafeLockFilePath(p) {
48477
- const resolved = path37.resolve(p);
48478
- const home = path37.resolve(os7.homedir());
48907
+ const resolved = path38.resolve(p);
48908
+ const home = path38.resolve(os7.homedir());
48479
48909
  if (resolved === "/" || resolved === home || resolved.length <= home.length) {
48480
48910
  return false;
48481
48911
  }
48482
- const segments = resolved.split(path37.sep).filter((s) => s.length > 0);
48912
+ const segments = resolved.split(path38.sep).filter((s) => s.length > 0);
48483
48913
  if (segments.length < 4) {
48484
48914
  return false;
48485
48915
  }
48486
- const leaf = path37.basename(resolved);
48916
+ const leaf = path38.basename(resolved);
48487
48917
  if (leaf !== "bun.lock" && leaf !== "bun.lockb" && leaf !== "package-lock.json") {
48488
48918
  return false;
48489
48919
  }
48490
- const parent = path37.basename(path37.dirname(resolved));
48920
+ const parent = path38.basename(path38.dirname(resolved));
48491
48921
  if (parent !== "opencode") {
48492
48922
  return false;
48493
48923
  }
48494
48924
  return true;
48495
48925
  }
48496
48926
  function ensureDir(dir) {
48497
- if (!fs22.existsSync(dir)) {
48498
- fs22.mkdirSync(dir, { recursive: true });
48927
+ if (!fs23.existsSync(dir)) {
48928
+ fs23.mkdirSync(dir, { recursive: true });
48499
48929
  }
48500
48930
  }
48501
48931
  function loadJson(filepath) {
48502
48932
  try {
48503
- const content = fs22.readFileSync(filepath, "utf-8");
48933
+ const content = fs23.readFileSync(filepath, "utf-8");
48504
48934
  const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
48505
48935
  return JSON.parse(stripped);
48506
48936
  } catch {
@@ -48508,14 +48938,14 @@ function loadJson(filepath) {
48508
48938
  }
48509
48939
  }
48510
48940
  function saveJson(filepath, data) {
48511
- fs22.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
48941
+ fs23.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
48512
48942
  `, "utf-8");
48513
48943
  }
48514
48944
  function writeProjectConfigIfMissing(cwd) {
48515
48945
  try {
48516
- const opencodeDir = path37.join(cwd, ".opencode");
48517
- const projectConfigPath = path37.join(opencodeDir, "opencode-swarm.json");
48518
- if (fs22.existsSync(projectConfigPath)) {
48946
+ const opencodeDir = path38.join(cwd, ".opencode");
48947
+ const projectConfigPath = path38.join(opencodeDir, "opencode-swarm.json");
48948
+ if (fs23.existsSync(projectConfigPath)) {
48519
48949
  return;
48520
48950
  }
48521
48951
  ensureDir(opencodeDir);
@@ -48535,7 +48965,7 @@ async function install() {
48535
48965
  `);
48536
48966
  ensureDir(CONFIG_DIR);
48537
48967
  ensureDir(PROMPTS_DIR);
48538
- const LEGACY_CONFIG_PATH = path37.join(CONFIG_DIR, "config.json");
48968
+ const LEGACY_CONFIG_PATH = path38.join(CONFIG_DIR, "config.json");
48539
48969
  let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
48540
48970
  if (!opencodeConfig) {
48541
48971
  const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
@@ -48582,7 +49012,7 @@ async function install() {
48582
49012
  console.warn(`\u26A0 Could not clear opencode lock file \u2014 you may need to delete it manually:
48583
49013
  ${failed}`);
48584
49014
  }
48585
- if (!fs22.existsSync(PLUGIN_CONFIG_PATH)) {
49015
+ if (!fs23.existsSync(PLUGIN_CONFIG_PATH)) {
48586
49016
  const defaultConfig = {
48587
49017
  agents: { ...DEFAULT_AGENT_CONFIGS },
48588
49018
  max_iterations: 5
@@ -48661,14 +49091,14 @@ function evictPluginCaches() {
48661
49091
  const cleared = [];
48662
49092
  const failed = [];
48663
49093
  for (const cachePath of OPENCODE_PLUGIN_CACHE_PATHS) {
48664
- if (!fs22.existsSync(cachePath))
49094
+ if (!fs23.existsSync(cachePath))
48665
49095
  continue;
48666
49096
  if (!isSafeCachePath(cachePath)) {
48667
49097
  failed.push(`${cachePath} (refused: failed safety check)`);
48668
49098
  continue;
48669
49099
  }
48670
49100
  try {
48671
- fs22.rmSync(cachePath, { recursive: true, force: true });
49101
+ fs23.rmSync(cachePath, { recursive: true, force: true });
48672
49102
  cleared.push(cachePath);
48673
49103
  } catch (err) {
48674
49104
  failed.push(`${cachePath} (${err instanceof Error ? err.message : String(err)})`);
@@ -48680,14 +49110,14 @@ function evictLockFiles() {
48680
49110
  const cleared = [];
48681
49111
  const failed = [];
48682
49112
  for (const lockPath of OPENCODE_PLUGIN_LOCK_FILE_PATHS) {
48683
- if (!fs22.existsSync(lockPath))
49113
+ if (!fs23.existsSync(lockPath))
48684
49114
  continue;
48685
49115
  if (!isSafeLockFilePath(lockPath)) {
48686
49116
  failed.push(`${lockPath} (refused: failed safety check)`);
48687
49117
  continue;
48688
49118
  }
48689
49119
  try {
48690
- fs22.unlinkSync(lockPath);
49120
+ fs23.unlinkSync(lockPath);
48691
49121
  cleared.push(lockPath);
48692
49122
  } catch (err) {
48693
49123
  const code = err?.code;
@@ -48706,7 +49136,7 @@ async function uninstall() {
48706
49136
  `);
48707
49137
  const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
48708
49138
  if (!opencodeConfig) {
48709
- if (fs22.existsSync(OPENCODE_CONFIG_PATH)) {
49139
+ if (fs23.existsSync(OPENCODE_CONFIG_PATH)) {
48710
49140
  console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
48711
49141
  return 1;
48712
49142
  } else {
@@ -48738,13 +49168,13 @@ async function uninstall() {
48738
49168
  console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
48739
49169
  if (process.argv.includes("--clean")) {
48740
49170
  let cleaned = false;
48741
- if (fs22.existsSync(PLUGIN_CONFIG_PATH)) {
48742
- fs22.unlinkSync(PLUGIN_CONFIG_PATH);
49171
+ if (fs23.existsSync(PLUGIN_CONFIG_PATH)) {
49172
+ fs23.unlinkSync(PLUGIN_CONFIG_PATH);
48743
49173
  console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
48744
49174
  cleaned = true;
48745
49175
  }
48746
- if (fs22.existsSync(PROMPTS_DIR)) {
48747
- fs22.rmSync(PROMPTS_DIR, { recursive: true });
49176
+ if (fs23.existsSync(PROMPTS_DIR)) {
49177
+ fs23.rmSync(PROMPTS_DIR, { recursive: true });
48748
49178
  console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
48749
49179
  cleaned = true;
48750
49180
  }