instar 1.3.61 → 1.3.63

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 (73) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +176 -10
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  5. package/dist/config/ConfigDefaults.js +36 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  8. package/dist/core/PostUpdateMigrator.js +45 -0
  9. package/dist/core/PostUpdateMigrator.js.map +1 -1
  10. package/dist/core/ReapGuard.d.ts +79 -0
  11. package/dist/core/ReapGuard.d.ts.map +1 -0
  12. package/dist/core/ReapGuard.js +114 -0
  13. package/dist/core/ReapGuard.js.map +1 -0
  14. package/dist/core/SessionLivenessOracle.d.ts +104 -0
  15. package/dist/core/SessionLivenessOracle.d.ts.map +1 -0
  16. package/dist/core/SessionLivenessOracle.js +201 -0
  17. package/dist/core/SessionLivenessOracle.js.map +1 -0
  18. package/dist/core/SessionManager.d.ts +90 -10
  19. package/dist/core/SessionManager.d.ts.map +1 -1
  20. package/dist/core/SessionManager.js +200 -40
  21. package/dist/core/SessionManager.js.map +1 -1
  22. package/dist/core/SessionRefresh.d.ts +10 -0
  23. package/dist/core/SessionRefresh.d.ts.map +1 -1
  24. package/dist/core/SessionRefresh.js +12 -2
  25. package/dist/core/SessionRefresh.js.map +1 -1
  26. package/dist/core/types.d.ts +70 -0
  27. package/dist/core/types.d.ts.map +1 -1
  28. package/dist/core/types.js.map +1 -1
  29. package/dist/monitoring/ContextWedgeSentinel.d.ts +118 -0
  30. package/dist/monitoring/ContextWedgeSentinel.d.ts.map +1 -0
  31. package/dist/monitoring/ContextWedgeSentinel.js +238 -0
  32. package/dist/monitoring/ContextWedgeSentinel.js.map +1 -0
  33. package/dist/monitoring/ReapLog.d.ts +51 -0
  34. package/dist/monitoring/ReapLog.d.ts.map +1 -0
  35. package/dist/monitoring/ReapLog.js +82 -0
  36. package/dist/monitoring/ReapLog.js.map +1 -0
  37. package/dist/monitoring/ReapNotifier.d.ts +66 -0
  38. package/dist/monitoring/ReapNotifier.d.ts.map +1 -0
  39. package/dist/monitoring/ReapNotifier.js +112 -0
  40. package/dist/monitoring/ReapNotifier.js.map +1 -0
  41. package/dist/monitoring/SentinelNotifier.d.ts +1 -1
  42. package/dist/monitoring/SentinelNotifier.d.ts.map +1 -1
  43. package/dist/monitoring/SentinelNotifier.js.map +1 -1
  44. package/dist/monitoring/SessionReaper.d.ts +4 -0
  45. package/dist/monitoring/SessionReaper.d.ts.map +1 -1
  46. package/dist/monitoring/SessionReaper.js +19 -42
  47. package/dist/monitoring/SessionReaper.js.map +1 -1
  48. package/dist/monitoring/StaleSessionBackstop.d.ts +89 -0
  49. package/dist/monitoring/StaleSessionBackstop.d.ts.map +1 -0
  50. package/dist/monitoring/StaleSessionBackstop.js +176 -0
  51. package/dist/monitoring/StaleSessionBackstop.js.map +1 -0
  52. package/dist/monitoring/sentinelWiring.d.ts +23 -0
  53. package/dist/monitoring/sentinelWiring.d.ts.map +1 -1
  54. package/dist/monitoring/sentinelWiring.js +36 -0
  55. package/dist/monitoring/sentinelWiring.js.map +1 -1
  56. package/dist/scaffold/templates.d.ts.map +1 -1
  57. package/dist/scaffold/templates.js +5 -0
  58. package/dist/scaffold/templates.js.map +1 -1
  59. package/dist/server/AgentServer.d.ts +3 -0
  60. package/dist/server/AgentServer.d.ts.map +1 -1
  61. package/dist/server/AgentServer.js +1 -0
  62. package/dist/server/AgentServer.js.map +1 -1
  63. package/dist/server/routes.d.ts +1 -0
  64. package/dist/server/routes.d.ts.map +1 -1
  65. package/dist/server/routes.js +33 -11
  66. package/dist/server/routes.js.map +1 -1
  67. package/package.json +1 -1
  68. package/src/data/builtin-manifest.json +64 -64
  69. package/src/scaffold/templates.ts +5 -0
  70. package/upgrades/1.3.62.md +87 -0
  71. package/upgrades/1.3.63.md +87 -0
  72. package/upgrades/side-effects/context-wedge-sentinel.md +69 -0
  73. package/upgrades/side-effects/unified-session-lifecycle-robustness.md +241 -0
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA+RH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAksDD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA0uNtE;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"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA+RH,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAksDD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAi6NtE;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"}
@@ -3880,6 +3880,54 @@ export async function startServer(options) {
3880
3880
  // WorkingMemoryAssembler is initialized after activitySentinel (see below)
3881
3881
  // so it can wire episodicMemory from the sentinel.
3882
3882
  let workingMemory;
3883
+ // ── Reap observability + notify (UNIFIED-SESSION-LIFECYCLE §P3/§P4) ──
3884
+ // Wired BEFORE the boot purge so even boot-time reaps land in the reap-log
3885
+ // and surface a notice. The awake-checker is also wired here so the boot
3886
+ // purge is lease-gated (a standby never reaps another machine's sessions).
3887
+ // (The KEEP-guard is wired later, once its tracker deps exist — that is safe:
3888
+ // the boot purge passes knownDead and bypasses the guard, and the only other
3889
+ // guard consumers (monitorTick #2 age-limit / #3 idle-zombie) cannot fire a
3890
+ // kill in the first monitoring seconds — they require multi-hour age or 15+m
3891
+ // of observed idle — long after the guard is set below.)
3892
+ const { ReapLog } = await import('../monitoring/ReapLog.js');
3893
+ const { ReapNotifier } = await import('../monitoring/ReapNotifier.js');
3894
+ const reapLog = new ReapLog(config.stateDir, () => (coordinator.enabled ? coordinator.identity?.machineId : undefined));
3895
+ const reapNotifier = new ReapNotifier({
3896
+ resolveTopic: (tmuxSession) => {
3897
+ const t = telegram?.getTopicForSession(tmuxSession);
3898
+ if (t == null)
3899
+ return null;
3900
+ const n = typeof t === 'number' ? t : Number(t);
3901
+ return Number.isFinite(n) ? n : null;
3902
+ },
3903
+ lifelineTopic: () => telegram?.getLifelineTopicId() ?? null,
3904
+ // SUMMARY tier → through the formatter/tone-gate (HTML-escaped, quiet-hours
3905
+ // aware). The notifier already coalesces, so a burst is one message.
3906
+ send: (topicId, text) => notify('SUMMARY', 'session-reap', text, topicId),
3907
+ }, {
3908
+ enabled: config.monitoring?.reapNotify?.enabled ?? true,
3909
+ coalesceWindowMs: config.monitoring?.reapNotify?.coalesceWindowMs ?? 60_000,
3910
+ });
3911
+ sessionManager.setAwakeChecker(() => !coordinator.enabled || coordinator.isAwake);
3912
+ sessionManager.on('sessionReaped', (e) => {
3913
+ reapLog.recordReaped({
3914
+ session: e.session.name,
3915
+ tmuxSession: e.session.tmuxSession,
3916
+ reason: e.reason,
3917
+ disposition: e.disposition,
3918
+ origin: e.origin,
3919
+ });
3920
+ reapNotifier.onReaped({ session: e.session, reason: e.reason, disposition: e.disposition, origin: e.origin });
3921
+ });
3922
+ sessionManager.on('reapBlocked', (e) => {
3923
+ reapLog.recordSkipped({
3924
+ session: e.session.name,
3925
+ tmuxSession: e.session.tmuxSession,
3926
+ reason: e.reason,
3927
+ skipped: e.skipped,
3928
+ origin: e.origin,
3929
+ });
3930
+ });
3883
3931
  // Fast startup purge — remove session records for dead tmux sessions BEFORE
3884
3932
  // monitoring starts. Prevents the death spiral where stale sessions overwhelm
3885
3933
  // the health endpoint (synchronous tmux has-session calls) and cause the
@@ -5178,10 +5226,12 @@ export async function startServer(options) {
5178
5226
  // replace"). undefined when the corresponding sentinel is disabled.
5179
5227
  let socketRecoveryActive;
5180
5228
  let silenceRecoveryActive;
5229
+ let wedgeRecoveryActive;
5181
5230
  {
5182
5231
  const { SocketDisconnectSentinel } = await import('../monitoring/SocketDisconnectSentinel.js');
5183
5232
  const { ActiveWorkSilenceSentinel } = await import('../monitoring/ActiveWorkSilenceSentinel.js');
5184
- const { buildSocketDisconnectDeps, buildActiveWorkSilenceDeps, OutputActivityTracker, } = await import('../monitoring/sentinelWiring.js');
5233
+ const { ContextWedgeSentinel } = await import('../monitoring/ContextWedgeSentinel.js');
5234
+ const { buildSocketDisconnectDeps, buildActiveWorkSilenceDeps, buildContextWedgeDeps, OutputActivityTracker, } = await import('../monitoring/sentinelWiring.js');
5185
5235
  const { SentinelNotifier } = await import('../monitoring/SentinelNotifier.js');
5186
5236
  const sessionSurface = {
5187
5237
  captureOutput: (s, lines) => sessionManager.captureOutput(s, lines),
@@ -5249,6 +5299,45 @@ export async function startServer(options) {
5249
5299
  ? ' ActiveWorkSilenceSentinel enabled (silent-freeze watchdog — Telegram escalation ON, consolidated)'
5250
5300
  : ' ActiveWorkSilenceSentinel enabled (silent-freeze watchdog — logs only, Telegram escalation OFF)'));
5251
5301
  }
5302
+ // ── ContextWedgeSentinel — thinking-block-400 fast-fail wedge ──
5303
+ // Detection + audit ship default-ON (harmless housekeeping). The
5304
+ // destructive fresh-respawn is gated by autoRecovery (default OFF +
5305
+ // dryRun) and rides the Graduated Feature Rollout track. freshRespawn is
5306
+ // late-bound to _sessionRefresh (assigned later in boot) and only invoked
5307
+ // at recovery time; it uses fresh-mode so the new session never --resume-s
5308
+ // the corrupted transcript. Spec: docs/specs/context-wedge-sentinel.md.
5309
+ const wedgeCfg = config.monitoring?.contextWedgeSentinel ?? { enabled: true };
5310
+ if (wedgeCfg.enabled !== false) {
5311
+ const autoRecovery = wedgeCfg.autoRecovery ?? { enabled: false, dryRun: true };
5312
+ const wedgeSentinel = new ContextWedgeSentinel(buildContextWedgeDeps({
5313
+ sessions: sessionSurface,
5314
+ escalate: (name, text) => notifier.escalate('context-wedge', name, text),
5315
+ autoRecovery,
5316
+ freshRespawn: async (name) => {
5317
+ if (!_sessionRefresh)
5318
+ return false;
5319
+ const result = await _sessionRefresh.refreshSession({
5320
+ sessionName: name,
5321
+ fresh: true,
5322
+ reason: 'context-wedge-400',
5323
+ });
5324
+ return result.ok;
5325
+ },
5326
+ }), {
5327
+ enabled: wedgeCfg.enabled,
5328
+ tickIntervalMs: wedgeCfg.tickIntervalMs,
5329
+ confirmWindowMs: wedgeCfg.confirmWindowMs,
5330
+ });
5331
+ wedgeSentinel.on('detected', (e) => notifier.record('detected', 'context-wedge', e.sessionName));
5332
+ wedgeSentinel.on('recovered', (e) => notifier.record('recovered', 'context-wedge', e.sessionName, 'fresh respawn'));
5333
+ wedgeSentinel.on('dry-run', (e) => notifier.record('dry-run', 'context-wedge', e.sessionName, 'would fresh-respawn'));
5334
+ wedgeSentinel.on('false-alarm', (e) => notifier.record('false-alarm', 'context-wedge', e.sessionName, 'signature scrolled out of tail'));
5335
+ wedgeSentinel.on('recovery-error', (e) => notifier.record('recovery-error', 'context-wedge', e.sessionName, e.err instanceof Error ? e.err.message : String(e.err)));
5336
+ wedgeSentinel.start();
5337
+ wedgeRecoveryActive = (s) => wedgeSentinel.isRecoveryActive(s);
5338
+ const mode = autoRecovery.enabled ? (autoRecovery.dryRun ? 'auto-recover dry-run' : 'auto-recover LIVE') : 'detect-only';
5339
+ console.log(pc.green(` ContextWedgeSentinel enabled (thinking-block-400 wedge — ${mode})`));
5340
+ }
5252
5341
  }
5253
5342
  // Recompose the zombie-kill veto to include ALL four recovery sentinels now
5254
5343
  // that socket + silence exist (the interim set above covered only compaction
@@ -5259,7 +5348,8 @@ export async function startServer(options) {
5259
5348
  const composedRecoveryActive = (session) => compactionSentinel.isRecoveryActive(session.tmuxSession) ||
5260
5349
  rateLimitSentinel.isRecoveryActive(session.tmuxSession) ||
5261
5350
  (socketRecoveryActive?.(session.tmuxSession) ?? false) ||
5262
- (silenceRecoveryActive?.(session.tmuxSession) ?? false);
5351
+ (silenceRecoveryActive?.(session.tmuxSession) ?? false) ||
5352
+ (wedgeRecoveryActive?.(session.tmuxSession) ?? false);
5263
5353
  sessionManager.setActiveRecoveryChecker(composedRecoveryActive);
5264
5354
  // Trigger 1: PreCompact hook event — report to sentinel.
5265
5355
  hookEventReceiver.on('PreCompact', () => {
@@ -7679,14 +7769,15 @@ export async function startServer(options) {
7679
7769
  const n = typeof t === 'number' ? t : Number(t);
7680
7770
  return Number.isFinite(n) ? n : null;
7681
7771
  };
7682
- const sessionReaper = new SessionReaper({
7683
- listRunningSessions: () => sessionManager.listRunningSessions(),
7684
- captureOutput: (s, n) => sessionManager.captureOutput(s, n) ?? '',
7685
- hasActiveProcesses: (s) => sessionManager.hasActiveProcesses(s),
7686
- frameworkForSession: (s) => sessionManager.frameworkForSession(s),
7772
+ // Shared stateless KEEP-guard deps (UNIFIED-SESSION-LIFECYCLE §P2). Built
7773
+ // once here and used to back BOTH the SessionReaper and the ReapAuthority's
7774
+ // guard (`sessionManager.setReapGuard`), so a killer cannot end a session the
7775
+ // reaper would have kept — the same chain protects every kill path.
7776
+ const reapGuardDeps = {
7777
+ protectedSessions: () => sessionManager.getProtectedSessions(),
7687
7778
  isRecoveryActive: (session) => composedRecoveryActive(session),
7688
- isRelayLeaseActive: (id) => sessionManager.isRelayLeaseActive(id),
7689
7779
  hasPendingInjection: (s) => sessionManager.getPendingInjection(s) != null,
7780
+ isRelayLeaseActive: (id) => sessionManager.isRelayLeaseActive(id),
7690
7781
  topicBinding: _resolveTopic,
7691
7782
  // Gate I is a v1 stub (returns false): active conversation is already
7692
7783
  // covered by the relay-lease + pending-injection gates and by render
@@ -7723,7 +7814,23 @@ export async function startServer(options) {
7723
7814
  return true;
7724
7815
  return fresh(path.join(config.stateDir, 'state', 'build', 'build-state.json'));
7725
7816
  },
7726
- protectedSessions: () => sessionManager.getProtectedSessions(),
7817
+ hasActiveProcesses: (s) => sessionManager.hasActiveProcesses(s),
7818
+ };
7819
+ // Wire the ReapAuthority's KEEP-guard. minAgeMs:0 disables spawn-grace here —
7820
+ // the killers that consult this guard (age-limit #2, idle-zombie #3) already
7821
+ // gate on their own age/idle thresholds, so the reaper-specific spawn-grace
7822
+ // would otherwise delay legitimate zombie kills for young-but-stuck sessions.
7823
+ {
7824
+ const { ReapGuard } = await import('../core/ReapGuard.js');
7825
+ sessionManager.setReapGuard(new ReapGuard(reapGuardDeps, { minAgeMs: 0 }));
7826
+ }
7827
+ // (setAwakeChecker is wired earlier, before the boot purge, so the purge is
7828
+ // lease-gated — see the §P3/§P4 block above.)
7829
+ const sessionReaper = new SessionReaper({
7830
+ ...reapGuardDeps,
7831
+ listRunningSessions: () => sessionManager.listRunningSessions(),
7832
+ captureOutput: (s, n) => sessionManager.captureOutput(s, n) ?? '',
7833
+ frameworkForSession: (s) => sessionManager.frameworkForSession(s),
7727
7834
  pressure: () => {
7728
7835
  const total = _os.totalmem();
7729
7836
  const freePct = total > 0 ? (_os.freemem() / total) * 100 : 100;
@@ -7736,6 +7843,65 @@ export async function startServer(options) {
7736
7843
  audit: fileAuditSink(config.stateDir),
7737
7844
  }, config.monitoring?.sessionReaper);
7738
7845
  sessionReaper.start();
7846
+ // ── Unkillability backstop (UNIFIED-SESSION-LIFECYCLE §P5) ───────────────
7847
+ // Signal-only: raises ONE deduped Attention item (never auto-kills) when a
7848
+ // session is KEPT forever despite faking work, or is stuck indeterminate.
7849
+ {
7850
+ const { StaleSessionBackstop } = await import('../monitoring/StaleSessionBackstop.js');
7851
+ const { probeTranscript } = await import('../monitoring/transcriptProber.js');
7852
+ const { makeAttentionPoster } = await import('../monitoring/sentinelWiring.js');
7853
+ const _crypto = await import('node:crypto');
7854
+ const staleCfg = config.monitoring?.staleBackstop ?? {};
7855
+ const progressFloorBytes = staleCfg.progressFloorBytes ?? 512;
7856
+ const hash = (s) => _crypto.createHash('sha1').update(s).digest('hex').slice(0, 16);
7857
+ const backstop = new StaleSessionBackstop({
7858
+ listRunningSessions: () => sessionManager.listRunningSessions(),
7859
+ probeLiveness: (names) => sessionManager.probeLivenessBatch(names),
7860
+ snapshot: (session) => {
7861
+ const framework = session.framework ?? sessionManager.frameworkForSession(session.tmuxSession) ?? 'claude-code';
7862
+ const sessionId = framework === 'claude-code' ? (session.claudeSessionId ?? '') : '';
7863
+ const tp = probeTranscript({ framework, sessionId, projectDir: '' });
7864
+ // Tail hash: read the last progressFloorBytes so a heartbeat-byte append
7865
+ // (same tail) is NOT counted as a meaningful advance.
7866
+ let tailHash = null;
7867
+ if (tp.resolved && tp.path) {
7868
+ try {
7869
+ const fd = fs.openSync(tp.path, 'r');
7870
+ try {
7871
+ const start = Math.max(0, tp.size - progressFloorBytes);
7872
+ const len = tp.size - start;
7873
+ const buf = Buffer.alloc(len);
7874
+ fs.readSync(fd, buf, 0, len, start);
7875
+ tailHash = hash(buf.toString('utf-8'));
7876
+ }
7877
+ finally {
7878
+ fs.closeSync(fd);
7879
+ }
7880
+ }
7881
+ catch {
7882
+ // @silent-fallback-ok — an unreadable transcript tail just means
7883
+ // "no meaningful-advance signal this tick"; the backstop treats a
7884
+ // null tail as ambiguous (never as progress), which is safe.
7885
+ tailHash = null;
7886
+ }
7887
+ }
7888
+ const frame = sessionManager.captureOutput(session.tmuxSession, 8) ?? '';
7889
+ return {
7890
+ transcriptResolved: tp.resolved,
7891
+ transcriptSize: tp.size,
7892
+ transcriptTailHash: tailHash,
7893
+ mainProcessActive: sessionManager.hasActiveProcesses(session.tmuxSession),
7894
+ idleStateToken: hash(frame),
7895
+ };
7896
+ },
7897
+ raiseAttention: makeAttentionPoster({ port: config.port, authToken: config.authToken ?? '' }),
7898
+ setLongIndeterminate: (id, isLong) => sessionManager.markLongIndeterminate(id, isLong),
7899
+ }, staleCfg);
7900
+ backstop.start();
7901
+ if (staleCfg.enabled !== false) {
7902
+ console.log(pc.green(' Unkillability backstop enabled (§P5 — signal-only, never auto-kills)'));
7903
+ }
7904
+ }
7739
7905
  if (config.monitoring?.sessionReaper?.enabled) {
7740
7906
  console.log(pc.green(config.monitoring.sessionReaper.dryRun === false
7741
7907
  ? ' SessionReaper enabled (idle-session reaper — LIVE)'
@@ -7888,7 +8054,7 @@ export async function startServer(options) {
7888
8054
  }
7889
8055
  }
7890
8056
  }
7891
- const server = new AgentServer({ config, sessionManager, state, scheduler, telegram, relationships, feedback, feedbackAnomalyDetector, dispatches, updateChecker, autoUpdater, autoDispatcher, quotaTracker, quotaManager, publisher, viewer, tunnel, evolution, watchdog, topicMemory, triageNurse, projectMapper, coherenceGate: scopeVerifier, contextHierarchy, canonicalState, operationGate, sentinel, adaptiveTrust, memoryMonitor, orphanReaper, coherenceMonitor, commitmentTracker, semanticMemory, activitySentinel, rateLimitSentinel, releaseReadinessSentinel: releaseReadinessSentinel ?? undefined, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, sessionRefresh: _sessionRefresh ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, localSigningKeyPem, leaseTransport, liveTailReceiver, handoffWireTransport, onHandoffBegin, onHandoffInitiate: handoffInitiate, handoffInProgress: handoffSentinelInProgress, messageLedger, currentInboundByTopic, replyMarkerTransport, onReplyMarker: messageLedger ? (marker) => { const m = marker; messageLedger.applyRemoteReplyMarker(m.dedupeKey, { platform: m.platform, replyIdempotencyKey: m.replyIdempotencyKey, epoch: m.epoch, topic: m.topic ?? null }); } : undefined, whatsapp: whatsappAdapter, slack: slackAdapter, imessage: imessageAdapter, whatsappBusinessBackend, messageBridge, hookEventReceiver, worktreeMonitor, subagentTracker, instructionsVerifier, handshakeManager: threadlineHandshake, threadlineRouter, conversationStore, warrantsReplyGate, collaborationSurfacer, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, responseReviewGate, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, proxyCoordinator, topicIntentStore, topicIntentArcCheck, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, briefDeps, workingMemory, taskFlowRegistry, threadlineFlowBridge, sessionReaper, unjustifiedStopGate, stopGateDb, stopNotifier });
8057
+ const server = new AgentServer({ config, sessionManager, state, scheduler, telegram, relationships, feedback, feedbackAnomalyDetector, dispatches, updateChecker, autoUpdater, autoDispatcher, quotaTracker, quotaManager, publisher, viewer, tunnel, evolution, watchdog, topicMemory, triageNurse, projectMapper, coherenceGate: scopeVerifier, contextHierarchy, canonicalState, operationGate, sentinel, adaptiveTrust, memoryMonitor, orphanReaper, coherenceMonitor, commitmentTracker, semanticMemory, activitySentinel, rateLimitSentinel, releaseReadinessSentinel: releaseReadinessSentinel ?? undefined, messageRouter, summarySentinel, spawnManager, systemReviewer, capabilityMapper, selfKnowledgeTree, coverageAuditor, topicResumeMap: _topicResumeMap ?? undefined, sessionRefresh: _sessionRefresh ?? undefined, autonomyManager, trustElevationTracker, autonomousEvolution, coordinator: coordinator.enabled ? coordinator : undefined, localSigningKeyPem, leaseTransport, liveTailReceiver, handoffWireTransport, onHandoffBegin, onHandoffInitiate: handoffInitiate, handoffInProgress: handoffSentinelInProgress, messageLedger, currentInboundByTopic, replyMarkerTransport, onReplyMarker: messageLedger ? (marker) => { const m = marker; messageLedger.applyRemoteReplyMarker(m.dedupeKey, { platform: m.platform, replyIdempotencyKey: m.replyIdempotencyKey, epoch: m.epoch, topic: m.topic ?? null }); } : undefined, whatsapp: whatsappAdapter, slack: slackAdapter, imessage: imessageAdapter, whatsappBusinessBackend, messageBridge, hookEventReceiver, worktreeMonitor, subagentTracker, instructionsVerifier, handshakeManager: threadlineHandshake, threadlineRouter, conversationStore, warrantsReplyGate, collaborationSurfacer, threadResumeMap, topicLinkageHandler: topicLinkageHandler ?? undefined, threadlineRelayClient, threadlineReplyWaiters, listenerManager: listenerManager ?? undefined, responseReviewGate, messagingToneGate, outboundDedupGate, telemetryHeartbeat, pasteManager, featureRegistry, discoveryEvaluator, completionEvaluator, unifiedTrust, liveConfig, sharedStateLedger, ledgerSessionRegistry, worktreeManager, oidcEnrolledRepos: parallelDevConfig?.oidcEnrolledRepos, initiativeTracker, projectRoundRunner, projectDriftChecker, machineHeartbeat, proxyCoordinator, topicIntentStore, topicIntentArcCheck, usherSignalStore, intelligence: sharedIntelligence ?? undefined, telegramBridgeConfig, telegramBridge: telegramBridge ?? undefined, threadlineObservability, briefDeps, workingMemory, taskFlowRegistry, threadlineFlowBridge, sessionReaper, reapLog, unjustifiedStopGate, stopGateDb, stopNotifier });
7892
8058
  // Boot-recovery (tunnel-failure-resilience spec Part 6): if the agent
7893
8059
  // died mid-relay-episode, the persisted tunnel.json carries
7894
8060
  // rotationPending=true. Rotate the dashboard PIN + authToken BEFORE