@clinebot/core 0.0.35 → 0.0.36

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 (335) hide show
  1. package/README.md +1 -2
  2. package/dist/ClineCore.d.ts +53 -39
  3. package/dist/ClineCore.d.ts.map +1 -1
  4. package/dist/account/index.d.ts +1 -1
  5. package/dist/account/index.d.ts.map +1 -1
  6. package/dist/account/rpc.d.ts +6 -6
  7. package/dist/account/rpc.d.ts.map +1 -1
  8. package/dist/cron/index.d.ts +6 -0
  9. package/dist/cron/index.d.ts.map +1 -0
  10. package/dist/cron/resource-limiter.d.ts +9 -0
  11. package/dist/cron/resource-limiter.d.ts.map +1 -0
  12. package/dist/cron/schedule-command-service.d.ts +10 -0
  13. package/dist/cron/schedule-command-service.d.ts.map +1 -0
  14. package/dist/cron/schedule-service.d.ts +100 -0
  15. package/dist/cron/schedule-service.d.ts.map +1 -0
  16. package/dist/cron/scheduler.d.ts +66 -0
  17. package/dist/cron/scheduler.d.ts.map +1 -0
  18. package/dist/cron/sqlite-schedule-store.d.ts +52 -0
  19. package/dist/cron/sqlite-schedule-store.d.ts.map +1 -0
  20. package/dist/extensions/config/agent-config-loader.d.ts +4 -3
  21. package/dist/extensions/config/agent-config-loader.d.ts.map +1 -1
  22. package/dist/extensions/config/runtime-commands.d.ts +1 -0
  23. package/dist/extensions/config/runtime-commands.d.ts.map +1 -1
  24. package/dist/extensions/config/user-instruction-config-loader.d.ts +1 -0
  25. package/dist/extensions/config/user-instruction-config-loader.d.ts.map +1 -1
  26. package/dist/extensions/context/agentic-compaction.d.ts +2 -2
  27. package/dist/extensions/context/agentic-compaction.d.ts.map +1 -1
  28. package/dist/extensions/context/compaction-shared.d.ts +5 -4
  29. package/dist/extensions/context/compaction-shared.d.ts.map +1 -1
  30. package/dist/extensions/context/compaction.d.ts.map +1 -1
  31. package/dist/extensions/plugin/plugin-config-loader.d.ts +9 -2
  32. package/dist/extensions/plugin/plugin-config-loader.d.ts.map +1 -1
  33. package/dist/extensions/plugin/plugin-loader.d.ts +5 -3
  34. package/dist/extensions/plugin/plugin-loader.d.ts.map +1 -1
  35. package/dist/extensions/plugin/plugin-module-import.d.ts.map +1 -1
  36. package/dist/extensions/plugin/plugin-sandbox.d.ts +15 -2
  37. package/dist/extensions/plugin/plugin-sandbox.d.ts.map +1 -1
  38. package/dist/extensions/plugin/plugin-targeting.d.ts +7 -0
  39. package/dist/extensions/plugin/plugin-targeting.d.ts.map +1 -0
  40. package/dist/extensions/plugin-sandbox-bootstrap.js +211 -211
  41. package/dist/extensions/tools/definitions.d.ts +1 -1
  42. package/dist/extensions/tools/definitions.d.ts.map +1 -1
  43. package/dist/extensions/tools/executors/apply-patch.d.ts +3 -1
  44. package/dist/extensions/tools/executors/apply-patch.d.ts.map +1 -1
  45. package/dist/extensions/tools/executors/search.d.ts +1 -1
  46. package/dist/extensions/tools/executors/search.d.ts.map +1 -1
  47. package/dist/extensions/tools/index.d.ts +2 -0
  48. package/dist/extensions/tools/index.d.ts.map +1 -1
  49. package/dist/extensions/tools/presets.d.ts +26 -43
  50. package/dist/extensions/tools/presets.d.ts.map +1 -1
  51. package/dist/extensions/tools/runtime.d.ts +25 -0
  52. package/dist/extensions/tools/runtime.d.ts.map +1 -0
  53. package/dist/extensions/tools/schemas.d.ts.map +1 -1
  54. package/dist/extensions/tools/team/team-tools.d.ts +1 -0
  55. package/dist/extensions/tools/team/team-tools.d.ts.map +1 -1
  56. package/dist/hooks/hook-file-hooks.d.ts +4 -1
  57. package/dist/hooks/hook-file-hooks.d.ts.map +1 -1
  58. package/dist/hooks/index.d.ts +0 -1
  59. package/dist/hooks/index.d.ts.map +1 -1
  60. package/dist/hooks/subprocess.d.ts +8 -1
  61. package/dist/hooks/subprocess.d.ts.map +1 -1
  62. package/dist/hub/browser-websocket.d.ts +18 -0
  63. package/dist/hub/browser-websocket.d.ts.map +1 -0
  64. package/dist/hub/client.d.ts +45 -0
  65. package/dist/hub/client.d.ts.map +1 -0
  66. package/dist/hub/connect.d.ts +15 -0
  67. package/dist/hub/connect.d.ts.map +1 -0
  68. package/dist/hub/daemon-entry.d.ts +2 -0
  69. package/dist/hub/daemon-entry.d.ts.map +1 -0
  70. package/dist/hub/daemon-entry.js +1045 -0
  71. package/dist/hub/daemon.d.ts +5 -0
  72. package/dist/hub/daemon.d.ts.map +1 -0
  73. package/dist/hub/defaults.d.ts +13 -0
  74. package/dist/hub/defaults.d.ts.map +1 -0
  75. package/dist/hub/discovery.d.ts +29 -0
  76. package/dist/hub/discovery.d.ts.map +1 -0
  77. package/dist/hub/index.d.ts +15 -0
  78. package/dist/hub/index.d.ts.map +1 -0
  79. package/dist/hub/index.js +1044 -0
  80. package/dist/hub/native-transport.d.ts +17 -0
  81. package/dist/hub/native-transport.d.ts.map +1 -0
  82. package/dist/hub/runtime-handlers.d.ts +11 -0
  83. package/dist/hub/runtime-handlers.d.ts.map +1 -0
  84. package/dist/hub/server.d.ts +86 -0
  85. package/dist/hub/server.d.ts.map +1 -0
  86. package/dist/hub/session-client.d.ts +87 -0
  87. package/dist/hub/session-client.d.ts.map +1 -0
  88. package/dist/hub/start-shared-server.d.ts +19 -0
  89. package/dist/hub/start-shared-server.d.ts.map +1 -0
  90. package/dist/hub/transport.d.ts +8 -0
  91. package/dist/hub/transport.d.ts.map +1 -0
  92. package/dist/hub/ui-client.d.ts +44 -0
  93. package/dist/hub/ui-client.d.ts.map +1 -0
  94. package/dist/hub/workspace.d.ts +4 -0
  95. package/dist/hub/workspace.d.ts.map +1 -0
  96. package/dist/index.d.ts +26 -15
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +498 -476
  99. package/dist/llms/configured-provider-registry.d.ts +28 -0
  100. package/dist/llms/configured-provider-registry.d.ts.map +1 -0
  101. package/dist/llms/provider-defaults.d.ts +27 -0
  102. package/dist/llms/provider-defaults.d.ts.map +1 -0
  103. package/dist/llms/provider-settings.d.ts +202 -0
  104. package/dist/llms/provider-settings.d.ts.map +1 -0
  105. package/dist/llms/runtime-config.d.ts +4 -0
  106. package/dist/llms/runtime-config.d.ts.map +1 -0
  107. package/dist/llms/runtime-registry.d.ts +20 -0
  108. package/dist/llms/runtime-registry.d.ts.map +1 -0
  109. package/dist/llms/runtime-types.d.ts +85 -0
  110. package/dist/llms/runtime-types.d.ts.map +1 -0
  111. package/dist/runtime/host.d.ts +1 -2
  112. package/dist/runtime/host.d.ts.map +1 -1
  113. package/dist/runtime/rules.d.ts +1 -0
  114. package/dist/runtime/rules.d.ts.map +1 -1
  115. package/dist/runtime/runtime-builder.d.ts.map +1 -1
  116. package/dist/runtime/runtime-host.d.ts +22 -24
  117. package/dist/runtime/runtime-host.d.ts.map +1 -1
  118. package/dist/runtime/runtime-oauth-token-manager.d.ts.map +1 -1
  119. package/dist/runtime/session-runtime.d.ts +1 -19
  120. package/dist/runtime/session-runtime.d.ts.map +1 -1
  121. package/dist/services/global-settings.d.ts +12 -0
  122. package/dist/services/global-settings.d.ts.map +1 -0
  123. package/dist/services/local-runtime-bootstrap.d.ts +9 -3
  124. package/dist/services/local-runtime-bootstrap.d.ts.map +1 -1
  125. package/dist/services/plugin-tools.d.ts +16 -0
  126. package/dist/services/plugin-tools.d.ts.map +1 -0
  127. package/dist/services/providers/local-provider-registry.d.ts +4 -4
  128. package/dist/services/providers/local-provider-registry.d.ts.map +1 -1
  129. package/dist/services/providers/local-provider-service.d.ts +13 -13
  130. package/dist/services/providers/local-provider-service.d.ts.map +1 -1
  131. package/dist/services/session-data.d.ts +1 -1
  132. package/dist/services/session-data.d.ts.map +1 -1
  133. package/dist/services/storage/provider-settings-legacy-migration.d.ts +1 -1
  134. package/dist/services/storage/provider-settings-legacy-migration.d.ts.map +1 -1
  135. package/dist/services/telemetry/index.js +28 -15
  136. package/dist/services/workspace-manifest.d.ts +11 -0
  137. package/dist/services/workspace-manifest.d.ts.map +1 -1
  138. package/dist/session/persistence-service.d.ts +11 -23
  139. package/dist/session/persistence-service.d.ts.map +1 -1
  140. package/dist/session/session-manifest-store.d.ts +22 -0
  141. package/dist/session/session-manifest-store.d.ts.map +1 -0
  142. package/dist/session/session-row.d.ts +93 -0
  143. package/dist/session/session-row.d.ts.map +1 -0
  144. package/dist/session/session-service.d.ts +2 -102
  145. package/dist/session/session-service.d.ts.map +1 -1
  146. package/dist/session/subagent-session-manager.d.ts +36 -0
  147. package/dist/session/subagent-session-manager.d.ts.map +1 -0
  148. package/dist/session/team-persistence-store.d.ts +24 -0
  149. package/dist/session/team-persistence-store.d.ts.map +1 -0
  150. package/dist/transports/hub.d.ts +47 -0
  151. package/dist/transports/hub.d.ts.map +1 -0
  152. package/dist/transports/local.d.ts +10 -6
  153. package/dist/transports/local.d.ts.map +1 -1
  154. package/dist/transports/remote.d.ts +10 -0
  155. package/dist/transports/remote.d.ts.map +1 -0
  156. package/dist/transports/runtime-host-support.d.ts +3 -2
  157. package/dist/transports/runtime-host-support.d.ts.map +1 -1
  158. package/dist/types/chat-schema.d.ts +10 -12
  159. package/dist/types/chat-schema.d.ts.map +1 -1
  160. package/dist/types/config.d.ts +8 -7
  161. package/dist/types/config.d.ts.map +1 -1
  162. package/dist/types/provider-settings.d.ts +4 -5
  163. package/dist/types/provider-settings.d.ts.map +1 -1
  164. package/dist/types/session.d.ts +2 -1
  165. package/dist/types/session.d.ts.map +1 -1
  166. package/dist/types.d.ts +8 -1
  167. package/dist/types.d.ts.map +1 -1
  168. package/package.json +20 -6
  169. package/src/ClineCore.ts +68 -40
  170. package/src/account/index.ts +3 -3
  171. package/src/account/rpc.ts +12 -12
  172. package/src/cron/index.ts +5 -0
  173. package/src/cron/resource-limiter.ts +46 -0
  174. package/src/cron/schedule-command-service.ts +193 -0
  175. package/src/cron/schedule-service.ts +703 -0
  176. package/src/cron/scheduler.ts +637 -0
  177. package/src/cron/sqlite-schedule-store.ts +708 -0
  178. package/src/extensions/config/agent-config-loader.ts +17 -7
  179. package/src/extensions/config/runtime-commands.ts +6 -0
  180. package/src/extensions/config/user-instruction-config-loader.ts +1 -0
  181. package/src/extensions/context/agentic-compaction.ts +3 -3
  182. package/src/extensions/context/basic-compaction.ts +2 -2
  183. package/src/extensions/context/compaction-shared.ts +5 -4
  184. package/src/extensions/context/compaction.ts +3 -3
  185. package/src/extensions/plugin/plugin-config-loader.ts +17 -2
  186. package/src/extensions/plugin/plugin-loader.ts +48 -4
  187. package/src/extensions/plugin/plugin-module-import.ts +0 -2
  188. package/src/extensions/plugin/plugin-sandbox-bootstrap.ts +93 -39
  189. package/src/extensions/plugin/plugin-sandbox.ts +47 -27
  190. package/src/extensions/plugin/plugin-targeting.ts +32 -0
  191. package/src/extensions/tools/definitions.ts +30 -49
  192. package/src/extensions/tools/executors/apply-patch.ts +69 -80
  193. package/src/extensions/tools/executors/search.ts +195 -3
  194. package/src/extensions/tools/index.ts +10 -0
  195. package/src/extensions/tools/presets.ts +31 -46
  196. package/src/extensions/tools/runtime.ts +261 -0
  197. package/src/extensions/tools/schemas.ts +4 -2
  198. package/src/extensions/tools/team/team-tools.ts +21 -0
  199. package/src/hooks/hook-file-hooks.ts +8 -2
  200. package/src/hooks/index.ts +0 -7
  201. package/src/hooks/subprocess-runner.ts +1 -1
  202. package/src/hooks/subprocess.ts +9 -0
  203. package/src/hub/browser-websocket.ts +137 -0
  204. package/src/hub/client.ts +574 -0
  205. package/src/hub/connect.ts +156 -0
  206. package/src/hub/daemon-entry.ts +87 -0
  207. package/src/hub/daemon.ts +181 -0
  208. package/src/hub/defaults.ts +43 -0
  209. package/src/hub/discovery.ts +247 -0
  210. package/src/hub/index.ts +14 -0
  211. package/src/hub/native-transport.ts +31 -0
  212. package/src/hub/runtime-handlers.ts +140 -0
  213. package/src/hub/server.ts +1888 -0
  214. package/src/hub/session-client.ts +460 -0
  215. package/src/hub/start-shared-server.ts +58 -0
  216. package/src/hub/transport.ts +14 -0
  217. package/src/hub/ui-client.ts +122 -0
  218. package/src/hub/workspace.ts +19 -0
  219. package/src/index.ts +124 -68
  220. package/src/llms/configured-provider-registry.ts +193 -0
  221. package/src/llms/provider-defaults.ts +637 -0
  222. package/src/llms/provider-settings.ts +263 -0
  223. package/src/llms/runtime-config.ts +43 -0
  224. package/src/llms/runtime-registry.ts +171 -0
  225. package/src/llms/runtime-types.ts +121 -0
  226. package/src/runtime/host.ts +107 -269
  227. package/src/runtime/index.ts +1 -0
  228. package/src/runtime/rules.ts +12 -0
  229. package/src/runtime/runtime-builder.ts +24 -8
  230. package/src/runtime/runtime-host.ts +89 -61
  231. package/src/runtime/runtime-oauth-token-manager.ts +11 -15
  232. package/src/runtime/session-runtime.ts +0 -24
  233. package/src/services/global-settings.ts +122 -0
  234. package/src/services/local-runtime-bootstrap.ts +51 -13
  235. package/src/services/plugin-tools.ts +85 -0
  236. package/src/services/providers/local-provider-registry.ts +6 -6
  237. package/src/services/providers/local-provider-service.ts +42 -37
  238. package/src/services/session-data.ts +15 -9
  239. package/src/services/storage/provider-settings-legacy-migration.ts +6 -4
  240. package/src/services/storage/provider-settings-manager.ts +1 -1
  241. package/src/services/workspace-manifest.ts +18 -0
  242. package/src/session/file-session-service.ts +1 -1
  243. package/src/session/index.ts +6 -27
  244. package/src/session/persistence-service.ts +119 -504
  245. package/src/session/session-manifest-store.ts +158 -0
  246. package/src/session/session-row.ts +199 -0
  247. package/src/session/session-service.ts +17 -376
  248. package/src/session/session-team-coordination.ts +1 -1
  249. package/src/session/subagent-session-manager.ts +397 -0
  250. package/src/session/team-persistence-store.ts +176 -0
  251. package/src/transports/hub.ts +656 -0
  252. package/src/transports/local.ts +135 -40
  253. package/src/transports/remote.ts +26 -0
  254. package/src/transports/runtime-host-support.ts +63 -9
  255. package/src/types/chat-schema.ts +4 -5
  256. package/src/types/config.ts +8 -7
  257. package/src/types/provider-settings.ts +11 -7
  258. package/src/types/session.ts +2 -4
  259. package/src/types.ts +27 -1
  260. package/dist/hooks/persistent.d.ts +0 -64
  261. package/dist/hooks/persistent.d.ts.map +0 -1
  262. package/dist/runtime/rpc-runtime-ensure.d.ts +0 -65
  263. package/dist/runtime/rpc-runtime-ensure.d.ts.map +0 -1
  264. package/dist/runtime/rpc-spawn-lease.d.ts +0 -8
  265. package/dist/runtime/rpc-spawn-lease.d.ts.map +0 -1
  266. package/dist/session/rpc-session-service.d.ts +0 -16
  267. package/dist/session/rpc-session-service.d.ts.map +0 -1
  268. package/dist/session/sqlite-rpc-session-backend.d.ts +0 -31
  269. package/dist/session/sqlite-rpc-session-backend.d.ts.map +0 -1
  270. package/dist/transports/rpc.d.ts +0 -51
  271. package/dist/transports/rpc.d.ts.map +0 -1
  272. package/src/ClineCore.test.ts +0 -226
  273. package/src/account/cline-account-service.test.ts +0 -185
  274. package/src/account/featurebase-token.test.ts +0 -175
  275. package/src/account/rpc.test.ts +0 -63
  276. package/src/auth/bounded-ttl-cache.test.ts +0 -38
  277. package/src/auth/client.test.ts +0 -69
  278. package/src/auth/cline.test.ts +0 -267
  279. package/src/auth/codex.test.ts +0 -170
  280. package/src/auth/oca.test.ts +0 -340
  281. package/src/auth/server.test.ts +0 -287
  282. package/src/auth/utils.test.ts +0 -128
  283. package/src/extensions/config/agent-config-loader.test.ts +0 -236
  284. package/src/extensions/config/hooks-config-loader.test.ts +0 -20
  285. package/src/extensions/config/runtime-commands.test.ts +0 -115
  286. package/src/extensions/config/unified-config-file-watcher.test.ts +0 -196
  287. package/src/extensions/config/user-instruction-config-loader.test.ts +0 -246
  288. package/src/extensions/context/compaction.test.ts +0 -483
  289. package/src/extensions/mcp/config-loader.test.ts +0 -238
  290. package/src/extensions/mcp/manager.test.ts +0 -105
  291. package/src/extensions/plugin/plugin-config-loader.test.ts +0 -184
  292. package/src/extensions/plugin/plugin-loader.test.ts +0 -292
  293. package/src/extensions/plugin/plugin-sandbox.test.ts +0 -423
  294. package/src/extensions/tools/definitions.test.ts +0 -780
  295. package/src/extensions/tools/executors/bash.test.ts +0 -87
  296. package/src/extensions/tools/executors/editor.test.ts +0 -35
  297. package/src/extensions/tools/executors/file-read.test.ts +0 -125
  298. package/src/extensions/tools/model-tool-routing.test.ts +0 -86
  299. package/src/extensions/tools/presets.test.ts +0 -70
  300. package/src/extensions/tools/team/multi-agent.lifecycle.test.ts +0 -455
  301. package/src/extensions/tools/team/spawn-agent-tool.test.ts +0 -381
  302. package/src/extensions/tools/team/team-tools.test.ts +0 -918
  303. package/src/hooks/checkpoint-hooks.test.ts +0 -168
  304. package/src/hooks/hook-file-hooks.test.ts +0 -311
  305. package/src/hooks/persistent.ts +0 -661
  306. package/src/runtime/history.test.ts +0 -114
  307. package/src/runtime/host.test.ts +0 -230
  308. package/src/runtime/rpc-runtime-ensure.test.ts +0 -123
  309. package/src/runtime/rpc-runtime-ensure.ts +0 -659
  310. package/src/runtime/rpc-spawn-lease.test.ts +0 -81
  311. package/src/runtime/rpc-spawn-lease.ts +0 -156
  312. package/src/runtime/runtime-builder.team-persistence.test.ts +0 -245
  313. package/src/runtime/runtime-builder.test.ts +0 -615
  314. package/src/runtime/runtime-oauth-token-manager.test.ts +0 -137
  315. package/src/runtime/runtime-parity.test.ts +0 -143
  316. package/src/services/providers/local-provider-service.test.ts +0 -1062
  317. package/src/services/session-data.test.ts +0 -160
  318. package/src/services/storage/provider-settings-legacy-migration.test.ts +0 -424
  319. package/src/services/storage/provider-settings-manager.test.ts +0 -191
  320. package/src/services/telemetry/OpenTelemetryAdapter.test.ts +0 -157
  321. package/src/services/telemetry/OpenTelemetryProvider.test.ts +0 -326
  322. package/src/services/telemetry/TelemetryLoggerSink.test.ts +0 -42
  323. package/src/services/telemetry/TelemetryService.test.ts +0 -134
  324. package/src/services/telemetry/distinct-id.test.ts +0 -57
  325. package/src/services/workspace/file-indexer.d.ts +0 -11
  326. package/src/services/workspace/file-indexer.test.ts +0 -156
  327. package/src/services/workspace/mention-enricher.test.ts +0 -106
  328. package/src/session/persistence-service.test.ts +0 -300
  329. package/src/session/rpc-session-service.ts +0 -114
  330. package/src/session/session-service.team-persistence.test.ts +0 -48
  331. package/src/session/sqlite-rpc-session-backend.ts +0 -301
  332. package/src/transports/local.e2e.test.ts +0 -380
  333. package/src/transports/local.test.ts +0 -2559
  334. package/src/transports/rpc.test.ts +0 -82
  335. package/src/transports/rpc.ts +0 -665
