@cursor/july 0.1.74 → 0.1.76

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 (140) hide show
  1. package/dist/channels/checks.d.ts +111 -0
  2. package/dist/channels/checks.d.ts.map +1 -0
  3. package/dist/channels/checks.js +86 -0
  4. package/dist/channels/deployments/deployments-channel.d.ts +44 -0
  5. package/dist/channels/deployments/deployments-channel.d.ts.map +1 -0
  6. package/dist/channels/deployments/deployments-channel.js +92 -0
  7. package/dist/channels/deployments/index.d.ts +26 -0
  8. package/dist/channels/deployments/index.d.ts.map +1 -0
  9. package/dist/channels/deployments/index.js +25 -0
  10. package/dist/channels/deployments/types.d.ts +69 -0
  11. package/dist/channels/deployments/types.d.ts.map +1 -0
  12. package/dist/channels/deployments/types.js +6 -0
  13. package/dist/channels/github/checks.d.ts +13 -48
  14. package/dist/channels/github/checks.d.ts.map +1 -1
  15. package/dist/channels/github/checks.js +56 -64
  16. package/dist/channels/origin/api.d.ts +100 -0
  17. package/dist/channels/origin/api.d.ts.map +1 -0
  18. package/dist/channels/origin/api.js +225 -0
  19. package/dist/channels/origin/binding.d.ts +44 -0
  20. package/dist/channels/origin/binding.d.ts.map +1 -0
  21. package/dist/channels/origin/binding.js +45 -0
  22. package/dist/channels/origin/checks.d.ts +107 -0
  23. package/dist/channels/origin/checks.d.ts.map +1 -0
  24. package/dist/channels/origin/checks.js +145 -0
  25. package/dist/channels/origin/index.d.ts +3 -0
  26. package/dist/channels/origin/index.d.ts.map +1 -1
  27. package/dist/channels/origin/index.js +3 -0
  28. package/dist/channels/origin/origin-channel.d.ts +4 -4
  29. package/dist/channels/origin/origin-channel.d.ts.map +1 -1
  30. package/dist/channels/origin/origin-channel.js +12 -2
  31. package/dist/channels/origin/types.d.ts +36 -0
  32. package/dist/channels/origin/types.d.ts.map +1 -1
  33. package/dist/channels.d.ts +1 -0
  34. package/dist/channels.d.ts.map +1 -1
  35. package/dist/channels.js +1 -0
  36. package/dist/docs/404.html +2 -2
  37. package/dist/docs/ab.html +3 -3
  38. package/dist/docs/assets/{app.BETd-WqU.js → app.b8bhB2SV.js} +1 -1
  39. package/dist/docs/assets/chunks/@localSearchIndexroot.DGZeXVqn.js +1 -0
  40. package/dist/docs/assets/chunks/{VPLocalSearchBox.wEaGEmV9.js → VPLocalSearchBox.lLSeIyWw.js} +1 -1
  41. package/dist/docs/assets/chunks/{theme.DNDicFOP.js → theme.C_owesa-.js} +2 -2
  42. package/dist/docs/assets/{reference_channels.md.MN8iDy8V.js → reference_channels.md.G5GysZ7e.js} +2 -2
  43. package/dist/docs/assets/{reference_channels.md.MN8iDy8V.lean.js → reference_channels.md.G5GysZ7e.lean.js} +1 -1
  44. package/dist/docs/building-with-agents.html +3 -3
  45. package/dist/docs/concepts.html +3 -3
  46. package/dist/docs/deployment.html +3 -3
  47. package/dist/docs/evals.html +3 -3
  48. package/dist/docs/example-agents/approval-buddy.html +3 -3
  49. package/dist/docs/example-agents/benny.html +3 -3
  50. package/dist/docs/example-agents/bugbot.html +3 -3
  51. package/dist/docs/example-agents/codebase-wiki.html +3 -3
  52. package/dist/docs/example-agents/codeowners-review.html +3 -3
  53. package/dist/docs/example-agents/concierge.html +3 -3
  54. package/dist/docs/example-agents/fsd.html +3 -3
  55. package/dist/docs/example-agents/index.html +3 -3
  56. package/dist/docs/example-agents/knowledge-base.html +3 -3
  57. package/dist/docs/example-agents/oncall.html +3 -3
  58. package/dist/docs/example-agents/security-reviewer.html +3 -3
  59. package/dist/docs/example-agents/slack-agent.html +3 -3
  60. package/dist/docs/example-agents/weather-agent.html +3 -3
  61. package/dist/docs/guides/agent-to-agent.html +3 -3
  62. package/dist/docs/guides/cloud-runtime.html +3 -3
  63. package/dist/docs/guides/convert-automation.html +3 -3
  64. package/dist/docs/guides/github.html +3 -3
  65. package/dist/docs/guides/human-in-the-loop.html +3 -3
  66. package/dist/docs/guides/mcp-oauth.html +3 -3
  67. package/dist/docs/guides/opentelemetry.html +3 -3
  68. package/dist/docs/guides/slack.html +3 -3
  69. package/dist/docs/guides/webhooks.html +3 -3
  70. package/dist/docs/hashmap.json +1 -1
  71. package/dist/docs/hillclimbing.html +3 -3
  72. package/dist/docs/index.html +3 -3
  73. package/dist/docs/quickstart.html +3 -3
  74. package/dist/docs/reference/agent-config.html +3 -3
  75. package/dist/docs/reference/artifacts.html +3 -3
  76. package/dist/docs/reference/channels.html +5 -5
  77. package/dist/docs/reference/cli.html +3 -3
  78. package/dist/docs/reference/connections.html +3 -3
  79. package/dist/docs/reference/hooks.html +3 -3
  80. package/dist/docs/reference/http-api.html +3 -3
  81. package/dist/docs/reference/instructions.html +3 -3
  82. package/dist/docs/reference/playground.html +3 -3
  83. package/dist/docs/reference/project-layout.html +3 -3
  84. package/dist/docs/reference/prompt.html +3 -3
  85. package/dist/docs/reference/schedules.html +3 -3
  86. package/dist/docs/reference/sessions.html +3 -3
  87. package/dist/docs/reference/skills.html +3 -3
  88. package/dist/docs/reference/subagents.html +3 -3
  89. package/dist/docs/reference/tools.html +3 -3
  90. package/dist/docs/scaffolding-agents.html +3 -3
  91. package/dist/docs/storage.html +3 -3
  92. package/dist/docs/templates/agentic-owners.html +3 -3
  93. package/dist/docs/templates/demo.html +3 -3
  94. package/dist/docs/templates/pr-autofixer.html +3 -3
  95. package/dist/docs/templates/security-reviewer.html +3 -3
  96. package/dist/docs/templates/triage.html +3 -3
  97. package/dist/docs/troubleshooting.html +3 -3
  98. package/dist/internal/authored-alias-hooks.d.ts +12 -0
  99. package/dist/internal/authored-alias-hooks.d.ts.map +1 -1
  100. package/dist/internal/authored-alias-hooks.js +60 -8
  101. package/dist/internal/authored-loaders.d.ts +5 -3
  102. package/dist/internal/authored-loaders.d.ts.map +1 -1
  103. package/dist/internal/authored-loaders.js +13 -4
  104. package/dist/internal/cursor-deployment-relay.d.ts +77 -0
  105. package/dist/internal/cursor-deployment-relay.d.ts.map +1 -0
  106. package/dist/internal/cursor-deployment-relay.js +201 -0
  107. package/dist/internal/deployment-scm-event-stream.js +4 -4
  108. package/dist/internal/distribution.d.ts.map +1 -1
  109. package/dist/internal/distribution.js +1 -0
  110. package/dist/internal/review-comments.d.ts +62 -0
  111. package/dist/internal/review-comments.d.ts.map +1 -1
  112. package/dist/internal/review-comments.js +199 -0
  113. package/dist/internal/server.d.ts.map +1 -1
  114. package/dist/internal/server.js +114 -5
  115. package/dist/playground/assets/{index-D_8I9TM0.js → index-BWqjJcRo.js} +1 -1
  116. package/dist/playground/assets/index-Bfwz2yLN.css +1 -0
  117. package/dist/playground/index.html +2 -2
  118. package/docs/reference/channels.md +15 -0
  119. package/package.json +7 -1
  120. package/src/channels/checks.ts +185 -0
  121. package/src/channels/deployments/deployments-channel.ts +109 -0
  122. package/src/channels/deployments/index.ts +26 -0
  123. package/src/channels/deployments/types.ts +80 -0
  124. package/src/channels/github/checks.ts +90 -115
  125. package/src/channels/origin/api.ts +318 -0
  126. package/src/channels/origin/binding.ts +96 -0
  127. package/src/channels/origin/checks.ts +250 -0
  128. package/src/channels/origin/index.ts +3 -0
  129. package/src/channels/origin/origin-channel.ts +18 -6
  130. package/src/channels/origin/types.ts +37 -0
  131. package/src/channels.ts +16 -0
  132. package/src/internal/authored-alias-hooks.ts +75 -7
  133. package/src/internal/authored-loaders.ts +15 -4
  134. package/src/internal/cursor-deployment-relay.ts +274 -0
  135. package/src/internal/deployment-scm-event-stream.ts +4 -4
  136. package/src/internal/distribution.ts +1 -0
  137. package/src/internal/review-comments.ts +286 -0
  138. package/src/internal/server.ts +149 -0
  139. package/dist/docs/assets/chunks/@localSearchIndexroot.DM5INS71.js +0 -1
  140. package/dist/playground/assets/index-M3nSMc6_.css +0 -1
