opencode-swarm 7.6.0 → 7.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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.6.0",
37
+ version: "7.8.0",
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
@@ -14589,6 +14597,11 @@ var init_spec_hash = __esm(() => {
14589
14597
  };
14590
14598
  });
14591
14599
 
14600
+ // src/plan/utils.ts
14601
+ function derivePlanId(plan) {
14602
+ return `${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
14603
+ }
14604
+
14592
14605
  // src/plan/ledger.ts
14593
14606
  import * as crypto2 from "crypto";
14594
14607
  import * as fs from "fs";
@@ -14777,7 +14790,7 @@ async function takeSnapshotEvent(directory, plan, options) {
14777
14790
  if (options?.approvalMetadata) {
14778
14791
  snapshotPayload.approval = options.approvalMetadata;
14779
14792
  }
14780
- const planId = `${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
14793
+ const planId = derivePlanId(plan);
14781
14794
  return appendLedgerEvent(directory, {
14782
14795
  event_type: "snapshot",
14783
14796
  source: options?.source ?? "takeSnapshotEvent",
@@ -14972,7 +14985,7 @@ async function loadLastApprovedPlan(directory, expectedPlanId) {
14972
14985
  continue;
14973
14986
  }
14974
14987
  if (expectedPlanId !== undefined) {
14975
- const payloadPlanId = `${payload.plan.swarm}-${payload.plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
14988
+ const payloadPlanId = derivePlanId(payload.plan);
14976
14989
  if (payloadPlanId !== expectedPlanId) {
14977
14990
  continue;
14978
14991
  }
@@ -15173,7 +15186,7 @@ async function loadPlan(directory) {
15173
15186
  if (!startupLedgerCheckedWorkspaces.has(resolvedWorkspace)) {
15174
15187
  startupLedgerCheckedWorkspaces.add(resolvedWorkspace);
15175
15188
  if (ledgerHash !== "" && planHash !== ledgerHash) {
15176
- const currentPlanId = `${validated.swarm}-${validated.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
15189
+ const currentPlanId = derivePlanId(validated);
15177
15190
  const ledgerEvents = await readLedgerEvents(directory);
15178
15191
  const firstEvent = ledgerEvents.length > 0 ? ledgerEvents[0] : null;
15179
15192
  if (firstEvent && firstEvent.plan_id !== currentPlanId) {
@@ -15256,7 +15269,7 @@ async function loadPlan(directory) {
15256
15269
  try {
15257
15270
  const rawParsed = JSON.parse(planJsonContent);
15258
15271
  if (typeof rawParsed?.swarm === "string" && typeof rawParsed?.title === "string") {
15259
- rawPlanId = `${rawParsed.swarm}-${rawParsed.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
15272
+ rawPlanId = derivePlanId(rawParsed);
15260
15273
  }
15261
15274
  } catch {}
15262
15275
  if (await ledgerExists(directory)) {
@@ -15382,7 +15395,7 @@ async function savePlan(directory, plan, options) {
15382
15395
  }
15383
15396
  }
15384
15397
  const currentPlan = await _internals3.loadPlanJsonOnly(directory);
15385
- const planId = `${validated.swarm}-${validated.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
15398
+ const planId = derivePlanId(validated);
15386
15399
  const planHashForInit = computePlanHash(validated);
15387
15400
  if (!await ledgerExists(directory)) {
15388
15401
  try {
@@ -15483,7 +15496,7 @@ async function savePlan(directory, plan, options) {
15483
15496
  const oldTask = oldTaskMap.get(task.id);
15484
15497
  if (oldTask && oldTask.status !== task.status) {
15485
15498
  const eventInput = {
15486
- plan_id: `${validated.swarm}-${validated.title}`.replace(/[^a-zA-Z0-9-_]/g, "_"),
15499
+ plan_id: derivePlanId(validated),
15487
15500
  event_type: "task_status_changed",
15488
15501
  task_id: task.id,
15489
15502
  phase_id: phase.id,
@@ -16040,7 +16053,8 @@ var init_tool_names = __esm(() => {
16040
16053
  "get_qa_gate_profile",
16041
16054
  "set_qa_gates",
16042
16055
  "web_search",
16043
- "convene_general_council"
16056
+ "convene_general_council",
16057
+ "write_final_council_evidence"
16044
16058
  ];
16045
16059
  TOOL_NAME_SET = new Set(TOOL_NAMES);
16046
16060
  });
@@ -16277,7 +16291,8 @@ var init_constants = __esm(() => {
16277
16291
  "get_qa_gate_profile",
16278
16292
  "set_qa_gates",
16279
16293
  "convene_general_council",
16280
- "web_search"
16294
+ "web_search",
16295
+ "write_final_council_evidence"
16281
16296
  ],
16282
16297
  explorer: [
16283
16298
  "complexity_hotspots",
@@ -16403,12 +16418,26 @@ var init_constants = __esm(() => {
16403
16418
  "repo_map"
16404
16419
  ],
16405
16420
  critic_oversight: [
16406
- "complexity_hotspots",
16407
- "detect_domains",
16408
- "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",
16409
16433
  "retrieve_summary",
16434
+ "knowledge_recall",
16410
16435
  "symbols",
16411
- "knowledge_recall"
16436
+ "batch_symbols",
16437
+ "search",
16438
+ "imports",
16439
+ "complexity_hotspots",
16440
+ "detect_domains"
16412
16441
  ],
16413
16442
  docs: [
16414
16443
  "detect_domains",
@@ -16502,60 +16531,43 @@ var init_constants = __esm(() => {
16502
16531
  });
16503
16532
 
16504
16533
  // src/config/schema.ts
16505
- function stripKnownSwarmPrefix(agentName) {
16534
+ function getCanonicalAgentRole(agentName, generatedAgentNames) {
16506
16535
  if (!agentName)
16507
16536
  return agentName;
16508
16537
  const normalized = agentName.toLowerCase();
16509
- let stripped = normalized;
16510
- let previous = "";
16511
- while (stripped !== previous) {
16512
- previous = stripped;
16513
- for (const prefix of KNOWN_SWARM_PREFIXES) {
16514
- for (const sep2 of SEPARATORS) {
16515
- const prefixWithSep = prefix + sep2;
16516
- if (stripped.startsWith(prefixWithSep)) {
16517
- stripped = stripped.slice(prefixWithSep.length);
16518
- break;
16519
- }
16520
- }
16521
- if (stripped !== previous)
16522
- break;
16523
- }
16538
+ if (CANONICAL_ROLES_SET.has(normalized)) {
16539
+ return normalized;
16524
16540
  }
16525
- if (ALL_AGENT_NAMES.includes(stripped)) {
16526
- 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
+ }
16527
16548
  }
16528
- for (const agent of ALL_AGENT_NAMES) {
16549
+ for (const role of CANONICAL_ROLES_LONGEST_FIRST) {
16529
16550
  for (const sep2 of SEPARATORS) {
16530
- const suffix = sep2 + agent;
16551
+ const suffix = sep2 + role;
16531
16552
  if (normalized.endsWith(suffix)) {
16532
- return agent;
16553
+ return role;
16533
16554
  }
16534
16555
  }
16535
- if (normalized === agent) {
16536
- return agent;
16537
- }
16538
16556
  }
16539
16557
  return agentName;
16540
16558
  }
16541
- 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;
16542
16563
  var init_schema = __esm(() => {
16543
16564
  init_zod();
16544
16565
  init_constants();
16545
- KNOWN_SWARM_PREFIXES = [
16546
- "paid",
16547
- "local",
16548
- "cloud",
16549
- "enterprise",
16550
- "mega",
16551
- "default",
16552
- "custom",
16553
- "team",
16554
- "project",
16555
- "swarm",
16556
- "synthetic"
16557
- ];
16558
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);
16559
16571
  AgentOverrideConfigSchema = exports_external.object({
16560
16572
  model: exports_external.string().optional(),
16561
16573
  variant: exports_external.string().min(1).optional(),
@@ -17102,12 +17114,7 @@ var init_schema = __esm(() => {
17102
17114
  maxConcurrentTasks: exports_external.number().int().min(1).max(64).default(1),
17103
17115
  evidenceLockTimeoutMs: exports_external.number().int().min(1000).max(300000).default(60000),
17104
17116
  max_coders: exports_external.number().int().min(1).max(16).default(3),
17105
- max_reviewers: exports_external.number().int().min(1).max(16).default(2),
17106
- stageB: exports_external.object({
17107
- parallel: exports_external.object({
17108
- enabled: exports_external.boolean().default(false)
17109
- }).default({ enabled: false })
17110
- }).default({ parallel: { enabled: false } })
17117
+ max_reviewers: exports_external.number().int().min(1).max(16).default(2)
17111
17118
  });
17112
17119
  PluginConfigSchema = exports_external.object({
17113
17120
  agents: exports_external.record(exports_external.string(), AgentOverrideConfigSchema).optional(),
@@ -17173,13 +17180,143 @@ var init_schema = __esm(() => {
17173
17180
  critic_model: exports_external.string().optional(),
17174
17181
  max_interactions_per_phase: exports_external.number().int().min(5).max(200).default(50),
17175
17182
  deadlock_threshold: exports_external.number().int().min(2).max(10).default(3),
17176
- escalation_mode: exports_external.enum(["pause", "terminate"]).default("pause")
17177
- }).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(() => ({
17178
17270
  enabled: false,
17179
17271
  max_interactions_per_phase: 50,
17180
17272
  deadlock_threshold: 3,
17181
- escalation_mode: "pause"
17182
- })
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
+ }))
17183
17320
  });
17184
17321
  });
17185
17322
 
@@ -19870,7 +20007,8 @@ var init_qa_gate_profile = __esm(() => {
19870
20007
  sast_enabled: true,
19871
20008
  mutation_test: false,
19872
20009
  council_general_review: false,
19873
- drift_check: true
20010
+ drift_check: true,
20011
+ final_council: false
19874
20012
  };
19875
20013
  });
19876
20014
  // node_modules/quick-lru/index.js
@@ -20520,6 +20658,7 @@ var init_delegation_gate = __esm(() => {
20520
20658
  init_state();
20521
20659
  init_telemetry();
20522
20660
  init_logger();
20661
+ init_task_id();
20523
20662
  init_guardrails();
20524
20663
  init_normalize_tool_name();
20525
20664
  init_utils2();
@@ -20559,6 +20698,7 @@ function resetSwarmState() {
20559
20698
  swarmState.opencodeClient = null;
20560
20699
  swarmState.curatorInitAgentNames = [];
20561
20700
  swarmState.curatorPhaseAgentNames = [];
20701
+ swarmState.generatedAgentNames = [];
20562
20702
  _rehydrationCache = null;
20563
20703
  swarmState.fullAutoEnabledInConfig = false;
20564
20704
  swarmState.environmentProfiles.clear();
@@ -20603,6 +20743,7 @@ var init_state = __esm(() => {
20603
20743
  opencodeClient: null,
20604
20744
  curatorInitAgentNames: [],
20605
20745
  curatorPhaseAgentNames: [],
20746
+ generatedAgentNames: [],
20606
20747
  lastBudgetPct: 0,
20607
20748
  agentSessions: defaultRunContext.agentSessions,
20608
20749
  pendingRehydrations: new Set,
@@ -40758,8 +40899,254 @@ var init_export = __esm(() => {
40758
40899
  init_export_service();
40759
40900
  });
40760
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
+
40761
41148
  // src/commands/full-auto.ts
40762
- async function handleFullAutoCommand(_directory, args, sessionID) {
41149
+ async function handleFullAutoCommand(directory, args, sessionID) {
40763
41150
  if (!sessionID || sessionID.trim() === "") {
40764
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.";
40765
41152
  }
@@ -40779,16 +41166,63 @@ async function handleFullAutoCommand(_directory, args, sessionID) {
40779
41166
  if (newFullAutoMode && !swarmState.fullAutoEnabledInConfig) {
40780
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.";
40781
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
+ }
40782
41203
  session.fullAutoMode = newFullAutoMode;
40783
41204
  if (!newFullAutoMode) {
40784
41205
  session.fullAutoInteractionCount = 0;
40785
41206
  session.fullAutoDeadlockCount = 0;
40786
41207
  session.fullAutoLastQuestionHash = null;
40787
41208
  }
40788
- 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(" ");
40789
41220
  }
40790
41221
  var init_full_auto = __esm(() => {
41222
+ init_config();
41223
+ init_state2();
40791
41224
  init_state();
41225
+ init_logger();
40792
41226
  });
40793
41227
 
40794
41228
  // src/services/handoff-service.ts
@@ -41173,19 +41607,19 @@ var init_handoff_service = __esm(() => {
41173
41607
 
41174
41608
  // src/commands/handoff.ts
41175
41609
  import crypto4 from "crypto";
41176
- import { renameSync as renameSync6 } from "fs";
41610
+ import { renameSync as renameSync7 } from "fs";
41177
41611
  async function handleHandoffCommand(directory, _args) {
41178
41612
  const handoffData = await getHandoffData(directory);
41179
41613
  const markdown = formatHandoffMarkdown(handoffData);
41180
41614
  const resolvedPath = validateSwarmPath(directory, "handoff.md");
41181
41615
  const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
41182
41616
  await bunWrite(tempPath, markdown);
41183
- renameSync6(tempPath, resolvedPath);
41617
+ renameSync7(tempPath, resolvedPath);
41184
41618
  const continuationPrompt = formatContinuationPrompt(handoffData);
41185
41619
  const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
41186
41620
  const promptTempPath = `${promptPath}.tmp.${crypto4.randomUUID()}`;
41187
41621
  await bunWrite(promptTempPath, continuationPrompt);
41188
- renameSync6(promptTempPath, promptPath);
41622
+ renameSync7(promptTempPath, promptPath);
41189
41623
  await writeSnapshot(directory, swarmState);
41190
41624
  await flushPendingSnapshot(directory);
41191
41625
  return `## Handoff Brief Written
@@ -41560,9 +41994,9 @@ var init_issue = __esm(() => {
41560
41994
 
41561
41995
  // src/hooks/knowledge-migrator.ts
41562
41996
  import { randomUUID as randomUUID2 } from "crypto";
41563
- import { existsSync as existsSync14, readFileSync as readFileSync10 } from "fs";
41997
+ import { existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
41564
41998
  import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
41565
- import * as path24 from "path";
41999
+ import * as path25 from "path";
41566
42000
  async function migrateKnowledgeToExternal(_directory, _config) {
41567
42001
  return {
41568
42002
  migrated: false,
@@ -41573,10 +42007,10 @@ async function migrateKnowledgeToExternal(_directory, _config) {
41573
42007
  };
41574
42008
  }
41575
42009
  async function migrateContextToKnowledge(directory, config3) {
41576
- const sentinelPath = path24.join(directory, ".swarm", ".knowledge-migrated");
41577
- 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");
41578
42012
  const knowledgePath = resolveSwarmKnowledgePath(directory);
41579
- if (existsSync14(sentinelPath)) {
42013
+ if (existsSync15(sentinelPath)) {
41580
42014
  return {
41581
42015
  migrated: false,
41582
42016
  entriesMigrated: 0,
@@ -41585,7 +42019,7 @@ async function migrateContextToKnowledge(directory, config3) {
41585
42019
  skippedReason: "sentinel-exists"
41586
42020
  };
41587
42021
  }
41588
- if (!existsSync14(contextPath)) {
42022
+ if (!existsSync15(contextPath)) {
41589
42023
  return {
41590
42024
  migrated: false,
41591
42025
  entriesMigrated: 0,
@@ -41770,16 +42204,16 @@ function truncateLesson(text) {
41770
42204
  return `${text.slice(0, 277)}...`;
41771
42205
  }
41772
42206
  function inferProjectName(directory) {
41773
- const packageJsonPath = path24.join(directory, "package.json");
41774
- if (existsSync14(packageJsonPath)) {
42207
+ const packageJsonPath = path25.join(directory, "package.json");
42208
+ if (existsSync15(packageJsonPath)) {
41775
42209
  try {
41776
- const pkg = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
42210
+ const pkg = JSON.parse(readFileSync11(packageJsonPath, "utf-8"));
41777
42211
  if (pkg.name && typeof pkg.name === "string") {
41778
42212
  return pkg.name;
41779
42213
  }
41780
42214
  } catch {}
41781
42215
  }
41782
- return path24.basename(directory);
42216
+ return path25.basename(directory);
41783
42217
  }
41784
42218
  async function writeSentinel(sentinelPath, migrated, dropped) {
41785
42219
  const sentinel = {
@@ -41791,7 +42225,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
41791
42225
  schema_version: 1,
41792
42226
  migration_tool: "knowledge-migrator.ts"
41793
42227
  };
41794
- await mkdir5(path24.dirname(sentinelPath), { recursive: true });
42228
+ await mkdir5(path25.dirname(sentinelPath), { recursive: true });
41795
42229
  await writeFile6(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
41796
42230
  }
41797
42231
  var _internals14;
@@ -42312,8 +42746,8 @@ function containsControlChars(str) {
42312
42746
  var init_path_security = () => {};
42313
42747
 
42314
42748
  // src/tools/lint.ts
42315
- import * as fs11 from "fs";
42316
- import * as path25 from "path";
42749
+ import * as fs12 from "fs";
42750
+ import * as path26 from "path";
42317
42751
  function validateArgs(args) {
42318
42752
  if (typeof args !== "object" || args === null)
42319
42753
  return false;
@@ -42324,9 +42758,9 @@ function validateArgs(args) {
42324
42758
  }
42325
42759
  function getLinterCommand(linter, mode, projectDir) {
42326
42760
  const isWindows = process.platform === "win32";
42327
- const binDir = path25.join(projectDir, "node_modules", ".bin");
42328
- const biomeBin = isWindows ? path25.join(binDir, "biome.EXE") : path25.join(binDir, "biome");
42329
- 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");
42330
42764
  switch (linter) {
42331
42765
  case "biome":
42332
42766
  if (mode === "fix") {
@@ -42342,7 +42776,7 @@ function getLinterCommand(linter, mode, projectDir) {
42342
42776
  }
42343
42777
  function getAdditionalLinterCommand(linter, mode, cwd) {
42344
42778
  const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
42345
- 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;
42346
42780
  switch (linter) {
42347
42781
  case "ruff":
42348
42782
  return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
@@ -42376,12 +42810,12 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
42376
42810
  }
42377
42811
  }
42378
42812
  function detectRuff(cwd) {
42379
- if (fs11.existsSync(path25.join(cwd, "ruff.toml")))
42813
+ if (fs12.existsSync(path26.join(cwd, "ruff.toml")))
42380
42814
  return isCommandAvailable("ruff");
42381
42815
  try {
42382
- const pyproject = path25.join(cwd, "pyproject.toml");
42383
- if (fs11.existsSync(pyproject)) {
42384
- 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");
42385
42819
  if (content.includes("[tool.ruff]"))
42386
42820
  return isCommandAvailable("ruff");
42387
42821
  }
@@ -42389,21 +42823,21 @@ function detectRuff(cwd) {
42389
42823
  return false;
42390
42824
  }
42391
42825
  function detectClippy(cwd) {
42392
- return fs11.existsSync(path25.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
42826
+ return fs12.existsSync(path26.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
42393
42827
  }
42394
42828
  function detectGolangciLint(cwd) {
42395
- return fs11.existsSync(path25.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
42829
+ return fs12.existsSync(path26.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
42396
42830
  }
42397
42831
  function detectCheckstyle(cwd) {
42398
- const hasMaven = fs11.existsSync(path25.join(cwd, "pom.xml"));
42399
- const hasGradle = fs11.existsSync(path25.join(cwd, "build.gradle")) || fs11.existsSync(path25.join(cwd, "build.gradle.kts"));
42400
- 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"));
42401
42835
  return (hasMaven || hasGradle) && hasBinary;
42402
42836
  }
42403
42837
  function detectKtlint(cwd) {
42404
- 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")) || (() => {
42405
42839
  try {
42406
- 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"));
42407
42841
  } catch {
42408
42842
  return false;
42409
42843
  }
@@ -42412,7 +42846,7 @@ function detectKtlint(cwd) {
42412
42846
  }
42413
42847
  function detectDotnetFormat(cwd) {
42414
42848
  try {
42415
- const files = fs11.readdirSync(cwd);
42849
+ const files = fs12.readdirSync(cwd);
42416
42850
  const hasCsproj = files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"));
42417
42851
  return hasCsproj && isCommandAvailable("dotnet");
42418
42852
  } catch {
@@ -42420,14 +42854,14 @@ function detectDotnetFormat(cwd) {
42420
42854
  }
42421
42855
  }
42422
42856
  function detectCppcheck(cwd) {
42423
- if (fs11.existsSync(path25.join(cwd, "CMakeLists.txt"))) {
42857
+ if (fs12.existsSync(path26.join(cwd, "CMakeLists.txt"))) {
42424
42858
  return isCommandAvailable("cppcheck");
42425
42859
  }
42426
42860
  try {
42427
- const dirsToCheck = [cwd, path25.join(cwd, "src")];
42861
+ const dirsToCheck = [cwd, path26.join(cwd, "src")];
42428
42862
  const hasCpp = dirsToCheck.some((dir) => {
42429
42863
  try {
42430
- 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));
42431
42865
  } catch {
42432
42866
  return false;
42433
42867
  }
@@ -42438,13 +42872,13 @@ function detectCppcheck(cwd) {
42438
42872
  }
42439
42873
  }
42440
42874
  function detectSwiftlint(cwd) {
42441
- return fs11.existsSync(path25.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
42875
+ return fs12.existsSync(path26.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
42442
42876
  }
42443
42877
  function detectDartAnalyze(cwd) {
42444
- 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"));
42445
42879
  }
42446
42880
  function detectRubocop(cwd) {
42447
- 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"));
42448
42882
  }
42449
42883
  function detectAdditionalLinter(cwd) {
42450
42884
  if (detectRuff(cwd))
@@ -42472,10 +42906,10 @@ function detectAdditionalLinter(cwd) {
42472
42906
  function findBinInAncestors(startDir, binName) {
42473
42907
  let dir = startDir;
42474
42908
  while (true) {
42475
- const candidate = path25.join(dir, "node_modules", ".bin", binName);
42476
- if (fs11.existsSync(candidate))
42909
+ const candidate = path26.join(dir, "node_modules", ".bin", binName);
42910
+ if (fs12.existsSync(candidate))
42477
42911
  return candidate;
42478
- const parent = path25.dirname(dir);
42912
+ const parent = path26.dirname(dir);
42479
42913
  if (parent === dir)
42480
42914
  break;
42481
42915
  dir = parent;
@@ -42484,11 +42918,11 @@ function findBinInAncestors(startDir, binName) {
42484
42918
  }
42485
42919
  function findBinInEnvPath(binName) {
42486
42920
  const searchPath = process.env.PATH ?? "";
42487
- for (const dir of searchPath.split(path25.delimiter)) {
42921
+ for (const dir of searchPath.split(path26.delimiter)) {
42488
42922
  if (!dir)
42489
42923
  continue;
42490
- const candidate = path25.join(dir, binName);
42491
- if (fs11.existsSync(candidate))
42924
+ const candidate = path26.join(dir, binName);
42925
+ if (fs12.existsSync(candidate))
42492
42926
  return candidate;
42493
42927
  }
42494
42928
  return null;
@@ -42496,17 +42930,17 @@ function findBinInEnvPath(binName) {
42496
42930
  async function detectAvailableLinter(directory) {
42497
42931
  if (!directory)
42498
42932
  return null;
42499
- if (!fs11.existsSync(directory))
42933
+ if (!fs12.existsSync(directory))
42500
42934
  return null;
42501
42935
  const projectDir = directory;
42502
42936
  const isWindows = process.platform === "win32";
42503
- const biomeBin = isWindows ? path25.join(projectDir, "node_modules", ".bin", "biome.EXE") : path25.join(projectDir, "node_modules", ".bin", "biome");
42504
- 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");
42505
42939
  const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
42506
42940
  if (localResult)
42507
42941
  return localResult;
42508
- const biomeAncestor = findBinInAncestors(path25.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
42509
- 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");
42510
42944
  if (biomeAncestor || eslintAncestor) {
42511
42945
  return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
42512
42946
  }
@@ -42525,11 +42959,11 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
42525
42959
  stderr: "pipe"
42526
42960
  });
42527
42961
  const biomeExit = biomeProc.exited;
42528
- const timeout = new Promise((resolve9) => setTimeout(() => resolve9("timeout"), DETECT_TIMEOUT));
42962
+ const timeout = new Promise((resolve10) => setTimeout(() => resolve10("timeout"), DETECT_TIMEOUT));
42529
42963
  const result = await Promise.race([biomeExit, timeout]);
42530
42964
  if (result === "timeout") {
42531
42965
  biomeProc.kill();
42532
- } else if (biomeProc.exitCode === 0 && fs11.existsSync(biomeBin)) {
42966
+ } else if (biomeProc.exitCode === 0 && fs12.existsSync(biomeBin)) {
42533
42967
  return "biome";
42534
42968
  }
42535
42969
  } catch {}
@@ -42539,11 +42973,11 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
42539
42973
  stderr: "pipe"
42540
42974
  });
42541
42975
  const eslintExit = eslintProc.exited;
42542
- const timeout = new Promise((resolve9) => setTimeout(() => resolve9("timeout"), DETECT_TIMEOUT));
42976
+ const timeout = new Promise((resolve10) => setTimeout(() => resolve10("timeout"), DETECT_TIMEOUT));
42543
42977
  const result = await Promise.race([eslintExit, timeout]);
42544
42978
  if (result === "timeout") {
42545
42979
  eslintProc.kill();
42546
- } else if (eslintProc.exitCode === 0 && fs11.existsSync(eslintBin)) {
42980
+ } else if (eslintProc.exitCode === 0 && fs12.existsSync(eslintBin)) {
42547
42981
  return "eslint";
42548
42982
  }
42549
42983
  } catch {}
@@ -42728,8 +43162,8 @@ For Rust: rustup component add clippy`
42728
43162
  });
42729
43163
 
42730
43164
  // src/tools/secretscan.ts
42731
- import * as fs12 from "fs";
42732
- import * as path26 from "path";
43165
+ import * as fs13 from "fs";
43166
+ import * as path27 from "path";
42733
43167
  function calculateShannonEntropy(str) {
42734
43168
  if (str.length === 0)
42735
43169
  return 0;
@@ -42777,11 +43211,11 @@ function isGlobOrPathPattern(pattern) {
42777
43211
  return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
42778
43212
  }
42779
43213
  function loadSecretScanIgnore(scanDir) {
42780
- const ignorePath = path26.join(scanDir, ".secretscanignore");
43214
+ const ignorePath = path27.join(scanDir, ".secretscanignore");
42781
43215
  try {
42782
- if (!fs12.existsSync(ignorePath))
43216
+ if (!fs13.existsSync(ignorePath))
42783
43217
  return [];
42784
- const content = fs12.readFileSync(ignorePath, "utf8");
43218
+ const content = fs13.readFileSync(ignorePath, "utf8");
42785
43219
  const patterns = [];
42786
43220
  for (const rawLine of content.split(/\r?\n/)) {
42787
43221
  const line = rawLine.trim();
@@ -42800,7 +43234,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
42800
43234
  if (exactNames.has(entry))
42801
43235
  return true;
42802
43236
  for (const pattern of globPatterns) {
42803
- if (path26.matchesGlob(relPath, pattern))
43237
+ if (path27.matchesGlob(relPath, pattern))
42804
43238
  return true;
42805
43239
  }
42806
43240
  return false;
@@ -42821,7 +43255,7 @@ function validateDirectoryInput(dir) {
42821
43255
  return null;
42822
43256
  }
42823
43257
  function isBinaryFile(filePath, buffer) {
42824
- const ext = path26.extname(filePath).toLowerCase();
43258
+ const ext = path27.extname(filePath).toLowerCase();
42825
43259
  if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
42826
43260
  return true;
42827
43261
  }
@@ -42899,7 +43333,7 @@ function createRedactedContext(line, findings) {
42899
43333
  function scanFileForSecrets(filePath) {
42900
43334
  const findings = [];
42901
43335
  try {
42902
- const lstat = fs12.lstatSync(filePath);
43336
+ const lstat = fs13.lstatSync(filePath);
42903
43337
  if (lstat.isSymbolicLink()) {
42904
43338
  return findings;
42905
43339
  }
@@ -42908,14 +43342,14 @@ function scanFileForSecrets(filePath) {
42908
43342
  }
42909
43343
  let buffer;
42910
43344
  if (O_NOFOLLOW !== undefined) {
42911
- const fd = fs12.openSync(filePath, "r", O_NOFOLLOW);
43345
+ const fd = fs13.openSync(filePath, "r", O_NOFOLLOW);
42912
43346
  try {
42913
- buffer = fs12.readFileSync(fd);
43347
+ buffer = fs13.readFileSync(fd);
42914
43348
  } finally {
42915
- fs12.closeSync(fd);
43349
+ fs13.closeSync(fd);
42916
43350
  }
42917
43351
  } else {
42918
- buffer = fs12.readFileSync(filePath);
43352
+ buffer = fs13.readFileSync(filePath);
42919
43353
  }
42920
43354
  if (isBinaryFile(filePath, buffer)) {
42921
43355
  return findings;
@@ -42957,9 +43391,9 @@ function isSymlinkLoop(realPath, visited) {
42957
43391
  return false;
42958
43392
  }
42959
43393
  function isPathWithinScope(realPath, scanDir) {
42960
- const resolvedScanDir = path26.resolve(scanDir);
42961
- const resolvedRealPath = path26.resolve(realPath);
42962
- 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}\\`);
42963
43397
  }
42964
43398
  function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
42965
43399
  skippedDirs: 0,
@@ -42970,7 +43404,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
42970
43404
  const files = [];
42971
43405
  let entries;
42972
43406
  try {
42973
- entries = fs12.readdirSync(dir);
43407
+ entries = fs13.readdirSync(dir);
42974
43408
  } catch {
42975
43409
  stats.fileErrors++;
42976
43410
  return files;
@@ -42985,15 +43419,15 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
42985
43419
  return a.localeCompare(b);
42986
43420
  });
42987
43421
  for (const entry of entries) {
42988
- const fullPath = path26.join(dir, entry);
42989
- const relPath = path26.relative(scanDir, fullPath).replace(/\\/g, "/");
43422
+ const fullPath = path27.join(dir, entry);
43423
+ const relPath = path27.relative(scanDir, fullPath).replace(/\\/g, "/");
42990
43424
  if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
42991
43425
  stats.skippedDirs++;
42992
43426
  continue;
42993
43427
  }
42994
43428
  let lstat;
42995
43429
  try {
42996
- lstat = fs12.lstatSync(fullPath);
43430
+ lstat = fs13.lstatSync(fullPath);
42997
43431
  } catch {
42998
43432
  stats.fileErrors++;
42999
43433
  continue;
@@ -43005,7 +43439,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
43005
43439
  if (lstat.isDirectory()) {
43006
43440
  let realPath;
43007
43441
  try {
43008
- realPath = fs12.realpathSync(fullPath);
43442
+ realPath = fs13.realpathSync(fullPath);
43009
43443
  } catch {
43010
43444
  stats.fileErrors++;
43011
43445
  continue;
@@ -43021,7 +43455,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
43021
43455
  const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
43022
43456
  files.push(...subFiles);
43023
43457
  } else if (lstat.isFile()) {
43024
- const ext = path26.extname(fullPath).toLowerCase();
43458
+ const ext = path27.extname(fullPath).toLowerCase();
43025
43459
  if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
43026
43460
  files.push(fullPath);
43027
43461
  } else {
@@ -43224,7 +43658,7 @@ var init_secretscan = __esm(() => {
43224
43658
  redactTemplate: () => "SK[REDACTED]"
43225
43659
  }
43226
43660
  ];
43227
- O_NOFOLLOW = process.platform !== "win32" ? fs12.constants.O_NOFOLLOW : undefined;
43661
+ O_NOFOLLOW = process.platform !== "win32" ? fs13.constants.O_NOFOLLOW : undefined;
43228
43662
  secretscan = createSwarmTool({
43229
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.",
43230
43664
  args: {
@@ -43281,15 +43715,15 @@ var init_secretscan = __esm(() => {
43281
43715
  }
43282
43716
  }
43283
43717
  try {
43284
- const _scanDirRaw = path26.resolve(directory);
43718
+ const _scanDirRaw = path27.resolve(directory);
43285
43719
  const scanDir = (() => {
43286
43720
  try {
43287
- return fs12.realpathSync(_scanDirRaw);
43721
+ return fs13.realpathSync(_scanDirRaw);
43288
43722
  } catch {
43289
43723
  return _scanDirRaw;
43290
43724
  }
43291
43725
  })();
43292
- if (!fs12.existsSync(scanDir)) {
43726
+ if (!fs13.existsSync(scanDir)) {
43293
43727
  const errorResult = {
43294
43728
  error: "directory not found",
43295
43729
  scan_dir: directory,
@@ -43300,7 +43734,7 @@ var init_secretscan = __esm(() => {
43300
43734
  };
43301
43735
  return JSON.stringify(errorResult, null, 2);
43302
43736
  }
43303
- const dirStat = fs12.statSync(scanDir);
43737
+ const dirStat = fs13.statSync(scanDir);
43304
43738
  if (!dirStat.isDirectory()) {
43305
43739
  const errorResult = {
43306
43740
  error: "target must be a directory, not a file",
@@ -43351,7 +43785,7 @@ var init_secretscan = __esm(() => {
43351
43785
  break;
43352
43786
  const fileFindings = scanFileForSecrets(filePath);
43353
43787
  try {
43354
- const stat3 = fs12.statSync(filePath);
43788
+ const stat3 = fs13.statSync(filePath);
43355
43789
  if (stat3.size > MAX_FILE_SIZE_BYTES) {
43356
43790
  skippedFiles++;
43357
43791
  continue;
@@ -43427,15 +43861,15 @@ var init_secretscan = __esm(() => {
43427
43861
  });
43428
43862
 
43429
43863
  // src/test-impact/analyzer.ts
43430
- import fs13 from "fs";
43431
- import path27 from "path";
43864
+ import fs14 from "fs";
43865
+ import path28 from "path";
43432
43866
  function normalizePath(p) {
43433
43867
  return p.replace(/\\/g, "/");
43434
43868
  }
43435
43869
  function isCacheStale(impactMap, generatedAtMs) {
43436
43870
  for (const sourcePath of Object.keys(impactMap)) {
43437
43871
  try {
43438
- const stat3 = fs13.statSync(sourcePath);
43872
+ const stat3 = fs14.statSync(sourcePath);
43439
43873
  if (stat3.mtimeMs > generatedAtMs) {
43440
43874
  return true;
43441
43875
  }
@@ -43449,15 +43883,15 @@ function resolveRelativeImport(fromDir, importPath) {
43449
43883
  if (!importPath.startsWith(".")) {
43450
43884
  return null;
43451
43885
  }
43452
- const resolved = path27.resolve(fromDir, importPath);
43453
- if (path27.extname(resolved)) {
43454
- 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()) {
43455
43889
  return normalizePath(resolved);
43456
43890
  }
43457
43891
  } else {
43458
43892
  for (const ext of EXTENSIONS_TO_TRY) {
43459
43893
  const withExt = resolved + ext;
43460
- if (fs13.existsSync(withExt) && fs13.statSync(withExt).isFile()) {
43894
+ if (fs14.existsSync(withExt) && fs14.statSync(withExt).isFile()) {
43461
43895
  return normalizePath(withExt);
43462
43896
  }
43463
43897
  }
@@ -43476,13 +43910,13 @@ function findTestFilesSync(cwd) {
43476
43910
  function walk(dir, visitedInodes) {
43477
43911
  let entries;
43478
43912
  try {
43479
- entries = fs13.readdirSync(dir, { withFileTypes: true });
43913
+ entries = fs14.readdirSync(dir, { withFileTypes: true });
43480
43914
  } catch {
43481
43915
  return;
43482
43916
  }
43483
43917
  let dirInode;
43484
43918
  try {
43485
- dirInode = fs13.statSync(dir).ino;
43919
+ dirInode = fs14.statSync(dir).ino;
43486
43920
  } catch {
43487
43921
  return;
43488
43922
  }
@@ -43495,12 +43929,12 @@ function findTestFilesSync(cwd) {
43495
43929
  for (const entry of entries) {
43496
43930
  if (entry.isDirectory()) {
43497
43931
  if (!skipDirs.has(entry.name)) {
43498
- walk(path27.join(dir, entry.name), visitedInodes);
43932
+ walk(path28.join(dir, entry.name), visitedInodes);
43499
43933
  }
43500
43934
  } else if (entry.isFile()) {
43501
43935
  const name = entry.name;
43502
43936
  if (/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name)) {
43503
- testFiles.push(normalizePath(path27.join(dir, entry.name)));
43937
+ testFiles.push(normalizePath(path28.join(dir, entry.name)));
43504
43938
  }
43505
43939
  }
43506
43940
  }
@@ -43530,7 +43964,7 @@ async function buildImpactMapInternal(cwd) {
43530
43964
  for (const testFile of testFiles) {
43531
43965
  let content;
43532
43966
  try {
43533
- content = fs13.readFileSync(testFile, "utf-8");
43967
+ content = fs14.readFileSync(testFile, "utf-8");
43534
43968
  } catch {
43535
43969
  continue;
43536
43970
  }
@@ -43538,7 +43972,7 @@ async function buildImpactMapInternal(cwd) {
43538
43972
  continue;
43539
43973
  }
43540
43974
  const imports = extractImports(content);
43541
- const testDir = path27.dirname(testFile);
43975
+ const testDir = path28.dirname(testFile);
43542
43976
  for (const importPath of imports) {
43543
43977
  const resolvedSource = resolveRelativeImport(testDir, importPath);
43544
43978
  if (resolvedSource === null) {
@@ -43560,10 +43994,10 @@ async function buildImpactMap(cwd) {
43560
43994
  return impactMap;
43561
43995
  }
43562
43996
  async function loadImpactMap(cwd) {
43563
- const cachePath = path27.join(cwd, ".swarm", "cache", "impact-map.json");
43564
- if (fs13.existsSync(cachePath)) {
43997
+ const cachePath = path28.join(cwd, ".swarm", "cache", "impact-map.json");
43998
+ if (fs14.existsSync(cachePath)) {
43565
43999
  try {
43566
- const content = fs13.readFileSync(cachePath, "utf-8");
44000
+ const content = fs14.readFileSync(cachePath, "utf-8");
43567
44001
  const data = JSON.parse(content);
43568
44002
  const map3 = data.map;
43569
44003
  const generatedAt = new Date(data.generatedAt).getTime();
@@ -43575,17 +44009,17 @@ async function loadImpactMap(cwd) {
43575
44009
  return _internals17.buildImpactMap(cwd);
43576
44010
  }
43577
44011
  async function saveImpactMap(cwd, impactMap) {
43578
- const cacheDir2 = path27.join(cwd, ".swarm", "cache");
43579
- const cachePath = path27.join(cacheDir2, "impact-map.json");
43580
- if (!fs13.existsSync(cacheDir2)) {
43581
- 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 });
43582
44016
  }
43583
44017
  const data = {
43584
44018
  generatedAt: new Date().toISOString(),
43585
44019
  fileCount: Object.keys(impactMap).length,
43586
44020
  map: impactMap
43587
44021
  };
43588
- fs13.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
44022
+ fs14.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
43589
44023
  }
43590
44024
  async function analyzeImpact(changedFiles, cwd) {
43591
44025
  if (!Array.isArray(changedFiles)) {
@@ -43602,7 +44036,7 @@ async function analyzeImpact(changedFiles, cwd) {
43602
44036
  const impactedTestsSet = new Set;
43603
44037
  const untestedFiles = [];
43604
44038
  for (const changedFile of validFiles) {
43605
- const normalizedChanged = normalizePath(path27.resolve(changedFile));
44039
+ const normalizedChanged = normalizePath(path28.resolve(changedFile));
43606
44040
  const tests = impactMap[normalizedChanged];
43607
44041
  if (tests && tests.length > 0) {
43608
44042
  for (const test of tests) {
@@ -43865,10 +44299,10 @@ function detectFlakyTests(allHistory) {
43865
44299
  var FLAKY_THRESHOLD = 0.3, MIN_RUNS_FOR_QUARANTINE = 5, MAX_HISTORY_RUNS = 20;
43866
44300
 
43867
44301
  // src/test-impact/history-store.ts
43868
- import fs14 from "fs";
43869
- import path28 from "path";
44302
+ import fs15 from "fs";
44303
+ import path29 from "path";
43870
44304
  function getHistoryPath(workingDir) {
43871
- return path28.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
44305
+ return path29.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
43872
44306
  }
43873
44307
  function sanitizeErrorMessage(errorMessage) {
43874
44308
  if (errorMessage === undefined) {
@@ -43923,9 +44357,9 @@ function appendTestRun(record3, workingDir) {
43923
44357
  changedFiles: sanitizeChangedFiles(record3.changedFiles || [])
43924
44358
  };
43925
44359
  const historyPath = getHistoryPath(workingDir);
43926
- const historyDir = path28.dirname(historyPath);
43927
- if (!fs14.existsSync(historyDir)) {
43928
- fs14.mkdirSync(historyDir, { recursive: true });
44360
+ const historyDir = path29.dirname(historyPath);
44361
+ if (!fs15.existsSync(historyDir)) {
44362
+ fs15.mkdirSync(historyDir, { recursive: true });
43929
44363
  }
43930
44364
  const existingRecords = readAllRecords(historyPath);
43931
44365
  existingRecords.push(sanitizedRecord);
@@ -43950,24 +44384,24 @@ function appendTestRun(record3, workingDir) {
43950
44384
  `)}
43951
44385
  `;
43952
44386
  const tempPath = `${historyPath}.tmp`;
43953
- fs14.writeFileSync(tempPath, content, "utf-8");
43954
- fs14.renameSync(tempPath, historyPath);
44387
+ fs15.writeFileSync(tempPath, content, "utf-8");
44388
+ fs15.renameSync(tempPath, historyPath);
43955
44389
  } catch (err) {
43956
44390
  try {
43957
44391
  const tempPath = `${historyPath}.tmp`;
43958
- if (fs14.existsSync(tempPath)) {
43959
- fs14.unlinkSync(tempPath);
44392
+ if (fs15.existsSync(tempPath)) {
44393
+ fs15.unlinkSync(tempPath);
43960
44394
  }
43961
44395
  } catch {}
43962
44396
  throw new Error(`Failed to write test history: ${err instanceof Error ? err.message : String(err)}`);
43963
44397
  }
43964
44398
  }
43965
44399
  function readAllRecords(historyPath) {
43966
- if (!fs14.existsSync(historyPath)) {
44400
+ if (!fs15.existsSync(historyPath)) {
43967
44401
  return [];
43968
44402
  }
43969
44403
  try {
43970
- const content = fs14.readFileSync(historyPath, "utf-8");
44404
+ const content = fs15.readFileSync(historyPath, "utf-8");
43971
44405
  const lines = content.split(`
43972
44406
  `);
43973
44407
  const records = [];
@@ -44004,8 +44438,8 @@ var init_history_store = __esm(() => {
44004
44438
  });
44005
44439
 
44006
44440
  // src/tools/resolve-working-directory.ts
44007
- import * as fs15 from "fs";
44008
- import * as path29 from "path";
44441
+ import * as fs16 from "fs";
44442
+ import * as path30 from "path";
44009
44443
  function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
44010
44444
  if (workingDirectory == null || workingDirectory === "") {
44011
44445
  return { success: true, directory: fallbackDirectory };
@@ -44025,18 +44459,18 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
44025
44459
  };
44026
44460
  }
44027
44461
  }
44028
- const normalizedDir = path29.normalize(workingDirectory);
44029
- const pathParts = normalizedDir.split(path29.sep);
44462
+ const normalizedDir = path30.normalize(workingDirectory);
44463
+ const pathParts = normalizedDir.split(path30.sep);
44030
44464
  if (pathParts.includes("..")) {
44031
44465
  return {
44032
44466
  success: false,
44033
44467
  message: "Invalid working_directory: path traversal sequences (..) are not allowed"
44034
44468
  };
44035
44469
  }
44036
- const resolvedDir = path29.resolve(normalizedDir);
44470
+ const resolvedDir = path30.resolve(normalizedDir);
44037
44471
  let statResult;
44038
44472
  try {
44039
- statResult = fs15.statSync(resolvedDir);
44473
+ statResult = fs16.statSync(resolvedDir);
44040
44474
  } catch {
44041
44475
  return {
44042
44476
  success: false,
@@ -44049,17 +44483,17 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
44049
44483
  message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
44050
44484
  };
44051
44485
  }
44052
- const resolvedFallback = path29.resolve(fallbackDirectory);
44486
+ const resolvedFallback = path30.resolve(fallbackDirectory);
44053
44487
  let fallbackExists = false;
44054
44488
  try {
44055
- fs15.statSync(resolvedFallback);
44489
+ fs16.statSync(resolvedFallback);
44056
44490
  fallbackExists = true;
44057
44491
  } catch {
44058
44492
  fallbackExists = false;
44059
44493
  }
44060
44494
  if (workingDirectory != null && workingDirectory !== "") {
44061
44495
  if (fallbackExists) {
44062
- const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path29.sep);
44496
+ const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path30.sep);
44063
44497
  if (isSubdirectory) {
44064
44498
  return {
44065
44499
  success: false,
@@ -44080,8 +44514,8 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
44080
44514
  var init_resolve_working_directory = () => {};
44081
44515
 
44082
44516
  // src/tools/test-runner.ts
44083
- import * as fs16 from "fs";
44084
- import * as path30 from "path";
44517
+ import * as fs17 from "fs";
44518
+ import * as path31 from "path";
44085
44519
  function isAbsolutePath(str) {
44086
44520
  if (str.startsWith("/"))
44087
44521
  return true;
@@ -44146,19 +44580,19 @@ function hasDevDependency(devDeps, ...patterns) {
44146
44580
  return hasPackageJsonDependency(devDeps, ...patterns);
44147
44581
  }
44148
44582
  function detectGoTest(cwd) {
44149
- return fs16.existsSync(path30.join(cwd, "go.mod")) && isCommandAvailable("go");
44583
+ return fs17.existsSync(path31.join(cwd, "go.mod")) && isCommandAvailable("go");
44150
44584
  }
44151
44585
  function detectJavaMaven(cwd) {
44152
- return fs16.existsSync(path30.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
44586
+ return fs17.existsSync(path31.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
44153
44587
  }
44154
44588
  function detectGradle(cwd) {
44155
- const hasBuildFile = fs16.existsSync(path30.join(cwd, "build.gradle")) || fs16.existsSync(path30.join(cwd, "build.gradle.kts"));
44156
- 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"));
44157
44591
  return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
44158
44592
  }
44159
44593
  function detectDotnetTest(cwd) {
44160
44594
  try {
44161
- const files = fs16.readdirSync(cwd);
44595
+ const files = fs17.readdirSync(cwd);
44162
44596
  const hasCsproj = files.some((f) => f.endsWith(".csproj"));
44163
44597
  return hasCsproj && isCommandAvailable("dotnet");
44164
44598
  } catch {
@@ -44166,32 +44600,32 @@ function detectDotnetTest(cwd) {
44166
44600
  }
44167
44601
  }
44168
44602
  function detectCTest(cwd) {
44169
- const hasSource = fs16.existsSync(path30.join(cwd, "CMakeLists.txt"));
44170
- 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"));
44171
44605
  return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
44172
44606
  }
44173
44607
  function detectSwiftTest(cwd) {
44174
- return fs16.existsSync(path30.join(cwd, "Package.swift")) && isCommandAvailable("swift");
44608
+ return fs17.existsSync(path31.join(cwd, "Package.swift")) && isCommandAvailable("swift");
44175
44609
  }
44176
44610
  function detectDartTest(cwd) {
44177
- 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"));
44178
44612
  }
44179
44613
  function detectRSpec(cwd) {
44180
- const hasRSpecFile = fs16.existsSync(path30.join(cwd, ".rspec"));
44181
- const hasGemfile = fs16.existsSync(path30.join(cwd, "Gemfile"));
44182
- 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"));
44183
44617
  const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
44184
44618
  return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
44185
44619
  }
44186
44620
  function detectMinitest(cwd) {
44187
- 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");
44188
44622
  }
44189
44623
  async function detectTestFramework(cwd) {
44190
44624
  const baseDir = cwd;
44191
44625
  try {
44192
- const packageJsonPath = path30.join(baseDir, "package.json");
44193
- if (fs16.existsSync(packageJsonPath)) {
44194
- 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");
44195
44629
  const pkg = JSON.parse(content);
44196
44630
  const _deps = pkg.dependencies || {};
44197
44631
  const devDeps = pkg.devDependencies || {};
@@ -44210,38 +44644,38 @@ async function detectTestFramework(cwd) {
44210
44644
  return "jest";
44211
44645
  if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
44212
44646
  return "mocha";
44213
- 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"))) {
44214
44648
  if (scripts.test?.includes("bun"))
44215
44649
  return "bun";
44216
44650
  }
44217
44651
  }
44218
44652
  } catch {}
44219
44653
  try {
44220
- const pyprojectTomlPath = path30.join(baseDir, "pyproject.toml");
44221
- const setupCfgPath = path30.join(baseDir, "setup.cfg");
44222
- const requirementsTxtPath = path30.join(baseDir, "requirements.txt");
44223
- if (fs16.existsSync(pyprojectTomlPath)) {
44224
- 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");
44225
44659
  if (content.includes("[tool.pytest"))
44226
44660
  return "pytest";
44227
44661
  if (content.includes("pytest"))
44228
44662
  return "pytest";
44229
44663
  }
44230
- if (fs16.existsSync(setupCfgPath)) {
44231
- const content = fs16.readFileSync(setupCfgPath, "utf-8");
44664
+ if (fs17.existsSync(setupCfgPath)) {
44665
+ const content = fs17.readFileSync(setupCfgPath, "utf-8");
44232
44666
  if (content.includes("[pytest]"))
44233
44667
  return "pytest";
44234
44668
  }
44235
- if (fs16.existsSync(requirementsTxtPath)) {
44236
- const content = fs16.readFileSync(requirementsTxtPath, "utf-8");
44669
+ if (fs17.existsSync(requirementsTxtPath)) {
44670
+ const content = fs17.readFileSync(requirementsTxtPath, "utf-8");
44237
44671
  if (content.includes("pytest"))
44238
44672
  return "pytest";
44239
44673
  }
44240
44674
  } catch {}
44241
44675
  try {
44242
- const cargoTomlPath = path30.join(baseDir, "Cargo.toml");
44243
- if (fs16.existsSync(cargoTomlPath)) {
44244
- 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");
44245
44679
  if (content.includes("[dev-dependencies]")) {
44246
44680
  if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
44247
44681
  return "cargo";
@@ -44250,10 +44684,10 @@ async function detectTestFramework(cwd) {
44250
44684
  }
44251
44685
  } catch {}
44252
44686
  try {
44253
- const pesterConfigPath = path30.join(baseDir, "pester.config.ps1");
44254
- const pesterConfigJsonPath = path30.join(baseDir, "pester.config.ps1.json");
44255
- const pesterPs1Path = path30.join(baseDir, "tests.ps1");
44256
- 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)) {
44257
44691
  return "pester";
44258
44692
  }
44259
44693
  } catch {}
@@ -44281,12 +44715,12 @@ function isTestDirectoryPath(normalizedPath) {
44281
44715
  return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
44282
44716
  }
44283
44717
  function resolveWorkspacePath(file3, workingDir) {
44284
- return path30.isAbsolute(file3) ? path30.resolve(file3) : path30.resolve(workingDir, file3);
44718
+ return path31.isAbsolute(file3) ? path31.resolve(file3) : path31.resolve(workingDir, file3);
44285
44719
  }
44286
44720
  function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
44287
44721
  if (!preferRelative)
44288
44722
  return absolutePath;
44289
- return path30.relative(workingDir, absolutePath);
44723
+ return path31.relative(workingDir, absolutePath);
44290
44724
  }
44291
44725
  function dedupePush(target, value) {
44292
44726
  if (!target.includes(value)) {
@@ -44323,18 +44757,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
44323
44757
  }
44324
44758
  }
44325
44759
  function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
44326
- const relativeDir = path30.dirname(relativePath);
44760
+ const relativeDir = path31.dirname(relativePath);
44327
44761
  const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
44328
44762
  const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
44329
- const rootDir = path30.join(workingDir, dirName);
44330
- return nestedRelativeDir ? [rootDir, path30.join(rootDir, nestedRelativeDir)] : [rootDir];
44763
+ const rootDir = path31.join(workingDir, dirName);
44764
+ return nestedRelativeDir ? [rootDir, path31.join(rootDir, nestedRelativeDir)] : [rootDir];
44331
44765
  });
44332
44766
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
44333
44767
  if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
44334
- 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))));
44335
44769
  }
44336
44770
  if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
44337
- 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))));
44338
44772
  }
44339
44773
  return [...new Set(directories)];
44340
44774
  }
@@ -44362,23 +44796,23 @@ function isLanguageSpecificTestFile(basename5) {
44362
44796
  }
44363
44797
  function isConventionTestFilePath(filePath) {
44364
44798
  const normalizedPath = filePath.replace(/\\/g, "/");
44365
- const basename5 = path30.basename(filePath);
44799
+ const basename5 = path31.basename(filePath);
44366
44800
  return hasCompoundTestExtension(basename5) || basename5.includes(".spec.") || basename5.includes(".test.") || isLanguageSpecificTestFile(basename5) || isTestDirectoryPath(normalizedPath);
44367
44801
  }
44368
44802
  function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
44369
44803
  const testFiles = [];
44370
44804
  for (const file3 of sourceFiles) {
44371
44805
  const absoluteFile = resolveWorkspacePath(file3, workingDir);
44372
- const relativeFile = path30.relative(workingDir, absoluteFile);
44373
- const basename5 = path30.basename(absoluteFile);
44374
- const dirname13 = path30.dirname(absoluteFile);
44375
- 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);
44376
44810
  if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
44377
44811
  dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
44378
44812
  continue;
44379
44813
  }
44380
44814
  const nameWithoutExt = basename5.replace(/\.[^.]+$/, "");
44381
- const ext = path30.extname(basename5);
44815
+ const ext = path31.extname(basename5);
44382
44816
  const genericTestNames = [
44383
44817
  `${nameWithoutExt}.spec${ext}`,
44384
44818
  `${nameWithoutExt}.test${ext}`
@@ -44387,7 +44821,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
44387
44821
  const colocatedCandidates = [
44388
44822
  ...genericTestNames,
44389
44823
  ...languageSpecificTestNames
44390
- ].map((candidateName) => path30.join(dirname13, candidateName));
44824
+ ].map((candidateName) => path31.join(dirname13, candidateName));
44391
44825
  const testDirectoryNames = [
44392
44826
  basename5,
44393
44827
  ...genericTestNames,
@@ -44396,11 +44830,11 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
44396
44830
  const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
44397
44831
  const possibleTestFiles = [
44398
44832
  ...colocatedCandidates,
44399
- ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path30.join(dirname13, dirName, candidateName))),
44400
- ...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)))
44401
44835
  ];
44402
44836
  for (const testFile of possibleTestFiles) {
44403
- if (fs16.existsSync(testFile)) {
44837
+ if (fs17.existsSync(testFile)) {
44404
44838
  dedupePush(testFiles, toWorkspaceOutputPath(testFile, workingDir, preferRelativeOutput));
44405
44839
  }
44406
44840
  }
@@ -44417,8 +44851,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
44417
44851
  for (const testFile of candidateTestFiles) {
44418
44852
  try {
44419
44853
  const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
44420
- const content = fs16.readFileSync(absoluteTestFile, "utf-8");
44421
- const testDir = path30.dirname(absoluteTestFile);
44854
+ const content = fs17.readFileSync(absoluteTestFile, "utf-8");
44855
+ const testDir = path31.dirname(absoluteTestFile);
44422
44856
  const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
44423
44857
  let match;
44424
44858
  match = importRegex.exec(content);
@@ -44426,8 +44860,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
44426
44860
  const importPath = match[1];
44427
44861
  let resolvedImport;
44428
44862
  if (importPath.startsWith(".")) {
44429
- resolvedImport = path30.resolve(testDir, importPath);
44430
- const existingExt = path30.extname(resolvedImport);
44863
+ resolvedImport = path31.resolve(testDir, importPath);
44864
+ const existingExt = path31.extname(resolvedImport);
44431
44865
  if (!existingExt) {
44432
44866
  for (const extToTry of [
44433
44867
  ".ts",
@@ -44438,7 +44872,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
44438
44872
  ".cjs"
44439
44873
  ]) {
44440
44874
  const withExt = resolvedImport + extToTry;
44441
- if (absoluteSourceFiles.includes(withExt) || fs16.existsSync(withExt)) {
44875
+ if (absoluteSourceFiles.includes(withExt) || fs17.existsSync(withExt)) {
44442
44876
  resolvedImport = withExt;
44443
44877
  break;
44444
44878
  }
@@ -44447,12 +44881,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
44447
44881
  } else {
44448
44882
  continue;
44449
44883
  }
44450
- const importBasename = path30.basename(resolvedImport, path30.extname(resolvedImport));
44451
- const importDir = path30.dirname(resolvedImport);
44884
+ const importBasename = path31.basename(resolvedImport, path31.extname(resolvedImport));
44885
+ const importDir = path31.dirname(resolvedImport);
44452
44886
  for (const sourceFile of absoluteSourceFiles) {
44453
- const sourceDir = path30.dirname(sourceFile);
44454
- const sourceBasename = path30.basename(sourceFile, path30.extname(sourceFile));
44455
- 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");
44456
44890
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
44457
44891
  dedupePush(testFiles, testFile);
44458
44892
  break;
@@ -44465,8 +44899,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
44465
44899
  while (match !== null) {
44466
44900
  const importPath = match[1];
44467
44901
  if (importPath.startsWith(".")) {
44468
- let resolvedImport = path30.resolve(testDir, importPath);
44469
- const existingExt = path30.extname(resolvedImport);
44902
+ let resolvedImport = path31.resolve(testDir, importPath);
44903
+ const existingExt = path31.extname(resolvedImport);
44470
44904
  if (!existingExt) {
44471
44905
  for (const extToTry of [
44472
44906
  ".ts",
@@ -44477,18 +44911,18 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
44477
44911
  ".cjs"
44478
44912
  ]) {
44479
44913
  const withExt = resolvedImport + extToTry;
44480
- if (absoluteSourceFiles.includes(withExt) || fs16.existsSync(withExt)) {
44914
+ if (absoluteSourceFiles.includes(withExt) || fs17.existsSync(withExt)) {
44481
44915
  resolvedImport = withExt;
44482
44916
  break;
44483
44917
  }
44484
44918
  }
44485
44919
  }
44486
- const importDir = path30.dirname(resolvedImport);
44487
- const importBasename = path30.basename(resolvedImport, path30.extname(resolvedImport));
44920
+ const importDir = path31.dirname(resolvedImport);
44921
+ const importBasename = path31.basename(resolvedImport, path31.extname(resolvedImport));
44488
44922
  for (const sourceFile of absoluteSourceFiles) {
44489
- const sourceDir = path30.dirname(sourceFile);
44490
- const sourceBasename = path30.basename(sourceFile, path30.extname(sourceFile));
44491
- 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");
44492
44926
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
44493
44927
  dedupePush(testFiles, testFile);
44494
44928
  break;
@@ -44591,8 +45025,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
44591
45025
  return ["mvn", "test"];
44592
45026
  case "gradle": {
44593
45027
  const isWindows = process.platform === "win32";
44594
- const hasGradlewBat = fs16.existsSync(path30.join(baseDir, "gradlew.bat"));
44595
- 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"));
44596
45030
  if (hasGradlewBat && isWindows)
44597
45031
  return ["gradlew.bat", "test"];
44598
45032
  if (hasGradlew)
@@ -44609,7 +45043,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
44609
45043
  "cmake-build-release",
44610
45044
  "out"
44611
45045
  ];
44612
- 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";
44613
45047
  return ["ctest", "--test-dir", actualBuildDir];
44614
45048
  }
44615
45049
  case "swift-test":
@@ -44930,9 +45364,9 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
44930
45364
  stderr: "pipe",
44931
45365
  cwd
44932
45366
  });
44933
- const timeoutPromise = new Promise((resolve12) => setTimeout(() => {
45367
+ const timeoutPromise = new Promise((resolve13) => setTimeout(() => {
44934
45368
  proc.kill();
44935
- resolve12(-1);
45369
+ resolve13(-1);
44936
45370
  }, timeout_ms));
44937
45371
  const [exitCode, stdoutResult, stderrResult] = await Promise.all([
44938
45372
  Promise.race([proc.exited, timeoutPromise]),
@@ -45262,7 +45696,7 @@ var init_test_runner = __esm(() => {
45262
45696
  const sourceFiles = args.files.filter((file3) => {
45263
45697
  if (directTestFiles.includes(file3))
45264
45698
  return false;
45265
- const ext = path30.extname(file3).toLowerCase();
45699
+ const ext = path31.extname(file3).toLowerCase();
45266
45700
  return SOURCE_EXTENSIONS.has(ext);
45267
45701
  });
45268
45702
  const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
@@ -45297,7 +45731,7 @@ var init_test_runner = __esm(() => {
45297
45731
  if (isConventionTestFilePath(f)) {
45298
45732
  return false;
45299
45733
  }
45300
- const ext = path30.extname(f).toLowerCase();
45734
+ const ext = path31.extname(f).toLowerCase();
45301
45735
  return SOURCE_EXTENSIONS.has(ext);
45302
45736
  });
45303
45737
  if (sourceFiles.length === 0) {
@@ -45324,7 +45758,7 @@ var init_test_runner = __esm(() => {
45324
45758
  if (isConventionTestFilePath(f)) {
45325
45759
  return false;
45326
45760
  }
45327
- const ext = path30.extname(f).toLowerCase();
45761
+ const ext = path31.extname(f).toLowerCase();
45328
45762
  return SOURCE_EXTENSIONS.has(ext);
45329
45763
  });
45330
45764
  if (sourceFiles.length === 0) {
@@ -45342,8 +45776,8 @@ var init_test_runner = __esm(() => {
45342
45776
  const impactResult = await analyzeImpact(sourceFiles, workingDir);
45343
45777
  if (impactResult.impactedTests.length > 0) {
45344
45778
  testFiles = impactResult.impactedTests.map((absPath) => {
45345
- const relativePath = path30.relative(workingDir, absPath);
45346
- return path30.isAbsolute(relativePath) ? absPath : relativePath;
45779
+ const relativePath = path31.relative(workingDir, absPath);
45780
+ return path31.isAbsolute(relativePath) ? absPath : relativePath;
45347
45781
  });
45348
45782
  } else {
45349
45783
  graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
@@ -45418,8 +45852,8 @@ var init_test_runner = __esm(() => {
45418
45852
  });
45419
45853
 
45420
45854
  // src/services/preflight-service.ts
45421
- import * as fs17 from "fs";
45422
- import * as path31 from "path";
45855
+ import * as fs18 from "fs";
45856
+ import * as path32 from "path";
45423
45857
  function validateDirectoryPath(dir) {
45424
45858
  if (!dir || typeof dir !== "string") {
45425
45859
  throw new Error("Directory path is required");
@@ -45427,8 +45861,8 @@ function validateDirectoryPath(dir) {
45427
45861
  if (dir.includes("..")) {
45428
45862
  throw new Error("Directory path must not contain path traversal sequences");
45429
45863
  }
45430
- const normalized = path31.normalize(dir);
45431
- 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);
45432
45866
  return absolutePath;
45433
45867
  }
45434
45868
  function validateTimeout(timeoutMs, defaultValue) {
@@ -45451,9 +45885,9 @@ function validateTimeout(timeoutMs, defaultValue) {
45451
45885
  }
45452
45886
  function getPackageVersion(dir) {
45453
45887
  try {
45454
- const packagePath = path31.join(dir, "package.json");
45455
- if (fs17.existsSync(packagePath)) {
45456
- 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");
45457
45891
  const pkg = JSON.parse(content);
45458
45892
  return pkg.version ?? null;
45459
45893
  }
@@ -45462,9 +45896,9 @@ function getPackageVersion(dir) {
45462
45896
  }
45463
45897
  function getChangelogVersion(dir) {
45464
45898
  try {
45465
- const changelogPath = path31.join(dir, "CHANGELOG.md");
45466
- if (fs17.existsSync(changelogPath)) {
45467
- 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");
45468
45902
  const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
45469
45903
  if (match) {
45470
45904
  return match[1];
@@ -45476,10 +45910,10 @@ function getChangelogVersion(dir) {
45476
45910
  function getVersionFileVersion(dir) {
45477
45911
  const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
45478
45912
  for (const file3 of possibleFiles) {
45479
- const filePath = path31.join(dir, file3);
45480
- if (fs17.existsSync(filePath)) {
45913
+ const filePath = path32.join(dir, file3);
45914
+ if (fs18.existsSync(filePath)) {
45481
45915
  try {
45482
- const content = fs17.readFileSync(filePath, "utf-8").trim();
45916
+ const content = fs18.readFileSync(filePath, "utf-8").trim();
45483
45917
  const match = content.match(/(\d+\.\d+\.\d+)/);
45484
45918
  if (match) {
45485
45919
  return match[1];
@@ -45803,8 +46237,8 @@ async function runEvidenceCheck(dir) {
45803
46237
  async function runRequirementCoverageCheck(dir, currentPhase) {
45804
46238
  const startTime = Date.now();
45805
46239
  try {
45806
- const specPath = path31.join(dir, ".swarm", "spec.md");
45807
- if (!fs17.existsSync(specPath)) {
46240
+ const specPath = path32.join(dir, ".swarm", "spec.md");
46241
+ if (!fs18.existsSync(specPath)) {
45808
46242
  return {
45809
46243
  type: "req_coverage",
45810
46244
  status: "skip",
@@ -46101,9 +46535,6 @@ var init_promote = __esm(() => {
46101
46535
  });
46102
46536
 
46103
46537
  // src/commands/qa-gates.ts
46104
- function derivePlanId(plan) {
46105
- return `${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
46106
- }
46107
46538
  function isGateName(name) {
46108
46539
  return ALL_GATE_NAMES.includes(name);
46109
46540
  }
@@ -46229,7 +46660,8 @@ var init_qa_gates = __esm(() => {
46229
46660
  "sast_enabled",
46230
46661
  "mutation_test",
46231
46662
  "council_general_review",
46232
- "drift_check"
46663
+ "drift_check",
46664
+ "final_council"
46233
46665
  ];
46234
46666
  });
46235
46667
 
@@ -46283,13 +46715,13 @@ class CircuitBreaker {
46283
46715
  if (this.config.callTimeoutMs <= 0) {
46284
46716
  return fn();
46285
46717
  }
46286
- return new Promise((resolve13, reject) => {
46718
+ return new Promise((resolve14, reject) => {
46287
46719
  const timeout = setTimeout(() => {
46288
46720
  reject(new Error(`Call timeout after ${this.config.callTimeoutMs}ms`));
46289
46721
  }, this.config.callTimeoutMs);
46290
46722
  fn().then((result) => {
46291
46723
  clearTimeout(timeout);
46292
- resolve13(result);
46724
+ resolve14(result);
46293
46725
  }).catch((error93) => {
46294
46726
  clearTimeout(timeout);
46295
46727
  reject(error93);
@@ -46576,7 +47008,7 @@ var init_queue = __esm(() => {
46576
47008
 
46577
47009
  // src/background/worker.ts
46578
47010
  function sleep(ms) {
46579
- return new Promise((resolve13) => setTimeout(resolve13, ms));
47011
+ return new Promise((resolve14) => setTimeout(resolve14, ms));
46580
47012
  }
46581
47013
 
46582
47014
  class WorkerManager {
@@ -46921,8 +47353,8 @@ var init_manager3 = __esm(() => {
46921
47353
  });
46922
47354
 
46923
47355
  // src/commands/reset.ts
46924
- import * as fs18 from "fs";
46925
- import * as path32 from "path";
47356
+ import * as fs19 from "fs";
47357
+ import * as path33 from "path";
46926
47358
  async function handleResetCommand(directory, args) {
46927
47359
  const hasConfirm = args.includes("--confirm");
46928
47360
  if (!hasConfirm) {
@@ -46950,8 +47382,8 @@ async function handleResetCommand(directory, args) {
46950
47382
  for (const filename of filesToReset) {
46951
47383
  try {
46952
47384
  const resolvedPath = validateSwarmPath(directory, filename);
46953
- if (fs18.existsSync(resolvedPath)) {
46954
- fs18.unlinkSync(resolvedPath);
47385
+ if (fs19.existsSync(resolvedPath)) {
47386
+ fs19.unlinkSync(resolvedPath);
46955
47387
  results.push(`- \u2705 Deleted ${filename}`);
46956
47388
  } else {
46957
47389
  results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
@@ -46962,9 +47394,9 @@ async function handleResetCommand(directory, args) {
46962
47394
  }
46963
47395
  for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
46964
47396
  try {
46965
- const rootPath = path32.join(directory, filename);
46966
- if (fs18.existsSync(rootPath)) {
46967
- fs18.unlinkSync(rootPath);
47397
+ const rootPath = path33.join(directory, filename);
47398
+ if (fs19.existsSync(rootPath)) {
47399
+ fs19.unlinkSync(rootPath);
46968
47400
  results.push(`- \u2705 Deleted ${filename} (root)`);
46969
47401
  }
46970
47402
  } catch {}
@@ -46977,8 +47409,8 @@ async function handleResetCommand(directory, args) {
46977
47409
  }
46978
47410
  try {
46979
47411
  const summariesPath = validateSwarmPath(directory, "summaries");
46980
- if (fs18.existsSync(summariesPath)) {
46981
- fs18.rmSync(summariesPath, { recursive: true, force: true });
47412
+ if (fs19.existsSync(summariesPath)) {
47413
+ fs19.rmSync(summariesPath, { recursive: true, force: true });
46982
47414
  results.push("- \u2705 Deleted summaries/ directory");
46983
47415
  } else {
46984
47416
  results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
@@ -47001,14 +47433,14 @@ var init_reset = __esm(() => {
47001
47433
  });
47002
47434
 
47003
47435
  // src/commands/reset-session.ts
47004
- import * as fs19 from "fs";
47005
- import * as path33 from "path";
47436
+ import * as fs20 from "fs";
47437
+ import * as path34 from "path";
47006
47438
  async function handleResetSessionCommand(directory, _args) {
47007
47439
  const results = [];
47008
47440
  try {
47009
47441
  const statePath = validateSwarmPath(directory, "session/state.json");
47010
- if (fs19.existsSync(statePath)) {
47011
- fs19.unlinkSync(statePath);
47442
+ if (fs20.existsSync(statePath)) {
47443
+ fs20.unlinkSync(statePath);
47012
47444
  results.push("\u2705 Deleted .swarm/session/state.json");
47013
47445
  } else {
47014
47446
  results.push("\u23ED\uFE0F state.json not found (already clean)");
@@ -47017,15 +47449,15 @@ async function handleResetSessionCommand(directory, _args) {
47017
47449
  results.push("\u274C Failed to delete state.json");
47018
47450
  }
47019
47451
  try {
47020
- const sessionDir = path33.dirname(validateSwarmPath(directory, "session/state.json"));
47021
- if (fs19.existsSync(sessionDir)) {
47022
- 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);
47023
47455
  const otherFiles = files.filter((f) => f !== "state.json");
47024
47456
  let deletedCount = 0;
47025
47457
  for (const file3 of otherFiles) {
47026
- const filePath = path33.join(sessionDir, file3);
47027
- if (fs19.lstatSync(filePath).isFile()) {
47028
- fs19.unlinkSync(filePath);
47458
+ const filePath = path34.join(sessionDir, file3);
47459
+ if (fs20.lstatSync(filePath).isFile()) {
47460
+ fs20.unlinkSync(filePath);
47029
47461
  deletedCount++;
47030
47462
  }
47031
47463
  }
@@ -47055,7 +47487,7 @@ var init_reset_session = __esm(() => {
47055
47487
  });
47056
47488
 
47057
47489
  // src/summaries/manager.ts
47058
- import * as path34 from "path";
47490
+ import * as path35 from "path";
47059
47491
  function sanitizeSummaryId(id) {
47060
47492
  if (!id || id.length === 0) {
47061
47493
  throw new Error("Invalid summary ID: empty string");
@@ -47078,7 +47510,7 @@ function sanitizeSummaryId(id) {
47078
47510
  }
47079
47511
  async function loadFullOutput(directory, id) {
47080
47512
  const sanitizedId = sanitizeSummaryId(id);
47081
- const relativePath = path34.join("summaries", `${sanitizedId}.json`);
47513
+ const relativePath = path35.join("summaries", `${sanitizedId}.json`);
47082
47514
  validateSwarmPath(directory, relativePath);
47083
47515
  const content = await readSwarmFileAsync(directory, relativePath);
47084
47516
  if (content === null) {
@@ -47140,18 +47572,18 @@ var init_retrieve = __esm(() => {
47140
47572
  });
47141
47573
 
47142
47574
  // src/commands/rollback.ts
47143
- import * as fs20 from "fs";
47144
- import * as path35 from "path";
47575
+ import * as fs21 from "fs";
47576
+ import * as path36 from "path";
47145
47577
  async function handleRollbackCommand(directory, args) {
47146
47578
  const phaseArg = args[0];
47147
47579
  if (!phaseArg) {
47148
47580
  const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
47149
- if (!fs20.existsSync(manifestPath2)) {
47581
+ if (!fs21.existsSync(manifestPath2)) {
47150
47582
  return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
47151
47583
  }
47152
47584
  let manifest2;
47153
47585
  try {
47154
- manifest2 = JSON.parse(fs20.readFileSync(manifestPath2, "utf-8"));
47586
+ manifest2 = JSON.parse(fs21.readFileSync(manifestPath2, "utf-8"));
47155
47587
  } catch {
47156
47588
  return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
47157
47589
  }
@@ -47173,12 +47605,12 @@ async function handleRollbackCommand(directory, args) {
47173
47605
  return "Error: Phase number must be a positive integer.";
47174
47606
  }
47175
47607
  const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
47176
- if (!fs20.existsSync(manifestPath)) {
47608
+ if (!fs21.existsSync(manifestPath)) {
47177
47609
  return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
47178
47610
  }
47179
47611
  let manifest;
47180
47612
  try {
47181
- manifest = JSON.parse(fs20.readFileSync(manifestPath, "utf-8"));
47613
+ manifest = JSON.parse(fs21.readFileSync(manifestPath, "utf-8"));
47182
47614
  } catch {
47183
47615
  return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
47184
47616
  }
@@ -47188,10 +47620,10 @@ async function handleRollbackCommand(directory, args) {
47188
47620
  return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
47189
47621
  }
47190
47622
  const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
47191
- if (!fs20.existsSync(checkpointDir)) {
47623
+ if (!fs21.existsSync(checkpointDir)) {
47192
47624
  return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
47193
47625
  }
47194
- const checkpointFiles = fs20.readdirSync(checkpointDir);
47626
+ const checkpointFiles = fs21.readdirSync(checkpointDir);
47195
47627
  if (checkpointFiles.length === 0) {
47196
47628
  return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
47197
47629
  }
@@ -47206,10 +47638,10 @@ async function handleRollbackCommand(directory, args) {
47206
47638
  if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
47207
47639
  continue;
47208
47640
  }
47209
- const src = path35.join(checkpointDir, file3);
47210
- const dest = path35.join(swarmDir, file3);
47641
+ const src = path36.join(checkpointDir, file3);
47642
+ const dest = path36.join(swarmDir, file3);
47211
47643
  try {
47212
- fs20.cpSync(src, dest, { recursive: true, force: true });
47644
+ fs21.cpSync(src, dest, { recursive: true, force: true });
47213
47645
  successes.push(file3);
47214
47646
  } catch (error93) {
47215
47647
  failures.push({ file: file3, error: error93.message });
@@ -47226,16 +47658,16 @@ async function handleRollbackCommand(directory, args) {
47226
47658
  ].join(`
47227
47659
  `);
47228
47660
  }
47229
- const existingLedgerPath = path35.join(swarmDir, "plan-ledger.jsonl");
47230
- if (fs20.existsSync(existingLedgerPath)) {
47231
- fs20.unlinkSync(existingLedgerPath);
47661
+ const existingLedgerPath = path36.join(swarmDir, "plan-ledger.jsonl");
47662
+ if (fs21.existsSync(existingLedgerPath)) {
47663
+ fs21.unlinkSync(existingLedgerPath);
47232
47664
  }
47233
47665
  try {
47234
- const planJsonPath = path35.join(swarmDir, "plan.json");
47235
- if (fs20.existsSync(planJsonPath)) {
47236
- 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");
47237
47669
  const plan = PlanSchema.parse(JSON.parse(planRaw));
47238
- const planId = `${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
47670
+ const planId = derivePlanId(plan);
47239
47671
  const planHash = computePlanHash(plan);
47240
47672
  await initLedger(directory, planId, planHash, plan);
47241
47673
  await appendLedgerEvent(directory, {
@@ -47260,7 +47692,7 @@ async function handleRollbackCommand(directory, args) {
47260
47692
  timestamp: new Date().toISOString()
47261
47693
  };
47262
47694
  try {
47263
- fs20.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
47695
+ fs21.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
47264
47696
  `);
47265
47697
  } catch (error93) {
47266
47698
  console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
@@ -47308,11 +47740,11 @@ async function handleSimulateCommand(directory, args) {
47308
47740
  ];
47309
47741
  const report = reportLines.filter(Boolean).join(`
47310
47742
  `);
47311
- const fs21 = await import("fs/promises");
47312
- const path36 = await import("path");
47313
- const reportPath = path36.join(directory, ".swarm", "simulate-report.md");
47314
- await fs21.mkdir(path36.dirname(reportPath), { recursive: true });
47315
- 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");
47316
47748
  return `${darkMatterPairs.length} hidden coupling pairs detected`;
47317
47749
  }
47318
47750
  var init_simulate = __esm(() => {
@@ -47665,8 +48097,8 @@ __export(exports_commands, {
47665
48097
  VALID_COMMANDS: () => VALID_COMMANDS,
47666
48098
  COMMAND_REGISTRY: () => COMMAND_REGISTRY
47667
48099
  });
47668
- import fs21 from "fs";
47669
- import path36 from "path";
48100
+ import fs22 from "fs";
48101
+ import path37 from "path";
47670
48102
  function buildHelpText() {
47671
48103
  const lines = ["## Swarm Commands", ""];
47672
48104
  const CATEGORIES = [
@@ -47775,11 +48207,11 @@ function createSwarmCommandHandler(directory, agents) {
47775
48207
  return;
47776
48208
  }
47777
48209
  let isFirstRun = false;
47778
- const sentinelPath = path36.join(directory, ".swarm", ".first-run-complete");
48210
+ const sentinelPath = path37.join(directory, ".swarm", ".first-run-complete");
47779
48211
  try {
47780
- const swarmDir = path36.join(directory, ".swarm");
47781
- fs21.mkdirSync(swarmDir, { recursive: true });
47782
- 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()}
47783
48215
  `, { flag: "wx" });
47784
48216
  isFirstRun = true;
47785
48217
  } catch (_err) {}
@@ -47962,24 +48394,24 @@ function validateAliases() {
47962
48394
  }
47963
48395
  aliasTargets.get(target).push(name);
47964
48396
  const visited = new Set;
47965
- const path37 = [];
48397
+ const path38 = [];
47966
48398
  let current = target;
47967
48399
  while (current) {
47968
48400
  const currentEntry = COMMAND_REGISTRY[current];
47969
48401
  if (!currentEntry)
47970
48402
  break;
47971
48403
  if (visited.has(current)) {
47972
- const cycleStart = path37.indexOf(current);
48404
+ const cycleStart = path38.indexOf(current);
47973
48405
  const fullChain = [
47974
48406
  name,
47975
- ...path37.slice(0, cycleStart > 0 ? cycleStart : path37.length),
48407
+ ...path38.slice(0, cycleStart > 0 ? cycleStart : path38.length),
47976
48408
  current
47977
48409
  ].join(" \u2192 ");
47978
48410
  errors5.push(`Circular alias detected: ${fullChain}`);
47979
48411
  break;
47980
48412
  }
47981
48413
  visited.add(current);
47982
- path37.push(current);
48414
+ path38.push(current);
47983
48415
  current = currentEntry.aliasOf || "";
47984
48416
  }
47985
48417
  }
@@ -48437,68 +48869,68 @@ init_package();
48437
48869
  init_registry();
48438
48870
  init_cache_paths();
48439
48871
  init_constants();
48440
- import * as fs22 from "fs";
48872
+ import * as fs23 from "fs";
48441
48873
  import * as os7 from "os";
48442
- import * as path37 from "path";
48874
+ import * as path38 from "path";
48443
48875
  var { version: version4 } = package_default;
48444
48876
  var CONFIG_DIR = getPluginConfigDir();
48445
- var OPENCODE_CONFIG_PATH = path37.join(CONFIG_DIR, "opencode.json");
48446
- var PLUGIN_CONFIG_PATH = path37.join(CONFIG_DIR, "opencode-swarm.json");
48447
- 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");
48448
48880
  var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
48449
48881
  var OPENCODE_PLUGIN_LOCK_FILE_PATHS = getPluginLockFilePaths();
48450
48882
  function isSafeCachePath(p) {
48451
- const resolved = path37.resolve(p);
48452
- const home = path37.resolve(os7.homedir());
48883
+ const resolved = path38.resolve(p);
48884
+ const home = path38.resolve(os7.homedir());
48453
48885
  if (resolved === "/" || resolved === home || resolved.length <= home.length) {
48454
48886
  return false;
48455
48887
  }
48456
- const segments = resolved.split(path37.sep).filter((s) => s.length > 0);
48888
+ const segments = resolved.split(path38.sep).filter((s) => s.length > 0);
48457
48889
  if (segments.length < 4) {
48458
48890
  return false;
48459
48891
  }
48460
- const leaf = path37.basename(resolved);
48892
+ const leaf = path38.basename(resolved);
48461
48893
  if (leaf !== "opencode-swarm@latest" && leaf !== "opencode-swarm") {
48462
48894
  return false;
48463
48895
  }
48464
- const parent = path37.basename(path37.dirname(resolved));
48896
+ const parent = path38.basename(path38.dirname(resolved));
48465
48897
  if (parent !== "packages" && parent !== "node_modules") {
48466
48898
  return false;
48467
48899
  }
48468
- const grandparent = path37.basename(path37.dirname(path37.dirname(resolved)));
48900
+ const grandparent = path38.basename(path38.dirname(path38.dirname(resolved)));
48469
48901
  if (grandparent !== "opencode") {
48470
48902
  return false;
48471
48903
  }
48472
48904
  return true;
48473
48905
  }
48474
48906
  function isSafeLockFilePath(p) {
48475
- const resolved = path37.resolve(p);
48476
- const home = path37.resolve(os7.homedir());
48907
+ const resolved = path38.resolve(p);
48908
+ const home = path38.resolve(os7.homedir());
48477
48909
  if (resolved === "/" || resolved === home || resolved.length <= home.length) {
48478
48910
  return false;
48479
48911
  }
48480
- const segments = resolved.split(path37.sep).filter((s) => s.length > 0);
48912
+ const segments = resolved.split(path38.sep).filter((s) => s.length > 0);
48481
48913
  if (segments.length < 4) {
48482
48914
  return false;
48483
48915
  }
48484
- const leaf = path37.basename(resolved);
48916
+ const leaf = path38.basename(resolved);
48485
48917
  if (leaf !== "bun.lock" && leaf !== "bun.lockb" && leaf !== "package-lock.json") {
48486
48918
  return false;
48487
48919
  }
48488
- const parent = path37.basename(path37.dirname(resolved));
48920
+ const parent = path38.basename(path38.dirname(resolved));
48489
48921
  if (parent !== "opencode") {
48490
48922
  return false;
48491
48923
  }
48492
48924
  return true;
48493
48925
  }
48494
48926
  function ensureDir(dir) {
48495
- if (!fs22.existsSync(dir)) {
48496
- fs22.mkdirSync(dir, { recursive: true });
48927
+ if (!fs23.existsSync(dir)) {
48928
+ fs23.mkdirSync(dir, { recursive: true });
48497
48929
  }
48498
48930
  }
48499
48931
  function loadJson(filepath) {
48500
48932
  try {
48501
- const content = fs22.readFileSync(filepath, "utf-8");
48933
+ const content = fs23.readFileSync(filepath, "utf-8");
48502
48934
  const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
48503
48935
  return JSON.parse(stripped);
48504
48936
  } catch {
@@ -48506,14 +48938,14 @@ function loadJson(filepath) {
48506
48938
  }
48507
48939
  }
48508
48940
  function saveJson(filepath, data) {
48509
- fs22.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
48941
+ fs23.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
48510
48942
  `, "utf-8");
48511
48943
  }
48512
48944
  function writeProjectConfigIfMissing(cwd) {
48513
48945
  try {
48514
- const opencodeDir = path37.join(cwd, ".opencode");
48515
- const projectConfigPath = path37.join(opencodeDir, "opencode-swarm.json");
48516
- 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)) {
48517
48949
  return;
48518
48950
  }
48519
48951
  ensureDir(opencodeDir);
@@ -48533,7 +48965,7 @@ async function install() {
48533
48965
  `);
48534
48966
  ensureDir(CONFIG_DIR);
48535
48967
  ensureDir(PROMPTS_DIR);
48536
- const LEGACY_CONFIG_PATH = path37.join(CONFIG_DIR, "config.json");
48968
+ const LEGACY_CONFIG_PATH = path38.join(CONFIG_DIR, "config.json");
48537
48969
  let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
48538
48970
  if (!opencodeConfig) {
48539
48971
  const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
@@ -48580,7 +49012,7 @@ async function install() {
48580
49012
  console.warn(`\u26A0 Could not clear opencode lock file \u2014 you may need to delete it manually:
48581
49013
  ${failed}`);
48582
49014
  }
48583
- if (!fs22.existsSync(PLUGIN_CONFIG_PATH)) {
49015
+ if (!fs23.existsSync(PLUGIN_CONFIG_PATH)) {
48584
49016
  const defaultConfig = {
48585
49017
  agents: { ...DEFAULT_AGENT_CONFIGS },
48586
49018
  max_iterations: 5
@@ -48659,14 +49091,14 @@ function evictPluginCaches() {
48659
49091
  const cleared = [];
48660
49092
  const failed = [];
48661
49093
  for (const cachePath of OPENCODE_PLUGIN_CACHE_PATHS) {
48662
- if (!fs22.existsSync(cachePath))
49094
+ if (!fs23.existsSync(cachePath))
48663
49095
  continue;
48664
49096
  if (!isSafeCachePath(cachePath)) {
48665
49097
  failed.push(`${cachePath} (refused: failed safety check)`);
48666
49098
  continue;
48667
49099
  }
48668
49100
  try {
48669
- fs22.rmSync(cachePath, { recursive: true, force: true });
49101
+ fs23.rmSync(cachePath, { recursive: true, force: true });
48670
49102
  cleared.push(cachePath);
48671
49103
  } catch (err) {
48672
49104
  failed.push(`${cachePath} (${err instanceof Error ? err.message : String(err)})`);
@@ -48678,14 +49110,14 @@ function evictLockFiles() {
48678
49110
  const cleared = [];
48679
49111
  const failed = [];
48680
49112
  for (const lockPath of OPENCODE_PLUGIN_LOCK_FILE_PATHS) {
48681
- if (!fs22.existsSync(lockPath))
49113
+ if (!fs23.existsSync(lockPath))
48682
49114
  continue;
48683
49115
  if (!isSafeLockFilePath(lockPath)) {
48684
49116
  failed.push(`${lockPath} (refused: failed safety check)`);
48685
49117
  continue;
48686
49118
  }
48687
49119
  try {
48688
- fs22.unlinkSync(lockPath);
49120
+ fs23.unlinkSync(lockPath);
48689
49121
  cleared.push(lockPath);
48690
49122
  } catch (err) {
48691
49123
  const code = err?.code;
@@ -48704,7 +49136,7 @@ async function uninstall() {
48704
49136
  `);
48705
49137
  const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
48706
49138
  if (!opencodeConfig) {
48707
- if (fs22.existsSync(OPENCODE_CONFIG_PATH)) {
49139
+ if (fs23.existsSync(OPENCODE_CONFIG_PATH)) {
48708
49140
  console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
48709
49141
  return 1;
48710
49142
  } else {
@@ -48736,13 +49168,13 @@ async function uninstall() {
48736
49168
  console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
48737
49169
  if (process.argv.includes("--clean")) {
48738
49170
  let cleaned = false;
48739
- if (fs22.existsSync(PLUGIN_CONFIG_PATH)) {
48740
- fs22.unlinkSync(PLUGIN_CONFIG_PATH);
49171
+ if (fs23.existsSync(PLUGIN_CONFIG_PATH)) {
49172
+ fs23.unlinkSync(PLUGIN_CONFIG_PATH);
48741
49173
  console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
48742
49174
  cleaned = true;
48743
49175
  }
48744
- if (fs22.existsSync(PROMPTS_DIR)) {
48745
- fs22.rmSync(PROMPTS_DIR, { recursive: true });
49176
+ if (fs23.existsSync(PROMPTS_DIR)) {
49177
+ fs23.rmSync(PROMPTS_DIR, { recursive: true });
48746
49178
  console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
48747
49179
  cleaned = true;
48748
49180
  }