agents 0.30.1 → 0.32.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 (182) hide show
  1. package/README.md +2 -1
  2. package/dist/{agent-routing-CDbpVjYq.d.ts → agent-routing-vVMA7m8Y.d.ts} +69 -608
  3. package/dist/agent-routing.d.ts +1 -1
  4. package/dist/agent-tool-types.d.ts +1 -1
  5. package/dist/{agent-tools-C8DH8Yii.d.ts → agent-tools-gGXXkf1z.d.ts} +2 -2
  6. package/dist/agent-tools.d.ts +1 -1
  7. package/dist/agent-tools.js +0 -1
  8. package/dist/agent-tools.js.map +1 -1
  9. package/dist/{ai-iXw0uOGj.d.ts → ai-CDn3Abax.d.ts} +30 -4
  10. package/dist/{ai-sdk-DRPh2rRa.js → ai-sdk-Kon40i0q.js} +2 -36
  11. package/dist/ai-sdk-Kon40i0q.js.map +1 -0
  12. package/dist/browser/ai.d.ts +1 -1
  13. package/dist/browser/ai.js +16 -3
  14. package/dist/browser/ai.js.map +1 -1
  15. package/dist/browser/index.d.ts +64 -16
  16. package/dist/browser/index.js +4 -4
  17. package/dist/browser/tools/ai-sdk.d.ts +7 -5
  18. package/dist/browser/tools/ai-sdk.js +4 -4
  19. package/dist/browser/tools/ai-sdk.js.map +1 -1
  20. package/dist/browser/tools/pi.d.ts +9 -15
  21. package/dist/browser/tools/pi.js +6 -14
  22. package/dist/browser/tools/pi.js.map +1 -1
  23. package/dist/browser/tools/tanstack-ai.d.ts +48 -25
  24. package/dist/browser/tools/tanstack-ai.js +8 -4
  25. package/dist/browser/tools/tanstack-ai.js.map +1 -1
  26. package/dist/{browser-DccPw_wW.js → browser-1eUbPvC2.js} +413 -14
  27. package/dist/browser-1eUbPvC2.js.map +1 -0
  28. package/dist/{browser-DlXhSAdf.d.ts → browser-D9RNpJuT.d.ts} +254 -20
  29. package/dist/browser-tool-BhjCcNVE.d.ts +71 -0
  30. package/dist/browser-tool-DRan7Lk6.js +497 -0
  31. package/dist/browser-tool-DRan7Lk6.js.map +1 -0
  32. package/dist/capability-id-B3J8Nok_.js +13 -0
  33. package/dist/capability-id-B3J8Nok_.js.map +1 -0
  34. package/dist/catalog-BpOejOsE.js +239 -0
  35. package/dist/catalog-BpOejOsE.js.map +1 -0
  36. package/dist/catalog-BpiVV1OF.d.ts +173 -0
  37. package/dist/chat/index.d.ts +2 -2
  38. package/dist/chat-sdk/index.d.ts +3 -3
  39. package/dist/chat-sdk/index.js +1 -1
  40. package/dist/client-4OlMIJx-.js.map +1 -1
  41. package/dist/{client-BnYbNT3z.js → client-DMWujQJ1.js} +68 -244
  42. package/dist/client-DMWujQJ1.js.map +1 -0
  43. package/dist/{client-C27CtRZr.d.ts → client-eSfgYvd3.d.ts} +9 -7
  44. package/dist/client.d.ts +1 -1
  45. package/dist/{cloudflare-Dzvc7V2N.js → cloudflare-CUUm_9q9.js} +26 -4
  46. package/dist/cloudflare-CUUm_9q9.js.map +1 -0
  47. package/dist/{connector-DAXBOIIi.js → connector-CM-uuxKM.js} +96 -8
  48. package/dist/connector-CM-uuxKM.js.map +1 -0
  49. package/dist/{connector-20DJ6p4k.d.ts → connector-DZ71EjE-.d.ts} +109 -9
  50. package/dist/{do-oauth-client-provider-DfsUcpc3.d.ts → do-oauth-client-provider-DtNqv7oj.d.ts} +26 -2
  51. package/dist/{index-YSKgfgg9.d.ts → emitter-BJZtCVjQ.d.ts} +6 -140
  52. package/dist/emitter-DPOVcCln.js +15 -0
  53. package/dist/emitter-DPOVcCln.js.map +1 -0
  54. package/dist/experimental/channels/web/index.js +1 -1
  55. package/dist/experimental/webmcp.js +1 -1
  56. package/dist/{handler-stateless-Bly_nSH3.js → handler-stateless-B5hU3dxK.js} +35 -2
  57. package/dist/handler-stateless-B5hU3dxK.js.map +1 -0
  58. package/dist/{handler-stateless-DxYpJ_XF.d.ts → handler-stateless-C90kD5_R.d.ts} +3 -47
  59. package/dist/harness/container/index.d.ts +15 -15
  60. package/dist/harness/container/index.js +0 -1
  61. package/dist/harness/container/index.js.map +1 -1
  62. package/dist/harness/container/runtime/index.js +2 -2
  63. package/dist/harness/opencode/index.js +0 -1
  64. package/dist/harness/opencode/index.js.map +1 -1
  65. package/dist/harness/pi/index.d.ts +15 -7
  66. package/dist/harness/pi/index.js +74 -151
  67. package/dist/harness/pi/index.js.map +1 -1
  68. package/dist/harness/think/index.d.ts +2 -1
  69. package/dist/{images-xaDv2Fqe.js → images-CfuRCjwq.js} +1 -5
  70. package/dist/images-CfuRCjwq.js.map +1 -0
  71. package/dist/{index-DCxk3OSJ.d.ts → index-8k4qsX1T.d.ts} +2 -28
  72. package/dist/index.d.ts +15 -16
  73. package/dist/index.js +3 -3
  74. package/dist/internal-hosts-Kfp5A392.d.ts +230 -0
  75. package/dist/internal-kmw70xwR.js.map +1 -1
  76. package/dist/invoker-BC1SZ3q1.js +26 -0
  77. package/dist/invoker-BC1SZ3q1.js.map +1 -0
  78. package/dist/invoker-DoLFPJZV.d.ts +21 -0
  79. package/dist/markdown-BZ-VLtA1.js +86 -0
  80. package/dist/markdown-BZ-VLtA1.js.map +1 -0
  81. package/dist/mcp/client/do-oauth-client-provider.d.ts +4 -2
  82. package/dist/mcp/client/do-oauth-client-provider.js +15 -1
  83. package/dist/mcp/client/do-oauth-client-provider.js.map +1 -1
  84. package/dist/mcp/client/index.d.ts +15 -1
  85. package/dist/mcp/client/index.js +2 -2
  86. package/dist/mcp/client/x402.d.ts +7 -5
  87. package/dist/mcp/client/x402.js +34 -1
  88. package/dist/mcp/client/x402.js.map +1 -1
  89. package/dist/mcp/index.d.ts +561 -27
  90. package/dist/mcp/index.js +180 -3
  91. package/dist/mcp/index.js.map +1 -1
  92. package/dist/mcp/server/index.d.ts +1 -1
  93. package/dist/mcp/server/index.js +1 -1
  94. package/dist/models/ai-sdk/index.d.ts +2 -2
  95. package/dist/models/ai-sdk/index.js +1 -1
  96. package/dist/models/opencode/index.d.ts +2 -2
  97. package/dist/models/opencode/index.js +1 -1
  98. package/dist/models/pi-ai/index.d.ts +3 -28
  99. package/dist/models/pi-ai/index.js +160 -18
  100. package/dist/models/pi-ai/index.js.map +1 -1
  101. package/dist/observability/ai/index.js +1 -2
  102. package/dist/observability/ai/index.js.map +1 -1
  103. package/dist/observability/index.d.ts +170 -9
  104. package/dist/observability/index.js +386 -11
  105. package/dist/observability/index.js.map +1 -1
  106. package/dist/protocol-BEgrJYC5.d.ts +29 -29
  107. package/dist/react.d.ts +2 -2
  108. package/dist/resource-B59OV2a2.js +325 -0
  109. package/dist/resource-B59OV2a2.js.map +1 -0
  110. package/dist/routing/index.d.ts +1 -1
  111. package/dist/script-CFDLTk5b.d.ts +91 -0
  112. package/dist/script-workspace-BpdAYq1R.d.ts +41 -0
  113. package/dist/serializable.d.ts +1 -1
  114. package/dist/{session-store-yvwq1f9x.js → session-7CDgVE0z.js} +455 -33
  115. package/dist/session-7CDgVE0z.js.map +1 -0
  116. package/dist/{session-store-_IK6dV-w.d.ts → session-store-B7Ca-u1t.d.ts} +8 -1
  117. package/dist/settings-Dk2il2Hf.js.map +1 -1
  118. package/dist/skill-DRBcIBjC.d.ts +221 -0
  119. package/dist/skills/index.d.ts +275 -36
  120. package/dist/skills/index.js +265 -1534
  121. package/dist/skills/index.js.map +1 -1
  122. package/dist/skills/runner.d.ts +37 -0
  123. package/dist/skills/runner.js +912 -0
  124. package/dist/skills/runner.js.map +1 -0
  125. package/dist/skills/tools/ai-sdk.d.ts +36 -0
  126. package/dist/skills/tools/ai-sdk.js +94 -0
  127. package/dist/skills/tools/ai-sdk.js.map +1 -0
  128. package/dist/source-9RQzlEhM.d.ts +112 -0
  129. package/dist/{src-DfLzdwlK.js → src-DoGNJ4Ud.js} +21 -6
  130. package/dist/src-DoGNJ4Ud.js.map +1 -0
  131. package/dist/sub-routing.d.ts +12 -12
  132. package/dist/tool-CTp72Jb_.d.ts +10 -10
  133. package/dist/tool-CxKsvxjm.js.map +1 -1
  134. package/dist/tool-DkT_DJBm.js.map +1 -1
  135. package/dist/tool-DoVberpN.d.ts +22 -22
  136. package/dist/tool-helpers-BI7ifO2S.js +255 -0
  137. package/dist/tool-helpers-BI7ifO2S.js.map +1 -0
  138. package/dist/{transport-CPh7YGiw.d.ts → transport-5moD2pW5.d.ts} +1 -43
  139. package/dist/types-D2naO3rA.d.ts +49 -0
  140. package/dist/vite.d.ts +2 -2
  141. package/dist/vite.js +10 -258
  142. package/dist/vite.js.map +1 -1
  143. package/dist/voice/index.d.ts +1 -1
  144. package/dist/websockets/index.js +1 -1
  145. package/dist/{websockets-CyoeosdO.js → websockets-C6SJtWCJ.js} +1 -2
  146. package/dist/{websockets-CyoeosdO.js.map → websockets-C6SJtWCJ.js.map} +1 -1
  147. package/dist/workflow-types.d.ts +1 -1
  148. package/dist/workflows.d.ts +1 -1
  149. package/dist/workflows.js +0 -1
  150. package/dist/workflows.js.map +1 -1
  151. package/docs/browse-the-web.md +247 -413
  152. package/docs/harnesses/pi.md +36 -30
  153. package/docs/index.md +4 -4
  154. package/docs/mcp-client.md +25 -1
  155. package/docs/mcp-servers.md +26 -7
  156. package/docs/models-pi-ai.md +9 -11
  157. package/docs/models.md +1 -8
  158. package/docs/observability.md +5 -3
  159. package/docs/securing-mcp-servers.md +113 -302
  160. package/package.json +31 -17
  161. package/dist/ai-sdk-DRPh2rRa.js.map +0 -1
  162. package/dist/browser-DccPw_wW.js.map +0 -1
  163. package/dist/browser-tool-B1mhifin.js +0 -616
  164. package/dist/browser-tool-B1mhifin.js.map +0 -1
  165. package/dist/browser-tool-Cxjk5sgG.d.ts +0 -92
  166. package/dist/client-BnYbNT3z.js.map +0 -1
  167. package/dist/cloudflare-Dzvc7V2N.js.map +0 -1
  168. package/dist/connector-DAXBOIIi.js.map +0 -1
  169. package/dist/handler-stateless-Bly_nSH3.js.map +0 -1
  170. package/dist/images-xaDv2Fqe.js.map +0 -1
  171. package/dist/index-iv9FTXX9.d.ts +0 -311
  172. package/dist/invoker-CG0_p_Wq.d.ts +0 -20
  173. package/dist/invoker-CHMnoxIA.js +0 -57
  174. package/dist/invoker-CHMnoxIA.js.map +0 -1
  175. package/dist/session-store-yvwq1f9x.js.map +0 -1
  176. package/dist/skills/compile.d.ts +0 -40
  177. package/dist/skills/compile.js +0 -65
  178. package/dist/skills/compile.js.map +0 -1
  179. package/dist/src-DfLzdwlK.js.map +0 -1
  180. package/dist/tool-helpers-O5BDVEAY.js +0 -58
  181. package/dist/tool-helpers-O5BDVEAY.js.map +0 -1
  182. package/skills-module.d.ts +0 -22
