opencode-swarm 6.50.0 → 6.51.0

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
@@ -117,10 +117,37 @@ function isLowCapabilityModel(modelId) {
117
117
  const lower = modelId.toLowerCase();
118
118
  return LOW_CAPABILITY_MODELS.some((substr) => lower.includes(substr));
119
119
  }
120
- var QA_AGENTS, PIPELINE_AGENTS, ORCHESTRATOR_NAME = "architect", ALL_SUBAGENT_NAMES, ALL_AGENT_NAMES, AGENT_TOOL_MAP, WRITE_TOOL_NAMES, TOOL_DESCRIPTIONS, DEFAULT_MODELS, DEFAULT_SCORING_CONFIG, LOW_CAPABILITY_MODELS;
120
+ var QA_AGENTS, PIPELINE_AGENTS, ORCHESTRATOR_NAME = "architect", ALL_SUBAGENT_NAMES, ALL_AGENT_NAMES, AGENT_TOOL_MAP, WRITE_TOOL_NAMES, TOOL_DESCRIPTIONS, DEFAULT_MODELS, DEFAULT_SCORING_CONFIG, LOW_CAPABILITY_MODELS, TURBO_MODE_BANNER = `## \uD83D\uDE80 TURBO MODE ACTIVE
121
+
122
+ **Speed optimization enabled for this session.**
123
+
124
+ While Turbo Mode is active:
125
+ - **Stage A gates** (lint, imports, pre_check_batch) are still REQUIRED for ALL tasks
126
+ - **Tier 3 tasks** (security-sensitive files matching: architect*.ts, delegation*.ts, guardrails*.ts, adversarial*.ts, sanitiz*.ts, auth*, permission*, crypto*, secret*, security) still require FULL review (Stage B)
127
+ - **Tier 0-2 tasks** can skip Stage B (reviewer, test_engineer) to speed up execution
128
+ - **Phase completion gates** (completion-verify and drift verification gate) are automatically bypassed \u2014 phase_complete will succeed without drift verification evidence when turbo is active. Note: turbo bypass is session-scoped; one session's turbo does not affect other sessions.
129
+
130
+ Classification still determines the pipeline:
131
+ - TIER 0 (metadata): lint + diff only \u2014 no change
132
+ - TIER 1 (docs): Stage A + reviewer \u2014 no change
133
+ - TIER 2 (standard code): Stage A + reviewer + test_engineer \u2014 CAN SKIP Stage B with turboMode
134
+ - TIER 3 (critical): Stage A + 2x reviewer + 2x test_engineer \u2014 Stage B REQUIRED (no turbo bypass)
135
+
136
+ Do NOT skip Stage A gates. Do NOT skip Stage B for TIER 3.
137
+ `, FULL_AUTO_BANNER = `## \u26A1 FULL-AUTO MODE ACTIVE
138
+
139
+ You are operating without a human in the loop. All escalations route to the Autonomous Oversight Critic instead of a user.
140
+
141
+ Behavioral changes:
142
+ - TIER 3 escalations go to the critic, not a human. Frame your questions technically, not conversationally.
143
+ - Phase completion approval comes from the critic. Ensure all evidence is written before requesting.
144
+ - The critic defaults to REJECT. Do not attempt to pressure, negotiate, or shortcut. Complete the evidence trail.
145
+ - If the critic returns ESCALATE_TO_HUMAN, the session will pause or terminate. Only the critic can trigger this.
146
+ - Do NOT ask "Ready for Phase N+1?" \u2014 call phase_complete directly. The critic reviews automatically.
147
+ `;
121
148
  var init_constants = __esm(() => {
122
149
  init_tool_names();
123
- QA_AGENTS = ["reviewer", "critic"];
150
+ QA_AGENTS = ["reviewer", "critic", "critic_oversight"];
124
151
  PIPELINE_AGENTS = ["explorer", "coder", "test_engineer"];
125
152
  ALL_SUBAGENT_NAMES = [
126
153
  "sme",
@@ -276,6 +303,14 @@ var init_constants = __esm(() => {
276
303
  "symbols",
277
304
  "knowledgeRecall"
278
305
  ],
306
+ critic_oversight: [
307
+ "complexity_hotspots",
308
+ "detect_domains",
309
+ "imports",
310
+ "retrieve_summary",
311
+ "symbols",
312
+ "knowledgeRecall"
313
+ ],
279
314
  docs: [
280
315
  "detect_domains",
281
316
  "extract_code_blocks",
@@ -366,6 +401,7 @@ var init_constants = __esm(() => {
366
401
  critic: "opencode/trinity-large-preview-free",
367
402
  critic_sounding_board: "opencode/trinity-large-preview-free",
368
403
  critic_drift_verifier: "opencode/trinity-large-preview-free",
404
+ critic_oversight: "opencode/trinity-large-preview-free",
369
405
  docs: "opencode/trinity-large-preview-free",
370
406
  designer: "opencode/trinity-large-preview-free",
371
407
  curator_init: "opencode/trinity-large-preview-free",
@@ -15107,7 +15143,19 @@ var init_schema = __esm(() => {
15107
15143
  }).optional(),
15108
15144
  incremental_verify: IncrementalVerifyConfigSchema.optional(),
15109
15145
  compaction_service: CompactionConfigSchema.optional(),
15110
- turbo_mode: exports_external.boolean().default(false).optional()
15146
+ turbo_mode: exports_external.boolean().default(false).optional(),
15147
+ full_auto: exports_external.object({
15148
+ enabled: exports_external.boolean().default(false),
15149
+ critic_model: exports_external.string().optional(),
15150
+ max_interactions_per_phase: exports_external.number().int().min(5).max(200).default(50),
15151
+ deadlock_threshold: exports_external.number().int().min(2).max(10).default(3),
15152
+ escalation_mode: exports_external.enum(["pause", "terminate"]).default("pause")
15153
+ }).optional().default({
15154
+ enabled: false,
15155
+ max_interactions_per_phase: 50,
15156
+ deadlock_threshold: 3,
15157
+ escalation_mode: "pause"
15158
+ })
15111
15159
  });
15112
15160
  });
15113
15161
 
@@ -15873,7 +15921,533 @@ var init_telemetry = __esm(() => {
15873
15921
  },
15874
15922
  turboModeChanged(sessionId, enabled, agentName) {
15875
15923
  emit("turbo_mode_changed", { sessionId, enabled, agentName });
15924
+ },
15925
+ autoOversightEscalation(sessionId, reason, interactionCount, deadlockCount, phase) {
15926
+ emit("auto_oversight_escalation", {
15927
+ sessionId,
15928
+ reason,
15929
+ interactionCount,
15930
+ deadlockCount,
15931
+ phase
15932
+ });
15933
+ }
15934
+ };
15935
+ });
15936
+
15937
+ // src/state.ts
15938
+ var exports_state = {};
15939
+ __export(exports_state, {
15940
+ updateAgentEventTime: () => updateAgentEventTime,
15941
+ swarmState: () => swarmState,
15942
+ startAgentSession: () => startAgentSession,
15943
+ resetSwarmState: () => resetSwarmState,
15944
+ rehydrateSessionFromDisk: () => rehydrateSessionFromDisk,
15945
+ recordPhaseAgentDispatch: () => recordPhaseAgentDispatch,
15946
+ pruneOldWindows: () => pruneOldWindows,
15947
+ hasActiveTurboMode: () => hasActiveTurboMode,
15948
+ hasActiveFullAuto: () => hasActiveFullAuto,
15949
+ getTaskState: () => getTaskState,
15950
+ getAgentSession: () => getAgentSession,
15951
+ getActiveWindow: () => getActiveWindow,
15952
+ ensureAgentSession: () => ensureAgentSession,
15953
+ endAgentSession: () => endAgentSession,
15954
+ buildRehydrationCache: () => buildRehydrationCache,
15955
+ beginInvocation: () => beginInvocation,
15956
+ applyRehydrationCache: () => applyRehydrationCache,
15957
+ advanceTaskState: () => advanceTaskState
15958
+ });
15959
+ import * as fs5 from "fs/promises";
15960
+ import * as path5 from "path";
15961
+ function resetSwarmState() {
15962
+ swarmState.activeToolCalls.clear();
15963
+ swarmState.toolAggregates.clear();
15964
+ swarmState.activeAgent.clear();
15965
+ swarmState.delegationChains.clear();
15966
+ swarmState.pendingEvents = 0;
15967
+ swarmState.lastBudgetPct = 0;
15968
+ swarmState.agentSessions.clear();
15969
+ swarmState.pendingRehydrations.clear();
15970
+ swarmState.opencodeClient = null;
15971
+ swarmState.curatorInitAgentNames = [];
15972
+ swarmState.curatorPhaseAgentNames = [];
15973
+ _rehydrationCache = null;
15974
+ swarmState.fullAutoEnabledInConfig = false;
15975
+ }
15976
+ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000, directory) {
15977
+ const now = Date.now();
15978
+ const staleIds = [];
15979
+ for (const [id, session] of swarmState.agentSessions) {
15980
+ if (now - session.lastToolCallTime > staleDurationMs) {
15981
+ staleIds.push(id);
15876
15982
  }
15983
+ }
15984
+ for (const id of staleIds) {
15985
+ swarmState.agentSessions.delete(id);
15986
+ }
15987
+ const sessionState = {
15988
+ agentName,
15989
+ lastToolCallTime: now,
15990
+ lastAgentEventTime: now,
15991
+ delegationActive: false,
15992
+ activeInvocationId: 0,
15993
+ lastInvocationIdByAgent: {},
15994
+ windows: {},
15995
+ lastCompactionHint: 0,
15996
+ architectWriteCount: 0,
15997
+ lastCoderDelegationTaskId: null,
15998
+ currentTaskId: null,
15999
+ gateLog: new Map,
16000
+ reviewerCallCount: new Map,
16001
+ lastGateFailure: null,
16002
+ partialGateWarningsIssuedForTask: new Set,
16003
+ selfFixAttempted: false,
16004
+ selfCodingWarnedAtCount: 0,
16005
+ catastrophicPhaseWarnings: new Set,
16006
+ lastPhaseCompleteTimestamp: 0,
16007
+ lastPhaseCompletePhase: 0,
16008
+ phaseAgentsDispatched: new Set,
16009
+ lastCompletedPhaseAgentsDispatched: new Set,
16010
+ qaSkipCount: 0,
16011
+ qaSkipTaskIds: [],
16012
+ taskWorkflowStates: new Map,
16013
+ lastGateOutcome: null,
16014
+ declaredCoderScope: null,
16015
+ lastScopeViolation: null,
16016
+ scopeViolationDetected: false,
16017
+ modifiedFilesThisCoderTask: [],
16018
+ turboMode: false,
16019
+ fullAutoMode: swarmState.fullAutoEnabledInConfig,
16020
+ fullAutoInteractionCount: 0,
16021
+ fullAutoDeadlockCount: 0,
16022
+ fullAutoLastQuestionHash: null,
16023
+ model_fallback_index: 0,
16024
+ modelFallbackExhausted: false,
16025
+ coderRevisions: 0,
16026
+ revisionLimitHit: false,
16027
+ loopDetectionWindow: [],
16028
+ pendingAdvisoryMessages: [],
16029
+ sessionRehydratedAt: 0
16030
+ };
16031
+ swarmState.agentSessions.set(sessionId, sessionState);
16032
+ telemetry.sessionStarted(sessionId, agentName);
16033
+ swarmState.activeAgent.set(sessionId, agentName);
16034
+ applyRehydrationCache(sessionState);
16035
+ if (directory) {
16036
+ let rehydrationPromise;
16037
+ rehydrationPromise = rehydrateSessionFromDisk(directory, sessionState).catch((err2) => {
16038
+ console.warn("[state] Rehydration failed:", err2 instanceof Error ? err2.message : String(err2));
16039
+ }).finally(() => {
16040
+ swarmState.pendingRehydrations.delete(rehydrationPromise);
16041
+ });
16042
+ swarmState.pendingRehydrations.add(rehydrationPromise);
16043
+ }
16044
+ }
16045
+ function endAgentSession(sessionId) {
16046
+ swarmState.agentSessions.delete(sessionId);
16047
+ }
16048
+ function getAgentSession(sessionId) {
16049
+ return swarmState.agentSessions.get(sessionId);
16050
+ }
16051
+ function ensureAgentSession(sessionId, agentName, directory) {
16052
+ const now = Date.now();
16053
+ let session = swarmState.agentSessions.get(sessionId);
16054
+ if (session) {
16055
+ if (agentName && agentName !== session.agentName) {
16056
+ const oldName = session.agentName;
16057
+ session.agentName = agentName;
16058
+ telemetry.agentActivated(sessionId, agentName, oldName);
16059
+ session.delegationActive = false;
16060
+ session.lastAgentEventTime = now;
16061
+ if (!session.windows) {
16062
+ session.activeInvocationId = 0;
16063
+ session.lastInvocationIdByAgent = {};
16064
+ session.windows = {};
16065
+ }
16066
+ }
16067
+ if (!session.windows) {
16068
+ session.activeInvocationId = 0;
16069
+ session.lastInvocationIdByAgent = {};
16070
+ session.windows = {};
16071
+ }
16072
+ if (session.lastCompactionHint === undefined) {
16073
+ session.lastCompactionHint = 0;
16074
+ }
16075
+ if (session.architectWriteCount === undefined) {
16076
+ session.architectWriteCount = 0;
16077
+ }
16078
+ if (session.lastCoderDelegationTaskId === undefined) {
16079
+ session.lastCoderDelegationTaskId = null;
16080
+ }
16081
+ if (session.currentTaskId === undefined) {
16082
+ session.currentTaskId = null;
16083
+ }
16084
+ if (!session.gateLog) {
16085
+ session.gateLog = new Map;
16086
+ }
16087
+ if (!session.reviewerCallCount) {
16088
+ session.reviewerCallCount = new Map;
16089
+ }
16090
+ if (session.lastGateFailure === undefined) {
16091
+ session.lastGateFailure = null;
16092
+ }
16093
+ if (!session.partialGateWarningsIssuedForTask) {
16094
+ session.partialGateWarningsIssuedForTask = new Set;
16095
+ }
16096
+ if (session.selfFixAttempted === undefined) {
16097
+ session.selfFixAttempted = false;
16098
+ }
16099
+ if (session.selfCodingWarnedAtCount === undefined) {
16100
+ session.selfCodingWarnedAtCount = 0;
16101
+ }
16102
+ if (!session.catastrophicPhaseWarnings) {
16103
+ session.catastrophicPhaseWarnings = new Set;
16104
+ }
16105
+ if (session.lastPhaseCompleteTimestamp === undefined) {
16106
+ session.lastPhaseCompleteTimestamp = 0;
16107
+ }
16108
+ if (session.lastPhaseCompletePhase === undefined) {
16109
+ session.lastPhaseCompletePhase = 0;
16110
+ }
16111
+ if (!session.phaseAgentsDispatched) {
16112
+ session.phaseAgentsDispatched = new Set;
16113
+ }
16114
+ if (!session.lastCompletedPhaseAgentsDispatched) {
16115
+ session.lastCompletedPhaseAgentsDispatched = new Set;
16116
+ }
16117
+ if (session.qaSkipCount === undefined) {
16118
+ session.qaSkipCount = 0;
16119
+ }
16120
+ if (!session.qaSkipTaskIds) {
16121
+ session.qaSkipTaskIds = [];
16122
+ }
16123
+ if (!session.taskWorkflowStates) {
16124
+ session.taskWorkflowStates = new Map;
16125
+ }
16126
+ if (session.lastGateOutcome === undefined) {
16127
+ session.lastGateOutcome = null;
16128
+ }
16129
+ if (session.declaredCoderScope === undefined) {
16130
+ session.declaredCoderScope = null;
16131
+ }
16132
+ if (session.lastScopeViolation === undefined) {
16133
+ session.lastScopeViolation = null;
16134
+ }
16135
+ if (session.modifiedFilesThisCoderTask === undefined) {
16136
+ session.modifiedFilesThisCoderTask = [];
16137
+ }
16138
+ if (session.scopeViolationDetected === undefined) {
16139
+ session.scopeViolationDetected = false;
16140
+ }
16141
+ if (session.turboMode === undefined) {
16142
+ session.turboMode = false;
16143
+ }
16144
+ if (session.model_fallback_index === undefined) {
16145
+ session.model_fallback_index = 0;
16146
+ }
16147
+ if (session.modelFallbackExhausted === undefined) {
16148
+ session.modelFallbackExhausted = false;
16149
+ }
16150
+ if (session.loopDetectionWindow === undefined) {
16151
+ session.loopDetectionWindow = [];
16152
+ }
16153
+ if (session.pendingAdvisoryMessages === undefined) {
16154
+ session.pendingAdvisoryMessages = [];
16155
+ }
16156
+ if (session.coderRevisions === undefined) {
16157
+ session.coderRevisions = 0;
16158
+ }
16159
+ if (session.revisionLimitHit === undefined) {
16160
+ session.revisionLimitHit = false;
16161
+ }
16162
+ if (session.sessionRehydratedAt === undefined) {
16163
+ session.sessionRehydratedAt = 0;
16164
+ }
16165
+ session.lastToolCallTime = now;
16166
+ return session;
16167
+ }
16168
+ startAgentSession(sessionId, agentName ?? "unknown", 7200000, directory);
16169
+ session = swarmState.agentSessions.get(sessionId);
16170
+ if (!session) {
16171
+ throw new Error(`Failed to create guardrail session for ${sessionId}`);
16172
+ }
16173
+ return session;
16174
+ }
16175
+ function updateAgentEventTime(sessionId) {
16176
+ const session = swarmState.agentSessions.get(sessionId);
16177
+ if (session) {
16178
+ session.lastAgentEventTime = Date.now();
16179
+ }
16180
+ }
16181
+ function beginInvocation(sessionId, agentName) {
16182
+ const session = swarmState.agentSessions.get(sessionId);
16183
+ if (!session) {
16184
+ throw new Error(`Cannot begin invocation: session ${sessionId} does not exist`);
16185
+ }
16186
+ const stripped = stripKnownSwarmPrefix(agentName);
16187
+ if (stripped === ORCHESTRATOR_NAME) {
16188
+ return null;
16189
+ }
16190
+ const lastId = session.lastInvocationIdByAgent[stripped] || 0;
16191
+ const newId = lastId + 1;
16192
+ session.lastInvocationIdByAgent[stripped] = newId;
16193
+ session.activeInvocationId = newId;
16194
+ const now = Date.now();
16195
+ const window2 = {
16196
+ id: newId,
16197
+ agentName: stripped,
16198
+ startedAtMs: now,
16199
+ toolCalls: 0,
16200
+ consecutiveErrors: 0,
16201
+ hardLimitHit: false,
16202
+ lastSuccessTimeMs: now,
16203
+ recentToolCalls: [],
16204
+ warningIssued: false,
16205
+ warningReason: ""
16206
+ };
16207
+ const key = `${stripped}:${newId}`;
16208
+ session.windows[key] = window2;
16209
+ pruneOldWindows(sessionId, 24 * 60 * 60 * 1000, 50);
16210
+ telemetry.delegationBegin(sessionId, stripped, session.currentTaskId ?? "unknown");
16211
+ return window2;
16212
+ }
16213
+ function getActiveWindow(sessionId) {
16214
+ const session = swarmState.agentSessions.get(sessionId);
16215
+ if (!session || !session.windows) {
16216
+ return;
16217
+ }
16218
+ const stripped = stripKnownSwarmPrefix(session.agentName);
16219
+ const key = `${stripped}:${session.activeInvocationId}`;
16220
+ return session.windows[key];
16221
+ }
16222
+ function pruneOldWindows(sessionId, maxAgeMs = 24 * 60 * 60 * 1000, maxWindows = 50) {
16223
+ const session = swarmState.agentSessions.get(sessionId);
16224
+ if (!session || !session.windows) {
16225
+ return;
16226
+ }
16227
+ const now = Date.now();
16228
+ const entries = Object.entries(session.windows);
16229
+ const validByAge = entries.filter(([_, window2]) => now - window2.startedAtMs < maxAgeMs);
16230
+ const sorted = validByAge.sort((a, b) => b[1].startedAtMs - a[1].startedAtMs);
16231
+ const toKeep = sorted.slice(0, maxWindows);
16232
+ session.windows = Object.fromEntries(toKeep);
16233
+ }
16234
+ function recordPhaseAgentDispatch(sessionId, agentName) {
16235
+ const session = swarmState.agentSessions.get(sessionId);
16236
+ if (!session) {
16237
+ return;
16238
+ }
16239
+ if (!session.phaseAgentsDispatched) {
16240
+ session.phaseAgentsDispatched = new Set;
16241
+ }
16242
+ const normalizedName = stripKnownSwarmPrefix(agentName);
16243
+ session.phaseAgentsDispatched.add(normalizedName);
16244
+ }
16245
+ function isValidTaskId(taskId) {
16246
+ if (taskId === null || taskId === undefined) {
16247
+ return false;
16248
+ }
16249
+ if (typeof taskId !== "string") {
16250
+ return false;
16251
+ }
16252
+ const trimmed = taskId.trim();
16253
+ return trimmed.length > 0;
16254
+ }
16255
+ function advanceTaskState(session, taskId, newState) {
16256
+ if (!isValidTaskId(taskId)) {
16257
+ return;
16258
+ }
16259
+ if (!session || !(session.taskWorkflowStates instanceof Map)) {
16260
+ throw new Error("INVALID_SESSION: session.taskWorkflowStates must be a Map instance");
16261
+ }
16262
+ const STATE_ORDER = [
16263
+ "idle",
16264
+ "coder_delegated",
16265
+ "pre_check_passed",
16266
+ "reviewer_run",
16267
+ "tests_run",
16268
+ "complete"
16269
+ ];
16270
+ const current = session.taskWorkflowStates.get(taskId) ?? "idle";
16271
+ const currentIndex = STATE_ORDER.indexOf(current);
16272
+ const newIndex = STATE_ORDER.indexOf(newState);
16273
+ if (newIndex <= currentIndex) {
16274
+ throw new Error(`INVALID_TASK_STATE_TRANSITION: ${taskId} ${current} \u2192 ${newState}`);
16275
+ }
16276
+ if (newState === "complete" && current !== "tests_run") {
16277
+ throw new Error(`INVALID_TASK_STATE_TRANSITION: ${taskId} cannot reach complete from ${current} \u2014 must pass through tests_run first`);
16278
+ }
16279
+ session.taskWorkflowStates.set(taskId, newState);
16280
+ telemetry.taskStateChanged(session.agentName, taskId, newState, current);
16281
+ }
16282
+ function getTaskState(session, taskId) {
16283
+ if (!isValidTaskId(taskId)) {
16284
+ return "idle";
16285
+ }
16286
+ if (!session.taskWorkflowStates) {
16287
+ session.taskWorkflowStates = new Map;
16288
+ }
16289
+ return session.taskWorkflowStates.get(taskId) ?? "idle";
16290
+ }
16291
+ function planStatusToWorkflowState(status) {
16292
+ switch (status) {
16293
+ case "in_progress":
16294
+ return "coder_delegated";
16295
+ case "completed":
16296
+ return "complete";
16297
+ default:
16298
+ return "idle";
16299
+ }
16300
+ }
16301
+ function evidenceToWorkflowState(evidence) {
16302
+ const gates = evidence.gates ?? {};
16303
+ const requiredGates = evidence.required_gates ?? [];
16304
+ if (requiredGates.length > 0) {
16305
+ const allPassed = requiredGates.every((gate) => gates[gate] != null);
16306
+ if (allPassed) {
16307
+ return "complete";
16308
+ }
16309
+ }
16310
+ if (gates.test_engineer != null) {
16311
+ return "tests_run";
16312
+ }
16313
+ if (gates.reviewer != null) {
16314
+ return "reviewer_run";
16315
+ }
16316
+ if (Object.keys(gates).length > 0) {
16317
+ return "coder_delegated";
16318
+ }
16319
+ return "idle";
16320
+ }
16321
+ async function readPlanFromDisk(directory) {
16322
+ try {
16323
+ const planPath = path5.join(directory, ".swarm", "plan.json");
16324
+ const content = await fs5.readFile(planPath, "utf-8");
16325
+ const parsed = JSON.parse(content);
16326
+ return PlanSchema.parse(parsed);
16327
+ } catch {
16328
+ return null;
16329
+ }
16330
+ }
16331
+ async function readGateEvidenceFromDisk(directory) {
16332
+ const evidenceMap = new Map;
16333
+ try {
16334
+ const evidenceDir = path5.join(directory, ".swarm", "evidence");
16335
+ const entries = await fs5.readdir(evidenceDir, { withFileTypes: true });
16336
+ for (const entry of entries) {
16337
+ if (!entry.isFile() || !entry.name.endsWith(".json")) {
16338
+ continue;
16339
+ }
16340
+ const taskId = entry.name.replace(/\.json$/, "");
16341
+ if (!/^\d+\.\d+(\.\d+)*$/.test(taskId)) {
16342
+ continue;
16343
+ }
16344
+ try {
16345
+ const filePath = path5.join(evidenceDir, entry.name);
16346
+ const content = await fs5.readFile(filePath, "utf-8");
16347
+ const parsed = JSON.parse(content);
16348
+ if (parsed && typeof parsed.taskId === "string" && Array.isArray(parsed.required_gates)) {
16349
+ evidenceMap.set(taskId, parsed);
16350
+ }
16351
+ } catch {}
16352
+ }
16353
+ } catch {}
16354
+ return evidenceMap;
16355
+ }
16356
+ async function buildRehydrationCache(directory) {
16357
+ const planTaskStates = new Map;
16358
+ const plan = await readPlanFromDisk(directory);
16359
+ if (plan) {
16360
+ for (const phase of plan.phases ?? []) {
16361
+ for (const task of phase.tasks ?? []) {
16362
+ planTaskStates.set(task.id, planStatusToWorkflowState(task.status));
16363
+ }
16364
+ }
16365
+ }
16366
+ const evidenceMap = await readGateEvidenceFromDisk(directory);
16367
+ _rehydrationCache = { planTaskStates, evidenceMap };
16368
+ }
16369
+ function applyRehydrationCache(session) {
16370
+ if (!_rehydrationCache) {
16371
+ return;
16372
+ }
16373
+ if (!session.taskWorkflowStates) {
16374
+ session.taskWorkflowStates = new Map;
16375
+ }
16376
+ const { planTaskStates, evidenceMap } = _rehydrationCache;
16377
+ const STATE_ORDER = [
16378
+ "idle",
16379
+ "coder_delegated",
16380
+ "pre_check_passed",
16381
+ "reviewer_run",
16382
+ "tests_run",
16383
+ "complete"
16384
+ ];
16385
+ for (const [taskId, planState] of planTaskStates) {
16386
+ const existingState = session.taskWorkflowStates.get(taskId);
16387
+ const evidence = evidenceMap.get(taskId);
16388
+ if (evidence) {
16389
+ const derivedState = evidenceToWorkflowState(evidence);
16390
+ const existingIndex = existingState ? STATE_ORDER.indexOf(existingState) : -1;
16391
+ const derivedIndex = STATE_ORDER.indexOf(derivedState);
16392
+ if (derivedIndex > existingIndex) {
16393
+ session.taskWorkflowStates.set(taskId, derivedState);
16394
+ }
16395
+ } else {
16396
+ const existingIndex = existingState ? STATE_ORDER.indexOf(existingState) : -1;
16397
+ const derivedIndex = STATE_ORDER.indexOf(planState);
16398
+ if (derivedIndex > existingIndex) {
16399
+ session.taskWorkflowStates.set(taskId, planState);
16400
+ }
16401
+ }
16402
+ }
16403
+ }
16404
+ async function rehydrateSessionFromDisk(directory, session) {
16405
+ await buildRehydrationCache(directory);
16406
+ applyRehydrationCache(session);
16407
+ }
16408
+ function hasActiveTurboMode(sessionID) {
16409
+ if (sessionID) {
16410
+ const session = swarmState.agentSessions.get(sessionID);
16411
+ return session?.turboMode === true;
16412
+ }
16413
+ for (const [_sessionId, session] of swarmState.agentSessions) {
16414
+ if (session.turboMode === true) {
16415
+ return true;
16416
+ }
16417
+ }
16418
+ return false;
16419
+ }
16420
+ function hasActiveFullAuto(sessionID) {
16421
+ if (sessionID) {
16422
+ const session = swarmState.agentSessions.get(sessionID);
16423
+ return session?.fullAutoMode === true;
16424
+ }
16425
+ for (const [_sessionId, session] of swarmState.agentSessions) {
16426
+ if (session.fullAutoMode === true) {
16427
+ return true;
16428
+ }
16429
+ }
16430
+ return false;
16431
+ }
16432
+ var _rehydrationCache = null, swarmState;
16433
+ var init_state = __esm(() => {
16434
+ init_constants();
16435
+ init_plan_schema();
16436
+ init_schema();
16437
+ init_telemetry();
16438
+ swarmState = {
16439
+ activeToolCalls: new Map,
16440
+ toolAggregates: new Map,
16441
+ activeAgent: new Map,
16442
+ delegationChains: new Map,
16443
+ pendingEvents: 0,
16444
+ opencodeClient: null,
16445
+ curatorInitAgentNames: [],
16446
+ curatorPhaseAgentNames: [],
16447
+ lastBudgetPct: 0,
16448
+ agentSessions: new Map,
16449
+ pendingRehydrations: new Set,
16450
+ fullAutoEnabledInConfig: false
15877
16451
  };
15878
16452
  });