@@ -1,16 +1,16 @@
1
1
  /**
2
- * Generic CI checks (GitHub Checks API) for agent authors.
2
+ * GitHub CI checks (Checks API) the GitHub {@link CiCheckWriter} behind the
3
+ * shared check lifecycle in `../checks.js`.
3
4
  *
4
- * `createGitHubCheck` opens a merge-box check run on a commit and returns a
5
- * handle for updating and concluding it, so an agent can report its own CI
6
- * result (name, summary, and a "Details" link e.g. the agent session run).
7
- * Works with any client exposing `getOctokit()` (`ctx.github`,
5
+ * `createGitHubCheck` opens a merge-box check run on a commit and returns the
6
+ * shared `CiCheck` handle; `resumeGitHubCheck` rebuilds one from a stored
7
+ * check-run id. Works with any client exposing `getOctokit()` (`ctx.github`,
8
8
  * `ctx.host.github`), and is also reachable as `ctx.github.createCheck(...)`.
9
9
  *
10
10
  * Posting checks needs `checks:write`. With `cursorAccount`, declare
11
11
  * `githubChannel({ checks: true })` so the hosted lease is minted on the
12
12
  * `contents-write` tier; GitHub App / PAT credentials need the equivalent
13
- * permission.
13
+ * permission. API failures are normalized into `GitHubApiError`.
14
14
  */
