agents 0.22.0 → 0.23.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 (186) hide show
  1. package/README.md +20 -1
  2. package/dist/{agent-routing-CnkaHb-v.d.ts → agent-routing-DE5zmCQ8.d.ts} +1038 -394
  3. package/dist/agent-routing.d.ts +1 -1
  4. package/dist/agent-tool-types.d.ts +26 -26
  5. package/dist/{agent-tools-C0XJqWzB.d.ts → agent-tools-DtXMTDGM.d.ts} +7 -7
  6. package/dist/agent-tools.d.ts +21 -21
  7. package/dist/browser/ai.js +4 -1
  8. package/dist/browser/ai.js.map +1 -1
  9. package/dist/browser/tanstack-ai.js.map +1 -1
  10. package/dist/callable-decorator-DP__HhBA.d.ts +72 -0
  11. package/dist/callable-decorator.d.ts +18 -0
  12. package/dist/callable-decorator.js +71 -0
  13. package/dist/callable-decorator.js.map +1 -0
  14. package/dist/capability-BjSKYpzg.js.map +1 -1
  15. package/dist/capability-runner-Be_-PLR1.d.ts +459 -0
  16. package/dist/channel-Bnm4S7T2.d.ts +491 -0
  17. package/dist/channels/ai-sdk.d.ts +46 -0
  18. package/dist/channels/ai-sdk.js +120 -0
  19. package/dist/channels/ai-sdk.js.map +1 -0
  20. package/dist/channels/email.d.ts +95 -0
  21. package/dist/channels/email.js +323 -0
  22. package/dist/channels/email.js.map +1 -0
  23. package/dist/channels/index.d.ts +233 -0
  24. package/dist/channels/index.js +608 -0
  25. package/dist/channels/index.js.map +1 -0
  26. package/dist/channels/slack.d.ts +140 -0
  27. package/dist/channels/slack.js +614 -0
  28. package/dist/channels/slack.js.map +1 -0
  29. package/dist/channels/tanstack-ai.d.ts +39 -0
  30. package/dist/channels/tanstack-ai.js +17 -0
  31. package/dist/channels/tanstack-ai.js.map +1 -0
  32. package/dist/channels/telegram.d.ts +106 -0
  33. package/dist/channels/telegram.js +427 -0
  34. package/dist/channels/telegram.js.map +1 -0
  35. package/dist/channels/voice.d.ts +45 -0
  36. package/dist/channels/voice.js +122 -0
  37. package/dist/channels/voice.js.map +1 -0
  38. package/dist/chat/index.d.ts +2325 -2019
  39. package/dist/chat/index.js +888 -518
  40. package/dist/chat/index.js.map +1 -1
  41. package/dist/chat-sdk/index.d.ts +7 -7
  42. package/dist/chat-sdk/index.js +1 -1
  43. package/dist/client.d.ts +1 -1
  44. package/dist/context/index.d.ts +216 -0
  45. package/dist/context/index.js +454 -0
  46. package/dist/context/index.js.map +1 -0
  47. package/dist/{current-agent-CuMErtly.d.ts → current-agent-Da_C9a3b.d.ts} +90 -107
  48. package/dist/current-agent-DhoDkSnH.js.map +1 -1
  49. package/dist/{diagnostics-CaBjfz4J.js → diagnostics-BzvaX2UT.js} +5 -1
  50. package/dist/diagnostics-BzvaX2UT.js.map +1 -0
  51. package/dist/diagnostics-C4jcz3VK.js +360 -0
  52. package/dist/diagnostics-C4jcz3VK.js.map +1 -0
  53. package/dist/index-BB0kqhIz.d.ts +101 -0
  54. package/dist/index-BVVgDSdq.d.ts +1 -0
  55. package/dist/index-XDkuQ7zm.d.ts +89 -0
  56. package/dist/{index-DcSAZKsB.d.ts → index-YSKgfgg9.d.ts} +3 -1
  57. package/dist/index.d.ts +91 -82
  58. package/dist/index.js +3 -2
  59. package/dist/ingress-BfetZbMO.js +83 -0
  60. package/dist/ingress-BfetZbMO.js.map +1 -0
  61. package/dist/internal-CYlgHl1l.js +59 -0
  62. package/dist/internal-CYlgHl1l.js.map +1 -0
  63. package/dist/internal_context.d.ts +1 -1
  64. package/dist/lifecycle/index.d.ts +35 -17
  65. package/dist/lifecycle/index.js +1 -1
  66. package/dist/lifecycle-CMRGjZdw.js +1299 -0
  67. package/dist/lifecycle-CMRGjZdw.js.map +1 -0
  68. package/dist/mcp/client/index.d.ts +20 -20
  69. package/dist/mcp/index.d.ts +35 -35
  70. package/dist/mcp/index.js +1 -1
  71. package/dist/observability/index.d.ts +1 -1
  72. package/dist/observability/index.js +1 -1
  73. package/dist/react.d.ts +4 -4
  74. package/dist/{retries-CAvxtG9d.d.ts → retries-D9Ds-1lz.d.ts} +17 -6
  75. package/dist/retries.d.ts +8 -6
  76. package/dist/retries.js +13 -1
  77. package/dist/retries.js.map +1 -1
  78. package/dist/routing/index.d.ts +137 -0
  79. package/dist/routing/index.js +244 -0
  80. package/dist/routing/index.js.map +1 -0
  81. package/dist/sanitize-D9TujEK8.js +79 -0
  82. package/dist/sanitize-D9TujEK8.js.map +1 -0
  83. package/dist/scheduler-DD9NdYbF.js +665 -0
  84. package/dist/scheduler-DD9NdYbF.js.map +1 -0
  85. package/dist/{scheduler-DQoTGoAW.d.ts → scheduler-Dwh85ZGl.d.ts} +21 -22
  86. package/dist/schedules/index.d.ts +1 -1
  87. package/dist/schedules/index.js +1 -1
  88. package/dist/sentence-chunker-BAidJ4DA.d.ts +68 -0
  89. package/dist/serializable.d.ts +1 -1
  90. package/dist/sessions/index.d.ts +441 -0
  91. package/dist/sessions/index.js +2063 -0
  92. package/dist/sessions/index.js.map +1 -0
  93. package/dist/skills/index.d.ts +99 -0
  94. package/dist/skills/index.js +254 -5
  95. package/dist/skills/index.js.map +1 -1
  96. package/dist/{src-5W6JNKVb.js → src-DlSHshb2.js} +1460 -1110
  97. package/dist/src-DlSHshb2.js.map +1 -0
  98. package/dist/streams/index.d.ts +120 -0
  99. package/dist/streams/index.js +107 -0
  100. package/dist/streams/index.js.map +1 -0
  101. package/dist/streams-D6tJ0NN9.d.ts +370 -0
  102. package/dist/streams-DZKgAj9b.js +709 -0
  103. package/dist/streams-DZKgAj9b.js.map +1 -0
  104. package/dist/sub-routing.d.ts +12 -12
  105. package/dist/surface-bZZJqBka.js +17 -0
  106. package/dist/surface-bZZJqBka.js.map +1 -0
  107. package/dist/tasks/index.d.ts +64 -0
  108. package/dist/tasks/index.js +2 -0
  109. package/dist/tasks-BRJ5zgya.d.ts +517 -0
  110. package/dist/tasks-ylZgBjhj.js +1656 -0
  111. package/dist/tasks-ylZgBjhj.js.map +1 -0
  112. package/dist/text-segment-joiner-BtAFQSA_.js +57 -0
  113. package/dist/text-segment-joiner-BtAFQSA_.js.map +1 -0
  114. package/dist/text-stream-CpdiKrJB.js +272 -0
  115. package/dist/text-stream-CpdiKrJB.js.map +1 -0
  116. package/dist/tokens-nHAKcN6M.js +52 -0
  117. package/dist/tokens-nHAKcN6M.js.map +1 -0
  118. package/dist/tool-schema-CBjGPrsQ.js +31 -0
  119. package/dist/tool-schema-CBjGPrsQ.js.map +1 -0
  120. package/dist/types-B7LojTe4.d.ts +202 -0
  121. package/dist/types-_Faxb570.d.ts +439 -0
  122. package/dist/voice/client.d.ts +226 -0
  123. package/dist/voice/client.js +932 -0
  124. package/dist/voice/client.js.map +1 -0
  125. package/dist/voice/errors.d.ts +43 -0
  126. package/dist/voice/errors.js +41 -0
  127. package/dist/voice/errors.js.map +1 -0
  128. package/dist/voice/index.d.ts +271 -0
  129. package/dist/voice/index.js +1812 -0
  130. package/dist/voice/index.js.map +1 -0
  131. package/dist/voice/react.d.ts +167 -0
  132. package/dist/voice/react.js +234 -0
  133. package/dist/voice/react.js.map +1 -0
  134. package/dist/voice/sfu.d.ts +71 -0
  135. package/dist/voice/sfu.js +157 -0
  136. package/dist/voice/sfu.js.map +1 -0
  137. package/dist/voice/text.d.ts +6 -0
  138. package/dist/voice/text.js +2 -0
  139. package/dist/voice/types.d.ts +58 -0
  140. package/dist/voice/types.js +18 -0
  141. package/dist/voice/types.js.map +1 -0
  142. package/dist/voice/workers-ai.d.ts +136 -0
  143. package/dist/voice/workers-ai.js +568 -0
  144. package/dist/voice/workers-ai.js.map +1 -0
  145. package/dist/websockets/index.d.ts +192 -0
  146. package/dist/websockets/index.js +2 -0
  147. package/dist/websockets-DUfRHPRq.js +502 -0
  148. package/dist/websockets-DUfRHPRq.js.map +1 -0
  149. package/dist/workflow-types.d.ts +25 -25
  150. package/dist/workflows.d.ts +21 -21
  151. package/dist/workflows.js +1 -1
  152. package/docs/agent-class.md +2 -2
  153. package/docs/agent-tools.md +2 -1
  154. package/docs/channels.md +323 -0
  155. package/docs/chat-agents.md +6 -13
  156. package/docs/context.md +131 -0
  157. package/docs/index.md +15 -12
  158. package/docs/lifecycle.md +102 -55
  159. package/docs/long-running-agents.md +2 -2
  160. package/docs/mcp-servers.md +5 -1
  161. package/docs/resumable-streaming.md +1 -1
  162. package/docs/routing.md +105 -0
  163. package/docs/sessions.md +237 -871
  164. package/docs/streams.md +213 -0
  165. package/docs/sub-agents.md +184 -124
  166. package/docs/tasks.md +246 -0
  167. package/docs/voice.md +745 -0
  168. package/package.json +115 -13
  169. package/dist/capability-runner-CvHGZqUu.d.ts +0 -150
  170. package/dist/compaction-helpers-iiKMr2TQ.js +0 -340
  171. package/dist/compaction-helpers-iiKMr2TQ.js.map +0 -1
  172. package/dist/compaction-helpers-wUz6M3us.d.ts +0 -621
  173. package/dist/diagnostics-CaBjfz4J.js.map +0 -1
  174. package/dist/durable-object-lifecycle-D6nNQJJd.js +0 -862
  175. package/dist/durable-object-lifecycle-D6nNQJJd.js.map +0 -1
  176. package/dist/experimental/memory/session/index.d.ts +0 -671
  177. package/dist/experimental/memory/session/index.js +0 -2379
  178. package/dist/experimental/memory/session/index.js.map +0 -1
  179. package/dist/experimental/memory/utils/index.d.ts +0 -96
  180. package/dist/experimental/memory/utils/index.js +0 -79
  181. package/dist/experimental/memory/utils/index.js.map +0 -1
  182. package/dist/scheduler-CR9RHGos.js +0 -857
  183. package/dist/scheduler-CR9RHGos.js.map +0 -1
  184. package/dist/src-5W6JNKVb.js.map +0 -1
  185. package/dist/tool-output-truncation-CNnnGZQ3.js +0 -98
  186. package/dist/tool-output-truncation-CNnnGZQ3.js.map +0 -1
