@cursor/july 0.1.62 → 0.1.73

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 (286) hide show
  1. package/AGENTS.md +4 -5
  2. package/README.md +23 -11
  3. package/dist/bin/agent-serve.js +11 -2
  4. package/dist/channels/github/api.d.ts +2 -0
  5. package/dist/channels/github/api.d.ts.map +1 -1
  6. package/dist/channels/github/api.js +2 -1
  7. package/dist/channels/github/binding.d.ts +7 -0
  8. package/dist/channels/github/binding.d.ts.map +1 -1
  9. package/dist/channels/github/binding.js +4 -0
  10. package/dist/channels/github/checks.d.ts +99 -0
  11. package/dist/channels/github/checks.d.ts.map +1 -0
  12. package/dist/channels/github/checks.js +108 -0
  13. package/dist/channels/github/cursor-account.d.ts +4 -4
  14. package/dist/channels/github/cursor-account.d.ts.map +1 -1
  15. package/dist/channels/github/cursor-account.js +7 -5
  16. package/dist/channels/github/index.d.ts +1 -0
  17. package/dist/channels/github/index.d.ts.map +1 -1
  18. package/dist/channels/github/index.js +1 -0
  19. package/dist/channels/github/types.d.ts +8 -0
  20. package/dist/channels/github/types.d.ts.map +1 -1
  21. package/dist/channels/slack/channel-watch.d.ts +2 -1
  22. package/dist/channels/slack/channel-watch.d.ts.map +1 -1
  23. package/dist/channels/slack/channel-watch.js +7 -3
  24. package/dist/channels/slack/dispatch.d.ts +9 -0
  25. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  26. package/dist/channels/slack/dispatch.js +41 -21
  27. package/dist/channels/slack/manifest.d.ts +2 -2
  28. package/dist/channels/slack/manifest.d.ts.map +1 -1
  29. package/dist/channels/slack/manifest.js +14 -11
  30. package/dist/channels/slack/nudge-store.d.ts +16 -0
  31. package/dist/channels/slack/nudge-store.d.ts.map +1 -1
  32. package/dist/channels/slack/nudge-store.js +53 -0
  33. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  34. package/dist/channels/slack/slack-channel.js +4 -1
  35. package/dist/channels/slack/types.d.ts +24 -7
  36. package/dist/channels/slack/types.d.ts.map +1 -1
  37. package/dist/connections.d.ts +17 -5
  38. package/dist/connections.d.ts.map +1 -1
  39. package/dist/connections.js +17 -5
  40. package/dist/docs/404.html +2 -2
  41. package/dist/docs/ab.html +3 -3
  42. package/dist/docs/assets/{app.B-biogkN.js → app.CdbcFD8T.js} +1 -1
  43. package/dist/docs/assets/chunks/@localSearchIndexroot.DQad--_z.js +1 -0
  44. package/dist/docs/assets/chunks/{VPLocalSearchBox.DZqKtFZS.js → VPLocalSearchBox.D_NKImM7.js} +1 -1
  45. package/dist/docs/assets/chunks/{theme.BwC5zP2r.js → theme.CMvz7cu9.js} +2 -2
  46. package/dist/docs/assets/{concepts.md.CqOsxbMU.js → concepts.md.BXAm6G-C.js} +1 -1
  47. package/dist/docs/assets/{guides_mcp-oauth.md.C7G7IykG.js → guides_mcp-oauth.md.CzEB6RaG.js} +1 -1
  48. package/dist/docs/assets/{reference_agent-config.md.DHkkvcEZ.js → reference_agent-config.md.BZnEKfEc.js} +3 -4
  49. package/dist/docs/assets/{reference_agent-config.md.DHkkvcEZ.lean.js → reference_agent-config.md.BZnEKfEc.lean.js} +1 -1
  50. package/dist/docs/assets/{reference_connections.md.CSQiNzre.js → reference_connections.md.Cu3N-S3Q.js} +26 -9
  51. package/dist/docs/assets/reference_connections.md.Cu3N-S3Q.lean.js +1 -0
  52. package/dist/docs/assets/{reference_sessions.md.DBVFi2Sx.js → reference_sessions.md.B0DdlM-K.js} +1 -1
  53. package/dist/docs/assets/{reference_tools.md.kJfJAP2m.js → reference_tools.md.DTg_kEsx.js} +2 -2
  54. package/dist/docs/assets/{reference_tools.md.kJfJAP2m.lean.js → reference_tools.md.DTg_kEsx.lean.js} +1 -1
  55. package/dist/docs/assets/troubleshooting.md.DQ-hYuZT.js +1 -0
  56. package/dist/docs/building-with-agents.html +3 -3
  57. package/dist/docs/concepts.html +5 -5
  58. package/dist/docs/deployment.html +3 -3
  59. package/dist/docs/evals.html +3 -3
  60. package/dist/docs/example-agents/approval-buddy.html +3 -3
  61. package/dist/docs/example-agents/benny.html +3 -3
  62. package/dist/docs/example-agents/bugbot.html +3 -3
  63. package/dist/docs/example-agents/codebase-wiki.html +3 -3
  64. package/dist/docs/example-agents/codeowners-review.html +3 -3
  65. package/dist/docs/example-agents/concierge.html +3 -3
  66. package/dist/docs/example-agents/fsd.html +3 -3
  67. package/dist/docs/example-agents/index.html +3 -3
  68. package/dist/docs/example-agents/knowledge-base.html +3 -3
  69. package/dist/docs/example-agents/oncall.html +3 -3
  70. package/dist/docs/example-agents/security-reviewer.html +3 -3
  71. package/dist/docs/example-agents/slack-agent.html +3 -3
  72. package/dist/docs/example-agents/weather-agent.html +3 -3
  73. package/dist/docs/guides/agent-to-agent.html +3 -3
  74. package/dist/docs/guides/cloud-runtime.html +3 -3
  75. package/dist/docs/guides/convert-automation.html +3 -3
  76. package/dist/docs/guides/github.html +3 -3
  77. package/dist/docs/guides/human-in-the-loop.html +3 -3
  78. package/dist/docs/guides/mcp-oauth.html +5 -5
  79. package/dist/docs/guides/opentelemetry.html +3 -3
  80. package/dist/docs/guides/slack.html +3 -3
  81. package/dist/docs/guides/webhooks.html +3 -3
  82. package/dist/docs/hashmap.json +1 -1
  83. package/dist/docs/hillclimbing.html +3 -3
  84. package/dist/docs/index.html +3 -3
  85. package/dist/docs/quickstart.html +3 -3
  86. package/dist/docs/reference/agent-config.html +5 -6
  87. package/dist/docs/reference/artifacts.html +3 -3
  88. package/dist/docs/reference/channels.html +3 -3
  89. package/dist/docs/reference/cli.html +3 -3
  90. package/dist/docs/reference/connections.html +28 -11
  91. package/dist/docs/reference/hooks.html +3 -3
  92. package/dist/docs/reference/http-api.html +3 -3
  93. package/dist/docs/reference/instructions.html +3 -3
  94. package/dist/docs/reference/playground.html +3 -3
  95. package/dist/docs/reference/project-layout.html +3 -3
  96. package/dist/docs/reference/prompt.html +3 -3
  97. package/dist/docs/reference/schedules.html +3 -3
  98. package/dist/docs/reference/sessions.html +5 -5
  99. package/dist/docs/reference/skills.html +3 -3
  100. package/dist/docs/reference/subagents.html +3 -3
  101. package/dist/docs/reference/tools.html +5 -5
  102. package/dist/docs/scaffolding-agents.html +3 -3
  103. package/dist/docs/storage.html +3 -3
  104. package/dist/docs/templates/agentic-owners.html +3 -3
  105. package/dist/docs/templates/demo.html +3 -3
  106. package/dist/docs/templates/pr-autofixer.html +3 -3
  107. package/dist/docs/templates/security-reviewer.html +3 -3
  108. package/dist/docs/templates/triage.html +3 -3
  109. package/dist/docs/troubleshooting.html +5 -5
  110. package/dist/files-backends/agent-store-presigned-url.js +1 -1
  111. package/dist/index.d.ts +2 -2
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +1 -1
  114. package/dist/internal/advertise-tools.d.ts +79 -0
  115. package/dist/internal/advertise-tools.d.ts.map +1 -0
  116. package/dist/internal/advertise-tools.js +185 -0
  117. package/dist/internal/cli-deploy.d.ts.map +1 -1
  118. package/dist/internal/cli-deploy.js +7 -1
  119. package/dist/internal/cli-manifest.d.ts +19 -0
  120. package/dist/internal/cli-manifest.d.ts.map +1 -0
  121. package/dist/internal/cli-manifest.js +49 -0
  122. package/dist/internal/cli-slack.d.ts.map +1 -1
  123. package/dist/internal/cli-slack.js +9 -1
  124. package/dist/internal/convert-automation/convert-workflow.d.ts.map +1 -1
  125. package/dist/internal/convert-automation/convert-workflow.js +2 -10
  126. package/dist/internal/cursor/account-mcp.d.ts +29 -3
  127. package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
  128. package/dist/internal/cursor/account-mcp.js +147 -67
  129. package/dist/internal/cursor/backend-client.d.ts +11 -6
  130. package/dist/internal/cursor/backend-client.d.ts.map +1 -1
  131. package/dist/internal/cursor/backend-client.js +32 -10
  132. package/dist/internal/cursor-account-mcp-auth.d.ts +11 -0
  133. package/dist/internal/cursor-account-mcp-auth.d.ts.map +1 -1
  134. package/dist/internal/cursor-account-mcp-auth.js +69 -0
  135. package/dist/internal/cursor-agent-template.d.ts +9 -0
  136. package/dist/internal/cursor-agent-template.d.ts.map +1 -0
  137. package/dist/internal/cursor-agent-template.js +37 -0
  138. package/dist/internal/deploy-client.d.ts +1 -0
  139. package/dist/internal/deploy-client.d.ts.map +1 -1
  140. package/dist/internal/deploy-client.js +18 -2
  141. package/dist/internal/deploy-manifest.d.ts +76 -0
  142. package/dist/internal/deploy-manifest.d.ts.map +1 -0
  143. package/dist/internal/deploy-manifest.js +117 -0
  144. package/dist/internal/deployment-scm-event-stream.d.ts +116 -0
  145. package/dist/internal/deployment-scm-event-stream.d.ts.map +1 -0
  146. package/dist/internal/deployment-scm-event-stream.js +474 -0
  147. package/dist/internal/discovery.d.ts.map +1 -1
  148. package/dist/internal/discovery.js +111 -10
  149. package/dist/internal/init-project.d.ts.map +1 -1
  150. package/dist/internal/init-project.js +12 -123
  151. package/dist/internal/init-scaffold.d.ts +8 -0
  152. package/dist/internal/init-scaffold.d.ts.map +1 -0
  153. package/dist/internal/init-scaffold.js +168 -0
  154. package/dist/internal/inline-stdio-mcp.d.ts +2 -0
  155. package/dist/internal/inline-stdio-mcp.d.ts.map +1 -1
  156. package/dist/internal/inline-stdio-mcp.js +10 -8
  157. package/dist/internal/json-schema.d.ts +7 -0
  158. package/dist/internal/json-schema.d.ts.map +1 -1
  159. package/dist/internal/json-schema.js +18 -3
  160. package/dist/internal/mcp-endpoint.js +7 -7
  161. package/dist/internal/mcp-host.d.ts +18 -0
  162. package/dist/internal/mcp-host.d.ts.map +1 -1
  163. package/dist/internal/mcp-host.js +43 -5
  164. package/dist/internal/mcp-oauth.d.ts +22 -0
  165. package/dist/internal/mcp-oauth.d.ts.map +1 -1
  166. package/dist/internal/mcp-oauth.js +40 -1
  167. package/dist/internal/package-inline-stdio.d.ts.map +1 -1
  168. package/dist/internal/package-inline-stdio.js +5 -5
  169. package/dist/internal/review-comments.d.ts +97 -0
  170. package/dist/internal/review-comments.d.ts.map +1 -1
  171. package/dist/internal/review-comments.js +151 -0
  172. package/dist/internal/sanitize-mcp-tool-name.d.ts +20 -0
  173. package/dist/internal/sanitize-mcp-tool-name.d.ts.map +1 -0
  174. package/dist/internal/sanitize-mcp-tool-name.js +30 -0
  175. package/dist/internal/sdk-runner.d.ts +1 -1
  176. package/dist/internal/sdk-runner.d.ts.map +1 -1
  177. package/dist/internal/sdk-runner.js +36 -13
  178. package/dist/internal/server.d.ts.map +1 -1
  179. package/dist/internal/server.js +18 -0
  180. package/dist/internal/session-engine.d.ts +66 -0
  181. package/dist/internal/session-engine.d.ts.map +1 -1
  182. package/dist/internal/session-engine.js +428 -110
  183. package/dist/internal/shallow-clone.d.ts +170 -0
  184. package/dist/internal/shallow-clone.d.ts.map +1 -0
  185. package/dist/internal/shallow-clone.js +412 -0
  186. package/dist/internal/slack-provision-client.d.ts +2 -0
  187. package/dist/internal/slack-provision-client.d.ts.map +1 -1
  188. package/dist/internal/slack-provision-client.js +1 -0
  189. package/dist/internal/terminal-style.d.ts +18 -0
  190. package/dist/internal/terminal-style.d.ts.map +1 -1
  191. package/dist/internal/terminal-style.js +46 -1
  192. package/dist/internal/turn-lease-store.d.ts +44 -0
  193. package/dist/internal/turn-lease-store.d.ts.map +1 -0
  194. package/dist/internal/turn-lease-store.js +139 -0
  195. package/dist/internal/workspace.d.ts +14 -0
  196. package/dist/internal/workspace.d.ts.map +1 -1
  197. package/dist/internal/workspace.js +33 -0
  198. package/dist/playground/assets/index-77uhu5Kr.css +1 -0
  199. package/dist/playground/assets/index-D4buox4m.js +85 -0
  200. package/dist/playground/index.html +2 -2
  201. package/dist/storage-protocol.d.ts +122 -0
  202. package/dist/storage-protocol.d.ts.map +1 -0
  203. package/dist/storage-protocol.js +173 -0
  204. package/dist/storage.d.ts +2 -72
  205. package/dist/storage.d.ts.map +1 -1
  206. package/dist/storage.js +2 -82
  207. package/dist/tools.d.ts +7 -0
  208. package/dist/tools.d.ts.map +1 -1
  209. package/dist/types.d.ts +141 -6
  210. package/dist/types.d.ts.map +1 -1
  211. package/docs/concepts.md +4 -4
  212. package/docs/guides/mcp-oauth.md +3 -1
  213. package/docs/reference/agent-config.md +11 -12
  214. package/docs/reference/connections.md +108 -10
  215. package/docs/reference/sessions.md +2 -2
  216. package/docs/reference/tools.md +14 -0
  217. package/docs/troubleshooting.md +3 -2
  218. package/package.json +7 -2
  219. package/skills/create-agent/SKILL.md +12 -9
  220. package/skills/debug/SKILL.md +2 -1
  221. package/skills/framework-map/SKILL.md +6 -6
  222. package/skills/mcp-auth/SKILL.md +8 -6
  223. package/src/bin/agent-serve.ts +12 -2
  224. package/src/channels/github/api.ts +6 -1
  225. package/src/channels/github/binding.ts +21 -0
  226. package/src/channels/github/checks.ts +179 -0
  227. package/src/channels/github/cursor-account.ts +9 -6
  228. package/src/channels/github/index.ts +1 -0
  229. package/src/channels/github/types.ts +8 -0
  230. package/src/channels/slack/channel-watch.ts +6 -3
  231. package/src/channels/slack/dispatch.ts +40 -3
  232. package/src/channels/slack/manifest.ts +9 -10
  233. package/src/channels/slack/nudge-store.ts +56 -0
  234. package/src/channels/slack/slack-channel.ts +3 -0
  235. package/src/channels/slack/types.ts +24 -7
  236. package/src/connections.ts +17 -5
  237. package/src/index.ts +5 -0
  238. package/src/internal/advertise-tools.ts +278 -0
  239. package/src/internal/cli-deploy.ts +11 -1
  240. package/src/internal/cli-manifest.ts +63 -0
  241. package/src/internal/cli-slack.ts +10 -1
  242. package/src/internal/convert-automation/convert-workflow.ts +2 -11
  243. package/src/internal/cursor/account-mcp.ts +208 -73
  244. package/src/internal/cursor/backend-client.ts +45 -11
  245. package/src/internal/cursor-account-mcp-auth.ts +83 -0
  246. package/src/internal/cursor-agent-template.ts +46 -0
  247. package/src/internal/deploy-client.ts +25 -6
  248. package/src/internal/deploy-manifest.ts +161 -0
  249. package/src/internal/deployment-scm-event-stream.ts +593 -0
  250. package/src/internal/discovery.ts +132 -3
  251. package/src/internal/init-project.ts +18 -153
  252. package/src/internal/init-scaffold.ts +176 -0
  253. package/src/internal/inline-stdio-mcp.ts +13 -0
  254. package/src/internal/json-schema.ts +24 -3
  255. package/src/internal/mcp-endpoint.ts +6 -0
  256. package/src/internal/mcp-host.ts +70 -9
  257. package/src/internal/mcp-oauth.ts +55 -1
  258. package/src/internal/package-inline-stdio.ts +5 -1
  259. package/src/internal/review-comments.ts +245 -0
  260. package/src/internal/sanitize-mcp-tool-name.ts +33 -0
  261. package/src/internal/sdk-runner.ts +50 -11
  262. package/src/internal/server.ts +19 -0
  263. package/src/internal/session-engine.ts +392 -19
  264. package/src/internal/shallow-clone.ts +595 -0
  265. package/src/internal/slack-provision-client.ts +3 -0
  266. package/src/internal/terminal-style.ts +67 -1
  267. package/src/internal/turn-lease-store.ts +147 -0
  268. package/src/internal/workspace.ts +33 -0
  269. package/src/storage-protocol.ts +247 -0
  270. package/src/storage.ts +16 -110
  271. package/src/tools.ts +7 -0
  272. package/src/types.ts +149 -7
  273. package/templates/agentic-owners/agent/agent.ts +3 -0
  274. package/templates/demo/agent/agent.ts +3 -0
  275. package/templates/pr-autofixer/agent/lib/drive-schemas.ts +4 -1
  276. package/templates/security-reviewer/agent/agent.ts +3 -0
  277. package/templates/triage/agent/agent.ts +3 -0
  278. package/dist/docs/assets/chunks/@localSearchIndexroot.5ozYNf74.js +0 -1
  279. package/dist/docs/assets/reference_connections.md.CSQiNzre.lean.js +0 -1
  280. package/dist/docs/assets/troubleshooting.md.CuVztCKs.js +0 -1
  281. package/dist/playground/assets/index-B4rcOgeP.css +0 -1
  282. package/dist/playground/assets/index-DXcY42Jv.js +0 -85
  283. /package/dist/docs/assets/{concepts.md.CqOsxbMU.lean.js → concepts.md.BXAm6G-C.lean.js} +0 -0
  284. /package/dist/docs/assets/{guides_mcp-oauth.md.C7G7IykG.lean.js → guides_mcp-oauth.md.CzEB6RaG.lean.js} +0 -0
  285. /package/dist/docs/assets/{reference_sessions.md.DBVFi2Sx.lean.js → reference_sessions.md.B0DdlM-K.lean.js} +0 -0
  286. /package/dist/docs/assets/{troubleshooting.md.CuVztCKs.lean.js → troubleshooting.md.DQ-hYuZT.lean.js} +0 -0
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Advertised connection tools (`defineConnection({ advertiseTools: true })`).
3
+ *
4
+ * The session engine calls {@link resolveAdvertisedTools} while building
5
+ * every local turn: for each advertising connection it lists the server's
6
+ * tools and synthesizes a named 1:1 passthrough server tool per entry —
7
+ * the server's own names, descriptions, and live schemas — merged into the
8
+ * authored `agent/tools/` catalog. Because it runs at turn-build time it
9
+ * covers every way a turn starts (dispatcher sends, follow-ups, reminder
10
+ * fires that call the engine directly) and survives process restarts,
11
+ * since nothing is parked in memory between turns.
12
+ *
13
+ * Connections with per-session `auth` are listed and called through a
14
+ * one-off client carrying that session's headers (the registry's cached
15
+ * per-name client would leak one session's identity into another);
16
+ * auth-less connections go through the shared `host.mcp` registry, which
17
+ * also covers serve-resolved transports (Cursor account bridges, peers).
18
+ *
19
+ * Advertised names follow the Cursor-account MCP bridge
20
+ * (`packages/agent-serve/src/internal/cursor/account-mcp.ts`): slug
21
+ * `[^a-zA-Z0-9_-]` to `_`, collision suffixes `_2` / `_3`, and call the
22
+ * original advertised name. That is the same mapping `packages/agent`
23
+ * `normalizeMcpToolName` uses for IDE/Sand MCP tools. A listing failure
24
+ * still fails the turn rather than running it with a silently shrunken
25
+ * toolset.
26
+ */
27
+
28
+ import type {
29
+ DiscoveredConnection,
30
+ DiscoveredTool,
31
+ HostMcpCallResult,
32
+ HostMcpToolInfo,
33
+ JsonSchemaObject,
34
+ ResolvedAgent,
35
+ SessionInfo,
36
+ ToolDefinition,
37
+ } from "../types.js";
38
+ import { brandDefinition } from "./brand.js";
39
+ import type { HostMcpOneOff } from "./mcp-host.js";
40
+ import {
41
+ sanitizeMcpToolName,
42
+ suffixMcpToolName,
43
+ } from "./sanitize-mcp-tool-name.js";
44
+
45
+ /**
46
+ * What the resolver needs from the host MCP registry: the shared cached
47
+ * clients for auth-less connections, and one-off clients (per-session
48
+ * headers, never cached) for auth'd ones. `McpHost` implements this.
49
+ */
50
+ export interface AdvertiseHostMcp {
51
+ listTools(connectionName: string): Promise<HostMcpToolInfo[]>;
52
+ callTool(
53
+ connectionName: string,
54
+ toolName: string,
55
+ args?: Record<string, unknown>
56
+ ): Promise<HostMcpCallResult>;
57
+ oneOff(connection: DiscoveredConnection): HostMcpOneOff;
58
+ }
59
+
60
+ /**
61
+ * Model-facing advertised names after {@link sanitizeMcpToolName} — the
62
+ * same MCP-client shape the Cursor-account bridge documents
63
+ * (`^[a-zA-Z0-9_-]{1,128}$`). Authored `agent/tools/` filenames stay on
64
+ * discovery's stricter `NAME_PATTERN` (must start alphanumeric).
65
+ */
66
+ export const ADVERTISED_TOOL_NAME_PATTERN: RegExp = /^[A-Za-z0-9_-]{1,128}$/;
67
+
68
+ const ANY_OBJECT_SCHEMA: JsonSchemaObject = {
69
+ type: "object",
70
+ additionalProperties: true,
71
+ };
72
+
73
+ /** How one advertising connection is listed and called. */
74
+ export interface AdvertisedToolSource {
75
+ listTools(): Promise<HostMcpToolInfo[]>;
76
+ callTool(
77
+ toolName: string,
78
+ args: Record<string, unknown>
79
+ ): Promise<HostMcpCallResult>;
80
+ }
81
+
82
+ /**
83
+ * Resolve the advertised tools for one session. Returns `[]` when no
84
+ * connection advertises; throws (failing the turn) when a listing fails
85
+ * or a definition is invalid.
86
+ */
87
+ export async function resolveAdvertisedTools(args: {
88
+ agent: ResolvedAgent;
89
+ session: SessionInfo;
90
+ hostMcp: AdvertiseHostMcp;
91
+ /** Test seam; defaults to {@link sourceForConnection}. */
92
+ sourceFor?: (
93
+ connection: DiscoveredConnection,
94
+ session: SessionInfo,
95
+ hostMcp: AdvertiseHostMcp
96
+ ) => Promise<AdvertisedToolSource>;
97
+ }): Promise<DiscoveredTool[]> {
98
+ const advertising = args.agent.connections.filter(
99
+ (connection) => connection.advertiseTools === true
100
+ );
101
+ if (advertising.length === 0) {
102
+ return [];
103
+ }
104
+ const sourceFor = args.sourceFor ?? sourceForConnection;
105
+ const claimed = new Set(args.agent.tools.map((tool) => tool.name));
106
+ const resolved: DiscoveredTool[] = [];
107
+ for (const connection of advertising) {
108
+ const source = await sourceFor(connection, args.session, args.hostMcp);
109
+ let listed: HostMcpToolInfo[];
110
+ try {
111
+ listed = await source.listTools();
112
+ } catch (error) {
113
+ throw new Error(
114
+ `Failed to list tools on advertised connection "${connection.name}": ${describeError(error)}`,
115
+ { cause: error }
116
+ );
117
+ }
118
+ const exposed = exposeListedTools(listed, claimed);
119
+ for (const { info, exposedName } of exposed) {
120
+ resolved.push(toDiscoveredTool(connection, info, exposedName, source));
121
+ claimed.add(exposedName);
122
+ }
123
+ }
124
+ return resolved;
125
+ }
126
+
127
+ /**
128
+ * The production source for one advertising connection: the shared
129
+ * `host.mcp` registry client for auth-less connections (which also covers
130
+ * serve-resolved transports — Cursor account bridges, peers), or a
131
+ * registry one-off with the session's headers substituted when the
132
+ * connection has per-session `auth`. The auth callback is evaluated once
133
+ * per turn, here; the one-off opens a fresh client per operation so one
134
+ * session's identity can never serve another's call.
135
+ */
136
+ export async function sourceForConnection(
137
+ connection: DiscoveredConnection,
138
+ session: SessionInfo,
139
+ hostMcp: AdvertiseHostMcp
140
+ ): Promise<AdvertisedToolSource> {
141
+ if (connection.auth === undefined) {
142
+ return {
143
+ listTools: () => hostMcp.listTools(connection.name),
144
+ callTool: (toolName, callArgs) =>
145
+ hostMcp.callTool(connection.name, toolName, callArgs),
146
+ };
147
+ }
148
+ const transport = connection.transport;
149
+ if (!("url" in transport)) {
150
+ // Discovery rejects auth on non-URL transports; guard for callers that
151
+ // bypass discovery (hand-built projects).
152
+ throw new Error(
153
+ `Connection "${connection.name}" has per-session auth but no URL transport.`
154
+ );
155
+ }
156
+ const evaluated = await connection.auth(session);
157
+ return hostMcp.oneOff({
158
+ ...connection,
159
+ transport: {
160
+ ...transport,
161
+ headers: { ...transport.headers, ...evaluated.headers },
162
+ },
163
+ });
164
+ }
165
+
166
+ /**
167
+ * Same catalog rule as the Cursor-account bridge: slug illegal characters,
168
+ * then `_2` / `_3` … for colliders (including authored tools already in
169
+ * `claimed`). Suffix assignment is stable for a colliding group: sort by
170
+ * original advertised name, independent of `listTools` order.
171
+ */
172
+ function exposeListedTools(
173
+ listed: HostMcpToolInfo[],
174
+ claimed: ReadonlySet<string>
175
+ ): Array<{ info: HostMcpToolInfo; exposedName: string }> {
176
+ const byBase = new Map<string, HostMcpToolInfo[]>();
177
+ for (const info of listed) {
178
+ const base = sanitizeMcpToolName(info.name);
179
+ const group = byBase.get(base);
180
+ if (group === undefined) {
181
+ byBase.set(base, [info]);
182
+ } else {
183
+ group.push(info);
184
+ }
185
+ }
186
+ const taken = new Set(claimed);
187
+ const exposedNameByInfo = new Map<HostMcpToolInfo, string>();
188
+ const sortedBases = [...byBase.keys()].sort((left, right) =>
189
+ left < right ? -1 : left > right ? 1 : 0
190
+ );
191
+ for (const base of sortedBases) {
192
+ const group = byBase.get(base)!;
193
+ group.sort((left, right) =>
194
+ left.name < right.name ? -1 : left.name > right.name ? 1 : 0
195
+ );
196
+ group.forEach((info, index) => {
197
+ let suffixIndex = index;
198
+ let exposedName = suffixMcpToolName(base, suffixIndex);
199
+ while (taken.has(exposedName)) {
200
+ suffixIndex++;
201
+ exposedName = suffixMcpToolName(base, suffixIndex);
202
+ }
203
+ taken.add(exposedName);
204
+ exposedNameByInfo.set(info, exposedName);
205
+ });
206
+ }
207
+ return listed.map((info) => ({
208
+ info,
209
+ exposedName: exposedNameByInfo.get(info)!,
210
+ }));
211
+ }
212
+
213
+ function toDiscoveredTool(
214
+ connection: DiscoveredConnection,
215
+ info: HostMcpToolInfo,
216
+ exposedName: string,
217
+ source: AdvertisedToolSource
218
+ ): DiscoveredTool {
219
+ const description =
220
+ info.description === undefined || info.description.trim() === ""
221
+ ? `${info.name} — MCP tool on the "${connection.name}" connection, forwarded 1:1.`
222
+ : info.description;
223
+ const inputSchema = info.inputSchema ?? ANY_OBJECT_SCHEMA;
224
+ const outputSchema = info.outputSchema;
225
+ const definition: ToolDefinition = brandDefinition("tool", {
226
+ description,
227
+ inputSchema,
228
+ ...(outputSchema === undefined ? {} : { outputSchema }),
229
+ execute: async (input: Record<string, unknown>) =>
230
+ formatMcpToolResult(
231
+ connection.name,
232
+ info.name,
233
+ await source.callTool(info.name, input ?? {})
234
+ ),
235
+ } as unknown as ToolDefinition);
236
+ return {
237
+ name: exposedName,
238
+ description,
239
+ inputSchema,
240
+ ...(outputSchema === undefined ? {} : { outputSchema }),
241
+ execution: "server",
242
+ needsApproval: false,
243
+ definition,
244
+ };
245
+ }
246
+
247
+ /**
248
+ * Render an MCP call result for the model: text parts joined, non-text
249
+ * parts noted by type, `isError` surfaced as a thrown error so the turn
250
+ * records a tool error instead of error-shaped prose.
251
+ */
252
+ export function formatMcpToolResult(
253
+ connectionName: string,
254
+ toolName: string,
255
+ result: HostMcpCallResult
256
+ ): string {
257
+ const parts = result.content.map((item) =>
258
+ item.type === "text" && typeof item.text === "string"
259
+ ? item.text
260
+ : `[${item.type} content omitted]`
261
+ );
262
+ const text = parts.join("\n").trim();
263
+ if (result.isError === true) {
264
+ throw new Error(
265
+ text === "" ? `${connectionName} tool ${toolName} failed` : text
266
+ );
267
+ }
268
+ if (text !== "") {
269
+ return text;
270
+ }
271
+ return result.structuredContent !== undefined
272
+ ? JSON.stringify(result.structuredContent, null, 2)
273
+ : "(empty result)";
274
+ }
275
+
276
+ function describeError(error: unknown): string {
277
+ return error instanceof Error ? error.message : String(error);
278
+ }
@@ -22,6 +22,7 @@ import {
22
22
  SIGN_IN_HINT,
23
23
  } from "./cursor/credentials.js";