15
15
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
16
16
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
@@ -21,7 +21,53 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
21
21
  step((generator = generator.apply(thisArg, _arguments || [])).next());
22
22
  });
23
23
  };
24
- import { wrapOctokitError, } from "./api.js";
24
+ import { openCiCheck, resumeCiCheck, } from "../checks.js";
25
+ import { wrapOctokitError } from "./api.js";
26
+ /**
27
+ * GitHub writer: first write creates the check run (capturing its id), later
28
+ * writes patch it.
29
+ */
30
+ function githubCheckWriter(input) {
31
+ let checkRunId = input.checkRunId;
32
+ return (write) => __awaiter(this, void 0, void 0, function* () {
33
+ const octokit = yield input.github.getOctokit();
34
+ const base = {
35
+ owner: input.owner,
36
+ repo: input.repo,
37
+ name: input.name,
38
+ status: write.status,
39
+ conclusion: write.conclusion,
40
+ completed_at: write.completedAt,
41
+ details_url: write.detailsUrl,
42
+ output: write.output,
43
+ };
44
+ if (checkRunId === undefined) {
45
+ if (input.sha === undefined) {
46
+ throw new Error("githubChannel: cannot create a check without a sha.");
47
+ }
48
+ try {
49
+ const response = yield octokit.rest.checks.create(Object.assign(Object.assign({}, base), { head_sha: input.sha, started_at: write.startedAt }));
50
+ checkRunId = response.data.id;
51
+ return {
52
+ id: response.data.id,
53
+ url: typeof response.data.html_url === "string"
54
+ ? response.data.html_url
55
+ : undefined,
56
+ };
57
+ }
58
+ catch (error) {
59
+ throw wrapOctokitError(error, "POST", `/repos/${input.owner}/${input.repo}/check-runs`);
60
+ }
61
+ }
62
+ try {
63
+ yield octokit.rest.checks.update(Object.assign(Object.assign({}, base), { check_run_id: checkRunId }));
64
+ return undefined;
65
+ }
66
+ catch (error) {
67
+ throw wrapOctokitError(error, "PATCH", `/repos/${input.owner}/${input.repo}/check-runs/${checkRunId}`);
68
+ }
69
+ });
70
+ }
25
71
  /**
26
72
  * Create a CI check run on a commit and return a handle for later updates.
27
73
  *
@@ -40,69 +86,15 @@ import { wrapOctokitError, } from "./api.js";
40
86
  * ```
41
87
  */
42
88
  export function createGitHubCheck(input) {
43
- return __awaiter(this, void 0, void 0, function* () {
44
- var _a;
45
- const octokit = yield input.github.getOctokit();
46
- let created;
47
- try {
48
- const response = yield octokit.rest.checks.create({
49
- owner: input.owner,
50
- repo: input.repo,
51
- name: input.name,
52
- head_sha: input.sha,
53
- status: (_a = input.status) !== null && _a !== void 0 ? _a : "in_progress",
54
- started_at: new Date().toISOString(),
55
- details_url: input.detailsUrl,
56
- output: input.output,
57
- });
58
- created = response.data;
59
- }
60
- catch (error) {
61
- throw wrapOctokitError(error, "POST", `/repos/${input.owner}/${input.repo}/check-runs`);
62
- }
63
- return resumeGitHubCheck({
64
- github: input.github,
65
- owner: input.owner,
66
- repo: input.repo,
67
- name: input.name,
68
- checkRunId: created.id,
69
- url: typeof created.html_url === "string" ? created.html_url : undefined,
70
- });
71
- });
89
+ return openCiCheck(githubCheckWriter(input), input);
72
90
  }
73
91
  /**
74
92
  * Rebuild a {@link GitHubCheck} handle for an existing check run id (e.g.
75
93
  * after a process restart). No API call is made until the first update.
76
94
  */
