instar 1.3.90 → 1.3.92

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.
Files changed (152) hide show
  1. package/.claude/skills/autonomous/hooks/autonomous-stop-hook.sh +17 -0
  2. package/dashboard/index.html +108 -0
  3. package/dist/commands/server.d.ts.map +1 -1
  4. package/dist/commands/server.js +214 -1
  5. package/dist/commands/server.js.map +1 -1
  6. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  7. package/dist/config/ConfigDefaults.js +30 -0
  8. package/dist/config/ConfigDefaults.js.map +1 -1
  9. package/dist/config/LiveConfig.d.ts +3 -1
  10. package/dist/config/LiveConfig.d.ts.map +1 -1
  11. package/dist/config/LiveConfig.js +4 -1
  12. package/dist/config/LiveConfig.js.map +1 -1
  13. package/dist/config/stageWriteGuard.d.ts +23 -0
  14. package/dist/config/stageWriteGuard.d.ts.map +1 -0
  15. package/dist/config/stageWriteGuard.js +33 -0
  16. package/dist/config/stageWriteGuard.js.map +1 -0
  17. package/dist/core/DeliverMessageHandler.d.ts +33 -0
  18. package/dist/core/DeliverMessageHandler.d.ts.map +1 -0
  19. package/dist/core/DeliverMessageHandler.js +34 -0
  20. package/dist/core/DeliverMessageHandler.js.map +1 -0
  21. package/dist/core/LeaseCoordinator.d.ts +39 -2
  22. package/dist/core/LeaseCoordinator.d.ts.map +1 -1
  23. package/dist/core/LeaseCoordinator.js +45 -9
  24. package/dist/core/LeaseCoordinator.js.map +1 -1
  25. package/dist/core/MachineIdentity.d.ts +28 -1
  26. package/dist/core/MachineIdentity.d.ts.map +1 -1
  27. package/dist/core/MachineIdentity.js +81 -1
  28. package/dist/core/MachineIdentity.js.map +1 -1
  29. package/dist/core/MachineLoadBroker.d.ts +94 -0
  30. package/dist/core/MachineLoadBroker.d.ts.map +1 -0
  31. package/dist/core/MachineLoadBroker.js +87 -0
  32. package/dist/core/MachineLoadBroker.js.map +1 -0
  33. package/dist/core/MachinePoolRegistry.d.ts +94 -0
  34. package/dist/core/MachinePoolRegistry.d.ts.map +1 -0
  35. package/dist/core/MachinePoolRegistry.js +150 -0
  36. package/dist/core/MachinePoolRegistry.js.map +1 -0
  37. package/dist/core/MeshRpc.d.ts +165 -0
  38. package/dist/core/MeshRpc.d.ts.map +1 -0
  39. package/dist/core/MeshRpc.js +156 -0
  40. package/dist/core/MeshRpc.js.map +1 -0
  41. package/dist/core/MeshRpcClient.d.ts +59 -0
  42. package/dist/core/MeshRpcClient.d.ts.map +1 -0
  43. package/dist/core/MeshRpcClient.js +58 -0
  44. package/dist/core/MeshRpcClient.js.map +1 -0
  45. package/dist/core/MultiMachineCoordinator.d.ts +11 -0
  46. package/dist/core/MultiMachineCoordinator.d.ts.map +1 -1
  47. package/dist/core/MultiMachineCoordinator.js +13 -0
  48. package/dist/core/MultiMachineCoordinator.js.map +1 -1
  49. package/dist/core/NicknameAssigner.d.ts +51 -0
  50. package/dist/core/NicknameAssigner.d.ts.map +1 -0
  51. package/dist/core/NicknameAssigner.js +91 -0
  52. package/dist/core/NicknameAssigner.js.map +1 -0
  53. package/dist/core/NicknameCommand.d.ts +28 -0
  54. package/dist/core/NicknameCommand.d.ts.map +1 -0
  55. package/dist/core/NicknameCommand.js +69 -0
  56. package/dist/core/NicknameCommand.js.map +1 -0
  57. package/dist/core/PlacementExecutor.d.ts +71 -0
  58. package/dist/core/PlacementExecutor.d.ts.map +1 -0
  59. package/dist/core/PlacementExecutor.js +156 -0
  60. package/dist/core/PlacementExecutor.js.map +1 -0
  61. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  62. package/dist/core/PostUpdateMigrator.js +21 -0
  63. package/dist/core/PostUpdateMigrator.js.map +1 -1
  64. package/dist/core/RebalancePlanner.d.ts +48 -0
  65. package/dist/core/RebalancePlanner.d.ts.map +1 -0
  66. package/dist/core/RebalancePlanner.js +71 -0
  67. package/dist/core/RebalancePlanner.js.map +1 -0
  68. package/dist/core/SessionManager.d.ts +20 -3
  69. package/dist/core/SessionManager.d.ts.map +1 -1
  70. package/dist/core/SessionManager.js +54 -6
  71. package/dist/core/SessionManager.js.map +1 -1
  72. package/dist/core/SessionOwnership.d.ts +103 -0
  73. package/dist/core/SessionOwnership.d.ts.map +1 -0
  74. package/dist/core/SessionOwnership.js +0 -0
  75. package/dist/core/SessionOwnership.js.map +1 -0
  76. package/dist/core/SessionOwnershipRegistry.d.ts +115 -0
  77. package/dist/core/SessionOwnershipRegistry.d.ts.map +1 -0
  78. package/dist/core/SessionOwnershipRegistry.js +128 -0
  79. package/dist/core/SessionOwnershipRegistry.js.map +1 -0
  80. package/dist/core/SessionPoolE2EResultStore.d.ts +45 -0
  81. package/dist/core/SessionPoolE2EResultStore.d.ts.map +1 -0
  82. package/dist/core/SessionPoolE2EResultStore.js +66 -0
  83. package/dist/core/SessionPoolE2EResultStore.js.map +1 -0
  84. package/dist/core/SessionRouter.d.ts +95 -0
  85. package/dist/core/SessionRouter.d.ts.map +1 -0
  86. package/dist/core/SessionRouter.js +151 -0
  87. package/dist/core/SessionRouter.js.map +1 -0
  88. package/dist/core/StageAdvancer.d.ts +47 -0
  89. package/dist/core/StageAdvancer.d.ts.map +1 -0
  90. package/dist/core/StageAdvancer.js +70 -0
  91. package/dist/core/StageAdvancer.js.map +1 -0
  92. package/dist/core/TransferByNickname.d.ts +51 -0
  93. package/dist/core/TransferByNickname.d.ts.map +1 -0
  94. package/dist/core/TransferByNickname.js +50 -0
  95. package/dist/core/TransferByNickname.js.map +1 -0
  96. package/dist/core/TransferOrchestrator.d.ts +113 -0
  97. package/dist/core/TransferOrchestrator.d.ts.map +1 -0
  98. package/dist/core/TransferOrchestrator.js +79 -0
  99. package/dist/core/TransferOrchestrator.js.map +1 -0
  100. package/dist/core/types.d.ts +177 -1
  101. package/dist/core/types.d.ts.map +1 -1
  102. package/dist/core/types.js.map +1 -1
  103. package/dist/monitoring/RateLimitSentinel.d.ts +24 -2
  104. package/dist/monitoring/RateLimitSentinel.d.ts.map +1 -1
  105. package/dist/monitoring/RateLimitSentinel.js +25 -14
  106. package/dist/monitoring/RateLimitSentinel.js.map +1 -1
  107. package/dist/scaffold/templates.d.ts.map +1 -1
  108. package/dist/scaffold/templates.js +5 -0
  109. package/dist/scaffold/templates.js.map +1 -1
  110. package/dist/server/AgentServer.d.ts +8 -0
  111. package/dist/server/AgentServer.d.ts.map +1 -1
  112. package/dist/server/AgentServer.js +4 -0
  113. package/dist/server/AgentServer.js.map +1 -1
  114. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  115. package/dist/server/CapabilityIndex.js +14 -0
  116. package/dist/server/CapabilityIndex.js.map +1 -1
  117. package/dist/server/routes.d.ts +12 -0
  118. package/dist/server/routes.d.ts.map +1 -1
  119. package/dist/server/routes.js +91 -0
  120. package/dist/server/routes.js.map +1 -1
  121. package/package.json +1 -1
  122. package/src/data/builtin-manifest.json +65 -65
  123. package/src/scaffold/templates.ts +5 -0
  124. package/upgrades/1.3.91.md +54 -0
  125. package/upgrades/1.3.92.md +63 -0
  126. package/upgrades/side-effects/session-error-nudge-rearm.md +17 -0
  127. package/upgrades/side-effects/session-pool-capability-classification.md +16 -0
  128. package/upgrades/side-effects/session-pool-review-fixes.md +23 -0
  129. package/upgrades/side-effects/session-pool-track-a-router-lease.md +29 -0
  130. package/upgrades/side-effects/session-pool-track-b-agent-awareness.md +29 -0
  131. package/upgrades/side-effects/session-pool-track-b-nicknames.md +35 -0
  132. package/upgrades/side-effects/session-pool-track-b-pool-api.md +36 -0
  133. package/upgrades/side-effects/session-pool-track-b-registry.md +31 -0
  134. package/upgrades/side-effects/session-pool-track-b-wiring.md +39 -0
  135. package/upgrades/side-effects/session-pool-track-c-dispatcher.md +24 -0
  136. package/upgrades/side-effects/session-pool-track-c-meshrpc.md +35 -0
  137. package/upgrades/side-effects/session-pool-track-c-route-wiring.md +31 -0
  138. package/upgrades/side-effects/session-pool-track-d-ownership-fsm.md +31 -0
  139. package/upgrades/side-effects/session-pool-track-d-registry.md +27 -0
  140. package/upgrades/side-effects/session-pool-track-d-wiring.md +30 -0
  141. package/upgrades/side-effects/session-pool-track-e-boot-wiring.md +20 -0
  142. package/upgrades/side-effects/session-pool-track-e-placement-core.md +17 -0
  143. package/upgrades/side-effects/session-pool-track-e-router.md +23 -0
  144. package/upgrades/side-effects/session-pool-track-f-config.md +12 -0
  145. package/upgrades/side-effects/session-pool-track-f-handoff-core.md +17 -0
  146. package/upgrades/side-effects/session-pool-track-g-load-broker.md +16 -0
  147. package/upgrades/side-effects/session-pool-track-h-gate-wiring.md +17 -0
  148. package/upgrades/side-effects/session-pool-track-h-mesh-client.md +15 -0
  149. package/upgrades/side-effects/session-pool-track-h-rebalance.md +13 -0
  150. package/upgrades/side-effects/session-pool-track-h-rollout-gate.md +17 -0
  151. package/upgrades/side-effects/session-pool-track-h-stage-guard.md +16 -0
  152. package/upgrades/side-effects/transient-api-error-recovery-generalization.md +18 -0
