@clinebot/core 0.0.28 → 0.0.29

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 (339) hide show
  1. package/README.md +7 -0
  2. package/dist/ClineCore.d.ts +28 -2
  3. package/dist/ClineCore.d.ts.map +1 -1
  4. package/dist/account/cline-account-service.d.ts +1 -1
  5. package/dist/account/cline-account-service.d.ts.map +1 -1
  6. package/dist/account/index.d.ts +1 -1
  7. package/dist/account/index.d.ts.map +1 -1
  8. package/dist/account/types.d.ts +5 -0
  9. package/dist/account/types.d.ts.map +1 -1
  10. package/dist/auth/bounded-ttl-cache.d.ts +14 -0
  11. package/dist/auth/bounded-ttl-cache.d.ts.map +1 -0
  12. package/dist/auth/cline.d.ts +27 -2
  13. package/dist/auth/cline.d.ts.map +1 -1
  14. package/dist/auth/oca.d.ts.map +1 -1
  15. package/dist/chat/chat-schema.d.ts +11 -11
  16. package/dist/extensions/config/agent-config-loader.d.ts.map +1 -0
  17. package/dist/{agents → extensions/config}/agent-config-parser.d.ts +2 -2
  18. package/dist/extensions/config/agent-config-parser.d.ts.map +1 -0
  19. package/dist/{agents → extensions/config}/hooks-config-loader.d.ts +1 -1
  20. package/dist/extensions/config/hooks-config-loader.d.ts.map +1 -0
  21. package/dist/{agents → extensions/config}/index.d.ts +2 -4
  22. package/dist/extensions/config/index.d.ts.map +1 -0
  23. package/dist/{runtime/commands.d.ts → extensions/config/runtime-commands.d.ts} +2 -3
  24. package/dist/extensions/config/runtime-commands.d.ts.map +1 -0
  25. package/dist/extensions/config/unified-config-file-watcher.d.ts.map +1 -0
  26. package/dist/extensions/config/user-instruction-config-loader.d.ts.map +1 -0
  27. package/dist/extensions/context/agentic-compaction.d.ts +13 -0
  28. package/dist/extensions/context/agentic-compaction.d.ts.map +1 -0
  29. package/dist/extensions/context/basic-compaction.d.ts +9 -0
  30. package/dist/extensions/context/basic-compaction.d.ts.map +1 -0
  31. package/dist/extensions/context/compaction-shared.d.ts +60 -0
  32. package/dist/extensions/context/compaction-shared.d.ts.map +1 -0
  33. package/dist/extensions/context/compaction.d.ts +20 -0
  34. package/dist/extensions/context/compaction.d.ts.map +1 -0
  35. package/dist/extensions/index.d.ts +5 -0
  36. package/dist/extensions/index.d.ts.map +1 -0
  37. package/dist/extensions/mcp/client.d.ts +3 -0
  38. package/dist/extensions/mcp/client.d.ts.map +1 -0
  39. package/dist/extensions/mcp/config-loader.d.ts.map +1 -0
  40. package/dist/extensions/mcp/index.d.ts +9 -0
  41. package/dist/extensions/mcp/index.d.ts.map +1 -0
  42. package/dist/{mcp → extensions/mcp}/manager.d.ts +1 -2
  43. package/dist/extensions/mcp/manager.d.ts.map +1 -0
  44. package/dist/extensions/mcp/name-transform.d.ts +3 -0
  45. package/dist/extensions/mcp/name-transform.d.ts.map +1 -0
  46. package/dist/extensions/mcp/policies.d.ts +15 -0
  47. package/dist/extensions/mcp/policies.d.ts.map +1 -0
  48. package/dist/extensions/mcp/tools.d.ts +4 -0
  49. package/dist/extensions/mcp/tools.d.ts.map +1 -0
  50. package/dist/{mcp → extensions/mcp}/types.d.ts +29 -1
  51. package/dist/extensions/mcp/types.d.ts.map +1 -0
  52. package/dist/{agents → extensions/plugin}/plugin-config-loader.d.ts +1 -1
  53. package/dist/extensions/plugin/plugin-config-loader.d.ts.map +1 -0
  54. package/dist/{agents → extensions/plugin}/plugin-loader.d.ts +1 -1
  55. package/dist/extensions/plugin/plugin-loader.d.ts.map +1 -0
  56. package/dist/extensions/plugin/plugin-module-import.d.ts +5 -0
  57. package/dist/extensions/plugin/plugin-module-import.d.ts.map +1 -0
  58. package/dist/{agents → extensions/plugin}/plugin-sandbox.d.ts +1 -1
  59. package/dist/extensions/plugin/plugin-sandbox.d.ts.map +1 -0
  60. package/dist/extensions/plugin-sandbox-bootstrap.js +485 -0
  61. package/dist/hooks/index.d.ts +4 -0
  62. package/dist/hooks/index.d.ts.map +1 -0
  63. package/dist/hooks/persistent.d.ts +64 -0
  64. package/dist/hooks/persistent.d.ts.map +1 -0
  65. package/dist/hooks/subprocess-runner.d.ts +22 -0
  66. package/dist/hooks/subprocess-runner.d.ts.map +1 -0
  67. package/dist/hooks/subprocess.d.ts +189 -0
  68. package/dist/hooks/subprocess.d.ts.map +1 -0
  69. package/dist/index.d.ts +22 -25
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +560 -447
  72. package/dist/prompt/default-system.d.ts +2 -0
  73. package/dist/prompt/default-system.d.ts.map +1 -0
  74. package/dist/providers/local-provider-service.d.ts +1 -1
  75. package/dist/providers/local-provider-service.d.ts.map +1 -1
  76. package/dist/runtime/checkpoint-hooks.d.ts +21 -0
  77. package/dist/runtime/checkpoint-hooks.d.ts.map +1 -0
  78. package/dist/runtime/hook-file-hooks.d.ts +1 -1
  79. package/dist/runtime/hook-file-hooks.d.ts.map +1 -1
  80. package/dist/runtime/rules.d.ts +1 -1
  81. package/dist/runtime/rules.d.ts.map +1 -1
  82. package/dist/runtime/runtime-builder.d.ts +1 -1
  83. package/dist/runtime/runtime-builder.d.ts.map +1 -1
  84. package/dist/runtime/session-runtime.d.ts +25 -5
  85. package/dist/runtime/session-runtime.d.ts.map +1 -1
  86. package/dist/runtime/subprocess-sandbox.d.ts.map +1 -0
  87. package/dist/runtime/team-runtime-registry.d.ts +1 -1
  88. package/dist/runtime/team-runtime-registry.d.ts.map +1 -1
  89. package/dist/runtime/tool-approval.d.ts +1 -1
  90. package/dist/session/default-session-manager.d.ts +4 -3
  91. package/dist/session/default-session-manager.d.ts.map +1 -1
  92. package/dist/session/file-session-service.d.ts +1 -1
  93. package/dist/session/file-session-service.d.ts.map +1 -1
  94. package/dist/session/{unified-session-persistence-service.d.ts → persistence-service.d.ts} +11 -42
  95. package/dist/session/persistence-service.d.ts.map +1 -0
  96. package/dist/session/rpc-session-service.d.ts +1 -1
  97. package/dist/session/rpc-session-service.d.ts.map +1 -1
  98. package/dist/session/session-agent-events.d.ts +1 -1
  99. package/dist/session/session-artifacts.d.ts.map +1 -1
  100. package/dist/session/session-config-builder.d.ts.map +1 -1
  101. package/dist/session/session-graph.d.ts +1 -1
  102. package/dist/session/session-graph.d.ts.map +1 -1
  103. package/dist/session/session-host.d.ts.map +1 -1
  104. package/dist/session/session-manager.d.ts +6 -5
  105. package/dist/session/session-manager.d.ts.map +1 -1
  106. package/dist/session/session-manifest.d.ts +1 -1
  107. package/dist/session/session-service.d.ts +3 -2
  108. package/dist/session/session-service.d.ts.map +1 -1
  109. package/dist/session/session-team-coordination.d.ts +2 -1
  110. package/dist/session/session-team-coordination.d.ts.map +1 -1
  111. package/dist/session/utils/helpers.d.ts +51 -3
  112. package/dist/session/utils/helpers.d.ts.map +1 -1
  113. package/dist/session/utils/types.d.ts +41 -7
  114. package/dist/session/utils/types.d.ts.map +1 -1
  115. package/dist/session/workspace-manager.d.ts +1 -2
  116. package/dist/session/workspace-manager.d.ts.map +1 -1
  117. package/dist/session/workspace-manifest.d.ts +1 -22
  118. package/dist/session/workspace-manifest.d.ts.map +1 -1
  119. package/dist/storage/file-team-store.d.ts +2 -1
  120. package/dist/storage/file-team-store.d.ts.map +1 -1
  121. package/dist/storage/sqlite-team-store.d.ts +4 -1
  122. package/dist/storage/sqlite-team-store.d.ts.map +1 -1
  123. package/dist/storage/team-store.d.ts.map +1 -1
  124. package/dist/team/delegated-agent.d.ts +44 -0
  125. package/dist/team/delegated-agent.d.ts.map +1 -0
  126. package/dist/team/index.d.ts +1 -0
  127. package/dist/team/index.d.ts.map +1 -1
  128. package/dist/team/multi-agent.d.ts +229 -0
  129. package/dist/team/multi-agent.d.ts.map +1 -0
  130. package/dist/team/projections.d.ts +2 -2
  131. package/dist/team/projections.d.ts.map +1 -1
  132. package/dist/team/runtime.d.ts +5 -0
  133. package/dist/team/runtime.d.ts.map +1 -0
  134. package/dist/team/spawn-agent-tool.d.ts +85 -0
  135. package/dist/team/spawn-agent-tool.d.ts.map +1 -0
  136. package/dist/team/subagent-prompts.d.ts +4 -0
  137. package/dist/team/subagent-prompts.d.ts.map +1 -0
  138. package/dist/team/team-tools.d.ts +35 -0
  139. package/dist/team/team-tools.d.ts.map +1 -0
  140. package/dist/telemetry/OpenTelemetryProvider.d.ts +11 -1
  141. package/dist/telemetry/OpenTelemetryProvider.d.ts.map +1 -1
  142. package/dist/telemetry/{LoggerTelemetryAdapter.d.ts → TelemetryLoggerSink.d.ts} +10 -4
  143. package/dist/telemetry/TelemetryLoggerSink.d.ts.map +1 -0
  144. package/dist/telemetry/TelemetryService.d.ts.map +1 -1
  145. package/dist/telemetry/index.js +15 -28
  146. package/dist/tools/definitions.d.ts +4 -3
  147. package/dist/tools/definitions.d.ts.map +1 -1
  148. package/dist/tools/index.d.ts +5 -5
  149. package/dist/tools/index.d.ts.map +1 -1
  150. package/dist/tools/model-tool-routing.d.ts.map +1 -1
  151. package/dist/tools/presets.d.ts +26 -0
  152. package/dist/tools/presets.d.ts.map +1 -1
  153. package/dist/tools/schemas.d.ts +8 -0
  154. package/dist/tools/schemas.d.ts.map +1 -1
  155. package/dist/tools/types.d.ts +23 -2
  156. package/dist/tools/types.d.ts.map +1 -1
  157. package/dist/types/config.d.ts +47 -3
  158. package/dist/types/config.d.ts.map +1 -1
  159. package/dist/types/events.d.ts +1 -1
  160. package/dist/types/provider-settings.d.ts +1 -1
  161. package/dist/types/provider-settings.d.ts.map +1 -1
  162. package/dist/types/storage.d.ts +2 -1
  163. package/dist/types/storage.d.ts.map +1 -1
  164. package/dist/types.d.ts +7 -16
  165. package/dist/types.d.ts.map +1 -1
  166. package/package.json +15 -12
  167. package/src/ClineCore.test.ts +150 -0
  168. package/src/ClineCore.ts +114 -8
  169. package/src/account/cline-account-service.test.ts +84 -0
  170. package/src/account/cline-account-service.ts +2 -2
  171. package/src/account/index.ts +1 -0
  172. package/src/account/types.ts +6 -0
  173. package/src/auth/bounded-ttl-cache.test.ts +38 -0
  174. package/src/auth/bounded-ttl-cache.ts +53 -0
  175. package/src/auth/cline.test.ts +173 -36
  176. package/src/auth/cline.ts +395 -93
  177. package/src/auth/oca.test.ts +125 -0
  178. package/src/auth/oca.ts +17 -4
  179. package/src/{agents → extensions/config}/agent-config-loader.test.ts +1 -1
  180. package/src/{agents → extensions/config}/agent-config-parser.ts +2 -2
  181. package/src/{agents → extensions/config}/hooks-config-loader.ts +1 -1
  182. package/src/{agents → extensions/config}/index.ts +7 -11
  183. package/src/{runtime/commands.test.ts → extensions/config/runtime-commands.test.ts} +20 -3
  184. package/src/{runtime/commands.ts → extensions/config/runtime-commands.ts} +1 -8
  185. package/src/{agents → extensions/config}/unified-config-file-watcher.ts +15 -2
  186. package/src/{agents → extensions/config}/user-instruction-config-loader.test.ts +90 -2
  187. package/src/{agents → extensions/config}/user-instruction-config-loader.ts +126 -12
  188. package/src/extensions/context/agentic-compaction.ts +119 -0
  189. package/src/extensions/context/basic-compaction.ts +275 -0
  190. package/src/extensions/context/compaction-shared.ts +458 -0
  191. package/src/extensions/context/compaction.test.ts +477 -0
  192. package/src/extensions/context/compaction.ts +203 -0
  193. package/src/extensions/index.ts +12 -0
  194. package/src/extensions/mcp/client.ts +420 -0
  195. package/src/{mcp → extensions/mcp}/index.ts +16 -0
  196. package/src/{mcp → extensions/mcp}/manager.test.ts +1 -2
  197. package/src/{mcp → extensions/mcp}/manager.ts +3 -5
  198. package/src/extensions/mcp/name-transform.ts +33 -0
  199. package/src/extensions/mcp/policies.ts +47 -0
  200. package/src/extensions/mcp/tools.ts +47 -0
  201. package/src/{mcp → extensions/mcp}/types.ts +35 -7
  202. package/src/{agents → extensions/plugin}/plugin-config-loader.test.ts +18 -13
  203. package/src/{agents → extensions/plugin}/plugin-config-loader.ts +1 -1
  204. package/src/{agents → extensions/plugin}/plugin-loader.test.ts +41 -4
  205. package/src/extensions/plugin/plugin-loader.ts +106 -0
  206. package/src/extensions/plugin/plugin-module-import.ts +278 -0
  207. package/src/{agents → extensions/plugin}/plugin-sandbox-bootstrap.ts +30 -92
  208. package/src/{agents → extensions/plugin}/plugin-sandbox.test.ts +60 -3
  209. package/src/{agents → extensions/plugin}/plugin-sandbox.ts +146 -56
  210. package/src/hooks/index.ts +25 -0
  211. package/src/hooks/persistent.ts +661 -0
  212. package/src/hooks/subprocess-runner.ts +196 -0
  213. package/src/hooks/subprocess.ts +669 -0
  214. package/src/index.ts +200 -118
  215. package/src/prompt/default-system.ts +21 -0
  216. package/src/providers/local-provider-registry.ts +1 -1
  217. package/src/providers/local-provider-service.test.ts +23 -2
  218. package/src/providers/local-provider-service.ts +2 -2
  219. package/src/runtime/checkpoint-hooks.test.ts +167 -0
  220. package/src/runtime/checkpoint-hooks.ts +186 -0
  221. package/src/runtime/hook-file-hooks.test.ts +40 -1
  222. package/src/runtime/hook-file-hooks.ts +35 -16
  223. package/src/runtime/index.ts +4 -19
  224. package/src/runtime/rules.ts +4 -1
  225. package/src/runtime/runtime-builder.team-persistence.test.ts +3 -6
  226. package/src/runtime/runtime-builder.test.ts +266 -160
  227. package/src/runtime/runtime-builder.ts +120 -47
  228. package/src/runtime/runtime-parity.test.ts +22 -22
  229. package/src/runtime/session-runtime.ts +36 -6
  230. package/src/runtime/{sandbox/subprocess-sandbox.ts → subprocess-sandbox.ts} +24 -3
  231. package/src/runtime/team-runtime-registry.ts +1 -4
  232. package/src/runtime/tool-approval.ts +1 -1
  233. package/src/session/default-session-manager.e2e.test.ts +2 -2
  234. package/src/session/default-session-manager.test.ts +553 -9
  235. package/src/session/default-session-manager.ts +140 -46
  236. package/src/session/file-session-service.ts +3 -3
  237. package/src/session/index.ts +6 -6
  238. package/src/session/persistence-service.test.ts +212 -0
  239. package/src/session/{unified-session-persistence-service.ts → persistence-service.ts} +106 -172
  240. package/src/session/rpc-session-service.ts +3 -3
  241. package/src/session/runtime-oauth-token-manager.ts +1 -1
  242. package/src/session/session-agent-events.ts +1 -1
  243. package/src/session/session-artifacts.ts +32 -4
  244. package/src/session/session-config-builder.ts +22 -9
  245. package/src/session/session-graph.ts +1 -1
  246. package/src/session/session-host.ts +19 -11
  247. package/src/session/session-manager.ts +11 -6
  248. package/src/session/session-service.team-persistence.test.ts +1 -1
  249. package/src/session/session-service.ts +6 -9
  250. package/src/session/session-team-coordination.ts +7 -3
  251. package/src/session/session-telemetry.ts +1 -1
  252. package/src/session/utils/helpers.test.ts +160 -0
  253. package/src/session/utils/helpers.ts +289 -42
  254. package/src/session/utils/types.ts +47 -7
  255. package/src/session/workspace-manager.ts +5 -3
  256. package/src/session/workspace-manifest.ts +3 -49
  257. package/src/storage/file-team-store.ts +2 -5
  258. package/src/storage/provider-settings-legacy-migration.ts +2 -2
  259. package/src/storage/provider-settings-manager.test.ts +1 -1
  260. package/src/storage/sqlite-team-store.ts +212 -125
  261. package/src/storage/team-store.ts +1 -5
  262. package/src/team/delegated-agent.ts +131 -0
  263. package/src/team/index.ts +1 -0
  264. package/src/team/multi-agent.lifecycle.test.ts +201 -0
  265. package/src/team/multi-agent.ts +1666 -0
  266. package/src/team/projections.ts +2 -4
  267. package/src/team/runtime.ts +54 -0
  268. package/src/team/spawn-agent-tool.test.ts +387 -0
  269. package/src/team/spawn-agent-tool.ts +207 -0
  270. package/src/team/subagent-prompts.ts +41 -0
  271. package/src/team/team-tools.test.ts +802 -0
  272. package/src/team/team-tools.ts +792 -0
  273. package/src/telemetry/OpenTelemetryProvider.test.ts +25 -3
  274. package/src/telemetry/OpenTelemetryProvider.ts +108 -18
  275. package/src/telemetry/TelemetryLoggerSink.test.ts +42 -0
  276. package/src/telemetry/{LoggerTelemetryAdapter.ts → TelemetryLoggerSink.ts} +21 -14
  277. package/src/telemetry/TelemetryService.test.ts +7 -7
  278. package/src/telemetry/TelemetryService.ts +2 -4
  279. package/src/tools/definitions.test.ts +76 -0
  280. package/src/tools/definitions.ts +41 -2
  281. package/src/tools/executors/apply-patch.ts +1 -1
  282. package/src/tools/executors/editor.ts +1 -1
  283. package/src/tools/executors/file-read.ts +1 -1
  284. package/src/tools/executors/search.ts +1 -1
  285. package/src/tools/executors/web-fetch.ts +1 -1
  286. package/src/tools/index.ts +6 -1
  287. package/src/tools/model-tool-routing.ts +2 -0
  288. package/src/tools/presets.test.ts +8 -0
  289. package/src/tools/presets.ts +40 -2
  290. package/src/tools/schemas.ts +19 -0
  291. package/src/tools/types.ts +31 -2
  292. package/src/types/config.ts +61 -7
  293. package/src/types/events.ts +1 -1
  294. package/src/types/index.ts +0 -1
  295. package/src/types/provider-settings.ts +1 -1
  296. package/src/types/storage.ts +2 -5
  297. package/src/types.ts +32 -44
  298. package/dist/agents/agent-config-loader.d.ts.map +0 -1
  299. package/dist/agents/agent-config-parser.d.ts.map +0 -1
  300. package/dist/agents/hooks-config-loader.d.ts.map +0 -1
  301. package/dist/agents/index.d.ts.map +0 -1
  302. package/dist/agents/plugin-config-loader.d.ts.map +0 -1
  303. package/dist/agents/plugin-loader.d.ts.map +0 -1
  304. package/dist/agents/plugin-sandbox-bootstrap.js +0 -446
  305. package/dist/agents/plugin-sandbox.d.ts.map +0 -1
  306. package/dist/agents/unified-config-file-watcher.d.ts.map +0 -1
  307. package/dist/agents/user-instruction-config-loader.d.ts.map +0 -1
  308. package/dist/mcp/config-loader.d.ts.map +0 -1
  309. package/dist/mcp/index.d.ts +0 -5
  310. package/dist/mcp/index.d.ts.map +0 -1
  311. package/dist/mcp/manager.d.ts.map +0 -1
  312. package/dist/mcp/types.d.ts.map +0 -1
  313. package/dist/runtime/commands.d.ts.map +0 -1
  314. package/dist/runtime/sandbox/subprocess-sandbox.d.ts.map +0 -1
  315. package/dist/runtime/skills.d.ts +0 -14
  316. package/dist/runtime/skills.d.ts.map +0 -1
  317. package/dist/runtime/workflows.d.ts +0 -14
  318. package/dist/runtime/workflows.d.ts.map +0 -1
  319. package/dist/session/unified-session-persistence-service.d.ts.map +0 -1
  320. package/dist/telemetry/LoggerTelemetryAdapter.d.ts.map +0 -1
  321. package/dist/types/workspace.d.ts +0 -8
  322. package/dist/types/workspace.d.ts.map +0 -1
  323. package/src/agents/plugin-loader.ts +0 -175
  324. package/src/runtime/skills.ts +0 -44
  325. package/src/runtime/workflows.test.ts +0 -119
  326. package/src/runtime/workflows.ts +0 -45
  327. package/src/session/unified-session-persistence-service.test.ts +0 -85
  328. package/src/telemetry/LoggerTelemetryAdapter.test.ts +0 -42
  329. package/src/types/workspace.ts +0 -7
  330. /package/dist/{agents → extensions/config}/agent-config-loader.d.ts +0 -0
  331. /package/dist/{agents → extensions/config}/unified-config-file-watcher.d.ts +0 -0
  332. /package/dist/{agents → extensions/config}/user-instruction-config-loader.d.ts +0 -0
  333. /package/dist/{mcp → extensions/mcp}/config-loader.d.ts +0 -0
  334. /package/dist/runtime/{sandbox/subprocess-sandbox.d.ts → subprocess-sandbox.d.ts} +0 -0
  335. /package/src/{agents → extensions/config}/agent-config-loader.ts +0 -0
  336. /package/src/{agents → extensions/config}/hooks-config-loader.test.ts +0 -0
  337. /package/src/{agents → extensions/config}/unified-config-file-watcher.test.ts +0 -0
  338. /package/src/{mcp → extensions/mcp}/config-loader.test.ts +0 -0
  339. /package/src/{mcp → extensions/mcp}/config-loader.ts +0 -0
