opencode-swarm 7.18.3 → 7.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -34,7 +34,7 @@ var package_default;
34
34
  var init_package = __esm(() => {
35
35
  package_default = {
36
36
  name: "opencode-swarm",
37
- version: "7.18.3",
37
+ version: "7.19.1",
38
38
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
39
39
  main: "dist/index.js",
40
40
  types: "dist/index.d.ts",
@@ -14893,6 +14893,17 @@ function applyEventToPlan(plan, event) {
14893
14893
  return plan;
14894
14894
  case "task_added":
14895
14895
  return plan;
14896
+ case "task_removed":
14897
+ if (event.task_id) {
14898
+ for (const phase of plan.phases) {
14899
+ const idx = phase.tasks.findIndex((t) => t.id === event.task_id);
14900
+ if (idx !== -1) {
14901
+ phase.tasks.splice(idx, 1);
14902
+ break;
14903
+ }
14904
+ }
14905
+ }
14906
+ return plan;
14896
14907
  case "task_updated":
14897
14908
  return plan;
14898
14909
  case "plan_rebuilt":
@@ -15000,7 +15011,7 @@ async function loadLastApprovedPlan(directory, expectedPlanId) {
15000
15011
  }
15001
15012
  return null;
15002
15013
  }
15003
- var LEDGER_SCHEMA_VERSION = "1.0.0", LEDGER_FILENAME = "plan-ledger.jsonl", PLAN_JSON_FILENAME = "plan.json", LedgerStaleWriterError;
15014
+ var LEDGER_SCHEMA_VERSION = "1.1.0", LEDGER_FILENAME = "plan-ledger.jsonl", PLAN_JSON_FILENAME = "plan.json", LedgerStaleWriterError;
15004
15015
  var init_ledger = __esm(() => {
15005
15016
  init_plan_schema();
15006
15017
  LedgerStaleWriterError = class LedgerStaleWriterError extends Error {
@@ -15290,7 +15301,13 @@ async function loadPlan(directory) {
15290
15301
  const planMdContent2 = await readSwarmFileAsync(directory, "plan.md");
15291
15302
  if (planMdContent2 !== null) {
15292
15303
  const migrated = migrateLegacyPlan(planMdContent2);
15293
- await savePlan(directory, migrated);
15304
+ const { removedCount } = await savePlanWithAutoAcknowledgedRemovals(directory, migrated, "load_plan_migration_from_md", "migrate legacy plan.md to plan.json");
15305
+ if (removedCount > 0) {
15306
+ migrated._midLoadRemovals = {
15307
+ count: removedCount,
15308
+ source: "load_plan_migration_from_md"
15309
+ };
15310
+ }
15294
15311
  return migrated;
15295
15312
  }
15296
15313
  }
@@ -15319,7 +15336,13 @@ async function loadPlan(directory) {
15319
15336
  try {
15320
15337
  const rebuilt = await replayFromLedger(directory);
15321
15338
  if (rebuilt) {
15322
- await savePlan(directory, rebuilt);
15339
+ const { removedCount } = await savePlanWithAutoAcknowledgedRemovals(directory, rebuilt, "load_plan_rebuild_from_ledger", "rebuild plan from ledger replay");
15340
+ if (removedCount > 0) {
15341
+ rebuilt._midLoadRemovals = {
15342
+ count: removedCount,
15343
+ source: "load_plan_rebuild_from_ledger"
15344
+ };
15345
+ }
15323
15346
  return rebuilt;
15324
15347
  }
15325
15348
  try {
@@ -15333,7 +15356,13 @@ async function loadPlan(directory) {
15333
15356
  if (approved) {
15334
15357
  const approvedPhase = approved.approval && typeof approved.approval === "object" && "phase" in approved.approval ? approved.approval.phase : undefined;
15335
15358
  warn(`[loadPlan] Ledger replay returned no plan \u2014 recovered from critic-approved snapshot seq=${approved.seq} timestamp=${approved.timestamp} (approval phase=${approvedPhase ?? "unknown"}). This may roll the plan back to an earlier phase \u2014 verify before continuing.`);
15336
- await savePlan(directory, approved.plan);
15359
+ const { removedCount: snapshotRemovedCount } = await savePlanWithAutoAcknowledgedRemovals(directory, approved.plan, "load_plan_recovery_from_approved_snapshot", "restore from critic-approved snapshot");
15360
+ if (snapshotRemovedCount > 0) {
15361
+ approved.plan._midLoadRemovals = {
15362
+ count: snapshotRemovedCount,
15363
+ source: "load_plan_recovery_from_approved_snapshot"
15364
+ };
15365
+ }
15337
15366
  try {
15338
15367
  await takeSnapshotEvent(directory, approved.plan, {
15339
15368
  source: "recovery_from_approved_snapshot",
@@ -15354,6 +15383,28 @@ async function loadPlan(directory) {
15354
15383
  }
15355
15384
  return null;
15356
15385
  }
15386
+ async function savePlanWithAutoAcknowledgedRemovals(directory, plan, source, reason, options) {
15387
+ const existing = await _internals3.loadPlanJsonOnly(directory);
15388
+ const newIds = new Set;
15389
+ for (const phase of plan.phases) {
15390
+ for (const task of phase.tasks)
15391
+ newIds.add(task.id);
15392
+ }
15393
+ const removedIds = [];
15394
+ if (existing) {
15395
+ for (const phase of existing.phases) {
15396
+ for (const task of phase.tasks) {
15397
+ if (!newIds.has(task.id))
15398
+ removedIds.push(task.id);
15399
+ }
15400
+ }
15401
+ }
15402
+ await savePlan(directory, plan, {
15403
+ ...options ?? {},
15404
+ acknowledged_removals: { ids: removedIds, reason, source }
15405
+ });
15406
+ return { removedCount: removedIds.length };
15407
+ }
15357
15408
  async function savePlan(directory, plan, options) {
15358
15409
  if (directory === null || directory === undefined || typeof directory !== "string" || directory.trim().length === 0) {
15359
15410
  throw new Error(`Invalid directory: directory must be a non-empty string`);
@@ -15490,6 +15541,73 @@ async function savePlan(directory, plan, options) {
15490
15541
  oldTaskMap.set(task.id, { phase: task.phase, status: task.status });
15491
15542
  }
15492
15543
  }
15544
+ const newTaskIds = new Set;
15545
+ for (const phase of validated.phases) {
15546
+ for (const task of phase.tasks)
15547
+ newTaskIds.add(task.id);
15548
+ }
15549
+ const missingTasks = [];
15550
+ for (const [id, info] of oldTaskMap.entries()) {
15551
+ if (!newTaskIds.has(id)) {
15552
+ missingTasks.push({ id, phase: info.phase, status: info.status });
15553
+ }
15554
+ }
15555
+ const ack = options?.acknowledged_removals;
15556
+ if (missingTasks.length > 0) {
15557
+ if (!ack) {
15558
+ throw new PlanTaskRemovalNotAcknowledgedError(missingTasks);
15559
+ }
15560
+ if (typeof ack.reason !== "string" || ack.reason.trim().length === 0) {
15561
+ throw new Error("PLAN_ACKNOWLEDGED_REMOVAL_INVALID: acknowledged_removals.reason must be a non-empty string.");
15562
+ }
15563
+ if (typeof ack.source !== "string" || ack.source.trim().length === 0) {
15564
+ throw new Error("PLAN_ACKNOWLEDGED_REMOVAL_INVALID: acknowledged_removals.source must be a non-empty string.");
15565
+ }
15566
+ const ackSet = new Set(ack.ids);
15567
+ const missingIdsSet = new Set(missingTasks.map((t) => t.id));
15568
+ const unacked = missingTasks.filter((t) => !ackSet.has(t.id));
15569
+ if (unacked.length > 0) {
15570
+ throw new PlanTaskRemovalNotAcknowledgedError(unacked);
15571
+ }
15572
+ for (const id of ack.ids) {
15573
+ if (!missingIdsSet.has(id)) {
15574
+ throw new Error(`PLAN_ACKNOWLEDGED_REMOVAL_INVALID: acknowledged_removals contains "${id}" but that task is not missing from the plan.`);
15575
+ }
15576
+ }
15577
+ try {
15578
+ for (const missing of missingTasks) {
15579
+ const eventInput = {
15580
+ plan_id: derivePlanId(validated),
15581
+ event_type: "task_removed",
15582
+ task_id: missing.id,
15583
+ phase_id: missing.phase,
15584
+ from_status: missing.status,
15585
+ source: ack.source,
15586
+ payload: { reason: ack.reason, source: ack.source }
15587
+ };
15588
+ const capturedTaskId = missing.id;
15589
+ await retryCasWithBackoff(directory, eventInput, {
15590
+ expectedHash: currentHash,
15591
+ planHashAfter: hashAfter,
15592
+ verifyValid: async () => {
15593
+ const onDisk = await _internals3.loadPlanJsonOnly(directory);
15594
+ if (!onDisk)
15595
+ return true;
15596
+ for (const p of onDisk.phases) {
15597
+ if (p.tasks.some((x) => x.id === capturedTaskId))
15598
+ return true;
15599
+ }
15600
+ return false;
15601
+ }
15602
+ });
15603
+ }
15604
+ } catch (error49) {
15605
+ if (error49 instanceof LedgerStaleWriterError) {
15606
+ throw new PlanConcurrentModificationError(`Concurrent plan modification detected after retries: ${error49.message}. Please retry the operation.`);
15607
+ }
15608
+ throw error49;
15609
+ }
15610
+ }
15493
15611
  try {
15494
15612
  for (const phase of validated.phases) {
15495
15613
  for (const task of phase.tasks) {
@@ -15890,7 +16008,7 @@ function migrateLegacyPlan(planContent, swarmId) {
15890
16008
  };
15891
16009
  return plan;
15892
16010
  }
15893
- var PlanConcurrentModificationError, startupLedgerCheckedWorkspaces, recoveryMutexes, _internals3, CAS_BACKOFF_START_MS = 5, CAS_BACKOFF_CAP_MS = 250, CAS_BACKOFF_JITTER = 0.25, CAS_MAX_RETRIES = 3;
16011
+ var PlanConcurrentModificationError, PlanTaskRemovalNotAcknowledgedError, startupLedgerCheckedWorkspaces, recoveryMutexes, _internals3, CAS_BACKOFF_START_MS = 5, CAS_BACKOFF_CAP_MS = 250, CAS_BACKOFF_JITTER = 0.25, CAS_MAX_RETRIES = 3;
15894
16012
  var init_manager = __esm(() => {
15895
16013
  init_plan_schema();
15896
16014
  init_utils2();
@@ -15905,6 +16023,15 @@ var init_manager = __esm(() => {
15905
16023
  this.name = "PlanConcurrentModificationError";
15906
16024
  }
15907
16025
  };
16026
+ PlanTaskRemovalNotAcknowledgedError = class PlanTaskRemovalNotAcknowledgedError extends Error {
16027
+ missingTasks;
16028
+ constructor(missingTasks) {
16029
+ const idList = missingTasks.map((t) => `${t.id}(${t.status})`).join(", ");
16030
+ super(`PLAN_TASK_REMOVAL_NOT_ACKNOWLEDGED: the following tasks were present in the prior plan but missing from the new save: ${idList}. Pass acknowledged_removals.ids covering all missing task IDs with a non-empty reason to proceed.`);
16031
+ this.name = "PlanTaskRemovalNotAcknowledgedError";
16032
+ this.missingTasks = missingTasks;
16033
+ }
16034
+ };
15908
16035
  startupLedgerCheckedWorkspaces = new Set;
15909
16036
  recoveryMutexes = new Map;
15910
16037
  _internals3 = {
@@ -16064,6 +16191,7 @@ var init_tool_names = __esm(() => {
16064
16191
  "skill_improve",
16065
16192
  "spec_write",
16066
16193
  "knowledge_ack",
16194
+ "swarm_command",
16067
16195
  "lean_turbo_plan_lanes",
16068
16196
  "lean_turbo_acquire_locks",
16069
16197
  "lean_turbo_runner_status",
@@ -16316,6 +16444,7 @@ var init_constants = __esm(() => {
16316
16444
  "skill_inspect",
16317
16445
  "skill_improve",
16318
16446
  "knowledge_ack",
16447
+ "swarm_command",
16319
16448
  "lean_turbo_plan_lanes",
16320
16449
  "lean_turbo_acquire_locks",
16321
16450
  "lean_turbo_runner_status",
@@ -16337,7 +16466,8 @@ var init_constants = __esm(() => {
16337
16466
  "todo_extract",
16338
16467
  "doc_scan",
16339
16468
  "knowledge_recall",
16340
- "repo_map"
16469
+ "repo_map",
16470
+ "swarm_command"
16341
16471
  ],
16342
16472
  coder: [
16343
16473
  "diff",
@@ -16351,7 +16481,8 @@ var init_constants = __esm(() => {
16351
16481
  "syntax_check",
16352
16482
  "knowledge_add",
16353
16483
  "knowledge_recall",
16354
- "repo_map"
16484
+ "repo_map",
16485
+ "swarm_command"
16355
16486
  ],
16356
16487
  test_engineer: [
16357
16488
  "test_runner",
@@ -16366,7 +16497,8 @@ var init_constants = __esm(() => {
16366
16497
  "pkg_audit",
16367
16498
  "build_check",
16368
16499
  "syntax_check",
16369
- "search"
16500
+ "search",
16501
+ "swarm_command"
16370
16502
  ],
16371
16503
  sme: [
16372
16504
  "complexity_hotspots",
@@ -16377,7 +16509,8 @@ var init_constants = __esm(() => {
16377
16509
  "schema_drift",
16378
16510
  "search",
16379
16511
  "symbols",
16380
- "knowledge_recall"
16512
+ "knowledge_recall",
16513
+ "swarm_command"
16381
16514
  ],
16382
16515
  reviewer: [
16383
16516
  "diff",
@@ -16399,7 +16532,8 @@ var init_constants = __esm(() => {
16399
16532
  "search",
16400
16533
  "batch_symbols",
16401
16534
  "suggest_patch",
16402
- "repo_map"
16535
+ "repo_map",
16536
+ "swarm_command"
16403
16537
  ],
16404
16538
  critic: [
16405
16539
  "complexity_hotspots",
@@ -16410,7 +16544,8 @@ var init_constants = __esm(() => {
16410
16544
  "knowledge_recall",
16411
16545
  "req_coverage",
16412
16546
  "get_approved_plan",
16413
- "repo_map"
16547
+ "repo_map",
16548
+ "swarm_command"
16414
16549
  ],
16415
16550
  critic_sounding_board: [
16416
16551
  "complexity_hotspots",
@@ -16478,14 +16613,16 @@ var init_constants = __esm(() => {
16478
16613
  "search",
16479
16614
  "symbols",
16480
16615
  "todo_extract",
16481
- "knowledge_recall"
16616
+ "knowledge_recall",
16617
+ "swarm_command"
16482
16618
  ],
16483
16619
  designer: [
16484
16620
  "extract_code_blocks",
16485
16621
  "retrieve_summary",
16486
16622
  "search",
16487
16623
  "symbols",
16488
- "knowledge_recall"
16624
+ "knowledge_recall",
16625
+ "swarm_command"
16489
16626
  ],
16490
16627
  curator_init: ["knowledge_recall"],
16491
16628
  curator_phase: ["knowledge_recall"],
@@ -16501,7 +16638,8 @@ var init_constants = __esm(() => {
16501
16638
  "skill_improve",
16502
16639
  "search",
16503
16640
  "doc_scan",
16504
- "doc_extract"
16641
+ "doc_extract",
16642
+ "web_search"
16505
16643
  ],
16506
16644
  spec_writer: [
16507
16645
  "search",
@@ -16585,6 +16723,7 @@ var init_constants = __esm(() => {
16585
16723
  skill_improve: "run the skill_improver agent to review and refine skills",
16586
16724
  spec_write: "author or update .swarm/spec.md for the current project",
16587
16725
  knowledge_ack: "record an explicit KNOWLEDGE_APPLIED/IGNORED/VIOLATED acknowledgment",
16726
+ swarm_command: "run supported /swarm commands through the canonical command registry",
16588
16727
  lean_turbo_plan_lanes: "partition phase tasks into parallel lanes based on file-scope conflicts for Lean Turbo execution",
16589
16728
  lean_turbo_acquire_locks: "acquire file locks for all files in a lane (all-or-nothing) before lane execution",
16590
16729
  lean_turbo_runner_status: "read Lean Turbo run state from .swarm/turbo-state.json",
@@ -16601,67 +16740,67 @@ var init_constants = __esm(() => {
16601
16740
  DEFAULT_AGENT_CONFIGS = {
16602
16741
  coder: {
16603
16742
  model: "opencode/minimax-m2.5-free",
16604
- fallback_models: ["opencode/big-pickle"]
16743
+ fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
16605
16744
  },
16606
16745
  reviewer: {
16607
16746
  model: "opencode/big-pickle",
16608
- fallback_models: ["opencode/minimax-m2.5-free"]
16747
+ fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
16609
16748
  },
16610
16749
  test_engineer: {
16611
- model: "opencode/big-pickle",
16612
- fallback_models: ["opencode/minimax-m2.5-free"]
16750
+ model: "opencode/gpt-5-nano",
16751
+ fallback_models: ["opencode/big-pickle"]
16613
16752
  },
16614
16753
  explorer: {
16615
16754
  model: "opencode/big-pickle",
16616
- fallback_models: ["opencode/minimax-m2.5-free"]
16755
+ fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
16617
16756
  },
16618
16757
  sme: {
16619
16758
  model: "opencode/big-pickle",
16620
- fallback_models: ["opencode/minimax-m2.5-free"]
16759
+ fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
16621
16760
  },
16622
16761
  critic: {
16623
16762
  model: "opencode/big-pickle",
16624
- fallback_models: ["opencode/minimax-m2.5-free"]
16763
+ fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
16625
16764
  },
16626
16765
  docs: {
16627
16766
  model: "opencode/big-pickle",
16628
- fallback_models: ["opencode/minimax-m2.5-free"]
16767
+ fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
16629
16768
  },
16630
16769
  designer: {
16631
16770
  model: "opencode/big-pickle",
16632
- fallback_models: ["opencode/minimax-m2.5-free"]
16771
+ fallback_models: ["opencode/gpt-5-nano", "opencode/big-pickle"]
16633
16772
  },
16634
16773
  critic_sounding_board: {
16635
- model: "opencode/big-pickle",
16636
- fallback_models: ["opencode/minimax-m2.5-free"]
16774
+ model: "opencode/gpt-5-nano",
16775
+ fallback_models: ["opencode/big-pickle"]
16637
16776
  },
16638
16777
  critic_drift_verifier: {
16639
- model: "opencode/big-pickle",
16640
- fallback_models: ["opencode/minimax-m2.5-free"]
16778
+ model: "opencode/gpt-5-nano",
16779
+ fallback_models: ["opencode/big-pickle"]
16641
16780
  },
16642
16781
  critic_hallucination_verifier: {
16643
- model: "opencode/big-pickle",
16644
- fallback_models: ["opencode/minimax-m2.5-free"]
16782
+ model: "opencode/gpt-5-nano",
16783
+ fallback_models: ["opencode/big-pickle"]
16645
16784
  },
16646
16785
  critic_oversight: {
16647
- model: "opencode/big-pickle",
16648
- fallback_models: ["opencode/minimax-m2.5-free"]
16786
+ model: "opencode/gpt-5-nano",
16787
+ fallback_models: ["opencode/big-pickle"]
16649
16788
  },
16650
16789
  curator_init: {
16651
- model: "opencode/big-pickle",
16652
- fallback_models: ["opencode/minimax-m2.5-free"]
16790
+ model: "opencode/gpt-5-nano",
16791
+ fallback_models: ["opencode/big-pickle"]
16653
16792
  },
16654
16793
  curator_phase: {
16655
- model: "opencode/big-pickle",
16656
- fallback_models: ["opencode/minimax-m2.5-free"]
16794
+ model: "opencode/gpt-5-nano",
16795
+ fallback_models: ["opencode/big-pickle"]
16657
16796
  },
16658
16797
  skill_improver: {
16659
16798
  model: "opencode/big-pickle",
16660
- fallback_models: ["opencode/minimax-m2.5-free"]
16799
+ fallback_models: ["opencode/gpt-5-nano"]
16661
16800
  },
16662
16801
  spec_writer: {
16663
16802
  model: "opencode/big-pickle",
16664
- fallback_models: ["opencode/minimax-m2.5-free"]
16803
+ fallback_models: ["opencode/gpt-5-nano"]
16665
16804
  }
16666
16805
  };
16667
16806
  });
@@ -17544,8 +17683,7 @@ function handleAgentsCommand(agents, guardrails) {
17544
17683
  if (hasUnregistered) {
17545
17684
  lines.push("", "### Unregistered Subagents");
17546
17685
  for (const name of unregistered) {
17547
- const hint = UNREGISTERED_AGENT_HINTS[name] ?? "requires configuration";
17548
- lines.push(`- **${name}** (${hint})`);
17686
+ lines.push(`- **${name}** (requires configuration)`);
17549
17687
  }
17550
17688
  }
17551
17689
  if (guardrails?.profiles && Object.keys(guardrails.profiles).length > 0) {
@@ -17574,18 +17712,9 @@ function handleAgentsCommand(agents, guardrails) {
17574
17712
  return lines.join(`
17575
17713
  `);
17576
17714
  }
17577
- var UNREGISTERED_AGENT_HINTS;
17578
17715
  var init_agents = __esm(() => {
17579
17716
  init_constants();
17580
17717
  init_schema();
17581
- UNREGISTERED_AGENT_HINTS = {
17582
- designer: "enable ui_review.enabled",
17583
- council_generalist: "enable council.general.enabled",
17584
- council_skeptic: "enable council.general.enabled",
17585
- council_domain_expert: "enable council.general.enabled",
17586
- skill_improver: "registered by default unless agents.skill_improver.disabled is true",
17587
- spec_writer: "registered by default unless agents.spec_writer.disabled is true"
17588
- };
17589
17718
  });
17590
17719
 
17591
17720
  // src/commands/analyze.ts
@@ -20236,13 +20365,6 @@ var init_qa_gate_profile = __esm(() => {
20236
20365
  final_council: false
20237
20366
  };
20238
20367
  });
20239
- // src/parallel/runtime-config.ts
20240
- var lockedProfileCache;
20241
- var init_runtime_config = __esm(() => {
20242
- init_plan_schema();
20243
- lockedProfileCache = new Map;
20244
- });
20245
-
20246
20368
  // node_modules/quick-lru/index.js
20247
20369
  var QuickLRU;
20248
20370
  var init_quick_lru = __esm(() => {
@@ -20826,7 +20948,7 @@ var init_model_limits = __esm(() => {
20826
20948
  var init_normalize_tool_name = () => {};
20827
20949
 
20828
20950
  // src/hooks/guardrails.ts
20829
- var storedInputArgs, TRANSIENT_STATUS_CODES, toolCallsSinceLastWrite, noOpWarningIssued, consecutiveNoToolTurns, DC_SAFE_TARGETS, DC_FS_ROOTS, pathNormalizationCache, globMatcherCache;
20951
+ var SPEC_DRIFT_BLOCKED_TOOLS, storedInputArgs, TRANSIENT_STATUS_CODES, toolCallsSinceLastWrite, noOpWarningIssued, consecutiveNoToolTurns, DC_SAFE_TARGETS, DC_FS_ROOTS, pathNormalizationCache, globMatcherCache;
20830
20952
  var init_guardrails = __esm(() => {
20831
20953
  init_quick_lru();
20832
20954
  init_agents2();
@@ -20845,6 +20967,13 @@ var init_guardrails = __esm(() => {
20845
20967
  init_loop_detector();
20846
20968
  init_model_limits();
20847
20969
  init_normalize_tool_name();
20970
+ SPEC_DRIFT_BLOCKED_TOOLS = new Set([
20971
+ "save_plan",
20972
+ "update_task_status",
20973
+ "phase_complete",
20974
+ "lean_turbo_run_phase",
20975
+ "lean_turbo_acquire_locks"
20976
+ ]);
20848
20977
  storedInputArgs = new Map;
20849
20978
  TRANSIENT_STATUS_CODES = new Set([408, 429, 500, 502, 503, 504, 529]);
20850
20979
  toolCallsSinceLastWrite = new Map;
@@ -20888,7 +21017,6 @@ function clearPendingCoderScope() {
20888
21017
  var pendingCoderScopeByTaskId;
20889
21018
  var init_delegation_gate = __esm(() => {
20890
21019
  init_schema();
20891
- init_runtime_config();
20892
21020
  init_state();
20893
21021
  init_telemetry();
20894
21022
  init_logger();
@@ -38256,31 +38384,12 @@ function parseArgs(args) {
38256
38384
  }
38257
38385
  return out;
38258
38386
  }
38259
- async function handleCouncilCommand(directory, args) {
38387
+ async function handleCouncilCommand(_directory, args) {
38260
38388
  const parsed = parseArgs(args);
38261
38389
  const question = sanitizeQuestion(parsed.rest.join(" "));
38262
38390
  if (!question) {
38263
38391
  return USAGE;
38264
38392
  }
38265
- const config3 = loadPluginConfig(directory);
38266
- if (config3.council?.general?.enabled !== true) {
38267
- return [
38268
- "General Council is not enabled for this project.",
38269
- "",
38270
- "Enable it in `.opencode/opencode-swarm.json` or `~/.config/opencode/opencode-swarm.json`:",
38271
- "",
38272
- "```json",
38273
- "{",
38274
- ' "council": {',
38275
- ' "general": { "enabled": true }',
38276
- " }",
38277
- "}",
38278
- "```",
38279
- "",
38280
- "Then restart OpenCode and run `/swarm config doctor` before trying `/swarm council` again."
38281
- ].join(`
38282
- `);
38283
- }
38284
38393
  const tokens = ["MODE: COUNCIL"];
38285
38394
  if (parsed.preset) {
38286
38395
  tokens.push(`preset=${parsed.preset}`);
@@ -38292,7 +38401,6 @@ async function handleCouncilCommand(directory, args) {
38292
38401
  }
38293
38402
  var MAX_QUESTION_LEN = 2000, USAGE;
38294
38403
  var init_council = __esm(() => {
38295
- init_loader();
38296
38404
  USAGE = [
38297
38405
  "Usage: /swarm council <question> [--preset <name>] [--spec-review]",
38298
38406
  "",
@@ -39769,7 +39877,6 @@ __export(exports_config_doctor, {
39769
39877
  restoreFromBackup: () => restoreFromBackup,
39770
39878
  getConfigPaths: () => getConfigPaths,
39771
39879
  createConfigBackup: () => createConfigBackup,
39772
- collectConfiguredModelRefs: () => collectConfiguredModelRefs,
39773
39880
  applySafeAutoFixes: () => applySafeAutoFixes
39774
39881
  });
39775
39882
  import * as crypto3 from "crypto";
@@ -40163,129 +40270,6 @@ function validateConfigKey(path24, value, _config) {
40163
40270
  }
40164
40271
  return findings;
40165
40272
  }
40166
- function addConfiguredModel(refs, model, configPath) {
40167
- if (typeof model !== "string")
40168
- return;
40169
- const trimmed = model.trim();
40170
- if (!trimmed)
40171
- return;
40172
- const paths = refs.get(trimmed) ?? new Set;
40173
- paths.add(configPath);
40174
- refs.set(trimmed, paths);
40175
- }
40176
- function addConfiguredAgentModels(refs, agents, prefix) {
40177
- if (!agents || typeof agents !== "object" || Array.isArray(agents))
40178
- return;
40179
- for (const [agentName, value] of Object.entries(agents)) {
40180
- if (!value || typeof value !== "object" || Array.isArray(value))
40181
- continue;
40182
- const agent = value;
40183
- addConfiguredModel(refs, agent.model, `${prefix}.${agentName}.model`);
40184
- if (Array.isArray(agent.fallback_models)) {
40185
- agent.fallback_models.forEach((model, index) => {
40186
- addConfiguredModel(refs, model, `${prefix}.${agentName}.fallback_models[${index}]`);
40187
- });
40188
- }
40189
- }
40190
- }
40191
- function collectConfiguredModelRefs(config3) {
40192
- const refs = new Map;
40193
- const rawConfig = config3;
40194
- addConfiguredAgentModels(refs, rawConfig.agents, "agents");
40195
- if (rawConfig.swarms && typeof rawConfig.swarms === "object" && !Array.isArray(rawConfig.swarms)) {
40196
- for (const [swarmId, value] of Object.entries(rawConfig.swarms)) {
40197
- if (!value || typeof value !== "object" || Array.isArray(value))
40198
- continue;
40199
- addConfiguredAgentModels(refs, value.agents, `swarms.${swarmId}.agents`);
40200
- }
40201
- }
40202
- if (rawConfig.full_auto && typeof rawConfig.full_auto === "object" && !Array.isArray(rawConfig.full_auto)) {
40203
- addConfiguredModel(refs, rawConfig.full_auto.critic_model, "full_auto.critic_model");
40204
- }
40205
- if (rawConfig.skill_improver && typeof rawConfig.skill_improver === "object" && !Array.isArray(rawConfig.skill_improver)) {
40206
- const skillImprover = rawConfig.skill_improver;
40207
- addConfiguredModel(refs, skillImprover.model, "skill_improver.model");
40208
- if (Array.isArray(skillImprover.fallback_models)) {
40209
- skillImprover.fallback_models.forEach((model, index) => {
40210
- addConfiguredModel(refs, model, `skill_improver.fallback_models[${index}]`);
40211
- });
40212
- }
40213
- }
40214
- if (rawConfig.spec_writer && typeof rawConfig.spec_writer === "object" && !Array.isArray(rawConfig.spec_writer)) {
40215
- const specWriter = rawConfig.spec_writer;
40216
- addConfiguredModel(refs, specWriter.model, "spec_writer.model");
40217
- if (Array.isArray(specWriter.fallback_models)) {
40218
- specWriter.fallback_models.forEach((model, index) => {
40219
- addConfiguredModel(refs, model, `spec_writer.fallback_models[${index}]`);
40220
- });
40221
- }
40222
- }
40223
- const council = rawConfig.council;
40224
- const general = council && typeof council === "object" && !Array.isArray(council) ? council.general : undefined;
40225
- if (general && typeof general === "object" && !Array.isArray(general)) {
40226
- addConfiguredModel(refs, general.moderatorModel, "council.general.moderatorModel");
40227
- if (Array.isArray(general.members)) {
40228
- general.members.forEach((member, index) => {
40229
- if (!member || typeof member !== "object" || Array.isArray(member)) {
40230
- return;
40231
- }
40232
- addConfiguredModel(refs, member.model, `council.general.members[${index}].model`);
40233
- });
40234
- }
40235
- if (general.presets && typeof general.presets === "object" && !Array.isArray(general.presets)) {
40236
- for (const [presetName, members] of Object.entries(general.presets)) {
40237
- if (!Array.isArray(members))
40238
- continue;
40239
- members.forEach((member, index) => {
40240
- if (!member || typeof member !== "object" || Array.isArray(member)) {
40241
- return;
40242
- }
40243
- addConfiguredModel(refs, member.model, `council.general.presets.${presetName}[${index}].model`);
40244
- });
40245
- }
40246
- }
40247
- }
40248
- return refs;
40249
- }
40250
- function validateConfiguredModels(config3, modelAvailability) {
40251
- const refs = collectConfiguredModelRefs(config3);
40252
- const findings = [];
40253
- if (modelAvailability.error) {
40254
- findings.push({
40255
- id: "model-availability-unchecked",
40256
- title: "Model availability check skipped",
40257
- description: `Could not load OpenCode provider models from ${modelAvailability.source}: ` + modelAvailability.error,
40258
- severity: "info",
40259
- path: "agents",
40260
- autoFixable: false
40261
- });
40262
- return findings;
40263
- }
40264
- if (refs.size === 0)
40265
- return findings;
40266
- for (const [modelId, paths] of refs.entries()) {
40267
- if (modelAvailability.availableModelIds.has(modelId))
40268
- continue;
40269
- findings.push({
40270
- id: "configured-model-unavailable",
40271
- title: "Configured model is unavailable",
40272
- description: `Configured model ${formatModelIdForDoctor(modelId)} was not found in the active OpenCode provider model registry. ` + "Run `/models` to choose a currently available model, then update opencode-swarm.json.",
40273
- severity: "error",
40274
- path: [...paths].sort().join(", "),
40275
- currentValue: modelId,
40276
- autoFixable: false
40277
- });
40278
- }
40279
- return findings;
40280
- }
40281
- function formatModelIdForDoctor(modelId) {
40282
- const json3 = JSON.stringify(modelId);
40283
- if (!json3)
40284
- return '"<invalid model id>"';
40285
- if (json3.length <= 160)
40286
- return json3;
40287
- return `${json3.slice(0, 157)}..."`;
40288
- }
40289
40273
  function walkConfigAndValidate(obj, path24, config3, findings) {
40290
40274
  if (obj === null || obj === undefined) {
40291
40275
  return;
@@ -40310,12 +40294,9 @@ function walkConfigAndValidate(obj, path24, config3, findings) {
40310
40294
  walkConfigAndValidate(value, newPath, config3, findings);
40311
40295
  }
40312
40296
  }
40313
- function runConfigDoctor(config3, directory, options = {}) {
40297
+ function runConfigDoctor(config3, directory) {
40314
40298
  const findings = [];
40315
40299
  walkConfigAndValidate(config3, "", config3, findings);
40316
- if (options.modelAvailability) {
40317
- findings.push(...validateConfiguredModels(config3, options.modelAvailability));
40318
- }
40319
40300
  const summary = {
40320
40301
  info: findings.filter((f) => f.severity === "info").length,
40321
40302
  warn: findings.filter((f) => f.severity === "warn").length,
@@ -40477,8 +40458,8 @@ function shouldRunOnStartup(automationConfig) {
40477
40458
  }
40478
40459
  return automationConfig.capabilities?.config_doctor_on_startup === true;
40479
40460
  }
40480
- async function runConfigDoctorWithFixes(directory, config3, autoFix = false, options = {}) {
40481
- const result = runConfigDoctor(config3, directory, options);
40461
+ async function runConfigDoctorWithFixes(directory, config3, autoFix = false) {
40462
+ const result = runConfigDoctor(config3, directory);
40482
40463
  const artifactPath = writeDoctorArtifact(directory, result);
40483
40464
  if (!autoFix) {
40484
40465
  return {
@@ -40498,7 +40479,7 @@ async function runConfigDoctorWithFixes(directory, config3, autoFix = false, opt
40498
40479
  if (appliedFixes.length > 0) {
40499
40480
  const freshConfig = readConfigFromFile(directory);
40500
40481
  if (freshConfig) {
40501
- const newResult = runConfigDoctor(freshConfig.config, directory, options);
40482
+ const newResult = runConfigDoctor(freshConfig.config, directory);
40502
40483
  writeDoctorArtifact(directory, newResult);
40503
40484
  }
40504
40485
  }
@@ -42120,23 +42101,6 @@ var init_tool_doctor = __esm(() => {
42120
42101
  ];
42121
42102
  });
42122
42103
 
42123
- // src/utils/timeout.ts
42124
- async function withTimeout(promise3, ms, timeoutError) {
42125
- let timer;
42126
- const timeoutPromise = new Promise((_, reject) => {
42127
- timer = setTimeout(() => reject(timeoutError), ms);
42128
- if (typeof timer.unref === "function") {
42129
- timer.unref();
42130
- }
42131
- });
42132
- try {
42133
- return await Promise.race([promise3, timeoutPromise]);
42134
- } finally {
42135
- if (timer !== undefined)
42136
- clearTimeout(timer);
42137
- }
42138
- }
42139
-
42140
42104
  // src/commands/doctor.ts
42141
42105
  function formatToolDoctorMarkdown(result) {
42142
42106
  const lines = [
@@ -42210,67 +42174,13 @@ function formatDoctorMarkdown(result) {
42210
42174
  return lines.join(`
42211
42175
  `);
42212
42176
  }
42213
- function extractAvailableModelIds(response) {
42214
- const available = new Set;
42215
- if (response?.providers !== undefined && !Array.isArray(response.providers)) {
42216
- throw new Error("provider registry returned malformed provider list");
42217
- }
42218
- for (const provider of response?.providers ?? []) {
42219
- if (!provider || typeof provider !== "object" || !provider.id || !provider.models || typeof provider.models !== "object" || Array.isArray(provider.models)) {
42220
- continue;
42221
- }
42222
- for (const [modelKey, modelInfo] of Object.entries(provider.models)) {
42223
- available.add(`${provider.id}/${modelKey}`);
42224
- if (modelInfo && typeof modelInfo === "object" && modelInfo.id) {
42225
- available.add(`${provider.id}/${modelInfo.id}`);
42226
- }
42227
- }
42228
- }
42229
- return available;
42230
- }
42231
- async function loadModelAvailability(directory, client, options = {}) {
42232
- const providerClient = client;
42233
- const providers = providerClient?.config?.providers;
42234
- if (typeof providers !== "function") {
42235
- return;
42236
- }
42237
- try {
42238
- const response = await withTimeout(providers({ directory }), options.timeoutMs ?? MODEL_REGISTRY_TIMEOUT_MS, new Error(`OpenCode provider model registry lookup exceeded ${options.timeoutMs ?? MODEL_REGISTRY_TIMEOUT_MS}ms`));
42239
- if (response.error) {
42240
- return {
42241
- availableModelIds: new Set,
42242
- source: MODEL_REGISTRY_SOURCE,
42243
- error: typeof response.error === "string" ? response.error : JSON.stringify(response.error)
42244
- };
42245
- }
42246
- if (!response.data) {
42247
- return {
42248
- availableModelIds: new Set,
42249
- source: MODEL_REGISTRY_SOURCE,
42250
- error: "provider registry returned no data"
42251
- };
42252
- }
42253
- return {
42254
- availableModelIds: extractAvailableModelIds(response.data),
42255
- source: MODEL_REGISTRY_SOURCE
42256
- };
42257
- } catch (error93) {
42258
- return {
42259
- availableModelIds: new Set,
42260
- source: MODEL_REGISTRY_SOURCE,
42261
- error: error93 instanceof Error ? error93.message : String(error93)
42262
- };
42263
- }
42264
- }
42265
- async function handleDoctorCommand(directory, args, options = {}) {
42177
+ async function handleDoctorCommand(directory, args) {
42266
42178
  const enableAutoFix = args.includes("--fix") || args.includes("-f");
42267
42179
  const config3 = loadPluginConfig(directory);
42268
- const modelAvailability = await loadModelAvailability(directory, options.client);
42269
- const doctorOptions = { modelAvailability };
42270
- const result = runConfigDoctor(config3, directory, doctorOptions);
42180
+ const result = runConfigDoctor(config3, directory);
42271
42181
  if (enableAutoFix && result.hasAutoFixableIssues) {
42272
42182
  const { runConfigDoctorWithFixes: runConfigDoctorWithFixes2 } = await Promise.resolve().then(() => (init_config_doctor(), exports_config_doctor));
42273
- const fixResult = await runConfigDoctorWithFixes2(directory, config3, true, doctorOptions);
42183
+ const fixResult = await runConfigDoctorWithFixes2(directory, config3, true);
42274
42184
  return formatDoctorMarkdown(fixResult.result);
42275
42185
  }
42276
42186
  return formatDoctorMarkdown(result);
@@ -42279,7 +42189,6 @@ async function handleDoctorToolsCommand(directory, _args) {
42279
42189
  const result = runToolDoctor(directory);
42280
42190
  return formatToolDoctorMarkdown(result);
42281
42191
  }
42282
- var MODEL_REGISTRY_TIMEOUT_MS = 3000, MODEL_REGISTRY_SOURCE = "OpenCode config.providers";
42283
42192
  var init_doctor = __esm(() => {
42284
42193
  init_loader();
42285
42194
  init_config_doctor();
@@ -42620,7 +42529,7 @@ function getVerdictEmoji(verdict) {
42620
42529
  return getVerdictIcon(verdict);
42621
42530
  }
42622
42531
  async function getTaskEvidenceData(directory, taskId) {
42623
- const result = await loadEvidence(directory, taskId);
42532
+ const result = await _internals13.loadEvidence(directory, taskId);
42624
42533
  if (result.status !== "found") {
42625
42534
  return {
42626
42535
  hasEvidence: false,
@@ -42643,13 +42552,13 @@ async function getTaskEvidenceData(directory, taskId) {
42643
42552
  };
42644
42553
  }
42645
42554
  async function getEvidenceListData(directory) {
42646
- const taskIds = await listEvidenceTaskIds(directory);
42555
+ const taskIds = await _internals13.listEvidenceTaskIds(directory);
42647
42556
  if (taskIds.length === 0) {
42648
42557
  return { hasEvidence: false, tasks: [] };
42649
42558
  }
42650
42559
  const tasks = [];
42651
42560
  for (const taskId of taskIds) {
42652
- const result = await loadEvidence(directory, taskId);
42561
+ const result = await _internals13.loadEvidence(directory, taskId);
42653
42562
  if (result.status === "found") {
42654
42563
  tasks.push({
42655
42564
  taskId,
@@ -42763,8 +42672,13 @@ async function handleEvidenceSummaryCommand(directory) {
42763
42672
  return lines.join(`
42764
42673
  `);
42765
42674
  }
42675
+ var _internals13;
42766
42676
  var init_evidence_service = __esm(() => {
42767
42677
  init_manager2();
42678
+ _internals13 = {
42679
+ loadEvidence,
42680
+ listEvidenceTaskIds
42681
+ };
42768
42682
  });
42769
42683
 
42770
42684
  // src/commands/evidence.ts
@@ -43168,7 +43082,7 @@ function extractCurrentPhaseFromPlan2(plan) {
43168
43082
  if (!plan) {
43169
43083
  return { currentPhase: null, currentTask: null, incompleteTasks: [] };
43170
43084
  }
43171
- if (!_internals13.validatePlanPhases(plan)) {
43085
+ if (!_internals14.validatePlanPhases(plan)) {
43172
43086
  return { currentPhase: null, currentTask: null, incompleteTasks: [] };
43173
43087
  }
43174
43088
  let currentPhase = null;
@@ -43310,9 +43224,9 @@ function extractPhaseMetrics(content) {
43310
43224
  async function getHandoffData(directory) {
43311
43225
  const now = new Date().toISOString();
43312
43226
  const sessionContent = await readSwarmFileAsync(directory, "session/state.json");
43313
- const sessionState = _internals13.parseSessionState(sessionContent);
43227
+ const sessionState = _internals14.parseSessionState(sessionContent);
43314
43228
  const plan = await loadPlanJsonOnly(directory);
43315
- const planInfo = _internals13.extractCurrentPhaseFromPlan(plan);
43229
+ const planInfo = _internals14.extractCurrentPhaseFromPlan(plan);
43316
43230
  if (!plan) {
43317
43231
  const planMdContent = await readSwarmFileAsync(directory, "plan.md");
43318
43232
  if (planMdContent) {
@@ -43331,8 +43245,8 @@ async function getHandoffData(directory) {
43331
43245
  }
43332
43246
  }
43333
43247
  const contextContent = await readSwarmFileAsync(directory, "context.md");
43334
- const recentDecisions = _internals13.extractDecisions(contextContent);
43335
- const rawPhaseMetrics = _internals13.extractPhaseMetrics(contextContent);
43248
+ const recentDecisions = _internals14.extractDecisions(contextContent);
43249
+ const rawPhaseMetrics = _internals14.extractPhaseMetrics(contextContent);
43336
43250
  const phaseMetrics = sanitizeString(rawPhaseMetrics, 1000);
43337
43251
  let delegationState = null;
43338
43252
  if (sessionState?.delegationState) {
@@ -43496,13 +43410,13 @@ ${lines.join(`
43496
43410
  `)}
43497
43411
  \`\`\``;
43498
43412
  }
43499
- var RTL_OVERRIDE_PATTERN, MAX_TASK_ID_LENGTH = 100, MAX_DECISION_LENGTH = 500, MAX_INCOMPLETE_TASKS = 20, _internals13;
43413
+ var RTL_OVERRIDE_PATTERN, MAX_TASK_ID_LENGTH = 100, MAX_DECISION_LENGTH = 500, MAX_INCOMPLETE_TASKS = 20, _internals14;
43500
43414
  var init_handoff_service = __esm(() => {
43501
43415
  init_utils2();
43502
43416
  init_manager();
43503
43417
  init_utils();
43504
43418
  RTL_OVERRIDE_PATTERN = /[\u202e\u202d\u202c\u200f]/g;
43505
- _internals13 = {
43419
+ _internals14 = {
43506
43420
  getHandoffData,
43507
43421
  formatHandoffMarkdown,
43508
43422
  formatContinuationPrompt,
@@ -43621,22 +43535,22 @@ async function writeSnapshot(directory, state) {
43621
43535
  }
43622
43536
  function createSnapshotWriterHook(directory) {
43623
43537
  return (_input, _output) => {
43624
- _writeInFlight = _writeInFlight.then(() => _internals14.writeSnapshot(directory, swarmState), () => _internals14.writeSnapshot(directory, swarmState));
43538
+ _writeInFlight = _writeInFlight.then(() => _internals15.writeSnapshot(directory, swarmState), () => _internals15.writeSnapshot(directory, swarmState));
43625
43539
  return _writeInFlight;
43626
43540
  };
43627
43541
  }
43628
43542
  async function flushPendingSnapshot(directory) {
43629
- _writeInFlight = _writeInFlight.then(() => _internals14.writeSnapshot(directory, swarmState), () => _internals14.writeSnapshot(directory, swarmState));
43543
+ _writeInFlight = _writeInFlight.then(() => _internals15.writeSnapshot(directory, swarmState), () => _internals15.writeSnapshot(directory, swarmState));
43630
43544
  await _writeInFlight;
43631
43545
  }
43632
- var _writeInFlight, _internals14;
43546
+ var _writeInFlight, _internals15;
43633
43547
  var init_snapshot_writer = __esm(() => {
43634
43548
  init_utils2();
43635
43549
  init_state();
43636
43550
  init_utils();
43637
43551
  init_bun_compat();
43638
43552
  _writeInFlight = Promise.resolve();
43639
- _internals14 = {
43553
+ _internals15 = {
43640
43554
  writeSnapshot,
43641
43555
  createSnapshotWriterHook,
43642
43556
  flushPendingSnapshot
@@ -44101,9 +44015,9 @@ async function migrateContextToKnowledge(directory, config3) {
44101
44015
  skippedReason: "empty-context"
44102
44016
  };
44103
44017
  }
44104
- const rawEntries = _internals15.parseContextMd(contextContent);
44018
+ const rawEntries = _internals16.parseContextMd(contextContent);
44105
44019
  if (rawEntries.length === 0) {
44106
- await _internals15.writeSentinel(sentinelPath, 0, 0);
44020
+ await _internals16.writeSentinel(sentinelPath, 0, 0);
44107
44021
  return {
44108
44022
  migrated: true,
44109
44023
  entriesMigrated: 0,
@@ -44114,10 +44028,10 @@ async function migrateContextToKnowledge(directory, config3) {
44114
44028
  const existing = await readKnowledge(knowledgePath);
44115
44029
  let migrated = 0;
44116
44030
  let dropped = 0;
44117
- const projectName = _internals15.inferProjectName(directory);
44031
+ const projectName = _internals16.inferProjectName(directory);
44118
44032
  for (const raw of rawEntries) {
44119
44033
  if (config3.validation_enabled !== false) {
44120
- const category = raw.categoryHint ?? _internals15.inferCategoryFromText(raw.text);
44034
+ const category = raw.categoryHint ?? _internals16.inferCategoryFromText(raw.text);
44121
44035
  const result = validateLesson(raw.text, existing.map((e) => e.lesson), {
44122
44036
  category,
44123
44037
  scope: "global",
@@ -44137,8 +44051,8 @@ async function migrateContextToKnowledge(directory, config3) {
44137
44051
  const entry = {
44138
44052
  id: randomUUID2(),
44139
44053
  tier: "swarm",
44140
- lesson: _internals15.truncateLesson(raw.text),
44141
- category: raw.categoryHint ?? _internals15.inferCategoryFromText(raw.text),
44054
+ lesson: _internals16.truncateLesson(raw.text),
44055
+ category: raw.categoryHint ?? _internals16.inferCategoryFromText(raw.text),
44142
44056
  tags: [...inferredTags, `migration:${raw.sourceSection}`],
44143
44057
  scope: "global",
44144
44058
  confidence: 0.3,
@@ -44161,7 +44075,7 @@ async function migrateContextToKnowledge(directory, config3) {
44161
44075
  if (migrated > 0) {
44162
44076
  await rewriteKnowledge(knowledgePath, existing);
44163
44077
  }
44164
- await _internals15.writeSentinel(sentinelPath, migrated, dropped);
44078
+ await _internals16.writeSentinel(sentinelPath, migrated, dropped);
44165
44079
  log(`[knowledge-migrator] Migrated ${migrated} entries, dropped ${dropped}`);
44166
44080
  return {
44167
44081
  migrated: true,
@@ -44171,7 +44085,7 @@ async function migrateContextToKnowledge(directory, config3) {
44171
44085
  };
44172
44086
  }
44173
44087
  function parseContextMd(content) {
44174
- const sections = _internals15.splitIntoSections(content);
44088
+ const sections = _internals16.splitIntoSections(content);
44175
44089
  const entries = [];
44176
44090
  const seen = new Set;
44177
44091
  const sectionPatterns = [
@@ -44187,7 +44101,7 @@ function parseContextMd(content) {
44187
44101
  const match = sectionPatterns.find((sp) => sp.pattern.test(section.heading));
44188
44102
  if (!match)
44189
44103
  continue;
44190
- const bullets = _internals15.extractBullets(section.body);
44104
+ const bullets = _internals16.extractBullets(section.body);
44191
44105
  for (const bullet of bullets) {
44192
44106
  if (bullet.length < 15)
44193
44107
  continue;
@@ -44196,9 +44110,9 @@ function parseContextMd(content) {
44196
44110
  continue;
44197
44111
  seen.add(normalized);
44198
44112
  entries.push({
44199
- text: _internals15.truncateLesson(bullet),
44113
+ text: _internals16.truncateLesson(bullet),
44200
44114
  sourceSection: match.sourceSection,
44201
- categoryHint: _internals15.inferCategoryFromText(bullet)
44115
+ categoryHint: _internals16.inferCategoryFromText(bullet)
44202
44116
  });
44203
44117
  }
44204
44118
  }
@@ -44291,12 +44205,12 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
44291
44205
  await mkdir8(path28.dirname(sentinelPath), { recursive: true });
44292
44206
  await writeFile9(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
44293
44207
  }
44294
- var _internals15;
44208
+ var _internals16;
44295
44209
  var init_knowledge_migrator = __esm(() => {
44296
44210
  init_logger();
44297
44211
  init_knowledge_store();
44298
44212
  init_knowledge_validator();
44299
- _internals15 = {
44213
+ _internals16 = {
44300
44214
  migrateContextToKnowledge,
44301
44215
  migrateKnowledgeToExternal,
44302
44216
  parseContextMd,
@@ -44433,9 +44347,9 @@ var init_knowledge = __esm(() => {
44433
44347
 
44434
44348
  // src/services/plan-service.ts
44435
44349
  async function getPlanData(directory, phaseArg) {
44436
- const plan = await loadPlanJsonOnly(directory);
44350
+ const plan = await _internals17.loadPlanJsonOnly(directory);
44437
44351
  if (plan) {
44438
- const fullMarkdown = derivePlanMarkdown(plan);
44352
+ const fullMarkdown = _internals17.derivePlanMarkdown(plan);
44439
44353
  if (phaseArg === undefined || phaseArg === null || phaseArg === "") {
44440
44354
  return {
44441
44355
  hasPlan: true,
@@ -44478,7 +44392,7 @@ async function getPlanData(directory, phaseArg) {
44478
44392
  isLegacy: false
44479
44393
  };
44480
44394
  }
44481
- const planContent = await readSwarmFileAsync(directory, "plan.md");
44395
+ const planContent = await _internals17.readSwarmFileAsync(directory, "plan.md");
44482
44396
  if (!planContent) {
44483
44397
  return {
44484
44398
  hasPlan: false,
@@ -44574,9 +44488,15 @@ async function handlePlanCommand(directory, args) {
44574
44488
  const planData = await getPlanData(directory, phaseArg);
44575
44489
  return formatPlanMarkdown(planData);
44576
44490
  }
44491
+ var _internals17;
44577
44492
  var init_plan_service = __esm(() => {
44578
44493
  init_utils2();
44579
44494
  init_manager();
44495
+ _internals17 = {
44496
+ loadPlanJsonOnly,
44497
+ derivePlanMarkdown,
44498
+ readSwarmFileAsync
44499
+ };
44580
44500
  });
44581
44501
 
44582
44502
  // src/commands/plan.ts
@@ -45162,7 +45082,7 @@ async function runAdditionalLint(linter, mode, cwd) {
45162
45082
  };
45163
45083
  }
45164
45084
  }
45165
- var MAX_OUTPUT_BYTES = 512000, MAX_COMMAND_LENGTH = 500, lint, _internals16;
45085
+ var MAX_OUTPUT_BYTES = 512000, MAX_COMMAND_LENGTH = 500, lint, _internals18;
45166
45086
  var init_lint = __esm(() => {
45167
45087
  init_zod();
45168
45088
  init_discovery();
@@ -45194,15 +45114,15 @@ var init_lint = __esm(() => {
45194
45114
  }
45195
45115
  const { mode } = args;
45196
45116
  const cwd = directory;
45197
- const linter = await _internals16.detectAvailableLinter(directory);
45117
+ const linter = await _internals18.detectAvailableLinter(directory);
45198
45118
  if (linter) {
45199
- const result = await _internals16.runLint(linter, mode, directory);
45119
+ const result = await _internals18.runLint(linter, mode, directory);
45200
45120
  return JSON.stringify(result, null, 2);
45201
45121
  }
45202
- const additionalLinter = _internals16.detectAdditionalLinter(cwd);
45122
+ const additionalLinter = _internals18.detectAdditionalLinter(cwd);
45203
45123
  if (additionalLinter) {
45204
45124
  warn(`[lint] Using ${additionalLinter} linter for this project`);
45205
- const result = await _internals16.runAdditionalLint(additionalLinter, mode, cwd);
45125
+ const result = await _internals18.runAdditionalLint(additionalLinter, mode, cwd);
45206
45126
  return JSON.stringify(result, null, 2);
45207
45127
  }
45208
45128
  const errorResult = {
@@ -45216,7 +45136,7 @@ For Rust: rustup component add clippy`
45216
45136
  return JSON.stringify(errorResult, null, 2);
45217
45137
  }
45218
45138
  });
45219
- _internals16 = {
45139
+ _internals18 = {
45220
45140
  detectAvailableLinter,
45221
45141
  runLint,
45222
45142
  detectAdditionalLinter,
@@ -45530,7 +45450,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
45530
45450
  }
45531
45451
  async function runSecretscan(directory) {
45532
45452
  try {
45533
- const result = await _internals17.secretscan.execute({ directory }, {});
45453
+ const result = await _internals19.secretscan.execute({ directory }, {});
45534
45454
  const jsonStr = typeof result === "string" ? result : result.output;
45535
45455
  return JSON.parse(jsonStr);
45536
45456
  } catch (e) {
@@ -45545,7 +45465,7 @@ async function runSecretscan(directory) {
45545
45465
  return errorResult;
45546
45466
  }
45547
45467
  }
45548
- var MAX_FILE_PATH_LENGTH = 500, MAX_FILE_SIZE_BYTES, MAX_FILES_SCANNED = 1000, MAX_FINDINGS = 100, MAX_OUTPUT_BYTES2 = 512000, MAX_LINE_LENGTH = 1e4, MAX_CONTENT_BYTES, BINARY_SIGNATURES, BINARY_PREFIX_BYTES = 4, BINARY_NULL_CHECK_BYTES = 8192, BINARY_NULL_THRESHOLD = 0.1, DEFAULT_EXCLUDE_DIRS, DEFAULT_EXCLUDE_EXTENSIONS, SECRET_PATTERNS, O_NOFOLLOW, secretscan, _internals17;
45468
+ var MAX_FILE_PATH_LENGTH = 500, MAX_FILE_SIZE_BYTES, MAX_FILES_SCANNED = 1000, MAX_FINDINGS = 100, MAX_OUTPUT_BYTES2 = 512000, MAX_LINE_LENGTH = 1e4, MAX_CONTENT_BYTES, BINARY_SIGNATURES, BINARY_PREFIX_BYTES = 4, BINARY_NULL_CHECK_BYTES = 8192, BINARY_NULL_THRESHOLD = 0.1, DEFAULT_EXCLUDE_DIRS, DEFAULT_EXCLUDE_EXTENSIONS, SECRET_PATTERNS, O_NOFOLLOW, secretscan, _internals19;
45549
45469
  var init_secretscan = __esm(() => {
45550
45470
  init_zod();
45551
45471
  init_path_security();
@@ -45917,7 +45837,7 @@ var init_secretscan = __esm(() => {
45917
45837
  }
45918
45838
  }
45919
45839
  });
45920
- _internals17 = {
45840
+ _internals19 = {
45921
45841
  secretscan,
45922
45842
  runSecretscan
45923
45843
  };
@@ -46489,14 +46409,14 @@ function buildGoBackend() {
46489
46409
  selectEntryPoints
46490
46410
  };
46491
46411
  }
46492
- var PROFILE_ID = "go", IMPORT_REGEX_SINGLE, IMPORT_REGEX_GROUP, IMPORT_REGEX_GROUP_LINE, _internals18;
46412
+ var PROFILE_ID = "go", IMPORT_REGEX_SINGLE, IMPORT_REGEX_GROUP, IMPORT_REGEX_GROUP_LINE, _internals20;
46493
46413
  var init_go = __esm(() => {
46494
46414
  init_default_backend();
46495
46415
  init_profiles();
46496
46416
  IMPORT_REGEX_SINGLE = /^\s*import\s+(?:[a-zA-Z_.][a-zA-Z0-9_]*\s+)?"([^"]+)"/gm;
46497
46417
  IMPORT_REGEX_GROUP = /^\s*import\s*\(([\s\S]*?)\)/gm;
46498
46418
  IMPORT_REGEX_GROUP_LINE = /(?:[a-zA-Z_.][a-zA-Z0-9_]*\s+)?"([^"]+)"/g;
46499
- _internals18 = { extractImports };
46419
+ _internals20 = { extractImports };
46500
46420
  });
46501
46421
 
46502
46422
  // src/lang/backends/python.ts
@@ -46608,13 +46528,13 @@ function buildPythonBackend() {
46608
46528
  selectEntryPoints: selectEntryPoints2
46609
46529
  };
46610
46530
  }
46611
- var PROFILE_ID2 = "python", IMPORT_REGEX_FROM_WITH_TARGETS, IMPORT_REGEX_IMPORT, _internals19;
46531
+ var PROFILE_ID2 = "python", IMPORT_REGEX_FROM_WITH_TARGETS, IMPORT_REGEX_IMPORT, _internals21;
46612
46532
  var init_python = __esm(() => {
46613
46533
  init_default_backend();
46614
46534
  init_profiles();
46615
46535
  IMPORT_REGEX_FROM_WITH_TARGETS = /^\s*from\s+(\.*[\w.]*)\s+import\s+(\([^)]*\)|[^\n#]+)/gm;
46616
46536
  IMPORT_REGEX_IMPORT = /^\s*import\s+([^\n#]+)/gm;
46617
- _internals19 = { extractImports: extractImports2 };
46537
+ _internals21 = { extractImports: extractImports2 };
46618
46538
  });
46619
46539
 
46620
46540
  // src/test-impact/analyzer.ts
@@ -46825,7 +46745,7 @@ function addImpactEdgesForTestFile(testFile, content, impactMap) {
46825
46745
  return;
46826
46746
  }
46827
46747
  if (PYTHON_EXTENSIONS.has(ext)) {
46828
- const modules = _internals19.extractImports(testFile, content);
46748
+ const modules = _internals21.extractImports(testFile, content);
46829
46749
  for (const mod of modules) {
46830
46750
  const resolved = resolvePythonImport(testDir, mod);
46831
46751
  if (resolved !== null)
@@ -46834,7 +46754,7 @@ function addImpactEdgesForTestFile(testFile, content, impactMap) {
46834
46754
  return;
46835
46755
  }
46836
46756
  if (GO_EXTENSIONS.has(ext)) {
46837
- const imports = _internals18.extractImports(testFile, content);
46757
+ const imports = _internals20.extractImports(testFile, content);
46838
46758
  for (const importPath of imports) {
46839
46759
  const sourceFiles = resolveGoImport(testDir, importPath);
46840
46760
  for (const source of sourceFiles)
@@ -46861,8 +46781,8 @@ async function buildImpactMapInternal(cwd) {
46861
46781
  return impactMap;
46862
46782
  }
46863
46783
  async function buildImpactMap(cwd) {
46864
- const impactMap = await _internals20.buildImpactMapInternal(cwd);
46865
- await _internals20.saveImpactMap(cwd, impactMap);
46784
+ const impactMap = await _internals22.buildImpactMapInternal(cwd);
46785
+ await _internals22.saveImpactMap(cwd, impactMap);
46866
46786
  return impactMap;
46867
46787
  }
46868
46788
  async function loadImpactMap(cwd) {
@@ -46873,12 +46793,12 @@ async function loadImpactMap(cwd) {
46873
46793
  const data = JSON.parse(content);
46874
46794
  const map3 = data.map;
46875
46795
  const generatedAt = new Date(data.generatedAt).getTime();
46876
- if (!_internals20.isCacheStale(map3, generatedAt)) {
46796
+ if (!_internals22.isCacheStale(map3, generatedAt)) {
46877
46797
  return map3;
46878
46798
  }
46879
46799
  } catch {}
46880
46800
  }
46881
- return _internals20.buildImpactMap(cwd);
46801
+ return _internals22.buildImpactMap(cwd);
46882
46802
  }
46883
46803
  async function saveImpactMap(cwd, impactMap) {
46884
46804
  const cacheDir2 = path34.join(cwd, ".swarm", "cache");
@@ -46904,7 +46824,7 @@ async function analyzeImpact(changedFiles, cwd) {
46904
46824
  };
46905
46825
  }
46906
46826
  const validFiles = changedFiles.filter((f) => typeof f === "string" && f.length > 0 && !f.includes("\x00"));
46907
- const impactMap = await _internals20.loadImpactMap(cwd);
46827
+ const impactMap = await _internals22.loadImpactMap(cwd);
46908
46828
  const impactedTestsSet = new Set;
46909
46829
  const untestedFiles = [];
46910
46830
  for (const changedFile of validFiles) {
@@ -46945,7 +46865,7 @@ async function analyzeImpact(changedFiles, cwd) {
46945
46865
  impactMap
46946
46866
  };
46947
46867
  }
46948
- var IMPORT_REGEX_ES, IMPORT_REGEX_REQUIRE, IMPORT_REGEX_REEXPORT, TS_EXTENSIONS, PYTHON_EXTENSIONS, GO_EXTENSIONS, EXTENSIONS_TO_TRY, goModuleCache, _internals20;
46868
+ var IMPORT_REGEX_ES, IMPORT_REGEX_REQUIRE, IMPORT_REGEX_REEXPORT, TS_EXTENSIONS, PYTHON_EXTENSIONS, GO_EXTENSIONS, EXTENSIONS_TO_TRY, goModuleCache, _internals22;
46949
46869
  var init_analyzer = __esm(() => {
46950
46870
  init_go();
46951
46871
  init_python();
@@ -46957,7 +46877,7 @@ var init_analyzer = __esm(() => {
46957
46877
  GO_EXTENSIONS = new Set([".go"]);
46958
46878
  EXTENSIONS_TO_TRY = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
46959
46879
  goModuleCache = new Map;
46960
- _internals20 = {
46880
+ _internals22 = {
46961
46881
  normalizePath,
46962
46882
  isCacheStale,
46963
46883
  resolveRelativeImport,
@@ -47437,7 +47357,7 @@ function readPackageJsonRaw(dir) {
47437
47357
  }
47438
47358
  }
47439
47359
  function readPackageJson(dir) {
47440
- return _internals21.readPackageJsonRaw(dir);
47360
+ return _internals23.readPackageJsonRaw(dir);
47441
47361
  }
47442
47362
  function readPackageJsonTestScript(dir) {
47443
47363
  return readPackageJson(dir)?.scripts?.test ?? null;
@@ -47607,7 +47527,7 @@ function buildTypescriptBackend() {
47607
47527
  selectEntryPoints: selectEntryPoints3
47608
47528
  };
47609
47529
  }
47610
- var PROFILE_ID3 = "typescript", IMPORT_REGEX_ES2, IMPORT_REGEX_BARE, IMPORT_REGEX_REQUIRE2, IMPORT_REGEX_DYNAMIC, IMPORT_REGEX_REEXPORT2, _internals21;
47530
+ var PROFILE_ID3 = "typescript", IMPORT_REGEX_ES2, IMPORT_REGEX_BARE, IMPORT_REGEX_REQUIRE2, IMPORT_REGEX_DYNAMIC, IMPORT_REGEX_REEXPORT2, _internals23;
47611
47531
  var init_typescript = __esm(() => {
47612
47532
  init_default_backend();
47613
47533
  init_profiles();
@@ -47616,7 +47536,7 @@ var init_typescript = __esm(() => {
47616
47536
  IMPORT_REGEX_REQUIRE2 = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
47617
47537
  IMPORT_REGEX_DYNAMIC = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
47618
47538
  IMPORT_REGEX_REEXPORT2 = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
47619
- _internals21 = {
47539
+ _internals23 = {
47620
47540
  readPackageJsonRaw,
47621
47541
  readPackageJsonTestScript,
47622
47542
  frameworkFromScriptsTest
@@ -47647,7 +47567,7 @@ __export(exports_dispatch, {
47647
47567
  pickedProfiles: () => pickedProfiles,
47648
47568
  pickBackend: () => pickBackend,
47649
47569
  clearDispatchCache: () => clearDispatchCache,
47650
- _internals: () => _internals22
47570
+ _internals: () => _internals24
47651
47571
  });
47652
47572
  import * as fs21 from "fs";
47653
47573
  import * as path38 from "path";
@@ -47702,7 +47622,7 @@ function findManifestRoot(start) {
47702
47622
  return start;
47703
47623
  }
47704
47624
  function evictIfNeeded() {
47705
- if (cache.size <= _internals22.cacheCapacity)
47625
+ if (cache.size <= _internals24.cacheCapacity)
47706
47626
  return;
47707
47627
  let oldestKey;
47708
47628
  let oldestOrder = Infinity;
@@ -47733,7 +47653,7 @@ async function pickBackend(dir) {
47733
47653
  evictIfNeeded();
47734
47654
  return null;
47735
47655
  }
47736
- const profiles = await _internals22.detectProjectLanguages(root);
47656
+ const profiles = await _internals24.detectProjectLanguages(root);
47737
47657
  if (profiles.length === 0) {
47738
47658
  cache.set(cacheKey, {
47739
47659
  hash: hash3,
@@ -47765,12 +47685,12 @@ function clearDispatchCache() {
47765
47685
  manifestRootCache.clear();
47766
47686
  insertCounter = 0;
47767
47687
  }
47768
- var _internals22, cache, insertCounter = 0, MANIFEST_FILES, _MANIFEST_SET, manifestRootCache;
47688
+ var _internals24, cache, insertCounter = 0, MANIFEST_FILES, _MANIFEST_SET, manifestRootCache;
47769
47689
  var init_dispatch = __esm(() => {
47770
47690
  init_backends();
47771
47691
  init_detector();
47772
47692
  init_registry_backend();
47773
- _internals22 = {
47693
+ _internals24 = {
47774
47694
  detectProjectLanguages,
47775
47695
  cacheCapacity: 64
47776
47696
  };
@@ -49307,9 +49227,9 @@ function getVersionFileVersion(dir) {
49307
49227
  async function runVersionCheck(dir, _timeoutMs) {
49308
49228
  const startTime = Date.now();
49309
49229
  try {
49310
- const packageVersion = _internals23.getPackageVersion(dir);
49311
- const changelogVersion = _internals23.getChangelogVersion(dir);
49312
- const versionFileVersion = _internals23.getVersionFileVersion(dir);
49230
+ const packageVersion = _internals25.getPackageVersion(dir);
49231
+ const changelogVersion = _internals25.getChangelogVersion(dir);
49232
+ const versionFileVersion = _internals25.getVersionFileVersion(dir);
49313
49233
  const versions3 = [];
49314
49234
  if (packageVersion)
49315
49235
  versions3.push(`package.json: ${packageVersion}`);
@@ -49659,7 +49579,7 @@ async function runPreflight(dir, phase, config3) {
49659
49579
  const reportId = `preflight-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
49660
49580
  let validatedDir;
49661
49581
  try {
49662
- validatedDir = _internals23.validateDirectoryPath(dir);
49582
+ validatedDir = _internals25.validateDirectoryPath(dir);
49663
49583
  } catch (error93) {
49664
49584
  return {
49665
49585
  id: reportId,
@@ -49679,7 +49599,7 @@ async function runPreflight(dir, phase, config3) {
49679
49599
  }
49680
49600
  let validatedTimeout;
49681
49601
  try {
49682
- validatedTimeout = _internals23.validateTimeout(config3?.checkTimeoutMs, DEFAULT_CONFIG.checkTimeoutMs);
49602
+ validatedTimeout = _internals25.validateTimeout(config3?.checkTimeoutMs, DEFAULT_CONFIG.checkTimeoutMs);
49683
49603
  } catch (error93) {
49684
49604
  return {
49685
49605
  id: reportId,
@@ -49720,12 +49640,12 @@ async function runPreflight(dir, phase, config3) {
49720
49640
  });
49721
49641
  const checks5 = [];
49722
49642
  log("[Preflight] Running lint check...");
49723
- const lintResult = await _internals23.runLintCheck(validatedDir, cfg.linter, cfg.checkTimeoutMs);
49643
+ const lintResult = await _internals25.runLintCheck(validatedDir, cfg.linter, cfg.checkTimeoutMs);
49724
49644
  checks5.push(lintResult);
49725
49645
  log(`[Preflight] Lint check: ${lintResult.status} ${lintResult.message}`);
49726
49646
  if (!cfg.skipTests) {
49727
49647
  log("[Preflight] Running tests check...");
49728
- const testsResult = await _internals23.runTestsCheck(validatedDir, cfg.testScope, cfg.checkTimeoutMs);
49648
+ const testsResult = await _internals25.runTestsCheck(validatedDir, cfg.testScope, cfg.checkTimeoutMs);
49729
49649
  checks5.push(testsResult);
49730
49650
  log(`[Preflight] Tests check: ${testsResult.status} ${testsResult.message}`);
49731
49651
  } else {
@@ -49737,7 +49657,7 @@ async function runPreflight(dir, phase, config3) {
49737
49657
  }
49738
49658
  if (!cfg.skipSecrets) {
49739
49659
  log("[Preflight] Running secrets check...");
49740
- const secretsResult = await _internals23.runSecretsCheck(validatedDir, cfg.checkTimeoutMs);
49660
+ const secretsResult = await _internals25.runSecretsCheck(validatedDir, cfg.checkTimeoutMs);
49741
49661
  checks5.push(secretsResult);
49742
49662
  log(`[Preflight] Secrets check: ${secretsResult.status} ${secretsResult.message}`);
49743
49663
  } else {
@@ -49749,7 +49669,7 @@ async function runPreflight(dir, phase, config3) {
49749
49669
  }
49750
49670
  if (!cfg.skipEvidence) {
49751
49671
  log("[Preflight] Running evidence check...");
49752
- const evidenceResult = await _internals23.runEvidenceCheck(validatedDir);
49672
+ const evidenceResult = await _internals25.runEvidenceCheck(validatedDir);
49753
49673
  checks5.push(evidenceResult);
49754
49674
  log(`[Preflight] Evidence check: ${evidenceResult.status} ${evidenceResult.message}`);
49755
49675
  } else {
@@ -49760,12 +49680,12 @@ async function runPreflight(dir, phase, config3) {
49760
49680
  });
49761
49681
  }
49762
49682
  log("[Preflight] Running requirement coverage check...");
49763
- const reqCoverageResult = await _internals23.runRequirementCoverageCheck(validatedDir, phase);
49683
+ const reqCoverageResult = await _internals25.runRequirementCoverageCheck(validatedDir, phase);
49764
49684
  checks5.push(reqCoverageResult);
49765
49685
  log(`[Preflight] Requirement coverage check: ${reqCoverageResult.status} ${reqCoverageResult.message}`);
49766
49686
  if (!cfg.skipVersion) {
49767
49687
  log("[Preflight] Running version check...");
49768
- const versionResult = await _internals23.runVersionCheck(validatedDir, cfg.checkTimeoutMs);
49688
+ const versionResult = await _internals25.runVersionCheck(validatedDir, cfg.checkTimeoutMs);
49769
49689
  checks5.push(versionResult);
49770
49690
  log(`[Preflight] Version check: ${versionResult.status} ${versionResult.message}`);
49771
49691
  } else {
@@ -49828,10 +49748,10 @@ function formatPreflightMarkdown(report) {
49828
49748
  async function handlePreflightCommand(directory, _args) {
49829
49749
  const plan = await loadPlan(directory);
49830
49750
  const phase = plan?.current_phase ?? 1;
49831
- const report = await _internals23.runPreflight(directory, phase);
49832
- return _internals23.formatPreflightMarkdown(report);
49751
+ const report = await _internals25.runPreflight(directory, phase);
49752
+ return _internals25.formatPreflightMarkdown(report);
49833
49753
  }
49834
- var MIN_CHECK_TIMEOUT_MS = 5000, MAX_CHECK_TIMEOUT_MS = 300000, DEFAULT_CONFIG, _internals23;
49754
+ var MIN_CHECK_TIMEOUT_MS = 5000, MAX_CHECK_TIMEOUT_MS = 300000, DEFAULT_CONFIG, _internals25;
49835
49755
  var init_preflight_service = __esm(() => {
49836
49756
  init_manager2();
49837
49757
  init_manager();
@@ -49848,7 +49768,7 @@ var init_preflight_service = __esm(() => {
49848
49768
  testScope: "convention",
49849
49769
  linter: "biome"
49850
49770
  };
49851
- _internals23 = {
49771
+ _internals25 = {
49852
49772
  runPreflight,
49853
49773
  formatPreflightMarkdown,
49854
49774
  handlePreflightCommand,
@@ -51372,6 +51292,25 @@ var init_context_budget_service = __esm(() => {
51372
51292
  });
51373
51293
 
51374
51294
  // src/services/status-service.ts
51295
+ import * as fsSync2 from "fs";
51296
+ import * as path46 from "path";
51297
+ function readSpecStalenessSnapshot(directory) {
51298
+ try {
51299
+ const p = path46.join(directory, ".swarm", "spec-staleness.json");
51300
+ if (!fsSync2.existsSync(p))
51301
+ return { stale: false };
51302
+ const raw = fsSync2.readFileSync(p, "utf-8");
51303
+ const parsed = JSON.parse(raw);
51304
+ return {
51305
+ stale: true,
51306
+ reason: typeof parsed?.reason === "string" ? parsed.reason : undefined,
51307
+ storedHash: typeof parsed?.specHash_plan === "string" ? parsed.specHash_plan : undefined,
51308
+ currentHash: typeof parsed?.specHash_current === "string" || parsed?.specHash_current === null ? parsed.specHash_current : undefined
51309
+ };
51310
+ } catch {
51311
+ return { stale: false };
51312
+ }
51313
+ }
51375
51314
  async function getStatusData(directory, agents) {
51376
51315
  const plan = await loadPlan(directory);
51377
51316
  let status;
@@ -51437,11 +51376,21 @@ async function getStatusData(directory, agents) {
51437
51376
  };
51438
51377
  }
51439
51378
  }
51379
+ const drift = readSpecStalenessSnapshot(directory);
51380
+ if (drift.stale) {
51381
+ status.specStale = true;
51382
+ status.specStaleReason = drift.reason;
51383
+ status.specStaleStoredHash = drift.storedHash;
51384
+ status.specStaleCurrentHash = drift.currentHash;
51385
+ } else if (plan && plan._specStale) {
51386
+ status.specStale = true;
51387
+ status.specStaleReason = plan._specStaleReason;
51388
+ }
51440
51389
  return enrichWithLeanTurbo(status, directory);
51441
51390
  }
51442
51391
  function enrichWithLeanTurbo(status, directory) {
51443
51392
  const turboMode = hasActiveTurboMode();
51444
- const leanActive = _internals24.hasActiveLeanTurbo();
51393
+ const leanActive = _internals26.hasActiveLeanTurbo();
51445
51394
  let turboStrategy = "off";
51446
51395
  if (leanActive) {
51447
51396
  turboStrategy = "lean";
@@ -51460,7 +51409,7 @@ function enrichWithLeanTurbo(status, directory) {
51460
51409
  }
51461
51410
  }
51462
51411
  if (leanSessionID) {
51463
- const runState = _internals24.loadLeanTurboRunState(directory, leanSessionID);
51412
+ const runState = _internals26.loadLeanTurboRunState(directory, leanSessionID);
51464
51413
  if (runState) {
51465
51414
  status.leanTurboPhase = runState.phase;
51466
51415
  status.leanMaxParallelCoders = runState.maxParallelCoders;
@@ -51492,7 +51441,7 @@ function enrichWithLeanTurbo(status, directory) {
51492
51441
  }
51493
51442
  }
51494
51443
  }
51495
- status.fullAutoActive = _internals24.hasActiveFullAuto();
51444
+ status.fullAutoActive = _internals26.hasActiveFullAuto();
51496
51445
  return status;
51497
51446
  }
51498
51447
  function formatStatusMarkdown(status) {
@@ -51503,6 +51452,12 @@ function formatStatusMarkdown(status) {
51503
51452
  `**Tasks**: ${status.completedTasks}/${status.totalTasks} complete`,
51504
51453
  `**Agents**: ${status.agentCount} registered`
51505
51454
  ];
51455
+ if (status.specStale) {
51456
+ const reason = status.specStaleReason ?? "spec.md changed since plan saved";
51457
+ const stored = status.specStaleStoredHash ?? "unknown";
51458
+ const current = status.specStaleCurrentHash ?? "(spec.md missing)";
51459
+ lines.push("", `**Spec drift detected**: ${reason} (stored: ${stored}, current: ${current})`, "Run `/swarm clarify` to update the spec or `/swarm acknowledge-spec-drift` to dismiss.");
51460
+ }
51506
51461
  if (status.turboStrategy && status.turboStrategy !== "off") {
51507
51462
  lines.push("");
51508
51463
  if (status.turboStrategy === "lean") {
@@ -51552,11 +51507,23 @@ function formatStatusMarkdown(status) {
51552
51507
  async function handleStatusCommand(directory, agents) {
51553
51508
  const statusData = await getStatusData(directory, agents);
51554
51509
  if (!statusData.hasPlan) {
51510
+ if (statusData.specStale) {
51511
+ const reason = statusData.specStaleReason ?? "spec.md changed since plan saved";
51512
+ const stored = statusData.specStaleStoredHash ?? "unknown";
51513
+ const current = statusData.specStaleCurrentHash ?? "(spec.md missing)";
51514
+ return [
51515
+ "No active swarm plan found.",
51516
+ "",
51517
+ `**Spec drift detected**: ${reason} (stored: ${stored}, current: ${current})`,
51518
+ "Run `/swarm clarify` to update the spec or `/swarm acknowledge-spec-drift` to dismiss."
51519
+ ].join(`
51520
+ `);
51521
+ }
51555
51522
  return "No active swarm plan found.";
51556
51523
  }
51557
51524
  return formatStatusMarkdown(statusData);
51558
51525
  }
51559
- var _internals24;
51526
+ var _internals26;
51560
51527
  var init_status_service = __esm(() => {
51561
51528
  init_extractors();
51562
51529
  init_utils2();
@@ -51565,7 +51532,7 @@ var init_status_service = __esm(() => {
51565
51532
  init_state3();
51566
51533
  init_compaction_service();
51567
51534
  init_context_budget_service();
51568
- _internals24 = {
51535
+ _internals26 = {
51569
51536
  loadLeanTurboRunState,
51570
51537
  hasActiveLeanTurbo,
51571
51538
  hasActiveFullAuto
@@ -51656,7 +51623,7 @@ async function handleTurboCommand(directory, args, sessionID) {
51656
51623
  if (arg0 === "on") {
51657
51624
  let strategy = "standard";
51658
51625
  try {
51659
- const { config: config3 } = _internals25.loadPluginConfigWithMeta(directory);
51626
+ const { config: config3 } = _internals27.loadPluginConfigWithMeta(directory);
51660
51627
  if (config3.turbo?.strategy === "lean") {
51661
51628
  strategy = "lean";
51662
51629
  }
@@ -51711,7 +51678,7 @@ function enableLeanTurbo(session, directory, sessionID) {
51711
51678
  let maxParallelCoders = 4;
51712
51679
  let conflictPolicy = "serialize";
51713
51680
  try {
51714
- const { config: config3 } = _internals25.loadPluginConfigWithMeta(directory);
51681
+ const { config: config3 } = _internals27.loadPluginConfigWithMeta(directory);
51715
51682
  const leanConfig = config3.turbo?.lean;
51716
51683
  if (leanConfig) {
51717
51684
  maxParallelCoders = leanConfig.max_parallel_coders ?? 4;
@@ -51781,13 +51748,13 @@ function buildStatusMessage(session, directory, sessionID) {
51781
51748
  ].join(`
51782
51749
  `);
51783
51750
  }
51784
- var _internals25;
51751
+ var _internals27;
51785
51752
  var init_turbo = __esm(() => {
51786
51753
  init_config();
51787
51754
  init_state();
51788
51755
  init_state3();
51789
51756
  init_logger();
51790
- _internals25 = {
51757
+ _internals27 = {
51791
51758
  loadPluginConfigWithMeta
51792
51759
  };
51793
51760
  });
@@ -51853,6 +51820,270 @@ var init_write_retro2 = __esm(() => {
51853
51820
  init_write_retro();
51854
51821
  });
51855
51822
 
51823
+ // src/commands/command-dispatch.ts
51824
+ import fs28 from "fs";
51825
+ import path47 from "path";
51826
+ function normalizeSwarmCommandInput(command, argumentText) {
51827
+ if (command !== "swarm" && !command.startsWith("swarm-")) {
51828
+ return { isSwarmCommand: false, tokens: [] };
51829
+ }
51830
+ if (command === "swarm") {
51831
+ return {
51832
+ isSwarmCommand: true,
51833
+ tokens: argumentText.trim().split(/\s+/).filter(Boolean)
51834
+ };
51835
+ }
51836
+ const subcommand = command.slice("swarm-".length);
51837
+ const extraArgs = argumentText.trim().split(/\s+/).filter(Boolean);
51838
+ return {
51839
+ isSwarmCommand: true,
51840
+ tokens: [subcommand, ...extraArgs].filter(Boolean)
51841
+ };
51842
+ }
51843
+ function canonicalCommandKey(resolved) {
51844
+ return resolved.entry.aliasOf ?? resolved.key;
51845
+ }
51846
+ function formatCommandNotFound(tokens) {
51847
+ const attemptedCommand = tokens[0] || "";
51848
+ const MAX_DISPLAY = 100;
51849
+ const displayCommand = attemptedCommand.length > MAX_DISPLAY ? `${attemptedCommand.slice(0, MAX_DISPLAY)}...` : attemptedCommand;
51850
+ const similar = _internals28.findSimilarCommands(attemptedCommand);
51851
+ const header = `Command \`/swarm ${displayCommand}\` not found.`;
51852
+ const suggestions = similar.length > 0 ? `Did you mean:
51853
+ ${similar.map((cmd) => ` - /swarm ${cmd}`).join(`
51854
+ `)}` : "";
51855
+ const footer = "Run `/swarm help` for all commands.";
51856
+ return [header, suggestions, footer].filter(Boolean).join(`
51857
+
51858
+ `);
51859
+ }
51860
+ function maybeMarkFirstRun(directory) {
51861
+ const sentinelPath = path47.join(directory, ".swarm", ".first-run-complete");
51862
+ try {
51863
+ const swarmDir = path47.join(directory, ".swarm");
51864
+ fs28.mkdirSync(swarmDir, { recursive: true });
51865
+ fs28.writeFileSync(sentinelPath, `first-run-complete: ${new Date().toISOString()}
51866
+ `, { flag: "wx" });
51867
+ return true;
51868
+ } catch {
51869
+ return false;
51870
+ }
51871
+ }
51872
+ function prependWelcome(text) {
51873
+ const welcomeMessage = `Welcome to OpenCode Swarm!
51874
+ ` + `
51875
+ ` + `Run \`/swarm help\` to see all available commands, or \`/swarm config\` to review your configuration.
51876
+ `;
51877
+ return welcomeMessage + text;
51878
+ }
51879
+ async function executeSwarmCommand(args) {
51880
+ const {
51881
+ directory,
51882
+ agents,
51883
+ sessionID,
51884
+ tokens,
51885
+ includeWelcome = false,
51886
+ buildHelpText,
51887
+ policy
51888
+ } = args;
51889
+ let text;
51890
+ const resolved = resolveCommand(tokens);
51891
+ if (!resolved) {
51892
+ text = tokens.length === 0 && buildHelpText ? buildHelpText() : formatCommandNotFound(tokens);
51893
+ } else {
51894
+ const policyResult = policy?.(resolved) ?? { allowed: true };
51895
+ if (!policyResult.allowed) {
51896
+ text = policyResult.message;
51897
+ } else {
51898
+ try {
51899
+ text = await resolved.entry.handler({
51900
+ directory,
51901
+ args: resolved.remainingArgs,
51902
+ sessionID,
51903
+ agents
51904
+ });
51905
+ } catch (_err) {
51906
+ const cmdName = tokens[0] || "unknown";
51907
+ const errMsg = _err instanceof Error ? _err.message : String(_err);
51908
+ text = `Error executing /swarm ${cmdName}: ${errMsg}`;
51909
+ }
51910
+ if (resolved.warning) {
51911
+ text = `${resolved.warning}
51912
+
51913
+ ${text}`;
51914
+ }
51915
+ }
51916
+ }
51917
+ if (includeWelcome && maybeMarkFirstRun(directory)) {
51918
+ text = prependWelcome(text);
51919
+ }
51920
+ return {
51921
+ text,
51922
+ resolved: resolved ?? undefined,
51923
+ canonicalKey: resolved ? canonicalCommandKey(resolved) : undefined
51924
+ };
51925
+ }
51926
+ var init_command_dispatch = __esm(() => {
51927
+ init_registry();
51928
+ });
51929
+
51930
+ // src/commands/tool-policy.ts
51931
+ function classifySwarmCommandToolUse(resolved) {
51932
+ const canonicalKey = canonicalCommandKey(resolved);
51933
+ const args = resolved.remainingArgs;
51934
+ if (!SWARM_COMMAND_TOOL_ALLOWLIST.has(canonicalKey)) {
51935
+ return {
51936
+ allowed: false,
51937
+ message: `/swarm ${canonicalKey} is not available through the chat tool yet.
51938
+
51939
+ ` + `Use the canonical CLI path for now: \`bunx opencode-swarm run ${canonicalKey}\`.
51940
+ ` + `Commands with state changes, auto-heal behavior, or subprocesses need confirmation gates before chat-tool support.`
51941
+ };
51942
+ }
51943
+ if (canonicalKey === "config doctor" && args.some((arg) => arg === "--fix" || arg === "-f")) {
51944
+ return {
51945
+ allowed: false,
51946
+ message: "/swarm config doctor --fix is not available through swarm_command. Run the CLI command directly when you intend to modify config files."
51947
+ };
51948
+ }
51949
+ if (NO_ARGS.has(canonicalKey) && args.length > 0) {
51950
+ return {
51951
+ allowed: false,
51952
+ message: `/swarm ${canonicalKey} does not accept arguments through swarm_command.`
51953
+ };
51954
+ }
51955
+ if (canonicalKey === "knowledge") {
51956
+ if (args.length === 0)
51957
+ return { allowed: true };
51958
+ if (args.length === 1 && args[0] === "list")
51959
+ return { allowed: true };
51960
+ return {
51961
+ allowed: false,
51962
+ message: "Only `/swarm knowledge` and `/swarm knowledge list` are available through swarm_command. Knowledge migrate/quarantine/restore are intentionally excluded."
51963
+ };
51964
+ }
51965
+ if (canonicalKey === "retrieve") {
51966
+ if (args.length !== 1 || !SUMMARY_ID_PATTERN.test(args[0])) {
51967
+ return {
51968
+ allowed: false,
51969
+ message: "Usage through swarm_command: `/swarm retrieve <summary-id>` with a single summary ID such as S1."
51970
+ };
51971
+ }
51972
+ }
51973
+ if (canonicalKey === "benchmark") {
51974
+ const allowedFlags = new Set(["--cumulative", "--ci-gate"]);
51975
+ const invalid = args.filter((arg) => !allowedFlags.has(arg));
51976
+ if (invalid.length > 0) {
51977
+ return {
51978
+ allowed: false,
51979
+ message: "Only `--cumulative` and `--ci-gate` are supported for `/swarm benchmark` through swarm_command."
51980
+ };
51981
+ }
51982
+ }
51983
+ if (canonicalKey === "show-plan") {
51984
+ if (args.length > 1 || args[0] && !/^\d+$/.test(args[0])) {
51985
+ return {
51986
+ allowed: false,
51987
+ message: "Usage through swarm_command: `/swarm show-plan` or `/swarm show-plan <phase-number>`."
51988
+ };
51989
+ }
51990
+ }
51991
+ if (canonicalKey === "evidence") {
51992
+ if (args.length > 1 || args[0] && !TASK_ID_PATTERN.test(args[0])) {
51993
+ return {
51994
+ allowed: false,
51995
+ message: "Usage through swarm_command: `/swarm evidence` or `/swarm evidence <task-id>`."
51996
+ };
51997
+ }
51998
+ }
51999
+ if (canonicalKey === "help" && args.length > 2) {
52000
+ return {
52001
+ allowed: false,
52002
+ message: "Usage through swarm_command: `/swarm help` or `/swarm help <command>`."
52003
+ };
52004
+ }
52005
+ return { allowed: true };
52006
+ }
52007
+ function classifySwarmCommandChatFallbackUse(resolved) {
52008
+ const canonicalKey = canonicalCommandKey(resolved);
52009
+ const args = resolved.remainingArgs;
52010
+ if (canonicalKey === "config doctor" && args.some((arg) => arg === "--fix" || arg === "-f")) {
52011
+ return {
52012
+ allowed: false,
52013
+ message: "/swarm config doctor --fix is not available through chat fallback because it can modify configuration files. Run the CLI command directly when you intend to apply fixes."
52014
+ };
52015
+ }
52016
+ if (canonicalKey === "knowledge migrate" || canonicalKey === "knowledge quarantine" || canonicalKey === "knowledge restore") {
52017
+ return {
52018
+ allowed: false,
52019
+ message: `/swarm ${canonicalKey} is not available through chat fallback because it mutates .swarm knowledge state. ` + "Run the CLI command directly after confirming the intended state change."
52020
+ };
52021
+ }
52022
+ return { allowed: true };
52023
+ }
52024
+ var SWARM_COMMAND_TOOL_COMMANDS, SWARM_COMMAND_TOOL_ALLOWLIST, NO_ARGS, SUMMARY_ID_PATTERN, TASK_ID_PATTERN;
52025
+ var init_tool_policy = __esm(() => {
52026
+ init_command_dispatch();
52027
+ SWARM_COMMAND_TOOL_COMMANDS = [
52028
+ "agents",
52029
+ "config",
52030
+ "config doctor",
52031
+ "config-doctor",
52032
+ "doctor",
52033
+ "doctor tools",
52034
+ "status",
52035
+ "show-plan",
52036
+ "plan",
52037
+ "help",
52038
+ "history",
52039
+ "evidence",
52040
+ "evidence summary",
52041
+ "evidence-summary",
52042
+ "retrieve",
52043
+ "diagnose",
52044
+ "preflight",
52045
+ "benchmark",
52046
+ "knowledge",
52047
+ "sync-plan",
52048
+ "export",
52049
+ "list-agents"
52050
+ ];
52051
+ SWARM_COMMAND_TOOL_ALLOWLIST = new Set([
52052
+ "agents",
52053
+ "config",
52054
+ "config doctor",
52055
+ "doctor tools",
52056
+ "status",
52057
+ "show-plan",
52058
+ "help",
52059
+ "history",
52060
+ "evidence",
52061
+ "evidence summary",
52062
+ "retrieve",
52063
+ "diagnose",
52064
+ "preflight",
52065
+ "benchmark",
52066
+ "knowledge",
52067
+ "sync-plan",
52068
+ "export"
52069
+ ]);
52070
+ NO_ARGS = new Set([
52071
+ "agents",
52072
+ "config",
52073
+ "config doctor",
52074
+ "doctor tools",
52075
+ "status",
52076
+ "history",
52077
+ "evidence summary",
52078
+ "diagnose",
52079
+ "preflight",
52080
+ "sync-plan",
52081
+ "export"
52082
+ ]);
52083
+ SUMMARY_ID_PATTERN = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
52084
+ TASK_ID_PATTERN = /^[A-Za-z0-9_.:-]{1,64}$/;
52085
+ });
52086
+
51856
52087
  // src/commands/command-names.ts
51857
52088
  var COMMAND_NAMES, COMMAND_NAME_SET;
51858
52089
  var init_command_names = __esm(() => {
@@ -51865,6 +52096,7 @@ var init_command_names = __esm(() => {
51865
52096
  var exports_commands = {};
51866
52097
  __export(exports_commands, {
51867
52098
  resolveCommand: () => resolveCommand,
52099
+ normalizeSwarmCommandInput: () => normalizeSwarmCommandInput,
51868
52100
  handleWriteRetroCommand: () => handleWriteRetroCommand,
51869
52101
  handleTurboCommand: () => handleTurboCommand,
51870
52102
  handleSyncPlanCommand: () => handleSyncPlanCommand,
@@ -51906,18 +52138,27 @@ __export(exports_commands, {
51906
52138
  handleAnalyzeCommand: () => handleAnalyzeCommand,
51907
52139
  handleAgentsCommand: () => handleAgentsCommand,
51908
52140
  handleAcknowledgeSpecDriftCommand: () => handleAcknowledgeSpecDriftCommand,
52141
+ formatCommandNotFound: () => formatCommandNotFound,
52142
+ executeSwarmCommand: () => executeSwarmCommand,
51909
52143
  createSwarmCommandHandler: () => createSwarmCommandHandler,
52144
+ classifySwarmCommandToolUse: () => classifySwarmCommandToolUse,
52145
+ classifySwarmCommandChatFallbackUse: () => classifySwarmCommandChatFallbackUse,
51910
52146
  buildHelpText: () => buildHelpText,
52147
+ agentHasSwarmCommandTool: () => agentHasSwarmCommandTool,
51911
52148
  VALID_COMMANDS: () => VALID_COMMANDS,
51912
- LLM_MEDIATION_WARNING: () => LLM_MEDIATION_WARNING,
52149
+ SWARM_COMMAND_TOOL_COMMANDS: () => SWARM_COMMAND_TOOL_COMMANDS,
52150
+ SWARM_COMMAND_TOOL_ALLOWLIST: () => SWARM_COMMAND_TOOL_ALLOWLIST,
51913
52151
  COMMAND_REGISTRY: () => COMMAND_REGISTRY,
51914
52152
  COMMAND_NAME_SET: () => COMMAND_NAME_SET,
51915
52153
  COMMAND_NAMES: () => COMMAND_NAMES
51916
52154
  });
51917
- import fs28 from "fs";
51918
- import path46 from "path";
51919
52155
  function buildHelpText() {
51920
- const lines = ["## Swarm Commands", "", LLM_MEDIATION_WARNING, ""];
52156
+ const lines = [
52157
+ "## Swarm Commands",
52158
+ "",
52159
+ "**Chat routing note**: supported read-only `/swarm` commands are routed through the `swarm_command` tool when the active agent has that tool. Unsupported or state-changing commands remain chat-mediated; use `bunx opencode-swarm run <subcommand>` when you need canonical output.",
52160
+ ""
52161
+ ];
51921
52162
  const CATEGORIES = [
51922
52163
  "core",
51923
52164
  "agent",
@@ -52012,92 +52253,127 @@ function buildHelpText() {
52012
52253
  return lines.join(`
52013
52254
  `);
52014
52255
  }
52015
- function createSwarmCommandHandler(directory, agents, client) {
52256
+ function createSwarmCommandHandler(directory, agents, options = {}) {
52016
52257
  return async (input, output) => {
52017
- if (input.command !== "swarm" && !input.command.startsWith("swarm-")) {
52258
+ const normalized = normalizeSwarmCommandInput(input.command, input.arguments);
52259
+ if (!normalized.isSwarmCommand) {
52018
52260
  return;
52019
52261
  }
52020
- let isFirstRun = false;
52021
- const sentinelPath = path46.join(directory, ".swarm", ".first-run-complete");
52022
- try {
52023
- const swarmDir = path46.join(directory, ".swarm");
52024
- fs28.mkdirSync(swarmDir, { recursive: true });
52025
- fs28.writeFileSync(sentinelPath, `first-run-complete: ${new Date().toISOString()}
52026
- `, { flag: "wx" });
52027
- isFirstRun = true;
52028
- } catch (_err) {}
52029
- let tokens;
52030
- if (input.command === "swarm") {
52031
- tokens = input.arguments.trim().split(/\s+/).filter(Boolean);
52032
- } else {
52033
- const subcommand = input.command.slice("swarm-".length);
52034
- const extraArgs = input.arguments.trim().split(/\s+/).filter(Boolean);
52035
- tokens = [subcommand, ...extraArgs];
52036
- }
52037
- let text;
52038
- const resolved = resolveCommand(tokens);
52039
- if (!resolved) {
52040
- if (tokens.length === 0) {
52041
- text = buildHelpText();
52042
- } else {
52043
- const attemptedCommand = tokens[0] || "";
52044
- const MAX_DISPLAY = 100;
52045
- const displayCommand = attemptedCommand.length > MAX_DISPLAY ? `${attemptedCommand.slice(0, MAX_DISPLAY)}...` : attemptedCommand;
52046
- const similar = _internals26.findSimilarCommands(attemptedCommand);
52047
- const header = `Command \`/swarm ${displayCommand}\` not found.`;
52048
- const suggestions = similar.length > 0 ? `Did you mean:
52049
- ${similar.map((cmd) => ` \u2022 /swarm ${cmd}`).join(`
52050
- `)}` : "";
52051
- const footer = "Run `/swarm help` for all commands.";
52052
- text = [header, suggestions, footer].filter(Boolean).join(`
52053
-
52054
- `);
52055
- }
52056
- } else {
52057
- try {
52058
- text = await resolved.entry.handler({
52059
- directory,
52060
- args: resolved.remainingArgs,
52061
- sessionID: input.sessionID,
52062
- agents,
52063
- client
52064
- });
52065
- } catch (_err) {
52066
- const cmdName = tokens[0] || "unknown";
52067
- const errMsg = _err instanceof Error ? _err.message : String(_err);
52068
- text = `Error executing /swarm ${cmdName}: ${errMsg}`;
52069
- }
52070
- if (resolved.warning) {
52071
- text = `${resolved.warning}
52072
-
52073
- ${text}`;
52074
- }
52075
- }
52076
- if (isFirstRun) {
52077
- const welcomeMessage = `Welcome to OpenCode Swarm! \uD83D\uDC1D
52078
- ` + `
52079
- ` + `Start here: run \`/swarm diagnose\`, then \`/swarm agents\` to confirm the plugin loaded and see the exact models in use.
52080
- ` + `If a model is unavailable, edit \`.opencode/opencode-swarm.json\` or \`~/.config/opencode/opencode-swarm.json\` and run \`/swarm config doctor\`.
52081
- ` + `Useful next steps: \`/swarm brainstorm <task>\` for guided planning, \`/swarm full-auto on\` for autonomous runs after enabling it in config, and \`/swarm council <question>\` after enabling council.general.
52082
-
52083
- `;
52084
- text = welcomeMessage + text;
52085
- }
52086
52262
  output.parts.splice(0, output.parts.length, {
52087
52263
  type: "text",
52088
- text
52264
+ text: await buildSwarmCommandPrompt({
52265
+ directory,
52266
+ agents,
52267
+ sessionID: input.sessionID,
52268
+ tokens: normalized.tokens,
52269
+ activeAgentName: options.getActiveAgentName?.(input.sessionID),
52270
+ registeredAgents: options.registeredAgents
52271
+ })
52089
52272
  });
52273
+ return;
52090
52274
  };
52091
52275
  }
52092
- var LLM_MEDIATION_WARNING;
52276
+ async function buildSwarmCommandPrompt(args) {
52277
+ const {
52278
+ directory,
52279
+ agents,
52280
+ sessionID,
52281
+ tokens,
52282
+ activeAgentName,
52283
+ registeredAgents
52284
+ } = args;
52285
+ const resolved = _internals28.resolveCommand(tokens);
52286
+ if (!resolved) {
52287
+ if (tokens.length === 0) {
52288
+ return buildHelpText();
52289
+ }
52290
+ return formatCommandNotFound(tokens);
52291
+ }
52292
+ const typedResolved = resolved;
52293
+ const canonicalKey = canonicalCommandKey(typedResolved);
52294
+ const policy = classifySwarmCommandToolUse(typedResolved);
52295
+ const isV1ToolCommand = SWARM_COMMAND_TOOL_ALLOWLIST.has(canonicalKey);
52296
+ const canUseTool = agentHasSwarmCommandTool(activeAgentName, agents, registeredAgents);
52297
+ if (canUseTool && policy.allowed && isV1ToolCommand) {
52298
+ return routeToSwarmCommandTool({
52299
+ command: canonicalKey,
52300
+ args: resolved.remainingArgs,
52301
+ original: `/swarm ${tokens.join(" ")}`.trim()
52302
+ });
52303
+ }
52304
+ if (canUseTool && isV1ToolCommand && !policy.allowed) {
52305
+ return [
52306
+ `The user typed \`/swarm ${tokens.join(" ")}\`.`,
52307
+ policy.message,
52308
+ "Do not invent command output. Explain the limitation and recommend the canonical CLI path above."
52309
+ ].join(`
52310
+ `);
52311
+ }
52312
+ const chatFallbackPolicy = classifySwarmCommandChatFallbackUse(typedResolved);
52313
+ if (!chatFallbackPolicy.allowed) {
52314
+ return [
52315
+ `The user typed \`/swarm ${tokens.join(" ")}\`.`,
52316
+ chatFallbackPolicy.message,
52317
+ "Do not execute this command through chat and do not invent command output."
52318
+ ].join(`
52319
+ `);
52320
+ }
52321
+ const result = await executeSwarmCommand({
52322
+ directory,
52323
+ agents,
52324
+ sessionID,
52325
+ tokens
52326
+ });
52327
+ return formatCanonicalPromptFallback({
52328
+ original: `/swarm ${tokens.join(" ")}`.trim(),
52329
+ text: result.text
52330
+ });
52331
+ }
52332
+ function agentHasSwarmCommandTool(activeAgentName, agents, registeredAgents) {
52333
+ const name = activeAgentName ?? ORCHESTRATOR_NAME;
52334
+ const registeredTools = registeredAgents?.[name]?.tools;
52335
+ if (registeredTools) {
52336
+ return registeredTools.swarm_command === true;
52337
+ }
52338
+ const explicitTools = agents[name]?.config?.tools;
52339
+ if (explicitTools) {
52340
+ return explicitTools.swarm_command === true;
52341
+ }
52342
+ const baseName = stripKnownSwarmPrefix(name);
52343
+ return AGENT_TOOL_MAP[baseName]?.includes("swarm_command") === true;
52344
+ }
52345
+ function formatCanonicalPromptFallback(args) {
52346
+ return [
52347
+ `The user typed \`${args.original}\`.`,
52348
+ "Canonical opencode-swarm command output follows.",
52349
+ "Show this output verbatim and add no extra swarm state.",
52350
+ "",
52351
+ args.text
52352
+ ].join(`
52353
+ `);
52354
+ }
52355
+ function routeToSwarmCommandTool(args) {
52356
+ return [
52357
+ `The user typed \`${args.original}\`.`,
52358
+ "Call the `swarm_command` tool exactly once with:",
52359
+ JSON.stringify({ command: args.command, args: args.args }, null, 2),
52360
+ "After the tool returns, show the tool output verbatim and add no extra swarm state."
52361
+ ].join(`
52362
+ `);
52363
+ }
52093
52364
  var init_commands = __esm(() => {
52365
+ init_constants();
52366
+ init_schema();
52367
+ init_command_dispatch();
52094
52368
  init_registry();
52369
+ init_tool_policy();
52095
52370
  init_acknowledge_spec_drift();
52096
52371
  init_agents();
52097
52372
  init_archive();
52098
52373
  init_benchmark();
52099
52374
  init_checkpoint2();
52100
52375
  init_close();
52376
+ init_command_dispatch();
52101
52377
  init_command_names();
52102
52378
  init_config2();
52103
52379
  init_council();
@@ -52125,10 +52401,9 @@ var init_commands = __esm(() => {
52125
52401
  init_simulate();
52126
52402
  init_status();
52127
52403
  init_sync_plan();
52404
+ init_tool_policy();
52128
52405
  init_turbo();
52129
52406
  init_write_retro2();
52130
- LLM_MEDIATION_WARNING = "> \u26A0\uFE0F Chat-typed `/swarm` is LLM-mediated in current OpenCode (see anomalyco/opencode#9306).\n" + `> The text below is the canonical handler output, but the model may rephrase it before display.
52131
- ` + "> For deterministic output, run `bunx opencode-swarm run <subcommand>` from a terminal.";
52132
52407
  });
52133
52408
 
52134
52409
  // src/commands/registry.ts
@@ -52158,7 +52433,7 @@ function findSimilarCommands(query) {
52158
52433
  }
52159
52434
  const scored = VALID_COMMANDS.map((cmd) => {
52160
52435
  const cmdLower = cmd.toLowerCase();
52161
- const fullScore = _internals26.levenshteinDistance(q, cmdLower);
52436
+ const fullScore = _internals28.levenshteinDistance(q, cmdLower);
52162
52437
  let tokenScore = Infinity;
52163
52438
  if (cmd.includes(" ") || cmd.includes("-")) {
52164
52439
  const qTokens = q.split(/[\s-]+/);
@@ -52171,7 +52446,7 @@ function findSimilarCommands(query) {
52171
52446
  for (const ct of cmdTokens) {
52172
52447
  if (ct.length === 0)
52173
52448
  continue;
52174
- const dist = _internals26.levenshteinDistance(qt, ct);
52449
+ const dist = _internals28.levenshteinDistance(qt, ct);
52175
52450
  if (dist < minDist)
52176
52451
  minDist = dist;
52177
52452
  }
@@ -52181,7 +52456,7 @@ function findSimilarCommands(query) {
52181
52456
  }
52182
52457
  const dashStrippedQ = q.replace(/-/g, "");
52183
52458
  const dashStrippedCmd = cmdLower.replace(/-/g, "");
52184
- const dashScore = _internals26.levenshteinDistance(dashStrippedQ, dashStrippedCmd);
52459
+ const dashScore = _internals28.levenshteinDistance(dashStrippedQ, dashStrippedCmd);
52185
52460
  const score = Math.min(fullScore, tokenScore, dashScore);
52186
52461
  return { cmd, score };
52187
52462
  });
@@ -52213,11 +52488,11 @@ async function handleHelpCommand(ctx) {
52213
52488
  return buildHelpText2();
52214
52489
  }
52215
52490
  const tokens = targetCommand.split(/\s+/);
52216
- const resolved = _internals26.resolveCommand(tokens);
52491
+ const resolved = _internals28.resolveCommand(tokens);
52217
52492
  if (resolved) {
52218
- return _internals26.buildDetailedHelp(resolved.key, resolved.entry);
52493
+ return _internals28.buildDetailedHelp(resolved.key, resolved.entry);
52219
52494
  }
52220
- const similar = _internals26.findSimilarCommands(targetCommand);
52495
+ const similar = _internals28.findSimilarCommands(targetCommand);
52221
52496
  const { buildHelpText: fullHelp } = await Promise.resolve().then(() => (init_commands(), exports_commands));
52222
52497
  if (similar.length > 0) {
52223
52498
  return `Command '/swarm ${targetCommand}' not found.
@@ -52253,24 +52528,24 @@ function validateAliases() {
52253
52528
  }
52254
52529
  aliasTargets.get(target).push(name);
52255
52530
  const visited = new Set;
52256
- const path47 = [];
52531
+ const path48 = [];
52257
52532
  let current = target;
52258
52533
  while (current) {
52259
52534
  const currentEntry = COMMAND_REGISTRY[current];
52260
52535
  if (!currentEntry)
52261
52536
  break;
52262
52537
  if (visited.has(current)) {
52263
- const cycleStart = path47.indexOf(current);
52538
+ const cycleStart = path48.indexOf(current);
52264
52539
  const fullChain = [
52265
52540
  name,
52266
- ...path47.slice(0, cycleStart > 0 ? cycleStart : path47.length),
52541
+ ...path48.slice(0, cycleStart > 0 ? cycleStart : path48.length),
52267
52542
  current
52268
52543
  ].join(" \u2192 ");
52269
52544
  errors5.push(`Circular alias detected: ${fullChain}`);
52270
52545
  break;
52271
52546
  }
52272
52547
  visited.add(current);
52273
- path47.push(current);
52548
+ path48.push(current);
52274
52549
  current = currentEntry.aliasOf || "";
52275
52550
  }
52276
52551
  }
@@ -52311,7 +52586,7 @@ function resolveCommand(tokens) {
52311
52586
  }
52312
52587
  return null;
52313
52588
  }
52314
- var COMMAND_REGISTRY, VALID_COMMANDS, _internals26, validation;
52589
+ var COMMAND_REGISTRY, VALID_COMMANDS, _internals28, validation;
52315
52590
  var init_registry = __esm(() => {
52316
52591
  init_acknowledge_spec_drift();
52317
52592
  init_agents();
@@ -52381,7 +52656,7 @@ var init_registry = __esm(() => {
52381
52656
  clashesWithNativeCcCommand: "/agents"
52382
52657
  },
52383
52658
  help: {
52384
- handler: (ctx) => _internals26.handleHelpCommand(ctx),
52659
+ handler: (ctx) => _internals28.handleHelpCommand(ctx),
52385
52660
  description: "Show help for swarm commands",
52386
52661
  category: "core",
52387
52662
  args: "[command]",
@@ -52400,13 +52675,13 @@ var init_registry = __esm(() => {
52400
52675
  clashesWithNativeCcCommand: "/config"
52401
52676
  },
52402
52677
  "config doctor": {
52403
- handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args, { client: ctx.client }),
52678
+ handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args),
52404
52679
  description: "Run config doctor checks",
52405
52680
  subcommandOf: "config",
52406
52681
  category: "diagnostics"
52407
52682
  },
52408
52683
  "config-doctor": {
52409
- handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args, { client: ctx.client }),
52684
+ handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args),
52410
52685
  description: "Run config doctor checks",
52411
52686
  subcommandOf: "config",
52412
52687
  category: "diagnostics",
@@ -52481,7 +52756,7 @@ var init_registry = __esm(() => {
52481
52756
  deprecated: true
52482
52757
  },
52483
52758
  doctor: {
52484
- handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args, { client: ctx.client }),
52759
+ handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args),
52485
52760
  description: "Run config doctor checks",
52486
52761
  category: "diagnostics",
52487
52762
  aliasOf: "config doctor",
@@ -52753,7 +53028,7 @@ Subcommands:
52753
53028
  }
52754
53029
  };
52755
53030
  VALID_COMMANDS = Object.keys(COMMAND_REGISTRY);
52756
- _internals26 = {
53031
+ _internals28 = {
52757
53032
  handleHelpCommand,
52758
53033
  validateAliases,
52759
53034
  resolveCommand,
@@ -52761,7 +53036,7 @@ Subcommands:
52761
53036
  findSimilarCommands,
52762
53037
  buildDetailedHelp
52763
53038
  };
52764
- validation = _internals26.validateAliases();
53039
+ validation = _internals28.validateAliases();
52765
53040
  if (!validation.valid) {
52766
53041
  throw new Error(`COMMAND_REGISTRY alias validation failed:
52767
53042
  ${validation.errors.join(`
@@ -52781,53 +53056,53 @@ init_cache_paths();
52781
53056
  init_constants();
52782
53057
  import * as fs29 from "fs";
52783
53058
  import * as os7 from "os";
52784
- import * as path47 from "path";
53059
+ import * as path48 from "path";
52785
53060
  var { version: version4 } = package_default;
52786
53061
  var CONFIG_DIR = getPluginConfigDir();
52787
- var OPENCODE_CONFIG_PATH = path47.join(CONFIG_DIR, "opencode.json");
52788
- var PLUGIN_CONFIG_PATH = path47.join(CONFIG_DIR, "opencode-swarm.json");
52789
- var PROMPTS_DIR = path47.join(CONFIG_DIR, "opencode-swarm");
53062
+ var OPENCODE_CONFIG_PATH = path48.join(CONFIG_DIR, "opencode.json");
53063
+ var PLUGIN_CONFIG_PATH = path48.join(CONFIG_DIR, "opencode-swarm.json");
53064
+ var PROMPTS_DIR = path48.join(CONFIG_DIR, "opencode-swarm");
52790
53065
  var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
52791
53066
  var OPENCODE_PLUGIN_LOCK_FILE_PATHS = getPluginLockFilePaths();
52792
53067
  function isSafeCachePath(p) {
52793
- const resolved = path47.resolve(p);
52794
- const home = path47.resolve(os7.homedir());
53068
+ const resolved = path48.resolve(p);
53069
+ const home = path48.resolve(os7.homedir());
52795
53070
  if (resolved === "/" || resolved === home || resolved.length <= home.length) {
52796
53071
  return false;
52797
53072
  }
52798
- const segments = resolved.split(path47.sep).filter((s) => s.length > 0);
53073
+ const segments = resolved.split(path48.sep).filter((s) => s.length > 0);
52799
53074
  if (segments.length < 4) {
52800
53075
  return false;
52801
53076
  }
52802
- const leaf = path47.basename(resolved);
53077
+ const leaf = path48.basename(resolved);
52803
53078
  if (leaf !== "opencode-swarm@latest" && leaf !== "opencode-swarm") {
52804
53079
  return false;
52805
53080
  }
52806
- const parent = path47.basename(path47.dirname(resolved));
53081
+ const parent = path48.basename(path48.dirname(resolved));
52807
53082
  if (parent !== "packages" && parent !== "node_modules") {
52808
53083
  return false;
52809
53084
  }
52810
- const grandparent = path47.basename(path47.dirname(path47.dirname(resolved)));
53085
+ const grandparent = path48.basename(path48.dirname(path48.dirname(resolved)));
52811
53086
  if (grandparent !== "opencode") {
52812
53087
  return false;
52813
53088
  }
52814
53089
  return true;
52815
53090
  }
52816
53091
  function isSafeLockFilePath(p) {
52817
- const resolved = path47.resolve(p);
52818
- const home = path47.resolve(os7.homedir());
53092
+ const resolved = path48.resolve(p);
53093
+ const home = path48.resolve(os7.homedir());
52819
53094
  if (resolved === "/" || resolved === home || resolved.length <= home.length) {
52820
53095
  return false;
52821
53096
  }
52822
- const segments = resolved.split(path47.sep).filter((s) => s.length > 0);
53097
+ const segments = resolved.split(path48.sep).filter((s) => s.length > 0);
52823
53098
  if (segments.length < 4) {
52824
53099
  return false;
52825
53100
  }
52826
- const leaf = path47.basename(resolved);
53101
+ const leaf = path48.basename(resolved);
52827
53102
  if (leaf !== "bun.lock" && leaf !== "bun.lockb" && leaf !== "package-lock.json") {
52828
53103
  return false;
52829
53104
  }
52830
- const parent = path47.basename(path47.dirname(resolved));
53105
+ const parent = path48.basename(path48.dirname(resolved));
52831
53106
  if (parent !== "opencode") {
52832
53107
  return false;
52833
53108
  }
@@ -52853,8 +53128,8 @@ function saveJson(filepath, data) {
52853
53128
  }
52854
53129
  function writeProjectConfigIfMissing(cwd) {
52855
53130
  try {
52856
- const opencodeDir = path47.join(cwd, ".opencode");
52857
- const projectConfigPath = path47.join(opencodeDir, "opencode-swarm.json");
53131
+ const opencodeDir = path48.join(cwd, ".opencode");
53132
+ const projectConfigPath = path48.join(opencodeDir, "opencode-swarm.json");
52858
53133
  if (fs29.existsSync(projectConfigPath)) {
52859
53134
  return;
52860
53135
  }
@@ -52871,7 +53146,7 @@ async function install() {
52871
53146
  `);
52872
53147
  ensureDir(CONFIG_DIR);
52873
53148
  ensureDir(PROMPTS_DIR);
52874
- const LEGACY_CONFIG_PATH = path47.join(CONFIG_DIR, "config.json");
53149
+ const LEGACY_CONFIG_PATH = path48.join(CONFIG_DIR, "config.json");
52875
53150
  let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
52876
53151
  if (!opencodeConfig) {
52877
53152
  const legacyConfig = loadJson(LEGACY_CONFIG_PATH);