opencode-swarm 6.21.3 → 6.22.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/index.js CHANGED
@@ -14549,7 +14549,7 @@ async function loadEvidence(directory, taskId) {
14549
14549
  return { status: "found", bundle: validated };
14550
14550
  } catch (error49) {
14551
14551
  warn(`Wrapped flat retrospective failed validation for task ${sanitizedTaskId}: ${error49 instanceof Error ? error49.message : String(error49)}`);
14552
- const errors3 = error49 instanceof ZodError ? error49.issues.map((e) => e.path.join(".") + ": " + e.message) : [String(error49)];
14552
+ const errors3 = error49 instanceof ZodError ? error49.issues.map((e) => `${e.path.join(".")}: ${e.message}`) : [String(error49)];
14553
14553
  return { status: "invalid_schema", errors: errors3 };
14554
14554
  }
14555
14555
  }
@@ -14558,7 +14558,7 @@ async function loadEvidence(directory, taskId) {
14558
14558
  return { status: "found", bundle: validated };
14559
14559
  } catch (error49) {
14560
14560
  warn(`Evidence bundle validation failed for task ${sanitizedTaskId}: ${error49 instanceof Error ? error49.message : String(error49)}`);
14561
- const errors3 = error49 instanceof ZodError ? error49.issues.map((e) => e.path.join(".") + ": " + e.message) : [String(error49)];
14561
+ const errors3 = error49 instanceof ZodError ? error49.issues.map((e) => `${e.path.join(".")}: ${e.message}`) : [String(error49)];
14562
14562
  return { status: "invalid_schema", errors: errors3 };
14563
14563
  }
14564
14564
  }
