@cursor/july 0.1.73 → 0.1.75

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 (159) hide show
  1. package/AGENTS.md +13 -8
  2. package/dist/bin/agent-serve.js +7 -5
  3. package/dist/channels/checks.d.ts +111 -0
  4. package/dist/channels/checks.d.ts.map +1 -0
  5. package/dist/channels/checks.js +86 -0
  6. package/dist/channels/deployments/deployments-channel.d.ts +44 -0
  7. package/dist/channels/deployments/deployments-channel.d.ts.map +1 -0
  8. package/dist/channels/deployments/deployments-channel.js +92 -0
  9. package/dist/channels/deployments/index.d.ts +26 -0
  10. package/dist/channels/deployments/index.d.ts.map +1 -0
  11. package/dist/channels/deployments/index.js +25 -0
  12. package/dist/channels/deployments/types.d.ts +69 -0
  13. package/dist/channels/deployments/types.d.ts.map +1 -0
  14. package/dist/channels/deployments/types.js +6 -0
  15. package/dist/channels/github/checks.d.ts +13 -48
  16. package/dist/channels/github/checks.d.ts.map +1 -1
  17. package/dist/channels/github/checks.js +56 -64
  18. package/dist/channels/origin/api.d.ts +100 -0
  19. package/dist/channels/origin/api.d.ts.map +1 -0
  20. package/dist/channels/origin/api.js +225 -0
  21. package/dist/channels/origin/binding.d.ts +44 -0
  22. package/dist/channels/origin/binding.d.ts.map +1 -0
  23. package/dist/channels/origin/binding.js +45 -0
  24. package/dist/channels/origin/checks.d.ts +107 -0
  25. package/dist/channels/origin/checks.d.ts.map +1 -0
  26. package/dist/channels/origin/checks.js +145 -0
  27. package/dist/channels/origin/index.d.ts +3 -0
  28. package/dist/channels/origin/index.d.ts.map +1 -1
  29. package/dist/channels/origin/index.js +3 -0
  30. package/dist/channels/origin/origin-channel.d.ts +4 -4
  31. package/dist/channels/origin/origin-channel.d.ts.map +1 -1
  32. package/dist/channels/origin/origin-channel.js +12 -2
  33. package/dist/channels/origin/types.d.ts +36 -0
  34. package/dist/channels/origin/types.d.ts.map +1 -1
  35. package/dist/channels.d.ts +1 -0
  36. package/dist/channels.d.ts.map +1 -1
  37. package/dist/channels.js +1 -0
  38. package/dist/docs/404.html +2 -2
  39. package/dist/docs/ab.html +3 -3
  40. package/dist/docs/assets/{app.CdbcFD8T.js → app.b8bhB2SV.js} +1 -1
  41. package/dist/docs/assets/chunks/@localSearchIndexroot.DGZeXVqn.js +1 -0
  42. package/dist/docs/assets/chunks/{VPLocalSearchBox.D_NKImM7.js → VPLocalSearchBox.lLSeIyWw.js} +1 -1
  43. package/dist/docs/assets/chunks/{theme.CMvz7cu9.js → theme.C_owesa-.js} +2 -2
  44. package/dist/docs/assets/{reference_channels.md.MN8iDy8V.js → reference_channels.md.G5GysZ7e.js} +2 -2
  45. package/dist/docs/assets/{reference_channels.md.MN8iDy8V.lean.js → reference_channels.md.G5GysZ7e.lean.js} +1 -1
  46. package/dist/docs/assets/{reference_cli.md.Cl14Jfo3.js → reference_cli.md.TAaYU8br.js} +3 -3
  47. package/dist/docs/assets/{reference_cli.md.Cl14Jfo3.lean.js → reference_cli.md.TAaYU8br.lean.js} +1 -1
  48. package/dist/docs/assets/scaffolding-agents.md.CiGsJ1aw.js +1 -0
  49. package/dist/docs/assets/{scaffolding-agents.md.CrWSA0Ko.lean.js → scaffolding-agents.md.CiGsJ1aw.lean.js} +1 -1
  50. package/dist/docs/building-with-agents.html +3 -3
  51. package/dist/docs/concepts.html +3 -3
  52. package/dist/docs/deployment.html +3 -3
  53. package/dist/docs/evals.html +3 -3
  54. package/dist/docs/example-agents/approval-buddy.html +3 -3
  55. package/dist/docs/example-agents/benny.html +3 -3
  56. package/dist/docs/example-agents/bugbot.html +3 -3
  57. package/dist/docs/example-agents/codebase-wiki.html +3 -3
  58. package/dist/docs/example-agents/codeowners-review.html +3 -3
  59. package/dist/docs/example-agents/concierge.html +3 -3
  60. package/dist/docs/example-agents/fsd.html +3 -3
  61. package/dist/docs/example-agents/index.html +3 -3
  62. package/dist/docs/example-agents/knowledge-base.html +3 -3
  63. package/dist/docs/example-agents/oncall.html +3 -3
  64. package/dist/docs/example-agents/security-reviewer.html +3 -3
  65. package/dist/docs/example-agents/slack-agent.html +3 -3
  66. package/dist/docs/example-agents/weather-agent.html +3 -3
  67. package/dist/docs/guides/agent-to-agent.html +3 -3
  68. package/dist/docs/guides/cloud-runtime.html +3 -3
  69. package/dist/docs/guides/convert-automation.html +3 -3
  70. package/dist/docs/guides/github.html +3 -3
  71. package/dist/docs/guides/human-in-the-loop.html +3 -3
  72. package/dist/docs/guides/mcp-oauth.html +3 -3
  73. package/dist/docs/guides/opentelemetry.html +3 -3
  74. package/dist/docs/guides/slack.html +3 -3
  75. package/dist/docs/guides/webhooks.html +3 -3
  76. package/dist/docs/hashmap.json +1 -1
  77. package/dist/docs/hillclimbing.html +3 -3
  78. package/dist/docs/index.html +3 -3
  79. package/dist/docs/quickstart.html +3 -3
  80. package/dist/docs/reference/agent-config.html +3 -3
  81. package/dist/docs/reference/artifacts.html +3 -3
  82. package/dist/docs/reference/channels.html +5 -5
  83. package/dist/docs/reference/cli.html +6 -6
  84. package/dist/docs/reference/connections.html +3 -3
  85. package/dist/docs/reference/hooks.html +3 -3
  86. package/dist/docs/reference/http-api.html +3 -3
  87. package/dist/docs/reference/instructions.html +3 -3
  88. package/dist/docs/reference/playground.html +3 -3
  89. package/dist/docs/reference/project-layout.html +3 -3
  90. package/dist/docs/reference/prompt.html +3 -3
  91. package/dist/docs/reference/schedules.html +3 -3
  92. package/dist/docs/reference/sessions.html +3 -3
  93. package/dist/docs/reference/skills.html +3 -3
  94. package/dist/docs/reference/subagents.html +3 -3
  95. package/dist/docs/reference/tools.html +3 -3
  96. package/dist/docs/scaffolding-agents.html +5 -5
  97. package/dist/docs/storage.html +3 -3
  98. package/dist/docs/templates/agentic-owners.html +3 -3
  99. package/dist/docs/templates/demo.html +3 -3
  100. package/dist/docs/templates/pr-autofixer.html +3 -3
  101. package/dist/docs/templates/security-reviewer.html +3 -3
  102. package/dist/docs/templates/triage.html +3 -3
  103. package/dist/docs/troubleshooting.html +3 -3
  104. package/dist/internal/cli-skills.d.ts +4 -2
  105. package/dist/internal/cli-skills.d.ts.map +1 -1
  106. package/dist/internal/cli-skills.js +8 -3
  107. package/dist/internal/cursor-deployment-relay.d.ts +77 -0
  108. package/dist/internal/cursor-deployment-relay.d.ts.map +1 -0
  109. package/dist/internal/cursor-deployment-relay.js +201 -0
  110. package/dist/internal/distribution.d.ts.map +1 -1
  111. package/dist/internal/distribution.js +1 -0
  112. package/dist/internal/install-cursor-skills.d.ts +71 -16
  113. package/dist/internal/install-cursor-skills.d.ts.map +1 -1
  114. package/dist/internal/install-cursor-skills.js +160 -48
  115. package/dist/internal/sdk-runner.d.ts.map +1 -1
  116. package/dist/internal/sdk-runner.js +6 -2
  117. package/dist/internal/server.d.ts.map +1 -1
  118. package/dist/internal/server.js +114 -5
  119. package/dist/playground/assets/index-BJy9UJrF.js +85 -0
  120. package/dist/playground/assets/index-BrSd5vff.css +1 -0
  121. package/dist/playground/index.html +2 -2
  122. package/docs/reference/channels.md +15 -0
  123. package/docs/reference/cli.md +16 -8
  124. package/docs/scaffolding-agents.md +14 -6
  125. package/package.json +9 -1
  126. package/scripts/install-cursor-skills.mjs +36 -0
  127. package/skills/ab/SKILL.md +1 -1
  128. package/skills/create-agent/SKILL.md +1 -1
  129. package/skills/debug/SKILL.md +1 -1
  130. package/skills/evals/SKILL.md +1 -1
  131. package/skills/framework-map/SKILL.md +1 -1
  132. package/skills/github/SKILL.md +1 -1
  133. package/skills/hillclimb/SKILL.md +1 -1
  134. package/skills/mcp-auth/SKILL.md +1 -1
  135. package/skills/otel/SKILL.md +1 -1
  136. package/skills/setup-slack/SKILL.md +1 -1
  137. package/src/bin/agent-serve.ts +7 -5
  138. package/src/channels/checks.ts +185 -0
  139. package/src/channels/deployments/deployments-channel.ts +109 -0
  140. package/src/channels/deployments/index.ts +26 -0
  141. package/src/channels/deployments/types.ts +80 -0
  142. package/src/channels/github/checks.ts +90 -115
  143. package/src/channels/origin/api.ts +318 -0
  144. package/src/channels/origin/binding.ts +96 -0
  145. package/src/channels/origin/checks.ts +250 -0
  146. package/src/channels/origin/index.ts +3 -0
  147. package/src/channels/origin/origin-channel.ts +18 -6
  148. package/src/channels/origin/types.ts +37 -0
  149. package/src/channels.ts +16 -0
  150. package/src/internal/cli-skills.ts +10 -2
  151. package/src/internal/cursor-deployment-relay.ts +274 -0
  152. package/src/internal/distribution.ts +1 -0
  153. package/src/internal/install-cursor-skills.ts +204 -49
  154. package/src/internal/sdk-runner.ts +6 -3
  155. package/src/internal/server.ts +149 -0
  156. package/dist/docs/assets/chunks/@localSearchIndexroot.DQad--_z.js +0 -1
  157. package/dist/docs/assets/scaffolding-agents.md.CrWSA0Ko.js +0 -1
  158. package/dist/playground/assets/index-77uhu5Kr.css +0 -1
  159. package/dist/playground/assets/index-D4buox4m.js +0 -85
