svamp-cli 0.2.178 → 0.2.180

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 (24) hide show
  1. package/dist/{agentCommands-BIn9btot.mjs → agentCommands-CKSZimNF.mjs} +5 -5
  2. package/dist/{auth-DY_tcgLY.mjs → auth-BVDufOmQ.mjs} +1 -1
  3. package/dist/cli.mjs +65 -63
  4. package/dist/{commands-J9WOCzDG.mjs → commands-BG-Y0806.mjs} +2 -2
  5. package/dist/{commands-kepmDOXD.mjs → commands-BS2iZc30.mjs} +2 -2
  6. package/dist/{commands-BfdkS7Iy.mjs → commands-CBWOeFLL.mjs} +1 -1
  7. package/dist/{commands-MjIkmrmC.mjs → commands-CL9hxClH.mjs} +25 -4
  8. package/dist/{commands-WgUO8QeK.mjs → commands-CUSKCGUs.mjs} +1 -1
  9. package/dist/{commands-BTyp-k7w.mjs → commands-DuvX1TtC.mjs} +5 -5
  10. package/dist/{commands-CdMEMD_c.mjs → commands-qbv-1BoA.mjs} +1 -1
  11. package/dist/{fleet-CDllUpMj.mjs → fleet-IKkKrYCK.mjs} +1 -1
  12. package/dist/{frpc-D4x74mG6.mjs → frpc-CLJ1PNTL.mjs} +1 -1
  13. package/dist/{headlessCli-CmBCGmNV.mjs → headlessCli-C8-hCKbi.mjs} +2 -2
  14. package/dist/index.mjs +1 -1
  15. package/dist/{package-B-yM7SvY.mjs → package-4UtwIq9O.mjs} +1 -1
  16. package/dist/{rpc-2TJ6ipXZ.mjs → rpc-D3J1JM29.mjs} +1 -1
  17. package/dist/{rpc-DBH2bo8s.mjs → rpc-DLPG3JvW.mjs} +3 -2
  18. package/dist/{run-B-1WDymr.mjs → run-C9PMX7NQ.mjs} +163 -142
  19. package/dist/{run-BVNBqt1C.mjs → run-D5-ounOl.mjs} +1 -1
  20. package/dist/{scheduler-C3j8Tghm.mjs → scheduler-Bgs6H33k.mjs} +8 -6
  21. package/dist/{serveCommands-BFWBxK8L.mjs → serveCommands-Dx5BiAfU.mjs} +5 -5
  22. package/dist/{serveManager-DXm1bdoU.mjs → serveManager-B6bHAn0B.mjs} +2 -2
  23. package/dist/{sideband-Da1VG2iq.mjs → sideband-Dd1I6S5u.mjs} +1 -1
  24. package/package.json +1 -1
@@ -58,7 +58,7 @@ async function serviceExpose(args) {
58
58
  process.exit(1);
59
59
  }
