svamp-cli 0.2.322 → 0.2.324

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.
Files changed (28) hide show
  1. package/dist/{adminCommands-CnJSw_fJ.mjs → adminCommands-CHE1wq5m.mjs} +1 -1
  2. package/dist/{agentCommands-ri042RB5.mjs → agentCommands-D7CV6DKL.mjs} +5 -5
  3. package/dist/{auth-CvQD_JbA.mjs → auth-BfimMIpL.mjs} +1 -1
  4. package/dist/{cli-BPJoSvJ0.mjs → cli-Dv0vM2P7.mjs} +82 -77
  5. package/dist/cli.mjs +2 -2
  6. package/dist/{commands-BWWAxC-g.mjs → commands-4hjEGB-I.mjs} +11 -11
  7. package/dist/{commands-yuhNv9AR.mjs → commands-BA4LVlQW.mjs} +2 -2
  8. package/dist/{commands-BxG6r6us.mjs → commands-BQ7UFowe.mjs} +3 -3
  9. package/dist/{commands-Db0PpuwO.mjs → commands-CQK2nD3o.mjs} +7 -4
  10. package/dist/{commands-BW_5joei.mjs → commands-CdbvHh2p.mjs} +2 -2
  11. package/dist/{commands-DR8N0cmJ.mjs → commands-CuyCq5eZ.mjs} +3 -3
  12. package/dist/{commands-AOno1gcV.mjs → commands-GRfwAHgR.mjs} +17 -5
  13. package/dist/{commands-D7iQqb-i.mjs → commands-jaaQooYW.mjs} +1 -1
  14. package/dist/{fleet--8tb1jX3.mjs → fleet-CSh3MUcM.mjs} +3 -3
  15. package/dist/{headlessCli-COD8n9AD.mjs → headlessCli-Zl5Yu4CL.mjs} +2 -2
  16. package/dist/index.mjs +1 -1
  17. package/dist/{notifyCommands-DLo0ANDt.mjs → notifyCommands-BQZXhfLt.mjs} +1 -1
  18. package/dist/{package-DK43B5gu.mjs → package-DgboZg2o.mjs} +2 -2
  19. package/dist/{pinnedClaudeCode-C8CmQv3y.mjs → pinnedClaudeCode-8SZDu7O-.mjs} +1 -1
  20. package/dist/{rpc-JWRwb6oY.mjs → rpc-BIzMNjqC.mjs} +1 -1
  21. package/dist/{rpc-DMlurOlf.mjs → rpc-C1KIoUyz.mjs} +1 -1
  22. package/dist/{run-BXDA0YFP.mjs → run-CEp9YpUZ.mjs} +350 -55
  23. package/dist/{run-RYTtTBDy.mjs → run-DKAROgSg.mjs} +1 -1
  24. package/dist/{scheduler-CkYMjhum.mjs → scheduler-DIYulmdV.mjs} +1 -1
  25. package/dist/{serveCommands-BX3D9l8T.mjs → serveCommands-Bq5Cw3mE.mjs} +10 -10
  26. package/dist/{sideband-CdXFW-wu.mjs → sideband-C83128hf.mjs} +1 -1
  27. package/package.json +2 -2
  28. package/dist/supervisorLock-DmfzJx7B.mjs +0 -159
@@ -9,7 +9,7 @@ import { execFile, execSync, spawn, exec as exec$1 } from 'child_process';
9
9
  import * as crypto from 'crypto';
10
10
  import { randomUUID, createHash } from 'crypto';
11
11
  import { randomUUID as randomUUID$1, randomBytes, createHash as createHash$1, timingSafeEqual } from 'node:crypto';
12
- import { existsSync, readFileSync, mkdirSync as mkdirSync$1, writeFileSync as writeFileSync$1, chmodSync as chmodSync$1, rmSync as rmSync$1, cpSync, statSync, realpathSync, readdirSync, renameSync, appendFileSync, openSync, readSync, closeSync, unlinkSync as unlinkSync$1 } from 'node:fs';
12
+ import { existsSync, readFileSync, mkdirSync as mkdirSync$1, writeFileSync as writeFileSync$1, chmodSync as chmodSync$1, rmSync as rmSync$1, cpSync, statSync, realpathSync, readdirSync, renameSync, appendFileSync, openSync, readSync, closeSync, unlinkSync as unlinkSync$1, writeSync } from 'node:fs';
13
13
  import { exec, spawn as spawn$1, execSync as execSync$1, execFile as execFile$1, execFileSync } from 'node:child_process';
14
14
  import { promisify } from 'util';
15
15
  import * as http from 'http';
