instar 1.3.405 → 1.3.407
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/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +48 -8
- package/dist/commands/server.js.map +1 -1
- package/dist/monitoring/SessionReaper.d.ts +24 -0
- package/dist/monitoring/SessionReaper.d.ts.map +1 -1
- package/dist/monitoring/SessionReaper.js +29 -0
- package/dist/monitoring/SessionReaper.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.406.md +25 -0
- package/upgrades/1.3.407.md +37 -0
- package/upgrades/side-effects/pool-stream-connector-observability.md +53 -0
- package/upgrades/side-effects/reaper-durable-candidacy.md +46 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAaH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAQ3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AAuBjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAiG7D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AA6JtD,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA05BD,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAGvE,UAAU,CAAC,EAAE,MAAM,OAAO,8BAA8B,EAAE,WAAW,GAAG,IAAI,EAK5E,qBAAqB,CAAC,EAAE,MAAM,OAAO,gCAAgC,EAAE,kBAAkB,GAAG,IAAI,GAC/F,IAAI,CAyUN;AA2lBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAaH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAQ3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AAuBjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAiG7D,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AA6JtD,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA05BD,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAGvE,UAAU,CAAC,EAAE,MAAM,OAAO,8BAA8B,EAAE,WAAW,GAAG,IAAI,EAK5E,qBAAqB,CAAC,EAAE,MAAM,OAAO,gCAAgC,EAAE,kBAAkB,GAAG,IAAI,GAC/F,IAAI,CAyUN;AA2lBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAsiUtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
|
package/dist/commands/server.js
CHANGED
|
@@ -9480,6 +9480,29 @@ export async function startServer(options) {
|
|
|
9480
9480
|
// path so the reaper's fallback probe() can resolve + verify idle. Without this
|
|
9481
9481
|
// the probe used '' and every transcript read as unresolved (kept everything).
|
|
9482
9482
|
transcriptProjectDir: () => config.projectDir,
|
|
9483
|
+
// Durable candidacy (A): persist the reaper's idle-candidacy clock to disk so
|
|
9484
|
+
// it survives server restarts. On a box that restarts every ~10min (SleepWake-
|
|
9485
|
+
// under-load churn) the in-memory 45-min clock never matured → reaper never
|
|
9486
|
+
// reaped. The per-tick all-clear + render-stasis re-gate keeps it safe.
|
|
9487
|
+
loadCandidacy: () => {
|
|
9488
|
+
try {
|
|
9489
|
+
const f = path.join(config.stateDir, 'state', 'session-reaper-candidacy.json');
|
|
9490
|
+
if (!fs.existsSync(f))
|
|
9491
|
+
return {};
|
|
9492
|
+
return JSON.parse(fs.readFileSync(f, 'utf-8'));
|
|
9493
|
+
}
|
|
9494
|
+
catch {
|
|
9495
|
+
return {};
|
|
9496
|
+
}
|
|
9497
|
+
},
|
|
9498
|
+
saveCandidacy: (map) => {
|
|
9499
|
+
try {
|
|
9500
|
+
const dir = path.join(config.stateDir, 'state');
|
|
9501
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
9502
|
+
fs.writeFileSync(path.join(dir, 'session-reaper-candidacy.json'), JSON.stringify(map));
|
|
9503
|
+
}
|
|
9504
|
+
catch { /* @silent-fallback-ok — best-effort; clock resets next restart on failure */ }
|
|
9505
|
+
},
|
|
9483
9506
|
pressure: () => {
|
|
9484
9507
|
const total = _os.totalmem();
|
|
9485
9508
|
const freePct = total > 0 ? (_os.freemem() / total) * 100 : 100;
|
|
@@ -10281,11 +10304,14 @@ export async function startServer(options) {
|
|
|
10281
10304
|
// the ticket is bound to that sender and consumed once on upgrade.
|
|
10282
10305
|
'pool-stream-ticket': (cmd, sender) => {
|
|
10283
10306
|
const c = cmd;
|
|
10284
|
-
if (!_streamTicketStore)
|
|
10307
|
+
if (!_streamTicketStore) {
|
|
10308
|
+
console.log(pc.dim(` [pool-stream-ticket] mint request from ${sender} REFUSED: store disabled`));
|
|
10285
10309
|
return { ok: false, reason: 'pool-stream disabled' };
|
|
10310
|
+
}
|
|
10286
10311
|
if (!c.session || typeof c.session !== 'string')
|
|
10287
10312
|
return { ok: false, reason: 'session required' };
|
|
10288
10313
|
const minted = _streamTicketStore.mint(sender);
|
|
10314
|
+
console.log(pc.dim(` [pool-stream-ticket] minted ticket for ${sender}`));
|
|
10289
10315
|
return { ok: true, ticket: minted.ticket, expiresAtMs: minted.expiresAtMs };
|
|
10290
10316
|
},
|
|
10291
10317
|
// COHERENCE-JOURNAL-SPEC §3.4 — always-registered journal-sync verb
|
|
@@ -10406,37 +10432,51 @@ export async function startServer(options) {
|
|
|
10406
10432
|
// bounded reconnect → machine-unreachable).
|
|
10407
10433
|
{
|
|
10408
10434
|
const { WebSocket: WsClient } = await import('ws');
|
|
10435
|
+
const psLog = (m) => console.log(pc.dim(` [pool-stream-connector] ${m}`));
|
|
10409
10436
|
_poolStreamConnector = {
|
|
10410
10437
|
connect: (machineId, handlers) => {
|
|
10411
10438
|
const httpUrl = peerUrl(machineId);
|
|
10412
|
-
if (!httpUrl)
|
|
10439
|
+
if (!httpUrl) {
|
|
10440
|
+
psLog(`connect ${machineId}: no peer url → unreachable`);
|
|
10413
10441
|
return null;
|
|
10442
|
+
}
|
|
10414
10443
|
let ws = null;
|
|
10415
10444
|
let open = false;
|
|
10416
10445
|
let closed = false;
|
|
10417
10446
|
const pending = [];
|
|
10418
10447
|
(async () => {
|
|
10419
10448
|
try {
|
|
10420
|
-
|
|
10449
|
+
psLog(`minting ticket from ${machineId} (${httpUrl})`);
|
|
10450
|
+
// EXPLICIT 10s timeout (live-verify finding 2026-06-07): without
|
|
10451
|
+
// it a wedged mint hung indefinitely — the stream never opened
|
|
10452
|
+
// AND never errored (the connector's onClose never fired), so the
|
|
10453
|
+
// dashboard sat silent forever. A bounded send fails honestly →
|
|
10454
|
+
// onClose → the proxy surfaces peer-stream-lost / unreachable.
|
|
10455
|
+
const r = await meshClient.send({ machineId, url: httpUrl }, { type: 'pool-stream-ticket', session: '*' }, 0, { timeoutMs: 10_000 });
|
|
10421
10456
|
const ticket = r.ok && r.result && typeof r.result === 'object' ? r.result.ticket : undefined;
|
|
10422
|
-
if (!ticket
|
|
10457
|
+
if (!ticket) {
|
|
10458
|
+
psLog(`mint failed for ${machineId}: ok=${r.ok} status=${r.status} reason=${r.reason ?? ''} hasTicket=${!!ticket}`);
|
|
10423
10459
|
if (!closed)
|
|
10424
10460
|
handlers.onClose();
|
|
10425
10461
|
return;
|
|
10426
10462
|
}
|
|
10463
|
+
if (closed)
|
|
10464
|
+
return;
|
|
10427
10465
|
const wsUrl = httpUrl.replace(/^http/, 'ws').replace(/\/$/, '') + `/pool-stream?ticket=${encodeURIComponent(ticket)}`;
|
|
10466
|
+
psLog(`ticket ok; opening upstream ws to ${machineId}`);
|
|
10428
10467
|
ws = new WsClient(wsUrl);
|
|
10429
|
-
ws.on('open', () => { open = true; for (const m of pending)
|
|
10468
|
+
ws.on('open', () => { open = true; psLog(`upstream OPEN to ${machineId}`); for (const m of pending)
|
|
10430
10469
|
ws.send(m); pending.length = 0; handlers.onOpen(); });
|
|
10431
10470
|
ws.on('message', (d) => { try {
|
|
10432
10471
|
handlers.onFrame(JSON.parse(String(d)));
|
|
10433
10472
|
}
|
|
10434
10473
|
catch { /* @silent-fallback-ok: a non-JSON peer frame is dropped; the stream protocol is JSON-only (§2.2) */ } });
|
|
10435
|
-
ws.on('close', () => handlers.onClose());
|
|
10436
|
-
ws.on('error', () => { if (!open)
|
|
10474
|
+
ws.on('close', (code) => { psLog(`upstream CLOSE from ${machineId} (code ${code}, wasOpen ${open})`); handlers.onClose(); });
|
|
10475
|
+
ws.on('error', (e) => { psLog(`upstream ERROR to ${machineId}: ${e?.message ?? e}`); if (!open)
|
|
10437
10476
|
handlers.onClose(); });
|
|
10438
10477
|
}
|
|
10439
|
-
catch {
|
|
10478
|
+
catch (e) {
|
|
10479
|
+
psLog(`connect to ${machineId} threw: ${e?.message ?? e}`);
|
|
10440
10480
|
if (!closed)
|
|
10441
10481
|
handlers.onClose();
|
|
10442
10482
|
}
|