svamp-cli 0.2.309 → 0.2.311
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{adminCommands-BTLHQXmA.mjs → adminCommands-U5D7i8tD.mjs} +1 -1
- package/dist/{agentCommands-DdNUACV8.mjs → agentCommands-BefFTl6g.mjs} +5 -5
- package/dist/{auth-Bn8TbaOP.mjs → auth-DgGAjihq.mjs} +1 -1
- package/dist/{cli-BaDWWDiz.mjs → cli-B0TyKXyU.mjs} +70 -70
- package/dist/cli.mjs +2 -2
- package/dist/{commands-Bb0oF3eZ.mjs → commands-BCQbBzYU.mjs} +2 -2
- package/dist/{commands-BTN9XxVx.mjs → commands-BoGUxb2o.mjs} +1 -1
- package/dist/{commands-C2u988x1.mjs → commands-CEOhve0Y.mjs} +2 -2
- package/dist/{commands-DGbLwT_h.mjs → commands-CjVl4amM.mjs} +8 -8
- package/dist/{commands-2uOorIjB.mjs → commands-CnqL60f7.mjs} +1 -1
- package/dist/{commands-DPvy0iVT.mjs → commands-XQ8-fOSu.mjs} +1 -1
- package/dist/{commands-BPgxgkXW.mjs → commands-imLC7CK2.mjs} +2 -2
- package/dist/{commands-r86haNJD.mjs → commands-xoalqGUY.mjs} +2 -2
- package/dist/{fleet-CeLE0t97.mjs → fleet-BS5eS0Wz.mjs} +2 -2
- package/dist/{frpc-Cv6J2Mex.mjs → frpc-DvBVvsZC.mjs} +1 -1
- package/dist/{headlessCli-BXc9Fvzb.mjs → headlessCli-C9wTLm1x.mjs} +2 -2
- package/dist/index.mjs +1 -1
- package/dist/{notifyCommands-iVnI_Lb2.mjs → notifyCommands-0IltLO-S.mjs} +1 -1
- package/dist/package-CFhmZcVJ.mjs +64 -0
- package/dist/{pinnedClaudeCode-C6MSkqS9.mjs → pinnedClaudeCode-zDzkOTi2.mjs} +1 -1
- package/dist/{rpc-CkcBAtcs.mjs → rpc-BLWr4p8g.mjs} +1 -1
- package/dist/{rpc-BwxwusfB.mjs → rpc-BXpuORiQ.mjs} +1 -1
- package/dist/{run-2Stz5l7J.mjs → run-CMoQtnIj.mjs} +1 -1
- package/dist/{run-DLG-_xa7.mjs → run-DtVX2pQN.mjs} +127 -55
- package/dist/{scheduler-CurN4UtP.mjs → scheduler-7aLvf5mn.mjs} +1 -1
- package/dist/{serveCommands-CtVZhR-V.mjs → serveCommands-D7BieIJ5.mjs} +19 -12
- package/dist/{sideband-C_3PVGh-.mjs → sideband-DjjXlVhw.mjs} +1 -1
- package/package.json +2 -2
- package/dist/package-CeseSmYI.mjs +0 -64
|
@@ -2379,10 +2379,8 @@ class ServeManager {
|
|
|
2379
2379
|
*/
|
|
2380
2380
|
listMounts(sessionId) {
|
|
2381
2381
|
const all = Array.from(this.mounts.values());
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
}
|
|
2385
|
-
return all;
|
|
2382
|
+
const filtered = sessionId ? all.filter((m) => m.sessionId === sessionId) : all;
|
|
2383
|
+
return filtered.map((m) => ({ ...m, url: this.getMountUrl(m.name) || void 0 }));
|
|
2386
2384
|
}
|
|
2387
2385
|
/** #0649: look up a single mount by name (for ownership checks before remove/replace). */
|
|
2388
2386
|
getMount(name) {
|
|
@@ -2393,10 +2391,8 @@ class ServeManager {
|
|
|
2393
2391
|
*/
|
|
2394
2392
|
getInfo() {
|
|
2395
2393
|
const running = this.proxyServer != null;
|
|
2396
|
-
const firstMount = this.mounts.values().next().value;
|
|
2397
|
-
const firstUrl = firstMount ? this.getMountUrl(firstMount.name) : null;
|
|
2398
2394
|
return {
|
|
2399
|
-
url:
|
|
2395
|
+
url: null,
|
|
2400
2396
|
port: running ? this.port : 0,
|
|
2401
2397
|
authProxyPort: running ? this.port : 0,
|
|
2402
2398
|
running,
|
|
@@ -3151,7 +3147,7 @@ Connection: close\r
|
|
|
3151
3147
|
const mount = this.mounts.get(mountName);
|
|
3152
3148
|
const subdomainOverride = mount?.access === "link" && mount.linkToken ? /* @__PURE__ */ new Map([[this.port, buildLinkSubdomain(subdomainSafe, mount.linkToken)]]) : void 0;
|
|
3153
3149
|
try {
|
|
3154
|
-
const { FrpcTunnel } = await import('./frpc-
|
|
3150
|
+
const { FrpcTunnel } = await import('./frpc-DvBVvsZC.mjs');
|
|
3155
3151
|
let tunnel;
|
|
3156
3152
|
tunnel = new FrpcTunnel({
|
|
3157
3153
|
name: tunnelName,
|
|
@@ -4093,7 +4089,8 @@ function inZone(date, tz) {
|
|
|
4093
4089
|
o[x.type] = x.value;
|
|
4094
4090
|
return o;
|
|
4095
4091
|
}, {});
|
|
4096
|
-
|
|
4092
|
+
const midnight24 = p.hour === "24";
|
|
4093
|
+
return new Date(+p.year, +p.month - 1, +p.day + (midnight24 ? 1 : 0), midnight24 ? 0 : +p.hour, +p.minute);
|
|
4097
4094
|
} catch {
|
|
4098
4095
|
return date;
|
|
4099
4096
|
}
|
|
@@ -4926,10 +4923,16 @@ class ChannelOutbox {
|
|
|
4926
4923
|
this.emitter.on(channelId, onReply);
|
|
4927
4924
|
});
|
|
4928
4925
|
}
|
|
4929
|
-
/**
|
|
4930
|
-
|
|
4926
|
+
/**
|
|
4927
|
+
* Push subscription for SSE: calls onReply for each new matching reply.
|
|
4928
|
+
* Same key rule as since()/wait(): correlationId-first (knowing the unguessable reply
|
|
4929
|
+
* key proves ownership of that conversation), identity (`to`) only as the fallback.
|
|
4930
|
+
* Without this, several callers sharing a `to` (e.g. caller-supplied/'anonymous'
|
|
4931
|
+
* senders) would receive each other's replies — the cross-caller leak class of #0786.
|
|
4932
|
+
*/
|
|
4933
|
+
subscribe(channelId, to, onReply, correlationId) {
|
|
4931
4934
|
const handler = (r) => {
|
|
4932
|
-
if (r.to === to) onReply(r);
|
|
4935
|
+
if (correlationId ? r.correlationId === correlationId : r.to === to) onReply(r);
|
|
4933
4936
|
};
|
|
4934
4937
|
this.emitter.on(channelId, handler);
|
|
4935
4938
|
return () => this.emitter.off(channelId, handler);
|
|
@@ -5020,6 +5023,17 @@ const SESSION_VIEW_METHODS = /* @__PURE__ */ new Set([
|
|
|
5020
5023
|
"reregister",
|
|
5021
5024
|
"recordMeetingActivity"
|
|
5022
5025
|
]);
|
|
5026
|
+
const MACHINE_MEMBER_READABLE = /* @__PURE__ */ new Set([
|
|
5027
|
+
"getMetadata",
|
|
5028
|
+
"getAgentState",
|
|
5029
|
+
"getActivityState",
|
|
5030
|
+
"getMessages",
|
|
5031
|
+
"getLatestMessages",
|
|
5032
|
+
"getMessageCount",
|
|
5033
|
+
"getSharing",
|
|
5034
|
+
"listChannels",
|
|
5035
|
+
"registerListener"
|
|
5036
|
+
]);
|
|
5023
5037
|
function sessionMethodMinRole(method) {
|
|
5024
5038
|
const mapped = SESSION_METHOD_MIN_ROLE[method];
|
|
5025
5039
|
if (mapped) return mapped;
|
|
@@ -5362,11 +5376,12 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
5362
5376
|
const rpc = handlers.getSessionRPCHandlers?.(sid);
|
|
5363
5377
|
if (!rpc) continue;
|
|
5364
5378
|
if (!hasMachineAccess && !await hasExplicitSessionAccess(rpc, "view", context)) continue;
|
|
5379
|
+
const readCtx = hasMachineAccess ? void 0 : context;
|
|
5365
5380
|
try {
|
|
5366
5381
|
const [metaResult, stateResult, activity] = await Promise.all([
|
|
5367
|
-
rpc.getMetadata(
|
|
5368
|
-
rpc.getAgentState(
|
|
5369
|
-
rpc.getActivityState(
|
|
5382
|
+
rpc.getMetadata(readCtx),
|
|
5383
|
+
rpc.getAgentState(readCtx),
|
|
5384
|
+
rpc.getActivityState(readCtx).catch(() => ({
|
|
5370
5385
|
active: false,
|
|
5371
5386
|
thinking: false,
|
|
5372
5387
|
time: Date.now()
|
|
@@ -5382,7 +5397,10 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
5382
5397
|
thinking: activity.thinking ?? false,
|
|
5383
5398
|
activeAt: activity.time || Date.now()
|
|
5384
5399
|
});
|
|
5385
|
-
} catch {
|
|
5400
|
+
} catch (err) {
|
|
5401
|
+
console.debug(
|
|
5402
|
+
`[HYPHA MACHINE] getSessions: skipped session ${sid} (${hasMachineAccess ? "machine-access" : "session-shared"}): ${err?.message ?? err}`
|
|
5403
|
+
);
|
|
5386
5404
|
}
|
|
5387
5405
|
}
|
|
5388
5406
|
return sessions;
|
|
@@ -5402,8 +5420,10 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
5402
5420
|
throw new Error(`Session ${sessionId} not found on this machine`);
|
|
5403
5421
|
}
|
|
5404
5422
|
const requiredRole = sessionMethodMinRole(method);
|
|
5423
|
+
let machineAuthorized = false;
|
|
5405
5424
|
try {
|
|
5406
5425
|
authorizeRequest(context, currentMetadata.sharing, requiredRole);
|
|
5426
|
+
machineAuthorized = true;
|
|
5407
5427
|
} catch (machineErr) {
|
|
5408
5428
|
if (!await hasExplicitSessionAccess(rpc, requiredRole, context)) throw machineErr;
|
|
5409
5429
|
}
|
|
@@ -5411,9 +5431,10 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
5411
5431
|
if (typeof handler !== "function") {
|
|
5412
5432
|
throw new Error(`Unknown session method: ${method}`);
|
|
5413
5433
|
}
|
|
5434
|
+
const dispatchCtx = machineAuthorized && MACHINE_MEMBER_READABLE.has(method) ? void 0 : context;
|
|
5414
5435
|
const paramNames = getParamNames(handler);
|
|
5415
5436
|
const callArgs = paramNames.map(
|
|
5416
|
-
(name) => name === "context" ?
|
|
5437
|
+
(name) => name === "context" ? dispatchCtx : kwargs?.[name] ?? void 0
|
|
5417
5438
|
);
|
|
5418
5439
|
return await handler(...callArgs);
|
|
5419
5440
|
},
|
|
@@ -5427,14 +5448,16 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
5427
5448
|
if (!rpc) {
|
|
5428
5449
|
throw new Error(`Session ${sessionId} not found on this machine`);
|
|
5429
5450
|
}
|
|
5451
|
+
let machineAuthorized = false;
|
|
5430
5452
|
try {
|
|
5431
5453
|
authorizeRequest(context, currentMetadata.sharing, "view");
|
|
5454
|
+
machineAuthorized = true;
|
|
5432
5455
|
} catch (machineErr) {
|
|
5433
5456
|
if (!await hasExplicitSessionAccess(rpc, "view", context)) {
|
|
5434
5457
|
throw machineErr;
|
|
5435
5458
|
}
|
|
5436
5459
|
}
|
|
5437
|
-
return await rpc.registerListener(callback, context);
|
|
5460
|
+
return await rpc.registerListener(callback, machineAuthorized ? void 0 : context);
|
|
5438
5461
|
},
|
|
5439
5462
|
// Spawn a new session
|
|
5440
5463
|
spawnSession: async (options, context) => {
|
|
@@ -5810,9 +5833,11 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
5810
5833
|
const { exec } = await import('child_process');
|
|
5811
5834
|
const { homedir } = await import('os');
|
|
5812
5835
|
return new Promise((resolve) => {
|
|
5813
|
-
exec(command, { cwd: cwd || homedir(), timeout: 3e4, maxBuffer: 1024 * 1024 }, (err, stdout, stderr) => {
|
|
5836
|
+
exec(command, { cwd: cwd || homedir(), timeout: 3e4, maxBuffer: 16 * 1024 * 1024 }, (err, stdout, stderr) => {
|
|
5814
5837
|
if (err) {
|
|
5815
|
-
|
|
5838
|
+
const enobufs = err.code === "ENOBUFS";
|
|
5839
|
+
const errText = enobufs ? `output exceeded the 16 MB buffer and was truncated (the command may have completed): ${stderr || err.message}` : stderr || err.message;
|
|
5840
|
+
resolve({ success: false, stdout: stdout || "", stderr: errText, exitCode: err.code ?? 1 });
|
|
5816
5841
|
} else {
|
|
5817
5842
|
resolve({ success: true, stdout, stderr: stderr || "", exitCode: 0 });
|
|
5818
5843
|
}
|
|
@@ -5823,6 +5848,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
5823
5848
|
/** Start a new terminal PTY session. Returns { sessionId, cols, rows }. */
|
|
5824
5849
|
terminalStart: async (params = {}, context) => {
|
|
5825
5850
|
authorizeRequest(context, currentMetadata.sharing, "admin");
|
|
5851
|
+
const terminalClient = context?.from;
|
|
5826
5852
|
const pty = await getPtyModule();
|
|
5827
5853
|
const { homedir: getHomedir } = await import('os');
|
|
5828
5854
|
const cols = params.cols || 80;
|
|
@@ -5877,7 +5903,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
5877
5903
|
server.emit({
|
|
5878
5904
|
type: "svamp:terminal-output",
|
|
5879
5905
|
data: { type: "output", content: batch, sessionId },
|
|
5880
|
-
to: "*"
|
|
5906
|
+
to: terminalClient ?? "*"
|
|
5881
5907
|
});
|
|
5882
5908
|
} catch {
|
|
5883
5909
|
}
|
|
@@ -5896,7 +5922,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
5896
5922
|
server.emit({
|
|
5897
5923
|
type: "svamp:terminal-output",
|
|
5898
5924
|
data: { type: "exit", content: "", sessionId, exitCode, signal },
|
|
5899
|
-
to: "*"
|
|
5925
|
+
to: terminalClient ?? "*"
|
|
5900
5926
|
});
|
|
5901
5927
|
} catch {
|
|
5902
5928
|
}
|
|
@@ -6254,7 +6280,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
6254
6280
|
const tunnels = handlers.tunnels;
|
|
6255
6281
|
if (!tunnels) throw new Error("Tunnel management not available");
|
|
6256
6282
|
if (tunnels.has(params.name)) throw new Error(`Tunnel '${params.name}' already running`);
|
|
6257
|
-
const { FrpcTunnel } = await import('./frpc-
|
|
6283
|
+
const { FrpcTunnel } = await import('./frpc-DvBVvsZC.mjs');
|
|
6258
6284
|
const tunnel = new FrpcTunnel({
|
|
6259
6285
|
name: params.name,
|
|
6260
6286
|
ports: params.ports,
|
|
@@ -6421,8 +6447,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
6421
6447
|
const info = sm.getInfo();
|
|
6422
6448
|
const isAdmin = serveCallerTrusted(context);
|
|
6423
6449
|
const mounts = (info.mounts || []).map((m) => sanitizeMountForRole(m, isAdmin));
|
|
6424
|
-
|
|
6425
|
-
return { ...info, url: topUrl, mounts };
|
|
6450
|
+
return { ...info, url: null, mounts };
|
|
6426
6451
|
},
|
|
6427
6452
|
/**
|
|
6428
6453
|
* Aggregate frpc tunnel health for all serve mounts.
|
|
@@ -6748,7 +6773,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
6748
6773
|
}
|
|
6749
6774
|
const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
|
|
6750
6775
|
const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
|
|
6751
|
-
const { toolsForRole } = await import('./sideband-
|
|
6776
|
+
const { toolsForRole } = await import('./sideband-DjjXlVhw.mjs');
|
|
6752
6777
|
const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
|
|
6753
6778
|
return fmt(r2);
|
|
6754
6779
|
}
|
|
@@ -6853,7 +6878,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
6853
6878
|
return { ok: false, call_id: callId, status: "busy", error: "channel is busy (too many concurrent requests) \u2014 retry shortly" };
|
|
6854
6879
|
}
|
|
6855
6880
|
const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
|
|
6856
|
-
const { queryCore } = await import('./commands-
|
|
6881
|
+
const { queryCore } = await import('./commands-BoGUxb2o.mjs');
|
|
6857
6882
|
const timeout = c.reply?.timeout_sec || 120;
|
|
6858
6883
|
let result;
|
|
6859
6884
|
try {
|
|
@@ -8891,7 +8916,7 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
|
|
|
8891
8916
|
const ownerCtx = ownerEmail ? { user: { email: ownerEmail, id: ownerEmail } } : void 0;
|
|
8892
8917
|
try {
|
|
8893
8918
|
if (c.system && c.action?.kind !== "agent") {
|
|
8894
|
-
const role = ownerEmail && r.sender.name.toLowerCase() === ownerEmail.toLowerCase() ? "owner" : "collaborator";
|
|
8919
|
+
const role = r.sender.verified && ownerEmail && r.sender.name.toLowerCase() === ownerEmail.toLowerCase() ? "owner" : "collaborator";
|
|
8895
8920
|
const envelope = renderMessage(c, {
|
|
8896
8921
|
sender: r.sender,
|
|
8897
8922
|
body: { message: params.message },
|
|
@@ -15219,6 +15244,7 @@ function runsFile(projectRoot, workflow) {
|
|
|
15219
15244
|
const safe = workflow.replace(/[^\w.-]+/g, "_");
|
|
15220
15245
|
return join$1(runsDir(projectRoot), `${safe}.jsonl`);
|
|
15221
15246
|
}
|
|
15247
|
+
let _runSeq = 0;
|
|
15222
15248
|
function shortRunId(seed) {
|
|
15223
15249
|
let h = 2166136261;
|
|
15224
15250
|
for (let i = 0; i < seed.length; i++) {
|
|
@@ -15444,7 +15470,7 @@ async function runWorkflowInner(projectRoot, wf, opts) {
|
|
|
15444
15470
|
});
|
|
15445
15471
|
const exec = opts.execStep || defaultExecStep;
|
|
15446
15472
|
const start = now();
|
|
15447
|
-
const id = shortRunId(`${wf.name}:${start.iso}:${start.ms}`);
|
|
15473
|
+
const id = shortRunId(`${wf.name}:${start.iso}:${start.ms}:${_runSeq++}`);
|
|
15448
15474
|
const env = wf.session ? { ...process.env, SVAMP_SESSION_ID: wf.session } : process.env;
|
|
15449
15475
|
const run = {
|
|
15450
15476
|
id,
|
|
@@ -16332,6 +16358,28 @@ async function writeSessionFileChunk(directory, sessionMetadata, path, content,
|
|
|
16332
16358
|
}
|
|
16333
16359
|
}
|
|
16334
16360
|
|
|
16361
|
+
function isStdinWritable(proc) {
|
|
16362
|
+
if (!proc || proc.exitCode !== null) return false;
|
|
16363
|
+
const stdin = proc.stdin;
|
|
16364
|
+
if (!stdin) return false;
|
|
16365
|
+
if (stdin.destroyed === true) return false;
|
|
16366
|
+
if (stdin.writable === false) return false;
|
|
16367
|
+
return true;
|
|
16368
|
+
}
|
|
16369
|
+
function serializeUserFrame(text) {
|
|
16370
|
+
return JSON.stringify({ type: "user", message: { role: "user", content: text } }) + "\n";
|
|
16371
|
+
}
|
|
16372
|
+
function writeUserFrame(proc, text, onError) {
|
|
16373
|
+
if (!isStdinWritable(proc)) return false;
|
|
16374
|
+
try {
|
|
16375
|
+
proc.stdin.write(serializeUserFrame(text));
|
|
16376
|
+
return true;
|
|
16377
|
+
} catch (err) {
|
|
16378
|
+
onError?.(err);
|
|
16379
|
+
return false;
|
|
16380
|
+
}
|
|
16381
|
+
}
|
|
16382
|
+
|
|
16335
16383
|
const __filename$1 = fileURLToPath(import.meta.url);
|
|
16336
16384
|
const __dirname$1 = dirname$1(__filename$1);
|
|
16337
16385
|
const CLAUDE_SKILLS_DIR = join(os$1.homedir(), ".claude", "skills");
|
|
@@ -17206,7 +17254,7 @@ function createSvampConfigChecker(directory, sessionId, getMetadata, setMetadata
|
|
|
17206
17254
|
const gaveUpCfg = readLoopJson(directory, sessionId, "loop.config.json") || {};
|
|
17207
17255
|
const curMax = typeof gaveUpCfg.max_iterations === "number" ? gaveUpCfg.max_iterations : iter;
|
|
17208
17256
|
const nextMax = Math.max(curMax * 2, iter + 10);
|
|
17209
|
-
const msg = s.phase === "done" ? `\u{1F501} Loop complete \u2705 \u2014 finished after ${iter} iteration${plural}.` : `\u{1F501} Loop paused \u{1F6D1} \u2014 did NOT finish after ${iter} iteration${plural}${s.gave_up_reason ? ` (${s.gave_up_reason})` : ""}. Resume & extend with: svamp session loop-
|
|
17257
|
+
const msg = s.phase === "done" ? `\u{1F501} Loop complete \u2705 \u2014 finished after ${iter} iteration${plural}.` : `\u{1F501} Loop paused \u{1F6D1} \u2014 did NOT finish after ${iter} iteration${plural}${s.gave_up_reason ? ` (${s.gave_up_reason})` : ""}. Resume & extend with: svamp session loop-extend ${sessionId} --reason "<why more turns are needed>" --turns ${Math.max(10, nextMax - iter)}`;
|
|
17210
17258
|
sessionService.pushMessage(
|
|
17211
17259
|
s.phase === "gave_up" ? { type: "message", message: msg, level: "warning" } : { type: "message", message: msg },
|
|
17212
17260
|
"event"
|
|
@@ -17275,7 +17323,7 @@ function createSvampConfigChecker(directory, sessionId, getMetadata, setMetadata
|
|
|
17275
17323
|
maxExtensions
|
|
17276
17324
|
});
|
|
17277
17325
|
if (!grant.granted) {
|
|
17278
|
-
sessionService.pushMessage({ type: "message", message: `\u{1F6D1} Extension refused \u2014 this loop already used all ${grant.max} allowed extension${grant.max === 1 ? "" : "s"} (${grant.used}/${grant.max}). A hard cap is a hard cap; do the remaining work or raise the limit manually: svamp session loop-
|
|
17326
|
+
sessionService.pushMessage({ type: "message", message: `\u{1F6D1} Extension refused \u2014 this loop already used all ${grant.max} allowed extension${grant.max === 1 ? "" : "s"} (${grant.used}/${grant.max}). A hard cap is a hard cap; do the remaining work or raise the limit manually: svamp session loop-extend ${sessionId} --reason "<why>" --turns <N>`, level: "warning" }, "event");
|
|
17279
17327
|
logger.log(`[svampConfig] loop-extend refused (bounded ${grant.used}/${grant.max})`);
|
|
17280
17328
|
} else {
|
|
17281
17329
|
const wasStopped = existing.active === false || existing.phase === "done" || existing.phase === "gave_up" || existing.phase === "cancelled";
|
|
@@ -17829,7 +17877,7 @@ async function startDaemon(options) {
|
|
|
17829
17877
|
try {
|
|
17830
17878
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
17831
17879
|
if (!dir) return;
|
|
17832
|
-
const { reconcileServiceLinks } = await import('./agentCommands-
|
|
17880
|
+
const { reconcileServiceLinks } = await import('./agentCommands-BefFTl6g.mjs');
|
|
17833
17881
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
17834
17882
|
const config = readSvampConfig(configPath);
|
|
17835
17883
|
const entries = Array.from(urls.entries());
|
|
@@ -17847,7 +17895,7 @@ async function startDaemon(options) {
|
|
|
17847
17895
|
}
|
|
17848
17896
|
}
|
|
17849
17897
|
async function createExposedTunnel(spec) {
|
|
17850
|
-
const { FrpcTunnel } = await import('./frpc-
|
|
17898
|
+
const { FrpcTunnel } = await import('./frpc-DvBVvsZC.mjs');
|
|
17851
17899
|
const tunnel = new FrpcTunnel({
|
|
17852
17900
|
name: spec.name,
|
|
17853
17901
|
ports: spec.ports,
|
|
@@ -17875,7 +17923,7 @@ async function startDaemon(options) {
|
|
|
17875
17923
|
ensureAutoInstalledCommands(logger);
|
|
17876
17924
|
(async () => {
|
|
17877
17925
|
try {
|
|
17878
|
-
const { beginClaudeVersionReconcile } = await import('./pinnedClaudeCode-
|
|
17926
|
+
const { beginClaudeVersionReconcile } = await import('./pinnedClaudeCode-zDzkOTi2.mjs');
|
|
17879
17927
|
beginClaudeVersionReconcile((msg) => logger.log(msg));
|
|
17880
17928
|
} catch (e) {
|
|
17881
17929
|
logger.log(`[claude-version] check failed: ${e?.message || e}`);
|
|
@@ -19194,7 +19242,7 @@ ${parts.join("\n")}`);
|
|
|
19194
19242
|
auto_resumes: prog.auto_resumes
|
|
19195
19243
|
});
|
|
19196
19244
|
const extNote = summarizeExtensions(ls.extensions, maxExt);
|
|
19197
|
-
const resumeHint = iterStop ? `Extend with a reason: svamp session loop-extend ${sessionId} --reason "<why>"
|
|
19245
|
+
const resumeHint = iterStop ? `Extend with a reason: svamp session loop-extend ${sessionId} --reason "<why>" [--turns <N>]` : `Raise the cost cap to resume (--max won't \u2014 it only raises the iteration cap): svamp session loop ${sessionId} --max-runtime-sec <N> and/or --max-tokens-per-hour <N>`;
|
|
19198
19246
|
const detail = `${budgetCheck.reason} (hard ${iterStop ? "iteration ceiling" : "cost ceiling"} \u2014 will not auto-resume)${extNote ? ` [${extNote}]` : ""}. ${resumeHint}`;
|
|
19199
19247
|
sessionService.pushMessage({ type: "message", message: `\u{1F6D1} Loop stopped \u2014 ${detail}`, level: "warning" }, "event");
|
|
19200
19248
|
checkSvampConfig?.();
|
|
@@ -19446,6 +19494,9 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
19446
19494
|
}
|
|
19447
19495
|
return child;
|
|
19448
19496
|
};
|
|
19497
|
+
const writeUserFrameToClaude = (text) => writeUserFrame(claudeProcess, text, (err) => {
|
|
19498
|
+
logger.log(`[Session ${sessionId}] Claude stdin write failed: ${err?.message || err}`);
|
|
19499
|
+
});
|
|
19449
19500
|
const restartClaudeHandler = async (opts) => {
|
|
19450
19501
|
logger.log(`[Session ${sessionId}] Restart Claude requested`);
|
|
19451
19502
|
if (isRestartingClaude || isSwitchingMode) {
|
|
@@ -19484,6 +19535,9 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
19484
19535
|
spawnClaude(void 0, { permissionMode: currentPermissionMode });
|
|
19485
19536
|
sessionService.updateMetadata(sessionMetadata);
|
|
19486
19537
|
logger.log(`[Session ${sessionId}] Claude respawned with --resume ${claudeResumeId}`);
|
|
19538
|
+
if ((sessionMetadata.messageQueue?.length ?? 0) > 0 && !trackedSession?.stopped) {
|
|
19539
|
+
setTimeout(() => processMessageQueueRef?.(), 300);
|
|
19540
|
+
}
|
|
19487
19541
|
if (beforeRespawnError) {
|
|
19488
19542
|
return { success: false, message: `Edit failed (session restored): ${beforeRespawnError}` };
|
|
19489
19543
|
}
|
|
@@ -19708,15 +19762,26 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
19708
19762
|
pendingCompactTurn = isCompactCommand(text);
|
|
19709
19763
|
if (!claudeProcess || claudeProcess.exitCode !== null) {
|
|
19710
19764
|
spawnClaude(text, msgMeta);
|
|
19765
|
+
signalProcessing(true);
|
|
19766
|
+
sessionWasProcessing = true;
|
|
19767
|
+
} else if (writeUserFrameToClaude(text)) {
|
|
19768
|
+
signalProcessing(true);
|
|
19769
|
+
sessionWasProcessing = true;
|
|
19711
19770
|
} else {
|
|
19712
|
-
|
|
19713
|
-
|
|
19714
|
-
|
|
19715
|
-
|
|
19716
|
-
|
|
19771
|
+
logger.log(`[Session ${sessionId}] Claude stdin unwritable \u2014 requeueing message for respawn delivery`);
|
|
19772
|
+
const existingQueue = sessionMetadata.messageQueue || [];
|
|
19773
|
+
sessionMetadata = {
|
|
19774
|
+
...sessionMetadata,
|
|
19775
|
+
messageQueue: [...existingQueue, { id: randomUUID$1(), text, createdAt: Date.now(), alreadyStored: true }]
|
|
19776
|
+
};
|
|
19777
|
+
sessionService.updateMetadata(sessionMetadata);
|
|
19778
|
+
signalProcessing(true);
|
|
19779
|
+
sessionWasProcessing = true;
|
|
19780
|
+
try {
|
|
19781
|
+
claudeProcess.kill("SIGTERM");
|
|
19782
|
+
} catch {
|
|
19783
|
+
}
|
|
19717
19784
|
}
|
|
19718
|
-
signalProcessing(true);
|
|
19719
|
-
sessionWasProcessing = true;
|
|
19720
19785
|
},
|
|
19721
19786
|
onAbort: () => {
|
|
19722
19787
|
logger.log(`[Session ${sessionId}] Abort requested`);
|
|
@@ -19818,6 +19883,9 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
19818
19883
|
isKillingClaude = false;
|
|
19819
19884
|
if (trackedSession?.stopped) return;
|
|
19820
19885
|
spawnClaude(void 0, { permissionMode: normalizedMode });
|
|
19886
|
+
if ((sessionMetadata.messageQueue?.length ?? 0) > 0 && !trackedSession?.stopped) {
|
|
19887
|
+
setTimeout(() => processMessageQueueRef?.(), 300);
|
|
19888
|
+
}
|
|
19821
19889
|
} finally {
|
|
19822
19890
|
isKillingClaude = false;
|
|
19823
19891
|
isSwitchingMode = false;
|
|
@@ -20081,11 +20149,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
20081
20149
|
});
|
|
20082
20150
|
},
|
|
20083
20151
|
onIssue: async (params) => {
|
|
20084
|
-
const { issueRpc } = await import('./rpc-
|
|
20152
|
+
const { issueRpc } = await import('./rpc-BLWr4p8g.mjs');
|
|
20085
20153
|
return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
|
|
20086
20154
|
},
|
|
20087
20155
|
onWorkflow: async (params) => {
|
|
20088
|
-
const { workflowRpc } = await import('./rpc-
|
|
20156
|
+
const { workflowRpc } = await import('./rpc-BXpuORiQ.mjs');
|
|
20089
20157
|
return workflowRpc(params?.cwd || directory, params || {});
|
|
20090
20158
|
},
|
|
20091
20159
|
onRipgrep: async (args, cwd) => {
|
|
@@ -20231,12 +20299,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
20231
20299
|
try {
|
|
20232
20300
|
if (!claudeProcess || claudeProcess.exitCode !== null) {
|
|
20233
20301
|
spawnClaude(next.text);
|
|
20234
|
-
} else {
|
|
20235
|
-
const stdinMsg = JSON.stringify({
|
|
20236
|
-
type: "user",
|
|
20237
|
-
message: { role: "user", content: next.text }
|
|
20238
|
-
});
|
|
20239
|
-
claudeProcess.stdin?.write(stdinMsg + "\n");
|
|
20302
|
+
} else if (writeUserFrameToClaude(next.text)) {
|
|
20240
20303
|
if (claudeResumeId && !trackedSession?.stopped) {
|
|
20241
20304
|
saveSession({
|
|
20242
20305
|
sessionId,
|
|
@@ -20250,6 +20313,15 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
20250
20313
|
wasProcessing: true
|
|
20251
20314
|
});
|
|
20252
20315
|
}
|
|
20316
|
+
} else {
|
|
20317
|
+
logger.log(`[Session ${sessionId}] Claude stdin unwritable during queue drain \u2014 restoring head + respawning`);
|
|
20318
|
+
sessionMetadata = { ...sessionMetadata, messageQueue: [next, ...remaining] };
|
|
20319
|
+
sessionService.updateMetadata(sessionMetadata);
|
|
20320
|
+
sessionWasProcessing = false;
|
|
20321
|
+
try {
|
|
20322
|
+
claudeProcess.kill("SIGTERM");
|
|
20323
|
+
} catch {
|
|
20324
|
+
}
|
|
20253
20325
|
}
|
|
20254
20326
|
} catch (err) {
|
|
20255
20327
|
logger.log(`[Session ${sessionId}] Error in processMessageQueue spawn: ${err.message}`);
|
|
@@ -20755,11 +20827,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
20755
20827
|
});
|
|
20756
20828
|
},
|
|
20757
20829
|
onIssue: async (params) => {
|
|
20758
|
-
const { issueRpc } = await import('./rpc-
|
|
20830
|
+
const { issueRpc } = await import('./rpc-BLWr4p8g.mjs');
|
|
20759
20831
|
return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
|
|
20760
20832
|
},
|
|
20761
20833
|
onWorkflow: async (params) => {
|
|
20762
|
-
const { workflowRpc } = await import('./rpc-
|
|
20834
|
+
const { workflowRpc } = await import('./rpc-BXpuORiQ.mjs');
|
|
20763
20835
|
return workflowRpc(params?.cwd || directory, params || {});
|
|
20764
20836
|
},
|
|
20765
20837
|
onRipgrep: async (args, cwd) => {
|
|
@@ -21089,7 +21161,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
21089
21161
|
const iterStop = !isCostCeiling(budgetCheck.kind);
|
|
21090
21162
|
writeGoalLoopState(directory, sessionId, { ...ls, active: false, phase: "gave_up", completed_at: now, gave_up_reason: `resource budget exhausted \u2014 ${budgetCheck.reason}`, ledger });
|
|
21091
21163
|
const acpExtNote = summarizeExtensions(ls.extensions, acpMaxExt);
|
|
21092
|
-
const acpResumeHint = iterStop ? `Extend with a reason: svamp session loop-extend ${sessionId} --reason "<why>"
|
|
21164
|
+
const acpResumeHint = iterStop ? `Extend with a reason: svamp session loop-extend ${sessionId} --reason "<why>" [--turns <N>]` : `Raise the cost cap to resume (--max won't \u2014 it only raises the iteration cap): svamp session loop ${sessionId} --max-runtime-sec <N> and/or --max-tokens-per-hour <N>`;
|
|
21093
21165
|
sessionService.pushMessage({ type: "message", message: `\u{1F6D1} Loop stopped \u2014 ${budgetCheck.reason} (hard ${iterStop ? "iteration ceiling" : "cost ceiling"} \u2014 will not auto-resume)${acpExtNote ? ` [${acpExtNote}]` : ""}. ${acpResumeHint}`, level: "warning" }, "event");
|
|
21094
21166
|
checkSvampConfig?.();
|
|
21095
21167
|
return;
|
|
@@ -21717,7 +21789,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
21717
21789
|
}
|
|
21718
21790
|
if (persistedSessions.length > 0) {
|
|
21719
21791
|
try {
|
|
21720
|
-
const { awaitClaudeVersionReady } = await import('./pinnedClaudeCode-
|
|
21792
|
+
const { awaitClaudeVersionReady } = await import('./pinnedClaudeCode-zDzkOTi2.mjs');
|
|
21721
21793
|
await awaitClaudeVersionReady();
|
|
21722
21794
|
} catch {
|
|
21723
21795
|
}
|
|
@@ -21922,7 +21994,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
21922
21994
|
const PING_TIMEOUT_MS = 15e3;
|
|
21923
21995
|
const POST_RECONNECT_GRACE_MS = 2e4;
|
|
21924
21996
|
const RECONNECT_JITTER_MS = 2500;
|
|
21925
|
-
const { WorkflowScheduler } = await import('./scheduler-
|
|
21997
|
+
const { WorkflowScheduler } = await import('./scheduler-7aLvf5mn.mjs');
|
|
21926
21998
|
const workflowProjectRoots = () => {
|
|
21927
21999
|
const dirs = /* @__PURE__ */ new Set();
|
|
21928
22000
|
for (const s of pidToTrackedSession.values()) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { j as resolveProjectRoot, E as listWorkflows, F as isWorkflowEnabled, G as workflowSchedules, H as inZone, y as runWorkflow, I as cronMatches } from './run-
|
|
1
|
+
import { j as resolveProjectRoot, E as listWorkflows, F as isWorkflowEnabled, G as workflowSchedules, H as inZone, y as runWorkflow, I as cronMatches } from './run-DtVX2pQN.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-
|
|
57
|
+
const { connectAndGetMachine } = await import('./commands-BoGUxb2o.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-
|
|
96
|
+
const { connectAndGetMachine } = await import('./commands-BoGUxb2o.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-
|
|
185
|
+
const { connectAndGetMachine } = await import('./commands-BoGUxb2o.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-
|
|
205
|
+
const { connectAndGetMachine } = await import('./commands-BoGUxb2o.mjs');
|
|
206
206
|
const all = hasFlag(args, "--all", "-a");
|
|
207
207
|
const json = hasFlag(args, "--json");
|
|
208
208
|
const sessionId = getFlag(args, "--session");
|
|
@@ -221,6 +221,7 @@ async function serveList(args, machineId) {
|
|
|
221
221
|
const session = m.sessionId ? m.sessionId.slice(0, 8) : "-";
|
|
222
222
|
console.log(` ${m.name}`);
|
|
223
223
|
console.log(` Directory: ${m.directory}`);
|
|
224
|
+
console.log(` URL: ${m.url || "-"}`);
|
|
224
225
|
console.log(` Session: ${session}`);
|
|
225
226
|
console.log(` Added: ${new Date(m.addedAt).toISOString().slice(0, 16).replace("T", " ")}`);
|
|
226
227
|
console.log("");
|
|
@@ -235,15 +236,15 @@ async function serveList(args, machineId) {
|
|
|
235
236
|
}
|
|
236
237
|
}
|
|
237
238
|
async function serveInfo(machineId) {
|
|
238
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
239
|
+
const { connectAndGetMachine } = await import('./commands-BoGUxb2o.mjs');
|
|
239
240
|
const { machine, server } = await connectAndGetMachine(machineId);
|
|
240
241
|
try {
|
|
241
242
|
const info = await machine.serveInfo();
|
|
242
243
|
console.log(`Static file server:`);
|
|
243
244
|
console.log(` Status: ${info.running ? "running" : "stopped"}`);
|
|
244
245
|
console.log(` Port: ${info.port || "-"}`);
|
|
245
|
-
console.log(` URL: ${info.url || "(not exposed)"}`);
|
|
246
246
|
console.log(` Mounts: ${info.mountCount}`);
|
|
247
|
+
console.log(` URLs: per-mount \u2014 run 'svamp serve list' to see each mount's own URL`);
|
|
247
248
|
} catch (err) {
|
|
248
249
|
console.error(`Error: ${err.message || err}`);
|
|
249
250
|
process.exit(1);
|
|
@@ -254,20 +255,26 @@ async function serveInfo(machineId) {
|
|
|
254
255
|
}
|
|
255
256
|
function printServeHelp() {
|
|
256
257
|
console.log(`
|
|
257
|
-
svamp serve \u2014
|
|
258
|
+
svamp serve \u2014 Static file server (per-mount subdomains)
|
|
258
259
|
|
|
259
|
-
Serve local directories via a
|
|
260
|
-
|
|
260
|
+
Serve local directories via a daemon-managed HTTP server. Each mount gets its OWN
|
|
261
|
+
public URL on its own subdomain (static-<name>-<token>.svc\u2026) \u2014 there is NO single
|
|
262
|
+
server URL. Multiple sessions register different mounts without port conflicts.
|
|
263
|
+
|
|
264
|
+
IMPORTANT: use each mount's own URL exactly as printed. NEVER build a URL by
|
|
265
|
+
appending a path (e.g. /<name>/) to another mount's URL or to 'serve info' \u2014 that
|
|
266
|
+
lands on a DIFFERENT project's subdomain and serves the wrong files. To get a
|
|
267
|
+
mount's URL, read it from 'svamp serve <name>' (on create) or 'svamp serve list'.
|
|
261
268
|
|
|
262
269
|
Usage:
|
|
263
|
-
svamp serve <name> [directory] Add a mount and print
|
|
270
|
+
svamp serve <name> [directory] Add a mount and print ITS OWN url (dir defaults to .)
|
|
264
271
|
svamp serve add <name> [directory] Same as above
|
|
265
272
|
svamp serve apply <yaml> Apply a declarative mount config (idempotent).
|
|
266
273
|
Supports static and managed-process mounts
|
|
267
274
|
with wake-on-request and idle timeout.
|
|
268
275
|
svamp serve remove <name> Remove a mount
|
|
269
|
-
svamp serve list [--all] [--json] List mounts (default:
|
|
270
|
-
svamp serve info Show server status
|
|
276
|
+
svamp serve list [--all] [--json] List mounts + each mount's own URL (default: this session)
|
|
277
|
+
svamp serve info Show server status (per-mount URLs via 'serve list')
|
|
271
278
|
|
|
272
279
|
Access tiers (default: link):
|
|
273
280
|
(no flag) Capability URL \u2014 anyone with the URL can view.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R as READ_ONLY_TOOLS, O as loadMachineContext, P as buildMachineInstructions, Q as machineToolsForRole, T as buildMachineTools } from './run-
|
|
1
|
+
import { R as READ_ONLY_TOOLS, O as loadMachineContext, P as buildMachineInstructions, Q as machineToolsForRole, T as buildMachineTools } from './run-DtVX2pQN.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.
|
|
3
|
+
"version": "0.2.311",
|
|
4
4
|
"description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
|
|
5
5
|
"author": "Amun AI AB",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"scripts": {
|
|
21
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
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-sharing-notify-resolve.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-outpost-setup.mjs && npx tsx test/test-outpost-pairing.mjs && npx tsx test/test-outpost-coordinator.mjs && npx tsx test/e2e-outpost-transport.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-session-rpc-role-map.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-pinned-codex.mjs && npx tsx test/test-codex-request-timeout.mjs && npx tsx test/test-codex-app-server.mjs && npx tsx test/e2e-codex-midturn-steer.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-listener-backoff.mjs && npx tsx test/test-session-identity-env.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-store-lock.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-runs-lock.mjs && npx tsx test/test-workflow-idle.mjs && npx tsx test/test-workflow-reconcile.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-store-lock.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 && npx tsx test/test-codex-skills.mjs",
|
|
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-sharing-notify-resolve.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-stdin-delivery.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-outpost-setup.mjs && npx tsx test/test-outpost-pairing.mjs && npx tsx test/test-outpost-coordinator.mjs && npx tsx test/e2e-outpost-transport.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-machine-session-visibility.mjs && npx tsx test/test-session-access-fallback.mjs && npx tsx test/test-session-rpc-role-map.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-pinned-codex.mjs && npx tsx test/test-codex-request-timeout.mjs && npx tsx test/test-codex-app-server.mjs && npx tsx test/e2e-codex-midturn-steer.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-listener-backoff.mjs && npx tsx test/test-session-identity-env.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-store-lock.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-runs-lock.mjs && npx tsx test/test-workflow-idle.mjs && npx tsx test/test-workflow-reconcile.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-store-lock.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 && npx tsx test/test-codex-skills.mjs",
|
|
24
24
|
"test:hypha": "node --no-warnings test/test-hypha-service.mjs",
|
|
25
25
|
"dev": "tsx src/cli.ts",
|
|
26
26
|
"dev:daemon": "tsx src/cli.ts daemon start-sync",
|