@dexto/agent-management 1.5.7 → 1.6.0

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 (145) hide show
  1. package/dist/AgentFactory.cjs +5 -9
  2. package/dist/AgentFactory.d.ts +6 -5
  3. package/dist/AgentFactory.d.ts.map +1 -1
  4. package/dist/AgentFactory.js +5 -9
  5. package/dist/AgentManager.cjs +2 -2
  6. package/dist/AgentManager.d.ts +1 -1
  7. package/dist/AgentManager.d.ts.map +1 -1
  8. package/dist/AgentManager.js +4 -4
  9. package/dist/agent-creation.cjs +95 -0
  10. package/dist/agent-creation.d.ts +15 -0
  11. package/dist/agent-creation.d.ts.map +1 -0
  12. package/dist/agent-creation.js +78 -0
  13. package/dist/config/config-enrichment.cjs +2 -12
  14. package/dist/config/config-enrichment.d.ts +1 -1
  15. package/dist/config/config-enrichment.d.ts.map +1 -1
  16. package/dist/config/config-enrichment.js +2 -12
  17. package/dist/config/config-manager.cjs +4 -4
  18. package/dist/config/config-manager.d.ts +1 -1
  19. package/dist/config/config-manager.d.ts.map +1 -1
  20. package/dist/config/config-manager.js +3 -1
  21. package/dist/config/loader.d.ts +3 -3
  22. package/dist/config/loader.d.ts.map +1 -1
  23. package/dist/images/image-store.cjs +256 -0
  24. package/dist/images/image-store.d.ts +70 -0
  25. package/dist/images/image-store.d.ts.map +1 -0
  26. package/dist/images/image-store.js +210 -0
  27. package/dist/index.cjs +43 -2
  28. package/dist/index.d.ts +5 -2
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +43 -1
  31. package/dist/models/custom-models.cjs +1 -1
  32. package/dist/models/custom-models.d.ts +7 -7
  33. package/dist/models/custom-models.d.ts.map +1 -1
  34. package/dist/models/custom-models.js +1 -1
  35. package/dist/plugins/discover-plugins.cjs +15 -31
  36. package/dist/plugins/discover-plugins.d.ts.map +1 -1
  37. package/dist/plugins/discover-plugins.js +15 -31
  38. package/dist/plugins/discover-skills.cjs +4 -0
  39. package/dist/plugins/discover-skills.d.ts +6 -3
  40. package/dist/plugins/discover-skills.d.ts.map +1 -1
  41. package/dist/plugins/discover-skills.js +4 -0
  42. package/dist/plugins/index.cjs +0 -2
  43. package/dist/plugins/index.d.ts +5 -6
  44. package/dist/plugins/index.d.ts.map +1 -1
  45. package/dist/plugins/index.js +0 -2
  46. package/dist/plugins/list-plugins.cjs +3 -1
  47. package/dist/plugins/list-plugins.d.ts.map +1 -1
  48. package/dist/plugins/list-plugins.js +3 -1
  49. package/dist/plugins/load-plugin.cjs +0 -13
  50. package/dist/plugins/load-plugin.d.ts +3 -5
  51. package/dist/plugins/load-plugin.d.ts.map +1 -1
  52. package/dist/plugins/load-plugin.js +0 -13
  53. package/dist/plugins/schemas.cjs +1 -11
  54. package/dist/plugins/schemas.d.ts +14 -69
  55. package/dist/plugins/schemas.d.ts.map +1 -1
  56. package/dist/plugins/schemas.js +1 -10
  57. package/dist/plugins/types.d.ts +2 -20
  58. package/dist/plugins/types.d.ts.map +1 -1
  59. package/dist/plugins/validate-plugin.cjs +7 -37
  60. package/dist/plugins/validate-plugin.d.ts +6 -24
  61. package/dist/plugins/validate-plugin.d.ts.map +1 -1
  62. package/dist/plugins/validate-plugin.js +8 -38
  63. package/dist/preferences/errors.cjs +11 -0
  64. package/dist/preferences/errors.d.ts +1 -0
  65. package/dist/preferences/errors.d.ts.map +1 -1
  66. package/dist/preferences/errors.js +11 -0
  67. package/dist/preferences/loader.cjs +119 -6
  68. package/dist/preferences/loader.d.ts +21 -1
  69. package/dist/preferences/loader.d.ts.map +1 -1
  70. package/dist/preferences/loader.js +102 -1
  71. package/dist/preferences/schemas.cjs +12 -0
  72. package/dist/preferences/schemas.d.ts +38 -12
  73. package/dist/preferences/schemas.d.ts.map +1 -1
  74. package/dist/preferences/schemas.js +10 -0
  75. package/dist/registry/registry.d.ts +4 -44
  76. package/dist/registry/registry.d.ts.map +1 -1
  77. package/dist/runtime/AgentPool.d.ts +2 -2
  78. package/dist/runtime/AgentPool.d.ts.map +1 -1
  79. package/dist/runtime/AgentRuntime.cjs +20 -15
  80. package/dist/runtime/AgentRuntime.d.ts +2 -2
  81. package/dist/runtime/AgentRuntime.d.ts.map +1 -1
  82. package/dist/runtime/AgentRuntime.js +20 -15
  83. package/dist/runtime/approval-delegation.d.ts +2 -2
  84. package/dist/runtime/approval-delegation.d.ts.map +1 -1
  85. package/dist/runtime/schemas.d.ts +1 -1
  86. package/dist/runtime/types.d.ts +2 -1
  87. package/dist/runtime/types.d.ts.map +1 -1
  88. package/dist/{tool-provider → tool-factories/agent-spawner}/error-codes.d.ts +1 -1
  89. package/dist/tool-factories/agent-spawner/error-codes.d.ts.map +1 -0
  90. package/dist/{tool-provider → tool-factories/agent-spawner}/errors.d.ts +1 -1
  91. package/dist/tool-factories/agent-spawner/errors.d.ts.map +1 -0
  92. package/dist/tool-factories/agent-spawner/factory.cjs +290 -0
  93. package/dist/tool-factories/agent-spawner/factory.d.ts +4 -0
  94. package/dist/tool-factories/agent-spawner/factory.d.ts.map +1 -0
  95. package/dist/tool-factories/agent-spawner/factory.js +279 -0
  96. package/dist/{tool-provider → tool-factories/agent-spawner}/index.cjs +9 -9
  97. package/dist/{tool-provider → tool-factories/agent-spawner}/index.d.ts +3 -3
  98. package/dist/tool-factories/agent-spawner/index.d.ts.map +1 -0
  99. package/dist/{tool-provider → tool-factories/agent-spawner}/index.js +4 -4
  100. package/dist/{tool-provider → tool-factories/agent-spawner}/llm-resolution.cjs +1 -1
  101. package/dist/{tool-provider → tool-factories/agent-spawner}/llm-resolution.d.ts +4 -4
  102. package/dist/tool-factories/agent-spawner/llm-resolution.d.ts.map +1 -0
  103. package/dist/{tool-provider → tool-factories/agent-spawner}/llm-resolution.js +1 -1
  104. package/dist/{tool-provider/runtime-service.cjs → tool-factories/agent-spawner/runtime.cjs} +112 -73
  105. package/dist/{tool-provider/runtime-service.d.ts → tool-factories/agent-spawner/runtime.d.ts} +8 -6
  106. package/dist/tool-factories/agent-spawner/runtime.d.ts.map +1 -0
  107. package/dist/{tool-provider/runtime-service.js → tool-factories/agent-spawner/runtime.js} +98 -69
  108. package/dist/{tool-provider → tool-factories/agent-spawner}/schemas.cjs +2 -2
  109. package/dist/{tool-provider → tool-factories/agent-spawner}/schemas.d.ts +4 -4
  110. package/dist/tool-factories/agent-spawner/schemas.d.ts.map +1 -0
  111. package/dist/{tool-provider → tool-factories/agent-spawner}/schemas.js +2 -2
  112. package/dist/{tool-provider → tool-factories/agent-spawner}/spawn-agent-tool.cjs +8 -7
  113. package/dist/tool-factories/agent-spawner/spawn-agent-tool.d.ts +11 -0
  114. package/dist/tool-factories/agent-spawner/spawn-agent-tool.d.ts.map +1 -0
  115. package/dist/{tool-provider → tool-factories/agent-spawner}/spawn-agent-tool.js +8 -7
  116. package/dist/tool-factories/agent-spawner/types.d.ts.map +1 -0
  117. package/dist/utils/api-key-resolver.cjs +1 -1
  118. package/dist/utils/api-key-resolver.js +1 -1
  119. package/dist/utils/feature-flags.cjs +3 -1
  120. package/dist/utils/feature-flags.d.ts +2 -2
  121. package/dist/utils/feature-flags.d.ts.map +1 -1
  122. package/dist/utils/feature-flags.js +3 -1
  123. package/dist/writer.d.ts +2 -1
  124. package/dist/writer.d.ts.map +1 -1
  125. package/package.json +6 -3
  126. package/dist/tool-provider/error-codes.d.ts.map +0 -1
  127. package/dist/tool-provider/errors.d.ts.map +0 -1
  128. package/dist/tool-provider/index.d.ts.map +0 -1
  129. package/dist/tool-provider/llm-resolution.d.ts.map +0 -1
  130. package/dist/tool-provider/runtime-service.d.ts.map +0 -1
  131. package/dist/tool-provider/schemas.d.ts.map +0 -1
  132. package/dist/tool-provider/spawn-agent-tool.d.ts +0 -10
  133. package/dist/tool-provider/spawn-agent-tool.d.ts.map +0 -1
  134. package/dist/tool-provider/tool-provider.cjs +0 -46
  135. package/dist/tool-provider/tool-provider.d.ts +0 -24
  136. package/dist/tool-provider/tool-provider.d.ts.map +0 -1
  137. package/dist/tool-provider/tool-provider.js +0 -22
  138. package/dist/tool-provider/types.d.ts.map +0 -1
  139. /package/dist/{tool-provider → tool-factories/agent-spawner}/error-codes.cjs +0 -0
  140. /package/dist/{tool-provider → tool-factories/agent-spawner}/error-codes.js +0 -0
  141. /package/dist/{tool-provider → tool-factories/agent-spawner}/errors.cjs +0 -0
  142. /package/dist/{tool-provider → tool-factories/agent-spawner}/errors.js +0 -0
  143. /package/dist/{tool-provider → tool-factories/agent-spawner}/types.cjs +0 -0
  144. /package/dist/{tool-provider → tool-factories/agent-spawner}/types.d.ts +0 -0
  145. /package/dist/{tool-provider → tool-factories/agent-spawner}/types.js +0 -0
