@cursor/july 0.1.100 → 0.1.101

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 (254) hide show
  1. package/dist/bin/agent-serve.js +3 -2
  2. package/dist/channels/deployments/deployments-channel.d.ts +41 -5
  3. package/dist/channels/deployments/deployments-channel.d.ts.map +1 -1
  4. package/dist/channels/deployments/deployments-channel.js +88 -8
  5. package/dist/channels/deployments/types.d.ts +4 -3
  6. package/dist/channels/deployments/types.d.ts.map +1 -1
  7. package/dist/channels/origin/defaults.d.ts +43 -0
  8. package/dist/channels/origin/defaults.d.ts.map +1 -0
  9. package/dist/channels/origin/defaults.js +111 -0
  10. package/dist/channels/origin/index.d.ts +2 -0
  11. package/dist/channels/origin/index.d.ts.map +1 -1
  12. package/dist/channels/origin/index.js +2 -0
  13. package/dist/channels/origin/origin-channel.d.ts +2 -1
  14. package/dist/channels/origin/origin-channel.d.ts.map +1 -1
  15. package/dist/channels/origin/origin-channel.js +24 -3
  16. package/dist/channels/origin/state.d.ts +32 -0
  17. package/dist/channels/origin/state.d.ts.map +1 -0
  18. package/dist/channels/origin/state.js +23 -0
  19. package/dist/channels/origin/types.d.ts +23 -1
  20. package/dist/channels/origin/types.d.ts.map +1 -1
  21. package/dist/channels/slack/api.d.ts.map +1 -1
  22. package/dist/channels/slack/api.js +2 -1
  23. package/dist/channels/slack/code-fences.d.ts +17 -0
  24. package/dist/channels/slack/code-fences.d.ts.map +1 -0
  25. package/dist/channels/slack/code-fences.js +168 -0
  26. package/dist/channels/slack/index.d.ts +1 -0
  27. package/dist/channels/slack/index.d.ts.map +1 -1
  28. package/dist/channels/slack/index.js +1 -0
  29. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  30. package/dist/channels/slack/live-delivery.js +11 -4
  31. package/dist/connections.d.ts +18 -2
  32. package/dist/connections.d.ts.map +1 -1
  33. package/dist/connections.js +18 -2
  34. package/dist/docs/404.html +2 -2
  35. package/dist/docs/ab.html +4 -4
  36. package/dist/docs/assets/{app.DZ1e0Ycq.js → app.BASO9Kih.js} +1 -1
  37. package/dist/docs/assets/chunks/@localSearchIndexroot.DbFXINq2.js +1 -0
  38. package/dist/docs/assets/chunks/{VPLocalSearchBox.l8omwc6D.js → VPLocalSearchBox.DwkqxoE0.js} +1 -1
  39. package/dist/docs/assets/chunks/{theme.JVcD6gel.js → theme.CCil_13e.js} +2 -2
  40. package/dist/docs/assets/{reference_connections.md.BiGoBAk2.js → reference_connections.md.Di6jJAXF.js} +12 -2
  41. package/dist/docs/assets/{reference_connections.md.BiGoBAk2.lean.js → reference_connections.md.Di6jJAXF.lean.js} +1 -1
  42. package/dist/docs/assets/{reference_http-api.md.BEJx9XVj.js → reference_http-api.md.oySXBO8o.js} +1 -1
  43. package/dist/docs/building-with-agents.html +4 -4
  44. package/dist/docs/concepts.html +4 -4
  45. package/dist/docs/deployment.html +4 -4
  46. package/dist/docs/evals.html +4 -4
  47. package/dist/docs/guides/agent-to-agent.html +4 -4
  48. package/dist/docs/guides/cloud-runtime.html +4 -4
  49. package/dist/docs/guides/convert-automation.html +4 -4
  50. package/dist/docs/guides/github.html +4 -4
  51. package/dist/docs/guides/human-in-the-loop.html +4 -4
  52. package/dist/docs/guides/mcp-oauth.html +4 -4
  53. package/dist/docs/guides/opentelemetry.html +4 -4
  54. package/dist/docs/guides/slack.html +4 -4
  55. package/dist/docs/guides/webhooks.html +4 -4
  56. package/dist/docs/hashmap.json +1 -1
  57. package/dist/docs/hillclimbing.html +4 -4
  58. package/dist/docs/index.html +4 -4
  59. package/dist/docs/llms-full.txt +32 -1
  60. package/dist/docs/quickstart.html +4 -4
  61. package/dist/docs/reference/agent-config.html +4 -4
  62. package/dist/docs/reference/artifacts.html +4 -4
  63. package/dist/docs/reference/channels.html +4 -4
  64. package/dist/docs/reference/cli.html +4 -4
  65. package/dist/docs/reference/connections.html +16 -6
  66. package/dist/docs/reference/connections.md +31 -0
  67. package/dist/docs/reference/hooks.html +4 -4
  68. package/dist/docs/reference/http-api.html +6 -6
  69. package/dist/docs/reference/http-api.md +1 -1
  70. package/dist/docs/reference/instructions.html +4 -4
  71. package/dist/docs/reference/playground.html +4 -4
  72. package/dist/docs/reference/project-layout.html +4 -4
  73. package/dist/docs/reference/prompt.html +4 -4
  74. package/dist/docs/reference/schedules.html +4 -4
  75. package/dist/docs/reference/sessions.html +4 -4
  76. package/dist/docs/reference/skills.html +4 -4
  77. package/dist/docs/reference/subagents.html +4 -4
  78. package/dist/docs/reference/tools.html +4 -4
  79. package/dist/docs/scaffolding-agents.html +4 -4
  80. package/dist/docs/skills/ab.html +4 -4
  81. package/dist/docs/skills/create-agent.html +4 -4
  82. package/dist/docs/skills/debug.html +4 -4
  83. package/dist/docs/skills/evals.html +4 -4
  84. package/dist/docs/skills/framework-map.html +4 -4
  85. package/dist/docs/skills/github.html +4 -4
  86. package/dist/docs/skills/hillclimb.html +4 -4
  87. package/dist/docs/skills/index.html +4 -4
  88. package/dist/docs/skills/mcp-auth.html +4 -4
  89. package/dist/docs/skills/otel.html +4 -4
  90. package/dist/docs/skills/setup-slack.html +4 -4
  91. package/dist/docs/storage.html +4 -4
  92. package/dist/docs/templates/agentic-owners.html +4 -4
  93. package/dist/docs/templates/agents-md.html +4 -4
  94. package/dist/docs/templates/code-wiki.html +4 -4
  95. package/dist/docs/templates/demo.html +4 -4
  96. package/dist/docs/templates/pr-autofixer.html +4 -4
  97. package/dist/docs/templates/security-help.html +4 -4
  98. package/dist/docs/templates/security-reviewer.html +4 -4
  99. package/dist/docs/templates/triage.html +4 -4
  100. package/dist/docs/troubleshooting.html +4 -4
  101. package/dist/extensions/cursor-cloud-agents/extension.d.ts +55 -0
  102. package/dist/extensions/cursor-cloud-agents/extension.d.ts.map +1 -0
  103. package/dist/extensions/cursor-cloud-agents/extension.js +64 -0
  104. package/dist/extensions/cursor-cloud-agents/lib/cloud.d.ts +30 -0
  105. package/dist/extensions/cursor-cloud-agents/lib/cloud.d.ts.map +1 -0
  106. package/dist/extensions/cursor-cloud-agents/lib/cloud.js +45 -0
  107. package/dist/extensions/cursor-cloud-agents/lib/fleet.d.ts +25 -0
  108. package/dist/extensions/cursor-cloud-agents/lib/fleet.d.ts.map +1 -0
  109. package/dist/extensions/cursor-cloud-agents/lib/fleet.js +85 -0
  110. package/dist/extensions/cursor-cloud-agents/lib/repos.d.ts +15 -0
  111. package/dist/extensions/cursor-cloud-agents/lib/repos.d.ts.map +1 -0
  112. package/dist/extensions/cursor-cloud-agents/lib/repos.js +55 -0
  113. package/dist/extensions/cursor-cloud-agents/skills/handoff.md +27 -0
  114. package/dist/extensions/cursor-cloud-agents/tools/follow_up.d.ts +4 -0
  115. package/dist/extensions/cursor-cloud-agents/tools/follow_up.d.ts.map +1 -0
  116. package/dist/extensions/cursor-cloud-agents/tools/follow_up.js +37 -0
  117. package/dist/extensions/cursor-cloud-agents/tools/launch.d.ts +4 -0
  118. package/dist/extensions/cursor-cloud-agents/tools/launch.d.ts.map +1 -0
  119. package/dist/extensions/cursor-cloud-agents/tools/launch.js +83 -0
  120. package/dist/extensions/cursor-cloud-agents/tools/list.d.ts +4 -0
  121. package/dist/extensions/cursor-cloud-agents/tools/list.d.ts.map +1 -0
  122. package/dist/extensions/cursor-cloud-agents/tools/list.js +36 -0
  123. package/dist/extensions/cursor-cloud-agents/tools/status.d.ts +4 -0
  124. package/dist/extensions/cursor-cloud-agents/tools/status.d.ts.map +1 -0
  125. package/dist/extensions/cursor-cloud-agents/tools/status.js +41 -0
  126. package/dist/extensions.d.ts +49 -0
  127. package/dist/extensions.d.ts.map +1 -0
  128. package/dist/extensions.js +75 -0
  129. package/dist/index.d.ts +2 -1
  130. package/dist/index.d.ts.map +1 -1
  131. package/dist/index.js +2 -1
  132. package/dist/internal/advertise-tools.d.ts +4 -1
  133. package/dist/internal/advertise-tools.d.ts.map +1 -1
  134. package/dist/internal/advertise-tools.js +20 -1
  135. package/dist/internal/as-of.d.ts +18 -0
  136. package/dist/internal/as-of.d.ts.map +1 -1
  137. package/dist/internal/as-of.js +131 -0
  138. package/dist/internal/cli-deploy.d.ts.map +1 -1
  139. package/dist/internal/cli-deploy.js +64 -19
  140. package/dist/internal/continuation-identity.d.ts.map +1 -1
  141. package/dist/internal/continuation-identity.js +3 -1
  142. package/dist/internal/cursor/hosted-deployment-secrets.d.ts +16 -0
  143. package/dist/internal/cursor/hosted-deployment-secrets.d.ts.map +1 -0
  144. package/dist/internal/cursor/hosted-deployment-secrets.js +61 -0
  145. package/dist/internal/cursor-deployment-relay.d.ts +15 -1
  146. package/dist/internal/cursor-deployment-relay.d.ts.map +1 -1
  147. package/dist/internal/cursor-deployment-relay.js +46 -7
  148. package/dist/internal/deploy-client.d.ts +23 -0
  149. package/dist/internal/deploy-client.d.ts.map +1 -1
  150. package/dist/internal/deploy-client.js +54 -12
  151. package/dist/internal/discovery.d.ts.map +1 -1
  152. package/dist/internal/discovery.js +415 -120
  153. package/dist/internal/distribution.d.ts.map +1 -1
  154. package/dist/internal/distribution.js +5 -0
  155. package/dist/internal/framework-file-storage.d.ts +3 -3
  156. package/dist/internal/framework-file-storage.d.ts.map +1 -1
  157. package/dist/internal/framework-file-storage.js +34 -5
  158. package/dist/internal/hosted-delivery.d.ts +3 -1
  159. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  160. package/dist/internal/hosted-delivery.js +19 -32
  161. package/dist/internal/hosted-execution-diag.d.ts +5 -0
  162. package/dist/internal/hosted-execution-diag.d.ts.map +1 -1
  163. package/dist/internal/hosted-execution-diag.js +5 -0
  164. package/dist/internal/hosted-execution-flush.d.ts +46 -0
  165. package/dist/internal/hosted-execution-flush.d.ts.map +1 -0
  166. package/dist/internal/hosted-execution-flush.js +81 -0
  167. package/dist/internal/mcp-endpoint.js +1 -0
  168. package/dist/internal/mcp-host.d.ts +2 -1
  169. package/dist/internal/mcp-host.d.ts.map +1 -1
  170. package/dist/internal/mcp-host.js +35 -15
  171. package/dist/internal/review-comments.d.ts +1 -1
  172. package/dist/internal/review-comments.d.ts.map +1 -1
  173. package/dist/internal/review-comments.js +4 -4
  174. package/dist/internal/server.d.ts +3 -0
  175. package/dist/internal/server.d.ts.map +1 -1
  176. package/dist/internal/server.js +79 -104
  177. package/dist/internal/session-engine.d.ts +9 -7
  178. package/dist/internal/session-engine.d.ts.map +1 -1
  179. package/dist/internal/session-engine.js +45 -34
  180. package/dist/internal/session-run-log.d.ts +2 -1
  181. package/dist/internal/session-run-log.d.ts.map +1 -1
  182. package/dist/internal/session-run-log.js +2 -1
  183. package/dist/internal/start-log-store.d.ts +60 -0
  184. package/dist/internal/start-log-store.d.ts.map +1 -0
  185. package/dist/internal/start-log-store.js +151 -0
  186. package/dist/internal/tool-policy.d.ts +8 -0
  187. package/dist/internal/tool-policy.d.ts.map +1 -1
  188. package/dist/internal/tool-policy.js +19 -7
  189. package/dist/playground/assets/{index-DVs98vPL.js → index-BnNN1-EK.js} +45 -45
  190. package/dist/playground/assets/index-DBQCwFp0.css +1 -0
  191. package/dist/playground/index.html +2 -2
  192. package/dist/storage-protocol.d.ts +24 -0
  193. package/dist/storage-protocol.d.ts.map +1 -1
  194. package/dist/storage-protocol.js +33 -0
  195. package/dist/storage.d.ts +1 -1
  196. package/dist/storage.d.ts.map +1 -1
  197. package/dist/storage.js +1 -1
  198. package/dist/types.d.ts +118 -6
  199. package/dist/types.d.ts.map +1 -1
  200. package/dist/types.js +29 -1
  201. package/docs/reference/connections.md +31 -0
  202. package/docs/reference/http-api.md +1 -1
  203. package/package.json +18 -4
  204. package/src/bin/agent-serve.ts +11 -2
  205. package/src/channels/deployments/deployments-channel.ts +117 -8
  206. package/src/channels/deployments/types.ts +4 -3
  207. package/src/channels/origin/defaults.ts +143 -0
  208. package/src/channels/origin/index.ts +2 -0
  209. package/src/channels/origin/origin-channel.ts +37 -1
  210. package/src/channels/origin/state.ts +54 -0
  211. package/src/channels/origin/types.ts +24 -0
  212. package/src/channels/slack/api.ts +2 -1
  213. package/src/channels/slack/code-fences.ts +183 -0
  214. package/src/channels/slack/index.ts +1 -0
  215. package/src/channels/slack/live-delivery.ts +16 -13
  216. package/src/connections.ts +18 -1
  217. package/src/extensions/cursor-cloud-agents/extension.ts +118 -0
  218. package/src/extensions/cursor-cloud-agents/lib/cloud.ts +79 -0
  219. package/src/extensions/cursor-cloud-agents/lib/fleet.ts +109 -0
  220. package/src/extensions/cursor-cloud-agents/lib/repos.ts +81 -0
  221. package/src/extensions/cursor-cloud-agents/skills/handoff.md +27 -0
  222. package/src/extensions/cursor-cloud-agents/tools/follow_up.ts +29 -0
  223. package/src/extensions/cursor-cloud-agents/tools/launch.ts +84 -0
  224. package/src/extensions/cursor-cloud-agents/tools/list.ts +31 -0
  225. package/src/extensions/cursor-cloud-agents/tools/status.ts +39 -0
  226. package/src/extensions.ts +98 -0
  227. package/src/index.ts +2 -0
  228. package/src/internal/advertise-tools.ts +37 -12
  229. package/src/internal/as-of.ts +163 -0
  230. package/src/internal/cli-deploy.ts +86 -23
  231. package/src/internal/continuation-identity.ts +3 -1
  232. package/src/internal/cursor/hosted-deployment-secrets.ts +72 -0
  233. package/src/internal/cursor-deployment-relay.ts +65 -8
  234. package/src/internal/deploy-client.ts +73 -18
  235. package/src/internal/discovery.ts +470 -113
  236. package/src/internal/distribution.ts +5 -0
  237. package/src/internal/framework-file-storage.ts +39 -5
  238. package/src/internal/hosted-delivery.ts +38 -63
  239. package/src/internal/hosted-execution-diag.ts +6 -0
  240. package/src/internal/hosted-execution-flush.ts +142 -0
  241. package/src/internal/mcp-endpoint.ts +1 -0
  242. package/src/internal/mcp-host.ts +40 -14
  243. package/src/internal/review-comments.ts +5 -2
  244. package/src/internal/server.ts +81 -100
  245. package/src/internal/session-engine.ts +56 -28
  246. package/src/internal/session-run-log.ts +2 -1
  247. package/src/internal/start-log-store.ts +177 -0
  248. package/src/internal/tool-policy.ts +39 -9
  249. package/src/storage-protocol.ts +37 -0
  250. package/src/storage.ts +1 -0
  251. package/src/types.ts +172 -14
  252. package/dist/docs/assets/chunks/@localSearchIndexroot.j70vvPL4.js +0 -1
  253. package/dist/playground/assets/index-BszoQDc6.css +0 -1
  254. /package/dist/docs/assets/{reference_http-api.md.BEJx9XVj.lean.js → reference_http-api.md.oySXBO8o.lean.js} +0 -0