@@ -2408,6 +2408,7 @@ function serveStaticMount(req, res, opts) {
2408
2408
  const { rootDir, relPath, mountUrlPrefix } = opts;
2409
2409
  const browse = opts.browse !== false;
2410
2410
  const attachment = opts.attachment === true;
2411
+ const allowHidden = opts.allowHidden === true;
2411
2412
  const method = (req.method || "GET").toUpperCase();
2412
2413
  if (method === "OPTIONS") {
2413
2414
  res.writeHead(204, CORS);
@@ -2431,7 +2432,7 @@ function serveStaticMount(req, res, opts) {
2431
2432
  sendFile(req, res, rootDir, rootStat, attachment);
2432
2433
  return;
2433
2434
  }
2434
- if (hasBlockedDotSegment(relPath)) {
2435
+ if (!allowHidden && hasBlockedDotSegment(relPath)) {
2435
2436
  res.writeHead(404, CORS);
2436
2437
  res.end("Not Found");
2437
2438
  return;
@@ -3810,7 +3811,7 @@ a{color:#0969da;text-decoration:none;font-weight:500}a:hover{text-decoration:und
3810
3811
  const normRel = this.toSessionRelative(rootDir, m[2] || "");
3811
3812
  if (method === "GET" || method === "HEAD") {
3812
3813
  if (url.searchParams.get("list") === "1") {
3813
- const lex = containedPath(rootDir, normRel);
3814
+ const lex = this.resolveContainedPath(rootDir, normRel);
3814
3815
  if (!lex) {
3815
3816
  deny(403, "Forbidden");
3816
3817
  return;
@@ -3838,7 +3839,7 @@ a{color:#0969da;text-decoration:none;font-weight:500}a:hover{text-decoration:und
3838
3839
  return;
3839
3840
  }
3840
3841
  const asAttachment = url.searchParams.get("download") === "1";
3841
- serveStaticMount(req, res, { rootDir, relPath: normRel ? `/${normRel}` : "/", mountUrlPrefix: "", browse: false, attachment: asAttachment});
3842
+ serveStaticMount(req, res, { rootDir, relPath: normRel ? `/${normRel}` : "/", mountUrlPrefix: "", browse: false, attachment: asAttachment, allowHidden: true});
3842
3843
  return;
3843
3844
  }
3844
3845
  if (method === "PUT" || method === "DELETE") {
@@ -4413,6 +4414,29 @@ var serveManager = /*#__PURE__*/Object.freeze({
4413
4414
  sanitizeMountForRole: sanitizeMountForRole
4414
4415
  });
4415
4416
 
4417
+ const EXEC_MAX_BUFFER = 16 * 1024 * 1024;
4418
+ function execFailureOutcome(err, stdout, stderr) {
4419
+ const e = err || {};
4420
+ const rawCode = e.code;
4421
+ const enobufs = rawCode === "ENOBUFS";
4422
+ const timedOut = rawCode === "ETIMEDOUT" || e.killed === true && !!e.signal;
4423
+ let exitCode;
4424
+ if (typeof rawCode === "number") exitCode = rawCode;
4425
+ else if (timedOut) exitCode = 124;
4426
+ else exitCode = 1;
4427
+ const base = stderr || e.message || "";
4428
+ let text = base;
4429
+ if (enobufs) {
4430
+ text = `output exceeded the ${Math.round(EXEC_MAX_BUFFER / (1024 * 1024))} MB buffer and was truncated (the command may have completed): ${base}`;
4431
+ } else if (timedOut) {
4432
+ text = `command timed out and was killed (it may have partially completed): ${base}`;
4433
+ }
4434
+ return { success: false, stdout: stdout || "", stderr: text, exitCode };
4435
+ }
4436
+ function execSuccessOutcome(stdout, stderr) {
4437
+ return { success: true, stdout: stdout || "", stderr: stderr || "", exitCode: 0 };
4438
+ }
4439
+
4416
4440
  const EXAMPLE_HYPHA_PROXY_URL = "https://proxy.hypha.aicell.io";
4417
4441
  const MODE_KEY = "SVAMP_CLAUDE_PROXY";
4418
4442
  const HYPHA_PROXY_URL_KEY = "SVAMP_HYPHA_PROXY_URL";
@@ -4843,6 +4867,13 @@ function stripV1(url) {
4843
4867
  }
4844
4868
  return trimmed;
4845
4869
  }
4870
+ function promptCacheTtlEnv(env, subscription) {
4871
+ if (env.FORCE_PROMPT_CACHING_5M) return void 0;
4872
+ if (!subscription) {
4873
+ return env.ENABLE_PROMPT_CACHING_1H === "1" ? "1" : void 0;
4874
+ }
4875
+ return env.ENABLE_PROMPT_CACHING_1H === "0" ? void 0 : "1";
4876
+ }
4846
4877
  function resolveAccountEnv(account, env = process.env, svampHome) {
4847
4878
  switch (account.method) {
4848
4879
  case "anthropic-api-key":
@@ -4851,7 +4882,9 @@ function resolveAccountEnv(account, env = process.env, svampHome) {
4851
4882
  claudeEnv: {
4852
4883
  ANTHROPIC_API_KEY: account.secret,
4853
4884
  ANTHROPIC_BASE_URL: account.baseUrl ? stripV1(account.baseUrl) : void 0,
4854
- CLAUDE_CODE_OAUTH_TOKEN: void 0
4885
+ CLAUDE_CODE_OAUTH_TOKEN: void 0,
4886
+ // #0986: metered first-party key — the 1h TTL costs 2.0x per cache write.
4887
+ ENABLE_PROMPT_CACHING_1H: promptCacheTtlEnv(env, false)
4855
4888
  },
4856
4889
  describe: `anthropic API key (${account.label})`
4857
4890
  };
@@ -4862,7 +4895,9 @@ function resolveAccountEnv(account, env = process.env, svampHome) {
4862
4895
  claudeEnv: {
4863
4896
  ANTHROPIC_BASE_URL: url,
4864
4897
  ANTHROPIC_API_KEY: account.secret,
4865
- CLAUDE_CODE_OAUTH_TOKEN: void 0
4898
+ CLAUDE_CODE_OAUTH_TOKEN: void 0,
4899
+ // #0986: an arbitrary gateway's billing model is unknown — opt-in only.
4900
+ ENABLE_PROMPT_CACHING_1H: promptCacheTtlEnv(env, false)
4866
4901
  },
4867
4902
  describe: `anthropic gateway ${url} (${account.label})`
4868
4903
  };
@@ -4879,7 +4914,7 @@ function resolveAccountEnv(account, env = process.env, svampHome) {
4879
4914
  ANTHROPIC_API_KEY: token,
4880
4915
  CLAUDE_CODE_OAUTH_TOKEN: void 0,
4881
4916
  // #0203: subscription backend qualifies for the free 1h prompt-cache TTL.
4882
- ENABLE_PROMPT_CACHING_1H: env.FORCE_PROMPT_CACHING_5M ? void 0 : "1"
4917
+ ENABLE_PROMPT_CACHING_1H: promptCacheTtlEnv(env, true)
4883
4918
  },
4884
4919
  describe: `hypha proxy ${url} (${account.label})`
4885
4920
  };
@@ -4890,7 +4925,9 @@ function resolveAccountEnv(account, env = process.env, svampHome) {
4890
4925
  claudeEnv: {
4891
4926
  CLAUDE_CODE_OAUTH_TOKEN: account.secret,
4892
4927
  ANTHROPIC_BASE_URL: void 0,
4893
- ANTHROPIC_API_KEY: void 0
4928
+ ANTHROPIC_API_KEY: void 0,
4929
+ // #0986: subscription token — free 1h TTL.
4930
+ ENABLE_PROMPT_CACHING_1H: promptCacheTtlEnv(env, true)
4894
4931
  },
4895
4932
  describe: `claude subscription token (${account.label})`
4896
4933
  };
@@ -4900,7 +4937,9 @@ function resolveAccountEnv(account, env = process.env, svampHome) {
4900
4937
  claudeEnv: {
4901
4938
  CLAUDE_CODE_OAUTH_TOKEN: account.accessToken,
4902
4939
  ANTHROPIC_BASE_URL: void 0,
4903
- ANTHROPIC_API_KEY: void 0
4940
+ ANTHROPIC_API_KEY: void 0,
4941
+ // #0986: subscription OAuth — free 1h TTL.
4942
+ ENABLE_PROMPT_CACHING_1H: promptCacheTtlEnv(env, true)
4904
4943
  },
4905
4944
  describe: `claude subscription oauth (${account.label})`
4906
4945
  };
@@ -5520,10 +5559,16 @@ const genKey = () => "ck_" + randomBytes(18).toString("base64url");
5520
5559
  const DEFAULT_TEMPLATE = `<inbound-message from="\${sender.name}" sender-type="\${sender.kind}" verified="\${sender.verified}" channel="\${channel.name}" call-id="\${call.id}" at="\${now}">
5521
5560
  \${body.message}
5522
5561
  </inbound-message>`;
5562
+ const CHANNEL_ID_RE = /^[A-Za-z0-9_.-]{1,64}$/;
5563
+ function isValidChannelId(id) {
5564
+ return typeof id === "string" && CHANNEL_ID_RE.test(id) && id !== "." && id !== "..";
5565
+ }
5523
5566
  function validateChannel(c) {
5524
5567
  const errs = [];
5525
5568
  if (!c || typeof c !== "object") return ["channel must be an object"];
5526
5569
  if (!c.name) errs.push("name required");
5570
+ if (c.id !== void 0 && !isValidChannelId(c.id))
5571
+ errs.push("id must match [A-Za-z0-9_.-]{1,64} (no path separators)");
5527
5572
  const m = c.identity?.mode;
5528
5573
  if (!["per-key", "caller-supplied", "fixed"].includes(m)) errs.push("identity.mode must be per-key|caller-supplied|fixed");
5529
5574
  if (m === "fixed" && !c.identity.fixed?.name) errs.push("identity.fixed.name required for fixed mode");
@@ -5590,10 +5635,14 @@ class ChannelStore {
5590
5635
  } catch {
5591
5636
  }
5592
5637
  }
5638
+ // #0982: reject a traversing/oversized id at the path boundary itself, so no
5639
+ // caller (RPC, HTTP, CLI) can reach outside this.dir regardless of its own checks.
5593
5640
  _path(id) {
5641
+ if (!isValidChannelId(id)) throw new Error(`invalid channel id: ${String(id).slice(0, 64)}`);
5594
5642
  return join$1(this.dir, `${id}.json`);
5595
5643
  }
5596
5644
  _lock(id) {
5645
+ if (!isValidChannelId(id)) throw new Error(`invalid channel id: ${String(id).slice(0, 64)}`);
5597
5646
  return join$1(this.dir, `${id}.json.lock`);
5598
5647
  }
5599
5648
  // #0679: the actual validate + atomic write, WITHOUT the lock, so a locked RMW mutator can
@@ -6462,6 +6511,15 @@ async function registerMachineService(server, machineId, metadata, daemonState,
6462
6511
  serveCallerTrusted(context),
6463
6512
  process.env.SVAMP_OWNER_EMAIL
6464
6513
  );
6514
+ const assertMayReplaceMount = (sm, name, context) => {
6515
+ const existingMount = sm.getMount(name);
6516
+ if (!existingMount || serveCallerTrusted(context)) return;
6517
+ const callerEmail = (context?.user?.email || "").toLowerCase();
6518
+ const mountOwner = (existingMount.ownerEmail || "").toLowerCase();
6519
+ if (!callerEmail || !mountOwner || callerEmail !== mountOwner) {
6520
+ throw new Error(`Not authorized to replace mount '${name}' (owned by another user)`);
6521
+ }
6522
+ };
6465
6523
  let lastInboundRpcAt = Date.now();
6466
6524
  const trackInbound = () => {
6467
6525
  lastInboundRpcAt = Date.now();
@@ -6602,6 +6660,21 @@ async function registerMachineService(server, machineId, metadata, daemonState,
6602
6660
  }
6603
6661
  return result;
6604
6662
  },
6663
+ /**
6664
+ * #0970: list ARCHIVED (stopped-but-persisted) sessions.
6665
+ *
6666
+ * Kept as its own method rather than a flag on listSessions so no existing caller's
6667
+ * view silently gains stopped rows. Machine-level `view` only: an archived session has
6668
+ * no live RPC handler, so the per-session sharing check listSessions falls back to
6669
+ * cannot run — rather than guess, this returns nothing to a caller without machine
6670
+ * access. That is the conservative direction (a session-shared user simply keeps
6671
+ * today's behaviour).
6672
+ */
6673
+ listArchivedSessions: async (context) => {
6674
+ trackInbound();
6675
+ authorizeRequest(context, currentMetadata.sharing, "view");
6676
+ return handlers.getArchivedSessions?.() || [];
6677
+ },
6605
6678
  /**
6606
6679
  * Get summary info for all sessions (metadata, agent state, activity).
6607
6680
  * Replaces the need to discover and query N individual session services.
@@ -7079,14 +7152,9 @@ async function registerMachineService(server, machineId, metadata, daemonState,
7079
7152
  const { exec } = await import('child_process');
7080
7153
  const { homedir } = await import('os');
7081
7154
  return new Promise((resolve) => {
7082
- exec(command, { cwd: cwd || homedir(), timeout: 3e4, maxBuffer: 16 * 1024 * 1024 }, (err, stdout, stderr) => {
7083
- if (err) {
7084
- const enobufs = err.code === "ENOBUFS";
7085
- const errText = enobufs ? `output exceeded the 16 MB buffer and was truncated (the command may have completed): ${stderr || err.message}` : stderr || err.message;
7086
- resolve({ success: false, stdout: stdout || "", stderr: errText, exitCode: err.code ?? 1 });
7087
- } else {
7088
- resolve({ success: true, stdout, stderr: stderr || "", exitCode: 0 });
7089
- }
7155
+ exec(command, { cwd: cwd || homedir(), timeout: 3e4, maxBuffer: EXEC_MAX_BUFFER }, (err, stdout, stderr) => {
7156
+ if (err) resolve(execFailureOutcome(err, stdout, stderr));
7157
+ else resolve(execSuccessOutcome(stdout, stderr));
7090
7158
  });
7091
7159
  });
7092
7160
  },
@@ -7631,6 +7699,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
7631
7699
  if (params.sessionId && !serveCallerTrusted(context)) {
7632
7700
  await authorizeSessionAccess(params.sessionId, "admin", context);
7633
7701
  }
7702
+ assertMayReplaceMount(sm, params.name, context);
7634
7703
  const ownerEmail2 = resolveMountOwnerEmailFor(params.ownerEmail, context);
7635
7704
  const access = params.access || "owner";
7636
7705
  return sm.addMount(params.name, params.directory, params.sessionId, access, ownerEmail2);
@@ -7651,14 +7720,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
7651
7720
  if (params.sessionId && !serveCallerTrusted(context)) {
7652
7721
  await authorizeSessionAccess(params.sessionId, "admin", context);
7653
7722
  }
7654
- const existingMount = sm.getMount(params.name);
7655
- if (existingMount && !serveCallerTrusted(context)) {
7656
- const callerEmail = (context?.user?.email || "").toLowerCase();
7657
- const mountOwner = (existingMount.ownerEmail || "").toLowerCase();
7658
- if (!callerEmail || !mountOwner || callerEmail !== mountOwner) {
7659
- throw new Error(`Not authorized to replace mount '${params.name}' (owned by another user)`);
7660
- }
7661
- }
7723
+ assertMayReplaceMount(sm, params.name, context);
7662
7724
  const ownerEmail2 = resolveMountOwnerEmailFor(params.ownerEmail, context);
7663
7725
  const access = params.access ?? "owner";
7664
7726
  return sm.applyMount({
@@ -8029,7 +8091,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
8029
8091
  }
8030
8092
  const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
8031
8093
  const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
8032
- const { toolsForRole } = await import('./sideband-CdXFW-wu.mjs');
8094
+ const { toolsForRole } = await import('./sideband-C83128hf.mjs');
8033
8095
  const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
8034
8096
  return fmt(r2);
8035
8097
  }
@@ -8134,7 +8196,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
8134
8196
  return { ok: false, call_id: callId, status: "busy", error: "channel is busy (too many concurrent requests) \u2014 retry shortly" };
8135
8197
  }
8136
8198
  const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
8137
- const { queryCore } = await import('./commands-AOno1gcV.mjs');
8199
+ const { queryCore } = await import('./commands-GRfwAHgR.mjs');
8138
8200
  const timeout = c.reply?.timeout_sec || 120;
8139
8201
  let result;
8140
8202
  try {
@@ -10241,7 +10303,7 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
10241
10303
  return { ok: result.status === "completed", call_id: callId, correlationId: callId, status: result.status, reply: result.reply, tool_calls: result.toolCalls, error: result.error };
10242
10304
  }
10243
10305
  if (c.action?.kind === "loop") return { error: "loop channels are served by the channel server, not channelSend" };
10244
- if (params.no_reply && c.action?.kind === "message") {
10306
+ if (params.no_reply && c.action?.kind === "message" && r.sender.verified) {
10245
10307
  const envelope = renderMessage(c, { sender: r.sender, body: { message: params.message }, callId });
10246
10308
  const wire = JSON.stringify({ role: "user", content: { type: "text", text: envelope } });
10247
10309
  await deliverUserMessageCore(wire, params.localId || callId, void 0, true);
@@ -10448,17 +10510,29 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
10448
10510
  return { ...lastActivity, sessionId, pendingPermissions };
10449
10511
  },
10450
10512
  // ── File Operations (optional, admin-only) ──
10513
+ // #0965: file BYTES now travel over the HTTP files-gateway (the always-on frp tunnel,
10514
+ // GET/HEAD/PUT/DELETE + ?list=1 in serveManager), NOT this hypha-rpc control WebSocket. A
10515
+ // large base64 body over RPC died on any WS blip and starved the session heartbeat. So
10516
+ // `writeFile`, `writeFileChunk` and `listDirectory` below are DEPRECATED — no current
10517
+ // frontend calls them; they're retained only so a cached/stale PWA build still has a
10518
+ // working handler (there is no client-version guard). EXCEPTIONS that stay first-class:
10519
+ // • `readFile` — control-plane, NOT file transfer: the CLI `loop status` and the
10520
+ // frontend `getSessionLoopStatus` read small `.svamp/<id>/loop/*.json` files through
10521
+ // it. Keeping loop status off the file tunnel avoids coupling the loop UI to it.
10522
+ // • `filesEndpoint` — resolves the gateway URL the frontend uses for all of the above.
10451
10523
  readFile: async (path, context) => {
10452
10524
  authorizeRequest(context, metadata.sharing, "admin");
10453
10525
  if (!callbacks.onReadFile) throw new Error("readFile not supported");
10454
10526
  return await callbacks.onReadFile(path);
10455
10527
  },
10528
+ /** @deprecated #0965 — use the HTTP files-gateway (PUT). Retained for cached-PWA skew only. */
10456
10529
  writeFile: async (path, content, context) => {
10457
10530
  authorizeRequest(context, metadata.sharing, "admin");
10458
10531
  if (!callbacks.onWriteFile) throw new Error("writeFile not supported");
10459
10532
  await callbacks.onWriteFile(path, content);
10460
10533
  return { success: true };
10461
10534
  },
10535
+ /** @deprecated #0965 — superseded by the HTTP files-gateway (PUT). Retained for cached-PWA skew only. */
10462
10536
  writeFileChunk: async (path, content, uploadId, chunkIndex, totalChunks, isLast, context) => {
10463
10537
  authorizeRequest(context, metadata.sharing, "admin");
10464
10538
  if (!callbacks.onWriteFileChunk) throw new Error("writeFileChunk not supported");
@@ -10472,6 +10546,7 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
10472
10546
  authorizeRequest(context, metadata.sharing, "admin");
10473
10547
  return { url: callbacks.onFilesEndpoint?.() ?? null };
10474
10548
  },
10549
+ /** @deprecated #0965 — use the HTTP files-gateway (GET ?list=1). Retained for cached-PWA skew only. */
10475
10550
  listDirectory: async (path, context) => {
10476
10551
  authorizeRequest(context, metadata.sharing, "admin");
10477
10552
  if (!callbacks.onListDirectory) throw new Error("listDirectory not supported");
@@ -17837,6 +17912,197 @@ function shouldForceReconnect(consecutiveHeartbeatFailures) {
17837
17912
  return consecutiveHeartbeatFailures === 2 || consecutiveHeartbeatFailures % 3 === 0;
17838
17913
  }
17839
17914
 
17915
+ function acquireSupervisorLock(pidFile, pid = process.pid) {
17916
+ try {
17917
+ const fd = openSync(pidFile, "wx");
17918
+ try {
17919
+ writeSync(fd, String(pid));
17920
+ } finally {
17921
+ closeSync(fd);
17922
+ }
17923
+ return { acquired: true };
17924
+ } catch (err) {
17925
+ if (err?.code !== "EEXIST") throw err;
17926
+ }
17927
+ let existingPid = 0;
17928
+ try {
17929
+ existingPid = parseInt(readFileSync(pidFile, "utf-8").trim(), 10);
17930
+ } catch {
17931
+ }
17932
+ if (!existingPid || Number.isNaN(existingPid) || existingPid <= 0) {
17933
+ try {
17934
+ unlinkSync$1(pidFile);
17935
+ } catch {
17936
+ }
17937
+ return { acquired: false, staleCleaned: true };
17938
+ }
17939
+ if (isPidAlive(existingPid)) {
17940
+ return { acquired: false, heldBy: existingPid };
17941
+ }
17942
+ try {
17943
+ unlinkSync$1(pidFile);
17944
+ } catch {
17945
+ }
17946
+ return { acquired: false, staleCleaned: true };
17947
+ }
17948
+ function acquireSupervisorLockWithRetry(pidFile, pid = process.pid) {
17949
+ let result = acquireSupervisorLock(pidFile, pid);
17950
+ if (!result.acquired && result.staleCleaned) {
17951
+ result = acquireSupervisorLock(pidFile, pid);
17952
+ }
17953
+ return { acquired: result.acquired, heldBy: result.heldBy };
17954
+ }
17955
+ function releaseSupervisorLock(pidFile, pid = process.pid) {
17956
+ try {
17957
+ if (!existsSync(pidFile)) return;
17958
+ const content = parseInt(readFileSync(pidFile, "utf-8").trim(), 10);
17959
+ if (content === pid) unlinkSync$1(pidFile);
17960
+ } catch {
17961
+ }
17962
+ }
17963
+ function isPidAlive(pid) {
17964
+ if (!pid || Number.isNaN(pid) || pid <= 0) return false;
17965
+ try {
17966
+ process.kill(pid, 0);
17967
+ return true;
17968
+ } catch (err) {
17969
+ return err?.code === "EPERM";
17970
+ }
17971
+ }
17972
+ function isSupervisorPid(pid) {
17973
+ if (!pid || Number.isNaN(pid) || pid <= 0) return false;
17974
+ if (process.platform === "win32") return null;
17975
+ try {
17976
+ const out = execFileSync("ps", ["-o", "command=", "-p", String(pid)], {
17977
+ encoding: "utf-8",
17978
+ timeout: 5e3,
17979
+ stdio: ["ignore", "pipe", "ignore"]
17980
+ }).trim();
17981
+ if (!out) return false;
17982
+ return /daemon\s+start-supervised/.test(out);
17983
+ } catch {
17984
+ return null;
17985
+ }
17986
+ }
17987
+ function shouldSignalSupervisor(opts) {
17988
+ const { pid, alive, isSupervisor } = opts;
17989
+ if (!pid || Number.isNaN(pid) || pid <= 0) return false;
17990
+ if (!alive) return false;
17991
+ if (isSupervisor === false) return false;
17992
+ return true;
17993
+ }
17994
+ function findOrphanedSyncPids(currentSupervisorPid = process.pid) {
17995
+ if (process.platform === "win32") return [];
17996
+ const pids = [];
17997
+ try {
17998
+ const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
17999
+ const pgrepArgs = uid !== void 0 ? ["-u", String(uid), "-af", "svamp daemon start-sync"] : ["-af", "svamp daemon start-sync"];
18000
+ const output = execFileSync("pgrep", pgrepArgs, {
18001
+ encoding: "utf-8",
18002
+ timeout: 5e3
18003
+ });
18004
+ for (const line of output.split("\n")) {
18005
+ const trimmed = line.trim();
18006
+ if (!trimmed) continue;
18007
+ const match = trimmed.match(/^(\d+)\s/);
18008
+ if (!match) continue;
18009
+ const pid = parseInt(match[1], 10);
18010
+ if (Number.isNaN(pid) || pid <= 0) continue;
18011
+ if (pid === process.pid) continue;
18012
+ const ppid = getPpid(pid);
18013
+ if (ppid === currentSupervisorPid) continue;
18014
+ pids.push(pid);
18015
+ }
18016
+ } catch (err) {
18017
+ if (err?.status !== 1) ;
18018
+ }
18019
+ return pids;
18020
+ }
18021
+ function getPpid(pid) {
18022
+ if (process.platform === "win32") return 0;
18023
+ try {
18024
+ const out = execFileSync("ps", ["-o", "ppid=", "-p", String(pid)], {
18025
+ encoding: "utf-8",
18026
+ timeout: 2e3
18027
+ }).trim();
18028
+ const ppid = parseInt(out, 10);
18029
+ return Number.isNaN(ppid) ? 0 : ppid;
18030
+ } catch {
18031
+ return 0;
18032
+ }
18033
+ }
18034
+ async function killOrphanedSyncs(pids, opts = {}) {
18035
+ if (pids.length === 0) return;
18036
+ const log = opts.log || (() => {
18037
+ });
18038
+ const gracePeriodMs = opts.gracePeriodMs ?? 3e3;
18039
+ log(`Killing ${pids.length} orphan sync daemon(s): ${pids.join(", ")}`);
18040
+ for (const pid of pids) {
18041
+ try {
18042
+ process.kill(pid, "SIGTERM");
18043
+ } catch {
18044
+ }
18045
+ }
18046
+ const pollStep = 100;
18047
+ const steps = Math.max(1, Math.ceil(gracePeriodMs / pollStep));
18048
+ for (let i = 0; i < steps; i++) {
18049
+ await new Promise((r) => setTimeout(r, pollStep));
18050
+ if (pids.every((p) => !isPidAlive(p))) {
18051
+ log("All orphan daemons exited cleanly");
18052
+ return;
18053
+ }
18054
+ }
18055
+ const survivors = pids.filter(isPidAlive);
18056
+ if (survivors.length > 0) {
18057
+ log(`Force-killing survivors: ${survivors.join(", ")}`);
18058
+ for (const pid of survivors) {
18059
+ try {
18060
+ process.kill(pid, "SIGKILL");
18061
+ } catch {
18062
+ }
18063
+ }
18064
+ }
18065
+ }
18066
+ function watchParentLiveness(opts) {
18067
+ if (process.env.SVAMP_SUPERVISED !== "1") {
18068
+ return () => {
18069
+ };
18070
+ }
18071
+ const supervisorPid = process.ppid;
18072
+ if (!supervisorPid || supervisorPid === 1) {
18073
+ return () => {
18074
+ };
18075
+ }
18076
+ const intervalMs = opts.intervalMs ?? 5e3;
18077
+ let fired = false;
18078
+ const timer = setInterval(() => {
18079
+ if (fired) return;
18080
+ if (!isPidAlive(supervisorPid)) {
18081
+ fired = true;
18082
+ clearInterval(timer);
18083
+ opts.onParentDeath();
18084
+ }
18085
+ }, intervalMs);
18086
+ timer.unref?.();
18087
+ return () => {
18088
+ clearInterval(timer);
18089
+ };
18090
+ }
18091
+
18092
+ var supervisorLock = /*#__PURE__*/Object.freeze({
18093
+ __proto__: null,
18094
+ acquireSupervisorLock: acquireSupervisorLock,
18095
+ acquireSupervisorLockWithRetry: acquireSupervisorLockWithRetry,
18096
+ findOrphanedSyncPids: findOrphanedSyncPids,
18097
+ getPpid: getPpid,
18098
+ isPidAlive: isPidAlive,
18099
+ isSupervisorPid: isSupervisorPid,
18100
+ killOrphanedSyncs: killOrphanedSyncs,
18101
+ releaseSupervisorLock: releaseSupervisorLock,
18102
+ shouldSignalSupervisor: shouldSignalSupervisor,
18103
+ watchParentLiveness: watchParentLiveness
18104
+ });
18105
+
17840
18106
  const SVAMP_HOME$1 = process.env.SVAMP_HOME || join$1(os.homedir(), ".svamp");
17841
18107
  function generateHookSettings(portOrOptions = {}) {
17842
18108
  const opts = typeof portOrOptions === "number" ? { sessionStartPort: portOrOptions } : portOrOptions;
@@ -18797,7 +19063,9 @@ function spawnHeadlessEvaluator(prompt, opts) {
18797
19063
  const evalArgs = [
18798
19064
  "--print",
18799
19065
  prompt,
18800
- // Read-only reviewer (mirrors .claude/agents/loop-evaluator.md): it inspects real repo
19066
+ // Read-only reviewer (#0995: NOT the retired .claude/agents/loop-evaluator.md subagent
19067
+ // this is a separate `claude --print` process whose prompt buildEvaluatorPrompt owns,
19068
+ // which is what keeps the #0189 independence invariant): it inspects real repo
18801
19069
  // state but must not mutate the working tree it's judging. The allowedTools whitelist
18802
19070
  // already excludes mutation tools; --disallowedTools is belt-and-suspenders. Kept to
18803
19071
  // Write/Edit only — MultiEdit/NotebookEdit aren't known tool names on some claude builds
@@ -19323,6 +19591,26 @@ function clearSessionArchivedFlag(sessionId) {
19323
19591
  return null;
19324
19592
  }
19325
19593
  }
19594
+ function loadArchivedSessionInfos(isLive) {
19595
+ const out = [];
19596
+ const index = loadSessionIndex();
19597
+ for (const [sessionId, entry] of Object.entries(index)) {
19598
+ if (isLive(sessionId)) continue;
19599
+ try {
19600
+ const data = JSON.parse(readFileSync$1(getSessionFilePath(entry.directory, sessionId), "utf-8"));
19601
+ if (!data?.sessionId) continue;
19602
+ out.push({
19603
+ sessionId: data.sessionId,
19604
+ startedBy: data.startedBy || "unknown",
19605
+ directory: data.directory || entry.directory,
19606
+ active: false,
19607
+ metadata: data.metadata
19608
+ });
19609
+ } catch {
19610
+ }
19611
+ }
19612
+ return out;
19613
+ }
19326
19614
  function loadPersistedSessions() {
19327
19615
  const sessions = [];
19328
19616
  const index = loadSessionIndex();
@@ -19473,7 +19761,7 @@ async function startDaemon(options) {
19473
19761
  process.on("SIGINT", () => requestShutdown("os-signal"));
19474
19762
  process.on("SIGTERM", () => requestShutdown("os-signal"));
19475
19763
  process.on("SIGUSR1", () => requestShutdown("os-signal-cleanup"));
19476
- const { watchParentLiveness } = await import('./supervisorLock-DmfzJx7B.mjs');
19764
+ const { watchParentLiveness } = await Promise.resolve().then(function () { return supervisorLock; });
19477
19765
  const cancelParentWatchdog = watchParentLiveness({
19478
19766
  intervalMs: 5e3,
19479
19767
  onParentDeath: () => {
@@ -19666,7 +19954,7 @@ async function startDaemon(options) {
19666
19954
  try {
19667
19955
  const dir = loadSessionIndex()[sessionId]?.directory;
19668
19956
  if (!dir) return;
19669
- const { reconcileServiceLinks } = await import('./agentCommands-ri042RB5.mjs');
19957
+ const { reconcileServiceLinks } = await import('./agentCommands-D7CV6DKL.mjs');
19670
19958
  const configPath = getSvampConfigPath(dir, sessionId);
19671
19959
  const config = readSvampConfig(configPath);
19672
19960
  const entries = Array.from(urls.entries());
@@ -19688,7 +19976,7 @@ async function startDaemon(options) {
19688
19976
  try {
19689
19977
  const dir = loadSessionIndex()[sessionId]?.directory;
19690
19978
  if (!dir) return;
19691
- const { reconcileServiceLinks } = await import('./agentCommands-ri042RB5.mjs');
19979
+ const { reconcileServiceLinks } = await import('./agentCommands-D7CV6DKL.mjs');
19692
19980
  const configPath = getSvampConfigPath(dir, sessionId);
19693
19981
  const config = readSvampConfig(configPath);
19694
19982
  const incoming = [{
@@ -19709,7 +19997,7 @@ async function startDaemon(options) {
19709
19997
  try {
19710
19998
  const dir = loadSessionIndex()[sessionId]?.directory;
19711
19999
  if (!dir) return;
19712
- const { dropServiceLinks } = await import('./agentCommands-ri042RB5.mjs');
20000
+ const { dropServiceLinks } = await import('./agentCommands-D7CV6DKL.mjs');
19713
20001
  const configPath = getSvampConfigPath(dir, sessionId);
19714
20002
  const config = readSvampConfig(configPath);
19715
20003
  if (dropServiceLinks(config, "serve", mountName)) {
@@ -19752,7 +20040,7 @@ async function startDaemon(options) {
19752
20040
  ensureAutoInstalledCommands(logger);
19753
20041
  (async () => {
19754
20042
  try {
19755
- const { beginClaudeVersionReconcile } = await import('./pinnedClaudeCode-C8CmQv3y.mjs');
20043
+ const { beginClaudeVersionReconcile } = await import('./pinnedClaudeCode-8SZDu7O-.mjs');
19756
20044
  beginClaudeVersionReconcile((msg) => logger.log(msg));
19757
20045
  } catch (e) {
19758
20046
  logger.log(`[claude-version] check failed: ${e?.message || e}`);
@@ -22072,21 +22360,18 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
22072
22360
  logger.log(`[Session ${sessionId}] Bash: ${command} (cwd: ${cwd || directory}, timeout: ${execTimeout}ms)`);
22073
22361
  const { exec: exec2 } = await import('child_process');
22074
22362
  return new Promise((resolve2) => {
22075
- exec2(command, { cwd: cwd || directory, timeout: execTimeout, maxBuffer: 1024 * 1024 }, (err, stdout, stderr) => {
22076
- if (err) {
22077
- resolve2({ success: false, stdout: stdout || "", stderr: stderr || err.message, exitCode: err.code ?? 1 });
22078
- } else {
22079
- resolve2({ success: true, stdout, stderr: stderr || "", exitCode: 0 });
22080
- }
22363
+ exec2(command, { cwd: cwd || directory, timeout: execTimeout, maxBuffer: EXEC_MAX_BUFFER }, (err, stdout, stderr) => {
22364
+ if (err) resolve2(execFailureOutcome(err, stdout, stderr));
22365
+ else resolve2(execSuccessOutcome(stdout, stderr));
22081
22366
  });
22082
22367
  });
22083
22368
  },
22084
22369
  onIssue: async (params) => {
22085
- const { issueRpc } = await import('./rpc-JWRwb6oY.mjs');
22370
+ const { issueRpc } = await import('./rpc-BIzMNjqC.mjs');
22086
22371
  return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
22087
22372
  },
22088
22373
  onWorkflow: async (params) => {
22089
- const { workflowRpc } = await import('./rpc-DMlurOlf.mjs');
22374
+ const { workflowRpc } = await import('./rpc-C1KIoUyz.mjs');
22090
22375
  return workflowRpc(params?.cwd || directory, params || {});
22091
22376
  },
22092
22377
  onRipgrep: async (args, cwd) => {
@@ -22783,21 +23068,18 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
22783
23068
  const execTimeout = timeout || 12e4;
22784
23069
  const { exec: exec2 } = await import('child_process');
22785
23070
  return new Promise((resolve2) => {
22786
- exec2(command, { cwd: cwd || directory, timeout: execTimeout, maxBuffer: 1024 * 1024 }, (err, stdout, stderr) => {
22787
- if (err) {
22788
- resolve2({ success: false, stdout: stdout || "", stderr: stderr || err.message, exitCode: err.code ?? 1 });
22789
- } else {
22790
- resolve2({ success: true, stdout, stderr: stderr || "", exitCode: 0 });
22791
- }
23071
+ exec2(command, { cwd: cwd || directory, timeout: execTimeout, maxBuffer: EXEC_MAX_BUFFER }, (err, stdout, stderr) => {
23072
+ if (err) resolve2(execFailureOutcome(err, stdout, stderr));
23073
+ else resolve2(execSuccessOutcome(stdout, stderr));
22792
23074
  });
22793
23075
  });
22794
23076
  },
22795
23077
  onIssue: async (params) => {
22796
- const { issueRpc } = await import('./rpc-JWRwb6oY.mjs');
23078
+ const { issueRpc } = await import('./rpc-BIzMNjqC.mjs');
22797
23079
  return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
22798
23080
  },
22799
23081
  onWorkflow: async (params) => {
22800
- const { workflowRpc } = await import('./rpc-DMlurOlf.mjs');
23082
+ const { workflowRpc } = await import('./rpc-C1KIoUyz.mjs');
22801
23083
  return workflowRpc(params?.cwd || directory, params || {});
22802
23084
  },
22803
23085
  onRipgrep: async (args, cwd) => {
@@ -23626,6 +23908,11 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
23626
23908
  logger.log("Shutdown requested via hypha-app (ignored \u2014 daemon never self-terminates)");
23627
23909
  },
23628
23910
  getTrackedSessions: getCurrentChildren,
23911
+ // #0970: archived (stopped-but-persisted) sessions, so CLI id resolution can find them.
23912
+ getArchivedSessions: () => {
23913
+ const live = new Set(getCurrentChildren().map((c) => c.sessionId));
23914
+ return loadArchivedSessionInfos((id) => live.has(id));
23915
+ },
23629
23916
  getSessionRPCHandlers: (sessionId) => {
23630
23917
  for (const [, session] of pidToTrackedSession) {
23631
23918
  if (session.svampSessionId === sessionId && !session.stopped && session.sessionRPCHandlers) {
@@ -23849,7 +24136,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
23849
24136
  }
23850
24137
  if (persistedSessions.length > 0) {
23851
24138
  try {
23852
- const { awaitClaudeVersionReady } = await import('./pinnedClaudeCode-C8CmQv3y.mjs');
24139
+ const { awaitClaudeVersionReady } = await import('./pinnedClaudeCode-8SZDu7O-.mjs');
23853
24140
  await awaitClaudeVersionReady();
23854
24141
  } catch {
23855
24142
  }
@@ -23950,8 +24237,16 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
23950
24237
  const supPidFile = join(SVAMP_HOME, "supervisor.pid");
23951
24238
  const supPid = existsSync$1(supPidFile) ? parseInt(readFileSync$1(supPidFile, "utf-8").trim(), 10) : NaN;
23952
24239
  if (supPid && !isNaN(supPid)) {
23953
- process.kill(supPid, "SIGUSR2");
23954
- return;
24240
+ const ok = shouldSignalSupervisor({
24241
+ pid: supPid,
24242
+ alive: isPidAlive(supPid),
24243
+ isSupervisor: isSupervisorPid(supPid)
24244
+ });
24245
+ if (ok) {
24246
+ process.kill(supPid, "SIGUSR2");
24247
+ return;
24248
+ }
24249
+ logger.log(`[graceful-restart] supervisor.pid ${supPid} is stale or not a supervisor \u2014 not signalling`);
23955
24250
  }
23956
24251
  } catch {
23957
24252
  }
@@ -24098,7 +24393,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
24098
24393
  const PING_TIMEOUT_MS = 15e3;
24099
24394
  const POST_RECONNECT_GRACE_MS = 2e4;
24100
24395
  const RECONNECT_JITTER_MS = 2500;
24101
- const { WorkflowScheduler } = await import('./scheduler-CkYMjhum.mjs');
24396
+ const { WorkflowScheduler } = await import('./scheduler-DIYulmdV.mjs');
24102
24397
  const workflowProjectRoots = () => {
24103
24398
  const dirs = /* @__PURE__ */ new Set();
24104
24399
  for (const s of pidToTrackedSession.values()) {
@@ -24731,4 +25026,4 @@ var run = /*#__PURE__*/Object.freeze({
24731
25026
  writeStopMarker: writeStopMarker
24732
25027
  });
24733
25028
 
24734
- export { listSkillFiles as $, saveWorkflow as A, rawWorkflow as B, listWorkflows as C, isWorkflowEnabled as D, workflowSchedules as E, inZone as F, cronMatches as G, summarize as H, workflowSteps as I, parseJwtEmail as J, computeCollectionConfigUpdate as K, SYSTEM_COLLECTION_CONFIG as L, loadMachineContext as M, buildMachineInstructions as N, machineToolsForRole as O, buildMachineTools as P, parseFrontmatter as Q, READ_ONLY_TOOLS as R, SharingNotificationSync as S, getSkillsServer as T, getSkillsWorkspaceName as U, getSkillsCollectionName as V, fetchWithTimeout as W, searchSkills as X, SKILLS_DIR as Y, getSkillInfo as Z, downloadSkillFile as _, createSessionStore as a, resolveModel as a0, formatHandle as a1, normalizeAllowedUser as a2, loadSecurityContextConfig as a3, resolveSecurityContext as a4, buildSecurityContextFromFlags as a5, mergeSecurityContexts as a6, buildSessionShareUrl as a7, computeOutboundHop as a8, registerAwaitingReply as a9, kimiSetup as aA, api as aB, run as aC, buildMachineShareUrl as aa, parseHandle as ab, handleMatchesMetadata as ac, PINNED_CODEX_VERSION as ad, clearStopMarker as ae, stopMarkerExists as af, withFileLock as ag, describeMisconfiguration as ah, buildMachineDeps as ai, applyClaudeProxyEnv as aj, composeSessionId as ak, generateFriendlyName as al, generateHookSettings as am, instanceConfig as an, frpc as ao, staticFileServer as ap, claudeAuth as aq, codexProvider as ar, projectInfo as as, DefaultTransport$1 as at, acpBackend as au, acpAgentConfig as av, codexAppServerBackend as aw, GeminiTransport$1 as ax, KimiTransport$1 as ay, kimiProvider as az, stopDaemon as b, connectToHypha as c, daemonStatus as d, shortId as e, resolveProjectRoot as f, getHyphaServerUrl$1 as g, getIssue as h, resumeIssue as i, addComment as j, addIssue as k, listIssues as l, isPendingIssue as m, searchIssues as n, isVisibleTo as o, pauseIssue as p, getRun as q, registerMachineService as r, startDaemon as s, listRuns as t, updateIssue as u, getWorkflow as v, runWorkflow as w, setWorkflowEnabled as x, removeWorkflow as y, validateWorkflowName as z };
25029
+ export { listSkillFiles as $, saveWorkflow as A, rawWorkflow as B, listWorkflows as C, isWorkflowEnabled as D, workflowSchedules as E, inZone as F, cronMatches as G, summarize as H, workflowSteps as I, parseJwtEmail as J, computeCollectionConfigUpdate as K, SYSTEM_COLLECTION_CONFIG as L, loadMachineContext as M, buildMachineInstructions as N, machineToolsForRole as O, buildMachineTools as P, parseFrontmatter as Q, READ_ONLY_TOOLS as R, SharingNotificationSync as S, getSkillsServer as T, getSkillsWorkspaceName as U, getSkillsCollectionName as V, fetchWithTimeout as W, searchSkills as X, SKILLS_DIR as Y, getSkillInfo as Z, downloadSkillFile as _, createSessionStore as a, resolveModel as a0, formatHandle as a1, normalizeAllowedUser as a2, loadSecurityContextConfig as a3, resolveSecurityContext as a4, buildSecurityContextFromFlags as a5, mergeSecurityContexts as a6, buildSessionShareUrl as a7, computeOutboundHop as a8, registerAwaitingReply as a9, kimiSetup as aA, api as aB, supervisorLock as aC, run as aD, buildMachineShareUrl as aa, parseHandle as ab, handleMatchesMetadata as ac, PINNED_CODEX_VERSION as ad, clearStopMarker as ae, stopMarkerExists as af, withFileLock as ag, describeMisconfiguration as ah, buildMachineDeps as ai, applyClaudeProxyEnv as aj, composeSessionId as ak, generateFriendlyName as al, generateHookSettings as am, instanceConfig as an, frpc as ao, staticFileServer as ap, claudeAuth as aq, codexProvider as ar, projectInfo as as, DefaultTransport$1 as at, acpBackend as au, acpAgentConfig as av, codexAppServerBackend as aw, GeminiTransport$1 as ax, KimiTransport$1 as ay, kimiProvider as az, stopDaemon as b, connectToHypha as c, daemonStatus as d, shortId as e, resolveProjectRoot as f, getHyphaServerUrl$1 as g, getIssue as h, resumeIssue as i, addComment as j, addIssue as k, listIssues as l, isPendingIssue as m, searchIssues as n, isVisibleTo as o, pauseIssue as p, getRun as q, registerMachineService as r, startDaemon as s, listRuns as t, updateIssue as u, getWorkflow as v, runWorkflow as w, setWorkflowEnabled as x, removeWorkflow as y, validateWorkflowName as z };