llmist 16.1.0 → 16.2.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.
package/dist/index.js CHANGED
@@ -2,6 +2,12 @@ var __defProp = Object.defineProperty;
2
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
4
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
6
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
7
+ }) : x)(function(x) {
8
+ if (typeof require !== "undefined") return require.apply(this, arguments);
9
+ throw Error('Dynamic require of "' + x + '" is not supported');
10
+ });
5
11
  var __esm = (fn, res) => function __init() {
6
12
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
13
  };
@@ -347,15 +353,15 @@ var init_execution_tree = __esm({
347
353
  const parentId = params.parentId ?? this.parentNodeId;
348
354
  const parent = parentId ? this.nodes.get(parentId) : null;
349
355
  const depth = parent ? parent.depth + 1 : this.baseDepth;
350
- const path = parent ? [...parent.path] : [];
356
+ const path3 = parent ? [...parent.path] : [];
351
357
  const id = this.generateLLMCallId(params.iteration, parentId);
352
- path.push(id);
358
+ path3.push(id);
353
359
  const node = {
354
360
  id,
355
361
  type: "llm_call",
356
362
  parentId,
357
363
  depth,
358
- path,
364
+ path: path3,
359
365
  createdAt: Date.now(),
360
366
  completedAt: null,
361
367
  iteration: params.iteration,
@@ -466,15 +472,15 @@ var init_execution_tree = __esm({
466
472
  const parentId = params.parentId ?? this.getCurrentLLMCallId() ?? this.parentNodeId;
467
473
  const parent = parentId ? this.nodes.get(parentId) : null;
468
474
  const depth = parent ? parent.depth + 1 : this.baseDepth;
469
- const path = parent ? [...parent.path] : [];
475
+ const path3 = parent ? [...parent.path] : [];
470
476
  const id = this.generateGadgetId(params.invocationId);
471
- path.push(id);
477
+ path3.push(id);
472
478
  const node = {
473
479
  id,
474
480
  type: "gadget",
475
481
  parentId,
476
482
  depth,
477
- path,
483
+ path: path3,
478
484
  createdAt: Date.now(),
479
485
  completedAt: null,
480
486
  invocationId: params.invocationId,
@@ -1413,8 +1419,8 @@ ${this.endPrefix}`
1413
1419
  });
1414
1420
  if (media && media.length > 0 && mediaIds && mediaIds.length > 0) {
1415
1421
  const idRefs = media.map((m, i) => {
1416
- const path = storedMedia?.[i]?.path;
1417
- const pathInfo = path ? ` \u2192 saved to: ${path}` : "";
1422
+ const path3 = storedMedia?.[i]?.path;
1423
+ const pathInfo = path3 ? ` \u2192 saved to: ${path3}` : "";
1418
1424
  return `[Media: ${mediaIds[i]} (${m.kind})${pathInfo}]`;
1419
1425
  }).join("\n");
1420
1426
  const textWithIds = `Result (${invocationId}): ${result}
@@ -4022,29 +4028,29 @@ function schemaToJSONSchema(schema, options) {
4022
4028
  }
4023
4029
  function detectDescriptionMismatch(schema, jsonSchema) {
4024
4030
  const mismatches = [];
4025
- function checkSchema(zodSchema, json, path) {
4031
+ function checkSchema(zodSchema, json, path3) {
4026
4032
  if (!zodSchema || typeof zodSchema !== "object") return;
4027
4033
  const def = zodSchema._def;
4028
4034
  const jsonObj = json;
4029
4035
  if (def?.description && !jsonObj?.description) {
4030
- mismatches.push(path || "root");
4036
+ mismatches.push(path3 || "root");
4031
4037
  }
4032
4038
  if (def?.typeName === "ZodObject" && def?.shape) {
4033
4039
  const shape = typeof def.shape === "function" ? def.shape() : def.shape;
4034
4040
  for (const [key, fieldSchema] of Object.entries(shape)) {
4035
4041
  const properties = jsonObj?.properties;
4036
4042
  const jsonProp = properties?.[key];
4037
- checkSchema(fieldSchema, jsonProp, path ? `${path}.${key}` : key);
4043
+ checkSchema(fieldSchema, jsonProp, path3 ? `${path3}.${key}` : key);
4038
4044
  }
4039
4045
  }
4040
4046
  if (def?.typeName === "ZodArray" && def?.type) {
4041
- checkSchema(def.type, jsonObj?.items, path ? `${path}[]` : "[]");
4047
+ checkSchema(def.type, jsonObj?.items, path3 ? `${path3}[]` : "[]");
4042
4048
  }
4043
4049
  if ((def?.typeName === "ZodOptional" || def?.typeName === "ZodNullable") && def?.innerType) {
4044
- checkSchema(def.innerType, json, path);
4050
+ checkSchema(def.innerType, json, path3);
4045
4051
  }
4046
4052
  if (def?.typeName === "ZodDefault" && def?.innerType) {
4047
- checkSchema(def.innerType, json, path);
4053
+ checkSchema(def.innerType, json, path3);
4048
4054
  }
4049
4055
  }
4050
4056
  checkSchema(schema, jsonSchema, "");
@@ -4136,7 +4142,7 @@ Example fixes:
4136
4142
  );
4137
4143
  }
4138
4144
  }
4139
- function findUnknownTypes(schema, path = []) {
4145
+ function findUnknownTypes(schema, path3 = []) {
4140
4146
  const issues = [];
4141
4147
  if (!schema || typeof schema !== "object") {
4142
4148
  return issues;
@@ -4148,7 +4154,7 @@ function findUnknownTypes(schema, path = []) {
4148
4154
  }
4149
4155
  if (schema.properties) {
4150
4156
  for (const [propName, propSchema] of Object.entries(schema.properties)) {
4151
- const propPath = [...path, propName];
4157
+ const propPath = [...path3, propName];
4152
4158
  if (hasNoType(propSchema)) {
4153
4159
  issues.push(propPath.join(".") || propName);
4154
4160
  }
@@ -4156,7 +4162,7 @@ function findUnknownTypes(schema, path = []) {
4156
4162
  }
4157
4163
  }
4158
4164
  if (schema.items) {
4159
- const itemPath = [...path, "[]"];
4165
+ const itemPath = [...path3, "[]"];
4160
4166
  if (hasNoType(schema.items)) {
4161
4167
  issues.push(itemPath.join("."));
4162
4168
  }
@@ -4164,17 +4170,17 @@ function findUnknownTypes(schema, path = []) {
4164
4170
  }
4165
4171
  if (schema.anyOf) {
4166
4172
  schema.anyOf.forEach((subSchema, index) => {
4167
- issues.push(...findUnknownTypes(subSchema, [...path, `anyOf[${index}]`]));
4173
+ issues.push(...findUnknownTypes(subSchema, [...path3, `anyOf[${index}]`]));
4168
4174
  });
4169
4175
  }
4170
4176
  if (schema.oneOf) {
4171
4177
  schema.oneOf.forEach((subSchema, index) => {
4172
- issues.push(...findUnknownTypes(subSchema, [...path, `oneOf[${index}]`]));
4178
+ issues.push(...findUnknownTypes(subSchema, [...path3, `oneOf[${index}]`]));
4173
4179
  });
4174
4180
  }
4175
4181
  if (schema.allOf) {
4176
4182
  schema.allOf.forEach((subSchema, index) => {
4177
- issues.push(...findUnknownTypes(subSchema, [...path, `allOf[${index}]`]));
4183
+ issues.push(...findUnknownTypes(subSchema, [...path3, `allOf[${index}]`]));
4178
4184
  });
4179
4185
  }
4180
4186
  return issues;
@@ -5190,6 +5196,625 @@ var init_registry = __esm({
5190
5196
  }
5191
5197
  });
5192
5198
 
5199
+ // src/skills/activation.ts
5200
+ import { execSync } from "child_process";
5201
+ function substituteArguments(instructions, args) {
5202
+ if (!args) {
5203
+ return instructions.replace(/\$ARGUMENTS\[\d+\]/g, "").replace(/\$ARGUMENTS/g, "").replace(/\$\d+/g, "");
5204
+ }
5205
+ const parts = splitArguments(args);
5206
+ let result = instructions.replace(/\$ARGUMENTS\[(\d+)\]/g, (_match, index) => {
5207
+ const i = Number.parseInt(index, 10);
5208
+ return parts[i] ?? "";
5209
+ });
5210
+ result = result.replace(/\$ARGUMENTS/g, args);
5211
+ result = result.replace(/\$(\d+)/g, (_match, index) => {
5212
+ const i = Number.parseInt(index, 10);
5213
+ return parts[i] ?? "";
5214
+ });
5215
+ return result;
5216
+ }
5217
+ function preprocessShellCommands(instructions, options) {
5218
+ const { cwd, shell = "bash", timeoutMs = 1e4 } = options ?? {};
5219
+ return instructions.replace(/!`([^`]+)`/g, (_match, command) => {
5220
+ try {
5221
+ const output = execSync(command, {
5222
+ cwd,
5223
+ shell: shell === "powershell" ? "powershell" : "/bin/bash",
5224
+ timeout: timeoutMs,
5225
+ encoding: "utf-8",
5226
+ stdio: ["pipe", "pipe", "pipe"]
5227
+ });
5228
+ return output.trim();
5229
+ } catch (error) {
5230
+ const msg = error instanceof Error ? error.message : String(error);
5231
+ return `[Error executing \`${command}\`: ${msg}]`;
5232
+ }
5233
+ });
5234
+ }
5235
+ function substituteVariables(instructions, variables) {
5236
+ return instructions.replace(/\$\{(\w+)\}/g, (_match, varName) => {
5237
+ return variables[varName] ?? "";
5238
+ });
5239
+ }
5240
+ function resolveInstructions(instructions, options) {
5241
+ let resolved = instructions;
5242
+ if (options?.variables) {
5243
+ resolved = substituteVariables(resolved, options.variables);
5244
+ }
5245
+ resolved = substituteArguments(resolved, options?.arguments);
5246
+ if (options?.enableShellPreprocessing !== false) {
5247
+ resolved = preprocessShellCommands(resolved, {
5248
+ cwd: options?.cwd,
5249
+ shell: options?.shell,
5250
+ timeoutMs: options?.shellTimeoutMs
5251
+ });
5252
+ }
5253
+ return resolved;
5254
+ }
5255
+ function splitArguments(args) {
5256
+ const parts = [];
5257
+ let current = "";
5258
+ let inQuote = null;
5259
+ for (const char of args) {
5260
+ if (inQuote) {
5261
+ if (char === inQuote) {
5262
+ inQuote = null;
5263
+ } else {
5264
+ current += char;
5265
+ }
5266
+ } else if (char === '"' || char === "'") {
5267
+ inQuote = char;
5268
+ } else if (char === " " || char === " ") {
5269
+ if (current) {
5270
+ parts.push(current);
5271
+ current = "";
5272
+ }
5273
+ } else {
5274
+ current += char;
5275
+ }
5276
+ }
5277
+ if (current) parts.push(current);
5278
+ return parts;
5279
+ }
5280
+ var init_activation = __esm({
5281
+ "src/skills/activation.ts"() {
5282
+ "use strict";
5283
+ }
5284
+ });
5285
+
5286
+ // src/skills/parser.ts
5287
+ import fs from "fs";
5288
+ import path from "path";
5289
+ import yaml from "js-yaml";
5290
+ function parseFrontmatter(content) {
5291
+ const trimmed = content.trimStart();
5292
+ if (!trimmed.startsWith("---")) {
5293
+ return { frontmatter: {}, body: content };
5294
+ }
5295
+ const endIndex = trimmed.indexOf("\n---", 3);
5296
+ if (endIndex === -1) {
5297
+ return { frontmatter: {}, body: content };
5298
+ }
5299
+ const yamlBlock = trimmed.slice(3, endIndex).trim();
5300
+ const body = trimmed.slice(endIndex + 4).trim();
5301
+ const parsed = yaml.load(yamlBlock);
5302
+ const frontmatter = typeof parsed === "object" && parsed !== null ? parsed : {};
5303
+ return { frontmatter, body };
5304
+ }
5305
+ function parseMetadata(frontmatter, fallbackName) {
5306
+ const name = parseString(frontmatter.name) ?? fallbackName ?? "unnamed-skill";
5307
+ const description = parseString(frontmatter.description) ?? "";
5308
+ return {
5309
+ name,
5310
+ description,
5311
+ argumentHint: parseString(frontmatter["argument-hint"]),
5312
+ allowedTools: parseStringArray(frontmatter["allowed-tools"]),
5313
+ model: parseString(frontmatter.model),
5314
+ context: parseContext(frontmatter.context),
5315
+ agent: parseString(frontmatter.agent),
5316
+ paths: parseStringArray(frontmatter.paths),
5317
+ gadgets: parseStringArray(frontmatter.gadgets),
5318
+ disableModelInvocation: parseBool(frontmatter["disable-model-invocation"]),
5319
+ userInvocable: parseBool(frontmatter["user-invocable"]),
5320
+ shell: parseShell(frontmatter.shell),
5321
+ version: parseString(frontmatter.version)
5322
+ };
5323
+ }
5324
+ function scanResources(skillDir) {
5325
+ const resources = [];
5326
+ for (const category of RESOURCE_CATEGORIES) {
5327
+ const categoryDir = path.join(skillDir, category);
5328
+ if (!fs.existsSync(categoryDir)) continue;
5329
+ const stat = fs.statSync(categoryDir);
5330
+ if (!stat.isDirectory()) continue;
5331
+ for (const file of walkDirectory(categoryDir)) {
5332
+ resources.push({
5333
+ relativePath: path.relative(skillDir, file),
5334
+ absolutePath: file,
5335
+ category
5336
+ });
5337
+ }
5338
+ }
5339
+ return resources;
5340
+ }
5341
+ function parseSkillFile(skillMdPath, source, loadInstructions = false) {
5342
+ const content = fs.readFileSync(skillMdPath, "utf-8");
5343
+ return parseSkillContent(content, skillMdPath, source, loadInstructions);
5344
+ }
5345
+ function parseSkillContent(content, sourcePath, source, loadInstructions = false) {
5346
+ const sourceDir = path.dirname(sourcePath);
5347
+ const fallbackName = path.basename(sourceDir);
5348
+ const { frontmatter, body } = parseFrontmatter(content);
5349
+ const metadata = parseMetadata(frontmatter, fallbackName);
5350
+ const resources = fs.existsSync(sourceDir) ? scanResources(sourceDir) : [];
5351
+ return {
5352
+ metadata,
5353
+ instructions: loadInstructions ? body : null,
5354
+ resources,
5355
+ sourcePath,
5356
+ sourceDir,
5357
+ source
5358
+ };
5359
+ }
5360
+ function validateMetadata(metadata) {
5361
+ const issues = [];
5362
+ if (!metadata.name) {
5363
+ issues.push("Skill name is required");
5364
+ } else {
5365
+ if (metadata.name.length > MAX_NAME_LENGTH) {
5366
+ issues.push(`Skill name exceeds ${MAX_NAME_LENGTH} characters`);
5367
+ }
5368
+ if (!NAME_PATTERN.test(metadata.name)) {
5369
+ issues.push(
5370
+ "Skill name must contain only lowercase letters, numbers, and hyphens, and must start with a letter or number"
5371
+ );
5372
+ }
5373
+ }
5374
+ if (!metadata.description) {
5375
+ issues.push("Skill description is required");
5376
+ } else if (metadata.description.length > MAX_DESCRIPTION_LENGTH) {
5377
+ issues.push(`Skill description exceeds ${MAX_DESCRIPTION_LENGTH} characters`);
5378
+ }
5379
+ if (metadata.context && metadata.context !== "fork" && metadata.context !== "inline") {
5380
+ issues.push('Skill context must be "fork" or "inline"');
5381
+ }
5382
+ return issues;
5383
+ }
5384
+ function parseString(value) {
5385
+ if (value == null) return void 0;
5386
+ if (typeof value === "string") return value;
5387
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
5388
+ return void 0;
5389
+ }
5390
+ function parseStringArray(value) {
5391
+ if (value == null) return void 0;
5392
+ if (Array.isArray(value)) {
5393
+ return value.filter((v) => typeof v === "string" || typeof v === "number").map(String);
5394
+ }
5395
+ if (typeof value === "string") return [value];
5396
+ return void 0;
5397
+ }
5398
+ function parseContext(value) {
5399
+ if (value === "fork" || value === "inline") return value;
5400
+ return void 0;
5401
+ }
5402
+ function parseShell(value) {
5403
+ if (value === "bash" || value === "powershell") return value;
5404
+ return void 0;
5405
+ }
5406
+ function parseBool(value) {
5407
+ if (value === true || value === false) return value;
5408
+ if (value === "true") return true;
5409
+ if (value === "false") return false;
5410
+ return void 0;
5411
+ }
5412
+ function* walkDirectory(dir) {
5413
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
5414
+ for (const entry of entries) {
5415
+ const fullPath = path.join(dir, entry.name);
5416
+ if (entry.isDirectory()) {
5417
+ yield* walkDirectory(fullPath);
5418
+ } else if (entry.isFile()) {
5419
+ yield fullPath;
5420
+ }
5421
+ }
5422
+ }
5423
+ var RESOURCE_CATEGORIES, MAX_NAME_LENGTH, MAX_DESCRIPTION_LENGTH, NAME_PATTERN;
5424
+ var init_parser = __esm({
5425
+ "src/skills/parser.ts"() {
5426
+ "use strict";
5427
+ RESOURCE_CATEGORIES = ["scripts", "references", "assets"];
5428
+ MAX_NAME_LENGTH = 64;
5429
+ MAX_DESCRIPTION_LENGTH = 1024;
5430
+ NAME_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
5431
+ }
5432
+ });
5433
+
5434
+ // src/skills/registry.ts
5435
+ var registry_exports = {};
5436
+ __export(registry_exports, {
5437
+ SkillRegistry: () => SkillRegistry
5438
+ });
5439
+ import { minimatch } from "minimatch";
5440
+ var DEFAULT_CHAR_BUDGET, SUMMARY_DESCRIPTION_LIMIT, SkillRegistry;
5441
+ var init_registry2 = __esm({
5442
+ "src/skills/registry.ts"() {
5443
+ "use strict";
5444
+ DEFAULT_CHAR_BUDGET = 8e3;
5445
+ SUMMARY_DESCRIPTION_LIMIT = 250;
5446
+ SkillRegistry = class _SkillRegistry {
5447
+ skills = /* @__PURE__ */ new Map();
5448
+ /**
5449
+ * Register a skill. Overwrites any existing skill with the same name.
5450
+ *
5451
+ * Unlike GadgetRegistry (which throws on duplicates), SkillRegistry allows
5452
+ * overwriting because skills are loaded from multiple sources with intentional
5453
+ * priority ordering (project > user > default).
5454
+ */
5455
+ register(skill) {
5456
+ this.skills.set(skill.name.toLowerCase(), skill);
5457
+ }
5458
+ /** Register multiple skills. */
5459
+ registerMany(skills) {
5460
+ for (const skill of skills) {
5461
+ this.register(skill);
5462
+ }
5463
+ }
5464
+ /** Remove a skill by name (case-insensitive). Returns true if removed. */
5465
+ remove(name) {
5466
+ return this.skills.delete(name.toLowerCase());
5467
+ }
5468
+ /** Remove all registered skills. */
5469
+ clear() {
5470
+ this.skills.clear();
5471
+ }
5472
+ /** Get a skill by name (case-insensitive). */
5473
+ get(name) {
5474
+ return this.skills.get(name.toLowerCase());
5475
+ }
5476
+ /** Check if a skill exists by name (case-insensitive). */
5477
+ has(name) {
5478
+ return this.skills.has(name.toLowerCase());
5479
+ }
5480
+ /** Get all registered skills. */
5481
+ getAll() {
5482
+ return [...this.skills.values()];
5483
+ }
5484
+ /** Get all skill names. */
5485
+ getNames() {
5486
+ return [...this.skills.keys()];
5487
+ }
5488
+ /** Number of registered skills. */
5489
+ get size() {
5490
+ return this.skills.size;
5491
+ }
5492
+ /**
5493
+ * Get skills that are visible to the LLM for auto-triggering.
5494
+ * Excludes skills with disableModelInvocation: true.
5495
+ */
5496
+ getModelInvocable() {
5497
+ return this.getAll().filter((s) => s.isModelInvocable);
5498
+ }
5499
+ /**
5500
+ * Get skills that the user can invoke via /skill-name.
5501
+ * Excludes skills with userInvocable: false.
5502
+ */
5503
+ getUserInvocable() {
5504
+ return this.getAll().filter((s) => s.isUserInvocable);
5505
+ }
5506
+ /**
5507
+ * Generate metadata summaries for system prompt injection (Tier 1).
5508
+ *
5509
+ * Each skill contributes a one-line summary: "name — description".
5510
+ * Output is truncated to fit the character budget.
5511
+ *
5512
+ * @param charBudget - Maximum characters for all summaries combined.
5513
+ */
5514
+ getMetadataSummaries(charBudget = DEFAULT_CHAR_BUDGET) {
5515
+ const invocable = this.getModelInvocable();
5516
+ if (invocable.length === 0) return "";
5517
+ const lines = [];
5518
+ let totalChars = 0;
5519
+ for (const skill of invocable) {
5520
+ const desc = skill.description.length > SUMMARY_DESCRIPTION_LIMIT ? `${skill.description.slice(0, SUMMARY_DESCRIPTION_LIMIT - 3)}...` : skill.description;
5521
+ const line = `- ${skill.name}: ${desc}`;
5522
+ if (totalChars + line.length > charBudget) break;
5523
+ lines.push(line);
5524
+ totalChars += line.length + 1;
5525
+ }
5526
+ return lines.join("\n");
5527
+ }
5528
+ /**
5529
+ * Find skills whose `paths` patterns match a given file path.
5530
+ * Used for auto-activation when the user is working on specific files.
5531
+ */
5532
+ findByFilePath(filePath) {
5533
+ return this.getModelInvocable().filter((skill) => {
5534
+ const patterns = skill.metadata.paths;
5535
+ if (!patterns || patterns.length === 0) return false;
5536
+ return patterns.some((pattern) => minimatch(filePath, pattern));
5537
+ });
5538
+ }
5539
+ /**
5540
+ * Merge another registry into this one.
5541
+ * Skills from the other registry overwrite existing skills with the same name.
5542
+ */
5543
+ merge(other) {
5544
+ for (const skill of other.getAll()) {
5545
+ this.register(skill);
5546
+ }
5547
+ }
5548
+ /** Create a registry from an array of skills. */
5549
+ static from(skills) {
5550
+ const registry = new _SkillRegistry();
5551
+ registry.registerMany(skills);
5552
+ return registry;
5553
+ }
5554
+ };
5555
+ }
5556
+ });
5557
+
5558
+ // src/skills/skill.ts
5559
+ import fs2 from "fs/promises";
5560
+ var Skill;
5561
+ var init_skill = __esm({
5562
+ "src/skills/skill.ts"() {
5563
+ "use strict";
5564
+ init_activation();
5565
+ init_parser();
5566
+ Skill = class _Skill {
5567
+ metadata;
5568
+ sourcePath;
5569
+ sourceDir;
5570
+ source;
5571
+ _instructions;
5572
+ _resources;
5573
+ _resourceCache = /* @__PURE__ */ new Map();
5574
+ _resourceLoading = /* @__PURE__ */ new Map();
5575
+ constructor(parsed) {
5576
+ this.metadata = parsed.metadata;
5577
+ this.sourcePath = parsed.sourcePath;
5578
+ this.sourceDir = parsed.sourceDir;
5579
+ this.source = parsed.source;
5580
+ this._instructions = parsed.instructions;
5581
+ this._resources = parsed.resources;
5582
+ }
5583
+ /** Skill name for registry lookup. */
5584
+ get name() {
5585
+ return this.metadata.name;
5586
+ }
5587
+ /** Skill description for LLM matching. */
5588
+ get description() {
5589
+ return this.metadata.description;
5590
+ }
5591
+ /** Whether the LLM can auto-trigger this skill. */
5592
+ get isModelInvocable() {
5593
+ return this.metadata.disableModelInvocation !== true;
5594
+ }
5595
+ /** Whether the user can invoke this skill via /skill-name. */
5596
+ get isUserInvocable() {
5597
+ return this.metadata.userInvocable !== false;
5598
+ }
5599
+ /**
5600
+ * Load and cache Tier 2 instructions.
5601
+ * If instructions were loaded during parsing, returns the cached value.
5602
+ */
5603
+ async getInstructions() {
5604
+ if (this._instructions !== null) return this._instructions;
5605
+ const content = await fs2.readFile(this.sourcePath, "utf-8");
5606
+ const { body } = parseFrontmatter(content);
5607
+ this._instructions = body;
5608
+ return body;
5609
+ }
5610
+ /**
5611
+ * List Tier 3 resources.
5612
+ * Resources are discovered at parse time but content is loaded on demand.
5613
+ */
5614
+ getResources() {
5615
+ return this._resources;
5616
+ }
5617
+ /**
5618
+ * Load a specific Tier 3 resource by relative path.
5619
+ * Results are cached for the lifetime of this Skill instance.
5620
+ * Concurrent calls for the same resource share a single read.
5621
+ */
5622
+ async getResource(relativePath) {
5623
+ if (relativePath.includes("..")) {
5624
+ throw new Error(`Invalid resource path (path traversal): ${relativePath}`);
5625
+ }
5626
+ const cached = this._resourceCache.get(relativePath);
5627
+ if (cached !== void 0) return cached;
5628
+ const existing = this._resourceLoading.get(relativePath);
5629
+ if (existing) return existing;
5630
+ const resource = this._resources.find((r) => r.relativePath === relativePath);
5631
+ if (!resource) {
5632
+ throw new Error(`Resource not found: ${relativePath} in skill ${this.name}`);
5633
+ }
5634
+ const loadPromise = fs2.readFile(resource.absolutePath, "utf-8").then(
5635
+ (content) => {
5636
+ this._resourceCache.set(relativePath, content);
5637
+ this._resourceLoading.delete(relativePath);
5638
+ return content;
5639
+ },
5640
+ (error) => {
5641
+ this._resourceLoading.delete(relativePath);
5642
+ throw new Error(
5643
+ `Failed to load resource ${relativePath} in skill ${this.name}: ${error instanceof Error ? error.message : String(error)}`
5644
+ );
5645
+ }
5646
+ );
5647
+ this._resourceLoading.set(relativePath, loadPromise);
5648
+ return loadPromise;
5649
+ }
5650
+ /**
5651
+ * Activate this skill with optional arguments.
5652
+ *
5653
+ * Performs:
5654
+ * 1. Variable substitution (${SKILL_DIR}, etc.)
5655
+ * 2. Argument substitution ($ARGUMENTS, $0, $1)
5656
+ * 3. Shell preprocessing (!`command`)
5657
+ * 4. Resource loading (if eagerResources is true)
5658
+ */
5659
+ async activate(options) {
5660
+ const instructions = await this.getInstructions();
5661
+ const resolvedInstructions = resolveInstructions(instructions, {
5662
+ arguments: options?.arguments,
5663
+ variables: {
5664
+ SKILL_DIR: this.sourceDir,
5665
+ CLAUDE_SKILL_DIR: this.sourceDir
5666
+ },
5667
+ cwd: options?.cwd ?? this.sourceDir,
5668
+ shell: this.metadata.shell,
5669
+ enableShellPreprocessing: options?.enableShellPreprocessing,
5670
+ shellTimeoutMs: options?.shellTimeoutMs
5671
+ });
5672
+ const loadedResources = /* @__PURE__ */ new Map();
5673
+ if (options?.eagerResources) {
5674
+ for (const resource of this._resources) {
5675
+ const content = await this.getResource(resource.relativePath);
5676
+ loadedResources.set(resource.relativePath, content);
5677
+ }
5678
+ }
5679
+ return {
5680
+ skillName: this.name,
5681
+ resolvedInstructions,
5682
+ gadgets: [],
5683
+ // Gadgets are resolved by the CLI layer
5684
+ loadedResources
5685
+ };
5686
+ }
5687
+ /**
5688
+ * Create a Skill from a SKILL.md content string.
5689
+ * Useful for testing or dynamic skill creation.
5690
+ */
5691
+ static fromContent(content, sourcePath, source = { type: "directory", path: sourcePath }) {
5692
+ const parsed = parseSkillContent(content, sourcePath, source, true);
5693
+ return new _Skill(parsed);
5694
+ }
5695
+ };
5696
+ }
5697
+ });
5698
+
5699
+ // src/skills/loader.ts
5700
+ import fs3 from "fs";
5701
+ import os from "os";
5702
+ import path2 from "path";
5703
+ function loadSkillsFromDirectory(dir, source, onWarning) {
5704
+ if (!fs3.existsSync(dir)) return [];
5705
+ const stat = fs3.statSync(dir);
5706
+ if (!stat.isDirectory()) return [];
5707
+ const skills = [];
5708
+ scanForSkills(dir, source, skills, onWarning);
5709
+ return skills;
5710
+ }
5711
+ function discoverSkills(options) {
5712
+ const registry = new SkillRegistry();
5713
+ const userSkillsDir = options?.userDir ?? path2.join(os.homedir(), CONFIG_DIR_NAME, SKILLS_DIR_NAME);
5714
+ const userSkills = loadSkillsFromDirectory(userSkillsDir, {
5715
+ type: "user",
5716
+ path: userSkillsDir
5717
+ });
5718
+ registry.registerMany(userSkills);
5719
+ if (options?.projectDir) {
5720
+ const projectSkillsDir = path2.join(options.projectDir, CONFIG_DIR_NAME, SKILLS_DIR_NAME);
5721
+ const projectSkills = loadSkillsFromDirectory(projectSkillsDir, {
5722
+ type: "project",
5723
+ path: projectSkillsDir
5724
+ });
5725
+ registry.registerMany(projectSkills);
5726
+ }
5727
+ if (options?.additionalDirs) {
5728
+ for (const dir of options.additionalDirs) {
5729
+ const resolvedDir = dir.startsWith("~") ? path2.join(os.homedir(), dir.slice(1)) : dir;
5730
+ const skills = loadSkillsFromDirectory(resolvedDir, {
5731
+ type: "directory",
5732
+ path: resolvedDir
5733
+ });
5734
+ registry.registerMany(skills);
5735
+ }
5736
+ }
5737
+ return registry;
5738
+ }
5739
+ function scanForSkills(dir, source, results, onWarning) {
5740
+ let entries;
5741
+ try {
5742
+ entries = fs3.readdirSync(dir, { withFileTypes: true });
5743
+ } catch (error) {
5744
+ onWarning?.(
5745
+ `Cannot read skill directory ${dir}: ${error instanceof Error ? error.message : String(error)}`
5746
+ );
5747
+ return;
5748
+ }
5749
+ const skillMdPath = path2.join(dir, "SKILL.md");
5750
+ if (fs3.existsSync(skillMdPath)) {
5751
+ try {
5752
+ const parsed = parseSkillFile(skillMdPath, source, false);
5753
+ results.push(new Skill(parsed));
5754
+ } catch (error) {
5755
+ onWarning?.(
5756
+ `Failed to parse ${skillMdPath}: ${error instanceof Error ? error.message : String(error)}`
5757
+ );
5758
+ }
5759
+ return;
5760
+ }
5761
+ for (const entry of entries) {
5762
+ if (entry.isDirectory() && !entry.name.startsWith(".")) {
5763
+ scanForSkills(path2.join(dir, entry.name), source, results, onWarning);
5764
+ }
5765
+ }
5766
+ }
5767
+ var SKILLS_DIR_NAME, CONFIG_DIR_NAME;
5768
+ var init_loader = __esm({
5769
+ "src/skills/loader.ts"() {
5770
+ "use strict";
5771
+ init_parser();
5772
+ init_registry2();
5773
+ init_skill();
5774
+ SKILLS_DIR_NAME = "skills";
5775
+ CONFIG_DIR_NAME = ".llmist";
5776
+ }
5777
+ });
5778
+
5779
+ // src/skills/use-skill-gadget.ts
5780
+ import { z as z4 } from "zod";
5781
+ function createUseSkillGadget(registry) {
5782
+ const summaries = registry.getMetadataSummaries();
5783
+ const skillNames = registry.getModelInvocable().map((s) => s.name);
5784
+ const description = [
5785
+ "Activate a skill to get specialized instructions for a task.",
5786
+ "Available skills:",
5787
+ summaries
5788
+ ].join("\n");
5789
+ return createGadget({
5790
+ name: USE_SKILL_GADGET_NAME,
5791
+ description,
5792
+ schema: z4.object({
5793
+ skill: z4.enum(skillNames).describe("Name of the skill to activate"),
5794
+ arguments: z4.string().optional().describe("Arguments for the skill (e.g., a filename, issue number, or search query)")
5795
+ }),
5796
+ execute: async ({ skill: skillName, arguments: args }) => {
5797
+ const skill = registry.get(skillName);
5798
+ if (!skill) {
5799
+ return `Unknown skill: "${skillName}". Available skills: ${skillNames.join(", ")}`;
5800
+ }
5801
+ const activation = await skill.activate({
5802
+ arguments: args,
5803
+ cwd: process.cwd()
5804
+ });
5805
+ return activation.resolvedInstructions;
5806
+ }
5807
+ });
5808
+ }
5809
+ var USE_SKILL_GADGET_NAME;
5810
+ var init_use_skill_gadget = __esm({
5811
+ "src/skills/use-skill-gadget.ts"() {
5812
+ "use strict";
5813
+ init_create_gadget();
5814
+ USE_SKILL_GADGET_NAME = "UseSkill";
5815
+ }
5816
+ });
5817
+
5193
5818
  // src/agent/builder-utils.ts
5194
5819
  function formatGadgetCall(gadgetName, invocationId, parameters, prefixes) {
5195
5820
  const startPrefix = prefixes?.start ?? GADGET_START_PREFIX;
@@ -12194,6 +12819,10 @@ var init_builder = __esm({
12194
12819
  "use strict";
12195
12820
  init_model_shortcuts();
12196
12821
  init_registry();
12822
+ init_activation();
12823
+ init_loader();
12824
+ init_parser();
12825
+ init_use_skill_gadget();
12197
12826
  init_agent();
12198
12827
  init_agent_internal_key();
12199
12828
  init_builder_utils();
@@ -12205,12 +12834,14 @@ var init_builder = __esm({
12205
12834
  retry;
12206
12835
  subagents;
12207
12836
  policies;
12837
+ skills;
12208
12838
  constructor(client) {
12209
12839
  this.core = { client, initialMessages: [] };
12210
12840
  this.gadgets = { gadgets: [] };
12211
12841
  this.retry = {};
12212
12842
  this.subagents = {};
12213
12843
  this.policies = {};
12844
+ this.skills = { preActivated: [], skillDirs: [] };
12214
12845
  }
12215
12846
  /** Set the model to use. Supports aliases like "sonnet", "flash". */
12216
12847
  withModel(model) {
@@ -12347,6 +12978,38 @@ var init_builder = __esm({
12347
12978
  this.policies.compactionConfig = { enabled: false };
12348
12979
  return this;
12349
12980
  }
12981
+ // ─── Skills ──────────────────────────────────────────────────────────────────
12982
+ /** Register a skill registry for this agent. */
12983
+ withSkills(registry) {
12984
+ this.skills.registry = registry;
12985
+ return this;
12986
+ }
12987
+ /**
12988
+ * Pre-activate a specific skill before the agent starts.
12989
+ * Instructions are injected into the system prompt.
12990
+ *
12991
+ * Note: each call replaces (not appends) the pre-activated skill for that name.
12992
+ * This is safe for REPL loops where the same builder is reused.
12993
+ */
12994
+ withSkill(name, args) {
12995
+ const existing = this.skills.preActivated.findIndex((s) => s.name === name);
12996
+ if (existing !== -1) {
12997
+ this.skills.preActivated[existing] = { name, args };
12998
+ } else {
12999
+ this.skills.preActivated.push({ name, args });
13000
+ }
13001
+ return this;
13002
+ }
13003
+ /** Clear all pre-activated skills. Call between REPL iterations. */
13004
+ clearPreActivatedSkills() {
13005
+ this.skills.preActivated = [];
13006
+ return this;
13007
+ }
13008
+ /** Add a directory to scan for skills. */
13009
+ withSkillsFrom(dir) {
13010
+ this.skills.skillDirs.push(dir);
13011
+ return this;
13012
+ }
12350
13013
  /** Configure retry behavior for LLM API calls. */
12351
13014
  withRetry(config) {
12352
13015
  this.retry.retryConfig = { ...config, enabled: config.enabled ?? true };
@@ -12438,16 +13101,75 @@ var init_builder = __esm({
12438
13101
  composeHooks() {
12439
13102
  return HookComposer.compose(this.core.hooks, this.core.trailingMessage);
12440
13103
  }
13104
+ resolveSkillRegistry() {
13105
+ if (this.skills.registry) {
13106
+ if (this.skills.skillDirs.length > 0) {
13107
+ for (const dir of this.skills.skillDirs) {
13108
+ const skills = loadSkillsFromDirectory(dir, { type: "directory", path: dir });
13109
+ this.skills.registry.registerMany(skills);
13110
+ }
13111
+ }
13112
+ return this.skills.registry;
13113
+ }
13114
+ if (this.skills.skillDirs.length > 0) {
13115
+ const { SkillRegistry: SR } = (init_registry2(), __toCommonJS(registry_exports));
13116
+ const reg = new SR();
13117
+ for (const dir of this.skills.skillDirs) {
13118
+ const skills = loadSkillsFromDirectory(dir, { type: "directory", path: dir });
13119
+ reg.registerMany(skills);
13120
+ }
13121
+ return reg;
13122
+ }
13123
+ return void 0;
13124
+ }
13125
+ /**
13126
+ * Resolve pre-activated skill instructions synchronously.
13127
+ * Reads SKILL.md from disk via readFileSync (skills are local files).
13128
+ */
13129
+ resolvePreActivatedInstructions(skillRegistry) {
13130
+ if (this.skills.preActivated.length === 0) return void 0;
13131
+ const fs4 = __require("fs");
13132
+ const blocks = [];
13133
+ for (const { name, args } of this.skills.preActivated) {
13134
+ const skill = skillRegistry.get(name);
13135
+ if (!skill) continue;
13136
+ const content = fs4.readFileSync(skill.sourcePath, "utf-8");
13137
+ const { body } = parseFrontmatter(content);
13138
+ const resolved = resolveInstructions(body, {
13139
+ arguments: args,
13140
+ variables: { SKILL_DIR: skill.sourceDir, CLAUDE_SKILL_DIR: skill.sourceDir },
13141
+ cwd: skill.sourceDir,
13142
+ shell: skill.metadata.shell
13143
+ });
13144
+ blocks.push(`## Skill: ${name}
13145
+
13146
+ ${resolved}`);
13147
+ }
13148
+ return blocks.length > 0 ? blocks.join("\n\n---\n\n") : void 0;
13149
+ }
12441
13150
  buildAgentOptions(userPrompt) {
12442
13151
  if (!this.core.client) {
12443
13152
  const { LLMist: LLMistClass } = (init_client(), __toCommonJS(client_exports));
12444
13153
  this.core.client = new LLMistClass();
12445
13154
  }
12446
13155
  const registry = GadgetRegistry.from(this.gadgets.gadgets);
13156
+ let systemPrompt = this.core.systemPrompt;
13157
+ const skillRegistry = this.resolveSkillRegistry();
13158
+ if (skillRegistry && skillRegistry.size > 0) {
13159
+ if (skillRegistry.getModelInvocable().length > 0) {
13160
+ registry.registerByClass(createUseSkillGadget(skillRegistry));
13161
+ }
13162
+ const preActivatedBlock = this.resolvePreActivatedInstructions(skillRegistry);
13163
+ if (preActivatedBlock) {
13164
+ systemPrompt = systemPrompt ? `${systemPrompt}
13165
+
13166
+ ${preActivatedBlock}` : preActivatedBlock;
13167
+ }
13168
+ }
12447
13169
  return {
12448
13170
  client: this.core.client,
12449
13171
  model: this.core.model ?? "openai:gpt-5-nano",
12450
- systemPrompt: this.core.systemPrompt,
13172
+ systemPrompt,
12451
13173
  userPrompt,
12452
13174
  registry,
12453
13175
  maxIterations: this.core.maxIterations,
@@ -13132,8 +13854,8 @@ var init_error_formatter = __esm({
13132
13854
  const parts = [];
13133
13855
  parts.push(`Error: Invalid parameters for '${gadgetName}':`);
13134
13856
  for (const issue of zodError.issues) {
13135
- const path = issue.path.join(".") || "root";
13136
- parts.push(` - ${path}: ${issue.message}`);
13857
+ const path3 = issue.path.join(".") || "root";
13858
+ parts.push(` - ${path3}: ${issue.message}`);
13137
13859
  }
13138
13860
  parts.push("");
13139
13861
  parts.push("Gadget Usage:");
@@ -13198,7 +13920,7 @@ function stripMarkdownFences(content) {
13198
13920
  return cleaned.trim();
13199
13921
  }
13200
13922
  var globalInvocationCounter, GadgetCallParser;
13201
- var init_parser = __esm({
13923
+ var init_parser2 = __esm({
13202
13924
  "src/gadgets/parser.ts"() {
13203
13925
  "use strict";
13204
13926
  init_constants();
@@ -13234,8 +13956,9 @@ var init_parser = __esm({
13234
13956
  * - `GadgetName` - Auto-generate ID, no dependencies
13235
13957
  * - `GadgetName:my_id` - Explicit ID, no dependencies
13236
13958
  * - `GadgetName:my_id:dep1,dep2` - Explicit ID with dependencies
13959
+ * - `GadgetName:my_id:dep1:dep2:dep3` - Colons treated as dep separators (LLM resilience)
13237
13960
  *
13238
- * Dependencies must be comma-separated invocation IDs.
13961
+ * Dependencies can be comma-separated or colon-separated invocation IDs.
13239
13962
  */
13240
13963
  parseInvocationMetadata(headerLine) {
13241
13964
  const parts = headerLine.split(":");
@@ -13252,7 +13975,12 @@ var init_parser = __esm({
13252
13975
  dependencies: []
13253
13976
  };
13254
13977
  } else {
13255
- const deps = parts[2].split(",").map((d) => d.trim()).filter((d) => d.length > 0);
13978
+ const depsRaw = parts.slice(2).join(",");
13979
+ const deps = [
13980
+ ...new Set(
13981
+ depsRaw.split(",").map((d) => d.trim()).filter((d) => d.length > 0)
13982
+ )
13983
+ ];
13256
13984
  return {
13257
13985
  gadgetName: parts[0],
13258
13986
  invocationId: parts[1].trim(),
@@ -13404,7 +14132,7 @@ var init_typed_gadget = __esm({
13404
14132
 
13405
14133
  // src/gadgets/executor.ts
13406
14134
  import equal from "fast-deep-equal";
13407
- import { z as z4 } from "zod";
14135
+ import { z as z5 } from "zod";
13408
14136
  function getHostExportsInternal() {
13409
14137
  return {
13410
14138
  AgentBuilder,
@@ -13412,7 +14140,7 @@ function getHostExportsInternal() {
13412
14140
  createGadget,
13413
14141
  ExecutionTree,
13414
14142
  LLMist,
13415
- z: z4
14143
+ z: z5
13416
14144
  };
13417
14145
  }
13418
14146
  var GadgetExecutor;
@@ -13430,7 +14158,7 @@ var init_executor = __esm({
13430
14158
  init_create_gadget();
13431
14159
  init_error_formatter();
13432
14160
  init_exceptions();
13433
- init_parser();
14161
+ init_parser2();
13434
14162
  init_typed_gadget();
13435
14163
  GadgetExecutor = class {
13436
14164
  registry;
@@ -13825,6 +14553,8 @@ var init_gadget_concurrency_manager = __esm({
13825
14553
  concurrencyQueue = /* @__PURE__ */ new Map();
13826
14554
  /** All active gadget promises, keyed by invocationId */
13827
14555
  inFlightExecutions = /* @__PURE__ */ new Map();
14556
+ /** Gadget name for each in-flight invocationId (for timeout event emission) */
14557
+ inFlightGadgetNames = /* @__PURE__ */ new Map();
13828
14558
  /** Queue of exclusive gadgets deferred until in-flight gadgets complete */
13829
14559
  exclusiveQueue = [];
13830
14560
  constructor(options) {
@@ -13952,6 +14682,7 @@ var init_gadget_concurrency_manager = __esm({
13952
14682
  const currentCount = this.activeCountByGadget.get(gadgetName) ?? 0;
13953
14683
  this.activeCountByGadget.set(gadgetName, currentCount + 1);
13954
14684
  this.inFlightExecutions.set(invocationId, promise);
14685
+ this.inFlightGadgetNames.set(invocationId, gadgetName);
13955
14686
  }
13956
14687
  /**
13957
14688
  * Called when a gadget execution completes.
@@ -13995,11 +14726,25 @@ var init_gadget_concurrency_manager = __esm({
13995
14726
  this.exclusiveQueue.push(call);
13996
14727
  }
13997
14728
  /**
13998
- * Clear the inFlightExecutions map after all promises have completed.
13999
- * Called after waitForAll resolves.
14729
+ * Clear all in-flight tracking state.
14730
+ * Called after all promises have completed, or on force-timeout.
14731
+ * Also clears active gadget counts to prevent stale state when
14732
+ * hanging promises eventually resolve into the void.
14000
14733
  */
14001
14734
  clearInFlight() {
14002
14735
  this.inFlightExecutions.clear();
14736
+ this.inFlightGadgetNames.clear();
14737
+ this.activeCountByGadget.clear();
14738
+ }
14739
+ /**
14740
+ * Get metadata for all currently in-flight executions.
14741
+ * Used by the dispatcher to emit skip events when the in-flight timeout fires.
14742
+ */
14743
+ getInFlightEntries() {
14744
+ return Array.from(this.inFlightGadgetNames.entries()).map(([invocationId, gadgetName]) => ({
14745
+ invocationId,
14746
+ gadgetName
14747
+ }));
14003
14748
  }
14004
14749
  // ==========================================================================
14005
14750
  // Waiting
@@ -14324,6 +15069,7 @@ var init_gadget_dispatcher = __esm({
14324
15069
  logger;
14325
15070
  pushToQueue;
14326
15071
  drainQueue;
15072
+ inFlightTimeoutMs;
14327
15073
  constructor(options) {
14328
15074
  this.iteration = options.iteration;
14329
15075
  this.hookLifecycle = options.hookLifecycle;
@@ -14338,6 +15084,7 @@ var init_gadget_dispatcher = __esm({
14338
15084
  this.logger = options.logger ?? createLogger({ name: "llmist:gadget-dispatcher" });
14339
15085
  this.pushToQueue = options.pushToQueue;
14340
15086
  this.drainQueue = options.drainQueue;
15087
+ this.inFlightTimeoutMs = options.inFlightTimeoutMs ?? 3e5;
14341
15088
  }
14342
15089
  // ==========================================================================
14343
15090
  // Primary dispatch entry point
@@ -14369,39 +15116,54 @@ var init_gadget_dispatcher = __esm({
14369
15116
  parentId: this.parentNodeId
14370
15117
  });
14371
15118
  }
15119
+ let effectiveCall = call;
14372
15120
  if (call.dependencies.length > 0) {
14373
- if (call.dependencies.includes(call.invocationId)) {
14374
- this.logger.warn("Gadget has self-referential dependency (depends on itself)", {
15121
+ const selfRefs = [];
15122
+ const validDeps = [];
15123
+ for (const dep of call.dependencies) {
15124
+ (dep === call.invocationId ? selfRefs : validDeps).push(dep);
15125
+ }
15126
+ if (selfRefs.length > 0) {
15127
+ this.logger.warn("Filtering self-referential dependencies", {
14375
15128
  gadgetName: call.gadgetName,
14376
- invocationId: call.invocationId
15129
+ invocationId: call.invocationId,
15130
+ removedSelfRefs: selfRefs,
15131
+ remainingDeps: validDeps
14377
15132
  });
14378
- const errorMessage = `Gadget "${call.invocationId}" cannot depend on itself (self-referential dependency)`;
14379
- for await (const evt of this.emitGadgetSkipEvents(call, call.invocationId, errorMessage)) {
14380
- yield evt;
15133
+ effectiveCall = { ...call, dependencies: validDeps };
15134
+ if (validDeps.length === 0) {
15135
+ const errorMessage = `Gadget "${call.invocationId}" cannot depend on itself (self-referential dependency)`;
15136
+ for await (const evt of this.emitGadgetSkipEvents(
15137
+ effectiveCall,
15138
+ call.invocationId,
15139
+ errorMessage
15140
+ )) {
15141
+ yield evt;
15142
+ }
15143
+ return;
14381
15144
  }
14382
- return;
14383
15145
  }
14384
- const failedDep = this.dependencyResolver.getFailedDependency(call);
15146
+ const failedDep = this.dependencyResolver.getFailedDependency(effectiveCall);
14385
15147
  if (failedDep) {
14386
- const skipEvents = await this.handleFailedDependency(call, failedDep);
15148
+ const skipEvents = await this.handleFailedDependency(effectiveCall, failedDep);
14387
15149
  for (const evt of skipEvents) {
14388
15150
  yield evt;
14389
15151
  }
14390
15152
  return;
14391
15153
  }
14392
- if (!this.dependencyResolver.isAllSatisfied(call)) {
14393
- const unsatisfied = call.dependencies.filter(
15154
+ if (!this.dependencyResolver.isAllSatisfied(effectiveCall)) {
15155
+ const unsatisfied = effectiveCall.dependencies.filter(
14394
15156
  (dep) => !this.dependencyResolver.isCompleted(dep)
14395
15157
  );
14396
15158
  this.logger.debug("Queueing gadget for later - waiting on dependencies", {
14397
- gadgetName: call.gadgetName,
14398
- invocationId: call.invocationId,
15159
+ gadgetName: effectiveCall.gadgetName,
15160
+ invocationId: effectiveCall.invocationId,
14399
15161
  waitingOn: unsatisfied
14400
15162
  });
14401
- this.dependencyResolver.addPending(call);
15163
+ this.dependencyResolver.addPending(effectiveCall);
14402
15164
  return;
14403
15165
  }
14404
- for await (const evt of this._checkLimitThenExecute(call)) {
15166
+ for await (const evt of this._checkLimitThenExecute(effectiveCall)) {
14405
15167
  yield evt;
14406
15168
  }
14407
15169
  for await (const evt of this.processPendingGadgets()) {
@@ -14540,7 +15302,31 @@ var init_gadget_dispatcher = __esm({
14540
15302
  queuedCount: this.concurrencyManager.getQueuedGadgetCount()
14541
15303
  });
14542
15304
  const POLL_INTERVAL_MS = 100;
15305
+ const startTime = Date.now();
14543
15306
  while (this.concurrencyManager.inFlightCount > 0 || this.concurrencyManager.hasQueuedGadgets()) {
15307
+ if (Date.now() - startTime >= this.inFlightTimeoutMs) {
15308
+ const timedOutEntries = this.concurrencyManager.getInFlightEntries();
15309
+ this.logger.error("In-flight gadget timeout exceeded, force-clearing remaining gadgets", {
15310
+ timeoutMs: this.inFlightTimeoutMs,
15311
+ remainingInFlight: timedOutEntries.length,
15312
+ remainingQueued: this.concurrencyManager.getQueuedGadgetCount(),
15313
+ timedOutInvocations: timedOutEntries.map((e) => e.invocationId)
15314
+ });
15315
+ const timeoutError = `Gadget execution timed out after ${this.inFlightTimeoutMs}ms`;
15316
+ for (const { invocationId, gadgetName } of timedOutEntries) {
15317
+ this.dependencyResolver.markFailed(invocationId);
15318
+ yield {
15319
+ type: "gadget_skipped",
15320
+ gadgetName,
15321
+ invocationId,
15322
+ parameters: {},
15323
+ failedDependency: invocationId,
15324
+ failedDependencyError: timeoutError
15325
+ };
15326
+ }
15327
+ this.concurrencyManager.clearInFlight();
15328
+ break;
15329
+ }
14544
15330
  const allDone = this.concurrencyManager.getAllDonePromise();
14545
15331
  const result = await Promise.race([
14546
15332
  allDone,
@@ -15031,7 +15817,7 @@ var init_stream_processor = __esm({
15031
15817
  "src/agent/stream-processor.ts"() {
15032
15818
  "use strict";
15033
15819
  init_executor();
15034
- init_parser();
15820
+ init_parser2();
15035
15821
  init_logger();
15036
15822
  init_gadget_concurrency_manager();
15037
15823
  init_gadget_dependency_resolver();
@@ -15126,7 +15912,8 @@ var init_stream_processor = __esm({
15126
15912
  const evts = [...this.completedResultsQueue];
15127
15913
  this.completedResultsQueue = [];
15128
15914
  return evts;
15129
- }
15915
+ },
15916
+ inFlightTimeoutMs: options.inFlightTimeoutMs
15130
15917
  });
15131
15918
  }
15132
15919
  /**
@@ -15350,6 +16137,7 @@ var init_stream_processor_factory = __esm({
15350
16137
  logger;
15351
16138
  requestHumanInput;
15352
16139
  defaultGadgetTimeoutMs;
16140
+ inFlightTimeoutMs;
15353
16141
  gadgetExecutionMode;
15354
16142
  client;
15355
16143
  mediaStore;
@@ -15368,6 +16156,7 @@ var init_stream_processor_factory = __esm({
15368
16156
  this.logger = options.logger;
15369
16157
  this.requestHumanInput = options.requestHumanInput;
15370
16158
  this.defaultGadgetTimeoutMs = options.defaultGadgetTimeoutMs;
16159
+ this.inFlightTimeoutMs = options.inFlightTimeoutMs;
15371
16160
  this.gadgetExecutionMode = options.gadgetExecutionMode;
15372
16161
  this.client = options.client;
15373
16162
  this.mediaStore = options.mediaStore;
@@ -15399,6 +16188,7 @@ var init_stream_processor_factory = __esm({
15399
16188
  logger: this.logger.getSubLogger({ name: "stream-processor" }),
15400
16189
  requestHumanInput: this.requestHumanInput,
15401
16190
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
16191
+ inFlightTimeoutMs: this.inFlightTimeoutMs,
15402
16192
  gadgetExecutionMode: this.gadgetExecutionMode,
15403
16193
  client: this.client,
15404
16194
  mediaStore: this.mediaStore,
@@ -16155,7 +16945,7 @@ init_builder();
16155
16945
  init_event_handlers();
16156
16946
  init_file_logging();
16157
16947
  init_hook_presets();
16158
- import { z as z5 } from "zod";
16948
+ import { z as z6 } from "zod";
16159
16949
 
16160
16950
  // src/agent/compaction/index.ts
16161
16951
  init_config();
@@ -16464,7 +17254,7 @@ function resultWithFile(result, fileData, mimeType, options) {
16464
17254
 
16465
17255
  // src/index.ts
16466
17256
  init_output_viewer();
16467
- init_parser();
17257
+ init_parser2();
16468
17258
  init_registry();
16469
17259
  init_typed_gadget();
16470
17260
  init_constants2();
@@ -16731,6 +17521,14 @@ var SimpleSessionManager = class extends BaseSessionManager {
16731
17521
  }
16732
17522
  };
16733
17523
 
17524
+ // src/skills/index.ts
17525
+ init_activation();
17526
+ init_loader();
17527
+ init_parser();
17528
+ init_registry2();
17529
+ init_skill();
17530
+ init_use_skill_gadget();
17531
+
16734
17532
  // src/utils/format.ts
16735
17533
  function truncate(text3, maxLength, suffix = "...") {
16736
17534
  if (text3.length <= maxLength) return text3;
@@ -16926,11 +17724,14 @@ export {
16926
17724
  OpenRouterProvider,
16927
17725
  RateLimitTracker,
16928
17726
  SimpleSessionManager,
17727
+ Skill,
17728
+ SkillRegistry,
16929
17729
  SlidingWindowStrategy,
16930
17730
  StreamProcessor,
16931
17731
  SummarizationStrategy,
16932
17732
  TaskCompletionSignal,
16933
17733
  TimeoutException,
17734
+ USE_SKILL_GADGET_NAME,
16934
17735
  audioFromBase64,
16935
17736
  audioFromBuffer,
16936
17737
  collectEvents,
@@ -16948,10 +17749,12 @@ export {
16948
17749
  createOpenAIProviderFromEnv,
16949
17750
  createOpenRouterProviderFromEnv,
16950
17751
  createSubagent,
17752
+ createUseSkillGadget,
16951
17753
  defaultLogger,
16952
17754
  detectAudioMimeType,
16953
17755
  detectImageMimeType,
16954
17756
  discoverProviderAdapters,
17757
+ discoverSkills,
16955
17758
  extractMessageText,
16956
17759
  extractRetryAfterMs,
16957
17760
  filterByDepth,
@@ -16994,15 +17797,21 @@ export {
16994
17797
  iterationProgressHint,
16995
17798
  listPresets,
16996
17799
  listSubagents,
17800
+ loadSkillsFromDirectory,
16997
17801
  normalizeMessageContent,
16998
17802
  parallelGadgetHint,
16999
17803
  parseDataUrl,
17804
+ parseFrontmatter,
17000
17805
  parseManifest,
17806
+ parseMetadata,
17001
17807
  parseRetryAfterHeader,
17808
+ parseSkillContent,
17809
+ parseSkillFile,
17002
17810
  randomDelay,
17003
17811
  resetFileLoggingState,
17004
17812
  resolveConfig,
17005
17813
  resolveHintTemplate,
17814
+ resolveInstructions,
17006
17815
  resolveModel,
17007
17816
  resolvePromptTemplate,
17008
17817
  resolveRateLimitConfig,
@@ -17017,9 +17826,12 @@ export {
17017
17826
  resultWithImages,
17018
17827
  resultWithMedia,
17019
17828
  runWithHandlers,
17829
+ scanResources,
17020
17830
  schemaToJSONSchema,
17021
17831
  stream,
17022
17832
  stripProviderPrefix,
17833
+ substituteArguments,
17834
+ substituteVariables,
17023
17835
  text,
17024
17836
  timing,
17025
17837
  toBase64,
@@ -17027,9 +17839,10 @@ export {
17027
17839
  validateAndApplyDefaults,
17028
17840
  validateGadgetParams,
17029
17841
  validateGadgetSchema,
17842
+ validateMetadata,
17030
17843
  withErrorHandling,
17031
17844
  withRetry,
17032
17845
  withTimeout,
17033
- z5 as z
17846
+ z6 as z
17034
17847
  };
17035
17848
  //# sourceMappingURL=index.js.map