@cuylabs/agent-core 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/{chunk-GFTW23FV.js → chunk-BGG2HVIR.js} +4 -2
  2. package/dist/{chunk-TOTDGK3P.js → chunk-CSR75JVC.js} +4 -5
  3. package/dist/{chunk-ICZ66572.js → chunk-CZ5XOVDV.js} +40 -9
  4. package/dist/{chunk-2O4MCSQS.js → chunk-FYC33XFI.js} +31 -10
  5. package/dist/{chunk-WBPOZ7CL.js → chunk-HNEI7JVE.js} +114 -38
  6. package/dist/{chunk-SPILYYDF.js → chunk-I7EJGKUP.js} +79 -7
  7. package/dist/{chunk-SSFBF3US.js → chunk-JPBFAQNS.js} +7 -12
  8. package/dist/{chunk-5FMSGQVX.js → chunk-JZRLCTSD.js} +8 -2
  9. package/dist/{chunk-V4RFNEET.js → chunk-MLTJHUVG.js} +34 -16
  10. package/dist/{chunk-QAL3OMI3.js → chunk-MO3N6M32.js} +4 -1
  11. package/dist/{chunk-CMYN2RCB.js → chunk-NWQUZWLT.js} +13 -7
  12. package/dist/{chunk-MXAP4UG6.js → chunk-QJV5XPPS.js} +238 -86
  13. package/dist/{chunk-T4UIX5D7.js → chunk-S6AKEPAX.js} +9 -3
  14. package/dist/{chunk-N3VX7FEE.js → chunk-STDJYXYK.js} +1 -4
  15. package/dist/{chunk-6HZBHFOL.js → chunk-TPZ37IWI.js} +10 -1
  16. package/dist/{chunk-NDZWXCBZ.js → chunk-TZ4VA4VX.js} +33 -11
  17. package/dist/chunk-US7S4FYW.js +610 -0
  18. package/dist/{chunk-RN6WZEUF.js → chunk-WI5JFEAI.js} +71 -36
  19. package/dist/{chunk-5NVVNXPQ.js → chunk-ZKEC7MFQ.js} +5 -30
  20. package/dist/dispatch/index.d.ts +5 -3
  21. package/dist/dispatch/index.js +3 -3
  22. package/dist/execution/index.d.ts +6 -4
  23. package/dist/execution/index.js +7 -7
  24. package/dist/index.d.ts +8 -5
  25. package/dist/index.js +119 -116
  26. package/dist/inference/errors/index.js +1 -1
  27. package/dist/inference/index.d.ts +6 -4
  28. package/dist/inference/index.js +6 -6
  29. package/dist/{instance-DzPiv6EK.d.ts → instance-N5VhcNT2.d.ts} +45 -7
  30. package/dist/logger/index.js +1 -1
  31. package/dist/mcp/index.d.ts +116 -3
  32. package/dist/mcp/index.js +6 -2
  33. package/dist/middleware/index.d.ts +5 -3
  34. package/dist/middleware/index.js +3 -3
  35. package/dist/{model-messages-CJfwfzGe.d.ts → model-messages-DnsiSiZj.d.ts} +1 -1
  36. package/dist/models/index.js +2 -2
  37. package/dist/models/reasoning/index.js +2 -2
  38. package/dist/plugin/index.d.ts +4 -2
  39. package/dist/plugin/index.js +1 -1
  40. package/dist/profiles/index.d.ts +4 -2
  41. package/dist/profiles/index.js +1 -1
  42. package/dist/prompt/index.d.ts +5 -3
  43. package/dist/prompt/index.js +2 -2
  44. package/dist/safety/index.d.ts +5 -3
  45. package/dist/safety/index.js +1 -1
  46. package/dist/skill/index.d.ts +5 -3
  47. package/dist/skill/index.js +2 -2
  48. package/dist/storage/index.d.ts +5 -3
  49. package/dist/storage/index.js +1 -1
  50. package/dist/subagents/index.d.ts +4 -2
  51. package/dist/subagents/index.js +4 -4
  52. package/dist/team/index.d.ts +5 -3
  53. package/dist/team/index.js +1 -1
  54. package/dist/tool/index.d.ts +5 -3
  55. package/dist/tool/index.js +2 -2
  56. package/dist/{types-Bj_J8u_W.d.ts → types-DMjoFKKv.d.ts} +55 -7
  57. package/package.json +1 -6
  58. package/dist/chunk-ROTGCYDW.js +0 -221
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createSkillRegistry,
3
3
  emptySkillRegistry
