@dexto/agent-management 1.6.1 → 1.6.3
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.
- package/dist/agent-creation.cjs +2 -1
- package/dist/agent-creation.d.ts.map +1 -1
- package/dist/agent-creation.js +2 -1
- package/dist/index.cjs +5 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/models/custom-models.cjs +4 -3
- package/dist/models/custom-models.d.ts +26 -5
- package/dist/models/custom-models.d.ts.map +1 -1
- package/dist/models/custom-models.js +4 -3
- package/dist/preferences/loader.cjs +2 -2
- package/dist/preferences/loader.d.ts +3 -3
- package/dist/preferences/loader.d.ts.map +1 -1
- package/dist/preferences/loader.js +2 -2
- package/dist/preferences/schemas.cjs +42 -11
- package/dist/preferences/schemas.d.ts +60 -12
- package/dist/preferences/schemas.d.ts.map +1 -1
- package/dist/preferences/schemas.js +43 -7
- package/dist/tool-factories/agent-spawner/runtime.cjs +48 -1
- package/dist/tool-factories/agent-spawner/runtime.d.ts +3 -1
- package/dist/tool-factories/agent-spawner/runtime.d.ts.map +1 -1
- package/dist/tool-factories/agent-spawner/runtime.js +54 -2
- package/dist/tool-factories/agent-spawner/schemas.cjs +12 -0
- package/dist/tool-factories/agent-spawner/schemas.d.ts +9 -0
- package/dist/tool-factories/agent-spawner/schemas.d.ts.map +1 -1
- package/dist/tool-factories/agent-spawner/schemas.js +10 -0
- package/dist/tool-factories/creator-tools/factory.cjs +434 -0
- package/dist/tool-factories/creator-tools/factory.d.ts +4 -0
- package/dist/tool-factories/creator-tools/factory.d.ts.map +1 -0
- package/dist/tool-factories/creator-tools/factory.js +407 -0
- package/dist/tool-factories/creator-tools/index.cjs +33 -0
- package/dist/tool-factories/creator-tools/index.d.ts +3 -0
- package/dist/tool-factories/creator-tools/index.d.ts.map +1 -0
- package/dist/tool-factories/creator-tools/index.js +10 -0
- package/dist/tool-factories/creator-tools/schemas.cjs +41 -0
- package/dist/tool-factories/creator-tools/schemas.d.ts +15 -0
- package/dist/tool-factories/creator-tools/schemas.d.ts.map +1 -0
- package/dist/tool-factories/creator-tools/schemas.js +16 -0
- package/dist/utils/path.cjs +7 -1
- package/dist/utils/path.d.ts +8 -0
- package/dist/utils/path.d.ts.map +1 -1
- package/dist/utils/path.js +6 -1
- package/package.json +5 -5
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parse as yamlParse } from "yaml";
|
|
4
|
+
import {
|
|
5
|
+
ToolError,
|
|
6
|
+
defineTool,
|
|
7
|
+
assertValidPromptName
|
|
8
|
+
} from "@dexto/core";
|
|
9
|
+
import { discoverStandaloneSkills, getSkillSearchPaths } from "../../plugins/discover-skills.js";
|
|
10
|
+
import {
|
|
11
|
+
CREATOR_TOOL_NAMES,
|
|
12
|
+
CreatorToolsConfigSchema
|
|
13
|
+
} from "./schemas.js";
|
|
14
|
+
import { getDextoGlobalPath } from "../../utils/path.js";
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
const SkillCreateInputSchema = z.object({
|
|
17
|
+
id: z.string().min(1).describe("Skill id (kebab-case)."),
|
|
18
|
+
description: z.string().min(1).describe("Short description of what the skill does."),
|
|
19
|
+
content: z.string().min(1).describe("Skill body (markdown) without frontmatter."),
|
|
20
|
+
allowedTools: z.array(z.string().min(1)).optional().describe("Optional allowed-tools list for the skill frontmatter."),
|
|
21
|
+
toolkits: z.array(z.string().min(1)).optional().describe("Optional toolkits list for the skill frontmatter."),
|
|
22
|
+
scope: z.enum(["global", "workspace"]).optional(),
|
|
23
|
+
overwrite: z.boolean().optional()
|
|
24
|
+
}).strict();
|
|
25
|
+
const SkillUpdateInputSchema = z.object({
|
|
26
|
+
id: z.string().min(1),
|
|
27
|
+
content: z.string().min(1).describe("New SKILL.md body (markdown) without frontmatter."),
|
|
28
|
+
description: z.string().min(1).optional(),
|
|
29
|
+
allowedTools: z.array(z.string().min(1)).optional().describe("Optional allowed-tools list for the skill frontmatter."),
|
|
30
|
+
toolkits: z.array(z.string().min(1)).optional().describe("Optional toolkits list for the skill frontmatter."),
|
|
31
|
+
scope: z.enum(["global", "workspace"]).optional()
|
|
32
|
+
}).strict();
|
|
33
|
+
const SkillListInputSchema = z.object({
|
|
34
|
+
projectPath: z.string().optional(),
|
|
35
|
+
query: z.string().optional().describe("Optional search term to filter skills by name or path")
|
|
36
|
+
}).strict();
|
|
37
|
+
const SkillSearchInputSchema = z.object({
|
|
38
|
+
query: z.string().optional().describe("Optional search term to filter skills by name or description"),
|
|
39
|
+
limit: z.number().int().min(1).max(200).optional().describe(
|
|
40
|
+
"Maximum number of skills to return. If omitted, all matches are returned for queries; otherwise defaults to 50."
|
|
41
|
+
)
|
|
42
|
+
}).strict();
|
|
43
|
+
const ToolCatalogInputSchema = z.object({
|
|
44
|
+
query: z.string().optional().describe("Optional search term to filter tools by id or description"),
|
|
45
|
+
limit: z.number().int().min(1).max(500).optional().describe("Maximum number of tools to return (defaults to all)."),
|
|
46
|
+
includeDescriptions: z.boolean().optional().describe("Include tool descriptions (defaults to true).")
|
|
47
|
+
}).strict();
|
|
48
|
+
function normalizeSkillQuery(value) {
|
|
49
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
50
|
+
}
|
|
51
|
+
function matchesSkillQuery(value, query) {
|
|
52
|
+
if (!value) return false;
|
|
53
|
+
const normalizedQuery = normalizeSkillQuery(query);
|
|
54
|
+
if (!normalizedQuery) return false;
|
|
55
|
+
return normalizeSkillQuery(value).includes(normalizedQuery);
|
|
56
|
+
}
|
|
57
|
+
function resolvePromptSkillName(info, id) {
|
|
58
|
+
return info.displayName || info.name || id;
|
|
59
|
+
}
|
|
60
|
+
function resolveWorkspaceBasePath(context) {
|
|
61
|
+
const workspacePath = context.workspace?.path;
|
|
62
|
+
const fallbackWorkingDir = context.services ? context.services.filesystemService?.getConfig().workingDirectory : void 0;
|
|
63
|
+
return workspacePath || fallbackWorkingDir || process.cwd();
|
|
64
|
+
}
|
|
65
|
+
function resolveWorkspaceSkillDirs(context) {
|
|
66
|
+
const base = resolveWorkspaceBasePath(context);
|
|
67
|
+
return {
|
|
68
|
+
primary: path.join(base, ".agents", "skills"),
|
|
69
|
+
legacy: path.join(base, ".dexto", "skills")
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function resolveSkillBaseDirectory(scope, context) {
|
|
73
|
+
if (scope === "global") {
|
|
74
|
+
return { baseDir: getDextoGlobalPath("skills"), scope: "global" };
|
|
75
|
+
}
|
|
76
|
+
return { baseDir: resolveWorkspaceSkillDirs(context).primary, scope: "workspace" };
|
|
77
|
+
}
|
|
78
|
+
function resolveSkillDirectory(input, context) {
|
|
79
|
+
return resolveSkillBaseDirectory(input.scope, context);
|
|
80
|
+
}
|
|
81
|
+
async function pathExists(filePath) {
|
|
82
|
+
return await fs.stat(filePath).then(() => true).catch(() => false);
|
|
83
|
+
}
|
|
84
|
+
async function resolveSkillUpdateDirectory(input, context) {
|
|
85
|
+
if (input.scope === "global") {
|
|
86
|
+
return resolveSkillBaseDirectory("global", context);
|
|
87
|
+
}
|
|
88
|
+
const { primary, legacy } = resolveWorkspaceSkillDirs(context);
|
|
89
|
+
const skillId = input.id.trim();
|
|
90
|
+
const primaryFile = path.join(primary, skillId, "SKILL.md");
|
|
91
|
+
if (await pathExists(primaryFile)) {
|
|
92
|
+
return { baseDir: primary, scope: "workspace" };
|
|
93
|
+
}
|
|
94
|
+
const legacyFile = path.join(legacy, skillId, "SKILL.md");
|
|
95
|
+
if (await pathExists(legacyFile)) {
|
|
96
|
+
return { baseDir: legacy, scope: "workspace" };
|
|
97
|
+
}
|
|
98
|
+
return { baseDir: primary, scope: "workspace" };
|
|
99
|
+
}
|
|
100
|
+
function ensurePathWithinBase(baseDir, targetDir, toolId) {
|
|
101
|
+
const resolvedBase = path.resolve(baseDir);
|
|
102
|
+
const resolvedTarget = path.resolve(targetDir);
|
|
103
|
+
const rel = path.relative(resolvedBase, resolvedTarget);
|
|
104
|
+
if (rel.startsWith("..") || path.isAbsolute(rel)) {
|
|
105
|
+
throw ToolError.validationFailed(toolId, "invalid skill path");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function formatFrontmatterLine(key, value) {
|
|
109
|
+
if (typeof value === "string") {
|
|
110
|
+
return `${key}: ${JSON.stringify(value)}`;
|
|
111
|
+
}
|
|
112
|
+
return `${key}: ${value}`;
|
|
113
|
+
}
|
|
114
|
+
function titleizeSkillId(id) {
|
|
115
|
+
return id.split("-").filter(Boolean).map((segment) => segment[0]?.toUpperCase() + segment.slice(1)).join(" ");
|
|
116
|
+
}
|
|
117
|
+
function resolveSkillCreateInput(input) {
|
|
118
|
+
const id = input.id.trim();
|
|
119
|
+
const description = input.description.trim();
|
|
120
|
+
const content = input.content.trim();
|
|
121
|
+
return {
|
|
122
|
+
...input,
|
|
123
|
+
id,
|
|
124
|
+
description,
|
|
125
|
+
content
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function formatFrontmatterList(key, values) {
|
|
129
|
+
const normalized = values.map((value) => JSON.stringify(value.trim()));
|
|
130
|
+
return `${key}: [${normalized.join(", ")}]`;
|
|
131
|
+
}
|
|
132
|
+
function buildSkillMarkdownFromParts(options) {
|
|
133
|
+
const id = options.id.trim();
|
|
134
|
+
const title = titleizeSkillId(id) || id;
|
|
135
|
+
const lines = ["---"];
|
|
136
|
+
lines.push(formatFrontmatterLine("name", id));
|
|
137
|
+
lines.push(formatFrontmatterLine("description", options.description.trim()));
|
|
138
|
+
if (options.toolkits && options.toolkits.length > 0) {
|
|
139
|
+
lines.push(formatFrontmatterList("toolkits", options.toolkits));
|
|
140
|
+
}
|
|
141
|
+
if (options.allowedTools && options.allowedTools.length > 0) {
|
|
142
|
+
lines.push(formatFrontmatterList("allowed-tools", options.allowedTools));
|
|
143
|
+
}
|
|
144
|
+
lines.push("---", "", `# ${title}`, "", options.content.trim());
|
|
145
|
+
return lines.join("\n").replace(/\n{3,}/g, "\n\n");
|
|
146
|
+
}
|
|
147
|
+
function buildSkillMarkdown(input) {
|
|
148
|
+
return buildSkillMarkdownFromParts({
|
|
149
|
+
id: input.id,
|
|
150
|
+
description: input.description,
|
|
151
|
+
content: input.content,
|
|
152
|
+
allowedTools: input.allowedTools,
|
|
153
|
+
toolkits: input.toolkits
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
async function readSkillFrontmatter(skillFile) {
|
|
157
|
+
try {
|
|
158
|
+
const raw = await fs.readFile(skillFile, "utf-8");
|
|
159
|
+
const match = raw.match(/^---\s*\n([\s\S]*?)\n---\s*\n/);
|
|
160
|
+
if (!match) return {};
|
|
161
|
+
const frontmatter = yamlParse(match[1] ?? "");
|
|
162
|
+
if (!frontmatter || typeof frontmatter !== "object") return {};
|
|
163
|
+
const name = typeof frontmatter.name === "string" ? frontmatter.name.trim() : void 0;
|
|
164
|
+
const description = typeof frontmatter.description === "string" ? frontmatter.description.trim() : void 0;
|
|
165
|
+
const allowedToolsRaw = frontmatter["allowed-tools"];
|
|
166
|
+
const toolkitsRaw = frontmatter.toolkits;
|
|
167
|
+
const allowedTools = Array.isArray(allowedToolsRaw) ? allowedToolsRaw.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length > 0) : void 0;
|
|
168
|
+
const toolkits = Array.isArray(toolkitsRaw) ? toolkitsRaw.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length > 0) : void 0;
|
|
169
|
+
const result = {};
|
|
170
|
+
if (name) result.name = name;
|
|
171
|
+
if (description) result.description = description;
|
|
172
|
+
if (allowedTools && allowedTools.length > 0) result.allowedTools = allowedTools;
|
|
173
|
+
if (toolkits && toolkits.length > 0) result.toolkits = toolkits;
|
|
174
|
+
return result;
|
|
175
|
+
} catch {
|
|
176
|
+
return {};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
async function refreshAgentPrompts(context, skillFile) {
|
|
180
|
+
const agent = context.agent;
|
|
181
|
+
if (!agent) return false;
|
|
182
|
+
const effective = agent.getEffectiveConfig();
|
|
183
|
+
const existingPrompts = Array.isArray(effective.prompts) ? [...effective.prompts] : [];
|
|
184
|
+
const alreadyPresent = existingPrompts.some((prompt) => {
|
|
185
|
+
if (!prompt || typeof prompt !== "object") return false;
|
|
186
|
+
const record = prompt;
|
|
187
|
+
return record.type === "file" && record.file === skillFile;
|
|
188
|
+
});
|
|
189
|
+
const nextPrompts = alreadyPresent ? existingPrompts : [...existingPrompts, { type: "file", file: skillFile }];
|
|
190
|
+
await agent.refreshPrompts(nextPrompts);
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
const creatorToolsFactory = {
|
|
194
|
+
configSchema: CreatorToolsConfigSchema,
|
|
195
|
+
metadata: {
|
|
196
|
+
displayName: "Creator Tools",
|
|
197
|
+
description: "Create and manage standalone skills",
|
|
198
|
+
category: "agents"
|
|
199
|
+
},
|
|
200
|
+
create: (config) => {
|
|
201
|
+
const enabledTools = config.enabledTools ?? CREATOR_TOOL_NAMES;
|
|
202
|
+
const skillCreateTool = defineTool({
|
|
203
|
+
id: "skill_create",
|
|
204
|
+
description: "Create a standalone SKILL.md file and register it with the running agent. Provide id, description, content, and optional toolkits/allowedTools.",
|
|
205
|
+
inputSchema: SkillCreateInputSchema,
|
|
206
|
+
execute: async (input, context) => {
|
|
207
|
+
const resolvedInput = resolveSkillCreateInput(input);
|
|
208
|
+
const skillId = resolvedInput.id.trim();
|
|
209
|
+
assertValidPromptName(skillId, {
|
|
210
|
+
context: "skill_create",
|
|
211
|
+
hint: "Use kebab-case skill ids (e.g., release-notes)"
|
|
212
|
+
});
|
|
213
|
+
const { baseDir, scope } = resolveSkillDirectory(resolvedInput, context);
|
|
214
|
+
const skillDir = path.join(baseDir, skillId);
|
|
215
|
+
ensurePathWithinBase(baseDir, skillDir, "skill_create");
|
|
216
|
+
const skillFile = path.join(skillDir, "SKILL.md");
|
|
217
|
+
const exists = await pathExists(skillFile);
|
|
218
|
+
if (exists && !resolvedInput.overwrite) {
|
|
219
|
+
throw ToolError.validationFailed(
|
|
220
|
+
"skill_create",
|
|
221
|
+
`Skill already exists at ${skillFile}`
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
const markdown = buildSkillMarkdown(resolvedInput);
|
|
225
|
+
await fs.mkdir(skillDir, { recursive: true });
|
|
226
|
+
await fs.writeFile(skillFile, markdown, "utf-8");
|
|
227
|
+
const refreshed = await refreshAgentPrompts(context, skillFile);
|
|
228
|
+
const displayName = titleizeSkillId(skillId) || skillId;
|
|
229
|
+
return {
|
|
230
|
+
created: true,
|
|
231
|
+
id: skillId,
|
|
232
|
+
name: displayName,
|
|
233
|
+
description: resolvedInput.description.trim(),
|
|
234
|
+
scope,
|
|
235
|
+
path: skillFile,
|
|
236
|
+
promptsRefreshed: refreshed
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
const skillUpdateTool = defineTool({
|
|
241
|
+
id: "skill_update",
|
|
242
|
+
description: "Update an existing standalone SKILL.md file.",
|
|
243
|
+
inputSchema: SkillUpdateInputSchema,
|
|
244
|
+
execute: async (input, context) => {
|
|
245
|
+
const skillId = input.id.trim();
|
|
246
|
+
assertValidPromptName(skillId, {
|
|
247
|
+
context: "skill_update",
|
|
248
|
+
hint: "Use kebab-case skill ids (e.g., release-notes)"
|
|
249
|
+
});
|
|
250
|
+
const { baseDir, scope } = await resolveSkillUpdateDirectory(input, context);
|
|
251
|
+
const skillDir = path.join(baseDir, skillId);
|
|
252
|
+
ensurePathWithinBase(baseDir, skillDir, "skill_update");
|
|
253
|
+
const skillFile = path.join(skillDir, "SKILL.md");
|
|
254
|
+
const exists = await pathExists(skillFile);
|
|
255
|
+
if (!exists) {
|
|
256
|
+
throw ToolError.validationFailed(
|
|
257
|
+
"skill_update",
|
|
258
|
+
`Skill not found at ${skillFile}`
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
const existing = await readSkillFrontmatter(skillFile);
|
|
262
|
+
const description = input.description?.trim() || existing.description;
|
|
263
|
+
if (!description) {
|
|
264
|
+
throw ToolError.validationFailed(
|
|
265
|
+
"skill_update",
|
|
266
|
+
"description is required when the existing skill is missing one"
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
const allowedTools = input.allowedTools !== void 0 ? input.allowedTools : existing.allowedTools;
|
|
270
|
+
const toolkits = input.toolkits !== void 0 ? input.toolkits : existing.toolkits;
|
|
271
|
+
const markdown = buildSkillMarkdownFromParts({
|
|
272
|
+
id: skillId,
|
|
273
|
+
description,
|
|
274
|
+
content: input.content.trim(),
|
|
275
|
+
allowedTools,
|
|
276
|
+
toolkits
|
|
277
|
+
});
|
|
278
|
+
await fs.writeFile(skillFile, markdown, "utf-8");
|
|
279
|
+
const refreshed = await refreshAgentPrompts(context, skillFile);
|
|
280
|
+
return {
|
|
281
|
+
updated: true,
|
|
282
|
+
id: skillId,
|
|
283
|
+
description,
|
|
284
|
+
scope,
|
|
285
|
+
path: skillFile,
|
|
286
|
+
promptsRefreshed: refreshed
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
const skillSearchTool = defineTool({
|
|
291
|
+
id: "skill_search",
|
|
292
|
+
description: "Search loaded skills (supports query).",
|
|
293
|
+
inputSchema: SkillSearchInputSchema,
|
|
294
|
+
execute: async (input, context) => {
|
|
295
|
+
const query = input.query?.trim() ?? "";
|
|
296
|
+
const normalizedQuery = normalizeSkillQuery(query);
|
|
297
|
+
const hasQuery = normalizedQuery.length > 0;
|
|
298
|
+
const limit = input.limit ?? (hasQuery ? void 0 : 50);
|
|
299
|
+
const promptManager = context.services?.prompts;
|
|
300
|
+
if (!promptManager) {
|
|
301
|
+
throw ToolError.configInvalid(
|
|
302
|
+
"skill_search requires ToolExecutionContext.services.prompts"
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
const loaded = await promptManager.list();
|
|
306
|
+
let results = Object.entries(loaded).map(([id, info]) => ({
|
|
307
|
+
id,
|
|
308
|
+
name: resolvePromptSkillName(info, id),
|
|
309
|
+
...info.displayName ? { displayName: info.displayName } : {},
|
|
310
|
+
...info.commandName ? { commandName: info.commandName } : {},
|
|
311
|
+
...info.description ? { description: info.description } : {},
|
|
312
|
+
...info.context ? { context: info.context } : {},
|
|
313
|
+
...info.agent ? { agent: info.agent } : {}
|
|
314
|
+
}));
|
|
315
|
+
if (hasQuery && normalizedQuery) {
|
|
316
|
+
results = results.filter((entry) => {
|
|
317
|
+
if (matchesSkillQuery(entry.id, normalizedQuery)) return true;
|
|
318
|
+
if (matchesSkillQuery(entry.name, normalizedQuery)) return true;
|
|
319
|
+
if (matchesSkillQuery(entry.displayName, normalizedQuery)) return true;
|
|
320
|
+
if (matchesSkillQuery(entry.commandName, normalizedQuery)) return true;
|
|
321
|
+
if (matchesSkillQuery(entry.description, normalizedQuery)) return true;
|
|
322
|
+
return false;
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
results.sort((a, b) => a.name.localeCompare(b.name));
|
|
326
|
+
const limited = typeof limit === "number" ? results.slice(0, limit) : results;
|
|
327
|
+
return {
|
|
328
|
+
query: input.query?.trim(),
|
|
329
|
+
count: limited.length,
|
|
330
|
+
total: results.length,
|
|
331
|
+
skills: limited,
|
|
332
|
+
_hint: limited.length > 0 ? "Use invoke_skill with the skill id or commandName for loaded skills." : "No skills matched the query."
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
const skillListTool = defineTool({
|
|
337
|
+
id: "skill_list",
|
|
338
|
+
description: "List discovered standalone skills and their search paths. Supports optional query filtering.",
|
|
339
|
+
inputSchema: SkillListInputSchema,
|
|
340
|
+
execute: async (input) => {
|
|
341
|
+
const query = input.query?.trim().toLowerCase();
|
|
342
|
+
const skills = discoverStandaloneSkills(input.projectPath);
|
|
343
|
+
const filtered = query ? skills.filter((skill) => {
|
|
344
|
+
if (skill.name.toLowerCase().includes(query)) return true;
|
|
345
|
+
if (skill.path.toLowerCase().includes(query)) return true;
|
|
346
|
+
if (skill.skillFile.toLowerCase().includes(query)) return true;
|
|
347
|
+
return false;
|
|
348
|
+
}) : skills;
|
|
349
|
+
return {
|
|
350
|
+
searchPaths: getSkillSearchPaths(),
|
|
351
|
+
skills: filtered
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
const toolCatalogTool = defineTool({
|
|
356
|
+
id: "tool_catalog",
|
|
357
|
+
description: "List available tools and configured toolkits for the current agent (from the loaded image/config).",
|
|
358
|
+
inputSchema: ToolCatalogInputSchema,
|
|
359
|
+
execute: async (input, context) => {
|
|
360
|
+
const agent = context.agent;
|
|
361
|
+
if (!agent) {
|
|
362
|
+
throw ToolError.configInvalid(
|
|
363
|
+
"tool_catalog requires ToolExecutionContext.agent"
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
const toolSet = await agent.getAllTools();
|
|
367
|
+
let tools = Object.entries(toolSet).map(([id, tool]) => ({
|
|
368
|
+
id,
|
|
369
|
+
description: tool.description || "No description provided",
|
|
370
|
+
source: id.startsWith("mcp--") ? "mcp" : "local"
|
|
371
|
+
}));
|
|
372
|
+
const query = input.query?.trim().toLowerCase();
|
|
373
|
+
if (query) {
|
|
374
|
+
tools = tools.filter((tool) => {
|
|
375
|
+
if (tool.id.toLowerCase().includes(query)) return true;
|
|
376
|
+
if ((tool.description ?? "").toLowerCase().includes(query)) return true;
|
|
377
|
+
return false;
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
tools.sort((a, b) => a.id.localeCompare(b.id));
|
|
381
|
+
const includeDescriptions = input.includeDescriptions !== false;
|
|
382
|
+
if (!includeDescriptions) {
|
|
383
|
+
tools = tools.map((tool) => ({ id: tool.id, source: tool.source }));
|
|
384
|
+
}
|
|
385
|
+
const limited = typeof input.limit === "number" ? tools.slice(0, input.limit) : tools;
|
|
386
|
+
return {
|
|
387
|
+
query: input.query?.trim(),
|
|
388
|
+
count: limited.length,
|
|
389
|
+
total: tools.length,
|
|
390
|
+
tools: limited,
|
|
391
|
+
_hint: limited.length > 0 ? "Use tool ids in allowed-tools. Use toolkits from the agent config or image defaults." : "No tools matched the query."
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
const toolCreators = {
|
|
396
|
+
skill_create: () => skillCreateTool,
|
|
397
|
+
skill_update: () => skillUpdateTool,
|
|
398
|
+
skill_search: () => skillSearchTool,
|
|
399
|
+
skill_list: () => skillListTool,
|
|
400
|
+
tool_catalog: () => toolCatalogTool
|
|
401
|
+
};
|
|
402
|
+
return enabledTools.map((toolName) => toolCreators[toolName]());
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
export {
|
|
406
|
+
creatorToolsFactory
|
|
407
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var creator_tools_exports = {};
|
|
20
|
+
__export(creator_tools_exports, {
|
|
21
|
+
CREATOR_TOOL_NAMES: () => import_schemas.CREATOR_TOOL_NAMES,
|
|
22
|
+
CreatorToolsConfigSchema: () => import_schemas.CreatorToolsConfigSchema,
|
|
23
|
+
creatorToolsFactory: () => import_factory.creatorToolsFactory
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(creator_tools_exports);
|
|
26
|
+
var import_factory = require("./factory.js");
|
|
27
|
+
var import_schemas = require("./schemas.js");
|
|
28
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
29
|
+
0 && (module.exports = {
|
|
30
|
+
CREATOR_TOOL_NAMES,
|
|
31
|
+
CreatorToolsConfigSchema,
|
|
32
|
+
creatorToolsFactory
|
|
33
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tool-factories/creator-tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EACH,wBAAwB,EACxB,kBAAkB,EAClB,KAAK,kBAAkB,EACvB,KAAK,eAAe,GACvB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var schemas_exports = {};
|
|
20
|
+
__export(schemas_exports, {
|
|
21
|
+
CREATOR_TOOL_NAMES: () => CREATOR_TOOL_NAMES,
|
|
22
|
+
CreatorToolsConfigSchema: () => CreatorToolsConfigSchema
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(schemas_exports);
|
|
25
|
+
var import_zod = require("zod");
|
|
26
|
+
const CREATOR_TOOL_NAMES = [
|
|
27
|
+
"skill_create",
|
|
28
|
+
"skill_update",
|
|
29
|
+
"skill_search",
|
|
30
|
+
"skill_list",
|
|
31
|
+
"tool_catalog"
|
|
32
|
+
];
|
|
33
|
+
const CreatorToolsConfigSchema = import_zod.z.object({
|
|
34
|
+
type: import_zod.z.literal("creator-tools"),
|
|
35
|
+
enabledTools: import_zod.z.array(import_zod.z.enum(CREATOR_TOOL_NAMES)).optional().describe("Subset of creator tools to enable")
|
|
36
|
+
}).strict();
|
|
37
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
38
|
+
0 && (module.exports = {
|
|
39
|
+
CREATOR_TOOL_NAMES,
|
|
40
|
+
CreatorToolsConfigSchema
|
|
41
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const CREATOR_TOOL_NAMES: readonly ["skill_create", "skill_update", "skill_search", "skill_list", "tool_catalog"];
|
|
3
|
+
export type CreatorToolName = (typeof CREATOR_TOOL_NAMES)[number];
|
|
4
|
+
export declare const CreatorToolsConfigSchema: z.ZodObject<{
|
|
5
|
+
type: z.ZodLiteral<"creator-tools">;
|
|
6
|
+
enabledTools: z.ZodOptional<z.ZodArray<z.ZodEnum<["skill_create", "skill_update", "skill_search", "skill_list", "tool_catalog"]>, "many">>;
|
|
7
|
+
}, "strict", z.ZodTypeAny, {
|
|
8
|
+
type: "creator-tools";
|
|
9
|
+
enabledTools?: ("skill_create" | "skill_update" | "skill_search" | "skill_list" | "tool_catalog")[] | undefined;
|
|
10
|
+
}, {
|
|
11
|
+
type: "creator-tools";
|
|
12
|
+
enabledTools?: ("skill_create" | "skill_update" | "skill_search" | "skill_list" | "tool_catalog")[] | undefined;
|
|
13
|
+
}>;
|
|
14
|
+
export type CreatorToolsConfig = z.output<typeof CreatorToolsConfigSchema>;
|
|
15
|
+
//# sourceMappingURL=schemas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../../src/tool-factories/creator-tools/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,kBAAkB,yFAMrB,CAAC;AAEX,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAElE,eAAO,MAAM,wBAAwB;;;;;;;;;EAQxB,CAAC;AAEd,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,wBAAwB,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const CREATOR_TOOL_NAMES = [
|
|
3
|
+
"skill_create",
|
|
4
|
+
"skill_update",
|
|
5
|
+
"skill_search",
|
|
6
|
+
"skill_list",
|
|
7
|
+
"tool_catalog"
|
|
8
|
+
];
|
|
9
|
+
const CreatorToolsConfigSchema = z.object({
|
|
10
|
+
type: z.literal("creator-tools"),
|
|
11
|
+
enabledTools: z.array(z.enum(CREATOR_TOOL_NAMES)).optional().describe("Subset of creator tools to enable")
|
|
12
|
+
}).strict();
|
|
13
|
+
export {
|
|
14
|
+
CREATOR_TOOL_NAMES,
|
|
15
|
+
CreatorToolsConfigSchema
|
|
16
|
+
};
|
package/dist/utils/path.cjs
CHANGED
|
@@ -33,6 +33,7 @@ __export(path_exports, {
|
|
|
33
33
|
findPackageRoot: () => findPackageRoot,
|
|
34
34
|
getDextoEnvPath: () => getDextoEnvPath,
|
|
35
35
|
getDextoGlobalPath: () => getDextoGlobalPath,
|
|
36
|
+
getDextoPackageRoot: () => getDextoPackageRoot,
|
|
36
37
|
getDextoPath: () => getDextoPath,
|
|
37
38
|
isPath: () => isPath,
|
|
38
39
|
resolveBundledScript: () => resolveBundledScript
|
|
@@ -47,6 +48,10 @@ var import_url = require("url");
|
|
|
47
48
|
var import_fs_walk = require("./fs-walk.js");
|
|
48
49
|
var import_execution_context = require("./execution-context.js");
|
|
49
50
|
const import_meta = {};
|
|
51
|
+
function getDextoPackageRoot() {
|
|
52
|
+
const packageRoot = process.env.DEXTO_PACKAGE_ROOT;
|
|
53
|
+
return typeof packageRoot === "string" && packageRoot.length > 0 ? packageRoot : void 0;
|
|
54
|
+
}
|
|
50
55
|
function getDextoPath(type, filename, startPath) {
|
|
51
56
|
const context = (0, import_execution_context.getExecutionContext)(startPath);
|
|
52
57
|
let basePath;
|
|
@@ -134,7 +139,7 @@ function resolveBundledScript(scriptPath) {
|
|
|
134
139
|
}
|
|
135
140
|
return null;
|
|
136
141
|
};
|
|
137
|
-
const envRoot =
|
|
142
|
+
const envRoot = getDextoPackageRoot();
|
|
138
143
|
const fromEnv = tryRoots([envRoot]);
|
|
139
144
|
if (fromEnv) return fromEnv;
|
|
140
145
|
try {
|
|
@@ -208,6 +213,7 @@ function getDextoEnvPath(startPath = process.cwd()) {
|
|
|
208
213
|
findPackageRoot,
|
|
209
214
|
getDextoEnvPath,
|
|
210
215
|
getDextoGlobalPath,
|
|
216
|
+
getDextoPackageRoot,
|
|
211
217
|
getDextoPath,
|
|
212
218
|
isPath,
|
|
213
219
|
resolveBundledScript
|
package/dist/utils/path.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the package root for standalone binary installs.
|
|
3
|
+
*
|
|
4
|
+
* This is intentionally `undefined` for normal npm/pnpm installs.
|
|
5
|
+
* The env var is set by the CLI bootstrap (`packages/cli/src/index.ts`)
|
|
6
|
+
* when it detects executable-based distribution layout.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getDextoPackageRoot(): string | undefined;
|
|
1
9
|
/**
|
|
2
10
|
* Standard path resolver for logs/db/config/anything in dexto projects
|
|
3
11
|
* Context-aware with dev mode support:
|
package/dist/utils/path.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAuCxF;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAc1E;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAe5E;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAW3C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,SAAS,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAKhF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAwD/D;AAED;;GAEG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,IAAI,CAAC,CAUhE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,SAAS,GAAE,MAAsB,GAAG,MAAM,CAkCzE"}
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAgBA;;;;;;GAMG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,SAAS,CAGxD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAuCxF;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAc1E;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAe5E;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAW3C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,SAAS,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAKhF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAwD/D;AAED;;GAEG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,IAAI,CAAC,CAUhE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,SAAS,GAAE,MAAsB,GAAG,MAAM,CAkCzE"}
|
package/dist/utils/path.js
CHANGED
|
@@ -10,6 +10,10 @@ import {
|
|
|
10
10
|
findDextoSourceRoot,
|
|
11
11
|
findDextoProjectRoot
|
|
12
12
|
} from "./execution-context.js";
|
|
13
|
+
function getDextoPackageRoot() {
|
|
14
|
+
const packageRoot = process.env.DEXTO_PACKAGE_ROOT;
|
|
15
|
+
return typeof packageRoot === "string" && packageRoot.length > 0 ? packageRoot : void 0;
|
|
16
|
+
}
|
|
13
17
|
function getDextoPath(type, filename, startPath) {
|
|
14
18
|
const context = getExecutionContext(startPath);
|
|
15
19
|
let basePath;
|
|
@@ -97,7 +101,7 @@ function resolveBundledScript(scriptPath) {
|
|
|
97
101
|
}
|
|
98
102
|
return null;
|
|
99
103
|
};
|
|
100
|
-
const envRoot =
|
|
104
|
+
const envRoot = getDextoPackageRoot();
|
|
101
105
|
const fromEnv = tryRoots([envRoot]);
|
|
102
106
|
if (fromEnv) return fromEnv;
|
|
103
107
|
try {
|
|
@@ -170,6 +174,7 @@ export {
|
|
|
170
174
|
findPackageRoot,
|
|
171
175
|
getDextoEnvPath,
|
|
172
176
|
getDextoGlobalPath,
|
|
177
|
+
getDextoPackageRoot,
|
|
173
178
|
getDextoPath,
|
|
174
179
|
isPath,
|
|
175
180
|
resolveBundledScript
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dexto/agent-management",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"yaml": "^2.7.1",
|
|
18
18
|
"zod": "^3.25.0",
|
|
19
|
-
"@dexto/agent-config": "1.6.
|
|
20
|
-
"@dexto/core": "1.6.
|
|
21
|
-
"@dexto/orchestration": "1.6.
|
|
22
|
-
"@dexto/tools-builtins": "1.6.
|
|
19
|
+
"@dexto/agent-config": "1.6.3",
|
|
20
|
+
"@dexto/core": "1.6.3",
|
|
21
|
+
"@dexto/orchestration": "1.6.3",
|
|
22
|
+
"@dexto/tools-builtins": "1.6.3"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "^22.13.5"
|