@cjhyy/code-shell-core 0.9.2 → 0.9.4

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 (38) hide show
  1. package/dist/cli/agent-server-stdio.js +26 -1
  2. package/dist/cli/agent-server-tcp.js +58 -7
  3. package/dist/engine/engine.d.ts +8 -0
  4. package/dist/engine/engine.js +16 -12
  5. package/dist/engine/model-facade.d.ts +3 -0
  6. package/dist/engine/model-facade.js +2 -0
  7. package/dist/engine/run-tooling.js +8 -8
  8. package/dist/engine/streaming-tool-queue.d.ts +4 -1
  9. package/dist/engine/streaming-tool-queue.js +17 -2
  10. package/dist/engine/turn-loop.d.ts +14 -5
  11. package/dist/engine/turn-loop.js +92 -37
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.js +1 -1
  14. package/dist/llm/prompt-cache.d.ts +48 -0
  15. package/dist/llm/prompt-cache.js +100 -0
  16. package/dist/llm/providers/anthropic.d.ts +3 -0
  17. package/dist/llm/providers/anthropic.js +77 -53
  18. package/dist/llm/providers/openai.d.ts +7 -27
  19. package/dist/llm/providers/openai.js +120 -68
  20. package/dist/llm/types.d.ts +3 -0
  21. package/dist/onboarding.js +72 -49
  22. package/dist/panel-apps/manifest.d.ts +12 -12
  23. package/dist/profile/types.d.ts +26 -26
  24. package/dist/protocol/background-result-wakeup.d.ts +3 -1
  25. package/dist/protocol/background-result-wakeup.js +5 -5
  26. package/dist/protocol/server.d.ts +13 -0
  27. package/dist/protocol/server.js +22 -3
  28. package/dist/services/index.d.ts +0 -1
  29. package/dist/services/index.js +0 -1
  30. package/dist/session/memory.js +2 -2
  31. package/dist/session/session-manager.js +30 -1
  32. package/dist/tool-system/builtin/agent-notifications.d.ts +25 -1
  33. package/dist/tool-system/builtin/agent-notifications.js +334 -2
  34. package/dist/tool-system/context.d.ts +9 -4
  35. package/dist/tool-system/external-tool-exposure.js +11 -10
  36. package/package.json +2 -1
  37. package/dist/services/notifier.d.ts +0 -33
  38. package/dist/services/notifier.js +0 -83
@@ -125,6 +125,11 @@ export declare const WorkspaceProfileRequirementsSchema: z.ZodObject<{
125
125
  hint?: string | undefined;
126
126
  }>, "many">>;
