profclaw 0.0.1-beta.2 → 2.0.0

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 (156) hide show
  1. package/CHANGELOG.md +21 -38
  2. package/CONTRIBUTING.md +3 -5
  3. package/README.md +128 -63
  4. package/dist/chat/execution/tools/index.d.ts +1 -1
  5. package/dist/chat/execution/tools/index.js +41 -2
  6. package/dist/chat/providers/slack/index.d.ts +2 -2
  7. package/dist/cli/commands/models.js +39 -26
  8. package/dist/cli/commands/onboard.js +64 -79
  9. package/dist/cli/commands/setup.js +293 -90
  10. package/dist/cli/index.js +0 -6
  11. package/dist/cli/providers.d.ts +15 -0
  12. package/dist/cli/providers.js +41 -0
  13. package/dist/core/deployment.js +2 -0
  14. package/dist/providers/ai-sdk.js +26 -6
  15. package/dist/routes/channels.d.ts +12 -0
  16. package/dist/routes/channels.js +166 -0
  17. package/dist/server/route-loader.js +1 -0
  18. package/dist/server.js +115 -109
  19. package/package.json +1 -1
  20. package/skills/git-workflow/SKILL.md +3 -3
  21. package/ui/dist/assets/{ActivityView-DIPQSJ_d.js → ActivityView-BeshZXmE.js} +1 -1
  22. package/ui/dist/assets/{AgentList-CqyaYrcq.js → AgentList-QVHeldPi.js} +1 -1
  23. package/ui/dist/assets/{AnalyticsDashboard-C-mjuGHT.js → AnalyticsDashboard-C9R97dXE.js} +1 -1
  24. package/ui/dist/assets/{AreaChart-CfYWmbtr.js → AreaChart-B73gaiVQ.js} +1 -1
  25. package/ui/dist/assets/{CartesianChart-BaQ3It0c.js → CartesianChart-CXYL2R-A.js} +1 -1
  26. package/ui/dist/assets/{ChatView-DxxQy6pl.js → ChatView-qjZErlrp.js} +1 -1
  27. package/ui/dist/assets/{CostsDashboard-CDBBcGkg.js → CostsDashboard-O4DCLy1i.js} +1 -1
  28. package/ui/dist/assets/{EstimateSelect-CDjf5qKl.js → EstimateSelect-1hQf4Osk.js} +1 -1
  29. package/ui/dist/assets/{FloatingChatbot-CZHjvJIe.js → FloatingChatbot-BZBzrJxd.js} +1 -1
  30. package/ui/dist/assets/{InviteCodeManagement-DTm-IPTm.js → InviteCodeManagement-LEoGqYeA.js} +1 -1
  31. package/ui/dist/assets/{ProjectDetail-DlYUcOss.js → ProjectDetail--gPfvATB.js} +1 -1
  32. package/ui/dist/assets/{ProjectIcon-BMRpnM04.js → ProjectIcon-Chd_ofsw.js} +1 -1
  33. package/ui/dist/assets/{ProjectList-D85TN0i0.js → ProjectList-BvUfVB6c.js} +1 -1
  34. package/ui/dist/assets/{Settings-CgPqzUvj.js → Settings-1kaf7VHE.js} +1 -1
  35. package/ui/dist/assets/{StatusIndicator-yig0uZEA.js → StatusIndicator-pRfkNcdV.js} +1 -1
  36. package/ui/dist/assets/{SummaryDetail-CwLAfHgJ.js → SummaryDetail-DV3AmONk.js} +1 -1
  37. package/ui/dist/assets/{SummaryList-BvS5Idnu.js → SummaryList-B6kXiTxL.js} +1 -1
  38. package/ui/dist/assets/{TaskDetail-zarC1fOt.js → TaskDetail-CV6CzbOS.js} +1 -1
  39. package/ui/dist/assets/{TaskList-CyJq3ANE.js → TaskList-DL7brQKd.js} +1 -1
  40. package/ui/dist/assets/{TicketBoard-BlWr3-iH.js → TicketBoard-CrkkFj7C.js} +1 -1
  41. package/ui/dist/assets/{TicketDetail-DmqWKj2W.js → TicketDetail-hnnYclpD.js} +1 -1
  42. package/ui/dist/assets/{TicketList-Scj4pMWa.js → TicketList-CsDAyQCL.js} +1 -1
  43. package/ui/dist/assets/{UserManagement-BH7uG7dw.js → UserManagement-BGFQyTSr.js} +1 -1
  44. package/ui/dist/assets/{ViewSwitcher-3HzZUdWn.js → ViewSwitcher-CnL0OqA8.js} +1 -1
  45. package/ui/dist/assets/{alert-dialog-DWPb2IfQ.js → alert-dialog-SKM6Gjz4.js} +1 -1
  46. package/ui/dist/assets/{archive-CGck7gxR.js → archive-BsLa7brF.js} +1 -1
  47. package/ui/dist/assets/{badge-DEmc3Z_l.js → badge-CVHH1a-v.js} +1 -1
  48. package/ui/dist/assets/{brain-CfFdLVqb.js → brain-6o_RHVpe.js} +1 -1
  49. package/ui/dist/assets/{bug-DqSGPUUE.js → bug-CmZI7jqM.js} +1 -1
  50. package/ui/dist/assets/{calendar-BuZ4zbPW.js → calendar-Bf0t2B82.js} +1 -1
  51. package/ui/dist/assets/{chevron-up-DcJ4LL_N.js → chevron-up-CoUsOvZj.js} +1 -1
  52. package/ui/dist/assets/{circle-x-C78PNZjF.js → circle-x-Dgw11LgT.js} +1 -1
  53. package/ui/dist/assets/{constants-DhDjZe4P.js → constants-Q5Zivl-a.js} +1 -1
  54. package/ui/dist/assets/{cpu-Ck6AoG8c.js → cpu-DiPMQICV.js} +1 -1
  55. package/ui/dist/assets/{database-CA2w8Lvt.js → database-BwTfupDi.js} +1 -1
  56. package/ui/dist/assets/{dialog-BOdGWhgE.js → dialog-BUqN9Psj.js} +1 -1
  57. package/ui/dist/assets/{ellipsis-FhHKRbfl.js → ellipsis-UJx4Xnf6.js} +1 -1
  58. package/ui/dist/assets/{ellipsis-vertical-CO0UqE4-.js → ellipsis-vertical-DoULYEKn.js} +1 -1
  59. package/ui/dist/assets/{file-code-ChnhYYj1.js → file-code-B2UrJLwi.js} +1 -1
  60. package/ui/dist/assets/{folder-open-CHwA1-ve.js → folder-open-BJi577JH.js} +1 -1
  61. package/ui/dist/assets/{funnel-ByEjRFNB.js → funnel-PkaD_HSR.js} +1 -1
  62. package/ui/dist/assets/{git-branch-GTOPQgU4.js → git-branch-C_K30am0.js} +1 -1
  63. package/ui/dist/assets/{git-commit-horizontal-F5M84Kut.js → git-commit-horizontal-IT6ecxWQ.js} +1 -1
  64. package/ui/dist/assets/{globe-CQWfr7hT.js → globe-f-jjCa_g.js} +1 -1
  65. package/ui/dist/assets/{hash-nKC9gtLg.js → hash-DNEv8Elo.js} +1 -1
  66. package/ui/dist/assets/{history-DfFSA9xJ.js → history-BQSBo_1Q.js} +1 -1
  67. package/ui/dist/assets/{index-DHGvP9mp.js → index-BUmnwPQr.js} +1 -1
  68. package/ui/dist/assets/{index-Z4-RtZcs.js → index-BfF5G4Cw.js} +1 -1
  69. package/ui/dist/assets/{index-DeI8lKRR.js → index-C8N375c2.js} +1 -1
  70. package/ui/dist/assets/index-CuxnqVVz.css +1 -0
  71. package/ui/dist/assets/{index-Ca3vk7Gq.js → index-CzMM3QOk.js} +1 -1
  72. package/ui/dist/assets/{index--JkIxVXb.js → index-lJlNPFVJ.js} +3 -3
  73. package/ui/dist/assets/{index-a4Fxq0Hb.js → index-nS3EErDg.js} +1 -1
  74. package/ui/dist/assets/{layers-DFeLExSa.js → layers-jFqVrWMD.js} +1 -1
  75. package/ui/dist/assets/{layout-dashboard-WmgjMhWF.js → layout-dashboard-CcKt1hXw.js} +1 -1
  76. package/ui/dist/assets/{lightbulb-Bo8hEr7B.js → lightbulb-Jhp7FvbU.js} +1 -1
  77. package/ui/dist/assets/{link-2-YqrpQXBH.js → link-2-DdO7ostF.js} +1 -1
  78. package/ui/dist/assets/{markdown-renderer-Croje6Xe.js → markdown-renderer-n1ToC4XQ.js} +1 -1
  79. package/ui/dist/assets/{message-square-CD0H5hot.js → message-square-CBgH65X7.js} +1 -1
  80. package/ui/dist/assets/{pencil-DpFnj5dn.js → pencil-CYXCEPQh.js} +1 -1
  81. package/ui/dist/assets/{play-DVgea_jT.js → play-d1ONaH0-.js} +1 -1
  82. package/ui/dist/assets/{popover-JXecfWG5.js → popover-CrmZgoWu.js} +1 -1
  83. package/ui/dist/assets/{progress-C1ghf1Fu.js → progress-uv4SPkL5.js} +1 -1
  84. package/ui/dist/assets/{rocket-BFxPYGx9.js → rocket-DhvUetsk.js} +1 -1
  85. package/ui/dist/assets/{select-MADP8m6Q.js → select-CeQ8AHGy.js} +1 -1
  86. package/ui/dist/assets/{send-eYnW_7n-.js → send-P0r5D7td.js} +1 -1
  87. package/ui/dist/assets/{server-CPMaysH8.js → server-CVHTZB72.js} +1 -1
  88. package/ui/dist/assets/{settings-2-scXUOuE_.js → settings-2-ocj5uHGx.js} +1 -1
  89. package/ui/dist/assets/{sheet-r6NSOxi-.js → sheet-DuQExSho.js} +1 -1
  90. package/ui/dist/assets/{shield-check-PEr7nmVw.js → shield-check-DfVdE34l.js} +1 -1
  91. package/ui/dist/assets/{shield-off-CLtXio62.js → shield-off-8l0J6R-8.js} +1 -1
  92. package/ui/dist/assets/{skeleton-C9oEzNlU.js → skeleton-TFiFJ3nB.js} +1 -1
  93. package/ui/dist/assets/{smartphone-DusFfY0U.js → smartphone-77_g3SQn.js} +1 -1
  94. package/ui/dist/assets/{square-e1yxB2eR.js → square-Ckzsr3Rn.js} +1 -1
  95. package/ui/dist/assets/{switch-tNs0n-kz.js → switch-CAePkd6k.js} +1 -1
  96. package/ui/dist/assets/{table-CXxtLicg.js → table-ZjAZ7hkt.js} +1 -1
  97. package/ui/dist/assets/{tag-tAwMmQ9G.js → tag-C35mgoEv.js} +1 -1
  98. package/ui/dist/assets/{textarea-BjiEeIWh.js → textarea-DsVPnSgR.js} +1 -1
  99. package/ui/dist/assets/{timer-Vel1N3RP.js → timer-DHJBS2w1.js} +1 -1
  100. package/ui/dist/assets/{tooltip-ZMwtfr1J.js → tooltip-BYmQ331W.js} +1 -1
  101. package/ui/dist/assets/{trash-2-eM-CNwsZ.js → trash-2-keO5tKPE.js} +1 -1
  102. package/ui/dist/assets/{trending-up-BGafmjRo.js → trending-up-BBv8KbrY.js} +1 -1
  103. package/ui/dist/assets/{wand-sparkles-DPvcd9Pi.js → wand-sparkles-BusQ52ZK.js} +1 -1
  104. package/ui/dist/assets/{wrench-B8s3zYVV.js → wrench-02YaOSiK.js} +1 -1
  105. package/ui/dist/index.html +2 -2
  106. package/dist/chat/auto-reply.d.ts +0 -90
  107. package/dist/chat/auto-reply.js +0 -272
  108. package/dist/chat/execution/pty.d.ts +0 -92
  109. package/dist/chat/execution/pty.js +0 -285
  110. package/dist/chat/execution/tools/glinr-ops.d.ts +0 -202
  111. package/dist/chat/execution/tools/glinr-ops.js +0 -694
  112. package/dist/cli/commands/browser.d.ts +0 -3
  113. package/dist/cli/commands/browser.js +0 -138
  114. package/dist/cli/commands/canvas.d.ts +0 -3
  115. package/dist/cli/commands/canvas.js +0 -155
  116. package/dist/cli/commands/nodes.d.ts +0 -3
  117. package/dist/cli/commands/nodes.js +0 -193
  118. package/dist/diagnostics/exporters.d.ts +0 -21
  119. package/dist/diagnostics/exporters.js +0 -138
  120. package/dist/diagnostics/index.d.ts +0 -10
  121. package/dist/diagnostics/index.js +0 -9
  122. package/dist/diagnostics/middleware.d.ts +0 -12
  123. package/dist/diagnostics/middleware.js +0 -58
  124. package/dist/diagnostics/tracer.d.ts +0 -133
  125. package/dist/diagnostics/tracer.js +0 -257
  126. package/dist/discovery/index.d.ts +0 -8
  127. package/dist/discovery/index.js +0 -7
  128. package/dist/discovery/mdns.d.ts +0 -40
  129. package/dist/discovery/mdns.js +0 -249
  130. package/dist/plugins/registry.d.ts +0 -122
  131. package/dist/plugins/registry.js +0 -352
  132. package/dist/plugins/sandbox.d.ts +0 -77
  133. package/dist/plugins/sandbox.js +0 -287
  134. package/dist/plugins/search/brave.d.ts +0 -9
  135. package/dist/plugins/search/brave.js +0 -157
  136. package/dist/plugins/search/duckduckgo.d.ts +0 -9
  137. package/dist/plugins/search/duckduckgo.js +0 -171
  138. package/dist/plugins/search/index.d.ts +0 -13
  139. package/dist/plugins/search/index.js +0 -23
  140. package/dist/plugins/search/searxng.d.ts +0 -9
  141. package/dist/plugins/search/searxng.js +0 -170
  142. package/dist/plugins/search/serper.d.ts +0 -9
  143. package/dist/plugins/search/serper.js +0 -135
  144. package/dist/plugins/search/tavily.d.ts +0 -9
  145. package/dist/plugins/search/tavily.js +0 -146
  146. package/dist/providers/adapters/anthropic.d.ts +0 -26
  147. package/dist/providers/adapters/anthropic.js +0 -306
  148. package/dist/providers/adapters/base.d.ts +0 -53
  149. package/dist/providers/adapters/base.js +0 -99
  150. package/dist/providers/adapters/ollama.d.ts +0 -30
  151. package/dist/providers/adapters/ollama.js +0 -292
  152. package/dist/utils/ai-cache.d.ts +0 -72
  153. package/dist/utils/ai-cache.js +0 -204
  154. package/dist/utils/file-lock.d.ts +0 -85
  155. package/dist/utils/file-lock.js +0 -204
  156. package/ui/dist/assets/index-WclMPci1.css +0 -1
