svamp-cli 0.2.331 → 0.2.332
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-DQ6TQAXa.mjs → adminCommands-BNGSC5oD.mjs} +1 -1
- package/dist/{agentCommands-CovUtOYv.mjs → agentCommands-DD47Krr1.mjs} +5 -5
- package/dist/{auth-CMWkQmps.mjs → auth-CE3Cnkn6.mjs} +1 -1
- package/dist/{cli-Cd_6Xp2x.mjs → cli-CdYVO7ce.mjs} +93 -77
- package/dist/cli.mjs +2 -2
- package/dist/{commands-D2he7eNq.mjs → commands-09sPSIH-.mjs} +3 -3
- package/dist/{commands-DCTCLAPA.mjs → commands-14Tf0D6G.mjs} +3 -3
- package/dist/{commands-OwmAlnGb.mjs → commands-BIKekqQG.mjs} +1 -1
- package/dist/{commands-Bv52WaQ0.mjs → commands-BIx8s0JL.mjs} +11 -11
- package/dist/{commands-CWkWkrZF.mjs → commands-C2X-uElg.mjs} +1 -1
- package/dist/{commands-CpXKePYP.mjs → commands-CHKSUX7x.mjs} +3 -3
- package/dist/{commands-B-PLeiIB.mjs → commands-D7wwybeC.mjs} +8 -3
- package/dist/{commands-BCWHfbuw.mjs → commands-DXJlhBPk.mjs} +24 -11
- package/dist/{fleet-DrLOwe6r.mjs → fleet-bAe_gJfS.mjs} +2 -2
- package/dist/{headlessCli-CDjGYUpj.mjs → headlessCli-Bwg5pf3s.mjs} +2 -2
- package/dist/index.mjs +1 -1
- package/dist/{notifyCommands-DSRd8YaE.mjs → notifyCommands-Cc3wLAWW.mjs} +1 -1
- package/dist/package-CPQqs8ty.mjs +64 -0
- package/dist/{rpc-OmhzsDGP.mjs → rpc-Bv6_c-xW.mjs} +1 -1
- package/dist/{rpc-CVBhR9Cj.mjs → rpc-DObWvEis.mjs} +1 -1
- package/dist/{run-DcwSfoyP.mjs → run-CyyWhgFI.mjs} +1 -1
- package/dist/{run-CSNL62FQ.mjs → run-DGhVoN3s.mjs} +177 -56
- package/dist/{scheduler-DDw3YLzH.mjs → scheduler-BvtNZ0pl.mjs} +1 -1
- package/dist/{serveCommands-BQ0jhFUR.mjs → serveCommands-CEM708Ls.mjs} +10 -10
- package/dist/{sideband-S3ycJa01.mjs → sideband--9vWYqKA.mjs} +1 -1
- package/package.json +3 -3
- package/dist/package-C23qFmVz.mjs +0 -64
|
@@ -3738,7 +3738,7 @@ class ServeManager {
|
|
|
3738
3738
|
/**
|
|
3739
3739
|
* Get the public URL for a mount (mount-specific subdomain).
|
|
3740
3740
|
* For `access: 'link'` mounts, the subdomain itself carries the capability —
|
|
3741
|
-
* the tunnel registers a long random suffix (~
|
|
3741
|
+
* the tunnel registers a long random suffix (~88 bits of entropy (randomBytes(11), 22 hex chars)), so the
|
|
3742
3742
|
* URL is identical in shape to other tiers, just longer. Content serves
|
|
3743
3743
|
* from the root, so HTML with absolute paths (`/style.css`, `/app.js`)
|
|
3744
3744
|
* works unchanged.
|
|
@@ -8332,7 +8332,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
8332
8332
|
}
|
|
8333
8333
|
const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
|
|
8334
8334
|
const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
|
|
8335
|
-
const { toolsForRole } = await import('./sideband
|
|
8335
|
+
const { toolsForRole } = await import('./sideband--9vWYqKA.mjs');
|
|
8336
8336
|
const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
|
|
8337
8337
|
return fmt(r2);
|
|
8338
8338
|
}
|
|
@@ -8421,6 +8421,33 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
8421
8421
|
};
|
|
8422
8422
|
const _caps = statelessDispatchCaps();
|
|
8423
8423
|
const statelessLimiter = new StatelessDispatchLimiter(_caps.concurrent, _caps.perSender);
|
|
8424
|
+
const MAX_RECEIVE_POLLS_PER_CHANNEL = Math.max(
|
|
8425
|
+
1,
|
|
8426
|
+
Number(process.env.SVAMP_MAX_CHANNEL_RECEIVE_POLLS) || 16
|
|
8427
|
+
);
|
|
8428
|
+
const _receivePolls = /* @__PURE__ */ new Map();
|
|
8429
|
+
const acquireReceiveSlot = (channelId) => {
|
|
8430
|
+
const n = _receivePolls.get(channelId) || 0;
|
|
8431
|
+
if (n >= MAX_RECEIVE_POLLS_PER_CHANNEL) return false;
|
|
8432
|
+
_receivePolls.set(channelId, n + 1);
|
|
8433
|
+
return true;
|
|
8434
|
+
};
|
|
8435
|
+
const releaseReceiveSlot = (channelId) => {
|
|
8436
|
+
const n = (_receivePolls.get(channelId) || 1) - 1;
|
|
8437
|
+
if (n <= 0) _receivePolls.delete(channelId);
|
|
8438
|
+
else _receivePolls.set(channelId, n);
|
|
8439
|
+
};
|
|
8440
|
+
const _outboxCache = /* @__PURE__ */ new Map();
|
|
8441
|
+
const getOutbox = (dir) => {
|
|
8442
|
+
let ob = _outboxCache.get(dir);
|
|
8443
|
+
if (!ob) {
|
|
8444
|
+
ob = new ChannelOutbox(dir);
|
|
8445
|
+
_outboxCache.set(dir, ob);
|
|
8446
|
+
} else {
|
|
8447
|
+
ob.reload();
|
|
8448
|
+
}
|
|
8449
|
+
return ob;
|
|
8450
|
+
};
|
|
8424
8451
|
const dispatchStateless = async (c, dir, kwargs, context) => {
|
|
8425
8452
|
const u = context?.user;
|
|
8426
8453
|
const r = resolveSender(c, {
|
|
@@ -8437,7 +8464,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
8437
8464
|
return { ok: false, call_id: callId, status: "busy", error: "channel is busy (too many concurrent requests) \u2014 retry shortly" };
|
|
8438
8465
|
}
|
|
8439
8466
|
const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
|
|
8440
|
-
const { queryCore } = await import('./commands-
|
|
8467
|
+
const { queryCore } = await import('./commands-C2X-uElg.mjs');
|
|
8441
8468
|
const timeout = c.reply?.timeout_sec || 120;
|
|
8442
8469
|
let result;
|
|
8443
8470
|
let thrownSessionId;
|
|
@@ -8539,15 +8566,22 @@ ${d?.error || "not found"}`;
|
|
|
8539
8566
|
const waitRaw = Number(kwargs.wait ?? 25);
|
|
8540
8567
|
const waitSec = Number.isFinite(waitRaw) ? waitRaw : 25;
|
|
8541
8568
|
const waitMs = Math.min(Math.max(0, waitSec * 1e3), 6e4);
|
|
8542
|
-
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
|
|
8569
|
+
if (!acquireReceiveSlot(c.id)) {
|
|
8570
|
+
return { error: "busy: too many concurrent receive polls on this channel \u2014 retry shortly", retryable: true };
|
|
8571
|
+
}
|
|
8572
|
+
try {
|
|
8573
|
+
const outbox = getOutbox(dir);
|
|
8574
|
+
const deadline = Date.now() + waitMs;
|
|
8575
|
+
for (; ; ) {
|
|
8576
|
+
const replies = outbox.since(c.id, cursor, r.sender.name, kwargs.correlationId);
|
|
8577
|
+
if (replies.length || Date.now() >= deadline) {
|
|
8578
|
+
return { ok: true, replies, cursor: outbox.cursor(c.id) };
|
|
8579
|
+
}
|
|
8580
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
8581
|
+
outbox.reload();
|
|
8548
8582
|
}
|
|
8549
|
-
|
|
8550
|
-
|
|
8583
|
+
} finally {
|
|
8584
|
+
releaseReceiveSlot(c.id);
|
|
8551
8585
|
}
|
|
8552
8586
|
},
|
|
8553
8587
|
// Safety-restricted file upload (#0093). Deny-by-default: only channels whose
|
|
@@ -15783,8 +15817,28 @@ const SENSITIVE_ENV_VARS = [
|
|
|
15783
15817
|
"GH_TOKEN",
|
|
15784
15818
|
"NPM_TOKEN",
|
|
15785
15819
|
"DOCKER_PASSWORD",
|
|
15786
|
-
"DOCKER_CONFIG"
|
|
15820
|
+
"DOCKER_CONFIG",
|
|
15821
|
+
// #1110: svamp's own persisted credentials (written by `svamp daemon codex-auth` /
|
|
15822
|
+
// `kimi-auth` / `wise-agent auth`, and by the generic LLM_* aliases).
|
|
15823
|
+
"OPENAI_API_KEY",
|
|
15824
|
+
"GEMINI_API_KEY",
|
|
15825
|
+
"XAI_API_KEY",
|
|
15826
|
+
"ANTHROPIC_ADMIN_KEY",
|
|
15827
|
+
"LLM_API_KEY",
|
|
15828
|
+
"CLOUDFLARE_API_TOKEN",
|
|
15829
|
+
"R2_ACCESS_KEY_ID",
|
|
15830
|
+
"R2_SECRET_ACCESS_KEY",
|
|
15831
|
+
"X_API_KEY"
|
|
15787
15832
|
];
|
|
15833
|
+
const CREDENTIAL_NAME_RE = /(^|_)(KEY|APIKEY|TOKEN|SECRET|PASSWORD|CREDENTIALS)$/;
|
|
15834
|
+
const CREDENTIAL_SWEEP_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
15835
|
+
"ANTHROPIC_API_KEY",
|
|
15836
|
+
"ANTHROPIC_AUTH_TOKEN"
|
|
15837
|
+
]);
|
|
15838
|
+
function isCredentialEnvName(key) {
|
|
15839
|
+
if (CREDENTIAL_SWEEP_ALLOWLIST.has(key)) return false;
|
|
15840
|
+
return CREDENTIAL_NAME_RE.test(key);
|
|
15841
|
+
}
|
|
15788
15842
|
async function stageCredentialsForSharing(sessionId) {
|
|
15789
15843
|
const realHome = homedir$1();
|
|
15790
15844
|
const realClaudeDir = join$1(realHome, ".claude");
|
|
@@ -15858,6 +15912,9 @@ function sanitizeEnvForSharing(env) {
|
|
|
15858
15912
|
for (const key of SENSITIVE_ENV_VARS) {
|
|
15859
15913
|
delete sanitized[key];
|
|
15860
15914
|
}
|
|
15915
|
+
for (const key of Object.keys(sanitized)) {
|
|
15916
|
+
if (isCredentialEnvName(key)) delete sanitized[key];
|
|
15917
|
+
}
|
|
15861
15918
|
return sanitized;
|
|
15862
15919
|
}
|
|
15863
15920
|
async function sweepOrphanedStagedHomes(activeSessionIds) {
|
|
@@ -15900,6 +15957,7 @@ async function copyDirRecursive(src, dest) {
|
|
|
15900
15957
|
|
|
15901
15958
|
var credentialStaging = /*#__PURE__*/Object.freeze({
|
|
15902
15959
|
__proto__: null,
|
|
15960
|
+
isCredentialEnvName: isCredentialEnvName,
|
|
15903
15961
|
sanitizeEnvForSharing: sanitizeEnvForSharing,
|
|
15904
15962
|
stageCredentialsForSharing: stageCredentialsForSharing,
|
|
15905
15963
|
sweepOrphanedStagedHomes: sweepOrphanedStagedHomes
|
|
@@ -17092,7 +17150,8 @@ function planLogPrune(files, policy = DEFAULT_LOG_PRUNE_POLICY, nowMs = Date.now
|
|
|
17092
17150
|
const overCount = keepFiles > 0 ? perStart.slice(keepFiles) : perStart;
|
|
17093
17151
|
const tooOld = maxAgeMs > 0 ? perStart.filter((f) => nowMs - f.mtimeMs > maxAgeMs) : [];
|
|
17094
17152
|
const deleteFiles = [...new Set([...overCount, ...tooOld].map((f) => f.name))];
|
|
17095
|
-
const
|
|
17153
|
+
const doomed = new Set(deleteFiles);
|
|
17154
|
+
const truncateFiles = files.filter((f) => (APPEND_ONLY_LOGS.includes(f.name) || isPerStartLog(f.name)) && !doomed.has(f.name)).filter((f) => policy.maxBytes > 0 && f.size > policy.maxBytes).map((f) => ({ name: f.name, size: f.size }));
|
|
17096
17155
|
return { deleteFiles, truncateFiles };
|
|
17097
17156
|
}
|
|
17098
17157
|
function resolveLogPrunePolicy(env = process.env) {
|
|
@@ -17114,6 +17173,40 @@ function tailSlice(buf, tailBytes) {
|
|
|
17114
17173
|
return nl >= 0 && nl + 1 < cut.length ? cut.subarray(nl + 1) : cut;
|
|
17115
17174
|
}
|
|
17116
17175
|
|
|
17176
|
+
const CARRIER_FIELDS = ["message", "error", "detail", "reason", "description"];
|
|
17177
|
+
function formatLogArg(a) {
|
|
17178
|
+
if (typeof a === "string") return a;
|
|
17179
|
+
if (a instanceof Error) return a.stack || `${a.name}: ${a.message}`;
|
|
17180
|
+
if (a === void 0) return "undefined";
|
|
17181
|
+
if (a === null) return "null";
|
|
17182
|
+
try {
|
|
17183
|
+
const s = JSON.stringify(a);
|
|
17184
|
+
if (s === void 0 || s === "{}") return String(a);
|
|
17185
|
+
return s;
|
|
17186
|
+
} catch {
|
|
17187
|
+
try {
|
|
17188
|
+
return String(a);
|
|
17189
|
+
} catch {
|
|
17190
|
+
return "[unserializable]";
|
|
17191
|
+
}
|
|
17192
|
+
}
|
|
17193
|
+
}
|
|
17194
|
+
function formatLogArgs(args) {
|
|
17195
|
+
return args.map(formatLogArg).join(" ");
|
|
17196
|
+
}
|
|
17197
|
+
function describeRejectionReason(reason) {
|
|
17198
|
+
if (typeof reason === "string") return reason;
|
|
17199
|
+
if (reason instanceof Error) return `${reason.name}: ${reason.message}`;
|
|
17200
|
+
if (reason && typeof reason === "object") {
|
|
17201
|
+
for (const f of CARRIER_FIELDS) {
|
|
17202
|
+
const v = reason[f];
|
|
17203
|
+
if (typeof v === "string" && v.trim() !== "") return v;
|
|
17204
|
+
if (v instanceof Error) return `${v.name}: ${v.message}`;
|
|
17205
|
+
}
|
|
17206
|
+
}
|
|
17207
|
+
return formatLogArg(reason);
|
|
17208
|
+
}
|
|
17209
|
+
|
|
17117
17210
|
function isWorkflowEnabled(wf) {
|
|
17118
17211
|
return wf.enabled !== false;
|
|
17119
17212
|
}
|
|
@@ -17135,6 +17228,12 @@ function validateWorkflowName(name) {
|
|
|
17135
17228
|
function workflowPath(projectRoot, name) {
|
|
17136
17229
|
return join$1(workflowsDir(projectRoot), `${validateWorkflowName(name)}.yaml`);
|
|
17137
17230
|
}
|
|
17231
|
+
function resolveWorkflowPath(projectRoot, name) {
|
|
17232
|
+
const canonical = workflowPath(projectRoot, name);
|
|
17233
|
+
if (existsSync(canonical)) return canonical;
|
|
17234
|
+
const alt = join$1(workflowsDir(projectRoot), `${validateWorkflowName(name)}.yml`);
|
|
17235
|
+
return existsSync(alt) ? alt : canonical;
|
|
17236
|
+
}
|
|
17138
17237
|
function normalizeOn(on) {
|
|
17139
17238
|
if (!on || typeof on !== "object") {
|
|
17140
17239
|
return void 0;
|
|
@@ -17231,7 +17330,7 @@ function listWorkflows(projectRoot) {
|
|
|
17231
17330
|
function getWorkflow(projectRoot, name) {
|
|
17232
17331
|
let p;
|
|
17233
17332
|
try {
|
|
17234
|
-
p =
|
|
17333
|
+
p = resolveWorkflowPath(projectRoot, name);
|
|
17235
17334
|
} catch {
|
|
17236
17335
|
return null;
|
|
17237
17336
|
}
|
|
@@ -17245,7 +17344,7 @@ function getWorkflow(projectRoot, name) {
|
|
|
17245
17344
|
function rawWorkflow(projectRoot, name) {
|
|
17246
17345
|
let p;
|
|
17247
17346
|
try {
|
|
17248
|
-
p =
|
|
17347
|
+
p = resolveWorkflowPath(projectRoot, name);
|
|
17249
17348
|
} catch {
|
|
17250
17349
|
return null;
|
|
17251
17350
|
}
|
|
@@ -17258,6 +17357,13 @@ function saveWorkflow(projectRoot, wf) {
|
|
|
17258
17357
|
const tmp = `${path}.tmp-${process.pid}-${randomBytes(4).toString("hex")}`;
|
|
17259
17358
|
writeFileSync$1(tmp, serializeWorkflow(wf));
|
|
17260
17359
|
renameSync(tmp, path);
|
|
17360
|
+
const alt = join$1(dir, `${validateWorkflowName(wf.name)}.yml`);
|
|
17361
|
+
if (alt !== path && existsSync(alt)) {
|
|
17362
|
+
try {
|
|
17363
|
+
unlinkSync$1(alt);
|
|
17364
|
+
} catch {
|
|
17365
|
+
}
|
|
17366
|
+
}
|
|
17261
17367
|
}
|
|
17262
17368
|
function setWorkflowEnabled(projectRoot, name, enabled) {
|
|
17263
17369
|
const wf = getWorkflow(projectRoot, name);
|
|
@@ -17269,7 +17375,7 @@ function setWorkflowEnabled(projectRoot, name, enabled) {
|
|
|
17269
17375
|
return next;
|
|
17270
17376
|
}
|
|
17271
17377
|
function removeWorkflow(projectRoot, name) {
|
|
17272
|
-
const p =
|
|
17378
|
+
const p = resolveWorkflowPath(projectRoot, name);
|
|
17273
17379
|
if (!existsSync(p)) return false;
|
|
17274
17380
|
try {
|
|
17275
17381
|
unlinkSync$1(p);
|
|
@@ -19328,17 +19434,23 @@ function isLoopActive(directory, sessionId) {
|
|
|
19328
19434
|
const s = readLoopState(directory, sessionId);
|
|
19329
19435
|
return !!s && s.active !== false && s.phase !== "dormant" && !isTerminalLoopPhase(s.phase);
|
|
19330
19436
|
}
|
|
19331
|
-
function loopOwnerSession(directory, sessionId) {
|
|
19332
|
-
const s = readLoopState(directory, sessionId);
|
|
19333
|
-
if (!s || s.active === false || s.phase === "dormant" || isTerminalLoopPhase(s.phase)) return null;
|
|
19334
|
-
return typeof s.session_id === "string" ? s.session_id : null;
|
|
19335
|
-
}
|
|
19336
19437
|
function isLoopActiveForSession(directory, sessionId) {
|
|
19337
19438
|
const s = readLoopState(directory, sessionId);
|
|
19338
19439
|
if (!s || s.active === false || s.phase === "dormant" || isTerminalLoopPhase(s.phase)) return false;
|
|
19339
19440
|
if (typeof s.session_id !== "string") return true;
|
|
19340
19441
|
return s.session_id === sessionId;
|
|
19341
19442
|
}
|
|
19443
|
+
function loopExistsForSession(directory, sessionId) {
|
|
19444
|
+
const s = readLoopState(directory, sessionId);
|
|
19445
|
+
if (!s || s.active === false || isTerminalLoopPhase(s.phase)) return false;
|
|
19446
|
+
if (typeof s.session_id !== "string") return true;
|
|
19447
|
+
return s.session_id === sessionId;
|
|
19448
|
+
}
|
|
19449
|
+
function loopOwnerSessionIncludingDormant(directory, sessionId) {
|
|
19450
|
+
const s = readLoopState(directory, sessionId);
|
|
19451
|
+
if (!s || s.active === false || isTerminalLoopPhase(s.phase)) return null;
|
|
19452
|
+
return typeof s.session_id === "string" ? s.session_id : null;
|
|
19453
|
+
}
|
|
19342
19454
|
function isLoopArmedForSession(directory, sessionId) {
|
|
19343
19455
|
const s = readLoopState(directory, sessionId);
|
|
19344
19456
|
if (!s || s.active === false || s.phase !== "dormant") return false;
|
|
@@ -20052,7 +20164,7 @@ function ensureHomeDir() {
|
|
|
20052
20164
|
mkdirSync(LOGS_DIR, { recursive: true });
|
|
20053
20165
|
}
|
|
20054
20166
|
}
|
|
20055
|
-
function pruneDaemonLogs() {
|
|
20167
|
+
function pruneDaemonLogs(exclude = []) {
|
|
20056
20168
|
try {
|
|
20057
20169
|
const policy = resolveLogPrunePolicy(process.env);
|
|
20058
20170
|
const entries = readdirSync$1(LOGS_DIR).map((name) => {
|
|
@@ -20063,7 +20175,7 @@ function pruneDaemonLogs() {
|
|
|
20063
20175
|
return null;
|
|
20064
20176
|
}
|
|
20065
20177
|
}).filter((e) => e !== null);
|
|
20066
|
-
const plan = planLogPrune(entries, policy);
|
|
20178
|
+
const plan = planLogPrune(entries, policy, Date.now(), exclude);
|
|
20067
20179
|
for (const name of plan.deleteFiles) {
|
|
20068
20180
|
try {
|
|
20069
20181
|
unlinkSync(join(LOGS_DIR, name));
|
|
@@ -20085,10 +20197,13 @@ function createLogger() {
|
|
|
20085
20197
|
ensureHomeDir();
|
|
20086
20198
|
pruneDaemonLogs();
|
|
20087
20199
|
const logFile = join(LOGS_DIR, `daemon-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.log`);
|
|
20200
|
+
const sweepMs = Math.max(6e4, Number(process.env.SVAMP_LOG_PRUNE_INTERVAL_MS) || 36e5);
|
|
20201
|
+
const sweepTimer = setInterval(() => pruneDaemonLogs([basename$1(logFile)]), sweepMs);
|
|
20202
|
+
if (typeof sweepTimer.unref === "function") sweepTimer.unref();
|
|
20088
20203
|
return {
|
|
20089
20204
|
logFilePath: logFile,
|
|
20090
20205
|
log: (...args) => {
|
|
20091
|
-
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${args
|
|
20206
|
+
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${formatLogArgs(args)}
|
|
20092
20207
|
`;
|
|
20093
20208
|
fs$1.appendFile(logFile, line).catch(() => {
|
|
20094
20209
|
});
|
|
@@ -20097,7 +20212,7 @@ function createLogger() {
|
|
|
20097
20212
|
}
|
|
20098
20213
|
},
|
|
20099
20214
|
error: (...args) => {
|
|
20100
|
-
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${args
|
|
20215
|
+
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ERROR: ${formatLogArgs(args)}
|
|
20101
20216
|
`;
|
|
20102
20217
|
fs$1.appendFile(logFile, line).catch(() => {
|
|
20103
20218
|
});
|
|
@@ -20254,7 +20369,7 @@ async function startDaemon(options) {
|
|
|
20254
20369
|
const UNHANDLED_REJECTION_WINDOW_MS = 6e4;
|
|
20255
20370
|
process.on("unhandledRejection", (reason) => {
|
|
20256
20371
|
if (shutdownRequested) return;
|
|
20257
|
-
const msg =
|
|
20372
|
+
const msg = describeRejectionReason(reason);
|
|
20258
20373
|
logger.error("Unhandled rejection:", reason);
|
|
20259
20374
|
const isTransient = TRANSIENT_REJECTION_PATTERNS.some((p) => msg.toLowerCase().includes(p.toLowerCase()));
|
|
20260
20375
|
const isSessionLoss = msg.toLowerCase().includes("session does not exist");
|
|
@@ -20383,7 +20498,7 @@ async function startDaemon(options) {
|
|
|
20383
20498
|
try {
|
|
20384
20499
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
20385
20500
|
if (!dir) return;
|
|
20386
|
-
const { reconcileServiceLinks } = await import('./agentCommands-
|
|
20501
|
+
const { reconcileServiceLinks } = await import('./agentCommands-DD47Krr1.mjs');
|
|
20387
20502
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
20388
20503
|
const config = readSvampConfig(configPath);
|
|
20389
20504
|
const entries = Array.from(urls.entries());
|
|
@@ -20405,7 +20520,7 @@ async function startDaemon(options) {
|
|
|
20405
20520
|
try {
|
|
20406
20521
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
20407
20522
|
if (!dir) return;
|
|
20408
|
-
const { reconcileServiceLinks } = await import('./agentCommands-
|
|
20523
|
+
const { reconcileServiceLinks } = await import('./agentCommands-DD47Krr1.mjs');
|
|
20409
20524
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
20410
20525
|
const config = readSvampConfig(configPath);
|
|
20411
20526
|
const incoming = [{
|
|
@@ -20426,7 +20541,7 @@ async function startDaemon(options) {
|
|
|
20426
20541
|
try {
|
|
20427
20542
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
20428
20543
|
if (!dir) return;
|
|
20429
|
-
const { dropServiceLinks } = await import('./agentCommands-
|
|
20544
|
+
const { dropServiceLinks } = await import('./agentCommands-DD47Krr1.mjs');
|
|
20430
20545
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
20431
20546
|
const config = readSvampConfig(configPath);
|
|
20432
20547
|
if (dropServiceLinks(config, "serve", mountName)) {
|
|
@@ -22879,11 +22994,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
22879
22994
|
});
|
|
22880
22995
|
},
|
|
22881
22996
|
onIssue: async (params) => {
|
|
22882
|
-
const { issueRpc } = await import('./rpc-
|
|
22997
|
+
const { issueRpc } = await import('./rpc-DObWvEis.mjs');
|
|
22883
22998
|
return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
|
|
22884
22999
|
},
|
|
22885
23000
|
onWorkflow: async (params) => {
|
|
22886
|
-
const { workflowRpc } = await import('./rpc-
|
|
23001
|
+
const { workflowRpc } = await import('./rpc-Bv6_c-xW.mjs');
|
|
22887
23002
|
return workflowRpc(params?.cwd || directory, params || {});
|
|
22888
23003
|
},
|
|
22889
23004
|
onRipgrep: async (args, cwd) => {
|
|
@@ -23108,8 +23223,21 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
23108
23223
|
verify_errors: 0,
|
|
23109
23224
|
// fresh verification budget on re-arm
|
|
23110
23225
|
stall_hinted: false,
|
|
23111
|
-
resumed_at: Date.now()
|
|
23226
|
+
resumed_at: Date.now(),
|
|
23112
23227
|
// #0156: re-arm the stall hint
|
|
23228
|
+
// A re-arm starts a NEW work batch, so the previous batch's progress
|
|
23229
|
+
// baseline must not carry over. assessLoopProgress tracks a MONOTONIC
|
|
23230
|
+
// MINIMUM over the retained history, and a durable loop only parks
|
|
23231
|
+
// dormant once the oracle reads 0 pending — so the old tail is
|
|
23232
|
+
// `pending: 0` and best === 0 forever. Without this reset the first
|
|
23233
|
+
// new marker (pending >= 1) can never beat it, the loop reads STUCK
|
|
23234
|
+
// from checkpoint 3 onward while it is genuinely resolving issues,
|
|
23235
|
+
// `auto_resumes` never resets (updateLoopProgress keys that off the
|
|
23236
|
+
// same signal), and the finite #0958 cap burns down to a terminal
|
|
23237
|
+
// gave_up. That contradicts the invariant that a slow-but-PRODUCTIVE
|
|
23238
|
+
// loop is never killed by the cap.
|
|
23239
|
+
progress_history: [],
|
|
23240
|
+
auto_resumes: 0
|
|
23113
23241
|
});
|
|
23114
23242
|
} catch {
|
|
23115
23243
|
}
|
|
@@ -23591,11 +23719,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
23591
23719
|
});
|
|
23592
23720
|
},
|
|
23593
23721
|
onIssue: async (params) => {
|
|
23594
|
-
const { issueRpc } = await import('./rpc-
|
|
23722
|
+
const { issueRpc } = await import('./rpc-DObWvEis.mjs');
|
|
23595
23723
|
return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
|
|
23596
23724
|
},
|
|
23597
23725
|
onWorkflow: async (params) => {
|
|
23598
|
-
const { workflowRpc } = await import('./rpc-
|
|
23726
|
+
const { workflowRpc } = await import('./rpc-Bv6_c-xW.mjs');
|
|
23599
23727
|
return workflowRpc(params?.cwd || directory, params || {});
|
|
23600
23728
|
},
|
|
23601
23729
|
onRipgrep: async (args, cwd) => {
|
|
@@ -23938,7 +24066,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
23938
24066
|
};
|
|
23939
24067
|
try {
|
|
23940
24068
|
if (!ls.acp_budget_warned && acpCumTokens === 0 && (ledger?.turns || 0) >= 1 && ls.budget && (ls.budget.max_tokens || ls.budget.max_tokens_per_hour)) {
|
|
23941
|
-
sessionService.pushMessage({ type: "message", message: "\u26A0\uFE0F
|
|
24069
|
+
sessionService.pushMessage({ type: "message", message: "\u26A0\uFE0F The token/rate cost cap (--max-tokens-per-hour) is INERT for this agent \u2014 it exposes no token usage, so this loop is bounded only by --max (iterations) and --max-runtime-sec. Set one of those to cap cost.", level: "warning" }, "event");
|
|
23942
24070
|
ls.acp_budget_warned = true;
|
|
23943
24071
|
}
|
|
23944
24072
|
const acpMaxExt = resolveMaxExtensions(process.env.SVAMP_LOOP_MAX_EXTENSIONS);
|
|
@@ -24259,7 +24387,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24259
24387
|
const wasInMemory = teardownTrackedSession(sessionId);
|
|
24260
24388
|
idleTriggerTracker.forget(sessionId);
|
|
24261
24389
|
const markedArchived = markSessionAsArchived(sessionId);
|
|
24262
|
-
if (loopDir &&
|
|
24390
|
+
if (loopDir && loopExistsForSession(loopDir, sessionId)) {
|
|
24263
24391
|
deactivateLoop(loopDir, sessionId);
|
|
24264
24392
|
logger.log(`Deactivated loop for archived session ${sessionId}`);
|
|
24265
24393
|
}
|
|
@@ -24317,7 +24445,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24317
24445
|
teardownTrackedSession(sessionId);
|
|
24318
24446
|
idleTriggerTracker.forget(sessionId);
|
|
24319
24447
|
deletePersistedSession(sessionId);
|
|
24320
|
-
if (loopDir &&
|
|
24448
|
+
if (loopDir && loopExistsForSession(loopDir, sessionId)) {
|
|
24321
24449
|
deactivateLoop(loopDir, sessionId);
|
|
24322
24450
|
}
|
|
24323
24451
|
logger.log(`Session ${sessionId} deleted`);
|
|
@@ -24658,7 +24786,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24658
24786
|
try {
|
|
24659
24787
|
for (const ent of readdirSync$1(join(p.directory, ".svamp"), { withFileTypes: true })) {
|
|
24660
24788
|
if (!ent.isDirectory() || knownSessionIds.has(ent.name)) continue;
|
|
24661
|
-
const owner =
|
|
24789
|
+
const owner = loopOwnerSessionIncludingDormant(p.directory, ent.name);
|
|
24662
24790
|
if (owner && !knownSessionIds.has(owner)) {
|
|
24663
24791
|
deactivateLoop(p.directory, ent.name);
|
|
24664
24792
|
logger.log(`[loop] Deactivated stale loop-state for ${ent.name} in ${p.directory} (owner no longer known)`);
|
|
@@ -24666,7 +24794,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24666
24794
|
}
|
|
24667
24795
|
} catch {
|
|
24668
24796
|
}
|
|
24669
|
-
const legacyOwner =
|
|
24797
|
+
const legacyOwner = loopOwnerSessionIncludingDormant(p.directory);
|
|
24670
24798
|
if (legacyOwner && !knownSessionIds.has(legacyOwner)) {
|
|
24671
24799
|
deactivateLoop(p.directory);
|
|
24672
24800
|
logger.log(`[loop] Deactivated stale legacy loop-state in ${p.directory} (owner session ${legacyOwner} no longer known)`);
|
|
@@ -24727,7 +24855,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24727
24855
|
try {
|
|
24728
24856
|
const lp = join(getLoopDir(persisted.directory, persisted.sessionId), "loop-state.json");
|
|
24729
24857
|
const cur = readLoopState(persisted.directory, persisted.sessionId);
|
|
24730
|
-
if (cur) atomicWriteLoopState(lp, { ...cur, active: true, phase: "continue", completed_at: void 0, verify_errors: 0, resumed_at: Date.now() });
|
|
24858
|
+
if (cur) atomicWriteLoopState(lp, { ...cur, active: true, phase: "continue", completed_at: void 0, verify_errors: 0, resumed_at: Date.now(), progress_history: [], auto_resumes: 0 });
|
|
24731
24859
|
} catch {
|
|
24732
24860
|
}
|
|
24733
24861
|
}
|
|
@@ -24865,13 +24993,16 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24865
24993
|
}
|
|
24866
24994
|
if (sessionsToLoopResume.length > 0 && !options?.noAutoContinue) {
|
|
24867
24995
|
logger.log(`Resuming loop for ${sessionsToLoopResume.length} session(s)...`);
|
|
24868
|
-
|
|
24996
|
+
const LOOP_RESUME_STEP_MS = Number(process.env.SVAMP_AUTO_CONTINUE_STEP_MS) || 300;
|
|
24997
|
+
const LOOP_RESUME_MAX_SPREAD_MS = Number(process.env.SVAMP_AUTO_CONTINUE_MAX_SPREAD_MS) || 6e4;
|
|
24998
|
+
sessionsToLoopResume.forEach(({ sessionId, directory: sessDir }, loopResumeIndex) => {
|
|
24999
|
+
const loopResumeDelay = 2e3 + Math.min(loopResumeIndex * LOOP_RESUME_STEP_MS, LOOP_RESUME_MAX_SPREAD_MS) + Math.floor(Math.random() * LOOP_RESUME_STEP_MS);
|
|
24869
25000
|
try {
|
|
24870
25001
|
const tracked = Array.from(pidToTrackedSession.values()).find((s) => s.svampSessionId === sessionId);
|
|
24871
25002
|
const rpc = tracked?.sessionRPCHandlers;
|
|
24872
25003
|
if (!rpc) {
|
|
24873
25004
|
logger.log(`Session ${sessionId} RPC handlers not found for loop resume`);
|
|
24874
|
-
|
|
25005
|
+
return;
|
|
24875
25006
|
}
|
|
24876
25007
|
const loopTurnFingerprint = () => {
|
|
24877
25008
|
try {
|
|
@@ -24897,7 +25028,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24897
25028
|
if (!isLoopActiveForSession(sessDir, sessionId)) return;
|
|
24898
25029
|
const fpBefore = loopTurnFingerprint();
|
|
24899
25030
|
await sendResume("");
|
|
24900
|
-
const graceMs = Math.max(5e3, Number(process.env.SVAMP_LOOP_RESUME_WATCHDOG_MS) || 45e3);
|
|
25031
|
+
const graceMs = Math.max(5e3, Number(process.env.SVAMP_LOOP_RESUME_WATCHDOG_MS) || 45e3) + Math.min(loopResumeIndex * LOOP_RESUME_STEP_MS, LOOP_RESUME_MAX_SPREAD_MS);
|
|
24901
25032
|
setTimeout(() => {
|
|
24902
25033
|
try {
|
|
24903
25034
|
if (!isLoopActiveForSession(sessDir, sessionId)) return;
|
|
@@ -24914,11 +25045,11 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24914
25045
|
} catch (err) {
|
|
24915
25046
|
logger.log(`Failed to resume loop for session ${sessionId}: ${err.message}`);
|
|
24916
25047
|
}
|
|
24917
|
-
},
|
|
25048
|
+
}, loopResumeDelay);
|
|
24918
25049
|
} catch (err) {
|
|
24919
25050
|
logger.log(`Failed to find session service for loop resume ${sessionId}: ${err.message}`);
|
|
24920
25051
|
}
|
|
24921
|
-
}
|
|
25052
|
+
});
|
|
24922
25053
|
}
|
|
24923
25054
|
(async () => {
|
|
24924
25055
|
try {
|
|
@@ -24928,27 +25059,17 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24928
25059
|
logger.log(`[ARTIFACT SYNC] Background init failed: ${err.message}`);
|
|
24929
25060
|
}
|
|
24930
25061
|
})();
|
|
24931
|
-
let appToken;
|
|
24932
|
-
try {
|
|
24933
|
-
appToken = await server.generateToken({});
|
|
24934
|
-
logger.log(`App connection token generated`);
|
|
24935
|
-
} catch (err) {
|
|
24936
|
-
logger.log("Could not generate token (server may not support it):", err);
|
|
24937
|
-
}
|
|
24938
25062
|
console.log("Svamp daemon started successfully!");
|
|
24939
25063
|
console.log(` Machine ID: ${machineId}`);
|
|
24940
25064
|
console.log(` Hypha server: ${hyphaServerUrl}`);
|
|
24941
25065
|
console.log(` Workspace: ${server.config.workspace}`);
|
|
24942
|
-
if (appToken) {
|
|
24943
|
-
console.log(` App token: ${appToken}`);
|
|
24944
|
-
}
|
|
24945
25066
|
console.log(` Service: svamp-machine-${machineId}`);
|
|
24946
25067
|
console.log(` Log file: ${logger.logFilePath}`);
|
|
24947
25068
|
const HEARTBEAT_INTERVAL_MS = 1e4;
|
|
24948
25069
|
const PING_TIMEOUT_MS = 15e3;
|
|
24949
25070
|
const POST_RECONNECT_GRACE_MS = 2e4;
|
|
24950
25071
|
const RECONNECT_JITTER_MS = 2500;
|
|
24951
|
-
const { WorkflowScheduler } = await import('./scheduler-
|
|
25072
|
+
const { WorkflowScheduler } = await import('./scheduler-BvtNZ0pl.mjs');
|
|
24952
25073
|
const workflowProjectRoots = () => {
|
|
24953
25074
|
const dirs = /* @__PURE__ */ new Set();
|
|
24954
25075
|
for (const s of pidToTrackedSession.values()) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f as resolveProjectRoot, D as listWorkflows, E as isWorkflowEnabled, F as workflowSchedules, G as inZone, w as runWorkflow, H as cronMatches } from './run-
|
|
1
|
+
import { f as resolveProjectRoot, D as listWorkflows, E as isWorkflowEnabled, F as workflowSchedules, G as inZone, w as runWorkflow, H as cronMatches } from './run-DGhVoN3s.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
|
-
import { w as wantsHelp } from './cli-
|
|
3
|
-
import './run-
|
|
2
|
+
import { w as wantsHelp } from './cli-CdYVO7ce.mjs';
|
|
3
|
+
import './run-DGhVoN3s.mjs';
|
|
4
4
|
import 'os';
|
|
5
5
|
import 'fs/promises';
|
|
6
6
|
import 'fs';
|
|
@@ -77,7 +77,7 @@ async function handleServeCommand() {
|
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
async function serveAdd(args, machineId) {
|
|
80
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
80
|
+
const { connectAndGetMachine } = await import('./commands-C2X-uElg.mjs');
|
|
81
81
|
const pos = positionalArgs(args);
|
|
82
82
|
const name = pos[0];
|
|
83
83
|
if (!name) {
|
|
@@ -110,7 +110,7 @@ async function serveAdd(args, machineId) {
|
|
|
110
110
|
}
|
|
111
111
|
if (sessionId && result?.url) {
|
|
112
112
|
try {
|
|
113
|
-
const { autoAddSessionLink } = await import('./agentCommands-
|
|
113
|
+
const { autoAddSessionLink } = await import('./agentCommands-DD47Krr1.mjs');
|
|
114
114
|
autoAddSessionLink(String(result.url), name, void 0, { kind: "serve", name });
|
|
115
115
|
} catch {
|
|
116
116
|
}
|
|
@@ -124,7 +124,7 @@ async function serveAdd(args, machineId) {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
async function serveApply(args, machineId) {
|
|
127
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
127
|
+
const { connectAndGetMachine } = await import('./commands-C2X-uElg.mjs');
|
|
128
128
|
const fs = await import('fs');
|
|
129
129
|
const yaml = await import('yaml');
|
|
130
130
|
const file = positionalArgs(args)[0];
|
|
@@ -209,7 +209,7 @@ async function serveApply(args, machineId) {
|
|
|
209
209
|
console.log(`URL: ${result.url}`);
|
|
210
210
|
if (params.sessionId && result?.url) {
|
|
211
211
|
try {
|
|
212
|
-
const { autoAddSessionLink } = await import('./agentCommands-
|
|
212
|
+
const { autoAddSessionLink } = await import('./agentCommands-DD47Krr1.mjs');
|
|
213
213
|
const prevSession = process.env.SVAMP_SESSION_ID;
|
|
214
214
|
process.env.SVAMP_SESSION_ID = String(params.sessionId);
|
|
215
215
|
try {
|
|
@@ -230,7 +230,7 @@ async function serveApply(args, machineId) {
|
|
|
230
230
|
}
|
|
231
231
|
}
|
|
232
232
|
async function serveRemove(args, machineId) {
|
|
233
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
233
|
+
const { connectAndGetMachine } = await import('./commands-C2X-uElg.mjs');
|
|
234
234
|
const pos = positionalArgs(args);
|
|
235
235
|
const name = pos[0];
|
|
236
236
|
if (!name) {
|
|
@@ -240,7 +240,7 @@ async function serveRemove(args, machineId) {
|
|
|
240
240
|
const { machine, server } = await connectAndGetMachine(machineId);
|
|
241
241
|
try {
|
|
242
242
|
await machine.serveRemove({ name });
|
|
243
|
-
const { removeSessionLinkByService } = await import('./agentCommands-
|
|
243
|
+
const { removeSessionLinkByService } = await import('./agentCommands-DD47Krr1.mjs');
|
|
244
244
|
removeSessionLinkByService("serve", name);
|
|
245
245
|
console.log(`Mount '${name}' removed.`);
|
|
246
246
|
} catch (err) {
|
|
@@ -252,7 +252,7 @@ async function serveRemove(args, machineId) {
|
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
254
|
async function serveList(args, machineId) {
|
|
255
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
255
|
+
const { connectAndGetMachine } = await import('./commands-C2X-uElg.mjs');
|
|
256
256
|
const all = hasFlag(args, "--all", "-a");
|
|
257
257
|
const json = hasFlag(args, "--json");
|
|
258
258
|
const sessionId = getFlag(args, "--session");
|
|
@@ -286,7 +286,7 @@ async function serveList(args, machineId) {
|
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
288
|
async function serveInfo(machineId) {
|
|
289
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
289
|
+
const { connectAndGetMachine } = await import('./commands-C2X-uElg.mjs');
|
|
290
290
|
const { machine, server } = await connectAndGetMachine(machineId);
|
|
291
291
|
try {
|
|
292
292
|
const info = await machine.serveInfo();
|
|
@@ -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-DGhVoN3s.mjs';
|
|
2
2
|
import 'node:child_process';
|
|
3
3
|
import 'os';
|
|
4
4
|
import 'fs/promises';
|