127
127
  }, "strip", z.ZodTypeAny, {
128
+ tools: {
129
+ bin: string;
130
+ minVersion?: string | undefined;
131
+ hint?: string | undefined;
132
+ }[];
128
133
  skills: {
129
134
  source: "github";
130
135
  scope: "project";
@@ -132,12 +137,12 @@ export declare const WorkspaceProfileRequirementsSchema: z.ZodObject<{
132
137
  fullDepth: boolean;
133
138
  skills?: string[] | undefined;
134
139
  }[];
135
- tools: {
140
+ }, {
141
+ tools?: {
136
142
  bin: string;
137
143
  minVersion?: string | undefined;
138
144
  hint?: string | undefined;
139
- }[];
140
- }, {
145
+ }[] | undefined;
141
146
  skills?: {
142
147
  source: "github";
143
148
  repo: string;
@@ -145,11 +150,6 @@ export declare const WorkspaceProfileRequirementsSchema: z.ZodObject<{
145
150
  skills?: string[] | undefined;
146
151
  fullDepth?: boolean | undefined;
147
152
  }[] | undefined;
148
- tools?: {
149
- bin: string;
150
- minVersion?: string | undefined;
151
- hint?: string | undefined;
152
- }[] | undefined;
153
153
  }>;
154
154
  export type SkillRequirement = z.infer<typeof skillRequirementSchema>;
155
155
  export type ToolRequirement = z.infer<typeof toolRequirementSchema>;
@@ -206,6 +206,11 @@ export declare const WorkspaceProfileSchema: z.ZodObject<{
206
206
  hint?: string | undefined;
207
207
  }>, "many">>;
208
208
  }, "strip", z.ZodTypeAny, {
209
+ tools: {
210
+ bin: string;
211
+ minVersion?: string | undefined;
212
+ hint?: string | undefined;
213
+ }[];
209
214
  skills: {
210
215
  source: "github";
211
216
  scope: "project";
@@ -213,12 +218,12 @@ export declare const WorkspaceProfileSchema: z.ZodObject<{
213
218
  fullDepth: boolean;
214
219
  skills?: string[] | undefined;
215
220
  }[];
216
- tools: {
221
+ }, {
222
+ tools?: {
217
223
  bin: string;
218
224
  minVersion?: string | undefined;
219
225
  hint?: string | undefined;
220
- }[];
221
- }, {
226
+ }[] | undefined;
222
227
  skills?: {
223
228
  source: "github";
224
229
  repo: string;
@@ -226,11 +231,6 @@ export declare const WorkspaceProfileSchema: z.ZodObject<{
226
231
  skills?: string[] | undefined;
227
232
  fullDepth?: boolean | undefined;
228
233
  }[] | undefined;
229
- tools?: {
230
- bin: string;
231
- minVersion?: string | undefined;
232
- hint?: string | undefined;
233
- }[] | undefined;
234
234
  }>>;
235
235
  /**
236
236
  * true → 独占工作面:激活时把**未声明**的 skill/plugin/mcp/agent 显式关掉,
@@ -264,6 +264,11 @@ export declare const WorkspaceProfileSchema: z.ZodObject<{
264
264
  version?: string | undefined;
265
265
  description?: string | undefined;
266
266
  requires?: {
267
+ tools: {
268
+ bin: string;
269
+ minVersion?: string | undefined;
270
+ hint?: string | undefined;
271
+ }[];
267
272
  skills: {
268
273
  source: "github";
269
274
  scope: "project";
@@ -271,11 +276,6 @@ export declare const WorkspaceProfileSchema: z.ZodObject<{
271
276
  fullDepth: boolean;
272
277
  skills?: string[] | undefined;
273
278
  }[];
274
- tools: {
275
- bin: string;
276
- minVersion?: string | undefined;
277
- hint?: string | undefined;
278
- }[];
279
279
  } | undefined;
280
280
  mainInstruction?: string | undefined;
281
281
  }, {
@@ -289,6 +289,11 @@ export declare const WorkspaceProfileSchema: z.ZodObject<{
289
289
  plugins?: string[] | undefined;
290
290
  agents?: string[] | undefined;
291
291
  requires?: {
292
+ tools?: {
293
+ bin: string;
294
+ minVersion?: string | undefined;
295
+ hint?: string | undefined;
296
+ }[] | undefined;
292
297
  skills?: {
293
298
  source: "github";
294
299
  repo: string;
@@ -296,11 +301,6 @@ export declare const WorkspaceProfileSchema: z.ZodObject<{
296
301
  skills?: string[] | undefined;
297
302
  fullDepth?: boolean | undefined;
298
303
  }[] | undefined;
299
- tools?: {
300
- bin: string;
301
- minVersion?: string | undefined;
302
- hint?: string | undefined;
303
- }[] | undefined;
304
304
  } | undefined;
305
305
  exclusiveCapabilities?: boolean | undefined;
306
306
  mainInstruction?: string | undefined;
@@ -1,4 +1,5 @@
1
1
  import type { StreamEvent } from "../types.js";
2
+ import { type NotificationQueue } from "../tool-system/builtin/agent-notifications.js";
2
3
  import type { ApprovalRouter } from "../tool-system/permission.js";
3
4
  import type { ChatSession } from "./chat-session.js";
4
5
  import type { ChatSessionManager } from "./chat-session-manager.js";
@@ -8,11 +9,12 @@ interface BackgroundResultWakeOptions {
8
9
  rehydrate(sessionId: string): Promise<ChatSession | null>;
9
10
  approvalRouter: ApprovalRouter;
10
11
  onStream(event: StreamEvent): void;
12
+ notificationMailbox?: NotificationQueue;
11
13
  }
12
14
  /**
13
15
  * Drain pending background results into exactly one synthetic continuation.
14
16
  * Busy sessions are awaited so a completion cannot fall into the gap between
15
17
  * the notification bus callback and the interactive run-boundary re-check.
16
18
  */
17
- export declare function wakeSessionForBackgroundResults({ sessionId, manager, rehydrate, approvalRouter, onStream, }: BackgroundResultWakeOptions): Promise<boolean>;
19
+ export declare function wakeSessionForBackgroundResults({ sessionId, manager, rehydrate, approvalRouter, onStream, notificationMailbox, }: BackgroundResultWakeOptions): Promise<boolean>;
18
20
  export {};
@@ -5,7 +5,7 @@ import { buildNotificationMessage, notificationQueue, } from "../tool-system/bui
5
5
  * Busy sessions are awaited so a completion cannot fall into the gap between
6
6
  * the notification bus callback and the interactive run-boundary re-check.
7
7
  */
8
- export async function wakeSessionForBackgroundResults({ sessionId, manager, rehydrate, approvalRouter, onStream, }) {
8
+ export async function wakeSessionForBackgroundResults({ sessionId, manager, rehydrate, approvalRouter, onStream, notificationMailbox = notificationQueue, }) {
9
9
  if (!manager) {
10
10
  logger.debug("bg_wakeup.skipped", { sessionId, reason: "no_chat_manager" });
11
11
  return false;
@@ -22,7 +22,7 @@ export async function wakeSessionForBackgroundResults({ sessionId, manager, rehy
22
22
  while (session.isBusy()) {
23
23
  logger.debug("bg_wakeup.waiting_for_idle", {
24
24
  sessionId,
25
- pendingCount: notificationQueue.getSnapshot(sessionId).length,
25
+ pendingCount: notificationMailbox.getSnapshot(sessionId).length,
26
26
  });
27
27
  await session.settled;
28
28
  if (manager.isUnavailable(sessionId)) {
@@ -63,7 +63,7 @@ export async function wakeSessionForBackgroundResults({ sessionId, manager, rehy
63
63
  });
64
64
  return false;
65
65
  }
66
- const pending = notificationQueue.drainAll(sessionId);
66
+ const pending = notificationMailbox.drainAll(sessionId);
67
67
  if (pending.length === 0) {
68
68
  logger.debug("bg_wakeup.skipped", { sessionId, reason: "no_pending_results" });
69
69
  return false;
@@ -77,7 +77,7 @@ export async function wakeSessionForBackgroundResults({ sessionId, manager, rehy
77
77
  approvalRouter,
78
78
  });
79
79
  if (result.turnCount === 0) {
80
- const restored = notificationQueue.restoreResults(sessionId, pending);
80
+ const restored = notificationMailbox.restoreResults(sessionId, pending);
81
81
  logger.warn("bg_wakeup.turn_not_started", {
82
82
  sessionId,
83
83
  restored,
@@ -89,7 +89,7 @@ export async function wakeSessionForBackgroundResults({ sessionId, manager, rehy
89
89
  }
90
90
  catch (error) {
91
91
  const message = error instanceof Error ? error.message : String(error);
92
- const restored = notificationQueue.restoreResults(sessionId, pending);
92
+ const restored = notificationMailbox.restoreResults(sessionId, pending);
93
93
  logger.warn("bg_wakeup.turn_failed", { sessionId, error: message, restored });
94
94
  // A setup failure can occur before the turn loop emits its own terminal
95
95
  // event. Emit an error so every renderer clears its busy state, but keep
@@ -17,6 +17,7 @@ import type { Transport } from "./transport.js";
17
17
  import type { Engine } from "../engine/engine.js";
18
18
  import type { ValidatedSettings } from "../settings/schema.js";
19
19
  import { type ApprovalRouter } from "../tool-system/permission.js";
20
+ import { type NotificationQueue, type NotificationQueuePersistence } from "../tool-system/builtin/agent-notifications.js";
20
21
  import type { ChatSessionManager } from "./chat-session-manager.js";
21
22
  import type { ResolvedComposition } from "../composition/types.js";
22
23
  /**
@@ -106,6 +107,16 @@ export interface AgentServerOptions {
106
107
  * write.
107
108
  */
108
109
  sessionDiskRoot?: string;
110
+ /** Durable per-session result mailbox. Omitted keeps the in-memory behavior. */
111
+ notificationPersistence?: NotificationQueuePersistence;
112
+ /** Test/host seam; production uses the process singleton. */
113
+ notificationMailbox?: NotificationQueue;
114
+ /**
115
+ * Whether this server instance owns durable result restoration and idle
116
+ * wakeups. Defaults to true. Multi-connection hosts set one process-lifetime
117
+ * owner and leave connection servers as observation-only forwarders.
118
+ */
119
+ ownsBackgroundWakeups?: boolean;
109
120
  /** Shared owner router; injectable for hosts/tests, process singleton by default. */
110
121
  approvalRouter?: ApprovalRouter;
111
122
  /**
@@ -197,8 +208,10 @@ export declare class AgentServer {
197
208
  * itself outlives the server (it's a process-local singleton).
198
209
  */
199
210
  private bgAgentBusUnsubscribe;
211
+ private readonly ownsBackgroundWakeups;
200
212
  private readonly wakeupsInFlight;
201
213
  private readonly sessionWorkspaceRpc;
214
+ private readonly notificationMailbox;
202
215
  /**
203
216
  * Effective session manager for the connection this server serves. Without
204
217
  * a resolveIdentity hook this is exactly the host-supplied manager —
@@ -381,8 +381,10 @@ export class AgentServer {
381
381
  * itself outlives the server (it's a process-local singleton).
382
382
  */
383
383
  bgAgentBusUnsubscribe = null;
384
+ ownsBackgroundWakeups;
384
385
  wakeupsInFlight = new Set();
385
386
  sessionWorkspaceRpc;
387
+ notificationMailbox;
386
388
  /**
387
389
  * Effective session manager for the connection this server serves. Without
388
390
  * a resolveIdentity hook this is exactly the host-supplied manager —
@@ -407,6 +409,11 @@ export class AgentServer {
407
409
  return manager;
408
410
  }
409
411
  constructor(options) {
412
+ this.notificationMailbox = options.notificationMailbox ?? notificationQueue;
413
+ this.ownsBackgroundWakeups = options.ownsBackgroundWakeups !== false;
414
+ if (options.notificationPersistence) {
415
+ this.notificationMailbox.attachPersistence(options.notificationPersistence);
416
+ }
410
417
  this.baseChatManager = options.chatManager ?? null;
411
418
  this.resolveIdentity = options.resolveIdentity ?? null;
412
419
  this.sessionDiskRoot = options.sessionDiskRoot;
@@ -509,8 +516,9 @@ export class AgentServer {
509
516
  // legacy UI event is only an observation path. A renderer transport
510
517
  // failure after accepting the event must not strand the result in the
511
518
  // queue, so schedule the wake from finally.
512
- if (envelope.kind === "result")
519
+ if (this.ownsBackgroundWakeups && envelope.kind === "result") {
513
520
  this.maybeWakeIdleSession(sessionId);
521
+ }
514
522
  }
515
523
  // Background work that finishes while the session is idle (a
516
524
  // run_in_background Bash like a download, a background sub-agent, or a
@@ -523,6 +531,14 @@ export class AgentServer {
523
531
  // continuation. A never-exiting dev server emits no completion, so it
524
532
  // never wakes anything (no task/service classification needed).
525
533
  });
534
+ // Results restored from disk are deliberately not republished on the
535
+ // observation bus: their required destination is the original chat. Feed
536
+ // them into the same guarded wake path as live completions instead.
537
+ if (this.ownsBackgroundWakeups) {
538
+ for (const sessionId of this.notificationMailbox.restorePersistedSessions()) {
539
+ this.maybeWakeIdleSession(sessionId);
540
+ }
541
+ }
526
542
  // Notify client we're ready
527
543
  this.notify(Methods.Status, { status: "ready" });
528
544
  }
@@ -549,13 +565,15 @@ export class AgentServer {
549
565
  * wakeup turns while getOrCreate waits for a closing generation to settle.
550
566
  */
551
567
  maybeWakeIdleSession(sessionId) {
568
+ if (!this.ownsBackgroundWakeups)
569
+ return;
552
570
  if (this.wakeupsInFlight.has(sessionId))
553
571
  return;
554
572
  this.wakeupsInFlight.add(sessionId);
555
573
  void this.wakeIdleSession(sessionId)
556
574
  .then((ranTurn) => {
557
575
  this.wakeupsInFlight.delete(sessionId);
558
- if (ranTurn && notificationQueue.getSnapshot(sessionId).length > 0) {
576
+ if (ranTurn && this.notificationMailbox.getSnapshot(sessionId).length > 0) {
559
577
  this.maybeWakeIdleSession(sessionId);
560
578
  }
561
579
  })
@@ -574,6 +592,7 @@ export class AgentServer {
574
592
  rehydrate: (id) => this.rehydrateSessionForWake(id),
575
593
  approvalRouter: this.approvalRouter,
576
594
  onStream: (event) => this.notify(Methods.StreamEvent, { sessionId, event }),
595
+ notificationMailbox: this.notificationMailbox,
577
596
  });
578
597
  }
579
598
  async rehydrateSessionForWake(sessionId) {
@@ -582,7 +601,7 @@ export class AgentServer {
582
601
  if (this.chatManager.isUnavailable(sessionId))
583
602
  return null;
584
603
  try {
585
- const pending = notificationQueue.getSnapshot(sessionId);
604
+ const pending = this.notificationMailbox.getSnapshot(sessionId);
586
605
  if (pending.length === 0) {
587
606
  logger.debug("bg_wakeup.rehydrate_skipped_no_pending", { sessionId });
588
607
  return null;
@@ -3,7 +3,6 @@
3
3
  */
4
4
  export { analytics, trackEvent } from "./analytics.js";
5
5
  export { authorize, refreshToken, generatePKCE, createHardenedOAuthFetch, type OAuthConfig, type OAuthTokens, type OAuthAuthorizeOptions, type OAuthRefreshOptions, type HardenedOAuthFetchOptions, } from "./oauth.js";
6
- export { notify, notifyComplete, notifyError } from "./notifier.js";
7
6
  export { diagnostics } from "./diagnostics.js";
8
7
  export { buildExtractionPrompt, parseExtractionResponse, type ExtractedMemory, } from "./extract-memories.js";
9
8
  export { shouldAutoDream, recordSession, recordDreamComplete, buildDreamSystemPrompt, buildDreamUserPrompt, } from "./auto-dream.js";
@@ -9,7 +9,6 @@ export { analytics, trackEvent } from "./analytics.js";
9
9
  // to the tool_result-based microcompact in ContextManager). Removed to end
10
10
  // the "which microcompact?" ambiguity — the source of truth is ContextManager.
11
11
  export { authorize, refreshToken, generatePKCE, createHardenedOAuthFetch, } from "./oauth.js";
12
- export { notify, notifyComplete, notifyError } from "./notifier.js";
13
12
  export { diagnostics } from "./diagnostics.js";
14
13
  export { buildExtractionPrompt, parseExtractionResponse, } from "./extract-memories.js";
15
14
  export { shouldAutoDream, recordSession, recordDreamComplete, buildDreamSystemPrompt, buildDreamUserPrompt, } from "./auto-dream.js";
@@ -23,7 +23,7 @@
23
23
  * Deletes are SOFT — files are moved to <baseDir>/memory-trash/<ISO>/<scope>/
24
24
  * rather than removed, so accidental deletions are recoverable.
25
25
  */
26
- import { mkdirSync, existsSync, readFileSync, writeFileSync, readdirSync, renameSync, statSync, } from "node:fs";
26
+ import { mkdirSync, existsSync, readFileSync, readdirSync, renameSync, statSync } from "node:fs";
27
27
  import { join } from "node:path";
28
28
  import { homedir } from "node:os";
29
29
  import { createHash, randomUUID } from "node:crypto";
@@ -174,7 +174,7 @@ export class MemoryManager {
174
174
  frontmatterLine("updateCount", updateCount) +
175
175
  `---\n\n` +
176
176
  `${entry.content}\n`;
177
- writeFileSync(filePath, content, "utf-8");
177
+ writeFileAtomic(filePath, content, 0o600);
178
178
  // Incremental index update. Initialize the cache on first
179
179
  // save by paying one loadAll() — every save after that just
180
180
  // mutates the cache and rewrites MEMORY.md.
@@ -237,13 +237,42 @@ function normalizedSessionKind(kind) {
237
237
  export function codeShellHome() {
238
238
  return process.env.CODE_SHELL_HOME || join(homedir(), ".code-shell");
239
239
  }
240
+ /** True when this process is a test runner. `bun test` sets NODE_ENV itself. */
241
+ function isTestRunner() {
242
+ return process.env.NODE_ENV === "test" || process.env.BUN_TEST === "1";
243
+ }
244
+ /** The real per-user home, ignoring any CODE_SHELL_HOME override. */
245
+ function defaultHome() {
246
+ return join(homedir(), ".code-shell");
247
+ }
240
248
  /**
241
249
  * Canonical root for every persisted CodeShell session. An explicit `home`
242
250
  * (a `~/.code-shell`-equivalent data root) overrides the default resolution;
243
251
  * absent → `codeShellHome()` exactly as before.
244
252
  */
245
253
  export function sessionsRoot(home) {
246
- return join(home ?? codeShellHome(), "sessions");
254
+ const resolvedHome = home ?? codeShellHome();
255
+ // Fail closed rather than write fixture sessions into the developer's real
256
+ // store. The bunfig preload only applies when Bun resolves a bunfig.toml:
257
+ // `bun test <file>` from a subdirectory, or an IDE/CI runner with its own
258
+ // cwd, finds none and silently fell through to ~/.code-shell — which is how
259
+ // ~700 `test-model` sessions ended up in the real store and the sidebar.
260
+ //
261
+ // Guarded here rather than in codeShellHome() because the home is also the
262
+ // legitimate root for settings/projects/trust that many tests read by
263
+ // design; only the SESSIONS root is the one tests corrupt.
264
+ if (isTestRunner() && resolvedHome === defaultHome()) {
265
+ // Prefer the preload's sandbox. Many test files delete CODE_SHELL_HOME in
266
+ // cleanup, and bun shares one process across files, so isolation would
267
+ // otherwise vanish for every later suite.
268
+ const sandbox = process.env.CODE_SHELL_TEST_HOME;
269
+ if (sandbox)
270
+ return join(sandbox, "sessions");
271
+ throw new SessionError("Refusing to use the real ~/.code-shell/sessions from a test. Set CODE_SHELL_HOME " +
272
+ "to a temp dir (packages/core/test-setup.ts does this via the bunfig preload) " +
273
+ "or pass an explicit storageDir.");
274
+ }
275
+ return join(resolvedHome, "sessions");
247
276
  }
248
277
  function isSessionWorkspace(value) {
249
278
  if (!value || typeof value !== "object")
@@ -119,12 +119,23 @@ export type NotificationItem = {
119
119
  enqueuedAt: number;
120
120
  };
121
121
  type Listener = () => void;
122
- declare class NotificationQueue {
122
+ export interface NotificationQueuePersistence {
123
+ fileForSession(sessionId: string): string | null;
124
+ /** Optional startup inventory. Lazy per-session restore works without it. */
125
+ listSessionIds?(): readonly string[];
126
+ }
127
+ export declare class NotificationQueue {
123
128
  private buckets;
124
129
  private listeners;
125
130
  private sequences;
126
131
  private sequenceRoutes;
132
+ private persistence;
133
+ private restoredSessions;
127
134
  private readonly maxSequenceRoutes;
135
+ attachPersistence(persistence: NotificationQueuePersistence | null): void;
136
+ /** Restore every persisted mailbox discovered by the host during startup. */
137
+ restorePersistedSessions(): string[];
138
+ restorePersistedSession(sessionId: string): number;
128
139
  enqueue(draft: NotificationEnvelopeDraft): NotificationEnvelope | undefined;
129
140
  enqueue(item: NotificationItem, sessionId: string): ResultEnvelope | undefined;
130
141
  subscribe: (listener: Listener) => (() => void);
@@ -143,6 +154,19 @@ declare class NotificationQueue {
143
154
  clearProgress(sessionId: string, agentId: string, runtimeGeneration?: number): boolean;
144
155
  clearDirections(sessionId: string, runtimeGeneration: number): boolean;
145
156
  reset(sessionId?: string): void;
157
+ private resultSnapshot;
158
+ private persistAddedResults;
159
+ private persistRemovedResults;
160
+ private replacePersistedResults;
161
+ /**
162
+ * Cross-process mailbox mutation. The directory lock exists before the JSON
163
+ * file does, and the current contents are re-read inside that lock. This
164
+ * avoids both the old lock-outside seed race and stale-snapshot overwrite.
165
+ */
166
+ private mutatePersistedResults;
167
+ private parsePersistedResultsForMutation;
168
+ private quarantineCorruptFile;
169
+ private reseedSequence;
146
170
  private notify;
147
171
  }
148
172
  type EnvelopeBusHandler = (envelope: NotificationEnvelope) => void;