@@ -39,29 +39,14 @@ function validatePluginDirectory(pluginPath) {
39
39
  const errors = [];
40
40
  const warnings = [];
41
41
  let manifest;
42
- let format;
43
42
  const absolutePath = path.isAbsolute(pluginPath) ? pluginPath : path.resolve(pluginPath);
44
43
  if (!(0, import_fs.existsSync)(absolutePath)) {
45
44
  errors.push(`Directory does not exist: ${absolutePath}`);
46
45
  return { valid: false, errors, warnings };
47
46
  }
48
- const dextoPluginDir = path.join(absolutePath, ".dexto-plugin");
49
- const claudePluginDir = path.join(absolutePath, ".claude-plugin");
50
- let manifestPath;
51
- if ((0, import_fs.existsSync)(dextoPluginDir)) {
52
- manifestPath = path.join(dextoPluginDir, "plugin.json");
53
- format = "dexto";
54
- } else if ((0, import_fs.existsSync)(claudePluginDir)) {
55
- manifestPath = path.join(claudePluginDir, "plugin.json");
56
- format = "claude-code";
57
- } else {
58
- errors.push("Missing .dexto-plugin or .claude-plugin directory");
59
- return { valid: false, errors, warnings };
60
- }
47
+ const manifestPath = path.join(absolutePath, ".claude-plugin", "plugin.json");
61
48
  if (!(0, import_fs.existsSync)(manifestPath)) {
62
- errors.push(
63
- `Missing ${format === "dexto" ? ".dexto-plugin" : ".claude-plugin"}/plugin.json`
64
- );
49
+ errors.push("Missing .claude-plugin/plugin.json");
65
50
  return { valid: false, errors, warnings };
66
51
  }
67
52
  try {
@@ -75,8 +60,7 @@ function validatePluginDirectory(pluginPath) {
75
60
  );
76
61
  return { valid: false, errors, warnings };
77
62
  }
78
- const schema = format === "dexto" ? import_schemas.DextoPluginManifestSchema : import_schemas.PluginManifestSchema;
79
- const result = schema.safeParse(parsed);
63
+ const result = import_schemas.PluginManifestSchema.safeParse(parsed);
80
64
  if (!result.success) {
81
65
  const issues = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`);
82
66
  errors.push(`Schema validation failed: ${issues.join("; ")}`);
@@ -112,7 +96,6 @@ function validatePluginDirectory(pluginPath) {
112
96
  return {
113
97
  valid: errors.length === 0,
114
98
  manifest,
115
- format,
116
99
  errors,
117
100
  warnings
118
101
  };
@@ -143,31 +126,18 @@ function checkDirectoryHasSkills(skillsDir) {
143
126
  return false;
144
127
  }
145
128
  }
146
- function tryLoadManifest(pluginPath, returnFormat) {
147
- const dextoManifestPath = path.join(pluginPath, ".dexto-plugin", "plugin.json");
148
- const claudeManifestPath = path.join(pluginPath, ".claude-plugin", "plugin.json");
149
- let manifestPath;
150
- let format;
151
- if ((0, import_fs.existsSync)(dextoManifestPath)) {
152
- manifestPath = dextoManifestPath;
153
- format = "dexto";
154
- } else if ((0, import_fs.existsSync)(claudeManifestPath)) {
155
- manifestPath = claudeManifestPath;
156
- format = "claude-code";
157
- } else {
129
+ function tryLoadManifest(pluginPath) {
130
+ const manifestPath = path.join(pluginPath, ".claude-plugin", "plugin.json");
131
+ if (!(0, import_fs.existsSync)(manifestPath)) {
158
132
  return null;
159
133
  }
160
134
  try {
161
135
  const content = (0, import_fs.readFileSync)(manifestPath, "utf-8");
162
136
  const parsed = JSON.parse(content);
163
- const schema = format === "dexto" ? import_schemas.DextoPluginManifestSchema : import_schemas.PluginManifestSchema;
164
- const result = schema.safeParse(parsed);
137
+ const result = import_schemas.PluginManifestSchema.safeParse(parsed);
165
138
  if (!result.success) {
166
139
  return null;
167
140
  }
168
- if (returnFormat) {
169
- return { manifest: result.data, format };
170
- }
171
141
  return result.data;
172
142
  } catch {
173
143
  return null;
@@ -4,24 +4,16 @@
4
4
  * Validates plugin directory structure and manifest.
5
5
  * Checks for required files, valid JSON, and schema compliance.
6
6
  *
7
- * Supports two plugin formats:
8
- * - .claude-plugin/plugin.json: Claude Code compatible format
9
- * - .dexto-plugin/plugin.json: Dexto-native format with extended features (preferred)
7
+ * Supports Claude Code compatible plugins:
8
+ * - .claude-plugin/plugin.json
10
9
  */
11
- import type { PluginValidationResult, PluginManifest, DextoPluginManifest, PluginFormat } from './types.js';
12
- /**
13
- * Extended validation result with plugin format
14
- */
15
- export interface ExtendedPluginValidationResult extends PluginValidationResult {
16
- /** Plugin format detected */
17
- format?: PluginFormat;
18
- }
10
+ import type { PluginValidationResult, PluginManifest } from './types.js';
19
11
  /**
20
12
  * Validates a plugin directory structure and manifest.
21
13
  *
22
14
  * Checks:
23
15
  * 1. Directory exists
24
- * 2. .dexto-plugin/plugin.json OR .claude-plugin/plugin.json exists (Dexto format preferred)
16
+ * 2. .claude-plugin/plugin.json exists
25
17
  * 3. plugin.json is valid JSON
26
18
  * 4. plugin.json matches schema (name is required)
27
19
  * 5. At least one command or skill exists (warning if none)
@@ -29,25 +21,15 @@ export interface ExtendedPluginValidationResult extends PluginValidationResult {
29
21
  * @param pluginPath Absolute or relative path to plugin directory
30
22
  * @returns Validation result with manifest (if valid), errors, and warnings
31
23
  */
32
- export declare function validatePluginDirectory(pluginPath: string): ExtendedPluginValidationResult;
33
- /**
34
- * Result of manifest loading with format information
35
- */
36
- export interface LoadedManifestResult {
37
- manifest: PluginManifest | DextoPluginManifest;
38
- format: PluginFormat;
39
- }
24
+ export declare function validatePluginDirectory(pluginPath: string): PluginValidationResult;
40
25
  /**
41
26
  * Attempts to load and validate a plugin manifest from a directory.
42
27
  * Returns null if the manifest doesn't exist, is invalid JSON, or fails schema validation.
43
28
  *
44
- * Checks for .dexto-plugin first (preferred), then falls back to .claude-plugin.
45
- *
46
29
  * This is a shared utility used by discover-plugins, list-plugins, and import-plugin.
47
30
  *
48
31
  * @param pluginPath Absolute path to the plugin directory
49
- * @returns Validated manifest with format or null if not a valid plugin
32
+ * @returns Validated manifest or null if not a valid plugin
50
33
  */
51
34
  export declare function tryLoadManifest(pluginPath: string): PluginManifest | null;
52
- export declare function tryLoadManifest(pluginPath: string, returnFormat: true): LoadedManifestResult | null;
53
35
  //# sourceMappingURL=validate-plugin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate-plugin.d.ts","sourceRoot":"","sources":["../../src/plugins/validate-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EACR,sBAAsB,EACtB,cAAc,EACd,mBAAmB,EACnB,YAAY,EACf,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,MAAM,WAAW,8BAA+B,SAAQ,sBAAsB;IAC1E,6BAA6B;IAC7B,MAAM,CAAC,EAAE,YAAY,CAAC;CACzB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,8BAA8B,CAyG1F;AAuCD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC,QAAQ,EAAE,cAAc,GAAG,mBAAmB,CAAC;IAC/C,MAAM,EAAE,YAAY,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAAC;AAC3E,wBAAgB,eAAe,CAC3B,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,IAAI,GACnB,oBAAoB,GAAG,IAAI,CAAC"}
1
+ {"version":3,"file":"validate-plugin.d.ts","sourceRoot":"","sources":["../../src/plugins/validate-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEzE;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,MAAM,GAAG,sBAAsB,CAsFlF;AAuCD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAmBzE"}
@@ -1,33 +1,18 @@
1
1
  import * as path from "path";
2
2
  import { existsSync, readFileSync, readdirSync } from "fs";
3
- import { PluginManifestSchema, DextoPluginManifestSchema } from "./schemas.js";
3
+ import { PluginManifestSchema } from "./schemas.js";
4
4
  function validatePluginDirectory(pluginPath) {
5
5
  const errors = [];
6
6
  const warnings = [];
7
7
  let manifest;
8
- let format;
9
8
  const absolutePath = path.isAbsolute(pluginPath) ? pluginPath : path.resolve(pluginPath);
10
9
  if (!existsSync(absolutePath)) {
11
10
  errors.push(`Directory does not exist: ${absolutePath}`);
12
11
  return { valid: false, errors, warnings };
13
12
  }
14
- const dextoPluginDir = path.join(absolutePath, ".dexto-plugin");
15
- const claudePluginDir = path.join(absolutePath, ".claude-plugin");
16
- let manifestPath;
17
- if (existsSync(dextoPluginDir)) {
18
- manifestPath = path.join(dextoPluginDir, "plugin.json");
19
- format = "dexto";
20
- } else if (existsSync(claudePluginDir)) {
21
- manifestPath = path.join(claudePluginDir, "plugin.json");
22
- format = "claude-code";
23
- } else {
24
- errors.push("Missing .dexto-plugin or .claude-plugin directory");
25
- return { valid: false, errors, warnings };
26
- }
13
+ const manifestPath = path.join(absolutePath, ".claude-plugin", "plugin.json");
27
14
  if (!existsSync(manifestPath)) {
28
- errors.push(
29
- `Missing ${format === "dexto" ? ".dexto-plugin" : ".claude-plugin"}/plugin.json`
30
- );
15
+ errors.push("Missing .claude-plugin/plugin.json");
31
16
  return { valid: false, errors, warnings };
32
17
  }
33
18
  try {
@@ -41,8 +26,7 @@ function validatePluginDirectory(pluginPath) {
41
26
  );
42
27
  return { valid: false, errors, warnings };
43
28
  }
44
- const schema = format === "dexto" ? DextoPluginManifestSchema : PluginManifestSchema;
45
- const result = schema.safeParse(parsed);
29
+ const result = PluginManifestSchema.safeParse(parsed);
46
30
  if (!result.success) {
47
31
  const issues = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`);
48
32
  errors.push(`Schema validation failed: ${issues.join("; ")}`);
@@ -78,7 +62,6 @@ function validatePluginDirectory(pluginPath) {
78
62
  return {
79
63
  valid: errors.length === 0,
80
64
  manifest,
81
- format,
82
65
  errors,
83
66
  warnings
84
67
  };
@@ -109,31 +92,18 @@ function checkDirectoryHasSkills(skillsDir) {
109
92
  return false;
110
93
  }
111
94
  }
112
- function tryLoadManifest(pluginPath, returnFormat) {
113
- const dextoManifestPath = path.join(pluginPath, ".dexto-plugin", "plugin.json");
114
- const claudeManifestPath = path.join(pluginPath, ".claude-plugin", "plugin.json");
115
- let manifestPath;
116
- let format;
117
- if (existsSync(dextoManifestPath)) {
118
- manifestPath = dextoManifestPath;
119
- format = "dexto";
120
- } else if (existsSync(claudeManifestPath)) {
121
- manifestPath = claudeManifestPath;
122
- format = "claude-code";
123
- } else {
95
+ function tryLoadManifest(pluginPath) {
96
+ const manifestPath = path.join(pluginPath, ".claude-plugin", "plugin.json");
97
+ if (!existsSync(manifestPath)) {
124
98
  return null;
125
99
  }
126
100
  try {
127
101
  const content = readFileSync(manifestPath, "utf-8");
128
102
  const parsed = JSON.parse(content);
129
- const schema = format === "dexto" ? DextoPluginManifestSchema : PluginManifestSchema;
130
- const result = schema.safeParse(parsed);
103
+ const result = PluginManifestSchema.safeParse(parsed);
131
104
  if (!result.success) {
132
105
  return null;
133
106
  }
134
- if (returnFormat) {
135
- return { manifest: result.data, format };
136
- }
137
107
  return result.data;
138
108
  } catch {
139
109
  return null;
@@ -66,6 +66,17 @@ class PreferenceError {
66
66
  }));
67
67
  return new import_core.DextoValidationError(issues);
68
68
  }
69
+ static invalidAgentId(agentId) {
70
+ return new import_core.DextoValidationError([
71
+ {
72
+ code: import_error_codes.PreferenceErrorCode.INVALID_PREFERENCE_VALUE,
73
+ message: `agentId is invalid: ${agentId}`,
74
+ scope: "preference",
75
+ type: import_core.ErrorType.USER,
76
+ severity: "error"
77
+ }
78
+ ]);
79
+ }
69
80
  }
70
81
  // Annotate the CommonJS export names for ESM import in node:
71
82
  0 && (module.exports = {
@@ -14,5 +14,6 @@ export declare class PreferenceError {
14
14
  cause: string;
15
15
  }>;
16
16
  static validationFailed(zodError: ZodError): DextoValidationError;
17
+ static invalidAgentId(agentId: string): DextoValidationError;
17
18
  }
18
19
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/preferences/errors.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAa,MAAM,aAAa,CAAC;AACjF,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AAGpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,qBAAa,eAAe;IACxB,MAAM,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM;;;IAW3C,MAAM,CAAC,aAAa,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;;;;IAW3D,MAAM,CAAC,cAAc,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;;;;IAW5D,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ;CAW7C"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/preferences/errors.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAa,MAAM,aAAa,CAAC;AACjF,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,KAAK,CAAC;AAGpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,qBAAa,eAAe;IACxB,MAAM,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM;;;IAW3C,MAAM,CAAC,aAAa,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;;;;IAW3D,MAAM,CAAC,cAAc,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;;;;IAW5D,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ;IAY1C,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM;CAWxC"}
@@ -42,6 +42,17 @@ class PreferenceError {
42
42
  }));
