@enactprotocol/shared 1.2.13 → 2.0.1

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 (207) hide show
  1. package/README.md +44 -0
  2. package/dist/config.d.ts +164 -0
  3. package/dist/config.d.ts.map +1 -0
  4. package/dist/config.js +386 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/constants.d.ts +15 -5
  7. package/dist/constants.d.ts.map +1 -0
  8. package/dist/constants.js +24 -8
  9. package/dist/constants.js.map +1 -0
  10. package/dist/execution/command.d.ts +102 -0
  11. package/dist/execution/command.d.ts.map +1 -0
  12. package/dist/execution/command.js +262 -0
  13. package/dist/execution/command.js.map +1 -0
  14. package/dist/execution/index.d.ts +12 -0
  15. package/dist/execution/index.d.ts.map +1 -0
  16. package/dist/execution/index.js +17 -0
  17. package/dist/execution/index.js.map +1 -0
  18. package/dist/execution/runtime.d.ts +82 -0
  19. package/dist/execution/runtime.d.ts.map +1 -0
  20. package/dist/execution/runtime.js +273 -0
  21. package/dist/execution/runtime.js.map +1 -0
  22. package/dist/execution/types.d.ts +306 -0
  23. package/dist/execution/types.d.ts.map +1 -0
  24. package/dist/execution/types.js +14 -0
  25. package/dist/execution/types.js.map +1 -0
  26. package/dist/execution/validation.d.ts +43 -0
  27. package/dist/execution/validation.d.ts.map +1 -0
  28. package/dist/execution/validation.js +430 -0
  29. package/dist/execution/validation.js.map +1 -0
  30. package/dist/index.d.ts +21 -21
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +49 -25
  33. package/dist/index.js.map +1 -0
  34. package/dist/manifest/index.d.ts +7 -0
  35. package/dist/manifest/index.d.ts.map +1 -0
  36. package/dist/manifest/index.js +10 -0
  37. package/dist/manifest/index.js.map +1 -0
  38. package/dist/manifest/loader.d.ts +76 -0
  39. package/dist/manifest/loader.d.ts.map +1 -0
  40. package/dist/manifest/loader.js +146 -0
  41. package/dist/manifest/loader.js.map +1 -0
  42. package/dist/manifest/parser.d.ts +64 -0
  43. package/dist/manifest/parser.d.ts.map +1 -0
  44. package/dist/manifest/parser.js +135 -0
  45. package/dist/manifest/parser.js.map +1 -0
  46. package/dist/manifest/validator.d.ts +95 -0
  47. package/dist/manifest/validator.d.ts.map +1 -0
  48. package/dist/manifest/validator.js +258 -0
  49. package/dist/manifest/validator.js.map +1 -0
  50. package/dist/paths.d.ts +57 -0
  51. package/dist/paths.d.ts.map +1 -0
  52. package/dist/paths.js +93 -0
  53. package/dist/paths.js.map +1 -0
  54. package/dist/registry.d.ts +73 -0
  55. package/dist/registry.d.ts.map +1 -0
  56. package/dist/registry.js +147 -0
  57. package/dist/registry.js.map +1 -0
  58. package/dist/resolver.d.ts +89 -0
  59. package/dist/resolver.d.ts.map +1 -0
  60. package/dist/resolver.js +282 -0
  61. package/dist/resolver.js.map +1 -0
  62. package/dist/types/index.d.ts +6 -0
  63. package/dist/types/index.d.ts.map +1 -0
  64. package/dist/types/index.js +5 -0
  65. package/dist/types/index.js.map +1 -0
  66. package/dist/types/manifest.d.ts +201 -0
  67. package/dist/types/manifest.d.ts.map +1 -0
  68. package/dist/types/manifest.js +13 -0
  69. package/dist/types/manifest.js.map +1 -0
  70. package/dist/types.d.ts +5 -132
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/types.js +5 -3
  73. package/dist/types.js.map +1 -0
  74. package/dist/utils/fs.d.ts +105 -0
  75. package/dist/utils/fs.d.ts.map +1 -0
  76. package/dist/utils/fs.js +233 -0
  77. package/dist/utils/fs.js.map +1 -0
  78. package/dist/utils/logger.d.ts +102 -25
  79. package/dist/utils/logger.d.ts.map +1 -0
  80. package/dist/utils/logger.js +214 -57
  81. package/dist/utils/logger.js.map +1 -0
  82. package/dist/utils/version.d.ts +60 -2
  83. package/dist/utils/version.d.ts.map +1 -0
  84. package/dist/utils/version.js +255 -31
  85. package/dist/utils/version.js.map +1 -0
  86. package/package.json +16 -58
  87. package/src/config.ts +510 -0
  88. package/src/constants.ts +36 -0
  89. package/src/execution/command.ts +314 -0
  90. package/src/execution/index.ts +73 -0
  91. package/src/execution/runtime.ts +308 -0
  92. package/src/execution/types.ts +379 -0
  93. package/src/execution/validation.ts +508 -0
  94. package/src/index.ts +238 -30
  95. package/src/manifest/index.ts +36 -0
  96. package/src/manifest/loader.ts +187 -0
  97. package/src/manifest/parser.ts +173 -0
  98. package/src/manifest/validator.ts +309 -0
  99. package/src/paths.ts +108 -0
  100. package/src/registry.ts +219 -0
  101. package/src/resolver.ts +345 -0
  102. package/src/types/index.ts +30 -0
  103. package/src/types/manifest.ts +255 -0
  104. package/src/types.ts +5 -188
  105. package/src/utils/fs.ts +281 -0
  106. package/src/utils/logger.ts +270 -59
  107. package/src/utils/version.ts +304 -36
  108. package/tests/config.test.ts +515 -0
  109. package/tests/execution/command.test.ts +317 -0
  110. package/tests/execution/validation.test.ts +384 -0
  111. package/tests/fixtures/invalid-tool.yaml +4 -0
  112. package/tests/fixtures/valid-tool.md +62 -0
  113. package/tests/fixtures/valid-tool.yaml +40 -0
  114. package/tests/index.test.ts +8 -0
  115. package/tests/manifest/loader.test.ts +291 -0
  116. package/tests/manifest/parser.test.ts +345 -0
  117. package/tests/manifest/validator.test.ts +394 -0
  118. package/tests/manifest-types.test.ts +358 -0
  119. package/tests/paths.test.ts +153 -0
  120. package/tests/registry.test.ts +231 -0
  121. package/tests/resolver.test.ts +272 -0
  122. package/tests/utils/fs.test.ts +388 -0
  123. package/tests/utils/logger.test.ts +480 -0
  124. package/tests/utils/version.test.ts +390 -0
  125. package/tsconfig.json +12 -0
  126. package/dist/LocalToolResolver.d.ts +0 -84
  127. package/dist/LocalToolResolver.js +0 -353
  128. package/dist/api/enact-api.d.ts +0 -130
  129. package/dist/api/enact-api.js +0 -428
  130. package/dist/api/index.d.ts +0 -2
  131. package/dist/api/index.js +0 -2
  132. package/dist/api/types.d.ts +0 -103
  133. package/dist/api/types.js +0 -1
  134. package/dist/core/DaggerExecutionProvider.d.ts +0 -169
  135. package/dist/core/DaggerExecutionProvider.js +0 -1029
  136. package/dist/core/DirectExecutionProvider.d.ts +0 -23
  137. package/dist/core/DirectExecutionProvider.js +0 -406
  138. package/dist/core/EnactCore.d.ts +0 -162
  139. package/dist/core/EnactCore.js +0 -597
  140. package/dist/core/NativeExecutionProvider.d.ts +0 -9
  141. package/dist/core/NativeExecutionProvider.js +0 -16
  142. package/dist/core/index.d.ts +0 -3
  143. package/dist/core/index.js +0 -3
  144. package/dist/exec/index.d.ts +0 -3
  145. package/dist/exec/index.js +0 -3
  146. package/dist/exec/logger.d.ts +0 -11
  147. package/dist/exec/logger.js +0 -57
  148. package/dist/exec/validate.d.ts +0 -5
  149. package/dist/exec/validate.js +0 -167
  150. package/dist/lib/enact-direct.d.ts +0 -150
  151. package/dist/lib/enact-direct.js +0 -159
  152. package/dist/lib/index.d.ts +0 -1
  153. package/dist/lib/index.js +0 -1
  154. package/dist/security/index.d.ts +0 -3
  155. package/dist/security/index.js +0 -3
  156. package/dist/security/security.d.ts +0 -23
  157. package/dist/security/security.js +0 -137
  158. package/dist/security/sign.d.ts +0 -103
  159. package/dist/security/sign.js +0 -666
  160. package/dist/security/verification-enforcer.d.ts +0 -53
  161. package/dist/security/verification-enforcer.js +0 -204
  162. package/dist/services/McpCoreService.d.ts +0 -98
  163. package/dist/services/McpCoreService.js +0 -124
  164. package/dist/services/index.d.ts +0 -1
  165. package/dist/services/index.js +0 -1
  166. package/dist/utils/config.d.ts +0 -111
  167. package/dist/utils/config.js +0 -342
  168. package/dist/utils/env-loader.d.ts +0 -54
  169. package/dist/utils/env-loader.js +0 -270
  170. package/dist/utils/help.d.ts +0 -36
  171. package/dist/utils/help.js +0 -248
  172. package/dist/utils/index.d.ts +0 -7
  173. package/dist/utils/index.js +0 -7
  174. package/dist/utils/silent-monitor.d.ts +0 -67
  175. package/dist/utils/silent-monitor.js +0 -242
  176. package/dist/utils/timeout.d.ts +0 -5
  177. package/dist/utils/timeout.js +0 -23
  178. package/dist/web/env-manager-server.d.ts +0 -29
  179. package/dist/web/env-manager-server.js +0 -367
  180. package/dist/web/index.d.ts +0 -1
  181. package/dist/web/index.js +0 -1
  182. package/src/LocalToolResolver.ts +0 -424
  183. package/src/api/enact-api.ts +0 -604
  184. package/src/api/index.ts +0 -2
  185. package/src/api/types.ts +0 -114
  186. package/src/core/DaggerExecutionProvider.ts +0 -1357
  187. package/src/core/DirectExecutionProvider.ts +0 -484
  188. package/src/core/EnactCore.ts +0 -847
  189. package/src/core/index.ts +0 -3
  190. package/src/exec/index.ts +0 -3
  191. package/src/exec/logger.ts +0 -63
  192. package/src/exec/validate.ts +0 -238
  193. package/src/lib/enact-direct.ts +0 -254
  194. package/src/lib/index.ts +0 -1
  195. package/src/services/McpCoreService.ts +0 -201
  196. package/src/services/index.ts +0 -1
  197. package/src/utils/config.ts +0 -438
  198. package/src/utils/env-loader.ts +0 -370
  199. package/src/utils/help.ts +0 -257
  200. package/src/utils/index.ts +0 -7
  201. package/src/utils/silent-monitor.ts +0 -328
  202. package/src/utils/timeout.ts +0 -26
  203. package/src/web/env-manager-server.ts +0 -465
  204. package/src/web/index.ts +0 -1
  205. package/src/web/static/app.js +0 -663
  206. package/src/web/static/index.html +0 -117
  207. package/src/web/static/style.css +0 -291
