@cursor/july 0.1.94 → 0.1.96
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/AGENTS.md +3 -4
- package/dist/channels/deployments/types.d.ts +1 -1
- package/dist/channels/deployments/types.d.ts.map +1 -1
- package/dist/channels/deployments/types.js +1 -0
- package/dist/channels/github/github-channel.d.ts.map +1 -1
- package/dist/channels/github/github-channel.js +14 -2
- package/dist/channels/github/types.d.ts +18 -3
- package/dist/channels/github/types.d.ts.map +1 -1
- package/dist/channels/origin/api.d.ts +59 -13
- package/dist/channels/origin/api.d.ts.map +1 -1
- package/dist/channels/origin/api.js +168 -27
- package/dist/channels/origin/binding.d.ts +2 -2
- package/dist/channels/origin/checks.d.ts +6 -6
- package/dist/channels/origin/checks.js +6 -6
- package/dist/channels/origin/cursor-account.d.ts +5 -3
- package/dist/channels/origin/cursor-account.d.ts.map +1 -1
- package/dist/channels/origin/cursor-account.js +5 -3
- package/dist/channels/origin/origin-channel.d.ts.map +1 -1
- package/dist/channels/origin/origin-channel.js +11 -3
- package/dist/channels/origin/origin-webhook.d.ts +11 -1
- package/dist/channels/origin/origin-webhook.d.ts.map +1 -1
- package/dist/channels/origin/origin-webhook.js +23 -3
- package/dist/channels/origin/types.d.ts +8 -0
- package/dist/channels/origin/types.d.ts.map +1 -1
- package/dist/channels/slack/api.d.ts +9 -0
- package/dist/channels/slack/api.d.ts.map +1 -1
- package/dist/channels/slack/api.js +36 -5
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +17 -46
- package/dist/channels/slack/dispatch.d.ts +7 -1
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +47 -23
- package/dist/channels/slack/inbound.d.ts +8 -0
- package/dist/channels/slack/inbound.d.ts.map +1 -1
- package/dist/channels/slack/inbound.js +32 -0
- package/dist/channels/slack/live-delivery.d.ts +26 -29
- package/dist/channels/slack/live-delivery.d.ts.map +1 -1
- package/dist/channels/slack/live-delivery.js +172 -73
- package/dist/channels/slack/manifest.d.ts.map +1 -1
- package/dist/channels/slack/manifest.js +5 -1
- package/dist/channels/slack/nudge-carrier.d.ts +2 -0
- package/dist/channels/slack/nudge-carrier.d.ts.map +1 -1
- package/dist/channels/slack/nudge-carrier.js +48 -1
- package/dist/channels/slack/pr-ref.d.ts +7 -1
- package/dist/channels/slack/pr-ref.d.ts.map +1 -1
- package/dist/channels/slack/pr-ref.js +42 -23
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +2 -2
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +4 -4
- package/dist/docs/assets/{app.CFDEas4I.js → app.jXleCmOc.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DFoGuETX.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.B1IIYpYS.js → VPLocalSearchBox.8LhyglIT.js} +1 -1
- package/dist/docs/assets/chunks/{theme.Ct4NSiLm.js → theme.9ged-pr2.js} +2 -2
- package/dist/docs/assets/index.md.CI93Ltlb.js +5 -0
- package/dist/docs/assets/{index.md.DRakGHFe.lean.js → index.md.CI93Ltlb.lean.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.Cw6_ICYG.js → reference_cli.md.CCnG-nJx.js} +4 -2
- package/dist/docs/assets/{reference_cli.md.Cw6_ICYG.lean.js → reference_cli.md.CCnG-nJx.lean.js} +1 -1
- package/dist/docs/assets/{reference_skills.md.8son6Hjm.js → reference_skills.md.BFW9retM.js} +3 -3
- package/dist/docs/assets/{templates_agentic-owners.md.DqtPdm6f.js → templates_agentic-owners.md.BZSH4N9z.js} +1 -1
- package/dist/docs/assets/templates_code-wiki.md.CDYZIBFN.js +2 -0
- package/dist/docs/assets/templates_code-wiki.md.CDYZIBFN.lean.js +1 -0
- package/dist/docs/assets/{templates_demo.md.DhFcWN6j.js → templates_demo.md.BeQX9V3H.js} +1 -1
- package/dist/docs/assets/{templates_pr-autofixer.md.DU7dQpor.js → templates_pr-autofixer.md.x5zl6-GT.js} +2 -2
- package/dist/docs/assets/{templates_pr-autofixer.md.DU7dQpor.lean.js → templates_pr-autofixer.md.x5zl6-GT.lean.js} +1 -1
- package/dist/docs/assets/templates_security-help.md.C3Ny_Qr2.js +4 -0
- package/dist/docs/assets/templates_security-help.md.C3Ny_Qr2.lean.js +1 -0
- package/dist/docs/assets/{templates_security-reviewer.md.CTa7u_l1.js → templates_security-reviewer.md.lshxbCLK.js} +2 -2
- package/dist/docs/assets/{templates_security-reviewer.md.CTa7u_l1.lean.js → templates_security-reviewer.md.lshxbCLK.lean.js} +1 -1
- package/dist/docs/assets/{templates_triage.md.CVlpctKS.js → templates_triage.md.Co4UNzkZ.js} +3 -3
- package/dist/docs/assets/{templates_triage.md.CVlpctKS.lean.js → templates_triage.md.Co4UNzkZ.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +4 -4
- package/dist/docs/concepts.html +4 -4
- package/dist/docs/deployment.html +4 -4
- package/dist/docs/evals.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 +4 -4
- package/dist/docs/guides/github.html +4 -4
- 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/index.md +5 -1
- package/dist/docs/llms-full.txt +189 -26
- package/dist/docs/llms.txt +2 -0
- 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 +8 -6
- package/dist/docs/reference/cli.md +4 -1
- 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 +7 -7
- package/dist/docs/reference/subagents.html +4 -4
- package/dist/docs/reference/tools.html +4 -4
- package/dist/docs/scaffolding-agents.html +4 -4
- package/dist/docs/storage.html +4 -4
- package/dist/docs/templates/agentic-owners.html +7 -7
- package/dist/docs/templates/agentic-owners.md +1 -1
- package/dist/docs/templates/code-wiki.html +28 -0
- package/dist/docs/templates/code-wiki.md +91 -0
- package/dist/docs/templates/demo.html +6 -6
- package/dist/docs/templates/demo.md +3 -2
- package/dist/docs/templates/pr-autofixer.html +6 -6
- package/dist/docs/templates/pr-autofixer.md +7 -13
- package/dist/docs/templates/security-help.html +30 -0
- package/dist/docs/templates/security-help.md +65 -0
- package/dist/docs/templates/security-reviewer.html +6 -6
- package/dist/docs/templates/security-reviewer.md +1 -2
- package/dist/docs/templates/triage.html +7 -7
- package/dist/docs/templates/triage.md +2 -6
- package/dist/docs/troubleshooting.html +4 -4
- package/dist/files-backends/cursor-hosted.d.ts +26 -0
- package/dist/files-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/files-backends/cursor-hosted.js +32 -4
- package/dist/files.d.ts +2 -0
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +5 -0
- package/dist/internal/advertise-tools.d.ts +2 -0
- package/dist/internal/advertise-tools.d.ts.map +1 -1
- package/dist/internal/advertise-tools.js +15 -1
- package/dist/internal/bounded.d.ts +7 -0
- package/dist/internal/bounded.d.ts.map +1 -0
- package/dist/internal/bounded.js +32 -0
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +142 -7
- package/dist/internal/conversation-mirror.d.ts +85 -0
- package/dist/internal/conversation-mirror.d.ts.map +1 -0
- package/dist/internal/conversation-mirror.js +312 -0
- package/dist/internal/cursor/backend-client.d.ts.map +1 -1
- package/dist/internal/cursor/backend-client.js +22 -48
- package/dist/internal/cursor/session-token.d.ts +45 -0
- package/dist/internal/cursor/session-token.d.ts.map +1 -0
- package/dist/internal/cursor/session-token.js +99 -0
- package/dist/internal/cursor-agent-template.d.ts +1 -1
- package/dist/internal/cursor-agent-template.d.ts.map +1 -1
- package/dist/internal/cursor-agent-template.js +1 -0
- package/dist/internal/deferred-channel-session.d.ts +20 -0
- package/dist/internal/deferred-channel-session.d.ts.map +1 -0
- package/dist/internal/deferred-channel-session.js +62 -0
- package/dist/internal/deploy-client.d.ts +13 -1
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +11 -1
- package/dist/internal/deploy-manifest.d.ts.map +1 -1
- package/dist/internal/deploy-manifest.js +11 -5
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +22 -2
- package/dist/internal/framework-file-storage.d.ts +61 -0
- package/dist/internal/framework-file-storage.d.ts.map +1 -0
- package/dist/internal/framework-file-storage.js +204 -0
- package/dist/internal/framework-storage-selection.d.ts +38 -16
- package/dist/internal/framework-storage-selection.d.ts.map +1 -1
- package/dist/internal/framework-storage-selection.js +78 -17
- package/dist/internal/hosted-admission-context.d.ts +20 -0
- package/dist/internal/hosted-admission-context.d.ts.map +1 -0
- package/dist/internal/hosted-admission-context.js +31 -0
- package/dist/internal/hosted-delivery-protocol.d.ts +5 -0
- package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
- package/dist/internal/hosted-delivery-protocol.js +33 -1
- package/dist/internal/hosted-delivery.d.ts +11 -2
- package/dist/internal/hosted-delivery.d.ts.map +1 -1
- package/dist/internal/hosted-delivery.js +79 -35
- package/dist/internal/hosted-managed-automation.d.ts +30 -0
- package/dist/internal/hosted-managed-automation.d.ts.map +1 -0
- package/dist/internal/hosted-managed-automation.js +58 -0
- package/dist/internal/init-project.d.ts.map +1 -1
- package/dist/internal/init-project.js +2 -0
- package/dist/internal/install-cursor-skills.d.ts.map +1 -1
- package/dist/internal/install-cursor-skills.js +1 -3
- package/dist/internal/managed-delivery.d.ts +80 -0
- package/dist/internal/managed-delivery.d.ts.map +1 -0
- package/dist/internal/managed-delivery.js +86 -0
- package/dist/internal/review-comments.d.ts.map +1 -1
- package/dist/internal/review-comments.js +10 -98
- package/dist/internal/runtime-dispatch-runner.d.ts +5 -1
- package/dist/internal/runtime-dispatch-runner.d.ts.map +1 -1
- package/dist/internal/runtime-dispatch-runner.js +7 -0
- package/dist/internal/scm/pr-url.d.ts +14 -0
- package/dist/internal/scm/pr-url.d.ts.map +1 -0
- package/dist/internal/scm/pr-url.js +65 -0
- package/dist/internal/sdk-runner.d.ts +25 -0
- package/dist/internal/sdk-runner.d.ts.map +1 -1
- package/dist/internal/sdk-runner.js +70 -0
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +11 -2
- package/dist/internal/session-engine.d.ts +13 -0
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +71 -3
- package/dist/internal/steering.d.ts +15 -0
- package/dist/internal/steering.d.ts.map +1 -0
- package/dist/internal/steering.js +18 -0
- package/dist/playground/assets/index-B1DDvBeC.css +1 -0
- package/dist/playground/assets/{index-B3JCyigB.js → index-Cx9CclK_.js} +47 -47
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted.d.ts +8 -0
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted.js +4 -3
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +5 -1
- package/docs/reference/cli.md +4 -1
- package/docs/templates/agentic-owners.md +1 -1
- package/docs/templates/code-wiki.md +96 -0
- package/docs/templates/demo.md +3 -2
- package/docs/templates/pr-autofixer.md +7 -13
- package/docs/templates/security-help.md +70 -0
- package/docs/templates/security-reviewer.md +1 -2
- package/docs/templates/triage.md +2 -6
- package/package.json +2 -2
- package/skills/ab/SKILL.md +13 -97
- package/skills/create-agent/SKILL.md +123 -223
- package/skills/debug/SKILL.md +34 -68
- package/skills/evals/SKILL.md +55 -180
- package/skills/framework-map/SKILL.md +83 -145
- package/skills/github/SKILL.md +53 -111
- package/skills/hillclimb/SKILL.md +40 -163
- package/skills/mcp-auth/SKILL.md +48 -107
- package/skills/otel/SKILL.md +22 -68
- package/skills/setup-slack/SKILL.md +77 -208
- package/src/channels/deployments/types.ts +1 -0
- package/src/channels/github/github-channel.ts +23 -8
- package/src/channels/github/types.ts +19 -2
- package/src/channels/origin/api.ts +242 -30
- package/src/channels/origin/binding.ts +2 -2
- package/src/channels/origin/checks.ts +6 -6
- package/src/channels/origin/cursor-account.ts +5 -3
- package/src/channels/origin/origin-channel.ts +13 -1
- package/src/channels/origin/origin-webhook.ts +27 -3
- package/src/channels/origin/types.ts +8 -0
- package/src/channels/slack/api.ts +41 -5
- package/src/channels/slack/defaults.ts +15 -49
- package/src/channels/slack/dispatch.ts +56 -22
- package/src/channels/slack/inbound.ts +43 -0
- package/src/channels/slack/live-delivery.ts +235 -114
- package/src/channels/slack/manifest.ts +5 -1
- package/src/channels/slack/nudge-carrier.ts +48 -1
- package/src/channels/slack/pr-ref.ts +56 -25
- package/src/channels/slack/slack-channel.ts +2 -0
- package/src/files-backends/cursor-hosted.ts +41 -2
- package/src/files.ts +11 -0
- package/src/internal/advertise-tools.ts +18 -2
- package/src/internal/bounded.ts +28 -0
- package/src/internal/cli-deploy.ts +183 -7
- package/src/internal/conversation-mirror.ts +406 -0
- package/src/internal/cursor/backend-client.ts +34 -58
- package/src/internal/cursor/session-token.ts +115 -0
- package/src/internal/cursor-agent-template.ts +1 -0
- package/src/internal/deferred-channel-session.ts +61 -0
- package/src/internal/deploy-client.ts +24 -1
- package/src/internal/deploy-manifest.ts +10 -5
- package/src/internal/discovery.ts +25 -2
- package/src/internal/framework-file-storage.ts +222 -0
- package/src/internal/framework-storage-selection.ts +101 -19
- package/src/internal/hosted-admission-context.ts +37 -0
- package/src/internal/hosted-delivery-protocol.ts +44 -1
- package/src/internal/hosted-delivery.ts +105 -40
- package/src/internal/hosted-managed-automation.ts +72 -0
- package/src/internal/init-project.ts +2 -0
- package/src/internal/install-cursor-skills.ts +1 -4
- package/src/internal/managed-delivery.ts +125 -0
- package/src/internal/review-comments.ts +10 -113
- package/src/internal/runtime-dispatch-runner.ts +10 -0
- package/src/internal/scm/pr-url.ts +95 -0
- package/src/internal/sdk-runner.ts +103 -0
- package/src/internal/server.ts +12 -0
- package/src/internal/session-engine.ts +76 -4
- package/src/internal/steering.ts +17 -0
- package/src/storage-backends/cursor-hosted.ts +10 -1
- package/src/types.ts +2 -1
- package/templates/agentic-owners/README.md +1 -1
- package/templates/agentic-owners/agent/agent.ts +0 -10
- package/templates/agentic-owners/agent/channels/github.ts +5 -14
- package/templates/agentic-owners/agent/lib/config.ts +0 -8
- package/templates/agentic-owners/agent/lib/review.ts +2 -15
- package/templates/agentic-owners/agent/tools/record_review.ts +2 -4
- package/templates/code-wiki/README.md +34 -0
- package/templates/code-wiki/agent/agent.ts +8 -0
- package/templates/code-wiki/agent/channels/github.ts +144 -0
- package/templates/code-wiki/agent/instructions.md +39 -0
- package/templates/code-wiki/agent/lib/repos.ts +5 -0
- package/templates/code-wiki/agent/lib/wiki.ts +22 -0
- package/templates/code-wiki/agent/tools/apply_wiki.ts +219 -0
- package/templates/code-wiki/evals/evals.config.ts +5 -0
- package/templates/code-wiki/evals/wiki.eval.ts +132 -0
- package/templates/code-wiki/init.json +25 -0
- package/templates/code-wiki/package.json +18 -0
- package/templates/code-wiki/tsconfig.json +12 -0
- package/templates/demo/agent/agent.ts +0 -10
- package/templates/pr-autofixer/README.md +0 -2
- package/templates/pr-autofixer/agent/agent.ts +0 -11
- package/templates/pr-autofixer/agent/channels/slack.ts +0 -7
- package/templates/pr-autofixer/agent/lib/pr-state.ts +5 -17
- package/templates/pr-autofixer/agent/lib/repos.ts +0 -1
- package/templates/security-help/README.md +2 -2
- package/templates/security-help/agent/agent.ts +1 -2
- package/templates/security-help/agent/channels/slack.ts +0 -3
- package/templates/security-help/agent/instructions.md +9 -10
- package/templates/security-help/agent/skills/access-request.md +1 -1
- package/templates/security-help/agent/skills/faq.md +31 -0
- package/templates/security-help/agent/skills/security-playbooks.md +1 -1
- package/templates/security-help/package.json +1 -2
- package/templates/security-reviewer/agent/agent.ts +0 -10
- package/templates/triage/agent/agent.ts +0 -10
- package/templates/triage/agent/channels/queue.ts +1 -1
- package/templates/triage/agent/channels/webhook.ts +1 -3
- package/dist/docs/assets/chunks/@localSearchIndexroot.DU3U2Ij2.js +0 -1
- package/dist/docs/assets/index.md.DRakGHFe.js +0 -5
- package/dist/internal/deployment-scm-event-stream.d.ts +0 -116
- package/dist/internal/deployment-scm-event-stream.d.ts.map +0 -1
- package/dist/internal/deployment-scm-event-stream.js +0 -474
- package/dist/playground/assets/index-D9N7-q97.css +0 -1
- package/src/internal/deployment-scm-event-stream.ts +0 -593
- package/templates/security-help/agent/knowledge/faq/approvals.md +0 -5
- package/templates/security-help/agent/knowledge/faq/channels.md +0 -6
- package/templates/security-help/agent/knowledge/faq/phishing.md +0 -10
- package/templates/security-help/agent/skills/security-first-pass.md +0 -15
- /package/dist/docs/assets/{reference_skills.md.8son6Hjm.lean.js → reference_skills.md.BFW9retM.lean.js} +0 -0
- /package/dist/docs/assets/{templates_agentic-owners.md.DqtPdm6f.lean.js → templates_agentic-owners.md.BZSH4N9z.lean.js} +0 -0
- /package/dist/docs/assets/{templates_demo.md.DhFcWN6j.lean.js → templates_demo.md.BeQX9V3H.lean.js} +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Code wiki
|
|
2
|
+
|
|
3
|
+
Keeps `wiki/` pages current after a pull request merges. Opens a
|
|
4
|
+
follow-up PR against that merge's base when a durable fact changed.
|
|
5
|
+
Skips chores. Same-base updates stack on `wiki/<base>`.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @cursor/july init ./code-wiki --template code-wiki
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`init` asks which repos to watch. Skip the prompt with
|
|
12
|
+
`--var repos=owner/repo`.
|
|
13
|
+
|
|
14
|
+
## Run
|
|
15
|
+
|
|
16
|
+
Connect GitHub in Cursor for those repos. Then sign the host in:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
agent-sdk login
|
|
20
|
+
agent-sdk dev
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Events and API calls use your Cursor GitHub connection. Replay a merged PR:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
agent-sdk github replay https://github.com/owner/repo/pull/1 --dir . --action closed
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Files
|
|
30
|
+
|
|
31
|
+
- `agent/lib/repos.ts`: watched repos
|
|
32
|
+
- `agent/lib/wiki.ts`: wiki path rules
|
|
33
|
+
- `agent/instructions.md`: what counts as a wiki update
|
|
34
|
+
- `evals/wiki.eval.ts`: skip and update smoke cases
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { HostGitHubClient } from "@cursor/july";
|
|
2
|
+
import {
|
|
3
|
+
defaultGitHubAuth,
|
|
4
|
+
githubChannel,
|
|
5
|
+
} from "@cursor/july/channels/github";
|
|
6
|
+
import { REPOS, watches } from "../lib/repos.js";
|
|
7
|
+
import { WIKI_DIR, isWikiPath } from "../lib/wiki.js";
|
|
8
|
+
|
|
9
|
+
const MAX_DIFF_CHARS = 150_000;
|
|
10
|
+
const MAX_WIKI_PAGES = 40;
|
|
11
|
+
const LIST_FILES_CAP = 3000;
|
|
12
|
+
|
|
13
|
+
type Octokit = Awaited<ReturnType<HostGitHubClient["getOctokit"]>>;
|
|
14
|
+
|
|
15
|
+
export default githubChannel({
|
|
16
|
+
cursorAccount: { repos: REPOS, permissions: "contents-write" },
|
|
17
|
+
deliverReplies: false,
|
|
18
|
+
onComment: () => null,
|
|
19
|
+
onPullRequest: async (ctx, pr) => {
|
|
20
|
+
if (!watches(ctx.repository.fullName)) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
if (pr.action !== "closed" || !pr.merged) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
if (pr.headRef.startsWith(`${WIKI_DIR}/`)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const octokit = await ctx.github.getOctokit();
|
|
30
|
+
const pull = {
|
|
31
|
+
owner: ctx.repository.owner,
|
|
32
|
+
repo: ctx.repository.name,
|
|
33
|
+
pull_number: pr.number,
|
|
34
|
+
};
|
|
35
|
+
const listed = await octokit.paginate(octokit.rest.pulls.listFiles, {
|
|
36
|
+
...pull,
|
|
37
|
+
per_page: 100,
|
|
38
|
+
});
|
|
39
|
+
const files = listed.map((file) => file.filename);
|
|
40
|
+
if (
|
|
41
|
+
files.length > 0 &&
|
|
42
|
+
files.length < LIST_FILES_CAP &&
|
|
43
|
+
files.every(isWikiPath)
|
|
44
|
+
) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
auth: defaultGitHubAuth(ctx),
|
|
49
|
+
context: [
|
|
50
|
+
"This pull request merged. Read pr/files.txt, pr/diff.patch, and wiki/.",
|
|
51
|
+
],
|
|
52
|
+
async workspaceFiles() {
|
|
53
|
+
const [diff, wiki] = await Promise.all([
|
|
54
|
+
octokit.rest.pulls.get({ ...pull, mediaType: { format: "diff" } }),
|
|
55
|
+
loadWiki(octokit, pull.owner, pull.repo, pr.baseRef),
|
|
56
|
+
]);
|
|
57
|
+
const text = String(diff.data);
|
|
58
|
+
return {
|
|
59
|
+
"pr/base.ref": `${pr.baseRef}\n`,
|
|
60
|
+
"pr/files.txt": `${files.join("\n")}\n`,
|
|
61
|
+
"pr/diff.patch":
|
|
62
|
+
text.length > MAX_DIFF_CHARS
|
|
63
|
+
? `${text.slice(0, MAX_DIFF_CHARS)}\n…[truncated]\n`
|
|
64
|
+
: text,
|
|
65
|
+
...wiki,
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
async function loadWiki(
|
|
73
|
+
octokit: Octokit,
|
|
74
|
+
owner: string,
|
|
75
|
+
repo: string,
|
|
76
|
+
ref: string
|
|
77
|
+
): Promise<Record<string, string>> {
|
|
78
|
+
const listed = await readContents(octokit, {
|
|
79
|
+
owner,
|
|
80
|
+
repo,
|
|
81
|
+
path: WIKI_DIR,
|
|
82
|
+
ref,
|
|
83
|
+
});
|
|
84
|
+
if (!Array.isArray(listed)) {
|
|
85
|
+
return { "wiki/pages.txt": "" };
|
|
86
|
+
}
|
|
87
|
+
const markdown = listed.filter(
|
|
88
|
+
(item) => item.type === "file" && item.name.endsWith(".md")
|
|
89
|
+
);
|
|
90
|
+
const truncated = markdown.length > MAX_WIKI_PAGES;
|
|
91
|
+
const files = markdown.slice(0, MAX_WIKI_PAGES);
|
|
92
|
+
const pages: Record<string, string> = {};
|
|
93
|
+
await Promise.all(
|
|
94
|
+
files.map(async (file) => {
|
|
95
|
+
const body = await readContents(octokit, {
|
|
96
|
+
owner,
|
|
97
|
+
repo,
|
|
98
|
+
path: `${WIKI_DIR}/${file.name}`,
|
|
99
|
+
ref,
|
|
100
|
+
});
|
|
101
|
+
if (
|
|
102
|
+
body === undefined ||
|
|
103
|
+
Array.isArray(body) ||
|
|
104
|
+
body.encoding !== "base64" ||
|
|
105
|
+
typeof body.content !== "string"
|
|
106
|
+
) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
pages[`${WIKI_DIR}/${file.name}`] = Buffer.from(
|
|
110
|
+
body.content,
|
|
111
|
+
"base64"
|
|
112
|
+
).toString("utf8");
|
|
113
|
+
})
|
|
114
|
+
);
|
|
115
|
+
const names = Object.keys(pages).sort();
|
|
116
|
+
pages["wiki/pages.txt"] = truncated
|
|
117
|
+
? `${names.join("\n")}\n…[truncated]\n`
|
|
118
|
+
: `${names.join("\n")}\n`;
|
|
119
|
+
return pages;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function readContents(
|
|
123
|
+
octokit: Octokit,
|
|
124
|
+
args: { owner: string; repo: string; path: string; ref: string }
|
|
125
|
+
) {
|
|
126
|
+
try {
|
|
127
|
+
const { data } = await octokit.rest.repos.getContent(args);
|
|
128
|
+
return data;
|
|
129
|
+
} catch (error) {
|
|
130
|
+
if (isNotFound(error)) {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function isNotFound(error: unknown): boolean {
|
|
138
|
+
return (
|
|
139
|
+
typeof error === "object" &&
|
|
140
|
+
error !== null &&
|
|
141
|
+
"status" in error &&
|
|
142
|
+
error.status === 404
|
|
143
|
+
);
|
|
144
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Code wiki
|
|
2
|
+
|
|
3
|
+
You keep the in-repo wiki current after a pull request merges.
|
|
4
|
+
|
|
5
|
+
## Read
|
|
6
|
+
|
|
7
|
+
The workspace has `pr/files.txt`, `pr/diff.patch`, and `wiki/`.
|
|
8
|
+
`wiki/pages.txt` lists existing pages. Missing pages mean the wiki is
|
|
9
|
+
empty. Read the file list and the pages that own the change. Use the
|
|
10
|
+
diff only to test a fact.
|
|
11
|
+
|
|
12
|
+
## Decide
|
|
13
|
+
|
|
14
|
+
Update only when the merge changes a durable fact someone would look
|
|
15
|
+
up later: how a system works, a public or operator contract, a default
|
|
16
|
+
or ownership change, a removed feature.
|
|
17
|
+
|
|
18
|
+
An empty wiki is not a license to document the whole repo. Create a
|
|
19
|
+
page only for a durable contract in this merge.
|
|
20
|
+
|
|
21
|
+
Skip lint, format, lockfiles, dependency pins, tests-only, cherry-picks,
|
|
22
|
+
backports, telemetry-only changes, one-off bug fixes that leave the
|
|
23
|
+
described behavior the same, knobs the wiki never mentioned, and facts
|
|
24
|
+
the matching page already states.
|
|
25
|
+
|
|
26
|
+
Do not write a changelog or a PR list.
|
|
27
|
+
|
|
28
|
+
## Write
|
|
29
|
+
|
|
30
|
+
Call `apply_wiki` once.
|
|
31
|
+
|
|
32
|
+
- Skip: `{ verdict: "skip", reason }` with one line.
|
|
33
|
+
- Update: `{ verdict: "update", reason, pages }` with full page bodies.
|
|
34
|
+
|
|
35
|
+
Pages stay under `wiki/`, flat, `*.md`. Keep `_index.md` in sync when
|
|
36
|
+
you add a page. Each catalog line names the page and the paths it owns.
|
|
37
|
+
Short declarative sentences. Edit only the stale or missing facts.
|
|
38
|
+
|
|
39
|
+
Reply with `skip` or `update` and the reason.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const WIKI_DIR = "wiki";
|
|
2
|
+
|
|
3
|
+
const PAGE = /^[A-Za-z0-9._-]+\.md$/;
|
|
4
|
+
|
|
5
|
+
export function isWikiPath(path: string): boolean {
|
|
6
|
+
return path === WIKI_DIR || path.startsWith(`${WIKI_DIR}/`);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function wikiPagePath(raw: string): string | undefined {
|
|
10
|
+
const path = raw.replace(/^\/+/, "");
|
|
11
|
+
if (path.includes("..") || path.includes("\\")) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
if (!path.startsWith(`${WIKI_DIR}/`) || !path.endsWith(".md")) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
const name = path.slice(WIKI_DIR.length + 1);
|
|
18
|
+
if (!PAGE.test(name)) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
return `${WIKI_DIR}/${name}`;
|
|
22
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import type { HostGitHubClient } from "@cursor/july";
|
|
4
|
+
import { parseGitHubPrContinuationKey } from "@cursor/july/channels/github";
|
|
5
|
+
import { defineTool } from "@cursor/july/tools";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { wikiPagePath } from "../lib/wiki.js";
|
|
8
|
+
|
|
9
|
+
const page = z.object({
|
|
10
|
+
path: z.string().min(1).max(160),
|
|
11
|
+
content: z.string().min(1).max(32_000),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
type Page = z.infer<typeof page>;
|
|
15
|
+
type Octokit = Awaited<ReturnType<HostGitHubClient["getOctokit"]>>;
|
|
16
|
+
|
|
17
|
+
type Write = {
|
|
18
|
+
octokit: Octokit;
|
|
19
|
+
owner: string;
|
|
20
|
+
repo: string;
|
|
21
|
+
number: number;
|
|
22
|
+
label: string;
|
|
23
|
+
reason: string;
|
|
24
|
+
pages: Page[];
|
|
25
|
+
base: string;
|
|
26
|
+
branch: string;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default defineTool({
|
|
30
|
+
description:
|
|
31
|
+
"Skip or open a wiki follow-up PR for this merged pull request. Call once.",
|
|
32
|
+
inputSchema: z.discriminatedUnion("verdict", [
|
|
33
|
+
z.object({
|
|
34
|
+
verdict: z.literal("skip"),
|
|
35
|
+
reason: z.string().min(1).max(280),
|
|
36
|
+
}),
|
|
37
|
+
z.object({
|
|
38
|
+
verdict: z.literal("update"),
|
|
39
|
+
reason: z.string().min(1).max(280),
|
|
40
|
+
pages: z.array(page).min(1).max(8),
|
|
41
|
+
}),
|
|
42
|
+
]),
|
|
43
|
+
async execute(input, ctx) {
|
|
44
|
+
if (ctx.session.purpose === "eval") {
|
|
45
|
+
return { posted: false, reason: "eval", verdict: input.verdict };
|
|
46
|
+
}
|
|
47
|
+
if (input.verdict === "skip") {
|
|
48
|
+
return { posted: false, reason: input.reason, verdict: "skip" };
|
|
49
|
+
}
|
|
50
|
+
const ref = parseGitHubPrContinuationKey(ctx.session.continuationKey ?? "");
|
|
51
|
+
if (ref === undefined) {
|
|
52
|
+
throw new Error("apply_wiki requires a GitHub pull request session");
|
|
53
|
+
}
|
|
54
|
+
const base = (
|
|
55
|
+
await readFile(join(ctx.workspaceDir, "pr/base.ref"), "utf8")
|
|
56
|
+
).trim();
|
|
57
|
+
const branch = wikiUpdateBranch(base);
|
|
58
|
+
if (branch === undefined) {
|
|
59
|
+
throw new Error("missing pr/base.ref");
|
|
60
|
+
}
|
|
61
|
+
const pages = input.pages.map((item) => {
|
|
62
|
+
const path = wikiPagePath(item.path);
|
|
63
|
+
if (path === undefined) {
|
|
64
|
+
throw new Error(`invalid wiki path: ${item.path}`);
|
|
65
|
+
}
|
|
66
|
+
return { path, content: item.content };
|
|
67
|
+
});
|
|
68
|
+
return openWikiPr({
|
|
69
|
+
octokit: await ctx.host.github.getOctokit(),
|
|
70
|
+
owner: ref.owner,
|
|
71
|
+
repo: ref.repo,
|
|
72
|
+
number: ref.number,
|
|
73
|
+
label: `${ref.owner}/${ref.repo}#${ref.number}`,
|
|
74
|
+
reason: input.reason,
|
|
75
|
+
pages,
|
|
76
|
+
base,
|
|
77
|
+
branch,
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
function wikiUpdateBranch(base: string): string | undefined {
|
|
83
|
+
if (base === "" || !/^[A-Za-z0-9._/-]+$/.test(base)) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
return `wiki/${base.replaceAll("/", "-")}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function openWikiPr(input: Write) {
|
|
90
|
+
const repo = { owner: input.owner, repo: input.repo };
|
|
91
|
+
const existing = await input.octokit.rest.pulls.list({
|
|
92
|
+
...repo,
|
|
93
|
+
state: "open",
|
|
94
|
+
head: `${input.owner}:${input.branch}`,
|
|
95
|
+
base: input.base,
|
|
96
|
+
per_page: 1,
|
|
97
|
+
});
|
|
98
|
+
const open = existing.data[0];
|
|
99
|
+
if (open !== undefined && citesSource(open.body, input.number)) {
|
|
100
|
+
return {
|
|
101
|
+
posted: false,
|
|
102
|
+
reason: "exists",
|
|
103
|
+
verdict: "update",
|
|
104
|
+
pr: input.label,
|
|
105
|
+
url: open.html_url,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const branchSha = await refSha(input.octokit, repo, input.branch);
|
|
109
|
+
const parent =
|
|
110
|
+
branchSha ?? (await refSha(input.octokit, repo, input.base));
|
|
111
|
+
if (parent === undefined) {
|
|
112
|
+
throw new Error(`missing base ref: ${input.base}`);
|
|
113
|
+
}
|
|
114
|
+
const { data: commit } = await input.octokit.rest.git.getCommit({
|
|
115
|
+
...repo,
|
|
116
|
+
commit_sha: parent,
|
|
117
|
+
});
|
|
118
|
+
const blobs = await Promise.all(
|
|
119
|
+
input.pages.map(async (item) => {
|
|
120
|
+
const { data } = await input.octokit.rest.git.createBlob({
|
|
121
|
+
...repo,
|
|
122
|
+
content: Buffer.from(item.content).toString("base64"),
|
|
123
|
+
encoding: "base64",
|
|
124
|
+
});
|
|
125
|
+
return {
|
|
126
|
+
path: item.path,
|
|
127
|
+
mode: "100644" as const,
|
|
128
|
+
type: "blob" as const,
|
|
129
|
+
sha: data.sha,
|
|
130
|
+
};
|
|
131
|
+
})
|
|
132
|
+
);
|
|
133
|
+
const { data: tree } = await input.octokit.rest.git.createTree({
|
|
134
|
+
...repo,
|
|
135
|
+
base_tree: commit.tree.sha,
|
|
136
|
+
tree: blobs,
|
|
137
|
+
});
|
|
138
|
+
const { data: next } = await input.octokit.rest.git.createCommit({
|
|
139
|
+
...repo,
|
|
140
|
+
message: `wiki: ${input.reason}`,
|
|
141
|
+
tree: tree.sha,
|
|
142
|
+
parents: [parent],
|
|
143
|
+
});
|
|
144
|
+
if (branchSha === undefined) {
|
|
145
|
+
await input.octokit.rest.git.createRef({
|
|
146
|
+
...repo,
|
|
147
|
+
ref: `refs/heads/${input.branch}`,
|
|
148
|
+
sha: next.sha,
|
|
149
|
+
});
|
|
150
|
+
} else {
|
|
151
|
+
await input.octokit.rest.git.updateRef({
|
|
152
|
+
...repo,
|
|
153
|
+
ref: `heads/${input.branch}`,
|
|
154
|
+
sha: next.sha,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
if (open !== undefined) {
|
|
158
|
+
await input.octokit.rest.pulls.update({
|
|
159
|
+
...repo,
|
|
160
|
+
pull_number: open.number,
|
|
161
|
+
body: appendSource(open.body ?? "", input.reason, input.number),
|
|
162
|
+
});
|
|
163
|
+
return {
|
|
164
|
+
posted: true,
|
|
165
|
+
verdict: "update",
|
|
166
|
+
pr: input.label,
|
|
167
|
+
url: open.html_url,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const { data: pull } = await input.octokit.rest.pulls.create({
|
|
171
|
+
...repo,
|
|
172
|
+
title: `wiki: update from #${input.number}`,
|
|
173
|
+
head: input.branch,
|
|
174
|
+
base: input.base,
|
|
175
|
+
body: `${input.reason}\n\nSource: #${input.number}`,
|
|
176
|
+
});
|
|
177
|
+
return {
|
|
178
|
+
posted: true,
|
|
179
|
+
verdict: "update",
|
|
180
|
+
pr: input.label,
|
|
181
|
+
url: pull.html_url,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async function refSha(
|
|
186
|
+
octokit: Octokit,
|
|
187
|
+
repo: { owner: string; repo: string },
|
|
188
|
+
name: string
|
|
189
|
+
): Promise<string | undefined> {
|
|
190
|
+
try {
|
|
191
|
+
const { data } = await octokit.rest.git.getRef({
|
|
192
|
+
...repo,
|
|
193
|
+
ref: `heads/${name}`,
|
|
194
|
+
});
|
|
195
|
+
return data.object.sha;
|
|
196
|
+
} catch (error) {
|
|
197
|
+
if (isNotFound(error)) {
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function citesSource(body: string | null | undefined, number: number): boolean {
|
|
205
|
+
return new RegExp(`(?:^|\\n)Source:.*#${number}(?:\\s|$)`).test(body ?? "");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function appendSource(body: string, reason: string, number: number): string {
|
|
209
|
+
return `${body.trim()}\n\n${reason}\nSource: #${number}`;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function isNotFound(error: unknown): boolean {
|
|
213
|
+
return (
|
|
214
|
+
typeof error === "object" &&
|
|
215
|
+
error !== null &&
|
|
216
|
+
"status" in error &&
|
|
217
|
+
error.status === 404
|
|
218
|
+
);
|
|
219
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { defineEval } from "@cursor/july/evals";
|
|
2
|
+
|
|
3
|
+
function merged(title: string): string {
|
|
4
|
+
return [
|
|
5
|
+
"GitHub pull request trigger: acme/api#12",
|
|
6
|
+
"Action: closed",
|
|
7
|
+
"PR: https://github.com/acme/api/pull/12",
|
|
8
|
+
`Title: ${title}`,
|
|
9
|
+
"Head: feat/change (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)",
|
|
10
|
+
"Base: main",
|
|
11
|
+
"Author: sam",
|
|
12
|
+
"",
|
|
13
|
+
"This pull request merged. Read pr/files.txt, pr/diff.patch, and wiki/.",
|
|
14
|
+
].join("\n");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const INDEX = [
|
|
18
|
+
"# Wiki",
|
|
19
|
+
"",
|
|
20
|
+
"- [Billing](billing.md): usage events posted to the warehouse",
|
|
21
|
+
"- [App](app.md): HTTP handlers and UI chrome",
|
|
22
|
+
"",
|
|
23
|
+
].join("\n");
|
|
24
|
+
|
|
25
|
+
const BILLING = [
|
|
26
|
+
"# Billing",
|
|
27
|
+
"",
|
|
28
|
+
"Usage events are protobuf messages in `proto/billing.proto`.",
|
|
29
|
+
"Each event has `account_id` and `amount_cents`.",
|
|
30
|
+
"",
|
|
31
|
+
].join("\n");
|
|
32
|
+
|
|
33
|
+
const APP = [
|
|
34
|
+
"# App",
|
|
35
|
+
"",
|
|
36
|
+
"The sidebar opener is a querySelector on `.opener`.",
|
|
37
|
+
"",
|
|
38
|
+
].join("\n");
|
|
39
|
+
|
|
40
|
+
export default defineEval({
|
|
41
|
+
tags: ["smoke"],
|
|
42
|
+
cases: [
|
|
43
|
+
{
|
|
44
|
+
id: "skip-lint",
|
|
45
|
+
description: "A quote-style lint fix does not open a wiki PR.",
|
|
46
|
+
async test(t) {
|
|
47
|
+
await t.send(merged("Fix sidebar opener lint failure"), {
|
|
48
|
+
workspaceFiles: {
|
|
49
|
+
"pr/files.txt": "src/sidebar.ts\n",
|
|
50
|
+
"pr/diff.patch": [
|
|
51
|
+
"diff --git a/src/sidebar.ts b/src/sidebar.ts",
|
|
52
|
+
"-const opener = document.querySelector('.opener')",
|
|
53
|
+
'+const opener = document.querySelector(".opener");',
|
|
54
|
+
].join("\n"),
|
|
55
|
+
"wiki/pages.txt": "wiki/_index.md\nwiki/app.md\n",
|
|
56
|
+
"wiki/_index.md": INDEX,
|
|
57
|
+
"wiki/app.md": APP,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
t.succeeded();
|
|
61
|
+
t.calledTool("apply_wiki", { input: { verdict: "skip" } });
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: "update-contract",
|
|
66
|
+
description: "New billing proto fields update the billing page.",
|
|
67
|
+
async test(t) {
|
|
68
|
+
await t.send(merged("Add unified fields to billing events"), {
|
|
69
|
+
workspaceFiles: {
|
|
70
|
+
"pr/files.txt": "proto/billing.proto\n",
|
|
71
|
+
"pr/diff.patch": [
|
|
72
|
+
"diff --git a/proto/billing.proto b/proto/billing.proto",
|
|
73
|
+
" message UsageEvent {",
|
|
74
|
+
" string account_id = 1;",
|
|
75
|
+
" int64 amount_cents = 2;",
|
|
76
|
+
"+ string usage_unit = 12;",
|
|
77
|
+
"+ string workspace_id = 13;",
|
|
78
|
+
" }",
|
|
79
|
+
].join("\n"),
|
|
80
|
+
"wiki/pages.txt": "wiki/_index.md\nwiki/billing.md\n",
|
|
81
|
+
"wiki/_index.md": INDEX,
|
|
82
|
+
"wiki/billing.md": BILLING,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
t.succeeded();
|
|
86
|
+
t.calledTool("apply_wiki", { input: { verdict: "update" } });
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: "skip-docs",
|
|
91
|
+
description: "A markdown-only merge does not open a wiki PR.",
|
|
92
|
+
async test(t) {
|
|
93
|
+
await t.send(merged("Document factory delete in servicetests"), {
|
|
94
|
+
workspaceFiles: {
|
|
95
|
+
"pr/files.txt": "backend/server/src/factory/README.md\n",
|
|
96
|
+
"pr/diff.patch": [
|
|
97
|
+
"diff --git a/backend/server/src/factory/README.md b/backend/server/src/factory/README.md",
|
|
98
|
+
"+Drive environment delete from markdown servicetests.",
|
|
99
|
+
].join("\n"),
|
|
100
|
+
"wiki/pages.txt": "wiki/_index.md\n",
|
|
101
|
+
"wiki/_index.md": INDEX,
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
t.succeeded();
|
|
105
|
+
t.calledTool("apply_wiki", { input: { verdict: "skip" } });
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: "skip-cherry-pick",
|
|
110
|
+
description: "A release-train cherry-pick does not open a wiki PR.",
|
|
111
|
+
async test(t) {
|
|
112
|
+
await t.send(
|
|
113
|
+
merged("[CP releases/3.19] Stop stale Project corner loaders"),
|
|
114
|
+
{
|
|
115
|
+
workspaceFiles: {
|
|
116
|
+
"pr/files.txt": "src/projects.ts\n",
|
|
117
|
+
"pr/diff.patch": [
|
|
118
|
+
"diff --git a/src/projects.ts b/src/projects.ts",
|
|
119
|
+
"+if (status.seq < last.seq) return;",
|
|
120
|
+
].join("\n"),
|
|
121
|
+
"wiki/pages.txt": "wiki/_index.md\nwiki/app.md\n",
|
|
122
|
+
"wiki/_index.md": INDEX,
|
|
123
|
+
"wiki/app.md": APP,
|
|
124
|
+
},
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
t.succeeded();
|
|
128
|
+
t.calledTool("apply_wiki", { input: { verdict: "skip" } });
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"questions": [
|
|
3
|
+
{
|
|
4
|
+
"id": "repos",
|
|
5
|
+
"prompt": "Which GitHub repos should this agent watch for merges?",
|
|
6
|
+
"hint": "Comma-separated owner/repo. One GitHub owner.",
|
|
7
|
+
"placeholder": "acme/api, acme/web",
|
|
8
|
+
"parse": "owner-repo-list"
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"replace": [
|
|
12
|
+
{
|
|
13
|
+
"file": "agent/lib/repos.ts",
|
|
14
|
+
"find": "[\"owner/repo\"]",
|
|
15
|
+
"answer": "repos",
|
|
16
|
+
"as": "json-array"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"file": "README.md",
|
|
20
|
+
"find": "owner/repo",
|
|
21
|
+
"answer": "repos",
|
|
22
|
+
"as": "first"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "code-wiki",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Keeps an in-repo wiki current after pull requests merge.",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"check": "tsc --noEmit",
|
|
8
|
+
"dev": "agent-sdk dev"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@cursor/july": "latest",
|
|
12
|
+
"zod": "^3.25.0"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/node": "^22.14.0",
|
|
16
|
+
"typescript": "^5.8.0"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -1,18 +1,8 @@
|
|
|
1
|
-
import { homedir } from "node:os";
|
|
2
|
-
import { join } from "node:path";
|
|
3
1
|
import { defineAgent } from "@cursor/july";
|
|
4
2
|
|
|
5
3
|
export default defineAgent({
|
|
6
|
-
model: {
|
|
7
|
-
id: "grok-4.5",
|
|
8
|
-
params: [
|
|
9
|
-
{ id: "effort", value: "high" },
|
|
10
|
-
{ id: "fast", value: "true" },
|
|
11
|
-
],
|
|
12
|
-
},
|
|
13
4
|
tools: ["read", "grep"],
|
|
14
5
|
local: {
|
|
15
6
|
sandbox: true,
|
|
16
|
-
cwd: join(homedir(), ".cache", "agent-serve", "demo"),
|
|
17
7
|
},
|
|
18
8
|
});
|