@clinebot/core 0.0.36 → 0.0.37

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 (228) hide show
  1. package/dist/ClineCore.d.ts +312 -3
  2. package/dist/ClineCore.d.ts.map +1 -1
  3. package/dist/account/cline-account-service.d.ts.map +1 -1
  4. package/dist/cron/cron-event-ingress.d.ts +38 -0
  5. package/dist/cron/cron-event-ingress.d.ts.map +1 -0
  6. package/dist/cron/cron-materializer.d.ts +36 -0
  7. package/dist/cron/cron-materializer.d.ts.map +1 -0
  8. package/dist/cron/cron-reconciler.d.ts +62 -0
  9. package/dist/cron/cron-reconciler.d.ts.map +1 -0
  10. package/dist/cron/cron-report-writer.d.ts +41 -0
  11. package/dist/cron/cron-report-writer.d.ts.map +1 -0
  12. package/dist/cron/cron-runner.d.ts +43 -0
  13. package/dist/cron/cron-runner.d.ts.map +1 -0
  14. package/dist/cron/cron-schema.d.ts +3 -0
  15. package/dist/cron/cron-schema.d.ts.map +1 -0
  16. package/dist/cron/cron-service.d.ts +57 -0
  17. package/dist/cron/cron-service.d.ts.map +1 -0
  18. package/dist/cron/cron-spec-parser.d.ts +27 -0
  19. package/dist/cron/cron-spec-parser.d.ts.map +1 -0
  20. package/dist/cron/cron-watcher.d.ts +23 -0
  21. package/dist/cron/cron-watcher.d.ts.map +1 -0
  22. package/dist/cron/scheduler.d.ts +3 -1
  23. package/dist/cron/scheduler.d.ts.map +1 -1
  24. package/dist/cron/sqlite-cron-store.d.ts +230 -0
  25. package/dist/cron/sqlite-cron-store.d.ts.map +1 -0
  26. package/dist/extensions/plugin/plugin-config-loader.d.ts +7 -1
  27. package/dist/extensions/plugin/plugin-config-loader.d.ts.map +1 -1
  28. package/dist/extensions/plugin/plugin-loader.d.ts +10 -6
  29. package/dist/extensions/plugin/plugin-loader.d.ts.map +1 -1
  30. package/dist/extensions/plugin/plugin-sandbox.d.ts +7 -1
  31. package/dist/extensions/plugin/plugin-sandbox.d.ts.map +1 -1
  32. package/dist/extensions/plugin-sandbox-bootstrap.js +236 -275
  33. package/dist/extensions/tools/constants.d.ts +1 -0
  34. package/dist/extensions/tools/constants.d.ts.map +1 -1
  35. package/dist/extensions/tools/definitions.d.ts +2 -3
  36. package/dist/extensions/tools/definitions.d.ts.map +1 -1
  37. package/dist/extensions/tools/executors/editor.d.ts.map +1 -1
  38. package/dist/extensions/tools/helpers.d.ts +1 -0
  39. package/dist/extensions/tools/helpers.d.ts.map +1 -1
  40. package/dist/extensions/tools/index.d.ts +1 -2
  41. package/dist/extensions/tools/index.d.ts.map +1 -1
  42. package/dist/extensions/tools/presets.d.ts +1 -1
  43. package/dist/extensions/tools/schemas.d.ts +25 -3
  44. package/dist/extensions/tools/schemas.d.ts.map +1 -1
  45. package/dist/extensions/tools/team/delegated-agent.d.ts +2 -2
  46. package/dist/extensions/tools/team/delegated-agent.d.ts.map +1 -1
  47. package/dist/extensions/tools/team/multi-agent.d.ts +7 -3
  48. package/dist/extensions/tools/team/multi-agent.d.ts.map +1 -1
  49. package/dist/extensions/tools/team/team-tools.d.ts.map +1 -1
  50. package/dist/extensions/tools/types.d.ts +0 -5
  51. package/dist/extensions/tools/types.d.ts.map +1 -1
  52. package/dist/hooks/hook-bridge.d.ts +118 -0
  53. package/dist/hooks/hook-bridge.d.ts.map +1 -0
  54. package/dist/hooks/hook-file-hooks.d.ts +2 -1
  55. package/dist/hooks/hook-file-hooks.d.ts.map +1 -1
  56. package/dist/hooks/hook-registry.d.ts +16 -0
  57. package/dist/hooks/hook-registry.d.ts.map +1 -0
  58. package/dist/hub/browser-websocket.d.ts.map +1 -1
  59. package/dist/hub/client.d.ts +7 -1
  60. package/dist/hub/client.d.ts.map +1 -1
  61. package/dist/hub/daemon-entry.js +721 -461
  62. package/dist/hub/daemon.d.ts.map +1 -1
  63. package/dist/hub/defaults.d.ts +8 -4
  64. package/dist/hub/defaults.d.ts.map +1 -1
  65. package/dist/hub/index.js +665 -415
  66. package/dist/hub/runtime-handlers.d.ts.map +1 -1
  67. package/dist/hub/server.d.ts +18 -0
  68. package/dist/hub/server.d.ts.map +1 -1
  69. package/dist/hub/session-client.d.ts +3 -0
  70. package/dist/hub/session-client.d.ts.map +1 -1
  71. package/dist/hub/start-shared-server.d.ts.map +1 -1
  72. package/dist/hub/ui-client.d.ts +1 -0
  73. package/dist/hub/ui-client.d.ts.map +1 -1
  74. package/dist/index.d.ts +9 -7
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +756 -467
  77. package/dist/llms/cline-recommended-models.d.ts +20 -0
  78. package/dist/llms/cline-recommended-models.d.ts.map +1 -0
  79. package/dist/llms/handler-factory.d.ts +16 -0
  80. package/dist/llms/handler-factory.d.ts.map +1 -0
  81. package/dist/llms/provider-defaults.d.ts.map +1 -1
  82. package/dist/llms/provider-settings.d.ts +45 -2
  83. package/dist/llms/provider-settings.d.ts.map +1 -1
  84. package/dist/llms/runtime-registry.d.ts.map +1 -1
  85. package/dist/runtime/agent-config-adapter.d.ts +148 -0
  86. package/dist/runtime/agent-config-adapter.d.ts.map +1 -0
  87. package/dist/runtime/agent-runtime-config-builder.d.ts +96 -0
  88. package/dist/runtime/agent-runtime-config-builder.d.ts.map +1 -0
  89. package/dist/runtime/history.d.ts +6 -0
  90. package/dist/runtime/history.d.ts.map +1 -1
  91. package/dist/runtime/host.d.ts.map +1 -1
  92. package/dist/runtime/loop-detection.d.ts +59 -0
  93. package/dist/runtime/loop-detection.d.ts.map +1 -0
  94. package/dist/runtime/mistake-tracker.d.ts +69 -0
  95. package/dist/runtime/mistake-tracker.d.ts.map +1 -0
  96. package/dist/runtime/runtime-builder.d.ts.map +1 -1
  97. package/dist/runtime/runtime-event-adapter.d.ts +102 -0
  98. package/dist/runtime/runtime-event-adapter.d.ts.map +1 -0
  99. package/dist/runtime/runtime-host.d.ts +28 -3
  100. package/dist/runtime/runtime-host.d.ts.map +1 -1
  101. package/dist/runtime/session-runtime-orchestrator.d.ts +261 -0
  102. package/dist/runtime/session-runtime-orchestrator.d.ts.map +1 -0
  103. package/dist/runtime/session-runtime.d.ts +16 -3
  104. package/dist/runtime/session-runtime.d.ts.map +1 -1
  105. package/dist/runtime/user-input-builder.d.ts +24 -0
  106. package/dist/runtime/user-input-builder.d.ts.map +1 -0
  107. package/dist/services/index.js +28 -0
  108. package/dist/services/local-runtime-bootstrap.d.ts.map +1 -1
  109. package/dist/services/plugin-tools.d.ts.map +1 -1
  110. package/dist/services/providers/local-provider-registry.d.ts +197 -21
  111. package/dist/services/providers/local-provider-registry.d.ts.map +1 -1
  112. package/dist/services/providers/local-provider-service.d.ts +3 -1
  113. package/dist/services/providers/local-provider-service.d.ts.map +1 -1
  114. package/dist/services/session-data.d.ts.map +1 -1
  115. package/dist/services/session-telemetry.d.ts +7 -2
  116. package/dist/services/session-telemetry.d.ts.map +1 -1
  117. package/dist/services/storage/file-team-store.d.ts.map +1 -1
  118. package/dist/services/storage/provider-settings-legacy-migration.d.ts.map +1 -1
  119. package/dist/services/storage/provider-settings-manager.d.ts +1 -0
  120. package/dist/services/storage/provider-settings-manager.d.ts.map +1 -1
  121. package/dist/services/storage/sqlite-team-store.d.ts.map +1 -1
  122. package/dist/session/conversation-store.d.ts +30 -0
  123. package/dist/session/conversation-store.d.ts.map +1 -0
  124. package/dist/session/message-builder.d.ts +65 -0
  125. package/dist/session/message-builder.d.ts.map +1 -0
  126. package/dist/session/session-manifest.d.ts +1 -1
  127. package/dist/transports/hub.d.ts +14 -3
  128. package/dist/transports/hub.d.ts.map +1 -1
  129. package/dist/transports/local.d.ts +14 -4
  130. package/dist/transports/local.d.ts.map +1 -1
  131. package/dist/transports/remote.d.ts.map +1 -1
  132. package/dist/types/chat-schema.d.ts +5 -5
  133. package/dist/types/config.d.ts +9 -0
  134. package/dist/types/config.d.ts.map +1 -1
  135. package/dist/types/events.d.ts +7 -6
  136. package/dist/types/events.d.ts.map +1 -1
  137. package/dist/types/provider-settings.d.ts +2 -2
  138. package/dist/types/provider-settings.d.ts.map +1 -1
  139. package/dist/types/session.d.ts +5 -2
  140. package/dist/types/session.d.ts.map +1 -1
  141. package/dist/types.d.ts +4 -4
  142. package/dist/types.d.ts.map +1 -1
  143. package/package.json +4 -4
  144. package/src/ClineCore.ts +691 -6
  145. package/src/account/cline-account-service.ts +44 -6
  146. package/src/cron/cron-event-ingress.ts +357 -0
  147. package/src/cron/cron-materializer.ts +97 -0
  148. package/src/cron/cron-reconciler.ts +241 -0
  149. package/src/cron/cron-report-writer.ts +153 -0
  150. package/src/cron/cron-runner.ts +495 -0
  151. package/src/cron/cron-schema.ts +127 -0
  152. package/src/cron/cron-service.ts +163 -0
  153. package/src/cron/cron-spec-parser.ts +489 -0
  154. package/src/cron/cron-watcher.ts +102 -0
  155. package/src/cron/index.ts +10 -0
  156. package/src/cron/scheduler.ts +141 -6
  157. package/src/cron/sqlite-cron-store.ts +1286 -0
  158. package/src/extensions/plugin/plugin-config-loader.ts +21 -1
  159. package/src/extensions/plugin/plugin-loader.ts +25 -9
  160. package/src/extensions/plugin/plugin-sandbox-bootstrap.ts +151 -1
  161. package/src/extensions/plugin/plugin-sandbox.ts +131 -7
  162. package/src/extensions/tools/constants.ts +2 -0
  163. package/src/extensions/tools/definitions.ts +31 -22
  164. package/src/extensions/tools/executors/editor.ts +4 -3
  165. package/src/extensions/tools/helpers.ts +24 -0
  166. package/src/extensions/tools/index.ts +1 -2
  167. package/src/extensions/tools/presets.ts +1 -1
  168. package/src/extensions/tools/schemas.ts +13 -18
  169. package/src/extensions/tools/team/delegated-agent.ts +8 -3
  170. package/src/extensions/tools/team/multi-agent.ts +135 -19
  171. package/src/extensions/tools/team/team-tools.ts +151 -91
  172. package/src/extensions/tools/types.ts +0 -6
  173. package/src/hooks/hook-bridge.ts +489 -0
  174. package/src/hooks/hook-file-hooks.ts +58 -3
  175. package/src/hooks/hook-registry.ts +257 -0
  176. package/src/hub/browser-websocket.ts +26 -4
  177. package/src/hub/client.ts +72 -13
  178. package/src/hub/daemon-entry.ts +35 -0
  179. package/src/hub/daemon.ts +117 -14
  180. package/src/hub/defaults.ts +39 -12
  181. package/src/hub/runtime-handlers.ts +4 -3
  182. package/src/hub/server.ts +506 -77
  183. package/src/hub/session-client.ts +43 -1
  184. package/src/hub/start-shared-server.ts +3 -0
  185. package/src/hub/ui-client.ts +4 -0
  186. package/src/index.ts +46 -1
  187. package/src/llms/cline-recommended-models.ts +167 -0
  188. package/src/llms/handler-factory.ts +56 -0
  189. package/src/llms/provider-defaults.ts +17 -1
  190. package/src/llms/provider-settings.ts +48 -1
  191. package/src/llms/runtime-registry.ts +1 -0
  192. package/src/runtime/agent-config-adapter.ts +636 -0
  193. package/src/runtime/agent-runtime-config-builder.ts +205 -0
  194. package/src/runtime/error-feedback.ts +142 -0
  195. package/src/runtime/history.ts +137 -0
  196. package/src/runtime/host.ts +22 -0
  197. package/src/runtime/loop-detection.ts +162 -0
  198. package/src/runtime/mistake-tracker.ts +221 -0
  199. package/src/runtime/runtime-builder.ts +61 -5
  200. package/src/runtime/runtime-event-adapter.ts +412 -0
  201. package/src/runtime/runtime-host.ts +45 -1
  202. package/src/runtime/session-runtime-orchestrator.ts +1253 -0
  203. package/src/runtime/session-runtime.ts +16 -2
  204. package/src/runtime/user-input-builder.ts +167 -0
  205. package/src/services/local-runtime-bootstrap.ts +128 -22
  206. package/src/services/plugin-tools.ts +1 -0
  207. package/src/services/providers/local-provider-registry.ts +273 -57
  208. package/src/services/providers/local-provider-service.ts +67 -7
  209. package/src/services/session-data.ts +16 -14
  210. package/src/services/session-telemetry.ts +6 -15
  211. package/src/services/storage/file-team-store.ts +1 -5
  212. package/src/services/storage/provider-settings-legacy-migration.ts +8 -47
  213. package/src/services/storage/provider-settings-manager.ts +16 -1
  214. package/src/services/storage/sqlite-team-store.ts +1 -5
  215. package/src/session/conversation-store.ts +77 -0
  216. package/src/session/message-builder.ts +941 -0
  217. package/src/transports/hub.ts +458 -33
  218. package/src/transports/local.ts +296 -65
  219. package/src/transports/remote.ts +1 -0
  220. package/src/types/config.ts +9 -0
  221. package/src/types/events.ts +8 -6
  222. package/src/types/index.ts +3 -0
  223. package/src/types/provider-settings.ts +8 -1
  224. package/src/types/session.ts +5 -2
  225. package/src/types.ts +15 -1
  226. package/dist/cron/index.d.ts +0 -6
  227. package/dist/cron/index.d.ts.map +0 -1
  228. package/dist/services/telemetry/index.js +0 -28
