svamp-cli 0.2.306 → 0.2.308
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-Cx_Rp-TR.mjs → adminCommands-CtecEU3a.mjs} +1 -1
- package/dist/{agentCommands-CUcyA_KE.mjs → agentCommands-DEJpgdgc.mjs} +5 -5
- package/dist/{auth-BBjbREk1.mjs → auth-BTodo5Et.mjs} +1 -1
- package/dist/{cli-Jj5S5UOL.mjs → cli-Ko4XpjRo.mjs} +76 -70
- package/dist/cli.mjs +2 -2
- package/dist/{commands-BRQBNTsJ.mjs → commands-B-u0fICz.mjs} +2 -2
- package/dist/{commands-DkKdjnPE.mjs → commands-B2ARVwag.mjs} +2 -2
- package/dist/{commands-CvwLQ3MM.mjs → commands-D3Nu5cYE.mjs} +1 -1
- package/dist/{commands-DlyOpWwF.mjs → commands-DA7rAZqn.mjs} +1 -1
- package/dist/{commands-3UnC4Lnb.mjs → commands-DKOYCcmo.mjs} +1 -1
- package/dist/{commands-BeD9b-Eh.mjs → commands-DfbOYRLs.mjs} +2 -2
- package/dist/{commands-DJt9EFd7.mjs → commands-GNplzSQX.mjs} +2 -2
- package/dist/{commands-ByP8QKuO.mjs → commands-dBiQcDJ1.mjs} +7 -7
- package/dist/{fleet-cBng1VMn.mjs → fleet-CXixARxe.mjs} +38 -2
- package/dist/{frpc-C1jS23Sn.mjs → frpc-DV_IIYpM.mjs} +1 -1
- package/dist/{headlessCli-CsnDECCN.mjs → headlessCli-DfkgeGnQ.mjs} +2 -2
- package/dist/index.mjs +1 -1
- package/dist/{notifyCommands-D7Ja6442.mjs → notifyCommands-BUE_-OCX.mjs} +1 -1
- package/dist/package-GdCOuQCx.mjs +64 -0
- package/dist/{rpc-BxmbyDga.mjs → rpc-BjKmyKdA.mjs} +1 -1
- package/dist/{rpc-iNafaHoh.mjs → rpc-wL-45Raf.mjs} +1 -1
- package/dist/{run-Bd57zohL.mjs → run-VQIHMUdo.mjs} +203 -66
- package/dist/{run-D351s_uv.mjs → run-ofbo9uzA.mjs} +1 -1
- package/dist/{scheduler-CZYOanXt.mjs → scheduler-Dia9Akaw.mjs} +1 -1
- package/dist/{serveCommands-DotLju8m.mjs → serveCommands-DehmO1cO.mjs} +5 -5
- package/dist/{sideband-DM1-IAV7.mjs → sideband-CGiNKfNE.mjs} +1 -1
- package/package.json +2 -2
- package/dist/package-DUF-safU.mjs +0 -64
|
@@ -3047,7 +3047,7 @@ Connection: close\r
|
|
|
3047
3047
|
const mount = this.mounts.get(mountName);
|
|
3048
3048
|
const subdomainOverride = mount?.access === "link" && mount.linkToken ? /* @__PURE__ */ new Map([[this.port, buildLinkSubdomain(subdomainSafe, mount.linkToken)]]) : void 0;
|
|
3049
3049
|
try {
|
|
3050
|
-
const { FrpcTunnel } = await import('./frpc-
|
|
3050
|
+
const { FrpcTunnel } = await import('./frpc-DV_IIYpM.mjs');
|
|
3051
3051
|
let tunnel;
|
|
3052
3052
|
tunnel = new FrpcTunnel({
|
|
3053
3053
|
name: tunnelName,
|
|
@@ -4857,8 +4857,43 @@ const SESSION_METHOD_MIN_ROLE = {
|
|
|
4857
4857
|
refineLastReply: "admin",
|
|
4858
4858
|
undoLastEdit: "admin"
|
|
4859
4859
|
};
|
|
4860
|
+
const SESSION_VIEW_METHODS = /* @__PURE__ */ new Set([
|
|
4861
|
+
// read-only (authorizeRequest at view-role)
|
|
4862
|
+
"getMessages",
|
|
4863
|
+
"getLatestMessages",
|
|
4864
|
+
"getMessageCount",
|
|
4865
|
+
"getMetadata",
|
|
4866
|
+
"getSharing",
|
|
4867
|
+
"getInbox",
|
|
4868
|
+
"getEffectiveRole",
|
|
4869
|
+
"getActivityState",
|
|
4870
|
+
"getAgentState",
|
|
4871
|
+
"getChannelSkill",
|
|
4872
|
+
"getMeetingActivity",
|
|
4873
|
+
"listChannels",
|
|
4874
|
+
"outpostList",
|
|
4875
|
+
"registerListener",
|
|
4876
|
+
// self-authenticating (own capability key / token) or liveness — machine role stays view
|
|
4877
|
+
"channelDescribe",
|
|
4878
|
+
"channelExecTool",
|
|
4879
|
+
"channelGetProfile",
|
|
4880
|
+
"channelList",
|
|
4881
|
+
"channelOwns",
|
|
4882
|
+
"channelReceive",
|
|
4883
|
+
"channelSend",
|
|
4884
|
+
"channelUpload",
|
|
4885
|
+
"outpostHello",
|
|
4886
|
+
"outpostPoll",
|
|
4887
|
+
"outpostResult",
|
|
4888
|
+
"disconnect",
|
|
4889
|
+
"reregister",
|
|
4890
|
+
"recordMeetingActivity"
|
|
4891
|
+
]);
|
|
4860
4892
|
function sessionMethodMinRole(method) {
|
|
4861
|
-
|
|
4893
|
+
const mapped = SESSION_METHOD_MIN_ROLE[method];
|
|
4894
|
+
if (mapped) return mapped;
|
|
4895
|
+
if (SESSION_VIEW_METHODS.has(method)) return "view";
|
|
4896
|
+
return "admin";
|
|
4862
4897
|
}
|
|
4863
4898
|
function getParamNames(fn) {
|
|
4864
4899
|
const src = fn.toString();
|
|
@@ -6088,7 +6123,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
|
|
|
6088
6123
|
const tunnels = handlers.tunnels;
|
|
6089
6124
|
if (!tunnels) throw new Error("Tunnel management not available");
|
|
6090
6125
|
if (tunnels.has(params.name)) throw new Error(`Tunnel '${params.name}' already running`);
|
|
6091
|
-
const { FrpcTunnel } = await import('./frpc-
|
|
6126
|
+
const { FrpcTunnel } = await import('./frpc-DV_IIYpM.mjs');
|
|
6092
6127
|
const tunnel = new FrpcTunnel({
|
|
6093
6128
|
name: params.name,
|
|
6094
6129
|
ports: params.ports,
|
|
@@ -6573,7 +6608,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
6573
6608
|
let owner;
|
|
6574
6609
|
try {
|
|
6575
6610
|
role2 = (await rpc.getEffectiveRole(context))?.role ?? null;
|
|
6576
|
-
if (!role2) return { success: false, error: "Not authorized
|
|
6611
|
+
if (!roleAtLeast(role2, "interact")) return { success: false, error: "Not authorized: WISE ask requires interact access to this session." };
|
|
6577
6612
|
const m = await rpc.getMetadata(context);
|
|
6578
6613
|
cwd = m?.metadata?.path;
|
|
6579
6614
|
owner = m?.metadata?.sharing?.owner;
|
|
@@ -6582,12 +6617,12 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
6582
6617
|
}
|
|
6583
6618
|
const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
|
|
6584
6619
|
const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
|
|
6585
|
-
const { toolsForRole } = await import('./sideband-
|
|
6620
|
+
const { toolsForRole } = await import('./sideband-CGiNKfNE.mjs');
|
|
6586
6621
|
const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
|
|
6587
6622
|
return fmt(r2);
|
|
6588
6623
|
}
|
|
6589
6624
|
const role = getEffectiveRole(context, currentMetadata.sharing);
|
|
6590
|
-
if (!role) return { success: false, error: "Not authorized
|
|
6625
|
+
if (!roleAtLeast(role, "interact")) return { success: false, error: "Not authorized: WISE ask requires interact access to this machine." };
|
|
6591
6626
|
const machineDeps = buildMachineDeps(
|
|
6592
6627
|
{
|
|
6593
6628
|
getSessionIds: handlers.getSessionIds,
|
|
@@ -6687,7 +6722,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
6687
6722
|
return { ok: false, call_id: callId, status: "busy", error: "channel is busy (too many concurrent requests) \u2014 retry shortly" };
|
|
6688
6723
|
}
|
|
6689
6724
|
const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
|
|
6690
|
-
const { queryCore } = await import('./commands-
|
|
6725
|
+
const { queryCore } = await import('./commands-D3Nu5cYE.mjs');
|
|
6691
6726
|
const timeout = c.reply?.timeout_sec || 120;
|
|
6692
6727
|
let result;
|
|
6693
6728
|
try {
|
|
@@ -7457,6 +7492,7 @@ class OutpostCoordinator {
|
|
|
7457
7492
|
clearTimer;
|
|
7458
7493
|
execTimeoutMs;
|
|
7459
7494
|
staleMs;
|
|
7495
|
+
randToken;
|
|
7460
7496
|
sweeper = null;
|
|
7461
7497
|
constructor(opts = {}) {
|
|
7462
7498
|
this.now = opts.now || (() => Date.now());
|
|
@@ -7464,6 +7500,7 @@ class OutpostCoordinator {
|
|
|
7464
7500
|
this.clearTimer = opts.clearTimer || ((t) => clearTimeout(t));
|
|
7465
7501
|
this.execTimeoutMs = opts.execTimeoutMs ?? OUTPOST_EXEC_TIMEOUT_MS;
|
|
7466
7502
|
this.staleMs = opts.staleMs ?? OUTPOST_STALE_MS;
|
|
7503
|
+
this.randToken = opts.randToken || (() => randomBytes(9).toString("base64url"));
|
|
7467
7504
|
}
|
|
7468
7505
|
isStale(c, at) {
|
|
7469
7506
|
return at - c.lastSeen > this.staleMs;
|
|
@@ -7575,7 +7612,7 @@ class OutpostCoordinator {
|
|
|
7575
7612
|
* machine is not connected.
|
|
7576
7613
|
*/
|
|
7577
7614
|
enqueueExec(machine, cmd, cwd) {
|
|
7578
|
-
const id = `x${(++this.seq).toString(36)}_${this.now().toString(36)}`;
|
|
7615
|
+
const id = `x${(++this.seq).toString(36)}_${this.now().toString(36)}_${this.randToken()}`;
|
|
7579
7616
|
if (!this.isConnected(machine)) {
|
|
7580
7617
|
return {
|
|
7581
7618
|
id,
|
|
@@ -10470,8 +10507,23 @@ function computeCollectionConfigUpdate(existingConfig, extra) {
|
|
|
10470
10507
|
function emailHash(email) {
|
|
10471
10508
|
return createHash("sha256").update(email.toLowerCase()).digest("hex").slice(0, 12);
|
|
10472
10509
|
}
|
|
10510
|
+
function sessionIdHash(sessionId) {
|
|
10511
|
+
return createHash("sha256").update(sessionId).digest("hex").slice(0, 12);
|
|
10512
|
+
}
|
|
10513
|
+
function roleLabel(role) {
|
|
10514
|
+
switch (role) {
|
|
10515
|
+
case "admin":
|
|
10516
|
+
return "full access";
|
|
10517
|
+
case "interact":
|
|
10518
|
+
return "can interact";
|
|
10519
|
+
case "view":
|
|
10520
|
+
return "view only";
|
|
10521
|
+
default:
|
|
10522
|
+
return String(role);
|
|
10523
|
+
}
|
|
10524
|
+
}
|
|
10473
10525
|
function shareAlias(sessionId, recipientEmail) {
|
|
10474
|
-
return `share-${sessionId
|
|
10526
|
+
return `share-${sessionIdHash(sessionId)}-${emailHash(recipientEmail)}`;
|
|
10475
10527
|
}
|
|
10476
10528
|
function eventAlias(eventId, recipientEmail) {
|
|
10477
10529
|
return `evt-${emailHash(recipientEmail)}-${eventId.slice(0, 8)}`;
|
|
@@ -10479,18 +10531,56 @@ function eventAlias(eventId, recipientEmail) {
|
|
|
10479
10531
|
class SharingNotificationSync {
|
|
10480
10532
|
server;
|
|
10481
10533
|
artifactManager = null;
|
|
10534
|
+
amResolvedAt = 0;
|
|
10482
10535
|
shareCollectionId = null;
|
|
10483
10536
|
eventCollectionId = null;
|
|
10484
10537
|
initialized = false;
|
|
10485
10538
|
log;
|
|
10539
|
+
// A resolved `public/artifact-manager` proxy is bound to a SPECIFIC backend client_id. When that
|
|
10540
|
+
// backend pod is replaced (deploy/restart/idle-evict), the new instance registers under the same
|
|
10541
|
+
// public alias but a fresh client_id — the cached proxy dangles and every call TIMES OUT (~30s).
|
|
10542
|
+
// Before this fix that silently broke ALL zero-click share writes fleet-wide (empty
|
|
10543
|
+
// svamp-shared-sessions → recipients never auto-discovered). So we re-resolve on a short TTL and,
|
|
10544
|
+
// on any RPC error, force one fresh re-resolve + retry (a dead pod's proxy always fails first).
|
|
10545
|
+
static AM_TTL_MS = 3e4;
|
|
10486
10546
|
constructor(server, log) {
|
|
10487
10547
|
this.server = server;
|
|
10488
10548
|
this.log = log;
|
|
10489
10549
|
}
|
|
10550
|
+
/**
|
|
10551
|
+
* Resolve `public/artifact-manager` on the daemon's live connection. hypha-rpc re-queries the
|
|
10552
|
+
* server registry on each getService() call, so a fresh resolve yields the CURRENTLY-registered
|
|
10553
|
+
* live instance (not the dangling cached one). Cached within a short TTL to avoid a lookup per
|
|
10554
|
+
* write; `force` bypasses the cache after a failure.
|
|
10555
|
+
*/
|
|
10556
|
+
async getAM(force = false) {
|
|
10557
|
+
const now = Date.now();
|
|
10558
|
+
if (!force && this.artifactManager && now - this.amResolvedAt < SharingNotificationSync.AM_TTL_MS) {
|
|
10559
|
+
return this.artifactManager;
|
|
10560
|
+
}
|
|
10561
|
+
const am = await this.server.getService("public/artifact-manager");
|
|
10562
|
+
this.artifactManager = am;
|
|
10563
|
+
this.amResolvedAt = Date.now();
|
|
10564
|
+
return am;
|
|
10565
|
+
}
|
|
10566
|
+
/**
|
|
10567
|
+
* Run an artifact-manager operation with automatic recovery from a stale/dead proxy: try with the
|
|
10568
|
+
* (possibly cached) instance; on ANY error, force a fresh re-resolve and retry ONCE. This is the
|
|
10569
|
+
* heart of the stale-proxy fix — a replaced backend pod makes the first call time out, the retry
|
|
10570
|
+
* re-binds to the live instance and succeeds. The caller still catches the final error.
|
|
10571
|
+
*/
|
|
10572
|
+
async withAM(op) {
|
|
10573
|
+
try {
|
|
10574
|
+
return await op(await this.getAM(false));
|
|
10575
|
+
} catch (err) {
|
|
10576
|
+
this.log(`[SHARING NOTIFY] artifact-manager call failed (${err?.message}); re-resolving + retrying`);
|
|
10577
|
+
return await op(await this.getAM(true));
|
|
10578
|
+
}
|
|
10579
|
+
}
|
|
10490
10580
|
async init() {
|
|
10491
10581
|
try {
|
|
10492
|
-
|
|
10493
|
-
if (!
|
|
10582
|
+
const am = await this.getAM(true);
|
|
10583
|
+
if (!am) {
|
|
10494
10584
|
this.log("[SHARING NOTIFY] Artifact manager not available");
|
|
10495
10585
|
return;
|
|
10496
10586
|
}
|
|
@@ -10519,15 +10609,17 @@ class SharingNotificationSync {
|
|
|
10519
10609
|
shareType: params.shareType || "session"
|
|
10520
10610
|
};
|
|
10521
10611
|
try {
|
|
10522
|
-
|
|
10523
|
-
|
|
10524
|
-
|
|
10525
|
-
|
|
10526
|
-
|
|
10527
|
-
|
|
10528
|
-
|
|
10529
|
-
|
|
10530
|
-
|
|
10612
|
+
await this.withAM(async (am) => {
|
|
10613
|
+
const artifact = await am.create({
|
|
10614
|
+
alias,
|
|
10615
|
+
parent_id: this.shareCollectionId,
|
|
10616
|
+
type: "share-notification",
|
|
10617
|
+
stage: true,
|
|
10618
|
+
manifest,
|
|
10619
|
+
_rkwargs: true
|
|
10620
|
+
});
|
|
10621
|
+
await am.commit({ artifact_id: artifact.id, _rkwargs: true }).catch(() => {
|
|
10622
|
+
});
|
|
10531
10623
|
});
|
|
10532
10624
|
} catch (createErr) {
|
|
10533
10625
|
this.log(`[SHARING NOTIFY] share-notification attach skipped for ${params.recipientEmail}: ${createErr.message}`);
|
|
@@ -10545,8 +10637,10 @@ class SharingNotificationSync {
|
|
|
10545
10637
|
userEmail: params.ownerEmail
|
|
10546
10638
|
},
|
|
10547
10639
|
title: `${typeLabel} shared with you`,
|
|
10548
|
-
//
|
|
10549
|
-
|
|
10640
|
+
// #0689: render the recipient's ACTUAL role (view/interact/admin) — authorize.ts genuinely
|
|
10641
|
+
// enforces per-user roles, so the old hardcoded "(full access)" misstated a view/interact
|
|
10642
|
+
// invitee's access.
|
|
10643
|
+
body: `${params.ownerEmail} shared "${params.label || "Untitled"}" with you (${roleLabel(params.role)})`,
|
|
10550
10644
|
level: "info",
|
|
10551
10645
|
action: shareType === "session" ? {
|
|
10552
10646
|
type: "add-session-bookmark",
|
|
@@ -10569,14 +10663,16 @@ class SharingNotificationSync {
|
|
|
10569
10663
|
if (!this.initialized || !this.shareCollectionId) return;
|
|
10570
10664
|
const alias = shareAlias(sessionId, recipientEmail);
|
|
10571
10665
|
try {
|
|
10572
|
-
|
|
10573
|
-
|
|
10574
|
-
|
|
10575
|
-
|
|
10576
|
-
|
|
10577
|
-
|
|
10578
|
-
|
|
10579
|
-
|
|
10666
|
+
await this.withAM(async (am) => {
|
|
10667
|
+
const existing = await am.read({
|
|
10668
|
+
artifact_id: alias,
|
|
10669
|
+
parent_id: this.shareCollectionId,
|
|
10670
|
+
_rkwargs: true
|
|
10671
|
+
});
|
|
10672
|
+
await am.delete({
|
|
10673
|
+
artifact_id: existing.id,
|
|
10674
|
+
_rkwargs: true
|
|
10675
|
+
});
|
|
10580
10676
|
});
|
|
10581
10677
|
this.log(`[SHARING NOTIFY] Removed share notification for ${recipientEmail} on ${sessionId.slice(0, 8)}`);
|
|
10582
10678
|
} catch {
|
|
@@ -10607,17 +10703,19 @@ class SharingNotificationSync {
|
|
|
10607
10703
|
if (!this.initialized || !this.eventCollectionId) return;
|
|
10608
10704
|
const alias = eventAlias(event.id, event.recipientEmail);
|
|
10609
10705
|
try {
|
|
10610
|
-
|
|
10611
|
-
|
|
10612
|
-
|
|
10613
|
-
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
|
|
10617
|
-
|
|
10618
|
-
|
|
10619
|
-
|
|
10620
|
-
|
|
10706
|
+
await this.withAM(async (am) => {
|
|
10707
|
+
const artifact = await am.create({
|
|
10708
|
+
alias,
|
|
10709
|
+
parent_id: this.eventCollectionId,
|
|
10710
|
+
type: "user-event",
|
|
10711
|
+
stage: true,
|
|
10712
|
+
manifest: event,
|
|
10713
|
+
_rkwargs: true
|
|
10714
|
+
});
|
|
10715
|
+
await am.commit({
|
|
10716
|
+
artifact_id: artifact.id,
|
|
10717
|
+
_rkwargs: true
|
|
10718
|
+
});
|
|
10621
10719
|
});
|
|
10622
10720
|
this.log(`[USER EVENT] Published ${event.type} to ${event.recipientEmail}`);
|
|
10623
10721
|
try {
|
|
@@ -10644,7 +10742,7 @@ class SharingNotificationSync {
|
|
|
10644
10742
|
const all = [];
|
|
10645
10743
|
const seen = /* @__PURE__ */ new Set();
|
|
10646
10744
|
for (let offset = 0; ; offset += PAGE) {
|
|
10647
|
-
const page = await this.
|
|
10745
|
+
const page = await this.withAM((am) => am.list({ parent_id: parentId, offset, limit: PAGE, _rkwargs: true }));
|
|
10648
10746
|
if (!Array.isArray(page) || page.length === 0) break;
|
|
10649
10747
|
let fresh = 0;
|
|
10650
10748
|
for (const c of page) {
|
|
@@ -10685,7 +10783,7 @@ class SharingNotificationSync {
|
|
|
10685
10783
|
live.push(m);
|
|
10686
10784
|
}
|
|
10687
10785
|
for (const id of expiredOwnedIds) {
|
|
10688
|
-
this.
|
|
10786
|
+
this.withAM((am) => am.delete({ artifact_id: id, _rkwargs: true })).catch(() => {
|
|
10689
10787
|
});
|
|
10690
10788
|
}
|
|
10691
10789
|
return live.sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));
|
|
@@ -10711,7 +10809,7 @@ class SharingNotificationSync {
|
|
|
10711
10809
|
return m && typeof m.id === "string" && (m.id === eventId || m.id.slice(0, 8) === short) && typeof m.recipientEmail === "string" && m.recipientEmail.toLowerCase() === normalized;
|
|
10712
10810
|
});
|
|
10713
10811
|
if (!match) return false;
|
|
10714
|
-
await this.
|
|
10812
|
+
await this.withAM((am) => am.delete({ artifact_id: match.id, _rkwargs: true }));
|
|
10715
10813
|
this.log(`[USER EVENT] Acked ${eventId.slice(0, 8)} for ${recipientEmail}`);
|
|
10716
10814
|
return true;
|
|
10717
10815
|
} catch (err) {
|
|
@@ -10722,13 +10820,15 @@ class SharingNotificationSync {
|
|
|
10722
10820
|
// ── Sharing config diff + sync ───────────────────────────────────
|
|
10723
10821
|
async syncSharing(sessionId, oldSharing, newSharing, context) {
|
|
10724
10822
|
if (!this.initialized) return;
|
|
10725
|
-
const
|
|
10726
|
-
(oldSharing?.allowedUsers || []).map((u) => u.email.toLowerCase())
|
|
10823
|
+
const oldRoleByEmail = new Map(
|
|
10824
|
+
(oldSharing?.allowedUsers || []).map((u) => [u.email.toLowerCase(), u.role])
|
|
10727
10825
|
);
|
|
10826
|
+
const oldEmails = new Set(oldRoleByEmail.keys());
|
|
10728
10827
|
const newUsers = newSharing.allowedUsers || [];
|
|
10729
10828
|
const newEmails = new Set(newUsers.map((u) => u.email.toLowerCase()));
|
|
10730
10829
|
for (const user of newUsers) {
|
|
10731
|
-
|
|
10830
|
+
const prevRole = oldRoleByEmail.get(user.email.toLowerCase());
|
|
10831
|
+
if (prevRole === void 0 || prevRole !== user.role) {
|
|
10732
10832
|
this.notifyShare({
|
|
10733
10833
|
recipientEmail: user.email,
|
|
10734
10834
|
sessionId,
|
|
@@ -12165,6 +12265,16 @@ function codexCumulativeTokens(payload) {
|
|
|
12165
12265
|
return nonCachedInput + output + Math.round(cached * 0.1);
|
|
12166
12266
|
}
|
|
12167
12267
|
|
|
12268
|
+
const PINNED_CODEX_VERSION = "0.146.0";
|
|
12269
|
+
const MIN_CODEX_STEER_VERSION = { major: 0, minor: 129, patch: 0 };
|
|
12270
|
+
function cmpVer(a, b) {
|
|
12271
|
+
return a.major - b.major || a.minor - b.minor || a.patch - b.patch;
|
|
12272
|
+
}
|
|
12273
|
+
function codexSupportsSteer(v) {
|
|
12274
|
+
if (!v) return false;
|
|
12275
|
+
return cmpVer(v, MIN_CODEX_STEER_VERSION) >= 0;
|
|
12276
|
+
}
|
|
12277
|
+
|
|
12168
12278
|
function parseCodexVersion(v) {
|
|
12169
12279
|
const m = v.match(/codex-cli\s+(\d+)\.(\d+)\.(\d+)/);
|
|
12170
12280
|
if (!m) return null;
|
|
@@ -12181,6 +12291,16 @@ function codexAppServerAvailable() {
|
|
|
12181
12291
|
return null;
|
|
12182
12292
|
}
|
|
12183
12293
|
}
|
|
12294
|
+
let _steerSupport = null;
|
|
12295
|
+
function codexSupportsSteerInstalled() {
|
|
12296
|
+
if (_steerSupport !== null) return _steerSupport;
|
|
12297
|
+
try {
|
|
12298
|
+
_steerSupport = codexSupportsSteer(parseCodexVersion(execSync$1("codex --version", { encoding: "utf8" }).trim()));
|
|
12299
|
+
} catch {
|
|
12300
|
+
_steerSupport = false;
|
|
12301
|
+
}
|
|
12302
|
+
return _steerSupport;
|
|
12303
|
+
}
|
|
12184
12304
|
class CodexAppServerClient {
|
|
12185
12305
|
constructor(opts) {
|
|
12186
12306
|
this.opts = opts;
|
|
@@ -12337,19 +12457,36 @@ class CodexAppServerClient {
|
|
|
12337
12457
|
/**
|
|
12338
12458
|
* Inject additional input into the CURRENTLY RUNNING turn (Claude-Code-style mid-turn steering).
|
|
12339
12459
|
*
|
|
12340
|
-
* codex app-server
|
|
12341
|
-
*
|
|
12342
|
-
*
|
|
12343
|
-
*
|
|
12344
|
-
*
|
|
12460
|
+
* Uses codex app-server's NATIVE `turn/steer` — the correct primitive for "append this message to
|
|
12461
|
+
* the in-flight turn without interrupting it." The steered input is applied at the next model step
|
|
12462
|
+
* (it does NOT abort a running tool call), the assistant finishes the current work and drains the
|
|
12463
|
+
* steered message as user input before its next LLM call, and NO separate `turn/started` /
|
|
12464
|
+
* `turn/completed` fires — the original single in-flight completion still resolves `sendTurnAndWait`.
|
|
12465
|
+
* So we send it WITHOUT arming a new `pendingTurn` slot and WITHOUT overwriting `_turnId`.
|
|
12466
|
+
*
|
|
12467
|
+
* (The earlier #86 implementation fired a second `turn/start` mid-turn; on codex 0.144 that
|
|
12468
|
+
* ABORTS/REPLACES the running turn instead of folding — the "cuts off the previous task" bug.)
|
|
12345
12469
|
*
|
|
12346
|
-
* Returns false when there is
|
|
12347
|
-
* turn
|
|
12470
|
+
* Returns false when there is no active turn to steer, or when the server REJECTS the steer
|
|
12471
|
+
* (no active turn / expectedTurnId mismatch / non-steerable turn kind such as review or manual
|
|
12472
|
+
* compact). The caller then falls back to client-side queueing (post-turn drain via sendPrompt),
|
|
12473
|
+
* so a rejected steer degrades gracefully rather than losing the message.
|
|
12348
12474
|
*/
|
|
12349
|
-
async injectInput(prompt,
|
|
12350
|
-
if (!this._threadId || !this.pendingTurn) return false;
|
|
12351
|
-
|
|
12352
|
-
|
|
12475
|
+
async injectInput(prompt, _o) {
|
|
12476
|
+
if (!this._threadId || !this.pendingTurn || !this._turnId) return false;
|
|
12477
|
+
if (!codexSupportsSteerInstalled()) return false;
|
|
12478
|
+
const params = {
|
|
12479
|
+
threadId: this._threadId,
|
|
12480
|
+
expectedTurnId: this._turnId,
|
|
12481
|
+
input: [{ type: "text", text: prompt }]
|
|
12482
|
+
};
|
|
12483
|
+
try {
|
|
12484
|
+
await this.request("turn/steer", params);
|
|
12485
|
+
return true;
|
|
12486
|
+
} catch (e) {
|
|
12487
|
+
this.log("[codex-app-server] turn/steer rejected \u2014 falling back to post-turn queue", e);
|
|
12488
|
+
return false;
|
|
12489
|
+
}
|
|
12353
12490
|
}
|
|
12354
12491
|
/** Interrupt the in-flight turn (real server-side abort — the old MCP path couldn't do this). */
|
|
12355
12492
|
async interrupt() {
|
|
@@ -17475,7 +17612,7 @@ async function startDaemon(options) {
|
|
|
17475
17612
|
try {
|
|
17476
17613
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
17477
17614
|
if (!dir) return;
|
|
17478
|
-
const { reconcileServiceLinks } = await import('./agentCommands-
|
|
17615
|
+
const { reconcileServiceLinks } = await import('./agentCommands-DEJpgdgc.mjs');
|
|
17479
17616
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
17480
17617
|
const config = readSvampConfig(configPath);
|
|
17481
17618
|
const entries = Array.from(urls.entries());
|
|
@@ -17493,7 +17630,7 @@ async function startDaemon(options) {
|
|
|
17493
17630
|
}
|
|
17494
17631
|
}
|
|
17495
17632
|
async function createExposedTunnel(spec) {
|
|
17496
|
-
const { FrpcTunnel } = await import('./frpc-
|
|
17633
|
+
const { FrpcTunnel } = await import('./frpc-DV_IIYpM.mjs');
|
|
17497
17634
|
const tunnel = new FrpcTunnel({
|
|
17498
17635
|
name: spec.name,
|
|
17499
17636
|
ports: spec.ports,
|
|
@@ -19711,11 +19848,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
19711
19848
|
});
|
|
19712
19849
|
},
|
|
19713
19850
|
onIssue: async (params) => {
|
|
19714
|
-
const { issueRpc } = await import('./rpc-
|
|
19851
|
+
const { issueRpc } = await import('./rpc-wL-45Raf.mjs');
|
|
19715
19852
|
return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
|
|
19716
19853
|
},
|
|
19717
19854
|
onWorkflow: async (params) => {
|
|
19718
|
-
const { workflowRpc } = await import('./rpc-
|
|
19855
|
+
const { workflowRpc } = await import('./rpc-BjKmyKdA.mjs');
|
|
19719
19856
|
return workflowRpc(params?.cwd || directory, params || {});
|
|
19720
19857
|
},
|
|
19721
19858
|
onRipgrep: async (args, cwd) => {
|
|
@@ -20347,11 +20484,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
20347
20484
|
});
|
|
20348
20485
|
},
|
|
20349
20486
|
onIssue: async (params) => {
|
|
20350
|
-
const { issueRpc } = await import('./rpc-
|
|
20487
|
+
const { issueRpc } = await import('./rpc-wL-45Raf.mjs');
|
|
20351
20488
|
return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
|
|
20352
20489
|
},
|
|
20353
20490
|
onWorkflow: async (params) => {
|
|
20354
|
-
const { workflowRpc } = await import('./rpc-
|
|
20491
|
+
const { workflowRpc } = await import('./rpc-BjKmyKdA.mjs');
|
|
20355
20492
|
return workflowRpc(params?.cwd || directory, params || {});
|
|
20356
20493
|
},
|
|
20357
20494
|
onRipgrep: async (args, cwd) => {
|
|
@@ -21502,7 +21639,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
21502
21639
|
const PING_TIMEOUT_MS = 15e3;
|
|
21503
21640
|
const POST_RECONNECT_GRACE_MS = 2e4;
|
|
21504
21641
|
const RECONNECT_JITTER_MS = 2500;
|
|
21505
|
-
const { WorkflowScheduler } = await import('./scheduler-
|
|
21642
|
+
const { WorkflowScheduler } = await import('./scheduler-Dia9Akaw.mjs');
|
|
21506
21643
|
const workflowProjectRoots = () => {
|
|
21507
21644
|
const dirs = /* @__PURE__ */ new Set();
|
|
21508
21645
|
for (const s of pidToTrackedSession.values()) {
|
|
@@ -22135,4 +22272,4 @@ var run = /*#__PURE__*/Object.freeze({
|
|
|
22135
22272
|
writeStopMarker: writeStopMarker
|
|
22136
22273
|
});
|
|
22137
22274
|
|
|
22138
|
-
export {
|
|
22275
|
+
export { getSkillInfo as $, removeWorkflow as A, validateWorkflowName as B, saveWorkflow as C, rawWorkflow as D, listWorkflows as E, isWorkflowEnabled as F, workflowCrons as G, cronMatches as H, summarize as I, workflowSteps as J, parseJwtEmail as K, computeCollectionConfigUpdate as L, SYSTEM_COLLECTION_CONFIG as M, loadMachineContext as N, buildMachineInstructions as O, machineToolsForRole as P, buildMachineTools as Q, READ_ONLY_TOOLS as R, SharingNotificationSync as S, PINNED_CODEX_VERSION as T, parseFrontmatter as U, getSkillsServer as V, getSkillsWorkspaceName as W, getSkillsCollectionName as X, fetchWithTimeout as Y, searchSkills as Z, SKILLS_DIR as _, createSessionStore as a, downloadSkillFile as a0, listSkillFiles as a1, resolveModel as a2, clearStopMarker as a3, stopMarkerExists as a4, formatHandle as a5, normalizeAllowedUser as a6, loadSecurityContextConfig as a7, resolveSecurityContext as a8, buildSecurityContextFromFlags as a9, mergeSecurityContexts as aa, buildSessionShareUrl as ab, computeOutboundHop as ac, registerAwaitingReply as ad, buildMachineShareUrl as ae, parseHandle as af, handleMatchesMetadata as ag, describeMisconfiguration as ah, buildMachineDeps as ai, applyClaudeProxyEnv as aj, composeSessionId as ak, generateFriendlyName as al, generateHookSettings as am, staticFileServer as an, instanceConfig as ao, claudeAuth as ap, codexProvider as aq, projectInfo as ar, DefaultTransport$1 as as, acpBackend as at, acpAgentConfig as au, codexAppServerBackend as av, GeminiTransport$1 as aw, api as ax, run as ay, stopDaemon as b, connectToHypha as c, daemonStatus as d, getFrpsSubdomainHost as e, getFrpsServerPort as f, getHyphaServerUrl$1 as g, getFrpsServerAddr as h, shortId as i, resolveProjectRoot as j, getIssue as k, resumeIssue as l, addComment as m, addIssue as n, listIssues as o, pauseIssue as p, searchIssues as q, registerMachineService as r, startDaemon as s, isVisibleTo as t, updateIssue as u, getRun as v, listRuns as w, getWorkflow as x, runWorkflow as y, setWorkflowEnabled as z };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import {
|
|
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-VQIHMUdo.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 { j as resolveProjectRoot, E as listWorkflows, F as isWorkflowEnabled, G as workflowCrons, y as runWorkflow, H as cronMatches } from './run-
|
|
1
|
+
import { j as resolveProjectRoot, E as listWorkflows, F as isWorkflowEnabled, G as workflowCrons, y as runWorkflow, H as cronMatches } from './run-VQIHMUdo.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|
|
@@ -54,7 +54,7 @@ async function handleServeCommand() {
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
async function serveAdd(args, machineId) {
|
|
57
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
57
|
+
const { connectAndGetMachine } = await import('./commands-D3Nu5cYE.mjs');
|
|
58
58
|
const pos = positionalArgs(args);
|
|
59
59
|
const name = pos[0];
|
|
60
60
|
if (!name) {
|
|
@@ -93,7 +93,7 @@ async function serveAdd(args, machineId) {
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
async function serveApply(args, machineId) {
|
|
96
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
96
|
+
const { connectAndGetMachine } = await import('./commands-D3Nu5cYE.mjs');
|
|
97
97
|
const fs = await import('fs');
|
|
98
98
|
const yaml = await import('yaml');
|
|
99
99
|
const file = positionalArgs(args)[0];
|
|
@@ -182,7 +182,7 @@ async function serveApply(args, machineId) {
|
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
184
|
async function serveRemove(args, machineId) {
|
|
185
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
185
|
+
const { connectAndGetMachine } = await import('./commands-D3Nu5cYE.mjs');
|
|
186
186
|
const pos = positionalArgs(args);
|
|
187
187
|
const name = pos[0];
|
|
188
188
|
if (!name) {
|
|
@@ -202,7 +202,7 @@ async function serveRemove(args, machineId) {
|
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
async function serveList(args, machineId) {
|
|
205
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
205
|
+
const { connectAndGetMachine } = await import('./commands-D3Nu5cYE.mjs');
|
|
206
206
|
const all = hasFlag(args, "--all", "-a");
|
|
207
207
|
const json = hasFlag(args, "--json");
|
|
208
208
|
const sessionId = getFlag(args, "--session");
|
|
@@ -235,7 +235,7 @@ async function serveList(args, machineId) {
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
async function serveInfo(machineId) {
|
|
238
|
-
const { connectAndGetMachine } = await import('./commands-
|
|
238
|
+
const { connectAndGetMachine } = await import('./commands-D3Nu5cYE.mjs');
|
|
239
239
|
const { machine, server } = await connectAndGetMachine(machineId);
|
|
240
240
|
try {
|
|
241
241
|
const info = await machine.serveInfo();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R as READ_ONLY_TOOLS, N as loadMachineContext, O as buildMachineInstructions, P as machineToolsForRole, Q as buildMachineTools } from './run-
|
|
1
|
+
import { R as READ_ONLY_TOOLS, N as loadMachineContext, O as buildMachineInstructions, P as machineToolsForRole, Q as buildMachineTools } from './run-VQIHMUdo.mjs';
|
|
2
2
|
import 'node:child_process';
|
|
3
3
|
import 'os';
|
|
4
4
|
import 'fs/promises';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svamp-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.308",
|
|
4
4
|
"description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
|
|
5
5
|
"author": "Amun AI AB",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"scripts": {
|
|
21
21
|
"build": "rm -rf dist bin/skills bin/commands && mkdir -p bin/skills && cp -r ../../skills/artifact bin/skills/artifact && cp -r ../../skills/crew bin/skills/crew && cp -r ../../commands bin/commands && tsc --noEmit && pkgroll",
|
|
22
22
|
"typecheck": "tsc --noEmit",
|
|
23
|
-
"test": "npx tsx test/test-context-window.mjs && npx tsx test/test-ratelimit-retry.mjs && npx tsx test/test-instance-config.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-sharing-notify-sync.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-backend-accounts.mjs && npx tsx test/test-codex-force-model.mjs && npx tsx test/test-backend-oauth.mjs && npx tsx test/test-btw-proxy-env.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-inbox-guard.mjs && npx tsx test/test-user-events.mjs && npx tsx test/test-migrate-children.mjs && npx tsx test/test-outpost-install.mjs && npx tsx test/test-outpost-setup.mjs && npx tsx test/test-outpost-pairing.mjs && npx tsx test/test-outpost-coordinator.mjs && npx tsx test/e2e-outpost-transport.mjs && npx tsx test/test-inbox-reconcile.mjs && npx tsx test/test-auto-topic.mjs && npx tsx test/test-project-info.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-isolation-disable.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-session-access-fallback.mjs && npx tsx test/test-session-rpc-role-map.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-codex-app-server.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-listener-backoff.mjs && npx tsx test/test-session-identity-env.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-session-send-query.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && node test/test-supervisor-restart.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-compact-detect.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox-store.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-inbox-cross-machine.mjs && npx tsx test/test-issue-store.mjs && npx tsx test/test-issue-store-lock.mjs && npx tsx test/test-issue-close-gate.mjs && npx tsx test/test-loop-verify.mjs && npx tsx test/test-restore-decision.mjs && npx tsx test/test-issue-rpc.mjs && npx tsx test/test-issue-pause.mjs && npx tsx test/test-workflow-store.mjs && npx tsx test/test-workflow-rpc.mjs && npx tsx test/test-workflow-scheduler.mjs && npx tsx test/test-cron.mjs && npx tsx test/test-workflow-runs.mjs && npx tsx test/test-workflow-runs-lock.mjs && npx tsx test/test-workflow-idle.mjs && npx tsx test/test-workflow-reconcile.mjs && npx tsx test/test-serve-link-subdomain.mjs && npx tsx test/test-short-id.mjs && npx tsx test/test-transcript-edit.mjs && npx tsx test/test-edit-history.mjs && npx tsx test/test-friendly-name.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-ws-upgrade.mjs && npx tsx test/test-serve-auth.mjs && npx tsx test/test-static-file-server.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only && npx tsx test/test-frpc-status.mjs && node test/pinnedClaudeCode.test.mjs && node test/fleet.test.mjs && npx tsx test/test-session-file.mjs && npx tsx test/test-channel-rpc.mjs && npx tsx test/test-wise-agent.mjs && npx tsx test/test-channel-agent.mjs && npx tsx test/test-channels-service.mjs && npx tsx test/test-hotreload-seam.mjs && npx tsx test/test-hot-reload.mjs && npx tsx test/test-hot-reload-live.mjs && npx tsx test/test-session-core.mjs && npx tsx test/test-channel-async-reply.mjs && npx tsx test/test-outbox-reload.mjs && npx tsx test/test-channel-binding.mjs && npx tsx test/test-channel-store-lock.mjs && npx tsx test/test-channel-identity.mjs && npx tsx test/test-stateless-dispatch-limiter.mjs && npx tsx test/test-shared-session-identity.mjs && npx tsx test/test-wise-agent-auth.mjs && npx tsx test/test-channel-http.mjs && npx tsx test/test-channel-upload.mjs && npx tsx test/test-wise-voice.mjs && npx tsx test/test-wise-headless.mjs && npx tsx test/test-wise-machine.mjs && npx tsx test/test-crew-merge.mjs && npx tsx test/test-crew-verdict-routing.mjs && npx tsx test/test-crew-standalone.mjs && npx tsx test/test-session-links.mjs && npx tsx test/test-issue-loop-pause-guard.mjs && npx tsx test/test-artifact-guard.mjs && npx tsx test/test-artifact-sync-pagination.mjs && npx tsx test/test-graceful-restart.mjs && npx tsx test/test-flush-exit.mjs && npx tsx test/test-codex-skills.mjs",
|
|
23
|
+
"test": "npx tsx test/test-context-window.mjs && npx tsx test/test-ratelimit-retry.mjs && npx tsx test/test-instance-config.mjs && npx tsx test/test-authorize.mjs && npx tsx test/test-normalize-allowed-user.mjs && npx tsx test/test-share-url.mjs && npx tsx test/test-update-sharing-normalization.mjs && npx tsx test/test-sharing-notify-sync.mjs && npx tsx test/test-sharing-notify-resolve.mjs && npx tsx test/test-staged-homes-sweep.mjs && npx tsx test/test-session-helpers.mjs && npx tsx test/test-cli-routing.mjs && npx tsx test/test-security-context.mjs && npx tsx test/test-isolation-decision.mjs && npx tsx test/test-message-helpers.mjs && npx tsx test/test-agent-config.mjs && npx tsx test/test-wrap-command.mjs && npx tsx test/test-credential-staging.mjs && npx tsx test/test-claude-auth.mjs && npx tsx test/test-backend-accounts.mjs && npx tsx test/test-codex-force-model.mjs && npx tsx test/test-backend-oauth.mjs && npx tsx test/test-btw-proxy-env.mjs && npx tsx test/test-output-formatters.mjs && npx tsx test/test-inbox-guard.mjs && npx tsx test/test-user-events.mjs && npx tsx test/test-migrate-children.mjs && npx tsx test/test-outpost-install.mjs && npx tsx test/test-outpost-setup.mjs && npx tsx test/test-outpost-pairing.mjs && npx tsx test/test-outpost-coordinator.mjs && npx tsx test/e2e-outpost-transport.mjs && npx tsx test/test-inbox-reconcile.mjs && npx tsx test/test-auto-topic.mjs && npx tsx test/test-project-info.mjs && npx tsx test/test-agent-types.mjs && npx tsx test/test-transport.mjs && npx tsx test/test-session-update-handlers.mjs && npx tsx test/test-session-scanner.mjs && npx tsx test/test-hypha-client.mjs && npx tsx test/test-hook-settings.mjs && npx tsx test/test-session-service-logic.mjs && npx tsx test/test-daemon-persistence.mjs && npx tsx test/test-detect-isolation.mjs && npx tsx test/test-isolation-disable.mjs && npx tsx test/test-machine-service-logic.mjs && npx tsx test/test-session-access-fallback.mjs && npx tsx test/test-session-rpc-role-map.mjs && npx tsx test/test-interactive-helpers.mjs && npx tsx test/test-pinned-codex.mjs && npx tsx test/test-codex-app-server.mjs && npx tsx test/e2e-codex-midturn-steer.mjs && npx tsx test/test-acp-backend.mjs && npx tsx test/test-acp-bridge.mjs && npx tsx test/test-listener-backoff.mjs && npx tsx test/test-session-identity-env.mjs && npx tsx test/test-hook-server.mjs && npx tsx test/test-session-commands.mjs && npx tsx test/test-interactive-console.mjs && npx tsx test/test-session-messages.mjs && npx tsx test/test-session-send-query.mjs && npx tsx test/test-skills.mjs && npx tsx test/test-agent-grouping.mjs && npx tsx test/test-machine-list-directory.mjs && npx tsx test/test-service-commands.mjs && npx tsx test/test-supervisor.mjs && npx tsx test/test-supervisor-lock.mjs && node test/test-supervisor-restart.mjs && npx tsx test/test-clear-detection.mjs && npx tsx test/test-compact-detect.mjs && npx tsx test/test-session-consolidation.mjs && npx tsx test/test-inbox-store.mjs && npx tsx test/test-inbox.mjs && npx tsx test/test-inbox-cross-machine.mjs && npx tsx test/test-issue-store.mjs && npx tsx test/test-issue-store-lock.mjs && npx tsx test/test-issue-close-gate.mjs && npx tsx test/test-loop-verify.mjs && npx tsx test/test-restore-decision.mjs && npx tsx test/test-issue-rpc.mjs && npx tsx test/test-issue-pause.mjs && npx tsx test/test-workflow-store.mjs && npx tsx test/test-workflow-rpc.mjs && npx tsx test/test-workflow-scheduler.mjs && npx tsx test/test-cron.mjs && npx tsx test/test-workflow-runs.mjs && npx tsx test/test-workflow-runs-lock.mjs && npx tsx test/test-workflow-idle.mjs && npx tsx test/test-workflow-reconcile.mjs && npx tsx test/test-serve-link-subdomain.mjs && npx tsx test/test-short-id.mjs && npx tsx test/test-transcript-edit.mjs && npx tsx test/test-edit-history.mjs && npx tsx test/test-friendly-name.mjs && npx tsx test/test-session-rpc-dispatch.mjs && npx tsx test/test-sandbox-cli.mjs && npx tsx test/test-serve-manager.mjs && npx tsx test/test-serve-ws-upgrade.mjs && npx tsx test/test-serve-auth.mjs && npx tsx test/test-static-file-server.mjs && npx tsx test/test-serve-stability.mjs && npx tsx test/test-frpc-e2e.mjs --unit-only && npx tsx test/test-frpc-status.mjs && node test/pinnedClaudeCode.test.mjs && node test/fleet.test.mjs && npx tsx test/test-session-file.mjs && npx tsx test/test-channel-rpc.mjs && npx tsx test/test-wise-agent.mjs && npx tsx test/test-channel-agent.mjs && npx tsx test/test-channels-service.mjs && npx tsx test/test-hotreload-seam.mjs && npx tsx test/test-hot-reload.mjs && npx tsx test/test-hot-reload-live.mjs && npx tsx test/test-session-core.mjs && npx tsx test/test-channel-async-reply.mjs && npx tsx test/test-outbox-reload.mjs && npx tsx test/test-channel-binding.mjs && npx tsx test/test-channel-store-lock.mjs && npx tsx test/test-channel-identity.mjs && npx tsx test/test-stateless-dispatch-limiter.mjs && npx tsx test/test-shared-session-identity.mjs && npx tsx test/test-wise-agent-auth.mjs && npx tsx test/test-channel-http.mjs && npx tsx test/test-channel-upload.mjs && npx tsx test/test-wise-voice.mjs && npx tsx test/test-wise-headless.mjs && npx tsx test/test-wise-machine.mjs && npx tsx test/test-crew-merge.mjs && npx tsx test/test-crew-verdict-routing.mjs && npx tsx test/test-crew-standalone.mjs && npx tsx test/test-session-links.mjs && npx tsx test/test-issue-loop-pause-guard.mjs && npx tsx test/test-artifact-guard.mjs && npx tsx test/test-artifact-sync-pagination.mjs && npx tsx test/test-graceful-restart.mjs && npx tsx test/test-flush-exit.mjs && npx tsx test/test-codex-skills.mjs",
|
|
24
24
|
"test:hypha": "node --no-warnings test/test-hypha-service.mjs",
|
|
25
25
|
"dev": "tsx src/cli.ts",
|
|
26
26
|
"dev:daemon": "tsx src/cli.ts daemon start-sync",
|