opencode-swarm 6.50.0 → 6.52.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: false,
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();
@@ -47051,6 +47173,38 @@ async function handleExportCommand(directory, _args) {
47051
47173
  const exportData = await getExportData(directory);
47052
47174
  return formatExportMarkdown(exportData);
47053
47175
  }
47176
+ // src/commands/full-auto.ts
47177
+ init_state();
47178
+ async function handleFullAutoCommand(_directory, args2, sessionID) {
47179
+ if (!sessionID || sessionID.trim() === "") {
47180
+ return "Error: No active session context. Full-Auto Mode requires an active session. Use /swarm full-auto from within an OpenCode session, or start a session first.";
47181
+ }
47182
+ const session = getAgentSession(sessionID);
47183
+ if (!session) {
47184
+ return "Error: No active session. Full-Auto Mode requires an active session to operate.";
47185
+ }
47186
+ const arg = args2[0]?.toLowerCase();
47187
+ let newFullAutoMode;
47188
+ let feedback;
47189
+ if (arg === "on") {
47190
+ newFullAutoMode = true;
47191
+ feedback = "Full-Auto Mode enabled";
47192
+ } else if (arg === "off") {
47193
+ newFullAutoMode = false;
47194
+ feedback = "Full-Auto Mode disabled";
47195
+ } else {
47196
+ newFullAutoMode = !session.fullAutoMode;
47197
+ feedback = newFullAutoMode ? "Full-Auto Mode enabled" : "Full-Auto Mode disabled";
47198
+ }
47199
+ session.fullAutoMode = newFullAutoMode;
47200
+ if (!newFullAutoMode) {
47201
+ session.fullAutoInteractionCount = 0;
47202
+ session.fullAutoDeadlockCount = 0;
47203
+ session.fullAutoLastQuestionHash = null;
47204
+ }
47205
+ return feedback;
47206
+ }
47207
+
47054
47208
  // src/commands/handoff.ts
47055
47209
  init_utils2();
47056
47210
  import crypto4 from "crypto";
@@ -47358,6 +47512,7 @@ function formatHandoffMarkdown(data) {
47358
47512
  }
47359
47513
 
47360
47514
  // src/commands/handoff.ts
47515
+ init_state();
47361
47516
  async function handleHandoffCommand(directory, _args) {
47362
47517
  const handoffData = await getHandoffData(directory);
47363
47518
  const markdown = formatHandoffMarkdown(handoffData);
@@ -48781,6 +48936,7 @@ async function handleResetCommand(directory, args2) {
48781
48936
 
48782
48937
  // src/commands/reset-session.ts
48783
48938
  init_utils2();
48939
+ init_state();
48784
48940
  import * as fs21 from "fs";
48785
48941
  import * as path30 from "path";
48786
48942
  async function handleResetSessionCommand(directory, _args) {
@@ -49429,8 +49585,10 @@ No plan content available. Start by creating a .swarm/plan.md file.
49429
49585
  // src/services/status-service.ts
49430
49586
  init_utils2();
49431
49587
  init_manager2();
49588
+ init_state();
49432
49589
 
49433
49590
  // src/services/compaction-service.ts
49591
+ init_state();
49434
49592
  import * as fs23 from "fs";
49435
49593
  import * as path33 from "path";
49436
49594
  function makeInitialState() {
@@ -49820,6 +49978,7 @@ No active swarm plan found. Nothing to sync.`;
49820
49978
  }
49821
49979
 
49822
49980
  // src/commands/turbo.ts
49981
+ init_state();
49823
49982
  async function handleTurboCommand(_directory, args2, sessionID) {
49824
49983
  if (!sessionID || sessionID.trim() === "") {
49825
49984
  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.";
@@ -50023,6 +50182,10 @@ var COMMAND_REGISTRY = {
50023
50182
  handler: (ctx) => handleTurboCommand(ctx.directory, ctx.args, ctx.sessionID),
50024
50183
  description: "Toggle Turbo Mode for the active session [on|off]"
50025
50184
  },
50185
+ "full-auto": {
50186
+ handler: (ctx) => handleFullAutoCommand(ctx.directory, ctx.args, ctx.sessionID),
50187
+ description: "Toggle Full-Auto Mode for the active session [on|off]"
50188
+ },
50026
50189
  "write-retro": {
50027
50190
  handler: (ctx) => handleWriteRetroCommand(ctx.directory, ctx.args),
50028
50191
  description: "Write a retrospective evidence bundle for a completed phase <json>"
@@ -50083,8 +50246,6 @@ var ARCHITECT_PROMPT = `You are Architect - orchestrator of a multi-agent swarm.
50083
50246
  Swarm: {{SWARM_ID}}
50084
50247
  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
50248
 
50086
- {{TURBO_MODE_BANNER}}
50087
-
50088
50249
  ## PROJECT CONTEXT
50089
50250
  Session-start priming block. Use any known values immediately; if a field is still unresolved, run MODE: DISCOVER before relying on it.
50090
50251
  Language: {{PROJECT_LANGUAGE}}
@@ -51112,29 +51273,6 @@ ${customAppendPrompt}`;
51112
51273
  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
51274
  \u2192 REQUIRED: Print "testengineer-adversarial: [PASS | FAIL \u2014 details]"`)?.replace(/\{\{ADVERSARIAL_TEST_CHECKLIST\}\}/g, " [GATE] test_engineer-adversarial: PASS / FAIL \u2014 value: ___");
51114
51275
  }
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
51276
  return {
51139
51277
  name: "architect",
51140
51278
  description: "Central orchestrator of the development pipeline. Analyzes requests, coordinates SME consultation, manages code generation, and triages QA feedback.",
@@ -51594,6 +51732,90 @@ RULES:
51594
51732
  - Report the first deviation point, not all downstream consequences
51595
51733
  - VERDICT is APPROVED only if ALL tasks are VERIFIED with no DRIFT
51596
51734
  `;
51735
+ var AUTONOMOUS_OVERSIGHT_PROMPT = `## AUTONOMOUS OVERSIGHT MODE
51736
+
51737
+ 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.
51738
+
51739
+ ## CONSTITUTION
51740
+
51741
+ These rules are absolute. You cannot override, relax, or reinterpret them.
51742
+
51743
+ 1. DEFAULT POSTURE IS REJECT. You approve only when you have positive evidence of correctness. Absence of problems is not evidence of quality.
51744
+ 2. CROSS-VERIFY EVERYTHING. Do not trust the architect's summary. Read the actual files, evidence, plan, and test results yourself.
51745
+ 3. NO RUBBER-STAMPING. If you cannot articulate exactly what you verified and why it's correct, your verdict is REJECT.
51746
+ 4. SCOPE CONTAINMENT. If work was done outside the plan scope, REJECT. Scope creep in autonomous mode is a critical failure.
51747
+ 5. EVIDENCE OVER CLAIMS. The architect may claim tests pass, reviews succeeded, or gates cleared. Verify the evidence files exist and contain valid data.
51748
+ 6. ESCALATE UNCERTAINTY. If you are uncertain about a product/design decision (not a technical one), respond with ESCALATE_TO_HUMAN instead of guessing.
51749
+ 7. GATE COMPLETENESS. Every task must have: (a) implementation evidence, (b) review evidence with verdict, (c) test evidence with pass/fail. Missing any = REJECT.
51750
+ 8. REGRESSION AWARENESS. If the architect claims a fix, verify it doesn't break something else. Check for test results beyond the changed files.
51751
+ 9. DEPENDENCY VIGILANCE. Any new dependency must be verified as a real package. Any phantom dependency = CRITICAL REJECT.
51752
+ 10. SECURITY BOUNDARY. Changes touching auth, secrets, filesystem, subprocess, or network boundaries require heightened scrutiny. Missing validation at any trust boundary = REJECT.
51753
+
51754
+ ## VERIFICATION PROTOCOL
51755
+
51756
+ For every decision point, execute the relevant protocol:
51757
+
51758
+ ### Plan Review
51759
+ 1. Read .swarm/plan.md and .swarm/spec.md (if exists)
51760
+ 2. For each task: verify it has a clear objective, target file, and acceptance criteria
51761
+ 3. Check dependency ordering \u2014 no task should depend on a later task's output
51762
+ 4. Check scope containment \u2014 every task maps to a stated requirement
51763
+ 5. Flag any task that touches 6+ files or mixes unrelated concerns
51764
+ VERDICT: APPROVED | NEEDS_REVISION | REJECTED
51765
+
51766
+ ### Task Completion Review
51767
+ 1. Read the evidence bundle for the task
51768
+ 2. Verify review evidence exists with a non-rubber-stamp verdict
51769
+ 3. Verify test evidence exists with PASS status
51770
+ 4. Verify the diff is contained to the stated scope
51771
+ 5. Check for unplanned side effects in other files
51772
+ VERDICT: APPROVED | BLOCKED \u2014 [reason]
51773
+
51774
+ ### Phase Completion Review
51775
+ 1. Verify ALL tasks in the phase are marked completed with evidence
51776
+ 2. Verify retrospective evidence exists with lessons learned
51777
+ 3. Verify drift check evidence exists (if spec.md present)
51778
+ 4. Verify regression sweep results exist
51779
+ 5. Cross-reference: do completed tasks match the plan? Any dropped? Any added?
51780
+ 6. Check: was the reviewer dispatched at least once this phase?
51781
+ VERDICT: APPROVED | BLOCKED \u2014 [missing items]
51782
+
51783
+ ### Question Resolution
51784
+ When the architect asks a question:
51785
+ 1. Determine if this is a TECHNICAL question or a PRODUCT/DESIGN question
51786
+ 2. TECHNICAL: answer it directly using your knowledge of the codebase, plan, and spec
51787
+ 3. PRODUCT/DESIGN: respond with ESCALATE_TO_HUMAN \u2014 you do not make product decisions
51788
+ 4. AMBIGUOUS: ask the architect to rephrase with more context before answering
51789
+ VERDICT: ANSWER | ESCALATE_TO_HUMAN | REPHRASE
51790
+
51791
+ ## SELF-CRITIQUE
51792
+
51793
+ After generating your initial verdict, check yourself:
51794
+ 1. Did you check every item in the protocol, or did you skip steps?
51795
+ 2. If APPROVED: argue against yourself. What could go wrong that you didn't check?
51796
+ 3. If REJECTED: is the rejection grounded in a specific rule number, or is it vague unease?
51797
+ If the self-critique changes your verdict, update it.
51798
+
51799
+ ## ANTI-PATTERNS
51800
+
51801
+ Watch for these architect behaviors \u2014 any detected = immediate REJECT:
51802
+ - Skipping reviewer delegation ("this is a simple change")
51803
+ - Batching multiple tasks into one coder call
51804
+ - Marking tasks complete without evidence
51805
+ - Relaxing test requirements ("tests are flaky, skipping")
51806
+ - Scope expansion ("while we're here, let's also...")
51807
+ - Self-approving ("I verified this myself")
51808
+ - Pressure language ("we need to move fast", "this is blocking")
51809
+
51810
+ ## OUTPUT FORMAT
51811
+
51812
+ Every response MUST use this structure:
51813
+
51814
+ VERDICT: APPROVED | NEEDS_REVISION | REJECTED | BLOCKED | ANSWER | ESCALATE_TO_HUMAN | REPHRASE
51815
+ REASONING: [2-4 sentences \u2014 what you verified and why]
51816
+ EVIDENCE_CHECKED: [list of files/artifacts you read]
51817
+ ANTI_PATTERNS_DETECTED: [list or "none"]
51818
+ ESCALATION_NEEDED: YES | NO`;
51597
51819
  function createCriticAgent(model, customPrompt, customAppendPrompt, role = "plan_critic") {
51598
51820
  let prompt;
51599
51821
  if (customPrompt) {
@@ -51634,6 +51856,25 @@ ${customAppendPrompt}` : rolePrompt;
51634
51856
  }
51635
51857
  };
51636
51858
  }
51859
+ function createCriticAutonomousOversightAgent(model, customAppendPrompt) {
51860
+ const prompt = customAppendPrompt ? `${AUTONOMOUS_OVERSIGHT_PROMPT}
51861
+
51862
+ ${customAppendPrompt}` : AUTONOMOUS_OVERSIGHT_PROMPT;
51863
+ return {
51864
+ name: "critic_oversight",
51865
+ description: "Critic in AUTONOMOUS OVERSIGHT mode \u2014 sole quality gate in full-auto.",
51866
+ config: {
51867
+ model,
51868
+ temperature: 0.1,
51869
+ prompt,
51870
+ tools: {
51871
+ write: false,
51872
+ edit: false,
51873
+ patch: false
51874
+ }
51875
+ }
51876
+ };
51877
+ }
51637
51878
 
51638
51879
  // src/agents/curator-agent.ts
51639
51880
  var ROLE_CONFIG = {
@@ -52624,6 +52865,11 @@ If you call @coder instead of @${swarmId}_coder, the call will FAIL or go to the
52624
52865
  critic.name = prefixName("critic_drift_verifier");
52625
52866
  agents.push(applyOverrides(critic, swarmAgents, swarmPrefix));
52626
52867
  }
