@cursor/july 0.1.24 → 0.1.25

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 (195) hide show
  1. package/dist/bin/agent-serve.js +0 -0
  2. package/dist/channels/github/instrument.d.ts +20 -0
  3. package/dist/channels/github/instrument.d.ts.map +1 -0
  4. package/dist/docs/404.html +1 -1
  5. package/dist/docs/ab.html +2 -2
  6. package/dist/docs/assets/{app.CvSGaAxk.js → app.DYcC9FY-.js} +1 -1
  7. package/dist/docs/assets/chunks/@localSearchIndexroot.BQTzJjR_.js +1 -0
  8. package/dist/docs/assets/chunks/{VPLocalSearchBox.J1jJbCvs.js → VPLocalSearchBox.o4N_knTV.js} +1 -1
  9. package/dist/docs/assets/chunks/{theme.C7vfzr7h.js → theme.DQ-njyo0.js} +2 -2
  10. package/dist/docs/building-with-agents.html +2 -2
  11. package/dist/docs/concepts.html +2 -2
  12. package/dist/docs/deployment.html +2 -2
  13. package/dist/docs/evals.html +2 -2
  14. package/dist/docs/example-agents/approval-buddy.html +2 -2
  15. package/dist/docs/example-agents/benny.html +2 -2
  16. package/dist/docs/example-agents/bugbot.html +2 -2
  17. package/dist/docs/example-agents/codebase-wiki.html +2 -2
  18. package/dist/docs/example-agents/codeowners-review.html +2 -2
  19. package/dist/docs/example-agents/concierge.html +2 -2
  20. package/dist/docs/example-agents/fsd.html +2 -2
  21. package/dist/docs/example-agents/index.html +2 -2
  22. package/dist/docs/example-agents/knowledge-base.html +2 -2
  23. package/dist/docs/example-agents/oncall.html +2 -2
  24. package/dist/docs/example-agents/security-reviewer.html +2 -2
  25. package/dist/docs/example-agents/slack-agent.html +2 -2
  26. package/dist/docs/example-agents/weather-agent.html +2 -2
  27. package/dist/docs/guides/agent-to-agent.html +2 -2
  28. package/dist/docs/guides/cloud-runtime.html +2 -2
  29. package/dist/docs/guides/github.html +2 -2
  30. package/dist/docs/guides/human-in-the-loop.html +2 -2
  31. package/dist/docs/guides/mcp-oauth.html +2 -2
  32. package/dist/docs/guides/slack.html +2 -2
  33. package/dist/docs/guides/webhooks.html +2 -2
  34. package/dist/docs/hillclimbing.html +2 -2
  35. package/dist/docs/index.html +2 -2
  36. package/dist/docs/quickstart.html +2 -2
  37. package/dist/docs/reference/agent-config.html +2 -2
  38. package/dist/docs/reference/channels.html +2 -2
  39. package/dist/docs/reference/cli.html +2 -2
  40. package/dist/docs/reference/connections.html +2 -2
  41. package/dist/docs/reference/hooks.html +2 -2
  42. package/dist/docs/reference/http-api.html +2 -2
  43. package/dist/docs/reference/instructions.html +2 -2
  44. package/dist/docs/reference/playground.html +2 -2
  45. package/dist/docs/reference/project-layout.html +2 -2
  46. package/dist/docs/reference/prompt.html +2 -2
  47. package/dist/docs/reference/schedules.html +2 -2
  48. package/dist/docs/reference/sessions.html +2 -2
  49. package/dist/docs/reference/skills.html +2 -2
  50. package/dist/docs/reference/subagents.html +2 -2
  51. package/dist/docs/reference/tools.html +2 -2
  52. package/dist/docs/scaffolding-agents.html +2 -2
  53. package/dist/docs/storage.html +2 -2
  54. package/dist/docs/troubleshooting.html +2 -2
  55. package/dist/internal/json-dir-store.d.ts +32 -0
  56. package/dist/internal/json-dir-store.d.ts.map +1 -0
  57. package/dist/internal/json-dir-store.js +100 -0
  58. package/dist/playground/assets/index-CjOQ4hN9.css +1 -0
  59. package/dist/playground/assets/{index-DTG9OsPV.js → index-DqXdAFGa.js} +41 -41
  60. package/dist/playground/index.html +2 -2
  61. package/package.json +31 -24
  62. package/src/artifacts.ts +78 -0
  63. package/src/bin/agent-serve.version.test.ts +64 -0
  64. package/src/channels/github/api.test.ts +64 -0
  65. package/src/channels/github/auth.test.ts +105 -0
  66. package/src/channels/github/cursor-account.test.ts +204 -0
  67. package/src/channels/github/forward.test.ts +457 -0
  68. package/src/channels/github/github.test.ts +943 -0
  69. package/src/channels/github/replay.test.ts +179 -0
  70. package/src/channels/slack/api.post-message.test.ts +148 -0
  71. package/src/channels/slack/approvals.test.ts +328 -0
  72. package/src/channels/slack/block-actions.test.ts +452 -0
  73. package/src/channels/slack/bot-mentions.test.ts +267 -0
  74. package/src/channels/slack/channel-watch.test.ts +363 -0
  75. package/src/channels/slack/cursor-account.test.ts +253 -0
  76. package/src/channels/slack/defaults.final-post.test.ts +182 -0
  77. package/src/channels/slack/dispatch.test.ts +795 -0
  78. package/src/channels/slack/eval-directive.test.ts +273 -0
  79. package/src/channels/slack/message-body.test.ts +54 -0
  80. package/src/channels/slack/nudge-store.test.ts +143 -0
  81. package/src/channels/slack/slack.test.ts +391 -0
  82. package/src/channels/slack/stop.test.ts +23 -0
  83. package/src/channels/slack/thread-context.test.ts +202 -0
  84. package/src/evals/assertions.test.ts +617 -0
  85. package/src/evals/assertions.ts +37 -1
  86. package/src/evals/expect.test.ts +144 -0
  87. package/src/evals/judge.test.ts +181 -0
  88. package/src/evals/loaders.test.ts +132 -0
  89. package/src/evals/matchers.test.ts +95 -0
  90. package/src/evals/reporters.test.ts +303 -0
  91. package/src/evals/run-facts.test.ts +259 -0
  92. package/src/evals.ts +1 -0
  93. package/src/index.ts +1 -0
  94. package/src/internal/ab-snapshot.test.ts +325 -0
  95. package/src/internal/approval-gate.test.ts +49 -0
  96. package/src/internal/approvals.integration.test.ts +383 -0
  97. package/src/internal/artifacts-store.test.ts +283 -0
  98. package/src/internal/artifacts-store.ts +290 -0
  99. package/src/internal/authored-loaders.test.ts +31 -0
  100. package/src/internal/builtin-tools/artifacts.test.ts +247 -0
  101. package/src/internal/builtin-tools/artifacts.ts +74 -0
  102. package/src/internal/builtin-tools/index.ts +21 -0
  103. package/src/internal/builtin-tools/reminders.test.ts +201 -0
  104. package/src/internal/channel-route-schema.test.ts +294 -0
  105. package/src/internal/chat-attach.test.ts +262 -0
  106. package/src/internal/cli-deploy.test.ts +1991 -0
  107. package/src/internal/cli-docs.test.ts +161 -0
  108. package/src/internal/cli-mcp.test.ts +789 -0
  109. package/src/internal/cli-skills.test.ts +133 -0
  110. package/src/internal/cli-slack.test.ts +1654 -0
  111. package/src/internal/cli-slack.ts +13 -4
  112. package/src/internal/cloud-merge.test.ts +74 -0
  113. package/src/internal/cron.test.ts +22 -0
  114. package/src/internal/cursor/account-mcp.test.ts +807 -0
  115. package/src/internal/cursor/backend-client.test.ts +591 -0
  116. package/src/internal/cursor/credentials.test.ts +351 -0
  117. package/src/internal/cursor/github-credentials.test.ts +136 -0
  118. package/src/internal/cursor-account-mcp-auth.test.ts +310 -0
  119. package/src/internal/cursor-account.integration.test.ts +441 -0
  120. package/src/internal/cursor-event-relay.test.ts +746 -0
  121. package/src/internal/cursor-github-credentials.integration.test.ts +271 -0
  122. package/src/internal/cursor-slack-relay.test.ts +525 -0
  123. package/src/internal/deploy-source.test.ts +111 -0
  124. package/src/internal/discovery.artifact-tool.test.ts +136 -0
  125. package/src/internal/discovery.artifacts.test.ts +119 -0
  126. package/src/internal/discovery.builtin-tools.test.ts +94 -0
  127. package/src/internal/discovery.concurrency.test.ts +60 -0
  128. package/src/internal/discovery.cursor-account.test.ts +133 -0
  129. package/src/internal/discovery.cwd.test.ts +83 -0
  130. package/src/internal/discovery.hosting.test.ts +80 -0
  131. package/src/internal/discovery.identity.test.ts +44 -0
  132. package/src/internal/discovery.ts +102 -1
  133. package/src/internal/distribution.ts +1 -0
  134. package/src/internal/docs-site.test.ts +66 -0
  135. package/src/internal/duration.test.ts +29 -0
  136. package/src/internal/eval-judge-model.test.ts +187 -0
  137. package/src/internal/eval-run-store.cancel.test.ts +142 -0
  138. package/src/internal/eval-run-store.storage.test.ts +211 -0
  139. package/src/internal/eval-runner.http.test.ts +403 -0
  140. package/src/internal/eval-runner.run.test.ts +928 -0
  141. package/src/internal/evals-client.test.ts +307 -0
  142. package/src/internal/event-mapper.test.ts +243 -0
  143. package/src/internal/github-fanout.test.ts +213 -0
  144. package/src/internal/handleAgentServeTrigger.test.ts +185 -0
  145. package/src/internal/host-kv.test.ts +82 -0
  146. package/src/internal/host-platforms.test.ts +126 -0
  147. package/src/internal/http-channel.test.ts +402 -0
  148. package/src/internal/init-project.test.ts +270 -0
  149. package/src/internal/install-cursor-skills.test.ts +262 -0
  150. package/src/internal/local-env.test.ts +120 -0
  151. package/src/internal/log-ring.test.ts +31 -0
  152. package/src/internal/logs-client.test.ts +350 -0
  153. package/src/internal/mcp-endpoint.test.ts +436 -0
  154. package/src/internal/mcp-host.test.ts +298 -0
  155. package/src/internal/mcp-oauth.test.ts +148 -0
  156. package/src/internal/net.test.ts +17 -0
  157. package/src/internal/peer-connections.test.ts +128 -0
  158. package/src/internal/peer-mcp.integration.test.ts +289 -0
  159. package/src/internal/playground/toolchain.test.ts +53 -0
  160. package/src/internal/playground-cli.test.ts +187 -0
  161. package/src/internal/playground-proxy.test.ts +376 -0
  162. package/src/internal/prompt-context.integration.test.ts +232 -0
  163. package/src/internal/prompt-context.test.ts +127 -0
  164. package/src/internal/reminder-runner.test.ts +390 -0
  165. package/src/internal/reminder-store.test.ts +53 -0
  166. package/src/internal/request-headers.test.ts +27 -0
  167. package/src/internal/resolve-prod-target.test.ts +787 -0
  168. package/src/internal/resolved-connections.test.ts +295 -0
  169. package/src/internal/router.test.ts +57 -0
  170. package/src/internal/sdk-runner.test.ts +290 -0
  171. package/src/internal/server.artifacts.test.ts +303 -0
  172. package/src/internal/server.ts +43 -0
  173. package/src/internal/session-engine.artifacts.test.ts +243 -0
  174. package/src/internal/session-engine.coalesce.test.ts +169 -0
  175. package/src/internal/session-engine.concurrency.test.ts +250 -0
  176. package/src/internal/session-engine.host-oauth-mcp.test.ts +110 -0
  177. package/src/internal/session-engine.interrupt.test.ts +577 -0
  178. package/src/internal/session-engine.storage.test.ts +547 -0
  179. package/src/internal/session-engine.ts +125 -0
  180. package/src/internal/session-urls.test.ts +28 -0
  181. package/src/internal/sessions-client.test.ts +518 -0
  182. package/src/internal/storage-coordinator.test.ts +517 -0
  183. package/src/internal/storage-coordinator.ts +62 -0
  184. package/src/internal/tool-call.test.ts +458 -0
  185. package/src/internal/tool-result.test.ts +52 -0
  186. package/src/internal/trajectory.approvals.test.ts +83 -0
  187. package/src/internal/trajectory.subagents.test.ts +198 -0
  188. package/src/internal/turn-governor.test.ts +137 -0
  189. package/src/internal/update-check.test.ts +485 -0
  190. package/src/internal/workspace.test.ts +207 -0
  191. package/src/storage-backends/cursor-hosted.test.ts +121 -0
  192. package/src/storage.ts +6 -0
  193. package/src/types.ts +134 -1
  194. package/dist/docs/assets/chunks/@localSearchIndexroot.CL2Y0Zmh.js +0 -1
  195. package/dist/playground/assets/index-CidizGZv.css +0 -1
