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.
- package/CHANGELOG.md +21 -38
- package/CONTRIBUTING.md +3 -5
- package/README.md +128 -63
- package/dist/chat/execution/tools/index.d.ts +1 -1
- package/dist/chat/execution/tools/index.js +41 -2
- package/dist/chat/providers/slack/index.d.ts +2 -2
- package/dist/cli/commands/models.js +39 -26
- package/dist/cli/commands/onboard.js +64 -79
- package/dist/cli/commands/setup.js +293 -90
- package/dist/cli/index.js +0 -6
- package/dist/cli/providers.d.ts +15 -0
- package/dist/cli/providers.js +41 -0
- package/dist/core/deployment.js +2 -0
- package/dist/providers/ai-sdk.js +26 -6
- package/dist/routes/channels.d.ts +12 -0
- package/dist/routes/channels.js +166 -0
- package/dist/server/route-loader.js +1 -0
- package/dist/server.js +115 -109
- package/package.json +1 -1
- package/skills/git-workflow/SKILL.md +3 -3
- package/ui/dist/assets/{ActivityView-DIPQSJ_d.js → ActivityView-BeshZXmE.js} +1 -1
- package/ui/dist/assets/{AgentList-CqyaYrcq.js → AgentList-QVHeldPi.js} +1 -1
- package/ui/dist/assets/{AnalyticsDashboard-C-mjuGHT.js → AnalyticsDashboard-C9R97dXE.js} +1 -1
- package/ui/dist/assets/{AreaChart-CfYWmbtr.js → AreaChart-B73gaiVQ.js} +1 -1
- package/ui/dist/assets/{CartesianChart-BaQ3It0c.js → CartesianChart-CXYL2R-A.js} +1 -1
- package/ui/dist/assets/{ChatView-DxxQy6pl.js → ChatView-qjZErlrp.js} +1 -1
- package/ui/dist/assets/{CostsDashboard-CDBBcGkg.js → CostsDashboard-O4DCLy1i.js} +1 -1
- package/ui/dist/assets/{EstimateSelect-CDjf5qKl.js → EstimateSelect-1hQf4Osk.js} +1 -1
- package/ui/dist/assets/{FloatingChatbot-CZHjvJIe.js → FloatingChatbot-BZBzrJxd.js} +1 -1
- package/ui/dist/assets/{InviteCodeManagement-DTm-IPTm.js → InviteCodeManagement-LEoGqYeA.js} +1 -1
- package/ui/dist/assets/{ProjectDetail-DlYUcOss.js → ProjectDetail--gPfvATB.js} +1 -1
- package/ui/dist/assets/{ProjectIcon-BMRpnM04.js → ProjectIcon-Chd_ofsw.js} +1 -1
- package/ui/dist/assets/{ProjectList-D85TN0i0.js → ProjectList-BvUfVB6c.js} +1 -1
- package/ui/dist/assets/{Settings-CgPqzUvj.js → Settings-1kaf7VHE.js} +1 -1
- package/ui/dist/assets/{StatusIndicator-yig0uZEA.js → StatusIndicator-pRfkNcdV.js} +1 -1
- package/ui/dist/assets/{SummaryDetail-CwLAfHgJ.js → SummaryDetail-DV3AmONk.js} +1 -1
- package/ui/dist/assets/{SummaryList-BvS5Idnu.js → SummaryList-B6kXiTxL.js} +1 -1
- package/ui/dist/assets/{TaskDetail-zarC1fOt.js → TaskDetail-CV6CzbOS.js} +1 -1
- package/ui/dist/assets/{TaskList-CyJq3ANE.js → TaskList-DL7brQKd.js} +1 -1
- package/ui/dist/assets/{TicketBoard-BlWr3-iH.js → TicketBoard-CrkkFj7C.js} +1 -1
- package/ui/dist/assets/{TicketDetail-DmqWKj2W.js → TicketDetail-hnnYclpD.js} +1 -1
- package/ui/dist/assets/{TicketList-Scj4pMWa.js → TicketList-CsDAyQCL.js} +1 -1
- package/ui/dist/assets/{UserManagement-BH7uG7dw.js → UserManagement-BGFQyTSr.js} +1 -1
- package/ui/dist/assets/{ViewSwitcher-3HzZUdWn.js → ViewSwitcher-CnL0OqA8.js} +1 -1
- package/ui/dist/assets/{alert-dialog-DWPb2IfQ.js → alert-dialog-SKM6Gjz4.js} +1 -1
- package/ui/dist/assets/{archive-CGck7gxR.js → archive-BsLa7brF.js} +1 -1
- package/ui/dist/assets/{badge-DEmc3Z_l.js → badge-CVHH1a-v.js} +1 -1
- package/ui/dist/assets/{brain-CfFdLVqb.js → brain-6o_RHVpe.js} +1 -1
- package/ui/dist/assets/{bug-DqSGPUUE.js → bug-CmZI7jqM.js} +1 -1
- package/ui/dist/assets/{calendar-BuZ4zbPW.js → calendar-Bf0t2B82.js} +1 -1
- package/ui/dist/assets/{chevron-up-DcJ4LL_N.js → chevron-up-CoUsOvZj.js} +1 -1
- package/ui/dist/assets/{circle-x-C78PNZjF.js → circle-x-Dgw11LgT.js} +1 -1
- package/ui/dist/assets/{constants-DhDjZe4P.js → constants-Q5Zivl-a.js} +1 -1
- package/ui/dist/assets/{cpu-Ck6AoG8c.js → cpu-DiPMQICV.js} +1 -1
- package/ui/dist/assets/{database-CA2w8Lvt.js → database-BwTfupDi.js} +1 -1
- package/ui/dist/assets/{dialog-BOdGWhgE.js → dialog-BUqN9Psj.js} +1 -1
- package/ui/dist/assets/{ellipsis-FhHKRbfl.js → ellipsis-UJx4Xnf6.js} +1 -1
- package/ui/dist/assets/{ellipsis-vertical-CO0UqE4-.js → ellipsis-vertical-DoULYEKn.js} +1 -1
- package/ui/dist/assets/{file-code-ChnhYYj1.js → file-code-B2UrJLwi.js} +1 -1
- package/ui/dist/assets/{folder-open-CHwA1-ve.js → folder-open-BJi577JH.js} +1 -1
- package/ui/dist/assets/{funnel-ByEjRFNB.js → funnel-PkaD_HSR.js} +1 -1
- package/ui/dist/assets/{git-branch-GTOPQgU4.js → git-branch-C_K30am0.js} +1 -1
- package/ui/dist/assets/{git-commit-horizontal-F5M84Kut.js → git-commit-horizontal-IT6ecxWQ.js} +1 -1
- package/ui/dist/assets/{globe-CQWfr7hT.js → globe-f-jjCa_g.js} +1 -1
- package/ui/dist/assets/{hash-nKC9gtLg.js → hash-DNEv8Elo.js} +1 -1
- package/ui/dist/assets/{history-DfFSA9xJ.js → history-BQSBo_1Q.js} +1 -1
- package/ui/dist/assets/{index-DHGvP9mp.js → index-BUmnwPQr.js} +1 -1
- package/ui/dist/assets/{index-Z4-RtZcs.js → index-BfF5G4Cw.js} +1 -1
- package/ui/dist/assets/{index-DeI8lKRR.js → index-C8N375c2.js} +1 -1
- package/ui/dist/assets/index-CuxnqVVz.css +1 -0
- package/ui/dist/assets/{index-Ca3vk7Gq.js → index-CzMM3QOk.js} +1 -1
- package/ui/dist/assets/{index--JkIxVXb.js → index-lJlNPFVJ.js} +3 -3
- package/ui/dist/assets/{index-a4Fxq0Hb.js → index-nS3EErDg.js} +1 -1
- package/ui/dist/assets/{layers-DFeLExSa.js → layers-jFqVrWMD.js} +1 -1
- package/ui/dist/assets/{layout-dashboard-WmgjMhWF.js → layout-dashboard-CcKt1hXw.js} +1 -1
- package/ui/dist/assets/{lightbulb-Bo8hEr7B.js → lightbulb-Jhp7FvbU.js} +1 -1
- package/ui/dist/assets/{link-2-YqrpQXBH.js → link-2-DdO7ostF.js} +1 -1
- package/ui/dist/assets/{markdown-renderer-Croje6Xe.js → markdown-renderer-n1ToC4XQ.js} +1 -1
- package/ui/dist/assets/{message-square-CD0H5hot.js → message-square-CBgH65X7.js} +1 -1
- package/ui/dist/assets/{pencil-DpFnj5dn.js → pencil-CYXCEPQh.js} +1 -1
- package/ui/dist/assets/{play-DVgea_jT.js → play-d1ONaH0-.js} +1 -1
- package/ui/dist/assets/{popover-JXecfWG5.js → popover-CrmZgoWu.js} +1 -1
- package/ui/dist/assets/{progress-C1ghf1Fu.js → progress-uv4SPkL5.js} +1 -1
- package/ui/dist/assets/{rocket-BFxPYGx9.js → rocket-DhvUetsk.js} +1 -1
- package/ui/dist/assets/{select-MADP8m6Q.js → select-CeQ8AHGy.js} +1 -1
- package/ui/dist/assets/{send-eYnW_7n-.js → send-P0r5D7td.js} +1 -1
- package/ui/dist/assets/{server-CPMaysH8.js → server-CVHTZB72.js} +1 -1
- package/ui/dist/assets/{settings-2-scXUOuE_.js → settings-2-ocj5uHGx.js} +1 -1
- package/ui/dist/assets/{sheet-r6NSOxi-.js → sheet-DuQExSho.js} +1 -1
- package/ui/dist/assets/{shield-check-PEr7nmVw.js → shield-check-DfVdE34l.js} +1 -1
- package/ui/dist/assets/{shield-off-CLtXio62.js → shield-off-8l0J6R-8.js} +1 -1
- package/ui/dist/assets/{skeleton-C9oEzNlU.js → skeleton-TFiFJ3nB.js} +1 -1
- package/ui/dist/assets/{smartphone-DusFfY0U.js → smartphone-77_g3SQn.js} +1 -1
- package/ui/dist/assets/{square-e1yxB2eR.js → square-Ckzsr3Rn.js} +1 -1
- package/ui/dist/assets/{switch-tNs0n-kz.js → switch-CAePkd6k.js} +1 -1
- package/ui/dist/assets/{table-CXxtLicg.js → table-ZjAZ7hkt.js} +1 -1
- package/ui/dist/assets/{tag-tAwMmQ9G.js → tag-C35mgoEv.js} +1 -1
- package/ui/dist/assets/{textarea-BjiEeIWh.js → textarea-DsVPnSgR.js} +1 -1
- package/ui/dist/assets/{timer-Vel1N3RP.js → timer-DHJBS2w1.js} +1 -1
- package/ui/dist/assets/{tooltip-ZMwtfr1J.js → tooltip-BYmQ331W.js} +1 -1
- package/ui/dist/assets/{trash-2-eM-CNwsZ.js → trash-2-keO5tKPE.js} +1 -1
- package/ui/dist/assets/{trending-up-BGafmjRo.js → trending-up-BBv8KbrY.js} +1 -1
- package/ui/dist/assets/{wand-sparkles-DPvcd9Pi.js → wand-sparkles-BusQ52ZK.js} +1 -1
- package/ui/dist/assets/{wrench-B8s3zYVV.js → wrench-02YaOSiK.js} +1 -1
- package/ui/dist/index.html +2 -2
- package/dist/chat/auto-reply.d.ts +0 -90
- package/dist/chat/auto-reply.js +0 -272
- package/dist/chat/execution/pty.d.ts +0 -92
- package/dist/chat/execution/pty.js +0 -285
- package/dist/chat/execution/tools/glinr-ops.d.ts +0 -202
- package/dist/chat/execution/tools/glinr-ops.js +0 -694
- package/dist/cli/commands/browser.d.ts +0 -3
- package/dist/cli/commands/browser.js +0 -138
- package/dist/cli/commands/canvas.d.ts +0 -3
- package/dist/cli/commands/canvas.js +0 -155
- package/dist/cli/commands/nodes.d.ts +0 -3
- package/dist/cli/commands/nodes.js +0 -193
- package/dist/diagnostics/exporters.d.ts +0 -21
- package/dist/diagnostics/exporters.js +0 -138
- package/dist/diagnostics/index.d.ts +0 -10
- package/dist/diagnostics/index.js +0 -9
- package/dist/diagnostics/middleware.d.ts +0 -12
- package/dist/diagnostics/middleware.js +0 -58
- package/dist/diagnostics/tracer.d.ts +0 -133
- package/dist/diagnostics/tracer.js +0 -257
- package/dist/discovery/index.d.ts +0 -8
- package/dist/discovery/index.js +0 -7
- package/dist/discovery/mdns.d.ts +0 -40
- package/dist/discovery/mdns.js +0 -249
- package/dist/plugins/registry.d.ts +0 -122
- package/dist/plugins/registry.js +0 -352
- package/dist/plugins/sandbox.d.ts +0 -77
- package/dist/plugins/sandbox.js +0 -287
- package/dist/plugins/search/brave.d.ts +0 -9
- package/dist/plugins/search/brave.js +0 -157
- package/dist/plugins/search/duckduckgo.d.ts +0 -9
- package/dist/plugins/search/duckduckgo.js +0 -171
- package/dist/plugins/search/index.d.ts +0 -13
- package/dist/plugins/search/index.js +0 -23
- package/dist/plugins/search/searxng.d.ts +0 -9
- package/dist/plugins/search/searxng.js +0 -170
- package/dist/plugins/search/serper.d.ts +0 -9
- package/dist/plugins/search/serper.js +0 -135
- package/dist/plugins/search/tavily.d.ts +0 -9
- package/dist/plugins/search/tavily.js +0 -146
- package/dist/providers/adapters/anthropic.d.ts +0 -26
- package/dist/providers/adapters/anthropic.js +0 -306
- package/dist/providers/adapters/base.d.ts +0 -53
- package/dist/providers/adapters/base.js +0 -99
- package/dist/providers/adapters/ollama.d.ts +0 -30
- package/dist/providers/adapters/ollama.js +0 -292
- package/dist/utils/ai-cache.d.ts +0 -72
- package/dist/utils/ai-cache.js +0 -204
- package/dist/utils/file-lock.d.ts +0 -85
- package/dist/utils/file-lock.js +0 -204
- package/ui/dist/assets/index-WclMPci1.css +0 -1
package/dist/plugins/registry.js
DELETED
|
@@ -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
|
package/dist/plugins/sandbox.js
DELETED
|
@@ -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
|