@enactprotocol/shared 1.0.12

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 (97) hide show
  1. package/dist/LocalToolResolver.d.ts +84 -0
  2. package/dist/LocalToolResolver.js +353 -0
  3. package/dist/api/enact-api.d.ts +124 -0
  4. package/dist/api/enact-api.js +406 -0
  5. package/dist/api/index.d.ts +2 -0
  6. package/dist/api/index.js +2 -0
  7. package/dist/api/types.d.ts +83 -0
  8. package/dist/api/types.js +1 -0
  9. package/dist/core/DaggerExecutionProvider.d.ts +169 -0
  10. package/dist/core/DaggerExecutionProvider.js +996 -0
  11. package/dist/core/DirectExecutionProvider.d.ts +23 -0
  12. package/dist/core/DirectExecutionProvider.js +406 -0
  13. package/dist/core/EnactCore.d.ts +138 -0
  14. package/dist/core/EnactCore.js +609 -0
  15. package/dist/core/index.d.ts +3 -0
  16. package/dist/core/index.js +3 -0
  17. package/dist/exec/index.d.ts +3 -0
  18. package/dist/exec/index.js +3 -0
  19. package/dist/exec/logger.d.ts +11 -0
  20. package/dist/exec/logger.js +57 -0
  21. package/dist/exec/validate.d.ts +5 -0
  22. package/dist/exec/validate.js +167 -0
  23. package/dist/index.d.ts +25 -0
  24. package/dist/index.js +29 -0
  25. package/dist/lib/enact-direct.d.ts +156 -0
  26. package/dist/lib/enact-direct.js +158 -0
  27. package/dist/lib/index.d.ts +1 -0
  28. package/dist/lib/index.js +1 -0
  29. package/dist/security/index.d.ts +3 -0
  30. package/dist/security/index.js +3 -0
  31. package/dist/security/security.d.ts +23 -0
  32. package/dist/security/security.js +137 -0
  33. package/dist/security/sign.d.ts +103 -0
  34. package/dist/security/sign.js +532 -0
  35. package/dist/security/verification-enforcer.d.ts +41 -0
  36. package/dist/security/verification-enforcer.js +181 -0
  37. package/dist/services/McpCoreService.d.ts +102 -0
  38. package/dist/services/McpCoreService.js +120 -0
  39. package/dist/services/index.d.ts +1 -0
  40. package/dist/services/index.js +1 -0
  41. package/dist/types.d.ts +130 -0
  42. package/dist/types.js +3 -0
  43. package/dist/utils/config.d.ts +32 -0
  44. package/dist/utils/config.js +78 -0
  45. package/dist/utils/env-loader.d.ts +54 -0
  46. package/dist/utils/env-loader.js +270 -0
  47. package/dist/utils/help.d.ts +36 -0
  48. package/dist/utils/help.js +248 -0
  49. package/dist/utils/index.d.ts +7 -0
  50. package/dist/utils/index.js +7 -0
  51. package/dist/utils/logger.d.ts +35 -0
  52. package/dist/utils/logger.js +75 -0
  53. package/dist/utils/silent-monitor.d.ts +67 -0
  54. package/dist/utils/silent-monitor.js +242 -0
  55. package/dist/utils/timeout.d.ts +5 -0
  56. package/dist/utils/timeout.js +23 -0
  57. package/dist/utils/version.d.ts +4 -0
  58. package/dist/utils/version.js +14 -0
  59. package/dist/web/env-manager-server.d.ts +29 -0
  60. package/dist/web/env-manager-server.js +367 -0
  61. package/dist/web/index.d.ts +1 -0
  62. package/dist/web/index.js +1 -0
  63. package/package.json +79 -0
  64. package/src/LocalToolResolver.ts +424 -0
  65. package/src/api/enact-api.ts +569 -0
  66. package/src/api/index.ts +2 -0
  67. package/src/api/types.ts +93 -0
  68. package/src/core/DaggerExecutionProvider.ts +1308 -0
  69. package/src/core/DirectExecutionProvider.ts +484 -0
  70. package/src/core/EnactCore.ts +833 -0
  71. package/src/core/index.ts +3 -0
  72. package/src/exec/index.ts +3 -0
  73. package/src/exec/logger.ts +63 -0
  74. package/src/exec/validate.ts +238 -0
  75. package/src/index.ts +42 -0
  76. package/src/lib/enact-direct.ts +258 -0
  77. package/src/lib/index.ts +1 -0
  78. package/src/security/index.ts +3 -0
  79. package/src/security/security.ts +188 -0
  80. package/src/security/sign.ts +797 -0
  81. package/src/security/verification-enforcer.ts +268 -0
  82. package/src/services/McpCoreService.ts +203 -0
  83. package/src/services/index.ts +1 -0
  84. package/src/types.ts +190 -0
  85. package/src/utils/config.ts +97 -0
  86. package/src/utils/env-loader.ts +370 -0
  87. package/src/utils/help.ts +257 -0
  88. package/src/utils/index.ts +7 -0
  89. package/src/utils/logger.ts +83 -0
  90. package/src/utils/silent-monitor.ts +328 -0
  91. package/src/utils/timeout.ts +26 -0
  92. package/src/utils/version.ts +16 -0
  93. package/src/web/env-manager-server.ts +465 -0
  94. package/src/web/index.ts +1 -0
  95. package/src/web/static/app.js +663 -0
  96. package/src/web/static/index.html +117 -0
  97. package/src/web/static/style.css +291 -0