15879
16453
 
@@ -37983,13 +38557,13 @@ __export(exports_review_receipt, {
37983
38557
  buildApprovedReceipt: () => buildApprovedReceipt
37984
38558
  });
37985
38559
  import * as crypto5 from "crypto";
37986
- import * as fs29 from "fs";
37987
- import * as path40 from "path";
38560
+ import * as fs31 from "fs";
38561
+ import * as path41 from "path";
37988
38562
  function resolveReceiptsDir(directory) {
37989
- return path40.join(directory, ".swarm", "review-receipts");
38563
+ return path41.join(directory, ".swarm", "review-receipts");
37990
38564
  }
37991
38565
  function resolveReceiptIndexPath(directory) {
37992
- return path40.join(resolveReceiptsDir(directory), "index.json");
38566
+ return path41.join(resolveReceiptsDir(directory), "index.json");
37993
38567
  }
37994
38568
  function buildReceiptFilename(id, date9) {
37995
38569
  const dateStr = date9.toISOString().slice(0, 10);
@@ -38012,11 +38586,11 @@ function isScopeStale(receipt, currentContent) {
38012
38586
  }
38013
38587
  async function readReceiptIndex(directory) {
38014
38588
  const indexPath = resolveReceiptIndexPath(directory);
38015
- if (!fs29.existsSync(indexPath)) {
38589
+ if (!fs31.existsSync(indexPath)) {
38016
38590
  return { schema_version: 1, entries: [] };
38017
38591
  }
38018
38592
  try {
38019
- const content = await fs29.promises.readFile(indexPath, "utf-8");
38593
+ const content = await fs31.promises.readFile(indexPath, "utf-8");
38020
38594
  const parsed = JSON.parse(content);
38021
38595
  if (parsed.schema_version !== 1 || !Array.isArray(parsed.entries)) {
38022
38596
  return { schema_version: 1, entries: [] };
@@ -38028,21 +38602,21 @@ async function readReceiptIndex(directory) {
38028
38602
  }
38029
38603
  async function writeReceiptIndex(directory, index) {
38030
38604
  const indexPath = resolveReceiptIndexPath(directory);
38031
- const dir = path40.dirname(indexPath);
38032
- await fs29.promises.mkdir(dir, { recursive: true });
38605
+ const dir = path41.dirname(indexPath);
38606
+ await fs31.promises.mkdir(dir, { recursive: true });
38033
38607
  const tmpPath = `${indexPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
38034
- await fs29.promises.writeFile(tmpPath, JSON.stringify(index, null, 2), "utf-8");
38035
- fs29.renameSync(tmpPath, indexPath);
38608
+ await fs31.promises.writeFile(tmpPath, JSON.stringify(index, null, 2), "utf-8");
38609
+ fs31.renameSync(tmpPath, indexPath);
38036
38610
  }
38037
38611
  async function persistReviewReceipt(directory, receipt) {
38038
38612
  const receiptsDir = resolveReceiptsDir(directory);
38039
- await fs29.promises.mkdir(receiptsDir, { recursive: true });
38613
+ await fs31.promises.mkdir(receiptsDir, { recursive: true });
38040
38614
  const now = new Date(receipt.reviewed_at);
38041
38615
  const filename = buildReceiptFilename(receipt.id, now);
38042
- const receiptPath = path40.join(receiptsDir, filename);
38616
+ const receiptPath = path41.join(receiptsDir, filename);
38043
38617
  const tmpPath = `${receiptPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
38044
- await fs29.promises.writeFile(tmpPath, JSON.stringify(receipt, null, 2), "utf-8");
38045
- fs29.renameSync(tmpPath, receiptPath);
38618
+ await fs31.promises.writeFile(tmpPath, JSON.stringify(receipt, null, 2), "utf-8");
38619
+ fs31.renameSync(tmpPath, receiptPath);
38046
38620
  const index = await readReceiptIndex(directory);
38047
38621
  const entry = {
38048
38622
  id: receipt.id,
@@ -38061,9 +38635,9 @@ async function readReceiptById(directory, receiptId) {
38061
38635
  const entry = index.entries.find((e) => e.id === receiptId);
38062
38636
  if (!entry)
38063
38637
  return null;
38064
- const receiptPath = path40.join(resolveReceiptsDir(directory), entry.filename);
38638
+ const receiptPath = path41.join(resolveReceiptsDir(directory), entry.filename);
38065
38639
  try {
38066
- const content = await fs29.promises.readFile(receiptPath, "utf-8");
38640
+ const content = await fs31.promises.readFile(receiptPath, "utf-8");
38067
38641
  return JSON.parse(content);
38068
38642
  } catch {
38069
38643
  return null;
@@ -38074,9 +38648,9 @@ async function readReceiptsByScopeHash(directory, scopeHash) {
38074
38648
  const matching = index.entries.filter((e) => e.scope_hash === scopeHash).sort((a, b) => b.reviewed_at.localeCompare(a.reviewed_at));
38075
38649
  const receipts = [];
38076
38650
  for (const entry of matching) {
38077
- const receiptPath = path40.join(resolveReceiptsDir(directory), entry.filename);
38651
+ const receiptPath = path41.join(resolveReceiptsDir(directory), entry.filename);
38078
38652
  try {
38079
- const content = await fs29.promises.readFile(receiptPath, "utf-8");
38653
+ const content = await fs31.promises.readFile(receiptPath, "utf-8");
38080
38654
  receipts.push(JSON.parse(content));
38081
38655
  } catch {}
38082
38656
  }
@@ -38087,9 +38661,9 @@ async function readAllReceipts(directory) {
38087
38661
  const sorted = [...index.entries].sort((a, b) => b.reviewed_at.localeCompare(a.reviewed_at));
38088
38662
  const receipts = [];
38089
38663
  for (const entry of sorted) {
38090
- const receiptPath = path40.join(resolveReceiptsDir(directory), entry.filename);
38664
+ const receiptPath = path41.join(resolveReceiptsDir(directory), entry.filename);
38091
38665
  try {
38092
- const content = await fs29.promises.readFile(receiptPath, "utf-8");
38666
+ const content = await fs31.promises.readFile(receiptPath, "utf-8");
38093
38667
  receipts.push(JSON.parse(content));
38094
38668
  } catch {}
38095
38669
  }
@@ -38221,15 +38795,15 @@ __export(exports_doc_scan, {
38221
38795
  doc_extract: () => doc_extract
38222
38796
  });
38223
38797
  import * as crypto6 from "crypto";
38224
- import * as fs32 from "fs";
38798
+ import * as fs34 from "fs";
38225
38799
  import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
38226
- import * as path44 from "path";
38800
+ import * as path45 from "path";
38227
38801
  function normalizeSeparators(filePath) {
38228
38802
  return filePath.replace(/\\/g, "/");
38229
38803
  }
38230
38804
  function matchesDocPattern(filePath, patterns) {
38231
38805
  const normalizedPath = normalizeSeparators(filePath);
38232
- const basename6 = path44.basename(filePath);
38806
+ const basename6 = path45.basename(filePath);
38233
38807
  for (const pattern of patterns) {
38234
38808
  if (!pattern.includes("/") && !pattern.includes("\\")) {
38235
38809
  if (basename6 === pattern) {
@@ -38285,7 +38859,7 @@ function stripMarkdown(text) {
38285
38859
  return text.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/^\s*[-*\u2022]\s+/gm, "").replace(/^\s*\d+\.\s+/gm, "").trim();
38286
38860
  }
38287
38861
  async function scanDocIndex(directory) {
38288
- const manifestPath = path44.join(directory, ".swarm", "doc-manifest.json");
38862
+ const manifestPath = path45.join(directory, ".swarm", "doc-manifest.json");
38289
38863
  const defaultPatterns = DocsConfigSchema.parse({}).doc_patterns;
38290
38864
  const extraPatterns = [
38291
38865
  "ARCHITECTURE.md",
@@ -38302,8 +38876,8 @@ async function scanDocIndex(directory) {
38302
38876
  let cacheValid = true;
38303
38877
  for (const file3 of existingManifest.files) {
38304
38878
  try {
38305
- const fullPath = path44.join(directory, file3.path);
38306
- const stat2 = fs32.statSync(fullPath);
38879
+ const fullPath = path45.join(directory, file3.path);
38880
+ const stat2 = fs34.statSync(fullPath);
38307
38881
  if (stat2.mtimeMs > new Date(existingManifest.scanned_at).getTime()) {
38308
38882
  cacheValid = false;
38309
38883
  break;
@@ -38321,7 +38895,7 @@ async function scanDocIndex(directory) {
38321
38895
  const discoveredFiles = [];
38322
38896
  let rawEntries;
38323
38897
  try {
38324
- rawEntries = fs32.readdirSync(directory, { recursive: true });
38898
+ rawEntries = fs34.readdirSync(directory, { recursive: true });
38325
38899
  } catch {
38326
38900
  const manifest2 = {
38327
38901
  schema_version: 1,
@@ -38332,10 +38906,10 @@ async function scanDocIndex(directory) {
38332
38906
  }
38333
38907
  const entries = rawEntries.filter((e) => typeof e === "string");
38334
38908
  for (const entry of entries) {
38335
- const fullPath = path44.join(directory, entry);
38909
+ const fullPath = path45.join(directory, entry);
38336
38910
  let stat2;
38337
38911
  try {
38338
- stat2 = fs32.statSync(fullPath);
38912
+ stat2 = fs34.statSync(fullPath);
38339
38913
  } catch {
38340
38914
  continue;
38341
38915
  }
@@ -38364,11 +38938,11 @@ async function scanDocIndex(directory) {
38364
38938
  }
38365
38939
  let content;
38366
38940
  try {
38367
- content = fs32.readFileSync(fullPath, "utf-8");
38941
+ content = fs34.readFileSync(fullPath, "utf-8");
38368
38942
  } catch {
38369
38943
  continue;
38370
38944
  }
38371
- const { title, summary } = extractTitleAndSummary(content, path44.basename(entry));
38945
+ const { title, summary } = extractTitleAndSummary(content, path45.basename(entry));
38372
38946
  const lineCount = content.split(`
38373
38947
  `).length;
38374
38948
  discoveredFiles.push({
@@ -38394,7 +38968,7 @@ async function scanDocIndex(directory) {
38394
38968
  files: discoveredFiles
38395
38969
  };
38396
38970
  try {
38397
- await mkdir6(path44.dirname(manifestPath), { recursive: true });
38971
+ await mkdir6(path45.dirname(manifestPath), { recursive: true });
38398
38972
  await writeFile5(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
38399
38973
  } catch {}
38400
38974
  return { manifest, cached: false };
@@ -38433,7 +39007,7 @@ function extractConstraintsFromContent(content) {
38433
39007
  return constraints;
38434
39008
  }
38435
39009
  async function extractDocConstraints(directory, taskFiles, taskDescription) {
38436
- const manifestPath = path44.join(directory, ".swarm", "doc-manifest.json");
39010
+ const manifestPath = path45.join(directory, ".swarm", "doc-manifest.json");
38437
39011
  let manifest;
38438
39012
  try {
38439
39013
  const content = await readFile6(manifestPath, "utf-8");
@@ -38459,7 +39033,7 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
38459
39033
  }
38460
39034
  let fullContent;
38461
39035
  try {
38462
- fullContent = await readFile6(path44.join(directory, docFile.path), "utf-8");
39036
+ fullContent = await readFile6(path45.join(directory, docFile.path), "utf-8");
38463
39037
  } catch {
38464
39038
  skippedCount++;
38465
39039
  continue;
@@ -38482,7 +39056,7 @@ async function extractDocConstraints(directory, taskFiles, taskDescription) {
38482
39056
  tier: "swarm",
38483
39057
  lesson: constraint,
38484
39058
  category: "architecture",
38485
- tags: ["doc-scan", path44.basename(docFile.path)],
39059
+ tags: ["doc-scan", path45.basename(docFile.path)],
38486
39060
  scope: "global",
38487
39061
  confidence: 0.5,
38488
39062
  status: "candidate",
@@ -38555,9 +39129,9 @@ var init_doc_scan = __esm(() => {
38555
39129
  }
38556
39130
  } catch {}
38557
39131
  if (force) {
38558
- const manifestPath = path44.join(directory, ".swarm", "doc-manifest.json");
39132
+ const manifestPath = path45.join(directory, ".swarm", "doc-manifest.json");
38559
39133
  try {
38560
- fs32.unlinkSync(manifestPath);
39134
+ fs34.unlinkSync(manifestPath);
38561
39135
  } catch {}
38562
39136
  }
38563
39137
  const { manifest, cached: cached3 } = await scanDocIndex(directory);
@@ -38609,11 +39183,11 @@ __export(exports_curator_drift, {
38609
39183
  readPriorDriftReports: () => readPriorDriftReports,
38610
39184
  buildDriftInjectionText: () => buildDriftInjectionText
38611
39185
  });
38612
- import * as fs35 from "fs";
38613
- import * as path47 from "path";
39186
+ import * as fs37 from "fs";
39187
+ import * as path48 from "path";
38614
39188
  async function readPriorDriftReports(directory) {
38615
- const swarmDir = path47.join(directory, ".swarm");
38616
- const entries = await fs35.promises.readdir(swarmDir).catch(() => null);
39189
+ const swarmDir = path48.join(directory, ".swarm");
39190
+ const entries = await fs37.promises.readdir(swarmDir).catch(() => null);
38617
39191
  if (entries === null)
38618
39192
  return [];
38619
39193
  const reportFiles = entries.filter((name2) => name2.startsWith(DRIFT_REPORT_PREFIX) && name2.endsWith(".json")).sort();
@@ -38639,10 +39213,10 @@ async function readPriorDriftReports(directory) {
38639
39213
  async function writeDriftReport(directory, report) {
38640
39214
  const filename = `${DRIFT_REPORT_PREFIX}${report.phase}.json`;
38641
39215
  const filePath = validateSwarmPath(directory, filename);
38642
- const swarmDir = path47.dirname(filePath);
38643
- await fs35.promises.mkdir(swarmDir, { recursive: true });
39216
+ const swarmDir = path48.dirname(filePath);
39217
+ await fs37.promises.mkdir(swarmDir, { recursive: true });
38644
39218
  try {
38645
- await fs35.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
39219
+ await fs37.promises.writeFile(filePath, JSON.stringify(report, null, 2), "utf-8");
38646
39220
  } catch (err2) {
38647
39221
  throw new Error(`[curator-drift] Failed to write drift report to ${filePath}: ${String(err2)}`);
38648
39222
  }
@@ -40209,8 +40783,8 @@ ${JSON.stringify(symbolNames, null, 2)}`);
40209
40783
  var moduleRtn;
40210
40784
  var Module = moduleArg;
40211
40785
  var readyPromiseResolve, readyPromiseReject;
40212
- var readyPromise = new Promise((resolve20, reject) => {
40213
- readyPromiseResolve = resolve20;
40786
+ var readyPromise = new Promise((resolve21, reject) => {
40787
+ readyPromiseResolve = resolve21;
40214
40788
  readyPromiseReject = reject;
40215
40789
  });
40216
40790
  var ENVIRONMENT_IS_WEB = typeof window == "object";
@@ -40232,11 +40806,11 @@ ${JSON.stringify(symbolNames, null, 2)}`);
40232
40806
  throw toThrow;
40233
40807
  }, "quit_");
40234
40808
  var scriptDirectory = "";
40235
- function locateFile(path57) {
40809
+ function locateFile(path58) {
40236
40810
  if (Module["locateFile"]) {
40237
- return Module["locateFile"](path57, scriptDirectory);
40811
+ return Module["locateFile"](path58, scriptDirectory);
40238
40812
  }
40239
- return scriptDirectory + path57;
40813
+ return scriptDirectory + path58;
40240
40814
  }
40241
40815
  __name(locateFile, "locateFile");
40242
40816
  var readAsync, readBinary;
@@ -40290,13 +40864,13 @@ ${JSON.stringify(symbolNames, null, 2)}`);
40290
40864
  }
40291
40865
  readAsync = /* @__PURE__ */ __name(async (url3) => {
40292
40866
  if (isFileURI(url3)) {
40293
- return new Promise((resolve20, reject) => {
40867
+ return new Promise((resolve21, reject) => {
40294
40868
  var xhr = new XMLHttpRequest;
40295
40869
  xhr.open("GET", url3, true);
40296
40870
  xhr.responseType = "arraybuffer";
40297
40871
  xhr.onload = () => {
40298
40872
  if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
40299
- resolve20(xhr.response);
40873
+ resolve21(xhr.response);
40300
40874
  return;
40301
40875
  }
40302
40876
  reject(xhr.status);
@@ -40516,10 +41090,10 @@ ${JSON.stringify(symbolNames, null, 2)}`);
40516
41090
  __name(receiveInstantiationResult, "receiveInstantiationResult");
40517
41091
  var info2 = getWasmImports();
40518
41092
  if (Module["instantiateWasm"]) {
40519
- return new Promise((resolve20, reject) => {
41093
+ return new Promise((resolve21, reject) => {
40520
41094
  Module["instantiateWasm"](info2, (mod, inst) => {
40521
41095
  receiveInstance(mod, inst);
40522
- resolve20(mod.exports);
41096
+ resolve21(mod.exports);
40523
41097
  });
40524
41098
  });
40525
41099
  }
@@ -41985,13 +42559,13 @@ __export(exports_runtime, {
41985
42559
  getInitializedLanguages: () => getInitializedLanguages,
41986
42560
  clearParserCache: () => clearParserCache
41987
42561
  });
41988
- import * as path57 from "path";
42562
+ import * as path58 from "path";
41989
42563
  import { fileURLToPath as fileURLToPath2 } from "url";
41990
42564
  async function initTreeSitter() {
41991
42565
  if (treeSitterInitialized) {
41992
42566
  return;
41993
42567
  }
41994
- const thisDir = path57.dirname(fileURLToPath2(import.meta.url));
42568
+ const thisDir = path58.dirname(fileURLToPath2(import.meta.url));
41995
42569
  const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
41996
42570
  if (isSource) {
41997
42571
  await Parser.init();
@@ -41999,7 +42573,7 @@ async function initTreeSitter() {
41999
42573
  const grammarsDir = getGrammarsDirAbsolute();
42000
42574
  await Parser.init({
42001
42575
  locateFile(scriptName) {
42002
- return path57.join(grammarsDir, scriptName);
42576
+ return path58.join(grammarsDir, scriptName);
42003
42577
  }
42004
42578
  });
42005
42579
  }
@@ -42020,9 +42594,9 @@ function getWasmFileName(languageId) {
42020
42594
  return `tree-sitter-${sanitized}.wasm`;
42021
42595
  }
42022
42596
  function getGrammarsDirAbsolute() {
42023
- const thisDir = path57.dirname(fileURLToPath2(import.meta.url));
42597
+ const thisDir = path58.dirname(fileURLToPath2(import.meta.url));
42024
42598
  const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/lang");
42025
- return isSource ? path57.join(thisDir, "grammars") : path57.join(thisDir, "lang", "grammars");
42599
+ return isSource ? path58.join(thisDir, "grammars") : path58.join(thisDir, "lang", "grammars");
42026
42600
  }
42027
42601
  async function loadGrammar(languageId) {
42028
42602
  if (typeof languageId !== "string" || languageId.length > 100) {
@@ -42038,9 +42612,9 @@ async function loadGrammar(languageId) {
42038
42612
  await initTreeSitter();
42039
42613
  const parser = new Parser;
42040
42614
  const wasmFileName = getWasmFileName(normalizedId);
42041
- const wasmPath = path57.join(getGrammarsDirAbsolute(), wasmFileName);
42042
- const { existsSync: existsSync35 } = await import("fs");
42043
- if (!existsSync35(wasmPath)) {
42615
+ const wasmPath = path58.join(getGrammarsDirAbsolute(), wasmFileName);
42616
+ const { existsSync: existsSync36 } = await import("fs");
42617
+ if (!existsSync36(wasmPath)) {
42044
42618
  throw new Error(`Grammar file not found for ${languageId}: ${wasmPath}
42045
42619
  Make sure to run 'bun run build' to copy grammar files to dist/lang/grammars/`);
42046
42620
  }
@@ -42073,9 +42647,9 @@ async function isGrammarAvailable(languageId) {
42073
42647
  }
42074
42648
  try {
42075
42649
  const wasmFileName = getWasmFileName(normalizedId);
42076
- const wasmPath = path57.join(getGrammarsDirAbsolute(), wasmFileName);
42077
- const { statSync: statSync14 } = await import("fs");
42078
- statSync14(wasmPath);
42650
+ const wasmPath = path58.join(getGrammarsDirAbsolute(), wasmFileName);
42651
+ const { statSync: statSync15 } = await import("fs");
42652
+ statSync15(wasmPath);
42079
42653
  return true;
42080
42654
  } catch {
42081
42655
  return false;
@@ -42260,467 +42834,7 @@ async function handleArchiveCommand(directory, args2) {
42260
42834
 
42261
42835
  // src/commands/benchmark.ts
42262
42836
  init_manager();
42263
-
42264
- // src/state.ts
42265
- init_constants();
42266
- init_plan_schema();
42267
- init_schema();
42268
- init_telemetry();
42269
- import * as fs5 from "fs/promises";
42270
- import * as path5 from "path";
42271
- var _rehydrationCache = null;
42272
- var swarmState = {
42273
- activeToolCalls: new Map,
42274
- toolAggregates: new Map,
42275
- activeAgent: new Map,
42276
- delegationChains: new Map,
42277
- pendingEvents: 0,
42278
- opencodeClient: null,
42279
- curatorInitAgentNames: [],
42280
- curatorPhaseAgentNames: [],
42281
- lastBudgetPct: 0,
42282
- agentSessions: new Map,
42283
- pendingRehydrations: new Set
42284
- };
42285
- function startAgentSession(sessionId, agentName, staleDurationMs = 7200000, directory) {
42286
- const now = Date.now();
42287
- const staleIds = [];
42288
- for (const [id, session] of swarmState.agentSessions) {
42289
- if (now - session.lastToolCallTime > staleDurationMs) {
42290
- staleIds.push(id);
42291
- }
42292
- }
42293
- for (const id of staleIds) {
42294
- swarmState.agentSessions.delete(id);
42295
- }
42296
- const sessionState = {
42297
- agentName,
42298
- lastToolCallTime: now,
42299
- lastAgentEventTime: now,
42300
- delegationActive: false,
42301
- activeInvocationId: 0,
42302
- lastInvocationIdByAgent: {},
42303
- windows: {},
42304
- lastCompactionHint: 0,
42305
- architectWriteCount: 0,
42306
- lastCoderDelegationTaskId: null,
42307
- currentTaskId: null,
42308
- gateLog: new Map,
42309
- reviewerCallCount: new Map,
42310
- lastGateFailure: null,
42311
- partialGateWarningsIssuedForTask: new Set,
42312
- selfFixAttempted: false,
42313
- selfCodingWarnedAtCount: 0,
42314
- catastrophicPhaseWarnings: new Set,
42315
- lastPhaseCompleteTimestamp: 0,
42316
- lastPhaseCompletePhase: 0,
42317
- phaseAgentsDispatched: new Set,
42318
- lastCompletedPhaseAgentsDispatched: new Set,
42319
- qaSkipCount: 0,
42320
- qaSkipTaskIds: [],
42321
- taskWorkflowStates: new Map,
42322
- lastGateOutcome: null,
42323
- declaredCoderScope: null,
42324
- lastScopeViolation: null,
42325
- scopeViolationDetected: false,
42326
- modifiedFilesThisCoderTask: [],
42327
- turboMode: false,
42328
- model_fallback_index: 0,
42329
- modelFallbackExhausted: false,
42330
- coderRevisions: 0,
42331
- revisionLimitHit: false,
42332
- loopDetectionWindow: [],
42333
- pendingAdvisoryMessages: [],
42334
- sessionRehydratedAt: 0
42335
- };
42336
- swarmState.agentSessions.set(sessionId, sessionState);
42337
- telemetry.sessionStarted(sessionId, agentName);
42338
- swarmState.activeAgent.set(sessionId, agentName);
42339
- applyRehydrationCache(sessionState);
42340
- if (directory) {
42341
- let rehydrationPromise;
42342
- rehydrationPromise = rehydrateSessionFromDisk(directory, sessionState).catch((err2) => {
42343
- console.warn("[state] Rehydration failed:", err2 instanceof Error ? err2.message : String(err2));
42344
- }).finally(() => {
42345
- swarmState.pendingRehydrations.delete(rehydrationPromise);
42346
- });
42347
- swarmState.pendingRehydrations.add(rehydrationPromise);
42348
- }
42349
- }
42350
- function getAgentSession(sessionId) {
42351
- return swarmState.agentSessions.get(sessionId);
42352
- }
42353
- function ensureAgentSession(sessionId, agentName, directory) {
42354
- const now = Date.now();
42355
- let session = swarmState.agentSessions.get(sessionId);
42356
- if (session) {
42357
- if (agentName && agentName !== session.agentName) {
42358
- const oldName = session.agentName;
42359
- session.agentName = agentName;
42360
- telemetry.agentActivated(sessionId, agentName, oldName);
42361
- session.delegationActive = false;
42362
- session.lastAgentEventTime = now;
42363
- if (!session.windows) {
42364
- session.activeInvocationId = 0;
42365
- session.lastInvocationIdByAgent = {};
42366
- session.windows = {};
42367
- }
42368
- }
42369
- if (!session.windows) {
42370
- session.activeInvocationId = 0;
42371
- session.lastInvocationIdByAgent = {};
42372
- session.windows = {};
42373
- }
42374
- if (session.lastCompactionHint === undefined) {
42375
- session.lastCompactionHint = 0;
42376
- }
42377
- if (session.architectWriteCount === undefined) {
42378
- session.architectWriteCount = 0;
42379
- }
42380
- if (session.lastCoderDelegationTaskId === undefined) {
42381
- session.lastCoderDelegationTaskId = null;
42382
- }
42383
- if (session.currentTaskId === undefined) {
42384
- session.currentTaskId = null;
42385
- }
42386
- if (!session.gateLog) {
42387
- session.gateLog = new Map;
42388
- }
42389
- if (!session.reviewerCallCount) {
42390
- session.reviewerCallCount = new Map;
42391
- }
42392
- if (session.lastGateFailure === undefined) {
42393
- session.lastGateFailure = null;
42394
- }
42395
- if (!session.partialGateWarningsIssuedForTask) {
42396
- session.partialGateWarningsIssuedForTask = new Set;
42397
- }
42398
- if (session.selfFixAttempted === undefined) {
42399
- session.selfFixAttempted = false;
42400
- }
42401
- if (session.selfCodingWarnedAtCount === undefined) {
42402
- session.selfCodingWarnedAtCount = 0;
42403
- }
42404
- if (!session.catastrophicPhaseWarnings) {
42405
- session.catastrophicPhaseWarnings = new Set;
42406
- }
42407
- if (session.lastPhaseCompleteTimestamp === undefined) {
42408
- session.lastPhaseCompleteTimestamp = 0;
42409
- }
42410
- if (session.lastPhaseCompletePhase === undefined) {
42411
- session.lastPhaseCompletePhase = 0;
42412
- }
42413
- if (!session.phaseAgentsDispatched) {
42414
- session.phaseAgentsDispatched = new Set;
42415
- }
42416
- if (!session.lastCompletedPhaseAgentsDispatched) {
42417
- session.lastCompletedPhaseAgentsDispatched = new Set;
42418
- }
42419
- if (session.qaSkipCount === undefined) {
42420
- session.qaSkipCount = 0;
42421
- }
42422
- if (!session.qaSkipTaskIds) {
42423
- session.qaSkipTaskIds = [];
42424
- }
42425
- if (!session.taskWorkflowStates) {
42426
- session.taskWorkflowStates = new Map;
42427
- }
42428
- if (session.lastGateOutcome === undefined) {
42429
- session.lastGateOutcome = null;
42430
- }
42431
- if (session.declaredCoderScope === undefined) {
42432
- session.declaredCoderScope = null;
42433
- }
42434
- if (session.lastScopeViolation === undefined) {
42435
- session.lastScopeViolation = null;
42436
- }
42437
- if (session.modifiedFilesThisCoderTask === undefined) {
42438
- session.modifiedFilesThisCoderTask = [];
42439
- }
42440
- if (session.scopeViolationDetected === undefined) {
42441
- session.scopeViolationDetected = false;
42442
- }
42443
- if (session.turboMode === undefined) {
42444
- session.turboMode = false;
42445
- }
42446
- if (session.model_fallback_index === undefined) {
42447
- session.model_fallback_index = 0;
42448
- }
42449
- if (session.modelFallbackExhausted === undefined) {
42450
- session.modelFallbackExhausted = false;
42451
- }
42452
- if (session.loopDetectionWindow === undefined) {
42453
- session.loopDetectionWindow = [];
42454
- }
42455
- if (session.pendingAdvisoryMessages === undefined) {
42456
- session.pendingAdvisoryMessages = [];
42457
- }
42458
- if (session.coderRevisions === undefined) {
42459
- session.coderRevisions = 0;
42460
- }
42461
- if (session.revisionLimitHit === undefined) {
42462
- session.revisionLimitHit = false;
42463
- }
42464
- if (session.sessionRehydratedAt === undefined) {
42465
- session.sessionRehydratedAt = 0;
42466
- }
42467
- session.lastToolCallTime = now;
42468
- return session;
42469
- }
42470
- startAgentSession(sessionId, agentName ?? "unknown", 7200000, directory);
42471
- session = swarmState.agentSessions.get(sessionId);
42472
- if (!session) {
42473
- throw new Error(`Failed to create guardrail session for ${sessionId}`);
42474
- }
42475
- return session;
42476
- }
42477
- function updateAgentEventTime(sessionId) {
42478
- const session = swarmState.agentSessions.get(sessionId);
42479
- if (session) {
42480
- session.lastAgentEventTime = Date.now();
42481
- }
42482
- }
42483
- function beginInvocation(sessionId, agentName) {
42484
- const session = swarmState.agentSessions.get(sessionId);
42485
- if (!session) {
42486
- throw new Error(`Cannot begin invocation: session ${sessionId} does not exist`);
42487
- }
42488
- const stripped = stripKnownSwarmPrefix(agentName);
42489
- if (stripped === ORCHESTRATOR_NAME) {
42490
- return null;
42491
- }
42492
- const lastId = session.lastInvocationIdByAgent[stripped] || 0;
42493
- const newId = lastId + 1;
42494
- session.lastInvocationIdByAgent[stripped] = newId;
42495
- session.activeInvocationId = newId;
42496
- const now = Date.now();
42497
- const window2 = {
42498
- id: newId,
42499
- agentName: stripped,
42500
- startedAtMs: now,
42501
- toolCalls: 0,
42502
- consecutiveErrors: 0,
42503
- hardLimitHit: false,
42504
- lastSuccessTimeMs: now,
42505
- recentToolCalls: [],
42506
- warningIssued: false,
42507
- warningReason: ""
42508
- };
42509
- const key = `${stripped}:${newId}`;
42510
- session.windows[key] = window2;
42511
- pruneOldWindows(sessionId, 24 * 60 * 60 * 1000, 50);
42512
- telemetry.delegationBegin(sessionId, stripped, session.currentTaskId ?? "unknown");
42513
- return window2;
42514
- }
42515
- function getActiveWindow(sessionId) {
42516
- const session = swarmState.agentSessions.get(sessionId);
42517
- if (!session || !session.windows) {
42518
- return;
42519
- }
42520
- const stripped = stripKnownSwarmPrefix(session.agentName);
42521
- const key = `${stripped}:${session.activeInvocationId}`;
42522
- return session.windows[key];
42523
- }
42524
- function pruneOldWindows(sessionId, maxAgeMs = 24 * 60 * 60 * 1000, maxWindows = 50) {
42525
- const session = swarmState.agentSessions.get(sessionId);
42526
- if (!session || !session.windows) {
42527
- return;
42528
- }
42529
- const now = Date.now();
42530
- const entries = Object.entries(session.windows);
42531
- const validByAge = entries.filter(([_, window2]) => now - window2.startedAtMs < maxAgeMs);
42532
- const sorted = validByAge.sort((a, b) => b[1].startedAtMs - a[1].startedAtMs);
42533
- const toKeep = sorted.slice(0, maxWindows);
42534
- session.windows = Object.fromEntries(toKeep);
42535
- }
42536
- function recordPhaseAgentDispatch(sessionId, agentName) {
42537
- const session = swarmState.agentSessions.get(sessionId);
42538
- if (!session) {
42539
- return;
42540
- }
42541
- if (!session.phaseAgentsDispatched) {
42542
- session.phaseAgentsDispatched = new Set;
42543
- }
42544
- const normalizedName = stripKnownSwarmPrefix(agentName);
42545
- session.phaseAgentsDispatched.add(normalizedName);
42546
- }
42547
- function isValidTaskId(taskId) {
42548
- if (taskId === null || taskId === undefined) {
42549
- return false;
42550
- }
42551
- if (typeof taskId !== "string") {
42552
- return false;
42553
- }
42554
- const trimmed = taskId.trim();
42555
- return trimmed.length > 0;
42556
- }
42557
- function advanceTaskState(session, taskId, newState) {
42558
- if (!isValidTaskId(taskId)) {
42559
- return;
42560
- }
42561
- if (!session || !(session.taskWorkflowStates instanceof Map)) {
42562
- throw new Error("INVALID_SESSION: session.taskWorkflowStates must be a Map instance");
42563
- }
42564
- const STATE_ORDER = [
42565
- "idle",
42566
- "coder_delegated",
42567
- "pre_check_passed",
42568
- "reviewer_run",
42569
- "tests_run",
42570
- "complete"
42571
- ];
42572
- const current = session.taskWorkflowStates.get(taskId) ?? "idle";
42573
- const currentIndex = STATE_ORDER.indexOf(current);
42574
- const newIndex = STATE_ORDER.indexOf(newState);
42575
- if (newIndex <= currentIndex) {
42576
- throw new Error(`INVALID_TASK_STATE_TRANSITION: ${taskId} ${current} \u2192 ${newState}`);
42577
- }
42578
- if (newState === "complete" && current !== "tests_run") {
42579
- throw new Error(`INVALID_TASK_STATE_TRANSITION: ${taskId} cannot reach complete from ${current} \u2014 must pass through tests_run first`);
42580
- }
42581
- session.taskWorkflowStates.set(taskId, newState);
42582
- telemetry.taskStateChanged(session.agentName, taskId, newState, current);
42583
- }
42584
- function getTaskState(session, taskId) {
42585
- if (!isValidTaskId(taskId)) {
42586
- return "idle";
42587
- }
42588
- if (!session.taskWorkflowStates) {
42589
- session.taskWorkflowStates = new Map;
42590
- }
42591
- return session.taskWorkflowStates.get(taskId) ?? "idle";
42592
- }
42593
- function planStatusToWorkflowState(status) {
42594
- switch (status) {
42595
- case "in_progress":
42596
- return "coder_delegated";
42597
- case "completed":
42598
- return "complete";
42599
- default:
42600
- return "idle";
42601
- }
42602
- }
42603
- function evidenceToWorkflowState(evidence) {
42604
- const gates = evidence.gates ?? {};
42605
- const requiredGates = evidence.required_gates ?? [];
42606
- if (requiredGates.length > 0) {
42607
- const allPassed = requiredGates.every((gate) => gates[gate] != null);
42608
- if (allPassed) {
42609
- return "complete";
42610
- }
42611
- }
42612
- if (gates.test_engineer != null) {
42613
- return "tests_run";
42614
- }
42615
- if (gates.reviewer != null) {
42616
- return "reviewer_run";
42617
- }
42618
- if (Object.keys(gates).length > 0) {
42619
- return "coder_delegated";
42620
- }
42621
- return "idle";
42622
- }
42623
- async function readPlanFromDisk(directory) {
42624
- try {
42625
- const planPath = path5.join(directory, ".swarm", "plan.json");
42626
- const content = await fs5.readFile(planPath, "utf-8");
42627
- const parsed = JSON.parse(content);
42628
- return PlanSchema.parse(parsed);
42629
- } catch {
42630
- return null;
42631
- }
42632
- }
42633
- async function readGateEvidenceFromDisk(directory) {
42634
- const evidenceMap = new Map;
42635
- try {
42636
- const evidenceDir = path5.join(directory, ".swarm", "evidence");
42637
- const entries = await fs5.readdir(evidenceDir, { withFileTypes: true });
42638
- for (const entry of entries) {
42639
- if (!entry.isFile() || !entry.name.endsWith(".json")) {
42640
- continue;
42641
- }
42642
- const taskId = entry.name.replace(/\.json$/, "");
42643
- if (!/^\d+\.\d+(\.\d+)*$/.test(taskId)) {
42644
- continue;
42645
- }
42646
- try {
42647
- const filePath = path5.join(evidenceDir, entry.name);
42648
- const content = await fs5.readFile(filePath, "utf-8");
42649
- const parsed = JSON.parse(content);
42650
- if (parsed && typeof parsed.taskId === "string" && Array.isArray(parsed.required_gates)) {
42651
- evidenceMap.set(taskId, parsed);
42652
- }
42653
- } catch {}
42654
- }
42655
- } catch {}
42656
- return evidenceMap;
42657
- }
42658
- async function buildRehydrationCache(directory) {
42659
- const planTaskStates = new Map;
42660
- const plan = await readPlanFromDisk(directory);
42661
- if (plan) {
42662
- for (const phase of plan.phases ?? []) {
42663
- for (const task of phase.tasks ?? []) {
42664
- planTaskStates.set(task.id, planStatusToWorkflowState(task.status));
42665
- }
42666
- }
42667
- }
42668
- const evidenceMap = await readGateEvidenceFromDisk(directory);
42669
- _rehydrationCache = { planTaskStates, evidenceMap };
42670
- }
42671
- function applyRehydrationCache(session) {
42672
- if (!_rehydrationCache) {
42673
- return;
42674
- }
42675
- if (!session.taskWorkflowStates) {
42676
- session.taskWorkflowStates = new Map;
42677
- }
42678
- const { planTaskStates, evidenceMap } = _rehydrationCache;
42679
- const STATE_ORDER = [
42680
- "idle",
42681
- "coder_delegated",
42682
- "pre_check_passed",
42683
- "reviewer_run",
42684
- "tests_run",
42685
- "complete"
42686
- ];
42687
- for (const [taskId, planState] of planTaskStates) {
42688
- const existingState = session.taskWorkflowStates.get(taskId);
42689
- const evidence = evidenceMap.get(taskId);
42690
- if (evidence) {
42691
- const derivedState = evidenceToWorkflowState(evidence);
42692
- const existingIndex = existingState ? STATE_ORDER.indexOf(existingState) : -1;
42693
- const derivedIndex = STATE_ORDER.indexOf(derivedState);
42694
- if (derivedIndex > existingIndex) {
42695
- session.taskWorkflowStates.set(taskId, derivedState);
42696
- }
42697
- } else {
42698
- const existingIndex = existingState ? STATE_ORDER.indexOf(existingState) : -1;
42699
- const derivedIndex = STATE_ORDER.indexOf(planState);
42700
- if (derivedIndex > existingIndex) {
42701
- session.taskWorkflowStates.set(taskId, planState);
42702
- }
42703
- }
42704
- }
42705
- }
42706
- async function rehydrateSessionFromDisk(directory, session) {
42707
- await buildRehydrationCache(directory);
42708
- applyRehydrationCache(session);
42709
- }
42710
- function hasActiveTurboMode(sessionID) {
42711
- if (sessionID) {
42712
- const session = swarmState.agentSessions.get(sessionID);
42713
- return session?.turboMode === true;
42714
- }
42715
- for (const [_sessionId, session] of swarmState.agentSessions) {
42716
- if (session.turboMode === true) {
42717
- return true;
42718
- }
42719
- }
42720
- return false;
42721
- }
42722
-
42723
- // src/commands/benchmark.ts
42837
+ init_state();
42724
42838
  init_utils();
42725
42839
  var CI = {
42726
42840
  review_pass_rate: 70,
@@ -44098,9 +44212,10 @@ async function writeCheckpoint(directory) {
44098
44212
 
44099
44213
  // src/session/snapshot-writer.ts
44100
44214
  init_utils2();
44215
+ init_state();
44216
+ init_utils();
44101
44217
  import { mkdirSync as mkdirSync5, renameSync as renameSync5 } from "fs";
44102
44218
  import * as path13 from "path";
44103
- init_utils();
44104
44219
  var _writeInFlight = Promise.resolve();
44105
44220
  function serializeAgentSession(s) {
44106
44221
  const gateLog = {};
@@ -44168,6 +44283,10 @@ function serializeAgentSession(s) {
44168
44283
  modelFallbackExhausted: s.modelFallbackExhausted ?? false,
44169
44284
  coderRevisions: s.coderRevisions ?? 0,
44170
44285
  revisionLimitHit: s.revisionLimitHit ?? false,
44286
+ fullAutoMode: s.fullAutoMode ?? false,
44287
+ fullAutoInteractionCount: s.fullAutoInteractionCount ?? 0,
44288
+ fullAutoDeadlockCount: s.fullAutoDeadlockCount ?? 0,
44289
+ fullAutoLastQuestionHash: s.fullAutoLastQuestionHash ?? null,
44171
44290
  sessionRehydratedAt: s.sessionRehydratedAt ?? 0
44172
44291
  };
44173
44292
  }
@@ -44208,6 +44327,9 @@ async function flushPendingSnapshot(directory) {
44208
44327
  await _writeInFlight;
44209
44328
  }
44210
44329
 
44330
+ // src/commands/close.ts
44331
+ init_state();
44332
+
44211
44333
  // src/tools/write-retro.ts
44212
44334
  init_tool();
44213
44335
  init_evidence_schema();
@@ -47358,6 +47480,7 @@ function formatHandoffMarkdown(data) {
47358
47480
  }
47359
47481
 
47360
47482
  // src/commands/handoff.ts
47483
+ init_state();
47361
47484
  async function handleHandoffCommand(directory, _args) {
47362
47485
  const handoffData = await getHandoffData(directory);
47363
47486
  const markdown = formatHandoffMarkdown(handoffData);
@@ -48781,6 +48904,7 @@ async function handleResetCommand(directory, args2) {
48781
48904
 
48782
48905
  // src/commands/reset-session.ts
48783
48906
  init_utils2();
48907
+ init_state();
48784
48908
  import * as fs21 from "fs";
48785
48909
  import * as path30 from "path";
48786
48910
  async function handleResetSessionCommand(directory, _args) {
@@ -49429,8 +49553,10 @@ No plan content available. Start by creating a .swarm/plan.md file.
49429
49553
  // src/services/status-service.ts
49430
49554
  init_utils2();
49431
49555
  init_manager2();
49556
+ init_state();
49432
49557
 
49433
49558
  // src/services/compaction-service.ts
49559
+ init_state();
49434
49560
  import * as fs23 from "fs";
49435
49561
  import * as path33 from "path";
49436
49562
  function makeInitialState() {
@@ -49820,6 +49946,7 @@ No active swarm plan found. Nothing to sync.`;
49820
49946
  }
49821
49947
 
49822
49948
  // src/commands/turbo.ts
49949
+ init_state();
49823
49950
  async function handleTurboCommand(_directory, args2, sessionID) {
49824
49951
  if (!sessionID || sessionID.trim() === "") {
49825
49952
  return "Error: No active session context. Turbo Mode requires an active session. Use /swarm turbo from within an OpenCode session, or start a session first.";
@@ -50083,8 +50210,6 @@ var ARCHITECT_PROMPT = `You are Architect - orchestrator of a multi-agent swarm.
50083
50210
  Swarm: {{SWARM_ID}}
50084
50211
  Your agents: {{AGENT_PREFIX}}explorer, {{AGENT_PREFIX}}sme, {{AGENT_PREFIX}}coder, {{AGENT_PREFIX}}reviewer, {{AGENT_PREFIX}}test_engineer, {{AGENT_PREFIX}}critic, {{AGENT_PREFIX}}critic_sounding_board, {{AGENT_PREFIX}}docs, {{AGENT_PREFIX}}designer
50085
50212
 
50086
- {{TURBO_MODE_BANNER}}
50087
-
50088
50213
  ## PROJECT CONTEXT
50089
50214
  Session-start priming block. Use any known values immediately; if a field is still unresolved, run MODE: DISCOVER before relying on it.
50090
50215
  Language: {{PROJECT_LANGUAGE}}
@@ -51112,29 +51237,6 @@ ${customAppendPrompt}`;
51112
51237
  prompt = prompt?.replace(/\{\{ADVERSARIAL_TEST_STEP\}\}/g, ` 5m. {{AGENT_PREFIX}}test_engineer - Adversarial tests. FAIL \u2192 coder retry from 5g. Scope: attack vectors only \u2014 malformed inputs, boundary violations, injection attempts.
51113
51238
  \u2192 REQUIRED: Print "testengineer-adversarial: [PASS | FAIL \u2014 details]"`)?.replace(/\{\{ADVERSARIAL_TEST_CHECKLIST\}\}/g, " [GATE] test_engineer-adversarial: PASS / FAIL \u2014 value: ___");
51114
51239
  }
51115
- const TURBO_MODE_BANNER = `## \uD83D\uDE80 TURBO MODE ACTIVE
51116
-
51117
- **Speed optimization enabled for this session.**
51118
-
51119
- While Turbo Mode is active:
51120
- - **Stage A gates** (lint, imports, pre_check_batch) are still REQUIRED for ALL tasks
51121
- - **Tier 3 tasks** (security-sensitive files matching: architect*.ts, delegation*.ts, guardrails*.ts, adversarial*.ts, sanitiz*.ts, auth*, permission*, crypto*, secret*, security) still require FULL review (Stage B)
51122
- - **Tier 0-2 tasks** can skip Stage B (reviewer, test_engineer) to speed up execution
51123
- - **Phase completion gates** (completion-verify and drift verification gate) are automatically bypassed \u2014 phase_complete will succeed without drift verification evidence when turbo is active. Note: turbo bypass is session-scoped; one session's turbo does not affect other sessions.
51124
-
51125
- Classification still determines the pipeline:
51126
- - TIER 0 (metadata): lint + diff only \u2014 no change
51127
- - TIER 1 (docs): Stage A + reviewer \u2014 no change
51128
- - TIER 2 (standard code): Stage A + reviewer + test_engineer \u2014 CAN SKIP Stage B with turboMode
51129
- - TIER 3 (critical): Stage A + 2x reviewer + 2x test_engineer \u2014 Stage B REQUIRED (no turbo bypass)
51130
-
51131
- Do NOT skip Stage A gates. Do NOT skip Stage B for TIER 3.
51132
- `;
51133
- if (hasActiveTurboMode()) {
51134
- prompt = prompt?.replace(/\{\{TURBO_MODE_BANNER\}\}/g, TURBO_MODE_BANNER);
51135
- } else {
51136
- prompt = prompt?.replace(/\{\{TURBO_MODE_BANNER\}\}/g, "");
51137
- }
51138
51240
  return {
51139
51241
  name: "architect",
51140
51242
  description: "Central orchestrator of the development pipeline. Analyzes requests, coordinates SME consultation, manages code generation, and triages QA feedback.",
@@ -51594,6 +51696,90 @@ RULES:
51594
51696
  - Report the first deviation point, not all downstream consequences
51595
51697
  - VERDICT is APPROVED only if ALL tasks are VERIFIED with no DRIFT
51596
51698
  `;
51699
+ var AUTONOMOUS_OVERSIGHT_PROMPT = `## AUTONOMOUS OVERSIGHT MODE
51700
+
51701
+ You are the sole quality gate between the architect and production. There is no human reviewer. Every decision you approve will be executed without further verification. Act accordingly.
51702
+
51703
+ ## CONSTITUTION
51704
+
51705
+ These rules are absolute. You cannot override, relax, or reinterpret them.
51706
+
51707
+ 1. DEFAULT POSTURE IS REJECT. You approve only when you have positive evidence of correctness. Absence of problems is not evidence of quality.
51708
+ 2. CROSS-VERIFY EVERYTHING. Do not trust the architect's summary. Read the actual files, evidence, plan, and test results yourself.
51709
+ 3. NO RUBBER-STAMPING. If you cannot articulate exactly what you verified and why it's correct, your verdict is REJECT.
51710
+ 4. SCOPE CONTAINMENT. If work was done outside the plan scope, REJECT. Scope creep in autonomous mode is a critical failure.
51711
+ 5. EVIDENCE OVER CLAIMS. The architect may claim tests pass, reviews succeeded, or gates cleared. Verify the evidence files exist and contain valid data.
51712
+ 6. ESCALATE UNCERTAINTY. If you are uncertain about a product/design decision (not a technical one), respond with ESCALATE_TO_HUMAN instead of guessing.
51713
+ 7. GATE COMPLETENESS. Every task must have: (a) implementation evidence, (b) review evidence with verdict, (c) test evidence with pass/fail. Missing any = REJECT.
51714
+ 8. REGRESSION AWARENESS. If the architect claims a fix, verify it doesn't break something else. Check for test results beyond the changed files.
51715
+ 9. DEPENDENCY VIGILANCE. Any new dependency must be verified as a real package. Any phantom dependency = CRITICAL REJECT.
51716
+ 10. SECURITY BOUNDARY. Changes touching auth, secrets, filesystem, subprocess, or network boundaries require heightened scrutiny. Missing validation at any trust boundary = REJECT.
51717
+
51718
+ ## VERIFICATION PROTOCOL
51719
+
51720
+ For every decision point, execute the relevant protocol:
51721
+
51722
+ ### Plan Review
51723
+ 1. Read .swarm/plan.md and .swarm/spec.md (if exists)
51724
+ 2. For each task: verify it has a clear objective, target file, and acceptance criteria
51725
+ 3. Check dependency ordering \u2014 no task should depend on a later task's output
51726
+ 4. Check scope containment \u2014 every task maps to a stated requirement
51727
+ 5. Flag any task that touches 6+ files or mixes unrelated concerns
51728
+ VERDICT: APPROVED | NEEDS_REVISION | REJECTED
51729
+
51730
+ ### Task Completion Review
51731
+ 1. Read the evidence bundle for the task
51732
+ 2. Verify review evidence exists with a non-rubber-stamp verdict
51733
+ 3. Verify test evidence exists with PASS status
51734
+ 4. Verify the diff is contained to the stated scope
51735
+ 5. Check for unplanned side effects in other files
51736
+ VERDICT: APPROVED | BLOCKED \u2014 [reason]
51737
+
51738
+ ### Phase Completion Review
51739
+ 1. Verify ALL tasks in the phase are marked completed with evidence
51740
+ 2. Verify retrospective evidence exists with lessons learned
51741
+ 3. Verify drift check evidence exists (if spec.md present)
51742
+ 4. Verify regression sweep results exist
51743
+ 5. Cross-reference: do completed tasks match the plan? Any dropped? Any added?
51744
+ 6. Check: was the reviewer dispatched at least once this phase?
51745
+ VERDICT: APPROVED | BLOCKED \u2014 [missing items]
51746
+
51747
+ ### Question Resolution
51748
+ When the architect asks a question:
51749
+ 1. Determine if this is a TECHNICAL question or a PRODUCT/DESIGN question
51750
+ 2. TECHNICAL: answer it directly using your knowledge of the codebase, plan, and spec
51751
+ 3. PRODUCT/DESIGN: respond with ESCALATE_TO_HUMAN \u2014 you do not make product decisions
51752
+ 4. AMBIGUOUS: ask the architect to rephrase with more context before answering
51753
+ VERDICT: ANSWER | ESCALATE_TO_HUMAN | REPHRASE
51754
+
51755
+ ## SELF-CRITIQUE
51756
+
51757
+ After generating your initial verdict, check yourself:
51758
+ 1. Did you check every item in the protocol, or did you skip steps?
51759
+ 2. If APPROVED: argue against yourself. What could go wrong that you didn't check?
51760
+ 3. If REJECTED: is the rejection grounded in a specific rule number, or is it vague unease?
51761
+ If the self-critique changes your verdict, update it.
51762
+
51763
+ ## ANTI-PATTERNS
51764
+
51765
+ Watch for these architect behaviors \u2014 any detected = immediate REJECT:
51766
+ - Skipping reviewer delegation ("this is a simple change")
51767
+ - Batching multiple tasks into one coder call
51768
+ - Marking tasks complete without evidence
51769
+ - Relaxing test requirements ("tests are flaky, skipping")
51770
+ - Scope expansion ("while we're here, let's also...")
51771
+ - Self-approving ("I verified this myself")
51772
+ - Pressure language ("we need to move fast", "this is blocking")
51773
+
51774
+ ## OUTPUT FORMAT
51775
+
51776
+ Every response MUST use this structure:
51777
+
51778
+ VERDICT: APPROVED | NEEDS_REVISION | REJECTED | BLOCKED | ANSWER | ESCALATE_TO_HUMAN | REPHRASE
51779
+ REASONING: [2-4 sentences \u2014 what you verified and why]
51780
+ EVIDENCE_CHECKED: [list of files/artifacts you read]
51781
+ ANTI_PATTERNS_DETECTED: [list or "none"]
51782
+ ESCALATION_NEEDED: YES | NO`;
51597
51783
  function createCriticAgent(model, customPrompt, customAppendPrompt, role = "plan_critic") {
51598
51784
  let prompt;
51599
51785
  if (customPrompt) {
@@ -51634,6 +51820,25 @@ ${customAppendPrompt}` : rolePrompt;
51634
51820
  }
51635
51821
  };
51636
51822
  }
51823
+ function createCriticAutonomousOversightAgent(model, customAppendPrompt) {
51824
+ const prompt = customAppendPrompt ? `${AUTONOMOUS_OVERSIGHT_PROMPT}
51825
+
51826
+ ${customAppendPrompt}` : AUTONOMOUS_OVERSIGHT_PROMPT;
51827
+ return {
51828
+ name: "critic_oversight",
51829
+ description: "Critic in AUTONOMOUS OVERSIGHT mode \u2014 sole quality gate in full-auto.",
51830
+ config: {
51831
+ model,
51832
+ temperature: 0.1,
51833
+ prompt,
51834
+ tools: {
51835
+ write: false,
51836
+ edit: false,
51837
+ patch: false
51838
+ }
51839
+ }
51840
+ };
51841
+ }
51637
51842
 
51638
51843
  // src/agents/curator-agent.ts
51639
51844
  var ROLE_CONFIG = {
@@ -52624,6 +52829,11 @@ If you call @coder instead of @${swarmId}_coder, the call will FAIL or go to the
52624
52829
  critic.name = prefixName("critic_drift_verifier");
52625
52830
  agents.push(applyOverrides(critic, swarmAgents, swarmPrefix));
52626
52831
  }
52832
+ if (!isAgentDisabled("critic_oversight", swarmAgents, swarmPrefix)) {
52833
+ const critic = createCriticAutonomousOversightAgent(swarmAgents?.critic_oversight?.model ?? getModel("critic"));
52834
+ critic.name = prefixName("critic_oversight");
52835
+ agents.push(applyOverrides(critic, swarmAgents, swarmPrefix));
52836
+ }
52627
52837
  if (!isAgentDisabled("curator_init", swarmAgents, swarmPrefix)) {
52628
52838
  const curatorInitPrompts = getPrompts("curator_init");
52629
52839
  const curatorInit = createCuratorAgent(swarmAgents?.curator_init?.model ?? getModel("explorer"), curatorInitPrompts.prompt, curatorInitPrompts.appendPrompt, "curator_init");
@@ -53065,10 +53275,11 @@ init_constants();
53065
53275
  init_schema();
53066
53276
 
53067
53277
  // src/hooks/agent-activity.ts
53068
- import { renameSync as renameSync9, unlinkSync as unlinkSync4 } from "fs";
53069
- import * as nodePath2 from "path";
53278
+ init_state();
53070
53279
  init_utils();
53071
53280
  init_utils2();
53281
+ import { renameSync as renameSync9, unlinkSync as unlinkSync4 } from "fs";
53282
+ import * as nodePath2 from "path";
53072
53283
  function createAgentActivityHooks(config3, directory) {
53073
53284
  if (config3.hooks?.agent_activity === false) {
53074
53285
  return {
@@ -53722,6 +53933,7 @@ function maskToolOutput(msg, _threshold) {
53722
53933
  return freedTokens;
53723
53934
  }
53724
53935
  // src/hooks/curator-llm-factory.ts
53936
+ init_state();
53725
53937
  function resolveCuratorAgentName(mode, sessionId) {
53726
53938
  const suffix = mode === "init" ? "curator_init" : "curator_phase";
53727
53939
  const registeredNames = mode === "init" ? swarmState.curatorInitAgentNames : swarmState.curatorPhaseAgentNames;
@@ -53881,6 +54093,7 @@ function shouldParallelizeReview(routing) {
53881
54093
  }
53882
54094
 
53883
54095
  // src/hooks/delegation-gate.ts
54096
+ init_state();
53884
54097
  init_telemetry();
53885
54098
 
53886
54099
  // src/hooks/guardrails.ts
@@ -53949,10 +54162,12 @@ function classifyFile(filePath) {
53949
54162
 
53950
54163
  // src/hooks/guardrails.ts
53951
54164
  init_manager2();
54165
+ init_state();
53952
54166
  init_telemetry();
53953
54167
  init_utils();
53954
54168
 
53955
54169
  // src/hooks/loop-detector.ts
54170
+ init_state();
53956
54171
  function hashDelegation(toolName, args2) {
53957
54172
  const targetAgent = typeof args2?.subagent_type === "string" ? args2.subagent_type : "unknown";
53958
54173
  const firstArgKey = args2 != null ? Object.keys(args2)[0] ?? "noargs" : "noargs";
@@ -55797,6 +56012,7 @@ function createDelegationSanitizerHook(directory) {
55797
56012
  // src/hooks/delegation-tracker.ts
55798
56013
  init_constants();
55799
56014
  init_schema();
56015
+ init_state();
55800
56016
  function createDelegationTrackerHook(config3, guardrailsEnabled = true) {
55801
56017
  return async (input, _output) => {
55802
56018
  const now = Date.now();
@@ -55842,6 +56058,562 @@ function createDelegationTrackerHook(config3, guardrailsEnabled = true) {
55842
56058
  }
55843
56059
  };
55844
56060
  }
56061
+ // src/hooks/full-auto-intercept.ts
56062
+ import * as fs30 from "fs";
56063
+ init_schema();
56064
+
56065
+ // src/parallel/file-locks.ts
56066
+ var import_proper_lockfile3 = __toESM(require_proper_lockfile(), 1);
56067
+ import * as fs29 from "fs";
56068
+ import * as path40 from "path";
56069
+ var LOCKS_DIR = ".swarm/locks";
56070
+ var LOCK_TIMEOUT_MS = 5 * 60 * 1000;
56071
+ function getLockFilePath(directory, filePath) {
56072
+ const normalized = path40.resolve(directory, filePath);
56073
+ if (!normalized.startsWith(path40.resolve(directory))) {
56074
+ throw new Error("Invalid file path: path traversal not allowed");
56075
+ }
56076
+ const hash3 = Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
56077
+ return path40.join(directory, LOCKS_DIR, `${hash3}.lock`);
56078
+ }
56079
+ async function tryAcquireLock(directory, filePath, agent, taskId) {
56080
+ const lockPath = getLockFilePath(directory, filePath);
56081
+ const locksDir = path40.dirname(lockPath);
56082
+ if (!fs29.existsSync(locksDir)) {
56083
+ fs29.mkdirSync(locksDir, { recursive: true });
56084
+ }
56085
+ if (!fs29.existsSync(lockPath)) {
56086
+ fs29.writeFileSync(lockPath, "", "utf-8");
56087
+ }
56088
+ let release;
56089
+ try {
56090
+ release = await import_proper_lockfile3.default.lock(lockPath, {
56091
+ stale: LOCK_TIMEOUT_MS,
56092
+ retries: { retries: 0 },
56093
+ realpath: false
56094
+ });
56095
+ } catch (err2) {
56096
+ const code = err2.code;
56097
+ if (code === "ELOCKED" || code === "EEXIST") {
56098
+ return { acquired: false };
56099
+ }
56100
+ throw err2;
56101
+ }
56102
+ const lock = {
56103
+ filePath,
56104
+ agent,
56105
+ taskId,
56106
+ timestamp: new Date().toISOString(),
56107
+ expiresAt: Date.now() + LOCK_TIMEOUT_MS,
56108
+ _release: release
56109
+ };
56110
+ return { acquired: true, lock };
56111
+ }
56112
+
56113
+ // src/hooks/full-auto-intercept.ts
56114
+ init_state();
56115
+ init_telemetry();
56116
+ init_utils2();
56117
+ var END_OF_SENTENCE_QUESTION_PATTERN = /\?\s*$/;
56118
+ var ESCALATION_PATTERNS = [
56119
+ /Ready for Phase (?:\d+|\[?N\+1\]?)\?/i,
56120
+ /escalat/i,
56121
+ /What would you like/i,
56122
+ /Should I proceed/i,
56123
+ /Do you want/i
56124
+ ];
56125
+ var MID_SENTENCE_QUESTION_PATTERNS = [
56126
+ /\b(v\d+\?)/i,
56127
+ /\b(v\d+\.\d+\?)/i,
56128
+ /\bAPI\?/i,
56129
+ /\bOK\?/i,
56130
+ /\b\d+\?\d+/
56131
+ ];
56132
+ function hashString(str) {
56133
+ let hash3 = 5381;
56134
+ for (let i2 = 0;i2 < str.length; i2++) {
56135
+ hash3 = (hash3 << 5) + hash3 + str.charCodeAt(i2);
56136
+ hash3 = hash3 & hash3;
56137
+ }
56138
+ return Math.abs(hash3).toString(36);
56139
+ }
56140
+ function isMidSentenceQuestion(text) {
56141
+ return MID_SENTENCE_QUESTION_PATTERNS.some((pattern) => pattern.test(text));
56142
+ }
56143
+ function resolveOversightAgentName(architectAgentName) {
56144
+ if (!architectAgentName) {
56145
+ return "critic_oversight";
56146
+ }
56147
+ const stripped = stripKnownSwarmPrefix(architectAgentName);
56148
+ if (stripped !== "architect") {
56149
+ return "critic_oversight";
56150
+ }
56151
+ const baseRole = "architect";
56152
+ const lastIndex = architectAgentName.toLowerCase().lastIndexOf(baseRole);
56153
+ if (lastIndex <= 0) {
56154
+ return "critic_oversight";
56155
+ }
56156
+ const prefix = architectAgentName.slice(0, lastIndex);
56157
+ return `${prefix}critic_oversight`;
56158
+ }
56159
+ function detectEscalation(text) {
56160
+ for (const pattern of ESCALATION_PATTERNS) {
56161
+ if (pattern.test(text)) {
56162
+ return "phase_completion";
56163
+ }
56164
+ }
56165
+ if (END_OF_SENTENCE_QUESTION_PATTERN.test(text)) {
56166
+ if (!isMidSentenceQuestion(text)) {
56167
+ return "question";
56168
+ }
56169
+ }
56170
+ return null;
56171
+ }
56172
+ function extractMessageText3(message) {
56173
+ if (!message?.parts)
56174
+ return "";
56175
+ const textParts = message.parts.filter((p) => p?.type === "text" && p.text);
56176
+ return textParts.map((p) => p.text ?? "").join(`
56177
+ `);
56178
+ }
56179
+ function parseCriticResponse(rawResponse) {
56180
+ const result = {
56181
+ verdict: "NEEDS_REVISION",
56182
+ reasoning: "",
56183
+ evidenceChecked: [],
56184
+ antiPatternsDetected: [],
56185
+ escalationNeeded: false,
56186
+ rawResponse
56187
+ };
56188
+ const lines = rawResponse.split(`
56189
+ `);
56190
+ let currentKey = "";
56191
+ let currentValue = "";
56192
+ const commitField = (res, key, value) => {
56193
+ switch (key) {
56194
+ case "VERDICT": {
56195
+ const validVerdicts = [
56196
+ "APPROVED",
56197
+ "NEEDS_REVISION",
56198
+ "REJECTED",
56199
+ "BLOCKED",
56200
+ "ANSWER",
56201
+ "ESCALATE_TO_HUMAN",
56202
+ "REPHRASE"
56203
+ ];
56204
+ const normalized = value.trim().toUpperCase().replace(/[`*]/g, "");
56205
+ if (validVerdicts.includes(normalized)) {
56206
+ res.verdict = normalized;
56207
+ } else {
56208
+ console.warn(`[full-auto-intercept] Unknown verdict '${value}' \u2014 defaulting to NEEDS_REVISION`);
56209
+ res.verdict = "NEEDS_REVISION";
56210
+ }
56211
+ break;
56212
+ }
56213
+ case "REASONING":
56214
+ res.reasoning = value.trim();
56215
+ break;
56216
+ case "EVIDENCE_CHECKED":
56217
+ if (value && value !== "none" && value !== '"none"') {
56218
+ res.evidenceChecked = value.split(",").map((s) => s.trim()).filter(Boolean);
56219
+ }
56220
+ break;
56221
+ case "ANTI_PATTERNS_DETECTED":
56222
+ if (value && value !== "none" && value !== '"none"') {
56223
+ res.antiPatternsDetected = value.split(",").map((s) => s.trim()).filter(Boolean);
56224
+ }
56225
+ break;
56226
+ case "ESCALATION_NEEDED":
56227
+ res.escalationNeeded = value.trim().toUpperCase() === "YES";
56228
+ break;
56229
+ }
56230
+ };
56231
+ for (const line of lines) {
56232
+ const colonIndex = line.indexOf(":");
56233
+ if (colonIndex !== -1) {
56234
+ const key = line.slice(0, colonIndex).trim().toUpperCase();
56235
+ if ([
56236
+ "VERDICT",
56237
+ "REASONING",
56238
+ "EVIDENCE_CHECKED",
56239
+ "ANTI_PATTERNS_DETECTED",
56240
+ "ESCALATION_NEEDED"
56241
+ ].includes(key)) {
56242
+ if (currentKey) {
56243
+ commitField(result, currentKey, currentValue);
56244
+ }
56245
+ currentKey = key;
56246
+ currentValue = line.slice(colonIndex + 1).trim();
56247
+ } else {
56248
+ currentValue += `
56249
+ ${line}`;
56250
+ }
56251
+ } else {
56252
+ if (line.trim()) {
56253
+ currentValue += `
56254
+ ${line}`;
56255
+ }
56256
+ }
56257
+ }
56258
+ if (currentKey) {
56259
+ commitField(result, currentKey, currentValue);
56260
+ }
56261
+ return result;
56262
+ }
56263
+ function escalationTypeToInteractionMode(escalationType) {
56264
+ return escalationType === "phase_completion" ? "phase_completion" : "question_resolution";
56265
+ }
56266
+ async function writeAutoOversightEvent(directory, architectOutput, criticVerdict, criticReasoning, evidenceChecked, interactionCount, deadlockCount, escalationType) {
56267
+ const event = {
56268
+ type: "auto_oversight",
56269
+ timestamp: new Date().toISOString(),
56270
+ interaction_mode: escalationTypeToInteractionMode(escalationType),
56271
+ architect_output: architectOutput,
56272
+ critic_verdict: criticVerdict,
56273
+ critic_reasoning: criticReasoning,
56274
+ evidence_checked: evidenceChecked,
56275
+ interaction_count: interactionCount,
56276
+ deadlock_count: deadlockCount
56277
+ };
56278
+ const lockTaskId = `auto-oversight-${Date.now()}`;
56279
+ const eventsFilePath = "events.jsonl";
56280
+ const dir = directory;
56281
+ let lockResult;
56282
+ try {
56283
+ lockResult = await tryAcquireLock(dir, eventsFilePath, "auto-oversight", lockTaskId);
56284
+ } catch (error93) {
56285
+ console.warn(`[full-auto-intercept] Warning: failed to acquire lock for auto_oversight event: ${error93 instanceof Error ? error93.message : String(error93)}`);
56286
+ }
56287
+ if (!lockResult?.acquired) {
56288
+ console.warn(`[full-auto-intercept] Warning: could not acquire lock for events.jsonl write \u2014 proceeding without lock`);
56289
+ }
56290
+ try {
56291
+ const eventsPath = validateSwarmPath(dir, "events.jsonl");
56292
+ fs30.appendFileSync(eventsPath, `${JSON.stringify(event)}
56293
+ `, "utf-8");
56294
+ } catch (writeError) {
56295
+ console.error(`[full-auto-intercept] Warning: failed to write auto_oversight event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
56296
+ } finally {
56297
+ if (lockResult?.acquired && lockResult.lock._release) {
56298
+ try {
56299
+ await lockResult.lock._release();
56300
+ } catch (releaseError) {
56301
+ console.error(`[full-auto-intercept] Lock release failed:`, releaseError);
56302
+ }
56303
+ }
56304
+ }
56305
+ }
56306
+ function injectVerdictIntoMessages(messages, architectIndex, criticResult, _escalationType, oversightAgentName) {
56307
+ if (criticResult.escalationNeeded || criticResult.verdict === "ESCALATE_TO_HUMAN") {
56308
+ const verdictMessage2 = {
56309
+ info: {
56310
+ role: "assistant",
56311
+ agent: oversightAgentName
56312
+ },
56313
+ parts: [
56314
+ {
56315
+ type: "text",
56316
+ text: `[FULL-AUTO OVERSIGHT \u2014 ESCALATE_TO_HUMAN]
56317
+
56318
+ Critic reasoning: ${criticResult.reasoning}
56319
+
56320
+ This question requires human judgment. The swarm has been paused for human review.`
56321
+ }
56322
+ ]
56323
+ };
56324
+ messages.splice(architectIndex + 1, 0, verdictMessage2);
56325
+ return;
56326
+ }
56327
+ if (criticResult.verdict === "ANSWER") {
56328
+ const verdictMessage2 = {
56329
+ info: {
56330
+ role: "assistant",
56331
+ agent: oversightAgentName
56332
+ },
56333
+ parts: [
56334
+ {
56335
+ type: "text",
56336
+ text: `[FULL-AUTO OVERSIGHT \u2014 ANSWER]
56337
+
56338
+ ${criticResult.reasoning}`
56339
+ }
56340
+ ]
56341
+ };
56342
+ messages.splice(architectIndex + 1, 0, verdictMessage2);
56343
+ return;
56344
+ }
56345
+ const verdictEmoji = criticResult.verdict === "APPROVED" ? "\u2705" : criticResult.verdict === "NEEDS_REVISION" ? "\uD83D\uDD04" : criticResult.verdict === "REJECTED" ? "\u274C" : criticResult.verdict === "BLOCKED" ? "\uD83D\uDEAB" : "\uD83D\uDCAC";
56346
+ const verdictMessage = {
56347
+ info: {
56348
+ role: "assistant",
56349
+ agent: oversightAgentName
56350
+ },
56351
+ parts: [
56352
+ {
56353
+ type: "text",
56354
+ text: `[FULL-AUTO OVERSIGHT] ${verdictEmoji} **${criticResult.verdict}**
56355
+
56356
+ Critic reasoning: ${criticResult.reasoning}`
56357
+ }
56358
+ ]
56359
+ };
56360
+ messages.splice(architectIndex + 1, 0, verdictMessage);
56361
+ }
56362
+ async function dispatchCriticAndWriteEvent(directory, architectOutput, criticContext, criticModel, escalationType, interactionCount, deadlockCount, oversightAgentName) {
56363
+ const client = swarmState.opencodeClient;
56364
+ if (!client) {
56365
+ console.warn("[full-auto-intercept] No opencodeClient \u2014 critic dispatch skipped (fallback to PENDING)");
56366
+ const result = {
56367
+ verdict: "PENDING",
56368
+ reasoning: "No opencodeClient available \u2014 critic dispatch not possible",
56369
+ evidenceChecked: [],
56370
+ antiPatternsDetected: [],
56371
+ escalationNeeded: false,
56372
+ rawResponse: ""
56373
+ };
56374
+ await writeAutoOversightEvent(directory, architectOutput, result.verdict, result.reasoning, result.evidenceChecked, interactionCount, deadlockCount, escalationType);
56375
+ return result;
56376
+ }
56377
+ const oversightAgent = createCriticAutonomousOversightAgent(criticModel, criticContext);
56378
+ console.log(`[full-auto-intercept] Dispatching critic: ${oversightAgent.name} using model ${criticModel}`);
56379
+ let ephemeralSessionId;
56380
+ const cleanup = () => {
56381
+ if (ephemeralSessionId) {
56382
+ const id = ephemeralSessionId;
56383
+ ephemeralSessionId = undefined;
56384
+ client.session.delete({ path: { id } }).catch(() => {});
56385
+ }
56386
+ };
56387
+ let criticResponse = "";
56388
+ try {
56389
+ const createResult = await client.session.create({
56390
+ query: { directory }
56391
+ });
56392
+ if (!createResult.data) {
56393
+ throw new Error(`Failed to create critic session: ${JSON.stringify(createResult.error)}`);
56394
+ }
56395
+ ephemeralSessionId = createResult.data.id;
56396
+ console.log(`[full-auto-intercept] Created ephemeral session: ${ephemeralSessionId}`);
56397
+ const promptResult = await client.session.prompt({
56398
+ path: { id: ephemeralSessionId },
56399
+ body: {
56400
+ agent: oversightAgentName,
56401
+ tools: { write: false, edit: false, patch: false },
56402
+ parts: [{ type: "text", text: criticContext }]
56403
+ }
56404
+ });
56405
+ if (!promptResult.data) {
56406
+ throw new Error(`Critic LLM prompt failed: ${JSON.stringify(promptResult.error)}`);
56407
+ }
56408
+ const textParts = promptResult.data.parts.filter((p) => p.type === "text");
56409
+ criticResponse = textParts.map((p) => p.text).join(`
56410
+ `);
56411
+ console.log(`[full-auto-intercept] Critic response received (${criticResponse.length} chars)`);
56412
+ if (!criticResponse.trim()) {
56413
+ console.warn("[full-auto-intercept] Critic returned empty response \u2014 using fallback verdict");
56414
+ criticResponse = `VERDICT: NEEDS_REVISION
56415
+ REASONING: Critic returned empty response
56416
+ EVIDENCE_CHECKED: none
56417
+ ANTI_PATTERNS_DETECTED: empty_response
56418
+ ESCALATION_NEEDED: NO`;
56419
+ }
56420
+ } finally {
56421
+ cleanup();
56422
+ }
56423
+ let parsed;
56424
+ try {
56425
+ parsed = parseCriticResponse(criticResponse);
56426
+ console.log(`[full-auto-intercept] Critic verdict: ${parsed.verdict} | escalation: ${parsed.escalationNeeded}`);
56427
+ } catch (parseError) {
56428
+ console.error(`[full-auto-intercept] Failed to parse critic response: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
56429
+ parsed = {
56430
+ verdict: "NEEDS_REVISION",
56431
+ reasoning: "Critic response parsing failed \u2014 defaulting to NEEDS_REVISION",
56432
+ evidenceChecked: [],
56433
+ antiPatternsDetected: [],
56434
+ escalationNeeded: false,
56435
+ rawResponse: criticResponse
56436
+ };
56437
+ }
56438
+ try {
56439
+ await writeAutoOversightEvent(directory, architectOutput, parsed.verdict, parsed.reasoning, parsed.evidenceChecked, interactionCount, deadlockCount, escalationType);
56440
+ } catch (writeError) {
56441
+ console.error(`[full-auto-intercept] Failed to write auto_oversight event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
56442
+ }
56443
+ return parsed;
56444
+ }
56445
+ function createFullAutoInterceptHook(config3, directory) {
56446
+ const fullAutoConfig = config3.full_auto ?? {
56447
+ enabled: false,
56448
+ max_interactions_per_phase: 50,
56449
+ deadlock_threshold: 3,
56450
+ escalation_mode: "pause"
56451
+ };
56452
+ if (fullAutoConfig.enabled !== true) {
56453
+ return {
56454
+ messagesTransform: async () => {}
56455
+ };
56456
+ }
56457
+ const deadlockThreshold = fullAutoConfig.deadlock_threshold ?? 3;
56458
+ const maxInteractions = fullAutoConfig.max_interactions_per_phase ?? 50;
56459
+ const escalationMode = fullAutoConfig.escalation_mode ?? "pause";
56460
+ const messagesTransform = async (_input, output) => {
56461
+ const messages = output.messages;
56462
+ if (!messages || messages.length === 0)
56463
+ return;
56464
+ let lastArchitectMessageIndex = -1;
56465
+ for (let i2 = messages.length - 1;i2 >= 0; i2--) {
56466
+ const msg = messages[i2];
56467
+ if (msg?.info?.role === "user") {
56468
+ const agent = msg.info?.agent;
56469
+ const strippedAgent = agent ? stripKnownSwarmPrefix(agent) : undefined;
56470
+ if (!agent || strippedAgent === "architect") {
56471
+ lastArchitectMessageIndex = i2;
56472
+ break;
56473
+ }
56474
+ }
56475
+ }
56476
+ if (lastArchitectMessageIndex === -1)
56477
+ return;
56478
+ const architectMessage = messages[lastArchitectMessageIndex];
56479
+ const architectText = extractMessageText3(architectMessage);
56480
+ if (!architectText)
56481
+ return;
56482
+ const sessionID = architectMessage.info?.sessionID;
56483
+ if (!hasActiveFullAuto(sessionID))
56484
+ return;
56485
+ let session = null;
56486
+ if (sessionID) {
56487
+ const { ensureAgentSession: ensureAgentSession2 } = await Promise.resolve().then(() => (init_state(), exports_state));
56488
+ session = ensureAgentSession2(sessionID);
56489
+ }
56490
+ if (session) {
56491
+ const interactionCount = session.fullAutoInteractionCount ?? 0;
56492
+ if (interactionCount >= maxInteractions) {
56493
+ const escalated = await handleEscalation(directory, "interaction_limit", sessionID, architectText, interactionCount, session.fullAutoDeadlockCount ?? 0, escalationMode);
56494
+ if (escalated)
56495
+ return;
56496
+ }
56497
+ }
56498
+ const escalationType = detectEscalation(architectText);
56499
+ if (!escalationType)
56500
+ return;
56501
+ if (session) {
56502
+ session.fullAutoInteractionCount = (session.fullAutoInteractionCount ?? 0) + 1;
56503
+ }
56504
+ if (escalationType === "question") {
56505
+ const questionHash = hashString(architectText.trim());
56506
+ if (session) {
56507
+ const lastQuestionHash = session.fullAutoLastQuestionHash;
56508
+ if (lastQuestionHash === questionHash) {
56509
+ session.fullAutoDeadlockCount = (session.fullAutoDeadlockCount ?? 0) + 1;
56510
+ console.warn(`[full-auto-intercept] Potential deadlock detected (count: ${session.fullAutoDeadlockCount}/${deadlockThreshold}) \u2014 identical question repeated`);
56511
+ if (session.fullAutoDeadlockCount >= deadlockThreshold) {
56512
+ const escalated = await handleEscalation(directory, "deadlock", sessionID, architectText, session.fullAutoInteractionCount ?? 0, session.fullAutoDeadlockCount, escalationMode);
56513
+ if (escalated)
56514
+ return;
56515
+ }
56516
+ } else {
56517
+ session.fullAutoDeadlockCount = 0;
56518
+ }
56519
+ session.fullAutoLastQuestionHash = questionHash;
56520
+ }
56521
+ }
56522
+ console.log(`[full-auto-intercept] Escalation detected (${escalationType}) \u2014 triggering autonomous oversight`);
56523
+ const criticContext = buildCriticContext(architectText, escalationType);
56524
+ const criticModel = fullAutoConfig.critic_model ?? "claude-sonnet-4-20250514";
56525
+ const oversightAgent = createCriticAutonomousOversightAgent(criticModel, criticContext);
56526
+ const architectAgent = architectMessage.info?.agent;
56527
+ const resolvedOversightAgentName = resolveOversightAgentName(architectAgent);
56528
+ const dispatchAgentName = resolvedOversightAgentName && resolvedOversightAgentName.length > 0 ? resolvedOversightAgentName : "critic_oversight";
56529
+ console.log(`[full-auto-intercept] Created autonomous oversight agent: ${oversightAgent.name} using model ${criticModel} (dispatch as: ${dispatchAgentName})`);
56530
+ const criticResult = await dispatchCriticAndWriteEvent(directory, architectText, criticContext, criticModel, escalationType, session?.fullAutoInteractionCount ?? 0, session?.fullAutoDeadlockCount ?? 0, dispatchAgentName);
56531
+ injectVerdictIntoMessages(messages, lastArchitectMessageIndex, criticResult, escalationType, dispatchAgentName);
56532
+ };
56533
+ return {
56534
+ messagesTransform
56535
+ };
56536
+ }
56537
+ function buildCriticContext(architectOutput, escalationType) {
56538
+ const contextHeader = escalationType === "phase_completion" ? `## ARCHITECT PHASE COMPLETION REQUEST
56539
+
56540
+ The architect has signaled phase completion and is awaiting oversight approval to proceed.` : `## ARCHITECT QUESTION
56541
+
56542
+ The architect has asked a question and is awaiting an autonomous answer or escalation.`;
56543
+ const truncatedOutput = architectOutput.length > 2000 ? architectOutput.slice(0, 2000) + `
56544
+ ... [truncated]` : architectOutput;
56545
+ return `${contextHeader}
56546
+
56547
+ ### ARCHITECT OUTPUT:
56548
+ ${truncatedOutput}
56549
+
56550
+ ### YOUR TASK:
56551
+ Evaluate the architect's output and provide a response. If this is a question, answer it directly if you have sufficient information. If this is a phase completion, verify all tasks are complete and provide APPROVED or NEEDS_REVISION.
56552
+
56553
+ Remember: You are the sole quality gate. Default posture is REJECT unless you have positive evidence of correctness.`;
56554
+ }
56555
+ async function writeEscalationReport(directory, reason, architectOutput, interactionCount, deadlockCount, phase) {
56556
+ try {
56557
+ const reportPath = validateSwarmPath(directory, "escalation-report.md");
56558
+ let currentPhase = phase;
56559
+ if (currentPhase === undefined) {
56560
+ try {
56561
+ const planPath = validateSwarmPath(directory, "plan.json");
56562
+ const planContent = fs30.readFileSync(planPath, "utf-8");
56563
+ const plan = JSON.parse(planContent);
56564
+ const incompletePhases = plan.phases.filter((p) => p.status !== "complete").sort((a, b) => b.id - a.id);
56565
+ currentPhase = incompletePhases[0]?.id;
56566
+ } catch {}
56567
+ }
56568
+ const timestamp = new Date().toISOString();
56569
+ const reasonLabels = {
56570
+ interaction_limit: "Interaction Limit Exceeded",
56571
+ deadlock: "Deadlock Threshold Exceeded",
56572
+ ESCALATE_TO_HUMAN: "Critic Response: ESCALATE_TO_HUMAN"
56573
+ };
56574
+ const reportContent = `# Full-Auto Escalation Report
56575
+
56576
+ ## Timestamp
56577
+ ${timestamp}
56578
+
56579
+ ## Reason for Escalation
56580
+ ${reasonLabels[reason]}
56581
+
56582
+ ## Architect Output That Triggered Escalation
56583
+ \`\`\`
56584
+ ${architectOutput.slice(0, 4000)}
56585
+ ${architectOutput.length > 4000 ? `
56586
+ ... [output truncated]` : ""}
56587
+ \`\`\`
56588
+
56589
+ ## FullAuto State at Time of Escalation
56590
+ - **Interaction Count**: ${interactionCount}
56591
+ - **Deadlock Count**: ${deadlockCount}
56592
+
56593
+ ## Current Phase and Plan Context
56594
+ - **Current Phase**: ${currentPhase !== undefined ? `Phase ${currentPhase}` : "Unknown"}
56595
+ ${currentPhase !== undefined ? `- **Phase Status**: Pending completion` : ""}
56596
+
56597
+ ## Resolution
56598
+ This escalation requires human intervention. The swarm has been paused.
56599
+ Please review the architect's output above and provide guidance.
56600
+ `;
56601
+ fs30.writeFileSync(reportPath, reportContent, "utf-8");
56602
+ console.log(`[full-auto-intercept] Escalation report written to: ${reportPath}`);
56603
+ } catch (error93) {
56604
+ console.error(`[full-auto-intercept] Failed to write escalation report:`, error93 instanceof Error ? error93.message : String(error93));
56605
+ }
56606
+ }
56607
+ async function handleEscalation(directory, reason, sessionID, architectOutput, interactionCount, deadlockCount, escalationMode, phase) {
56608
+ telemetry.autoOversightEscalation(sessionID ?? "unknown", reason, interactionCount, deadlockCount, phase);
56609
+ await writeEscalationReport(directory, reason, architectOutput, interactionCount, deadlockCount, phase);
56610
+ if (escalationMode === "terminate") {
56611
+ console.error(`[full-auto-intercept] ESCALATION (terminate mode) \u2014 reason: ${reason}, session: ${sessionID}`);
56612
+ process.exit(1);
56613
+ }
56614
+ console.warn(`[full-auto-intercept] ESCALATION (pause mode) \u2014 reason: ${reason}, session: ${sessionID}`);
56615
+ return true;
56616
+ }
55845
56617
  // src/hooks/messages-transform.ts
55846
56618
  function consolidateSystemMessages(messages) {
55847
56619
  if (messages.length > 0 && messages[0].role === "system" && messages[0].content !== undefined && typeof messages[0].content === "string" && messages[0].content.trim().length > 0) {
@@ -55910,7 +56682,7 @@ function consolidateSystemMessages(messages) {
55910
56682
  // src/hooks/phase-monitor.ts
55911
56683
  init_schema();
55912
56684
  init_manager2();
55913
- import * as path41 from "path";
56685
+ import * as path42 from "path";
55914
56686
  init_utils2();
55915
56687
  function createPhaseMonitorHook(directory, preflightManager, curatorRunner, delegateFactory) {
55916
56688
  let lastKnownPhase = null;
@@ -55931,9 +56703,9 @@ function createPhaseMonitorHook(directory, preflightManager, curatorRunner, dele
55931
56703
  const llmDelegate = delegateFactory?.(sessionId);
55932
56704
  const initResult = await runner(directory, curatorConfig, llmDelegate);
55933
56705
  if (initResult.briefing) {
55934
- const briefingPath = path41.join(directory, ".swarm", "curator-briefing.md");
56706
+ const briefingPath = path42.join(directory, ".swarm", "curator-briefing.md");
55935
56707
  const { mkdir: mkdir5, writeFile: writeFile5 } = await import("fs/promises");
55936
- await mkdir5(path41.dirname(briefingPath), { recursive: true });
56708
+ await mkdir5(path42.dirname(briefingPath), { recursive: true });
55937
56709
  await writeFile5(briefingPath, initResult.briefing, "utf-8");
55938
56710
  const { buildApprovedReceipt: buildApprovedReceipt2, persistReviewReceipt: persistReviewReceipt2 } = await Promise.resolve().then(() => (init_review_receipt(), exports_review_receipt));
55939
56711
  const initReceipt = buildApprovedReceipt2({
@@ -56066,15 +56838,15 @@ init_schema();
56066
56838
  init_manager();
56067
56839
  init_detector();
56068
56840
  init_manager2();
56069
- import * as fs33 from "fs";
56070
- import * as path45 from "path";
56841
+ import * as fs35 from "fs";
56842
+ import * as path46 from "path";
56071
56843
 
56072
56844
  // src/services/decision-drift-analyzer.ts
56073
56845
  init_utils2();
56074
56846
  init_manager2();
56075
56847
  init_utils();
56076
- import * as fs30 from "fs";
56077
- import * as path42 from "path";
56848
+ import * as fs32 from "fs";
56849
+ import * as path43 from "path";
56078
56850
  var DEFAULT_DRIFT_CONFIG = {
56079
56851
  staleThresholdPhases: 1,
56080
56852
  detectContradictions: true,
@@ -56228,11 +57000,11 @@ async function analyzeDecisionDrift(directory, config3 = {}) {
56228
57000
  currentPhase = legacyPhase;
56229
57001
  }
56230
57002
  }
56231
- const contextPath = path42.join(directory, ".swarm", "context.md");
57003
+ const contextPath = path43.join(directory, ".swarm", "context.md");
56232
57004
  let contextContent = "";
56233
57005
  try {
56234
- if (fs30.existsSync(contextPath)) {
56235
- contextContent = fs30.readFileSync(contextPath, "utf-8");
57006
+ if (fs32.existsSync(contextPath)) {
57007
+ contextContent = fs32.readFileSync(contextPath, "utf-8");
56236
57008
  }
56237
57009
  } catch (error93) {
56238
57010
  log("[DecisionDriftAnalyzer] context file read failed", {
@@ -56351,14 +57123,15 @@ init_preflight_integration();
56351
57123
  init_preflight_service();
56352
57124
 
56353
57125
  // src/hooks/system-enhancer.ts
57126
+ init_state();
56354
57127
  init_telemetry();
56355
57128
  init_utils();
56356
57129
 
56357
57130
  // src/hooks/adversarial-detector.ts
56358
57131
  init_constants();
56359
57132
  init_schema();
56360
- import * as fs31 from "fs/promises";
56361
- import * as path43 from "path";
57133
+ import * as fs33 from "fs/promises";
57134
+ import * as path44 from "path";
56362
57135
  function safeGet(obj, key) {
56363
57136
  if (!obj || !Object.hasOwn(obj, key))
56364
57137
  return;
@@ -56572,10 +57345,10 @@ async function handleDebuggingSpiral(match, taskId, directory) {
56572
57345
  let eventLogged = false;
56573
57346
  let checkpointCreated = false;
56574
57347
  try {
56575
- const swarmDir = path43.join(directory, ".swarm");
56576
- await fs31.mkdir(swarmDir, { recursive: true });
56577
- const eventsPath = path43.join(swarmDir, "events.jsonl");
56578
- await fs31.appendFile(eventsPath, `${formatDebuggingSpiralEvent(match, taskId)}
57348
+ const swarmDir = path44.join(directory, ".swarm");
57349
+ await fs33.mkdir(swarmDir, { recursive: true });
57350
+ const eventsPath = path44.join(swarmDir, "events.jsonl");
57351
+ await fs33.appendFile(eventsPath, `${formatDebuggingSpiralEvent(match, taskId)}
56579
57352
  `);
56580
57353
  eventLogged = true;
56581
57354
  } catch {}
@@ -56986,7 +57759,7 @@ function createSystemEnhancerHook(config3, directory) {
56986
57759
  } catch {}
56987
57760
  try {
56988
57761
  const darkMatterPath = validateSwarmPath(directory, "dark-matter.md");
56989
- if (!fs33.existsSync(darkMatterPath)) {
57762
+ if (!fs35.existsSync(darkMatterPath)) {
56990
57763
  const {
56991
57764
  detectDarkMatter: detectDarkMatter2,
56992
57765
  formatDarkMatterOutput: formatDarkMatterOutput2,
@@ -56998,10 +57771,10 @@ function createSystemEnhancerHook(config3, directory) {
56998
57771
  });
56999
57772
  if (darkMatter && darkMatter.length > 0) {
57000
57773
  const darkMatterReport = formatDarkMatterOutput2(darkMatter);
57001
- await fs33.promises.writeFile(darkMatterPath, darkMatterReport, "utf-8");
57774
+ await fs35.promises.writeFile(darkMatterPath, darkMatterReport, "utf-8");
57002
57775
  warn(`[system-enhancer] Dark matter scan complete: ${darkMatter.length} co-change patterns found`);
57003
57776
  try {
57004
- const projectName = path45.basename(path45.resolve(directory));
57777
+ const projectName = path46.basename(path46.resolve(directory));
57005
57778
  const knowledgeEntries = darkMatterToKnowledgeEntries2(darkMatter, projectName);
57006
57779
  const knowledgePath = resolveSwarmKnowledgePath(directory);
57007
57780
  const existingEntries = await readKnowledge(knowledgePath);
@@ -57065,11 +57838,11 @@ function createSystemEnhancerHook(config3, directory) {
57065
57838
  if (handoffContent) {
57066
57839
  const handoffPath = validateSwarmPath(directory, "handoff.md");
57067
57840
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
57068
- if (fs33.existsSync(consumedPath)) {
57841
+ if (fs35.existsSync(consumedPath)) {
57069
57842
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
57070
- fs33.unlinkSync(consumedPath);
57843
+ fs35.unlinkSync(consumedPath);
57071
57844
  }
57072
- fs33.renameSync(handoffPath, consumedPath);
57845
+ fs35.renameSync(handoffPath, consumedPath);
57073
57846
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
57074
57847
  The previous model's session ended. Here is your starting context:
57075
57848
 
@@ -57195,6 +57968,15 @@ ${handoffBlock}`);
57195
57968
  const activeAgent_retro = swarmState.activeAgent.get(sessionId_retro ?? "");
57196
57969
  const isArchitect2 = !activeAgent_retro || stripKnownSwarmPrefix(activeAgent_retro) === "architect";
57197
57970
  if (isArchitect2) {
57971
+ const sessionIdBanner = _input.sessionID;
57972
+ if (hasActiveTurboMode(sessionIdBanner) || hasActiveFullAuto(sessionIdBanner)) {
57973
+ if (hasActiveTurboMode(sessionIdBanner)) {
57974
+ tryInject(TURBO_MODE_BANNER);
57975
+ }
57976
+ if (hasActiveFullAuto(sessionIdBanner)) {
57977
+ tryInject(FULL_AUTO_BANNER);
57978
+ }
57979
+ }
57198
57980
  try {
57199
57981
  const currentPhaseNum = plan2?.current_phase ?? 1;
57200
57982
  const retroText = await buildRetroInjection(directory, currentPhaseNum, plan2?.title ?? undefined);
@@ -57357,11 +58139,11 @@ ${budgetWarning}`);
57357
58139
  if (handoffContent) {
57358
58140
  const handoffPath = validateSwarmPath(directory, "handoff.md");
57359
58141
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
57360
- if (fs33.existsSync(consumedPath)) {
58142
+ if (fs35.existsSync(consumedPath)) {
57361
58143
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
57362
- fs33.unlinkSync(consumedPath);
58144
+ fs35.unlinkSync(consumedPath);
57363
58145
  }
57364
- fs33.renameSync(handoffPath, consumedPath);
58146
+ fs35.renameSync(handoffPath, consumedPath);
57365
58147
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
57366
58148
  The previous model's session ended. Here is your starting context:
57367
58149
 
@@ -57527,6 +58309,29 @@ ${handoffBlock}`;
57527
58309
  const activeAgent_retro_b = swarmState.activeAgent.get(sessionId_retro_b ?? "");
57528
58310
  const isArchitect_b = !activeAgent_retro_b || stripKnownSwarmPrefix(activeAgent_retro_b) === "architect";
57529
58311
  if (isArchitect_b) {
58312
+ const sessionIdBanner_b = _input.sessionID;
58313
+ if (hasActiveTurboMode(sessionIdBanner_b) || hasActiveFullAuto(sessionIdBanner_b)) {
58314
+ if (hasActiveTurboMode(sessionIdBanner_b)) {
58315
+ candidates.push({
58316
+ id: `candidate-${idCounter++}`,
58317
+ kind: "agent_context",
58318
+ text: TURBO_MODE_BANNER,
58319
+ tokens: estimateTokens(TURBO_MODE_BANNER),
58320
+ priority: 1,
58321
+ metadata: { contentType: "prose" }
58322
+ });
58323
+ }
58324
+ if (hasActiveFullAuto(sessionIdBanner_b)) {
58325
+ candidates.push({
58326
+ id: `candidate-${idCounter++}`,
58327
+ kind: "agent_context",
58328
+ text: FULL_AUTO_BANNER,
58329
+ tokens: estimateTokens(FULL_AUTO_BANNER),
58330
+ priority: 1,
58331
+ metadata: { contentType: "prose" }
58332
+ });
58333
+ }
58334
+ }
57530
58335
  try {
57531
58336
  const currentPhaseNum_b = plan?.current_phase ?? 1;
57532
58337
  const retroText_b = await buildRetroInjection(directory, currentPhaseNum_b, plan?.title ?? undefined);
@@ -58055,6 +58860,7 @@ function createDarkMatterDetectorHook(directory) {
58055
58860
  }
58056
58861
 
58057
58862
  // src/hooks/delegation-ledger.ts
58863
+ init_state();
58058
58864
  var ledgerBySession = new Map;
58059
58865
  var callStartTimes = new Map;
58060
58866
  function createDelegationLedgerHook(config3, _directory, injectAdvisory) {
@@ -58146,14 +58952,14 @@ function isReadTool(toolName) {
58146
58952
  }
58147
58953
 
58148
58954
  // src/hooks/incremental-verify.ts
58149
- import * as fs34 from "fs";
58150
- import * as path46 from "path";
58955
+ import * as fs36 from "fs";
58956
+ import * as path47 from "path";
58151
58957
 
58152
58958
  // src/hooks/spawn-helper.ts
58153
58959
  import * as child_process4 from "child_process";
58154
58960
  var WIN32_CMD_BINARIES = new Set(["npm", "npx", "pnpm", "yarn"]);
58155
58961
  function spawnAsync(command, cwd, timeoutMs) {
58156
- return new Promise((resolve14) => {
58962
+ return new Promise((resolve15) => {
58157
58963
  try {
58158
58964
  const [rawCmd, ...args2] = command;
58159
58965
  const cmd = process.platform === "win32" && WIN32_CMD_BINARIES.has(rawCmd) && !rawCmd.includes(".") ? `${rawCmd}.cmd` : rawCmd;
@@ -58200,24 +59006,24 @@ function spawnAsync(command, cwd, timeoutMs) {
58200
59006
  try {
58201
59007
  proc.kill();
58202
59008
  } catch {}
58203
- resolve14(null);
59009
+ resolve15(null);
58204
59010
  }, timeoutMs);
58205
59011
  proc.on("close", (code) => {
58206
59012
  if (done)
58207
59013
  return;
58208
59014
  done = true;
58209
59015
  clearTimeout(timer);
58210
- resolve14({ exitCode: code ?? 1, stdout, stderr });
59016
+ resolve15({ exitCode: code ?? 1, stdout, stderr });
58211
59017
  });
58212
59018
  proc.on("error", () => {
58213
59019
  if (done)
58214
59020
  return;
58215
59021
  done = true;
58216
59022
  clearTimeout(timer);
58217
- resolve14(null);
59023
+ resolve15(null);
58218
59024
  });
58219
59025
  } catch {
58220
- resolve14(null);
59026
+ resolve15(null);
58221
59027
  }
58222
59028
  });
58223
59029
  }
@@ -58225,21 +59031,21 @@ function spawnAsync(command, cwd, timeoutMs) {
58225
59031
  // src/hooks/incremental-verify.ts
58226
59032
  var emittedSkipAdvisories = new Set;
58227
59033
  function detectPackageManager(projectDir) {
58228
- if (fs34.existsSync(path46.join(projectDir, "bun.lockb")))
59034
+ if (fs36.existsSync(path47.join(projectDir, "bun.lockb")))
58229
59035
  return "bun";
58230
- if (fs34.existsSync(path46.join(projectDir, "pnpm-lock.yaml")))
59036
+ if (fs36.existsSync(path47.join(projectDir, "pnpm-lock.yaml")))
58231
59037
  return "pnpm";
58232
- if (fs34.existsSync(path46.join(projectDir, "yarn.lock")))
59038
+ if (fs36.existsSync(path47.join(projectDir, "yarn.lock")))
58233
59039
  return "yarn";
58234
- if (fs34.existsSync(path46.join(projectDir, "package-lock.json")))
59040
+ if (fs36.existsSync(path47.join(projectDir, "package-lock.json")))
58235
59041
  return "npm";
58236
59042
  return "bun";
58237
59043
  }
58238
59044
  function detectTypecheckCommand(projectDir) {
58239
- const pkgPath = path46.join(projectDir, "package.json");
58240
- if (fs34.existsSync(pkgPath)) {
59045
+ const pkgPath = path47.join(projectDir, "package.json");
59046
+ if (fs36.existsSync(pkgPath)) {
58241
59047
  try {
58242
- const pkg = JSON.parse(fs34.readFileSync(pkgPath, "utf8"));
59048
+ const pkg = JSON.parse(fs36.readFileSync(pkgPath, "utf8"));
58243
59049
  const scripts = pkg.scripts;
58244
59050
  if (scripts?.typecheck) {
58245
59051
  const pm = detectPackageManager(projectDir);
@@ -58253,8 +59059,8 @@ function detectTypecheckCommand(projectDir) {
58253
59059
  ...pkg.dependencies,
58254
59060
  ...pkg.devDependencies
58255
59061
  };
58256
- if (!deps?.typescript && !fs34.existsSync(path46.join(projectDir, "tsconfig.json"))) {}
58257
- const hasTSMarkers = deps?.typescript || fs34.existsSync(path46.join(projectDir, "tsconfig.json"));
59062
+ if (!deps?.typescript && !fs36.existsSync(path47.join(projectDir, "tsconfig.json"))) {}
59063
+ const hasTSMarkers = deps?.typescript || fs36.existsSync(path47.join(projectDir, "tsconfig.json"));
58258
59064
  if (hasTSMarkers) {
58259
59065
  return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
58260
59066
  }
@@ -58262,17 +59068,17 @@ function detectTypecheckCommand(projectDir) {
58262
59068
  return null;
58263
59069
  }
58264
59070
  }
58265
- if (fs34.existsSync(path46.join(projectDir, "go.mod"))) {
59071
+ if (fs36.existsSync(path47.join(projectDir, "go.mod"))) {
58266
59072
  return { command: ["go", "vet", "./..."], language: "go" };
58267
59073
  }
58268
- if (fs34.existsSync(path46.join(projectDir, "Cargo.toml"))) {
59074
+ if (fs36.existsSync(path47.join(projectDir, "Cargo.toml"))) {
58269
59075
  return { command: ["cargo", "check"], language: "rust" };
58270
59076
  }
58271
- if (fs34.existsSync(path46.join(projectDir, "pyproject.toml")) || fs34.existsSync(path46.join(projectDir, "requirements.txt")) || fs34.existsSync(path46.join(projectDir, "setup.py"))) {
59077
+ if (fs36.existsSync(path47.join(projectDir, "pyproject.toml")) || fs36.existsSync(path47.join(projectDir, "requirements.txt")) || fs36.existsSync(path47.join(projectDir, "setup.py"))) {
58272
59078
  return { command: null, language: "python" };
58273
59079
  }
58274
59080
  try {
58275
- const entries = fs34.readdirSync(projectDir);
59081
+ const entries = fs36.readdirSync(projectDir);
58276
59082
  if (entries.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
58277
59083
  return {
58278
59084
  command: ["dotnet", "build", "--no-restore"],
@@ -58606,7 +59412,8 @@ ${freshPreamble}` : `<curator_briefing>${truncatedBriefing}</curator_briefing>`;
58606
59412
  // src/hooks/scope-guard.ts
58607
59413
  init_constants();
58608
59414
  init_schema();
58609
- import * as path48 from "path";
59415
+ init_state();
59416
+ import * as path49 from "path";
58610
59417
  var WRITE_TOOLS = new Set(WRITE_TOOL_NAMES);
58611
59418
  function createScopeGuardHook(config3, directory, injectAdvisory) {
58612
59419
  const enabled = config3.enabled ?? true;
@@ -58658,19 +59465,20 @@ function createScopeGuardHook(config3, directory, injectAdvisory) {
58658
59465
  }
58659
59466
  function isFileInScope(filePath, scopeEntries, directory) {
58660
59467
  const dir = directory ?? process.cwd();
58661
- const resolvedFile = path48.resolve(dir, filePath);
59468
+ const resolvedFile = path49.resolve(dir, filePath);
58662
59469
  return scopeEntries.some((scope) => {
58663
- const resolvedScope = path48.resolve(dir, scope);
59470
+ const resolvedScope = path49.resolve(dir, scope);
58664
59471
  if (resolvedFile === resolvedScope)
58665
59472
  return true;
58666
- const rel = path48.relative(resolvedScope, resolvedFile);
58667
- return rel.length > 0 && !rel.startsWith("..") && !path48.isAbsolute(rel);
59473
+ const rel = path49.relative(resolvedScope, resolvedFile);
59474
+ return rel.length > 0 && !rel.startsWith("..") && !path49.isAbsolute(rel);
58668
59475
  });
58669
59476
  }
58670
59477
 
58671
59478
  // src/hooks/self-review.ts
58672
59479
  init_constants();
58673
59480
  init_schema();
59481
+ init_state();
58674
59482
  function createSelfReviewHook(config3, injectAdvisory) {
58675
59483
  const enabled = config3.enabled ?? true;
58676
59484
  const skipInTurbo = config3.skip_in_turbo ?? true;
@@ -58713,8 +59521,8 @@ function createSelfReviewHook(config3, injectAdvisory) {
58713
59521
  }
58714
59522
 
58715
59523
  // src/hooks/slop-detector.ts
58716
- import * as fs36 from "fs";
58717
- import * as path49 from "path";
59524
+ import * as fs38 from "fs";
59525
+ import * as path50 from "path";
58718
59526
  var WRITE_EDIT_TOOLS = new Set([
58719
59527
  "write",
58720
59528
  "edit",
@@ -58759,12 +59567,12 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
58759
59567
  function walkFiles(dir, exts, deadline) {
58760
59568
  const results = [];
58761
59569
  try {
58762
- for (const entry of fs36.readdirSync(dir, { withFileTypes: true })) {
59570
+ for (const entry of fs38.readdirSync(dir, { withFileTypes: true })) {
58763
59571
  if (deadline !== undefined && Date.now() > deadline)
58764
59572
  break;
58765
59573
  if (entry.isSymbolicLink())
58766
59574
  continue;
58767
- const full = path49.join(dir, entry.name);
59575
+ const full = path50.join(dir, entry.name);
58768
59576
  if (entry.isDirectory()) {
58769
59577
  if (entry.name === "node_modules" || entry.name === ".git")
58770
59578
  continue;
@@ -58779,7 +59587,7 @@ function walkFiles(dir, exts, deadline) {
58779
59587
  return results;
58780
59588
  }
58781
59589
  function checkDeadExports(content, projectDir, startTime) {
58782
- const hasPackageJson = fs36.existsSync(path49.join(projectDir, "package.json"));
59590
+ const hasPackageJson = fs38.existsSync(path50.join(projectDir, "package.json"));
58783
59591
  if (!hasPackageJson)
58784
59592
  return null;
58785
59593
  const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
@@ -58802,7 +59610,7 @@ function checkDeadExports(content, projectDir, startTime) {
58802
59610
  if (found || Date.now() - startTime > 480)
58803
59611
  break;
58804
59612
  try {
58805
- const text = fs36.readFileSync(file3, "utf-8");
59613
+ const text = fs38.readFileSync(file3, "utf-8");
58806
59614
  if (importPattern.test(text))
58807
59615
  found = true;
58808
59616
  importPattern.lastIndex = 0;
@@ -58935,7 +59743,7 @@ Review before proceeding.`;
58935
59743
 
58936
59744
  // src/hooks/steering-consumed.ts
58937
59745
  init_utils2();
58938
- import * as fs37 from "fs";
59746
+ import * as fs39 from "fs";
58939
59747
  function recordSteeringConsumed(directory, directiveId) {
58940
59748
  try {
58941
59749
  const eventsPath = validateSwarmPath(directory, "events.jsonl");
@@ -58944,7 +59752,7 @@ function recordSteeringConsumed(directory, directiveId) {
58944
59752
  directiveId,
58945
59753
  timestamp: new Date().toISOString()
58946
59754
  };
58947
- fs37.appendFileSync(eventsPath, `${JSON.stringify(event)}
59755
+ fs39.appendFileSync(eventsPath, `${JSON.stringify(event)}
58948
59756
  `, "utf-8");
58949
59757
  } catch {}
58950
59758
  }
@@ -58989,6 +59797,7 @@ init_config_doctor();
58989
59797
 
58990
59798
  // src/session/snapshot-reader.ts
58991
59799
  init_utils2();
59800
+ init_state();
58992
59801
  import { renameSync as renameSync13 } from "fs";
58993
59802
  var TRANSIENT_SESSION_FIELDS = [
58994
59803
  { name: "revisionLimitHit", resetValue: false },
@@ -59081,6 +59890,10 @@ function deserializeAgentSession(s) {
59081
59890
  modelFallbackExhausted: s.modelFallbackExhausted ?? false,
59082
59891
  coderRevisions: s.coderRevisions ?? 0,
59083
59892
  revisionLimitHit: s.revisionLimitHit ?? false,
59893
+ fullAutoMode: s.fullAutoMode ?? false,
59894
+ fullAutoInteractionCount: s.fullAutoInteractionCount ?? 0,
59895
+ fullAutoDeadlockCount: s.fullAutoDeadlockCount ?? 0,
59896
+ fullAutoLastQuestionHash: s.fullAutoLastQuestionHash ?? null,
59084
59897
  sessionRehydratedAt: s.sessionRehydratedAt ?? 0
59085
59898
  };
59086
59899
  }
@@ -59176,19 +59989,20 @@ async function loadSnapshot(directory) {
59176
59989
  }
59177
59990
 
59178
59991
  // src/index.ts
59992
+ init_state();
59179
59993
  init_telemetry();
59180
59994
 
59181
59995
  // src/tools/batch-symbols.ts
59182
59996
  init_tool();
59183
59997
  init_create_tool();
59184
- import * as fs39 from "fs";
59185
- import * as path51 from "path";
59998
+ import * as fs41 from "fs";
59999
+ import * as path52 from "path";
59186
60000
 
59187
60001
  // src/tools/symbols.ts
59188
60002
  init_tool();
59189
60003
  init_create_tool();
59190
- import * as fs38 from "fs";
59191
- import * as path50 from "path";
60004
+ import * as fs40 from "fs";
60005
+ import * as path51 from "path";
59192
60006
  var MAX_FILE_SIZE_BYTES2 = 1024 * 1024;
59193
60007
  var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
59194
60008
  function containsWindowsAttacks(str) {
@@ -59205,11 +60019,11 @@ function containsWindowsAttacks(str) {
59205
60019
  }
59206
60020
  function isPathInWorkspace(filePath, workspace) {
59207
60021
  try {
59208
- const resolvedPath = path50.resolve(workspace, filePath);
59209
- const realWorkspace = fs38.realpathSync(workspace);
59210
- const realResolvedPath = fs38.realpathSync(resolvedPath);
59211
- const relativePath = path50.relative(realWorkspace, realResolvedPath);
59212
- if (relativePath.startsWith("..") || path50.isAbsolute(relativePath)) {
60022
+ const resolvedPath = path51.resolve(workspace, filePath);
60023
+ const realWorkspace = fs40.realpathSync(workspace);
60024
+ const realResolvedPath = fs40.realpathSync(resolvedPath);
60025
+ const relativePath = path51.relative(realWorkspace, realResolvedPath);
60026
+ if (relativePath.startsWith("..") || path51.isAbsolute(relativePath)) {
59213
60027
  return false;
59214
60028
  }
59215
60029
  return true;
@@ -59221,17 +60035,17 @@ function validatePathForRead(filePath, workspace) {
59221
60035
  return isPathInWorkspace(filePath, workspace);
59222
60036
  }
59223
60037
  function extractTSSymbols(filePath, cwd) {
59224
- const fullPath = path50.join(cwd, filePath);
60038
+ const fullPath = path51.join(cwd, filePath);
59225
60039
  if (!validatePathForRead(fullPath, cwd)) {
59226
60040
  return [];
59227
60041
  }
59228
60042
  let content;
59229
60043
  try {
59230
- const stats = fs38.statSync(fullPath);
60044
+ const stats = fs40.statSync(fullPath);
59231
60045
  if (stats.size > MAX_FILE_SIZE_BYTES2) {
59232
60046
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES2})`);
59233
60047
  }
59234
- content = fs38.readFileSync(fullPath, "utf-8");
60048
+ content = fs40.readFileSync(fullPath, "utf-8");
59235
60049
  } catch {
59236
60050
  return [];
59237
60051
  }
@@ -59373,17 +60187,17 @@ function extractTSSymbols(filePath, cwd) {
59373
60187
  });
59374
60188
  }
59375
60189
  function extractPythonSymbols(filePath, cwd) {
59376
- const fullPath = path50.join(cwd, filePath);
60190
+ const fullPath = path51.join(cwd, filePath);
59377
60191
  if (!validatePathForRead(fullPath, cwd)) {
59378
60192
  return [];
59379
60193
  }
59380
60194
  let content;
59381
60195
  try {
59382
- const stats = fs38.statSync(fullPath);
60196
+ const stats = fs40.statSync(fullPath);
59383
60197
  if (stats.size > MAX_FILE_SIZE_BYTES2) {
59384
60198
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES2})`);
59385
60199
  }
59386
- content = fs38.readFileSync(fullPath, "utf-8");
60200
+ content = fs40.readFileSync(fullPath, "utf-8");
59387
60201
  } catch {
59388
60202
  return [];
59389
60203
  }
@@ -59456,7 +60270,7 @@ var symbols = createSwarmTool({
59456
60270
  }, null, 2);
59457
60271
  }
59458
60272
  const cwd = directory;
59459
- const ext = path50.extname(file3);
60273
+ const ext = path51.extname(file3);
59460
60274
  if (containsControlChars(file3)) {
59461
60275
  return JSON.stringify({
59462
60276
  file: file3,
@@ -59532,14 +60346,14 @@ function containsWindowsAttacks2(str) {
59532
60346
  }
59533
60347
  function isPathInWorkspace2(filePath, workspace) {
59534
60348
  try {
59535
- const resolvedPath = path51.resolve(workspace, filePath);
59536
- if (!fs39.existsSync(resolvedPath)) {
60349
+ const resolvedPath = path52.resolve(workspace, filePath);
60350
+ if (!fs41.existsSync(resolvedPath)) {
59537
60351
  return true;
59538
60352
  }
59539
- const realWorkspace = fs39.realpathSync(workspace);
59540
- const realResolvedPath = fs39.realpathSync(resolvedPath);
59541
- const relativePath = path51.relative(realWorkspace, realResolvedPath);
59542
- if (relativePath.startsWith("..") || path51.isAbsolute(relativePath)) {
60353
+ const realWorkspace = fs41.realpathSync(workspace);
60354
+ const realResolvedPath = fs41.realpathSync(resolvedPath);
60355
+ const relativePath = path52.relative(realWorkspace, realResolvedPath);
60356
+ if (relativePath.startsWith("..") || path52.isAbsolute(relativePath)) {
59543
60357
  return false;
59544
60358
  }
59545
60359
  return true;
@@ -59548,7 +60362,7 @@ function isPathInWorkspace2(filePath, workspace) {
59548
60362
  }
59549
60363
  }
59550
60364
  function processFile(file3, cwd, exportedOnly) {
59551
- const ext = path51.extname(file3);
60365
+ const ext = path52.extname(file3);
59552
60366
  if (containsControlChars(file3)) {
59553
60367
  return {
59554
60368
  file: file3,
@@ -59581,8 +60395,8 @@ function processFile(file3, cwd, exportedOnly) {
59581
60395
  errorType: "path-outside-workspace"
59582
60396
  };
59583
60397
  }
59584
- const fullPath = path51.join(cwd, file3);
59585
- if (!fs39.existsSync(fullPath)) {
60398
+ const fullPath = path52.join(cwd, file3);
60399
+ if (!fs41.existsSync(fullPath)) {
59586
60400
  return {
59587
60401
  file: file3,
59588
60402
  success: false,
@@ -59613,14 +60427,14 @@ function processFile(file3, cwd, exportedOnly) {
59613
60427
  }
59614
60428
  let isEmptyFile = false;
59615
60429
  try {
59616
- const stats = fs39.statSync(fullPath);
60430
+ const stats = fs41.statSync(fullPath);
59617
60431
  if (stats.size === 0) {
59618
60432
  isEmptyFile = true;
59619
60433
  }
59620
60434
  } catch {}
59621
60435
  if (syms.length === 0) {
59622
60436
  try {
59623
- const content = fs39.readFileSync(fullPath, "utf-8");
60437
+ const content = fs41.readFileSync(fullPath, "utf-8");
59624
60438
  if (content.trim().length === 0) {
59625
60439
  isEmptyFile = true;
59626
60440
  }
@@ -59871,8 +60685,8 @@ init_dist();
59871
60685
  init_manager();
59872
60686
  init_create_tool();
59873
60687
  init_resolve_working_directory();
59874
- import * as fs40 from "fs";
59875
- import * as path52 from "path";
60688
+ import * as fs42 from "fs";
60689
+ import * as path53 from "path";
59876
60690
  var EVIDENCE_DIR = ".swarm/evidence";
59877
60691
  var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
59878
60692
  function isValidTaskId3(taskId) {
@@ -59889,18 +60703,18 @@ function isValidTaskId3(taskId) {
59889
60703
  return TASK_ID_PATTERN2.test(taskId);
59890
60704
  }
59891
60705
  function isPathWithinSwarm(filePath, workspaceRoot) {
59892
- const normalizedWorkspace = path52.resolve(workspaceRoot);
59893
- const swarmPath = path52.join(normalizedWorkspace, ".swarm", "evidence");
59894
- const normalizedPath = path52.resolve(filePath);
60706
+ const normalizedWorkspace = path53.resolve(workspaceRoot);
60707
+ const swarmPath = path53.join(normalizedWorkspace, ".swarm", "evidence");
60708
+ const normalizedPath = path53.resolve(filePath);
59895
60709
  return normalizedPath.startsWith(swarmPath);
59896
60710
  }
59897
60711
  function readEvidenceFile(evidencePath) {
59898
- if (!fs40.existsSync(evidencePath)) {
60712
+ if (!fs42.existsSync(evidencePath)) {
59899
60713
  return null;
59900
60714
  }
59901
60715
  let content;
59902
60716
  try {
59903
- content = fs40.readFileSync(evidencePath, "utf-8");
60717
+ content = fs42.readFileSync(evidencePath, "utf-8");
59904
60718
  } catch {
59905
60719
  return null;
59906
60720
  }
@@ -59972,7 +60786,7 @@ var check_gate_status = createSwarmTool({
59972
60786
  };
59973
60787
  return JSON.stringify(errorResult, null, 2);
59974
60788
  }
59975
- const evidencePath = path52.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
60789
+ const evidencePath = path53.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
59976
60790
  if (!isPathWithinSwarm(evidencePath, directory)) {
59977
60791
  const errorResult = {
59978
60792
  taskId: taskIdInput,
@@ -60065,10 +60879,11 @@ init_co_change_analyzer();
60065
60879
  // src/tools/completion-verify.ts
60066
60880
  init_dist();
60067
60881
  init_utils2();
60068
- import * as fs41 from "fs";
60069
- import * as path53 from "path";
60882
+ init_state();
60070
60883
  init_create_tool();
60071
60884
  init_resolve_working_directory();
60885
+ import * as fs43 from "fs";
60886
+ import * as path54 from "path";
60072
60887
  function extractMatches(regex, text) {
60073
60888
  return Array.from(text.matchAll(regex));
60074
60889
  }
@@ -60162,7 +60977,7 @@ async function executeCompletionVerify(args2, directory) {
60162
60977
  let plan;
60163
60978
  try {
60164
60979
  const planPath = validateSwarmPath(directory, "plan.json");
60165
- const planRaw = fs41.readFileSync(planPath, "utf-8");
60980
+ const planRaw = fs43.readFileSync(planPath, "utf-8");
60166
60981
  plan = JSON.parse(planRaw);
60167
60982
  } catch {
60168
60983
  const result2 = {
@@ -60220,10 +61035,10 @@ async function executeCompletionVerify(args2, directory) {
60220
61035
  let hasFileReadFailure = false;
60221
61036
  for (const filePath of fileTargets) {
60222
61037
  const normalizedPath = filePath.replace(/\\/g, "/");
60223
- const resolvedPath = path53.resolve(directory, normalizedPath);
60224
- const projectRoot = path53.resolve(directory);
60225
- const relative9 = path53.relative(projectRoot, resolvedPath);
60226
- const withinProject = relative9 === "" || !relative9.startsWith("..") && !path53.isAbsolute(relative9);
61038
+ const resolvedPath = path54.resolve(directory, normalizedPath);
61039
+ const projectRoot = path54.resolve(directory);
61040
+ const relative9 = path54.relative(projectRoot, resolvedPath);
61041
+ const withinProject = relative9 === "" || !relative9.startsWith("..") && !path54.isAbsolute(relative9);
60227
61042
  if (!withinProject) {
60228
61043
  blockedTasks.push({
60229
61044
  task_id: task.id,
@@ -60236,7 +61051,7 @@ async function executeCompletionVerify(args2, directory) {
60236
61051
  }
60237
61052
  let fileContent;
60238
61053
  try {
60239
- fileContent = fs41.readFileSync(resolvedPath, "utf-8");
61054
+ fileContent = fs43.readFileSync(resolvedPath, "utf-8");
60240
61055
  } catch {
60241
61056
  blockedTasks.push({
60242
61057
  task_id: task.id,
@@ -60278,9 +61093,9 @@ async function executeCompletionVerify(args2, directory) {
60278
61093
  blockedTasks
60279
61094
  };
60280
61095
  try {
60281
- const evidenceDir = path53.join(directory, ".swarm", "evidence", `${phase}`);
60282
- const evidencePath = path53.join(evidenceDir, "completion-verify.json");
60283
- fs41.mkdirSync(evidenceDir, { recursive: true });
61096
+ const evidenceDir = path54.join(directory, ".swarm", "evidence", `${phase}`);
61097
+ const evidencePath = path54.join(evidenceDir, "completion-verify.json");
61098
+ fs43.mkdirSync(evidenceDir, { recursive: true });
60284
61099
  const evidenceBundle = {
60285
61100
  schema_version: "1.0.0",
60286
61101
  task_id: "completion-verify",
@@ -60301,7 +61116,7 @@ async function executeCompletionVerify(args2, directory) {
60301
61116
  }
60302
61117
  ]
60303
61118
  };
60304
- fs41.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
61119
+ fs43.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
60305
61120
  } catch {}
60306
61121
  return JSON.stringify(result, null, 2);
60307
61122
  }
@@ -60355,12 +61170,12 @@ var completion_verify = createSwarmTool({
60355
61170
  });
60356
61171
  // src/tools/complexity-hotspots.ts
60357
61172
  init_dist();
60358
- import * as fs43 from "fs";
60359
- import * as path55 from "path";
61173
+ import * as fs45 from "fs";
61174
+ import * as path56 from "path";
60360
61175
 
60361
61176
  // src/quality/metrics.ts
60362
- import * as fs42 from "fs";
60363
- import * as path54 from "path";
61177
+ import * as fs44 from "fs";
61178
+ import * as path55 from "path";
60364
61179
  var MAX_FILE_SIZE_BYTES3 = 256 * 1024;
60365
61180
  var MIN_DUPLICATION_LINES = 10;
60366
61181
  function estimateCyclomaticComplexity(content) {
@@ -60398,11 +61213,11 @@ function estimateCyclomaticComplexity(content) {
60398
61213
  }
60399
61214
  function getComplexityForFile(filePath) {
60400
61215
  try {
60401
- const stat2 = fs42.statSync(filePath);
61216
+ const stat2 = fs44.statSync(filePath);
60402
61217
  if (stat2.size > MAX_FILE_SIZE_BYTES3) {
60403
61218
  return null;
60404
61219
  }
60405
- const content = fs42.readFileSync(filePath, "utf-8");
61220
+ const content = fs44.readFileSync(filePath, "utf-8");
60406
61221
  return estimateCyclomaticComplexity(content);
60407
61222
  } catch {
60408
61223
  return null;
@@ -60412,8 +61227,8 @@ async function computeComplexityDelta(files, workingDir) {
60412
61227
  let totalComplexity = 0;
60413
61228
  const analyzedFiles = [];
60414
61229
  for (const file3 of files) {
60415
- const fullPath = path54.isAbsolute(file3) ? file3 : path54.join(workingDir, file3);
60416
- if (!fs42.existsSync(fullPath)) {
61230
+ const fullPath = path55.isAbsolute(file3) ? file3 : path55.join(workingDir, file3);
61231
+ if (!fs44.existsSync(fullPath)) {
60417
61232
  continue;
60418
61233
  }
60419
61234
  const complexity = getComplexityForFile(fullPath);
@@ -60534,8 +61349,8 @@ function countGoExports(content) {
60534
61349
  }
60535
61350
  function getExportCountForFile(filePath) {
60536
61351
  try {
60537
- const content = fs42.readFileSync(filePath, "utf-8");
60538
- const ext = path54.extname(filePath).toLowerCase();
61352
+ const content = fs44.readFileSync(filePath, "utf-8");
61353
+ const ext = path55.extname(filePath).toLowerCase();
60539
61354
  switch (ext) {
60540
61355
  case ".ts":
60541
61356
  case ".tsx":
@@ -60561,8 +61376,8 @@ async function computePublicApiDelta(files, workingDir) {
60561
61376
  let totalExports = 0;
60562
61377
  const analyzedFiles = [];
60563
61378
  for (const file3 of files) {
60564
- const fullPath = path54.isAbsolute(file3) ? file3 : path54.join(workingDir, file3);
60565
- if (!fs42.existsSync(fullPath)) {
61379
+ const fullPath = path55.isAbsolute(file3) ? file3 : path55.join(workingDir, file3);
61380
+ if (!fs44.existsSync(fullPath)) {
60566
61381
  continue;
60567
61382
  }
60568
61383
  const exports = getExportCountForFile(fullPath);
@@ -60595,16 +61410,16 @@ async function computeDuplicationRatio(files, workingDir) {
60595
61410
  let duplicateLines = 0;
60596
61411
  const analyzedFiles = [];
60597
61412
  for (const file3 of files) {
60598
- const fullPath = path54.isAbsolute(file3) ? file3 : path54.join(workingDir, file3);
60599
- if (!fs42.existsSync(fullPath)) {
61413
+ const fullPath = path55.isAbsolute(file3) ? file3 : path55.join(workingDir, file3);
61414
+ if (!fs44.existsSync(fullPath)) {
60600
61415
  continue;
60601
61416
  }
60602
61417
  try {
60603
- const stat2 = fs42.statSync(fullPath);
61418
+ const stat2 = fs44.statSync(fullPath);
60604
61419
  if (stat2.size > MAX_FILE_SIZE_BYTES3) {
60605
61420
  continue;
60606
61421
  }
60607
- const content = fs42.readFileSync(fullPath, "utf-8");
61422
+ const content = fs44.readFileSync(fullPath, "utf-8");
60608
61423
  const lines = content.split(`
60609
61424
  `).filter((line) => line.trim().length > 0);
60610
61425
  if (lines.length < MIN_DUPLICATION_LINES) {
@@ -60628,8 +61443,8 @@ function countCodeLines(content) {
60628
61443
  return lines.length;
60629
61444
  }
60630
61445
  function isTestFile(filePath) {
60631
- const basename8 = path54.basename(filePath);
60632
- const _ext = path54.extname(filePath).toLowerCase();
61446
+ const basename8 = path55.basename(filePath);
61447
+ const _ext = path55.extname(filePath).toLowerCase();
60633
61448
  const testPatterns = [
60634
61449
  ".test.",
60635
61450
  ".spec.",
@@ -60710,8 +61525,8 @@ function matchGlobSegment(globSegments, pathSegments) {
60710
61525
  }
60711
61526
  return gIndex === globSegments.length && pIndex === pathSegments.length;
60712
61527
  }
60713
- function matchesGlobSegment(path55, glob) {
60714
- const normalizedPath = path55.replace(/\\/g, "/");
61528
+ function matchesGlobSegment(path56, glob) {
61529
+ const normalizedPath = path56.replace(/\\/g, "/");
60715
61530
  const normalizedGlob = glob.replace(/\\/g, "/");
60716
61531
  if (normalizedPath.includes("//")) {
60717
61532
  return false;
@@ -60742,8 +61557,8 @@ function simpleGlobToRegex2(glob) {
60742
61557
  function hasGlobstar(glob) {
60743
61558
  return glob.includes("**");
60744
61559
  }
60745
- function globMatches(path55, glob) {
60746
- const normalizedPath = path55.replace(/\\/g, "/");
61560
+ function globMatches(path56, glob) {
61561
+ const normalizedPath = path56.replace(/\\/g, "/");
60747
61562
  if (!glob || glob === "") {
60748
61563
  if (normalizedPath.includes("//")) {
60749
61564
  return false;
@@ -60779,31 +61594,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
60779
61594
  async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
60780
61595
  let testLines = 0;
60781
61596
  let codeLines = 0;
60782
- const srcDir = path54.join(workingDir, "src");
60783
- if (fs42.existsSync(srcDir)) {
61597
+ const srcDir = path55.join(workingDir, "src");
61598
+ if (fs44.existsSync(srcDir)) {
60784
61599
  await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
60785
61600
  codeLines += lines;
60786
61601
  });
60787
61602
  }
60788
61603
  const possibleSrcDirs = ["lib", "app", "source", "core"];
60789
61604
  for (const dir of possibleSrcDirs) {
60790
- const dirPath = path54.join(workingDir, dir);
60791
- if (fs42.existsSync(dirPath)) {
61605
+ const dirPath = path55.join(workingDir, dir);
61606
+ if (fs44.existsSync(dirPath)) {
60792
61607
  await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
60793
61608
  codeLines += lines;
60794
61609
  });
60795
61610
  }
60796
61611
  }
60797
- const testsDir = path54.join(workingDir, "tests");
60798
- if (fs42.existsSync(testsDir)) {
61612
+ const testsDir = path55.join(workingDir, "tests");
61613
+ if (fs44.existsSync(testsDir)) {
60799
61614
  await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
60800
61615
  testLines += lines;
60801
61616
  });
60802
61617
  }
60803
61618
  const possibleTestDirs = ["test", "__tests__", "specs"];
60804
61619
  for (const dir of possibleTestDirs) {
60805
- const dirPath = path54.join(workingDir, dir);
60806
- if (fs42.existsSync(dirPath) && dirPath !== testsDir) {
61620
+ const dirPath = path55.join(workingDir, dir);
61621
+ if (fs44.existsSync(dirPath) && dirPath !== testsDir) {
60807
61622
  await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
60808
61623
  testLines += lines;
60809
61624
  });
@@ -60815,9 +61630,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
60815
61630
  }
60816
61631
  async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
60817
61632
  try {
60818
- const entries = fs42.readdirSync(dirPath, { withFileTypes: true });
61633
+ const entries = fs44.readdirSync(dirPath, { withFileTypes: true });
60819
61634
  for (const entry of entries) {
60820
- const fullPath = path54.join(dirPath, entry.name);
61635
+ const fullPath = path55.join(dirPath, entry.name);
60821
61636
  if (entry.isDirectory()) {
60822
61637
  if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
60823
61638
  continue;
@@ -60825,7 +61640,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
60825
61640
  await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
60826
61641
  } else if (entry.isFile()) {
60827
61642
  const relativePath = fullPath.replace(`${dirPath}/`, "");
60828
- const ext = path54.extname(entry.name).toLowerCase();
61643
+ const ext = path55.extname(entry.name).toLowerCase();
60829
61644
  const validExts = [
60830
61645
  ".ts",
60831
61646
  ".tsx",
@@ -60861,7 +61676,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
60861
61676
  continue;
60862
61677
  }
60863
61678
  try {
60864
- const content = fs42.readFileSync(fullPath, "utf-8");
61679
+ const content = fs44.readFileSync(fullPath, "utf-8");
60865
61680
  const lines = countCodeLines(content);
60866
61681
  callback(lines);
60867
61682
  } catch {}
@@ -61062,11 +61877,11 @@ async function getGitChurn(days, directory) {
61062
61877
  }
61063
61878
  function getComplexityForFile2(filePath) {
61064
61879
  try {
61065
- const stat2 = fs43.statSync(filePath);
61880
+ const stat2 = fs45.statSync(filePath);
61066
61881
  if (stat2.size > MAX_FILE_SIZE_BYTES4) {
61067
61882
  return null;
61068
61883
  }
61069
- const content = fs43.readFileSync(filePath, "utf-8");
61884
+ const content = fs45.readFileSync(filePath, "utf-8");
61070
61885
  return estimateCyclomaticComplexity(content);
61071
61886
  } catch {
61072
61887
  return null;
@@ -61077,7 +61892,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
61077
61892
  const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
61078
61893
  const filteredChurn = new Map;
61079
61894
  for (const [file3, count] of churnMap) {
61080
- const ext = path55.extname(file3).toLowerCase();
61895
+ const ext = path56.extname(file3).toLowerCase();
61081
61896
  if (extSet.has(ext)) {
61082
61897
  filteredChurn.set(file3, count);
61083
61898
  }
@@ -61087,8 +61902,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
61087
61902
  let analyzedFiles = 0;
61088
61903
  for (const [file3, churnCount] of filteredChurn) {
61089
61904
  let fullPath = file3;
61090
- if (!fs43.existsSync(fullPath)) {
61091
- fullPath = path55.join(cwd, file3);
61905
+ if (!fs45.existsSync(fullPath)) {
61906
+ fullPath = path56.join(cwd, file3);
61092
61907
  }
61093
61908
  const complexity = getComplexityForFile2(fullPath);
61094
61909
  if (complexity !== null) {
@@ -61352,9 +62167,10 @@ var curator_analyze = createSwarmTool({
61352
62167
  });
61353
62168
  // src/tools/declare-scope.ts
61354
62169
  init_tool();
61355
- import * as fs44 from "fs";
61356
- import * as path56 from "path";
62170
+ init_state();
61357
62171
  init_create_tool();
62172
+ import * as fs46 from "fs";
62173
+ import * as path57 from "path";
61358
62174
  function validateTaskIdFormat(taskId) {
61359
62175
  const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
61360
62176
  if (!taskIdPattern.test(taskId)) {
@@ -61432,8 +62248,8 @@ async function executeDeclareScope(args2, fallbackDir) {
61432
62248
  };
61433
62249
  }
61434
62250
  }
61435
- normalizedDir = path56.normalize(args2.working_directory);
61436
- const pathParts = normalizedDir.split(path56.sep);
62251
+ normalizedDir = path57.normalize(args2.working_directory);
62252
+ const pathParts = normalizedDir.split(path57.sep);
61437
62253
  if (pathParts.includes("..")) {
61438
62254
  return {
61439
62255
  success: false,
@@ -61443,11 +62259,11 @@ async function executeDeclareScope(args2, fallbackDir) {
61443
62259
  ]
61444
62260
  };
61445
62261
  }
61446
- const resolvedDir = path56.resolve(normalizedDir);
62262
+ const resolvedDir = path57.resolve(normalizedDir);
61447
62263
  try {
61448
- const realPath = fs44.realpathSync(resolvedDir);
61449
- const planPath2 = path56.join(realPath, ".swarm", "plan.json");
61450
- if (!fs44.existsSync(planPath2)) {
62264
+ const realPath = fs46.realpathSync(resolvedDir);
62265
+ const planPath2 = path57.join(realPath, ".swarm", "plan.json");
62266
+ if (!fs46.existsSync(planPath2)) {
61451
62267
  return {
61452
62268
  success: false,
61453
62269
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -61470,8 +62286,8 @@ async function executeDeclareScope(args2, fallbackDir) {
61470
62286
  console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
61471
62287
  }
61472
62288
  const directory = normalizedDir || fallbackDir;
61473
- const planPath = path56.resolve(directory, ".swarm", "plan.json");
61474
- if (!fs44.existsSync(planPath)) {
62289
+ const planPath = path57.resolve(directory, ".swarm", "plan.json");
62290
+ if (!fs46.existsSync(planPath)) {
61475
62291
  return {
61476
62292
  success: false,
61477
62293
  message: "No plan found",
@@ -61480,7 +62296,7 @@ async function executeDeclareScope(args2, fallbackDir) {
61480
62296
  }
61481
62297
  let planContent;
61482
62298
  try {
61483
- planContent = JSON.parse(fs44.readFileSync(planPath, "utf-8"));
62299
+ planContent = JSON.parse(fs46.readFileSync(planPath, "utf-8"));
61484
62300
  } catch {
61485
62301
  return {
61486
62302
  success: false,
@@ -61512,8 +62328,8 @@ async function executeDeclareScope(args2, fallbackDir) {
61512
62328
  const normalizeErrors = [];
61513
62329
  const dir = normalizedDir || fallbackDir || process.cwd();
61514
62330
  const mergedFiles = rawMergedFiles.map((file3) => {
61515
- if (path56.isAbsolute(file3)) {
61516
- const relativePath = path56.relative(dir, file3).replace(/\\/g, "/");
62331
+ if (path57.isAbsolute(file3)) {
62332
+ const relativePath = path57.relative(dir, file3).replace(/\\/g, "/");
61517
62333
  if (relativePath.startsWith("..")) {
61518
62334
  normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
61519
62335
  return file3;
@@ -61852,20 +62668,20 @@ function validateBase(base) {
61852
62668
  function validatePaths(paths) {
61853
62669
  if (!paths)
61854
62670
  return null;
61855
- for (const path58 of paths) {
61856
- if (!path58 || path58.length === 0) {
62671
+ for (const path59 of paths) {
62672
+ if (!path59 || path59.length === 0) {
61857
62673
  return "empty path not allowed";
61858
62674
  }
61859
- if (path58.length > MAX_PATH_LENGTH) {
62675
+ if (path59.length > MAX_PATH_LENGTH) {
61860
62676
  return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
61861
62677
  }
61862
- if (SHELL_METACHARACTERS2.test(path58)) {
62678
+ if (SHELL_METACHARACTERS2.test(path59)) {
61863
62679
  return "path contains shell metacharacters";
61864
62680
  }
61865
- if (path58.startsWith("-")) {
62681
+ if (path59.startsWith("-")) {
61866
62682
  return 'path cannot start with "-" (option-like arguments not allowed)';
61867
62683
  }
61868
- if (CONTROL_CHAR_PATTERN2.test(path58)) {
62684
+ if (CONTROL_CHAR_PATTERN2.test(path59)) {
61869
62685
  return "path contains control characters";
61870
62686
  }
61871
62687
  }
@@ -61946,8 +62762,8 @@ var diff = createSwarmTool({
61946
62762
  if (parts2.length >= 3) {
61947
62763
  const additions = parseInt(parts2[0], 10) || 0;
61948
62764
  const deletions = parseInt(parts2[1], 10) || 0;
61949
- const path58 = parts2[2];
61950
- files.push({ path: path58, additions, deletions });
62765
+ const path59 = parts2[2];
62766
+ files.push({ path: path59, additions, deletions });
61951
62767
  }
61952
62768
  }
61953
62769
  const contractChanges = [];
@@ -62229,8 +63045,8 @@ Use these as DOMAIN values when delegating to @sme.`;
62229
63045
  // src/tools/evidence-check.ts
62230
63046
  init_dist();
62231
63047
  init_create_tool();
62232
- import * as fs45 from "fs";
62233
- import * as path58 from "path";
63048
+ import * as fs47 from "fs";
63049
+ import * as path59 from "path";
62234
63050
  var MAX_FILE_SIZE_BYTES5 = 1024 * 1024;
62235
63051
  var MAX_EVIDENCE_FILES = 1000;
62236
63052
  var EVIDENCE_DIR2 = ".swarm/evidence";
@@ -62257,9 +63073,9 @@ function validateRequiredTypes(input) {
62257
63073
  return null;
62258
63074
  }
62259
63075
  function isPathWithinSwarm2(filePath, cwd) {
62260
- const normalizedCwd = path58.resolve(cwd);
62261
- const swarmPath = path58.join(normalizedCwd, ".swarm");
62262
- const normalizedPath = path58.resolve(filePath);
63076
+ const normalizedCwd = path59.resolve(cwd);
63077
+ const swarmPath = path59.join(normalizedCwd, ".swarm");
63078
+ const normalizedPath = path59.resolve(filePath);
62263
63079
  return normalizedPath.startsWith(swarmPath);
62264
63080
  }
62265
63081
  function parseCompletedTasks(planContent) {
@@ -62275,12 +63091,12 @@ function parseCompletedTasks(planContent) {
62275
63091
  }
62276
63092
  function readEvidenceFiles(evidenceDir, _cwd) {
62277
63093
  const evidence = [];
62278
- if (!fs45.existsSync(evidenceDir) || !fs45.statSync(evidenceDir).isDirectory()) {
63094
+ if (!fs47.existsSync(evidenceDir) || !fs47.statSync(evidenceDir).isDirectory()) {
62279
63095
  return evidence;
62280
63096
  }
62281
63097
  let files;
62282
63098
  try {
62283
- files = fs45.readdirSync(evidenceDir);
63099
+ files = fs47.readdirSync(evidenceDir);
62284
63100
  } catch {
62285
63101
  return evidence;
62286
63102
  }
@@ -62289,14 +63105,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
62289
63105
  if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
62290
63106
  continue;
62291
63107
  }
62292
- const filePath = path58.join(evidenceDir, filename);
63108
+ const filePath = path59.join(evidenceDir, filename);
62293
63109
  try {
62294
- const resolvedPath = path58.resolve(filePath);
62295
- const evidenceDirResolved = path58.resolve(evidenceDir);
63110
+ const resolvedPath = path59.resolve(filePath);
63111
+ const evidenceDirResolved = path59.resolve(evidenceDir);
62296
63112
  if (!resolvedPath.startsWith(evidenceDirResolved)) {
62297
63113
  continue;
62298
63114
  }
62299
- const stat2 = fs45.lstatSync(filePath);
63115
+ const stat2 = fs47.lstatSync(filePath);
62300
63116
  if (!stat2.isFile()) {
62301
63117
  continue;
62302
63118
  }
@@ -62305,7 +63121,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
62305
63121
  }
62306
63122
  let fileStat;
62307
63123
  try {
62308
- fileStat = fs45.statSync(filePath);
63124
+ fileStat = fs47.statSync(filePath);
62309
63125
  if (fileStat.size > MAX_FILE_SIZE_BYTES5) {
62310
63126
  continue;
62311
63127
  }
@@ -62314,7 +63130,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
62314
63130
  }
62315
63131
  let content;
62316
63132
  try {
62317
- content = fs45.readFileSync(filePath, "utf-8");
63133
+ content = fs47.readFileSync(filePath, "utf-8");
62318
63134
  } catch {
62319
63135
  continue;
62320
63136
  }
@@ -62410,7 +63226,7 @@ var evidence_check = createSwarmTool({
62410
63226
  return JSON.stringify(errorResult, null, 2);
62411
63227
  }
62412
63228
  const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
62413
- const planPath = path58.join(cwd, PLAN_FILE);
63229
+ const planPath = path59.join(cwd, PLAN_FILE);
62414
63230
  if (!isPathWithinSwarm2(planPath, cwd)) {
62415
63231
  const errorResult = {
62416
63232
  error: "plan file path validation failed",
@@ -62424,7 +63240,7 @@ var evidence_check = createSwarmTool({
62424
63240
  }
62425
63241
  let planContent;
62426
63242
  try {
62427
- planContent = fs45.readFileSync(planPath, "utf-8");
63243
+ planContent = fs47.readFileSync(planPath, "utf-8");
62428
63244
  } catch {
62429
63245
  const result2 = {
62430
63246
  message: "No completed tasks found in plan.",
@@ -62442,7 +63258,7 @@ var evidence_check = createSwarmTool({
62442
63258
  };
62443
63259
  return JSON.stringify(result2, null, 2);
62444
63260
  }
62445
- const evidenceDir = path58.join(cwd, EVIDENCE_DIR2);
63261
+ const evidenceDir = path59.join(cwd, EVIDENCE_DIR2);
62446
63262
  const evidence = readEvidenceFiles(evidenceDir, cwd);
62447
63263
  const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
62448
63264
  const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
@@ -62459,8 +63275,8 @@ var evidence_check = createSwarmTool({
62459
63275
  // src/tools/file-extractor.ts
62460
63276
  init_tool();
62461
63277
  init_create_tool();
62462
- import * as fs46 from "fs";
62463
- import * as path59 from "path";
63278
+ import * as fs48 from "fs";
63279
+ import * as path60 from "path";
62464
63280
  var EXT_MAP = {
62465
63281
  python: ".py",
62466
63282
  py: ".py",
@@ -62522,8 +63338,8 @@ var extract_code_blocks = createSwarmTool({
62522
63338
  execute: async (args2, directory) => {
62523
63339
  const { content, output_dir, prefix } = args2;
62524
63340
  const targetDir = output_dir || directory;
62525
- if (!fs46.existsSync(targetDir)) {
62526
- fs46.mkdirSync(targetDir, { recursive: true });
63341
+ if (!fs48.existsSync(targetDir)) {
63342
+ fs48.mkdirSync(targetDir, { recursive: true });
62527
63343
  }
62528
63344
  if (!content) {
62529
63345
  return "Error: content is required";
@@ -62541,16 +63357,16 @@ var extract_code_blocks = createSwarmTool({
62541
63357
  if (prefix) {
62542
63358
  filename = `${prefix}_${filename}`;
62543
63359
  }
62544
- let filepath = path59.join(targetDir, filename);
62545
- const base = path59.basename(filepath, path59.extname(filepath));
62546
- const ext = path59.extname(filepath);
63360
+ let filepath = path60.join(targetDir, filename);
63361
+ const base = path60.basename(filepath, path60.extname(filepath));
63362
+ const ext = path60.extname(filepath);
62547
63363
  let counter = 1;
62548
- while (fs46.existsSync(filepath)) {
62549
- filepath = path59.join(targetDir, `${base}_${counter}${ext}`);
63364
+ while (fs48.existsSync(filepath)) {
63365
+ filepath = path60.join(targetDir, `${base}_${counter}${ext}`);
62550
63366
  counter++;
62551
63367
  }
62552
63368
  try {
62553
- fs46.writeFileSync(filepath, code.trim(), "utf-8");
63369
+ fs48.writeFileSync(filepath, code.trim(), "utf-8");
62554
63370
  savedFiles.push(filepath);
62555
63371
  } catch (error93) {
62556
63372
  errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
@@ -62580,7 +63396,7 @@ init_create_tool();
62580
63396
  var GITINGEST_TIMEOUT_MS = 1e4;
62581
63397
  var GITINGEST_MAX_RESPONSE_BYTES = 5242880;
62582
63398
  var GITINGEST_MAX_RETRIES = 2;
62583
- var delay = (ms) => new Promise((resolve21) => setTimeout(resolve21, ms));
63399
+ var delay = (ms) => new Promise((resolve22) => setTimeout(resolve22, ms));
62584
63400
  async function fetchGitingest(args2) {
62585
63401
  for (let attempt = 0;attempt <= GITINGEST_MAX_RETRIES; attempt++) {
62586
63402
  try {
@@ -62666,8 +63482,8 @@ var gitingest = createSwarmTool({
62666
63482
  // src/tools/imports.ts
62667
63483
  init_dist();
62668
63484
  init_create_tool();
62669
- import * as fs47 from "fs";
62670
- import * as path60 from "path";
63485
+ import * as fs49 from "fs";
63486
+ import * as path61 from "path";
62671
63487
  var MAX_FILE_PATH_LENGTH2 = 500;
62672
63488
  var MAX_SYMBOL_LENGTH = 256;
62673
63489
  var MAX_FILE_SIZE_BYTES6 = 1024 * 1024;
@@ -62715,7 +63531,7 @@ function validateSymbolInput(symbol3) {
62715
63531
  return null;
62716
63532
  }
62717
63533
  function isBinaryFile2(filePath, buffer) {
62718
- const ext = path60.extname(filePath).toLowerCase();
63534
+ const ext = path61.extname(filePath).toLowerCase();
62719
63535
  if (ext === ".json" || ext === ".md" || ext === ".txt") {
62720
63536
  return false;
62721
63537
  }
@@ -62739,15 +63555,15 @@ function parseImports(content, targetFile, targetSymbol) {
62739
63555
  const imports = [];
62740
63556
  let _resolvedTarget;
62741
63557
  try {
62742
- _resolvedTarget = path60.resolve(targetFile);
63558
+ _resolvedTarget = path61.resolve(targetFile);
62743
63559
  } catch {
62744
63560
  _resolvedTarget = targetFile;
62745
63561
  }
62746
- const targetBasename = path60.basename(targetFile, path60.extname(targetFile));
63562
+ const targetBasename = path61.basename(targetFile, path61.extname(targetFile));
62747
63563
  const targetWithExt = targetFile;
62748
63564
  const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
62749
- const normalizedTargetWithExt = path60.normalize(targetWithExt).replace(/\\/g, "/");
62750
- const normalizedTargetWithoutExt = path60.normalize(targetWithoutExt).replace(/\\/g, "/");
63565
+ const normalizedTargetWithExt = path61.normalize(targetWithExt).replace(/\\/g, "/");
63566
+ const normalizedTargetWithoutExt = path61.normalize(targetWithoutExt).replace(/\\/g, "/");
62751
63567
  const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
62752
63568
  for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
62753
63569
  const modulePath = match[1] || match[2] || match[3];
@@ -62770,9 +63586,9 @@ function parseImports(content, targetFile, targetSymbol) {
62770
63586
  }
62771
63587
  const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
62772
63588
  let isMatch = false;
62773
- const _targetDir = path60.dirname(targetFile);
62774
- const targetExt = path60.extname(targetFile);
62775
- const targetBasenameNoExt = path60.basename(targetFile, targetExt);
63589
+ const _targetDir = path61.dirname(targetFile);
63590
+ const targetExt = path61.extname(targetFile);
63591
+ const targetBasenameNoExt = path61.basename(targetFile, targetExt);
62776
63592
  const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
62777
63593
  const moduleName = modulePath.split(/[/\\]/).pop() || "";
62778
63594
  const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
@@ -62829,7 +63645,7 @@ var SKIP_DIRECTORIES3 = new Set([
62829
63645
  function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
62830
63646
  let entries;
62831
63647
  try {
62832
- entries = fs47.readdirSync(dir);
63648
+ entries = fs49.readdirSync(dir);
62833
63649
  } catch (e) {
62834
63650
  stats.fileErrors.push({
62835
63651
  path: dir,
@@ -62840,13 +63656,13 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
62840
63656
  entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
62841
63657
  for (const entry of entries) {
62842
63658
  if (SKIP_DIRECTORIES3.has(entry)) {
62843
- stats.skippedDirs.push(path60.join(dir, entry));
63659
+ stats.skippedDirs.push(path61.join(dir, entry));
62844
63660
  continue;
62845
63661
  }
62846
- const fullPath = path60.join(dir, entry);
63662
+ const fullPath = path61.join(dir, entry);
62847
63663
  let stat2;
62848
63664
  try {
62849
- stat2 = fs47.statSync(fullPath);
63665
+ stat2 = fs49.statSync(fullPath);
62850
63666
  } catch (e) {
62851
63667
  stats.fileErrors.push({
62852
63668
  path: fullPath,
@@ -62857,7 +63673,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
62857
63673
  if (stat2.isDirectory()) {
62858
63674
  findSourceFiles(fullPath, files, stats);
62859
63675
  } else if (stat2.isFile()) {
62860
- const ext = path60.extname(fullPath).toLowerCase();
63676
+ const ext = path61.extname(fullPath).toLowerCase();
62861
63677
  if (SUPPORTED_EXTENSIONS.includes(ext)) {
62862
63678
  files.push(fullPath);
62863
63679
  }
@@ -62914,8 +63730,8 @@ var imports = createSwarmTool({
62914
63730
  return JSON.stringify(errorResult, null, 2);
62915
63731
  }
62916
63732
  try {
62917
- const targetFile = path60.resolve(file3);
62918
- if (!fs47.existsSync(targetFile)) {
63733
+ const targetFile = path61.resolve(file3);
63734
+ if (!fs49.existsSync(targetFile)) {
62919
63735
  const errorResult = {
62920
63736
  error: `target file not found: ${file3}`,
62921
63737
  target: file3,
@@ -62925,7 +63741,7 @@ var imports = createSwarmTool({
62925
63741
  };
62926
63742
  return JSON.stringify(errorResult, null, 2);
62927
63743
  }
62928
- const targetStat = fs47.statSync(targetFile);
63744
+ const targetStat = fs49.statSync(targetFile);
62929
63745
  if (!targetStat.isFile()) {
62930
63746
  const errorResult = {
62931
63747
  error: "target must be a file, not a directory",
@@ -62936,7 +63752,7 @@ var imports = createSwarmTool({
62936
63752
  };
62937
63753
  return JSON.stringify(errorResult, null, 2);
62938
63754
  }
62939
- const baseDir = path60.dirname(targetFile);
63755
+ const baseDir = path61.dirname(targetFile);
62940
63756
  const scanStats = {
62941
63757
  skippedDirs: [],
62942
63758
  skippedFiles: 0,
@@ -62951,12 +63767,12 @@ var imports = createSwarmTool({
62951
63767
  if (consumers.length >= MAX_CONSUMERS)
62952
63768
  break;
62953
63769
  try {
62954
- const stat2 = fs47.statSync(filePath);
63770
+ const stat2 = fs49.statSync(filePath);
62955
63771
  if (stat2.size > MAX_FILE_SIZE_BYTES6) {
62956
63772
  skippedFileCount++;
62957
63773
  continue;
62958
63774
  }
62959
- const buffer = fs47.readFileSync(filePath);
63775
+ const buffer = fs49.readFileSync(filePath);
62960
63776
  if (isBinaryFile2(filePath, buffer)) {
62961
63777
  skippedFileCount++;
62962
63778
  continue;
@@ -63156,7 +63972,7 @@ init_dist();
63156
63972
  init_config();
63157
63973
  init_knowledge_store();
63158
63974
  init_create_tool();
63159
- import { existsSync as existsSync38 } from "fs";
63975
+ import { existsSync as existsSync39 } from "fs";
63160
63976
  var DEFAULT_LIMIT = 10;
63161
63977
  var MAX_LESSON_LENGTH = 200;
63162
63978
  var VALID_CATEGORIES3 = [
@@ -63225,14 +64041,14 @@ function validateLimit(limit) {
63225
64041
  }
63226
64042
  async function readSwarmKnowledge(directory) {
63227
64043
  const swarmPath = resolveSwarmKnowledgePath(directory);
63228
- if (!existsSync38(swarmPath)) {
64044
+ if (!existsSync39(swarmPath)) {
63229
64045
  return [];
63230
64046
  }
63231
64047
  return readKnowledge(swarmPath);
63232
64048
  }
63233
64049
  async function readHiveKnowledge() {
63234
64050
  const hivePath = resolveHiveKnowledgePath();
63235
- if (!existsSync38(hivePath)) {
64051
+ if (!existsSync39(hivePath)) {
63236
64052
  return [];
63237
64053
  }
63238
64054
  return readKnowledge(hivePath);
@@ -63545,62 +64361,13 @@ init_dist();
63545
64361
  init_config();
63546
64362
  init_schema();
63547
64363
  init_manager();
63548
- import * as fs49 from "fs";
64364
+ import * as fs50 from "fs";
63549
64365
  import * as path62 from "path";
63550
64366
  init_review_receipt();
63551
64367
  init_utils2();
63552
-
63553
- // src/parallel/file-locks.ts
63554
- var import_proper_lockfile3 = __toESM(require_proper_lockfile(), 1);
63555
- import * as fs48 from "fs";
63556
- import * as path61 from "path";
63557
- var LOCKS_DIR = ".swarm/locks";
63558
- var LOCK_TIMEOUT_MS = 5 * 60 * 1000;
63559
- function getLockFilePath(directory, filePath) {
63560
- const normalized = path61.resolve(directory, filePath);
63561
- if (!normalized.startsWith(path61.resolve(directory))) {
63562
- throw new Error("Invalid file path: path traversal not allowed");
63563
- }
63564
- const hash3 = Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
63565
- return path61.join(directory, LOCKS_DIR, `${hash3}.lock`);
63566
- }
63567
- async function tryAcquireLock(directory, filePath, agent, taskId) {
63568
- const lockPath = getLockFilePath(directory, filePath);
63569
- const locksDir = path61.dirname(lockPath);
63570
- if (!fs48.existsSync(locksDir)) {
63571
- fs48.mkdirSync(locksDir, { recursive: true });
63572
- }
63573
- if (!fs48.existsSync(lockPath)) {
63574
- fs48.writeFileSync(lockPath, "", "utf-8");
63575
- }
63576
- let release;
63577
- try {
63578
- release = await import_proper_lockfile3.default.lock(lockPath, {
63579
- stale: LOCK_TIMEOUT_MS,
63580
- retries: { retries: 0 },
63581
- realpath: false
63582
- });
63583
- } catch (err2) {
63584
- const code = err2.code;
63585
- if (code === "ELOCKED" || code === "EEXIST") {
63586
- return { acquired: false };
63587
- }
63588
- throw err2;
63589
- }
63590
- const lock = {
63591
- filePath,
63592
- agent,
63593
- taskId,
63594
- timestamp: new Date().toISOString(),
63595
- expiresAt: Date.now() + LOCK_TIMEOUT_MS,
63596
- _release: release
63597
- };
63598
- return { acquired: true, lock };
63599
- }
63600
-
63601
- // src/tools/phase-complete.ts
63602
64368
  init_ledger();
63603
64369
  init_manager2();
64370
+ init_state();
63604
64371
  init_telemetry();
63605
64372
  init_create_tool();
63606
64373
  init_resolve_working_directory();
@@ -63824,7 +64591,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
63824
64591
  let driftVerdictFound = false;
63825
64592
  let driftVerdictApproved = false;
63826
64593
  try {
63827
- const driftEvidenceContent = fs49.readFileSync(driftEvidencePath, "utf-8");
64594
+ const driftEvidenceContent = fs50.readFileSync(driftEvidencePath, "utf-8");
63828
64595
  const driftEvidence = JSON.parse(driftEvidenceContent);
63829
64596
  const entries = driftEvidence.entries ?? [];
63830
64597
  for (const entry of entries) {
@@ -63855,13 +64622,13 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
63855
64622
  }
63856
64623
  if (!driftVerdictFound) {
63857
64624
  const specPath = path62.join(dir, ".swarm", "spec.md");
63858
- const specExists = fs49.existsSync(specPath);
64625
+ const specExists = fs50.existsSync(specPath);
63859
64626
  if (!specExists) {
63860
64627
  let incompleteTaskCount = 0;
63861
64628
  let planPhaseFound = false;
63862
64629
  try {
63863
64630
  const planPath = validateSwarmPath(dir, "plan.json");
63864
- const planRaw = fs49.readFileSync(planPath, "utf-8");
64631
+ const planRaw = fs50.readFileSync(planPath, "utf-8");
63865
64632
  const plan = JSON.parse(planRaw);
63866
64633
  const targetPhase = plan.phases.find((p) => p.id === phase);
63867
64634
  if (targetPhase) {
@@ -63986,7 +64753,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
63986
64753
  let phaseRequiredAgents;
63987
64754
  try {
63988
64755
  const planPath = validateSwarmPath(dir, "plan.json");
63989
- const planRaw = fs49.readFileSync(planPath, "utf-8");
64756
+ const planRaw = fs50.readFileSync(planPath, "utf-8");
63990
64757
  const plan = JSON.parse(planRaw);
63991
64758
  const phaseObj = plan.phases.find((p) => p.id === phase);
63992
64759
  phaseRequiredAgents = phaseObj?.required_agents;
@@ -64001,7 +64768,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
64001
64768
  if (agentsMissing.length > 0) {
64002
64769
  try {
64003
64770
  const planPath = validateSwarmPath(dir, "plan.json");
64004
- const planRaw = fs49.readFileSync(planPath, "utf-8");
64771
+ const planRaw = fs50.readFileSync(planPath, "utf-8");
64005
64772
  const plan = JSON.parse(planRaw);
64006
64773
  const targetPhase = plan.phases.find((p) => p.id === phase);
64007
64774
  if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
@@ -64041,7 +64808,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
64041
64808
  if (phaseCompleteConfig.regression_sweep?.enforce) {
64042
64809
  try {
64043
64810
  const planPath = validateSwarmPath(dir, "plan.json");
64044
- const planRaw = fs49.readFileSync(planPath, "utf-8");
64811
+ const planRaw = fs50.readFileSync(planPath, "utf-8");
64045
64812
  const plan = JSON.parse(planRaw);
64046
64813
  const targetPhase = plan.phases.find((p) => p.id === phase);
64047
64814
  if (targetPhase) {
@@ -64095,7 +64862,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
64095
64862
  }
64096
64863
  try {
64097
64864
  const eventsPath = validateSwarmPath(dir, "events.jsonl");
64098
- fs49.appendFileSync(eventsPath, `${JSON.stringify(event)}
64865
+ fs50.appendFileSync(eventsPath, `${JSON.stringify(event)}
64099
64866
  `, "utf-8");
64100
64867
  } catch (writeError) {
64101
64868
  warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -64116,6 +64883,9 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
64116
64883
  contributorSession.lastCompletedPhaseAgentsDispatched = new Set(contributorSession.phaseAgentsDispatched);
64117
64884
  }
64118
64885
  contributorSession.phaseAgentsDispatched = new Set;
64886
+ contributorSession.fullAutoInteractionCount = 0;
64887
+ contributorSession.fullAutoDeadlockCount = 0;
64888
+ contributorSession.fullAutoLastQuestionHash = null;
64119
64889
  contributorSession.lastPhaseCompleteTimestamp = now;
64120
64890
  const oldPhase = contributorSession.lastPhaseCompletePhase;
64121
64891
  contributorSession.lastPhaseCompletePhase = phase;
@@ -64145,12 +64915,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
64145
64915
  warnings.push(`Warning: failed to update plan.json phase status`);
64146
64916
  try {
64147
64917
  const planPath = validateSwarmPath(dir, "plan.json");
64148
- const planRaw = fs49.readFileSync(planPath, "utf-8");
64918
+ const planRaw = fs50.readFileSync(planPath, "utf-8");
64149
64919
  const plan2 = JSON.parse(planRaw);
64150
64920
  const phaseObj = plan2.phases.find((p) => p.id === phase);
64151
64921
  if (phaseObj) {
64152
64922
  phaseObj.status = "complete";
64153
- fs49.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
64923
+ fs50.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
64154
64924
  }
64155
64925
  } catch {}
64156
64926
  } else if (plan) {
@@ -64187,12 +64957,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
64187
64957
  warnings.push(`Warning: failed to update plan.json phase status`);
64188
64958
  try {
64189
64959
  const planPath = validateSwarmPath(dir, "plan.json");
64190
- const planRaw = fs49.readFileSync(planPath, "utf-8");
64960
+ const planRaw = fs50.readFileSync(planPath, "utf-8");
64191
64961
  const plan = JSON.parse(planRaw);
64192
64962
  const phaseObj = plan.phases.find((p) => p.id === phase);
64193
64963
  if (phaseObj) {
64194
64964
  phaseObj.status = "complete";
64195
- fs49.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
64965
+ fs50.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
64196
64966
  }
64197
64967
  } catch {}
64198
64968
  }
@@ -64249,7 +65019,7 @@ init_dist();
64249
65019
  init_discovery();
64250
65020
  init_utils();
64251
65021
  init_create_tool();
64252
- import * as fs50 from "fs";
65022
+ import * as fs51 from "fs";
64253
65023
  import * as path63 from "path";
64254
65024
  var MAX_OUTPUT_BYTES5 = 52428800;
64255
65025
  var AUDIT_TIMEOUT_MS = 120000;
@@ -64278,31 +65048,31 @@ function validateArgs3(args2) {
64278
65048
  function detectEcosystems(directory) {
64279
65049
  const ecosystems = [];
64280
65050
  const cwd = directory;
64281
- if (fs50.existsSync(path63.join(cwd, "package.json"))) {
65051
+ if (fs51.existsSync(path63.join(cwd, "package.json"))) {
64282
65052
  ecosystems.push("npm");
64283
65053
  }
64284
- if (fs50.existsSync(path63.join(cwd, "pyproject.toml")) || fs50.existsSync(path63.join(cwd, "requirements.txt"))) {
65054
+ if (fs51.existsSync(path63.join(cwd, "pyproject.toml")) || fs51.existsSync(path63.join(cwd, "requirements.txt"))) {
64285
65055
  ecosystems.push("pip");
64286
65056
  }
64287
- if (fs50.existsSync(path63.join(cwd, "Cargo.toml"))) {
65057
+ if (fs51.existsSync(path63.join(cwd, "Cargo.toml"))) {
64288
65058
  ecosystems.push("cargo");
64289
65059
  }
64290
- if (fs50.existsSync(path63.join(cwd, "go.mod"))) {
65060
+ if (fs51.existsSync(path63.join(cwd, "go.mod"))) {
64291
65061
  ecosystems.push("go");
64292
65062
  }
64293
65063
  try {
64294
- const files = fs50.readdirSync(cwd);
65064
+ const files = fs51.readdirSync(cwd);
64295
65065
  if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
64296
65066
  ecosystems.push("dotnet");
64297
65067
  }
64298
65068
  } catch {}
64299
- if (fs50.existsSync(path63.join(cwd, "Gemfile")) || fs50.existsSync(path63.join(cwd, "Gemfile.lock"))) {
65069
+ if (fs51.existsSync(path63.join(cwd, "Gemfile")) || fs51.existsSync(path63.join(cwd, "Gemfile.lock"))) {
64300
65070
  ecosystems.push("ruby");
64301
65071
  }
64302
- if (fs50.existsSync(path63.join(cwd, "pubspec.yaml"))) {
65072
+ if (fs51.existsSync(path63.join(cwd, "pubspec.yaml"))) {
64303
65073
  ecosystems.push("dart");
64304
65074
  }
64305
- if (fs50.existsSync(path63.join(cwd, "composer.lock"))) {
65075
+ if (fs51.existsSync(path63.join(cwd, "composer.lock"))) {
64306
65076
  ecosystems.push("composer");
64307
65077
  }
64308
65078
  return ecosystems;
@@ -65461,7 +66231,7 @@ var pkg_audit = createSwarmTool({
65461
66231
  // src/tools/placeholder-scan.ts
65462
66232
  init_dist();
65463
66233
  init_manager();
65464
- import * as fs51 from "fs";
66234
+ import * as fs52 from "fs";
65465
66235
  import * as path64 from "path";
65466
66236
  init_utils();
65467
66237
  init_create_tool();
@@ -65796,7 +66566,7 @@ async function placeholderScan(input, directory) {
65796
66566
  if (!fullPath.startsWith(resolvedDirectory + path64.sep) && fullPath !== resolvedDirectory) {
65797
66567
  continue;
65798
66568
  }
65799
- if (!fs51.existsSync(fullPath)) {
66569
+ if (!fs52.existsSync(fullPath)) {
65800
66570
  continue;
65801
66571
  }
65802
66572
  if (isAllowedByGlobs(filePath, allow_globs)) {
@@ -65804,11 +66574,11 @@ async function placeholderScan(input, directory) {
65804
66574
  }
65805
66575
  let content;
65806
66576
  try {
65807
- const stat2 = fs51.statSync(fullPath);
66577
+ const stat2 = fs52.statSync(fullPath);
65808
66578
  if (stat2.size > MAX_FILE_SIZE) {
65809
66579
  continue;
65810
66580
  }
65811
- content = fs51.readFileSync(fullPath, "utf-8");
66581
+ content = fs52.readFileSync(fullPath, "utf-8");
65812
66582
  } catch {
65813
66583
  continue;
65814
66584
  }
@@ -65870,7 +66640,7 @@ var placeholder_scan = createSwarmTool({
65870
66640
  });
65871
66641
  // src/tools/pre-check-batch.ts
65872
66642
  init_dist();
65873
- import * as fs53 from "fs";
66643
+ import * as fs54 from "fs";
65874
66644
  import * as path66 from "path";
65875
66645
 
65876
66646
  // node_modules/yocto-queue/index.js
@@ -66164,7 +66934,7 @@ var quality_budget = createSwarmTool({
66164
66934
  init_dist();
66165
66935
  init_manager();
66166
66936
  init_detector();
66167
- import * as fs52 from "fs";
66937
+ import * as fs53 from "fs";
66168
66938
  import * as path65 from "path";
66169
66939
  import { extname as extname14 } from "path";
66170
66940
 
@@ -67065,17 +67835,17 @@ var SEVERITY_ORDER = {
67065
67835
  };
67066
67836
  function shouldSkipFile(filePath) {
67067
67837
  try {
67068
- const stats = fs52.statSync(filePath);
67838
+ const stats = fs53.statSync(filePath);
67069
67839
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
67070
67840
  return { skip: true, reason: "file too large" };
67071
67841
  }
67072
67842
  if (stats.size === 0) {
67073
67843
  return { skip: true, reason: "empty file" };
67074
67844
  }
67075
- const fd = fs52.openSync(filePath, "r");
67845
+ const fd = fs53.openSync(filePath, "r");
67076
67846
  const buffer = Buffer.alloc(8192);
67077
- const bytesRead = fs52.readSync(fd, buffer, 0, 8192, 0);
67078
- fs52.closeSync(fd);
67847
+ const bytesRead = fs53.readSync(fd, buffer, 0, 8192, 0);
67848
+ fs53.closeSync(fd);
67079
67849
  if (bytesRead > 0) {
67080
67850
  let nullCount = 0;
67081
67851
  for (let i2 = 0;i2 < bytesRead; i2++) {
@@ -67114,7 +67884,7 @@ function countBySeverity(findings) {
67114
67884
  }
67115
67885
  function scanFileWithTierA(filePath, language) {
67116
67886
  try {
67117
- const content = fs52.readFileSync(filePath, "utf-8");
67887
+ const content = fs53.readFileSync(filePath, "utf-8");
67118
67888
  const findings = executeRulesSync(filePath, content, language);
67119
67889
  return findings.map((f) => ({
67120
67890
  rule_id: f.rule_id,
@@ -67167,7 +67937,7 @@ async function sastScan(input, directory, config3) {
67167
67937
  _filesSkipped++;
67168
67938
  continue;
67169
67939
  }
67170
- if (!fs52.existsSync(resolvedPath)) {
67940
+ if (!fs53.existsSync(resolvedPath)) {
67171
67941
  _filesSkipped++;
67172
67942
  continue;
67173
67943
  }
@@ -67623,7 +68393,7 @@ async function runSecretscanWithFiles(files, directory) {
67623
68393
  }
67624
68394
  let stat2;
67625
68395
  try {
67626
- stat2 = fs53.statSync(file3);
68396
+ stat2 = fs54.statSync(file3);
67627
68397
  } catch {
67628
68398
  skippedFiles++;
67629
68399
  continue;
@@ -67634,7 +68404,7 @@ async function runSecretscanWithFiles(files, directory) {
67634
68404
  }
67635
68405
  let content;
67636
68406
  try {
67637
- const buffer = fs53.readFileSync(file3);
68407
+ const buffer = fs54.readFileSync(file3);
67638
68408
  if (buffer.includes(0)) {
67639
68409
  skippedFiles++;
67640
68410
  continue;
@@ -68167,10 +68937,11 @@ ${paginatedContent}`;
68167
68937
  });
68168
68938
  // src/tools/save-plan.ts
68169
68939
  init_tool();
68170
- import * as fs54 from "fs";
68940
+ import * as fs55 from "fs";
68171
68941
  import * as path67 from "path";
68172
68942
  init_ledger();
68173
68943
  init_manager2();
68944
+ init_state();
68174
68945
  init_create_tool();
68175
68946
  function detectPlaceholderContent(args2) {
68176
68947
  const issues = [];
@@ -68312,7 +69083,7 @@ async function executeSavePlan(args2, fallbackDir) {
68312
69083
  phases_count: plan.phases.length,
68313
69084
  tasks_count: tasksCount
68314
69085
  });
68315
- await fs54.promises.writeFile(markerPath, marker, "utf8");
69086
+ await fs55.promises.writeFile(markerPath, marker, "utf8");
68316
69087
  } catch {}
68317
69088
  const warnings = [];
68318
69089
  let criticReviewFound = false;
@@ -68372,7 +69143,7 @@ var save_plan = createSwarmTool({
68372
69143
  // src/tools/sbom-generate.ts
68373
69144
  init_dist();
68374
69145
  init_manager();
68375
- import * as fs55 from "fs";
69146
+ import * as fs56 from "fs";
68376
69147
  import * as path68 from "path";
68377
69148
 
68378
69149
  // src/sbom/detectors/index.ts
@@ -69221,7 +69992,7 @@ function findManifestFiles(rootDir) {
69221
69992
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
69222
69993
  function searchDir(dir) {
69223
69994
  try {
69224
- const entries = fs55.readdirSync(dir, { withFileTypes: true });
69995
+ const entries = fs56.readdirSync(dir, { withFileTypes: true });
69225
69996
  for (const entry of entries) {
69226
69997
  const fullPath = path68.join(dir, entry.name);
69227
69998
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
@@ -69248,7 +70019,7 @@ function findManifestFilesInDirs(directories, workingDir) {
69248
70019
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
69249
70020
  for (const dir of directories) {
69250
70021
  try {
69251
- const entries = fs55.readdirSync(dir, { withFileTypes: true });
70022
+ const entries = fs56.readdirSync(dir, { withFileTypes: true });
69252
70023
  for (const entry of entries) {
69253
70024
  const fullPath = path68.join(dir, entry.name);
69254
70025
  if (entry.isFile()) {
@@ -69285,7 +70056,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
69285
70056
  }
69286
70057
  function ensureOutputDir(outputDir) {
69287
70058
  try {
69288
- fs55.mkdirSync(outputDir, { recursive: true });
70059
+ fs56.mkdirSync(outputDir, { recursive: true });
69289
70060
  } catch (error93) {
69290
70061
  if (!error93 || error93.code !== "EEXIST") {
69291
70062
  throw error93;
@@ -69379,10 +70150,10 @@ var sbom_generate = createSwarmTool({
69379
70150
  for (const manifestFile of manifestFiles) {
69380
70151
  try {
69381
70152
  const fullPath = path68.isAbsolute(manifestFile) ? manifestFile : path68.join(workingDir, manifestFile);
69382
- if (!fs55.existsSync(fullPath)) {
70153
+ if (!fs56.existsSync(fullPath)) {
69383
70154
  continue;
69384
70155
  }
69385
- const content = fs55.readFileSync(fullPath, "utf-8");
70156
+ const content = fs56.readFileSync(fullPath, "utf-8");
69386
70157
  const components = detectComponents(manifestFile, content);
69387
70158
  processedFiles.push(manifestFile);
69388
70159
  if (components.length > 0) {
@@ -69396,7 +70167,7 @@ var sbom_generate = createSwarmTool({
69396
70167
  const bomJson = serializeCycloneDX(bom);
69397
70168
  const filename = generateSbomFilename();
69398
70169
  const outputPath = path68.join(outputDir, filename);
69399
- fs55.writeFileSync(outputPath, bomJson, "utf-8");
70170
+ fs56.writeFileSync(outputPath, bomJson, "utf-8");
69400
70171
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
69401
70172
  try {
69402
70173
  const timestamp = new Date().toISOString();
@@ -69438,7 +70209,7 @@ var sbom_generate = createSwarmTool({
69438
70209
  // src/tools/schema-drift.ts
69439
70210
  init_dist();
69440
70211
  init_create_tool();
69441
- import * as fs56 from "fs";
70212
+ import * as fs57 from "fs";
69442
70213
  import * as path69 from "path";
69443
70214
  var SPEC_CANDIDATES = [
69444
70215
  "openapi.json",
@@ -69480,19 +70251,19 @@ function discoverSpecFile(cwd, specFileArg) {
69480
70251
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
69481
70252
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
69482
70253
  }
69483
- const stats = fs56.statSync(resolvedPath);
70254
+ const stats = fs57.statSync(resolvedPath);
69484
70255
  if (stats.size > MAX_SPEC_SIZE) {
69485
70256
  throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
69486
70257
  }
69487
- if (!fs56.existsSync(resolvedPath)) {
70258
+ if (!fs57.existsSync(resolvedPath)) {
69488
70259
  throw new Error(`Spec file not found: ${resolvedPath}`);
69489
70260
  }
69490
70261
  return resolvedPath;
69491
70262
  }
69492
70263
  for (const candidate of SPEC_CANDIDATES) {
69493
70264
  const candidatePath = path69.resolve(cwd, candidate);
69494
- if (fs56.existsSync(candidatePath)) {
69495
- const stats = fs56.statSync(candidatePath);
70265
+ if (fs57.existsSync(candidatePath)) {
70266
+ const stats = fs57.statSync(candidatePath);
69496
70267
  if (stats.size <= MAX_SPEC_SIZE) {
69497
70268
  return candidatePath;
69498
70269
  }
@@ -69501,7 +70272,7 @@ function discoverSpecFile(cwd, specFileArg) {
69501
70272
  return null;
69502
70273
  }
69503
70274
  function parseSpec(specFile) {
69504
- const content = fs56.readFileSync(specFile, "utf-8");
70275
+ const content = fs57.readFileSync(specFile, "utf-8");
69505
70276
  const ext = path69.extname(specFile).toLowerCase();
69506
70277
  if (ext === ".json") {
69507
70278
  return parseJsonSpec(content);
@@ -69573,7 +70344,7 @@ function extractRoutes(cwd) {
69573
70344
  function walkDir(dir) {
69574
70345
  let entries;
69575
70346
  try {
69576
- entries = fs56.readdirSync(dir, { withFileTypes: true });
70347
+ entries = fs57.readdirSync(dir, { withFileTypes: true });
69577
70348
  } catch {
69578
70349
  return;
69579
70350
  }
@@ -69606,7 +70377,7 @@ function extractRoutes(cwd) {
69606
70377
  }
69607
70378
  function extractRoutesFromFile(filePath) {
69608
70379
  const routes = [];
69609
- const content = fs56.readFileSync(filePath, "utf-8");
70380
+ const content = fs57.readFileSync(filePath, "utf-8");
69610
70381
  const lines = content.split(/\r?\n/);
69611
70382
  const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
69612
70383
  const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
@@ -69753,7 +70524,7 @@ var schema_drift = createSwarmTool({
69753
70524
  // src/tools/search.ts
69754
70525
  init_tool();
69755
70526
  init_create_tool();
69756
- import * as fs57 from "fs";
70527
+ import * as fs58 from "fs";
69757
70528
  import * as path70 from "path";
69758
70529
  var DEFAULT_MAX_RESULTS = 100;
69759
70530
  var DEFAULT_MAX_LINES = 200;
@@ -69791,8 +70562,8 @@ function containsWindowsAttacks3(str) {
69791
70562
  function isPathInWorkspace3(filePath, workspace) {
69792
70563
  try {
69793
70564
  const resolvedPath = path70.resolve(workspace, filePath);
69794
- const realWorkspace = fs57.realpathSync(workspace);
69795
- const realResolvedPath = fs57.realpathSync(resolvedPath);
70565
+ const realWorkspace = fs58.realpathSync(workspace);
70566
+ const realResolvedPath = fs58.realpathSync(resolvedPath);
69796
70567
  const relativePath = path70.relative(realWorkspace, realResolvedPath);
69797
70568
  if (relativePath.startsWith("..") || path70.isAbsolute(relativePath)) {
69798
70569
  return false;
@@ -69812,7 +70583,7 @@ function findRgInEnvPath() {
69812
70583
  continue;
69813
70584
  const isWindows = process.platform === "win32";
69814
70585
  const candidate = path70.join(dir, isWindows ? "rg.exe" : "rg");
69815
- if (fs57.existsSync(candidate))
70586
+ if (fs58.existsSync(candidate))
69816
70587
  return candidate;
69817
70588
  }
69818
70589
  return null;
@@ -69939,7 +70710,7 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
69939
70710
  return files;
69940
70711
  }
69941
70712
  try {
69942
- const entries = fs57.readdirSync(dir, { withFileTypes: true });
70713
+ const entries = fs58.readdirSync(dir, { withFileTypes: true });
69943
70714
  for (const entry of entries) {
69944
70715
  const fullPath = path70.join(dir, entry.name);
69945
70716
  const relativePath = path70.relative(workspace, fullPath);
@@ -69989,7 +70760,7 @@ async function fallbackSearch(opts) {
69989
70760
  }
69990
70761
  let stats;
69991
70762
  try {
69992
- stats = fs57.statSync(fullPath);
70763
+ stats = fs58.statSync(fullPath);
69993
70764
  if (stats.size > MAX_FILE_SIZE_BYTES8) {
69994
70765
  continue;
69995
70766
  }
@@ -69998,7 +70769,7 @@ async function fallbackSearch(opts) {
69998
70769
  }
69999
70770
  let content;
70000
70771
  try {
70001
- content = fs57.readFileSync(fullPath, "utf-8");
70772
+ content = fs58.readFileSync(fullPath, "utf-8");
70002
70773
  } catch {
70003
70774
  continue;
70004
70775
  }
@@ -70110,7 +70881,7 @@ var search = createSwarmTool({
70110
70881
  message: "Exclude pattern contains invalid Windows-specific sequence"
70111
70882
  }, null, 2);
70112
70883
  }
70113
- if (!fs57.existsSync(directory)) {
70884
+ if (!fs58.existsSync(directory)) {
70114
70885
  return JSON.stringify({
70115
70886
  error: true,
70116
70887
  type: "unknown",
@@ -70153,7 +70924,7 @@ init_secretscan();
70153
70924
  // src/tools/suggest-patch.ts
70154
70925
  init_tool();
70155
70926
  init_create_tool();
70156
- import * as fs58 from "fs";
70927
+ import * as fs59 from "fs";
70157
70928
  import * as path71 from "path";
70158
70929
  var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
70159
70930
  function containsWindowsAttacks4(str) {
@@ -70169,11 +70940,11 @@ function containsWindowsAttacks4(str) {
70169
70940
  function isPathInWorkspace4(filePath, workspace) {
70170
70941
  try {
70171
70942
  const resolvedPath = path71.resolve(workspace, filePath);
70172
- if (!fs58.existsSync(resolvedPath)) {
70943
+ if (!fs59.existsSync(resolvedPath)) {
70173
70944
  return true;
70174
70945
  }
70175
- const realWorkspace = fs58.realpathSync(workspace);
70176
- const realResolvedPath = fs58.realpathSync(resolvedPath);
70946
+ const realWorkspace = fs59.realpathSync(workspace);
70947
+ const realResolvedPath = fs59.realpathSync(resolvedPath);
70177
70948
  const relativePath = path71.relative(realWorkspace, realResolvedPath);
70178
70949
  if (relativePath.startsWith("..") || path71.isAbsolute(relativePath)) {
70179
70950
  return false;
@@ -70347,7 +71118,7 @@ var suggestPatch = createSwarmTool({
70347
71118
  message: "changes cannot be empty"
70348
71119
  }, null, 2);
70349
71120
  }
70350
- if (!fs58.existsSync(directory)) {
71121
+ if (!fs59.existsSync(directory)) {
70351
71122
  return JSON.stringify({
70352
71123
  success: false,
70353
71124
  error: true,
@@ -70384,7 +71155,7 @@ var suggestPatch = createSwarmTool({
70384
71155
  continue;
70385
71156
  }
70386
71157
  const fullPath = path71.resolve(directory, change.file);
70387
- if (!fs58.existsSync(fullPath)) {
71158
+ if (!fs59.existsSync(fullPath)) {
70388
71159
  errors5.push({
70389
71160
  success: false,
70390
71161
  error: true,
@@ -70398,7 +71169,7 @@ var suggestPatch = createSwarmTool({
70398
71169
  }
70399
71170
  let content;
70400
71171
  try {
70401
- content = fs58.readFileSync(fullPath, "utf-8");
71172
+ content = fs59.readFileSync(fullPath, "utf-8");
70402
71173
  } catch (err2) {
70403
71174
  errors5.push({
70404
71175
  success: false,
@@ -70478,7 +71249,7 @@ var suggestPatch = createSwarmTool({
70478
71249
  init_dist();
70479
71250
  init_manager();
70480
71251
  init_detector();
70481
- import * as fs59 from "fs";
71252
+ import * as fs60 from "fs";
70482
71253
  import * as path72 from "path";
70483
71254
  init_create_tool();
70484
71255
  var MAX_FILE_SIZE2 = 5 * 1024 * 1024;
@@ -70575,7 +71346,7 @@ async function syntaxCheck(input, directory, config3) {
70575
71346
  }
70576
71347
  let content;
70577
71348
  try {
70578
- content = fs59.readFileSync(fullPath, "utf8");
71349
+ content = fs60.readFileSync(fullPath, "utf8");
70579
71350
  } catch {
70580
71351
  result.skipped_reason = "file_read_error";
70581
71352
  skippedCount++;
@@ -70655,7 +71426,7 @@ init_test_runner();
70655
71426
  init_dist();
70656
71427
  init_utils();
70657
71428
  init_create_tool();
70658
- import * as fs60 from "fs";
71429
+ import * as fs61 from "fs";
70659
71430
  import * as path73 from "path";
70660
71431
  var MAX_TEXT_LENGTH = 200;
70661
71432
  var MAX_FILE_SIZE_BYTES9 = 1024 * 1024;
@@ -70746,7 +71517,7 @@ function isSupportedExtension(filePath) {
70746
71517
  function findSourceFiles2(dir, files = []) {
70747
71518
  let entries;
70748
71519
  try {
70749
- entries = fs60.readdirSync(dir);
71520
+ entries = fs61.readdirSync(dir);
70750
71521
  } catch {
70751
71522
  return files;
70752
71523
  }
@@ -70758,7 +71529,7 @@ function findSourceFiles2(dir, files = []) {
70758
71529
  const fullPath = path73.join(dir, entry);
70759
71530
  let stat2;
70760
71531
  try {
70761
- stat2 = fs60.statSync(fullPath);
71532
+ stat2 = fs61.statSync(fullPath);
70762
71533
  } catch {
70763
71534
  continue;
70764
71535
  }
@@ -70851,7 +71622,7 @@ var todo_extract = createSwarmTool({
70851
71622
  return JSON.stringify(errorResult, null, 2);
70852
71623
  }
70853
71624
  const scanPath = resolvedPath;
70854
- if (!fs60.existsSync(scanPath)) {
71625
+ if (!fs61.existsSync(scanPath)) {
70855
71626
  const errorResult = {
70856
71627
  error: `path not found: ${pathsInput}`,
70857
71628
  total: 0,
@@ -70861,7 +71632,7 @@ var todo_extract = createSwarmTool({
70861
71632
  return JSON.stringify(errorResult, null, 2);
70862
71633
  }
70863
71634
  const filesToScan = [];
70864
- const stat2 = fs60.statSync(scanPath);
71635
+ const stat2 = fs61.statSync(scanPath);
70865
71636
  if (stat2.isFile()) {
70866
71637
  if (isSupportedExtension(scanPath)) {
70867
71638
  filesToScan.push(scanPath);
@@ -70880,11 +71651,11 @@ var todo_extract = createSwarmTool({
70880
71651
  const allEntries = [];
70881
71652
  for (const filePath of filesToScan) {
70882
71653
  try {
70883
- const fileStat = fs60.statSync(filePath);
71654
+ const fileStat = fs61.statSync(filePath);
70884
71655
  if (fileStat.size > MAX_FILE_SIZE_BYTES9) {
70885
71656
  continue;
70886
71657
  }
70887
- const content = fs60.readFileSync(filePath, "utf-8");
71658
+ const content = fs61.readFileSync(filePath, "utf-8");
70888
71659
  const entries = parseTodoComments(content, filePath, tagsSet);
70889
71660
  allEntries.push(...entries);
70890
71661
  } catch {}
@@ -70913,18 +71684,18 @@ var todo_extract = createSwarmTool({
70913
71684
  init_tool();
70914
71685
  init_schema();
70915
71686
  init_gate_evidence();
70916
- import * as fs62 from "fs";
71687
+ import * as fs63 from "fs";
70917
71688
  import * as path75 from "path";
70918
71689
 
70919
71690
  // src/hooks/diff-scope.ts
70920
- import * as fs61 from "fs";
71691
+ import * as fs62 from "fs";
70921
71692
  import * as path74 from "path";
70922
71693
  function getDeclaredScope(taskId, directory) {
70923
71694
  try {
70924
71695
  const planPath = path74.join(directory, ".swarm", "plan.json");
70925
- if (!fs61.existsSync(planPath))
71696
+ if (!fs62.existsSync(planPath))
70926
71697
  return null;
70927
- const raw = fs61.readFileSync(planPath, "utf-8");
71698
+ const raw = fs62.readFileSync(planPath, "utf-8");
70928
71699
  const plan = JSON.parse(raw);
70929
71700
  for (const phase of plan.phases ?? []) {
70930
71701
  for (const task of phase.tasks ?? []) {
@@ -71002,6 +71773,7 @@ async function validateDiffScope(taskId, directory) {
71002
71773
 
71003
71774
  // src/tools/update-task-status.ts
71004
71775
  init_manager2();
71776
+ init_state();
71005
71777
  init_telemetry();
71006
71778
  init_create_tool();
71007
71779
  var VALID_STATUSES2 = [
@@ -71052,7 +71824,7 @@ function checkReviewerGate(taskId, workingDirectory) {
71052
71824
  const resolvedDir2 = workingDirectory;
71053
71825
  try {
71054
71826
  const planPath = path75.join(resolvedDir2, ".swarm", "plan.json");
71055
- const planRaw = fs62.readFileSync(planPath, "utf-8");
71827
+ const planRaw = fs63.readFileSync(planPath, "utf-8");
71056
71828
  const plan = JSON.parse(planRaw);
71057
71829
  for (const planPhase of plan.phases ?? []) {
71058
71830
  for (const task of planPhase.tasks ?? []) {
@@ -71119,7 +71891,7 @@ function checkReviewerGate(taskId, workingDirectory) {
71119
71891
  try {
71120
71892
  const resolvedDir2 = workingDirectory;
71121
71893
  const planPath = path75.join(resolvedDir2, ".swarm", "plan.json");
71122
- const planRaw = fs62.readFileSync(planPath, "utf-8");
71894
+ const planRaw = fs63.readFileSync(planPath, "utf-8");
71123
71895
  const plan = JSON.parse(planRaw);
71124
71896
  for (const planPhase of plan.phases ?? []) {
71125
71897
  for (const task of planPhase.tasks ?? []) {
@@ -71314,9 +72086,9 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
71314
72086
  }
71315
72087
  const resolvedDir = path75.resolve(normalizedDir);
71316
72088
  try {
71317
- const realPath = fs62.realpathSync(resolvedDir);
72089
+ const realPath = fs63.realpathSync(resolvedDir);
71318
72090
  const planPath = path75.join(realPath, ".swarm", "plan.json");
71319
- if (!fs62.existsSync(planPath)) {
72091
+ if (!fs63.existsSync(planPath)) {
71320
72092
  return {
71321
72093
  success: false,
71322
72094
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -71348,11 +72120,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
71348
72120
  if (args2.status === "in_progress") {
71349
72121
  try {
71350
72122
  const evidencePath = path75.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
71351
- fs62.mkdirSync(path75.dirname(evidencePath), { recursive: true });
71352
- const fd = fs62.openSync(evidencePath, "wx");
72123
+ fs63.mkdirSync(path75.dirname(evidencePath), { recursive: true });
72124
+ const fd = fs63.openSync(evidencePath, "wx");
71353
72125
  let writeOk = false;
71354
72126
  try {
71355
- fs62.writeSync(fd, JSON.stringify({
72127
+ fs63.writeSync(fd, JSON.stringify({
71356
72128
  task_id: args2.task_id,
71357
72129
  required_gates: ["reviewer", "test_engineer"],
71358
72130
  gates: {},
@@ -71360,10 +72132,10 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
71360
72132
  }, null, 2));
71361
72133
  writeOk = true;
71362
72134
  } finally {
71363
- fs62.closeSync(fd);
72135
+ fs63.closeSync(fd);
71364
72136
  if (!writeOk) {
71365
72137
  try {
71366
- fs62.unlinkSync(evidencePath);
72138
+ fs63.unlinkSync(evidencePath);
71367
72139
  } catch {}
71368
72140
  }
71369
72141
  }
@@ -71374,7 +72146,7 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
71374
72146
  let phaseRequiresReviewer = true;
71375
72147
  try {
71376
72148
  const planPath = path75.join(directory, ".swarm", "plan.json");
71377
- const planRaw = fs62.readFileSync(planPath, "utf-8");
72149
+ const planRaw = fs63.readFileSync(planPath, "utf-8");
71378
72150
  const plan = JSON.parse(planRaw);
71379
72151
  const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
71380
72152
  if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
@@ -71472,7 +72244,7 @@ var update_task_status = createSwarmTool({
71472
72244
  init_tool();
71473
72245
  init_utils2();
71474
72246
  init_create_tool();
71475
- import fs63 from "fs";
72247
+ import fs64 from "fs";
71476
72248
  import path76 from "path";
71477
72249
  function normalizeVerdict(verdict) {
71478
72250
  switch (verdict) {
@@ -71533,10 +72305,10 @@ async function executeWriteDriftEvidence(args2, directory) {
71533
72305
  }
71534
72306
  const evidenceDir = path76.dirname(validatedPath);
71535
72307
  try {
71536
- await fs63.promises.mkdir(evidenceDir, { recursive: true });
72308
+ await fs64.promises.mkdir(evidenceDir, { recursive: true });
71537
72309
  const tempPath = path76.join(evidenceDir, `.${filename}.tmp`);
71538
- await fs63.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
71539
- await fs63.promises.rename(tempPath, validatedPath);
72310
+ await fs64.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
72311
+ await fs64.promises.rename(tempPath, validatedPath);
71540
72312
  return JSON.stringify({
71541
72313
  success: true,
71542
72314
  phase,
@@ -71614,6 +72386,14 @@ ${footerLines.join(`
71614
72386
  var _heartbeatTimers = new Map;
71615
72387
  var OpenCodeSwarm = async (ctx) => {
71616
72388
  const { config: config3, loadedFromFile } = loadPluginConfigWithMeta(ctx.directory);
72389
+ if (config3.full_auto?.enabled === true) {
72390
+ const criticModel = config3.full_auto.critic_model ?? config3.agents?.critic?.model ?? DEFAULT_MODELS.critic;
72391
+ const architectModel = config3.agents?.architect?.model ?? DEFAULT_MODELS.default;
72392
+ if (criticModel === architectModel) {
72393
+ console.warn("[opencode-swarm] Full-auto mode warning: critic model matches architect model. Model validation is advisory-only; full-auto remains enabled. (Runtime architect model is determined by the orchestrator)");
72394
+ }
72395
+ }
72396
+ swarmState.fullAutoEnabledInConfig = config3.full_auto?.enabled === true;
71617
72397
  swarmState.opencodeClient = ctx.client;
71618
72398
  await loadSnapshot(ctx.directory);
71619
72399
  initTelemetry(ctx.directory);
@@ -71652,6 +72432,7 @@ var OpenCodeSwarm = async (ctx) => {
71652
72432
  const delegationHandler = createDelegationTrackerHook(config3, guardrailsConfig.enabled);
71653
72433
  const authorityConfig = AuthorityConfigSchema.parse(config3.authority ?? {});
71654
72434
  const guardrailsHooks = createGuardrailsHooks(ctx.directory, undefined, guardrailsConfig, authorityConfig);
72435
+ const fullAutoInterceptHook = createFullAutoInterceptHook(config3, ctx.directory);
71655
72436
  const watchdogConfig = WatchdogConfigSchema.parse(config3.watchdog ?? {});
71656
72437
  const advisoryInjector = (sessionId, message) => {
71657
72438
  const s = swarmState.agentSessions.get(sessionId);
@@ -72034,6 +72815,7 @@ var OpenCodeSwarm = async (ctx) => {
72034
72815
  pipelineHook["experimental.chat.messages.transform"],
72035
72816
  contextBudgetHandler,
72036
72817
  guardrailsHooks.messagesTransform,
72818
+ fullAutoInterceptHook?.messagesTransform,
72037
72819
  delegationGateHooks.messagesTransform,
72038
72820
  delegationSanitizerHook,
72039
72821
  knowledgeInjectorHook,