@@ -1,5 +1,9 @@
1
1
  import { existsSync } from "node:fs";
2
- import type { AgentConfig, WorkspaceInfo } from "@clinebot/shared";
2
+ import type {
3
+ AgentConfig,
4
+ PluginSetupContext,
5
+ WorkspaceInfo,
6
+ } from "@clinebot/shared";
3
7
  import {
4
8
  discoverPluginModulePaths as discoverPluginModulePathsFromShared,
5
9
  resolveConfiguredPluginModulePaths,
@@ -69,6 +73,12 @@ export interface ResolveAndLoadAgentPluginsOptions
69
73
  * in the extension context.
70
74
  */
71
75
  workspaceInfo?: WorkspaceInfo;
76
+ session?: PluginSetupContext["session"];
77
+ client?: PluginSetupContext["client"];
78
+ user?: PluginSetupContext["user"];
79
+ automation?: PluginSetupContext["automation"];
80
+ logger?: PluginSetupContext["logger"];
81
+ telemetry?: PluginSetupContext["telemetry"];
72
82
  }
73
83
 
74
84
  export async function resolveAndLoadAgentPlugins(
@@ -90,7 +100,13 @@ export async function resolveAndLoadAgentPlugins(
90
100
  exportName: options.exportName,
91
101
  providerId: options.providerId,
92
102
  modelId: options.modelId,
103
+ session: options.session,
104
+ client: options.client,
105
+ user: options.user,
93
106
  workspaceInfo: options.workspaceInfo,
107
+ automation: options.automation,
108
+ logger: options.logger,
109
+ telemetry: options.telemetry,
94
110
  });
