@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,272 @@
1
+ const require_index = require('../providers/basic/ash/dist/index.cjs');
2
+ let ufo = require("ufo");
3
+ let _aigne_ash = require("@aigne/ash");
4
+
5
+ //#region src/agent-runners/ash-runner.ts
6
+ const MAX_FANOUT_BRANCHES = 100;
7
+ function normalizeToolEntries(manifest) {
8
+ return (manifest.tools ?? []).map((t) => {
9
+ if (typeof t === "string") return {
10
+ path: t,
11
+ ops: ["read", "exec"]
12
+ };
13
+ return {
14
+ path: t.path,
15
+ ops: t.ops ?? ["read", "exec"],
16
+ maxDepth: t.maxDepth
17
+ };
18
+ });
19
+ }
20
+ function collectActionPaths(source) {
21
+ const paths = [];
22
+ for (const m of source.matchAll(/\baction\s+(\/[^\s{]+)/g)) paths.push(m[1]);
23
+ return paths;
24
+ }
25
+ function countFanoutBranches(source) {
26
+ let count = 0;
27
+ let depth = 0;
28
+ let inFanout = false;
29
+ const tokens = source.split(/(\bfanout\b|\{|\}|,)/);
30
+ for (const token of tokens) if (token === "fanout") inFanout = true;
31
+ else if (token === "{" && inFanout) {
32
+ depth++;
33
+ if (depth === 1) count = 1;
34
+ } else if (token === "}" && inFanout && depth > 0) {
35
+ depth--;
36
+ if (depth === 0) inFanout = false;
37
+ } else if (token === "," && inFanout && depth === 1) count++;
38
+ return count;
39
+ }
40
+ async function runAshAgent(opts) {
41
+ const { afs, manifest, input, session, mountPath } = opts;
42
+ const inputKey = manifest.inputKey ?? "message";
43
+ const outputKey = manifest.outputKey;
44
+ const scriptFile = manifest.script ?? "pipeline.ash";
45
+ const candidatePaths = [(0, ufo.joinURL)(mountPath, scriptFile), (0, ufo.joinURL)("/packages", scriptFile)];
46
+ let scriptSource;
47
+ let lastPathTried = candidatePaths[0];
48
+ for (const candidate of candidatePaths) {
49
+ lastPathTried = candidate;
50
+ try {
51
+ const raw = await afs.read(candidate);
52
+ const content = typeof raw === "string" ? raw : String(raw?.data?.content ?? raw?.data ?? raw ?? "");
53
+ if (content) {
54
+ scriptSource = content;
55
+ break;
56
+ }
57
+ } catch {}
58
+ }
59
+ if (!scriptSource) return {
60
+ success: false,
61
+ error: {
62
+ code: "SCRIPT_NOT_FOUND",
63
+ message: `Cannot read script at ${lastPathTried}`
64
+ }
65
+ };
66
+ const childTools = normalizeToolEntries(manifest);
67
+ const scope = opts.afs.scope;
68
+ const tools = scope ? [...scope.allowedTools] : childTools;
69
+ const actionPaths = collectActionPaths(scriptSource);
70
+ for (const actionPath of actionPaths) {
71
+ if (actionPath.includes("${")) continue;
72
+ const check = require_index.validateActionPath(actionPath, tools);
73
+ if (!check.allowed) return {
74
+ success: false,
75
+ error: {
76
+ code: check.code,
77
+ message: check.reason,
78
+ path: check.path
79
+ }
80
+ };
81
+ }
82
+ const branchCount = countFanoutBranches(scriptSource);
83
+ if (branchCount > MAX_FANOUT_BRANCHES) return {
84
+ success: false,
85
+ error: {
86
+ code: "FANOUT_LIMIT",
87
+ message: `Fanout has ${branchCount} branches, exceeding limit of ${MAX_FANOUT_BRANCHES}`
88
+ }
89
+ };
90
+ let compiled;
91
+ try {
92
+ compiled = (0, _aigne_ash.compileSource)(scriptSource);
93
+ } catch (e) {
94
+ return {
95
+ success: false,
96
+ error: {
97
+ code: "ASH_COMPILE_ERROR",
98
+ message: e.message ?? String(e)
99
+ }
100
+ };
101
+ }
102
+ const errors = compiled.diagnostics.filter((d) => !d.severity || d.severity === "error");
103
+ if (errors.length > 0) {
104
+ const traversal = errors.find((d) => /path traversal/i.test(d.message ?? ""));
105
+ if (traversal) return {
106
+ success: false,
107
+ error: {
108
+ code: "PATH_TRAVERSAL",
109
+ message: traversal.message
110
+ }
111
+ };
112
+ return {
113
+ success: false,
114
+ error: {
115
+ code: "ASH_COMPILE_ERROR",
116
+ message: errors.map((d) => `${d.code}: ${d.message}`).join("; ")
117
+ }
118
+ };
119
+ }
120
+ if (!compiled.program) return {
121
+ success: false,
122
+ error: {
123
+ code: "ASH_COMPILE_ERROR",
124
+ message: "Compilation produced no program"
125
+ }
126
+ };
127
+ const program = compiled.program;
128
+ const inputValue = input[inputKey];
129
+ if (inputValue !== void 0) {
130
+ if (typeof inputValue === "string" || typeof inputValue === "number") program.params.set("input", inputValue);
131
+ }
132
+ if (typeof inputValue === "object" && inputValue !== null) {
133
+ for (const [k, v] of Object.entries(inputValue)) if (typeof v === "string" || typeof v === "number") program.params.set(`input.${k}`, v);
134
+ else if (Array.isArray(v)) program.params.set(`input.${k}`, v);
135
+ }
136
+ const writeCollector = {};
137
+ let lastWriteData = null;
138
+ const resolveReadPath = (path) => {
139
+ if (!path.startsWith("./") && !path.startsWith("../")) return path;
140
+ const resolved = (0, ufo.joinURL)(mountPath, path);
141
+ const mountNormalized = mountPath.endsWith("/") ? mountPath : `${mountPath}/`;
142
+ if (resolved !== mountPath && !resolved.startsWith(mountNormalized)) throw new Error(`PATH_TRAVERSAL: ${path} escapes mountPath ${mountPath}`);
143
+ return resolved;
144
+ };
145
+ const ctx = {
146
+ world: {
147
+ read: async (path) => {
148
+ const resolved = resolveReadPath(path);
149
+ const check = require_index.validateToolCall(resolved, "read", tools);
150
+ if (!check.allowed) throw new Error(`TOOL_WHITELIST_VIOLATION: ${check.reason}`);
151
+ const data = await afs.read(resolved);
152
+ if (Array.isArray(data)) return data;
153
+ if (data && typeof data === "object" && "list" in data) return data.list ?? [];
154
+ if (data && typeof data === "object" && "data" in data) {
155
+ const inner = data.data;
156
+ if (Array.isArray(inner)) return inner;
157
+ return inner != null ? [inner] : [];
158
+ }
159
+ return data != null ? [data] : [];
160
+ },
161
+ write: (path, data) => {
162
+ writeCollector[path] = data;
163
+ lastWriteData = data;
164
+ if (!path.startsWith("/output/") && !path.startsWith("$")) {
165
+ const check = require_index.validateToolCall(path, "write", tools);
166
+ if (!check.allowed) throw new Error(`TOOL_WHITELIST_VIOLATION: ${check.reason}`);
167
+ afs.write?.(path, { content: data }).catch(() => {});
168
+ }
169
+ },
170
+ publish: () => {},
171
+ exec: async (path, _input, params) => {
172
+ const check = require_index.validateActionPath(path, tools);
173
+ if (!check.allowed) throw new Error(`TOOL_WHITELIST_VIOLATION: ${check.reason}`);
174
+ const result = await afs.exec(path, params ?? {}, {});
175
+ if (result == null) return [];
176
+ if (typeof result === "object" && "data" in result) {
177
+ const d = result.data;
178
+ if (Array.isArray(d)) return d;
179
+ return d != null ? [d] : [];
180
+ }
181
+ return Array.isArray(result) ? result : [result];
182
+ }
183
+ },
184
+ caps: new Set(["*"]),
185
+ logger: { log: (_stage, _action, _detail) => {} }
186
+ };
187
+ let totalSteps = 0;
188
+ try {
189
+ for (const job of program.jobs) {
190
+ if (program.routeTargets?.has(job.name)) continue;
191
+ const result = await job.execute(ctx);
192
+ totalSteps += result.recordCount || 1;
193
+ if (result.status === "error") {
194
+ const whitelist = result.errors.find((message) => message.startsWith("TOOL_WHITELIST_VIOLATION"));
195
+ if (whitelist) return {
196
+ success: false,
197
+ error: {
198
+ code: "TOOL_WHITELIST_VIOLATION",
199
+ message: whitelist
200
+ },
201
+ _meta: {
202
+ pipeline_steps: totalSteps,
203
+ session
204
+ }
205
+ };
206
+ return {
207
+ success: false,
208
+ error: {
209
+ code: "ASH_RUNTIME_ERROR",
210
+ message: result.errors.join("; ")
211
+ },
212
+ _meta: {
213
+ pipeline_steps: totalSteps,
214
+ session
215
+ }
216
+ };
217
+ }
218
+ }
219
+ } catch (e) {
220
+ const message = e?.message ?? String(e);
221
+ if (typeof message === "string" && message.startsWith("PATH_TRAVERSAL")) return {
222
+ success: false,
223
+ error: {
224
+ code: "PATH_TRAVERSAL",
225
+ message
226
+ },
227
+ _meta: {
228
+ pipeline_steps: totalSteps,
229
+ session
230
+ }
231
+ };
232
+ if (typeof message === "string" && message.startsWith("TOOL_WHITELIST_VIOLATION")) return {
233
+ success: false,
234
+ error: {
235
+ code: "TOOL_WHITELIST_VIOLATION",
236
+ message
237
+ },
238
+ _meta: {
239
+ pipeline_steps: totalSteps,
240
+ session
241
+ }
242
+ };
243
+ return {
244
+ success: false,
245
+ error: {
246
+ code: "ASH_RUNTIME_ERROR",
247
+ message
248
+ },
249
+ _meta: {
250
+ pipeline_steps: totalSteps,
251
+ session
252
+ }
253
+ };
254
+ }
255
+ let finalData;
256
+ if (outputKey && writeCollector[(0, ufo.joinURL)("/output", outputKey)]) finalData = writeCollector[(0, ufo.joinURL)("/output", outputKey)];
257
+ else if (lastWriteData != null) finalData = lastWriteData;
258
+ else finalData = null;
259
+ const ashResult = {
260
+ success: true,
261
+ data: { result: finalData },
262
+ _meta: {
263
+ pipeline_steps: totalSteps,
264
+ session
265
+ }
266
+ };
267
+ if (outputKey && finalData != null) ashResult.result = { [outputKey]: finalData };
268
+ return ashResult;
269
+ }
270
+
271
+ //#endregion
272
+ exports.runAshAgent = runAshAgent;
@@ -0,0 +1,30 @@
1
+ import { AFSRoot, AgentManifest } from "@aigne/afs";
2
+
3
+ //#region src/agent-runners/ash-runner.d.ts
4
+ interface AshRunnerInput {
5
+ afs: AFSRoot;
6
+ manifest: AgentManifest;
7
+ input: Record<string, unknown>;
8
+ session?: string;
9
+ parentSession?: string;
10
+ chain?: string[];
11
+ mountPath: string;
12
+ }
13
+ interface AshRunnerResult {
14
+ success: boolean;
15
+ data?: Record<string, unknown>;
16
+ result?: Record<string, unknown>;
17
+ error?: {
18
+ code: string;
19
+ message: string;
20
+ path?: string;
21
+ };
22
+ _meta?: {
23
+ pipeline_steps: number;
24
+ session?: string;
25
+ };
26
+ }
27
+ declare function runAshAgent(opts: AshRunnerInput): Promise<AshRunnerResult>;
28
+ //#endregion
29
+ export { AshRunnerInput, AshRunnerResult, runAshAgent };
30
+ //# sourceMappingURL=ash-runner.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ash-runner.d.cts","names":[],"sources":["../../src/agent-runners/ash-runner.ts"],"mappings":";;;UAWiB,cAAA;EACf,GAAA,EAAK,OAAA;EACL,QAAA,EAAU,aAAA;EACV,KAAA,EAAO,MAAA;EACP,OAAA;EACA,aAAA;EACA,KAAA;EACA,SAAA;AAAA;AAAA,UAGe,eAAA;EACf,OAAA;EACA,IAAA,GAAO,MAAA;EACP,MAAA,GAAS,MAAA;EACT,KAAA;IAAU,IAAA;IAAc,OAAA;IAAiB,IAAA;EAAA;EACzC,KAAA;IACE,cAAA;IACA,OAAA;EAAA;AAAA;AAAA,iBA4CkB,WAAA,CAAY,IAAA,EAAM,cAAA,GAAiB,OAAA,CAAQ,eAAA"}
@@ -0,0 +1,30 @@
1
+ import { AFSRoot, AgentManifest } from "@aigne/afs";
2
+
3
+ //#region src/agent-runners/ash-runner.d.ts
4
+ interface AshRunnerInput {
5
+ afs: AFSRoot;
6
+ manifest: AgentManifest;
7
+ input: Record<string, unknown>;
8
+ session?: string;
9
+ parentSession?: string;
10
+ chain?: string[];
11
+ mountPath: string;
12
+ }
13
+ interface AshRunnerResult {
14
+ success: boolean;
15
+ data?: Record<string, unknown>;
16
+ result?: Record<string, unknown>;
17
+ error?: {
18
+ code: string;
19
+ message: string;
20
+ path?: string;
21
+ };
22
+ _meta?: {
23
+ pipeline_steps: number;
24
+ session?: string;
25
+ };
26
+ }
27
+ declare function runAshAgent(opts: AshRunnerInput): Promise<AshRunnerResult>;
28
+ //#endregion
29
+ export { AshRunnerInput, AshRunnerResult, runAshAgent };
30
+ //# sourceMappingURL=ash-runner.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ash-runner.d.mts","names":[],"sources":["../../src/agent-runners/ash-runner.ts"],"mappings":";;;UAWiB,cAAA;EACf,GAAA,EAAK,OAAA;EACL,QAAA,EAAU,aAAA;EACV,KAAA,EAAO,MAAA;EACP,OAAA;EACA,aAAA;EACA,KAAA;EACA,SAAA;AAAA;AAAA,UAGe,eAAA;EACf,OAAA;EACA,IAAA,GAAO,MAAA;EACP,MAAA,GAAS,MAAA;EACT,KAAA;IAAU,IAAA;IAAc,OAAA;IAAiB,IAAA;EAAA;EACzC,KAAA;IACE,cAAA;IACA,OAAA;EAAA;AAAA;AAAA,iBA4CkB,WAAA,CAAY,IAAA,EAAM,cAAA,GAAiB,OAAA,CAAQ,eAAA"}
@@ -0,0 +1,273 @@
1
+ import { validateActionPath, validateToolCall } from "../providers/basic/ash/dist/index.mjs";
2
+ import { joinURL } from "ufo";
3
+ import { compileSource } from "@aigne/ash";
4
+
5
+ //#region src/agent-runners/ash-runner.ts
6
+ const MAX_FANOUT_BRANCHES = 100;
7
+ function normalizeToolEntries(manifest) {
8
+ return (manifest.tools ?? []).map((t) => {
9
+ if (typeof t === "string") return {
10
+ path: t,
11
+ ops: ["read", "exec"]
12
+ };
13
+ return {
14
+ path: t.path,
15
+ ops: t.ops ?? ["read", "exec"],
16
+ maxDepth: t.maxDepth
17
+ };
18
+ });
19
+ }
20
+ function collectActionPaths(source) {
21
+ const paths = [];
22
+ for (const m of source.matchAll(/\baction\s+(\/[^\s{]+)/g)) paths.push(m[1]);
23
+ return paths;
24
+ }
25
+ function countFanoutBranches(source) {
26
+ let count = 0;
27
+ let depth = 0;
28
+ let inFanout = false;
29
+ const tokens = source.split(/(\bfanout\b|\{|\}|,)/);
30
+ for (const token of tokens) if (token === "fanout") inFanout = true;
31
+ else if (token === "{" && inFanout) {
32
+ depth++;
33
+ if (depth === 1) count = 1;
34
+ } else if (token === "}" && inFanout && depth > 0) {
35
+ depth--;
36
+ if (depth === 0) inFanout = false;
37
+ } else if (token === "," && inFanout && depth === 1) count++;
38
+ return count;
39
+ }
40
+ async function runAshAgent(opts) {
41
+ const { afs, manifest, input, session, mountPath } = opts;
42
+ const inputKey = manifest.inputKey ?? "message";
43
+ const outputKey = manifest.outputKey;
44
+ const scriptFile = manifest.script ?? "pipeline.ash";
45
+ const candidatePaths = [joinURL(mountPath, scriptFile), joinURL("/packages", scriptFile)];
46
+ let scriptSource;
47
+ let lastPathTried = candidatePaths[0];
48
+ for (const candidate of candidatePaths) {
49
+ lastPathTried = candidate;
50
+ try {
51
+ const raw = await afs.read(candidate);
52
+ const content = typeof raw === "string" ? raw : String(raw?.data?.content ?? raw?.data ?? raw ?? "");
53
+ if (content) {
54
+ scriptSource = content;
55
+ break;
56
+ }
57
+ } catch {}
58
+ }
59
+ if (!scriptSource) return {
60
+ success: false,
61
+ error: {
62
+ code: "SCRIPT_NOT_FOUND",
63
+ message: `Cannot read script at ${lastPathTried}`
64
+ }
65
+ };
66
+ const childTools = normalizeToolEntries(manifest);
67
+ const scope = opts.afs.scope;
68
+ const tools = scope ? [...scope.allowedTools] : childTools;
69
+ const actionPaths = collectActionPaths(scriptSource);
70
+ for (const actionPath of actionPaths) {
71
+ if (actionPath.includes("${")) continue;
72
+ const check = validateActionPath(actionPath, tools);
73
+ if (!check.allowed) return {
74
+ success: false,
75
+ error: {
76
+ code: check.code,
77
+ message: check.reason,
78
+ path: check.path
79
+ }
80
+ };
81
+ }
82
+ const branchCount = countFanoutBranches(scriptSource);
83
+ if (branchCount > MAX_FANOUT_BRANCHES) return {
84
+ success: false,
85
+ error: {
86
+ code: "FANOUT_LIMIT",
87
+ message: `Fanout has ${branchCount} branches, exceeding limit of ${MAX_FANOUT_BRANCHES}`
88
+ }
89
+ };
90
+ let compiled;
91
+ try {
92
+ compiled = compileSource(scriptSource);
93
+ } catch (e) {
94
+ return {
95
+ success: false,
96
+ error: {
97
+ code: "ASH_COMPILE_ERROR",
98
+ message: e.message ?? String(e)
99
+ }
100
+ };
101
+ }
102
+ const errors = compiled.diagnostics.filter((d) => !d.severity || d.severity === "error");
103
+ if (errors.length > 0) {
104
+ const traversal = errors.find((d) => /path traversal/i.test(d.message ?? ""));
105
+ if (traversal) return {
106
+ success: false,
107
+ error: {
108
+ code: "PATH_TRAVERSAL",
109
+ message: traversal.message
110
+ }
111
+ };
112
+ return {
113
+ success: false,
114
+ error: {
115
+ code: "ASH_COMPILE_ERROR",
116
+ message: errors.map((d) => `${d.code}: ${d.message}`).join("; ")
117
+ }
118
+ };
119
+ }
120
+ if (!compiled.program) return {
121
+ success: false,
122
+ error: {
123
+ code: "ASH_COMPILE_ERROR",
124
+ message: "Compilation produced no program"
125
+ }
126
+ };
127
+ const program = compiled.program;
128
+ const inputValue = input[inputKey];
129
+ if (inputValue !== void 0) {
130
+ if (typeof inputValue === "string" || typeof inputValue === "number") program.params.set("input", inputValue);
131
+ }
132
+ if (typeof inputValue === "object" && inputValue !== null) {
133
+ for (const [k, v] of Object.entries(inputValue)) if (typeof v === "string" || typeof v === "number") program.params.set(`input.${k}`, v);
134
+ else if (Array.isArray(v)) program.params.set(`input.${k}`, v);
135
+ }
136
+ const writeCollector = {};
137
+ let lastWriteData = null;
138
+ const resolveReadPath = (path) => {
139
+ if (!path.startsWith("./") && !path.startsWith("../")) return path;
140
+ const resolved = joinURL(mountPath, path);
141
+ const mountNormalized = mountPath.endsWith("/") ? mountPath : `${mountPath}/`;
142
+ if (resolved !== mountPath && !resolved.startsWith(mountNormalized)) throw new Error(`PATH_TRAVERSAL: ${path} escapes mountPath ${mountPath}`);
143
+ return resolved;
144
+ };
145
+ const ctx = {
146
+ world: {
147
+ read: async (path) => {
148
+ const resolved = resolveReadPath(path);
149
+ const check = validateToolCall(resolved, "read", tools);
150
+ if (!check.allowed) throw new Error(`TOOL_WHITELIST_VIOLATION: ${check.reason}`);
151
+ const data = await afs.read(resolved);
152
+ if (Array.isArray(data)) return data;
153
+ if (data && typeof data === "object" && "list" in data) return data.list ?? [];
154
+ if (data && typeof data === "object" && "data" in data) {
155
+ const inner = data.data;
156
+ if (Array.isArray(inner)) return inner;
157
+ return inner != null ? [inner] : [];
158
+ }
159
+ return data != null ? [data] : [];
160
+ },
161
+ write: (path, data) => {
162
+ writeCollector[path] = data;
163
+ lastWriteData = data;
164
+ if (!path.startsWith("/output/") && !path.startsWith("$")) {
165
+ const check = validateToolCall(path, "write", tools);
166
+ if (!check.allowed) throw new Error(`TOOL_WHITELIST_VIOLATION: ${check.reason}`);
167
+ afs.write?.(path, { content: data }).catch(() => {});
168
+ }
169
+ },
170
+ publish: () => {},
171
+ exec: async (path, _input, params) => {
172
+ const check = validateActionPath(path, tools);
173
+ if (!check.allowed) throw new Error(`TOOL_WHITELIST_VIOLATION: ${check.reason}`);
174
+ const result = await afs.exec(path, params ?? {}, {});
175
+ if (result == null) return [];
176
+ if (typeof result === "object" && "data" in result) {
177
+ const d = result.data;
178
+ if (Array.isArray(d)) return d;
179
+ return d != null ? [d] : [];
180
+ }
181
+ return Array.isArray(result) ? result : [result];
182
+ }
183
+ },
184
+ caps: new Set(["*"]),
185
+ logger: { log: (_stage, _action, _detail) => {} }
186
+ };
187
+ let totalSteps = 0;
188
+ try {
189
+ for (const job of program.jobs) {
190
+ if (program.routeTargets?.has(job.name)) continue;
191
+ const result = await job.execute(ctx);
192
+ totalSteps += result.recordCount || 1;
193
+ if (result.status === "error") {
194
+ const whitelist = result.errors.find((message) => message.startsWith("TOOL_WHITELIST_VIOLATION"));
195
+ if (whitelist) return {
196
+ success: false,
197
+ error: {
198
+ code: "TOOL_WHITELIST_VIOLATION",
199
+ message: whitelist
200
+ },
201
+ _meta: {
202
+ pipeline_steps: totalSteps,
203
+ session
204
+ }
205
+ };
206
+ return {
207
+ success: false,
208
+ error: {
209
+ code: "ASH_RUNTIME_ERROR",
210
+ message: result.errors.join("; ")
211
+ },
212
+ _meta: {
213
+ pipeline_steps: totalSteps,
214
+ session
215
+ }
216
+ };
217
+ }
218
+ }
219
+ } catch (e) {
220
+ const message = e?.message ?? String(e);
221
+ if (typeof message === "string" && message.startsWith("PATH_TRAVERSAL")) return {
222
+ success: false,
223
+ error: {
224
+ code: "PATH_TRAVERSAL",
225
+ message
226
+ },
227
+ _meta: {
228
+ pipeline_steps: totalSteps,
229
+ session
230
+ }
231
+ };
232
+ if (typeof message === "string" && message.startsWith("TOOL_WHITELIST_VIOLATION")) return {
233
+ success: false,
234
+ error: {
235
+ code: "TOOL_WHITELIST_VIOLATION",
236
+ message
237
+ },
238
+ _meta: {
239
+ pipeline_steps: totalSteps,
240
+ session
241
+ }
242
+ };
243
+ return {
244
+ success: false,
245
+ error: {
246
+ code: "ASH_RUNTIME_ERROR",
247
+ message
248
+ },
249
+ _meta: {
250
+ pipeline_steps: totalSteps,
251
+ session
252
+ }
253
+ };
254
+ }
255
+ let finalData;
256
+ if (outputKey && writeCollector[joinURL("/output", outputKey)]) finalData = writeCollector[joinURL("/output", outputKey)];
257
+ else if (lastWriteData != null) finalData = lastWriteData;
258
+ else finalData = null;
259
+ const ashResult = {
260
+ success: true,
261
+ data: { result: finalData },
262
+ _meta: {
263
+ pipeline_steps: totalSteps,
264
+ session
265
+ }
266
+ };
267
+ if (outputKey && finalData != null) ashResult.result = { [outputKey]: finalData };
268
+ return ashResult;
269
+ }
270
+
271
+ //#endregion
272
+ export { runAshAgent };
273
+ //# sourceMappingURL=ash-runner.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ash-runner.mjs","names":[],"sources":["../../src/agent-runners/ash-runner.ts"],"sourcesContent":["import type { AFSRoot, AgentManifest } from \"@aigne/afs\";\nimport { type ToolEntry, validateActionPath, validateToolCall } from \"@aigne/afs-ash\";\nimport {\n type CompileResult,\n compileSource,\n type JobContext,\n type WorldInterface,\n} from \"@aigne/ash\";\nimport { joinURL } from \"ufo\";\nimport type { AgentScope } from \"../program/scoped-afs.js\";\n\nexport interface AshRunnerInput {\n afs: AFSRoot;\n manifest: AgentManifest;\n input: Record<string, unknown>;\n session?: string;\n parentSession?: string;\n chain?: string[];\n mountPath: string;\n}\n\nexport interface AshRunnerResult {\n success: boolean;\n data?: Record<string, unknown>;\n result?: Record<string, unknown>;\n error?: { code: string; message: string; path?: string };\n _meta?: {\n pipeline_steps: number;\n session?: string;\n };\n}\n\nconst MAX_FANOUT_BRANCHES = 100;\n\nfunction normalizeToolEntries(manifest: AgentManifest): ToolEntry[] {\n return (manifest.tools ?? []).map((t) => {\n if (typeof t === \"string\") return { path: t, ops: [\"read\", \"exec\"] };\n return { path: t.path, ops: t.ops ?? [\"read\", \"exec\"], maxDepth: t.maxDepth };\n });\n}\n\nfunction collectActionPaths(source: string): string[] {\n const paths: string[] = [];\n const actionRegex = /\\baction\\s+(\\/[^\\s{]+)/g;\n for (const m of source.matchAll(actionRegex)) {\n paths.push(m[1]!);\n }\n return paths;\n}\n\nfunction countFanoutBranches(source: string): number {\n // Count comma-separated branches inside fanout { ... }\n // Each branch is a pipeline separated by commas\n let count = 0;\n let depth = 0;\n let inFanout = false;\n const tokens = source.split(/(\\bfanout\\b|\\{|\\}|,)/);\n for (const token of tokens) {\n if (token === \"fanout\") inFanout = true;\n else if (token === \"{\" && inFanout) {\n depth++;\n if (depth === 1) count = 1; // first branch\n } else if (token === \"}\" && inFanout && depth > 0) {\n depth--;\n if (depth === 0) inFanout = false;\n } else if (token === \",\" && inFanout && depth === 1) {\n count++;\n }\n }\n return count;\n}\n\nexport async function runAshAgent(opts: AshRunnerInput): Promise<AshRunnerResult> {\n const { afs, manifest, input, session, mountPath } = opts;\n\n const inputKey = manifest.inputKey ?? \"message\";\n const outputKey = manifest.outputKey;\n const scriptFile = manifest.script ?? \"pipeline.ash\";\n\n // B12: Runtime AFS projects the blocklet directory at /packages; the\n // external mountPath (/blocklets/<id>) isn't a valid internal path after\n // activation. Try mountPath first (works in tests + pre-activation),\n // fall back to /packages (production post-activation).\n const candidatePaths = [joinURL(mountPath, scriptFile), joinURL(\"/packages\", scriptFile)];\n\n let scriptSource: string | undefined;\n let lastPathTried = candidatePaths[0]!;\n for (const candidate of candidatePaths) {\n lastPathTried = candidate;\n try {\n const raw = await afs.read!(candidate);\n const content =\n typeof raw === \"string\"\n ? raw\n : String((raw as any)?.data?.content ?? raw?.data ?? raw ?? \"\");\n if (content) {\n scriptSource = content;\n break;\n }\n } catch {\n // Try next candidate\n }\n }\n\n if (!scriptSource) {\n return {\n success: false,\n error: { code: \"SCRIPT_NOT_FOUND\", message: `Cannot read script at ${lastPathTried}` },\n };\n }\n\n const childTools = normalizeToolEntries(manifest);\n // Phase 6 — `scope.allowedTools` is the single source of truth for the\n // whitelist. `projectForChild` already intersected parent + child tools,\n // so the runner just reads it. Callers that bypass projection fall back\n // to the manifest's own tools.\n const scope = (opts.afs as AgentScope).scope;\n const tools: ToolEntry[] = scope ? [...scope.allowedTools] : childTools;\n\n // Pre-compile: check action paths against whitelist\n const actionPaths = collectActionPaths(scriptSource);\n for (const actionPath of actionPaths) {\n if (actionPath.includes(\"${\")) continue;\n const check = validateActionPath(actionPath, tools);\n if (!check.allowed) {\n return {\n success: false,\n error: { code: check.code!, message: check.reason!, path: check.path },\n };\n }\n }\n\n // Pre-compile: fanout branch limit\n const branchCount = countFanoutBranches(scriptSource);\n if (branchCount > MAX_FANOUT_BRANCHES) {\n return {\n success: false,\n error: {\n code: \"FANOUT_LIMIT\",\n message: `Fanout has ${branchCount} branches, exceeding limit of ${MAX_FANOUT_BRANCHES}`,\n },\n };\n }\n\n // Compile\n let compiled: CompileResult;\n try {\n compiled = compileSource(scriptSource);\n } catch (e: any) {\n return {\n success: false,\n error: { code: \"ASH_COMPILE_ERROR\", message: e.message ?? String(e) },\n };\n }\n\n const errors = compiled.diagnostics.filter((d) => !d.severity || d.severity === \"error\");\n if (errors.length > 0) {\n // B12: path-traversal diagnostics (from ash type-checker's `..` rejection)\n // surface as PATH_TRAVERSAL so consumers can distinguish them from general\n // compile errors.\n const traversal = errors.find((d) => /path traversal/i.test(d.message ?? \"\"));\n if (traversal) {\n return {\n success: false,\n error: { code: \"PATH_TRAVERSAL\", message: traversal.message },\n };\n }\n return {\n success: false,\n error: {\n code: \"ASH_COMPILE_ERROR\",\n message: errors.map((d) => `${d.code}: ${d.message}`).join(\"; \"),\n },\n };\n }\n\n if (!compiled.program) {\n return {\n success: false,\n error: { code: \"ASH_COMPILE_ERROR\", message: \"Compilation produced no program\" },\n };\n }\n\n const program = compiled.program;\n\n // Bind $input into params\n const inputValue = input[inputKey];\n if (inputValue !== undefined) {\n if (typeof inputValue === \"string\" || typeof inputValue === \"number\") {\n program.params.set(\"input\", inputValue);\n }\n }\n if (typeof inputValue === \"object\" && inputValue !== null) {\n for (const [k, v] of Object.entries(inputValue as Record<string, unknown>)) {\n if (typeof v === \"string\" || typeof v === \"number\") {\n program.params.set(`input.${k}`, v);\n } else if (Array.isArray(v)) {\n program.params.set(`input.${k}`, v as (string | number)[]);\n }\n }\n }\n\n // Write collector: captures save/tee writes for output\n const writeCollector: Record<string, unknown[]> = {};\n let lastWriteData: unknown[] | null = null;\n\n // B12: Resolve blocklet-relative paths (`./foo`, `../foo`) against mountPath.\n // Reject resolved paths that escape mountPath with a PATH_TRAVERSAL marker so\n // caller can surface the structured error instead of a silent empty array.\n const resolveReadPath = (path: string): string => {\n if (!path.startsWith(\"./\") && !path.startsWith(\"../\")) return path;\n const resolved = joinURL(mountPath, path);\n const mountNormalized = mountPath.endsWith(\"/\") ? mountPath : `${mountPath}/`;\n if (resolved !== mountPath && !resolved.startsWith(mountNormalized)) {\n throw new Error(`PATH_TRAVERSAL: ${path} escapes mountPath ${mountPath}`);\n }\n return resolved;\n };\n\n const world: WorldInterface = {\n read: async (path: string): Promise<unknown[]> => {\n const resolved = resolveReadPath(path);\n const check = validateToolCall(resolved, \"read\", tools);\n if (!check.allowed) {\n throw new Error(`TOOL_WHITELIST_VIOLATION: ${check.reason}`);\n }\n const data = await afs.read!(resolved);\n if (Array.isArray(data)) return data;\n if (data && typeof data === \"object\" && \"list\" in (data as any)) {\n return ((data as any).list ?? []) as unknown[];\n }\n if (data && typeof data === \"object\" && \"data\" in (data as any)) {\n const inner = (data as any).data;\n if (Array.isArray(inner)) return inner;\n return inner != null ? [inner] : [];\n }\n return data != null ? [data] : [];\n },\n\n write: (path: string, data: unknown[]): void => {\n writeCollector[path] = data;\n lastWriteData = data;\n // Forward non-output writes to AFS\n if (!path.startsWith(\"/output/\") && !path.startsWith(\"$\")) {\n const check = validateToolCall(path, \"write\", tools);\n if (!check.allowed) {\n throw new Error(`TOOL_WHITELIST_VIOLATION: ${check.reason}`);\n }\n afs.write?.(path, { content: data } as any).catch(() => {});\n }\n },\n\n publish: (): void => {},\n\n exec: async (\n path: string,\n _input: unknown[],\n params?: Record<string, unknown>,\n ): Promise<unknown[]> => {\n const check = validateActionPath(path, tools);\n if (!check.allowed) {\n throw new Error(`TOOL_WHITELIST_VIOLATION: ${check.reason}`);\n }\n\n const result = await afs.exec!(path, params ?? {}, {});\n if (result == null) return [];\n if (typeof result === \"object\" && \"data\" in result) {\n const d = (result as any).data;\n if (Array.isArray(d)) return d;\n return d != null ? [d] : [];\n }\n return Array.isArray(result) ? result : [result];\n },\n };\n\n const logger = {\n log: (_stage: string, _action: string, _detail?: unknown) => {},\n };\n\n const ctx: JobContext = {\n world,\n caps: new Set([\"*\"]),\n logger,\n };\n\n let totalSteps = 0;\n\n try {\n for (const job of program.jobs) {\n if (program.routeTargets?.has(job.name)) continue;\n\n const result = await job.execute(ctx);\n totalSteps += result.recordCount || 1;\n\n if (result.status === \"error\") {\n const whitelist = result.errors.find((message) =>\n message.startsWith(\"TOOL_WHITELIST_VIOLATION\"),\n );\n if (whitelist) {\n return {\n success: false,\n error: { code: \"TOOL_WHITELIST_VIOLATION\", message: whitelist },\n _meta: { pipeline_steps: totalSteps, session },\n };\n }\n return {\n success: false,\n error: { code: \"ASH_RUNTIME_ERROR\", message: result.errors.join(\"; \") },\n _meta: { pipeline_steps: totalSteps, session },\n };\n }\n }\n } catch (e: any) {\n const message = e?.message ?? String(e);\n if (typeof message === \"string\" && message.startsWith(\"PATH_TRAVERSAL\")) {\n return {\n success: false,\n error: { code: \"PATH_TRAVERSAL\", message },\n _meta: { pipeline_steps: totalSteps, session },\n };\n }\n if (typeof message === \"string\" && message.startsWith(\"TOOL_WHITELIST_VIOLATION\")) {\n return {\n success: false,\n error: { code: \"TOOL_WHITELIST_VIOLATION\", message },\n _meta: { pipeline_steps: totalSteps, session },\n };\n }\n return {\n success: false,\n error: { code: \"ASH_RUNTIME_ERROR\", message },\n _meta: { pipeline_steps: totalSteps, session },\n };\n }\n\n // Determine output data\n let finalData: unknown;\n if (outputKey && writeCollector[joinURL(\"/output\", outputKey)]) {\n finalData = writeCollector[joinURL(\"/output\", outputKey)];\n } else if (lastWriteData != null) {\n finalData = lastWriteData;\n } else {\n finalData = null;\n }\n\n const ashResult: AshRunnerResult = {\n success: true,\n data: { result: finalData },\n _meta: { pipeline_steps: totalSteps, session },\n };\n\n if (outputKey && finalData != null) {\n ashResult.result = { [outputKey]: finalData };\n }\n\n return ashResult;\n}\n"],"mappings":"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"}