@enactprotocol/shared 1.0.14 → 1.2.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 (38) hide show
  1. package/dist/api/enact-api.js +2 -2
  2. package/dist/api/types.d.ts +10 -3
  3. package/dist/core/DaggerExecutionProvider.d.ts +1 -1
  4. package/dist/core/DaggerExecutionProvider.js +23 -19
  5. package/dist/core/EnactCore.d.ts +36 -19
  6. package/dist/core/EnactCore.js +162 -217
  7. package/dist/core/NativeExecutionProvider.d.ts +9 -0
  8. package/dist/core/NativeExecutionProvider.js +16 -0
  9. package/dist/index.d.ts +0 -4
  10. package/dist/index.js +0 -4
  11. package/dist/lib/enact-direct.d.ts +0 -15
  12. package/dist/lib/enact-direct.js +0 -11
  13. package/dist/security/sign.d.ts +5 -5
  14. package/dist/security/sign.js +247 -113
  15. package/dist/security/verification-enforcer.d.ts +12 -0
  16. package/dist/security/verification-enforcer.js +26 -3
  17. package/dist/services/McpCoreService.d.ts +0 -12
  18. package/dist/services/McpCoreService.js +0 -9
  19. package/dist/types.d.ts +5 -4
  20. package/dist/utils/config.js +1 -1
  21. package/dist/utils/env-loader.js +1 -1
  22. package/dist/utils/help.js +1 -1
  23. package/package.json +3 -6
  24. package/src/api/enact-api.ts +2 -2
  25. package/src/api/types.ts +11 -4
  26. package/src/core/DaggerExecutionProvider.ts +26 -13
  27. package/src/core/EnactCore.ts +232 -269
  28. package/src/index.ts +0 -5
  29. package/src/lib/enact-direct.ts +0 -21
  30. package/src/services/McpCoreService.ts +0 -20
  31. package/src/types.ts +10 -12
  32. package/src/utils/config.ts +1 -1
  33. package/src/utils/env-loader.ts +1 -1
  34. package/src/utils/help.ts +1 -1
  35. package/src/security/index.ts +0 -3
  36. package/src/security/security.ts +0 -188
  37. package/src/security/sign.ts +0 -797
  38. package/src/security/verification-enforcer.ts +0 -268
@@ -5,10 +5,6 @@ import type {
5
5
  ExecutionEnvironment,
6
6
  } from "../types.js";
7
7
  import { EnactApiClient } from "../api/enact-api.js";
