opencode-swarm 6.29.0 → 6.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -35663,6 +35663,26 @@ function extractCurrentPhaseFromPlan2(plan) {
35663
35663
  init_utils2();
35664
35664
  init_manager2();
35665
35665
 
35666
+ // src/services/compaction-service.ts
35667
+ function makeInitialState() {
35668
+ return {
35669
+ lastObservationAt: 0,
35670
+ lastReflectionAt: 0,
35671
+ lastEmergencyAt: 0,
35672
+ observationCount: 0,
35673
+ reflectionCount: 0,
35674
+ emergencyCount: 0,
35675
+ lastSnapshotAt: null
35676
+ };
35677
+ }
35678
+ var state = makeInitialState();
35679
+ function getCompactionMetrics() {
35680
+ return {
35681
+ compactionCount: state.observationCount + state.reflectionCount + state.emergencyCount,
35682
+ lastSnapshotAt: state.lastSnapshotAt
35683
+ };
35684
+ }
35685
+
35666
35686
  // src/services/context-budget-service.ts
35667
35687
  init_utils2();
35668
35688
  var DEFAULT_CONTEXT_BUDGET_CONFIG = {
@@ -35689,6 +35709,7 @@ async function getStatusData(directory, agents) {
35689
35709
  }
35690
35710
  }
35691
35711
  const agentCount2 = Object.keys(agents).length;
35712
+ const metrics2 = getCompactionMetrics();
35692
35713
  return {
35693
35714
  hasPlan: true,
35694
35715
  currentPhase: currentPhase2,
@@ -35698,12 +35719,13 @@ async function getStatusData(directory, agents) {
35698
35719
  isLegacy: false,
35699
35720
  turboMode: hasActiveTurboMode(),
35700
35721
  contextBudgetPct: swarmState.lastBudgetPct > 0 ? swarmState.lastBudgetPct : null,
35701
- compactionCount: 0,
35702
- lastSnapshotAt: null
35722
+ compactionCount: metrics2.compactionCount,
35723
+ lastSnapshotAt: metrics2.lastSnapshotAt
35703
35724
  };
35704
35725
  }
35705
35726
  const planContent = await readSwarmFileAsync(directory, "plan.md");
35706
35727
  if (!planContent) {
35728
+ const metrics2 = getCompactionMetrics();
35707
35729
  return {
35708
35730
  hasPlan: false,
35709
35731
  currentPhase: "Unknown",
@@ -35713,8 +35735,8 @@ async function getStatusData(directory, agents) {
35713
35735
  isLegacy: true,
35714
35736
  turboMode: hasActiveTurboMode(),
35715
35737
  contextBudgetPct: swarmState.lastBudgetPct > 0 ? swarmState.lastBudgetPct : null,
35716
- compactionCount: 0,
35717
- lastSnapshotAt: null
35738
+ compactionCount: metrics2.compactionCount,
35739
+ lastSnapshotAt: metrics2.lastSnapshotAt
35718
35740
  };
35719
35741
  }
35720
35742
  const currentPhase = extractCurrentPhase(planContent) || "Unknown";
@@ -35722,6 +35744,7 @@ async function getStatusData(directory, agents) {
35722
35744
  const incompleteTasks = (planContent.match(/^- \[ \]/gm) || []).length;
35723
35745
  const totalTasks = completedTasks + incompleteTasks;
35724
35746
  const agentCount = Object.keys(agents).length;
35747
+ const metrics = getCompactionMetrics();
35725
35748
  return {
35726
35749
  hasPlan: true,
35727
35750
  currentPhase,
@@ -35731,8 +35754,8 @@ async function getStatusData(directory, agents) {
35731
35754
  isLegacy: true,
35732
35755
  turboMode: hasActiveTurboMode(),
35733
35756
  contextBudgetPct: swarmState.lastBudgetPct > 0 ? swarmState.lastBudgetPct : null,
35734
- compactionCount: 0,
35735
- lastSnapshotAt: null
35757
+ compactionCount: metrics.compactionCount,
35758
+ lastSnapshotAt: metrics.lastSnapshotAt
35736
35759
  };
35737
35760
  }
35738
35761
  function formatStatusMarkdown(status) {
package/dist/index.js CHANGED
@@ -35942,7 +35942,7 @@ __export(exports_gate_evidence, {
35942
35942
  DEFAULT_REQUIRED_GATES: () => DEFAULT_REQUIRED_GATES
35943
35943
  });
35944
35944
  import { mkdirSync as mkdirSync8, readFileSync as readFileSync13, renameSync as renameSync7, unlinkSync as unlinkSync4 } from "fs";
35945
- import * as path28 from "path";
35945
+ import * as path29 from "path";
35946
35946
  function isValidTaskId2(taskId) {
35947
35947
  if (!taskId)
35948
35948
  return false;
@@ -35989,10 +35989,10 @@ function expandRequiredGates(existingGates, newAgentType) {
35989
35989
  return combined.sort();
35990
35990
  }
35991
35991
  function getEvidenceDir(directory) {
35992
- return path28.join(directory, ".swarm", "evidence");
35992
+ return path29.join(directory, ".swarm", "evidence");
35993
35993
  }
35994
35994
  function getEvidencePath(directory, taskId) {
35995
- return path28.join(getEvidenceDir(directory), `${taskId}.json`);
35995
+ return path29.join(getEvidenceDir(directory), `${taskId}.json`);
35996
35996
  }
35997
35997
  function readExisting(evidencePath) {
35998
35998
  try {
@@ -36106,10 +36106,10 @@ function createPreflightIntegration(config3) {
36106
36106
  });
36107
36107
  const report = await runPreflight(directory, request.currentPhase, preflightConfig);
36108
36108
  if (statusArtifact) {
36109
- const state = report.overall === "pass" ? "success" : "failure";
36110
- statusArtifact.recordOutcome(state, request.currentPhase, report.message);
36109
+ const state2 = report.overall === "pass" ? "success" : "failure";
36110
+ statusArtifact.recordOutcome(state2, request.currentPhase, report.message);
36111
36111
  console.log("[PreflightIntegration] Status artifact updated", {
36112
- state,
36112
+ state: state2,
36113
36113
  phase: request.currentPhase,
36114
36114
  message: report.message
36115
36115
  });
@@ -39418,7 +39418,8 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000, dire
39418
39418
  scopeViolationDetected: false,
39419
39419
  modifiedFilesThisCoderTask: [],
39420
39420
  turboMode: false,
39421
- loopDetectionWindow: []
39421
+ loopDetectionWindow: [],
39422
+ pendingAdvisoryMessages: []
39422
39423
  };
39423
39424
  swarmState.agentSessions.set(sessionId, sessionState);
39424
39425
  swarmState.activeAgent.set(sessionId, agentName);
@@ -39523,6 +39524,9 @@ function ensureAgentSession(sessionId, agentName, directory) {
39523
39524
  if (session.loopDetectionWindow === undefined) {
39524
39525
  session.loopDetectionWindow = [];
39525
39526
  }
39527
+ if (session.pendingAdvisoryMessages === undefined) {
39528
+ session.pendingAdvisoryMessages = [];
39529
+ }
39526
39530
  session.lastToolCallTime = now;
39527
39531
  return session;
39528
39532
  }
@@ -47608,6 +47612,97 @@ No plan content available. Start by creating a .swarm/plan.md file.
47608
47612
  init_utils2();
47609
47613
  init_manager2();
47610
47614
 
47615
+ // src/services/compaction-service.ts
47616
+ import * as fs15 from "fs";
47617
+ import * as path27 from "path";
47618
+ function makeInitialState() {
47619
+ return {
47620
+ lastObservationAt: 0,
47621
+ lastReflectionAt: 0,
47622
+ lastEmergencyAt: 0,
47623
+ observationCount: 0,
47624
+ reflectionCount: 0,
47625
+ emergencyCount: 0,
47626
+ lastSnapshotAt: null
47627
+ };
47628
+ }
47629
+ var state = makeInitialState();
47630
+ function appendSnapshot(directory, tier, budgetPct, message) {
47631
+ try {
47632
+ const snapshotPath = path27.join(directory, ".swarm", "context-snapshot.md");
47633
+ const timestamp = new Date().toISOString();
47634
+ const entry = `
47635
+ ## [${tier.toUpperCase()}] ${timestamp} \u2014 ${budgetPct.toFixed(1)}% used
47636
+ ${message}
47637
+ `;
47638
+ fs15.appendFileSync(snapshotPath, entry, "utf-8");
47639
+ } catch {}
47640
+ }
47641
+ function buildObservationMessage(budgetPct) {
47642
+ return `[CONTEXT COMPACTION \u2014 OBSERVATION TIER]
47643
+ ` + `Context window is ${budgetPct.toFixed(1)}% used. Initiating observation compaction.
47644
+ ` + `INSTRUCTIONS: Summarise the key decisions made so far, files changed, errors resolved, ` + `and the current task state. Discard verbose tool outputs and raw file reads. ` + `Preserve: plan task ID, agent verdicts, file paths touched, unresolved blockers.
47645
+ ` + `[/CONTEXT COMPACTION]`;
47646
+ }
47647
+ function buildReflectionMessage(budgetPct) {
47648
+ return `[CONTEXT COMPACTION \u2014 REFLECTION TIER]
47649
+ ` + `Context window is ${budgetPct.toFixed(1)}% used. Initiating reflection compaction.
47650
+ ` + `INSTRUCTIONS: Re-summarise into a tighter format. Discard completed task details ` + `and resolved errors. Retain ONLY: current phase tasks remaining, open blockers, ` + `last 3 reviewer/test verdicts, and active file scope.
47651
+ ` + `[/CONTEXT COMPACTION]`;
47652
+ }
47653
+ function buildEmergencyMessage(budgetPct, preserveLastN) {
47654
+ return `[CONTEXT COMPACTION \u2014 EMERGENCY TIER]
47655
+ ` + `Context window is ${budgetPct.toFixed(1)}% used. EMERGENCY compaction required.
47656
+ ` + `INSTRUCTIONS: Retain ONLY the system prompt, the current task context, and the ` + `last ${preserveLastN} conversation turns. Discard everything else. ` + `If you cannot complete the current task in the remaining context, escalate to the user.
47657
+ ` + `[/CONTEXT COMPACTION]`;
47658
+ }
47659
+ function createCompactionService(config3, directory, injectMessage) {
47660
+ return {
47661
+ toolAfter: async (_input, _output) => {
47662
+ if (!config3.enabled)
47663
+ return;
47664
+ const budgetPct = swarmState.lastBudgetPct ?? 0;
47665
+ if (budgetPct <= 0)
47666
+ return;
47667
+ const sessionId = _input.sessionID;
47668
+ try {
47669
+ if (budgetPct >= config3.emergencyThreshold && budgetPct > state.lastEmergencyAt + 5) {
47670
+ state.lastEmergencyAt = budgetPct;
47671
+ state.emergencyCount++;
47672
+ const msg = buildEmergencyMessage(budgetPct, config3.preserveLastNTurns);
47673
+ appendSnapshot(directory, "emergency", budgetPct, msg);
47674
+ state.lastSnapshotAt = new Date().toISOString();
47675
+ injectMessage(sessionId, msg);
47676
+ return;
47677
+ }
47678
+ if (budgetPct >= config3.reflectionThreshold && budgetPct > state.lastReflectionAt + 5) {
47679
+ state.lastReflectionAt = budgetPct;
47680
+ state.reflectionCount++;
47681
+ const msg = buildReflectionMessage(budgetPct);
47682
+ appendSnapshot(directory, "reflection", budgetPct, msg);
47683
+ state.lastSnapshotAt = new Date().toISOString();
47684
+ injectMessage(sessionId, msg);
47685
+ return;
47686
+ }
47687
+ if (budgetPct >= config3.observationThreshold && budgetPct > state.lastObservationAt + 5) {
47688
+ state.lastObservationAt = budgetPct;
47689
+ state.observationCount++;
47690
+ const msg = buildObservationMessage(budgetPct);
47691
+ appendSnapshot(directory, "observation", budgetPct, msg);
47692
+ state.lastSnapshotAt = new Date().toISOString();
47693
+ injectMessage(sessionId, msg);
47694
+ }
47695
+ } catch {}
47696
+ }
47697
+ };
47698
+ }
47699
+ function getCompactionMetrics() {
47700
+ return {
47701
+ compactionCount: state.observationCount + state.reflectionCount + state.emergencyCount,
47702
+ lastSnapshotAt: state.lastSnapshotAt
47703
+ };
47704
+ }
47705
+
47611
47706
  // src/services/context-budget-service.ts
47612
47707
  init_utils2();
47613
47708
  function validateDirectory(directory) {
@@ -47650,9 +47745,9 @@ async function readBudgetState(directory) {
47650
47745
  return null;
47651
47746
  }
47652
47747
  }
47653
- async function writeBudgetState(directory, state) {
47748
+ async function writeBudgetState(directory, state2) {
47654
47749
  const resolvedPath = validateSwarmPath(directory, "session/budget-state.json");
47655
- const content = JSON.stringify(state, null, 2);
47750
+ const content = JSON.stringify(state2, null, 2);
47656
47751
  await Bun.write(resolvedPath, content);
47657
47752
  }
47658
47753
  async function countEvents(directory) {
@@ -47741,25 +47836,25 @@ async function formatBudgetWarning(report, directory, config3) {
47741
47836
  return formatWarningMessage(report);
47742
47837
  }
47743
47838
  const budgetState = await readBudgetState(directory);
47744
- const state = budgetState || {
47839
+ const state2 = budgetState || {
47745
47840
  warningFiredAtTurn: null,
47746
47841
  criticalFiredAtTurn: null,
47747
47842
  lastInjectedAtTurn: null
47748
47843
  };
47749
47844
  const currentTurn = report.estimatedTurnCount;
47750
47845
  if (report.status === "warning") {
47751
- if (config3.warningMode === "once" && state.warningFiredAtTurn !== null) {
47846
+ if (config3.warningMode === "once" && state2.warningFiredAtTurn !== null) {
47752
47847
  return null;
47753
47848
  }
47754
- if (config3.warningMode === "interval" && state.warningFiredAtTurn !== null && currentTurn - state.warningFiredAtTurn < config3.warningIntervalTurns) {
47849
+ if (config3.warningMode === "interval" && state2.warningFiredAtTurn !== null && currentTurn - state2.warningFiredAtTurn < config3.warningIntervalTurns) {
47755
47850
  return null;
47756
47851
  }
47757
- state.warningFiredAtTurn = currentTurn;
47758
- state.lastInjectedAtTurn = currentTurn;
47759
- await writeBudgetState(directory, state);
47852
+ state2.warningFiredAtTurn = currentTurn;
47853
+ state2.lastInjectedAtTurn = currentTurn;
47854
+ await writeBudgetState(directory, state2);
47760
47855
  } else if (report.status === "critical") {
47761
- state.criticalFiredAtTurn = currentTurn;
47762
- state.lastInjectedAtTurn = currentTurn;
47856
+ state2.criticalFiredAtTurn = currentTurn;
47857
+ state2.lastInjectedAtTurn = currentTurn;
47763
47858
  }
47764
47859
  return formatWarningMessage(report);
47765
47860
  }
@@ -47788,6 +47883,7 @@ async function getStatusData(directory, agents) {
47788
47883
  }
47789
47884
  }
47790
47885
  const agentCount2 = Object.keys(agents).length;
47886
+ const metrics2 = getCompactionMetrics();
47791
47887
  return {
47792
47888
  hasPlan: true,
47793
47889
  currentPhase: currentPhase2,
@@ -47797,12 +47893,13 @@ async function getStatusData(directory, agents) {
47797
47893
  isLegacy: false,
47798
47894
  turboMode: hasActiveTurboMode(),
47799
47895
  contextBudgetPct: swarmState.lastBudgetPct > 0 ? swarmState.lastBudgetPct : null,
47800
- compactionCount: 0,
47801
- lastSnapshotAt: null
47896
+ compactionCount: metrics2.compactionCount,
47897
+ lastSnapshotAt: metrics2.lastSnapshotAt
47802
47898
  };
47803
47899
  }
47804
47900
  const planContent = await readSwarmFileAsync(directory, "plan.md");
47805
47901
  if (!planContent) {
47902
+ const metrics2 = getCompactionMetrics();
47806
47903
  return {
47807
47904
  hasPlan: false,
47808
47905
  currentPhase: "Unknown",
@@ -47812,8 +47909,8 @@ async function getStatusData(directory, agents) {
47812
47909
  isLegacy: true,
47813
47910
  turboMode: hasActiveTurboMode(),
47814
47911
  contextBudgetPct: swarmState.lastBudgetPct > 0 ? swarmState.lastBudgetPct : null,
47815
- compactionCount: 0,
47816
- lastSnapshotAt: null
47912
+ compactionCount: metrics2.compactionCount,
47913
+ lastSnapshotAt: metrics2.lastSnapshotAt
47817
47914
  };
47818
47915
  }
47819
47916
  const currentPhase = extractCurrentPhase(planContent) || "Unknown";
@@ -47821,6 +47918,7 @@ async function getStatusData(directory, agents) {
47821
47918
  const incompleteTasks = (planContent.match(/^- \[ \]/gm) || []).length;
47822
47919
  const totalTasks = completedTasks + incompleteTasks;
47823
47920
  const agentCount = Object.keys(agents).length;
47921
+ const metrics = getCompactionMetrics();
47824
47922
  return {
47825
47923
  hasPlan: true,
47826
47924
  currentPhase,
@@ -47830,8 +47928,8 @@ async function getStatusData(directory, agents) {
47830
47928
  isLegacy: true,
47831
47929
  turboMode: hasActiveTurboMode(),
47832
47930
  contextBudgetPct: swarmState.lastBudgetPct > 0 ? swarmState.lastBudgetPct : null,
47833
- compactionCount: 0,
47834
- lastSnapshotAt: null
47931
+ compactionCount: metrics.compactionCount,
47932
+ lastSnapshotAt: metrics.lastSnapshotAt
47835
47933
  };
47836
47934
  }
47837
47935
  function formatStatusMarkdown(status) {
@@ -48461,11 +48559,11 @@ async function doFlush(directory) {
48461
48559
  const activitySection = renderActivitySection();
48462
48560
  const updated = replaceOrAppendSection(existing, "## Agent Activity", activitySection);
48463
48561
  const flushedCount = swarmState.pendingEvents;
48464
- const path27 = `${directory}/.swarm/context.md`;
48465
- const tempPath = `${path27}.tmp`;
48562
+ const path28 = `${directory}/.swarm/context.md`;
48563
+ const tempPath = `${path28}.tmp`;
48466
48564
  try {
48467
48565
  await Bun.write(tempPath, updated);
48468
- renameSync6(tempPath, path27);
48566
+ renameSync6(tempPath, path28);
48469
48567
  } catch (writeError) {
48470
48568
  try {
48471
48569
  unlinkSync3(tempPath);
@@ -49035,14 +49133,14 @@ function maskToolOutput(msg, _threshold) {
49035
49133
  }
49036
49134
  // src/hooks/delegation-gate.ts
49037
49135
  init_schema();
49038
- import * as fs15 from "fs";
49039
- import * as path29 from "path";
49136
+ import * as fs16 from "fs";
49137
+ import * as path30 from "path";
49040
49138
 
49041
49139
  // src/hooks/guardrails.ts
49042
49140
  init_constants();
49043
49141
  init_schema();
49044
49142
  init_manager2();
49045
- import * as path27 from "path";
49143
+ import * as path28 from "path";
49046
49144
  init_utils();
49047
49145
 
49048
49146
  // src/hooks/loop-detector.ts
@@ -49135,10 +49233,10 @@ function isArchitect(sessionId) {
49135
49233
  function isOutsideSwarmDir(filePath, directory) {
49136
49234
  if (!filePath)
49137
49235
  return false;
49138
- const swarmDir = path27.resolve(directory, ".swarm");
49139
- const resolved = path27.resolve(directory, filePath);
49140
- const relative4 = path27.relative(swarmDir, resolved);
49141
- return relative4.startsWith("..") || path27.isAbsolute(relative4);
49236
+ const swarmDir = path28.resolve(directory, ".swarm");
49237
+ const resolved = path28.resolve(directory, filePath);
49238
+ const relative4 = path28.relative(swarmDir, resolved);
49239
+ return relative4.startsWith("..") || path28.isAbsolute(relative4);
49142
49240
  }
49143
49241
  function isSourceCodePath(filePath) {
49144
49242
  if (!filePath)
@@ -49205,13 +49303,13 @@ function getCurrentTaskId(sessionId) {
49205
49303
  return session?.currentTaskId ?? `${sessionId}:unknown`;
49206
49304
  }
49207
49305
  function isInDeclaredScope(filePath, scopeEntries) {
49208
- const resolvedFile = path27.resolve(filePath);
49306
+ const resolvedFile = path28.resolve(filePath);
49209
49307
  return scopeEntries.some((scope) => {
49210
- const resolvedScope = path27.resolve(scope);
49308
+ const resolvedScope = path28.resolve(scope);
49211
49309
  if (resolvedFile === resolvedScope)
49212
49310
  return true;
49213
- const rel = path27.relative(resolvedScope, resolvedFile);
49214
- return rel.length > 0 && !rel.startsWith("..") && !path27.isAbsolute(rel);
49311
+ const rel = path28.relative(resolvedScope, resolvedFile);
49312
+ return rel.length > 0 && !rel.startsWith("..") && !path28.isAbsolute(rel);
49215
49313
  });
49216
49314
  }
49217
49315
  function createGuardrailsHooks(directoryOrConfig, config3) {
@@ -49298,9 +49396,9 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
49298
49396
  const args2 = output.args;
49299
49397
  const targetPath = args2?.filePath ?? args2?.path ?? args2?.file ?? args2?.target;
49300
49398
  if (typeof targetPath === "string" && targetPath.length > 0) {
49301
- const resolvedTarget = path27.resolve(directory, targetPath).toLowerCase();
49302
- const planMdPath = path27.resolve(directory, ".swarm", "plan.md").toLowerCase();
49303
- const planJsonPath = path27.resolve(directory, ".swarm", "plan.json").toLowerCase();
49399
+ const resolvedTarget = path28.resolve(directory, targetPath).toLowerCase();
49400
+ const planMdPath = path28.resolve(directory, ".swarm", "plan.md").toLowerCase();
49401
+ const planJsonPath = path28.resolve(directory, ".swarm", "plan.json").toLowerCase();
49304
49402
  if (resolvedTarget === planMdPath || resolvedTarget === planJsonPath) {
49305
49403
  throw new Error("PLAN STATE VIOLATION: Direct writes to .swarm/plan.md and .swarm/plan.json are blocked. " + "plan.md is auto-regenerated from plan.json by PlanSyncWorker. " + "Use update_task_status() to mark tasks complete, " + "phase_complete() for phase transitions, or " + "save_plan to create/restructure plans.");
49306
49404
  }
@@ -49349,9 +49447,9 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
49349
49447
  }
49350
49448
  }
49351
49449
  for (const p of paths) {
49352
- const resolvedP = path27.resolve(directory, p);
49353
- const planMdPath = path27.resolve(directory, ".swarm", "plan.md").toLowerCase();
49354
- const planJsonPath = path27.resolve(directory, ".swarm", "plan.json").toLowerCase();
49450
+ const resolvedP = path28.resolve(directory, p);
49451
+ const planMdPath = path28.resolve(directory, ".swarm", "plan.md").toLowerCase();
49452
+ const planJsonPath = path28.resolve(directory, ".swarm", "plan.json").toLowerCase();
49355
49453
  if (resolvedP.toLowerCase() === planMdPath || resolvedP.toLowerCase() === planJsonPath) {
49356
49454
  throw new Error("PLAN STATE VIOLATION: Direct writes to .swarm/plan.md and .swarm/plan.json are blocked. " + "plan.md is auto-regenerated from plan.json by PlanSyncWorker. " + "Use update_task_status() to mark tasks complete, " + "phase_complete() for phase transitions, or " + "save_plan to create/restructure plans.");
49357
49455
  }
@@ -49371,7 +49469,7 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
49371
49469
  }
49372
49470
  }
49373
49471
  }
49374
- if (typeof targetPath === "string" && targetPath.length > 0 && isOutsideSwarmDir(targetPath, directory) && isSourceCodePath(path27.relative(directory, path27.resolve(directory, targetPath)))) {
49472
+ if (typeof targetPath === "string" && targetPath.length > 0 && isOutsideSwarmDir(targetPath, directory) && isSourceCodePath(path28.relative(directory, path28.resolve(directory, targetPath)))) {
49375
49473
  const session2 = swarmState.agentSessions.get(input.sessionID);
49376
49474
  if (session2) {
49377
49475
  session2.architectWriteCount++;
@@ -49653,6 +49751,30 @@ ${pending.message}
49653
49751
  }
49654
49752
  }
49655
49753
  }
49754
+ if (isArchitectSession && (session?.pendingAdvisoryMessages?.length ?? 0) > 0) {
49755
+ const advisories = session.pendingAdvisoryMessages;
49756
+ let targetMsg = systemMessages[0];
49757
+ if (!targetMsg) {
49758
+ const newMsg = {
49759
+ info: { role: "system" },
49760
+ parts: [{ type: "text", text: "" }]
49761
+ };
49762
+ messages.unshift(newMsg);
49763
+ targetMsg = newMsg;
49764
+ }
49765
+ const textPart2 = (targetMsg.parts ?? []).find((part) => part.type === "text" && typeof part.text === "string");
49766
+ if (textPart2) {
49767
+ const joined = advisories.join(`
49768
+ ---
49769
+ `);
49770
+ textPart2.text = `[ADVISORIES]
49771
+ ${joined}
49772
+ [/ADVISORIES]
49773
+
49774
+ ` + textPart2.text;
49775
+ }
49776
+ session.pendingAdvisoryMessages = [];
49777
+ }
49656
49778
  if (isArchitectSession && session && session.architectWriteCount > session.selfCodingWarnedAtCount) {
49657
49779
  let targetSystemMessage = systemMessages[0];
49658
49780
  if (!targetSystemMessage) {
@@ -49880,13 +50002,13 @@ function getEvidenceTaskId(session, directory) {
49880
50002
  if (typeof directory !== "string" || directory.length === 0) {
49881
50003
  return null;
49882
50004
  }
49883
- const resolvedDirectory = path29.resolve(directory);
49884
- const planPath = path29.join(resolvedDirectory, ".swarm", "plan.json");
49885
- const resolvedPlanPath = path29.resolve(planPath);
49886
- if (!resolvedPlanPath.startsWith(resolvedDirectory + path29.sep) && resolvedPlanPath !== resolvedDirectory) {
50005
+ const resolvedDirectory = path30.resolve(directory);
50006
+ const planPath = path30.join(resolvedDirectory, ".swarm", "plan.json");
50007
+ const resolvedPlanPath = path30.resolve(planPath);
50008
+ if (!resolvedPlanPath.startsWith(resolvedDirectory + path30.sep) && resolvedPlanPath !== resolvedDirectory) {
49887
50009
  return null;
49888
50010
  }
49889
- const planContent = fs15.readFileSync(resolvedPlanPath, "utf-8");
50011
+ const planContent = fs16.readFileSync(resolvedPlanPath, "utf-8");
49890
50012
  const plan = JSON.parse(planContent);
49891
50013
  if (!plan || !Array.isArray(plan.phases)) {
49892
50014
  return null;
@@ -49944,23 +50066,23 @@ function createDelegationGateHook(config3, directory) {
49944
50066
  if (targetAgent === "test_engineer")
49945
50067
  hasTestEngineer = true;
49946
50068
  if (targetAgent === "reviewer" && session.taskWorkflowStates) {
49947
- for (const [taskId, state] of session.taskWorkflowStates) {
49948
- if (state === "coder_delegated" || state === "pre_check_passed") {
50069
+ for (const [taskId, state2] of session.taskWorkflowStates) {
50070
+ if (state2 === "coder_delegated" || state2 === "pre_check_passed") {
49949
50071
  try {
49950
50072
  advanceTaskState(session, taskId, "reviewer_run");
49951
50073
  } catch (err2) {
49952
- console.warn(`[delegation-gate] toolAfter: could not advance ${taskId} (${state}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
50074
+ console.warn(`[delegation-gate] toolAfter: could not advance ${taskId} (${state2}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
49953
50075
  }
49954
50076
  }
49955
50077
  }
49956
50078
  }
49957
50079
  if (targetAgent === "test_engineer" && session.taskWorkflowStates) {
49958
- for (const [taskId, state] of session.taskWorkflowStates) {
49959
- if (state === "reviewer_run") {
50080
+ for (const [taskId, state2] of session.taskWorkflowStates) {
50081
+ if (state2 === "reviewer_run") {
49960
50082
  try {
49961
50083
  advanceTaskState(session, taskId, "tests_run");
49962
50084
  } catch (err2) {
49963
- console.warn(`[delegation-gate] toolAfter: could not advance ${taskId} (${state}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
50085
+ console.warn(`[delegation-gate] toolAfter: could not advance ${taskId} (${state2}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
49964
50086
  }
49965
50087
  }
49966
50088
  }
@@ -49976,12 +50098,12 @@ function createDelegationGateHook(config3, directory) {
49976
50098
  if (seedTaskId && !otherSession.taskWorkflowStates.has(seedTaskId)) {
49977
50099
  otherSession.taskWorkflowStates.set(seedTaskId, "coder_delegated");
49978
50100
  }
49979
- for (const [taskId, state] of otherSession.taskWorkflowStates) {
49980
- if (state === "coder_delegated" || state === "pre_check_passed") {
50101
+ for (const [taskId, state2] of otherSession.taskWorkflowStates) {
50102
+ if (state2 === "coder_delegated" || state2 === "pre_check_passed") {
49981
50103
  try {
49982
50104
  advanceTaskState(otherSession, taskId, "reviewer_run");
49983
50105
  } catch (err2) {
49984
- console.warn(`[delegation-gate] toolAfter cross-session: could not advance ${taskId} (${state}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
50106
+ console.warn(`[delegation-gate] toolAfter cross-session: could not advance ${taskId} (${state2}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
49985
50107
  }
49986
50108
  }
49987
50109
  }
@@ -49991,12 +50113,12 @@ function createDelegationGateHook(config3, directory) {
49991
50113
  if (seedTaskId && !otherSession.taskWorkflowStates.has(seedTaskId)) {
49992
50114
  otherSession.taskWorkflowStates.set(seedTaskId, "reviewer_run");
49993
50115
  }
49994
- for (const [taskId, state] of otherSession.taskWorkflowStates) {
49995
- if (state === "reviewer_run") {
50116
+ for (const [taskId, state2] of otherSession.taskWorkflowStates) {
50117
+ if (state2 === "reviewer_run") {
49996
50118
  try {
49997
50119
  advanceTaskState(otherSession, taskId, "tests_run");
49998
50120
  } catch (err2) {
49999
- console.warn(`[delegation-gate] toolAfter cross-session: could not advance ${taskId} (${state}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
50121
+ console.warn(`[delegation-gate] toolAfter cross-session: could not advance ${taskId} (${state2}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
50000
50122
  }
50001
50123
  }
50002
50124
  }
@@ -50060,23 +50182,23 @@ function createDelegationGateHook(config3, directory) {
50060
50182
  session.qaSkipTaskIds = [];
50061
50183
  }
50062
50184
  if (hasReviewer && session.taskWorkflowStates) {
50063
- for (const [taskId, state] of session.taskWorkflowStates) {
50064
- if (state === "coder_delegated" || state === "pre_check_passed") {
50185
+ for (const [taskId, state2] of session.taskWorkflowStates) {
50186
+ if (state2 === "coder_delegated" || state2 === "pre_check_passed") {
50065
50187
  try {
50066
50188
  advanceTaskState(session, taskId, "reviewer_run");
50067
50189
  } catch (err2) {
50068
- console.warn(`[delegation-gate] fallback: could not advance ${taskId} (${state}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
50190
+ console.warn(`[delegation-gate] fallback: could not advance ${taskId} (${state2}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
50069
50191
  }
50070
50192
  }
50071
50193
  }
50072
50194
  }
50073
50195
  if (hasReviewer && hasTestEngineer && session.taskWorkflowStates) {
50074
- for (const [taskId, state] of session.taskWorkflowStates) {
50075
- if (state === "reviewer_run") {
50196
+ for (const [taskId, state2] of session.taskWorkflowStates) {
50197
+ if (state2 === "reviewer_run") {
50076
50198
  try {
50077
50199
  advanceTaskState(session, taskId, "tests_run");
50078
50200
  } catch (err2) {
50079
- console.warn(`[delegation-gate] fallback: could not advance ${taskId} (${state}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
50201
+ console.warn(`[delegation-gate] fallback: could not advance ${taskId} (${state2}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
50080
50202
  }
50081
50203
  }
50082
50204
  }
@@ -50091,12 +50213,12 @@ function createDelegationGateHook(config3, directory) {
50091
50213
  if (seedTaskId && !otherSession.taskWorkflowStates.has(seedTaskId)) {
50092
50214
  otherSession.taskWorkflowStates.set(seedTaskId, "coder_delegated");
50093
50215
  }
50094
- for (const [taskId, state] of otherSession.taskWorkflowStates) {
50095
- if (state === "coder_delegated" || state === "pre_check_passed") {
50216
+ for (const [taskId, state2] of otherSession.taskWorkflowStates) {
50217
+ if (state2 === "coder_delegated" || state2 === "pre_check_passed") {
50096
50218
  try {
50097
50219
  advanceTaskState(otherSession, taskId, "reviewer_run");
50098
50220
  } catch (err2) {
50099
- console.warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${state}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
50221
+ console.warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${state2}) \u2192 reviewer_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
50100
50222
  }
50101
50223
  }
50102
50224
  }
@@ -50112,12 +50234,12 @@ function createDelegationGateHook(config3, directory) {
50112
50234
  if (seedTaskId && !otherSession.taskWorkflowStates.has(seedTaskId)) {
50113
50235
  otherSession.taskWorkflowStates.set(seedTaskId, "reviewer_run");
50114
50236
  }
50115
- for (const [taskId, state] of otherSession.taskWorkflowStates) {
50116
- if (state === "reviewer_run") {
50237
+ for (const [taskId, state2] of otherSession.taskWorkflowStates) {
50238
+ if (state2 === "reviewer_run") {
50117
50239
  try {
50118
50240
  advanceTaskState(otherSession, taskId, "tests_run");
50119
50241
  } catch (err2) {
50120
- console.warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${state}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
50242
+ console.warn(`[delegation-gate] fallback cross-session: could not advance ${taskId} (${state2}) \u2192 tests_run: ${err2 instanceof Error ? err2.message : String(err2)}`);
50121
50243
  }
50122
50244
  }
50123
50245
  }
@@ -50363,7 +50485,7 @@ ${warningLines.join(`
50363
50485
  }
50364
50486
  // src/hooks/delegation-sanitizer.ts
50365
50487
  init_utils2();
50366
- import * as fs16 from "fs";
50488
+ import * as fs17 from "fs";
50367
50489
  var SANITIZATION_PATTERNS = [
50368
50490
  /\b\d+(st|nd|rd|th)\s+(attempt|try|time)\b/gi,
50369
50491
  /\b(5th|fifth|final|last)\s+attempt\b/gi,
@@ -50434,7 +50556,7 @@ function createDelegationSanitizerHook(directory) {
50434
50556
  stripped_patterns: result.stripped,
50435
50557
  timestamp: new Date().toISOString()
50436
50558
  };
50437
- fs16.appendFileSync(eventsPath, `${JSON.stringify(event)}
50559
+ fs17.appendFileSync(eventsPath, `${JSON.stringify(event)}
50438
50560
  `, "utf-8");
50439
50561
  } catch {}
50440
50562
  }
@@ -50684,13 +50806,13 @@ init_schema();
50684
50806
  init_manager();
50685
50807
  init_detector();
50686
50808
  init_manager2();
50687
- import * as fs18 from "fs";
50809
+ import * as fs19 from "fs";
50688
50810
 
50689
50811
  // src/services/decision-drift-analyzer.ts
50690
50812
  init_utils2();
50691
50813
  init_manager2();
50692
- import * as fs17 from "fs";
50693
- import * as path30 from "path";
50814
+ import * as fs18 from "fs";
50815
+ import * as path31 from "path";
50694
50816
  var DEFAULT_DRIFT_CONFIG = {
50695
50817
  staleThresholdPhases: 1,
50696
50818
  detectContradictions: true,
@@ -50844,11 +50966,11 @@ async function analyzeDecisionDrift(directory, config3 = {}) {
50844
50966
  currentPhase = legacyPhase;
50845
50967
  }
50846
50968
  }
50847
- const contextPath = path30.join(directory, ".swarm", "context.md");
50969
+ const contextPath = path31.join(directory, ".swarm", "context.md");
50848
50970
  let contextContent = "";
50849
50971
  try {
50850
- if (fs17.existsSync(contextPath)) {
50851
- contextContent = fs17.readFileSync(contextPath, "utf-8");
50972
+ if (fs18.existsSync(contextPath)) {
50973
+ contextContent = fs18.readFileSync(contextPath, "utf-8");
50852
50974
  }
50853
50975
  } catch {
50854
50976
  return {
@@ -51342,11 +51464,11 @@ function createSystemEnhancerHook(config3, directory) {
51342
51464
  if (handoffContent) {
51343
51465
  const handoffPath = validateSwarmPath(directory, "handoff.md");
51344
51466
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
51345
- if (fs18.existsSync(consumedPath)) {
51467
+ if (fs19.existsSync(consumedPath)) {
51346
51468
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
51347
- fs18.unlinkSync(consumedPath);
51469
+ fs19.unlinkSync(consumedPath);
51348
51470
  }
51349
- fs18.renameSync(handoffPath, consumedPath);
51471
+ fs19.renameSync(handoffPath, consumedPath);
51350
51472
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
51351
51473
  The previous model's session ended. Here is your starting context:
51352
51474
 
@@ -51626,11 +51748,11 @@ ${budgetWarning}`);
51626
51748
  if (handoffContent) {
51627
51749
  const handoffPath = validateSwarmPath(directory, "handoff.md");
51628
51750
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
51629
- if (fs18.existsSync(consumedPath)) {
51751
+ if (fs19.existsSync(consumedPath)) {
51630
51752
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
51631
- fs18.unlinkSync(consumedPath);
51753
+ fs19.unlinkSync(consumedPath);
51632
51754
  }
51633
- fs18.renameSync(handoffPath, consumedPath);
51755
+ fs19.renameSync(handoffPath, consumedPath);
51634
51756
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
51635
51757
  The previous model's session ended. Here is your starting context:
51636
51758
 
@@ -52308,14 +52430,14 @@ function createDarkMatterDetectorHook(directory) {
52308
52430
  }
52309
52431
 
52310
52432
  // src/hooks/incremental-verify.ts
52311
- import * as fs19 from "fs";
52312
- import * as path31 from "path";
52433
+ import * as fs20 from "fs";
52434
+ import * as path32 from "path";
52313
52435
  function detectTypecheckCommand(projectDir) {
52314
- const pkgPath = path31.join(projectDir, "package.json");
52315
- if (!fs19.existsSync(pkgPath))
52436
+ const pkgPath = path32.join(projectDir, "package.json");
52437
+ if (!fs20.existsSync(pkgPath))
52316
52438
  return null;
52317
52439
  try {
52318
- const pkg = JSON.parse(fs19.readFileSync(pkgPath, "utf8"));
52440
+ const pkg = JSON.parse(fs20.readFileSync(pkgPath, "utf8"));
52319
52441
  const scripts = pkg.scripts;
52320
52442
  if (scripts?.typecheck)
52321
52443
  return ["bun", "run", "typecheck"];
@@ -52325,7 +52447,7 @@ function detectTypecheckCommand(projectDir) {
52325
52447
  ...pkg.dependencies,
52326
52448
  ...pkg.devDependencies
52327
52449
  };
52328
- if (!deps?.typescript && !fs19.existsSync(path31.join(projectDir, "tsconfig.json"))) {
52450
+ if (!deps?.typescript && !fs20.existsSync(path32.join(projectDir, "tsconfig.json"))) {
52329
52451
  return null;
52330
52452
  }
52331
52453
  return ["npx", "tsc", "--noEmit"];
@@ -52392,7 +52514,7 @@ ${errorSummary}`);
52392
52514
  // src/hooks/knowledge-reader.ts
52393
52515
  import { existsSync as existsSync19 } from "fs";
52394
52516
  import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
52395
- import * as path32 from "path";
52517
+ import * as path33 from "path";
52396
52518
  var JACCARD_THRESHOLD = 0.6;
52397
52519
  var HIVE_TIER_BOOST = 0.05;
52398
52520
  var SAME_PROJECT_PENALTY = -0.05;
@@ -52440,7 +52562,7 @@ function inferCategoriesFromPhase(phaseDescription) {
52440
52562
  return ["process", "tooling"];
52441
52563
  }
52442
52564
  async function recordLessonsShown(directory, lessonIds, currentPhase) {
52443
- const shownFile = path32.join(directory, ".swarm", ".knowledge-shown.json");
52565
+ const shownFile = path33.join(directory, ".swarm", ".knowledge-shown.json");
52444
52566
  try {
52445
52567
  let shownData = {};
52446
52568
  if (existsSync19(shownFile)) {
@@ -52448,7 +52570,7 @@ async function recordLessonsShown(directory, lessonIds, currentPhase) {
52448
52570
  shownData = JSON.parse(content);
52449
52571
  }
52450
52572
  shownData[currentPhase] = lessonIds;
52451
- await mkdir4(path32.dirname(shownFile), { recursive: true });
52573
+ await mkdir4(path33.dirname(shownFile), { recursive: true });
52452
52574
  await writeFile4(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
52453
52575
  } catch {
52454
52576
  console.warn("[swarm] Knowledge: failed to record shown lessons");
@@ -52543,7 +52665,7 @@ async function readMergedKnowledge(directory, config3, context) {
52543
52665
  return topN;
52544
52666
  }
52545
52667
  async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
52546
- const shownFile = path32.join(directory, ".swarm", ".knowledge-shown.json");
52668
+ const shownFile = path33.join(directory, ".swarm", ".knowledge-shown.json");
52547
52669
  try {
52548
52670
  if (!existsSync19(shownFile)) {
52549
52671
  return;
@@ -53015,12 +53137,12 @@ Use this data to avoid repeating known failure patterns.`;
53015
53137
  // src/hooks/curator-drift.ts
53016
53138
  init_event_bus();
53017
53139
  init_utils2();
53018
- import * as fs20 from "fs";
53019
- import * as path33 from "path";
53140
+ import * as fs21 from "fs";
53141
+ import * as path34 from "path";
53020
53142
  var DRIFT_REPORT_PREFIX = "drift-report-phase-";
53021
53143
  async function readPriorDriftReports(directory) {
53022
- const swarmDir = path33.join(directory, ".swarm");
53023
- const entries = await fs20.promises.readdir(swarmDir).catch(() => null);
53144
+ const swarmDir = path34.join(directory, ".swarm");
53145
+ const entries = await fs21.promises.readdir(swarmDir).catch(() => null);
53024
53146
  if (entries === null)
53025
53147
  return [];
53026
53148
  const reportFiles = entries.filter((name2) => name2.startsWith(DRIFT_REPORT_PREFIX) && name2.endsWith(".json")).sort();
@@ -53046,10 +53168,10 @@ async function readPriorDriftReports(directory) {
53046
53168
  async function writeDriftReport(directory, report) {
53047
53169
  const filename = `${DRIFT_REPORT_PREFIX}${report.phase}.json`;
53048
53170
  const filePath = validateSwarmPath(directory, filename);
53049
- const swarmDir = path33.dirname(filePath);
53050
- await fs20.promises.mkdir(swarmDir, { recursive: true });
53171
+ const swarmDir = path34.dirname(filePath);
53172
+ await fs21.promises.mkdir(swarmDir, { recursive: true });
53051
53173
  try {
53052
- await fs20.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
53174
+ await fs21.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
53053
53175
  } catch (err2) {
53054
53176
  throw new Error(`[curator-drift] Failed to write drift report to ${filePath}: ${String(err2)}`);
53055
53177
  }
@@ -53435,7 +53557,7 @@ Review before proceeding.`;
53435
53557
 
53436
53558
  // src/hooks/steering-consumed.ts
53437
53559
  init_utils2();
53438
- import * as fs21 from "fs";
53560
+ import * as fs22 from "fs";
53439
53561
  function recordSteeringConsumed(directory, directiveId) {
53440
53562
  try {
53441
53563
  const eventsPath = validateSwarmPath(directory, "events.jsonl");
@@ -53444,7 +53566,7 @@ function recordSteeringConsumed(directory, directiveId) {
53444
53566
  directiveId,
53445
53567
  timestamp: new Date().toISOString()
53446
53568
  };
53447
- fs21.appendFileSync(eventsPath, `${JSON.stringify(event)}
53569
+ fs22.appendFileSync(eventsPath, `${JSON.stringify(event)}
53448
53570
  `, "utf-8");
53449
53571
  } catch {}
53450
53572
  }
@@ -53484,87 +53606,6 @@ function createSteeringConsumedHook(directory) {
53484
53606
  return safeHook(hook);
53485
53607
  }
53486
53608
 
53487
- // src/services/compaction-service.ts
53488
- import * as fs22 from "fs";
53489
- import * as path34 from "path";
53490
- function makeInitialState() {
53491
- return {
53492
- lastObservationAt: 0,
53493
- lastReflectionAt: 0,
53494
- lastEmergencyAt: 0,
53495
- observationCount: 0,
53496
- reflectionCount: 0,
53497
- emergencyCount: 0
53498
- };
53499
- }
53500
- function appendSnapshot(directory, tier, budgetPct, message) {
53501
- try {
53502
- const snapshotPath = path34.join(directory, ".swarm", "context-snapshot.md");
53503
- const timestamp = new Date().toISOString();
53504
- const entry = `
53505
- ## [${tier.toUpperCase()}] ${timestamp} \u2014 ${budgetPct.toFixed(1)}% used
53506
- ${message}
53507
- `;
53508
- fs22.appendFileSync(snapshotPath, entry, "utf-8");
53509
- } catch {}
53510
- }
53511
- function buildObservationMessage(budgetPct) {
53512
- return `[CONTEXT COMPACTION \u2014 OBSERVATION TIER]
53513
- ` + `Context window is ${budgetPct.toFixed(1)}% used. Initiating observation compaction.
53514
- ` + `INSTRUCTIONS: Summarise the key decisions made so far, files changed, errors resolved, ` + `and the current task state. Discard verbose tool outputs and raw file reads. ` + `Preserve: plan task ID, agent verdicts, file paths touched, unresolved blockers.
53515
- ` + `[/CONTEXT COMPACTION]`;
53516
- }
53517
- function buildReflectionMessage(budgetPct) {
53518
- return `[CONTEXT COMPACTION \u2014 REFLECTION TIER]
53519
- ` + `Context window is ${budgetPct.toFixed(1)}% used. Initiating reflection compaction.
53520
- ` + `INSTRUCTIONS: Re-summarise into a tighter format. Discard completed task details ` + `and resolved errors. Retain ONLY: current phase tasks remaining, open blockers, ` + `last 3 reviewer/test verdicts, and active file scope.
53521
- ` + `[/CONTEXT COMPACTION]`;
53522
- }
53523
- function buildEmergencyMessage(budgetPct, preserveLastN) {
53524
- return `[CONTEXT COMPACTION \u2014 EMERGENCY TIER]
53525
- ` + `Context window is ${budgetPct.toFixed(1)}% used. EMERGENCY compaction required.
53526
- ` + `INSTRUCTIONS: Retain ONLY the system prompt, the current task context, and the ` + `last ${preserveLastN} conversation turns. Discard everything else. ` + `If you cannot complete the current task in the remaining context, escalate to the user.
53527
- ` + `[/CONTEXT COMPACTION]`;
53528
- }
53529
- function createCompactionService(config3, directory, injectMessage) {
53530
- const state = makeInitialState();
53531
- return {
53532
- toolAfter: async (_input, _output) => {
53533
- if (!config3.enabled)
53534
- return;
53535
- const budgetPct = swarmState.lastBudgetPct ?? 0;
53536
- if (budgetPct <= 0)
53537
- return;
53538
- const sessionId = _input.sessionID;
53539
- try {
53540
- if (budgetPct >= config3.emergencyThreshold && budgetPct > state.lastEmergencyAt + 5) {
53541
- state.lastEmergencyAt = budgetPct;
53542
- state.emergencyCount++;
53543
- const msg = buildEmergencyMessage(budgetPct, config3.preserveLastNTurns);
53544
- appendSnapshot(directory, "emergency", budgetPct, msg);
53545
- injectMessage(sessionId, msg);
53546
- return;
53547
- }
53548
- if (budgetPct >= config3.reflectionThreshold && budgetPct > state.lastReflectionAt + 5) {
53549
- state.lastReflectionAt = budgetPct;
53550
- state.reflectionCount++;
53551
- const msg = buildReflectionMessage(budgetPct);
53552
- appendSnapshot(directory, "reflection", budgetPct, msg);
53553
- injectMessage(sessionId, msg);
53554
- return;
53555
- }
53556
- if (budgetPct >= config3.observationThreshold && budgetPct > state.lastObservationAt + 5) {
53557
- state.lastObservationAt = budgetPct;
53558
- state.observationCount++;
53559
- const msg = buildObservationMessage(budgetPct);
53560
- appendSnapshot(directory, "observation", budgetPct, msg);
53561
- injectMessage(sessionId, msg);
53562
- }
53563
- } catch {}
53564
- }
53565
- };
53566
- }
53567
-
53568
53609
  // src/index.ts
53569
53610
  init_config_doctor();
53570
53611
 
@@ -61228,8 +61269,8 @@ function parsePackageResolved(content) {
61228
61269
  const pins = resolved.pins || [];
61229
61270
  for (const pin of pins) {
61230
61271
  const identity = pin.identity || pin.package || "";
61231
- const state = pin.state || {};
61232
- const version3 = state.version || state.revision || "";
61272
+ const state2 = pin.state || {};
61273
+ const version3 = state2.version || state2.revision || "";
61233
61274
  let org = "";
61234
61275
  const location = pin.location || "";
61235
61276
  const orgMatch = location.match(/github\.com\/([^/]+)\//);
@@ -62719,8 +62760,8 @@ function checkReviewerGate(taskId, workingDirectory) {
62719
62760
  continue;
62720
62761
  }
62721
62762
  validSessionCount++;
62722
- const state = getTaskState(session, taskId);
62723
- if (state === "tests_run" || state === "complete") {
62763
+ const state2 = getTaskState(session, taskId);
62764
+ if (state2 === "tests_run" || state2 === "complete") {
62724
62765
  return { blocked: false, reason: "" };
62725
62766
  }
62726
62767
  }
@@ -62731,8 +62772,8 @@ function checkReviewerGate(taskId, workingDirectory) {
62731
62772
  for (const [sessionId, session] of swarmState.agentSessions) {
62732
62773
  if (!(session.taskWorkflowStates instanceof Map))
62733
62774
  continue;
62734
- const state = getTaskState(session, taskId);
62735
- stateEntries.push(`${sessionId}: ${state}`);
62775
+ const state2 = getTaskState(session, taskId);
62776
+ stateEntries.push(`${sessionId}: ${state2}`);
62736
62777
  }
62737
62778
  try {
62738
62779
  const resolvedDir2 = workingDirectory ?? process.cwd();
@@ -63085,16 +63126,24 @@ var OpenCodeSwarm = async (ctx) => {
63085
63126
  classThreshold: 3,
63086
63127
  commentStripThreshold: 5,
63087
63128
  diffLineThreshold: 200
63088
- }, ctx.directory, (_sessionId, message) => {
63089
- console.warn(`[slop-detector] ${message}`);
63129
+ }, ctx.directory, (sessionId, message) => {
63130
+ const s = swarmState.agentSessions.get(sessionId);
63131
+ if (s) {
63132
+ s.pendingAdvisoryMessages ??= [];
63133
+ s.pendingAdvisoryMessages.push(message);
63134
+ }
63090
63135
  }) : null;
63091
63136
  const incrementalVerifyHook = config3.incremental_verify?.enabled !== false ? createIncrementalVerifyHook(config3.incremental_verify ?? {
63092
63137
  enabled: true,
63093
63138
  command: null,
63094
63139
  timeoutMs: 30000,
63095
63140
  triggerAgents: ["coder"]
63096
- }, ctx.directory, (_sessionId, message) => {
63097
- console.warn(`[incremental-verify] ${message}`);
63141
+ }, ctx.directory, (sessionId, message) => {
63142
+ const s = swarmState.agentSessions.get(sessionId);
63143
+ if (s) {
63144
+ s.pendingAdvisoryMessages ??= [];
63145
+ s.pendingAdvisoryMessages.push(message);
63146
+ }
63098
63147
  }) : null;
63099
63148
  const compactionServiceHook = config3.compaction_service?.enabled !== false ? createCompactionService(config3.compaction_service ?? {
63100
63149
  enabled: true,
@@ -63102,8 +63151,12 @@ var OpenCodeSwarm = async (ctx) => {
63102
63151
  reflectionThreshold: 60,
63103
63152
  emergencyThreshold: 80,
63104
63153
  preserveLastNTurns: 5
63105
- }, ctx.directory, (_sessionId, message) => {
63106
- console.warn(`[compaction-service] ${message}`);
63154
+ }, ctx.directory, (sessionId, message) => {
63155
+ const s = swarmState.agentSessions.get(sessionId);
63156
+ if (s) {
63157
+ s.pendingAdvisoryMessages ??= [];
63158
+ s.pendingAdvisoryMessages.push(message);
63159
+ }
63107
63160
  }) : null;
63108
63161
  const snapshotWriterHook = createSnapshotWriterHook(ctx.directory);
63109
63162
  const automationConfig = AutomationConfigSchema.parse(config3.automation ?? {});
@@ -63381,7 +63434,8 @@ var OpenCodeSwarm = async (ctx) => {
63381
63434
  const pressureSession = ensureAgentSession(input.sessionID, swarmState.activeAgent.get(input.sessionID) ?? ORCHESTRATOR_NAME);
63382
63435
  if (!pressureSession.contextPressureWarningSent) {
63383
63436
  pressureSession.contextPressureWarningSent = true;
63384
- console.warn(`[context-pressure] CONTEXT PRESSURE: ${swarmState.lastBudgetPct.toFixed(1)}% of context window estimated used. Prioritize completing the current task.`);
63437
+ pressureSession.pendingAdvisoryMessages ??= [];
63438
+ pressureSession.pendingAdvisoryMessages.push(`CONTEXT PRESSURE: ${swarmState.lastBudgetPct.toFixed(1)}% of context window used. Prioritize completing the current task before starting new work.`);
63385
63439
  }
63386
63440
  }
63387
63441
  await safeHook(activityHooks.toolBefore)(input, output);
@@ -21,3 +21,8 @@ export interface CompactionServiceHook {
21
21
  }) => Promise<void>;
22
22
  }
23
23
  export declare function createCompactionService(config: CompactionConfig, directory: string, injectMessage: (sessionId: string, message: string) => void): CompactionServiceHook;
24
+ export declare function getCompactionMetrics(): {
25
+ compactionCount: number;
26
+ lastSnapshotAt: string | null;
27
+ };
28
+ export declare function resetCompactionState(): void;
package/dist/state.d.ts CHANGED
@@ -129,6 +129,8 @@ export interface AgentSessionState {
129
129
  };
130
130
  /** Flag to track if the 50% context pressure warning has been sent this session */
131
131
  contextPressureWarningSent?: boolean;
132
+ /** Queue of advisory messages (e.g., SLOP, context pressure) pending injection into next messagesTransform */
133
+ pendingAdvisoryMessages?: string[];
132
134
  }
133
135
  /**
134
136
  * Represents a single agent invocation window with isolated guardrail budgets.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "6.29.0",
3
+ "version": "6.29.1",
4
4
  "description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",