opencode-swarm 6.43.2 → 6.44.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
@@ -16125,9 +16125,278 @@ var require_proper_lockfile = __commonJS((exports, module) => {
16125
16125
  module.exports.checkSync = checkSync;
16126
16126
  });
16127
16127
 
16128
+ // src/plan/ledger.ts
16129
+ import * as crypto2 from "crypto";
16130
+ import * as fs4 from "fs";
16131
+ import * as path7 from "path";
16132
+ function getLedgerPath(directory) {
16133
+ return path7.join(directory, ".swarm", LEDGER_FILENAME);
16134
+ }
16135
+ function getPlanJsonPath(directory) {
16136
+ return path7.join(directory, ".swarm", PLAN_JSON_FILENAME);
16137
+ }
16138
+ function computePlanHash(plan) {
16139
+ const normalized = {
16140
+ schema_version: plan.schema_version,
16141
+ title: plan.title,
16142
+ swarm: plan.swarm,
16143
+ current_phase: plan.current_phase,
16144
+ migration_status: plan.migration_status,
16145
+ phases: plan.phases.map((phase) => ({
16146
+ id: phase.id,
16147
+ name: phase.name,
16148
+ status: phase.status,
16149
+ required_agents: phase.required_agents ? [...phase.required_agents].sort() : undefined,
16150
+ tasks: phase.tasks.map((task) => ({
16151
+ id: task.id,
16152
+ phase: task.phase,
16153
+ status: task.status,
16154
+ size: task.size,
16155
+ description: task.description,
16156
+ depends: [...task.depends].sort(),
16157
+ acceptance: task.acceptance,
16158
+ files_touched: [...task.files_touched].sort(),
16159
+ evidence_path: task.evidence_path,
16160
+ blocked_reason: task.blocked_reason
16161
+ }))
16162
+ }))
16163
+ };
16164
+ const jsonString = JSON.stringify(normalized);
16165
+ return crypto2.createHash("sha256").update(jsonString, "utf8").digest("hex");
16166
+ }
16167
+ function computeCurrentPlanHash(directory) {
16168
+ const planPath = getPlanJsonPath(directory);
16169
+ try {
16170
+ const content = fs4.readFileSync(planPath, "utf8");
16171
+ const plan = JSON.parse(content);
16172
+ return computePlanHash(plan);
16173
+ } catch {
16174
+ return "";
16175
+ }
16176
+ }
16177
+ async function ledgerExists(directory) {
16178
+ const ledgerPath = getLedgerPath(directory);
16179
+ return fs4.existsSync(ledgerPath);
16180
+ }
16181
+ async function getLatestLedgerSeq(directory) {
16182
+ const ledgerPath = getLedgerPath(directory);
16183
+ if (!fs4.existsSync(ledgerPath)) {
16184
+ return 0;
16185
+ }
16186
+ try {
16187
+ const content = fs4.readFileSync(ledgerPath, "utf8");
16188
+ const lines = content.trim().split(`
16189
+ `).filter((line) => line.trim() !== "");
16190
+ if (lines.length === 0) {
16191
+ return 0;
16192
+ }
16193
+ let maxSeq = 0;
16194
+ for (const line of lines) {
16195
+ try {
16196
+ const event = JSON.parse(line);
16197
+ if (event.seq > maxSeq) {
16198
+ maxSeq = event.seq;
16199
+ }
16200
+ } catch {}
16201
+ }
16202
+ return maxSeq;
16203
+ } catch {
16204
+ return 0;
16205
+ }
16206
+ }
16207
+ async function readLedgerEvents(directory) {
16208
+ const ledgerPath = getLedgerPath(directory);
16209
+ if (!fs4.existsSync(ledgerPath)) {
16210
+ return [];
16211
+ }
16212
+ try {
16213
+ const content = fs4.readFileSync(ledgerPath, "utf8");
16214
+ const lines = content.trim().split(`
16215
+ `).filter((line) => line.trim() !== "");
16216
+ const events = [];
16217
+ for (const line of lines) {
16218
+ try {
16219
+ const event = JSON.parse(line);
16220
+ events.push(event);
16221
+ } catch {}
16222
+ }
16223
+ events.sort((a, b) => a.seq - b.seq);
16224
+ return events;
16225
+ } catch {
16226
+ return [];
16227
+ }
16228
+ }
16229
+ async function initLedger(directory, planId) {
16230
+ const ledgerPath = getLedgerPath(directory);
16231
+ const planJsonPath = getPlanJsonPath(directory);
16232
+ if (fs4.existsSync(ledgerPath)) {
16233
+ throw new Error("Ledger already initialized. Use appendLedgerEvent to add events.");
16234
+ }
16235
+ let planHashAfter = "";
16236
+ try {
16237
+ if (fs4.existsSync(planJsonPath)) {
16238
+ const content = fs4.readFileSync(planJsonPath, "utf8");
16239
+ const plan = JSON.parse(content);
16240
+ planHashAfter = computePlanHash(plan);
16241
+ }
16242
+ } catch {}
16243
+ const event = {
16244
+ seq: 1,
16245
+ timestamp: new Date().toISOString(),
16246
+ plan_id: planId,
16247
+ event_type: "plan_created",
16248
+ source: "initLedger",
16249
+ plan_hash_before: "",
16250
+ plan_hash_after: planHashAfter,
16251
+ schema_version: LEDGER_SCHEMA_VERSION
16252
+ };
16253
+ fs4.mkdirSync(path7.join(directory, ".swarm"), { recursive: true });
16254
+ const tempPath = `${ledgerPath}.tmp`;
16255
+ const line = `${JSON.stringify(event)}
16256
+ `;
16257
+ fs4.writeFileSync(tempPath, line, "utf8");
16258
+ fs4.renameSync(tempPath, ledgerPath);
16259
+ }
16260
+ async function appendLedgerEvent(directory, eventInput, options) {
16261
+ const ledgerPath = getLedgerPath(directory);
16262
+ const latestSeq = await getLatestLedgerSeq(directory);
16263
+ const nextSeq = latestSeq + 1;
16264
+ const planHashBefore = computeCurrentPlanHash(directory);
16265
+ if (options?.expectedSeq !== undefined && options.expectedSeq !== latestSeq) {
16266
+ throw new LedgerStaleWriterError(`Stale writer: expected seq ${options.expectedSeq} but found ${latestSeq}`);
16267
+ }
16268
+ if (options?.expectedHash !== undefined && options.expectedHash !== planHashBefore) {
16269
+ throw new LedgerStaleWriterError(`Stale writer: expected hash ${options.expectedHash} but found ${planHashBefore}`);
16270
+ }
16271
+ const planHashAfter = options?.planHashAfter ?? planHashBefore;
16272
+ const event = {
16273
+ ...eventInput,
16274
+ seq: nextSeq,
16275
+ timestamp: new Date().toISOString(),
16276
+ plan_hash_before: planHashBefore,
16277
+ plan_hash_after: planHashAfter,
16278
+ schema_version: LEDGER_SCHEMA_VERSION
16279
+ };
16280
+ fs4.mkdirSync(path7.join(directory, ".swarm"), { recursive: true });
16281
+ const tempPath = `${ledgerPath}.tmp`;
16282
+ const line = `${JSON.stringify(event)}
16283
+ `;
16284
+ if (fs4.existsSync(ledgerPath)) {
16285
+ const existingContent = fs4.readFileSync(ledgerPath, "utf8");
16286
+ fs4.writeFileSync(tempPath, existingContent + line, "utf8");
16287
+ } else {
16288
+ throw new Error("Ledger not initialized. Call initLedger() first.");
16289
+ }
16290
+ fs4.renameSync(tempPath, ledgerPath);
16291
+ return event;
16292
+ }
16293
+ async function takeSnapshotEvent(directory, plan, options) {
16294
+ const payloadHash = computePlanHash(plan);
16295
+ const snapshotPayload = {
16296
+ plan,
16297
+ payload_hash: payloadHash
16298
+ };
16299
+ return appendLedgerEvent(directory, {
16300
+ event_type: "snapshot",
16301
+ source: "takeSnapshotEvent",
16302
+ plan_id: plan.title,
16303
+ payload: snapshotPayload
16304
+ }, options);
16305
+ }
16306
+ async function replayFromLedger(directory, options) {
16307
+ const events = await readLedgerEvents(directory);
16308
+ if (events.length === 0) {
16309
+ return null;
16310
+ }
16311
+ {
16312
+ const snapshotEvents = events.filter((e) => e.event_type === "snapshot");
16313
+ if (snapshotEvents.length > 0) {
16314
+ const latestSnapshotEvent = snapshotEvents[snapshotEvents.length - 1];
16315
+ const snapshotPayload = latestSnapshotEvent.payload;
16316
+ let plan2 = snapshotPayload.plan;
16317
+ const eventsAfterSnapshot = events.filter((e) => e.seq > latestSnapshotEvent.seq);
16318
+ for (const event of eventsAfterSnapshot) {
16319
+ plan2 = applyEventToPlan(plan2, event);
16320
+ if (plan2 === null) {
16321
+ return null;
16322
+ }
16323
+ }
16324
+ return plan2;
16325
+ }
16326
+ }
16327
+ const planJsonPath = getPlanJsonPath(directory);
16328
+ if (!fs4.existsSync(planJsonPath)) {
16329
+ return null;
16330
+ }
16331
+ let plan;
16332
+ try {
16333
+ const content = fs4.readFileSync(planJsonPath, "utf8");
16334
+ plan = JSON.parse(content);
16335
+ } catch {
16336
+ return null;
16337
+ }
16338
+ for (const event of events) {
16339
+ if (plan === null) {
16340
+ return null;
16341
+ }
16342
+ plan = applyEventToPlan(plan, event);
16343
+ }
16344
+ return plan;
16345
+ }
16346
+ function applyEventToPlan(plan, event) {
16347
+ switch (event.event_type) {
16348
+ case "plan_created":
16349
+ return plan;
16350
+ case "task_status_changed":
16351
+ if (event.task_id && event.to_status) {
16352
+ for (const phase of plan.phases) {
16353
+ const task = phase.tasks.find((t) => t.id === event.task_id);
16354
+ if (task) {
16355
+ task.status = event.to_status;
16356
+ break;
16357
+ }
16358
+ }
16359
+ }
16360
+ return plan;
16361
+ case "phase_completed":
16362
+ if (event.phase_id) {
16363
+ const phase = plan.phases.find((p) => p.id === event.phase_id);
16364
+ if (phase) {
16365
+ phase.status = "complete";
16366
+ }
16367
+ }
16368
+ return plan;
16369
+ case "plan_exported":
16370
+ return plan;
16371
+ case "task_added":
16372
+ return plan;
16373
+ case "task_updated":
16374
+ return plan;
16375
+ case "plan_rebuilt":
16376
+ return plan;
16377
+ case "task_reordered":
16378
+ return plan;
16379
+ case "snapshot":
16380
+ return plan;
16381
+ case "plan_reset":
16382
+ return null;
16383
+ default:
16384
+ throw new Error(`applyEventToPlan: unhandled event type "${event.event_type}" at seq ${event.seq}`);
16385
+ }
16386
+ }
16387
+ var LEDGER_SCHEMA_VERSION = "1.0.0", LEDGER_FILENAME = "plan-ledger.jsonl", PLAN_JSON_FILENAME = "plan.json", LedgerStaleWriterError;
16388
+ var init_ledger = __esm(() => {
16389
+ LedgerStaleWriterError = class LedgerStaleWriterError extends Error {
16390
+ constructor(message) {
16391
+ super(message);
16392
+ this.name = "LedgerStaleWriterError";
16393
+ }
16394
+ };
16395
+ });
16396
+
16128
16397
  // src/plan/manager.ts
16129
16398
  import { renameSync as renameSync3, unlinkSync } from "fs";