@@ -0,0 +1,48 @@
1
+ /**
2
+ * RebalancePlanner — the pure Stage-3 load-rebalance decision (Multi-Machine Session
3
+ * Pool §L4 "Load-rebalance trigger conditions"). Given the machine capacities + the
4
+ * current session→machine assignments, it proposes a BOUNDED set of transfers off
5
+ * over-saturated machines. It is evaluated ONLY on the heartbeat interval by the
6
+ * caller (never per message), and is deliberately conservative to avoid a cascade:
7
+ *
8
+ * - A machine is a rebalance SOURCE only if its session ratio exceeds
9
+ * `rebalanceThresholdPercent` (default 0.85 of maxSessions).
10
+ * - Only NON-pinned, low-priority sessions that are off cool-down
11
+ * (`now - lastTransferredAt > placementCooldownMs`) are movable; a hard pin or a
12
+ * critical session is NEVER proactively rebalanced.
13
+ * - At most ONE move per source per cycle (capped overall by `maxMovesPerCycle`), and
14
+ * a working copy of capacities is updated as moves are proposed so the planner never
15
+ * piles every session onto one target.
16
+ * - The TARGET is chosen by the same `PlacementExecutor.decide(reason:'rebalance')`
17
+ * the router uses — a move is proposed only if it lands on a DIFFERENT, eligible
18
+ * machine. No move ⇒ empty result (rebalance never forces a churn).
19
+ *
20
+ * Pure over its inputs; the caller performs the actual transfers (TransferOrchestrator).
21
+ */
22
+ import type { PlacementExecutor, TopicPlacement } from './PlacementExecutor.js';
23
+ import type { MachineCapacity } from './types.js';
24
+ export interface RebalanceSession {
25
+ sessionKey: string;
26
+ ownerMachineId: string;
27
+ pinned?: boolean;
28
+ lowPriority?: boolean;
29
+ lastTransferredAt?: number;
30
+ topicMetadata?: TopicPlacement;
31
+ }
32
+ export interface RebalanceInput {
33
+ machines: MachineCapacity[];
34
+ sessions: RebalanceSession[];
35
+ rebalanceThresholdPercent: number;
36
+ placementCooldownMs: number;
37
+ now: number;
38
+ /** Hard cap on moves proposed per cycle (default = number of saturated sources). */
39
+ maxMovesPerCycle?: number;
40
+ }
41
+ export interface RebalanceMove {
42
+ sessionKey: string;
43
+ fromMachine: string;
44
+ toMachine: string;
45
+ reason: string;
46
+ }
47
+ export declare function planRebalance(input: RebalanceInput, placement: PlacementExecutor): RebalanceMove[];
48
+ //# sourceMappingURL=RebalancePlanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RebalancePlanner.d.ts","sourceRoot":"","sources":["../../src/core/RebalancePlanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,cAAc,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,yBAAyB,EAAE,MAAM,CAAC;IAClC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAMD,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,iBAAiB,GAAG,aAAa,EAAE,CA+ClG"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * RebalancePlanner — the pure Stage-3 load-rebalance decision (Multi-Machine Session
3
+ * Pool §L4 "Load-rebalance trigger conditions"). Given the machine capacities + the
4
+ * current session→machine assignments, it proposes a BOUNDED set of transfers off
5
+ * over-saturated machines. It is evaluated ONLY on the heartbeat interval by the
6
+ * caller (never per message), and is deliberately conservative to avoid a cascade:
7
+ *
8
+ * - A machine is a rebalance SOURCE only if its session ratio exceeds
9
+ * `rebalanceThresholdPercent` (default 0.85 of maxSessions).
10
+ * - Only NON-pinned, low-priority sessions that are off cool-down
11
+ * (`now - lastTransferredAt > placementCooldownMs`) are movable; a hard pin or a
12
+ * critical session is NEVER proactively rebalanced.
13
+ * - At most ONE move per source per cycle (capped overall by `maxMovesPerCycle`), and
14
+ * a working copy of capacities is updated as moves are proposed so the planner never
15
+ * piles every session onto one target.
16
+ * - The TARGET is chosen by the same `PlacementExecutor.decide(reason:'rebalance')`
17
+ * the router uses — a move is proposed only if it lands on a DIFFERENT, eligible
18
+ * machine. No move ⇒ empty result (rebalance never forces a churn).
19
+ *
20
+ * Pure over its inputs; the caller performs the actual transfers (TransferOrchestrator).
21
+ */
22
+ function sessionRatio(m) {
23
+ return m.maxSessions && m.maxSessions > 0 ? (m.activeSessionCount ?? 0) / m.maxSessions : 0;
24
+ }
25
+ export function planRebalance(input, placement) {
26
+ // Working copy of capacities (mutated as moves are proposed → no pile-on).
27
+ const caps = new Map(input.machines.map((m) => [m.machineId, { ...m }]));
28
+ const threshold = input.rebalanceThresholdPercent;
29
+ const saturated = (id) => {
30
+ const m = caps.get(id);
31
+ return !!m && m.online && sessionRatio(m) > threshold;
32
+ };
33
+ const sources = input.machines.filter((m) => saturated(m.machineId)).sort((a, b) => sessionRatio(caps.get(b.machineId)) - sessionRatio(caps.get(a.machineId)));
34
+ const cap = input.maxMovesPerCycle ?? sources.length;
35
+ const moves = [];
36
+ const movedSessions = new Set();
37
+ for (const src of sources) {
38
+ if (moves.length >= cap)
39
+ break;
40
+ if (!saturated(src.machineId))
41
+ continue; // a prior move may have relieved it
42
+ // Eligible movable sessions on this source.
43
+ const candidates = input.sessions.filter((s) => s.ownerMachineId === src.machineId &&
44
+ !movedSessions.has(s.sessionKey) &&
45
+ !s.pinned && !s.topicMetadata?.pinned &&
46
+ (s.lowPriority ?? true) &&
47
+ input.now - (s.lastTransferredAt ?? 0) > input.placementCooldownMs);
48
+ for (const s of candidates) {
49
+ // One move per source per cycle (cascade guard).
50
+ const decision = placement.decide({
51
+ sessionKey: s.sessionKey,
52
+ topicMetadata: s.topicMetadata ?? {},
53
+ machineRegistry: [...caps.values()],
54
+ currentOwner: undefined, // rebalance ignores stickiness
55
+ reason: 'rebalance',
56
+ });
57
+ if (decision.outcome === 'placed' && decision.chosenMachine && decision.chosenMachine !== src.machineId) {
58
+ moves.push({ sessionKey: s.sessionKey, fromMachine: src.machineId, toMachine: decision.chosenMachine, reason: 'load-rebalance' });
59
+ movedSessions.add(s.sessionKey);
60
+ // Update the working copy: source −1, target +1.
61
+ const from = caps.get(src.machineId);
62
+ const to = caps.get(decision.chosenMachine);
63
+ from.activeSessionCount = Math.max(0, (from.activeSessionCount ?? 0) - 1);
64
+ to.activeSessionCount = (to.activeSessionCount ?? 0) + 1;
65
+ break; // one move per source this cycle
66
+ }
67
+ }
68
+ }
69
+ return moves;
70
+ }
71
+ //# sourceMappingURL=RebalancePlanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RebalancePlanner.js","sourceRoot":"","sources":["../../src/core/RebalancePlanner.ts"],"names":[],"mappings":"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"}
@@ -36,6 +36,15 @@ import type { InputDetector } from '../monitoring/PromptGate.js';
36
36
  import type { Session, SessionManagerConfig, ModelTier } from './types.js';
