@aigne/agent-runtime 1.12.0-beta.5

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 (234) hide show
  1. package/LICENSE.md +26 -0
  2. package/README.md +79 -0
  3. package/dist/agent-runners/ai-runner.cjs +133 -0
  4. package/dist/agent-runners/ai-runner.d.cts +33 -0
  5. package/dist/agent-runners/ai-runner.d.cts.map +1 -0
  6. package/dist/agent-runners/ai-runner.d.mts +33 -0
  7. package/dist/agent-runners/ai-runner.d.mts.map +1 -0
  8. package/dist/agent-runners/ai-runner.mjs +134 -0
  9. package/dist/agent-runners/ai-runner.mjs.map +1 -0
  10. package/dist/agent-runners/ash-runner.cjs +272 -0
  11. package/dist/agent-runners/ash-runner.d.cts +30 -0
  12. package/dist/agent-runners/ash-runner.d.cts.map +1 -0
  13. package/dist/agent-runners/ash-runner.d.mts +30 -0
  14. package/dist/agent-runners/ash-runner.d.mts.map +1 -0
  15. package/dist/agent-runners/ash-runner.mjs +273 -0
  16. package/dist/agent-runners/ash-runner.mjs.map +1 -0
  17. package/dist/agent-runners/budget.cjs +71 -0
  18. package/dist/agent-runners/budget.d.cts +40 -0
  19. package/dist/agent-runners/budget.d.cts.map +1 -0
  20. package/dist/agent-runners/budget.d.mts +40 -0
  21. package/dist/agent-runners/budget.d.mts.map +1 -0
  22. package/dist/agent-runners/budget.mjs +67 -0
  23. package/dist/agent-runners/budget.mjs.map +1 -0
  24. package/dist/agent-runners/code-runner.cjs +61 -0
  25. package/dist/agent-runners/code-runner.mjs +61 -0
  26. package/dist/agent-runners/code-runner.mjs.map +1 -0
  27. package/dist/agent-runners/env-whitelist.cjs +36 -0
  28. package/dist/agent-runners/env-whitelist.d.cts +5 -0
  29. package/dist/agent-runners/env-whitelist.d.cts.map +1 -0
  30. package/dist/agent-runners/env-whitelist.d.mts +5 -0
  31. package/dist/agent-runners/env-whitelist.d.mts.map +1 -0
  32. package/dist/agent-runners/env-whitelist.mjs +36 -0
  33. package/dist/agent-runners/env-whitelist.mjs.map +1 -0
  34. package/dist/agent-runners/guide-rails.cjs +47 -0
  35. package/dist/agent-runners/guide-rails.d.cts +16 -0
  36. package/dist/agent-runners/guide-rails.d.cts.map +1 -0
  37. package/dist/agent-runners/guide-rails.d.mts +16 -0
  38. package/dist/agent-runners/guide-rails.d.mts.map +1 -0
  39. package/dist/agent-runners/guide-rails.mjs +48 -0
  40. package/dist/agent-runners/guide-rails.mjs.map +1 -0
  41. package/dist/agent-runners/hook-channel.cjs +55 -0
  42. package/dist/agent-runners/hook-channel.d.cts +38 -0
  43. package/dist/agent-runners/hook-channel.d.cts.map +1 -0
  44. package/dist/agent-runners/hook-channel.d.mts +38 -0
  45. package/dist/agent-runners/hook-channel.d.mts.map +1 -0
  46. package/dist/agent-runners/hook-channel.mjs +55 -0
  47. package/dist/agent-runners/hook-channel.mjs.map +1 -0
  48. package/dist/agent-runners/hooks.cjs +107 -0
  49. package/dist/agent-runners/hooks.d.cts +41 -0
  50. package/dist/agent-runners/hooks.d.cts.map +1 -0
  51. package/dist/agent-runners/hooks.d.mts +41 -0
  52. package/dist/agent-runners/hooks.d.mts.map +1 -0
  53. package/dist/agent-runners/hooks.mjs +107 -0
  54. package/dist/agent-runners/hooks.mjs.map +1 -0
  55. package/dist/agent-runners/memory-afs.cjs +342 -0
  56. package/dist/agent-runners/memory-afs.d.cts +221 -0
  57. package/dist/agent-runners/memory-afs.d.cts.map +1 -0
  58. package/dist/agent-runners/memory-afs.d.mts +221 -0
  59. package/dist/agent-runners/memory-afs.d.mts.map +1 -0
  60. package/dist/agent-runners/memory-afs.mjs +326 -0
  61. package/dist/agent-runners/memory-afs.mjs.map +1 -0
  62. package/dist/agent-runners/memory-archive.cjs +263 -0
  63. package/dist/agent-runners/memory-archive.d.cts +47 -0
  64. package/dist/agent-runners/memory-archive.d.cts.map +1 -0
  65. package/dist/agent-runners/memory-archive.d.mts +47 -0
  66. package/dist/agent-runners/memory-archive.d.mts.map +1 -0
  67. package/dist/agent-runners/memory-archive.mjs +257 -0
  68. package/dist/agent-runners/memory-archive.mjs.map +1 -0
  69. package/dist/agent-runners/orchestrator-runner.cjs +302 -0
  70. package/dist/agent-runners/orchestrator-runner.d.cts +23 -0
  71. package/dist/agent-runners/orchestrator-runner.d.cts.map +1 -0
  72. package/dist/agent-runners/orchestrator-runner.d.mts +23 -0
  73. package/dist/agent-runners/orchestrator-runner.d.mts.map +1 -0
  74. package/dist/agent-runners/orchestrator-runner.mjs +303 -0
  75. package/dist/agent-runners/orchestrator-runner.mjs.map +1 -0
  76. package/dist/agent-runners/orchestrator-state.cjs +68 -0
  77. package/dist/agent-runners/orchestrator-state.d.cts +23 -0
  78. package/dist/agent-runners/orchestrator-state.d.cts.map +1 -0
  79. package/dist/agent-runners/orchestrator-state.d.mts +23 -0
  80. package/dist/agent-runners/orchestrator-state.d.mts.map +1 -0
  81. package/dist/agent-runners/orchestrator-state.mjs +65 -0
  82. package/dist/agent-runners/orchestrator-state.mjs.map +1 -0
  83. package/dist/agent-runners/retry.cjs +30 -0
  84. package/dist/agent-runners/retry.d.cts +13 -0
  85. package/dist/agent-runners/retry.d.cts.map +1 -0
  86. package/dist/agent-runners/retry.d.mts +13 -0
  87. package/dist/agent-runners/retry.d.mts.map +1 -0
  88. package/dist/agent-runners/retry.mjs +30 -0
  89. package/dist/agent-runners/retry.mjs.map +1 -0
  90. package/dist/agent-runners/scratchpad-afs.cjs +276 -0
  91. package/dist/agent-runners/scratchpad-afs.d.cts +103 -0
  92. package/dist/agent-runners/scratchpad-afs.d.cts.map +1 -0
  93. package/dist/agent-runners/scratchpad-afs.d.mts +103 -0
  94. package/dist/agent-runners/scratchpad-afs.d.mts.map +1 -0
  95. package/dist/agent-runners/scratchpad-afs.mjs +271 -0
  96. package/dist/agent-runners/scratchpad-afs.mjs.map +1 -0
  97. package/dist/agent-runners/stream-router.cjs +72 -0
  98. package/dist/agent-runners/stream-router.d.cts +22 -0
  99. package/dist/agent-runners/stream-router.d.cts.map +1 -0
  100. package/dist/agent-runners/stream-router.d.mts +22 -0
  101. package/dist/agent-runners/stream-router.d.mts.map +1 -0
  102. package/dist/agent-runners/stream-router.mjs +72 -0
  103. package/dist/agent-runners/stream-router.mjs.map +1 -0
  104. package/dist/agent-runners/system-prompt.cjs +35 -0
  105. package/dist/agent-runners/system-prompt.d.cts +17 -0
  106. package/dist/agent-runners/system-prompt.d.cts.map +1 -0
  107. package/dist/agent-runners/system-prompt.d.mts +17 -0
  108. package/dist/agent-runners/system-prompt.d.mts.map +1 -0
  109. package/dist/agent-runners/system-prompt.mjs +34 -0
  110. package/dist/agent-runners/system-prompt.mjs.map +1 -0
  111. package/dist/agent-runners/team-modes/aggregates.cjs +36 -0
  112. package/dist/agent-runners/team-modes/aggregates.mjs +35 -0
  113. package/dist/agent-runners/team-modes/aggregates.mjs.map +1 -0
  114. package/dist/agent-runners/team-modes/iterate.cjs +46 -0
  115. package/dist/agent-runners/team-modes/iterate.mjs +47 -0
  116. package/dist/agent-runners/team-modes/iterate.mjs.map +1 -0
  117. package/dist/agent-runners/team-modes/parallel.cjs +59 -0
  118. package/dist/agent-runners/team-modes/parallel.mjs +60 -0
  119. package/dist/agent-runners/team-modes/parallel.mjs.map +1 -0
  120. package/dist/agent-runners/team-modes/reflection.cjs +155 -0
  121. package/dist/agent-runners/team-modes/reflection.mjs +156 -0
  122. package/dist/agent-runners/team-modes/reflection.mjs.map +1 -0
  123. package/dist/agent-runners/team-modes/sequential.cjs +63 -0
  124. package/dist/agent-runners/team-modes/sequential.mjs +64 -0
  125. package/dist/agent-runners/team-modes/sequential.mjs.map +1 -0
  126. package/dist/agent-runners/team-modes/utils.cjs +39 -0
  127. package/dist/agent-runners/team-modes/utils.mjs +36 -0
  128. package/dist/agent-runners/team-modes/utils.mjs.map +1 -0
  129. package/dist/agent-runners/team-runner.cjs +277 -0
  130. package/dist/agent-runners/team-runner.d.cts +34 -0
  131. package/dist/agent-runners/team-runner.d.cts.map +1 -0
  132. package/dist/agent-runners/team-runner.d.mts +34 -0
  133. package/dist/agent-runners/team-runner.d.mts.map +1 -0
  134. package/dist/agent-runners/team-runner.mjs +278 -0
  135. package/dist/agent-runners/team-runner.mjs.map +1 -0
  136. package/dist/agent-runners/template-context.cjs +32 -0
  137. package/dist/agent-runners/template-context.d.cts +43 -0
  138. package/dist/agent-runners/template-context.d.cts.map +1 -0
  139. package/dist/agent-runners/template-context.d.mts +43 -0
  140. package/dist/agent-runners/template-context.d.mts.map +1 -0
  141. package/dist/agent-runners/template-context.mjs +33 -0
  142. package/dist/agent-runners/template-context.mjs.map +1 -0
  143. package/dist/index.cjs +123 -0
  144. package/dist/index.d.cts +29 -0
  145. package/dist/index.d.mts +29 -0
  146. package/dist/index.mjs +29 -0
  147. package/dist/program/agent-action.cjs +496 -0
  148. package/dist/program/agent-action.d.cts +42 -0
  149. package/dist/program/agent-action.d.cts.map +1 -0
  150. package/dist/program/agent-action.d.mts +42 -0
  151. package/dist/program/agent-action.d.mts.map +1 -0
  152. package/dist/program/agent-action.mjs +497 -0
  153. package/dist/program/agent-action.mjs.map +1 -0
  154. package/dist/program/agent-messages-tools.cjs +137 -0
  155. package/dist/program/agent-messages-tools.d.cts +59 -0
  156. package/dist/program/agent-messages-tools.d.cts.map +1 -0
  157. package/dist/program/agent-messages-tools.d.mts +59 -0
  158. package/dist/program/agent-messages-tools.d.mts.map +1 -0
  159. package/dist/program/agent-messages-tools.mjs +130 -0
  160. package/dist/program/agent-messages-tools.mjs.map +1 -0
  161. package/dist/program/agent-runner-registry.cjs +314 -0
  162. package/dist/program/agent-runner-registry.d.cts +52 -0
  163. package/dist/program/agent-runner-registry.d.cts.map +1 -0
  164. package/dist/program/agent-runner-registry.d.mts +52 -0
  165. package/dist/program/agent-runner-registry.d.mts.map +1 -0
  166. package/dist/program/agent-runner-registry.mjs +313 -0
  167. package/dist/program/agent-runner-registry.mjs.map +1 -0
  168. package/dist/program/agent-subscribe.cjs +72 -0
  169. package/dist/program/agent-subscribe.d.cts +18 -0
  170. package/dist/program/agent-subscribe.d.cts.map +1 -0
  171. package/dist/program/agent-subscribe.d.mts +18 -0
  172. package/dist/program/agent-subscribe.d.mts.map +1 -0
  173. package/dist/program/agent-subscribe.mjs +73 -0
  174. package/dist/program/agent-subscribe.mjs.map +1 -0
  175. package/dist/program/agent-tools.cjs +135 -0
  176. package/dist/program/agent-tools.d.cts +35 -0
  177. package/dist/program/agent-tools.d.cts.map +1 -0
  178. package/dist/program/agent-tools.d.mts +35 -0
  179. package/dist/program/agent-tools.d.mts.map +1 -0
  180. package/dist/program/agent-tools.mjs +136 -0
  181. package/dist/program/agent-tools.mjs.map +1 -0
  182. package/dist/program/manifest-nesting.cjs +57 -0
  183. package/dist/program/manifest-nesting.d.cts +13 -0
  184. package/dist/program/manifest-nesting.d.cts.map +1 -0
  185. package/dist/program/manifest-nesting.d.mts +13 -0
  186. package/dist/program/manifest-nesting.d.mts.map +1 -0
  187. package/dist/program/manifest-nesting.mjs +57 -0
  188. package/dist/program/manifest-nesting.mjs.map +1 -0
  189. package/dist/program/result-contract.cjs +55 -0
  190. package/dist/program/result-contract.d.cts +23 -0
  191. package/dist/program/result-contract.d.cts.map +1 -0
  192. package/dist/program/result-contract.d.mts +23 -0
  193. package/dist/program/result-contract.d.mts.map +1 -0
  194. package/dist/program/result-contract.mjs +51 -0
  195. package/dist/program/result-contract.mjs.map +1 -0
  196. package/dist/program/runner-error.cjs +71 -0
  197. package/dist/program/runner-error.d.cts +25 -0
  198. package/dist/program/runner-error.d.cts.map +1 -0
  199. package/dist/program/runner-error.d.mts +25 -0
  200. package/dist/program/runner-error.d.mts.map +1 -0
  201. package/dist/program/runner-error.mjs +72 -0
  202. package/dist/program/runner-error.mjs.map +1 -0
  203. package/dist/program/scoped-afs.cjs +538 -0
  204. package/dist/program/scoped-afs.d.cts +245 -0
  205. package/dist/program/scoped-afs.d.cts.map +1 -0
  206. package/dist/program/scoped-afs.d.mts +245 -0
  207. package/dist/program/scoped-afs.d.mts.map +1 -0
  208. package/dist/program/scoped-afs.mjs +531 -0
  209. package/dist/program/scoped-afs.mjs.map +1 -0
  210. package/dist/program/session-hierarchy.cjs +1 -0
  211. package/dist/program/session-hierarchy.d.cts +2 -0
  212. package/dist/program/session-hierarchy.d.mts +2 -0
  213. package/dist/program/session-hierarchy.mjs +3 -0
  214. package/dist/program/tool-discovery/ash-frontmatter.cjs +83 -0
  215. package/dist/program/tool-discovery/ash-frontmatter.d.cts +21 -0
  216. package/dist/program/tool-discovery/ash-frontmatter.d.cts.map +1 -0
  217. package/dist/program/tool-discovery/ash-frontmatter.d.mts +21 -0
  218. package/dist/program/tool-discovery/ash-frontmatter.d.mts.map +1 -0
  219. package/dist/program/tool-discovery/ash-frontmatter.mjs +84 -0
  220. package/dist/program/tool-discovery/ash-frontmatter.mjs.map +1 -0
  221. package/dist/program/tool-discovery/dot-path-resolver.cjs +60 -0
  222. package/dist/program/tool-discovery/dot-path-resolver.mjs +61 -0
  223. package/dist/program/tool-discovery/dot-path-resolver.mjs.map +1 -0
  224. package/dist/program/tool-discovery/skill-gate.cjs +36 -0
  225. package/dist/program/tool-discovery/skill-gate.d.cts +10 -0
  226. package/dist/program/tool-discovery/skill-gate.d.cts.map +1 -0
  227. package/dist/program/tool-discovery/skill-gate.d.mts +10 -0
  228. package/dist/program/tool-discovery/skill-gate.d.mts.map +1 -0
  229. package/dist/program/tool-discovery/skill-gate.mjs +35 -0
  230. package/dist/program/tool-discovery/skill-gate.mjs.map +1 -0
  231. package/dist/providers/basic/ash/dist/index.cjs +1809 -0
  232. package/dist/providers/basic/ash/dist/index.mjs +1807 -0
  233. package/dist/providers/basic/ash/dist/index.mjs.map +1 -0
  234. package/package.json +67 -0
