@songsid/agend 2.1.0-beta.7 → 2.1.0-beta.8

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.
@@ -18,6 +18,8 @@ export declare class ContextGuardian extends EventEmitter {
18
18
  private logger;
19
19
  private statusFilePath;
20
20
  private consecutiveReadFailures;
21
+ private watching;
22
+ private readonly onStatusFileChange;
21
23
  constructor(_config: GuardianConfig, logger: Logger, statusFilePath: string);
22
24
  startWatching(): void;
23
25
  private readAndCheck;
@@ -16,6 +16,8 @@ export class ContextGuardian extends EventEmitter {
16
16
  logger;
17
17
  statusFilePath;
18
18
  consecutiveReadFailures = 0;
19
+ watching = false;
20
+ onStatusFileChange = () => this.readAndCheck();
19
21
  constructor(_config, logger, statusFilePath) {
20
22
  super();
21
23
  this._config = _config;
@@ -23,8 +25,11 @@ export class ContextGuardian extends EventEmitter {
23
25
  this.statusFilePath = statusFilePath;
24
26
  }
25
27
  startWatching() {
28
+ if (this.watching)
29
+ return;
30
+ this.watching = true;
26
31
  this.logger.debug({ path: this.statusFilePath }, "Watching status line file");
27
- watchFile(this.statusFilePath, { interval: 2000 }, () => this.readAndCheck());
32
+ watchFile(this.statusFilePath, { interval: 2000 }, this.onStatusFileChange);
28
33
  }
29
34
  readAndCheck() {
30
35
  try {
@@ -67,7 +72,10 @@ export class ContextGuardian extends EventEmitter {
67
72
  }
68
73
  }
69
74
  stop() {
70
- unwatchFile(this.statusFilePath);
75
+ if (!this.watching)
76
+ return;
77
+ unwatchFile(this.statusFilePath, this.onStatusFileChange);
78
+ this.watching = false;
71
79
  }
72
80
  }
73
81
  //# sourceMappingURL=context-guardian.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context-guardian.js","sourceRoot":"","sources":["../src/context-guardian.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAM3E;;;;;;;;;;GAUG;AACH,MAAM,OAAO,eAAgB,SAAQ,YAAY;IAKrC;IACA;IALF,cAAc,CAAS;IACvB,uBAAuB,GAAG,CAAC,CAAC;IAEpC,YACU,OAAuB,EACvB,MAAc,EACtB,cAAsB;QAEtB,KAAK,EAAE,CAAC;QAJA,YAAO,GAAP,OAAO,CAAgB;QACvB,WAAM,GAAN,MAAM,CAAQ;QAItB,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACvC,CAAC;IAED,aAAa;QACX,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,EAAE,2BAA2B,CAAC,CAAC;QAC9E,SAAS,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;IAChF,CAAC;IAEO,YAAY;QAClB,IAAI,CAAC;YACH,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC;gBAAE,OAAO;YAC7C,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;YACvD,MAAM,IAAI,GAAmB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC7C,MAAM,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC;YAE/B,IAAI,EAAE,CAAC,eAAe,IAAI,IAAI,EAAE,CAAC;gBAC/B,IAAI,CAAC,uBAAuB,GAAG,CAAC,CAAC;gBACjC,MAAM,MAAM,GAAkB;oBAC5B,eAAe,EAAE,EAAE,CAAC,eAAe;oBACnC,oBAAoB,EAAE,EAAE,CAAC,oBAAoB,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,eAAe,CAAC;oBAC3E,mBAAmB,EAAE,EAAE,CAAC,mBAAmB;iBAC5C,CAAC;gBACF,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC;gBAC5B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;oBAChB,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,GAAG;oBACjC,IAAI,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;oBAC/C,OAAO,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC,KAAK;oBACnE,OAAO,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,eAAe,GAAG,CAAC,CAAC,CAAC,KAAK;iBACpE,EAAE,wBAAwB,CAAC,CAAC;gBAC7B,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,GAAG,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;YAC7D,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,uBAAuB,EAAE,CAAC;gBAC/B,IAAI,IAAI,CAAC,uBAAuB,IAAI,CAAC,EAAE,CAAC;oBACtC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,mBAAmB,EAAE,IAAI,CAAC,uBAAuB,EAAE,EAAE,oDAAoD,CAAC,CAAC;gBAChI,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,uBAAuB,EAAE,CAAC;YAC/B,IAAI,IAAI,CAAC,uBAAuB,IAAI,CAAC,EAAE,CAAC;gBACtC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,mBAAmB,EAAE,IAAI,CAAC,uBAAuB,EAAE,EAAE,gDAAgD,CAAC,CAAC;YACjI,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,iCAAiC,CAAC,CAAC;YAChE,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI;QACF,WAAW,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACnC,CAAC;CACF"}
1
+ {"version":3,"file":"context-guardian.js","sourceRoot":"","sources":["../src/context-guardian.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { Daemon } from "./daemon.js";
2
+ import { createLogger } from "./logger.js";
2
3
  const args = process.argv.slice(2);
3
4
  function getArg(name) {
4
5
  const idx = args.indexOf(name);
@@ -15,7 +16,7 @@ catch (err) {
15
16
  process.exit(1);
16
17
  }
17
18
  const topicMode = args.includes("--topic-mode");
18
- const daemon = new Daemon(name, config, instanceDir, topicMode);
19
+ const daemon = new Daemon(name, config, instanceDir, topicMode, undefined, undefined, createLogger(config.log_level));
19
20
  daemon.start().catch((err) => {
20
21
  console.error("Daemon failed:", err);
21
22
  process.exit(1);
@@ -1 +1 @@
1
- {"version":3,"file":"daemon-entry.js","sourceRoot":"","sources":["../src/daemon-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,SAAS,MAAM,CAAC,IAAY;IAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACzC,CAAC;AAED,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;AAClC,MAAM,WAAW,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAC7C,IAAI,MAAsB,CAAC;AAC3B,IAAI,CAAC;IACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAC1C,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACb,OAAO,CAAC,KAAK,CAAC,kCAAmC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;AAChD,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;AAEhE,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAC3B,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;IAC1B,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC;AACF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAChC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC"}
1
+ {"version":3,"file":"daemon-entry.js","sourceRoot":"","sources":["../src/daemon-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,SAAS,MAAM,CAAC,IAAY;IAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACzC,CAAC;AAED,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;AAClC,MAAM,WAAW,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAC7C,IAAI,MAAsB,CAAC;AAC3B,IAAI,CAAC;IACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAC1C,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACb,OAAO,CAAC,KAAK,CAAC,kCAAmC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;AAChD,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;AAEtH,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAC3B,OAAO,CAAC,KAAK,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;IAC1B,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC;AACF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAChC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC"}
package/dist/daemon.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { EventEmitter } from "node:events";
2
2
  import type { InstanceConfig, RotationSnapshot } from "./types.js";
3
+ import type { Logger } from "./logger.js";
3
4
  import { MessageBus } from "./channel/message-bus.js";
4
5
  import type { CliBackend, InstanceState, InstanceStateSnapshot } from "./backend/types.js";
5
6
  import { HangDetector } from "./hang-detector.js";
@@ -99,6 +100,8 @@ export declare class Daemon extends EventEmitter {
99
100
  private lastBuiltInstructions;
100
101
  private pasteQueueDepth;
101
102
  private errorMonitorTimer;
103
+ /** Prevent in-flight monitor callbacks from re-arming after a pause. */
104
+ private runtimeMonitorsFrozen;
102
105
  private errorWaitingForRecovery;
103
106
  private errorDetectedAt;
104
107
  /** Whether this instance is in an abnormal error state (auto-pause is normal). */
@@ -114,7 +117,7 @@ export declare class Daemon extends EventEmitter {
114
117
  private static ERROR_COOLDOWN_MS;
115
118
  private lastErrorCount;
116
119
  private lastDetectedErrorType;
117
- constructor(name: string, config: InstanceConfig, instanceDir: string, topicMode?: boolean, backend?: CliBackend | undefined, controlClient?: TmuxControlClient | undefined);
120
+ constructor(name: string, config: InstanceConfig, instanceDir: string, topicMode?: boolean, backend?: CliBackend | undefined, controlClient?: TmuxControlClient | undefined, rootLogger?: Logger);
118
121
  start(): Promise<void>;
119
122
  private startHealthCheck;
120
123
  /**
@@ -142,6 +145,10 @@ export declare class Daemon extends EventEmitter {
142
145
  /** Respawn the CLI in the preserved window and block until its prompt is ready. */
143
146
  wake(timeoutMs?: number): Promise<void>;
144
147
  private startInstanceStateMonitor;
148
+ /** Stop every runtime poller/watcher while preserving IPC and daemon state. */
149
+ private freezeRuntimeMonitors;
150
+ /** Restore the same monitor objects after wake without adding event listeners. */
151
+ private resumeRuntimeMonitors;
145
152
  getMessageBus(): MessageBus;
146
153
  private summarizeTool;
147
154
  private addToolStatus;
package/dist/daemon.js CHANGED
@@ -3,7 +3,6 @@ import { mkdirSync, writeFileSync, readFileSync, existsSync, unlinkSync, rmSync,
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { createHash, randomBytes } from "node:crypto";
5
5
  import { EventEmitter } from "node:events";
6
- import { createLogger } from "./logger.js";
7
6
  import { TmuxManager } from "./tmux-manager.js";
8
7
  import { TranscriptMonitor } from "./transcript-monitor.js";
9
8
  import { ContextGuardian } from "./context-guardian.js";
@@ -189,6 +188,8 @@ export class Daemon extends EventEmitter {
189
188
  pasteQueueDepth = 0;
190
189
  // PTY error pattern monitoring
191
190
  errorMonitorTimer = null;
191
+ /** Prevent in-flight monitor callbacks from re-arming after a pause. */
192
+ runtimeMonitorsFrozen = false;
192
193
  errorWaitingForRecovery = false; // true = error detected, waiting for ready pattern
193
194
  errorDetectedAt = 0;
194
195
  /** Whether this instance is in an abnormal error state (auto-pause is normal). */
@@ -215,7 +216,7 @@ export class Daemon extends EventEmitter {
215
216
  // still registers as new (prevents the old hash-dedup's permanent suppression).
216
217
  lastErrorCount = new Map();
217
218
  lastDetectedErrorType = null;
218
- constructor(name, config, instanceDir, topicMode = false, backend, controlClient) {
219
+ constructor(name, config, instanceDir, topicMode = false, backend, controlClient, rootLogger) {
219
220
  super();
220
221
  this.name = name;
221
222
  this.config = config;
@@ -223,7 +224,9 @@ export class Daemon extends EventEmitter {
223
224
  this.topicMode = topicMode;
224
225
  this.backend = backend;
225
226
  this.controlClient = controlClient;
226
- this.logger = createLogger(config.log_level);
227
+ if (!rootLogger)
228
+ throw new Error("Daemon requires a shared root logger");
229
+ this.logger = rootLogger.child({ instance: name }, { level: config.log_level });
227
230
  this.tmuxSessionName = getTmuxSession();
228
231
  this.messageBus = new MessageBus();
229
232
  this.messageBus.setLogger(this.logger);
@@ -521,11 +524,18 @@ export class Daemon extends EventEmitter {
521
524
  this.logger.info(`${this.name} ready`);
522
525
  }
523
526
  startHealthCheck() {
527
+ if (this.runtimeMonitorsFrozen || this.healthCheckTimer)
528
+ return;
524
529
  const { max_retries, backoff, reset_after } = this.config.restart_policy;
525
530
  if (max_retries <= 0)
526
531
  return; // restart disabled
527
532
  const scheduleNext = () => {
533
+ if (this.runtimeMonitorsFrozen || this.healthCheckTimer)
534
+ return;
528
535
  this.healthCheckTimer = setTimeout(async () => {
536
+ this.healthCheckTimer = null;
537
+ if (this.runtimeMonitorsFrozen)
538
+ return;
529
539
  // Instance directory removed externally (e.g. `rm -rf ~/.agend/instances/<name>`).
530
540
  // Stop the loop permanently — otherwise every tick triggers a respawn, whose
531
541
  // writeRotationSnapshot fails with ENOENT and gets caught as "Failed to respawn",
@@ -776,6 +786,8 @@ export class Daemon extends EventEmitter {
776
786
  * (ready pattern visible), it goes back to monitoring for new errors.
777
787
  */
778
788
  startErrorMonitor() {
789
+ if (this.runtimeMonitorsFrozen || this.errorMonitorTimer)
790
+ return;
779
791
  const patterns = this.backend?.getErrorPatterns?.() ?? [];
780
792
  const dialogs = this.backend?.getRuntimeDialogs?.() ?? [];
781
793
  if (!patterns.length && !dialogs.length)
@@ -895,26 +907,13 @@ export class Daemon extends EventEmitter {
895
907
  }
896
908
  async stop() {
897
909
  this.logger.info("Stopping daemon instance");
898
- if (this.healthCheckTimer) {
899
- clearTimeout(this.healthCheckTimer);
900
- this.healthCheckTimer = null;
901
- }
902
- if (this.errorMonitorTimer) {
903
- clearInterval(this.errorMonitorTimer);
904
- this.errorMonitorTimer = null;
905
- }
906
- if (this.instanceStateMonitorTimer) {
907
- clearInterval(this.instanceStateMonitorTimer);
908
- this.instanceStateMonitorTimer = null;
909
- }
910
+ this.freezeRuntimeMonitors();
910
911
  if (this.toolStatusDebounce) {
911
912
  clearTimeout(this.toolStatusDebounce);
912
913
  this.toolStatusDebounce = null;
913
914
  }
914
915
  this.pendingIpcRequests.clear();
915
916
  this.hangDetector?.stop();
916
- this.transcriptMonitor?.stop();
917
- this.guardian?.stop();
918
917
  if (this.adapter)
919
918
  await this.adapter.stop();
920
919
  // Notify MCP servers of graceful shutdown (prevents reconnect attempts)
@@ -1007,6 +1006,7 @@ export class Daemon extends EventEmitter {
1007
1006
  }
1008
1007
  this.pauseWakeState = "pausing";
1009
1008
  this.healthCheckPaused = true;
1009
+ this.freezeRuntimeMonitors();
1010
1010
  const transition = (async () => {
1011
1011
  try {
1012
1012
  this.saveSessionId();
@@ -1053,6 +1053,7 @@ export class Daemon extends EventEmitter {
1053
1053
  this.pauseWakeState = "active";
1054
1054
  this.healthCheckPaused = false;
1055
1055
  this.pauseRequested = false;
1056
+ this.resumeRuntimeMonitors();
1056
1057
  throw err;
1057
1058
  }
1058
1059
  })();
@@ -1105,6 +1106,7 @@ export class Daemon extends EventEmitter {
1105
1106
  }
1106
1107
  catch { }
1107
1108
  this.transcriptMonitor?.resetOffset();
1109
+ this.resumeRuntimeMonitors();
1108
1110
  this.logger.info("Instance auto-woke");
1109
1111
  this.ipcServer?.broadcast({
1110
1112
  type: "instance_state", instanceName: this.name, state: this.instanceState, pausedAt: null,
@@ -1124,7 +1126,7 @@ export class Daemon extends EventEmitter {
1124
1126
  }
1125
1127
  }
1126
1128
  startInstanceStateMonitor() {
1127
- if (!this.tmux || !this.backend || this.instanceStateMonitorTimer)
1129
+ if (this.runtimeMonitorsFrozen || !this.tmux || !this.backend || this.instanceStateMonitorTimer)
1128
1130
  return;
1129
1131
  const rawConfig = this.config.hang_detector;
1130
1132
  const timeoutMinutes = rawConfig?.timeout_minutes;
@@ -1180,6 +1182,37 @@ export class Daemon extends EventEmitter {
1180
1182
  void poll();
1181
1183
  this.instanceStateMonitorTimer = setInterval(() => { void poll(); }, pollIntervalMs);
1182
1184
  }
1185
+ /** Stop every runtime poller/watcher while preserving IPC and daemon state. */
1186
+ freezeRuntimeMonitors() {
1187
+ this.runtimeMonitorsFrozen = true;
1188
+ if (this.healthCheckTimer) {
1189
+ clearTimeout(this.healthCheckTimer);
1190
+ this.healthCheckTimer = null;
1191
+ }
1192
+ if (this.errorMonitorTimer) {
1193
+ clearInterval(this.errorMonitorTimer);
1194
+ this.errorMonitorTimer = null;
1195
+ }
1196
+ if (this.instanceStateMonitorTimer) {
1197
+ clearInterval(this.instanceStateMonitorTimer);
1198
+ this.instanceStateMonitorTimer = null;
1199
+ }
1200
+ this.transcriptMonitor?.stop();
1201
+ this.guardian?.stop();
1202
+ }
1203
+ /** Restore the same monitor objects after wake without adding event listeners. */
1204
+ resumeRuntimeMonitors() {
1205
+ if (!this.runtimeMonitorsFrozen)
1206
+ return;
1207
+ this.runtimeMonitorsFrozen = false;
1208
+ this.startHealthCheck();
1209
+ if (!this.config.lightweight) {
1210
+ this.transcriptMonitor?.startPolling();
1211
+ this.guardian?.startWatching();
1212
+ this.startErrorMonitor();
1213
+ }
1214
+ this.startInstanceStateMonitor();
1215
+ }
1183
1216
  getMessageBus() {
1184
1217
  return this.messageBus;
1185
1218
  }