svamp-cli 0.2.284 → 0.2.290

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-DPZaByla.mjs → adminCommands-BVvpkVsG.mjs} +22 -3
  2. package/dist/{agentCommands-B23M4vER.mjs → agentCommands-fY4keaFA.mjs} +5 -5
  3. package/dist/{auth-DPZSnISj.mjs → auth-SR7v-8nf.mjs} +1 -1
  4. package/dist/{cli-D8tJd71c.mjs → cli-Re14H3q0.mjs} +76 -69
  5. package/dist/cli.mjs +2 -2
  6. package/dist/{commands-CDFhSKgn.mjs → commands-BC-T6wDo.mjs} +2 -2
  7. package/dist/{commands-BHO7rzSh.mjs → commands-Bv5EcsN_.mjs} +1 -1
  8. package/dist/{commands-DDf0W30g.mjs → commands-CBsV6z9K.mjs} +2 -2
  9. package/dist/commands-CIyv2Qt-.mjs +258 -0
  10. package/dist/{commands-BABblJRp.mjs → commands-Dc9t_OeY.mjs} +1 -1
  11. package/dist/{commands-BqaOHWym.mjs → commands-Dd-6WXYJ.mjs} +9 -9
  12. package/dist/{commands-Cp8G-iuw.mjs → commands-Dwf-ntY-.mjs} +2 -2
  13. package/dist/{commands-DqsoW-S0.mjs → commands-zagci6-n.mjs} +1 -1
  14. package/dist/{fleet-BxhHefua.mjs → fleet-DlRlerEG.mjs} +1 -1
  15. package/dist/{frpc-BsR6aGNJ.mjs → frpc-B8zTErxt.mjs} +45 -27
  16. package/dist/{headlessCli-B-aMhdKx.mjs → headlessCli-D22LyDyO.mjs} +2 -2
  17. package/dist/index.mjs +1 -1
  18. package/dist/{notifyCommands-CfnthGpX.mjs → notifyCommands-5PueOg8Q.mjs} +1 -1
  19. package/dist/package-CpmmajAP.mjs +64 -0
  20. package/dist/{rpc-BjrKqEib.mjs → rpc-D3Hg4y67.mjs} +1 -1
  21. package/dist/{rpc-B5BRaVsS.mjs → rpc-olai-LcU.mjs} +1 -1
  22. package/dist/{run-DWJenrBe.mjs → run-B6V1wuT6.mjs} +1 -1
  23. package/dist/{run-CRTzyKbn.mjs → run-BNiSOlBf.mjs} +164 -30
  24. package/dist/{scheduler-QYMtbUDe.mjs → scheduler--MbVadb0.mjs} +1 -1
  25. package/dist/{serveCommands-Cj3MLbZb.mjs → serveCommands-BONMg_af.mjs} +5 -5
  26. package/dist/{sideband-CKmZxwY6.mjs → sideband-Dnuy9-IL.mjs} +1 -1
  27. package/package.json +46 -46
  28. package/dist/package-Br4fCS7J.mjs +0 -64
@@ -2973,7 +2973,7 @@ Connection: close\r
2973
2973
  const mount = this.mounts.get(mountName);
2974
2974
  const subdomainOverride = mount?.access === "link" && mount.linkToken ? /* @__PURE__ */ new Map([[this.port, buildLinkSubdomain(subdomainSafe, mount.linkToken)]]) : void 0;
