@agentforge/core 0.14.0 → 0.15.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
@@ -1406,7 +1406,7 @@ function createToolExecutor(config = {}) {
1406
1406
  }
1407
1407
  if (attempt < policy.maxAttempts) {
1408
1408
  const delay = calculateBackoff(attempt, policy);
1409
- await new Promise((resolve3) => setTimeout(resolve3, delay));
1409
+ await new Promise((resolve) => setTimeout(resolve, delay));
1410
1410
  }
1411
1411
  }
1412
1412
  }
@@ -1463,12 +1463,12 @@ function createToolExecutor(config = {}) {
1463
1463
  }
1464
1464
  async function execute(tool, input, options = {}) {
1465
1465
  const priority = options.priority || priorityFn(tool);
1466
- return new Promise((resolve3, reject) => {
1466
+ return new Promise((resolve, reject) => {
1467
1467
  queue.push({
1468
1468
  tool,
1469
1469
  input,
1470
1470
  priority,
1471
- resolve: resolve3,
1471
+ resolve,
1472
1472
  reject,
1473
1473
  timestamp: Date.now()
1474
1474
  });
@@ -1768,7 +1768,7 @@ function retry(tool, options = {}) {
1768
1768
  lastError = error;
1769
1769
  if (attempt < maxAttempts) {
1770
1770
  const waitTime = backoff === "exponential" ? delay * Math.pow(2, attempt - 1) : delay * attempt;
1771
- await new Promise((resolve3) => setTimeout(resolve3, waitTime));
1771
+ await new Promise((resolve) => setTimeout(resolve, waitTime));
1772
1772
  }
1773
1773
  }
1774
1774
  }
@@ -1829,7 +1829,7 @@ function createMockTool(config) {
1829
1829
  const startTime = Date.now();
1830
1830
  if (latency) {
1831
1831
  const delay = typeof latency === "number" ? latency : Math.random() * (latency.max - latency.min) + latency.min;
1832
- await new Promise((resolve3) => setTimeout(resolve3, delay));
1832
+ await new Promise((resolve) => setTimeout(resolve, delay));
1833
1833
  }
1834
1834
  if (errorRate > 0 && Math.random() < errorRate) {
1835
1835
  const error2 = new Error(`Random error from ${name}`);
@@ -1900,8 +1900,8 @@ function createToolSimulator(config) {
1900
1900
  if (!latency) return 0;
1901
1901
  const u1 = Math.random();
1902
1902
  const u2 = Math.random();
1903
- const z4 = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
1904
- return Math.max(0, latency.mean + z4 * latency.stddev);
1903
+ const z3 = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
1904
+ return Math.max(0, latency.mean + z3 * latency.stddev);
1905
1905
  }
1906
1906
  return {
1907
1907
  execute: async (toolName, input) => {
@@ -1912,7 +1912,7 @@ function createToolSimulator(config) {
1912
1912
  const startTime = Date.now();
1913
1913
  if (latency) {
1914
1914
  const delay = generateLatency();
1915
- await new Promise((resolve3) => setTimeout(resolve3, delay));
1915
+ await new Promise((resolve) => setTimeout(resolve, delay));
1916
1916
  }
1917
1917
  if (errorRate > 0 && Math.random() < errorRate) {
1918
1918
  const error = new Error(`Simulated error from ${toolName}`);
@@ -2270,7 +2270,7 @@ function calculateDelay(attempt, strategy, initialDelay, maxDelay) {
2270
2270
  return Math.min(delay, maxDelay);
2271
2271
  }
2272
2272
  function sleep(ms) {
2273
- return new Promise((resolve3) => setTimeout(resolve3, ms));
2273
+ return new Promise((resolve) => setTimeout(resolve, ms));
2274
2274
  }
2275
2275
  function withRetry(node, options = {}) {
2276
2276
  const {
@@ -2516,14 +2516,14 @@ var withLogging = (options) => {
2516
2516
  onComplete,
2517
2517
  onError
2518
2518
  } = options;
2519
- const logger8 = providedLogger || createLogger(name, { level });
2519
+ const logger5 = providedLogger || createLogger(name, { level });
2520
2520
  return (node) => {
2521
2521
  return async (state) => {
2522
2522
  const startTime = Date.now();
2523
2523
  try {
2524
2524
  if (logInput) {
2525
2525
  const data = extractData ? extractData(state) : { state };
2526
- logger8.info("Node execution started", data);
2526
+ logger5.info("Node execution started", data);
2527
2527
  }
2528
2528
  if (onStart) {
2529
2529
  onStart(state);
@@ -2533,9 +2533,9 @@ var withLogging = (options) => {
2533
2533
  if (logOutput) {
2534
2534
  const data = extractData ? extractData(result) : { result };
2535
2535
  if (logDuration) {
2536
- logger8.info(`Node execution completed (${duration}ms)`, data);
2536
+ logger5.info(`Node execution completed (${duration}ms)`, data);
2537
2537
  } else {
2538
- logger8.info("Node execution completed", data);
2538
+ logger5.info("Node execution completed", data);
2539
2539
  }
2540
2540
  }
2541
2541
  if (onComplete) {
@@ -2546,7 +2546,7 @@ var withLogging = (options) => {
2546
2546
  const duration = Date.now() - startTime;
2547
2547
  const err = error instanceof Error ? error : new Error(String(error));
2548
2548
  if (logErrors) {
2549
- logger8.error(`Node execution failed (${duration}ms)`, {
2549
+ logger5.error(`Node execution failed (${duration}ms)`, {
2550
2550
  error: err.message,
2551
2551
  stack: err.stack
2552
2552
  });
@@ -2582,7 +2582,7 @@ function withLogging2(options) {
2582
2582
  function production(node, options) {
2583
2583
  const {
2584
2584
  nodeName,
2585
- logger: logger8,
2585
+ logger: logger5,
2586
2586
  enableMetrics = true,
2587
2587
  enableTracing = true,
2588
2588
  enableRetry = true,
@@ -2590,7 +2590,7 @@ function production(node, options) {
2590
2590
  retryOptions = {},
2591
2591
  errorOptions = {}
2592
2592
  } = options;
2593
- const actualLogger = logger8 || createLogger(nodeName, { level: "info" /* INFO */ });
2593
+ const actualLogger = logger5 || createLogger(nodeName, { level: "info" /* INFO */ });
2594
2594
  const middleware = [];
2595
2595
  middleware.push(
2596
2596
  withLogging2({
@@ -2654,9 +2654,9 @@ function development(node, options) {
2654
2654
  const {
2655
2655
  nodeName,
2656
2656
  verbose = true,
2657
- logger: logger8
2657
+ logger: logger5
2658
2658
  } = options;
2659
- const actualLogger = logger8 || createLogger(nodeName, { level: "debug" /* DEBUG */ });
2659
+ const actualLogger = logger5 || createLogger(nodeName, { level: "debug" /* DEBUG */ });
2660
2660
  return withLogging2({
2661
2661
  logger: actualLogger,
2662
2662
  name: nodeName,
@@ -2680,7 +2680,7 @@ function testing(node, options) {
2680
2680
  invocations.push(state);
2681
2681
  }
2682
2682
  if (delay > 0) {
2683
- await new Promise((resolve3) => setTimeout(resolve3, delay));
2683
+ await new Promise((resolve) => setTimeout(resolve, delay));
2684
2684
  }
2685
2685
  if (simulateError) {
2686
2686
  throw simulateError;
@@ -3139,12 +3139,12 @@ var ConcurrencyController = class {
3139
3139
  }
3140
3140
  throw new Error(`Queue is full (max size: ${this.maxQueueSize})`);
3141
3141
  }
3142
- return new Promise((resolve3, reject) => {
3142
+ return new Promise((resolve, reject) => {
3143
3143
  const task = {
3144
3144
  state,
3145
3145
  priority,
3146
3146
  executor,
3147
- resolve: resolve3,
3147
+ resolve,
3148
3148
  reject,
3149
3149
  timestamp: Date.now()
3150
3150
  };
@@ -3609,7 +3609,7 @@ async function* throttle(stream, options) {
3609
3609
  const now = Date.now();
3610
3610
  const timeSinceLastEmit = now - lastEmit;
3611
3611
  if (timeSinceLastEmit < interval) {
3612
- await new Promise((resolve3) => setTimeout(resolve3, interval - timeSinceLastEmit));
3612
+ await new Promise((resolve) => setTimeout(resolve, interval - timeSinceLastEmit));
3613
3613
  }
3614
3614
  lastEmit = Date.now();
3615
3615
  yield item;
@@ -4124,17 +4124,17 @@ var ConnectionPool = class {
4124
4124
  this.options.onAcquire?.(connection);
4125
4125
  return connection;
4126
4126
  }
4127
- return new Promise((resolve3, reject) => {
4127
+ return new Promise((resolve, reject) => {
4128
4128
  const timeout2 = poolConfig.acquireTimeout || 3e4;
4129
4129
  const timer = setTimeout(() => {
4130
- const index = this.pending.findIndex((p) => p.resolve === resolve3);
4130
+ const index = this.pending.findIndex((p) => p.resolve === resolve);
4131
4131
  if (index !== -1) {
4132
4132
  this.pending.splice(index, 1);
4133
4133
  this.stats.pending--;
4134
4134
  }
4135
4135
  reject(new Error("Acquire timeout"));
4136
4136
  }, timeout2);
4137
- this.pending.push({ resolve: resolve3, reject, timeout: timer });
4137
+ this.pending.push({ resolve, reject, timeout: timer });
4138
4138
  this.stats.pending++;
4139
4139
  });
4140
4140
  }
@@ -4218,7 +4218,7 @@ var ConnectionPool = class {
4218
4218
  this.pending = [];
4219
4219
  this.stats.pending = 0;
4220
4220
  while (this.connections.some((c) => c.inUse)) {
4221
- await new Promise((resolve3) => setTimeout(resolve3, 100));
4221
+ await new Promise((resolve) => setTimeout(resolve, 100));
4222
4222
  }
4223
4223
  }
4224
4224
  async clear() {
@@ -4545,10 +4545,10 @@ var BatchProcessor = class {
4545
4545
  failedBatches: 0
4546
4546
  };
4547
4547
  add(input) {
4548
- return new Promise((resolve3, reject) => {
4548
+ return new Promise((resolve, reject) => {
4549
4549
  this.pending.push({
4550
4550
  input,
4551
- resolve: resolve3,
4551
+ resolve,
4552
4552
  reject,
4553
4553
  addedAt: Date.now()
4554
4554
  });
@@ -5308,841 +5308,6 @@ function loadPrompt(promptName, options = {}, promptsDir) {
5308
5308
  );
5309
5309
  }
5310
5310
  }
5311
-
5312
- // src/skills/types.ts
5313
- var TrustPolicyReason = /* @__PURE__ */ ((TrustPolicyReason2) => {
5314
- TrustPolicyReason2["NOT_SCRIPT"] = "not-script";
5315
- TrustPolicyReason2["WORKSPACE_TRUST"] = "workspace-trust";
5316
- TrustPolicyReason2["TRUSTED_ROOT"] = "trusted-root";
5317
- TrustPolicyReason2["UNTRUSTED_SCRIPT_DENIED"] = "untrusted-script-denied";
5318
- TrustPolicyReason2["UNTRUSTED_SCRIPT_ALLOWED"] = "untrusted-script-allowed-override";
5319
- TrustPolicyReason2["UNKNOWN_TRUST_LEVEL"] = "unknown-trust-level";
5320
- return TrustPolicyReason2;
5321
- })(TrustPolicyReason || {});
5322
- var SkillRegistryEvent = /* @__PURE__ */ ((SkillRegistryEvent2) => {
5323
- SkillRegistryEvent2["SKILL_DISCOVERED"] = "skill:discovered";
5324
- SkillRegistryEvent2["SKILL_WARNING"] = "skill:warning";
5325
- SkillRegistryEvent2["SKILL_ACTIVATED"] = "skill:activated";
5326
- SkillRegistryEvent2["SKILL_RESOURCE_LOADED"] = "skill:resource-loaded";
5327
- SkillRegistryEvent2["TRUST_POLICY_DENIED"] = "trust:policy-denied";
5328
- SkillRegistryEvent2["TRUST_POLICY_ALLOWED"] = "trust:policy-allowed";
5329
- return SkillRegistryEvent2;
5330
- })(SkillRegistryEvent || {});
5331
-
5332
- // src/skills/parser.ts
5333
- import matter from "gray-matter";
5334
- var SKILL_NAME_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
5335
- var SKILL_NAME_MAX_LENGTH = 64;
5336
- var SKILL_DESCRIPTION_MAX_LENGTH = 1024;
5337
- function validateSkillName(name) {
5338
- const errors = [];
5339
- if (name === void 0 || name === null) {
5340
- errors.push({ field: "name", message: "name is required" });
5341
- return errors;
5342
- }
5343
- if (typeof name !== "string") {
5344
- errors.push({ field: "name", message: "name must be a string" });
5345
- return errors;
5346
- }
5347
- if (name.length === 0) {
5348
- errors.push({ field: "name", message: "name must not be empty" });
5349
- return errors;
5350
- }
5351
- if (name.length > SKILL_NAME_MAX_LENGTH) {
5352
- errors.push({
5353
- field: "name",
5354
- message: `name must be at most ${SKILL_NAME_MAX_LENGTH} characters (got ${name.length})`
5355
- });
5356
- return errors;
5357
- }
5358
- if (!SKILL_NAME_PATTERN.test(name)) {
5359
- errors.push({
5360
- field: "name",
5361
- message: "name must be lowercase alphanumeric with hyphens, no leading/trailing/consecutive hyphens"
5362
- });
5363
- }
5364
- if (name.includes("--")) {
5365
- errors.push({
5366
- field: "name",
5367
- message: "name must not contain consecutive hyphens"
5368
- });
5369
- }
5370
- return errors;
5371
- }
5372
- function validateSkillDescription(description) {
5373
- const errors = [];
5374
- if (description === void 0 || description === null) {
5375
- errors.push({ field: "description", message: "description is required" });
5376
- return errors;
5377
- }
5378
- if (typeof description !== "string") {
5379
- errors.push({ field: "description", message: "description must be a string" });
5380
- return errors;
5381
- }
5382
- if (description.trim().length === 0) {
5383
- errors.push({ field: "description", message: "description must not be empty" });
5384
- return errors;
5385
- }
5386
- if (description.length > SKILL_DESCRIPTION_MAX_LENGTH) {
5387
- errors.push({
5388
- field: "description",
5389
- message: `description must be at most ${SKILL_DESCRIPTION_MAX_LENGTH} characters (got ${description.length})`
5390
- });
5391
- }
5392
- return errors;
5393
- }
5394
- function validateSkillNameMatchesDir(name, dirName) {
5395
- if (name !== dirName) {
5396
- return [{
5397
- field: "name",
5398
- message: `name "${name}" must match parent directory name "${dirName}"`
5399
- }];
5400
- }
5401
- return [];
5402
- }
5403
- function parseSkillContent(content, dirName) {
5404
- let parsed;
5405
- try {
5406
- parsed = matter(content);
5407
- } catch (err) {
5408
- return {
5409
- success: false,
5410
- error: `Failed to parse frontmatter: ${err instanceof Error ? err.message : String(err)}`
5411
- };
5412
- }
5413
- const data = parsed.data;
5414
- const errors = [
5415
- ...validateSkillName(data.name),
5416
- ...validateSkillDescription(data.description)
5417
- ];
5418
- if (typeof data.name === "string" && data.name.length > 0 && SKILL_NAME_PATTERN.test(data.name)) {
5419
- errors.push(...validateSkillNameMatchesDir(data.name, dirName));
5420
- }
5421
- if (errors.length > 0) {
5422
- return {
5423
- success: false,
5424
- error: errors.map((e) => `${e.field}: ${e.message}`).join("; ")
5425
- };
5426
- }
5427
- const metadata = {
5428
- name: data.name,
5429
- description: data.description
5430
- };
5431
- if (data.license !== void 0) {
5432
- metadata.license = String(data.license);
5433
- }
5434
- if (Array.isArray(data.compatibility)) {
5435
- metadata.compatibility = data.compatibility.map(String);
5436
- }
5437
- if (data.metadata !== void 0 && typeof data.metadata === "object" && data.metadata !== null) {
5438
- metadata.metadata = data.metadata;
5439
- }
5440
- if (Array.isArray(data["allowed-tools"])) {
5441
- metadata.allowedTools = data["allowed-tools"].map(String);
5442
- }
5443
- return {
5444
- success: true,
5445
- metadata,
5446
- body: parsed.content
5447
- };
5448
- }
5449
-
5450
- // src/skills/scanner.ts
5451
- import { existsSync, readdirSync, statSync, readFileSync as readFileSync2 } from "fs";
5452
- import { resolve, basename } from "path";
5453
- import { homedir } from "os";
5454
- var logger5 = createLogger("agentforge:core:skills:scanner", { level: "info" /* INFO */ });
5455
- function expandHome(p) {
5456
- if (p.startsWith("~/") || p === "~") {
5457
- return resolve(homedir(), p.slice(2));
5458
- }
5459
- return p;
5460
- }
5461
- function scanSkillRoot(rootPath) {
5462
- const resolvedRoot = resolve(expandHome(rootPath));
5463
- const candidates = [];
5464
- if (!existsSync(resolvedRoot)) {
5465
- logger5.debug("Skill root does not exist, skipping", { rootPath: resolvedRoot });
5466
- return candidates;
5467
- }
5468
- let entries;
5469
- try {
5470
- entries = readdirSync(resolvedRoot);
5471
- } catch (err) {
5472
- logger5.warn("Failed to read skill root directory", {
5473
- rootPath: resolvedRoot,
5474
- error: err instanceof Error ? err.message : String(err)
5475
- });
5476
- return candidates;
5477
- }
5478
- for (const entry of entries) {
5479
- const entryPath = resolve(resolvedRoot, entry);
5480
- let stat;
5481
- try {
5482
- stat = statSync(entryPath);
5483
- } catch {
5484
- continue;
5485
- }
5486
- if (!stat.isDirectory()) {
5487
- continue;
5488
- }
5489
- const skillMdPath = resolve(entryPath, "SKILL.md");
5490
- if (!existsSync(skillMdPath)) {
5491
- continue;
5492
- }
5493
- try {
5494
- const content = readFileSync2(skillMdPath, "utf-8");
5495
- candidates.push({
5496
- skillPath: entryPath,
5497
- dirName: basename(entryPath),
5498
- content,
5499
- rootPath: resolvedRoot
5500
- });
5501
- } catch (err) {
5502
- logger5.warn("Failed to read SKILL.md", {
5503
- path: skillMdPath,
5504
- error: err instanceof Error ? err.message : String(err)
5505
- });
5506
- }
5507
- }
5508
- logger5.debug("Scanned skill root", {
5509
- rootPath: resolvedRoot,
5510
- candidatesFound: candidates.length
5511
- });
5512
- return candidates;
5513
- }
5514
- function scanAllSkillRoots(skillRoots) {
5515
- const allCandidates = [];
5516
- for (const root of skillRoots) {
5517
- const candidates = scanSkillRoot(root);
5518
- allCandidates.push(...candidates);
5519
- }
5520
- logger5.info("Skill discovery complete", {
5521
- rootsScanned: skillRoots.length,
5522
- totalCandidates: allCandidates.length
5523
- });
5524
- return allCandidates;
5525
- }
5526
-
5527
- // src/skills/activation.ts
5528
- import { readFileSync as readFileSync3, realpathSync } from "fs";
5529
- import { resolve as resolve2, relative, isAbsolute } from "path";
5530
- import matter2 from "gray-matter";
5531
- import { z as z3 } from "zod";
5532
-
5533
- // src/skills/trust.ts
5534
- var SCRIPT_PATH_PREFIX = "scripts/";
5535
- var SCRIPT_PATH_EXACT = "scripts";
5536
- function normalizeRootConfig(root) {
5537
- if (typeof root === "string") {
5538
- return { path: root, trust: "untrusted" };
5539
- }
5540
- return root;
5541
- }
5542
- function isScriptResource(resourcePath) {
5543
- let normalized = resourcePath.trim().replace(/\\/g, "/");
5544
- normalized = normalized.replace(/\/+/g, "/");
5545
- while (normalized.startsWith("./")) {
5546
- normalized = normalized.slice(2);
5547
- }
5548
- const lower = normalized.toLowerCase();
5549
- return lower === SCRIPT_PATH_EXACT || lower.startsWith(SCRIPT_PATH_PREFIX);
5550
- }
5551
- function evaluateTrustPolicy(resourcePath, trustLevel, allowUntrustedScripts = false) {
5552
- if (!isScriptResource(resourcePath)) {
5553
- return {
5554
- allowed: true,
5555
- reason: "not-script" /* NOT_SCRIPT */,
5556
- message: "Resource is not a script \u2014 no trust check required"
5557
- };
5558
- }
5559
- switch (trustLevel) {
5560
- case "workspace":
5561
- return {
5562
- allowed: true,
5563
- reason: "workspace-trust" /* WORKSPACE_TRUST */,
5564
- message: "Script allowed \u2014 skill root has workspace trust"
5565
- };
5566
- case "trusted":
5567
- return {
5568
- allowed: true,
5569
- reason: "trusted-root" /* TRUSTED_ROOT */,
5570
- message: "Script allowed \u2014 skill root is explicitly trusted"
5571
- };
5572
- case "untrusted":
5573
- if (allowUntrustedScripts) {
5574
- return {
5575
- allowed: true,
5576
- reason: "untrusted-script-allowed-override" /* UNTRUSTED_SCRIPT_ALLOWED */,
5577
- message: "Script from untrusted root allowed via allowUntrustedScripts override"
5578
- };
5579
- }
5580
- return {
5581
- allowed: false,
5582
- reason: "untrusted-script-denied" /* UNTRUSTED_SCRIPT_DENIED */,
5583
- message: `Script access denied \u2014 skill root is untrusted. Scripts from untrusted roots are blocked by default for security. To allow, set 'allowUntrustedScripts: true' in SkillRegistryConfig or promote the skill root to 'trusted' or 'workspace' trust level.`
5584
- };
5585
- default:
5586
- return {
5587
- allowed: false,
5588
- reason: "unknown-trust-level" /* UNKNOWN_TRUST_LEVEL */,
5589
- message: `Script access denied \u2014 trust level "${trustLevel}" is unknown and is treated as untrusted for security.`
5590
- };
5591
- }
5592
- }
5593
-
5594
- // src/skills/activation.ts
5595
- var logger6 = createLogger("agentforge:core:skills:activation", { level: "info" /* INFO */ });
5596
- var activateSkillSchema = z3.object({
5597
- name: z3.string().describe('The name of the skill to activate (e.g., "code-review")')
5598
- });
5599
- var readSkillResourceSchema = z3.object({
5600
- name: z3.string().describe("The name of the skill that owns the resource"),
5601
- path: z3.string().describe('Relative path to the resource file within the skill directory (e.g., "references/GUIDE.md", "scripts/setup.sh")')
5602
- });
5603
- function resolveResourcePath(skillPath, resourcePath) {
5604
- if (isAbsolute(resourcePath)) {
5605
- return { success: false, error: "Absolute resource paths are not allowed" };
5606
- }
5607
- const segments = resourcePath.split(/[/\\]/);
5608
- if (segments.some((seg) => seg === "..")) {
5609
- return { success: false, error: "Path traversal is not allowed \u2014 resource paths must stay within the skill directory" };
5610
- }
5611
- const resolvedPath = resolve2(skillPath, resourcePath);
5612
- const resolvedSkillPath = resolve2(skillPath);
5613
- const rel = relative(resolvedSkillPath, resolvedPath);
5614
- if (rel.startsWith("..") || resolve2(resolvedSkillPath, rel) !== resolvedPath) {
5615
- return { success: false, error: "Path traversal is not allowed \u2014 resource paths must stay within the skill directory" };
5616
- }
5617
- try {
5618
- const realSkillRoot = realpathSync(resolvedSkillPath);
5619
- const realTarget = realpathSync(resolvedPath);
5620
- const realRel = relative(realSkillRoot, realTarget);
5621
- if (realRel.startsWith("..") || isAbsolute(realRel)) {
5622
- return { success: false, error: "Symlink target escapes the skill directory \u2014 access denied" };
5623
- }
5624
- } catch {
5625
- }
5626
- return { success: true, resolvedPath };
5627
- }
5628
- function createActivateSkillTool(registry) {
5629
- return new ToolBuilder().name("activate-skill").description(
5630
- "Activate an Agent Skill by name, loading its full instructions. Returns the complete SKILL.md body content for the named skill. Use this when you see a relevant skill in <available_skills> and want to follow its instructions."
5631
- ).category("skills" /* SKILLS */).tags(["skill", "activation", "agent-skills"]).schema(activateSkillSchema).implement(async ({ name }) => {
5632
- const skill = registry.get(name);
5633
- if (!skill) {
5634
- const availableNames = registry.getNames();
5635
- const suggestion = availableNames.length > 0 ? ` Available skills: ${availableNames.join(", ")}` : " No skills are currently registered.";
5636
- const errorMsg = `Skill "${name}" not found.${suggestion}`;
5637
- logger6.warn("Skill activation failed \u2014 not found", { name, availableCount: availableNames.length });
5638
- return errorMsg;
5639
- }
5640
- const skillMdPath = resolve2(skill.skillPath, "SKILL.md");
5641
- try {
5642
- const content = readFileSync3(skillMdPath, "utf-8");
5643
- const body = extractBody(content);
5644
- logger6.info("Skill activated", {
5645
- name: skill.metadata.name,
5646
- skillPath: skill.skillPath,
5647
- bodyLength: body.length
5648
- });
5649
- registry.emitEvent("skill:activated" /* SKILL_ACTIVATED */, {
5650
- name: skill.metadata.name,
5651
- skillPath: skill.skillPath,
5652
- bodyLength: body.length
5653
- });
5654
- return body;
5655
- } catch (error) {
5656
- const errorMsg = `Failed to read skill "${name}" instructions: ${error instanceof Error ? error.message : String(error)}`;
5657
- logger6.error("Skill activation failed \u2014 read error", {
5658
- name,
5659
- skillPath: skill.skillPath,
5660
- error: error instanceof Error ? error.message : String(error)
5661
- });
5662
- return errorMsg;
5663
- }
5664
- }).build();
5665
- }
5666
- function createReadSkillResourceTool(registry) {
5667
- return new ToolBuilder().name("read-skill-resource").description(
5668
- "Read a resource file from an activated Agent Skill. Returns the content of a file within the skill directory (e.g., references/, scripts/, assets/). The path must be relative to the skill root and cannot traverse outside it."
5669
- ).category("skills" /* SKILLS */).tags(["skill", "resource", "agent-skills"]).schema(readSkillResourceSchema).implement(async ({ name, path: resourcePath }) => {
5670
- const skill = registry.get(name);
5671
- if (!skill) {
5672
- const availableNames = registry.getNames();
5673
- const suggestion = availableNames.length > 0 ? ` Available skills: ${availableNames.join(", ")}` : " No skills are currently registered.";
5674
- const errorMsg = `Skill "${name}" not found.${suggestion}`;
5675
- logger6.warn("Skill resource load failed \u2014 skill not found", { name, resourcePath });
5676
- return errorMsg;
5677
- }
5678
- const pathResult = resolveResourcePath(skill.skillPath, resourcePath);
5679
- if (!pathResult.success) {
5680
- logger6.warn("Skill resource load blocked \u2014 path traversal", {
5681
- name,
5682
- resourcePath,
5683
- error: pathResult.error
5684
- });
5685
- return pathResult.error;
5686
- }
5687
- const policyDecision = evaluateTrustPolicy(
5688
- resourcePath,
5689
- skill.trustLevel,
5690
- registry.getAllowUntrustedScripts()
5691
- );
5692
- if (!policyDecision.allowed) {
5693
- logger6.warn("Skill resource load blocked \u2014 trust policy", {
5694
- name,
5695
- resourcePath,
5696
- trustLevel: skill.trustLevel,
5697
- reason: policyDecision.reason,
5698
- message: policyDecision.message
5699
- });
5700
- registry.emitEvent("trust:policy-denied" /* TRUST_POLICY_DENIED */, {
5701
- name: skill.metadata.name,
5702
- resourcePath,
5703
- trustLevel: skill.trustLevel,
5704
- reason: policyDecision.reason,
5705
- message: policyDecision.message
5706
- });
5707
- return policyDecision.message;
5708
- }
5709
- if (policyDecision.reason !== "not-script" /* NOT_SCRIPT */) {
5710
- logger6.info("Skill resource trust policy \u2014 allowed", {
5711
- name,
5712
- resourcePath,
5713
- trustLevel: skill.trustLevel,
5714
- reason: policyDecision.reason
5715
- });
5716
- registry.emitEvent("trust:policy-allowed" /* TRUST_POLICY_ALLOWED */, {
5717
- name: skill.metadata.name,
5718
- resourcePath,
5719
- trustLevel: skill.trustLevel,
5720
- reason: policyDecision.reason
5721
- });
5722
- }
5723
- try {
5724
- const content = readFileSync3(pathResult.resolvedPath, "utf-8");
5725
- logger6.info("Skill resource loaded", {
5726
- name: skill.metadata.name,
5727
- resourcePath,
5728
- resolvedPath: pathResult.resolvedPath,
5729
- contentLength: content.length
5730
- });
5731
- registry.emitEvent("skill:resource-loaded" /* SKILL_RESOURCE_LOADED */, {
5732
- name: skill.metadata.name,
5733
- resourcePath,
5734
- resolvedPath: pathResult.resolvedPath,
5735
- contentLength: content.length
5736
- });
5737
- return content;
5738
- } catch (error) {
5739
- const errorMsg = `Failed to read resource "${resourcePath}" from skill "${name}": ${error instanceof Error ? error.message : String(error)}`;
5740
- logger6.warn("Skill resource load failed \u2014 file not found or unreadable", {
5741
- name,
5742
- resourcePath,
5743
- error: error instanceof Error ? error.message : String(error)
5744
- });
5745
- return errorMsg;
5746
- }
5747
- }).build();
5748
- }
5749
- function createSkillActivationTools(registry) {
5750
- return [
5751
- createActivateSkillTool(registry),
5752
- createReadSkillResourceTool(registry)
5753
- ];
5754
- }
5755
- function extractBody(content) {
5756
- return matter2(content).content.trim();
5757
- }
5758
-
5759
- // src/skills/registry.ts
5760
- import { resolve as resolvePath } from "path";
5761
- var logger7 = createLogger("agentforge:core:skills:registry", { level: "info" /* INFO */ });
5762
- var SkillRegistry = class {
5763
- skills = /* @__PURE__ */ new Map();
5764
- eventHandlers = /* @__PURE__ */ new Map();
5765
- config;
5766
- scanErrors = [];
5767
- /** Maps resolved root paths → trust levels for skill trust assignment */
5768
- rootTrustMap = /* @__PURE__ */ new Map();
5769
- /**
5770
- * Create a SkillRegistry and immediately scan configured roots for skills.
5771
- *
5772
- * @param config - Registry configuration with skill root paths
5773
- *
5774
- * @example
5775
- * ```ts
5776
- * const registry = new SkillRegistry({
5777
- * skillRoots: ['.agentskills', '~/.agentskills', './project-skills'],
5778
- * });
5779
- * console.log(`Discovered ${registry.size()} skills`);
5780
- * ```
5781
- */
5782
- constructor(config) {
5783
- this.config = config;
5784
- this.discover();
5785
- }
5786
- /**
5787
- * Scan all configured roots and populate the registry.
5788
- *
5789
- * Called automatically during construction. Can be called again
5790
- * to re-scan (clears existing skills first).
5791
- */
5792
- discover() {
5793
- this.skills.clear();
5794
- this.scanErrors = [];
5795
- this.rootTrustMap.clear();
5796
- const normalizedRoots = this.config.skillRoots.map(normalizeRootConfig);
5797
- const plainPaths = normalizedRoots.map((r) => r.path);
5798
- for (const root of normalizedRoots) {
5799
- const resolvedPath = resolvePath(expandHome(root.path));
5800
- this.rootTrustMap.set(resolvedPath, root.trust);
5801
- }
5802
- const candidates = scanAllSkillRoots(plainPaths);
5803
- let successCount = 0;
5804
- let warningCount = 0;
5805
- for (const candidate of candidates) {
5806
- const result = parseSkillContent(candidate.content, candidate.dirName);
5807
- if (!result.success) {
5808
- warningCount++;
5809
- this.scanErrors.push({
5810
- path: candidate.skillPath,
5811
- error: result.error || "Unknown parse error"
5812
- });
5813
- this.emit("skill:warning" /* SKILL_WARNING */, {
5814
- skillPath: candidate.skillPath,
5815
- rootPath: candidate.rootPath,
5816
- error: result.error
5817
- });
5818
- logger7.warn("Skipping invalid skill", {
5819
- skillPath: candidate.skillPath,
5820
- error: result.error
5821
- });
5822
- continue;
5823
- }
5824
- const skill = {
5825
- metadata: result.metadata,
5826
- skillPath: candidate.skillPath,
5827
- rootPath: candidate.rootPath,
5828
- trustLevel: this.rootTrustMap.get(candidate.rootPath) ?? "untrusted"
5829
- };
5830
- if (this.skills.has(skill.metadata.name)) {
5831
- const existing = this.skills.get(skill.metadata.name);
5832
- warningCount++;
5833
- const warningMsg = `Duplicate skill name "${skill.metadata.name}" from "${candidate.rootPath}" \u2014 keeping version from "${existing.rootPath}" (first root takes precedence)`;
5834
- this.scanErrors.push({
5835
- path: candidate.skillPath,
5836
- error: warningMsg
5837
- });
5838
- this.emit("skill:warning" /* SKILL_WARNING */, {
5839
- skillPath: candidate.skillPath,
5840
- rootPath: candidate.rootPath,
5841
- duplicateOf: existing.skillPath,
5842
- error: warningMsg
5843
- });
5844
- logger7.warn("Duplicate skill name, keeping first", {
5845
- name: skill.metadata.name,
5846
- kept: existing.skillPath,
5847
- skipped: candidate.skillPath
5848
- });
5849
- continue;
5850
- }
5851
- this.skills.set(skill.metadata.name, skill);
5852
- successCount++;
5853
- this.emit("skill:discovered" /* SKILL_DISCOVERED */, skill);
5854
- logger7.debug("Skill discovered", {
5855
- name: skill.metadata.name,
5856
- description: skill.metadata.description.slice(0, 80),
5857
- skillPath: skill.skillPath
5858
- });
5859
- }
5860
- logger7.info("Skill registry populated", {
5861
- rootsScanned: this.config.skillRoots.length,
5862
- skillsDiscovered: successCount,
5863
- warnings: warningCount
5864
- });
5865
- }
5866
- // ─── Query API (parallel to ToolRegistry) ──────────────────────────────
5867
- /**
5868
- * Get a skill by name.
5869
- *
5870
- * @param name - The skill name
5871
- * @returns The skill, or undefined if not found
5872
- *
5873
- * @example
5874
- * ```ts
5875
- * const skill = registry.get('code-review');
5876
- * if (skill) {
5877
- * console.log(skill.metadata.description);
5878
- * }
5879
- * ```
5880
- */
5881
- get(name) {
5882
- return this.skills.get(name);
5883
- }
5884
- /**
5885
- * Get all discovered skills.
5886
- *
5887
- * @returns Array of all skills
5888
- *
5889
- * @example
5890
- * ```ts
5891
- * const allSkills = registry.getAll();
5892
- * console.log(`Total skills: ${allSkills.length}`);
5893
- * ```
5894
- */
5895
- getAll() {
5896
- return Array.from(this.skills.values());
5897
- }
5898
- /**
5899
- * Check if a skill exists in the registry.
5900
- *
5901
- * @param name - The skill name
5902
- * @returns True if the skill exists
5903
- *
5904
- * @example
5905
- * ```ts
5906
- * if (registry.has('code-review')) {
5907
- * console.log('Skill available!');
5908
- * }
5909
- * ```
5910
- */
5911
- has(name) {
5912
- return this.skills.has(name);
5913
- }
5914
- /**
5915
- * Get the number of discovered skills.
5916
- *
5917
- * @returns Number of skills in the registry
5918
- *
5919
- * @example
5920
- * ```ts
5921
- * console.log(`Registry has ${registry.size()} skills`);
5922
- * ```
5923
- */
5924
- size() {
5925
- return this.skills.size;
5926
- }
5927
- /**
5928
- * Get all skill names.
5929
- *
5930
- * @returns Array of skill names
5931
- */
5932
- getNames() {
5933
- return Array.from(this.skills.keys());
5934
- }
5935
- /**
5936
- * Get errors/warnings from the last scan.
5937
- *
5938
- * Useful for diagnostics and observability.
5939
- *
5940
- * @returns Array of scan errors with paths
5941
- */
5942
- getScanErrors() {
5943
- return this.scanErrors;
5944
- }
5945
- /**
5946
- * Check whether untrusted script access is allowed via config override.
5947
- *
5948
- * Used by activation tools to pass the override flag to trust policy checks.
5949
- *
5950
- * @returns True if `allowUntrustedScripts` is set in config
5951
- */
5952
- getAllowUntrustedScripts() {
5953
- return this.config.allowUntrustedScripts ?? false;
5954
- }
5955
- /**
5956
- * Get the `allowed-tools` list for a skill.
5957
- *
5958
- * Returns the `allowedTools` array from the skill's frontmatter metadata,
5959
- * enabling agents to filter their tool set based on what the skill expects.
5960
- *
5961
- * @param name - The skill name
5962
- * @returns Array of allowed tool names, or undefined if skill not found or field not set
5963
- *
5964
- * @example
5965
- * ```ts
5966
- * const allowed = registry.getAllowedTools('code-review');
5967
- * if (allowed) {
5968
- * const filteredTools = allTools.filter(t => allowed.includes(t.name));
5969
- * }
5970
- * ```
5971
- */
5972
- getAllowedTools(name) {
5973
- const skill = this.skills.get(name);
5974
- return skill?.metadata.allowedTools;
5975
- }
5976
- // ─── Prompt Generation ─────────────────────────────────────────────────
5977
- /**
5978
- * Generate an `<available_skills>` XML block for system prompt injection.
5979
- *
5980
- * Returns an empty string when:
5981
- * - `config.enabled` is `false` (default) — agents operate with unmodified prompts
5982
- * - No skills match the filter criteria
5983
- *
5984
- * The output composes naturally with `toolRegistry.generatePrompt()` —
5985
- * simply concatenate both into the system prompt.
5986
- *
5987
- * @param options - Optional filtering (subset of skill names)
5988
- * @returns XML string or empty string
5989
- *
5990
- * @example
5991
- * ```ts
5992
- * // All skills
5993
- * const xml = registry.generatePrompt();
5994
- *
5995
- * // Subset for a focused agent
5996
- * const xml = registry.generatePrompt({ skills: ['code-review', 'testing'] });
5997
- *
5998
- * // Compose with tool prompt
5999
- * const systemPrompt = [
6000
- * toolRegistry.generatePrompt(),
6001
- * skillRegistry.generatePrompt(),
6002
- * ].filter(Boolean).join('\n\n');
6003
- * ```
6004
- */
6005
- generatePrompt(options) {
6006
- if (!this.config.enabled) {
6007
- logger7.debug("Skill prompt generation skipped (disabled)", {
6008
- enabled: this.config.enabled ?? false
6009
- });
6010
- return "";
6011
- }
6012
- let skills = this.getAll();
6013
- if (options?.skills && options.skills.length > 0) {
6014
- const requested = new Set(options.skills);
6015
- skills = skills.filter((s) => requested.has(s.metadata.name));
6016
- }
6017
- if (this.config.maxDiscoveredSkills !== void 0 && this.config.maxDiscoveredSkills >= 0) {
6018
- skills = skills.slice(0, this.config.maxDiscoveredSkills);
6019
- }
6020
- if (skills.length === 0) {
6021
- logger7.debug("Skill prompt generation produced empty result", {
6022
- totalDiscovered: this.size(),
6023
- filterApplied: !!(options?.skills && options.skills.length > 0),
6024
- maxCap: this.config.maxDiscoveredSkills
6025
- });
6026
- return "";
6027
- }
6028
- const skillEntries = skills.map((skill) => {
6029
- const lines = [
6030
- " <skill>",
6031
- ` <name>${escapeXml(skill.metadata.name)}</name>`,
6032
- ` <description>${escapeXml(skill.metadata.description)}</description>`,
6033
- ` <location>${escapeXml(skill.skillPath)}</location>`,
6034
- " </skill>"
6035
- ];
6036
- return lines.join("\n");
6037
- });
6038
- const xml = `<available_skills>
6039
- ${skillEntries.join("\n")}
6040
- </available_skills>`;
6041
- const estimatedTokens = Math.ceil(xml.length / 4);
6042
- logger7.info("Skill prompt generated", {
6043
- skillCount: skills.length,
6044
- totalDiscovered: this.size(),
6045
- filterApplied: !!(options?.skills && options.skills.length > 0),
6046
- maxCap: this.config.maxDiscoveredSkills,
6047
- estimatedTokens,
6048
- xmlLength: xml.length
6049
- });
6050
- return xml;
6051
- }
6052
- // ─── Event System ──────────────────────────────────────────────────────
6053
- /**
6054
- * Register an event handler.
6055
- *
6056
- * @param event - The event to listen for
6057
- * @param handler - The handler function
6058
- *
6059
- * @example
6060
- * ```ts
6061
- * registry.on(SkillRegistryEvent.SKILL_DISCOVERED, (skill) => {
6062
- * console.log('Found skill:', skill.metadata.name);
6063
- * });
6064
- * ```
6065
- */
6066
- on(event, handler) {
6067
- if (!this.eventHandlers.has(event)) {
6068
- this.eventHandlers.set(event, /* @__PURE__ */ new Set());
6069
- }
6070
- this.eventHandlers.get(event).add(handler);
6071
- }
6072
- /**
6073
- * Unregister an event handler.
6074
- *
6075
- * @param event - The event to stop listening for
6076
- * @param handler - The handler function to remove
6077
- */
6078
- off(event, handler) {
6079
- const handlers = this.eventHandlers.get(event);
6080
- if (handlers) {
6081
- handlers.delete(handler);
6082
- }
6083
- }
6084
- /**
6085
- * Emit an event to all registered handlers.
6086
- *
6087
- * @param event - The event to emit
6088
- * @param data - The event data
6089
- * @private
6090
- */
6091
- emit(event, data) {
6092
- const handlers = this.eventHandlers.get(event);
6093
- if (handlers) {
6094
- handlers.forEach((handler) => {
6095
- try {
6096
- handler(data);
6097
- } catch (error) {
6098
- logger7.error("Skill event handler error", {
6099
- event,
6100
- error: error instanceof Error ? error.message : String(error),
6101
- stack: error instanceof Error ? error.stack : void 0
6102
- });
6103
- }
6104
- });
6105
- }
6106
- }
6107
- /**
6108
- * Emit an event (public API for activation tools).
6109
- *
6110
- * Used by skill activation tools to emit `skill:activated` and
6111
- * `skill:resource-loaded` events through the registry's event system.
6112
- *
6113
- * @param event - The event to emit
6114
- * @param data - The event data
6115
- */
6116
- emitEvent(event, data) {
6117
- this.emit(event, data);
6118
- }
6119
- // ─── Tool Integration ────────────────────────────────────────────────
6120
- /**
6121
- * Create activation tools pre-wired to this registry instance.
6122
- *
6123
- * Returns `activate-skill` and `read-skill-resource` tools that
6124
- * agents can use to load skill instructions and resources on demand.
6125
- *
6126
- * @returns Array of [activate-skill, read-skill-resource] tools
6127
- *
6128
- * @example
6129
- * ```ts
6130
- * const agent = createReActAgent({
6131
- * model: llm,
6132
- * tools: [
6133
- * ...toolRegistry.toLangChainTools(),
6134
- * ...skillRegistry.toActivationTools(),
6135
- * ],
6136
- * });
6137
- * ```
6138
- */
6139
- toActivationTools() {
6140
- return createSkillActivationTools(this);
6141
- }
6142
- };
6143
- function escapeXml(str) {
6144
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
6145
- }
6146
5311
  export {
6147
5312
  AgentError,
6148
5313
  AlertManager,
@@ -6161,8 +5326,6 @@ export {
6161
5326
  MissingDescriptionError,
6162
5327
  Profiler,
6163
5328
  RegistryEvent,
6164
- SkillRegistry,
6165
- SkillRegistryEvent,
6166
5329
  TimeoutError,
6167
5330
  ToolBuilder,
6168
5331
  ToolCategory,
@@ -6172,7 +5335,6 @@ export {
6172
5335
  ToolNameSchema,
6173
5336
  ToolRegistry,
6174
5337
  ToolRelationsSchema,
6175
- TrustPolicyReason,
6176
5338
  batch,
6177
5339
  broadcast,
6178
5340
  cache,
@@ -6186,7 +5348,6 @@ export {
6186
5348
  composeWithOptions,
6187
5349
  conditional,
6188
5350
  configureLangSmith,
6189
- createActivateSkillTool,
6190
5351
  createAlertManager,
6191
5352
  createApprovalRequiredInterrupt,
6192
5353
  createAuditLogger,
@@ -6215,13 +5376,11 @@ export {
6215
5376
  createParallelWorkflow,
6216
5377
  createProfiler,
6217
5378
  createProgressTracker,
6218
- createReadSkillResourceTool,
6219
5379
  createSSEFormatter,
6220
5380
  createSequentialWorkflow,
6221
5381
  createSharedCache,
6222
5382
  createSharedConcurrencyController,
6223
5383
  createSharedRateLimiter,
6224
- createSkillActivationTools,
6225
5384
  createSqliteCheckpointer,
6226
5385
  createStateAnnotation,
6227
5386
  createSubgraph,
@@ -6232,8 +5391,6 @@ export {
6232
5391
  createToolUnsafe,
6233
5392
  createWebSocketHandler,
6234
5393
  development,
6235
- evaluateTrustPolicy,
6236
- expandHome,
6237
5394
  filter,
6238
5395
  formatAgentResumedEvent,
6239
5396
  formatAgentWaitingEvent,
@@ -6253,26 +5410,20 @@ export {
6253
5410
  isCustomInterrupt,
6254
5411
  isHumanRequestInterrupt,
6255
5412
  isMemoryCheckpointer,
6256
- isScriptResource,
6257
5413
  isTracingEnabled,
6258
5414
  loadPrompt,
6259
5415
  map,
6260
5416
  merge,
6261
5417
  mergeState,
6262
- normalizeRootConfig,
6263
5418
  parallel,
6264
5419
  parseSSEEvent,
6265
- parseSkillContent,
6266
5420
  presets,
6267
5421
  production,
6268
5422
  reduce,
6269
5423
  renderTemplate,
6270
- resolveResourcePath,
6271
5424
  retry,
6272
5425
  safeValidateSchemaDescriptions,
6273
5426
  sanitizeValue,
6274
- scanAllSkillRoots,
6275
- scanSkillRoot,
6276
5427
  sendMessage,
6277
5428
  sequential,
6278
5429
  sequentialBuilder,
@@ -6284,9 +5435,6 @@ export {
6284
5435
  toLangChainTools,
6285
5436
  toolBuilder,
6286
5437
  validateSchemaDescriptions,
6287
- validateSkillDescription,
6288
- validateSkillName,
6289
- validateSkillNameMatchesDir,
6290
5438
  validateState,
6291
5439
  validateTool,
6292
5440
  validateToolMetadata,