@@ -31,7 +31,7 @@ import { pathToFileURL } from "node:url";
31
31
  import { resolveABMaxPlaygroundSessions } from "../ab.js";
32
32
  import { resolveArtifactsMax } from "../artifacts.js";
33
33
  import { httpChannel } from "../channels.js";
34
- import { cursorAccountServersHasMixedWildcard, DEFAULT_MODEL, isInlineStdioConnection, isToolEffect, MAX_RUNNING_TURNS_LIMIT, normalizeConnectionEffects, normalizeCursorAccountServers, toPublicCloudInfo, } from "../types.js";
34
+ import { cursorAccountServersHasMixedWildcard, DEFAULT_MODEL, isInlineStdioConnection, isToolEffect, MAX_RUNNING_TURNS_LIMIT, normalizeConnectionEffects, normalizeConnectionTools, normalizeCursorAccountServers, toPublicCloudInfo, } from "../types.js";
35
35
  import { registerAuthoredModuleLoaders } from "./authored-loaders.js";
36
36
  import { normalizePositiveInt } from "./bounded-int.js";
37
37
  import { getDefinitionKind } from "./brand.js";
@@ -310,6 +310,7 @@ function loadAgent(ctx, agentDir, options) {
310
310
  }
311
311
  const tools = yield loadTools(ctx, join(agentDir, "tools"));