60
60
  if (foreground) {
61
- const { runFrpcTunnel } = await import('./frpc-D4x74mG6.mjs');
61
+ const { runFrpcTunnel } = await import('./frpc-CLJ1PNTL.mjs');
62
62
  await runFrpcTunnel(name, ports, void 0, {
63
63
  group,
64
64
  groupKey,
@@ -68,7 +68,7 @@ async function serviceExpose(args) {
68
68
  });
69
69
  return;
70
70
  }
71
- const { connectAndGetMachine } = await import('./commands-MjIkmrmC.mjs');
71
+ const { connectAndGetMachine } = await import('./commands-CL9hxClH.mjs');
72
72
  const { server, machine } = await connectAndGetMachine();
73
73
  try {
74
74
  const status = await machine.tunnelStart({
@@ -123,7 +123,7 @@ async function serviceServe(args) {
123
123
  };
124
124
  process.on("SIGINT", cleanup);
125
125
  process.on("SIGTERM", cleanup);
126
- const { runFrpcTunnel } = await import('./frpc-D4x74mG6.mjs');
126
+ const { runFrpcTunnel } = await import('./frpc-CLJ1PNTL.mjs');
127
127
  await runFrpcTunnel(name, [caddyPort]);
128
128
  } catch (err) {
129
129
  console.error(`Error serving directory: ${err.message}`);
@@ -132,7 +132,7 @@ async function serviceServe(args) {
132
132
  }
133
133
  async function serviceList(_args) {
134
134
  try {
135
- const { connectAndGetMachine } = await import('./commands-MjIkmrmC.mjs');
135
+ const { connectAndGetMachine } = await import('./commands-CL9hxClH.mjs');
136
136
  const { server, machine } = await connectAndGetMachine();
137
137
  try {
138
138
  const tunnels = await machine.tunnelList({});
@@ -172,7 +172,7 @@ async function serviceDelete(args) {
172
172
  process.exit(1);
173
173
  }
174
174
  try {
175
- const { connectAndGetMachine } = await import('./commands-MjIkmrmC.mjs');
175
+ const { connectAndGetMachine } = await import('./commands-CL9hxClH.mjs');
176
176
  const { server, machine } = await connectAndGetMachine();
177
177
  try {
178
178
  await machine.tunnelStop({ name });
@@ -1,7 +1,7 @@
1
1
  import os from 'os';
2
2
  import fs__default from 'fs';
3
3
  import { resolve, join, relative } from 'path';
4
- import { C as parseFrontmatter, D as getSkillsServer, E as getSkillsWorkspaceName, F as getSkillsCollectionName, G as fetchWithTimeout, H as searchSkills, I as SKILLS_DIR, J as getSkillInfo, K as downloadSkillFile, L as listSkillFiles } from './run-B-1WDymr.mjs';
4
+ import { C as parseFrontmatter, D as getSkillsServer, E as getSkillsWorkspaceName, F as getSkillsCollectionName, G as fetchWithTimeout, H as searchSkills, I as SKILLS_DIR, J as getSkillInfo, K as downloadSkillFile, L as listSkillFiles } from './run-C9PMX7NQ.mjs';
5
5
  import 'fs/promises';
6
6
  import 'url';
7
7
  import 'child_process';
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import os from 'node:os';
4
- import { c as connectToHypha } from './run-B-1WDymr.mjs';
4
+ import { c as connectToHypha } from './run-C9PMX7NQ.mjs';
5
5
  import { PINNED_CLAUDE_CODE_VERSION } from './pinnedClaudeCode-HydRNEt7.mjs';
6
6
  import 'os';
7
7
  import 'fs/promises';
@@ -4,7 +4,7 @@ import { mkdirSync, writeFileSync, unlinkSync, existsSync, chmodSync, readFileSy
4
4
  import { join } from 'path';
5
5
  import { homedir, platform, arch } from 'os';
6
6
  import { randomUUID, createHash } from 'crypto';
7
- import { h as getFrpsSubdomainHost, i as getFrpsServerPort, j as getFrpsServerAddr } from './run-B-1WDymr.mjs';
7
+ import { h as getFrpsSubdomainHost, i as getFrpsServerPort, j as getFrpsServerAddr } from './run-C9PMX7NQ.mjs';
8
8
  import 'fs/promises';
9
9
  import 'url';
10
10
  import 'node:crypto';
@@ -1,5 +1,5 @@
1
- import { M as resolveModel, _ as describeMisconfiguration, $ as buildMachineDeps } from './run-B-1WDymr.mjs';
2
- import { handleRealtimeEvent, initMachineVoiceSession } from './sideband-Da1VG2iq.mjs';
1
+ import { M as resolveModel, _ as describeMisconfiguration, $ as buildMachineDeps } from './run-C9PMX7NQ.mjs';
2
+ import { handleRealtimeEvent, initMachineVoiceSession } from './sideband-Dd1I6S5u.mjs';
3
3
  import { WebSocket } from 'ws';
4
4
  import { execSync, spawn } from 'child_process';
5
5
  import 'os';
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { c as connectToHypha, a as createSessionStore, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, s as startDaemon, b as stopDaemon } from './run-B-1WDymr.mjs';
1
+ export { c as connectToHypha, a as createSessionStore, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, s as startDaemon, b as stopDaemon } from './run-C9PMX7NQ.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -1,5 +1,5 @@
1
1
  var name = "svamp-cli";
2
- var version = "0.2.178";
2
+ var version = "0.2.180";
3
3
  var description = "Svamp CLI — AI workspace daemon on Hypha Cloud";
4
4
  var author = "Amun AI AB";
5
5
  var license = "SEE LICENSE IN LICENSE";
@@ -1,4 +1,4 @@
1
- import { m as resolveProjectRoot, u as updateIssue, n as getIssue, o as addComment, p as addIssue, q as listIssues, t as searchIssues } from './run-B-1WDymr.mjs';
1
+ import { m as resolveProjectRoot, u as updateIssue, n as getIssue, o as addComment, p as addIssue, q as listIssues, t as searchIssues } from './run-C9PMX7NQ.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -1,5 +1,5 @@
1
1
  import { spawnSync } from 'node:child_process';
2
- import { m as resolveProjectRoot } from './run-B-1WDymr.mjs';
2
+ import { m as resolveProjectRoot } from './run-C9PMX7NQ.mjs';
3
3
  import { g as getWorkflow, w as workflowSteps, r as removeWorkflow, s as saveWorkflow, a as rawWorkflow, l as listWorkflows } from './store-BPL__e4D.mjs';
4
4
  import 'os';
5
5
  import 'fs/promises';
@@ -57,11 +57,12 @@ function workflowRpc(cwd, params) {
57
57
  const wf = getWorkflow(root, String(params.name));
58
58
  if (!wf) throw new Error(`Workflow not found: ${params.name}`);
59
59
  const steps = workflowSteps(wf);
60
+ const stepEnv = wf.session ? { ...process.env, SVAMP_SESSION_ID: wf.session } : process.env;
60
61
  const out = [`\u25B6 running workflow "${wf.name}" (${steps.length} step${steps.length === 1 ? "" : "s"})`];
61
62
  for (let i = 0; i < steps.length; i++) {
62
63
  const step = steps[i];
63
64
  out.push(` [${i + 1}/${steps.length}] $ ${step.run}`);
64
- const r = spawnSync("sh", ["-c", step.run], { cwd: root, encoding: "utf-8", timeout: 12e4 });
65
+ const r = spawnSync("sh", ["-c", step.run], { cwd: root, encoding: "utf-8", timeout: 12e4, env: stepEnv });
65
66
  if (r.stdout) out.push(r.stdout.trimEnd());
66
67
  if (r.stderr) out.push(r.stderr.trimEnd());
67
68
  if (r.status !== 0) {
@@ -2699,7 +2699,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
2699
2699
  const tunnels = handlers.tunnels;
2700
2700
  if (!tunnels) throw new Error("Tunnel management not available");
2701
2701
  if (tunnels.has(params.name)) throw new Error(`Tunnel '${params.name}' already running`);
2702
- const { FrpcTunnel } = await import('./frpc-D4x74mG6.mjs');
2702
+ const { FrpcTunnel } = await import('./frpc-CLJ1PNTL.mjs');
2703
2703
  const tunnel = new FrpcTunnel({
2704
2704
  name: params.name,
2705
2705
  ports: params.ports,
@@ -3146,7 +3146,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
3146
3146
  }
3147
3147
  const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
3148
3148
  const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
3149
- const { toolsForRole } = await import('./sideband-Da1VG2iq.mjs');
3149
+ const { toolsForRole } = await import('./sideband-Dd1I6S5u.mjs');
3150
3150
  const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
3151
3151
  return fmt(r2);
3152
3152
  }
@@ -3245,7 +3245,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
3245
3245
  if (r.error || !r.sender) return { error: r.error || "unauthorized" };
3246
3246
  const callId = "call_" + Math.random().toString(16).slice(2, 12);
3247
3247
  const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
3248
- const { queryCore } = await import('./commands-MjIkmrmC.mjs');
3248
+ const { queryCore } = await import('./commands-CL9hxClH.mjs');
3249
3249
  const timeout = c.reply?.timeout_sec || 120;
3250
3250
  let result;
3251
3251
  try {
@@ -3389,6 +3389,132 @@ ${d?.error || "not found"}`;
3389
3389
  };
3390
3390
  }
3391
3391
 
3392
+ const SVAMP_HOME$2 = process.env.SVAMP_HOME || join(os.homedir(), ".svamp");
3393
+ const num = (key, def) => {
3394
+ const v = Number(process.env[key]);
3395
+ return Number.isFinite(v) && v > 0 ? v : def;
3396
+ };
3397
+ const MAX_AGENT_HOPS = num("SVAMP_INBOX_MAX_HOPS", 3);
3398
+ const URGENT_BURST = num("SVAMP_INBOX_URGENT_BURST", 5);
3399
+ const URGENT_REFILL_MS = num("SVAMP_INBOX_URGENT_REFILL_MS", 6e4);
3400
+ const BREAKER_WINDOW_MS = num("SVAMP_INBOX_BREAKER_WINDOW_MS", 6e4);
3401
+ const BREAKER_MAX_WAKES = num("SVAMP_INBOX_BREAKER_MAX_WAKES", 30);
3402
+ const BREAKER_COOLDOWN_MS = num("SVAMP_INBOX_BREAKER_COOLDOWN_MS", 12e4);
3403
+ const CTX_STALE_MS = num("SVAMP_INBOX_CTX_STALE_MS", 30 * 6e4);
3404
+ function ctxPath(sessionId) {
3405
+ return join(SVAMP_HOME$2, "inbound", `${sessionId}.json`);
3406
+ }
3407
+ function writeInboundContext(sessionId, ctx) {
3408
+ try {
3409
+ const p = ctxPath(sessionId);
3410
+ mkdirSync(join(SVAMP_HOME$2, "inbound"), { recursive: true });
3411
+ const tmp = p + ".tmp";
3412
+ writeFileSync(tmp, JSON.stringify({ ...ctx, deliveredAt: Date.now() }));
3413
+ try {
3414
+ rmSync(p, { force: true });
3415
+ } catch {
3416
+ }
3417
+ writeFileSync(p, readFileSync(tmp));
3418
+ try {
3419
+ rmSync(tmp, { force: true });
3420
+ } catch {
3421
+ }
3422
+ } catch {
3423
+ }
3424
+ }
3425
+ function clearInboundContext(sessionId) {
3426
+ try {
3427
+ rmSync(ctxPath(sessionId), { force: true });
3428
+ } catch {
3429
+ }
3430
+ }
3431
+ function readInboundContext(sessionId) {
3432
+ try {
3433
+ const p = ctxPath(sessionId);
3434
+ if (!existsSync(p)) return null;
3435
+ const ctx = JSON.parse(readFileSync(p, "utf-8"));
3436
+ if (!ctx || typeof ctx.hopCount !== "number") return null;
3437
+ if (Date.now() - (ctx.deliveredAt || 0) > CTX_STALE_MS) return null;
3438
+ return ctx;
3439
+ } catch {
3440
+ return null;
3441
+ }
3442
+ }
3443
+ function computeOutboundHop(sessionId) {
3444
+ if (!sessionId) return { hopCount: 0, fromInboxTurn: false };
3445
+ const ctx = readInboundContext(sessionId);
3446
+ if (ctx) return { hopCount: (ctx.hopCount || 0) + 1, threadId: ctx.threadId, fromInboxTurn: true };
3447
+ return { hopCount: 1, fromInboxTurn: false };
3448
+ }
3449
+ const buckets = /* @__PURE__ */ new Map();
3450
+ function takeUrgentToken(sender, now) {
3451
+ let b = buckets.get(sender);
3452
+ if (!b) {
3453
+ b = { tokens: URGENT_BURST, last: now };
3454
+ buckets.set(sender, b);
3455
+ }
3456
+ const refill = Math.floor((now - b.last) / URGENT_REFILL_MS);
3457
+ if (refill > 0) {
3458
+ b.tokens = Math.min(URGENT_BURST, b.tokens + refill);
3459
+ b.last = now;
3460
+ }
3461
+ if (b.tokens > 0) {
3462
+ b.tokens -= 1;
3463
+ return true;
3464
+ }
3465
+ return false;
3466
+ }
3467
+ let wakeTimes = [];
3468
+ let breakerOpenUntil = 0;
3469
+ function isBreakerOpenAt(now) {
3470
+ return now < breakerOpenUntil;
3471
+ }
3472
+ function recordWake(now) {
3473
+ wakeTimes = wakeTimes.filter((t) => now - t < BREAKER_WINDOW_MS);
3474
+ wakeTimes.push(now);
3475
+ if (wakeTimes.length > BREAKER_MAX_WAKES) {
3476
+ breakerOpenUntil = now + BREAKER_COOLDOWN_MS;
3477
+ return true;
3478
+ }
3479
+ return false;
3480
+ }
3481
+ function senderIsHuman(message) {
3482
+ const f = message.from || "";
3483
+ return f.startsWith("cli:") || f.startsWith("user:");
3484
+ }
3485
+ function senderKey(message) {
3486
+ return message.fromSession || message.from || "unknown";
3487
+ }
3488
+ function classifyInbound(message, now = Date.now()) {
3489
+ const hop = message.hopCount ?? 0;
3490
+ const human = senderIsHuman(message);
3491
+ if (!human && !message.channel && hop > MAX_AGENT_HOPS) {
3492
+ return { action: "silent", reason: `loop-guard: hop ${hop} > ${MAX_AGENT_HOPS}` };
3493
+ }
3494
+ if (message.urgency !== "urgent") {
3495
+ return { action: "queue", reason: "non-urgent" };
3496
+ }
3497
+ if (human) {
3498
+ const tripped2 = recordWake(now);
3499
+ return { action: "wake", reason: "urgent (human)", breakerTripped: tripped2 };
3500
+ }
3501
+ if (isBreakerOpenAt(now)) {
3502
+ return { action: "queue", reason: "circuit-breaker-open" };
3503
+ }
3504
+ if (!takeUrgentToken(senderKey(message), now)) {
3505
+ return { action: "queue", reason: "rate-limited" };
3506
+ }
3507
+ const tripped = recordWake(now);
3508
+ return { action: "wake", reason: "urgent", breakerTripped: tripped };
3509
+ }
3510
+ function applyInboxClear(inbox, opts) {
3511
+ let kept;
3512
+ if (opts?.messageId) kept = inbox.filter((m) => m.messageId !== opts.messageId);
3513
+ else if (opts?.all) kept = [];
3514
+ else kept = inbox.filter((m) => !m.read);
3515
+ return { kept, removed: inbox.length - kept.length };
3516
+ }
3517
+
3392
3518
  const PARTICIPANTS_CHANNEL_ID = "sys-participants";
3393
3519
  function channelPublicView(c) {
3394
3520
  return { id: c.id, name: c.name, description: c.description, identity: { mode: c.identity?.mode }, action: c.action?.kind, bind: c.bind };
@@ -4453,16 +4579,12 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
4453
4579
  },
4454
4580
  clearInbox: async (opts, context) => {
4455
4581
  authorizeRequest(context, metadata.sharing, "admin");
4456
- if (opts?.all) {
4457
- inbox.length = 0;
4458
- } else {
4459
- for (let i = inbox.length - 1; i >= 0; i--) {
4460
- if (inbox[i].read) inbox.splice(i, 1);
4461
- }
4462
- }
4582
+ const { kept, removed } = applyInboxClear(inbox, opts);
4583
+ inbox.length = 0;
4584
+ inbox.push(...kept);
4463
4585
  syncInboxToMetadata();
4464
4586
  notifyListeners({ type: "inbox-update", sessionId, cleared: true });
4465
- return { success: true, remaining: inbox.length };
4587
+ return { success: true, removed, remaining: inbox.length };
4466
4588
  },
4467
4589
  // ── Listener Registration ──
4468
4590
  registerListener: async (callback, context) => {
@@ -4977,11 +5099,29 @@ function friendlyNameFromId(id) {
4977
5099
  }
4978
5100
  function composeSessionId(friendlyName, takenIds = [], len = 6) {
4979
5101
  const taken = takenIds instanceof Set ? takenIds : new Set(takenIds);
4980
- let width = len;
4981
- for (let attempt = 0; ; attempt++) {
4982
- const candidate = `${friendlyName}-${shortId(width, LOWER_ALPHABET)}`;
4983
- if (!taken.has(candidate)) return candidate;
4984
- if (attempt > 0 && attempt % 16 === 0) width++;
5102
+ const A = LOWER_ALPHABET.length;
5103
+ const nthSuffix = (i, width2) => {
5104
+ let s = "";
5105
+ for (let k = 0; k < width2; k++) {
5106
+ s = LOWER_ALPHABET[i % A] + s;
5107
+ i = Math.floor(i / A);
5108
+ }
5109
+ return s;
5110
+ };
5111
+ let width = Math.max(1, len);
5112
+ for (; ; ) {
5113
+ const space = Math.pow(A, width);
5114
+ for (let i = 0; i < 64; i++) {
5115
+ const candidate = `${friendlyName}-${shortId(width, LOWER_ALPHABET)}`;
5116
+ if (!taken.has(candidate)) return candidate;
5117
+ }
5118
+ if (space <= 1e6) {
5119
+ for (let i = 0; i < space; i++) {
5120
+ const candidate = `${friendlyName}-${nthSuffix(i, width)}`;
5121
+ if (!taken.has(candidate)) return candidate;
5122
+ }
5123
+ }
5124
+ width++;
4985
5125
  }
4986
5126
  }
4987
5127
  function formatHandle(projectName, friendlyName) {
@@ -5005,125 +5145,6 @@ function handleMatchesMetadata(parsed, metadata) {
5005
5145
  return true;
5006
5146
  }
5007
5147
 
5008
- const SVAMP_HOME$2 = process.env.SVAMP_HOME || join(os.homedir(), ".svamp");
5009
- const num = (key, def) => {
5010
- const v = Number(process.env[key]);
5011
- return Number.isFinite(v) && v > 0 ? v : def;
5012
- };
5013
- const MAX_AGENT_HOPS = num("SVAMP_INBOX_MAX_HOPS", 3);
5014
- const URGENT_BURST = num("SVAMP_INBOX_URGENT_BURST", 5);
5015
- const URGENT_REFILL_MS = num("SVAMP_INBOX_URGENT_REFILL_MS", 6e4);
5016
- const BREAKER_WINDOW_MS = num("SVAMP_INBOX_BREAKER_WINDOW_MS", 6e4);
5017
- const BREAKER_MAX_WAKES = num("SVAMP_INBOX_BREAKER_MAX_WAKES", 30);
5018
- const BREAKER_COOLDOWN_MS = num("SVAMP_INBOX_BREAKER_COOLDOWN_MS", 12e4);
5019
- const CTX_STALE_MS = num("SVAMP_INBOX_CTX_STALE_MS", 30 * 6e4);
5020
- function ctxPath(sessionId) {
5021
- return join(SVAMP_HOME$2, "inbound", `${sessionId}.json`);
5022
- }
5023
- function writeInboundContext(sessionId, ctx) {
5024
- try {
5025
- const p = ctxPath(sessionId);
5026
- mkdirSync(join(SVAMP_HOME$2, "inbound"), { recursive: true });
5027
- const tmp = p + ".tmp";
5028
- writeFileSync(tmp, JSON.stringify({ ...ctx, deliveredAt: Date.now() }));
5029
- try {
5030
- rmSync(p, { force: true });
5031
- } catch {
5032
- }
5033
- writeFileSync(p, readFileSync(tmp));
5034
- try {
5035
- rmSync(tmp, { force: true });
5036
- } catch {
5037
- }
5038
- } catch {
5039
- }
5040
- }
5041
- function clearInboundContext(sessionId) {
5042
- try {
5043
- rmSync(ctxPath(sessionId), { force: true });
5044
- } catch {
5045
- }
5046
- }
5047
- function readInboundContext(sessionId) {
5048
- try {
5049
- const p = ctxPath(sessionId);
5050
- if (!existsSync(p)) return null;
5051
- const ctx = JSON.parse(readFileSync(p, "utf-8"));
5052
- if (!ctx || typeof ctx.hopCount !== "number") return null;
5053
- if (Date.now() - (ctx.deliveredAt || 0) > CTX_STALE_MS) return null;
5054
- return ctx;
5055
- } catch {
5056
- return null;
5057
- }
5058
- }
5059
- function computeOutboundHop(sessionId) {
5060
- if (!sessionId) return { hopCount: 0, fromInboxTurn: false };
5061
- const ctx = readInboundContext(sessionId);
5062
- if (ctx) return { hopCount: (ctx.hopCount || 0) + 1, threadId: ctx.threadId, fromInboxTurn: true };
5063
- return { hopCount: 1, fromInboxTurn: false };
5064
- }
5065
- const buckets = /* @__PURE__ */ new Map();
5066
- function takeUrgentToken(sender, now) {
5067
- let b = buckets.get(sender);
5068
- if (!b) {
5069
- b = { tokens: URGENT_BURST, last: now };
5070
- buckets.set(sender, b);
5071
- }
5072
- const refill = Math.floor((now - b.last) / URGENT_REFILL_MS);
5073
- if (refill > 0) {
5074
- b.tokens = Math.min(URGENT_BURST, b.tokens + refill);
5075
- b.last = now;
5076
- }
5077
- if (b.tokens > 0) {
5078
- b.tokens -= 1;
5079
- return true;
5080
- }
5081
- return false;
5082
- }
5083
- let wakeTimes = [];
5084
- let breakerOpenUntil = 0;
5085
- function isBreakerOpenAt(now) {
5086
- return now < breakerOpenUntil;
5087
- }
5088
- function recordWake(now) {
5089
- wakeTimes = wakeTimes.filter((t) => now - t < BREAKER_WINDOW_MS);
5090
- wakeTimes.push(now);
5091
- if (wakeTimes.length > BREAKER_MAX_WAKES) {
5092
- breakerOpenUntil = now + BREAKER_COOLDOWN_MS;
5093
- return true;
5094
- }
5095
- return false;
5096
- }
5097
- function senderIsHuman(message) {
5098
- const f = message.from || "";
5099
- return f.startsWith("cli:") || f.startsWith("user:");
5100
- }
5101
- function senderKey(message) {
5102
- return message.fromSession || message.from || "unknown";
5103
- }
5104
- function classifyInbound(message, now = Date.now()) {
5105
- const hop = message.hopCount ?? 0;
5106
- const human = senderIsHuman(message);
5107
- if (!human && !message.channel && hop > MAX_AGENT_HOPS) {
5108
- return { action: "silent", reason: `loop-guard: hop ${hop} > ${MAX_AGENT_HOPS}` };
5109
- }
5110
- if (message.urgency !== "urgent") {
5111
- return { action: "queue", reason: "non-urgent" };
5112
- }
5113
- if (human) {
5114
- const tripped2 = recordWake(now);
5115
- return { action: "wake", reason: "urgent (human)", breakerTripped: tripped2 };
5116
- }
5117
- if (isBreakerOpenAt(now)) {
5118
- return { action: "queue", reason: "circuit-breaker-open" };
5119
- }
5120
- if (!takeUrgentToken(senderKey(message), now)) {
5121
- return { action: "queue", reason: "rate-limited" };
5122
- }
5123
- const tripped = recordWake(now);
5124
- return { action: "wake", reason: "urgent", breakerTripped: tripped };
5125
- }
5126
-
5127
5148
  function resolveProjectRoot$1(directory) {
5128
5149
  try {
5129
5150
  const top = execSync("git rev-parse --show-toplevel", {
@@ -11547,7 +11568,7 @@ async function startDaemon(options) {
11547
11568
  saveExposedTunnels(list);
11548
11569
  }
11549
11570
  async function createExposedTunnel(spec) {
11550
- const { FrpcTunnel } = await import('./frpc-D4x74mG6.mjs');
11571
+ const { FrpcTunnel } = await import('./frpc-CLJ1PNTL.mjs');
11551
11572
  const tunnel = new FrpcTunnel({
11552
11573
  name: spec.name,
11553
11574
  ports: spec.ports,
@@ -11567,7 +11588,7 @@ async function startDaemon(options) {
11567
11588
  return tunnel;
11568
11589
  }
11569
11590
  const tunnelRecreateState = /* @__PURE__ */ new Map();
11570
- const { ServeManager } = await import('./serveManager-DXm1bdoU.mjs');
11591
+ const { ServeManager } = await import('./serveManager-B6bHAn0B.mjs');
11571
11592
  const serveManager = new ServeManager(SVAMP_HOME, (msg) => logger.log(`[SERVE] ${msg}`), hyphaServerUrl);
11572
11593
  ensureAutoInstalledSkills(logger).catch(() => {
11573
11594
  });
@@ -13358,11 +13379,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
13358
13379
  });
13359
13380
  },
13360
13381
  onIssue: async (params) => {
13361
- const { issueRpc } = await import('./rpc-2TJ6ipXZ.mjs');
13382
+ const { issueRpc } = await import('./rpc-D3J1JM29.mjs');
13362
13383
  return issueRpc(params?.cwd || directory, params || {});
13363
13384
  },
13364
13385
  onWorkflow: async (params) => {
13365
- const { workflowRpc } = await import('./rpc-DBH2bo8s.mjs');
13386
+ const { workflowRpc } = await import('./rpc-DLPG3JvW.mjs');
13366
13387
  return workflowRpc(params?.cwd || directory, params || {});
13367
13388
  },
13368
13389
  onRipgrep: async (args, cwd) => {
@@ -13868,11 +13889,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
13868
13889
  });
13869
13890
  },
13870
13891
  onIssue: async (params) => {
13871
- const { issueRpc } = await import('./rpc-2TJ6ipXZ.mjs');
13892
+ const { issueRpc } = await import('./rpc-D3J1JM29.mjs');
13872
13893
  return issueRpc(params?.cwd || directory, params || {});
13873
13894
  },
13874
13895
  onWorkflow: async (params) => {
13875
- const { workflowRpc } = await import('./rpc-DBH2bo8s.mjs');
13896
+ const { workflowRpc } = await import('./rpc-DLPG3JvW.mjs');
13876
13897
  return workflowRpc(params?.cwd || directory, params || {});
13877
13898
  },
13878
13899
  onRipgrep: async (args, cwd) => {
@@ -14625,7 +14646,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
14625
14646
  const PING_TIMEOUT_MS = 15e3;
14626
14647
  const POST_RECONNECT_GRACE_MS = 2e4;
14627
14648
  const RECONNECT_JITTER_MS = 2500;
14628
- const { WorkflowScheduler } = await import('./scheduler-C3j8Tghm.mjs');
14649
+ const { WorkflowScheduler } = await import('./scheduler-Bgs6H33k.mjs');
14629
14650
  const workflowScheduler = new WorkflowScheduler({
14630
14651
  projectRoots: () => {
14631
14652
  const dirs = /* @__PURE__ */ new Set();
@@ -1,4 +1,4 @@
1
- import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { a0 as composeSessionId, a1 as generateFriendlyName, c as connectToHypha, a as createSessionStore, r as registerMachineService, a2 as generateHookSettings } from './run-B-1WDymr.mjs';
1
+ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { a0 as composeSessionId, a1 as generateFriendlyName, c as connectToHypha, a as createSessionStore, r as registerMachineService, a2 as generateHookSettings } from './run-C9PMX7NQ.mjs';
2
2
  import os from 'node:os';
3
3
  import { resolve, join } from 'node:path';
4
4
  import { existsSync, readFileSync, watch } from 'node:fs';
@@ -1,5 +1,5 @@
1
1
  import { spawn } from 'node:child_process';
2
- import { m as resolveProjectRoot, v as cronMatches } from './run-B-1WDymr.mjs';
2
+ import { m as resolveProjectRoot, v as cronMatches } from './run-C9PMX7NQ.mjs';
3
3
  import { l as listWorkflows, b as workflowCrons, w as workflowSteps } from './store-BPL__e4D.mjs';
4
4
  import 'os';
5
5
  import 'fs/promises';
@@ -23,9 +23,10 @@ import 'node:fs/promises';
23
23
  import 'node:util';
24
24
  import 'yaml';
25
25
 
26
- function defaultRunStep(root, command, log) {
26
+ function defaultRunStep(root, command, ownerSession, log) {
27
27
  try {
28
- const child = spawn("sh", ["-c", command], { cwd: root, detached: true, stdio: "ignore" });
28
+ const env = ownerSession ? { ...process.env, SVAMP_SESSION_ID: ownerSession } : process.env;
29
+ const child = spawn("sh", ["-c", command], { cwd: root, detached: true, stdio: "ignore", env });
29
30
  child.on("error", (e) => log?.(`[workflow] step spawn error in ${root}: ${e.message}`));
30
31
  child.unref();
31
32
  } catch (e) {
@@ -84,9 +85,10 @@ class WorkflowScheduler {
84
85
  }
85
86
  fire(root, wf) {
86
87
  const steps = workflowSteps(wf);
87
- this.deps.log?.(`[workflow] schedule fired "${wf.name}" (${steps.length} step${steps.length === 1 ? "" : "s"}) in ${root}`);
88
- const run = this.deps.runStep || ((r, c) => defaultRunStep(r, c, this.deps.log));
89
- for (const step of steps) run(root, step.run);
88
+ const owner = wf.session || null;
89
+ this.deps.log?.(`[workflow] schedule fired "${wf.name}" (${steps.length} step${steps.length === 1 ? "" : "s"}) in ${root}${owner ? ` as ${owner}` : ""}`);
90
+ const run = this.deps.runStep || ((r, c, o) => defaultRunStep(r, c, o, this.deps.log));
91
+ for (const step of steps) run(root, step.run, owner);
90
92
  }
91
93
  }
92
94
 
@@ -54,7 +54,7 @@ async function handleServeCommand() {
54
54
  }
55
55
  }
56
56
  async function serveAdd(args, machineId) {
57
- const { connectAndGetMachine } = await import('./commands-MjIkmrmC.mjs');
57
+ const { connectAndGetMachine } = await import('./commands-CL9hxClH.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-MjIkmrmC.mjs');
96
+ const { connectAndGetMachine } = await import('./commands-CL9hxClH.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-MjIkmrmC.mjs');
185
+ const { connectAndGetMachine } = await import('./commands-CL9hxClH.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-MjIkmrmC.mjs');
205
+ const { connectAndGetMachine } = await import('./commands-CL9hxClH.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-MjIkmrmC.mjs');
238
+ const { connectAndGetMachine } = await import('./commands-CL9hxClH.mjs');
239
239
  const { machine, server } = await connectAndGetMachine(machineId);
240
240
  try {
241
241
  const info = await machine.serveInfo();
@@ -4,7 +4,7 @@ import * as fs from 'fs';
4
4
  import * as http from 'http';
5
5
  import * as net from 'net';
6
6
  import * as path from 'path';
7
- import { k as getHyphaServerUrl, S as ServeAuth, l as hasCookieToken } from './run-B-1WDymr.mjs';
7
+ import { k as getHyphaServerUrl, S as ServeAuth, l as hasCookieToken } from './run-C9PMX7NQ.mjs';
8
8
  import 'os';
9
9
  import 'fs/promises';
10
10
  import 'url';
@@ -733,7 +733,7 @@ class ServeManager {
733
733
  const mount = this.mounts.get(mountName);
734
734
  const subdomainOverride = mount?.access === "link" && mount.linkToken ? /* @__PURE__ */ new Map([[this.port, buildLinkSubdomain(subdomainSafe, mount.linkToken)]]) : void 0;
735
735
  try {
736
- const { FrpcTunnel } = await import('./frpc-D4x74mG6.mjs');
736
+ const { FrpcTunnel } = await import('./frpc-CLJ1PNTL.mjs');
737
737
  let tunnel;
738
738
  tunnel = new FrpcTunnel({
739
739
  name: tunnelName,
@@ -1,4 +1,4 @@
1
- import { R as READ_ONLY_TOOLS, y as loadMachineContext, z as buildMachineInstructions, A as machineToolsForRole, B as buildMachineTools } from './run-B-1WDymr.mjs';
1
+ import { R as READ_ONLY_TOOLS, y as loadMachineContext, z as buildMachineInstructions, A as machineToolsForRole, B as buildMachineTools } from './run-C9PMX7NQ.mjs';
2
2
  import 'node:child_process';
3
3
  import 'os';
4
4
  import 'fs/promises';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svamp-cli",
3
- "version": "0.2.178",
3
+ "version": "0.2.180",
4
4
  "description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
5
5
  "author": "Amun AI AB",
6
6
  "license": "SEE LICENSE IN LICENSE",