llmist 16.1.0 → 16.2.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.
- package/dist/index.cjs +796 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +482 -1
- package/dist/index.d.ts +482 -1
- package/dist/index.js +776 -31
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -358,15 +358,15 @@ var init_execution_tree = __esm({
|
|
|
358
358
|
const parentId = params.parentId ?? this.parentNodeId;
|
|
359
359
|
const parent = parentId ? this.nodes.get(parentId) : null;
|
|
360
360
|
const depth = parent ? parent.depth + 1 : this.baseDepth;
|
|
361
|
-
const
|
|
361
|
+
const path3 = parent ? [...parent.path] : [];
|
|
362
362
|
const id = this.generateLLMCallId(params.iteration, parentId);
|
|
363
|
-
|
|
363
|
+
path3.push(id);
|
|
364
364
|
const node = {
|
|
365
365
|
id,
|
|
366
366
|
type: "llm_call",
|
|
367
367
|
parentId,
|
|
368
368
|
depth,
|
|
369
|
-
path,
|
|
369
|
+
path: path3,
|
|
370
370
|
createdAt: Date.now(),
|
|
371
371
|
completedAt: null,
|
|
372
372
|
iteration: params.iteration,
|
|
@@ -477,15 +477,15 @@ var init_execution_tree = __esm({
|
|
|
477
477
|
const parentId = params.parentId ?? this.getCurrentLLMCallId() ?? this.parentNodeId;
|
|
478
478
|
const parent = parentId ? this.nodes.get(parentId) : null;
|
|
479
479
|
const depth = parent ? parent.depth + 1 : this.baseDepth;
|
|
480
|
-
const
|
|
480
|
+
const path3 = parent ? [...parent.path] : [];
|
|
481
481
|
const id = this.generateGadgetId(params.invocationId);
|
|
482
|
-
|
|
482
|
+
path3.push(id);
|
|
483
483
|
const node = {
|
|
484
484
|
id,
|
|
485
485
|
type: "gadget",
|
|
486
486
|
parentId,
|
|
487
487
|
depth,
|
|
488
|
-
path,
|
|
488
|
+
path: path3,
|
|
489
489
|
createdAt: Date.now(),
|
|
490
490
|
completedAt: null,
|
|
491
491
|
invocationId: params.invocationId,
|
|
@@ -1424,8 +1424,8 @@ ${this.endPrefix}`
|
|
|
1424
1424
|
});
|
|
1425
1425
|
if (media && media.length > 0 && mediaIds && mediaIds.length > 0) {
|
|
1426
1426
|
const idRefs = media.map((m, i) => {
|
|
1427
|
-
const
|
|
1428
|
-
const pathInfo =
|
|
1427
|
+
const path3 = storedMedia?.[i]?.path;
|
|
1428
|
+
const pathInfo = path3 ? ` \u2192 saved to: ${path3}` : "";
|
|
1429
1429
|
return `[Media: ${mediaIds[i]} (${m.kind})${pathInfo}]`;
|
|
1430
1430
|
}).join("\n");
|
|
1431
1431
|
const textWithIds = `Result (${invocationId}): ${result}
|
|
@@ -4032,29 +4032,29 @@ function schemaToJSONSchema(schema, options) {
|
|
|
4032
4032
|
}
|
|
4033
4033
|
function detectDescriptionMismatch(schema, jsonSchema) {
|
|
4034
4034
|
const mismatches = [];
|
|
4035
|
-
function checkSchema(zodSchema, json,
|
|
4035
|
+
function checkSchema(zodSchema, json, path3) {
|
|
4036
4036
|
if (!zodSchema || typeof zodSchema !== "object") return;
|
|
4037
4037
|
const def = zodSchema._def;
|
|
4038
4038
|
const jsonObj = json;
|
|
4039
4039
|
if (def?.description && !jsonObj?.description) {
|
|
4040
|
-
mismatches.push(
|
|
4040
|
+
mismatches.push(path3 || "root");
|
|
4041
4041
|
}
|
|
4042
4042
|
if (def?.typeName === "ZodObject" && def?.shape) {
|
|
4043
4043
|
const shape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
4044
4044
|
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
4045
4045
|
const properties = jsonObj?.properties;
|
|
4046
4046
|
const jsonProp = properties?.[key];
|
|
4047
|
-
checkSchema(fieldSchema, jsonProp,
|
|
4047
|
+
checkSchema(fieldSchema, jsonProp, path3 ? `${path3}.${key}` : key);
|
|
4048
4048
|
}
|
|
4049
4049
|
}
|
|
4050
4050
|
if (def?.typeName === "ZodArray" && def?.type) {
|
|
4051
|
-
checkSchema(def.type, jsonObj?.items,
|
|
4051
|
+
checkSchema(def.type, jsonObj?.items, path3 ? `${path3}[]` : "[]");
|
|
4052
4052
|
}
|
|
4053
4053
|
if ((def?.typeName === "ZodOptional" || def?.typeName === "ZodNullable") && def?.innerType) {
|
|
4054
|
-
checkSchema(def.innerType, json,
|
|
4054
|
+
checkSchema(def.innerType, json, path3);
|
|
4055
4055
|
}
|
|
4056
4056
|
if (def?.typeName === "ZodDefault" && def?.innerType) {
|
|
4057
|
-
checkSchema(def.innerType, json,
|
|
4057
|
+
checkSchema(def.innerType, json, path3);
|
|
4058
4058
|
}
|
|
4059
4059
|
}
|
|
4060
4060
|
checkSchema(schema, jsonSchema, "");
|
|
@@ -4147,7 +4147,7 @@ Example fixes:
|
|
|
4147
4147
|
);
|
|
4148
4148
|
}
|
|
4149
4149
|
}
|
|
4150
|
-
function findUnknownTypes(schema,
|
|
4150
|
+
function findUnknownTypes(schema, path3 = []) {
|
|
4151
4151
|
const issues = [];
|
|
4152
4152
|
if (!schema || typeof schema !== "object") {
|
|
4153
4153
|
return issues;
|
|
@@ -4159,7 +4159,7 @@ function findUnknownTypes(schema, path = []) {
|
|
|
4159
4159
|
}
|
|
4160
4160
|
if (schema.properties) {
|
|
4161
4161
|
for (const [propName, propSchema] of Object.entries(schema.properties)) {
|
|
4162
|
-
const propPath = [...
|
|
4162
|
+
const propPath = [...path3, propName];
|
|
4163
4163
|
if (hasNoType(propSchema)) {
|
|
4164
4164
|
issues.push(propPath.join(".") || propName);
|
|
4165
4165
|
}
|
|
@@ -4167,7 +4167,7 @@ function findUnknownTypes(schema, path = []) {
|
|
|
4167
4167
|
}
|
|
4168
4168
|
}
|
|
4169
4169
|
if (schema.items) {
|
|
4170
|
-
const itemPath = [...
|
|
4170
|
+
const itemPath = [...path3, "[]"];
|
|
4171
4171
|
if (hasNoType(schema.items)) {
|
|
4172
4172
|
issues.push(itemPath.join("."));
|
|
4173
4173
|
}
|
|
@@ -4175,17 +4175,17 @@ function findUnknownTypes(schema, path = []) {
|
|
|
4175
4175
|
}
|
|
4176
4176
|
if (schema.anyOf) {
|
|
4177
4177
|
schema.anyOf.forEach((subSchema, index) => {
|
|
4178
|
-
issues.push(...findUnknownTypes(subSchema, [...
|
|
4178
|
+
issues.push(...findUnknownTypes(subSchema, [...path3, `anyOf[${index}]`]));
|
|
4179
4179
|
});
|
|
4180
4180
|
}
|
|
4181
4181
|
if (schema.oneOf) {
|
|
4182
4182
|
schema.oneOf.forEach((subSchema, index) => {
|
|
4183
|
-
issues.push(...findUnknownTypes(subSchema, [...
|
|
4183
|
+
issues.push(...findUnknownTypes(subSchema, [...path3, `oneOf[${index}]`]));
|
|
4184
4184
|
});
|
|
4185
4185
|
}
|
|
4186
4186
|
if (schema.allOf) {
|
|
4187
4187
|
schema.allOf.forEach((subSchema, index) => {
|
|
4188
|
-
issues.push(...findUnknownTypes(subSchema, [...
|
|
4188
|
+
issues.push(...findUnknownTypes(subSchema, [...path3, `allOf[${index}]`]));
|
|
4189
4189
|
});
|
|
4190
4190
|
}
|
|
4191
4191
|
return issues;
|
|
@@ -5203,6 +5203,626 @@ var init_registry = __esm({
|
|
|
5203
5203
|
}
|
|
5204
5204
|
});
|
|
5205
5205
|
|
|
5206
|
+
// src/skills/activation.ts
|
|
5207
|
+
function substituteArguments(instructions, args) {
|
|
5208
|
+
if (!args) {
|
|
5209
|
+
return instructions.replace(/\$ARGUMENTS\[\d+\]/g, "").replace(/\$ARGUMENTS/g, "").replace(/\$\d+/g, "");
|
|
5210
|
+
}
|
|
5211
|
+
const parts = splitArguments(args);
|
|
5212
|
+
let result = instructions.replace(/\$ARGUMENTS\[(\d+)\]/g, (_match, index) => {
|
|
5213
|
+
const i = Number.parseInt(index, 10);
|
|
5214
|
+
return parts[i] ?? "";
|
|
5215
|
+
});
|
|
5216
|
+
result = result.replace(/\$ARGUMENTS/g, args);
|
|
5217
|
+
result = result.replace(/\$(\d+)/g, (_match, index) => {
|
|
5218
|
+
const i = Number.parseInt(index, 10);
|
|
5219
|
+
return parts[i] ?? "";
|
|
5220
|
+
});
|
|
5221
|
+
return result;
|
|
5222
|
+
}
|
|
5223
|
+
function preprocessShellCommands(instructions, options) {
|
|
5224
|
+
const { cwd, shell = "bash", timeoutMs = 1e4 } = options ?? {};
|
|
5225
|
+
return instructions.replace(/!`([^`]+)`/g, (_match, command) => {
|
|
5226
|
+
try {
|
|
5227
|
+
const output = (0, import_node_child_process.execSync)(command, {
|
|
5228
|
+
cwd,
|
|
5229
|
+
shell: shell === "powershell" ? "powershell" : "/bin/bash",
|
|
5230
|
+
timeout: timeoutMs,
|
|
5231
|
+
encoding: "utf-8",
|
|
5232
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
5233
|
+
});
|
|
5234
|
+
return output.trim();
|
|
5235
|
+
} catch (error) {
|
|
5236
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
5237
|
+
return `[Error executing \`${command}\`: ${msg}]`;
|
|
5238
|
+
}
|
|
5239
|
+
});
|
|
5240
|
+
}
|
|
5241
|
+
function substituteVariables(instructions, variables) {
|
|
5242
|
+
return instructions.replace(/\$\{(\w+)\}/g, (_match, varName) => {
|
|
5243
|
+
return variables[varName] ?? "";
|
|
5244
|
+
});
|
|
5245
|
+
}
|
|
5246
|
+
function resolveInstructions(instructions, options) {
|
|
5247
|
+
let resolved = instructions;
|
|
5248
|
+
if (options?.variables) {
|
|
5249
|
+
resolved = substituteVariables(resolved, options.variables);
|
|
5250
|
+
}
|
|
5251
|
+
resolved = substituteArguments(resolved, options?.arguments);
|
|
5252
|
+
if (options?.enableShellPreprocessing !== false) {
|
|
5253
|
+
resolved = preprocessShellCommands(resolved, {
|
|
5254
|
+
cwd: options?.cwd,
|
|
5255
|
+
shell: options?.shell,
|
|
5256
|
+
timeoutMs: options?.shellTimeoutMs
|
|
5257
|
+
});
|
|
5258
|
+
}
|
|
5259
|
+
return resolved;
|
|
5260
|
+
}
|
|
5261
|
+
function splitArguments(args) {
|
|
5262
|
+
const parts = [];
|
|
5263
|
+
let current = "";
|
|
5264
|
+
let inQuote = null;
|
|
5265
|
+
for (const char of args) {
|
|
5266
|
+
if (inQuote) {
|
|
5267
|
+
if (char === inQuote) {
|
|
5268
|
+
inQuote = null;
|
|
5269
|
+
} else {
|
|
5270
|
+
current += char;
|
|
5271
|
+
}
|
|
5272
|
+
} else if (char === '"' || char === "'") {
|
|
5273
|
+
inQuote = char;
|
|
5274
|
+
} else if (char === " " || char === " ") {
|
|
5275
|
+
if (current) {
|
|
5276
|
+
parts.push(current);
|
|
5277
|
+
current = "";
|
|
5278
|
+
}
|
|
5279
|
+
} else {
|
|
5280
|
+
current += char;
|
|
5281
|
+
}
|
|
5282
|
+
}
|
|
5283
|
+
if (current) parts.push(current);
|
|
5284
|
+
return parts;
|
|
5285
|
+
}
|
|
5286
|
+
var import_node_child_process;
|
|
5287
|
+
var init_activation = __esm({
|
|
5288
|
+
"src/skills/activation.ts"() {
|
|
5289
|
+
"use strict";
|
|
5290
|
+
import_node_child_process = require("child_process");
|
|
5291
|
+
}
|
|
5292
|
+
});
|
|
5293
|
+
|
|
5294
|
+
// src/skills/parser.ts
|
|
5295
|
+
function parseFrontmatter(content) {
|
|
5296
|
+
const trimmed = content.trimStart();
|
|
5297
|
+
if (!trimmed.startsWith("---")) {
|
|
5298
|
+
return { frontmatter: {}, body: content };
|
|
5299
|
+
}
|
|
5300
|
+
const endIndex = trimmed.indexOf("\n---", 3);
|
|
5301
|
+
if (endIndex === -1) {
|
|
5302
|
+
return { frontmatter: {}, body: content };
|
|
5303
|
+
}
|
|
5304
|
+
const yamlBlock = trimmed.slice(3, endIndex).trim();
|
|
5305
|
+
const body = trimmed.slice(endIndex + 4).trim();
|
|
5306
|
+
const parsed = import_js_yaml.default.load(yamlBlock);
|
|
5307
|
+
const frontmatter = typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
5308
|
+
return { frontmatter, body };
|
|
5309
|
+
}
|
|
5310
|
+
function parseMetadata(frontmatter, fallbackName) {
|
|
5311
|
+
const name = parseString(frontmatter.name) ?? fallbackName ?? "unnamed-skill";
|
|
5312
|
+
const description = parseString(frontmatter.description) ?? "";
|
|
5313
|
+
return {
|
|
5314
|
+
name,
|
|
5315
|
+
description,
|
|
5316
|
+
argumentHint: parseString(frontmatter["argument-hint"]),
|
|
5317
|
+
allowedTools: parseStringArray(frontmatter["allowed-tools"]),
|
|
5318
|
+
model: parseString(frontmatter.model),
|
|
5319
|
+
context: parseContext(frontmatter.context),
|
|
5320
|
+
agent: parseString(frontmatter.agent),
|
|
5321
|
+
paths: parseStringArray(frontmatter.paths),
|
|
5322
|
+
gadgets: parseStringArray(frontmatter.gadgets),
|
|
5323
|
+
disableModelInvocation: parseBool(frontmatter["disable-model-invocation"]),
|
|
5324
|
+
userInvocable: parseBool(frontmatter["user-invocable"]),
|
|
5325
|
+
shell: parseShell(frontmatter.shell),
|
|
5326
|
+
version: parseString(frontmatter.version)
|
|
5327
|
+
};
|
|
5328
|
+
}
|
|
5329
|
+
function scanResources(skillDir) {
|
|
5330
|
+
const resources = [];
|
|
5331
|
+
for (const category of RESOURCE_CATEGORIES) {
|
|
5332
|
+
const categoryDir = import_node_path3.default.join(skillDir, category);
|
|
5333
|
+
if (!import_node_fs2.default.existsSync(categoryDir)) continue;
|
|
5334
|
+
const stat = import_node_fs2.default.statSync(categoryDir);
|
|
5335
|
+
if (!stat.isDirectory()) continue;
|
|
5336
|
+
for (const file of walkDirectory(categoryDir)) {
|
|
5337
|
+
resources.push({
|
|
5338
|
+
relativePath: import_node_path3.default.relative(skillDir, file),
|
|
5339
|
+
absolutePath: file,
|
|
5340
|
+
category
|
|
5341
|
+
});
|
|
5342
|
+
}
|
|
5343
|
+
}
|
|
5344
|
+
return resources;
|
|
5345
|
+
}
|
|
5346
|
+
function parseSkillFile(skillMdPath, source, loadInstructions = false) {
|
|
5347
|
+
const content = import_node_fs2.default.readFileSync(skillMdPath, "utf-8");
|
|
5348
|
+
return parseSkillContent(content, skillMdPath, source, loadInstructions);
|
|
5349
|
+
}
|
|
5350
|
+
function parseSkillContent(content, sourcePath, source, loadInstructions = false) {
|
|
5351
|
+
const sourceDir = import_node_path3.default.dirname(sourcePath);
|
|
5352
|
+
const fallbackName = import_node_path3.default.basename(sourceDir);
|
|
5353
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
5354
|
+
const metadata = parseMetadata(frontmatter, fallbackName);
|
|
5355
|
+
const resources = import_node_fs2.default.existsSync(sourceDir) ? scanResources(sourceDir) : [];
|
|
5356
|
+
return {
|
|
5357
|
+
metadata,
|
|
5358
|
+
instructions: loadInstructions ? body : null,
|
|
5359
|
+
resources,
|
|
5360
|
+
sourcePath,
|
|
5361
|
+
sourceDir,
|
|
5362
|
+
source
|
|
5363
|
+
};
|
|
5364
|
+
}
|
|
5365
|
+
function validateMetadata(metadata) {
|
|
5366
|
+
const issues = [];
|
|
5367
|
+
if (!metadata.name) {
|
|
5368
|
+
issues.push("Skill name is required");
|
|
5369
|
+
} else {
|
|
5370
|
+
if (metadata.name.length > MAX_NAME_LENGTH) {
|
|
5371
|
+
issues.push(`Skill name exceeds ${MAX_NAME_LENGTH} characters`);
|
|
5372
|
+
}
|
|
5373
|
+
if (!NAME_PATTERN.test(metadata.name)) {
|
|
5374
|
+
issues.push(
|
|
5375
|
+
"Skill name must contain only lowercase letters, numbers, and hyphens, and must start with a letter or number"
|
|
5376
|
+
);
|
|
5377
|
+
}
|
|
5378
|
+
}
|
|
5379
|
+
if (!metadata.description) {
|
|
5380
|
+
issues.push("Skill description is required");
|
|
5381
|
+
} else if (metadata.description.length > MAX_DESCRIPTION_LENGTH) {
|
|
5382
|
+
issues.push(`Skill description exceeds ${MAX_DESCRIPTION_LENGTH} characters`);
|
|
5383
|
+
}
|
|
5384
|
+
if (metadata.context && metadata.context !== "fork" && metadata.context !== "inline") {
|
|
5385
|
+
issues.push('Skill context must be "fork" or "inline"');
|
|
5386
|
+
}
|
|
5387
|
+
return issues;
|
|
5388
|
+
}
|
|
5389
|
+
function parseString(value) {
|
|
5390
|
+
if (value == null) return void 0;
|
|
5391
|
+
if (typeof value === "string") return value;
|
|
5392
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
5393
|
+
return void 0;
|
|
5394
|
+
}
|
|
5395
|
+
function parseStringArray(value) {
|
|
5396
|
+
if (value == null) return void 0;
|
|
5397
|
+
if (Array.isArray(value)) {
|
|
5398
|
+
return value.filter((v) => typeof v === "string" || typeof v === "number").map(String);
|
|
5399
|
+
}
|
|
5400
|
+
if (typeof value === "string") return [value];
|
|
5401
|
+
return void 0;
|
|
5402
|
+
}
|
|
5403
|
+
function parseContext(value) {
|
|
5404
|
+
if (value === "fork" || value === "inline") return value;
|
|
5405
|
+
return void 0;
|
|
5406
|
+
}
|
|
5407
|
+
function parseShell(value) {
|
|
5408
|
+
if (value === "bash" || value === "powershell") return value;
|
|
5409
|
+
return void 0;
|
|
5410
|
+
}
|
|
5411
|
+
function parseBool(value) {
|
|
5412
|
+
if (value === true || value === false) return value;
|
|
5413
|
+
if (value === "true") return true;
|
|
5414
|
+
if (value === "false") return false;
|
|
5415
|
+
return void 0;
|
|
5416
|
+
}
|
|
5417
|
+
function* walkDirectory(dir) {
|
|
5418
|
+
const entries = import_node_fs2.default.readdirSync(dir, { withFileTypes: true });
|
|
5419
|
+
for (const entry of entries) {
|
|
5420
|
+
const fullPath = import_node_path3.default.join(dir, entry.name);
|
|
5421
|
+
if (entry.isDirectory()) {
|
|
5422
|
+
yield* walkDirectory(fullPath);
|
|
5423
|
+
} else if (entry.isFile()) {
|
|
5424
|
+
yield fullPath;
|
|
5425
|
+
}
|
|
5426
|
+
}
|
|
5427
|
+
}
|
|
5428
|
+
var import_node_fs2, import_node_path3, import_js_yaml, RESOURCE_CATEGORIES, MAX_NAME_LENGTH, MAX_DESCRIPTION_LENGTH, NAME_PATTERN;
|
|
5429
|
+
var init_parser = __esm({
|
|
5430
|
+
"src/skills/parser.ts"() {
|
|
5431
|
+
"use strict";
|
|
5432
|
+
import_node_fs2 = __toESM(require("fs"), 1);
|
|
5433
|
+
import_node_path3 = __toESM(require("path"), 1);
|
|
5434
|
+
import_js_yaml = __toESM(require("js-yaml"), 1);
|
|
5435
|
+
RESOURCE_CATEGORIES = ["scripts", "references", "assets"];
|
|
5436
|
+
MAX_NAME_LENGTH = 64;
|
|
5437
|
+
MAX_DESCRIPTION_LENGTH = 1024;
|
|
5438
|
+
NAME_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
|
|
5439
|
+
}
|
|
5440
|
+
});
|
|
5441
|
+
|
|
5442
|
+
// src/skills/registry.ts
|
|
5443
|
+
var registry_exports = {};
|
|
5444
|
+
__export(registry_exports, {
|
|
5445
|
+
SkillRegistry: () => SkillRegistry
|
|
5446
|
+
});
|
|
5447
|
+
var import_minimatch, DEFAULT_CHAR_BUDGET, SUMMARY_DESCRIPTION_LIMIT, SkillRegistry;
|
|
5448
|
+
var init_registry2 = __esm({
|
|
5449
|
+
"src/skills/registry.ts"() {
|
|
5450
|
+
"use strict";
|
|
5451
|
+
import_minimatch = require("minimatch");
|
|
5452
|
+
DEFAULT_CHAR_BUDGET = 8e3;
|
|
5453
|
+
SUMMARY_DESCRIPTION_LIMIT = 250;
|
|
5454
|
+
SkillRegistry = class _SkillRegistry {
|
|
5455
|
+
skills = /* @__PURE__ */ new Map();
|
|
5456
|
+
/**
|
|
5457
|
+
* Register a skill. Overwrites any existing skill with the same name.
|
|
5458
|
+
*
|
|
5459
|
+
* Unlike GadgetRegistry (which throws on duplicates), SkillRegistry allows
|
|
5460
|
+
* overwriting because skills are loaded from multiple sources with intentional
|
|
5461
|
+
* priority ordering (project > user > default).
|
|
5462
|
+
*/
|
|
5463
|
+
register(skill) {
|
|
5464
|
+
this.skills.set(skill.name.toLowerCase(), skill);
|
|
5465
|
+
}
|
|
5466
|
+
/** Register multiple skills. */
|
|
5467
|
+
registerMany(skills) {
|
|
5468
|
+
for (const skill of skills) {
|
|
5469
|
+
this.register(skill);
|
|
5470
|
+
}
|
|
5471
|
+
}
|
|
5472
|
+
/** Remove a skill by name (case-insensitive). Returns true if removed. */
|
|
5473
|
+
remove(name) {
|
|
5474
|
+
return this.skills.delete(name.toLowerCase());
|
|
5475
|
+
}
|
|
5476
|
+
/** Remove all registered skills. */
|
|
5477
|
+
clear() {
|
|
5478
|
+
this.skills.clear();
|
|
5479
|
+
}
|
|
5480
|
+
/** Get a skill by name (case-insensitive). */
|
|
5481
|
+
get(name) {
|
|
5482
|
+
return this.skills.get(name.toLowerCase());
|
|
5483
|
+
}
|
|
5484
|
+
/** Check if a skill exists by name (case-insensitive). */
|
|
5485
|
+
has(name) {
|
|
5486
|
+
return this.skills.has(name.toLowerCase());
|
|
5487
|
+
}
|
|
5488
|
+
/** Get all registered skills. */
|
|
5489
|
+
getAll() {
|
|
5490
|
+
return [...this.skills.values()];
|
|
5491
|
+
}
|
|
5492
|
+
/** Get all skill names. */
|
|
5493
|
+
getNames() {
|
|
5494
|
+
return [...this.skills.keys()];
|
|
5495
|
+
}
|
|
5496
|
+
/** Number of registered skills. */
|
|
5497
|
+
get size() {
|
|
5498
|
+
return this.skills.size;
|
|
5499
|
+
}
|
|
5500
|
+
/**
|
|
5501
|
+
* Get skills that are visible to the LLM for auto-triggering.
|
|
5502
|
+
* Excludes skills with disableModelInvocation: true.
|
|
5503
|
+
*/
|
|
5504
|
+
getModelInvocable() {
|
|
5505
|
+
return this.getAll().filter((s) => s.isModelInvocable);
|
|
5506
|
+
}
|
|
5507
|
+
/**
|
|
5508
|
+
* Get skills that the user can invoke via /skill-name.
|
|
5509
|
+
* Excludes skills with userInvocable: false.
|
|
5510
|
+
*/
|
|
5511
|
+
getUserInvocable() {
|
|
5512
|
+
return this.getAll().filter((s) => s.isUserInvocable);
|
|
5513
|
+
}
|
|
5514
|
+
/**
|
|
5515
|
+
* Generate metadata summaries for system prompt injection (Tier 1).
|
|
5516
|
+
*
|
|
5517
|
+
* Each skill contributes a one-line summary: "name — description".
|
|
5518
|
+
* Output is truncated to fit the character budget.
|
|
5519
|
+
*
|
|
5520
|
+
* @param charBudget - Maximum characters for all summaries combined.
|
|
5521
|
+
*/
|
|
5522
|
+
getMetadataSummaries(charBudget = DEFAULT_CHAR_BUDGET) {
|
|
5523
|
+
const invocable = this.getModelInvocable();
|
|
5524
|
+
if (invocable.length === 0) return "";
|
|
5525
|
+
const lines = [];
|
|
5526
|
+
let totalChars = 0;
|
|
5527
|
+
for (const skill of invocable) {
|
|
5528
|
+
const desc = skill.description.length > SUMMARY_DESCRIPTION_LIMIT ? `${skill.description.slice(0, SUMMARY_DESCRIPTION_LIMIT - 3)}...` : skill.description;
|
|
5529
|
+
const line = `- ${skill.name}: ${desc}`;
|
|
5530
|
+
if (totalChars + line.length > charBudget) break;
|
|
5531
|
+
lines.push(line);
|
|
5532
|
+
totalChars += line.length + 1;
|
|
5533
|
+
}
|
|
5534
|
+
return lines.join("\n");
|
|
5535
|
+
}
|
|
5536
|
+
/**
|
|
5537
|
+
* Find skills whose `paths` patterns match a given file path.
|
|
5538
|
+
* Used for auto-activation when the user is working on specific files.
|
|
5539
|
+
*/
|
|
5540
|
+
findByFilePath(filePath) {
|
|
5541
|
+
return this.getModelInvocable().filter((skill) => {
|
|
5542
|
+
const patterns = skill.metadata.paths;
|
|
5543
|
+
if (!patterns || patterns.length === 0) return false;
|
|
5544
|
+
return patterns.some((pattern) => (0, import_minimatch.minimatch)(filePath, pattern));
|
|
5545
|
+
});
|
|
5546
|
+
}
|
|
5547
|
+
/**
|
|
5548
|
+
* Merge another registry into this one.
|
|
5549
|
+
* Skills from the other registry overwrite existing skills with the same name.
|
|
5550
|
+
*/
|
|
5551
|
+
merge(other) {
|
|
5552
|
+
for (const skill of other.getAll()) {
|
|
5553
|
+
this.register(skill);
|
|
5554
|
+
}
|
|
5555
|
+
}
|
|
5556
|
+
/** Create a registry from an array of skills. */
|
|
5557
|
+
static from(skills) {
|
|
5558
|
+
const registry = new _SkillRegistry();
|
|
5559
|
+
registry.registerMany(skills);
|
|
5560
|
+
return registry;
|
|
5561
|
+
}
|
|
5562
|
+
};
|
|
5563
|
+
}
|
|
5564
|
+
});
|
|
5565
|
+
|
|
5566
|
+
// src/skills/skill.ts
|
|
5567
|
+
var import_promises2, Skill;
|
|
5568
|
+
var init_skill = __esm({
|
|
5569
|
+
"src/skills/skill.ts"() {
|
|
5570
|
+
"use strict";
|
|
5571
|
+
import_promises2 = __toESM(require("fs/promises"), 1);
|
|
5572
|
+
init_activation();
|
|
5573
|
+
init_parser();
|
|
5574
|
+
Skill = class _Skill {
|
|
5575
|
+
metadata;
|
|
5576
|
+
sourcePath;
|
|
5577
|
+
sourceDir;
|
|
5578
|
+
source;
|
|
5579
|
+
_instructions;
|
|
5580
|
+
_resources;
|
|
5581
|
+
_resourceCache = /* @__PURE__ */ new Map();
|
|
5582
|
+
_resourceLoading = /* @__PURE__ */ new Map();
|
|
5583
|
+
constructor(parsed) {
|
|
5584
|
+
this.metadata = parsed.metadata;
|
|
5585
|
+
this.sourcePath = parsed.sourcePath;
|
|
5586
|
+
this.sourceDir = parsed.sourceDir;
|
|
5587
|
+
this.source = parsed.source;
|
|
5588
|
+
this._instructions = parsed.instructions;
|
|
5589
|
+
this._resources = parsed.resources;
|
|
5590
|
+
}
|
|
5591
|
+
/** Skill name for registry lookup. */
|
|
5592
|
+
get name() {
|
|
5593
|
+
return this.metadata.name;
|
|
5594
|
+
}
|
|
5595
|
+
/** Skill description for LLM matching. */
|
|
5596
|
+
get description() {
|
|
5597
|
+
return this.metadata.description;
|
|
5598
|
+
}
|
|
5599
|
+
/** Whether the LLM can auto-trigger this skill. */
|
|
5600
|
+
get isModelInvocable() {
|
|
5601
|
+
return this.metadata.disableModelInvocation !== true;
|
|
5602
|
+
}
|
|
5603
|
+
/** Whether the user can invoke this skill via /skill-name. */
|
|
5604
|
+
get isUserInvocable() {
|
|
5605
|
+
return this.metadata.userInvocable !== false;
|
|
5606
|
+
}
|
|
5607
|
+
/**
|
|
5608
|
+
* Load and cache Tier 2 instructions.
|
|
5609
|
+
* If instructions were loaded during parsing, returns the cached value.
|
|
5610
|
+
*/
|
|
5611
|
+
async getInstructions() {
|
|
5612
|
+
if (this._instructions !== null) return this._instructions;
|
|
5613
|
+
const content = await import_promises2.default.readFile(this.sourcePath, "utf-8");
|
|
5614
|
+
const { body } = parseFrontmatter(content);
|
|
5615
|
+
this._instructions = body;
|
|
5616
|
+
return body;
|
|
5617
|
+
}
|
|
5618
|
+
/**
|
|
5619
|
+
* List Tier 3 resources.
|
|
5620
|
+
* Resources are discovered at parse time but content is loaded on demand.
|
|
5621
|
+
*/
|
|
5622
|
+
getResources() {
|
|
5623
|
+
return this._resources;
|
|
5624
|
+
}
|
|
5625
|
+
/**
|
|
5626
|
+
* Load a specific Tier 3 resource by relative path.
|
|
5627
|
+
* Results are cached for the lifetime of this Skill instance.
|
|
5628
|
+
* Concurrent calls for the same resource share a single read.
|
|
5629
|
+
*/
|
|
5630
|
+
async getResource(relativePath) {
|
|
5631
|
+
if (relativePath.includes("..")) {
|
|
5632
|
+
throw new Error(`Invalid resource path (path traversal): ${relativePath}`);
|
|
5633
|
+
}
|
|
5634
|
+
const cached = this._resourceCache.get(relativePath);
|
|
5635
|
+
if (cached !== void 0) return cached;
|
|
5636
|
+
const existing = this._resourceLoading.get(relativePath);
|
|
5637
|
+
if (existing) return existing;
|
|
5638
|
+
const resource = this._resources.find((r) => r.relativePath === relativePath);
|
|
5639
|
+
if (!resource) {
|
|
5640
|
+
throw new Error(`Resource not found: ${relativePath} in skill ${this.name}`);
|
|
5641
|
+
}
|
|
5642
|
+
const loadPromise = import_promises2.default.readFile(resource.absolutePath, "utf-8").then(
|
|
5643
|
+
(content) => {
|
|
5644
|
+
this._resourceCache.set(relativePath, content);
|
|
5645
|
+
this._resourceLoading.delete(relativePath);
|
|
5646
|
+
return content;
|
|
5647
|
+
},
|
|
5648
|
+
(error) => {
|
|
5649
|
+
this._resourceLoading.delete(relativePath);
|
|
5650
|
+
throw new Error(
|
|
5651
|
+
`Failed to load resource ${relativePath} in skill ${this.name}: ${error instanceof Error ? error.message : String(error)}`
|
|
5652
|
+
);
|
|
5653
|
+
}
|
|
5654
|
+
);
|
|
5655
|
+
this._resourceLoading.set(relativePath, loadPromise);
|
|
5656
|
+
return loadPromise;
|
|
5657
|
+
}
|
|
5658
|
+
/**
|
|
5659
|
+
* Activate this skill with optional arguments.
|
|
5660
|
+
*
|
|
5661
|
+
* Performs:
|
|
5662
|
+
* 1. Variable substitution (${SKILL_DIR}, etc.)
|
|
5663
|
+
* 2. Argument substitution ($ARGUMENTS, $0, $1)
|
|
5664
|
+
* 3. Shell preprocessing (!`command`)
|
|
5665
|
+
* 4. Resource loading (if eagerResources is true)
|
|
5666
|
+
*/
|
|
5667
|
+
async activate(options) {
|
|
5668
|
+
const instructions = await this.getInstructions();
|
|
5669
|
+
const resolvedInstructions = resolveInstructions(instructions, {
|
|
5670
|
+
arguments: options?.arguments,
|
|
5671
|
+
variables: {
|
|
5672
|
+
SKILL_DIR: this.sourceDir,
|
|
5673
|
+
CLAUDE_SKILL_DIR: this.sourceDir
|
|
5674
|
+
},
|
|
5675
|
+
cwd: options?.cwd ?? this.sourceDir,
|
|
5676
|
+
shell: this.metadata.shell,
|
|
5677
|
+
enableShellPreprocessing: options?.enableShellPreprocessing,
|
|
5678
|
+
shellTimeoutMs: options?.shellTimeoutMs
|
|
5679
|
+
});
|
|
5680
|
+
const loadedResources = /* @__PURE__ */ new Map();
|
|
5681
|
+
if (options?.eagerResources) {
|
|
5682
|
+
for (const resource of this._resources) {
|
|
5683
|
+
const content = await this.getResource(resource.relativePath);
|
|
5684
|
+
loadedResources.set(resource.relativePath, content);
|
|
5685
|
+
}
|
|
5686
|
+
}
|
|
5687
|
+
return {
|
|
5688
|
+
skillName: this.name,
|
|
5689
|
+
resolvedInstructions,
|
|
5690
|
+
gadgets: [],
|
|
5691
|
+
// Gadgets are resolved by the CLI layer
|
|
5692
|
+
loadedResources
|
|
5693
|
+
};
|
|
5694
|
+
}
|
|
5695
|
+
/**
|
|
5696
|
+
* Create a Skill from a SKILL.md content string.
|
|
5697
|
+
* Useful for testing or dynamic skill creation.
|
|
5698
|
+
*/
|
|
5699
|
+
static fromContent(content, sourcePath, source = { type: "directory", path: sourcePath }) {
|
|
5700
|
+
const parsed = parseSkillContent(content, sourcePath, source, true);
|
|
5701
|
+
return new _Skill(parsed);
|
|
5702
|
+
}
|
|
5703
|
+
};
|
|
5704
|
+
}
|
|
5705
|
+
});
|
|
5706
|
+
|
|
5707
|
+
// src/skills/loader.ts
|
|
5708
|
+
function loadSkillsFromDirectory(dir, source, onWarning) {
|
|
5709
|
+
if (!import_node_fs3.default.existsSync(dir)) return [];
|
|
5710
|
+
const stat = import_node_fs3.default.statSync(dir);
|
|
5711
|
+
if (!stat.isDirectory()) return [];
|
|
5712
|
+
const skills = [];
|
|
5713
|
+
scanForSkills(dir, source, skills, onWarning);
|
|
5714
|
+
return skills;
|
|
5715
|
+
}
|
|
5716
|
+
function discoverSkills(options) {
|
|
5717
|
+
const registry = new SkillRegistry();
|
|
5718
|
+
const userSkillsDir = options?.userDir ?? import_node_path4.default.join(import_node_os2.default.homedir(), CONFIG_DIR_NAME, SKILLS_DIR_NAME);
|
|
5719
|
+
const userSkills = loadSkillsFromDirectory(userSkillsDir, {
|
|
5720
|
+
type: "user",
|
|
5721
|
+
path: userSkillsDir
|
|
5722
|
+
});
|
|
5723
|
+
registry.registerMany(userSkills);
|
|
5724
|
+
if (options?.projectDir) {
|
|
5725
|
+
const projectSkillsDir = import_node_path4.default.join(options.projectDir, CONFIG_DIR_NAME, SKILLS_DIR_NAME);
|
|
5726
|
+
const projectSkills = loadSkillsFromDirectory(projectSkillsDir, {
|
|
5727
|
+
type: "project",
|
|
5728
|
+
path: projectSkillsDir
|
|
5729
|
+
});
|
|
5730
|
+
registry.registerMany(projectSkills);
|
|
5731
|
+
}
|
|
5732
|
+
if (options?.additionalDirs) {
|
|
5733
|
+
for (const dir of options.additionalDirs) {
|
|
5734
|
+
const resolvedDir = dir.startsWith("~") ? import_node_path4.default.join(import_node_os2.default.homedir(), dir.slice(1)) : dir;
|
|
5735
|
+
const skills = loadSkillsFromDirectory(resolvedDir, {
|
|
5736
|
+
type: "directory",
|
|
5737
|
+
path: resolvedDir
|
|
5738
|
+
});
|
|
5739
|
+
registry.registerMany(skills);
|
|
5740
|
+
}
|
|
5741
|
+
}
|
|
5742
|
+
return registry;
|
|
5743
|
+
}
|
|
5744
|
+
function scanForSkills(dir, source, results, onWarning) {
|
|
5745
|
+
let entries;
|
|
5746
|
+
try {
|
|
5747
|
+
entries = import_node_fs3.default.readdirSync(dir, { withFileTypes: true });
|
|
5748
|
+
} catch (error) {
|
|
5749
|
+
onWarning?.(
|
|
5750
|
+
`Cannot read skill directory ${dir}: ${error instanceof Error ? error.message : String(error)}`
|
|
5751
|
+
);
|
|
5752
|
+
return;
|
|
5753
|
+
}
|
|
5754
|
+
const skillMdPath = import_node_path4.default.join(dir, "SKILL.md");
|
|
5755
|
+
if (import_node_fs3.default.existsSync(skillMdPath)) {
|
|
5756
|
+
try {
|
|
5757
|
+
const parsed = parseSkillFile(skillMdPath, source, false);
|
|
5758
|
+
results.push(new Skill(parsed));
|
|
5759
|
+
} catch (error) {
|
|
5760
|
+
onWarning?.(
|
|
5761
|
+
`Failed to parse ${skillMdPath}: ${error instanceof Error ? error.message : String(error)}`
|
|
5762
|
+
);
|
|
5763
|
+
}
|
|
5764
|
+
return;
|
|
5765
|
+
}
|
|
5766
|
+
for (const entry of entries) {
|
|
5767
|
+
if (entry.isDirectory() && !entry.name.startsWith(".")) {
|
|
5768
|
+
scanForSkills(import_node_path4.default.join(dir, entry.name), source, results, onWarning);
|
|
5769
|
+
}
|
|
5770
|
+
}
|
|
5771
|
+
}
|
|
5772
|
+
var import_node_fs3, import_node_os2, import_node_path4, SKILLS_DIR_NAME, CONFIG_DIR_NAME;
|
|
5773
|
+
var init_loader = __esm({
|
|
5774
|
+
"src/skills/loader.ts"() {
|
|
5775
|
+
"use strict";
|
|
5776
|
+
import_node_fs3 = __toESM(require("fs"), 1);
|
|
5777
|
+
import_node_os2 = __toESM(require("os"), 1);
|
|
5778
|
+
import_node_path4 = __toESM(require("path"), 1);
|
|
5779
|
+
init_parser();
|
|
5780
|
+
init_registry2();
|
|
5781
|
+
init_skill();
|
|
5782
|
+
SKILLS_DIR_NAME = "skills";
|
|
5783
|
+
CONFIG_DIR_NAME = ".llmist";
|
|
5784
|
+
}
|
|
5785
|
+
});
|
|
5786
|
+
|
|
5787
|
+
// src/skills/use-skill-gadget.ts
|
|
5788
|
+
function createUseSkillGadget(registry) {
|
|
5789
|
+
const summaries = registry.getMetadataSummaries();
|
|
5790
|
+
const skillNames = registry.getModelInvocable().map((s) => s.name);
|
|
5791
|
+
const description = [
|
|
5792
|
+
"Activate a skill to get specialized instructions for a task.",
|
|
5793
|
+
"Available skills:",
|
|
5794
|
+
summaries
|
|
5795
|
+
].join("\n");
|
|
5796
|
+
return createGadget({
|
|
5797
|
+
name: USE_SKILL_GADGET_NAME,
|
|
5798
|
+
description,
|
|
5799
|
+
schema: import_zod2.z.object({
|
|
5800
|
+
skill: import_zod2.z.enum(skillNames).describe("Name of the skill to activate"),
|
|
5801
|
+
arguments: import_zod2.z.string().optional().describe("Arguments for the skill (e.g., a filename, issue number, or search query)")
|
|
5802
|
+
}),
|
|
5803
|
+
execute: async ({ skill: skillName, arguments: args }) => {
|
|
5804
|
+
const skill = registry.get(skillName);
|
|
5805
|
+
if (!skill) {
|
|
5806
|
+
return `Unknown skill: "${skillName}". Available skills: ${skillNames.join(", ")}`;
|
|
5807
|
+
}
|
|
5808
|
+
const activation = await skill.activate({
|
|
5809
|
+
arguments: args,
|
|
5810
|
+
cwd: process.cwd()
|
|
5811
|
+
});
|
|
5812
|
+
return activation.resolvedInstructions;
|
|
5813
|
+
}
|
|
5814
|
+
});
|
|
5815
|
+
}
|
|
5816
|
+
var import_zod2, USE_SKILL_GADGET_NAME;
|
|
5817
|
+
var init_use_skill_gadget = __esm({
|
|
5818
|
+
"src/skills/use-skill-gadget.ts"() {
|
|
5819
|
+
"use strict";
|
|
5820
|
+
import_zod2 = require("zod");
|
|
5821
|
+
init_create_gadget();
|
|
5822
|
+
USE_SKILL_GADGET_NAME = "UseSkill";
|
|
5823
|
+
}
|
|
5824
|
+
});
|
|
5825
|
+
|
|
5206
5826
|
// src/agent/builder-utils.ts
|
|
5207
5827
|
function formatGadgetCall(gadgetName, invocationId, parameters, prefixes) {
|
|
5208
5828
|
const startPrefix = prefixes?.start ?? GADGET_START_PREFIX;
|
|
@@ -5336,7 +5956,7 @@ function resolveLoggingDirectory(state, baseDirectory, counterPadding, subagentC
|
|
|
5336
5956
|
if (!fullPath) {
|
|
5337
5957
|
const chronoNumber = getNextCounter(state, parentDir);
|
|
5338
5958
|
const subdirName = `${formatCallNumber(chronoNumber, counterPadding)}-${parentGadgetInvocationId}`;
|
|
5339
|
-
fullPath = (0,
|
|
5959
|
+
fullPath = (0, import_node_path5.join)(parentDir, subdirName);
|
|
5340
5960
|
state.subagentDirectories.set(subagentKey, fullPath);
|
|
5341
5961
|
}
|
|
5342
5962
|
state.activeDirectoryByContext.set(contextKey, fullPath);
|
|
@@ -5355,8 +5975,8 @@ function formatCallNumber(n, padding = 4) {
|
|
|
5355
5975
|
return n.toString().padStart(padding, "0");
|
|
5356
5976
|
}
|
|
5357
5977
|
async function writeLogFile(dir, filename, content) {
|
|
5358
|
-
await (0,
|
|
5359
|
-
await (0,
|
|
5978
|
+
await (0, import_promises3.mkdir)(dir, { recursive: true });
|
|
5979
|
+
await (0, import_promises3.writeFile)((0, import_node_path5.join)(dir, filename), content, "utf-8");
|
|
5360
5980
|
}
|
|
5361
5981
|
function createFileLoggingHooks(options, state = getDefaultState()) {
|
|
5362
5982
|
const {
|
|
@@ -5366,7 +5986,7 @@ function createFileLoggingHooks(options, state = getDefaultState()) {
|
|
|
5366
5986
|
formatRequest = formatLlmRequest,
|
|
5367
5987
|
onFileWritten
|
|
5368
5988
|
} = options;
|
|
5369
|
-
const baseDirectory = (0,
|
|
5989
|
+
const baseDirectory = (0, import_node_path5.resolve)(options.directory);
|
|
5370
5990
|
if (!state.counters.has(baseDirectory)) {
|
|
5371
5991
|
state.counters.set(baseDirectory, startingCounter - 1);
|
|
5372
5992
|
}
|
|
@@ -5394,7 +6014,7 @@ function createFileLoggingHooks(options, state = getDefaultState()) {
|
|
|
5394
6014
|
await writeLogFile(currentDirectory, filename, content);
|
|
5395
6015
|
if (onFileWritten) {
|
|
5396
6016
|
onFileWritten({
|
|
5397
|
-
filePath: (0,
|
|
6017
|
+
filePath: (0, import_node_path5.join)(currentDirectory, filename),
|
|
5398
6018
|
type: "request",
|
|
5399
6019
|
callNumber: currentCallNumber,
|
|
5400
6020
|
contentLength: content.length,
|
|
@@ -5423,7 +6043,7 @@ function createFileLoggingHooks(options, state = getDefaultState()) {
|
|
|
5423
6043
|
await writeLogFile(currentDirectory, filename, content);
|
|
5424
6044
|
if (onFileWritten) {
|
|
5425
6045
|
onFileWritten({
|
|
5426
|
-
filePath: (0,
|
|
6046
|
+
filePath: (0, import_node_path5.join)(currentDirectory, filename),
|
|
5427
6047
|
type: "response",
|
|
5428
6048
|
callNumber: currentCallNumber,
|
|
5429
6049
|
contentLength: content.length,
|
|
@@ -5445,12 +6065,12 @@ function getEnvFileLoggingHooks() {
|
|
|
5445
6065
|
}
|
|
5446
6066
|
return createFileLoggingHooks({ directory });
|
|
5447
6067
|
}
|
|
5448
|
-
var
|
|
6068
|
+
var import_promises3, import_node_path5, defaultState, ENV_LOG_RAW_DIRECTORY;
|
|
5449
6069
|
var init_file_logging = __esm({
|
|
5450
6070
|
"src/agent/file-logging.ts"() {
|
|
5451
6071
|
"use strict";
|
|
5452
|
-
|
|
5453
|
-
|
|
6072
|
+
import_promises3 = require("fs/promises");
|
|
6073
|
+
import_node_path5 = require("path");
|
|
5454
6074
|
init_messages();
|
|
5455
6075
|
ENV_LOG_RAW_DIRECTORY = "LLMIST_LOG_RAW_DIRECTORY";
|
|
5456
6076
|
}
|
|
@@ -12207,6 +12827,10 @@ var init_builder = __esm({
|
|
|
12207
12827
|
"use strict";
|
|
12208
12828
|
init_model_shortcuts();
|
|
12209
12829
|
init_registry();
|
|
12830
|
+
init_activation();
|
|
12831
|
+
init_loader();
|
|
12832
|
+
init_parser();
|
|
12833
|
+
init_use_skill_gadget();
|
|
12210
12834
|
init_agent();
|
|
12211
12835
|
init_agent_internal_key();
|
|
12212
12836
|
init_builder_utils();
|
|
@@ -12218,12 +12842,14 @@ var init_builder = __esm({
|
|
|
12218
12842
|
retry;
|
|
12219
12843
|
subagents;
|
|
12220
12844
|
policies;
|
|
12845
|
+
skills;
|
|
12221
12846
|
constructor(client) {
|
|
12222
12847
|
this.core = { client, initialMessages: [] };
|
|
12223
12848
|
this.gadgets = { gadgets: [] };
|
|
12224
12849
|
this.retry = {};
|
|
12225
12850
|
this.subagents = {};
|
|
12226
12851
|
this.policies = {};
|
|
12852
|
+
this.skills = { preActivated: [], skillDirs: [] };
|
|
12227
12853
|
}
|
|
12228
12854
|
/** Set the model to use. Supports aliases like "sonnet", "flash". */
|
|
12229
12855
|
withModel(model) {
|
|
@@ -12360,6 +12986,38 @@ var init_builder = __esm({
|
|
|
12360
12986
|
this.policies.compactionConfig = { enabled: false };
|
|
12361
12987
|
return this;
|
|
12362
12988
|
}
|
|
12989
|
+
// ─── Skills ──────────────────────────────────────────────────────────────────
|
|
12990
|
+
/** Register a skill registry for this agent. */
|
|
12991
|
+
withSkills(registry) {
|
|
12992
|
+
this.skills.registry = registry;
|
|
12993
|
+
return this;
|
|
12994
|
+
}
|
|
12995
|
+
/**
|
|
12996
|
+
* Pre-activate a specific skill before the agent starts.
|
|
12997
|
+
* Instructions are injected into the system prompt.
|
|
12998
|
+
*
|
|
12999
|
+
* Note: each call replaces (not appends) the pre-activated skill for that name.
|
|
13000
|
+
* This is safe for REPL loops where the same builder is reused.
|
|
13001
|
+
*/
|
|
13002
|
+
withSkill(name, args) {
|
|
13003
|
+
const existing = this.skills.preActivated.findIndex((s) => s.name === name);
|
|
13004
|
+
if (existing !== -1) {
|
|
13005
|
+
this.skills.preActivated[existing] = { name, args };
|
|
13006
|
+
} else {
|
|
13007
|
+
this.skills.preActivated.push({ name, args });
|
|
13008
|
+
}
|
|
13009
|
+
return this;
|
|
13010
|
+
}
|
|
13011
|
+
/** Clear all pre-activated skills. Call between REPL iterations. */
|
|
13012
|
+
clearPreActivatedSkills() {
|
|
13013
|
+
this.skills.preActivated = [];
|
|
13014
|
+
return this;
|
|
13015
|
+
}
|
|
13016
|
+
/** Add a directory to scan for skills. */
|
|
13017
|
+
withSkillsFrom(dir) {
|
|
13018
|
+
this.skills.skillDirs.push(dir);
|
|
13019
|
+
return this;
|
|
13020
|
+
}
|
|
12363
13021
|
/** Configure retry behavior for LLM API calls. */
|
|
12364
13022
|
withRetry(config) {
|
|
12365
13023
|
this.retry.retryConfig = { ...config, enabled: config.enabled ?? true };
|
|
@@ -12451,16 +13109,75 @@ var init_builder = __esm({
|
|
|
12451
13109
|
composeHooks() {
|
|
12452
13110
|
return HookComposer.compose(this.core.hooks, this.core.trailingMessage);
|
|
12453
13111
|
}
|
|
13112
|
+
resolveSkillRegistry() {
|
|
13113
|
+
if (this.skills.registry) {
|
|
13114
|
+
if (this.skills.skillDirs.length > 0) {
|
|
13115
|
+
for (const dir of this.skills.skillDirs) {
|
|
13116
|
+
const skills = loadSkillsFromDirectory(dir, { type: "directory", path: dir });
|
|
13117
|
+
this.skills.registry.registerMany(skills);
|
|
13118
|
+
}
|
|
13119
|
+
}
|
|
13120
|
+
return this.skills.registry;
|
|
13121
|
+
}
|
|
13122
|
+
if (this.skills.skillDirs.length > 0) {
|
|
13123
|
+
const { SkillRegistry: SR } = (init_registry2(), __toCommonJS(registry_exports));
|
|
13124
|
+
const reg = new SR();
|
|
13125
|
+
for (const dir of this.skills.skillDirs) {
|
|
13126
|
+
const skills = loadSkillsFromDirectory(dir, { type: "directory", path: dir });
|
|
13127
|
+
reg.registerMany(skills);
|
|
13128
|
+
}
|
|
13129
|
+
return reg;
|
|
13130
|
+
}
|
|
13131
|
+
return void 0;
|
|
13132
|
+
}
|
|
13133
|
+
/**
|
|
13134
|
+
* Resolve pre-activated skill instructions synchronously.
|
|
13135
|
+
* Reads SKILL.md from disk via readFileSync (skills are local files).
|
|
13136
|
+
*/
|
|
13137
|
+
resolvePreActivatedInstructions(skillRegistry) {
|
|
13138
|
+
if (this.skills.preActivated.length === 0) return void 0;
|
|
13139
|
+
const fs4 = require("fs");
|
|
13140
|
+
const blocks = [];
|
|
13141
|
+
for (const { name, args } of this.skills.preActivated) {
|
|
13142
|
+
const skill = skillRegistry.get(name);
|
|
13143
|
+
if (!skill) continue;
|
|
13144
|
+
const content = fs4.readFileSync(skill.sourcePath, "utf-8");
|
|
13145
|
+
const { body } = parseFrontmatter(content);
|
|
13146
|
+
const resolved = resolveInstructions(body, {
|
|
13147
|
+
arguments: args,
|
|
13148
|
+
variables: { SKILL_DIR: skill.sourceDir, CLAUDE_SKILL_DIR: skill.sourceDir },
|
|
13149
|
+
cwd: skill.sourceDir,
|
|
13150
|
+
shell: skill.metadata.shell
|
|
13151
|
+
});
|
|
13152
|
+
blocks.push(`## Skill: ${name}
|
|
13153
|
+
|
|
13154
|
+
${resolved}`);
|
|
13155
|
+
}
|
|
13156
|
+
return blocks.length > 0 ? blocks.join("\n\n---\n\n") : void 0;
|
|
13157
|
+
}
|
|
12454
13158
|
buildAgentOptions(userPrompt) {
|
|
12455
13159
|
if (!this.core.client) {
|
|
12456
13160
|
const { LLMist: LLMistClass } = (init_client(), __toCommonJS(client_exports));
|
|
12457
13161
|
this.core.client = new LLMistClass();
|
|
12458
13162
|
}
|
|
12459
13163
|
const registry = GadgetRegistry.from(this.gadgets.gadgets);
|
|
13164
|
+
let systemPrompt = this.core.systemPrompt;
|
|
13165
|
+
const skillRegistry = this.resolveSkillRegistry();
|
|
13166
|
+
if (skillRegistry && skillRegistry.size > 0) {
|
|
13167
|
+
if (skillRegistry.getModelInvocable().length > 0) {
|
|
13168
|
+
registry.registerByClass(createUseSkillGadget(skillRegistry));
|
|
13169
|
+
}
|
|
13170
|
+
const preActivatedBlock = this.resolvePreActivatedInstructions(skillRegistry);
|
|
13171
|
+
if (preActivatedBlock) {
|
|
13172
|
+
systemPrompt = systemPrompt ? `${systemPrompt}
|
|
13173
|
+
|
|
13174
|
+
${preActivatedBlock}` : preActivatedBlock;
|
|
13175
|
+
}
|
|
13176
|
+
}
|
|
12460
13177
|
return {
|
|
12461
13178
|
client: this.core.client,
|
|
12462
13179
|
model: this.core.model ?? "openai:gpt-5-nano",
|
|
12463
|
-
systemPrompt
|
|
13180
|
+
systemPrompt,
|
|
12464
13181
|
userPrompt,
|
|
12465
13182
|
registry,
|
|
12466
13183
|
maxIterations: this.core.maxIterations,
|
|
@@ -13145,8 +13862,8 @@ var init_error_formatter = __esm({
|
|
|
13145
13862
|
const parts = [];
|
|
13146
13863
|
parts.push(`Error: Invalid parameters for '${gadgetName}':`);
|
|
13147
13864
|
for (const issue of zodError.issues) {
|
|
13148
|
-
const
|
|
13149
|
-
parts.push(` - ${
|
|
13865
|
+
const path3 = issue.path.join(".") || "root";
|
|
13866
|
+
parts.push(` - ${path3}: ${issue.message}`);
|
|
13150
13867
|
}
|
|
13151
13868
|
parts.push("");
|
|
13152
13869
|
parts.push("Gadget Usage:");
|
|
@@ -13211,7 +13928,7 @@ function stripMarkdownFences(content) {
|
|
|
13211
13928
|
return cleaned.trim();
|
|
13212
13929
|
}
|
|
13213
13930
|
var globalInvocationCounter, GadgetCallParser;
|
|
13214
|
-
var
|
|
13931
|
+
var init_parser2 = __esm({
|
|
13215
13932
|
"src/gadgets/parser.ts"() {
|
|
13216
13933
|
"use strict";
|
|
13217
13934
|
init_constants();
|
|
@@ -13423,15 +14140,15 @@ function getHostExportsInternal() {
|
|
|
13423
14140
|
createGadget,
|
|
13424
14141
|
ExecutionTree,
|
|
13425
14142
|
LLMist,
|
|
13426
|
-
z:
|
|
14143
|
+
z: import_zod3.z
|
|
13427
14144
|
};
|
|
13428
14145
|
}
|
|
13429
|
-
var import_fast_deep_equal,
|
|
14146
|
+
var import_fast_deep_equal, import_zod3, GadgetExecutor;
|
|
13430
14147
|
var init_executor = __esm({
|
|
13431
14148
|
"src/gadgets/executor.ts"() {
|
|
13432
14149
|
"use strict";
|
|
13433
14150
|
import_fast_deep_equal = __toESM(require("fast-deep-equal"), 1);
|
|
13434
|
-
|
|
14151
|
+
import_zod3 = require("zod");
|
|
13435
14152
|
init_builder();
|
|
13436
14153
|
init_hook_utils();
|
|
13437
14154
|
init_client();
|
|
@@ -13443,7 +14160,7 @@ var init_executor = __esm({
|
|
|
13443
14160
|
init_create_gadget();
|
|
13444
14161
|
init_error_formatter();
|
|
13445
14162
|
init_exceptions();
|
|
13446
|
-
|
|
14163
|
+
init_parser2();
|
|
13447
14164
|
init_typed_gadget();
|
|
13448
14165
|
GadgetExecutor = class {
|
|
13449
14166
|
registry;
|
|
@@ -15044,7 +15761,7 @@ var init_stream_processor = __esm({
|
|
|
15044
15761
|
"src/agent/stream-processor.ts"() {
|
|
15045
15762
|
"use strict";
|
|
15046
15763
|
init_executor();
|
|
15047
|
-
|
|
15764
|
+
init_parser2();
|
|
15048
15765
|
init_logger();
|
|
15049
15766
|
init_gadget_concurrency_manager();
|
|
15050
15767
|
init_gadget_dependency_resolver();
|
|
@@ -16206,11 +16923,14 @@ __export(index_exports, {
|
|
|
16206
16923
|
OpenRouterProvider: () => OpenRouterProvider,
|
|
16207
16924
|
RateLimitTracker: () => RateLimitTracker,
|
|
16208
16925
|
SimpleSessionManager: () => SimpleSessionManager,
|
|
16926
|
+
Skill: () => Skill,
|
|
16927
|
+
SkillRegistry: () => SkillRegistry,
|
|
16209
16928
|
SlidingWindowStrategy: () => SlidingWindowStrategy,
|
|
16210
16929
|
StreamProcessor: () => StreamProcessor,
|
|
16211
16930
|
SummarizationStrategy: () => SummarizationStrategy,
|
|
16212
16931
|
TaskCompletionSignal: () => TaskCompletionSignal,
|
|
16213
16932
|
TimeoutException: () => TimeoutException,
|
|
16933
|
+
USE_SKILL_GADGET_NAME: () => USE_SKILL_GADGET_NAME,
|
|
16214
16934
|
audioFromBase64: () => audioFromBase64,
|
|
16215
16935
|
audioFromBuffer: () => audioFromBuffer,
|
|
16216
16936
|
collectEvents: () => collectEvents,
|
|
@@ -16228,10 +16948,12 @@ __export(index_exports, {
|
|
|
16228
16948
|
createOpenAIProviderFromEnv: () => createOpenAIProviderFromEnv,
|
|
16229
16949
|
createOpenRouterProviderFromEnv: () => createOpenRouterProviderFromEnv,
|
|
16230
16950
|
createSubagent: () => createSubagent,
|
|
16951
|
+
createUseSkillGadget: () => createUseSkillGadget,
|
|
16231
16952
|
defaultLogger: () => defaultLogger,
|
|
16232
16953
|
detectAudioMimeType: () => detectAudioMimeType,
|
|
16233
16954
|
detectImageMimeType: () => detectImageMimeType,
|
|
16234
16955
|
discoverProviderAdapters: () => discoverProviderAdapters,
|
|
16956
|
+
discoverSkills: () => discoverSkills,
|
|
16235
16957
|
extractMessageText: () => extractMessageText,
|
|
16236
16958
|
extractRetryAfterMs: () => extractRetryAfterMs,
|
|
16237
16959
|
filterByDepth: () => filterByDepth,
|
|
@@ -16274,15 +16996,21 @@ __export(index_exports, {
|
|
|
16274
16996
|
iterationProgressHint: () => iterationProgressHint,
|
|
16275
16997
|
listPresets: () => listPresets,
|
|
16276
16998
|
listSubagents: () => listSubagents,
|
|
16999
|
+
loadSkillsFromDirectory: () => loadSkillsFromDirectory,
|
|
16277
17000
|
normalizeMessageContent: () => normalizeMessageContent,
|
|
16278
17001
|
parallelGadgetHint: () => parallelGadgetHint,
|
|
16279
17002
|
parseDataUrl: () => parseDataUrl,
|
|
17003
|
+
parseFrontmatter: () => parseFrontmatter,
|
|
16280
17004
|
parseManifest: () => parseManifest,
|
|
17005
|
+
parseMetadata: () => parseMetadata,
|
|
16281
17006
|
parseRetryAfterHeader: () => parseRetryAfterHeader,
|
|
17007
|
+
parseSkillContent: () => parseSkillContent,
|
|
17008
|
+
parseSkillFile: () => parseSkillFile,
|
|
16282
17009
|
randomDelay: () => randomDelay,
|
|
16283
17010
|
resetFileLoggingState: () => resetFileLoggingState,
|
|
16284
17011
|
resolveConfig: () => resolveConfig,
|
|
16285
17012
|
resolveHintTemplate: () => resolveHintTemplate,
|
|
17013
|
+
resolveInstructions: () => resolveInstructions,
|
|
16286
17014
|
resolveModel: () => resolveModel,
|
|
16287
17015
|
resolvePromptTemplate: () => resolvePromptTemplate,
|
|
16288
17016
|
resolveRateLimitConfig: () => resolveRateLimitConfig,
|
|
@@ -16297,9 +17025,12 @@ __export(index_exports, {
|
|
|
16297
17025
|
resultWithImages: () => resultWithImages,
|
|
16298
17026
|
resultWithMedia: () => resultWithMedia,
|
|
16299
17027
|
runWithHandlers: () => runWithHandlers,
|
|
17028
|
+
scanResources: () => scanResources,
|
|
16300
17029
|
schemaToJSONSchema: () => schemaToJSONSchema,
|
|
16301
17030
|
stream: () => stream,
|
|
16302
17031
|
stripProviderPrefix: () => stripProviderPrefix,
|
|
17032
|
+
substituteArguments: () => substituteArguments,
|
|
17033
|
+
substituteVariables: () => substituteVariables,
|
|
16303
17034
|
text: () => text,
|
|
16304
17035
|
timing: () => timing,
|
|
16305
17036
|
toBase64: () => toBase64,
|
|
@@ -16307,13 +17038,14 @@ __export(index_exports, {
|
|
|
16307
17038
|
validateAndApplyDefaults: () => validateAndApplyDefaults,
|
|
16308
17039
|
validateGadgetParams: () => validateGadgetParams,
|
|
16309
17040
|
validateGadgetSchema: () => validateGadgetSchema,
|
|
17041
|
+
validateMetadata: () => validateMetadata,
|
|
16310
17042
|
withErrorHandling: () => withErrorHandling,
|
|
16311
17043
|
withRetry: () => withRetry,
|
|
16312
17044
|
withTimeout: () => withTimeout,
|
|
16313
|
-
z: () =>
|
|
17045
|
+
z: () => import_zod4.z
|
|
16314
17046
|
});
|
|
16315
17047
|
module.exports = __toCommonJS(index_exports);
|
|
16316
|
-
var
|
|
17048
|
+
var import_zod4 = require("zod");
|
|
16317
17049
|
init_agent();
|
|
16318
17050
|
init_builder();
|
|
16319
17051
|
init_event_handlers();
|
|
@@ -16627,7 +17359,7 @@ function resultWithFile(result, fileData, mimeType, options) {
|
|
|
16627
17359
|
|
|
16628
17360
|
// src/index.ts
|
|
16629
17361
|
init_output_viewer();
|
|
16630
|
-
|
|
17362
|
+
init_parser2();
|
|
16631
17363
|
init_registry();
|
|
16632
17364
|
init_typed_gadget();
|
|
16633
17365
|
init_constants2();
|
|
@@ -16894,6 +17626,14 @@ var SimpleSessionManager = class extends BaseSessionManager {
|
|
|
16894
17626
|
}
|
|
16895
17627
|
};
|
|
16896
17628
|
|
|
17629
|
+
// src/skills/index.ts
|
|
17630
|
+
init_activation();
|
|
17631
|
+
init_loader();
|
|
17632
|
+
init_parser();
|
|
17633
|
+
init_registry2();
|
|
17634
|
+
init_skill();
|
|
17635
|
+
init_use_skill_gadget();
|
|
17636
|
+
|
|
16897
17637
|
// src/utils/format.ts
|
|
16898
17638
|
function truncate(text3, maxLength, suffix = "...") {
|
|
16899
17639
|
if (text3.length <= maxLength) return text3;
|
|
@@ -17090,11 +17830,14 @@ function getHostExports2(ctx) {
|
|
|
17090
17830
|
OpenRouterProvider,
|
|
17091
17831
|
RateLimitTracker,
|
|
17092
17832
|
SimpleSessionManager,
|
|
17833
|
+
Skill,
|
|
17834
|
+
SkillRegistry,
|
|
17093
17835
|
SlidingWindowStrategy,
|
|
17094
17836
|
StreamProcessor,
|
|
17095
17837
|
SummarizationStrategy,
|
|
17096
17838
|
TaskCompletionSignal,
|
|
17097
17839
|
TimeoutException,
|
|
17840
|
+
USE_SKILL_GADGET_NAME,
|
|
17098
17841
|
audioFromBase64,
|
|
17099
17842
|
audioFromBuffer,
|
|
17100
17843
|
collectEvents,
|
|
@@ -17112,10 +17855,12 @@ function getHostExports2(ctx) {
|
|
|
17112
17855
|
createOpenAIProviderFromEnv,
|
|
17113
17856
|
createOpenRouterProviderFromEnv,
|
|
17114
17857
|
createSubagent,
|
|
17858
|
+
createUseSkillGadget,
|
|
17115
17859
|
defaultLogger,
|
|
17116
17860
|
detectAudioMimeType,
|
|
17117
17861
|
detectImageMimeType,
|
|
17118
17862
|
discoverProviderAdapters,
|
|
17863
|
+
discoverSkills,
|
|
17119
17864
|
extractMessageText,
|
|
17120
17865
|
extractRetryAfterMs,
|
|
17121
17866
|
filterByDepth,
|
|
@@ -17158,15 +17903,21 @@ function getHostExports2(ctx) {
|
|
|
17158
17903
|
iterationProgressHint,
|
|
17159
17904
|
listPresets,
|
|
17160
17905
|
listSubagents,
|
|
17906
|
+
loadSkillsFromDirectory,
|
|
17161
17907
|
normalizeMessageContent,
|
|
17162
17908
|
parallelGadgetHint,
|
|
17163
17909
|
parseDataUrl,
|
|
17910
|
+
parseFrontmatter,
|
|
17164
17911
|
parseManifest,
|
|
17912
|
+
parseMetadata,
|
|
17165
17913
|
parseRetryAfterHeader,
|
|
17914
|
+
parseSkillContent,
|
|
17915
|
+
parseSkillFile,
|
|
17166
17916
|
randomDelay,
|
|
17167
17917
|
resetFileLoggingState,
|
|
17168
17918
|
resolveConfig,
|
|
17169
17919
|
resolveHintTemplate,
|
|
17920
|
+
resolveInstructions,
|
|
17170
17921
|
resolveModel,
|
|
17171
17922
|
resolvePromptTemplate,
|
|
17172
17923
|
resolveRateLimitConfig,
|
|
@@ -17181,9 +17932,12 @@ function getHostExports2(ctx) {
|
|
|
17181
17932
|
resultWithImages,
|
|
17182
17933
|
resultWithMedia,
|
|
17183
17934
|
runWithHandlers,
|
|
17935
|
+
scanResources,
|
|
17184
17936
|
schemaToJSONSchema,
|
|
17185
17937
|
stream,
|
|
17186
17938
|
stripProviderPrefix,
|
|
17939
|
+
substituteArguments,
|
|
17940
|
+
substituteVariables,
|
|
17187
17941
|
text,
|
|
17188
17942
|
timing,
|
|
17189
17943
|
toBase64,
|
|
@@ -17191,6 +17945,7 @@ function getHostExports2(ctx) {
|
|
|
17191
17945
|
validateAndApplyDefaults,
|
|
17192
17946
|
validateGadgetParams,
|
|
17193
17947
|
validateGadgetSchema,
|
|
17948
|
+
validateMetadata,
|
|
17194
17949
|
withErrorHandling,
|
|
17195
17950
|
withRetry,
|
|
17196
17951
|
withTimeout,
|