@cursor/july 0.1.1 → 0.1.2
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 +24 -2
- package/README.md +25 -15
- package/dist/bin/agent-serve.js +101 -12
- package/dist/channels/github/api.d.ts.map +1 -1
- package/dist/channels/github/api.js +31 -14
- package/dist/channels/github/cursor-account.d.ts +43 -0
- package/dist/channels/github/cursor-account.d.ts.map +1 -0
- package/dist/channels/github/cursor-account.js +95 -0
- package/dist/channels/github/github-channel.d.ts.map +1 -1
- package/dist/channels/github/github-channel.js +46 -9
- package/dist/channels/github/index.d.ts +2 -2
- package/dist/channels/github/index.js +2 -2
- package/dist/channels/github/types.d.ts +17 -0
- package/dist/channels/github/types.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.d.ts +8 -2
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +8 -0
- package/dist/channels/slack/types.d.ts +24 -3
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/channels/slack/types.js +15 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +8 -8
- package/dist/docs/assets/{ab.md.COdXkces.js → ab.md.BMCZ6Hd7.js} +3 -3
- package/dist/docs/assets/{ab.md.COdXkces.lean.js → ab.md.BMCZ6Hd7.lean.js} +1 -1
- package/dist/docs/assets/{app.DqfFEmJd.js → app.Oje4vhlk.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.zwQ9RCQ7.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.BaLEdS15.js → VPLocalSearchBox.H5XZ2zCB.js} +1 -1
- package/dist/docs/assets/chunks/{theme.CZRvu_0q.js → theme.CTR_TuaE.js} +2 -2
- package/dist/docs/assets/{deployment.md.Dx1TYNk5.js → deployment.md.DTKwE15Z.js} +3 -3
- package/dist/docs/assets/{deployment.md.Dx1TYNk5.lean.js → deployment.md.DTKwE15Z.lean.js} +1 -1
- package/dist/docs/assets/{evals.md.DPZ_MAnI.js → evals.md.DAgEc_hL.js} +3 -3
- package/dist/docs/assets/{guides_agent-to-agent.md.CrtrsySy.js → guides_agent-to-agent.md.Bpzgq2Pq.js} +1 -1
- package/dist/docs/assets/{guides_cloud-runtime.md.CYlNMTNp.js → guides_cloud-runtime.md.gVzabdQL.js} +1 -1
- package/dist/docs/assets/{guides_github.md.DwbKhCeS.js → guides_github.md.DOOCpqsW.js} +11 -4
- package/dist/docs/assets/{guides_github.md.DwbKhCeS.lean.js → guides_github.md.DOOCpqsW.lean.js} +1 -1
- package/dist/docs/assets/{guides_human-in-the-loop.md.Dvuctx7s.js → guides_human-in-the-loop.md.DlUqsp1S.js} +2 -2
- package/dist/docs/assets/{guides_slack.md.bv41fHfW.js → guides_slack.md.CCwqHvSV.js} +4 -4
- package/dist/docs/assets/{guides_slack.md.bv41fHfW.lean.js → guides_slack.md.CCwqHvSV.lean.js} +1 -1
- package/dist/docs/assets/{guides_webhooks.md.hFTik3lf.js → guides_webhooks.md.B1EswtUu.js} +2 -2
- package/dist/docs/assets/index.md.m81y7TY7.js +20 -0
- package/dist/docs/assets/{index.md.BPKcj5AI.lean.js → index.md.m81y7TY7.lean.js} +1 -1
- package/dist/docs/assets/quickstart.md.CfU8_uTC.js +192 -0
- package/dist/docs/assets/quickstart.md.CfU8_uTC.lean.js +1 -0
- package/dist/docs/assets/{reference_agent-config.md.Bpd7HQwf.js → reference_agent-config.md.DrW2JUM8.js} +4 -4
- package/dist/docs/assets/{reference_agent-config.md.Bpd7HQwf.lean.js → reference_agent-config.md.DrW2JUM8.lean.js} +1 -1
- package/dist/docs/assets/{reference_channels.md.D7JTR03W.js → reference_channels.md.DdmiKgqf.js} +4 -4
- package/dist/docs/assets/{reference_channels.md.D7JTR03W.lean.js → reference_channels.md.DdmiKgqf.lean.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.C3vNH_DE.js → reference_connections.md.zaEYCLHT.js} +1 -1
- package/dist/docs/assets/{reference_hooks.md.BCEc3MyM.js → reference_hooks.md.DyLVfE1O.js} +1 -1
- package/dist/docs/assets/{reference_hooks.md.BCEc3MyM.lean.js → reference_hooks.md.DyLVfE1O.lean.js} +1 -1
- package/dist/docs/assets/{reference_http-api.md.DBAahtdz.js → reference_http-api.md.Dx_nmDG6.js} +1 -1
- package/dist/docs/assets/{reference_instructions.md.BC05LEQ8.js → reference_instructions.md.CgoV-YEb.js} +9 -7
- package/dist/docs/assets/{reference_instructions.md.BC05LEQ8.lean.js → reference_instructions.md.CgoV-YEb.lean.js} +1 -1
- package/dist/docs/assets/{reference_schedules.md.D7qijxLk.js → reference_schedules.md.w_F2mXB6.js} +2 -2
- package/dist/docs/assets/{reference_skills.md.VQnlBT3Q.js → reference_skills.md.B_jHN7JL.js} +3 -3
- package/dist/docs/assets/{reference_skills.md.VQnlBT3Q.lean.js → reference_skills.md.B_jHN7JL.lean.js} +1 -1
- package/dist/docs/assets/{reference_subagents.md.CIRAVcPK.js → reference_subagents.md.zWAMNfi1.js} +1 -1
- package/dist/docs/assets/{reference_tools.md.DF5kwlt0.js → reference_tools.md.CqgJroI0.js} +2 -2
- package/dist/docs/assets/scaffolding-agents.md.C3pTrmoE.js +1 -0
- package/dist/docs/assets/scaffolding-agents.md.C3pTrmoE.lean.js +1 -0
- package/dist/docs/assets/storage.md.CVnInNiN.js +17 -0
- package/dist/docs/assets/storage.md.CVnInNiN.lean.js +1 -0
- package/dist/docs/building-with-agents.html +4 -4
- package/dist/docs/concepts.html +4 -4
- package/dist/docs/deployment.html +7 -7
- package/dist/docs/evals.html +7 -7
- package/dist/docs/guides/agent-to-agent.html +6 -6
- package/dist/docs/guides/cloud-runtime.html +5 -5
- package/dist/docs/guides/github.html +14 -7
- package/dist/docs/guides/human-in-the-loop.html +6 -6
- package/dist/docs/guides/slack.html +8 -8
- package/dist/docs/guides/webhooks.html +6 -6
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +5 -5
- package/dist/docs/index.html +7 -7
- package/dist/docs/quickstart.html +180 -23
- package/dist/docs/reference/agent-config.html +7 -7
- package/dist/docs/reference/channels.html +8 -8
- package/dist/docs/reference/cli.html +4 -4
- package/dist/docs/reference/connections.html +5 -5
- package/dist/docs/reference/hooks.html +5 -5
- package/dist/docs/reference/http-api.html +6 -6
- package/dist/docs/reference/instructions.html +13 -11
- package/dist/docs/reference/playground.html +4 -4
- package/dist/docs/reference/project-layout.html +4 -4
- package/dist/docs/reference/schedules.html +7 -7
- package/dist/docs/reference/sessions.html +4 -4
- package/dist/docs/reference/skills.html +6 -6
- package/dist/docs/reference/subagents.html +6 -6
- package/dist/docs/reference/tools.html +7 -7
- package/dist/docs/scaffolding-agents.html +5 -5
- package/dist/docs/storage.html +41 -0
- package/dist/docs/troubleshooting.html +4 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/internal/cli-deploy.d.ts +52 -0
- package/dist/internal/cli-deploy.d.ts.map +1 -0
- package/dist/internal/cli-deploy.js +731 -0
- package/dist/internal/cursor/backend-client.d.ts +10 -1
- package/dist/internal/cursor/backend-client.d.ts.map +1 -1
- package/dist/internal/cursor/backend-client.js +79 -1
- package/dist/internal/cursor/github-credentials.d.ts +44 -0
- package/dist/internal/cursor/github-credentials.d.ts.map +1 -0
- package/dist/internal/cursor/github-credentials.js +195 -0
- package/dist/internal/deploy-client.d.ts +176 -0
- package/dist/internal/deploy-client.d.ts.map +1 -0
- package/dist/internal/deploy-client.js +375 -0
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +73 -5
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +1 -0
- package/dist/internal/eval-run-store.d.ts +22 -3
- package/dist/internal/eval-run-store.d.ts.map +1 -1
- package/dist/internal/eval-run-store.js +37 -19
- package/dist/internal/handleAgentServeTrigger.d.ts.map +1 -1
- package/dist/internal/handleAgentServeTrigger.js +10 -12
- package/dist/internal/host-platforms.d.ts +7 -2
- package/dist/internal/host-platforms.d.ts.map +1 -1
- package/dist/internal/host-platforms.js +15 -10
- package/dist/internal/hosting.d.ts +37 -0
- package/dist/internal/hosting.d.ts.map +1 -0
- package/dist/internal/hosting.js +67 -0
- package/dist/internal/reminder-runner.d.ts +7 -0
- package/dist/internal/reminder-runner.d.ts.map +1 -1
- package/dist/internal/reminder-runner.js +50 -6
- package/dist/internal/reminder-store.d.ts +2 -0
- package/dist/internal/reminder-store.d.ts.map +1 -1
- package/dist/internal/reminder-store.js +18 -0
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +173 -42
- package/dist/internal/session-engine.d.ts +49 -0
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +246 -17
- package/dist/internal/storage-coordinator.d.ts +139 -0
- package/dist/internal/storage-coordinator.d.ts.map +1 -0
- package/dist/internal/storage-coordinator.js +499 -0
- package/dist/playground/assets/cursor-icons-outline-BxTT_FVJ.woff2 +0 -0
- package/dist/playground/assets/index-B1Qc9h2u.css +1 -0
- package/dist/playground/assets/{index-FlWjhg3x.js → index-CpDYCj8W.js} +42 -42
- package/dist/playground/index.html +2 -2
- package/dist/storage.d.ts +204 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +153 -0
- package/dist/types.d.ts +44 -3
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +3 -2
- package/docs/guides/github.md +43 -8
- package/docs/guides/slack.md +1 -1
- package/docs/quickstart.md +329 -51
- package/docs/reference/instructions.md +8 -6
- package/docs/scaffolding-agents.md +1 -1
- package/docs/storage.md +98 -0
- package/package.json +8 -1
- package/skills/github/SKILL.md +9 -1
- package/src/bin/agent-serve.ts +139 -0
- package/src/channels/github/api.ts +42 -23
- package/src/channels/github/cursor-account.ts +165 -0
- package/src/channels/github/github-channel.ts +66 -6
- package/src/channels/github/index.ts +2 -2
- package/src/channels/github/types.ts +19 -0
- package/src/channels/slack/slack-channel.ts +17 -3
- package/src/channels/slack/types.ts +44 -3
- package/src/index.ts +13 -0
- package/src/internal/cli-deploy.ts +940 -0
- package/src/internal/cursor/backend-client.ts +103 -1
- package/src/internal/cursor/github-credentials.ts +248 -0
- package/src/internal/deploy-client.ts +591 -0
- package/src/internal/discovery.ts +88 -1
- package/src/internal/distribution.ts +1 -0
- package/src/internal/eval-run-store.ts +48 -19
- package/src/internal/handleAgentServeTrigger.ts +10 -12
- package/src/internal/host-platforms.ts +28 -11
- package/src/internal/hosting.ts +77 -0
- package/src/internal/reminder-runner.ts +50 -6
- package/src/internal/reminder-store.ts +21 -0
- package/src/internal/server.ts +213 -27
- package/src/internal/session-engine.ts +285 -7
- package/src/internal/storage-coordinator.ts +615 -0
- package/src/storage.ts +325 -0
- package/src/types.ts +40 -2
- package/dist/docs/assets/chunks/@localSearchIndexroot.CcVk1uKq.js +0 -1
- package/dist/docs/assets/index.md.BPKcj5AI.js +0 -20
- package/dist/docs/assets/quickstart.md.tVPiGK_L.js +0 -35
- package/dist/docs/assets/quickstart.md.tVPiGK_L.lean.js +0 -1
- package/dist/docs/assets/scaffolding-agents.md.CyYfWGdc.js +0 -1
- package/dist/docs/assets/scaffolding-agents.md.CyYfWGdc.lean.js +0 -1
- package/dist/playground/assets/cursor-icons-outline-oY2V_mvK.woff2 +0 -0
- package/dist/playground/assets/index-1K-hG-7p.css +0 -1
- /package/dist/docs/assets/{evals.md.DPZ_MAnI.lean.js → evals.md.DAgEc_hL.lean.js} +0 -0
- /package/dist/docs/assets/{guides_agent-to-agent.md.CrtrsySy.lean.js → guides_agent-to-agent.md.Bpzgq2Pq.lean.js} +0 -0
- /package/dist/docs/assets/{guides_cloud-runtime.md.CYlNMTNp.lean.js → guides_cloud-runtime.md.gVzabdQL.lean.js} +0 -0
- /package/dist/docs/assets/{guides_human-in-the-loop.md.Dvuctx7s.lean.js → guides_human-in-the-loop.md.DlUqsp1S.lean.js} +0 -0
- /package/dist/docs/assets/{guides_webhooks.md.hFTik3lf.lean.js → guides_webhooks.md.B1EswtUu.lean.js} +0 -0
- /package/dist/docs/assets/{reference_connections.md.C3vNH_DE.lean.js → reference_connections.md.zaEYCLHT.lean.js} +0 -0
- /package/dist/docs/assets/{reference_http-api.md.DBAahtdz.lean.js → reference_http-api.md.Dx_nmDG6.lean.js} +0 -0
- /package/dist/docs/assets/{reference_schedules.md.D7qijxLk.lean.js → reference_schedules.md.w_F2mXB6.lean.js} +0 -0
- /package/dist/docs/assets/{reference_subagents.md.CIRAVcPK.lean.js → reference_subagents.md.zWAMNfi1.lean.js} +0 -0
- /package/dist/docs/assets/{reference_tools.md.DF5kwlt0.lean.js → reference_tools.md.CqgJroI0.lean.js} +0 -0
package/docs/storage.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Storage"
|
|
3
|
+
description: "Point agentkit's durable storage at a backend you own with defineStorage."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Storage
|
|
7
|
+
|
|
8
|
+
agentkit owns durable storage for sessions, continuation tokens,
|
|
9
|
+
reminders, playground eval history, and live A/B samples. It chooses the
|
|
10
|
+
keys (under `agentkit/v1/`), when to read and write, and how to restore
|
|
11
|
+
after restart.
|
|
12
|
+
|
|
13
|
+
Keys have bounded length: caller-controlled segments (channel ids,
|
|
14
|
+
continuation tokens) are URI-encoded, and any segment past 256 encoded
|
|
15
|
+
bytes is replaced by its `sha256:…` digest — deterministically, so writes
|
|
16
|
+
and lookups always agree. Backends can rely on this instead of imposing
|
|
17
|
+
their own key-length caps (which would silently drop writes, since a
|
|
18
|
+
throwing `put` is at-most-once).
|
|
19
|
+
|
|
20
|
+
By default that storage lives under `--state-root` on local disk. Fine
|
|
21
|
+
for one machine; it does not survive replacing the host.
|
|
22
|
+
|
|
23
|
+
To keep the same framework storage across hosts, plug in a key-value
|
|
24
|
+
backend with `agent/storage.ts`. You provide `put` / `get` / `delete` /
|
|
25
|
+
`list`. agentkit does the rest.
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
// agent/storage.ts
|
|
29
|
+
import { defineStorage } from "@cursor/july/storage";
|
|
30
|
+
|
|
31
|
+
export default defineStorage({
|
|
32
|
+
put: (key, value) => db.upsert(key, value),
|
|
33
|
+
get: (key) => db.get(key),
|
|
34
|
+
delete: (key) => db.delete(key),
|
|
35
|
+
list: (prefix) => db.listByPrefix(prefix), // [{ key, value }], key order
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
> [!NOTE]
|
|
40
|
+
> Import paths here use `@cursor/july/storage`. On projects still
|
|
41
|
+
> using `@anysphere/agent-serve`, swap the import. See
|
|
42
|
+
> [Run the CLI](./README.md#run-the-cli) for the full rename table.
|
|
43
|
+
|
|
44
|
+
## Which methods to provide
|
|
45
|
+
|
|
46
|
+
| Method | Required | Role |
|
|
47
|
+
| --- | --- | --- |
|
|
48
|
+
| `put` | Yes | Write or update a value |
|
|
49
|
+
| `get` | For restore | Look up one key |
|
|
50
|
+
| `list` | For restore | Return entries under a prefix, in key order |
|
|
51
|
+
| `delete` | For cleanup | Remove a key |
|
|
52
|
+
|
|
53
|
+
A throwing `put` is logged and dropped. It never fails a turn. When
|
|
54
|
+
resolving a missing continuation token, a throwing `get` fails the
|
|
55
|
+
follow-up so a store outage does not open a new session. Return
|
|
56
|
+
`undefined` only for a real miss.
|
|
57
|
+
|
|
58
|
+
## Policy
|
|
59
|
+
|
|
60
|
+
Two knobs change behavior:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
export default defineStorage({
|
|
64
|
+
policy: {
|
|
65
|
+
// Batch event writes while the session is busy (default: once per turn)
|
|
66
|
+
debounceMs: 30_000,
|
|
67
|
+
// Cap how much loads at serve start, or "off" to restore on demand
|
|
68
|
+
restore: { maxSessions: 500 },
|
|
69
|
+
},
|
|
70
|
+
// put / get / delete / list …
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
| Knob | Default | Meaning |
|
|
75
|
+
| --- | --- | --- |
|
|
76
|
+
| `debounceMs` | unset (once per turn) | Wait this long after activity before writing event batches |
|
|
77
|
+
| `restore` | caps below | How much to load at serve start |
|
|
78
|
+
| `restore.maxSessions` | `1000` | Max sessions loaded at serve start |
|
|
79
|
+
| `restore.maxAgeMs` | 30 days | Skip older sessions at serve start |
|
|
80
|
+
| `restore.maxTotalBytes` | 1 GiB | Stop loading once this budget is reached |
|
|
81
|
+
|
|
82
|
+
Set `restore: "off"` on high-traffic hosts. Sessions then load when a
|
|
83
|
+
follow-up arrives instead of at startup.
|
|
84
|
+
|
|
85
|
+
## Restore after restart
|
|
86
|
+
|
|
87
|
+
With `get` and `list`, serve can rebuild local state from your store:
|
|
88
|
+
|
|
89
|
+
- At startup, agentkit loads recent sessions up to the restore caps.
|
|
90
|
+
Local disk wins when both sides have the same session. Reminders
|
|
91
|
+
hydrate the same way into `--state-root/reminders`.
|
|
92
|
+
- On demand, a missing continuation token resolves through the store
|
|
93
|
+
and resumes that session.
|
|
94
|
+
- Playground eval history and A/B aggregates can load from the same
|
|
95
|
+
sink.
|
|
96
|
+
|
|
97
|
+
A turn in flight at crash time is not replayed. The next follow-up
|
|
98
|
+
resumes from the last flushed state.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cursor/july",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
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": {
|
|
@@ -117,6 +117,13 @@
|
|
|
117
117
|
"import": "./dist/ab.js",
|
|
118
118
|
"default": "./dist/ab.js"
|
|
119
119
|
},
|
|
120
|
+
"./storage": {
|
|
121
|
+
"anysphere-source": "./src/storage.ts",
|
|
122
|
+
"bun": "./src/storage.ts",
|
|
123
|
+
"types": "./dist/storage.d.ts",
|
|
124
|
+
"import": "./dist/storage.js",
|
|
125
|
+
"default": "./dist/storage.js"
|
|
126
|
+
},
|
|
120
127
|
"./package.json": {
|
|
121
128
|
"anysphere-source": "./package.json",
|
|
122
129
|
"bun": "./package.json",
|
package/skills/github/SKILL.md
CHANGED
|
@@ -20,7 +20,8 @@ import { defaultGitHubAuth, githubChannel } from "@anysphere/agent-serve/channel
|
|
|
20
20
|
|
|
21
21
|
export default githubChannel({
|
|
22
22
|
botName: "my-agent", // or GITHUB_APP_SLUG; used to ignore self-comments
|
|
23
|
-
|
|
23
|
+
cursorAccount: { repos: ["owner/repo"] }, // permissions?: "read" | "pr-write" | "contents-write"
|
|
24
|
+
|
|
24
25
|
onPullRequest: (ctx, pr) =>
|
|
25
26
|
pr.action === "opened" ? { auth: defaultGitHubAuth(ctx) } : null,
|
|
26
27
|
onCheckSuite: (ctx, suite) =>
|
|
@@ -44,6 +45,13 @@ the model should reason about the event.
|
|
|
44
45
|
|
|
45
46
|
## Auth modes
|
|
46
47
|
|
|
48
|
+
- **`cursorAccount`** → the signed-in Cursor principal supplies both the SCM
|
|
49
|
+
event stream and a short-lived, repo-scoped GitHub credential. It works in
|
|
50
|
+
local dev (`agentkit login`) and hosted deployments (`CURSOR_API_KEY`).
|
|
51
|
+
`ctx.github`, `ctx.host.github`, and child `gh` commands share the lease.
|
|
52
|
+
Use `{ repos: ["owner/repo"] }`, or `true` with `serve --cursor-events
|
|
53
|
+
--repo owner/repo`. One host credential covers up to 20 repositories under
|
|
54
|
+
one GitHub owner; it cannot span owners.
|
|
47
55
|
- **Secret set** → route auth is `allowAll()` + `X-Hub-Signature-256`
|
|
48
56
|
verification before parsing; the HMAC becomes the request principal.
|
|
49
57
|
- **No secret** → `localDevStrict()` (loopback only) — except under
|
package/src/bin/agent-serve.ts
CHANGED
|
@@ -31,6 +31,18 @@ import {
|
|
|
31
31
|
cmdRun,
|
|
32
32
|
cmdTrajectory,
|
|
33
33
|
} from "../internal/cli-ax.js";
|
|
34
|
+
import {
|
|
35
|
+
cmdDeploy,
|
|
36
|
+
cmdDeploymentStatus,
|
|
37
|
+
cmdDeployments,
|
|
38
|
+
cmdRotatePodCredential,
|
|
39
|
+
cmdRotateToken,
|
|
40
|
+
cmdSecretsList,
|
|
41
|
+
cmdSecretsSet,
|
|
42
|
+
cmdSecretsUnset,
|
|
43
|
+
cmdStop,
|
|
44
|
+
type DeployCliOptions,
|
|
45
|
+
} from "../internal/cli-deploy.js";
|
|
34
46
|
import { CLI_COMMAND_NAME as CLI } from "../internal/distribution.js";
|
|
35
47
|
import { runSession } from "../internal/run-client.js";
|
|
36
48
|
import { formatTrajectoryText } from "../internal/trajectory.js";
|
|
@@ -60,6 +72,17 @@ Usage:
|
|
|
60
72
|
${CLI} login [--api-key <key>] [--key-name <name>]
|
|
61
73
|
${CLI} logout
|
|
62
74
|
${CLI} whoami [--json]
|
|
75
|
+
${CLI} deploy [--dir <path>] [--slug <slug>] [--team <id>] [--json]
|
|
76
|
+
[--no-wait] [--repo <url>] [--ref <ref>]
|
|
77
|
+
[--path <agentPath>] [--cursor-events-repo <owner/name>]...
|
|
78
|
+
[--allow-domain <domain>]...
|
|
79
|
+
${CLI} deployments [--team <id>] [--json]
|
|
80
|
+
${CLI} deployment <slug> [--team <id>] [--json]
|
|
81
|
+
${CLI} stop <slug> [--team <id>] [--json] [--no-wait]
|
|
82
|
+
${CLI} rotate-token <slug> [--team <id>]
|
|
83
|
+
${CLI} rotate-pod-credential <slug> [--team <id>]
|
|
84
|
+
${CLI} secrets set <slug> NAME[=VALUE]... | list <slug> | unset <slug> NAME
|
|
85
|
+
[--team <id>] [--json]
|
|
63
86
|
${CLI} slack <subcommand> …
|
|
64
87
|
${CLI} github <subcommand> …
|
|
65
88
|
|
|
@@ -86,6 +109,20 @@ Commands:
|
|
|
86
109
|
inference, cloud runtime, and cursorAccount MCP connections.
|
|
87
110
|
logout Remove the stored Cursor credentials.
|
|
88
111
|
whoami Show which Cursor account powers this host (and why).
|
|
112
|
+
deploy Deploy onto Cursor's managed agent-serve hosting, then wait for
|
|
113
|
+
the engine to come up. First deploy of a slug prints the alias
|
|
114
|
+
token exactly once — save it.
|
|
115
|
+
deployments List the team's deployments (slug, status, generation, kind).
|
|
116
|
+
deployment Show one deployment in full (status, lastError, engine info).
|
|
117
|
+
stop Stop a deployment and wait until it reports stopped.
|
|
118
|
+
rotate-token Mint a new alias token for a deployment (shown once); the old
|
|
119
|
+
token stops working immediately.
|
|
120
|
+
rotate-pod-credential
|
|
121
|
+
Rotate a deployment's pod credential (prints the masked key);
|
|
122
|
+
the running pod keeps the old one until the next deploy.
|
|
123
|
+
secrets Manage deployment secrets: set (upsert by name; NAMEs without
|
|
124
|
+
=VALUE are prompted for with hidden input, or read from piped
|
|
125
|
+
stdin), list (names + createdAt; never values), unset.
|
|
89
126
|
slack Slack channel pack: init, manifests, doctor (see slack help).
|
|
90
127
|
github GitHub webhook pack: forward live deliveries, events, doctor
|
|
91
128
|
(wraps \`gh webhook forward\`; see github help).
|
|
@@ -120,6 +157,10 @@ Options:
|
|
|
120
157
|
connections (defineConnection({ agent })) on cloud-runtime
|
|
121
158
|
turns; local turns always use loopback.
|
|
122
159
|
--no-schedules Disable the cron runner outside dev mode.
|
|
160
|
+
--team deploy/deployments/deployment/stop/rotate-token: Cursor
|
|
161
|
+
team id. Defaults to the account's team when it has one.
|
|
162
|
+
--no-wait deploy/stop: return right after the request is accepted
|
|
163
|
+
instead of polling until a terminal status.
|
|
123
164
|
--no-playground Disable the bundled web playground at /playground (also skips
|
|
124
165
|
auto-build / HMR).
|
|
125
166
|
--no-docs Disable the documentation site at /docs (also skips its
|
|
@@ -150,6 +191,15 @@ Options:
|
|
|
150
191
|
--repo serve --cursor-events: repo to subscribe to (repeatable).
|
|
151
192
|
github forward: owner/repo to forward from (inferred from
|
|
152
193
|
the git remote when omitted; last wins).
|
|
194
|
+
deploy: https git repo URL the control plane builds from.
|
|
195
|
+
--ref deploy: git ref to build (defaults to the repo's default
|
|
196
|
+
branch server-side).
|
|
197
|
+
--path deploy: agent directory relative to the repo root.
|
|
198
|
+
--cursor-events-repo deploy: repo (owner/name) whose SCM events the
|
|
199
|
+
deployed engine pulls (repeatable).
|
|
200
|
+
--allow-domain deploy: egress domain the engine pod may reach
|
|
201
|
+
(repeatable; unioned with hosting.egressDomains from the
|
|
202
|
+
agent manifest). Repo-backed deploys only.
|
|
153
203
|
--org github forward: organization login (org-level hooks).
|
|
154
204
|
--channel github: select one channel id when several are declared.
|
|
155
205
|
--secret github forward: webhook signing secret (defaults to
|
|
@@ -233,6 +283,12 @@ async function main(argv: string[]): Promise<number> {
|
|
|
233
283
|
comment: { type: "string" },
|
|
234
284
|
"dry-run": { type: "boolean", default: false },
|
|
235
285
|
out: { type: "string" },
|
|
286
|
+
team: { type: "string" },
|
|
287
|
+
"no-wait": { type: "boolean", default: false },
|
|
288
|
+
ref: { type: "string" },
|
|
289
|
+
path: { type: "string" },
|
|
290
|
+
"cursor-events-repo": { type: "string", multiple: true },
|
|
291
|
+
"allow-domain": { type: "string", multiple: true },
|
|
236
292
|
},
|
|
237
293
|
});
|
|
238
294
|
const dir = values.dir ?? ".";
|
|
@@ -317,6 +373,69 @@ async function main(argv: string[]): Promise<number> {
|
|
|
317
373
|
return cmdWhoami({ json: values.json });
|
|
318
374
|
}
|
|
319
375
|
|
|
376
|
+
case "deploy": {
|
|
377
|
+
// `--repo` is repeatable for `serve --cursor-events`; deploy targets a
|
|
378
|
+
// single source repo, so the last one wins.
|
|
379
|
+
const repo = values.repo?.at(-1);
|
|
380
|
+
return cmdDeploy({
|
|
381
|
+
...deployOptionsFromValues(values),
|
|
382
|
+
dir,
|
|
383
|
+
...(values.slug === undefined ? {} : { slug: values.slug }),
|
|
384
|
+
...(repo === undefined ? {} : { repo }),
|
|
385
|
+
...(values.ref === undefined ? {} : { ref: values.ref }),
|
|
386
|
+
...(values.path === undefined ? {} : { path: values.path }),
|
|
387
|
+
...(values["cursor-events-repo"] === undefined
|
|
388
|
+
? {}
|
|
389
|
+
: { cursorEventsRepos: values["cursor-events-repo"] }),
|
|
390
|
+
...(values["allow-domain"] === undefined
|
|
391
|
+
? {}
|
|
392
|
+
: { allowDomains: values["allow-domain"] }),
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
case "deployments": {
|
|
397
|
+
return cmdDeployments(deployOptionsFromValues(values));
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
case "deployment": {
|
|
401
|
+
return cmdDeploymentStatus(
|
|
402
|
+
positionals[0],
|
|
403
|
+
deployOptionsFromValues(values)
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
case "stop": {
|
|
408
|
+
return cmdStop(positionals[0], deployOptionsFromValues(values));
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
case "rotate-token": {
|
|
412
|
+
return cmdRotateToken(positionals[0], deployOptionsFromValues(values));
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
case "rotate-pod-credential": {
|
|
416
|
+
return cmdRotatePodCredential(
|
|
417
|
+
positionals[0],
|
|
418
|
+
deployOptionsFromValues(values)
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
case "secrets": {
|
|
423
|
+
const base = deployOptionsFromValues(values);
|
|
424
|
+
switch (positionals[0]) {
|
|
425
|
+
case "set":
|
|
426
|
+
return cmdSecretsSet(positionals[1], positionals.slice(2), base);
|
|
427
|
+
case "list":
|
|
428
|
+
return cmdSecretsList(positionals[1], base);
|
|
429
|
+
case "unset":
|
|
430
|
+
return cmdSecretsUnset(positionals[1], positionals[2], base);
|
|
431
|
+
default:
|
|
432
|
+
process.stderr.write(
|
|
433
|
+
`Usage: ${CLI} secrets <set|list|unset> <slug> ... [--team <id>] [--json]\n`
|
|
434
|
+
);
|
|
435
|
+
return 1;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
320
439
|
case "run": {
|
|
321
440
|
const messages = await loadMessages(
|
|
322
441
|
values.message,
|
|
@@ -511,6 +630,12 @@ async function main(argv: string[]): Promise<number> {
|
|
|
511
630
|
)
|
|
512
631
|
);
|
|
513
632
|
lines.push(section("hooks", info.hooks));
|
|
633
|
+
lines.push(
|
|
634
|
+
section("hosting egress domains", info.hosting?.egressDomains ?? [])
|
|
635
|
+
);
|
|
636
|
+
lines.push(
|
|
637
|
+
section("hosting secret names", info.hosting?.secretNames ?? [])
|
|
638
|
+
);
|
|
514
639
|
if (info.diagnostics.length > 0) {
|
|
515
640
|
lines.push(`\ndiagnostics:\n${formatDiagnostics(info.diagnostics)}`);
|
|
516
641
|
}
|
|
@@ -646,6 +771,20 @@ async function main(argv: string[]): Promise<number> {
|
|
|
646
771
|
}
|
|
647
772
|
}
|
|
648
773
|
|
|
774
|
+
function deployOptionsFromValues(values: {
|
|
775
|
+
team?: string;
|
|
776
|
+
json?: boolean;
|
|
777
|
+
"no-wait"?: boolean;
|
|
778
|
+
"api-key"?: string;
|
|
779
|
+
}): DeployCliOptions {
|
|
780
|
+
return {
|
|
781
|
+
...(values.team === undefined ? {} : { team: values.team }),
|
|
782
|
+
json: values.json === true,
|
|
783
|
+
noWait: values["no-wait"] === true,
|
|
784
|
+
...(values["api-key"] === undefined ? {} : { apiKey: values["api-key"] }),
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
|
|
649
788
|
function axFromOptions(
|
|
650
789
|
partial: Partial<AxCliOptions> & { dir: string }
|
|
651
790
|
): AxCliOptions {
|
|
@@ -17,6 +17,10 @@ import {
|
|
|
17
17
|
resolveGitHubInstallationId,
|
|
18
18
|
resolveGitHubPrivateKey,
|
|
19
19
|
} from "./auth.js";
|
|
20
|
+
import {
|
|
21
|
+
type CursorAccountGithubTokenResolver,
|
|
22
|
+
isCursorAccountGithubTokenResolver,
|
|
23
|
+
} from "./cursor-account.js";
|
|
20
24
|
import type { GitHubChannelCredentials } from "./types.js";
|
|
21
25
|
|
|
22
26
|
export type GitHubJsonObject = Record<string, unknown>;
|
|
@@ -91,19 +95,31 @@ export async function createGitHubOctokit(input: {
|
|
|
91
95
|
credentials?: GitHubChannelCredentials;
|
|
92
96
|
installationId?: number;
|
|
93
97
|
}): Promise<Octokit> {
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
const
|
|
98
|
+
const transport = githubOctokitTransport(input.api);
|
|
99
|
+
|
|
100
|
+
const dynamicToken: CursorAccountGithubTokenResolver | undefined =
|
|
101
|
+
isCursorAccountGithubTokenResolver(input.credentials?.token)
|
|
102
|
+
? input.credentials.token
|
|
103
|
+
: isCursorAccountGithubTokenResolver(input.credentials?.installationToken)
|
|
104
|
+
? input.credentials.installationToken
|
|
105
|
+
: undefined;
|
|
106
|
+
if (dynamicToken !== undefined) {
|
|
107
|
+
const octokit = new Octokit(transport);
|
|
108
|
+
octokit.hook.before("request", async (request) => {
|
|
109
|
+
const token = await resolveCredentialValue(dynamicToken);
|
|
110
|
+
if (token === undefined) {
|
|
111
|
+
throw new Error("githubChannel: dynamic GitHub token is unavailable.");
|
|
112
|
+
}
|
|
113
|
+
request.headers.authorization = `Bearer ${token}`;
|
|
114
|
+
});
|
|
115
|
+
return octokit;
|
|
116
|
+
}
|
|
97
117
|
|
|
98
118
|
const explicit =
|
|
99
119
|
(await resolveCredentialValue(input.credentials?.token)) ??
|
|
100
120
|
(await resolveCredentialValue(input.credentials?.installationToken));
|
|
101
121
|
if (explicit !== undefined) {
|
|
102
|
-
return new Octokit({
|
|
103
|
-
auth: explicit,
|
|
104
|
-
...(baseUrl === undefined ? {} : { baseUrl }),
|
|
105
|
-
...(requestOptions === undefined ? {} : { request: requestOptions }),
|
|
106
|
-
});
|
|
122
|
+
return new Octokit({ ...transport, auth: explicit });
|
|
107
123
|
}
|
|
108
124
|
|
|
109
125
|
const installationId = await resolveGitHubInstallationId(
|
|
@@ -118,26 +134,34 @@ export async function createGitHubOctokit(input: {
|
|
|
118
134
|
input.credentials?.privateKey
|
|
119
135
|
);
|
|
120
136
|
return new Octokit({
|
|
137
|
+
...transport,
|
|
121
138
|
authStrategy: createAppAuth,
|
|
122
139
|
auth: {
|
|
123
140
|
appId,
|
|
124
141
|
privateKey,
|
|
125
142
|
installationId,
|
|
126
143
|
},
|
|
127
|
-
...(baseUrl === undefined ? {} : { baseUrl }),
|
|
128
|
-
...(requestOptions === undefined ? {} : { request: requestOptions }),
|
|
129
144
|
});
|
|
130
145
|
}
|
|
131
146
|
|
|
132
147
|
// Local testing: ambient PAT / `gh auth token` when App creds are unset.
|
|
133
|
-
const token = await resolveGitHubAccessToken(input);
|
|
134
148
|
return new Octokit({
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
...(requestOptions === undefined ? {} : { request: requestOptions }),
|
|
149
|
+
...transport,
|
|
150
|
+
auth: await resolveGitHubAccessToken(input),
|
|
138
151
|
});
|
|
139
152
|
}
|
|
140
153
|
|
|
154
|
+
/** Shared `baseUrl` / custom `fetch` for every Octokit constructed here. */
|
|
155
|
+
function githubOctokitTransport(api: GitHubApiOptions | undefined): {
|
|
156
|
+
baseUrl?: string;
|
|
157
|
+
request?: { fetch: typeof fetch };
|
|
158
|
+
} {
|
|
159
|
+
return {
|
|
160
|
+
baseUrl: api?.apiBaseUrl,
|
|
161
|
+
request: api?.fetch === undefined ? undefined : { fetch: api.fetch },
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
141
165
|
/**
|
|
142
166
|
* Call a GitHub REST path with channel auth. Prefer typed Octokit methods via
|
|
143
167
|
* {@link createGitHubOctokit} / `ctx.github.getOctokit()` when possible.
|
|
@@ -152,15 +176,10 @@ export async function callGitHubApi<T = unknown>(input: {
|
|
|
152
176
|
options?: { auth?: boolean; headers?: Readonly<Record<string, string>> };
|
|
153
177
|
}): Promise<GitHubApiResponse<T>> {
|
|
154
178
|
if (input.options?.auth === false) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
...(input.api?.fetch === undefined
|
|
160
|
-
? {}
|
|
161
|
-
: { request: { fetch: input.api.fetch } }),
|
|
162
|
-
});
|
|
163
|
-
return requestWithOctokit(octokit, input);
|
|
179
|
+
return requestWithOctokit(
|
|
180
|
+
new Octokit(githubOctokitTransport(input.api)),
|
|
181
|
+
input
|
|
182
|
+
);
|
|
164
183
|
}
|
|
165
184
|
|
|
166
185
|
const octokit = await createGitHubOctokit({
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor-account mode for GitHub channels.
|
|
3
|
+
*
|
|
4
|
+
* The channel declares the intent at definition time. The serve host binds
|
|
5
|
+
* this placeholder to its signed-in Cursor account after it resolves the
|
|
6
|
+
* repository scope into private runtime metadata (never by rewriting the
|
|
7
|
+
* authored `cursorAccount` options object).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { GitHubChannelOptions } from "./types.js";
|
|
11
|
+
|
|
12
|
+
export const CURSOR_GITHUB_MAX_REPOS = 20;
|
|
13
|
+
const CURSOR_GITHUB_REPO_PATTERN = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
|
14
|
+
const cursorAccountTokenResolvers = new WeakSet<object>();
|
|
15
|
+
|
|
16
|
+
/** Least → most privilege. Host mints one lease at the max requested tier. */
|
|
17
|
+
export const CURSOR_GITHUB_PERMISSIONS = [
|
|
18
|
+
"read",
|
|
19
|
+
"pr-write",
|
|
20
|
+
"contents-write",
|
|
21
|
+
] as const;
|
|
22
|
+
|
|
23
|
+
export type CursorGithubPermissions =
|
|
24
|
+
(typeof CURSOR_GITHUB_PERMISSIONS)[number];
|
|
25
|
+
|
|
26
|
+
export interface CursorGithubRepoScope {
|
|
27
|
+
owner: string;
|
|
28
|
+
repos: readonly string[];
|
|
29
|
+
permissions: CursorGithubPermissions;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type CursorAccountGithubTokenResolver = () => Promise<string>;
|
|
33
|
+
|
|
34
|
+
export interface PendingCursorGithubCredentials {
|
|
35
|
+
bind(getToken: () => Promise<string>): void;
|
|
36
|
+
getToken(): Promise<string>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface GithubCursorAccountRuntime {
|
|
40
|
+
/** Authored channel options (not rewritten). */
|
|
41
|
+
options: GitHubChannelOptions;
|
|
42
|
+
credentials: PendingCursorGithubCredentials;
|
|
43
|
+
/**
|
|
44
|
+
* Normalized repo + permissions scope when `cursorAccount` is an object.
|
|
45
|
+
* Absent for `cursorAccount: true` (scope comes from serve `--repo`).
|
|
46
|
+
*/
|
|
47
|
+
scope: CursorGithubRepoScope | undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const runtimeByDefinition = new WeakMap<object, GithubCursorAccountRuntime>();
|
|
51
|
+
|
|
52
|
+
export function parseCursorGithubPermissions(
|
|
53
|
+
value: unknown,
|
|
54
|
+
fallback: CursorGithubPermissions = "pr-write"
|
|
55
|
+
): CursorGithubPermissions {
|
|
56
|
+
if (value === undefined) {
|
|
57
|
+
return fallback;
|
|
58
|
+
}
|
|
59
|
+
if (value === "read" || value === "pr-write" || value === "contents-write") {
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
throw new Error(
|
|
63
|
+
'Cursor account GitHub permissions must be "read", "pr-write", or "contents-write".'
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function parseCursorGithubRepoScope(
|
|
68
|
+
values: readonly string[],
|
|
69
|
+
permissions: CursorGithubPermissions = "pr-write"
|
|
70
|
+
): CursorGithubRepoScope {
|
|
71
|
+
const repos = [
|
|
72
|
+
...new Set(values.map((repo) => repo.trim().toLowerCase()).filter(Boolean)),
|
|
73
|
+
];
|
|
74
|
+
if (repos.length === 0) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
"Cursor account GitHub credentials require at least one repository."
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
if (repos.length > CURSOR_GITHUB_MAX_REPOS) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`Cursor account GitHub credentials support at most ${CURSOR_GITHUB_MAX_REPOS} repositories.`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
for (const repo of repos) {
|
|
85
|
+
if (!CURSOR_GITHUB_REPO_PATTERN.test(repo) || repo.includes("..")) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`Invalid Cursor account GitHub repository "${repo}"; expected owner/repo.`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const owner = repos[0]?.split("/", 1)[0];
|
|
92
|
+
if (owner === undefined) {
|
|
93
|
+
throw new Error("Cursor account GitHub repository owner is missing.");
|
|
94
|
+
}
|
|
95
|
+
if (repos.some((repo) => repo.split("/", 1)[0] !== owner)) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
"Cursor account GitHub repositories must share one owner for a single installation token."
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
owner,
|
|
102
|
+
repos,
|
|
103
|
+
permissions: parseCursorGithubPermissions(permissions),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** One host credential: the most privileged requested tier wins. */
|
|
108
|
+
export function resolveCursorGithubPermissions(
|
|
109
|
+
values: readonly CursorGithubPermissions[]
|
|
110
|
+
): CursorGithubPermissions {
|
|
111
|
+
let max: CursorGithubPermissions = "read";
|
|
112
|
+
for (const value of values) {
|
|
113
|
+
if (
|
|
114
|
+
CURSOR_GITHUB_PERMISSIONS.indexOf(value) >
|
|
115
|
+
CURSOR_GITHUB_PERMISSIONS.indexOf(max)
|
|
116
|
+
) {
|
|
117
|
+
max = value;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return values.length === 0 ? "pr-write" : max;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function createCursorAccountGithubTokenResolver(
|
|
124
|
+
getToken: () => Promise<string>
|
|
125
|
+
): CursorAccountGithubTokenResolver {
|
|
126
|
+
const resolver = () => getToken();
|
|
127
|
+
cursorAccountTokenResolvers.add(resolver);
|
|
128
|
+
return resolver;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function isCursorAccountGithubTokenResolver(
|
|
132
|
+
value: unknown
|
|
133
|
+
): value is CursorAccountGithubTokenResolver {
|
|
134
|
+
return typeof value === "function" && cursorAccountTokenResolvers.has(value);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function createPendingCursorGithubCredentials(): PendingCursorGithubCredentials {
|
|
138
|
+
let getBoundToken: (() => Promise<string>) | undefined;
|
|
139
|
+
return {
|
|
140
|
+
bind(getToken) {
|
|
141
|
+
getBoundToken = getToken;
|
|
142
|
+
},
|
|
143
|
+
getToken() {
|
|
144
|
+
if (getBoundToken === undefined) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
"githubChannel({ cursorAccount: true }) has not been bound to a signed-in Cursor host."
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
return getBoundToken();
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function registerGithubCursorAccountRuntime(
|
|
155
|
+
definition: object,
|
|
156
|
+
runtime: GithubCursorAccountRuntime
|
|
157
|
+
): void {
|
|
158
|
+
runtimeByDefinition.set(definition, runtime);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function getGithubCursorAccountRuntime(
|
|
162
|
+
definition: object
|
|
163
|
+
): GithubCursorAccountRuntime | undefined {
|
|
164
|
+
return runtimeByDefinition.get(definition);
|
|
165
|
+
}
|