@clinebot/core 0.0.27 → 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 +8 -8
  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 +16 -13
  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
package/src/auth/oca.ts CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  captureAuthSucceeded,
8
8
  identifyAccount,
9
9
  } from "../telemetry/core-events";
10
+ import { BoundedTtlCache } from "./bounded-ttl-cache";
10
11
  import { startLocalOAuthServer } from "./server";
11
12
  import type {
12
13
  OAuthCredentials,
@@ -113,7 +114,14 @@ const OCA_CONFIG_DEFAULTS: OcaOAuthConfig = {
113
114
  };
114
115
 
115
116
  const OCA_FLOW_STATE = new Map<string, OcaAuthFlowState>();
116
- const DISCOVERY_CACHE = new Map<string, string>();
117
+ /** OpenID discovery documents change rarely; bound memory in long-lived processes. */
118
+ const DISCOVERY_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
119
+ const DISCOVERY_ERROR_FALLBACK_TTL_MS = 5 * 60 * 1000;
120
+ const DISCOVERY_CACHE_MAX_ENTRIES = 32;
121
+ const discoveryEndpointCache = new BoundedTtlCache(
122
+ DISCOVERY_CACHE_TTL_MS,
123
+ DISCOVERY_CACHE_MAX_ENTRIES,
124
+ );
117
125
 
118
126
  function resolveMode(mode?: OcaMode | (() => OcaMode)): OcaMode {
119
127
  if (typeof mode === "function") {
@@ -219,7 +227,7 @@ async function discoverTokenEndpoint(
219
227
  requestTimeoutMs: number,
220
228
  ): Promise<string> {
221
229
  const normalizedIdcsUrl = normalizeBaseUrl(idcsUrl);
222
- const cached = DISCOVERY_CACHE.get(normalizedIdcsUrl);
230
+ const cached = discoveryEndpointCache.get(normalizedIdcsUrl);
223
231
  if (cached) {
224
232
  return cached;
225
233
  }
@@ -232,14 +240,19 @@ async function discoverTokenEndpoint(
232
240
 
233
241
  if (!response.ok) {
234
242
  const fallback = `${normalizedIdcsUrl}/oauth2/v1/token`;
235
- DISCOVERY_CACHE.set(normalizedIdcsUrl, fallback);
243
+ discoveryEndpointCache.set(
244
+ normalizedIdcsUrl,
245
+ fallback,
246
+ Date.now(),
247
+ DISCOVERY_ERROR_FALLBACK_TTL_MS,
248
+ );
236
249
  return fallback;
237
250
  }
238
251
 
239
252
  const discovery = (await response.json()) as OcaDiscoveryDocument;
240
253
  const endpoint =
241
254
  discovery.token_endpoint || `${normalizedIdcsUrl}/oauth2/v1/token`;
242
- DISCOVERY_CACHE.set(normalizedIdcsUrl, endpoint);
255
+ discoveryEndpointCache.set(normalizedIdcsUrl, endpoint);
243
256
  return endpoint;
244
257
  }
245
258
 
@@ -1,7 +1,7 @@
1
1
  import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
2
2
  import { tmpdir } from "node:os";
3
3
  import { join } from "node:path";
4
- import type { Tool, ToolContext } from "@clinebot/agents";
4
+ import type { Tool, ToolContext } from "@clinebot/shared";
5
5
  import { afterEach, describe, expect, it } from "vitest";
6
6
  import {
7
7
  AGENT_CONFIG_DIRECTORY_NAME,
@@ -1,7 +1,7 @@
1
- import type { AgentConfig, Tool } from "@clinebot/agents";
1
+ import type { AgentConfig, Tool } from "@clinebot/shared";
2
2
  import YAML from "yaml";
3
3
  import { z } from "zod";
4
- import { ALL_DEFAULT_TOOL_NAMES, type DefaultToolName } from "../tools";
4
+ import { ALL_DEFAULT_TOOL_NAMES, type DefaultToolName } from "../../tools";
5
5
 
6
6
  const AgentConfigFrontmatterSchema = z.object({
7
7
  name: z.string().trim().min(1),
@@ -1,11 +1,11 @@
1
1
  import { existsSync, readdirSync } from "node:fs";
2
2
  import { basename, extname, join } from "node:path";
3
- import type { HookEventName } from "@clinebot/agents";
4
3
  import {
5
4
  HOOKS_CONFIG_DIRECTORY_NAME,
6
5
  resolveDocumentsHooksDirectoryPath,
7
6
  resolveHooksConfigSearchPaths as resolveHooksConfigSearchPathsFromShared,
8
7
  } from "@clinebot/shared/storage";
8
+ import type { HookEventName } from "../../hooks";
9
9
 
10
10
  export { HOOKS_CONFIG_DIRECTORY_NAME, resolveDocumentsHooksDirectoryPath };
11
11
 
@@ -30,18 +30,14 @@ export {
30
30
  resolveHooksConfigSearchPaths,
31
31
  toHookConfigFileName,
32
32
  } from "./hooks-config-loader";
33
- export type { ResolveAgentPluginPathsOptions } from "./plugin-config-loader";
34
- export {
35
- discoverPluginModulePaths,
36
- resolveAgentPluginPaths,
37
- resolveAndLoadAgentPlugins,
38
- resolvePluginConfigSearchPaths,
39
- } from "./plugin-config-loader";
40
- export type { LoadAgentPluginFromPathOptions } from "./plugin-loader";
33
+ export type {
34
+ AvailableRuntimeCommand,
35
+ RuntimeCommandKind,
36
+ } from "./runtime-commands";
41
37
  export {
42
- loadAgentPluginFromPath,
43
- loadAgentPluginsFromPaths,
44
- } from "./plugin-loader";
38
+ listAvailableRuntimeCommandsFromWatcher,
39
+ resolveRuntimeSlashCommandFromWatcher,
40
+ } from "./runtime-commands";
45
41
  export type {
46
42
  UnifiedConfigDefinition,
47
43
  UnifiedConfigFileCandidate,
@@ -2,11 +2,11 @@ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
2
2
  import { tmpdir } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import { afterEach, describe, expect, it } from "vitest";
5
- import { createUserInstructionConfigWatcher } from "../agents";
6
5
  import {
7
6
  listAvailableRuntimeCommandsFromWatcher,
8
7
  resolveRuntimeSlashCommandFromWatcher,
9
- } from "./commands";
8
+ } from "./runtime-commands";
9
+ import { createUserInstructionConfigWatcher } from "./user-instruction-config-loader";
10
10
 
11
11
  describe("runtime command registry", () => {
12
12
  const tempRoots: string[] = [];
@@ -61,7 +61,7 @@ Run the release workflow.`,
61
61
  }
62
62
  });
63
63
 
64
- it("expands skill and workflow slash commands with workflow precedence", async () => {
64
+ it("expands slash commands with workflow precedence and ignores disabled entries", async () => {
65
65
  const tempRoot = await mkdtemp(join(tmpdir(), "core-runtime-commands-"));
66
66
  tempRoots.push(tempRoot);
67
67
  const skillDir = join(tempRoot, "skills", "ship");
@@ -76,6 +76,14 @@ name: ship
76
76
  ---
77
77
  Run the ship workflow.`,
78
78
  );
79
+ await writeFile(
80
+ join(workflowsDir, "disabled.md"),
81
+ `---
82
+ name: disabled
83
+ disabled: true
84
+ ---
85
+ Do not run this workflow.`,
86
+ );
79
87
 
80
88
  const watcher = createUserInstructionConfigWatcher({
81
89
  skills: { directories: [join(tempRoot, "skills")] },
@@ -91,6 +99,15 @@ Run the ship workflow.`,
91
99
  expect(resolveRuntimeSlashCommandFromWatcher("/ship now", watcher)).toBe(
92
100
  "Run the ship workflow. now",
93
101
  );
102
+ expect(resolveRuntimeSlashCommandFromWatcher("/disabled", watcher)).toBe(
103
+ "/disabled",
104
+ );
105
+ expect(resolveRuntimeSlashCommandFromWatcher("/missing", watcher)).toBe(
106
+ "/missing",
107
+ );
108
+ expect(
109
+ resolveRuntimeSlashCommandFromWatcher("please run /ship", watcher),
110
+ ).toBe("please run /ship");
94
111
  } finally {
95
112
  watcher.stop();
96
113
  }
@@ -2,7 +2,7 @@ import type {
2
2
  SkillConfig,
3
3
  UserInstructionConfigWatcher,
4
4
  WorkflowConfig,
5
- } from "../agents";
5
+ } from "./user-instruction-config-loader";
6
6
 
7
7
  export type RuntimeCommandKind = "skill" | "workflow";
8
8
 
@@ -74,10 +74,3 @@ export function resolveRuntimeSlashCommandFromWatcher(
74
74
  );
75
75
  return matched ? `${matched.instructions}${remainder}` : input;
76
76
  }
77
-
78
- export function listAvailableRuntimeCommandsForKindFromWatcher(
79
- watcher: UserInstructionConfigWatcher,
80
- kind: RuntimeCommandKind,
81
- ): AvailableRuntimeCommand[] {
82
- return listCommandsForKind(watcher, kind);
83
- }
@@ -84,6 +84,13 @@ function isMissingDirectoryError(error: unknown): boolean {
84
84
  return isErrnoException(error) && error.code === "ENOENT";
85
85
  }
86
86
 
87
+ function isInaccessibleDirectoryError(error: unknown): boolean {
88
+ return (
89
+ isErrnoException(error) &&
90
+ (error.code === "EACCES" || error.code === "EPERM")
91
+ );
92
+ }
93
+
87
94
  export class UnifiedConfigFileWatcher<
88
95
  TType extends string = string,
89
96
  TItem = unknown,
@@ -289,7 +296,10 @@ export class UnifiedConfigFileWatcher<
289
296
  }
290
297
  });
291
298
  } catch (error) {
292
- if (!isMissingDirectoryError(error)) {
299
+ if (
300
+ !isMissingDirectoryError(error) &&
301
+ !isInaccessibleDirectoryError(error)
302
+ ) {
293
303
  const types = desiredTypesByDirectory.get(directoryPath);
294
304
  if (!types) {
295
305
  continue;
@@ -474,7 +484,10 @@ export class UnifiedConfigFileWatcher<
474
484
  }))
475
485
  .sort((a, b) => a.fileName.localeCompare(b.fileName));
476
486
  } catch (error) {
477
- if (isMissingDirectoryError(error)) {
487
+ if (
488
+ isMissingDirectoryError(error) ||
489
+ isInaccessibleDirectoryError(error)
490
+ ) {
478
491
  return [];
479
492
  }
480
493
  throw error;
@@ -3,7 +3,10 @@ import { tmpdir } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import { afterEach, describe, expect, it } from "vitest";
5
5
  import {
6
+ createRulesConfigDefinition,
7
+ createSkillsConfigDefinition,
6
8
  createUserInstructionConfigWatcher,
9
+ createWorkflowsConfigDefinition,
7
10
  parseRuleConfigFromMarkdown,
8
11
  parseSkillConfigFromMarkdown,
9
12
  parseWorkflowConfigFromMarkdown,
@@ -48,18 +51,34 @@ describe("user instruction config loader", () => {
48
51
  expect.arrayContaining([
49
52
  join(workspacePath, ".clinerules", "skills"),
50
53
  join(workspacePath, ".cline", "skills"),
51
- join(workspacePath, ".claude", "skills"),
52
54
  join(workspacePath, ".agents", "skills"),
53
55
  ]),
54
56
  );
55
57
  expect(resolveRulesConfigSearchPaths(workspacePath)).toEqual(
56
- expect.arrayContaining([join(workspacePath, ".clinerules")]),
58
+ expect.arrayContaining([
59
+ join(workspacePath, "AGENTS.md"),
60
+ join(workspacePath, ".clinerules"),
61
+ join(workspacePath, ".cline", "rules"),
62
+ ]),
57
63
  );
58
64
  expect(resolveWorkflowsConfigSearchPaths(workspacePath)).toEqual(
59
65
  expect.arrayContaining([join(workspacePath, ".clinerules", "workflows")]),
60
66
  );
61
67
  });
62
68
 
69
+ it("discovers managed plugin instruction roots from workspace .cline manifests", () => {
70
+ const workspacePath = "/repo/demo";
71
+ expect(
72
+ createSkillsConfigDefinition({ workspacePath }).directories,
73
+ ).toContain(join(workspacePath, ".cline"));
74
+ expect(
75
+ createRulesConfigDefinition({ workspacePath }).directories,
76
+ ).toContain(join(workspacePath, ".cline"));
77
+ expect(
78
+ createWorkflowsConfigDefinition({ workspacePath }).directories,
79
+ ).toContain(join(workspacePath, ".cline"));
80
+ });
81
+
63
82
  it("parses markdown frontmatter for skill, rule, and workflow configs", () => {
64
83
  const skill = parseSkillConfigFromMarkdown(
65
84
  `---
@@ -155,4 +174,73 @@ Escalation runbook`,
155
174
  watcher.stop();
156
175
  }
157
176
  });
177
+
178
+ it("loads enterprise-style managed rules, workflows, and skills through the default workspace watcher", async () => {
179
+ const tempRoot = await mkdtemp(
180
+ join(tmpdir(), "core-user-instructions-managed-"),
181
+ );
182
+ tempRoots.push(tempRoot);
183
+
184
+ const pluginRoot = join(tempRoot, ".cline", "enterprise");
185
+ await mkdir(join(pluginRoot, "workflows"), { recursive: true });
186
+ await mkdir(join(pluginRoot, "skills", "security-review"), {
187
+ recursive: true,
188
+ });
189
+ await writeFile(
190
+ join(pluginRoot, "managed.json"),
191
+ JSON.stringify({ source: "enterprise", version: "1", files: [] }),
192
+ );
193
+ await writeFile(
194
+ join(pluginRoot, "rules.md"),
195
+ `---
196
+ name: enterprise-policy
197
+ ---
198
+ Follow enterprise policy.`,
199
+ );
200
+ await writeFile(
201
+ join(pluginRoot, "workflows", "triage.md"),
202
+ `---
203
+ name: triage
204
+ ---
205
+ Follow the triage workflow.`,
206
+ );
207
+ await writeFile(
208
+ join(pluginRoot, "skills", "security-review", "SKILL.md"),
209
+ `---
210
+ name: security-review
211
+ ---
212
+ Use the security review checklist.`,
213
+ );
214
+
215
+ const watcher = createUserInstructionConfigWatcher({
216
+ skills: { workspacePath: tempRoot },
217
+ rules: { workspacePath: tempRoot },
218
+ workflows: { workspacePath: tempRoot },
219
+ });
220
+
221
+ try {
222
+ await watcher.start();
223
+ const rules = watcher.getSnapshot("rule");
224
+ const workflows = watcher.getSnapshot("workflow");
225
+ const skills = watcher.getSnapshot("skill");
226
+
227
+ expect(
228
+ [...rules.values()].some((rule) =>
229
+ rule.item.instructions.includes("enterprise policy"),
230
+ ),
231
+ ).toBe(true);
232
+ expect(
233
+ [...workflows.values()].some((workflow) =>
234
+ workflow.item.instructions.includes("triage workflow"),
235
+ ),
236
+ ).toBe(true);
237
+ expect(
238
+ [...skills.values()].some((skill) =>
239
+ skill.item.instructions.includes("security review checklist"),
240
+ ),
241
+ ).toBe(true);
242
+ } finally {
243
+ watcher.stop();
244
+ }
245
+ });
158
246
  });
@@ -1,4 +1,4 @@
1
- import { readdir, stat } from "node:fs/promises";
1
+ import { readdir, readFile, stat } from "node:fs/promises";
2
2
  import { basename, dirname, extname, join } from "node:path";
3
3
  import {
4
4
  RULES_CONFIG_DIRECTORY_NAME,
@@ -19,6 +19,7 @@ import {
19
19
  } from "./unified-config-file-watcher";
20
20
 
21
21
  const SKILL_FILE_NAME = "SKILL.md";
22
+ const MANAGED_PLUGIN_MANIFEST_FILE_NAME = "managed.json";
22
23
 
23
24
  const MARKDOWN_EXTENSIONS = new Set([".md", ".markdown", ".txt"]);
24
25
 
@@ -97,10 +98,57 @@ function normalizeName(name: string): string {
97
98
  return name.trim().toLowerCase();
98
99
  }
99
100
 
101
+ function isIgnorableDirectoryError(error: unknown): boolean {
102
+ const nodeError = error as NodeJS.ErrnoException;
103
+ return (
104
+ nodeError?.code === "ENOENT" ||
105
+ nodeError?.code === "EACCES" ||
106
+ nodeError?.code === "EPERM"
107
+ );
108
+ }
109
+
100
110
  function isMarkdownFile(fileName: string): boolean {
101
111
  return MARKDOWN_EXTENSIONS.has(extname(fileName).toLowerCase());
102
112
  }
103
113
 
114
+ async function discoverManagedPluginRoots(
115
+ clineDirectoryPath: string,
116
+ ): Promise<string[]> {
117
+ try {
118
+ const entries = await readdir(clineDirectoryPath, { withFileTypes: true });
119
+ const pluginRoots: string[] = [];
120
+ for (const entry of entries) {
121
+ if (!entry.isDirectory()) {
122
+ continue;
123
+ }
124
+ const pluginRoot = join(clineDirectoryPath, entry.name);
125
+ const manifestPath = join(pluginRoot, MANAGED_PLUGIN_MANIFEST_FILE_NAME);
126
+ try {
127
+ const content = await readFile(manifestPath, "utf8");
128
+ const parsed = JSON.parse(content) as unknown;
129
+ if (parsed && typeof parsed === "object") {
130
+ pluginRoots.push(pluginRoot);
131
+ }
132
+ } catch (error) {
133
+ if (isIgnorableDirectoryError(error)) {
134
+ continue;
135
+ }
136
+ const nodeError = error as NodeJS.ErrnoException;
137
+ if (nodeError?.name === "SyntaxError") {
138
+ continue;
139
+ }
140
+ throw error;
141
+ }
142
+ }
143
+ return pluginRoots.sort((a, b) => a.localeCompare(b));
144
+ } catch (error) {
145
+ if (isIgnorableDirectoryError(error)) {
146
+ return [];
147
+ }
148
+ throw error;
149
+ }
150
+ }
151
+
104
152
  function parseMarkdownFrontmatter(
105
153
  content: string,
106
154
  ): ParseMarkdownFrontmatterResult {
@@ -267,6 +315,16 @@ export function resolveWorkflowsConfigSearchPaths(
267
315
  async function discoverSkillFiles(
268
316
  directoryPath: string,
269
317
  ): Promise<ReadonlyArray<UnifiedConfigFileCandidate>> {
318
+ if (basename(directoryPath) === ".cline") {
319
+ const pluginRoots = await discoverManagedPluginRoots(directoryPath);
320
+ const nestedCandidates = await Promise.all(
321
+ pluginRoots.map((pluginRoot) =>
322
+ discoverSkillFiles(join(pluginRoot, SKILLS_CONFIG_DIRECTORY_NAME)),
323
+ ),
324
+ );
325
+ return nestedCandidates.flat();
326
+ }
327
+
270
328
  try {
271
329
  const entries = await readdir(directoryPath, { withFileTypes: true });
272
330
  const candidates: UnifiedConfigFileCandidate[] = [];
@@ -289,8 +347,7 @@ async function discoverSkillFiles(
289
347
  }
290
348
  return candidates;
291
349
  } catch (error) {
292
- const nodeError = error as NodeJS.ErrnoException;
293
- if (nodeError.code === "ENOENT") {
350
+ if (isIgnorableDirectoryError(error)) {
294
351
  return [];
295
352
  }
296
353
  throw error;
@@ -300,6 +357,16 @@ async function discoverSkillFiles(
300
357
  async function discoverRulesLikeFiles(
301
358
  directoryPath: string,
302
359
  ): Promise<ReadonlyArray<UnifiedConfigFileCandidate>> {
360
+ if (basename(directoryPath) === ".cline") {
361
+ const pluginRoots = await discoverManagedPluginRoots(directoryPath);
362
+ const nestedCandidates = await Promise.all(
363
+ pluginRoots.map((pluginRoot) =>
364
+ discoverRulesLikeFiles(join(pluginRoot, "rules.md")),
365
+ ),
366
+ );
367
+ return nestedCandidates.flat();
368
+ }
369
+
303
370
  try {
304
371
  const entryStat = await stat(directoryPath);
305
372
  if (entryStat.isFile()) {
@@ -312,40 +379,81 @@ async function discoverRulesLikeFiles(
312
379
  ];
313
380
  }
314
381
  } catch (error) {
315
- const nodeError = error as NodeJS.ErrnoException;
316
- if (nodeError.code !== "ENOENT") {
382
+ if (!isIgnorableDirectoryError(error)) {
317
383
  throw error;
318
384
  }
319
385
  }
320
386
 
321
387
  try {
322
388
  const entries = await readdir(directoryPath, { withFileTypes: true });
323
- return entries
389
+ const candidates = entries
324
390
  .filter((entry) => entry.isFile() && isMarkdownFile(entry.name))
325
391
  .map((entry) => ({
326
392
  directoryPath,
327
393
  fileName: entry.name,
328
394
  filePath: join(directoryPath, entry.name),
329
395
  }));
396
+
397
+ // Special case: if this is a workspace root directory, also check for AGENTS.md
398
+ const agentsPath = join(directoryPath, "AGENTS.md");
399
+ try {
400
+ const agentsStat = await stat(agentsPath);
401
+ if (agentsStat.isFile()) {
402
+ // Check if AGENTS.md is not already in the candidates
403
+ const alreadyIncluded = candidates.some(
404
+ (c) => c.fileName === "AGENTS.md",
405
+ );
406
+ if (!alreadyIncluded) {
407
+ candidates.push({
408
+ directoryPath,
409
+ fileName: "AGENTS.md",
410
+ filePath: agentsPath,
411
+ });
412
+ }
413
+ }
414
+ } catch {
415
+ // AGENTS.md doesn't exist or is not accessible, which is fine
416
+ }
417
+
418
+ return candidates;
330
419
  } catch (error) {
331
- const nodeError = error as NodeJS.ErrnoException;
332
- if (nodeError.code === "ENOENT") {
420
+ if (isIgnorableDirectoryError(error)) {
333
421
  return [];
334
422
  }
335
423
  throw error;
336
424
  }
337
425
  }
338
426
 
427
+ async function discoverManagedWorkflowFiles(
428
+ directoryPath: string,
429
+ ): Promise<ReadonlyArray<UnifiedConfigFileCandidate>> {
430
+ if (basename(directoryPath) === ".cline") {
431
+ const pluginRoots = await discoverManagedPluginRoots(directoryPath);
432
+ const nestedCandidates = await Promise.all(
433
+ pluginRoots.map((pluginRoot) =>
434
+ discoverRulesLikeFiles(
435
+ join(pluginRoot, WORKFLOWS_CONFIG_DIRECTORY_NAME),
436
+ ),
437
+ ),
438
+ );
439
+ return nestedCandidates.flat();
440
+ }
441
+ return discoverRulesLikeFiles(directoryPath);
442
+ }
443
+
339
444
  export function createSkillsConfigDefinition(
340
445
  options?: CreateSkillsConfigDefinitionOptions,
341
446
  ): UnifiedConfigDefinition<"skill", SkillConfig> {
342
447
  const directories =
343
448
  options?.directories ??
344
449
  resolveSkillsConfigSearchPaths(options?.workspacePath);
450
+ const managedRoot = options?.workspacePath
451
+ ? join(options.workspacePath, ".cline")
452
+ : undefined;
345
453
 
346
454
  return {
347
455
  type: "skill",
348
- directories,
456
+ directories: managedRoot ? [...directories, managedRoot] : directories,
349
457
  discoverFiles: discoverSkillFiles,
350
458
  includeFile: (fileName) => fileName === SKILL_FILE_NAME,
351
459
  parseFile: (context) =>
@@ -363,10 +471,13 @@ export function createRulesConfigDefinition(
363
471
  const directories =
364
472
  options?.directories ??
365
473
  resolveRulesConfigSearchPaths(options?.workspacePath);
474
+ const managedRoot = options?.workspacePath
475
+ ? join(options.workspacePath, ".cline")
476
+ : undefined;
366
477
 
367
478
  return {
368
479
  type: "rule",
369
- directories,
480
+ directories: managedRoot ? [...directories, managedRoot] : directories,
370
481
  discoverFiles: discoverRulesLikeFiles,
371
482
  includeFile: (fileName, filePath) =>
372
483
  fileName === ".clinerules" ||
@@ -387,11 +498,14 @@ export function createWorkflowsConfigDefinition(
387
498
  const directories =
388
499
  options?.directories ??
389
500
  resolveWorkflowsConfigSearchPaths(options?.workspacePath);
501
+ const managedRoot = options?.workspacePath
502
+ ? join(options.workspacePath, ".cline")
503
+ : undefined;
390
504
 
391
505
  return {
392
506
  type: "workflow",
393
- directories,
394
- discoverFiles: discoverRulesLikeFiles,
507
+ directories: managedRoot ? [...directories, managedRoot] : directories,
508
+ discoverFiles: discoverManagedWorkflowFiles,
395
509
  includeFile: (fileName) => isMarkdownFile(fileName),
396
510
  parseFile: (context) =>
397
511
  parseWorkflowConfigFromMarkdown(