@@ -0,0 +1,96 @@
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
+
12
+ import {
13
+ createOriginClient,
14
+ type OriginApiMethod,
15
+ type OriginClient,
16
+ resolveOriginAppCredentialParts,
17
+ } from "./api.js";
18
+ import {
19
+ createOriginCheck,
20
+ type OriginCheck,
21
+ type OriginCheckCreateInput,
22
+ } from "./checks.js";
23
+ import type { OriginAppOptions, OriginRepositoryRef } from "./types.js";
24
+
25
+ /** Origin operations exposed to hooks (`ctx.origin`). */
26
+ export interface OriginHandle {
27
+ /** Installation id the outbound credential is minted for, when known. */
28
+ installationId: string | undefined;
29
+ repository: OriginRepositoryRef;
30
+ /**
31
+ * Call an Origin public REST path with the channel's app credential.
32
+ * Throws `OriginApiError` on API failure.
33
+ */
34
+ request<T = unknown>(input: {
35
+ method: OriginApiMethod;
36
+ path: string;
37
+ body?: unknown;
38
+ }): Promise<T>;
39
+ /**
40
+ * Open a CI check run on `sha` and get a handle for updating and
41
+ * concluding it. Needs an app installation with
42
+ * `repository:checks:write` — Origin check writes are installation-only.
43
+ */
44
+ createCheck(
45
+ input: Omit<OriginCheckCreateInput, "origin" | "owner" | "repo">
46
+ ): Promise<OriginCheck>;
47
+ }
48
+
49
+ export function buildOriginBinding(input: {
50
+ repository: OriginRepositoryRef;
51
+ /** Installation id from the delivery envelope, when present. */
52
+ installationId?: string;
53
+ /** Channel-authored outbound app credentials / API base. */
54
+ app?: OriginAppOptions;
55
+ /** Injectable fetch for tests. */
56
+ fetch?: typeof fetch;
57
+ }): OriginHandle {
58
+ let client: OriginClient | undefined;
59
+ const getClient = (): OriginClient => {
60
+ if (client === undefined) {
61
+ const fromEnv = resolveOriginAppCredentialParts();
62
+ const appId = input.app?.appId ?? fromEnv.appId;
63
+ const installationId =
64
+ input.app?.installationId ??
65
+ input.installationId ??
66
+ fromEnv.installationId;
67
+ const privateKey = input.app?.privateKey ?? fromEnv.privateKey;
68
+ const credentials =
69
+ appId !== undefined &&
70
+ installationId !== undefined &&
71
+ privateKey !== undefined
72
+ ? { appId, installationId, privateKey }
73
+ : undefined;
74
+ client = createOriginClient({
75
+ token: input.app?.token,
76
+ credentials,
77
+ apiBaseUrl: input.app?.apiBaseUrl,
78
+ fetch: input.fetch,
79
+ });
80
+ }
81
+ return client;
82
+ };
83
+
84
+ return {
85
+ installationId: input.app?.installationId ?? input.installationId,
86
+ repository: input.repository,
87
+ request: (request) => getClient().request(request),
88
+ createCheck: (check) =>
89
+ createOriginCheck({
90
+ ...check,
91
+ origin: getClient(),
92
+ owner: input.repository.owner,
93
+ repo: input.repository.name,
94
+ }),
95
+ };
96
+ }
@@ -0,0 +1,250 @@
1
+ /**
2
+ * Origin CI checks — the Origin {@link CiCheckWriter} behind the shared check
3
+ * lifecycle in `../checks.js`.
4
+ *
5
+ * Origin check runs are idempotent upserts keyed by `(repo, head SHA, suite
6
+ * key, check key)`, so every write re-POSTs the full desired state with a
7
+ * fresh `externalUpdatedAt`, and `resumeOriginCheck` needs only those
8
+ * identity fields (no server id) to rebuild a handle after a restart.
9
+ *
10
+ * Posting needs `repository:checks:write` and is installation-only: the
11
+ * client must authenticate with an `oit_…` installation token (see
12
+ * `createOriginClient` / `originAppTokenProvider` in `api.js`). Works with
13
+ * any client exposing `request()` (`ctx.origin`, `createOriginClient()`),
14
+ * and is also reachable as `ctx.origin.createCheck(...)`. API failures throw
15
+ * `OriginApiError`.
16
+ */
17
+
18
+ import {
19
+ type CiCheck,
20
+ type CiCheckConcludeInput,
21
+ type CiCheckConclusion,
22
+ type CiCheckCreateInput,
23
+ type CiCheckOutput,
24
+ type CiCheckRef,
25
+ type CiCheckStatus,
26
+ type CiChecksClient,
27
+ type CiCheckUpdateInput,
28
+ type CiCheckWriter,
29
+ openCiCheck,
30
+ resumeCiCheck,
31
+ } from "../checks.js";
32
+ import type { OriginApiMethod } from "./api.js";
33
+
34
+ /** Any client that can call the Origin public REST API. */
35
+ export interface OriginCheckClient {
36
+ request<T = unknown>(input: {
37
+ method: OriginApiMethod;
38
+ path: string;
39
+ body?: unknown;
40
+ }): Promise<T>;
41
+ }
42
+
43
+ export type OriginCheckRunStatus = CiCheckStatus;
44
+
45
+ /** Origin accepts the shared conclusion set plus `stale`. */
46
+ export type OriginCheckRunConclusion = CiCheckConclusion | "stale";
47
+
48
+ export type OriginCheckOutput = CiCheckOutput;
49
+ export type OriginCheckUpdateInput =
50
+ CiCheckUpdateInput<OriginCheckRunConclusion>;
51
+ export type OriginCheckConcludeInput =
52
+ CiCheckConcludeInput<OriginCheckRunConclusion>;
53
+
54
+ /** A created check run. All methods throw `OriginApiError` on API failure. */
55
+ export type OriginCheck = CiCheck<OriginCheckRunConclusion> & CiCheckRef;
56
+
57
+ /** The upsert identity + client an Origin check is bound to. */
58
+ export interface OriginCheckIdentityInput {
59
+ /** Client used for every API call on the returned handle. */
60
+ origin: OriginCheckClient;
61
+ /** Repository owner slug, e.g. `"anysphere"`. */
62
+ owner: string;
63
+ /** Repository name, e.g. `"everysphere"`. */
64
+ repo: string;
65
+ /** Check name shown in the PR merge box, e.g. `"Cursor Security Review"`. */
66
+ name: string;
67
+ /** Commit the check attaches to (usually the PR head SHA). */
68
+ sha: string;
69
+ /**
70
+ * Stable, app-chosen key identifying the logical check across attempts
71
+ * (part of the upsert identity). Defaults to a slug of `name`.
72
+ */
73
+ key?: string;
74
+ /** Suite the check belongs to. Defaults to a suite mirroring the check. */
75
+ suite?: { key?: string; name?: string; detailsUrl?: string };
76
+ /**
77
+ * Provider-assigned immutable identity for this check attempt. Defaults to
78
+ * a deterministic id derived from the keys and `sha`.
79
+ */
80
+ externalId?: string;
81
+ }
82
+
83
+ export interface OriginCheckCreateInput
84
+ extends OriginCheckIdentityInput,
85
+ CiCheckCreateInput {}
86
+
87
+ /**
88
+ * Origin rejects the whole upsert when `output.title` exceeds 255 characters
89
+ * or a body exceeds 65,535 UTF-8 bytes, so the writer caps rather than
90
+ * risking a lost check write.
91
+ */
92
+ const OUTPUT_TITLE_MAX_CHARS = 255;
93
+ const OUTPUT_BODY_MAX_BYTES = 65_000;
94
+
95
+ /** Truncate to at most `maxBytes` UTF-8 bytes without severing a character. */
96
+ function capUtf8Bytes(text: string, maxBytes: number): string {
97
+ const encoded = new TextEncoder().encode(text);
98
+ if (encoded.length <= maxBytes) {
99
+ return text;
100
+ }
101
+ // A non-fatal decode turns a trailing partial character into U+FFFD;
102
+ // stripping it keeps the result valid (and re-encodable) under the cap.
103
+ return new TextDecoder("utf-8")
104
+ .decode(encoded.subarray(0, maxBytes))
105
+ .replace(/\uFFFD+$/, "");
106
+ }
107
+
108
+ function cappedOutput(
109
+ output: CiCheckOutput | undefined
110
+ ): Record<string, unknown> | undefined {
111
+ if (output === undefined) {
112
+ return undefined;
113
+ }
114
+ return {
115
+ title: output.title.slice(0, OUTPUT_TITLE_MAX_CHARS),
116
+ summary: capUtf8Bytes(output.summary, OUTPUT_BODY_MAX_BYTES),
117
+ ...(output.text === undefined
118
+ ? {}
119
+ : { text: capUtf8Bytes(output.text, OUTPUT_BODY_MAX_BYTES) }),
120
+ };
121
+ }
122
+
123
+ /** Derive a stable check key from a display name, e.g. `cursor-security-review`. */
124
+ export function originCheckKeyFromName(name: string): string {
125
+ const slug = name
126
+ .toLowerCase()
127
+ .replace(/[^a-z0-9]+/g, "-")
128
+ .replace(/^-+|-+$/g, "")
129
+ .slice(0, 100);
130
+ return slug === "" ? "check" : slug;
131
+ }
132
+
133
+ /**
134
+ * Origin writer: every write is a full keyed upsert. Tracks the last written
135
+ * status so an output-only update cannot regress a running check to queued.
136
+ */
137
+ function originCheckWriter(
138
+ input: OriginCheckIdentityInput & { status?: CiCheckStatus }
139
+ ): CiCheckWriter<OriginCheckRunConclusion> {
140
+ const key = input.key ?? originCheckKeyFromName(input.name);
141
+ const suiteKey = input.suite?.key ?? key;
142
+ const externalId =
143
+ input.externalId ?? `agent-serve:${suiteKey}:${key}:${input.sha}`;
144
+ const path = `/v1/origin/repos/${encodeURIComponent(input.owner)}/${encodeURIComponent(
145
+ input.repo
146
+ )}/check-runs`;
147
+ let lastStatus: CiCheckStatus = input.status ?? "in_progress";
148
+ return async (write) => {
149
+ const status =
150
+ write.status ??
151
+ (write.conclusion === undefined ? lastStatus : "completed");
152
+ lastStatus = status;
153
+ const response = await input.origin.request<{
154
+ checkRun?: { id?: unknown };
155
+ }>({
156
+ method: "POST",
157
+ path,
158
+ body: {
159
+ headSha: input.sha,
160
+ checkSuite: {
161
+ key: suiteKey,
162
+ name: input.suite?.name ?? input.name,
163
+ externalId: `agent-serve:${suiteKey}`,
164
+ ...(input.suite?.detailsUrl === undefined
165
+ ? {}
166
+ : { detailsUrl: input.suite.detailsUrl }),
167
+ },
168
+ checkRun: {
169
+ key,
170
+ name: input.name,
171
+ status,
172
+ conclusion: write.conclusion,
173
+ // Origin only applies an upsert when this timestamp is at least as
174
+ // new as the stored check; timestamp every write when it is built.
175
+ externalUpdatedAt: new Date().toISOString(),
176
+ externalId,
177
+ startedAt: write.startedAt,
178
+ completedAt: write.completedAt,
179
+ detailsUrl: write.detailsUrl,
180
+ output: cappedOutput(write.output),
181
+ },
182
+ },
183
+ });
184
+ const id = response?.checkRun?.id;
185
+ return typeof id === "string" ? { id } : undefined;
186
+ };
187
+ }
188
+
189
+ /**
190
+ * Create a CI check run on a commit and return a handle for later updates.
191
+ *
192
+ * ```ts
193
+ * const check = await createOriginCheck({
194
+ * origin: ctx.origin,
195
+ * owner: ctx.repository.owner,
196
+ * repo: ctx.repository.name,
197
+ * name: "Cursor Security Review",
198
+ * sha: pr.headSha,
199
+ * detailsUrl: sessionUrl,
200
+ * output: { title: "Running…", summary: `[View session](${sessionUrl})` },
201
+ * });
202
+ * // …do the work…
203
+ * await check.conclude({ conclusion: "success", output: { … } });
204
+ * ```
205
+ */
206
+ export function createOriginCheck(
207
+ input: OriginCheckCreateInput
208
+ ): Promise<OriginCheck> {
209
+ return openCiCheck(originCheckWriter(input), input);
210
+ }
211
+
212
+ /**
213
+ * Rebuild an {@link OriginCheck} handle for an existing check run (e.g.
214
+ * after a process restart) from its upsert identity — no server id needed.
215
+ * No API call is made until the first update.
216
+ */
217
+ export function resumeOriginCheck(
218
+ input: OriginCheckIdentityInput & {
219
+ /** Last known status; defaults to `"in_progress"`. */
220
+ status?: CiCheckStatus;
221
+ /** Server-assigned id (`cr_…`) when known. */
222
+ id?: string;
223
+ }
224
+ ): OriginCheck {
225
+ return resumeCiCheck(
226
+ originCheckWriter(input),
227
+ input.id === undefined ? undefined : { id: input.id }
228
+ );
229
+ }
230
+
231
+ /**
232
+ * Repo-bound checks adapter satisfying the shared {@link CiChecksClient}
233
+ * contract — hand it to forge-agnostic check code when there is no channel
234
+ * `ctx.origin` (e.g. CI entrypoints).
235
+ */
236
+ export function bindOriginChecks(input: {
237
+ origin: OriginCheckClient;
238
+ owner: string;
239
+ repo: string;
240
+ }): CiChecksClient<OriginCheckRunConclusion> {
241
+ return {
242
+ createCheck: (check) =>
243
+ createOriginCheck({
244
+ ...check,
245
+ origin: input.origin,
246
+ owner: input.owner,
247
+ repo: input.repo,
248
+ }),
249
+ };
250
+ }
@@ -22,6 +22,9 @@
22
22
  * matching GitHub's `github-webhook` pattern.
