svamp-cli 0.2.251 → 0.2.253
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/{agentCommands-Bcqo8iMs.mjs → agentCommands-DYoNzX4K.mjs} +5 -5
- package/dist/{auth-aefPotnn.mjs → auth-D0nW0Gyj.mjs} +1 -1
- package/dist/cli.mjs +77 -70
- package/dist/{commands-Cy6dc7Ey.mjs → commands-B9wShol7.mjs} +1 -1
- package/dist/{commands-BwvIihFY.mjs → commands-C3YGnWyy.mjs} +1 -1
- package/dist/{commands-BF-wFyla.mjs → commands-CfDWN8Ej.mjs} +2 -2
- package/dist/{commands-DV7Somb0.mjs → commands-CvWkQB_c.mjs} +1 -1
- package/dist/{commands-CBOY46Ig.mjs → commands-EhQiKpwu.mjs} +6 -6
- package/dist/{commands-hPm8AYNG.mjs → commands-YPQSZ4Qx.mjs} +9 -2
- package/dist/{commands-D7Sifr5h.mjs → commands-_Tr8pO3_.mjs} +2 -2
- package/dist/{fleet-CBIJW3k7.mjs → fleet-Ndfbo8Ni.mjs} +2 -2
- package/dist/{frpc-DshAO_N4.mjs → frpc-CLQB-GM1.mjs} +1 -1
- package/dist/{headlessCli-l72fsaU0.mjs → headlessCli-CbCWVR81.mjs} +2 -2
- package/dist/index.mjs +1 -1
- package/dist/{package-ayXBWSo-.mjs → package-BTW_-LFn.mjs} +1 -1
- package/dist/{pinnedClaudeCode-ivV7xAp3.mjs → pinnedClaudeCode-DuLXaoGP.mjs} +1 -1
- package/dist/{rpc-B2BhUPgt.mjs → rpc-0HSLhpCb.mjs} +1 -1
- package/dist/{rpc-CtfcD14b.mjs → rpc-BB-AxQa_.mjs} +1 -1
- package/dist/{run-BCU137ie.mjs → run-BtWV7xhR.mjs} +1 -1
- package/dist/{run-CRe59VaY.mjs → run-hYUl-Fln.mjs} +146 -71
- package/dist/{scheduler-CW_l0_B6.mjs → scheduler-DaFydJPf.mjs} +1 -1
- package/dist/{serveCommands-JgPmRokC.mjs → serveCommands-BgtRllaY.mjs} +5 -5
- package/dist/{serveManager-CL0QrW7Z.mjs → serveManager-BK5OjhXU.mjs} +2 -2
- package/dist/{sideband-CiE3Nqih.mjs → sideband-C0qzprWp.mjs} +1 -1
- package/package.json +1 -1
|
@@ -1869,20 +1869,7 @@ class ChannelOutbox {
|
|
|
1869
1869
|
this.byChannel.delete(channelId);
|
|
1870
1870
|
this.seqByChannel.delete(channelId);
|
|
1871
1871
|
if (!existsSync(this.file)) return;
|
|
1872
|
-
|
|
1873
|
-
const kept = readFileSync(this.file, "utf8").split("\n").filter((l) => {
|
|
1874
|
-
if (!l.trim()) return false;
|
|
1875
|
-
try {
|
|
1876
|
-
return JSON.parse(l).channelId !== channelId;
|
|
1877
|
-
} catch {
|
|
1878
|
-
return false;
|
|
1879
|
-
}
|
|
1880
|
-
});
|
|
1881
|
-
const tmp = this.file + ".tmp";
|
|
1882
|
-
writeFileSync(tmp, kept.join("\n") + (kept.length ? "\n" : ""));
|
|
1883
|
-
renameSync(tmp, this.file);
|
|
1884
|
-
} catch {
|
|
1885
|
-
}
|
|
1872
|
+
this._compact();
|
|
1886
1873
|
}
|
|
1887
1874
|
}
|
|
1888
1875
|
|
|
@@ -2998,7 +2985,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
2998
2985
|
const tunnels = handlers.tunnels;
|
|
2999
2986
|
if (!tunnels) throw new Error("Tunnel management not available");
|
|
3000
2987
|
if (tunnels.has(params.name)) throw new Error(`Tunnel '${params.name}' already running`);
|
|
3001
|
-
const { FrpcTunnel } = await import('./frpc-
|
|
2988
|
+
const { FrpcTunnel } = await import('./frpc-CLQB-GM1.mjs');
|
|
3002
2989
|
const tunnel = new FrpcTunnel({
|
|
3003
2990
|
name: params.name,
|
|
3004
2991
|
ports: params.ports,
|
|
@@ -3223,6 +3210,11 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
3223
3210
|
};
|
|
3224
3211
|
let wired = false;
|
|
3225
3212
|
if (sid) {
|
|
3213
|
+
try {
|
|
3214
|
+
await authorizeSessionAccess(sid, "admin", context);
|
|
3215
|
+
} catch {
|
|
3216
|
+
return { success: false, error: `Not authorized: launching a meeting agent for session ${sid} requires admin access to that session.` };
|
|
3217
|
+
}
|
|
3226
3218
|
const sessionRpc = handlers.getSessionRPCHandlers?.(sid);
|
|
3227
3219
|
if (sessionRpc?.saveChannel) {
|
|
3228
3220
|
try {
|
|
@@ -3304,10 +3296,12 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
3304
3296
|
},
|
|
3305
3297
|
// Drives the title-bar "WISE in a meeting" indicator (poll per session).
|
|
3306
3298
|
wiseMeetingStatus: async (params, context) => {
|
|
3307
|
-
if (!roleAtLeast(getEffectiveRole(context, currentMetadata.sharing), "view")) {
|
|
3308
|
-
return { active: false, error: "Not authorized to view meeting status on this machine." };
|
|
3309
|
-
}
|
|
3310
3299
|
if (params?.sessionId) {
|
|
3300
|
+
try {
|
|
3301
|
+
await authorizeSessionAccess(params.sessionId, "view", context);
|
|
3302
|
+
} catch {
|
|
3303
|
+
return { active: false, error: `Not authorized to view meeting status for session ${params.sessionId}.` };
|
|
3304
|
+
}
|
|
3311
3305
|
const rec = activeMeetingAgents.get(params.sessionId);
|
|
3312
3306
|
let transcript = [];
|
|
3313
3307
|
try {
|
|
@@ -3317,6 +3311,9 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
3317
3311
|
}
|
|
3318
3312
|
return { active: !!rec, meeting: rec || null, transcript };
|
|
3319
3313
|
}
|
|
3314
|
+
if (!roleAtLeast(getEffectiveRole(context, currentMetadata.sharing), "view")) {
|
|
3315
|
+
return { active: false, error: "Not authorized to view meeting status on this machine." };
|
|
3316
|
+
}
|
|
3320
3317
|
return { active: activeMeetingAgents.size > 0, meetings: Array.from(activeMeetingAgents.values()) };
|
|
3321
3318
|
},
|
|
3322
3319
|
// GAP 3 — post a chat message into the live meeting. The deep coding agent
|
|
@@ -3455,7 +3452,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
3455
3452
|
}
|
|
3456
3453
|
const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
|
|
3457
3454
|
const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
|
|
3458
|
-
const { toolsForRole } = await import('./sideband-
|
|
3455
|
+
const { toolsForRole } = await import('./sideband-C0qzprWp.mjs');
|
|
3459
3456
|
const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
|
|
3460
3457
|
return fmt(r2);
|
|
3461
3458
|
}
|
|
@@ -3554,7 +3551,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
3554
3551
|
if (r.error || !r.sender) return { error: r.error || "unauthorized" };
|
|
3555
3552
|
const callId = "call_" + Math.random().toString(16).slice(2, 12);
|
|
3556
3553
|
const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
|
|
3557
|
-
const { queryCore } = await import('./commands-
|
|
3554
|
+
const { queryCore } = await import('./commands-YPQSZ4Qx.mjs');
|
|
3558
3555
|
const timeout = c.reply?.timeout_sec || 120;
|
|
3559
3556
|
let result;
|
|
3560
3557
|
try {
|
|
@@ -3816,14 +3813,19 @@ function registerAwaitingReply(sessionId, threadId, now = Date.now()) {
|
|
|
3816
3813
|
}
|
|
3817
3814
|
writeAwaiting(sessionId, map);
|
|
3818
3815
|
}
|
|
3819
|
-
function
|
|
3816
|
+
function peekAwaitingReply(sessionId, threadId, now = Date.now()) {
|
|
3820
3817
|
if (!sessionId || !threadId) return false;
|
|
3821
3818
|
const map = readAwaiting(sessionId);
|
|
3822
3819
|
const at = map[threadId];
|
|
3823
3820
|
if (typeof at !== "number") return false;
|
|
3821
|
+
return now - at <= AWAIT_TTL_MS;
|
|
3822
|
+
}
|
|
3823
|
+
function consumeAwaitingReply(sessionId, threadId) {
|
|
3824
|
+
if (!sessionId || !threadId) return;
|
|
3825
|
+
const map = readAwaiting(sessionId);
|
|
3826
|
+
if (!(threadId in map)) return;
|
|
3824
3827
|
delete map[threadId];
|
|
3825
3828
|
writeAwaiting(sessionId, map);
|
|
3826
|
-
return now - at <= AWAIT_TTL_MS;
|
|
3827
3829
|
}
|
|
3828
3830
|
function computeOutboundHop(sessionId) {
|
|
3829
3831
|
if (!sessionId) return { hopCount: 0, fromInboxTurn: false };
|
|
@@ -4180,6 +4182,26 @@ function isStructuredMessage(msg) {
|
|
|
4180
4182
|
function escapeXml(s) {
|
|
4181
4183
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
4182
4184
|
}
|
|
4185
|
+
function sanitizeInboundInboxMessage(message, opts) {
|
|
4186
|
+
if (opts.trusted) return message;
|
|
4187
|
+
const email = opts.callerEmail;
|
|
4188
|
+
return {
|
|
4189
|
+
...message,
|
|
4190
|
+
// Attribute to the SERVER-KNOWN identity, never the caller's self-asserted `from`.
|
|
4191
|
+
// An authenticated collaborator is an honest verified human (`user:<email>` → may
|
|
4192
|
+
// wake, attributed to THEM not the owner); an anonymous caller cannot claim human.
|
|
4193
|
+
from: email ? `user:${email}` : "agent:anonymous",
|
|
4194
|
+
verified: !!email,
|
|
4195
|
+
// Strip self-asserted channel provenance + async-reply routing a direct caller
|
|
4196
|
+
// has no business setting (legit channel ingress goes via the trusted channel path).
|
|
4197
|
+
channel: void 0,
|
|
4198
|
+
channelId: void 0,
|
|
4199
|
+
correlationId: void 0,
|
|
4200
|
+
// Escape the body so a nested </svamp-message> can't break out and forge a second
|
|
4201
|
+
// attributed envelope in the agent's transcript.
|
|
4202
|
+
body: xmlEscape(String(message.body ?? "").slice(0, 16 * 1024))
|
|
4203
|
+
};
|
|
4204
|
+
}
|
|
4183
4205
|
function formatInboxMessageXml(msg) {
|
|
4184
4206
|
if (!isStructuredMessage(msg)) return msg.body;
|
|
4185
4207
|
const attrs = [`message-id="${escapeXml(msg.messageId)}"`];
|
|
@@ -5308,12 +5330,14 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
|
|
|
5308
5330
|
// ── Inbox ──
|
|
5309
5331
|
sendInboxMessage: async (message, context) => {
|
|
5310
5332
|
authorizeRequest(context, metadata.sharing, "interact");
|
|
5311
|
-
|
|
5333
|
+
const trusted = getEffectiveRole(context, metadata.sharing) === "admin";
|
|
5334
|
+
const msg = sanitizeInboundInboxMessage(message, { trusted, callerEmail: context?.user?.email });
|
|
5335
|
+
inbox.push(msg);
|
|
5312
5336
|
while (inbox.length > INBOX_MAX) inbox.shift();
|
|
5313
5337
|
syncInboxToMetadata();
|
|
5314
|
-
callbacks.onInboxMessage?.(
|
|
5315
|
-
notifyListeners({ type: "inbox-update", sessionId, message });
|
|
5316
|
-
return { success: true, messageId:
|
|
5338
|
+
callbacks.onInboxMessage?.(msg);
|
|
5339
|
+
notifyListeners({ type: "inbox-update", sessionId, message: msg });
|
|
5340
|
+
return { success: true, messageId: msg.messageId };
|
|
5317
5341
|
},
|
|
5318
5342
|
getInbox: async (opts, context) => {
|
|
5319
5343
|
authorizeRequest(context, metadata.sharing, "view");
|
|
@@ -6282,12 +6306,10 @@ async function registerDebugService(server, machineId, deps) {
|
|
|
6282
6306
|
// require_context: true → Hypha injects the caller context as the last arg of every
|
|
6283
6307
|
// method, which the authorize() gate below enforces. 'unlisted' only hides discovery.
|
|
6284
6308
|
config: { visibility: "unlisted", require_context: true },
|
|
6285
|
-
healthCheck: async () =>
|
|
6286
|
-
|
|
6287
|
-
machineId,
|
|
6288
|
-
|
|
6289
|
-
timestamp: Date.now()
|
|
6290
|
-
}),
|
|
6309
|
+
healthCheck: async (context) => {
|
|
6310
|
+
authorize(context, "view");
|
|
6311
|
+
return { ok: true, machineId, uptime: process.uptime(), timestamp: Date.now() };
|
|
6312
|
+
},
|
|
6291
6313
|
getSessionStates: async (context) => {
|
|
6292
6314
|
authorize(context, "view");
|
|
6293
6315
|
const sessions = deps.getTrackedSessions();
|
|
@@ -10130,6 +10152,18 @@ var api = /*#__PURE__*/Object.freeze({
|
|
|
10130
10152
|
searchSkills: searchSkills
|
|
10131
10153
|
});
|
|
10132
10154
|
|
|
10155
|
+
function signalProcessTree(child, signal) {
|
|
10156
|
+
const pid = child.pid;
|
|
10157
|
+
if (pid === void 0) return;
|
|
10158
|
+
try {
|
|
10159
|
+
process.kill(-pid, signal);
|
|
10160
|
+
} catch {
|
|
10161
|
+
try {
|
|
10162
|
+
child.kill(signal);
|
|
10163
|
+
} catch {
|
|
10164
|
+
}
|
|
10165
|
+
}
|
|
10166
|
+
}
|
|
10133
10167
|
const DEFAULT_PROBE_INTERVAL_S = 10;
|
|
10134
10168
|
const DEFAULT_PROBE_TIMEOUT_S = 5;
|
|
10135
10169
|
const DEFAULT_PROBE_FAILURE_THRESHOLD = 3;
|
|
@@ -10153,7 +10187,7 @@ class ProcessSupervisor {
|
|
|
10153
10187
|
/** Stop all managed processes (called on daemon shutdown). */
|
|
10154
10188
|
async stopAll() {
|
|
10155
10189
|
const ids = Array.from(this.entries.keys());
|
|
10156
|
-
await Promise.all(ids.map((id) => this.stop(id).catch(() => {
|
|
10190
|
+
await Promise.all(ids.map((id) => this.stop(id, { markDesiredStopped: false }).catch(() => {
|
|
10157
10191
|
})));
|
|
10158
10192
|
}
|
|
10159
10193
|
// ── Public API ────────────────────────────────────────────────────────────
|
|
@@ -10191,11 +10225,20 @@ class ProcessSupervisor {
|
|
|
10191
10225
|
throw new Error(`Process '${entry.spec.name}' is already running`);
|
|
10192
10226
|
}
|
|
10193
10227
|
entry.stopping = false;
|
|
10228
|
+
if (entry.spec.desiredStopped) {
|
|
10229
|
+
entry.spec.desiredStopped = false;
|
|
10230
|
+
await this.persistSpec(entry.spec);
|
|
10231
|
+
}
|
|
10194
10232
|
this.resetFailureTracking(entry);
|
|
10195
10233
|
await this.startEntry(entry, false);
|
|
10196
10234
|
}
|
|
10197
|
-
/**
|
|
10198
|
-
|
|
10235
|
+
/**
|
|
10236
|
+
* Stop a running process. Does NOT remove it from supervision.
|
|
10237
|
+
* @param opts.markDesiredStopped When true (default — an EXPLICIT user `stop`), persist
|
|
10238
|
+
* a desired-stopped intent so a daemon restart does not resurrect it. `stopAll` (a daemon
|
|
10239
|
+
* shutdown, not a user action) passes false so keepAlive processes auto-restore (#nightly).
|
|
10240
|
+
*/
|
|
10241
|
+
async stop(idOrName, opts) {
|
|
10199
10242
|
const entry = this.require(idOrName);
|
|
10200
10243
|
entry.stopping = true;
|
|
10201
10244
|
this.clearTimers(entry);
|
|
@@ -10206,6 +10249,10 @@ class ProcessSupervisor {
|
|
|
10206
10249
|
entry.state.status = "stopped";
|
|
10207
10250
|
entry.state.stoppedAt = Date.now();
|
|
10208
10251
|
entry.state.pid = void 0;
|
|
10252
|
+
if (opts?.markDesiredStopped !== false && !entry.deleted && !entry.spec.desiredStopped) {
|
|
10253
|
+
entry.spec.desiredStopped = true;
|
|
10254
|
+
await this.persistSpec(entry.spec);
|
|
10255
|
+
}
|
|
10209
10256
|
}
|
|
10210
10257
|
/** Restart a process (stop if running, then start again). */
|
|
10211
10258
|
async restart(idOrName) {
|
|
@@ -10223,6 +10270,10 @@ class ProcessSupervisor {
|
|
|
10223
10270
|
if (entry.deleted) return;
|
|
10224
10271
|
entry.stopping = false;
|
|
10225
10272
|
this.resetFailureTracking(entry);
|
|
10273
|
+
if (entry.spec.desiredStopped) {
|
|
10274
|
+
entry.spec.desiredStopped = false;
|
|
10275
|
+
await this.persistSpec(entry.spec);
|
|
10276
|
+
}
|
|
10226
10277
|
entry.state.restartCount++;
|
|
10227
10278
|
await this.startEntry(entry, false);
|
|
10228
10279
|
} finally {
|
|
@@ -10357,12 +10408,17 @@ class ProcessSupervisor {
|
|
|
10357
10408
|
const spec = JSON.parse(raw);
|
|
10358
10409
|
const entry = this.makeEntry(spec);
|
|
10359
10410
|
this.entries.set(spec.id, entry);
|
|
10360
|
-
if (spec.keepAlive) {
|
|
10411
|
+
if (spec.keepAlive && !spec.desiredStopped) {
|
|
10361
10412
|
await this.startEntry(
|
|
10362
10413
|
entry,
|
|
10363
10414
|
true
|
|
10364
10415
|
/* onRestore */
|
|
10365
10416
|
);
|
|
10417
|
+
} else if (spec.keepAlive && spec.desiredStopped) {
|
|
10418
|
+
entry.state.status = "stopped";
|
|
10419
|
+
if (spec.ttl !== void 0 && spec.ttl > 0) this.setupTTL(entry);
|
|
10420
|
+
} else if (spec.ttl !== void 0 && spec.ttl > 0) {
|
|
10421
|
+
this.setupTTL(entry);
|
|
10366
10422
|
}
|
|
10367
10423
|
loaded++;
|
|
10368
10424
|
} catch (err) {
|
|
@@ -10439,7 +10495,13 @@ class ProcessSupervisor {
|
|
|
10439
10495
|
const child = spawn$1(spec.command, spec.args, {
|
|
10440
10496
|
cwd: spec.workdir,
|
|
10441
10497
|
env,
|
|
10442
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
10498
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
10499
|
+
// #0316: run each supervised process in its OWN process group (setsid) so a
|
|
10500
|
+
// shell-wrapping spec (`bash -c …`, `npm start`) can be torn down with the whole
|
|
10501
|
+
// tree — otherwise stop/restart/TTL only kills the direct PID and leaks
|
|
10502
|
+
// grandchildren. Kills below signal the group (negative PID). POSIX only; on
|
|
10503
|
+
// Windows `detached` just decouples the console and the group-kill falls back.
|
|
10504
|
+
detached: process.platform !== "win32"
|
|
10443
10505
|
});
|
|
10444
10506
|
entry.child = child;
|
|
10445
10507
|
state.status = "running";
|
|
@@ -10489,7 +10551,6 @@ class ProcessSupervisor {
|
|
|
10489
10551
|
const uptime = state.startedAt ? Date.now() - state.startedAt : 0;
|
|
10490
10552
|
const now = Date.now();
|
|
10491
10553
|
if (uptime > BACKOFF_RESET_WINDOW_MS) {
|
|
10492
|
-
state.restartCount = 0;
|
|
10493
10554
|
state.consecutiveFailures = 0;
|
|
10494
10555
|
entry.failureWindowStart = void 0;
|
|
10495
10556
|
} else {
|
|
@@ -10602,10 +10663,7 @@ class ProcessSupervisor {
|
|
|
10602
10663
|
console.warn(`[SUPERVISOR] Probe failed for '${entry.spec.name}' \u2014 killing to trigger restart`);
|
|
10603
10664
|
entry.state.consecutiveProbeFailures = 0;
|
|
10604
10665
|
if (entry.child) {
|
|
10605
|
-
|
|
10606
|
-
entry.child.kill("SIGTERM");
|
|
10607
|
-
} catch {
|
|
10608
|
-
}
|
|
10666
|
+
signalProcessTree(entry.child, "SIGTERM");
|
|
10609
10667
|
}
|
|
10610
10668
|
}
|
|
10611
10669
|
// ── TTL ───────────────────────────────────────────────────────────────────
|
|
@@ -10650,15 +10708,9 @@ class ProcessSupervisor {
|
|
|
10650
10708
|
};
|
|
10651
10709
|
child.once("exit", done);
|
|
10652
10710
|
child.once("close", done);
|
|
10653
|
-
|
|
10654
|
-
child.kill("SIGTERM");
|
|
10655
|
-
} catch {
|
|
10656
|
-
}
|
|
10711
|
+
signalProcessTree(child, "SIGTERM");
|
|
10657
10712
|
forceKillTimer = setTimeout(() => {
|
|
10658
|
-
|
|
10659
|
-
child.kill("SIGKILL");
|
|
10660
|
-
} catch {
|
|
10661
|
-
}
|
|
10713
|
+
signalProcessTree(child, "SIGKILL");
|
|
10662
10714
|
hardDeadlineTimer = setTimeout(() => {
|
|
10663
10715
|
if (!resolved) {
|
|
10664
10716
|
resolved = true;
|
|
@@ -11361,6 +11413,9 @@ function fireIdleWorkflows(root, sessionId, deps = {}) {
|
|
|
11361
11413
|
}
|
|
11362
11414
|
|
|
11363
11415
|
const UNBOUNDED_LOOP_ITERATIONS = 1e6;
|
|
11416
|
+
function loopCancelledDuringVerify(current) {
|
|
11417
|
+
return !!current && (current.phase === "cancelled" || current.active === false);
|
|
11418
|
+
}
|
|
11364
11419
|
function backlogOraclePending(projectRoot, sessionId) {
|
|
11365
11420
|
const inScope = (i) => !sessionId || isVisibleTo(i, sessionId);
|
|
11366
11421
|
return listIssues(projectRoot).filter(inScope).filter((i) => i.status === "ready" || i.status === "in_progress").map((i) => ({ id: i.id }));
|
|
@@ -11488,7 +11543,7 @@ function computeSoftTurnCap(hardMax, cadence) {
|
|
|
11488
11543
|
return Math.ceil(hardMax / chunks);
|
|
11489
11544
|
}
|
|
11490
11545
|
const DEFAULT_LOOP_STUCK_CHECKPOINTS = 3;
|
|
11491
|
-
const DEFAULT_LOOP_MAX_AUTORESUMES =
|
|
11546
|
+
const DEFAULT_LOOP_MAX_AUTORESUMES = Number.POSITIVE_INFINITY;
|
|
11492
11547
|
const PROGRESS_HISTORY_CAP = 12;
|
|
11493
11548
|
function resolveStuckLimit(envValue) {
|
|
11494
11549
|
const n = Number(envValue);
|
|
@@ -11533,7 +11588,8 @@ function decideLoopContinuation(input) {
|
|
|
11533
11588
|
return { action: "continue", kind: "progress", consumeAutoResume: false, reason: `still making progress (${stuckCheckpoints}/${stuckLimit} stuck checkpoints)` };
|
|
11534
11589
|
}
|
|
11535
11590
|
if (autoResumes < maxAutoResumes) {
|
|
11536
|
-
|
|
11591
|
+
const label = Number.isFinite(maxAutoResumes) ? `auto-resume ${autoResumes + 1}/${maxAutoResumes}` : `auto-resume ${autoResumes + 1} (unbounded \u2014 bounded only by the cost/iteration ceiling)`;
|
|
11592
|
+
return { action: "continue", kind: "autoresume", consumeAutoResume: true, reason: `no progress across ${stuckCheckpoints} checkpoints \u2014 ${label}` };
|
|
11537
11593
|
}
|
|
11538
11594
|
const tail = `no progress across ${stuckCheckpoints} checkpoints; ${maxAutoResumes} auto-resume(s) exhausted`;
|
|
11539
11595
|
return { action: "stop", kind: "stuck", reason: input.stuckReason ? `${input.stuckReason} \u2014 ${tail}` : tail };
|
|
@@ -12505,17 +12561,30 @@ function classifyOptsForMessage(sessionId, message, ownerEmail) {
|
|
|
12505
12561
|
const fromVal = message.from || "";
|
|
12506
12562
|
const senderEmail = message.verified && fromVal.includes("@") ? fromVal.replace(/^user:/, "").toLowerCase() : void 0;
|
|
12507
12563
|
const self = !!(ownerEmail && senderEmail && senderEmail === String(ownerEmail).toLowerCase());
|
|
12508
|
-
const openThreadReply =
|
|
12564
|
+
const openThreadReply = peekAwaitingReply(sessionId, message.threadId);
|
|
12509
12565
|
return { self, openThreadReply };
|
|
12510
12566
|
}
|
|
12567
|
+
function classifyInboundForSession(sessionId, message, ownerEmail) {
|
|
12568
|
+
const opts = classifyOptsForMessage(sessionId, message, ownerEmail);
|
|
12569
|
+
const decision = classifyInbound(message, Date.now(), opts);
|
|
12570
|
+
if (opts.openThreadReply && decision.action === "wake") {
|
|
12571
|
+
consumeAwaitingReply(sessionId, message.threadId);
|
|
12572
|
+
}
|
|
12573
|
+
return decision;
|
|
12574
|
+
}
|
|
12511
12575
|
function writeGoalLoopState(directory, sessionId, state) {
|
|
12512
12576
|
try {
|
|
12513
12577
|
const dir = getLoopDir(directory, sessionId);
|
|
12514
12578
|
mkdirSync$1(dir, { recursive: true });
|
|
12515
|
-
|
|
12579
|
+
atomicWriteLoopState(join$1(dir, "loop-state.json"), { session_id: sessionId, engine: "goal", ...state });
|
|
12516
12580
|
} catch {
|
|
12517
12581
|
}
|
|
12518
12582
|
}
|
|
12583
|
+
function atomicWriteLoopState(path, obj) {
|
|
12584
|
+
const tmp = path + ".tmp";
|
|
12585
|
+
writeFileSync$1(tmp, JSON.stringify(obj, null, 2));
|
|
12586
|
+
renameSync$1(tmp, path);
|
|
12587
|
+
}
|
|
12519
12588
|
function safeBacklogPendingCount(projectRoot, sessionId) {
|
|
12520
12589
|
try {
|
|
12521
12590
|
return backlogOraclePending(projectRoot, sessionId).length;
|
|
@@ -12881,7 +12950,7 @@ function createSvampConfigChecker(directory, sessionId, getMetadata, setMetadata
|
|
|
12881
12950
|
if (wasStopped) {
|
|
12882
12951
|
try {
|
|
12883
12952
|
const sp = join$1(getLoopDir(directory, sessionId), "loop-state.json");
|
|
12884
|
-
|
|
12953
|
+
atomicWriteLoopState(sp, {
|
|
12885
12954
|
...existing,
|
|
12886
12955
|
active: true,
|
|
12887
12956
|
phase: "continue",
|
|
@@ -12893,7 +12962,7 @@ function createSvampConfigChecker(directory, sessionId, getMetadata, setMetadata
|
|
|
12893
12962
|
gave_up_reason: void 0,
|
|
12894
12963
|
stall_hinted: false,
|
|
12895
12964
|
resumed_at: Date.now()
|
|
12896
|
-
}
|
|
12965
|
+
});
|
|
12897
12966
|
} catch {
|
|
12898
12967
|
}
|
|
12899
12968
|
const eq = getMetadata().messageQueue || [];
|
|
@@ -13380,7 +13449,7 @@ async function startDaemon(options) {
|
|
|
13380
13449
|
try {
|
|
13381
13450
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
13382
13451
|
if (!dir) return;
|
|
13383
|
-
const { reconcileServiceLinks } = await import('./agentCommands-
|
|
13452
|
+
const { reconcileServiceLinks } = await import('./agentCommands-DYoNzX4K.mjs');
|
|
13384
13453
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
13385
13454
|
const config = readSvampConfig(configPath);
|
|
13386
13455
|
const entries = Array.from(urls.entries());
|
|
@@ -13398,7 +13467,7 @@ async function startDaemon(options) {
|
|
|
13398
13467
|
}
|
|
13399
13468
|
}
|
|
13400
13469
|
async function createExposedTunnel(spec) {
|
|
13401
|
-
const { FrpcTunnel } = await import('./frpc-
|
|
13470
|
+
const { FrpcTunnel } = await import('./frpc-CLQB-GM1.mjs');
|
|
13402
13471
|
const tunnel = new FrpcTunnel({
|
|
13403
13472
|
name: spec.name,
|
|
13404
13473
|
ports: spec.ports,
|
|
@@ -13418,14 +13487,14 @@ async function startDaemon(options) {
|
|
|
13418
13487
|
return tunnel;
|
|
13419
13488
|
}
|
|
13420
13489
|
const tunnelRecreateState = /* @__PURE__ */ new Map();
|
|
13421
|
-
const { ServeManager } = await import('./serveManager-
|
|
13490
|
+
const { ServeManager } = await import('./serveManager-BK5OjhXU.mjs');
|
|
13422
13491
|
const serveManager = new ServeManager(SVAMP_HOME, (msg) => logger.log(`[SERVE] ${msg}`), hyphaServerUrl);
|
|
13423
13492
|
ensureAutoInstalledSkills(logger).catch(() => {
|
|
13424
13493
|
});
|
|
13425
13494
|
ensureAutoInstalledCommands(logger);
|
|
13426
13495
|
(async () => {
|
|
13427
13496
|
try {
|
|
13428
|
-
const { beginClaudeVersionReconcile } = await import('./pinnedClaudeCode-
|
|
13497
|
+
const { beginClaudeVersionReconcile } = await import('./pinnedClaudeCode-DuLXaoGP.mjs');
|
|
13429
13498
|
beginClaudeVersionReconcile((msg) => logger.log(msg));
|
|
13430
13499
|
} catch (e) {
|
|
13431
13500
|
logger.log(`[claude-version] check failed: ${e?.message || e}`);
|
|
@@ -14096,6 +14165,10 @@ ${parts.join("\n")}`);
|
|
|
14096
14165
|
log: (m) => logger.log(`[Session ${sessionId}] ${m}`)
|
|
14097
14166
|
}
|
|
14098
14167
|
);
|
|
14168
|
+
if (loopCancelledDuringVerify(readLoopState(directory, sessionId))) {
|
|
14169
|
+
logger.log(`[Session ${sessionId}] loop was cancelled during verification \u2014 not re-kicking (#0308)`);
|
|
14170
|
+
return;
|
|
14171
|
+
}
|
|
14099
14172
|
const ledger = ls.ledger;
|
|
14100
14173
|
const budget = ls.budget;
|
|
14101
14174
|
const progress_history = ls.progress_history;
|
|
@@ -14144,7 +14217,9 @@ ${parts.join("\n")}`);
|
|
|
14144
14217
|
max_iterations: ls.max_iterations,
|
|
14145
14218
|
budget,
|
|
14146
14219
|
started_at: startedAt,
|
|
14147
|
-
|
|
14220
|
+
// #0319: a PROGRESSING loop resets its hold counter so the evaluator-guided re-kick
|
|
14221
|
+
// mechanism re-engages fresh (it's making headway, not stuck); an auto-resume keeps it.
|
|
14222
|
+
holds: decision.kind === "progress" ? 0 : holds,
|
|
14148
14223
|
ledger,
|
|
14149
14224
|
progress_history,
|
|
14150
14225
|
auto_resumes: nextAuto
|
|
@@ -15410,7 +15485,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
15410
15485
|
},
|
|
15411
15486
|
onInboxMessage: (message) => {
|
|
15412
15487
|
if (trackedSession?.stopped) return;
|
|
15413
|
-
const decision =
|
|
15488
|
+
const decision = classifyInboundForSession(sessionId, message, sessionMetadata?.sharing?.owner);
|
|
15414
15489
|
logger.log(`[Session ${sessionId}] Inbox message (urgency: ${message.urgency || "normal"}, hop: ${message.hopCount ?? 0}, from: ${message.from || "unknown"}) \u2192 ${decision.action} (${decision.reason})`);
|
|
15415
15490
|
if (decision.breakerTripped) {
|
|
15416
15491
|
logger.error(`[Session ${sessionId}] Inbox circuit breaker TRIPPED \u2014 cross-agent wake rate too high; auto-waking paused.`);
|
|
@@ -15506,11 +15581,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
15506
15581
|
});
|
|
15507
15582
|
},
|
|
15508
15583
|
onIssue: async (params) => {
|
|
15509
|
-
const { issueRpc } = await import('./rpc-
|
|
15584
|
+
const { issueRpc } = await import('./rpc-0HSLhpCb.mjs');
|
|
15510
15585
|
return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
|
|
15511
15586
|
},
|
|
15512
15587
|
onWorkflow: async (params) => {
|
|
15513
|
-
const { workflowRpc } = await import('./rpc-
|
|
15588
|
+
const { workflowRpc } = await import('./rpc-BB-AxQa_.mjs');
|
|
15514
15589
|
return workflowRpc(params?.cwd || directory, params || {});
|
|
15515
15590
|
},
|
|
15516
15591
|
onRipgrep: async (args, cwd) => {
|
|
@@ -15692,7 +15767,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
15692
15767
|
if (s.active === false || s.phase === "done") {
|
|
15693
15768
|
try {
|
|
15694
15769
|
const lp = join$1(getLoopDir(directory, sessionId), "loop-state.json");
|
|
15695
|
-
|
|
15770
|
+
atomicWriteLoopState(lp, {
|
|
15696
15771
|
...s,
|
|
15697
15772
|
active: true,
|
|
15698
15773
|
phase: "continue",
|
|
@@ -15702,7 +15777,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
15702
15777
|
stall_hinted: false,
|
|
15703
15778
|
resumed_at: Date.now()
|
|
15704
15779
|
// #0156: re-arm the stall hint
|
|
15705
|
-
}
|
|
15780
|
+
});
|
|
15706
15781
|
} catch {
|
|
15707
15782
|
}
|
|
15708
15783
|
}
|
|
@@ -15919,7 +15994,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
15919
15994
|
},
|
|
15920
15995
|
onInboxMessage: (message) => {
|
|
15921
15996
|
if (acpStopped) return;
|
|
15922
|
-
const decision =
|
|
15997
|
+
const decision = classifyInboundForSession(sessionId, message, sessionMetadata?.sharing?.owner);
|
|
15923
15998
|
logger.log(`[${agentName} Session ${sessionId}] Inbox message (urgency: ${message.urgency || "normal"}, hop: ${message.hopCount ?? 0}, from: ${message.from || "unknown"}) \u2192 ${decision.action} (${decision.reason})`);
|
|
15924
15999
|
if (decision.breakerTripped) {
|
|
15925
16000
|
logger.error(`[${agentName} Session ${sessionId}] Inbox circuit breaker TRIPPED \u2014 auto-waking paused.`);
|
|
@@ -16046,11 +16121,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
16046
16121
|
});
|
|
16047
16122
|
},
|
|
16048
16123
|
onIssue: async (params) => {
|
|
16049
|
-
const { issueRpc } = await import('./rpc-
|
|
16124
|
+
const { issueRpc } = await import('./rpc-0HSLhpCb.mjs');
|
|
16050
16125
|
return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
|
|
16051
16126
|
},
|
|
16052
16127
|
onWorkflow: async (params) => {
|
|
16053
|
-
const { workflowRpc } = await import('./rpc-
|
|
16128
|
+
const { workflowRpc } = await import('./rpc-BB-AxQa_.mjs');
|
|
16054
16129
|
return workflowRpc(params?.cwd || directory, params || {});
|
|
16055
16130
|
},
|
|
16056
16131
|
onRipgrep: async (args, cwd) => {
|
|
@@ -16812,7 +16887,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
16812
16887
|
}
|
|
16813
16888
|
if (persistedSessions.length > 0) {
|
|
16814
16889
|
try {
|
|
16815
|
-
const { awaitClaudeVersionReady } = await import('./pinnedClaudeCode-
|
|
16890
|
+
const { awaitClaudeVersionReady } = await import('./pinnedClaudeCode-DuLXaoGP.mjs');
|
|
16816
16891
|
await awaitClaudeVersionReady();
|
|
16817
16892
|
} catch {
|
|
16818
16893
|
}
|
|
@@ -17009,7 +17084,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
17009
17084
|
const PING_TIMEOUT_MS = 15e3;
|
|
17010
17085
|
const POST_RECONNECT_GRACE_MS = 2e4;
|
|
17011
17086
|
const RECONNECT_JITTER_MS = 2500;
|
|
17012
|
-
const { WorkflowScheduler } = await import('./scheduler-
|
|
17087
|
+
const { WorkflowScheduler } = await import('./scheduler-DaFydJPf.mjs');
|
|
17013
17088
|
const workflowScheduler = new WorkflowScheduler({
|
|
17014
17089
|
projectRoots: () => {
|
|
17015
17090
|
const dirs = /* @__PURE__ */ new Set();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as resolveProjectRoot, H as listWorkflows, I as isWorkflowEnabled, J as workflowCrons, C as runWorkflow, K as cronMatches } from './run-
|
|
1
|
+
import { n as resolveProjectRoot, H as listWorkflows, I as isWorkflowEnabled, J as workflowCrons, C as runWorkflow, K as cronMatches } from './run-hYUl-Fln.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-YPQSZ4Qx.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-YPQSZ4Qx.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-YPQSZ4Qx.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-YPQSZ4Qx.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-
|
|
238
|
+
const { connectAndGetMachine } = await import('./commands-YPQSZ4Qx.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 { l as getHyphaServerUrl, S as ServeAuth, m as hasCookieToken } from './run-
|
|
7
|
+
import { l as getHyphaServerUrl, S as ServeAuth, m as hasCookieToken } from './run-hYUl-Fln.mjs';
|
|
8
8
|
import 'os';
|
|
9
9
|
import 'fs/promises';
|
|
10
10
|
import 'url';
|
|
@@ -751,7 +751,7 @@ class ServeManager {
|
|
|
751
751
|
const mount = this.mounts.get(mountName);
|
|
752
752
|
const subdomainOverride = mount?.access === "link" && mount.linkToken ? /* @__PURE__ */ new Map([[this.port, buildLinkSubdomain(subdomainSafe, mount.linkToken)]]) : void 0;
|
|
753
753
|
try {
|
|
754
|
-
const { FrpcTunnel } = await import('./frpc-
|
|
754
|
+
const { FrpcTunnel } = await import('./frpc-CLQB-GM1.mjs');
|
|
755
755
|
let tunnel;
|
|
756
756
|
tunnel = new FrpcTunnel({
|
|
757
757
|
name: tunnelName,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R as READ_ONLY_TOOLS, N as loadMachineContext, O as buildMachineInstructions, P as machineToolsForRole, Q as buildMachineTools } from './run-
|
|
1
|
+
import { R as READ_ONLY_TOOLS, N as loadMachineContext, O as buildMachineInstructions, P as machineToolsForRole, Q as buildMachineTools } from './run-hYUl-Fln.mjs';
|
|
2
2
|
import 'node:child_process';
|
|
3
3
|
import 'os';
|
|
4
4
|
import 'fs/promises';
|