@@ -52,6 +52,29 @@ describe("createOpenTelemetryTelemetryService", () => {
52
52
  await provider.dispose();
53
53
  });
54
54
 
55
+ it("registers a tracer provider when tracesExporter is set", async () => {
56
+ const { provider } = createOpenTelemetryTelemetryService({
57
+ metadata: {
58
+ extension_version: "1.2.3",
59
+ cline_type: "cli",
60
+ platform: "terminal",
61
+ platform_version: process.version,
62
+ os_type: process.platform,
63
+ os_version: "unknown",
64
+ },
65
+ enabled: true,
66
+ tracesExporter: "console",
67
+ logsExporter: "console",
68
+ metricsExporter: "console",
69
+ serviceName: "cline-test",
70
+ });
71
+
72
+ expect(provider.tracerProvider).not.toBeNull();
73
+ const span = provider.getTracer("test").startSpan("verify.tracing");
74
+ span.end();
75
+ await provider.dispose();
76
+ });
77
+
55
78
  it("does not create an OTEL provider when disabled", () => {
56
79
  const providerSpy = vi.spyOn(
57
80
  OpenTelemetryProvider.prototype,
@@ -78,8 +101,7 @@ describe("createOpenTelemetryTelemetryService", () => {
78
101
  it("attaches the logger adapter when creating configured telemetry", () => {
79
102
  const logger: BasicLogger = {
80
103
  debug: vi.fn(),
81
- info: vi.fn(),
82
- warn: vi.fn(),
104
+ log: vi.fn(),
83
105
  error: vi.fn(),
84
106
  };
85
107
  const { telemetry, provider } = createConfiguredTelemetryService({
@@ -101,7 +123,7 @@ describe("createOpenTelemetryTelemetryService", () => {
101
123
  properties: { sessionId: "session-1" },
102
124
  });
103
125
 
104
- expect(logger.info).toHaveBeenCalledWith(
126
+ expect(logger.log).toHaveBeenCalledWith(
105
127
  "telemetry.event",
106
128
  expect.objectContaining({
107
129
  event: "session.started",
@@ -4,11 +4,12 @@ import type {
4
4
  OpenTelemetryClientConfig,
5
5
  TelemetryMetadata,
6
6
  } from "@clinebot/shared";
7
- import { metrics } from "@opentelemetry/api";
7
+ import { metrics, type Tracer, trace } from "@opentelemetry/api";
8
8
  import { logs } from "@opentelemetry/api-logs";
9
9
  import { OTLPLogExporter as OTLPLogExporterHttp } from "@opentelemetry/exporter-logs-otlp-http";
10
10
  import { OTLPMetricExporter as OTLPMetricExporterHttp } from "@opentelemetry/exporter-metrics-otlp-http";
11
- import { Resource } from "@opentelemetry/resources";
11
+ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
12
+ import { resourceFromAttributes } from "@opentelemetry/resources";
12
13
  import {
13
14
  BatchLogRecordProcessor,
14
15
  ConsoleLogRecordExporter,
@@ -21,6 +22,13 @@ import {
21
22
  type MetricReader,
22
23
  PeriodicExportingMetricReader,
23
24
  } from "@opentelemetry/sdk-metrics";
25
+ import {
26
+ BatchSpanProcessor,
27
+ ConsoleSpanExporter,
28
+ SimpleSpanProcessor,
29
+ type SpanProcessor,
30
+ } from "@opentelemetry/sdk-trace-base";
31
+ import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
24
32
  import {
25
33
  ATTR_SERVICE_NAME,
26
34
  ATTR_SERVICE_VERSION,
@@ -38,13 +46,14 @@ type OpenTelemetryProtocol = "http/json";
38
46
  export interface OpenTelemetryProviderOptions
39
47
  extends Omit<
40
48
  OpenTelemetryClientConfig,
41
- "enabled" | "logsExporter" | "metricsExporter"
49
+ "enabled" | "logsExporter" | "metricsExporter" | "tracesExporter"
42
50
  > {
43
51
  serviceName?: string;
44
52
  serviceVersion?: string;
45
53
  enabled?: boolean;
46
54
  logsExporter?: string | OpenTelemetryExporterKind[];
47
55
  metricsExporter?: string | OpenTelemetryExporterKind[];
56
+ tracesExporter?: string | OpenTelemetryExporterKind[];
48
57
  metricExportIntervalMs?: number;
49
58
  logMaxQueueSize?: number;
50
59
  logBatchSize?: number;
@@ -64,11 +73,12 @@ export interface CreateOpenTelemetryTelemetryServiceOptions
64
73
  export class OpenTelemetryProvider {
65
74
  readonly meterProvider: MeterProvider | null;
66
75
  readonly loggerProvider: LoggerProvider | null;
76
+ readonly tracerProvider: NodeTracerProvider | null;
67
77
  private readonly options: OpenTelemetryProviderOptions;
68
78
 
69
79
  constructor(options: OpenTelemetryProviderOptions = {}) {
70
80
  this.options = options;
71
- const resource = new Resource({
81
+ const resource = resourceFromAttributes({
72
82
  [ATTR_SERVICE_NAME]: options.serviceName ?? "cline",
73
83
  ...(options.serviceVersion
74
84
  ? { [ATTR_SERVICE_VERSION]: options.serviceVersion }
@@ -77,6 +87,7 @@ export class OpenTelemetryProvider {
77
87
 
78
88
  this.meterProvider = this.createMeterProvider(resource);
79
89
  this.loggerProvider = this.createLoggerProvider(resource);
90
+ this.tracerProvider = this.createTracerProvider(resource);
80
91
 
81
92
  if (this.meterProvider) {
82
93
  metrics.setGlobalMeterProvider(this.meterProvider);
@@ -84,6 +95,17 @@ export class OpenTelemetryProvider {
84
95
  if (this.loggerProvider) {
85
96
  logs.setGlobalLoggerProvider(this.loggerProvider);
86
97
  }
98
+ if (this.tracerProvider) {
99
+ this.tracerProvider.register();
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Returns a tracer for manual spans. Requires {@link OpenTelemetryProviderOptions.tracesExporter}
105
+ * so that a {@link NodeTracerProvider} is registered.
106
+ */
107
+ getTracer(name = "cline", version?: string): Tracer {
108
+ return trace.getTracer(name, version ?? this.options.serviceVersion);
87
109
  }
88
110
 
89
111
  createAdapter(
@@ -122,6 +144,7 @@ export class OpenTelemetryProvider {
122
144
  await Promise.all([
123
145
  this.meterProvider?.forceFlush?.(),
124
146
  this.loggerProvider?.forceFlush?.(),
147
+ this.tracerProvider?.forceFlush?.(),
125
148
  ]);
126
149
  }
127
150
 
@@ -129,10 +152,13 @@ export class OpenTelemetryProvider {
129
152
  await Promise.all([
130
153
  this.meterProvider?.shutdown?.(),
131
154
  this.loggerProvider?.shutdown?.(),
155
+ this.tracerProvider?.shutdown?.(),
132
156
  ]);
133
157
  }
134
158
 
135
- private createMeterProvider(resource: Resource): MeterProvider | null {
159
+ private createMeterProvider(
160
+ resource: ReturnType<typeof resourceFromAttributes>,
161
+ ): MeterProvider | null {
136
162
  const exporters = normalizeExporters(this.options.metricsExporter);
137
163
  if (exporters.length === 0) {
138
164
  return null;
@@ -168,35 +194,71 @@ export class OpenTelemetryProvider {
168
194
  });
169
195
  }
170
196
 
171
- private createLoggerProvider(resource: Resource): LoggerProvider | null {
172
- const exporters = normalizeExporters(this.options.logsExporter);
197
+ private createTracerProvider(
198
+ resource: ReturnType<typeof resourceFromAttributes>,
199
+ ): NodeTracerProvider | null {
200
+ const exporters = normalizeExporters(this.options.tracesExporter);
173
201
  if (exporters.length === 0) {
174
202
  return null;
175
203
  }
176
204
 
177
- const provider = new LoggerProvider({ resource });
205
+ const traceEndpoint =
206
+ this.options.otlpTracesEndpoint ?? this.options.otlpEndpoint;
207
+ const traceHeaders =
208
+ this.options.otlpTracesHeaders ?? this.options.otlpHeaders;
209
+
210
+ const processors: SpanProcessor[] = [];
178
211
  for (const exporter of exporters) {
179
- const logExporter = createLogExporter(exporter, {
180
- endpoint: this.options.otlpEndpoint,
181
- headers: this.options.otlpHeaders,
212
+ const processor = createSpanProcessor(exporter, {
213
+ endpoint: traceEndpoint,
214
+ headers: traceHeaders,
182
215
  insecure: this.options.otlpInsecure ?? false,
183
216
  protocol: "http/json",
184
217
  });
185
- if (!logExporter) {
186
- continue;
218
+ if (processor) {
219
+ processors.push(processor);
187
220
  }
188
- provider.addLogRecordProcessor(
189
- new BatchLogRecordProcessor(logExporter, {
221
+ }
222
+ if (processors.length === 0) {
223
+ return null;
224
+ }
225
+
226
+ return new NodeTracerProvider({ resource, spanProcessors: processors });
227
+ }
228
+
229
+ private createLoggerProvider(
230
+ resource: ReturnType<typeof resourceFromAttributes>,
231
+ ): LoggerProvider | null {
232
+ const exporters = normalizeExporters(this.options.logsExporter);
233
+ if (exporters.length === 0) {
234
+ return null;
235
+ }
236
+
237
+ const processors = exporters
238
+ .map((exporter) => {
239
+ const logExporter = createLogExporter(exporter, {
240
+ endpoint: this.options.otlpEndpoint,
241
+ headers: this.options.otlpHeaders,
242
+ insecure: this.options.otlpInsecure ?? false,
243
+ protocol: "http/json",
244
+ });
245
+ if (!logExporter) {
246
+ return null;
247
+ }
248
+ return new BatchLogRecordProcessor(logExporter, {
190
249
  maxQueueSize: this.options.logMaxQueueSize ?? 2048,
191
250
  maxExportBatchSize: this.options.logBatchSize ?? 512,
192
251
  scheduledDelayMillis:
193
252
  this.options.logBatchTimeoutMs ??
194
253
  this.options.logBatchTimeout ??
195
254
  5000,
196
- }),
197
- );
255
+ });
256
+ })
257
+ .filter((p): p is BatchLogRecordProcessor => p !== null);
258
+ if (processors.length === 0) {
259
+ return null;
198
260
  }
199
- return provider;
261
+ return new LoggerProvider({ resource, processors });
200
262
  }
201
263
  }
202
264
 
@@ -214,6 +276,9 @@ export function createOpenTelemetryTelemetryService(
214
276
  metricsExporter: Array.isArray(options.metricsExporter)
215
277
  ? options.metricsExporter.join(",")
216
278
  : options.metricsExporter,
279
+ tracesExporter: Array.isArray(options.tracesExporter)
280
+ ? options.tracesExporter.join(",")
281
+ : options.tracesExporter,
217
282
  otlpProtocol: options.otlpProtocol,
218
283
  hasOtlpEndpoint: Boolean(options.otlpEndpoint),
219
284
  serviceName: options.serviceName,
@@ -280,6 +345,31 @@ function createLogExporter(
280
345
  });
281
346
  }
282
347
 
348
+ function createSpanProcessor(
349
+ exporter: OpenTelemetryExporterKind,
350
+ options: {
351
+ endpoint?: string;
352
+ headers?: Record<string, string>;
353
+ insecure: boolean;
354
+ protocol: OpenTelemetryProtocol;
355
+ },
356
+ ): SpanProcessor | null {
357
+ if (exporter === "console") {
358
+ return new SimpleSpanProcessor(new ConsoleSpanExporter());
359
+ }
360
+ if (!options.endpoint) {
361
+ return null;
362
+ }
363
+
364
+ const endpoint = ensurePathSuffix(options.endpoint, "/v1/traces");
365
+ return new BatchSpanProcessor(
366
+ new OTLPTraceExporter({
367
+ url: endpoint,
368
+ headers: options.headers,
369
+ }),
370
+ );
371
+ }
372
+
283
373
  function createMetricReader(
284
374
  exporter: OpenTelemetryExporterKind,
285
375
  options: {
@@ -0,0 +1,42 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { TelemetryLoggerSink } from "./TelemetryLoggerSink";
3
+
4
+ describe("TelemetryLoggerSink", () => {
5
+ it("logs events and metrics through the provided logger", async () => {
6
+ const logger = {
7
+ debug: vi.fn(),
8
+ log: vi.fn(),
9
+ };
10
+ const sink = new TelemetryLoggerSink({ logger });
11
+
12
+ sink.emit("session.started", { sessionId: "s1" });
13
+ sink.emitRequired("user.opt_out", { reason: "manual" });
14
+ sink.recordCounter("cline.session.starts.total", 1, {
15
+ sessionId: "s1",
16
+ });
17
+
18
+ expect(logger.log).toHaveBeenCalledWith("telemetry.event", {
19
+ telemetrySink: "TelemetryLoggerSink",
20
+ event: "session.started",
21
+ properties: { sessionId: "s1" },
22
+ });
23
+ expect(logger.log).toHaveBeenCalledWith("telemetry.required_event", {
24
+ telemetrySink: "TelemetryLoggerSink",
25
+ severity: "warn",
26
+ event: "user.opt_out",
27
+ properties: { reason: "manual" },
28
+ });
29
+ expect(logger.debug).toHaveBeenCalledWith("telemetry.metric", {
30
+ telemetrySink: "TelemetryLoggerSink",
31
+ instrument: "counter",
32
+ name: "cline.session.starts.total",
33
+ value: 1,
34
+ attributes: { sessionId: "s1" },
35
+ description: undefined,
36
+ required: false,
37
+ });
38
+
39
+ await sink.flush();
40
+ await sink.dispose();
41
+ });
42
+ });
@@ -4,20 +4,26 @@ import type {
4
4
  TelemetryProperties,
5
5
  } from "./ITelemetryAdapter";
6
6
 
7
- export interface LoggerTelemetryAdapterOptions {
7
+ /**
8
+ * {@link ITelemetryAdapter} implementation that forwards telemetry to a {@link BasicLogger}.
9
+ *
10
+ * This is intentionally named *Sink* (not "adapter") to distinguish it from host logging bridges
11
+ * such as the CLI Pino bundle: it consumes telemetry events and writes them to the injected logger.
12
+ */
13
+ export interface TelemetryLoggerSinkOptions {
8
14
  logger?: BasicLogger;
9
15
  name?: string;
10
16
  enabled?: boolean | (() => boolean);
11
17
  }
12
18
 
13
- export class LoggerTelemetryAdapter implements ITelemetryAdapter {
19
+ export class TelemetryLoggerSink implements ITelemetryAdapter {
14
20
  readonly name: string;
15
21
 
16
22
  private readonly logger?: BasicLogger;
17
23
  private readonly enabled: boolean | (() => boolean);
18
24
 
19
- constructor(options: LoggerTelemetryAdapterOptions = {}) {
20
- this.name = options.name ?? "LoggerTelemetryAdapter";
25
+ constructor(options: TelemetryLoggerSinkOptions = {}) {
26
+ this.name = options.name ?? "TelemetryLoggerSink";
21
27
  this.logger = options.logger;
22
28
  this.enabled = options.enabled ?? true;
23
29
  }
@@ -26,16 +32,17 @@ export class LoggerTelemetryAdapter implements ITelemetryAdapter {
26
32
  if (!this.isEnabled()) {
27
33
  return;
28
34
  }
29
- this.logger?.info?.("telemetry.event", {
30
- adapter: this.name,
35
+ this.logger?.log("telemetry.event", {
36
+ telemetrySink: this.name,
31
37
  event,
32
38
  properties,
33
39
  });
34
40
  }
35
41
 
36
42
  emitRequired(event: string, properties?: TelemetryProperties): void {
37
- this.logger?.warn?.("telemetry.required_event", {
38
- adapter: this.name,
43
+ this.logger?.log("telemetry.required_event", {
44
+ telemetrySink: this.name,
45
+ severity: "warn",
39
46
  event,
40
47
  properties,
41
48
  });
@@ -51,8 +58,8 @@ export class LoggerTelemetryAdapter implements ITelemetryAdapter {
51
58
  if (!required && !this.isEnabled()) {
52
59
  return;
53
60
  }
54
- this.logger?.debug?.("telemetry.metric", {
55
- adapter: this.name,
61
+ this.logger?.debug("telemetry.metric", {
62
+ telemetrySink: this.name,
56
63
  instrument: "counter",
57
64
  name,
58
65
  value,
@@ -72,8 +79,8 @@ export class LoggerTelemetryAdapter implements ITelemetryAdapter {
72
79
  if (!required && !this.isEnabled()) {
73
80
  return;
74
81
  }
75
- this.logger?.debug?.("telemetry.metric", {
76
- adapter: this.name,
82
+ this.logger?.debug("telemetry.metric", {
83
+ telemetrySink: this.name,
77
84
  instrument: "histogram",
78
85
  name,
79
86
  value,
@@ -93,8 +100,8 @@ export class LoggerTelemetryAdapter implements ITelemetryAdapter {
93
100
  if (!required && !this.isEnabled()) {
94
101
  return;
95
102
  }
96
- this.logger?.debug?.("telemetry.metric", {
97
- adapter: this.name,
103
+ this.logger?.debug("telemetry.metric", {
104
+ telemetrySink: this.name,
98
105
  instrument: "gauge",
99
106
  name,
100
107
  value,
@@ -53,8 +53,7 @@ describe("TelemetryService", () => {
53
53
  it("mirrors telemetry events into the logger when provided", () => {
54
54
  const logger: BasicLogger = {
55
55
  debug: vi.fn(),
56
- info: vi.fn(),
57
- warn: vi.fn(),
56
+ log: vi.fn(),
58
57
  error: vi.fn(),
59
58
  };
60
59
  const service = new TelemetryService({
@@ -75,10 +74,10 @@ describe("TelemetryService", () => {
75
74
  sessionId: "session-1",
76
75
  });
77
76
 
78
- expect(logger.info).toHaveBeenCalledWith(
77
+ expect(logger.log).toHaveBeenCalledWith(
79
78
  "telemetry.event",
80
79
  expect.objectContaining({
81
- adapter: "LoggerTelemetryAdapter",
80
+ telemetrySink: "TelemetryLoggerSink",
82
81
  event: "session.started",
83
82
  properties: expect.objectContaining({
84
83
  sessionId: "session-1",
@@ -87,10 +86,11 @@ describe("TelemetryService", () => {
87
86
  }),
88
87
  }),
89
88
  );
90
- expect(logger.warn).toHaveBeenCalledWith(
89
+ expect(logger.log).toHaveBeenCalledWith(
91
90
  "telemetry.required_event",
92
91
  expect.objectContaining({
93
- adapter: "LoggerTelemetryAdapter",
92
+ telemetrySink: "TelemetryLoggerSink",
93
+ severity: "warn",
94
94
  event: "user.opt_out",
95
95
  properties: expect.objectContaining({
96
96
  reason: "manual",
@@ -101,7 +101,7 @@ describe("TelemetryService", () => {
101
101
  expect(logger.debug).toHaveBeenCalledWith(
102
102
  "telemetry.metric",
103
103
  expect.objectContaining({
104
- adapter: "LoggerTelemetryAdapter",
104
+ telemetrySink: "TelemetryLoggerSink",
105
105
  instrument: "counter",
106
106
  name: "cline.session.starts.total",
107
107
  }),
@@ -5,7 +5,7 @@ import type {
5
5
  TelemetryProperties,
6
6
  } from "@clinebot/shared";
7
7
  import type { ITelemetryAdapter } from "./ITelemetryAdapter";
8
- import { LoggerTelemetryAdapter } from "./LoggerTelemetryAdapter";
8
+ import { TelemetryLoggerSink } from "./TelemetryLoggerSink";
9
9
 
10
10
  export interface TelemetryServiceOptions {
11
11
  adapters?: ITelemetryAdapter[];
@@ -24,9 +24,7 @@ export class TelemetryService implements ITelemetryService {
24
24
  constructor(options: TelemetryServiceOptions = {}) {
25
25
  this.adapters = [...(options.adapters ?? [])];
26
26
  if (options.logger) {
27
- this.adapters.push(
28
- new LoggerTelemetryAdapter({ logger: options.logger }),
29
- );
27
+ this.adapters.push(new TelemetryLoggerSink({ logger: options.logger }));
30
28
  }
31
29
  this.metadata = { ...(options.metadata ?? {}) };
32
30
  this.distinctId = options.distinctId;
@@ -187,6 +187,82 @@ describe("default ask_question tool", () => {
187
187
  });
188
188
  });
189
189
 
190
+ describe("default submit_and_exit tool", () => {
191
+ it("is excluded by default even when executor is provided", () => {
192
+ const tools = createDefaultTools({
193
+ executors: {
194
+ submit: async () => "ok",
195
+ },
196
+ });
197
+ expect(tools.map((tool) => tool.name)).not.toContain("submit_and_exit");
198
+ });
199
+
200
+ it("is included only when enabled with a submit executor", () => {
201
+ const toolsWithoutExecutor = createDefaultTools({
202
+ executors: {},
203
+ enableSubmitAndExit: true,
204
+ });
205
+ expect(toolsWithoutExecutor.map((tool) => tool.name)).not.toContain(
206
+ "submit_and_exit",
207
+ );
208
+
209
+ const toolsWithExecutor = createDefaultTools({
210
+ executors: {
211
+ submit: async () => "ok",
212
+ },
213
+ enableSubmitAndExit: true,
214
+ });
215
+ expect(toolsWithExecutor.map((tool) => tool.name)).toContain(
216
+ "submit_and_exit",
217
+ );
218
+ });
219
+
220
+ it("validates and executes submit_and_exit input", async () => {
221
+ const execute = vi.fn(async () => "submitted");
222
+ const tools = createDefaultTools({
223
+ executors: {
224
+ submit: execute,
225
+ },
226
+ enableReadFiles: false,
227
+ enableSearch: false,
228
+ enableBash: false,
229
+ enableWebFetch: false,
230
+ enableEditor: false,
231
+ enableSkills: false,
232
+ enableAskQuestion: false,
233
+ enableSubmitAndExit: true,
234
+ });
235
+ const submitTool = tools.find((tool) => tool.name === "submit_and_exit");
236
+ expect(submitTool).toBeDefined();
237
+ if (!submitTool) {
238
+ throw new Error("Expected submit_and_exit tool to be defined.");
239
+ }
240
+
241
+ const result = await submitTool.execute(
242
+ {
243
+ summary: "Done and verified with the requested checks.",
244
+ verified: true,
245
+ },
246
+ {
247
+ agentId: "agent-1",
248
+ conversationId: "conv-1",
249
+ iteration: 1,
250
+ },
251
+ );
252
+
253
+ expect(result).toBe("submitted");
254
+ expect(execute).toHaveBeenCalledWith(
255
+ "Done and verified with the requested checks.",
256
+ true,
257
+ expect.objectContaining({
258
+ agentId: "agent-1",
259
+ conversationId: "conv-1",
260
+ iteration: 1,
261
+ }),
262
+ );
263
+ });
264
+ });
265
+
190
266
  describe("default apply_patch tool", () => {
191
267
  it("is included only when enabled with an applyPatch executor", () => {
192
268
  const toolsWithoutExecutor = createDefaultTools({
@@ -4,8 +4,12 @@
4
4
  * Factory functions for creating the default tools.
5
5
  */
6
6
 
7
- import { createTool, type Tool } from "@clinebot/agents";
8
- import { validateWithZod, zodToJsonSchema } from "@clinebot/shared";
7
+ import {
8
+ createTool,
9
+ type Tool,
10
+ validateWithZod,
11
+ zodToJsonSchema,
12
+ } from "@clinebot/shared";
9
13
  import {
10
14
  formatError,
11
15
  formatReadFileQuery,
@@ -37,6 +41,8 @@ import {
37
41
  SkillsInputSchema,
38
42
  type StructuredCommandInput,
39
43
  StructuredCommandsInputUnionSchema,
44
+ type SubmitInput,
45
+ SubmitInputSchema,
40
46
  } from "./schemas";
41
47
  import type {
42
48
  ApplyPatchExecutor,
@@ -49,6 +55,7 @@ import type {
49
55
  SearchExecutor,
50
56
  SkillsExecutorWithMetadata,
51
57
  ToolOperationResult,
58
+ VerifySubmitExecutor,
52
59
  WebFetchExecutor,
53
60
  } from "./types";
54
61
 
@@ -603,6 +610,34 @@ export function createAskQuestionTool(
603
610
  });
604
611
  }
605
612
 
613
+ export function createSubmitAndExitTool(
614
+ executor: VerifySubmitExecutor,
615
+ config: Pick<DefaultToolsConfig, "submitTimeoutMs"> = {},
616
+ ): Tool<SubmitInput, string> {
617
+ const timeoutMs = config.submitTimeoutMs ?? 15000;
618
+
619
+ return createTool<SubmitInput, string>({
620
+ name: "submit_and_exit",
621
+ description:
622
+ "Submit the final answer and exit the conversation. " +
623
+ "For example, submit a summary of the investigation and confirm the issue is resolved. " +
624
+ "You should only submit once all necessary steps are completed. " +
625
+ "Provide a summary of the investigation and confirm the issue is resolved.",
626
+ inputSchema: zodToJsonSchema(SubmitInputSchema),
627
+ timeoutMs,
628
+ retryable: false,
629
+ maxRetries: 0,
630
+ execute: async (input, context) => {
631
+ const validatedInput = validateWithZod(SubmitInputSchema, input);
632
+ return withTimeout(
633
+ executor(validatedInput.summary, validatedInput.verified, context),
634
+ timeoutMs,
635
+ `submit_and_exit timed out after ${timeoutMs}ms`,
636
+ );
637
+ },
638
+ });
639
+ }
640
+
606
641
  // =============================================================================
607
642
  // Default Tools Factory
608
643
  // =============================================================================
@@ -657,6 +692,7 @@ export function createDefaultTools(options: CreateDefaultToolsOptions): Tool[] {
657
692
  enableEditor = true,
658
693
  enableSkills = true,
659
694
  enableAskQuestion = true,
695
+ enableSubmitAndExit = false,
660
696
  ...config
661
697
  } = options;
662
698
 
@@ -703,6 +739,9 @@ export function createDefaultTools(options: CreateDefaultToolsOptions): Tool[] {
703
739
  // Add ask_question tool if enabled and executor provided
704
740
  if (enableAskQuestion && executors.askQuestion) {
705
741
  tools.push(createAskQuestionTool(executors.askQuestion, config));
742
+ } else if (enableSubmitAndExit && executors.submit) {
743
+ // Add submit_and_exit tool if enabled and executor provided
744
+ tools.push(createSubmitAndExitTool(executors.submit, config));
706
745
  }
707
746
 
708
747
  return tools;
@@ -6,7 +6,7 @@
6
6
 
7
7
  import * as fs from "node:fs/promises";
8
8
  import * as path from "node:path";
9
- import type { ToolContext } from "@clinebot/agents";
9
+ import type { ToolContext } from "@clinebot/shared";
10
10
  import type { ApplyPatchInput } from "../schemas";
11
11
  import type { ApplyPatchExecutor } from "../types";
12
12
  import {
@@ -6,7 +6,7 @@
6
6
 
7
7
  import * as fs from "node:fs/promises";
8
8
  import * as path from "node:path";
9
- import type { ToolContext } from "@clinebot/agents";
9
+ import type { ToolContext } from "@clinebot/shared";
10
10
  import type { EditFileInput } from "../schemas";
11
11
  import type { EditorExecutor } from "../types";
12
12
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  import * as fs from "node:fs/promises";
8
8
  import * as path from "node:path";
9
- import type { ToolContext } from "@clinebot/agents";
9
+ import type { ToolContext } from "@clinebot/shared";
10
10
  import type { ReadFileRequest } from "../schemas";
11
11
  import type { FileReadExecutor } from "../types";
12
12
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  import * as fs from "node:fs/promises";
8
8
  import * as path from "node:path";
9
- import type { ToolContext } from "@clinebot/agents";
9
+ import type { ToolContext } from "@clinebot/shared";
10
10
  import { getFileIndex } from "../../input";
11
11
  import type { SearchExecutor } from "../types";
12
12
 
@@ -4,7 +4,7 @@
4
4
  * Built-in implementation for fetching web content using native fetch.
5
5
  */
6
6
 
7
- import type { ToolContext } from "@clinebot/agents";
7
+ import type { ToolContext } from "@clinebot/shared";
8
8
  import type { WebFetchExecutor } from "../types";
9
9
 
10
10
  /**