24
24
  import { authorizeCursorAccountConnectors } from "./cursor-account-mcp-auth.js";
25
+ import { readDeployTemplate } from "./cursor-agent-template.js";
25
26
  import {
26
27
  AgentServeDeployClient,
27
28
  type DeleteAccepted,
@@ -661,11 +662,20 @@ async function deployOne(
661
662
  ...(egressAllowedDomains.length === 0 ? {} : { egressAllowedDomains }),
662
663
  publicRoutePaths:
663
664
  publicRoutePaths.length === 0 ? undefined : publicRoutePaths,
665
+ // Deliberately NO manifest here: the control plane captures it from the
666
+ // provisioned engine (`GET /v1/manifest` after the health probe), which
667
+ // is the single write path for deploy manifests. `july manifest` remains
668
+ // available for local visibility only.
664
669
  };
665
670
 
666
671
  let accepted: DeployAccepted;
667
672
  try {
668
- accepted = await ctx.client.deploy({ teamId: ctx.teamId, slug, source });
673
+ accepted = await ctx.client.deploy({
674
+ teamId: ctx.teamId,
675
+ slug,
676
+ source,
677
+ template: readDeployTemplate(dir),
678
+ });
669
679
  } catch (error) {
670
680
  return renderApiError(error, ctx.err);
671
681
  }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * `july manifest` — print the offline deploy manifest (Wd-1 of
3
+ * `docs/agent-serve/agent-sdk-event-ingress-plan.md`).
4
+ *
5
+ * Loads the agent project from disk and emits the statically-derived
6
+ * metadata the control plane stores at deploy time: declared GitHub webhook
7
+ * events, egress domains, public routes, and the full `/v1/info` payload.
8
+ * Runs entirely offline — no VM, no engine, no network.
9
+ */
10
+
11
+ import {
12
+ buildAgentDeployManifest,
13
+ parseAgentDeployManifest,
14
+ } from "./deploy-manifest.js";
15
+ import { isAgentProjectDir, loadAgentProject } from "./discovery.js";
16
+
17
+ export interface CmdManifestOptions {
18
+ dir: string;
19
+ /** Compact single-line JSON (machine consumption); default pretty. */
20
+ json?: boolean;
21
+ /** Test seams. */
22
+ out?: (line: string) => void;
23
+ err?: (line: string) => void;
24
+ }
25
+
26
+ export async function cmdManifest(
27
+ options: CmdManifestOptions
28
+ ): Promise<number> {
29
+ const out = options.out ?? ((line: string) => process.stdout.write(line));
30
+ const err = options.err ?? ((line: string) => process.stderr.write(line));
31
+
32
+ if (!(await isAgentProjectDir(options.dir))) {
33
+ err(
34
+ `No agent project found at ${options.dir} (expected an agent.ts default-exporting defineAgent({ ... })).\n`
35
+ );
36
+ return 1;
37
+ }
38
+
39
+ const project = await loadAgentProject(options.dir);
40
+ for (const diagnostic of project.diagnostics) {
41
+ err(`${diagnostic.severity}: ${diagnostic.message}\n`);
42
+ }
43
+ if (project.diagnostics.some((d) => d.severity === "error")) {
44
+ return 1;
45
+ }
46
+
47
+ const manifest = buildAgentDeployManifest(project);
48
+ // Round-trip through the wire schema so `july manifest` can never emit
49
+ // something the control plane contract would reject.
50
+ if (
51
+ parseAgentDeployManifest(JSON.parse(JSON.stringify(manifest))) === undefined
52
+ ) {
53
+ err("internal error: generated manifest failed schema validation\n");
54
+ return 1;
55
+ }
56
+
57
+ out(
58
+ options.json === true
59
+ ? `${JSON.stringify(manifest)}\n`
60
+ : `${JSON.stringify(manifest, null, 2)}\n`
61
+ );
62
+ return 0;
63
+ }
@@ -402,7 +402,16 @@ function writePendingAdminWait(
402
402
  ? poll.oauthAuthorizeUrl
403
403
  : undefined;
404
404
  ctx.err(`Waiting for a Slack admin to approve the app${appSuffix}.\n\n`);
405
- if (requestUrl !== undefined) {
405
+ if (poll.approvalRequest === "pending") {
406
+ // Already in the admin queue: nothing to file, so no browser hop.
407
+ ctx.err(
408
+ ctx.dim(` Approval request sent; workspace owners were notified.\n\n`)
409
+ );
410
+ if (requestUrl !== undefined) {
411
+ ctx.err(ctx.dim(` Send a reminder from:\n\n`));
412
+ ctx.err(` ${requestUrl}\n\n`);
413
+ }
414
+ } else if (requestUrl !== undefined) {
406
415
  ctx.err(
407
416
  ctx.dim(
408
417
  ` Slack will notify workspace owners once the request is in their queue.\n` +
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  import { CLI_COMMAND_NAME, PACKAGE_NAME } from "../distribution.js";
10
+ import { MEMORY_TS } from "../init-scaffold.js";
10
11
  import { pascalCase, SlugRegistry, slugify } from "./slug.js";
11
12
  import type {
12
13
  ActionJson,
@@ -128,7 +129,7 @@ export function convertWorkflow(
128
129
  hasSlackAction && emitSlackAccountConnection(automation, out);
129
130
 
130
131
  if (workflow.memoryEnabled === true) {
131
- out.files.push({ path: "agent/hooks/memory.ts", contents: MEMORY_HOOK });
132
+ out.files.push({ path: "agent/hooks/memory.ts", contents: MEMORY_TS });
132
133
  }
133
134
 
134
135
  out.setupSteps.push(
@@ -1410,13 +1411,3 @@ function jsonComment(value: unknown): string[] {
1410
1411
  function dedupe(values: string[]): string[] {
1411
1412
  return [...new Set(values)];
1412
1413
  }
1413
-
1414
- /** Memory hook contents — identical to the `initProject` scaffold. */
1415
- const MEMORY_HOOK = `// Journals every turn (timestamp, session, user message, result) so
1416
- // future sessions can recall past work. The journal is shared across every
1417
- // session — and every user — of this agent. Pass your own MemoryBackend to
1418
- // change where memories live, or delete this file to opt out.
1419
- import { memoryHook } from "${PACKAGE_NAME}/memory";
1420
-
1421
- export default memoryHook();
1422
- `;