37
37
  import type { IntelligenceFramework } from './intelligenceProviderFactory.js';
38
38
  import { StateManager } from './StateManager.js';
39
+ /**
40
+ * Pure gate for the post-API-error nudge (the 2026-05-29 re-arm fix). A session is
41
+ * nudged only when it has NOT already been nudged in the CURRENT idle episode
42
+ * (`armedThisEpisode` false) AND it is under the lifetime runaway cap. The episode
43
+ * flag is cleared on recovery, so a long-running session that hits a SECOND transient
44
+ * API error is nudged again — fixing the prior once-per-session-forever strand.
45
+ * Exported so the decision boundary is unit-testable without driving the tmux loop.
46
+ */
47
+ export declare function shouldErrorNudge(armedThisEpisode: boolean, totalNudges: number, max?: number): boolean;
39
48
  export interface SessionManagerEvents {
40
49
  sessionComplete: [session: Session];
41
50
  /**
@@ -87,10 +96,18 @@ export declare class SessionManager extends EventEmitter {
87
96
  /** Track pending Telegram injections awaiting agent response.
88
97
  * Key = tmuxSession name. Cleared when agent replies via /telegram/reply/:topicId. */
89
98
  private pendingInjections;
90
- /** Track sessions that have been nudged after an API error.
91
- * Key = session ID. Prevents infinite nudge loops — each session gets ONE nudge.
92
- * If it goes idle again after the nudge, the zombie detector kills it normally. */
99
+ /** Track sessions nudged after an API error in the CURRENT idle episode.
100
+ * Key = session ID. Set when we nudge; CLEARED when the session recovers (produces
101
+ * output / leaves idle), so the NEXT API-error episode in a long-running session
102
+ * gets its own nudge. (Before 2026-05-29 this was once-per-session-FOREVER — a long
103
+ * autonomous run that hit a SECOND transient API error was never re-nudged and
104
+ * silently stranded at the prompt. The runaway cap lives in errorNudgeTotal.) */
93
105
  private errorNudgedSessions;
106
+ /** Total error-nudges issued per session (never cleared until sessionComplete).
107
+ * Bounds runaway: even with per-episode re-arming, a session stuck in a tight
108
+ * error→nudge→error loop that never truly recovers stops being nudged after
109
+ * MAX_ERROR_NUDGES_PER_SESSION and falls through to the normal zombie-kill path. */
110
+ private errorNudgeTotal;
94
111
  /** Sessions where we've already retried Enter for stuck pasted text.
95
112
  * Key = session ID. Prevents infinite retry loops — one retry per session. */
96
113
  private pasteRetried;
@@ -1 +1 @@
1
- {"version":3,"file":"SessionManager.d.ts","sourceRoot":"","sources":["../../src/core/SessionManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SessionManager.d.ts","sourceRoot":"","sources":["../../src/core/SessionManager.ts"],"names":[],"mappings":"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"}
@@ -63,6 +63,23 @@ const TERMINAL_ERROR_PATTERNS = [
63
63
  'ETIMEDOUT',
64
64
  'fetch failed',
65
65
  ];
66
+ /** Runaway cap: max error-nudges per session across its whole lifetime, regardless of
67
+ * per-episode re-arming. A session that flaps error→nudge→error this many times has a
68
+ * persistent problem (not a transient API blip) and should fall through to zombie-kill
69
+ * rather than be nudged forever. Generous enough that a long autonomous run with
70
+ * genuinely-transient errors never hits it. */
71
+ const MAX_ERROR_NUDGES_PER_SESSION = 50;
72
+ /**
73
+ * Pure gate for the post-API-error nudge (the 2026-05-29 re-arm fix). A session is
74
+ * nudged only when it has NOT already been nudged in the CURRENT idle episode
75
+ * (`armedThisEpisode` false) AND it is under the lifetime runaway cap. The episode
76
+ * flag is cleared on recovery, so a long-running session that hits a SECOND transient
77
+ * API error is nudged again — fixing the prior once-per-session-forever strand.
78
+ * Exported so the decision boundary is unit-testable without driving the tmux loop.
79
+ */
80
+ export function shouldErrorNudge(armedThisEpisode, totalNudges, max = MAX_ERROR_NUDGES_PER_SESSION) {
81
+ return !armedThisEpisode && totalNudges < max;
82
+ }
66
83
  /**
67
84
  * Process names that are always running in a Claude Code session (MCP servers, etc.)
68
85
  * These do NOT indicate activity — they're background infrastructure.
@@ -121,10 +138,18 @@ export class SessionManager extends EventEmitter {
121
138
  /** Track pending Telegram injections awaiting agent response.
122
139
  * Key = tmuxSession name. Cleared when agent replies via /telegram/reply/:topicId. */
123
140
  pendingInjections = new Map();
124
- /** Track sessions that have been nudged after an API error.
125
- * Key = session ID. Prevents infinite nudge loops — each session gets ONE nudge.
126
- * If it goes idle again after the nudge, the zombie detector kills it normally. */
141
+ /** Track sessions nudged after an API error in the CURRENT idle episode.
142
+ * Key = session ID. Set when we nudge; CLEARED when the session recovers (produces
143
+ * output / leaves idle), so the NEXT API-error episode in a long-running session
144
+ * gets its own nudge. (Before 2026-05-29 this was once-per-session-FOREVER — a long
145
+ * autonomous run that hit a SECOND transient API error was never re-nudged and
146
+ * silently stranded at the prompt. The runaway cap lives in errorNudgeTotal.) */
127
147
  errorNudgedSessions = new Set();
148
+ /** Total error-nudges issued per session (never cleared until sessionComplete).
149
+ * Bounds runaway: even with per-episode re-arming, a session stuck in a tight
150
+ * error→nudge→error loop that never truly recovers stops being nudged after
151
+ * MAX_ERROR_NUDGES_PER_SESSION and falls through to the normal zombie-kill path. */
152
+ errorNudgeTotal = new Map();
128
153
  /** Sessions where we've already retried Enter for stuck pasted text.
129
154
  * Key = session ID. Prevents infinite retry loops — one retry per session. */
130
155
  pasteRetried = new Set();
@@ -361,6 +386,7 @@ rm() { "${shimRunner}" rm "$@"; }
361
386
  detector.cleanup(session.tmuxSession);
362
387
  this.relayLeases.delete(session.id);
363
388
  this.errorNudgedSessions.delete(session.id);
389
+ this.errorNudgeTotal.delete(session.id);
364
390
  this.pasteRetried.delete(session.id);
365
391
  });