@@ -0,0 +1,912 @@
1
+ import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "../classPrivateFieldGet2-DZBYAB34.js";
2
+ import { t as _classPrivateMethodInitSpec } from "../classPrivateMethodInitSpec-qMjJ6sHQ.js";
3
+ import { i as extensionOf, o as parseSkillResourcePath } from "../resource-B59OV2a2.js";
4
+ import { t as formatSkill } from "../markdown-BZ-VLtA1.js";
5
+ import { RpcTarget } from "cloudflare:workers";
6
+ import { DynamicWorkerExecutor, resolveProvider } from "@cloudflare/codemode";
7
+ import { Bash, defineCommand } from "just-bash";
8
+ //#region src/skills/script-workspace.ts
9
+ /** Directory skill scripts and relative paths resolve against. */
10
+ const WORKSPACE_ROOT = "/workspace";
11
+ const TEXT_ENCODER = new TextEncoder();
12
+ const TEXT_DECODER = new TextDecoder();
13
+ /**
14
+ * @internal Adapt a Workspace for skill scripts. Relative paths resolve
15
+ * against `/workspace`, and paths outside `/workspace` are rejected.
16
+ */
17
+ function createSkillWorkspaceAccess(workspace) {
18
+ const { fs } = workspace;
19
+ const access = {
20
+ async readFile(path) {
21
+ try {
22
+ return TEXT_DECODER.decode(await drain(await fs.readFile(resolvePath(path))));
23
+ } catch (error) {
24
+ if (isNotFound(error)) return null;
25
+ throw error;
26
+ }
27
+ },
28
+ async listFiles(path) {
29
+ const directory = resolvePath(path);
30
+ return (await fs.readdir(directory)).map((entry) => ({
31
+ path: `${directory.replace(/\/$/, "")}/${entry.name}`,
32
+ name: entry.name,
33
+ type: entry.isDirectory ? "directory" : "file",
34
+ size: entry.size
35
+ }));
36
+ },
37
+ async glob(pattern) {
38
+ const segments = resolvePath(pattern).split("/").filter(Boolean);
39
+ const firstGlob = segments.findIndex((part) => /[*?[\]{}]/.test(part));
40
+ if (firstGlob === -1) {
41
+ const path = `/${segments.join("/")}`;
42
+ const found = await access.stat(path);
43
+ return found === null ? [] : [{
44
+ path,
45
+ ...found
46
+ }];
47
+ }
48
+ let matches;
49
+ try {
50
+ matches = await fs.find(`/${segments.slice(0, firstGlob).join("/")}`, segments.slice(firstGlob).join("/"));
51
+ } catch (error) {
52
+ if (isNotFound(error)) return [];
53
+ throw error;
54
+ }
55
+ return Promise.all(matches.filter((match) => isInsideRoot(match.path)).map(async (match) => match.type === "dir" ? {
56
+ path: match.path,
57
+ type: "directory",
58
+ size: 0
59
+ } : {
60
+ path: match.path,
61
+ type: "file",
62
+ size: (await fs.stat(match.path)).size
63
+ }));
64
+ },
65
+ async stat(path) {
66
+ try {
67
+ const info = await fs.stat(resolvePath(path));
68
+ return {
69
+ type: info.isDirectory ? "directory" : "file",
70
+ size: info.size
71
+ };
72
+ } catch (error) {
73
+ if (isNotFound(error)) return null;
74
+ throw error;
75
+ }
76
+ },
77
+ async writeFile(path, content) {
78
+ const absolute = resolvePath(path);
79
+ const parent = absolute.slice(0, absolute.lastIndexOf("/"));
80
+ if (parent) await fs.mkdir(parent, { recursive: true });
81
+ await fs.writeFile(absolute, typeof content === "string" ? TEXT_ENCODER.encode(content) : content);
82
+ }
83
+ };
84
+ return access;
85
+ }
86
+ function isInsideRoot(path) {
87
+ return path === WORKSPACE_ROOT || path.startsWith(`${WORKSPACE_ROOT}/`);
88
+ }
89
+ /** A script asked for a path outside `/workspace`. */
90
+ var SkillWorkspacePathError = class extends Error {
91
+ constructor(path) {
92
+ super(`Skill scripts can only access paths under ${WORKSPACE_ROOT}: ${path}`);
93
+ this.path = path;
94
+ this._tag = "SkillWorkspacePathError";
95
+ this.name = "SkillWorkspacePathError";
96
+ }
97
+ };
98
+ /**
99
+ * Resolve a script-supplied path to a normalized absolute path under
100
+ * `/workspace`. Relative paths resolve against `/workspace`; `.` and `..`
101
+ * are applied before the check, so `../x` or `/workspace/../x` cannot reach
102
+ * the rest of the Workspace filesystem.
103
+ *
104
+ * @throws SkillWorkspacePathError when the path resolves outside
105
+ * `/workspace`. The host bridge reports it to the script as a failed call.
106
+ */
107
+ function resolvePath(path) {
108
+ if (path.includes("\0")) throw new SkillWorkspacePathError(path);
109
+ const absolute = path.startsWith("/") ? path : `${WORKSPACE_ROOT}/${path}`;
110
+ const parts = [];
111
+ for (const part of absolute.split("/")) {
112
+ if (part === "" || part === ".") continue;
113
+ if (part === "..") {
114
+ parts.pop();
115
+ continue;
116
+ }
117
+ parts.push(part);
118
+ }
119
+ const resolved = `/${parts.join("/")}`;
120
+ if (!isInsideRoot(resolved)) throw new SkillWorkspacePathError(path);
121
+ return resolved;
122
+ }
123
+ function isNotFound(error) {
124
+ if (!error || typeof error !== "object") return false;
125
+ const record = error;
126
+ return record.code === "ENOENT" || typeof record.message === "string" && /ENOENT|no such file|not found/i.test(record.message);
127
+ }
128
+ async function drain(stream) {
129
+ const parts = [];
130
+ let total = 0;
131
+ const reader = stream.getReader();
132
+ try {
133
+ while (true) {
134
+ const { value, done } = await reader.read();
135
+ if (done) break;
136
+ if (!value || value.byteLength === 0) continue;
137
+ parts.push(value);
138
+ total += value.byteLength;
139
+ }
140
+ } finally {
141
+ reader.releaseLock();
142
+ }
143
+ if (parts.length === 1) return parts[0];
144
+ const bytes = new Uint8Array(total);
145
+ let offset = 0;
146
+ for (const part of parts) {
147
+ bytes.set(part, offset);
148
+ offset += part.byteLength;
149
+ }
150
+ return bytes;
151
+ }
152
+ //#endregion
153
+ //#region src/skills/runner.ts
154
+ const DEFAULT_SCRIPT_TIMEOUT_MS = 3e4;
155
+ const MAX_OUTPUT_ARTIFACT_BYTES = 64e3;
156
+ const MAX_OUTPUT_ARTIFACTS = 20;
157
+ const SUPPORTED_SCRIPT_EXTENSIONS = /* @__PURE__ */ new Set([
158
+ ".js",
159
+ ".mjs",
160
+ ".ts",
161
+ ".tsx",
162
+ ".py",
163
+ ".sh",
164
+ ".bash"
165
+ ]);
166
+ let runnerExperimentalWarned = false;
167
+ function effectiveTimeout(options) {
168
+ return options.timeout ?? DEFAULT_SCRIPT_TIMEOUT_MS;
169
+ }
170
+ function effectiveWorkspaceAccess(options) {
171
+ if (options.workspace) return options.workspace;
172
+ return options.workspaceInstance ? "read" : "none";
173
+ }
174
+ function parseSkillScriptPath(path) {
175
+ if (!path.startsWith("scripts/")) return {
176
+ ok: false,
177
+ error: `Skill script path must start with "scripts/": ${path}`
178
+ };
179
+ if (!parseSkillResourcePath(path).ok) return {
180
+ ok: false,
181
+ error: `Skill script path must be a normalized relative path under "scripts/": ${path}`
182
+ };
183
+ const extension = extensionOf(path);
184
+ if (!SUPPORTED_SCRIPT_EXTENSIONS.has(extension)) return {
185
+ ok: false,
186
+ error: `Unsupported skill script extension "${extension || "(none)"}" for ${path}. Supported extensions: ${[...SUPPORTED_SCRIPT_EXTENSIONS].join(", ")}`
187
+ };
188
+ if (extension === ".sh" || extension === ".bash") return {
189
+ ok: true,
190
+ runtime: "bash"
191
+ };
192
+ if (extension === ".py") return {
193
+ ok: true,
194
+ runtime: "python"
195
+ };
196
+ if (extension === ".ts" || extension === ".tsx") return {
197
+ ok: true,
198
+ runtime: "typescript"
199
+ };
200
+ return {
201
+ ok: true,
202
+ runtime: "javascript"
203
+ };
204
+ }
205
+ function validateMountedResourcePaths(request) {
206
+ for (const resource of request.resources ?? []) {
207
+ const path = parseSkillResourcePath(resource.path);
208
+ if (!path.ok) throw path.error;
209
+ }
210
+ }
211
+ function skillScriptContext(request) {
212
+ return { skill: {
213
+ name: request.skill.name,
214
+ description: request.skill.description,
215
+ ...request.skill.license === void 0 ? {} : { license: request.skill.license },
216
+ ...request.skill.compatibility === void 0 ? {} : { compatibility: request.skill.compatibility },
217
+ metadata: request.skill.metadata,
218
+ allowedTools: request.skill.allowedTools
219
+ } };
220
+ }
221
+ /**
222
+ * Text bundled resources exposed to function-style JS/TS scripts via
223
+ * `ctx.files`. Binary resources are omitted in v1.
224
+ */
225
+ function textFilesMap(request) {
226
+ const files = {};
227
+ for (const resource of request.resources ?? []) if ((resource.encoding ?? "text") === "text") files[resource.path] = resource.content;
228
+ return files;
229
+ }
230
+ function base64ToBytes(value) {
231
+ const binary = atob(value);
232
+ const bytes = new Uint8Array(binary.length);
233
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
234
+ return bytes;
235
+ }
236
+ function stdinText(stdin) {
237
+ return typeof stdin === "string" ? stdin : String(stdin ?? "");
238
+ }
239
+ function mountedFiles(request) {
240
+ const files = {
241
+ "/input.json": {
242
+ content: JSON.stringify(request.input),
243
+ encoding: "text"
244
+ },
245
+ "/context.json": {
246
+ content: JSON.stringify(skillScriptContext(request)),
247
+ encoding: "text"
248
+ },
249
+ "/skill/SKILL.md": {
250
+ content: formatSkill(request.skill),
251
+ encoding: "text"
252
+ }
253
+ };
254
+ for (const resource of request.resources ?? []) {
255
+ const path = parseSkillResourcePath(resource.path);
256
+ if (!path.ok) throw path.error;
257
+ files[`/skill/${resource.path}`] = {
258
+ content: resource.content,
259
+ encoding: resource.encoding ?? "text"
260
+ };
261
+ }
262
+ files[`/skill/${request.path}`] = {
263
+ content: request.source,
264
+ encoding: "text"
265
+ };
266
+ return files;
267
+ }
268
+ function bashFiles(request) {
269
+ const files = {
270
+ "/input.json": JSON.stringify(request.input),
271
+ "/context.json": JSON.stringify(skillScriptContext(request)),
272
+ "/skill-script.sh": request.source,
273
+ "/skill/SKILL.md": formatSkill(request.skill),
274
+ [`/skill/${request.path}`]: request.source
275
+ };
276
+ for (const resource of request.resources ?? []) {
277
+ const path = parseSkillResourcePath(resource.path);
278
+ if (!path.ok) throw path.error;
279
+ files[`/skill/${resource.path}`] = (resource.encoding ?? "text") === "base64" ? base64ToBytes(resource.content) : resource.content;
280
+ }
281
+ return files;
282
+ }
283
+ /**
284
+ * Wrap a function-style JS/TS skill module so it runs inside the codemode
285
+ * sandbox. The module must `export default` an async `run(input, ctx)`; we
286
+ * rewrite the default export to a local binding, build the `ctx` capability
287
+ * object from the host bridge proxy (`__host`), and invoke it.
288
+ */
289
+ function scriptModule(source, request) {
290
+ const runnableSource = stripStrayExports(source.replace(/^\s*export\s+default\s+/m, "const __skillRun = "));
291
+ const skillMeta = skillScriptContext(request).skill;
292
+ return [
293
+ "async () => {",
294
+ ` const input = ${JSON.stringify(request.input)};`,
295
+ ` const __skill = ${JSON.stringify(skillMeta)};`,
296
+ ` const __files = ${JSON.stringify(textFilesMap(request))};`,
297
+ " const workspace = {",
298
+ " readFile: (path) => __host.readFile(path),",
299
+ " listFiles: (path = \".\") => __host.listFiles(path),",
300
+ " glob: (pattern) => __host.glob(pattern),",
301
+ " stat: (path) => __host.stat(path),",
302
+ " writeFile: (path, content) => __host.writeFile({ path, content })",
303
+ " };",
304
+ " const tools = new Proxy(",
305
+ " { call: (name, input) => __host.callTool({ name, input }) },",
306
+ " {",
307
+ " get: (target, prop) =>",
308
+ " prop in target",
309
+ " ? target[prop]",
310
+ " : (input) => __host.callTool({ name: String(prop), input })",
311
+ " }",
312
+ " );",
313
+ " const output = {",
314
+ " writeFile: (name, content) => __host.writeOutput({ name, content })",
315
+ " };",
316
+ " const ctx = { skill: __skill, files: __files, workspace, tools, output };",
317
+ "",
318
+ runnableSource,
319
+ "",
320
+ " if (typeof __skillRun !== \"function\") {",
321
+ " throw new Error(\"Skill script default export must be a function (input, ctx).\");",
322
+ " }",
323
+ " return await __skillRun(input, ctx);",
324
+ "}"
325
+ ].join("\n");
326
+ }
327
+ /**
328
+ * Whether a script declares a default export, in either the raw author form
329
+ * (`export default ...`) or the bundled form esbuild emits
330
+ * (`export { run as default }`).
331
+ */
332
+ function hasDefaultExport(source) {
333
+ return /^\s*export\s+default\s+/m.test(source) || /export\s*\{[^}]*\bas\s+default\b[^}]*\}/m.test(source);
334
+ }
335
+ /**
336
+ * Remove `export { ... }` blocks, which are illegal inside the function wrapper
337
+ * the runner builds around skill scripts.
338
+ */
339
+ function stripStrayExports(source) {
340
+ return source.replace(/\n?export\s*\{[\s\S]*?\};?/g, "");
341
+ }
342
+ function rewriteBundledSource(source) {
343
+ const defaultBinding = source.match(/\bexport\s*\{[^}]*\b([A-Za-z_$][\w$]*)\s+as\s+default\b[^}]*\}/m);
344
+ const stripped = stripStrayExports(source);
345
+ if (defaultBinding) return `${stripped}\nconst __skillRun = ${defaultBinding[1]};`;
346
+ return stripped;
347
+ }
348
+ const RELATIVE_IMPORT = /(?:\bimport\s[^;]*?\bfrom\s*|\bimport\s*\(\s*|\bimport\s+)["']\.\.?\//;
349
+ /**
350
+ * Skill scripts run directly in the sandbox; there is no in-Worker bundler.
351
+ * A script must be one self-contained JavaScript module: TypeScript and
352
+ * scripts that import sibling files must be compiled before they are stored.
353
+ * esbuild's `export { run as default }` output is normalized into the
354
+ * `__skillRun` binding the wrapper expects.
355
+ */
356
+ function prepareJavaScriptSource(request, runtime) {
357
+ if (runtime === "javascript" && !RELATIVE_IMPORT.test(request.source)) return /^\s*export\s+default\s+/m.test(request.source) ? request.source : rewriteBundledSource(request.source);
358
+ throw new Error(`Skill script "${request.path}" must be compiled to a self-contained JavaScript module before it can run. Bundle TypeScript or multi-file scripts (for example with esbuild) before storing the skill.`);
359
+ }
360
+ async function executeToolFromSet(tools, name, input) {
361
+ const target = tools?.[name];
362
+ const execute = target && "execute" in target ? target.execute : void 0;
363
+ if (!execute) throw new Error(`Tool not available: ${name}`);
364
+ return execute(input);
365
+ }
366
+ function stringifyHostResult(result) {
367
+ return JSON.stringify({ result });
368
+ }
369
+ function stringifyHostError(error) {
370
+ return JSON.stringify({ error: error instanceof Error ? error.message : String(error) });
371
+ }
372
+ var _tools = /* @__PURE__ */ new WeakMap();
373
+ var _workspace = /* @__PURE__ */ new WeakMap();
374
+ var _workspaceAccess = /* @__PURE__ */ new WeakMap();
375
+ var _outputs = /* @__PURE__ */ new WeakMap();
376
+ var _SkillScriptHostBridge_brand = /* @__PURE__ */ new WeakSet();
377
+ /**
378
+ * The single source of truth for skill-script capabilities and permission
379
+ * enforcement. Every runtime delegates here:
380
+ *
381
+ * - JavaScript/TypeScript reach it through a codemode `ToolProvider`.
382
+ * - Python receives it as an RPC `RpcTarget` (JSON-marshalling methods).
383
+ * - Bash calls it from `just-bash` custom commands.
384
+ *
385
+ * Construct a fresh bridge per `run()` so the per-invocation `/output`
386
+ * artifact buffer is never shared between concurrent script runs.
387
+ */
388
+ var SkillScriptHostBridge = class extends RpcTarget {
389
+ constructor(tools, workspace, workspaceAccess) {
390
+ super();
391
+ _classPrivateMethodInitSpec(this, _SkillScriptHostBridge_brand);
392
+ _classPrivateFieldInitSpec(this, _tools, void 0);
393
+ _classPrivateFieldInitSpec(this, _workspace, void 0);
394
+ _classPrivateFieldInitSpec(this, _workspaceAccess, void 0);
395
+ _classPrivateFieldInitSpec(this, _outputs, /* @__PURE__ */ new Map());
396
+ _classPrivateFieldSet2(_tools, this, tools);
397
+ _classPrivateFieldSet2(_workspace, this, workspace === void 0 ? void 0 : createSkillWorkspaceAccess(workspace));
398
+ _classPrivateFieldSet2(_workspaceAccess, this, workspaceAccess);
399
+ }
400
+ get workspaceAccess() {
401
+ return _classPrivateFieldGet2(_workspaceAccess, this);
402
+ }
403
+ hasTools() {
404
+ return Boolean(_classPrivateFieldGet2(_tools, this) && Object.keys(_classPrivateFieldGet2(_tools, this)).length > 0);
405
+ }
406
+ async callTool(name, input) {
407
+ return executeToolFromSet(_classPrivateFieldGet2(_tools, this), name, input);
408
+ }
409
+ async readFile(path) {
410
+ return _assertClassBrand(_SkillScriptHostBridge_brand, this, _requireWorkspace).call(this, "read").readFile(path);
411
+ }
412
+ async listFiles(path = ".") {
413
+ return _assertClassBrand(_SkillScriptHostBridge_brand, this, _requireWorkspace).call(this, "read").listFiles(path);
414
+ }
415
+ async glob(pattern) {
416
+ return _assertClassBrand(_SkillScriptHostBridge_brand, this, _requireWorkspace).call(this, "read").glob(pattern);
417
+ }
418
+ async stat(path) {
419
+ return _assertClassBrand(_SkillScriptHostBridge_brand, this, _requireWorkspace).call(this, "read").stat(path);
420
+ }
421
+ async writeFile(path, content) {
422
+ await _assertClassBrand(_SkillScriptHostBridge_brand, this, _requireWorkspace).call(this, "read-write").writeFile(path, content);
423
+ }
424
+ writeOutput(name, content) {
425
+ const key = String(name);
426
+ const text = typeof content === "string" ? content : String(content ?? "");
427
+ if (new TextEncoder().encode(text).byteLength > MAX_OUTPUT_ARTIFACT_BYTES) throw new Error(`Output artifact "${key}" exceeds ${MAX_OUTPUT_ARTIFACT_BYTES} bytes.`);
428
+ if (!_classPrivateFieldGet2(_outputs, this).has(key) && _classPrivateFieldGet2(_outputs, this).size >= MAX_OUTPUT_ARTIFACTS) throw new Error(`Too many skill output artifacts (max ${MAX_OUTPUT_ARTIFACTS}).`);
429
+ _classPrivateFieldGet2(_outputs, this).set(key, {
430
+ path: key,
431
+ encoding: "text",
432
+ content: text
433
+ });
434
+ }
435
+ getOutputFiles() {
436
+ return [..._classPrivateFieldGet2(_outputs, this).values()];
437
+ }
438
+ async tool(name, inputJson = "{}") {
439
+ try {
440
+ const input = inputJson.trim() ? JSON.parse(inputJson) : {};
441
+ return stringifyHostResult(await this.callTool(name, input));
442
+ } catch (error) {
443
+ return stringifyHostError(error);
444
+ }
445
+ }
446
+ async workspaceReadFile(path) {
447
+ try {
448
+ return stringifyHostResult(await this.readFile(path));
449
+ } catch (error) {
450
+ return stringifyHostError(error);
451
+ }
452
+ }
453
+ async workspaceListFiles(path = ".") {
454
+ try {
455
+ return stringifyHostResult(await this.listFiles(path));
456
+ } catch (error) {
457
+ return stringifyHostError(error);
458
+ }
459
+ }
460
+ async workspaceGlob(pattern) {
461
+ try {
462
+ return stringifyHostResult(await this.glob(pattern));
463
+ } catch (error) {
464
+ return stringifyHostError(error);
465
+ }
466
+ }
467
+ async workspaceWriteFile(path, content) {
468
+ try {
469
+ await this.writeFile(path, content);
470
+ return stringifyHostResult(null);
471
+ } catch (error) {
472
+ return stringifyHostError(error);
473
+ }
474
+ }
475
+ };
476
+ function _requireWorkspace(access) {
477
+ if (!_classPrivateFieldGet2(_workspace, this) || _classPrivateFieldGet2(_workspaceAccess, this) === "none") throw new Error("Workspace access is not available.");
478
+ if (access === "read-write" && _classPrivateFieldGet2(_workspaceAccess, this) !== "read-write") throw new Error("Workspace write access is not available.");
479
+ return _classPrivateFieldGet2(_workspace, this);
480
+ }
481
+ /**
482
+ * Expose the bridge to JS/TS scripts as a single codemode provider namespace
483
+ * (`__host`). The sandbox `ctx` object wraps these calls into the friendly
484
+ * `workspace` / `tools` / `output` surface (see {@link scriptModule}).
485
+ */
486
+ function hostProvider(bridge) {
487
+ return {
488
+ name: "__host",
489
+ tools: {
490
+ callTool: { execute: (a) => {
491
+ const { name, input } = a;
492
+ return bridge.callTool(name, input);
493
+ } },
494
+ readFile: { execute: (a) => bridge.readFile(String(a)) },
495
+ listFiles: { execute: (a) => bridge.listFiles(typeof a === "string" ? a : ".") },
496
+ glob: { execute: (a) => bridge.glob(String(a)) },
497
+ stat: { execute: (a) => bridge.stat(String(a)) },
498
+ writeFile: { execute: (a) => {
499
+ const { path, content } = a;
500
+ return bridge.writeFile(path, content);
501
+ } },
502
+ writeOutput: { execute: async (a) => {
503
+ const { name, content } = a;
504
+ bridge.writeOutput(name, content);
505
+ return null;
506
+ } }
507
+ }
508
+ };
509
+ }
510
+ function pythonScriptModule(request) {
511
+ const source = request.source;
512
+ const sourceLiteral = JSON.stringify(source);
513
+ const filesLiteral = JSON.stringify(mountedFiles(request));
514
+ return String.raw`
515
+ import asyncio
516
+ import base64
517
+ import contextlib
518
+ import inspect
519
+ import io
520
+ import json
521
+ import os
522
+ import sys
523
+ import time
524
+ import types
525
+ from js import Object
526
+ from pyodide.ffi import to_js as pyodide_to_js
527
+ from workers import WorkerEntrypoint
528
+
529
+ SKILL_SOURCE = ${sourceLiteral}
530
+ SKILL_FILES = ${filesLiteral}
531
+
532
+ async def maybe_await(value):
533
+ if inspect.isawaitable(value):
534
+ return await value
535
+ return value
536
+
537
+ async def decode_host_response(raw):
538
+ data = json.loads(str(raw))
539
+ if "error" in data:
540
+ raise Exception(data["error"])
541
+ return data.get("result")
542
+
543
+ def to_js(obj):
544
+ return pyodide_to_js(obj, dict_converter=Object.fromEntries)
545
+
546
+ def materialize_files():
547
+ os.makedirs("/output", exist_ok=True)
548
+ for path, file in SKILL_FILES.items():
549
+ directory = os.path.dirname(path)
550
+ if directory:
551
+ os.makedirs(directory, exist_ok=True)
552
+ mode = "wb" if file.get("encoding") == "base64" else "w"
553
+ with open(path, mode) as handle:
554
+ if file.get("encoding") == "base64":
555
+ handle.write(base64.b64decode(file.get("content", "")))
556
+ else:
557
+ handle.write(file.get("content", ""))
558
+
559
+ def collect_output_files():
560
+ output_files = []
561
+ if not os.path.isdir("/output"):
562
+ return output_files
563
+
564
+ for root, _dirs, files in os.walk("/output"):
565
+ for name in sorted(files):
566
+ path = os.path.join(root, name)
567
+ with open(path, "rb") as handle:
568
+ content = handle.read()
569
+ if len(content) > ${MAX_OUTPUT_ARTIFACT_BYTES}:
570
+ raise Exception(f"Output artifact exceeds ${MAX_OUTPUT_ARTIFACT_BYTES} bytes: {path}")
571
+ try:
572
+ output_files.append({
573
+ "path": path,
574
+ "encoding": "text",
575
+ "content": content.decode("utf-8")
576
+ })
577
+ except UnicodeDecodeError:
578
+ output_files.append({
579
+ "path": path,
580
+ "encoding": "base64",
581
+ "content": base64.b64encode(content).decode("ascii")
582
+ })
583
+
584
+ return sorted(output_files, key=lambda file: file["path"])
585
+
586
+ def looks_function_style(source):
587
+ return "def run(" in source or "async def run(" in source
588
+
589
+ def timeout_trace(deadline):
590
+ def trace(frame, event, arg):
591
+ if time.monotonic() > deadline:
592
+ raise TimeoutError("Python script execution timed out")
593
+ return trace
594
+ return trace
595
+
596
+ class ToolNamespace:
597
+ def __init__(self, host):
598
+ self.host = host
599
+
600
+ async def call(self, name, input=None):
601
+ raw = await self.host.tool(name, json.dumps(input if input is not None else {}))
602
+ return await decode_host_response(raw)
603
+
604
+ def __getattr__(self, name):
605
+ async def call_tool(input=None):
606
+ return await self.call(name, input)
607
+ return call_tool
608
+
609
+ class WorkspaceNamespace:
610
+ def __init__(self, host):
611
+ self.host = host
612
+
613
+ async def read_file(self, path):
614
+ raw = await self.host.workspaceReadFile(path)
615
+ return await decode_host_response(raw)
616
+
617
+ async def list_files(self, path="."):
618
+ raw = await self.host.workspaceListFiles(path)
619
+ return await decode_host_response(raw)
620
+
621
+ async def glob(self, pattern):
622
+ raw = await self.host.workspaceGlob(pattern)
623
+ return await decode_host_response(raw)
624
+
625
+ async def write_file(self, path, content):
626
+ raw = await self.host.workspaceWriteFile(path, content)
627
+ return await decode_host_response(raw)
628
+
629
+ class Default(WorkerEntrypoint):
630
+ async def evaluate(self, input, ctx, host, timeout_ms=None):
631
+ materialize_files()
632
+ try:
633
+ if looks_function_style(SKILL_SOURCE):
634
+ skill_module = types.ModuleType("skill_script")
635
+ skill_module.tools = ToolNamespace(host)
636
+ skill_module.workspace = WorkspaceNamespace(host)
637
+ exec(SKILL_SOURCE, skill_module.__dict__)
638
+ if not hasattr(skill_module, "run") or not callable(skill_module.run):
639
+ raise Exception("Python function-style skill script must define a callable run(input, ctx).")
640
+ execution = maybe_await(skill_module.run(input, ctx))
641
+ previous_trace = sys.gettrace()
642
+ if timeout_ms is not None:
643
+ sys.settrace(timeout_trace(time.monotonic() + (timeout_ms / 1000)))
644
+ try:
645
+ if timeout_ms is not None:
646
+ result = await asyncio.wait_for(execution, timeout_ms / 1000)
647
+ else:
648
+ result = await execution
649
+ finally:
650
+ sys.settrace(previous_trace)
651
+ return to_js({
652
+ "result": result,
653
+ "logs": [],
654
+ "mode": "function",
655
+ "outputFiles": collect_output_files()
656
+ })
657
+
658
+ stdout = io.StringIO()
659
+ stderr = io.StringIO()
660
+ previous_stdin = sys.stdin
661
+ previous_trace = sys.gettrace()
662
+ if timeout_ms is not None:
663
+ sys.settrace(timeout_trace(time.monotonic() + (timeout_ms / 1000)))
664
+ sys.stdin = io.StringIO(json.dumps(input))
665
+ try:
666
+ namespace = {"__name__": "__main__", "__file__": "/skill/script.py"}
667
+ with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
668
+ exec(SKILL_SOURCE, namespace)
669
+ finally:
670
+ sys.stdin = previous_stdin
671
+ sys.settrace(previous_trace)
672
+ return to_js({
673
+ "result": {
674
+ "stdout": stdout.getvalue(),
675
+ "stderr": stderr.getvalue(),
676
+ "exitCode": 0
677
+ },
678
+ "logs": [],
679
+ "mode": "cli",
680
+ "outputFiles": collect_output_files()
681
+ })
682
+ except TimeoutError:
683
+ return to_js({"error": "Python script execution timed out", "logs": []})
684
+ except SystemExit as err:
685
+ return to_js({
686
+ "result": {
687
+ "stdout": stdout.getvalue() if "stdout" in locals() else "",
688
+ "stderr": stderr.getvalue() if "stderr" in locals() else "",
689
+ "exitCode": int(err.code) if isinstance(err.code, int) else 1
690
+ },
691
+ "logs": [],
692
+ "mode": "cli",
693
+ "outputFiles": collect_output_files()
694
+ })
695
+ except asyncio.TimeoutError:
696
+ return to_js({"error": "Python script execution timed out", "logs": []})
697
+ except Exception as err:
698
+ return to_js({"error": str(err), "logs": []})
699
+ `;
700
+ }
701
+ async function runPythonScript(request, options, bridge) {
702
+ const execution = options.loader.get(`skill-python-${crypto.randomUUID()}`, () => ({
703
+ compatibilityDate: "2026-05-23",
704
+ compatibilityFlags: ["python_workers", "disable_python_external_sdk"],
705
+ mainModule: "skill_runner.py",
706
+ modules: { "skill_runner.py": pythonScriptModule(request) },
707
+ globalOutbound: options.network ? void 0 : null
708
+ })).getEntrypoint().evaluate(request.input, skillScriptContext(request), bridge, effectiveTimeout(options));
709
+ let timeout = null;
710
+ const timeoutPromise = new Promise((_, reject) => {
711
+ timeout = setTimeout(() => reject(/* @__PURE__ */ new Error("Python script execution timed out")), effectiveTimeout(options));
712
+ });
713
+ try {
714
+ const response = await Promise.race([execution, timeoutPromise]);
715
+ if (response.error) throw new Error(response.error);
716
+ const outputFiles = response.outputFiles ?? [];
717
+ if (response.mode === "cli") {
718
+ if (typeof response.result === "object" && response.result !== null && outputFiles.length > 0) return {
719
+ ...response.result,
720
+ outputFiles
721
+ };
722
+ return response.result;
723
+ }
724
+ if (response.logs?.length || outputFiles.length > 0) return {
725
+ result: response.result,
726
+ ...response.logs?.length ? { logs: response.logs } : {},
727
+ ...outputFiles.length > 0 ? { outputFiles } : {}
728
+ };
729
+ return response.result;
730
+ } finally {
731
+ if (timeout) clearTimeout(timeout);
732
+ }
733
+ }
734
+ async function runBashScript(request, options, bridge) {
735
+ const customCommands = [];
736
+ if (bridge.workspaceAccess !== "none") {
737
+ customCommands.push(defineCommand("workspace-read", async (args) => {
738
+ const path = args[0];
739
+ if (!path) return {
740
+ stdout: "",
741
+ stderr: "Missing path\n",
742
+ exitCode: 2
743
+ };
744
+ try {
745
+ return {
746
+ stdout: await bridge.readFile(path) ?? "",
747
+ stderr: "",
748
+ exitCode: 0
749
+ };
750
+ } catch (error) {
751
+ return {
752
+ stdout: "",
753
+ stderr: `${error instanceof Error ? error.message : String(error)}\n`,
754
+ exitCode: 1
755
+ };
756
+ }
757
+ }), defineCommand("workspace-list", async (args) => {
758
+ const path = args[0] ?? ".";
759
+ try {
760
+ return {
761
+ stdout: JSON.stringify(await bridge.listFiles(path)) + "\n",
762
+ stderr: "",
763
+ exitCode: 0
764
+ };
765
+ } catch (error) {
766
+ return {
767
+ stdout: "",
768
+ stderr: `${error instanceof Error ? error.message : String(error)}\n`,
769
+ exitCode: 1
770
+ };
771
+ }
772
+ }), defineCommand("workspace-glob", async (args) => {
773
+ const pattern = args[0];
774
+ if (!pattern) return {
775
+ stdout: "",
776
+ stderr: "Missing pattern\n",
777
+ exitCode: 2
778
+ };
779
+ try {
780
+ return {
781
+ stdout: JSON.stringify(await bridge.glob(pattern)) + "\n",
782
+ stderr: "",
783
+ exitCode: 0
784
+ };
785
+ } catch (error) {
786
+ return {
787
+ stdout: "",
788
+ stderr: `${error instanceof Error ? error.message : String(error)}\n`,
789
+ exitCode: 1
790
+ };
791
+ }
792
+ }));
793
+ if (bridge.workspaceAccess === "read-write") customCommands.push(defineCommand("workspace-write", async (args, ctx) => {
794
+ const path = args[0];
795
+ if (!path) return {
796
+ stdout: "",
797
+ stderr: "Missing path\n",
798
+ exitCode: 2
799
+ };
800
+ try {
801
+ await bridge.writeFile(path, stdinText(ctx.stdin));
802
+ return {
803
+ stdout: "",
804
+ stderr: "",
805
+ exitCode: 0
806
+ };
807
+ } catch (error) {
808
+ return {
809
+ stdout: "",
810
+ stderr: `${error instanceof Error ? error.message : String(error)}\n`,
811
+ exitCode: 1
812
+ };
813
+ }
814
+ }));
815
+ }
816
+ if (bridge.hasTools()) customCommands.push(defineCommand("tool", async (args, ctx) => {
817
+ const name = args[0];
818
+ if (!name) return {
819
+ stdout: "",
820
+ stderr: "Missing tool name\n",
821
+ exitCode: 2
822
+ };
823
+ try {
824
+ const rawInput = args[1] ?? stdinText(ctx.stdin) ?? "{}";
825
+ const input = rawInput.trim() ? JSON.parse(rawInput) : {};
826
+ const result = await bridge.callTool(name, input);
827
+ return {
828
+ stdout: JSON.stringify(result) + "\n",
829
+ stderr: "",
830
+ exitCode: 0
831
+ };
832
+ } catch (error) {
833
+ return {
834
+ stdout: "",
835
+ stderr: `${error instanceof Error ? error.message : String(error)}\n`,
836
+ exitCode: 1
837
+ };
838
+ }
839
+ }));
840
+ const controller = new AbortController();
841
+ const timeout = setTimeout(() => controller.abort(), effectiveTimeout(options));
842
+ try {
843
+ const result = await new Bash({
844
+ files: bashFiles(request),
845
+ customCommands,
846
+ defenseInDepth: true,
847
+ network: options.network ? {} : void 0
848
+ }).exec("bash /skill-script.sh", {
849
+ signal: controller.signal,
850
+ stdin: JSON.stringify(request.input)
851
+ });
852
+ return {
853
+ stdout: result.stdout,
854
+ stderr: result.stderr,
855
+ exitCode: result.exitCode
856
+ };
857
+ } finally {
858
+ if (timeout) clearTimeout(timeout);
859
+ }
860
+ }
861
+ async function runJavaScriptScript(request, options, bridge, runtime) {
862
+ if (!hasDefaultExport(request.source)) throw new Error("JS/TS skill scripts must `export default` an async run(input, ctx) function.");
863
+ const source = prepareJavaScriptSource(request, runtime);
864
+ const result = await new DynamicWorkerExecutor({
865
+ loader: options.loader,
866
+ timeout: effectiveTimeout(options),
867
+ globalOutbound: options.network ? void 0 : null
868
+ }).execute(scriptModule(source, request), [resolveProvider(hostProvider(bridge))]);
869
+ if (result.error) {
870
+ const logs = result.logs?.length ? `\n\nConsole output:\n${result.logs.join("\n")}` : "";
871
+ throw new Error(`${result.error}${logs}`);
872
+ }
873
+ const outputFiles = bridge.getOutputFiles();
874
+ if (result.logs?.length || outputFiles.length > 0) return {
875
+ result: result.result,
876
+ ...result.logs?.length ? { logs: result.logs } : {},
877
+ ...outputFiles.length > 0 ? { outputFiles } : {}
878
+ };
879
+ return result.result;
880
+ }
881
+ /**
882
+ * Create a skill script runner backed by a Worker Loader.
883
+ *
884
+ * Capabilities are opt-in and enforced by a single host bridge: no network and
885
+ * no tools by default, read-only workspace access when `workspaceInstance` is
886
+ * provided. JS/TS scripts are function-style (`export default run(input, ctx)`)
887
+ * and receive `ctx = { skill, files, workspace, tools, output }`. Python and
888
+ * Bash use the path-based `/skill`, `/input.json`, `/output` contract.
889
+ *
890
+ * @experimental Skill script execution is experimental and may change before
891
+ * stabilizing.
892
+ */
893
+ function runner(options) {
894
+ return { async run(request) {
895
+ if (!runnerExperimentalWarned) {
896
+ runnerExperimentalWarned = true;
897
+ console.warn("[think] skills.runner script execution is experimental; the API and capabilities may change.");
898
+ }
899
+ const tools = typeof options.tools === "function" ? await options.tools() : options.tools;
900
+ const validation = parseSkillScriptPath(request.path);
901
+ if (!validation.ok) throw new Error(validation.error);
902
+ validateMountedResourcePaths(request);
903
+ const bridge = new SkillScriptHostBridge(tools, options.workspaceInstance, effectiveWorkspaceAccess(options));
904
+ if (validation.runtime === "bash") return await runBashScript(request, options, bridge);
905
+ if (validation.runtime === "python") return await runPythonScript(request, options, bridge);
906
+ return await runJavaScriptScript(request, options, bridge, validation.runtime);
907
+ } };
908
+ }
909
+ //#endregion
910
+ export { runner };
911
+
912
+ //# sourceMappingURL=runner.js.map