@clinebot/core 0.0.22 → 0.0.23

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 (260) hide show
  1. package/dist/ClineCore.d.ts +110 -0
  2. package/dist/ClineCore.d.ts.map +1 -0
  3. package/dist/account/cline-account-service.d.ts +2 -1
  4. package/dist/account/cline-account-service.d.ts.map +1 -1
  5. package/dist/account/index.d.ts +1 -1
  6. package/dist/account/index.d.ts.map +1 -1
  7. package/dist/account/rpc.d.ts +3 -1
  8. package/dist/account/rpc.d.ts.map +1 -1
  9. package/dist/account/types.d.ts +3 -0
  10. package/dist/account/types.d.ts.map +1 -1
  11. package/dist/agents/plugin-loader.d.ts.map +1 -1
  12. package/dist/agents/plugin-sandbox-bootstrap.js +17 -17
  13. package/dist/auth/client.d.ts +1 -1
  14. package/dist/auth/client.d.ts.map +1 -1
  15. package/dist/auth/cline.d.ts +1 -1
  16. package/dist/auth/cline.d.ts.map +1 -1
  17. package/dist/auth/codex.d.ts +1 -1
  18. package/dist/auth/codex.d.ts.map +1 -1
  19. package/dist/auth/oca.d.ts +1 -1
  20. package/dist/auth/oca.d.ts.map +1 -1
  21. package/dist/auth/utils.d.ts +2 -2
  22. package/dist/auth/utils.d.ts.map +1 -1
  23. package/dist/index.d.ts +50 -5
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +949 -0
  26. package/dist/providers/local-provider-service.d.ts +4 -4
  27. package/dist/providers/local-provider-service.d.ts.map +1 -1
  28. package/dist/runtime/runtime-builder.d.ts +1 -0
  29. package/dist/runtime/runtime-builder.d.ts.map +1 -1
  30. package/dist/runtime/session-runtime.d.ts +2 -1
  31. package/dist/runtime/session-runtime.d.ts.map +1 -1
  32. package/dist/runtime/team-runtime-registry.d.ts +13 -0
  33. package/dist/runtime/team-runtime-registry.d.ts.map +1 -0
  34. package/dist/session/default-session-manager.d.ts +2 -2
  35. package/dist/session/default-session-manager.d.ts.map +1 -1
  36. package/dist/session/rpc-runtime-ensure.d.ts +53 -0
  37. package/dist/session/rpc-runtime-ensure.d.ts.map +1 -0
  38. package/dist/session/session-config-builder.d.ts +2 -3
  39. package/dist/session/session-config-builder.d.ts.map +1 -1
  40. package/dist/session/session-host.d.ts +8 -18
  41. package/dist/session/session-host.d.ts.map +1 -1
  42. package/dist/session/session-manager.d.ts +1 -1
  43. package/dist/session/session-manager.d.ts.map +1 -1
  44. package/dist/session/session-manifest.d.ts +1 -2
  45. package/dist/session/session-manifest.d.ts.map +1 -1
  46. package/dist/session/unified-session-persistence-service.d.ts +2 -2
  47. package/dist/session/unified-session-persistence-service.d.ts.map +1 -1
  48. package/dist/session/utils/helpers.d.ts +1 -1
  49. package/dist/session/utils/helpers.d.ts.map +1 -1
  50. package/dist/session/utils/types.d.ts +1 -1
  51. package/dist/session/utils/types.d.ts.map +1 -1
  52. package/dist/storage/provider-settings-legacy-migration.d.ts.map +1 -1
  53. package/dist/telemetry/OpenTelemetryProvider.d.ts.map +1 -1
  54. package/dist/telemetry/distinct-id.d.ts +2 -0
  55. package/dist/telemetry/distinct-id.d.ts.map +1 -0
  56. package/dist/telemetry/{opentelemetry.d.ts → index.d.ts} +1 -1
  57. package/dist/telemetry/index.d.ts.map +1 -0
  58. package/dist/telemetry/index.js +28 -0
  59. package/dist/tools/constants.d.ts +1 -1
  60. package/dist/tools/constants.d.ts.map +1 -1
  61. package/dist/tools/definitions.d.ts +3 -3
  62. package/dist/tools/definitions.d.ts.map +1 -1
  63. package/dist/tools/executors/apply-patch.d.ts +1 -1
  64. package/dist/tools/executors/apply-patch.d.ts.map +1 -1
  65. package/dist/tools/executors/bash.d.ts +1 -1
  66. package/dist/tools/executors/bash.d.ts.map +1 -1
  67. package/dist/tools/executors/editor.d.ts +1 -1
  68. package/dist/tools/executors/editor.d.ts.map +1 -1
  69. package/dist/tools/executors/file-read.d.ts +1 -1
  70. package/dist/tools/executors/file-read.d.ts.map +1 -1
  71. package/dist/tools/executors/index.d.ts +14 -14
  72. package/dist/tools/executors/index.d.ts.map +1 -1
  73. package/dist/tools/executors/search.d.ts +1 -1
  74. package/dist/tools/executors/search.d.ts.map +1 -1
  75. package/dist/tools/executors/web-fetch.d.ts +1 -1
  76. package/dist/tools/executors/web-fetch.d.ts.map +1 -1
  77. package/dist/tools/helpers.d.ts +1 -1
  78. package/dist/tools/helpers.d.ts.map +1 -1
  79. package/dist/tools/index.d.ts +10 -10
  80. package/dist/tools/index.d.ts.map +1 -1
  81. package/dist/tools/model-tool-routing.d.ts +1 -1
  82. package/dist/tools/model-tool-routing.d.ts.map +1 -1
  83. package/dist/tools/presets.d.ts +1 -1
  84. package/dist/tools/presets.d.ts.map +1 -1
  85. package/dist/types/common.d.ts +17 -8
  86. package/dist/types/common.d.ts.map +1 -1
  87. package/dist/types/config.d.ts +4 -3
  88. package/dist/types/config.d.ts.map +1 -1
  89. package/dist/types/provider-settings.d.ts +1 -1
  90. package/dist/types/provider-settings.d.ts.map +1 -1
  91. package/dist/types.d.ts +5 -2
  92. package/dist/types.d.ts.map +1 -1
  93. package/dist/version.d.ts +2 -0
  94. package/dist/version.d.ts.map +1 -0
  95. package/package.json +44 -38
  96. package/src/ClineCore.ts +137 -0
  97. package/src/account/cline-account-service.test.ts +101 -0
  98. package/src/account/cline-account-service.ts +300 -0
  99. package/src/account/featurebase-token.test.ts +175 -0
  100. package/src/account/index.ts +23 -0
  101. package/src/account/rpc.test.ts +63 -0
  102. package/src/account/rpc.ts +185 -0
  103. package/src/account/types.ts +102 -0
  104. package/src/agents/agent-config-loader.test.ts +236 -0
  105. package/src/agents/agent-config-loader.ts +108 -0
  106. package/src/agents/agent-config-parser.ts +198 -0
  107. package/src/agents/hooks-config-loader.test.ts +20 -0
  108. package/src/agents/hooks-config-loader.ts +118 -0
  109. package/src/agents/index.ts +85 -0
  110. package/src/agents/plugin-config-loader.test.ts +140 -0
  111. package/src/agents/plugin-config-loader.ts +97 -0
  112. package/src/agents/plugin-loader.test.ts +210 -0
  113. package/src/agents/plugin-loader.ts +175 -0
  114. package/src/agents/plugin-sandbox-bootstrap.ts +448 -0
  115. package/src/agents/plugin-sandbox.test.ts +296 -0
  116. package/src/agents/plugin-sandbox.ts +341 -0
  117. package/src/agents/unified-config-file-watcher.test.ts +196 -0
  118. package/src/agents/unified-config-file-watcher.ts +483 -0
  119. package/src/agents/user-instruction-config-loader.test.ts +158 -0
  120. package/src/agents/user-instruction-config-loader.ts +438 -0
  121. package/src/auth/client.test.ts +40 -0
  122. package/src/auth/client.ts +25 -0
  123. package/src/auth/cline.test.ts +130 -0
  124. package/src/auth/cline.ts +420 -0
  125. package/src/auth/codex.test.ts +170 -0
  126. package/src/auth/codex.ts +491 -0
  127. package/src/auth/oca.test.ts +215 -0
  128. package/src/auth/oca.ts +573 -0
  129. package/src/auth/server.ts +216 -0
  130. package/src/auth/types.ts +81 -0
  131. package/src/auth/utils.test.ts +128 -0
  132. package/src/auth/utils.ts +247 -0
  133. package/src/chat/chat-schema.ts +82 -0
  134. package/src/index.ts +479 -0
  135. package/src/input/file-indexer.d.ts +11 -0
  136. package/src/input/file-indexer.test.ts +127 -0
  137. package/src/input/file-indexer.ts +327 -0
  138. package/src/input/index.ts +7 -0
  139. package/src/input/mention-enricher.test.ts +85 -0
  140. package/src/input/mention-enricher.ts +122 -0
  141. package/src/mcp/config-loader.test.ts +238 -0
  142. package/src/mcp/config-loader.ts +219 -0
  143. package/src/mcp/index.ts +26 -0
  144. package/src/mcp/manager.test.ts +106 -0
  145. package/src/mcp/manager.ts +262 -0
  146. package/src/mcp/types.ts +88 -0
  147. package/src/providers/local-provider-registry.ts +232 -0
  148. package/src/providers/local-provider-service.test.ts +783 -0
  149. package/src/providers/local-provider-service.ts +471 -0
  150. package/src/runtime/commands.test.ts +98 -0
  151. package/src/runtime/commands.ts +83 -0
  152. package/src/runtime/hook-file-hooks.test.ts +237 -0
  153. package/src/runtime/hook-file-hooks.ts +859 -0
  154. package/src/runtime/index.ts +37 -0
  155. package/src/runtime/rules.ts +34 -0
  156. package/src/runtime/runtime-builder.team-persistence.test.ts +245 -0
  157. package/src/runtime/runtime-builder.test.ts +371 -0
  158. package/src/runtime/runtime-builder.ts +631 -0
  159. package/src/runtime/runtime-parity.test.ts +143 -0
  160. package/src/runtime/sandbox/subprocess-sandbox.ts +231 -0
  161. package/src/runtime/session-runtime.ts +49 -0
  162. package/src/runtime/skills.ts +44 -0
  163. package/src/runtime/team-runtime-registry.ts +46 -0
  164. package/src/runtime/tool-approval.ts +104 -0
  165. package/src/runtime/workflows.test.ts +119 -0
  166. package/src/runtime/workflows.ts +45 -0
  167. package/src/session/default-session-manager.e2e.test.ts +384 -0
  168. package/src/session/default-session-manager.test.ts +1931 -0
  169. package/src/session/default-session-manager.ts +1422 -0
  170. package/src/session/file-session-service.ts +280 -0
  171. package/src/session/index.ts +45 -0
  172. package/src/session/rpc-runtime-ensure.ts +521 -0
  173. package/src/session/rpc-session-service.ts +107 -0
  174. package/src/session/rpc-spawn-lease.test.ts +49 -0
  175. package/src/session/rpc-spawn-lease.ts +122 -0
  176. package/src/session/runtime-oauth-token-manager.test.ts +137 -0
  177. package/src/session/runtime-oauth-token-manager.ts +272 -0
  178. package/src/session/session-agent-events.ts +248 -0
  179. package/src/session/session-artifacts.ts +106 -0
  180. package/src/session/session-config-builder.ts +113 -0
  181. package/src/session/session-graph.ts +92 -0
  182. package/src/session/session-host.test.ts +89 -0
  183. package/src/session/session-host.ts +205 -0
  184. package/src/session/session-manager.ts +69 -0
  185. package/src/session/session-manifest.ts +29 -0
  186. package/src/session/session-service.team-persistence.test.ts +48 -0
  187. package/src/session/session-service.ts +673 -0
  188. package/src/session/session-team-coordination.ts +229 -0
  189. package/src/session/session-telemetry.ts +100 -0
  190. package/src/session/sqlite-rpc-session-backend.ts +303 -0
  191. package/src/session/unified-session-persistence-service.test.ts +85 -0
  192. package/src/session/unified-session-persistence-service.ts +994 -0
  193. package/src/session/utils/helpers.ts +139 -0
  194. package/src/session/utils/types.ts +57 -0
  195. package/src/session/utils/usage.ts +32 -0
  196. package/src/session/workspace-manager.ts +98 -0
  197. package/src/session/workspace-manifest.ts +100 -0
  198. package/src/storage/artifact-store.ts +1 -0
  199. package/src/storage/file-team-store.ts +257 -0
  200. package/src/storage/index.ts +11 -0
  201. package/src/storage/provider-settings-legacy-migration.test.ts +424 -0
  202. package/src/storage/provider-settings-legacy-migration.ts +826 -0
  203. package/src/storage/provider-settings-manager.test.ts +191 -0
  204. package/src/storage/provider-settings-manager.ts +152 -0
  205. package/src/storage/session-store.ts +1 -0
  206. package/src/storage/sqlite-session-store.ts +275 -0
  207. package/src/storage/sqlite-team-store.ts +454 -0
  208. package/src/storage/team-store.ts +40 -0
  209. package/src/team/index.ts +4 -0
  210. package/src/team/projections.ts +285 -0
  211. package/src/telemetry/ITelemetryAdapter.ts +94 -0
  212. package/src/telemetry/LoggerTelemetryAdapter.test.ts +42 -0
  213. package/src/telemetry/LoggerTelemetryAdapter.ts +114 -0
  214. package/src/telemetry/OpenTelemetryAdapter.test.ts +157 -0
  215. package/src/telemetry/OpenTelemetryAdapter.ts +348 -0
  216. package/src/telemetry/OpenTelemetryProvider.test.ts +113 -0
  217. package/src/telemetry/OpenTelemetryProvider.ts +325 -0
  218. package/src/telemetry/TelemetryService.test.ts +134 -0
  219. package/src/telemetry/TelemetryService.ts +141 -0
  220. package/src/telemetry/core-events.ts +400 -0
  221. package/src/telemetry/distinct-id.test.ts +57 -0
  222. package/src/telemetry/distinct-id.ts +58 -0
  223. package/src/telemetry/index.ts +20 -0
  224. package/src/tools/constants.ts +35 -0
  225. package/src/tools/definitions.test.ts +704 -0
  226. package/src/tools/definitions.ts +709 -0
  227. package/src/tools/executors/apply-patch-parser.ts +520 -0
  228. package/src/tools/executors/apply-patch.ts +359 -0
  229. package/src/tools/executors/bash.test.ts +87 -0
  230. package/src/tools/executors/bash.ts +207 -0
  231. package/src/tools/executors/editor.test.ts +35 -0
  232. package/src/tools/executors/editor.ts +219 -0
  233. package/src/tools/executors/file-read.test.ts +49 -0
  234. package/src/tools/executors/file-read.ts +110 -0
  235. package/src/tools/executors/index.ts +87 -0
  236. package/src/tools/executors/search.ts +278 -0
  237. package/src/tools/executors/web-fetch.ts +259 -0
  238. package/src/tools/helpers.ts +130 -0
  239. package/src/tools/index.ts +169 -0
  240. package/src/tools/model-tool-routing.test.ts +86 -0
  241. package/src/tools/model-tool-routing.ts +132 -0
  242. package/src/tools/presets.test.ts +62 -0
  243. package/src/tools/presets.ts +168 -0
  244. package/src/tools/schemas.ts +327 -0
  245. package/src/tools/types.ts +329 -0
  246. package/src/types/common.ts +26 -0
  247. package/src/types/config.ts +86 -0
  248. package/src/types/events.ts +74 -0
  249. package/src/types/index.ts +24 -0
  250. package/src/types/provider-settings.ts +43 -0
  251. package/src/types/sessions.ts +16 -0
  252. package/src/types/storage.ts +64 -0
  253. package/src/types/workspace.ts +7 -0
  254. package/src/types.ts +132 -0
  255. package/src/version.ts +3 -0
  256. package/dist/index.node.d.ts +0 -47
  257. package/dist/index.node.d.ts.map +0 -1
  258. package/dist/index.node.js +0 -948
  259. package/dist/telemetry/opentelemetry.d.ts.map +0 -1
  260. package/dist/telemetry/opentelemetry.js +0 -27