366
392
  }
@@ -745,7 +771,8 @@ rm() { "${shimRunner}" rm "$@"; }
745
771
  // ── Error nudge: on first idle detection, check terminal for API errors ──
746
772
  // If the session went idle because of an API error (not a natural stop),
747
773
  // inject a nudge to get it working again instead of waiting 15m to kill.
748
- if (!this.errorNudgedSessions.has(session.id)) {
774
+ const nudgeTotal = this.errorNudgeTotal.get(session.id) ?? 0;
775
+ if (shouldErrorNudge(this.errorNudgedSessions.has(session.id), nudgeTotal)) {
749
776
  const recentOutput = this.captureOutput(session.tmuxSession, 30);
750
777
  if (recentOutput) {
751
778
  // Server-side throttle ("Server is temporarily limiting
@@ -762,8 +789,24 @@ rm() { "${shimRunner}" rm "$@"; }
762
789
  }
763
790
  const hasError = TERMINAL_ERROR_PATTERNS.some(p => recentOutput.includes(p));
764
791
  if (hasError) {
792
+ // Arm the per-episode guard (re-armed on recovery — see the
793
+ // "Session is active" branch). Prevents per-tick re-emit/re-nudge.
765
794
  this.errorNudgedSessions.add(session.id);
766
- console.log(`[SessionManager] Session "${session.name}" idle after API error — nudging to continue.`);
795
+ // If a recovery sentinel owns the generic transient-API-error class
796
+ // (production wiring), hand off to its backoff→verify→escalate
797
+ // lifecycle rather than an immediate retry that could re-hit a
798
+ // still-down API. The sentinel owns the retry budget + is re-armable
799
+ // across episodes by design. (Mirrors the rate-limit handoff above;
800
+ // generalizes that proven recovery to the whole transient-API class.)
801
+ if (this.listenerCount('apiErrorAtIdle') > 0) {
802
+ this.emit('apiErrorAtIdle', session.tmuxSession);
803
+ this.idlePromptSince.delete(session.id);
804
+ continue; // Skip to next session — sentinel owns recovery.
805
+ }
806
+ // Fallback (no sentinel wired, e.g. bare/test): the re-armable
807
+ // immediate nudge, bounded by the lifetime cap.
808
+ this.errorNudgeTotal.set(session.id, nudgeTotal + 1);
809
+ console.log(`[SessionManager] Session "${session.name}" idle after API error — nudging to continue (nudge #${nudgeTotal + 1} this session).`);
767
810
  this.sendInput(session.tmuxSession, 'You hit an API error. Please continue your work — skip or work around the action that failed.');
768
811
  this.idlePromptSince.delete(session.id); // Reset idle timer
769
812
  continue; // Skip to next session
@@ -815,8 +858,13 @@ rm() { "${shimRunner}" rm "$@"; }
815
858
  }
816
859
  }
817
860
  else {
818
- // Session is active — clear idle tracker
861
+ // Session is active — clear idle tracker AND re-arm the error nudge.
862
+ // The session producing output means the prior idle episode is over (the
863
+ // nudge worked, or the error cleared), so a FUTURE API-error episode in
864
+ // this same long-running session deserves its own nudge. (errorNudgeTotal
865
+ // is NOT cleared here — it's the lifetime runaway cap.)
819
866
  this.idlePromptSince.delete(session.id);
867
+ this.errorNudgedSessions.delete(session.id);
820
868
  }
821
869
  }
822
870
  }