43
43
  return new DextoValidationError(issues);
44
44
  }
45
+ static invalidAgentId(agentId) {
46
+ return new DextoValidationError([
47
+ {
48
+ code: PreferenceErrorCode.INVALID_PREFERENCE_VALUE,
49
+ message: `agentId is invalid: ${agentId}`,
50
+ scope: "preference",
51
+ type: ErrorType.USER,
52
+ severity: "error"
53
+ }
54
+ ]);
55
+ }
45
56
  }
46
57
  export {
47
58
  PreferenceError,
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,28 +17,42 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
  var loader_exports = {};
20
30
  __export(loader_exports, {
31
+ agentPreferencesExist: () => agentPreferencesExist,
21
32
  createInitialPreferences: () => createInitialPreferences,
33
+ getAgentPreferencesPath: () => getAgentPreferencesPath,
22
34
  getGlobalPreferencesPath: () => getGlobalPreferencesPath,
23
35
  globalPreferencesExist: () => globalPreferencesExist,
36
+ loadAgentPreferences: () => loadAgentPreferences,
24
37
  loadGlobalPreferences: () => loadGlobalPreferences,
38
+ saveAgentPreferences: () => saveAgentPreferences,
25
39
  saveGlobalPreferences: () => saveGlobalPreferences,
40
+ updateAgentPreferences: () => updateAgentPreferences,
26
41
  updateGlobalPreferences: () => updateGlobalPreferences
27
42
  });
28
43
  module.exports = __toCommonJS(loader_exports);
29
44
  var import_fs = require("fs");
30
45
  var import_fs2 = require("fs");
31
46
  var import_yaml = require("yaml");
32
- var import_path = require("../utils/path.js");
47
+ var import_path = __toESM(require("path"), 1);
48
+ var import_path2 = require("../utils/path.js");
33
49
  var import_core = require("@dexto/core");
34
50
  var import_core2 = require("@dexto/core");
35
51
  var import_schemas = require("./schemas.js");
36
52
  var import_constants = require("./constants.js");
37
53
  var import_errors = require("./errors.js");
38
54
  async function loadGlobalPreferences() {
39
- const preferencesPath = (0, import_path.getDextoGlobalPath)(import_constants.PREFERENCES_FILE);
55
+ const preferencesPath = (0, import_path2.getDextoGlobalPath)(import_constants.PREFERENCES_FILE);
40
56
  if (!(0, import_fs.existsSync)(preferencesPath)) {
41
57
  throw import_errors.PreferenceError.fileNotFound(preferencesPath);
42
58
  }
@@ -70,15 +86,107 @@ const PREFERENCES_FILE_HEADER = `# Dexto Global Preferences
70
86
  # Set sounds.enabled: false to disable all sounds.
71
87
 
72
88
  `;
89
+ const AGENT_PREFERENCES_FILE_HEADER = `# Dexto Agent Preferences
90
+ # Stored per-agent to customize runtime behavior without changing base config.
91
+ # Tool control:
92
+ # tools.disabled: list of tool names to exclude from LLM context.
93
+
94
+ `;
95
+ function getAgentPreferencesPath(agentId) {
96
+ if (!agentId || typeof agentId !== "string") {
97
+ throw import_errors.PreferenceError.invalidAgentId(String(agentId));
98
+ }
99
+ const trimmedId = agentId.trim();
100
+ if (!trimmedId) {
101
+ throw import_errors.PreferenceError.invalidAgentId(agentId);
102
+ }
103
+ const hasSeparators = trimmedId.includes("/") || trimmedId.includes("\\");
104
+ if (hasSeparators || trimmedId !== import_path.default.basename(trimmedId)) {
105
+ throw import_errors.PreferenceError.invalidAgentId(agentId);
106
+ }
107
+ const allowedPattern = /^[a-zA-Z0-9_-]+$/;
108
+ if (!allowedPattern.test(trimmedId)) {
109
+ throw import_errors.PreferenceError.invalidAgentId(agentId);
110
+ }
111
+ const filename = `${trimmedId}.preferences.yml`;
112
+ return (0, import_path2.getDextoGlobalPath)(import_path.default.join("agents", filename));
113
+ }
114
+ async function loadAgentPreferences(agentId) {
115
+ const preferencesPath = getAgentPreferencesPath(agentId);
116
+ if (!(0, import_fs.existsSync)(preferencesPath)) {
117
+ throw import_errors.PreferenceError.fileNotFound(preferencesPath);
118
+ }
119
+ try {
120
+ const fileContent = await import_fs2.promises.readFile(preferencesPath, "utf-8");
121
+ const rawPreferences = (0, import_yaml.parse)(fileContent);
122
+ const validation = import_schemas.AgentPreferencesSchema.safeParse(rawPreferences);
123
+ if (!validation.success) {
124
+ throw import_errors.PreferenceError.validationFailed(validation.error);
125
+ }
126
+ import_core.logger.debug(`Loaded agent preferences from: ${preferencesPath}`);
127
+ return validation.data;
128
+ } catch (error) {
129
+ if (error instanceof import_core2.DextoValidationError || error instanceof import_core2.DextoRuntimeError) {
130
+ throw error;
131
+ }
132
+ throw import_errors.PreferenceError.fileReadError(
133
+ preferencesPath,
134
+ error instanceof Error ? error.message : String(error)
135
+ );
136
+ }
137
+ }
138
+ async function saveAgentPreferences(agentId, preferences) {
139
+ const preferencesPath = getAgentPreferencesPath(agentId);
140
+ const validation = import_schemas.AgentPreferencesSchema.safeParse(preferences);
141
+ if (!validation.success) {
142
+ throw import_errors.PreferenceError.validationFailed(validation.error);
143
+ }
144
+ try {
145
+ import_core.logger.debug(`Saving agent preferences to: ${preferencesPath}`);
146
+ await import_fs2.promises.mkdir(import_path.default.dirname(preferencesPath), { recursive: true });
147
+ const yamlContent = (0, import_yaml.stringify)(preferences, {
148
+ indent: 2,
149
+ lineWidth: 100,
150
+ minContentWidth: 20
151
+ });
152
+ await import_fs2.promises.writeFile(preferencesPath, AGENT_PREFERENCES_FILE_HEADER + yamlContent, "utf-8");
153
+ import_core.logger.debug(
154
+ `\u2713 Saved agent preferences ${JSON.stringify(preferences)} to: ${preferencesPath}`
155
+ );
156
+ } catch (error) {
157
+ throw import_errors.PreferenceError.fileWriteError(
158
+ preferencesPath,
159
+ error instanceof Error ? error.message : String(error)
160
+ );
161
+ }
162
+ }
163
+ function agentPreferencesExist(agentId) {
164
+ const preferencesPath = getAgentPreferencesPath(agentId);
165
+ return (0, import_fs.existsSync)(preferencesPath);
166
+ }
167
+ async function updateAgentPreferences(agentId, updates) {
168
+ const existing = await loadAgentPreferences(agentId);
169
+ const merged = {
170
+ ...existing,
171
+ ...updates,
172
+ tools: updates.tools ? { ...existing.tools, ...updates.tools } : existing.tools
173
+ };
174
+ const validation = import_schemas.AgentPreferencesSchema.safeParse(merged);
175
+ if (!validation.success) {
176
+ throw import_errors.PreferenceError.validationFailed(validation.error);
177
+ }
178
+ await saveAgentPreferences(agentId, validation.data);
179
+ return validation.data;
180
+ }
73
181
  async function saveGlobalPreferences(preferences) {
74
- const preferencesPath = (0, import_path.getDextoGlobalPath)(import_constants.PREFERENCES_FILE);
182
+ const preferencesPath = (0, import_path2.getDextoGlobalPath)(import_constants.PREFERENCES_FILE);
75
183
  const validation = import_schemas.GlobalPreferencesSchema.safeParse(preferences);
76
184
  if (!validation.success) {
77
185
  throw import_errors.PreferenceError.validationFailed(validation.error);
78
186
  }
79
187
  try {
80
188
  import_core.logger.debug(`Saving global preferences to: ${preferencesPath}`);
81
- const dextoDir = (0, import_path.getDextoGlobalPath)("");
189
+ const dextoDir = (0, import_path2.getDextoGlobalPath)("");
82
190
  await import_fs2.promises.mkdir(dextoDir, { recursive: true });
83
191
  const yamlContent = (0, import_yaml.stringify)(preferences, {
84
192
  indent: 2,
@@ -97,11 +205,11 @@ async function saveGlobalPreferences(preferences) {
97
205
  }
98
206
  }
99
207
  function globalPreferencesExist() {
100
- const preferencesPath = (0, import_path.getDextoGlobalPath)(import_constants.PREFERENCES_FILE);
208
+ const preferencesPath = (0, import_path2.getDextoGlobalPath)(import_constants.PREFERENCES_FILE);
101
209
  return (0, import_fs.existsSync)(preferencesPath);
102
210
  }
103
211
  function getGlobalPreferencesPath() {
104
- return (0, import_path.getDextoGlobalPath)(import_constants.PREFERENCES_FILE);
212
+ return (0, import_path2.getDextoGlobalPath)(import_constants.PREFERENCES_FILE);
105
213
  }
106
214
  function createInitialPreferences(options) {
107
215
  const llmConfig = {
@@ -156,10 +264,15 @@ async function updateGlobalPreferences(updates) {
156
264
  }
157
265
  // Annotate the CommonJS export names for ESM import in node:
158
266
  0 && (module.exports = {
267
+ agentPreferencesExist,
159
268
  createInitialPreferences,
269
+ getAgentPreferencesPath,
160
270
  getGlobalPreferencesPath,
161
271
  globalPreferencesExist,
272
+ loadAgentPreferences,
162
273
  loadGlobalPreferences,
274
+ saveAgentPreferences,
163
275
  saveGlobalPreferences,
276
+ updateAgentPreferences,
164
277
  updateGlobalPreferences
165
278
  });
@@ -1,5 +1,5 @@
1
1
  import type { LLMProvider } from '@dexto/core';
2
- import { type GlobalPreferences } from './schemas.js';
2
+ import { type AgentPreferences, type GlobalPreferences } from './schemas.js';
3
3
  /**
4
4
  * Load global preferences from ~/.dexto/preferences.yml
5
5
  * @returns Global preferences object
@@ -7,6 +7,26 @@ import { type GlobalPreferences } from './schemas.js';
7
7
  * @throws DextoValidationError if preferences are invalid
8
8
  */
9
9
  export declare function loadGlobalPreferences(): Promise<GlobalPreferences>;
10
+ /**
11
+ * Resolve the agent preferences file path for an agent ID.
12
+ */
13
+ export declare function getAgentPreferencesPath(agentId: string): string;
14
+ /**
15
+ * Load agent preferences from ~/.dexto/agents/<agentId>.preferences.yml
16
+ */
17
+ export declare function loadAgentPreferences(agentId: string): Promise<AgentPreferences>;
18
+ /**
19
+ * Save agent preferences to ~/.dexto/agents/<agentId>.preferences.yml
20
+ */
21
+ export declare function saveAgentPreferences(agentId: string, preferences: AgentPreferences): Promise<void>;
22
+ /**
23
+ * Check if agent preferences exist (for first-time detection)
24
+ */
25
+ export declare function agentPreferencesExist(agentId: string): boolean;
26
+ /**
27
+ * Update agent preferences with partial updates
28
+ */
29
+ export declare function updateAgentPreferences(agentId: string, updates: Partial<AgentPreferences>): Promise<AgentPreferences>;
10
30
  /**
11
31
  * Save global preferences to ~/.dexto/preferences.yml
12
32
  * @param preferences Validated preferences object
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/preferences/loader.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAA2B,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAI/E;;;;;GAKG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CA+BxE;AAiBD;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCzF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAGhD;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACrC,QAAQ,EAAE,WAAW,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,KAAK,CAAC;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;IAC3E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,yEAAyE;IACzE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,yEAAyE;IACzE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qCAAqC;IACrC,MAAM,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,cAAc,CAAC,EAAE,OAAO,CAAC;KAC5B,CAAC;CACL;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,wBAAwB,GAAG,iBAAiB,CAsC7F;AAED;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACnC,GAAG,CAAC,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC;IAClD,KAAK,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC5C,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;CACjD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CACzC,OAAO,EAAE,wBAAwB,GAClC,OAAO,CAAC,iBAAiB,CAAC,CA4B5B"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/preferences/loader.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAGH,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACzB,MAAM,cAAc,CAAC;AAItB;;;;;GAKG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CA+BxE;AA2BD;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAsB/D;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA4BrF;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACtC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,gBAAgB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA8Bf;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAG9D;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CACxC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,GACnC,OAAO,CAAC,gBAAgB,CAAC,CAgB3B;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCzF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAGhD;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACrC,QAAQ,EAAE,WAAW,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,KAAK,CAAC;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;IAC3E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,yEAAyE;IACzE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,yEAAyE;IACzE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qCAAqC;IACrC,MAAM,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,cAAc,CAAC,EAAE,OAAO,CAAC;KAC5B,CAAC;CACL;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,wBAAwB,GAAG,iBAAiB,CAsC7F;AAED;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACnC,GAAG,CAAC,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAC;IAClD,KAAK,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC5C,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;CACjD,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CACzC,OAAO,EAAE,wBAAwB,GAClC,OAAO,CAAC,iBAAiB,CAAC,CA4B5B"}
@@ -1,10 +1,14 @@
1
1
  import { existsSync } from "fs";
2
2
  import { promises as fs } from "fs";
3
3
  import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
4
+ import path from "path";
4
5
  import { getDextoGlobalPath } from "../utils/path.js";
5
6
  import { logger } from "@dexto/core";
6
7
  import { DextoValidationError, DextoRuntimeError } from "@dexto/core";
7
- import { GlobalPreferencesSchema } from "./schemas.js";
8
+ import {
9
+ AgentPreferencesSchema,
10
+ GlobalPreferencesSchema
11
+ } from "./schemas.js";
8
12
  import { PREFERENCES_FILE } from "./constants.js";
9
13
  import { PreferenceError } from "./errors.js";
10
14
  async function loadGlobalPreferences() {
@@ -42,6 +46,98 @@ const PREFERENCES_FILE_HEADER = `# Dexto Global Preferences
42
46
  # Set sounds.enabled: false to disable all sounds.
43
47
 
44
48
  `;
49
+ const AGENT_PREFERENCES_FILE_HEADER = `# Dexto Agent Preferences
50
+ # Stored per-agent to customize runtime behavior without changing base config.
51
+ # Tool control:
52
+ # tools.disabled: list of tool names to exclude from LLM context.
53
+
54
+ `;
55
+ function getAgentPreferencesPath(agentId) {
56
+ if (!agentId || typeof agentId !== "string") {
57
+ throw PreferenceError.invalidAgentId(String(agentId));
58
+ }
59
+ const trimmedId = agentId.trim();
60
+ if (!trimmedId) {
61
+ throw PreferenceError.invalidAgentId(agentId);
62
+ }
63
+ const hasSeparators = trimmedId.includes("/") || trimmedId.includes("\\");
64
+ if (hasSeparators || trimmedId !== path.basename(trimmedId)) {
65
+ throw PreferenceError.invalidAgentId(agentId);
66
+ }
67
+ const allowedPattern = /^[a-zA-Z0-9_-]+$/;
68
+ if (!allowedPattern.test(trimmedId)) {
69
+ throw PreferenceError.invalidAgentId(agentId);
70
+ }
71
+ const filename = `${trimmedId}.preferences.yml`;
72
+ return getDextoGlobalPath(path.join("agents", filename));
73
+ }
74
+ async function loadAgentPreferences(agentId) {
75
+ const preferencesPath = getAgentPreferencesPath(agentId);
76
+ if (!existsSync(preferencesPath)) {
77
+ throw PreferenceError.fileNotFound(preferencesPath);
78
+ }
79
+ try {
80
+ const fileContent = await fs.readFile(preferencesPath, "utf-8");
81
+ const rawPreferences = parseYaml(fileContent);
82
+ const validation = AgentPreferencesSchema.safeParse(rawPreferences);
83
+ if (!validation.success) {
84
+ throw PreferenceError.validationFailed(validation.error);
85
+ }
86
+ logger.debug(`Loaded agent preferences from: ${preferencesPath}`);
87
+ return validation.data;
88
+ } catch (error) {
89
+ if (error instanceof DextoValidationError || error instanceof DextoRuntimeError) {
90
+ throw error;
91
+ }
92
+ throw PreferenceError.fileReadError(
93
+ preferencesPath,
94
+ error instanceof Error ? error.message : String(error)
95
+ );
96
+ }
97
+ }
98
+ async function saveAgentPreferences(agentId, preferences) {
99
+ const preferencesPath = getAgentPreferencesPath(agentId);
100
+ const validation = AgentPreferencesSchema.safeParse(preferences);
101
+ if (!validation.success) {
102
+ throw PreferenceError.validationFailed(validation.error);
103
+ }
104
+ try {
105
+ logger.debug(`Saving agent preferences to: ${preferencesPath}`);
106
+ await fs.mkdir(path.dirname(preferencesPath), { recursive: true });
107
+ const yamlContent = stringifyYaml(preferences, {
108
+ indent: 2,
109
+ lineWidth: 100,
110
+ minContentWidth: 20
111
+ });
112
+ await fs.writeFile(preferencesPath, AGENT_PREFERENCES_FILE_HEADER + yamlContent, "utf-8");
113
+ logger.debug(
114
+ `\u2713 Saved agent preferences ${JSON.stringify(preferences)} to: ${preferencesPath}`
115
+ );
116
+ } catch (error) {
117
+ throw PreferenceError.fileWriteError(
118
+ preferencesPath,
119
+ error instanceof Error ? error.message : String(error)
120
+ );
121
+ }
122
+ }
123
+ function agentPreferencesExist(agentId) {
124
+ const preferencesPath = getAgentPreferencesPath(agentId);
125
+ return existsSync(preferencesPath);
126
+ }
127
+ async function updateAgentPreferences(agentId, updates) {
128
+ const existing = await loadAgentPreferences(agentId);
129
+ const merged = {
130
+ ...existing,
131
+ ...updates,
132
+ tools: updates.tools ? { ...existing.tools, ...updates.tools } : existing.tools
133
+ };
134
+ const validation = AgentPreferencesSchema.safeParse(merged);
135
+ if (!validation.success) {
136
+ throw PreferenceError.validationFailed(validation.error);
137
+ }
138
+ await saveAgentPreferences(agentId, validation.data);
139
+ return validation.data;
140
+ }
45
141
  async function saveGlobalPreferences(preferences) {
46
142
  const preferencesPath = getDextoGlobalPath(PREFERENCES_FILE);
47
143
  const validation = GlobalPreferencesSchema.safeParse(preferences);
@@ -127,10 +223,15 @@ async function updateGlobalPreferences(updates) {
127
223
  return validation.data;
128
224
  }
129
225
  export {
226
+ agentPreferencesExist,
130
227
  createInitialPreferences,
228
+ getAgentPreferencesPath,
131
229
  getGlobalPreferencesPath,
132
230
  globalPreferencesExist,
231
+ loadAgentPreferences,
133
232
  loadGlobalPreferences,
233
+ saveAgentPreferences,
134
234
  saveGlobalPreferences,
235
+ updateAgentPreferences,
135
236
  updateGlobalPreferences
136
237
  };