@@ -1,847 +0,0 @@
1
- // src/core/EnactCore.ts - Core library for both CLI and MCP usage
2
- import type {
3
- EnactTool,
4
- ExecutionResult,
5
- ExecutionEnvironment,
6
- } from "../types.js";
7
- import { EnactApiClient } from "../api/enact-api.js";
8
- import {
9
- validateToolStructure,
10
- validateInputs,
11
- validateOutput,
12
- } from "../exec/validate.js";
13
- import { DirectExecutionProvider } from "./DirectExecutionProvider.js";
14
- import { DaggerExecutionProvider } from "./DaggerExecutionProvider.js";
15
- import { resolveToolEnvironmentVariables } from "../utils/env-loader.js";
16
- import logger from "../exec/logger.js";
17
- import yaml from "yaml";
18
- import fs from "fs";
19
- import path from "path";
20
- import { CryptoUtils, KeyManager, SecurityConfigManager, SigningService } from "@enactprotocol/security";
21
- import { getFrontendUrl, getApiUrl } from "../utils/config";
22
- import { EnactToolDefinition } from "../api/types.js";
23
-
24
- export interface EnactCoreOptions {
25
- apiUrl?: string;
26
- supabaseUrl?: string;
27
- executionProvider?: "direct" | "docker" | "dagger" | "cloud";
28
- authToken?: string;
29
- verbose?: boolean;
30
- defaultTimeout?: string;
31
- // Dagger-specific options
32
- daggerOptions?: {
33
- baseImage?: string;
34
- enableNetwork?: boolean;
35
- enableHostFS?: boolean;
36
- maxMemory?: string;
37
- maxCPU?: string;
38
- };
39
- }
40
-
41
- export interface ToolSearchOptions {
42
- query: string;
43
- limit?: number;
44
- tags?: string[];
45
- author?: string;
46
- format?: "json" | "table" | "list";
47
- }
48
-
49
- export interface ToolExecuteOptions {
50
- timeout?: string;
51
- force?: boolean;
52
- dryRun?: boolean;
53
- verbose?: boolean;
54
- isLocalFile?: boolean;
55
- dangerouslySkipVerification?: boolean;
56
- mount?: string; // Mount local directory to container (format: "localPath" or "localPath:containerPath")
57
- }
58
-
59
- export class EnactCore {
60
- private apiClient: EnactApiClient;
61
- private executionProvider: DirectExecutionProvider | DaggerExecutionProvider;
62
- private options: EnactCoreOptions;
63
-
64
- constructor(options: EnactCoreOptions = {}) {
65
- this.options = {
66
- apiUrl: "https://enact.tools", // Default, will be overridden by factory
67
- supabaseUrl: "https://xjnhhxwxovjifdxdwzih.supabase.co", // Default, will be overridden by factory
68
- executionProvider: "dagger",
69
- defaultTimeout: "30s",
70
- ...options,
71
- };
72
-
73
- this.apiClient = new EnactApiClient(
74
- this.options.apiUrl!,
75
- this.options.supabaseUrl!,
76
- );
77
-
78
- // Initialize the appropriate execution provider
79
- this.executionProvider = this.createExecutionProvider();
80
- }
81
-
82
- /**
83
- * Create EnactCore with config-based URLs
84
- */
85
- static async create(options: EnactCoreOptions = {}): Promise<EnactCore> {
86
- const frontendUrl = options.apiUrl || await getFrontendUrl();
87
- const apiUrl = options.supabaseUrl || await getApiUrl();
88
-
89
- return new EnactCore({
90
- ...options,
91
- apiUrl: frontendUrl,
92
- supabaseUrl: apiUrl,
93
- });
94
- }
95
- /**
96
- * Set authentication token for API operations
97
- */
98
- setAuthToken(token: string): void {
99
- this.options.authToken = token;
100
- }
101
-
102
- /**
103
- * Static method to search for tools (no execution provider needed)
104
- */
105
- static async searchTools(
106
- options: ToolSearchOptions,
107
- coreOptions: Pick<EnactCoreOptions, 'apiUrl' | 'supabaseUrl'> = {}
108
- ): Promise<EnactTool[]> {
109
- const apiClient = new EnactApiClient(
110
- coreOptions.apiUrl || "https://enact.tools",
111
- coreOptions.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co"
112
- );
113
-
114
- try {
115
- logger.info(`Searching for tools with query: "${options.query}"`);
116
-
117
- const searchParams = {
118
- query: options.query,
119
- limit: options.limit,
120
- tags: options.tags,
121
- };
122
-
123
- const results = await apiClient.searchTools(searchParams);
124
-
125
- // Parse and validate results
126
- const tools: EnactTool[] = [];
127
- for (const result of results) {
128
- if (result.name) {
129
- try {
130
- const tool = await EnactCore.getToolByName(result.name, undefined, coreOptions);
131
- if (tool) {
132
- tools.push(tool);
133
- }
134
- } catch (error) {
135
- logger.warn(`Failed to fetch tool ${result.name}:`, error);
136
- }
137
- }
138
- }
139
-
140
- logger.info(`Found ${tools.length} tools`);
141
- return tools;
142
- } catch (error) {
143
- logger.error("Error searching tools:", error);
144
-
145
- // If it's a 502 error (API server issue), try fallback to local filtering
146
- if (error instanceof Error && error.message.includes("502")) {
147
- logger.info(
148
- "Search API unavailable, trying fallback to local filtering...",
149
- );
150
- return EnactCore.searchToolsFallback(options, coreOptions);
151
- }
152
-
153
- throw new Error(
154
- `Search failed: ${error instanceof Error ? error.message : String(error)}`,
155
- );
156
- }
157
- }
158
-
159
- /**
160
- * Instance method wrapper for backward compatibility
161
- */
162
- async searchTools(options: ToolSearchOptions): Promise<EnactTool[]> {
163
- return EnactCore.searchTools(options, this.options);
164
- }
165
-
166
- /**
167
- * Static fallback search method that gets all tools and filters locally
168
- */
169
- private static async searchToolsFallback(
170
- options: ToolSearchOptions,
171
- coreOptions: Pick<EnactCoreOptions, 'apiUrl' | 'supabaseUrl'> = {}
172
- ): Promise<EnactTool[]> {
173
- const apiClient = new EnactApiClient(
174
- coreOptions.apiUrl || "https://enact.tools",
175
- coreOptions.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co"
176
- );
177
-
178
- try {
179
- logger.info("Using fallback search method...");
180
-
181
- // Get all tools (limited to avoid overwhelming the API)
182
- const allTools = await apiClient.getTools({
183
- limit: options.limit || 100,
184
- });
185
-
186
- // Filter tools locally based on search criteria
187
- const filteredTools: EnactTool[] = [];
188
- const query = options.query.toLowerCase();
189
-
190
- for (const result of allTools) {
191
- if (result.name) {
192
- try {
193
- const tool = await EnactCore.getToolByName(result.name, undefined, coreOptions);
194
- if (tool) {
195
- // Check if tool matches search criteria
196
- const matchesQuery =
197
- tool.name.toLowerCase().includes(query) ||
198
- (tool.description &&
199
- tool.description.toLowerCase().includes(query)) ||
200
- (tool.tags &&
201
- tool.tags.some((tag) => tag.toLowerCase().includes(query)));
202
-
203
- const matchesTags =
204
- !options.tags ||
205
- !options.tags.length ||
206
- (tool.tags &&
207
- options.tags.some((searchTag) =>
208
- tool.tags!.some((toolTag) =>
209
- toolTag.toLowerCase().includes(searchTag.toLowerCase()),
210
- ),
211
- ));
212
-
213
- const matchesAuthor =
214
- !options.author ||
215
- (tool.authors &&
216
- tool.authors.some(
217
- (author) =>
218
- author.name &&
219
- author.name
220
- .toLowerCase()
221
- .includes(options.author!.toLowerCase()),
222
- ));
223
-
224
- if (matchesQuery && matchesTags && matchesAuthor) {
225
- filteredTools.push(tool);
226
-
227
- // Apply limit if specified
228
- if (options.limit && filteredTools.length >= options.limit) {
229
- break;
230
- }
231
- }
232
- }
233
- } catch (error) {
234
- logger.warn(
235
- `Failed to fetch tool ${result.name} in fallback search:`,
236
- error,
237
- );
238
- }
239
- }
240
- }
241
-
242
- logger.info(`Fallback search found ${filteredTools.length} tools`);
243
- return filteredTools;
244
- } catch (fallbackError) {
245
- logger.error("Fallback search also failed:", fallbackError);
246
- throw new Error(
247
- `Search failed (including fallback): ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`,
248
- );
249
- }
250
- }
251
-
252
- /**
253
- * Static method to get a specific tool by name
254
- */
255
- static async getToolByName(
256
- name: string,
257
- version?: string,
258
- coreOptions: Pick<EnactCoreOptions, 'apiUrl' | 'supabaseUrl'> = {}
259
- ): Promise<EnactTool | null> {
260
- const apiClient = new EnactApiClient(
261
- coreOptions.apiUrl || "https://enact.tools",
262
- coreOptions.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co"
263
- );
264
-
265
- try {
266
- logger.info(`Fetching tool: ${name}${version ? `@${version}` : ""}`);
267
-
268
- const response = await apiClient.getTool(name);
269
-
270
- if (!response) {
271
- logger.info(`Tool not found: ${name}`);
272
- return null;
273
- }
274
-
275
- // Parse tool from response - prefer raw_content for signature compatibility
276
- let tool: EnactTool;
277
-
278
- // Try raw_content first (contains original tool definition with correct field names for signatures)
279
- if (response.raw_content && typeof response.raw_content === "string") {
280
- try {
281
- tool = JSON.parse(response.raw_content);
282
- } catch {
283
- tool = yaml.parse(response.raw_content);
284
- }
285
-
286
- // Merge signature information from response if not already in raw content
287
- if (!tool.signature && response.signature) {
288
- tool.signature = response.signature;
289
- }
290
- if (!tool.signatures && response.signatures) {
291
- // Convert object format to array format
292
- if (Array.isArray(response.signatures)) {
293
- tool.signatures = response.signatures;
294
- } else {
295
- // Convert object format {keyId: signatureData} to array format
296
- tool.signatures = Object.values(response.signatures);
297
- }
298
- }
299
- } else if (response.content && typeof response.content === "string") {
300
- tool = yaml.parse(response.content);
301
-
302
- // Merge signature information
303
- if (!tool.signature && response.signature) {
304
- tool.signature = response.signature;
305
- }
306
- if (!tool.signatures && response.signatures) {
307
- // Convert object format to array format
308
- if (Array.isArray(response.signatures)) {
309
- tool.signatures = response.signatures;
310
- } else {
311
- // Convert object format {keyId: signatureData} to array format
312
- tool.signatures = Object.values(response.signatures);
313
- }
314
- }
315
- } else {
316
- // Fallback: map database fields to tool format (may cause signature verification issues)
317
- tool = {
318
- name: response.name,
319
- description: response.description,
320
- command: response.command,
321
- timeout: response.timeout || "30s",
322
- tags: response.tags || [],
323
- license: response.license || response.spdx_license,
324
- outputSchema: response.output_schema || response.outputSchema,
325
- enact: response.protocol_version || response.enact || "1.0.0",
326
- version: response.version,
327
- inputSchema: response.input_schema || response.inputSchema,
328
- examples: response.examples,
329
- annotations: response.annotations,
330
- env: response.env_vars || response.env,
331
- resources: response.resources,
332
- signature: response.signature,
333
- signatures: response.signatures ? (Array.isArray(response.signatures) ? response.signatures : Object.values(response.signatures)) : undefined,
334
- namespace: response.namespace,
335
- };
336
- }
337
-
338
- logger.info(`Successfully fetched tool: ${tool.name}`);
339
- return tool;
340
- } catch (error) {
341
- if (error instanceof Error && error.message.includes("404")) {
342
- logger.info(`Tool not found: ${name}`);
343
- return null;
344
- }
345
-
346
- logger.error(
347
- `Error fetching tool: ${error instanceof Error ? error.message : String(error)}`,
348
- );
349
- throw error;
350
- }
351
- }
352
-
353
- /**
354
- * Instance method wrapper for backward compatibility
355
- */
356
- async getToolByName(
357
- name: string,
358
- version?: string,
359
- ): Promise<EnactTool | null> {
360
- return EnactCore.getToolByName(name, version, this.options);
361
- }
362
-
363
- /**
364
- * Execute a tool by name
365
- */
366
- async executeToolByName(
367
- name: string,
368
- inputs: Record<string, any> = {},
369
- options: ToolExecuteOptions = {},
370
- ): Promise<ExecutionResult> {
371
- const executionId = this.generateExecutionId();
372
-
373
- try {
374
- // Fetch the tool
375
- const tool = await this.getToolByName(name);
376
-
377
- if (!tool) {
378
- return {
379
- success: false,
380
- error: {
381
- message: `Tool not found: ${name}`,
382
- code: "NOT_FOUND",
383
- },
384
- metadata: {
385
- executionId,
386
- toolName: name,
387
- executedAt: new Date().toISOString(),
388
- environment: "direct",
389
- },
390
- };
391
- }
392
-
393
- // Execute the tool
394
- return await this.executeTool(tool, inputs, options);
395
- } catch (error) {
396
- return {
397
- success: false,
398
- error: {
399
- message: (error as Error).message,
400
- code: "EXECUTION_ERROR",
401
- },
402
- metadata: {
403
- executionId,
404
- toolName: name,
405
- executedAt: new Date().toISOString(),
406
- environment: "direct",
407
- },
408
- };
409
- }
410
- }
411
-
412
- public static async checkToolVerificationStatus(tool: EnactToolDefinition): Promise<boolean> {
413
- const documentForVerification = {
414
- command: tool.command,
415
- description: tool.description,
416
- from: tool.from,
417
- name: tool.name,
418
- signatures: tool.signatures?.map(sig => ({
419
- signature: sig.value,
420
- publicKey: "", // TODO: Look up the correct public key
421
- algorithm: sig.algorithm,
422
- timestamp: new Date(sig.created).getTime(),
423
- })),
424
- };
425
-
426
- let isValid = false;
427
-
428
- if (tool.signatures && tool.signatures.length > 0) {
429
- isValid = tool.signatures.some(sig => {
430
- const referenceSignature = {
431
- signature: sig.value,
432
- publicKey: "", // TODO: Lookup correct public key based on signature UUID
433
- algorithm: sig.algorithm,
434
- timestamp: new Date(sig.created).getTime()
435
- };
436
-
437
- return SigningService.verifyDocument(
438
- documentForVerification,
439
- referenceSignature,
440
- { includeFields: ['command', 'description', 'from', 'name'] }
441
- );
442
- });
443
- }
444
-
445
- return isValid;
446
- }
447
-
448
-
449
- private async verifyTool(tool: EnactTool, dangerouslySkipVerification: boolean = false): Promise<void> {
450
- if (dangerouslySkipVerification) {
451
- logger.warn(`Skipping signature verification for tool: ${tool.name}`);
452
- return;
453
- }
454
-
455
- try {
456
- if (!tool.signatures || tool.signatures.length === 0) {
457
- throw new Error(`Tool ${tool.name} does not have any signatures`);
458
- }
459
-
460
- // const documentForVerification = {
461
- // command: tool.command,
462
- // description: tool.description,
463
- // from: tool.from,
464
- // name: tool.name,
465
- // };
466
-
467
- // const referenceSignature = {
468
- // signature: tool.signatures[0].value,
469
- // publicKey: "", // Correct public key for UUID 71e02e2c-148c-4534-9900-bd9646e99333
470
- // algorithm: tool.signatures[0].algorithm,
471
- // timestamp: new Date(tool.signatures[0].created).getTime()
472
- // };
473
-
474
-
475
- // // Check what canonical document looks like
476
- // const canonicalDoc = SigningService.getCanonicalDocument(documentForVerification, { includeFields: ['command', 'description', 'from', 'name'] }
477
- // );
478
-
479
- // const docString = JSON.stringify(canonicalDoc);
480
- // const messageHash = CryptoUtils.hash(docString);
481
-
482
-
483
- // // Test direct crypto verification
484
- // const directVerify = CryptoUtils.verify(
485
- // referenceSignature.publicKey,
486
- // messageHash,
487
- // referenceSignature.signature
488
- // );
489
-
490
- // Check trusted keys
491
- // const trustedKeys = KeyManager.getAllTrustedPublicKeys();
492
-
493
- const isValid = await EnactCore.checkToolVerificationStatus(tool);
494
-
495
- console.log("Final verification result:", isValid);
496
-
497
- if (!isValid) {
498
- throw new Error(`Tool ${tool.name} has invalid signatures`);
499
- }
500
-
501
- logger.info(`Tool ${tool.name} signature verification passed`);
502
- } catch (error) {
503
- logger.error(`Signature verification failed for tool ${tool.name}:`, error);
504
- throw new Error(`Signature verification failed: ${error instanceof Error ? error.message : String(error)}`);
505
- }
506
- }
507
-
508
- /**
509
- * Execute a tool directly
510
- */
511
- async executeTool(
512
- tool: EnactTool,
513
- inputs: Record<string, any> = {},
514
- options: ToolExecuteOptions = {},
515
- ): Promise<ExecutionResult> {
516
- const executionId = this.generateExecutionId();
517
-
518
- try {
519
- logger.info(`Executing tool: ${tool.name}`);
520
-
521
- // Validate tool structure
522
- validateToolStructure(tool);
523
-
524
- // Validate inputs
525
- const validatedInputs = validateInputs(tool, inputs);
526
- const config = SecurityConfigManager.loadConfig();
527
-
528
- if( options.isLocalFile && config.allowLocalUnsigned){
529
- logger.warn(`Executing local file without signature verification: ${tool.name} (you can disallow in your security config)`);
530
- }
531
- if( options.dangerouslySkipVerification) {
532
- logger.warn(`Skipping signature verification for tool: ${tool.name} because of dangerouslySkipVerification option`);
533
- }
534
- const skipVerification = (options.isLocalFile && config.allowLocalUnsigned) || Boolean(options.dangerouslySkipVerification);
535
- // Verify tool signatures (unless explicitly skipped)
536
- await this.verifyTool(tool, skipVerification);
537
-
538
- // Resolve environment variables
539
- const { resolved: envVars } =
540
- await resolveToolEnvironmentVariables(tool.name, tool.env || {});
541
-
542
-
543
- // Execute the tool via the execution provider
544
- return await this.executionProvider.execute(
545
- tool,
546
- { ...validatedInputs, ...envVars },
547
- {
548
- vars: { ...envVars, ...validatedInputs },
549
- resources: {
550
- timeout: options.timeout || tool.timeout || this.options.defaultTimeout,
551
- },
552
- mount: options.mount,
553
- },
554
- );
555
- } catch (error) {
556
- return {
557
- success: false,
558
- error: {
559
- message: (error as Error).message,
560
- code: "EXECUTION_ERROR",
561
- },
562
- metadata: {
563
- executionId,
564
- toolName: tool.name,
565
- executedAt: new Date().toISOString(),
566
- environment: "direct",
567
- },
568
- };
569
- }
570
- }
571
-
572
- /**
573
- * Execute a tool from raw YAML definition
574
- */
575
- async executeRawTool(
576
- toolYaml: string,
577
- inputs: Record<string, any> = {},
578
- options: ToolExecuteOptions = {},
579
- ): Promise<ExecutionResult> {
580
- try {
581
- // Parse the YAML
582
- const tool = yaml.parse(toolYaml) as EnactTool;
583
-
584
- // Validate that it's a proper tool definition
585
- if (!tool || typeof tool !== "object") {
586
- throw new Error(
587
- "Invalid tool definition: YAML must contain a tool object",
588
- );
589
- }
590
-
591
- // Check for required fields
592
- if (!tool.name || !tool.description || !tool.command) {
593
- throw new Error(
594
- "Invalid tool definition: missing required fields (name, description, command)",
595
- );
596
- }
597
-
598
- // Execute the tool
599
- return await this.executeTool(tool, inputs, options);
600
- } catch (error) {
601
- const executionId = this.generateExecutionId();
602
-
603
- return {
604
- success: false,
605
- error: {
606
- message: (error as Error).message,
607
- code: "PARSE_ERROR",
608
- },
609
- metadata: {
610
- executionId,
611
- toolName: "unknown",
612
- executedAt: new Date().toISOString(),
613
- environment: "direct",
614
- },
615
- };
616
- }
617
- }
618
-
619
-
620
- /**
621
- * Static method to check if a tool exists
622
- */
623
- static async toolExists(
624
- name: string,
625
- coreOptions: Pick<EnactCoreOptions, 'apiUrl' | 'supabaseUrl'> = {}
626
- ): Promise<boolean> {
627
- try {
628
- const tool = await EnactCore.getToolByName(name, undefined, coreOptions);
629
- return tool !== null;
630
- } catch (error) {
631
- return false;
632
- }
633
- }
634
-
635
- /**
636
- * Instance method wrapper for backward compatibility
637
- */
638
- async toolExists(name: string): Promise<boolean> {
639
- return EnactCore.toolExists(name, this.options);
640
- }
641
-
642
- /**
643
- * Get tools by tags
644
- */
645
- async getToolsByTags(
646
- tags: string[],
647
- limit: number = 20,
648
- ): Promise<EnactTool[]> {
649
- return EnactCore.searchTools({
650
- query: tags.join(" "),
651
- tags,
652
- limit,
653
- }, this.options);
654
- }
655
-
656
- /**
657
- * Get tools by author
658
- */
659
- async getToolsByAuthor(
660
- author: string,
661
- limit: number = 20,
662
- ): Promise<EnactTool[]> {
663
- return EnactCore.searchTools({
664
- query: `author:${author}`,
665
- author,
666
- limit,
667
- }, this.options);
668
- }
669
-
670
- /**
671
- * Static method to get all tools with filters
672
- */
673
- static async getTools(
674
- options: {
675
- limit?: number;
676
- offset?: number;
677
- tags?: string[];
678
- author?: string;
679
- } = {},
680
- coreOptions: Pick<EnactCoreOptions, 'apiUrl' | 'supabaseUrl'> = {}
681
- ): Promise<EnactTool[]> {
682
- const apiClient = new EnactApiClient(
683
- coreOptions.apiUrl || "https://enact.tools",
684
- coreOptions.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co"
685
- );
686
-
687
- try {
688
- const apiResults = await apiClient.getTools(options);
689
-
690
- // Parse and validate results
691
- const tools: EnactTool[] = [];
692
- for (const result of apiResults) {
693
- if (result.name) {
694
- try {
695
- const tool = await EnactCore.getToolByName(result.name, undefined, coreOptions);
696
- if (tool) {
697
- tools.push(tool);
698
- }
699
- } catch (error) {
700
- logger.warn(`Failed to fetch tool ${result.name}:`, error);
701
- }
702
- }
703
- }
704
-
705
- return tools;
706
- } catch (error) {
707
- logger.error("Error getting tools:", error);
708
- throw new Error(
709
- `Failed to get tools: ${error instanceof Error ? error.message : String(error)}`,
710
- );
711
- }
712
- }
713
-
714
- /**
715
- * Instance method wrapper for backward compatibility
716
- */
717
- async getTools(
718
- options: {
719
- limit?: number;
720
- offset?: number;
721
- tags?: string[];
722
- author?: string;
723
- } = {},
724
- ): Promise<EnactTool[]> {
725
- return EnactCore.getTools(options, this.options);
726
- }
727
-
728
- /**
729
- * Get authentication status (placeholder - would need actual auth implementation)
730
- */
731
- async getAuthStatus(): Promise<{
732
- authenticated: boolean;
733
- user?: string;
734
- server?: string;
735
- }> {
736
- // This would need to check actual auth state
737
- // For now, return based on whether we have a token
738
- return {
739
- authenticated: !!this.options.authToken,
740
- server: this.options.apiUrl,
741
- };
742
- }
743
-
744
- /**
745
- * Static method to publish a tool
746
- */
747
- static async publishTool(
748
- tool: EnactTool,
749
- authToken: string,
750
- coreOptions: Pick<EnactCoreOptions, 'apiUrl' | 'supabaseUrl'> = {}
751
- ): Promise<{ success: boolean; message: string }> {
752
- const apiClient = new EnactApiClient(
753
- coreOptions.apiUrl || "https://enact.tools",
754
- coreOptions.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co"
755
- );
756
-
757
- try {
758
- validateToolStructure(tool);
759
-
760
- await apiClient.publishTool(tool, authToken);
761
-
762
- return {
763
- success: true,
764
- message: `Successfully published tool: ${tool.name}`,
765
- };
766
- } catch (error) {
767
- return {
768
- success: false,
769
- message: `Failed to publish tool: ${error instanceof Error ? error.message : String(error)}`,
770
- };
771
- }
772
- }
773
-
774
- /**
775
- * Instance method wrapper for backward compatibility
776
- */
777
- async publishTool(
778
- tool: EnactTool,
779
- ): Promise<{ success: boolean; message: string }> {
780
- if (!this.options.authToken) {
781
- return {
782
- success: false,
783
- message: "Authentication required to publish tools",
784
- };
785
- }
786
-
787
- return EnactCore.publishTool(tool, this.options.authToken, this.options);
788
- }
789
-
790
- /**
791
- * Get tool information (alias for getToolByName for consistency)
792
- */
793
- async getToolInfo(name: string, version?: string): Promise<EnactTool | null> {
794
- return EnactCore.getToolByName(name, version, this.options);
795
- }
796
-
797
- /**
798
- * Get core library status
799
- */
800
- async getStatus(): Promise<{
801
- executionProvider: string;
802
- apiUrl: string;
803
- defaultTimeout: string;
804
- authenticated: boolean;
805
- }> {
806
- const authStatus = await this.getAuthStatus();
807
-
808
- return {
809
- executionProvider: this.options.executionProvider || "direct",
810
- apiUrl: this.options.apiUrl || "https://enact.tools",
811
- defaultTimeout: this.options.defaultTimeout || "30s",
812
- authenticated: authStatus.authenticated,
813
- };
814
- }
815
-
816
- /**
817
- * Create the appropriate execution provider based on options
818
- */
819
- private createExecutionProvider():
820
- | DirectExecutionProvider
821
- | DaggerExecutionProvider {
822
- switch (this.options.executionProvider) {
823
- case "direct":
824
- return new DirectExecutionProvider();
825
- case "dagger":
826
- default:
827
- return new DaggerExecutionProvider(this.options.daggerOptions);
828
- }
829
- }
830
-
831
- /**
832
- * Switch execution provider at runtime
833
- */
834
- switchExecutionProvider(provider: "direct" | "dagger", options?: any): void {
835
- this.options.executionProvider = provider;
836
- this.executionProvider = this.createExecutionProvider();
837
- }
838
-
839
- /**
840
- * Generate execution ID
841
- */
842
- private generateExecutionId(): string {
843
- return `exec_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
844
- }
845
- }
846
-
847
- // No default instance to avoid eager initialization of Dagger