@dexto/agent-management 1.7.2 → 1.8.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 (57) hide show
  1. package/dist/agent-creation.cjs +6 -2
  2. package/dist/agent-creation.d.ts.map +1 -1
  3. package/dist/agent-creation.js +6 -2
  4. package/dist/config/config-enrichment.cjs +1 -16
  5. package/dist/config/config-enrichment.d.ts.map +1 -1
  6. package/dist/config/config-enrichment.js +2 -21
  7. package/dist/index.cjs +4 -0
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +4 -0
  11. package/dist/models/model-picker-state.cjs +2 -2
  12. package/dist/models/model-picker-state.d.ts +1 -1
  13. package/dist/models/model-picker-state.d.ts.map +1 -1
  14. package/dist/models/model-picker-state.js +1 -1
  15. package/dist/plugins/discover-skills.d.ts +2 -3
  16. package/dist/plugins/discover-skills.d.ts.map +1 -1
  17. package/dist/plugins/index.cjs +6 -0
  18. package/dist/plugins/index.d.ts +4 -0
  19. package/dist/plugins/index.d.ts.map +1 -1
  20. package/dist/plugins/index.js +4 -0
  21. package/dist/plugins/local-skill-source.cjs +104 -0
  22. package/dist/plugins/local-skill-source.d.ts +20 -0
  23. package/dist/plugins/local-skill-source.d.ts.map +1 -0
  24. package/dist/plugins/local-skill-source.js +70 -0
  25. package/dist/plugins/local-skill-sources.cjs +74 -0
  26. package/dist/plugins/local-skill-sources.d.ts +7 -0
  27. package/dist/plugins/local-skill-sources.d.ts.map +1 -0
  28. package/dist/plugins/local-skill-sources.js +40 -0
  29. package/dist/plugins/types.d.ts +1 -1
  30. package/dist/preferences/loader.d.ts +1 -1
  31. package/dist/preferences/loader.d.ts.map +1 -1
  32. package/dist/preferences/schemas.cjs +8 -7
  33. package/dist/preferences/schemas.d.ts.map +1 -1
  34. package/dist/preferences/schemas.js +3 -5
  35. package/dist/tool-factories/agent-spawner/factory.cjs +2 -4
  36. package/dist/tool-factories/agent-spawner/factory.d.ts.map +1 -1
  37. package/dist/tool-factories/agent-spawner/factory.js +2 -4
  38. package/dist/tool-factories/agent-spawner/llm-resolution.cjs +3 -3
  39. package/dist/tool-factories/agent-spawner/llm-resolution.js +1 -1
  40. package/dist/tool-factories/agent-spawner/runtime.cjs +8 -12
  41. package/dist/tool-factories/agent-spawner/runtime.d.ts +3 -3
  42. package/dist/tool-factories/agent-spawner/runtime.d.ts.map +1 -1
  43. package/dist/tool-factories/agent-spawner/runtime.js +6 -15
  44. package/dist/tool-factories/agent-spawner/schemas.d.ts +1 -1
  45. package/dist/tool-factories/agent-spawner/schemas.d.ts.map +1 -1
  46. package/dist/tool-factories/creator-tools/factory.cjs +49 -146
  47. package/dist/tool-factories/creator-tools/factory.d.ts.map +1 -1
  48. package/dist/tool-factories/creator-tools/factory.js +50 -148
  49. package/dist/utils/api-key-resolver.d.ts +1 -1
  50. package/dist/utils/api-key-resolver.d.ts.map +1 -1
  51. package/dist/utils/api-key-store.cjs +2 -2
  52. package/dist/utils/api-key-store.d.ts +1 -1
  53. package/dist/utils/api-key-store.d.ts.map +1 -1
  54. package/dist/utils/api-key-store.js +1 -1
  55. package/dist/writer.d.ts +1 -1
  56. package/dist/writer.d.ts.map +1 -1
  57. package/package.json +6 -5
