@cursor/july 0.1.24 → 0.1.26

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 (205) 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-channel.ts +19 -2
  69. package/src/channels/github/github.test.ts +985 -0
  70. package/src/channels/github/replay.test.ts +179 -0
  71. package/src/channels/github/types.ts +6 -0
  72. package/src/channels/slack/api.post-message.test.ts +148 -0
  73. package/src/channels/slack/api.ts +3 -1
  74. package/src/channels/slack/approvals.test.ts +328 -0
  75. package/src/channels/slack/block-actions.test.ts +469 -0
  76. package/src/channels/slack/bot-mentions.test.ts +267 -0
  77. package/src/channels/slack/channel-watch.test.ts +363 -0
  78. package/src/channels/slack/cursor-account.test.ts +301 -0
  79. package/src/channels/slack/cursor-account.ts +3 -1
  80. package/src/channels/slack/defaults.final-post.test.ts +182 -0
  81. package/src/channels/slack/dispatch.test.ts +875 -0
  82. package/src/channels/slack/dispatch.ts +12 -1
  83. package/src/channels/slack/eval-directive.test.ts +273 -0
  84. package/src/channels/slack/interactive.ts +3 -0
  85. package/src/channels/slack/message-body.test.ts +54 -0
  86. package/src/channels/slack/nudge-store.test.ts +143 -0
  87. package/src/channels/slack/slack-channel.ts +6 -0
  88. package/src/channels/slack/slack.test.ts +391 -0
  89. package/src/channels/slack/stop.test.ts +23 -0
  90. package/src/channels/slack/thread-context.test.ts +202 -0
  91. package/src/channels/slack/types.ts +6 -0
  92. package/src/evals/assertions.test.ts +617 -0
  93. package/src/evals/assertions.ts +37 -1
  94. package/src/evals/expect.test.ts +144 -0
  95. package/src/evals/judge.test.ts +181 -0
  96. package/src/evals/loaders.test.ts +132 -0
  97. package/src/evals/matchers.test.ts +95 -0
  98. package/src/evals/reporters.test.ts +303 -0
  99. package/src/evals/run-facts.test.ts +259 -0
  100. package/src/evals.ts +1 -0
  101. package/src/index.ts +1 -0
  102. package/src/internal/ab-snapshot.test.ts +325 -0
  103. package/src/internal/approval-gate.test.ts +49 -0
  104. package/src/internal/approvals.integration.test.ts +383 -0
  105. package/src/internal/artifacts-store.test.ts +283 -0
  106. package/src/internal/artifacts-store.ts +290 -0
  107. package/src/internal/authored-loaders.test.ts +31 -0
  108. package/src/internal/builtin-tools/artifacts.test.ts +247 -0
  109. package/src/internal/builtin-tools/artifacts.ts +74 -0
  110. package/src/internal/builtin-tools/index.ts +21 -0
  111. package/src/internal/builtin-tools/reminders.test.ts +201 -0
  112. package/src/internal/channel-route-schema.test.ts +294 -0
  113. package/src/internal/chat-attach.test.ts +262 -0
  114. package/src/internal/cli-deploy.test.ts +1991 -0
  115. package/src/internal/cli-docs.test.ts +161 -0
  116. package/src/internal/cli-mcp.test.ts +789 -0
  117. package/src/internal/cli-skills.test.ts +133 -0
  118. package/src/internal/cli-slack.test.ts +1654 -0
  119. package/src/internal/cli-slack.ts +13 -4
  120. package/src/internal/cloud-merge.test.ts +74 -0
  121. package/src/internal/cron.test.ts +22 -0
  122. package/src/internal/cursor/account-mcp.test.ts +807 -0
  123. package/src/internal/cursor/backend-client.test.ts +591 -0
  124. package/src/internal/cursor/credentials.test.ts +351 -0
  125. package/src/internal/cursor/github-credentials.test.ts +136 -0
  126. package/src/internal/cursor-account-mcp-auth.test.ts +310 -0
  127. package/src/internal/cursor-account.integration.test.ts +441 -0
  128. package/src/internal/cursor-event-relay.test.ts +746 -0
  129. package/src/internal/cursor-github-credentials.integration.test.ts +271 -0
  130. package/src/internal/cursor-slack-relay.test.ts +525 -0
  131. package/src/internal/deploy-source.test.ts +111 -0
  132. package/src/internal/discovery.artifact-tool.test.ts +136 -0
  133. package/src/internal/discovery.artifacts.test.ts +119 -0
  134. package/src/internal/discovery.builtin-tools.test.ts +94 -0
  135. package/src/internal/discovery.concurrency.test.ts +60 -0
  136. package/src/internal/discovery.cursor-account.test.ts +133 -0
  137. package/src/internal/discovery.cwd.test.ts +83 -0
  138. package/src/internal/discovery.hosting.test.ts +80 -0
  139. package/src/internal/discovery.identity.test.ts +44 -0
  140. package/src/internal/discovery.ts +102 -1
  141. package/src/internal/distribution.ts +1 -0
  142. package/src/internal/docs-site.test.ts +66 -0
  143. package/src/internal/duration.test.ts +29 -0
  144. package/src/internal/eval-judge-model.test.ts +187 -0
  145. package/src/internal/eval-run-store.cancel.test.ts +142 -0
  146. package/src/internal/eval-run-store.storage.test.ts +211 -0
  147. package/src/internal/eval-runner.http.test.ts +403 -0
  148. package/src/internal/eval-runner.run.test.ts +928 -0
  149. package/src/internal/evals-client.test.ts +307 -0
  150. package/src/internal/event-mapper.test.ts +243 -0
  151. package/src/internal/github-fanout.test.ts +213 -0
  152. package/src/internal/handleAgentServeTrigger.test.ts +185 -0
  153. package/src/internal/host-kv.test.ts +82 -0
  154. package/src/internal/host-platforms.test.ts +126 -0
  155. package/src/internal/http-channel.test.ts +402 -0
  156. package/src/internal/init-project.test.ts +270 -0
  157. package/src/internal/install-cursor-skills.test.ts +262 -0
  158. package/src/internal/local-env.test.ts +120 -0
  159. package/src/internal/log-ring.test.ts +31 -0
  160. package/src/internal/logs-client.test.ts +350 -0
  161. package/src/internal/mcp-endpoint.test.ts +436 -0
  162. package/src/internal/mcp-host.test.ts +298 -0
  163. package/src/internal/mcp-oauth.test.ts +148 -0
  164. package/src/internal/net.test.ts +17 -0
  165. package/src/internal/peer-connections.test.ts +128 -0
  166. package/src/internal/peer-mcp.integration.test.ts +289 -0
  167. package/src/internal/playground/toolchain.test.ts +53 -0
  168. package/src/internal/playground-cli.test.ts +187 -0
  169. package/src/internal/playground-proxy.test.ts +376 -0
  170. package/src/internal/prompt-context.integration.test.ts +232 -0
  171. package/src/internal/prompt-context.test.ts +127 -0
  172. package/src/internal/reminder-runner.test.ts +432 -0
  173. package/src/internal/reminder-runner.ts +1 -0
  174. package/src/internal/reminder-store.test.ts +53 -0
  175. package/src/internal/request-headers.test.ts +27 -0
  176. package/src/internal/resolve-prod-target.test.ts +787 -0
  177. package/src/internal/resolved-connections.test.ts +295 -0
  178. package/src/internal/router.test.ts +57 -0
  179. package/src/internal/schedule-runner.ts +1 -0
  180. package/src/internal/sdk-runner.test.ts +290 -0
  181. package/src/internal/server.artifacts.test.ts +334 -0
  182. package/src/internal/server.ts +45 -0
  183. package/src/internal/session-engine.artifacts.test.ts +293 -0
  184. package/src/internal/session-engine.coalesce.test.ts +169 -0
  185. package/src/internal/session-engine.concurrency.test.ts +250 -0
  186. package/src/internal/session-engine.host-oauth-mcp.test.ts +110 -0
  187. package/src/internal/session-engine.interrupt.test.ts +577 -0
  188. package/src/internal/session-engine.storage.test.ts +547 -0
  189. package/src/internal/session-engine.ts +129 -1
  190. package/src/internal/session-urls.test.ts +28 -0
  191. package/src/internal/sessions-client.test.ts +518 -0
  192. package/src/internal/storage-coordinator.test.ts +517 -0
  193. package/src/internal/storage-coordinator.ts +62 -0
  194. package/src/internal/tool-call.test.ts +458 -0
  195. package/src/internal/tool-result.test.ts +52 -0
  196. package/src/internal/trajectory.approvals.test.ts +83 -0
  197. package/src/internal/trajectory.subagents.test.ts +198 -0
  198. package/src/internal/turn-governor.test.ts +137 -0
  199. package/src/internal/update-check.test.ts +485 -0
  200. package/src/internal/workspace.test.ts +207 -0
  201. package/src/storage-backends/cursor-hosted.test.ts +121 -0
  202. package/src/storage.ts +6 -0
  203. package/src/types.ts +152 -2
  204. package/dist/docs/assets/chunks/@localSearchIndexroot.CL2Y0Zmh.js +0 -1
  205. 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),