4
- } from "./chunk-SPILYYDF.js";
4
+ } from "./chunk-I7EJGKUP.js";
5
5
  import {
6
6
  extractModelId,
7
7
  extractProvider
@@ -311,7 +311,9 @@ function formatInstructions(files, basePath) {
311
311
  for (const file of files) {
312
312
  const displayPath = basePath ? file.path.replace(basePath + sep, "").replace(basePath, "") : basename2(file.path);
313
313
  blocks.push("");
314
- blocks.push(`<instructions source="${displayPath}" scope="${file.source}">`);
314
+ blocks.push(
315
+ `<instructions source="${displayPath}" scope="${file.source}">`
316
+ );
315
317
  blocks.push(file.content);
316
318
  blocks.push("</instructions>");
317
319
  }
@@ -16,7 +16,9 @@ ${skillList}
16
16
 
17
17
  Only load a skill when the current task clearly matches its description. Skills provide detailed workflows, reference material, and scripts.`,
18
18
  parameters: z.object({
19
- name: z.string().describe("The name of the skill to load (must match one of the available skills)")
19
+ name: z.string().describe(
20
+ "The name of the skill to load (must match one of the available skills)"
21
+ )
20
22
  }),
21
23
  execute: async ({ name }) => {
22
24
  const content = await registry.loadContent(name);
@@ -78,10 +80,7 @@ function createSkillResourceTool(registry) {
78
80
  }
79
81
  function createSkillTools(registry) {
80
82
  if (registry.size === 0) return [];
81
- return [
82
- createSkillTool(registry),
83
- createSkillResourceTool(registry)
84
- ];
83
+ return [createSkillTool(registry), createSkillResourceTool(registry)];
85
84
  }
86
85
 
87
86
  export {
@@ -44,7 +44,8 @@ function serializeMessage(message) {
44
44
  if ("tokens" in message) serialized.tokens = message.tokens;
45
45
  if ("cost" in message) serialized.cost = message.cost;
46
46
  if ("error" in message) serialized.error = message.error;
47
- if ("toolCalls" in message && message.toolCalls) serialized.toolCalls = message.toolCalls;
47
+ if ("toolCalls" in message && message.toolCalls)
48
+ serialized.toolCalls = message.toolCalls;
48
49
  }
49
50
  if (message.role === "tool") {
50
51
  if ("toolCallId" in message) serialized.toolCallId = message.toolCallId;
@@ -163,7 +164,9 @@ function getLeafId(entries) {
163
164
  const hasChildren = /* @__PURE__ */ new Set();
164
165
  for (const children of childMap.values()) {
165
166
  for (const child of children) {
166
- const entry = entries.find((e) => e.type !== "header" && e.id === child);
167
+ const entry = entries.find(
168
+ (e) => e.type !== "header" && e.id === child
169
+ );
167
170
  if (entry && entry.type !== "header") {
168
171
  const parentId = entry.parentId;
169
172
  if (parentId) hasChildren.add(parentId);
@@ -281,7 +284,15 @@ var MemoryStorage = class {
281
284
  };
282
285
 
283
286
  // src/storage/file/helpers.ts
284
- import { appendFile, mkdir, readFile, readdir, stat, unlink, writeFile } from "fs/promises";
287
+ import {
288
+ appendFile,
289
+ mkdir,
290
+ readFile,
291
+ readdir,
292
+ stat,
293
+ unlink,
294
+ writeFile
295
+ } from "fs/promises";
285
296
  import { existsSync } from "fs";
286
297
  import { basename, join } from "path";
287
298
  async function ensureStorageDirectory(directory) {
@@ -391,7 +402,10 @@ var FileStorage = class {
391
402
  if (this.useCache && this.cache.has(sessionId)) {
392
403
  return this.cache.get(sessionId);
393
404
  }
394
- const entries = await loadEntriesFromDisk(this.getPath(sessionId), sessionId);
405
+ const entries = await loadEntriesFromDisk(
406
+ this.getPath(sessionId),
407
+ sessionId
408
+ );
395
409
  if (this.useCache) {
396
410
  this.cache.set(sessionId, entries);
397
411
  }
@@ -448,9 +462,15 @@ var FileStorage = class {
448
462
  async list() {
449
463
  await this.ensureDir();
450
464
  const infos = [];
451
- for (const sessionId of await listSessionIds(this.directory, this.extension)) {
465
+ for (const sessionId of await listSessionIds(
466
+ this.directory,
467
+ this.extension
468
+ )) {
452
469
  try {
453
- const info = extractSessionInfo(await this.getEntries(sessionId), this.getPath(sessionId));
470
+ const info = extractSessionInfo(
471
+ await this.getEntries(sessionId),
472
+ this.getPath(sessionId)
473
+ );
454
474
  if (info) {
455
475
  infos.push(info);
456
476
  }
@@ -490,7 +510,10 @@ function getDataDir(appName = "cuylabs") {
490
510
  return join2(homedir(), `.${appName}`);
491
511
  }
492
512
  if (platform === "win32") {
493
- return join2(process.env.APPDATA || join2(homedir(), "AppData", "Roaming"), appName);
513
+ return join2(
514
+ process.env.APPDATA || join2(homedir(), "AppData", "Roaming"),
515
+ appName
516
+ );
494
517
  }
495
518
  const xdgData = process.env.XDG_DATA_HOME || join2(homedir(), ".local", "share");
496
519
  return join2(xdgData, appName);
@@ -575,7 +598,11 @@ var SessionManager = class {
575
598
  if (!this.currentSessionId) {
576
599
  throw new Error("No session loaded");
577
600
  }
578
- const entry = createMessageEntry(message, this.currentLeafId, this.idsCache);
601
+ const entry = createMessageEntry(
602
+ message,
603
+ this.currentLeafId,
604
+ this.idsCache
605
+ );
579
606
  await this.storage.append(this.currentSessionId, entry);
580
607
  this.entriesCache.push(entry);
581
608
  this.idsCache.add(entry.id);
@@ -690,7 +717,11 @@ var SessionManager = class {
690
717
  if (!this.currentSessionId) {
691
718
  throw new Error("No session loaded");
692
719
  }
693
- const entry = createMetadataEntry(updates, this.currentLeafId, this.idsCache);
720
+ const entry = createMetadataEntry(
721
+ updates,
722
+ this.currentLeafId,
723
+ this.idsCache
724
+ );
694
725
  await this.storage.append(this.currentSessionId, entry);
695
726
  this.entriesCache.push(entry);
696
727
  this.idsCache.add(entry.id);
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  Profiles
3
- } from "./chunk-6HZBHFOL.js";
3
+ } from "./chunk-TPZ37IWI.js";
4
4
  import {
5
5
  createLocalDispatchRuntime
6
- } from "./chunk-SSFBF3US.js";
6
+ } from "./chunk-JPBFAQNS.js";
7
7
  import {
8
8
  Tool
9
9
  } from "./chunk-Q742PSH3.js";
@@ -168,7 +168,9 @@ Guidelines:
168
168
  }
169
169
  function toCompletedResult(record) {
170
170
  if (!record.result || !record.sessionId) {
171
- throw new Error(`Dispatch "${record.id}" did not produce a completed result.`);
171
+ throw new Error(
172
+ `Dispatch "${record.id}" did not produce a completed result.`
173
+ );
172
174
  }
173
175
  return {
174
176
  response: record.result.response,
@@ -200,7 +202,9 @@ function formatTerminalFailure(record) {
200
202
  );
201
203
  }
202
204
  return formatWaitErrorResult(
203
- new Error(`Subagent "${record.id}" is in unexpected state "${record.status}".`)
205
+ new Error(
206
+ `Subagent "${record.id}" is in unexpected state "${record.status}".`
207
+ )
204
208
  );
205
209
  }
206
210
  function createInvokeAgentTool(runtime, roles, options) {
@@ -238,7 +242,11 @@ function createInvokeAgentTool(runtime, roles, options) {
238
242
  );
239
243
  }
240
244
  if (isAsync) {
241
- return formatAsyncSpawnedResult(started.id, role.name, started.sessionId);
245
+ return formatAsyncSpawnedResult(
246
+ started.id,
247
+ role.name,
248
+ started.sessionId
249
+ );
242
250
  }
243
251
  try {
244
252
  const finished = await waitForTerminalDispatch(runtime, started.id);
@@ -377,7 +385,9 @@ function getConfiguredSubAgents(agent) {
377
385
  return installedSubAgents.get(agent)?.config;
378
386
  }
379
387
  function getInstalledSubAgentBackend(agent) {
380
- const backend = installedSubAgents.get(agent)?.backend;
388
+ const backend = installedSubAgents.get(
389
+ agent
390
+ )?.backend;
381
391
  return backend && backend !== "uninstalled" ? backend : void 0;
382
392
  }
383
393
  function clearInstalledSubAgents(agent) {
@@ -517,7 +527,9 @@ function parseSubAgentToolSpec(raw) {
517
527
  if (parts.length === 0) {
518
528
  return { mode: "inherit" };
519
529
  }
520
- const hasModified = parts.some((part) => part.startsWith("+") || part.startsWith("-"));
530
+ const hasModified = parts.some(
531
+ (part) => part.startsWith("+") || part.startsWith("-")
532
+ );
521
533
  if (hasModified) {
522
534
  return {
523
535
  mode: "modifiers",
@@ -553,7 +565,10 @@ function toSubAgentRole(parsed, resolvers = {}) {
553
565
  const toolSpec = parseSubAgentToolSpec(frontmatter.tools);
554
566
  if (toolSpec.mode === "explicit" || toolSpec.mode === "modifiers") {
555
567
  resolvedProfile = {
556
- ...resolvedProfile ?? { name: "custom", description: "Markdown-defined role" }
568
+ ...resolvedProfile ?? {
569
+ name: "custom",
570
+ description: "Markdown-defined role"
571
+ }
557
572
  };
558
573
  if (toolSpec.mode === "explicit") {
559
574
  resolvedProfile.allowTools = toolSpec.patterns;
@@ -643,7 +658,10 @@ function loadRoleDir(dir, source, resolvers, errors, onRole) {
643
658
  const content = readFileSync(filePath, "utf-8");
644
659
  const parsed = parseMarkdownSubAgentRole(content, filePath);
645
660
  if (!parsed) {
646
- errors.push({ path: filePath, error: "Missing required frontmatter (name, description)" });
661
+ errors.push({
662
+ path: filePath,
663
+ error: "Missing required frontmatter (name, description)"
664
+ });
647
665
  continue;
648
666
  }
649
667
  const role = toSubAgentRole(parsed, resolvers);
@@ -668,7 +686,10 @@ function loadRoleFile(filePath, source, resolvers, errors, onRole) {
668
686
  const content = readFileSync(filePath, "utf-8");
669
687
  const parsed = parseMarkdownSubAgentRole(content, filePath);
670
688
  if (!parsed) {
671
- errors.push({ path: filePath, error: "Missing required frontmatter (name, description)" });
689
+ errors.push({
690
+ path: filePath,
691
+ error: "Missing required frontmatter (name, description)"
692
+ });
672
693
  return null;
673
694
  }
674
695
  const role = toSubAgentRole(parsed, resolvers);
@@ -1,19 +1,17 @@
1
1
  import {
2
2
  Inference,
3
3
  buildModelCallContext
4
- } from "./chunk-CMYN2RCB.js";
4
+ } from "./chunk-NWQUZWLT.js";
5
5
  import {
6
- PRUNE_PROTECTED_TOOLS,
7
- accumulateUsage,
8
6
  currentScope,
9
7
  executeAgentToolCall,
10
8
  snapshotScope,
11
9
  streamWithinScope,
12
10
  withinScope
13
- } from "./chunk-5NVVNXPQ.js";
11
+ } from "./chunk-ZKEC7MFQ.js";
14
12
  import {
15
13
  LLMError
16
- } from "./chunk-N3VX7FEE.js";
14
+ } from "./chunk-STDJYXYK.js";
17
15
  import {
18
16
  extractModelId,
19
17
  extractProvider
@@ -23,7 +21,7 @@ import {
23
21
  } from "./chunk-FII65CN7.js";
24
22
  import {
25
23
  silentLogger
26
- } from "./chunk-T4UIX5D7.js";
24
+ } from "./chunk-S6AKEPAX.js";
27
25
 
28
26
  // src/execution/task/observer.ts
29
27
  function defaultAgentTaskCheckpointStrategy(input) {
@@ -321,13 +319,21 @@ function createAgentTaskRunner(agent, options = {}) {
321
319
  event,
322
320
  createdAt: turnState.updatedAt
323
321
  };
324
- await notifyObservers(baseObservers, async (observer) => {
325
- await observer.onCheckpoint?.(checkpoint);
326
- }, log);
322
+ await notifyObservers(
323
+ baseObservers,
324
+ async (observer) => {
325
+ await observer.onCheckpoint?.(checkpoint);
326
+ },
327
+ log
328
+ );
327
329
  };
328
- await notifyObservers(baseObservers, async (observer) => {
329
- await observer.onTaskStart?.(run, createSnapshot());
330
- }, log);
330
+ await notifyObservers(
331
+ baseObservers,
332
+ async (observer) => {
333
+ await observer.onTaskStart?.(run, createSnapshot());
334
+ },
335
+ log
336
+ );
331
337
  await emitCheckpoint("task-start");
332
338
  const activateCtx = baseObservers.find((o) => o.activateContext)?.activateContext?.bind(void 0, sessionId, executionId);
333
339
  try {
@@ -341,9 +347,13 @@ function createAgentTaskRunner(agent, options = {}) {
341
347
  toolCalls.push({ name: event.toolName, result: event.result });
342
348
  }
343
349
  const snapshot = createSnapshot();
344
- await notifyObservers(baseObservers, async (observer) => {
345
- await observer.onTaskEvent?.(run, event, snapshot);
346
- }, log);
350
+ await notifyObservers(
351
+ baseObservers,
352
+ async (observer) => {
353
+ await observer.onTaskEvent?.(run, event, snapshot);
354
+ },
355
+ log
356
+ );
347
357
  const checkpointReason = checkpointStrategy({
348
358
  run,
349
359
  event,
@@ -368,16 +378,28 @@ function createAgentTaskRunner(agent, options = {}) {
368
378
  usage: { ...turnState.usage },
369
379
  toolCalls
370
380
  };
371
- await notifyObservers(baseObservers, async (observer) => {
372
- await observer.onTaskComplete?.(run, result, createSnapshot());
373
- }, log);
381
+ await notifyObservers(
382
+ baseObservers,
383
+ async (observer) => {
384
+ await observer.onTaskComplete?.(run, result, createSnapshot());
385
+ },
386
+ log
387
+ );
374
388
  return result;
375
389
  } catch (error) {
376
390
  const normalizedError = error instanceof Error ? error : new Error(String(error));
377
391
  turnState = failAgentTurnState(turnState, normalizedError, nowIso());
378
- await notifyObservers(baseObservers, async (observer) => {
379
- await observer.onTaskError?.(run, normalizedError, createSnapshot());
380
- }, log);
392
+ await notifyObservers(
393
+ baseObservers,
394
+ async (observer) => {
395
+ await observer.onTaskError?.(
396
+ run,
397
+ normalizedError,
398
+ createSnapshot()
399
+ );
400
+ },
401
+ log
402
+ );
381
403
  await emitCheckpoint("task-error");
382
404
  throw normalizedError;
383
405
  }
@@ -633,6 +655,9 @@ function estimateConversationTokens(messages) {
633
655
  return total;
634
656
  }
635
657
 
658
+ // src/types/compaction.ts
659
+ var PRUNE_PROTECTED_TOOLS = ["skill"];
660
+
636
661
  // src/agent/context/pruning.ts
637
662
  var DEFAULT_CONTEXT_LIMITS = {
638
663
  contextWindow: 128e3,
@@ -744,18 +769,36 @@ async function pruneContext(messages, options = {}) {
744
769
  let summary;
745
770
  const initialTokens = estimateConversationTokens(currentMessages);
746
771
  if (!shouldPruneContext(initialTokens, limits)) {
747
- return { messages: currentMessages, removedCount: 0, tokensRemoved: 0, summarized: false };
772
+ return {
773
+ messages: currentMessages,
774
+ removedCount: 0,
775
+ tokensRemoved: 0,
776
+ summarized: false
777
+ };
748
778
  }
749
- const prunedMessages = pruneToolResults(currentMessages, limits.protectedTokens);
779
+ const prunedMessages = pruneToolResults(
780
+ currentMessages,
781
+ limits.protectedTokens
782
+ );
750
783
  const afterPruneTokens = estimateConversationTokens(prunedMessages);
751
784
  tokensRemoved = initialTokens - afterPruneTokens;
752
785
  currentMessages = prunedMessages;
753
786
  if (!isContextOverflowing(afterPruneTokens, limits)) {
754
- return { messages: currentMessages, removedCount: 0, tokensRemoved, summarized: false };
787
+ return {
788
+ messages: currentMessages,
789
+ removedCount: 0,
790
+ tokensRemoved,
791
+ summarized: false
792
+ };
755
793
  }
756
794
  const cutIndex = findCutPoint(currentMessages, limits.protectedTokens);
757
795
  if (cutIndex === 0) {
758
- return { messages: currentMessages, removedCount: 0, tokensRemoved, summarized: false };
796
+ return {
797
+ messages: currentMessages,
798
+ removedCount: 0,
799
+ tokensRemoved,
800
+ summarized: false
801
+ };
759
802
  }
760
803
  const toSummarize = currentMessages.slice(0, cutIndex);
761
804
  const toKeep = currentMessages.slice(cutIndex);
@@ -779,7 +822,13 @@ ${summary}`,
779
822
  } else {
780
823
  currentMessages = toKeep;
781
824
  }
782
- return { messages: currentMessages, removedCount, tokensRemoved, summarized, summary };
825
+ return {
826
+ messages: currentMessages,
827
+ removedCount,
828
+ tokensRemoved,
829
+ summarized,
830
+ summary
831
+ };
783
832
  }