@@ -0,0 +1,609 @@
1
+ import { EnactApiClient } from "../api/enact-api.js";
2
+ import { verifyCommandSafety, sanitizeEnvironmentVariables, } from "../security/security.js";
3
+ import { validateToolStructure, validateInputs, validateOutput, } from "../exec/validate.js";
4
+ import { DirectExecutionProvider } from "./DirectExecutionProvider.js";
5
+ import { DaggerExecutionProvider } from "./DaggerExecutionProvider.js";
6
+ import { resolveToolEnvironmentVariables } from "../utils/env-loader.js";
7
+ import logger from "../exec/logger.js";
8
+ import yaml from "yaml";
9
+ import { verifyTool as verifyToolSignatureWithPolicy, VERIFICATION_POLICIES, } from "../security/sign.js";
10
+ import { enforceSignatureVerification, createVerificationFailureResult, logSecurityAudit, } from "../security/verification-enforcer.js";
11
+ import fs from "fs";
12
+ import path from "path";
13
+ export class EnactCore {
14
+ constructor(options = {}) {
15
+ this.options = {
16
+ apiUrl: "https://enact.tools",
17
+ supabaseUrl: "https://xjnhhxwxovjifdxdwzih.supabase.co",
18
+ executionProvider: "direct",
19
+ defaultTimeout: "30s",
20
+ verificationPolicy: "permissive",
21
+ ...options,
22
+ };
23
+ this.apiClient = new EnactApiClient(this.options.apiUrl, this.options.supabaseUrl);
24
+ // Initialize the appropriate execution provider
25
+ this.executionProvider = this.createExecutionProvider();
26
+ }
27
+ /**
28
+ * Set authentication token for API operations
29
+ */
30
+ setAuthToken(token) {
31
+ this.options.authToken = token;
32
+ }
33
+ /**
34
+ * Search for tools
35
+ */
36
+ async searchTools(options) {
37
+ try {
38
+ logger.info(`Searching for tools with query: "${options.query}"`);
39
+ const searchParams = {
40
+ query: options.query,
41
+ limit: options.limit,
42
+ tags: options.tags,
43
+ };
44
+ const results = await this.apiClient.searchTools(searchParams);
45
+ // Parse and validate results
46
+ const tools = [];
47
+ for (const result of results) {
48
+ if (result.name) {
49
+ try {
50
+ const tool = await this.getToolByName(result.name);
51
+ if (tool) {
52
+ tools.push(tool);
53
+ }
54
+ }
55
+ catch (error) {
56
+ logger.warn(`Failed to fetch tool ${result.name}:`, error);
57
+ }
58
+ }
59
+ }
60
+ logger.info(`Found ${tools.length} tools`);
61
+ return tools;
62
+ }
63
+ catch (error) {
64
+ logger.error("Error searching tools:", error);
65
+ // If it's a 502 error (API server issue), try fallback to local filtering
66
+ if (error instanceof Error && error.message.includes("502")) {
67
+ logger.info("Search API unavailable, trying fallback to local filtering...");
68
+ return this.searchToolsFallback(options);
69
+ }
70
+ throw new Error(`Search failed: ${error instanceof Error ? error.message : String(error)}`);
71
+ }
72
+ }
73
+ /**
74
+ * Fallback search method that gets all tools and filters locally
75
+ */
76
+ async searchToolsFallback(options) {
77
+ try {
78
+ logger.info("Using fallback search method...");
79
+ // Get all tools (limited to avoid overwhelming the API)
80
+ const allTools = await this.apiClient.getTools({
81
+ limit: options.limit || 100,
82
+ });
83
+ // Filter tools locally based on search criteria
84
+ const filteredTools = [];
85
+ const query = options.query.toLowerCase();
86
+ for (const result of allTools) {
87
+ if (result.name) {
88
+ try {
89
+ const tool = await this.getToolByName(result.name);
90
+ if (tool) {
91
+ // Check if tool matches search criteria
92
+ const matchesQuery = tool.name.toLowerCase().includes(query) ||
93
+ (tool.description &&
94
+ tool.description.toLowerCase().includes(query)) ||
95
+ (tool.tags &&
96
+ tool.tags.some((tag) => tag.toLowerCase().includes(query)));
97
+ const matchesTags = !options.tags ||
98
+ !options.tags.length ||
99
+ (tool.tags &&
100
+ options.tags.some((searchTag) => tool.tags.some((toolTag) => toolTag.toLowerCase().includes(searchTag.toLowerCase()))));
101
+ const matchesAuthor = !options.author ||
102
+ (tool.authors &&
103
+ tool.authors.some((author) => author.name &&
104
+ author.name
105
+ .toLowerCase()
106
+ .includes(options.author.toLowerCase())));
107
+ if (matchesQuery && matchesTags && matchesAuthor) {
108
+ filteredTools.push(tool);
109
+ // Apply limit if specified
110
+ if (options.limit && filteredTools.length >= options.limit) {
111
+ break;
112
+ }
113
+ }
114
+ }
115
+ }
116
+ catch (error) {
117
+ logger.warn(`Failed to fetch tool ${result.name} in fallback search:`, error);
118
+ }
119
+ }
120
+ }
121
+ logger.info(`Fallback search found ${filteredTools.length} tools`);
122
+ return filteredTools;
123
+ }
124
+ catch (fallbackError) {
125
+ logger.error("Fallback search also failed:", fallbackError);
126
+ throw new Error(`Search failed (including fallback): ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`);
127
+ }
128
+ }
129
+ /**
130
+ * Get a specific tool by name
131
+ */
132
+ async getToolByName(name, version) {
133
+ try {
134
+ logger.info(`Fetching tool: ${name}${version ? `@${version}` : ""}`);
135
+ const response = await this.apiClient.getTool(name);
136
+ if (!response) {
137
+ logger.info(`Tool not found: ${name}`);
138
+ return null;
139
+ }
140
+ // Parse tool from response
141
+ let tool;
142
+ if (response.content && typeof response.content === "string") {
143
+ tool = yaml.parse(response.content);
144
+ }
145
+ else if (response.raw_content &&
146
+ typeof response.raw_content === "string") {
147
+ try {
148
+ tool = JSON.parse(response.raw_content);
149
+ }
150
+ catch {
151
+ tool = yaml.parse(response.raw_content);
152
+ }
153
+ // Merge signature information
154
+ if (response.signature || response.signatures) {
155
+ tool.signature = response.signature;
156
+ tool.signatures = response.signatures;
157
+ }
158
+ }
159
+ else {
160
+ // Map database fields to tool format
161
+ tool = {
162
+ name: response.name,
163
+ description: response.description,
164
+ command: response.command,
165
+ timeout: response.timeout || "30s",
166
+ tags: response.tags || [],
167
+ license: response.license || response.spdx_license,
168
+ outputSchema: response.output_schema || response.outputSchema,
169
+ enact: response.protocol_version || response.enact || "1.0.0",
170
+ version: response.version,
171
+ inputSchema: response.input_schema || response.inputSchema,
172
+ examples: response.examples,
173
+ annotations: response.annotations,
174
+ env: response.env_vars || response.env,
175
+ resources: response.resources,
176
+ signature: response.signature,
177
+ signatures: response.signatures,
178
+ namespace: response.namespace,
179
+ };
180
+ }
181
+ logger.info(`Successfully fetched tool: ${tool.name}`);
182
+ return tool;
183
+ }
184
+ catch (error) {
185
+ if (error instanceof Error && error.message.includes("404")) {
186
+ logger.info(`Tool not found: ${name}`);
187
+ return null;
188
+ }
189
+ logger.error(`Error fetching tool: ${error instanceof Error ? error.message : String(error)}`);
190
+ throw error;
191
+ }
192
+ }
193
+ /**
194
+ * Execute a tool by name
195
+ */
196
+ async executeToolByName(name, inputs = {}, options = {}) {
197
+ const executionId = this.generateExecutionId();
198
+ try {
199
+ // Fetch the tool
200
+ const tool = await this.getToolByName(name);
201
+ if (!tool) {
202
+ return {
203
+ success: false,
204
+ error: {
205
+ message: `Tool not found: ${name}`,
206
+ code: "NOT_FOUND",
207
+ },
208
+ metadata: {
209
+ executionId,
210
+ toolName: name,
211
+ executedAt: new Date().toISOString(),
212
+ environment: "direct",
213
+ },
214
+ };
215
+ }
216
+ // Execute the tool
217
+ return await this.executeTool(tool, inputs, options);
218
+ }
219
+ catch (error) {
220
+ return {
221
+ success: false,
222
+ error: {
223
+ message: error.message,
224
+ code: "EXECUTION_ERROR",
225
+ },
226
+ metadata: {
227
+ executionId,
228
+ toolName: name,
229
+ executedAt: new Date().toISOString(),
230
+ environment: "direct",
231
+ },
232
+ };
233
+ }
234
+ }
235
+ /**
236
+ * Execute a tool directly
237
+ */
238
+ async executeTool(tool, inputs = {}, options = {}) {
239
+ const executionId = this.generateExecutionId();
240
+ try {
241
+ logger.info(`Executing tool: ${tool.name}`);
242
+ // Validate tool structure
243
+ validateToolStructure(tool);
244
+ // MANDATORY SIGNATURE VERIFICATION - All tools must be verified before execution
245
+ const verificationResult = await enforceSignatureVerification(tool, {
246
+ skipVerification: options.skipVerification,
247
+ verifyPolicy: options.verifyPolicy,
248
+ force: options.force,
249
+ allowUnsigned: false, // Never allow unsigned tools in production
250
+ });
251
+ // Log security audit information
252
+ logSecurityAudit(tool, verificationResult, verificationResult.allowed, {
253
+ skipVerification: options.skipVerification,
254
+ verifyPolicy: options.verifyPolicy,
255
+ force: options.force,
256
+ });
257
+ // Block execution if verification fails
258
+ if (!verificationResult.allowed) {
259
+ return createVerificationFailureResult(tool, verificationResult, executionId);
260
+ }
261
+ // Validate inputs
262
+ const validatedInputs = validateInputs(tool, inputs);
263
+ // Check command safety
264
+ const safetyCheck = verifyCommandSafety(tool.command, tool);
265
+ if (!safetyCheck.isSafe && !options.force) {
266
+ return {
267
+ success: false,
268
+ error: {
269
+ message: `Unsafe command blocked: ${safetyCheck.blocked?.join(", ")}`,
270
+ code: "COMMAND_UNSAFE",
271
+ details: safetyCheck,
272
+ },
273
+ metadata: {
274
+ executionId,
275
+ toolName: tool.name,
276
+ version: tool.version,
277
+ executedAt: new Date().toISOString(),
278
+ environment: "direct",
279
+ command: tool.command,
280
+ },
281
+ };
282
+ }
283
+ // Log warnings
284
+ if (safetyCheck.warnings.length > 0) {
285
+ safetyCheck.warnings.forEach((warning) => logger.warn(warning));
286
+ }
287
+ // Dry run - just validate and return
288
+ if (options.dryRun) {
289
+ return {
290
+ success: true,
291
+ output: {
292
+ dryRun: true,
293
+ tool: tool.name,
294
+ command: tool.command,
295
+ inputs: validatedInputs,
296
+ safetyCheck,
297
+ },
298
+ metadata: {
299
+ executionId,
300
+ toolName: tool.name,
301
+ version: tool.version,
302
+ executedAt: new Date().toISOString(),
303
+ environment: "direct",
304
+ command: tool.command,
305
+ },
306
+ };
307
+ }
308
+ // Setup execution environment
309
+ // Load package environment variables from .env files
310
+ const envResult = await resolveToolEnvironmentVariables(tool.name, tool.env);
311
+ // Log any missing required environment variables
312
+ if (envResult.missing.length > 0) {
313
+ logger.warn(`Missing required environment variables: ${envResult.missing.join(", ")}`);
314
+ }
315
+ const environment = {
316
+ vars: {
317
+ ...envResult.resolved,
318
+ ...sanitizeEnvironmentVariables(validatedInputs),
319
+ },
320
+ resources: tool.resources,
321
+ namespace: tool.namespace,
322
+ };
323
+ // Setup execution provider
324
+ await this.executionProvider.setup(tool);
325
+ // Execute the tool
326
+ const result = await this.executionProvider.execute(tool, validatedInputs, environment);
327
+ // Validate output if schema is provided
328
+ if (result.success && result.output && tool.outputSchema) {
329
+ try {
330
+ result.output = validateOutput(tool, result.output);
331
+ }
332
+ catch (error) {
333
+ logger.warn(`Output validation failed: ${error.message}`);
334
+ }
335
+ }
336
+ logger.info(`Tool execution completed: ${tool.name} (success: ${result.success})`);
337
+ return result;
338
+ }
339
+ catch (error) {
340
+ logger.error(`Error executing tool: ${error.message}`);
341
+ return {
342
+ success: false,
343
+ error: {
344
+ message: error.message,
345
+ code: "EXECUTION_ERROR",
346
+ details: error,
347
+ },
348
+ metadata: {
349
+ executionId,
350
+ toolName: tool.name,
351
+ version: tool.version,
352
+ executedAt: new Date().toISOString(),
353
+ environment: "direct",
354
+ command: tool.command,
355
+ },
356
+ };
357
+ }
358
+ finally {
359
+ // Cleanup
360
+ try {
361
+ await this.executionProvider.cleanup();
362
+ }
363
+ catch (cleanupError) {
364
+ logger.error("Error during cleanup:", cleanupError);
365
+ }
366
+ }
367
+ }
368
+ /**
369
+ * Execute a tool from raw YAML definition
370
+ */
371
+ async executeRawTool(toolYaml, inputs = {}, options = {}) {
372
+ try {
373
+ // Parse the YAML
374
+ const tool = yaml.parse(toolYaml);
375
+ // Validate that it's a proper tool definition
376
+ if (!tool || typeof tool !== "object") {
377
+ throw new Error("Invalid tool definition: YAML must contain a tool object");
378
+ }
379
+ // Check for required fields
380
+ if (!tool.name || !tool.description || !tool.command) {
381
+ throw new Error("Invalid tool definition: missing required fields (name, description, command)");
382
+ }
383
+ // Execute the tool
384
+ return await this.executeTool(tool, inputs, options);
385
+ }
386
+ catch (error) {
387
+ const executionId = this.generateExecutionId();
388
+ return {
389
+ success: false,
390
+ error: {
391
+ message: error.message,
392
+ code: "PARSE_ERROR",
393
+ },
394
+ metadata: {
395
+ executionId,
396
+ toolName: "unknown",
397
+ executedAt: new Date().toISOString(),
398
+ environment: "direct",
399
+ },
400
+ };
401
+ }
402
+ }
403
+ /**
404
+ * Verify a tool's signature
405
+ */
406
+ async verifyTool(name, policy) {
407
+ try {
408
+ const tool = await this.getToolByName(name);
409
+ if (!tool) {
410
+ return {
411
+ verified: false,
412
+ signatures: [],
413
+ policy: policy || "permissive",
414
+ errors: [`Tool not found: ${name}`],
415
+ };
416
+ }
417
+ // Load public key from keys/file-public.pem
418
+ let publicKey;
419
+ try {
420
+ const keyPath = path.resolve(__dirname, "../../keys/file-public.pem");
421
+ publicKey = fs.readFileSync(keyPath, "utf8");
422
+ }
423
+ catch (e) {
424
+ logger.warn("Could not load public key for signature verification:", e);
425
+ }
426
+ if (!publicKey) {
427
+ return {
428
+ verified: false,
429
+ signatures: [],
430
+ policy: policy || "permissive",
431
+ errors: ["Public key not found for signature verification"],
432
+ };
433
+ }
434
+ const policyKey = (policy || "permissive").toUpperCase();
435
+ const policyObj = VERIFICATION_POLICIES[policyKey];
436
+ const verificationResult = await verifyToolSignatureWithPolicy(tool, policyObj);
437
+ if (!verificationResult.isValid) {
438
+ return {
439
+ verified: false,
440
+ signatures: [],
441
+ policy: policy || "permissive",
442
+ errors: verificationResult.errors,
443
+ };
444
+ }
445
+ const signatures = [];
446
+ if (tool.signature) {
447
+ signatures.push(tool.signature);
448
+ }
449
+ if (tool.signatures) {
450
+ signatures.push(...Object.values(tool.signatures));
451
+ }
452
+ return {
453
+ verified: verificationResult.isValid,
454
+ signatures,
455
+ policy: policy || "permissive",
456
+ };
457
+ }
458
+ catch (error) {
459
+ return {
460
+ verified: false,
461
+ signatures: [],
462
+ policy: policy || "permissive",
463
+ errors: [`Verification error: ${error.message}`],
464
+ };
465
+ }
466
+ }
467
+ /**
468
+ * Check if a tool exists
469
+ */
470
+ async toolExists(name) {
471
+ try {
472
+ const tool = await this.getToolByName(name);
473
+ return tool !== null;
474
+ }
475
+ catch (error) {
476
+ return false;
477
+ }
478
+ }
479
+ /**
480
+ * Get tools by tags
481
+ */
482
+ async getToolsByTags(tags, limit = 20) {
483
+ return this.searchTools({
484
+ query: tags.join(" "),
485
+ tags,
486
+ limit,
487
+ });
488
+ }
489
+ /**
490
+ * Get tools by author
491
+ */
492
+ async getToolsByAuthor(author, limit = 20) {
493
+ return this.searchTools({
494
+ query: `author:${author}`,
495
+ author,
496
+ limit,
497
+ });
498
+ }
499
+ /**
500
+ * Get all tools with filters
501
+ */
502
+ async getTools(options = {}) {
503
+ try {
504
+ const apiResults = await this.apiClient.getTools(options);
505
+ // Parse and validate results
506
+ const tools = [];
507
+ for (const result of apiResults) {
508
+ if (result.name) {
509
+ try {
510
+ const tool = await this.getToolByName(result.name);
511
+ if (tool) {
512
+ tools.push(tool);
513
+ }
514
+ }
515
+ catch (error) {
516
+ logger.warn(`Failed to fetch tool ${result.name}:`, error);
517
+ }
518
+ }
519
+ }
520
+ return tools;
521
+ }
522
+ catch (error) {
523
+ logger.error("Error getting tools:", error);
524
+ throw new Error(`Failed to get tools: ${error instanceof Error ? error.message : String(error)}`);
525
+ }
526
+ }
527
+ /**
528
+ * Get authentication status (placeholder - would need actual auth implementation)
529
+ */
530
+ async getAuthStatus() {
531
+ // This would need to check actual auth state
532
+ // For now, return based on whether we have a token
533
+ return {
534
+ authenticated: !!this.options.authToken,
535
+ server: this.options.apiUrl,
536
+ };
537
+ }
538
+ /**
539
+ * Publish a tool (requires authentication)
540
+ */
541
+ async publishTool(tool) {
542
+ if (!this.options.authToken) {
543
+ return {
544
+ success: false,
545
+ message: "Authentication required to publish tools",
546
+ };
547
+ }
548
+ try {
549
+ validateToolStructure(tool);
550
+ await this.apiClient.publishTool(tool, this.options.authToken);
551
+ return {
552
+ success: true,
553
+ message: `Successfully published tool: ${tool.name}`,
554
+ };
555
+ }
556
+ catch (error) {
557
+ return {
558
+ success: false,
559
+ message: `Failed to publish tool: ${error instanceof Error ? error.message : String(error)}`,
560
+ };
561
+ }
562
+ }
563
+ /**
564
+ * Get tool information (alias for getToolByName for consistency)
565
+ */
566
+ async getToolInfo(name, version) {
567
+ return this.getToolByName(name, version);
568
+ }
569
+ /**
570
+ * Get core library status
571
+ */
572
+ async getStatus() {
573
+ const authStatus = await this.getAuthStatus();
574
+ return {
575
+ executionProvider: this.options.executionProvider || "direct",
576
+ apiUrl: this.options.apiUrl || "https://enact.tools",
577
+ verificationPolicy: this.options.verificationPolicy || "permissive",
578
+ defaultTimeout: this.options.defaultTimeout || "30s",
579
+ authenticated: authStatus.authenticated,
580
+ };
581
+ }
582
+ /**
583
+ * Create the appropriate execution provider based on options
584
+ */
585
+ createExecutionProvider() {
586
+ switch (this.options.executionProvider) {
587
+ case "dagger":
588
+ return new DaggerExecutionProvider(this.options.daggerOptions);
589
+ case "direct":
590
+ default:
591
+ return new DirectExecutionProvider();
592
+ }
593
+ }
594
+ /**
595
+ * Switch execution provider at runtime
596
+ */
597
+ switchExecutionProvider(provider, options) {
598
+ this.options.executionProvider = provider;
599
+ this.executionProvider = this.createExecutionProvider();
600
+ }
601
+ /**
602
+ * Generate execution ID
603
+ */
604
+ generateExecutionId() {
605
+ return `exec_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
606
+ }
607
+ }
608
+ // Export a default instance
609
+ export const enactCore = new EnactCore();
@@ -0,0 +1,3 @@
1
+ export * from './EnactCore';
2
+ export * from './DirectExecutionProvider';
3
+ export * from './DaggerExecutionProvider';
@@ -0,0 +1,3 @@
1
+ export * from './EnactCore';
2
+ export * from './DirectExecutionProvider';
3
+ export * from './DaggerExecutionProvider';
@@ -0,0 +1,3 @@
1
+ export { default } from './logger';
2
+ export { default as logger } from './logger';
3
+ export * from './validate';
@@ -0,0 +1,3 @@
1
+ export { default } from './logger';
2
+ export { default as logger } from './logger';
3
+ export * from './validate';
@@ -0,0 +1,11 @@
1
+ declare const logger: import("pino").Logger<never, boolean>;
2
+ declare const wrappedLogger: {
3
+ info: (msg: string, ...args: any[]) => void;
4
+ warn: (msg: string, ...args: any[]) => void;
5
+ error: (msg: string, ...args: any[]) => void;
6
+ debug: (msg: string, ...args: any[]) => void;
7
+ clientLoggingEnabled: () => boolean;
8
+ isLevelEnabled: (level: string) => boolean;
9
+ pino: import("pino").Logger<never, boolean>;
10
+ };
11
+ export default wrappedLogger;
@@ -0,0 +1,57 @@
1
+ import pino from "pino";
2
+ // Determine if the environment is silent (e.g., CI, testing, or specific env var)
3
+ const isSilentMode = () => process.env.CI === "true" ||
4
+ process.env.NODE_ENV === "test" ||
5
+ process.env.ENACT_SILENT === "true" ||
6
+ process.env.ENACT_SKIP_INTERACTIVE === "true";
7
+ // Base logger configuration
8
+ const logger = pino({
9
+ level: process.env.LOG_LEVEL || "info",
10
+ // In tests, we don't want the pretty transport, as it adds noise.
11
+ // The output is captured anyway.
12
+ ...(process.env.NODE_ENV !== "test" && {
13
+ transport: {
14
+ target: "pino-pretty",
15
+ options: {
16
+ colorize: true,
17
+ ignore: "pid,hostname",
18
+ translateTime: "SYS:standard",
19
+ },
20
+ },
21
+ }),
22
+ });
23
+ // Wrapper to dynamically check silent mode on each call
24
+ const wrappedLogger = {
25
+ info: (...args) => {
26
+ if (!isSilentMode()) {
27
+ logger.info(...args);
28
+ }
29
+ },
30
+ warn: (...args) => {
31
+ if (!isSilentMode()) {
32
+ logger.warn(...args);
33
+ }
34
+ },
35
+ error: (...args) => {
36
+ // The silent tests expect errors to be silent too.
37
+ if (!isSilentMode()) {
38
+ logger.error(...args);
39
+ }
40
+ },
41
+ debug: (...args) => {
42
+ if (!isSilentMode() && (process.env.DEBUG || process.env.VERBOSE)) {
43
+ logger.debug(...args);
44
+ }
45
+ },
46
+ // Expose a way to check if client logging is enabled (for MCP)
47
+ clientLoggingEnabled: () => !process.env.ENACT_MCP_CLIENT,
48
+ isLevelEnabled: (level) => {
49
+ if (isSilentMode()) {
50
+ return false;
51
+ }
52
+ return logger.isLevelEnabled(level);
53
+ },
54
+ // Keep original pino instance available if needed
55
+ pino: logger,
56
+ };
57
+ export default wrappedLogger;