@@ -632,7 +716,10 @@ export class SessionEngine {
632
716
  lastCreated = session;
633
717
  return session;
634
718
  };
635
- const returned = await definition.receive(input, { send });
719
+ const returned = await definition.receive(input, {
720
+ send,
721
+ artifacts: this.artifactsApi(),
722
+ });
636
723
  const session = returned ?? lastCreated;
637
724
  if (session === undefined) {
638
725
  throw new Error(
@@ -1408,6 +1495,10 @@ export class SessionEngine {
1408
1495
  workspaceDir: this.harnessCwd(record),
1409
1496
  stateRoot: this.stateRoot,
1410
1497
  host: this.host,
1498
+ artifacts: this.artifactsApi({
1499
+ sessionId: record.sessionId,
1500
+ turnId,
1501
+ }),
1411
1502
  send: (channelId, message, sendOptions = {}) =>
1412
1503
  this.send(channelId, message, {
1413
1504
  ...sendOptions,
@@ -1730,6 +1821,14 @@ export class SessionEngine {
1730
1821
  workspaceDir,
1731
1822
  stateRoot: this.stateRoot,
1732
1823
  host: this.host,
1824
+ // Scratch calls have no real session; their facade stays unbound.
1825
+ artifacts:
1826
+ record === undefined
1827
+ ? this.artifactsApi()
1828
+ : this.artifactsApi({
1829
+ sessionId: record.sessionId,
1830
+ turnId: callId,
1831
+ }),
1733
1832
  send: (channelId, message, sendOptions = {}) =>
1734
1833
  this.send(channelId, message, {
1735
1834
  ...sendOptions,
@@ -1882,6 +1981,10 @@ export class SessionEngine {
1882
1981
  },
1883
1982
  session: this.sessionInfo(record),
1884
1983
  stateRoot: this.stateRoot,
1984
+ artifacts: this.artifactsApi({
1985
+ sessionId: record.sessionId,
1986
+ turnId: event.turnId,
1987
+ }),
1885
1988
  });
1886
1989
  } catch (error) {
1887
1990
  this.logger(
@@ -1951,6 +2054,31 @@ export class SessionEngine {
1951
2054
  return (await this.listSessionsWithSource(caller, options)).sessions;
1952
2055
  }
1953
2056
 
2057
+ /**
2058
+ * Artifacts for `GET /v1/artifacts`, newest-updated first. Without
2059
+ * `includeAll`, the sessions-list ownership rule applies: only artifacts
2060
+ * tagged on a session whose principal matches the caller. Session-less
2061
+ * artifacts are agent-scoped and visible only with `includeAll`.
2062
+ */
2063
+ async listArtifacts(
2064
+ caller: AuthContext | null,
2065
+ options?: { includeAll?: boolean; filter?: ArtifactListFilter }
2066
+ ): Promise<ArtifactRecord[]> {
2067
+ const records = await this.artifactsStore.list(options?.filter);
2068
+ if (options?.includeAll === true) {
2069
+ return records;
2070
+ }
2071
+ const sessions = await this.sessions.list();
2072
+ const owned = new Set(
2073
+ sessions
2074
+ .filter((record) => samePrincipal(record.auth, caller))
2075
+ .map((record) => record.sessionId)
2076
+ );
2077
+ return records.filter(
2078
+ (record) => record.sessionId !== undefined && owned.has(record.sessionId)
2079
+ );
2080
+ }
2081
+
1954
2082
  /**
1955
2083
  * Same as {@link listSessions}, plus which store answered
1956
2084
  * (`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
+ });