@cursor/july 0.1.55 → 0.1.61
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.
- package/dist/bin/agent-serve.js +30 -23
- package/dist/channels/github/github-channel.d.ts +12 -0
- package/dist/channels/github/github-channel.d.ts.map +1 -1
- package/dist/channels/github/github-channel.js +67 -15
- package/dist/channels/github/types.d.ts +27 -1
- package/dist/channels/github/types.d.ts.map +1 -1
- package/dist/channels/origin/cursor-account.d.ts +22 -0
- package/dist/channels/origin/cursor-account.d.ts.map +1 -0
- package/dist/channels/origin/cursor-account.js +35 -0
- package/dist/channels/origin/events.d.ts +10 -0
- package/dist/channels/origin/events.d.ts.map +1 -0
- package/dist/channels/origin/events.js +27 -0
- package/dist/channels/origin/index.d.ts +29 -0
- package/dist/channels/origin/index.d.ts.map +1 -0
- package/dist/channels/origin/index.js +28 -0
- package/dist/channels/origin/origin-channel.d.ts +68 -0
- package/dist/channels/origin/origin-channel.d.ts.map +1 -0
- package/dist/channels/origin/origin-channel.js +567 -0
- package/dist/channels/origin/origin-webhook.d.ts +38 -0
- package/dist/channels/origin/origin-webhook.d.ts.map +1 -0
- package/dist/channels/origin/origin-webhook.js +151 -0
- package/dist/channels/origin/types.d.ts +152 -0
- package/dist/channels/origin/types.d.ts.map +1 -0
- package/dist/channels/origin/types.js +1 -0
- package/dist/channels/slack/doctor.d.ts +17 -1
- package/dist/channels/slack/doctor.d.ts.map +1 -1
- package/dist/channels/slack/doctor.js +186 -10
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +4 -4
- package/dist/docs/assets/{app.CVQxhV85.js → app.CW3KJh72.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.BuymfBAo.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.QAPzJjql.js → VPLocalSearchBox.Bk6EWpPj.js} +1 -1
- package/dist/docs/assets/chunks/{theme.CSxTCOFu.js → theme.Bz9AodBA.js} +2 -2
- package/dist/docs/assets/{example-agents_fsd.md.DPz9ezO4.js → example-agents_fsd.md.ZeGEpAw_.js} +2 -2
- package/dist/docs/assets/{example-agents_fsd.md.DPz9ezO4.lean.js → example-agents_fsd.md.ZeGEpAw_.lean.js} +1 -1
- package/dist/docs/assets/{example-agents_security-reviewer.md.Dkf1gyo6.js → example-agents_security-reviewer.md.DBL1TwtP.js} +2 -2
- package/dist/docs/assets/{example-agents_security-reviewer.md.Dkf1gyo6.lean.js → example-agents_security-reviewer.md.DBL1TwtP.lean.js} +1 -1
- package/dist/docs/assets/guides_convert-automation.md.BhMzTkE5.js +12 -0
- package/dist/docs/assets/guides_convert-automation.md.BhMzTkE5.lean.js +1 -0
- package/dist/docs/assets/{guides_github.md.B8QKtIpw.js → guides_github.md.CLLQJKRB.js} +4 -4
- package/dist/docs/assets/{guides_github.md.B8QKtIpw.lean.js → guides_github.md.CLLQJKRB.lean.js} +1 -1
- package/dist/docs/assets/index.md.DhRHS_-L.js +5 -0
- package/dist/docs/assets/{index.md.COeoSkcF.lean.js → index.md.DhRHS_-L.lean.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.D_CCfG8R.js → reference_cli.md.Cl14Jfo3.js} +8 -2
- package/dist/docs/assets/{reference_cli.md.D_CCfG8R.lean.js → reference_cli.md.Cl14Jfo3.lean.js} +1 -1
- package/dist/docs/assets/scaffolding-agents.md.CrWSA0Ko.js +1 -0
- package/dist/docs/assets/{scaffolding-agents.md.mkc3B_ZW.lean.js → scaffolding-agents.md.CrWSA0Ko.lean.js} +1 -1
- package/dist/docs/assets/templates_agentic-owners.md.BkTLORaU.js +14 -0
- package/dist/docs/assets/templates_agentic-owners.md.BkTLORaU.lean.js +1 -0
- package/dist/docs/assets/templates_demo.md.Bgd6MBaZ.js +4 -0
- package/dist/docs/assets/templates_demo.md.Bgd6MBaZ.lean.js +1 -0
- package/dist/docs/assets/templates_pr-autofixer.md.DcmoeUNZ.js +8 -0
- package/dist/docs/assets/templates_pr-autofixer.md.DcmoeUNZ.lean.js +1 -0
- package/dist/docs/assets/templates_security-reviewer.md.C0yIUaYs.js +2 -0
- package/dist/docs/assets/templates_security-reviewer.md.C0yIUaYs.lean.js +1 -0
- package/dist/docs/building-with-agents.html +4 -4
- package/dist/docs/concepts.html +5 -5
- package/dist/docs/deployment.html +4 -4
- package/dist/docs/evals.html +4 -4
- package/dist/docs/example-agents/approval-buddy.html +4 -4
- package/dist/docs/example-agents/benny.html +4 -4
- package/dist/docs/example-agents/bugbot.html +4 -4
- package/dist/docs/example-agents/codebase-wiki.html +4 -4
- package/dist/docs/example-agents/codeowners-review.html +4 -4
- package/dist/docs/example-agents/concierge.html +4 -4
- package/dist/docs/example-agents/fsd.html +5 -5
- package/dist/docs/example-agents/index.html +4 -4
- package/dist/docs/example-agents/knowledge-base.html +4 -4
- package/dist/docs/example-agents/oncall.html +4 -4
- package/dist/docs/example-agents/security-reviewer.html +5 -5
- package/dist/docs/example-agents/slack-agent.html +4 -4
- package/dist/docs/example-agents/weather-agent.html +4 -4
- package/dist/docs/guides/agent-to-agent.html +4 -4
- package/dist/docs/guides/cloud-runtime.html +4 -4
- package/dist/docs/guides/convert-automation.html +36 -0
- package/dist/docs/guides/github.html +7 -7
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/mcp-oauth.html +4 -4
- package/dist/docs/guides/opentelemetry.html +4 -4
- package/dist/docs/guides/slack.html +4 -4
- package/dist/docs/guides/webhooks.html +4 -4
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +4 -4
- package/dist/docs/index.html +6 -6
- package/dist/docs/quickstart.html +4 -4
- package/dist/docs/reference/agent-config.html +4 -4
- package/dist/docs/reference/artifacts.html +4 -4
- package/dist/docs/reference/channels.html +4 -4
- package/dist/docs/reference/cli.html +12 -6
- package/dist/docs/reference/connections.html +4 -4
- package/dist/docs/reference/hooks.html +4 -4
- package/dist/docs/reference/http-api.html +4 -4
- package/dist/docs/reference/instructions.html +4 -4
- package/dist/docs/reference/playground.html +4 -4
- package/dist/docs/reference/project-layout.html +4 -4
- package/dist/docs/reference/prompt.html +4 -4
- package/dist/docs/reference/schedules.html +4 -4
- package/dist/docs/reference/sessions.html +4 -4
- package/dist/docs/reference/skills.html +4 -4
- package/dist/docs/reference/subagents.html +4 -4
- package/dist/docs/reference/tools.html +4 -4
- package/dist/docs/scaffolding-agents.html +5 -5
- package/dist/docs/storage.html +4 -4
- package/dist/docs/templates/agentic-owners.html +38 -0
- package/dist/docs/templates/demo.html +28 -0
- package/dist/docs/templates/pr-autofixer.html +32 -0
- package/dist/docs/templates/security-reviewer.html +26 -0
- package/dist/docs/templates/triage.html +5 -5
- package/dist/docs/troubleshooting.html +4 -4
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/internal/cli-ax.d.ts +2 -0
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +20 -0
- package/dist/internal/cli-slack.d.ts +2 -0
- package/dist/internal/cli-slack.d.ts.map +1 -1
- package/dist/internal/cli-slack.js +11 -2
- package/dist/internal/cursor-event-relay.d.ts +59 -11
- package/dist/internal/cursor-event-relay.d.ts.map +1 -1
- package/dist/internal/cursor-event-relay.js +133 -26
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +11 -2
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +1 -0
- package/dist/internal/handleAgentServeTrigger.d.ts +33 -6
- package/dist/internal/handleAgentServeTrigger.d.ts.map +1 -1
- package/dist/internal/handleAgentServeTrigger.js +97 -19
- package/dist/internal/init-interview.d.ts +67 -0
- package/dist/internal/init-interview.d.ts.map +1 -0
- package/dist/internal/init-interview.js +300 -0
- package/dist/internal/init-project.d.ts +4 -0
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +40 -16
- package/dist/internal/mcp-endpoint.d.ts +7 -0
- package/dist/internal/mcp-endpoint.d.ts.map +1 -1
- package/dist/internal/mcp-endpoint.js +7 -0
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +159 -57
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +20 -21
- package/dist/internal/session-links.d.ts +14 -0
- package/dist/internal/session-links.d.ts.map +1 -0
- package/dist/internal/session-links.js +69 -0
- package/dist/internal/sessions-client.d.ts.map +1 -1
- package/dist/internal/sessions-client.js +1 -0
- package/dist/playground/assets/index-ClbuaLpm.css +1 -0
- package/dist/playground/assets/{index-0oqXUkrR.js → index-SqkR13k_.js} +39 -39
- package/dist/playground/index.html +2 -2
- package/dist/types.d.ts +19 -12
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +15 -0
- package/docs/example-agents/fsd.md +3 -0
- package/docs/example-agents/security-reviewer.md +3 -0
- package/docs/guides/convert-automation.md +176 -0
- package/docs/guides/github.md +6 -2
- package/docs/reference/cli.md +34 -10
- package/docs/scaffolding-agents.md +3 -0
- package/docs/templates/agentic-owners.md +97 -0
- package/docs/templates/demo.md +84 -0
- package/docs/templates/pr-autofixer.md +136 -0
- package/docs/templates/security-reviewer.md +89 -0
- package/package.json +9 -1
- package/skills/github/SKILL.md +4 -5
- package/src/bin/agent-serve.ts +13 -6
- package/src/channels/github/github-channel.ts +95 -18
- package/src/channels/github/types.ts +31 -0
- package/src/channels/origin/cursor-account.ts +64 -0
- package/src/channels/origin/events.ts +41 -0
- package/src/channels/origin/index.ts +29 -0
- package/src/channels/origin/origin-channel.ts +784 -0
- package/src/channels/origin/origin-webhook.ts +202 -0
- package/src/channels/origin/types.ts +186 -0
- package/src/channels/slack/doctor.ts +218 -5
- package/src/index.ts +3 -1
- package/src/internal/cli-ax.ts +23 -0
- package/src/internal/cli-slack.ts +11 -1
- package/src/internal/cursor-event-relay.ts +193 -31
- package/src/internal/discovery.ts +15 -5
- package/src/internal/distribution.ts +1 -0
- package/src/internal/handleAgentServeTrigger.ts +129 -19
- package/src/internal/init-interview.ts +384 -0
- package/src/internal/init-project.ts +70 -15
- package/src/internal/mcp-endpoint.ts +7 -0
- package/src/internal/server.ts +188 -58
- package/src/internal/session-engine.ts +5 -21
- package/src/internal/session-links.ts +88 -0
- package/src/internal/sessions-client.ts +1 -0
- package/src/types.ts +19 -12
- package/templates/agentic-owners/README.md +73 -0
- package/templates/agentic-owners/agent/agent.ts +15 -0
- package/templates/agentic-owners/agent/channels/github.ts +85 -0
- package/templates/agentic-owners/agent/instructions.md +34 -0
- package/templates/agentic-owners/agent/lib/config.ts +13 -0
- package/templates/agentic-owners/agent/lib/github.ts +241 -0
- package/templates/agentic-owners/agent/lib/owners/README.md +50 -0
- package/templates/agentic-owners/agent/lib/owners/constants.ts +22 -0
- package/templates/agentic-owners/agent/lib/owners/decision.ts +485 -0
- package/templates/agentic-owners/agent/lib/owners/handles.ts +54 -0
- package/templates/agentic-owners/agent/lib/owners/match.ts +177 -0
- package/templates/agentic-owners/agent/lib/owners/matching.ts +95 -0
- package/templates/agentic-owners/agent/lib/owners/parse.ts +589 -0
- package/templates/agentic-owners/agent/lib/owners/policyMode.ts +65 -0
- package/templates/agentic-owners/agent/lib/owners/prompt.ts +66 -0
- package/templates/agentic-owners/agent/lib/owners/prompts/base-review.md +105 -0
- package/templates/agentic-owners/agent/lib/owners/types.ts +45 -0
- package/templates/agentic-owners/agent/lib/review.ts +777 -0
- package/templates/agentic-owners/agent/tools/record_review.ts +69 -0
- package/templates/agentic-owners/evals/evals.config.ts +5 -0
- package/templates/agentic-owners/evals/owners.eval.ts +116 -0
- package/templates/agentic-owners/package.json +20 -0
- package/templates/agentic-owners/tsconfig.json +12 -0
- package/templates/demo/README.md +33 -0
- package/templates/demo/agent/agent.ts +15 -0
- package/templates/demo/agent/channels/github.ts +50 -0
- package/templates/demo/agent/channels/queue.ts +30 -0
- package/templates/demo/agent/instructions.md +8 -0
- package/templates/demo/agent/lib/collect.ts +78 -0
- package/templates/demo/agent/tools/record_demo.ts +40 -0
- package/templates/demo/evals/demo.eval.ts +33 -0
- package/templates/demo/evals/evals.config.ts +5 -0
- package/templates/demo/package.json +18 -0
- package/templates/demo/tsconfig.json +12 -0
- package/templates/pr-autofixer/README.md +44 -0
- package/templates/pr-autofixer/agent/agent.ts +22 -0
- package/templates/pr-autofixer/agent/channels/drive.ts +40 -0
- package/templates/pr-autofixer/agent/channels/github.ts +167 -0
- package/templates/pr-autofixer/agent/channels/slack.ts +17 -0
- package/templates/pr-autofixer/agent/hooks/bind-agent.ts +19 -0
- package/templates/pr-autofixer/agent/instructions.md +83 -0
- package/templates/pr-autofixer/agent/lib/affinity.ts +33 -0
- package/templates/pr-autofixer/agent/lib/drive-schemas.ts +15 -0
- package/templates/pr-autofixer/agent/lib/drive.ts +79 -0
- package/templates/pr-autofixer/agent/lib/merge-watch.ts +123 -0
- package/templates/pr-autofixer/agent/lib/pr-state.ts +54 -0
- package/templates/pr-autofixer/agent/lib/repos.ts +19 -0
- package/templates/pr-autofixer/agent/lib/start-drive.ts +122 -0
- package/templates/pr-autofixer/agent/lib/webhook-buffer.ts +225 -0
- package/templates/pr-autofixer/agent/lib/webhook-routing.ts +231 -0
- package/templates/pr-autofixer/agent/storage.ts +7 -0
- package/templates/pr-autofixer/agent/tools/drive_pr.ts +22 -0
- package/templates/pr-autofixer/evals/coordinator.eval.ts +16 -0
- package/templates/pr-autofixer/evals/evals.config.ts +5 -0
- package/templates/pr-autofixer/init.json +25 -0
- package/templates/pr-autofixer/package.json +18 -0
- package/templates/pr-autofixer/tsconfig.json +12 -0
- package/templates/security-reviewer/README.md +31 -0
- package/templates/security-reviewer/agent/agent.ts +15 -0
- package/templates/security-reviewer/agent/channels/github.ts +46 -0
- package/templates/security-reviewer/agent/instructions.md +22 -0
- package/templates/security-reviewer/agent/lib/repos.ts +5 -0
- package/templates/security-reviewer/agent/tools/post_findings.ts +72 -0
- package/templates/security-reviewer/evals/evals.config.ts +5 -0
- package/templates/security-reviewer/evals/review.eval.ts +53 -0
- package/templates/security-reviewer/init.json +25 -0
- package/templates/security-reviewer/package.json +18 -0
- package/templates/security-reviewer/tsconfig.json +12 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.BFpWSo6D.js +0 -1
- package/dist/docs/assets/index.md.COeoSkcF.js +0 -5
- package/dist/docs/assets/scaffolding-agents.md.mkc3B_ZW.js +0 -1
- package/dist/playground/assets/index-tHCjJxv4.css +0 -1
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Review pull requests with owners policies"
|
|
3
|
+
description: "Scaffold the agent, commit .agentic-owners policies, and let it risk-tier PRs, request the owners, and approve what the policy allows."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Review pull requests with owners policies
|
|
7
|
+
|
|
8
|
+
This agent reviews every pull request in your repository. It risk-tiers
|
|
9
|
+
the diff, requests the owning team or user as reviewers, and approves
|
|
10
|
+
what your policy allows. Ownership rules live in
|
|
11
|
+
`.agentic-owners/policy.yml` files committed at any depth of the repo;
|
|
12
|
+
the closest policy to a changed file wins, and policies are always read
|
|
13
|
+
from the PR's base ref so a PR cannot exempt itself.
|
|
14
|
+
|
|
15
|
+
## Scaffold
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx @cursor/july init ./owners-agent --template agentic-owners
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`init` writes the project, installs dependencies, and puts `agent-sdk`
|
|
22
|
+
on PATH.
|
|
23
|
+
|
|
24
|
+
## Log in and run
|
|
25
|
+
|
|
26
|
+
Set your repositories in `agent/lib/config.ts` (`repos: ["you/your-repo"]`),
|
|
27
|
+
then:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
cd owners-agent
|
|
31
|
+
agent-sdk login
|
|
32
|
+
agent-sdk dev
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
PR events stream through your Cursor account — no webhook or GitHub App
|
|
36
|
+
setup. Open a PR, or replay a real one deterministically (this also works
|
|
37
|
+
with `repos` empty):
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
agent-sdk github replay https://github.com/you/your-repo/pull/123 --dir .
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Deploy with `agent-sdk deploy`.
|
|
44
|
+
|
|
45
|
+
## Policies
|
|
46
|
+
|
|
47
|
+
With no policy files, every PR gets a default risk review: very-low and
|
|
48
|
+
low risk approve, medium and above hold with a comment. Route reviews by
|
|
49
|
+
committing policies:
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
# .agentic-owners/policy.yml — anywhere in the repo; closest wins.
|
|
53
|
+
# paths are repo-root-relative globs, wherever the policy file lives.
|
|
54
|
+
version: 1
|
|
55
|
+
policies:
|
|
56
|
+
- paths: ["docs/**"]
|
|
57
|
+
always_approve: true
|
|
58
|
+
- paths: ["src/api/**"]
|
|
59
|
+
team: acme/platform # or user: alice
|
|
60
|
+
prompt: api-review.md # optional extra rubric, same directory
|
|
61
|
+
- paths: ["src/billing/**"]
|
|
62
|
+
user: alice
|
|
63
|
+
human_review_required: true # the agent never approves; a person must
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`self_review: true` lets a listed owner's own PRs clear their rule.
|
|
67
|
+
`global_exclusions` in the root policy opts paths out entirely.
|
|
68
|
+
|
|
69
|
+
## What one review does
|
|
70
|
+
|
|
71
|
+
One model turn per PR head assesses the host-fetched diff against the
|
|
72
|
+
base rubric plus any matched rule prompts, then records a verdict with
|
|
73
|
+
`record_review`. The host recomputes the policy from trusted state and
|
|
74
|
+
applies the deterministic decision:
|
|
75
|
+
|
|
76
|
+
- **Approve** when the tier is low and no matched rule demands a human,
|
|
77
|
+
bound to the head SHA.
|
|
78
|
+
- **Request reviewers** otherwise — the policy owners (max 2, never the
|
|
79
|
+
author), plus one status comment the agent keeps updated in place.
|
|
80
|
+
|
|
81
|
+
The model never writes to GitHub. A broken policy file fails closed with
|
|
82
|
+
a comment listing the validation issues.
|
|
83
|
+
|
|
84
|
+
## Rubric
|
|
85
|
+
|
|
86
|
+
Edit `agent/lib/owners/prompts/base-review.md` for the risk tiers and
|
|
87
|
+
their boundaries. Per-area guidance belongs in policy `prompt:` files
|
|
88
|
+
next to the policy that names them. The next review reads both.
|
|
89
|
+
|
|
90
|
+
## Evals
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
agent-sdk eval
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Three smoke reviews (docs-only, auth deletion, prompt injection). Eval
|
|
97
|
+
sessions skip GitHub writes.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Record a walkthrough from a collected PR"
|
|
3
|
+
description: "Scaffold the agent, seed the PR on the host, record a walkthrough, and comment the result."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Record a walkthrough from a collected PR
|
|
7
|
+
|
|
8
|
+
This agent records a walkthrough for a pull request you already opened.
|
|
9
|
+
The host fetches title, body, and files, writes `pr.md` and `files.md`,
|
|
10
|
+
then starts the turn. The model reads those files. It does not fetch
|
|
11
|
+
the PR.
|
|
12
|
+
|
|
13
|
+
## Scaffold
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx @cursor/july init ./demo-agent --template demo
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`init` writes the project, installs dependencies, and puts `agent-sdk`
|
|
20
|
+
on PATH.
|
|
21
|
+
|
|
22
|
+
## Log in
|
|
23
|
+
|
|
24
|
+
Model turns use your Cursor account.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
cd demo-agent
|
|
28
|
+
agent-sdk login
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The command opens a browser if you have no stored credential.
|
|
32
|
+
|
|
33
|
+
## Collect the PR
|
|
34
|
+
|
|
35
|
+
The host needs GitHub credentials so it can read the PR and comment:
|
|
36
|
+
`GITHUB_TOKEN`, `GH_TOKEN`, or `gh auth`.
|
|
37
|
+
|
|
38
|
+
In the playground, run `/queue/pr` and paste a PR URL or `owner/repo#N`.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
curl -X POST http://127.0.0.1:3000/demo-agent/v1/channels/queue/pr \
|
|
42
|
+
-H 'content-type: application/json' \
|
|
43
|
+
-d '{ "pr": "acme/shop#42" }'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The host fetches title, body, and files, writes `pr.md` and `files.md`,
|
|
47
|
+
and starts the turn. Retries coalesce on `pr:owner/repo#N`.
|
|
48
|
+
|
|
49
|
+
GitHub label `demo` or comment `/demo` when you terminate webhooks
|
|
50
|
+
yourself: self-host and set `GITHUB_WEBHOOK_SECRET`. Hosted Cursor
|
|
51
|
+
aliases require `X-Agent-Alias-Token`, which GitHub cannot send.
|
|
52
|
+
|
|
53
|
+
`record_demo` comments on that key. Eval sessions skip the comment.
|
|
54
|
+
|
|
55
|
+
## First walkthrough
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
agent-sdk dev
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Open the playground. Run `/queue/pr` with a PR. The model reads the
|
|
62
|
+
seeded files and calls `record_demo` once. Turns are sandboxed with
|
|
63
|
+
`read` and `grep` only: PR title and body are untrusted.
|
|
64
|
+
|
|
65
|
+
## Evals
|
|
66
|
+
|
|
67
|
+
One smoke case. The host seeds `pr.md` and `files.md`. No GitHub call.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
agent-sdk eval
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Deploy
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
agent-sdk deploy
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Run it from the agent's git checkout. It infers repository, ref, path,
|
|
80
|
+
and slug, builds on Cursor-managed hosting, and prints the URL.
|
|
81
|
+
`agent-sdk deployments` shows status.
|
|
82
|
+
|
|
83
|
+
Playground and `/queue/pr` need the alias token. GitHub label and
|
|
84
|
+
`/demo` stay on a self-hosted agent with a webhook secret.
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Fix pull requests on a Cursor cloud VM"
|
|
3
|
+
description: "Scaffold the agent, point it at your repos, and opt in to auto-fix a PR."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Fix pull requests on a Cursor cloud VM
|
|
7
|
+
|
|
8
|
+
This agent coordinates from chat and Slack, then hands each opted-in
|
|
9
|
+
pull request to a Cursor cloud VM with a real checkout. The same cloud
|
|
10
|
+
conversation resumes when you drive the PR again, GitHub reports a
|
|
11
|
+
change on that PR, or a merge-conflict reminder fires.
|
|
12
|
+
|
|
13
|
+
Chat never has the target checkout. `gh` and `git` run on the VM.
|
|
14
|
+
Opening a pull request does not start a session. Drive a PR from the
|
|
15
|
+
playground, Slack, or HTTP to opt in. After that, the agent auto-fixes:
|
|
16
|
+
it pushes verified fixes to the PR head and performs workflow actions.
|
|
17
|
+
It never merges, enables auto-merge, or force-pushes.
|
|
18
|
+
|
|
19
|
+
## Scaffold
|
|
20
|
+
|
|
21
|
+
On a TTY, `init` asks which GitHub repos to watch. Scripts pass the
|
|
22
|
+
same answer with `--var`:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx @cursor/july init ./pr-autofixer --template pr-autofixer
|
|
26
|
+
npx @cursor/july init ./pr-autofixer --template pr-autofixer \
|
|
27
|
+
--var repos=acme/widgets,acme/api --json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`init` writes the project, installs dependencies, and puts `agent-sdk`
|
|
31
|
+
on PATH. You can still edit `agent/lib/repos.ts` later, or override the
|
|
32
|
+
list with `PR_AUTOFIXER_REPOS`.
|
|
33
|
+
|
|
34
|
+
## Log in
|
|
35
|
+
|
|
36
|
+
Model turns and cloud agents use your Cursor account.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cd pr-autofixer
|
|
40
|
+
agent-sdk login
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The command opens a browser if you have no stored credential. Cloud
|
|
44
|
+
turns spend cloud-agent budget under that account.
|
|
45
|
+
|
|
46
|
+
## Point it at a repo
|
|
47
|
+
|
|
48
|
+
`init` writes the repo list into `agent/lib/repos.ts`. One owner. Up to
|
|
49
|
+
20 repos. The GitHub channel requests `contents-write` so the agent can
|
|
50
|
+
push to the PR head.
|
|
51
|
+
|
|
52
|
+
## First drive
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
agent-sdk dev
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Open the playground. Paste a PR URL or `owner/repo#N`. The local
|
|
59
|
+
agent calls `drive_pr`, which attaches the PR to a cloud session and
|
|
60
|
+
returns when that session exists. Autofix continues in the background.
|
|
61
|
+
`bcId` / `agentUrl` are included when already bound.
|
|
62
|
+
|
|
63
|
+
You can also POST:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
curl -X POST http://127.0.0.1:3000/pr-autofixer/v1/channels/drive \
|
|
67
|
+
-H 'content-type: application/json' \
|
|
68
|
+
-d '{
|
|
69
|
+
"pr": "https://github.com/acme/widgets/pull/1"
|
|
70
|
+
}'
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
HTTP and `drive_pr` both return when the session exists, not when
|
|
74
|
+
triage finishes. `bcId` / `agentUrl` are included when already bound.
|
|
75
|
+
|
|
76
|
+
A merged or closed PR returns `status: "finished"` and does not start
|
|
77
|
+
a session.
|
|
78
|
+
|
|
79
|
+
The VM starts from the PR base. The agent creates `autofix/pr-<N>` off
|
|
80
|
+
the PR head the first time it needs code, then pushes verified fixes
|
|
81
|
+
with `git push origin HEAD:<headRef>`. Workflow actions run through
|
|
82
|
+
`gh`. `autoCreatePR` is off, so the agent never opens a new PR.
|
|
83
|
+
|
|
84
|
+
## GitHub wakes
|
|
85
|
+
|
|
86
|
+
Mounted at `/v1/channels/github`. Cursor relays pull request, comment,
|
|
87
|
+
review, check, and failing status events for the repos you listed. A
|
|
88
|
+
wake only starts or resumes a cloud conversation after that PR has been
|
|
89
|
+
driven. `pull_request.opened` is ignored. A PR comment or review on an
|
|
90
|
+
opted-in PR wakes the agent. A comment on a plain GitHub issue does
|
|
91
|
+
not. The channel buffers about 3 seconds per PR. Payload details are
|
|
92
|
+
dropped on purpose. The follow-up says something changed.
|
|
93
|
+
|
|
94
|
+
Pending wakes snapshot to `host.kv` (`webhook-buffer`) before the
|
|
95
|
+
webhook is ACKed, and restore on restart. Affinity is
|
|
96
|
+
`affinity/{owner/repo#N}` → `bc-…` in the same store, written from
|
|
97
|
+
`agent.bound`. `agent/storage.ts` uses `cursorHostedStorage`, so both
|
|
98
|
+
survive host replace. Local serve without that plug-in falls back to
|
|
99
|
+
`--state-root/kv`.
|
|
100
|
+
|
|
101
|
+
Closing a PR cancels its merge-conflict reminder and drops buffered
|
|
102
|
+
wakes.
|
|
103
|
+
|
|
104
|
+
See [GitHub](../guides/github.md) for `cursorAccount` login and
|
|
105
|
+
fixture replay.
|
|
106
|
+
|
|
107
|
+
## Slack
|
|
108
|
+
|
|
109
|
+
`agent/channels/slack.ts` uses your signed-in Cursor account. Mention
|
|
110
|
+
the agent or DM it with a PR URL. Same `drive_pr` path as the
|
|
111
|
+
playground. See [Slack](../guides/slack.md).
|
|
112
|
+
|
|
113
|
+
## Evals
|
|
114
|
+
|
|
115
|
+
One smoke case. Chat without a PR must not call `drive_pr`, so a
|
|
116
|
+
routine eval cannot spawn a cloud agent.
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
agent-sdk eval
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Do not add cases that pass a PR URL unless you intend to spend cloud
|
|
123
|
+
budget.
|
|
124
|
+
|
|
125
|
+
## Deploy
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
agent-sdk deploy
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Run it from the agent's git checkout. It infers repository, ref, path,
|
|
132
|
+
and slug, builds on Cursor-managed hosting, and prints the URL.
|
|
133
|
+
`agent-sdk deployments` shows status.
|
|
134
|
+
|
|
135
|
+
See [Cloud runtime](../guides/cloud-runtime.md) for what changes on
|
|
136
|
+
the VM.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Review pull requests for exploitable bugs"
|
|
3
|
+
description: "Scaffold the agent, pick repos, replay a PR, and deploy."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Review pull requests for exploitable bugs
|
|
7
|
+
|
|
8
|
+
This agent reads a pull request diff and posts one review comment. It
|
|
9
|
+
reports exploitable bugs: injection, authz bypass, secret leaks, SSRF,
|
|
10
|
+
RCE. Style nits stay out.
|
|
11
|
+
|
|
12
|
+
The factory [Security Reviewer](../example-agents/security-reviewer.md)
|
|
13
|
+
runs a staged pipeline with parallel workers. This template is one
|
|
14
|
+
model turn.
|
|
15
|
+
|
|
16
|
+
## Scaffold
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx @cursor/july init ./security-reviewer --template security-reviewer
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`init` asks which GitHub repos to watch. Every repo must share one
|
|
23
|
+
owner. Pass `--var repos=acme/api,acme/web` to skip the prompt.
|
|
24
|
+
|
|
25
|
+
The list lands in `agent/lib/repos.ts`. The GitHub channel reads it for
|
|
26
|
+
`cursorAccount` and for the wake filter. Edit that file when the set
|
|
27
|
+
changes.
|
|
28
|
+
|
|
29
|
+
## Connect GitHub through Cursor
|
|
30
|
+
|
|
31
|
+
Connect GitHub in Cursor for those repositories (Settings or
|
|
32
|
+
[cursor.com/dashboard](https://cursor.com/dashboard)). Sign the host in:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
cd security-reviewer
|
|
36
|
+
agent-sdk login
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`cursorAccount` pulls SCM events from Cursor and mints a short-lived,
|
|
40
|
+
repo-scoped credential. `ctx.host.github` and child `gh` commands share
|
|
41
|
+
it. See the [GitHub guide](../guides/github.md).
|
|
42
|
+
|
|
43
|
+
## First review
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
agent-sdk dev
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`dev` starts the Cursor event relay for the watched repos. To drive a
|
|
50
|
+
known PR without waiting on a live push:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
agent-sdk github replay https://github.com/acme/api/pull/12 --dir .
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`replay` needs pull access. Draft PRs and repos outside
|
|
57
|
+
`agent/lib/repos.ts` are ignored. The channel writes `pr/diff.patch`
|
|
58
|
+
after the wake is acknowledged, then starts a model turn. The model
|
|
59
|
+
calls `post_findings` once.
|
|
60
|
+
|
|
61
|
+
Chat replies stay in the playground. `post_findings` writes the GitHub
|
|
62
|
+
comment.
|
|
63
|
+
|
|
64
|
+
## What to edit
|
|
65
|
+
|
|
66
|
+
- `agent/lib/repos.ts`: watched repos
|
|
67
|
+
- `agent/instructions.md`: what counts as a finding and the comment
|
|
68
|
+
shape
|
|
69
|
+
- `evals/review.eval.ts`: smoke cases
|
|
70
|
+
|
|
71
|
+
## Evals
|
|
72
|
+
|
|
73
|
+
Two smoke cases: one XSS fixture and one docs-only change.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
agent-sdk eval
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Eval sessions skip the GitHub write.
|
|
80
|
+
|
|
81
|
+
## Deploy
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
agent-sdk deploy
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Run it from the agent's git checkout. The command infers repository,
|
|
88
|
+
ref, path, and slug. The deployment uses the team's Cursor GitHub
|
|
89
|
+
connection for the same watched repos.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cursor/july",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.61",
|
|
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": {
|
|
@@ -70,6 +70,12 @@
|
|
|
70
70
|
"import": "./dist/channels/github/index.js",
|
|
71
71
|
"default": "./dist/channels/github/index.js"
|
|
72
72
|
},
|
|
73
|
+
"./channels/origin": {
|
|
74
|
+
"anysphere-source": "./src/channels/origin/index.ts",
|
|
75
|
+
"types": "./dist/channels/origin/index.d.ts",
|
|
76
|
+
"import": "./dist/channels/origin/index.js",
|
|
77
|
+
"default": "./dist/channels/origin/index.js"
|
|
78
|
+
},
|
|
73
79
|
"./skills": {
|
|
74
80
|
"anysphere-source": "./src/skills.ts",
|
|
75
81
|
"types": "./dist/skills.d.ts",
|
|
@@ -261,6 +267,7 @@
|
|
|
261
267
|
"@types/react-dom": "^19.0.0",
|
|
262
268
|
"@typescript/native-preview": "7.0.0-dev.20260701.1",
|
|
263
269
|
"@vitejs/plugin-react": "^5.1.2",
|
|
270
|
+
"minimatch": "^10.2.5",
|
|
264
271
|
"pg": "^8.18.0",
|
|
265
272
|
"pretty-ms": "^9.2.0",
|
|
266
273
|
"react": "^19.2.1",
|
|
@@ -272,6 +279,7 @@
|
|
|
272
279
|
"vite": "^7.3.0",
|
|
273
280
|
"vitepress": "1.6.4",
|
|
274
281
|
"vitest": "^4.0.18",
|
|
282
|
+
"yaml": "^2.4.2",
|
|
275
283
|
"zustand": "^5.0.9"
|
|
276
284
|
}
|
|
277
285
|
}
|
package/skills/github/SKILL.md
CHANGED
|
@@ -142,12 +142,11 @@ first real delivery.
|
|
|
142
142
|
|
|
143
143
|
- **Debounce per PR** (~3s, latest event wins) and re-buffer while CI
|
|
144
144
|
settles; skip a flush when a turn for that PR is already in flight.
|
|
145
|
-
- **Persist the buffer before ACKing** the webhook
|
|
146
|
-
|
|
147
|
-
start — a restart must not drop buffered wakes.
|
|
145
|
+
- **Persist the buffer before ACKing** the webhook in `host.kv`, then
|
|
146
|
+
restore it on channel start. A restart must not drop buffered wakes.
|
|
148
147
|
- **Stable continuation key** `pr:owner/repo#N` so every wake resumes the
|
|
149
|
-
PR's session
|
|
150
|
-
SDK agent id (write it from an `agent.bound` hook).
|
|
148
|
+
PR's session. Cross-channel resume needs an affinity store mapping PR →
|
|
149
|
+
SDK agent id (write it from an `agent.bound` hook with `ctx.host.kv`).
|
|
151
150
|
- **Discard payload details in wake prompts** — send a generic "re-check
|
|
152
151
|
the PR" refresh; the agent re-reads ground truth instead of trusting a
|
|
153
152
|
stale payload.
|
package/src/bin/agent-serve.ts
CHANGED
|
@@ -108,7 +108,7 @@ Usage:
|
|
|
108
108
|
${CLI} trajectory --events <file.ndjson> [--text]
|
|
109
109
|
${CLI} call <tool> [--input <json>] [--dir <path> | --url <baseUrl> | --prod]
|
|
110
110
|
[--session <id>] [--slug <slug>] [--team <id>]
|
|
111
|
-
${CLI} init [dir] [--template <name>] [--json]
|
|
111
|
+
${CLI} init [dir] [--template <name>] [--var id=value]... [--json]
|
|
112
112
|
${CLI} convert-automation <url> [--dir <path>] [--json]
|
|
113
113
|
${CLI} install-skills [--print] [--json]
|
|
114
114
|
${CLI} mcp --prod [--slug <slug>] [--team <id>] [--dir <path>]
|
|
@@ -198,9 +198,10 @@ Commands:
|
|
|
198
198
|
via POST /v1/tools/:toolName. --session runs it inside an
|
|
199
199
|
existing session and records it on that session's event stream.
|
|
200
200
|
init Scaffold a project (skipping existing files), npm install,
|
|
201
|
-
run login when unsigned, then print next steps.
|
|
202
|
-
|
|
203
|
-
|
|
201
|
+
run login when unsigned, then print next steps. Templates
|
|
202
|
+
with init.json interview on a TTY; --var answers without a
|
|
203
|
+
prompt. --json is machine-readable and never blocks on
|
|
204
|
+
login. No directory: print the setup guide.
|
|
204
205
|
convert-automation
|
|
205
206
|
Export a Cursor Automation into an agentkit project. <url> is
|
|
206
207
|
the dashboard URL (…/automations/<uuid> or
|
|
@@ -481,6 +482,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
481
482
|
options: {
|
|
482
483
|
dir: { type: "string", default: "." },
|
|
483
484
|
template: { type: "string" },
|
|
485
|
+
var: { type: "string", multiple: true },
|
|
484
486
|
port: { type: "string" },
|
|
485
487
|
host: { type: "string" },
|
|
486
488
|
mode: { type: "string" },
|
|
@@ -540,7 +542,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
540
542
|
org: { type: "string" },
|
|
541
543
|
"cursor-events": { type: "boolean", default: false },
|
|
542
544
|
secret: { type: "string" },
|
|
543
|
-
channel: { type: "string" },
|
|
545
|
+
channel: { type: "string", multiple: true },
|
|
544
546
|
install: { type: "boolean", default: false },
|
|
545
547
|
action: { type: "string" },
|
|
546
548
|
conclusion: { type: "string" },
|
|
@@ -594,6 +596,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
594
596
|
prefix: values.prefix,
|
|
595
597
|
noPrefix: values["no-prefix"],
|
|
596
598
|
channelPosts: values["channel-posts"],
|
|
599
|
+
channels: values.channel,
|
|
597
600
|
slackTeam: values["slack-team"],
|
|
598
601
|
prod: values.prod,
|
|
599
602
|
team: values.team,
|
|
@@ -620,7 +623,9 @@ async function main(argv: string[]): Promise<number> {
|
|
|
620
623
|
return cmdGithub(positionals[0], {
|
|
621
624
|
dir,
|
|
622
625
|
slug: values.slug,
|
|
623
|
-
channel
|
|
626
|
+
// `--channel` is repeatable for `slack doctor`; the github
|
|
627
|
+
// subcommands target a single channel, so the last one wins.
|
|
628
|
+
channel: values.channel?.at(-1),
|
|
624
629
|
host: values.host,
|
|
625
630
|
port,
|
|
626
631
|
url: values.url,
|
|
@@ -646,6 +651,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
646
651
|
dir,
|
|
647
652
|
initTarget: positionals[0],
|
|
648
653
|
template: values.template,
|
|
654
|
+
vars: values.var,
|
|
649
655
|
json: values.json,
|
|
650
656
|
});
|
|
651
657
|
}
|
|
@@ -1375,6 +1381,7 @@ function axFromOptions(
|
|
|
1375
1381
|
tags: partial.tags,
|
|
1376
1382
|
evalIds: partial.evalIds,
|
|
1377
1383
|
initTarget: partial.initTarget,
|
|
1384
|
+
vars: partial.vars,
|
|
1378
1385
|
toolName: partial.toolName,
|
|
1379
1386
|
toolInput: partial.toolInput,
|
|
1380
1387
|
url: partial.url,
|
|
@@ -136,6 +136,16 @@ const githubPullRequestPayloadSchema: z.ZodType<GitHubPullRequestPayload> =
|
|
|
136
136
|
sha: z.string().optional(),
|
|
137
137
|
}),
|
|
138
138
|
}),
|
|
139
|
+
changes: z
|
|
140
|
+
.object({
|
|
141
|
+
base: z
|
|
142
|
+
.object({
|
|
143
|
+
ref: z.object({ from: z.string().min(1).optional() }).optional(),
|
|
144
|
+
})
|
|
145
|
+
.optional(),
|
|
146
|
+
})
|
|
147
|
+
.nullable()
|
|
148
|
+
.optional(),
|
|
139
149
|
sender: senderSchema,
|
|
140
150
|
installation: installationSchema,
|
|
141
151
|
label: z
|
|
@@ -184,6 +194,32 @@ export function githubContinuationKey(ctx: GitHubParsedContext): string {
|
|
|
184
194
|
return `${kind}:${ctx.repository.fullName}#${ctx.conversation.number}`;
|
|
185
195
|
}
|
|
186
196
|
|
|
197
|
+
export interface GitHubPullRequestRef {
|
|
198
|
+
owner: string;
|
|
199
|
+
repo: string;
|
|
200
|
+
number: number;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Parse a pull-request continuation key minted by
|
|
205
|
+
* {@link githubContinuationKey} back into its repo + number. Undefined for
|
|
206
|
+
* issue keys and non-GitHub sessions — lets a server tool recover which PR
|
|
207
|
+
* its session is pinned to without trusting model-provided identifiers.
|
|
208
|
+
*/
|
|
209
|
+
export function parseGitHubPrContinuationKey(
|
|
210
|
+
key: string
|
|
211
|
+
): GitHubPullRequestRef | undefined {
|
|
212
|
+
const match = /^github-pr:([^/#\s]+)\/([^#\s]+)#(\d+)$/.exec(key);
|
|
213
|
+
if (match === null) {
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
owner: match[1]!,
|
|
218
|
+
repo: match[2]!,
|
|
219
|
+
number: Number(match[3]!),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
187
223
|
/** @deprecated Prefer {@link githubContinuationKey}. */
|
|
188
224
|
export function githubPullRequestContinuationKey(
|
|
189
225
|
ctx: GitHubParsedContext
|
|
@@ -338,6 +374,9 @@ export function parseGitHubPullRequestEvent(args: {
|
|
|
338
374
|
...(payload.pull_request.base.sha === undefined
|
|
339
375
|
? {}
|
|
340
376
|
: { baseSha: payload.pull_request.base.sha }),
|
|
377
|
+
...(payload.changes?.base?.ref?.from === undefined
|
|
378
|
+
? {}
|
|
379
|
+
: { baseRefChangedFrom: payload.changes.base.ref.from }),
|
|
341
380
|
draft: payload.pull_request.draft ?? false,
|
|
342
381
|
merged: payload.pull_request.merged === true,
|
|
343
382
|
...(payload.pull_request.user?.login === undefined
|
|
@@ -1469,15 +1508,34 @@ async function startTurn(input: {
|
|
|
1469
1508
|
cloud?: AgentCloudOptions;
|
|
1470
1509
|
state: GitHubChannelState;
|
|
1471
1510
|
}): Promise<Response> {
|
|
1472
|
-
const
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1511
|
+
const files = input.dispatch.workspaceFiles;
|
|
1512
|
+
const lazy = typeof files === "function";
|
|
1513
|
+
|
|
1514
|
+
const sendTurn = async () => {
|
|
1515
|
+
const workspaceFiles = lazy ? await files() : files;
|
|
1516
|
+
return input.args.send(input.message, {
|
|
1517
|
+
auth: input.dispatch.auth,
|
|
1518
|
+
continuationToken: githubContinuationKey(input.ctx),
|
|
1519
|
+
title: input.dispatch.title ?? defaultGitHubTitle(input.ctx),
|
|
1520
|
+
...(input.cloud === undefined ? {} : { cloud: input.cloud }),
|
|
1521
|
+
...(workspaceFiles === undefined ? {} : { workspaceFiles }),
|
|
1522
|
+
state: input.state as unknown as JsonValue,
|
|
1523
|
+
// Resume must refresh headSha / refs without wiping sticky banner id.
|
|
1524
|
+
refreshState: input.state as unknown as JsonValue,
|
|
1525
|
+
});
|
|
1526
|
+
};
|
|
1527
|
+
|
|
1528
|
+
if (lazy) {
|
|
1529
|
+
scheduleAfterAck(input.args, async () => {
|
|
1530
|
+
await sendTurn();
|
|
1531
|
+
});
|
|
1532
|
+
return Response.json(
|
|
1533
|
+
{ ok: true, dispatched: true, mode: "turn" },
|
|
1534
|
+
{ status: 202 }
|
|
1535
|
+
);
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
const session = await sendTurn();
|
|
1481
1539
|
return Response.json({
|
|
1482
1540
|
ok: true,
|
|
1483
1541
|
sessionId: session.id,
|
|
@@ -1486,22 +1544,41 @@ async function startTurn(input: {
|
|
|
1486
1544
|
});
|
|
1487
1545
|
}
|
|
1488
1546
|
|
|
1489
|
-
function
|
|
1547
|
+
function reportBackgroundFailure(error: unknown): void {
|
|
1548
|
+
const detail =
|
|
1549
|
+
error instanceof Error ? (error.stack ?? error.message) : String(error);
|
|
1550
|
+
console.error(`[github] background dispatch failed: ${detail}`);
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
function scheduleAfterAck(
|
|
1490
1554
|
args: ChannelHandlerArgs,
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
//
|
|
1495
|
-
// starts (and so tests can assert scheduling without racing microtasks).
|
|
1555
|
+
work: () => void | Promise<void>
|
|
1556
|
+
): void {
|
|
1557
|
+
// Defer past the current turn so the 202 can flush before work starts
|
|
1558
|
+
// (and so tests can assert scheduling without racing microtasks).
|
|
1496
1559
|
args.waitUntil(
|
|
1497
|
-
new Promise<void>((resolve
|
|
1560
|
+
new Promise<void>((resolve) => {
|
|
1498
1561
|
setImmediate(() => {
|
|
1499
1562
|
Promise.resolve()
|
|
1500
|
-
.then(
|
|
1501
|
-
.then(
|
|
1563
|
+
.then(work)
|
|
1564
|
+
.then(
|
|
1565
|
+
() => resolve(),
|
|
1566
|
+
(error: unknown) => {
|
|
1567
|
+
reportBackgroundFailure(error);
|
|
1568
|
+
resolve();
|
|
1569
|
+
}
|
|
1570
|
+
);
|
|
1502
1571
|
});
|
|
1503
1572
|
})
|
|
1504
1573
|
);
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
function acknowledgeTask(
|
|
1577
|
+
args: ChannelHandlerArgs,
|
|
1578
|
+
dispatch: GitHubTaskDispatch,
|
|
1579
|
+
extra: Record<string, unknown>
|
|
1580
|
+
): Response {
|
|
1581
|
+
scheduleAfterAck(args, dispatch.task);
|
|
1505
1582
|
return Response.json(
|
|
1506
1583
|
{ ok: true, dispatched: true, mode: "task", ...extra },
|
|
1507
1584
|
{ status: 202 }
|