784
833
 
785
834
  // src/agent/context/manager.ts
@@ -1327,6 +1376,29 @@ async function* runModelStep(options) {
1327
1376
  );
1328
1377
  }
1329
1378
 
1379
+ // src/types/messages.ts
1380
+ function accumulateUsage(current, next) {
1381
+ if (!next) return current;
1382
+ if (!current) {
1383
+ return {
1384
+ inputTokens: next.inputTokens ?? 0,
1385
+ outputTokens: next.outputTokens ?? 0,
1386
+ totalTokens: next.totalTokens ?? 0,
1387
+ cacheReadTokens: (next.cacheReadTokens ?? 0) || void 0,
1388
+ cacheWriteTokens: (next.cacheWriteTokens ?? 0) || void 0
1389
+ };
1390
+ }
1391
+ const cacheRead = (current.cacheReadTokens ?? 0) + (next.cacheReadTokens ?? 0);
1392
+ const cacheWrite = (current.cacheWriteTokens ?? 0) + (next.cacheWriteTokens ?? 0);
1393
+ return {
1394
+ inputTokens: (current.inputTokens ?? 0) + (next.inputTokens ?? 0),
1395
+ outputTokens: (current.outputTokens ?? 0) + (next.outputTokens ?? 0),
1396
+ totalTokens: (current.totalTokens ?? 0) + (next.totalTokens ?? 0),
1397
+ cacheReadTokens: cacheRead || void 0,
1398
+ cacheWriteTokens: cacheWrite || void 0
1399
+ };
1400
+ }
1401
+
1330
1402
  // src/execution/turn-runner/tool-batch.ts