77
95
  export function resumeGitHubCheck(input) {
78
- const patch = (update) => __awaiter(this, void 0, void 0, function* () {
79
- const octokit = yield input.github.getOctokit();
80
- try {
81
- yield octokit.rest.checks.update({
82
- owner: input.owner,
83
- repo: input.repo,
84
- check_run_id: input.checkRunId,
85
- name: input.name,
86
- status: update.status,
87
- conclusion: update.conclusion,
88
- completed_at: update.status === "completed" ? new Date().toISOString() : undefined,
89
- details_url: update.detailsUrl,
90
- output: update.output,
91
- });
92
- }
93
- catch (error) {
94
- throw wrapOctokitError(error, "PATCH", `/repos/${input.owner}/${input.repo}/check-runs/${input.checkRunId}`);
95
- }
96
- });
97
- return {
96
+ return resumeCiCheck(githubCheckWriter(input), {
98
97
  id: input.checkRunId,
99
98
  url: input.url,
100
- update: patch,
101
- conclude: (conclude) => patch({
102
- status: "completed",
103
- conclusion: conclude.conclusion,
104
- detailsUrl: conclude.detailsUrl,
105
- output: conclude.output,
106
- }),
107
- };
99
+ });
108
100
  }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Origin public REST helpers (`https://api.cursor.com/v1/origin/...`).