52868
+ if (!isAgentDisabled("critic_oversight", swarmAgents, swarmPrefix)) {
52869
+ const critic = createCriticAutonomousOversightAgent(swarmAgents?.critic_oversight?.model ?? getModel("critic"));
52870
+ critic.name = prefixName("critic_oversight");
52871
+ agents.push(applyOverrides(critic, swarmAgents, swarmPrefix));
52872
+ }
52627
52873
  if (!isAgentDisabled("curator_init", swarmAgents, swarmPrefix)) {
52628
52874
  const curatorInitPrompts = getPrompts("curator_init");
52629
52875
  const curatorInit = createCuratorAgent(swarmAgents?.curator_init?.model ?? getModel("explorer"), curatorInitPrompts.prompt, curatorInitPrompts.appendPrompt, "curator_init");
@@ -53065,10 +53311,11 @@ init_constants();
53065
53311
  init_schema();
53066
53312
 
53067
53313
  // src/hooks/agent-activity.ts
53068
- import { renameSync as renameSync9, unlinkSync as unlinkSync4 } from "fs";
53069
- import * as nodePath2 from "path";
53314
+ init_state();
53070
53315
  init_utils();
53071
53316
  init_utils2();
53317
+ import { renameSync as renameSync9, unlinkSync as unlinkSync4 } from "fs";
53318
+ import * as nodePath2 from "path";
53072
53319
  function createAgentActivityHooks(config3, directory) {
53073
53320
  if (config3.hooks?.agent_activity === false) {
53074
53321
  return {
@@ -53722,6 +53969,7 @@ function maskToolOutput(msg, _threshold) {
53722
53969
  return freedTokens;
53723
53970
  }
53724
53971
  // src/hooks/curator-llm-factory.ts
53972
+ init_state();
53725
53973
  function resolveCuratorAgentName(mode, sessionId) {
53726
53974
  const suffix = mode === "init" ? "curator_init" : "curator_phase";
53727
53975
  const registeredNames = mode === "init" ? swarmState.curatorInitAgentNames : swarmState.curatorPhaseAgentNames;
@@ -53881,6 +54129,7 @@ function shouldParallelizeReview(routing) {
53881
54129
  }
53882
54130
 
53883
54131
  // src/hooks/delegation-gate.ts
54132
+ init_state();
53884
54133
  init_telemetry();
53885
54134
 
53886
54135
  // src/hooks/guardrails.ts
@@ -53949,10 +54198,12 @@ function classifyFile(filePath) {
53949
54198
 
53950
54199
  // src/hooks/guardrails.ts
53951
54200
  init_manager2();
54201
+ init_state();
53952
54202
  init_telemetry();
53953
54203
  init_utils();
53954
54204
 
53955
54205
  // src/hooks/loop-detector.ts
54206
+ init_state();
53956
54207
  function hashDelegation(toolName, args2) {
53957
54208
  const targetAgent = typeof args2?.subagent_type === "string" ? args2.subagent_type : "unknown";
53958
54209
  const firstArgKey = args2 != null ? Object.keys(args2)[0] ?? "noargs" : "noargs";
@@ -55797,6 +56048,7 @@ function createDelegationSanitizerHook(directory) {
55797
56048
  // src/hooks/delegation-tracker.ts
55798
56049
  init_constants();
55799
56050
  init_schema();
56051
+ init_state();
55800
56052
  function createDelegationTrackerHook(config3, guardrailsEnabled = true) {
55801
56053
  return async (input, _output) => {
55802
56054
  const now = Date.now();
@@ -55842,6 +56094,562 @@ function createDelegationTrackerHook(config3, guardrailsEnabled = true) {
55842
56094
  }
55843
56095
  };
55844
56096
  }
56097
+ // src/hooks/full-auto-intercept.ts
56098
+ import * as fs30 from "fs";
56099
+ init_schema();
56100
+
56101
+ // src/parallel/file-locks.ts
56102
+ var import_proper_lockfile3 = __toESM(require_proper_lockfile(), 1);
56103
+ import * as fs29 from "fs";
56104
+ import * as path40 from "path";
56105
+ var LOCKS_DIR = ".swarm/locks";
56106
+ var LOCK_TIMEOUT_MS = 5 * 60 * 1000;
56107
+ function getLockFilePath(directory, filePath) {
56108
+ const normalized = path40.resolve(directory, filePath);
56109
+ if (!normalized.startsWith(path40.resolve(directory))) {
56110
+ throw new Error("Invalid file path: path traversal not allowed");
56111
+ }
56112
+ const hash3 = Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
56113
+ return path40.join(directory, LOCKS_DIR, `${hash3}.lock`);
56114
+ }
56115
+ async function tryAcquireLock(directory, filePath, agent, taskId) {
56116
+ const lockPath = getLockFilePath(directory, filePath);
56117
+ const locksDir = path40.dirname(lockPath);
56118
+ if (!fs29.existsSync(locksDir)) {
56119
+ fs29.mkdirSync(locksDir, { recursive: true });
56120
+ }
56121
+ if (!fs29.existsSync(lockPath)) {
56122
+ fs29.writeFileSync(lockPath, "", "utf-8");
56123
+ }
56124
+ let release;
56125
+ try {
56126
+ release = await import_proper_lockfile3.default.lock(lockPath, {
56127
+ stale: LOCK_TIMEOUT_MS,
56128
+ retries: { retries: 0 },
56129
+ realpath: false
56130
+ });
56131
+ } catch (err2) {
56132
+ const code = err2.code;
56133
+ if (code === "ELOCKED" || code === "EEXIST") {
56134
+ return { acquired: false };
56135
+ }
56136
+ throw err2;
56137
+ }
56138
+ const lock = {
56139
+ filePath,
56140
+ agent,
56141
+ taskId,
56142
+ timestamp: new Date().toISOString(),
56143
+ expiresAt: Date.now() + LOCK_TIMEOUT_MS,
56144
+ _release: release
56145
+ };
56146
+ return { acquired: true, lock };
56147
+ }
56148
+
56149
+ // src/hooks/full-auto-intercept.ts
56150
+ init_state();
56151
+ init_telemetry();
56152
+ init_utils2();
56153
+ var END_OF_SENTENCE_QUESTION_PATTERN = /\?\s*$/;
56154
+ var ESCALATION_PATTERNS = [
56155
+ /Ready for Phase (?:\d+|\[?N\+1\]?)\?/i,
56156
+ /escalat/i,
56157
+ /What would you like/i,
56158
+ /Should I proceed/i,
56159
+ /Do you want/i
56160
+ ];
56161
+ var MID_SENTENCE_QUESTION_PATTERNS = [
56162
+ /\b(v\d+\?)/i,
56163
+ /\b(v\d+\.\d+\?)/i,
56164
+ /\bAPI\?/i,
56165
+ /\bOK\?/i,
56166
+ /\b\d+\?\d+/
56167
+ ];
56168
+ function hashString(str) {
56169
+ let hash3 = 5381;
56170
+ for (let i2 = 0;i2 < str.length; i2++) {
56171
+ hash3 = (hash3 << 5) + hash3 + str.charCodeAt(i2);
56172
+ hash3 = hash3 & hash3;
56173
+ }
56174
+ return Math.abs(hash3).toString(36);
56175
+ }
56176
+ function isMidSentenceQuestion(text) {
56177
+ return MID_SENTENCE_QUESTION_PATTERNS.some((pattern) => pattern.test(text));
56178
+ }
56179
+ function resolveOversightAgentName(architectAgentName) {
56180
+ if (!architectAgentName) {
56181
+ return "critic_oversight";
56182
+ }
56183
+ const stripped = stripKnownSwarmPrefix(architectAgentName);
56184
+ if (stripped !== "architect") {
56185
+ return "critic_oversight";
56186
+ }
56187
+ const baseRole = "architect";
56188
+ const lastIndex = architectAgentName.toLowerCase().lastIndexOf(baseRole);
56189
+ if (lastIndex <= 0) {
56190
+ return "critic_oversight";
56191
+ }
56192
+ const prefix = architectAgentName.slice(0, lastIndex);
56193
+ return `${prefix}critic_oversight`;
56194
+ }
56195
+ function detectEscalation(text) {
56196
+ for (const pattern of ESCALATION_PATTERNS) {
56197
+ if (pattern.test(text)) {
56198
+ return "phase_completion";
56199
+ }
56200
+ }
56201
+ if (END_OF_SENTENCE_QUESTION_PATTERN.test(text)) {
56202
+ if (!isMidSentenceQuestion(text)) {
56203
+ return "question";
56204
+ }
56205
+ }
56206
+ return null;
56207
+ }
56208
+ function extractMessageText3(message) {
56209
+ if (!message?.parts)
56210
+ return "";
56211
+ const textParts = message.parts.filter((p) => p?.type === "text" && p.text);
56212
+ return textParts.map((p) => p.text ?? "").join(`
56213
+ `);
56214
+ }
56215
+ function parseCriticResponse(rawResponse) {
56216
+ const result = {
56217
+ verdict: "NEEDS_REVISION",
56218
+ reasoning: "",
56219
+ evidenceChecked: [],
56220
+ antiPatternsDetected: [],
56221
+ escalationNeeded: false,
56222
+ rawResponse
56223
+ };
56224
+ const lines = rawResponse.split(`
56225
+ `);
56226
+ let currentKey = "";
56227
+ let currentValue = "";
56228
+ const commitField = (res, key, value) => {
56229
+ switch (key) {
56230
+ case "VERDICT": {
56231
+ const validVerdicts = [
56232
+ "APPROVED",
56233
+ "NEEDS_REVISION",
56234
+ "REJECTED",
56235
+ "BLOCKED",
56236
+ "ANSWER",
56237
+ "ESCALATE_TO_HUMAN",
56238
+ "REPHRASE"
56239
+ ];
56240
+ const normalized = value.trim().toUpperCase().replace(/[`*]/g, "");
56241
+ if (validVerdicts.includes(normalized)) {
56242
+ res.verdict = normalized;
56243
+ } else {
56244
+ console.warn(`[full-auto-intercept] Unknown verdict '${value}' \u2014 defaulting to NEEDS_REVISION`);
56245
+ res.verdict = "NEEDS_REVISION";
56246
+ }
56247
+ break;
56248
+ }
56249
+ case "REASONING":
56250
+ res.reasoning = value.trim();
56251
+ break;
56252
+ case "EVIDENCE_CHECKED":
56253
+ if (value && value !== "none" && value !== '"none"') {
56254
+ res.evidenceChecked = value.split(",").map((s) => s.trim()).filter(Boolean);
56255
+ }
56256
+ break;
56257
+ case "ANTI_PATTERNS_DETECTED":
56258
+ if (value && value !== "none" && value !== '"none"') {
56259
+ res.antiPatternsDetected = value.split(",").map((s) => s.trim()).filter(Boolean);
56260
+ }
56261
+ break;
56262
+ case "ESCALATION_NEEDED":
56263
+ res.escalationNeeded = value.trim().toUpperCase() === "YES";
56264
+ break;
56265
+ }
56266
+ };
56267
+ for (const line of lines) {
56268
+ const colonIndex = line.indexOf(":");
56269
+ if (colonIndex !== -1) {
56270
+ const key = line.slice(0, colonIndex).trim().toUpperCase();
56271
+ if ([
56272
+ "VERDICT",
56273
+ "REASONING",
56274
+ "EVIDENCE_CHECKED",
56275
+ "ANTI_PATTERNS_DETECTED",
56276
+ "ESCALATION_NEEDED"
56277
+ ].includes(key)) {
56278
+ if (currentKey) {
56279
+ commitField(result, currentKey, currentValue);
56280
+ }
56281
+ currentKey = key;
56282
+ currentValue = line.slice(colonIndex + 1).trim();
56283
+ } else {
56284
+ currentValue += `
56285
+ ${line}`;
56286
+ }
56287
+ } else {
56288
+ if (line.trim()) {
56289
+ currentValue += `
56290
+ ${line}`;
56291
+ }
56292
+ }
56293
+ }
56294
+ if (currentKey) {
56295
+ commitField(result, currentKey, currentValue);
56296
+ }
56297
+ return result;
56298
+ }
56299
+ function escalationTypeToInteractionMode(escalationType) {
56300
+ return escalationType === "phase_completion" ? "phase_completion" : "question_resolution";
56301
+ }
56302
+ async function writeAutoOversightEvent(directory, architectOutput, criticVerdict, criticReasoning, evidenceChecked, interactionCount, deadlockCount, escalationType) {
56303
+ const event = {
56304
+ type: "auto_oversight",
56305
+ timestamp: new Date().toISOString(),
56306
+ interaction_mode: escalationTypeToInteractionMode(escalationType),
56307
+ architect_output: architectOutput,
56308
+ critic_verdict: criticVerdict,
56309
+ critic_reasoning: criticReasoning,
56310
+ evidence_checked: evidenceChecked,
56311
+ interaction_count: interactionCount,
56312
+ deadlock_count: deadlockCount
56313
+ };
56314
+ const lockTaskId = `auto-oversight-${Date.now()}`;
56315
+ const eventsFilePath = "events.jsonl";
56316
+ const dir = directory;
56317
+ let lockResult;
56318
+ try {
56319
+ lockResult = await tryAcquireLock(dir, eventsFilePath, "auto-oversight", lockTaskId);
56320
+ } catch (error93) {
56321
+ console.warn(`[full-auto-intercept] Warning: failed to acquire lock for auto_oversight event: ${error93 instanceof Error ? error93.message : String(error93)}`);
56322
+ }
56323
+ if (!lockResult?.acquired) {
56324
+ console.warn(`[full-auto-intercept] Warning: could not acquire lock for events.jsonl write \u2014 proceeding without lock`);
56325
+ }
56326
+ try {
56327
+ const eventsPath = validateSwarmPath(dir, "events.jsonl");
56328
+ fs30.appendFileSync(eventsPath, `${JSON.stringify(event)}
56329
+ `, "utf-8");
56330
+ } catch (writeError) {
56331
+ console.error(`[full-auto-intercept] Warning: failed to write auto_oversight event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
56332
+ } finally {
56333
+ if (lockResult?.acquired && lockResult.lock._release) {
56334
+ try {
56335
+ await lockResult.lock._release();
56336
+ } catch (releaseError) {
56337
+ console.error(`[full-auto-intercept] Lock release failed:`, releaseError);
56338
+ }
56339
+ }
56340
+ }
56341
+ }
56342
+ function injectVerdictIntoMessages(messages, architectIndex, criticResult, _escalationType, oversightAgentName) {
56343
+ if (criticResult.escalationNeeded || criticResult.verdict === "ESCALATE_TO_HUMAN") {
56344
+ const verdictMessage2 = {
56345
+ info: {
56346
+ role: "assistant",
56347
+ agent: oversightAgentName
56348
+ },
56349
+ parts: [
56350
+ {
56351
+ type: "text",
56352
+ text: `[FULL-AUTO OVERSIGHT \u2014 ESCALATE_TO_HUMAN]
56353
+
56354
+ Critic reasoning: ${criticResult.reasoning}
56355
+
56356
+ This question requires human judgment. The swarm has been paused for human review.`
56357
+ }
56358
+ ]
56359
+ };
56360
+ messages.splice(architectIndex + 1, 0, verdictMessage2);
56361
+ return;
56362
+ }
56363
+ if (criticResult.verdict === "ANSWER") {
56364
+ const verdictMessage2 = {
56365
+ info: {
56366
+ role: "assistant",
56367
+ agent: oversightAgentName
56368
+ },
56369
+ parts: [
56370
+ {
56371
+ type: "text",
56372
+ text: `[FULL-AUTO OVERSIGHT \u2014 ANSWER]
56373
+
56374
+ ${criticResult.reasoning}`
56375
+ }
56376
+ ]
56377
+ };
56378
+ messages.splice(architectIndex + 1, 0, verdictMessage2);
56379
+ return;
56380
+ }
56381
+ const verdictEmoji = criticResult.verdict === "APPROVED" ? "\u2705" : criticResult.verdict === "NEEDS_REVISION" ? "\uD83D\uDD04" : criticResult.verdict === "REJECTED" ? "\u274C" : criticResult.verdict === "BLOCKED" ? "\uD83D\uDEAB" : "\uD83D\uDCAC";
56382
+ const verdictMessage = {
56383
+ info: {
56384
+ role: "assistant",
56385
+ agent: oversightAgentName
56386
+ },
56387
+ parts: [
56388
+ {
56389
+ type: "text",
56390
+ text: `[FULL-AUTO OVERSIGHT] ${verdictEmoji} **${criticResult.verdict}**
56391
+
56392
+ Critic reasoning: ${criticResult.reasoning}`
56393
+ }
56394
+ ]
56395
+ };
56396
+ messages.splice(architectIndex + 1, 0, verdictMessage);
56397
+ }
56398
+ async function dispatchCriticAndWriteEvent(directory, architectOutput, criticContext, criticModel, escalationType, interactionCount, deadlockCount, oversightAgentName) {
56399
+ const client = swarmState.opencodeClient;
56400
+ if (!client) {
56401
+ console.warn("[full-auto-intercept] No opencodeClient \u2014 critic dispatch skipped (fallback to PENDING)");
56402
+ const result = {
56403
+ verdict: "PENDING",
56404
+ reasoning: "No opencodeClient available \u2014 critic dispatch not possible",
56405
+ evidenceChecked: [],
56406
+ antiPatternsDetected: [],
56407
+ escalationNeeded: false,
56408
+ rawResponse: ""
56409
+ };
56410
+ await writeAutoOversightEvent(directory, architectOutput, result.verdict, result.reasoning, result.evidenceChecked, interactionCount, deadlockCount, escalationType);
56411
+ return result;
56412
+ }
56413
+ const oversightAgent = createCriticAutonomousOversightAgent(criticModel, criticContext);
56414
+ console.log(`[full-auto-intercept] Dispatching critic: ${oversightAgent.name} using model ${criticModel}`);
56415
+ let ephemeralSessionId;
56416
+ const cleanup = () => {
56417
+ if (ephemeralSessionId) {
56418
+ const id = ephemeralSessionId;
56419
+ ephemeralSessionId = undefined;
56420
+ client.session.delete({ path: { id } }).catch(() => {});
56421
+ }
56422
+ };
56423
+ let criticResponse = "";
56424
+ try {
56425
+ const createResult = await client.session.create({
56426
+ query: { directory }
56427
+ });
56428
+ if (!createResult.data) {
56429
+ throw new Error(`Failed to create critic session: ${JSON.stringify(createResult.error)}`);
56430
+ }
56431
+ ephemeralSessionId = createResult.data.id;
56432
+ console.log(`[full-auto-intercept] Created ephemeral session: ${ephemeralSessionId}`);
56433
+ const promptResult = await client.session.prompt({
56434
+ path: { id: ephemeralSessionId },
56435
+ body: {
56436
+ agent: oversightAgentName,
56437
+ tools: { write: false, edit: false, patch: false },
56438
+ parts: [{ type: "text", text: criticContext }]
56439
+ }
56440
+ });
56441
+ if (!promptResult.data) {
56442
+ throw new Error(`Critic LLM prompt failed: ${JSON.stringify(promptResult.error)}`);
56443
+ }
56444
+ const textParts = promptResult.data.parts.filter((p) => p.type === "text");
56445
+ criticResponse = textParts.map((p) => p.text).join(`
56446
+ `);
56447
+ console.log(`[full-auto-intercept] Critic response received (${criticResponse.length} chars)`);
56448
+ if (!criticResponse.trim()) {
56449
+ console.warn("[full-auto-intercept] Critic returned empty response \u2014 using fallback verdict");
56450
+ criticResponse = `VERDICT: NEEDS_REVISION
56451
+ REASONING: Critic returned empty response
56452
+ EVIDENCE_CHECKED: none
56453
+ ANTI_PATTERNS_DETECTED: empty_response
56454
+ ESCALATION_NEEDED: NO`;
56455
+ }
56456
+ } finally {
56457
+ cleanup();
56458
+ }
56459
+ let parsed;
56460
+ try {
56461
+ parsed = parseCriticResponse(criticResponse);
56462
+ console.log(`[full-auto-intercept] Critic verdict: ${parsed.verdict} | escalation: ${parsed.escalationNeeded}`);
56463
+ } catch (parseError) {
56464
+ console.error(`[full-auto-intercept] Failed to parse critic response: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
56465
+ parsed = {
56466
+ verdict: "NEEDS_REVISION",
56467
+ reasoning: "Critic response parsing failed \u2014 defaulting to NEEDS_REVISION",
56468
+ evidenceChecked: [],
56469
+ antiPatternsDetected: [],
56470
+ escalationNeeded: false,
56471
+ rawResponse: criticResponse
56472
+ };
56473
+ }
56474
+ try {
56475
+ await writeAutoOversightEvent(directory, architectOutput, parsed.verdict, parsed.reasoning, parsed.evidenceChecked, interactionCount, deadlockCount, escalationType);
56476
+ } catch (writeError) {
56477
+ console.error(`[full-auto-intercept] Failed to write auto_oversight event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
56478
+ }
56479
+ return parsed;
56480
+ }
56481
+ function createFullAutoInterceptHook(config3, directory) {
56482
+ const fullAutoConfig = config3.full_auto ?? {
56483
+ enabled: false,
56484
+ max_interactions_per_phase: 50,
56485
+ deadlock_threshold: 3,
56486
+ escalation_mode: "pause"
56487
+ };
56488
+ if (fullAutoConfig.enabled !== true) {
56489
+ return {
56490
+ messagesTransform: async () => {}
56491
+ };
56492
+ }
56493
+ const deadlockThreshold = fullAutoConfig.deadlock_threshold ?? 3;
56494
+ const maxInteractions = fullAutoConfig.max_interactions_per_phase ?? 50;
56495
+ const escalationMode = fullAutoConfig.escalation_mode ?? "pause";
56496
+ const messagesTransform = async (_input, output) => {
56497
+ const messages = output.messages;
56498
+ if (!messages || messages.length === 0)
56499
+ return;
56500
+ let lastArchitectMessageIndex = -1;
56501
+ for (let i2 = messages.length - 1;i2 >= 0; i2--) {
56502
+ const msg = messages[i2];
56503
+ if (msg?.info?.role === "user") {
56504
+ const agent = msg.info?.agent;
56505
+ const strippedAgent = agent ? stripKnownSwarmPrefix(agent) : undefined;
56506
+ if (!agent || strippedAgent === "architect") {
56507
+ lastArchitectMessageIndex = i2;
56508
+ break;
56509
+ }
56510
+ }
56511
+ }
56512
+ if (lastArchitectMessageIndex === -1)
56513
+ return;
56514
+ const architectMessage = messages[lastArchitectMessageIndex];
56515
+ const architectText = extractMessageText3(architectMessage);
56516
+ if (!architectText)
56517
+ return;
56518
+ const sessionID = architectMessage.info?.sessionID;
56519
+ if (!hasActiveFullAuto(sessionID))
56520
+ return;
56521
+ let session = null;
56522
+ if (sessionID) {
56523
+ const { ensureAgentSession: ensureAgentSession2 } = await Promise.resolve().then(() => (init_state(), exports_state));
56524
+ session = ensureAgentSession2(sessionID);
56525
+ }
56526
+ if (session) {
56527
+ const interactionCount = session.fullAutoInteractionCount ?? 0;
56528
+ if (interactionCount >= maxInteractions) {
56529
+ const escalated = await handleEscalation(directory, "interaction_limit", sessionID, architectText, interactionCount, session.fullAutoDeadlockCount ?? 0, escalationMode);
56530
+ if (escalated)
56531
+ return;
56532
+ }
56533
+ }
56534
+ const escalationType = detectEscalation(architectText);
56535
+ if (!escalationType)
56536
+ return;
56537
+ if (session) {
56538
+ session.fullAutoInteractionCount = (session.fullAutoInteractionCount ?? 0) + 1;
56539
+ }
56540
+ if (escalationType === "question") {
56541
+ const questionHash = hashString(architectText.trim());
56542
+ if (session) {
56543
+ const lastQuestionHash = session.fullAutoLastQuestionHash;
56544
+ if (lastQuestionHash === questionHash) {
56545
+ session.fullAutoDeadlockCount = (session.fullAutoDeadlockCount ?? 0) + 1;
56546
+ console.warn(`[full-auto-intercept] Potential deadlock detected (count: ${session.fullAutoDeadlockCount}/${deadlockThreshold}) \u2014 identical question repeated`);
56547
+ if (session.fullAutoDeadlockCount >= deadlockThreshold) {
56548
+ const escalated = await handleEscalation(directory, "deadlock", sessionID, architectText, session.fullAutoInteractionCount ?? 0, session.fullAutoDeadlockCount, escalationMode);
56549
+ if (escalated)
56550
+ return;
56551
+ }
56552
+ } else {
56553
+ session.fullAutoDeadlockCount = 0;
56554
+ }
56555
+ session.fullAutoLastQuestionHash = questionHash;
56556
+ }
56557
+ }
56558
+ console.log(`[full-auto-intercept] Escalation detected (${escalationType}) \u2014 triggering autonomous oversight`);
56559
+ const criticContext = buildCriticContext(architectText, escalationType);
56560
+ const criticModel = fullAutoConfig.critic_model ?? "claude-sonnet-4-20250514";
56561
+ const oversightAgent = createCriticAutonomousOversightAgent(criticModel, criticContext);
56562
+ const architectAgent = architectMessage.info?.agent;
56563
+ const resolvedOversightAgentName = resolveOversightAgentName(architectAgent);
56564
+ const dispatchAgentName = resolvedOversightAgentName && resolvedOversightAgentName.length > 0 ? resolvedOversightAgentName : "critic_oversight";
56565
+ console.log(`[full-auto-intercept] Created autonomous oversight agent: ${oversightAgent.name} using model ${criticModel} (dispatch as: ${dispatchAgentName})`);
56566
+ const criticResult = await dispatchCriticAndWriteEvent(directory, architectText, criticContext, criticModel, escalationType, session?.fullAutoInteractionCount ?? 0, session?.fullAutoDeadlockCount ?? 0, dispatchAgentName);
56567
+ injectVerdictIntoMessages(messages, lastArchitectMessageIndex, criticResult, escalationType, dispatchAgentName);
56568
+ };
56569
+ return {
56570
+ messagesTransform
56571
+ };
56572
+ }
56573
+ function buildCriticContext(architectOutput, escalationType) {
56574
+ const contextHeader = escalationType === "phase_completion" ? `## ARCHITECT PHASE COMPLETION REQUEST
56575
+
56576
+ The architect has signaled phase completion and is awaiting oversight approval to proceed.` : `## ARCHITECT QUESTION
56577
+
56578
+ The architect has asked a question and is awaiting an autonomous answer or escalation.`;
56579
+ const truncatedOutput = architectOutput.length > 2000 ? architectOutput.slice(0, 2000) + `
56580
+ ... [truncated]` : architectOutput;
56581
+ return `${contextHeader}
56582
+
56583
+ ### ARCHITECT OUTPUT:
56584
+ ${truncatedOutput}
56585
+
56586
+ ### YOUR TASK:
56587
+ 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.
56588
+
56589
+ Remember: You are the sole quality gate. Default posture is REJECT unless you have positive evidence of correctness.`;
56590
+ }
56591
+ async function writeEscalationReport(directory, reason, architectOutput, interactionCount, deadlockCount, phase) {
56592
+ try {
56593
+ const reportPath = validateSwarmPath(directory, "escalation-report.md");
56594
+ let currentPhase = phase;
56595
+ if (currentPhase === undefined) {
56596
+ try {
56597
+ const planPath = validateSwarmPath(directory, "plan.json");
56598
+ const planContent = fs30.readFileSync(planPath, "utf-8");
56599
+ const plan = JSON.parse(planContent);
56600
+ const incompletePhases = plan.phases.filter((p) => p.status !== "complete").sort((a, b) => b.id - a.id);
56601
+ currentPhase = incompletePhases[0]?.id;
56602
+ } catch {}
56603
+ }
56604
+ const timestamp = new Date().toISOString();
56605
+ const reasonLabels = {
56606
+ interaction_limit: "Interaction Limit Exceeded",
56607
+ deadlock: "Deadlock Threshold Exceeded",
56608
+ ESCALATE_TO_HUMAN: "Critic Response: ESCALATE_TO_HUMAN"
56609
+ };
56610
+ const reportContent = `# Full-Auto Escalation Report
56611
+
56612
+ ## Timestamp
56613
+ ${timestamp}
56614
+
56615
+ ## Reason for Escalation
56616
+ ${reasonLabels[reason]}
56617
+
56618
+ ## Architect Output That Triggered Escalation
56619
+ \`\`\`
56620
+ ${architectOutput.slice(0, 4000)}
56621
+ ${architectOutput.length > 4000 ? `
56622
+ ... [output truncated]` : ""}
56623
+ \`\`\`
56624
+
56625
+ ## FullAuto State at Time of Escalation
56626
+ - **Interaction Count**: ${interactionCount}
56627
+ - **Deadlock Count**: ${deadlockCount}
56628
+
56629
+ ## Current Phase and Plan Context
56630
+ - **Current Phase**: ${currentPhase !== undefined ? `Phase ${currentPhase}` : "Unknown"}
56631
+ ${currentPhase !== undefined ? `- **Phase Status**: Pending completion` : ""}
56632
+
56633
+ ## Resolution
56634
+ This escalation requires human intervention. The swarm has been paused.
56635
+ Please review the architect's output above and provide guidance.
56636
+ `;
56637
+ fs30.writeFileSync(reportPath, reportContent, "utf-8");
56638
+ console.log(`[full-auto-intercept] Escalation report written to: ${reportPath}`);
56639
+ } catch (error93) {
56640
+ console.error(`[full-auto-intercept] Failed to write escalation report:`, error93 instanceof Error ? error93.message : String(error93));
56641
+ }
56642
+ }
56643
+ async function handleEscalation(directory, reason, sessionID, architectOutput, interactionCount, deadlockCount, escalationMode, phase) {
56644
+ telemetry.autoOversightEscalation(sessionID ?? "unknown", reason, interactionCount, deadlockCount, phase);
56645
+ await writeEscalationReport(directory, reason, architectOutput, interactionCount, deadlockCount, phase);
56646
+ if (escalationMode === "terminate") {
56647
+ console.error(`[full-auto-intercept] ESCALATION (terminate mode) \u2014 reason: ${reason}, session: ${sessionID}`);
56648
+ process.exit(1);
56649
+ }
56650
+ console.warn(`[full-auto-intercept] ESCALATION (pause mode) \u2014 reason: ${reason}, session: ${sessionID}`);
56651
+ return true;
56652
+ }
55845
56653
  // src/hooks/messages-transform.ts
55846
56654
  function consolidateSystemMessages(messages) {
55847
56655
  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 +56718,7 @@ function consolidateSystemMessages(messages) {
55910
56718
  // src/hooks/phase-monitor.ts
55911
56719
  init_schema();
55912
56720
  init_manager2();
55913
- import * as path41 from "path";
56721
+ import * as path42 from "path";
55914
56722
  init_utils2();
55915
56723
  function createPhaseMonitorHook(directory, preflightManager, curatorRunner, delegateFactory) {
55916
56724
  let lastKnownPhase = null;
@@ -55931,9 +56739,9 @@ function createPhaseMonitorHook(directory, preflightManager, curatorRunner, dele
55931
56739
  const llmDelegate = delegateFactory?.(sessionId);
55932
56740
  const initResult = await runner(directory, curatorConfig, llmDelegate);
55933
56741
  if (initResult.briefing) {
55934
- const briefingPath = path41.join(directory, ".swarm", "curator-briefing.md");
56742
+ const briefingPath = path42.join(directory, ".swarm", "curator-briefing.md");
55935
56743
  const { mkdir: mkdir5, writeFile: writeFile5 } = await import("fs/promises");
55936
- await mkdir5(path41.dirname(briefingPath), { recursive: true });
56744
+ await mkdir5(path42.dirname(briefingPath), { recursive: true });
55937
56745
  await writeFile5(briefingPath, initResult.briefing, "utf-8");
55938
56746
  const { buildApprovedReceipt: buildApprovedReceipt2, persistReviewReceipt: persistReviewReceipt2 } = await Promise.resolve().then(() => (init_review_receipt(), exports_review_receipt));
55939
56747
  const initReceipt = buildApprovedReceipt2({
@@ -56066,15 +56874,15 @@ init_schema();
56066
56874
  init_manager();
56067
56875
  init_detector();
56068
56876
  init_manager2();
56069
- import * as fs33 from "fs";
56070
- import * as path45 from "path";
56877
+ import * as fs35 from "fs";
56878
+ import * as path46 from "path";
56071
56879
 
56072
56880
  // src/services/decision-drift-analyzer.ts
56073
56881
  init_utils2();
56074
56882
  init_manager2();
56075
56883
  init_utils();
56076
- import * as fs30 from "fs";
56077
- import * as path42 from "path";
56884
+ import * as fs32 from "fs";
56885
+ import * as path43 from "path";
56078
56886
  var DEFAULT_DRIFT_CONFIG = {
56079
56887
  staleThresholdPhases: 1,
56080
56888
  detectContradictions: true,
@@ -56228,11 +57036,11 @@ async function analyzeDecisionDrift(directory, config3 = {}) {
56228
57036
  currentPhase = legacyPhase;
56229
57037
  }
56230
57038
  }
56231
- const contextPath = path42.join(directory, ".swarm", "context.md");
57039
+ const contextPath = path43.join(directory, ".swarm", "context.md");
56232
57040
  let contextContent = "";
56233
57041
  try {
56234
- if (fs30.existsSync(contextPath)) {
56235
- contextContent = fs30.readFileSync(contextPath, "utf-8");
57042
+ if (fs32.existsSync(contextPath)) {
57043
+ contextContent = fs32.readFileSync(contextPath, "utf-8");
56236
57044
  }
56237
57045
  } catch (error93) {
56238
57046
  log("[DecisionDriftAnalyzer] context file read failed", {
@@ -56351,14 +57159,15 @@ init_preflight_integration();
56351
57159
  init_preflight_service();
56352
57160
 
56353
57161
  // src/hooks/system-enhancer.ts
57162
+ init_state();
56354
57163
  init_telemetry();
56355
57164
  init_utils();
56356
57165
 
56357
57166
  // src/hooks/adversarial-detector.ts
56358
57167
  init_constants();
56359
57168
  init_schema();
56360
- import * as fs31 from "fs/promises";
56361
- import * as path43 from "path";
57169
+ import * as fs33 from "fs/promises";
57170
+ import * as path44 from "path";
56362
57171
  function safeGet(obj, key) {
56363
57172
  if (!obj || !Object.hasOwn(obj, key))
56364
57173
  return;
@@ -56572,10 +57381,10 @@ async function handleDebuggingSpiral(match, taskId, directory) {
56572
57381
  let eventLogged = false;
56573
57382
  let checkpointCreated = false;
56574
57383
  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)}
57384
+ const swarmDir = path44.join(directory, ".swarm");
57385
+ await fs33.mkdir(swarmDir, { recursive: true });
57386
+ const eventsPath = path44.join(swarmDir, "events.jsonl");
57387
+ await fs33.appendFile(eventsPath, `${formatDebuggingSpiralEvent(match, taskId)}
56579
57388
  `);
56580
57389
  eventLogged = true;
56581
57390
  } catch {}
@@ -56986,7 +57795,7 @@ function createSystemEnhancerHook(config3, directory) {
56986
57795
  } catch {}
56987
57796
  try {
56988
57797
  const darkMatterPath = validateSwarmPath(directory, "dark-matter.md");
56989
- if (!fs33.existsSync(darkMatterPath)) {
57798
+ if (!fs35.existsSync(darkMatterPath)) {
56990
57799
  const {
56991
57800
  detectDarkMatter: detectDarkMatter2,
56992
57801
  formatDarkMatterOutput: formatDarkMatterOutput2,
@@ -56998,10 +57807,10 @@ function createSystemEnhancerHook(config3, directory) {
56998
57807
  });
56999
57808
  if (darkMatter && darkMatter.length > 0) {
57000
57809
  const darkMatterReport = formatDarkMatterOutput2(darkMatter);
57001
- await fs33.promises.writeFile(darkMatterPath, darkMatterReport, "utf-8");
57810
+ await fs35.promises.writeFile(darkMatterPath, darkMatterReport, "utf-8");
57002
57811
  warn(`[system-enhancer] Dark matter scan complete: ${darkMatter.length} co-change patterns found`);
57003
57812
  try {
57004
- const projectName = path45.basename(path45.resolve(directory));
57813
+ const projectName = path46.basename(path46.resolve(directory));
57005
57814
  const knowledgeEntries = darkMatterToKnowledgeEntries2(darkMatter, projectName);
57006
57815
  const knowledgePath = resolveSwarmKnowledgePath(directory);
57007
57816
  const existingEntries = await readKnowledge(knowledgePath);
@@ -57065,11 +57874,11 @@ function createSystemEnhancerHook(config3, directory) {
57065
57874
  if (handoffContent) {
57066
57875
  const handoffPath = validateSwarmPath(directory, "handoff.md");
57067
57876
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
57068
- if (fs33.existsSync(consumedPath)) {
57877
+ if (fs35.existsSync(consumedPath)) {
57069
57878
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
57070
- fs33.unlinkSync(consumedPath);
57879
+ fs35.unlinkSync(consumedPath);
57071
57880
  }
57072
- fs33.renameSync(handoffPath, consumedPath);
57881
+ fs35.renameSync(handoffPath, consumedPath);
57073
57882
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
57074
57883
  The previous model's session ended. Here is your starting context:
57075
57884
 
@@ -57195,6 +58004,15 @@ ${handoffBlock}`);
57195
58004
  const activeAgent_retro = swarmState.activeAgent.get(sessionId_retro ?? "");
57196
58005
  const isArchitect2 = !activeAgent_retro || stripKnownSwarmPrefix(activeAgent_retro) === "architect";
57197
58006
  if (isArchitect2) {
58007
+ const sessionIdBanner = _input.sessionID;
58008
+ if (hasActiveTurboMode(sessionIdBanner) || hasActiveFullAuto(sessionIdBanner)) {
58009
+ if (hasActiveTurboMode(sessionIdBanner)) {
58010
+ tryInject(TURBO_MODE_BANNER);
58011
+ }
58012
+ if (hasActiveFullAuto(sessionIdBanner)) {
58013
+ tryInject(FULL_AUTO_BANNER);
58014
+ }
58015
+ }
57198
58016
  try {
57199
58017
  const currentPhaseNum = plan2?.current_phase ?? 1;
57200
58018
  const retroText = await buildRetroInjection(directory, currentPhaseNum, plan2?.title ?? undefined);
@@ -57357,11 +58175,11 @@ ${budgetWarning}`);
57357
58175
  if (handoffContent) {
57358
58176
  const handoffPath = validateSwarmPath(directory, "handoff.md");
57359
58177
  const consumedPath = validateSwarmPath(directory, "handoff-consumed.md");
57360
- if (fs33.existsSync(consumedPath)) {
58178
+ if (fs35.existsSync(consumedPath)) {
57361
58179
  warn("Duplicate handoff detected: handoff-consumed.md already exists");
57362
- fs33.unlinkSync(consumedPath);
58180
+ fs35.unlinkSync(consumedPath);
57363
58181
  }
57364
- fs33.renameSync(handoffPath, consumedPath);
58182
+ fs35.renameSync(handoffPath, consumedPath);
57365
58183
  const handoffBlock = `## HANDOFF \u2014 Resuming from model switch
57366
58184
  The previous model's session ended. Here is your starting context:
57367
58185
 
@@ -57527,6 +58345,29 @@ ${handoffBlock}`;
57527
58345
  const activeAgent_retro_b = swarmState.activeAgent.get(sessionId_retro_b ?? "");
57528
58346
  const isArchitect_b = !activeAgent_retro_b || stripKnownSwarmPrefix(activeAgent_retro_b) === "architect";
57529
58347
  if (isArchitect_b) {
58348
+ const sessionIdBanner_b = _input.sessionID;
58349
+ if (hasActiveTurboMode(sessionIdBanner_b) || hasActiveFullAuto(sessionIdBanner_b)) {
58350
+ if (hasActiveTurboMode(sessionIdBanner_b)) {
58351
+ candidates.push({
58352
+ id: `candidate-${idCounter++}`,
58353
+ kind: "agent_context",
58354
+ text: TURBO_MODE_BANNER,
58355
+ tokens: estimateTokens(TURBO_MODE_BANNER),
58356
+ priority: 1,
58357
+ metadata: { contentType: "prose" }
58358
+ });
58359
+ }
58360
+ if (hasActiveFullAuto(sessionIdBanner_b)) {
58361
+ candidates.push({
58362
+ id: `candidate-${idCounter++}`,
58363
+ kind: "agent_context",
58364
+ text: FULL_AUTO_BANNER,
58365
+ tokens: estimateTokens(FULL_AUTO_BANNER),
58366
+ priority: 1,
58367
+ metadata: { contentType: "prose" }
58368
+ });
58369
+ }
58370
+ }
57530
58371
  try {
57531
58372
  const currentPhaseNum_b = plan?.current_phase ?? 1;
57532
58373
  const retroText_b = await buildRetroInjection(directory, currentPhaseNum_b, plan?.title ?? undefined);
@@ -58055,6 +58896,7 @@ function createDarkMatterDetectorHook(directory) {
58055
58896
  }
58056
58897
 
58057
58898
  // src/hooks/delegation-ledger.ts
58899
+ init_state();
58058
58900
  var ledgerBySession = new Map;
58059
58901
  var callStartTimes = new Map;
58060
58902
  function createDelegationLedgerHook(config3, _directory, injectAdvisory) {
@@ -58146,14 +58988,14 @@ function isReadTool(toolName) {
58146
58988
  }
58147
58989
 
58148
58990
  // src/hooks/incremental-verify.ts
58149
- import * as fs34 from "fs";
58150
- import * as path46 from "path";
58991
+ import * as fs36 from "fs";
58992
+ import * as path47 from "path";
58151
58993
 
58152
58994
  // src/hooks/spawn-helper.ts
58153
58995
  import * as child_process4 from "child_process";
58154
58996
  var WIN32_CMD_BINARIES = new Set(["npm", "npx", "pnpm", "yarn"]);
58155
58997
  function spawnAsync(command, cwd, timeoutMs) {
58156
- return new Promise((resolve14) => {
58998
+ return new Promise((resolve15) => {
58157
58999
  try {
58158
59000
  const [rawCmd, ...args2] = command;
58159
59001
  const cmd = process.platform === "win32" && WIN32_CMD_BINARIES.has(rawCmd) && !rawCmd.includes(".") ? `${rawCmd}.cmd` : rawCmd;
@@ -58200,24 +59042,24 @@ function spawnAsync(command, cwd, timeoutMs) {
58200
59042
  try {
58201
59043
  proc.kill();
58202
59044
  } catch {}
58203
- resolve14(null);
59045
+ resolve15(null);
58204
59046
  }, timeoutMs);
58205
59047
  proc.on("close", (code) => {
58206
59048
  if (done)
58207
59049
  return;
58208
59050
  done = true;
58209
59051
  clearTimeout(timer);
58210
- resolve14({ exitCode: code ?? 1, stdout, stderr });
59052
+ resolve15({ exitCode: code ?? 1, stdout, stderr });
58211
59053
  });
58212
59054
  proc.on("error", () => {
58213
59055
  if (done)
58214
59056
  return;
58215
59057
  done = true;
58216
59058
  clearTimeout(timer);
58217
- resolve14(null);
59059
+ resolve15(null);
58218
59060
  });
58219
59061
  } catch {
58220
- resolve14(null);
59062
+ resolve15(null);
58221
59063
  }
58222
59064
  });
58223
59065
  }
@@ -58225,21 +59067,21 @@ function spawnAsync(command, cwd, timeoutMs) {
58225
59067
  // src/hooks/incremental-verify.ts
58226
59068
  var emittedSkipAdvisories = new Set;
58227
59069
  function detectPackageManager(projectDir) {
58228
- if (fs34.existsSync(path46.join(projectDir, "bun.lockb")))
59070
+ if (fs36.existsSync(path47.join(projectDir, "bun.lockb")))
58229
59071
  return "bun";
58230
- if (fs34.existsSync(path46.join(projectDir, "pnpm-lock.yaml")))
59072
+ if (fs36.existsSync(path47.join(projectDir, "pnpm-lock.yaml")))
58231
59073
  return "pnpm";
58232
- if (fs34.existsSync(path46.join(projectDir, "yarn.lock")))
59074
+ if (fs36.existsSync(path47.join(projectDir, "yarn.lock")))
58233
59075
  return "yarn";
58234
- if (fs34.existsSync(path46.join(projectDir, "package-lock.json")))
59076
+ if (fs36.existsSync(path47.join(projectDir, "package-lock.json")))
58235
59077
  return "npm";
58236
59078
  return "bun";
58237
59079
  }
58238
59080
  function detectTypecheckCommand(projectDir) {
58239
- const pkgPath = path46.join(projectDir, "package.json");
58240
- if (fs34.existsSync(pkgPath)) {
59081
+ const pkgPath = path47.join(projectDir, "package.json");
59082
+ if (fs36.existsSync(pkgPath)) {
58241
59083
  try {
58242
- const pkg = JSON.parse(fs34.readFileSync(pkgPath, "utf8"));
59084
+ const pkg = JSON.parse(fs36.readFileSync(pkgPath, "utf8"));
58243
59085
  const scripts = pkg.scripts;
58244
59086
  if (scripts?.typecheck) {
58245
59087
  const pm = detectPackageManager(projectDir);
@@ -58253,8 +59095,8 @@ function detectTypecheckCommand(projectDir) {
58253
59095
  ...pkg.dependencies,
58254
59096
  ...pkg.devDependencies
58255
59097
  };
58256
- if (!deps?.typescript && !fs34.existsSync(path46.join(projectDir, "tsconfig.json"))) {}
58257
- const hasTSMarkers = deps?.typescript || fs34.existsSync(path46.join(projectDir, "tsconfig.json"));
59098
+ if (!deps?.typescript && !fs36.existsSync(path47.join(projectDir, "tsconfig.json"))) {}
59099
+ const hasTSMarkers = deps?.typescript || fs36.existsSync(path47.join(projectDir, "tsconfig.json"));
58258
59100
  if (hasTSMarkers) {
58259
59101
  return { command: ["npx", "tsc", "--noEmit"], language: "typescript" };
58260
59102
  }
@@ -58262,17 +59104,17 @@ function detectTypecheckCommand(projectDir) {
58262
59104
  return null;
58263
59105
  }
58264
59106
  }
58265
- if (fs34.existsSync(path46.join(projectDir, "go.mod"))) {
59107
+ if (fs36.existsSync(path47.join(projectDir, "go.mod"))) {
58266
59108
  return { command: ["go", "vet", "./..."], language: "go" };
58267
59109
  }
58268
- if (fs34.existsSync(path46.join(projectDir, "Cargo.toml"))) {
59110
+ if (fs36.existsSync(path47.join(projectDir, "Cargo.toml"))) {
58269
59111
  return { command: ["cargo", "check"], language: "rust" };
58270
59112
  }
58271
- if (fs34.existsSync(path46.join(projectDir, "pyproject.toml")) || fs34.existsSync(path46.join(projectDir, "requirements.txt")) || fs34.existsSync(path46.join(projectDir, "setup.py"))) {
59113
+ if (fs36.existsSync(path47.join(projectDir, "pyproject.toml")) || fs36.existsSync(path47.join(projectDir, "requirements.txt")) || fs36.existsSync(path47.join(projectDir, "setup.py"))) {
58272
59114
  return { command: null, language: "python" };
58273
59115
  }
58274
59116
  try {
58275
- const entries = fs34.readdirSync(projectDir);
59117
+ const entries = fs36.readdirSync(projectDir);
58276
59118
  if (entries.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
58277
59119
  return {
58278
59120
  command: ["dotnet", "build", "--no-restore"],
@@ -58606,7 +59448,8 @@ ${freshPreamble}` : `<curator_briefing>${truncatedBriefing}</curator_briefing>`;
58606
59448
  // src/hooks/scope-guard.ts
58607
59449
  init_constants();
58608
59450
  init_schema();
58609
- import * as path48 from "path";
59451
+ init_state();
59452
+ import * as path49 from "path";
58610
59453
  var WRITE_TOOLS = new Set(WRITE_TOOL_NAMES);
58611
59454
  function createScopeGuardHook(config3, directory, injectAdvisory) {
58612
59455
  const enabled = config3.enabled ?? true;
@@ -58658,19 +59501,20 @@ function createScopeGuardHook(config3, directory, injectAdvisory) {
58658
59501
  }
58659
59502
  function isFileInScope(filePath, scopeEntries, directory) {
58660
59503
  const dir = directory ?? process.cwd();
58661
- const resolvedFile = path48.resolve(dir, filePath);
59504
+ const resolvedFile = path49.resolve(dir, filePath);
58662
59505
  return scopeEntries.some((scope) => {
58663
- const resolvedScope = path48.resolve(dir, scope);
59506
+ const resolvedScope = path49.resolve(dir, scope);
58664
59507
  if (resolvedFile === resolvedScope)
58665
59508
  return true;
58666
- const rel = path48.relative(resolvedScope, resolvedFile);
58667
- return rel.length > 0 && !rel.startsWith("..") && !path48.isAbsolute(rel);
59509
+ const rel = path49.relative(resolvedScope, resolvedFile);
59510
+ return rel.length > 0 && !rel.startsWith("..") && !path49.isAbsolute(rel);
58668
59511
  });
58669
59512
  }
58670
59513
 
58671
59514
  // src/hooks/self-review.ts
58672
59515
  init_constants();
58673
59516
  init_schema();
59517
+ init_state();
58674
59518
  function createSelfReviewHook(config3, injectAdvisory) {
58675
59519
  const enabled = config3.enabled ?? true;
58676
59520
  const skipInTurbo = config3.skip_in_turbo ?? true;
@@ -58713,8 +59557,8 @@ function createSelfReviewHook(config3, injectAdvisory) {
58713
59557
  }
58714
59558
 
58715
59559
  // src/hooks/slop-detector.ts
58716
- import * as fs36 from "fs";
58717
- import * as path49 from "path";
59560
+ import * as fs38 from "fs";
59561
+ import * as path50 from "path";
58718
59562
  var WRITE_EDIT_TOOLS = new Set([
58719
59563
  "write",
58720
59564
  "edit",
@@ -58759,12 +59603,12 @@ function checkBoilerplateExplosion(content, taskDescription, threshold) {
58759
59603
  function walkFiles(dir, exts, deadline) {
58760
59604
  const results = [];
58761
59605
  try {
58762
- for (const entry of fs36.readdirSync(dir, { withFileTypes: true })) {
59606
+ for (const entry of fs38.readdirSync(dir, { withFileTypes: true })) {
58763
59607
  if (deadline !== undefined && Date.now() > deadline)
58764
59608
  break;
58765
59609
  if (entry.isSymbolicLink())
58766
59610
  continue;
58767
- const full = path49.join(dir, entry.name);
59611
+ const full = path50.join(dir, entry.name);
58768
59612
  if (entry.isDirectory()) {
58769
59613
  if (entry.name === "node_modules" || entry.name === ".git")
58770
59614
  continue;
@@ -58779,7 +59623,7 @@ function walkFiles(dir, exts, deadline) {
58779
59623
  return results;
58780
59624
  }
58781
59625
  function checkDeadExports(content, projectDir, startTime) {
58782
- const hasPackageJson = fs36.existsSync(path49.join(projectDir, "package.json"));
59626
+ const hasPackageJson = fs38.existsSync(path50.join(projectDir, "package.json"));
58783
59627
  if (!hasPackageJson)
58784
59628
  return null;
58785
59629
  const exportMatches = content.matchAll(/^\+(?:export)\s+(?:function|class|const|type|interface)\s+(\w{3,})/gm);
@@ -58802,7 +59646,7 @@ function checkDeadExports(content, projectDir, startTime) {
58802
59646
  if (found || Date.now() - startTime > 480)
58803
59647
  break;
58804
59648
  try {
58805
- const text = fs36.readFileSync(file3, "utf-8");
59649
+ const text = fs38.readFileSync(file3, "utf-8");
58806
59650
  if (importPattern.test(text))
58807
59651
  found = true;
58808
59652
  importPattern.lastIndex = 0;
@@ -58935,7 +59779,7 @@ Review before proceeding.`;
58935
59779
 
58936
59780
  // src/hooks/steering-consumed.ts
58937
59781
  init_utils2();
58938
- import * as fs37 from "fs";
59782
+ import * as fs39 from "fs";
58939
59783
  function recordSteeringConsumed(directory, directiveId) {
58940
59784
  try {
58941
59785
  const eventsPath = validateSwarmPath(directory, "events.jsonl");
@@ -58944,7 +59788,7 @@ function recordSteeringConsumed(directory, directiveId) {
58944
59788
  directiveId,
58945
59789
  timestamp: new Date().toISOString()
58946
59790
  };
58947
- fs37.appendFileSync(eventsPath, `${JSON.stringify(event)}
59791
+ fs39.appendFileSync(eventsPath, `${JSON.stringify(event)}
58948
59792
  `, "utf-8");
58949
59793
  } catch {}
58950
59794
  }
@@ -58989,6 +59833,7 @@ init_config_doctor();
58989
59833
 
58990
59834
  // src/session/snapshot-reader.ts
58991
59835
  init_utils2();
59836
+ init_state();
58992
59837
  import { renameSync as renameSync13 } from "fs";
58993
59838
  var TRANSIENT_SESSION_FIELDS = [
58994
59839
  { name: "revisionLimitHit", resetValue: false },
@@ -59081,6 +59926,10 @@ function deserializeAgentSession(s) {
59081
59926
  modelFallbackExhausted: s.modelFallbackExhausted ?? false,
59082
59927
  coderRevisions: s.coderRevisions ?? 0,
59083
59928
  revisionLimitHit: s.revisionLimitHit ?? false,
59929
+ fullAutoMode: s.fullAutoMode ?? false,
59930
+ fullAutoInteractionCount: s.fullAutoInteractionCount ?? 0,
59931
+ fullAutoDeadlockCount: s.fullAutoDeadlockCount ?? 0,
59932
+ fullAutoLastQuestionHash: s.fullAutoLastQuestionHash ?? null,
59084
59933
  sessionRehydratedAt: s.sessionRehydratedAt ?? 0
59085
59934
  };
59086
59935
  }
@@ -59176,19 +60025,20 @@ async function loadSnapshot(directory) {
59176
60025
  }
59177
60026
 
59178
60027
  // src/index.ts
60028
+ init_state();
59179
60029
  init_telemetry();
59180
60030
 
59181
60031
  // src/tools/batch-symbols.ts
59182
60032
  init_tool();
59183
60033
  init_create_tool();
59184
- import * as fs39 from "fs";
59185
- import * as path51 from "path";
60034
+ import * as fs41 from "fs";
60035
+ import * as path52 from "path";
59186
60036
 
59187
60037
  // src/tools/symbols.ts
59188
60038
  init_tool();
59189
60039
  init_create_tool();
59190
- import * as fs38 from "fs";
59191
- import * as path50 from "path";
60040
+ import * as fs40 from "fs";
60041
+ import * as path51 from "path";
59192
60042
  var MAX_FILE_SIZE_BYTES2 = 1024 * 1024;
59193
60043
  var WINDOWS_RESERVED_NAMES = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
59194
60044
  function containsWindowsAttacks(str) {
@@ -59205,11 +60055,11 @@ function containsWindowsAttacks(str) {
59205
60055
  }
59206
60056
  function isPathInWorkspace(filePath, workspace) {
59207
60057
  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)) {
60058
+ const resolvedPath = path51.resolve(workspace, filePath);
60059
+ const realWorkspace = fs40.realpathSync(workspace);
60060
+ const realResolvedPath = fs40.realpathSync(resolvedPath);
60061
+ const relativePath = path51.relative(realWorkspace, realResolvedPath);
60062
+ if (relativePath.startsWith("..") || path51.isAbsolute(relativePath)) {
59213
60063
  return false;
59214
60064
  }
59215
60065
  return true;
@@ -59221,17 +60071,17 @@ function validatePathForRead(filePath, workspace) {
59221
60071
  return isPathInWorkspace(filePath, workspace);
59222
60072
  }
59223
60073
  function extractTSSymbols(filePath, cwd) {
59224
- const fullPath = path50.join(cwd, filePath);
60074
+ const fullPath = path51.join(cwd, filePath);
59225
60075
  if (!validatePathForRead(fullPath, cwd)) {
59226
60076
  return [];
59227
60077
  }
59228
60078
  let content;
59229
60079
  try {
59230
- const stats = fs38.statSync(fullPath);
60080
+ const stats = fs40.statSync(fullPath);
59231
60081
  if (stats.size > MAX_FILE_SIZE_BYTES2) {
59232
60082
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES2})`);
59233
60083
  }
59234
- content = fs38.readFileSync(fullPath, "utf-8");
60084
+ content = fs40.readFileSync(fullPath, "utf-8");
59235
60085
  } catch {
59236
60086
  return [];
59237
60087
  }
@@ -59373,17 +60223,17 @@ function extractTSSymbols(filePath, cwd) {
59373
60223
  });
59374
60224
  }
59375
60225
  function extractPythonSymbols(filePath, cwd) {
59376
- const fullPath = path50.join(cwd, filePath);
60226
+ const fullPath = path51.join(cwd, filePath);
59377
60227
  if (!validatePathForRead(fullPath, cwd)) {
59378
60228
  return [];
59379
60229
  }
59380
60230
  let content;
59381
60231
  try {
59382
- const stats = fs38.statSync(fullPath);
60232
+ const stats = fs40.statSync(fullPath);
59383
60233
  if (stats.size > MAX_FILE_SIZE_BYTES2) {
59384
60234
  throw new Error(`File too large: ${stats.size} bytes (max: ${MAX_FILE_SIZE_BYTES2})`);
59385
60235
  }
59386
- content = fs38.readFileSync(fullPath, "utf-8");
60236
+ content = fs40.readFileSync(fullPath, "utf-8");
59387
60237
  } catch {
59388
60238
  return [];
59389
60239
  }
@@ -59456,7 +60306,7 @@ var symbols = createSwarmTool({
59456
60306
  }, null, 2);
59457
60307
  }
59458
60308
  const cwd = directory;
59459
- const ext = path50.extname(file3);
60309
+ const ext = path51.extname(file3);
59460
60310
  if (containsControlChars(file3)) {
59461
60311
  return JSON.stringify({
59462
60312
  file: file3,
@@ -59532,14 +60382,14 @@ function containsWindowsAttacks2(str) {
59532
60382
  }
59533
60383
  function isPathInWorkspace2(filePath, workspace) {
59534
60384
  try {
59535
- const resolvedPath = path51.resolve(workspace, filePath);
59536
- if (!fs39.existsSync(resolvedPath)) {
60385
+ const resolvedPath = path52.resolve(workspace, filePath);
60386
+ if (!fs41.existsSync(resolvedPath)) {
59537
60387
  return true;
59538
60388
  }
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)) {
60389
+ const realWorkspace = fs41.realpathSync(workspace);
60390
+ const realResolvedPath = fs41.realpathSync(resolvedPath);
60391
+ const relativePath = path52.relative(realWorkspace, realResolvedPath);
60392
+ if (relativePath.startsWith("..") || path52.isAbsolute(relativePath)) {
59543
60393
  return false;
59544
60394
  }
59545
60395
  return true;
@@ -59548,7 +60398,7 @@ function isPathInWorkspace2(filePath, workspace) {
59548
60398
  }
59549
60399
  }
59550
60400
  function processFile(file3, cwd, exportedOnly) {
59551
- const ext = path51.extname(file3);
60401
+ const ext = path52.extname(file3);
59552
60402
  if (containsControlChars(file3)) {
59553
60403
  return {
59554
60404
  file: file3,
@@ -59581,8 +60431,8 @@ function processFile(file3, cwd, exportedOnly) {
59581
60431
  errorType: "path-outside-workspace"
59582
60432
  };
59583
60433
  }
59584
- const fullPath = path51.join(cwd, file3);
59585
- if (!fs39.existsSync(fullPath)) {
60434
+ const fullPath = path52.join(cwd, file3);
60435
+ if (!fs41.existsSync(fullPath)) {
59586
60436
  return {
59587
60437
  file: file3,
59588
60438
  success: false,
@@ -59613,14 +60463,14 @@ function processFile(file3, cwd, exportedOnly) {
59613
60463
  }
59614
60464
  let isEmptyFile = false;
59615
60465
  try {
59616
- const stats = fs39.statSync(fullPath);
60466
+ const stats = fs41.statSync(fullPath);
59617
60467
  if (stats.size === 0) {
59618
60468
  isEmptyFile = true;
59619
60469
  }
59620
60470
  } catch {}
59621
60471
  if (syms.length === 0) {
59622
60472
  try {
59623
- const content = fs39.readFileSync(fullPath, "utf-8");
60473
+ const content = fs41.readFileSync(fullPath, "utf-8");
59624
60474
  if (content.trim().length === 0) {
59625
60475
  isEmptyFile = true;
59626
60476
  }
@@ -59871,8 +60721,8 @@ init_dist();
59871
60721
  init_manager();
59872
60722
  init_create_tool();
59873
60723
  init_resolve_working_directory();
59874
- import * as fs40 from "fs";
59875
- import * as path52 from "path";
60724
+ import * as fs42 from "fs";
60725
+ import * as path53 from "path";
59876
60726
  var EVIDENCE_DIR = ".swarm/evidence";
59877
60727
  var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
59878
60728
  function isValidTaskId3(taskId) {
@@ -59889,18 +60739,18 @@ function isValidTaskId3(taskId) {
59889
60739
  return TASK_ID_PATTERN2.test(taskId);
59890
60740
  }
59891
60741
  function isPathWithinSwarm(filePath, workspaceRoot) {
59892
- const normalizedWorkspace = path52.resolve(workspaceRoot);
59893
- const swarmPath = path52.join(normalizedWorkspace, ".swarm", "evidence");
59894
- const normalizedPath = path52.resolve(filePath);
60742
+ const normalizedWorkspace = path53.resolve(workspaceRoot);
60743
+ const swarmPath = path53.join(normalizedWorkspace, ".swarm", "evidence");
60744
+ const normalizedPath = path53.resolve(filePath);
59895
60745
  return normalizedPath.startsWith(swarmPath);
59896
60746
  }
59897
60747
  function readEvidenceFile(evidencePath) {
59898
- if (!fs40.existsSync(evidencePath)) {
60748
+ if (!fs42.existsSync(evidencePath)) {
59899
60749
  return null;
59900
60750
  }
59901
60751
  let content;
59902
60752
  try {
59903
- content = fs40.readFileSync(evidencePath, "utf-8");
60753
+ content = fs42.readFileSync(evidencePath, "utf-8");
59904
60754
  } catch {
59905
60755
  return null;
59906
60756
  }
@@ -59972,7 +60822,7 @@ var check_gate_status = createSwarmTool({
59972
60822
  };
59973
60823
  return JSON.stringify(errorResult, null, 2);
59974
60824
  }
59975
- const evidencePath = path52.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
60825
+ const evidencePath = path53.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
59976
60826
  if (!isPathWithinSwarm(evidencePath, directory)) {
59977
60827
  const errorResult = {
59978
60828
  taskId: taskIdInput,
@@ -60065,10 +60915,11 @@ init_co_change_analyzer();
60065
60915
  // src/tools/completion-verify.ts
60066
60916
  init_dist();
60067
60917
  init_utils2();
60068
- import * as fs41 from "fs";
60069
- import * as path53 from "path";
60918
+ init_state();
60070
60919
  init_create_tool();
60071
60920
  init_resolve_working_directory();
60921
+ import * as fs43 from "fs";
60922
+ import * as path54 from "path";
60072
60923
  function extractMatches(regex, text) {
60073
60924
  return Array.from(text.matchAll(regex));
60074
60925
  }
@@ -60162,7 +61013,7 @@ async function executeCompletionVerify(args2, directory) {
60162
61013
  let plan;
60163
61014
  try {
60164
61015
  const planPath = validateSwarmPath(directory, "plan.json");
60165
- const planRaw = fs41.readFileSync(planPath, "utf-8");
61016
+ const planRaw = fs43.readFileSync(planPath, "utf-8");
60166
61017
  plan = JSON.parse(planRaw);
60167
61018
  } catch {
60168
61019
  const result2 = {
@@ -60220,10 +61071,10 @@ async function executeCompletionVerify(args2, directory) {
60220
61071
  let hasFileReadFailure = false;
60221
61072
  for (const filePath of fileTargets) {
60222
61073
  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);
61074
+ const resolvedPath = path54.resolve(directory, normalizedPath);
61075
+ const projectRoot = path54.resolve(directory);
61076
+ const relative9 = path54.relative(projectRoot, resolvedPath);
61077
+ const withinProject = relative9 === "" || !relative9.startsWith("..") && !path54.isAbsolute(relative9);
60227
61078
  if (!withinProject) {
60228
61079
  blockedTasks.push({
60229
61080
  task_id: task.id,
@@ -60236,7 +61087,7 @@ async function executeCompletionVerify(args2, directory) {
60236
61087
  }
60237
61088
  let fileContent;
60238
61089
  try {
60239
- fileContent = fs41.readFileSync(resolvedPath, "utf-8");
61090
+ fileContent = fs43.readFileSync(resolvedPath, "utf-8");
60240
61091
  } catch {
60241
61092
  blockedTasks.push({
60242
61093
  task_id: task.id,
@@ -60278,9 +61129,9 @@ async function executeCompletionVerify(args2, directory) {
60278
61129
  blockedTasks
60279
61130
  };
60280
61131
  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 });
61132
+ const evidenceDir = path54.join(directory, ".swarm", "evidence", `${phase}`);
61133
+ const evidencePath = path54.join(evidenceDir, "completion-verify.json");
61134
+ fs43.mkdirSync(evidenceDir, { recursive: true });
60284
61135
  const evidenceBundle = {
60285
61136
  schema_version: "1.0.0",
60286
61137
  task_id: "completion-verify",
@@ -60301,7 +61152,7 @@ async function executeCompletionVerify(args2, directory) {
60301
61152
  }
60302
61153
  ]
60303
61154
  };
60304
- fs41.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
61155
+ fs43.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
60305
61156
  } catch {}
60306
61157
  return JSON.stringify(result, null, 2);
60307
61158
  }
@@ -60355,12 +61206,12 @@ var completion_verify = createSwarmTool({
60355
61206
  });
60356
61207
  // src/tools/complexity-hotspots.ts
60357
61208
  init_dist();
60358
- import * as fs43 from "fs";
60359
- import * as path55 from "path";
61209
+ import * as fs45 from "fs";
61210
+ import * as path56 from "path";
60360
61211
 
60361
61212
  // src/quality/metrics.ts
60362
- import * as fs42 from "fs";
60363
- import * as path54 from "path";
61213
+ import * as fs44 from "fs";
61214
+ import * as path55 from "path";
60364
61215
  var MAX_FILE_SIZE_BYTES3 = 256 * 1024;
60365
61216
  var MIN_DUPLICATION_LINES = 10;
60366
61217
  function estimateCyclomaticComplexity(content) {
@@ -60398,11 +61249,11 @@ function estimateCyclomaticComplexity(content) {
60398
61249
  }
60399
61250
  function getComplexityForFile(filePath) {
60400
61251
  try {
60401
- const stat2 = fs42.statSync(filePath);
61252
+ const stat2 = fs44.statSync(filePath);
60402
61253
  if (stat2.size > MAX_FILE_SIZE_BYTES3) {
60403
61254
  return null;
60404
61255
  }
60405
- const content = fs42.readFileSync(filePath, "utf-8");
61256
+ const content = fs44.readFileSync(filePath, "utf-8");
60406
61257
  return estimateCyclomaticComplexity(content);
60407
61258
  } catch {
60408
61259
  return null;
@@ -60412,8 +61263,8 @@ async function computeComplexityDelta(files, workingDir) {
60412
61263
  let totalComplexity = 0;
60413
61264
  const analyzedFiles = [];
60414
61265
  for (const file3 of files) {
60415
- const fullPath = path54.isAbsolute(file3) ? file3 : path54.join(workingDir, file3);
60416
- if (!fs42.existsSync(fullPath)) {
61266
+ const fullPath = path55.isAbsolute(file3) ? file3 : path55.join(workingDir, file3);
61267
+ if (!fs44.existsSync(fullPath)) {
60417
61268
  continue;
60418
61269
  }
60419
61270
  const complexity = getComplexityForFile(fullPath);
@@ -60534,8 +61385,8 @@ function countGoExports(content) {
60534
61385
  }
60535
61386
  function getExportCountForFile(filePath) {
60536
61387
  try {
60537
- const content = fs42.readFileSync(filePath, "utf-8");
60538
- const ext = path54.extname(filePath).toLowerCase();
61388
+ const content = fs44.readFileSync(filePath, "utf-8");
61389
+ const ext = path55.extname(filePath).toLowerCase();
60539
61390
  switch (ext) {
60540
61391
  case ".ts":
60541
61392
  case ".tsx":
@@ -60561,8 +61412,8 @@ async function computePublicApiDelta(files, workingDir) {
60561
61412
  let totalExports = 0;
60562
61413
  const analyzedFiles = [];
60563
61414
  for (const file3 of files) {
60564
- const fullPath = path54.isAbsolute(file3) ? file3 : path54.join(workingDir, file3);
60565
- if (!fs42.existsSync(fullPath)) {
61415
+ const fullPath = path55.isAbsolute(file3) ? file3 : path55.join(workingDir, file3);
61416
+ if (!fs44.existsSync(fullPath)) {
60566
61417
  continue;
60567
61418
  }
60568
61419
  const exports = getExportCountForFile(fullPath);
@@ -60595,16 +61446,16 @@ async function computeDuplicationRatio(files, workingDir) {
60595
61446
  let duplicateLines = 0;
60596
61447
  const analyzedFiles = [];
60597
61448
  for (const file3 of files) {
60598
- const fullPath = path54.isAbsolute(file3) ? file3 : path54.join(workingDir, file3);
60599
- if (!fs42.existsSync(fullPath)) {
61449
+ const fullPath = path55.isAbsolute(file3) ? file3 : path55.join(workingDir, file3);
61450
+ if (!fs44.existsSync(fullPath)) {
60600
61451
  continue;
60601
61452
  }
60602
61453
  try {
60603
- const stat2 = fs42.statSync(fullPath);
61454
+ const stat2 = fs44.statSync(fullPath);
60604
61455
  if (stat2.size > MAX_FILE_SIZE_BYTES3) {
60605
61456
  continue;
60606
61457
  }
60607
- const content = fs42.readFileSync(fullPath, "utf-8");
61458
+ const content = fs44.readFileSync(fullPath, "utf-8");
60608
61459
  const lines = content.split(`
60609
61460
  `).filter((line) => line.trim().length > 0);
60610
61461
  if (lines.length < MIN_DUPLICATION_LINES) {
@@ -60628,8 +61479,8 @@ function countCodeLines(content) {
60628
61479
  return lines.length;
60629
61480
  }
60630
61481
  function isTestFile(filePath) {
60631
- const basename8 = path54.basename(filePath);
60632
- const _ext = path54.extname(filePath).toLowerCase();
61482
+ const basename8 = path55.basename(filePath);
61483
+ const _ext = path55.extname(filePath).toLowerCase();
60633
61484
  const testPatterns = [
60634
61485
  ".test.",
60635
61486
  ".spec.",
@@ -60710,8 +61561,8 @@ function matchGlobSegment(globSegments, pathSegments) {
60710
61561
  }
60711
61562
  return gIndex === globSegments.length && pIndex === pathSegments.length;
60712
61563
  }
60713
- function matchesGlobSegment(path55, glob) {
60714
- const normalizedPath = path55.replace(/\\/g, "/");
61564
+ function matchesGlobSegment(path56, glob) {
61565
+ const normalizedPath = path56.replace(/\\/g, "/");
60715
61566
  const normalizedGlob = glob.replace(/\\/g, "/");
60716
61567
  if (normalizedPath.includes("//")) {
60717
61568
  return false;
@@ -60742,8 +61593,8 @@ function simpleGlobToRegex2(glob) {
60742
61593
  function hasGlobstar(glob) {
60743
61594
  return glob.includes("**");
60744
61595
  }
60745
- function globMatches(path55, glob) {
60746
- const normalizedPath = path55.replace(/\\/g, "/");
61596
+ function globMatches(path56, glob) {
61597
+ const normalizedPath = path56.replace(/\\/g, "/");
60747
61598
  if (!glob || glob === "") {
60748
61599
  if (normalizedPath.includes("//")) {
60749
61600
  return false;
@@ -60779,31 +61630,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
60779
61630
  async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
60780
61631
  let testLines = 0;
60781
61632
  let codeLines = 0;
60782
- const srcDir = path54.join(workingDir, "src");
60783
- if (fs42.existsSync(srcDir)) {
61633
+ const srcDir = path55.join(workingDir, "src");
61634
+ if (fs44.existsSync(srcDir)) {
60784
61635
  await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
60785
61636
  codeLines += lines;
60786
61637
  });
60787
61638
  }
60788
61639
  const possibleSrcDirs = ["lib", "app", "source", "core"];
60789
61640
  for (const dir of possibleSrcDirs) {
60790
- const dirPath = path54.join(workingDir, dir);
60791
- if (fs42.existsSync(dirPath)) {
61641
+ const dirPath = path55.join(workingDir, dir);
61642
+ if (fs44.existsSync(dirPath)) {
60792
61643
  await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
60793
61644
  codeLines += lines;
60794
61645
  });
60795
61646
  }
60796
61647
  }
60797
- const testsDir = path54.join(workingDir, "tests");
60798
- if (fs42.existsSync(testsDir)) {
61648
+ const testsDir = path55.join(workingDir, "tests");
61649
+ if (fs44.existsSync(testsDir)) {
60799
61650
  await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
60800
61651
  testLines += lines;
60801
61652
  });
60802
61653
  }
60803
61654
  const possibleTestDirs = ["test", "__tests__", "specs"];
60804
61655
  for (const dir of possibleTestDirs) {
60805
- const dirPath = path54.join(workingDir, dir);
60806
- if (fs42.existsSync(dirPath) && dirPath !== testsDir) {
61656
+ const dirPath = path55.join(workingDir, dir);
61657
+ if (fs44.existsSync(dirPath) && dirPath !== testsDir) {
60807
61658
  await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
60808
61659
  testLines += lines;
60809
61660
  });
@@ -60815,9 +61666,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
60815
61666
  }
60816
61667
  async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
60817
61668
  try {
60818
- const entries = fs42.readdirSync(dirPath, { withFileTypes: true });
61669
+ const entries = fs44.readdirSync(dirPath, { withFileTypes: true });
60819
61670
  for (const entry of entries) {
60820
- const fullPath = path54.join(dirPath, entry.name);
61671
+ const fullPath = path55.join(dirPath, entry.name);
60821
61672
  if (entry.isDirectory()) {
60822
61673
  if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
60823
61674
  continue;
@@ -60825,7 +61676,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
60825
61676
  await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
60826
61677
  } else if (entry.isFile()) {
60827
61678
  const relativePath = fullPath.replace(`${dirPath}/`, "");
60828
- const ext = path54.extname(entry.name).toLowerCase();
61679
+ const ext = path55.extname(entry.name).toLowerCase();
60829
61680
  const validExts = [
60830
61681
  ".ts",
60831
61682
  ".tsx",
@@ -60861,7 +61712,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
60861
61712
  continue;
60862
61713
  }
60863
61714
  try {
60864
- const content = fs42.readFileSync(fullPath, "utf-8");
61715
+ const content = fs44.readFileSync(fullPath, "utf-8");
60865
61716
  const lines = countCodeLines(content);
60866
61717
  callback(lines);
60867
61718
  } catch {}
@@ -61062,11 +61913,11 @@ async function getGitChurn(days, directory) {
61062
61913
  }
61063
61914
  function getComplexityForFile2(filePath) {
61064
61915
  try {
61065
- const stat2 = fs43.statSync(filePath);
61916
+ const stat2 = fs45.statSync(filePath);
61066
61917
  if (stat2.size > MAX_FILE_SIZE_BYTES4) {
61067
61918
  return null;
61068
61919
  }
61069
- const content = fs43.readFileSync(filePath, "utf-8");
61920
+ const content = fs45.readFileSync(filePath, "utf-8");
61070
61921
  return estimateCyclomaticComplexity(content);
61071
61922
  } catch {
61072
61923
  return null;
@@ -61077,7 +61928,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
61077
61928
  const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
61078
61929
  const filteredChurn = new Map;
61079
61930
  for (const [file3, count] of churnMap) {
61080
- const ext = path55.extname(file3).toLowerCase();
61931
+ const ext = path56.extname(file3).toLowerCase();
61081
61932
  if (extSet.has(ext)) {
61082
61933
  filteredChurn.set(file3, count);
61083
61934
  }
@@ -61087,8 +61938,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
61087
61938
  let analyzedFiles = 0;
61088
61939
  for (const [file3, churnCount] of filteredChurn) {
61089
61940
  let fullPath = file3;
61090
- if (!fs43.existsSync(fullPath)) {
61091
- fullPath = path55.join(cwd, file3);
61941
+ if (!fs45.existsSync(fullPath)) {
61942
+ fullPath = path56.join(cwd, file3);
61092
61943
  }
61093
61944
  const complexity = getComplexityForFile2(fullPath);
61094
61945
  if (complexity !== null) {
@@ -61352,9 +62203,10 @@ var curator_analyze = createSwarmTool({
61352
62203
  });
61353
62204
  // src/tools/declare-scope.ts
61354
62205
  init_tool();
61355
- import * as fs44 from "fs";
61356
- import * as path56 from "path";
62206
+ init_state();
61357
62207
  init_create_tool();
62208
+ import * as fs46 from "fs";
62209
+ import * as path57 from "path";
61358
62210
  function validateTaskIdFormat(taskId) {
61359
62211
  const taskIdPattern = /^\d+\.\d+(\.\d+)*$/;
61360
62212
  if (!taskIdPattern.test(taskId)) {
@@ -61432,8 +62284,8 @@ async function executeDeclareScope(args2, fallbackDir) {
61432
62284
  };
61433
62285
  }
61434
62286
  }
61435
- normalizedDir = path56.normalize(args2.working_directory);
61436
- const pathParts = normalizedDir.split(path56.sep);
62287
+ normalizedDir = path57.normalize(args2.working_directory);
62288
+ const pathParts = normalizedDir.split(path57.sep);
61437
62289
  if (pathParts.includes("..")) {
61438
62290
  return {
61439
62291
  success: false,
@@ -61443,11 +62295,11 @@ async function executeDeclareScope(args2, fallbackDir) {
61443
62295
  ]
61444
62296
  };
61445
62297
  }
61446
- const resolvedDir = path56.resolve(normalizedDir);
62298
+ const resolvedDir = path57.resolve(normalizedDir);
61447
62299
  try {
61448
- const realPath = fs44.realpathSync(resolvedDir);
61449
- const planPath2 = path56.join(realPath, ".swarm", "plan.json");
61450
- if (!fs44.existsSync(planPath2)) {
62300
+ const realPath = fs46.realpathSync(resolvedDir);
62301
+ const planPath2 = path57.join(realPath, ".swarm", "plan.json");
62302
+ if (!fs46.existsSync(planPath2)) {
61451
62303
  return {
61452
62304
  success: false,
61453
62305
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -61470,8 +62322,8 @@ async function executeDeclareScope(args2, fallbackDir) {
61470
62322
  console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
61471
62323
  }
61472
62324
  const directory = normalizedDir || fallbackDir;
61473
- const planPath = path56.resolve(directory, ".swarm", "plan.json");
61474
- if (!fs44.existsSync(planPath)) {
62325
+ const planPath = path57.resolve(directory, ".swarm", "plan.json");
62326
+ if (!fs46.existsSync(planPath)) {
61475
62327
  return {
61476
62328
  success: false,
61477
62329
  message: "No plan found",
@@ -61480,7 +62332,7 @@ async function executeDeclareScope(args2, fallbackDir) {
61480
62332
  }
61481
62333
  let planContent;
61482
62334
  try {
61483
- planContent = JSON.parse(fs44.readFileSync(planPath, "utf-8"));
62335
+ planContent = JSON.parse(fs46.readFileSync(planPath, "utf-8"));
61484
62336
  } catch {
61485
62337
  return {
61486
62338
  success: false,
@@ -61512,8 +62364,8 @@ async function executeDeclareScope(args2, fallbackDir) {
61512
62364
  const normalizeErrors = [];
61513
62365
  const dir = normalizedDir || fallbackDir || process.cwd();
61514
62366
  const mergedFiles = rawMergedFiles.map((file3) => {
61515
- if (path56.isAbsolute(file3)) {
61516
- const relativePath = path56.relative(dir, file3).replace(/\\/g, "/");
62367
+ if (path57.isAbsolute(file3)) {
62368
+ const relativePath = path57.relative(dir, file3).replace(/\\/g, "/");
61517
62369
  if (relativePath.startsWith("..")) {
61518
62370
  normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
61519
62371
  return file3;
@@ -61852,20 +62704,20 @@ function validateBase(base) {
61852
62704
  function validatePaths(paths) {
61853
62705
  if (!paths)
61854
62706
  return null;
61855
- for (const path58 of paths) {
61856
- if (!path58 || path58.length === 0) {
62707
+ for (const path59 of paths) {
62708
+ if (!path59 || path59.length === 0) {
61857
62709
  return "empty path not allowed";
61858
62710
  }
61859
- if (path58.length > MAX_PATH_LENGTH) {
62711
+ if (path59.length > MAX_PATH_LENGTH) {
61860
62712
  return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
61861
62713
  }
61862
- if (SHELL_METACHARACTERS2.test(path58)) {
62714
+ if (SHELL_METACHARACTERS2.test(path59)) {
61863
62715
  return "path contains shell metacharacters";
61864
62716
  }
61865
- if (path58.startsWith("-")) {
62717
+ if (path59.startsWith("-")) {
61866
62718
  return 'path cannot start with "-" (option-like arguments not allowed)';
61867
62719
  }
61868
- if (CONTROL_CHAR_PATTERN2.test(path58)) {
62720
+ if (CONTROL_CHAR_PATTERN2.test(path59)) {
61869
62721
  return "path contains control characters";
61870
62722
  }
61871
62723
  }
@@ -61946,8 +62798,8 @@ var diff = createSwarmTool({
61946
62798
  if (parts2.length >= 3) {
61947
62799
  const additions = parseInt(parts2[0], 10) || 0;
61948
62800
  const deletions = parseInt(parts2[1], 10) || 0;
61949
- const path58 = parts2[2];
61950
- files.push({ path: path58, additions, deletions });
62801
+ const path59 = parts2[2];
62802
+ files.push({ path: path59, additions, deletions });
61951
62803
  }
61952
62804
  }
61953
62805
  const contractChanges = [];
@@ -62229,8 +63081,8 @@ Use these as DOMAIN values when delegating to @sme.`;
62229
63081
  // src/tools/evidence-check.ts
62230
63082
  init_dist();
62231
63083
  init_create_tool();
62232
- import * as fs45 from "fs";
62233
- import * as path58 from "path";
63084
+ import * as fs47 from "fs";
63085
+ import * as path59 from "path";
62234
63086
  var MAX_FILE_SIZE_BYTES5 = 1024 * 1024;
62235
63087
  var MAX_EVIDENCE_FILES = 1000;
62236
63088
  var EVIDENCE_DIR2 = ".swarm/evidence";
@@ -62257,9 +63109,9 @@ function validateRequiredTypes(input) {
62257
63109
  return null;
62258
63110
  }
62259
63111
  function isPathWithinSwarm2(filePath, cwd) {
62260
- const normalizedCwd = path58.resolve(cwd);
62261
- const swarmPath = path58.join(normalizedCwd, ".swarm");
62262
- const normalizedPath = path58.resolve(filePath);
63112
+ const normalizedCwd = path59.resolve(cwd);
63113
+ const swarmPath = path59.join(normalizedCwd, ".swarm");
63114
+ const normalizedPath = path59.resolve(filePath);
62263
63115
  return normalizedPath.startsWith(swarmPath);
62264
63116
  }
62265
63117
  function parseCompletedTasks(planContent) {
@@ -62275,12 +63127,12 @@ function parseCompletedTasks(planContent) {
62275
63127
  }
62276
63128
  function readEvidenceFiles(evidenceDir, _cwd) {
62277
63129
  const evidence = [];
62278
- if (!fs45.existsSync(evidenceDir) || !fs45.statSync(evidenceDir).isDirectory()) {
63130
+ if (!fs47.existsSync(evidenceDir) || !fs47.statSync(evidenceDir).isDirectory()) {
62279
63131
  return evidence;
62280
63132
  }
62281
63133
  let files;
62282
63134
  try {
62283
- files = fs45.readdirSync(evidenceDir);
63135
+ files = fs47.readdirSync(evidenceDir);
62284
63136
  } catch {
62285
63137
  return evidence;
62286
63138
  }
@@ -62289,14 +63141,14 @@ function readEvidenceFiles(evidenceDir, _cwd) {
62289
63141
  if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
62290
63142
  continue;
62291
63143
  }
62292
- const filePath = path58.join(evidenceDir, filename);
63144
+ const filePath = path59.join(evidenceDir, filename);
62293
63145
  try {
62294
- const resolvedPath = path58.resolve(filePath);
62295
- const evidenceDirResolved = path58.resolve(evidenceDir);
63146
+ const resolvedPath = path59.resolve(filePath);
63147
+ const evidenceDirResolved = path59.resolve(evidenceDir);
62296
63148
  if (!resolvedPath.startsWith(evidenceDirResolved)) {
62297
63149
  continue;
62298
63150
  }
62299
- const stat2 = fs45.lstatSync(filePath);
63151
+ const stat2 = fs47.lstatSync(filePath);
62300
63152
  if (!stat2.isFile()) {
62301
63153
  continue;
62302
63154
  }
@@ -62305,7 +63157,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
62305
63157
  }
62306
63158
  let fileStat;
62307
63159
  try {
62308
- fileStat = fs45.statSync(filePath);
63160
+ fileStat = fs47.statSync(filePath);
62309
63161
  if (fileStat.size > MAX_FILE_SIZE_BYTES5) {
62310
63162
  continue;
62311
63163
  }
@@ -62314,7 +63166,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
62314
63166
  }
62315
63167
  let content;
62316
63168
  try {
62317
- content = fs45.readFileSync(filePath, "utf-8");
63169
+ content = fs47.readFileSync(filePath, "utf-8");
62318
63170
  } catch {
62319
63171
  continue;
62320
63172
  }
@@ -62410,7 +63262,7 @@ var evidence_check = createSwarmTool({
62410
63262
  return JSON.stringify(errorResult, null, 2);
62411
63263
  }
62412
63264
  const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
62413
- const planPath = path58.join(cwd, PLAN_FILE);
63265
+ const planPath = path59.join(cwd, PLAN_FILE);
62414
63266
  if (!isPathWithinSwarm2(planPath, cwd)) {
62415
63267
  const errorResult = {
62416
63268
  error: "plan file path validation failed",
@@ -62424,7 +63276,7 @@ var evidence_check = createSwarmTool({
62424
63276
  }
62425
63277
  let planContent;
62426
63278
  try {
62427
- planContent = fs45.readFileSync(planPath, "utf-8");
63279
+ planContent = fs47.readFileSync(planPath, "utf-8");
62428
63280
  } catch {
62429
63281
  const result2 = {
62430
63282
  message: "No completed tasks found in plan.",
@@ -62442,7 +63294,7 @@ var evidence_check = createSwarmTool({
62442
63294
  };
62443
63295
  return JSON.stringify(result2, null, 2);
62444
63296
  }
62445
- const evidenceDir = path58.join(cwd, EVIDENCE_DIR2);
63297
+ const evidenceDir = path59.join(cwd, EVIDENCE_DIR2);
62446
63298
  const evidence = readEvidenceFiles(evidenceDir, cwd);
62447
63299
  const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
62448
63300
  const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
@@ -62459,8 +63311,8 @@ var evidence_check = createSwarmTool({
62459
63311
  // src/tools/file-extractor.ts
62460
63312
  init_tool();
62461
63313
  init_create_tool();
62462
- import * as fs46 from "fs";
62463
- import * as path59 from "path";
63314
+ import * as fs48 from "fs";
63315
+ import * as path60 from "path";
62464
63316
  var EXT_MAP = {
62465
63317
  python: ".py",
62466
63318
  py: ".py",
@@ -62522,8 +63374,8 @@ var extract_code_blocks = createSwarmTool({
62522
63374
  execute: async (args2, directory) => {
62523
63375
  const { content, output_dir, prefix } = args2;
62524
63376
  const targetDir = output_dir || directory;
62525
- if (!fs46.existsSync(targetDir)) {
62526
- fs46.mkdirSync(targetDir, { recursive: true });
63377
+ if (!fs48.existsSync(targetDir)) {
63378
+ fs48.mkdirSync(targetDir, { recursive: true });
62527
63379
  }
62528
63380
  if (!content) {
62529
63381
  return "Error: content is required";
@@ -62541,16 +63393,16 @@ var extract_code_blocks = createSwarmTool({
62541
63393
  if (prefix) {
62542
63394
  filename = `${prefix}_${filename}`;
62543
63395
  }
62544
- let filepath = path59.join(targetDir, filename);
62545
- const base = path59.basename(filepath, path59.extname(filepath));
62546
- const ext = path59.extname(filepath);
63396
+ let filepath = path60.join(targetDir, filename);
63397
+ const base = path60.basename(filepath, path60.extname(filepath));
63398
+ const ext = path60.extname(filepath);
62547
63399
  let counter = 1;
62548
- while (fs46.existsSync(filepath)) {
62549
- filepath = path59.join(targetDir, `${base}_${counter}${ext}`);
63400
+ while (fs48.existsSync(filepath)) {
63401
+ filepath = path60.join(targetDir, `${base}_${counter}${ext}`);
62550
63402
  counter++;
62551
63403
  }
62552
63404
  try {
62553
- fs46.writeFileSync(filepath, code.trim(), "utf-8");
63405
+ fs48.writeFileSync(filepath, code.trim(), "utf-8");
62554
63406
  savedFiles.push(filepath);
62555
63407
  } catch (error93) {
62556
63408
  errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
@@ -62580,7 +63432,7 @@ init_create_tool();
62580
63432
  var GITINGEST_TIMEOUT_MS = 1e4;
62581
63433
  var GITINGEST_MAX_RESPONSE_BYTES = 5242880;
62582
63434
  var GITINGEST_MAX_RETRIES = 2;
62583
- var delay = (ms) => new Promise((resolve21) => setTimeout(resolve21, ms));
63435
+ var delay = (ms) => new Promise((resolve22) => setTimeout(resolve22, ms));
62584
63436
  async function fetchGitingest(args2) {
62585
63437
  for (let attempt = 0;attempt <= GITINGEST_MAX_RETRIES; attempt++) {
62586
63438
  try {
@@ -62666,8 +63518,8 @@ var gitingest = createSwarmTool({
62666
63518
  // src/tools/imports.ts
62667
63519
  init_dist();
62668
63520
  init_create_tool();
62669
- import * as fs47 from "fs";
62670
- import * as path60 from "path";
63521
+ import * as fs49 from "fs";
63522
+ import * as path61 from "path";
62671
63523
  var MAX_FILE_PATH_LENGTH2 = 500;
62672
63524
  var MAX_SYMBOL_LENGTH = 256;
62673
63525
  var MAX_FILE_SIZE_BYTES6 = 1024 * 1024;
@@ -62715,7 +63567,7 @@ function validateSymbolInput(symbol3) {
62715
63567
  return null;
62716
63568
  }
62717
63569
  function isBinaryFile2(filePath, buffer) {
62718
- const ext = path60.extname(filePath).toLowerCase();
63570
+ const ext = path61.extname(filePath).toLowerCase();
62719
63571
  if (ext === ".json" || ext === ".md" || ext === ".txt") {
62720
63572
  return false;
62721
63573
  }
@@ -62739,15 +63591,15 @@ function parseImports(content, targetFile, targetSymbol) {
62739
63591
  const imports = [];
62740
63592
  let _resolvedTarget;
62741
63593
  try {
62742
- _resolvedTarget = path60.resolve(targetFile);
63594
+ _resolvedTarget = path61.resolve(targetFile);
62743
63595
  } catch {
62744
63596
  _resolvedTarget = targetFile;
62745
63597
  }
62746
- const targetBasename = path60.basename(targetFile, path60.extname(targetFile));
63598
+ const targetBasename = path61.basename(targetFile, path61.extname(targetFile));
62747
63599
  const targetWithExt = targetFile;
62748
63600
  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, "/");
63601
+ const normalizedTargetWithExt = path61.normalize(targetWithExt).replace(/\\/g, "/");
63602
+ const normalizedTargetWithoutExt = path61.normalize(targetWithoutExt).replace(/\\/g, "/");
62751
63603
  const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
62752
63604
  for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
62753
63605
  const modulePath = match[1] || match[2] || match[3];
@@ -62770,9 +63622,9 @@ function parseImports(content, targetFile, targetSymbol) {
62770
63622
  }
62771
63623
  const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
62772
63624
  let isMatch = false;
62773
- const _targetDir = path60.dirname(targetFile);
62774
- const targetExt = path60.extname(targetFile);
62775
- const targetBasenameNoExt = path60.basename(targetFile, targetExt);
63625
+ const _targetDir = path61.dirname(targetFile);
63626
+ const targetExt = path61.extname(targetFile);
63627
+ const targetBasenameNoExt = path61.basename(targetFile, targetExt);
62776
63628
  const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
62777
63629
  const moduleName = modulePath.split(/[/\\]/).pop() || "";
62778
63630
  const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
@@ -62829,7 +63681,7 @@ var SKIP_DIRECTORIES3 = new Set([
62829
63681
  function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
62830
63682
  let entries;
62831
63683
  try {
62832
- entries = fs47.readdirSync(dir);
63684
+ entries = fs49.readdirSync(dir);
62833
63685
  } catch (e) {
62834
63686
  stats.fileErrors.push({
62835
63687
  path: dir,
@@ -62840,13 +63692,13 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
62840
63692
  entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
62841
63693
  for (const entry of entries) {
62842
63694
  if (SKIP_DIRECTORIES3.has(entry)) {
62843
- stats.skippedDirs.push(path60.join(dir, entry));
63695
+ stats.skippedDirs.push(path61.join(dir, entry));
62844
63696
  continue;
62845
63697
  }
62846
- const fullPath = path60.join(dir, entry);
63698
+ const fullPath = path61.join(dir, entry);
62847
63699
  let stat2;
62848
63700
  try {
62849
- stat2 = fs47.statSync(fullPath);
63701
+ stat2 = fs49.statSync(fullPath);
62850
63702
  } catch (e) {
62851
63703
  stats.fileErrors.push({
62852
63704
  path: fullPath,
@@ -62857,7 +63709,7 @@ function findSourceFiles(dir, files = [], stats = { skippedDirs: [], skippedFile
62857
63709
  if (stat2.isDirectory()) {
62858
63710
  findSourceFiles(fullPath, files, stats);
62859
63711
  } else if (stat2.isFile()) {
62860
- const ext = path60.extname(fullPath).toLowerCase();
63712
+ const ext = path61.extname(fullPath).toLowerCase();
62861
63713
  if (SUPPORTED_EXTENSIONS.includes(ext)) {
62862
63714
  files.push(fullPath);
62863
63715
  }
@@ -62914,8 +63766,8 @@ var imports = createSwarmTool({
62914
63766
  return JSON.stringify(errorResult, null, 2);
62915
63767
  }
62916
63768
  try {
62917
- const targetFile = path60.resolve(file3);
62918
- if (!fs47.existsSync(targetFile)) {
63769
+ const targetFile = path61.resolve(file3);
63770
+ if (!fs49.existsSync(targetFile)) {
62919
63771
  const errorResult = {
62920
63772
  error: `target file not found: ${file3}`,
62921
63773
  target: file3,
@@ -62925,7 +63777,7 @@ var imports = createSwarmTool({
62925
63777
  };
62926
63778
  return JSON.stringify(errorResult, null, 2);
62927
63779
  }
62928
- const targetStat = fs47.statSync(targetFile);
63780
+ const targetStat = fs49.statSync(targetFile);
62929
63781
  if (!targetStat.isFile()) {
62930
63782
  const errorResult = {
62931
63783
  error: "target must be a file, not a directory",
@@ -62936,7 +63788,7 @@ var imports = createSwarmTool({
62936
63788
  };
62937
63789
  return JSON.stringify(errorResult, null, 2);
62938
63790
  }
62939
- const baseDir = path60.dirname(targetFile);
63791
+ const baseDir = path61.dirname(targetFile);
62940
63792
  const scanStats = {
62941
63793
  skippedDirs: [],
62942
63794
  skippedFiles: 0,
@@ -62951,12 +63803,12 @@ var imports = createSwarmTool({
62951
63803
  if (consumers.length >= MAX_CONSUMERS)
62952
63804
  break;
62953
63805
  try {
62954
- const stat2 = fs47.statSync(filePath);
63806
+ const stat2 = fs49.statSync(filePath);
62955
63807
  if (stat2.size > MAX_FILE_SIZE_BYTES6) {
62956
63808
  skippedFileCount++;
62957
63809
  continue;
62958
63810
  }
62959
- const buffer = fs47.readFileSync(filePath);
63811
+ const buffer = fs49.readFileSync(filePath);
62960
63812
  if (isBinaryFile2(filePath, buffer)) {
62961
63813
  skippedFileCount++;
62962
63814
  continue;
@@ -63156,7 +64008,7 @@ init_dist();
63156
64008
  init_config();
63157
64009
  init_knowledge_store();
63158
64010
  init_create_tool();
63159
- import { existsSync as existsSync38 } from "fs";
64011
+ import { existsSync as existsSync39 } from "fs";
63160
64012
  var DEFAULT_LIMIT = 10;
63161
64013
  var MAX_LESSON_LENGTH = 200;
63162
64014
  var VALID_CATEGORIES3 = [
@@ -63225,14 +64077,14 @@ function validateLimit(limit) {
63225
64077
  }
63226
64078
  async function readSwarmKnowledge(directory) {
63227
64079
  const swarmPath = resolveSwarmKnowledgePath(directory);
63228
- if (!existsSync38(swarmPath)) {
64080
+ if (!existsSync39(swarmPath)) {
63229
64081
  return [];
63230
64082
  }
63231
64083
  return readKnowledge(swarmPath);
63232
64084
  }
63233
64085
  async function readHiveKnowledge() {
63234
64086
  const hivePath = resolveHiveKnowledgePath();
63235
- if (!existsSync38(hivePath)) {
64087
+ if (!existsSync39(hivePath)) {
63236
64088
  return [];
63237
64089
  }
63238
64090
  return readKnowledge(hivePath);
@@ -63545,62 +64397,13 @@ init_dist();
63545
64397
  init_config();
63546
64398
  init_schema();
63547
64399
  init_manager();
63548
- import * as fs49 from "fs";
64400
+ import * as fs50 from "fs";
63549
64401
  import * as path62 from "path";
63550
64402
  init_review_receipt();
63551
64403
  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
64404
  init_ledger();
63603
64405
  init_manager2();
64406
+ init_state();
63604
64407
  init_telemetry();
63605
64408
  init_create_tool();
63606
64409
  init_resolve_working_directory();
@@ -63824,7 +64627,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
63824
64627
  let driftVerdictFound = false;
63825
64628
  let driftVerdictApproved = false;
63826
64629
  try {
63827
- const driftEvidenceContent = fs49.readFileSync(driftEvidencePath, "utf-8");
64630
+ const driftEvidenceContent = fs50.readFileSync(driftEvidencePath, "utf-8");
63828
64631
  const driftEvidence = JSON.parse(driftEvidenceContent);
63829
64632
  const entries = driftEvidence.entries ?? [];
63830
64633
  for (const entry of entries) {
@@ -63855,13 +64658,13 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
63855
64658
  }
63856
64659
  if (!driftVerdictFound) {
63857
64660
  const specPath = path62.join(dir, ".swarm", "spec.md");
63858
- const specExists = fs49.existsSync(specPath);
64661
+ const specExists = fs50.existsSync(specPath);
63859
64662
  if (!specExists) {
63860
64663
  let incompleteTaskCount = 0;
63861
64664
  let planPhaseFound = false;
63862
64665
  try {
63863
64666
  const planPath = validateSwarmPath(dir, "plan.json");
63864
- const planRaw = fs49.readFileSync(planPath, "utf-8");
64667
+ const planRaw = fs50.readFileSync(planPath, "utf-8");
63865
64668
  const plan = JSON.parse(planRaw);
63866
64669
  const targetPhase = plan.phases.find((p) => p.id === phase);
63867
64670
  if (targetPhase) {
@@ -63986,7 +64789,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
63986
64789
  let phaseRequiredAgents;
63987
64790
  try {
63988
64791
  const planPath = validateSwarmPath(dir, "plan.json");
63989
- const planRaw = fs49.readFileSync(planPath, "utf-8");
64792
+ const planRaw = fs50.readFileSync(planPath, "utf-8");
63990
64793
  const plan = JSON.parse(planRaw);
63991
64794
  const phaseObj = plan.phases.find((p) => p.id === phase);
63992
64795
  phaseRequiredAgents = phaseObj?.required_agents;
@@ -64001,7 +64804,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
64001
64804
  if (agentsMissing.length > 0) {
64002
64805
  try {
64003
64806
  const planPath = validateSwarmPath(dir, "plan.json");
64004
- const planRaw = fs49.readFileSync(planPath, "utf-8");
64807
+ const planRaw = fs50.readFileSync(planPath, "utf-8");
64005
64808
  const plan = JSON.parse(planRaw);
64006
64809
  const targetPhase = plan.phases.find((p) => p.id === phase);
64007
64810
  if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
@@ -64041,7 +64844,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
64041
64844
  if (phaseCompleteConfig.regression_sweep?.enforce) {
64042
64845
  try {
64043
64846
  const planPath = validateSwarmPath(dir, "plan.json");
64044
- const planRaw = fs49.readFileSync(planPath, "utf-8");
64847
+ const planRaw = fs50.readFileSync(planPath, "utf-8");
64045
64848
  const plan = JSON.parse(planRaw);
64046
64849
  const targetPhase = plan.phases.find((p) => p.id === phase);
64047
64850
  if (targetPhase) {
@@ -64095,7 +64898,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
64095
64898
  }
64096
64899
  try {
64097
64900
  const eventsPath = validateSwarmPath(dir, "events.jsonl");
64098
- fs49.appendFileSync(eventsPath, `${JSON.stringify(event)}
64901
+ fs50.appendFileSync(eventsPath, `${JSON.stringify(event)}
64099
64902
  `, "utf-8");
64100
64903
  } catch (writeError) {
64101
64904
  warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
@@ -64116,6 +64919,9 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
64116
64919
  contributorSession.lastCompletedPhaseAgentsDispatched = new Set(contributorSession.phaseAgentsDispatched);
64117
64920
  }
64118
64921
  contributorSession.phaseAgentsDispatched = new Set;
64922
+ contributorSession.fullAutoInteractionCount = 0;
64923
+ contributorSession.fullAutoDeadlockCount = 0;
64924
+ contributorSession.fullAutoLastQuestionHash = null;
64119
64925
  contributorSession.lastPhaseCompleteTimestamp = now;
64120
64926
  const oldPhase = contributorSession.lastPhaseCompletePhase;
64121
64927
  contributorSession.lastPhaseCompletePhase = phase;
@@ -64145,12 +64951,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
64145
64951
  warnings.push(`Warning: failed to update plan.json phase status`);
64146
64952
  try {
64147
64953
  const planPath = validateSwarmPath(dir, "plan.json");
64148
- const planRaw = fs49.readFileSync(planPath, "utf-8");
64954
+ const planRaw = fs50.readFileSync(planPath, "utf-8");
64149
64955
  const plan2 = JSON.parse(planRaw);
64150
64956
  const phaseObj = plan2.phases.find((p) => p.id === phase);
64151
64957
  if (phaseObj) {
64152
64958
  phaseObj.status = "complete";
64153
- fs49.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
64959
+ fs50.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
64154
64960
  }
64155
64961
  } catch {}
64156
64962
  } else if (plan) {
@@ -64187,12 +64993,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
64187
64993
  warnings.push(`Warning: failed to update plan.json phase status`);
64188
64994
  try {
64189
64995
  const planPath = validateSwarmPath(dir, "plan.json");
64190
- const planRaw = fs49.readFileSync(planPath, "utf-8");
64996
+ const planRaw = fs50.readFileSync(planPath, "utf-8");
64191
64997
  const plan = JSON.parse(planRaw);
64192
64998
  const phaseObj = plan.phases.find((p) => p.id === phase);
64193
64999
  if (phaseObj) {
64194
65000
  phaseObj.status = "complete";
64195
- fs49.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
65001
+ fs50.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
64196
65002
  }
64197
65003
  } catch {}
64198
65004
  }
@@ -64249,7 +65055,7 @@ init_dist();
64249
65055
  init_discovery();
64250
65056
  init_utils();
64251
65057
  init_create_tool();
64252
- import * as fs50 from "fs";
65058
+ import * as fs51 from "fs";
64253
65059
  import * as path63 from "path";
64254
65060
  var MAX_OUTPUT_BYTES5 = 52428800;
64255
65061
  var AUDIT_TIMEOUT_MS = 120000;
@@ -64278,31 +65084,31 @@ function validateArgs3(args2) {
64278
65084
  function detectEcosystems(directory) {
64279
65085
  const ecosystems = [];
64280
65086
  const cwd = directory;
64281
- if (fs50.existsSync(path63.join(cwd, "package.json"))) {
65087
+ if (fs51.existsSync(path63.join(cwd, "package.json"))) {
64282
65088
  ecosystems.push("npm");
64283
65089
  }
64284
- if (fs50.existsSync(path63.join(cwd, "pyproject.toml")) || fs50.existsSync(path63.join(cwd, "requirements.txt"))) {
65090
+ if (fs51.existsSync(path63.join(cwd, "pyproject.toml")) || fs51.existsSync(path63.join(cwd, "requirements.txt"))) {
64285
65091
  ecosystems.push("pip");
64286
65092
  }
64287
- if (fs50.existsSync(path63.join(cwd, "Cargo.toml"))) {
65093
+ if (fs51.existsSync(path63.join(cwd, "Cargo.toml"))) {
64288
65094
  ecosystems.push("cargo");
64289
65095
  }
64290
- if (fs50.existsSync(path63.join(cwd, "go.mod"))) {
65096
+ if (fs51.existsSync(path63.join(cwd, "go.mod"))) {
64291
65097
  ecosystems.push("go");
64292
65098
  }
64293
65099
  try {
64294
- const files = fs50.readdirSync(cwd);
65100
+ const files = fs51.readdirSync(cwd);
64295
65101
  if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
64296
65102
  ecosystems.push("dotnet");
64297
65103
  }
64298
65104
  } catch {}
64299
- if (fs50.existsSync(path63.join(cwd, "Gemfile")) || fs50.existsSync(path63.join(cwd, "Gemfile.lock"))) {
65105
+ if (fs51.existsSync(path63.join(cwd, "Gemfile")) || fs51.existsSync(path63.join(cwd, "Gemfile.lock"))) {
64300
65106
  ecosystems.push("ruby");
64301
65107
  }
64302
- if (fs50.existsSync(path63.join(cwd, "pubspec.yaml"))) {
65108
+ if (fs51.existsSync(path63.join(cwd, "pubspec.yaml"))) {
64303
65109
  ecosystems.push("dart");
64304
65110
  }
64305
- if (fs50.existsSync(path63.join(cwd, "composer.lock"))) {
65111
+ if (fs51.existsSync(path63.join(cwd, "composer.lock"))) {
64306
65112
  ecosystems.push("composer");
64307
65113
  }
64308
65114
  return ecosystems;
@@ -65461,7 +66267,7 @@ var pkg_audit = createSwarmTool({
65461
66267
  // src/tools/placeholder-scan.ts
65462
66268
  init_dist();
65463
66269
  init_manager();
65464
- import * as fs51 from "fs";
66270
+ import * as fs52 from "fs";
65465
66271
  import * as path64 from "path";
65466
66272
  init_utils();
65467
66273
  init_create_tool();
@@ -65796,7 +66602,7 @@ async function placeholderScan(input, directory) {
65796
66602
  if (!fullPath.startsWith(resolvedDirectory + path64.sep) && fullPath !== resolvedDirectory) {
65797
66603
  continue;
65798
66604
  }
65799
- if (!fs51.existsSync(fullPath)) {
66605
+ if (!fs52.existsSync(fullPath)) {
65800
66606
  continue;
65801
66607
  }
65802
66608
  if (isAllowedByGlobs(filePath, allow_globs)) {
@@ -65804,11 +66610,11 @@ async function placeholderScan(input, directory) {
65804
66610
  }
65805
66611
  let content;
65806
66612
  try {
65807
- const stat2 = fs51.statSync(fullPath);
66613
+ const stat2 = fs52.statSync(fullPath);
65808
66614
  if (stat2.size > MAX_FILE_SIZE) {
65809
66615
  continue;
65810
66616
  }
65811
- content = fs51.readFileSync(fullPath, "utf-8");
66617
+ content = fs52.readFileSync(fullPath, "utf-8");
65812
66618
  } catch {
65813
66619
  continue;
65814
66620
  }
@@ -65870,7 +66676,7 @@ var placeholder_scan = createSwarmTool({
65870
66676
  });
65871
66677
  // src/tools/pre-check-batch.ts
65872
66678
  init_dist();
65873
- import * as fs53 from "fs";
66679
+ import * as fs54 from "fs";
65874
66680
  import * as path66 from "path";
65875
66681
 
65876
66682
  // node_modules/yocto-queue/index.js
@@ -66164,7 +66970,7 @@ var quality_budget = createSwarmTool({
66164
66970
  init_dist();
66165
66971
  init_manager();
66166
66972
  init_detector();
66167
- import * as fs52 from "fs";
66973
+ import * as fs53 from "fs";
66168
66974
  import * as path65 from "path";
66169
66975
  import { extname as extname14 } from "path";
66170
66976
 
@@ -67065,17 +67871,17 @@ var SEVERITY_ORDER = {
67065
67871
  };
67066
67872
  function shouldSkipFile(filePath) {
67067
67873
  try {
67068
- const stats = fs52.statSync(filePath);
67874
+ const stats = fs53.statSync(filePath);
67069
67875
  if (stats.size > MAX_FILE_SIZE_BYTES7) {
67070
67876
  return { skip: true, reason: "file too large" };
67071
67877
  }
67072
67878
  if (stats.size === 0) {
67073
67879
  return { skip: true, reason: "empty file" };
67074
67880
  }
67075
- const fd = fs52.openSync(filePath, "r");
67881
+ const fd = fs53.openSync(filePath, "r");
67076
67882
  const buffer = Buffer.alloc(8192);
67077
- const bytesRead = fs52.readSync(fd, buffer, 0, 8192, 0);
67078
- fs52.closeSync(fd);
67883
+ const bytesRead = fs53.readSync(fd, buffer, 0, 8192, 0);
67884
+ fs53.closeSync(fd);
67079
67885
  if (bytesRead > 0) {
67080
67886
  let nullCount = 0;
67081
67887
  for (let i2 = 0;i2 < bytesRead; i2++) {
@@ -67114,7 +67920,7 @@ function countBySeverity(findings) {
67114
67920
  }
67115
67921
  function scanFileWithTierA(filePath, language) {
67116
67922
  try {
67117
- const content = fs52.readFileSync(filePath, "utf-8");
67923
+ const content = fs53.readFileSync(filePath, "utf-8");
67118
67924
  const findings = executeRulesSync(filePath, content, language);
67119
67925
  return findings.map((f) => ({
67120
67926
  rule_id: f.rule_id,
@@ -67167,7 +67973,7 @@ async function sastScan(input, directory, config3) {
67167
67973
  _filesSkipped++;
67168
67974
  continue;
67169
67975
  }
67170
- if (!fs52.existsSync(resolvedPath)) {
67976
+ if (!fs53.existsSync(resolvedPath)) {
67171
67977
  _filesSkipped++;
67172
67978
  continue;
67173
67979
  }
@@ -67623,7 +68429,7 @@ async function runSecretscanWithFiles(files, directory) {
67623
68429
  }
67624
68430
  let stat2;
67625
68431
  try {
67626
- stat2 = fs53.statSync(file3);
68432
+ stat2 = fs54.statSync(file3);
67627
68433
  } catch {
67628
68434
  skippedFiles++;
67629
68435
  continue;
@@ -67634,7 +68440,7 @@ async function runSecretscanWithFiles(files, directory) {
67634
68440
  }
67635
68441
  let content;
67636
68442
  try {
67637
- const buffer = fs53.readFileSync(file3);
68443
+ const buffer = fs54.readFileSync(file3);
67638
68444
  if (buffer.includes(0)) {
67639
68445
  skippedFiles++;
67640
68446
  continue;
@@ -68167,10 +68973,11 @@ ${paginatedContent}`;
68167
68973
  });
68168
68974
  // src/tools/save-plan.ts
68169
68975
  init_tool();
68170
- import * as fs54 from "fs";
68976
+ import * as fs55 from "fs";
68171
68977
  import * as path67 from "path";
68172
68978
  init_ledger();
68173
68979
  init_manager2();
68980
+ init_state();
68174
68981
  init_create_tool();
68175
68982
  function detectPlaceholderContent(args2) {
68176
68983
  const issues = [];
@@ -68312,7 +69119,7 @@ async function executeSavePlan(args2, fallbackDir) {
68312
69119
  phases_count: plan.phases.length,
68313
69120
  tasks_count: tasksCount
68314
69121
  });
68315
- await fs54.promises.writeFile(markerPath, marker, "utf8");
69122
+ await fs55.promises.writeFile(markerPath, marker, "utf8");
68316
69123
  } catch {}
68317
69124
  const warnings = [];
68318
69125
  let criticReviewFound = false;
@@ -68372,7 +69179,7 @@ var save_plan = createSwarmTool({
68372
69179
  // src/tools/sbom-generate.ts
68373
69180
  init_dist();
68374
69181
  init_manager();
68375
- import * as fs55 from "fs";
69182
+ import * as fs56 from "fs";
68376
69183
  import * as path68 from "path";
68377
69184
 
68378
69185
  // src/sbom/detectors/index.ts
@@ -69221,7 +70028,7 @@ function findManifestFiles(rootDir) {
69221
70028
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
69222
70029
  function searchDir(dir) {
69223
70030
  try {
69224
- const entries = fs55.readdirSync(dir, { withFileTypes: true });
70031
+ const entries = fs56.readdirSync(dir, { withFileTypes: true });
69225
70032
  for (const entry of entries) {
69226
70033
  const fullPath = path68.join(dir, entry.name);
69227
70034
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
@@ -69248,7 +70055,7 @@ function findManifestFilesInDirs(directories, workingDir) {
69248
70055
  const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
69249
70056
  for (const dir of directories) {
69250
70057
  try {
69251
- const entries = fs55.readdirSync(dir, { withFileTypes: true });
70058
+ const entries = fs56.readdirSync(dir, { withFileTypes: true });
69252
70059
  for (const entry of entries) {
69253
70060
  const fullPath = path68.join(dir, entry.name);
69254
70061
  if (entry.isFile()) {
@@ -69285,7 +70092,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
69285
70092
  }
69286
70093
  function ensureOutputDir(outputDir) {
69287
70094
  try {
69288
- fs55.mkdirSync(outputDir, { recursive: true });
70095
+ fs56.mkdirSync(outputDir, { recursive: true });
69289
70096
  } catch (error93) {
69290
70097
  if (!error93 || error93.code !== "EEXIST") {
69291
70098
  throw error93;
@@ -69379,10 +70186,10 @@ var sbom_generate = createSwarmTool({
69379
70186
  for (const manifestFile of manifestFiles) {
69380
70187
  try {
69381
70188
  const fullPath = path68.isAbsolute(manifestFile) ? manifestFile : path68.join(workingDir, manifestFile);
69382
- if (!fs55.existsSync(fullPath)) {
70189
+ if (!fs56.existsSync(fullPath)) {
69383
70190
  continue;
69384
70191
  }
69385
- const content = fs55.readFileSync(fullPath, "utf-8");
70192
+ const content = fs56.readFileSync(fullPath, "utf-8");
69386
70193
  const components = detectComponents(manifestFile, content);
69387
70194
  processedFiles.push(manifestFile);
69388
70195
  if (components.length > 0) {
@@ -69396,7 +70203,7 @@ var sbom_generate = createSwarmTool({
69396
70203
  const bomJson = serializeCycloneDX(bom);
69397
70204
  const filename = generateSbomFilename();
69398
70205
  const outputPath = path68.join(outputDir, filename);
69399
- fs55.writeFileSync(outputPath, bomJson, "utf-8");
70206
+ fs56.writeFileSync(outputPath, bomJson, "utf-8");
69400
70207
  const verdict = processedFiles.length > 0 ? "pass" : "pass";
69401
70208
  try {
69402
70209
  const timestamp = new Date().toISOString();
@@ -69438,7 +70245,7 @@ var sbom_generate = createSwarmTool({
69438
70245
  // src/tools/schema-drift.ts
69439
70246
  init_dist();
69440
70247
  init_create_tool();
69441
- import * as fs56 from "fs";
70248
+ import * as fs57 from "fs";
69442
70249
  import * as path69 from "path";
69443
70250
  var SPEC_CANDIDATES = [
69444
70251
  "openapi.json",
@@ -69480,19 +70287,19 @@ function discoverSpecFile(cwd, specFileArg) {
69480
70287
  if (!ALLOWED_EXTENSIONS.includes(ext)) {
69481
70288
  throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
69482
70289
  }
69483
- const stats = fs56.statSync(resolvedPath);
70290
+ const stats = fs57.statSync(resolvedPath);
69484
70291
  if (stats.size > MAX_SPEC_SIZE) {
69485
70292
  throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
69486
70293
  }
69487
- if (!fs56.existsSync(resolvedPath)) {
70294
+ if (!fs57.existsSync(resolvedPath)) {
69488
70295
  throw new Error(`Spec file not found: ${resolvedPath}`);
69489
70296
  }
69490
70297
  return resolvedPath;
69491
70298
  }
69492
70299
  for (const candidate of SPEC_CANDIDATES) {
69493
70300
  const candidatePath = path69.resolve(cwd, candidate);
69494
- if (fs56.existsSync(candidatePath)) {
69495
- const stats = fs56.statSync(candidatePath);
70301
+ if (fs57.existsSync(candidatePath)) {
70302
+ const stats = fs57.statSync(candidatePath);
69496
70303
  if (stats.size <= MAX_SPEC_SIZE) {
69497
70304
  return candidatePath;
69498
70305
  }
@@ -69501,7 +70308,7 @@ function discoverSpecFile(cwd, specFileArg) {
69501
70308
  return null;
69502
70309
  }
69503
70310
  function parseSpec(specFile) {
69504
- const content = fs56.readFileSync(specFile, "utf-8");
70311
+ const content = fs57.readFileSync(specFile, "utf-8");
69505
70312
  const ext = path69.extname(specFile).toLowerCase();
69506
70313
  if (ext === ".json") {
69507
70314
  return parseJsonSpec(content);
@@ -69573,7 +70380,7 @@ function extractRoutes(cwd) {
69573
70380
  function walkDir(dir) {
69574
70381
  let entries;
69575
70382
  try {
69576
- entries = fs56.readdirSync(dir, { withFileTypes: true });
70383
+ entries = fs57.readdirSync(dir, { withFileTypes: true });
69577
70384
  } catch {
69578
70385
  return;
69579
70386
  }
@@ -69606,7 +70413,7 @@ function extractRoutes(cwd) {
69606
70413
  }
69607
70414
  function extractRoutesFromFile(filePath) {
69608
70415
  const routes = [];
69609
- const content = fs56.readFileSync(filePath, "utf-8");
70416
+ const content = fs57.readFileSync(filePath, "utf-8");
69610
70417
  const lines = content.split(/\r?\n/);
69611
70418
  const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
69612
70419
  const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
@@ -69753,7 +70560,7 @@ var schema_drift = createSwarmTool({
69753
70560
  // src/tools/search.ts
69754
70561
  init_tool();
69755
70562
  init_create_tool();
69756
- import * as fs57 from "fs";
70563
+ import * as fs58 from "fs";
69757
70564
  import * as path70 from "path";
69758
70565
  var DEFAULT_MAX_RESULTS = 100;
69759
70566
  var DEFAULT_MAX_LINES = 200;
@@ -69791,8 +70598,8 @@ function containsWindowsAttacks3(str) {
69791
70598
  function isPathInWorkspace3(filePath, workspace) {
69792
70599
  try {
69793
70600
  const resolvedPath = path70.resolve(workspace, filePath);
69794
- const realWorkspace = fs57.realpathSync(workspace);
69795
- const realResolvedPath = fs57.realpathSync(resolvedPath);
70601
+ const realWorkspace = fs58.realpathSync(workspace);
70602
+ const realResolvedPath = fs58.realpathSync(resolvedPath);
69796
70603
  const relativePath = path70.relative(realWorkspace, realResolvedPath);
69797
70604
  if (relativePath.startsWith("..") || path70.isAbsolute(relativePath)) {
69798
70605
  return false;
@@ -69812,7 +70619,7 @@ function findRgInEnvPath() {
69812
70619
  continue;
69813
70620
  const isWindows = process.platform === "win32";
69814
70621
  const candidate = path70.join(dir, isWindows ? "rg.exe" : "rg");
69815
- if (fs57.existsSync(candidate))
70622
+ if (fs58.existsSync(candidate))
69816
70623
  return candidate;
69817
70624
  }
69818
70625
  return null;
@@ -69939,7 +70746,7 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
69939
70746
  return files;
69940
70747
  }
69941
70748
  try {
69942
- const entries = fs57.readdirSync(dir, { withFileTypes: true });
70749
+ const entries = fs58.readdirSync(dir, { withFileTypes: true });
69943
70750
  for (const entry of entries) {
69944
70751
  const fullPath = path70.join(dir, entry.name);
69945
70752
  const relativePath = path70.relative(workspace, fullPath);
@@ -69989,7 +70796,7 @@ async function fallbackSearch(opts) {
69989
70796
  }
69990
70797
  let stats;
69991
70798
  try {
69992
- stats = fs57.statSync(fullPath);
70799
+ stats = fs58.statSync(fullPath);
69993
70800
  if (stats.size > MAX_FILE_SIZE_BYTES8) {
69994
70801
  continue;
69995
70802
  }
@@ -69998,7 +70805,7 @@ async function fallbackSearch(opts) {
69998
70805
  }
69999
70806
  let content;
70000
70807
  try {
70001
- content = fs57.readFileSync(fullPath, "utf-8");
70808
+ content = fs58.readFileSync(fullPath, "utf-8");
70002
70809
  } catch {
70003
70810
  continue;
70004
70811
  }
@@ -70110,7 +70917,7 @@ var search = createSwarmTool({
70110
70917
  message: "Exclude pattern contains invalid Windows-specific sequence"
70111
70918
  }, null, 2);
70112
70919
  }
70113
- if (!fs57.existsSync(directory)) {
70920
+ if (!fs58.existsSync(directory)) {
70114
70921
  return JSON.stringify({
70115
70922
  error: true,
70116
70923
  type: "unknown",
@@ -70153,7 +70960,7 @@ init_secretscan();
70153
70960
  // src/tools/suggest-patch.ts
70154
70961
  init_tool();
70155
70962
  init_create_tool();
70156
- import * as fs58 from "fs";
70963
+ import * as fs59 from "fs";
70157
70964
  import * as path71 from "path";
70158
70965
  var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
70159
70966
  function containsWindowsAttacks4(str) {
@@ -70169,11 +70976,11 @@ function containsWindowsAttacks4(str) {
70169
70976
  function isPathInWorkspace4(filePath, workspace) {
70170
70977
  try {
70171
70978
  const resolvedPath = path71.resolve(workspace, filePath);
70172
- if (!fs58.existsSync(resolvedPath)) {
70979
+ if (!fs59.existsSync(resolvedPath)) {
70173
70980
  return true;
70174
70981
  }
70175
- const realWorkspace = fs58.realpathSync(workspace);
70176
- const realResolvedPath = fs58.realpathSync(resolvedPath);
70982
+ const realWorkspace = fs59.realpathSync(workspace);
70983
+ const realResolvedPath = fs59.realpathSync(resolvedPath);
70177
70984
  const relativePath = path71.relative(realWorkspace, realResolvedPath);
70178
70985
  if (relativePath.startsWith("..") || path71.isAbsolute(relativePath)) {
70179
70986
  return false;
@@ -70347,7 +71154,7 @@ var suggestPatch = createSwarmTool({
70347
71154
  message: "changes cannot be empty"
70348
71155
  }, null, 2);
70349
71156
  }
70350
- if (!fs58.existsSync(directory)) {
71157
+ if (!fs59.existsSync(directory)) {
70351
71158
  return JSON.stringify({
70352
71159
  success: false,
70353
71160
  error: true,
@@ -70384,7 +71191,7 @@ var suggestPatch = createSwarmTool({
70384
71191
  continue;
70385
71192
  }
70386
71193
  const fullPath = path71.resolve(directory, change.file);
70387
- if (!fs58.existsSync(fullPath)) {
71194
+ if (!fs59.existsSync(fullPath)) {
70388
71195
  errors5.push({
70389
71196
  success: false,
70390
71197
  error: true,
@@ -70398,7 +71205,7 @@ var suggestPatch = createSwarmTool({
70398
71205
  }
70399
71206
  let content;
70400
71207
  try {
70401
- content = fs58.readFileSync(fullPath, "utf-8");
71208
+ content = fs59.readFileSync(fullPath, "utf-8");
70402
71209
  } catch (err2) {
70403
71210
  errors5.push({
70404
71211
  success: false,
@@ -70478,7 +71285,7 @@ var suggestPatch = createSwarmTool({
70478
71285
  init_dist();
70479
71286
  init_manager();
70480
71287
  init_detector();
70481
- import * as fs59 from "fs";
71288
+ import * as fs60 from "fs";
70482
71289
  import * as path72 from "path";
70483
71290
  init_create_tool();
70484
71291
  var MAX_FILE_SIZE2 = 5 * 1024 * 1024;
@@ -70575,7 +71382,7 @@ async function syntaxCheck(input, directory, config3) {
70575
71382
  }
70576
71383
  let content;
70577
71384
  try {
70578
- content = fs59.readFileSync(fullPath, "utf8");
71385
+ content = fs60.readFileSync(fullPath, "utf8");
70579
71386
  } catch {
70580
71387
  result.skipped_reason = "file_read_error";
70581
71388
  skippedCount++;
@@ -70655,7 +71462,7 @@ init_test_runner();
70655
71462
  init_dist();
70656
71463
  init_utils();
70657
71464
  init_create_tool();
70658
- import * as fs60 from "fs";
71465
+ import * as fs61 from "fs";
70659
71466
  import * as path73 from "path";
70660
71467
  var MAX_TEXT_LENGTH = 200;
70661
71468
  var MAX_FILE_SIZE_BYTES9 = 1024 * 1024;
@@ -70746,7 +71553,7 @@ function isSupportedExtension(filePath) {
70746
71553
  function findSourceFiles2(dir, files = []) {
70747
71554
  let entries;
70748
71555
  try {
70749
- entries = fs60.readdirSync(dir);
71556
+ entries = fs61.readdirSync(dir);
70750
71557
  } catch {
70751
71558
  return files;
70752
71559
  }
@@ -70758,7 +71565,7 @@ function findSourceFiles2(dir, files = []) {
70758
71565
  const fullPath = path73.join(dir, entry);
70759
71566
  let stat2;
70760
71567
  try {
70761
- stat2 = fs60.statSync(fullPath);
71568
+ stat2 = fs61.statSync(fullPath);
70762
71569
  } catch {
70763
71570
  continue;
70764
71571
  }
@@ -70851,7 +71658,7 @@ var todo_extract = createSwarmTool({
70851
71658
  return JSON.stringify(errorResult, null, 2);
70852
71659
  }
70853
71660
  const scanPath = resolvedPath;
70854
- if (!fs60.existsSync(scanPath)) {
71661
+ if (!fs61.existsSync(scanPath)) {
70855
71662
  const errorResult = {
70856
71663
  error: `path not found: ${pathsInput}`,
70857
71664
  total: 0,
@@ -70861,7 +71668,7 @@ var todo_extract = createSwarmTool({
70861
71668
  return JSON.stringify(errorResult, null, 2);
70862
71669
  }
70863
71670
  const filesToScan = [];
70864
- const stat2 = fs60.statSync(scanPath);
71671
+ const stat2 = fs61.statSync(scanPath);
70865
71672
  if (stat2.isFile()) {
70866
71673
  if (isSupportedExtension(scanPath)) {
70867
71674
  filesToScan.push(scanPath);
@@ -70880,11 +71687,11 @@ var todo_extract = createSwarmTool({
70880
71687
  const allEntries = [];
70881
71688
  for (const filePath of filesToScan) {
70882
71689
  try {
70883
- const fileStat = fs60.statSync(filePath);
71690
+ const fileStat = fs61.statSync(filePath);
70884
71691
  if (fileStat.size > MAX_FILE_SIZE_BYTES9) {
70885
71692
  continue;
70886
71693
  }
70887
- const content = fs60.readFileSync(filePath, "utf-8");
71694
+ const content = fs61.readFileSync(filePath, "utf-8");
70888
71695
  const entries = parseTodoComments(content, filePath, tagsSet);
70889
71696
  allEntries.push(...entries);
70890
71697
  } catch {}
@@ -70913,18 +71720,18 @@ var todo_extract = createSwarmTool({
70913
71720
  init_tool();
70914
71721
  init_schema();
70915
71722
  init_gate_evidence();
70916
- import * as fs62 from "fs";
71723
+ import * as fs63 from "fs";
70917
71724
  import * as path75 from "path";
70918
71725
 
70919
71726
  // src/hooks/diff-scope.ts
70920
- import * as fs61 from "fs";
71727
+ import * as fs62 from "fs";
70921
71728
  import * as path74 from "path";
70922
71729
  function getDeclaredScope(taskId, directory) {
70923
71730
  try {
70924
71731
  const planPath = path74.join(directory, ".swarm", "plan.json");
70925
- if (!fs61.existsSync(planPath))
71732
+ if (!fs62.existsSync(planPath))
70926
71733
  return null;
70927
- const raw = fs61.readFileSync(planPath, "utf-8");
71734
+ const raw = fs62.readFileSync(planPath, "utf-8");
70928
71735
  const plan = JSON.parse(raw);
70929
71736
  for (const phase of plan.phases ?? []) {
70930
71737
  for (const task of phase.tasks ?? []) {
@@ -71002,6 +71809,7 @@ async function validateDiffScope(taskId, directory) {
71002
71809
 
71003
71810
  // src/tools/update-task-status.ts
71004
71811
  init_manager2();
71812
+ init_state();
71005
71813
  init_telemetry();
71006
71814
  init_create_tool();
71007
71815
  var VALID_STATUSES2 = [
@@ -71052,7 +71860,7 @@ function checkReviewerGate(taskId, workingDirectory) {
71052
71860
  const resolvedDir2 = workingDirectory;
71053
71861
  try {
71054
71862
  const planPath = path75.join(resolvedDir2, ".swarm", "plan.json");
71055
- const planRaw = fs62.readFileSync(planPath, "utf-8");
71863
+ const planRaw = fs63.readFileSync(planPath, "utf-8");
71056
71864
  const plan = JSON.parse(planRaw);
71057
71865
  for (const planPhase of plan.phases ?? []) {
71058
71866
  for (const task of planPhase.tasks ?? []) {
@@ -71119,7 +71927,7 @@ function checkReviewerGate(taskId, workingDirectory) {
71119
71927
  try {
71120
71928
  const resolvedDir2 = workingDirectory;
71121
71929
  const planPath = path75.join(resolvedDir2, ".swarm", "plan.json");
71122
- const planRaw = fs62.readFileSync(planPath, "utf-8");
71930
+ const planRaw = fs63.readFileSync(planPath, "utf-8");
71123
71931
  const plan = JSON.parse(planRaw);
71124
71932
  for (const planPhase of plan.phases ?? []) {
71125
71933
  for (const task of planPhase.tasks ?? []) {
@@ -71314,9 +72122,9 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
71314
72122
  }
71315
72123
  const resolvedDir = path75.resolve(normalizedDir);
71316
72124
  try {
71317
- const realPath = fs62.realpathSync(resolvedDir);
72125
+ const realPath = fs63.realpathSync(resolvedDir);
71318
72126
  const planPath = path75.join(realPath, ".swarm", "plan.json");
71319
- if (!fs62.existsSync(planPath)) {
72127
+ if (!fs63.existsSync(planPath)) {
71320
72128
  return {
71321
72129
  success: false,
71322
72130
  message: `Invalid working_directory: plan not found in "${realPath}"`,
@@ -71348,11 +72156,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
71348
72156
  if (args2.status === "in_progress") {
71349
72157
  try {
71350
72158
  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");
72159
+ fs63.mkdirSync(path75.dirname(evidencePath), { recursive: true });
72160
+ const fd = fs63.openSync(evidencePath, "wx");
71353
72161
  let writeOk = false;
71354
72162
  try {
71355
- fs62.writeSync(fd, JSON.stringify({
72163
+ fs63.writeSync(fd, JSON.stringify({
71356
72164
  task_id: args2.task_id,
71357
72165
  required_gates: ["reviewer", "test_engineer"],
71358
72166
  gates: {},
@@ -71360,10 +72168,10 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
71360
72168
  }, null, 2));
71361
72169
  writeOk = true;
71362
72170
  } finally {
71363
- fs62.closeSync(fd);
72171
+ fs63.closeSync(fd);
71364
72172
  if (!writeOk) {
71365
72173
  try {
71366
- fs62.unlinkSync(evidencePath);
72174
+ fs63.unlinkSync(evidencePath);
71367
72175
  } catch {}
71368
72176
  }
71369
72177
  }
@@ -71374,7 +72182,7 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
71374
72182
  let phaseRequiresReviewer = true;
71375
72183
  try {
71376
72184
  const planPath = path75.join(directory, ".swarm", "plan.json");
71377
- const planRaw = fs62.readFileSync(planPath, "utf-8");
72185
+ const planRaw = fs63.readFileSync(planPath, "utf-8");
71378
72186
  const plan = JSON.parse(planRaw);
71379
72187
  const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
71380
72188
  if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
@@ -71472,7 +72280,7 @@ var update_task_status = createSwarmTool({
71472
72280
  init_tool();
71473
72281
  init_utils2();
71474
72282
  init_create_tool();
71475
- import fs63 from "fs";
72283
+ import fs64 from "fs";
71476
72284
  import path76 from "path";
71477
72285
  function normalizeVerdict(verdict) {
71478
72286
  switch (verdict) {
@@ -71533,10 +72341,10 @@ async function executeWriteDriftEvidence(args2, directory) {
71533
72341
  }
71534
72342
  const evidenceDir = path76.dirname(validatedPath);
71535
72343
  try {
71536
- await fs63.promises.mkdir(evidenceDir, { recursive: true });
72344
+ await fs64.promises.mkdir(evidenceDir, { recursive: true });
71537
72345
  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);
72346
+ await fs64.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
72347
+ await fs64.promises.rename(tempPath, validatedPath);
71540
72348
  return JSON.stringify({
71541
72349
  success: true,
71542
72350
  phase,
@@ -71614,6 +72422,14 @@ ${footerLines.join(`
71614
72422
  var _heartbeatTimers = new Map;
71615
72423
  var OpenCodeSwarm = async (ctx) => {
71616
72424
  const { config: config3, loadedFromFile } = loadPluginConfigWithMeta(ctx.directory);
72425
+ if (config3.full_auto?.enabled === true) {
72426
+ const criticModel = config3.full_auto.critic_model ?? config3.agents?.critic?.model ?? DEFAULT_MODELS.critic;
72427
+ const architectModel = config3.agents?.architect?.model ?? DEFAULT_MODELS.default;
72428
+ if (criticModel === architectModel) {
72429
+ 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)");
72430
+ }
72431
+ }
72432
+ swarmState.fullAutoEnabledInConfig = config3.full_auto?.enabled === true;
71617
72433
  swarmState.opencodeClient = ctx.client;
71618
72434
  await loadSnapshot(ctx.directory);
71619
72435
  initTelemetry(ctx.directory);
@@ -71652,6 +72468,7 @@ var OpenCodeSwarm = async (ctx) => {
71652
72468
  const delegationHandler = createDelegationTrackerHook(config3, guardrailsConfig.enabled);
71653
72469
  const authorityConfig = AuthorityConfigSchema.parse(config3.authority ?? {});
71654
72470
  const guardrailsHooks = createGuardrailsHooks(ctx.directory, undefined, guardrailsConfig, authorityConfig);
72471
+ const fullAutoInterceptHook = createFullAutoInterceptHook(config3, ctx.directory);
71655
72472
  const watchdogConfig = WatchdogConfigSchema.parse(config3.watchdog ?? {});
71656
72473
  const advisoryInjector = (sessionId, message) => {
71657
72474
  const s = swarmState.agentSessions.get(sessionId);
@@ -71976,6 +72793,10 @@ var OpenCodeSwarm = async (ctx) => {
71976
72793
  template: "/swarm turbo",
71977
72794
  description: "Use /swarm turbo to enable turbo mode for faster execution"
71978
72795
  },
72796
+ "swarm-full-auto": {
72797
+ template: "/swarm full-auto $ARGUMENTS",
72798
+ description: "Use /swarm full-auto to toggle Full-Auto Mode for the active session [on|off]"
72799
+ },
71979
72800
  "swarm-write-retro": {
71980
72801
  template: "/swarm write-retro $ARGUMENTS",
71981
72802
  description: "Use /swarm write-retro to manually write a phase retrospective"
@@ -72034,6 +72855,7 @@ var OpenCodeSwarm = async (ctx) => {
72034
72855
  pipelineHook["experimental.chat.messages.transform"],
72035
72856
  contextBudgetHandler,
72036
72857
  guardrailsHooks.messagesTransform,
72858
+ fullAutoInterceptHook?.messagesTransform,
72037
72859
  delegationGateHooks.messagesTransform,
72038
72860
  delegationSanitizerHook,
72039
72861
  knowledgeInjectorHook,