2975
2975
  try {
2976
- const { FrpcTunnel } = await import('./frpc-BsR6aGNJ.mjs');
2976
+ const { FrpcTunnel } = await import('./frpc-B8zTErxt.mjs');
2977
2977
  let tunnel;
2978
2978
  tunnel = new FrpcTunnel({
2979
2979
  name: tunnelName,
@@ -3269,11 +3269,17 @@ function buildCodexProviderArgs(cfg) {
3269
3269
  if (cfg.model) configArgs.push("-c", `model=${JSON.stringify(cfg.model)}`);
3270
3270
  return { configArgs, env: { [CODEX_PROVIDER_KEY_ENV]: cfg.apiKey }, model: cfg.model };
3271
3271
  }
3272
+ function codexForcedModel(env = process.env) {
3273
+ const f = (env.SVAMP_CODEX_FORCE_MODEL || "").toLowerCase();
3274
+ if (!f || f === "0" || f === "false" || f === "no" || f === "off") return void 0;
3275
+ return env.SVAMP_CODEX_MODEL || env.LLM_MODEL || void 0;
3276
+ }
3272
3277
 
3273
3278
  var codexProvider = /*#__PURE__*/Object.freeze({
3274
3279
  __proto__: null,
3275
3280
  CODEX_PROVIDER_KEY_ENV: CODEX_PROVIDER_KEY_ENV,
3276
3281
  buildCodexProviderArgs: buildCodexProviderArgs,
3282
+ codexForcedModel: codexForcedModel,
3277
3283
  codexPermissionSettings: codexPermissionSettings,
3278
3284
  hasCustomProvider: hasCustomProvider,
3279
3285
  resolveCodexProvider: resolveCodexProvider
@@ -4361,6 +4367,48 @@ function renderMessage(channel, { sender = {}, body = {}, query = {}, callId, no
4361
4367
  return renderTemplate(channel.template || DEFAULT_TEMPLATE, ctx);
4362
4368
  }
4363
4369
 
4370
+ class StatelessDispatchLimiter {
4371
+ constructor(maxConcurrent, maxPerSender) {
4372
+ this.maxConcurrent = maxConcurrent;
4373
+ this.maxPerSender = maxPerSender;
4374
+ }
4375
+ inflight = 0;
4376
+ perSender = /* @__PURE__ */ new Map();
4377
+ /** Try to reserve a dispatch slot for `sender`. Returns false (reserve nothing) if either cap
4378
+ * is already at its limit. On true, the caller MUST call release(sender) exactly once. */
4379
+ tryAcquire(sender) {
4380
+ const key = sender || "anonymous";
4381
+ if (this.inflight >= this.maxConcurrent) return false;
4382
+ const s = this.perSender.get(key) || 0;
4383
+ if (s >= this.maxPerSender) return false;
4384
+ this.inflight++;
4385
+ this.perSender.set(key, s + 1);
4386
+ return true;
4387
+ }
4388
+ /** Release a slot previously reserved by tryAcquire. Clamped so a double-release can't drive
4389
+ * the counters negative. */
4390
+ release(sender) {
4391
+ const key = sender || "anonymous";
4392
+ if (this.inflight > 0) this.inflight--;
4393
+ const s = (this.perSender.get(key) || 0) - 1;
4394
+ if (s > 0) this.perSender.set(key, s);
4395
+ else this.perSender.delete(key);
4396
+ }
4397
+ /** Current total in-flight dispatches (for diagnostics/tests). */
4398
+ get active() {
4399
+ return this.inflight;
4400
+ }
4401
+ }
4402
+ function statelessDispatchCaps(env = process.env) {
4403
+ const num = (v, dflt) => {
4404
+ const n = Number(v);
4405
+ return Number.isFinite(n) && n > 0 ? Math.floor(n) : dflt;
4406
+ };
4407
+ const concurrent = num(env.SVAMP_CHANNEL_MAX_CONCURRENT, 6);
4408
+ const perSender = Math.min(num(env.SVAMP_CHANNEL_MAX_PER_SENDER, 2), concurrent);
4409
+ return { concurrent, perSender };
4410
+ }
4411
+
4364
4412
  const MAX_PER_CHANNEL = 200;
4365
4413
  const TTL_MS = 60 * 60 * 1e3;
4366
4414
  const COMPACT_EVERY = 500;
@@ -4588,6 +4636,11 @@ class ChannelOutbox {
4588
4636
  }
4589
4637
  }
4590
4638
 
4639
+ var outbox = /*#__PURE__*/Object.freeze({
4640
+ __proto__: null,
4641
+ ChannelOutbox: ChannelOutbox
4642
+ });
4643
+
4591
4644
  function getParamNames(fn) {
4592
4645
  const src = fn.toString();
4593
4646
  const match = src.match(/^(?:async\s+)?(?:function\s*\w*)?\s*\(([^)]*)\)/);
@@ -5816,7 +5869,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
5816
5869
  const tunnels = handlers.tunnels;
5817
5870
  if (!tunnels) throw new Error("Tunnel management not available");
5818
5871
  if (tunnels.has(params.name)) throw new Error(`Tunnel '${params.name}' already running`);
5819
- const { FrpcTunnel } = await import('./frpc-BsR6aGNJ.mjs');
5872
+ const { FrpcTunnel } = await import('./frpc-B8zTErxt.mjs');
5820
5873
  const tunnel = new FrpcTunnel({
5821
5874
  name: params.name,
5822
5875
  ports: params.ports,
@@ -6292,7 +6345,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
6292
6345
  }
6293
6346
  const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
6294
6347
  const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
6295
- const { toolsForRole } = await import('./sideband-CKmZxwY6.mjs');
6348
+ const { toolsForRole } = await import('./sideband-Dnuy9-IL.mjs');
6296
6349
  const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
6297
6350
  return fmt(r2);
6298
6351
  }
@@ -6379,6 +6432,8 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
6379
6432
  return handler(...callArgs);
6380
6433
  }
6381
6434
  };
6435
+ const _caps = statelessDispatchCaps();
6436
+ const statelessLimiter = new StatelessDispatchLimiter(_caps.concurrent, _caps.perSender);
6382
6437
  const dispatchStateless = async (c, dir, kwargs, context) => {
6383
6438
  const u = context?.user;
6384
6439
  const r = resolveSender(c, {
@@ -6390,8 +6445,12 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
6390
6445
  });
6391
6446
  if (r.error || !r.sender) return { error: r.error || "unauthorized" };
6392
6447
  const callId = "call_" + Math.random().toString(16).slice(2, 12);
6448
+ const senderKey = (r.sender.name || "anonymous").toLowerCase();
6449
+ if (!statelessLimiter.tryAcquire(senderKey)) {
6450
+ return { ok: false, call_id: callId, status: "busy", error: "channel is busy (too many concurrent requests) \u2014 retry shortly" };
6451
+ }
6393
6452
  const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
6394
- const { queryCore } = await import('./commands-BABblJRp.mjs');
6453
+ const { queryCore } = await import('./commands-Dc9t_OeY.mjs');
6395
6454
  const timeout = c.reply?.timeout_sec || 120;
6396
6455
  let result;
6397
6456
  try {
@@ -6399,6 +6458,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
6399
6458
  } catch (e) {
6400
6459
  return { ok: false, call_id: callId, status: "error", error: e?.message || String(e) };
6401
6460
  } finally {
6461
+ statelessLimiter.release(senderKey);
6402
6462
  if (result?.sessionId) {
6403
6463
  try {
6404
6464
  handlers.deleteSession?.(result.sessionId);
@@ -6723,7 +6783,9 @@ function recordWake(now) {
6723
6783
  }
6724
6784
  function senderIsHuman(message) {
6725
6785
  const f = message.from || "";
6726
- return f.startsWith("cli:") || f.startsWith("user:");
6786
+ if (!(f.startsWith("cli:") || f.startsWith("user:"))) return false;
6787
+ if (message.verified === false) return false;
6788
+ return true;
6727
6789
  }
6728
6790
  function senderKey(message) {
6729
6791
  return message.fromSession || message.from || "unknown";
@@ -9388,10 +9450,27 @@ class SessionArtifactSync {
9388
9450
  async listRemoteSessions() {
9389
9451
  if (!this.initialized || !this.artifactManager || !this.collectionId) return [];
9390
9452
  try {
9391
- const children = await this.artifactManager.list({
9392
- parent_id: this.collectionId,
9393
- _rkwargs: true
9394
- });
9453
+ const PAGE = 100;
9454
+ const children = [];
9455
+ const seen = /* @__PURE__ */ new Set();
9456
+ for (let offset = 0; ; offset += PAGE) {
9457
+ const page = await this.artifactManager.list({
9458
+ parent_id: this.collectionId,
9459
+ offset,
9460
+ limit: PAGE,
9461
+ _rkwargs: true
9462
+ });
9463
+ if (!Array.isArray(page) || page.length === 0) break;
9464
+ let fresh = 0;
9465
+ for (const c of page) {
9466
+ const k = String(c?.id ?? c?.manifest?.id ?? c?.alias ?? `${offset}:${fresh}`);
9467
+ if (seen.has(k)) continue;
9468
+ seen.add(k);
9469
+ children.push(c);
9470
+ fresh++;
9471
+ }
9472
+ if (page.length < PAGE || fresh === 0) break;
9473
+ }
9395
9474
  return (children || []).map((child) => ({
9396
9475
  sessionId: child.manifest?.sessionId || child.alias?.replace("session-", ""),
9397
9476
  machineId: child.manifest?.machineId,
@@ -9624,22 +9703,63 @@ class SharingNotificationSync {
9624
9703
  this.log(`[USER EVENT] Failed to publish ${event.type} for ${event.recipientEmail}: ${err.message}`);
9625
9704
  }
9626
9705
  }
9706
+ /**
9707
+ * List ALL children of a collection, paginating past hypha's default page cap (`limit=100`,
9708
+ * server hypha/artifact.py list_children). The svamp-user-events / svamp-shared-sessions
9709
+ * collections are GLOBAL across every deployment user, so a single unpaginated list() would
9710
+ * return only the newest ~100 rows across ALL recipients — silently hiding a given user's
9711
+ * events past that page. We page offset+=100 until a short/empty/duplicate page.
9712
+ */
9713
+ async listAllChildren(parentId) {
9714
+ const PAGE = 100;
9715
+ const all = [];
9716
+ const seen = /* @__PURE__ */ new Set();
9717
+ for (let offset = 0; ; offset += PAGE) {
9718
+ const page = await this.artifactManager.list({ parent_id: parentId, offset, limit: PAGE, _rkwargs: true });
9719
+ if (!Array.isArray(page) || page.length === 0) break;
9720
+ let fresh = 0;
9721
+ for (const c of page) {
9722
+ const k = String(c?.id ?? c?.manifest?.id ?? c?.alias ?? `${offset}:${fresh}`);
9723
+ if (seen.has(k)) continue;
9724
+ seen.add(k);
9725
+ all.push(c);
9726
+ fresh++;
9727
+ }
9728
+ if (page.length < PAGE || fresh === 0) break;
9729
+ }
9730
+ return all;
9731
+ }
9627
9732
  /**
9628
9733
  * List user events addressed to `recipientEmail` (the bell inbox), newest first, excluding
9629
9734
  * expired ones. Reuses the global svamp-user-events collection — cross-workspace by design.
9630
- * Mirrors the webapp's fetchUserEvents so the CLI reads the same source of truth.
9735
+ * Mirrors the webapp's fetchUserEvents so the CLI reads the same source of truth. Paginated
9736
+ * so a recipient's events past the first 100 global rows are not silently dropped; expired
9737
+ * events the caller owns are best-effort pruned (a no-op until the collection's
9738
+ * recipient_can_delete is active — swallowed on PermissionError).
9631
9739
  */
9632
9740
  async listUserEvents(recipientEmail) {
9633
9741
  if (!this.initialized || !this.eventCollectionId) return [];
9634
9742
  const normalized = recipientEmail.toLowerCase();
9635
9743
  try {
9636
- const children = await this.artifactManager.list({
9637
- parent_id: this.eventCollectionId,
9638
- _rkwargs: true
9639
- });
9744
+ const children = await this.listAllChildren(this.eventCollectionId);
9640
9745
  if (!Array.isArray(children)) return [];
9641
9746
  const now = Date.now();
9642
- return children.map((c) => c?.manifest).filter((m) => !!m && typeof m.recipientEmail === "string" && m.recipientEmail.toLowerCase() === normalized && (!m.expiresAt || m.expiresAt > now)).sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));
9747
+ const live = [];
9748
+ const expiredOwnedIds = [];
9749
+ for (const c of children) {
9750
+ const m = c?.manifest;
9751
+ if (!m || typeof m.recipientEmail !== "string" || m.recipientEmail.toLowerCase() !== normalized) continue;
9752
+ if (m.expiresAt && m.expiresAt <= now) {
9753
+ if (c?.id) expiredOwnedIds.push(c.id);
9754
+ continue;
9755
+ }
9756
+ live.push(m);
9757
+ }
9758
+ for (const id of expiredOwnedIds) {
9759
+ this.artifactManager.delete({ artifact_id: id, _rkwargs: true }).catch(() => {
9760
+ });
9761
+ }
9762
+ return live.sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));
9643
9763
  } catch (err) {
9644
9764
  this.log(`[USER EVENT] listUserEvents failed for ${recipientEmail}: ${err.message}`);
9645
9765
  return [];
@@ -9654,7 +9774,7 @@ class SharingNotificationSync {
9654
9774
  if (!this.initialized || !this.eventCollectionId) return false;
9655
9775
  const normalized = recipientEmail.toLowerCase();
9656
9776
  try {
9657
- const children = await this.artifactManager.list({ parent_id: this.eventCollectionId, _rkwargs: true });
9777
+ const children = await this.listAllChildren(this.eventCollectionId);
9658
9778
  if (!Array.isArray(children)) return false;
9659
9779
  const short = eventId.slice(0, 8);
9660
9780
  const match = children.find((c) => {
@@ -9944,6 +10064,7 @@ function startToolCall(toolCallId, toolKind, update, ctx, source) {
9944
10064
  ctx.activeToolCalls.delete(toolCallId);
9945
10065
  ctx.toolCallStartTimes.delete(toolCallId);
9946
10066
  ctx.toolCallTimeouts.delete(toolCallId);
10067
+ ctx.toolCallIdToNameMap.delete(toolCallId);
9947
10068
  ctx.log(`Tool call TIMEOUT: ${toolCallId} (${toolKind}) after ${(timeoutMs / 1e3).toFixed(0)}s`);
9948
10069
  if (ctx.activeToolCalls.size === 0) {
9949
10070
  ctx.emitIdleStatus();
@@ -12455,6 +12576,13 @@ function shouldIsolate(input) {
12455
12576
  return input.optionsSecurityContext !== null && input.optionsSecurityContext !== void 0;
12456
12577
  }
12457
12578
 
12579
+ function classifyRestoreContinuation(opts) {
12580
+ if (opts.isOrphaned) return "none";
12581
+ if (opts.loopActive) return "loop-resume";
12582
+ if (opts.wasProcessing && opts.hasResumeId) return "auto-continue";
12583
+ return "none";
12584
+ }
12585
+
12458
12586
  function getShareBaseUrl() {
12459
12587
  return getSvampWebBaseUrl();
12460
12588
  }
@@ -14409,7 +14537,7 @@ You are running inside a Svamp session (id: ${sessionId}${handle ? `, handle: ${
14409
14537
  - \`svamp session link add "<url>" --label "<label>" [--icon "\u{1F517}"]\` \u2014 surface viewable artifacts (dashboards, reports, apps) as buttons in the composer "Launch Pad". Manage many: \`link list\` \xB7 \`link update <id> [--url|--label|--icon]\` \xB7 \`link remove <id>\`. Adding the same URL again UPDATES that entry (URL is the dedup key \u2014 no duplicates). Tunnel/exposed URLs from \`svamp service expose\` are added to the Launch Pad AUTOMATICALLY, so do NOT \`session link add\` a URL you just exposed. A session can have MANY links (the Launch Pad); \`session set-link "<url>" "<label>"\` also appends + dedupes by URL (alias of \`link add\`).
14410
14538
  - \`svamp session notify "<msg>" [--level info|warning|error]\` \u2014 send a user notification
14411
14539
 
14412
- **Artifacts (rich inline output):** Write HTML to a file (\`.svamp/<sessionId>/outputs/\` for disposable, \`./outputs/\` for persistent) and emit \`<artifact src="./outputs/viz.html" title="..." />\` \u2014 the Svamp client renders it inline as a sandboxed iframe with theme CSS vars, auto-resize, file inlining, and a header with Reload/Fullscreen/\u22EE menu. Modes: \`default\`, \`bare\` (controls on hover), \`immersive\` (no chrome), \`card\` (click-to-open preview with \`description\`+\`poster\`). Use \`<artifact src="https://..." height="540" />\` to embed a live server. Run \`svamp serve <name> <dir>\` to share. Use a real backend server (\`svamp service expose\`) when you need persistence/auth. **Inline artifacts (\`<artifact>\u2026HTML\u2026</artifact>\` with a body) are for SMALL self-contained HTML only \u2014 anything large (images, datasets, big reports, base64) MUST be written to a file and referenced via \`<artifact src="./outputs/<file>" />\`, never pasted inline. An inline body over 512 KB is rejected (error card + stripped) because it bloats stored history.** See the \`artifact\` skill.
14540
+ **Artifacts (rich inline output):** Write HTML to a file (\`.svamp/<sessionId>/outputs/\` for disposable, \`./outputs/\` for persistent) and emit \`<artifact src="./outputs/viz.html" title="..." />\` \u2014 the Svamp client renders it inline as a sandboxed iframe with theme CSS vars, auto-resize, file inlining, and a header with Reload/Fullscreen/\u22EE menu. Modes: \`default\`, \`bare\` (controls on hover), \`immersive\` (no chrome), \`card\` (click-to-open preview with \`description\`+\`poster\`). Use \`<artifact src="https://..." height="540" />\` to embed a live server. To share it as a link, DEFAULT to a persistent, lazy mount \u2014 \`svamp serve apply <yaml>\` (a static dir, or a \`process:\` block with \`wake_on_request: true\` + \`idle_timeout_sec\` for a dynamic server): it survives daemon restarts, idles to near-zero memory, and wakes on the next visit (the serverless pattern users expect). Reserve ad-hoc \`svamp serve <name> <dir>\` / \`svamp service expose\` for genuinely throwaway demos ONLY \u2014 those vanish on restart, which confuses users who revisit. **Inline artifacts (\`<artifact>\u2026HTML\u2026</artifact>\` with a body) are for SMALL self-contained HTML only \u2014 anything large (images, datasets, big reports, base64) MUST be written to a file and referenced via \`<artifact src="./outputs/<file>" />\`, never pasted inline. An inline body over 512 KB is rejected (error card + stripped) because it bloats stored history.** See the \`artifact\` skill.
14413
14541
 
14414
14542
  ## Shared environment
14415
14543
 
@@ -16145,7 +16273,7 @@ async function startDaemon(options) {
16145
16273
  try {
16146
16274
  const dir = loadSessionIndex()[sessionId]?.directory;
16147
16275
  if (!dir) return;
16148
- const { reconcileServiceLinks } = await import('./agentCommands-B23M4vER.mjs');
16276
+ const { reconcileServiceLinks } = await import('./agentCommands-fY4keaFA.mjs');
16149
16277
  const configPath = getSvampConfigPath(dir, sessionId);
16150
16278
  const config = readSvampConfig(configPath);
16151
16279
  const entries = Array.from(urls.entries());
@@ -16163,7 +16291,7 @@ async function startDaemon(options) {
16163
16291
  }
16164
16292
  }
16165
16293
  async function createExposedTunnel(spec) {
16166
- const { FrpcTunnel } = await import('./frpc-BsR6aGNJ.mjs');
16294
+ const { FrpcTunnel } = await import('./frpc-B8zTErxt.mjs');
16167
16295
  const tunnel = new FrpcTunnel({
16168
16296
  name: spec.name,
16169
16297
  ports: spec.ports,
@@ -18379,11 +18507,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
18379
18507
  });
18380
18508
  },
18381
18509
  onIssue: async (params) => {
18382
- const { issueRpc } = await import('./rpc-B5BRaVsS.mjs');
18510
+ const { issueRpc } = await import('./rpc-olai-LcU.mjs');
18383
18511
  return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
18384
18512
  },
18385
18513
  onWorkflow: async (params) => {
18386
- const { workflowRpc } = await import('./rpc-BjrKqEib.mjs');
18514
+ const { workflowRpc } = await import('./rpc-D3Hg4y67.mjs');
18387
18515
  return workflowRpc(params?.cwd || directory, params || {});
18388
18516
  },
18389
18517
  onRipgrep: async (args, cwd) => {
@@ -18755,7 +18883,8 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
18755
18883
  logger.log(`[${agentName} Session ${sessionId}] Ignoring meta.permissionMode='${msgMeta.permissionMode}' from sendMessage (current: ${currentPermissionMode}; use switchMode to change)`);
18756
18884
  }
18757
18885
  {
18758
- const rawModel = typeof msgMeta?.model === "string" && msgMeta.model ? msgMeta.model : void 0;
18886
+ const forcedModel = agentName === "codex" ? codexForcedModel() : void 0;
18887
+ const rawModel = forcedModel || (typeof msgMeta?.model === "string" && msgMeta.model ? msgMeta.model : void 0);
18759
18888
  const desiredModel = rawModel || agentConfig?.default_model || void 0;
18760
18889
  if (desiredModel !== appliedAgentModel) {
18761
18890
  agentBackend?.setModel?.(desiredModel);
@@ -18995,11 +19124,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
18995
19124
  });
18996
19125
  },
18997
19126
  onIssue: async (params) => {
18998
- const { issueRpc } = await import('./rpc-B5BRaVsS.mjs');
19127
+ const { issueRpc } = await import('./rpc-olai-LcU.mjs');
18999
19128
  return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
19000
19129
  },
19001
19130
  onWorkflow: async (params) => {
19002
- const { workflowRpc } = await import('./rpc-BjrKqEib.mjs');
19131
+ const { workflowRpc } = await import('./rpc-D3Hg4y67.mjs');
19003
19132
  return workflowRpc(params?.cwd || directory, params || {});
19004
19133
  },
19005
19134
  onRipgrep: async (args, cwd) => {
@@ -19175,7 +19304,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
19175
19304
  }
19176
19305
  }
19177
19306
  }
19178
- const codexModel = options2.model || agentConfig?.default_model || provider.model || void 0;
19307
+ const codexModel = codexForcedModel() || options2.model || agentConfig?.default_model || provider.model || void 0;
19179
19308
  const codexPerm = codexPermissionSettings(currentPermissionMode);
19180
19309
  logger.log(`[Agent Session ${sessionId}] Codex backend: app-server (model=${codexModel ?? "default"}${provider.apiBase ? `, provider=${provider.apiBase}` : ""}${accountDesc ? `, account=${accountDesc}` : ""}, mode=${currentPermissionMode} \u2192 approval=${codexPerm.approvalPolicy}/sandbox=${codexPerm.sandbox})`);
19181
19310
  if (acpResumeThreadId) logger.log(`[Agent Session ${sessionId}] Resuming Codex thread ${acpResumeThreadId} (restart recovery)`);
@@ -19950,10 +20079,15 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
19950
20079
  break;
19951
20080
  }
19952
20081
  }
19953
- if (persisted.wasProcessing && persisted.claudeResumeId && !isOrphaned) {
20082
+ const _restoreAction = classifyRestoreContinuation({
20083
+ wasProcessing: !!persisted.wasProcessing,
20084
+ hasResumeId: !!persisted.claudeResumeId,
20085
+ isOrphaned: !!isOrphaned,
20086
+ loopActive: isLoopActiveForSession(persisted.directory, persisted.sessionId)
20087
+ });
20088
+ if (_restoreAction === "auto-continue") {
19954
20089
  sessionsToAutoContinue.push(persisted.sessionId);
19955
- }
19956
- if (!isOrphaned && !persisted.wasProcessing && isLoopActiveForSession(persisted.directory, persisted.sessionId)) {
20090
+ } else if (_restoreAction === "loop-resume") {
19957
20091
  sessionsToLoopResume.push({ sessionId: persisted.sessionId, directory: persisted.directory });
19958
20092
  }
19959
20093
  } else {
@@ -20114,7 +20248,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
20114
20248
  const PING_TIMEOUT_MS = 15e3;
20115
20249
  const POST_RECONNECT_GRACE_MS = 2e4;
20116
20250
  const RECONNECT_JITTER_MS = 2500;
20117
- const { WorkflowScheduler } = await import('./scheduler-QYMtbUDe.mjs');
20251
+ const { WorkflowScheduler } = await import('./scheduler--MbVadb0.mjs');
20118
20252
  const workflowScheduler = new WorkflowScheduler({
20119
20253
  projectRoots: () => {
20120
20254
  const dirs = /* @__PURE__ */ new Set();
@@ -20737,4 +20871,4 @@ var run = /*#__PURE__*/Object.freeze({
20737
20871
  writeStopMarker: writeStopMarker
20738
20872
  });
20739
20873
 
20740
- export { listSkillFiles as $, removeWorkflow as A, saveWorkflow as B, rawWorkflow as C, listWorkflows as D, isWorkflowEnabled as E, workflowCrons 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, clearStopMarker as a1, stopMarkerExists as a2, formatHandle as a3, normalizeAllowedUser as a4, loadSecurityContextConfig as a5, resolveSecurityContext as a6, buildSecurityContextFromFlags as a7, mergeSecurityContexts as a8, buildSessionShareUrl as a9, computeOutboundHop as aa, registerAwaitingReply as ab, buildMachineShareUrl as ac, parseHandle as ad, handleMatchesMetadata as ae, describeMisconfiguration as af, buildMachineDeps as ag, applyClaudeProxyEnv as ah, composeSessionId as ai, generateFriendlyName as aj, generateHookSettings as ak, staticFileServer as al, instanceConfig as am, claudeAuth as an, codexProvider as ao, projectInfo as ap, DefaultTransport$1 as aq, acpBackend as ar, acpAgentConfig as as, codexAppServerBackend as at, GeminiTransport$1 as au, api as av, run as aw, stopDaemon as b, connectToHypha as c, daemonStatus as d, getFrpsSubdomainHost as e, getFrpsServerPort as f, getHyphaServerUrl$1 as g, getFrpsServerAddr as h, shortId as i, resolveProjectRoot as j, getIssue as k, resumeIssue as l, addComment as m, addIssue as n, listIssues as o, pauseIssue as p, searchIssues as q, registerMachineService as r, startDaemon as s, isVisibleTo as t, updateIssue as u, getRun as v, listRuns as w, getWorkflow as x, runWorkflow as y, setWorkflowEnabled as z };
20874
+ export { listSkillFiles as $, removeWorkflow as A, saveWorkflow as B, rawWorkflow as C, listWorkflows as D, isWorkflowEnabled as E, workflowCrons 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, clearStopMarker as a1, stopMarkerExists as a2, ChannelStore as a3, gatewayBase as a4, genKey as a5, formatHandle as a6, normalizeAllowedUser as a7, loadSecurityContextConfig as a8, resolveSecurityContext as a9, run as aA, buildSecurityContextFromFlags as aa, mergeSecurityContexts as ab, buildSessionShareUrl as ac, computeOutboundHop as ad, registerAwaitingReply as ae, buildMachineShareUrl as af, parseHandle as ag, handleMatchesMetadata as ah, describeMisconfiguration as ai, buildMachineDeps as aj, applyClaudeProxyEnv as ak, composeSessionId as al, generateFriendlyName as am, generateHookSettings as an, staticFileServer as ao, instanceConfig as ap, claudeAuth as aq, codexProvider as ar, outbox as as, projectInfo as at, DefaultTransport$1 as au, acpBackend as av, acpAgentConfig as aw, codexAppServerBackend as ax, GeminiTransport$1 as ay, api as az, stopDaemon as b, connectToHypha as c, daemonStatus as d, getFrpsSubdomainHost as e, getFrpsServerPort as f, getHyphaServerUrl$1 as g, getFrpsServerAddr as h, shortId as i, resolveProjectRoot as j, getIssue as k, resumeIssue as l, addComment as m, addIssue as n, listIssues as o, pauseIssue as p, searchIssues as q, registerMachineService as r, startDaemon as s, isVisibleTo as t, updateIssue as u, getRun as v, listRuns as w, getWorkflow as x, runWorkflow as y, setWorkflowEnabled as z };
@@ -1,4 +1,4 @@
1
- import { j as resolveProjectRoot, D as listWorkflows, E as isWorkflowEnabled, F as workflowCrons, y as runWorkflow, G as cronMatches } from './run-CRTzyKbn.mjs';
1
+ import { j as resolveProjectRoot, D as listWorkflows, E as isWorkflowEnabled, F as workflowCrons, y as runWorkflow, G as cronMatches } from './run-BNiSOlBf.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -54,7 +54,7 @@ async function handleServeCommand() {
54
54
  }
55
55
  }
56
56
  async function serveAdd(args, machineId) {
57
- const { connectAndGetMachine } = await import('./commands-BABblJRp.mjs');
57
+ const { connectAndGetMachine } = await import('./commands-Dc9t_OeY.mjs');
58
58
  const pos = positionalArgs(args);
59
59
  const name = pos[0];
60
60
  if (!name) {
@@ -93,7 +93,7 @@ async function serveAdd(args, machineId) {
93
93
  }
94
94
  }
95
95
  async function serveApply(args, machineId) {
96
- const { connectAndGetMachine } = await import('./commands-BABblJRp.mjs');
96
+ const { connectAndGetMachine } = await import('./commands-Dc9t_OeY.mjs');
97
97
  const fs = await import('fs');
98
98
  const yaml = await import('yaml');
99
99
  const file = positionalArgs(args)[0];
@@ -182,7 +182,7 @@ async function serveApply(args, machineId) {
182
182
  }
183
183
  }
184
184
  async function serveRemove(args, machineId) {
185
- const { connectAndGetMachine } = await import('./commands-BABblJRp.mjs');
185
+ const { connectAndGetMachine } = await import('./commands-Dc9t_OeY.mjs');
186
186
  const pos = positionalArgs(args);
187
187
  const name = pos[0];
188
188
  if (!name) {
@@ -202,7 +202,7 @@ async function serveRemove(args, machineId) {
202
202
  }
203
203
  }
204
204
  async function serveList(args, machineId) {
205
- const { connectAndGetMachine } = await import('./commands-BABblJRp.mjs');
205
+ const { connectAndGetMachine } = await import('./commands-Dc9t_OeY.mjs');
206
206
  const all = hasFlag(args, "--all", "-a");
207
207
  const json = hasFlag(args, "--json");
208
208
  const sessionId = getFlag(args, "--session");
@@ -235,7 +235,7 @@ async function serveList(args, machineId) {
235
235
  }
236
236
  }
237
237
  async function serveInfo(machineId) {
238
- const { connectAndGetMachine } = await import('./commands-BABblJRp.mjs');
238
+ const { connectAndGetMachine } = await import('./commands-Dc9t_OeY.mjs');
239
239
  const { machine, server } = await connectAndGetMachine(machineId);
240
240
  try {
241
241
  const info = await machine.serveInfo();
@@ -1,4 +1,4 @@
1
- import { R as READ_ONLY_TOOLS, M as loadMachineContext, N as buildMachineInstructions, O as machineToolsForRole, P as buildMachineTools } from './run-CRTzyKbn.mjs';
1
+ import { R as READ_ONLY_TOOLS, M as loadMachineContext, N as buildMachineInstructions, O as machineToolsForRole, P as buildMachineTools } from './run-BNiSOlBf.mjs';
2
2
  import 'node:child_process';
3
3
  import 'os';
4
4
  import 'fs/promises';
package/package.json CHANGED
@@ -1,48 +1,48 @@
1
1
  {
2
- "name": "svamp-cli",
3
- "version": "0.2.284",
4
- "description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
5
- "author": "Amun AI AB",
6
- "license": "SEE LICENSE IN LICENSE",
7
- "type": "module",
8
- "bin": {
9
- "svamp": "./bin/svamp.mjs"
10
- },
11
- "files": [
12
- "dist",
13
- "bin"
14
- ],
15
- "main": "./dist/index.mjs",
16
- "exports": {
17
- ".": "./dist/index.mjs",
18
- "./cli": "./dist/cli.mjs"
19
- },
20
- "scripts": {
21
- "build": "rm -rf dist bin/skills bin/commands && mkdir -p bin/skills && cp -r ../../skills/artifact bin/skills/artifact && cp -r ../../skills/crew bin/skills/crew && cp -r ../../commands bin/commands && tsc --noEmit && pkgroll",
22
- "typecheck": "tsc --noEmit",
23
- "test": "npx tsx test/test-context-window.mjs && npx tsx test/test-ratelimit-retry.mjs && npx tsx test/test-instance-config.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-sharing-notify-sync.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-backend-accounts.mjs && npx tsx test/test-backend-oauth.mjs && npx tsx test/test-btw-proxy-env.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-inbox-guard.mjs && npx tsx test/test-user-events.mjs && npx tsx test/test-migrate-children.mjs && npx tsx test/test-inbox-reconcile.mjs && npx tsx test/test-auto-topic.mjs && npx tsx test/test-project-info.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-isolation-disable.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-session-access-fallback.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-app-server.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-session-send-query.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && node test/test-supervisor-restart.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-compact-detect.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox-store.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-inbox-cross-machine.mjs && npx tsx test/test-issue-store.mjs && npx tsx test/test-issue-close-gate.mjs && npx tsx test/test-loop-verify.mjs && npx tsx test/test-issue-rpc.mjs && npx tsx test/test-issue-pause.mjs && npx tsx test/test-workflow-store.mjs && npx tsx test/test-workflow-rpc.mjs && npx tsx test/test-workflow-scheduler.mjs && npx tsx test/test-cron.mjs && npx tsx test/test-workflow-runs.mjs && npx tsx test/test-workflow-idle.mjs && npx tsx test/test-serve-link-subdomain.mjs && npx tsx test/test-short-id.mjs && npx tsx test/test-transcript-edit.mjs && npx tsx test/test-edit-history.mjs && npx tsx test/test-friendly-name.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-ws-upgrade.mjs && npx tsx test/test-serve-auth.mjs && npx tsx test/test-static-file-server.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only && npx tsx test/test-frpc-status.mjs && node test/pinnedClaudeCode.test.mjs && node test/fleet.test.mjs && npx tsx test/test-session-file.mjs && npx tsx test/test-channel-rpc.mjs && npx tsx test/test-wise-agent.mjs && npx tsx test/test-channel-agent.mjs && npx tsx test/test-channels-service.mjs && npx tsx test/test-hotreload-seam.mjs && npx tsx test/test-hot-reload.mjs && npx tsx test/test-hot-reload-live.mjs && npx tsx test/test-session-core.mjs && npx tsx test/test-channel-async-reply.mjs && npx tsx test/test-outbox-reload.mjs && npx tsx test/test-channel-binding.mjs && npx tsx test/test-channel-identity.mjs && npx tsx test/test-shared-session-identity.mjs && npx tsx test/test-wise-agent-auth.mjs && npx tsx test/test-channel-http.mjs && npx tsx test/test-channel-upload.mjs && npx tsx test/test-wise-voice.mjs && npx tsx test/test-wise-headless.mjs && npx tsx test/test-wise-machine.mjs && npx tsx test/test-crew-merge.mjs && npx tsx test/test-crew-verdict-routing.mjs && npx tsx test/test-crew-standalone.mjs && npx tsx test/test-session-links.mjs && npx tsx test/test-issue-loop-pause-guard.mjs && npx tsx test/test-artifact-guard.mjs && npx tsx test/test-graceful-restart.mjs && npx tsx test/test-flush-exit.mjs",
24
- "test:hypha": "node --no-warnings test/test-hypha-service.mjs",
25
- "dev": "tsx src/cli.ts",
26
- "dev:daemon": "tsx src/cli.ts daemon start-sync",
27
- "test:e2e": "node --no-warnings test/e2e-session-tests.mjs",
28
- "test:frpc": "npx tsx test/test-frpc-e2e.mjs",
29
- "prepublishOnly": "yarn build"
30
- },
31
- "dependencies": {
32
- "@agentclientprotocol/sdk": "^0.14.1",
33
- "@modelcontextprotocol/sdk": "^1.25.3",
34
- "hypha-rpc": "0.21.42",
35
- "node-pty": "1.2.0-beta.11",
36
- "ws": "^8.18.0",
37
- "yaml": "^2.8.2",
38
- "zod": "^3.24.4"
39
- },
40
- "devDependencies": {
41
- "@types/node": ">=20",
42
- "@types/ws": "^8.5.14",
43
- "pkgroll": "^2.14.2",
44
- "tsx": "^4.20.6",
45
- "typescript": "5.9.3"
46
- },
47
- "packageManager": "yarn@1.22.22"
2
+ "name": "svamp-cli",
3
+ "version": "0.2.290",
4
+ "description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
5
+ "author": "Amun AI AB",
6
+ "license": "SEE LICENSE IN LICENSE",
7
+ "type": "module",
8
+ "bin": {
9
+ "svamp": "./bin/svamp.mjs"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "bin"
14
+ ],
15
+ "main": "./dist/index.mjs",
16
+ "exports": {
17
+ ".": "./dist/index.mjs",
18
+ "./cli": "./dist/cli.mjs"
19
+ },
20
+ "scripts": {
21
+ "build": "rm -rf dist bin/skills bin/commands && mkdir -p bin/skills && cp -r ../../skills/artifact bin/skills/artifact && cp -r ../../skills/crew bin/skills/crew && cp -r ../../commands bin/commands && tsc --noEmit && pkgroll",
22
+ "typecheck": "tsc --noEmit",
23
+ "test": "npx tsx test/test-context-window.mjs && npx tsx test/test-ratelimit-retry.mjs && npx tsx test/test-instance-config.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-sharing-notify-sync.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-backend-accounts.mjs && npx tsx test/test-codex-force-model.mjs && npx tsx test/test-backend-oauth.mjs && npx tsx test/test-btw-proxy-env.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-inbox-guard.mjs && npx tsx test/test-user-events.mjs && npx tsx test/test-migrate-children.mjs && npx tsx test/test-outpost-install.mjs && npx tsx test/test-inbox-reconcile.mjs && npx tsx test/test-auto-topic.mjs && npx tsx test/test-project-info.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-isolation-disable.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-session-access-fallback.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-app-server.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-session-send-query.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && node test/test-supervisor-restart.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-compact-detect.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox-store.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-inbox-cross-machine.mjs && npx tsx test/test-issue-store.mjs && npx tsx test/test-issue-close-gate.mjs && npx tsx test/test-loop-verify.mjs && npx tsx test/test-restore-decision.mjs && npx tsx test/test-issue-rpc.mjs && npx tsx test/test-issue-pause.mjs && npx tsx test/test-workflow-store.mjs && npx tsx test/test-workflow-rpc.mjs && npx tsx test/test-workflow-scheduler.mjs && npx tsx test/test-cron.mjs && npx tsx test/test-workflow-runs.mjs && npx tsx test/test-workflow-idle.mjs && npx tsx test/test-serve-link-subdomain.mjs && npx tsx test/test-short-id.mjs && npx tsx test/test-transcript-edit.mjs && npx tsx test/test-edit-history.mjs && npx tsx test/test-friendly-name.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-ws-upgrade.mjs && npx tsx test/test-serve-auth.mjs && npx tsx test/test-static-file-server.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only && npx tsx test/test-frpc-status.mjs && node test/pinnedClaudeCode.test.mjs && node test/fleet.test.mjs && npx tsx test/test-session-file.mjs && npx tsx test/test-channel-rpc.mjs && npx tsx test/test-wise-agent.mjs && npx tsx test/test-channel-agent.mjs && npx tsx test/test-channels-service.mjs && npx tsx test/test-hotreload-seam.mjs && npx tsx test/test-hot-reload.mjs && npx tsx test/test-hot-reload-live.mjs && npx tsx test/test-session-core.mjs && npx tsx test/test-channel-async-reply.mjs && npx tsx test/test-outbox-reload.mjs && npx tsx test/test-channel-binding.mjs && npx tsx test/test-channel-identity.mjs && npx tsx test/test-stateless-dispatch-limiter.mjs && npx tsx test/test-shared-session-identity.mjs && npx tsx test/test-wise-agent-auth.mjs && npx tsx test/test-channel-http.mjs && npx tsx test/test-channel-upload.mjs && npx tsx test/test-wise-voice.mjs && npx tsx test/test-wise-headless.mjs && npx tsx test/test-wise-machine.mjs && npx tsx test/test-crew-merge.mjs && npx tsx test/test-crew-verdict-routing.mjs && npx tsx test/test-crew-standalone.mjs && npx tsx test/test-session-links.mjs && npx tsx test/test-issue-loop-pause-guard.mjs && npx tsx test/test-artifact-guard.mjs && npx tsx test/test-artifact-sync-pagination.mjs && npx tsx test/test-graceful-restart.mjs && npx tsx test/test-flush-exit.mjs",
24
+ "test:hypha": "node --no-warnings test/test-hypha-service.mjs",
25
+ "dev": "tsx src/cli.ts",
26
+ "dev:daemon": "tsx src/cli.ts daemon start-sync",
27
+ "test:e2e": "node --no-warnings test/e2e-session-tests.mjs",
28
+ "test:frpc": "npx tsx test/test-frpc-e2e.mjs",
29
+ "prepublishOnly": "yarn build"
30
+ },
31
+ "dependencies": {
32
+ "@agentclientprotocol/sdk": "^0.14.1",
33
+ "@modelcontextprotocol/sdk": "^1.25.3",
34
+ "hypha-rpc": "0.21.42",
35
+ "node-pty": "1.2.0-beta.11",
36
+ "ws": "^8.18.0",
37
+ "yaml": "^2.8.2",
38
+ "zod": "^3.24.4"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": ">=20",
42
+ "@types/ws": "^8.5.14",
43
+ "pkgroll": "^2.14.2",
44
+ "tsx": "^4.20.6",
45
+ "typescript": "5.9.3"
46
+ },
47
+ "packageManager": "yarn@1.22.22"
48
48
  }