@0xmaxma/claude-gateway 1.6.9 → 1.7.1

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 (216) hide show
  1. package/README.md +149 -20
  2. package/config.template.json +59 -1
  3. package/dist/agent/dreaming/accept.d.ts +43 -0
  4. package/dist/agent/dreaming/accept.d.ts.map +1 -0
  5. package/dist/agent/dreaming/accept.js +230 -0
  6. package/dist/agent/dreaming/accept.js.map +1 -0
  7. package/dist/agent/dreaming/applier.d.ts +77 -0
  8. package/dist/agent/dreaming/applier.d.ts.map +1 -0
  9. package/dist/agent/dreaming/applier.js +406 -0
  10. package/dist/agent/dreaming/applier.js.map +1 -0
  11. package/dist/agent/dreaming/audit.d.ts +27 -0
  12. package/dist/agent/dreaming/audit.d.ts.map +1 -0
  13. package/dist/agent/dreaming/audit.js +100 -0
  14. package/dist/agent/dreaming/audit.js.map +1 -0
  15. package/dist/agent/dreaming/compactor.d.ts +66 -0
  16. package/dist/agent/dreaming/compactor.d.ts.map +1 -0
  17. package/dist/agent/dreaming/compactor.js +306 -0
  18. package/dist/agent/dreaming/compactor.js.map +1 -0
  19. package/dist/agent/dreaming/config.d.ts +19 -0
  20. package/dist/agent/dreaming/config.d.ts.map +1 -0
  21. package/dist/agent/dreaming/config.js +107 -0
  22. package/dist/agent/dreaming/config.js.map +1 -0
  23. package/dist/agent/dreaming/episodic.d.ts +42 -0
  24. package/dist/agent/dreaming/episodic.d.ts.map +1 -0
  25. package/dist/agent/dreaming/episodic.js +116 -0
  26. package/dist/agent/dreaming/episodic.js.map +1 -0
  27. package/dist/agent/dreaming/gather.d.ts +31 -0
  28. package/dist/agent/dreaming/gather.d.ts.map +1 -0
  29. package/dist/agent/dreaming/gather.js +55 -0
  30. package/dist/agent/dreaming/gather.js.map +1 -0
  31. package/dist/agent/dreaming/index.d.ts +87 -0
  32. package/dist/agent/dreaming/index.d.ts.map +1 -0
  33. package/dist/agent/dreaming/index.js +377 -0
  34. package/dist/agent/dreaming/index.js.map +1 -0
  35. package/dist/agent/dreaming/migrate-cli.d.ts +17 -0
  36. package/dist/agent/dreaming/migrate-cli.d.ts.map +1 -0
  37. package/dist/agent/dreaming/migrate-cli.js +42 -0
  38. package/dist/agent/dreaming/migrate-cli.js.map +1 -0
  39. package/dist/agent/dreaming/migrate.d.ts +72 -0
  40. package/dist/agent/dreaming/migrate.d.ts.map +1 -0
  41. package/dist/agent/dreaming/migrate.js +374 -0
  42. package/dist/agent/dreaming/migrate.js.map +1 -0
  43. package/dist/agent/dreaming/report.d.ts +39 -0
  44. package/dist/agent/dreaming/report.d.ts.map +1 -0
  45. package/dist/agent/dreaming/report.js +121 -0
  46. package/dist/agent/dreaming/report.js.map +1 -0
  47. package/dist/agent/dreaming/reviewer.d.ts +43 -0
  48. package/dist/agent/dreaming/reviewer.d.ts.map +1 -0
  49. package/dist/agent/dreaming/reviewer.js +249 -0
  50. package/dist/agent/dreaming/reviewer.js.map +1 -0
  51. package/dist/agent/dreaming/staleness.d.ts +68 -0
  52. package/dist/agent/dreaming/staleness.d.ts.map +1 -0
  53. package/dist/agent/dreaming/staleness.js +281 -0
  54. package/dist/agent/dreaming/staleness.js.map +1 -0
  55. package/dist/agent/dreaming/types.d.ts +130 -0
  56. package/dist/agent/dreaming/types.d.ts.map +1 -0
  57. package/dist/agent/dreaming/types.js +10 -0
  58. package/dist/agent/dreaming/types.js.map +1 -0
  59. package/dist/agent/knowledge/archive-db.d.ts +114 -0
  60. package/dist/agent/knowledge/archive-db.d.ts.map +1 -0
  61. package/dist/agent/knowledge/archive-db.js +474 -0
  62. package/dist/agent/knowledge/archive-db.js.map +1 -0
  63. package/dist/agent/knowledge/chunk.d.ts +21 -0
  64. package/dist/agent/knowledge/chunk.d.ts.map +1 -0
  65. package/dist/agent/knowledge/chunk.js +67 -0
  66. package/dist/agent/knowledge/chunk.js.map +1 -0
  67. package/dist/agent/knowledge/config.d.ts +20 -0
  68. package/dist/agent/knowledge/config.d.ts.map +1 -0
  69. package/dist/agent/knowledge/config.js +143 -0
  70. package/dist/agent/knowledge/config.js.map +1 -0
  71. package/dist/agent/knowledge/graph-demo.d.ts +25 -0
  72. package/dist/agent/knowledge/graph-demo.d.ts.map +1 -0
  73. package/dist/agent/knowledge/graph-demo.js +132 -0
  74. package/dist/agent/knowledge/graph-demo.js.map +1 -0
  75. package/dist/agent/knowledge/index.d.ts +24 -0
  76. package/dist/agent/knowledge/index.d.ts.map +1 -0
  77. package/dist/agent/knowledge/index.js +50 -0
  78. package/dist/agent/knowledge/index.js.map +1 -0
  79. package/dist/agent/knowledge/indexer.d.ts +34 -0
  80. package/dist/agent/knowledge/indexer.d.ts.map +1 -0
  81. package/dist/agent/knowledge/indexer.js +271 -0
  82. package/dist/agent/knowledge/indexer.js.map +1 -0
  83. package/dist/agent/knowledge/lifecycle.d.ts +91 -0
  84. package/dist/agent/knowledge/lifecycle.d.ts.map +1 -0
  85. package/dist/agent/knowledge/lifecycle.js +205 -0
  86. package/dist/agent/knowledge/lifecycle.js.map +1 -0
  87. package/dist/agent/knowledge/provenance.d.ts +15 -0
  88. package/dist/agent/knowledge/provenance.d.ts.map +1 -0
  89. package/dist/agent/knowledge/provenance.js +37 -0
  90. package/dist/agent/knowledge/provenance.js.map +1 -0
  91. package/dist/agent/knowledge/reindex-cli.d.ts +13 -0
  92. package/dist/agent/knowledge/reindex-cli.d.ts.map +1 -0
  93. package/dist/agent/knowledge/reindex-cli.js +53 -0
  94. package/dist/agent/knowledge/reindex-cli.js.map +1 -0
  95. package/dist/agent/knowledge/reindex-spawn.d.ts +30 -0
  96. package/dist/agent/knowledge/reindex-spawn.d.ts.map +1 -0
  97. package/dist/agent/knowledge/reindex-spawn.js +97 -0
  98. package/dist/agent/knowledge/reindex-spawn.js.map +1 -0
  99. package/dist/agent/knowledge/shared-promote.d.ts +18 -0
  100. package/dist/agent/knowledge/shared-promote.d.ts.map +1 -0
  101. package/dist/agent/knowledge/shared-promote.js +29 -0
  102. package/dist/agent/knowledge/shared-promote.js.map +1 -0
  103. package/dist/agent/knowledge/shared-writer.d.ts +24 -0
  104. package/dist/agent/knowledge/shared-writer.d.ts.map +1 -0
  105. package/dist/agent/knowledge/shared-writer.js +97 -0
  106. package/dist/agent/knowledge/shared-writer.js.map +1 -0
  107. package/dist/agent/knowledge/types.d.ts +83 -0
  108. package/dist/agent/knowledge/types.d.ts.map +1 -0
  109. package/dist/agent/knowledge/types.js +12 -0
  110. package/dist/agent/knowledge/types.js.map +1 -0
  111. package/dist/agent/knowledge/wiki.d.ts +107 -0
  112. package/dist/agent/knowledge/wiki.d.ts.map +1 -0
  113. package/dist/agent/knowledge/wiki.js +415 -0
  114. package/dist/agent/knowledge/wiki.js.map +1 -0
  115. package/dist/agent/memory-metrics.d.ts +48 -0
  116. package/dist/agent/memory-metrics.d.ts.map +1 -0
  117. package/dist/agent/memory-metrics.js +156 -0
  118. package/dist/agent/memory-metrics.js.map +1 -0
  119. package/dist/agent/runner.d.ts +34 -1
  120. package/dist/agent/runner.d.ts.map +1 -1
  121. package/dist/agent/runner.js +223 -19
  122. package/dist/agent/runner.js.map +1 -1
  123. package/dist/agent/skill-learning/config.d.ts +18 -0
  124. package/dist/agent/skill-learning/config.d.ts.map +1 -0
  125. package/dist/agent/skill-learning/config.js +71 -0
  126. package/dist/agent/skill-learning/config.js.map +1 -0
  127. package/dist/agent/skill-learning/curator.d.ts +45 -0
  128. package/dist/agent/skill-learning/curator.d.ts.map +1 -0
  129. package/dist/agent/skill-learning/curator.js +171 -0
  130. package/dist/agent/skill-learning/curator.js.map +1 -0
  131. package/dist/agent/skill-learning/index.d.ts +79 -0
  132. package/dist/agent/skill-learning/index.d.ts.map +1 -0
  133. package/dist/agent/skill-learning/index.js +308 -0
  134. package/dist/agent/skill-learning/index.js.map +1 -0
  135. package/dist/agent/skill-learning/metrics.d.ts +13 -0
  136. package/dist/agent/skill-learning/metrics.d.ts.map +1 -0
  137. package/dist/agent/skill-learning/metrics.js +109 -0
  138. package/dist/agent/skill-learning/metrics.js.map +1 -0
  139. package/dist/agent/skill-learning/notifier.d.ts +111 -0
  140. package/dist/agent/skill-learning/notifier.d.ts.map +1 -0
  141. package/dist/agent/skill-learning/notifier.js +398 -0
  142. package/dist/agent/skill-learning/notifier.js.map +1 -0
  143. package/dist/agent/skill-learning/reviewer.d.ts +61 -0
  144. package/dist/agent/skill-learning/reviewer.d.ts.map +1 -0
  145. package/dist/agent/skill-learning/reviewer.js +271 -0
  146. package/dist/agent/skill-learning/reviewer.js.map +1 -0
  147. package/dist/agent/skill-learning/telemetry.d.ts +22 -0
  148. package/dist/agent/skill-learning/telemetry.d.ts.map +1 -0
  149. package/dist/agent/skill-learning/telemetry.js +90 -0
  150. package/dist/agent/skill-learning/telemetry.js.map +1 -0
  151. package/dist/agent/skill-learning/trigger.d.ts +23 -0
  152. package/dist/agent/skill-learning/trigger.d.ts.map +1 -0
  153. package/dist/agent/skill-learning/trigger.js +44 -0
  154. package/dist/agent/skill-learning/trigger.js.map +1 -0
  155. package/dist/agent/skill-learning/types.d.ts +165 -0
  156. package/dist/agent/skill-learning/types.d.ts.map +1 -0
  157. package/dist/agent/skill-learning/types.js +11 -0
  158. package/dist/agent/skill-learning/types.js.map +1 -0
  159. package/dist/agent/skill-learning/writer.d.ts +37 -0
  160. package/dist/agent/skill-learning/writer.d.ts.map +1 -0
  161. package/dist/agent/skill-learning/writer.js +223 -0
  162. package/dist/agent/skill-learning/writer.js.map +1 -0
  163. package/dist/agent/workspace-loader.d.ts +83 -6
  164. package/dist/agent/workspace-loader.d.ts.map +1 -1
  165. package/dist/agent/workspace-loader.js +207 -14
  166. package/dist/agent/workspace-loader.js.map +1 -1
  167. package/dist/api/gateway-router.d.ts +2 -0
  168. package/dist/api/gateway-router.d.ts.map +1 -1
  169. package/dist/api/gateway-router.js +293 -6
  170. package/dist/api/gateway-router.js.map +1 -1
  171. package/dist/api/skills-router.d.ts +2 -2
  172. package/dist/api/skills-router.d.ts.map +1 -1
  173. package/dist/api/skills-router.js +61 -1
  174. package/dist/api/skills-router.js.map +1 -1
  175. package/dist/apps/agent-manager.d.ts +7 -0
  176. package/dist/apps/agent-manager.d.ts.map +1 -1
  177. package/dist/apps/agent-manager.js +13 -1
  178. package/dist/apps/agent-manager.js.map +1 -1
  179. package/dist/config/migrator.d.ts +2 -0
  180. package/dist/config/migrator.d.ts.map +1 -1
  181. package/dist/config/migrator.js +72 -1
  182. package/dist/config/migrator.js.map +1 -1
  183. package/dist/history/cleanup.d.ts +7 -0
  184. package/dist/history/cleanup.d.ts.map +1 -1
  185. package/dist/history/cleanup.js +27 -0
  186. package/dist/history/cleanup.js.map +1 -1
  187. package/dist/history/db.d.ts +65 -0
  188. package/dist/history/db.d.ts.map +1 -1
  189. package/dist/history/db.js +261 -0
  190. package/dist/history/db.js.map +1 -1
  191. package/dist/index.js +122 -20
  192. package/dist/index.js.map +1 -1
  193. package/dist/session/process.d.ts +20 -0
  194. package/dist/session/process.d.ts.map +1 -1
  195. package/dist/session/process.js +128 -4
  196. package/dist/session/process.js.map +1 -1
  197. package/dist/skills/loader.d.ts +8 -0
  198. package/dist/skills/loader.d.ts.map +1 -1
  199. package/dist/skills/loader.js +29 -1
  200. package/dist/skills/loader.js.map +1 -1
  201. package/dist/types.d.ts +116 -0
  202. package/dist/types.d.ts.map +1 -1
  203. package/dist/ui/web-ui.d.ts.map +1 -1
  204. package/dist/ui/web-ui.js +1126 -3
  205. package/dist/ui/web-ui.js.map +1 -1
  206. package/mcp/package.json +2 -1
  207. package/mcp/server.ts +8 -2
  208. package/mcp/tools/image/module.ts +58 -7
  209. package/mcp/tools/memory/archive-reader.test.ts +212 -0
  210. package/mcp/tools/memory/archive-reader.ts +253 -0
  211. package/mcp/tools/memory/module.ts +152 -0
  212. package/mcp/tools/memory/retrieval-recorder.ts +66 -0
  213. package/mcp/tools/skills/module.ts +28 -0
  214. package/mcp/types.ts +9 -3
  215. package/package.json +1 -1
  216. package/resource/claude_gateway.svg +1038 -112