@@ -1,352 +0,0 @@
1
- /**
2
- * profClaw Plugin Registry
3
- *
4
- * Manages plugin registration, instantiation, and health monitoring.
5
- */
6
- // ============================================================================
7
- // Search Provider Registry
8
- // ============================================================================
9
- class SearchProviderRegistry {
10
- definitions = new Map();
11
- instances = new Map();
12
- configs = new Map();
13
- healthCache = new Map();
14
- HEALTH_CACHE_TTL = 60_000; // 1 minute
15
- /**
16
- * Register a search provider plugin
17
- */
18
- register(definition) {
19
- this.definitions.set(definition.metadata.id, definition);
20
- console.log(`[Plugins] Registered search provider: ${definition.metadata.name}`);
21
- }
22
- /**
23
- * Unregister a search provider
24
- */
25
- unregister(pluginId) {
26
- this.definitions.delete(pluginId);
27
- // Remove any instances using this plugin
28
- for (const [configId, config] of this.configs) {
29
- if (config.pluginId === pluginId) {
30
- this.instances.delete(configId);
31
- this.configs.delete(configId);
32
- }
33
- }
34
- }
35
- /**
36
- * Create a provider instance from config
37
- */
38
- create(config) {
39
- const definition = this.definitions.get(config.pluginId);
40
- if (!definition) {
41
- throw new Error(`Unknown search provider plugin: ${config.pluginId}`);
42
- }
43
- const instance = definition.factory(config);
44
- this.instances.set(config.id, instance);
45
- this.configs.set(config.id, config);
46
- return instance;
47
- }
48
- /**
49
- * Get provider by config ID
50
- */
51
- get(configId) {
52
- return this.instances.get(configId);
53
- }
54
- /**
55
- * Get all active (enabled) providers
56
- */
57
- getActive() {
58
- const active = [];
59
- for (const [configId, config] of this.configs) {
60
- if (config.enabled) {
61
- const instance = this.instances.get(configId);
62
- if (instance)
63
- active.push(instance);
64
- }
65
- }
66
- // Sort by priority (higher first)
67
- return active.sort((a, b) => {
68
- const configA = this.getConfigByInstance(a);
69
- const configB = this.getConfigByInstance(b);
70
- return (configB?.priority || 0) - (configA?.priority || 0);
71
- });
72
- }
73
- /**
74
- * Get primary (highest priority enabled) provider
75
- */
76
- getPrimary() {
77
- const active = this.getActive();
78
- return active[0];
79
- }
80
- /**
81
- * List all registered plugin IDs
82
- */
83
- listRegistered() {
84
- return Array.from(this.definitions.keys());
85
- }
86
- /**
87
- * Get plugin metadata
88
- */
89
- getMetadata(pluginId) {
90
- return this.definitions.get(pluginId)?.metadata;
91
- }
92
- /**
93
- * Get all plugin metadata
94
- */
95
- getAllMetadata() {
96
- return Array.from(this.definitions.values()).map((d) => d.metadata);
97
- }
98
- /**
99
- * Get settings schema for a plugin
100
- */
101
- getSettingsSchema(pluginId) {
102
- return this.definitions.get(pluginId)?.settingsSchema;
103
- }
104
- /**
105
- * Get config by instance
106
- */
107
- getConfigByInstance(instance) {
108
- for (const [configId, inst] of this.instances) {
109
- if (inst === instance) {
110
- return this.configs.get(configId);
111
- }
112
- }
113
- return undefined;
114
- }
115
- /**
116
- * Get all configs
117
- */
118
- getAllConfigs() {
119
- return Array.from(this.configs.values());
120
- }
121
- /**
122
- * Update config
123
- */
124
- updateConfig(configId, updates) {
125
- const config = this.configs.get(configId);
126
- if (config) {
127
- const newConfig = { ...config, ...updates };
128
- this.configs.set(configId, newConfig);
129
- // Recreate instance with new config
130
- const definition = this.definitions.get(config.pluginId);
131
- if (definition) {
132
- const instance = definition.factory(newConfig);
133
- this.instances.set(configId, instance);
134
- }
135
- }
136
- }
137
- /**
138
- * Delete config and instance
139
- */
140
- deleteConfig(configId) {
141
- this.instances.delete(configId);
142
- this.configs.delete(configId);
143
- this.healthCache.delete(configId);
144
- }
145
- /**
146
- * Get health status (cached)
147
- */
148
- async getHealth(configId) {
149
- const cached = this.healthCache.get(configId);
150
- const now = Date.now();
151
- if (cached && now - cached.timestamp < this.HEALTH_CACHE_TTL) {
152
- return cached.health;
153
- }
154
- const instance = this.instances.get(configId);
155
- if (!instance) {
156
- return {
157
- healthy: false,
158
- lastCheck: new Date(),
159
- errorMessage: 'Provider not initialized',
160
- };
161
- }
162
- try {
163
- const health = await instance.healthCheck();
164
- this.healthCache.set(configId, { health, timestamp: now });
165
- return health;
166
- }
167
- catch (error) {
168
- const health = {
169
- healthy: false,
170
- lastCheck: new Date(),
171
- errorMessage: error instanceof Error ? error.message : 'Health check failed',
172
- };
173
- this.healthCache.set(configId, { health, timestamp: now });
174
- return health;
175
- }
176
- }
177
- /**
178
- * Search with automatic fallback
179
- */
180
- async search(query, options, preferredProvider) {
181
- const providers = this.getActive();
182
- if (providers.length === 0) {
183
- throw new Error('No search providers available');
184
- }
185
- // Try preferred provider first
186
- if (preferredProvider) {
187
- const preferred = this.get(preferredProvider);
188
- if (preferred) {
189
- try {
190
- return await preferred.search(query, options);
191
- }
192
- catch (error) {
193
- console.warn(`[Plugins] Preferred provider ${preferredProvider} failed, falling back:`, error);
194
- }
195
- }
196
- }
197
- // Try providers in priority order
198
- for (const provider of providers) {
199
- try {
200
- const isAvailable = await provider.isAvailable();
201
- if (!isAvailable)
202
- continue;
203
- return await provider.search(query, options);
204
- }
205
- catch (error) {
206
- console.warn(`[Plugins] Provider ${provider.metadata.id} failed:`, error);
207
- continue;
208
- }
209
- }
210
- throw new Error('All search providers failed');
211
- }
212
- }
213
- // ============================================================================
214
- // Tool Provider Registry
215
- // ============================================================================
216
- class ToolProviderRegistry {
217
- definitions = new Map();
218
- instances = new Map();
219
- configs = new Map();
220
- register(definition) {
221
- this.definitions.set(definition.metadata.id, definition);
222
- console.log(`[Plugins] Registered tool provider: ${definition.metadata.name}`);
223
- }
224
- unregister(pluginId) {
225
- this.definitions.delete(pluginId);
226
- for (const [configId, config] of this.configs) {
227
- if (config.pluginId === pluginId) {
228
- this.instances.delete(configId);
229
- this.configs.delete(configId);
230
- }
231
- }
232
- }
233
- create(config) {
234
- const definition = this.definitions.get(config.pluginId);
235
- if (!definition) {
236
- throw new Error(`Unknown tool provider plugin: ${config.pluginId}`);
237
- }
238
- const instance = definition.factory(config);
239
- this.instances.set(config.id, instance);
240
- this.configs.set(config.id, config);
241
- return instance;
242
- }
243
- get(configId) {
244
- return this.instances.get(configId);
245
- }
246
- getActive() {
247
- const active = [];
248
- for (const [configId, config] of this.configs) {
249
- if (config.enabled) {
250
- const instance = this.instances.get(configId);
251
- if (instance)
252
- active.push(instance);
253
- }
254
- }
255
- return active;
256
- }
257
- listRegistered() {
258
- return Array.from(this.definitions.keys());
259
- }
260
- getMetadata(pluginId) {
261
- return this.definitions.get(pluginId)?.metadata;
262
- }
263
- getAllMetadata() {
264
- return Array.from(this.definitions.values()).map((d) => d.metadata);
265
- }
266
- getSettingsSchema(pluginId) {
267
- return this.definitions.get(pluginId)?.settingsSchema;
268
- }
269
- getAllConfigs() {
270
- return Array.from(this.configs.values());
271
- }
272
- updateConfig(configId, updates) {
273
- const config = this.configs.get(configId);
274
- if (config) {
275
- const newConfig = { ...config, ...updates };
276
- this.configs.set(configId, newConfig);
277
- const definition = this.definitions.get(config.pluginId);
278
- if (definition) {
279
- const instance = definition.factory(newConfig);
280
- this.instances.set(configId, instance);
281
- }
282
- }
283
- }
284
- deleteConfig(configId) {
285
- this.instances.delete(configId);
286
- this.configs.delete(configId);
287
- }
288
- /**
289
- * Get all available tools across all providers
290
- */
291
- getAllTools() {
292
- const tools = [];
293
- for (const provider of this.getActive()) {
294
- for (const tool of provider.tools) {
295
- tools.push({ provider: provider.metadata.id, tool });
296
- }
297
- }
298
- return tools;
299
- }
300
- /**
301
- * Execute a tool by name
302
- */
303
- async execute(toolName, params) {
304
- for (const provider of this.getActive()) {
305
- const tool = provider.tools.find((t) => t.name === toolName);
306
- if (tool) {
307
- return provider.execute(toolName, params);
308
- }
309
- }
310
- throw new Error(`Tool not found: ${toolName}`);
311
- }
312
- }
313
- // ============================================================================
314
- // Global Plugin Manager
315
- // ============================================================================
316
- class PluginManager {
317
- search = new SearchProviderRegistry();
318
- tools = new ToolProviderRegistry();
319
- /**
320
- * Initialize built-in plugins
321
- */
322
- async initialize() {
323
- // Built-in plugins will be registered here
324
- // Import and register each plugin definition
325
- console.log('[Plugins] Plugin manager initialized');
326
- }
327
- /**
328
- * Get all plugin metadata across categories
329
- */
330
- getAllPlugins() {
331
- const plugins = [];
332
- for (const meta of this.search.getAllMetadata()) {
333
- plugins.push({ ...meta, category: 'search' });
334
- }
335
- for (const meta of this.tools.getAllMetadata()) {
336
- plugins.push({ ...meta, category: 'tool' });
337
- }
338
- return plugins;
339
- }
340
- }
341
- // ============================================================================
342
- // Singleton Instance
343
- // ============================================================================
344
- let manager = null;
345
- export function getPluginManager() {
346
- if (!manager) {
347
- manager = new PluginManager();
348
- }
349
- return manager;
350
- }
351
- export { SearchProviderRegistry, ToolProviderRegistry, PluginManager };
352
- //# sourceMappingURL=registry.js.map
@@ -1,77 +0,0 @@
1
- /**
2
- * Plugin Sandbox
3
- *
4
- * Runs plugins in isolated Node.js Worker threads with restricted access.
5
- * Plugins cannot access the filesystem, network, or process directly
6
- * unless explicitly granted permissions.
7
- */
8
- import { EventEmitter } from 'node:events';
9
- export type PluginPermission = 'fs:read' | 'fs:write' | 'net:fetch' | 'env:read' | 'exec' | 'tools';
10
- export interface SandboxConfig {
11
- pluginId: string;
12
- pluginPath: string;
13
- permissions: PluginPermission[];
14
- timeout: number;
15
- memoryLimit: number;
16
- }
17
- export interface SandboxMessage {
18
- type: 'init' | 'call' | 'result' | 'error' | 'log' | 'register-tool';
19
- id?: string;
20
- payload?: unknown;
21
- }
22
- export declare class PluginSandbox extends EventEmitter {
23
- private worker;
24
- private config;
25
- private pendingCalls;
26
- private callCounter;
27
- private healthy;
28
- constructor(config: SandboxConfig);
29
- /**
30
- * Start the sandbox worker
31
- */
32
- start(): Promise<void>;
33
- /**
34
- * Call a plugin method
35
- */
36
- call(method: string, args?: unknown[]): Promise<unknown>;
37
- /**
38
- * Stop the sandbox
39
- */
40
- stop(): Promise<void>;
41
- /**
42
- * Check if sandbox is healthy
43
- */
44
- isHealthy(): boolean;
45
- private handleMessage;
46
- private handleError;
47
- private handleExit;
48
- }
49
- declare class SandboxManager {
50
- private sandboxes;
51
- /**
52
- * Create and start a sandbox for a plugin
53
- */
54
- create(config: SandboxConfig): Promise<PluginSandbox>;
55
- /**
56
- * Get a running sandbox
57
- */
58
- get(pluginId: string): PluginSandbox | undefined;
59
- /**
60
- * Stop a sandbox
61
- */
62
- stop(pluginId: string): Promise<void>;
63
- /**
64
- * Stop all sandboxes
65
- */
66
- stopAll(): Promise<void>;
67
- /**
68
- * List running sandboxes
69
- */
70
- list(): Array<{
71
- pluginId: string;
72
- healthy: boolean;
73
- }>;
74
- }
75
- export declare function getSandboxManager(): SandboxManager;
76
- export { SandboxManager };
77
- //# sourceMappingURL=sandbox.d.ts.map
@@ -1,287 +0,0 @@
1
- /**
2
- * Plugin Sandbox
3
- *
4
- * Runs plugins in isolated Node.js Worker threads with restricted access.
5
- * Plugins cannot access the filesystem, network, or process directly
6
- * unless explicitly granted permissions.
7
- */
8
- import { Worker, isMainThread, parentPort, workerData } from 'node:worker_threads';
9
- import { EventEmitter } from 'node:events';
10
- // =============================================================================
11
- // Sandbox Runner (main thread)
12
- // =============================================================================
13
- export class PluginSandbox extends EventEmitter {
14
- worker = null;
15
- config;
16
- pendingCalls = new Map();
17
- callCounter = 0;
18
- healthy = false;
19
- constructor(config) {
20
- super();
21
- this.config = config;
22
- }
23
- /**
24
- * Start the sandbox worker
25
- */
26
- async start() {
27
- if (this.worker) {
28
- throw new Error(`Sandbox for ${this.config.pluginId} is already running`);
29
- }
30
- this.worker = new Worker(new URL(import.meta.url), {
31
- workerData: {
32
- pluginPath: this.config.pluginPath,
33
- permissions: this.config.permissions,
34
- pluginId: this.config.pluginId,
35
- },
36
- resourceLimits: {
37
- maxOldGenerationSizeMb: this.config.memoryLimit,
38
- maxYoungGenerationSizeMb: Math.ceil(this.config.memoryLimit / 4),
39
- },
40
- });
41
- this.worker.on('message', (msg) => this.handleMessage(msg));
42
- this.worker.on('error', (err) => this.handleError(err));
43
- this.worker.on('exit', (code) => this.handleExit(code));
44
- // Wait for init confirmation
45
- await new Promise((resolve, reject) => {
46
- const timer = setTimeout(() => reject(new Error('Sandbox init timeout')), this.config.timeout);
47
- const handler = (msg) => {
48
- if (msg.type === 'init') {
49
- clearTimeout(timer);
50
- this.healthy = true;
51
- this.worker?.removeListener('message', handler);
52
- resolve();
53
- }
54
- };
55
- this.worker?.on('message', handler);
56
- });
57
- }
58
- /**
59
- * Call a plugin method
60
- */
61
- async call(method, args = []) {
62
- if (!this.worker || !this.healthy) {
63
- throw new Error(`Sandbox for ${this.config.pluginId} is not running`);
64
- }
65
- const id = String(++this.callCounter);
66
- return new Promise((resolve, reject) => {
67
- const timer = setTimeout(() => {
68
- this.pendingCalls.delete(id);
69
- reject(new Error(`Plugin call ${method} timed out after ${this.config.timeout}ms`));
70
- }, this.config.timeout);
71
- this.pendingCalls.set(id, { resolve, reject, timer });
72
- this.worker?.postMessage({
73
- type: 'call',
74
- id,
75
- payload: { method, args },
76
- });
77
- });
78
- }
79
- /**
80
- * Stop the sandbox
81
- */
82
- async stop() {
83
- if (!this.worker)
84
- return;
85
- this.healthy = false;
86
- // Reject all pending calls
87
- for (const [id, pending] of this.pendingCalls) {
88
- clearTimeout(pending.timer);
89
- pending.reject(new Error('Sandbox stopped'));
90
- this.pendingCalls.delete(id);
91
- }
92
- await this.worker.terminate();
93
- this.worker = null;
94
- }
95
- /**
96
- * Check if sandbox is healthy
97
- */
98
- isHealthy() {
99
- return this.healthy;
100
- }
101
- // ===========================================================================
102
- // Private
103
- // ===========================================================================
104
- handleMessage(msg) {
105
- switch (msg.type) {
106
- case 'result': {
107
- const pending = this.pendingCalls.get(msg.id);
108
- if (pending) {
109
- clearTimeout(pending.timer);
110
- this.pendingCalls.delete(msg.id);
111
- pending.resolve(msg.payload);
112
- }
113
- break;
114
- }
115
- case 'error': {
116
- const pendingErr = this.pendingCalls.get(msg.id);
117
- if (pendingErr) {
118
- clearTimeout(pendingErr.timer);
119
- this.pendingCalls.delete(msg.id);
120
- pendingErr.reject(new Error(String(msg.payload)));
121
- }
122
- break;
123
- }
124
- case 'log': {
125
- this.emit('log', msg.payload);
126
- break;
127
- }
128
- case 'register-tool': {
129
- this.emit('register-tool', msg.payload);
130
- break;
131
- }
132
- }
133
- }
134
- handleError(err) {
135
- this.healthy = false;
136
- this.emit('error', err);
137
- }
138
- handleExit(code) {
139
- this.healthy = false;
140
- this.worker = null;
141
- // Reject all pending calls
142
- for (const [id, pending] of this.pendingCalls) {
143
- clearTimeout(pending.timer);
144
- pending.reject(new Error(`Sandbox exited with code ${code}`));
145
- this.pendingCalls.delete(id);
146
- }
147
- this.emit('exit', code);
148
- }
149
- }
150
- // =============================================================================
151
- // Sandbox Manager
152
- // =============================================================================
153
- class SandboxManager {
154
- sandboxes = new Map();
155
- /**
156
- * Create and start a sandbox for a plugin
157
- */
158
- async create(config) {
159
- if (this.sandboxes.has(config.pluginId)) {
160
- throw new Error(`Sandbox already exists for ${config.pluginId}`);
161
- }
162
- const sandbox = new PluginSandbox(config);
163
- await sandbox.start();
164
- this.sandboxes.set(config.pluginId, sandbox);
165
- sandbox.on('exit', () => {
166
- this.sandboxes.delete(config.pluginId);
167
- });
168
- return sandbox;
169
- }
170
- /**
171
- * Get a running sandbox
172
- */
173
- get(pluginId) {
174
- return this.sandboxes.get(pluginId);
175
- }
176
- /**
177
- * Stop a sandbox
178
- */
179
- async stop(pluginId) {
180
- const sandbox = this.sandboxes.get(pluginId);
181
- if (sandbox) {
182
- await sandbox.stop();
183
- this.sandboxes.delete(pluginId);
184
- }
185
- }
186
- /**
187
- * Stop all sandboxes
188
- */
189
- async stopAll() {
190
- const promises = Array.from(this.sandboxes.values()).map((s) => s.stop());
191
- await Promise.allSettled(promises);
192
- this.sandboxes.clear();
193
- }
194
- /**
195
- * List running sandboxes
196
- */
197
- list() {
198
- return Array.from(this.sandboxes.entries()).map(([id, sb]) => ({
199
- pluginId: id,
200
- healthy: sb.isHealthy(),
201
- }));
202
- }
203
- }
204
- // =============================================================================
205
- // Worker Thread Entry (runs inside sandbox)
206
- // =============================================================================
207
- if (!isMainThread && parentPort && workerData) {
208
- const { pluginPath, permissions, pluginId } = workerData;
209
- // Create restricted API surface
210
- const sandboxApi = {
211
- log: (...args) => {
212
- parentPort?.postMessage({
213
- type: 'log',
214
- payload: { pluginId, level: 'info', args: args.map(String) },
215
- });
216
- },
217
- registerTool: (tool) => {
218
- if (!permissions.includes('tools')) {
219
- throw new Error('Plugin does not have "tools" permission');
220
- }
221
- parentPort?.postMessage({
222
- type: 'register-tool',
223
- payload: tool,
224
- });
225
- },
226
- fetch: permissions.includes('net:fetch')
227
- ? globalThis.fetch
228
- : () => { throw new Error('Plugin does not have "net:fetch" permission'); },
229
- };
230
- // Load plugin
231
- (async () => {
232
- try {
233
- const pluginModule = await import(pluginPath);
234
- const plugin = pluginModule.default || pluginModule;
235
- // Call onLoad if present
236
- if (typeof plugin.onLoad === 'function') {
237
- await plugin.onLoad(sandboxApi);
238
- }
239
- // Notify main thread we're ready
240
- parentPort?.postMessage({ type: 'init' });
241
- // Handle calls from main thread
242
- parentPort?.on('message', async (msg) => {
243
- if (msg.type !== 'call' || !msg.id)
244
- return;
245
- const { method, args } = msg.payload;
246
- try {
247
- const fn = plugin[method];
248
- if (typeof fn !== 'function') {
249
- throw new Error(`Plugin method ${method} not found`);
250
- }
251
- const result = await fn.apply(plugin, args);
252
- parentPort?.postMessage({
253
- type: 'result',
254
- id: msg.id,
255
- payload: result,
256
- });
257
- }
258
- catch (error) {
259
- parentPort?.postMessage({
260
- type: 'error',
261
- id: msg.id,
262
- payload: error instanceof Error ? error.message : String(error),
263
- });
264
- }
265
- });
266
- }
267
- catch (error) {
268
- parentPort?.postMessage({
269
- type: 'error',
270
- payload: `Failed to load plugin: ${error instanceof Error ? error.message : String(error)}`,
271
- });
272
- process.exit(1);
273
- }
274
- })();
275
- }
276
- // =============================================================================
277
- // Singleton
278
- // =============================================================================
279
- let manager = null;
280
- export function getSandboxManager() {
281
- if (!manager) {
282
- manager = new SandboxManager();
283
- }
284
- return manager;
285
- }
286
- export { SandboxManager };
287
- //# sourceMappingURL=sandbox.js.map