swarm-code 0.1.22 → 0.1.23

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/core/rlm.js CHANGED
@@ -171,6 +171,7 @@ export async function runRlmLoop(options) {
171
171
  const { context, query, model, repl, signal, onProgress, onSubQueryStart, onSubQuery, systemPrompt, threadHandler, mergeHandler, } = options;
172
172
  let totalSubQueries = 0;
173
173
  let iterationSubQueries = 0;
174
+ let mergedAlready = false;
174
175
  const llmQueryHandler = async (subContext, instruction) => {
175
176
  if (signal?.aborted)
176
177
  throw new Error("Aborted");
@@ -217,7 +218,10 @@ export async function runRlmLoop(options) {
217
218
  repl.setThreadHandler(threadHandler);
218
219
  }
219
220
  if (mergeHandler) {
220
- repl.setMergeHandler(mergeHandler);
221
+ repl.setMergeHandler(async () => {
222
+ mergedAlready = true;
223
+ return mergeHandler();
224
+ });
221
225
  }
222
226
  }
223
227
  await initRepl();
@@ -374,7 +378,7 @@ export async function runRlmLoop(options) {
374
378
  });
375
379
  if (execResult.hasFinal && execResult.finalValue !== null) {
376
380
  // Auto-merge any unmerged thread branches before returning
377
- if (mergeHandler) {
381
+ if (mergeHandler && !mergedAlready) {
378
382
  try {
379
383
  await mergeHandler();
380
384
  }
@@ -422,7 +426,7 @@ export async function runRlmLoop(options) {
422
426
  });
423
427
  }
424
428
  // Auto-merge any remaining thread branches even though FINAL was never called
425
- if (mergeHandler) {
429
+ if (mergeHandler && !mergedAlready) {
426
430
  try {
427
431
  await mergeHandler();
428
432
  }
@@ -757,8 +757,11 @@ export async function runInteractiveSwarm(rawArgs) {
757
757
  logError(`Directory "${args.dir}" does not exist`);
758
758
  process.exit(1);
759
759
  }
760
- // First-run onboarding
760
+ // First-run onboarding (may create ~/.swarm/config.yaml with user's chosen model)
761
761
  await runOnboarding();
762
+ // Reload config to pick up any changes from onboarding
763
+ // (onboarding writes ~/.swarm/config.yaml but loadConfig() already ran before it)
764
+ Object.assign(config, loadConfig());
762
765
  // Override config with CLI args
763
766
  if (args.agent)
764
767
  config.default_agent = args.agent;
@@ -960,6 +963,22 @@ export async function runInteractiveSwarm(rawArgs) {
960
963
  else if (merged > 0) {
961
964
  logSuccess(`Merged ${merged} branches`);
962
965
  }
966
+ // Clean up merged worktrees
967
+ if (config.auto_cleanup_worktrees) {
968
+ for (const r of results) {
969
+ if (r.success) {
970
+ const thread = threads.find((t) => t.branchName === r.branch);
971
+ if (thread) {
972
+ try {
973
+ await threadManager.destroyWorktree(thread.id);
974
+ }
975
+ catch {
976
+ // Non-fatal
977
+ }
978
+ }
979
+ }
980
+ }
981
+ }
963
982
  const summary = results
964
983
  .map((r) => (r.success ? `Merged ${r.branch}: ${r.message}` : `FAILED ${r.branch}: ${r.message}`))
965
984
  .join("\n");
@@ -80,6 +80,7 @@ export declare class ThreadManager {
80
80
  };
81
81
  /** Cleanup all worktrees. */
82
82
  cleanup(): Promise<void>;
83
- private cleanupWorktree;
83
+ /** Destroy a specific thread's worktree and branch. */
84
+ destroyWorktree(threadId: string): Promise<void>;
84
85
  private failResult;
85
86
  }
@@ -486,7 +486,7 @@ export class ThreadManager {
486
486
  state.status = "cancelled";
487
487
  state.phase = "cancelled";
488
488
  state.completedAt = Date.now();
489
- await this.cleanupWorktree(threadId);
489
+ await this.destroyWorktree(threadId);
490
490
  return this.failResult(state, "Thread cancelled during execution");
491
491
  }
492
492
  // Capture diff
@@ -570,7 +570,7 @@ export class ThreadManager {
570
570
  const { cost } = this.budget.recordCost(threadId, errModel);
571
571
  state.estimatedCostUsd = cost;
572
572
  // Cleanup worktree on failure
573
- await this.cleanupWorktree(threadId);
573
+ await this.destroyWorktree(threadId);
574
574
  return this.failResult(state, errorMsg);
575
575
  }
576
576
  finally {
@@ -637,7 +637,8 @@ export class ThreadManager {
637
637
  await this.worktreeManager.destroyAll();
638
638
  }
639
639
  }
640
- async cleanupWorktree(threadId) {
640
+ /** Destroy a specific thread's worktree and branch. */
641
+ async destroyWorktree(threadId) {
641
642
  try {
642
643
  await this.worktreeManager.destroy(threadId, true);
643
644
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swarm-code",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "description": "Open-source swarm-native coding agent orchestrator — spawns parallel coding agents in isolated git worktrees, built on RLM (arXiv:2512.24601)",
5
5
  "type": "module",
6
6
  "bin": {