@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,201 +0,0 @@
1
- // src/services/McpCoreService.ts - Direct core integration for MCP server
2
- import { EnactCore } from "../core/EnactCore";
3
- import type { EnactTool, ExecutionResult } from "../types";
4
- import type { ToolSearchOptions, ToolExecuteOptions } from "../core/EnactCore";
5
- import { getFrontendUrl, getApiUrl } from "../utils/config";
6
-
7
- export class McpCoreService {
8
- private core: EnactCore;
9
-
10
- constructor(options?: {
11
- apiUrl?: string;
12
- supabaseUrl?: string;
13
- authToken?: string;
14
- }) {
15
- this.core = new EnactCore({
16
- apiUrl: options?.apiUrl || "https://enact.tools",
17
- supabaseUrl: options?.supabaseUrl || "https://xjnhhxwxovjifdxdwzih.supabase.co",
18
- authToken: options?.authToken,
19
- });
20
- }
21
-
22
- /**
23
- * Create McpCoreService with config-based URLs
24
- */
25
- static async create(options?: {
26
- apiUrl?: string;
27
- supabaseUrl?: string;
28
- authToken?: string;
29
- }): Promise<McpCoreService> {
30
- const frontendUrl = options?.apiUrl || await getFrontendUrl();
31
- const apiUrl = options?.supabaseUrl || await getApiUrl();
32
-
33
- return new McpCoreService({
34
- ...options,
35
- apiUrl: frontendUrl,
36
- supabaseUrl: apiUrl,
37
- });
38
- }
39
-
40
- /**
41
- * Set authentication token
42
- */
43
- setAuthToken(token: string): void {
44
- this.core.setAuthToken(token);
45
- }
46
-
47
- /**
48
- * Search for tools
49
- */
50
- async searchTools(
51
- query: string,
52
- options?: {
53
- limit?: number;
54
- tags?: string[];
55
- author?: string;
56
- },
57
- ): Promise<EnactTool[]> {
58
- const searchOptions: ToolSearchOptions = {
59
- query,
60
- limit: options?.limit,
61
- tags: options?.tags,
62
- author: options?.author,
63
- };
64
-
65
- return await this.core.searchTools(searchOptions);
66
- }
67
-
68
- /**
69
- * Get a specific tool by name
70
- */
71
- async getToolInfo(name: string): Promise<EnactTool | null> {
72
- return await this.core.getToolByName(name);
73
- }
74
-
75
- /**
76
- * Execute a tool by name
77
- */
78
- async executeToolByName(
79
- name: string,
80
- inputs: Record<string, any> = {},
81
- options?: {
82
- timeout?: string;
83
- force?: boolean;
84
- dryRun?: boolean;
85
- },
86
- ): Promise<ExecutionResult> {
87
- const executeOptions: ToolExecuteOptions = {
88
- timeout: options?.timeout,
89
- force: options?.force,
90
- dryRun: options?.dryRun,
91
- };
92
-
93
- return await this.core.executeToolByName(name, inputs, executeOptions);
94
- }
95
-
96
- /**
97
- * Execute a tool from raw YAML definition
98
- */
99
- async executeRawTool(
100
- toolYaml: string,
101
- inputs: Record<string, any> = {},
102
- options?: {
103
- timeout?: string;
104
- force?: boolean;
105
- dryRun?: boolean;
106
- },
107
- ): Promise<ExecutionResult> {
108
- const executeOptions: ToolExecuteOptions = {
109
- timeout: options?.timeout,
110
- force: options?.force,
111
- dryRun: options?.dryRun,
112
- };
113
-
114
- return await this.core.executeRawTool(toolYaml, inputs, executeOptions);
115
- }
116
-
117
-
118
- /**
119
- * Check if a tool exists
120
- */
121
- async toolExists(name: string): Promise<boolean> {
122
- return await this.core.toolExists(name);
123
- }
124
-
125
- /**
126
- * Get tools by tags
127
- */
128
- async getToolsByTags(
129
- tags: string[],
130
- limit: number = 20,
131
- ): Promise<EnactTool[]> {
132
- return await this.core.getToolsByTags(tags, limit);
133
- }
134
-
135
- /**
136
- * Get tools by author
137
- */
138
- async getToolsByAuthor(
139
- author: string,
140
- limit: number = 20,
141
- ): Promise<EnactTool[]> {
142
- return await this.core.getToolsByAuthor(author, limit);
143
- }
144
-
145
- /**
146
- * Get all tools with filters
147
- */
148
- async getTools(options?: {
149
- limit?: number;
150
- offset?: number;
151
- tags?: string[];
152
- author?: string;
153
- }): Promise<EnactTool[]> {
154
- return await this.core.getTools(options);
155
- }
156
-
157
- /**
158
- * Get authentication status
159
- */
160
- async getAuthStatus(): Promise<{
161
- authenticated: boolean;
162
- user?: string;
163
- server?: string;
164
- }> {
165
- return await this.core.getAuthStatus();
166
- }
167
-
168
- /**
169
- * Check if service is available (always true for core service)
170
- */
171
- async isAvailable(): Promise<boolean> {
172
- return true;
173
- }
174
-
175
- /**
176
- * Get service path info (not applicable for core service)
177
- */
178
- async getPathInfo(): Promise<{
179
- detectedPath: string | null;
180
- isAvailable: boolean;
181
- version?: string;
182
- }> {
183
- return {
184
- detectedPath: "core-library",
185
- isAvailable: true,
186
- version: "2.0.0-core",
187
- };
188
- }
189
-
190
- /**
191
- * Publish a tool (requires authentication)
192
- */
193
- async publishTool(
194
- tool: EnactTool,
195
- ): Promise<{ success: boolean; message: string }> {
196
- return await this.core.publishTool(tool);
197
- }
198
- }
199
-
200
- // Create and export singleton instance
201
- export const mcpCoreService = new McpCoreService();
@@ -1 +0,0 @@
1
- export * from './McpCoreService';
@@ -1,438 +0,0 @@
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
- const TRUSTED_KEYS_DIR = join(CONFIG_DIR, "trusted-keys");
11
-
12
- // Define config interface
13
- export interface EnactConfig {
14
- defaultUrl?: string;
15
- history?: string[];
16
- urls?: {
17
- frontend?: string;
18
- api?: string;
19
- };
20
- }
21
-
22
- /**
23
- * Ensure config directory and file exist
24
- */
25
- export async function ensureConfig(): Promise<void> {
26
- if (!existsSync(CONFIG_DIR)) {
27
- await mkdir(CONFIG_DIR, { recursive: true });
28
- }
29
-
30
- if (!existsSync(CONFIG_FILE)) {
31
- const defaultConfig = {
32
- history: [],
33
- urls: {
34
- frontend: DEFAULT_FRONTEND_URL,
35
- api: DEFAULT_API_URL,
36
- },
37
- };
38
- await writeFile(CONFIG_FILE, JSON.stringify(defaultConfig, null, 2));
39
- }
40
- }
41
-
42
- /**
43
- * Read the config file
44
- */
45
- export async function readConfig(): Promise<EnactConfig> {
46
- await ensureConfig();
47
-
48
- try {
49
- const data = await readFile(CONFIG_FILE, "utf8");
50
- const config = JSON.parse(data) as EnactConfig;
51
-
52
- // Migrate old configs that don't have URLs section
53
- if (!config.urls) {
54
- config.urls = {
55
- frontend: DEFAULT_FRONTEND_URL,
56
- api: DEFAULT_API_URL,
57
- };
58
- await writeConfig(config);
59
- }
60
-
61
- return config;
62
- } catch (error) {
63
- console.error("Failed to read config:", (error as Error).message);
64
- return {
65
- history: [],
66
- urls: {
67
- frontend: DEFAULT_FRONTEND_URL,
68
- api: DEFAULT_API_URL,
69
- },
70
- };
71
- }
72
- }
73
-
74
- /**
75
- * Write to the config file
76
- */
77
- export async function writeConfig(config: EnactConfig): Promise<void> {
78
- await ensureConfig();
79
- await writeFile(CONFIG_FILE, JSON.stringify(config, null, 2));
80
- }
81
-
82
- /**
83
- * Add a file to the publish history
84
- */
85
- export async function addToHistory(filePath: string): Promise<void> {
86
- const config = await readConfig();
87
-
88
- if (!config.history) {
89
- config.history = [];
90
- }
91
-
92
- // Add to history if not already there
93
- if (!config.history.includes(filePath)) {
94
- config.history.unshift(filePath);
95
-
96
- // Keep history to a reasonable size
97
- config.history = config.history.slice(0, 10);
98
-
99
- await writeConfig(config);
100
- }
101
- }
102
-
103
- /**
104
- * Get the publish history
105
- */
106
- export async function getHistory(): Promise<string[]> {
107
- const config = await readConfig();
108
- return config.history || [];
109
- }
110
-
111
- /**
112
- * Set the default publish URL
113
- */
114
- export async function setDefaultUrl(url: string): Promise<void> {
115
- const config = await readConfig();
116
- config.defaultUrl = url;
117
- await writeConfig(config);
118
- }
119
-
120
- /**
121
- * Get the default publish URL
122
- */
123
- export async function getDefaultUrl(): Promise<string | undefined> {
124
- const config = await readConfig();
125
- return config.defaultUrl;
126
- }
127
-
128
- // Default URLs
129
- const DEFAULT_FRONTEND_URL = "https://enact.tools";
130
- const DEFAULT_API_URL = "https://xjnhhxwxovjifdxdwzih.supabase.co";
131
-
132
- // Default trusted public key (Enact Protocol official key)
133
- const DEFAULT_ENACT_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
134
- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8VyE3jGm5yT2mKnPx1dQF7q8Z2Kv
135
- 7mX9YnE2mK8vF3tY9pL6xH2dF8sK3mN7wQ5vT2gR8sL4xN6pM9uE3wF2Qw==
136
- -----END PUBLIC KEY-----`;
137
-
138
- // Trusted key metadata interface (for .meta files)
139
- export interface TrustedKeyMeta {
140
- name: string;
141
- description?: string;
142
- addedAt: string;
143
- source: "default" | "user" | "organization";
144
- keyFile: string;
145
- }
146
-
147
- // Combined trusted key interface
148
- export interface TrustedKey {
149
- id: string;
150
- name: string;
151
- publicKey: string;
152
- description?: string;
153
- addedAt: string;
154
- source: "default" | "user" | "organization";
155
- keyFile: string;
156
- }
157
-
158
- /**
159
- * Get the frontend URL with fallbacks
160
- */
161
- export async function getFrontendUrl(): Promise<string> {
162
- // 1. Environment variable override
163
- if (process.env.ENACT_FRONTEND_URL) {
164
- return process.env.ENACT_FRONTEND_URL;
165
- }
166
-
167
- // 2. Config file setting
168
- const config = await readConfig();
169
- if (config.urls?.frontend) {
170
- return config.urls.frontend;
171
- }
172
-
173
- // 3. Default
174
- return DEFAULT_FRONTEND_URL;
175
- }
176
-
177
- /**
178
- * Get the API URL with fallbacks
179
- */
180
- export async function getApiUrl(): Promise<string> {
181
- // 1. Environment variable override
182
- if (process.env.ENACT_API_URL) {
183
- return process.env.ENACT_API_URL;
184
- }
185
-
186
- // 2. Config file setting
187
- const config = await readConfig();
188
- if (config.urls?.api) {
189
- return config.urls.api;
190
- }
191
-
192
- // 3. Default
193
- return DEFAULT_API_URL;
194
- }
195
-
196
- /**
197
- * Set the frontend URL in config
198
- */
199
- export async function setFrontendUrl(url: string): Promise<void> {
200
- const config = await readConfig();
201
- if (!config.urls) {
202
- config.urls = {};
203
- }
204
- config.urls.frontend = url;
205
- await writeConfig(config);
206
- }
207
-
208
- /**
209
- * Set the API URL in config
210
- */
211
- export async function setApiUrl(url: string): Promise<void> {
212
- const config = await readConfig();
213
- if (!config.urls) {
214
- config.urls = {};
215
- }
216
- config.urls.api = url;
217
- await writeConfig(config);
218
- }
219
-
220
- /**
221
- * Reset URLs to defaults
222
- */
223
- export async function resetUrls(): Promise<void> {
224
- const config = await readConfig();
225
- if (config.urls) {
226
- delete config.urls.frontend;
227
- delete config.urls.api;
228
- }
229
- await writeConfig(config);
230
- }
231
-
232
- /**
233
- * Get current URL configuration
234
- */
235
- export async function getUrlConfig(): Promise<{
236
- frontend: { value: string; source: string };
237
- api: { value: string; source: string };
238
- }> {
239
- const config = await readConfig();
240
-
241
- // Determine frontend URL source
242
- let frontendValue = DEFAULT_FRONTEND_URL;
243
- let frontendSource = "default";
244
-
245
- if (config.urls?.frontend) {
246
- frontendValue = config.urls.frontend;
247
- frontendSource = "config";
248
- }
249
-
250
- if (process.env.ENACT_FRONTEND_URL) {
251
- frontendValue = process.env.ENACT_FRONTEND_URL;
252
- frontendSource = "environment";
253
- }
254
-
255
- // Determine API URL source
256
- let apiValue = DEFAULT_API_URL;
257
- let apiSource = "default";
258
-
259
- if (config.urls?.api) {
260
- apiValue = config.urls.api;
261
- apiSource = "config";
262
- }
263
-
264
- if (process.env.ENACT_API_URL) {
265
- apiValue = process.env.ENACT_API_URL;
266
- apiSource = "environment";
267
- }
268
-
269
- return {
270
- frontend: { value: frontendValue, source: frontendSource },
271
- api: { value: apiValue, source: apiSource },
272
- };
273
- }
274
-
275
- /**
276
- * Ensure trusted keys directory exists with default key
277
- */
278
- async function ensureTrustedKeysDir(): Promise<void> {
279
- if (!existsSync(CONFIG_DIR)) {
280
- await mkdir(CONFIG_DIR, { recursive: true });
281
- }
282
-
283
- if (!existsSync(TRUSTED_KEYS_DIR)) {
284
- await mkdir(TRUSTED_KEYS_DIR, { recursive: true });
285
- }
286
-
287
- // Create default Enact Protocol key if it doesn't exist
288
- const defaultKeyFile = join(TRUSTED_KEYS_DIR, "enact-protocol-official.pem");
289
- const defaultMetaFile = join(TRUSTED_KEYS_DIR, "enact-protocol-official.meta");
290
-
291
- if (!existsSync(defaultKeyFile)) {
292
- await writeFile(defaultKeyFile, DEFAULT_ENACT_PUBLIC_KEY);
293
- }
294
-
295
- if (!existsSync(defaultMetaFile)) {
296
- const defaultMeta: TrustedKeyMeta = {
297
- name: "Enact Protocol Official",
298
- description: "Official Enact Protocol signing key for verified tools",
299
- addedAt: new Date().toISOString(),
300
- source: "default",
301
- keyFile: "enact-protocol-official.pem"
302
- };
303
- await writeFile(defaultMetaFile, JSON.stringify(defaultMeta, null, 2));
304
- }
305
- }
306
-
307
- /**
308
- * Read all trusted keys from directory
309
- */
310
- export async function getTrustedKeys(): Promise<TrustedKey[]> {
311
- await ensureTrustedKeysDir();
312
-
313
- const keys: TrustedKey[] = [];
314
-
315
- try {
316
- const { readdir } = await import('fs/promises');
317
- const files = await readdir(TRUSTED_KEYS_DIR);
318
-
319
- // Get all .pem files
320
- const pemFiles = files.filter(f => f.endsWith('.pem'));
321
-
322
- for (const pemFile of pemFiles) {
323
- try {
324
- const keyId = pemFile.replace('.pem', '');
325
- const keyPath = join(TRUSTED_KEYS_DIR, pemFile);
326
- const metaPath = join(TRUSTED_KEYS_DIR, `${keyId}.meta`);
327
-
328
- // Read the public key
329
- const publicKey = await readFile(keyPath, 'utf8');
330
-
331
- // Read metadata if it exists
332
- let meta: TrustedKeyMeta = {
333
- name: keyId,
334
- addedAt: new Date().toISOString(),
335
- source: "user",
336
- keyFile: pemFile
337
- };
338
-
339
- if (existsSync(metaPath)) {
340
- try {
341
- const metaData = await readFile(metaPath, 'utf8');
342
- meta = { ...meta, ...JSON.parse(metaData) };
343
- } catch {
344
- // Use defaults if meta file is corrupted
345
- }
346
- }
347
-
348
- keys.push({
349
- id: keyId,
350
- name: meta.name,
351
- publicKey: publicKey.trim(),
352
- description: meta.description,
353
- addedAt: meta.addedAt,
354
- source: meta.source,
355
- keyFile: pemFile
356
- });
357
- } catch (error) {
358
- console.warn(`Warning: Could not read key file ${pemFile}:`, error);
359
- }
360
- }
361
- } catch (error) {
362
- console.error("Failed to read trusted keys directory:", error);
363
- }
364
-
365
- return keys;
366
- }
367
-
368
- /**
369
- * Add a trusted key
370
- */
371
- export async function addTrustedKey(keyData: {
372
- id: string;
373
- name: string;
374
- publicKey: string;
375
- description?: string;
376
- source?: "user" | "organization";
377
- }): Promise<void> {
378
- await ensureTrustedKeysDir();
379
-
380
- const keyFile = `${keyData.id}.pem`;
381
- const metaFile = `${keyData.id}.meta`;
382
- const keyPath = join(TRUSTED_KEYS_DIR, keyFile);
383
- const metaPath = join(TRUSTED_KEYS_DIR, metaFile);
384
-
385
- // Check if key already exists
386
- if (existsSync(keyPath)) {
387
- throw new Error(`Key with ID '${keyData.id}' already exists`);
388
- }
389
-
390
- // Write the public key file
391
- await writeFile(keyPath, keyData.publicKey);
392
-
393
- // Write the metadata file
394
- const meta: TrustedKeyMeta = {
395
- name: keyData.name,
396
- description: keyData.description,
397
- addedAt: new Date().toISOString(),
398
- source: keyData.source || "user",
399
- keyFile
400
- };
401
- await writeFile(metaPath, JSON.stringify(meta, null, 2));
402
- }
403
-
404
- /**
405
- * Remove a trusted key
406
- */
407
- export async function removeTrustedKey(keyId: string): Promise<void> {
408
- const keyPath = join(TRUSTED_KEYS_DIR, `${keyId}.pem`);
409
- const metaPath = join(TRUSTED_KEYS_DIR, `${keyId}.meta`);
410
-
411
- if (!existsSync(keyPath)) {
412
- throw new Error(`Trusted key '${keyId}' not found`);
413
- }
414
-
415
- // Remove both files
416
- const { unlink } = await import('fs/promises');
417
- await unlink(keyPath);
418
-
419
- if (existsSync(metaPath)) {
420
- await unlink(metaPath);
421
- }
422
- }
423
-
424
- /**
425
- * Get a specific trusted key
426
- */
427
- export async function getTrustedKey(keyId: string): Promise<TrustedKey | null> {
428
- const keys = await getTrustedKeys();
429
- return keys.find(k => k.id === keyId) || null;
430
- }
431
-
432
- /**
433
- * Check if a public key is trusted
434
- */
435
- export async function isKeyTrusted(publicKey: string): Promise<boolean> {
436
- const keys = await getTrustedKeys();
437
- return keys.some(k => k.publicKey.trim() === publicKey.trim());
438
- }