312
312
  const skills = yield loadSkills(ctx, join(agentDir, "skills"));
313
+ const extensions = yield appendExtensions(ctx, join(agentDir, "extensions"), tools, skills);
313
314
  const connections = yield loadConnections(ctx, yield resolveMcpConnectionsDir(ctx, agentDir));
314
315
  const hostConnections = yield loadHostConnections(ctx, agentDir, connections);
315
316
  const seedFiles = yield loadSeedFiles(ctx, agentDir);
@@ -430,6 +431,7 @@ function loadAgent(ctx, agentDir, options) {
430
431
  local }, (allowedTools === undefined ? {} : { allowedTools })), { hosting,
431
432
  concurrency }), (architecture === undefined ? {} : { architecture })), { tools,
432
433
  skills,
434
+ extensions,
433
435
  connections,
434
436
  hostConnections,
435
437
  subagents,
@@ -662,17 +664,34 @@ function loadInstructionsModule(ctx, modulePath) {
662
664
  // Tools
663
665
  // ============================================================================
664
666
  function loadTools(ctx, toolsDir) {
667
+ return __awaiter(this, void 0, void 0, function* () {
668
+ const tools = [];
669
+ for (const { name, path } of yield toolModuleEntries(ctx, toolsDir)) {
670
+ const definition = yield importDefault(ctx, path, "tool");
671
+ if (definition === undefined) {
672
+ continue;
673
+ }
674
+ const tool = compileTool(ctx, path, name, definition);
675
+ if (tool !== undefined) {
676
+ tools.push(tool);
677
+ }
678
+ }
679
+ return tools;
680
+ });
681
+ }
682
+ /** The module files of a `tools/` directory whose filenames are valid tool names. */
683
+ function toolModuleEntries(ctx, toolsDir) {
665
684
  return __awaiter(this, void 0, void 0, function* () {
666
685
  if (!(yield isDirectory(toolsDir))) {
667
686
  return [];
668
687
  }
669
- const tools = [];
688
+ const entries = [];
670
689
  for (const entry of yield sortedEntries(toolsDir)) {
671
- const entryPath = join(toolsDir, entry.name);
690
+ const path = join(toolsDir, entry.name);
672
691
  if (entry.isDirectory()) {
673
692
  ctx.diagnostics.push({
674
693
  severity: "warning",
675
- path: displayPath(ctx, entryPath),
694
+ path: displayPath(ctx, path),
676
695
  message: "Nested tool directories are not supported; ignoring.",
677
696
  });
678
697
  continue;
@@ -681,94 +700,99 @@ function loadTools(ctx, toolsDir) {
681
700
  continue;
682
701
  }
683
702
  const name = moduleStem(entry.name);
684
- if (!NAME_PATTERN.test(name)) {
685
- ctx.diagnostics.push({
686
- severity: "error",
687
- path: displayPath(ctx, entryPath),
688
- message: `Tool name "${name}" must match ${NAME_PATTERN} (the filename becomes the tool name the model sees).`,
689
- });
690
- continue;
691
- }
692
- const definition = yield importDefault(ctx, entryPath, "tool");
693
- if (definition === undefined) {
694
- continue;
695
- }
696
- const tool = definition;
697
- if (isBlank(tool.description)) {
698
- ctx.diagnostics.push({
699
- severity: "error",
700
- path: displayPath(ctx, entryPath),
701
- message: "Tools require a non-empty description.",
702
- });
703
- continue;
704
- }
705
- const execution = tool.execution === "agent" ? "agent" : "server";
706
- const needsApprovalConfigured = tool.needsApproval === true || typeof tool.needsApproval === "function";
707
- const effect = declaredEffect(tool);
708
- if (execution === "agent") {
709
- if (isBlank(tool.script)) {
710
- ctx.diagnostics.push({
711
- severity: "error",
712
- path: displayPath(ctx, entryPath),
713
- message: 'Tools with execution: "agent" require a non-empty `script` (shell body; JSON on stdin, result on stdout).',
714
- });
715
- continue;
716
- }
717
- if (typeof tool.execute === "function") {
718
- ctx.diagnostics.push({
719
- severity: "warning",
720
- path: displayPath(ctx, entryPath),
721
- message: '`execute` is ignored when execution is "agent"; the Cursor agent runs `script` instead.',
722
- });
723
- }
724
- if (needsApprovalConfigured) {
725
- ctx.diagnostics.push({
726
- severity: "error",
727
- path: displayPath(ctx, entryPath),
728
- message: '`needsApproval` is only supported for execution: "server" tools (in-process).',
729
- });
730
- continue;
731
- }
732
- }
733
- else if (typeof tool.execute !== "function") {
734
- ctx.diagnostics.push({
735
- severity: "error",
736
- path: displayPath(ctx, entryPath),
737
- message: 'Tools require an execute(input, ctx) function (or set execution: "agent" with a script).',
738
- });
739
- continue;
703
+ if (validateName(ctx, "tool", name, path)) {
704
+ entries.push({ name, path });
740
705
  }
741
- let inputSchema;
742
- try {
743
- inputSchema = toolInputJsonSchema(tool.inputSchema);
744
- }
745
- catch (error) {
746
- ctx.diagnostics.push({
747
- severity: "error",
748
- path: displayPath(ctx, entryPath),
749
- message: `Failed to convert inputSchema to JSON Schema: ${errorMessage(error)}`,
750
- });
751
- continue;
752
- }
753
- let outputSchema;
754
- try {
755
- outputSchema = toolOutputJsonSchema(tool.outputSchema);
756
- }
757
- catch (error) {
758
- ctx.diagnostics.push({
759
- severity: "error",
760
- path: displayPath(ctx, entryPath),
761
- message: `Failed to convert outputSchema to JSON Schema: ${errorMessage(error)}`,
762
- });
763
- continue;
764
- }
765
- tools.push(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ name, description: tool.description, inputSchema }, (outputSchema === undefined ? {} : { outputSchema })), { execution, needsApproval: needsApprovalConfigured }), (effect === undefined ? {} : { effect })), (execution === "agent" && tool.script !== undefined
766
- ? { script: tool.script }
767
- : {})), { definition: tool }));
768
706
  }
769
- return tools;
707
+ return entries;
770
708
  });