@@ -0,0 +1,83 @@
1
+ let js_yaml = require("js-yaml");
2
+
3
+ //#region src/program/tool-discovery/ash-frontmatter.ts
4
+ /**
5
+ * ASH frontmatter parser (S13).
6
+ *
7
+ * Extracts tool schemas from `# ---` YAML blocks in .ash files.
8
+ * All file I/O goes through AFS (never `fs.readFile`).
9
+ */
10
+ /**
11
+ * Parse the `# ---` YAML frontmatter from an .ash file.
12
+ * Returns ToolSchema on success, FrontmatterError on failure.
13
+ */
14
+ async function parseFrontmatter(afs, filePath) {
15
+ let content;
16
+ try {
17
+ content = await afs.read(filePath);
18
+ } catch {
19
+ return {
20
+ error: `Failed to read file: ${filePath}`,
21
+ file: filePath
22
+ };
23
+ }
24
+ if (!content || !content.trim()) return {
25
+ error: "Empty file",
26
+ file: filePath
27
+ };
28
+ const yamlBlock = extractYamlBlock(content);
29
+ if (!yamlBlock) return {
30
+ error: "No valid frontmatter block found (missing # --- delimiters)",
31
+ file: filePath
32
+ };
33
+ let parsed;
34
+ try {
35
+ parsed = (0, js_yaml.load)(yamlBlock);
36
+ } catch (e) {
37
+ return {
38
+ error: `YAML parse error: ${e instanceof Error ? e.message : String(e)}`,
39
+ file: filePath
40
+ };
41
+ }
42
+ if (!parsed || typeof parsed !== "object") return {
43
+ error: "Frontmatter must be a YAML mapping",
44
+ file: filePath
45
+ };
46
+ const name = parsed.name;
47
+ if (!name || typeof name !== "string" || !name.trim()) return {
48
+ error: "Missing or empty 'name' field in frontmatter",
49
+ file: filePath
50
+ };
51
+ const description = typeof parsed.description === "string" ? parsed.description.trim() : "";
52
+ const input = typeof parsed.input === "object" && parsed.input !== null ? parsed.input : void 0;
53
+ const output = typeof parsed.output === "object" && parsed.output !== null ? parsed.output : void 0;
54
+ return {
55
+ name: name.trim(),
56
+ description,
57
+ filePath,
58
+ input,
59
+ output
60
+ };
61
+ }
62
+ function extractYamlBlock(content) {
63
+ const lines = content.split("\n");
64
+ let startIdx = -1;
65
+ let endIdx = -1;
66
+ for (let i = 0; i < lines.length; i++) if (lines[i].trim() === "# ---") if (startIdx === -1) startIdx = i;
67
+ else {
68
+ endIdx = i;
69
+ break;
70
+ }
71
+ if (startIdx === -1 || endIdx === -1) return null;
72
+ const yamlLines = [];
73
+ for (let i = startIdx + 1; i < endIdx; i++) {
74
+ const line = lines[i];
75
+ if (line.startsWith("# ")) yamlLines.push(line.slice(2));
76
+ else if (line.startsWith("#")) yamlLines.push(line.slice(1));
77
+ else yamlLines.push(line);
78
+ }
79
+ return yamlLines.join("\n");
80
+ }
81
+
82
+ //#endregion
83
+ exports.parseFrontmatter = parseFrontmatter;
@@ -0,0 +1,21 @@
1
+ //#region src/program/tool-discovery/ash-frontmatter.d.ts
2
+ /**
3
+ * ASH frontmatter parser (S13).
4
+ *
5
+ * Extracts tool schemas from `# ---` YAML blocks in .ash files.
6
+ * All file I/O goes through AFS (never `fs.readFile`).
7
+ */
8
+ interface ToolSchema {
9
+ name: string;
10
+ description: string;
11
+ filePath: string;
12
+ input?: Record<string, {
13
+ type?: string;
14
+ required?: boolean;
15
+ description?: string;
16
+ }>;
17
+ output?: Record<string, unknown>;
18
+ }
19
+ //#endregion
20
+ export { ToolSchema };
21
+ //# sourceMappingURL=ash-frontmatter.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ash-frontmatter.d.cts","names":[],"sources":["../../../src/program/tool-discovery/ash-frontmatter.ts"],"mappings":";;AASA;;;;;UAAiB,UAAA;EACf,IAAA;EACA,WAAA;EACA,QAAA;EACA,KAAA,GAAQ,MAAA;IAAiB,IAAA;IAAe,QAAA;IAAoB,WAAA;EAAA;EAC5D,MAAA,GAAS,MAAA;AAAA"}
@@ -0,0 +1,21 @@
1
+ //#region src/program/tool-discovery/ash-frontmatter.d.ts
2
+ /**
3
+ * ASH frontmatter parser (S13).
4
+ *
5
+ * Extracts tool schemas from `# ---` YAML blocks in .ash files.
6
+ * All file I/O goes through AFS (never `fs.readFile`).
7
+ */
8
+ interface ToolSchema {
9
+ name: string;
10
+ description: string;
11
+ filePath: string;
12
+ input?: Record<string, {
13
+ type?: string;
14
+ required?: boolean;
15
+ description?: string;
16
+ }>;
17
+ output?: Record<string, unknown>;
18
+ }
19
+ //#endregion
20
+ export { ToolSchema };
21
+ //# sourceMappingURL=ash-frontmatter.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ash-frontmatter.d.mts","names":[],"sources":["../../../src/program/tool-discovery/ash-frontmatter.ts"],"mappings":";;AASA;;;;;UAAiB,UAAA;EACf,IAAA;EACA,WAAA;EACA,QAAA;EACA,KAAA,GAAQ,MAAA;IAAiB,IAAA;IAAe,QAAA;IAAoB,WAAA;EAAA;EAC5D,MAAA,GAAS,MAAA;AAAA"}
@@ -0,0 +1,84 @@
1
+ import { load } from "js-yaml";
2
+
3
+ //#region src/program/tool-discovery/ash-frontmatter.ts
4
+ /**
5
+ * ASH frontmatter parser (S13).
6
+ *
7
+ * Extracts tool schemas from `# ---` YAML blocks in .ash files.
8
+ * All file I/O goes through AFS (never `fs.readFile`).
9
+ */
10
+ /**
11
+ * Parse the `# ---` YAML frontmatter from an .ash file.
12
+ * Returns ToolSchema on success, FrontmatterError on failure.
13
+ */
14
+ async function parseFrontmatter(afs, filePath) {
15
+ let content;
16
+ try {
17
+ content = await afs.read(filePath);
18
+ } catch {
19
+ return {
20
+ error: `Failed to read file: ${filePath}`,
21
+ file: filePath
22
+ };
23
+ }
24
+ if (!content || !content.trim()) return {
25
+ error: "Empty file",
26
+ file: filePath
27
+ };
28
+ const yamlBlock = extractYamlBlock(content);
29
+ if (!yamlBlock) return {
30
+ error: "No valid frontmatter block found (missing # --- delimiters)",
31
+ file: filePath
32
+ };
33
+ let parsed;
34
+ try {
35
+ parsed = load(yamlBlock);
36
+ } catch (e) {
37
+ return {
38
+ error: `YAML parse error: ${e instanceof Error ? e.message : String(e)}`,
39
+ file: filePath
40
+ };
41
+ }
42
+ if (!parsed || typeof parsed !== "object") return {
43
+ error: "Frontmatter must be a YAML mapping",
44
+ file: filePath
45
+ };
46
+ const name = parsed.name;
47
+ if (!name || typeof name !== "string" || !name.trim()) return {
48
+ error: "Missing or empty 'name' field in frontmatter",
49
+ file: filePath
50
+ };
51
+ const description = typeof parsed.description === "string" ? parsed.description.trim() : "";
52
+ const input = typeof parsed.input === "object" && parsed.input !== null ? parsed.input : void 0;
53
+ const output = typeof parsed.output === "object" && parsed.output !== null ? parsed.output : void 0;
54
+ return {
55
+ name: name.trim(),
56
+ description,
57
+ filePath,
58
+ input,
59
+ output
60
+ };
61
+ }
62
+ function extractYamlBlock(content) {
63
+ const lines = content.split("\n");
64
+ let startIdx = -1;
65
+ let endIdx = -1;
66
+ for (let i = 0; i < lines.length; i++) if (lines[i].trim() === "# ---") if (startIdx === -1) startIdx = i;
67
+ else {
68
+ endIdx = i;
69
+ break;
70
+ }
71
+ if (startIdx === -1 || endIdx === -1) return null;
72
+ const yamlLines = [];
73
+ for (let i = startIdx + 1; i < endIdx; i++) {
74
+ const line = lines[i];
75
+ if (line.startsWith("# ")) yamlLines.push(line.slice(2));
76
+ else if (line.startsWith("#")) yamlLines.push(line.slice(1));
77
+ else yamlLines.push(line);
78
+ }
79
+ return yamlLines.join("\n");
80
+ }
81
+
82
+ //#endregion
83
+ export { parseFrontmatter };
84
+ //# sourceMappingURL=ash-frontmatter.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ash-frontmatter.mjs","names":["parseYAML"],"sources":["../../../src/program/tool-discovery/ash-frontmatter.ts"],"sourcesContent":["/**\n * ASH frontmatter parser (S13).\n *\n * Extracts tool schemas from `# ---` YAML blocks in .ash files.\n * All file I/O goes through AFS (never `fs.readFile`).\n */\n\nimport { load as parseYAML } from \"js-yaml\";\n\nexport interface ToolSchema {\n name: string;\n description: string;\n filePath: string;\n input?: Record<string, { type?: string; required?: boolean; description?: string }>;\n output?: Record<string, unknown>;\n}\n\nexport interface FrontmatterError {\n error: string;\n file: string;\n}\n\ninterface AFSReader {\n read(path: string): Promise<string>;\n}\n\n/**\n * Parse the `# ---` YAML frontmatter from an .ash file.\n * Returns ToolSchema on success, FrontmatterError on failure.\n */\nexport async function parseFrontmatter(\n afs: AFSReader,\n filePath: string,\n): Promise<ToolSchema | FrontmatterError> {\n let content: string;\n try {\n content = await afs.read(filePath);\n } catch {\n return { error: `Failed to read file: ${filePath}`, file: filePath };\n }\n\n if (!content || !content.trim()) {\n return { error: \"Empty file\", file: filePath };\n }\n\n const yamlBlock = extractYamlBlock(content);\n if (!yamlBlock) {\n return { error: \"No valid frontmatter block found (missing # --- delimiters)\", file: filePath };\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = parseYAML(yamlBlock) as Record<string, unknown>;\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n return { error: `YAML parse error: ${msg}`, file: filePath };\n }\n\n if (!parsed || typeof parsed !== \"object\") {\n return { error: \"Frontmatter must be a YAML mapping\", file: filePath };\n }\n\n const name = parsed.name;\n if (!name || typeof name !== \"string\" || !name.trim()) {\n return { error: \"Missing or empty 'name' field in frontmatter\", file: filePath };\n }\n\n const description = typeof parsed.description === \"string\" ? parsed.description.trim() : \"\";\n const input =\n typeof parsed.input === \"object\" && parsed.input !== null\n ? (parsed.input as Record<\n string,\n { type?: string; required?: boolean; description?: string }\n >)\n : undefined;\n const output =\n typeof parsed.output === \"object\" && parsed.output !== null\n ? (parsed.output as Record<string, unknown>)\n : undefined;\n\n return { name: name.trim(), description, filePath, input, output };\n}\n\nfunction extractYamlBlock(content: string): string | null {\n const lines = content.split(\"\\n\");\n\n let startIdx = -1;\n let endIdx = -1;\n\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i]!.trim();\n if (trimmed === \"# ---\") {\n if (startIdx === -1) {\n startIdx = i;\n } else {\n endIdx = i;\n break;\n }\n }\n }\n\n if (startIdx === -1 || endIdx === -1) return null;\n\n const yamlLines: string[] = [];\n for (let i = startIdx + 1; i < endIdx; i++) {\n const line = lines[i]!;\n // Strip leading \"# \" or \"#\" prefix\n if (line.startsWith(\"# \")) {\n yamlLines.push(line.slice(2));\n } else if (line.startsWith(\"#\")) {\n yamlLines.push(line.slice(1));\n } else {\n yamlLines.push(line);\n }\n }\n\n return yamlLines.join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;;;;AA8BA,eAAsB,iBACpB,KACA,UACwC;CACxC,IAAI;AACJ,KAAI;AACF,YAAU,MAAM,IAAI,KAAK,SAAS;SAC5B;AACN,SAAO;GAAE,OAAO,wBAAwB;GAAY,MAAM;GAAU;;AAGtE,KAAI,CAAC,WAAW,CAAC,QAAQ,MAAM,CAC7B,QAAO;EAAE,OAAO;EAAc,MAAM;EAAU;CAGhD,MAAM,YAAY,iBAAiB,QAAQ;AAC3C,KAAI,CAAC,UACH,QAAO;EAAE,OAAO;EAA+D,MAAM;EAAU;CAGjG,IAAI;AACJ,KAAI;AACF,WAASA,KAAU,UAAU;UACtB,GAAG;AAEV,SAAO;GAAE,OAAO,qBADJ,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;GACV,MAAM;GAAU;;AAG9D,KAAI,CAAC,UAAU,OAAO,WAAW,SAC/B,QAAO;EAAE,OAAO;EAAsC,MAAM;EAAU;CAGxE,MAAM,OAAO,OAAO;AACpB,KAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,CAAC,KAAK,MAAM,CACnD,QAAO;EAAE,OAAO;EAAgD,MAAM;EAAU;CAGlF,MAAM,cAAc,OAAO,OAAO,gBAAgB,WAAW,OAAO,YAAY,MAAM,GAAG;CACzF,MAAM,QACJ,OAAO,OAAO,UAAU,YAAY,OAAO,UAAU,OAChD,OAAO,QAIR;CACN,MAAM,SACJ,OAAO,OAAO,WAAW,YAAY,OAAO,WAAW,OAClD,OAAO,SACR;AAEN,QAAO;EAAE,MAAM,KAAK,MAAM;EAAE;EAAa;EAAU;EAAO;EAAQ;;AAGpE,SAAS,iBAAiB,SAAgC;CACxD,MAAM,QAAQ,QAAQ,MAAM,KAAK;CAEjC,IAAI,WAAW;CACf,IAAI,SAAS;AAEb,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,IAEhC,KADgB,MAAM,GAAI,MAAM,KAChB,QACd,KAAI,aAAa,GACf,YAAW;MACN;AACL,WAAS;AACT;;AAKN,KAAI,aAAa,MAAM,WAAW,GAAI,QAAO;CAE7C,MAAM,YAAsB,EAAE;AAC9B,MAAK,IAAI,IAAI,WAAW,GAAG,IAAI,QAAQ,KAAK;EAC1C,MAAM,OAAO,MAAM;AAEnB,MAAI,KAAK,WAAW,KAAK,CACvB,WAAU,KAAK,KAAK,MAAM,EAAE,CAAC;WACpB,KAAK,WAAW,IAAI,CAC7B,WAAU,KAAK,KAAK,MAAM,EAAE,CAAC;MAE7B,WAAU,KAAK,KAAK;;AAIxB,QAAO,UAAU,KAAK,KAAK"}
@@ -0,0 +1,60 @@
1
+ let ufo = require("ufo");
2
+
3
+ //#region src/program/tool-discovery/dot-path-resolver.ts
4
+ const DEFAULT_OPS = [
5
+ "read",
6
+ "list",
7
+ "search",
8
+ "query"
9
+ ];
10
+ const DEFAULT_MAX_DEPTH = 5;
11
+ /**
12
+ * Resolve bare dot-paths (e.g. `./knowledge/`, `./tools/`) to absolute
13
+ * blocklet-scoped whitelist entries.
14
+ *
15
+ * Directories (trailing `/` or `/**`) become glob patterns with maxDepth.
16
+ * File paths resolve to exact entries without maxDepth.
17
+ */
18
+ function resolveDotPaths(paths, blockletRoot) {
19
+ const seen = /* @__PURE__ */ new Set();
20
+ const result = [];
21
+ for (const raw of paths) {
22
+ if (!raw) continue;
23
+ if (raw.includes("\0")) throw new Error("TOOL_PATH_OUTSIDE_BLOCKLET: null bytes disallowed");
24
+ const normalized = normalizeDotPath(raw, blockletRoot);
25
+ if (seen.has(normalized.path)) continue;
26
+ seen.add(normalized.path);
27
+ result.push(normalized);
28
+ }
29
+ return result;
30
+ }
31
+ function normalizeDotPath(raw, blockletRoot) {
32
+ if (!raw.startsWith("./") && !raw.startsWith("../") && raw.startsWith("/")) throw new Error(`TOOL_PATH_OUTSIDE_BLOCKLET: absolute path '${raw}' outside blocklet root`);
33
+ const stripped = raw.replace(/\/?\*\*\/?$/, "").replace(/\/$/, "");
34
+ const isDir = raw.endsWith("/") || raw.endsWith("/**") || raw.endsWith("/**/");
35
+ const absolute = (0, ufo.joinURL)(blockletRoot, ...resolveSegments(stripped));
36
+ if (isDir) return {
37
+ path: `${absolute}/**`,
38
+ ops: DEFAULT_OPS,
39
+ maxDepth: DEFAULT_MAX_DEPTH
40
+ };
41
+ return {
42
+ path: absolute,
43
+ ops: DEFAULT_OPS
44
+ };
45
+ }
46
+ function resolveSegments(dotPath) {
47
+ const parts = dotPath.split("/").filter(Boolean);
48
+ const resolved = [];
49
+ for (const part of parts) {
50
+ if (part === ".") continue;
51
+ if (part === "..") {
52
+ if (resolved.length === 0) throw new Error(`TOOL_PATH_OUTSIDE_BLOCKLET: path '${dotPath}' escapes outside blocklet root`);
53
+ resolved.pop();
54
+ } else resolved.push(part);
55
+ }
56
+ return resolved;
57
+ }
58
+
59
+ //#endregion
60
+ exports.resolveDotPaths = resolveDotPaths;
@@ -0,0 +1,61 @@
1
+ import { joinURL } from "ufo";
2
+
3
+ //#region src/program/tool-discovery/dot-path-resolver.ts
4
+ const DEFAULT_OPS = [
5
+ "read",
6
+ "list",
7
+ "search",
8
+ "query"
9
+ ];
10
+ const DEFAULT_MAX_DEPTH = 5;
11
+ /**
12
+ * Resolve bare dot-paths (e.g. `./knowledge/`, `./tools/`) to absolute
13
+ * blocklet-scoped whitelist entries.
14
+ *
15
+ * Directories (trailing `/` or `/**`) become glob patterns with maxDepth.
16
+ * File paths resolve to exact entries without maxDepth.
17
+ */
18
+ function resolveDotPaths(paths, blockletRoot) {
19
+ const seen = /* @__PURE__ */ new Set();
20
+ const result = [];
21
+ for (const raw of paths) {
22
+ if (!raw) continue;
23
+ if (raw.includes("\0")) throw new Error("TOOL_PATH_OUTSIDE_BLOCKLET: null bytes disallowed");
24
+ const normalized = normalizeDotPath(raw, blockletRoot);
25
+ if (seen.has(normalized.path)) continue;
26
+ seen.add(normalized.path);
27
+ result.push(normalized);
28
+ }
29
+ return result;
30
+ }
31
+ function normalizeDotPath(raw, blockletRoot) {
32
+ if (!raw.startsWith("./") && !raw.startsWith("../") && raw.startsWith("/")) throw new Error(`TOOL_PATH_OUTSIDE_BLOCKLET: absolute path '${raw}' outside blocklet root`);
33
+ const stripped = raw.replace(/\/?\*\*\/?$/, "").replace(/\/$/, "");
34
+ const isDir = raw.endsWith("/") || raw.endsWith("/**") || raw.endsWith("/**/");
35
+ const absolute = joinURL(blockletRoot, ...resolveSegments(stripped));
36
+ if (isDir) return {
37
+ path: `${absolute}/**`,
38
+ ops: DEFAULT_OPS,
39
+ maxDepth: DEFAULT_MAX_DEPTH
40
+ };
41
+ return {
42
+ path: absolute,
43
+ ops: DEFAULT_OPS
44
+ };
45
+ }
46
+ function resolveSegments(dotPath) {
47
+ const parts = dotPath.split("/").filter(Boolean);
48
+ const resolved = [];
49
+ for (const part of parts) {
50
+ if (part === ".") continue;
51
+ if (part === "..") {
52
+ if (resolved.length === 0) throw new Error(`TOOL_PATH_OUTSIDE_BLOCKLET: path '${dotPath}' escapes outside blocklet root`);
53
+ resolved.pop();
54
+ } else resolved.push(part);
55
+ }
56
+ return resolved;
57
+ }
58
+
59
+ //#endregion
60
+ export { resolveDotPaths };
61
+ //# sourceMappingURL=dot-path-resolver.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dot-path-resolver.mjs","names":[],"sources":["../../../src/program/tool-discovery/dot-path-resolver.ts"],"sourcesContent":["/**\n * Dot-protocol bare-path resolver (S13).\n *\n * Resolves relative paths from manifest `tools:` into absolute blocklet-scoped\n * ToolEntry[] for the path-validator whitelist. Pure function; no I/O.\n */\n\nimport type { ToolEntry } from \"@aigne/afs-ash\";\nimport { joinURL } from \"ufo\";\n\n// `query` pairs with `list` (read-class collection view, design §3.1b).\nconst DEFAULT_OPS: string[] = [\"read\", \"list\", \"search\", \"query\"];\nconst DEFAULT_MAX_DEPTH = 5;\n\n/**\n * Resolve bare dot-paths (e.g. `./knowledge/`, `./tools/`) to absolute\n * blocklet-scoped whitelist entries.\n *\n * Directories (trailing `/` or `/**`) become glob patterns with maxDepth.\n * File paths resolve to exact entries without maxDepth.\n */\nexport function resolveDotPaths(paths: string[], blockletRoot: string): ToolEntry[] {\n const seen = new Set<string>();\n const result: ToolEntry[] = [];\n\n for (const raw of paths) {\n if (!raw) continue;\n\n if (raw.includes(\"\\0\")) {\n throw new Error(\"TOOL_PATH_OUTSIDE_BLOCKLET: null bytes disallowed\");\n }\n\n const normalized = normalizeDotPath(raw, blockletRoot);\n if (seen.has(normalized.path)) continue;\n seen.add(normalized.path);\n result.push(normalized);\n }\n\n return result;\n}\n\nfunction normalizeDotPath(raw: string, blockletRoot: string): ToolEntry {\n if (!raw.startsWith(\"./\") && !raw.startsWith(\"../\") && raw.startsWith(\"/\")) {\n throw new Error(`TOOL_PATH_OUTSIDE_BLOCKLET: absolute path '${raw}' outside blocklet root`);\n }\n\n const stripped = raw.replace(/\\/?\\*\\*\\/?$/, \"\").replace(/\\/$/, \"\");\n const isDir = raw.endsWith(\"/\") || raw.endsWith(\"/**\") || raw.endsWith(\"/**/\");\n\n const cleanSegments = resolveSegments(stripped);\n const absolute = joinURL(blockletRoot, ...cleanSegments);\n\n if (isDir) {\n return {\n path: `${absolute}/**`,\n ops: DEFAULT_OPS,\n maxDepth: DEFAULT_MAX_DEPTH,\n };\n }\n\n return { path: absolute, ops: DEFAULT_OPS };\n}\n\nfunction resolveSegments(dotPath: string): string[] {\n const parts = dotPath.split(\"/\").filter(Boolean);\n const resolved: string[] = [];\n\n for (const part of parts) {\n if (part === \".\") continue;\n if (part === \"..\") {\n if (resolved.length === 0) {\n throw new Error(\n `TOOL_PATH_OUTSIDE_BLOCKLET: path '${dotPath}' escapes outside blocklet root`,\n );\n }\n resolved.pop();\n } else {\n resolved.push(part);\n }\n }\n\n return resolved;\n}\n"],"mappings":";;;AAWA,MAAM,cAAwB;CAAC;CAAQ;CAAQ;CAAU;CAAQ;AACjE,MAAM,oBAAoB;;;;;;;;AAS1B,SAAgB,gBAAgB,OAAiB,cAAmC;CAClF,MAAM,uBAAO,IAAI,KAAa;CAC9B,MAAM,SAAsB,EAAE;AAE9B,MAAK,MAAM,OAAO,OAAO;AACvB,MAAI,CAAC,IAAK;AAEV,MAAI,IAAI,SAAS,KAAK,CACpB,OAAM,IAAI,MAAM,oDAAoD;EAGtE,MAAM,aAAa,iBAAiB,KAAK,aAAa;AACtD,MAAI,KAAK,IAAI,WAAW,KAAK,CAAE;AAC/B,OAAK,IAAI,WAAW,KAAK;AACzB,SAAO,KAAK,WAAW;;AAGzB,QAAO;;AAGT,SAAS,iBAAiB,KAAa,cAAiC;AACtE,KAAI,CAAC,IAAI,WAAW,KAAK,IAAI,CAAC,IAAI,WAAW,MAAM,IAAI,IAAI,WAAW,IAAI,CACxE,OAAM,IAAI,MAAM,8CAA8C,IAAI,yBAAyB;CAG7F,MAAM,WAAW,IAAI,QAAQ,eAAe,GAAG,CAAC,QAAQ,OAAO,GAAG;CAClE,MAAM,QAAQ,IAAI,SAAS,IAAI,IAAI,IAAI,SAAS,MAAM,IAAI,IAAI,SAAS,OAAO;CAG9E,MAAM,WAAW,QAAQ,cAAc,GADjB,gBAAgB,SAAS,CACS;AAExD,KAAI,MACF,QAAO;EACL,MAAM,GAAG,SAAS;EAClB,KAAK;EACL,UAAU;EACX;AAGH,QAAO;EAAE,MAAM;EAAU,KAAK;EAAa;;AAG7C,SAAS,gBAAgB,SAA2B;CAClD,MAAM,QAAQ,QAAQ,MAAM,IAAI,CAAC,OAAO,QAAQ;CAChD,MAAM,WAAqB,EAAE;AAE7B,MAAK,MAAM,QAAQ,OAAO;AACxB,MAAI,SAAS,IAAK;AAClB,MAAI,SAAS,MAAM;AACjB,OAAI,SAAS,WAAW,EACtB,OAAM,IAAI,MACR,qCAAqC,QAAQ,iCAC9C;AAEH,YAAS,KAAK;QAEd,UAAS,KAAK,KAAK;;AAIvB,QAAO"}
@@ -0,0 +1,36 @@
1
+
2
+ //#region src/program/tool-discovery/skill-gate.ts
3
+ /**
4
+ * Return only the ToolSchemas whose gating skill is in the active set.
5
+ * Must be called on every tool call (not just catalog build) so mid-run
6
+ * skill removal disables helpers immediately.
7
+ */
8
+ function filterByActiveSkills(helpers, activeSkills) {
9
+ return helpers.filter((h) => activeSkills.has(h.skill)).map((h) => h.schema);
10
+ }
11
+ /**
12
+ * Merge local tools with active skill helpers. When a skill helper has the
13
+ * same name as a local tool, the helper wins (shadow) and a warning is emitted.
14
+ */
15
+ function mergeWithShadowing(tools, activeHelpers) {
16
+ const warnings = [];
17
+ const helperNames = new Set(activeHelpers.map((h) => h.name));
18
+ const merged = [];
19
+ for (const tool of tools) {
20
+ if (helperNames.has(tool.name)) {
21
+ const helper = activeHelpers.find((h) => h.name === tool.name);
22
+ warnings.push(`tool_shadow: "${tool.name}" from ${tool.filePath} shadowed by skill helper ${helper.filePath}`);
23
+ continue;
24
+ }
25
+ merged.push(tool);
26
+ }
27
+ merged.push(...activeHelpers);
28
+ return {
29
+ merged,
30
+ warnings
31
+ };
32
+ }
33
+
34
+ //#endregion
35
+ exports.filterByActiveSkills = filterByActiveSkills;
36
+ exports.mergeWithShadowing = mergeWithShadowing;
@@ -0,0 +1,10 @@
1
+ import { ToolSchema } from "./ash-frontmatter.cjs";
2
+
3
+ //#region src/program/tool-discovery/skill-gate.d.ts
4
+ interface SkillHelper {
5
+ skill: string;
6
+ schema: ToolSchema;
7
+ }
8
+ //#endregion
9
+ export { SkillHelper };
10
+ //# sourceMappingURL=skill-gate.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-gate.d.cts","names":[],"sources":["../../../src/program/tool-discovery/skill-gate.ts"],"mappings":";;;UASiB,WAAA;EACf,KAAA;EACA,MAAA,EAAQ,UAAA;AAAA"}
@@ -0,0 +1,10 @@
1
+ import { ToolSchema } from "./ash-frontmatter.mjs";
2
+
3
+ //#region src/program/tool-discovery/skill-gate.d.ts
4
+ interface SkillHelper {
5
+ skill: string;
6
+ schema: ToolSchema;
7
+ }
8
+ //#endregion
9
+ export { SkillHelper };
10
+ //# sourceMappingURL=skill-gate.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-gate.d.mts","names":[],"sources":["../../../src/program/tool-discovery/skill-gate.ts"],"mappings":";;;UASiB,WAAA;EACf,KAAA;EACA,MAAA,EAAQ,UAAA;AAAA"}
@@ -0,0 +1,35 @@
1
+ //#region src/program/tool-discovery/skill-gate.ts
2
+ /**
3
+ * Return only the ToolSchemas whose gating skill is in the active set.
4
+ * Must be called on every tool call (not just catalog build) so mid-run
5
+ * skill removal disables helpers immediately.
6
+ */
7
+ function filterByActiveSkills(helpers, activeSkills) {
8
+ return helpers.filter((h) => activeSkills.has(h.skill)).map((h) => h.schema);
9
+ }
10
+ /**
11
+ * Merge local tools with active skill helpers. When a skill helper has the
12
+ * same name as a local tool, the helper wins (shadow) and a warning is emitted.
13
+ */
14
+ function mergeWithShadowing(tools, activeHelpers) {
15
+ const warnings = [];
16
+ const helperNames = new Set(activeHelpers.map((h) => h.name));
17
+ const merged = [];
18
+ for (const tool of tools) {
19
+ if (helperNames.has(tool.name)) {
20
+ const helper = activeHelpers.find((h) => h.name === tool.name);
21
+ warnings.push(`tool_shadow: "${tool.name}" from ${tool.filePath} shadowed by skill helper ${helper.filePath}`);
22
+ continue;
23
+ }
24
+ merged.push(tool);
25
+ }
26
+ merged.push(...activeHelpers);
27
+ return {
28
+ merged,
29
+ warnings
30
+ };
31
+ }
32
+
33
+ //#endregion
34
+ export { filterByActiveSkills, mergeWithShadowing };
35
+ //# sourceMappingURL=skill-gate.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-gate.mjs","names":[],"sources":["../../../src/program/tool-discovery/skill-gate.ts"],"sourcesContent":["/**\n * Skill-gated helper filter (S13).\n *\n * Runtime filter that intersects the full helper catalog with the active $skills set.\n * Pure function; no I/O.\n */\n\nimport type { ToolSchema } from \"./ash-frontmatter.js\";\n\nexport interface SkillHelper {\n skill: string;\n schema: ToolSchema;\n}\n\n/**\n * Return only the ToolSchemas whose gating skill is in the active set.\n * Must be called on every tool call (not just catalog build) so mid-run\n * skill removal disables helpers immediately.\n */\nexport function filterByActiveSkills(\n helpers: SkillHelper[],\n activeSkills: Set<string>,\n): ToolSchema[] {\n return helpers.filter((h) => activeSkills.has(h.skill)).map((h) => h.schema);\n}\n\n/**\n * Merge local tools with active skill helpers. When a skill helper has the\n * same name as a local tool, the helper wins (shadow) and a warning is emitted.\n */\nexport function mergeWithShadowing(\n tools: ToolSchema[],\n activeHelpers: ToolSchema[],\n): { merged: ToolSchema[]; warnings: string[] } {\n const warnings: string[] = [];\n const helperNames = new Set(activeHelpers.map((h) => h.name));\n const merged: ToolSchema[] = [];\n\n for (const tool of tools) {\n if (helperNames.has(tool.name)) {\n const helper = activeHelpers.find((h) => h.name === tool.name)!;\n warnings.push(\n `tool_shadow: \"${tool.name}\" from ${tool.filePath} shadowed by skill helper ${helper.filePath}`,\n );\n continue;\n }\n merged.push(tool);\n }\n\n merged.push(...activeHelpers);\n return { merged, warnings };\n}\n"],"mappings":";;;;;;AAmBA,SAAgB,qBACd,SACA,cACc;AACd,QAAO,QAAQ,QAAQ,MAAM,aAAa,IAAI,EAAE,MAAM,CAAC,CAAC,KAAK,MAAM,EAAE,OAAO;;;;;;AAO9E,SAAgB,mBACd,OACA,eAC8C;CAC9C,MAAM,WAAqB,EAAE;CAC7B,MAAM,cAAc,IAAI,IAAI,cAAc,KAAK,MAAM,EAAE,KAAK,CAAC;CAC7D,MAAM,SAAuB,EAAE;AAE/B,MAAK,MAAM,QAAQ,OAAO;AACxB,MAAI,YAAY,IAAI,KAAK,KAAK,EAAE;GAC9B,MAAM,SAAS,cAAc,MAAM,MAAM,EAAE,SAAS,KAAK,KAAK;AAC9D,YAAS,KACP,iBAAiB,KAAK,KAAK,SAAS,KAAK,SAAS,4BAA4B,OAAO,WACtF;AACD;;AAEF,SAAO,KAAK,KAAK;;AAGnB,QAAO,KAAK,GAAG,cAAc;AAC7B,QAAO;EAAE;EAAQ;EAAU"}