opencode-swarm 6.53.2 → 6.53.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -31389,7 +31389,7 @@ var init_ledger = __esm(() => {
31389
31389
  });
31390
31390
 
31391
31391
  // src/plan/manager.ts
31392
- import { existsSync as existsSync7, renameSync as renameSync4, unlinkSync } from "fs";
31392
+ import { copyFileSync, existsSync as existsSync7, renameSync as renameSync4, unlinkSync } from "fs";
31393
31393
  import * as path11 from "path";
31394
31394
  async function loadPlanJsonOnly(directory) {
31395
31395
  const planJsonContent = await readSwarmFileAsync(directory, "plan.json");
@@ -31647,18 +31647,61 @@ async function savePlan(directory, plan, options) {
31647
31647
  if (existingEvents.length > 0 && existingEvents[0].plan_id !== planId) {
31648
31648
  const swarmDir2 = path11.resolve(directory, ".swarm");
31649
31649
  const oldLedgerPath = path11.join(swarmDir2, "plan-ledger.jsonl");
31650
- const archivePath = path11.join(swarmDir2, `plan-ledger.archived-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
31650
+ const oldLedgerBackupPath = path11.join(swarmDir2, `plan-ledger.backup-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
31651
+ let backupExists = false;
31651
31652
  if (existsSync7(oldLedgerPath)) {
31652
- renameSync4(oldLedgerPath, archivePath);
31653
- warn(`[savePlan] Ledger identity mismatch (was "${existingEvents[0].plan_id}", now "${planId}") \u2014 archived old ledger to ${archivePath} and reinitializing.`);
31653
+ try {
31654
+ renameSync4(oldLedgerPath, oldLedgerBackupPath);
31655
+ backupExists = true;
31656
+ } catch (renameErr) {
31657
+ throw new Error(`[savePlan] Cannot reinitialize ledger: could not move old ledger aside (rename failed: ${renameErr instanceof Error ? renameErr.message : String(renameErr)}). The existing ledger has plan_id="${existingEvents[0].plan_id}" which does not match the current plan="${planId}". To proceed, close any programs that may have the ledger file open, or run /swarm reset-session to clear the ledger.`);
31658
+ }
31654
31659
  }
31655
- try {
31656
- await initLedger(directory, planId, planHashForInit);
31657
- } catch (initErr) {
31658
- if (!(initErr instanceof Error && initErr.message.includes("already initialized"))) {
31659
- throw initErr;
31660
+ let initSucceeded = false;
31661
+ if (backupExists) {
31662
+ try {
31663
+ await initLedger(directory, planId, planHashForInit);
31664
+ initSucceeded = true;
31665
+ } catch (initErr) {
31666
+ const errorMessage = String(initErr);
31667
+ if (errorMessage.includes("already initialized")) {
31668
+ try {
31669
+ if (existsSync7(oldLedgerBackupPath))
31670
+ unlinkSync(oldLedgerBackupPath);
31671
+ } catch {}
31672
+ } else {
31673
+ if (existsSync7(oldLedgerBackupPath)) {
31674
+ try {
31675
+ renameSync4(oldLedgerBackupPath, oldLedgerPath);
31676
+ } catch {
31677
+ copyFileSync(oldLedgerBackupPath, oldLedgerPath);
31678
+ try {
31679
+ unlinkSync(oldLedgerBackupPath);
31680
+ } catch {}
31681
+ }
31682
+ }
31683
+ throw initErr;
31684
+ }
31660
31685
  }
31661
31686
  }
31687
+ if (initSucceeded && backupExists) {
31688
+ const archivePath = path11.join(swarmDir2, `plan-ledger.archived-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
31689
+ try {
31690
+ renameSync4(oldLedgerBackupPath, archivePath);
31691
+ warn(`[savePlan] Ledger identity mismatch (was "${existingEvents[0].plan_id}", now "${planId}") \u2014 archived old ledger to ${archivePath} and reinitializing.`);
31692
+ } catch (renameErr) {
31693
+ warn(`[savePlan] Could not archive old ledger (rename failed: ${renameErr instanceof Error ? renameErr.message : String(renameErr)}). Old ledger may still exist at ${oldLedgerBackupPath}.`);
31694
+ try {
31695
+ if (existsSync7(oldLedgerBackupPath))
31696
+ unlinkSync(oldLedgerBackupPath);
31697
+ } catch {}
31698
+ }
31699
+ } else if (!initSucceeded && backupExists) {
31700
+ try {
31701
+ if (existsSync7(oldLedgerBackupPath))
31702
+ unlinkSync(oldLedgerBackupPath);
31703
+ } catch {}
31704
+ }
31662
31705
  }
31663
31706
  }
31664
31707
  const currentHash = computeCurrentPlanHash(directory);
@@ -32167,13 +32210,13 @@ __export(exports_co_change_analyzer, {
32167
32210
  co_change_analyzer: () => co_change_analyzer,
32168
32211
  buildCoChangeMatrix: () => buildCoChangeMatrix
32169
32212
  });
32170
- import * as child_process2 from "child_process";
32213
+ import * as child_process3 from "child_process";
32171
32214
  import { randomUUID as randomUUID2 } from "crypto";
32172
32215
  import { readdir as readdir2, readFile as readFile4, stat } from "fs/promises";
32173
32216
  import * as path17 from "path";
32174
32217
  import { promisify } from "util";
32175
32218
  function getExecFileAsync() {
32176
- return promisify(child_process2.execFile);
32219
+ return promisify(child_process3.execFile);
32177
32220
  }
32178
32221
  async function parseGitLog(directory, maxCommits) {
32179
32222
  const commitMap = new Map;
@@ -43290,6 +43333,52 @@ import { execFileSync } from "child_process";
43290
43333
  import { promises as fs9 } from "fs";
43291
43334
  import path14 from "path";
43292
43335
 
43336
+ // src/git/branch.ts
43337
+ init_logger();
43338
+ import * as child_process2 from "child_process";
43339
+ var GIT_TIMEOUT_MS2 = 30000;
43340
+ function gitExec2(args2, cwd) {
43341
+ const result = child_process2.spawnSync("git", args2, {
43342
+ cwd,
43343
+ encoding: "utf-8",
43344
+ timeout: GIT_TIMEOUT_MS2,
43345
+ stdio: ["pipe", "pipe", "pipe"]
43346
+ });
43347
+ if (result.status !== 0) {
43348
+ throw new Error(result.stderr || `git exited with ${result.status}`);
43349
+ }
43350
+ return result.stdout;
43351
+ }
43352
+ function isGitRepo2(cwd) {
43353
+ try {
43354
+ gitExec2(["rev-parse", "--git-dir"], cwd);
43355
+ return true;
43356
+ } catch {
43357
+ return false;
43358
+ }
43359
+ }
43360
+ function getCurrentBranch(cwd) {
43361
+ const output = gitExec2(["rev-parse", "--abbrev-ref", "HEAD"], cwd);
43362
+ return output.trim();
43363
+ }
43364
+ function getDefaultBaseBranch(cwd) {
43365
+ try {
43366
+ gitExec2(["rev-parse", "--verify", "origin/main"], cwd);
43367
+ return "origin/main";
43368
+ } catch {
43369
+ try {
43370
+ gitExec2(["rev-parse", "--verify", "origin/master"], cwd);
43371
+ return "origin/master";
43372
+ } catch {
43373
+ return "origin/main";
43374
+ }
43375
+ }
43376
+ }
43377
+ function hasUncommittedChanges(cwd) {
43378
+ const status = gitExec2(["status", "--porcelain"], cwd);
43379
+ return status.trim().length > 0;
43380
+ }
43381
+
43293
43382
  // src/hooks/knowledge-reader.ts
43294
43383
  init_knowledge_store();
43295
43384
  import { existsSync as existsSync5 } from "fs";
@@ -44681,8 +44770,28 @@ var write_retro = createSwarmTool({
44681
44770
  });
44682
44771
 
44683
44772
  // src/commands/close.ts
44773
+ var ARCHIVE_ARTIFACTS = [
44774
+ "plan.json",
44775
+ "plan.md",
44776
+ "context.md",
44777
+ "events.jsonl",
44778
+ "handoff.md",
44779
+ "handoff-prompt.md",
44780
+ "handoff-consumed.md",
44781
+ "escalation-report.md",
44782
+ "close-lessons.md"
44783
+ ];
44784
+ var ACTIVE_STATE_TO_CLEAN = [
44785
+ "plan.md",
44786
+ "events.jsonl",
44787
+ "handoff.md",
44788
+ "handoff-prompt.md",
44789
+ "handoff-consumed.md",
44790
+ "escalation-report.md"
44791
+ ];
44684
44792
  async function handleCloseCommand(directory, args2) {
44685
44793
  const planPath = validateSwarmPath(directory, "plan.json");
44794
+ const swarmDir = path14.join(directory, ".swarm");
44686
44795
  let planExists = false;
44687
44796
  let planData = {
44688
44797
  title: path14.basename(directory) || "Ad-hoc session",
@@ -44696,13 +44805,14 @@ async function handleCloseCommand(directory, args2) {
44696
44805
  if (error93?.code !== "ENOENT") {
44697
44806
  return `\u274C Failed to read plan.json: ${error93 instanceof Error ? error93.message : String(error93)}`;
44698
44807
  }
44699
- const swarmDirExists = await fs9.access(path14.join(directory, ".swarm")).then(() => true).catch(() => false);
44808
+ const swarmDirExists = await fs9.access(swarmDir).then(() => true).catch(() => false);
44700
44809
  if (!swarmDirExists) {
44701
44810
  return `\u274C No .swarm/ directory found in ${directory}. Run /swarm close from the project root, or run /swarm plan first.`;
44702
44811
  }
44703
44812
  }
44704
44813
  const phases = planData.phases ?? [];
44705
44814
  const inProgressPhases = phases.filter((p) => p.status === "in_progress");
44815
+ const isForced = args2.includes("--force");
44706
44816
  let planAlreadyDone = false;
44707
44817
  if (planExists) {
44708
44818
  planAlreadyDone = phases.length > 0 && phases.every((p) => p.status === "complete" || p.status === "completed" || p.status === "blocked" || p.status === "closed");
@@ -44719,7 +44829,7 @@ async function handleCloseCommand(directory, args2) {
44719
44829
  try {
44720
44830
  retroResult = await executeWriteRetro({
44721
44831
  phase: phase.id,
44722
- summary: "Phase closed via /swarm close",
44832
+ summary: isForced ? `Phase force-closed via /swarm close --force` : `Phase closed via /swarm close`,
44723
44833
  task_count: Math.max(1, (phase.tasks ?? []).length),
44724
44834
  task_complexity: "simple",
44725
44835
  total_tool_calls: 0,
@@ -44747,7 +44857,7 @@ async function handleCloseCommand(directory, args2) {
44747
44857
  }
44748
44858
  }
44749
44859
  }
44750
- const lessonsFilePath = path14.join(directory, ".swarm", "close-lessons.md");
44860
+ const lessonsFilePath = path14.join(swarmDir, "close-lessons.md");
44751
44861
  let explicitLessons = [];
44752
44862
  try {
44753
44863
  const lessonsText = await fs9.readFile(lessonsFilePath, "utf-8");
@@ -44787,13 +44897,83 @@ async function handleCloseCommand(directory, args2) {
44787
44897
  console.warn("[close-command] Failed to write plan.json:", error93);
44788
44898
  }
44789
44899
  }
44900
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
44901
+ const archiveDir = path14.join(swarmDir, "archive", `swarm-${timestamp}`);
44902
+ let archiveResult = "";
44903
+ let archivedFileCount = 0;
44904
+ const archivedActiveStateFiles = new Set;
44905
+ try {
44906
+ await fs9.mkdir(archiveDir, { recursive: true });
44907
+ for (const artifact of ARCHIVE_ARTIFACTS) {
44908
+ const srcPath = path14.join(swarmDir, artifact);
44909
+ const destPath = path14.join(archiveDir, artifact);
44910
+ try {
44911
+ await fs9.copyFile(srcPath, destPath);
44912
+ archivedFileCount++;
44913
+ if (ACTIVE_STATE_TO_CLEAN.includes(artifact)) {
44914
+ archivedActiveStateFiles.add(artifact);
44915
+ }
44916
+ } catch {}
44917
+ }
44918
+ const evidenceDir = path14.join(swarmDir, "evidence");
44919
+ const archiveEvidenceDir = path14.join(archiveDir, "evidence");
44920
+ try {
44921
+ const evidenceEntries = await fs9.readdir(evidenceDir);
44922
+ if (evidenceEntries.length > 0) {
44923
+ await fs9.mkdir(archiveEvidenceDir, { recursive: true });
44924
+ for (const entry of evidenceEntries) {
44925
+ const srcEntry = path14.join(evidenceDir, entry);
44926
+ const destEntry = path14.join(archiveEvidenceDir, entry);
44927
+ try {
44928
+ const stat = await fs9.stat(srcEntry);
44929
+ if (stat.isDirectory()) {
44930
+ await fs9.mkdir(destEntry, { recursive: true });
44931
+ const subEntries = await fs9.readdir(srcEntry);
44932
+ for (const sub of subEntries) {
44933
+ await fs9.copyFile(path14.join(srcEntry, sub), path14.join(destEntry, sub)).catch(() => {});
44934
+ }
44935
+ } else {
44936
+ await fs9.copyFile(srcEntry, destEntry);
44937
+ }
44938
+ archivedFileCount++;
44939
+ } catch {}
44940
+ }
44941
+ }
44942
+ } catch {}
44943
+ const sessionStatePath = path14.join(swarmDir, "session", "state.json");
44944
+ try {
44945
+ const archiveSessionDir = path14.join(archiveDir, "session");
44946
+ await fs9.mkdir(archiveSessionDir, { recursive: true });
44947
+ await fs9.copyFile(sessionStatePath, path14.join(archiveSessionDir, "state.json"));
44948
+ archivedFileCount++;
44949
+ } catch {}
44950
+ archiveResult = `Archived ${archivedFileCount} artifact(s) to .swarm/archive/swarm-${timestamp}/`;
44951
+ } catch (archiveError) {
44952
+ warnings.push(`Archive creation failed: ${archiveError instanceof Error ? archiveError.message : String(archiveError)}`);
44953
+ archiveResult = "Archive creation failed (see warnings)";
44954
+ }
44790
44955
  try {
44791
44956
  await archiveEvidence(directory, 30, 10);
44792
44957
  } catch (error93) {
44793
44958
  console.warn("[close-command] archiveEvidence error:", error93);
44794
44959
  }
44795
- const swarmDir = path14.join(directory, ".swarm");
44796
44960
  let configBackupsRemoved = 0;
44961
+ const cleanedFiles = [];
44962
+ if (archivedActiveStateFiles.size > 0) {
44963
+ for (const artifact of ACTIVE_STATE_TO_CLEAN) {
44964
+ if (!archivedActiveStateFiles.has(artifact)) {
44965
+ warnings.push(`Preserved ${artifact} because it was not successfully archived.`);
44966
+ continue;
44967
+ }
44968
+ const filePath = path14.join(swarmDir, artifact);
44969
+ try {
44970
+ await fs9.unlink(filePath);
44971
+ cleanedFiles.push(artifact);
44972
+ } catch {}
44973
+ }
44974
+ } else {
44975
+ warnings.push("Skipped active-state cleanup because no active-state files were archived. Files preserved to prevent data loss.");
44976
+ }
44797
44977
  try {
44798
44978
  const swarmFiles = await fs9.readdir(swarmDir);
44799
44979
  const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
@@ -44804,13 +44984,14 @@ async function handleCloseCommand(directory, args2) {
44804
44984
  } catch {}
44805
44985
  }
44806
44986
  } catch {}
44807
- const contextPath = path14.join(directory, ".swarm", "context.md");
44987
+ const contextPath = path14.join(swarmDir, "context.md");
44808
44988
  const contextContent = [
44809
44989
  "# Context",
44810
44990
  "",
44811
44991
  "## Status",
44812
44992
  `Session closed after: ${projectName}`,
44813
44993
  `Closed: ${new Date().toISOString()}`,
44994
+ `Finalization: ${isForced ? "forced" : planAlreadyDone ? "plan-already-done" : "normal"}`,
44814
44995
  "No active plan. Next session starts fresh.",
44815
44996
  ""
44816
44997
  ].join(`
@@ -44823,46 +45004,112 @@ async function handleCloseCommand(directory, args2) {
44823
45004
  const pruneBranches = args2.includes("--prune-branches");
44824
45005
  const prunedBranches = [];
44825
45006
  const pruneErrors = [];
44826
- if (pruneBranches) {
45007
+ let gitAlignResult = "";
45008
+ const isGit = isGitRepo2(directory);
45009
+ if (isGit) {
44827
45010
  try {
44828
- const branchOutput = execFileSync("git", ["branch", "-vv"], {
44829
- cwd: directory,
44830
- encoding: "utf-8",
44831
- stdio: ["pipe", "pipe", "pipe"]
44832
- });
44833
- const goneBranches = branchOutput.split(`
44834
- `).filter((line) => line.includes(": gone]")).map((line) => line.trim().replace(/^[*+]\s+/, "").split(/\s+/)[0]).filter(Boolean);
44835
- for (const branch of goneBranches) {
44836
- try {
44837
- execFileSync("git", ["branch", "-d", branch], {
44838
- cwd: directory,
44839
- encoding: "utf-8",
44840
- stdio: ["pipe", "pipe", "pipe"]
44841
- });
44842
- prunedBranches.push(branch);
44843
- } catch {
44844
- pruneErrors.push(branch);
45011
+ const currentBranch = getCurrentBranch(directory);
45012
+ if (currentBranch === "HEAD") {
45013
+ gitAlignResult = "Skipped git alignment: detached HEAD state";
45014
+ warnings.push("Repo is in detached HEAD state. Checkout a branch before starting a new swarm.");
45015
+ } else if (hasUncommittedChanges(directory)) {
45016
+ gitAlignResult = "Skipped git alignment: uncommitted changes in worktree";
45017
+ warnings.push("Uncommitted changes detected. Commit or stash before aligning to main.");
45018
+ } else {
45019
+ const baseBranch = getDefaultBaseBranch(directory);
45020
+ const localBase = baseBranch.replace(/^origin\//, "");
45021
+ if (currentBranch === localBase) {
45022
+ try {
45023
+ execFileSync("git", ["fetch", "origin", localBase], {
45024
+ cwd: directory,
45025
+ encoding: "utf-8",
45026
+ timeout: 30000,
45027
+ stdio: ["pipe", "pipe", "pipe"]
45028
+ });
45029
+ const mergeBase = execFileSync("git", ["merge-base", "HEAD", baseBranch], {
45030
+ cwd: directory,
45031
+ encoding: "utf-8",
45032
+ timeout: 1e4,
45033
+ stdio: ["pipe", "pipe", "pipe"]
45034
+ }).trim();
45035
+ const headSha = execFileSync("git", ["rev-parse", "HEAD"], {
45036
+ cwd: directory,
45037
+ encoding: "utf-8",
45038
+ timeout: 1e4,
45039
+ stdio: ["pipe", "pipe", "pipe"]
45040
+ }).trim();
45041
+ if (mergeBase === headSha) {
45042
+ execFileSync("git", ["merge", "--ff-only", baseBranch], {
45043
+ cwd: directory,
45044
+ encoding: "utf-8",
45045
+ timeout: 30000,
45046
+ stdio: ["pipe", "pipe", "pipe"]
45047
+ });
45048
+ gitAlignResult = `Aligned to ${baseBranch} (fast-forward)`;
45049
+ } else {
45050
+ gitAlignResult = `On ${localBase} but cannot fast-forward to ${baseBranch} (diverged)`;
45051
+ warnings.push(`Local ${localBase} has diverged from ${baseBranch}. Manual merge/rebase needed.`);
45052
+ }
45053
+ } catch (fetchErr) {
45054
+ gitAlignResult = `Fetch from origin/${localBase} failed \u2014 remote may be unavailable`;
45055
+ warnings.push(`Git fetch failed: ${fetchErr instanceof Error ? fetchErr.message : String(fetchErr)}`);
45056
+ }
45057
+ } else {
45058
+ gitAlignResult = `On branch ${currentBranch}. Switch to ${localBase} manually when ready for a new swarm.`;
44845
45059
  }
44846
45060
  }
44847
- } catch {}
45061
+ } catch (gitError) {
45062
+ gitAlignResult = `Git alignment error: ${gitError instanceof Error ? gitError.message : String(gitError)}`;
45063
+ }
45064
+ if (pruneBranches) {
45065
+ try {
45066
+ const branchOutput = execFileSync("git", ["branch", "-vv"], {
45067
+ cwd: directory,
45068
+ encoding: "utf-8",
45069
+ stdio: ["pipe", "pipe", "pipe"]
45070
+ });
45071
+ const goneBranches = branchOutput.split(`
45072
+ `).filter((line) => line.includes(": gone]")).map((line) => line.trim().replace(/^[*+]\s+/, "").split(/\s+/)[0]).filter(Boolean);
45073
+ for (const branch of goneBranches) {
45074
+ try {
45075
+ execFileSync("git", ["branch", "-d", branch], {
45076
+ cwd: directory,
45077
+ encoding: "utf-8",
45078
+ stdio: ["pipe", "pipe", "pipe"]
45079
+ });
45080
+ prunedBranches.push(branch);
45081
+ } catch {
45082
+ pruneErrors.push(branch);
45083
+ }
45084
+ }
45085
+ } catch {}
45086
+ }
45087
+ } else {
45088
+ gitAlignResult = "Not a git repository \u2014 skipped git alignment";
44848
45089
  }
44849
45090
  const closeSummaryPath = validateSwarmPath(directory, "close-summary.md");
45091
+ const finalizationType = isForced ? "Forced closure" : planAlreadyDone ? "Plan already terminal \u2014 cleanup only" : "Normal finalization";
44850
45092
  const actionsPerformed = [
44851
45093
  ...!planAlreadyDone && inProgressPhases.length > 0 ? ["- Wrote retrospectives for in-progress phases"] : [],
44852
- "- Archived evidence bundles",
45094
+ `- ${archiveResult}`,
45095
+ ...cleanedFiles.length > 0 ? [
45096
+ `- Cleaned ${cleanedFiles.length} active-state file(s): ${cleanedFiles.join(", ")}`
45097
+ ] : [],
44853
45098
  "- Reset context.md for next session",
44854
45099
  ...configBackupsRemoved > 0 ? [`- Removed ${configBackupsRemoved} stale config backup file(s)`] : [],
44855
45100
  ...prunedBranches.length > 0 ? [
44856
45101
  `- Pruned ${prunedBranches.length} stale local git branch(es): ${prunedBranches.join(", ")}`
44857
45102
  ] : [],
44858
45103
  "- Cleared agent sessions and delegation chains",
44859
- ...planExists && !planAlreadyDone ? ["- Set non-completed phases/tasks to closed status"] : []
45104
+ ...planExists && !planAlreadyDone ? ["- Set non-completed phases/tasks to closed status"] : [],
45105
+ ...gitAlignResult ? [`- Git: ${gitAlignResult}`] : []
44860
45106
  ];
44861
45107
  const summaryContent = [
44862
45108
  "# Swarm Close Summary",
44863
45109
  "",
44864
45110
  `**Project:** ${projectName}`,
44865
45111
  `**Closed:** ${new Date().toISOString()}`,
45112
+ `**Finalization:** ${finalizationType}`,
44866
45113
  "",
44867
45114
  `## Phases Closed: ${closedPhases.length}`,
44868
45115
  !planExists ? "_No plan \u2014 ad-hoc session_" : closedPhases.length > 0 ? closedPhases.map((id) => `- Phase ${id}`).join(`
@@ -44873,7 +45120,9 @@ async function handleCloseCommand(directory, args2) {
44873
45120
  `) : "_No incomplete tasks_",
44874
45121
  "",
44875
45122
  "## Actions Performed",
44876
- ...actionsPerformed
45123
+ ...actionsPerformed,
45124
+ "",
45125
+ ...warnings.length > 0 ? ["## Warnings", ...warnings.map((w) => `- ${w}`), ""] : []
44877
45126
  ].join(`
44878
45127
  `);
44879
45128
  try {
@@ -44892,11 +45141,21 @@ async function handleCloseCommand(directory, args2) {
44892
45141
  if (pruneErrors.length > 0) {
44893
45142
  warnings.push(`Could not prune ${pruneErrors.length} branch(es) (unmerged or checked out): ${pruneErrors.join(", ")}`);
44894
45143
  }
44895
- const warningMsg = warnings.length > 0 ? ` Warnings: ${warnings.join("; ")}.` : "";
45144
+ const warningMsg = warnings.length > 0 ? `
45145
+
45146
+ **Warnings:**
45147
+ ${warnings.map((w) => `- ${w}`).join(`
45148
+ `)}` : "";
44896
45149
  if (planAlreadyDone) {
44897
- return `\u2705 Session closed. Plan was already in a terminal state \u2014 cleanup steps applied.${warningMsg}`;
45150
+ return `\u2705 Session finalized. Plan was already in a terminal state \u2014 cleanup and archive applied.
45151
+
45152
+ **Archive:** ${archiveResult}
45153
+ **Git:** ${gitAlignResult}${warningMsg}`;
44898
45154
  }
44899
- return `\u2705 Swarm closed successfully. ${closedPhases.length} phase(s) closed, ${closedTasks.length} incomplete task(s) marked closed.${warningMsg}`;
45155
+ return `\u2705 Swarm finalized. ${closedPhases.length} phase(s) closed, ${closedTasks.length} incomplete task(s) marked closed.
45156
+
45157
+ **Archive:** ${archiveResult}
45158
+ **Git:** ${gitAlignResult}${warningMsg}`;
44900
45159
  }
44901
45160
 
44902
45161
  // src/commands/config.ts
@@ -46051,7 +46310,7 @@ init_loader();
46051
46310
  init_manager();
46052
46311
  init_utils2();
46053
46312
  init_manager2();
46054
- import * as child_process3 from "child_process";
46313
+ import * as child_process4 from "child_process";
46055
46314
  import { existsSync as existsSync8, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
46056
46315
  import path19 from "path";
46057
46316
  import { fileURLToPath } from "url";
@@ -46293,7 +46552,7 @@ async function checkGitRepository(directory) {
46293
46552
  detail: "Invalid directory \u2014 cannot check git status"
46294
46553
  };
46295
46554
  }
46296
- child_process3.execSync("git rev-parse --git-dir", {
46555
+ child_process4.execSync("git rev-parse --git-dir", {
46297
46556
  cwd: directory,
46298
46557
  stdio: "pipe"
46299
46558
  });
@@ -47177,7 +47436,7 @@ async function handleExportCommand(directory, _args) {
47177
47436
  init_state();
47178
47437
  async function handleFullAutoCommand(_directory, args2, sessionID) {
47179
47438
  if (!sessionID || sessionID.trim() === "") {
47180
- return "Error: No active session context. Full-Auto Mode requires an active session. Use /swarm full-auto from within an OpenCode session, or start a session first.";
47439
+ return "Error: No active session context. Full-Auto Mode requires an active session. Use /swarm-full-auto from within an OpenCode session, or start a session first.";
47181
47440
  }
47182
47441
  const session = getAgentSession(sessionID);
47183
47442
  if (!session) {
@@ -47185,16 +47444,15 @@ async function handleFullAutoCommand(_directory, args2, sessionID) {
47185
47444
  }
47186
47445
  const arg = args2[0]?.toLowerCase();
47187
47446
  let newFullAutoMode;
47188
- let feedback;
47189
47447
  if (arg === "on") {
47190
47448
  newFullAutoMode = true;
47191
- feedback = "Full-Auto Mode enabled";
47192
47449
  } else if (arg === "off") {
47193
47450
  newFullAutoMode = false;
47194
- feedback = "Full-Auto Mode disabled";
47195
47451
  } else {
47196
47452
  newFullAutoMode = !session.fullAutoMode;
47197
- feedback = newFullAutoMode ? "Full-Auto Mode enabled" : "Full-Auto Mode disabled";
47453
+ }
47454
+ if (newFullAutoMode && !swarmState.fullAutoEnabledInConfig) {
47455
+ return "Error: Full-Auto Mode cannot be enabled because full_auto.enabled is not set to true in the swarm plugin config. The autonomous oversight hook is inactive without config-level enablement. Set full_auto.enabled = true in your opencode-swarm config and restart.";
47198
47456
  }
47199
47457
  session.fullAutoMode = newFullAutoMode;
47200
47458
  if (!newFullAutoMode) {
@@ -47202,7 +47460,7 @@ async function handleFullAutoCommand(_directory, args2, sessionID) {
47202
47460
  session.fullAutoDeadlockCount = 0;
47203
47461
  session.fullAutoLastQuestionHash = null;
47204
47462
  }
47205
- return feedback;
47463
+ return newFullAutoMode ? "Full-Auto Mode enabled" : "Full-Auto Mode disabled";
47206
47464
  }
47207
47465
 
47208
47466
  // src/commands/handoff.ts
@@ -47510,6 +47768,64 @@ function formatHandoffMarkdown(data) {
47510
47768
  return lines.join(`
47511
47769
  `);
47512
47770
  }
47771
+ function formatContinuationPrompt(data) {
47772
+ const lines = [];
47773
+ lines.push("## Resume Swarm");
47774
+ lines.push("");
47775
+ if (data.currentPhase) {
47776
+ lines.push(`**Phase**: ${data.currentPhase}`);
47777
+ }
47778
+ if (data.currentTask) {
47779
+ lines.push(`**Current Task**: ${data.currentTask}`);
47780
+ }
47781
+ let nextTask;
47782
+ if (data.incompleteTasks.length > 0) {
47783
+ nextTask = data.incompleteTasks.find((t) => t !== data.currentTask);
47784
+ if (nextTask) {
47785
+ lines.push(`**Next Task**: ${nextTask}`);
47786
+ }
47787
+ }
47788
+ if (data.pendingQA) {
47789
+ lines.push("");
47790
+ lines.push(`**Pending QA Blocker**: ${data.pendingQA.taskId}`);
47791
+ if (data.pendingQA.lastFailure) {
47792
+ lines.push(` - Last failure: ${data.pendingQA.lastFailure}`);
47793
+ }
47794
+ }
47795
+ if (data.recentDecisions.length > 0) {
47796
+ const last3 = data.recentDecisions.slice(-3);
47797
+ lines.push("");
47798
+ lines.push("**Recent Decisions (do not revisit)**:");
47799
+ for (const decision of last3) {
47800
+ lines.push(`- ${decision}`);
47801
+ }
47802
+ }
47803
+ if (data.incompleteTasks.length > 2) {
47804
+ const remaining = data.incompleteTasks.filter((t) => t !== data.currentTask && t !== nextTask);
47805
+ if (remaining.length > 0) {
47806
+ lines.push("");
47807
+ lines.push(`**Remaining Tasks**: ${remaining.slice(0, 8).join(", ")}${remaining.length > 8 ? ` (+${remaining.length - 8} more)` : ""}`);
47808
+ }
47809
+ }
47810
+ lines.push("");
47811
+ lines.push("**To resume**:");
47812
+ lines.push("1. Read `.swarm/handoff.md` for full context");
47813
+ lines.push("2. Use `knowledge_recall` to recall relevant lessons before starting");
47814
+ if (data.pendingQA) {
47815
+ lines.push(`3. Resolve QA blocker on task ${data.pendingQA.taskId} before continuing`);
47816
+ } else if (data.currentTask) {
47817
+ lines.push(`3. Continue work on task ${data.currentTask}`);
47818
+ } else if (nextTask) {
47819
+ lines.push(`3. Begin work on task ${nextTask}`);
47820
+ } else {
47821
+ lines.push("3. Review the plan and pick up the next incomplete task");
47822
+ }
47823
+ lines.push("4. Do not re-implement completed tasks or revisit settled decisions");
47824
+ return `\`\`\`markdown
47825
+ ${lines.join(`
47826
+ `)}
47827
+ \`\`\``;
47828
+ }
47513
47829
 
47514
47830
  // src/commands/handoff.ts
47515
47831
  init_state();
@@ -47520,17 +47836,27 @@ async function handleHandoffCommand(directory, _args) {
47520
47836
  const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
47521
47837
  await Bun.write(tempPath, markdown);
47522
47838
  renameSync7(tempPath, resolvedPath);
47839
+ const continuationPrompt = formatContinuationPrompt(handoffData);
47840
+ const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
47841
+ const promptTempPath = `${promptPath}.tmp.${crypto4.randomUUID()}`;
47842
+ await Bun.write(promptTempPath, continuationPrompt);
47843
+ renameSync7(promptTempPath, promptPath);
47523
47844
  await writeSnapshot(directory, swarmState);
47524
47845
  await flushPendingSnapshot(directory);
47525
47846
  return `## Handoff Brief Written
47526
47847
 
47527
47848
  Brief written to \`.swarm/handoff.md\`.
47849
+ Continuation prompt written to \`.swarm/handoff-prompt.md\`.
47528
47850
 
47529
47851
  ${markdown}
47530
47852
 
47531
47853
  ---
47532
47854
 
47533
- **Next Step:** Start a new OpenCode session, switch to your target model, and send: \`continue the previous work\``;
47855
+ ## Continuation Prompt
47856
+
47857
+ Copy and paste the block below into your next session to resume cleanly:
47858
+
47859
+ ${continuationPrompt}`;
47534
47860
  }
47535
47861
 
47536
47862
  // src/services/history-service.ts
@@ -50089,6 +50415,11 @@ var COMMAND_REGISTRY = {
50089
50415
  description: "Run config doctor checks",
50090
50416
  subcommandOf: "config"
50091
50417
  },
50418
+ "config-doctor": {
50419
+ handler: (ctx) => handleDoctorCommand(ctx.directory, ctx.args),
50420
+ description: "Run config doctor checks",
50421
+ subcommandOf: "config"
50422
+ },
50092
50423
  "doctor tools": {
50093
50424
  handler: (ctx) => handleDoctorToolsCommand(ctx.directory, ctx.args),
50094
50425
  description: "Run tool registration coherence check"
@@ -50122,6 +50453,11 @@ var COMMAND_REGISTRY = {
50122
50453
  description: "Generate evidence summary with completion ratio and blockers",
50123
50454
  subcommandOf: "evidence"
50124
50455
  },
50456
+ "evidence-summary": {
50457
+ handler: (ctx) => handleEvidenceSummaryCommand(ctx.directory),
50458
+ description: "Generate evidence summary with completion ratio and blockers",
50459
+ subcommandOf: "evidence"
50460
+ },
50125
50461
  archive: {
50126
50462
  handler: (ctx) => handleArchiveCommand(ctx.directory, ctx.args),
50127
50463
  description: "Archive old evidence bundles [--dry-run]"
@@ -56151,12 +56487,23 @@ init_state();
56151
56487
  init_telemetry();
56152
56488
  init_utils2();
56153
56489
  var END_OF_SENTENCE_QUESTION_PATTERN = /\?\s*$/;
56154
- var ESCALATION_PATTERNS = [
56155
- /Ready for Phase (?:\d+|\[?N\+1\]?)\?/i,
56490
+ var PHASE_COMPLETION_PATTERNS = [
56491
+ /Ready for Phase (?:\d+|\[?N\+1\]?)\??/i,
56492
+ /phase.{0,20}(?:complete|finish|done|wrap)/i,
56493
+ /move(?:d?)?\s+(?:on\s+)?to\s+(?:the\s+)?(?:next\s+)?phase/i
56494
+ ];
56495
+ var QUESTION_ESCALATION_PATTERNS = [
56156
56496
  /escalat/i,
56157
56497
  /What would you like/i,
56158
56498
  /Should I proceed/i,
56159
- /Do you want/i
56499
+ /Do you want/i,
56500
+ /Shall I/i,
56501
+ /Would you like/i,
56502
+ /Can I proceed/i,
56503
+ /May I proceed/i,
56504
+ /Awaiting (?:your |)(?:approval|confirmation|input|decision|direction)/i,
56505
+ /Please (?:confirm|approve|advise|let me know)/i,
56506
+ /How (?:would you like|should I)/i
56160
56507
  ];
56161
56508
  var MID_SENTENCE_QUESTION_PATTERNS = [
56162
56509
  /\b(v\d+\?)/i,
@@ -56193,11 +56540,16 @@ function resolveOversightAgentName(architectAgentName) {
56193
56540
  return `${prefix}critic_oversight`;
56194
56541
  }
56195
56542
  function detectEscalation(text) {
56196
- for (const pattern of ESCALATION_PATTERNS) {
56543
+ for (const pattern of PHASE_COMPLETION_PATTERNS) {
56197
56544
  if (pattern.test(text)) {
56198
56545
  return "phase_completion";
56199
56546
  }
56200
56547
  }
56548
+ for (const pattern of QUESTION_ESCALATION_PATTERNS) {
56549
+ if (pattern.test(text)) {
56550
+ return "question";
56551
+ }
56552
+ }
56201
56553
  if (END_OF_SENTENCE_QUESTION_PATTERN.test(text)) {
56202
56554
  if (!isMidSentenceQuestion(text)) {
56203
56555
  return "question";
@@ -56339,7 +56691,7 @@ async function writeAutoOversightEvent(directory, architectOutput, criticVerdict
56339
56691
  }
56340
56692
  }
56341
56693
  }
56342
- function injectVerdictIntoMessages(messages, architectIndex, criticResult, _escalationType, oversightAgentName) {
56694
+ function injectVerdictIntoMessages(messages, architectIndex, criticResult, escalationType, oversightAgentName) {
56343
56695
  if (criticResult.escalationNeeded || criticResult.verdict === "ESCALATE_TO_HUMAN") {
56344
56696
  const verdictMessage2 = {
56345
56697
  info: {
@@ -56376,6 +56728,19 @@ ${criticResult.reasoning}`
56376
56728
  ]
56377
56729
  };
56378
56730
  messages.splice(architectIndex + 1, 0, verdictMessage2);
56731
+ const continuationMessage = {
56732
+ info: {
56733
+ role: "user",
56734
+ agent: oversightAgentName
56735
+ },
56736
+ parts: [
56737
+ {
56738
+ type: "text",
56739
+ text: "[FULL-AUTO CONTINUATION] The critic has answered your question. Incorporate the answer above and continue executing the current plan. Do not ask follow-up questions about this answer \u2014 proceed with implementation."
56740
+ }
56741
+ ]
56742
+ };
56743
+ messages.splice(architectIndex + 2, 0, continuationMessage);
56379
56744
  return;
56380
56745
  }
56381
56746
  const verdictEmoji = criticResult.verdict === "APPROVED" ? "\u2705" : criticResult.verdict === "NEEDS_REVISION" ? "\uD83D\uDD04" : criticResult.verdict === "REJECTED" ? "\u274C" : criticResult.verdict === "BLOCKED" ? "\uD83D\uDEAB" : "\uD83D\uDCAC";
@@ -56394,6 +56759,35 @@ Critic reasoning: ${criticResult.reasoning}`
56394
56759
  ]
56395
56760
  };
56396
56761
  messages.splice(architectIndex + 1, 0, verdictMessage);
56762
+ if (criticResult.verdict === "APPROVED" && escalationType === "phase_completion") {
56763
+ const continuationMessage = {
56764
+ info: {
56765
+ role: "user",
56766
+ agent: oversightAgentName
56767
+ },
56768
+ parts: [
56769
+ {
56770
+ type: "text",
56771
+ text: "[FULL-AUTO CONTINUATION] Phase approved by autonomous oversight. Call `phase_complete` now to finalize this phase, then proceed to the next phase in the plan. Do not wait for further human input."
56772
+ }
56773
+ ]
56774
+ };
56775
+ messages.splice(architectIndex + 2, 0, continuationMessage);
56776
+ } else if (criticResult.verdict === "APPROVED") {
56777
+ const continuationMessage = {
56778
+ info: {
56779
+ role: "user",
56780
+ agent: oversightAgentName
56781
+ },
56782
+ parts: [
56783
+ {
56784
+ type: "text",
56785
+ text: "[FULL-AUTO CONTINUATION] Approved by autonomous oversight. Continue executing the current task and plan. Do not wait for further human input."
56786
+ }
56787
+ ]
56788
+ };
56789
+ messages.splice(architectIndex + 2, 0, continuationMessage);
56790
+ }
56397
56791
  }
56398
56792
  async function dispatchCriticAndWriteEvent(directory, architectOutput, criticContext, criticModel, escalationType, interactionCount, deadlockCount, oversightAgentName) {
56399
56793
  const client = swarmState.opencodeClient;
@@ -57879,6 +58273,10 @@ function createSystemEnhancerHook(config3, directory) {
57879
58273
  fs35.unlinkSync(consumedPath);
57880
58274
  }
57881
58275
  fs35.renameSync(handoffPath, consumedPath);
58276
+ try {
58277
+ const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
58278
+ fs35.unlinkSync(promptPath);
58279
+ } catch {}
57882
58280
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
57883
58281
  The previous model's session ended. Here is your starting context:
57884
58282
 
@@ -58992,14 +59390,14 @@ import * as fs36 from "fs";
58992
59390
  import * as path47 from "path";
58993
59391
 
58994
59392
  // src/hooks/spawn-helper.ts
58995
- import * as child_process4 from "child_process";
59393
+ import * as child_process5 from "child_process";
58996
59394
  var WIN32_CMD_BINARIES = new Set(["npm", "npx", "pnpm", "yarn"]);
58997
59395
  function spawnAsync(command, cwd, timeoutMs) {
58998
59396
  return new Promise((resolve15) => {
58999
59397
  try {
59000
59398
  const [rawCmd, ...args2] = command;
59001
59399
  const cmd = process.platform === "win32" && WIN32_CMD_BINARIES.has(rawCmd) && !rawCmd.includes(".") ? `${rawCmd}.cmd` : rawCmd;
59002
- const proc = child_process4.spawn(cmd, args2, {
59400
+ const proc = child_process5.spawn(cmd, args2, {
59003
59401
  cwd,
59004
59402
  stdio: ["ignore", "pipe", "pipe"]
59005
59403
  });
@@ -60007,6 +60405,9 @@ async function rehydrateState(snapshot) {
60007
60405
  for (const field of TRANSIENT_SESSION_FIELDS) {
60008
60406
  session[field.name] = field.resetValue;
60009
60407
  }
60408
+ if (session.fullAutoMode && !swarmState.fullAutoEnabledInConfig) {
60409
+ session.fullAutoMode = false;
60410
+ }
60010
60411
  swarmState.agentSessions.set(sessionId, session);
60011
60412
  }
60012
60413
  }
@@ -62408,7 +62809,7 @@ var declare_scope = createSwarmTool({
62408
62809
  });
62409
62810
  // src/tools/diff.ts
62410
62811
  init_dist();
62411
- import * as child_process5 from "child_process";
62812
+ import * as child_process6 from "child_process";
62412
62813
 
62413
62814
  // src/diff/ast-diff.ts
62414
62815
  init_tree_sitter();
@@ -62776,13 +63177,13 @@ var diff = createSwarmTool({
62776
63177
  numstatArgs.push("--", ...typedArgs.paths);
62777
63178
  fullDiffArgs.push("--", ...typedArgs.paths);
62778
63179
  }
62779
- const numstatOutput = child_process5.execFileSync("git", numstatArgs, {
63180
+ const numstatOutput = child_process6.execFileSync("git", numstatArgs, {
62780
63181
  encoding: "utf-8",
62781
63182
  timeout: DIFF_TIMEOUT_MS,
62782
63183
  maxBuffer: MAX_BUFFER_BYTES,
62783
63184
  cwd: directory
62784
63185
  });
62785
- const fullDiffOutput = child_process5.execFileSync("git", fullDiffArgs, {
63186
+ const fullDiffOutput = child_process6.execFileSync("git", fullDiffArgs, {
62786
63187
  encoding: "utf-8",
62787
63188
  timeout: DIFF_TIMEOUT_MS,
62788
63189
  maxBuffer: MAX_BUFFER_BYTES,
@@ -62831,23 +63232,23 @@ var diff = createSwarmTool({
62831
63232
  let oldContent;
62832
63233
  let newContent;
62833
63234
  if (base === "staged") {
62834
- oldContent = child_process5.execFileSync("git", ["show", `HEAD:${file3.path}`], {
63235
+ oldContent = child_process6.execFileSync("git", ["show", `HEAD:${file3.path}`], {
62835
63236
  encoding: "utf-8",
62836
63237
  timeout: 5000,
62837
63238
  cwd: directory
62838
63239
  });
62839
- newContent = child_process5.execFileSync("git", ["show", `:${file3.path}`], {
63240
+ newContent = child_process6.execFileSync("git", ["show", `:${file3.path}`], {
62840
63241
  encoding: "utf-8",
62841
63242
  timeout: 5000,
62842
63243
  cwd: directory
62843
63244
  });
62844
63245
  } else if (base === "unstaged") {
62845
- oldContent = child_process5.execFileSync("git", ["show", `:${file3.path}`], {
63246
+ oldContent = child_process6.execFileSync("git", ["show", `:${file3.path}`], {
62846
63247
  encoding: "utf-8",
62847
63248
  timeout: 5000,
62848
63249
  cwd: directory
62849
63250
  });
62850
- newContent = child_process5.execFileSync("git", ["show", `HEAD:${file3.path}`], {
63251
+ newContent = child_process6.execFileSync("git", ["show", `HEAD:${file3.path}`], {
62851
63252
  encoding: "utf-8",
62852
63253
  timeout: 5000,
62853
63254
  cwd: directory
@@ -62856,12 +63257,12 @@ var diff = createSwarmTool({
62856
63257
  const pathModule = await import("path");
62857
63258
  newContent = fsModule.readFileSync(pathModule.join(directory, file3.path), "utf-8");
62858
63259
  } else {
62859
- oldContent = child_process5.execFileSync("git", ["show", `${base}:${file3.path}`], {
63260
+ oldContent = child_process6.execFileSync("git", ["show", `${base}:${file3.path}`], {
62860
63261
  encoding: "utf-8",
62861
63262
  timeout: 5000,
62862
63263
  cwd: directory
62863
63264
  });
62864
- newContent = child_process5.execFileSync("git", ["show", `HEAD:${file3.path}`], {
63265
+ newContent = child_process6.execFileSync("git", ["show", `HEAD:${file3.path}`], {
62865
63266
  encoding: "utf-8",
62866
63267
  timeout: 5000,
62867
63268
  cwd: directory
@@ -64972,7 +65373,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
64972
65373
  }
64973
65374
  } catch {}
64974
65375
  }
64975
- } catch (error93) {
65376
+ } catch (_error) {
64976
65377
  if (await ledgerExists(dir)) {
64977
65378
  try {
64978
65379
  const rebuilt = await replayFromLedger(dir);
@@ -67685,7 +68086,7 @@ function executeRulesSync(filePath, content, language) {
67685
68086
  }
67686
68087
 
67687
68088
  // src/sast/semgrep.ts
67688
- import * as child_process6 from "child_process";
68089
+ import * as child_process7 from "child_process";
67689
68090
  var semgrepAvailableCache = null;
67690
68091
  var DEFAULT_RULES_DIR = ".swarm/semgrep-rules";
67691
68092
  var DEFAULT_TIMEOUT_MS3 = 30000;
@@ -67694,7 +68095,7 @@ function isSemgrepAvailable() {
67694
68095
  return semgrepAvailableCache;
67695
68096
  }
67696
68097
  try {
67697
- child_process6.execFileSync("semgrep", ["--version"], {
68098
+ child_process7.execFileSync("semgrep", ["--version"], {
67698
68099
  encoding: "utf-8",
67699
68100
  stdio: "pipe"
67700
68101
  });
@@ -67753,7 +68154,7 @@ function mapSemgrepSeverity(severity) {
67753
68154
  }
67754
68155
  async function executeWithTimeout(command, args2, options) {
67755
68156
  return new Promise((resolve24) => {
67756
- const child = child_process6.spawn(command, args2, {
68157
+ const child = child_process7.spawn(command, args2, {
67757
68158
  shell: false,
67758
68159
  cwd: options.cwd
67759
68160
  });
@@ -72699,7 +73100,7 @@ var OpenCodeSwarm = async (ctx) => {
72699
73100
  ...opencodeConfig.command || {},
72700
73101
  swarm: {
72701
73102
  template: "/swarm $ARGUMENTS",
72702
- description: "Swarm management commands: /swarm [status|plan|agents|history|config|evidence|handoff|archive|diagnose|preflight|sync-plan|benchmark|export|reset|rollback|retrieve|clarify|analyze|specify|dark-matter|knowledge|curate|close]"
73103
+ description: "Swarm management commands: /swarm [status|plan|agents|history|config|evidence|handoff|archive|diagnose|preflight|sync-plan|benchmark|export|reset|rollback|retrieve|clarify|analyze|specify|dark-matter|knowledge|curate|turbo|full-auto|write-retro|reset-session|simulate|promote|checkpoint|close]"
72703
73104
  },
72704
73105
  "swarm-status": {
72705
73106
  template: "/swarm status",
@@ -72794,8 +73195,8 @@ var OpenCodeSwarm = async (ctx) => {
72794
73195
  description: "Use /swarm turbo to enable turbo mode for faster execution"
72795
73196
  },
72796
73197
  "swarm-full-auto": {
72797
- template: "/swarm full-auto $ARGUMENTS",
72798
- description: "Use /swarm full-auto to toggle Full-Auto Mode for the active session [on|off]"
73198
+ template: "/swarm-full-auto $ARGUMENTS",
73199
+ description: "Toggle Full-Auto Mode for the active session [on|off]"
72799
73200
  },
72800
73201
  "swarm-write-retro": {
72801
73202
  template: "/swarm write-retro $ARGUMENTS",