3
+ *
4
+ * Origin writes such as CI check runs are installation-only: they need an
5
+ * `oit_…` installation token minted from Origin app credentials (EdDSA app
6
+ * JWT → `/v1/origin/app/installations/{id}/access_tokens`). This module
7
+ * consolidates that flow so agents configure credentials once and call
8
+ * {@link createOriginClient} — the GitHub-channel analogue of
9
+ * `createGitHubOctokit`.
10
+ *
11
+ * Credentials resolve from options first, then the environment:
12
+ * `ORIGIN_APP_ID` (or `AGENT_SERVE_ORIGIN_APP_ID`),
13
+ * `ORIGIN_APP_INSTALLATION_ID`, `ORIGIN_APP_PRIVATE_KEY` (PKCS8 PEM for the
14
+ * app's Ed25519 key; literal `\n` sequences are normalized), and
15
+ * `ORIGIN_API_BASE_URL` for the public REST base.
16
+ */
17
+ /**
18
+ * Public Origin REST base (check runs, installation tokens). Distinct from
19
+ * the webhook JWKS base (`DEFAULT_ORIGIN_API_BASE_URL` in
20
+ * `origin-webhook.ts`).
21
+ */
22
+ export declare const DEFAULT_ORIGIN_PUBLIC_API_BASE_URL = "https://api.cursor.com";
23
+ export type OriginApiMethod = "DELETE" | "GET" | "PATCH" | "POST" | "PUT";
24
+ /** Normalized Origin REST failure — the `GitHubApiError` analogue. */
25
+ export declare class OriginApiError extends Error {
26
+ readonly body: unknown;
27
+ readonly method: string;
28
+ readonly path: string;
29
+ readonly status: number;
30
+ constructor(input: {
31
+ body: unknown;
32
+ method: string;
33
+ path: string;
34
+ status: number;
35
+ });
36
+ }
37
+ /** Yields a bearer for Origin REST calls (usually a short-lived `oit_…`). */
38
+ export type OriginTokenProvider = () => Promise<string>;
39
+ export interface OriginAppCredentials {
40
+ /** Origin app id (`app_<typeid>`). */
41
+ appId: string;
42
+ /** Installation the token is minted for. */
43
+ installationId: string;
44
+ /** PKCS8 PEM for the app's EdDSA (Ed25519) private key. */
45
+ privateKey: string;
46
+ }
47
+ /** Each Origin app credential field found in the environment, when set. */
48
+ export declare function resolveOriginAppCredentialParts(env?: NodeJS.ProcessEnv): Partial<OriginAppCredentials>;
49
+ /**
50
+ * Read Origin app credentials from the environment. Returns `undefined` when
51
+ * incomplete so callers can fail with a clear message at use time instead of
52
+ * at startup.
53
+ */
54
+ export declare function resolveOriginAppCredentials(env?: NodeJS.ProcessEnv): OriginAppCredentials | undefined;
55
+ /** Public Origin REST base. Trailing slashes are stripped for path joins. */
56
+ export declare function originPublicApiBaseUrl(env?: NodeJS.ProcessEnv): string;
57
+ /**
58
+ * A cached per-use token provider for one set of app credentials. Every call
59
+ * inside the reuse window returns the same `oit_…`; the first call after it
60
+ * re-mints.
61
+ */
62
+ export declare function originAppTokenProvider(input: {
63
+ credentials: OriginAppCredentials;
64
+ apiBaseUrl?: string;
65
+ fetch?: typeof fetch;
66
+ now?: () => number;
67
+ }): OriginTokenProvider;
68
+ export interface OriginClientOptions {
69
+ /** Static bearer (`oit_…`) or refreshing provider used for every call. */
70
+ token?: string | OriginTokenProvider;
71
+ /**
72
+ * App credentials to mint installation tokens from. Defaults to the
73
+ * environment ({@link resolveOriginAppCredentials}).
74
+ */
75
+ credentials?: OriginAppCredentials;
76
+ /** Public Origin REST base. Defaults to `ORIGIN_API_BASE_URL` / prod. */
77
+ apiBaseUrl?: string;
78
+ /** Injectable fetch for tests. */
79
+ fetch?: typeof fetch;
80
+ }
81
+ /** Minimal authenticated Origin REST client (the `Octokit` analogue). */
82
+ export interface OriginClient {
83
+ readonly apiBaseUrl: string;
84
+ /**
85
+ * Call an Origin public REST path (e.g. `/v1/origin/repos/o/r/check-runs`).
86
+ * Throws {@link OriginApiError} on non-2xx responses.
87
+ */
88
+ request<T = unknown>(input: {
89
+ method: OriginApiMethod;
90
+ path: string;
91
+ body?: unknown;
92
+ }): Promise<T>;
93
+ }
94
+ /**
95
+ * Build an authenticated Origin REST client. Auth resolution: explicit
96
+ * token/provider, then app credentials (options or environment). Missing
97
+ * auth fails at the first request with a clear message.
98
+ */
99
+ export declare function createOriginClient(options?: OriginClientOptions): OriginClient;
100
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/channels/origin/api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,2BAA2B,CAAC;AAS3E,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAE1E,sEAAsE;AACtE,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,YAAY,KAAK,EAAE;QACjB,IAAI,EAAE,OAAO,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;KAChB,EASA;CACF;AAED,6EAA6E;AAC7E,MAAM,MAAM,mBAAmB,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;AAExD,MAAM,WAAW,oBAAoB;IACnC,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,cAAc,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;CACpB;AAaD,2EAA2E;AAC3E,wBAAgB,+BAA+B,CAC7C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,oBAAoB,CAAC,CAO/B;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,oBAAoB,GAAG,SAAS,CAWlC;AAED,6EAA6E;AAC7E,wBAAgB,sBAAsB,CACpC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAGR;AA8DD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE;IAC5C,WAAW,EAAE,oBAAoB,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB,GAAG,mBAAmB,CAmBtB;AAED,MAAM,WAAW,mBAAmB;IAClC,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAAC;IACrC;;;OAGG;IACH,WAAW,CAAC,EAAE,oBAAoB,CAAC;IACnC,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,yEAAyE;AACzE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE;QAC1B,MAAM,EAAE,eAAe,CAAC;QACxB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,GAAE,mBAAwB,GAChC,YAAY,CAoEd"}
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Origin public REST helpers (`https://api.cursor.com/v1/origin/...`).
3
+ *
4
+ * Origin writes such as CI check runs are installation-only: they need an
5
+ * `oit_…` installation token minted from Origin app credentials (EdDSA app
6
+ * JWT → `/v1/origin/app/installations/{id}/access_tokens`). This module
7
+ * consolidates that flow so agents configure credentials once and call
8
+ * {@link createOriginClient} — the GitHub-channel analogue of
9
+ * `createGitHubOctokit`.
10
+ *
11
+ * Credentials resolve from options first, then the environment:
12
+ * `ORIGIN_APP_ID` (or `AGENT_SERVE_ORIGIN_APP_ID`),
13
+ * `ORIGIN_APP_INSTALLATION_ID`, `ORIGIN_APP_PRIVATE_KEY` (PKCS8 PEM for the
14
+ * app's Ed25519 key; literal `\n` sequences are normalized), and
15
+ * `ORIGIN_API_BASE_URL` for the public REST base.
16
+ */
17
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
18
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
19
+ return new (P || (P = Promise))(function (resolve, reject) {
20
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
21
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
22
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
23
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
24
+ });
25
+ };
26
+ import { Buffer } from "node:buffer";
27
+ import { createPrivateKey, sign } from "node:crypto";
28
+ /**
29
+ * Public Origin REST base (check runs, installation tokens). Distinct from
30
+ * the webhook JWKS base (`DEFAULT_ORIGIN_API_BASE_URL` in
31
+ * `origin-webhook.ts`).
32
+ */
33
+ export const DEFAULT_ORIGIN_PUBLIC_API_BASE_URL = "https://api.cursor.com";
34
+ /** Fixed audience for Origin app JWTs (`APP_TOKEN_AUDIENCE` backend-side). */
35
+ const ORIGIN_APP_TOKEN_AUDIENCE = "origin-apps";
36
+ const APP_JWT_TTL_SECONDS = 5 * 60;
37
+ /** Re-mint the `oit_` token after this long; tokens outlive it comfortably. */
38
+ const TOKEN_REUSE_MS = 4 * 60 * 1000;
39
+ const TOKEN_EXCHANGE_TIMEOUT_MS = 30000;
40
+ /** Normalized Origin REST failure — the `GitHubApiError` analogue. */
41
+ export class OriginApiError extends Error {
42
+ constructor(input) {
43
+ super(`Origin ${input.method} ${input.path} failed with HTTP ${input.status}.`);
44
+ this.name = "OriginApiError";
45
+ this.body = input.body;
46
+ this.method = input.method;
47
+ this.path = input.path;
48
+ this.status = input.status;
49
+ }
50
+ }
51
+ /** Vault/env round-trip: literal `\n` sequences appear in practice. */
52
+ function normalizePrivateKeyPem(raw) {
53
+ const pem = raw === null || raw === void 0 ? void 0 : raw.trim().replace(/\\n/g, "\n");
54
+ return pem === undefined || pem === "" ? undefined : pem;
55
+ }
56
+ function envValue(value) {
57
+ const trimmed = value === null || value === void 0 ? void 0 : value.trim();
58
+ return trimmed === undefined || trimmed === "" ? undefined : trimmed;
59
+ }
60
+ /** Each Origin app credential field found in the environment, when set. */
61
+ export function resolveOriginAppCredentialParts(env = process.env) {
62
+ var _a;
63
+ return {
64
+ appId: (_a = envValue(env.ORIGIN_APP_ID)) !== null && _a !== void 0 ? _a : envValue(env.AGENT_SERVE_ORIGIN_APP_ID),
65
+ installationId: envValue(env.ORIGIN_APP_INSTALLATION_ID),
66
+ privateKey: normalizePrivateKeyPem(env.ORIGIN_APP_PRIVATE_KEY),
67
+ };
68
+ }
69
+ /**
70
+ * Read Origin app credentials from the environment. Returns `undefined` when
71
+ * incomplete so callers can fail with a clear message at use time instead of
72
+ * at startup.
73
+ */
74
+ export function resolveOriginAppCredentials(env = process.env) {
75
+ const { appId, installationId, privateKey } = resolveOriginAppCredentialParts(env);
76
+ if (appId === undefined ||
77
+ installationId === undefined ||
78
+ privateKey === undefined) {
79
+ return undefined;
80
+ }
81
+ return { appId, installationId, privateKey };
82
+ }
83
+ /** Public Origin REST base. Trailing slashes are stripped for path joins. */
84
+ export function originPublicApiBaseUrl(env = process.env) {
85
+ var _a;
86
+ const fromEnv = (_a = envValue(env.ORIGIN_API_BASE_URL)) === null || _a === void 0 ? void 0 : _a.replace(/\/+$/, "");
87
+ return fromEnv !== null && fromEnv !== void 0 ? fromEnv : DEFAULT_ORIGIN_PUBLIC_API_BASE_URL;
88
+ }
89
+ function base64UrlJson(value) {
90
+ return Buffer.from(JSON.stringify(value)).toString("base64url");
91
+ }
92
+ function mintOriginAppJwt(credentials, nowMs) {
93
+ const now = Math.floor(nowMs / 1000);
94
+ const header = base64UrlJson({
95
+ alg: "EdDSA",
96
+ kid: credentials.appId,
97
+ typ: "JWT",
98
+ });
99
+ const payload = base64UrlJson({
100
+ iss: credentials.appId,
101
+ aud: ORIGIN_APP_TOKEN_AUDIENCE,
102
+ iat: now,
103
+ exp: now + APP_JWT_TTL_SECONDS,
104
+ });
105
+ const signingInput = `${header}.${payload}`;
106
+ const key = createPrivateKey(credentials.privateKey);
107
+ const signature = sign(null, Buffer.from(signingInput), key).toString("base64url");
108
+ return `${signingInput}.${signature}`;
109
+ }
110
+ function mintOriginInstallationToken(input) {
111
+ return __awaiter(this, void 0, void 0, function* () {
112
+ const jwt = mintOriginAppJwt(input.credentials, input.nowMs);
113
+ const path = `/v1/origin/app/installations/${encodeURIComponent(input.credentials.installationId)}/access_tokens`;
114
+ const response = yield input.fetchImpl(`${input.apiBaseUrl}${path}`, {
115
+ method: "POST",
116
+ headers: { authorization: `Bearer ${jwt}` },
117
+ signal: AbortSignal.timeout(TOKEN_EXCHANGE_TIMEOUT_MS),
118
+ });
119
+ const body = yield response.json().catch(() => undefined);
120
+ const token = typeof body === "object" && body !== null && !Array.isArray(body)
121
+ ? body.token
122
+ : undefined;
123
+ if (!response.ok || typeof token !== "string" || token === "") {
124
+ // Never echo the body: on success it contains the installation token.
125
+ throw new OriginApiError({
126
+ body: undefined,
127
+ method: "POST",
128
+ path,
129
+ status: response.status,
130
+ });
131
+ }
132
+ return token;
133
+ });
134
+ }
135
+ /**
136
+ * A cached per-use token provider for one set of app credentials. Every call
137
+ * inside the reuse window returns the same `oit_…`; the first call after it
138
+ * re-mints.
139
+ */
140
+ export function originAppTokenProvider(input) {
141
+ var _a, _b, _c;
142
+ const apiBaseUrl = (_a = input.apiBaseUrl) !== null && _a !== void 0 ? _a : originPublicApiBaseUrl();
143
+ const fetchImpl = (_b = input.fetch) !== null && _b !== void 0 ? _b : fetch;
144
+ const now = (_c = input.now) !== null && _c !== void 0 ? _c : Date.now;
145
+ let cached;
146
+ return () => __awaiter(this, void 0, void 0, function* () {
147
+ const nowMs = now();
148
+ if (cached !== undefined && nowMs - cached.mintedAtMs < TOKEN_REUSE_MS) {
149
+ return cached.token;
150
+ }
151
+ const token = yield mintOriginInstallationToken({
152
+ credentials: input.credentials,
153
+ apiBaseUrl,
154
+ fetchImpl,
155
+ nowMs,
156
+ });
157
+ cached = { token, mintedAtMs: nowMs };
158
+ return token;
159
+ });
160
+ }
161
+ /**
162
+ * Build an authenticated Origin REST client. Auth resolution: explicit
163
+ * token/provider, then app credentials (options or environment). Missing
164
+ * auth fails at the first request with a clear message.
165
+ */
166
+ export function createOriginClient(options = {}) {
167
+ var _a, _b;
168
+ const apiBaseUrl = ((_a = options.apiBaseUrl) !== null && _a !== void 0 ? _a : originPublicApiBaseUrl()).replace(/\/+$/, "");
169
+ const fetchImpl = (_b = options.fetch) !== null && _b !== void 0 ? _b : fetch;
170
+ let tokenProvider;
171
+ const getToken = () => __awaiter(this, void 0, void 0, function* () {
172
+ var _a;
173
+ if (typeof options.token === "string") {
174
+ return options.token;
175
+ }
176
+ if (typeof options.token === "function") {
177
+ return yield options.token();
178
+ }
179
+ if (tokenProvider === undefined) {
180
+ const credentials = (_a = options.credentials) !== null && _a !== void 0 ? _a : resolveOriginAppCredentials();
181
+ if (credentials === undefined) {
182
+ throw new Error("originClient: no Origin credential available (pass token / credentials, or set ORIGIN_APP_ID + ORIGIN_APP_INSTALLATION_ID + ORIGIN_APP_PRIVATE_KEY).");
183
+ }
184
+ tokenProvider = originAppTokenProvider({
185
+ credentials,
186
+ apiBaseUrl,
187
+ fetch: fetchImpl,
188
+ });
189
+ }
190
+ return yield tokenProvider();
191
+ });
192
+ return {
193
+ apiBaseUrl,
194
+ request(input) {
195
+ return __awaiter(this, void 0, void 0, function* () {
196
+ const path = input.path.startsWith("/") ? input.path : `/${input.path}`;
197
+ const token = yield getToken();
198
+ const response = yield fetchImpl(`${apiBaseUrl}${path}`, {
199
+ method: input.method,
200
+ headers: Object.assign({ authorization: `Bearer ${token}` }, (input.body === undefined
201
+ ? {}
202
+ : { "content-type": "application/json" })),
203
+ body: input.body === undefined ? undefined : JSON.stringify(input.body),
204
+ });
205
+ const text = yield response.text();
206
+ let parsed;
207
+ try {
208
+ parsed = text === "" ? undefined : JSON.parse(text);
209
+ }
210
+ catch (_a) {
211
+ parsed = text;
212
+ }
213
+ if (!response.ok) {
214
+ throw new OriginApiError({
215
+ body: parsed,
216
+ method: input.method,
217
+ path,
218
+ status: response.status,
219
+ });
220
+ }
221
+ return parsed;
222
+ });
223
+ },
224
+ };
225
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Rebuild the Origin API handle (`ctx.origin`) for inbound hooks.
3
+ *
4
+ * The handle is repo-bound and lazy: no credential is resolved until the
5
+ * first call, so channels without outbound Origin credentials still dispatch
6
+ * normally. Credential resolution combines the channel's `app` option with
7
+ * the environment (`ORIGIN_APP_ID` / `ORIGIN_APP_INSTALLATION_ID` /
8
+ * `ORIGIN_APP_PRIVATE_KEY`); the delivery's installation id fills in when
9
+ * neither pins one — the GitHub webhook `installation.id` analogue.
10
+ */
11
+ import { type OriginApiMethod } from "./api.js";
12
+ import { type OriginCheck, type OriginCheckCreateInput } from "./checks.js";
13
+ import type { OriginAppOptions, OriginRepositoryRef } from "./types.js";
14
+ /** Origin operations exposed to hooks (`ctx.origin`). */
15
+ export interface OriginHandle {
16
+ /** Installation id the outbound credential is minted for, when known. */
17
+ installationId: string | undefined;
18
+ repository: OriginRepositoryRef;
19
+ /**
20
+ * Call an Origin public REST path with the channel's app credential.
21
+ * Throws `OriginApiError` on API failure.
22
+ */
23
+ request<T = unknown>(input: {
24
+ method: OriginApiMethod;
25
+ path: string;
26
+ body?: unknown;
27
+ }): Promise<T>;
28
+ /**
29
+ * Open a CI check run on `sha` and get a handle for updating and
30
+ * concluding it. Needs an app installation with
31
+ * `repository:checks:write` — Origin check writes are installation-only.
32
+ */
33
+ createCheck(input: Omit<OriginCheckCreateInput, "origin" | "owner" | "repo">): Promise<OriginCheck>;
34
+ }
35
+ export declare function buildOriginBinding(input: {
36
+ repository: OriginRepositoryRef;
37
+ /** Installation id from the delivery envelope, when present. */
38
+ installationId?: string;
39
+ /** Channel-authored outbound app credentials / API base. */
40
+ app?: OriginAppOptions;
41
+ /** Injectable fetch for tests. */
42
+ fetch?: typeof fetch;
43
+ }): OriginHandle;
44
+ //# sourceMappingURL=binding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../../src/channels/origin/binding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAEL,KAAK,eAAe,EAGrB,MAAM,UAAU,CAAC;AAClB,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAC5B,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAExE,yDAAyD;AACzD,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,UAAU,EAAE,mBAAmB,CAAC;IAChC;;;OAGG;IACH,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE;QAC1B,MAAM,EAAE,eAAe,CAAC;QACxB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACf;;;;OAIG;IACH,WAAW,CACT,KAAK,EAAE,IAAI,CAAC,sBAAsB,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC,GAC/D,OAAO,CAAC,WAAW,CAAC,CAAC;CACzB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,UAAU,EAAE,mBAAmB,CAAC;IAChC,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4DAA4D;IAC5D,GAAG,CAAC,EAAE,gBAAgB,CAAC;IACvB,kCAAkC;IAClC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB,GAAG,YAAY,CAuCf"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Rebuild the Origin API handle (`ctx.origin`) for inbound hooks.
3
+ *
4
+ * The handle is repo-bound and lazy: no credential is resolved until the
5
+ * first call, so channels without outbound Origin credentials still dispatch
6
+ * normally. Credential resolution combines the channel's `app` option with
7
+ * the environment (`ORIGIN_APP_ID` / `ORIGIN_APP_INSTALLATION_ID` /
8
+ * `ORIGIN_APP_PRIVATE_KEY`); the delivery's installation id fills in when
9
+ * neither pins one — the GitHub webhook `installation.id` analogue.
10
+ */
11
+ import { createOriginClient, resolveOriginAppCredentialParts, } from "./api.js";
12
+ import { createOriginCheck, } from "./checks.js";
13
+ export function buildOriginBinding(input) {
14
+ var _a;
15
+ var _b;
16
+ let client;
17
+ const getClient = () => {
18
+ var _a, _b, _c, _d, _e;
19
+ var _f, _g, _h, _j;
20
+ if (client === undefined) {
21
+ const fromEnv = resolveOriginAppCredentialParts();
22
+ const appId = (_f = (_a = input.app) === null || _a === void 0 ? void 0 : _a.appId) !== null && _f !== void 0 ? _f : fromEnv.appId;
23
+ const installationId = (_h = (_g = (_b = input.app) === null || _b === void 0 ? void 0 : _b.installationId) !== null && _g !== void 0 ? _g : input.installationId) !== null && _h !== void 0 ? _h : fromEnv.installationId;
24
+ const privateKey = (_j = (_c = input.app) === null || _c === void 0 ? void 0 : _c.privateKey) !== null && _j !== void 0 ? _j : fromEnv.privateKey;
25
+ const credentials = appId !== undefined &&
26
+ installationId !== undefined &&
27
+ privateKey !== undefined
28
+ ? { appId, installationId, privateKey }
29
+ : undefined;
30
+ client = createOriginClient({
31
+ token: (_d = input.app) === null || _d === void 0 ? void 0 : _d.token,
32
+ credentials,
33
+ apiBaseUrl: (_e = input.app) === null || _e === void 0 ? void 0 : _e.apiBaseUrl,
34
+ fetch: input.fetch,
35
+ });
36
+ }
37
+ return client;
38
+ };
39
+ return {
40
+ installationId: (_b = (_a = input.app) === null || _a === void 0 ? void 0 : _a.installationId) !== null && _b !== void 0 ? _b : input.installationId,
41
+ repository: input.repository,
42
+ request: (request) => getClient().request(request),
43
+ createCheck: (check) => createOriginCheck(Object.assign(Object.assign({}, check), { origin: getClient(), owner: input.repository.owner, repo: input.repository.name })),
44
+ };
45
+ }