@@ -1097,11 +1097,158 @@ function runner(options) {
1097
1097
  } };
1098
1098
  }
1099
1099
  //#endregion
1100
+ //#region src/skills/workspace.ts
1101
+ /** @internal Parse and adapt a Computer or legacy Shell Workspace. */
1102
+ function createSkillWorkspaceFiles(workspace, rootOverride) {
1103
+ const computer = isComputerWorkspace(workspace);
1104
+ const root = parseRoot(rootOverride ?? (computer ? "/workspace/.agents/skills" : "/.agents/skills"));
1105
+ const exists = async (path) => {
1106
+ try {
1107
+ const stat = computer ? await workspace.fs.stat(path) : await workspace.stat(path);
1108
+ return stat !== null && stat !== void 0;
1109
+ } catch (error) {
1110
+ if (isNotFound(error)) return false;
1111
+ throw error;
1112
+ }
1113
+ };
1114
+ const readText = async (path) => {
1115
+ try {
1116
+ return computer ? await workspace.fs.readFile(path, "utf8") : await workspace.readFile(path);
1117
+ } catch (error) {
1118
+ if (isNotFound(error)) return null;
1119
+ throw error;
1120
+ }
1121
+ };
1122
+ const readBytes = async (path) => {
1123
+ if (!computer) return workspace.readFileBytes(path);
1124
+ try {
1125
+ return await drain(await workspace.fs.readFile(path));
1126
+ } catch (error) {
1127
+ if (isNotFound(error)) return null;
1128
+ throw error;
1129
+ }
1130
+ };
1131
+ const mkdirParent = async (path) => {
1132
+ const parent = path.slice(0, path.lastIndexOf("/"));
1133
+ if (!parent) return;
1134
+ if (computer) await workspace.fs.mkdir(parent, { recursive: true });
1135
+ else await workspace.mkdir(parent, { recursive: true });
1136
+ };
1137
+ return {
1138
+ root,
1139
+ path(name, relativePath) {
1140
+ return `${root}/${parseSkillDirectoryName(name)}/${parseRelativePath(relativePath)}`;
1141
+ },
1142
+ exists,
1143
+ readText,
1144
+ async readResource(path, descriptor) {
1145
+ if ((descriptor.encoding ?? "text") === "text") {
1146
+ const content = await readText(path);
1147
+ return content === null ? null : {
1148
+ ...descriptor,
1149
+ content
1150
+ };
1151
+ }
1152
+ const bytes = await readBytes(path);
1153
+ return bytes === null ? null : {
1154
+ ...descriptor,
1155
+ content: encodeBase64(bytes)
1156
+ };
1157
+ },
1158
+ async writeText(path, content) {
1159
+ await mkdirParent(path);
1160
+ if (computer) await workspace.fs.writeFile(path, content);
1161
+ else await workspace.writeFile(path, content);
1162
+ },
1163
+ async writeResource(path, resource) {
1164
+ await mkdirParent(path);
1165
+ if ((resource.encoding ?? "text") === "text") {
1166
+ if (computer) await workspace.fs.writeFile(path, resource.content);
1167
+ else await workspace.writeFile(path, resource.content);
1168
+ return;
1169
+ }
1170
+ const bytes = decodeBase64(resource.content);
1171
+ if (computer) await workspace.fs.writeFile(path, bytes);
1172
+ else await workspace.writeFileBytes(path, bytes, resource.mimeType);
1173
+ }
1174
+ };
1175
+ }
1176
+ function isComputerWorkspace(workspace) {
1177
+ return "fs" in workspace;
1178
+ }
1179
+ function parseRoot(root) {
1180
+ if (!root.startsWith("/") || root.includes("\0") || root.split("/").some((part) => part === "." || part === "..")) throw new Error(`Skill Workspace root must be a normalized absolute path: ${root}`);
1181
+ const normalized = root.replace(/\/{2,}/g, "/").replace(/\/$/, "");
1182
+ if (!normalized) throw new Error("Skill Workspace root cannot be /");
1183
+ return normalized;
1184
+ }
1185
+ function parseSkillDirectoryName(name) {
1186
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(name)) throw new Error(`Skill name must be a safe Workspace directory name: ${name}`);
1187
+ return name;
1188
+ }
1189
+ function parseRelativePath(path) {
1190
+ if (path.startsWith("/") || path.includes("\0") || path.split("/").some((part) => part === "" || part === "." || part === "..")) throw new Error(`Skill file path must be normalized and relative: ${path}`);
1191
+ return path;
1192
+ }
1193
+ function isNotFound(error) {
1194
+ if (!error || typeof error !== "object") return false;
1195
+ const record = error;
1196
+ return record.code === "ENOENT" || typeof record.message === "string" && /ENOENT|no such file|not found/i.test(record.message);
1197
+ }
1198
+ async function drain(stream) {
1199
+ const parts = [];
1200
+ let total = 0;
1201
+ const reader = stream.getReader();
1202
+ try {
1203
+ while (true) {
1204
+ const { value, done } = await reader.read();
1205
+ if (done) break;
1206
+ if (!value || value.byteLength === 0) continue;
1207
+ parts.push(value);
1208
+ total += value.byteLength;
1209
+ }
1210
+ } finally {
1211
+ reader.releaseLock();
1212
+ }
1213
+ if (parts.length === 1) return parts[0];
1214
+ const bytes = new Uint8Array(total);
1215
+ let offset = 0;
1216
+ for (const part of parts) {
1217
+ bytes.set(part, offset);
1218
+ offset += part.byteLength;
1219
+ }
1220
+ return bytes;
1221
+ }
1222
+ function decodeBase64(value) {
1223
+ const binary = atob(value);
1224
+ const bytes = new Uint8Array(binary.length);
1225
+ for (let index = 0; index < binary.length; index++) bytes[index] = binary.charCodeAt(index);
1226
+ return bytes;
1227
+ }
1228
+ function encodeBase64(bytes) {
1229
+ const parts = [];
1230
+ for (let offset = 0; offset < bytes.byteLength; offset += 32768) parts.push(String.fromCharCode(...bytes.subarray(offset, offset + 32768)));
1231
+ return btoa(parts.join(""));
1232
+ }
1233
+ //#endregion
1100
1234
  //#region src/skills/registry.ts
