@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
@@ -0,0 +1,656 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { basename } from "node:path";
3
+ import type {
4
+ AgentResult,
5
+ SessionRecord as HubSessionRecord,
6
+ HubToolExecutorName,
7
+ JsonValue,
8
+ ToolContext,
9
+ } from "@clinebot/shared";
10
+ import type { ToolExecutors } from "../extensions/tools";
11
+ import type { HookEventPayload } from "../hooks";
12
+ import { NodeHubClient } from "../hub/client";
13
+ import type {
14
+ RuntimeHost,
15
+ RuntimeHostSubscribeOptions,
16
+ SendSessionInput,
17
+ SessionAccumulatedUsage,
18
+ StartSessionInput,
19
+ StartSessionResult,
20
+ } from "../runtime/runtime-host";
21
+ import {
22
+ type SessionManifest,
23
+ SessionManifestSchema,
24
+ } from "../session/session-manifest";
25
+ import { SessionSource, type SessionStatus } from "../types/common";
26
+ import type { CoreSessionEvent } from "../types/events";
27
+ import type { SessionRecord } from "../types/sessions";
28
+ import {
29
+ RuntimeHostEventBus,
30
+ readPersistedMessagesFile,
31
+ } from "./runtime-host-support";
32
+
33
+ function toJsonRecord(
34
+ value: Record<string, unknown> | undefined,
35
+ ): Record<string, JsonValue | undefined> | undefined {
36
+ if (!value) {
37
+ return undefined;
38
+ }
39
+ return JSON.parse(JSON.stringify(value)) as Record<
40
+ string,
41
+ JsonValue | undefined
42
+ >;
43
+ }
44
+
45
+ function isHubToolExecutorName(value: unknown): value is HubToolExecutorName {
46
+ return (
47
+ value === "readFile" ||
48
+ value === "search" ||
49
+ value === "bash" ||
50
+ value === "webFetch" ||
51
+ value === "editor" ||
52
+ value === "applyPatch" ||
53
+ value === "skills" ||
54
+ value === "askQuestion" ||
55
+ value === "submit"
56
+ );
57
+ }
58
+
59
+ function parseToolContext(value: unknown): ToolContext {
60
+ const payload =
61
+ value && typeof value === "object" && !Array.isArray(value)
62
+ ? (value as Record<string, unknown>)
63
+ : {};
64
+ return {
65
+ agentId: typeof payload.agentId === "string" ? payload.agentId : "",
66
+ conversationId:
67
+ typeof payload.conversationId === "string" ? payload.conversationId : "",
68
+ iteration: typeof payload.iteration === "number" ? payload.iteration : 0,
69
+ metadata:
70
+ payload.metadata &&
71
+ typeof payload.metadata === "object" &&
72
+ !Array.isArray(payload.metadata)
73
+ ? (payload.metadata as Record<string, unknown>)
74
+ : undefined,
75
+ };
76
+ }
77
+
78
+ export interface HubRuntimeHostOptions {
79
+ url: string;
80
+ authToken?: string;
81
+ clientType?: string;
82
+ displayName?: string;
83
+ }
84
+
85
+ function mapStatus(
86
+ status: HubSessionRecord["status"] | undefined,
87
+ ): SessionStatus {
88
+ switch (status) {
89
+ case "idle":
90
+ case "completed":
91
+ return "completed";
92
+ case "failed":
93
+ return "failed";
94
+ case "aborted":
95
+ return "cancelled";
96
+ default:
97
+ return "running";
98
+ }
99
+ }
100
+
101
+ function toSessionRecord(session: HubSessionRecord): SessionRecord {
102
+ const metadata =
103
+ session.metadata && typeof session.metadata === "object"
104
+ ? JSON.parse(JSON.stringify(session.metadata))
105
+ : undefined;
106
+ return {
107
+ sessionId: session.sessionId,
108
+ parentSessionId:
109
+ typeof metadata?.parentSessionId === "string"
110
+ ? metadata.parentSessionId
111
+ : undefined,
112
+ agentId:
113
+ session.runtimeSession?.agentId ||
114
+ (typeof metadata?.agentId === "string" ? metadata.agentId : undefined),
115
+ parentAgentId:
116
+ typeof metadata?.parentAgentId === "string"
117
+ ? metadata.parentAgentId
118
+ : undefined,
119
+ conversationId:
120
+ typeof metadata?.conversationId === "string"
121
+ ? metadata.conversationId
122
+ : undefined,
123
+ isSubagent:
124
+ typeof metadata?.isSubagent === "boolean" ? metadata.isSubagent : false,
125
+ source:
126
+ typeof metadata?.source === "string"
127
+ ? metadata.source
128
+ : SessionSource.CORE,
129
+ pid: typeof metadata?.pid === "number" ? metadata.pid : undefined,
130
+ startedAt: new Date(session.createdAt).toISOString(),
131
+ endedAt:
132
+ mapStatus(session.status) === "running"
133
+ ? undefined
134
+ : new Date(session.updatedAt).toISOString(),
135
+ exitCode:
136
+ mapStatus(session.status) === "completed"
137
+ ? 0
138
+ : mapStatus(session.status) === "failed"
139
+ ? 1
140
+ : undefined,
141
+ status: mapStatus(session.status),
142
+ interactive: metadata?.interactive === true,
143
+ provider:
144
+ typeof metadata?.provider === "string" ? metadata.provider : "hub",
145
+ model: typeof metadata?.model === "string" ? metadata.model : "hub",
146
+ cwd: session.cwd?.trim() || session.workspaceRoot,
147
+ workspaceRoot: session.workspaceRoot,
148
+ teamName:
149
+ typeof metadata?.teamName === "string" ? metadata.teamName : undefined,
150
+ enableTools:
151
+ session.runtimeOptions?.enableTools ?? metadata?.enableTools === true,
152
+ enableSpawn:
153
+ session.runtimeOptions?.enableSpawn ?? metadata?.enableSpawn === true,
154
+ enableTeams:
155
+ session.runtimeOptions?.enableTeams ?? metadata?.enableTeams === true,
156
+ prompt: typeof metadata?.prompt === "string" ? metadata.prompt : undefined,
157
+ metadata,
158
+ updatedAt: new Date(session.updatedAt).toISOString(),
159
+ messagesPath:
160
+ typeof metadata?.messagesPath === "string"
161
+ ? metadata.messagesPath
162
+ : undefined,
163
+ hookPath:
164
+ typeof metadata?.hookPath === "string" ? metadata.hookPath : undefined,
165
+ };
166
+ }
167
+
168
+ function buildManifest(
169
+ sessionId: string,
170
+ input: StartSessionInput,
171
+ session: HubSessionRecord | undefined,
172
+ ): SessionManifest {
173
+ const workspaceRoot =
174
+ session?.workspaceRoot?.trim() ||
175
+ input.config.workspaceRoot ||
176
+ input.config.cwd;
177
+ return SessionManifestSchema.parse({
178
+ version: 1,
179
+ session_id: sessionId,
180
+ source: input.source ?? SessionSource.CORE,
181
+ pid: process.pid,
182
+ started_at: new Date(session?.createdAt ?? Date.now()).toISOString(),
183
+ status: mapStatus(session?.status),
184
+ interactive: input.interactive === true,
185
+ provider: input.config.providerId,
186
+ model: input.config.modelId,
187
+ cwd: session?.cwd?.trim() || input.config.cwd,
188
+ workspace_root: workspaceRoot,
189
+ team_name: input.config.teamName,
190
+ enable_tools: input.config.enableTools,
191
+ enable_spawn: input.config.enableSpawnAgent,
192
+ enable_teams: input.config.enableAgentTeams,
193
+ prompt: input.prompt?.trim() || undefined,
194
+ metadata:
195
+ input.sessionMetadata && Object.keys(input.sessionMetadata).length > 0
196
+ ? input.sessionMetadata
197
+ : undefined,
198
+ });
199
+ }
200
+
201
+ export class HubRuntimeHost implements RuntimeHost {
202
+ public readonly runtimeAddress: string;
203
+ private readonly client: NodeHubClient;
204
+ private readonly events = new RuntimeHostEventBus();
205
+ private readonly sessionToolExecutors = new Map<
206
+ string,
207
+ Partial<ToolExecutors>
208
+ >();
209
+ private readonly sessionSubscriptions = new Map<string, () => void>();
210
+
211
+ constructor(
212
+ options: HubRuntimeHostOptions,
213
+ clientContext?: { workspaceRoot?: string; cwd?: string },
214
+ ) {
215
+ this.runtimeAddress = options.url;
216
+ this.client = new NodeHubClient({
217
+ url: options.url,
218
+ authToken: options.authToken,
219
+ clientType: options.clientType ?? "core-hub-runtime",
220
+ displayName: options.displayName ?? "core hub runtime",
221
+ workspaceRoot: clientContext?.workspaceRoot,
222
+ cwd: clientContext?.cwd,
223
+ });
224
+ }
225
+
226
+ async connect(): Promise<void> {
227
+ await this.client.connect();
228
+ }
229
+
230
+ async start(input: StartSessionInput): Promise<StartSessionResult> {
231
+ const advertisedToolExecutors = Object.keys(
232
+ input.localRuntime?.defaultToolExecutors ?? {},
233
+ ).filter(isHubToolExecutorName);
234
+ const reply = await this.client.command("session.create", {
235
+ workspaceRoot: input.config.workspaceRoot?.trim() || input.config.cwd,
236
+ cwd: input.config.cwd,
237
+ sessionConfig: toJsonRecord(input.config as Record<string, unknown>),
238
+ metadata: {
239
+ ...(input.sessionMetadata ?? {}),
240
+ source: input.source ?? SessionSource.CORE,
241
+ provider: input.config.providerId,
242
+ model: input.config.modelId,
243
+ enableTools: input.config.enableTools,
244
+ enableSpawn: input.config.enableSpawnAgent,
245
+ enableTeams: input.config.enableAgentTeams,
246
+ teamName: input.config.teamName,
247
+ prompt: input.prompt,
248
+ interactive: input.interactive === true,
249
+ },
250
+ runtimeOptions: {
251
+ toolExecutors: advertisedToolExecutors,
252
+ },
253
+ toolPolicies: toJsonRecord(
254
+ input.toolPolicies as Record<string, unknown> | undefined,
255
+ ),
256
+ initialMessages: input.initialMessages,
257
+ });
258
+ const session = reply.payload?.session as HubSessionRecord | undefined;
259
+ const sessionId = session?.sessionId?.trim();
260
+ if (!sessionId) {
261
+ throw new Error("Hub runtime did not return a session id.");
262
+ }
263
+ if (input.localRuntime?.defaultToolExecutors) {
264
+ this.sessionToolExecutors.set(
265
+ sessionId,
266
+ input.localRuntime.defaultToolExecutors,
267
+ );
268
+ }
269
+ this.ensureSessionSubscription(sessionId);
270
+
271
+ return {
272
+ sessionId,
273
+ manifest: buildManifest(sessionId, input, session),
274
+ manifestPath: "",
275
+ messagesPath: "",
276
+ result: undefined,
277
+ };
278
+ }
279
+
280
+ async send(input: SendSessionInput): Promise<AgentResult | undefined> {
281
+ this.ensureSessionSubscription(input.sessionId);
282
+ const reply = await this.client.command(
283
+ "run.start",
284
+ {
285
+ sessionId: input.sessionId,
286
+ input: input.prompt,
287
+ attachments:
288
+ (input.userImages?.length ?? 0) > 0 ||
289
+ (input.userFiles?.length ?? 0) > 0
290
+ ? {
291
+ ...(input.userImages?.length
292
+ ? { userImages: input.userImages }
293
+ : {}),
294
+ ...(input.userFiles?.length
295
+ ? {
296
+ userFiles: input.userFiles.map((filePath) => ({
297
+ name: basename(filePath),
298
+ content: readFileSync(filePath, "utf8"),
299
+ })),
300
+ }
301
+ : {}),
302
+ }
303
+ : undefined,
304
+ },
305
+ input.sessionId,
306
+ );
307
+ return reply.payload?.result as AgentResult | undefined;
308
+ }
309
+
310
+ async getAccumulatedUsage(
311
+ sessionId: string,
312
+ ): Promise<SessionAccumulatedUsage | undefined> {
313
+ const reply = await this.client.command(
314
+ "session.get",
315
+ undefined,
316
+ sessionId,
317
+ );
318
+ const session = reply.payload?.session as
319
+ | (HubSessionRecord & { usage?: SessionAccumulatedUsage })
320
+ | undefined;
321
+ return session?.usage ? { ...session.usage } : undefined;
322
+ }
323
+
324
+ async abort(sessionId: string, reason?: unknown): Promise<void> {
325
+ await this.client.command(
326
+ "run.abort",
327
+ { sessionId, reason: typeof reason === "string" ? reason : undefined },
328
+ sessionId,
329
+ );
330
+ }
331
+
332
+ async stop(sessionId: string): Promise<void> {
333
+ this.sessionToolExecutors.delete(sessionId);
334
+ this.disposeSessionSubscription(sessionId);
335
+ await this.client.command("session.detach", { sessionId }, sessionId);
336
+ }
337
+
338
+ async dispose(): Promise<void> {
339
+ for (const [sessionId, unsubscribe] of this.sessionSubscriptions) {
340
+ unsubscribe();
341
+ try {
342
+ await this.client.command("session.detach", { sessionId }, sessionId);
343
+ } catch {
344
+ // Best-effort detach during shutdown.
345
+ }
346
+ }
347
+ this.sessionSubscriptions.clear();
348
+ this.sessionToolExecutors.clear();
349
+ this.client.close();
350
+ }
351
+
352
+ async get(sessionId: string): Promise<SessionRecord | undefined> {
353
+ const reply = await this.client.command(
354
+ "session.get",
355
+ undefined,
356
+ sessionId,
357
+ );
358
+ const session = reply.payload?.session as HubSessionRecord | undefined;
359
+ return session ? toSessionRecord(session) : undefined;
360
+ }
361
+
362
+ async list(limit = 100): Promise<SessionRecord[]> {
363
+ const reply = await this.client.command("session.list", { limit });
364
+ const sessions =
365
+ (reply.payload?.sessions as HubSessionRecord[] | undefined) ?? [];
366
+ return sessions.map(toSessionRecord);
367
+ }
368
+
369
+ async delete(sessionId: string): Promise<boolean> {
370
+ this.sessionToolExecutors.delete(sessionId);
371
+ this.disposeSessionSubscription(sessionId);
372
+ const reply = await this.client.command("session.delete", { sessionId });
373
+ return reply.payload?.deleted === true;
374
+ }
375
+
376
+ async update(
377
+ sessionId: string,
378
+ updates: {
379
+ prompt?: string | null;
380
+ metadata?: Record<string, unknown> | null;
381
+ title?: string | null;
382
+ },
383
+ ): Promise<{ updated: boolean }> {
384
+ const metadata: Record<string, unknown> = {
385
+ ...(updates.metadata ?? {}),
386
+ };
387
+ if (typeof updates.prompt === "string") {
388
+ metadata.prompt = updates.prompt;
389
+ }
390
+ if (typeof updates.title === "string") {
391
+ metadata.title = updates.title;
392
+ }
393
+ const reply = await this.client.command("session.update", {
394
+ sessionId,
395
+ metadata,
396
+ });
397
+ return { updated: reply.ok };
398
+ }
399
+
400
+ async readMessages(
401
+ sessionId: string,
402
+ ): Promise<import("@clinebot/llms").Message[]> {
403
+ const session = await this.get(sessionId);
404
+ return readPersistedMessagesFile(session?.messagesPath);
405
+ }
406
+
407
+ async handleHookEvent(_payload: HookEventPayload): Promise<void> {
408
+ await this.client.command("session.hook", { payload: _payload });
409
+ }
410
+
411
+ subscribe(
412
+ listener: (event: CoreSessionEvent) => void,
413
+ options?: RuntimeHostSubscribeOptions,
414
+ ): () => void {
415
+ return this.events.subscribe(listener, options);
416
+ }
417
+
418
+ private ensureSessionSubscription(sessionId: string): void {
419
+ const target = sessionId.trim();
420
+ if (!target || this.sessionSubscriptions.has(target)) {
421
+ return;
422
+ }
423
+ const subscription = this.client.subscribe(
424
+ (event) => {
425
+ this.handleHubEvent(event);
426
+ },
427
+ { sessionId: target },
428
+ );
429
+ this.sessionSubscriptions.set(
430
+ target,
431
+ typeof subscription === "function" ? subscription : () => {},
432
+ );
433
+ }
434
+
435
+ private disposeSessionSubscription(sessionId: string): void {
436
+ const target = sessionId.trim();
437
+ if (!target) {
438
+ return;
439
+ }
440
+ this.sessionSubscriptions.get(target)?.();
441
+ this.sessionSubscriptions.delete(target);
442
+ }
443
+
444
+ private handleHubEvent(
445
+ event: import("@clinebot/shared").HubEventEnvelope,
446
+ ): void {
447
+ const sessionId = event.sessionId?.trim();
448
+ if (event.event === "capability.requested") {
449
+ void this.handleCapabilityRequest(event);
450
+ return;
451
+ }
452
+ if (!sessionId) {
453
+ return;
454
+ }
455
+
456
+ switch (event.event) {
457
+ case "assistant.delta": {
458
+ const text =
459
+ typeof event.payload?.text === "string" ? event.payload.text : "";
460
+ if (!text) {
461
+ return;
462
+ }
463
+ this.events.emit({
464
+ type: "agent_event",
465
+ payload: {
466
+ sessionId,
467
+ event: {
468
+ type: "content_start",
469
+ contentType: "text",
470
+ text,
471
+ },
472
+ },
473
+ });
474
+ return;
475
+ }
476
+ case "reasoning.delta": {
477
+ const text =
478
+ typeof event.payload?.text === "string" ? event.payload.text : "";
479
+ const redacted = event.payload?.redacted === true;
480
+ if (!text && !redacted) {
481
+ return;
482
+ }
483
+ this.events.emit({
484
+ type: "agent_event",
485
+ payload: {
486
+ sessionId,
487
+ event: {
488
+ type: "content_start",
489
+ contentType: "reasoning",
490
+ reasoning: text,
491
+ redacted,
492
+ },
493
+ },
494
+ });
495
+ return;
496
+ }
497
+ case "tool.started": {
498
+ this.events.emit({
499
+ type: "agent_event",
500
+ payload: {
501
+ sessionId,
502
+ event: {
503
+ type: "content_start",
504
+ contentType: "tool",
505
+ toolCallId:
506
+ typeof event.payload?.toolCallId === "string"
507
+ ? event.payload.toolCallId
508
+ : undefined,
509
+ toolName:
510
+ typeof event.payload?.toolName === "string"
511
+ ? event.payload.toolName
512
+ : undefined,
513
+ input: event.payload?.input,
514
+ },
515
+ },
516
+ });
517
+ return;
518
+ }
519
+ case "tool.finished": {
520
+ this.events.emit({
521
+ type: "agent_event",
522
+ payload: {
523
+ sessionId,
524
+ event: {
525
+ type: "content_end",
526
+ contentType: "tool",
527
+ toolCallId:
528
+ typeof event.payload?.toolCallId === "string"
529
+ ? event.payload.toolCallId
530
+ : undefined,
531
+ toolName:
532
+ typeof event.payload?.toolName === "string"
533
+ ? event.payload.toolName
534
+ : undefined,
535
+ output: event.payload?.output,
536
+ error:
537
+ typeof event.payload?.error === "string"
538
+ ? event.payload.error
539
+ : undefined,
540
+ },
541
+ },
542
+ });
543
+ return;
544
+ }
545
+ case "run.started":
546
+ case "session.created":
547
+ case "session.updated":
548
+ case "session.attached":
549
+ case "session.detached": {
550
+ const session = event.payload?.session as HubSessionRecord | undefined;
551
+ this.events.emit({
552
+ type: "status",
553
+ payload: {
554
+ sessionId,
555
+ status: session?.status ?? "running",
556
+ },
557
+ });
558
+ return;
559
+ }
560
+ case "run.completed":
561
+ case "run.aborted": {
562
+ this.sessionToolExecutors.delete(sessionId);
563
+ this.events.emit({
564
+ type: "ended",
565
+ payload: {
566
+ sessionId,
567
+ reason:
568
+ typeof event.payload?.reason === "string"
569
+ ? event.payload.reason
570
+ : event.event === "run.aborted"
571
+ ? "aborted"
572
+ : "completed",
573
+ ts: event.timestamp ?? Date.now(),
574
+ },
575
+ });
576
+ return;
577
+ }
578
+ default:
579
+ return;
580
+ }
581
+ }
582
+
583
+ private async handleCapabilityRequest(
584
+ event: import("@clinebot/shared").HubEventEnvelope,
585
+ ): Promise<void> {
586
+ const sessionId = event.sessionId?.trim();
587
+ if (!sessionId) {
588
+ return;
589
+ }
590
+ const targetClientId =
591
+ typeof event.payload?.targetClientId === "string"
592
+ ? event.payload.targetClientId
593
+ : undefined;
594
+ if (targetClientId && targetClientId !== this.client.getClientId()) {
595
+ return;
596
+ }
597
+ const requestId =
598
+ typeof event.payload?.requestId === "string"
599
+ ? event.payload.requestId
600
+ : "";
601
+ const capabilityName =
602
+ typeof event.payload?.capabilityName === "string"
603
+ ? event.payload.capabilityName
604
+ : "";
605
+ if (!requestId || !capabilityName.startsWith("tool_executor.")) {
606
+ return;
607
+ }
608
+ const executorName = capabilityName.slice("tool_executor.".length);
609
+ const executors = this.sessionToolExecutors.get(sessionId);
610
+ const executor = executors?.[executorName as keyof ToolExecutors] as
611
+ | ((...args: unknown[]) => Promise<unknown>)
612
+ | undefined;
613
+ if (typeof executor !== "function") {
614
+ await this.client.command(
615
+ "capability.respond",
616
+ {
617
+ requestId,
618
+ ok: false,
619
+ error: `No executor registered for ${executorName}`,
620
+ },
621
+ sessionId,
622
+ );
623
+ return;
624
+ }
625
+ const payload =
626
+ event.payload?.payload &&
627
+ typeof event.payload.payload === "object" &&
628
+ !Array.isArray(event.payload.payload)
629
+ ? (event.payload.payload as Record<string, unknown>)
630
+ : {};
631
+ const args = Array.isArray(payload.args) ? [...payload.args] : [];
632
+ const context = parseToolContext(payload.context);
633
+ try {
634
+ const result = await executor(...args, context);
635
+ await this.client.command(
636
+ "capability.respond",
637
+ {
638
+ requestId,
639
+ ok: true,
640
+ payload: { result },
641
+ },
642
+ sessionId,
643
+ );
644
+ } catch (error) {
645
+ await this.client.command(
646
+ "capability.respond",
647
+ {
648
+ requestId,
649
+ ok: false,
650
+ error: error instanceof Error ? error.message : String(error),
651
+ },
652
+ sessionId,
653
+ );
654
+ }
655
+ }
656
+ }