23
23
  */
24
24
 
25
+ export * from "./api.js";
26
+ export * from "./binding.js";
27
+ export * from "./checks.js";
25
28
  export * from "./cursor-account.js";
26
29
  export * from "./events.js";
27
30
  export * from "./origin-channel.js";
@@ -13,6 +13,7 @@ import type {
13
13
  ChannelDefinition,
14
14
  ChannelHandlerArgs,
15
15
  } from "../../types.js";
16
+ import { buildOriginBinding } from "./binding.js";
16
17
  import {
17
18
  parseCursorOriginRepoScope,
18
19
  registerOriginCursorAccountRuntime,
@@ -268,7 +269,7 @@ function originSender(
268
269
  export function parseOriginPullRequestEvent(input: {
269
270
  envelope: OriginWebhookEnvelope;
270
271
  }): {
271
- ctx: Omit<OriginEventContext, "host" | "artifacts">;
272
+ ctx: Omit<OriginEventContext, "host" | "artifacts" | "origin">;
272
273
  pullRequest: OriginPullRequestEvent;
273
274
  payload: Record<string, unknown>;
274
275
  } | null {
@@ -294,6 +295,7 @@ export function parseOriginPullRequestEvent(input: {
294
295
  ctx: {
295
296
  deliveryId: input.envelope.deliveryId,
296
297
  eventType,
298
+ installationId: input.envelope.installationId,
297
299
  repository,
298
300
  pullRequestNumber: number,
299
301
  pullRequestUrl: url,
@@ -332,7 +334,7 @@ export function parseOriginPullRequestEvent(input: {
332
334
  * as {@link defaultGitHubAuth}).
333
335
  */
334
336
  export function defaultOriginAuth(
335
- ctx: Omit<OriginEventContext, "host" | "artifacts">
337
+ ctx: Omit<OriginEventContext, "host" | "artifacts" | "origin">
336
338
  ): AuthContext {
337
339
  const senderId = ctx.sender?.id;
338
340
  return {
@@ -363,7 +365,7 @@ export function defaultOriginTitle(
363
365
  }
364
366
 
365
367
  export function defaultOriginPullRequestMessage(
366
- ctx: Omit<OriginEventContext, "host" | "artifacts">,
368
+ ctx: Omit<OriginEventContext, "host" | "artifacts" | "origin">,
367
369
  pullRequest: OriginPullRequestEvent
368
370
  ): string {
369
371
  const head =
@@ -381,7 +383,7 @@ export function defaultOriginPullRequestMessage(
381
383
  }
382
384
 
383
385
  export function defaultOriginPullRequestDispatch(
384
- ctx: Omit<OriginEventContext, "host" | "artifacts">,
386
+ ctx: Omit<OriginEventContext, "host" | "artifacts" | "origin">,
385
387
  pullRequest: OriginPullRequestEvent
386
388
  ): OriginTurnDispatch | null {
387
389
  if (!DEFAULT_PULL_REQUEST_TYPES.has(pullRequest.type)) {
@@ -397,13 +399,19 @@ function isTaskDispatch(
397
399
  }
398
400
 
399
401
  function enrichEventContext(input: {
400
- ctx: Omit<OriginEventContext, "host" | "artifacts">;
402
+ ctx: Omit<OriginEventContext, "host" | "artifacts" | "origin">;
401
403
  args: ChannelHandlerArgs;
404
+ options: OriginChannelOptions;
402
405
  }): OriginEventContext {
403
406
  return {
404
407
  ...input.ctx,
405
408
  host: input.args.host,
406
409
  artifacts: input.args.artifacts,
410
+ origin: buildOriginBinding({
411
+ repository: input.ctx.repository,
412
+ installationId: input.ctx.installationId,
413
+ app: input.options.app,
414
+ }),
407
415
  };
408
416
  }
409
417
 
@@ -525,7 +533,11 @@ export async function dispatchOriginWebhook(input: {
525
533
  { status: 400 }
526
534
  );
527
535
  }
528
- const ctx = enrichEventContext({ ctx: parsed.ctx, args: input.args });
536
+ const ctx = enrichEventContext({
537
+ ctx: parsed.ctx,
538
+ args: input.args,
539
+ options: input.options,
540
+ });
529
541
  const { pullRequest, payload } = parsed;
530
542
  const repoAllowlist = configuredOriginRepoAllowlist(input.options);
531
543
  if (
@@ -6,6 +6,8 @@ import type {
6
6
  ChannelStartArgs,
7
7
  HostContext,
8
8
  } from "../../types.js";
9
+ import type { OriginTokenProvider } from "./api.js";
10
+ import type { OriginHandle } from "./binding.js";
9
11
 
10
12
  export interface OriginActor {
11
13
  id: string;
@@ -48,12 +50,21 @@ export interface OriginReview {
48
50
  export interface OriginEventContext {
49
51
  deliveryId?: string;
50
52
  eventType: string;
53
+ /** Origin app installation id from the delivery envelope, when present. */
54
+ installationId?: string;
51
55
  repository: OriginRepositoryRef;
52
56
  pullRequestNumber: number;
53
57
  pullRequestUrl: string;
54
58
  sender?: OriginActor;
55
59
  host: HostContext;
56
60
  artifacts: ArtifactsApi;
61
+ /**
62
+ * Repo-bound Origin public API handle (REST calls + `createCheck`).
63
+ * Outbound credentials come from {@link OriginChannelOptions.app} or the
64
+ * `ORIGIN_APP_*` environment; resolution is lazy, so hooks that never call
65
+ * it need no credentials.
66
+ */
67
+ origin: OriginHandle;
57
68
  }
58
69
 
59
70
  export type OriginTurnDispatch = {
@@ -114,6 +125,26 @@ export interface OriginWebhookEnvelope {
114
125
  };
115
126
  }
116
127
 
128
+ /**
129
+ * Outbound Origin app credentials for `ctx.origin` (public REST calls, CI
130
+ * check runs). Fields left unset fall back to the environment
131
+ * (`ORIGIN_APP_ID` / `ORIGIN_APP_INSTALLATION_ID` / `ORIGIN_APP_PRIVATE_KEY`
132
+ * / `ORIGIN_API_BASE_URL`); the delivery's installation id fills in when
133
+ * neither pins one.
134
+ */
135
+ export interface OriginAppOptions {
136
+ /** Origin app id (`app_<typeid>`). */
137
+ appId?: string;
138
+ /** Installation id outbound tokens are minted for. */
139
+ installationId?: string;
140
+ /** PKCS8 PEM for the app's EdDSA (Ed25519) private key. */
141
+ privateKey?: string;
142
+ /** Static bearer (`oit_…`) or provider, bypassing the app-JWT mint. */
143
+ token?: string | OriginTokenProvider;
144
+ /** Public Origin REST base, e.g. `https://api.cursor.com`. */
145
+ apiBaseUrl?: string;
146
+ }
147
+
117
148
  export interface OriginChannelOptions {
118
149
  /**
119
150
  * Use the signed-in Cursor account for inbound Origin events via
@@ -149,6 +180,12 @@ export interface OriginChannelOptions {
149
180
  * (GitHub's no-secret posture); `--dev` / skip-verify admits loopback only.
150
181
  */
151
182
  auth?: AuthPolicy[];
183
+ /**
184
+ * Outbound Origin app credentials for `ctx.origin` (REST calls, CI check
185
+ * runs). Optional: every field falls back to the `ORIGIN_APP_*`
186
+ * environment, and inbound-only channels need none.
187
+ */
188
+ app?: OriginAppOptions;
152
189
  /** Route path under `/v1/channels/<name>`. Defaults to `/`. */
153
190
  path?: string;
154
191
  /** Origin API base used to fetch `/v1/origin/keys` for v1ed verify. */
package/src/channels.ts CHANGED
@@ -47,6 +47,22 @@
47
47
  * Handlers receive `args.body` / `args.query` inferred from those schemas.
48
48
  */
49
49
 
50
+ export {
51
+ type CiCheck,
52
+ type CiCheckConcludeInput,
53
+ type CiCheckConclusion,
54
+ type CiCheckCreateInput,
55
+ type CiCheckOutput,
56
+ type CiCheckRef,
57
+ type CiCheckStatus,
58
+ type CiChecksClient,
59
+ type CiCheckUpdateInput,
60
+ type CiCheckWrite,
61
+ type CiCheckWriter,
62
+ openCiCheck,
63
+ resumeCiCheck,
64
+ } from "./channels/checks.js";
65
+
50
66
  import { Buffer } from "node:buffer";
51
67
  import { timingSafeEqual } from "node:crypto";
52
68
  import { brandDefinition } from "./internal/brand.js";
@@ -1,15 +1,18 @@
1
1
  /**
2
2
  * `install-skills` — install the package's coding-agent skills into
3
- * `~/.cursor/skills/agentkit/` without running `init`.
3
+ * `~/.cursor/skills/agentsdk/` without running `init`.
4
4
  *
5
5
  * Never prompts: running the command is the confirmation. The interactive
6
- * offer lives in `init`.
6
+ * offer lives in `init`. Consumer `npm install` / `npx` copies the same
7
+ * skills in postinstall (with `alwaysApply: true` so Cursor injects them);
8
+ * this command refreshes them without reinstalling.
7
9
  */
8
10
 
9
11
  import { CLI_COMMAND_NAME } from "./distribution.js";
10
12
  import {
11
13
  formatSkillInstall,
12
14
  installCursorSkills,
15
+ LEGACY_CURSOR_SKILLS_NAMESPACE,
13
16
  planSkillInstall,
14
17
  type SkillInstallPlan,
15
18
  } from "./install-cursor-skills.js";
@@ -90,6 +93,11 @@ function previewBlock(plan: SkillInstallPlan): string {
90
93
  if (plan.orphans.length > 0) {
91
94
  lines.push(` removes: ${plan.orphans.join(", ")}`);
92
95
  }
96
+ if (plan.hasLegacyNamespace) {
97
+ lines.push(
98
+ ` removes: ${LEGACY_CURSOR_SKILLS_NAMESPACE}/ (legacy namespace)`
99
+ );
100
+ }
93
101
  lines.push(` location: ${plan.directory}`);
94
102
  return `${lines.join("\n")}\n`;
95
103
  }