16130
- import * as path9 from "path";
16399
+ import * as path8 from "path";
16131
16400
  async function loadPlanJsonOnly(directory) {
16132
16401
  const planJsonContent = await readSwarmFileAsync(directory, "plan.json");
16133
16402
  if (planJsonContent !== null) {
@@ -16158,6 +16427,17 @@ function compareTaskIds(a, b) {
16158
16427
  }
16159
16428
  return 0;
16160
16429
  }
16430
+ async function getLatestLedgerHash(directory) {
16431
+ try {
16432
+ const events = await readLedgerEvents(directory);
16433
+ if (events.length === 0)
16434
+ return "";
16435
+ const lastEvent = events[events.length - 1];
16436
+ return lastEvent.plan_hash_after;
16437
+ } catch {
16438
+ return "";
16439
+ }
16440
+ }
16161
16441
  function computePlanContentHash(plan) {
16162
16442
  const content = {
16163
16443
  schema_version: plan.schema_version,
@@ -16209,13 +16489,13 @@ async function isPlanMdInSync(directory, plan) {
16209
16489
  return normalizedActual.includes(normalizedExpected) || normalizedExpected.includes(normalizedActual.replace(/^#.*$/gm, "").trim());
16210
16490
  }
16211
16491
  async function regeneratePlanMarkdown(directory, plan) {
16212
- const swarmDir = path9.resolve(directory, ".swarm");
16492
+ const swarmDir = path8.resolve(directory, ".swarm");
16213
16493
  const contentHash = computePlanContentHash(plan);
16214
16494
  const markdown = derivePlanMarkdown(plan);
16215
16495
  const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
16216
16496
  ${markdown}`;
16217
- const mdPath = path9.join(swarmDir, "plan.md");
16218
- const mdTempPath = path9.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
16497
+ const mdPath = path8.join(swarmDir, "plan.md");
16498
+ const mdTempPath = path8.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
16219
16499
  try {
16220
16500
  await Bun.write(mdTempPath, markdownWithHash);
16221
16501
  renameSync3(mdTempPath, mdPath);
@@ -16242,9 +16522,34 @@ async function loadPlan(directory) {
16242
16522
  warn(`Failed to regenerate plan.md: ${regenError instanceof Error ? regenError.message : String(regenError)}. Proceeding with plan.json only.`);
16243
16523
  }
16244
16524
  }
16525
+ if (await ledgerExists(directory)) {
16526
+ const planHash = computePlanHash(validated);
16527
+ const ledgerHash = await getLatestLedgerHash(directory);
16528
+ if (ledgerHash !== "" && planHash !== ledgerHash) {
16529
+ warn("[loadPlan] plan.json is stale (hash mismatch with ledger) \u2014 rebuilding from ledger. If this recurs, run /swarm reset-session to clear stale session state.");
16530
+ try {
16531
+ const rebuilt = await replayFromLedger(directory);
16532
+ if (rebuilt) {
16533
+ await rebuildPlan(directory, rebuilt);
16534
+ warn("[loadPlan] Rebuilt plan from ledger. Checkpoint available at SWARM_PLAN.md if it exists.");
16535
+ return rebuilt;
16536
+ }
16537
+ } catch (replayError) {
16538
+ warn(`[loadPlan] Ledger replay failed during hash-mismatch rebuild: ${replayError instanceof Error ? replayError.message : String(replayError)}. Returning stale plan.json. To recover: check SWARM_PLAN.md for a checkpoint, or run /swarm reset-session.`);
16539
+ }
16540
+ }
16541
+ }
16245
16542
  return validated;
16246
16543
  } catch (error93) {
16247
- warn(`Plan validation failed for .swarm/plan.json: ${error93 instanceof Error ? error93.message : String(error93)}`);
16544
+ warn(`[loadPlan] plan.json validation failed: ${error93 instanceof Error ? error93.message : String(error93)}. Attempting rebuild from ledger. If rebuild fails, check SWARM_PLAN.md for a checkpoint.`);
16545
+ if (await ledgerExists(directory)) {
16546
+ const rebuilt = await replayFromLedger(directory);
16547
+ if (rebuilt) {
16548
+ await rebuildPlan(directory, rebuilt);
16549
+ warn("[loadPlan] Rebuilt plan from ledger after validation failure. Projection was stale.");
16550
+ return rebuilt;
16551
+ }
16552
+ }
16248
16553
  const planMdContent2 = await readSwarmFileAsync(directory, "plan.md");
16249
16554
  if (planMdContent2 !== null) {
16250
16555
  const migrated = migrateLegacyPlan(planMdContent2);
@@ -16260,6 +16565,13 @@ async function loadPlan(directory) {
16260
16565
  await savePlan(directory, migrated);
16261
16566
  return migrated;
16262
16567
  }
16568
+ if (await ledgerExists(directory)) {
16569
+ const rebuilt = await replayFromLedger(directory);
16570
+ if (rebuilt) {
16571
+ await savePlan(directory, rebuilt);
16572
+ return rebuilt;
16573
+ }
16574
+ }
16263
16575
  return null;
16264
16576
  }
16265
16577
  async function savePlan(directory, plan, options) {
@@ -16269,10 +16581,10 @@ async function savePlan(directory, plan, options) {
16269
16581
  const validated = PlanSchema.parse(plan);
16270
16582
  if (options?.preserveCompletedStatuses !== false) {
16271
16583
  try {
16272
- const currentPlan = await loadPlanJsonOnly(directory);
16273
- if (currentPlan) {
16584
+ const currentPlan2 = await loadPlanJsonOnly(directory);
16585
+ if (currentPlan2) {
16274
16586
  const completedTaskIds = new Set;
16275
- for (const phase of currentPlan.phases) {
16587
+ for (const phase of currentPlan2.phases) {
16276
16588
  for (const task of phase.tasks) {
16277
16589
  if (task.status === "completed")
16278
16590
  completedTaskIds.add(task.id);
@@ -16302,9 +16614,58 @@ async function savePlan(directory, plan, options) {
16302
16614
  phase.status = "pending";
16303
16615
  }
16304
16616
  }
16305
- const swarmDir = path9.resolve(directory, ".swarm");
16306
- const planPath = path9.join(swarmDir, "plan.json");
16307
- const tempPath = path9.join(swarmDir, `plan.json.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
16617
+ const currentPlan = await loadPlanJsonOnly(directory);
16618
+ if (!await ledgerExists(directory)) {
16619
+ const planId = `${validated.swarm}-${validated.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
16620
+ await initLedger(directory, planId);
16621
+ }
16622
+ const currentHash = computeCurrentPlanHash(directory);
16623
+ const hashAfter = computePlanHash(validated);
16624
+ if (currentPlan) {
16625
+ const oldTaskMap = new Map;
16626
+ for (const phase of currentPlan.phases) {
16627
+ for (const task of phase.tasks) {
16628
+ oldTaskMap.set(task.id, { phase: task.phase, status: task.status });
16629
+ }
16630
+ }
16631
+ try {
16632
+ for (const phase of validated.phases) {
16633
+ for (const task of phase.tasks) {
16634
+ const oldTask = oldTaskMap.get(task.id);
16635
+ if (oldTask && oldTask.status !== task.status) {
16636
+ const eventInput = {
16637
+ plan_id: `${validated.swarm}-${validated.title}`.replace(/[^a-zA-Z0-9-_]/g, "_"),
16638
+ event_type: "task_status_changed",
16639
+ task_id: task.id,
16640
+ phase_id: phase.id,
16641
+ from_status: oldTask.status,
16642
+ to_status: task.status,
16643
+ source: "savePlan"
16644
+ };
16645
+ await appendLedgerEvent(directory, eventInput, {
16646
+ expectedHash: currentHash,
16647
+ planHashAfter: hashAfter
16648
+ });
16649
+ }
16650
+ }
16651
+ }
16652
+ } catch (error93) {
16653
+ if (error93 instanceof LedgerStaleWriterError) {
16654
+ throw new Error(`Concurrent plan modification detected: ${error93.message}. Please retry the operation.`);
16655
+ }
16656
+ throw error93;
16657
+ }
16658
+ }
16659
+ const SNAPSHOT_INTERVAL = 50;
16660
+ const latestSeq = await getLatestLedgerSeq(directory);
16661
+ if (latestSeq > 0 && latestSeq % SNAPSHOT_INTERVAL === 0) {
16662
+ await takeSnapshotEvent(directory, validated, {
16663
+ planHashAfter: hashAfter
16664
+ }).catch(() => {});
16665
+ }
16666
+ const swarmDir = path8.resolve(directory, ".swarm");
16667
+ const planPath = path8.join(swarmDir, "plan.json");
16668
+ const tempPath = path8.join(swarmDir, `plan.json.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
16308
16669
  try {
16309
16670
  await Bun.write(tempPath, JSON.stringify(validated, null, 2));
16310
16671
  renameSync3(tempPath, planPath);
@@ -16317,8 +16678,8 @@ async function savePlan(directory, plan, options) {
16317
16678
  const markdown = derivePlanMarkdown(validated);
16318
16679
  const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
16319
16680
  ${markdown}`;
16320
- const mdPath = path9.join(swarmDir, "plan.md");
16321
- const mdTempPath = path9.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
16681
+ const mdPath = path8.join(swarmDir, "plan.md");
16682
+ const mdTempPath = path8.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
16322
16683
  try {
16323
16684
  await Bun.write(mdTempPath, markdownWithHash);
16324
16685
  renameSync3(mdTempPath, mdPath);
@@ -16328,7 +16689,7 @@ ${markdown}`;
16328
16689
  } catch {}
16329
16690
  }
16330
16691
  try {
16331
- const markerPath = path9.join(swarmDir, ".plan-write-marker");
16692
+ const markerPath = path8.join(swarmDir, ".plan-write-marker");
16332
16693
  const tasksCount = validated.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
16333
16694
  const marker = JSON.stringify({
16334
16695
  source: "plan_manager",
@@ -16339,6 +16700,22 @@ ${markdown}`;
16339
16700
  await Bun.write(markerPath, marker);
16340
16701
  } catch {}
16341
16702
  }
16703
+ async function rebuildPlan(directory, plan) {
16704
+ const targetPlan = plan ?? await replayFromLedger(directory);
16705
+ if (!targetPlan)
16706
+ return null;
16707
+ const swarmDir = path8.join(directory, ".swarm");
16708
+ const planPath = path8.join(swarmDir, "plan.json");
16709
+ const mdPath = path8.join(swarmDir, "plan.md");
16710
+ const tempPlanPath = path8.join(swarmDir, `plan.json.rebuild.${Date.now()}`);
16711
+ await Bun.write(tempPlanPath, JSON.stringify(targetPlan, null, 2));
16712
+ renameSync3(tempPlanPath, planPath);
16713
+ const markdown = derivePlanMarkdown(targetPlan);
16714
+ const tempMdPath = path8.join(swarmDir, `plan.md.rebuild.${Date.now()}`);
16715
+ await Bun.write(tempMdPath, markdown);
16716
+ renameSync3(tempMdPath, mdPath);
16717
+ return targetPlan;
16718
+ }
16342
16719
  function derivePlanMarkdown(plan) {
16343
16720
  const statusMap = {
16344
16721
  pending: "PENDING",
@@ -16609,6 +16986,7 @@ var init_manager2 = __esm(() => {
16609
16986
  init_plan_schema();
16610
16987
  init_utils2();
16611
16988
  init_utils();
16989
+ init_ledger();
16612
16990
  });
16613
16991
 
16614
16992
  // src/services/config-doctor.ts
@@ -16624,20 +17002,20 @@ __export(exports_config_doctor, {
16624
17002
  createConfigBackup: () => createConfigBackup,
16625
17003
  applySafeAutoFixes: () => applySafeAutoFixes
16626
17004
  });
16627
- import * as crypto2 from "crypto";
16628
- import * as fs5 from "fs";
17005
+ import * as crypto3 from "crypto";
17006
+ import * as fs7 from "fs";
16629
17007
  import * as os4 from "os";
16630
- import * as path14 from "path";
17008
+ import * as path16 from "path";
16631
17009
  function getUserConfigDir3() {
16632
- return process.env.XDG_CONFIG_HOME || path14.join(os4.homedir(), ".config");
17010
+ return process.env.XDG_CONFIG_HOME || path16.join(os4.homedir(), ".config");
16633
17011
  }
16634
17012
  function getConfigPaths(directory) {
16635
- const userConfigPath = path14.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
16636
- const projectConfigPath = path14.join(directory, ".opencode", "opencode-swarm.json");
17013
+ const userConfigPath = path16.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
17014
+ const projectConfigPath = path16.join(directory, ".opencode", "opencode-swarm.json");
16637
17015
  return { userConfigPath, projectConfigPath };
16638
17016
  }
16639
17017
  function computeHash(content) {
16640
- return crypto2.createHash("sha256").update(content, "utf-8").digest("hex");
17018
+ return crypto3.createHash("sha256").update(content, "utf-8").digest("hex");
16641
17019
  }
16642
17020
  function isValidConfigPath(configPath, directory) {
16643
17021
  const normalizedPath = configPath.replace(/\\/g, "/");
@@ -16658,9 +17036,9 @@ function isValidConfigPath(configPath, directory) {
16658
17036
  const normalizedUser = userConfigPath.replace(/\\/g, "/");
16659
17037
  const normalizedProject = projectConfigPath.replace(/\\/g, "/");
16660
17038
  try {
16661
- const resolvedConfig = path14.resolve(configPath);
16662
- const resolvedUser = path14.resolve(normalizedUser);
16663
- const resolvedProject = path14.resolve(normalizedProject);
17039
+ const resolvedConfig = path16.resolve(configPath);
17040
+ const resolvedUser = path16.resolve(normalizedUser);
17041
+ const resolvedProject = path16.resolve(normalizedProject);
16664
17042
  return resolvedConfig === resolvedUser || resolvedConfig === resolvedProject;
16665
17043
  } catch {
16666
17044
  return false;
@@ -16670,19 +17048,19 @@ function createConfigBackup(directory) {
16670
17048
  const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
16671
17049
  let configPath = projectConfigPath;
16672
17050
  let content = null;
16673
- if (fs5.existsSync(projectConfigPath)) {
17051
+ if (fs7.existsSync(projectConfigPath)) {
16674
17052
  try {
16675
- content = fs5.readFileSync(projectConfigPath, "utf-8");
17053
+ content = fs7.readFileSync(projectConfigPath, "utf-8");
16676
17054
  } catch (error93) {
16677
17055
  log("[ConfigDoctor] project config read failed", {
16678
17056
  error: error93 instanceof Error ? error93.message : String(error93)
16679
17057
  });
16680
17058
  }
16681
17059
  }
16682
- if (content === null && fs5.existsSync(userConfigPath)) {
17060
+ if (content === null && fs7.existsSync(userConfigPath)) {
16683
17061
  configPath = userConfigPath;
16684
17062
  try {
16685
- content = fs5.readFileSync(userConfigPath, "utf-8");
17063
+ content = fs7.readFileSync(userConfigPath, "utf-8");
16686
17064
  } catch (error93) {
16687
17065
  log("[ConfigDoctor] user config read failed", {
16688
17066
  error: error93 instanceof Error ? error93.message : String(error93)
@@ -16700,12 +17078,12 @@ function createConfigBackup(directory) {
16700
17078
  };
16701
17079
  }
16702
17080
  function writeBackupArtifact(directory, backup) {
16703
- const swarmDir = path14.join(directory, ".swarm");
16704
- if (!fs5.existsSync(swarmDir)) {
16705
- fs5.mkdirSync(swarmDir, { recursive: true });
17081
+ const swarmDir = path16.join(directory, ".swarm");
17082
+ if (!fs7.existsSync(swarmDir)) {
17083
+ fs7.mkdirSync(swarmDir, { recursive: true });
16706
17084
  }
16707
17085
  const backupFilename = `config-backup-${backup.createdAt}.json`;
16708
- const backupPath = path14.join(swarmDir, backupFilename);
17086
+ const backupPath = path16.join(swarmDir, backupFilename);
16709
17087
  const artifact = {
16710
17088
  createdAt: backup.createdAt,
16711
17089
  configPath: backup.configPath,
@@ -16713,15 +17091,15 @@ function writeBackupArtifact(directory, backup) {
16713
17091
  content: backup.content,
16714
17092
  preview: backup.content.substring(0, 500) + (backup.content.length > 500 ? "..." : "")
16715
17093
  };
16716
- fs5.writeFileSync(backupPath, JSON.stringify(artifact, null, 2), "utf-8");
17094
+ fs7.writeFileSync(backupPath, JSON.stringify(artifact, null, 2), "utf-8");
16717
17095
  return backupPath;
16718
17096
  }
16719
17097
  function restoreFromBackup(backupPath, directory) {
16720
- if (!fs5.existsSync(backupPath)) {
17098
+ if (!fs7.existsSync(backupPath)) {
16721
17099
  return null;
16722
17100
  }
16723
17101
  try {
16724
- const artifact = JSON.parse(fs5.readFileSync(backupPath, "utf-8"));
17102
+ const artifact = JSON.parse(fs7.readFileSync(backupPath, "utf-8"));
16725
17103
  if (!artifact.content || !artifact.configPath || !artifact.contentHash) {
16726
17104
  return null;
16727
17105
  }
@@ -16735,11 +17113,11 @@ function restoreFromBackup(backupPath, directory) {
16735
17113
  return null;
16736
17114
  }
16737
17115
  const targetPath = artifact.configPath;
16738
- const targetDir = path14.dirname(targetPath);
16739
- if (!fs5.existsSync(targetDir)) {
16740
- fs5.mkdirSync(targetDir, { recursive: true });
17116
+ const targetDir = path16.dirname(targetPath);
17117
+ if (!fs7.existsSync(targetDir)) {
17118
+ fs7.mkdirSync(targetDir, { recursive: true });
16741
17119
  }
16742
- fs5.writeFileSync(targetPath, artifact.content, "utf-8");
17120
+ fs7.writeFileSync(targetPath, artifact.content, "utf-8");
16743
17121
  return targetPath;
16744
17122
  } catch {
16745
17123
  return null;
@@ -16749,12 +17127,12 @@ function readConfigFromFile(directory) {
16749
17127
  const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
16750
17128
  let configPath = projectConfigPath;
16751
17129
  let configContent = null;
16752
- if (fs5.existsSync(projectConfigPath)) {
17130
+ if (fs7.existsSync(projectConfigPath)) {
16753
17131
  configPath = projectConfigPath;
16754
- configContent = fs5.readFileSync(projectConfigPath, "utf-8");
16755
- } else if (fs5.existsSync(userConfigPath)) {
17132
+ configContent = fs7.readFileSync(projectConfigPath, "utf-8");
17133
+ } else if (fs7.existsSync(userConfigPath)) {
16756
17134
  configPath = userConfigPath;
16757
- configContent = fs5.readFileSync(userConfigPath, "utf-8");
17135
+ configContent = fs7.readFileSync(userConfigPath, "utf-8");
16758
17136
  }
16759
17137
  if (configContent === null) {
16760
17138
  return null;
@@ -16766,9 +17144,9 @@ function readConfigFromFile(directory) {
16766
17144
  return null;
16767
17145
  }
16768
17146
  }
16769
- function validateConfigKey(path15, value, _config) {
17147
+ function validateConfigKey(path17, value, _config) {
16770
17148
  const findings = [];
16771
- switch (path15) {
17149
+ switch (path17) {
16772
17150
  case "agents": {
16773
17151
  if (value !== undefined) {
16774
17152
  findings.push({
@@ -17015,27 +17393,27 @@ function validateConfigKey(path15, value, _config) {
17015
17393
  }
17016
17394
  return findings;
17017
17395
  }
17018
- function walkConfigAndValidate(obj, path15, config3, findings) {
17396
+ function walkConfigAndValidate(obj, path17, config3, findings) {
17019
17397
  if (obj === null || obj === undefined) {
17020
17398
  return;
17021
17399
  }
17022
- if (path15 && typeof obj === "object" && !Array.isArray(obj)) {
17023
- const keyFindings = validateConfigKey(path15, obj, config3);
17400
+ if (path17 && typeof obj === "object" && !Array.isArray(obj)) {
17401
+ const keyFindings = validateConfigKey(path17, obj, config3);
17024
17402
  findings.push(...keyFindings);
17025
17403
  }
17026
17404
  if (typeof obj !== "object") {
17027
- const keyFindings = validateConfigKey(path15, obj, config3);
17405
+ const keyFindings = validateConfigKey(path17, obj, config3);
17028
17406
  findings.push(...keyFindings);
17029
17407
  return;
17030
17408
  }
17031
17409
  if (Array.isArray(obj)) {
17032
17410
  obj.forEach((item, index) => {
17033
- walkConfigAndValidate(item, `${path15}[${index}]`, config3, findings);
17411
+ walkConfigAndValidate(item, `${path17}[${index}]`, config3, findings);
17034
17412
  });
17035
17413
  return;
17036
17414
  }
17037
17415
  for (const [key, value] of Object.entries(obj)) {
17038
- const newPath = path15 ? `${path15}.${key}` : key;
17416
+ const newPath = path17 ? `${path17}.${key}` : key;
17039
17417
  walkConfigAndValidate(value, newPath, config3, findings);
17040
17418
  }
17041
17419
  }
@@ -17050,9 +17428,9 @@ function runConfigDoctor(config3, directory) {
17050
17428
  const hasAutoFixableIssues = findings.some((f) => f.autoFixable && f.proposedFix?.risk === "low");
17051
17429
  const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
17052
17430
  let configSource = "defaults";
17053
- if (fs5.existsSync(projectConfigPath)) {
17431
+ if (fs7.existsSync(projectConfigPath)) {
17054
17432
  configSource = projectConfigPath;
17055
- } else if (fs5.existsSync(userConfigPath)) {
17433
+ } else if (fs7.existsSync(userConfigPath)) {
17056
17434
  configSource = userConfigPath;
17057
17435
  }
17058
17436
  return {
@@ -17081,12 +17459,12 @@ function applySafeAutoFixes(directory, result) {
17081
17459
  const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
17082
17460
  let configPath = projectConfigPath;
17083
17461
  let configContent;
17084
- if (fs5.existsSync(projectConfigPath)) {
17462
+ if (fs7.existsSync(projectConfigPath)) {
17085
17463
  configPath = projectConfigPath;
17086
- configContent = fs5.readFileSync(projectConfigPath, "utf-8");
17087
- } else if (fs5.existsSync(userConfigPath)) {
17464
+ configContent = fs7.readFileSync(projectConfigPath, "utf-8");
17465
+ } else if (fs7.existsSync(userConfigPath)) {
17088
17466
  configPath = userConfigPath;
17089
- configContent = fs5.readFileSync(userConfigPath, "utf-8");
17467
+ configContent = fs7.readFileSync(userConfigPath, "utf-8");
17090
17468
  } else {
17091
17469
  return { appliedFixes, updatedConfigPath: null };
17092
17470
  }
@@ -17155,22 +17533,22 @@ function applySafeAutoFixes(directory, result) {
17155
17533
  }
17156
17534
  }
17157
17535
  if (appliedFixes.length > 0) {
17158
- const configDir = path14.dirname(configPath);
17159
- if (!fs5.existsSync(configDir)) {
17160
- fs5.mkdirSync(configDir, { recursive: true });
17536
+ const configDir = path16.dirname(configPath);
17537
+ if (!fs7.existsSync(configDir)) {
17538
+ fs7.mkdirSync(configDir, { recursive: true });
17161
17539
  }
17162
- fs5.writeFileSync(configPath, JSON.stringify(config3, null, 2), "utf-8");
17540
+ fs7.writeFileSync(configPath, JSON.stringify(config3, null, 2), "utf-8");
17163
17541
  updatedConfigPath = configPath;
17164
17542
  }
17165
17543
  return { appliedFixes, updatedConfigPath };
17166
17544
  }
17167
17545
  function writeDoctorArtifact(directory, result) {
17168
- const swarmDir = path14.join(directory, ".swarm");
17169
- if (!fs5.existsSync(swarmDir)) {
17170
- fs5.mkdirSync(swarmDir, { recursive: true });
17546
+ const swarmDir = path16.join(directory, ".swarm");
17547
+ if (!fs7.existsSync(swarmDir)) {
17548
+ fs7.mkdirSync(swarmDir, { recursive: true });
17171
17549
  }
17172
17550
  const artifactFilename = "config-doctor.json";
17173
- const artifactPath = path14.join(swarmDir, artifactFilename);
17551
+ const artifactPath = path16.join(swarmDir, artifactFilename);
17174
17552
  const guiOutput = {
17175
17553
  timestamp: result.timestamp,
17176
17554
  summary: result.summary,
@@ -17191,7 +17569,7 @@ function writeDoctorArtifact(directory, result) {
17191
17569
  } : null
17192
17570
  }))
17193
17571
  };
17194
- fs5.writeFileSync(artifactPath, JSON.stringify(guiOutput, null, 2), "utf-8");
17572
+ fs7.writeFileSync(artifactPath, JSON.stringify(guiOutput, null, 2), "utf-8");
17195
17573
  return artifactPath;
17196
17574
  }
17197
17575
  function shouldRunOnStartup(automationConfig) {
@@ -17531,9 +17909,9 @@ var init_evidence_summary_service = __esm(() => {
17531
17909
  });
17532
17910
 
17533
17911
  // src/cli/index.ts
17534
- import * as fs15 from "fs";
17912
+ import * as fs17 from "fs";
17535
17913
  import * as os5 from "os";
17536
- import * as path25 from "path";
17914
+ import * as path27 from "path";
17537
17915
 
17538
17916
  // src/commands/agents.ts
17539
17917
  function handleAgentsCommand(agents, guardrails) {
@@ -31620,7 +31998,7 @@ async function handleClarifyCommand(_directory, args) {
31620
31998
  }
31621
31999
 
31622
32000
  // src/commands/close.ts
31623
- import { promises as fs4 } from "fs";
32001
+ import { promises as fs6 } from "fs";
31624
32002
  init_manager();
31625
32003
 
31626
32004
  // src/hooks/knowledge-store.ts
@@ -32256,10 +32634,31 @@ async function runAutoPromotion(directory, config3) {
32256
32634
  // src/commands/close.ts
32257
32635
  init_utils2();
32258
32636
 
32637
+ // src/plan/checkpoint.ts
32638
+ init_plan_schema();
32639
+ init_ledger();
32640
+ init_manager2();
32641
+ import * as fs5 from "fs";
32642
+ import * as path9 from "path";
32643
+ async function writeCheckpoint(directory) {
32644
+ try {
32645
+ const plan = await loadPlan(directory);
32646
+ if (!plan)
32647
+ return;
32648
+ const jsonPath = path9.join(directory, "SWARM_PLAN.json");
32649
+ const mdPath = path9.join(directory, "SWARM_PLAN.md");
32650
+ fs5.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
32651
+ const md = derivePlanMarkdown(plan);
32652
+ fs5.writeFileSync(mdPath, md, "utf8");
32653
+ } catch (error93) {
32654
+ console.warn(`[checkpoint] Failed to write SWARM_PLAN checkpoint: ${error93 instanceof Error ? error93.message : String(error93)}`);
32655
+ }
32656
+ }
32657
+
32259
32658
  // src/session/snapshot-writer.ts
32260
32659
  init_utils2();
32261
- import { mkdirSync as mkdirSync3, renameSync as renameSync2 } from "fs";
32262
- import * as path7 from "path";
32660
+ import { mkdirSync as mkdirSync4, renameSync as renameSync4 } from "fs";
32661
+ import * as path10 from "path";
32263
32662
  init_utils();
32264
32663
  var _writeInFlight = Promise.resolve();
32265
32664
  function serializeAgentSession(s) {
@@ -32346,11 +32745,11 @@ async function writeSnapshot(directory, state) {
32346
32745
  }
32347
32746
  const content = JSON.stringify(snapshot, null, 2);
32348
32747
  const resolvedPath = validateSwarmPath(directory, "session/state.json");
32349
- const dir = path7.dirname(resolvedPath);
32350
- mkdirSync3(dir, { recursive: true });
32748
+ const dir = path10.dirname(resolvedPath);
32749
+ mkdirSync4(dir, { recursive: true });
32351
32750
  const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
32352
32751
  await Bun.write(tempPath, content);
32353
- renameSync2(tempPath, resolvedPath);
32752
+ renameSync4(tempPath, resolvedPath);
32354
32753
  } catch (error93) {
32355
32754
  log("[snapshot-writer] write failed", {
32356
32755
  error: error93 instanceof Error ? error93.message : String(error93)
@@ -32709,7 +33108,7 @@ async function handleCloseCommand(directory, _args) {
32709
33108
  const planPath = validateSwarmPath(directory, "plan.json");
32710
33109
  let planData;
32711
33110
  try {
32712
- const content = await fs4.readFile(planPath, "utf-8");
33111
+ const content = await fs6.readFile(planPath, "utf-8");
32713
33112
  planData = JSON.parse(content);
32714
33113
  } catch (error93) {
32715
33114
  return `\u274C Failed to read plan.json: ${error93 instanceof Error ? error93.message : String(error93)}`;
@@ -32776,7 +33175,7 @@ async function handleCloseCommand(directory, _args) {
32776
33175
  }
32777
33176
  }
32778
33177
  try {
32779
- await fs4.writeFile(planPath, JSON.stringify(planData, null, 2), "utf-8");
33178
+ await fs6.writeFile(planPath, JSON.stringify(planData, null, 2), "utf-8");
32780
33179
  } catch (error93) {
32781
33180
  console.warn("[close-command] Failed to write plan.json:", error93);
32782
33181
  }
@@ -32808,7 +33207,7 @@ async function handleCloseCommand(directory, _args) {
32808
33207
  ].join(`
32809
33208
  `);
32810
33209
  try {
32811
- await fs4.writeFile(closeSummaryPath, summaryContent, "utf-8");
33210
+ await fs6.writeFile(closeSummaryPath, summaryContent, "utf-8");
32812
33211
  } catch (error93) {
32813
33212
  console.warn("[close-command] Failed to write close-summary.md:", error93);
32814
33213
  }
@@ -32817,6 +33216,7 @@ async function handleCloseCommand(directory, _args) {
32817
33216
  } catch (error93) {
32818
33217
  console.warn("[close-command] flushPendingSnapshot error:", error93);
32819
33218
  }
33219
+ await writeCheckpoint(directory).catch(() => {});
32820
33220
  swarmState.agentSessions.clear();
32821
33221
  swarmState.delegationChains.clear();
32822
33222
  const warningMsg = warnings.length > 0 ? ` Warnings: ${warnings.join("; ")}.` : "";
@@ -32825,14 +33225,14 @@ async function handleCloseCommand(directory, _args) {
32825
33225
 
32826
33226
  // src/commands/config.ts
32827
33227
  import * as os3 from "os";
32828
- import * as path8 from "path";
33228
+ import * as path11 from "path";
32829
33229
  function getUserConfigDir2() {
32830
- return process.env.XDG_CONFIG_HOME || path8.join(os3.homedir(), ".config");
33230
+ return process.env.XDG_CONFIG_HOME || path11.join(os3.homedir(), ".config");
32831
33231
  }
32832
33232
  async function handleConfigCommand(directory, _args) {
32833
33233
  const config3 = loadPluginConfig(directory);
32834
- const userConfigPath = path8.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
32835
- const projectConfigPath = path8.join(directory, ".opencode", "opencode-swarm.json");
33234
+ const userConfigPath = path11.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
33235
+ const projectConfigPath = path11.join(directory, ".opencode", "opencode-swarm.json");
32836
33236
  const lines = [
32837
33237
  "## Swarm Configuration",
32838
33238
  "",
@@ -32850,7 +33250,7 @@ async function handleConfigCommand(directory, _args) {
32850
33250
  }
32851
33251
 
32852
33252
  // src/hooks/hive-promoter.ts
32853
- import path10 from "path";
33253
+ import path12 from "path";
32854
33254
 
32855
33255
  // src/background/event-bus.ts
32856
33256
  init_utils();
@@ -33105,7 +33505,7 @@ async function promoteToHive(directory, lesson, category) {
33105
33505
  schema_version: 1,
33106
33506
  created_at: new Date().toISOString(),
33107
33507
  updated_at: new Date().toISOString(),
33108
- source_project: path10.basename(directory) || "unknown",
33508
+ source_project: path12.basename(directory) || "unknown",
33109
33509
  encounter_score: 1
33110
33510
  };
33111
33511
  await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
@@ -33183,13 +33583,13 @@ function formatCurationSummary(summary) {
33183
33583
  }
33184
33584
 
33185
33585
  // src/commands/dark-matter.ts
33186
- import path12 from "path";
33586
+ import path14 from "path";
33187
33587
 
33188
33588
  // src/tools/co-change-analyzer.ts
33189
33589
  import * as child_process from "child_process";
33190
33590
  import { randomUUID } from "crypto";
33191
33591
  import { readdir, readFile as readFile2, stat } from "fs/promises";
33192
- import * as path11 from "path";
33592
+ import * as path13 from "path";
33193
33593
  import { promisify } from "util";
33194
33594
  function getExecFileAsync() {
33195
33595
  return promisify(child_process.execFile);
@@ -33291,7 +33691,7 @@ async function scanSourceFiles(dir) {
33291
33691
  try {
33292
33692
  const entries = await readdir(dir, { withFileTypes: true });
33293
33693
  for (const entry of entries) {
33294
- const fullPath = path11.join(dir, entry.name);
33694
+ const fullPath = path13.join(dir, entry.name);
33295
33695
  if (entry.isDirectory()) {
33296
33696
  if (skipDirs.has(entry.name)) {
33297
33697
  continue;
@@ -33299,7 +33699,7 @@ async function scanSourceFiles(dir) {
33299
33699
  const subFiles = await scanSourceFiles(fullPath);
33300
33700
  results.push(...subFiles);
33301
33701
  } else if (entry.isFile()) {
33302
- const ext = path11.extname(entry.name);
33702
+ const ext = path13.extname(entry.name);
33303
33703
  if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
33304
33704
  results.push(fullPath);
33305
33705
  }
@@ -33321,8 +33721,8 @@ async function getStaticEdges(directory) {
33321
33721
  continue;
33322
33722
  }
33323
33723
  try {
33324
- const sourceDir = path11.dirname(sourceFile);
33325
- const resolvedPath = path11.resolve(sourceDir, importPath);
33724
+ const sourceDir = path13.dirname(sourceFile);
33725
+ const resolvedPath = path13.resolve(sourceDir, importPath);
33326
33726
  const extensions = [
33327
33727
  "",
33328
33728
  ".ts",
@@ -33347,8 +33747,8 @@ async function getStaticEdges(directory) {
33347
33747
  if (!targetFile) {
33348
33748
  continue;
33349
33749
  }
33350
- const relSource = path11.relative(directory, sourceFile).replace(/\\/g, "/");
33351
- const relTarget = path11.relative(directory, targetFile).replace(/\\/g, "/");
33750
+ const relSource = path13.relative(directory, sourceFile).replace(/\\/g, "/");
33751
+ const relTarget = path13.relative(directory, targetFile).replace(/\\/g, "/");
33352
33752
  const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
33353
33753
  edges.add(key);
33354
33754
  } catch {}
@@ -33360,7 +33760,7 @@ async function getStaticEdges(directory) {
33360
33760
  function isTestImplementationPair(fileA, fileB) {
33361
33761
  const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
33362
33762
  const getBaseName = (filePath) => {
33363
- const base = path11.basename(filePath);
33763
+ const base = path13.basename(filePath);
33364
33764
  for (const pattern of testPatterns) {
33365
33765
  if (base.endsWith(pattern)) {
33366
33766
  return base.slice(0, -pattern.length);
@@ -33370,16 +33770,16 @@ function isTestImplementationPair(fileA, fileB) {
33370
33770
  };
33371
33771
  const baseA = getBaseName(fileA);
33372
33772
  const baseB = getBaseName(fileB);
33373
- return baseA === baseB && baseA !== path11.basename(fileA) && baseA !== path11.basename(fileB);
33773
+ return baseA === baseB && baseA !== path13.basename(fileA) && baseA !== path13.basename(fileB);
33374
33774
  }
33375
33775
  function hasSharedPrefix(fileA, fileB) {
33376
- const dirA = path11.dirname(fileA);
33377
- const dirB = path11.dirname(fileB);
33776
+ const dirA = path13.dirname(fileA);
33777
+ const dirB = path13.dirname(fileB);
33378
33778
  if (dirA !== dirB) {
33379
33779
  return false;
33380
33780
  }
33381
- const baseA = path11.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
33382
- const baseB = path11.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
33781
+ const baseA = path13.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
33782
+ const baseB = path13.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
33383
33783
  if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
33384
33784
  return true;
33385
33785
  }
@@ -33433,8 +33833,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
33433
33833
  const entries = [];
33434
33834
  const now = new Date().toISOString();
33435
33835
  for (const pair of pairs.slice(0, 10)) {
33436
- const baseA = path11.basename(pair.fileA);
33437
- const baseB = path11.basename(pair.fileB);
33836
+ const baseA = path13.basename(pair.fileA);
33837
+ const baseB = path13.basename(pair.fileB);
33438
33838
  let lesson = `Files ${pair.fileA} and ${pair.fileB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
33439
33839
  if (lesson.length > 280) {
33440
33840
  lesson = `Files ${baseA} and ${baseB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
@@ -33544,7 +33944,7 @@ async function handleDarkMatterCommand(directory, args) {
33544
33944
  const output = formatDarkMatterOutput(pairs);
33545
33945
  if (pairs.length > 0) {
33546
33946
  try {
33547
- const projectName = path12.basename(path12.resolve(directory));
33947
+ const projectName = path14.basename(path14.resolve(directory));
33548
33948
  const entries = darkMatterToKnowledgeEntries(pairs, projectName);
33549
33949
  if (entries.length > 0) {
33550
33950
  const knowledgePath = resolveSwarmKnowledgePath(directory);
@@ -33565,8 +33965,8 @@ async function handleDarkMatterCommand(directory, args) {
33565
33965
 
33566
33966
  // src/services/diagnose-service.ts
33567
33967
  import { execSync } from "child_process";
33568
- import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
33569
- import path13 from "path";
33968
+ import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
33969
+ import path15 from "path";
33570
33970
  import { fileURLToPath } from "url";
33571
33971
  init_manager();
33572
33972
  init_utils2();
@@ -33802,7 +34202,7 @@ async function checkConfigBackups(directory) {
33802
34202
  }
33803
34203
  async function checkGitRepository(directory) {
33804
34204
  try {
33805
- if (!existsSync4(directory) || !statSync3(directory).isDirectory()) {
34205
+ if (!existsSync5(directory) || !statSync3(directory).isDirectory()) {
33806
34206
  return {
33807
34207
  name: "Git Repository",
33808
34208
  status: "\u274C",
@@ -33863,8 +34263,8 @@ async function checkSpecStaleness(directory, plan) {
33863
34263
  };
33864
34264
  }
33865
34265
  async function checkConfigParseability(directory) {
33866
- const configPath = path13.join(directory, ".opencode/opencode-swarm.json");
33867
- if (!existsSync4(configPath)) {
34266
+ const configPath = path15.join(directory, ".opencode/opencode-swarm.json");
34267
+ if (!existsSync5(configPath)) {
33868
34268
  return {
33869
34269
  name: "Config Parseability",
33870
34270
  status: "\u2705",
@@ -33872,7 +34272,7 @@ async function checkConfigParseability(directory) {
33872
34272
  };
33873
34273
  }
33874
34274
  try {
33875
- const content = readFileSync3(configPath, "utf-8");
34275
+ const content = readFileSync5(configPath, "utf-8");
33876
34276
  JSON.parse(content);
33877
34277
  return {
33878
34278
  name: "Config Parseability",
@@ -33910,15 +34310,15 @@ async function checkGrammarWasmFiles() {
33910
34310
  "tree-sitter-ini.wasm",
33911
34311
  "tree-sitter-regex.wasm"
33912
34312
  ];
33913
- const thisDir = path13.dirname(fileURLToPath(import.meta.url));
34313
+ const thisDir = path15.dirname(fileURLToPath(import.meta.url));
33914
34314
  const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/services");
33915
- const grammarDir = isSource ? path13.join(thisDir, "..", "lang", "grammars") : path13.join(thisDir, "lang", "grammars");
34315
+ const grammarDir = isSource ? path15.join(thisDir, "..", "lang", "grammars") : path15.join(thisDir, "lang", "grammars");
33916
34316
  const missing = [];
33917
- if (!existsSync4(path13.join(grammarDir, "tree-sitter.wasm"))) {
34317
+ if (!existsSync5(path15.join(grammarDir, "tree-sitter.wasm"))) {
33918
34318
  missing.push("tree-sitter.wasm (core runtime)");
33919
34319
  }
33920
34320
  for (const file3 of grammarFiles) {
33921
- if (!existsSync4(path13.join(grammarDir, file3))) {
34321
+ if (!existsSync5(path15.join(grammarDir, file3))) {
33922
34322
  missing.push(file3);
33923
34323
  }
33924
34324
  }
@@ -33936,8 +34336,8 @@ async function checkGrammarWasmFiles() {
33936
34336
  };
33937
34337
  }
33938
34338
  async function checkCheckpointManifest(directory) {
33939
- const manifestPath = path13.join(directory, ".swarm/checkpoints.json");
33940
- if (!existsSync4(manifestPath)) {
34339
+ const manifestPath = path15.join(directory, ".swarm/checkpoints.json");
34340
+ if (!existsSync5(manifestPath)) {
33941
34341
  return {
33942
34342
  name: "Checkpoint Manifest",
33943
34343
  status: "\u2705",
@@ -33945,7 +34345,7 @@ async function checkCheckpointManifest(directory) {
33945
34345
  };
33946
34346
  }
33947
34347
  try {
33948
- const content = readFileSync3(manifestPath, "utf-8");
34348
+ const content = readFileSync5(manifestPath, "utf-8");
33949
34349
  const parsed = JSON.parse(content);
33950
34350
  if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
33951
34351
  return {
@@ -33988,8 +34388,8 @@ async function checkCheckpointManifest(directory) {
33988
34388
  }
33989
34389
  }
33990
34390
  async function checkEventStreamIntegrity(directory) {
33991
- const eventsPath = path13.join(directory, ".swarm/events.jsonl");
33992
- if (!existsSync4(eventsPath)) {
34391
+ const eventsPath = path15.join(directory, ".swarm/events.jsonl");
34392
+ if (!existsSync5(eventsPath)) {
33993
34393
  return {
33994
34394
  name: "Event Stream",
33995
34395
  status: "\u2705",
@@ -33997,7 +34397,7 @@ async function checkEventStreamIntegrity(directory) {
33997
34397
  };
33998
34398
  }
33999
34399
  try {
34000
- const content = readFileSync3(eventsPath, "utf-8");
34400
+ const content = readFileSync5(eventsPath, "utf-8");
34001
34401
  const lines = content.split(`
34002
34402
  `).filter((line) => line.trim() !== "");
34003
34403
  let malformedCount = 0;
@@ -34029,8 +34429,8 @@ async function checkEventStreamIntegrity(directory) {
34029
34429
  }
34030
34430
  }
34031
34431
  async function checkSteeringDirectives(directory) {
34032
- const eventsPath = path13.join(directory, ".swarm/events.jsonl");
34033
- if (!existsSync4(eventsPath)) {
34432
+ const eventsPath = path15.join(directory, ".swarm/events.jsonl");
34433
+ if (!existsSync5(eventsPath)) {
34034
34434
  return {
34035
34435
  name: "Steering Directives",
34036
34436
  status: "\u2705",
@@ -34038,7 +34438,7 @@ async function checkSteeringDirectives(directory) {
34038
34438
  };
34039
34439
  }
34040
34440
  try {
34041
- const content = readFileSync3(eventsPath, "utf-8");
34441
+ const content = readFileSync5(eventsPath, "utf-8");
34042
34442
  const lines = content.split(`
34043
34443
  `).filter((line) => line.trim() !== "");
34044
34444
  const directivesIssued = [];
@@ -34085,8 +34485,8 @@ async function checkCurator(directory) {
34085
34485
  detail: "Disabled (enable via curator.enabled)"
34086
34486
  };
34087
34487
  }
34088
- const summaryPath = path13.join(directory, ".swarm/curator-summary.json");
34089
- if (!existsSync4(summaryPath)) {
34488
+ const summaryPath = path15.join(directory, ".swarm/curator-summary.json");
34489
+ if (!existsSync5(summaryPath)) {
34090
34490
  return {
34091
34491
  name: "Curator",
34092
34492
  status: "\u2705",
@@ -34094,7 +34494,7 @@ async function checkCurator(directory) {
34094
34494
  };
34095
34495
  }
34096
34496
  try {
34097
- const content = readFileSync3(summaryPath, "utf-8");
34497
+ const content = readFileSync5(summaryPath, "utf-8");
34098
34498
  const parsed = JSON.parse(content);
34099
34499
  if (typeof parsed.schema_version !== "number" || parsed.schema_version !== 1) {
34100
34500
  return {
@@ -34524,8 +34924,8 @@ async function handleExportCommand(directory, _args) {
34524
34924
  }
34525
34925
  // src/commands/handoff.ts
34526
34926
  init_utils2();
34527
- import crypto3 from "crypto";
34528
- import { renameSync as renameSync4 } from "fs";
34927
+ import crypto4 from "crypto";
34928
+ import { renameSync as renameSync5 } from "fs";
34529
34929
 
34530
34930
  // src/services/handoff-service.ts
34531
34931
  init_utils2();
@@ -34833,9 +35233,9 @@ async function handleHandoffCommand(directory, _args) {
34833
35233
  const handoffData = await getHandoffData(directory);
34834
35234
  const markdown = formatHandoffMarkdown(handoffData);
34835
35235
  const resolvedPath = validateSwarmPath(directory, "handoff.md");
34836
- const tempPath = `${resolvedPath}.tmp.${crypto3.randomUUID()}`;
35236
+ const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
34837
35237
  await Bun.write(tempPath, markdown);
34838
- renameSync4(tempPath, resolvedPath);
35238
+ renameSync5(tempPath, resolvedPath);
34839
35239
  await writeSnapshot(directory, swarmState);
34840
35240
  await flushPendingSnapshot(directory);
34841
35241
  return `## Handoff Brief Written
@@ -34980,14 +35380,14 @@ async function handleHistoryCommand(directory, _args) {
34980
35380
  }
34981
35381
  // src/hooks/knowledge-migrator.ts
34982
35382
  import { randomUUID as randomUUID2 } from "crypto";
34983
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
35383
+ import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
34984
35384
  import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
34985
- import * as path15 from "path";
35385
+ import * as path17 from "path";
34986
35386
  async function migrateContextToKnowledge(directory, config3) {
34987
- const sentinelPath = path15.join(directory, ".swarm", ".knowledge-migrated");
34988
- const contextPath = path15.join(directory, ".swarm", "context.md");
35387
+ const sentinelPath = path17.join(directory, ".swarm", ".knowledge-migrated");
35388
+ const contextPath = path17.join(directory, ".swarm", "context.md");
34989
35389
  const knowledgePath = resolveSwarmKnowledgePath(directory);
34990
- if (existsSync6(sentinelPath)) {
35390
+ if (existsSync7(sentinelPath)) {
34991
35391
  return {
34992
35392
  migrated: false,
34993
35393
  entriesMigrated: 0,
@@ -34996,7 +35396,7 @@ async function migrateContextToKnowledge(directory, config3) {
34996
35396
  skippedReason: "sentinel-exists"
34997
35397
  };
34998
35398
  }
34999
- if (!existsSync6(contextPath)) {
35399
+ if (!existsSync7(contextPath)) {
35000
35400
  return {
35001
35401
  migrated: false,
35002
35402
  entriesMigrated: 0,
@@ -35181,16 +35581,16 @@ function truncateLesson(text) {
35181
35581
  return `${text.slice(0, 277)}...`;
35182
35582
  }
35183
35583
  function inferProjectName(directory) {
35184
- const packageJsonPath = path15.join(directory, "package.json");
35185
- if (existsSync6(packageJsonPath)) {
35584
+ const packageJsonPath = path17.join(directory, "package.json");
35585
+ if (existsSync7(packageJsonPath)) {
35186
35586
  try {
35187
- const pkg = JSON.parse(readFileSync5(packageJsonPath, "utf-8"));
35587
+ const pkg = JSON.parse(readFileSync7(packageJsonPath, "utf-8"));
35188
35588
  if (pkg.name && typeof pkg.name === "string") {
35189
35589
  return pkg.name;
35190
35590
  }
35191
35591
  } catch {}
35192
35592
  }
35193
- return path15.basename(directory);
35593
+ return path17.basename(directory);
35194
35594
  }
35195
35595
  async function writeSentinel(sentinelPath, migrated, dropped) {
35196
35596
  const sentinel = {
@@ -35202,7 +35602,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
35202
35602
  schema_version: 1,
35203
35603
  migration_tool: "knowledge-migrator.ts"
35204
35604
  };
35205
- await mkdir3(path15.dirname(sentinelPath), { recursive: true });
35605
+ await mkdir3(path17.dirname(sentinelPath), { recursive: true });
35206
35606
  await writeFile3(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
35207
35607
  }
35208
35608
 
@@ -35438,20 +35838,20 @@ async function handlePlanCommand(directory, args) {
35438
35838
  // src/services/preflight-service.ts
35439
35839
  init_manager();
35440
35840
  init_manager2();
35441
- import * as fs11 from "fs";
35442
- import * as path21 from "path";
35841
+ import * as fs13 from "fs";
35842
+ import * as path23 from "path";
35443
35843
 
35444
35844
  // src/tools/lint.ts
35445
- import * as fs7 from "fs";
35446
- import * as path17 from "path";
35845
+ import * as fs9 from "fs";
35846
+ import * as path19 from "path";
35447
35847
 
35448
35848
  // src/build/discovery.ts
35449
- import * as fs6 from "fs";
35450
- import * as path16 from "path";
35849
+ import * as fs8 from "fs";
35850
+ import * as path18 from "path";
35451
35851
 
35452
35852
  // src/lang/detector.ts
35453
35853
  import { access, readdir as readdir2 } from "fs/promises";
35454
- import { extname as extname2, join as join11 } from "path";
35854
+ import { extname as extname2, join as join13 } from "path";
35455
35855
 
35456
35856
  // src/lang/profiles.ts
35457
35857
  class LanguageRegistry {
@@ -36376,7 +36776,7 @@ async function detectProjectLanguages(projectDir) {
36376
36776
  if (detectFile.includes("*") || detectFile.includes("?"))
36377
36777
  continue;
36378
36778
  try {
36379
- await access(join11(dir, detectFile));
36779
+ await access(join13(dir, detectFile));
36380
36780
  detected.add(profile.id);
36381
36781
  break;
36382
36782
  } catch {}
@@ -36397,7 +36797,7 @@ async function detectProjectLanguages(projectDir) {
36397
36797
  const topEntries = await readdir2(projectDir, { withFileTypes: true });
36398
36798
  for (const entry of topEntries) {
36399
36799
  if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
36400
- await scanDir(join11(projectDir, entry.name));
36800
+ await scanDir(join13(projectDir, entry.name));
36401
36801
  }
36402
36802
  }
36403
36803
  } catch {}
@@ -36540,16 +36940,16 @@ function findBuildFiles(workingDir, patterns) {
36540
36940
  if (pattern.includes("*")) {
36541
36941
  const dir = workingDir;
36542
36942
  try {
36543
- const files = fs6.readdirSync(dir);
36943
+ const files = fs8.readdirSync(dir);
36544
36944
  const regex = simpleGlobToRegex(pattern);
36545
36945
  const matches = files.filter((f) => regex.test(f));
36546
36946
  if (matches.length > 0) {
36547
- return path16.join(dir, matches[0]);
36947
+ return path18.join(dir, matches[0]);
36548
36948
  }
36549
36949
  } catch {}
36550
36950
  } else {
36551
- const filePath = path16.join(workingDir, pattern);
36552
- if (fs6.existsSync(filePath)) {
36951
+ const filePath = path18.join(workingDir, pattern);
36952
+ if (fs8.existsSync(filePath)) {
36553
36953
  return filePath;
36554
36954
  }
36555
36955
  }
@@ -36557,12 +36957,12 @@ function findBuildFiles(workingDir, patterns) {
36557
36957
  return null;
36558
36958
  }
36559
36959
  function getRepoDefinedScripts(workingDir, scripts) {
36560
- const packageJsonPath = path16.join(workingDir, "package.json");
36561
- if (!fs6.existsSync(packageJsonPath)) {
36960
+ const packageJsonPath = path18.join(workingDir, "package.json");
36961
+ if (!fs8.existsSync(packageJsonPath)) {
36562
36962
  return [];
36563
36963
  }
36564
36964
  try {
36565
- const content = fs6.readFileSync(packageJsonPath, "utf-8");
36965
+ const content = fs8.readFileSync(packageJsonPath, "utf-8");
36566
36966
  const pkg = JSON.parse(content);
36567
36967
  if (!pkg.scripts || typeof pkg.scripts !== "object") {
36568
36968
  return [];
@@ -36598,8 +36998,8 @@ function findAllBuildFiles(workingDir) {
36598
36998
  const regex = simpleGlobToRegex(pattern);
36599
36999
  findFilesRecursive(workingDir, regex, allBuildFiles);
36600
37000
  } else {
36601
- const filePath = path16.join(workingDir, pattern);
36602
- if (fs6.existsSync(filePath)) {
37001
+ const filePath = path18.join(workingDir, pattern);
37002
+ if (fs8.existsSync(filePath)) {
36603
37003
  allBuildFiles.add(filePath);
36604
37004
  }
36605
37005
  }
@@ -36609,9 +37009,9 @@ function findAllBuildFiles(workingDir) {
36609
37009
  }
36610
37010
  function findFilesRecursive(dir, regex, results) {
36611
37011
  try {
36612
- const entries = fs6.readdirSync(dir, { withFileTypes: true });
37012
+ const entries = fs8.readdirSync(dir, { withFileTypes: true });
36613
37013
  for (const entry of entries) {
36614
- const fullPath = path16.join(dir, entry.name);
37014
+ const fullPath = path18.join(dir, entry.name);
36615
37015
  if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
36616
37016
  findFilesRecursive(fullPath, regex, results);
36617
37017
  } else if (entry.isFile() && regex.test(entry.name)) {
@@ -36634,8 +37034,8 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
36634
37034
  let foundCommand = false;
36635
37035
  for (const cmd of sortedCommands) {
36636
37036
  if (cmd.detectFile) {
36637
- const detectFilePath = path16.join(workingDir, cmd.detectFile);
36638
- if (!fs6.existsSync(detectFilePath)) {
37037
+ const detectFilePath = path18.join(workingDir, cmd.detectFile);
37038
+ if (!fs8.existsSync(detectFilePath)) {
36639
37039
  continue;
36640
37040
  }
36641
37041
  }
@@ -36782,9 +37182,9 @@ function validateArgs(args) {
36782
37182
  }
36783
37183
  function getLinterCommand(linter, mode, projectDir) {
36784
37184
  const isWindows = process.platform === "win32";
36785
- const binDir = path17.join(projectDir, "node_modules", ".bin");
36786
- const biomeBin = isWindows ? path17.join(binDir, "biome.EXE") : path17.join(binDir, "biome");
36787
- const eslintBin = isWindows ? path17.join(binDir, "eslint.cmd") : path17.join(binDir, "eslint");
37185
+ const binDir = path19.join(projectDir, "node_modules", ".bin");
37186
+ const biomeBin = isWindows ? path19.join(binDir, "biome.EXE") : path19.join(binDir, "biome");
37187
+ const eslintBin = isWindows ? path19.join(binDir, "eslint.cmd") : path19.join(binDir, "eslint");
36788
37188
  switch (linter) {
36789
37189
  case "biome":
36790
37190
  if (mode === "fix") {
@@ -36800,7 +37200,7 @@ function getLinterCommand(linter, mode, projectDir) {
36800
37200
  }
36801
37201
  function getAdditionalLinterCommand(linter, mode, cwd) {
36802
37202
  const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
36803
- const gradlew = fs7.existsSync(path17.join(cwd, gradlewName)) ? path17.join(cwd, gradlewName) : null;
37203
+ const gradlew = fs9.existsSync(path19.join(cwd, gradlewName)) ? path19.join(cwd, gradlewName) : null;
36804
37204
  switch (linter) {
36805
37205
  case "ruff":
36806
37206
  return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
@@ -36834,12 +37234,12 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
36834
37234
  }
36835
37235
  }
36836
37236
  function detectRuff(cwd) {
36837
- if (fs7.existsSync(path17.join(cwd, "ruff.toml")))
37237
+ if (fs9.existsSync(path19.join(cwd, "ruff.toml")))
36838
37238
  return isCommandAvailable("ruff");
36839
37239
  try {
36840
- const pyproject = path17.join(cwd, "pyproject.toml");
36841
- if (fs7.existsSync(pyproject)) {
36842
- const content = fs7.readFileSync(pyproject, "utf-8");
37240
+ const pyproject = path19.join(cwd, "pyproject.toml");
37241
+ if (fs9.existsSync(pyproject)) {
37242
+ const content = fs9.readFileSync(pyproject, "utf-8");
36843
37243
  if (content.includes("[tool.ruff]"))
36844
37244
  return isCommandAvailable("ruff");
36845
37245
  }
@@ -36847,21 +37247,21 @@ function detectRuff(cwd) {
36847
37247
  return false;
36848
37248
  }
36849
37249
  function detectClippy(cwd) {
36850
- return fs7.existsSync(path17.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
37250
+ return fs9.existsSync(path19.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
36851
37251
  }
36852
37252
  function detectGolangciLint(cwd) {
36853
- return fs7.existsSync(path17.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
37253
+ return fs9.existsSync(path19.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
36854
37254
  }
36855
37255
  function detectCheckstyle(cwd) {
36856
- const hasMaven = fs7.existsSync(path17.join(cwd, "pom.xml"));
36857
- const hasGradle = fs7.existsSync(path17.join(cwd, "build.gradle")) || fs7.existsSync(path17.join(cwd, "build.gradle.kts"));
36858
- const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs7.existsSync(path17.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
37256
+ const hasMaven = fs9.existsSync(path19.join(cwd, "pom.xml"));
37257
+ const hasGradle = fs9.existsSync(path19.join(cwd, "build.gradle")) || fs9.existsSync(path19.join(cwd, "build.gradle.kts"));
37258
+ const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs9.existsSync(path19.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
36859
37259
  return (hasMaven || hasGradle) && hasBinary;
36860
37260
  }
36861
37261
  function detectKtlint(cwd) {
36862
- const hasKotlin = fs7.existsSync(path17.join(cwd, "build.gradle.kts")) || fs7.existsSync(path17.join(cwd, "build.gradle")) || (() => {
37262
+ const hasKotlin = fs9.existsSync(path19.join(cwd, "build.gradle.kts")) || fs9.existsSync(path19.join(cwd, "build.gradle")) || (() => {
36863
37263
  try {
36864
- return fs7.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
37264
+ return fs9.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
36865
37265
  } catch {
36866
37266
  return false;
36867
37267
  }
@@ -36870,7 +37270,7 @@ function detectKtlint(cwd) {
36870
37270
  }
36871
37271
  function detectDotnetFormat(cwd) {
36872
37272
  try {
36873
- const files = fs7.readdirSync(cwd);
37273
+ const files = fs9.readdirSync(cwd);
36874
37274
  const hasCsproj = files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"));
36875
37275
  return hasCsproj && isCommandAvailable("dotnet");
36876
37276
  } catch {
@@ -36878,14 +37278,14 @@ function detectDotnetFormat(cwd) {
36878
37278
  }
36879
37279
  }
36880
37280
  function detectCppcheck(cwd) {
36881
- if (fs7.existsSync(path17.join(cwd, "CMakeLists.txt"))) {
37281
+ if (fs9.existsSync(path19.join(cwd, "CMakeLists.txt"))) {
36882
37282
  return isCommandAvailable("cppcheck");
36883
37283
  }
36884
37284
  try {
36885
- const dirsToCheck = [cwd, path17.join(cwd, "src")];
37285
+ const dirsToCheck = [cwd, path19.join(cwd, "src")];
36886
37286
  const hasCpp = dirsToCheck.some((dir) => {
36887
37287
  try {
36888
- return fs7.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
37288
+ return fs9.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
36889
37289
  } catch {
36890
37290
  return false;
36891
37291
  }
@@ -36896,13 +37296,13 @@ function detectCppcheck(cwd) {
36896
37296
  }
36897
37297
  }
36898
37298
  function detectSwiftlint(cwd) {
36899
- return fs7.existsSync(path17.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
37299
+ return fs9.existsSync(path19.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
36900
37300
  }
36901
37301
  function detectDartAnalyze(cwd) {
36902
- return fs7.existsSync(path17.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
37302
+ return fs9.existsSync(path19.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
36903
37303
  }
36904
37304
  function detectRubocop(cwd) {
36905
- return (fs7.existsSync(path17.join(cwd, "Gemfile")) || fs7.existsSync(path17.join(cwd, "gems.rb")) || fs7.existsSync(path17.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
37305
+ return (fs9.existsSync(path19.join(cwd, "Gemfile")) || fs9.existsSync(path19.join(cwd, "gems.rb")) || fs9.existsSync(path19.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
36906
37306
  }
36907
37307
  function detectAdditionalLinter(cwd) {
36908
37308
  if (detectRuff(cwd))
@@ -36927,17 +37327,53 @@ function detectAdditionalLinter(cwd) {
36927
37327
  return "rubocop";
36928
37328
  return null;
36929
37329
  }
37330
+ function findBinInAncestors(startDir, binName) {
37331
+ let dir = startDir;
37332
+ while (true) {
37333
+ const candidate = path19.join(dir, "node_modules", ".bin", binName);
37334
+ if (fs9.existsSync(candidate))
37335
+ return candidate;
37336
+ const parent = path19.dirname(dir);
37337
+ if (parent === dir)
37338
+ break;
37339
+ dir = parent;
37340
+ }
37341
+ return null;
37342
+ }
37343
+ function findBinInEnvPath(binName) {
37344
+ const searchPath = process.env.PATH ?? "";
37345
+ for (const dir of searchPath.split(path19.delimiter)) {
37346
+ if (!dir)
37347
+ continue;
37348
+ const candidate = path19.join(dir, binName);
37349
+ if (fs9.existsSync(candidate))
37350
+ return candidate;
37351
+ }
37352
+ return null;
37353
+ }
36930
37354
  async function detectAvailableLinter(directory) {
36931
- const _DETECT_TIMEOUT = 2000;
36932
37355
  if (!directory)
36933
37356
  return null;
36934
- if (!fs7.existsSync(directory))
37357
+ if (!fs9.existsSync(directory))
36935
37358
  return null;
36936
37359
  const projectDir = directory;
36937
37360
  const isWindows = process.platform === "win32";
36938
- const biomeBin = isWindows ? path17.join(projectDir, "node_modules", ".bin", "biome.EXE") : path17.join(projectDir, "node_modules", ".bin", "biome");
36939
- const eslintBin = isWindows ? path17.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path17.join(projectDir, "node_modules", ".bin", "eslint");
36940
- return _detectAvailableLinter(projectDir, biomeBin, eslintBin);
37361
+ const biomeBin = isWindows ? path19.join(projectDir, "node_modules", ".bin", "biome.EXE") : path19.join(projectDir, "node_modules", ".bin", "biome");
37362
+ const eslintBin = isWindows ? path19.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path19.join(projectDir, "node_modules", ".bin", "eslint");
37363
+ const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
37364
+ if (localResult)
37365
+ return localResult;
37366
+ const biomeAncestor = findBinInAncestors(path19.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
37367
+ const eslintAncestor = findBinInAncestors(path19.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
37368
+ if (biomeAncestor || eslintAncestor) {
37369
+ return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
37370
+ }
37371
+ const pathBiome = findBinInEnvPath(isWindows ? "biome.EXE" : "biome");
37372
+ const pathEslint = findBinInEnvPath(isWindows ? "eslint.cmd" : "eslint");
37373
+ if (pathBiome || pathEslint) {
37374
+ return _detectAvailableLinter(projectDir, pathBiome ?? biomeBin, pathEslint ?? eslintBin);
37375
+ }
37376
+ return null;
36941
37377
  }
36942
37378
  async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
36943
37379
  const DETECT_TIMEOUT = 2000;
@@ -36951,7 +37387,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
36951
37387
  const result = await Promise.race([biomeExit, timeout]);
36952
37388
  if (result === "timeout") {
36953
37389
  biomeProc.kill();
36954
- } else if (biomeProc.exitCode === 0 && fs7.existsSync(biomeBin)) {
37390
+ } else if (biomeProc.exitCode === 0 && fs9.existsSync(biomeBin)) {
36955
37391
  return "biome";
36956
37392
  }
36957
37393
  } catch {}
@@ -36965,7 +37401,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
36965
37401
  const result = await Promise.race([eslintExit, timeout]);
36966
37402
  if (result === "timeout") {
36967
37403
  eslintProc.kill();
36968
- } else if (eslintProc.exitCode === 0 && fs7.existsSync(eslintBin)) {
37404
+ } else if (eslintProc.exitCode === 0 && fs9.existsSync(eslintBin)) {
36969
37405
  return "eslint";
36970
37406
  }
36971
37407
  } catch {}
@@ -37135,8 +37571,8 @@ For Rust: rustup component add clippy`
37135
37571
  });
37136
37572
 
37137
37573
  // src/tools/secretscan.ts
37138
- import * as fs8 from "fs";
37139
- import * as path18 from "path";
37574
+ import * as fs10 from "fs";
37575
+ import * as path20 from "path";
37140
37576
  var MAX_FILE_PATH_LENGTH = 500;
37141
37577
  var MAX_FILE_SIZE_BYTES = 512 * 1024;
37142
37578
  var MAX_FILES_SCANNED = 1000;
@@ -37363,11 +37799,11 @@ function isGlobOrPathPattern(pattern) {
37363
37799
  return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
37364
37800
  }
37365
37801
  function loadSecretScanIgnore(scanDir) {
37366
- const ignorePath = path18.join(scanDir, ".secretscanignore");
37802
+ const ignorePath = path20.join(scanDir, ".secretscanignore");
37367
37803
  try {
37368
- if (!fs8.existsSync(ignorePath))
37804
+ if (!fs10.existsSync(ignorePath))
37369
37805
  return [];
37370
- const content = fs8.readFileSync(ignorePath, "utf8");
37806
+ const content = fs10.readFileSync(ignorePath, "utf8");
37371
37807
  const patterns = [];
37372
37808
  for (const rawLine of content.split(/\r?\n/)) {
37373
37809
  const line = rawLine.trim();
@@ -37386,7 +37822,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
37386
37822
  if (exactNames.has(entry))
37387
37823
  return true;
37388
37824
  for (const pattern of globPatterns) {
37389
- if (path18.matchesGlob(relPath, pattern))
37825
+ if (path20.matchesGlob(relPath, pattern))
37390
37826
  return true;
37391
37827
  }
37392
37828
  return false;
@@ -37407,7 +37843,7 @@ function validateDirectoryInput(dir) {
37407
37843
  return null;
37408
37844
  }
37409
37845
  function isBinaryFile(filePath, buffer) {
37410
- const ext = path18.extname(filePath).toLowerCase();
37846
+ const ext = path20.extname(filePath).toLowerCase();
37411
37847
  if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
37412
37848
  return true;
37413
37849
  }
@@ -37482,11 +37918,11 @@ function createRedactedContext(line, findings) {
37482
37918
  result += line.slice(lastEnd);
37483
37919
  return result;
37484
37920
  }
37485
- var O_NOFOLLOW = process.platform !== "win32" ? fs8.constants.O_NOFOLLOW : undefined;
37921
+ var O_NOFOLLOW = process.platform !== "win32" ? fs10.constants.O_NOFOLLOW : undefined;
37486
37922
  function scanFileForSecrets(filePath) {
37487
37923
  const findings = [];
37488
37924
  try {
37489
- const lstat = fs8.lstatSync(filePath);
37925
+ const lstat = fs10.lstatSync(filePath);
37490
37926
  if (lstat.isSymbolicLink()) {
37491
37927
  return findings;
37492
37928
  }
@@ -37495,14 +37931,14 @@ function scanFileForSecrets(filePath) {
37495
37931
  }
37496
37932
  let buffer;
37497
37933
  if (O_NOFOLLOW !== undefined) {
37498
- const fd = fs8.openSync(filePath, "r", O_NOFOLLOW);
37934
+ const fd = fs10.openSync(filePath, "r", O_NOFOLLOW);
37499
37935
  try {
37500
- buffer = fs8.readFileSync(fd);
37936
+ buffer = fs10.readFileSync(fd);
37501
37937
  } finally {
37502
- fs8.closeSync(fd);
37938
+ fs10.closeSync(fd);
37503
37939
  }
37504
37940
  } else {
37505
- buffer = fs8.readFileSync(filePath);
37941
+ buffer = fs10.readFileSync(filePath);
37506
37942
  }
37507
37943
  if (isBinaryFile(filePath, buffer)) {
37508
37944
  return findings;
@@ -37544,9 +37980,9 @@ function isSymlinkLoop(realPath, visited) {
37544
37980
  return false;
37545
37981
  }
37546
37982
  function isPathWithinScope(realPath, scanDir) {
37547
- const resolvedScanDir = path18.resolve(scanDir);
37548
- const resolvedRealPath = path18.resolve(realPath);
37549
- return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path18.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
37983
+ const resolvedScanDir = path20.resolve(scanDir);
37984
+ const resolvedRealPath = path20.resolve(realPath);
37985
+ return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path20.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
37550
37986
  }
37551
37987
  function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
37552
37988
  skippedDirs: 0,
@@ -37557,7 +37993,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
37557
37993
  const files = [];
37558
37994
  let entries;
37559
37995
  try {
37560
- entries = fs8.readdirSync(dir);
37996
+ entries = fs10.readdirSync(dir);
37561
37997
  } catch {
37562
37998
  stats.fileErrors++;
37563
37999
  return files;
@@ -37572,15 +38008,15 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
37572
38008
  return a.localeCompare(b);
37573
38009
  });
37574
38010
  for (const entry of entries) {
37575
- const fullPath = path18.join(dir, entry);
37576
- const relPath = path18.relative(scanDir, fullPath).replace(/\\/g, "/");
38011
+ const fullPath = path20.join(dir, entry);
38012
+ const relPath = path20.relative(scanDir, fullPath).replace(/\\/g, "/");
37577
38013
  if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
37578
38014
  stats.skippedDirs++;
37579
38015
  continue;
37580
38016
  }
37581
38017
  let lstat;
37582
38018
  try {
37583
- lstat = fs8.lstatSync(fullPath);
38019
+ lstat = fs10.lstatSync(fullPath);
37584
38020
  } catch {
37585
38021
  stats.fileErrors++;
37586
38022
  continue;
@@ -37592,7 +38028,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
37592
38028
  if (lstat.isDirectory()) {
37593
38029
  let realPath;
37594
38030
  try {
37595
- realPath = fs8.realpathSync(fullPath);
38031
+ realPath = fs10.realpathSync(fullPath);
37596
38032
  } catch {
37597
38033
  stats.fileErrors++;
37598
38034
  continue;
@@ -37608,7 +38044,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
37608
38044
  const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
37609
38045
  files.push(...subFiles);
37610
38046
  } else if (lstat.isFile()) {
37611
- const ext = path18.extname(fullPath).toLowerCase();
38047
+ const ext = path20.extname(fullPath).toLowerCase();
37612
38048
  if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
37613
38049
  files.push(fullPath);
37614
38050
  } else {
@@ -37674,8 +38110,8 @@ var secretscan = createSwarmTool({
37674
38110
  }
37675
38111
  }
37676
38112
  try {
37677
- const scanDir = path18.resolve(directory);
37678
- if (!fs8.existsSync(scanDir)) {
38113
+ const scanDir = path20.resolve(directory);
38114
+ if (!fs10.existsSync(scanDir)) {
37679
38115
  const errorResult = {
37680
38116
  error: "directory not found",
37681
38117
  scan_dir: directory,
@@ -37686,7 +38122,7 @@ var secretscan = createSwarmTool({
37686
38122
  };
37687
38123
  return JSON.stringify(errorResult, null, 2);
37688
38124
  }
37689
- const dirStat = fs8.statSync(scanDir);
38125
+ const dirStat = fs10.statSync(scanDir);
37690
38126
  if (!dirStat.isDirectory()) {
37691
38127
  const errorResult = {
37692
38128
  error: "target must be a directory, not a file",
@@ -37737,7 +38173,7 @@ var secretscan = createSwarmTool({
37737
38173
  break;
37738
38174
  const fileFindings = scanFileForSecrets(filePath);
37739
38175
  try {
37740
- const stat2 = fs8.statSync(filePath);
38176
+ const stat2 = fs10.statSync(filePath);
37741
38177
  if (stat2.size > MAX_FILE_SIZE_BYTES) {
37742
38178
  skippedFiles++;
37743
38179
  continue;
@@ -37824,12 +38260,12 @@ async function runSecretscan(directory) {
37824
38260
  }
37825
38261
 
37826
38262
  // src/tools/test-runner.ts
37827
- import * as fs10 from "fs";
37828
- import * as path20 from "path";
38263
+ import * as fs12 from "fs";
38264
+ import * as path22 from "path";
37829
38265
 
37830
38266
  // src/tools/resolve-working-directory.ts
37831
- import * as fs9 from "fs";
37832
- import * as path19 from "path";
38267
+ import * as fs11 from "fs";
38268
+ import * as path21 from "path";
37833
38269
  function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
37834
38270
  if (workingDirectory == null || workingDirectory === "") {
37835
38271
  return { success: true, directory: fallbackDirectory };
@@ -37849,17 +38285,17 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
37849
38285
  };
37850
38286
  }
37851
38287
  }
37852
- const normalizedDir = path19.normalize(workingDirectory);
37853
- const pathParts = normalizedDir.split(path19.sep);
38288
+ const normalizedDir = path21.normalize(workingDirectory);
38289
+ const pathParts = normalizedDir.split(path21.sep);
37854
38290
  if (pathParts.includes("..")) {
37855
38291
  return {
37856
38292
  success: false,
37857
38293
  message: "Invalid working_directory: path traversal sequences (..) are not allowed"
37858
38294
  };
37859
38295
  }
37860
- const resolvedDir = path19.resolve(normalizedDir);
38296
+ const resolvedDir = path21.resolve(normalizedDir);
37861
38297
  try {
37862
- const realPath = fs9.realpathSync(resolvedDir);
38298
+ const realPath = fs11.realpathSync(resolvedDir);
37863
38299
  return { success: true, directory: realPath };
37864
38300
  } catch {
37865
38301
  return {
@@ -37940,19 +38376,19 @@ function hasDevDependency(devDeps, ...patterns) {
37940
38376
  return hasPackageJsonDependency(devDeps, ...patterns);
37941
38377
  }
37942
38378
  function detectGoTest(cwd) {
37943
- return fs10.existsSync(path20.join(cwd, "go.mod")) && isCommandAvailable("go");
38379
+ return fs12.existsSync(path22.join(cwd, "go.mod")) && isCommandAvailable("go");
37944
38380
  }
37945
38381
  function detectJavaMaven(cwd) {
37946
- return fs10.existsSync(path20.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
38382
+ return fs12.existsSync(path22.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
37947
38383
  }
37948
38384
  function detectGradle(cwd) {
37949
- const hasBuildFile = fs10.existsSync(path20.join(cwd, "build.gradle")) || fs10.existsSync(path20.join(cwd, "build.gradle.kts"));
37950
- const hasGradlew = fs10.existsSync(path20.join(cwd, "gradlew")) || fs10.existsSync(path20.join(cwd, "gradlew.bat"));
38385
+ const hasBuildFile = fs12.existsSync(path22.join(cwd, "build.gradle")) || fs12.existsSync(path22.join(cwd, "build.gradle.kts"));
38386
+ const hasGradlew = fs12.existsSync(path22.join(cwd, "gradlew")) || fs12.existsSync(path22.join(cwd, "gradlew.bat"));
37951
38387
  return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
37952
38388
  }
37953
38389
  function detectDotnetTest(cwd) {
37954
38390
  try {
37955
- const files = fs10.readdirSync(cwd);
38391
+ const files = fs12.readdirSync(cwd);
37956
38392
  const hasCsproj = files.some((f) => f.endsWith(".csproj"));
37957
38393
  return hasCsproj && isCommandAvailable("dotnet");
37958
38394
  } catch {
@@ -37960,32 +38396,32 @@ function detectDotnetTest(cwd) {
37960
38396
  }
37961
38397
  }
37962
38398
  function detectCTest(cwd) {
37963
- const hasSource = fs10.existsSync(path20.join(cwd, "CMakeLists.txt"));
37964
- const hasBuildCache = fs10.existsSync(path20.join(cwd, "CMakeCache.txt")) || fs10.existsSync(path20.join(cwd, "build", "CMakeCache.txt"));
38399
+ const hasSource = fs12.existsSync(path22.join(cwd, "CMakeLists.txt"));
38400
+ const hasBuildCache = fs12.existsSync(path22.join(cwd, "CMakeCache.txt")) || fs12.existsSync(path22.join(cwd, "build", "CMakeCache.txt"));
37965
38401
  return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
37966
38402
  }
37967
38403
  function detectSwiftTest(cwd) {
37968
- return fs10.existsSync(path20.join(cwd, "Package.swift")) && isCommandAvailable("swift");
38404
+ return fs12.existsSync(path22.join(cwd, "Package.swift")) && isCommandAvailable("swift");
37969
38405
  }
37970
38406
  function detectDartTest(cwd) {
37971
- return fs10.existsSync(path20.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
38407
+ return fs12.existsSync(path22.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
37972
38408
  }
37973
38409
  function detectRSpec(cwd) {
37974
- const hasRSpecFile = fs10.existsSync(path20.join(cwd, ".rspec"));
37975
- const hasGemfile = fs10.existsSync(path20.join(cwd, "Gemfile"));
37976
- const hasSpecDir = fs10.existsSync(path20.join(cwd, "spec"));
38410
+ const hasRSpecFile = fs12.existsSync(path22.join(cwd, ".rspec"));
38411
+ const hasGemfile = fs12.existsSync(path22.join(cwd, "Gemfile"));
38412
+ const hasSpecDir = fs12.existsSync(path22.join(cwd, "spec"));
37977
38413
  const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
37978
38414
  return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
37979
38415
  }
37980
38416
  function detectMinitest(cwd) {
37981
- return fs10.existsSync(path20.join(cwd, "test")) && (fs10.existsSync(path20.join(cwd, "Gemfile")) || fs10.existsSync(path20.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
38417
+ return fs12.existsSync(path22.join(cwd, "test")) && (fs12.existsSync(path22.join(cwd, "Gemfile")) || fs12.existsSync(path22.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
37982
38418
  }
37983
38419
  async function detectTestFramework(cwd) {
37984
38420
  const baseDir = cwd;
37985
38421
  try {
37986
- const packageJsonPath = path20.join(baseDir, "package.json");
37987
- if (fs10.existsSync(packageJsonPath)) {
37988
- const content = fs10.readFileSync(packageJsonPath, "utf-8");
38422
+ const packageJsonPath = path22.join(baseDir, "package.json");
38423
+ if (fs12.existsSync(packageJsonPath)) {
38424
+ const content = fs12.readFileSync(packageJsonPath, "utf-8");
37989
38425
  const pkg = JSON.parse(content);
37990
38426
  const _deps = pkg.dependencies || {};
37991
38427
  const devDeps = pkg.devDependencies || {};
@@ -38004,38 +38440,38 @@ async function detectTestFramework(cwd) {
38004
38440
  return "jest";
38005
38441
  if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
38006
38442
  return "mocha";
38007
- if (fs10.existsSync(path20.join(baseDir, "bun.lockb")) || fs10.existsSync(path20.join(baseDir, "bun.lock"))) {
38443
+ if (fs12.existsSync(path22.join(baseDir, "bun.lockb")) || fs12.existsSync(path22.join(baseDir, "bun.lock"))) {
38008
38444
  if (scripts.test?.includes("bun"))
38009
38445
  return "bun";
38010
38446
  }
38011
38447
  }
38012
38448
  } catch {}
38013
38449
  try {
38014
- const pyprojectTomlPath = path20.join(baseDir, "pyproject.toml");
38015
- const setupCfgPath = path20.join(baseDir, "setup.cfg");
38016
- const requirementsTxtPath = path20.join(baseDir, "requirements.txt");
38017
- if (fs10.existsSync(pyprojectTomlPath)) {
38018
- const content = fs10.readFileSync(pyprojectTomlPath, "utf-8");
38450
+ const pyprojectTomlPath = path22.join(baseDir, "pyproject.toml");
38451
+ const setupCfgPath = path22.join(baseDir, "setup.cfg");
38452
+ const requirementsTxtPath = path22.join(baseDir, "requirements.txt");
38453
+ if (fs12.existsSync(pyprojectTomlPath)) {
38454
+ const content = fs12.readFileSync(pyprojectTomlPath, "utf-8");
38019
38455
  if (content.includes("[tool.pytest"))
38020
38456
  return "pytest";
38021
38457
  if (content.includes("pytest"))
38022
38458
  return "pytest";
38023
38459
  }
38024
- if (fs10.existsSync(setupCfgPath)) {
38025
- const content = fs10.readFileSync(setupCfgPath, "utf-8");
38460
+ if (fs12.existsSync(setupCfgPath)) {
38461
+ const content = fs12.readFileSync(setupCfgPath, "utf-8");
38026
38462
  if (content.includes("[pytest]"))
38027
38463
  return "pytest";
38028
38464
  }
38029
- if (fs10.existsSync(requirementsTxtPath)) {
38030
- const content = fs10.readFileSync(requirementsTxtPath, "utf-8");
38465
+ if (fs12.existsSync(requirementsTxtPath)) {
38466
+ const content = fs12.readFileSync(requirementsTxtPath, "utf-8");
38031
38467
  if (content.includes("pytest"))
38032
38468
  return "pytest";
38033
38469
  }
38034
38470
  } catch {}
38035
38471
  try {
38036
- const cargoTomlPath = path20.join(baseDir, "Cargo.toml");
38037
- if (fs10.existsSync(cargoTomlPath)) {
38038
- const content = fs10.readFileSync(cargoTomlPath, "utf-8");
38472
+ const cargoTomlPath = path22.join(baseDir, "Cargo.toml");
38473
+ if (fs12.existsSync(cargoTomlPath)) {
38474
+ const content = fs12.readFileSync(cargoTomlPath, "utf-8");
38039
38475
  if (content.includes("[dev-dependencies]")) {
38040
38476
  if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
38041
38477
  return "cargo";
@@ -38044,10 +38480,10 @@ async function detectTestFramework(cwd) {
38044
38480
  }
38045
38481
  } catch {}
38046
38482
  try {
38047
- const pesterConfigPath = path20.join(baseDir, "pester.config.ps1");
38048
- const pesterConfigJsonPath = path20.join(baseDir, "pester.config.ps1.json");
38049
- const pesterPs1Path = path20.join(baseDir, "tests.ps1");
38050
- if (fs10.existsSync(pesterConfigPath) || fs10.existsSync(pesterConfigJsonPath) || fs10.existsSync(pesterPs1Path)) {
38483
+ const pesterConfigPath = path22.join(baseDir, "pester.config.ps1");
38484
+ const pesterConfigJsonPath = path22.join(baseDir, "pester.config.ps1.json");
38485
+ const pesterPs1Path = path22.join(baseDir, "tests.ps1");
38486
+ if (fs12.existsSync(pesterConfigPath) || fs12.existsSync(pesterConfigJsonPath) || fs12.existsSync(pesterPs1Path)) {
38051
38487
  return "pester";
38052
38488
  }
38053
38489
  } catch {}
@@ -38098,8 +38534,8 @@ function getTestFilesFromConvention(sourceFiles) {
38098
38534
  const testFiles = [];
38099
38535
  for (const file3 of sourceFiles) {
38100
38536
  const normalizedPath = file3.replace(/\\/g, "/");
38101
- const basename4 = path20.basename(file3);
38102
- const dirname9 = path20.dirname(file3);
38537
+ const basename4 = path22.basename(file3);
38538
+ const dirname10 = path22.dirname(file3);
38103
38539
  if (hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
38104
38540
  if (!testFiles.includes(file3)) {
38105
38541
  testFiles.push(file3);
@@ -38108,16 +38544,16 @@ function getTestFilesFromConvention(sourceFiles) {
38108
38544
  }
38109
38545
  for (const _pattern of TEST_PATTERNS) {
38110
38546
  const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
38111
- const ext = path20.extname(basename4);
38547
+ const ext = path22.extname(basename4);
38112
38548
  const possibleTestFiles = [
38113
- path20.join(dirname9, `${nameWithoutExt}.spec${ext}`),
38114
- path20.join(dirname9, `${nameWithoutExt}.test${ext}`),
38115
- path20.join(dirname9, "__tests__", `${nameWithoutExt}${ext}`),
38116
- path20.join(dirname9, "tests", `${nameWithoutExt}${ext}`),
38117
- path20.join(dirname9, "test", `${nameWithoutExt}${ext}`)
38549
+ path22.join(dirname10, `${nameWithoutExt}.spec${ext}`),
38550
+ path22.join(dirname10, `${nameWithoutExt}.test${ext}`),
38551
+ path22.join(dirname10, "__tests__", `${nameWithoutExt}${ext}`),
38552
+ path22.join(dirname10, "tests", `${nameWithoutExt}${ext}`),
38553
+ path22.join(dirname10, "test", `${nameWithoutExt}${ext}`)
38118
38554
  ];
38119
38555
  for (const testFile of possibleTestFiles) {
38120
- if (fs10.existsSync(testFile) && !testFiles.includes(testFile)) {
38556
+ if (fs12.existsSync(testFile) && !testFiles.includes(testFile)) {
38121
38557
  testFiles.push(testFile);
38122
38558
  }
38123
38559
  }
@@ -38133,8 +38569,8 @@ async function getTestFilesFromGraph(sourceFiles) {
38133
38569
  }
38134
38570
  for (const testFile of candidateTestFiles) {
38135
38571
  try {
38136
- const content = fs10.readFileSync(testFile, "utf-8");
38137
- const testDir = path20.dirname(testFile);
38572
+ const content = fs12.readFileSync(testFile, "utf-8");
38573
+ const testDir = path22.dirname(testFile);
38138
38574
  const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
38139
38575
  let match;
38140
38576
  match = importRegex.exec(content);
@@ -38142,8 +38578,8 @@ async function getTestFilesFromGraph(sourceFiles) {
38142
38578
  const importPath = match[1];
38143
38579
  let resolvedImport;
38144
38580
  if (importPath.startsWith(".")) {
38145
- resolvedImport = path20.resolve(testDir, importPath);
38146
- const existingExt = path20.extname(resolvedImport);
38581
+ resolvedImport = path22.resolve(testDir, importPath);
38582
+ const existingExt = path22.extname(resolvedImport);
38147
38583
  if (!existingExt) {
38148
38584
  for (const extToTry of [
38149
38585
  ".ts",
@@ -38154,7 +38590,7 @@ async function getTestFilesFromGraph(sourceFiles) {
38154
38590
  ".cjs"
38155
38591
  ]) {
38156
38592
  const withExt = resolvedImport + extToTry;
38157
- if (sourceFiles.includes(withExt) || fs10.existsSync(withExt)) {
38593
+ if (sourceFiles.includes(withExt) || fs12.existsSync(withExt)) {
38158
38594
  resolvedImport = withExt;
38159
38595
  break;
38160
38596
  }
@@ -38163,12 +38599,12 @@ async function getTestFilesFromGraph(sourceFiles) {
38163
38599
  } else {
38164
38600
  continue;
38165
38601
  }
38166
- const importBasename = path20.basename(resolvedImport, path20.extname(resolvedImport));
38167
- const importDir = path20.dirname(resolvedImport);
38602
+ const importBasename = path22.basename(resolvedImport, path22.extname(resolvedImport));
38603
+ const importDir = path22.dirname(resolvedImport);
38168
38604
  for (const sourceFile of sourceFiles) {
38169
- const sourceDir = path20.dirname(sourceFile);
38170
- const sourceBasename = path20.basename(sourceFile, path20.extname(sourceFile));
38171
- const isRelatedDir = importDir === sourceDir || importDir === path20.join(sourceDir, "__tests__") || importDir === path20.join(sourceDir, "tests") || importDir === path20.join(sourceDir, "test");
38605
+ const sourceDir = path22.dirname(sourceFile);
38606
+ const sourceBasename = path22.basename(sourceFile, path22.extname(sourceFile));
38607
+ const isRelatedDir = importDir === sourceDir || importDir === path22.join(sourceDir, "__tests__") || importDir === path22.join(sourceDir, "tests") || importDir === path22.join(sourceDir, "test");
38172
38608
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
38173
38609
  if (!testFiles.includes(testFile)) {
38174
38610
  testFiles.push(testFile);
@@ -38183,8 +38619,8 @@ async function getTestFilesFromGraph(sourceFiles) {
38183
38619
  while (match !== null) {
38184
38620
  const importPath = match[1];
38185
38621
  if (importPath.startsWith(".")) {
38186
- let resolvedImport = path20.resolve(testDir, importPath);
38187
- const existingExt = path20.extname(resolvedImport);
38622
+ let resolvedImport = path22.resolve(testDir, importPath);
38623
+ const existingExt = path22.extname(resolvedImport);
38188
38624
  if (!existingExt) {
38189
38625
  for (const extToTry of [
38190
38626
  ".ts",
@@ -38195,18 +38631,18 @@ async function getTestFilesFromGraph(sourceFiles) {
38195
38631
  ".cjs"
38196
38632
  ]) {
38197
38633
  const withExt = resolvedImport + extToTry;
38198
- if (sourceFiles.includes(withExt) || fs10.existsSync(withExt)) {
38634
+ if (sourceFiles.includes(withExt) || fs12.existsSync(withExt)) {
38199
38635
  resolvedImport = withExt;
38200
38636
  break;
38201
38637
  }
38202
38638
  }
38203
38639
  }
38204
- const importDir = path20.dirname(resolvedImport);
38205
- const importBasename = path20.basename(resolvedImport, path20.extname(resolvedImport));
38640
+ const importDir = path22.dirname(resolvedImport);
38641
+ const importBasename = path22.basename(resolvedImport, path22.extname(resolvedImport));
38206
38642
  for (const sourceFile of sourceFiles) {
38207
- const sourceDir = path20.dirname(sourceFile);
38208
- const sourceBasename = path20.basename(sourceFile, path20.extname(sourceFile));
38209
- const isRelatedDir = importDir === sourceDir || importDir === path20.join(sourceDir, "__tests__") || importDir === path20.join(sourceDir, "tests") || importDir === path20.join(sourceDir, "test");
38643
+ const sourceDir = path22.dirname(sourceFile);
38644
+ const sourceBasename = path22.basename(sourceFile, path22.extname(sourceFile));
38645
+ const isRelatedDir = importDir === sourceDir || importDir === path22.join(sourceDir, "__tests__") || importDir === path22.join(sourceDir, "tests") || importDir === path22.join(sourceDir, "test");
38210
38646
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
38211
38647
  if (!testFiles.includes(testFile)) {
38212
38648
  testFiles.push(testFile);
@@ -38291,8 +38727,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
38291
38727
  return ["mvn", "test"];
38292
38728
  case "gradle": {
38293
38729
  const isWindows = process.platform === "win32";
38294
- const hasGradlewBat = fs10.existsSync(path20.join(baseDir, "gradlew.bat"));
38295
- const hasGradlew = fs10.existsSync(path20.join(baseDir, "gradlew"));
38730
+ const hasGradlewBat = fs12.existsSync(path22.join(baseDir, "gradlew.bat"));
38731
+ const hasGradlew = fs12.existsSync(path22.join(baseDir, "gradlew"));
38296
38732
  if (hasGradlewBat && isWindows)
38297
38733
  return ["gradlew.bat", "test"];
38298
38734
  if (hasGradlew)
@@ -38309,7 +38745,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
38309
38745
  "cmake-build-release",
38310
38746
  "out"
38311
38747
  ];
38312
- const actualBuildDir = buildDirCandidates.find((d) => fs10.existsSync(path20.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
38748
+ const actualBuildDir = buildDirCandidates.find((d) => fs12.existsSync(path22.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
38313
38749
  return ["ctest", "--test-dir", actualBuildDir];
38314
38750
  }
38315
38751
  case "swift-test":
@@ -38851,7 +39287,7 @@ var test_runner = createSwarmTool({
38851
39287
  let effectiveScope = scope;
38852
39288
  if (scope === "all") {} else if (scope === "convention") {
38853
39289
  const sourceFiles = args.files.filter((f) => {
38854
- const ext = path20.extname(f).toLowerCase();
39290
+ const ext = path22.extname(f).toLowerCase();
38855
39291
  return SOURCE_EXTENSIONS.has(ext);
38856
39292
  });
38857
39293
  if (sourceFiles.length === 0) {
@@ -38867,7 +39303,7 @@ var test_runner = createSwarmTool({
38867
39303
  testFiles = getTestFilesFromConvention(sourceFiles);
38868
39304
  } else if (scope === "graph") {
38869
39305
  const sourceFiles = args.files.filter((f) => {
38870
- const ext = path20.extname(f).toLowerCase();
39306
+ const ext = path22.extname(f).toLowerCase();
38871
39307
  return SOURCE_EXTENSIONS.has(ext);
38872
39308
  });
38873
39309
  if (sourceFiles.length === 0) {
@@ -38938,8 +39374,8 @@ function validateDirectoryPath(dir) {
38938
39374
  if (dir.includes("..")) {
38939
39375
  throw new Error("Directory path must not contain path traversal sequences");
38940
39376
  }
38941
- const normalized = path21.normalize(dir);
38942
- const absolutePath = path21.isAbsolute(normalized) ? normalized : path21.resolve(normalized);
39377
+ const normalized = path23.normalize(dir);
39378
+ const absolutePath = path23.isAbsolute(normalized) ? normalized : path23.resolve(normalized);
38943
39379
  return absolutePath;
38944
39380
  }
38945
39381
  function validateTimeout(timeoutMs, defaultValue) {
@@ -38962,9 +39398,9 @@ function validateTimeout(timeoutMs, defaultValue) {
38962
39398
  }
38963
39399
  function getPackageVersion(dir) {
38964
39400
  try {
38965
- const packagePath = path21.join(dir, "package.json");
38966
- if (fs11.existsSync(packagePath)) {
38967
- const content = fs11.readFileSync(packagePath, "utf-8");
39401
+ const packagePath = path23.join(dir, "package.json");
39402
+ if (fs13.existsSync(packagePath)) {
39403
+ const content = fs13.readFileSync(packagePath, "utf-8");
38968
39404
  const pkg = JSON.parse(content);
38969
39405
  return pkg.version ?? null;
38970
39406
  }
@@ -38973,9 +39409,9 @@ function getPackageVersion(dir) {
38973
39409
  }
38974
39410
  function getChangelogVersion(dir) {
38975
39411
  try {
38976
- const changelogPath = path21.join(dir, "CHANGELOG.md");
38977
- if (fs11.existsSync(changelogPath)) {
38978
- const content = fs11.readFileSync(changelogPath, "utf-8");
39412
+ const changelogPath = path23.join(dir, "CHANGELOG.md");
39413
+ if (fs13.existsSync(changelogPath)) {
39414
+ const content = fs13.readFileSync(changelogPath, "utf-8");
38979
39415
  const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
38980
39416
  if (match) {
38981
39417
  return match[1];
@@ -38987,10 +39423,10 @@ function getChangelogVersion(dir) {
38987
39423
  function getVersionFileVersion(dir) {
38988
39424
  const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
38989
39425
  for (const file3 of possibleFiles) {
38990
- const filePath = path21.join(dir, file3);
38991
- if (fs11.existsSync(filePath)) {
39426
+ const filePath = path23.join(dir, file3);
39427
+ if (fs13.existsSync(filePath)) {
38992
39428
  try {
38993
- const content = fs11.readFileSync(filePath, "utf-8").trim();
39429
+ const content = fs13.readFileSync(filePath, "utf-8").trim();
38994
39430
  const match = content.match(/(\d+\.\d+\.\d+)/);
38995
39431
  if (match) {
38996
39432
  return match[1];
@@ -39534,7 +39970,7 @@ async function handlePromoteCommand(directory, args) {
39534
39970
  }
39535
39971
 
39536
39972
  // src/commands/reset.ts
39537
- import * as fs12 from "fs";
39973
+ import * as fs14 from "fs";
39538
39974
 
39539
39975
  // src/background/manager.ts
39540
39976
  init_utils();
@@ -40235,8 +40671,8 @@ async function handleResetCommand(directory, args) {
40235
40671
  for (const filename of filesToReset) {
40236
40672
  try {
40237
40673
  const resolvedPath = validateSwarmPath(directory, filename);
40238
- if (fs12.existsSync(resolvedPath)) {
40239
- fs12.unlinkSync(resolvedPath);
40674
+ if (fs14.existsSync(resolvedPath)) {
40675
+ fs14.unlinkSync(resolvedPath);
40240
40676
  results.push(`- \u2705 Deleted ${filename}`);
40241
40677
  } else {
40242
40678
  results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
@@ -40253,8 +40689,8 @@ async function handleResetCommand(directory, args) {
40253
40689
  }
40254
40690
  try {
40255
40691
  const summariesPath = validateSwarmPath(directory, "summaries");
40256
- if (fs12.existsSync(summariesPath)) {
40257
- fs12.rmSync(summariesPath, { recursive: true, force: true });
40692
+ if (fs14.existsSync(summariesPath)) {
40693
+ fs14.rmSync(summariesPath, { recursive: true, force: true });
40258
40694
  results.push("- \u2705 Deleted summaries/ directory");
40259
40695
  } else {
40260
40696
  results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
@@ -40274,14 +40710,14 @@ async function handleResetCommand(directory, args) {
40274
40710
 
40275
40711
  // src/commands/reset-session.ts
40276
40712
  init_utils2();
40277
- import * as fs13 from "fs";
40278
- import * as path22 from "path";
40713
+ import * as fs15 from "fs";
40714
+ import * as path24 from "path";
40279
40715
  async function handleResetSessionCommand(directory, _args) {
40280
40716
  const results = [];
40281
40717
  try {
40282
40718
  const statePath = validateSwarmPath(directory, "session/state.json");
40283
- if (fs13.existsSync(statePath)) {
40284
- fs13.unlinkSync(statePath);
40719
+ if (fs15.existsSync(statePath)) {
40720
+ fs15.unlinkSync(statePath);
40285
40721
  results.push("\u2705 Deleted .swarm/session/state.json");
40286
40722
  } else {
40287
40723
  results.push("\u23ED\uFE0F state.json not found (already clean)");
@@ -40290,15 +40726,15 @@ async function handleResetSessionCommand(directory, _args) {
40290
40726
  results.push("\u274C Failed to delete state.json");
40291
40727
  }
40292
40728
  try {
40293
- const sessionDir = path22.dirname(validateSwarmPath(directory, "session/state.json"));
40294
- if (fs13.existsSync(sessionDir)) {
40295
- const files = fs13.readdirSync(sessionDir);
40729
+ const sessionDir = path24.dirname(validateSwarmPath(directory, "session/state.json"));
40730
+ if (fs15.existsSync(sessionDir)) {
40731
+ const files = fs15.readdirSync(sessionDir);
40296
40732
  const otherFiles = files.filter((f) => f !== "state.json");
40297
40733
  let deletedCount = 0;
40298
40734
  for (const file3 of otherFiles) {
40299
- const filePath = path22.join(sessionDir, file3);
40300
- if (fs13.lstatSync(filePath).isFile()) {
40301
- fs13.unlinkSync(filePath);
40735
+ const filePath = path24.join(sessionDir, file3);
40736
+ if (fs15.lstatSync(filePath).isFile()) {
40737
+ fs15.unlinkSync(filePath);
40302
40738
  deletedCount++;
40303
40739
  }
40304
40740
  }
@@ -40326,7 +40762,7 @@ async function handleResetSessionCommand(directory, _args) {
40326
40762
  // src/summaries/manager.ts
40327
40763
  init_utils2();
40328
40764
  init_utils();
40329
- import * as path23 from "path";
40765
+ import * as path25 from "path";
40330
40766
  var SUMMARY_ID_REGEX = /^S\d+$/;
40331
40767
  function sanitizeSummaryId(id) {
40332
40768
  if (!id || id.length === 0) {
@@ -40350,7 +40786,7 @@ function sanitizeSummaryId(id) {
40350
40786
  }
40351
40787
  async function loadFullOutput(directory, id) {
40352
40788
  const sanitizedId = sanitizeSummaryId(id);
40353
- const relativePath = path23.join("summaries", `${sanitizedId}.json`);
40789
+ const relativePath = path25.join("summaries", `${sanitizedId}.json`);
40354
40790
  validateSwarmPath(directory, relativePath);
40355
40791
  const content = await readSwarmFileAsync(directory, relativePath);
40356
40792
  if (content === null) {
@@ -40403,18 +40839,18 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
40403
40839
 
40404
40840
  // src/commands/rollback.ts
40405
40841
  init_utils2();
40406
- import * as fs14 from "fs";
40407
- import * as path24 from "path";
40842
+ import * as fs16 from "fs";
40843
+ import * as path26 from "path";
40408
40844
  async function handleRollbackCommand(directory, args) {
40409
40845
  const phaseArg = args[0];
40410
40846
  if (!phaseArg) {
40411
40847
  const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
40412
- if (!fs14.existsSync(manifestPath2)) {
40848
+ if (!fs16.existsSync(manifestPath2)) {
40413
40849
  return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
40414
40850
  }
40415
40851
  let manifest2;
40416
40852
  try {
40417
- manifest2 = JSON.parse(fs14.readFileSync(manifestPath2, "utf-8"));
40853
+ manifest2 = JSON.parse(fs16.readFileSync(manifestPath2, "utf-8"));
40418
40854
  } catch {
40419
40855
  return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
40420
40856
  }
@@ -40436,12 +40872,12 @@ async function handleRollbackCommand(directory, args) {
40436
40872
  return "Error: Phase number must be a positive integer.";
40437
40873
  }
40438
40874
  const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
40439
- if (!fs14.existsSync(manifestPath)) {
40875
+ if (!fs16.existsSync(manifestPath)) {
40440
40876
  return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
40441
40877
  }
40442
40878
  let manifest;
40443
40879
  try {
40444
- manifest = JSON.parse(fs14.readFileSync(manifestPath, "utf-8"));
40880
+ manifest = JSON.parse(fs16.readFileSync(manifestPath, "utf-8"));
40445
40881
  } catch {
40446
40882
  return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
40447
40883
  }
@@ -40451,10 +40887,10 @@ async function handleRollbackCommand(directory, args) {
40451
40887
  return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
40452
40888
  }
40453
40889
  const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
40454
- if (!fs14.existsSync(checkpointDir)) {
40890
+ if (!fs16.existsSync(checkpointDir)) {
40455
40891
  return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
40456
40892
  }
40457
- const checkpointFiles = fs14.readdirSync(checkpointDir);
40893
+ const checkpointFiles = fs16.readdirSync(checkpointDir);
40458
40894
  if (checkpointFiles.length === 0) {
40459
40895
  return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
40460
40896
  }
@@ -40462,10 +40898,10 @@ async function handleRollbackCommand(directory, args) {
40462
40898
  const successes = [];
40463
40899
  const failures = [];
40464
40900
  for (const file3 of checkpointFiles) {
40465
- const src = path24.join(checkpointDir, file3);
40466
- const dest = path24.join(swarmDir, file3);
40901
+ const src = path26.join(checkpointDir, file3);
40902
+ const dest = path26.join(swarmDir, file3);
40467
40903
  try {
40468
- fs14.cpSync(src, dest, { recursive: true, force: true });
40904
+ fs16.cpSync(src, dest, { recursive: true, force: true });
40469
40905
  successes.push(file3);
40470
40906
  } catch (error93) {
40471
40907
  failures.push({ file: file3, error: error93.message });
@@ -40482,7 +40918,7 @@ async function handleRollbackCommand(directory, args) {
40482
40918
  timestamp: new Date().toISOString()
40483
40919
  };
40484
40920
  try {
40485
- fs14.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
40921
+ fs16.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
40486
40922
  `);
40487
40923
  } catch (error93) {
40488
40924
  console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
@@ -40525,11 +40961,11 @@ async function handleSimulateCommand(directory, args) {
40525
40961
  ];
40526
40962
  const report = reportLines.filter(Boolean).join(`
40527
40963
  `);
40528
- const fs15 = await import("fs/promises");
40529
- const path25 = await import("path");
40530
- const reportPath = path25.join(directory, ".swarm", "simulate-report.md");
40531
- await fs15.mkdir(path25.dirname(reportPath), { recursive: true });
40532
- await fs15.writeFile(reportPath, report, "utf-8");
40964
+ const fs17 = await import("fs/promises");
40965
+ const path27 = await import("path");
40966
+ const reportPath = path27.join(directory, ".swarm", "simulate-report.md");
40967
+ await fs17.mkdir(path27.dirname(reportPath), { recursive: true });
40968
+ await fs17.writeFile(reportPath, report, "utf-8");
40533
40969
  return `${darkMatterPairs.length} hidden coupling pairs detected`;
40534
40970
  }
40535
40971
 
@@ -41011,18 +41447,18 @@ function resolveCommand(tokens) {
41011
41447
  }
41012
41448
 
41013
41449
  // src/cli/index.ts
41014
- var CONFIG_DIR = path25.join(process.env.XDG_CONFIG_HOME || path25.join(os5.homedir(), ".config"), "opencode");
41015
- var OPENCODE_CONFIG_PATH = path25.join(CONFIG_DIR, "opencode.json");
41016
- var PLUGIN_CONFIG_PATH = path25.join(CONFIG_DIR, "opencode-swarm.json");
41017
- var PROMPTS_DIR = path25.join(CONFIG_DIR, "opencode-swarm");
41450
+ var CONFIG_DIR = path27.join(process.env.XDG_CONFIG_HOME || path27.join(os5.homedir(), ".config"), "opencode");
41451
+ var OPENCODE_CONFIG_PATH = path27.join(CONFIG_DIR, "opencode.json");
41452
+ var PLUGIN_CONFIG_PATH = path27.join(CONFIG_DIR, "opencode-swarm.json");
41453
+ var PROMPTS_DIR = path27.join(CONFIG_DIR, "opencode-swarm");
41018
41454
  function ensureDir(dir) {
41019
- if (!fs15.existsSync(dir)) {
41020
- fs15.mkdirSync(dir, { recursive: true });
41455
+ if (!fs17.existsSync(dir)) {
41456
+ fs17.mkdirSync(dir, { recursive: true });
41021
41457
  }
41022
41458
  }
41023
41459
  function loadJson(filepath) {
41024
41460
  try {
41025
- const content = fs15.readFileSync(filepath, "utf-8");
41461
+ const content = fs17.readFileSync(filepath, "utf-8");
41026
41462
  const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
41027
41463
  return JSON.parse(stripped);
41028
41464
  } catch {
@@ -41030,7 +41466,7 @@ function loadJson(filepath) {
41030
41466
  }
41031
41467
  }
41032
41468
  function saveJson(filepath, data) {
41033
- fs15.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
41469
+ fs17.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
41034
41470
  `, "utf-8");
41035
41471
  }
41036
41472
  async function install() {
@@ -41038,7 +41474,7 @@ async function install() {
41038
41474
  `);
41039
41475
  ensureDir(CONFIG_DIR);
41040
41476
  ensureDir(PROMPTS_DIR);
41041
- const LEGACY_CONFIG_PATH = path25.join(CONFIG_DIR, "config.json");
41477
+ const LEGACY_CONFIG_PATH = path27.join(CONFIG_DIR, "config.json");
41042
41478
  let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
41043
41479
  if (!opencodeConfig) {
41044
41480
  const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
@@ -41063,7 +41499,7 @@ async function install() {
41063
41499
  saveJson(OPENCODE_CONFIG_PATH, opencodeConfig);
41064
41500
  console.log("\u2713 Added opencode-swarm to OpenCode plugins");
41065
41501
  console.log("\u2713 Disabled default OpenCode agents (explore, general)");
41066
- if (!fs15.existsSync(PLUGIN_CONFIG_PATH)) {
41502
+ if (!fs17.existsSync(PLUGIN_CONFIG_PATH)) {
41067
41503
  const defaultConfig = {
41068
41504
  agents: {
41069
41505
  coder: { model: "opencode/minimax-m2.5-free" },
@@ -41106,7 +41542,7 @@ async function uninstall() {
41106
41542
  `);
41107
41543
  const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
41108
41544
  if (!opencodeConfig) {
41109
- if (fs15.existsSync(OPENCODE_CONFIG_PATH)) {
41545
+ if (fs17.existsSync(OPENCODE_CONFIG_PATH)) {
41110
41546
  console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
41111
41547
  return 1;
41112
41548
  } else {
@@ -41138,13 +41574,13 @@ async function uninstall() {
41138
41574
  console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
41139
41575
  if (process.argv.includes("--clean")) {
41140
41576
  let cleaned = false;
41141
- if (fs15.existsSync(PLUGIN_CONFIG_PATH)) {
41142
- fs15.unlinkSync(PLUGIN_CONFIG_PATH);
41577
+ if (fs17.existsSync(PLUGIN_CONFIG_PATH)) {
41578
+ fs17.unlinkSync(PLUGIN_CONFIG_PATH);
41143
41579
  console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
41144
41580
  cleaned = true;
41145
41581
  }
41146
- if (fs15.existsSync(PROMPTS_DIR)) {
41147
- fs15.rmSync(PROMPTS_DIR, { recursive: true });
41582
+ if (fs17.existsSync(PROMPTS_DIR)) {
41583
+ fs17.rmSync(PROMPTS_DIR, { recursive: true });
41148
41584
  console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
41149
41585
  cleaned = true;
41150
41586
  }