@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,97 @@
1
+ // src/utils/config.ts
2
+ import { homedir } from "os";
3
+ import { join } from "path";
4
+ import { existsSync } from "fs";
5
+ import { mkdir, readFile, writeFile } from "fs/promises";
6
+
7
+ // Define config paths
8
+ const CONFIG_DIR = join(homedir(), ".enact");
9
+ const CONFIG_FILE = join(CONFIG_DIR, "config.json");
10
+
11
+ // Define config interface
12
+ export interface EnactConfig {
13
+ defaultUrl?: string;
14
+ history?: string[];
15
+ }
16
+
17
+ /**
18
+ * Ensure config directory and file exist
19
+ */
20
+ export async function ensureConfig(): Promise<void> {
21
+ if (!existsSync(CONFIG_DIR)) {
22
+ await mkdir(CONFIG_DIR, { recursive: true });
23
+ }
24
+
25
+ if (!existsSync(CONFIG_FILE)) {
26
+ await writeConfig({ history: [] });
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Read the config file
32
+ */
33
+ export async function readConfig(): Promise<EnactConfig> {
34
+ await ensureConfig();
35
+
36
+ try {
37
+ const data = await readFile(CONFIG_FILE, "utf8");
38
+ return JSON.parse(data) as EnactConfig;
39
+ } catch (error) {
40
+ console.error("Failed to read config:", (error as Error).message);
41
+ return { history: [] };
42
+ }
43
+ }
44
+
45
+ /**
46
+ * Write to the config file
47
+ */
48
+ export async function writeConfig(config: EnactConfig): Promise<void> {
49
+ await ensureConfig();
50
+ await writeFile(CONFIG_FILE, JSON.stringify(config, null, 2));
51
+ }
52
+
53
+ /**
54
+ * Add a file to the publish history
55
+ */
56
+ export async function addToHistory(filePath: string): Promise<void> {
57
+ const config = await readConfig();
58
+
59
+ if (!config.history) {
60
+ config.history = [];
61
+ }
62
+
63
+ // Add to history if not already there
64
+ if (!config.history.includes(filePath)) {
65
+ config.history.unshift(filePath);
66
+
67
+ // Keep history to a reasonable size
68
+ config.history = config.history.slice(0, 10);
69
+
70
+ await writeConfig(config);
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Get the publish history
76
+ */
77
+ export async function getHistory(): Promise<string[]> {
78
+ const config = await readConfig();
79
+ return config.history || [];
80
+ }
81
+
82
+ /**
83
+ * Set the default publish URL
84
+ */
85
+ export async function setDefaultUrl(url: string): Promise<void> {
86
+ const config = await readConfig();
87
+ config.defaultUrl = url;
88
+ await writeConfig(config);
89
+ }
90
+
91
+ /**
92
+ * Get the default publish URL
93
+ */
94
+ export async function getDefaultUrl(): Promise<string | undefined> {
95
+ const config = await readConfig();
96
+ return config.defaultUrl;
97
+ }
@@ -0,0 +1,370 @@
1
+ // src/utils/env-loader.ts - Environment variable loader for Enact tools with package namespace support
2
+ import { join } from "path";
3
+ import { homedir } from "os";
4
+ import { existsSync } from "fs";
5
+ import { readFile } from "fs/promises";
6
+ import { config as loadDotenv } from "dotenv";
7
+
8
+ interface EnvVariable {
9
+ value: string;
10
+ description?: string;
11
+ source?: string;
12
+ required?: boolean;
13
+ encrypted?: boolean;
14
+ createdAt: string;
15
+ updatedAt: string;
16
+ }
17
+
18
+ interface PackageEnvConfig {
19
+ variables: Record<string, EnvVariable>;
20
+ }
21
+
22
+ // Configuration paths
23
+ const CONFIG_DIR = join(homedir(), ".enact");
24
+
25
+ /**
26
+ * Extract package namespace from tool name (excluding tool name)
27
+ * e.g., "kgroves88/dagger/social/bluesky-poster" -> "kgroves88/dagger/social"
28
+ */
29
+ function extractPackageNamespace(toolName: string): string {
30
+ const parts = toolName.split("/");
31
+ if (parts.length < 2) {
32
+ throw new Error(
33
+ 'Tool name must be in format "org/package" or "org/package/tool"',
34
+ );
35
+ }
36
+
37
+ // Use all path parts except the last one (tool name)
38
+ // For tools like "kgroves88/dagger/social/bluesky-poster",
39
+ // we want the package path "kgroves88/dagger/social"
40
+ if (parts.length >= 2) {
41
+ return parts.slice(0, -1).join("/");
42
+ }
43
+
44
+ return parts[0]; // fallback for edge cases
45
+ }
46
+
47
+ /**
48
+ * Get the environment file path for a package namespace
49
+ */
50
+ function getPackageEnvPath(packageNamespace: string): string {
51
+ return join(CONFIG_DIR, "env", packageNamespace, ".env");
52
+ }
53
+
54
+ /**
55
+ * Simple decryption for encrypted values
56
+ */
57
+ function decryptValue(encryptedValue: string): string {
58
+ try {
59
+ return Buffer.from(encryptedValue, "base64").toString("utf8");
60
+ } catch {
61
+ return encryptedValue; // Return as-is if decryption fails
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Read environment configuration for a package namespace
67
+ */
68
+ async function readPackageEnvConfig(
69
+ packageNamespace: string,
70
+ ): Promise<PackageEnvConfig> {
71
+ const envFile = getPackageEnvPath(packageNamespace);
72
+
73
+ if (!existsSync(envFile)) {
74
+ return { variables: {} };
75
+ }
76
+
77
+ try {
78
+ const data = await readFile(envFile, "utf8");
79
+
80
+ // Check if it's a simple .env file (KEY=value format) or JSON
81
+ if (data.trim().startsWith("{")) {
82
+ // It's JSON format (legacy package-managed variables)
83
+ return JSON.parse(data) as PackageEnvConfig;
84
+ } else {
85
+ // It's simple .env format (project mode), return empty since these are handled separately
86
+ return { variables: {} };
87
+ }
88
+ } catch (error) {
89
+ // Only warn if it's not a simple .env file parsing issue
90
+ if (!(error as Error).message.includes("Unexpected token")) {
91
+ console.warn(
92
+ `Failed to read env config from ${envFile}: ${(error as Error).message}`,
93
+ );
94
+ }
95
+ return { variables: {} };
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Load environment variables from Enact configuration for a specific package namespace
101
+ */
102
+ export async function loadPackageEnvironmentVariables(
103
+ packageNamespace: string,
104
+ ): Promise<Record<string, string>> {
105
+ const config = await readPackageEnvConfig(packageNamespace);
106
+ const envVars: Record<string, string> = {};
107
+
108
+ // Load variables from the package namespace
109
+ for (const [name, envVar] of Object.entries(config.variables)) {
110
+ const value = envVar.encrypted ? decryptValue(envVar.value) : envVar.value;
111
+ envVars[name] = value;
112
+ }
113
+
114
+ return envVars;
115
+ }
116
+
117
+ /**
118
+ * Load environment variables from a package-based .env file
119
+ */
120
+ function loadPackageEnvFile(toolName: string): Record<string, string> {
121
+ if (!toolName) {
122
+ return {};
123
+ }
124
+
125
+ try {
126
+ const packageNamespace = extractPackageNamespace(toolName);
127
+ const packageEnvPath = getPackageEnvPath(packageNamespace);
128
+
129
+ if (!existsSync(packageEnvPath)) {
130
+ return {};
131
+ }
132
+
133
+ // Load .env file and return the parsed variables
134
+ const result = loadDotenv({ path: packageEnvPath });
135
+ return result.parsed || {};
136
+ } catch (error) {
137
+ console.warn(
138
+ `Warning: Failed to load package .env file: ${(error as Error).message}`,
139
+ );
140
+ return {};
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Resolve environment variables for a tool definition with package namespace support
146
+ * Combines system environment, Enact package configuration, and tool-specific requirements
147
+ * Following the Enact protocol format:
148
+ * env:
149
+ * VARIABLE_NAME:
150
+ * description: string
151
+ * source: string
152
+ * required: boolean
153
+ * default: string (optional)
154
+ */
155
+ export async function resolveToolEnvironmentVariables(
156
+ toolName: string,
157
+ toolEnvConfig?: Record<string, any>,
158
+ ): Promise<{
159
+ resolved: Record<string, string>;
160
+ missing: string[];
161
+ configLink?: string;
162
+ }> {
163
+ // Start with system environment variables
164
+ const resolved: Record<string, string> = { ...process.env } as Record<
165
+ string,
166
+ string
167
+ >;
168
+
169
+ // Load package .env file (if it exists) - priority 2
170
+ const packageEnvVars = loadPackageEnvFile(toolName);
171
+ Object.assign(resolved, packageEnvVars);
172
+
173
+ // Load package-specific environment variables if we have a tool name - priority 3 (highest)
174
+ if (toolName) {
175
+ try {
176
+ const packageNamespace = extractPackageNamespace(toolName);
177
+ const packageJsonEnvVars =
178
+ await loadPackageEnvironmentVariables(packageNamespace);
179
+
180
+ // Override with package-managed JSON variables (highest priority)
181
+ Object.assign(resolved, packageJsonEnvVars);
182
+ } catch (error) {
183
+ // If we can't extract package namespace, continue without package env vars
184
+ console.warn(
185
+ `Warning: Could not load package environment variables: ${(error as Error).message}`,
186
+ );
187
+ }
188
+ }
189
+
190
+ const missing: string[] = [];
191
+
192
+ // Check tool-specific environment requirements following Enact protocol
193
+ if (toolEnvConfig) {
194
+ for (const [varName, config] of Object.entries(toolEnvConfig)) {
195
+ if (typeof config === "object" && config !== null) {
196
+ // Enact protocol: each env var has description, source, required, and optional default
197
+ const isRequired = config.required === true;
198
+ const defaultValue = config.default;
199
+ const source = config.source;
200
+
201
+ // Check if variable is already resolved
202
+ if (!(varName in resolved) || resolved[varName] === "") {
203
+ if (defaultValue !== undefined) {
204
+ resolved[varName] = String(defaultValue);
205
+ } else if (isRequired) {
206
+ missing.push(varName);
207
+ }
208
+ }
209
+
210
+ // Handle different sources as specified in the Enact protocol
211
+ if (source && resolved[varName]) {
212
+ // The source field tells us where the value should come from
213
+ // For now, we'll just ensure the variable is available
214
+ // In the future, this could be extended to support different sources
215
+ // like "user", "system", "config", etc.
216
+ }
217
+ }
218
+ }
219
+ }
220
+
221
+ // Generate and show configuration link if there are missing variables
222
+ let configLink: string | undefined;
223
+ if (missing.length > 0) {
224
+ configLink = generateConfigLink(missing, toolName) || undefined;
225
+ if (configLink) {
226
+ console.log(`\n🔧 Missing environment variables: ${missing.join(", ")}`);
227
+ console.log(`📋 Configure them here: ${configLink}\n`);
228
+ } else {
229
+ console.log(
230
+ `\n⚠️ Missing required environment variables: ${missing.join(", ")}`,
231
+ );
232
+ console.log(
233
+ `💡 Set them using the 'enact env set' command or your system environment\n`,
234
+ );
235
+ }
236
+ }
237
+
238
+ return { resolved, missing, configLink };
239
+ }
240
+
241
+ /**
242
+ * Get available environment variables for a package namespace
243
+ */
244
+ export async function getPackageEnvironmentVariables(
245
+ packageNamespace: string,
246
+ ): Promise<{
247
+ package: Record<
248
+ string,
249
+ { value: string; encrypted: boolean; description?: string }
250
+ >;
251
+ system: Record<string, string>;
252
+ }> {
253
+ const packageConfig = await readPackageEnvConfig(packageNamespace);
254
+
255
+ const packageVars: Record<
256
+ string,
257
+ { value: string; encrypted: boolean; description?: string }
258
+ > = {};
259
+
260
+ // Process package variables
261
+ for (const [name, envVar] of Object.entries(packageConfig.variables)) {
262
+ packageVars[name] = {
263
+ value: envVar.encrypted ? "[encrypted]" : envVar.value,
264
+ encrypted: envVar.encrypted || false,
265
+ description: envVar.description,
266
+ };
267
+ }
268
+
269
+ // System environment variables (filtered to avoid exposing sensitive data)
270
+ const system = Object.fromEntries(
271
+ Object.entries(process.env)
272
+ .filter(
273
+ ([key]) =>
274
+ // Only include environment variables that look like they might be relevant for tools
275
+ key.includes("API") ||
276
+ key.includes("TOKEN") ||
277
+ key.includes("KEY") ||
278
+ key.includes("URL") ||
279
+ key.includes("HOST") ||
280
+ key.includes("PORT") ||
281
+ key.startsWith("ENACT_") ||
282
+ key.startsWith("NODE_") ||
283
+ key.startsWith("NPM_"),
284
+ )
285
+ .map(([key, value]) => [key, value || ""]),
286
+ );
287
+
288
+ return { package: packageVars, system };
289
+ }
290
+
291
+ /**
292
+ * Validate that all required environment variables are available
293
+ * Following the Enact protocol format for environment variables
294
+ */
295
+ export function validateRequiredEnvironmentVariables(
296
+ toolEnvConfig: Record<string, any> | undefined,
297
+ availableVars: Record<string, string>,
298
+ ): { valid: boolean; missing: string[]; errors: string[] } {
299
+ const missing: string[] = [];
300
+ const errors: string[] = [];
301
+
302
+ if (!toolEnvConfig) {
303
+ return { valid: true, missing, errors };
304
+ }
305
+
306
+ for (const [varName, config] of Object.entries(toolEnvConfig)) {
307
+ if (typeof config === "object" && config !== null) {
308
+ // Enact protocol: description, source, required are all required fields
309
+ // default is optional
310
+ const isRequired = config.required === true;
311
+ const hasDefault = config.default !== undefined;
312
+ const description = config.description || "";
313
+ const source = config.source || "";
314
+
315
+ if (
316
+ isRequired &&
317
+ !hasDefault &&
318
+ (!(varName in availableVars) || availableVars[varName] === "")
319
+ ) {
320
+ missing.push(varName);
321
+ const errorMsg = `Required environment variable '${varName}' is not set`;
322
+ const detailMsg = description ? ` - ${description}` : "";
323
+ const sourceMsg = source ? ` (source: ${source})` : "";
324
+ errors.push(`${errorMsg}${detailMsg}${sourceMsg}`);
325
+ }
326
+ }
327
+ }
328
+
329
+ return {
330
+ valid: missing.length === 0,
331
+ missing,
332
+ errors,
333
+ };
334
+ }
335
+
336
+ // Export the package namespace extraction function for use in other modules
337
+ export { extractPackageNamespace };
338
+
339
+ // Load .env file if it exists
340
+ loadDotenv();
341
+
342
+ /**
343
+ * Get the web server URL if it's running
344
+ */
345
+ export function getWebServerUrl(): string | null {
346
+ // For now, default to localhost:5555 as that's the standard port
347
+ // When running via MCP (npx -p enact-cli enact-mcp), the web server is automatically started
348
+ // TODO: In the future, we could check if the server is actually responding or get the port dynamically
349
+ return "http://localhost:5555";
350
+ }
351
+
352
+ /**
353
+ * Generate a configuration link for missing environment variables
354
+ */
355
+ export function generateConfigLink(
356
+ missingVars: string[],
357
+ toolName: string,
358
+ ): string | null {
359
+ const webUrl = getWebServerUrl();
360
+ if (!webUrl) {
361
+ return null;
362
+ }
363
+
364
+ // Extract package namespace from tool name (exclude tool name itself)
365
+ const packageNamespace = extractPackageNamespace(toolName);
366
+
367
+ const encodedVars = encodeURIComponent(JSON.stringify(missingVars));
368
+ const encodedPackage = encodeURIComponent(packageNamespace);
369
+ return `${webUrl}/?vars=${encodedVars}&package=${encodedPackage}`;
370
+ }