@@ -3,6 +3,7 @@ import { AgentConfig, GatewayConfig, Logger, ModelConfig, StreamEvent, ApiAttach
3
3
  import { type SkillRegistry } from '../skills';
4
4
  import { type CliChannel } from '../cli-viewer/pairing-store';
5
5
  import { HistoryDB } from '../history/db';
6
+ import type { SkillLearningManager } from './skill-learning';
6
7
  export declare const MAX_IMAGE_SIZE_BYTES: number;
7
8
  export declare const DEFAULT_MODELS: ModelConfig[];
8
9
  export declare const CHANNEL_COALESCE_WINDOW_MS = 1200;
@@ -57,6 +58,7 @@ export declare class AgentRunner extends EventEmitter {
57
58
  private readonly sessionHistory;
58
59
  private readonly apiChatIds;
59
60
  private skillRegistry;
61
+ private skillLearning?;
60
62
  private readonly configPath;
61
63
  private readonly historyDb;
62
64
  private readonly agentsBaseDir;
@@ -68,6 +70,9 @@ export declare class AgentRunner extends EventEmitter {
68
70
  */
69
71
  setSkillRegistry(registry: SkillRegistry): void;
70
72
  getSkillRegistry(): SkillRegistry;
73
+ /** Wire the skill-learning manager (planning-62). Optional; unset = feature off. */
74
+ setSkillLearning(manager: SkillLearningManager | undefined): void;
75
+ getSkillLearning(): SkillLearningManager | undefined;
71
76
  get workspacePath(): string;
72
77
  /**
73
78
  * Bind a local HTTP server that receives POST /channel from TelegramReceiver.
@@ -183,6 +188,16 @@ export declare class AgentRunner extends EventEmitter {
183
188
  */
184
189
  static remapImageParamsRefs(p: ImageParams | undefined, stagedPaths: readonly string[] | undefined, promotedPaths: readonly string[] | undefined): ImageParams | undefined;
185
190
  private static buildChannelXml;
191
+ /**
192
+ * Await a SessionProcess's in-flight crash-triggered auto-restart
193
+ * (scheduleRestart's setTimeout → spawnProcess) instead of handing back a
194
+ * process whose sendMessage() will silently no-op. Resolves once the new
195
+ * child is attached ('restarted'); rejects on a definitive restart failure
196
+ * ('restartFailed', or 'failed' once MAX_RESTARTS is exhausted) or, as a
197
+ * last resort, on SESSION_RESTART_WAIT_TIMEOUT_MS so a caller is never left
198
+ * hanging past that bound.
199
+ */
200
+ private waitForSessionRestart;
186
201
  private getOrSpawnSession;
187
202
  private spawnSession;
188
203
  static isApiBuiltinCommand(content: string): boolean;
@@ -289,10 +304,28 @@ export declare class AgentRunner extends EventEmitter {
289
304
  * restarted so the change reaches them on their next spawn. The recomposed
290
305
  * CLAUDE.md is already on disk, so a skipped busy session picks up the
291
306
  * change on its own next natural spawn.
307
+ * @param opts.deferIdle When true, idle sessions are NOT `stop()`ed now.
308
+ * Instead they are added to the runner-level `pendingRestarts` set, so each
309
+ * respawns cleanly on its next message (the same lossless mechanism used for
310
+ * the image-size-threshold restart) rather than being SIGKILLed mid-idle and
311
+ * losing its in-context state. Since CLAUDE.md is frozen-at-spawn, an idle
312
+ * bystander gains nothing from an immediate stop — the recomposed file
313
+ * applies on its next spawn either way. Use for agent-writable/identity and
314
+ * skills changes, where dropping an unrelated idle session is pure downside.
315
+ * NB: idle sessions are deferred via `pendingRestarts`, NOT
316
+ * `proc.markPendingRestart()` — the latter emits `deferredRestartReady`
317
+ * synchronously on an idle process, which stops it immediately (no deferral).
318
+ * @returns Counts of sessions handled: `immediate` (stopped now), `deferred`
319
+ * (armed to restart on next turn/message), `skipped` (left untouched).
292
320
  */
293
321
  restartOrDefer(opts?: {
294
322
  skipBusy?: boolean;
295
- }): Promise<void>;
323
+ deferIdle?: boolean;
324
+ }): Promise<{
325
+ immediate: number;
326
+ deferred: number;
327
+ skipped: number;
328
+ }>;
296
329
  /**
297
330
  * Format a timestamp as a human-readable age string (e.g. "5m ago", "2h ago").
298
331
  */
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"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"}
@@ -61,6 +61,7 @@ const screen_1 = require("../shell/screen");
61
61
  const db_1 = require("../history/db");
62
62
  const media_store_1 = require("../history/media-store");
63
63
  const cleanup_1 = require("../history/cleanup");
64
+ const knowledge_1 = require("./knowledge");
64
65
  const DEFAULT_IDLE_TIMEOUT_MINUTES = 30;
65
66
  const DEFAULT_MAX_CONCURRENT = 20;
66
67
  const ANTHROPIC_SOCKET_ERROR = 'socket connection was closed unexpectedly';
@@ -99,6 +100,11 @@ const MAX_API_IMAGES = 5;
99
100
  * CLI turn is still producing a result that must reach history, exactly like
100
101
  * the client-disconnect path. This cap bounds a genuinely hung turn. */
101
102
  const API_TIMEOUT_HARD_CAP_EXTRA_MS = 600000;
103
+ // Bound on getOrSpawnSession's wait for a crash-triggered auto-restart to land
104
+ // (session/process.ts's AUTO_RESTART_DELAY_MS is 5s, plus real CLI spawn time
105
+ // observed up to a few seconds more) — generous, but must not be the long
106
+ // API_TIMEOUT_HARD_CAP_EXTRA_MS chain: this is a pre-turn gap, not a turn.
107
+ const SESSION_RESTART_WAIT_TIMEOUT_MS = 20000;
102
108
  // Hard timeout for the one-shot local `claude -p` triage during recovery
103
109
  // (Epic #195, Phase 3b). A slow/hung triage collapses to a safe notify-only.
104
110
  const RECOVERY_TRIAGE_TIMEOUT_MS = 15000;
@@ -327,6 +333,13 @@ class AgentRunner extends events_1.EventEmitter {
327
333
  getSkillRegistry() {
328
334
  return this.skillRegistry;
329
335
  }
336
+ /** Wire the skill-learning manager (planning-62). Optional; unset = feature off. */
337
+ setSkillLearning(manager) {
338
+ this.skillLearning = manager;
339
+ }
340
+ getSkillLearning() {
341
+ return this.skillLearning;
342
+ }
330
343
  get workspacePath() {
331
344
  return this.agentConfig.workspace;
332
345
  }
@@ -481,6 +494,8 @@ class AgentRunner extends events_1.EventEmitter {
481
494
  failureClass: body.failureClass ?? null,
482
495
  turnKey: body.turnKey ?? chatId,
483
496
  };
497
+ // Skill-learning: an incident-driven recovery attempt on this chat's turn.
498
+ this.skillLearning?.onRecoveryFired(chatId);
484
499
  try {
485
500
  const result = await (0, recovery_executor_1.runRecovery)(req, {
486
501
  autoRecover,
@@ -952,15 +967,25 @@ class AgentRunner extends events_1.EventEmitter {
952
967
  ts: userTs,
953
968
  });
954
969
  }
955
- // Restart session before this turn if accumulated image size exceeded threshold
970
+ // Consume a deferred restart before this turn (armed by the image-size
971
+ // threshold, or by a workspace/skills change that deferred this idle
972
+ // session). Guard on isProcessing: this same chatId key can be driven by
973
+ // a web-UI live-view turn (sendMessageToSession) that does NOT hold
974
+ // turnActive, so the session may be mid-stream here. Stopping it would
975
+ // truncate that live turn — instead leave the flag armed and consume it
976
+ // on the next idle turn. In the normal channel flow the session is idle
977
+ // at this point (turnActive serialises channel turns), so the guard is a
978
+ // no-op and the restart proceeds as before.
956
979
  if (this.pendingRestarts.has(chatId)) {
957
980
  const existingSession = this.sessions.get(chatId);
958
- if (existingSession) {
959
- await existingSession.stop();
960
- this.sessions.delete(chatId);
981
+ if (!existingSession?.isProcessing) {
982
+ if (existingSession) {
983
+ await existingSession.stop();
984
+ this.sessions.delete(chatId);
985
+ }
986
+ this.pendingRestarts.delete(chatId);
987
+ this.imageSizePerChat.delete(chatId);
961
988
  }
962
- this.pendingRestarts.delete(chatId);
963
- this.imageSizePerChat.delete(chatId);
964
989
  }
965
990
  // Route to session process (map key = chatId, actual sessionId passed separately)
966
991
  // Channel sessions use agent-level model (not per-session)
@@ -968,11 +993,13 @@ class AgentRunner extends events_1.EventEmitter {
968
993
  // Merge buffered messages into one turn: concat channel XML blocks, append
969
994
  // any skill context, and accumulate image paths for size tracking.
970
995
  const blocks = [];
996
+ const invokedSkills = [];
971
997
  for (const entry of entries) {
972
998
  let channelXml = AgentRunner.buildChannelXml(entry);
973
999
  const skillInvocation = (0, skills_1.detectSkillCommand)(entry.content ?? '', this.skillRegistry);
974
1000
  if (skillInvocation) {
975
1001
  channelXml += (0, skills_1.formatSkillContext)(skillInvocation);
1002
+ invokedSkills.push(skillInvocation.skillKey);
976
1003
  this.logger.info('Skill invoked', {
977
1004
  skill: skillInvocation.skillKey,
978
1005
  args: skillInvocation.args,
@@ -998,6 +1025,8 @@ class AgentRunner extends events_1.EventEmitter {
998
1025
  }
999
1026
  session.setProcessing(true);
1000
1027
  const turnText = blocks.join('\n');
1028
+ // Skill-learning: mark the start of a user turn (cheap, best-effort).
1029
+ this.skillLearning?.onTurnStart(chatId, sessionId, entries[0]?.content ?? '', invokedSkills);
1001
1030
  session.sendMessage(turnText);
1002
1031
  // Remember this turn for the C1 guarded resend (Phase 3b): reset the
1003
1032
  // delivered/resent flags so a resend can only fire if this turn stalls
@@ -1138,6 +1167,37 @@ class AgentRunner extends events_1.EventEmitter {
1138
1167
  `message_id="${meta['message_id'] ?? ''}" user="${AgentRunner.escapeXmlAttr(meta['user'] ?? '')}" ` +
1139
1168
  `ts="${meta['ts'] ?? new Date().toISOString()}"${optionalAttrs}>${repliedBlock}${params.content ?? ''}</channel>`);
1140
1169
  }
1170
+ /**
1171
+ * Await a SessionProcess's in-flight crash-triggered auto-restart
1172
+ * (scheduleRestart's setTimeout → spawnProcess) instead of handing back a
1173
+ * process whose sendMessage() will silently no-op. Resolves once the new
1174
+ * child is attached ('restarted'); rejects on a definitive restart failure
1175
+ * ('restartFailed', or 'failed' once MAX_RESTARTS is exhausted) or, as a
1176
+ * last resort, on SESSION_RESTART_WAIT_TIMEOUT_MS so a caller is never left
1177
+ * hanging past that bound.
1178
+ */
1179
+ waitForSessionRestart(proc) {
1180
+ if (proc.isRunning())
1181
+ return Promise.resolve();
1182
+ return new Promise((resolve, reject) => {
1183
+ const timer = setTimeout(() => {
1184
+ cleanup();
1185
+ reject(new Error('Session restart did not complete in time'));
1186
+ }, SESSION_RESTART_WAIT_TIMEOUT_MS);
1187
+ const onRestarted = () => { cleanup(); resolve(); };
1188
+ const onRestartFailed = (err) => { cleanup(); reject(err); };
1189
+ const onFailed = () => { cleanup(); reject(new Error('Session failed permanently (max restarts exceeded)')); };
1190
+ const cleanup = () => {
1191
+ clearTimeout(timer);
1192
+ proc.off('restarted', onRestarted);
1193
+ proc.off('restartFailed', onRestartFailed);
1194
+ proc.off('failed', onFailed);
1195
+ };
1196
+ proc.once('restarted', onRestarted);
1197
+ proc.once('restartFailed', onRestartFailed);
1198
+ proc.once('failed', onFailed);
1199
+ });
1200
+ }
1141
1201
  async getOrSpawnSession(mapKey, // Map lookup key (chatId for telegram/discord, sessionId for API)
1142
1202
  source, sessionId, // actual session UUID (only for channel sessions; equals mapKey for API)
1143
1203
  modelOverride) {
@@ -1153,6 +1213,19 @@ class AgentRunner extends events_1.EventEmitter {
1153
1213
  return pending;
1154
1214
  const existing = this.sessions.get(mapKey);
1155
1215
  if (existing) {
1216
+ // The mapped SessionProcess can be mid auto-restart (its child crashed —
1217
+ // see the 'exit'/scheduleRestart cycle in session/process.ts — and the
1218
+ // AUTO_RESTART_DELAY_MS timer hasn't fired the replacement child yet).
1219
+ // existing.sendMessage() silently no-ops while .process is null (only a
1220
+ // warning log, no error, no event), which previously left the caller's
1221
+ // pendingApiSessions entry stuck until the long timeout chain (the same
1222
+ // failure mode this whole area was already patched for — see the
1223
+ // session.on('exit', onExit) fix in sendApiMessage/sendApiMessageStream —
1224
+ // but THIS gap is hit before a turn even starts, so that fix can't see
1225
+ // it). Wait for the pending respawn to actually land before handing the
1226
+ // session back.
1227
+ if (!existing.isRunning())
1228
+ await this.waitForSessionRestart(existing);
1156
1229
  // Restart if model changed (including switching back to the agent default)
1157
1230
  if (existing.modelOverride !== effectiveOverride) {
1158
1231
  this.logger.info('Model changed, restarting session', { mapKey, oldModel: existing.modelOverride, newModel: effectiveOverride ?? agentDefaultModel });
@@ -1204,6 +1277,9 @@ class AgentRunner extends events_1.EventEmitter {
1204
1277
  // Apply per-session model override (caller already normalized to undefined when == agent default)
1205
1278
  if (modelOverride)
1206
1279
  proc.modelOverride = modelOverride;
1280
+ // Keep the searchable memory archive (planning-64) fresh for the memory_search
1281
+ // tool. Fire-and-forget, detached, OFF the event loop — never blocks the spawn.
1282
+ (0, knowledge_1.spawnArchiveReindex)(this.agentConfig.workspace, this.agentConfig.knowledge, this.gatewayConfig.gateway.knowledge);
1207
1283
  // Per-agent → global → MAX_HISTORY_MESSAGES: the configured cap on how many
1208
1284
  // history messages a healthy spawn re-injects. Lets an operator lower the
1209
1285
  // context loaded at session start (e.g. 50 → 30) without touching code.
@@ -1293,6 +1369,12 @@ class AgentRunner extends events_1.EventEmitter {
1293
1369
  const msg = obj['message'];
1294
1370
  if (Array.isArray(msg?.content)) {
1295
1371
  for (const block of msg.content) {
1372
+ // Skill-learning: count every tool_use this turn (deduped by block
1373
+ // id inside the manager, since cumulative assistant snapshots re-emit
1374
+ // completed blocks). Cheap, best-effort.
1375
+ if (block.type === 'tool_use') {
1376
+ this.skillLearning?.onToolUse(mapKey, block['id']);
1377
+ }
1296
1378
  // LINE sends images through its own line_image tool (not the reply
1297
1379
  // tool's `files`), so capture those sends into history too — the
1298
1380
  // web transcript and the session image catalog key off mediaFiles.
@@ -1426,6 +1508,13 @@ class AgentRunner extends events_1.EventEmitter {
1426
1508
  }
1427
1509
  if (obj['type'] === 'result') {
1428
1510
  proc.setProcessing(false);
1511
+ // Skill-learning: on the headless backend `result` is the true
1512
+ // end-of-user-turn (exactly one per message) — persist the turn metric
1513
+ // here. pty-shell fires `result` per sub-turn, so its capture is driven
1514
+ // by `session_idle` (below) to avoid over-counting.
1515
+ if (proc.backend !== 'pty-shell') {
1516
+ this.skillLearning?.onTurnEnd(mapKey, actualSessionId);
1517
+ }
1429
1518
  // Gateway turn queue: on the headless backend `result` is the true end
1430
1519
  // of the user's turn (exactly one per message), so flush the next
1431
1520
  // queued turn here. On pty-shell `result` fires per sub-turn (across
@@ -1579,6 +1668,8 @@ class AgentRunner extends events_1.EventEmitter {
1579
1668
  if (!proc.hasPendingRestart()) {
1580
1669
  this.flushNextTurn(mapKey);
1581
1670
  }
1671
+ // Skill-learning: pty-shell session_idle is the true end-of-user-turn.
1672
+ this.skillLearning?.onTurnEnd(mapKey, actualSessionId);
1582
1673
  typingDoneTimer = setTimeout(() => {
1583
1674
  this.writeTypingDone(mapKey);
1584
1675
  typingDoneTimer = null;
@@ -1591,6 +1682,7 @@ class AgentRunner extends events_1.EventEmitter {
1591
1682
  // Use actualSessionId (captured at spawn time) — NOT getActiveSessionId() —
1592
1683
  // so tokens are attributed to the session that owns this process.
1593
1684
  proc.on('tokenUsage', async ({ inputTokens, totalTokens }) => {
1685
+ this.skillLearning?.onTokenUsage(mapKey, inputTokens, totalTokens);
1594
1686
  try {
1595
1687
  const ch = this.channelFor(mapKey);
1596
1688
  const index = await this.sessionStore.listSessions(this.agentConfig.id, mapKey, ch);
@@ -1958,6 +2050,8 @@ class AgentRunner extends events_1.EventEmitter {
1958
2050
  */
1959
2051
  handleRequestTooLarge(mapKey, proc) {
1960
2052
  proc.setProcessing(false);
2053
+ // Skill-learning: a recovery event this turn (feeds the trigger + recovery-rate measure).
2054
+ this.skillLearning?.onRecoveryFired(mapKey);
1961
2055
  // Recovery steps through the ladder rungs strictly below the configured cap;
1962
2056
  // the number of those rungs is how many shrink attempts exist before even the
1963
2057
  // smallest (0-history) spawn has been tried and still trips 32MB.
@@ -2012,9 +2106,23 @@ class AgentRunner extends events_1.EventEmitter {
2012
2106
  * restarted so the change reaches them on their next spawn. The recomposed
2013
2107
  * CLAUDE.md is already on disk, so a skipped busy session picks up the
2014
2108
  * change on its own next natural spawn.
2109
+ * @param opts.deferIdle When true, idle sessions are NOT `stop()`ed now.
2110
+ * Instead they are added to the runner-level `pendingRestarts` set, so each
2111
+ * respawns cleanly on its next message (the same lossless mechanism used for
2112
+ * the image-size-threshold restart) rather than being SIGKILLed mid-idle and
2113
+ * losing its in-context state. Since CLAUDE.md is frozen-at-spawn, an idle
2114
+ * bystander gains nothing from an immediate stop — the recomposed file
2115
+ * applies on its next spawn either way. Use for agent-writable/identity and
2116
+ * skills changes, where dropping an unrelated idle session is pure downside.
2117
+ * NB: idle sessions are deferred via `pendingRestarts`, NOT
2118
+ * `proc.markPendingRestart()` — the latter emits `deferredRestartReady`
2119
+ * synchronously on an idle process, which stops it immediately (no deferral).
2120
+ * @returns Counts of sessions handled: `immediate` (stopped now), `deferred`
2121
+ * (armed to restart on next turn/message), `skipped` (left untouched).
2015
2122
  */
2016
2123
  async restartOrDefer(opts) {
2017
2124
  const skipBusy = opts?.skipBusy ?? false;
2125
+ const deferIdle = opts?.deferIdle ?? false;
2018
2126
  let immediate = 0;
2019
2127
  let deferred = 0;
2020
2128
  let skipped = 0;
@@ -2028,6 +2136,22 @@ class AgentRunner extends events_1.EventEmitter {
2028
2136
  proc.markPendingRestart();
2029
2137
  deferred++;
2030
2138
  }
2139
+ else if (deferIdle && proc.source !== 'api') {
2140
+ // Lossless deferral for CHANNEL sessions only: leave the idle process
2141
+ // running and arm a restart on its next message (mirrors the
2142
+ // image-size-threshold path). Do NOT call proc.markPendingRestart() here
2143
+ // — on an idle process it fires deferredRestartReady immediately and
2144
+ // stops the session.
2145
+ //
2146
+ // Guard on source: `pendingRestarts` is consumed ONLY in injectTurn (the
2147
+ // channel turn path, keyed by chatId). api / __heartbeat__ sessions are
2148
+ // keyed by sessionId and never flow through injectTurn, so an entry armed
2149
+ // for them would never be consumed — it would leak in the Set and the
2150
+ // change would never reach the session. Fall through to an immediate stop
2151
+ // so those respawn fresh on their next use, exactly as before deferIdle.
2152
+ this.pendingRestarts.add(id);
2153
+ deferred++;
2154
+ }
2031
2155
  else {
2032
2156
  toStopNow.push(id);
2033
2157
  }
@@ -2041,6 +2165,7 @@ class AgentRunner extends events_1.EventEmitter {
2041
2165
  immediate++;
2042
2166
  }
2043
2167
  this.logger.info('restartOrDefer: sessions restarted', { immediate, deferred, skipped });
2168
+ return { immediate, deferred, skipped };
2044
2169
  }
2045
2170
  /**
2046
2171
  * Format a timestamp as a human-readable age string (e.g. "5m ago", "2h ago").
@@ -2439,17 +2564,31 @@ class AgentRunner extends events_1.EventEmitter {
2439
2564
  let quietTimer;
2440
2565
  // Track partial message text for delta computation (--include-partial-messages)
2441
2566
  let lastPartialText = '';
2442
- const done = (result) => {
2567
+ // Guards done/fail against a double-fire — e.g. onExit racing a 'result'
2568
+ // line that already settled this turn (see onExit below).
2569
+ let settled = false;
2570
+ const done = (result, interrupted = false) => {
2571
+ if (settled)
2572
+ return;
2573
+ settled = true;
2443
2574
  cleanup();
2444
2575
  const attachments = this.popApiAttachments(sessionId);
2576
+ const trimmed = result.trim();
2577
+ // A /stop that lands before any text or attachment came out of this turn
2578
+ // would otherwise persist nothing at all — the last committed message
2579
+ // stays the user's forever, and the web sidebar's "typing…" indicator
2580
+ // never clears (it only clears once the last message is from the
2581
+ // assistant). Same wording buildInitialPrompt uses to patch this same
2582
+ // dangling-turn shape for the next spawn's in-memory context.
2583
+ const finalText = !trimmed && !attachments.length && interrupted ? process_1.INTERRUPTED_NO_REPLY_TEXT : trimmed;
2445
2584
  // Persist assistant reply. Image-only replies (empty text but attachments
2446
2585
  // present) must also persist — otherwise the screenshot vanishes from history.
2447
- if (result.trim() || attachments.length) {
2586
+ if (finalText || attachments.length) {
2448
2587
  const apiAssistantTs = Date.now();
2449
2588
  this.sessionStore
2450
2589
  .appendMessage(this.agentConfig.id, sessionId, {
2451
2590
  role: 'assistant',
2452
- content: result.trim(),
2591
+ content: finalText,
2453
2592
  ts: apiAssistantTs,
2454
2593
  })
2455
2594
  .catch(() => { });
@@ -2458,14 +2597,17 @@ class AgentRunner extends events_1.EventEmitter {
2458
2597
  sessionId,
2459
2598
  source: 'api',
2460
2599
  role: 'assistant',
2461
- content: result.trim(),
2600
+ content: finalText,
2462
2601
  mediaFiles: attachments.length ? attachments.map((a) => `media/${a.relPath}`) : undefined,
2463
2602
  ts: apiAssistantTs,
2464
2603
  });
2465
2604
  }
2466
- resolve({ text: result.trim(), attachments });
2605
+ resolve({ text: finalText, attachments });
2467
2606
  };
2468
2607
  const fail = (err) => {
2608
+ if (settled)
2609
+ return;
2610
+ settled = true;
2469
2611
  // Terminal close for a turn that produced no result (#75): record it so
2470
2612
  // history does not end on a dangling user message, and drain the
2471
2613
  // attachment buffer so nothing leaks into the next turn.
@@ -2473,6 +2615,26 @@ class AgentRunner extends events_1.EventEmitter {
2473
2615
  cleanup();
2474
2616
  reject(err); // no-op when the soft timeout already rejected
2475
2617
  };
2618
+ // The subprocess died without ever emitting a final `result` line (crash,
2619
+ // an unexpected signal — distinct from a graceful /stop, whose SIGINT
2620
+ // handler still emits a terminal result before exiting, so `done()` wins
2621
+ // that race and this is a no-op). Without this, a mid-turn crash left
2622
+ // pendingApiSessions — and the caller's pending-response spinner — stuck
2623
+ // until the up-to-15-minute opts.timeoutMs + API_TIMEOUT_HARD_CAP_EXTRA_MS
2624
+ // safety net finally fired.
2625
+ //
2626
+ // If the exit followed a /stop (the CLI's SIGINT handler fell through to
2627
+ // default termination instead of flushing a result line), that's a
2628
+ // successful stop, not a crash — resolve like the graceful path instead
2629
+ // of surfacing "process exited unexpectedly" for a stop the user asked for.
2630
+ const onExit = () => {
2631
+ const interrupted = session.consumeInterruptFlag();
2632
+ if (interrupted) {
2633
+ done(buffer.join(''), true);
2634
+ return;
2635
+ }
2636
+ fail(Object.assign(new Error('Session process exited unexpectedly before responding.'), { code: 'PROCESS_EXITED' }));
2637
+ };
2476
2638
  const cleanup = () => {
2477
2639
  clearTimeout(globalTimer);
2478
2640
  if (hardCapTimer)
@@ -2480,12 +2642,13 @@ class AgentRunner extends events_1.EventEmitter {
2480
2642
  if (quietTimer)
2481
2643
  clearTimeout(quietTimer);
2482
2644
  session.off('output', onOutput);
2645
+ session.off('exit', onExit);
2483
2646
  this.pendingApiSessions.delete(sessionId);
2484
2647
  };
2485
2648
  const resetQuiet = () => {
2486
2649
  if (quietTimer)
2487
2650
  clearTimeout(quietTimer);
2488
- quietTimer = setTimeout(() => done(buffer.join('')), 2000);
2651
+ quietTimer = setTimeout(() => done(buffer.join(''), session.consumeInterruptFlag()), 2000);
2489
2652
  };
2490
2653
  const onOutput = (line) => {
2491
2654
  try {
@@ -2521,7 +2684,12 @@ class AgentRunner extends events_1.EventEmitter {
2521
2684
  // accumulated buffer (needed for non-Anthropic models e.g. OpenRouter,
2522
2685
  // which emit result:"" even though the text arrived via stream_event chunks).
2523
2686
  const resultText = obj['result'] || buffer.join('');
2524
- done(resultText);
2687
+ // Consumed here (rather than left for onExit) so the graceful path — a
2688
+ // result line flushed before the subprocess exits — still gets credit
2689
+ // for the interrupt; onExit's own consumeInterruptFlag() call would
2690
+ // otherwise see it already cleared and take the (harmless, settled-
2691
+ // guarded) fail() branch instead.
2692
+ done(resultText, session.consumeInterruptFlag());
2525
2693
  }
2526
2694
  }
2527
2695
  catch {
@@ -2541,6 +2709,7 @@ class AgentRunner extends events_1.EventEmitter {
2541
2709
  }, API_TIMEOUT_HARD_CAP_EXTRA_MS);
2542
2710
  }, opts.timeoutMs);
2543
2711
  session.on('output', onOutput);
2712
+ session.on('exit', onExit);
2544
2713
  session.setProcessing(true);
2545
2714
  session.sendMessage(channelXml);
2546
2715
  // Do NOT call resetQuiet() here — the quiet timer should only start
@@ -2621,21 +2790,29 @@ class AgentRunner extends events_1.EventEmitter {
2621
2790
  let lastPartialText = '';
2622
2791
  // Accumulate tool_use blocks from stream_event (content_block_start → delta → stop)
2623
2792
  const toolBlocks = new Map();
2624
- const done = (result) => {
2793
+ const done = (result, interrupted = false) => {
2625
2794
  if (settled)
2626
2795
  return;
2627
2796
  settled = true;
2628
2797
  cleanup();
2629
2798
  const attachments = this.popApiAttachments(sessionId);
2799
+ const trimmed = result.trim();
2800
+ // A /stop that lands before any text or attachment came out of this turn
2801
+ // would otherwise persist nothing at all — the last committed message
2802
+ // stays the user's forever, and the web sidebar's "typing…" indicator
2803
+ // never clears (it only clears once the last message is from the
2804
+ // assistant). Same wording buildInitialPrompt uses to patch this same
2805
+ // dangling-turn shape for the next spawn's in-memory context.
2806
+ const finalText = !trimmed && !attachments.length && interrupted ? process_1.INTERRUPTED_NO_REPLY_TEXT : trimmed;
2630
2807
  // Persist assistant reply regardless of whether the SSE client is still connected.
2631
2808
  // Image-only replies (empty text but attachments present) must also persist —
2632
2809
  // otherwise the screenshot vanishes from history once the stream ends.
2633
- if (result.trim() || attachments.length) {
2810
+ if (finalText || attachments.length) {
2634
2811
  const streamAssistantTs = Date.now();
2635
2812
  this.sessionStore
2636
2813
  .appendMessage(this.agentConfig.id, sessionId, {
2637
2814
  role: 'assistant',
2638
- content: result.trim(),
2815
+ content: finalText,
2639
2816
  ts: streamAssistantTs,
2640
2817
  })
2641
2818
  .catch(() => { });
@@ -2644,12 +2821,12 @@ class AgentRunner extends events_1.EventEmitter {
2644
2821
  sessionId,
2645
2822
  source: 'api',
2646
2823
  role: 'assistant',
2647
- content: result.trim(),
2824
+ content: finalText,
2648
2825
  mediaFiles: attachments.length ? attachments.map((a) => `media/${a.relPath}`) : undefined,
2649
2826
  ts: streamAssistantTs,
2650
2827
  });
2651
2828
  }
2652
- callbacks.onDone(result.trim(), attachments);
2829
+ callbacks.onDone(finalText, attachments);
2653
2830
  };
2654
2831
  const fail = (err) => {
2655
2832
  if (settled)
@@ -2663,11 +2840,32 @@ class AgentRunner extends events_1.EventEmitter {
2663
2840
  this.persistFailedApiTurn(chatId, sessionId, err, opts.skipUserMessage);
2664
2841
  notifyError(err);
2665
2842
  };
2843
+ // The subprocess died without ever emitting a final `result` line (crash,
2844
+ // an unexpected signal — distinct from a graceful /stop, whose SIGINT
2845
+ // handler still emits a terminal result before exiting, so `done()` wins
2846
+ // that race and this is a no-op via the `settled` guard in fail()).
2847
+ // Without this, a mid-turn crash left pendingApiSessions — and the web's
2848
+ // pending-response spinner — stuck until the up-to-15-minute
2849
+ // opts.timeoutMs + API_TIMEOUT_HARD_CAP_EXTRA_MS safety net finally fired.
2850
+ //
2851
+ // If the exit followed a /stop (the CLI's SIGINT handler fell through to
2852
+ // default termination instead of flushing a result line), that's a
2853
+ // successful stop, not a crash — resolve like the graceful path instead
2854
+ // of surfacing "process exited unexpectedly" for a stop the user asked for.
2855
+ const onExit = () => {
2856
+ const interrupted = session.consumeInterruptFlag();
2857
+ if (interrupted) {
2858
+ done(buffer.join(''), true);
2859
+ return;
2860
+ }
2861
+ fail(Object.assign(new Error('Session process exited unexpectedly before responding.'), { code: 'PROCESS_EXITED' }));
2862
+ };
2666
2863
  const cleanup = () => {
2667
2864
  clearTimeout(globalTimer);
2668
2865
  if (hardCapTimer)
2669
2866
  clearTimeout(hardCapTimer);
2670
2867
  session.off('output', onOutput);
2868
+ session.off('exit', onExit);
2671
2869
  this.pendingApiSessions.delete(sessionId);
2672
2870
  };
2673
2871
  // Called when the SSE client disconnects. Marks clientGone so SSE writes
@@ -2740,7 +2938,12 @@ class AgentRunner extends events_1.EventEmitter {
2740
2938
  lastPartialText = ''; // reset for next turn
2741
2939
  // Use || so empty-string result falls back to buffer (OpenRouter emits result:"").
2742
2940
  const resultText = obj['result'] || buffer.join('');
2743
- done(resultText);
2941
+ // Consumed here (rather than left for onExit) so the graceful path — a
2942
+ // result line flushed before the subprocess exits — still gets credit
2943
+ // for the interrupt; onExit's own consumeInterruptFlag() call would
2944
+ // otherwise see it already cleared and take the (harmless, settled-
2945
+ // guarded) fail() branch instead.
2946
+ done(resultText, session.consumeInterruptFlag());
2744
2947
  }
2745
2948
  }
2746
2949
  catch {
@@ -2769,6 +2972,7 @@ class AgentRunner extends events_1.EventEmitter {
2769
2972
  }, API_TIMEOUT_HARD_CAP_EXTRA_MS);
2770
2973
  }, opts.timeoutMs);
2771
2974
  session.on('output', onOutput);
2975
+ session.on('exit', onExit);
2772
2976
  // Image paths only work when allowTools:true — Claude needs the Read tool to access them
2773
2977
  const allowToolsStream = opts.allowTools ?? false;
2774
2978
  if (!allowToolsStream && imagePathsStream.length) {