@@ -0,0 +1,448 @@
1
+ import { existsSync } from "node:fs";
2
+ import { builtinModules, createRequire } from "node:module";
3
+ import { dirname, resolve } from "node:path";
4
+ /**
5
+ * Bootstrap script for the plugin sandbox subprocess.
6
+ *
7
+ * This file runs inside an isolated Node.js child process spawned by
8
+ * {@link SubprocessSandbox}. It receives RPC calls over IPC and dynamically
9
+ * imports plugin modules, wiring up their contributions (tools, commands,
10
+ * shortcuts, flags, renderers, providers) and lifecycle hooks.
11
+ *
12
+ * Because it executes in a separate process it must be self-contained — no
13
+ * imports from the rest of the codebase are allowed.
14
+ */
15
+
16
+ import { fileURLToPath } from "node:url";
17
+ import createJiti from "jiti";
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // Types (intentionally minimal – mirrors only what the RPC protocol needs)
21
+ // ---------------------------------------------------------------------------
22
+
23
+ interface PluginTool {
24
+ name: string;
25
+ description?: string;
26
+ inputSchema?: unknown;
27
+ timeoutMs?: number;
28
+ retryable?: boolean;
29
+ execute: (input: unknown, context: unknown) => Promise<unknown>;
30
+ }
31
+
32
+ interface PluginCommand {
33
+ name: string;
34
+ description?: string;
35
+ handler?: (input: string) => Promise<string>;
36
+ }
37
+
38
+ interface PluginShortcut {
39
+ name: string;
40
+ value: string;
41
+ description?: string;
42
+ }
43
+
44
+ interface PluginFlag {
45
+ name: string;
46
+ description?: string;
47
+ defaultValue?: boolean | string | number;
48
+ }
49
+
50
+ interface PluginMessageRenderer {
51
+ name: string;
52
+ render: (message: unknown) => string;
53
+ }
54
+
55
+ interface PluginProvider {
56
+ name: string;
57
+ description?: string;
58
+ metadata?: Record<string, unknown>;
59
+ }
60
+
61
+ interface PluginApi {
62
+ registerTool(tool: PluginTool): void;
63
+ registerCommand(command: PluginCommand): void;
64
+ registerShortcut(shortcut: PluginShortcut): void;
65
+ registerFlag(flag: PluginFlag): void;
66
+ registerMessageRenderer(renderer: PluginMessageRenderer): void;
67
+ registerProvider(provider: PluginProvider): void;
68
+ }
69
+
70
+ interface PluginModule {
71
+ name: string;
72
+ manifest: Record<string, unknown>;
73
+ setup?: (api: PluginApi) => void | Promise<void>;
74
+ [hookName: string]: unknown;
75
+ }
76
+
77
+ interface ContributionDescriptor {
78
+ id: string;
79
+ name: string;
80
+ description?: string;
81
+ inputSchema?: unknown;
82
+ timeoutMs?: number;
83
+ retryable?: boolean;
84
+ value?: string;
85
+ defaultValue?: boolean | string | number;
86
+ metadata?: Record<string, unknown>;
87
+ }
88
+
89
+ interface PluginDescriptor {
90
+ pluginId: string;
91
+ name: string;
92
+ manifest: Record<string, unknown>;
93
+ contributions: {
94
+ tools: ContributionDescriptor[];
95
+ commands: ContributionDescriptor[];
96
+ shortcuts: ContributionDescriptor[];
97
+ flags: ContributionDescriptor[];
98
+ messageRenderers: ContributionDescriptor[];
99
+ providers: ContributionDescriptor[];
100
+ };
101
+ }
102
+
103
+ interface PluginState {
104
+ plugin: PluginModule;
105
+ handlers: {
106
+ tools: Map<string, PluginTool["execute"]>;
107
+ commands: Map<string, NonNullable<PluginCommand["handler"]>>;
108
+ messageRenderers: Map<string, PluginMessageRenderer["render"]>;
109
+ };
110
+ }
111
+
112
+ function isObject(value: unknown): value is Record<string, unknown> {
113
+ return typeof value === "object" && value !== null;
114
+ }
115
+
116
+ function assertValidPluginModule(
117
+ plugin: unknown,
118
+ pluginPath: string,
119
+ ): asserts plugin is PluginModule {
120
+ if (!isObject(plugin)) {
121
+ throw new Error(`Invalid plugin module: ${pluginPath}`);
122
+ }
123
+ if (typeof plugin.name !== "string" || !plugin.name) {
124
+ throw new Error(`Invalid plugin name: ${pluginPath}`);
125
+ }
126
+ if (!isObject(plugin.manifest)) {
127
+ throw new Error(`Invalid plugin manifest: ${pluginPath}`);
128
+ }
129
+ }
130
+
131
+ // ---------------------------------------------------------------------------
132
+ // State
133
+ // ---------------------------------------------------------------------------
134
+
135
+ let pluginCounter = 0;
136
+ const pluginState = new Map<string, PluginState>();
137
+ const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
138
+ const WORKSPACE_ALIASES = collectWorkspaceAliases(MODULE_DIR);
139
+ const BUILTIN_MODULES = new Set(
140
+ builtinModules.flatMap((id) => [id, id.replace(/^node:/, "")]),
141
+ );
142
+
143
+ // ---------------------------------------------------------------------------
144
+ // IPC helpers
145
+ // ---------------------------------------------------------------------------
146
+
147
+ function toErrorPayload(error: unknown): { message: string; stack?: string } {
148
+ const message = error instanceof Error ? error.message : String(error);
149
+ const stack = error instanceof Error ? error.stack : undefined;
150
+ return { message, stack };
151
+ }
152
+
153
+ function sendResponse(
154
+ id: string,
155
+ ok: boolean,
156
+ result: unknown,
157
+ error?: { message: string; stack?: string },
158
+ ): void {
159
+ if (!process.send) return;
160
+ process.send({ type: "response", id, ok, result, error });
161
+ }
162
+
163
+ function emitEvent(name: string, payload?: unknown): void {
164
+ if (!process.send) return;
165
+ process.send({ type: "event", name, payload });
166
+ }
167
+
168
+ // Expose event emitter to plugins.
169
+ (globalThis as Record<string, unknown>).__clinePluginHost = { emitEvent };
170
+
171
+ // ---------------------------------------------------------------------------
172
+ // Helpers
173
+ // ---------------------------------------------------------------------------
174
+
175
+ function sanitizeObject(value: unknown): Record<string, unknown> {
176
+ if (!value || typeof value !== "object") return {};
177
+ return value as Record<string, unknown>;
178
+ }
179
+
180
+ function makeId(pluginId: string, prefix: string): string {
181
+ return `${pluginId}_${prefix}_${Math.random().toString(36).slice(2, 10)}`;
182
+ }
183
+
184
+ function getPlugin(pluginId: string): PluginState {
185
+ const state = pluginState.get(pluginId);
186
+ if (!state) {
187
+ throw new Error(`Unknown sandbox plugin id: ${pluginId}`);
188
+ }
189
+ return state;
190
+ }
191
+
192
+ function collectWorkspaceAliases(startDir: string): Record<string, string> {
193
+ const root = resolve(startDir, "..", "..", "..", "..");
194
+ const aliases: Record<string, string> = {};
195
+ const candidates: Record<string, string> = {
196
+ "@clinebot/agents": resolve(root, "packages/agents/src/index.ts"),
197
+ "@clinebot/core": resolve(root, "packages/core/src/index.ts"),
198
+ "@clinebot/llms": resolve(root, "packages/llms/src/index.ts"),
199
+ "@clinebot/llms/models": resolve(root, "packages/llms/src/models.ts"),
200
+ "@clinebot/llms/providers": resolve(root, "packages/llms/src/providers.ts"),
201
+ "@clinebot/llms/runtime": resolve(root, "packages/llms/src/runtime.ts"),
202
+ "@clinebot/rpc": resolve(root, "packages/rpc/src/index.ts"),
203
+ "@clinebot/scheduler": resolve(root, "packages/scheduler/src/index.ts"),
204
+ "@clinebot/shared": resolve(root, "packages/shared/src/index.ts"),
205
+ "@clinebot/shared/storage": resolve(
206
+ root,
207
+ "packages/shared/src/storage/index.ts",
208
+ ),
209
+ "@clinebot/shared/db": resolve(root, "packages/shared/src/db/index.ts"),
210
+ };
211
+ for (const [key, value] of Object.entries(candidates)) {
212
+ if (existsSync(value)) {
213
+ aliases[key] = value;
214
+ }
215
+ }
216
+ return aliases;
217
+ }
218
+
219
+ function collectPluginImportAliases(
220
+ pluginPath: string,
221
+ ): Record<string, string> {
222
+ const pluginRequire = createRequire(pluginPath);
223
+ const aliases: Record<string, string> = {};
224
+ for (const [specifier, sourcePath] of Object.entries(WORKSPACE_ALIASES)) {
225
+ try {
226
+ pluginRequire.resolve(specifier);
227
+ continue;
228
+ } catch {
229
+ // Use the workspace source only when the plugin package does not provide
230
+ // its own installed SDK dependency.
231
+ }
232
+ aliases[specifier] = sourcePath;
233
+ }
234
+ return aliases;
235
+ }
236
+
237
+ async function importPluginModule(
238
+ pluginPath: string,
239
+ ): Promise<Record<string, unknown>> {
240
+ const aliases = collectPluginImportAliases(pluginPath);
241
+ const jiti = createJiti(pluginPath, {
242
+ alias: aliases,
243
+ cache: false,
244
+ requireCache: false,
245
+ esmResolve: true,
246
+ interopDefault: false,
247
+ nativeModules: [...BUILTIN_MODULES],
248
+ transformModules: Object.keys(aliases),
249
+ });
250
+ return (await jiti.import(pluginPath, {})) as Record<string, unknown>;
251
+ }
252
+
253
+ // ---------------------------------------------------------------------------
254
+ // RPC methods
255
+ // ---------------------------------------------------------------------------
256
+
257
+ async function initialize(args: {
258
+ pluginPaths?: string[];
259
+ exportName?: string;
260
+ }): Promise<PluginDescriptor[]> {
261
+ const descriptors: PluginDescriptor[] = [];
262
+ const exportName = args.exportName || "plugin";
263
+
264
+ for (const pluginPath of args.pluginPaths || []) {
265
+ const moduleExports = await importPluginModule(pluginPath);
266
+ const plugin = (moduleExports.default ??
267
+ moduleExports[exportName]) as unknown;
268
+ assertValidPluginModule(plugin, pluginPath);
269
+
270
+ const pluginId = `plugin_${++pluginCounter}`;
271
+ const contributions: PluginDescriptor["contributions"] = {
272
+ tools: [],
273
+ commands: [],
274
+ shortcuts: [],
275
+ flags: [],
276
+ messageRenderers: [],
277
+ providers: [],
278
+ };
279
+ const handlers: PluginState["handlers"] = {
280
+ tools: new Map(),
281
+ commands: new Map(),
282
+ messageRenderers: new Map(),
283
+ };
284
+
285
+ const api: PluginApi = {
286
+ registerTool: (tool) => {
287
+ const id = makeId(pluginId, "tool");
288
+ handlers.tools.set(id, tool.execute);
289
+ contributions.tools.push({
290
+ id,
291
+ name: tool.name,
292
+ description: tool.description,
293
+ inputSchema: tool.inputSchema,
294
+ timeoutMs: tool.timeoutMs,
295
+ retryable: tool.retryable,
296
+ });
297
+ },
298
+ registerCommand: (command) => {
299
+ const id = makeId(pluginId, "command");
300
+ if (typeof command.handler === "function") {
301
+ handlers.commands.set(id, command.handler);
302
+ }
303
+ contributions.commands.push({
304
+ id,
305
+ name: command.name,
306
+ description: command.description,
307
+ });
308
+ },
309
+ registerShortcut: (shortcut) => {
310
+ contributions.shortcuts.push({
311
+ id: makeId(pluginId, "shortcut"),
312
+ name: shortcut.name,
313
+ value: shortcut.value,
314
+ description: shortcut.description,
315
+ });
316
+ },
317
+ registerFlag: (flag) => {
318
+ contributions.flags.push({
319
+ id: makeId(pluginId, "flag"),
320
+ name: flag.name,
321
+ description: flag.description,
322
+ defaultValue: flag.defaultValue,
323
+ });
324
+ },
325
+ registerMessageRenderer: (renderer) => {
326
+ const id = makeId(pluginId, "renderer");
327
+ handlers.messageRenderers.set(id, renderer.render);
328
+ contributions.messageRenderers.push({ id, name: renderer.name });
329
+ },
330
+ registerProvider: (provider) => {
331
+ contributions.providers.push({
332
+ id: makeId(pluginId, "provider"),
333
+ name: provider.name,
334
+ description: provider.description,
335
+ metadata: sanitizeObject(provider.metadata),
336
+ });
337
+ },
338
+ };
339
+
340
+ if (typeof plugin.setup === "function") {
341
+ await plugin.setup(api);
342
+ }
343
+
344
+ pluginState.set(pluginId, { plugin, handlers });
345
+ descriptors.push({
346
+ pluginId,
347
+ name: plugin.name,
348
+ manifest: plugin.manifest,
349
+ contributions,
350
+ });
351
+ }
352
+
353
+ return descriptors;
354
+ }
355
+
356
+ async function invokeHook(args: {
357
+ pluginId: string;
358
+ hookName: string;
359
+ payload: unknown;
360
+ }): Promise<unknown> {
361
+ const state = getPlugin(args.pluginId);
362
+ const handler = state.plugin[args.hookName];
363
+ if (typeof handler !== "function") {
364
+ return undefined;
365
+ }
366
+ return await (handler as (payload: unknown) => Promise<unknown>)(
367
+ args.payload,
368
+ );
369
+ }
370
+
371
+ async function executeTool(args: {
372
+ pluginId: string;
373
+ contributionId: string;
374
+ input: unknown;
375
+ context: unknown;
376
+ }): Promise<unknown> {
377
+ const state = getPlugin(args.pluginId);
378
+ const handler = state.handlers.tools.get(args.contributionId);
379
+ if (typeof handler !== "function") {
380
+ throw new Error("Unknown sandbox tool contribution");
381
+ }
382
+ return await handler(args.input, args.context);
383
+ }
384
+
385
+ async function executeCommand(args: {
386
+ pluginId: string;
387
+ contributionId: string;
388
+ input: string;
389
+ }): Promise<string> {
390
+ const state = getPlugin(args.pluginId);
391
+ const handler = state.handlers.commands.get(args.contributionId);
392
+ if (typeof handler !== "function") {
393
+ return "";
394
+ }
395
+ return await handler(args.input);
396
+ }
397
+
398
+ async function renderMessage(args: {
399
+ pluginId: string;
400
+ contributionId: string;
401
+ message: unknown;
402
+ }): Promise<string> {
403
+ const state = getPlugin(args.pluginId);
404
+ const handler = state.handlers.messageRenderers.get(args.contributionId);
405
+ if (typeof handler !== "function") {
406
+ return "";
407
+ }
408
+ return await handler(args.message);
409
+ }
410
+
411
+ // ---------------------------------------------------------------------------
412
+ // Message dispatch
413
+ // ---------------------------------------------------------------------------
414
+
415
+ const methods: Record<string, (args: never) => Promise<unknown>> = {
416
+ initialize,
417
+ invokeHook,
418
+ executeTool,
419
+ executeCommand,
420
+ renderMessage,
421
+ };
422
+
423
+ process.on(
424
+ "message",
425
+ async (message: {
426
+ type: string;
427
+ id: string;
428
+ method: string;
429
+ args?: unknown;
430
+ }) => {
431
+ if (!message || message.type !== "call") {
432
+ return;
433
+ }
434
+ const method = methods[message.method];
435
+ if (!method) {
436
+ sendResponse(message.id, false, undefined, {
437
+ message: `Unknown method: ${String(message.method)}`,
438
+ });
439
+ return;
440
+ }
441
+ try {
442
+ const result = await method((message.args || {}) as never);
443
+ sendResponse(message.id, true, result);
444
+ } catch (error) {
445
+ sendResponse(message.id, false, undefined, toErrorPayload(error));
446
+ }
447
+ },
448
+ );