@gajae-code/coding-agent 0.11.10 → 0.11.11

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 (111) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/types/cli.d.ts +8 -1
  3. package/dist/types/config/model-profile-activation.d.ts +1 -0
  4. package/dist/types/config/model-profile-contract.d.ts +2 -0
  5. package/dist/types/config/settings-schema.d.ts +57 -2
  6. package/dist/types/config/settings.d.ts +1 -0
  7. package/dist/types/extensibility/extensions/types.d.ts +21 -0
  8. package/dist/types/gjc-runtime/linux-proc.d.ts +22 -14
  9. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +60 -0
  10. package/dist/types/gjc-runtime/state-runtime.d.ts +3 -1
  11. package/dist/types/modes/acp/acp-agent.d.ts +14 -9
  12. package/dist/types/modes/components/queue-pane.d.ts +8 -0
  13. package/dist/types/modes/components/queued-message-selector.d.ts +6 -0
  14. package/dist/types/modes/components/welcome.d.ts +1 -0
  15. package/dist/types/modes/interactive-mode.d.ts +5 -1
  16. package/dist/types/runtime/memory-domain.d.ts +9 -0
  17. package/dist/types/runtime/memory-guard-contract.d.ts +71 -0
  18. package/dist/types/runtime/memory-guard.d.ts +39 -0
  19. package/dist/types/runtime/memory-limit.d.ts +11 -0
  20. package/dist/types/runtime-mcp/manager.d.ts +8 -0
  21. package/dist/types/sdk/acp/final-text.d.ts +19 -0
  22. package/dist/types/sdk/acp/mcp.d.ts +23 -0
  23. package/dist/types/sdk/broker/lifecycle.d.ts +2 -0
  24. package/dist/types/sdk/bus/chat-daemon-control.d.ts +2 -1
  25. package/dist/types/sdk/bus/index.d.ts +3 -1
  26. package/dist/types/sdk/bus/rate-limit-pool.d.ts +2 -0
  27. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +6 -4
  28. package/dist/types/sdk/bus/telegram-daemon.d.ts +23 -3
  29. package/dist/types/sdk/host/control/operations.d.ts +1 -0
  30. package/dist/types/sdk/lifecycle-session.d.ts +10 -1
  31. package/dist/types/sdk/startup-capability.d.ts +6 -0
  32. package/dist/types/session/agent-session.d.ts +9 -11
  33. package/dist/types/session/fallback-chain-controller.d.ts +18 -2
  34. package/dist/types/session/internal/managed-session-scope.d.ts +27 -0
  35. package/dist/types/session/session-manager.d.ts +34 -0
  36. package/dist/types/task/executor.d.ts +6 -0
  37. package/dist/types/task/types.d.ts +36 -0
  38. package/dist/types/task/ultragoal-redteam-activation.d.ts +33 -0
  39. package/dist/types/tools/resource-gc.d.ts +19 -0
  40. package/package.json +8 -8
  41. package/scripts/generate-sdk-operation-inventory.ts +2 -0
  42. package/scripts/run-test-manifest.ts +6 -4
  43. package/src/cli/args.ts +14 -8
  44. package/src/cli/fast-help.ts +1 -1
  45. package/src/cli.ts +48 -2
  46. package/src/commands/sdk.ts +91 -7
  47. package/src/config/model-profile-activation.ts +1 -0
  48. package/src/config/model-profile-contract.ts +13 -0
  49. package/src/config/model-profiles.ts +24 -0
  50. package/src/config/settings-schema.ts +61 -2
  51. package/src/config/settings.ts +8 -0
  52. package/src/defaults/gjc/skills/ralplan/SKILL.md +21 -2
  53. package/src/defaults/gjc/skills/ultragoal/SKILL.md +1 -1
  54. package/src/extensibility/extensions/runner.ts +4 -0
  55. package/src/extensibility/extensions/types.ts +14 -0
  56. package/src/gjc-runtime/deep-interview-ambiguity.ts +16 -2
  57. package/src/gjc-runtime/deep-interview-state.ts +25 -3
  58. package/src/gjc-runtime/linux-proc.ts +70 -36
  59. package/src/gjc-runtime/ralplan-runtime.ts +252 -1
  60. package/src/gjc-runtime/state-runtime.ts +48 -11
  61. package/src/internal-urls/docs-index.generated.ts +4 -4
  62. package/src/internal-urls/local-protocol.ts +23 -4
  63. package/src/modes/acp/acp-agent.ts +554 -60
  64. package/src/modes/acp/acp-event-mapper.ts +93 -6
  65. package/src/modes/components/model-selector.ts +15 -1
  66. package/src/modes/components/notifications-settings-editor.ts +1 -1
  67. package/src/modes/components/queue-pane.ts +55 -9
  68. package/src/modes/components/queued-message-selector.ts +53 -10
  69. package/src/modes/components/tool-status-header.ts +1 -4
  70. package/src/modes/components/welcome.ts +18 -3
  71. package/src/modes/controllers/command-controller.ts +4 -0
  72. package/src/modes/controllers/extension-ui-controller.ts +4 -10
  73. package/src/modes/controllers/input-controller.ts +44 -3
  74. package/src/modes/interactive-mode.ts +65 -26
  75. package/src/modes/runtime-init.ts +1 -0
  76. package/src/prompts/agents/executor.md +1 -1
  77. package/src/runtime/memory-domain.ts +66 -0
  78. package/src/runtime/memory-guard-contract.ts +73 -0
  79. package/src/runtime/memory-guard.ts +292 -0
  80. package/src/runtime/memory-limit.ts +50 -0
  81. package/src/runtime-mcp/manager.ts +26 -6
  82. package/src/sdk/acp/adapter.ts +8 -1
  83. package/src/sdk/acp/final-text.ts +40 -0
  84. package/src/sdk/acp/mcp.ts +26 -0
  85. package/src/sdk/broker/lifecycle.ts +82 -1
  86. package/src/sdk/bus/chat-daemon-cli.ts +2 -2
  87. package/src/sdk/bus/chat-daemon-control.ts +4 -3
  88. package/src/sdk/bus/config.ts +1 -1
  89. package/src/sdk/bus/index.ts +162 -22
  90. package/src/sdk/bus/rate-limit-pool.ts +8 -0
  91. package/src/sdk/bus/telegram-daemon-contract.ts +6 -4
  92. package/src/sdk/bus/telegram-daemon.ts +531 -53
  93. package/src/sdk/host/control/dispatch.ts +2 -0
  94. package/src/sdk/host/control/operations.ts +1 -0
  95. package/src/sdk/host/host.ts +2 -2
  96. package/src/sdk/lifecycle-session.ts +19 -3
  97. package/src/sdk/protocol/operation-inventory.generated.json +47 -0
  98. package/src/sdk/protocol/operation-registry.ts +1 -0
  99. package/src/sdk/session.ts +12 -1
  100. package/src/sdk/startup-capability.ts +6 -0
  101. package/src/session/agent-session.ts +256 -142
  102. package/src/session/fallback-chain-controller.ts +47 -8
  103. package/src/session/internal/managed-session-scope.ts +40 -10
  104. package/src/session/internal/native-publish-outcome.ts +8 -3
  105. package/src/session/session-manager.ts +608 -25
  106. package/src/task/executor.ts +11 -3
  107. package/src/task/index.ts +2 -0
  108. package/src/task/types.ts +22 -11
  109. package/src/task/ultragoal-redteam-activation.ts +75 -0
  110. package/src/tools/resource-gc.ts +496 -120
  111. package/src/workflow/workflow-intent-diff.ts +4 -1