@@ -24,6 +24,10 @@ import {
24
24
  import {
25
25
  type AgentProject,
26
26
  type ApprovalDecision,
27
+ type ArtifactListFilter,
28
+ type ArtifactRecord,
29
+ type ArtifactsApi,
30
+ type ArtifactTagInput,
27
31
  type AuthContext,
28
32
  type CallToolOptions,
29
33
  type ChannelDefinition,
@@ -60,6 +64,7 @@ import { ABCollector } from "./ab-collector.js";
60
64
  import { foldABStream } from "./ab-fold.js";
61
65
  import { type ABSnapshot, buildABSnapshot } from "./ab-snapshot.js";
62
66
  import { ApprovalGate } from "./approval-gate.js";
67
+ import { ArtifactsStore } from "./artifacts-store.js";
63
68
  import { samePrincipal } from "./auth.js";
64
69
  import { mergeCloudOptions, resolveSessionRuntime } from "./cloud-merge.js";
65
70
  import { isDevMode } from "./dev-mode.js";
@@ -278,6 +283,8 @@ export class SessionEngine {
278
283
  private reminderApi: HostContext["reminders"];
279
284
  private evalsApi: HostContext["evals"];
280
285
  private readonly kvApi: HostContext["kv"];
286
+ /** Engine-owned artifacts service behind every `ctx.artifacts` facade. */
287
+ private readonly artifactsStore: ArtifactsStore;
281
288
  /** Serve-time resolved connections (see {@link setResolvedConnections}). */
282
289
  private resolvedConnections: EngineResolvedConnection[] = [];
283
290
 
@@ -315,6 +322,11 @@ export class SessionEngine {
315
322
  stateRoot: options.stateRoot,
316
323
  ...(this.storage === undefined ? {} : { storage: this.storage }),
317
324
  });
325
+ this.artifactsStore = new ArtifactsStore({
326
+ stateRoot: options.stateRoot,
327
+ storage: this.storage,
328
+ config: options.project.artifacts,
329
+ });
318
330
  this.abCollector = new ABCollector(
319
331
  options.project.abs,
320
332
  this.logger,
@@ -370,6 +382,78 @@ export class SessionEngine {
370
382
  };
371
383
  }
372
384
 
385
+ /** Unbound `ctx.artifacts` facade (channel handlers, scratch tool calls). */
386
+ get artifacts(): ArtifactsApi {
387
+ return this.artifactsApi();
388
+ }
389
+
390
+ /**
391
+ * Build one `ctx.artifacts` facade over the engine-owned artifacts
392
+ * service. With a `binding` (tools, hooks) `tag` auto-fills the bound
393
+ * session (and turn when known) and rejects a conflicting explicit
394
+ * `sessionId`; without one (channel handlers) callers may pass
395
+ * `sessionId` / `turnId` explicitly.
396
+ */
397
+ artifactsApi(binding?: { sessionId: string; turnId?: string }): ArtifactsApi {
398
+ return {
399
+ tag: async (input) => {
400
+ if (binding === undefined) {
401
+ return this.tagArtifact(input);
402
+ }
403
+ if (
404
+ input.sessionId !== undefined &&
405
+ input.sessionId !== binding.sessionId
406
+ ) {
407
+ throw new Error(
408
+ `artifacts.tag: this context is bound to session ${binding.sessionId}; cannot tag for ${input.sessionId}`
409
+ );
410
+ }
411
+ return this.tagArtifact({
412
+ ...input,
413
+ sessionId: binding.sessionId,
414
+ turnId: input.turnId ?? binding.turnId,
415
+ });
416
+ },
417
+ list: (filter) => this.artifactsStore.list(filter),
418
+ };
419
+ }
420
+
421
+ /**
422
+ * Single tag funnel: upsert the row, then — for session-bound tags —
423
+ * append `artifact.tagged` through {@link appendEvent} so persistence
424
+ * flush and hook fan-out are inherited. Session-less tags skip the event.
425
+ * An unknown `sessionId` rejects before the row is written (appending to
426
+ * a session that was never materialized here would mint an orphan local
427
+ * event log, breaking the local-over-sink restore invariant).
428
+ */
429
+ private async tagArtifact(input: ArtifactTagInput): Promise<ArtifactRecord> {
430
+ if (
431
+ input.sessionId !== undefined &&
432
+ (await this.getOrRestoreSession(input.sessionId)) === undefined
433
+ ) {
434
+ throw new UnknownSessionError(input.sessionId);
435
+ }
436
+ const record = await this.artifactsStore.tag(input);
437
+ if (record.sessionId !== undefined) {
438
+ await this.appendEvent(record.sessionId, {
439
+ type: "artifact.tagged",
440
+ turnId: record.turnId,
441
+ data: {
442
+ id: record.id,
443
+ kind: record.kind,
444
+ key: record.key,
445
+ title: record.title,
446
+ data: record.data,
447
+ source: record.source,
448
+ },
449
+ });
450
+ }
451
+ this.logger(
452
+ `[session] artifact tagged kind=${record.kind} id=${record.id} source=${record.source} session=${record.sessionId ?? "-"} key=${record.key ?? "-"}`
453
+ );
454
+ return record;
455
+ }
456
+
373
457
  private slackNudgeHostApi(): SlackNudgeHostApi {
374
458
  return {
375
459
  append: (input) => this.nudgeStore.append(input),
@@ -1408,6 +1492,10 @@ export class SessionEngine {
1408
1492
  workspaceDir: this.harnessCwd(record),
1409
1493
  stateRoot: this.stateRoot,
1410
1494
  host: this.host,
1495
+ artifacts: this.artifactsApi({
1496
+ sessionId: record.sessionId,
1497
+ turnId,
1498
+ }),
1411
1499
  send: (channelId, message, sendOptions = {}) =>
1412
1500
  this.send(channelId, message, {
1413
1501
  ...sendOptions,
@@ -1730,6 +1818,14 @@ export class SessionEngine {
1730
1818
  workspaceDir,
1731
1819
  stateRoot: this.stateRoot,
1732
1820
  host: this.host,
1821
+ // Scratch calls have no real session; their facade stays unbound.
1822
+ artifacts:
1823
+ record === undefined
1824
+ ? this.artifactsApi()
1825
+ : this.artifactsApi({
1826
+ sessionId: record.sessionId,
1827
+ turnId: callId,
1828
+ }),
1733
1829
  send: (channelId, message, sendOptions = {}) =>
1734
1830
  this.send(channelId, message, {
1735
1831
  ...sendOptions,
@@ -1882,6 +1978,10 @@ export class SessionEngine {
1882
1978
  },
1883
1979
  session: this.sessionInfo(record),
1884
1980
  stateRoot: this.stateRoot,
1981
+ artifacts: this.artifactsApi({
1982
+ sessionId: record.sessionId,
1983
+ turnId: event.turnId,
1984
+ }),
1885
1985
  });
1886
1986
  } catch (error) {
1887
1987
  this.logger(
@@ -1951,6 +2051,31 @@ export class SessionEngine {
1951
2051
  return (await this.listSessionsWithSource(caller, options)).sessions;
1952
2052
  }
1953
2053
 
2054
+ /**
2055
+ * Artifacts for `GET /v1/artifacts`, newest-updated first. Without
2056
+ * `includeAll`, the sessions-list ownership rule applies: only artifacts
2057
+ * tagged on a session whose principal matches the caller. Session-less
2058
+ * artifacts are agent-scoped and visible only with `includeAll`.
2059
+ */
2060
+ async listArtifacts(
2061
+ caller: AuthContext | null,
2062
+ options?: { includeAll?: boolean; filter?: ArtifactListFilter }
2063
+ ): Promise<ArtifactRecord[]> {
2064
+ const records = await this.artifactsStore.list(options?.filter);
2065
+ if (options?.includeAll === true) {
2066
+ return records;
2067
+ }
2068
+ const sessions = await this.sessions.list();
2069
+ const owned = new Set(
2070
+ sessions
2071
+ .filter((record) => samePrincipal(record.auth, caller))
2072
+ .map((record) => record.sessionId)
2073
+ );
2074
+ return records.filter(
2075
+ (record) => record.sessionId !== undefined && owned.has(record.sessionId)
2076
+ );
2077
+ }
2078
+
1954
2079
  /**
1955
2080
  * Same as {@link listSessions}, plus which store answered
1956
2081
  * (`cursor-hosted` = durable DB via the control-plane proxy; `local` =
@@ -0,0 +1,28 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ eventsUrlForSession,
4
+ playgroundUrlForSession,
5
+ sessionUrlsForRequest,
6
+ } from "./session-urls.js";
7
+
8
+ describe("sessionUrls", () => {
9
+ it("builds playground and trace URLs for a single-agent mount", () => {
10
+ const request = new Request("http://127.0.0.1:3000/v1/channels/review");
11
+ expect(sessionUrlsForRequest(request, "", "ses_abc")).toEqual({
12
+ playgroundUrl: "http://127.0.0.1:3000/playground?sessionId=ses_abc",
13
+ traceUrl: "http://127.0.0.1:3000/v1/session/ses_abc/events",
14
+ });
15
+ });
16
+
17
+ it("prefixes the multi-agent slug mount", () => {
18
+ const request = new Request(
19
+ "http://127.0.0.1:3000/bugbot/v1/channels/review"
20
+ );
21
+ expect(playgroundUrlForSession(request, "/bugbot", "ses_1")).toBe(
22
+ "http://127.0.0.1:3000/bugbot/playground?sessionId=ses_1"
23
+ );
24
+ expect(eventsUrlForSession(request.url, "bugbot", "ses with spaces")).toBe(
25
+ "http://127.0.0.1:3000/bugbot/v1/session/ses%20with%20spaces/events"
26
+ );
27
+ });
28
+ });