1101
1235
  const SKILL_CONTEXT_LABEL = "think_skills";
1102
1236
  function stableSourceFingerprint(sources) {
1103
1237
  return sources.map((source) => `${source.id}:${source.fingerprint}`).join("|");
1104
1238
  }
1239
+ function renderSkillMarkdown(skill) {
1240
+ const lines = [
1241
+ "---",
1242
+ `name: ${JSON.stringify(skill.name)}`,
1243
+ `description: ${JSON.stringify(skill.description)}`
1244
+ ];
1245
+ if (skill.compatibility) lines.push(`compatibility: ${JSON.stringify(skill.compatibility)}`);
1246
+ if (skill.license) lines.push(`license: ${JSON.stringify(skill.license)}`);
1247
+ if (skill.allowedTools) lines.push(`allowed-tools: ${JSON.stringify(skill.allowedTools)}`);
1248
+ if (skill.metadata) lines.push(`metadata: ${JSON.stringify(skill.metadata)}`);
1249
+ lines.push("---", "", skill.body);
1250
+ return lines.join("\n");
1251
+ }
1105
1252
  function wrapSkillContent(skill) {
1106
1253
  const version = skill.version ? ` version="${skill.version}"` : "";
1107
1254
  const resourceList = skill.resources?.length ? [
@@ -1137,6 +1284,9 @@ var SkillRegistry = class {
1137
1284
  this.descriptors = /* @__PURE__ */ new Map();
1138
1285
  this.sourceBySkill = /* @__PURE__ */ new Map();
1139
1286
  this.loaded = false;
1287
+ this.workspaceFiles = null;
1288
+ this.workspaceSkillNames = /* @__PURE__ */ new Set();
1289
+ this.workspaceResources = /* @__PURE__ */ new Map();
1140
1290
  this.sources = sources;
1141
1291
  this.scriptRunner = scriptRunner;
1142
1292
  }
@@ -1184,6 +1334,72 @@ var SkillRegistry = class {
1184
1334
  await this.load();
1185
1335
  this.warnings.push(...refreshErrors);
1186
1336
  }
1337
+ /**
1338
+ * Seed resolved Agent Skills into Computer or legacy Shell storage.
1339
+ * Existing files are preserved by default, and become authoritative for
1340
+ * activation, resource reads, and script execution.
1341
+ */
1342
+ async seedWorkspace(workspace, options = {}) {
1343
+ await this.load();
1344
+ const files = createSkillWorkspaceFiles(workspace, options.root);
1345
+ const result = {
1346
+ written: 0,
1347
+ preserved: 0,
1348
+ skipped: 0,
1349
+ warnings: [],
1350
+ root: files.root
1351
+ };
1352
+ const seeded = /* @__PURE__ */ new Set();
1353
+ const resources = /* @__PURE__ */ new Map();
1354
+ for (const descriptor of this.descriptors.values()) {
1355
+ const source = this.sourceBySkill.get(descriptor.name);
1356
+ let skill = null;
1357
+ try {
1358
+ skill = await source?.load(descriptor.name) ?? null;
1359
+ } catch (error) {
1360
+ result.skipped++;
1361
+ result.warnings.push(`Could not load skill "${descriptor.name}" for Workspace seeding: ${error instanceof Error ? error.message : String(error)}`);
1362
+ continue;
1363
+ }
1364
+ if (!skill) {
1365
+ result.skipped++;
1366
+ result.warnings.push(`Could not load skill "${descriptor.name}" for Workspace seeding.`);
1367
+ continue;
1368
+ }
1369
+ resources.set(descriptor.name, new Map((skill.resources ?? []).map((resource) => [resource.path, resource])));
1370
+ const skillPath = files.path(descriptor.name, "SKILL.md");
1371
+ if (await this.writeSeedFile(files, skillPath, skill.rawContent ?? renderSkillMarkdown(skill), options, result)) seeded.add(descriptor.name);
1372
+ }
1373
+ this.workspaceFiles = files;
1374
+ this.workspaceSkillNames = seeded;
1375
+ this.workspaceResources = resources;
1376
+ return result;
1377
+ }
1378
+ /**
1379
+ * Route skill reads through an already-seeded Workspace without probing or
1380
+ * rewriting its files. Hosts use this when the durable source fingerprint
1381
+ * matches the recorded projection fingerprint.
1382
+ */
1383
+ async useWorkspace(workspace, options = {}) {
1384
+ await this.load();
1385
+ this.workspaceFiles = createSkillWorkspaceFiles(workspace, options.root);
1386
+ this.workspaceSkillNames = new Set(this.descriptors.keys());
1387
+ this.workspaceResources.clear();
1388
+ }
1389
+ async writeSeedFile(files, path, content, options, result) {
1390
+ try {
1391
+ if (options.onConflict !== "replace" && await files.exists(path)) {
1392
+ result.preserved++;
1393
+ return true;
1394
+ }
1395
+ await files.writeText(path, content);
1396
+ result.written++;
1397
+ return true;
1398
+ } catch {
1399
+ result.skipped++;
1400
+ return false;
1401
+ }
1402
+ }
1187
1403
  async snapshot() {
1188
1404
  await this.load();
1189
1405
  const catalog = [];
@@ -1192,6 +1408,7 @@ var SkillRegistry = class {
1192
1408
  fingerprint: this.fingerprint,
1193
1409
  catalogPrompt: catalog.length ? [
1194
1410
  "Available skills. When a task matches a skill, use activate_skill with its name before proceeding.",
1411
+ ...this.workspaceFiles ? [`Skill files are available at ${this.workspaceFiles.root}. Workspace edits affect later activations and resource reads.`] : [],
1195
1412
  "",
1196
1413
  ...catalog
1197
1414
  ].join("\n") : null
@@ -1203,7 +1420,23 @@ var SkillRegistry = class {
1203
1420
  async loadSkill(name) {
1204
1421
  await this.load();
1205
1422
  const source = this.sourceBySkill.get(name);
1206
- return source ? source.load(name) : null;
1423
+ if (!source) return null;
1424
+ const original = await source.load(name);
1425
+ if (!original) return null;
1426
+ this.workspaceResources.set(name, new Map((original.resources ?? []).map((resource) => [resource.path, resource])));
1427
+ if (!this.workspaceSkillNames.has(name)) return original;
1428
+ const rawContent = await this.workspaceFiles?.readText(this.workspaceFiles.path(name, "SKILL.md"));
1429
+ if (rawContent === null || rawContent === void 0) return null;
1430
+ const parsed = parseSkillMarkdown(rawContent);
1431
+ if (!parsed) return null;
1432
+ return {
1433
+ ...original,
1434
+ ...parsed,
1435
+ rawContent,
1436
+ sourceId: original.sourceId,
1437
+ version: original.version,
1438
+ resources: original.resources
1439
+ };
1207
1440
  }
1208
1441
  resolveResourceTarget(name, path) {
1209
1442
  const pathError = validateResourcePath(path);
@@ -1233,6 +1466,24 @@ var SkillRegistry = class {
1233
1466
  }
1234
1467
  async readResource(name, path) {
1235
1468
  const source = this.sourceBySkill.get(name);
1469
+ if (this.workspaceSkillNames.has(name) && this.workspaceFiles) {
1470
+ let descriptor = this.workspaceResources.get(name)?.get(path);
1471
+ if (!descriptor) {
1472
+ const skill = await source?.load(name);
1473
+ const resources = new Map((skill?.resources ?? []).map((resource) => [resource.path, resource]));
1474
+ this.workspaceResources.set(name, resources);
1475
+ descriptor = resources.get(path);
1476
+ }
1477
+ if (!descriptor) return `Resource not found: ${name}/${path}`;
1478
+ const workspacePath = this.workspaceFiles.path(name, path);
1479
+ const existing = await this.workspaceFiles.readResource(workspacePath, descriptor);
1480
+ if (existing) return existing;
1481
+ if (!source?.readResource) return `Skill "${name}" has no readable resources.`;
1482
+ const resource = await source.readResource(name, path);
1483
+ if (!resource) return `Resource not found: ${name}/${path}`;
1484
+ await this.workspaceFiles.writeResource(workspacePath, resource);
1485
+ return resource;
1486
+ }
1236
1487
  if (!source?.readResource) return `Skill "${name}" has no readable resources.`;
1237
1488
  return await source.readResource(name, path) ?? `Resource not found: ${name}/${path}`;
1238
1489
  }
@@ -1296,10 +1547,8 @@ var SkillRegistry = class {
1296
1547
  const script = skill.resources?.find((resource) => resource.path === path);
1297
1548
  if (!script) return `Script not found: ${name}/${path}`;
1298
1549
  if (script.kind !== "script") return `Resource is not a script: ${name}/${path}`;
1299
- const source = this.sourceBySkill.get(name);
1300
- if (!source?.readResource) return `Skill "${name}" has no readable resources.`;
1301
- const resource = await source.readResource(name, path);
1302
- if (!resource) return `Script not found: ${name}/${path}`;
1550
+ const resource = await this.readResource(name, path);
1551
+ if (typeof resource === "string") return resource;
1303
1552
  if ((resource.encoding ?? "text") !== "text") return `Script resource must be text, got ${resource.encoding}: ${name}/${path}`;
1304
1553
  try {
1305
1554
  return await this.scriptRunner.run({