@cursor/july 0.1.78 → 0.1.80

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 (78) hide show
  1. package/dist/channels/github/api.d.ts.map +1 -1
  2. package/dist/channels/github/api.js +8 -1
  3. package/dist/channels/github/cursor-account.d.ts +17 -0
  4. package/dist/channels/github/cursor-account.d.ts.map +1 -1
  5. package/dist/channels/github/cursor-account.js +47 -0
  6. package/dist/docs/404.html +1 -1
  7. package/dist/docs/ab.html +2 -2
  8. package/dist/docs/assets/{app.BsA7t7rS.js → app.e4_wtjUS.js} +1 -1
  9. package/dist/docs/assets/chunks/@localSearchIndexroot.BGiMJpnL.js +1 -0
  10. package/dist/docs/assets/chunks/{VPLocalSearchBox.B1hHhktM.js → VPLocalSearchBox.DbdzyEie.js} +1 -1
  11. package/dist/docs/assets/chunks/{theme.DLpLSsQh.js → theme.D8HpLrLK.js} +2 -2
  12. package/dist/docs/building-with-agents.html +2 -2
  13. package/dist/docs/concepts.html +2 -2
  14. package/dist/docs/deployment.html +2 -2
  15. package/dist/docs/evals.html +2 -2
  16. package/dist/docs/example-agents/approval-buddy.html +2 -2
  17. package/dist/docs/example-agents/benny.html +2 -2
  18. package/dist/docs/example-agents/bugbot.html +2 -2
  19. package/dist/docs/example-agents/codebase-wiki.html +2 -2
  20. package/dist/docs/example-agents/codeowners-review.html +2 -2
  21. package/dist/docs/example-agents/concierge.html +2 -2
  22. package/dist/docs/example-agents/fsd.html +2 -2
  23. package/dist/docs/example-agents/index.html +2 -2
  24. package/dist/docs/example-agents/knowledge-base.html +2 -2
  25. package/dist/docs/example-agents/oncall.html +2 -2
  26. package/dist/docs/example-agents/security-reviewer.html +2 -2
  27. package/dist/docs/example-agents/slack-agent.html +2 -2
  28. package/dist/docs/example-agents/weather-agent.html +2 -2
  29. package/dist/docs/guides/agent-to-agent.html +2 -2
  30. package/dist/docs/guides/cloud-runtime.html +2 -2
  31. package/dist/docs/guides/convert-automation.html +2 -2
  32. package/dist/docs/guides/github.html +2 -2
  33. package/dist/docs/guides/human-in-the-loop.html +2 -2
  34. package/dist/docs/guides/mcp-oauth.html +2 -2
  35. package/dist/docs/guides/opentelemetry.html +2 -2
  36. package/dist/docs/guides/slack.html +2 -2
  37. package/dist/docs/guides/webhooks.html +2 -2
  38. package/dist/docs/hillclimbing.html +2 -2
  39. package/dist/docs/index.html +2 -2
  40. package/dist/docs/quickstart.html +2 -2
  41. package/dist/docs/reference/agent-config.html +2 -2
  42. package/dist/docs/reference/artifacts.html +2 -2
  43. package/dist/docs/reference/channels.html +2 -2
  44. package/dist/docs/reference/cli.html +2 -2
  45. package/dist/docs/reference/connections.html +2 -2
  46. package/dist/docs/reference/hooks.html +2 -2
  47. package/dist/docs/reference/http-api.html +2 -2
  48. package/dist/docs/reference/instructions.html +2 -2
  49. package/dist/docs/reference/playground.html +2 -2
  50. package/dist/docs/reference/project-layout.html +2 -2
  51. package/dist/docs/reference/prompt.html +2 -2
  52. package/dist/docs/reference/schedules.html +2 -2
  53. package/dist/docs/reference/sessions.html +2 -2
  54. package/dist/docs/reference/skills.html +2 -2
  55. package/dist/docs/reference/subagents.html +2 -2
  56. package/dist/docs/reference/tools.html +2 -2
  57. package/dist/docs/scaffolding-agents.html +2 -2
  58. package/dist/docs/storage.html +2 -2
  59. package/dist/docs/templates/agentic-owners.html +2 -2
  60. package/dist/docs/templates/demo.html +2 -2
  61. package/dist/docs/templates/pr-autofixer.html +2 -2
  62. package/dist/docs/templates/security-reviewer.html +2 -2
  63. package/dist/docs/templates/triage.html +2 -2
  64. package/dist/docs/troubleshooting.html +2 -2
  65. package/dist/internal/review-comments.d.ts +37 -7
  66. package/dist/internal/review-comments.d.ts.map +1 -1
  67. package/dist/internal/review-comments.js +209 -10
  68. package/dist/internal/server.d.ts.map +1 -1
  69. package/dist/internal/server.js +101 -49
  70. package/package.json +1 -1
  71. package/src/channels/github/api.ts +8 -0
  72. package/src/channels/github/cursor-account.ts +56 -0
  73. package/src/internal/review-comments.ts +257 -16
  74. package/src/internal/server.ts +124 -60
  75. package/templates/agentic-owners/agent/lib/owners/match.ts +64 -3
  76. package/templates/agentic-owners/agent/lib/owners/parse.ts +55 -1
  77. package/templates/agentic-owners/agent/lib/owners/types.ts +5 -0
  78. package/dist/docs/assets/chunks/@localSearchIndexroot.Dcs6boxD.js +0 -1
