@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
@@ -16,7 +16,11 @@ import type {
16
16
  ToolEffectDeclaration,
17
17
  ToolExecuteResult,
18
18
  } from "../types.js";
19
- import { timeArgViolation } from "./as-of.js";
19
+ import {
20
+ forwardTimeArgument,
21
+ missingTimeWindow,
22
+ timeArgViolation,
23
+ } from "./as-of.js";
20
24
 
21
25
  /** What the host does with one tool call. */
22
26
  export type ToolDecision =
@@ -64,6 +68,14 @@ export interface ToolCallFacts {
64
68
  asOf?: string;
65
69
  /** The tool's declared time-bound argument names, if it made them. */
66
70
  timeArgs?: readonly string[];
71
+ /**
72
+ * String-typed time-window property names a vendor tool's own input schema
73
+ * declares (`from`/`to`/`since`/...). In a frozen session a call that omits
74
+ * one is refused: the vendor fills an omitted window with a live default
75
+ * the argument walker can never see. Advertised/bridged MCP tools only —
76
+ * authored tools declare {@link timeArgs} instead.
77
+ */
78
+ timeWindow?: readonly string[];
67
79
  }
68
80
 
69
81
  /**
@@ -159,14 +171,32 @@ function unclassifiedRefusal(toolName: string): string {
159
171
  export function decideToolCall(facts: ToolCallFacts): ToolDecision {
160
172
  // Before the dry-run split: a frozen session bounds its reads whether or
161
173
  // not its writes are stubbed.
162
- if (
163
- facts.asOf !== undefined &&
164
- facts.timeArgs !== undefined &&
165
- facts.timeArgs.length > 0
166
- ) {
167
- const violation = timeArgViolation(facts.input, facts.timeArgs, facts.asOf);
168
- if (violation !== undefined) {
169
- return { kind: "unbounded", message: violation };
174
+ if (facts.asOf !== undefined) {
175
+ if (facts.timeArgs !== undefined && facts.timeArgs.length > 0) {
176
+ const violation = timeArgViolation(
177
+ facts.input,
178
+ facts.timeArgs,
179
+ facts.asOf
180
+ );
181
+ if (violation !== undefined) {
182
+ return { kind: "unbounded", message: violation };
183
+ }
184
+ }
185
+ const forward = forwardTimeArgument(facts.input, facts.asOf);
186
+ if (forward !== undefined) {
187
+ return { kind: "unbounded", message: forward };
188
+ }
189
+ // Present values are checked above; absent ones are the vendor's live
190
+ // default window, which no walker can see. Require them explicitly.
191
+ if (facts.timeWindow !== undefined) {
192
+ const omitted = missingTimeWindow(
193
+ facts.input,
194
+ facts.timeWindow,
195
+ facts.asOf
196
+ );
197
+ if (omitted !== undefined) {
198
+ return { kind: "unbounded", message: omitted };
199
+ }
170
200
  }
171
201
  }
172
202
  if (!facts.dryRun) {
@@ -39,6 +39,7 @@ const DURABLE_SESSION_RECORD_KEY_RE =
39
39
  * | `agentkit/v1/{agent}/session/{sessionId}` | `SessionRecord` |
40
40
  * | `agentkit/v1/{agent}/session-events/{sessionId}/{index}` | `SessionEvent[]` chunk (index = first event's index, zero-padded) |
41
41
  * | `agentkit/v1/{agent}/session-runs/{sessionPublicId}` | One session-level hosted-execution log (executions[] + lastFailure) |
42
+ * | `agentkit/v1/{agent}/logs/{logId}` | Hosted engine stdout/stderr tee (on-disk `start.log`; `ses_…` after send, `wf:{workflowId}` on admission failure) |
42
43
  * | `agentkit/v1/{agent}/continuation/{channelId}/{token}` | `{ sessionId }` |
43
44
  * | `agentkit/v1/{agent}/kv/{key}` | Author JSON via `HostContext.kv` |
44
45
  *
@@ -69,6 +70,17 @@ export const storageKeys = {
69
70
  `${STORAGE_KEY_ROOT}/${agent}/session-runs/${keySegment(sessionPublicId)}`,
70
71
  sessionRunsPrefix: (agent: string): string =>
71
72
  `${STORAGE_KEY_ROOT}/${agent}/session-runs/`,
73
+ /**
74
+ * The v2 customer log: the engine stdout/stderr tee (on-disk `start.log`).
75
+ * `logId` is the factory `ses_…` after a `send`, or
76
+ * `wf:{workflowId}` / `wf:{workflowId}/{runId}` when admission fails
77
+ * before a session exists. Skip/task admissions do not write this key.
78
+ * Stored as raw UTF-8, not JSON — the file store accepts 64 MiB
79
+ * objects, and this key is flushed in snapshots, not per line.
80
+ */
81
+ log: (agent: string, logId: string): string =>
82
+ `${STORAGE_KEY_ROOT}/${agent}/logs/${keySegment(logId)}`,
83
+ logsPrefix: (agent: string): string => `${STORAGE_KEY_ROOT}/${agent}/logs/`,
72
84
  continuation: (
73
85
  agent: string,
74
86
  channelId: string,
@@ -111,6 +123,31 @@ export const storageKeys = {
111
123
  */
112
124
  export const MAX_KEY_SEGMENT_BYTES = 256;
113
125
 
126
+ /**
127
+ * Stable start-log object id. A `send` attaches to the factory session
128
+ * so the factory/dashboard session-runs read can see it. Admission that
129
+ * fails before a session exists is keyed on the Temporal workflow run
130
+ * (`wf:{workflowId}` or `wf:{workflowId}/{runId}`) so the object joins
131
+ * the Temporal UI. A successful skip/task writes nothing — there is no
132
+ * customer log.
133
+ */
134
+ export function frameworkStartLogId(args: {
135
+ sessionPublicId?: string | null;
136
+ workflowId?: string | null;
137
+ runId?: string | null;
138
+ }): string | undefined {
139
+ const sessionPublicId = args.sessionPublicId?.trim() ?? "";
140
+ if (sessionPublicId.length > 0) {
141
+ return sessionPublicId;
142
+ }
143
+ const workflowId = args.workflowId?.trim() ?? "";
144
+ if (workflowId.length === 0) {
145
+ return undefined;
146
+ }
147
+ const runId = args.runId?.trim() ?? "";
148
+ return runId.length > 0 ? `wf:${workflowId}/${runId}` : `wf:${workflowId}`;
149
+ }
150
+
114
151
  /**
115
152
  * URI-encode one caller-controlled key segment, substituting a `sha256:…`
116
153
  * digest of the raw value when the encoding exceeds
package/src/storage.ts CHANGED
@@ -63,6 +63,7 @@ export type {
63
63
  DurableSessionSummary,
64
64
  } from "./storage-protocol.js";
65
65
  export {
66
+ frameworkStartLogId,
66
67
  GOLDEN_DURABLE_SESSION_RECORD,
67
68
  isDurableSessionRecordKey,
68
69
  keySegment,
package/src/types.ts CHANGED
@@ -50,6 +50,8 @@ export type DefinitionKind =
50
50
  | "instructions"
51
51
  | "tool"
52
52
  | "skill"
53
+ | "extension"
54
+ | "disabled-tool"
53
55
  | "connection"
54
56
  | "channel"
55
57
  | "http-channel"
@@ -952,6 +954,42 @@ export function normalizeConnectionEffects(
952
954
  return unique;
953
955
  }
954
956
 
957
+ /**
958
+ * Trim, drop blanks, and unique-preserve authored
959
+ * {@link ConnectionConfig.tools} name lists. Invalid shapes are left
960
+ * for discovery.
961
+ */
962
+ export function normalizeConnectionTools(tools: readonly string[]): string[] {
963
+ const unique: string[] = [];
964
+ const seen = new Set<string>();
965
+ for (const raw of tools) {
966
+ const name = raw.trim();
967
+ if (name === "" || seen.has(name)) {
968
+ continue;
969
+ }
970
+ seen.add(name);
971
+ unique.push(name);
972
+ }
973
+ return unique;
974
+ }
975
+
976
+ /** True when `toolName` passes the connection's `tools` / `disallowedTools` filter. */
977
+ export function connectionAllowsTool(
978
+ filter: {
979
+ tools?: readonly string[];
980
+ disallowedTools?: readonly string[];
981
+ },
982
+ toolName: string
983
+ ): boolean {
984
+ if (filter.tools !== undefined && !filter.tools.includes(toolName)) {
985
+ return false;
986
+ }
987
+ return (
988
+ filter.disallowedTools === undefined ||
989
+ !filter.disallowedTools.includes(toolName)
990
+ );
991
+ }
992
+
955
993
  /**
956
994
  * A tool's declared {@link ToolEffect} — fixed, or decided per call from
957
995
  * validated input for tools that read or write depending on their arguments
@@ -1065,6 +1103,66 @@ export interface SkillConfig {
1065
1103
 
1066
1104
  export type SkillDefinition = SkillConfig & BrandedDefinition<"skill">;
1067
1105
 
1106
+ // ============================================================================
1107
+ // Extensions (agent/extensions/<ns>.ts | agent/extensions/<ns>/extension.ts)
1108
+ // ============================================================================
1109
+
1110
+ /**
1111
+ * Input to `defineExtension`, the `extension.ts` at the root of an
1112
+ * agent-shaped tree (`tools/`, `skills/`, `lib/`).
1113
+ */
1114
+ export interface ExtensionOptions<TConfig, TInput = TConfig> {
1115
+ /** The tree's directory; pass `import.meta.dirname`. */
1116
+ root: string;
1117
+ /** What the extension adds; shown by `info`. */
1118
+ description?: string;
1119
+ /** Mount configuration schema. A consumer's settings are validated at mount. */
1120
+ config?: z.ZodType<TConfig, z.ZodTypeDef, TInput>;
1121
+ }
1122
+
1123
+ /**
1124
+ * What `extension.ts` default-exports. A consumer calls it from
1125
+ * `agent/extensions/<ns>.ts` to mount the extension with a configuration;
1126
+ * the extension's own modules import it to read that configuration.
1127
+ */
1128
+ export interface Extension<TConfig = undefined, TInput = TConfig>
1129
+ extends ExtensionDeclaration {
1130
+ (
1131
+ ...args: undefined extends TInput ? [config?: TInput] : [config: TInput]
1132
+ ): ExtensionMount;
1133
+ /** The mounted configuration (schema defaults applied); throws before the mount. */
1134
+ readonly config: TConfig;
1135
+ }
1136
+
1137
+ /** The mount-independent part of an {@link Extension}. */
1138
+ export interface ExtensionDeclaration {
1139
+ readonly root: string;
1140
+ readonly description: string | undefined;
1141
+ }
1142
+
1143
+ /** What `agent/extensions/<ns>.ts` default-exports. */
1144
+ export interface ExtensionMount extends BrandedDefinition<"extension"> {
1145
+ readonly extension: ExtensionDeclaration;
1146
+ readonly config: unknown;
1147
+ }
1148
+
1149
+ /**
1150
+ * `export default disableTool()` in a directory mount's `tools/<name>.ts`
1151
+ * removes the extension's `<ns>__<name>`.
1152
+ */
1153
+ export type DisabledToolDefinition = BrandedDefinition<"disabled-tool">;
1154
+
1155
+ /** One mounted extension and the names it contributed. */
1156
+ export interface DiscoveredExtension {
1157
+ /** Mount namespace: the filename stem or directory name under `agent/extensions/`. */
1158
+ name: string;
1159
+ description?: string;
1160
+ /** Composed tool names (`<ns>__<name>`), overrides applied. */
1161
+ tools: string[];
1162
+ /** Composed skill names (`<ns>__<name>`), overrides applied. */
1163
+ skills: string[];
1164
+ }
1165
+
1068
1166
  // ============================================================================
1069
1167
  // MCP connections (agent/mcp-connections/*.ts)
1070
1168
  // ============================================================================
@@ -1213,19 +1311,38 @@ export type InlineStdioConnectionConfig = {
1213
1311
  * cloud VM.
1214
1312
  */
1215
1313
  export type ConnectionConfig = (
1216
- | Exclude<ConnectionTransport, { cursorAccount: true }>
1217
- | {
1218
- cursorAccount: true;
1314
+ | ((
1315
+ | Exclude<ConnectionTransport, { cursorAccount: true }>
1316
+ | {
1317
+ cursorAccount: true;
1318
+ /**
1319
+ * Which account connectors to expose.
1320
+ *
1321
+ * - Omit, pass `"*"`, or pass `["*"]` to forward **every** connected
1322
+ * HTTP/SSE server on the account (no per-connector allowlist).
1323
+ * - Pass connector names as they appear in the Cursor account's MCP
1324
+ * config (e.g. `["Linear", "Notion"]`) to restrict the set.
1325
+ */
1326
+ servers?: string[] | "*";
1327
+ }
1328
+ ) & {
1219
1329
  /**
1220
- * Which account connectors to expose.
1330
+ * Tool-name allowlist. Same shape as {@link AgentConfig.tools}:
1331
+ * when set, only these MCP tool names (the server's `tools/list`
1332
+ * names) are advertised and callable through `host.mcp`. Names
1333
+ * the server does not list are omitted, not guessed.
1334
+ *
1335
+ * A list of names is an allowlist. An object of handlers authors
1336
+ * TypeScript tools ({@link InlineStdioConnectionConfig}).
1221
1337
  *
1222
- * - Omit, pass `"*"`, or pass `["*"]` to forward **every** connected
1223
- * HTTP/SSE server on the account (no per-connector allowlist).
1224
- * - Pass connector names as they appear in the Cursor account's MCP
1225
- * config (e.g. `["Linear", "Notion"]`) to restrict the set.
1338
+ * On a model-visible connection this requires {@link advertiseTools}:
1339
+ * an attached server would still expose every tool. On
1340
+ * `host-connections/` it restricts `host.mcp` alone.
1341
+ *
1342
+ * Combines with {@link disallowedTools} as deny-wins.
1226
1343
  */
1227
- servers?: string[] | "*";
1228
- }
1344
+ tools?: readonly string[];
1345
+ })
1229
1346
  | InlineStdioConnectionConfig
1230
1347
  ) & {
1231
1348
  /** Documentation only; shown in `info` output. */
@@ -1300,6 +1417,16 @@ export type ConnectionConfig = (
1300
1417
  * are the same.
1301
1418
  */
1302
1419
  effects?: ConnectionEffects;
1420
+ /**
1421
+ * Tool-name denylist. Same shape as the Cursor SDK's
1422
+ * `disallowedTools`: when set, these MCP tool names are omitted from
1423
+ * the advertised set and rejected on `host.mcp`. Combines with
1424
+ * {@link ConnectionConfig.tools} as deny-wins.
1425
+ *
1426
+ * On a model-visible connection this requires {@link advertiseTools}.
1427
+ * On `host-connections/` it restricts `host.mcp` alone.
1428
+ */
1429
+ disallowedTools?: readonly string[];
1303
1430
  };
1304
1431
 
1305
1432
  /**
@@ -1322,7 +1449,11 @@ export function isInlineStdioConnection(
1322
1449
  ): connection is InlineStdioConnectionConfig & {
1323
1450
  description?: string;
1324
1451
  } {
1325
- return "tools" in connection && connection.tools !== undefined;
1452
+ return (
1453
+ "tools" in connection &&
1454
+ connection.tools !== undefined &&
1455
+ !Array.isArray(connection.tools)
1456
+ );
1326
1457
  }
1327
1458
 
1328
1459
  /**
@@ -1873,9 +2004,13 @@ export interface SendMessageOptions {
1873
2004
  dryRun?: boolean;
1874
2005
  /**
1875
2006
  * ISO-8601 instant with a timezone, frozen at create: the prompt states
1876
- * it, {@link ToolContext.now} returns it, and tools that declare
1877
- * {@link ToolConfig.timeArgs} refuse calls not bounded at or before it. A
1878
- * tool that declares nothing still reads the present.
2007
+ * it, {@link ToolContext.now} returns it, and every tool call is checked
2008
+ * against it a relative time argument (`now-1h`), an absolute one after
2009
+ * the instant, or an omitted window a vendor schema declares is refused so
2010
+ * the model retries with explicit absolute bounds. Tools may also declare
2011
+ * {@link ToolConfig.timeArgs} for precise per-field checking. The check
2012
+ * reads arguments, not behavior: a tool that reads present state without a
2013
+ * time argument still answers from the present.
1879
2014
  */
1880
2015
  asOf?: string;
1881
2016
  /**
@@ -2791,6 +2926,8 @@ export interface DiscoveredTool {
2791
2926
  advertised?: true;
2792
2927
  /** Name of the advertising connection an advertised tool came from. */
2793
2928
  connection?: string;
2929
+ /** Mounted extension this tool came from; absent for `agent/tools/`. */
2930
+ extension?: string;
2794
2931
  /**
2795
2932
  * Agent tools: script body materialized under
2796
2933
  * `.agent-serve/tools/<name>.sh`.
@@ -2809,6 +2946,8 @@ export interface DiscoveredSkill {
2809
2946
  markdown: string;
2810
2947
  /** Package-relative sibling files. */
2811
2948
  files: Record<string, SkillFileSource>;
2949
+ /** Mounted extension this skill came from; absent for `agent/skills/`. */
2950
+ extension?: string;
2812
2951
  }
2813
2952
 
2814
2953
  export interface DiscoveredConnection {
@@ -2824,6 +2963,16 @@ export interface DiscoveredConnection {
2824
2963
  * Absent means every listed tool is advertised.
2825
2964
  */
2826
2965
  effects?: readonly ToolEffect[];
2966
+ /**
2967
+ * Normalized tool-name allowlist from {@link ConnectionConfig.tools}.
2968
+ * Absent means every listed tool is kept.
2969
+ */
2970
+ tools?: readonly string[];
2971
+ /**
2972
+ * Normalized tool-name denylist from
2973
+ * {@link ConnectionConfig.disallowedTools}.
2974
+ */
2975
+ disallowedTools?: readonly string[];
2827
2976
  }
2828
2977
 
2829
2978
  export interface DiscoveredChannel {
@@ -2895,6 +3044,11 @@ export interface ResolvedAgent {
2895
3044
  architecture?: AgentArchitecture;
2896
3045
  tools: DiscoveredTool[];
2897
3046
  skills: DiscoveredSkill[];
3047
+ /**
3048
+ * Mounted `agent/extensions/`. Their tools and skills are already merged
3049
+ * into {@link tools} and {@link skills}; this records provenance.
3050
+ */
3051
+ extensions?: DiscoveredExtension[];
2898
3052
  connections: DiscoveredConnection[];
2899
3053
  /**
2900
3054
  * MCP connections from `agent/host-connections/`. Host tools and
@@ -2977,11 +3131,15 @@ export interface AgentProjectInfo {
2977
3131
  inputSchema: JsonSchemaObject;
2978
3132
  }>;
2979
3133
  skills: Array<{ name: string; description: string }>;
3134
+ /** Mounted extensions and the tool / skill names each contributed. */
3135
+ extensions: DiscoveredExtension[];
2980
3136
  connections: Array<{
2981
3137
  name: string;
2982
3138
  transport: string;
2983
3139
  advertiseTools?: boolean;
2984
3140
  effects?: readonly ToolEffect[];
3141
+ tools?: readonly string[];
3142
+ disallowedTools?: readonly string[];
2985
3143
  /**
2986
3144
  * Present only for `cursorAccount` connections: the connector-name
2987
3145
  * allowlist, or `"*"` for every connected server. Structured twin of the