1331
1403
  function cloneToolResultRecord(options) {
1332
1404
  return new Map(
@@ -1453,11 +1525,7 @@ async function runToolBatch(options) {
1453
1525
  let safe = false;
1454
1526
  let initialized;
1455
1527
  try {
1456
- const result = await isParallelSafe(
1457
- tool,
1458
- toolCall.args,
1459
- options.cwd
1460
- );
1528
+ const result = await isParallelSafe(tool, toolCall.args, options.cwd);
1461
1529
  safe = result.safe;
1462
1530
  initialized = result.initialized;
1463
1531
  } catch {
@@ -1586,7 +1654,11 @@ function cloneAgentWorkflowTurnState(state) {
1586
1654
  ...state,
1587
1655
  systemPrompts: [...state.systemPrompts],
1588
1656
  messages: state.messages.map(cloneMessageSnapshot),
1589
- ...state.pendingInput ? { pendingInput: cloneMessageSnapshot(state.pendingInput) } : {},
1657
+ ...state.pendingInput ? {
1658
+ pendingInput: cloneMessageSnapshot(
1659
+ state.pendingInput
1660
+ )
1661
+ } : {},
1590
1662
  ...state.usage ? { usage: cloneUsage(state.usage) } : {},
1591
1663
  ...state.turnState ? { turnState: structuredClone(state.turnState) } : {},
1592
1664
  ...state.lastModelStep ? { lastModelStep: structuredClone(state.lastModelStep) } : {},
@@ -1612,12 +1684,14 @@ function applyWorkflowInterventions(state, interventions, updatedAt) {
1612
1684
  if (interventions.length === 0) {
1613
1685
  return state;
1614
1686
  }
1615
- const injected = interventions.map((intervention) => ({
1616
- id: intervention.id,
1617
- role: "user",
1618
- createdAt: intervention.createdAt,
1619
- content: intervention.message
1620
- }));
1687
+ const injected = interventions.map(
1688
+ (intervention) => ({
1689
+ id: intervention.id,
1690
+ role: "user",
1691
+ createdAt: intervention.createdAt,
1692
+ content: intervention.message
1693
+ })
1694
+ );
1621
1695
  return {
1622
1696
  ...state,
1623
1697
  messages: [...state.messages, ...injected],
@@ -1982,6 +2056,7 @@ export {
1982
2056
  estimateTokens,
1983
2057
  estimateMessageTokens,
1984
2058
  estimateConversationTokens,
2059
+ PRUNE_PROTECTED_TOOLS,
1985
2060
  DEFAULT_CONTEXT_LIMITS,
1986
2061
  getUsableTokenLimit,
1987
2062
  findCutPoint,
@@ -1991,6 +2066,7 @@ export {
1991
2066
  ContextOverflowError,
1992
2067
  processStepStream,
1993
2068
  runModelStep,
2069
+ accumulateUsage,
1994
2070
  runToolBatch,
1995
2071
  commitStep,
1996
2072
  commitOutput,
@@ -118,9 +118,14 @@ async function loadSkillMetadata(filePath, scope, source, maxSize) {
118
118
  import { readFile as readFile2, readdir, stat as stat2 } from "fs/promises";
119
119
  import { extname, join as join2, relative } from "path";
120
120
  async function loadSkillContent(metadata) {
121
+ if (!metadata.filePath) {
122
+ throw new Error(
123
+ `Cannot load skill content for "${metadata.name}": no file path. Pack-contributed skills must have content pre-cached via SkillRegistry.register(metadata, content).`
124
+ );
125
+ }
121
126
  const raw = await readFile2(metadata.filePath, "utf-8");
122
127
  const { body } = parseFrontmatter(raw);
123
- const resources = await scanSkillResources(metadata.baseDir);
128
+ const resources = await scanSkillResources(metadata.baseDir ?? "");
124
129
  return {
125
130
  ...metadata,
126
131
  body,
@@ -128,6 +133,14 @@ async function loadSkillContent(metadata) {
128
133
  };
129
134
  }
130
135
  async function loadResourceContent(resource) {
136
+ if (resource.content !== void 0) {
137
+ return resource.content;
138
+ }
139
+ if (!resource.absolutePath) {
140
+ throw new Error(
141
+ `Resource "${resource.relativePath}" has no content or absolute path.`
142
+ );
143
+ }
131
144
  return readFile2(resource.absolutePath, "utf-8");
132
145
  }
133
146
  async function scanSkillResources(baseDir) {
@@ -158,7 +171,14 @@ async function collectFiles(dirPath, baseDir, type, resources, maxDepth = 3, cur
158
171
  absolutePath: fullPath
159
172
  });
160
173
  } else if (entry.isDirectory()) {
161
- await collectFiles(fullPath, baseDir, type, resources, maxDepth, currentDepth + 1);
174
+ await collectFiles(
175
+ fullPath,
176
+ baseDir,
177
+ type,
178
+ resources,
179
+ maxDepth,
180
+ currentDepth + 1
181
+ );
162
182
  }
163
183
  }
164
184
  } catch {
@@ -197,7 +217,9 @@ function deduplicateSkills(skills) {
197
217
  byName.set(skill.name, skill);
198
218
  }
199
219
  }
200
- return Array.from(byName.values()).sort((a, b) => a.name.localeCompare(b.name));
220
+ return Array.from(byName.values()).sort(
221
+ (a, b) => a.name.localeCompare(b.name)
222
+ );
201
223
  }
202
224
 
203
225
  // src/skill/discovery/fs.ts
@@ -256,7 +278,9 @@ async function scanRoot(root, maxDepth, maxFileSize = DEFAULT_SKILL_MAX_SIZE) {
256
278
  dirsScanned++;
257
279
  try {
258
280
  const entries = await readdir2(dirPath, { withFileTypes: true });
259
- const hasSkillFile = entries.some((entry) => entry.isFile() && entry.name === SKILL_FILENAME);
281
+ const hasSkillFile = entries.some(
282
+ (entry) => entry.isFile() && entry.name === SKILL_FILENAME
283
+ );
260
284
  if (hasSkillFile) {
261
285
  const filePath = join4(dirPath, SKILL_FILENAME);
262
286
  const metadata = await loadSkillMetadata(
@@ -304,7 +328,11 @@ async function discoverSkills(cwd, config) {
304
328
  if (config?.roots) {
305
329
  for (const root of config.roots) {
306
330
  const absRoot = resolve2(resolvedCwd, root);
307
- roots.push({ path: absRoot, scope: "global", source: { type: "local", root: absRoot } });
331
+ roots.push({
332
+ path: absRoot,
333
+ scope: "global",
334
+ source: { type: "local", root: absRoot }
335
+ });
308
336
  }
309
337
  }
310
338
  const home = homedir();
@@ -488,9 +516,13 @@ var SkillRegistry = class {
488
516
  lines.push("");
489
517
  lines.push(`<skill name="${skill.name}" scope="${skill.scope}">`);
490
518
  lines.push(` <description>${skill.description}</description>`);
491
- lines.push(` <file>${skill.filePath}</file>`);
519
+ if (skill.filePath) {
520
+ lines.push(` <file>${skill.filePath}</file>`);
521
+ }
492
522
  if (skill.dependencies && skill.dependencies.length > 0) {
493
- lines.push(` <depends-on>${skill.dependencies.join(", ")}</depends-on>`);
523
+ lines.push(
524
+ ` <depends-on>${skill.dependencies.join(", ")}</depends-on>`
525
+ );
494
526
  }
495
527
  lines.push("</skill>");
496
528
  }
@@ -546,6 +578,46 @@ var SkillRegistry = class {
546
578
  // ==========================================================================
547
579
  // Cache Management
548
580
  // ==========================================================================
581
+ // ==========================================================================
582
+ // External Registration (for capability packs)
583
+ // ==========================================================================
584
+ /**
585
+ * Register an externally defined skill with optional pre-loaded content.
586
+ *
587
+ * Intended for capability packs that contribute skills without placing
588
+ * files on disk — the pack's inline body is stored directly in the
589
+ * content cache so the agent can load it without a file read.
590
+ *
591
+ * **Priority:** registered skills have lower priority than discovered
592
+ * skills. If a skill with the same name was already found during
593
+ * discovery, the discovered skill wins and this call is a no-op.
594
+ *
595
+ * @param metadata L1 metadata describing the skill.
596
+ * @param content Pre-built content (L2). When provided, this is stored
597
+ * in the cache so `loadContent()` never reads a file.
598
+ */
599
+ register(metadata, content) {
600
+ const existing = this.skills.get(metadata.name);
601
+ if (existing) {
602
+ const protectedExisting = existing.scope === "builtin" || existing.source.type === "local" || existing.filePath !== void 0 || existing.baseDir !== void 0;
603
+ if (protectedExisting) {
604
+ return "skipped";
605
+ }
606
+ this.skills.set(metadata.name, metadata);
607
+ if (content) {
608
+ this.contentCache.set(metadata.name, content);
609
+ }
610
+ return "updated";
611
+ }
612
+ this.skills.set(metadata.name, metadata);
613
+ if (content) {
614
+ this.contentCache.set(metadata.name, content);
615
+ }
616
+ return "registered";
617
+ }
618
+ // ==========================================================================
619
+ // Cache Management
620
+ // ==========================================================================
549
621
  /** Clear the content cache, forcing reloads on next access. */
550
622
  clearContentCache() {
551
623
  this.contentCache.clear();