95
111
  return {
96
112
  extensions: report.plugins,
@@ -109,7 +125,11 @@ export async function resolveAndLoadAgentPlugins(
109
125
  providerId: options.providerId,
110
126
  modelId: options.modelId,
111
127
  cwd: options.cwd,
128
+ session: options.session,
129
+ client: options.client,
130
+ user: options.user,
112
131
  workspaceInfo: options.workspaceInfo,
132
+ logger: options.logger,
113
133
  });
114
134
  return {
115
135
  extensions: sandboxed.extensions ?? [],
@@ -1,5 +1,5 @@
1
1
  import { resolve } from "node:path";
2
- import type { AgentConfig, PluginSetupContext } from "@clinebot/shared";
2
+ import type { AgentExtension, PluginSetupContext } from "@clinebot/shared";
3
3
  import { normalizePluginManifest } from "@clinebot/shared";
4
4
  import type {
5
5
  PluginInitializationFailure,
@@ -11,7 +11,6 @@ import {
11
11
  type PluginTargeting,
12
12
  } from "./plugin-targeting";
13
13
 
14
- type AgentPlugin = NonNullable<AgentConfig["extensions"]>[number];
15
14
  type PluginLike = {
16
15
  name: string;
17
16
  manifest: {
@@ -26,7 +25,13 @@ export interface LoadAgentPluginFromPathOptions {
26
25
  exportName?: string;
27
26
  cwd?: string;
28
27
  useCache?: boolean;
28
+ session?: PluginSetupContext["session"];
29
+ client?: PluginSetupContext["client"];
30
+ user?: PluginSetupContext["user"];
29
31
  workspaceInfo?: PluginSetupContext["workspaceInfo"];
32
+ automation?: PluginSetupContext["automation"];
33
+ logger?: PluginSetupContext["logger"];
34
+ telemetry?: PluginSetupContext["telemetry"];
30
35
  }
31
36
 
32
37
  function isObject(value: unknown): value is Record<string, unknown> {
@@ -109,7 +114,7 @@ function validatePluginExport(
109
114
  export async function loadAgentPluginFromPath(
110
115
  pluginPath: string,
111
116
  options: LoadAgentPluginFromPathOptions = {},
112
- ): Promise<AgentPlugin> {
117
+ ): Promise<AgentExtension> {
113
118
  const absolutePath = resolve(options.cwd ?? process.cwd(), pluginPath);
114
119
  const moduleExports = await importPluginModule(absolutePath, {
115
120
  useCache: options.useCache,
@@ -119,14 +124,25 @@ export async function loadAgentPluginFromPath(
119
124
  moduleExports[exportName]) as unknown;
120
125
 
121
126
  validatePluginExport(plugin, absolutePath);
122
- const pluginTyped = plugin as AgentPlugin;
127
+ const pluginTyped = plugin as AgentExtension;
123
128
  const originalSetup = pluginTyped.setup;
124
129
 
125
130
  // Wrap setup to inject workspace context
126
- const setupWithContext: AgentPlugin["setup"] = originalSetup
131
+ const setupWithContext: AgentExtension["setup"] = originalSetup
127
132
  ? (api, _ctx) => {
133
+ const session = {
134
+ ...options.session,
135
+ ..._ctx.session,
136
+ };
128
137
  const ctx = {
129
- workspaceInfo: options.workspaceInfo,
138
+ ..._ctx,
139
+ session: Object.keys(session).length > 0 ? session : undefined,
140
+ client: options.client ?? _ctx.client,
141
+ user: options.user ?? _ctx.user,
142
+ workspaceInfo: options.workspaceInfo ?? _ctx.workspaceInfo,
143
+ automation: options.automation ?? _ctx.automation,
144
+ logger: options.logger ?? _ctx.logger,
145
+ telemetry: options.telemetry ?? _ctx.telemetry,
130
146
  };
131
147
  return originalSetup(api, ctx);
132
148
  }
@@ -142,7 +158,7 @@ export async function loadAgentPluginFromPath(
142
158
  export async function loadAgentPluginsFromPaths(
143
159
  pluginPaths: string[],
144
160
  options: LoadAgentPluginFromPathOptions & PluginTargeting = {},
145
- ): Promise<AgentPlugin[]> {
161
+ ): Promise<AgentExtension[]> {
146
162
  const report = await loadAgentPluginsFromPathsWithDiagnostics(
147
163
  pluginPaths,
148
164
  options,
@@ -154,7 +170,7 @@ export async function loadAgentPluginsFromPathsWithDiagnostics(
154
170
  pluginPaths: string[],
155
171
  options: LoadAgentPluginFromPathOptions & PluginTargeting = {},
156
172
  ): Promise<{
157
- plugins: AgentPlugin[];
173
+ plugins: AgentExtension[];
158
174
  failures: PluginInitializationFailure[];
159
175
  warnings: PluginInitializationWarning[];
160
176
  }> {
@@ -162,7 +178,7 @@ export async function loadAgentPluginsFromPathsWithDiagnostics(
162
178
  const warnings: PluginInitializationWarning[] = [];
163
179
  const loadedByName = new Map<
164
180
  string,
165
- { plugin: AgentPlugin; pluginPath: string; order: number }
181
+ { plugin: AgentExtension; pluginPath: string; order: number }
166
182
  >();
167
183
  let order = 0;
168
184
 
@@ -10,7 +10,11 @@
10
10
  * depend on local helpers that can be inlined into the sandbox build.
11
11
  */
12
12
 
13
- import { normalizePluginManifest, type PluginManifest } from "@clinebot/shared";
13
+ import {
14
+ type AutomationEventEnvelope,
15
+ normalizePluginManifest,
16
+ type PluginManifest,
17
+ } from "@clinebot/shared";
14
18
  import { importPluginModule } from "./plugin-module-import";
15
19
  import {
16
20
  matchesPluginManifestTargeting,
@@ -47,15 +51,37 @@ interface PluginProvider {
47
51
  metadata?: Record<string, unknown>;
48
52
  }
49
53
 
54
+ interface PluginAutomationEventType {
55
+ eventType: string;
56
+ source: string;
57
+ description?: string;
58
+ attributesSchema?: Record<string, unknown>;
59
+ payloadSchema?: Record<string, unknown>;
60
+ examples?: AutomationEventEnvelope[];
61
+ metadata?: Record<string, unknown>;
62
+ }
63
+
50
64
  interface PluginApi {
51
65
  registerTool(tool: PluginTool): void;
52
66
  registerCommand(command: PluginCommand): void;
53
67
  registerMessageBuilder(builder: PluginMessageBuilder): void;
54
68
  registerProvider(provider: PluginProvider): void;
69
+ registerAutomationEventType(eventType: PluginAutomationEventType): void;
55
70
  }
56
71
 
57
72
  interface PluginSetupCtx {
73
+ session?: unknown;
74
+ client?: unknown;
75
+ user?: unknown;
58
76
  workspaceInfo?: unknown;
77
+ automation?: {
78
+ ingestEvent(event: AutomationEventEnvelope): void | Promise<void>;
79
+ };
80
+ logger?: {
81
+ debug(message: string, metadata?: Record<string, unknown>): void;
82
+ log(message: string, metadata?: Record<string, unknown>): void;
83
+ error(message: string, metadata?: Record<string, unknown>): void;
84
+ };
59
85
  }
60
86
 
61
87
  interface PluginModule {
@@ -77,6 +103,17 @@ interface ContributionDescriptor {
77
103
  metadata?: Record<string, unknown>;
78
104
  }
79
105
 
106
+ interface AutomationEventTypeDescriptor {
107
+ id: string;
108
+ eventType: string;
109
+ source: string;
110
+ description?: string;
111
+ attributesSchema?: Record<string, unknown>;
112
+ payloadSchema?: Record<string, unknown>;
113
+ examples?: AutomationEventEnvelope[];
114
+ metadata?: Record<string, unknown>;
115
+ }
116
+
80
117
  interface PluginDescriptor {
81
118
  pluginId: string;
82
119
  pluginPath: string;
@@ -87,6 +124,7 @@ interface PluginDescriptor {
87
124
  commands: ContributionDescriptor[];
88
125
  messageBuilders: ContributionDescriptor[];
89
126
  providers: ContributionDescriptor[];
127
+ automationEventTypes: AutomationEventTypeDescriptor[];
90
128
  shortcuts?: ContributionDescriptor[];
91
129
  flags?: ContributionDescriptor[];
92
130
  };
@@ -166,9 +204,32 @@ function assertValidPluginSetupCtx(
166
204
  if (!isObject(ctx)) {
167
205
  throw new Error("Plugin setup context must be an object");
168
206
  }
207
+ if (ctx.session !== undefined && !isObject(ctx.session)) {
208
+ throw new Error("Plugin setup context session must be an object");
209
+ }
210
+ if (ctx.client !== undefined && !isObject(ctx.client)) {
211
+ throw new Error("Plugin setup context client must be an object");
212
+ }
213
+ if (ctx.user !== undefined && !isObject(ctx.user)) {
214
+ throw new Error("Plugin setup context user must be an object");
215
+ }
169
216
  if (ctx.workspaceInfo !== undefined && !isObject(ctx.workspaceInfo)) {
170
217
  throw new Error("Plugin setup context workspaceInfo must be an object");
171
218
  }
219
+ if (ctx.automation !== undefined && !isObject(ctx.automation)) {
220
+ throw new Error("Plugin setup context automation must be an object");
221
+ }
222
+ if (
223
+ ctx.automation !== undefined &&
224
+ typeof ctx.automation.ingestEvent !== "function"
225
+ ) {
226
+ throw new Error(
227
+ "Plugin setup context automation.ingestEvent must be a function",
228
+ );
229
+ }
230
+ if (ctx.logger !== undefined && !isObject(ctx.logger)) {
231
+ throw new Error("Plugin setup context logger must be an object");
232
+ }
172
233
  }
173
234
 
174
235
  // ---------------------------------------------------------------------------
@@ -226,6 +287,45 @@ function sanitizeObject(value: unknown): Record<string, unknown> {
226
287
  return value as Record<string, unknown>;
227
288
  }
228
289
 
290
+ function sanitizeLogMetadata(
291
+ value: unknown,
292
+ ): Record<string, unknown> | undefined {
293
+ if (!value || typeof value !== "object") {
294
+ return undefined;
295
+ }
296
+ const metadata = { ...(value as Record<string, unknown>) };
297
+ if (metadata.error instanceof Error) {
298
+ metadata.error = {
299
+ name: metadata.error.name,
300
+ message: metadata.error.message,
301
+ stack: metadata.error.stack,
302
+ };
303
+ }
304
+ return metadata;
305
+ }
306
+
307
+ function createPluginLogger(
308
+ pluginName: string,
309
+ ): NonNullable<PluginSetupCtx["logger"]> {
310
+ const emitLog = (
311
+ level: "debug" | "log" | "error",
312
+ message: string,
313
+ metadata?: Record<string, unknown>,
314
+ ) => {
315
+ emitEvent("plugin_log", {
316
+ level,
317
+ pluginName,
318
+ message,
319
+ metadata: sanitizeLogMetadata(metadata),
320
+ });
321
+ };
322
+ return {
323
+ debug: (message, metadata) => emitLog("debug", message, metadata),
324
+ log: (message, metadata) => emitLog("log", message, metadata),
325
+ error: (message, metadata) => emitLog("error", message, metadata),
326
+ };
327
+ }
328
+
229
329
  function makeId(pluginId: string, prefix: string): string {
230
330
  const key = `${pluginId}:${prefix}`;
231
331
  const next = (contributionCounters.get(key) ?? 0) + 1;
@@ -233,6 +333,30 @@ function makeId(pluginId: string, prefix: string): string {
233
333
  return `${pluginId}_${prefix}_${next}`;
234
334
  }
235
335
 
336
+ function normalizeAutomationEventType(
337
+ eventType: PluginAutomationEventType,
338
+ ): PluginAutomationEventType {
339
+ const normalizedEventType =
340
+ typeof eventType.eventType === "string" ? eventType.eventType.trim() : "";
341
+ const source =
342
+ typeof eventType.source === "string" ? eventType.source.trim() : "";
343
+ if (!normalizedEventType) {
344
+ throw new Error("Automation event type contribution requires eventType");
345
+ }
346
+ if (!source) {
347
+ throw new Error("Automation event type contribution requires source");
348
+ }
349
+ return {
350
+ ...eventType,
351
+ eventType: normalizedEventType,
352
+ source,
353
+ examples: eventType.examples ? [...eventType.examples] : undefined,
354
+ metadata: eventType.metadata
355
+ ? sanitizeObject(eventType.metadata)
356
+ : undefined,
357
+ };
358
+ }
359
+
236
360
  function getPlugin(pluginId: string): PluginState {
237
361
  const state = pluginState.get(pluginId);
238
362
  if (!state) {
@@ -251,7 +375,11 @@ async function initialize(args: {
251
375
  providerId?: string;
252
376
  modelId?: string;
253
377
  cwd?: string;
378
+ session?: unknown;
379
+ client?: unknown;
380
+ user?: unknown;
254
381
  workspaceInfo?: unknown;
382
+ loggerEnabled?: boolean;
255
383
  }): Promise<InitializeResult> {
256
384
  pluginState.clear();
257
385
  pluginCounter = 0;
@@ -305,6 +433,7 @@ async function initialize(args: {
305
433
  commands: [],
306
434
  messageBuilders: [],
307
435
  providers: [],
436
+ automationEventTypes: [],
308
437
  shortcuts: [],
309
438
  flags: [],
310
439
  };
@@ -351,12 +480,33 @@ async function initialize(args: {
351
480
  metadata: sanitizeObject(provider.metadata),
352
481
  });
353
482
  },
483
+ registerAutomationEventType: (eventType) => {
484
+ contributions.automationEventTypes.push({
485
+ id: makeId(pluginId, "automation_event"),
486
+ ...normalizeAutomationEventType(eventType),
487
+ });
488
+ },
354
489
  };
355
490
 
356
491
  if (typeof plugin.setup === "function") {
357
492
  try {
358
493
  const setupCtx = {
494
+ session: args.session,
495
+ client: args.client,
496
+ user: args.user,
359
497
  workspaceInfo: args.workspaceInfo,
498
+ ...(args.loggerEnabled
499
+ ? { logger: createPluginLogger(plugin.name) }
500
+ : {}),
501
+ ...(plugin.manifest.capabilities.includes("automationEvents")
502
+ ? {
503
+ automation: {
504
+ ingestEvent: (event: AutomationEventEnvelope) => {
505
+ emitEvent("automation_event", event);
506
+ },
507
+ },
508
+ }
509
+ : {}),
360
510
  };
361
511
  assertValidPluginSetupCtx(setupCtx);
362
512
  await plugin.setup(api, setupCtx);
@@ -4,7 +4,10 @@ import { dirname, join } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import type {
6
6
  AgentConfig,
7
+ AgentExtensionAutomationEventType,
7
8
  HookStage,
9
+ Message,
10
+ PluginSetupContext,
8
11
  Tool,
9
12
  WorkspaceInfo,
10
13
  } from "@clinebot/shared";
@@ -12,6 +15,11 @@ import { SubprocessSandbox } from "../../runtime/subprocess-sandbox";
12
15
  import type { PluginLoadDiagnostics } from "./plugin-load-report";
13
16
  import type { PluginTargeting } from "./plugin-targeting";
14
17
 
18
+ export type SandboxedPluginSetupContext = Pick<
19
+ PluginSetupContext,
20
+ "session" | "client" | "user" | "workspaceInfo" | "logger"
21
+ >;
22
+
15
23
  export interface PluginSandboxOptions extends PluginTargeting {
16
24
  pluginPaths: string[];
17
25
  exportName?: string;
@@ -31,6 +39,11 @@ export interface PluginSandboxOptions extends PluginTargeting {
31
39
  * so they can inspect git state without running their own commands.
32
40
  */
33
41
  workspaceInfo?: WorkspaceInfo;
42
+ session?: SandboxedPluginSetupContext["session"];
43
+ client?: SandboxedPluginSetupContext["client"];
44
+ user?: SandboxedPluginSetupContext["user"];
45
+ /** Enables a logger bridge that forwards sandbox log calls to the host. */
46
+ logger?: SandboxedPluginSetupContext["logger"];
34
47
  }
35
48
 
36
49
  type AgentExtension = NonNullable<AgentConfig["extensions"]>[number];
@@ -46,6 +59,11 @@ type SandboxedContributionDescriptor = {
46
59
  metadata?: Record<string, unknown>;
47
60
  };
48
61
 
62
+ type SandboxedAutomationEventTypeDescriptor =
63
+ AgentExtensionAutomationEventType & {
64
+ id: string;
65
+ };
66
+
49
67
  type SandboxedPluginDescriptor = {
50
68
  pluginId: string;
51
69
  pluginPath: string;
@@ -56,6 +74,7 @@ type SandboxedPluginDescriptor = {
56
74
  commands: SandboxedContributionDescriptor[];
57
75
  messageBuilders: SandboxedContributionDescriptor[];
58
76
  providers: SandboxedContributionDescriptor[];
77
+ automationEventTypes: SandboxedAutomationEventTypeDescriptor[];
59
78
  shortcuts?: SandboxedContributionDescriptor[];
60
79
  flags?: SandboxedContributionDescriptor[];
61
80
  };
@@ -75,6 +94,8 @@ function normalizeDescriptor(
75
94
  commands: descriptor.contributions?.commands ?? [],
76
95
  messageBuilders: descriptor.contributions?.messageBuilders ?? [],
77
96
  providers: descriptor.contributions?.providers ?? [],
97
+ automationEventTypes:
98
+ descriptor.contributions?.automationEventTypes ?? [],
78
99
  shortcuts: descriptor.contributions?.shortcuts ?? [],
79
100
  flags: descriptor.contributions?.flags ?? [],
80
101
  },
@@ -145,6 +166,21 @@ const HOOK_BINDINGS: Array<{
145
166
  extensionKey: "onSessionStart",
146
167
  sandboxHookName: "onSessionStart",
147
168
  },
169
+ {
170
+ stage: "run_start",
171
+ extensionKey: "onRunStart",
172
+ sandboxHookName: "onRunStart",
173
+ },
174
+ {
175
+ stage: "iteration_start",
176
+ extensionKey: "onIterationStart",
177
+ sandboxHookName: "onIterationStart",
178
+ },
179
+ {
180
+ stage: "turn_start",
181
+ extensionKey: "onTurnStart",
182
+ sandboxHookName: "onTurnStart",
183
+ },
148
184
  {
149
185
  stage: "before_agent_start",
150
186
  extensionKey: "onBeforeAgentStart",
@@ -165,6 +201,21 @@ const HOOK_BINDINGS: Array<{
165
201
  extensionKey: "onTurnEnd",
166
202
  sandboxHookName: "onTurnEnd",
167
203
  },
204
+ {
205
+ stage: "stop_error",
206
+ extensionKey: "onAgentError",
207
+ sandboxHookName: "onAgentError",
208
+ },
209
+ {
210
+ stage: "iteration_end",
211
+ extensionKey: "onIterationEnd",
212
+ sandboxHookName: "onIterationEnd",
213
+ },
214
+ {
215
+ stage: "run_end",
216
+ extensionKey: "onRunEnd",
217
+ sandboxHookName: "onRunEnd",
218
+ },
168
219
  {
169
220
  stage: "session_shutdown",
170
221
  extensionKey: "onSessionShutdown",
@@ -216,7 +267,11 @@ export async function loadSandboxedPlugins(
216
267
  providerId: options.providerId,
217
268
  modelId: options.modelId,
218
269
  cwd: options.cwd,
270
+ session: options.session,
271
+ client: options.client,
272
+ user: options.user,
219
273
  workspaceInfo: options.workspaceInfo,
274
+ loggerEnabled: Boolean(options.logger),
220
275
  };
221
276
 
222
277
  // Guard against concurrent re-initialization when multiple tools/hooks
@@ -266,6 +321,13 @@ export async function loadSandboxedPlugins(
266
321
  contributionTimeoutMs,
267
322
  reinitialize,
268
323
  );
324
+ registerMessageBuilders(
325
+ api,
326
+ sandbox,
327
+ descriptor,
328
+ contributionTimeoutMs,
329
+ reinitialize,
330
+ );
269
331
  registerSimpleContributions(api, descriptor);
270
332
  },
271
333
  };
@@ -393,13 +455,6 @@ function registerSimpleContributions(
393
455
  api: AgentExtensionApi,
394
456
  descriptor: SandboxedPluginDescriptor,
395
457
  ): void {
396
- for (const rd of descriptor.contributions?.messageBuilders ?? []) {
397
- api.registerMessageBuilder({
398
- name: rd.name,
399
- build: (m) => m,
400
- });
401
- }
402
-
403
458
  for (const pd of descriptor.contributions?.providers ?? []) {
404
459
  api.registerProvider({
405
460
  name: pd.name,
@@ -407,6 +462,75 @@ function registerSimpleContributions(
407
462
  metadata: pd.metadata,
408
463
  });
409
464
  }
465
+
466
+ for (const eventType of descriptor.contributions?.automationEventTypes ??
467
+ []) {
468
+ api.registerAutomationEventType({
469
+ eventType: eventType.eventType,
470
+ source: eventType.source,
471
+ description: eventType.description,
472
+ attributesSchema: eventType.attributesSchema,
473
+ payloadSchema: eventType.payloadSchema,
474
+ examples: eventType.examples,
475
+ metadata: eventType.metadata,
476
+ });
477
+ }
478
+ }
479
+
480
+ function registerMessageBuilders(
481
+ api: AgentExtensionApi,
482
+ sandbox: SubprocessSandbox,
483
+ descriptor: SandboxedPluginDescriptor,
484
+ timeoutMs: number,
485
+ reinitialize: () => Promise<void>,
486
+ ): void {
487
+ for (const bd of descriptor.contributions?.messageBuilders ?? []) {
488
+ api.registerMessageBuilder({
489
+ name: bd.name,
490
+ async build(messages) {
491
+ try {
492
+ const result = await sandbox.call<unknown[]>(
493
+ "buildMessages",
494
+ {
495
+ pluginId: descriptor.pluginId,
496
+ contributionId: bd.id,
497
+ messages,
498
+ },
499
+ { timeoutMs },
500
+ );
501
+ return isMessageArray(result) ? result : messages;
502
+ } catch (error) {
503
+ if (!isUnknownPluginIdError(error)) {
504
+ throw error;
505
+ }
506
+ await reinitialize();
507
+ const result = await sandbox.call<unknown[]>(
508
+ "buildMessages",
509
+ {
510
+ pluginId: descriptor.pluginId,
511
+ contributionId: bd.id,
512
+ messages,
513
+ },
514
+ { timeoutMs },
515
+ );
516
+ return isMessageArray(result) ? result : messages;
517
+ }
518
+ },
519
+ });
520
+ }
521
+ }
522
+
523
+ function isMessageArray(value: unknown): value is Message[] {
524
+ return (
525
+ Array.isArray(value) &&
526
+ value.every(
527
+ (entry) =>
528
+ typeof entry === "object" &&
529
+ entry !== null &&
530
+ "role" in entry &&
531
+ "content" in entry,
532
+ )
533
+ );
410
534
  }
411
535
 
412
536
  function makeHookHandler(
@@ -18,6 +18,7 @@ export const DefaultToolNames = {
18
18
  EDITOR: "editor",
19
19
  SKILLS: "skills",
20
20
  ASK: "ask_question",
21
+ SUBMIT_AND_EXIT: "submit_and_exit",
21
22
  } as const;
22
23
 
23
24
  /**
@@ -32,4 +33,5 @@ export const ALL_DEFAULT_TOOL_NAMES: DefaultToolName[] = [
32
33
  DefaultToolNames.EDITOR,
33
34
  DefaultToolNames.SKILLS,
34
35
  DefaultToolNames.ASK,
36
+ DefaultToolNames.SUBMIT_AND_EXIT,
35
37
  ];