@@ -68,17 +68,24 @@ type ConnectionTask = {
68
68
 
69
69
  const STARTUP_TIMEOUT_MS = 250;
70
70
  const STARTUP_TIMEOUT_GRACE_MS = 500;
71
+ /**
72
+ * Default ceiling on how long `discoverAndConnect` waits for a server batch to
73
+ * come up. Deliberately short: a config with a large `timeout` must not be able
74
+ * to hang ordinary startup. ACP lifecycle launches carry their own, larger
75
+ * budget derived from the readiness deadline (see `maxStartupTimeoutMs`).
76
+ */
71
77
  const MAX_STARTUP_TIMEOUT_MS = 1_750;
72
78
 
73
- function resolveStartupTimeoutMs(configs: MCPServerConfig[]): number {
79
+ export function resolveStartupTimeoutMs(configs: MCPServerConfig[], maxStartupTimeoutMs?: number): number {
80
+ const ceiling =
81
+ typeof maxStartupTimeoutMs === "number" && Number.isFinite(maxStartupTimeoutMs) && maxStartupTimeoutMs > 0
82
+ ? Math.max(STARTUP_TIMEOUT_MS, maxStartupTimeoutMs)
83
+ : MAX_STARTUP_TIMEOUT_MS;
74
84
  const configuredTimeouts = configs
75
85
  .map(config => config.timeout)
76
86
  .filter((timeout): timeout is number => typeof timeout === "number" && Number.isFinite(timeout) && timeout > 0);
77
87
  if (configuredTimeouts.length === 0) return STARTUP_TIMEOUT_MS;
78
- return Math.min(
79
- MAX_STARTUP_TIMEOUT_MS,
80
- Math.max(STARTUP_TIMEOUT_MS, Math.max(...configuredTimeouts) + STARTUP_TIMEOUT_GRACE_MS),
81
- );
88
+ return Math.min(ceiling, Math.max(STARTUP_TIMEOUT_MS, Math.max(...configuredTimeouts) + STARTUP_TIMEOUT_GRACE_MS));
82
89
  }
83
90
 
84
91
  function trackPromise<T>(promise: Promise<T>): TrackedPromise<T> {
@@ -185,6 +192,13 @@ export interface MCPDiscoverOptions {
185
192
  export interface MCPManagerOptions {
186
193
  /** Restrict this instance to tools from an explicit MCP config. */
187
194
  toolsOnly?: boolean;
195
+ /**
196
+ * Ceiling for the startup wait, in milliseconds. Only ACP lifecycle launches
197
+ * set this, so a slow ACP MCP handshake gets the readiness budget while every
198
+ * other consumer keeps the short default. Non-positive or non-finite values
199
+ * are ignored and the default applies.
200
+ */
201
+ maxStartupTimeoutMs?: number;
188
202
  }
189
203
 
190
204
  /**
@@ -269,12 +283,15 @@ export class MCPManager {
269
283
  );
270
284
  }
271
285
 
286
+ readonly #maxStartupTimeoutMs: number | undefined;
287
+
272
288
  constructor(
273
289
  private cwd: string,
274
290
  private toolCache: MCPToolCache | null = null,
275
291
  options: MCPManagerOptions = {},
276
292
  ) {
277
293
  this.#toolsOnly = options.toolsOnly === true;
294
+ this.#maxStartupTimeoutMs = options.maxStartupTimeoutMs;
278
295
  }
279
296
 
280
297
  isToolsOnly(): boolean {
@@ -633,7 +650,10 @@ export class MCPManager {
633
650
  }
634
651
 
635
652
  if (connectionTasks.length > 0) {
636
- const startupTimeoutMs = resolveStartupTimeoutMs(connectionTasks.map(task => task.config));
653
+ const startupTimeoutMs = resolveStartupTimeoutMs(
654
+ connectionTasks.map(task => task.config),
655
+ this.#maxStartupTimeoutMs,
656
+ );
637
657
  const firstUnexpectedFailure = Promise.withResolvers<{ reason: unknown }>();
638
658
  if (this.#toolsOnly) {
639
659
  for (const task of connectionTasks) {
@@ -179,7 +179,14 @@ export class AcpSdkAdapter {
179
179
  this.#assertGenericDisposition("global", operation);
180
180
  if (isLifecycleOperation(operation) && !idempotencyKey)
181
181
  throw new AcpSdkAdapterError("invalid_input", "idempotencyKey is required for lifecycle operations.");
182
- return await this.#client.global(operation, input, { idempotencyKey });
182
+ const readinessTimeoutMs =
183
+ typeof input.readinessTimeoutMs === "number" && Number.isSafeInteger(input.readinessTimeoutMs)
184
+ ? input.readinessTimeoutMs
185
+ : undefined;
186
+ return await this.#client.global(operation, input, {
187
+ idempotencyKey,
188
+ ...(readinessTimeoutMs ? { timeoutMs: readinessTimeoutMs + 1_000 } : {}),
189
+ });
183
190
  }
184
191
 
185
192
  async sdkControl(params: { operation: string; input?: JsonObject }): Promise<unknown> {
@@ -0,0 +1,40 @@
1
+ export const ACP_FINAL_TEXT_LIMIT = 100_000;
2
+
3
+ export interface BoundedAcpFinalText {
4
+ text: string;
5
+ truncated: boolean;
6
+ }
7
+
8
+ export type AcpFinalTextResolution =
9
+ | { kind: "none"; final: BoundedAcpFinalText }
10
+ | { kind: "emit"; final: BoundedAcpFinalText; text: string }
11
+ | { kind: "divergent"; final: BoundedAcpFinalText };
12
+
13
+ export function boundAcpFinalText(value: string): BoundedAcpFinalText {
14
+ if (value.length <= ACP_FINAL_TEXT_LIMIT) return { text: value, truncated: false };
15
+ let text = value.slice(0, ACP_FINAL_TEXT_LIMIT);
16
+ const finalCodeUnit = text.charCodeAt(text.length - 1);
17
+ if (finalCodeUnit >= 0xd800 && finalCodeUnit <= 0xdbff) text = text.slice(0, -1);
18
+ return { text, truncated: true };
19
+ }
20
+
21
+ export function acpFinalTextFromMessage(message: unknown): BoundedAcpFinalText {
22
+ const content = (message as { content?: unknown } | null | undefined)?.content;
23
+ if (typeof content === "string") return boundAcpFinalText(content);
24
+ if (!Array.isArray(content)) return { text: "", truncated: false };
25
+ const parts: string[] = [];
26
+ for (const block of content) {
27
+ if (!block || typeof block !== "object" || (block as { type?: unknown }).type !== "text") continue;
28
+ const text = (block as { text?: unknown }).text;
29
+ if (typeof text === "string") parts.push(text);
30
+ }
31
+ return boundAcpFinalText(parts.join(""));
32
+ }
33
+
34
+ export function resolveAcpFinalText(streamed: string, finalText: string): AcpFinalTextResolution {
35
+ const final = boundAcpFinalText(finalText);
36
+ if (!final.text || streamed === final.text || streamed.includes(final.text)) return { kind: "none", final };
37
+ if (!streamed) return { kind: "emit", final, text: final.text };
38
+ if (final.text.startsWith(streamed)) return { kind: "emit", final, text: final.text.slice(streamed.length) };
39
+ return { kind: "divergent", final };
40
+ }
@@ -0,0 +1,26 @@
1
+ export const ACP_MCP_REQUEST_TIMEOUT_MS = 30_000;
2
+ export const ACP_MCP_LIFECYCLE_TIMEOUT_MS = ACP_MCP_REQUEST_TIMEOUT_MS + 500;
3
+ /**
4
+ * Slice of the readiness budget reserved for the work that follows MCP startup
5
+ * (session wiring, marker publication). The ACP MCP startup ceiling is the
6
+ * remaining time to `semanticReadyDeadlineAt` minus this headroom, so a slow
7
+ * MCP handshake cannot consume the whole readiness window.
8
+ */
9
+ export const ACP_MCP_STARTUP_HEADROOM_MS = 250;
10
+
11
+ export interface SessionLifecycleMcpStdioServer {
12
+ type?: "stdio";
13
+ name: string;
14
+ command: string;
15
+ args: string[];
16
+ env?: Record<string, string>;
17
+ }
18
+
19
+ export interface SessionLifecycleMcpRemoteServer {
20
+ type: "http" | "sse";
21
+ name: string;
22
+ url: string;
23
+ headers?: Record<string, string>;
24
+ }
25
+
26
+ export type SessionLifecycleMcpServer = SessionLifecycleMcpStdioServer | SessionLifecycleMcpRemoteServer;
@@ -29,6 +29,7 @@ import {
29
29
  type VerifiedSessionDeleteResult,
30
30
  type VerifiedSessionDeleteTarget,
31
31
  } from "../../session/session-storage";
32
+ import type { SessionLifecycleMcpServer } from "../acp/mcp";
32
33
  import { SdkClient, SdkClientError } from "../client/client";
33
34
  import {
34
35
  type LogicalSessionCandidate,
@@ -215,6 +216,7 @@ export interface SessionLifecycleLaunchRequest {
215
216
  /** Broker-issued effect marker which the child echoes only after host readiness. */
216
217
  effectMarker?: string;
217
218
  modelPreset?: string;
219
+ mcpServers?: SessionLifecycleMcpServer[];
218
220
  worktree?: SessionLifecycleWorktreeTarget;
219
221
  receivedAt: number;
220
222
  requestedReadinessTimeoutMs: number;
@@ -248,6 +250,77 @@ function hasValidTranscriptAuthority(path: unknown, identity: unknown): path is
248
250
  return typeof path === "string" && path.length > 0 && isSessionLifecycleTranscriptIdentity(identity);
249
251
  }
250
252
 
253
+ function isSessionLifecycleMcpServer(value: unknown): value is SessionLifecycleMcpServer {
254
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
255
+ const server = value as Record<string, unknown>;
256
+ if (server.type === "http" || server.type === "sse") {
257
+ if (
258
+ !Object.keys(server).every(key => key === "type" || key === "name" || key === "url" || key === "headers") ||
259
+ typeof server.name !== "string" ||
260
+ !/^[A-Za-z0-9_.-]{1,100}$/.test(server.name) ||
261
+ typeof server.url !== "string" ||
262
+ server.url.length > 8_192
263
+ )
264
+ return false;
265
+ try {
266
+ const url = new URL(server.url);
267
+ if (url.protocol !== "http:" && url.protocol !== "https:") return false;
268
+ } catch {
269
+ return false;
270
+ }
271
+ if (server.headers === undefined) return true;
272
+ if (typeof server.headers !== "object" || server.headers === null || Array.isArray(server.headers)) return false;
273
+ const headers = server.headers as Record<string, unknown>;
274
+ return (
275
+ Object.keys(headers).length <= 100 &&
276
+ Object.entries(headers).every(
277
+ ([name, headerValue]) =>
278
+ name.length > 0 &&
279
+ name.length <= 256 &&
280
+ !name.includes("\r") &&
281
+ !name.includes("\n") &&
282
+ typeof headerValue === "string" &&
283
+ headerValue.length <= 8_192 &&
284
+ !headerValue.includes("\r") &&
285
+ !headerValue.includes("\n"),
286
+ )
287
+ );
288
+ }
289
+ const env = server.env;
290
+ return (
291
+ Object.keys(server).every(
292
+ key => key === "type" || key === "name" || key === "command" || key === "args" || key === "env",
293
+ ) &&
294
+ (server.type === undefined || server.type === "stdio") &&
295
+ typeof server.name === "string" &&
296
+ /^[A-Za-z0-9_.-]{1,100}$/.test(server.name) &&
297
+ typeof server.command === "string" &&
298
+ server.command.length <= 4_096 &&
299
+ path.isAbsolute(server.command) &&
300
+ Array.isArray(server.args) &&
301
+ server.args.length <= 100 &&
302
+ server.args.every(argument => typeof argument === "string" && argument.length <= 8_192) &&
303
+ (env === undefined ||
304
+ (typeof env === "object" &&
305
+ env !== null &&
306
+ !Array.isArray(env) &&
307
+ Object.keys(env).length <= 100 &&
308
+ Object.entries(env).every(
309
+ ([name, envValue]) =>
310
+ /^[A-Za-z_][A-Za-z0-9_]*$/.test(name) && typeof envValue === "string" && envValue.length <= 32_768,
311
+ )))
312
+ );
313
+ }
314
+
315
+ function isSessionLifecycleMcpServers(value: unknown): value is SessionLifecycleMcpServer[] {
316
+ return (
317
+ Array.isArray(value) &&
318
+ value.length <= 64 &&
319
+ value.every(isSessionLifecycleMcpServer) &&
320
+ new Set(value.map(server => server.name)).size === value.length
321
+ );
322
+ }
323
+
251
324
  export function readSessionLifecycleLaunchRequest(
252
325
  value: string | undefined,
253
326
  now = Date.now(),
@@ -278,6 +351,7 @@ export function readSessionLifecycleLaunchRequest(
278
351
  (request.effectMarker !== undefined &&
279
352
  (typeof request.effectMarker !== "string" || !/^[A-Za-z0-9._-]{1,128}$/.test(request.effectMarker))) ||
280
353
  (request.modelPreset !== undefined && (typeof request.modelPreset !== "string" || !request.modelPreset)) ||
354
+ (request.mcpServers !== undefined && !isSessionLifecycleMcpServers(request.mcpServers)) ||
281
355
  !hasValidLifecycleDeadlines(
282
356
  {
283
357
  receivedAt: request.receivedAt as number,
@@ -310,6 +384,7 @@ type SessionLaunch = {
310
384
  sessionPath?: string;
311
385
  sessionIdentity?: SessionLifecycleTranscriptIdentity;
312
386
  modelPreset?: string;
387
+ mcpServers?: SessionLifecycleMcpServer[];
313
388
  worktree?: SessionLifecycleWorktreeTarget;
314
389
  worktreePlan?: GjcLaunchWorktreePlan;
315
390
  };
@@ -2299,9 +2374,12 @@ async function launchInput(
2299
2374
  if (input.modelPreset !== undefined && (typeof input.modelPreset !== "string" || input.modelPreset.length === 0))
2300
2375
  return fail("invalid_input", "modelPreset must be a non-empty exact profile ID.");
2301
2376
  const modelPreset = text(input.modelPreset);
2377
+ if (input.mcpServers !== undefined && !isSessionLifecycleMcpServers(input.mcpServers))
2378
+ return fail("invalid_input", "mcpServers must contain unique valid stdio, HTTP, or SSE server definitions.");
2379
+ const mcpServers = input.mcpServers as SessionLifecycleMcpServer[] | undefined;
2302
2380
 
2303
2381
  if (operation === "session.create")
2304
- return { id: randomUUID(), cwd, root: resolvedRoot, modelPreset, worktree, worktreePlan };
2382
+ return { id: randomUUID(), cwd, root: resolvedRoot, modelPreset, mcpServers, worktree, worktreePlan };
2305
2383
  if (operation === "session.resume") {
2306
2384
  if (!requested) return fail("invalid_input", "sessionId is required to resume a saved session.");
2307
2385
  const savedPath = text(input.sessionPath);
@@ -2315,6 +2393,7 @@ async function launchInput(
2315
2393
  sessionPath: saved.path,
2316
2394
  sessionIdentity: saved.identity,
2317
2395
  modelPreset,
2396
+ mcpServers,
2318
2397
  worktree,
2319
2398
  worktreePlan,
2320
2399
  };
@@ -2336,6 +2415,7 @@ async function launchInput(
2336
2415
  sourceSessionIdentity: source.identity,
2337
2416
  sourceCwd,
2338
2417
  modelPreset,
2418
+ mcpServers,
2339
2419
  worktree,
2340
2420
  worktreePlan,
2341
2421
  };
@@ -2805,6 +2885,7 @@ async function executeLifecycleResponse(
2805
2885
  ...(launch.sessionPath ? { sessionPath: launch.sessionPath } : {}),
2806
2886
  ...(launch.sessionIdentity ? { sessionIdentity: launch.sessionIdentity } : {}),
2807
2887
  ...(launch.modelPreset ? { modelPreset: launch.modelPreset } : {}),
2888
+ ...(launch.mcpServers ? { mcpServers: launch.mcpServers } : {}),
2808
2889
  ...(launch.worktree ? { worktree: launch.worktree } : {}),
2809
2890
  };
2810
2891
  let child: ChildProcess | undefined;
@@ -67,7 +67,7 @@ async function loadConfig(agentDir: string, kind: ChatDaemonKind): Promise<ChatD
67
67
  idleTimeoutMs: 60_000,
68
68
  rich: { enabled: true },
69
69
  richDraft: { enabled: false },
70
- toolActivity: { enabled: true },
70
+ toolActivity: { enabled: false },
71
71
  topics: { nameTemplate: undefined },
72
72
  btw: { enabled: true },
73
73
  streaming: { enabled: true },
@@ -102,7 +102,7 @@ async function loadConfig(agentDir: string, kind: ChatDaemonKind): Promise<ChatD
102
102
  idleTimeoutMs: 60_000,
103
103
  rich: { enabled: true },
104
104
  richDraft: { enabled: false },
105
- toolActivity: { enabled: true },
105
+ toolActivity: { enabled: false },
106
106
  topics: { nameTemplate: undefined },
107
107
  btw: { enabled: true },
108
108
  streaming: { enabled: true },
@@ -34,11 +34,12 @@ export type ChatDaemonAction = "stop" | "reload";
34
34
  * concrete detached quarantine plus a proven-absent canonical lock pathname —
35
35
  * when deleting an observed owner-lock lease. Generation 12 refreshes retained
36
36
  * native path and process authority semantics. Generation 13 rejects special
37
- * files before retained native authority opens.
37
+ * files before retained native authority opens. Generation 14 reloads shared
38
+ * chat daemons after notification configuration parsing changes.
38
39
  */
39
40
  export const CHAT_DAEMON_GENERATIONS: Readonly<Record<ChatDaemonKind, number>> = {
40
- discord: 13,
41
- slack: 13,
41
+ discord: 14,
42
+ slack: 14,
42
43
  };
43
44
 
44
45
  export function chatDaemonGeneration(kind: ChatDaemonKind): number {
@@ -170,7 +170,7 @@ export function parseNotificationSettingsSnapshot(rawConfig?: unknown): Notifica
170
170
  enabled: notificationSettingsBoolean(richDraft.enabled, false),
171
171
  },
172
172
  toolActivity: {
173
- enabled: notificationSettingsBoolean(toolActivity.enabled, true),
173
+ enabled: notificationSettingsBoolean(toolActivity.enabled, false),
174
174
  },
175
175
  streaming: {
176
176
  enabled: notificationSettingsBoolean(streaming.enabled, true),