8
- import {
9
- verifyCommandSafety,
10
- sanitizeEnvironmentVariables,
11
- } from "../security/security.js";
12
8
  import {
13
9
  validateToolStructure,
14
10
  validateInputs,
@@ -19,17 +15,9 @@ import { DaggerExecutionProvider } from "./DaggerExecutionProvider.js";
19
15
  import { resolveToolEnvironmentVariables } from "../utils/env-loader.js";
20
16
  import logger from "../exec/logger.js";
21
17
  import yaml from "yaml";
22
- import {
23
- verifyTool as verifyToolSignatureWithPolicy,
24
- VERIFICATION_POLICIES,
25
- } from "../security/sign.js";
26
- import {
27
- enforceSignatureVerification,
28
- createVerificationFailureResult,
29
- logSecurityAudit,
30
- } from "../security/verification-enforcer.js";
31
18
  import fs from "fs";
32
19
  import path from "path";
20
+ import { CryptoUtils, KeyManager, SecurityConfigManager, SigningService } from "@enactprotocol/security";
33
21
 
34
22
  export interface EnactCoreOptions {
35
23
  apiUrl?: string;
@@ -38,7 +26,6 @@ export interface EnactCoreOptions {
38
26
  authToken?: string;
39
27
  verbose?: boolean;
40
28
  defaultTimeout?: string;
41
- verificationPolicy?: "permissive" | "enterprise" | "paranoid";
42
29
  // Dagger-specific options
43
30
  daggerOptions?: {
44
31
  baseImage?: string;
@@ -59,11 +46,11 @@ export interface ToolSearchOptions {
59
46
 
60
47
  export interface ToolExecuteOptions {
61
48
  timeout?: string;
62
- verifyPolicy?: "permissive" | "enterprise" | "paranoid";
63
- skipVerification?: boolean;
64
49
  force?: boolean;
65
50
  dryRun?: boolean;
66
51
  verbose?: boolean;
52
+ isLocalFile?: boolean;
53
+ dangerouslySkipVerification?: boolean;
67
54
  }
68
55
 
69
56
  export class EnactCore {
@@ -77,7 +64,6 @@ export class EnactCore {
77
64
  supabaseUrl: "https://xjnhhxwxovjifdxdwzih.supabase.co",
78
65
  executionProvider: "dagger",
79
66
  defaultTimeout: "30s",
80
- verificationPolicy: "permissive",
81
67
  ...options,
82
68
  };
83
69
 
@@ -97,9 +83,17 @@ export class EnactCore {
97
83
  }
98
84
 
99
85
  /**
100
- * Search for tools
86
+ * Static method to search for tools (no execution provider needed)
101
87
  */
102
- async searchTools(options: ToolSearchOptions): Promise<EnactTool[]> {
88
+ static async searchTools(
89
+ options: ToolSearchOptions,
90
+ coreOptions: Pick<EnactCoreOptions, 'apiUrl' | 'supabaseUrl'> = {}
91
+ ): Promise<EnactTool[]> {
92
+ const apiClient = new EnactApiClient(
93
+ coreOptions.apiUrl || "https://enact.tools",
94
+ coreOptions.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co"
95
+ );
96
+
103
97
  try {
104
98
  logger.info(`Searching for tools with query: "${options.query}"`);
105
99
 
@@ -109,14 +103,14 @@ export class EnactCore {
109
103
  tags: options.tags,
110
104
  };
111
105
 
112
- const results = await this.apiClient.searchTools(searchParams);
106
+ const results = await apiClient.searchTools(searchParams);
113
107
 
114
108
  // Parse and validate results
115
109
  const tools: EnactTool[] = [];
116
110
  for (const result of results) {
117
111
  if (result.name) {
118
112
  try {
119
- const tool = await this.getToolByName(result.name);
113
+ const tool = await EnactCore.getToolByName(result.name, undefined, coreOptions);
120
114
  if (tool) {
121
115
  tools.push(tool);
122
116
  }
@@ -136,7 +130,7 @@ export class EnactCore {
136
130
  logger.info(
137
131
  "Search API unavailable, trying fallback to local filtering...",
138
132
  );
139
- return this.searchToolsFallback(options);
133
+ return EnactCore.searchToolsFallback(options, coreOptions);
140
134
  }
141
135
 
142
136
  throw new Error(
@@ -146,16 +140,29 @@ export class EnactCore {
146
140
  }
147
141
 
148
142
  /**
149
- * Fallback search method that gets all tools and filters locally
143
+ * Instance method wrapper for backward compatibility
150
144
  */
151
- private async searchToolsFallback(
145
+ async searchTools(options: ToolSearchOptions): Promise<EnactTool[]> {
146
+ return EnactCore.searchTools(options, this.options);
147
+ }
148
+
149
+ /**
150
+ * Static fallback search method that gets all tools and filters locally
151
+ */
152
+ private static async searchToolsFallback(
152
153
  options: ToolSearchOptions,
154
+ coreOptions: Pick<EnactCoreOptions, 'apiUrl' | 'supabaseUrl'> = {}
153
155
  ): Promise<EnactTool[]> {
156
+ const apiClient = new EnactApiClient(
157
+ coreOptions.apiUrl || "https://enact.tools",
158
+ coreOptions.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co"
159
+ );
160
+
154
161
  try {
155
162
  logger.info("Using fallback search method...");
156
163
 
157
164
  // Get all tools (limited to avoid overwhelming the API)
158
- const allTools = await this.apiClient.getTools({
165
+ const allTools = await apiClient.getTools({
159
166
  limit: options.limit || 100,
160
167
  });
161
168
 
@@ -166,7 +173,7 @@ export class EnactCore {
166
173
  for (const result of allTools) {
167
174
  if (result.name) {
168
175
  try {
169
- const tool = await this.getToolByName(result.name);
176
+ const tool = await EnactCore.getToolByName(result.name, undefined, coreOptions);
170
177
  if (tool) {
171
178
  // Check if tool matches search criteria
172
179
  const matchesQuery =
@@ -226,44 +233,70 @@ export class EnactCore {
226
233
  }
227
234
 
228
235
  /**
229
- * Get a specific tool by name
236
+ * Static method to get a specific tool by name
230
237
  */
231
- async getToolByName(
238
+ static async getToolByName(
232
239
  name: string,
233
240
  version?: string,
241
+ coreOptions: Pick<EnactCoreOptions, 'apiUrl' | 'supabaseUrl'> = {}
234
242
  ): Promise<EnactTool | null> {
243
+ const apiClient = new EnactApiClient(
244
+ coreOptions.apiUrl || "https://enact.tools",
245
+ coreOptions.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co"
246
+ );
247
+
235
248
  try {
236
249
  logger.info(`Fetching tool: ${name}${version ? `@${version}` : ""}`);
237
250
 
238
- const response = await this.apiClient.getTool(name);
251
+ const response = await apiClient.getTool(name);
239
252
 
240
253
  if (!response) {
241
254
  logger.info(`Tool not found: ${name}`);
242
255
  return null;
243
256
  }
244
257
 
245
- // Parse tool from response
258
+ // Parse tool from response - prefer raw_content for signature compatibility
246
259
  let tool: EnactTool;
247
260
 
248
- if (response.content && typeof response.content === "string") {
249
- tool = yaml.parse(response.content);
250
- } else if (
251
- response.raw_content &&
252
- typeof response.raw_content === "string"
253
- ) {
261
+ // Try raw_content first (contains original tool definition with correct field names for signatures)
262
+ if (response.raw_content && typeof response.raw_content === "string") {
254
263
  try {
255
264
  tool = JSON.parse(response.raw_content);
256
265
  } catch {
257
266
  tool = yaml.parse(response.raw_content);
258
267
  }
259
268
 
269
+ // Merge signature information from response if not already in raw content
270
+ if (!tool.signature && response.signature) {
271
+ tool.signature = response.signature;
272
+ }
273
+ if (!tool.signatures && response.signatures) {
274
+ // Convert object format to array format
275
+ if (Array.isArray(response.signatures)) {
276
+ tool.signatures = response.signatures;
277
+ } else {
278
+ // Convert object format {keyId: signatureData} to array format
279
+ tool.signatures = Object.values(response.signatures);
280
+ }
281
+ }
282
+ } else if (response.content && typeof response.content === "string") {
283
+ tool = yaml.parse(response.content);
284
+
260
285
  // Merge signature information
261
- if (response.signature || response.signatures) {
286
+ if (!tool.signature && response.signature) {
262
287
  tool.signature = response.signature;
263
- tool.signatures = response.signatures;
288
+ }
289
+ if (!tool.signatures && response.signatures) {
290
+ // Convert object format to array format
291
+ if (Array.isArray(response.signatures)) {
292
+ tool.signatures = response.signatures;
293
+ } else {
294
+ // Convert object format {keyId: signatureData} to array format
295
+ tool.signatures = Object.values(response.signatures);
296
+ }
264
297
  }
265
298
  } else {
266
- // Map database fields to tool format
299
+ // Fallback: map database fields to tool format (may cause signature verification issues)
267
300
  tool = {
268
301
  name: response.name,
269
302
  description: response.description,
@@ -280,7 +313,7 @@ export class EnactCore {
280
313
  env: response.env_vars || response.env,
281
314
  resources: response.resources,
282
315
  signature: response.signature,
283
- signatures: response.signatures,
316
+ signatures: response.signatures ? (Array.isArray(response.signatures) ? response.signatures : Object.values(response.signatures)) : undefined,
284
317
  namespace: response.namespace,
285
318
  };
286
319
  }
@@ -300,6 +333,16 @@ export class EnactCore {
300
333
  }
301
334
  }
302
335
 
336
+ /**
337
+ * Instance method wrapper for backward compatibility
338
+ */
339
+ async getToolByName(
340
+ name: string,
341
+ version?: string,
342
+ ): Promise<EnactTool | null> {
343
+ return EnactCore.getToolByName(name, version, this.options);
344
+ }
345
+
303
346
  /**
304
347
  * Execute a tool by name
305
348
  */
@@ -349,6 +392,69 @@ export class EnactCore {
349
392
  }
350
393
  }
351
394
 
395
+ private async verifyTool(tool: EnactTool, dangerouslySkipVerification: boolean = false): Promise<void> {
396
+ if (dangerouslySkipVerification) {
397
+ logger.warn(`Skipping signature verification for tool: ${tool.name}`);
398
+ return;
399
+ }
400
+
401
+ try {
402
+ if (!tool.signatures || tool.signatures.length === 0) {
403
+ throw new Error(`Tool ${tool.name} does not have any signatures`);
404
+ }
405
+ const documentForVerification = {
406
+ command: tool.command
407
+ };
408
+
409
+ const referenceSignature = {
410
+ signature: tool.signatures[0].value,
411
+ publicKey: tool.signatures[0].signer,
412
+ algorithm: tool.signatures[0].algorithm,
413
+ timestamp: new Date(tool.signatures[0].created).getTime()
414
+ };
415
+
416
+
417
+ // Check what canonical document looks like
418
+ const canonicalDoc = SigningService.getCanonicalDocument(documentForVerification, { includeFields: ['command'] });
419
+ // console.log("Canonical document:", JSON.stringify(canonicalDoc));
420
+
421
+ const docString = JSON.stringify(canonicalDoc);
422
+ const messageHash = CryptoUtils.hash(docString);
423
+ // console.log("Document string:", docString);
424
+ // console.log("Message hash:", messageHash);
425
+
426
+ // Test direct crypto verification
427
+ const directVerify = CryptoUtils.verify(
428
+ referenceSignature.publicKey,
429
+ messageHash,
430
+ referenceSignature.signature
431
+ );
432
+ console.log("Direct crypto verification result:", directVerify);
433
+
434
+ // Check trusted keys
435
+ const trustedKeys = KeyManager.getAllTrustedPublicKeys();
436
+ console.log("Trusted keys:", trustedKeys);
437
+ console.log("Is our public key trusted?", trustedKeys.includes(referenceSignature.publicKey));
438
+
439
+ const isValid = SigningService.verifyDocument(
440
+ documentForVerification,
441
+ referenceSignature,
442
+ { includeFields: ['command'] }
443
+ );
444
+
445
+ console.log("Final verification result:", isValid);
446
+
447
+ if (!isValid) {
448
+ throw new Error(`Tool ${tool.name} has invalid signatures`);
449
+ }
450
+
451
+ logger.info(`Tool ${tool.name} signature verification passed`);
452
+ } catch (error) {
453
+ logger.error(`Signature verification failed for tool ${tool.name}:`, error);
454
+ throw new Error(`Signature verification failed: ${error instanceof Error ? error.message : String(error)}`);
455
+ }
456
+ }
457
+
352
458
  /**
353
459
  * Execute a tool directly
354
460
  */
@@ -365,153 +471,50 @@ export class EnactCore {
365
471
  // Validate tool structure
366
472
  validateToolStructure(tool);
367
473
 
368
- // MANDATORY SIGNATURE VERIFICATION - All tools must be verified before execution
369
- const verificationResult = await enforceSignatureVerification(tool, {
370
- skipVerification: options.skipVerification,
371
- verifyPolicy: options.verifyPolicy,
372
- force: options.force,
373
- allowUnsigned: false, // Never allow unsigned tools in production
374
- });
375
-
376
- // Log security audit information
377
- logSecurityAudit(tool, verificationResult, verificationResult.allowed, {
378
- skipVerification: options.skipVerification,
379
- verifyPolicy: options.verifyPolicy,
380
- force: options.force,
381
- });
382
-
383
- // Block execution if verification fails
384
- if (!verificationResult.allowed) {
385
- return createVerificationFailureResult(
386
- tool,
387
- verificationResult,
388
- executionId,
389
- );
390
- }
391
-
392
474
  // Validate inputs
393
475
  const validatedInputs = validateInputs(tool, inputs);
394
-
395
- // Check command safety
396
- const safetyCheck = verifyCommandSafety(tool.command, tool);
397
- if (!safetyCheck.isSafe && !options.force) {
398
- return {
399
- success: false,
400
- error: {
401
- message: `Unsafe command blocked: ${safetyCheck.blocked?.join(", ")}`,
402
- code: "COMMAND_UNSAFE",
403
- details: safetyCheck,
404
- },
405
- metadata: {
406
- executionId,
407
- toolName: tool.name,
408
- version: tool.version,
409
- executedAt: new Date().toISOString(),
410
- environment: "direct",
411
- command: tool.command,
412
- },
413
- };
476
+ const config = SecurityConfigManager.loadConfig();
477
+
478
+ if( options.isLocalFile && config.allowLocalUnsigned){
479
+ logger.warn(`Executing local file without signature verification: ${tool.name} (you can disallow in your security config)`);
414
480
  }
415
-
416
- // Log warnings
417
- if (safetyCheck.warnings.length > 0) {
418
- safetyCheck.warnings.forEach((warning: string) => logger.warn(warning));
481
+ if( options.dangerouslySkipVerification) {
482
+ logger.warn(`Skipping signature verification for tool: ${tool.name} because of dangerouslySkipVerification option`);
419
483
  }
484
+ const skipVerification = (options.isLocalFile && config.allowLocalUnsigned) || Boolean(options.dangerouslySkipVerification);
485
+ // Verify tool signatures (unless explicitly skipped)
486
+ await this.verifyTool(tool, skipVerification);
420
487
 
421
- // Dry run - just validate and return
422
- if (options.dryRun) {
423
- return {
424
- success: true,
425
- output: {
426
- dryRun: true,
427
- tool: tool.name,
428
- command: tool.command,
429
- inputs: validatedInputs,
430
- safetyCheck,
431
- },
432
- metadata: {
433
- executionId,
434
- toolName: tool.name,
435
- version: tool.version,
436
- executedAt: new Date().toISOString(),
437
- environment: "direct",
438
- command: tool.command,
439
- },
440
- };
441
- }
442
-
443
- // Setup execution environment
444
- // Load package environment variables from .env files
445
- const envResult = await resolveToolEnvironmentVariables(
446
- tool.name,
447
- tool.env,
448
- );
449
-
450
- // Log any missing required environment variables
451
- if (envResult.missing.length > 0) {
452
- logger.warn(
453
- `Missing required environment variables: ${envResult.missing.join(", ")}`,
454
- );
455
- }
456
-
457
- const environment: ExecutionEnvironment = {
458
- vars: {
459
- ...envResult.resolved,
460
- ...sanitizeEnvironmentVariables(validatedInputs),
461
- },
462
- resources: tool.resources,
463
- namespace: tool.namespace,
464
- };
488
+ // Resolve environment variables
489
+ const { resolved: envVars } =
490
+ await resolveToolEnvironmentVariables(tool.name, tool.env || {});
465
491
 
466
- // Setup execution provider
467
- await this.executionProvider.setup(tool);
468
492
 
469
- // Execute the tool
470
- const result = await this.executionProvider.execute(
493
+ // Execute the tool via the execution provider
494
+ return await this.executionProvider.execute(
471
495
  tool,
472
- validatedInputs,
473
- environment,
474
- );
475
-
476
- // Validate output if schema is provided
477
- if (result.success && result.output && tool.outputSchema) {
478
- try {
479
- result.output = validateOutput(tool, result.output);
480
- } catch (error) {
481
- logger.warn(`Output validation failed: ${(error as Error).message}`);
482
- }
483
- }
484
-
485
- logger.info(
486
- `Tool execution completed: ${tool.name} (success: ${result.success})`,
496
+ { ...validatedInputs, ...envVars },
497
+ {
498
+ vars: { ...envVars, ...validatedInputs },
499
+ resources: {
500
+ timeout: options.timeout || tool.timeout || this.options.defaultTimeout,
501
+ },
502
+ },
487
503
  );
488
- return result;
489
504
  } catch (error) {
490
- logger.error(`Error executing tool: ${(error as Error).message}`);
491
-
492
505
  return {
493
506
  success: false,
494
507
  error: {
495
508
  message: (error as Error).message,
496
509
  code: "EXECUTION_ERROR",
497
- details: error,
498
510
  },
499
511
  metadata: {
500
512
  executionId,
501
513
  toolName: tool.name,
502
- version: tool.version,
503
514
  executedAt: new Date().toISOString(),
504
515
  environment: "direct",
505
- command: tool.command,
506
516
  },
507
517
  };
508
- } finally {
509
- // Cleanup
510
- try {
511
- await this.executionProvider.cleanup();
512
- } catch (cleanupError) {
513
- logger.error("Error during cleanup:", cleanupError);
514
- }
515
518
  }
516
519
  }
517
520
 
@@ -562,100 +565,27 @@ export class EnactCore {
562
565
  }
563
566
  }
564
567
 
568
+
565
569
  /**
566
- * Verify a tool's signature
570
+ * Static method to check if a tool exists
567
571
  */
568
- async verifyTool(
572
+ static async toolExists(
569
573
  name: string,
570
- policy?: string,
571
- ): Promise<{
572
- verified: boolean;
573
- signatures: any[];
574
- policy: string;
575
- errors?: string[];
576
- }> {
574
+ coreOptions: Pick<EnactCoreOptions, 'apiUrl' | 'supabaseUrl'> = {}
575
+ ): Promise<boolean> {
577
576
  try {
578
- const tool = await this.getToolByName(name);
579
-
580
- if (!tool) {
581
- return {
582
- verified: false,
583
- signatures: [],
584
- policy: policy || "permissive",
585
- errors: [`Tool not found: ${name}`],
586
- };
587
- }
588
-
589
- // Load public key from keys/file-public.pem
590
- let publicKey: string | undefined;
591
- try {
592
- const keyPath = path.resolve(__dirname, "../../keys/file-public.pem");
593
- publicKey = fs.readFileSync(keyPath, "utf8");
594
- } catch (e) {
595
- logger.warn("Could not load public key for signature verification:", e);
596
- }
597
- if (!publicKey) {
598
- return {
599
- verified: false,
600
- signatures: [],
601
- policy: policy || "permissive",
602
- errors: ["Public key not found for signature verification"],
603
- };
604
- }
605
- const policyKey = (policy || "permissive").toUpperCase() as
606
- | "PERMISSIVE"
607
- | "ENTERPRISE"
608
- | "PARANOID";
609
- const policyObj = VERIFICATION_POLICIES[policyKey];
610
- const verificationResult = await verifyToolSignatureWithPolicy(
611
- tool,
612
- policyObj,
613
- );
614
-
615
- if (!verificationResult.isValid) {
616
- return {
617
- verified: false,
618
- signatures: [],
619
- policy: policy || "permissive",
620
- errors: verificationResult.errors,
621
- };
622
- }
623
-
624
- const signatures: any[] = [];
625
-
626
- if (tool.signature) {
627
- signatures.push(tool.signature);
628
- }
629
-
630
- if (tool.signatures) {
631
- signatures.push(...Object.values(tool.signatures));
632
- }
633
-
634
- return {
635
- verified: verificationResult.isValid,
636
- signatures,
637
- policy: policy || "permissive",
638
- };
577
+ const tool = await EnactCore.getToolByName(name, undefined, coreOptions);
578
+ return tool !== null;
639
579
  } catch (error) {
640
- return {
641
- verified: false,
642
- signatures: [],
643
- policy: policy || "permissive",
644
- errors: [`Verification error: ${(error as Error).message}`],
645
- };
580
+ return false;
646
581
  }
647
582
  }
648
583
 
649
584
  /**
650
- * Check if a tool exists
585
+ * Instance method wrapper for backward compatibility
651
586
  */
652
587
  async toolExists(name: string): Promise<boolean> {
653
- try {
654
- const tool = await this.getToolByName(name);
655
- return tool !== null;
656
- } catch (error) {
657
- return false;
658
- }
588
+ return EnactCore.toolExists(name, this.options);
659
589
  }
660
590
 
661
591
  /**
@@ -665,11 +595,11 @@ export class EnactCore {
665
595
  tags: string[],
666
596
  limit: number = 20,
667
597
  ): Promise<EnactTool[]> {
668
- return this.searchTools({
598
+ return EnactCore.searchTools({
669
599
  query: tags.join(" "),
670
600
  tags,
671
601
  limit,
672
- });
602
+ }, this.options);
673
603
  }
674
604
 
675
605
  /**
@@ -679,33 +609,39 @@ export class EnactCore {
679
609
  author: string,
680
610
  limit: number = 20,
681
611
  ): Promise<EnactTool[]> {
682
- return this.searchTools({
612
+ return EnactCore.searchTools({
683
613
  query: `author:${author}`,
684
614
  author,
685
615
  limit,
686
- });
616
+ }, this.options);
687
617
  }
688
618
 
689
619
  /**
690
- * Get all tools with filters
620
+ * Static method to get all tools with filters
691
621
  */
692
- async getTools(
622
+ static async getTools(
693
623
  options: {
694
624
  limit?: number;
695
625
  offset?: number;
696
626
  tags?: string[];
697
627
  author?: string;
698
628
  } = {},
629
+ coreOptions: Pick<EnactCoreOptions, 'apiUrl' | 'supabaseUrl'> = {}
699
630
  ): Promise<EnactTool[]> {
631
+ const apiClient = new EnactApiClient(
632
+ coreOptions.apiUrl || "https://enact.tools",
633
+ coreOptions.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co"
634
+ );
635
+
700
636
  try {
701
- const apiResults = await this.apiClient.getTools(options);
637
+ const apiResults = await apiClient.getTools(options);
702
638
 
703
639
  // Parse and validate results
704
640
  const tools: EnactTool[] = [];
705
641
  for (const result of apiResults) {
706
642
  if (result.name) {
707
643
  try {
708
- const tool = await this.getToolByName(result.name);
644
+ const tool = await EnactCore.getToolByName(result.name, undefined, coreOptions);
709
645
  if (tool) {
710
646
  tools.push(tool);
711
647
  }
@@ -724,6 +660,20 @@ export class EnactCore {
724
660
  }
725
661
  }
726
662
 
663
+ /**
664
+ * Instance method wrapper for backward compatibility
665
+ */
666
+ async getTools(
667
+ options: {
668
+ limit?: number;
669
+ offset?: number;
670
+ tags?: string[];
671
+ author?: string;
672
+ } = {},
673
+ ): Promise<EnactTool[]> {
674
+ return EnactCore.getTools(options, this.options);
675
+ }
676
+
727
677
  /**
728
678
  * Get authentication status (placeholder - would need actual auth implementation)
729
679
  */
@@ -741,22 +691,22 @@ export class EnactCore {
741
691
  }
742
692
 
743
693
  /**
744
- * Publish a tool (requires authentication)
694
+ * Static method to publish a tool
745
695
  */
746
- async publishTool(
696
+ static async publishTool(
747
697
  tool: EnactTool,
698
+ authToken: string,
699
+ coreOptions: Pick<EnactCoreOptions, 'apiUrl' | 'supabaseUrl'> = {}
748
700
  ): Promise<{ success: boolean; message: string }> {
749
- if (!this.options.authToken) {
750
- return {
751
- success: false,
752
- message: "Authentication required to publish tools",
753
- };
754
- }
701
+ const apiClient = new EnactApiClient(
702
+ coreOptions.apiUrl || "https://enact.tools",
703
+ coreOptions.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co"
704
+ );
755
705
 
756
706
  try {
757
707
  validateToolStructure(tool);
758
708
 
759
- await this.apiClient.publishTool(tool, this.options.authToken);
709
+ await apiClient.publishTool(tool, authToken);
760
710
 
761
711
  return {
762
712
  success: true,
@@ -770,11 +720,27 @@ export class EnactCore {
770
720
  }
771
721
  }
772
722
 
723
+ /**
724
+ * Instance method wrapper for backward compatibility
725
+ */
726
+ async publishTool(
727
+ tool: EnactTool,
728
+ ): Promise<{ success: boolean; message: string }> {
729
+ if (!this.options.authToken) {
730
+ return {
731
+ success: false,
732
+ message: "Authentication required to publish tools",
733
+ };
734
+ }
735
+
736
+ return EnactCore.publishTool(tool, this.options.authToken, this.options);
737
+ }
738
+
773
739
  /**
774
740
  * Get tool information (alias for getToolByName for consistency)
775
741
  */
776
742
  async getToolInfo(name: string, version?: string): Promise<EnactTool | null> {
777
- return this.getToolByName(name, version);
743
+ return EnactCore.getToolByName(name, version, this.options);
778
744
  }
779
745
 
780
746
  /**
@@ -783,7 +749,6 @@ export class EnactCore {
783
749
  async getStatus(): Promise<{
784
750
  executionProvider: string;
785
751
  apiUrl: string;
786
- verificationPolicy: string;
787
752
  defaultTimeout: string;
788
753
  authenticated: boolean;
789
754
  }> {
@@ -792,7 +757,6 @@ export class EnactCore {
792
757
  return {
793
758
  executionProvider: this.options.executionProvider || "direct",
794
759
  apiUrl: this.options.apiUrl || "https://enact.tools",
795
- verificationPolicy: this.options.verificationPolicy || "permissive",
796
760
  defaultTimeout: this.options.defaultTimeout || "30s",
797
761
  authenticated: authStatus.authenticated,
798
762
  };
@@ -829,5 +793,4 @@ export class EnactCore {
829
793
  }
830
794
  }
831
795
 
832
- // Export a default instance
833
- export const enactCore = new EnactCore();
796
+ // No default instance to avoid eager initialization of Dagger