@@ -36296,8 +36296,8 @@ var init_tree_sitter = __esm(() => {
36296
36296
  bytes = Promise.resolve(input);
36297
36297
  } else {
36298
36298
  if (globalThis.process?.versions.node) {
36299
- const fs25 = await import("fs/promises");
36300
- bytes = fs25.readFile(input);
36299
+ const fs27 = await import("fs/promises");
36300
+ bytes = fs27.readFile(input);
36301
36301
  } else {
36302
36302
  bytes = fetch(input).then((response) => response.arrayBuffer().then((buffer) => {
36303
36303
  if (response.ok) {
@@ -36352,11 +36352,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
36352
36352
  throw toThrow;
36353
36353
  }, "quit_");
36354
36354
  var scriptDirectory = "";
36355
- function locateFile(path36) {
36355
+ function locateFile(path39) {
36356
36356
  if (Module["locateFile"]) {
36357
- return Module["locateFile"](path36, scriptDirectory);
36357
+ return Module["locateFile"](path39, scriptDirectory);
36358
36358
  }
36359
- return scriptDirectory + path36;
36359
+ return scriptDirectory + path39;
36360
36360
  }
36361
36361
  __name(locateFile, "locateFile");
36362
36362
  var readAsync, readBinary;
@@ -38104,7 +38104,7 @@ var init_runtime = __esm(() => {
38104
38104
  });
38105
38105
 
38106
38106
  // src/index.ts
38107
- import * as path45 from "path";
38107
+ import * as path48 from "path";
38108
38108
 
38109
38109
  // src/tools/tool-names.ts
38110
38110
  var TOOL_NAMES = [
@@ -38763,6 +38763,16 @@ var KnowledgeConfigSchema = exports_external.object({
38763
38763
  min_retrievals_for_utility: exports_external.number().min(1).max(100).default(3),
38764
38764
  schema_version: exports_external.number().int().min(1).default(1)
38765
38765
  });
38766
+ var CuratorConfigSchema = exports_external.object({
38767
+ enabled: exports_external.boolean().default(false),
38768
+ init_enabled: exports_external.boolean().default(true),
38769
+ phase_enabled: exports_external.boolean().default(true),
38770
+ max_summary_tokens: exports_external.number().min(500).max(8000).default(2000),
38771
+ min_knowledge_confidence: exports_external.number().min(0).max(1).default(0.7),
38772
+ compliance_report: exports_external.boolean().default(true),
38773
+ suppress_warnings: exports_external.boolean().default(true),
38774
+ drift_inject_max_chars: exports_external.number().min(100).max(2000).default(500)
38775
+ });
38766
38776
  var PluginConfigSchema = exports_external.object({
38767
38777
  agents: exports_external.record(exports_external.string(), AgentOverrideConfigSchema).optional(),
38768
38778
  swarms: exports_external.record(exports_external.string(), SwarmConfigSchema).optional(),
@@ -38790,6 +38800,7 @@ var PluginConfigSchema = exports_external.object({
38790
38800
  checkpoint: CheckpointConfigSchema.optional(),
38791
38801
  automation: AutomationConfigSchema.optional(),
38792
38802
  knowledge: KnowledgeConfigSchema.optional(),
38803
+ curator: CuratorConfigSchema.optional(),
38793
38804
  tool_output: exports_external.object({
38794
38805
  truncation_enabled: exports_external.boolean().default(true),
38795
38806
  max_lines: exports_external.number().min(10).max(500).default(150),
@@ -42540,7 +42551,7 @@ async function readRejectedLessons(directory) {
42540
42551
  }
42541
42552
  async function appendKnowledge(filePath, entry) {
42542
42553
  await mkdir(path9.dirname(filePath), { recursive: true });
42543
- await appendFile(filePath, JSON.stringify(entry) + `
42554
+ await appendFile(filePath, `${JSON.stringify(entry)}
42544
42555
  `, "utf-8");
42545
42556
  }
42546
42557
  async function rewriteKnowledge(filePath, entries) {
@@ -43123,7 +43134,7 @@ async function checkPhaseBoundaries(plan) {
43123
43134
  for (const phase of plan.phases) {
43124
43135
  for (const task of phase.tasks) {
43125
43136
  const taskPhaseNum = parseInt(task.id.split(".")[0], 10);
43126
- if (isNaN(taskPhaseNum)) {
43137
+ if (Number.isNaN(taskPhaseNum)) {
43127
43138
  mismatches.push(`Task ${task.id} has invalid phase number`);
43128
43139
  } else if (taskPhaseNum !== phase.id) {
43129
43140
  mismatches.push(`Task ${task.id} found under Phase ${phase.id}`);
@@ -43935,7 +43946,7 @@ function sanitizeString(str, maxLength) {
43935
43946
  return "";
43936
43947
  const sanitized = String(str).replace(RTL_OVERRIDE_PATTERN, "");
43937
43948
  if (sanitized.length > maxLength) {
43938
- return sanitized.substring(0, maxLength - 3) + "...";
43949
+ return `${sanitized.substring(0, maxLength - 3)}...`;
43939
43950
  }
43940
43951
  return sanitized;
43941
43952
  }
@@ -44106,7 +44117,7 @@ async function getHandoffData(directory) {
44106
44117
  const phaseMatch = planMdContent.match(/^## Phase (\d+):?\s*(.+)?$/m);
44107
44118
  const taskMatch = planMdContent.match(/^- \[ \] (\d+\.\d+)/g);
44108
44119
  if (phaseMatch) {
44109
- planInfo.currentPhase = sanitizeString(`Phase ${phaseMatch[1]}${phaseMatch[2] ? ": " + phaseMatch[2] : ""}`, MAX_TASK_ID_LENGTH);
44120
+ planInfo.currentPhase = sanitizeString(`Phase ${phaseMatch[1]}${phaseMatch[2] ? `: ${phaseMatch[2]}` : ""}`, MAX_TASK_ID_LENGTH);
44110
44121
  }
44111
44122
  if (taskMatch) {
44112
44123
  const rawTasks = taskMatch.map((t) => t.replace("- [ ] ", ""));
@@ -44273,7 +44284,8 @@ function serializeAgentSession(s) {
44273
44284
  lastPhaseCompletePhase: s.lastPhaseCompletePhase ?? 0,
44274
44285
  phaseAgentsDispatched,
44275
44286
  qaSkipCount: s.qaSkipCount ?? 0,
44276
- qaSkipTaskIds: s.qaSkipTaskIds ?? []
44287
+ qaSkipTaskIds: s.qaSkipTaskIds ?? [],
44288
+ taskWorkflowStates: Object.fromEntries(s.taskWorkflowStates ?? new Map)
44277
44289
  };
44278
44290
  }
44279
44291
  async function writeSnapshot(directory, state) {
@@ -46135,7 +46147,7 @@ No plan content available. Start by creating a .swarm/plan.md file.
46135
46147
  if (incompleteTasks.length > 0) {
46136
46148
  const truncateTask = (task) => {
46137
46149
  const text = task.replace("- [ ] ", "");
46138
- return text.length > 60 ? text.slice(0, 57) + "..." : text;
46150
+ return text.length > 60 ? `${text.slice(0, 57)}...` : text;
46139
46151
  };
46140
46152
  compactResult.push(`- Current: ${truncateTask(incompleteTasks[0])}`);
46141
46153
  const lookahead = incompleteTasks.slice(1, 1 + Math.min(lookaheadCount, 1));
@@ -47201,7 +47213,7 @@ function shouldMaskToolOutput(msg, index, totalMessages, recentWindowSize, thres
47201
47213
  const age = totalMessages - 1 - index;
47202
47214
  return age > recentWindowSize || text.length > threshold;
47203
47215
  }
47204
- function maskToolOutput(msg, threshold) {
47216
+ function maskToolOutput(msg, _threshold) {
47205
47217
  if (!msg?.parts)
47206
47218
  return 0;
47207
47219
  let freedTokens = 0;
@@ -48322,6 +48334,416 @@ function consolidateSystemMessages(messages) {
48322
48334
  }
48323
48335
  // src/hooks/phase-monitor.ts
48324
48336
  init_manager2();
48337
+
48338
+ // src/hooks/curator.ts
48339
+ init_event_bus();
48340
+ import * as fs14 from "fs";
48341
+ import * as path26 from "path";
48342
+ init_utils2();
48343
+ async function readCuratorSummary(directory) {
48344
+ const content = await readSwarmFileAsync(directory, "curator-summary.json");
48345
+ if (content === null) {
48346
+ return null;
48347
+ }
48348
+ try {
48349
+ const parsed = JSON.parse(content);
48350
+ if (parsed.schema_version !== 1) {
48351
+ console.warn(`Curator summary has unsupported schema version: ${parsed.schema_version}. Expected 1.`);
48352
+ return null;
48353
+ }
48354
+ return parsed;
48355
+ } catch {
48356
+ console.warn("Failed to parse curator-summary.json: invalid JSON");
48357
+ return null;
48358
+ }
48359
+ }
48360
+ async function writeCuratorSummary(directory, summary) {
48361
+ const resolvedPath = validateSwarmPath(directory, "curator-summary.json");
48362
+ fs14.mkdirSync(path26.dirname(resolvedPath), { recursive: true });
48363
+ await Bun.write(resolvedPath, JSON.stringify(summary, null, 2));
48364
+ }
48365
+ function normalizeAgentName(name2) {
48366
+ return name2.toLowerCase().replace(/^(mega|paid|local|lowtier|modelrelay)_/, "");
48367
+ }
48368
+ function filterPhaseEvents(eventsJsonl, phase, sinceTimestamp) {
48369
+ const lines = eventsJsonl.split(`
48370
+ `);
48371
+ const filtered = [];
48372
+ for (const line of lines) {
48373
+ if (!line.trim())
48374
+ continue;
48375
+ try {
48376
+ const event = JSON.parse(line);
48377
+ if (sinceTimestamp) {
48378
+ if (event.timestamp > sinceTimestamp) {
48379
+ filtered.push(event);
48380
+ }
48381
+ } else {
48382
+ if (event.phase === phase) {
48383
+ filtered.push(event);
48384
+ }
48385
+ }
48386
+ } catch {
48387
+ console.warn("filterPhaseEvents: skipping malformed line");
48388
+ }
48389
+ }
48390
+ return filtered;
48391
+ }
48392
+ function checkPhaseCompliance(phaseEvents, agentsDispatched, requiredAgents, phase) {
48393
+ const observations = [];
48394
+ const timestamp = new Date().toISOString();
48395
+ for (const agent of requiredAgents) {
48396
+ const normalizedAgent = normalizeAgentName(agent);
48397
+ const isDispatched = agentsDispatched.some((a) => normalizeAgentName(a) === normalizedAgent);
48398
+ if (!isDispatched) {
48399
+ observations.push({
48400
+ phase,
48401
+ timestamp,
48402
+ type: "workflow_deviation",
48403
+ severity: "warning",
48404
+ description: `Agent '${agent}' required but not dispatched in phase ${phase}`
48405
+ });
48406
+ }
48407
+ }
48408
+ const coderDelegations = [];
48409
+ const reviewerDelegations = [];
48410
+ for (let i2 = 0;i2 < phaseEvents.length; i2++) {
48411
+ const e = phaseEvents[i2];
48412
+ try {
48413
+ if (e.type === "agent.delegation") {
48414
+ const agent = e.agent;
48415
+ if (agent && typeof agent === "string") {
48416
+ const normalized = normalizeAgentName(agent);
48417
+ if (normalized === "coder") {
48418
+ coderDelegations.push({ event: e, index: i2 });
48419
+ } else if (normalized === "reviewer") {
48420
+ reviewerDelegations.push({ event: e, index: i2 });
48421
+ }
48422
+ }
48423
+ }
48424
+ } catch {}
48425
+ }
48426
+ for (const coderEvent of coderDelegations) {
48427
+ const hasSubsequentReviewer = reviewerDelegations.some((r) => r.index > coderEvent.index);
48428
+ if (!hasSubsequentReviewer) {
48429
+ observations.push({
48430
+ phase,
48431
+ timestamp,
48432
+ type: "missing_reviewer",
48433
+ severity: "warning",
48434
+ description: `Coder delegation in phase ${phase} has no subsequent reviewer delegation`
48435
+ });
48436
+ }
48437
+ }
48438
+ let phaseCompleteIndex = -1;
48439
+ let retroIndex = -1;
48440
+ for (let i2 = 0;i2 < phaseEvents.length; i2++) {
48441
+ const e = phaseEvents[i2];
48442
+ try {
48443
+ const eventType = e.type;
48444
+ const evidenceType = e.evidence_type;
48445
+ if (typeof eventType === "string" && (eventType === "phase_complete" || eventType === "phase.complete")) {
48446
+ phaseCompleteIndex = i2;
48447
+ }
48448
+ if (typeof eventType === "string" && eventType === "retrospective.written" || typeof evidenceType === "string" && evidenceType === "retrospective") {
48449
+ retroIndex = i2;
48450
+ }
48451
+ } catch {}
48452
+ }
48453
+ if (phaseCompleteIndex !== -1 && retroIndex === -1) {
48454
+ observations.push({
48455
+ phase,
48456
+ timestamp,
48457
+ type: "missing_retro",
48458
+ severity: "warning",
48459
+ description: `Phase ${phase} completed without retrospective evidence`
48460
+ });
48461
+ }
48462
+ const domainDetectionEvents = [];
48463
+ const smeDelegations = [];
48464
+ for (let i2 = 0;i2 < phaseEvents.length; i2++) {
48465
+ const e = phaseEvents[i2];
48466
+ try {
48467
+ if (e.type === "domains.detected") {
48468
+ domainDetectionEvents.push({ event: e, index: i2 });
48469
+ }
48470
+ if (e.type === "agent.delegation" && e.agent) {
48471
+ const agent = e.agent;
48472
+ if (agent && typeof agent === "string") {
48473
+ const normalized = normalizeAgentName(agent);
48474
+ if (normalized === "sme") {
48475
+ smeDelegations.push({ event: e, index: i2 });
48476
+ }
48477
+ }
48478
+ }
48479
+ } catch {}
48480
+ }
48481
+ for (const domainEvent of domainDetectionEvents) {
48482
+ const hasSubsequentSme = smeDelegations.some((s) => s.index > domainEvent.index);
48483
+ if (!hasSubsequentSme) {
48484
+ observations.push({
48485
+ phase,
48486
+ timestamp,
48487
+ type: "missing_sme",
48488
+ severity: "info",
48489
+ description: `Domains detected in phase ${phase} but no SME consultation found`
48490
+ });
48491
+ }
48492
+ }
48493
+ return observations;
48494
+ }
48495
+ async function runCuratorInit(directory, config3) {
48496
+ try {
48497
+ const priorSummary = await readCuratorSummary(directory);
48498
+ const knowledgePath = resolveSwarmKnowledgePath(directory);
48499
+ const allEntries = await readKnowledge(knowledgePath);
48500
+ const highConfidenceEntries = allEntries.filter((e) => typeof e.confidence === "number" && e.confidence >= config3.min_knowledge_confidence);
48501
+ const contextMd = await readSwarmFileAsync(directory, "context.md");
48502
+ const briefingParts = [];
48503
+ if (priorSummary) {
48504
+ briefingParts.push(`## Prior Session Summary (Phase ${priorSummary.last_phase_covered})`);
48505
+ briefingParts.push(priorSummary.digest);
48506
+ if (priorSummary.compliance_observations.length > 0 && !config3.suppress_warnings) {
48507
+ briefingParts.push(`
48508
+ ## Compliance Observations`);
48509
+ for (const obs of priorSummary.compliance_observations) {
48510
+ briefingParts.push(`- [${obs.severity.toUpperCase()}] Phase ${obs.phase}: ${obs.description}`);
48511
+ }
48512
+ }
48513
+ if (priorSummary.knowledge_recommendations.length > 0) {
48514
+ briefingParts.push(`
48515
+ ## Knowledge Recommendations`);
48516
+ for (const rec of priorSummary.knowledge_recommendations) {
48517
+ briefingParts.push(`- ${rec.action}: ${rec.lesson} (${rec.reason})`);
48518
+ }
48519
+ }
48520
+ } else {
48521
+ briefingParts.push("## First Session \u2014 No Prior Summary");
48522
+ briefingParts.push("This is the first curator run for this project. No prior phase data available.");
48523
+ }
48524
+ if (highConfidenceEntries.length > 0) {
48525
+ briefingParts.push(`
48526
+ ## High-Confidence Knowledge`);
48527
+ for (const entry of highConfidenceEntries.slice(0, 10)) {
48528
+ const lesson = typeof entry.lesson === "string" ? entry.lesson : JSON.stringify(entry.lesson);
48529
+ briefingParts.push(`- ${lesson}`);
48530
+ }
48531
+ }
48532
+ if (contextMd) {
48533
+ briefingParts.push(`
48534
+ ## Context Summary`);
48535
+ const maxContextChars = config3.max_summary_tokens * 2;
48536
+ briefingParts.push(contextMd.slice(0, maxContextChars));
48537
+ }
48538
+ const contradictions = allEntries.filter((e) => Array.isArray(e.tags) && e.tags.some((t) => t.includes("contradiction"))).map((e) => typeof e.lesson === "string" ? e.lesson : JSON.stringify(e.lesson));
48539
+ const result = {
48540
+ briefing: briefingParts.join(`
48541
+ `),
48542
+ contradictions,
48543
+ knowledge_entries_reviewed: allEntries.length,
48544
+ prior_phases_covered: priorSummary ? priorSummary.last_phase_covered : 0
48545
+ };
48546
+ getGlobalEventBus().publish("curator.init.completed", {
48547
+ prior_phases_covered: result.prior_phases_covered,
48548
+ knowledge_entries_reviewed: result.knowledge_entries_reviewed,
48549
+ contradictions_found: contradictions.length
48550
+ });
48551
+ return result;
48552
+ } catch (err2) {
48553
+ getGlobalEventBus().publish("curator.error", {
48554
+ operation: "init",
48555
+ error: String(err2)
48556
+ });
48557
+ return {
48558
+ briefing: `## Curator Init Failed
48559
+ Could not load prior session context.`,
48560
+ contradictions: [],
48561
+ knowledge_entries_reviewed: 0,
48562
+ prior_phases_covered: 0
48563
+ };
48564
+ }
48565
+ }
48566
+ async function runCuratorPhase(directory, phase, agentsDispatched, _config, _knowledgeConfig) {
48567
+ try {
48568
+ const priorSummary = await readCuratorSummary(directory);
48569
+ const eventsJsonlContent = await readSwarmFileAsync(directory, "events.jsonl");
48570
+ const phaseEvents = eventsJsonlContent ? filterPhaseEvents(eventsJsonlContent, phase) : [];
48571
+ const contextMd = await readSwarmFileAsync(directory, "context.md");
48572
+ const requiredAgents = ["reviewer", "test_engineer"];
48573
+ const complianceObservations = checkPhaseCompliance(phaseEvents, agentsDispatched, requiredAgents, phase);
48574
+ const tasksCompleted = phaseEvents.filter((e) => e.type === "task.completed").length;
48575
+ const keyDecisions = [];
48576
+ if (contextMd) {
48577
+ const decisionSection = contextMd.match(/## Decisions\r?\n([\s\S]*?)(?:\r?\n##|$)/);
48578
+ if (decisionSection) {
48579
+ const lines = decisionSection[1].split(`
48580
+ `);
48581
+ for (const line of lines) {
48582
+ const trimmed = line.trim();
48583
+ if (trimmed.startsWith("- ")) {
48584
+ keyDecisions.push(trimmed.slice(2));
48585
+ }
48586
+ }
48587
+ }
48588
+ }
48589
+ const phaseDigest = {
48590
+ phase,
48591
+ timestamp: new Date().toISOString(),
48592
+ summary: `Phase ${phase} completed. ${tasksCompleted} tasks recorded. ${complianceObservations.length} compliance observations.`,
48593
+ agents_used: [...new Set(agentsDispatched.map(normalizeAgentName))],
48594
+ tasks_completed: tasksCompleted,
48595
+ tasks_total: tasksCompleted,
48596
+ key_decisions: keyDecisions.slice(0, 5),
48597
+ blockers_resolved: []
48598
+ };
48599
+ const knowledgeRecommendations = [];
48600
+ const sessionId = `session-${Date.now()}`;
48601
+ const now = new Date().toISOString();
48602
+ let updatedSummary;
48603
+ if (priorSummary) {
48604
+ updatedSummary = {
48605
+ ...priorSummary,
48606
+ last_updated: now,
48607
+ last_phase_covered: Math.max(priorSummary.last_phase_covered, phase),
48608
+ digest: priorSummary.digest + `
48609
+
48610
+ ### Phase ${phase}
48611
+ ${phaseDigest.summary}`,
48612
+ phase_digests: [...priorSummary.phase_digests, phaseDigest],
48613
+ compliance_observations: [
48614
+ ...priorSummary.compliance_observations,
48615
+ ...complianceObservations
48616
+ ],
48617
+ knowledge_recommendations: knowledgeRecommendations
48618
+ };
48619
+ } else {
48620
+ updatedSummary = {
48621
+ schema_version: 1,
48622
+ session_id: sessionId,
48623
+ last_updated: now,
48624
+ last_phase_covered: phase,
48625
+ digest: `### Phase ${phase}
48626
+ ${phaseDigest.summary}`,
48627
+ phase_digests: [phaseDigest],
48628
+ compliance_observations: complianceObservations,
48629
+ knowledge_recommendations: knowledgeRecommendations
48630
+ };
48631
+ }
48632
+ await writeCuratorSummary(directory, updatedSummary);
48633
+ const eventsPath = path26.join(directory, ".swarm", "events.jsonl");
48634
+ for (const obs of complianceObservations) {
48635
+ await appendKnowledge(eventsPath, {
48636
+ type: "curator_compliance",
48637
+ timestamp: obs.timestamp,
48638
+ phase: obs.phase,
48639
+ observation_type: obs.type,
48640
+ severity: obs.severity,
48641
+ description: obs.description
48642
+ });
48643
+ }
48644
+ const result = {
48645
+ phase,
48646
+ digest: phaseDigest,
48647
+ compliance: complianceObservations,
48648
+ knowledge_recommendations: knowledgeRecommendations,
48649
+ summary_updated: true
48650
+ };
48651
+ getGlobalEventBus().publish("curator.phase.completed", {
48652
+ phase,
48653
+ compliance_count: complianceObservations.length,
48654
+ summary_updated: true
48655
+ });
48656
+ return result;
48657
+ } catch (err2) {
48658
+ getGlobalEventBus().publish("curator.error", {
48659
+ operation: "phase",
48660
+ phase,
48661
+ error: String(err2)
48662
+ });
48663
+ return {
48664
+ phase,
48665
+ digest: {
48666
+ phase,
48667
+ timestamp: new Date().toISOString(),
48668
+ summary: `Phase ${phase} curator run failed: ${String(err2)}`,
48669
+ agents_used: [],
48670
+ tasks_completed: 0,
48671
+ tasks_total: 0,
48672
+ key_decisions: [],
48673
+ blockers_resolved: []
48674
+ },
48675
+ compliance: [],
48676
+ knowledge_recommendations: [],
48677
+ summary_updated: false
48678
+ };
48679
+ }
48680
+ }
48681
+ async function applyCuratorKnowledgeUpdates(directory, recommendations, _knowledgeConfig) {
48682
+ let applied = 0;
48683
+ let skipped = 0;
48684
+ if (recommendations.length === 0) {
48685
+ return { applied, skipped };
48686
+ }
48687
+ const knowledgePath = resolveSwarmKnowledgePath(directory);
48688
+ const entries = await readKnowledge(knowledgePath);
48689
+ let modified = false;
48690
+ const appliedIds = new Set;
48691
+ const updatedEntries = entries.map((entry) => {
48692
+ const rec = recommendations.find((r) => r.entry_id === entry.id);
48693
+ if (!rec)
48694
+ return entry;
48695
+ switch (rec.action) {
48696
+ case "promote":
48697
+ appliedIds.add(entry.id);
48698
+ applied++;
48699
+ modified = true;
48700
+ return {
48701
+ ...entry,
48702
+ hive_eligible: true,
48703
+ confidence: Math.min(1, (entry.confidence ?? 0) + 0.1),
48704
+ updated_at: new Date().toISOString()
48705
+ };
48706
+ case "archive":
48707
+ appliedIds.add(entry.id);
48708
+ applied++;
48709
+ modified = true;
48710
+ return {
48711
+ ...entry,
48712
+ status: "archived",
48713
+ updated_at: new Date().toISOString()
48714
+ };
48715
+ case "flag_contradiction":
48716
+ appliedIds.add(entry.id);
48717
+ applied++;
48718
+ modified = true;
48719
+ return {
48720
+ ...entry,
48721
+ tags: [
48722
+ ...entry.tags ?? [],
48723
+ `contradiction:${(rec.reason ?? "").slice(0, 50)}`
48724
+ ],
48725
+ updated_at: new Date().toISOString()
48726
+ };
48727
+ default:
48728
+ return entry;
48729
+ }
48730
+ });
48731
+ for (const rec of recommendations) {
48732
+ if (rec.entry_id !== undefined && !appliedIds.has(rec.entry_id)) {
48733
+ const found = entries.some((e) => e.id === rec.entry_id);
48734
+ if (!found) {
48735
+ console.warn(`[curator] applyCuratorKnowledgeUpdates: entry_id '${rec.entry_id}' not found \u2014 skipping`);
48736
+ }
48737
+ skipped++;
48738
+ }
48739
+ }
48740
+ if (modified) {
48741
+ await rewriteKnowledge(knowledgePath, updatedEntries);
48742
+ }
48743
+ return { applied, skipped };
48744
+ }
48745
+
48746
+ // src/hooks/phase-monitor.ts
48325
48747
  init_utils2();
48326
48748
  function createPhaseMonitorHook(directory, preflightManager) {
48327
48749
  let lastKnownPhase = null;
@@ -48332,6 +48754,12 @@ function createPhaseMonitorHook(directory, preflightManager) {
48332
48754
  const currentPhase = plan.current_phase ?? 1;
48333
48755
  if (lastKnownPhase === null) {
48334
48756
  lastKnownPhase = currentPhase;
48757
+ try {
48758
+ const curatorConfig = CuratorConfigSchema.parse({});
48759
+ if (curatorConfig.enabled && curatorConfig.init_enabled) {
48760
+ await runCuratorInit(directory, curatorConfig);
48761
+ }
48762
+ } catch {}
48335
48763
  return;
48336
48764
  }
48337
48765
  if (currentPhase !== lastKnownPhase) {
@@ -48432,7 +48860,7 @@ ${originalText}`;
48432
48860
  };
48433
48861
  }
48434
48862
  // src/hooks/system-enhancer.ts
48435
- import * as fs15 from "fs";
48863
+ import * as fs16 from "fs";
48436
48864
  init_manager();
48437
48865
  init_detector();
48438
48866
  init_manager2();
@@ -48440,8 +48868,8 @@ init_manager2();
48440
48868
  // src/services/decision-drift-analyzer.ts
48441
48869
  init_utils2();
48442
48870
  init_manager2();
48443
- import * as fs14 from "fs";
48444
- import * as path26 from "path";
48871
+ import * as fs15 from "fs";
48872
+ import * as path27 from "path";
48445
48873
  var DEFAULT_DRIFT_CONFIG = {
48446
48874
  staleThresholdPhases: 1,
48447
48875
  detectContradictions: true,
@@ -48595,11 +49023,11 @@ async function analyzeDecisionDrift(directory, config3 = {}) {
48595
49023
  currentPhase = legacyPhase;
48596
49024
  }
48597
49025
  }
48598
- const contextPath = path26.join(directory, ".swarm", "context.md");
49026
+ const contextPath = path27.join(directory, ".swarm", "context.md");
48599
49027
  let contextContent = "";
48600
49028
  try {
48601
- if (fs14.existsSync(contextPath)) {
48602
- contextContent = fs14.readFileSync(contextPath, "utf-8");
49029
+ if (fs15.existsSync(contextPath)) {
49030
+ contextContent = fs15.readFileSync(contextPath, "utf-8");
48603
49031
  }
48604
49032
  } catch {
48605
49033
  return {
@@ -49064,7 +49492,7 @@ ${top5.map((d) => `- [${d.category}] ${d.directive}`).join(`
49064
49492
  continue;
49065
49493
  const ts = retro.timestamp ?? b.bundle.created_at;
49066
49494
  const ageMs = now - new Date(ts).getTime();
49067
- if (isNaN(ageMs) || ageMs > cutoffMs)
49495
+ if (Number.isNaN(ageMs) || ageMs > cutoffMs)
49068
49496
  continue;
49069
49497
  allRetros.push({ entry: retro, timestamp: ts });
49070
49498
  }
@@ -49076,11 +49504,11 @@ ${top5.map((d) => `- [${d.category}] ${d.directive}`).join(`
49076
49504
  allRetros.sort((a, b) => {
49077
49505
  const ta = new Date(a.timestamp).getTime();
49078
49506
  const tb = new Date(b.timestamp).getTime();
49079
- if (isNaN(ta) && isNaN(tb))
49507
+ if (Number.isNaN(ta) && Number.isNaN(tb))
49080
49508
  return 0;
49081
- if (isNaN(ta))
49509
+ if (Number.isNaN(ta))
49082
49510
  return 1;
49083
- if (isNaN(tb))
49511
+ if (Number.isNaN(tb))
49084
49512
  return -1;
49085
49513
  return tb - ta;
49086
49514
  });
@@ -49125,7 +49553,7 @@ async function buildCoderRetroInjection(directory, currentPhaseNumber) {
49125
49553
  if (!retroEntry || retroEntry.verdict === "fail")
49126
49554
  return null;
49127
49555
  const lessons = retroEntry.lessons_learned ?? [];
49128
- const summaryLine = `[SWARM RETROSPECTIVE] From Phase ${prevPhase}:${retroEntry.summary ? " " + retroEntry.summary : ""}`;
49556
+ const summaryLine = `[SWARM RETROSPECTIVE] From Phase ${prevPhase}:${retroEntry.summary ? ` ${retroEntry.summary}` : ""}`;
49129
49557
  const allLines = [summaryLine, ...lessons];
49130
49558
  const text = allLines.join(`
49131
49559
  `);
@@ -49242,11 +49670,11 @@ function createSystemEnhancerHook(config3, directory) {
49242
49670
  if (handoffContent) {
49243
49671
  const handoffPath = validateSwarmPath(directory, "handoff.md");
49244
49672
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
49245
- if (fs15.existsSync(consumedPath)) {
49673
+ if (fs16.existsSync(consumedPath)) {
49246
49674
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
49247
- fs15.unlinkSync(consumedPath);
49675
+ fs16.unlinkSync(consumedPath);
49248
49676
  }
49249
- fs15.renameSync(handoffPath, consumedPath);
49677
+ fs16.renameSync(handoffPath, consumedPath);
49250
49678
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
49251
49679
  The previous model's session ended. Here is your starting context:
49252
49680
 
@@ -49522,11 +49950,11 @@ ${budgetWarning}`);
49522
49950
  if (handoffContent) {
49523
49951
  const handoffPath = validateSwarmPath(directory, "handoff.md");
49524
49952
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
49525
- if (fs15.existsSync(consumedPath)) {
49953
+ if (fs16.existsSync(consumedPath)) {
49526
49954
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
49527
- fs15.unlinkSync(consumedPath);
49955
+ fs16.unlinkSync(consumedPath);
49528
49956
  }
49529
- fs15.renameSync(handoffPath, consumedPath);
49957
+ fs16.renameSync(handoffPath, consumedPath);
49530
49958
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
49531
49959
  The previous model's session ended. Here is your starting context:
49532
49960
 
@@ -50204,7 +50632,7 @@ function createDarkMatterDetectorHook(directory) {
50204
50632
  // src/hooks/knowledge-reader.ts
50205
50633
  import { existsSync as existsSync18 } from "fs";
50206
50634
  import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
50207
- import * as path27 from "path";
50635
+ import * as path28 from "path";
50208
50636
  var JACCARD_THRESHOLD = 0.6;
50209
50637
  var HIVE_TIER_BOOST = 0.05;
50210
50638
  var SAME_PROJECT_PENALTY = -0.05;
@@ -50252,7 +50680,7 @@ function inferCategoriesFromPhase(phaseDescription) {
50252
50680
  return ["process", "tooling"];
50253
50681
  }
50254
50682
  async function recordLessonsShown(directory, lessonIds, currentPhase) {
50255
- const shownFile = path27.join(directory, ".swarm", ".knowledge-shown.json");
50683
+ const shownFile = path28.join(directory, ".swarm", ".knowledge-shown.json");
50256
50684
  try {
50257
50685
  let shownData = {};
50258
50686
  if (existsSync18(shownFile)) {
@@ -50260,7 +50688,7 @@ async function recordLessonsShown(directory, lessonIds, currentPhase) {
50260
50688
  shownData = JSON.parse(content);
50261
50689
  }
50262
50690
  shownData[currentPhase] = lessonIds;
50263
- await mkdir4(path27.dirname(shownFile), { recursive: true });
50691
+ await mkdir4(path28.dirname(shownFile), { recursive: true });
50264
50692
  await writeFile4(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
50265
50693
  } catch {
50266
50694
  console.warn("[swarm] Knowledge: failed to record shown lessons");
@@ -50355,7 +50783,7 @@ async function readMergedKnowledge(directory, config3, context) {
50355
50783
  return topN;
50356
50784
  }
50357
50785
  async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
50358
- const shownFile = path27.join(directory, ".swarm", ".knowledge-shown.json");
50786
+ const shownFile = path28.join(directory, ".swarm", ".knowledge-shown.json");
50359
50787
  try {
50360
50788
  if (!existsSync18(shownFile)) {
50361
50789
  return;
@@ -50823,6 +51251,160 @@ Use this data to avoid repeating known failure patterns.`;
50823
51251
  return prefix + summaryText + suffix;
50824
51252
  }
50825
51253
 
51254
+ // src/hooks/curator-drift.ts
51255
+ init_event_bus();
51256
+ init_utils2();
51257
+ import * as fs17 from "fs";
51258
+ import * as path29 from "path";
51259
+ var DRIFT_REPORT_PREFIX = "drift-report-phase-";
51260
+ async function readPriorDriftReports(directory) {
51261
+ const swarmDir = path29.join(directory, ".swarm");
51262
+ const entries = await fs17.promises.readdir(swarmDir).catch(() => null);
51263
+ if (entries === null)
51264
+ return [];
51265
+ const reportFiles = entries.filter((name2) => name2.startsWith(DRIFT_REPORT_PREFIX) && name2.endsWith(".json")).sort();
51266
+ const reports = [];
51267
+ for (const filename of reportFiles) {
51268
+ const content = await readSwarmFileAsync(directory, filename);
51269
+ if (content === null)
51270
+ continue;
51271
+ try {
51272
+ const report = JSON.parse(content);
51273
+ if (typeof report.phase !== "number" || typeof report.alignment !== "string") {
51274
+ console.warn(`[curator-drift] Skipping corrupt drift report: ${filename}`);
51275
+ continue;
51276
+ }
51277
+ reports.push(report);
51278
+ } catch {
51279
+ console.warn(`[curator-drift] Skipping unreadable drift report: ${filename}`);
51280
+ }
51281
+ }
51282
+ reports.sort((a, b) => a.phase - b.phase);
51283
+ return reports;
51284
+ }
51285
+ async function writeDriftReport(directory, report) {
51286
+ const filename = `${DRIFT_REPORT_PREFIX}${report.phase}.json`;
51287
+ const filePath = validateSwarmPath(directory, filename);
51288
+ const swarmDir = path29.dirname(filePath);
51289
+ await fs17.promises.mkdir(swarmDir, { recursive: true });
51290
+ try {
51291
+ await fs17.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
51292
+ } catch (err2) {
51293
+ throw new Error(`[curator-drift] Failed to write drift report to ${filePath}: ${String(err2)}`);
51294
+ }
51295
+ return filePath;
51296
+ }
51297
+ async function runCriticDriftCheck(directory, phase, curatorResult, config3) {
51298
+ try {
51299
+ const planMd = await readSwarmFileAsync(directory, "plan.md");
51300
+ const specMd = await readSwarmFileAsync(directory, "spec.md");
51301
+ const priorReports = await readPriorDriftReports(directory);
51302
+ const complianceCount = curatorResult.compliance.length;
51303
+ const warningCompliance = curatorResult.compliance.filter((obs) => obs.severity === "warning");
51304
+ let alignment = "ALIGNED";
51305
+ let driftScore = 0;
51306
+ if (!planMd) {
51307
+ alignment = "MINOR_DRIFT";
51308
+ driftScore = 0.3;
51309
+ } else if (warningCompliance.length >= 3) {
51310
+ alignment = "MAJOR_DRIFT";
51311
+ driftScore = Math.min(0.9, 0.5 + warningCompliance.length * 0.1);
51312
+ } else if (warningCompliance.length >= 1 || complianceCount >= 3) {
51313
+ alignment = "MINOR_DRIFT";
51314
+ driftScore = Math.min(0.49, 0.2 + complianceCount * 0.05);
51315
+ }
51316
+ const priorSummaries = priorReports.map((r) => r.injection_summary).filter(Boolean);
51317
+ const keyCorrections = warningCompliance.map((obs) => obs.description);
51318
+ const firstDeviation = warningCompliance.length > 0 ? {
51319
+ phase,
51320
+ task: "unknown",
51321
+ description: warningCompliance[0]?.description ?? ""
51322
+ } : null;
51323
+ const payloadLines = [
51324
+ `CURATOR_DIGEST: ${JSON.stringify(curatorResult.digest)}`,
51325
+ `CURATOR_COMPLIANCE: ${JSON.stringify(curatorResult.compliance)}`,
51326
+ `PLAN: ${planMd ?? "none"}`,
51327
+ `SPEC: ${specMd ?? "none"}`,
51328
+ `PRIOR_DRIFT_REPORTS: ${JSON.stringify(priorSummaries)}`
51329
+ ];
51330
+ const payload = payloadLines.join(`
51331
+ `);
51332
+ const requirementsChecked = curatorResult.digest.tasks_total;
51333
+ const requirementsSatisfied = curatorResult.digest.tasks_completed;
51334
+ const injectionSummaryRaw = `Phase ${phase}: ${alignment} (${driftScore.toFixed(2)}) \u2014 ${firstDeviation ? firstDeviation.description : "all requirements on track"}.${keyCorrections.length > 0 ? `Correction: ${keyCorrections[0] ?? ""}.` : ""}`;
51335
+ const injectionSummary = injectionSummaryRaw.slice(0, config3.drift_inject_max_chars);
51336
+ const report = {
51337
+ schema_version: 1,
51338
+ phase,
51339
+ timestamp: new Date().toISOString(),
51340
+ alignment,
51341
+ drift_score: driftScore,
51342
+ first_deviation: firstDeviation,
51343
+ compounding_effects: priorReports.filter((r) => r.alignment !== "ALIGNED").map((r) => `Phase ${r.phase}: ${r.alignment}`).slice(0, 5),
51344
+ corrections: keyCorrections.slice(0, 5),
51345
+ requirements_checked: requirementsChecked,
51346
+ requirements_satisfied: requirementsSatisfied,
51347
+ scope_additions: [],
51348
+ injection_summary: injectionSummary
51349
+ };
51350
+ const reportPath = await writeDriftReport(directory, report);
51351
+ getGlobalEventBus().publish("curator.drift.completed", {
51352
+ phase,
51353
+ alignment,
51354
+ drift_score: driftScore,
51355
+ report_path: reportPath
51356
+ });
51357
+ const injectionText = injectionSummary;
51358
+ return {
51359
+ phase,
51360
+ report,
51361
+ report_path: reportPath,
51362
+ injection_text: injectionText
51363
+ };
51364
+ } catch (err2) {
51365
+ getGlobalEventBus().publish("curator.error", {
51366
+ operation: "drift",
51367
+ phase,
51368
+ error: String(err2)
51369
+ });
51370
+ const defaultReport = {
51371
+ schema_version: 1,
51372
+ phase,
51373
+ timestamp: new Date().toISOString(),
51374
+ alignment: "ALIGNED",
51375
+ drift_score: 0,
51376
+ first_deviation: null,
51377
+ compounding_effects: [],
51378
+ corrections: [],
51379
+ requirements_checked: 0,
51380
+ requirements_satisfied: 0,
51381
+ scope_additions: [],
51382
+ injection_summary: `Phase ${phase}: drift analysis unavailable (${String(err2)})`
51383
+ };
51384
+ return {
51385
+ phase,
51386
+ report: defaultReport,
51387
+ report_path: "",
51388
+ injection_text: ""
51389
+ };
51390
+ }
51391
+ }
51392
+ function buildDriftInjectionText(report, maxChars) {
51393
+ if (maxChars <= 0) {
51394
+ return "";
51395
+ }
51396
+ let text;
51397
+ if (report.alignment === "ALIGNED" && report.drift_score < 0.1) {
51398
+ text = `<drift_report>Phase ${report.phase}: ALIGNED, all requirements on track.</drift_report>`;
51399
+ } else {
51400
+ const keyFinding = report.first_deviation?.description ?? "no deviation recorded";
51401
+ const score = report.drift_score ?? 0;
51402
+ const correctionClause = report.corrections?.[0] ? `Correction: ${report.corrections[0]}.` : "";
51403
+ text = `<drift_report>Phase ${report.phase}: ${report.alignment} (${score.toFixed(2)}) \u2014 ${keyFinding}. ${correctionClause}</drift_report>`;
51404
+ }
51405
+ return text.slice(0, maxChars);
51406
+ }
51407
+
50826
51408
  // src/hooks/knowledge-injector.ts
50827
51409
  init_utils2();
50828
51410
  function formatStars(confidence) {
@@ -50924,9 +51506,9 @@ function createKnowledgeInjectorHook(directory, config3) {
50924
51506
  ].join(`
50925
51507
  `);
50926
51508
  if (runMemory) {
50927
- cachedInjectionText = runMemory + `
51509
+ cachedInjectionText = `${runMemory}
50928
51510
 
50929
- ` + knowledgeSection;
51511
+ ${knowledgeSection}`;
50930
51512
  } else {
50931
51513
  cachedInjectionText = knowledgeSection;
50932
51514
  }
@@ -50940,13 +51522,25 @@ function createKnowledgeInjectorHook(directory, config3) {
50940
51522
  ` + rejectedLines.join(`
50941
51523
  `);
50942
51524
  }
51525
+ try {
51526
+ const driftReports = await readPriorDriftReports(directory);
51527
+ if (driftReports.length > 0 && cachedInjectionText !== null) {
51528
+ const latestReport = driftReports[driftReports.length - 1];
51529
+ const driftText = buildDriftInjectionText(latestReport, 500);
51530
+ if (driftText) {
51531
+ cachedInjectionText = `${driftText}
51532
+
51533
+ ${cachedInjectionText}`;
51534
+ }
51535
+ }
51536
+ } catch {}
50943
51537
  injectKnowledgeMessage(output, cachedInjectionText);
50944
51538
  });
50945
51539
  }
50946
51540
 
50947
51541
  // src/hooks/steering-consumed.ts
50948
51542
  init_utils2();
50949
- import * as fs16 from "fs";
51543
+ import * as fs18 from "fs";
50950
51544
  function recordSteeringConsumed(directory, directiveId) {
50951
51545
  try {
50952
51546
  const eventsPath = validateSwarmPath(directory, "events.jsonl");
@@ -50955,7 +51549,7 @@ function recordSteeringConsumed(directory, directiveId) {
50955
51549
  directiveId,
50956
51550
  timestamp: new Date().toISOString()
50957
51551
  };
50958
- fs16.appendFileSync(eventsPath, `${JSON.stringify(event)}
51552
+ fs18.appendFileSync(eventsPath, `${JSON.stringify(event)}
50959
51553
  `, "utf-8");
50960
51554
  } catch {}
50961
51555
  }
@@ -51000,6 +51594,27 @@ init_config_doctor();
51000
51594
 
51001
51595
  // src/session/snapshot-reader.ts
51002
51596
  init_utils2();
51597
+ import path30 from "path";
51598
+ var VALID_TASK_WORKFLOW_STATES = [
51599
+ "idle",
51600
+ "coder_delegated",
51601
+ "pre_check_passed",
51602
+ "reviewer_run",
51603
+ "tests_run",
51604
+ "complete"
51605
+ ];
51606
+ function deserializeTaskWorkflowStates(raw) {
51607
+ const m = new Map;
51608
+ if (!raw || typeof raw !== "object") {
51609
+ return m;
51610
+ }
51611
+ for (const [taskId, stateVal] of Object.entries(raw)) {
51612
+ if (VALID_TASK_WORKFLOW_STATES.includes(stateVal)) {
51613
+ m.set(taskId, stateVal);
51614
+ }
51615
+ }
51616
+ return m;
51617
+ }
51003
51618
  function deserializeAgentSession(s) {
51004
51619
  const gateLog = new Map;
51005
51620
  if (s.gateLog) {
@@ -51042,7 +51657,7 @@ function deserializeAgentSession(s) {
51042
51657
  phaseAgentsDispatched,
51043
51658
  qaSkipCount: s.qaSkipCount ?? 0,
51044
51659
  qaSkipTaskIds: s.qaSkipTaskIds ?? [],
51045
- taskWorkflowStates: new Map,
51660
+ taskWorkflowStates: deserializeTaskWorkflowStates(s.taskWorkflowStates),
51046
51661
  lastGateOutcome: null,
51047
51662
  declaredCoderScope: null,
51048
51663
  lastScopeViolation: null,
@@ -51096,11 +51711,53 @@ function rehydrateState(snapshot) {
51096
51711
  }
51097
51712
  }
51098
51713
  }
51714
+ async function reconcileTaskStatesFromPlan(directory) {
51715
+ let raw;
51716
+ try {
51717
+ raw = await Bun.file(path30.join(directory, ".swarm/plan.json")).text();
51718
+ } catch {
51719
+ return;
51720
+ }
51721
+ let plan;
51722
+ try {
51723
+ plan = JSON.parse(raw);
51724
+ } catch {
51725
+ return;
51726
+ }
51727
+ if (!plan?.phases || !Array.isArray(plan.phases)) {
51728
+ return;
51729
+ }
51730
+ for (const phase of plan.phases) {
51731
+ if (!phase?.tasks || !Array.isArray(phase.tasks)) {
51732
+ continue;
51733
+ }
51734
+ for (const task of phase.tasks) {
51735
+ if (!task?.id || typeof task.id !== "string") {
51736
+ continue;
51737
+ }
51738
+ const taskId = task.id;
51739
+ const planStatus = task.status;
51740
+ for (const session of swarmState.agentSessions.values()) {
51741
+ const currentState = getTaskState(session, taskId);
51742
+ if (planStatus === "completed" && currentState !== "tests_run" && currentState !== "complete") {
51743
+ try {
51744
+ advanceTaskState(session, taskId, "tests_run");
51745
+ } catch {}
51746
+ } else if (planStatus === "in_progress" && currentState === "idle") {
51747
+ try {
51748
+ advanceTaskState(session, taskId, "coder_delegated");
51749
+ } catch {}
51750
+ }
51751
+ }
51752
+ }
51753
+ }
51754
+ }
51099
51755
  async function loadSnapshot(directory) {
51100
51756
  try {
51101
51757
  const snapshot = await readSnapshot(directory);
51102
51758
  if (snapshot !== null) {
51103
51759
  rehydrateState(snapshot);
51760
+ await reconcileTaskStatesFromPlan(directory);
51104
51761
  }
51105
51762
  } catch {}
51106
51763
  }
@@ -51280,8 +51937,8 @@ var build_check = createSwarmTool({
51280
51937
  init_tool();
51281
51938
  init_create_tool();
51282
51939
  import { spawnSync } from "child_process";
51283
- import * as fs17 from "fs";
51284
- import * as path28 from "path";
51940
+ import * as fs19 from "fs";
51941
+ import * as path31 from "path";
51285
51942
  var CHECKPOINT_LOG_PATH = ".swarm/checkpoints.json";
51286
51943
  var MAX_LABEL_LENGTH = 100;
51287
51944
  var GIT_TIMEOUT_MS = 30000;
@@ -51332,13 +51989,13 @@ function validateLabel(label) {
51332
51989
  return null;
51333
51990
  }
51334
51991
  function getCheckpointLogPath(directory) {
51335
- return path28.join(directory, CHECKPOINT_LOG_PATH);
51992
+ return path31.join(directory, CHECKPOINT_LOG_PATH);
51336
51993
  }
51337
51994
  function readCheckpointLog(directory) {
51338
51995
  const logPath = getCheckpointLogPath(directory);
51339
51996
  try {
51340
- if (fs17.existsSync(logPath)) {
51341
- const content = fs17.readFileSync(logPath, "utf-8");
51997
+ if (fs19.existsSync(logPath)) {
51998
+ const content = fs19.readFileSync(logPath, "utf-8");
51342
51999
  const parsed = JSON.parse(content);
51343
52000
  if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
51344
52001
  return { version: 1, checkpoints: [] };
@@ -51350,13 +52007,13 @@ function readCheckpointLog(directory) {
51350
52007
  }
51351
52008
  function writeCheckpointLog(log2, directory) {
51352
52009
  const logPath = getCheckpointLogPath(directory);
51353
- const dir = path28.dirname(logPath);
51354
- if (!fs17.existsSync(dir)) {
51355
- fs17.mkdirSync(dir, { recursive: true });
52010
+ const dir = path31.dirname(logPath);
52011
+ if (!fs19.existsSync(dir)) {
52012
+ fs19.mkdirSync(dir, { recursive: true });
51356
52013
  }
51357
52014
  const tempPath = `${logPath}.tmp`;
51358
- fs17.writeFileSync(tempPath, JSON.stringify(log2, null, 2), "utf-8");
51359
- fs17.renameSync(tempPath, logPath);
52015
+ fs19.writeFileSync(tempPath, JSON.stringify(log2, null, 2), "utf-8");
52016
+ fs19.renameSync(tempPath, logPath);
51360
52017
  }
51361
52018
  function gitExec(args2) {
51362
52019
  const result = spawnSync("git", args2, {
@@ -51557,8 +52214,8 @@ var checkpoint = createSwarmTool({
51557
52214
  // src/tools/complexity-hotspots.ts
51558
52215
  init_dist();
51559
52216
  init_create_tool();
51560
- import * as fs18 from "fs";
51561
- import * as path29 from "path";
52217
+ import * as fs20 from "fs";
52218
+ import * as path32 from "path";
51562
52219
  var MAX_FILE_SIZE_BYTES2 = 256 * 1024;
51563
52220
  var DEFAULT_DAYS = 90;
51564
52221
  var DEFAULT_TOP_N = 20;
@@ -51687,11 +52344,11 @@ function estimateComplexity(content) {
51687
52344
  }
51688
52345
  function getComplexityForFile(filePath) {
51689
52346
  try {
51690
- const stat2 = fs18.statSync(filePath);
52347
+ const stat2 = fs20.statSync(filePath);
51691
52348
  if (stat2.size > MAX_FILE_SIZE_BYTES2) {
51692
52349
  return null;
51693
52350
  }
51694
- const content = fs18.readFileSync(filePath, "utf-8");
52351
+ const content = fs20.readFileSync(filePath, "utf-8");
51695
52352
  return estimateComplexity(content);
51696
52353
  } catch {
51697
52354
  return null;
@@ -51702,7 +52359,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
51702
52359
  const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
51703
52360
  const filteredChurn = new Map;
51704
52361
  for (const [file3, count] of churnMap) {
51705
- const ext = path29.extname(file3).toLowerCase();
52362
+ const ext = path32.extname(file3).toLowerCase();
51706
52363
  if (extSet.has(ext)) {
51707
52364
  filteredChurn.set(file3, count);
51708
52365
  }
@@ -51712,8 +52369,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
51712
52369
  let analyzedFiles = 0;
51713
52370
  for (const [file3, churnCount] of filteredChurn) {
51714
52371
  let fullPath = file3;
51715
- if (!fs18.existsSync(fullPath)) {
51716
- fullPath = path29.join(cwd, file3);
52372
+ if (!fs20.existsSync(fullPath)) {
52373
+ fullPath = path32.join(cwd, file3);
51717
52374
  }
51718
52375
  const complexity = getComplexityForFile(fullPath);
51719
52376
  if (complexity !== null) {
@@ -51860,8 +52517,8 @@ var complexity_hotspots = createSwarmTool({
51860
52517
  });
51861
52518
  // src/tools/declare-scope.ts
51862
52519
  init_tool();
51863
- import * as fs19 from "fs";
51864
- import * as path30 from "path";
52520
+ import * as fs21 from "fs";
52521
+ import * as path33 from "path";
51865
52522
  init_create_tool();
51866
52523
  function validateTaskIdFormat(taskId) {
51867
52524
  const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
@@ -51940,8 +52597,8 @@ async function executeDeclareScope(args2, fallbackDir) {
51940
52597
  };
51941
52598
  }
51942
52599
  }
51943
- normalizedDir = path30.normalize(args2.working_directory);
51944
- const pathParts = normalizedDir.split(path30.sep);
52600
+ normalizedDir = path33.normalize(args2.working_directory);
52601
+ const pathParts = normalizedDir.split(path33.sep);
51945
52602
  if (pathParts.includes("..")) {
51946
52603
  return {
51947
52604
  success: false,
@@ -51951,11 +52608,11 @@ async function executeDeclareScope(args2, fallbackDir) {
51951
52608
  ]
51952
52609
  };
51953
52610
  }
51954
- const resolvedDir = path30.resolve(normalizedDir);
52611
+ const resolvedDir = path33.resolve(normalizedDir);
51955
52612
  try {
51956
- const realPath = fs19.realpathSync(resolvedDir);
51957
- const planPath2 = path30.join(realPath, ".swarm", "plan.json");
51958
- if (!fs19.existsSync(planPath2)) {
52613
+ const realPath = fs21.realpathSync(resolvedDir);
52614
+ const planPath2 = path33.join(realPath, ".swarm", "plan.json");
52615
+ if (!fs21.existsSync(planPath2)) {
51959
52616
  return {
51960
52617
  success: false,
51961
52618
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -51975,8 +52632,8 @@ async function executeDeclareScope(args2, fallbackDir) {
51975
52632
  }
51976
52633
  }
51977
52634
  const directory = normalizedDir ?? fallbackDir ?? process.cwd();
51978
- const planPath = path30.resolve(directory, ".swarm", "plan.json");
51979
- if (!fs19.existsSync(planPath)) {
52635
+ const planPath = path33.resolve(directory, ".swarm", "plan.json");
52636
+ if (!fs21.existsSync(planPath)) {
51980
52637
  return {
51981
52638
  success: false,
51982
52639
  message: "No plan found",
@@ -51985,7 +52642,7 @@ async function executeDeclareScope(args2, fallbackDir) {
51985
52642
  }
51986
52643
  let planContent;
51987
52644
  try {
51988
- planContent = JSON.parse(fs19.readFileSync(planPath, "utf-8"));
52645
+ planContent = JSON.parse(fs21.readFileSync(planPath, "utf-8"));
51989
52646
  } catch {
51990
52647
  return {
51991
52648
  success: false,
@@ -52065,20 +52722,20 @@ function validateBase(base) {
52065
52722
  function validatePaths(paths) {
52066
52723
  if (!paths)
52067
52724
  return null;
52068
- for (const path31 of paths) {
52069
- if (!path31 || path31.length === 0) {
52725
+ for (const path34 of paths) {
52726
+ if (!path34 || path34.length === 0) {
52070
52727
  return "empty path not allowed";
52071
52728
  }
52072
- if (path31.length > MAX_PATH_LENGTH) {
52729
+ if (path34.length > MAX_PATH_LENGTH) {
52073
52730
  return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
52074
52731
  }
52075
- if (SHELL_METACHARACTERS2.test(path31)) {
52732
+ if (SHELL_METACHARACTERS2.test(path34)) {
52076
52733
  return "path contains shell metacharacters";
52077
52734
  }
52078
- if (path31.startsWith("-")) {
52735
+ if (path34.startsWith("-")) {
52079
52736
  return 'path cannot start with "-" (option-like arguments not allowed)';
52080
52737
  }
52081
- if (CONTROL_CHAR_PATTERN2.test(path31)) {
52738
+ if (CONTROL_CHAR_PATTERN2.test(path34)) {
52082
52739
  return "path contains control characters";
52083
52740
  }
52084
52741
  }
@@ -52158,8 +52815,8 @@ var diff = tool({
52158
52815
  if (parts2.length >= 3) {
52159
52816
  const additions = parseInt(parts2[0], 10) || 0;
52160
52817
  const deletions = parseInt(parts2[1], 10) || 0;
52161
- const path31 = parts2[2];
52162
- files.push({ path: path31, additions, deletions });
52818
+ const path34 = parts2[2];
52819
+ files.push({ path: path34, additions, deletions });
52163
52820
  }
52164
52821
  }
52165
52822
  const contractChanges = [];
@@ -52388,8 +53045,8 @@ Use these as DOMAIN values when delegating to @sme.`;
52388
53045
  // src/tools/evidence-check.ts
52389
53046
  init_dist();
52390
53047
  init_create_tool();
52391
- import * as fs20 from "fs";
52392
- import * as path31 from "path";
53048
+ import * as fs22 from "fs";
53049
+ import * as path34 from "path";
52393
53050
  var MAX_FILE_SIZE_BYTES3 = 1024 * 1024;
52394
53051
  var MAX_EVIDENCE_FILES = 1000;
52395
53052
  var EVIDENCE_DIR = ".swarm/evidence";
@@ -52412,9 +53069,9 @@ function validateRequiredTypes(input) {
52412
53069
  return null;
52413
53070
  }
52414
53071
  function isPathWithinSwarm(filePath, cwd) {
52415
- const normalizedCwd = path31.resolve(cwd);
52416
- const swarmPath = path31.join(normalizedCwd, ".swarm");
52417
- const normalizedPath = path31.resolve(filePath);
53072
+ const normalizedCwd = path34.resolve(cwd);
53073
+ const swarmPath = path34.join(normalizedCwd, ".swarm");
53074
+ const normalizedPath = path34.resolve(filePath);
52418
53075
  return normalizedPath.startsWith(swarmPath);
52419
53076
  }
52420
53077
  function parseCompletedTasks(planContent) {
@@ -52430,12 +53087,12 @@ function parseCompletedTasks(planContent) {
52430
53087
  }
52431
53088
  function readEvidenceFiles(evidenceDir, _cwd) {
52432
53089
  const evidence = [];
52433
- if (!fs20.existsSync(evidenceDir) || !fs20.statSync(evidenceDir).isDirectory()) {
53090
+ if (!fs22.existsSync(evidenceDir) || !fs22.statSync(evidenceDir).isDirectory()) {
52434
53091
  return evidence;
52435
53092
  }
52436
53093
  let files;
52437
53094
  try {
52438
- files = fs20.readdirSync(evidenceDir);
53095
+ files = fs22.readdirSync(evidenceDir);
52439
53096
  } catch {
52440
53097
  return evidence;
52441
53098
  }
@@ -52444,14 +53101,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
52444
53101
  if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
52445
53102
  continue;
52446
53103
  }
52447
- const filePath = path31.join(evidenceDir, filename);
53104
+ const filePath = path34.join(evidenceDir, filename);
52448
53105
  try {
52449
- const resolvedPath = path31.resolve(filePath);
52450
- const evidenceDirResolved = path31.resolve(evidenceDir);
53106
+ const resolvedPath = path34.resolve(filePath);
53107
+ const evidenceDirResolved = path34.resolve(evidenceDir);
52451
53108
  if (!resolvedPath.startsWith(evidenceDirResolved)) {
52452
53109
  continue;
52453
53110
  }
52454
- const stat2 = fs20.lstatSync(filePath);
53111
+ const stat2 = fs22.lstatSync(filePath);
52455
53112
  if (!stat2.isFile()) {
52456
53113
  continue;
52457
53114
  }
@@ -52460,7 +53117,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
52460
53117
  }
52461
53118
  let fileStat;
52462
53119
  try {
52463
- fileStat = fs20.statSync(filePath);
53120
+ fileStat = fs22.statSync(filePath);
52464
53121
  if (fileStat.size > MAX_FILE_SIZE_BYTES3) {
52465
53122
  continue;
52466
53123
  }
@@ -52469,7 +53126,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
52469
53126
  }
52470
53127
  let content;
52471
53128
  try {
52472
- content = fs20.readFileSync(filePath, "utf-8");
53129
+ content = fs22.readFileSync(filePath, "utf-8");
52473
53130
  } catch {
52474
53131
  continue;
52475
53132
  }
@@ -52554,7 +53211,7 @@ var evidence_check = createSwarmTool({
52554
53211
  return JSON.stringify(errorResult, null, 2);
52555
53212
  }
52556
53213
  const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
52557
- const planPath = path31.join(cwd, PLAN_FILE);
53214
+ const planPath = path34.join(cwd, PLAN_FILE);
52558
53215
  if (!isPathWithinSwarm(planPath, cwd)) {
52559
53216
  const errorResult = {
52560
53217
  error: "plan file path validation failed",
@@ -52568,7 +53225,7 @@ var evidence_check = createSwarmTool({
52568
53225
  }
52569
53226
  let planContent;
52570
53227
  try {
52571
- planContent = fs20.readFileSync(planPath, "utf-8");
53228
+ planContent = fs22.readFileSync(planPath, "utf-8");
52572
53229
  } catch {
52573
53230
  const result2 = {
52574
53231
  message: "No completed tasks found in plan.",
@@ -52586,7 +53243,7 @@ var evidence_check = createSwarmTool({
52586
53243
  };
52587
53244
  return JSON.stringify(result2, null, 2);
52588
53245
  }
52589
- const evidenceDir = path31.join(cwd, EVIDENCE_DIR);
53246
+ const evidenceDir = path34.join(cwd, EVIDENCE_DIR);
52590
53247
  const evidence = readEvidenceFiles(evidenceDir, cwd);
52591
53248
  const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
52592
53249
  const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
@@ -52603,8 +53260,8 @@ var evidence_check = createSwarmTool({
52603
53260
  // src/tools/file-extractor.ts
52604
53261
  init_tool();
52605
53262
  init_create_tool();
52606
- import * as fs21 from "fs";
52607
- import * as path32 from "path";
53263
+ import * as fs23 from "fs";
53264
+ import * as path35 from "path";
52608
53265
  var EXT_MAP = {
52609
53266
  python: ".py",
52610
53267
  py: ".py",
@@ -52666,8 +53323,8 @@ var extract_code_blocks = createSwarmTool({
52666
53323
  execute: async (args2, directory) => {
52667
53324
  const { content, output_dir, prefix } = args2;
52668
53325
  const targetDir = output_dir || directory;
52669
- if (!fs21.existsSync(targetDir)) {
52670
- fs21.mkdirSync(targetDir, { recursive: true });
53326
+ if (!fs23.existsSync(targetDir)) {
53327
+ fs23.mkdirSync(targetDir, { recursive: true });
52671
53328
  }
52672
53329
  if (!content) {
52673
53330
  return "Error: content is required";
@@ -52685,16 +53342,16 @@ var extract_code_blocks = createSwarmTool({
52685
53342
  if (prefix) {
52686
53343
  filename = `${prefix}_${filename}`;
52687
53344
  }
52688
- let filepath = path32.join(targetDir, filename);
52689
- const base = path32.basename(filepath, path32.extname(filepath));
52690
- const ext = path32.extname(filepath);
53345
+ let filepath = path35.join(targetDir, filename);
53346
+ const base = path35.basename(filepath, path35.extname(filepath));
53347
+ const ext = path35.extname(filepath);
52691
53348
  let counter = 1;
52692
- while (fs21.existsSync(filepath)) {
52693
- filepath = path32.join(targetDir, `${base}_${counter}${ext}`);
53349
+ while (fs23.existsSync(filepath)) {
53350
+ filepath = path35.join(targetDir, `${base}_${counter}${ext}`);
52694
53351
  counter++;
52695
53352
  }
52696
53353
  try {
52697
- fs21.writeFileSync(filepath, code.trim(), "utf-8");
53354
+ fs23.writeFileSync(filepath, code.trim(), "utf-8");
52698
53355
  savedFiles.push(filepath);
52699
53356
  } catch (error93) {
52700
53357
  errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
@@ -52802,8 +53459,8 @@ var gitingest = tool({
52802
53459
  });
52803
53460
  // src/tools/imports.ts
52804
53461
  init_dist();
52805
- import * as fs22 from "fs";
52806
- import * as path33 from "path";
53462
+ import * as fs24 from "fs";
53463
+ import * as path36 from "path";
52807
53464
  var MAX_FILE_PATH_LENGTH2 = 500;
52808
53465
  var MAX_SYMBOL_LENGTH = 256;
52809
53466
  var MAX_FILE_SIZE_BYTES4 = 1024 * 1024;
@@ -52857,7 +53514,7 @@ function validateSymbolInput(symbol3) {
52857
53514
  return null;
52858
53515
  }
52859
53516
  function isBinaryFile2(filePath, buffer) {
52860
- const ext = path33.extname(filePath).toLowerCase();
53517
+ const ext = path36.extname(filePath).toLowerCase();
52861
53518
  if (ext === ".json" || ext === ".md" || ext === ".txt") {
52862
53519
  return false;
52863
53520
  }
@@ -52881,15 +53538,15 @@ function parseImports(content, targetFile, targetSymbol) {
52881
53538
  const imports = [];
52882
53539
  let _resolvedTarget;
52883
53540
  try {
52884
- _resolvedTarget = path33.resolve(targetFile);
53541
+ _resolvedTarget = path36.resolve(targetFile);
52885
53542
  } catch {
52886
53543
  _resolvedTarget = targetFile;
52887
53544
  }
52888
- const targetBasename = path33.basename(targetFile, path33.extname(targetFile));
53545
+ const targetBasename = path36.basename(targetFile, path36.extname(targetFile));
52889
53546
  const targetWithExt = targetFile;
52890
53547
  const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
52891
- const normalizedTargetWithExt = path33.normalize(targetWithExt).replace(/\\/g, "/");
52892
- const normalizedTargetWithoutExt = path33.normalize(targetWithoutExt).replace(/\\/g, "/");
53548
+ const normalizedTargetWithExt = path36.normalize(targetWithExt).replace(/\\/g, "/");
53549
+ const normalizedTargetWithoutExt = path36.normalize(targetWithoutExt).replace(/\\/g, "/");
52893
53550
  const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
52894
53551
  for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
52895
53552
  const modulePath = match[1] || match[2] || match[3];
@@ -52912,9 +53569,9 @@ function parseImports(content, targetFile, targetSymbol) {
52912
53569
  }
52913
53570
  const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
52914
53571
  let isMatch = false;
52915
- const _targetDir = path33.dirname(targetFile);
52916
- const targetExt = path33.extname(targetFile);
52917
- const targetBasenameNoExt = path33.basename(targetFile, targetExt);
53572
+ const _targetDir = path36.dirname(targetFile);
53573
+ const targetExt = path36.extname(targetFile);
53574
+ const targetBasenameNoExt = path36.basename(targetFile, targetExt);
52918
53575
  const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
52919
53576
  const moduleName = modulePath.split(/[/\\]/).pop() || "";
52920
53577
  const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
@@ -52971,7 +53628,7 @@ var SKIP_DIRECTORIES2 = new Set([
52971
53628
  function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
52972
53629
  let entries;
52973
53630
  try {
52974
- entries = fs22.readdirSync(dir);
53631
+ entries = fs24.readdirSync(dir);
52975
53632
  } catch (e) {
52976
53633
  stats.fileErrors.push({
52977
53634
  path: dir,
@@ -52982,13 +53639,13 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
52982
53639
  entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
52983
53640
  for (const entry of entries) {
52984
53641
  if (SKIP_DIRECTORIES2.has(entry)) {
52985
- stats.skippedDirs.push(path33.join(dir, entry));
53642
+ stats.skippedDirs.push(path36.join(dir, entry));
52986
53643
  continue;
52987
53644
  }
52988
- const fullPath = path33.join(dir, entry);
53645
+ const fullPath = path36.join(dir, entry);
52989
53646
  let stat2;
52990
53647
  try {
52991
- stat2 = fs22.statSync(fullPath);
53648
+ stat2 = fs24.statSync(fullPath);
52992
53649
  } catch (e) {
52993
53650
  stats.fileErrors.push({
52994
53651
  path: fullPath,
@@ -52999,7 +53656,7 @@ function findSourceFiles2(dir, files = [], stats = { skippedDirs: [], skippedFil
52999
53656
  if (stat2.isDirectory()) {
53000
53657
  findSourceFiles2(fullPath, files, stats);
53001
53658
  } else if (stat2.isFile()) {
53002
- const ext = path33.extname(fullPath).toLowerCase();
53659
+ const ext = path36.extname(fullPath).toLowerCase();
53003
53660
  if (SUPPORTED_EXTENSIONS.includes(ext)) {
53004
53661
  files.push(fullPath);
53005
53662
  }
@@ -53055,8 +53712,8 @@ var imports = tool({
53055
53712
  return JSON.stringify(errorResult, null, 2);
53056
53713
  }
53057
53714
  try {
53058
- const targetFile = path33.resolve(file3);
53059
- if (!fs22.existsSync(targetFile)) {
53715
+ const targetFile = path36.resolve(file3);
53716
+ if (!fs24.existsSync(targetFile)) {
53060
53717
  const errorResult = {
53061
53718
  error: `target file not found: ${file3}`,
53062
53719
  target: file3,
@@ -53066,7 +53723,7 @@ var imports = tool({
53066
53723
  };
53067
53724
  return JSON.stringify(errorResult, null, 2);
53068
53725
  }
53069
- const targetStat = fs22.statSync(targetFile);
53726
+ const targetStat = fs24.statSync(targetFile);
53070
53727
  if (!targetStat.isFile()) {
53071
53728
  const errorResult = {
53072
53729
  error: "target must be a file, not a directory",
@@ -53077,7 +53734,7 @@ var imports = tool({
53077
53734
  };
53078
53735
  return JSON.stringify(errorResult, null, 2);
53079
53736
  }
53080
- const baseDir = path33.dirname(targetFile);
53737
+ const baseDir = path36.dirname(targetFile);
53081
53738
  const scanStats = {
53082
53739
  skippedDirs: [],
53083
53740
  skippedFiles: 0,
@@ -53092,12 +53749,12 @@ var imports = tool({
53092
53749
  if (consumers.length >= MAX_CONSUMERS)
53093
53750
  break;
53094
53751
  try {
53095
- const stat2 = fs22.statSync(filePath);
53752
+ const stat2 = fs24.statSync(filePath);
53096
53753
  if (stat2.size > MAX_FILE_SIZE_BYTES4) {
53097
53754
  skippedFileCount++;
53098
53755
  continue;
53099
53756
  }
53100
- const buffer = fs22.readFileSync(filePath);
53757
+ const buffer = fs24.readFileSync(filePath);
53101
53758
  if (isBinaryFile2(filePath, buffer)) {
53102
53759
  skippedFileCount++;
53103
53760
  continue;
@@ -53166,8 +53823,8 @@ init_lint();
53166
53823
 
53167
53824
  // src/tools/phase-complete.ts
53168
53825
  init_dist();
53169
- import * as fs23 from "fs";
53170
- import * as path34 from "path";
53826
+ import * as fs25 from "fs";
53827
+ import * as path37 from "path";
53171
53828
  init_manager();
53172
53829
  init_utils2();
53173
53830
  init_create_tool();
@@ -53357,7 +54014,7 @@ async function executePhaseComplete(args2, workingDirectory) {
53357
54014
  }
53358
54015
  if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
53359
54016
  try {
53360
- const projectName = path34.basename(dir);
54017
+ const projectName = path37.basename(dir);
53361
54018
  const knowledgeConfig = {
53362
54019
  enabled: true,
53363
54020
  swarm_max_entries: 100,
@@ -53380,6 +54037,16 @@ async function executePhaseComplete(args2, workingDirectory) {
53380
54037
  console.warn("[phase_complete] Failed to curate lessons from retrospective:", error93);
53381
54038
  }
53382
54039
  }
54040
+ try {
54041
+ const curatorConfig = CuratorConfigSchema.parse(config3.curator ?? {});
54042
+ if (curatorConfig.enabled && curatorConfig.phase_enabled) {
54043
+ const curatorResult = await runCuratorPhase(dir, phase, agentsDispatched, curatorConfig, {});
54044
+ await applyCuratorKnowledgeUpdates(dir, curatorResult.knowledge_recommendations, {});
54045
+ await runCriticDriftCheck(dir, phase, curatorResult, curatorConfig);
54046
+ }
54047
+ } catch (curatorError) {
54048
+ console.warn("[phase_complete] Curator pipeline error (non-blocking):", curatorError);
54049
+ }
53383
54050
  const effectiveRequired = [...phaseCompleteConfig.required_agents];
53384
54051
  if (phaseCompleteConfig.require_docs && !effectiveRequired.includes("docs")) {
53385
54052
  effectiveRequired.push("docs");
@@ -53418,7 +54085,7 @@ async function executePhaseComplete(args2, workingDirectory) {
53418
54085
  };
53419
54086
  try {
53420
54087
  const eventsPath = validateSwarmPath(dir, "events.jsonl");
53421
- fs23.appendFileSync(eventsPath, `${JSON.stringify(event)}
54088
+ fs25.appendFileSync(eventsPath, `${JSON.stringify(event)}
53422
54089
  `, "utf-8");
53423
54090
  } catch (writeError) {
53424
54091
  warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -53476,8 +54143,8 @@ init_dist();
53476
54143
  init_discovery();
53477
54144
  init_utils();
53478
54145
  init_create_tool();
53479
- import * as fs24 from "fs";
53480
- import * as path35 from "path";
54146
+ import * as fs26 from "fs";
54147
+ import * as path38 from "path";
53481
54148
  var MAX_OUTPUT_BYTES5 = 52428800;
53482
54149
  var AUDIT_TIMEOUT_MS = 120000;
53483
54150
  function isValidEcosystem(value) {
@@ -53495,28 +54162,28 @@ function validateArgs3(args2) {
53495
54162
  function detectEcosystems(directory) {
53496
54163
  const ecosystems = [];
53497
54164
  const cwd = directory;
53498
- if (fs24.existsSync(path35.join(cwd, "package.json"))) {
54165
+ if (fs26.existsSync(path38.join(cwd, "package.json"))) {
53499
54166
  ecosystems.push("npm");
53500
54167
  }
53501
- if (fs24.existsSync(path35.join(cwd, "pyproject.toml")) || fs24.existsSync(path35.join(cwd, "requirements.txt"))) {
54168
+ if (fs26.existsSync(path38.join(cwd, "pyproject.toml")) || fs26.existsSync(path38.join(cwd, "requirements.txt"))) {
53502
54169
  ecosystems.push("pip");
53503
54170
  }
53504
- if (fs24.existsSync(path35.join(cwd, "Cargo.toml"))) {
54171
+ if (fs26.existsSync(path38.join(cwd, "Cargo.toml"))) {
53505
54172
  ecosystems.push("cargo");
53506
54173
  }
53507
- if (fs24.existsSync(path35.join(cwd, "go.mod"))) {
54174
+ if (fs26.existsSync(path38.join(cwd, "go.mod"))) {
53508
54175
  ecosystems.push("go");
53509
54176
  }
53510
54177
  try {
53511
- const files = fs24.readdirSync(cwd);
54178
+ const files = fs26.readdirSync(cwd);
53512
54179
  if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
53513
54180
  ecosystems.push("dotnet");
53514
54181
  }
53515
54182
  } catch {}
53516
- if (fs24.existsSync(path35.join(cwd, "Gemfile")) || fs24.existsSync(path35.join(cwd, "Gemfile.lock"))) {
54183
+ if (fs26.existsSync(path38.join(cwd, "Gemfile")) || fs26.existsSync(path38.join(cwd, "Gemfile.lock"))) {
53517
54184
  ecosystems.push("ruby");
53518
54185
  }
53519
- if (fs24.existsSync(path35.join(cwd, "pubspec.yaml"))) {
54186
+ if (fs26.existsSync(path38.join(cwd, "pubspec.yaml"))) {
53520
54187
  ecosystems.push("dart");
53521
54188
  }
53522
54189
  return ecosystems;
@@ -54577,8 +55244,8 @@ var SUPPORTED_PARSER_EXTENSIONS = new Set([
54577
55244
  ]);
54578
55245
  // src/tools/pre-check-batch.ts
54579
55246
  init_dist();
54580
- import * as fs27 from "fs";
54581
- import * as path38 from "path";
55247
+ import * as fs29 from "fs";
55248
+ import * as path41 from "path";
54582
55249
 
54583
55250
  // node_modules/yocto-queue/index.js
54584
55251
  class Node2 {
@@ -54723,8 +55390,8 @@ function pLimit(concurrency) {
54723
55390
  },
54724
55391
  map: {
54725
55392
  async value(iterable, function_) {
54726
- const promises = Array.from(iterable, (value, index) => this(function_, value, index));
54727
- return Promise.all(promises);
55393
+ const promises2 = Array.from(iterable, (value, index) => this(function_, value, index));
55394
+ return Promise.all(promises2);
54728
55395
  }
54729
55396
  }
54730
55397
  });
@@ -54745,8 +55412,8 @@ init_lint();
54745
55412
  init_manager();
54746
55413
 
54747
55414
  // src/quality/metrics.ts
54748
- import * as fs25 from "fs";
54749
- import * as path36 from "path";
55415
+ import * as fs27 from "fs";
55416
+ import * as path39 from "path";
54750
55417
  var MAX_FILE_SIZE_BYTES5 = 256 * 1024;
54751
55418
  var MIN_DUPLICATION_LINES = 10;
54752
55419
  function estimateCyclomaticComplexity(content) {
@@ -54784,11 +55451,11 @@ function estimateCyclomaticComplexity(content) {
54784
55451
  }
54785
55452
  function getComplexityForFile2(filePath) {
54786
55453
  try {
54787
- const stat2 = fs25.statSync(filePath);
55454
+ const stat2 = fs27.statSync(filePath);
54788
55455
  if (stat2.size > MAX_FILE_SIZE_BYTES5) {
54789
55456
  return null;
54790
55457
  }
54791
- const content = fs25.readFileSync(filePath, "utf-8");
55458
+ const content = fs27.readFileSync(filePath, "utf-8");
54792
55459
  return estimateCyclomaticComplexity(content);
54793
55460
  } catch {
54794
55461
  return null;
@@ -54798,8 +55465,8 @@ async function computeComplexityDelta(files, workingDir) {
54798
55465
  let totalComplexity = 0;
54799
55466
  const analyzedFiles = [];
54800
55467
  for (const file3 of files) {
54801
- const fullPath = path36.isAbsolute(file3) ? file3 : path36.join(workingDir, file3);
54802
- if (!fs25.existsSync(fullPath)) {
55468
+ const fullPath = path39.isAbsolute(file3) ? file3 : path39.join(workingDir, file3);
55469
+ if (!fs27.existsSync(fullPath)) {
54803
55470
  continue;
54804
55471
  }
54805
55472
  const complexity = getComplexityForFile2(fullPath);
@@ -54920,8 +55587,8 @@ function countGoExports(content) {
54920
55587
  }
54921
55588
  function getExportCountForFile(filePath) {
54922
55589
  try {
54923
- const content = fs25.readFileSync(filePath, "utf-8");
54924
- const ext = path36.extname(filePath).toLowerCase();
55590
+ const content = fs27.readFileSync(filePath, "utf-8");
55591
+ const ext = path39.extname(filePath).toLowerCase();
54925
55592
  switch (ext) {
54926
55593
  case ".ts":
54927
55594
  case ".tsx":
@@ -54947,8 +55614,8 @@ async function computePublicApiDelta(files, workingDir) {
54947
55614
  let totalExports = 0;
54948
55615
  const analyzedFiles = [];
54949
55616
  for (const file3 of files) {
54950
- const fullPath = path36.isAbsolute(file3) ? file3 : path36.join(workingDir, file3);
54951
- if (!fs25.existsSync(fullPath)) {
55617
+ const fullPath = path39.isAbsolute(file3) ? file3 : path39.join(workingDir, file3);
55618
+ if (!fs27.existsSync(fullPath)) {
54952
55619
  continue;
54953
55620
  }
54954
55621
  const exports = getExportCountForFile(fullPath);
@@ -54981,16 +55648,16 @@ async function computeDuplicationRatio(files, workingDir) {
54981
55648
  let duplicateLines = 0;
54982
55649
  const analyzedFiles = [];
54983
55650
  for (const file3 of files) {
54984
- const fullPath = path36.isAbsolute(file3) ? file3 : path36.join(workingDir, file3);
54985
- if (!fs25.existsSync(fullPath)) {
55651
+ const fullPath = path39.isAbsolute(file3) ? file3 : path39.join(workingDir, file3);
55652
+ if (!fs27.existsSync(fullPath)) {
54986
55653
  continue;
54987
55654
  }
54988
55655
  try {
54989
- const stat2 = fs25.statSync(fullPath);
55656
+ const stat2 = fs27.statSync(fullPath);
54990
55657
  if (stat2.size > MAX_FILE_SIZE_BYTES5) {
54991
55658
  continue;
54992
55659
  }
54993
- const content = fs25.readFileSync(fullPath, "utf-8");
55660
+ const content = fs27.readFileSync(fullPath, "utf-8");
54994
55661
  const lines = content.split(`
54995
55662
  `).filter((line) => line.trim().length > 0);
54996
55663
  if (lines.length < MIN_DUPLICATION_LINES) {
@@ -55014,8 +55681,8 @@ function countCodeLines(content) {
55014
55681
  return lines.length;
55015
55682
  }
55016
55683
  function isTestFile(filePath) {
55017
- const basename8 = path36.basename(filePath);
55018
- const _ext = path36.extname(filePath).toLowerCase();
55684
+ const basename8 = path39.basename(filePath);
55685
+ const _ext = path39.extname(filePath).toLowerCase();
55019
55686
  const testPatterns = [
55020
55687
  ".test.",
55021
55688
  ".spec.",
@@ -55096,8 +55763,8 @@ function matchGlobSegment(globSegments, pathSegments) {
55096
55763
  }
55097
55764
  return gIndex === globSegments.length && pIndex === pathSegments.length;
55098
55765
  }
55099
- function matchesGlobSegment(path37, glob) {
55100
- const normalizedPath = path37.replace(/\\/g, "/");
55766
+ function matchesGlobSegment(path40, glob) {
55767
+ const normalizedPath = path40.replace(/\\/g, "/");
55101
55768
  const normalizedGlob = glob.replace(/\\/g, "/");
55102
55769
  if (normalizedPath.includes("//")) {
55103
55770
  return false;
@@ -55128,8 +55795,8 @@ function simpleGlobToRegex(glob) {
55128
55795
  function hasGlobstar(glob) {
55129
55796
  return glob.includes("**");
55130
55797
  }
55131
- function globMatches(path37, glob) {
55132
- const normalizedPath = path37.replace(/\\/g, "/");
55798
+ function globMatches(path40, glob) {
55799
+ const normalizedPath = path40.replace(/\\/g, "/");
55133
55800
  if (!glob || glob === "") {
55134
55801
  if (normalizedPath.includes("//")) {
55135
55802
  return false;
@@ -55165,31 +55832,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
55165
55832
  async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
55166
55833
  let testLines = 0;
55167
55834
  let codeLines = 0;
55168
- const srcDir = path36.join(workingDir, "src");
55169
- if (fs25.existsSync(srcDir)) {
55835
+ const srcDir = path39.join(workingDir, "src");
55836
+ if (fs27.existsSync(srcDir)) {
55170
55837
  await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
55171
55838
  codeLines += lines;
55172
55839
  });
55173
55840
  }
55174
55841
  const possibleSrcDirs = ["lib", "app", "source", "core"];
55175
55842
  for (const dir of possibleSrcDirs) {
55176
- const dirPath = path36.join(workingDir, dir);
55177
- if (fs25.existsSync(dirPath)) {
55843
+ const dirPath = path39.join(workingDir, dir);
55844
+ if (fs27.existsSync(dirPath)) {
55178
55845
  await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
55179
55846
  codeLines += lines;
55180
55847
  });
55181
55848
  }
55182
55849
  }
55183
- const testsDir = path36.join(workingDir, "tests");
55184
- if (fs25.existsSync(testsDir)) {
55850
+ const testsDir = path39.join(workingDir, "tests");
55851
+ if (fs27.existsSync(testsDir)) {
55185
55852
  await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
55186
55853
  testLines += lines;
55187
55854
  });
55188
55855
  }
55189
55856
  const possibleTestDirs = ["test", "__tests__", "specs"];
55190
55857
  for (const dir of possibleTestDirs) {
55191
- const dirPath = path36.join(workingDir, dir);
55192
- if (fs25.existsSync(dirPath) && dirPath !== testsDir) {
55858
+ const dirPath = path39.join(workingDir, dir);
55859
+ if (fs27.existsSync(dirPath) && dirPath !== testsDir) {
55193
55860
  await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
55194
55861
  testLines += lines;
55195
55862
  });
@@ -55201,9 +55868,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
55201
55868
  }
55202
55869
  async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
55203
55870
  try {
55204
- const entries = fs25.readdirSync(dirPath, { withFileTypes: true });
55871
+ const entries = fs27.readdirSync(dirPath, { withFileTypes: true });
55205
55872
  for (const entry of entries) {
55206
- const fullPath = path36.join(dirPath, entry.name);
55873
+ const fullPath = path39.join(dirPath, entry.name);
55207
55874
  if (entry.isDirectory()) {
55208
55875
  if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
55209
55876
  continue;
@@ -55211,7 +55878,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
55211
55878
  await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
55212
55879
  } else if (entry.isFile()) {
55213
55880
  const relativePath = fullPath.replace(`${process.cwd()}/`, "");
55214
- const ext = path36.extname(entry.name).toLowerCase();
55881
+ const ext = path39.extname(entry.name).toLowerCase();
55215
55882
  const validExts = [
55216
55883
  ".ts",
55217
55884
  ".tsx",
@@ -55247,7 +55914,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
55247
55914
  continue;
55248
55915
  }
55249
55916
  try {
55250
- const content = fs25.readFileSync(fullPath, "utf-8");
55917
+ const content = fs27.readFileSync(fullPath, "utf-8");
55251
55918
  const lines = countCodeLines(content);
55252
55919
  callback(lines);
55253
55920
  } catch {}
@@ -55461,8 +56128,8 @@ async function qualityBudget(input, directory) {
55461
56128
  init_dist();
55462
56129
  init_manager();
55463
56130
  init_detector();
55464
- import * as fs26 from "fs";
55465
- import * as path37 from "path";
56131
+ import * as fs28 from "fs";
56132
+ import * as path40 from "path";
55466
56133
  import { extname as extname9 } from "path";
55467
56134
 
55468
56135
  // src/sast/rules/c.ts
@@ -56329,17 +56996,17 @@ var SEVERITY_ORDER = {
56329
56996
  };
56330
56997
  function shouldSkipFile(filePath) {
56331
56998
  try {
56332
- const stats = fs26.statSync(filePath);
56999
+ const stats = fs28.statSync(filePath);
56333
57000
  if (stats.size > MAX_FILE_SIZE_BYTES6) {
56334
57001
  return { skip: true, reason: "file too large" };
56335
57002
  }
56336
57003
  if (stats.size === 0) {
56337
57004
  return { skip: true, reason: "empty file" };
56338
57005
  }
56339
- const fd = fs26.openSync(filePath, "r");
57006
+ const fd = fs28.openSync(filePath, "r");
56340
57007
  const buffer = Buffer.alloc(8192);
56341
- const bytesRead = fs26.readSync(fd, buffer, 0, 8192, 0);
56342
- fs26.closeSync(fd);
57008
+ const bytesRead = fs28.readSync(fd, buffer, 0, 8192, 0);
57009
+ fs28.closeSync(fd);
56343
57010
  if (bytesRead > 0) {
56344
57011
  let nullCount = 0;
56345
57012
  for (let i2 = 0;i2 < bytesRead; i2++) {
@@ -56378,7 +57045,7 @@ function countBySeverity(findings) {
56378
57045
  }
56379
57046
  function scanFileWithTierA(filePath, language) {
56380
57047
  try {
56381
- const content = fs26.readFileSync(filePath, "utf-8");
57048
+ const content = fs28.readFileSync(filePath, "utf-8");
56382
57049
  const findings = executeRulesSync(filePath, content, language);
56383
57050
  return findings.map((f) => ({
56384
57051
  rule_id: f.rule_id,
@@ -56425,8 +57092,8 @@ async function sastScan(input, directory, config3) {
56425
57092
  _filesSkipped++;
56426
57093
  continue;
56427
57094
  }
56428
- const resolvedPath = path37.isAbsolute(filePath) ? filePath : path37.resolve(directory, filePath);
56429
- if (!fs26.existsSync(resolvedPath)) {
57095
+ const resolvedPath = path40.isAbsolute(filePath) ? filePath : path40.resolve(directory, filePath);
57096
+ if (!fs28.existsSync(resolvedPath)) {
56430
57097
  _filesSkipped++;
56431
57098
  continue;
56432
57099
  }
@@ -56624,18 +57291,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
56624
57291
  let resolved;
56625
57292
  const isWinAbs = isWindowsAbsolutePath(inputPath);
56626
57293
  if (isWinAbs) {
56627
- resolved = path38.win32.resolve(inputPath);
56628
- } else if (path38.isAbsolute(inputPath)) {
56629
- resolved = path38.resolve(inputPath);
57294
+ resolved = path41.win32.resolve(inputPath);
57295
+ } else if (path41.isAbsolute(inputPath)) {
57296
+ resolved = path41.resolve(inputPath);
56630
57297
  } else {
56631
- resolved = path38.resolve(baseDir, inputPath);
57298
+ resolved = path41.resolve(baseDir, inputPath);
56632
57299
  }
56633
- const workspaceResolved = path38.resolve(workspaceDir);
57300
+ const workspaceResolved = path41.resolve(workspaceDir);
56634
57301
  let relative4;
56635
57302
  if (isWinAbs) {
56636
- relative4 = path38.win32.relative(workspaceResolved, resolved);
57303
+ relative4 = path41.win32.relative(workspaceResolved, resolved);
56637
57304
  } else {
56638
- relative4 = path38.relative(workspaceResolved, resolved);
57305
+ relative4 = path41.relative(workspaceResolved, resolved);
56639
57306
  }
56640
57307
  if (relative4.startsWith("..")) {
56641
57308
  return "path traversal detected";
@@ -56696,13 +57363,13 @@ async function runLintWrapped(files, directory, _config) {
56696
57363
  }
56697
57364
  async function runLintOnFiles(linter, files, workspaceDir) {
56698
57365
  const isWindows = process.platform === "win32";
56699
- const binDir = path38.join(workspaceDir, "node_modules", ".bin");
57366
+ const binDir = path41.join(workspaceDir, "node_modules", ".bin");
56700
57367
  const validatedFiles = [];
56701
57368
  for (const file3 of files) {
56702
57369
  if (typeof file3 !== "string") {
56703
57370
  continue;
56704
57371
  }
56705
- const resolvedPath = path38.resolve(file3);
57372
+ const resolvedPath = path41.resolve(file3);
56706
57373
  const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
56707
57374
  if (validationError) {
56708
57375
  continue;
@@ -56720,10 +57387,10 @@ async function runLintOnFiles(linter, files, workspaceDir) {
56720
57387
  }
56721
57388
  let command;
56722
57389
  if (linter === "biome") {
56723
- const biomeBin = isWindows ? path38.join(binDir, "biome.EXE") : path38.join(binDir, "biome");
57390
+ const biomeBin = isWindows ? path41.join(binDir, "biome.EXE") : path41.join(binDir, "biome");
56724
57391
  command = [biomeBin, "check", ...validatedFiles];
56725
57392
  } else {
56726
- const eslintBin = isWindows ? path38.join(binDir, "eslint.cmd") : path38.join(binDir, "eslint");
57393
+ const eslintBin = isWindows ? path41.join(binDir, "eslint.cmd") : path41.join(binDir, "eslint");
56727
57394
  command = [eslintBin, ...validatedFiles];
56728
57395
  }
56729
57396
  try {
@@ -56860,7 +57527,7 @@ async function runSecretscanWithFiles(files, directory) {
56860
57527
  skippedFiles++;
56861
57528
  continue;
56862
57529
  }
56863
- const resolvedPath = path38.resolve(file3);
57530
+ const resolvedPath = path41.resolve(file3);
56864
57531
  const validationError = validatePath(resolvedPath, directory, directory);
56865
57532
  if (validationError) {
56866
57533
  skippedFiles++;
@@ -56878,14 +57545,14 @@ async function runSecretscanWithFiles(files, directory) {
56878
57545
  };
56879
57546
  }
56880
57547
  for (const file3 of validatedFiles) {
56881
- const ext = path38.extname(file3).toLowerCase();
57548
+ const ext = path41.extname(file3).toLowerCase();
56882
57549
  if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
56883
57550
  skippedFiles++;
56884
57551
  continue;
56885
57552
  }
56886
57553
  let stat2;
56887
57554
  try {
56888
- stat2 = fs27.statSync(file3);
57555
+ stat2 = fs29.statSync(file3);
56889
57556
  } catch {
56890
57557
  skippedFiles++;
56891
57558
  continue;
@@ -56896,7 +57563,7 @@ async function runSecretscanWithFiles(files, directory) {
56896
57563
  }
56897
57564
  let content;
56898
57565
  try {
56899
- const buffer = fs27.readFileSync(file3);
57566
+ const buffer = fs29.readFileSync(file3);
56900
57567
  if (buffer.includes(0)) {
56901
57568
  skippedFiles++;
56902
57569
  continue;
@@ -57037,7 +57704,7 @@ async function runPreCheckBatch(input, workspaceDir) {
57037
57704
  warn(`pre_check_batch: Invalid file path: ${file3}`);
57038
57705
  continue;
57039
57706
  }
57040
- changedFiles.push(path38.resolve(directory, file3));
57707
+ changedFiles.push(path41.resolve(directory, file3));
57041
57708
  }
57042
57709
  if (changedFiles.length === 0) {
57043
57710
  warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
@@ -57188,7 +57855,7 @@ var pre_check_batch = createSwarmTool({
57188
57855
  };
57189
57856
  return JSON.stringify(errorResult, null, 2);
57190
57857
  }
57191
- const resolvedDirectory = path38.resolve(typedArgs.directory);
57858
+ const resolvedDirectory = path41.resolve(typedArgs.directory);
57192
57859
  const workspaceAnchor = resolvedDirectory;
57193
57860
  const dirError = validateDirectory3(resolvedDirectory, workspaceAnchor);
57194
57861
  if (dirError) {
@@ -57295,8 +57962,8 @@ ${paginatedContent}`;
57295
57962
  init_tool();
57296
57963
  init_manager2();
57297
57964
  init_create_tool();
57298
- import * as fs28 from "fs";
57299
- import * as path39 from "path";
57965
+ import * as fs30 from "fs";
57966
+ import * as path42 from "path";
57300
57967
  function detectPlaceholderContent(args2) {
57301
57968
  const issues = [];
57302
57969
  const placeholderPattern = /^\[\w[\w\s]*\]$/;
@@ -57400,19 +58067,19 @@ async function executeSavePlan(args2, fallbackDir) {
57400
58067
  try {
57401
58068
  await savePlan(dir, plan);
57402
58069
  try {
57403
- const markerPath = path39.join(dir, ".swarm", ".plan-write-marker");
58070
+ const markerPath = path42.join(dir, ".swarm", ".plan-write-marker");
57404
58071
  const marker = JSON.stringify({
57405
58072
  source: "save_plan",
57406
58073
  timestamp: new Date().toISOString(),
57407
58074
  phases_count: plan.phases.length,
57408
58075
  tasks_count: tasksCount
57409
58076
  });
57410
- await fs28.promises.writeFile(markerPath, marker, "utf8");
58077
+ await fs30.promises.writeFile(markerPath, marker, "utf8");
57411
58078
  } catch {}
57412
58079
  return {
57413
58080
  success: true,
57414
58081
  message: "Plan saved successfully",
57415
- plan_path: path39.join(dir, ".swarm", "plan.json"),
58082
+ plan_path: path42.join(dir, ".swarm", "plan.json"),
57416
58083
  phases_count: plan.phases.length,
57417
58084
  tasks_count: tasksCount
57418
58085
  };
@@ -57450,8 +58117,8 @@ var save_plan = createSwarmTool({
57450
58117
  // src/tools/sbom-generate.ts
57451
58118
  init_dist();
57452
58119
  init_manager();
57453
- import * as fs29 from "fs";
57454
- import * as path40 from "path";
58120
+ import * as fs31 from "fs";
58121
+ import * as path43 from "path";
57455
58122
 
57456
58123
  // src/sbom/detectors/dart.ts
57457
58124
  function parsePubspecLock(content) {
@@ -58297,9 +58964,9 @@ function findManifestFiles(rootDir) {
58297
58964
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
58298
58965
  function searchDir(dir) {
58299
58966
  try {
58300
- const entries = fs29.readdirSync(dir, { withFileTypes: true });
58967
+ const entries = fs31.readdirSync(dir, { withFileTypes: true });
58301
58968
  for (const entry of entries) {
58302
- const fullPath = path40.join(dir, entry.name);
58969
+ const fullPath = path43.join(dir, entry.name);
58303
58970
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
58304
58971
  continue;
58305
58972
  }
@@ -58309,7 +58976,7 @@ function findManifestFiles(rootDir) {
58309
58976
  for (const pattern of patterns) {
58310
58977
  const regex = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
58311
58978
  if (new RegExp(regex, "i").test(entry.name)) {
58312
- manifestFiles.push(path40.relative(cwd, fullPath));
58979
+ manifestFiles.push(path43.relative(cwd, fullPath));
58313
58980
  break;
58314
58981
  }
58315
58982
  }
@@ -58326,14 +58993,14 @@ function findManifestFilesInDirs(directories, workingDir) {
58326
58993
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
58327
58994
  for (const dir of directories) {
58328
58995
  try {
58329
- const entries = fs29.readdirSync(dir, { withFileTypes: true });
58996
+ const entries = fs31.readdirSync(dir, { withFileTypes: true });
58330
58997
  for (const entry of entries) {
58331
- const fullPath = path40.join(dir, entry.name);
58998
+ const fullPath = path43.join(dir, entry.name);
58332
58999
  if (entry.isFile()) {
58333
59000
  for (const pattern of patterns) {
58334
59001
  const regex = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
58335
59002
  if (new RegExp(regex, "i").test(entry.name)) {
58336
- found.push(path40.relative(workingDir, fullPath));
59003
+ found.push(path43.relative(workingDir, fullPath));
58337
59004
  break;
58338
59005
  }
58339
59006
  }
@@ -58346,11 +59013,11 @@ function findManifestFilesInDirs(directories, workingDir) {
58346
59013
  function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
58347
59014
  const dirs = new Set;
58348
59015
  for (const file3 of changedFiles) {
58349
- let currentDir = path40.dirname(file3);
59016
+ let currentDir = path43.dirname(file3);
58350
59017
  while (true) {
58351
- if (currentDir && currentDir !== "." && currentDir !== path40.sep) {
58352
- dirs.add(path40.join(workingDir, currentDir));
58353
- const parent = path40.dirname(currentDir);
59018
+ if (currentDir && currentDir !== "." && currentDir !== path43.sep) {
59019
+ dirs.add(path43.join(workingDir, currentDir));
59020
+ const parent = path43.dirname(currentDir);
58354
59021
  if (parent === currentDir)
58355
59022
  break;
58356
59023
  currentDir = parent;
@@ -58364,7 +59031,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
58364
59031
  }
58365
59032
  function ensureOutputDir(outputDir) {
58366
59033
  try {
58367
- fs29.mkdirSync(outputDir, { recursive: true });
59034
+ fs31.mkdirSync(outputDir, { recursive: true });
58368
59035
  } catch (error93) {
58369
59036
  if (!error93 || error93.code !== "EEXIST") {
58370
59037
  throw error93;
@@ -58456,11 +59123,11 @@ var sbom_generate = createSwarmTool({
58456
59123
  const processedFiles = [];
58457
59124
  for (const manifestFile of manifestFiles) {
58458
59125
  try {
58459
- const fullPath = path40.isAbsolute(manifestFile) ? manifestFile : path40.join(workingDir, manifestFile);
58460
- if (!fs29.existsSync(fullPath)) {
59126
+ const fullPath = path43.isAbsolute(manifestFile) ? manifestFile : path43.join(workingDir, manifestFile);
59127
+ if (!fs31.existsSync(fullPath)) {
58461
59128
  continue;
58462
59129
  }
58463
- const content = fs29.readFileSync(fullPath, "utf-8");
59130
+ const content = fs31.readFileSync(fullPath, "utf-8");
58464
59131
  const components = detectComponents(manifestFile, content);
58465
59132
  processedFiles.push(manifestFile);
58466
59133
  if (components.length > 0) {
@@ -58473,8 +59140,8 @@ var sbom_generate = createSwarmTool({
58473
59140
  const bom = generateCycloneDX(allComponents);
58474
59141
  const bomJson = serializeCycloneDX(bom);
58475
59142
  const filename = generateSbomFilename();
58476
- const outputPath = path40.join(outputDir, filename);
58477
- fs29.writeFileSync(outputPath, bomJson, "utf-8");
59143
+ const outputPath = path43.join(outputDir, filename);
59144
+ fs31.writeFileSync(outputPath, bomJson, "utf-8");
58478
59145
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
58479
59146
  try {
58480
59147
  const timestamp = new Date().toISOString();
@@ -58516,8 +59183,8 @@ var sbom_generate = createSwarmTool({
58516
59183
  // src/tools/schema-drift.ts
58517
59184
  init_dist();
58518
59185
  init_create_tool();
58519
- import * as fs30 from "fs";
58520
- import * as path41 from "path";
59186
+ import * as fs32 from "fs";
59187
+ import * as path44 from "path";
58521
59188
  var SPEC_CANDIDATES = [
58522
59189
  "openapi.json",
58523
59190
  "openapi.yaml",
@@ -58549,28 +59216,28 @@ function normalizePath2(p) {
58549
59216
  }
58550
59217
  function discoverSpecFile(cwd, specFileArg) {
58551
59218
  if (specFileArg) {
58552
- const resolvedPath = path41.resolve(cwd, specFileArg);
58553
- const normalizedCwd = cwd.endsWith(path41.sep) ? cwd : cwd + path41.sep;
59219
+ const resolvedPath = path44.resolve(cwd, specFileArg);
59220
+ const normalizedCwd = cwd.endsWith(path44.sep) ? cwd : cwd + path44.sep;
58554
59221
  if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
58555
59222
  throw new Error("Invalid spec_file: path traversal detected");
58556
59223
  }
58557
- const ext = path41.extname(resolvedPath).toLowerCase();
59224
+ const ext = path44.extname(resolvedPath).toLowerCase();
58558
59225
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
58559
59226
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
58560
59227
  }
58561
- const stats = fs30.statSync(resolvedPath);
59228
+ const stats = fs32.statSync(resolvedPath);
58562
59229
  if (stats.size > MAX_SPEC_SIZE) {
58563
59230
  throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
58564
59231
  }
58565
- if (!fs30.existsSync(resolvedPath)) {
59232
+ if (!fs32.existsSync(resolvedPath)) {
58566
59233
  throw new Error(`Spec file not found: ${resolvedPath}`);
58567
59234
  }
58568
59235
  return resolvedPath;
58569
59236
  }
58570
59237
  for (const candidate of SPEC_CANDIDATES) {
58571
- const candidatePath = path41.resolve(cwd, candidate);
58572
- if (fs30.existsSync(candidatePath)) {
58573
- const stats = fs30.statSync(candidatePath);
59238
+ const candidatePath = path44.resolve(cwd, candidate);
59239
+ if (fs32.existsSync(candidatePath)) {
59240
+ const stats = fs32.statSync(candidatePath);
58574
59241
  if (stats.size <= MAX_SPEC_SIZE) {
58575
59242
  return candidatePath;
58576
59243
  }
@@ -58579,8 +59246,8 @@ function discoverSpecFile(cwd, specFileArg) {
58579
59246
  return null;
58580
59247
  }
58581
59248
  function parseSpec(specFile) {
58582
- const content = fs30.readFileSync(specFile, "utf-8");
58583
- const ext = path41.extname(specFile).toLowerCase();
59249
+ const content = fs32.readFileSync(specFile, "utf-8");
59250
+ const ext = path44.extname(specFile).toLowerCase();
58584
59251
  if (ext === ".json") {
58585
59252
  return parseJsonSpec(content);
58586
59253
  }
@@ -58646,12 +59313,12 @@ function extractRoutes(cwd) {
58646
59313
  function walkDir(dir) {
58647
59314
  let entries;
58648
59315
  try {
58649
- entries = fs30.readdirSync(dir, { withFileTypes: true });
59316
+ entries = fs32.readdirSync(dir, { withFileTypes: true });
58650
59317
  } catch {
58651
59318
  return;
58652
59319
  }
58653
59320
  for (const entry of entries) {
58654
- const fullPath = path41.join(dir, entry.name);
59321
+ const fullPath = path44.join(dir, entry.name);
58655
59322
  if (entry.isSymbolicLink()) {
58656
59323
  continue;
58657
59324
  }
@@ -58661,7 +59328,7 @@ function extractRoutes(cwd) {
58661
59328
  }
58662
59329
  walkDir(fullPath);
58663
59330
  } else if (entry.isFile()) {
58664
- const ext = path41.extname(entry.name).toLowerCase();
59331
+ const ext = path44.extname(entry.name).toLowerCase();
58665
59332
  const baseName = entry.name.toLowerCase();
58666
59333
  if (![".ts", ".js", ".mjs"].includes(ext)) {
58667
59334
  continue;
@@ -58679,7 +59346,7 @@ function extractRoutes(cwd) {
58679
59346
  }
58680
59347
  function extractRoutesFromFile(filePath) {
58681
59348
  const routes = [];
58682
- const content = fs30.readFileSync(filePath, "utf-8");
59349
+ const content = fs32.readFileSync(filePath, "utf-8");
58683
59350
  const lines = content.split(/\r?\n/);
58684
59351
  const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
58685
59352
  const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
@@ -58830,8 +59497,8 @@ init_secretscan();
58830
59497
  // src/tools/symbols.ts
58831
59498
  init_tool();
58832
59499
  init_create_tool();
58833
- import * as fs31 from "fs";
58834
- import * as path42 from "path";
59500
+ import * as fs33 from "fs";
59501
+ import * as path45 from "path";
58835
59502
  var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
58836
59503
  var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
58837
59504
  function containsControlCharacters(str) {
@@ -58860,11 +59527,11 @@ function containsWindowsAttacks(str) {
58860
59527
  }
58861
59528
  function isPathInWorkspace(filePath, workspace) {
58862
59529
  try {
58863
- const resolvedPath = path42.resolve(workspace, filePath);
58864
- const realWorkspace = fs31.realpathSync(workspace);
58865
- const realResolvedPath = fs31.realpathSync(resolvedPath);
58866
- const relativePath = path42.relative(realWorkspace, realResolvedPath);
58867
- if (relativePath.startsWith("..") || path42.isAbsolute(relativePath)) {
59530
+ const resolvedPath = path45.resolve(workspace, filePath);
59531
+ const realWorkspace = fs33.realpathSync(workspace);
59532
+ const realResolvedPath = fs33.realpathSync(resolvedPath);
59533
+ const relativePath = path45.relative(realWorkspace, realResolvedPath);
59534
+ if (relativePath.startsWith("..") || path45.isAbsolute(relativePath)) {
58868
59535
  return false;
58869
59536
  }
58870
59537
  return true;
@@ -58876,17 +59543,17 @@ function validatePathForRead(filePath, workspace) {
58876
59543
  return isPathInWorkspace(filePath, workspace);
58877
59544
  }
58878
59545
  function extractTSSymbols(filePath, cwd) {
58879
- const fullPath = path42.join(cwd, filePath);
59546
+ const fullPath = path45.join(cwd, filePath);
58880
59547
  if (!validatePathForRead(fullPath, cwd)) {
58881
59548
  return [];
58882
59549
  }
58883
59550
  let content;
58884
59551
  try {
58885
- const stats = fs31.statSync(fullPath);
59552
+ const stats = fs33.statSync(fullPath);
58886
59553
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
58887
59554
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
58888
59555
  }
58889
- content = fs31.readFileSync(fullPath, "utf-8");
59556
+ content = fs33.readFileSync(fullPath, "utf-8");
58890
59557
  } catch {
58891
59558
  return [];
58892
59559
  }
@@ -59028,17 +59695,17 @@ function extractTSSymbols(filePath, cwd) {
59028
59695
  });
59029
59696
  }
59030
59697
  function extractPythonSymbols(filePath, cwd) {
59031
- const fullPath = path42.join(cwd, filePath);
59698
+ const fullPath = path45.join(cwd, filePath);
59032
59699
  if (!validatePathForRead(fullPath, cwd)) {
59033
59700
  return [];
59034
59701
  }
59035
59702
  let content;
59036
59703
  try {
59037
- const stats = fs31.statSync(fullPath);
59704
+ const stats = fs33.statSync(fullPath);
59038
59705
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
59039
59706
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES7})`);
59040
59707
  }
59041
- content = fs31.readFileSync(fullPath, "utf-8");
59708
+ content = fs33.readFileSync(fullPath, "utf-8");
59042
59709
  } catch {
59043
59710
  return [];
59044
59711
  }
@@ -59111,7 +59778,7 @@ var symbols = createSwarmTool({
59111
59778
  }, null, 2);
59112
59779
  }
59113
59780
  const cwd = directory;
59114
- const ext = path42.extname(file3);
59781
+ const ext = path45.extname(file3);
59115
59782
  if (containsControlCharacters(file3)) {
59116
59783
  return JSON.stringify({
59117
59784
  file: file3,
@@ -59181,8 +59848,8 @@ init_test_runner();
59181
59848
  // src/tools/todo-extract.ts
59182
59849
  init_dist();
59183
59850
  init_create_tool();
59184
- import * as fs32 from "fs";
59185
- import * as path43 from "path";
59851
+ import * as fs34 from "fs";
59852
+ import * as path46 from "path";
59186
59853
  var MAX_TEXT_LENGTH = 200;
59187
59854
  var MAX_FILE_SIZE_BYTES8 = 1024 * 1024;
59188
59855
  var SUPPORTED_EXTENSIONS2 = new Set([
@@ -59253,9 +59920,9 @@ function validatePathsInput(paths, cwd) {
59253
59920
  return { error: "paths contains path traversal", resolvedPath: null };
59254
59921
  }
59255
59922
  try {
59256
- const resolvedPath = path43.resolve(paths);
59257
- const normalizedCwd = path43.resolve(cwd);
59258
- const normalizedResolved = path43.resolve(resolvedPath);
59923
+ const resolvedPath = path46.resolve(paths);
59924
+ const normalizedCwd = path46.resolve(cwd);
59925
+ const normalizedResolved = path46.resolve(resolvedPath);
59259
59926
  if (!normalizedResolved.startsWith(normalizedCwd)) {
59260
59927
  return {
59261
59928
  error: "paths must be within the current working directory",
@@ -59271,13 +59938,13 @@ function validatePathsInput(paths, cwd) {
59271
59938
  }
59272
59939
  }
59273
59940
  function isSupportedExtension(filePath) {
59274
- const ext = path43.extname(filePath).toLowerCase();
59941
+ const ext = path46.extname(filePath).toLowerCase();
59275
59942
  return SUPPORTED_EXTENSIONS2.has(ext);
59276
59943
  }
59277
59944
  function findSourceFiles3(dir, files = []) {
59278
59945
  let entries;
59279
59946
  try {
59280
- entries = fs32.readdirSync(dir);
59947
+ entries = fs34.readdirSync(dir);
59281
59948
  } catch {
59282
59949
  return files;
59283
59950
  }
@@ -59286,10 +59953,10 @@ function findSourceFiles3(dir, files = []) {
59286
59953
  if (SKIP_DIRECTORIES3.has(entry)) {
59287
59954
  continue;
59288
59955
  }
59289
- const fullPath = path43.join(dir, entry);
59956
+ const fullPath = path46.join(dir, entry);
59290
59957
  let stat2;
59291
59958
  try {
59292
- stat2 = fs32.statSync(fullPath);
59959
+ stat2 = fs34.statSync(fullPath);
59293
59960
  } catch {
59294
59961
  continue;
59295
59962
  }
@@ -59382,7 +60049,7 @@ var todo_extract = createSwarmTool({
59382
60049
  return JSON.stringify(errorResult, null, 2);
59383
60050
  }
59384
60051
  const scanPath = resolvedPath;
59385
- if (!fs32.existsSync(scanPath)) {
60052
+ if (!fs34.existsSync(scanPath)) {
59386
60053
  const errorResult = {
59387
60054
  error: `path not found: ${pathsInput}`,
59388
60055
  total: 0,
@@ -59392,13 +60059,13 @@ var todo_extract = createSwarmTool({
59392
60059
  return JSON.stringify(errorResult, null, 2);
59393
60060
  }
59394
60061
  const filesToScan = [];
59395
- const stat2 = fs32.statSync(scanPath);
60062
+ const stat2 = fs34.statSync(scanPath);
59396
60063
  if (stat2.isFile()) {
59397
60064
  if (isSupportedExtension(scanPath)) {
59398
60065
  filesToScan.push(scanPath);
59399
60066
  } else {
59400
60067
  const errorResult = {
59401
- error: `unsupported file extension: ${path43.extname(scanPath)}`,
60068
+ error: `unsupported file extension: ${path46.extname(scanPath)}`,
59402
60069
  total: 0,
59403
60070
  byPriority: { high: 0, medium: 0, low: 0 },
59404
60071
  entries: []
@@ -59411,11 +60078,11 @@ var todo_extract = createSwarmTool({
59411
60078
  const allEntries = [];
59412
60079
  for (const filePath of filesToScan) {
59413
60080
  try {
59414
- const fileStat = fs32.statSync(filePath);
60081
+ const fileStat = fs34.statSync(filePath);
59415
60082
  if (fileStat.size > MAX_FILE_SIZE_BYTES8) {
59416
60083
  continue;
59417
60084
  }
59418
- const content = fs32.readFileSync(filePath, "utf-8");
60085
+ const content = fs34.readFileSync(filePath, "utf-8");
59419
60086
  const entries = parseTodoComments(content, filePath, tagsSet);
59420
60087
  allEntries.push(...entries);
59421
60088
  } catch {}
@@ -59443,8 +60110,8 @@ var todo_extract = createSwarmTool({
59443
60110
  // src/tools/update-task-status.ts
59444
60111
  init_tool();
59445
60112
  init_manager2();
59446
- import * as fs33 from "fs";
59447
- import * as path44 from "path";
60113
+ import * as fs35 from "fs";
60114
+ import * as path47 from "path";
59448
60115
  init_create_tool();
59449
60116
  var VALID_STATUSES = [
59450
60117
  "pending",
@@ -59481,6 +60148,10 @@ function checkReviewerGate(taskId) {
59481
60148
  const state = getTaskState(session, taskId);
59482
60149
  stateEntries.push(`${sessionId}: ${state}`);
59483
60150
  }
60151
+ const allIdle = stateEntries.length > 0 && stateEntries.every((e) => e.endsWith(": idle"));
60152
+ if (allIdle) {
60153
+ console.warn(`[update-task-status] Issue #81 regression detected for task ${taskId}: all ${stateEntries.length} session(s) show idle state. taskWorkflowStates may not be persisting across sessions.`);
60154
+ }
59484
60155
  const currentStateStr = stateEntries.length > 0 ? stateEntries.join(", ") : "no active sessions";
59485
60156
  return {
59486
60157
  blocked: true,
@@ -59544,8 +60215,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
59544
60215
  };
59545
60216
  }
59546
60217
  }
59547
- normalizedDir = path44.normalize(args2.working_directory);
59548
- const pathParts = normalizedDir.split(path44.sep);
60218
+ normalizedDir = path47.normalize(args2.working_directory);
60219
+ const pathParts = normalizedDir.split(path47.sep);
59549
60220
  if (pathParts.includes("..")) {
59550
60221
  return {
59551
60222
  success: false,
@@ -59555,11 +60226,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
59555
60226
  ]
59556
60227
  };
59557
60228
  }
59558
- const resolvedDir = path44.resolve(normalizedDir);
60229
+ const resolvedDir = path47.resolve(normalizedDir);
59559
60230
  try {
59560
- const realPath = fs33.realpathSync(resolvedDir);
59561
- const planPath = path44.join(realPath, ".swarm", "plan.json");
59562
- if (!fs33.existsSync(planPath)) {
60231
+ const realPath = fs35.realpathSync(resolvedDir);
60232
+ const planPath = path47.join(realPath, ".swarm", "plan.json");
60233
+ if (!fs35.existsSync(planPath)) {
59563
60234
  return {
59564
60235
  success: false,
59565
60236
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -59629,10 +60300,10 @@ function truncateToolOutput(output, maxLines, toolName) {
59629
60300
  footerLines.push(`Tool: ${toolName}`);
59630
60301
  }
59631
60302
  footerLines.push("Use /swarm retrieve <id> to get the full content");
59632
- return truncated.join(`
59633
- `) + `
59634
- ` + footerLines.join(`
59635
- `);
60303
+ return `${truncated.join(`
60304
+ `)}
60305
+ ${footerLines.join(`
60306
+ `)}`;
59636
60307
  }
59637
60308
 
59638
60309
  // src/index.ts
@@ -59690,7 +60361,7 @@ var OpenCodeSwarm = async (ctx) => {
59690
60361
  const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
59691
60362
  preflightTriggerManager = new PTM(automationConfig);
59692
60363
  const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
59693
- const swarmDir = path45.resolve(ctx.directory, ".swarm");
60364
+ const swarmDir = path48.resolve(ctx.directory, ".swarm");
59694
60365
  statusArtifact = new ASA(swarmDir);
59695
60366
  statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
59696
60367
  if (automationConfig.capabilities?.evidence_auto_summaries === true) {