@@ -1,5 +1,5 @@
1
1
  import type { HostGitHubClient } from "../types.js";
2
- export type ReviewCommentPublisher = "local_gh" | "host_github";
2
+ export type ReviewCommentPublisher = "local_gh" | "host_github" | "host_origin";
3
3
  export type ReviewCommentPostResult = {
4
4
  posted: boolean;
5
5
  publisher: ReviewCommentPublisher;
@@ -48,12 +48,24 @@ export type ReviewCommentPublisherImplementation = {
48
48
  postReview: (args: ReviewCommentPostArgs) => Promise<ReviewCommentPostResult>;
49
49
  };
50
50
  /**
51
- * SCMs this module can read review comments back from. Same growth seam as
52
- * `shallow-clone.ts`'s {@link import("./shallow-clone.js").ScmProvider}:
53
- * adding GitLab/Bitbucket/Origin means a resolver case plus a reader
54
- * implementation, and nothing above this line changes.
51
+ * SCMs this module can address. Same growth seam as `shallow-clone.ts`'s
52
+ * {@link import("./shallow-clone.js").ScmProvider}: adding a forge means a
53
+ * resolver case plus a publisher (and, when the public API supports it, a
54
+ * reader / thread resolver). Callers above this line stay provider-neutral.
55
55
  */
56
- export type ScmReviewProvider = "github";
56
+ export type ScmReviewProvider = "github" | "origin";
57
+ /**
58
+ * Origin public REST client used to post PR reviews (`ctx.origin` /
59
+ * {@link import("../channels/origin/api.js").createOriginClient}). Narrower
60
+ * than the full Origin handle so tests and CLI paths can inject `request()`.
61
+ */
62
+ export type HostOriginReviewClient = {
63
+ request(input: {
64
+ method: "DELETE" | "GET" | "PATCH" | "POST" | "PUT";
65
+ path: string;
66
+ body?: unknown;
67
+ }): Promise<unknown>;
68
+ };
57
69
  /** Which SCM's PR to read review comments from. */
58
70
  export type ScmReviewTarget = {
59
71
  provider: ScmReviewProvider;
@@ -126,7 +138,7 @@ export type ResolveReviewThreadsResult = {
126
138
  export type ReviewThreadResolverImplementation = {
127
139
  resolveReviewThreadsForComments: (args: ResolveReviewThreadsArgs) => Promise<ResolveReviewThreadsResult>;
128
140
  };
129
- /** Parse a PR URL into the SCM target to read comments from. */
141
+ /** Parse a PR URL into the SCM target to read or post comments on. */
130
142
  export declare function resolveScmReviewTarget(prUrl: string): ScmReviewTarget | undefined;
131
143
  /**
132
144
  * Reader for a resolved target, mirroring Bugbot's `createPrGitProvider`
@@ -213,5 +225,23 @@ export declare function createLocalGhReviewPublisher(): ReviewCommentPublisherIm
213
225
  * cursorAccount })` is bound.
214
226
  */
215
227
  export declare function createHostGithubReviewPublisher(github: HostGitHubClient): ReviewCommentPublisherImplementation;
228
+ /**
229
+ * Pick the publisher for `prUrl`'s SCM. GitHub falls back to local `gh`
230
+ * when no host client is bound (CLI). Origin has no local CLI publisher —
231
+ * returns undefined unless an Origin REST client is provided.
232
+ */
233
+ export declare function createReviewCommentPublisher(args: {
234
+ prUrl: string;
235
+ github?: HostGitHubClient;
236
+ origin?: HostOriginReviewClient;
237
+ }): ReviewCommentPublisherImplementation | undefined;
238
+ /**
239
+ * Posts a COMMENT-verdict Origin review through the public REST API.
240
+ *
241
+ * Public Origin REST has no diff-anchored review comments (those are an
242
+ * internal CreateCommentThread RPC). Inline comments in the request are
243
+ * folded into the review body so findings still land on the PR.
244
+ */
245
+ export declare function createHostOriginReviewPublisher(origin: HostOriginReviewClient): ReviewCommentPublisherImplementation;
216
246
  export {};
217
247
  //# sourceMappingURL=review-comments.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"review-comments.d.ts","sourceRoot":"","sources":["../../src/internal/review-comments.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"review-comments.d.ts","sourceRoot":"","sources":["../../src/internal/review-comments.ts"],"names":[],"mappings":"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"}
@@ -8,16 +8,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { spawn } from "node:child_process";
11
- /** Parse a PR URL into the SCM target to read comments from. */
11
+ /** Parse a PR URL into the SCM target to read or post comments on. */
12
12
  export function resolveScmReviewTarget(prUrl) {
13
- const parsed = parseGithubPrUrl(prUrl);
14
- return parsed.kind === "valid"
15
- ? {
16
- provider: "github",
17
- repo: parsed.value.repo,
18
- prNumber: parsed.value.prNumber,
19
- }
20
- : undefined;
13
+ const parsed = parseReviewPrUrl(prUrl);
14
+ return parsed.kind === "valid" ? parsed.value : undefined;
21
15
  }
22
16
  /**
23
17
  * Reader for a resolved target, mirroring Bugbot's `createPrGitProvider`
@@ -30,6 +24,10 @@ export function createReviewCommentReader(args) {
30
24
  return args.github === undefined
31
25
  ? undefined
32
26
  : createHostGithubReviewCommentReader(args.github);
27
+ case "origin":
28
+ // Public Origin REST lists discussion comments, not diff-anchored
29
+ // review threads. Stay undefined until a reader can fetch by id.
30
+ return undefined;
33
31
  }
34
32
  }
35
33
  /**
@@ -42,6 +40,8 @@ export function createReviewThreadResolver(args) {
42
40
  return args.github === undefined
43
41
  ? undefined
44
42
  : createHostGithubReviewThreadResolver(args.github);
43
+ case "origin":
44
+ return undefined;
45
45
  }
46
46
  }
47
47
  /**
@@ -66,7 +66,9 @@ export function resolveReviewThreadsForComments(args) {
66
66
  github: args.github,
67
67
  });
68
68
  if (resolver === undefined) {
69
- return skippedResolve("no GitHub client bound to resolve threads");
69
+ return skippedResolve(target.provider === "github"
70
+ ? "no GitHub client bound to resolve threads"
71
+ : `no thread resolver for ${target.provider}`);
70
72
  }
71
73
  return resolver.resolveReviewThreadsForComments({
72
74
  target,
@@ -341,6 +343,43 @@ export function createHostGithubReviewPublisher(github) {
341
343
  },
342
344
  };
343
345
  }
346
+ /**
347
+ * Pick the publisher for `prUrl`'s SCM. GitHub falls back to local `gh`
348
+ * when no host client is bound (CLI). Origin has no local CLI publisher —
349
+ * returns undefined unless an Origin REST client is provided.
350
+ */
351
+ export function createReviewCommentPublisher(args) {
352
+ const target = resolveScmReviewTarget(args.prUrl);
353
+ if (target === undefined) {
354
+ return undefined;
355
+ }
356
+ switch (target.provider) {
357
+ case "github":
358
+ return args.github !== undefined
359
+ ? createHostGithubReviewPublisher(args.github)
360
+ : createLocalGhReviewPublisher();
361
+ case "origin":
362
+ return args.origin === undefined
363
+ ? undefined
364
+ : createHostOriginReviewPublisher(args.origin);
365
+ }
366
+ }
367
+ /**
368
+ * Posts a COMMENT-verdict Origin review through the public REST API.
369
+ *
370
+ * Public Origin REST has no diff-anchored review comments (those are an
371
+ * internal CreateCommentThread RPC). Inline comments in the request are
372
+ * folded into the review body so findings still land on the PR.
373
+ */
374
+ export function createHostOriginReviewPublisher(origin) {
375
+ return {
376
+ postReview(args) {
377
+ return __awaiter(this, void 0, void 0, function* () {
378
+ return postReviewViaHostOrigin(origin, args);
379
+ });
380
+ },
381
+ };
382
+ }
344
383
  function postReviewViaHostGithub(github, args) {
345
384
  return __awaiter(this, void 0, void 0, function* () {
346
385
  var _a, _b, _c;
@@ -523,6 +562,70 @@ function skippedHost(detail) {
523
562
  detail,
524
563
  };
525
564
  }
565
+ function skippedOrigin(detail) {
566
+ return {
567
+ posted: false,
568
+ publisher: "host_origin",
569
+ mode: "skipped",
570
+ inlineCommentCount: 0,
571
+ detail,
572
+ };
573
+ }
574
+ function postReviewViaHostOrigin(origin, args) {
575
+ return __awaiter(this, void 0, void 0, function* () {
576
+ var _a, _b;
577
+ const target = resolveScmReviewTarget(args.prUrl);
578
+ if (target === undefined || target.provider !== "origin") {
579
+ return skippedOrigin("host Origin publisher only supports Origin PRs");
580
+ }
581
+ const [owner, repo] = target.repo.split("/", 2);
582
+ if (owner === undefined || repo === undefined || repo === "") {
583
+ return skippedOrigin("unparseable owner/repo from PR URL");
584
+ }
585
+ try {
586
+ (_a = args.signal) === null || _a === void 0 ? void 0 : _a.throwIfAborted();
587
+ yield origin.request({
588
+ method: "POST",
589
+ path: `/v1/origin/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/pulls/${target.prNumber}/reviews`,
590
+ body: {
591
+ verdict: "comment",
592
+ body: originReviewBody(args),
593
+ },
594
+ });
595
+ return {
596
+ posted: true,
597
+ publisher: "host_origin",
598
+ mode: "review_body_only",
599
+ inlineCommentCount: 0,
600
+ detail: `posted Origin review on ${target.repo}#${target.prNumber}`,
601
+ };
602
+ }
603
+ catch (error) {
604
+ if ((_b = args.signal) === null || _b === void 0 ? void 0 : _b.aborted) {
605
+ throw error;
606
+ }
607
+ return skippedOrigin(`host Origin review post failed: ${error instanceof Error ? error.message : String(error)}`);
608
+ }
609
+ });
610
+ }
611
+ /**
612
+ * Origin's public CreatePullRequestReview has a body, not inline comments.
613
+ * Fold attempted anchors into the summary so findings are not dropped.
614
+ */
615
+ function originReviewBody(args) {
616
+ if (args.comments.length === 0) {
617
+ return args.message;
618
+ }
619
+ const sections = args.comments.map((comment) => {
620
+ const location = comment.start_line !== undefined &&
621
+ comment.start_line > 0 &&
622
+ comment.start_line !== comment.line
623
+ ? `${comment.file}:${comment.start_line}-${comment.line}`
624
+ : `${comment.file}:${comment.line}`;
625
+ return `### \`${location}\`\n\n${comment.body}`;
626
+ });
627
+ return [args.message, ...sections].join("\n\n");
628
+ }
526
629
  function skippedResolve(detail) {
527
630
  return {
528
631
  requested: 0,
@@ -533,6 +636,102 @@ function skippedResolve(detail) {
533
636
  detail,
534
637
  };
535
638
  }
639
+ const ORIGIN_PR_PAGE_HOST_PATTERN = /^origin(-[a-z0-9]+)?\.cursor\.com$/i;
640
+ /**
641
+ * Provider-neutral PR URL parse. GitHub.com plus the Origin page shapes
642
+ * `parsePrTarget` in security-review-lib accepts. Duplicated here so
643
+ * agent-serve does not import that package.
644
+ */
645
+ function parseReviewPrUrl(prUrl) {
646
+ let url;
647
+ try {
648
+ url = new URL(prUrl);
649
+ }
650
+ catch (error) {
651
+ return {
652
+ kind: "invalid",
653
+ detail: `unparseable PR URL: ${error instanceof Error ? error.message : String(error)}`,
654
+ };
655
+ }
656
+ const parts = url.pathname.split("/").filter(Boolean);
657
+ const hostname = url.hostname;
658
+ if (hostname === "github.com" && parts.length >= 4 && parts[2] === "pull") {
659
+ const prNumber = Number(parts[3]);
660
+ if (Number.isInteger(prNumber) && prNumber > 0) {
661
+ return {
662
+ kind: "valid",
663
+ value: {
664
+ provider: "github",
665
+ repo: `${parts[0]}/${parts[1]}`,
666
+ prNumber,
667
+ },
668
+ };
669
+ }
670
+ }
671
+ if (ORIGIN_PR_PAGE_HOST_PATTERN.test(hostname) &&
672
+ parts.length >= 4 &&
673
+ parts[2] === "github") {
674
+ const prNumber = Number(parts[3]);
675
+ if (Number.isInteger(prNumber) && prNumber > 0) {
676
+ return {
677
+ kind: "valid",
678
+ value: {
679
+ provider: "origin",
680
+ repo: `${parts[0]}/${parts[1]}`,
681
+ prNumber,
682
+ },
683
+ };
684
+ }
685
+ }
686
+ if (/^(www\.)?cursor\.com$/i.test(hostname) &&
687
+ parts[0] === "codebase" &&
688
+ parts.length >= 5 &&
689
+ parts[3] === "pull") {
690
+ const prNumber = Number(parts[4]);
691
+ if (Number.isInteger(prNumber) && prNumber > 0) {
692
+ return {
693
+ kind: "valid",
694
+ value: {
695
+ provider: "origin",
696
+ repo: `${parts[1]}/${parts[2]}`,
697
+ prNumber,
698
+ },
699
+ };
700
+ }
701
+ }
702
+ if (hostname === "review.cursor.com" && parts[0] === "pr") {
703
+ if (parts.length >= 5 && parts[3] === "github") {
704
+ const prNumber = Number(parts[4]);
705
+ if (Number.isInteger(prNumber) && prNumber > 0) {
706
+ return {
707
+ kind: "valid",
708
+ value: {
709
+ provider: "origin",
710
+ repo: `${parts[1]}/${parts[2]}`,
711
+ prNumber,
712
+ },
713
+ };
714
+ }
715
+ }
716
+ if (parts.length >= 4) {
717
+ const prNumber = Number(parts[3]);
718
+ if (Number.isInteger(prNumber) && prNumber > 0) {
719
+ return {
720
+ kind: "valid",
721
+ value: {
722
+ provider: "origin",
723
+ repo: `${parts[1]}/${parts[2]}`,
724
+ prNumber,
725
+ },
726
+ };
727
+ }
728
+ }
729
+ }
730
+ return {
731
+ kind: "invalid",
732
+ detail: "unparseable PR URL: not a GitHub or Origin pull request",
733
+ };
734
+ }
536
735
  function parseGithubPrUrl(prUrl) {
537
736
  let url;
538
737
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/internal/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAuCH,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAOhB,YAAY,EACb,MAAM,aAAa,CAAC;AAwHrB,OAAO,EAAE,KAAK,WAAW,EAAmB,MAAM,iBAAiB,CAAC;AAwBpE,8EAA8E;AAC9E,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,CAAC;CACvB;AAaD,6EAA6E;AAC7E,MAAM,WAAW,0BAA0B;IACzC,oEAAoE;IACpE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,UAAU,EAAE,EACpB,OAAO,GAAE,YAAY,GAAG,0BAA+B,GACtD,OAAO,CAAC,gBAAgB,CAAC,CAoxB3B"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/internal/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwCH,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAOhB,YAAY,EACb,MAAM,aAAa,CAAC;AAwHrB,OAAO,EAAE,KAAK,WAAW,EAAmB,MAAM,iBAAiB,CAAC;AAwBpE,8EAA8E;AAC9E,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,CAAC;CACvB;AAaD,6EAA6E;AAC7E,MAAM,WAAW,0BAA0B;IACzC,oEAAoE;IACpE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,UAAU,EAAE,EACpB,OAAO,GAAE,YAAY,GAAG,0BAA+B,GACtD,OAAO,CAAC,gBAAgB,CAAC,CAwzB3B"}
@@ -36,7 +36,7 @@ import { once } from "node:events";
36
36
  import { createServer, } from "node:http";
37
37
  import { join } from "node:path";
38
38
  import { dispatchDeploymentEvent, getDeploymentsChannelOptions, } from "../channels/deployments/deployments-channel.js";
39
- import { createCursorAccountGithubTokenResolver, getGithubCursorAccountRuntime, parseCursorGithubRepoScope, resolveCursorGithubPermissions, resolveCursorGithubProxyUrl, } from "../channels/github/cursor-account.js";
39
+ import { createCursorAccountGithubTokenResolver, cursorGithubPermissionsForChannel, getGithubCursorAccountRuntime, resolveCursorGithubCredentialScope, resolveCursorGithubPermissions, resolveCursorGithubProxyUrl, } from "../channels/github/cursor-account.js";
40
40
  import { findGitHubChannelTargets } from "../channels/github/forward.js";
41
41
  import { getOriginCursorAccountRuntime, parseCursorOriginRepoScope, } from "../channels/origin/cursor-account.js";
42
42
  import { findOriginChannelTargets } from "../channels/origin/origin-channel.js";
@@ -160,53 +160,82 @@ export function startServer(mounts_1) {
160
160
  ? undefined
161
161
  : requireCursorEventsAuth(effectiveCursorEvents, accountKey);
162
162
  let cursorGithubCredentials;
163
- if (cursorGithubConfig.scope !== undefined) {
164
- if (cursorEventsAuth === undefined) {
165
- throw new Error("githubChannel({ cursorAccount: true }) could not resolve Cursor event authentication.");
166
- }
167
- if (options.allowAnonymous === true) {
168
- if (options.allowAnonymousCursorGithub !== true) {
169
- throw new Error("githubChannel({ cursorAccount: true }) cannot be served with --allow-anonymous because admitted callers could use the signed-in account's GitHub access. If every admitted caller is trusted (e.g. behind an SSO proxy), opt in with --allow-anonymous-cursor-github.");
163
+ if (cursorGithubTargets.length > 0) {
164
+ const githubProxyRequested = options.cursorGithubProxy === true;
165
+ const needsGithubAuth = cursorGithubConfig.scope !== undefined || githubProxyRequested;
166
+ if (needsGithubAuth) {
167
+ const cursorGithubAuth = cursorEventsAuth !== null && cursorEventsAuth !== void 0 ? cursorEventsAuth : ((accountKey === null || accountKey === void 0 ? void 0 : accountKey.apiKey) !== undefined && accountKey.apiKey.trim() !== ""
168
+ ? {
169
+ apiKey: accountKey.apiKey.trim(),
170
+ baseUrl: cursorExternalApiUrl(),
171
+ }
172
+ : undefined);
173
+ if (cursorGithubAuth === undefined) {
174
+ throw new Error("githubChannel({ cursorAccount: true }) could not resolve Cursor event authentication.");
170
175
  }
171
- logger("[agent-sdk] warning: --allow-anonymous-cursor-github — every admitted HTTP caller can drive sessions holding the signed-in account's repo-scoped GitHub credential; serve this only behind a trusted boundary (e.g. an SSO proxy)");
172
- }
173
- if (cursorGithubConfig.scope.permissions === "contents-write") {
174
- logger('[agent-sdk] warning: Cursor GitHub credentials include contents:write — the host holds a push-capable token shared with model-driven tools and untrusted webhook content; prefer permissions: "pr-write" unless this agent must push code');
175
- }
176
- const provider = new CursorGithubCredentialProvider({
177
- client: new CursorBackendClient({
178
- backendUrl: cursorEventsAuth.baseUrl,
179
- apiKey: cursorEventsAuth.apiKey,
180
- logger,
181
- }),
182
- scope: cursorGithubConfig.scope,
183
- logger,
184
- });
185
- cursorGithubCredentials = provider;
186
- const githubProxyUrl = options.cursorGithubProxy === true
187
- ? resolveCursorGithubProxyUrl(cursorEventsAuth.baseUrl)
188
- : undefined;
189
- if (githubProxyUrl !== undefined) {
190
- // Proxy mode: channel Octokit calls carry the Cursor API key to the
191
- // backend forwarder, which swaps in the installation token server-side
192
- // and logs every call with per-deployment attribution. The provider
193
- // still runs so child `gh` processes get a `GH_TOKEN` lease (v1).
194
- const proxyTransport = {
195
- apiBaseUrl: githubProxyUrl,
196
- headers: {
197
- "x-cursor-github-repos": cursorGithubConfig.scope.repos.join(","),
198
- "x-cursor-github-permissions": cursorGithubConfig.scope.permissions,
199
- },
200
- };
201
- for (const target of cursorGithubTargets) {
202
- target.accountRuntime.credentials.bind(() => __awaiter(this, void 0, void 0, function* () { return cursorEventsAuth.apiKey; }));
203
- target.accountRuntime.credentials.bindProxyTransport(proxyTransport);
176
+ if (options.allowAnonymous === true) {
177
+ if (options.allowAnonymousCursorGithub !== true) {
178
+ throw new Error("githubChannel({ cursorAccount: true }) cannot be served with --allow-anonymous because admitted callers could use the signed-in account's GitHub access. If every admitted caller is trusted (e.g. behind an SSO proxy), opt in with --allow-anonymous-cursor-github.");
179
+ }
180
+ logger("[agent-sdk] warning: --allow-anonymous-cursor-github — every admitted HTTP caller can drive sessions holding the signed-in account's repo-scoped GitHub credential; serve this only behind a trusted boundary (e.g. an SSO proxy)");
204
181
  }
205
- logger(`[agent-sdk] GitHub auth: channel API calls route through ${githubProxyUrl}`);
206
- }
207
- else {
208
- for (const target of cursorGithubTargets) {
209
- target.accountRuntime.credentials.bind(() => provider.getToken());
182
+ if (cursorGithubConfig.permissions === "contents-write") {
183
+ logger('[agent-sdk] warning: Cursor GitHub credentials include contents:write — the host holds a push-capable token shared with model-driven tools and untrusted webhook content; prefer permissions: "pr-write" unless this agent must push code');
184
+ }
185
+ const githubProxyUrl = githubProxyRequested
186
+ ? resolveCursorGithubProxyUrl(cursorGithubAuth.baseUrl)
187
+ : undefined;
188
+ if (cursorGithubConfig.scope !== undefined) {
189
+ const provider = new CursorGithubCredentialProvider({
190
+ client: new CursorBackendClient({
191
+ backendUrl: cursorGithubAuth.baseUrl,
192
+ apiKey: cursorGithubAuth.apiKey,
193
+ logger,
194
+ }),
195
+ scope: cursorGithubConfig.scope,
196
+ logger,
197
+ });
198
+ cursorGithubCredentials = provider;
199
+ if (githubProxyUrl !== undefined) {
200
+ // Proxy mode: channel Octokit calls carry the Cursor API key to the
201
+ // backend forwarder, which swaps in the installation token server-side
202
+ // and logs every call with per-deployment attribution. The provider
203
+ // still runs so child `gh` processes get a `GH_TOKEN` lease (v1).
204
+ const proxyTransport = {
205
+ apiBaseUrl: githubProxyUrl,
206
+ headers: {
207
+ "x-cursor-github-repos": cursorGithubConfig.scope.repos.join(","),
208
+ "x-cursor-github-permissions": cursorGithubConfig.permissions,
209
+ },
210
+ };
211
+ for (const target of cursorGithubTargets) {
212
+ target.accountRuntime.credentials.bind(() => __awaiter(this, void 0, void 0, function* () { return cursorGithubAuth.apiKey; }));
213
+ target.accountRuntime.credentials.bindProxyTransport(proxyTransport);
214
+ }
215
+ logger(`[agent-sdk] GitHub auth: channel API calls route through ${githubProxyUrl}`);
216
+ }
217
+ else {
218
+ for (const target of cursorGithubTargets) {
219
+ target.accountRuntime.credentials.bind(() => provider.getToken());
220
+ }
221
+ }
222
+ }
223
+ else if (githubProxyUrl !== undefined) {
224
+ // `cursorAccount: true` with no `--repo`: skip the startup token mint
225
+ // (it requires a repo list) and let github-proxy take the repo from
226
+ // each Octokit call. Hosted multi-tenant uses this with the
227
+ // deployment event stream.
228
+ const proxyTransport = {
229
+ apiBaseUrl: githubProxyUrl,
230
+ headers: {
231
+ "x-cursor-github-permissions": cursorGithubConfig.permissions,
232
+ },
233
+ };
234
+ for (const target of cursorGithubTargets) {
235
+ target.accountRuntime.credentials.bind(() => __awaiter(this, void 0, void 0, function* () { return cursorGithubAuth.apiKey; }));
236
+ target.accountRuntime.credentials.bindProxyTransport(proxyTransport);
237
+ }
238
+ logger(`[agent-sdk] GitHub auth: channel API calls route through ${githubProxyUrl} (repo scope per request)`);
210
239
  }
211
240
  }
212
241
  }
@@ -1543,11 +1572,23 @@ function collectCursorGithubTargets(mounts) {
1543
1572
  }
1544
1573
  return targets;
1545
1574
  }
1575
+ function cursorGithubPermissionsForTarget(target) {
1576
+ var _a;
1577
+ var _b;
1578
+ const authored = typeof target.accountRuntime.options.cursorAccount === "object"
1579
+ ? target.accountRuntime.options.cursorAccount.permissions
1580
+ : undefined;
1581
+ return ((_b = (_a = target.accountRuntime.scope) === null || _a === void 0 ? void 0 : _a.permissions) !== null && _b !== void 0 ? _b : cursorGithubPermissionsForChannel(target.accountRuntime.options, authored));
1582
+ }
1546
1583
  function resolveCursorGithubEventConfig(input) {
1547
1584
  var _a;
1548
1585
  var _b;
1549
1586
  if (input.targets.length === 0) {
1550
- return { cursorEvents: input.configured, scope: undefined };
1587
+ return {
1588
+ cursorEvents: input.configured,
1589
+ scope: undefined,
1590
+ permissions: "pr-write",
1591
+ };
1551
1592
  }
1552
1593
  const repos = [
1553
1594
  ...((_b = (_a = input.configured) === null || _a === void 0 ? void 0 : _a.repos) !== null && _b !== void 0 ? _b : []),
@@ -1555,11 +1596,19 @@ function resolveCursorGithubEventConfig(input) {
1555
1596
  ...((_b = (_a = target.accountRuntime.scope) === null || _a === void 0 ? void 0 : _a.repos) !== null && _b !== void 0 ? _b : []),
1556
1597
  ]; }),
1557
1598
  ];
1558
- const permissions = resolveCursorGithubPermissions(input.targets.map((target) => { var _a; var _b; return (_b = (_a = target.accountRuntime.scope) === null || _a === void 0 ? void 0 : _a.permissions) !== null && _b !== void 0 ? _b : "pr-write"; }));
1559
- const scope = parseCursorGithubRepoScope(repos, permissions);
1599
+ const permissions = resolveCursorGithubPermissions(input.targets.map(cursorGithubPermissionsForTarget));
1600
+ const scope = resolveCursorGithubCredentialScope(repos, permissions);
1601
+ if (scope === undefined) {
1602
+ return {
1603
+ cursorEvents: input.configured,
1604
+ scope: undefined,
1605
+ permissions,
1606
+ };
1607
+ }
1560
1608
  return {
1561
1609
  cursorEvents: Object.assign(Object.assign({}, input.configured), { repos: [...scope.repos] }),
1562
1610
  scope,
1611
+ permissions,
1563
1612
  };
1564
1613
  }
1565
1614
  function collectCursorOriginTargets(mounts) {
@@ -1591,6 +1640,9 @@ function resolveCursorOriginRepoScope(input) {
1591
1640
  ...(wantsHostRepos ? input.explicitRepos : []),
1592
1641
  ...input.targets.flatMap((target) => { var _a; var _b; return (_b = (_a = target.accountRuntime.scope) === null || _a === void 0 ? void 0 : _a.repos) !== null && _b !== void 0 ? _b : []; }),
1593
1642
  ];
1643
+ if (repos.length === 0) {
1644
+ return undefined;
1645
+ }
1594
1646
  return parseCursorOriginRepoScope(repos);
1595
1647
  }
1596
1648
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cursor/july",
3
- "version": "0.1.78",
3
+ "version": "0.1.80",
4
4
  "description": "(early alpha) Filesystem-first framework for defining Cursor agents as markdown and TypeScript and serving them over channels with the Cursor SDK.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "repository": {
@@ -20,6 +20,7 @@ import {
20
20
  import {
21
21
  type CursorAccountGithubTokenResolver,
22
22
  getCursorAccountGithubProxyTransport,
23
+ githubRepoFromOctokitRequest,
23
24
  isCursorAccountGithubTokenResolver,
24
25
  } from "./cursor-account.js";
25
26
  import type { GitHubChannelCredentials } from "./types.js";
@@ -121,6 +122,13 @@ export async function createGitHubOctokit(input: {
121
122
  request.headers.authorization = `Bearer ${token}`;
122
123
  if (proxyTransport !== undefined) {
123
124
  Object.assign(request.headers, proxyTransport.headers);
125
+ const existingRepos = request.headers["x-cursor-github-repos"];
126
+ if (typeof existingRepos !== "string" || existingRepos.trim() === "") {
127
+ const repo = githubRepoFromOctokitRequest(request);
128
+ if (repo !== undefined) {
129
+ request.headers["x-cursor-github-repos"] = repo;
130
+ }
131
+ }
124
132
  }
125
133
  });
126
134
  return octokit;
@@ -77,6 +77,62 @@ export function parseCursorGithubPermissions(
77
77
  );
78
78
  }
79
79
 
80
+ /**
81
+ * `owner/repo` from an Octokit request, for github-proxy calls that have no
82
+ * static `x-cursor-github-repos` header (`cursorAccount: true` with no
83
+ * `--repo` / channel `{ repos }`).
84
+ */
85
+ export function githubRepoFromOctokitRequest(request: {
86
+ owner?: unknown;
87
+ repo?: unknown;
88
+ url?: unknown;
89
+ }): string | undefined {
90
+ if (typeof request.owner === "string" && typeof request.repo === "string") {
91
+ const slug = `${request.owner.trim()}/${request.repo.trim()}`.toLowerCase();
92
+ if (CURSOR_GITHUB_REPO_PATTERN.test(slug) && !slug.includes("..")) {
93
+ return slug;
94
+ }
95
+ }
96
+ if (typeof request.url !== "string") {
97
+ return undefined;
98
+ }
99
+ const match = request.url.match(/\/repos\/([^/?#]+)\/([^/?#]+)/);
100
+ const owner = match?.[1]?.trim() ?? "";
101
+ const repo = match?.[2]?.trim() ?? "";
102
+ if (
103
+ owner === "" ||
104
+ repo === "" ||
105
+ owner.includes("{") ||
106
+ repo.includes("{")
107
+ ) {
108
+ return undefined;
109
+ }
110
+ const slug = `${owner}/${repo}`.toLowerCase();
111
+ if (!CURSOR_GITHUB_REPO_PATTERN.test(slug) || slug.includes("..")) {
112
+ return undefined;
113
+ }
114
+ return slug;
115
+ }
116
+
117
+ /**
118
+ * Merge `--repo` / channel-declared repos into a lease scope. Empty is
119
+ * valid for `cursorAccount: true`: hosted engines that pull events from
120
+ * the deployment stream (no `--cursor-events --repo`) still start, and
121
+ * github-proxy fills `x-cursor-github-repos` per Octokit call.
122
+ */
123
+ export function resolveCursorGithubCredentialScope(
124
+ values: readonly string[],
125
+ permissions: CursorGithubPermissions = "pr-write"
126
+ ): CursorGithubRepoScope | undefined {
127
+ const repos = [
128
+ ...new Set(values.map((repo) => repo.trim().toLowerCase()).filter(Boolean)),
129
+ ];
130
+ if (repos.length === 0) {
131
+ return undefined;
132
+ }
133
+ return parseCursorGithubRepoScope(repos, permissions);
134
+ }
135
+
80
136
  export function parseCursorGithubRepoScope(
81
137
  values: readonly string[],
82
138
  permissions: CursorGithubPermissions = "pr-write"