svamp-cli 0.2.44 → 0.2.46

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.
@@ -1,16 +1,16 @@
1
- import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import os from 'os';
1
+ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import os$1 from 'os';
2
2
  import fs, { mkdir as mkdir$1, readdir as readdir$1, readFile, writeFile as writeFile$1, rename, unlink } from 'fs/promises';
3
- import { readFileSync as readFileSync$1, mkdirSync, writeFileSync, renameSync, existsSync as existsSync$1, copyFileSync, unlinkSync, watch, rmdirSync } from 'fs';
3
+ import { readFileSync as readFileSync$1, mkdirSync, writeFileSync, renameSync, existsSync as existsSync$1, copyFileSync, unlinkSync as unlinkSync$1, watch, rmdirSync } from 'fs';
4
4
  import path__default, { join, dirname, resolve, basename } from 'path';
5
5
  import { fileURLToPath } from 'url';
6
6
  import { spawn as spawn$1, execSync as execSync$1 } from 'child_process';
7
7
  import { randomUUID as randomUUID$1 } from 'crypto';
8
- import { existsSync, readFileSync, writeFileSync as writeFileSync$1, mkdirSync as mkdirSync$1, appendFileSync } from 'node:fs';
8
+ import { existsSync, readFileSync, writeFileSync as writeFileSync$1, mkdirSync as mkdirSync$1, appendFileSync, unlinkSync } from 'node:fs';
9
9
  import { randomUUID, createHash } from 'node:crypto';
10
10
  import { join as join$1 } from 'node:path';
11
11
  import { spawn, execSync, execFile, execFileSync } from 'node:child_process';
12
12
  import { ndJsonStream, ClientSideConnection } from '@agentclientprotocol/sdk';
13
- import { homedir, platform } from 'node:os';
13
+ import os, { homedir, platform } from 'node:os';
14
14
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
15
15
  import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
16
16
  import { ElicitRequestSchema } from '@modelcontextprotocol/sdk/types.js';
@@ -1107,7 +1107,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
1107
1107
  const tunnels = handlers.tunnels;
1108
1108
  if (!tunnels) throw new Error("Tunnel management not available");
1109
1109
  if (tunnels.has(params.name)) throw new Error(`Tunnel '${params.name}' already running`);