@@ -33,7 +33,6 @@ __export(factory_exports, {
33
33
  module.exports = __toCommonJS(factory_exports);
34
34
  var import_node_fs = require("node:fs");
35
35
  var import_node_path = __toESM(require("node:path"), 1);
36
- var import_yaml = require("yaml");
37
36
  var import_core = require("@dexto/core");
38
37
  var import_discover_skills = require("../../plugins/discover-skills.js");
39
38
  var import_schemas = require("./schemas.js");
@@ -43,8 +42,6 @@ const SkillCreateInputSchema = import_zod.z.object({
43
42
  id: import_zod.z.string().min(1).describe("Skill id (kebab-case)."),
44
43
  description: import_zod.z.string().min(1).describe("Short description of what the skill does."),
45
44
  content: import_zod.z.string().min(1).describe("Skill body (markdown) without frontmatter."),
46
- allowedTools: import_zod.z.array(import_zod.z.string().min(1)).optional().describe("Optional allowed-tools list for the skill frontmatter."),
47
- toolkits: import_zod.z.array(import_zod.z.string().min(1)).optional().describe("Optional toolkits list for the skill frontmatter."),
48
45
  scope: import_zod.z.enum(["global", "workspace"]).optional(),
49
46
  overwrite: import_zod.z.boolean().optional()
50
47
  }).strict();
@@ -52,8 +49,6 @@ const SkillUpdateInputSchema = import_zod.z.object({
52
49
  id: import_zod.z.string().min(1),
53
50
  content: import_zod.z.string().min(1).describe("New SKILL.md body (markdown) without frontmatter."),
54
51
  description: import_zod.z.string().min(1).optional(),
55
- allowedTools: import_zod.z.array(import_zod.z.string().min(1)).optional().describe("Optional allowed-tools list for the skill frontmatter."),
56
- toolkits: import_zod.z.array(import_zod.z.string().min(1)).optional().describe("Optional toolkits list for the skill frontmatter."),
57
52
  scope: import_zod.z.enum(["global", "workspace"]).optional()
58
53
  }).strict();
59
54
  const SkillListInputSchema = import_zod.z.object({
@@ -85,8 +80,8 @@ function matchesSkillQuery(value, query) {
85
80
  if (!normalizedQuery) return false;
86
81
  return normalizeSkillQuery(value).includes(normalizedQuery);
87
82
  }
88
- function resolvePromptSkillName(info, id) {
89
- return info.displayName || info.name || id;
83
+ function resolveSkillName(info) {
84
+ return info.displayName || info.id;
90
85
  }
91
86
  function resolveWorkspaceBasePath(context) {
92
87
  const workspacePath = context.workspace?.path;
@@ -101,25 +96,6 @@ function resolveWorkspaceSkillDirs(context) {
101
96
  legacy: import_node_path.default.join(base, ".dexto", "skills")
102
97
  };
103
98
  }
104
- function findRegisteredSkillFile(skillId, context) {
105
- const prompts = context.agent?.getEffectiveConfig().prompts;
106
- if (!Array.isArray(prompts)) {
107
- return void 0;
108
- }
109
- for (const prompt of prompts) {
110
- if (!prompt || typeof prompt !== "object" || prompt.type !== "file") {
111
- continue;
112
- }
113
- const filePath = typeof prompt.file === "string" ? prompt.file : void 0;
114
- if (!filePath || import_node_path.default.basename(filePath) !== "SKILL.md") {
115
- continue;
116
- }
117
- if (import_node_path.default.basename(import_node_path.default.dirname(filePath)) === skillId) {
118
- return filePath;
119
- }
120
- }
121
- return void 0;
122
- }
123
99
  function resolveSkillBaseDirectory(scope, context) {
124
100
  if (scope === "global") {
125
101
  return { baseDir: (0, import_path.getDextoGlobalPath)("skills"), scope: "global" };
@@ -153,20 +129,6 @@ async function resolveSkillUpdateDirectory(input, context) {
153
129
  return { baseDir: primary, scope: "workspace" };
154
130
  }
155
131
  async function resolveExistingSkillLocation(input, context) {
156
- if (input.scope !== "global") {
157
- const registeredSkillFile = findRegisteredSkillFile(input.id.trim(), context);
158
- if (registeredSkillFile) {
159
- const skillDir2 = import_node_path.default.dirname(registeredSkillFile);
160
- const baseDir2 = import_node_path.default.dirname(skillDir2);
161
- ensurePathWithinBase(baseDir2, skillDir2, "skill_refresh");
162
- return {
163
- baseDir: baseDir2,
164
- scope: "workspace",
165
- skillDir: skillDir2,
166
- skillFile: registeredSkillFile
167
- };
168
- }
169
- }
170
132
  const { baseDir, scope } = await resolveSkillUpdateDirectory(input, context);
171
133
  const skillDir = import_node_path.default.join(baseDir, input.id.trim());
172
134
  ensurePathWithinBase(baseDir, skillDir, "skill_refresh");
@@ -206,10 +168,6 @@ function resolveSkillCreateInput(input) {
206
168
  content
207
169
  };
208
170
  }
209
- function formatFrontmatterList(key, values) {
210
- const normalized = values.map((value) => JSON.stringify(value.trim()));
211
- return `${key}: [${normalized.join(", ")}]`;
212
- }
213
171
  function buildSkillMarkdownFromParts(options) {
214
172
  const id = options.id.trim();
215
173
  const title = titleizeSkillId(id) || id;
@@ -217,12 +175,6 @@ function buildSkillMarkdownFromParts(options) {
217
175
  const lines = ["---"];
218
176
  lines.push(formatFrontmatterLine("name", id));
219
177
  lines.push(formatFrontmatterLine("description", options.description.trim()));
220
- if (options.toolkits && options.toolkits.length > 0) {
221
- lines.push(formatFrontmatterList("toolkits", options.toolkits));
222
- }
223
- if (options.allowedTools && options.allowedTools.length > 0) {
224
- lines.push(formatFrontmatterList("allowed-tools", options.allowedTools));
225
- }
226
178
  lines.push("---", "", `# ${title}`);
227
179
  if (body.length > 0) {
228
180
  lines.push("", body);
@@ -239,69 +191,36 @@ function buildSkillMarkdown(input) {
239
191
  return buildSkillMarkdownFromParts({
240
192
  id: input.id,
241
193
  description: input.description,
242
- content: input.content,
243
- allowedTools: input.allowedTools,
244
- toolkits: input.toolkits
194
+ content: input.content
245
195
  });
246
196
  }
247
- async function readSkillFrontmatter(skillFile) {
197
+ function frontmatterDescription(markdown) {
198
+ if (!markdown.startsWith("---\n")) return void 0;
199
+ const end = markdown.indexOf("\n---", 4);
200
+ if (end < 0) return void 0;
201
+ const line = markdown.slice(4, end).split("\n").find((candidate) => candidate.trim().startsWith("description:"));
202
+ return line?.split(":").slice(1).join(":").trim().replace(/^"|"$/g, "") || void 0;
203
+ }
204
+ async function readSkillDescription(skillFile) {
248
205
  try {
249
206
  const raw = await import_node_fs.promises.readFile(skillFile, "utf-8");
250
- const match = raw.match(/^---\s*\n([\s\S]*?)\n---\s*\n/);
251
- if (!match) return {};
252
- const frontmatter = (0, import_yaml.parse)(match[1] ?? "");
253
- if (!frontmatter || typeof frontmatter !== "object") return {};
254
- const name = typeof frontmatter.name === "string" ? frontmatter.name.trim() : void 0;
255
- const description = typeof frontmatter.description === "string" ? frontmatter.description.trim() : void 0;
256
- const allowedToolsRaw = frontmatter["allowed-tools"];
257
- const toolkitsRaw = frontmatter.toolkits;
258
- const allowedTools = Array.isArray(allowedToolsRaw) ? allowedToolsRaw.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length > 0) : void 0;
259
- const toolkits = Array.isArray(toolkitsRaw) ? toolkitsRaw.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length > 0) : void 0;
260
- const result = {};
261
- if (name) result.name = name;
262
- if (description) result.description = description;
263
- if (allowedTools && allowedTools.length > 0) result.allowedTools = allowedTools;
264
- if (toolkits && toolkits.length > 0) result.toolkits = toolkits;
265
- return result;
207
+ return frontmatterDescription(raw);
266
208
  } catch {
267
- return {};
209
+ return void 0;
268
210
  }
269
211
  }
270
- async function refreshAgentPrompts(context, skillFile) {
271
- const agent = context.agent;
272
- if (!agent) return false;
273
- const effective = agent.getEffectiveConfig();
274
- const existingPrompts = Array.isArray(effective.prompts) ? [...effective.prompts] : [];
275
- const alreadyPresent = existingPrompts.some((prompt) => {
276
- if (!prompt || typeof prompt !== "object") return false;
277
- const record = prompt;
278
- return record.type === "file" && record.file === skillFile;
279
- });
280
- const nextPrompts = alreadyPresent ? existingPrompts : [...existingPrompts, { type: "file", file: skillFile }];
281
- await agent.refreshPrompts(nextPrompts);
212
+ async function refreshAgentSkills(context) {
213
+ const skillManager = context.services?.skills;
214
+ if (!skillManager) return false;
215
+ await skillManager.refresh();
282
216
  return true;
283
217
  }
284
- function buildSkillBundleNotes(bundledMcpServers) {
285
- const notes = [
286
- "Creating or editing files under mcps/ only defines bundled MCP config. It does not implement or verify the target MCP server.",
287
- "After editing SKILL.md or bundled MCP files with non-creator tools, run skill_refresh so the current session sees the latest skill content and MCP metadata."
288
- ];
289
- if (bundledMcpServers.length > 0) {
290
- notes.push(
291
- "Bundled MCP config is present. Only describe the skill as shipping a real MCP when the config points at a bundled runnable server or a verified external command/package."
292
- );
293
- }
294
- return notes;
295
- }
296
- function inspectSkillBundle(skillDir, skillId) {
297
- const bundledMcpResult = (0, import_core.loadBundledMcpConfigFromDirectory)(skillDir, skillId, {
298
- scanNestedMcps: true
299
- });
300
- const bundledMcpServers = Object.keys(bundledMcpResult.mcpServers ?? {});
218
+ function inspectSkillBundle() {
301
219
  return {
302
- bundledMcpServers,
303
- bundledMcpWarnings: bundledMcpResult.warnings,
304
- notes: buildSkillBundleNotes(bundledMcpServers)
220
+ notes: [
221
+ "Files under mcps/ are inert bundled files. Configure MCP servers through normal MCP configuration paths.",
222
+ "After editing SKILL.md or bundled files with non-creator tools, run skill_refresh so the current session sees the latest skill content."
223
+ ]
305
224
  };
306
225
  }
307
226
  const creatorToolsFactory = {
@@ -315,7 +234,7 @@ const creatorToolsFactory = {
315
234
  const enabledTools = config.enabledTools ?? import_schemas.CREATOR_TOOL_NAMES;
316
235
  const skillCreateTool = (0, import_core.defineTool)({
317
236
  id: "skill_create",
318
- description: "Create a standalone SKILL.md file, scaffold bundled resource directories, and register it with the running agent. This scaffolds mcps/ but does not implement or verify an MCP server.",
237
+ description: "Create a standalone SKILL.md file, scaffold bundled resource directories, and register it with the running agent. Files under mcps/ are inert bundled files.",
319
238
  inputSchema: SkillCreateInputSchema,
320
239
  execute: async (input, context) => {
321
240
  const resolvedInput = resolveSkillCreateInput(input);
@@ -343,9 +262,9 @@ const creatorToolsFactory = {
343
262
  (directory) => import_node_fs.promises.mkdir(import_node_path.default.join(skillDir, directory), { recursive: true })
344
263
  )
345
264
  );
346
- const refreshed = await refreshAgentPrompts(context, skillFile);
265
+ const refreshed = await refreshAgentSkills(context);
347
266
  const displayName = titleizeSkillId(skillId) || skillId;
348
- const bundleDetails = inspectSkillBundle(skillDir, skillId);
267
+ const bundleDetails = inspectSkillBundle();
349
268
  return {
350
269
  created: true,
351
270
  id: skillId,
@@ -356,7 +275,7 @@ const creatorToolsFactory = {
356
275
  resourceDirectories: SKILL_RESOURCE_DIRECTORIES.map(
357
276
  (directory) => import_node_path.default.join(skillDir, directory)
358
277
  ),
359
- promptsRefreshed: refreshed,
278
+ skillsRefreshed: refreshed,
360
279
  ...bundleDetails
361
280
  };
362
281
  }
@@ -371,10 +290,7 @@ const creatorToolsFactory = {
371
290
  context: "skill_update",
372
291
  hint: "Use kebab-case skill ids (e.g., release-notes)"
373
292
  });
374
- const { scope, skillDir, skillFile } = await resolveExistingSkillLocation(
375
- input,
376
- context
377
- );
293
+ const { scope, skillFile } = await resolveExistingSkillLocation(input, context);
378
294
  const exists = await pathExists(skillFile);
379
295
  if (!exists) {
380
296
  throw import_core.ToolError.validationFailed(
@@ -382,40 +298,36 @@ const creatorToolsFactory = {
382
298
  `Skill not found at ${skillFile}`
383
299
  );
384
300
  }
385
- const existing = await readSkillFrontmatter(skillFile);
386
- const description = input.description?.trim() || existing.description;
301
+ const existingDescription = await readSkillDescription(skillFile);
302
+ const description = input.description?.trim() || existingDescription;
387
303
  if (!description) {
388
304
  throw import_core.ToolError.validationFailed(
389
305
  "skill_update",
390
306
  "description is required when the existing skill is missing one"
391
307
  );
392
308
  }
393
- const allowedTools = input.allowedTools !== void 0 ? input.allowedTools : existing.allowedTools;
394
- const toolkits = input.toolkits !== void 0 ? input.toolkits : existing.toolkits;
395
309
  const markdown = buildSkillMarkdownFromParts({
396
310
  id: skillId,
397
311
  description,
398
- content: input.content.trim(),
399
- allowedTools,
400
- toolkits
312
+ content: input.content.trim()
401
313
  });
402
314
  await import_node_fs.promises.writeFile(skillFile, markdown, "utf-8");
403
- const refreshed = await refreshAgentPrompts(context, skillFile);
404
- const bundleDetails = inspectSkillBundle(skillDir, skillId);
315
+ const refreshed = await refreshAgentSkills(context);
316
+ const bundleDetails = inspectSkillBundle();
405
317
  return {
406
318
  updated: true,
407
319
  id: skillId,
408
320
  description,
409
321
  scope,
410
322
  path: skillFile,
411
- promptsRefreshed: refreshed,
323
+ skillsRefreshed: refreshed,
412
324
  ...bundleDetails
413
325
  };
414
326
  }
415
327
  });
416
328
  const skillRefreshTool = (0, import_core.defineTool)({
417
329
  id: "skill_refresh",
418
- description: "Refresh one standalone skill bundle in the current session after editing SKILL.md, mcps/, scripts/, or references/. Rebuilds prompt metadata so bundled MCP servers can be discovered without restarting.",
330
+ description: "Refresh one standalone skill bundle in the current session after editing SKILL.md, handlers/, scripts/, mcps/, or references/.",
419
331
  inputSchema: SkillRefreshInputSchema,
420
332
  execute: async (input, context) => {
421
333
  const skillId = input.id.trim();
@@ -423,15 +335,12 @@ const creatorToolsFactory = {
423
335
  context: "skill_refresh",
424
336
  hint: "Use kebab-case skill ids (e.g., release-notes)"
425
337
  });
426
- if (!context.agent) {
338
+ if (!context.services?.skills) {
427
339
  throw import_core.ToolError.configInvalid(
428
- "skill_refresh requires ToolExecutionContext.agent"
340
+ "skill_refresh requires ToolExecutionContext.services.skills"
429
341
  );
430
342
  }
431
- const { scope, skillDir, skillFile } = await resolveExistingSkillLocation(
432
- input,
433
- context
434
- );
343
+ const { scope, skillFile } = await resolveExistingSkillLocation(input, context);
435
344
  const exists = await pathExists(skillFile);
436
345
  if (!exists) {
437
346
  throw import_core.ToolError.validationFailed(
@@ -439,14 +348,14 @@ const creatorToolsFactory = {
439
348
  `Skill not found at ${skillFile}`
440
349
  );
441
350
  }
442
- const refreshed = await refreshAgentPrompts(context, skillFile);
443
- const bundleDetails = inspectSkillBundle(skillDir, skillId);
351
+ const refreshed = await refreshAgentSkills(context);
352
+ const bundleDetails = inspectSkillBundle();
444
353
  return {
445
354
  refreshed: true,
446
355
  id: skillId,
447
356
  scope,
448
357
  path: skillFile,
449
- promptsRefreshed: refreshed,
358
+ skillsRefreshed: refreshed,
450
359
  ...bundleDetails
451
360
  };
452
361
  }
@@ -460,28 +369,22 @@ const creatorToolsFactory = {
460
369
  const normalizedQuery = normalizeSkillQuery(query);
461
370
  const hasQuery = normalizedQuery.length > 0;
462
371
  const limit = input.limit ?? (hasQuery ? void 0 : 50);
463
- const promptManager = context.services?.prompts;
464
- if (!promptManager) {
372
+ const skillManager = context.services?.skills;
373
+ if (!skillManager) {
465
374
  throw import_core.ToolError.configInvalid(
466
- "skill_search requires ToolExecutionContext.services.prompts"
375
+ "skill_search requires ToolExecutionContext.services.skills"
467
376
  );
468
377
  }
469
- const loaded = await promptManager.list();
470
- let results = Object.entries(loaded).map(([id, info]) => ({
471
- id,
472
- name: resolvePromptSkillName(info, id),
473
- ...info.displayName ? { displayName: info.displayName } : {},
474
- ...info.commandName ? { commandName: info.commandName } : {},
475
- ...info.description ? { description: info.description } : {},
476
- ...info.context ? { context: info.context } : {},
477
- ...info.agent ? { agent: info.agent } : {}
378
+ const loaded = await skillManager.list();
379
+ let results = loaded.map((info) => ({
380
+ id: info.id,
381
+ name: resolveSkillName(info),
382
+ ...info.description ? { description: info.description } : {}
478
383
  }));
479
384
  if (hasQuery && normalizedQuery) {
480
385
  results = results.filter((entry) => {
481
386
  if (matchesSkillQuery(entry.id, normalizedQuery)) return true;
482
387
  if (matchesSkillQuery(entry.name, normalizedQuery)) return true;
483
- if (matchesSkillQuery(entry.displayName, normalizedQuery)) return true;
484
- if (matchesSkillQuery(entry.commandName, normalizedQuery)) return true;
485
388
  if (matchesSkillQuery(entry.description, normalizedQuery)) return true;
486
389
  return false;
487
390
  });
@@ -552,7 +455,7 @@ const creatorToolsFactory = {
552
455
  count: limited.length,
553
456
  total: tools.length,
554
457
  tools: limited,
555
- _hint: limited.length > 0 ? "Use tool ids in allowed-tools. Use toolkits from the agent config or image defaults." : "No tools matched the query."
458
+ _hint: limited.length > 0 ? "Use exact tool ids when configuring agent permissions." : "No tools matched the query."
556
459
  };
557
460
  }
558
461
  });
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/tool-factories/creator-tools/factory.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAYvD,OAAO,EAIH,KAAK,kBAAkB,EAC1B,MAAM,cAAc,CAAC;AAqetB,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,kBAAkB,CAqT/D,CAAC"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/tool-factories/creator-tools/factory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAUvD,OAAO,EAIH,KAAK,kBAAkB,EAC1B,MAAM,cAAc,CAAC;AAqVtB,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,kBAAkB,CAmS/D,CAAC"}