@@ -1,661 +0,0 @@
1
- import { type ChildProcessWithoutNullStreams, spawn } from "node:child_process";
2
- import {
3
- type AgentHooks,
4
- type HookSessionContextProvider,
5
- resolveHookSessionContext,
6
- } from "@clinebot/shared";
7
- import {
8
- type AgentAbortHookPayload,
9
- type AgentEndHookPayload,
10
- type AgentErrorHookPayload,
11
- type AgentResumeHookPayload,
12
- type AgentStartHookPayload,
13
- createSubprocessHooks,
14
- type HookEventName,
15
- type HookEventPayload,
16
- type HookEventPayloadBase,
17
- HookOutputSchema,
18
- type PromptSubmitHookPayload,
19
- type RunHookResult,
20
- type SessionShutdownHookPayload,
21
- type ToolCallHookPayload,
22
- type ToolResultHookPayload,
23
- } from "./subprocess";
24
-
25
- type AgentHookControl = NonNullable<
26
- Awaited<ReturnType<NonNullable<AgentHooks["onToolCallStart"]>>>
27
- >;
28
- type AgentHookRunStartContext = Parameters<
29
- NonNullable<AgentHooks["onRunStart"]>
30
- >[0];
31
- type AgentHookSessionShutdownContext = Parameters<
32
- NonNullable<AgentHooks["onSessionShutdown"]>
33
- >[0];
34
- type AgentHookStopErrorContext = Parameters<
35
- NonNullable<AgentHooks["onStopError"]>
36
- >[0];
37
- type AgentHookToolCallEndContext = Parameters<
38
- NonNullable<AgentHooks["onToolCallEnd"]>
39
- >[0];
40
- type AgentHookToolCallStartContext = Parameters<
41
- NonNullable<AgentHooks["onToolCallStart"]>
42
- >[0];
43
- type AgentHookTurnEndContext = Parameters<
44
- NonNullable<AgentHooks["onTurnEnd"]>
45
- >[0];
46
-
47
- interface PersistentHookRequest {
48
- id: string;
49
- payload: HookEventPayload;
50
- }
51
-
52
- interface PersistentHookResponse {
53
- id: string;
54
- ok: boolean;
55
- result?: RunHookResult;
56
- error?: string;
57
- }
58
-
59
- interface PendingRequest {
60
- resolve: (result: RunHookResult | undefined) => void;
61
- reject: (error: Error) => void;
62
- timeoutId?: NodeJS.Timeout;
63
- }
64
-
65
- export interface PersistentHookClientOptions {
66
- command: string[];
67
- cwd?: string;
68
- env?: NodeJS.ProcessEnv;
69
- onSpawn?: (event: {
70
- command: string[];
71
- pid?: number;
72
- detached: boolean;
73
- }) => void;
74
- }
75
-
76
- export class PersistentHookClient {
77
- private readonly options: PersistentHookClientOptions;
78
- private child?: ChildProcessWithoutNullStreams;
79
- private startPromise?: Promise<void>;
80
- private readonly pending = new Map<string, PendingRequest>();
81
- private nextId = 0;
82
- private stdoutBuffer = "";
83
- private closing = false;
84
-
85
- constructor(options: PersistentHookClientOptions) {
86
- this.options = options;
87
- }
88
-
89
- async send(
90
- payload: HookEventPayload,
91
- options?: { timeoutMs?: number },
92
- ): Promise<RunHookResult | undefined> {
93
- await this.ensureStarted();
94
- const child = this.child;
95
- if (!child?.stdin || child.stdin.destroyed) {
96
- throw new Error("persistent hook worker stdin is unavailable");
97
- }
98
-
99
- const id = `hook_req_${String(++this.nextId).padStart(8, "0")}`;
100
- const frame = `${JSON.stringify({ id, payload } satisfies PersistentHookRequest)}\n`;
101
-
102
- return await new Promise<RunHookResult | undefined>((resolve, reject) => {
103
- const pending: PendingRequest = { resolve, reject };
104
- const timeoutMs = options?.timeoutMs ?? 0;
105
- if (timeoutMs > 0) {
106
- pending.timeoutId = setTimeout(() => {
107
- this.pending.delete(id);
108
- reject(
109
- new Error(`Persistent hook request timed out after ${timeoutMs}ms`),
110
- );
111
- }, timeoutMs);
112
- }
113
- this.pending.set(id, pending);
114
- child.stdin.write(frame, (error) => {
115
- if (!error) {
116
- return;
117
- }
118
- this.clearPendingRequest(id);
119
- reject(error instanceof Error ? error : new Error(String(error)));
120
- });
121
- });
122
- }
123
-
124
- async close(): Promise<void> {
125
- this.closing = true;
126
- for (const id of [...this.pending.keys()]) {
127
- this.rejectPendingRequest(id, new Error("persistent hook worker closed"));
128
- }
129
- const child = this.child;
130
- this.child = undefined;
131
- this.startPromise = undefined;
132
- this.stdoutBuffer = "";
133
- if (!child) {
134
- return;
135
- }
136
- await new Promise<void>((resolve) => {
137
- let settled = false;
138
- let forceKillId: NodeJS.Timeout | undefined;
139
- const finish = () => {
140
- if (settled) {
141
- return;
142
- }
143
- settled = true;
144
- if (forceKillId) {
145
- clearTimeout(forceKillId);
146
- }
147
- resolve();
148
- };
149
-
150
- child.once("close", () => finish());
151
-
152
- try {
153
- child.stdin.end();
154
- } catch {
155
- // Ignore stdin shutdown failures and continue to terminate the child.
156
- }
157
-
158
- if (!child.killed) {
159
- try {
160
- child.kill("SIGTERM");
161
- } catch {
162
- finish();
163
- return;
164
- }
165
- }
166
-
167
- forceKillId = setTimeout(() => {
168
- if (!child.killed) {
169
- try {
170
- child.kill("SIGKILL");
171
- } catch {
172
- // Ignore final kill errors.
173
- }
174
- }
175
- }, 250);
176
-
177
- setTimeout(() => finish(), 1000);
178
- });
179
- }
180
-
181
- private async ensureStarted(): Promise<void> {
182
- if (this.child && !this.child.killed) {
183
- return;
184
- }
185
- if (this.startPromise) {
186
- return await this.startPromise;
187
- }
188
- this.closing = false;
189
- this.startPromise = this.start();
190
- try {
191
- await this.startPromise;
192
- } finally {
193
- this.startPromise = undefined;
194
- }
195
- }
196
-
197
- private async start(): Promise<void> {
198
- const command = this.options.command;
199
- if (!Array.isArray(command) || command.length === 0) {
200
- throw new Error("PersistentHookClient requires a non-empty command");
201
- }
202
- const child = spawn(command[0], command.slice(1), {
203
- cwd: this.options.cwd,
204
- env: this.options.env,
205
- stdio: ["pipe", "pipe", "pipe"],
206
- });
207
- this.child = child;
208
- this.stdoutBuffer = "";
209
-
210
- child.stdout.setEncoding("utf8");
211
- child.stdout.on("data", (chunk: string) => {
212
- this.handleStdout(chunk);
213
- });
214
-
215
- child.stderr.setEncoding("utf8");
216
- let stderr = "";
217
- child.stderr.on("data", (chunk: string) => {
218
- stderr += chunk;
219
- });
220
-
221
- child.once("error", (error) => {
222
- this.handleChildExit(
223
- error instanceof Error ? error : new Error(String(error)),
224
- );
225
- });
226
- child.once("close", (code, signal) => {
227
- const detail =
228
- stderr.trim() ||
229
- `persistent hook worker exited with code ${code ?? "null"}${signal ? ` signal ${signal}` : ""}`;
230
- this.handleChildExit(new Error(detail));
231
- });
232
-
233
- await new Promise<void>((resolve, reject) => {
234
- child.once("spawn", () => {
235
- try {
236
- this.options.onSpawn?.({
237
- command,
238
- pid: child.pid ?? undefined,
239
- detached: false,
240
- });
241
- } catch {
242
- // Logging callbacks must not break subprocess execution.
243
- }
244
- resolve();
245
- });
246
- child.once("error", (error) =>
247
- reject(error instanceof Error ? error : new Error(String(error))),
248
- );
249
- });
250
- }
251
-
252
- private handleStdout(chunk: string): void {
253
- this.stdoutBuffer += chunk;
254
- let newlineIndex = this.stdoutBuffer.indexOf("\n");
255
- while (newlineIndex >= 0) {
256
- const line = this.stdoutBuffer.slice(0, newlineIndex).trim();
257
- this.stdoutBuffer = this.stdoutBuffer.slice(newlineIndex + 1);
258
- if (line) {
259
- this.handleResponseLine(line);
260
- }
261
- newlineIndex = this.stdoutBuffer.indexOf("\n");
262
- }
263
- }
264
-
265
- private handleResponseLine(line: string): void {
266
- let parsed: PersistentHookResponse;
267
- try {
268
- parsed = JSON.parse(line) as PersistentHookResponse;
269
- } catch {
270
- return;
271
- }
272
- if (!parsed || typeof parsed.id !== "string") {
273
- return;
274
- }
275
- const pending = this.clearPendingRequest(parsed.id);
276
- if (!pending) {
277
- return;
278
- }
279
- if (!parsed.ok) {
280
- pending.reject(
281
- new Error(parsed.error || "persistent hook worker failed"),
282
- );
283
- return;
284
- }
285
- pending.resolve(parsed.result);
286
- }
287
-
288
- private handleChildExit(error: Error): void {
289
- const child = this.child;
290
- if (!child) {
291
- return;
292
- }
293
- this.child = undefined;
294
- this.stdoutBuffer = "";
295
- if (this.closing) {
296
- return;
297
- }
298
- for (const id of [...this.pending.keys()]) {
299
- this.rejectPendingRequest(id, error);
300
- }
301
- }
302
-
303
- private clearPendingRequest(id: string): PendingRequest | undefined {
304
- const pending = this.pending.get(id);
305
- if (!pending) {
306
- return undefined;
307
- }
308
- this.pending.delete(id);
309
- if (pending.timeoutId) {
310
- clearTimeout(pending.timeoutId);
311
- }
312
- return pending;
313
- }
314
-
315
- private rejectPendingRequest(id: string, error: Error): void {
316
- const pending = this.clearPendingRequest(id);
317
- pending?.reject(error);
318
- }
319
- }
320
-
321
- export interface PersistentSubprocessHooksOptions {
322
- command?: string[];
323
- cwd?: string;
324
- env?: NodeJS.ProcessEnv;
325
- timeoutMs?: number;
326
- onSpawn?: (event: {
327
- command: string[];
328
- pid?: number;
329
- detached: boolean;
330
- }) => void;
331
- onDispatchError?: (error: Error, payload: HookEventPayload) => void;
332
- onDispatch?: (event: {
333
- payload: HookEventPayload;
334
- result?: RunHookResult;
335
- detached: boolean;
336
- }) => void;
337
- sessionContext?: HookSessionContextProvider;
338
- fallbackToSubprocess?: boolean;
339
- }
340
-
341
- export interface PersistentSubprocessHookControl {
342
- hooks: AgentHooks;
343
- shutdown: (ctx: {
344
- agentId: string;
345
- conversationId: string;
346
- parentAgentId: string | null;
347
- reason?: string;
348
- }) => Promise<void>;
349
- client: PersistentHookClient;
350
- }
351
-
352
- const DEFAULT_HOOK_WORKER_COMMAND = ["agent", "hook-worker"];
353
-
354
- function toError(error: unknown): Error {
355
- return error instanceof Error ? error : new Error(String(error));
356
- }
357
-
358
- function toHookControl(value: unknown): AgentHookControl | undefined {
359
- if (!value || typeof value !== "object") {
360
- return undefined;
361
- }
362
- const parsed = HookOutputSchema.safeParse(value);
363
- if (!parsed.success) {
364
- return undefined;
365
- }
366
- const maybe = parsed.data;
367
- const hasControlKey =
368
- "cancel" in maybe ||
369
- "review" in maybe ||
370
- "context" in maybe ||
371
- "contextModification" in maybe ||
372
- "overrideInput" in maybe ||
373
- "errorMessage" in maybe;
374
- if (!hasControlKey) {
375
- return undefined;
376
- }
377
- const contextFromHook =
378
- typeof maybe.context === "string"
379
- ? maybe.context
380
- : typeof maybe.contextModification === "string"
381
- ? maybe.contextModification
382
- : typeof maybe.errorMessage === "string" &&
383
- maybe.errorMessage.length > 0
384
- ? maybe.errorMessage
385
- : undefined;
386
- return {
387
- cancel: typeof maybe.cancel === "boolean" ? maybe.cancel : undefined,
388
- review: typeof maybe.review === "boolean" ? maybe.review : undefined,
389
- context: contextFromHook,
390
- overrideInput: Object.hasOwn(maybe, "overrideInput")
391
- ? maybe.overrideInput
392
- : undefined,
393
- };
394
- }
395
-
396
- function mapParams(input: unknown): Record<string, string> {
397
- if (!input || typeof input !== "object") {
398
- return {};
399
- }
400
- const output: Record<string, string> = {};
401
- for (const [key, value] of Object.entries(input as Record<string, unknown>)) {
402
- if (typeof value === "string") {
403
- output[key] = value;
404
- } else {
405
- output[key] = JSON.stringify(value);
406
- }
407
- }
408
- return output;
409
- }
410
-
411
- function basePayload(
412
- hookName: HookEventName,
413
- ctx: {
414
- agentId: string;
415
- conversationId: string;
416
- parentAgentId: string | null;
417
- },
418
- options: PersistentSubprocessHooksOptions,
419
- ): HookEventPayloadBase {
420
- const env = options.env ?? process.env;
421
- const userId = env.CLINE_USER_ID?.trim() || env.USER?.trim() || "unknown";
422
- const workspaceRoot = options.cwd || process.cwd();
423
- return {
424
- clineVersion: env.CLINE_VERSION?.trim() || "",
425
- hookName,
426
- timestamp: new Date().toISOString(),
427
- taskId: ctx.conversationId,
428
- sessionContext: resolveHookSessionContext(options.sessionContext, {
429
- hookName,
430
- conversationId: ctx.conversationId,
431
- agentId: ctx.agentId,
432
- parentAgentId: ctx.parentAgentId,
433
- }),
434
- workspaceRoots: workspaceRoot ? [workspaceRoot] : [],
435
- userId,
436
- agent_id: ctx.agentId,
437
- parent_agent_id: ctx.parentAgentId,
438
- };
439
- }
440
-
441
- function serializeHookError(error: Error): AgentErrorHookPayload["error"] {
442
- return {
443
- name: error.name,
444
- message: error.message,
445
- stack: error.stack,
446
- };
447
- }
448
-
449
- function isAbortReason(reason?: string): boolean {
450
- const value = String(reason ?? "").toLowerCase();
451
- return (
452
- value.includes("cancel") ||
453
- value.includes("abort") ||
454
- value.includes("interrupt")
455
- );
456
- }
457
-
458
- async function dispatchDetached(
459
- client: PersistentHookClient,
460
- payload: HookEventPayload,
461
- options: PersistentSubprocessHooksOptions,
462
- ): Promise<void> {
463
- try {
464
- const result = await client.send(payload, {
465
- timeoutMs: options.timeoutMs,
466
- });
467
- options.onDispatch?.({ payload, result, detached: true });
468
- } catch (error) {
469
- options.onDispatchError?.(toError(error), payload);
470
- }
471
- }
472
-
473
- export function createPersistentSubprocessHooks(
474
- options: PersistentSubprocessHooksOptions = {},
475
- ): PersistentSubprocessHookControl {
476
- const command = options.command ?? DEFAULT_HOOK_WORKER_COMMAND;
477
- const client = new PersistentHookClient({
478
- command,
479
- cwd: options.cwd,
480
- env: options.env,
481
- onSpawn: options.onSpawn,
482
- });
483
-
484
- const fallbackHooks = options.fallbackToSubprocess
485
- ? createSubprocessHooks(options)
486
- : undefined;
487
-
488
- const onRunStart = async (
489
- ctx: AgentHookRunStartContext,
490
- ): Promise<AgentHookControl | undefined> => {
491
- const isResume =
492
- (options.env ?? process.env).CLINE_HOOK_AGENT_RESUME === "1";
493
- if (isResume) {
494
- const resumePayload: AgentResumeHookPayload = {
495
- ...basePayload("agent_resume", ctx, options),
496
- hookName: "agent_resume",
497
- taskResume: {
498
- taskMetadata: {},
499
- previousState: {},
500
- },
501
- };
502
- await dispatchDetached(client, resumePayload, options);
503
- } else {
504
- const startPayload: AgentStartHookPayload = {
505
- ...basePayload("agent_start", ctx, options),
506
- hookName: "agent_start",
507
- taskStart: { taskMetadata: {} },
508
- };
509
- await dispatchDetached(client, startPayload, options);
510
- }
511
-
512
- const promptPayload: PromptSubmitHookPayload = {
513
- ...basePayload("prompt_submit", ctx, options),
514
- hookName: "prompt_submit",
515
- userPromptSubmit: {
516
- prompt: ctx.userMessage,
517
- attachments: [],
518
- },
519
- };
520
- await dispatchDetached(client, promptPayload, options);
521
- return undefined;
522
- };
523
-
524
- const onToolCallStart = async (
525
- ctx: AgentHookToolCallStartContext,
526
- ): Promise<AgentHookControl | undefined> => {
527
- const payload: ToolCallHookPayload = {
528
- ...basePayload("tool_call", ctx, options),
529
- hookName: "tool_call",
530
- iteration: ctx.iteration,
531
- tool_call: {
532
- id: ctx.call.id,
533
- name: ctx.call.name,
534
- input: ctx.call.input,
535
- },
536
- preToolUse: {
537
- toolName: ctx.call.name,
538
- parameters: mapParams(ctx.call.input),
539
- },
540
- };
541
-
542
- try {
543
- const result = await client.send(payload, {
544
- timeoutMs: options.timeoutMs,
545
- });
546
- options.onDispatch?.({ payload, result, detached: false });
547
- if (result?.timedOut) {
548
- throw new Error("tool_call hook command timed out");
549
- }
550
- if (result?.parseError) {
551
- throw new Error(
552
- `tool_call hook produced invalid control JSON: ${result.parseError}`,
553
- );
554
- }
555
- return toHookControl(result?.parsedJson);
556
- } catch (error) {
557
- options.onDispatchError?.(toError(error), payload);
558
- if (fallbackHooks) {
559
- return await fallbackHooks.hooks.onToolCallStart?.(ctx);
560
- }
561
- return undefined;
562
- }
563
- };
564
-
565
- const onToolCallEnd = async (
566
- ctx: AgentHookToolCallEndContext,
567
- ): Promise<AgentHookControl | undefined> => {
568
- const payload: ToolResultHookPayload = {
569
- ...basePayload("tool_result", ctx, options),
570
- hookName: "tool_result",
571
- iteration: ctx.iteration,
572
- tool_result: ctx.record,
573
- postToolUse: {
574
- toolName: ctx.record.name,
575
- parameters: mapParams(ctx.record.input),
576
- result:
577
- typeof ctx.record.output === "string"
578
- ? ctx.record.output
579
- : JSON.stringify(ctx.record.output),
580
- success: !ctx.record.error,
581
- executionTimeMs: ctx.record.durationMs,
582
- },
583
- };
584
- await dispatchDetached(client, payload, options);
585
- return undefined;
586
- };
587
-
588
- const onTurnEnd = async (
589
- ctx: AgentHookTurnEndContext,
590
- ): Promise<AgentHookControl | undefined> => {
591
- const payload: AgentEndHookPayload = {
592
- ...basePayload("agent_end", ctx, options),
593
- hookName: "agent_end",
594
- iteration: ctx.iteration,
595
- turn: ctx.turn,
596
- taskComplete: { taskMetadata: {} },
597
- };
598
- await dispatchDetached(client, payload, options);
599
- return undefined;
600
- };
601
-
602
- const onStopError = async (
603
- ctx: AgentHookStopErrorContext,
604
- ): Promise<AgentHookControl | undefined> => {
605
- const hookName: HookEventName = isAbortReason(ctx.error.message)
606
- ? "agent_abort"
607
- : "agent_error";
608
- const payload: AgentErrorHookPayload | AgentAbortHookPayload =
609
- hookName === "agent_error"
610
- ? {
611
- ...basePayload(hookName, ctx, options),
612
- hookName,
613
- iteration: ctx.iteration,
614
- error: serializeHookError(ctx.error),
615
- taskCancel: { taskMetadata: {} },
616
- }
617
- : {
618
- ...basePayload(hookName, ctx, options),
619
- hookName,
620
- reason: ctx.error.message,
621
- taskCancel: { taskMetadata: {} },
622
- };
623
- await dispatchDetached(client, payload, options);
624
- return undefined;
625
- };
626
-
627
- const shutdown = async ({
628
- agentId,
629
- conversationId,
630
- parentAgentId,
631
- reason,
632
- }: AgentHookSessionShutdownContext): Promise<void> => {
633
- const payload: SessionShutdownHookPayload = {
634
- ...basePayload(
635
- "session_shutdown",
636
- {
637
- agentId,
638
- conversationId,
639
- parentAgentId,
640
- },
641
- options,
642
- ),
643
- hookName: "session_shutdown",
644
- reason,
645
- };
646
- await dispatchDetached(client, payload, options);
647
- await client.close();
648
- };
649
-
650
- return {
651
- hooks: {
652
- onRunStart,
653
- onToolCallStart,
654
- onToolCallEnd,
655
- onTurnEnd,
656
- onStopError,
657
- },
658
- shutdown,
659
- client,
660
- };
661
- }