771
709
  }
710
+ /**
711
+ * Validate one tool definition against the tool contract and convert its
712
+ * schemas. Diagnostics point at `entryPath` (the authored file, or the
713
+ * extension mount that contributed the tool).
714
+ */
715
+ function compileTool(ctx, entryPath, name, tool) {
716
+ if (isBlank(tool.description)) {
717
+ ctx.diagnostics.push({
718
+ severity: "error",
719
+ path: displayPath(ctx, entryPath),
720
+ message: "Tools require a non-empty description.",
721
+ });
722
+ return undefined;
723
+ }
724
+ const execution = tool.execution === "agent" ? "agent" : "server";
725
+ const needsApprovalConfigured = tool.needsApproval === true || typeof tool.needsApproval === "function";
726
+ const effect = declaredEffect(tool);
727
+ if (execution === "agent") {
728
+ if (isBlank(tool.script)) {
729
+ ctx.diagnostics.push({
730
+ severity: "error",
731
+ path: displayPath(ctx, entryPath),
732
+ message: 'Tools with execution: "agent" require a non-empty `script` (shell body; JSON on stdin, result on stdout).',
733
+ });
734
+ return undefined;
735
+ }
736
+ if (typeof tool.execute === "function") {
737
+ ctx.diagnostics.push({
738
+ severity: "warning",
739
+ path: displayPath(ctx, entryPath),
740
+ message: '`execute` is ignored when execution is "agent"; the Cursor agent runs `script` instead.',
741
+ });
742
+ }
743
+ if (needsApprovalConfigured) {
744
+ ctx.diagnostics.push({
745
+ severity: "error",
746
+ path: displayPath(ctx, entryPath),
747
+ message: '`needsApproval` is only supported for execution: "server" tools (in-process).',
748
+ });
749
+ return undefined;
750
+ }
751
+ }
752
+ else if (typeof tool.execute !== "function") {
753
+ ctx.diagnostics.push({
754
+ severity: "error",
755
+ path: displayPath(ctx, entryPath),
756
+ message: 'Tools require an execute(input, ctx) function (or set execution: "agent" with a script).',
757
+ });
758
+ return undefined;
759
+ }
760
+ let inputSchema;
761
+ try {
762
+ inputSchema = toolInputJsonSchema(tool.inputSchema);
763
+ }
764
+ catch (error) {
765
+ ctx.diagnostics.push({
766
+ severity: "error",
767
+ path: displayPath(ctx, entryPath),
768
+ message: `Failed to convert inputSchema to JSON Schema: ${errorMessage(error)}`,
769
+ });
770
+ return undefined;
771
+ }
772
+ let outputSchema;
773
+ try {
774
+ outputSchema = toolOutputJsonSchema(tool.outputSchema);
775
+ }
776
+ catch (error) {
777
+ ctx.diagnostics.push({
778
+ severity: "error",
779
+ path: displayPath(ctx, entryPath),
780
+ message: `Failed to convert outputSchema to JSON Schema: ${errorMessage(error)}`,
781
+ });
782
+ return undefined;
783
+ }
784
+ return {
785
+ name,
786
+ description: tool.description,
787
+ inputSchema,
788
+ outputSchema,
789
+ execution,
790
+ needsApproval: needsApprovalConfigured,
791
+ effect,
792
+ script: execution === "agent" ? tool.script : undefined,
793
+ definition: tool,
794
+ };
795
+ }
772
796
  /**
773
797
  * Static view of a tool's `effect` for the manifest: the literal when it is
774
798
  * one, `"dynamic"` for a per-call predicate, `undefined` when undeclared. A
@@ -788,7 +812,7 @@ function declaredEffect(tool) {
788
812
  // ============================================================================
789
813
  function loadSkills(ctx, skillsDir) {
790
814
  return __awaiter(this, void 0, void 0, function* () {
791
- var _a, _b, _c, _d, _e;
815
+ var _a, _b;
792
816
  if (!(yield isDirectory(skillsDir))) {
793
817
  return [];
794
818
  }
@@ -807,7 +831,7 @@ function loadSkills(ctx, skillsDir) {
807
831
  }
808
832
  if (entry.name.endsWith(".md")) {
809
833
  const name = entry.name.slice(0, -".md".length);
810
- if (!validateSkillName(ctx, name, entryPath)) {
834
+ if (!validateName(ctx, "skill", name, entryPath)) {
811
835
  continue;
812
836
  }
813
837
  const { data, body } = parseFrontmatter(yield readFile(entryPath, "utf8"));
@@ -821,27 +845,217 @@ function loadSkills(ctx, skillsDir) {
821
845
  }
822
846
  if (isModuleFile(entry.name)) {
823
847
  const name = moduleStem(entry.name);
824
- if (!validateSkillName(ctx, name, entryPath)) {
848
+ if (!validateName(ctx, "skill", name, entryPath)) {
825
849
  continue;
826
850
  }
827
851
  const definition = yield importDefault(ctx, entryPath, "skill");
828
852
  if (definition === undefined) {
829
853
  continue;
830
854
  }
831
- const skill = definition;
832
- const files = {};
833
- for (const [rel, contents] of Object.entries((_c = skill.files) !== null && _c !== void 0 ? _c : {})) {
834
- files[rel] = { contents };
855
+ skills.push(compileSkill(name, definition));
856
+ }
857
+ }
858
+ return skills;
859
+ });
860
+ }
861
+ /** A skill whose body and sibling files are in memory (`defineSkill`, extensions). */
862
+ function compileSkill(name, skill) {
863
+ var _a, _b, _c;
864
+ const files = {};
865
+ for (const [rel, contents] of Object.entries((_a = skill.files) !== null && _a !== void 0 ? _a : {})) {
866
+ files[rel] = { contents };
867
+ }
868
+ return {
869
+ name,
870
+ description: (_c = (_b = skill.description) !== null && _b !== void 0 ? _b : deriveSkillDescription(skill.markdown)) !== null && _c !== void 0 ? _c : SKILL_DESCRIPTION_FALLBACK(name),
871
+ markdown: skill.markdown.trim(),
872
+ files,
873
+ };
874
+ }
875
+ // ============================================================================
876
+ // Extensions (agent/extensions/<ns>.ts | agent/extensions/<ns>/extension.ts)
877
+ // ============================================================================
878
+ /**
879
+ * Mount every extension under `agent/extensions/` and append its tools and
880
+ * skills to the authored lists as `<ns>__<name>`, stamped with `extension`.
881
+ * The namespace is the mount's filename stem or directory name.
882
+ */
883
+ function appendExtensions(ctx, extensionsDir, tools, skills) {
884
+ return __awaiter(this, void 0, void 0, function* () {
885
+ if (!(yield isDirectory(extensionsDir))) {
886
+ return [];
887
+ }
888
+ const extensions = [];
889
+ for (const entry of yield sortedEntries(extensionsDir)) {
890
+ const path = join(extensionsDir, entry.name);
891
+ const site = yield resolveMountSite(ctx, path, entry);
892
+ if (site === undefined) {
893
+ continue;
894
+ }
895
+ if (extensions.some((extension) => extension.name === site.ns)) {
896
+ ctx.diagnostics.push({
897
+ severity: "error",
898
+ path: displayPath(ctx, path),
899
+ message: `Extension "${site.ns}" is mounted twice (as a file and as a directory).`,
900
+ });
901
+ continue;
902
+ }
903
+ const mount = yield importDefault(ctx, site.mountPath, "extension");
904
+ if (mount === undefined) {
905
+ continue;
906
+ }
907
+ extensions.push(yield mountExtension(ctx, site, mount, tools, skills));
908
+ }
909
+ return extensions;
910
+ });
911
+ }
912
+ function resolveMountSite(ctx, path, entry) {
913
+ return __awaiter(this, void 0, void 0, function* () {
914
+ if (entry.isDirectory()) {
915
+ if (!validateName(ctx, "extension", entry.name, path)) {
916
+ return undefined;
917
+ }
918
+ const mountPath = yield findModuleFile(path, "extension");
919
+ if (mountPath === undefined) {
920
+ ctx.diagnostics.push({
921
+ severity: "error",
922
+ path: displayPath(ctx, path),
923
+ message: "A directory mount needs an extension.ts default-exporting the mount (`export default crm({ ... })`).",
924
+ });
925
+ return undefined;
926
+ }
927
+ return { ns: entry.name, mountPath, overlayDir: path };
928
+ }
929
+ if (!entry.isFile() || !isModuleFile(entry.name)) {
930
+ return undefined;
931
+ }
932
+ const ns = moduleStem(entry.name);
933
+ return validateName(ctx, "extension", ns, path)
934
+ ? { ns, mountPath: path }
935
+ : undefined;
936
+ });
937
+ }
938
+ /**
939
+ * Read the extension's tree with the agent loaders, lay the mount's overlay
940
+ * on top (a same-named file replaces, `disableTool()` removes), then
941
+ * namespace what is left.
942
+ */
943
+ function mountExtension(ctx, site, mount, tools, skills) {
944
+ return __awaiter(this, void 0, void 0, function* () {
945
+ const mounted = {
946
+ name: site.ns,
947
+ description: mount.extension.description,
948
+ tools: [],
949
+ skills: [],
950
+ };
951
+ const root = mount.extension.root;
952
+ if (!(yield isDirectory(root))) {
953
+ ctx.diagnostics.push({
954
+ severity: "error",
955
+ path: displayPath(ctx, site.mountPath),
956
+ message: `Extension "${site.ns}" declares root ${root}, which is not a directory. Pass \`import.meta.dirname\` from extension.ts.`,
957
+ });
958
+ return mounted;
959
+ }
960
+ yield warnUnsupportedExtensionSlots(ctx, root);
961
+ const contributedTools = new Map((yield loadTools(ctx, join(root, "tools"))).map((tool) => [tool.name, tool]));
962
+ const contributedSkills = new Map((yield loadSkills(ctx, join(root, "skills"))).map((skill) => [
963
+ skill.name,
964
+ skill,
965
+ ]));
966
+ if (site.overlayDir !== undefined) {
967
+ const overlay = yield loadOverlayTools(ctx, join(site.overlayDir, "tools"));
968
+ for (const tool of overlay.tools) {
969
+ contributedTools.set(tool.name, tool);
970
+ }
971
+ for (const disabled of overlay.disabled) {
972
+ if (!contributedTools.delete(disabled.name)) {
973
+ ctx.diagnostics.push({
974
+ severity: "error",
975
+ path: displayPath(ctx, disabled.path),
976
+ message: `disableTool() targets "${disabled.name}", which extension "${site.ns}" does not contribute.`,
977
+ });
835
978
  }
836
- skills.push({
837
- name,
838
- description: (_e = (_d = skill.description) !== null && _d !== void 0 ? _d : deriveSkillDescription(skill.markdown)) !== null && _e !== void 0 ? _e : SKILL_DESCRIPTION_FALLBACK(name),
839
- markdown: skill.markdown.trim(),
840
- files,
979
+ }
980
+ for (const skill of yield loadSkills(ctx, join(site.overlayDir, "skills"))) {
981
+ contributedSkills.set(skill.name, skill);
982
+ }
983
+ }
984
+ for (const [name, tool] of contributedTools) {
985
+ const composed = `${site.ns}__${name}`;
986
+ tools.push(Object.assign(Object.assign({}, tool), { name: composed, extension: site.ns }));
987
+ mounted.tools.push(composed);
988
+ }
989
+ for (const [name, skill] of contributedSkills) {
990
+ const composed = `${site.ns}__${name}`;
991
+ skills.push(Object.assign(Object.assign({}, skill), { name: composed, extension: site.ns }));
992
+ mounted.skills.push(composed);
993
+ }
994
+ return mounted;
995
+ });
996
+ }
997
+ /** A directory mount's `tools/`: replacements plus `disableTool()` markers. */
998
+ function loadOverlayTools(ctx, toolsDir) {
999
+ return __awaiter(this, void 0, void 0, function* () {
1000
+ const tools = [];
1001
+ const disabled = [];
1002
+ for (const { name, path } of yield toolModuleEntries(ctx, toolsDir)) {
1003
+ let mod;
1004
+ try {
1005
+ mod = yield ctx.importModule(path);
1006
+ }
1007
+ catch (error) {
1008
+ ctx.diagnostics.push({
1009
+ severity: "error",
1010
+ path: displayPath(ctx, path),
1011
+ message: `Failed to load module: ${errorMessage(error)}`,
1012
+ });
1013
+ continue;
1014
+ }
1015
+ const kind = getDefinitionKind(mod.default);
1016
+ if (kind === "disabled-tool") {
1017
+ disabled.push({ name, path });
1018
+ continue;
1019
+ }
1020
+ if (kind !== "tool") {
1021
+ ctx.diagnostics.push({
1022
+ severity: "error",
1023
+ path: displayPath(ctx, path),
1024
+ message: "An override must default-export defineTool({ ... }) or disableTool().",
1025
+ });
1026
+ continue;
1027
+ }
1028
+ const tool = compileTool(ctx, path, name, mod.default);
1029
+ if (tool !== undefined) {
1030
+ tools.push(tool);
1031
+ }
1032
+ }
1033
+ return { tools, disabled };
1034
+ });
1035
+ }
1036
+ /** Slots an agent has that an extension tree may not contribute (yet). */
1037
+ function warnUnsupportedExtensionSlots(ctx, root) {
1038
+ return __awaiter(this, void 0, void 0, function* () {
1039
+ const unsupported = [
1040
+ ["instructions.md", "instructions"],
1041
+ ["connections", "connections"],
1042
+ ["mcp-connections", "MCP connections"],
1043
+ ["hooks", "hooks"],
1044
+ ["subagents", "subagents"],
1045
+ ["channels", "channels"],
1046
+ ["schedules", "schedules"],
1047
+ ["extensions", "nested extensions"],
1048
+ ];
1049
+ for (const [slot, label] of unsupported) {
1050
+ const path = join(root, slot);
1051
+ if ((yield isDirectory(path)) || (yield isFile(path))) {
1052
+ ctx.diagnostics.push({
1053
+ severity: "warning",
1054
+ path: displayPath(ctx, path),
1055
+ message: `Extension ${label} are not supported yet; only tools/ and skills/ are mounted. Ignoring.`,
841
1056
  });
842
1057
  }
843
1058
  }
844
- return skills;
845
1059
  });
846
1060
  }
847
1061
  function loadPackagedSkill(ctx, skillDir, name) {
@@ -855,7 +1069,7 @@ function loadPackagedSkill(ctx, skillDir, name) {
855
1069
  });
856
1070
  return undefined;
857
1071
  }
858
- if (!validateSkillName(ctx, name, skillDir)) {
1072
+ if (!validateName(ctx, "skill", name, skillDir)) {
859
1073
  return undefined;
860
1074
  }
861
1075
  const { data, body } = parseFrontmatter(yield readFile(skillMdPath, "utf8"));
@@ -923,6 +1137,22 @@ function parseConnectionEffects(effects) {
923
1137
  }
924
1138
  return { ok: true, value: normalizeConnectionEffects(parsed) };
925
1139
  }
1140
+ function parseConnectionTools(tools) {
1141
+ if (tools === undefined) {
1142
+ return { ok: true, value: undefined };
1143
+ }
1144
+ if (!Array.isArray(tools) || tools.length === 0) {
1145
+ return { ok: false };
1146
+ }
1147
+ if (tools.some((name) => typeof name !== "string")) {
1148
+ return { ok: false };
1149
+ }
1150
+ const normalized = normalizeConnectionTools(tools);
1151
+ if (normalized.length === 0) {
1152
+ return { ok: false };
1153
+ }
1154
+ return { ok: true, value: normalized };
1155
+ }
926
1156
  function connectionHasSpawnOrRemote(connection) {
927
1157
  if ("cursorAccount" in connection && connection.cursorAccount === true) {
928
1158
  return true;
@@ -956,16 +1186,29 @@ function connectionTransport(connection) {
956
1186
  }
957
1187
  return undefined;
958
1188
  }
959
- function validateSkillName(ctx, name, entryPath) {
960
- if (NAME_PATTERN.test(name)) {
961
- return true;
1189
+ /**
1190
+ * Filenames become the names the model sees. `__` is reserved: it joins an
1191
+ * extension's namespace to its contribution (`crm__search`).
1192
+ */
1193
+ function validateName(ctx, kind, name, entryPath) {
1194
+ const label = { skill: "Skill", tool: "Tool", extension: "Extension" }[kind];
1195
+ if (!NAME_PATTERN.test(name)) {
1196
+ ctx.diagnostics.push({
1197
+ severity: "error",
1198
+ path: displayPath(ctx, entryPath),
1199
+ message: `${label} name "${name}" must match ${NAME_PATTERN}.`,
1200
+ });
1201
+ return false;
962
1202
  }
963
- ctx.diagnostics.push({
964
- severity: "error",
965
- path: displayPath(ctx, entryPath),
966
- message: `Skill name "${name}" must match ${NAME_PATTERN}.`,
967
- });
968
- return false;
1203
+ if (name.includes("__")) {
1204
+ ctx.diagnostics.push({
1205
+ severity: "error",
1206
+ path: displayPath(ctx, entryPath),
1207
+ message: `${label} name "${name}" may not contain "__"; it is reserved for extension contributions (\`<ns>__<name>\`).`,
1208
+ });
1209
+ return false;
1210
+ }
1211
+ return true;
969
1212
  }
970
1213
  /**
971
1214
  * Advertise the first non-empty, non-code-fence line of the body, with any
@@ -1024,7 +1267,7 @@ function resolveMcpConnectionsDir(ctx, agentDir) {
1024
1267
  function loadHostConnections(ctx, agentDir, modelConnections) {
1025
1268
  return __awaiter(this, void 0, void 0, function* () {
1026
1269
  const hostDir = join(agentDir, "host-connections");
1027
- const loaded = yield loadConnections(ctx, hostDir);
1270
+ const loaded = yield loadConnections(ctx, hostDir, "host");
1028
1271
  const modelNames = new Set(modelConnections.map((connection) => connection.name));
1029
1272
  const hostConnections = [];
1030
1273
  for (const connection of loaded) {
@@ -1057,8 +1300,8 @@ function loadHostConnections(ctx, agentDir, modelConnections) {
1057
1300
  return hostConnections;
1058
1301
  });
1059
1302
  }
1060
- function loadConnections(ctx, connectionsDir) {
1061
- return __awaiter(this, void 0, void 0, function* () {
1303
+ function loadConnections(ctx_1, connectionsDir_1) {
1304
+ return __awaiter(this, arguments, void 0, function* (ctx, connectionsDir, role = "model") {
1062
1305
  if (!(yield isDirectory(connectionsDir))) {
1063
1306
  return [];
1064
1307
  }
@@ -1143,6 +1386,48 @@ function loadConnections(ctx, connectionsDir) {
1143
1386
  });
1144
1387
  continue;
1145
1388
  }
1389
+ const parsedTools = isInlineStdioConnection(connection)
1390
+ ? { ok: true, value: undefined }
1391
+ : parseConnectionTools(connection.tools);
1392
+ if (!parsedTools.ok) {
1393
+ ctx.diagnostics.push({
1394
+ severity: "error",
1395
+ path: displayPath(ctx, entryPath),
1396
+ message: "MCP connection `tools` allowlist must be a non-empty array of tool names.",
1397
+ });
1398
+ continue;
1399
+ }
1400
+ if (isInlineStdioConnection(connection) &&
1401
+ connection.disallowedTools !== undefined) {
1402
+ ctx.diagnostics.push({
1403
+ severity: "error",
1404
+ path: displayPath(ctx, entryPath),
1405
+ message: "MCP connection `disallowedTools` is not supported on inline `tools` connections — author only the tools you want.",
1406
+ });
1407
+ continue;
1408
+ }
1409
+ const parsedDisallowed = isInlineStdioConnection(connection)
1410
+ ? { ok: true, value: undefined }
1411
+ : parseConnectionTools(connection.disallowedTools);
1412
+ if (!parsedDisallowed.ok) {
1413
+ ctx.diagnostics.push({
1414
+ severity: "error",
1415
+ path: displayPath(ctx, entryPath),
1416
+ message: "MCP connection `disallowedTools` must be a non-empty array of tool names.",
1417
+ });
1418
+ continue;
1419
+ }
1420
+ if ((parsedTools.value !== undefined ||
1421
+ parsedDisallowed.value !== undefined) &&
1422
+ role === "model" &&
1423
+ connection.advertiseTools !== true) {
1424
+ ctx.diagnostics.push({
1425
+ severity: "error",
1426
+ path: displayPath(ctx, entryPath),
1427
+ message: "MCP connection `tools` / `disallowedTools` filter advertised tools; set `advertiseTools: true` or drop the name list. Put the connection in `agent/host-connections/` to restrict `host.mcp` only.",
1428
+ });
1429
+ continue;
1430
+ }
1146
1431
  if (connection.advertiseTools === true &&
1147
1432
  isInlineStdioConnection(connection)) {
1148
1433
  ctx.diagnostics.push({
@@ -1225,6 +1510,8 @@ function loadConnections(ctx, connectionsDir) {
1225
1510
  auth: connection.auth,
1226
1511
  advertiseTools: connection.advertiseTools,
1227
1512
  effects: parsedEffects.value,
1513
+ tools: parsedTools.value,
1514
+ disallowedTools: parsedDisallowed.value,
1228
1515
  });
1229
1516
  }
1230
1517
  return connections;
@@ -1324,6 +1611,7 @@ function warnUnsupportedSubagentSlots(ctx, subagentDir) {
1324
1611
  const unsupported = [
1325
1612
  ["tools", "tools"],
1326
1613
  ["skills", "skills"],
1614
+ ["extensions", "extensions"],
1327
1615
  ["mcp-connections", "MCP connections"],
1328
1616
  ["host-connections", "host MCP connections"],
1329
1617
  ["connections", "MCP connections"],
@@ -1354,13 +1642,16 @@ function appendBuiltinTools(ctx, agentDir, tools, config) {
1354
1642
  return;
1355
1643
  }
1356
1644
  const agentPath = displayPath(ctx, join(agentDir, "agent.ts"));
1357
- const authored = new Set(tools.map((tool) => tool.name));
1358
1645
  for (const tool of builtin) {
1359
- if (authored.has(tool.name)) {
1646
+ const existing = tools.find((t) => t.name === tool.name);
1647
+ if (existing !== undefined) {
1648
+ const owner = existing.extension === undefined
1649
+ ? "Authored"
1650
+ : `Extension "${existing.extension}"`;
1360
1651
  ctx.diagnostics.push({
1361
1652
  severity: "warning",
1362
1653
  path: agentPath,
1363
- message: `Authored tool "${tool.name}" shadows the built-in tool of the same name; the authored tool wins.`,
1654
+ message: `${owner} tool "${tool.name}" shadows the built-in tool of the same name; the built-in is skipped.`,
1364
1655
  });
1365
1656
  continue;
1366
1657
  }
@@ -1875,7 +2166,7 @@ function loadSeedFiles(ctx, agentDir) {
1875
2166
  // ============================================================================
1876
2167
  export function projectInfo(project) {
1877
2168
  var _a, _b, _c, _d;
1878
- var _e;
2169
+ var _e, _f;
1879
2170
  const agent = project.agent;
1880
2171
  const httpRoutes = [
1881
2172
  { method: "POST", path: "/v1/session", url: "/v1/session" },
@@ -1922,11 +2213,13 @@ export function projectInfo(project) {
1922
2213
  })), skills: agent.skills.map((skill) => ({
1923
2214
  name: skill.name,
1924
2215
  description: skill.description,
1925
- })), connections: agent.connections.map((connection) => { var _a; return ({
2216
+ })), extensions: (_e = agent.extensions) !== null && _e !== void 0 ? _e : [], connections: agent.connections.map((connection) => { var _a; return ({
1926
2217
  name: connection.name,
1927
2218
  transport: connectionTransportLabel(connection.transport),
1928
2219
  advertiseTools: connection.advertiseTools,
1929
2220
  effects: connection.effects,
2221
+ tools: connection.tools,
2222
+ disallowedTools: connection.disallowedTools,
1930
2223
  cursorAccountServers: "cursorAccount" in connection.transport
1931
2224
  ? ((_a = connection.transport.servers) !== null && _a !== void 0 ? _a : "*")
1932
2225
  : undefined,
@@ -1993,7 +2286,7 @@ export function projectInfo(project) {
1993
2286
  : { name: project.storage.name }, artifacts: project.artifacts === undefined
1994
2287
  ? undefined
1995
2288
  : {
1996
- kinds: Object.keys((_e = project.artifacts.kinds) !== null && _e !== void 0 ? _e : {}),
2289
+ kinds: Object.keys((_f = project.artifacts.kinds) !== null && _f !== void 0 ? _f : {}),
1997
2290
  agentTool: project.artifacts.agentTool === true,
1998
2291
  max: resolveArtifactsMax(project.artifacts),
1999
2292
  }, otel: project.otel === undefined
@@ -2040,6 +2333,7 @@ const DEFINE_HELPER_NAME = {
2040
2333
  instructions: "defineInstructions",
2041
2334
  tool: "defineTool",
2042
2335
  skill: "defineSkill",
2336
+ extension: "defineExtension",
2043
2337
  connection: "defineConnection",
2044
2338
  channel: "defineChannel",
2045
2339
  "http-channel": "httpChannel",
@@ -2057,6 +2351,7 @@ function warnUnknownSlots(ctx, agentDir) {
2057
2351
  "instructions",
2058
2352
  "tools",
2059
2353
  "skills",
2354
+ "extensions",
2060
2355
  "mcp-connections",
2061
2356
  "host-connections",
2062
2357
  // Legacy slot name; resolveMcpConnectionsDir warns and still loads it.