svamp-cli 0.2.336 → 0.2.338
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-DaITgElz.mjs → adminCommands-BKGtamkH.mjs} +1 -1
- package/dist/{agentCommands-BcdnoUr6.mjs → agentCommands-f5J1vh6G.mjs} +14 -9
- package/dist/{auth-9yoac3_n.mjs → auth-lJyH6SZI.mjs} +1 -1
- package/dist/{cli-lUpt1gfZ.mjs → cli-BqCtL5Nf.mjs} +77 -77
- package/dist/cli.mjs +2 -2
- package/dist/{commands-y3NpuM8E.mjs → commands-C61n8oPq.mjs} +2 -2
- package/dist/{commands-BAoTIJjJ.mjs → commands-CBwYOKmf.mjs} +1 -1
- package/dist/{commands-CJ4_f3ok.mjs → commands-CRrmwZQh.mjs} +3 -3
- package/dist/{commands-CwiQbkMh.mjs → commands-CZkeeXsr.mjs} +1 -1
- package/dist/{commands-DsC3w_GZ.mjs → commands-CnjJSLfu.mjs} +3 -3
- package/dist/{commands-CLDMHR24.mjs → commands-DkqOgCiK.mjs} +3 -3
- package/dist/{commands-i4024Ot3.mjs → commands-RiTiB0yP.mjs} +2 -2
- package/dist/{commands-CEs0WPWz.mjs → commands-dB6sFeRR.mjs} +11 -11
- package/dist/{fleet-BW-km2ZJ.mjs → fleet-BehFx6MX.mjs} +1 -1
- package/dist/{headlessCli-BaBHCl_x.mjs → headlessCli-BvYt6HPK.mjs} +2 -2
- package/dist/index.mjs +1 -1
- package/dist/{notifyCommands-C428H5qy.mjs → notifyCommands-Blna-Sqz.mjs} +1 -1
- package/dist/{package-B-GyIfBE.mjs → package-Bp7_bE4c.mjs} +3 -3
- package/dist/{rpc-DUP-qb40.mjs → rpc-BQ75iSkj.mjs} +1 -1
- package/dist/{rpc-COwRfHss.mjs → rpc-CG6XWFXY.mjs} +1 -1
- package/dist/{run-CBNIHWhE.mjs → run--wM4gBLw.mjs} +271 -56
- package/dist/{run-DiwHqXsO.mjs → run-9rEzf5ez.mjs} +1 -1
- package/dist/{scheduler-Cx3yWga4.mjs → scheduler-QsXyNajm.mjs} +1 -1
- package/dist/{serveCommands-nhyPDFIK.mjs → serveCommands-C7jU4-zI.mjs} +10 -10
- package/dist/{sideband-QYJM3m1p.mjs → sideband-BBOHmvTf.mjs} +1 -1
- package/package.json +3 -3
|
@@ -5521,27 +5521,63 @@ function sleepSync$1(ms) {
|
|
|
5521
5521
|
} catch {
|
|
5522
5522
|
}
|
|
5523
5523
|
}
|
|
5524
|
+
function isProcessDead(pid) {
|
|
5525
|
+
try {
|
|
5526
|
+
process.kill(pid, 0);
|
|
5527
|
+
return false;
|
|
5528
|
+
} catch (e) {
|
|
5529
|
+
return e?.code === "ESRCH";
|
|
5530
|
+
}
|
|
5531
|
+
}
|
|
5524
5532
|
function withFileLock(lockPath, fn, opts) {
|
|
5525
5533
|
const deadlineMs = opts?.deadlineMs ?? 50;
|
|
5526
5534
|
const staleMs = opts?.staleMs ?? 5e3;
|
|
5535
|
+
const trackOwner = opts?.breakOnDeadOwner ?? false;
|
|
5536
|
+
const pidPath = join$1(lockPath, "owner.pid");
|
|
5527
5537
|
const deadline = Date.now() + deadlineMs;
|
|
5528
5538
|
let held = false;
|
|
5529
5539
|
while (Date.now() < deadline) {
|
|
5530
5540
|
try {
|
|
5531
5541
|
mkdirSync$1(lockPath);
|
|
5532
5542
|
held = true;
|
|
5543
|
+
if (trackOwner) {
|
|
5544
|
+
try {
|
|
5545
|
+
writeFileSync$1(pidPath, String(process.pid));
|
|
5546
|
+
} catch {
|
|
5547
|
+
}
|
|
5548
|
+
}
|
|
5533
5549
|
break;
|
|
5534
5550
|
} catch {
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5551
|
+
let broke = false;
|
|
5552
|
+
if (trackOwner) {
|
|
5553
|
+
try {
|
|
5554
|
+
const owner = Number(readFileSync(pidPath, "utf8"));
|
|
5555
|
+
if (Number.isInteger(owner) && owner > 0 && owner !== process.pid && isProcessDead(owner)) {
|
|
5556
|
+
rmSync$1(lockPath, { recursive: true, force: true });
|
|
5557
|
+
broke = true;
|
|
5558
|
+
}
|
|
5559
|
+
} catch {
|
|
5539
5560
|
}
|
|
5540
|
-
} catch {
|
|
5541
5561
|
}
|
|
5562
|
+
if (!broke) {
|
|
5563
|
+
try {
|
|
5564
|
+
if (Date.now() - statSync(lockPath).mtimeMs > staleMs) {
|
|
5565
|
+
rmSync$1(lockPath, { recursive: true, force: true });
|
|
5566
|
+
broke = true;
|
|
5567
|
+
}
|
|
5568
|
+
} catch {
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5571
|
+
if (broke) continue;
|
|
5542
5572
|
sleepSync$1(5);
|
|
5543
5573
|
}
|
|
5544
5574
|
}
|
|
5575
|
+
if (!held) {
|
|
5576
|
+
try {
|
|
5577
|
+
opts?.onFailOpen?.(lockPath);
|
|
5578
|
+
} catch {
|
|
5579
|
+
}
|
|
5580
|
+
}
|
|
5545
5581
|
try {
|
|
5546
5582
|
return fn();
|
|
5547
5583
|
} finally {
|
|
@@ -5554,6 +5590,33 @@ function withFileLock(lockPath, fn, opts) {
|
|
|
5554
5590
|
}
|
|
5555
5591
|
}
|
|
5556
5592
|
|
|
5593
|
+
function revGuardedMutate(lockPath, io, mutate, opts) {
|
|
5594
|
+
const deadlineMs = opts?.deadlineMs ?? 2e3;
|
|
5595
|
+
const maxAttempts = opts?.maxAttempts ?? 50;
|
|
5596
|
+
let last;
|
|
5597
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
5598
|
+
const settled = withFileLock(lockPath, () => {
|
|
5599
|
+
const base = io.read();
|
|
5600
|
+
const m = mutate(base.state);
|
|
5601
|
+
last = m.result;
|
|
5602
|
+
if (m.next === null) return { committed: true, result: m.result };
|
|
5603
|
+
if (opts?._seam) opts._seam(attempt);
|
|
5604
|
+
const again = io.read();
|
|
5605
|
+
if (again.rev !== base.rev) return { committed: false, result: m.result };
|
|
5606
|
+
io.write(m.next, base.rev + 1);
|
|
5607
|
+
return { committed: true, result: m.result };
|
|
5608
|
+
}, {
|
|
5609
|
+
deadlineMs,
|
|
5610
|
+
breakOnDeadOwner: true,
|
|
5611
|
+
onFailOpen: opts?.onFailOpen
|
|
5612
|
+
});
|
|
5613
|
+
last = settled.result;
|
|
5614
|
+
if (settled.committed) return settled.result;
|
|
5615
|
+
sleepSync$1(3 + attempt % 5);
|
|
5616
|
+
}
|
|
5617
|
+
return last;
|
|
5618
|
+
}
|
|
5619
|
+
|
|
5557
5620
|
const HARD_MAX_BYTES = 25 * 1024 * 1024;
|
|
5558
5621
|
const DEFAULT_MAX_BYTES = 5 * 1024 * 1024;
|
|
5559
5622
|
const DEFAULT_MAX_COUNT = 100;
|
|
@@ -5805,6 +5868,23 @@ const _CHANNEL_CACHE_TTL_MS = 1e3;
|
|
|
5805
5868
|
function invalidateChannelCache(dir) {
|
|
5806
5869
|
_channelListCache.delete(dir);
|
|
5807
5870
|
}
|
|
5871
|
+
function makeRmwSeam() {
|
|
5872
|
+
const delayMs = Number(process.env.SVAMP_TEST_RMW_DELAY_MS || 0);
|
|
5873
|
+
if (!delayMs || !Number.isFinite(delayMs)) return void 0;
|
|
5874
|
+
const readyFile = process.env.SVAMP_TEST_RMW_READY_FILE;
|
|
5875
|
+
let fired = false;
|
|
5876
|
+
return (attempt) => {
|
|
5877
|
+
if (attempt !== 0 || fired) return;
|
|
5878
|
+
fired = true;
|
|
5879
|
+
if (readyFile) {
|
|
5880
|
+
try {
|
|
5881
|
+
writeFileSync$1(readyFile, "1");
|
|
5882
|
+
} catch {
|
|
5883
|
+
}
|
|
5884
|
+
}
|
|
5885
|
+
sleepSync$1(delayMs);
|
|
5886
|
+
};
|
|
5887
|
+
}
|
|
5808
5888
|
class ChannelStore {
|
|
5809
5889
|
dir;
|
|
5810
5890
|
constructor(projectDir) {
|
|
@@ -5818,12 +5898,18 @@ class ChannelStore {
|
|
|
5818
5898
|
}
|
|
5819
5899
|
_lock(id) {
|
|
5820
5900
|
if (!isValidChannelId(id)) throw new Error(`invalid channel id: ${String(id).slice(0, 64)}`);
|
|
5901
|
+
mkdirSync$1(this.dir, { recursive: true });
|
|
5821
5902
|
return join$1(this.dir, `${id}.json.lock`);
|
|
5822
5903
|
}
|
|
5904
|
+
/** The default-filled canonical form of a channel (the minimal fields the store guarantees).
|
|
5905
|
+
* Extracted so `save()` can return the SAME shape it persists without re-running the write. */
|
|
5906
|
+
_applyDefaults(channel) {
|
|
5907
|
+
return { enabled: true, bind: "dynamic", template: DEFAULT_TEMPLATE, last_calls: [], ...channel };
|
|
5908
|
+
}
|
|
5823
5909
|
// #0679: the actual validate + atomic write, WITHOUT the lock, so a locked RMW mutator can
|
|
5824
5910
|
// reuse it inside its own lock section (no re-entrant re-lock / deadlock).
|
|
5825
5911
|
_writeChannel(channel) {
|
|
5826
|
-
const c =
|
|
5912
|
+
const c = this._applyDefaults(channel);
|
|
5827
5913
|
if (!c.id) c.id = genId();
|
|
5828
5914
|
const errs = validateChannel(c);
|
|
5829
5915
|
if (errs.length) throw new Error("invalid channel: " + errs.join("; "));
|
|
@@ -5875,8 +5961,11 @@ class ChannelStore {
|
|
|
5875
5961
|
}
|
|
5876
5962
|
}
|
|
5877
5963
|
save(channel) {
|
|
5878
|
-
if (channel.id) return
|
|
5879
|
-
return this.
|
|
5964
|
+
if (!channel.id) return this._writeChannel(channel);
|
|
5965
|
+
return this._rmw(channel.id, "save", () => {
|
|
5966
|
+
const merged = this._applyDefaults(channel);
|
|
5967
|
+
return { next: merged, result: merged };
|
|
5968
|
+
});
|
|
5880
5969
|
}
|
|
5881
5970
|
remove(id) {
|
|
5882
5971
|
return withFileLock(this._lock(id), () => {
|
|
@@ -5887,41 +5976,85 @@ class ChannelStore {
|
|
|
5887
5976
|
return true;
|
|
5888
5977
|
}
|
|
5889
5978
|
return false;
|
|
5979
|
+
}, {
|
|
5980
|
+
deadlineMs: 2e3,
|
|
5981
|
+
breakOnDeadOwner: true,
|
|
5982
|
+
onFailOpen: () => console.warn(`[channels] remove(${id}): lock contended for 2000ms \u2014 proceeding WITHOUT it`)
|
|
5890
5983
|
});
|
|
5891
5984
|
}
|
|
5892
|
-
// #0679: setEnabled/recordCall/addCaller are read-modify-write mutators — multiple
|
|
5893
|
-
// instances (one per session) point at the same
|
|
5894
|
-
// serialization two concurrent RMWs both read the same base
|
|
5895
|
-
// first (addCaller silently DROPS a freshly-generated caller
|
|
5896
|
-
//
|
|
5897
|
-
|
|
5985
|
+
// #0679: setEnabled/recordCall/addCaller/removeCaller are read-modify-write mutators — multiple
|
|
5986
|
+
// ChannelStore instances (one per session, plus the CLI) point at the same
|
|
5987
|
+
// .svamp/channels/<id>.json, so without serialization two concurrent RMWs both read the same base
|
|
5988
|
+
// and the second write clobbers the first (addCaller silently DROPS a freshly-generated caller
|
|
5989
|
+
// key; removeCaller silently RESURRECTS a revoked one — a SECURITY outcome).
|
|
5990
|
+
/**
|
|
5991
|
+
* #1226: the STRUCTURAL fix for those lost updates — a rev-guarded read-modify-write.
|
|
5992
|
+
*
|
|
5993
|
+
* withFileLock is bounded and FAIL-OPEN by design: on timeout it runs the mutation WITHOUT the
|
|
5994
|
+
* lock rather than hanging the daemon's single thread. That fail-open is a genuine lost-update
|
|
5995
|
+
* window, and merely widening the deadline (the earlier 50→2000 change) only shrinks the
|
|
5996
|
+
* PROBABILITY proportional to N×holdTime — the child's barrier harness reproduced 36-of-48
|
|
5997
|
+
* mutations lost at deadline=2000/hold=50/N=48. `revGuardedMutate` instead embeds a monotonic
|
|
5998
|
+
* `_rev`: it reads the base at rev R, applies the mutation, RE-READS immediately before writing,
|
|
5999
|
+
* and if the rev has advanced (a concurrent commit landed in its window) it retries against the
|
|
6000
|
+
* fresh base rather than clobbering. When the lock genuinely holds this is airtight; when it
|
|
6001
|
+
* fails open it collapses the loss window to the sub-millisecond re-read→rename gap (see
|
|
6002
|
+
* util/revLock.ts for the honest residual). `breakOnDeadOwner` (enabled inside revLock) also
|
|
6003
|
+
* closes the #1228 gap where a crashed holder's lock was never broken because deadlineMs(2000)
|
|
6004
|
+
* < staleMs(5000) — safe precisely because the rev guard tolerates the transient double-writer.
|
|
6005
|
+
*
|
|
6006
|
+
* recordCall uses a SHORT deadline + few attempts: it runs on every channel send (a hot path)
|
|
6007
|
+
* and all it can lose is one entry of a 20-deep rolling log, so it must not block the loop — but
|
|
6008
|
+
* it is still rev-guarded, so it no longer silently drops a log entry to a concurrent mutator
|
|
6009
|
+
* when it does acquire.
|
|
6010
|
+
*/
|
|
6011
|
+
_rmw(id, op, mutate, opts) {
|
|
6012
|
+
return revGuardedMutate(
|
|
6013
|
+
this._lock(id),
|
|
6014
|
+
{
|
|
6015
|
+
read: () => {
|
|
6016
|
+
const c = this.get(id);
|
|
6017
|
+
return { state: c, rev: c?._rev ?? 0 };
|
|
6018
|
+
},
|
|
6019
|
+
write: (state, rev) => {
|
|
6020
|
+
state._rev = rev;
|
|
6021
|
+
this._writeChannel(state);
|
|
6022
|
+
}
|
|
6023
|
+
},
|
|
6024
|
+
mutate,
|
|
6025
|
+
{
|
|
6026
|
+
deadlineMs: opts?.deadlineMs ?? 2e3,
|
|
6027
|
+
maxAttempts: opts?.maxAttempts,
|
|
6028
|
+
onFailOpen: () => {
|
|
6029
|
+
console.warn(`[channels] ${op}(${id}): lock contended \u2014 proceeding WITHOUT it (rev-guarded); a concurrent update is still highly unlikely to be lost`);
|
|
6030
|
+
},
|
|
6031
|
+
_seam: makeRmwSeam()
|
|
6032
|
+
}
|
|
6033
|
+
);
|
|
6034
|
+
}
|
|
5898
6035
|
setEnabled(id, enabled) {
|
|
5899
|
-
return
|
|
5900
|
-
|
|
5901
|
-
if (!c) return null;
|
|
6036
|
+
return this._rmw(id, "setEnabled", (c) => {
|
|
6037
|
+
if (!c) return { next: null, result: null };
|
|
5902
6038
|
c.enabled = enabled;
|
|
5903
|
-
return
|
|
6039
|
+
return { next: c, result: c };
|
|
5904
6040
|
});
|
|
5905
6041
|
}
|
|
5906
6042
|
recordCall(id, entry) {
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
if (!c) return;
|
|
6043
|
+
this._rmw(id, "recordCall", (c) => {
|
|
6044
|
+
if (!c) return { next: null, result: void 0 };
|
|
5910
6045
|
c.last_calls = c.last_calls || [];
|
|
5911
6046
|
c.last_calls.unshift({ at: (/* @__PURE__ */ new Date()).toISOString(), ...entry });
|
|
5912
6047
|
c.last_calls = c.last_calls.slice(0, 20);
|
|
5913
|
-
|
|
5914
|
-
});
|
|
6048
|
+
return { next: c, result: void 0 };
|
|
6049
|
+
}, { deadlineMs: 200, maxAttempts: 3 });
|
|
5915
6050
|
}
|
|
5916
6051
|
addCaller(id, name, kind = "agent") {
|
|
5917
|
-
return
|
|
5918
|
-
|
|
5919
|
-
if (!c) return null;
|
|
6052
|
+
return this._rmw(id, "addCaller", (c) => {
|
|
6053
|
+
if (!c) return { next: null, result: null };
|
|
5920
6054
|
c.identity.callers = c.identity.callers || [];
|
|
5921
6055
|
const caller = { name, kind, key: genKey() };
|
|
5922
6056
|
c.identity.callers.push(caller);
|
|
5923
|
-
|
|
5924
|
-
return caller;
|
|
6057
|
+
return { next: c, result: caller };
|
|
5925
6058
|
});
|
|
5926
6059
|
}
|
|
5927
6060
|
/**
|
|
@@ -5936,14 +6069,12 @@ class ChannelStore {
|
|
|
5936
6069
|
* resurrect the revoked entry by writing a stale base. Returns true when a caller was removed.
|
|
5937
6070
|
*/
|
|
5938
6071
|
removeCaller(id, name) {
|
|
5939
|
-
return
|
|
5940
|
-
|
|
5941
|
-
if (!c?.identity?.callers) return false;
|
|
6072
|
+
return this._rmw(id, "removeCaller", (c) => {
|
|
6073
|
+
if (!c?.identity?.callers) return { next: null, result: false };
|
|
5942
6074
|
const before = c.identity.callers.length;
|
|
5943
6075
|
c.identity.callers = c.identity.callers.filter((x) => x.name !== name);
|
|
5944
|
-
if (c.identity.callers.length === before) return false;
|
|
5945
|
-
|
|
5946
|
-
return true;
|
|
6076
|
+
if (c.identity.callers.length === before) return { next: null, result: false };
|
|
6077
|
+
return { next: c, result: true };
|
|
5947
6078
|
});
|
|
5948
6079
|
}
|
|
5949
6080
|
}
|
|
@@ -8378,7 +8509,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
8378
8509
|
}
|
|
8379
8510
|
const deps = buildSessionDeps(rpc, { cwd, ownerEmail: owner });
|
|
8380
8511
|
const sender = { name: context?.user?.email || context?.user?.id || "user", kind: "user", verified: true };
|
|
8381
|
-
const { toolsForRole } = await import('./sideband-
|
|
8512
|
+
const { toolsForRole } = await import('./sideband-BBOHmvTf.mjs');
|
|
8382
8513
|
const r2 = await runWiseAgent({ message: params.message, sender, config: { tools: toolsForRole(role2) }, deps, transport, model: resolved.model });
|
|
8383
8514
|
return fmt(r2);
|
|
8384
8515
|
}
|
|
@@ -8510,7 +8641,7 @@ QUESTION: ${params.question || "Summarize this concisely."}` }
|
|
|
8510
8641
|
return { ok: false, call_id: callId, status: "busy", error: "channel is busy (too many concurrent requests) \u2014 retry shortly" };
|
|
8511
8642
|
}
|
|
8512
8643
|
const rendered = renderMessage(c, { sender: r.sender, body: { message: kwargs.message }, callId });
|
|
8513
|
-
const { queryCore } = await import('./commands-
|
|
8644
|
+
const { queryCore } = await import('./commands-CBwYOKmf.mjs');
|
|
8514
8645
|
const timeout = c.reply?.timeout_sec || 120;
|
|
8515
8646
|
let result;
|
|
8516
8647
|
let thrownSessionId;
|
|
@@ -18453,6 +18584,18 @@ function computeObservedContext(usage) {
|
|
|
18453
18584
|
if (!usage) return 0;
|
|
18454
18585
|
return (usage.input_tokens || 0) + (usage.cache_creation_input_tokens || 0) + (usage.cache_read_input_tokens || 0);
|
|
18455
18586
|
}
|
|
18587
|
+
function peakRequestUsage(usages) {
|
|
18588
|
+
let best;
|
|
18589
|
+
let bestTokens = 0;
|
|
18590
|
+
for (const u of usages) {
|
|
18591
|
+
const n = computeObservedContext(u);
|
|
18592
|
+
if (n > bestTokens) {
|
|
18593
|
+
bestTokens = n;
|
|
18594
|
+
best = u ?? void 0;
|
|
18595
|
+
}
|
|
18596
|
+
}
|
|
18597
|
+
return bestTokens > 0 ? best : void 0;
|
|
18598
|
+
}
|
|
18456
18599
|
function inferWindowFromModelName(model) {
|
|
18457
18600
|
if (!model) return 0;
|
|
18458
18601
|
if (/\[1m\]/i.test(model)) return 1e6;
|
|
@@ -18610,6 +18753,26 @@ function decideCompactUnsupported(input) {
|
|
|
18610
18753
|
function describeNoBoundary(strikes, limit) {
|
|
18611
18754
|
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.`;
|
|
18612
18755
|
}
|
|
18756
|
+
function shouldAccountLoopTurn(state) {
|
|
18757
|
+
if (state.justCompacted) return false;
|
|
18758
|
+
if (state.compactPending) return false;
|
|
18759
|
+
return true;
|
|
18760
|
+
}
|
|
18761
|
+
function shouldPersistObservedContext(state) {
|
|
18762
|
+
if (state.justCompacted) return false;
|
|
18763
|
+
if (state.compactPending) return false;
|
|
18764
|
+
if (state.turnErrored) return false;
|
|
18765
|
+
return true;
|
|
18766
|
+
}
|
|
18767
|
+
function postCompactionObservedContext(compactMetadata) {
|
|
18768
|
+
const md = compactMetadata;
|
|
18769
|
+
if (!md || typeof md !== "object") return 0;
|
|
18770
|
+
for (const key of ["post_tokens", "postTokens", "post_token_count", "tokens_after", "after_tokens"]) {
|
|
18771
|
+
const v = md[key];
|
|
18772
|
+
if (typeof v === "number" && Number.isFinite(v) && v > 0) return Math.floor(v);
|
|
18773
|
+
}
|
|
18774
|
+
return 0;
|
|
18775
|
+
}
|
|
18613
18776
|
|
|
18614
18777
|
function fmtTokens(n) {
|
|
18615
18778
|
return Math.max(0, Math.round(n)).toLocaleString("en-US");
|
|
@@ -20741,7 +20904,7 @@ async function startDaemon(options) {
|
|
|
20741
20904
|
try {
|
|
20742
20905
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
20743
20906
|
if (!dir) return;
|
|
20744
|
-
const { reconcileServiceLinks } = await import('./agentCommands-
|
|
20907
|
+
const { reconcileServiceLinks } = await import('./agentCommands-f5J1vh6G.mjs');
|
|
20745
20908
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
20746
20909
|
const config = readSvampConfig(configPath);
|
|
20747
20910
|
const entries = Array.from(urls.entries());
|
|
@@ -20763,7 +20926,7 @@ async function startDaemon(options) {
|
|
|
20763
20926
|
try {
|
|
20764
20927
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
20765
20928
|
if (!dir) return;
|
|
20766
|
-
const { reconcileServiceLinks } = await import('./agentCommands-
|
|
20929
|
+
const { reconcileServiceLinks } = await import('./agentCommands-f5J1vh6G.mjs');
|
|
20767
20930
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
20768
20931
|
const config = readSvampConfig(configPath);
|
|
20769
20932
|
const incoming = [{
|
|
@@ -20784,7 +20947,7 @@ async function startDaemon(options) {
|
|
|
20784
20947
|
try {
|
|
20785
20948
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
20786
20949
|
if (!dir) return;
|
|
20787
|
-
const { dropServiceLinks } = await import('./agentCommands-
|
|
20950
|
+
const { dropServiceLinks } = await import('./agentCommands-f5J1vh6G.mjs');
|
|
20788
20951
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
20789
20952
|
const config = readSvampConfig(configPath);
|
|
20790
20953
|
if (dropServiceLinks(config, "serve", mountName)) {
|
|
@@ -20800,7 +20963,7 @@ async function startDaemon(options) {
|
|
|
20800
20963
|
try {
|
|
20801
20964
|
const dir = loadSessionIndex()[sessionId]?.directory;
|
|
20802
20965
|
if (!dir) return;
|
|
20803
|
-
const { dropServiceLinks } = await import('./agentCommands-
|
|
20966
|
+
const { dropServiceLinks } = await import('./agentCommands-f5J1vh6G.mjs');
|
|
20804
20967
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
20805
20968
|
const config = readSvampConfig(configPath);
|
|
20806
20969
|
if (dropServiceLinks(config, "tunnel", tunnelName)) {
|
|
@@ -20812,9 +20975,12 @@ async function startDaemon(options) {
|
|
|
20812
20975
|
}
|
|
20813
20976
|
}
|
|
20814
20977
|
let liveSessionDirs;
|
|
20978
|
+
let serviceRegistriesRestored = false;
|
|
20979
|
+
const managedLinkSessions = /* @__PURE__ */ new Set();
|
|
20980
|
+
let managedLinkSessionsSeeded = false;
|
|
20815
20981
|
async function reconcileAllServiceLinks() {
|
|
20816
20982
|
try {
|
|
20817
|
-
const { reconcileServiceLinksExact } = await import('./agentCommands-
|
|
20983
|
+
const { reconcileServiceLinksExact, hasManagedServiceLink } = await import('./agentCommands-f5J1vh6G.mjs');
|
|
20818
20984
|
const desiredBySession = /* @__PURE__ */ new Map();
|
|
20819
20985
|
const push = (sessionId, entry) => {
|
|
20820
20986
|
if (!sessionId || !entry.url) return;
|
|
@@ -20842,7 +21008,19 @@ async function startDaemon(options) {
|
|
|
20842
21008
|
for (const s of liveSessionDirs?.() ?? []) {
|
|
20843
21009
|
if (s.sessionId && s.directory) dirBySession.set(s.sessionId, s.directory);
|
|
20844
21010
|
}
|
|
20845
|
-
|
|
21011
|
+
if (!managedLinkSessionsSeeded) {
|
|
21012
|
+
for (const [sessionId, dir] of dirBySession) {
|
|
21013
|
+
try {
|
|
21014
|
+
if (hasManagedServiceLink(readSvampConfig(getSvampConfigPath(dir, sessionId)), ["serve", "tunnel"])) {
|
|
21015
|
+
managedLinkSessions.add(sessionId);
|
|
21016
|
+
}
|
|
21017
|
+
} catch {
|
|
21018
|
+
}
|
|
21019
|
+
}
|
|
21020
|
+
managedLinkSessionsSeeded = true;
|
|
21021
|
+
logger.log(`[launchpad] Seeded managed-link set: ${managedLinkSessions.size} of ${dirBySession.size} known sessions carry a serve/tunnel link`);
|
|
21022
|
+
}
|
|
21023
|
+
const sessionIds = /* @__PURE__ */ new Set([...managedLinkSessions, ...desiredBySession.keys()]);
|
|
20846
21024
|
for (const sessionId of sessionIds) {
|
|
20847
21025
|
try {
|
|
20848
21026
|
const dir = dirBySession.get(sessionId);
|
|
@@ -20850,9 +21028,14 @@ async function startDaemon(options) {
|
|
|
20850
21028
|
const configPath = getSvampConfigPath(dir, sessionId);
|
|
20851
21029
|
const config = readSvampConfig(configPath);
|
|
20852
21030
|
const desired = desiredBySession.get(sessionId) ?? [];
|
|
20853
|
-
if (reconcileServiceLinksExact(config, ["serve", "tunnel"], desired)) {
|
|
21031
|
+
if (reconcileServiceLinksExact(config, ["serve", "tunnel"], desired, { dropStale: serviceRegistriesRestored })) {
|
|
20854
21032
|
writeSvampConfig(configPath, config);
|
|
20855
|
-
logger.log(`[launchpad] Reconciled service links for session ${sessionId} (${desired.length} live)`);
|
|
21033
|
+
logger.log(`[launchpad] Reconciled service links for session ${sessionId} (${desired.length} live${serviceRegistriesRestored ? "" : ", upsert-only \u2014 restore in flight"})`);
|
|
21034
|
+
}
|
|
21035
|
+
if (desired.length > 0 || hasManagedServiceLink(config, ["serve", "tunnel"])) {
|
|
21036
|
+
managedLinkSessions.add(sessionId);
|
|
21037
|
+
} else {
|
|
21038
|
+
managedLinkSessions.delete(sessionId);
|
|
20856
21039
|
}
|
|
20857
21040
|
} catch (err) {
|
|
20858
21041
|
logger.log(`[launchpad] Reconcile failed for session ${sessionId}: ${err?.message || err}`);
|
|
@@ -21848,8 +22031,10 @@ ${parts.join("\n")}`);
|
|
|
21848
22031
|
let autoCompactDisabled = false;
|
|
21849
22032
|
let autoCompactRecoveryTried = false;
|
|
21850
22033
|
let justCompactedTurn = false;
|
|
22034
|
+
let compactTurnLatch = false;
|
|
21851
22035
|
let compactNoBoundaryStrikes = 0;
|
|
21852
22036
|
let compactSupported = void 0;
|
|
22037
|
+
let turnRequestUsages = [];
|
|
21853
22038
|
let noIsolationWarned = false;
|
|
21854
22039
|
const RATELIMIT_CFG = getRateLimitRetryConfig();
|
|
21855
22040
|
let currentTurnMessage;
|
|
@@ -22184,6 +22369,7 @@ ${parts.join("\n")}`);
|
|
|
22184
22369
|
if (typeof assistantModel === "string" && assistantModel.length > 0) {
|
|
22185
22370
|
lastMainModel = assistantModel;
|
|
22186
22371
|
}
|
|
22372
|
+
if (msg.message?.usage) turnRequestUsages.push(msg.message.usage);
|
|
22187
22373
|
}
|
|
22188
22374
|
const assistantContent = msg.type === "assistant" ? msg.message?.content ?? msg.content : void 0;
|
|
22189
22375
|
if (Array.isArray(assistantContent)) {
|
|
@@ -22333,18 +22519,25 @@ ${parts.join("\n")}`);
|
|
|
22333
22519
|
}
|
|
22334
22520
|
signalProcessing(false);
|
|
22335
22521
|
sessionWasProcessing = false;
|
|
22522
|
+
const peakUsage = peakRequestUsage(turnRequestUsages) ?? msg.usage;
|
|
22336
22523
|
const resolvedWindow = applyMaxContextWindow(resolveContextWindow({
|
|
22337
22524
|
modelUsage: msg.modelUsage,
|
|
22338
|
-
usage:
|
|
22525
|
+
usage: peakUsage,
|
|
22339
22526
|
mainModel: lastMainModel,
|
|
22340
22527
|
currentWindow: sessionMetadata.contextWindow
|
|
22341
22528
|
}), maxContextWindow);
|
|
22342
|
-
const observedThisTurn = computeObservedContext(
|
|
22343
|
-
|
|
22529
|
+
const observedThisTurn = computeObservedContext(peakUsage);
|
|
22530
|
+
const mayPersistObserved = shouldPersistObservedContext({
|
|
22531
|
+
justCompacted: justCompactedTurn,
|
|
22532
|
+
compactPending: compactTurnLatch,
|
|
22533
|
+
turnErrored: !!msg.is_error
|
|
22534
|
+
});
|
|
22535
|
+
const persistObserved = mayPersistObserved && observedThisTurn > 0 && observedThisTurn !== sessionMetadata.observedContext;
|
|
22536
|
+
if (resolvedWindow > 0 && resolvedWindow !== sessionMetadata.contextWindow || persistObserved) {
|
|
22344
22537
|
sessionMetadata = {
|
|
22345
22538
|
...sessionMetadata,
|
|
22346
22539
|
...resolvedWindow > 0 ? { contextWindow: resolvedWindow } : {},
|
|
22347
|
-
...
|
|
22540
|
+
...persistObserved ? { observedContext: observedThisTurn } : {}
|
|
22348
22541
|
};
|
|
22349
22542
|
sessionService.updateMetadata(sessionMetadata);
|
|
22350
22543
|
}
|
|
@@ -22365,7 +22558,11 @@ ${parts.join("\n")}`);
|
|
|
22365
22558
|
clearInboundContext(sessionId);
|
|
22366
22559
|
try {
|
|
22367
22560
|
const ls = readLoopState(directory, sessionId);
|
|
22368
|
-
|
|
22561
|
+
const accountLoopTurn = shouldAccountLoopTurn({
|
|
22562
|
+
justCompacted: justCompactedTurn,
|
|
22563
|
+
compactPending: compactTurnLatch
|
|
22564
|
+
});
|
|
22565
|
+
if (accountLoopTurn && ls && ls.engine === "goal" && ls.active !== false && ls.phase !== "dormant" && ls.phase !== "done" && ls.phase !== "gave_up" && ls.phase !== "cancelled") {
|
|
22369
22566
|
const now = Date.now();
|
|
22370
22567
|
const ledger = accumulateLedger(ls.ledger, {
|
|
22371
22568
|
turns: Number(msg.num_turns) || 0,
|
|
@@ -22422,9 +22619,10 @@ ${parts.join("\n")}`);
|
|
|
22422
22619
|
enabled: autoCompactEnabled
|
|
22423
22620
|
});
|
|
22424
22621
|
justCompactedTurn = false;
|
|
22622
|
+
compactTurnLatch = false;
|
|
22425
22623
|
if (mayEvaluateLayer1) {
|
|
22426
22624
|
try {
|
|
22427
|
-
const observed =
|
|
22625
|
+
const observed = observedThisTurn;
|
|
22428
22626
|
const decision = decideProactiveCompaction({
|
|
22429
22627
|
observed,
|
|
22430
22628
|
window: resolvedWindow > 0 ? resolvedWindow : sessionMetadata.contextWindow || 0,
|
|
@@ -22479,6 +22677,7 @@ ${parts.join("\n")}`);
|
|
|
22479
22677
|
} else if (msg.type === "system" && msg.subtype === "init") {
|
|
22480
22678
|
consecutiveOverloadRetries = 0;
|
|
22481
22679
|
overloadBailedThisTurn = false;
|
|
22680
|
+
turnRequestUsages = [];
|
|
22482
22681
|
if (!userMessagePending) {
|
|
22483
22682
|
turnInitiatedByUser = false;
|
|
22484
22683
|
logger.log(`[Session ${sessionId}] SDK-initiated turn (likely stale task_notification)`);
|
|
@@ -22541,7 +22740,16 @@ ${parts.join("\n")}`);
|
|
|
22541
22740
|
autoCompactWasAutoInjected = false;
|
|
22542
22741
|
autoCompactRecoveryTried = false;
|
|
22543
22742
|
justCompactedTurn = true;
|
|
22743
|
+
compactTurnLatch = true;
|
|
22544
22744
|
compactNoBoundaryStrikes = 0;
|
|
22745
|
+
try {
|
|
22746
|
+
const postObserved = postCompactionObservedContext(msg.compact_metadata);
|
|
22747
|
+
if (sessionMetadata.observedContext !== postObserved) {
|
|
22748
|
+
sessionMetadata = { ...sessionMetadata, observedContext: postObserved };
|
|
22749
|
+
sessionService.updateMetadata(sessionMetadata);
|
|
22750
|
+
}
|
|
22751
|
+
} catch {
|
|
22752
|
+
}
|
|
22545
22753
|
const compactLine = describeCompaction(msg.compact_metadata);
|
|
22546
22754
|
logger.log(`[Session ${sessionId}] ${compactLine}`);
|
|
22547
22755
|
sessionService.pushMessage(
|
|
@@ -22970,6 +23178,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
22970
23178
|
rateLimitRetryTimer = null;
|
|
22971
23179
|
}
|
|
22972
23180
|
pendingCompactTurn = isCompactCommand(text);
|
|
23181
|
+
if (pendingCompactTurn) compactTurnLatch = true;
|
|
22973
23182
|
if (!claudeProcess || claudeProcess.exitCode !== null) {
|
|
22974
23183
|
const preTurnWindow = applyMaxContextWindow(sessionMetadata.contextWindow || 0, maxContextWindow);
|
|
22975
23184
|
const preTurnObserved = sessionMetadata.observedContext || 0;
|
|
@@ -22994,6 +23203,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
22994
23203
|
};
|
|
22995
23204
|
sessionService.updateMetadata(sessionMetadata);
|
|
22996
23205
|
pendingCompactTurn = true;
|
|
23206
|
+
compactTurnLatch = true;
|
|
22997
23207
|
autoCompactWasAutoInjected = true;
|
|
22998
23208
|
spawnClaude("/compact", msgMeta);
|
|
22999
23209
|
signalProcessing(true);
|
|
@@ -23387,11 +23597,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
23387
23597
|
});
|
|
23388
23598
|
},
|
|
23389
23599
|
onIssue: async (params) => {
|
|
23390
|
-
const { issueRpc } = await import('./rpc-
|
|
23600
|
+
const { issueRpc } = await import('./rpc-BQ75iSkj.mjs');
|
|
23391
23601
|
return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
|
|
23392
23602
|
},
|
|
23393
23603
|
onWorkflow: async (params) => {
|
|
23394
|
-
const { workflowRpc } = await import('./rpc-
|
|
23604
|
+
const { workflowRpc } = await import('./rpc-CG6XWFXY.mjs');
|
|
23395
23605
|
return workflowRpc(params?.cwd || directory, params || {});
|
|
23396
23606
|
},
|
|
23397
23607
|
onRipgrep: async (args, cwd) => {
|
|
@@ -23531,6 +23741,7 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
23531
23741
|
turnInitiatedByUser = true;
|
|
23532
23742
|
currentTurnMessage = next.text;
|
|
23533
23743
|
pendingCompactTurn = isCompactCommand(next.text);
|
|
23744
|
+
if (pendingCompactTurn) compactTurnLatch = true;
|
|
23534
23745
|
autoCompactWasAutoInjected = pendingCompactTurn && !!next.autoCompact;
|
|
23535
23746
|
resetRateLimitStreak();
|
|
23536
23747
|
if (rateLimitRetryTimer) {
|
|
@@ -24114,11 +24325,11 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
|
|
|
24114
24325
|
});
|
|
24115
24326
|
},
|
|
24116
24327
|
onIssue: async (params) => {
|
|
24117
|
-
const { issueRpc } = await import('./rpc-
|
|
24328
|
+
const { issueRpc } = await import('./rpc-BQ75iSkj.mjs');
|
|
24118
24329
|
return issueRpc(params?.cwd || directory, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
|
|
24119
24330
|
},
|
|
24120
24331
|
onWorkflow: async (params) => {
|
|
24121
|
-
const { workflowRpc } = await import('./rpc-
|
|
24332
|
+
const { workflowRpc } = await import('./rpc-CG6XWFXY.mjs');
|
|
24122
24333
|
return workflowRpc(params?.cwd || directory, params || {});
|
|
24123
24334
|
},
|
|
24124
24335
|
onRipgrep: async (args, cwd) => {
|
|
@@ -25119,8 +25330,12 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
25119
25330
|
} catch (err) {
|
|
25120
25331
|
logger.log(`[serve] mount link reconcile failed: ${err?.message || err}`);
|
|
25121
25332
|
}
|
|
25333
|
+
serviceRegistriesRestored = true;
|
|
25122
25334
|
scheduleServiceLinkReconcile(3e3);
|
|
25123
|
-
}).catch((err) =>
|
|
25335
|
+
}).catch((err) => {
|
|
25336
|
+
serviceRegistriesRestored = true;
|
|
25337
|
+
logger.error(`[serve] mount restore failed: ${err?.message || err}`);
|
|
25338
|
+
});
|
|
25124
25339
|
const daemonOwnerEmail = parseJwtEmail(process.env.HYPHA_TOKEN || "") || null;
|
|
25125
25340
|
serveManager$1.setSessionResolver((sessionId) => {
|
|
25126
25341
|
for (const [, session] of pidToTrackedSession) {
|
|
@@ -25469,7 +25684,7 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
|
|
|
25469
25684
|
const PING_TIMEOUT_MS = 15e3;
|
|
25470
25685
|
const POST_RECONNECT_GRACE_MS = 2e4;
|
|
25471
25686
|
const RECONNECT_JITTER_MS = 2500;
|
|
25472
|
-
const { WorkflowScheduler } = await import('./scheduler-
|
|
25687
|
+
const { WorkflowScheduler } = await import('./scheduler-QsXyNajm.mjs');
|
|
25473
25688
|
const workflowProjectRoots = () => {
|
|
25474
25689
|
const dirs = /* @__PURE__ */ new Set();
|
|
25475
25690
|
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 { am as applyClaudeProxyEnv, an as composeSessionId, ao as generateFriendlyName, c as connectToHypha, a as createSessionStore, r as registerMachineService, ap as generateHookSettings } from './run
|
|
1
|
+
import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { am as applyClaudeProxyEnv, an as composeSessionId, ao as generateFriendlyName, c as connectToHypha, a as createSessionStore, r as registerMachineService, ap as generateHookSettings } from './run--wM4gBLw.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, E as listWorkflows, F as isWorkflowEnabled, G as workflowSchedules, H as inZone, x as runWorkflow, I as cronMatches } from './run
|
|
1
|
+
import { f as resolveProjectRoot, E as listWorkflows, F as isWorkflowEnabled, G as workflowSchedules, H as inZone, x as runWorkflow, I as cronMatches } from './run--wM4gBLw.mjs';
|
|
2
2
|
import 'os';
|
|
3
3
|
import 'fs/promises';
|
|
4
4
|
import 'fs';
|