@mushi-mushi/plugin-cursor-cloud 0.5.1 → 0.6.1
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/README.md +51 -22
- package/dist/index.d.ts +50 -15
- package/dist/index.js +89 -30
- package/dist/index.js.map +1 -1
- package/package.json +7 -11
package/README.md
CHANGED
|
@@ -9,12 +9,14 @@ Part of the Mushi Mushi monorepo — plain-English bug comprehension for vibe co
|
|
|
9
9
|
[](./LICENSE)
|
|
10
10
|
[](./src/index.ts)
|
|
11
11
|
|
|
12
|
-
> Mushi Mushi plugin: dispatch a [Cursor Cloud Agent](https://cursor.com/docs/cloud-agent/api/
|
|
12
|
+
> Mushi Mushi plugin: dispatch a [Cursor Cloud Agent](https://cursor.com/docs/cloud-agent/api/endpoints) when a critical bug is classified or a fix is requested. The agent investigates, opens a draft PR, and reports back through the Cursor REST API (**v1**).
|
|
13
13
|
|
|
14
14
|
This is the **opt-in marketplace** path. Teams install it in the Mushi admin
|
|
15
|
-
console, configure their Cursor API key +
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
console, configure their Cursor API key + repo URL, and pick a severity
|
|
16
|
+
threshold. For the **project-wide default** Cursor agent path (no plugin
|
|
17
|
+
install needed) set `autofix_agent = 'cursor_cloud'` in the Mushi console —
|
|
18
|
+
Mushi's own fix-worker then dispatches every fix through the same v1 API,
|
|
19
|
+
polls it to completion, and closes the loop on the draft PR.
|
|
18
20
|
|
|
19
21
|
## Why this exists
|
|
20
22
|
|
|
@@ -28,7 +30,7 @@ The flow:
|
|
|
28
30
|
```
|
|
29
31
|
Mushi report → classify-report → report.classified (severity=critical)
|
|
30
32
|
→ @mushi-mushi/plugin-cursor-cloud
|
|
31
|
-
→ POST https://api.cursor.com/
|
|
33
|
+
→ POST https://api.cursor.com/v1/agents
|
|
32
34
|
→ Cursor cloud agent investigates → opens draft PR
|
|
33
35
|
→ audit log to Mushi console
|
|
34
36
|
```
|
|
@@ -42,7 +44,13 @@ This plugin spends real Cursor API credit. Three hard guards are baked in:
|
|
|
42
44
|
2. **Repo gate** — silently no-ops when no `repoUrl` is configured.
|
|
43
45
|
3. **Idempotent retries** — `withRetry` from `@mushi-mushi/plugin-sdk`
|
|
44
46
|
honours `Retry-After` and treats 4xx (other than 429) as non-retryable
|
|
45
|
-
so a bad config never burns money in a tight loop.
|
|
47
|
+
so a bad config never burns money in a tight loop. On top of that every
|
|
48
|
+
dispatch sends a deterministic `agentId` (`bc-<uuid>` derived from the
|
|
49
|
+
event + report id), so a redelivered Mushi event gets Cursor's
|
|
50
|
+
`409 agent_id_conflict` instead of a second agent.
|
|
51
|
+
4. **No double dispatch** — when Mushi's own fix-worker already handed the
|
|
52
|
+
report to Cursor (`autofix_agent = 'cursor_cloud'`), the `fix.requested`
|
|
53
|
+
payload carries `data.fix.externalAgentId` and this plugin logs and skips.
|
|
46
54
|
|
|
47
55
|
## Install
|
|
48
56
|
|
|
@@ -57,16 +65,15 @@ import { createCursorCloudPlugin } from '@mushi-mushi/plugin-cursor-cloud'
|
|
|
57
65
|
|
|
58
66
|
const handler = createCursorCloudPlugin({
|
|
59
67
|
apiKey: process.env.CURSOR_API_KEY!,
|
|
60
|
-
workspaceId: process.env.CURSOR_WORKSPACE_ID!,
|
|
61
68
|
webhookSecret: process.env.MUSHI_PLUGIN_WEBHOOK_SECRET!,
|
|
62
69
|
repoUrl: 'https://github.com/your-org/your-repo',
|
|
63
70
|
severityThreshold: 'critical',
|
|
64
|
-
// Optional —
|
|
71
|
+
// Optional — branch/ref the agent starts from (repos[].startingRef).
|
|
72
|
+
startingRef: 'main',
|
|
73
|
+
// Optional — default is composer-2.5 (sent as model.id).
|
|
65
74
|
model: 'composer-2.5',
|
|
66
|
-
// Optional — default is true (
|
|
75
|
+
// Optional — default is true (top-level autoCreatePR; Cursor opens drafts).
|
|
67
76
|
autoCreatePR: true,
|
|
68
|
-
// Optional — default is 1 (single iteration before reporting back).
|
|
69
|
-
maxIterations: 1,
|
|
70
77
|
})
|
|
71
78
|
|
|
72
79
|
// Wire to your serverless platform — Mushi calls handler with a Standard
|
|
@@ -78,26 +85,47 @@ export default handler
|
|
|
78
85
|
|
|
79
86
|
| Field | Type | Required | Default | Description |
|
|
80
87
|
|---|---|---|---|---|
|
|
81
|
-
| `apiKey` | string | yes | — | Your Cursor API key (`
|
|
82
|
-
| `workspaceId` | string | yes | — | Your Cursor workspace ID (`ws_…`). |
|
|
88
|
+
| `apiKey` | string | yes | — | Your Cursor API key (`crsr_…`). |
|
|
83
89
|
| `webhookSecret` | string | yes* | `MUSHI_PLUGIN_WEBHOOK_SECRET` | Standard Webhooks HMAC secret for inbound Mushi events. *Required for self-hosted installs. |
|
|
84
|
-
| `repoUrl` | string | recommended | — | Target repo URL. If omitted, the plugin silently no-ops. |
|
|
90
|
+
| `repoUrl` | string | recommended | — | Target repo URL (`https://github.com/org/repo`, sent as `repos[].url`). If omitted, the plugin silently no-ops. |
|
|
91
|
+
| `startingRef` | string | no | repo default branch | Branch/ref the agent starts from (`repos[].startingRef`). |
|
|
85
92
|
| `severityThreshold` | `'low' \| 'medium' \| 'high' \| 'critical'` | no | `'critical'` | Minimum severity that triggers a run. |
|
|
86
|
-
| `model` | string | no | `'composer-2.5'` | Cursor model
|
|
87
|
-
| `autoCreatePR` | boolean | no | `true` | Whether
|
|
88
|
-
| `
|
|
93
|
+
| `model` | string | no | `'composer-2.5'` | Cursor model id (`model.id`). |
|
|
94
|
+
| `autoCreatePR` | boolean | no | `true` | Whether Cursor should open a (draft) PR — top-level `autoCreatePR` in v1. |
|
|
95
|
+
| `apiBase` | string | no | `https://api.cursor.com` | Override for proxies / tests. |
|
|
89
96
|
| `fetchImpl` | `typeof fetch` | no | global `fetch` | Override for tests. |
|
|
97
|
+
| `workspaceId` | string | deprecated | — | Not used by the v1 API; accepted so old configs still type-check. |
|
|
98
|
+
| `maxIterations` | number | deprecated | — | v1 has no iteration cap; ignored. |
|
|
90
99
|
|
|
91
100
|
## Events handled
|
|
92
101
|
|
|
93
102
|
| Event | Action |
|
|
94
103
|
|---|---|
|
|
95
104
|
| `report.classified` | Dispatch a run when `data.classification.severity` ≥ `severityThreshold`. |
|
|
96
|
-
| `fix.requested` |
|
|
105
|
+
| `fix.requested` | Dispatch a run regardless of severity — unless `data.fix.externalAgentId` is set (Mushi's fix-worker already dispatched this fix to Cursor). |
|
|
97
106
|
| `qa_story.failed` | Dispatch a run when a QA story run fails all its assertions. Requires `repoUrl`. |
|
|
107
|
+
| `skill_pipeline.step.dispatched` | Run one skill-pipeline step and check the `agentId` back in via `/v1/admin/skills/pipelines/:run/steps/:idx/checkin`. |
|
|
98
108
|
|
|
99
109
|
Other events are ignored.
|
|
100
110
|
|
|
111
|
+
## v0 vs v1
|
|
112
|
+
|
|
113
|
+
Cursor serves two Cloud Agents APIs. This plugin (since 0.6.0) and Mushi's
|
|
114
|
+
fix-worker speak **v1** (`POST /v1/agents`):
|
|
115
|
+
|
|
116
|
+
| | v0 (legacy, still served) | v1 (current) |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| Request | `{ prompt:{text}, source:{repository,ref}, target:{autoCreatePr,branchName,skipReviewerRequest}, model, webhook:{url,secret} }` | `{ prompt:{text}, repos:[{url,startingRef}], autoCreatePR, agentId:'bc-<uuid>', name, model:{id}, skipReviewerRequest }` |
|
|
119
|
+
| Response | `{ id, status, target:{url,branchName,prUrl} }` | `{ agent:{id,status,url,latestRunId}, run:{id,status,git:{branches:[{repoUrl,branch,prUrl}]}} }` |
|
|
120
|
+
| Idempotency | none | `agentId` reuse ⇒ `409 agent_id_conflict` |
|
|
121
|
+
| Branch name | `target.branchName` | not settable — ask for it in the prompt |
|
|
122
|
+
| Completion | `webhook` (`X-Webhook-Signature: sha256=<hex>`) on FINISHED/ERROR | poll `GET /v1/agents/{id}/runs/{runId}` (webhooks "coming soon") |
|
|
123
|
+
|
|
124
|
+
Mushi's server keeps a v0 code path behind `CURSOR_USE_V0_WEBHOOK=1` purely
|
|
125
|
+
for the push webhook (its `cursor-webhook` edge function verifies the
|
|
126
|
+
signature); this npm plugin has no completion tracking of its own and uses
|
|
127
|
+
v1 only.
|
|
128
|
+
|
|
101
129
|
## ⚠️ Breaking change in v0.3.0 — `webhookSecret` required
|
|
102
130
|
|
|
103
131
|
Previous versions derived the HMAC secret from `workspaceId` internally,
|
|
@@ -136,9 +164,10 @@ The test suite covers:
|
|
|
136
164
|
|
|
137
165
|
- Severity gate filters out anything below `severityThreshold` (no API call).
|
|
138
166
|
- `repoUrl` missing → silent no-op.
|
|
139
|
-
- `report.classified` with `severity: critical` → exactly one
|
|
140
|
-
- `fix.requested` → exactly one Cursor API call regardless of severity.
|
|
141
|
-
-
|
|
167
|
+
- `report.classified` with `severity: critical` → exactly one `POST /v1/agents` with the documented v1 body.
|
|
168
|
+
- `fix.requested` → exactly one Cursor API call regardless of severity, and none when `externalAgentId` is already set.
|
|
169
|
+
- `409 agent_id_conflict` on a redelivered event is treated as success.
|
|
170
|
+
- Bails on 401 (no money burned on bad keys).
|
|
142
171
|
|
|
143
172
|
## License
|
|
144
173
|
|
|
@@ -148,4 +177,4 @@ MIT — see [LICENSE](./LICENSE).
|
|
|
148
177
|
<!-- mushi-readme-stats-footer -->
|
|
149
178
|
---
|
|
150
179
|
|
|
151
|
-
<sub>Monorepo scale (
|
|
180
|
+
<sub>Monorepo scale (July 2026): 59 edge functions · 374 SQL migrations · 13 outbound plugins · 11 inbound adapters · 19 pipeline agents. Canonical counts: <a href="https://github.com/kensaurus/mushi-mushi/blob/master/docs/stats.md">docs/stats.md</a> · <code>pnpm docs-stats</code></sub>
|
package/dist/index.d.ts
CHANGED
|
@@ -4,36 +4,50 @@ import * as _mushi_mushi_plugin_sdk from '@mushi-mushi/plugin-sdk';
|
|
|
4
4
|
* Cursor Cloud Agent plugin for Mushi Mushi.
|
|
5
5
|
*
|
|
6
6
|
* Path A: Marketplace plugin — subscribes to `report.classified`,
|
|
7
|
-
* `qa_story.failed`,
|
|
8
|
-
* this plugin calls Cursor's HTTP REST API
|
|
9
|
-
* runs from Deno edge functions and Node alike)
|
|
10
|
-
*
|
|
7
|
+
* `qa_story.failed`, `fix.requested` and `skill_pipeline.step.dispatched`.
|
|
8
|
+
* When a qualifying event fires, this plugin calls Cursor's HTTP REST API
|
|
9
|
+
* directly (no @cursor/sdk — runs from Deno edge functions and Node alike)
|
|
10
|
+
* to create a Cloud Agent, and logs the resulting `agentId` + `prUrl` to the
|
|
11
|
+
* Mushi console.
|
|
11
12
|
*
|
|
12
13
|
* This is the *opt-in* path: teams install it from the Marketplace and
|
|
13
|
-
* configure their Cursor API key +
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
* configure their Cursor API key + repo URL in the plugin settings. The
|
|
15
|
+
* project-wide *default* Cursor path is `autofix_agent = 'cursor_cloud'`,
|
|
16
|
+
* dispatched by Mushi's own fix-worker; when THAT path emits
|
|
17
|
+
* `fix.requested` the payload carries `data.fix.externalAgentId` and this
|
|
18
|
+
* plugin deliberately does not start a second agent.
|
|
16
19
|
*
|
|
17
|
-
* Cursor
|
|
20
|
+
* API: Cursor Cloud Agents **v1** — https://cursor.com/docs/cloud-agent/api/endpoints
|
|
21
|
+
* POST https://api.cursor.com/v1/agents
|
|
22
|
+
* { prompt: { text }, repos: [{ url, startingRef? }], autoCreatePR (top-level),
|
|
23
|
+
* agentId?: 'bc-<uuid>' (idempotency; re-use ⇒ 409 agent_id_conflict),
|
|
24
|
+
* name?, model?: { id }, skipReviewerRequest? }
|
|
25
|
+
* → { agent: { id, status, url }, run: { id, status, git: { branches: [{ repoUrl, branch, prUrl }] } } }
|
|
26
|
+
* v0 (`source` / `target.autoCreatePr` / `webhook`) is still served by
|
|
27
|
+
* Cursor but no longer used here — see the README section "v0 vs v1".
|
|
18
28
|
*/
|
|
29
|
+
declare const CURSOR_API_BASE = "https://api.cursor.com";
|
|
30
|
+
declare const CURSOR_DEFAULT_MODEL = "composer-2.5";
|
|
19
31
|
interface CursorCloudPluginConfig {
|
|
20
32
|
/** Cursor API key (crsr_…). */
|
|
21
33
|
apiKey: string;
|
|
22
|
-
/** @deprecated
|
|
34
|
+
/** @deprecated Not used by the Cursor Cloud Agents v1 API; accepted for back-compat. */
|
|
23
35
|
workspaceId?: string;
|
|
24
|
-
/** Cursor model
|
|
36
|
+
/** Cursor model id (`model.id`). Defaults to `composer-2.5`. */
|
|
25
37
|
model?: string;
|
|
26
|
-
/** Whether
|
|
38
|
+
/** Whether Cursor should automatically open a (draft) PR. Defaults to true. */
|
|
27
39
|
autoCreatePR?: boolean;
|
|
28
|
-
/**
|
|
40
|
+
/** @deprecated v1 has no iteration cap; kept so existing configs still type-check. */
|
|
29
41
|
maxIterations?: number;
|
|
30
42
|
/** Lowest severity that triggers a Cursor agent run. Defaults to `critical`. */
|
|
31
43
|
severityThreshold?: 'low' | 'medium' | 'high' | 'critical';
|
|
32
44
|
/**
|
|
33
|
-
* URL of the target repository the Cursor agent will work in
|
|
34
|
-
* If not set, the plugin
|
|
45
|
+
* URL of the target repository the Cursor agent will work in
|
|
46
|
+
* (`https://github.com/org/repo`). If not set, the plugin no-ops.
|
|
35
47
|
*/
|
|
36
48
|
repoUrl?: string;
|
|
49
|
+
/** Branch/ref the agent starts from (`repos[].startingRef`). Defaults to the repo default branch. */
|
|
50
|
+
startingRef?: string;
|
|
37
51
|
/**
|
|
38
52
|
* Standard Webhooks secret for inbound Mushi events. Required for
|
|
39
53
|
* self-hosted installs — never derive this from workspaceId.
|
|
@@ -41,10 +55,14 @@ interface CursorCloudPluginConfig {
|
|
|
41
55
|
webhookSecret?: string;
|
|
42
56
|
/** Override `fetch` for tests. */
|
|
43
57
|
fetchImpl?: typeof fetch;
|
|
58
|
+
/** Override the API base (tests / proxies). */
|
|
59
|
+
apiBase?: string;
|
|
44
60
|
}
|
|
45
61
|
interface CursorAgentRunResponse {
|
|
46
62
|
agentId: string;
|
|
63
|
+
runId?: string;
|
|
47
64
|
status: string;
|
|
65
|
+
agentUrl?: string;
|
|
48
66
|
prUrl?: string;
|
|
49
67
|
}
|
|
50
68
|
interface CursorDispatchResult {
|
|
@@ -52,7 +70,24 @@ interface CursorDispatchResult {
|
|
|
52
70
|
reportId: string;
|
|
53
71
|
model: string;
|
|
54
72
|
}
|
|
73
|
+
/** Wire body for POST /v1/agents — exported so tests can pin the exact shape. */
|
|
74
|
+
declare function buildCreateAgentBody(input: {
|
|
75
|
+
prompt: string;
|
|
76
|
+
repoUrl: string;
|
|
77
|
+
startingRef?: string;
|
|
78
|
+
model: string;
|
|
79
|
+
autoCreatePR: boolean;
|
|
80
|
+
agentId?: string;
|
|
81
|
+
name?: string;
|
|
82
|
+
}): Record<string, unknown>;
|
|
83
|
+
/**
|
|
84
|
+
* `bc-<uuid>` derived from a stable seed (the Mushi delivery id) so a retried
|
|
85
|
+
* delivery re-uses the agent id and Cursor answers 409 `agent_id_conflict`
|
|
86
|
+
* instead of starting a second agent. RFC 9562 name-based layout over
|
|
87
|
+
* SHA-256 (WebCrypto — available in Node ≥ 20 and Deno).
|
|
88
|
+
*/
|
|
89
|
+
declare function deterministicAgentId(seed: string): Promise<string>;
|
|
55
90
|
/** Build the plugin handler and return a callable function. */
|
|
56
91
|
declare function createCursorCloudPlugin(cfg: CursorCloudPluginConfig): (input: _mushi_mushi_plugin_sdk.HandlePluginRequestInput) => Promise<_mushi_mushi_plugin_sdk.HandlePluginResult>;
|
|
57
92
|
|
|
58
|
-
export { type CursorAgentRunResponse, type CursorCloudPluginConfig, type CursorDispatchResult, createCursorCloudPlugin };
|
|
93
|
+
export { CURSOR_API_BASE, CURSOR_DEFAULT_MODEL, type CursorAgentRunResponse, type CursorCloudPluginConfig, type CursorDispatchResult, buildCreateAgentBody, createCursorCloudPlugin, deterministicAgentId };
|
package/dist/index.js
CHANGED
|
@@ -3,46 +3,78 @@ import {
|
|
|
3
3
|
createPluginHandler,
|
|
4
4
|
withRetry
|
|
5
5
|
} from "@mushi-mushi/plugin-sdk";
|
|
6
|
-
var CURSOR_API_BASE = "https://api.cursor.com
|
|
6
|
+
var CURSOR_API_BASE = "https://api.cursor.com";
|
|
7
|
+
var CURSOR_DEFAULT_MODEL = "composer-2.5";
|
|
7
8
|
var SEVERITY_RANK = {
|
|
8
9
|
low: 1,
|
|
9
10
|
medium: 2,
|
|
10
11
|
high: 3,
|
|
11
12
|
critical: 4
|
|
12
13
|
};
|
|
14
|
+
function buildCreateAgentBody(input) {
|
|
15
|
+
const body = {
|
|
16
|
+
prompt: { text: input.prompt },
|
|
17
|
+
repos: [{ url: input.repoUrl, ...input.startingRef ? { startingRef: input.startingRef } : {} }],
|
|
18
|
+
autoCreatePR: input.autoCreatePR,
|
|
19
|
+
skipReviewerRequest: true,
|
|
20
|
+
model: { id: input.model }
|
|
21
|
+
};
|
|
22
|
+
if (input.agentId) body.agentId = input.agentId;
|
|
23
|
+
if (input.name) body.name = input.name.slice(0, 100);
|
|
24
|
+
return body;
|
|
25
|
+
}
|
|
26
|
+
async function deterministicAgentId(seed) {
|
|
27
|
+
const data = new TextEncoder().encode(`mushi-mushi:plugin-cursor-cloud:v1\0${seed}`);
|
|
28
|
+
const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", data));
|
|
29
|
+
const b = digest.slice(0, 16);
|
|
30
|
+
b[6] = b[6] & 15 | 80;
|
|
31
|
+
b[8] = b[8] & 63 | 128;
|
|
32
|
+
let hex = "";
|
|
33
|
+
for (let i = 0; i < b.length; i++) hex += b[i].toString(16).padStart(2, "0");
|
|
34
|
+
return `bc-${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
35
|
+
}
|
|
13
36
|
async function createCursorAgentRun(cfg, opts, f) {
|
|
14
37
|
return withRetry(async () => {
|
|
15
|
-
const res = await f(`${CURSOR_API_BASE}/agents`, {
|
|
38
|
+
const res = await f(`${cfg.apiBase ?? CURSOR_API_BASE}/v1/agents`, {
|
|
16
39
|
method: "POST",
|
|
17
40
|
headers: {
|
|
18
41
|
"Content-Type": "application/json",
|
|
19
42
|
Authorization: `Bearer ${cfg.apiKey}`
|
|
20
43
|
},
|
|
21
|
-
body: JSON.stringify(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
})
|
|
44
|
+
body: JSON.stringify(
|
|
45
|
+
buildCreateAgentBody({
|
|
46
|
+
prompt: opts.prompt,
|
|
47
|
+
repoUrl: opts.repoUrl,
|
|
48
|
+
startingRef: cfg.startingRef,
|
|
49
|
+
model: cfg.model || CURSOR_DEFAULT_MODEL,
|
|
50
|
+
autoCreatePR: cfg.autoCreatePR,
|
|
51
|
+
agentId: opts.agentId,
|
|
52
|
+
name: opts.name
|
|
53
|
+
})
|
|
54
|
+
)
|
|
34
55
|
});
|
|
56
|
+
if (res.status === 409 && opts.agentId) {
|
|
57
|
+
const errBody = await res.json().catch(() => null);
|
|
58
|
+
if (errBody?.error?.code === "agent_id_conflict" || !errBody) {
|
|
59
|
+
return { agentId: opts.agentId, status: "EXISTS" };
|
|
60
|
+
}
|
|
61
|
+
throw res;
|
|
62
|
+
}
|
|
35
63
|
if (!res.ok) {
|
|
36
64
|
throw res;
|
|
37
65
|
}
|
|
38
66
|
const body = await res.json();
|
|
67
|
+
const prUrl = body.run?.git?.branches?.find((b) => typeof b.prUrl === "string")?.prUrl;
|
|
39
68
|
return {
|
|
40
|
-
agentId: body.
|
|
41
|
-
|
|
42
|
-
|
|
69
|
+
agentId: body.agent?.id ?? "",
|
|
70
|
+
runId: body.run?.id,
|
|
71
|
+
status: body.run?.status ?? body.agent?.status ?? "CREATING",
|
|
72
|
+
agentUrl: body.agent?.url,
|
|
73
|
+
prUrl
|
|
43
74
|
};
|
|
44
75
|
});
|
|
45
76
|
}
|
|
77
|
+
var DRAFT_PR_INSTRUCTION = "Open the pull request as a DRAFT (Cursor opens drafts by default; keep it that way). Do not refactor unrelated code and never merge.";
|
|
46
78
|
function buildPromptFromClassifiedReport(envelope, data) {
|
|
47
79
|
const lines = [
|
|
48
80
|
`A bug has been reported in your project and classified as ${data.classification.severity?.toUpperCase()}.`,
|
|
@@ -58,7 +90,7 @@ function buildPromptFromClassifiedReport(envelope, data) {
|
|
|
58
90
|
}
|
|
59
91
|
lines.push(
|
|
60
92
|
``,
|
|
61
|
-
`Please investigate this bug, identify the root cause in the codebase, and open a draft PR with a minimal fix
|
|
93
|
+
`Please investigate this bug, identify the root cause in the codebase, and open a draft PR with a minimal fix titled "fix: <summary> (MUSHI-${data.report.id})". ${DRAFT_PR_INSTRUCTION}`
|
|
62
94
|
);
|
|
63
95
|
return lines.join("\n");
|
|
64
96
|
}
|
|
@@ -68,9 +100,10 @@ function buildPromptFromFixRequested(envelope, fixData) {
|
|
|
68
100
|
``,
|
|
69
101
|
`Report title: ${fixData.report.title ?? "(untitled)"}`,
|
|
70
102
|
`Fix ID: ${fixData.fix.id}`,
|
|
103
|
+
fixData.fix.branch ? `Requested branch: ${fixData.fix.branch}` : "",
|
|
71
104
|
``,
|
|
72
|
-
`Please investigate the reported issue, identify the root cause, and open a draft PR with a minimal fix
|
|
73
|
-
].join("\n");
|
|
105
|
+
`Please investigate the reported issue, identify the root cause, and open a draft PR with a minimal fix titled "fix: <summary> (MUSHI-${fixData.report.id})". ${DRAFT_PR_INSTRUCTION}`
|
|
106
|
+
].filter((line) => line !== "").join("\n");
|
|
74
107
|
}
|
|
75
108
|
function buildPromptFromQaStoryFailed(envelope, data) {
|
|
76
109
|
return [
|
|
@@ -80,16 +113,21 @@ function buildPromptFromQaStoryFailed(envelope, data) {
|
|
|
80
113
|
`Title: ${data.title ?? "(untitled)"}`,
|
|
81
114
|
data.failureReason ? `Failure: ${data.failureReason}` : "",
|
|
82
115
|
``,
|
|
83
|
-
`Please investigate the failing assertion, identify the root cause in the codebase, and open a draft PR with a minimal fix.
|
|
116
|
+
`Please investigate the failing assertion, identify the root cause in the codebase, and open a draft PR with a minimal fix. ${DRAFT_PR_INSTRUCTION}`
|
|
84
117
|
].filter((line) => line !== "").join("\n");
|
|
85
118
|
}
|
|
86
119
|
function createCursorCloudPlugin(cfg) {
|
|
87
120
|
const minRank = SEVERITY_RANK[cfg.severityThreshold ?? "critical"];
|
|
88
|
-
const model = cfg.model ??
|
|
121
|
+
const model = cfg.model ?? CURSOR_DEFAULT_MODEL;
|
|
89
122
|
const autoCreatePR = cfg.autoCreatePR ?? true;
|
|
90
|
-
const maxIterations = cfg.maxIterations ?? 1;
|
|
91
123
|
const f = cfg.fetchImpl ?? fetch;
|
|
92
|
-
const resolvedCfg = {
|
|
124
|
+
const resolvedCfg = {
|
|
125
|
+
apiKey: cfg.apiKey,
|
|
126
|
+
model,
|
|
127
|
+
autoCreatePR,
|
|
128
|
+
startingRef: cfg.startingRef,
|
|
129
|
+
apiBase: cfg.apiBase
|
|
130
|
+
};
|
|
93
131
|
const webhookSecret = cfg.webhookSecret ?? (typeof process !== "undefined" ? process.env.MUSHI_PLUGIN_WEBHOOK_SECRET : void 0);
|
|
94
132
|
if (!webhookSecret) {
|
|
95
133
|
throw new Error(
|
|
@@ -112,7 +150,9 @@ function createCursorCloudPlugin(cfg) {
|
|
|
112
150
|
resolvedCfg,
|
|
113
151
|
{
|
|
114
152
|
repoUrl,
|
|
115
|
-
prompt: buildPromptFromClassifiedReport(e, data)
|
|
153
|
+
prompt: buildPromptFromClassifiedReport(e, data),
|
|
154
|
+
agentId: await deterministicAgentId(`report.classified:${e.projectId}:${data.report.id}`),
|
|
155
|
+
name: `Mushi report ${data.report.id.slice(0, 8)}`
|
|
116
156
|
},
|
|
117
157
|
f
|
|
118
158
|
);
|
|
@@ -121,6 +161,13 @@ function createCursorCloudPlugin(cfg) {
|
|
|
121
161
|
},
|
|
122
162
|
"fix.requested": async (e) => {
|
|
123
163
|
const data = e.data;
|
|
164
|
+
if (typeof data.fix?.externalAgentId === "string" && data.fix.externalAgentId.length > 0) {
|
|
165
|
+
console.warn(
|
|
166
|
+
"[cursor-cloud] fix.requested already dispatched by Mushi fix-worker",
|
|
167
|
+
JSON.stringify({ agentId: data.fix.externalAgentId, reportId: data.report.id, agent: data.fix.agent })
|
|
168
|
+
);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
124
171
|
const repoUrl = cfg.repoUrl ?? "";
|
|
125
172
|
if (!repoUrl) {
|
|
126
173
|
console.warn("[cursor-cloud] fix.requested skipped: repoUrl not configured.");
|
|
@@ -130,7 +177,9 @@ function createCursorCloudPlugin(cfg) {
|
|
|
130
177
|
resolvedCfg,
|
|
131
178
|
{
|
|
132
179
|
repoUrl,
|
|
133
|
-
prompt: buildPromptFromFixRequested(e, data)
|
|
180
|
+
prompt: buildPromptFromFixRequested(e, data),
|
|
181
|
+
agentId: await deterministicAgentId(`fix.requested:${e.projectId}:${data.fix.id}`),
|
|
182
|
+
name: `Mushi fix ${data.fix.id.slice(0, 8)}`
|
|
134
183
|
},
|
|
135
184
|
f
|
|
136
185
|
);
|
|
@@ -148,7 +197,9 @@ function createCursorCloudPlugin(cfg) {
|
|
|
148
197
|
resolvedCfg,
|
|
149
198
|
{
|
|
150
199
|
repoUrl,
|
|
151
|
-
prompt: buildPromptFromQaStoryFailed(e, data)
|
|
200
|
+
prompt: buildPromptFromQaStoryFailed(e, data),
|
|
201
|
+
agentId: await deterministicAgentId(`qa_story.failed:${e.projectId}:${data.storyId ?? e.deliveryId}`),
|
|
202
|
+
name: `Mushi QA story ${(data.storyId ?? "unknown").slice(0, 8)}`
|
|
152
203
|
},
|
|
153
204
|
f
|
|
154
205
|
);
|
|
@@ -179,7 +230,9 @@ function createCursorCloudPlugin(cfg) {
|
|
|
179
230
|
resolvedCfg,
|
|
180
231
|
{
|
|
181
232
|
repoUrl,
|
|
182
|
-
prompt: buildPromptFromSkillStep(data)
|
|
233
|
+
prompt: buildPromptFromSkillStep(data),
|
|
234
|
+
agentId: void 0,
|
|
235
|
+
name: `Mushi skill ${data.skillSlug.slice(0, 40)} #${data.stepIndex + 1}`
|
|
183
236
|
},
|
|
184
237
|
f
|
|
185
238
|
),
|
|
@@ -259,12 +312,18 @@ function buildPromptFromSkillStep(data) {
|
|
|
259
312
|
` status: "passed" (or "failed" if you could not complete it)`,
|
|
260
313
|
` pr_url: <your PR URL if you opened one>`,
|
|
261
314
|
``,
|
|
315
|
+
`Push your work to a branch named \`mushi/skill-${data.skillSlug.slice(0, 24)}-${data.runId.slice(0, 8)}\` and ${DRAFT_PR_INSTRUCTION}`,
|
|
316
|
+
``,
|
|
262
317
|
`\u2500\u2500\u2500 Context Packet \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`,
|
|
263
318
|
``,
|
|
264
319
|
data.contextPacket.slice(0, 32e3)
|
|
265
320
|
].join("\n");
|
|
266
321
|
}
|
|
267
322
|
export {
|
|
268
|
-
|
|
323
|
+
CURSOR_API_BASE,
|
|
324
|
+
CURSOR_DEFAULT_MODEL,
|
|
325
|
+
buildCreateAgentBody,
|
|
326
|
+
createCursorCloudPlugin,
|
|
327
|
+
deterministicAgentId
|
|
269
328
|
};
|
|
270
329
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// SPDX-License-Identifier: MIT\n// Copyright (c) 2024–2026 Kenji Sakuramoto (kensaurus) — Mushi Mushi\n/**\n * Cursor Cloud Agent plugin for Mushi Mushi.\n *\n * Path A: Marketplace plugin — subscribes to `report.classified`,\n * `qa_story.failed`, and `fix.requested`. When a qualifying event fires,\n * this plugin calls Cursor's HTTP REST API directly (no @cursor/sdk —\n * runs from Deno edge functions and Node alike) to create a Cloud Agent\n * run, and logs the resulting `agentId` + `prUrl` to the Mushi console.\n *\n * This is the *opt-in* path: teams install it from the Marketplace and\n * configure their Cursor API key + workspace ID in the plugin settings.\n * For the project-wide *default* Cursor agent path, see Path B in\n * packages/agents/src/adapters/cursor-cloud.ts.\n *\n * Cursor REST API docs: https://cursor.com/docs/cloud-agent/api/v0.md\n */\n\nimport {\n createPluginHandler,\n withRetry,\n type MushiEventEnvelope,\n type MushiReportClassifiedEvent,\n type MushiFixEvent,\n} from '@mushi-mushi/plugin-sdk'\n\nconst CURSOR_API_BASE = 'https://api.cursor.com/v0'\n\nconst SEVERITY_RANK: Record<string, number> = {\n low: 1,\n medium: 2,\n high: 3,\n critical: 4,\n}\n\nexport interface CursorCloudPluginConfig {\n /** Cursor API key (crsr_…). */\n apiKey: string\n /** @deprecated No longer required by Cursor Cloud Agents API. */\n workspaceId?: string\n /** Cursor model slug. Defaults to `composer-2.5`. */\n model?: string\n /** Whether the agent should automatically open a draft PR. Defaults to true. */\n autoCreatePR?: boolean\n /** Maximum iterations for the agent. Defaults to 1. */\n maxIterations?: number\n /** Lowest severity that triggers a Cursor agent run. Defaults to `critical`. */\n severityThreshold?: 'low' | 'medium' | 'high' | 'critical'\n /**\n * URL of the target repository the Cursor agent will work in.\n * If not set, the plugin will attempt to read it from the event payload.\n */\n repoUrl?: string\n /**\n * Standard Webhooks secret for inbound Mushi events. Required for\n * self-hosted installs — never derive this from workspaceId.\n */\n webhookSecret?: string\n /** Override `fetch` for tests. */\n fetchImpl?: typeof fetch\n}\n\nexport interface CursorAgentRunResponse {\n agentId: string\n status: string\n prUrl?: string\n}\n\nexport interface CursorDispatchResult {\n agentId: string\n reportId: string\n model: string\n}\n\n/**\n * Call Cursor's REST API to create a Cloud Agent run.\n * Returns the agentId so the caller can track the run in Mushi console.\n *\n * On non-2xx the raw Response is thrown so `withRetry` can inspect\n * `.status` and `Retry-After` and apply the documented retry policy:\n * - 429 / 5xx → retry with exponential back-off\n * - 4xx (not 429) → throw immediately (no money burned on bad keys)\n * - network error → retry\n */\nasync function createCursorAgentRun(\n cfg: Required<Pick<CursorCloudPluginConfig, 'apiKey' | 'model' | 'autoCreatePR' | 'maxIterations'>>,\n opts: { repoUrl: string; prompt: string; branchName?: string },\n f: typeof fetch,\n): Promise<CursorAgentRunResponse> {\n return withRetry(async () => {\n const res = await f(`${CURSOR_API_BASE}/agents`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${cfg.apiKey}`,\n },\n body: JSON.stringify({\n prompt: { text: opts.prompt },\n model: cfg.model || 'default',\n source: {\n repository: opts.repoUrl,\n ref: 'main',\n },\n target: {\n autoCreatePr: cfg.autoCreatePR,\n branchName: opts.branchName ?? `mushi/cursor-${Date.now()}`,\n skipReviewerRequest: true,\n },\n }),\n })\n if (!res.ok) {\n // Throw the Response itself so withRetry can read status / Retry-After.\n // This is the contract documented in @mushi-mushi/plugin-sdk/retry.ts.\n throw res\n }\n const body = (await res.json()) as { agentId?: string; id?: string; status?: string; prUrl?: string }\n return {\n agentId: body.agentId ?? body.id ?? '',\n status: body.status ?? 'queued',\n prUrl: body.prUrl,\n }\n })\n}\n\nfunction buildPromptFromClassifiedReport(\n envelope: MushiEventEnvelope,\n data: MushiReportClassifiedEvent,\n): string {\n const lines = [\n `A bug has been reported in your project and classified as ${data.classification.severity?.toUpperCase()}.`,\n ``,\n `Report ID: ${data.report.id}`,\n `Title: ${data.report.title ?? '(untitled)'}`,\n `Category: ${data.report.category ?? data.classification.category}`,\n `Severity: ${data.classification.severity}`,\n `Project: ${envelope.projectId}`,\n ]\n\n if (data.classification.tags?.length) {\n lines.push(`Tags: ${data.classification.tags.join(', ')}`)\n }\n\n lines.push(\n ``,\n `Please investigate this bug, identify the root cause in the codebase, ` +\n `and open a draft PR with a minimal fix. Do not refactor unrelated code.`,\n )\n\n return lines.join('\\n')\n}\n\nfunction buildPromptFromFixRequested(envelope: MushiEventEnvelope, fixData: MushiFixEvent): string {\n return [\n `A fix was requested for report ${fixData.report.id} in project ${envelope.projectId}.`,\n ``,\n `Report title: ${fixData.report.title ?? '(untitled)'}`,\n `Fix ID: ${fixData.fix.id}`,\n ``,\n `Please investigate the reported issue, identify the root cause, ` +\n `and open a draft PR with a minimal fix. Do not refactor unrelated code.`,\n ].join('\\n')\n}\n\nfunction buildPromptFromQaStoryFailed(\n envelope: MushiEventEnvelope,\n data: { storyId?: string; title?: string; failureReason?: string },\n): string {\n return [\n `A QA story failed in project ${envelope.projectId}.`,\n ``,\n `Story ID: ${data.storyId ?? 'unknown'}`,\n `Title: ${data.title ?? '(untitled)'}`,\n data.failureReason ? `Failure: ${data.failureReason}` : '',\n ``,\n `Please investigate the failing assertion, identify the root cause in the codebase, ` +\n `and open a draft PR with a minimal fix. Do not refactor unrelated code.`,\n ].filter((line) => line !== '').join('\\n')\n}\n\n/** Build the plugin handler and return a callable function. */\nexport function createCursorCloudPlugin(cfg: CursorCloudPluginConfig) {\n const minRank = SEVERITY_RANK[cfg.severityThreshold ?? 'critical']!\n const model = cfg.model ?? 'composer-2.5'\n const autoCreatePR = cfg.autoCreatePR ?? true\n const maxIterations = cfg.maxIterations ?? 1\n const f = cfg.fetchImpl ?? fetch\n\n const resolvedCfg = { apiKey: cfg.apiKey, model, autoCreatePR, maxIterations }\n\n const webhookSecret =\n cfg.webhookSecret ??\n (typeof process !== 'undefined' ? process.env.MUSHI_PLUGIN_WEBHOOK_SECRET : undefined)\n if (!webhookSecret) {\n throw new Error(\n 'Cursor Cloud plugin requires webhookSecret (or MUSHI_PLUGIN_WEBHOOK_SECRET) for inbound event verification.',\n )\n }\n\n return createPluginHandler({\n secret: webhookSecret,\n on: {\n 'report.classified': async (e) => {\n const data = e.data as MushiReportClassifiedEvent\n const rank = SEVERITY_RANK[data.classification.severity ?? ''] ?? 0\n if (rank < minRank) return\n\n const repoUrl = cfg.repoUrl ?? ''\n if (!repoUrl) {\n console.warn('[cursor-cloud] report.classified skipped: repoUrl not configured. ' +\n 'Set repoUrl in the plugin config so the agent knows which codebase to fix.')\n return\n }\n\n const run = await createCursorAgentRun(\n resolvedCfg,\n {\n repoUrl,\n prompt: buildPromptFromClassifiedReport(e, data),\n },\n f,\n )\n\n // Emit audit log — handler return type is void.\n const result: CursorDispatchResult = { agentId: run.agentId, reportId: data.report.id, model }\n console.warn('[cursor-cloud] dispatched', JSON.stringify(result))\n },\n\n 'fix.requested': async (e) => {\n const data = e.data as MushiFixEvent\n\n const repoUrl = cfg.repoUrl ?? ''\n if (!repoUrl) {\n console.warn('[cursor-cloud] fix.requested skipped: repoUrl not configured.')\n return\n }\n\n const run = await createCursorAgentRun(\n resolvedCfg,\n {\n repoUrl,\n prompt: buildPromptFromFixRequested(e, data),\n },\n f,\n )\n\n // Emit audit log — handler return type is void.\n const result: CursorDispatchResult = { agentId: run.agentId, reportId: data.report.id, model }\n console.warn('[cursor-cloud] fix.requested dispatched', JSON.stringify(result))\n },\n\n 'qa_story.failed': async (e) => {\n const data = e.data as { storyId?: string; title?: string; failureReason?: string }\n\n const repoUrl = cfg.repoUrl ?? ''\n if (!repoUrl) {\n console.warn('[cursor-cloud] qa_story.failed skipped: repoUrl not configured.')\n return\n }\n\n const run = await createCursorAgentRun(\n resolvedCfg,\n {\n repoUrl,\n prompt: buildPromptFromQaStoryFailed(e, data),\n },\n f,\n )\n\n const result: CursorDispatchResult = {\n agentId: run.agentId,\n reportId: data.storyId ?? 'unknown',\n model,\n }\n console.warn('[cursor-cloud] qa_story.failed dispatched', JSON.stringify(result))\n },\n\n // ── Skill pipeline step dispatch (Phase 5) ───────────────────────────\n // When a pipeline run is started in 'cloud' mode, the skills.ts route\n // fires this event for each step. The plugin creates a Cursor Cloud\n // agent run whose prompt is the pre-composed context_packet for that\n // step, stores the agentId on the step row, and reports back to Mushi\n // via the check-in endpoint.\n 'skill_pipeline.step.dispatched': async (e) => {\n const data = e.data as {\n runId: string\n stepIndex: number\n skillSlug: string\n contextPacket: string\n projectId: string\n }\n\n const repoUrl = cfg.repoUrl ?? ''\n if (!repoUrl) {\n console.warn('[cursor-cloud] skill_pipeline.step.dispatched skipped: repoUrl not configured.')\n return\n }\n\n let run: CursorAgentRunResponse\n try {\n run = await withRetry(\n () =>\n createCursorAgentRun(\n resolvedCfg,\n {\n repoUrl,\n prompt: buildPromptFromSkillStep(data),\n },\n f,\n ),\n { maxAttempts: 3 },\n )\n } catch (err) {\n console.error('[cursor-cloud] skill_pipeline step dispatch failed', String(err))\n const mushiUrl =\n (typeof process !== 'undefined' ? process.env.MUSHI_API_URL : undefined) ?? 'https://api.mushi.ai'\n const mushiKey =\n (typeof process !== 'undefined' ? process.env.MUSHI_API_KEY : undefined) ?? ''\n if (mushiKey) {\n try {\n await f(`${mushiUrl}/v1/admin/skills/pipelines/${data.runId}/steps/${data.stepIndex}/checkin`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Mushi-Api-Key': mushiKey,\n },\n body: JSON.stringify({\n status: 'failed',\n notes: `Cursor Cloud dispatch failed: ${String(err).slice(0, 400)}`,\n }),\n })\n } catch { /* best-effort */ }\n } else {\n console.warn(\n `[cursor-cloud] MUSHI_API_KEY unset — cannot report the failed dispatch for run ${data.runId} step ${data.stepIndex}. ` +\n `The step will remain 'running' server-side until it is manually checked in.`,\n )\n }\n return\n }\n\n console.log('[cursor-cloud] skill_pipeline step dispatched', {\n runId: data.runId,\n stepIndex: data.stepIndex,\n agentId: run.agentId,\n })\n\n // Report back to Mushi: update the step row with the agentId.\n // The console React Flow canvas will update via Realtime.\n // Use a best-effort POST to the check-in endpoint.\n const mushiUrl =\n (typeof process !== 'undefined' ? process.env.MUSHI_API_URL : undefined) ?? 'https://api.mushi.ai'\n const mushiKey =\n (typeof process !== 'undefined' ? process.env.MUSHI_API_KEY : undefined) ?? ''\n\n if (mushiKey) {\n try {\n await f(`${mushiUrl}/v1/admin/skills/pipelines/${data.runId}/steps/${data.stepIndex}/checkin`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Mushi-Api-Key': mushiKey,\n },\n body: JSON.stringify({\n status: 'running',\n agent_ref: run.agentId,\n notes: `Cursor Cloud agent dispatched (model: ${model})`,\n }),\n })\n } catch (err) {\n console.warn('[cursor-cloud] checkin failed (best-effort)', String(err))\n }\n } else {\n console.warn(\n `[cursor-cloud] MUSHI_API_KEY unset — agent ${run.agentId} was dispatched for run ${data.runId} step ${data.stepIndex} ` +\n `but its agent_ref/running status cannot be reported back. The console flow will not reflect this step until it is manually checked in.`,\n )\n }\n },\n },\n })\n}\n\nfunction buildPromptFromSkillStep(data: {\n runId: string\n stepIndex: number\n skillSlug: string\n contextPacket: string\n}): string {\n return [\n `# Mushi Skill Pipeline — Step ${data.stepIndex + 1}`,\n ``,\n `Skill: \\`${data.skillSlug}\\``,\n `Pipeline run: ${data.runId}`,\n ``,\n `You are executing step ${data.stepIndex + 1} of a Mushi skill pipeline. ` +\n `The full context packet below contains your instructions plus the complete report context.`,\n ``,\n `When you have completed this step, call the Mushi MCP tool \\`checkin_pipeline_step\\` with:`,\n ` run_id: \"${data.runId}\"`,\n ` step_index: ${data.stepIndex}`,\n ` status: \"passed\" (or \"failed\" if you could not complete it)`,\n ` pr_url: <your PR URL if you opened one>`,\n ``,\n `─── Context Packet ────────────────────────────────────────────────────`,\n ``,\n data.contextPacket.slice(0, 32_000),\n ].join('\\n')\n}\n"],"mappings":"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","names":["mushiUrl","mushiKey"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["// SPDX-License-Identifier: MIT\n// Copyright (c) 2024–2026 Kenji Sakuramoto (kensaurus) — Mushi Mushi\n/**\n * Cursor Cloud Agent plugin for Mushi Mushi.\n *\n * Path A: Marketplace plugin — subscribes to `report.classified`,\n * `qa_story.failed`, `fix.requested` and `skill_pipeline.step.dispatched`.\n * When a qualifying event fires, this plugin calls Cursor's HTTP REST API\n * directly (no @cursor/sdk — runs from Deno edge functions and Node alike)\n * to create a Cloud Agent, and logs the resulting `agentId` + `prUrl` to the\n * Mushi console.\n *\n * This is the *opt-in* path: teams install it from the Marketplace and\n * configure their Cursor API key + repo URL in the plugin settings. The\n * project-wide *default* Cursor path is `autofix_agent = 'cursor_cloud'`,\n * dispatched by Mushi's own fix-worker; when THAT path emits\n * `fix.requested` the payload carries `data.fix.externalAgentId` and this\n * plugin deliberately does not start a second agent.\n *\n * API: Cursor Cloud Agents **v1** — https://cursor.com/docs/cloud-agent/api/endpoints\n * POST https://api.cursor.com/v1/agents\n * { prompt: { text }, repos: [{ url, startingRef? }], autoCreatePR (top-level),\n * agentId?: 'bc-<uuid>' (idempotency; re-use ⇒ 409 agent_id_conflict),\n * name?, model?: { id }, skipReviewerRequest? }\n * → { agent: { id, status, url }, run: { id, status, git: { branches: [{ repoUrl, branch, prUrl }] } } }\n * v0 (`source` / `target.autoCreatePr` / `webhook`) is still served by\n * Cursor but no longer used here — see the README section \"v0 vs v1\".\n */\n\nimport {\n createPluginHandler,\n withRetry,\n type MushiEventEnvelope,\n type MushiReportClassifiedEvent,\n type MushiFixEvent,\n} from '@mushi-mushi/plugin-sdk'\n\nexport const CURSOR_API_BASE = 'https://api.cursor.com'\nexport const CURSOR_DEFAULT_MODEL = 'composer-2.5'\n\nconst SEVERITY_RANK: Record<string, number> = {\n low: 1,\n medium: 2,\n high: 3,\n critical: 4,\n}\n\nexport interface CursorCloudPluginConfig {\n /** Cursor API key (crsr_…). */\n apiKey: string\n /** @deprecated Not used by the Cursor Cloud Agents v1 API; accepted for back-compat. */\n workspaceId?: string\n /** Cursor model id (`model.id`). Defaults to `composer-2.5`. */\n model?: string\n /** Whether Cursor should automatically open a (draft) PR. Defaults to true. */\n autoCreatePR?: boolean\n /** @deprecated v1 has no iteration cap; kept so existing configs still type-check. */\n maxIterations?: number\n /** Lowest severity that triggers a Cursor agent run. Defaults to `critical`. */\n severityThreshold?: 'low' | 'medium' | 'high' | 'critical'\n /**\n * URL of the target repository the Cursor agent will work in\n * (`https://github.com/org/repo`). If not set, the plugin no-ops.\n */\n repoUrl?: string\n /** Branch/ref the agent starts from (`repos[].startingRef`). Defaults to the repo default branch. */\n startingRef?: string\n /**\n * Standard Webhooks secret for inbound Mushi events. Required for\n * self-hosted installs — never derive this from workspaceId.\n */\n webhookSecret?: string\n /** Override `fetch` for tests. */\n fetchImpl?: typeof fetch\n /** Override the API base (tests / proxies). */\n apiBase?: string\n}\n\nexport interface CursorAgentRunResponse {\n agentId: string\n runId?: string\n status: string\n agentUrl?: string\n prUrl?: string\n}\n\nexport interface CursorDispatchResult {\n agentId: string\n reportId: string\n model: string\n}\n\n/** Wire body for POST /v1/agents — exported so tests can pin the exact shape. */\nexport function buildCreateAgentBody(input: {\n prompt: string\n repoUrl: string\n startingRef?: string\n model: string\n autoCreatePR: boolean\n agentId?: string\n name?: string\n}): Record<string, unknown> {\n const body: Record<string, unknown> = {\n prompt: { text: input.prompt },\n repos: [{ url: input.repoUrl, ...(input.startingRef ? { startingRef: input.startingRef } : {}) }],\n autoCreatePR: input.autoCreatePR,\n skipReviewerRequest: true,\n model: { id: input.model },\n }\n if (input.agentId) body.agentId = input.agentId\n if (input.name) body.name = input.name.slice(0, 100)\n return body\n}\n\n/**\n * `bc-<uuid>` derived from a stable seed (the Mushi delivery id) so a retried\n * delivery re-uses the agent id and Cursor answers 409 `agent_id_conflict`\n * instead of starting a second agent. RFC 9562 name-based layout over\n * SHA-256 (WebCrypto — available in Node ≥ 20 and Deno).\n */\nexport async function deterministicAgentId(seed: string): Promise<string> {\n const data = new TextEncoder().encode(`mushi-mushi:plugin-cursor-cloud:v1\u0000${seed}`)\n const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', data))\n const b = digest.slice(0, 16)\n b[6] = (b[6] & 0x0f) | 0x50\n b[8] = (b[8] & 0x3f) | 0x80\n let hex = ''\n for (let i = 0; i < b.length; i++) hex += b[i].toString(16).padStart(2, '0')\n return `bc-${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`\n}\n\ninterface CreateAgentV1Response {\n agent?: { id?: string; status?: string; url?: string }\n run?: { id?: string; status?: string; git?: { branches?: Array<{ prUrl?: string }> } }\n}\n\n/**\n * Call Cursor's REST API (v1) to create a Cloud Agent.\n * Returns the agentId (and run id) so the caller can track the run in the\n * Mushi console.\n *\n * On non-2xx the raw Response is thrown so `withRetry` can inspect\n * `.status` and `Retry-After` and apply the documented retry policy:\n * - 429 / 5xx → retry with exponential back-off\n * - 4xx (not 429) → throw immediately (no money burned on bad keys)\n * - 409 agent_id_conflict → NOT an error: the agent already exists for\n * this delivery (retry / duplicate webhook)\n * - network error → retry\n */\nasync function createCursorAgentRun(\n cfg: Required<Pick<CursorCloudPluginConfig, 'apiKey' | 'model' | 'autoCreatePR'>> &\n Pick<CursorCloudPluginConfig, 'startingRef' | 'apiBase'>,\n opts: { repoUrl: string; prompt: string; agentId?: string; name?: string },\n f: typeof fetch,\n): Promise<CursorAgentRunResponse> {\n return withRetry(async () => {\n const res = await f(`${cfg.apiBase ?? CURSOR_API_BASE}/v1/agents`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${cfg.apiKey}`,\n },\n body: JSON.stringify(\n buildCreateAgentBody({\n prompt: opts.prompt,\n repoUrl: opts.repoUrl,\n startingRef: cfg.startingRef,\n model: cfg.model || CURSOR_DEFAULT_MODEL,\n autoCreatePR: cfg.autoCreatePR,\n agentId: opts.agentId,\n name: opts.name,\n }),\n ),\n })\n if (res.status === 409 && opts.agentId) {\n // Re-delivered event: Cursor already holds this agent. Idempotent success.\n const errBody = (await res.json().catch(() => null)) as { error?: { code?: string } } | null\n if (errBody?.error?.code === 'agent_id_conflict' || !errBody) {\n return { agentId: opts.agentId, status: 'EXISTS' }\n }\n throw res\n }\n if (!res.ok) {\n // Throw the Response itself so withRetry can read status / Retry-After.\n // This is the contract documented in @mushi-mushi/plugin-sdk/retry.ts.\n throw res\n }\n const body = (await res.json()) as CreateAgentV1Response\n const prUrl = body.run?.git?.branches?.find((b) => typeof b.prUrl === 'string')?.prUrl\n return {\n agentId: body.agent?.id ?? '',\n runId: body.run?.id,\n status: body.run?.status ?? body.agent?.status ?? 'CREATING',\n agentUrl: body.agent?.url,\n prUrl,\n }\n })\n}\n\nconst DRAFT_PR_INSTRUCTION =\n 'Open the pull request as a DRAFT (Cursor opens drafts by default; keep it that way). ' +\n 'Do not refactor unrelated code and never merge.'\n\nfunction buildPromptFromClassifiedReport(\n envelope: MushiEventEnvelope,\n data: MushiReportClassifiedEvent,\n): string {\n const lines = [\n `A bug has been reported in your project and classified as ${data.classification.severity?.toUpperCase()}.`,\n ``,\n `Report ID: ${data.report.id}`,\n `Title: ${data.report.title ?? '(untitled)'}`,\n `Category: ${data.report.category ?? data.classification.category}`,\n `Severity: ${data.classification.severity}`,\n `Project: ${envelope.projectId}`,\n ]\n\n if (data.classification.tags?.length) {\n lines.push(`Tags: ${data.classification.tags.join(', ')}`)\n }\n\n lines.push(\n ``,\n `Please investigate this bug, identify the root cause in the codebase, ` +\n `and open a draft PR with a minimal fix titled \"fix: <summary> (MUSHI-${data.report.id})\". ${DRAFT_PR_INSTRUCTION}`,\n )\n\n return lines.join('\\n')\n}\n\nfunction buildPromptFromFixRequested(envelope: MushiEventEnvelope, fixData: MushiFixEvent): string {\n return [\n `A fix was requested for report ${fixData.report.id} in project ${envelope.projectId}.`,\n ``,\n `Report title: ${fixData.report.title ?? '(untitled)'}`,\n `Fix ID: ${fixData.fix.id}`,\n fixData.fix.branch ? `Requested branch: ${fixData.fix.branch}` : '',\n ``,\n `Please investigate the reported issue, identify the root cause, ` +\n `and open a draft PR with a minimal fix titled \"fix: <summary> (MUSHI-${fixData.report.id})\". ${DRAFT_PR_INSTRUCTION}`,\n ]\n .filter((line) => line !== '')\n .join('\\n')\n}\n\nfunction buildPromptFromQaStoryFailed(\n envelope: MushiEventEnvelope,\n data: { storyId?: string; title?: string; failureReason?: string },\n): string {\n return [\n `A QA story failed in project ${envelope.projectId}.`,\n ``,\n `Story ID: ${data.storyId ?? 'unknown'}`,\n `Title: ${data.title ?? '(untitled)'}`,\n data.failureReason ? `Failure: ${data.failureReason}` : '',\n ``,\n `Please investigate the failing assertion, identify the root cause in the codebase, ` +\n `and open a draft PR with a minimal fix. ${DRAFT_PR_INSTRUCTION}`,\n ]\n .filter((line) => line !== '')\n .join('\\n')\n}\n\n/** Build the plugin handler and return a callable function. */\nexport function createCursorCloudPlugin(cfg: CursorCloudPluginConfig) {\n const minRank = SEVERITY_RANK[cfg.severityThreshold ?? 'critical']!\n const model = cfg.model ?? CURSOR_DEFAULT_MODEL\n const autoCreatePR = cfg.autoCreatePR ?? true\n const f = cfg.fetchImpl ?? fetch\n\n const resolvedCfg = {\n apiKey: cfg.apiKey,\n model,\n autoCreatePR,\n startingRef: cfg.startingRef,\n apiBase: cfg.apiBase,\n }\n\n const webhookSecret =\n cfg.webhookSecret ??\n (typeof process !== 'undefined' ? process.env.MUSHI_PLUGIN_WEBHOOK_SECRET : undefined)\n if (!webhookSecret) {\n throw new Error(\n 'Cursor Cloud plugin requires webhookSecret (or MUSHI_PLUGIN_WEBHOOK_SECRET) for inbound event verification.',\n )\n }\n\n return createPluginHandler({\n secret: webhookSecret,\n on: {\n 'report.classified': async (e) => {\n const data = e.data as MushiReportClassifiedEvent\n const rank = SEVERITY_RANK[data.classification.severity ?? ''] ?? 0\n if (rank < minRank) return\n\n const repoUrl = cfg.repoUrl ?? ''\n if (!repoUrl) {\n console.warn('[cursor-cloud] report.classified skipped: repoUrl not configured. ' +\n 'Set repoUrl in the plugin config so the agent knows which codebase to fix.')\n return\n }\n\n const run = await createCursorAgentRun(\n resolvedCfg,\n {\n repoUrl,\n prompt: buildPromptFromClassifiedReport(e, data),\n agentId: await deterministicAgentId(`report.classified:${e.projectId}:${data.report.id}`),\n name: `Mushi report ${data.report.id.slice(0, 8)}`,\n },\n f,\n )\n\n // Emit audit log — handler return type is void.\n const result: CursorDispatchResult = { agentId: run.agentId, reportId: data.report.id, model }\n console.warn('[cursor-cloud] dispatched', JSON.stringify(result))\n },\n\n 'fix.requested': async (e) => {\n const data = e.data as MushiFixEvent & { fix: { externalAgentId?: string; agent?: string } }\n\n // Mushi's first-class cursor_cloud path already created the agent —\n // the event tells us which one. Starting another would double the\n // spend and open two PRs for one report.\n if (typeof data.fix?.externalAgentId === 'string' && data.fix.externalAgentId.length > 0) {\n console.warn(\n '[cursor-cloud] fix.requested already dispatched by Mushi fix-worker',\n JSON.stringify({ agentId: data.fix.externalAgentId, reportId: data.report.id, agent: data.fix.agent }),\n )\n return\n }\n\n const repoUrl = cfg.repoUrl ?? ''\n if (!repoUrl) {\n console.warn('[cursor-cloud] fix.requested skipped: repoUrl not configured.')\n return\n }\n\n const run = await createCursorAgentRun(\n resolvedCfg,\n {\n repoUrl,\n prompt: buildPromptFromFixRequested(e, data),\n agentId: await deterministicAgentId(`fix.requested:${e.projectId}:${data.fix.id}`),\n name: `Mushi fix ${data.fix.id.slice(0, 8)}`,\n },\n f,\n )\n\n // Emit audit log — handler return type is void.\n const result: CursorDispatchResult = { agentId: run.agentId, reportId: data.report.id, model }\n console.warn('[cursor-cloud] fix.requested dispatched', JSON.stringify(result))\n },\n\n 'qa_story.failed': async (e) => {\n const data = e.data as { storyId?: string; title?: string; failureReason?: string }\n\n const repoUrl = cfg.repoUrl ?? ''\n if (!repoUrl) {\n console.warn('[cursor-cloud] qa_story.failed skipped: repoUrl not configured.')\n return\n }\n\n const run = await createCursorAgentRun(\n resolvedCfg,\n {\n repoUrl,\n prompt: buildPromptFromQaStoryFailed(e, data),\n agentId: await deterministicAgentId(`qa_story.failed:${e.projectId}:${data.storyId ?? e.deliveryId}`),\n name: `Mushi QA story ${(data.storyId ?? 'unknown').slice(0, 8)}`,\n },\n f,\n )\n\n const result: CursorDispatchResult = {\n agentId: run.agentId,\n reportId: data.storyId ?? 'unknown',\n model,\n }\n console.warn('[cursor-cloud] qa_story.failed dispatched', JSON.stringify(result))\n },\n\n // ── Skill pipeline step dispatch (Phase 5) ───────────────────────────\n // When a pipeline run is started in 'cloud' mode, the skills.ts route\n // fires this event for each step. The plugin creates a Cursor Cloud\n // agent run whose prompt is the pre-composed context_packet for that\n // step, stores the agentId on the step row, and reports back to Mushi\n // via the check-in endpoint.\n 'skill_pipeline.step.dispatched': async (e) => {\n const data = e.data as {\n runId: string\n stepIndex: number\n skillSlug: string\n contextPacket: string\n projectId: string\n }\n\n const repoUrl = cfg.repoUrl ?? ''\n if (!repoUrl) {\n console.warn('[cursor-cloud] skill_pipeline.step.dispatched skipped: repoUrl not configured.')\n return\n }\n\n let run: CursorAgentRunResponse\n try {\n run = await withRetry(\n () =>\n createCursorAgentRun(\n resolvedCfg,\n {\n repoUrl,\n prompt: buildPromptFromSkillStep(data),\n agentId: undefined,\n name: `Mushi skill ${data.skillSlug.slice(0, 40)} #${data.stepIndex + 1}`,\n },\n f,\n ),\n { maxAttempts: 3 },\n )\n } catch (err) {\n console.error('[cursor-cloud] skill_pipeline step dispatch failed', String(err))\n const mushiUrl =\n (typeof process !== 'undefined' ? process.env.MUSHI_API_URL : undefined) ?? 'https://api.mushi.ai'\n const mushiKey =\n (typeof process !== 'undefined' ? process.env.MUSHI_API_KEY : undefined) ?? ''\n if (mushiKey) {\n try {\n await f(`${mushiUrl}/v1/admin/skills/pipelines/${data.runId}/steps/${data.stepIndex}/checkin`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Mushi-Api-Key': mushiKey,\n },\n body: JSON.stringify({\n status: 'failed',\n notes: `Cursor Cloud dispatch failed: ${String(err).slice(0, 400)}`,\n }),\n })\n } catch { /* best-effort */ }\n } else {\n console.warn(\n `[cursor-cloud] MUSHI_API_KEY unset — cannot report the failed dispatch for run ${data.runId} step ${data.stepIndex}. ` +\n `The step will remain 'running' server-side until it is manually checked in.`,\n )\n }\n return\n }\n\n console.log('[cursor-cloud] skill_pipeline step dispatched', {\n runId: data.runId,\n stepIndex: data.stepIndex,\n agentId: run.agentId,\n })\n\n // Report back to Mushi: update the step row with the agentId.\n // The console React Flow canvas will update via Realtime.\n // Use a best-effort POST to the check-in endpoint.\n const mushiUrl =\n (typeof process !== 'undefined' ? process.env.MUSHI_API_URL : undefined) ?? 'https://api.mushi.ai'\n const mushiKey =\n (typeof process !== 'undefined' ? process.env.MUSHI_API_KEY : undefined) ?? ''\n\n if (mushiKey) {\n try {\n await f(`${mushiUrl}/v1/admin/skills/pipelines/${data.runId}/steps/${data.stepIndex}/checkin`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Mushi-Api-Key': mushiKey,\n },\n body: JSON.stringify({\n status: 'running',\n agent_ref: run.agentId,\n notes: `Cursor Cloud agent dispatched (model: ${model})`,\n }),\n })\n } catch (err) {\n console.warn('[cursor-cloud] checkin failed (best-effort)', String(err))\n }\n } else {\n console.warn(\n `[cursor-cloud] MUSHI_API_KEY unset — agent ${run.agentId} was dispatched for run ${data.runId} step ${data.stepIndex} ` +\n `but its agent_ref/running status cannot be reported back. The console flow will not reflect this step until it is manually checked in.`,\n )\n }\n },\n },\n })\n}\n\nfunction buildPromptFromSkillStep(data: {\n runId: string\n stepIndex: number\n skillSlug: string\n contextPacket: string\n}): string {\n return [\n `# Mushi Skill Pipeline — Step ${data.stepIndex + 1}`,\n ``,\n `Skill: \\`${data.skillSlug}\\``,\n `Pipeline run: ${data.runId}`,\n ``,\n `You are executing step ${data.stepIndex + 1} of a Mushi skill pipeline. ` +\n `The full context packet below contains your instructions plus the complete report context.`,\n ``,\n `When you have completed this step, call the Mushi MCP tool \\`checkin_pipeline_step\\` with:`,\n ` run_id: \"${data.runId}\"`,\n ` step_index: ${data.stepIndex}`,\n ` status: \"passed\" (or \"failed\" if you could not complete it)`,\n ` pr_url: <your PR URL if you opened one>`,\n ``,\n `Push your work to a branch named \\`mushi/skill-${data.skillSlug.slice(0, 24)}-${data.runId.slice(0, 8)}\\` and ${DRAFT_PR_INSTRUCTION}`,\n ``,\n `─── Context Packet ────────────────────────────────────────────────────`,\n ``,\n data.contextPacket.slice(0, 32_000),\n ].join('\\n')\n}\n"],"mappings":"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","names":["mushiUrl","mushiKey"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mushi-mushi/plugin-cursor-cloud",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Mushi Mushi plugin: dispatch a Cursor Cloud Agent when a critical bug is classified or a QA story fails — opens a signed draft PR automatically.",
|
|
6
6
|
"type": "module",
|
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
"LICENSE"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@mushi-mushi/plugin-sdk": "^0.
|
|
21
|
+
"@mushi-mushi/plugin-sdk": "^0.8.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@types/node": "^22.
|
|
25
|
-
"eslint": "^10.
|
|
24
|
+
"@types/node": "^22.20.0",
|
|
25
|
+
"eslint": "^10.6.0",
|
|
26
26
|
"tsup": "^8.5.1",
|
|
27
27
|
"typescript": "^6.0.3",
|
|
28
|
-
"vitest": "^4.1.
|
|
28
|
+
"vitest": "^4.1.9",
|
|
29
29
|
"@mushi-mushi/eslint-config": "0.0.0"
|
|
30
30
|
},
|
|
31
31
|
"repository": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"url": "https://github.com/kensaurus/mushi-mushi.git",
|
|
34
34
|
"directory": "packages/plugin-cursor-cloud"
|
|
35
35
|
},
|
|
36
|
-
"author": "Kenji Sakuramoto (https://
|
|
36
|
+
"author": "Kenji Sakuramoto <kensaurus@gmail.com> (https://github.com/kensaurus)",
|
|
37
37
|
"publishConfig": {
|
|
38
38
|
"access": "public",
|
|
39
39
|
"provenance": true
|
|
@@ -50,15 +50,11 @@
|
|
|
50
50
|
"integration"
|
|
51
51
|
],
|
|
52
52
|
"engines": {
|
|
53
|
-
"node": ">=20"
|
|
53
|
+
"node": ">=20.19.0"
|
|
54
54
|
},
|
|
55
55
|
"bugs": {
|
|
56
56
|
"url": "https://github.com/kensaurus/mushi-mushi/issues"
|
|
57
57
|
},
|
|
58
|
-
"funding": {
|
|
59
|
-
"type": "github",
|
|
60
|
-
"url": "https://github.com/sponsors/kensaurus"
|
|
61
|
-
},
|
|
62
58
|
"homepage": "https://kensaur.us/mushi-mushi",
|
|
63
59
|
"scripts": {
|
|
64
60
|
"build": "tsup",
|