@dexto/core 1.1.4

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.
@@ -0,0 +1,87 @@
1
+ import {
2
+ DextoRuntimeError
3
+ } from "./chunk-TPERKLLN.js";
4
+ import {
5
+ init_esm_shims
6
+ } from "./chunk-MVKLS3LM.js";
7
+
8
+ // src/storage/errors.ts
9
+ init_esm_shims();
10
+ var StorageError = class {
11
+ /**
12
+ * Connection failed error
13
+ */
14
+ static connectionFailed(reason, config) {
15
+ return new DextoRuntimeError(
16
+ "storage_connection_failed" /* CONNECTION_FAILED */,
17
+ "storage" /* STORAGE */,
18
+ "third_party" /* THIRD_PARTY */,
19
+ `Storage connection failed: ${reason}`,
20
+ { reason, config }
21
+ );
22
+ }
23
+ /**
24
+ * Backend not connected error
25
+ */
26
+ static notConnected(backendType) {
27
+ return new DextoRuntimeError(
28
+ "storage_connection_failed" /* CONNECTION_FAILED */,
29
+ "storage" /* STORAGE */,
30
+ "system" /* SYSTEM */,
31
+ `${backendType} not connected`,
32
+ { backendType }
33
+ );
34
+ }
35
+ /**
36
+ * Read operation failed
37
+ */
38
+ static readFailed(operation, reason, details) {
39
+ return new DextoRuntimeError(
40
+ "storage_read_failed" /* READ_FAILED */,
41
+ "storage" /* STORAGE */,
42
+ "system" /* SYSTEM */,
43
+ `Storage read failed for ${operation}: ${reason}`,
44
+ { operation, reason, ...details }
45
+ );
46
+ }
47
+ /**
48
+ * Write operation failed
49
+ */
50
+ static writeFailed(operation, reason, details) {
51
+ return new DextoRuntimeError(
52
+ "storage_write_failed" /* WRITE_FAILED */,
53
+ "storage" /* STORAGE */,
54
+ "system" /* SYSTEM */,
55
+ `Storage write failed for ${operation}: ${reason}`,
56
+ { operation, reason, ...details }
57
+ );
58
+ }
59
+ /**
60
+ * Delete operation failed
61
+ */
62
+ static deleteFailed(operation, reason, details) {
63
+ return new DextoRuntimeError(
64
+ "storage_delete_failed" /* DELETE_FAILED */,
65
+ "storage" /* STORAGE */,
66
+ "system" /* SYSTEM */,
67
+ `Storage delete failed for ${operation}: ${reason}`,
68
+ { operation, reason, ...details }
69
+ );
70
+ }
71
+ /**
72
+ * Migration failed error
73
+ */
74
+ static migrationFailed(reason, details) {
75
+ return new DextoRuntimeError(
76
+ "storage_migration_failed" /* MIGRATION_FAILED */,
77
+ "storage" /* STORAGE */,
78
+ "system" /* SYSTEM */,
79
+ `Database migration failed: ${reason}`,
80
+ { reason, ...details }
81
+ );
82
+ }
83
+ };
84
+
85
+ export {
86
+ StorageError
87
+ };
@@ -0,0 +1,535 @@
1
+ import {
2
+ loadGlobalPreferences
3
+ } from "./chunk-J6AXCN3H.js";
4
+ import {
5
+ RegistryError
6
+ } from "./chunk-PI6XFMEW.js";
7
+ import {
8
+ copyDirectory,
9
+ getDextoGlobalPath,
10
+ logger,
11
+ resolveBundledScript
12
+ } from "./chunk-D62MHQBE.js";
13
+ import {
14
+ DextoRuntimeError
15
+ } from "./chunk-TPERKLLN.js";
16
+ import {
17
+ init_esm_shims
18
+ } from "./chunk-MVKLS3LM.js";
19
+
20
+ // src/agent/registry/registry.ts
21
+ init_esm_shims();
22
+ import { existsSync, readFileSync } from "fs";
23
+ import { promises as fs2 } from "fs";
24
+ import path2 from "path";
25
+
26
+ // src/config/writer.ts
27
+ init_esm_shims();
28
+ import { promises as fs } from "fs";
29
+ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
30
+ import * as path from "path";
31
+
32
+ // src/config/errors.ts
33
+ init_esm_shims();
34
+ var ConfigError = class {
35
+ // File operation errors
36
+ static fileNotFound(configPath) {
37
+ return new DextoRuntimeError(
38
+ "config_file_not_found" /* FILE_NOT_FOUND */,
39
+ "config" /* CONFIG */,
40
+ "user" /* USER */,
41
+ `Configuration file not found: ${configPath}`,
42
+ { configPath },
43
+ "Ensure the configuration file exists at the specified path"
44
+ );
45
+ }
46
+ static fileReadError(configPath, cause) {
47
+ return new DextoRuntimeError(
48
+ "config_file_read_error" /* FILE_READ_ERROR */,
49
+ "config" /* CONFIG */,
50
+ "system" /* SYSTEM */,
51
+ `Failed to read configuration file: ${cause}`,
52
+ { configPath, cause },
53
+ "Check file permissions and ensure the file is not corrupted"
54
+ );
55
+ }
56
+ static fileWriteError(configPath, cause) {
57
+ return new DextoRuntimeError(
58
+ "config_file_write_error" /* FILE_WRITE_ERROR */,
59
+ "config" /* CONFIG */,
60
+ "system" /* SYSTEM */,
61
+ `Failed to write configuration file '${configPath}': ${cause}`,
62
+ { configPath, cause },
63
+ "Check file permissions and available disk space"
64
+ );
65
+ }
66
+ // Parsing errors
67
+ static parseError(configPath, cause) {
68
+ return new DextoRuntimeError(
69
+ "config_parse_error" /* PARSE_ERROR */,
70
+ "config" /* CONFIG */,
71
+ "user" /* USER */,
72
+ `Failed to parse configuration file: ${cause}`,
73
+ { configPath, cause },
74
+ "Ensure the configuration file contains valid YAML syntax"
75
+ );
76
+ }
77
+ // Resolution errors
78
+ static noProjectDefault(projectPath) {
79
+ return new DextoRuntimeError(
80
+ "config_no_project_default" /* NO_PROJECT_DEFAULT */,
81
+ "config" /* CONFIG */,
82
+ "user" /* USER */,
83
+ `No project default-agent.yml found and no global preferences configured.
84
+ Either create default-agent.yml in your project root (${projectPath}) or run \`dexto setup\` to configure preferences.`,
85
+ { projectPath },
86
+ "Run `dexto setup` or create a project-specific agent config"
87
+ );
88
+ }
89
+ static noGlobalPreferences() {
90
+ return new DextoRuntimeError(
91
+ "config_no_global_preferences" /* NO_GLOBAL_PREFERENCES */,
92
+ "config" /* CONFIG */,
93
+ "user" /* USER */,
94
+ `No global preferences found. Run \`dexto setup\` to get started.`,
95
+ {},
96
+ "Run `dexto setup` to configure your AI preferences"
97
+ );
98
+ }
99
+ static setupIncomplete() {
100
+ return new DextoRuntimeError(
101
+ "config_setup_incomplete" /* SETUP_INCOMPLETE */,
102
+ "config" /* CONFIG */,
103
+ "user" /* USER */,
104
+ `Global preferences setup is incomplete. Run \`dexto setup\` to complete.`,
105
+ {},
106
+ "Run `dexto setup` to complete your configuration"
107
+ );
108
+ }
109
+ static bundledNotFound(bundledPath) {
110
+ return new DextoRuntimeError(
111
+ "config_bundled_not_found" /* BUNDLED_NOT_FOUND */,
112
+ "config" /* CONFIG */,
113
+ "not_found" /* NOT_FOUND */,
114
+ `Bundled default agent not found: ${bundledPath}. Run npm run build first.`,
115
+ { path: bundledPath },
116
+ "Run `npm run build` to build the bundled agents"
117
+ );
118
+ }
119
+ static unknownContext(context) {
120
+ return new DextoRuntimeError(
121
+ "config_unknown_context" /* UNKNOWN_CONTEXT */,
122
+ "config" /* CONFIG */,
123
+ "system" /* SYSTEM */,
124
+ `Unknown execution context: ${context}`,
125
+ { context },
126
+ "This is an internal error - please report it"
127
+ );
128
+ }
129
+ };
130
+
131
+ // src/config/writer.ts
132
+ async function writeConfigFile(configPath, config) {
133
+ const absolutePath = path.resolve(configPath);
134
+ try {
135
+ const yamlContent = stringifyYaml(config, { indent: 2 });
136
+ await fs.writeFile(absolutePath, yamlContent, "utf-8");
137
+ logger.debug(`Wrote dexto config to: ${absolutePath}`);
138
+ } catch (error) {
139
+ throw ConfigError.fileWriteError(
140
+ absolutePath,
141
+ error instanceof Error ? error.message : String(error)
142
+ );
143
+ }
144
+ }
145
+ async function writeLLMPreferences(configPath, preferences, overrides) {
146
+ logger.debug(`Writing LLM preferences to: ${configPath}`, {
147
+ provider: overrides?.provider ?? preferences.llm.provider,
148
+ model: overrides?.model ?? preferences.llm.model,
149
+ hasApiKeyOverride: Boolean(overrides?.apiKey),
150
+ hasPreferenceApiKey: Boolean(preferences.llm.apiKey)
151
+ });
152
+ logger.debug(`Reading config file: ${configPath}`);
153
+ let fileContent;
154
+ try {
155
+ fileContent = await fs.readFile(configPath, "utf-8");
156
+ logger.debug(`Successfully read config file (${fileContent.length} chars)`);
157
+ } catch (error) {
158
+ logger.error(`Failed to read config file: ${configPath}`, { error });
159
+ throw ConfigError.fileReadError(
160
+ configPath,
161
+ error instanceof Error ? error.message : String(error)
162
+ );
163
+ }
164
+ let config;
165
+ try {
166
+ config = parseYaml(fileContent);
167
+ logger.debug(`Successfully parsed YAML config`, {
168
+ hasLlmSection: Boolean(config.llm),
169
+ existingProvider: config.llm?.provider,
170
+ existingModel: config.llm?.model
171
+ });
172
+ } catch (error) {
173
+ logger.error(`Failed to parse YAML config: ${configPath}`, { error });
174
+ throw ConfigError.parseError(
175
+ configPath,
176
+ error instanceof Error ? error.message : String(error)
177
+ );
178
+ }
179
+ const provider = overrides?.provider ?? preferences.llm.provider;
180
+ const model = overrides?.model ?? preferences.llm.model;
181
+ const apiKey = overrides?.apiKey ?? preferences.llm.apiKey;
182
+ logger.debug(`Applying LLM preferences`, {
183
+ finalProvider: provider,
184
+ finalModel: model,
185
+ hasApiKey: Boolean(apiKey),
186
+ source: overrides ? "CLI overrides + preferences" : "preferences only"
187
+ });
188
+ config.llm = {
189
+ ...config.llm,
190
+ // Preserve temperature, router, maxTokens, etc.
191
+ provider,
192
+ // Write user preference
193
+ model,
194
+ // Write user preference
195
+ apiKey
196
+ // Write user preference
197
+ };
198
+ await writeConfigFile(configPath, config);
199
+ logger.info(`\u2713 Applied preferences to: ${path.basename(configPath)} (${provider}/${model})`);
200
+ }
201
+ async function writePreferencesToAgent(installedPath, preferences, overrides) {
202
+ let stat;
203
+ try {
204
+ stat = await fs.stat(installedPath);
205
+ } catch (error) {
206
+ throw ConfigError.fileReadError(
207
+ installedPath,
208
+ error instanceof Error ? error.message : String(error)
209
+ );
210
+ }
211
+ if (stat.isFile()) {
212
+ if (installedPath.endsWith(".yml") || installedPath.endsWith(".yaml")) {
213
+ await writeLLMPreferences(installedPath, preferences, overrides);
214
+ logger.info(`\u2713 Applied preferences to: ${path.basename(installedPath)}`, null, "green");
215
+ } else {
216
+ logger.warn(`Skipping non-YAML file: ${installedPath}`, null, "yellow");
217
+ }
218
+ } else if (stat.isDirectory()) {
219
+ await writePreferencesToDirectory(installedPath, preferences, overrides);
220
+ } else {
221
+ throw ConfigError.fileReadError(installedPath, "Path is neither a file nor directory");
222
+ }
223
+ }
224
+ async function writePreferencesToDirectory(installedDir, preferences, overrides) {
225
+ const configFiles = await findAgentConfigFiles(installedDir);
226
+ if (configFiles.length === 0) {
227
+ logger.warn(`No YAML config files found in: ${installedDir}`);
228
+ return;
229
+ }
230
+ let successCount = 0;
231
+ const oldProvider = preferences.llm.provider;
232
+ const oldModel = preferences.llm.model;
233
+ const newProvider = overrides?.provider ?? preferences.llm.provider;
234
+ const newModel = overrides?.model ?? preferences.llm.model;
235
+ for (const configPath of configFiles) {
236
+ try {
237
+ await writeLLMPreferences(configPath, preferences, overrides);
238
+ logger.debug(`Applied preferences to: ${path.relative(installedDir, configPath)}`);
239
+ successCount++;
240
+ } catch (error) {
241
+ logger.warn(
242
+ `Failed to write preferences to ${configPath}: ${error instanceof Error ? error.message : String(error)}`
243
+ );
244
+ }
245
+ }
246
+ logger.info(
247
+ `\u2713 Applied preferences to ${successCount}/${configFiles.length} config files (${oldProvider}\u2192${newProvider}, ${oldModel}\u2192${newModel})`
248
+ );
249
+ }
250
+ async function findAgentConfigFiles(dir) {
251
+ const configFiles = [];
252
+ async function walkDir(currentDir) {
253
+ const entries = await fs.readdir(currentDir, { withFileTypes: true });
254
+ for (const entry of entries) {
255
+ const fullPath = path.join(currentDir, entry.name);
256
+ if (entry.isDirectory()) {
257
+ if (!["docs", "data"].includes(entry.name)) {
258
+ await walkDir(fullPath);
259
+ }
260
+ } else if (entry.name.endsWith(".yml") || entry.name.endsWith(".yaml")) {
261
+ configFiles.push(fullPath);
262
+ }
263
+ }
264
+ }
265
+ await walkDir(dir);
266
+ return configFiles;
267
+ }
268
+
269
+ // src/agent/registry/types.ts
270
+ init_esm_shims();
271
+ import { z } from "zod";
272
+ var AgentRegistryEntrySchema = z.object({
273
+ description: z.string(),
274
+ author: z.string(),
275
+ tags: z.array(z.string()),
276
+ source: z.string(),
277
+ main: z.string().optional()
278
+ }).strict();
279
+ var RegistrySchema = z.object({
280
+ version: z.string(),
281
+ agents: z.record(z.string(), AgentRegistryEntrySchema)
282
+ }).strict();
283
+
284
+ // src/agent/registry/registry.ts
285
+ var cachedRegistry = null;
286
+ var LocalAgentRegistry = class {
287
+ _registry = null;
288
+ /**
289
+ * Lazy load registry from JSON file
290
+ */
291
+ getRegistry() {
292
+ if (this._registry === null) {
293
+ this._registry = this.loadRegistry();
294
+ }
295
+ return this._registry;
296
+ }
297
+ /**
298
+ * Load registry from bundled JSON file
299
+ * Uses fail-fast approach - throws RegistryError for any loading issues
300
+ */
301
+ loadRegistry() {
302
+ let jsonPath;
303
+ try {
304
+ jsonPath = resolveBundledScript("agents/agent-registry.json");
305
+ } catch (_error) {
306
+ throw RegistryError.registryNotFound(
307
+ "agents/agent-registry.json (bundle resolution failed)"
308
+ );
309
+ }
310
+ if (!existsSync(jsonPath)) {
311
+ throw RegistryError.registryNotFound(jsonPath);
312
+ }
313
+ try {
314
+ const jsonData = readFileSync(jsonPath, "utf-8");
315
+ const rawRegistry = JSON.parse(jsonData);
316
+ return RegistrySchema.parse(rawRegistry);
317
+ } catch (error) {
318
+ throw RegistryError.registryParseError(
319
+ jsonPath,
320
+ error instanceof Error ? error.message : String(error)
321
+ );
322
+ }
323
+ }
324
+ /**
325
+ * Check if agent exists in registry
326
+ */
327
+ hasAgent(name) {
328
+ const registry = this.getRegistry();
329
+ return name in registry.agents;
330
+ }
331
+ /**
332
+ * Get available agents with their metadata from registry
333
+ */
334
+ getAvailableAgents() {
335
+ const registry = this.getRegistry();
336
+ return registry.agents;
337
+ }
338
+ /**
339
+ * Resolve main config file for installed agent
340
+ * Handles both directory agents (with main field) and single-file agents
341
+ */
342
+ resolveMainConfig(agentDir, agentName) {
343
+ const registry = this.getRegistry();
344
+ const agentData = registry.agents[agentName];
345
+ if (!agentData) {
346
+ const available = Object.keys(registry.agents);
347
+ throw RegistryError.agentNotFound(agentName, available);
348
+ }
349
+ if (agentData.source.endsWith("/")) {
350
+ if (!agentData.main) {
351
+ throw RegistryError.agentInvalidEntry(
352
+ agentName,
353
+ "directory entry missing main field"
354
+ );
355
+ }
356
+ const mainConfigPath = path2.join(agentDir, agentData.main);
357
+ if (!existsSync(mainConfigPath)) {
358
+ throw RegistryError.mainConfigMissing(agentName, mainConfigPath);
359
+ }
360
+ return mainConfigPath;
361
+ } else {
362
+ const filename = path2.basename(agentData.source);
363
+ const configPath = path2.join(agentDir, filename);
364
+ if (!existsSync(configPath)) {
365
+ throw RegistryError.configNotFound(configPath);
366
+ }
367
+ return configPath;
368
+ }
369
+ }
370
+ /**
371
+ * Install agent atomically using temp + rename pattern
372
+ * @param agentName Name of the agent to install
373
+ * @param injectPreferences Whether to inject global preferences into installed agent (default: true)
374
+ */
375
+ async installAgent(agentName, injectPreferences = true) {
376
+ logger.info(`Installing agent: ${agentName}`);
377
+ const registry = this.getRegistry();
378
+ const agentData = registry.agents[agentName];
379
+ if (!agentData) {
380
+ const available = Object.keys(registry.agents);
381
+ throw RegistryError.agentNotFound(agentName, available);
382
+ }
383
+ const globalAgentsDir = getDextoGlobalPath("agents");
384
+ const targetDir = path2.join(globalAgentsDir, agentName);
385
+ if (existsSync(targetDir)) {
386
+ logger.info(`Agent '${agentName}' already installed`);
387
+ return this.resolveMainConfig(targetDir, agentName);
388
+ }
389
+ await fs2.mkdir(globalAgentsDir, { recursive: true });
390
+ const sourcePath = resolveBundledScript(`agents/${agentData.source}`);
391
+ const tempDir = `${targetDir}.tmp.${Date.now()}`;
392
+ try {
393
+ if (agentData.source.endsWith("/")) {
394
+ await copyDirectory(sourcePath, tempDir);
395
+ } else {
396
+ await fs2.mkdir(tempDir, { recursive: true });
397
+ const targetFile = path2.join(tempDir, path2.basename(sourcePath));
398
+ await fs2.copyFile(sourcePath, targetFile);
399
+ }
400
+ const mainConfigPath = this.resolveMainConfig(tempDir, agentName);
401
+ if (!existsSync(mainConfigPath)) {
402
+ throw RegistryError.installationValidationFailed(agentName, mainConfigPath);
403
+ }
404
+ await fs2.rename(tempDir, targetDir);
405
+ logger.info(`\u2713 Installed agent '${agentName}' to ${targetDir}`);
406
+ if (injectPreferences) {
407
+ try {
408
+ const preferences = await loadGlobalPreferences();
409
+ await writePreferencesToAgent(targetDir, preferences);
410
+ logger.info(`\u2713 Applied global preferences to installed agent '${agentName}'`);
411
+ } catch (error) {
412
+ logger.warn(
413
+ `Failed to inject preferences to '${agentName}': ${error instanceof Error ? error.message : String(error)}`
414
+ );
415
+ console.log(
416
+ `\u26A0\uFE0F Warning: Could not apply preferences to '${agentName}' - agent will use bundled settings`
417
+ );
418
+ }
419
+ } else {
420
+ logger.info(
421
+ `Skipped preference injection for '${agentName}' (injectPreferences=false)`
422
+ );
423
+ }
424
+ return this.resolveMainConfig(targetDir, agentName);
425
+ } catch (error) {
426
+ try {
427
+ if (existsSync(tempDir)) {
428
+ await fs2.rm(tempDir, { recursive: true, force: true });
429
+ }
430
+ } catch (cleanupError) {
431
+ logger.error(
432
+ `Failed to clean up temp directory: ${cleanupError}. Skipping cleanup...`
433
+ );
434
+ }
435
+ throw RegistryError.installationFailed(
436
+ agentName,
437
+ error instanceof Error ? error.message : String(error)
438
+ );
439
+ }
440
+ }
441
+ /**
442
+ * Resolve a registry agent name to a config path
443
+ * NOTE: Only handles registry names, not file paths (routing done in loadAgentConfig)
444
+ * Handles installing agent if needed
445
+ * @param agentName Name of the agent to resolve
446
+ * @param autoInstall Whether to automatically install missing agents from registry (default: true)
447
+ * @param injectPreferences Whether to inject preferences during auto-installation (default: true)
448
+ */
449
+ async resolveAgent(agentName, autoInstall = true, injectPreferences = true) {
450
+ logger.debug(`Resolving registry agent: ${agentName}`);
451
+ const globalAgentsDir = getDextoGlobalPath("agents");
452
+ const installedPath = path2.join(globalAgentsDir, agentName);
453
+ if (existsSync(installedPath)) {
454
+ const mainConfig = this.resolveMainConfig(installedPath, agentName);
455
+ logger.debug(`Resolved installed agent '${agentName}' to: ${mainConfig}`);
456
+ return mainConfig;
457
+ }
458
+ logger.debug(`Agent '${agentName}' not found in installed path: ${installedPath}`);
459
+ if (this.hasAgent(agentName)) {
460
+ if (autoInstall) {
461
+ logger.info(`Installing agent '${agentName}' from registry...`);
462
+ return await this.installAgent(agentName, injectPreferences);
463
+ } else {
464
+ const registry2 = this.getRegistry();
465
+ const available2 = Object.keys(registry2.agents);
466
+ throw RegistryError.agentNotInstalledAutoInstallDisabled(agentName, available2);
467
+ }
468
+ }
469
+ const registry = this.getRegistry();
470
+ const available = Object.keys(registry.agents);
471
+ throw RegistryError.agentNotFound(agentName, available);
472
+ }
473
+ /**
474
+ * Get list of currently installed agents
475
+ */
476
+ async getInstalledAgents() {
477
+ const globalAgentsDir = getDextoGlobalPath("agents");
478
+ if (!existsSync(globalAgentsDir)) {
479
+ return [];
480
+ }
481
+ try {
482
+ const entries = await fs2.readdir(globalAgentsDir, { withFileTypes: true });
483
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => !name.startsWith(".tmp") && !name.includes(".tmp."));
484
+ } catch (error) {
485
+ logger.error(`Failed to read installed agents directory: ${error}`);
486
+ return [];
487
+ }
488
+ }
489
+ /**
490
+ * Check if an agent is safe to uninstall (not the default-agent which is critical)
491
+ */
492
+ isAgentSafeToUninstall(agentName) {
493
+ return agentName !== "default-agent";
494
+ }
495
+ /**
496
+ * Uninstall an agent by removing its directory
497
+ * @param agentName Name of the agent to uninstall
498
+ * @param force Whether to force uninstall even if agent is protected (default: false)
499
+ */
500
+ async uninstallAgent(agentName, force = false) {
501
+ const globalAgentsDir = getDextoGlobalPath("agents");
502
+ const agentDir = path2.join(globalAgentsDir, agentName);
503
+ logger.info(`Uninstalling agent: ${agentName} from ${agentDir}`);
504
+ if (!existsSync(agentDir)) {
505
+ throw RegistryError.agentNotInstalled(agentName);
506
+ }
507
+ if (!force && !this.isAgentSafeToUninstall(agentName)) {
508
+ throw RegistryError.agentProtected(agentName);
509
+ }
510
+ try {
511
+ await fs2.rm(agentDir, { recursive: true, force: true });
512
+ logger.info(`\u2713 Removed agent '${agentName}' from ${agentDir}`);
513
+ } catch (error) {
514
+ throw RegistryError.uninstallationFailed(
515
+ agentName,
516
+ error instanceof Error ? error.message : String(error)
517
+ );
518
+ }
519
+ }
520
+ };
521
+ function getAgentRegistry() {
522
+ if (cachedRegistry === null) {
523
+ cachedRegistry = new LocalAgentRegistry();
524
+ }
525
+ return cachedRegistry;
526
+ }
527
+
528
+ export {
529
+ ConfigError,
530
+ writeConfigFile,
531
+ writeLLMPreferences,
532
+ writePreferencesToAgent,
533
+ LocalAgentRegistry,
534
+ getAgentRegistry
535
+ };