1110
- const { FrpcTunnel } = await import('./frpc-DzRFx60H.mjs');
1110
+ const { FrpcTunnel } = await import('./frpc-j60b46eU.mjs');
1111
1111
  const tunnel = new FrpcTunnel({
1112
1112
  name: params.name,
1113
1113
  ports: params.ports,
@@ -5092,6 +5092,8 @@ const DEFAULT_PROBE_FAILURE_THRESHOLD = 3;
5092
5092
  const MAX_RESTART_DELAY_S = 300;
5093
5093
  const BACKOFF_RESET_WINDOW_MS = 6e4;
5094
5094
  const MAX_LOG_LINES = 300;
5095
+ const CRASH_LOOP_FAILURE_THRESHOLD = 10;
5096
+ const CRASH_LOOP_WINDOW_MS = 3e5;
5095
5097
  class ProcessSupervisor {
5096
5098
  entries = /* @__PURE__ */ new Map();
5097
5099
  persistDir;
@@ -5139,11 +5141,13 @@ class ProcessSupervisor {
5139
5141
  /** Start a stopped/failed process by id or name. */
5140
5142
  async start(idOrName) {
5141
5143
  const entry = this.require(idOrName);
5144
+ if (entry.deleted) throw new Error(`Process '${idOrName}' has been removed`);
5142
5145
  if (entry.child) {
5143
5146
  if (entry.stopping) throw new Error(`Process '${entry.spec.name}' is being stopped, try again shortly`);
5144
5147
  throw new Error(`Process '${entry.spec.name}' is already running`);
5145
5148
  }
5146
5149
  entry.stopping = false;
5150
+ this.resetFailureTracking(entry);
5147
5151
  await this.startEntry(entry, false);
5148
5152
  }
5149
5153
  /** Stop a running process. Does NOT remove it from supervision. */
@@ -5162,6 +5166,7 @@ class ProcessSupervisor {
5162
5166
  /** Restart a process (stop if running, then start again). */
5163
5167
  async restart(idOrName) {
5164
5168
  const entry = this.require(idOrName);
5169
+ if (entry.deleted) throw new Error(`Process '${idOrName}' has been removed`);
5165
5170
  if (entry.restarting) return;
5166
5171
  entry.restarting = true;
5167
5172
  try {
@@ -5171,7 +5176,9 @@ class ProcessSupervisor {
5171
5176
  await this.killChild(entry.child);
5172
5177
  entry.child = void 0;
5173
5178
  }
5179
+ if (entry.deleted) return;
5174
5180
  entry.stopping = false;
5181
+ this.resetFailureTracking(entry);
5175
5182
  entry.state.restartCount++;
5176
5183
  await this.startEntry(entry, false);
5177
5184
  } finally {
@@ -5182,7 +5189,16 @@ class ProcessSupervisor {
5182
5189
  async remove(idOrName) {
5183
5190
  const entry = this.require(idOrName);
5184
5191
  const id = entry.spec.id;
5185
- await this.stop(entry.spec.name);
5192
+ entry.deleted = true;
5193
+ entry.stopping = true;
5194
+ this.clearTimers(entry);
5195
+ if (entry.child) {
5196
+ await this.killChild(entry.child);
5197
+ entry.child = void 0;
5198
+ }
5199
+ entry.state.status = "stopped";
5200
+ entry.state.stoppedAt = Date.now();
5201
+ entry.state.pid = void 0;
5186
5202
  this.entries.delete(id);
5187
5203
  await this.deleteSpec(id);
5188
5204
  }
@@ -5232,7 +5248,9 @@ class ProcessSupervisor {
5232
5248
  await this.killChild(existing.child);
5233
5249
  existing.child = void 0;
5234
5250
  }
5251
+ if (existing.deleted) return { action: "updated", info: this.toInfo(existing) };
5235
5252
  existing.stopping = false;
5253
+ this.resetFailureTracking(existing);
5236
5254
  existing.state.status = "starting";
5237
5255
  this.spawnProcess(existing);
5238
5256
  return { action: "updated", info: this.toInfo(existing) };
@@ -5243,6 +5261,7 @@ class ProcessSupervisor {
5243
5261
  */
5244
5262
  async update(idOrName, partialSpec) {
5245
5263
  const entry = this.require(idOrName);
5264
+ if (entry.deleted) throw new Error(`Process '${idOrName}' has been removed`);
5246
5265
  const updatedSpec = { ...entry.spec, ...partialSpec };
5247
5266
  entry.spec = updatedSpec;
5248
5267
  await this.persistSpec(updatedSpec);
@@ -5252,7 +5271,9 @@ class ProcessSupervisor {
5252
5271
  await this.killChild(entry.child);
5253
5272
  entry.child = void 0;
5254
5273
  }
5274
+ if (entry.deleted) return this.toInfo(entry);
5255
5275
  entry.stopping = false;
5276
+ this.resetFailureTracking(entry);
5256
5277
  entry.state.status = "starting";
5257
5278
  this.spawnProcess(entry);
5258
5279
  return this.toInfo(entry);
@@ -5328,7 +5349,8 @@ class ProcessSupervisor {
5328
5349
  id: spec.id,
5329
5350
  status: "pending",
5330
5351
  restartCount: 0,
5331
- consecutiveProbeFailures: 0
5352
+ consecutiveProbeFailures: 0,
5353
+ consecutiveFailures: 0
5332
5354
  },
5333
5355
  logBuffer: [],
5334
5356
  stopping: false
@@ -5348,6 +5370,7 @@ class ProcessSupervisor {
5348
5370
  // ── Process spawning ──────────────────────────────────────────────────────
5349
5371
  async startEntry(entry, onRestore) {
5350
5372
  const { spec } = entry;
5373
+ if (entry.deleted) return;
5351
5374
  if (spec.ttl !== void 0 && spec.ttl > 0 && onRestore) {
5352
5375
  const elapsedS = (Date.now() - spec.createdAt) / 1e3;
5353
5376
  if (elapsedS >= spec.ttl) {
@@ -5366,6 +5389,7 @@ class ProcessSupervisor {
5366
5389
  }
5367
5390
  spawnProcess(entry) {
5368
5391
  const { spec, state } = entry;
5392
+ if (entry.deleted) return;
5369
5393
  try {
5370
5394
  const env = { ...process.env, ...spec.env ?? {} };
5371
5395
  const child = spawn$1(spec.command, spec.args, {
@@ -5408,6 +5432,7 @@ class ProcessSupervisor {
5408
5432
  state.pid = void 0;
5409
5433
  state.stoppedAt = Date.now();
5410
5434
  this.clearTimers(entry);
5435
+ if (entry.deleted) return;
5411
5436
  if (entry.stopping) {
5412
5437
  state.status = "stopped";
5413
5438
  console.log(`[SUPERVISOR] Process '${spec.name}' stopped (code=${code})`);
@@ -5417,31 +5442,65 @@ class ProcessSupervisor {
5417
5442
  state.status = crashed ? "failed" : "stopped";
5418
5443
  console.log(`[SUPERVISOR] Process '${spec.name}' exited (code=${code}, signal=${signal})`);
5419
5444
  if (!spec.keepAlive) return;
5445
+ const uptime = state.startedAt ? Date.now() - state.startedAt : 0;
5446
+ const now = Date.now();
5447
+ if (uptime > BACKOFF_RESET_WINDOW_MS) {
5448
+ state.restartCount = 0;
5449
+ state.consecutiveFailures = 0;
5450
+ entry.failureWindowStart = void 0;
5451
+ } else {
5452
+ if (!entry.failureWindowStart || now - entry.failureWindowStart > CRASH_LOOP_WINDOW_MS) {
5453
+ entry.failureWindowStart = now;
5454
+ state.consecutiveFailures = 1;
5455
+ } else {
5456
+ state.consecutiveFailures++;
5457
+ }
5458
+ }
5459
+ if (state.consecutiveFailures >= CRASH_LOOP_FAILURE_THRESHOLD) {
5460
+ const windowS = Math.round((now - (entry.failureWindowStart ?? now)) / 1e3);
5461
+ state.status = "crash-loop-backoff";
5462
+ state.crashLoopBackOff = {
5463
+ enteredAt: now,
5464
+ failureCount: state.consecutiveFailures,
5465
+ windowStart: entry.failureWindowStart ?? now
5466
+ };
5467
+ console.error(
5468
+ `[SUPERVISOR] '${spec.name}' entering CrashLoopBackOff: ${state.consecutiveFailures} failures in ${windowS}s. Restarts halted \u2014 run 'svamp process restart ${spec.name}' to retry.`
5469
+ );
5470
+ return;
5471
+ }
5420
5472
  if (spec.maxRestarts > 0 && state.restartCount >= spec.maxRestarts) {
5421
5473
  console.warn(`[SUPERVISOR] Process '${spec.name}' reached max restarts (${spec.maxRestarts}), not restarting`);
5422
5474
  state.status = "failed";
5423
5475
  return;
5424
5476
  }
5425
- const uptime = state.startedAt ? Date.now() - state.startedAt : 0;
5426
5477
  const baseDelay = spec.restartDelay * 1e3;
5427
5478
  let delayMs;
5428
5479
  if (uptime > BACKOFF_RESET_WINDOW_MS) {
5429
- state.restartCount = 0;
5430
5480
  delayMs = baseDelay;
5431
5481
  } else {
5432
- const backoffExponent = Math.min(state.restartCount, 10);
5482
+ const backoffExponent = Math.min(state.consecutiveFailures - 1, 10);
5433
5483
  delayMs = Math.min(baseDelay * Math.pow(2, backoffExponent), MAX_RESTART_DELAY_S * 1e3);
5434
5484
  const jitter = (Math.random() * 0.2 - 0.1) * delayMs;
5435
5485
  delayMs = Math.max(baseDelay, Math.round(delayMs + jitter));
5436
5486
  }
5437
- console.log(`[SUPERVISOR] Scheduling restart of '${spec.name}' in ${delayMs}ms (restart #${state.restartCount + 1}, uptime=${Math.round(uptime / 1e3)}s)`);
5487
+ console.log(
5488
+ `[SUPERVISOR] Scheduling restart of '${spec.name}' in ${delayMs}ms (failure ${state.consecutiveFailures}/${CRASH_LOOP_FAILURE_THRESHOLD}, restart #${state.restartCount + 1}, uptime=${Math.round(uptime / 1e3)}s)`
5489
+ );
5438
5490
  entry.restartTimer = setTimeout(() => {
5439
- if (entry.stopping) return;
5491
+ if (entry.deleted || entry.stopping) return;
5440
5492
  state.restartCount++;
5441
5493
  state.status = "starting";
5442
5494
  this.spawnProcess(entry);
5443
5495
  }, delayMs);
5444
5496
  }
5497
+ /** Reset all CrashLoopBackOff accounting. Called on user-initiated start/restart/spec-change. */
5498
+ resetFailureTracking(entry) {
5499
+ entry.state.consecutiveFailures = 0;
5500
+ entry.state.consecutiveProbeFailures = 0;
5501
+ entry.state.crashLoopBackOff = void 0;
5502
+ entry.failureWindowStart = void 0;
5503
+ }
5445
5504
  // ── Health probes ─────────────────────────────────────────────────────────
5446
5505
  setupProbe(entry) {
5447
5506
  const intervalMs = (entry.spec.probe.interval ?? DEFAULT_PROBE_INTERVAL_S) * 1e3;
@@ -5451,6 +5510,7 @@ class ProcessSupervisor {
5451
5510
  }, intervalMs);
5452
5511
  }
5453
5512
  async runHealthCheck(entry) {
5513
+ if (entry.deleted || entry.stopping) return;
5454
5514
  if (!entry.child || entry.state.status !== "running") return;
5455
5515
  const probe = entry.spec.probe;
5456
5516
  const urlPath = probe.path ?? "/";
@@ -5491,15 +5551,17 @@ class ProcessSupervisor {
5491
5551
  }
5492
5552
  }
5493
5553
  async triggerProbeRestart(entry) {
5494
- if (entry.restarting) return;
5554
+ if (entry.deleted) return;
5495
5555
  if (entry.stopping) return;
5496
- console.warn(`[SUPERVISOR] Restarting '${entry.spec.name}' due to probe failures`);
5556
+ if (entry.restarting) return;
5557
+ if (entry.state.status === "crash-loop-backoff") return;
5558
+ console.warn(`[SUPERVISOR] Probe failed for '${entry.spec.name}' \u2014 killing to trigger restart`);
5497
5559
  entry.state.consecutiveProbeFailures = 0;
5498
- this.clearTimers(entry);
5499
- try {
5500
- await this.restart(entry.spec.id);
5501
- } catch (err) {
5502
- console.error(`[SUPERVISOR] Probe-triggered restart failed for '${entry.spec.name}': ${err.message}`);
5560
+ if (entry.child) {
5561
+ try {
5562
+ entry.child.kill("SIGTERM");
5563
+ } catch {
5564
+ }
5503
5565
  }
5504
5566
  }
5505
5567
  // ── TTL ───────────────────────────────────────────────────────────────────
@@ -5514,9 +5576,11 @@ class ProcessSupervisor {
5514
5576
  entry.ttlTimer = setTimeout(() => this.expireProcess(entry), remainingS * 1e3);
5515
5577
  }
5516
5578
  expireProcess(entry) {
5579
+ if (entry.deleted) return;
5517
5580
  console.log(`[SUPERVISOR] Process '${entry.spec.name}' TTL expired`);
5518
5581
  entry.state.status = "expired";
5519
5582
  entry.stopping = true;
5583
+ entry.deleted = true;
5520
5584
  this.clearTimers(entry);
5521
5585
  const cleanup = async () => {
5522
5586
  if (entry.child) await this.killChild(entry.child);
@@ -5677,9 +5741,201 @@ You may be running in parallel with other agents \u2014 possibly sharing the sam
5677
5741
  `;
5678
5742
  }
5679
5743
 
5744
+ const SVAMP_HOME$1 = process.env.SVAMP_HOME || join$1(os.homedir(), ".svamp");
5745
+ function generateHookSettings(portOrOptions = {}) {
5746
+ const opts = typeof portOrOptions === "number" ? { sessionStartPort: portOrOptions } : portOrOptions;
5747
+ const hooksDir = join$1(SVAMP_HOME$1, "tmp", "hooks");
5748
+ mkdirSync$1(hooksDir, { recursive: true });
5749
+ const id = opts.id || String(process.pid);
5750
+ const validatorPath = join$1(hooksDir, `image-validator-${id}.cjs`);
5751
+ writeFileSync$1(validatorPath, IMAGE_VALIDATOR_SCRIPT, { mode: 493 });
5752
+ const cleanupPaths = [validatorPath];
5753
+ const hooks = {
5754
+ PreToolUse: [
5755
+ {
5756
+ matcher: "Read",
5757
+ hooks: [
5758
+ {
5759
+ type: "command",
5760
+ command: `node "${validatorPath}"`,
5761
+ timeout: 5
5762
+ }
5763
+ ]
5764
+ }
5765
+ ]
5766
+ };
5767
+ if (typeof opts.sessionStartPort === "number" && opts.sessionStartPort > 0) {
5768
+ const forwarderPath = join$1(hooksDir, `forwarder-${id}.cjs`);
5769
+ const forwarderCode = `#!/usr/bin/env node
5770
+ const http = require('http');
5771
+ const port = parseInt(process.argv[2], 10);
5772
+ if (!port || isNaN(port)) process.exit(1);
5773
+ const chunks = [];
5774
+ process.stdin.on('data', c => chunks.push(c));
5775
+ process.stdin.on('end', () => {
5776
+ const body = Buffer.concat(chunks);
5777
+ const req = http.request({
5778
+ host: '127.0.0.1', port, method: 'POST',
5779
+ path: '/hook/session-start',
5780
+ headers: { 'Content-Type': 'application/json', 'Content-Length': body.length }
5781
+ }, res => res.resume());
5782
+ req.on('error', () => {});
5783
+ req.end(body);
5784
+ });
5785
+ process.stdin.resume();
5786
+ `;
5787
+ writeFileSync$1(forwarderPath, forwarderCode, { mode: 493 });
5788
+ cleanupPaths.push(forwarderPath);
5789
+ hooks.SessionStart = [
5790
+ {
5791
+ matcher: "*",
5792
+ hooks: [
5793
+ {
5794
+ type: "command",
5795
+ command: `node "${forwarderPath}" ${opts.sessionStartPort}`
5796
+ }
5797
+ ]
5798
+ }
5799
+ ];
5800
+ }
5801
+ const settingsPath = join$1(hooksDir, `session-hook-${id}.json`);
5802
+ writeFileSync$1(settingsPath, JSON.stringify({ hooks }, null, 2));
5803
+ cleanupPaths.push(settingsPath);
5804
+ const cleanup = () => {
5805
+ for (const p of cleanupPaths) {
5806
+ try {
5807
+ if (existsSync(p)) unlinkSync(p);
5808
+ } catch {
5809
+ }
5810
+ }
5811
+ };
5812
+ return { settingsPath, validatorPath, hooksDir, cleanup };
5813
+ }
5814
+ const IMAGE_VALIDATOR_SCRIPT = `#!/usr/bin/env node
5815
+ 'use strict';
5816
+ const fs = require('node:fs');
5817
+
5818
+ const MAX_SIZE = 5 * 1024 * 1024;
5819
+ const IMAGE_EXTS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp']);
5820
+
5821
+ function readStdin() {
5822
+ return new Promise((resolve) => {
5823
+ let data = '';
5824
+ process.stdin.setEncoding('utf-8');
5825
+ process.stdin.on('data', (c) => { data += c; });
5826
+ process.stdin.on('end', () => resolve(data));
5827
+ process.stdin.on('error', () => resolve(''));
5828
+ });
5829
+ }
5830
+
5831
+ function deny(reason) {
5832
+ process.stderr.write(reason);
5833
+ process.exit(2);
5834
+ }
5835
+
5836
+ function detectFormat(head) {
5837
+ if (head.length >= 8
5838
+ && head[0] === 0x89 && head[1] === 0x50 && head[2] === 0x4E && head[3] === 0x47
5839
+ && head[4] === 0x0D && head[5] === 0x0A && head[6] === 0x1A && head[7] === 0x0A) return 'png';
5840
+ if (head.length >= 3
5841
+ && head[0] === 0xFF && head[1] === 0xD8 && head[2] === 0xFF) return 'jpeg';
5842
+ if (head.length >= 4
5843
+ && head[0] === 0x47 && head[1] === 0x49 && head[2] === 0x46 && head[3] === 0x38) return 'gif';
5844
+ if (head.length >= 12
5845
+ && head[0] === 0x52 && head[1] === 0x49 && head[2] === 0x46 && head[3] === 0x46
5846
+ && head[8] === 0x57 && head[9] === 0x45 && head[10] === 0x42 && head[11] === 0x50) return 'webp';
5847
+ return null;
5848
+ }
5849
+
5850
+ function checkTruncation(format, tail, fileSize, head) {
5851
+ if (format === 'png') {
5852
+ const iend = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82]);
5853
+ if (!tail.subarray(tail.length - 12).equals(iend)) {
5854
+ return 'PNG file is truncated or corrupt (missing IEND chunk).';
5855
+ }
5856
+ } else if (format === 'jpeg') {
5857
+ const last2 = tail.subarray(tail.length - 2);
5858
+ if (last2[0] !== 0xFF || last2[1] !== 0xD9) {
5859
+ return 'JPEG file is truncated (missing FF D9 EOI marker).';
5860
+ }
5861
+ } else if (format === 'gif') {
5862
+ if (tail[tail.length - 1] !== 0x3B) {
5863
+ return 'GIF file is truncated (missing 0x3B trailer).';
5864
+ }
5865
+ } else if (format === 'webp') {
5866
+ const riffSize = head.readUInt32LE(4);
5867
+ if (riffSize !== fileSize - 8) {
5868
+ return 'WebP file is corrupt (RIFF size ' + riffSize + ' != fileSize-8 ' + (fileSize - 8) + ').';
5869
+ }
5870
+ }
5871
+ return null;
5872
+ }
5873
+
5874
+ (async () => {
5875
+ const raw = await readStdin();
5876
+ let input;
5877
+ try { input = JSON.parse(raw); } catch { return; }
5878
+ if (!input || input.tool_name !== 'Read') return;
5879
+ const filePath = input.tool_input && input.tool_input.file_path;
5880
+ if (typeof filePath !== 'string' || !filePath) return;
5881
+
5882
+ const dot = filePath.lastIndexOf('.');
5883
+ if (dot < 0) return;
5884
+ const ext = filePath.slice(dot).toLowerCase();
5885
+ if (!IMAGE_EXTS.has(ext)) return;
5886
+
5887
+ let stat;
5888
+ try { stat = fs.statSync(filePath); } catch { return; } // missing \u2192 let Read tool report
5889
+ if (!stat.isFile()) return;
5890
+
5891
+ if (stat.size === 0) {
5892
+ deny('Image file is empty (0 bytes): ' + filePath + '. The Anthropic API will reject this image. Skip reading it.');
5893
+ }
5894
+ if (stat.size > MAX_SIZE) {
5895
+ deny('Image file is too large (' + (stat.size / 1024 / 1024).toFixed(1) + ' MB > 5 MB): ' + filePath + '. The Anthropic API rejects images larger than 5 MB. Skip reading it.');
5896
+ }
5897
+ if (stat.size < 12) {
5898
+ deny('Image file is too small to be a valid image (' + stat.size + ' bytes): ' + filePath + '. Skip reading it.');
5899
+ }
5900
+
5901
+ let head;
5902
+ let tail;
5903
+ try {
5904
+ const fd = fs.openSync(filePath, 'r');
5905
+ try {
5906
+ head = Buffer.alloc(32);
5907
+ const headLen = fs.readSync(fd, head, 0, 32, 0);
5908
+ head = head.subarray(0, headLen);
5909
+ const tailLen = Math.min(12, stat.size);
5910
+ tail = Buffer.alloc(tailLen);
5911
+ fs.readSync(fd, tail, 0, tailLen, stat.size - tailLen);
5912
+ } finally {
5913
+ fs.closeSync(fd);
5914
+ }
5915
+ } catch (err) {
5916
+ deny('Image file is unreadable: ' + filePath + ' \u2014 ' + (err && err.message || err) + '. Skip reading it.');
5917
+ }
5918
+
5919
+ const format = detectFormat(head);
5920
+ if (!format) {
5921
+ deny('Image file has invalid header \u2014 magic bytes do not match PNG/JPEG/GIF/WebP: ' + filePath + '. The file is corrupt or mislabeled. Skip reading it.');
5922
+ }
5923
+
5924
+ const expectedExts = { png: ['.png'], jpeg: ['.jpg', '.jpeg'], gif: ['.gif'], webp: ['.webp'] }[format];
5925
+ if (!expectedExts.includes(ext)) {
5926
+ deny('Image file extension "' + ext + '" does not match actual format "' + format + '": ' + filePath + '. Skip reading it.');
5927
+ }
5928
+
5929
+ const truncReason = checkTruncation(format, tail, stat.size, head);
5930
+ if (truncReason) {
5931
+ deny(truncReason + ' File: ' + filePath + '. Skip reading it.');
5932
+ }
5933
+ })().catch(() => { /* never block on validator errors */ });
5934
+ `;
5935
+
5680
5936
  const __filename$1 = fileURLToPath(import.meta.url);
5681
5937
  const __dirname$1 = dirname(__filename$1);
5682
- const CLAUDE_SKILLS_DIR = join(os.homedir(), ".claude", "skills");
5938
+ const CLAUDE_SKILLS_DIR = join(os$1.homedir(), ".claude", "skills");
5683
5939
  async function installSkillFromEndpoint(name, baseUrl) {
5684
5940
  const resp = await fetch(baseUrl, { signal: AbortSignal.timeout(15e3) });
5685
5941
  if (!resp.ok) throw new Error(`HTTP ${resp.status} from ${baseUrl}`);
@@ -5820,14 +6076,14 @@ function loadEnvFile(path) {
5820
6076
  return true;
5821
6077
  }
5822
6078
  function loadDotEnv() {
5823
- const svampEnv = join(process.env.SVAMP_HOME || os.homedir() + "/.svamp", ".env");
6079
+ const svampEnv = join(process.env.SVAMP_HOME || os$1.homedir() + "/.svamp", ".env");
5824
6080
  if (!loadEnvFile(svampEnv)) {
5825
- const hyphaEnv = join(process.env.HYPHA_HOME || os.homedir() + "/.hypha", ".env");
6081
+ const hyphaEnv = join(process.env.HYPHA_HOME || os$1.homedir() + "/.hypha", ".env");
5826
6082
  loadEnvFile(hyphaEnv);
5827
6083
  }
5828
6084
  }
5829
6085
  loadDotEnv();
5830
- const SVAMP_HOME = process.env.SVAMP_HOME || join(os.homedir(), ".svamp");
6086
+ const SVAMP_HOME = process.env.SVAMP_HOME || join(os$1.homedir(), ".svamp");
5831
6087
  const DAEMON_STATE_FILE = join(SVAMP_HOME, "daemon.state.json");
5832
6088
  const DAEMON_LOCK_FILE = join(SVAMP_HOME, "daemon.lock");
5833
6089
  const LOGS_DIR = join(SVAMP_HOME, "logs");
@@ -5941,7 +6197,7 @@ ${state.task}
5941
6197
  }
5942
6198
  function removeRalphState(filePath) {
5943
6199
  try {
5944
- unlinkSync(filePath);
6200
+ unlinkSync$1(filePath);
5945
6201
  } catch {
5946
6202
  }
5947
6203
  }
@@ -6313,27 +6569,27 @@ function deletePersistedSession(sessionId) {
6313
6569
  if (entry) {
6314
6570
  const sessionFile = getSessionFilePath(entry.directory, sessionId);
6315
6571
  try {
6316
- if (existsSync$1(sessionFile)) unlinkSync(sessionFile);
6572
+ if (existsSync$1(sessionFile)) unlinkSync$1(sessionFile);
6317
6573
  } catch {
6318
6574
  }
6319
6575
  const messagesFile = getSessionMessagesPath(entry.directory, sessionId);
6320
6576
  try {
6321
- if (existsSync$1(messagesFile)) unlinkSync(messagesFile);
6577
+ if (existsSync$1(messagesFile)) unlinkSync$1(messagesFile);
6322
6578
  } catch {
6323
6579
  }
6324
6580
  const configFile = getSvampConfigPath(entry.directory, sessionId);
6325
6581
  try {
6326
- if (existsSync$1(configFile)) unlinkSync(configFile);
6582
+ if (existsSync$1(configFile)) unlinkSync$1(configFile);
6327
6583
  } catch {
6328
6584
  }
6329
6585
  const ralphStateFile = getRalphStateFilePath(entry.directory, sessionId);
6330
6586
  try {
6331
- if (existsSync$1(ralphStateFile)) unlinkSync(ralphStateFile);
6587
+ if (existsSync$1(ralphStateFile)) unlinkSync$1(ralphStateFile);
6332
6588
  } catch {
6333
6589
  }
6334
6590
  const ralphProgressFile = getRalphProgressFilePath(entry.directory, sessionId);
6335
6591
  try {
6336
- if (existsSync$1(ralphProgressFile)) unlinkSync(ralphProgressFile);
6592
+ if (existsSync$1(ralphProgressFile)) unlinkSync$1(ralphProgressFile);
6337
6593
  } catch {
6338
6594
  }
6339
6595
  const sessionDir = getSessionDir(entry.directory, sessionId);
@@ -6464,7 +6720,7 @@ async function startDaemon(options) {
6464
6720
  process.on("SIGINT", () => requestShutdown("os-signal"));
6465
6721
  process.on("SIGTERM", () => requestShutdown("os-signal"));
6466
6722
  process.on("SIGUSR1", () => requestShutdown("os-signal-cleanup"));
6467
- const { watchParentLiveness } = await import('./supervisorLock-DwNAn0VN.mjs');
6723
+ const { watchParentLiveness } = await import('./supervisorLock-DmfzJx7B.mjs');
6468
6724
  const cancelParentWatchdog = watchParentLiveness({
6469
6725
  intervalMs: 5e3,
6470
6726
  onParentDeath: () => {
@@ -6603,7 +6859,7 @@ async function startDaemon(options) {
6603
6859
  machineId = readFileSync$1(machineIdFile, "utf-8").trim();
6604
6860
  }
6605
6861
  if (!machineId) {
6606
- machineId = `machine-${os.hostname()}-${randomUUID$1().slice(0, 8)}`;
6862
+ machineId = `machine-${os$1.hostname()}-${randomUUID$1().slice(0, 8)}`;
6607
6863
  try {
6608
6864
  writeFileSync(machineIdFile, machineId, "utf-8");
6609
6865
  } catch {
@@ -6618,7 +6874,7 @@ async function startDaemon(options) {
6618
6874
  const supervisor = new ProcessSupervisor(join(SVAMP_HOME, "processes"));
6619
6875
  await supervisor.init();
6620
6876
  const tunnels = /* @__PURE__ */ new Map();
6621
- const { ServeManager } = await import('./serveManager-DOXI2QzY.mjs');
6877
+ const { ServeManager } = await import('./serveManager-CUcu_V3q.mjs');
6622
6878
  const serveManager = new ServeManager(SVAMP_HOME, (msg) => logger.log(`[SERVE] ${msg}`), hyphaServerUrl);
6623
6879
  ensureAutoInstalledSkills(logger).catch(() => {
6624
6880
  });
@@ -6708,6 +6964,7 @@ async function startDaemon(options) {
6708
6964
  return await spawnAgentSession(sessionId, directory, agentName, options2, resumeSessionId);
6709
6965
  }
6710
6966
  let stagedCredentials = null;
6967
+ let hookSettings = null;
6711
6968
  try {
6712
6969
  let parseBashPermission2 = function(permission) {
6713
6970
  if (permission === "Bash") return;
@@ -6792,10 +7049,10 @@ async function startDaemon(options) {
6792
7049
  var parseBashPermission = parseBashPermission2, shouldAutoAllow = shouldAutoAllow2, killAndWaitForExit = killAndWaitForExit2, buildIsolationConfig = buildIsolationConfig2;
6793
7050
  let sessionMetadata = {
6794
7051
  path: directory,
6795
- host: os.hostname(),
7052
+ host: os$1.hostname(),
6796
7053
  version: "0.1.0",
6797
7054
  machineId,
6798
- homeDir: os.homedir(),
7055
+ homeDir: os$1.homedir(),
6799
7056
  svampHomeDir: SVAMP_HOME,
6800
7057
  svampLibDir: join(__dirname$1, ".."),
6801
7058
  svampToolsDir: join(__dirname$1, "..", "tools"),
@@ -6916,10 +7173,22 @@ async function startDaemon(options) {
6916
7173
  let isSwitchingMode = false;
6917
7174
  let checkSvampConfig;
6918
7175
  let cleanupSvampConfig;
7176
+ const VALID_CLAUDE_PERMISSION_MODES = /* @__PURE__ */ new Set(["default", "acceptEdits", "plan", "bypassPermissions"]);
6919
7177
  const CLAUDE_PERMISSION_MODE_MAP = {
6920
- "auto-approve-all": "bypassPermissions"
7178
+ "auto-approve-all": "bypassPermissions",
7179
+ "yolo": "bypassPermissions",
7180
+ "safe-yolo": "acceptEdits",
7181
+ "read-only": "plan"
7182
+ };
7183
+ const toClaudePermissionMode = (mode) => {
7184
+ if (!mode) return "default";
7185
+ const mapped = CLAUDE_PERMISSION_MODE_MAP[mode] ?? mode;
7186
+ if (!VALID_CLAUDE_PERMISSION_MODES.has(mapped)) {
7187
+ logger.log(`[Session ${sessionId}] Unknown permission mode '${mode}' \u2014 falling back to 'default'`);
7188
+ return "default";
7189
+ }
7190
+ return mapped;
6921
7191
  };
6922
- const toClaudePermissionMode = (mode) => CLAUDE_PERMISSION_MODE_MAP[mode] || mode;
6923
7192
  const getActiveSecurityContext = () => sessionMetadata.securityContext ?? options2.securityContext;
6924
7193
  const shouldIsolateSession = () => shouldIsolate({
6925
7194
  forceIsolation: options2.forceIsolation,
@@ -6956,11 +7225,28 @@ async function startDaemon(options) {
6956
7225
  if (model) args.push("--model", model);
6957
7226
  if (appendSystemPrompt) args.push("--append-system-prompt", appendSystemPrompt);
6958
7227
  if (claudeResumeId) args.push("--resume", claudeResumeId);
7228
+ if (!hookSettings) {
7229
+ try {
7230
+ hookSettings = generateHookSettings({ id: sessionId });
7231
+ logger.log(`[Session ${sessionId}] Hook settings: ${hookSettings.settingsPath} (validator: ${hookSettings.validatorPath})`);
7232
+ } catch (err) {
7233
+ logger.log(`[Session ${sessionId}] Failed to generate hook settings: ${err?.message || err}`);
7234
+ }
7235
+ }
7236
+ if (hookSettings) args.push("--settings", hookSettings.settingsPath);
6959
7237
  let spawnCommand = "claude";
6960
7238
  let spawnArgs = args;
6961
7239
  let extraEnv = {};
6962
7240
  isolationCleanupFiles = [];
6963
7241
  const isoConfig = buildIsolationConfig2(directory);
7242
+ if (isoConfig && hookSettings) {
7243
+ if (isoConfig.method === "nono") {
7244
+ isoConfig.nonoConfig = isoConfig.nonoConfig || {};
7245
+ const readFiles = isoConfig.nonoConfig.readFiles || [];
7246
+ readFiles.push(hookSettings.validatorPath, hookSettings.settingsPath);
7247
+ isoConfig.nonoConfig.readFiles = readFiles;
7248
+ }
7249
+ }
6964
7250
  if (isoConfig) {
6965
7251
  const wrapped = wrapWithIsolation(spawnCommand, spawnArgs, isoConfig);
6966
7252
  spawnCommand = wrapped.command;
@@ -7316,7 +7602,7 @@ ${progressContent}
7316
7602
  </system-reminder>
7317
7603
 
7318
7604
  The automated loop has finished. Review the progress above and let me know if you need anything else.`;
7319
- unlinkSync(progressPath);
7605
+ unlinkSync$1(progressPath);
7320
7606
  logger.log(`[Session ${sessionId}] Injected progress file content and deleted ${progressPath}`);
7321
7607
  }
7322
7608
  }
@@ -7663,12 +7949,12 @@ The automated loop has finished. Review the progress above and let me know if yo
7663
7949
  } catch {
7664
7950
  text = typeof content === "string" ? content : JSON.stringify(content);
7665
7951
  }
7666
- if (msgMeta?.permissionMode) {
7667
- currentPermissionMode = toClaudePermissionMode(msgMeta.permissionMode);
7668
- logger.log(`[Session ${sessionId}] Permission mode updated to: ${currentPermissionMode}`);
7669
- }
7670
7952
  if (msgMeta) {
7671
- lastSpawnMeta = { ...lastSpawnMeta, ...msgMeta };
7953
+ const { permissionMode: incomingPermissionMode, ...safeMsgMeta } = msgMeta;
7954
+ if (incomingPermissionMode && toClaudePermissionMode(incomingPermissionMode) !== currentPermissionMode) {
7955
+ logger.log(`[Session ${sessionId}] Ignoring meta.permissionMode='${incomingPermissionMode}' from sendMessage (current: ${currentPermissionMode}; use switchMode to change)`);
7956
+ }
7957
+ lastSpawnMeta = { ...lastSpawnMeta, ...safeMsgMeta };
7672
7958
  }
7673
7959
  if (isKillingClaude || isRestartingClaude || isSwitchingMode) {
7674
7960
  logger.log(`[Session ${sessionId}] Message received while restarting Claude, queuing to prevent loss`);
@@ -7832,12 +8118,13 @@ The automated loop has finished. Review the progress above and let me know if yo
7832
8118
  }
7833
8119
  },
7834
8120
  onSwitchMode: async (mode) => {
7835
- logger.log(`[Session ${sessionId}] Switch mode: ${mode}`);
8121
+ const normalizedMode = toClaudePermissionMode(mode);
8122
+ logger.log(`[Session ${sessionId}] Switch mode: ${mode}${mode !== normalizedMode ? ` \u2192 ${normalizedMode}` : ""}`);
7836
8123
  if (isRestartingClaude || isSwitchingMode) {
7837
8124
  logger.log(`[Session ${sessionId}] Switch mode deferred \u2014 restart/switch already in progress`);
7838
8125
  return;
7839
8126
  }
7840
- currentPermissionMode = mode;
8127
+ currentPermissionMode = normalizedMode;
7841
8128
  if (claudeProcess && claudeProcess.exitCode === null) {
7842
8129
  isSwitchingMode = true;
7843
8130
  isKillingClaude = true;
@@ -7845,7 +8132,7 @@ The automated loop has finished. Review the progress above and let me know if yo
7845
8132
  await killAndWaitForExit2(claudeProcess);
7846
8133
  isKillingClaude = false;
7847
8134
  if (trackedSession?.stopped) return;
7848
- spawnClaude(void 0, { permissionMode: mode });
8135
+ spawnClaude(void 0, { permissionMode: normalizedMode });
7849
8136
  } finally {
7850
8137
  isKillingClaude = false;
7851
8138
  isSwitchingMode = false;
@@ -8142,6 +8429,12 @@ The automated loop has finished. Review the progress above and let me know if yo
8142
8429
  resumeSessionId: claudeResumeId,
8143
8430
  restartAgent: restartClaudeHandler,
8144
8431
  cleanupCredentials: stagedCredentials?.cleanup,
8432
+ // Closure: hookSettings is generated lazily on first spawnClaude,
8433
+ // after this trackedSession is registered, so resolve the current
8434
+ // value at cleanup time rather than capturing null now.
8435
+ cleanupHookSettings: () => {
8436
+ hookSettings?.cleanup();
8437
+ },
8145
8438
  get childProcess() {
8146
8439
  return claudeProcess || void 0;
8147
8440
  }
@@ -8161,6 +8454,8 @@ The automated loop has finished. Review the progress above and let me know if yo
8161
8454
  stagedCredentials.cleanup().catch(() => {
8162
8455
  });
8163
8456
  }
8457
+ const hs = hookSettings;
8458
+ if (hs) hs.cleanup();
8164
8459
  return {
8165
8460
  type: "error",
8166
8461
  errorMessage: `Failed to register session service: ${err?.message || String(err)}`
@@ -8200,10 +8495,10 @@ The automated loop has finished. Review the progress above and let me know if yo
8200
8495
  var parseBashPermission = parseBashPermission2, shouldAutoAllow = shouldAutoAllow2;
8201
8496
  let sessionMetadata = {
8202
8497
  path: directory,
8203
- host: os.hostname(),
8498
+ host: os$1.hostname(),
8204
8499
  version: "0.1.0",
8205
8500
  machineId,
8206
- homeDir: os.homedir(),
8501
+ homeDir: os$1.homedir(),
8207
8502
  svampHomeDir: SVAMP_HOME,
8208
8503
  svampLibDir: join(__dirname$1, ".."),
8209
8504
  svampToolsDir: join(__dirname$1, "..", "tools"),
@@ -8246,8 +8541,8 @@ The automated loop has finished. Review the progress above and let me know if yo
8246
8541
  } catch {
8247
8542
  text = typeof content === "string" ? content : JSON.stringify(content);
8248
8543
  }
8249
- if (msgMeta?.permissionMode) {
8250
- currentPermissionMode = msgMeta.permissionMode;
8544
+ if (msgMeta?.permissionMode && msgMeta.permissionMode !== currentPermissionMode) {
8545
+ logger.log(`[${agentName} Session ${sessionId}] Ignoring meta.permissionMode='${msgMeta.permissionMode}' from sendMessage (current: ${currentPermissionMode}; use switchMode to change)`);
8251
8546
  }
8252
8547
  if (!acpBackendReady) {
8253
8548
  logger.log(`[${agentName} Session ${sessionId}] Backend not ready \u2014 queuing message`);
@@ -8792,6 +9087,7 @@ The automated loop has finished. Review the progress above and let me know if yo
8792
9087
  }
8793
9088
  session.cleanupCredentials?.().catch(() => {
8794
9089
  });
9090
+ session.cleanupHookSettings?.();
8795
9091
  session.cleanupSvampConfig?.();
8796
9092
  artifactSync.cancelSync(sessionId);
8797
9093
  pidToTrackedSession.delete(pid);
@@ -8824,14 +9120,14 @@ The automated loop has finished. Review the progress above and let me know if yo
8824
9120
  logger.log(`Failed to detect isolation capabilities: ${err}`);
8825
9121
  isolationCapabilities = { available: [], preferred: null, details: { nono: { found: false }, srt: { found: false }, bwrap: { found: false }, docker: { found: false }, podman: { found: false } } };
8826
9122
  }
8827
- const defaultHomeDir = existsSync$1("/data") ? "/data" : os.homedir();
9123
+ const defaultHomeDir = existsSync$1("/data") ? "/data" : os$1.homedir();
8828
9124
  const persistedMachineMeta = loadPersistedMachineMetadata(SVAMP_HOME);
8829
9125
  if (persistedMachineMeta) {
8830
9126
  logger.log(`Restored machine metadata (sharing=${!!persistedMachineMeta.sharing}, securityContextConfig=${!!persistedMachineMeta.securityContextConfig}, injectPlatformGuidance=${persistedMachineMeta.injectPlatformGuidance})`);
8831
9127
  }
8832
9128
  const machineMetadata = {
8833
- host: os.hostname(),
8834
- platform: os.platform(),
9129
+ host: os$1.hostname(),
9130
+ platform: os$1.platform(),
8835
9131
  svampVersion: "0.1.0 (hypha)",
8836
9132
  homeDir: defaultHomeDir,
8837
9133
  svampHomeDir: SVAMP_HOME,
@@ -9111,6 +9407,7 @@ The automated loop has finished. Review the progress above and let me know if yo
9111
9407
  });
9112
9408
  session.cleanupCredentials?.().catch(() => {
9113
9409
  });
9410
+ session.cleanupHookSettings?.();
9114
9411
  session.cleanupSvampConfig?.();
9115
9412
  if (session.svampSessionId) artifactSync.cancelSync(session.svampSessionId);
9116
9413
  pidToTrackedSession.delete(key);
@@ -9185,18 +9482,32 @@ The automated loop has finished. Review the progress above and let me know if yo
9185
9482
  }
9186
9483
  }
9187
9484
  }
9188
- const FRPC_FAILING_THRESHOLD_MS = 5 * 6e4;
9485
+ const FRPC_FAILING_THRESHOLD_MS = 2 * 6e4;
9486
+ const PROBE_STALENESS_THRESHOLD_MS = 2 * 6e4;
9487
+ const tunnelLooksDead = (h) => {
9488
+ if (h.failingDurationMs > FRPC_FAILING_THRESHOLD_MS) {
9489
+ return `failing ${Math.round(h.failingDurationMs / 1e3)}s`;
9490
+ }
9491
+ if (h.probe && !h.probe.ok && h.probe.stalenessMs > PROBE_STALENESS_THRESHOLD_MS) {
9492
+ return `probe stale ${Math.round(h.probe.stalenessMs / 1e3)}s`;
9493
+ }
9494
+ return null;
9495
+ };
9189
9496
  const serveHealth = serveManager.getTunnelHealth();
9190
- if (serveHealth && serveHealth.failingDurationMs > FRPC_FAILING_THRESHOLD_MS) {
9191
- logger.log(`Serve manager tunnel failing for ${Math.round(serveHealth.failingDurationMs / 1e3)}s (${serveHealth.consecutiveErrors} errors, ${serveHealth.restartAttempts} restarts) \u2014 recreating`);
9192
- serveManager.recreateTunnel().catch((err) => {
9193
- logger.log(`Failed to recreate serve tunnel: ${err.message}`);
9194
- });
9497
+ if (serveHealth) {
9498
+ const reason = tunnelLooksDead(serveHealth);
9499
+ if (reason) {
9500
+ logger.log(`Serve manager tunnel ${reason} (${serveHealth.consecutiveErrors} errors, ${serveHealth.restartAttempts} restarts) \u2014 recreating`);
9501
+ serveManager.recreateTunnel().catch((err) => {
9502
+ logger.log(`Failed to recreate serve tunnel: ${err.message}`);
9503
+ });
9504
+ }
9195
9505
  }
9196
9506
  for (const [name, tunnel] of tunnels) {
9197
9507
  const health = tunnel.status;
9198
- if (health.failingDurationMs > FRPC_FAILING_THRESHOLD_MS) {
9199
- logger.log(`frpc tunnel '${name}' failing for ${Math.round(health.failingDurationMs / 1e3)}s \u2014 destroying stale tunnel`);
9508
+ const reason = tunnelLooksDead(health);
9509
+ if (reason) {
9510
+ logger.log(`frpc tunnel '${name}' ${reason} \u2014 destroying stale tunnel`);
9200
9511
  tunnel.destroy();
9201
9512
  tunnels.delete(name);
9202
9513
  }
@@ -9533,7 +9844,7 @@ async function restartDaemon() {
9533
9844
  function daemonStatus() {
9534
9845
  const state = readDaemonStateFile();
9535
9846
  if (!state) {
9536
- const plistPath = join(os.homedir(), "Library", "LaunchAgents", "io.hypha.svamp.daemon.plist");
9847
+ const plistPath = join(os$1.homedir(), "Library", "LaunchAgents", "io.hypha.svamp.daemon.plist");
9537
9848
  if (existsSync$1(plistPath)) {
9538
9849
  console.log("Status: Not running (launchd service installed \u2014 may be starting)");
9539
9850
  } else {
@@ -9572,4 +9883,4 @@ var run = /*#__PURE__*/Object.freeze({
9572
9883
  stopDaemon: stopDaemon
9573
9884
  });
9574
9885
 
9575
- export { DefaultTransport$1 as D, GeminiTransport$1 as G, registerSessionService as a, stopDaemon as b, connectToHypha as c, daemonStatus as d, resolveSecurityContext as e, buildSecurityContextFromFlags as f, getHyphaServerUrl as g, acpBackend as h, acpAgentConfig as i, codexMcpBackend as j, claudeAuth as k, loadSecurityContextConfig as l, mergeSecurityContexts as m, run as n, registerMachineService as r, startDaemon as s };
9886
+ export { DefaultTransport$1 as D, GeminiTransport$1 as G, registerSessionService as a, stopDaemon as b, connectToHypha as c, daemonStatus as d, resolveSecurityContext as e, buildSecurityContextFromFlags as f, getHyphaServerUrl as g, generateHookSettings as h, acpBackend as i, acpAgentConfig as j, codexMcpBackend as k, loadSecurityContextConfig as l, mergeSecurityContexts as m, claudeAuth as n, run as o, registerMachineService as r, startDaemon as s };