svamp-cli 0.2.332 → 0.2.334
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-BNGSC5oD.mjs → adminCommands-CBuNOXdO.mjs} +1 -1
- package/dist/{agentCommands-DD47Krr1.mjs → agentCommands-D26EUFSD.mjs} +35 -6
- package/dist/{auth-CE3Cnkn6.mjs → auth-g7KNy7sB.mjs} +1 -1
- package/dist/{cli-CdYVO7ce.mjs → cli-CqGlhaWz.mjs} +77 -77
- package/dist/cli.mjs +2 -2
- package/dist/{commands-C2X-uElg.mjs → commands-6lx2QJEs.mjs} +1 -1
- package/dist/{commands-09sPSIH-.mjs → commands-BiA2_M_9.mjs} +3 -3
- package/dist/{commands-CHKSUX7x.mjs → commands-C2clJWyQ.mjs} +3 -3
- package/dist/{commands-14Tf0D6G.mjs → commands-Cj8WbqGh.mjs} +3 -3
- package/dist/{commands-BIKekqQG.mjs → commands-Ct2EXO44.mjs} +1 -1
- package/dist/{commands-DXJlhBPk.mjs → commands-DLHf6gma.mjs} +7 -9
- package/dist/{commands-BIx8s0JL.mjs → commands-VLcMD_8H.mjs} +11 -11
- package/dist/{commands-D7wwybeC.mjs → commands-cYTe9lAc.mjs} +8 -3
- package/dist/{fleet-bAe_gJfS.mjs → fleet-CXVxTQTU.mjs} +3 -3
- package/dist/{headlessCli-Bwg5pf3s.mjs → headlessCli-BYJunlMc.mjs} +2 -2
- package/dist/index.mjs +1 -1
- package/dist/{notifyCommands-Cc3wLAWW.mjs → notifyCommands-CfKQtXDj.mjs} +1 -1
- package/dist/package-CF7vQ3Fz.mjs +64 -0
- package/dist/{pinnedClaudeCode-BO0Qs_kE.mjs → pinnedClaudeCode-C43KnZ-Q.mjs} +27 -6
- package/dist/{rpc-DObWvEis.mjs → rpc-BsgXlOhI.mjs} +13 -1
- package/dist/{rpc-Bv6_c-xW.mjs → rpc-C6zBQ0L5.mjs} +2 -1
- package/dist/{run-CyyWhgFI.mjs → run-D4TWydj5.mjs} +1 -1
- package/dist/{run-DGhVoN3s.mjs → run-DEn3zLAt.mjs} +434 -101
- package/dist/{scheduler-BvtNZ0pl.mjs → scheduler-Ciu9Qfsi.mjs} +1 -1
- package/dist/{serveCommands-CEM708Ls.mjs → serveCommands-BTl4Fcku.mjs} +10 -10
- package/dist/{sideband--9vWYqKA.mjs → sideband-BMzd_SoN.mjs} +1 -1
- package/package.json +4 -4
- package/dist/package-CPQqs8ty.mjs +0 -64
|
@@ -7,8 +7,8 @@ import path__default, { join, delimiter, resolve as resolve$1, dirname as dirnam
|
|
|
7
7
|
import { fileURLToPath } from 'url';
|
|
8
8
|
import { execFile, execSync, spawn, exec as exec$1 } from 'child_process';
|
|
9
9
|
import * as crypto from 'crypto';
|
|
10
|
-
import { randomUUID, createHash } from 'crypto';
|
|
11
|
-
import { existsSync, readFileSync, mkdirSync as mkdirSync$1, writeFileSync as writeFileSync$1, chmodSync as chmodSync$1, rmSync as rmSync$1, cpSync, statSync, realpathSync, readdirSync, renameSync, appendFileSync, openSync, readSync, closeSync, unlinkSync as unlinkSync$1, writeSync } from 'node:fs';
|
|
10
|
+
import { randomUUID, createHash, randomBytes as randomBytes$1 } from 'crypto';
|
|
11
|
+
import { existsSync, readFileSync, mkdirSync as mkdirSync$1, writeFileSync as writeFileSync$1, chmodSync as chmodSync$1, rmSync as rmSync$1, cpSync, statSync, realpathSync, readdirSync, renameSync, appendFileSync, openSync, readSync, closeSync, unlinkSync as unlinkSync$1, fstatSync, writeSync } from 'node:fs';
|
|
12
12
|
import { join as join$1, extname, resolve, sep, basename, dirname } from 'node:path';
|
|
13
13
|
import { randomUUID as randomUUID$1, randomBytes, createHash as createHash$1, timingSafeEqual } from 'node:crypto';
|
|
14
14
|
import { exec, spawn as spawn$1, execSync as execSync$1, execFile as execFile$1, execFileSync } from 'node:child_process';
|
|
@@ -5446,10 +5446,11 @@ function cronMatches(expr, date) {
|
|
|
5446
5446
|
if (c.domRestricted && c.dowRestricted) return domOk || dowOk;
|
|
5447
5447
|
return domOk && dowOk;
|
|
5448
5448
|
}
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5449
|
+
const _zoneFormatters = /* @__PURE__ */ new Map();
|
|
5450
|
+
function zoneFormatter(tz) {
|
|
5451
|
+
let f = _zoneFormatters.get(tz);
|
|
5452
|
+
if (!f) {
|
|
5453
|
+
f = new Intl.DateTimeFormat("en-US", {
|
|
5453
5454
|
timeZone: tz,
|
|
5454
5455
|
hour12: false,
|
|
5455
5456
|
year: "numeric",
|
|
@@ -5457,7 +5458,15 @@ function inZone(date, tz) {
|
|
|
5457
5458
|
day: "2-digit",
|
|
5458
5459
|
hour: "2-digit",
|
|
5459
5460
|
minute: "2-digit"
|
|
5460
|
-
})
|
|
5461
|
+
});
|
|
5462
|
+
_zoneFormatters.set(tz, f);
|
|
5463
|
+
}
|
|
5464
|
+
return f;
|
|
5465
|
+
}
|
|
5466
|
+
function inZone(date, tz) {
|
|
5467
|
+
if (!tz) return date;
|
|
5468
|
+
try {
|
|
5469
|
+
const p = zoneFormatter(tz).formatToParts(date).reduce((o, x) => {
|
|
5461
5470
|
o[x.type] = x.value;
|
|
5462
5471
|
return o;
|
|
5463
5472
|
}, {});
|
|
@@ -5467,6 +5476,34 @@ function inZone(date, tz) {
|
|
|
5467
5476
|
return date;
|
|
5468
5477
|
}
|
|
5469
5478
|
}
|
|
5479
|
+
function nextFire(expr, from, tz) {
|
|
5480
|
+
const c = parseCron(expr);
|
|
5481
|
+
if (tz && scanForMatch(c, from, void 0) === null) return null;
|
|
5482
|
+
return scanForMatch(c, from, tz);
|
|
5483
|
+
}
|
|
5484
|
+
function scanForMatch(c, from, tz) {
|
|
5485
|
+
const d = new Date(from.getTime());
|
|
5486
|
+
d.setSeconds(0, 0);
|
|
5487
|
+
d.setMinutes(d.getMinutes() + 1);
|
|
5488
|
+
for (let i = 0; i < 366 * 24 * 60; i++) {
|
|
5489
|
+
if (cronMatches(c, tz ? inZone(d, tz) : d)) return new Date(d.getTime());
|
|
5490
|
+
d.setMinutes(d.getMinutes() + 1);
|
|
5491
|
+
}
|
|
5492
|
+
return null;
|
|
5493
|
+
}
|
|
5494
|
+
function describeNextFire(expr, tz, from = /* @__PURE__ */ new Date()) {
|
|
5495
|
+
let next;
|
|
5496
|
+
try {
|
|
5497
|
+
next = nextFire(expr, from, tz);
|
|
5498
|
+
} catch {
|
|
5499
|
+
return null;
|
|
5500
|
+
}
|
|
5501
|
+
if (!next) return "never fires";
|
|
5502
|
+
const shown = tz ? inZone(next, tz) : next;
|
|
5503
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
5504
|
+
const stamp = `${shown.getFullYear()}-${pad(shown.getMonth() + 1)}-${pad(shown.getDate())} ${pad(shown.getHours())}:${pad(shown.getMinutes())}`;
|
|
5505
|
+
return `next ${stamp} ${tz || "local"}`;
|
|
5506
|
+
}
|
|
5470
5507
|
function resolvePath(ctx, path) {
|
|
5471
5508
|
return path.split(".").reduce((o, k) => o == null ? void 0 : o[k], ctx);
|
|
5472
5509
|
}
|
|
@@ -7823,9 +7860,12 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
7823
7860
|
if (!tunnels) throw new Error("Tunnel management not available");
|
|
7824
7861
|
const client = tunnels.get(params.name);
|
|
7825
7862
|
if (!client) throw new Error(`Tunnel '${params.name}' not found`);
|
|
7863
|
+
const owner = handlers.listExposedTunnels?.().find((t) => t.name === params.name)?.sessionId;
|
|
7826
7864
|
client.destroy();
|
|
7827
7865
|
tunnels.delete(params.name);
|
|
7828
7866
|
handlers.forgetExposedTunnel?.(params.name);
|
|
7867
|
+
if (owner) handlers.dropTunnelSessionLink?.(owner, params.name);
|
|
7868
|
+
handlers.scheduleServiceLinkReconcile?.();
|
|
7829
7869
|
return { name: params.name, stopped: true };
|
|
7830
7870
|
},
|
|
7831
7871
|
/**
|
|
@@ -7868,6 +7908,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
7868
7908
|
sessionId: params.sessionId,
|
|
7869
7909
|
addedAt: Date.now()
|
|
7870
7910
|
});
|
|
7911
|
+
if (params.sessionId) handlers.scheduleServiceLinkReconcile?.();
|
|
7871
7912
|
const urls = {};
|
|
7872
7913
|
for (const [port, url] of tunnel.getUrls()) urls[port] = url;
|
|
7873
7914
|
return { ...tunnel.status, urls };
|
|
@@ -7879,9 +7920,12 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
7879
7920
|
if (!tunnels) throw new Error("Tunnel management not available");
|
|
7880
7921
|
const client = tunnels.get(params.name);
|
|
7881
7922
|
if (!client) throw new Error(`Tunnel '${params.name}' not found`);
|
|
7923
|
+
const owner = handlers.listExposedTunnels?.().find((t) => t.name === params.name)?.sessionId;
|
|
7882
7924
|
client.destroy();
|
|
7883
7925
|
tunnels.delete(params.name);
|
|
7884
7926
|
handlers.forgetExposedTunnel?.(params.name);
|
|
7927
|
+
if (owner) handlers.dropTunnelSessionLink?.(owner, params.name);
|
|
7928
|
+
handlers.scheduleServiceLinkReconcile?.();
|
|
7885
7929
|
return { name: params.name, stopped: true };
|
|
7886
7930
|
},
|
|
7887
7931
|
/**
|
|
@@ -7942,7 +7986,9 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
7942
7986
|
assertMayReplaceMount(sm, params.name, context);
|
|
7943
7987
|
const ownerEmail2 = resolveMountOwnerEmailFor(params.ownerEmail, context);
|
|
7944
7988
|
const access = params.access || "owner";
|
|
7945
|
-
|
|
7989
|
+
const result = sm.addMount(params.name, params.directory, params.sessionId, access, ownerEmail2);
|
|
7990
|
+
if (params.sessionId) handlers.scheduleServiceLinkReconcile?.();
|
|
7991
|
+
return result;
|
|
7946
7992
|
},
|
|
7947
7993
|
/**
|
|
7948
7994
|
* Apply a mount declaratively. Replaces existing mount with same name.
|
|
@@ -8332,7 +8378,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
8332
8378
|
}
|
|
8333
8379
|
const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
|
|
8334
8380
|
const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
|
|
8335
|
-
const { toolsForRole } = await import('./sideband
|
|
8381
|
+
const { toolsForRole } = await import('./sideband-BMzd_SoN.mjs');
|
|
8336
8382
|
const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
|
|
8337
8383
|
return fmt(r2);
|
|
8338
8384
|
}
|
|
@@ -8464,7 +8510,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
8464
8510
|
return { ok: false, call_id: callId, status: "busy", error: "channel is busy (too many concurrent requests) \u2014 retry shortly" };
|
|
8465
8511
|
}
|
|
8466
8512
|
const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
|
|
8467
|
-
const { queryCore } = await import('./commands-
|
|
8513
|
+
const { queryCore } = await import('./commands-6lx2QJEs.mjs');
|
|
8468
8514
|
const timeout = c.reply?.timeout_sec || 120;
|
|
8469
8515
|
let result;
|
|
8470
8516
|
let thrownSessionId;
|
|
@@ -9278,10 +9324,15 @@ const OUTPOST_EXEC_TIMEOUT_MS = 12 * 6e4;
|
|
|
9278
9324
|
const OUTPOST_MAX_OUTPUT_BYTES = 1 << 20;
|
|
9279
9325
|
function capOutpostOutput(s) {
|
|
9280
9326
|
if (!s) return "";
|
|
9281
|
-
|
|
9282
|
-
|
|
9283
|
-
|
|
9284
|
-
|
|
9327
|
+
const bytes = Buffer.byteLength(s, "utf-8");
|
|
9328
|
+
if (bytes <= OUTPOST_MAX_OUTPUT_BYTES) return s;
|
|
9329
|
+
const buf = Buffer.from(s, "utf-8");
|
|
9330
|
+
let start = buf.length - OUTPOST_MAX_OUTPUT_BYTES;
|
|
9331
|
+
while (start < buf.length && (buf[start] & 192) === 128) start++;
|
|
9332
|
+
const tail = buf.subarray(start).toString("utf-8");
|
|
9333
|
+
const dropped = bytes - Buffer.byteLength(tail, "utf-8");
|
|
9334
|
+
return `[svamp-daemon] output truncated: ${dropped} earlier bytes dropped
|
|
9335
|
+
${tail}`;
|
|
9285
9336
|
}
|
|
9286
9337
|
class OutpostCoordinator {
|
|
9287
9338
|
conns = /* @__PURE__ */ new Map();
|
|
@@ -9399,9 +9450,14 @@ class OutpostCoordinator {
|
|
|
9399
9450
|
resolveTarget(target) {
|
|
9400
9451
|
const live = this.listConnections();
|
|
9401
9452
|
if (target) {
|
|
9402
|
-
const
|
|
9403
|
-
if (
|
|
9404
|
-
|
|
9453
|
+
const byId = live.find((c) => c.machine === target);
|
|
9454
|
+
if (byId) return { machine: byId.machine };
|
|
9455
|
+
const byLabel = live.filter((c) => c.label === target);
|
|
9456
|
+
if (byLabel.length === 1) return { machine: byLabel[0].machine };
|
|
9457
|
+
if (byLabel.length > 1) {
|
|
9458
|
+
return { error: `outpost label "${target}" is ambiguous \u2014 ${byLabel.length} connected outposts share it (${byLabel.map((c) => c.machine).join(", ")}); pass the machine id instead` };
|
|
9459
|
+
}
|
|
9460
|
+
return { error: `no connected outpost named "${target}" (connected: ${live.map((c) => c.machine).join(", ") || "none"})` };
|
|
9405
9461
|
}
|
|
9406
9462
|
if (live.length === 0) return { error: "no remote outpost is connected \u2014 run the install one-liner on the remote machine first" };
|
|
9407
9463
|
if (live.length > 1) return { error: `multiple outposts connected (${live.map((c) => c.machine).join(", ")}) \u2014 pass a target` };
|
|
@@ -10015,7 +10071,7 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
|
|
|
10015
10071
|
ensureParticipantsChannel(initialMetadata.sharing);
|
|
10016
10072
|
const forkClaudeOnce = async (prompt, claudeSessionId, cwd, maxTurns, timeoutMs) => {
|
|
10017
10073
|
const { spawn } = await import('child_process');
|
|
10018
|
-
const forkEnv = { ...process.env, CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1" };
|
|
10074
|
+
const forkEnv = { ...process.env, CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1", DISABLE_AUTOUPDATER: "1" };
|
|
10019
10075
|
applyClaudeProxyEnv(forkEnv);
|
|
10020
10076
|
return new Promise((resolve) => {
|
|
10021
10077
|
const child = spawn("claude", [
|
|
@@ -11609,6 +11665,53 @@ function buildSessionIdentityEnv(identity) {
|
|
|
11609
11665
|
return env;
|
|
11610
11666
|
}
|
|
11611
11667
|
|
|
11668
|
+
async function downloadSkillAtomically(targetDir, files, fetchFile) {
|
|
11669
|
+
const stagingDir = `${targetDir}.tmp-${process.pid}-${Date.now().toString(36)}`;
|
|
11670
|
+
try {
|
|
11671
|
+
mkdirSync$1(stagingDir, { recursive: true });
|
|
11672
|
+
for (const filePath of files) {
|
|
11673
|
+
if (!filePath) continue;
|
|
11674
|
+
const content = await fetchFile(filePath);
|
|
11675
|
+
const localPath = join$1(stagingDir, filePath);
|
|
11676
|
+
if (!localPath.startsWith(stagingDir + "/")) continue;
|
|
11677
|
+
mkdirSync$1(dirname(localPath), { recursive: true });
|
|
11678
|
+
writeFileSync$1(localPath, content, "utf-8");
|
|
11679
|
+
}
|
|
11680
|
+
} catch (err) {
|
|
11681
|
+
rmSync$1(stagingDir, { recursive: true, force: true });
|
|
11682
|
+
throw err;
|
|
11683
|
+
}
|
|
11684
|
+
const backupDir = `${targetDir}.old-${process.pid}-${Date.now().toString(36)}`;
|
|
11685
|
+
let backedUp = false;
|
|
11686
|
+
try {
|
|
11687
|
+
if (existsSync(targetDir)) {
|
|
11688
|
+
renameSync(targetDir, backupDir);
|
|
11689
|
+
backedUp = true;
|
|
11690
|
+
}
|
|
11691
|
+
renameSync(stagingDir, targetDir);
|
|
11692
|
+
} catch (err) {
|
|
11693
|
+
if (backedUp && !existsSync(targetDir)) {
|
|
11694
|
+
try {
|
|
11695
|
+
renameSync(backupDir, targetDir);
|
|
11696
|
+
backedUp = false;
|
|
11697
|
+
} catch {
|
|
11698
|
+
}
|
|
11699
|
+
}
|
|
11700
|
+
try {
|
|
11701
|
+
rmSync$1(stagingDir, { recursive: true, force: true });
|
|
11702
|
+
} catch {
|
|
11703
|
+
}
|
|
11704
|
+
if (backedUp) {
|
|
11705
|
+
try {
|
|
11706
|
+
rmSync$1(backupDir, { recursive: true, force: true });
|
|
11707
|
+
} catch {
|
|
11708
|
+
}
|
|
11709
|
+
}
|
|
11710
|
+
throw err;
|
|
11711
|
+
}
|
|
11712
|
+
if (backedUp) rmSync$1(backupDir, { recursive: true, force: true });
|
|
11713
|
+
}
|
|
11714
|
+
|
|
11612
11715
|
const HOTRELOAD_ENV = "SVAMP_DEV_HOTRELOAD";
|
|
11613
11716
|
function isHotReloadEnabled(env = process.env) {
|
|
11614
11717
|
const v = env[HOTRELOAD_ENV];
|
|
@@ -14219,7 +14322,7 @@ function codexCumulativeTokens(payload) {
|
|
|
14219
14322
|
return nonCachedInput + output + Math.round(cached * 0.1);
|
|
14220
14323
|
}
|
|
14221
14324
|
|
|
14222
|
-
const PINNED_CODEX_VERSION = "0.
|
|
14325
|
+
const PINNED_CODEX_VERSION = "0.149.0";
|
|
14223
14326
|
const MIN_CODEX_STEER_VERSION = { major: 0, minor: 129, patch: 0 };
|
|
14224
14327
|
function cmpVer(a, b) {
|
|
14225
14328
|
return a.major - b.major || a.minor - b.minor || a.patch - b.patch;
|
|
@@ -15250,6 +15353,15 @@ function kimiProviderConfigured(configTomlText, provider) {
|
|
|
15250
15353
|
const block = nextTable < 0 ? rest : rest.slice(0, nextTable);
|
|
15251
15354
|
return /(^|\n)\s*api_key\s*=/.test(block);
|
|
15252
15355
|
}
|
|
15356
|
+
function kimiHasGlobalDefaultModel(configTomlText) {
|
|
15357
|
+
if (!configTomlText) return false;
|
|
15358
|
+
const firstTable = configTomlText.search(/(^|\n)\s*\[/);
|
|
15359
|
+
const preamble = firstTable < 0 ? configTomlText : configTomlText.slice(0, firstTable);
|
|
15360
|
+
return /(^|\n)\s*default_model\s*=/.test(preamble);
|
|
15361
|
+
}
|
|
15362
|
+
function kimiConfigComplete(configTomlText, provider) {
|
|
15363
|
+
return kimiProviderConfigured(configTomlText, provider) && kimiHasGlobalDefaultModel(configTomlText);
|
|
15364
|
+
}
|
|
15253
15365
|
function kimiModelMenu(env = process.env) {
|
|
15254
15366
|
return (env.SVAMP_KIMI_MODELS || "").split(",").map((s) => s.trim()).filter(Boolean).filter((m, i, a) => a.indexOf(m) === i);
|
|
15255
15367
|
}
|
|
@@ -15271,8 +15383,10 @@ var kimiProvider = /*#__PURE__*/Object.freeze({
|
|
|
15271
15383
|
buildKimiCatalogAddArgs: buildKimiCatalogAddArgs,
|
|
15272
15384
|
hasKimiProvider: hasKimiProvider,
|
|
15273
15385
|
kimiClampModel: kimiClampModel,
|
|
15386
|
+
kimiConfigComplete: kimiConfigComplete,
|
|
15274
15387
|
kimiDefaultModel: kimiDefaultModel,
|
|
15275
15388
|
kimiDefaultModelId: kimiDefaultModelId,
|
|
15389
|
+
kimiHasGlobalDefaultModel: kimiHasGlobalDefaultModel,
|
|
15276
15390
|
kimiModelMenu: kimiModelMenu,
|
|
15277
15391
|
kimiProviderConfigured: kimiProviderConfigured,
|
|
15278
15392
|
kimiSpawnEnv: kimiSpawnEnv,
|
|
@@ -15291,7 +15405,7 @@ async function ensureKimiProviderConfigured(env = process.env, command = "kimi",
|
|
|
15291
15405
|
}) {
|
|
15292
15406
|
const cfg = resolveKimiProvider(env);
|
|
15293
15407
|
if (!hasKimiProvider(cfg)) return false;
|
|
15294
|
-
if (
|
|
15408
|
+
if (kimiConfigComplete(readKimiConfig(), cfg.provider)) return true;
|
|
15295
15409
|
const args = buildKimiCatalogAddArgs(cfg);
|
|
15296
15410
|
if (!args) return false;
|
|
15297
15411
|
try {
|
|
@@ -15309,7 +15423,11 @@ async function ensureKimiProviderConfigured(env = process.env, command = "kimi",
|
|
|
15309
15423
|
);
|
|
15310
15424
|
});
|
|
15311
15425
|
log(`[kimi] configured provider '${cfg.provider}' in ${KIMI_CONFIG_PATH}`);
|
|
15312
|
-
|
|
15426
|
+
const complete = kimiConfigComplete(readKimiConfig(), cfg.provider);
|
|
15427
|
+
if (!complete) {
|
|
15428
|
+
log(`[kimi] catalog add left ${KIMI_CONFIG_PATH} without a global default_model \u2014 \`kimi acp\` will refuse session/new ("no default model configured")`);
|
|
15429
|
+
}
|
|
15430
|
+
return complete;
|
|
15313
15431
|
} catch (err) {
|
|
15314
15432
|
log(`[kimi] provider auto-config failed (${err?.message || err}); session may need kimi-auth`);
|
|
15315
15433
|
return false;
|
|
@@ -16297,14 +16415,21 @@ class ProcessSupervisor {
|
|
|
16297
16415
|
if (entry.stopping) throw new Error(`Process '${entry.spec.name}' is being stopped, try again shortly`);
|
|
16298
16416
|
throw new Error(`Process '${entry.spec.name}' is already running`);
|
|
16299
16417
|
}
|
|
16300
|
-
entry
|
|
16301
|
-
|
|
16302
|
-
|
|
16303
|
-
|
|
16304
|
-
|
|
16305
|
-
|
|
16306
|
-
|
|
16307
|
-
|
|
16418
|
+
return this.runExclusive(entry, async () => {
|
|
16419
|
+
if (entry.deleted) throw new Error(`Process '${idOrName}' has been removed`);
|
|
16420
|
+
if (entry.child) {
|
|
16421
|
+
if (entry.stopping) throw new Error(`Process '${entry.spec.name}' is being stopped, try again shortly`);
|
|
16422
|
+
throw new Error(`Process '${entry.spec.name}' is already running`);
|
|
16423
|
+
}
|
|
16424
|
+
entry.stopping = false;
|
|
16425
|
+
this.clearTimers(entry);
|
|
16426
|
+
if (entry.spec.desiredStopped) {
|
|
16427
|
+
entry.spec.desiredStopped = false;
|
|
16428
|
+
await this.persistSpec(entry.spec);
|
|
16429
|
+
}
|
|
16430
|
+
this.resetFailureTracking(entry);
|
|
16431
|
+
await this.startEntry(entry, false);
|
|
16432
|
+
});
|
|
16308
16433
|
}
|
|
16309
16434
|
/**
|
|
16310
16435
|
* Stop a running process. Does NOT remove it from supervision.
|
|
@@ -16314,7 +16439,7 @@ class ProcessSupervisor {
|
|
|
16314
16439
|
*/
|
|
16315
16440
|
/**
|
|
16316
16441
|
* #0347: run `fn` in the entry's lifecycle critical section. Each call awaits the previous
|
|
16317
|
-
* lifecycle op's SETTLEMENT before running, so stop/restart/apply/update/remove are strictly
|
|
16442
|
+
* lifecycle op's SETTLEMENT before running, so start/stop/restart/apply/update/remove are strictly
|
|
16318
16443
|
* serialized per entry and can never interleave across an `await killChild` (which is what let
|
|
16319
16444
|
* two ops double-spawn an orphan, or resurrect a just-stopped process). The chain tail never
|
|
16320
16445
|
* rejects (a failed op must not wedge the queue); the caller still gets the real result/error.
|
|
@@ -16531,7 +16656,7 @@ class ProcessSupervisor {
|
|
|
16531
16656
|
}
|
|
16532
16657
|
async persistSpec(spec) {
|
|
16533
16658
|
const filePath = path__default.join(this.persistDir, `${spec.id}.json`);
|
|
16534
|
-
const tmpPath = filePath
|
|
16659
|
+
const tmpPath = `${filePath}.tmp-${process.pid}-${randomBytes$1(4).toString("hex")}`;
|
|
16535
16660
|
await writeFile$1(tmpPath, JSON.stringify(spec, null, 2), "utf-8");
|
|
16536
16661
|
await rename(tmpPath, filePath);
|
|
16537
16662
|
}
|
|
@@ -17110,7 +17235,7 @@ function searchIssues(projectRoot, query) {
|
|
|
17110
17235
|
const q = query.trim();
|
|
17111
17236
|
if (!q) return [];
|
|
17112
17237
|
try {
|
|
17113
|
-
const out = execFileSync("rg", ["-l", "-i", "--no-messages", q, issuesDir(projectRoot)], { encoding: "utf-8" });
|
|
17238
|
+
const out = execFileSync("rg", ["-l", "-i", "-F", "--no-messages", "-e", q, "--", issuesDir(projectRoot)], { encoding: "utf-8" });
|
|
17114
17239
|
const files = out.split("\n").filter(Boolean);
|
|
17115
17240
|
const issues = [];
|
|
17116
17241
|
for (const f of files) {
|
|
@@ -17121,9 +17246,24 @@ function searchIssues(projectRoot, query) {
|
|
|
17121
17246
|
}
|
|
17122
17247
|
}
|
|
17123
17248
|
return issues.sort((a, b) => Number(a.id) - Number(b.id));
|
|
17124
|
-
} catch {
|
|
17125
|
-
|
|
17126
|
-
return
|
|
17249
|
+
} catch (e) {
|
|
17250
|
+
if (e?.status === 1) return [];
|
|
17251
|
+
return searchIssuesInMemory(projectRoot, q);
|
|
17252
|
+
}
|
|
17253
|
+
}
|
|
17254
|
+
function searchIssuesInMemory(projectRoot, q) {
|
|
17255
|
+
const ql = q.toLowerCase();
|
|
17256
|
+
return listIssues(projectRoot, { includeArchived: true }).filter((i) => i.title.toLowerCase().includes(ql) || (i.body || "").toLowerCase().includes(ql) || i.labels.some((l) => l.toLowerCase().includes(ql)));
|
|
17257
|
+
}
|
|
17258
|
+
function checkVerifyCommand(projectRoot, issue) {
|
|
17259
|
+
const cmd = issue?.verify?.type === "command" ? (issue.verify.text || "").trim() : "";
|
|
17260
|
+
if (!cmd) return { ok: true };
|
|
17261
|
+
try {
|
|
17262
|
+
execSync$1(cmd, { cwd: projectRoot, stdio: "pipe", timeout: 6e5, maxBuffer: 64 * 1024 * 1024 });
|
|
17263
|
+
return { ok: true, cmd };
|
|
17264
|
+
} catch (e) {
|
|
17265
|
+
const output = (String(e?.stdout || "") + String(e?.stderr || "")).split("\n").slice(-15).join("\n").trim();
|
|
17266
|
+
return { ok: false, cmd, output };
|
|
17127
17267
|
}
|
|
17128
17268
|
}
|
|
17129
17269
|
function summarize(issues) {
|
|
@@ -17166,11 +17306,29 @@ function resolveLogPrunePolicy(env = process.env) {
|
|
|
17166
17306
|
maxBytes: num(env.SVAMP_LOG_MAX_BYTES, DEFAULT_LOG_PRUNE_POLICY.maxBytes)
|
|
17167
17307
|
};
|
|
17168
17308
|
}
|
|
17169
|
-
function
|
|
17170
|
-
|
|
17171
|
-
|
|
17172
|
-
|
|
17173
|
-
|
|
17309
|
+
function trimToLineStart(buf) {
|
|
17310
|
+
const nl = buf.indexOf(10);
|
|
17311
|
+
return nl >= 0 && nl + 1 < buf.length ? buf.subarray(nl + 1) : buf;
|
|
17312
|
+
}
|
|
17313
|
+
|
|
17314
|
+
function readLogTail(path, tailBytes) {
|
|
17315
|
+
const fd = openSync(path, "r");
|
|
17316
|
+
try {
|
|
17317
|
+
const size = fstatSync(fd).size;
|
|
17318
|
+
const want = Math.min(Math.max(0, Math.floor(tailBytes)), size);
|
|
17319
|
+
if (want === 0) return { data: Buffer.alloc(0), truncated: size > 0 };
|
|
17320
|
+
const buf = Buffer.allocUnsafe(want);
|
|
17321
|
+
const start = size - want;
|
|
17322
|
+
let read = 0;
|
|
17323
|
+
while (read < want) {
|
|
17324
|
+
const n = readSync(fd, buf, read, want - read, start + read);
|
|
17325
|
+
if (n <= 0) break;
|
|
17326
|
+
read += n;
|
|
17327
|
+
}
|
|
17328
|
+
return { data: read === want ? buf : buf.subarray(0, read), truncated: size > want };
|
|
17329
|
+
} finally {
|
|
17330
|
+
closeSync(fd);
|
|
17331
|
+
}
|
|
17174
17332
|
}
|
|
17175
17333
|
|
|
17176
17334
|
const CARRIER_FIELDS = ["message", "error", "detail", "reason", "description"];
|
|
@@ -17889,6 +18047,15 @@ function isCostCeiling(kind) {
|
|
|
17889
18047
|
function isHardBudgetStop(kind) {
|
|
17890
18048
|
return isCostCeiling(kind) || kind === "iteration";
|
|
17891
18049
|
}
|
|
18050
|
+
function rearmStartedAt(startedAt, completedAt, now) {
|
|
18051
|
+
const fin = (v) => typeof v === "number" && Number.isFinite(v) && v > 0;
|
|
18052
|
+
if (!fin(startedAt)) return startedAt;
|
|
18053
|
+
if (!fin(completedAt)) return startedAt;
|
|
18054
|
+
if (completedAt < startedAt) return startedAt;
|
|
18055
|
+
const dormantMs = now - completedAt;
|
|
18056
|
+
if (dormantMs <= 0) return startedAt;
|
|
18057
|
+
return startedAt + dormantMs;
|
|
18058
|
+
}
|
|
17892
18059
|
function checkLoopBudget(ledger, limits, now, startedAt) {
|
|
17893
18060
|
const L = limits || {};
|
|
17894
18061
|
const led = ledger || { turns: 0, tokens: 0, window: [] };
|
|
@@ -18368,6 +18535,47 @@ function isContextTooLongError(text) {
|
|
|
18368
18535
|
if (t.includes("context") && t.includes("exceed") && t.includes("limit") && !t.includes("subscription")) return true;
|
|
18369
18536
|
return false;
|
|
18370
18537
|
}
|
|
18538
|
+
function shouldEvaluateProactiveCompaction(state) {
|
|
18539
|
+
if (!state.enabled) return false;
|
|
18540
|
+
if (state.disabled) return false;
|
|
18541
|
+
if (state.turnErrored) return false;
|
|
18542
|
+
if (state.compactPending) return false;
|
|
18543
|
+
if (state.justCompacted) return false;
|
|
18544
|
+
return true;
|
|
18545
|
+
}
|
|
18546
|
+
function compactSupportedFromSlashCommands(slashCommands) {
|
|
18547
|
+
if (!Array.isArray(slashCommands) || slashCommands.length === 0) return void 0;
|
|
18548
|
+
return slashCommands.some(
|
|
18549
|
+
(c) => typeof c === "string" && c.trim().replace(/^\//, "").toLowerCase() === "compact"
|
|
18550
|
+
);
|
|
18551
|
+
}
|
|
18552
|
+
const DEFAULT_COMPACT_NO_BOUNDARY_STRIKES = 3;
|
|
18553
|
+
function decideCompactUnsupported(input) {
|
|
18554
|
+
const prior = Math.max(0, input.priorStrikes || 0);
|
|
18555
|
+
const limit = Math.max(1, input.maxStrikes);
|
|
18556
|
+
if (input.turnErrored) {
|
|
18557
|
+
return { disable: false, warnUnsupported: false, strikes: prior, reason: "errored-turn" };
|
|
18558
|
+
}
|
|
18559
|
+
if (!input.wasAutoInjected) {
|
|
18560
|
+
return {
|
|
18561
|
+
disable: false,
|
|
18562
|
+
warnUnsupported: input.compactSupported === false,
|
|
18563
|
+
strikes: prior,
|
|
18564
|
+
reason: "user-typed"
|
|
18565
|
+
};
|
|
18566
|
+
}
|
|
18567
|
+
if (input.compactSupported === false) {
|
|
18568
|
+
return { disable: true, warnUnsupported: true, strikes: prior + 1, reason: "unsupported" };
|
|
18569
|
+
}
|
|
18570
|
+
const strikes = prior + 1;
|
|
18571
|
+
if (strikes >= limit) {
|
|
18572
|
+
return { disable: true, warnUnsupported: false, strikes, reason: "strikes-exhausted" };
|
|
18573
|
+
}
|
|
18574
|
+
return { disable: false, warnUnsupported: false, strikes, reason: "strike" };
|
|
18575
|
+
}
|
|
18576
|
+
function describeNoBoundary(strikes, limit) {
|
|
18577
|
+
return `Automatic compaction ran but reported no compaction boundary (attempt ${strikes} of ${limit}) \u2014 usually because there was nothing left to compact. Keeping automatic compaction enabled.`;
|
|
18578
|
+
}
|
|
18371
18579
|
|
|
18372
18580
|
function fmtTokens(n) {
|
|
18373
18581
|
return Math.max(0, Math.round(n)).toLocaleString("en-US");
|
|
@@ -18941,23 +19149,27 @@ function compareVersions(a, b) {
|
|
|
18941
19149
|
return 0;
|
|
18942
19150
|
}
|
|
18943
19151
|
async function installSkillFromEndpoint(name, baseUrl) {
|
|
18944
|
-
const
|
|
18945
|
-
if (!resp.ok) throw new Error(`HTTP ${resp.status} from ${baseUrl}`);
|
|
18946
|
-
const index = await resp.json();
|
|
19152
|
+
const index = await fetchEndpointSkillIndex(baseUrl);
|
|
18947
19153
|
const files = index.files || [];
|
|
18948
19154
|
if (files.length === 0) throw new Error(`Skill index at ${baseUrl} has no files`);
|
|
18949
|
-
|
|
18950
|
-
|
|
18951
|
-
for (const filePath of files) {
|
|
18952
|
-
if (!filePath) continue;
|
|
18953
|
-
const url = `${baseUrl}${filePath}`;
|
|
18954
|
-
const fileResp = await fetch(url, { signal: AbortSignal.timeout(3e4) });
|
|
19155
|
+
await downloadSkillAtomically(join(CLAUDE_SKILLS_DIR, name), files, async (filePath) => {
|
|
19156
|
+
const fileResp = await fetch(`${baseUrl}${filePath}`, { signal: AbortSignal.timeout(3e4) });
|
|
18955
19157
|
if (!fileResp.ok) throw new Error(`Failed to download ${filePath}: HTTP ${fileResp.status}`);
|
|
18956
|
-
|
|
18957
|
-
|
|
18958
|
-
|
|
18959
|
-
|
|
18960
|
-
|
|
19158
|
+
return fileResp.text();
|
|
19159
|
+
});
|
|
19160
|
+
}
|
|
19161
|
+
async function fetchEndpointSkillIndex(baseUrl) {
|
|
19162
|
+
const resp = await fetch(baseUrl, { signal: AbortSignal.timeout(15e3) });
|
|
19163
|
+
if (!resp.ok) throw new Error(`HTTP ${resp.status} from ${baseUrl}`);
|
|
19164
|
+
return await resp.json();
|
|
19165
|
+
}
|
|
19166
|
+
async function fetchEndpointSkillVersion(baseUrl) {
|
|
19167
|
+
try {
|
|
19168
|
+
const index = await fetchEndpointSkillIndex(baseUrl);
|
|
19169
|
+
const v = index?.version;
|
|
19170
|
+
return typeof v === "string" && v.trim() ? v.trim() : null;
|
|
19171
|
+
} catch {
|
|
19172
|
+
return null;
|
|
18961
19173
|
}
|
|
18962
19174
|
}
|
|
18963
19175
|
async function installSkillFromMarketplace(name) {
|
|
@@ -18981,26 +19193,11 @@ async function installSkillFromMarketplace(name) {
|
|
|
18981
19193
|
}
|
|
18982
19194
|
const files = await collectFiles();
|
|
18983
19195
|
if (files.length === 0) throw new Error(`Skill ${name} has no files in marketplace`);
|
|
18984
|
-
|
|
18985
|
-
|
|
18986
|
-
|
|
18987
|
-
|
|
18988
|
-
|
|
18989
|
-
const url = `${BASE}/files/${filePath}`;
|
|
18990
|
-
const resp = await fetch(url, { signal: AbortSignal.timeout(3e4) });
|
|
18991
|
-
if (!resp.ok) throw new Error(`Failed to download ${filePath}: HTTP ${resp.status}`);
|
|
18992
|
-
const content = await resp.text();
|
|
18993
|
-
const localPath = join(stagingDir, filePath);
|
|
18994
|
-
if (!localPath.startsWith(stagingDir + "/")) continue;
|
|
18995
|
-
mkdirSync(dirname$1(localPath), { recursive: true });
|
|
18996
|
-
writeFileSync(localPath, content, "utf-8");
|
|
18997
|
-
}
|
|
18998
|
-
rmSync(targetDir, { recursive: true, force: true });
|
|
18999
|
-
renameSync$1(stagingDir, targetDir);
|
|
19000
|
-
} catch (err) {
|
|
19001
|
-
rmSync(stagingDir, { recursive: true, force: true });
|
|
19002
|
-
throw err;
|
|
19003
|
-
}
|
|
19196
|
+
await downloadSkillAtomically(join(CLAUDE_SKILLS_DIR, name), files, async (filePath) => {
|
|
19197
|
+
const resp = await fetch(`${BASE}/files/${filePath}`, { signal: AbortSignal.timeout(3e4) });
|
|
19198
|
+
if (!resp.ok) throw new Error(`Failed to download ${filePath}: HTTP ${resp.status}`);
|
|
19199
|
+
return resp.text();
|
|
19200
|
+
});
|
|
19004
19201
|
}
|
|
19005
19202
|
function getBundledSkillsDir() {
|
|
19006
19203
|
try {
|
|
@@ -19219,9 +19416,16 @@ async function ensureAutoInstalledSkills(logger) {
|
|
|
19219
19416
|
marketplaceVersion: () => fetchMarketplaceSkillVersion("svamp")
|
|
19220
19417
|
},
|
|
19221
19418
|
{
|
|
19419
|
+
// #1192: the agent-skills endpoint's index already carries a `version` (verified live:
|
|
19420
|
+
// `{"name":"hypha","version":"1.0.0","files":[...]}`), and installSkillFromEndpoint
|
|
19421
|
+
// fetches that exact document anyway — it just used to discard the field. Supplying the
|
|
19422
|
+
// probe moves `hypha` off the "install once, never refresh" branch, so a machine is no
|
|
19423
|
+
// longer pinned forever to whatever version it first installed. Safe now that #1191
|
|
19424
|
+
// gave this downloader atomic staging: a refresh that fails mid-download leaves the
|
|
19425
|
+
// previous skill intact instead of half-overwriting it.
|
|
19222
19426
|
name: "hypha",
|
|
19223
|
-
install: () => installSkillFromEndpoint("hypha", `${getSkillsServer()}/ws/agent-skills/`)
|
|
19224
|
-
|
|
19427
|
+
install: () => installSkillFromEndpoint("hypha", `${getSkillsServer()}/ws/agent-skills/`),
|
|
19428
|
+
marketplaceVersion: () => fetchEndpointSkillVersion(`${getSkillsServer()}/ws/agent-skills/`)
|
|
19225
19429
|
},
|
|
19226
19430
|
{
|
|
19227
19431
|
// `<artifact>` block rendering — see packages/svamp-app/.../Artifact.tsx.
|
|
@@ -19787,13 +19991,13 @@ function createSvampConfigChecker(directory, sessionId, getMetadata, setMetadata
|
|
|
19787
19991
|
};
|
|
19788
19992
|
let announcedLoopStart = (() => {
|
|
19789
19993
|
const s = readLoopState(directory, sessionId);
|
|
19790
|
-
return s && (s.phase === "done" || s.phase === "gave_up") ? s.started_at ?? "\u2205" : null;
|
|
19994
|
+
return s && (s.phase === "done" || s.phase === "gave_up") ? String(s.started_at ?? "\u2205") : null;
|
|
19791
19995
|
})();
|
|
19792
19996
|
const loopChecker = () => {
|
|
19793
19997
|
try {
|
|
19794
19998
|
const s = readLoopState(directory, sessionId);
|
|
19795
19999
|
if (!s || s.phase !== "done" && s.phase !== "gave_up") return;
|
|
19796
|
-
const key = s.started_at ?? "\u2205";
|
|
20000
|
+
const key = String(s.started_at ?? "\u2205");
|
|
19797
20001
|
if (key === announcedLoopStart) return;
|
|
19798
20002
|
announcedLoopStart = key;
|
|
19799
20003
|
const iter = s.ledger && typeof s.ledger.turns === "number" && s.ledger.turns > 0 ? s.ledger.turns : typeof s.iteration === "number" ? s.iteration : 0;
|
|
@@ -20185,7 +20389,9 @@ function pruneDaemonLogs(exclude = []) {
|
|
|
20185
20389
|
for (const { name } of plan.truncateFiles) {
|
|
20186
20390
|
try {
|
|
20187
20391
|
const p = join(LOGS_DIR, name);
|
|
20188
|
-
const
|
|
20392
|
+
const keepBytes = Math.floor(policy.maxBytes / 8);
|
|
20393
|
+
const tail = readLogTail(p, keepBytes);
|
|
20394
|
+
const kept = tail.truncated ? trimToLineStart(tail.data) : tail.data;
|
|
20189
20395
|
writeFileSync(p, kept);
|
|
20190
20396
|
} catch {
|
|
20191
20397
|
}
|
|
@@ -20498,7 +20704,7 @@ async function startDaemon(options) {
|
|
|
20498
20704
|
try {
|
|
20499
20705
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
20500
20706
|
if (!dir) return;
|
|
20501
|
-
const { reconcileServiceLinks } = await import('./agentCommands-
|
|
20707
|
+
const { reconcileServiceLinks } = await import('./agentCommands-D26EUFSD.mjs');
|
|
20502
20708
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
20503
20709
|
const config = readSvampConfig(configPath);
|
|
20504
20710
|
const entries = Array.from(urls.entries());
|
|
@@ -20520,7 +20726,7 @@ async function startDaemon(options) {
|
|
|
20520
20726
|
try {
|
|
20521
20727
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
20522
20728
|
if (!dir) return;
|
|
20523
|
-
const { reconcileServiceLinks } = await import('./agentCommands-
|
|
20729
|
+
const { reconcileServiceLinks } = await import('./agentCommands-D26EUFSD.mjs');
|
|
20524
20730
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
20525
20731
|
const config = readSvampConfig(configPath);
|
|
20526
20732
|
const incoming = [{
|
|
@@ -20541,7 +20747,7 @@ async function startDaemon(options) {
|
|
|
20541
20747
|
try {
|
|
20542
20748
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
20543
20749
|
if (!dir) return;
|
|
20544
|
-
const { dropServiceLinks } = await import('./agentCommands-
|
|
20750
|
+
const { dropServiceLinks } = await import('./agentCommands-D26EUFSD.mjs');
|
|
20545
20751
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
20546
20752
|
const config = readSvampConfig(configPath);
|
|
20547
20753
|
if (dropServiceLinks(config, "serve", mountName)) {
|
|
@@ -20552,6 +20758,81 @@ async function startDaemon(options) {
|
|
|
20552
20758
|
logger.log(`[serve] Link drop failed for mount ${mountName}: ${err?.message || err}`);
|
|
20553
20759
|
}
|
|
20554
20760
|
}
|
|
20761
|
+
async function dropTunnelSessionLink(sessionId, tunnelName) {
|
|
20762
|
+
if (!sessionId) return;
|
|
20763
|
+
try {
|
|
20764
|
+
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
20765
|
+
if (!dir) return;
|
|
20766
|
+
const { dropServiceLinks } = await import('./agentCommands-D26EUFSD.mjs');
|
|
20767
|
+
const configPath = getSvampConfigPath(dir, sessionId);
|
|
20768
|
+
const config = readSvampConfig(configPath);
|
|
20769
|
+
if (dropServiceLinks(config, "tunnel", tunnelName)) {
|
|
20770
|
+
writeSvampConfig(configPath, config);
|
|
20771
|
+
logger.log(`[exposed-tunnels] Dropped Launch Pad link for tunnel ${tunnelName} \u2190 session ${sessionId}`);
|
|
20772
|
+
}
|
|
20773
|
+
} catch (err) {
|
|
20774
|
+
logger.log(`[exposed-tunnels] Link drop failed for tunnel ${tunnelName}: ${err?.message || err}`);
|
|
20775
|
+
}
|
|
20776
|
+
}
|
|
20777
|
+
let liveSessionDirs;
|
|
20778
|
+
async function reconcileAllServiceLinks() {
|
|
20779
|
+
try {
|
|
20780
|
+
const { reconcileServiceLinksExact } = await import('./agentCommands-D26EUFSD.mjs');
|
|
20781
|
+
const desiredBySession = /* @__PURE__ */ new Map();
|
|
20782
|
+
const push = (sessionId, entry) => {
|
|
20783
|
+
if (!sessionId || !entry.url) return;
|
|
20784
|
+
const list = desiredBySession.get(sessionId) ?? [];
|
|
20785
|
+
list.push(entry);
|
|
20786
|
+
desiredBySession.set(sessionId, list);
|
|
20787
|
+
};
|
|
20788
|
+
for (const m of serveManager$1.listMounts()) {
|
|
20789
|
+
if (m?.sessionId && m?.url) push(m.sessionId, { url: String(m.url), label: m.name, service: { kind: "serve", name: m.name } });
|
|
20790
|
+
}
|
|
20791
|
+
const specBySession = /* @__PURE__ */ new Map();
|
|
20792
|
+
for (const spec of loadExposedTunnels()) if (spec.sessionId) specBySession.set(spec.name, spec.sessionId);
|
|
20793
|
+
for (const [name, tunnel] of tunnels) {
|
|
20794
|
+
const sessionId = specBySession.get(name);
|
|
20795
|
+
if (!sessionId) continue;
|
|
20796
|
+
const urls = Array.from(tunnel.getUrls().entries());
|
|
20797
|
+
for (const [port, url] of urls) {
|
|
20798
|
+
push(sessionId, { url: String(url), label: urls.length > 1 ? `${name}:${port}` : name, service: { kind: "tunnel", name } });
|
|
20799
|
+
}
|
|
20800
|
+
}
|
|
20801
|
+
const dirBySession = /* @__PURE__ */ new Map();
|
|
20802
|
+
for (const [id, entry] of Object.entries(loadSessionIndex())) {
|
|
20803
|
+
if (entry?.directory) dirBySession.set(id, entry.directory);
|
|
20804
|
+
}
|
|
20805
|
+
for (const s of liveSessionDirs?.() ?? []) {
|
|
20806
|
+
if (s.sessionId && s.directory) dirBySession.set(s.sessionId, s.directory);
|
|
20807
|
+
}
|
|
20808
|
+
const sessionIds = /* @__PURE__ */ new Set([...dirBySession.keys(), ...desiredBySession.keys()]);
|
|
20809
|
+
for (const sessionId of sessionIds) {
|
|
20810
|
+
try {
|
|
20811
|
+
const dir = dirBySession.get(sessionId);
|
|
20812
|
+
if (!dir) continue;
|
|
20813
|
+
const configPath = getSvampConfigPath(dir, sessionId);
|
|
20814
|
+
const config = readSvampConfig(configPath);
|
|
20815
|
+
const desired = desiredBySession.get(sessionId) ?? [];
|
|
20816
|
+
if (reconcileServiceLinksExact(config, ["serve", "tunnel"], desired)) {
|
|
20817
|
+
writeSvampConfig(configPath, config);
|
|
20818
|
+
logger.log(`[launchpad] Reconciled service links for session ${sessionId} (${desired.length} live)`);
|
|
20819
|
+
}
|
|
20820
|
+
} catch (err) {
|
|
20821
|
+
logger.log(`[launchpad] Reconcile failed for session ${sessionId}: ${err?.message || err}`);
|
|
20822
|
+
}
|
|
20823
|
+
}
|
|
20824
|
+
} catch (err) {
|
|
20825
|
+
logger.log(`[launchpad] Service-link sweep failed: ${err?.message || err}`);
|
|
20826
|
+
}
|
|
20827
|
+
}
|
|
20828
|
+
let serviceLinkReconcileTimer;
|
|
20829
|
+
function scheduleServiceLinkReconcile(delayMs = 1200) {
|
|
20830
|
+
if (serviceLinkReconcileTimer) clearTimeout(serviceLinkReconcileTimer);
|
|
20831
|
+
serviceLinkReconcileTimer = setTimeout(() => {
|
|
20832
|
+
serviceLinkReconcileTimer = void 0;
|
|
20833
|
+
void reconcileAllServiceLinks();
|
|
20834
|
+
}, delayMs);
|
|
20835
|
+
}
|
|
20555
20836
|
async function createExposedTunnel(spec) {
|
|
20556
20837
|
const { FrpcTunnel } = await Promise.resolve().then(function () { return frpc; });
|
|
20557
20838
|
const tunnel = new FrpcTunnel({
|
|
@@ -20584,8 +20865,18 @@ async function startDaemon(options) {
|
|
|
20584
20865
|
ensureAutoInstalledCommands(logger);
|
|
20585
20866
|
(async () => {
|
|
20586
20867
|
try {
|
|
20587
|
-
const { beginClaudeVersionReconcile } = await import('./pinnedClaudeCode-
|
|
20588
|
-
|
|
20868
|
+
const { beginClaudeVersionReconcile, CLAUDE_VERSION_RECHECK_MS } = await import('./pinnedClaudeCode-C43KnZ-Q.mjs');
|
|
20869
|
+
const onResult = (result) => {
|
|
20870
|
+
if (result?.kind === "install-failed" || result?.kind === "skipped" || result?.kind === "not-installed") {
|
|
20871
|
+
logger.log(`[claude-version] WARNING \u2014 machine is NOT on the pinned Claude Code (${result.kind}). Sessions are running an untested build.`);
|
|
20872
|
+
}
|
|
20873
|
+
};
|
|
20874
|
+
beginClaudeVersionReconcile((msg) => logger.log(msg), { onResult });
|
|
20875
|
+
const jitter = Math.floor(Math.random() * 5 * 6e4);
|
|
20876
|
+
const timer = setInterval(() => {
|
|
20877
|
+
beginClaudeVersionReconcile((msg) => logger.log(msg), { onResult });
|
|
20878
|
+
}, CLAUDE_VERSION_RECHECK_MS + jitter);
|
|
20879
|
+
timer.unref?.();
|
|
20589
20880
|
} catch (e) {
|
|
20590
20881
|
logger.log(`[claude-version] check failed: ${e?.message || e}`);
|
|
20591
20882
|
}
|
|
@@ -20629,6 +20920,7 @@ async function startDaemon(options) {
|
|
|
20629
20920
|
}
|
|
20630
20921
|
});
|
|
20631
20922
|
const pidToTrackedSession = /* @__PURE__ */ new Map();
|
|
20923
|
+
liveSessionDirs = () => Array.from(pidToTrackedSession.values()).filter((s) => s.svampSessionId && !s.stopped).map((s) => ({ sessionId: s.svampSessionId, directory: s.directory }));
|
|
20632
20924
|
let sessionCoreRef = {
|
|
20633
20925
|
splitStreamLines,
|
|
20634
20926
|
handleClaudeMessage
|
|
@@ -21078,7 +21370,7 @@ ${v.guidance ? v.guidance + "\n" : ""}Criteria: ${v.criteria || "(none)"}
|
|
|
21078
21370
|
const cwd = sessionMetadata.path || directory;
|
|
21079
21371
|
const model = process.env.SVAMP_TOPIC_MODEL;
|
|
21080
21372
|
try {
|
|
21081
|
-
const forkEnv = { ...process.env, CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1" };
|
|
21373
|
+
const forkEnv = { ...process.env, CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1", DISABLE_AUTOUPDATER: "1" };
|
|
21082
21374
|
applyClaudeProxyEnv(forkEnv);
|
|
21083
21375
|
const child = spawn("claude", [
|
|
21084
21376
|
"--print",
|
|
@@ -21517,6 +21809,9 @@ ${parts.join("\n")}`);
|
|
|
21517
21809
|
let autoCompactWasAutoInjected = false;
|
|
21518
21810
|
let autoCompactDisabled = false;
|
|
21519
21811
|
let autoCompactRecoveryTried = false;
|
|
21812
|
+
let justCompactedTurn = false;
|
|
21813
|
+
let compactNoBoundaryStrikes = 0;
|
|
21814
|
+
let compactSupported = void 0;
|
|
21520
21815
|
let noIsolationWarned = false;
|
|
21521
21816
|
const RATELIMIT_CFG = getRateLimitRetryConfig();
|
|
21522
21817
|
let currentTurnMessage;
|
|
@@ -21962,15 +22257,30 @@ ${parts.join("\n")}`);
|
|
|
21962
22257
|
pendingCompactTurn = false;
|
|
21963
22258
|
const wasAuto = autoCompactWasAutoInjected;
|
|
21964
22259
|
autoCompactWasAutoInjected = false;
|
|
21965
|
-
|
|
22260
|
+
const d = decideCompactUnsupported({
|
|
22261
|
+
wasAutoInjected: wasAuto,
|
|
22262
|
+
turnErrored: !!msg.is_error,
|
|
22263
|
+
compactSupported,
|
|
22264
|
+
priorStrikes: compactNoBoundaryStrikes,
|
|
22265
|
+
maxStrikes: DEFAULT_COMPACT_NO_BOUNDARY_STRIKES
|
|
22266
|
+
});
|
|
22267
|
+
compactNoBoundaryStrikes = d.strikes;
|
|
22268
|
+
if (d.disable) {
|
|
21966
22269
|
autoCompactDisabled = true;
|
|
21967
|
-
logger.log(`[Session ${sessionId}]
|
|
22270
|
+
logger.log(`[Session ${sessionId}] Disabling the auto-compaction backstop for this session (${d.reason})`);
|
|
22271
|
+
}
|
|
22272
|
+
logger.log(`[Session ${sessionId}] /compact produced no compaction boundary (reason=${d.reason}, strikes=${d.strikes}, supported=${String(compactSupported)}, errored=${!!msg.is_error})`);
|
|
22273
|
+
if (d.warnUnsupported) {
|
|
22274
|
+
sessionService.pushMessage(
|
|
22275
|
+
{ type: "message", message: compactUnsupportedWarning(), level: "warning" },
|
|
22276
|
+
"event"
|
|
22277
|
+
);
|
|
22278
|
+
} else if (wasAuto && d.reason !== "errored-turn") {
|
|
22279
|
+
sessionService.pushMessage(
|
|
22280
|
+
{ type: "message", message: describeNoBoundary(d.strikes, DEFAULT_COMPACT_NO_BOUNDARY_STRIKES), level: "warning" },
|
|
22281
|
+
"event"
|
|
22282
|
+
);
|
|
21968
22283
|
}
|
|
21969
|
-
logger.log(`[Session ${sessionId}] /compact produced no compaction boundary \u2014 Claude Code likely too old to handle it in stream-json mode`);
|
|
21970
|
-
sessionService.pushMessage(
|
|
21971
|
-
{ type: "message", message: compactUnsupportedWarning(), level: "warning" },
|
|
21972
|
-
"event"
|
|
21973
|
-
);
|
|
21974
22284
|
}
|
|
21975
22285
|
if (!msg.is_error) {
|
|
21976
22286
|
resetRateLimitStreak();
|
|
@@ -22061,7 +22371,15 @@ ${parts.join("\n")}`);
|
|
|
22061
22371
|
logger.log(`[Session ${sessionId}] ${taskInfo}`);
|
|
22062
22372
|
sessionService.pushMessage({ type: "session_event", message: taskInfo }, "session");
|
|
22063
22373
|
}
|
|
22064
|
-
|
|
22374
|
+
const mayEvaluateLayer1 = shouldEvaluateProactiveCompaction({
|
|
22375
|
+
justCompacted: justCompactedTurn,
|
|
22376
|
+
compactPending: pendingCompactTurn,
|
|
22377
|
+
turnErrored: !!msg.is_error,
|
|
22378
|
+
disabled: autoCompactDisabled,
|
|
22379
|
+
enabled: autoCompactEnabled
|
|
22380
|
+
});
|
|
22381
|
+
justCompactedTurn = false;
|
|
22382
|
+
if (mayEvaluateLayer1) {
|
|
22065
22383
|
try {
|
|
22066
22384
|
const observed = computeObservedContext(msg.usage);
|
|
22067
22385
|
const decision = decideProactiveCompaction({
|
|
@@ -22125,6 +22443,7 @@ ${parts.join("\n")}`);
|
|
|
22125
22443
|
userMessagePending = false;
|
|
22126
22444
|
if (msg.slash_commands && Array.isArray(msg.slash_commands)) {
|
|
22127
22445
|
sessionMetadata = { ...sessionMetadata, slashCommands: msg.slash_commands };
|
|
22446
|
+
compactSupported = compactSupportedFromSlashCommands(msg.slash_commands);
|
|
22128
22447
|
}
|
|
22129
22448
|
if (typeof msg.model === "string" && msg.model.length > 0) {
|
|
22130
22449
|
lastMainModel = msg.model;
|
|
@@ -22178,6 +22497,8 @@ ${parts.join("\n")}`);
|
|
|
22178
22497
|
pendingCompactTurn = false;
|
|
22179
22498
|
autoCompactWasAutoInjected = false;
|
|
22180
22499
|
autoCompactRecoveryTried = false;
|
|
22500
|
+
justCompactedTurn = true;
|
|
22501
|
+
compactNoBoundaryStrikes = 0;
|
|
22181
22502
|
const compactLine = describeCompaction(msg.compact_metadata);
|
|
22182
22503
|
logger.log(`[Session ${sessionId}] ${compactLine}`);
|
|
22183
22504
|
sessionService.pushMessage(
|
|
@@ -22994,11 +23315,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
22994
23315
|
});
|
|
22995
23316
|
},
|
|
22996
23317
|
onIssue: async (params) => {
|
|
22997
|
-
const { issueRpc } = await import('./rpc-
|
|
23318
|
+
const { issueRpc } = await import('./rpc-BsgXlOhI.mjs');
|
|
22998
23319
|
return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
|
|
22999
23320
|
},
|
|
23000
23321
|
onWorkflow: async (params) => {
|
|
23001
|
-
const { workflowRpc } = await import('./rpc-
|
|
23322
|
+
const { workflowRpc } = await import('./rpc-C6zBQ0L5.mjs');
|
|
23002
23323
|
return workflowRpc(params?.cwd || directory, params || {});
|
|
23003
23324
|
},
|
|
23004
23325
|
onRipgrep: async (args, cwd) => {
|
|
@@ -23218,6 +23539,8 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
23218
23539
|
active: true,
|
|
23219
23540
|
phase: "continue",
|
|
23220
23541
|
iteration: 0,
|
|
23542
|
+
started_at: rearmStartedAt(s.started_at, s.completed_at, Date.now()),
|
|
23543
|
+
// #1170
|
|
23221
23544
|
completed_at: void 0,
|
|
23222
23545
|
gave_up_reason: void 0,
|
|
23223
23546
|
verify_errors: 0,
|
|
@@ -23719,11 +24042,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
23719
24042
|
});
|
|
23720
24043
|
},
|
|
23721
24044
|
onIssue: async (params) => {
|
|
23722
|
-
const { issueRpc } = await import('./rpc-
|
|
24045
|
+
const { issueRpc } = await import('./rpc-BsgXlOhI.mjs');
|
|
23723
24046
|
return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
|
|
23724
24047
|
},
|
|
23725
24048
|
onWorkflow: async (params) => {
|
|
23726
|
-
const { workflowRpc } = await import('./rpc-
|
|
24049
|
+
const { workflowRpc } = await import('./rpc-C6zBQ0L5.mjs');
|
|
23727
24050
|
return workflowRpc(params?.cwd || directory, params || {});
|
|
23728
24051
|
},
|
|
23729
24052
|
onRipgrep: async (args, cwd) => {
|
|
@@ -24588,7 +24911,11 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24588
24911
|
sharingNotificationSync,
|
|
24589
24912
|
persistExposedTunnel,
|
|
24590
24913
|
forgetExposedTunnel,
|
|
24591
|
-
listExposedTunnels: () => loadExposedTunnels().map((t) => ({ name: t.name, ports: t.ports, group: t.group, sessionId: t.sessionId, addedAt: t.addedAt }))
|
|
24914
|
+
listExposedTunnels: () => loadExposedTunnels().map((t) => ({ name: t.name, ports: t.ports, group: t.group, sessionId: t.sessionId, addedAt: t.addedAt })),
|
|
24915
|
+
dropTunnelSessionLink: (sessionId, tunnelName) => {
|
|
24916
|
+
void dropTunnelSessionLink(sessionId, tunnelName);
|
|
24917
|
+
},
|
|
24918
|
+
scheduleServiceLinkReconcile: () => scheduleServiceLinkReconcile()
|
|
24592
24919
|
});
|
|
24593
24920
|
const machineService = await registerMachineService(
|
|
24594
24921
|
server,
|
|
@@ -24720,6 +25047,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24720
25047
|
} catch (err) {
|
|
24721
25048
|
logger.log(`[serve] mount link reconcile failed: ${err?.message || err}`);
|
|
24722
25049
|
}
|
|
25050
|
+
scheduleServiceLinkReconcile(3e3);
|
|
24723
25051
|
}).catch((err) => logger.error(`[serve] mount restore failed: ${err?.message || err}`));
|
|
24724
25052
|
const daemonOwnerEmail = parseJwtEmail(process.env.HYPHA_TOKEN || "") || null;
|
|
24725
25053
|
serveManager$1.setSessionResolver((sessionId) => {
|
|
@@ -24803,7 +25131,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24803
25131
|
}
|
|
24804
25132
|
if (persistedSessions.length > 0) {
|
|
24805
25133
|
try {
|
|
24806
|
-
const { awaitClaudeVersionReady } = await import('./pinnedClaudeCode-
|
|
25134
|
+
const { awaitClaudeVersionReady } = await import('./pinnedClaudeCode-C43KnZ-Q.mjs');
|
|
24807
25135
|
await awaitClaudeVersionReady();
|
|
24808
25136
|
} catch {
|
|
24809
25137
|
}
|
|
@@ -25069,7 +25397,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
25069
25397
|
const PING_TIMEOUT_MS = 15e3;
|
|
25070
25398
|
const POST_RECONNECT_GRACE_MS = 2e4;
|
|
25071
25399
|
const RECONNECT_JITTER_MS = 2500;
|
|
25072
|
-
const { WorkflowScheduler } = await import('./scheduler-
|
|
25400
|
+
const { WorkflowScheduler } = await import('./scheduler-Ciu9Qfsi.mjs');
|
|
25073
25401
|
const workflowProjectRoots = () => {
|
|
25074
25402
|
const dirs = /* @__PURE__ */ new Set();
|
|
25075
25403
|
for (const s of pidToTrackedSession.values()) {
|
|
@@ -25108,6 +25436,9 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
25108
25436
|
};
|
|
25109
25437
|
runOAuthAccountRefresh();
|
|
25110
25438
|
const backendAccountRefreshInterval = setInterval(runOAuthAccountRefresh, 5 * 6e4);
|
|
25439
|
+
const serviceLinkSweepInterval = setInterval(() => {
|
|
25440
|
+
void reconcileAllServiceLinks();
|
|
25441
|
+
}, 6e4);
|
|
25111
25442
|
let heartbeatRunning = false;
|
|
25112
25443
|
let heartbeatCycle = 0;
|
|
25113
25444
|
const heartbeatInterval = setInterval(async () => {
|
|
@@ -25360,6 +25691,8 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
25360
25691
|
clearInterval(heartbeatInterval);
|
|
25361
25692
|
clearInterval(workflowSchedulerInterval);
|
|
25362
25693
|
clearInterval(backendAccountRefreshInterval);
|
|
25694
|
+
clearInterval(serviceLinkSweepInterval);
|
|
25695
|
+
if (serviceLinkReconcileTimer) clearTimeout(serviceLinkReconcileTimer);
|
|
25363
25696
|
if (proxyTokenRefreshInterval) clearInterval(proxyTokenRefreshInterval);
|
|
25364
25697
|
if (oauthRefreshInterval) clearInterval(oauthRefreshInterval);
|
|
25365
25698
|
if (unhandledRejectionResetTimer) clearTimeout(unhandledRejectionResetTimer);
|
|
@@ -25704,4 +26037,4 @@ var run = /*#__PURE__*/Object.freeze({
|
|
|
25704
26037
|
writeStopMarker: writeStopMarker
|
|
25705
26038
|
});
|
|
25706
26039
|
|
|
25707
|
-
export {
|
|
26040
|
+
export { SKILLS_DIR as $, validateCronExpr as A, validateWorkflowName as B, saveWorkflow as C, rawWorkflow as D, listWorkflows as E, isWorkflowEnabled as F, workflowSchedules as G, inZone as H, cronMatches as I, summarize as J, workflowSteps as K, describeNextFire as L, parseJwtEmail as M, computeCollectionConfigUpdate as N, SYSTEM_COLLECTION_CONFIG as O, loadMachineContext as P, buildMachineInstructions as Q, READ_ONLY_TOOLS as R, SharingNotificationSync as S, machineToolsForRole as T, buildMachineTools as U, parseFrontmatter as V, getSkillsServer as W, getSkillsWorkspaceName as X, getSkillsCollectionName as Y, fetchWithTimeout as Z, searchSkills as _, createSessionStore as a, getSkillInfo as a0, downloadSkillFile as a1, listSkillFiles as a2, resolveModel as a3, formatHandle as a4, normalizeAllowedUser as a5, loadSecurityContextConfig as a6, resolveSecurityContext as a7, buildSecurityContextFromFlags as a8, mergeSecurityContexts as a9, GeminiTransport$1 as aA, KimiTransport$1 as aB, kimiProvider as aC, kimiSetup as aD, api as aE, supervisorLock as aF, run as aG, buildSessionShareUrl as aa, computeOutboundHop as ab, registerAwaitingReply as ac, buildMachineShareUrl as ad, parseHandle as ae, handleMatchesMetadata as af, PINNED_CODEX_VERSION as ag, clearStopMarker as ah, stopMarkerExists as ai, withFileLock as aj, describeMisconfiguration as ak, buildMachineDeps as al, applyClaudeProxyEnv as am, composeSessionId as an, generateFriendlyName as ao, generateHookSettings as ap, instanceConfig as aq, frpc as ar, staticFileServer as as, claudeAuth as at, codexProvider as au, projectInfo as av, DefaultTransport$1 as aw, acpBackend as ax, acpAgentConfig as ay, codexAppServerBackend as az, stopDaemon as b, connectToHypha as c, daemonStatus as d, shortId as e, resolveProjectRoot as f, getHyphaServerUrl$1 as g, getIssue as h, checkVerifyCommand as i, resumeIssue as j, addComment as k, addIssue as l, listIssues as m, isPendingIssue as n, searchIssues as o, pauseIssue as p, isVisibleTo as q, registerMachineService as r, startDaemon as s, getRun as t, updateIssue as u, listRuns as v, getWorkflow as w, runWorkflow as x, setWorkflowEnabled as y, removeWorkflow as z };
|