svamp-cli 0.2.324 → 0.2.326
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/README.md +2 -3
- package/bin/skills/crew/SKILL.md +10 -2
- package/dist/{adminCommands-CHE1wq5m.mjs → adminCommands-D1NzA4Hb.mjs} +1 -1
- package/dist/{agentCommands-D7CV6DKL.mjs → agentCommands-DUHUBzrj.mjs} +5 -5
- package/dist/{auth-BfimMIpL.mjs → auth-DogM3PPm.mjs} +3 -3
- package/dist/{cli-Dv0vM2P7.mjs → cli-PWoHWBkF.mjs} +79 -79
- package/dist/cli.mjs +4 -4
- package/dist/{commands-CuyCq5eZ.mjs → commands-B5bC9eXz.mjs} +3 -3
- package/dist/{commands-CQK2nD3o.mjs → commands-CBk4dLUP.mjs} +3 -3
- package/dist/{commands-CdbvHh2p.mjs → commands-Ck4pP86Q.mjs} +4 -4
- package/dist/{commands-BA4LVlQW.mjs → commands-CqqQYRzg.mjs} +2 -2
- package/dist/{commands-GRfwAHgR.mjs → commands-CxfUr2Qr.mjs} +1 -1
- package/dist/{commands-4hjEGB-I.mjs → commands-D-4ry2I6.mjs} +13 -13
- package/dist/{commands-BQ7UFowe.mjs → commands-Dm9KNB-p.mjs} +3 -3
- package/dist/{commands-jaaQooYW.mjs → commands-Dt_MecCB.mjs} +3 -3
- package/dist/{fleet-CSh3MUcM.mjs → fleet-Bzg3YxM4.mjs} +2 -2
- package/dist/{headlessCli-Zl5Yu4CL.mjs → headlessCli-DvJI9DRh.mjs} +4 -4
- package/dist/index.mjs +3 -3
- package/dist/{notifyCommands-BQZXhfLt.mjs → notifyCommands-BpMErHcv.mjs} +1 -1
- package/dist/{package-DgboZg2o.mjs → package-D_BgajkI.mjs} +2 -2
- package/dist/{pinnedClaudeCode-8SZDu7O-.mjs → pinnedClaudeCode-BO0Qs_kE.mjs} +1 -1
- package/dist/{rpc-C1KIoUyz.mjs → rpc-27xBajCe.mjs} +3 -3
- package/dist/{rpc-BIzMNjqC.mjs → rpc-Qcj4M_LQ.mjs} +3 -3
- package/dist/{run-CEp9YpUZ.mjs → run-BBBr4jkI.mjs} +202 -47
- package/dist/{run-DKAROgSg.mjs → run-CocRShOR.mjs} +1 -1
- package/dist/{scheduler-DIYulmdV.mjs → scheduler-DjAVEyn3.mjs} +3 -3
- package/dist/{serveCommands-Bq5Cw3mE.mjs → serveCommands-BK-wWc_i.mjs} +12 -12
- package/dist/{sideband-C83128hf.mjs → sideband-5ck3CDWM.mjs} +3 -3
- package/package.json +3 -3
|
@@ -8,15 +8,15 @@ 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
10
|
import { randomUUID, createHash } from 'crypto';
|
|
11
|
-
import { randomUUID as randomUUID$1, randomBytes, createHash as createHash$1, timingSafeEqual } from 'node:crypto';
|
|
12
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';
|
|
12
|
+
import { join as join$1, extname, resolve, sep, basename, dirname } from 'node:path';
|
|
13
|
+
import { randomUUID as randomUUID$1, randomBytes, createHash as createHash$1, timingSafeEqual } from 'node:crypto';
|
|
13
14
|
import { exec, spawn as spawn$1, execSync as execSync$1, execFile as execFile$1, execFileSync } from 'node:child_process';
|
|
14
15
|
import { promisify } from 'util';
|
|
15
16
|
import * as http from 'http';
|
|
16
17
|
import * as net from 'net';
|
|
17
18
|
import { createServer } from 'net';
|
|
18
19
|
import os, { homedir as homedir$1, platform as platform$1 } from 'node:os';
|
|
19
|
-
import { join as join$1, extname, resolve, sep, basename, dirname } from 'node:path';
|
|
20
20
|
import { EventEmitter } from 'node:events';
|
|
21
21
|
import { ndJsonStream, ClientSideConnection } from '@agentclientprotocol/sdk';
|
|
22
22
|
import { promisify as promisify$1 } from 'node:util';
|
|
@@ -3160,6 +3160,9 @@ class ServeManager {
|
|
|
3160
3160
|
hyphaServerUrl;
|
|
3161
3161
|
/** #126: daemon-provided lookup of sessionId → { cwd, sharing, ownerEmail } for the files gateway. */
|
|
3162
3162
|
sessionResolver = null;
|
|
3163
|
+
/** Channel-capability authorizer: a `fileAccess`-enabled channel's caller key grants
|
|
3164
|
+
* whole-project file management for its session. Checked BEFORE email auth. */
|
|
3165
|
+
capabilityAuthorizer = null;
|
|
3163
3166
|
/**
|
|
3164
3167
|
* #0944/#0945: daemon-provided "this mount no longer backs that session's Launch Pad entry"
|
|
3165
3168
|
* hook. Fired with the OWNING session id, which is the only correct target — the CLI-side
|
|
@@ -3189,6 +3192,30 @@ class ServeManager {
|
|
|
3189
3192
|
setSessionResolver(fn) {
|
|
3190
3193
|
this.sessionResolver = fn;
|
|
3191
3194
|
}
|
|
3195
|
+
/**
|
|
3196
|
+
* Register the channel-capability authorizer used by the session-files gateway to admit
|
|
3197
|
+
* a `fileAccess`-enabled channel's caller key (ck_… bearer). Call once at daemon start.
|
|
3198
|
+
*/
|
|
3199
|
+
setCapabilityAuthorizer(fn) {
|
|
3200
|
+
this.capabilityAuthorizer = fn;
|
|
3201
|
+
}
|
|
3202
|
+
/**
|
|
3203
|
+
* Extract a channel capability token from the request, if one is present. A channel caller
|
|
3204
|
+
* key is `ck_`-prefixed; we ONLY return a token that carries that prefix so a Hypha JWT
|
|
3205
|
+
* bearer (used by the email-identity path) never collides with the capability authorizer.
|
|
3206
|
+
* Accepted carriers: `Authorization: Bearer ck_…` header, or `?key=ck_…` query param.
|
|
3207
|
+
* Returns null when no capability token is presented. NEVER log the returned value.
|
|
3208
|
+
*/
|
|
3209
|
+
extractCapabilityToken(req, url) {
|
|
3210
|
+
const auth = req.headers["authorization"];
|
|
3211
|
+
if (typeof auth === "string") {
|
|
3212
|
+
const m = /^Bearer\s+(\S+)$/i.exec(auth.trim());
|
|
3213
|
+
if (m && m[1].startsWith("ck_")) return m[1];
|
|
3214
|
+
}
|
|
3215
|
+
const q = url.searchParams.get("key");
|
|
3216
|
+
if (q && q.startsWith("ck_")) return q;
|
|
3217
|
+
return null;
|
|
3218
|
+
}
|
|
3192
3219
|
/**
|
|
3193
3220
|
* #0944/#0945: register the daemon's "drop this session's Launch Pad link for this mount"
|
|
3194
3221
|
* callback. Fired when a mount stops backing a session's Pad entry — on a real removal, and
|
|
@@ -3785,26 +3812,47 @@ a{color:#0969da;text-decoration:none;font-weight:500}a:hover{text-decoration:und
|
|
|
3785
3812
|
deny(404, "Unknown session");
|
|
3786
3813
|
return;
|
|
3787
3814
|
}
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3815
|
+
let capabilityGranted = false;
|
|
3816
|
+
const capToken = this.extractCapabilityToken(req, url);
|
|
3817
|
+
if (capToken && this.capabilityAuthorizer) {
|
|
3818
|
+
try {
|
|
3819
|
+
capabilityGranted = this.capabilityAuthorizer(sessionId, capToken);
|
|
3820
|
+
} catch {
|
|
3821
|
+
capabilityGranted = false;
|
|
3822
|
+
}
|
|
3792
3823
|
}
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
if (!sharing || !sharing.enabled) {
|
|
3798
|
-
this.log(`Files-gateway DENY '${sessionId}': ${userEmail} not owner and session not shared`);
|
|
3799
|
-
deny(403, "Access denied");
|
|
3824
|
+
if (!capabilityGranted) {
|
|
3825
|
+
const userEmail = this.auth ? await this.auth.authenticate(req).catch(() => null) : null;
|
|
3826
|
+
if (!userEmail) {
|
|
3827
|
+
deny(401, "Authentication required");
|
|
3800
3828
|
return;
|
|
3801
3829
|
}
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3830
|
+
const ownerEmail = (target.ownerEmail || "").toLowerCase();
|
|
3831
|
+
const isOwner = !!ownerEmail && userEmail.toLowerCase() === ownerEmail;
|
|
3832
|
+
if (!isOwner) {
|
|
3833
|
+
const principal = { user: { email: userEmail } };
|
|
3834
|
+
let granted = false;
|
|
3835
|
+
const sharing = target.sharing;
|
|
3836
|
+
if (sharing && sharing.enabled) {
|
|
3837
|
+
try {
|
|
3838
|
+
authorizeRequest(principal, sharing, "admin");
|
|
3839
|
+
granted = true;
|
|
3840
|
+
} catch {
|
|
3841
|
+
}
|
|
3842
|
+
}
|
|
3843
|
+
const machineSharing = target.machineSharing;
|
|
3844
|
+
if (!granted && machineSharing && machineSharing.enabled) {
|
|
3845
|
+
try {
|
|
3846
|
+
authorizeRequest(principal, machineSharing, "admin");
|
|
3847
|
+
granted = true;
|
|
3848
|
+
} catch {
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
if (!granted) {
|
|
3852
|
+
this.log(`Files-gateway DENY '${sessionId}': ${userEmail} not owner and not a session/machine admin`);
|
|
3853
|
+
deny(403, "Access denied");
|
|
3854
|
+
return;
|
|
3855
|
+
}
|
|
3808
3856
|
}
|
|
3809
3857
|
}
|
|
3810
3858
|
const rootDir = target.cwd;
|
|
@@ -5603,6 +5651,12 @@ function validateChannel(c) {
|
|
|
5603
5651
|
if (m === "fixed" && c.identity.fixed?.name && unsafe.test(c.identity.fixed.name)) errs.push(`identity.fixed.name must not contain < > " ' & or newlines`);
|
|
5604
5652
|
for (const cl of c.identity?.callers || []) if (unsafe.test(cl.name || "")) errs.push(`caller name "${cl.name}" must not contain < > " ' & or newlines`);
|
|
5605
5653
|
errs.push(...validateUploadConfig(c));
|
|
5654
|
+
if (c.fileAccess !== void 0) {
|
|
5655
|
+
if (typeof c.fileAccess !== "object" || c.fileAccess === null || Array.isArray(c.fileAccess))
|
|
5656
|
+
errs.push("fileAccess must be an object");
|
|
5657
|
+
else if (c.fileAccess.enabled !== void 0 && typeof c.fileAccess.enabled !== "boolean")
|
|
5658
|
+
errs.push("fileAccess.enabled must be a boolean");
|
|
5659
|
+
}
|
|
5606
5660
|
return errs;
|
|
5607
5661
|
}
|
|
5608
5662
|
function normalizeBind(c) {
|
|
@@ -5626,6 +5680,24 @@ function channelAsyncRepliable(c) {
|
|
|
5626
5680
|
if ((c.action?.kind ?? "message") !== "message") return false;
|
|
5627
5681
|
return bindMode(c) !== "stateless";
|
|
5628
5682
|
}
|
|
5683
|
+
function channelKeyGrantsFileAccess(channels, token) {
|
|
5684
|
+
if (!token || !token.startsWith("ck_")) return false;
|
|
5685
|
+
const presented = createHash$1("sha256").update(token).digest();
|
|
5686
|
+
const eq = (candidate) => {
|
|
5687
|
+
if (!candidate) return false;
|
|
5688
|
+
try {
|
|
5689
|
+
return timingSafeEqual(presented, createHash$1("sha256").update(candidate).digest());
|
|
5690
|
+
} catch {
|
|
5691
|
+
return false;
|
|
5692
|
+
}
|
|
5693
|
+
};
|
|
5694
|
+
for (const ch of channels) {
|
|
5695
|
+
if (!ch.fileAccess?.enabled) continue;
|
|
5696
|
+
if (eq(ch.identity?.shared_key)) return true;
|
|
5697
|
+
for (const caller of ch.identity?.callers || []) if (eq(caller.key)) return true;
|
|
5698
|
+
}
|
|
5699
|
+
return false;
|
|
5700
|
+
}
|
|
5629
5701
|
class ChannelStore {
|
|
5630
5702
|
dir;
|
|
5631
5703
|
constructor(projectDir) {
|
|
@@ -5654,7 +5726,7 @@ class ChannelStore {
|
|
|
5654
5726
|
if (errs.length) throw new Error("invalid channel: " + errs.join("; "));
|
|
5655
5727
|
mkdirSync$1(this.dir, { recursive: true });
|
|
5656
5728
|
const tmp = `${this._path(c.id)}.tmp-${process.pid}-${randomBytes(4).toString("hex")}`;
|
|
5657
|
-
writeFileSync$1(tmp, JSON.stringify(c, null, 2));
|
|
5729
|
+
writeFileSync$1(tmp, JSON.stringify(c, null, 2), { mode: 384 });
|
|
5658
5730
|
renameSync(tmp, this._path(c.id));
|
|
5659
5731
|
return c;
|
|
5660
5732
|
}
|
|
@@ -5836,6 +5908,32 @@ curl -X POST "${uploadUrl}" \\
|
|
|
5836
5908
|
-d '{"kwargs": {"channel": "${channel.id}", "filename": "report.pdf", "content_base64": "<base64>", "content_type": "application/pdf", "from": "your-name", "key": "${key}"}}'
|
|
5837
5909
|
\`\`\``;
|
|
5838
5910
|
})() : "";
|
|
5911
|
+
const filesBase = ctx?.filesEndpoint;
|
|
5912
|
+
const fileSection = channel.fileAccess?.enabled && filesBase ? `
|
|
5913
|
+
|
|
5914
|
+
## Managing project files
|
|
5915
|
+
This channel also grants **full file management of the whole project folder** \u2014 list,
|
|
5916
|
+
download, upload, and delete any file in the working directory (this is NOT the sandboxed
|
|
5917
|
+
\`upload\` above). Authenticate every request with your channel key as a Bearer token:
|
|
5918
|
+
|
|
5919
|
+
Base: \`${filesBase}\` \u2014 append a project-relative path (URL-encode as needed).
|
|
5920
|
+
|
|
5921
|
+
- **List a directory:** \`GET ${filesBase}/<dir>/?list=1\` \u2192 JSON of entries
|
|
5922
|
+
- **Download a file:** \`GET ${filesBase}/<path>\`
|
|
5923
|
+
- **Upload / overwrite:** \`PUT ${filesBase}/<path>\` with the raw file bytes as the body
|
|
5924
|
+
- **Delete a file:** \`DELETE ${filesBase}/<path>\`
|
|
5925
|
+
|
|
5926
|
+
\`\`\`bash
|
|
5927
|
+
# list the project root
|
|
5928
|
+
curl -H "Authorization: Bearer ${key}" "${filesBase}/?list=1"
|
|
5929
|
+
# download a file
|
|
5930
|
+
curl -H "Authorization: Bearer ${key}" "${filesBase}/README.md" -o README.md
|
|
5931
|
+
# upload / overwrite a file (raw bytes)
|
|
5932
|
+
curl -X PUT -H "Authorization: Bearer ${key}" --data-binary @local.txt "${filesBase}/notes/local.txt"
|
|
5933
|
+
# delete a file
|
|
5934
|
+
curl -X DELETE -H "Authorization: Bearer ${key}" "${filesBase}/notes/local.txt"
|
|
5935
|
+
\`\`\`
|
|
5936
|
+
> \u26A0\uFE0F Anyone holding this key can read, write, and **delete** any file in this project. Revoke it when you're done.` : "";
|
|
5839
5937
|
return `---
|
|
5840
5938
|
name: ${name}
|
|
5841
5939
|
description: ${desc}
|
|
@@ -5868,7 +5966,7 @@ curl -X POST "${sendUrl}" \\
|
|
|
5868
5966
|
-d '{"kwargs": {"channel": "${channel.id}", "message": "your message here", "from": "your-name", "key": "${key}"${sessionKv}}}'
|
|
5869
5967
|
\`\`\`
|
|
5870
5968
|
|
|
5871
|
-
Always-current copy of this skill (all ids filled in): ${skillUrl}${uploadSection}${queueSection}`;
|
|
5969
|
+
Always-current copy of this skill (all ids filled in): ${skillUrl}${uploadSection}${fileSection}${queueSection}`;
|
|
5872
5970
|
}
|
|
5873
5971
|
|
|
5874
5972
|
function keysMatch(a, b) {
|
|
@@ -8091,7 +8189,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
8091
8189
|
}
|
|
8092
8190
|
const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
|
|
8093
8191
|
const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
|
|
8094
|
-
const { toolsForRole } = await import('./sideband-
|
|
8192
|
+
const { toolsForRole } = await import('./sideband-5ck3CDWM.mjs');
|
|
8095
8193
|
const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
|
|
8096
8194
|
return fmt(r2);
|
|
8097
8195
|
}
|
|
@@ -8196,7 +8294,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
8196
8294
|
return { ok: false, call_id: callId, status: "busy", error: "channel is busy (too many concurrent requests) \u2014 retry shortly" };
|
|
8197
8295
|
}
|
|
8198
8296
|
const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
|
|
8199
|
-
const { queryCore } = await import('./commands-
|
|
8297
|
+
const { queryCore } = await import('./commands-CxfUr2Qr.mjs');
|
|
8200
8298
|
const timeout = c.reply?.timeout_sec || 120;
|
|
8201
8299
|
let result;
|
|
8202
8300
|
try {
|
|
@@ -9664,7 +9762,11 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
|
|
|
9664
9762
|
key: c.identity?.shared_key,
|
|
9665
9763
|
// The session this skill is being copied FROM — baked into `dynamic` channel
|
|
9666
9764
|
// instructions as the routing target so the copied link lands in THIS session.
|
|
9667
|
-
session: sessionId
|
|
9765
|
+
session: sessionId,
|
|
9766
|
+
// For a fileAccess-enabled channel, the session-files REST gateway prefix
|
|
9767
|
+
// (`<base>/s/<sessionId>/`) so generateSkillBody can render the file curl block.
|
|
9768
|
+
// Null until the always-on gateway tunnel is up ⇒ the file section is omitted.
|
|
9769
|
+
filesEndpoint: callbacks.onFilesEndpoint?.() ?? void 0
|
|
9668
9770
|
});
|
|
9669
9771
|
const skillUrlsFor = (c) => {
|
|
9670
9772
|
if (!channelsServiceId) return { skillUrl: void 0, sendUrl: void 0 };
|
|
@@ -10240,10 +10342,17 @@ function createSessionStore(server, sessionId, initialMetadata, initialAgentStat
|
|
|
10240
10342
|
return { error: e?.message || String(e) };
|
|
10241
10343
|
}
|
|
10242
10344
|
},
|
|
10243
|
-
recordMeetingActivity: async (params) => {
|
|
10345
|
+
recordMeetingActivity: async (params, context) => {
|
|
10244
10346
|
const c = channelStore.get(params.channel);
|
|
10245
10347
|
if (!c || c.enabled === false) return { error: "channel not found" };
|
|
10246
|
-
const
|
|
10348
|
+
const u = context?.user;
|
|
10349
|
+
const r = resolveSender(c, {
|
|
10350
|
+
key: params.key,
|
|
10351
|
+
from: params.from,
|
|
10352
|
+
hyphaUser: u && u.is_anonymous !== true ? u.email || u.id : void 0,
|
|
10353
|
+
hyphaAnonymous: u?.is_anonymous === true,
|
|
10354
|
+
hyphaWorkspace: u?.scope?.current_workspace
|
|
10355
|
+
});
|
|
10247
10356
|
if (r.error || !r.sender) return { error: r.error || "unauthorized" };
|
|
10248
10357
|
const text = String(params.text || "").replace(/\s+/g, " ").trim().slice(0, 1e3);
|
|
10249
10358
|
if (!text) return { ok: true };
|
|
@@ -11453,6 +11562,25 @@ function handleClaudeMessage(ctx, msg) {
|
|
|
11453
11562
|
}
|
|
11454
11563
|
}
|
|
11455
11564
|
|
|
11565
|
+
function sessionQueueMax(env = process.env) {
|
|
11566
|
+
return Math.max(10, Number(env.SVAMP_SESSION_QUEUE_MAX) || 200);
|
|
11567
|
+
}
|
|
11568
|
+
function appendToMessageQueue(existing, entry, max = sessionQueueMax()) {
|
|
11569
|
+
const next = [...existing, entry];
|
|
11570
|
+
if (next.length <= max) return { queue: next, dropped: 0 };
|
|
11571
|
+
const overflow = next.length - max;
|
|
11572
|
+
let budget = overflow;
|
|
11573
|
+
const kept = [];
|
|
11574
|
+
for (const item of next) {
|
|
11575
|
+
if (budget > 0 && item !== entry && item.inboxHop !== void 0) {
|
|
11576
|
+
budget--;
|
|
11577
|
+
continue;
|
|
11578
|
+
}
|
|
11579
|
+
kept.push(item);
|
|
11580
|
+
}
|
|
11581
|
+
return { queue: kept, dropped: overflow - budget };
|
|
11582
|
+
}
|
|
11583
|
+
|
|
11456
11584
|
const KNOWN_AGENT_LAUNCHERS = ["claude", "codex", "gemini", "kimi"];
|
|
11457
11585
|
function agentLauncherExists(cmd, env = process.env) {
|
|
11458
11586
|
if (!cmd) return false;
|
|
@@ -19954,7 +20082,7 @@ async function startDaemon(options) {
|
|
|
19954
20082
|
try {
|
|
19955
20083
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
19956
20084
|
if (!dir) return;
|
|
19957
|
-
const { reconcileServiceLinks } = await import('./agentCommands-
|
|
20085
|
+
const { reconcileServiceLinks } = await import('./agentCommands-DUHUBzrj.mjs');
|
|
19958
20086
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
19959
20087
|
const config = readSvampConfig(configPath);
|
|
19960
20088
|
const entries = Array.from(urls.entries());
|
|
@@ -19976,7 +20104,7 @@ async function startDaemon(options) {
|
|
|
19976
20104
|
try {
|
|
19977
20105
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
19978
20106
|
if (!dir) return;
|
|
19979
|
-
const { reconcileServiceLinks } = await import('./agentCommands-
|
|
20107
|
+
const { reconcileServiceLinks } = await import('./agentCommands-DUHUBzrj.mjs');
|
|
19980
20108
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
19981
20109
|
const config = readSvampConfig(configPath);
|
|
19982
20110
|
const incoming = [{
|
|
@@ -19997,7 +20125,7 @@ async function startDaemon(options) {
|
|
|
19997
20125
|
try {
|
|
19998
20126
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
19999
20127
|
if (!dir) return;
|
|
20000
|
-
const { dropServiceLinks } = await import('./agentCommands-
|
|
20128
|
+
const { dropServiceLinks } = await import('./agentCommands-DUHUBzrj.mjs');
|
|
20001
20129
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
20002
20130
|
const config = readSvampConfig(configPath);
|
|
20003
20131
|
if (dropServiceLinks(config, "serve", mountName)) {
|
|
@@ -20040,7 +20168,7 @@ async function startDaemon(options) {
|
|
|
20040
20168
|
ensureAutoInstalledCommands(logger);
|
|
20041
20169
|
(async () => {
|
|
20042
20170
|
try {
|
|
20043
|
-
const { beginClaudeVersionReconcile } = await import('./pinnedClaudeCode-
|
|
20171
|
+
const { beginClaudeVersionReconcile } = await import('./pinnedClaudeCode-BO0Qs_kE.mjs');
|
|
20044
20172
|
beginClaudeVersionReconcile((msg) => logger.log(msg));
|
|
20045
20173
|
} catch (e) {
|
|
20046
20174
|
logger.log(`[claude-version] check failed: ${e?.message || e}`);
|
|
@@ -22304,11 +22432,13 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
22304
22432
|
} else {
|
|
22305
22433
|
logger.log(`[Session ${sessionId}] Queuing inbox message for idle processing`);
|
|
22306
22434
|
const existingQueue = sessionMetadata.messageQueue || [];
|
|
22307
|
-
|
|
22308
|
-
|
|
22309
|
-
messageQueue: [...existingQueue, { id: message.messageId, text: formatted, displayText: formatted, createdAt: Date.now(), inboxHop: message.hopCount ?? 0, inboxThreadId: message.threadId || message.messageId }]
|
|
22310
|
-
};
|
|
22435
|
+
const { queue: cappedQueue, dropped } = appendToMessageQueue(existingQueue, { id: message.messageId, text: formatted, displayText: formatted, createdAt: Date.now(), inboxHop: message.hopCount ?? 0, inboxThreadId: message.threadId || message.messageId });
|
|
22436
|
+
sessionMetadata = { ...sessionMetadata, messageQueue: cappedQueue };
|
|
22311
22437
|
sessionService.updateMetadata(sessionMetadata);
|
|
22438
|
+
if (dropped > 0) {
|
|
22439
|
+
logger.log(`[Session ${sessionId}] Inbox queue over ${sessionQueueMax()}; dropped ${dropped} oldest queued inbox message(s)`);
|
|
22440
|
+
sessionService.pushMessage({ type: "message", message: `Inbox queue full (${sessionQueueMax()}) \u2014 dropped ${dropped} older queued message(s).`, level: "warning" }, "event");
|
|
22441
|
+
}
|
|
22312
22442
|
if (!sessionWasProcessing) {
|
|
22313
22443
|
setTimeout(() => processMessageQueueRef?.(), 200);
|
|
22314
22444
|
}
|
|
@@ -22367,11 +22497,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
22367
22497
|
});
|
|
22368
22498
|
},
|
|
22369
22499
|
onIssue: async (params) => {
|
|
22370
|
-
const { issueRpc } = await import('./rpc-
|
|
22500
|
+
const { issueRpc } = await import('./rpc-Qcj4M_LQ.mjs');
|
|
22371
22501
|
return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
|
|
22372
22502
|
},
|
|
22373
22503
|
onWorkflow: async (params) => {
|
|
22374
|
-
const { workflowRpc } = await import('./rpc-
|
|
22504
|
+
const { workflowRpc } = await import('./rpc-27xBajCe.mjs');
|
|
22375
22505
|
return workflowRpc(params?.cwd || directory, params || {});
|
|
22376
22506
|
},
|
|
22377
22507
|
onRipgrep: async (args, cwd) => {
|
|
@@ -22982,11 +23112,13 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
22982
23112
|
} else {
|
|
22983
23113
|
logger.log(`[${agentName} Session ${sessionId}] Queuing inbox message for idle processing`);
|
|
22984
23114
|
const existingQueue = sessionMetadata.messageQueue || [];
|
|
22985
|
-
|
|
22986
|
-
|
|
22987
|
-
messageQueue: [...existingQueue, { id: message.messageId, text: formatted, displayText: formatted, createdAt: Date.now(), inboxHop: message.hopCount ?? 0, inboxThreadId: message.threadId || message.messageId }]
|
|
22988
|
-
};
|
|
23115
|
+
const { queue: cappedQueue, dropped } = appendToMessageQueue(existingQueue, { id: message.messageId, text: formatted, displayText: formatted, createdAt: Date.now(), inboxHop: message.hopCount ?? 0, inboxThreadId: message.threadId || message.messageId });
|
|
23116
|
+
sessionMetadata = { ...sessionMetadata, messageQueue: cappedQueue };
|
|
22989
23117
|
sessionService.updateMetadata(sessionMetadata);
|
|
23118
|
+
if (dropped > 0) {
|
|
23119
|
+
logger.log(`[${agentName} Session ${sessionId}] Inbox queue over ${sessionQueueMax()}; dropped ${dropped} oldest queued inbox message(s)`);
|
|
23120
|
+
sessionService.pushMessage({ type: "message", message: `Inbox queue full (${sessionQueueMax()}) \u2014 dropped ${dropped} older queued message(s).`, level: "warning" }, "event");
|
|
23121
|
+
}
|
|
22990
23122
|
if (sessionMetadata.lifecycleState === "idle" && acpBackendReady) {
|
|
22991
23123
|
const queue = sessionMetadata.messageQueue;
|
|
22992
23124
|
if (queue && queue.length > 0) {
|
|
@@ -23075,11 +23207,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
23075
23207
|
});
|
|
23076
23208
|
},
|
|
23077
23209
|
onIssue: async (params) => {
|
|
23078
|
-
const { issueRpc } = await import('./rpc-
|
|
23210
|
+
const { issueRpc } = await import('./rpc-Qcj4M_LQ.mjs');
|
|
23079
23211
|
return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
|
|
23080
23212
|
},
|
|
23081
23213
|
onWorkflow: async (params) => {
|
|
23082
|
-
const { workflowRpc } = await import('./rpc-
|
|
23214
|
+
const { workflowRpc } = await import('./rpc-27xBajCe.mjs');
|
|
23083
23215
|
return workflowRpc(params?.cwd || directory, params || {});
|
|
23084
23216
|
},
|
|
23085
23217
|
onRipgrep: async (args, cwd) => {
|
|
@@ -24087,20 +24219,43 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24087
24219
|
} catch {
|
|
24088
24220
|
sharing = null;
|
|
24089
24221
|
}
|
|
24222
|
+
let machineSharing = null;
|
|
24223
|
+
try {
|
|
24224
|
+
machineSharing = machineService.getCurrentMetadata()?.sharing ?? null;
|
|
24225
|
+
} catch {
|
|
24226
|
+
machineSharing = null;
|
|
24227
|
+
}
|
|
24090
24228
|
return {
|
|
24091
24229
|
cwd: session.directory,
|
|
24092
24230
|
sharing,
|
|
24093
|
-
ownerEmail: sharing?.owner || daemonOwnerEmail
|
|
24231
|
+
ownerEmail: sharing?.owner || daemonOwnerEmail,
|
|
24232
|
+
machineSharing
|
|
24094
24233
|
};
|
|
24095
24234
|
}
|
|
24096
24235
|
}
|
|
24097
24236
|
return null;
|
|
24098
24237
|
});
|
|
24238
|
+
serveManager$1.setCapabilityAuthorizer((sessionId, token) => {
|
|
24239
|
+
if (!token || !token.startsWith("ck_")) return false;
|
|
24240
|
+
let cwd = null;
|
|
24241
|
+
for (const [, session] of pidToTrackedSession) {
|
|
24242
|
+
if (session.svampSessionId === sessionId && !session.stopped && session.directory) {
|
|
24243
|
+
cwd = session.directory;
|
|
24244
|
+
break;
|
|
24245
|
+
}
|
|
24246
|
+
}
|
|
24247
|
+
if (!cwd) return false;
|
|
24248
|
+
try {
|
|
24249
|
+
return channelKeyGrantsFileAccess(new ChannelStore(cwd).list(), token);
|
|
24250
|
+
} catch {
|
|
24251
|
+
return false;
|
|
24252
|
+
}
|
|
24253
|
+
});
|
|
24099
24254
|
const sessionFilesToken = createHash("sha256").update(`session-files:${machineId}`).digest("hex").slice(0, 20);
|
|
24100
24255
|
serveManager$1.ensureSessionFilesGateway(sessionFilesToken).then((base) => logger.log(`[serve] session-files gateway: ${base || "(tunnel pending)"}`)).catch((err) => logger.error(`[serve] session-files gateway failed: ${err?.message || err}`));
|
|
24101
24256
|
const persistedSessions = loadPersistedSessions();
|
|
24257
|
+
const knownIds = new Set(persistedSessions.map((s) => s.sessionId).concat(Object.keys(loadSessionIndex())));
|
|
24102
24258
|
try {
|
|
24103
|
-
const knownIds = new Set(persistedSessions.map((s) => s.sessionId).concat(Object.keys(loadSessionIndex())));
|
|
24104
24259
|
const { removed } = await sweepOrphanedStagedHomes(knownIds);
|
|
24105
24260
|
if (removed.length > 0) {
|
|
24106
24261
|
logger.log(`Cleaned up ${removed.length} orphaned staged home(s) from prior runs.`);
|
|
@@ -24111,7 +24266,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24111
24266
|
const sessionsToAutoContinue = [];
|
|
24112
24267
|
const sessionsToLoopResume = [];
|
|
24113
24268
|
{
|
|
24114
|
-
const knownSessionIds =
|
|
24269
|
+
const knownSessionIds = knownIds;
|
|
24115
24270
|
const sweptDirs = /* @__PURE__ */ new Set();
|
|
24116
24271
|
for (const p of persistedSessions) {
|
|
24117
24272
|
if (sweptDirs.has(p.directory)) continue;
|
|
@@ -24136,7 +24291,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24136
24291
|
}
|
|
24137
24292
|
if (persistedSessions.length > 0) {
|
|
24138
24293
|
try {
|
|
24139
|
-
const { awaitClaudeVersionReady } = await import('./pinnedClaudeCode-
|
|
24294
|
+
const { awaitClaudeVersionReady } = await import('./pinnedClaudeCode-BO0Qs_kE.mjs');
|
|
24140
24295
|
await awaitClaudeVersionReady();
|
|
24141
24296
|
} catch {
|
|
24142
24297
|
}
|
|
@@ -24393,7 +24548,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
24393
24548
|
const PING_TIMEOUT_MS = 15e3;
|
|
24394
24549
|
const POST_RECONNECT_GRACE_MS = 2e4;
|
|
24395
24550
|
const RECONNECT_JITTER_MS = 2500;
|
|
24396
|
-
const { WorkflowScheduler } = await import('./scheduler-
|
|
24551
|
+
const { WorkflowScheduler } = await import('./scheduler-DjAVEyn3.mjs');
|
|
24397
24552
|
const workflowProjectRoots = () => {
|
|
24398
24553
|
const dirs = /* @__PURE__ */ new Set();
|
|
24399
24554
|
for (const s of pidToTrackedSession.values()) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { aj as applyClaudeProxyEnv, ak as composeSessionId, al as generateFriendlyName, c as connectToHypha, a as createSessionStore, r as registerMachineService, am as generateHookSettings } from './run-
|
|
1
|
+
import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { aj as applyClaudeProxyEnv, ak as composeSessionId, al as generateFriendlyName, c as connectToHypha, a as createSessionStore, r as registerMachineService, am as generateHookSettings } from './run-BBBr4jkI.mjs';
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import { resolve, join } from 'node:path';
|
|
4
4
|
import { existsSync, readFileSync, watch } from 'node:fs';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f as resolveProjectRoot, C as listWorkflows, D as isWorkflowEnabled, E as workflowSchedules, F as inZone, w as runWorkflow, G as cronMatches } from './run-
|
|
1
|
+
import { f as resolveProjectRoot, C as listWorkflows, D as isWorkflowEnabled, E as workflowSchedules, F as inZone, w as runWorkflow, G as cronMatches } from './run-BBBr4jkI.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -6,14 +6,14 @@ import 'path';
|
|
|
6
6
|
import 'url';
|
|
7
7
|
import 'child_process';
|
|
8
8
|
import 'crypto';
|
|
9
|
-
import 'node:crypto';
|
|
10
9
|
import 'node:fs';
|
|
10
|
+
import 'node:path';
|
|
11
|
+
import 'node:crypto';
|
|
11
12
|
import 'node:child_process';
|
|
12
13
|
import 'util';
|
|
13
14
|
import 'http';
|
|
14
15
|
import 'net';
|
|
15
16
|
import 'node:os';
|
|
16
|
-
import 'node:path';
|
|
17
17
|
import 'node:events';
|
|
18
18
|
import '@agentclientprotocol/sdk';
|
|
19
19
|
import 'node:util';
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
|
-
import { w as wantsHelp } from './cli-
|
|
3
|
-
import './run-
|
|
2
|
+
import { w as wantsHelp } from './cli-PWoHWBkF.mjs';
|
|
3
|
+
import './run-BBBr4jkI.mjs';
|
|
4
4
|
import 'os';
|
|
5
5
|
import 'fs/promises';
|
|
6
6
|
import 'fs';
|
|
7
7
|
import 'url';
|
|
8
8
|
import 'child_process';
|
|
9
9
|
import 'crypto';
|
|
10
|
-
import 'node:crypto';
|
|
11
10
|
import 'node:fs';
|
|
11
|
+
import 'node:path';
|
|
12
|
+
import 'node:crypto';
|
|
12
13
|
import 'node:child_process';
|
|
13
14
|
import 'util';
|
|
14
15
|
import 'http';
|
|
15
16
|
import 'net';
|
|
16
17
|
import 'node:os';
|
|
17
|
-
import 'node:path';
|
|
18
18
|
import 'node:events';
|
|
19
19
|
import '@agentclientprotocol/sdk';
|
|
20
20
|
import 'node:util';
|
|
@@ -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-CxfUr2Qr.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-DUHUBzrj.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-CxfUr2Qr.mjs');
|
|
128
128
|
const fs = await import('fs');
|
|
129
129
|
const yaml = await import('yaml');
|
|
130
130
|
const file = positionalArgs(args)[0];
|
|
@@ -206,7 +206,7 @@ async function serveApply(args, machineId) {
|
|
|
206
206
|
console.log(`URL: ${result.url}`);
|
|
207
207
|
if (params.sessionId && result?.url) {
|
|
208
208
|
try {
|
|
209
|
-
const { autoAddSessionLink } = await import('./agentCommands-
|
|
209
|
+
const { autoAddSessionLink } = await import('./agentCommands-DUHUBzrj.mjs');
|
|
210
210
|
const prevSession = process.env.SVAMP_SESSION_ID;
|
|
211
211
|
process.env.SVAMP_SESSION_ID = String(params.sessionId);
|
|
212
212
|
try {
|
|
@@ -227,7 +227,7 @@ async function serveApply(args, machineId) {
|
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
229
|
async function serveRemove(args, machineId) {
|
|
230
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
230
|
+
const { connectAndGetMachine } = await import('./commands-CxfUr2Qr.mjs');
|
|
231
231
|
const pos = positionalArgs(args);
|
|
232
232
|
const name = pos[0];
|
|
233
233
|
if (!name) {
|
|
@@ -237,7 +237,7 @@ async function serveRemove(args, machineId) {
|
|
|
237
237
|
const { machine, server } = await connectAndGetMachine(machineId);
|
|
238
238
|
try {
|
|
239
239
|
await machine.serveRemove({ name });
|
|
240
|
-
const { removeSessionLinkByService } = await import('./agentCommands-
|
|
240
|
+
const { removeSessionLinkByService } = await import('./agentCommands-DUHUBzrj.mjs');
|
|
241
241
|
removeSessionLinkByService("serve", name);
|
|
242
242
|
console.log(`Mount '${name}' removed.`);
|
|
243
243
|
} catch (err) {
|
|
@@ -249,7 +249,7 @@ async function serveRemove(args, machineId) {
|
|
|
249
249
|
}
|
|
250
250
|
}
|
|
251
251
|
async function serveList(args, machineId) {
|
|
252
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
252
|
+
const { connectAndGetMachine } = await import('./commands-CxfUr2Qr.mjs');
|
|
253
253
|
const all = hasFlag(args, "--all", "-a");
|
|
254
254
|
const json = hasFlag(args, "--json");
|
|
255
255
|
const sessionId = getFlag(args, "--session");
|
|
@@ -283,7 +283,7 @@ async function serveList(args, machineId) {
|
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
285
|
async function serveInfo(machineId) {
|
|
286
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
286
|
+
const { connectAndGetMachine } = await import('./commands-CxfUr2Qr.mjs');
|
|
287
287
|
const { machine, server } = await connectAndGetMachine(machineId);
|
|
288
288
|
try {
|
|
289
289
|
const info = await machine.serveInfo();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R as READ_ONLY_TOOLS, M as loadMachineContext, N as buildMachineInstructions, O as machineToolsForRole, P as buildMachineTools } from './run-
|
|
1
|
+
import { R as READ_ONLY_TOOLS, M as loadMachineContext, N as buildMachineInstructions, O as machineToolsForRole, P as buildMachineTools } from './run-BBBr4jkI.mjs';
|
|
2
2
|
import 'node:child_process';
|
|
3
3
|
import 'os';
|
|
4
4
|
import 'fs/promises';
|
|
@@ -7,13 +7,13 @@ import 'path';
|
|
|
7
7
|
import 'url';
|
|
8
8
|
import 'child_process';
|
|
9
9
|
import 'crypto';
|
|
10
|
-
import 'node:crypto';
|
|
11
10
|
import 'node:fs';
|
|
11
|
+
import 'node:path';
|
|
12
|
+
import 'node:crypto';
|
|
12
13
|
import 'util';
|
|
13
14
|
import 'http';
|
|
14
15
|
import 'net';
|
|
15
16
|
import 'node:os';
|
|
16
|
-
import 'node:path';
|
|
17
17
|
import 'node:events';
|
|
18
18
|
import '@agentclientprotocol/sdk';
|
|
19
19
|
import 'node:util';
|