instar 1.3.912 → 1.3.913
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 +44 -1
- package/dist/commands/server.js.map +1 -1
- package/dist/monitoring/PresenceProxy.d.ts +4 -0
- package/dist/monitoring/PresenceProxy.d.ts.map +1 -1
- package/dist/monitoring/PresenceProxy.js +43 -3
- package/dist/monitoring/PresenceProxy.js.map +1 -1
- package/dist/monitoring/SessionRecovery.d.ts +17 -1
- package/dist/monitoring/SessionRecovery.d.ts.map +1 -1
- package/dist/monitoring/SessionRecovery.js +103 -16
- package/dist/monitoring/SessionRecovery.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.913.md +30 -0
- package/upgrades/side-effects/context-wall-recovery-robustness.md +62 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA4EH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAU3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AA0BjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AA8H7D,OAAO,KAAK,EAAW,oBAAoB,EAAe,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAgFtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AAyID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA+rDD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,YAAY,EACpB,YAAY,EAAE,oBAAoB,GAAG,IAAI,GACxC;IACD,YAAY,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAqBA;AAED,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,EAKhG,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,EAQrD,oBAAoB,CAAC,EAAE,MAAM;IAC3B,YAAY,EAAE,OAAO,kBAAkB,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,GACP,IAAI,CAwtBN;AAgmBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAuypBtE;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
|
@@ -45,6 +45,7 @@ import { configureHostSpawnSemaphore } from '../core/hostSpawnSemaphore.js';
|
|
|
45
45
|
import { SpawningTopicsRegistry } from '../core/SpawningTopicsRegistry.js';
|
|
46
46
|
import { planCredentialIdentityRepair } from '../core/CredentialIdentityRepairPlan.js';
|
|
47
47
|
import { TopicReachabilityVerifier } from '../monitoring/TopicReachabilityVerifier.js';
|
|
48
|
+
import { probeTranscript } from '../monitoring/transcriptProber.js';
|
|
48
49
|
import { SingleInstanceLock, installReleaseHandlers } from '../core/SingleInstanceLock.js';
|
|
49
50
|
import { resolveDevAgentGate, resolveStateSyncStores } from '../core/devAgentGate.js';
|
|
50
51
|
import { resolveAntiThrashKnobs, readingValidity } from '../core/SwapAntiThrash.js';
|
|
@@ -485,6 +486,10 @@ let _spawningTopicsRegistryRef = null;
|
|
|
485
486
|
// Module-level reference for session resume mapping.
|
|
486
487
|
// Set once in startServer() and used by spawnSessionForTopic/respawnSessionForTopic.
|
|
487
488
|
let _topicResumeMap = null;
|
|
489
|
+
// Context-wall recovery latch. These late-bound seams let every Telegram/Slack
|
|
490
|
+
// spawn chokepoint fail fresh while SessionRecovery owns a durable latch.
|
|
491
|
+
let _contextExhaustionFreshRequired = null;
|
|
492
|
+
let _clearContextExhaustionFreshRequired = null;
|
|
488
493
|
// ── Multi-Machine Session Pool (§L4) activation refs ──────────────────────
|
|
489
494
|
// The SessionRouter is constructed in startServer()'s mesh block, but the inbound
|
|
490
495
|
// dispatch handler that consults it is defined ABOVE startServer — so the router is
|
|
@@ -1098,6 +1103,11 @@ spawnOpts) {
|
|
|
1098
1103
|
// TopicResumeMap is authoritative — it saved the UUID for this specific topic at kill time
|
|
1099
1104
|
// or via the refresh heartbeat. Skip LLM validation (which was failing due to JSONL sampling
|
|
1100
1105
|
// issues and is redundant for an authoritative source).
|
|
1106
|
+
const contextWallForcesFresh = _contextExhaustionFreshRequired?.(topicId) === true;
|
|
1107
|
+
if (contextWallForcesFresh) {
|
|
1108
|
+
_topicResumeMap?.remove(topicId);
|
|
1109
|
+
console.log(`[spawnSessionForTopic] Context-exhaustion latch active for topic ${topicId} — forcing fresh spawn`);
|
|
1110
|
+
}
|
|
1101
1111
|
let resumeSessionId = _topicResumeMap?.get(topicId) ?? undefined;
|
|
1102
1112
|
if (resumeSessionId) {
|
|
1103
1113
|
console.log(`[spawnSessionForTopic] Found resume UUID for topic ${topicId}: ${resumeSessionId} (source: TopicResumeMap — trusted)`);
|
|
@@ -1219,6 +1229,9 @@ spawnOpts) {
|
|
|
1219
1229
|
}
|
|
1220
1230
|
}, 8000);
|
|
1221
1231
|
}
|
|
1232
|
+
if (contextWallForcesFresh) {
|
|
1233
|
+
_clearContextExhaustionFreshRequired?.(topicId);
|
|
1234
|
+
}
|
|
1222
1235
|
return newSessionName;
|
|
1223
1236
|
}
|
|
1224
1237
|
/**
|
|
@@ -7826,7 +7839,15 @@ export async function startServer(options) {
|
|
|
7826
7839
|
}
|
|
7827
7840
|
// Check resume map for session continuity (keyed on routing key, so a
|
|
7828
7841
|
// thread resumes its OWN session and not the channel-root one).
|
|
7829
|
-
const
|
|
7842
|
+
const contextWallForcesFresh = conversationId !== null
|
|
7843
|
+
&& _contextExhaustionFreshRequired?.(conversationId) === true;
|
|
7844
|
+
if (contextWallForcesFresh) {
|
|
7845
|
+
slackAdapter.removeChannelResume(routingKey);
|
|
7846
|
+
console.log(`[slack→session] Context-exhaustion latch active for conversation ${conversationId} — forcing fresh spawn`);
|
|
7847
|
+
}
|
|
7848
|
+
const resumeInfo = contextWallForcesFresh
|
|
7849
|
+
? null
|
|
7850
|
+
: slackAdapter.getChannelResume(routingKey);
|
|
7830
7851
|
const resumeSessionId = resumeInfo?.uuid ?? undefined;
|
|
7831
7852
|
if (resumeInfo) {
|
|
7832
7853
|
slackAdapter.removeChannelResume(routingKey);
|
|
@@ -7913,6 +7934,9 @@ export async function startServer(options) {
|
|
|
7913
7934
|
slackAdapter.registerChannelSession(routingKey, newSessionName, isThreadSession ? `${channelId} (thread ${replyThreadTs})` : undefined);
|
|
7914
7935
|
slackAdapter.trackMessageInjection(channelId, newSessionName, message.content);
|
|
7915
7936
|
console.log(`[slack→session] ${resumeSessionId ? 'Resumed' : 'Spawned'} "${newSessionName}" for ${isThreadSession ? `thread ${routingKey}` : `channel ${channelId}`}`);
|
|
7937
|
+
if (contextWallForcesFresh && conversationId !== null) {
|
|
7938
|
+
_clearContextExhaustionFreshRequired?.(conversationId);
|
|
7939
|
+
}
|
|
7916
7940
|
}
|
|
7917
7941
|
}
|
|
7918
7942
|
catch (err) {
|
|
@@ -10304,6 +10328,18 @@ export async function startServer(options) {
|
|
|
10304
10328
|
},
|
|
10305
10329
|
// P1/P2 cross-check dep — see SessionRecovery.killForRecovery().
|
|
10306
10330
|
hasActiveProcesses: (name) => sessionManager.hasActiveProcesses(name),
|
|
10331
|
+
probeTranscript: (name) => {
|
|
10332
|
+
const session = sessionManager.listRunningSessions()
|
|
10333
|
+
.find((candidate) => candidate.tmuxSession === name);
|
|
10334
|
+
if (!session?.claudeSessionId) {
|
|
10335
|
+
return { resolved: false, path: '', size: 0, mtime: 0 };
|
|
10336
|
+
}
|
|
10337
|
+
return probeTranscript({
|
|
10338
|
+
framework: session.framework ?? 'claude-code',
|
|
10339
|
+
sessionId: session.claudeSessionId,
|
|
10340
|
+
projectDir: session.cwd ?? config.sessions.projectDir,
|
|
10341
|
+
});
|
|
10342
|
+
},
|
|
10307
10343
|
respawnSession: async (topicId, _sessionName, recoveryPrompt) => {
|
|
10308
10344
|
// Check Slack first (synthetic IDs are negative)
|
|
10309
10345
|
const slackChId = slackProxyChannelMap.get(topicId);
|
|
@@ -10571,6 +10607,10 @@ export async function startServer(options) {
|
|
|
10571
10607
|
// Clean up after 60 seconds — by then the kill and respawn are done
|
|
10572
10608
|
setTimeout(() => contextExhaustionKills.delete(sessionName), 60_000);
|
|
10573
10609
|
});
|
|
10610
|
+
_contextExhaustionFreshRequired = (topicId) => sessionRecovery?.hasContextWedgedSeen(topicId) === true;
|
|
10611
|
+
_clearContextExhaustionFreshRequired = (topicId) => {
|
|
10612
|
+
sessionRecovery?.clearContextWedgedSeen(topicId);
|
|
10613
|
+
};
|
|
10574
10614
|
console.log(pc.green(' Session Recovery enabled (mechanical fast-path)'));
|
|
10575
10615
|
}
|
|
10576
10616
|
// SessionMonitor — proactive session health monitoring
|
|
@@ -12979,6 +13019,9 @@ export async function startServer(options) {
|
|
|
12979
13019
|
return { recovered: result.recovered };
|
|
12980
13020
|
}
|
|
12981
13021
|
: undefined,
|
|
13022
|
+
hasContextExhaustionLatch: sessionRecovery
|
|
13023
|
+
? (topicId) => sessionRecovery.hasContextWedgedSeen(topicId)
|
|
13024
|
+
: undefined,
|
|
12982
13025
|
// Shared per-topic mutex — coordinates with PromiseBeacon.
|
|
12983
13026
|
acquireProxyMutex: (topicId, holder) => proxyCoordinator.tryAcquire(topicId, holder),
|
|
12984
13027
|
releaseProxyMutex: (topicId, holder) => proxyCoordinator.release(topicId, holder),
|