ok
This commit is contained in:
@@ -2,47 +2,59 @@
|
||||
"version": 1,
|
||||
"skills": {
|
||||
"babysit": {
|
||||
"lastSyncedAt": 1780053556720
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"canvas": {
|
||||
"lastSyncedAt": 1780053556720
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"create-hook": {
|
||||
"lastSyncedAt": 1780053556720
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"create-rule": {
|
||||
"lastSyncedAt": 1780053556720
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"create-skill": {
|
||||
"lastSyncedAt": 1780053556720
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"create-subagent": {
|
||||
"lastSyncedAt": 1780053556720
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"sdk": {
|
||||
"lastSyncedAt": 1780053556720
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"migrate-to-skills": {
|
||||
"lastSyncedAt": 1780053556720
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"shell": {
|
||||
"lastSyncedAt": 1780053556720
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"split-to-prs": {
|
||||
"lastSyncedAt": 1780053556720
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"statusline": {
|
||||
"lastSyncedAt": 1780053556720
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"update-cli-config": {
|
||||
"lastSyncedAt": 1780053556720
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"update-cursor-settings": {
|
||||
"lastSyncedAt": 1780053556720
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"loop": {
|
||||
"lastSyncedAt": 1780053556720
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"review": {
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"review-bugbot": {
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"review-security": {
|
||||
"lastSyncedAt": 1782715883553
|
||||
},
|
||||
"automate": {
|
||||
"lastSyncedAt": 1782715883553
|
||||
}
|
||||
},
|
||||
"lastInventoryAt": 1780014510207
|
||||
"lastInventoryAt": 1782633007842
|
||||
}
|
||||
377
skills-cursor/automate/SKILL.md
Normal file
377
skills-cursor/automate/SKILL.md
Normal file
@@ -0,0 +1,377 @@
|
||||
---
|
||||
name: automate
|
||||
description: Use this skill to create Cursor Automations.
|
||||
environments:
|
||||
- local
|
||||
---
|
||||
# Create Automation (Interactive)
|
||||
|
||||
Use this skill when the user explicitly wants to make, build, set up, or create a new **Cursor Automation** — for example "create a Cursor automation", "open the Automations editor with this draft", or "set up a scheduled Cursor agent".
|
||||
|
||||
**Disambiguation.** "Automation" in a user workspace can mean many things (`.github/workflows`, CI pipelines, scheduled jobs, scripts, dbt, browser automation, shell scripts, workflow engines). Do **not** assume generic phrases like "automate this", "help me automate my deploys", or "make an automation" mean **Cursor Automation**. Route to the named surface when the user mentions one, use normal repo/product exploration when the context points elsewhere, or ask a short clarifying question when the target surface is ambiguous. Start this spine only when the user explicitly asks for Cursor Automations or confirms that Cursor Automations is the intended surface.
|
||||
|
||||
## Execution spine (every run)
|
||||
|
||||
1. **Finish-path check.** First, check whether the in-app Automations editor handoff is available (see **Finish availability** below). If neither the Automations editor tool nor the resource opener is available, immediately say "Please use this skill in the Agents Window." and stop.
|
||||
2. **Capture intent + proactive integration discovery.** After the finish-path check passes, if the prompt is missing 2+ of {what kicks it off, what should happen, what outcome}, send one short plain-chat message asking for a 1–2 sentence description and wait. Skip when the prompt already names trigger + action + outcome. Proactively run discovery for any integration the user named or implied — `gh repo view` on cwd; Slack MCP channels; PagerDuty MCP services; Linear/Sentry MCP teams/projects. Use the results to skip questions later.
|
||||
3. **Completeness gates.** Work through the trigger, tool, prompt, naming, and PCD checks below. Do not jump to a summary while required picker-backed fields are still unknown unless the user explicitly deferred them to the Automations editor.
|
||||
4. **One consolidated question.** Ask inline for whatever integration discovery couldn't resolve — trigger details, repo / channel / service when ambiguous, tools when not obvious. Default to plain-chat inline. Only escalate to `AskQuestion` for (a) the tools multi-select and (b) integration discovery candidate lists with 3+ matches.
|
||||
5. **Draft table → approval → finish handoff.** Show a compact Markdown table (plain language, no YAML) recapping name / description, trigger, tools, instructions, resolved settings, and "to finish in editor". User approves, then ask whether they are ready for you to open the Automations editor so they can finish any deferred values there. When they say yes, use the finish path from the availability check.
|
||||
|
||||
---
|
||||
|
||||
## House rules
|
||||
|
||||
- **Plain language only.** Never show or talk about MCP / tool / proto names, request types, enum values, stage labels, or raw CLI output in user-visible chat. Say "open the editor with the draft", "the Slack channel", "the repo and branch". Exception: the user explicitly asks to see internals.
|
||||
- **No YAML in finalization.** The draft table = compact Markdown only in plain language. Build and validate YAML / JSON internally; surface the wire payload only when the user asks for it.
|
||||
- **No automatic fallbacks.** Never submit, open a URL, paste a browser prefill link, or switch buckets. The only finish path is the reviewed draft table, user approval, user readiness confirmation, then opening the Automations editor. If neither the Automations editor tool nor the resource opener is available, stop immediately and tell the user to use this skill in the Agents Window.
|
||||
- **Creation-only.** This skill prepares new automations only. Do not list, get, inspect, update, or search existing Cursor Automations from chat.
|
||||
- **Integration discovery is allowed.** Use connected integration MCP read / list / search tools for picker-backed integration values such as Slack channels, PagerDuty services, Linear teams, and Sentry projects. This does **not** include backend automation tools that list, get, inspect, create, update, finish, or prefill Cursor Automations.
|
||||
- **Repo file references.** Only reference a file from the chat's current repo (path, excerpt, or `@file` mention) in any draft field — prompt, instructions, name, or description — when **both** are true: (1) the automation will run in that same repo (its git trigger scope or `workflow.gitConfig.repo` is the chat's repo) **and** (2) the file is committed to that repo (tracked by `git` on the branch the automation will check out, not just present in the working tree). If either condition fails, paraphrase the intent instead, or ask the user to commit and push the file first — do not embed the path or content. Untracked / staged-only / dirty-only files, files outside the automation's repo, and files in a different repo from the chat's checkout never qualify.
|
||||
|
||||
---
|
||||
|
||||
## PCD — Portal completeness & deferral
|
||||
|
||||
Use these checks to keep the draft complete before opening the editor. Do not show the ids to the user.
|
||||
|
||||
| Id | Scope |
|
||||
|----|-------|
|
||||
| **PCD:slack-trigger** | `slackTrigger` channel selection. Ask whether to specify channel(s) now or pick them in the Automations UI; discovery or explicit UI deferral must happen before the draft table. |
|
||||
| **PCD:slack-actions** | `slack` / `readSlack` actions. Ask for the destination or explicit editor deferral before the draft table. |
|
||||
| **PCD:git-scope** | `git` PR / push / CI triggers. Repo/org/branch scope must be resolved or explicitly deferred to the editor. |
|
||||
| **PCD:universal** | Every intentional gap appears in the draft table's "To finish in editor" row and is repeated in the final handoff note. |
|
||||
|
||||
### PCD matrix
|
||||
|
||||
| Scope | Before opening editor unless deferred |
|
||||
|-------|---------------------------------------|
|
||||
| **PCD:slack-trigger** | Slack channel ids are resolved, or user chose to pick channels in the Automations UI. Empty channels are valid only for explicit UI deferral. |
|
||||
| **PCD:slack-actions** | `slack.channel` / readSlack scope is resolved, or user chose **Select channels** in the editor. IDs must be `C…` / `G…` / `D…`, never `U…`. |
|
||||
| **PCD:git-scope** | PR triggers have repos/orgs; push triggers have repo + branch; CI triggers have repo scope. Use scoped repo discovery only after the user identifies the target. |
|
||||
|
||||
### PCD notes
|
||||
|
||||
- Slack trigger and Slack action destinations are separate questions. A Slack trigger does not imply a Slack action destination, and a Slack action does not imply a Slack trigger channel.
|
||||
- Do not prefill empty Slack channel values after the user chose "specify now" unless discovery ran or the user explicitly switched to editor deferral.
|
||||
- For Slack replies, offer "respond in the triggering thread" separately from "send to a specific channel or DM".
|
||||
- When `mcp` is enabled, the server must pass the **MCP existence gate** and **MCP auth gate** below. Prefer discovering and selecting the exact catalog server name yourself; ask the user only when multiple usable catalog matches fit the request or the requested integration is ambiguous. Do not call it a Cursor plugin. Do not invent server names.
|
||||
|
||||
### MCP existence gate
|
||||
|
||||
An MCP server is eligible only when the current user's available MCP/tool catalog proves it exists and is usable in this session. Before using an MCP for integration discovery or adding an `mcp` action to the draft, inspect the actual catalog exposed to the agent session and pick the right value to put into `mcp.server.name`.
|
||||
|
||||
**Read the right field from the catalog.** Each agent-side catalog entry lives at `~/.cursor/mcps/<folder>/SERVER_METADATA.json` and carries two distinct values:
|
||||
|
||||
- `serverIdentifier` — the scoped folder name the agent runtime uses (e.g. `dashboard-team-1-Linear`, `plugin-pagerduty-pagerduty-mcp`, `cursor-app-control`).
|
||||
- `serverName` — the plain name the user configured on cursor.com (e.g. `Linear`, `pagerduty-mcp`, `Databricks SQL`).
|
||||
|
||||
Write `serverName` into `workflow.actions[].mcp.server.name` and any `@[MCP: ...]` prompt mentions. Never write `serverIdentifier` / the folder name, never invent or paraphrase a prefix (`team-…`, `user-…`, `<orgId>-…`), and never hand-strip prefixes from the folder name — many `serverName`s contain spaces (e.g. `Databricks SQL`, `statsig read only console`), so string-munging the identifier is fragile. The Automations editor matches on trim + lowercase, so casing does not matter, but pass the exact `serverName` from `SERVER_METADATA.json` anyway. When you have a useful URL, you may also pass `templateMcpHints: [{ name: <serverName>, url: <serverUrl> }]` so a URL match can rescue a name drift.
|
||||
|
||||
**Eligibility — dashboard-backed servers only.** Only dashboard-backed servers appear in the Automations editor's `GetAvailableMcpServers` response, which is what the editor uses to resolve a prefilled `mcp` action to a connected server. Their `serverIdentifier` always begins with one of these prefixes:
|
||||
|
||||
- `dashboard-team-<teamId>-` (team-shared servers)
|
||||
- `dashboard-` (personal user-configured servers on cursor.com)
|
||||
- `plugin-<slug>-` (marketplace plugin servers)
|
||||
|
||||
Everything else in the agent catalog — `cursor-ide-browser`, `cursor-app-control`, `extension-…`, project `mcp.json` servers, and other local servers — does NOT appear in the dashboard catalog. Treat those as ineligible for the `mcp` action: do not add them to `workflow.actions`, do not reference them in `@[MCP: ...]` prompt mentions, and do not assume they will resolve when the editor opens. Prefilling an ineligible server lands the row in the blocked "Set up MCP" state and prevents the user from saving.
|
||||
|
||||
If one usable, dashboard-eligible catalog server clearly matches the user's requested integration, use it without asking the user to spell the server name. A name from the user prompt, a screenshot, a skill file, a workflow template, marketplace docs, or company convention is not proof.
|
||||
|
||||
If the catalog does not contain a usable, dashboard-eligible server, do not call that MCP, do not add an `mcp` action for it, and do not include `@[MCP: ...]` prompt mentions. Servers that are missing, disabled, or still need setup count as unavailable for prefill. Ask the user to set it up first, or leave the MCP out of the draft and record "Set up/select <integration> in the Automations editor" in **To finish in editor**. Unknown MCP server names are not valid deferred tool rows because prefilled missing MCPs block save.
|
||||
|
||||
### MCP auth gate
|
||||
|
||||
**Why this exists.** The Automations editor can prompt for MCP OAuth, but that flow navigates away from the draft and the user loses in-progress changes. Authenticate MCPs here in chat **before** you add an `mcp` action, show the draft table, or open the editor.
|
||||
|
||||
**When it applies.** Run this gate whenever you plan to add an `mcp` action or `@[MCP: ...]` prompt mention for a dashboard-eligible server — including after integration discovery for picker-backed values.
|
||||
|
||||
**Detect unauthenticated servers** from the current session catalog (do not guess). `STATUS.md` is written for both auth and generic error states, so its mere existence is **not** an auth signal — read the file and check its content:
|
||||
|
||||
- `~/.cursor/mcps/<folder>/STATUS.md` exists **and** its content says the server needs authentication (e.g. "needs authentication" / instructs calling `mcp_auth`). A STATUS.md that only reports a generic error is **not** an auth signal.
|
||||
- `GetMcpTools` (or equivalent catalog inspection) reports `serverStatus: "needsAuth"` for that server's `serverIdentifier`.
|
||||
- The server's live tool list is only `mcp_auth` (no other usable tools yet).
|
||||
- Integration discovery against that server fails with an authentication / authorization error.
|
||||
|
||||
A server that passes the existence gate but matches any auth signal above is **not authenticated** — treat it separately from "missing", "not set up", or generic error.
|
||||
|
||||
**Hard stop until authed.** If the target MCP is not authenticated:
|
||||
|
||||
1. **Stop the automation-drafting spine.** Do not add the `mcp` action, do not include `@[MCP: ...]` mentions, do not show the draft table, and do not open the Automations editor.
|
||||
2. **Tell the user plainly** which integration still needs to be connected (use `serverName`, never internal ids). Explain that connecting it now keeps their draft safe; deferring auth to the Automations editor can discard unsaved work.
|
||||
3. **Offer inline auth when available.** This skill runs in the Agents Window, where interactive MCP auth is supported. If the server exposes `mcp_auth` (via `GetMcpTools`, the server's tool list, or `STATUS.md`), ask whether you should start the connection flow now. When they agree, authenticate **one server at a time** by calling `mcp_auth` for that server's `serverIdentifier` (empty args through the MCP tool interface, or the session's `McpAuth` tool with `server_identifier` when that is what is listed). Wait for success, re-check auth, then resume drafting.
|
||||
4. **If inline auth is unavailable** (no `mcp_auth` tool in this session), direct them to connect the integration in Cursor Settings → MCP, then return here and confirm when ready. Do not open the editor while the MCP is still unauthenticated.
|
||||
|
||||
**Never defer MCP OAuth to the Automations editor.** Do not put "Authenticate/connect <integration> in the Automations editor" in **To finish in editor** for an MCP you intend to prefill. Unauthenticated prefilled MCP rows block save and the editor auth redirect loses draft state.
|
||||
|
||||
**After auth succeeds**, re-run the auth gate, then continue integration discovery and drafting. Only include the `mcp` tool in the draft once the server is authenticated and usable.
|
||||
|
||||
---
|
||||
|
||||
## Procedure
|
||||
|
||||
### Stage 0 — Finish availability (must run before intent capture)
|
||||
|
||||
**Finish availability** (check once per run; this is the agent-internal decision — never quote tool names back to the user). Do not mention this check to the user. Do not say anything like "I'll first check whether the Automations editor handoff is available in this session." Do not inspect Cursor backend automation tools. Do not inspect Cursor backend automation tool descriptors to recover an old finish path.
|
||||
|
||||
| Bucket | Signal | Default finish |
|
||||
|--------|--------|----------------|
|
||||
| **Automations editor** | `cursor-app-control.open_automation` listed | Open the Automations editor with the reviewed draft |
|
||||
| **Agents Window required** | Neither `cursor-app-control.open_automation` nor `cursor-app-control.open_resource` listed | Stop immediately — say "Please use this skill in the Agents Window." |
|
||||
|
||||
The Automations editor path uses `open_automation` directly with the reviewed draft. Do not inspect or call backend automation finish tools, build or paste a browser prefill URL, call `open_resource`, or build a `cursor://` deeplink.
|
||||
|
||||
If neither `cursor-app-control.open_automation` nor `cursor-app-control.open_resource` is available, do not continue the automation-drafting flow, do not generate a browser prefill URL, and do not ask follow-up questions. Immediately tell the user: "Please use this skill in the Agents Window."
|
||||
|
||||
### Stage 1 — Capture intent (plain chat, no AskQuestion)
|
||||
|
||||
Run this stage only after the finish availability check passes. If the user's prompt is thin, send one short plain-chat message and **wait**:
|
||||
|
||||
> "Before we dive in, what do you want this automation to do? What kicks it off, what should happen, and what's the outcome? A sentence or two is plenty. Let me know if you want some examples of what you can build."
|
||||
|
||||
Skip when the prompt already covers trigger + action + outcome, or the user said something similar to "walk me through it". The answer is freeform — never wrap this question in `AskQuestion`. Don't run repo discovery before Stage 1 fires or is deliberately skipped.
|
||||
|
||||
### Stage 2 — Authoring funnel
|
||||
|
||||
Existing automation edits are not supported in this flow. Do not list, get, inspect, update, or search existing automations through backend automation tools. Do not search by automation name or description. If the user wants to change an existing automation, ask them to edit it directly in the Automations UI or create a new replacement automation. Do not claim changes were saved from chat.
|
||||
|
||||
Work in Automations UI order: trigger → tools → prompt → name/description → draft table. Fill gaps from prior messages. Do not jump straight to YAML unless the user's prompt already covers the needed fields and PCD gates are satisfied or explicitly deferred.
|
||||
|
||||
#### Trigger
|
||||
|
||||
Use the **Appendix — Trigger selection tables** to pick the trigger and follow-ups. Resolve picker-backed values via integration discovery before asking; ask only for fields not already answered. A cron trigger without a resolved schedule is invalid for direct save; webhook triggers always come back to the editor after save for URL / auth.
|
||||
|
||||
#### Scheduled times
|
||||
|
||||
Cron stores a single expression, not a separate timezone field. If the user gives a schedule that maps cleanly to cron fields (for example "every weekday at 3am", "daily at 9am", or "Mondays at 9am"), include the cron trigger in the editor prefill. Treat "my timezone" or "local time" as the user's desired display-time intent when the hour/day pattern itself is expressible as cron. Do not put a schedule only in the prompt while leaving `workflow.triggers` empty.
|
||||
|
||||
For user-stated local times that cannot be encoded exactly as the Automations editor will display, do not pass a raw cron plus a timezone hint. Ask one more schedule question before opening the editor; do not open a scheduled automation with no trigger. Do not prefill `cron: {}`. It is invalid.
|
||||
|
||||
Valid cron examples:
|
||||
|
||||
```yaml
|
||||
# Every hour
|
||||
cron: { cron: "0 * * * *" }
|
||||
|
||||
# Every day at 9:00
|
||||
cron: { cron: "0 9 * * *" }
|
||||
|
||||
# Every Monday at 9:00
|
||||
cron: { cron: "0 9 * * 1" }
|
||||
|
||||
# Weekdays at 9:00
|
||||
cron: { cron: "0 9 * * 1-5" }
|
||||
```
|
||||
|
||||
#### Tools
|
||||
|
||||
Ask with structured multi-select when the tools are not obvious:
|
||||
|
||||
| Label | YAML |
|
||||
|-------|------|
|
||||
| Comment on PRs | `prComment` |
|
||||
| Post to Slack | `slack` |
|
||||
| Read Slack | `readSlack` |
|
||||
| Request reviewers | `requestReviewers` |
|
||||
| Manage check runs | `manageCheckRun` |
|
||||
| Use MCP server | `mcp` |
|
||||
|
||||
When `slack` / `readSlack` is enabled, resolve the channel via Slack MCP discovery before drafting or document UI deferral. When `mcp` is enabled, run the MCP existence gate and MCP auth gate first; only exact, authenticated, usable catalog matches may be added to `workflow.actions`, and `mcp.server.name` MUST be the `serverName` value from the matched entry's `SERVER_METADATA.json` — never the folder / `serverIdentifier`. If a requested MCP is missing or not set up, do not prefill it — ask the user to set it up or defer setup/selection to the editor. If it exists but is not authenticated, stop per the MCP auth gate — do not prefill it and do not defer OAuth to the editor.
|
||||
|
||||
#### Prompt + name
|
||||
|
||||
Ask "What should the agent do when [trigger]?" Default one tight paragraph; match the user's length if they gave more. Cloud compute is configured in the [Cloud Agent dashboard](https://cursor.com/dashboard?tab=cloud-agents). Suggest a name + 1–2 sentence description from prior answers.
|
||||
|
||||
#### Fast-path
|
||||
|
||||
If confidence is high and required fields are present, you may skip straight to the draft table. Do not use fast-path to skip Slack channel choices, Git repo/branch scope, `mcp.server.name`, an unresolved schedule, or the MCP auth gate — fast-path never bypasses the **Hard stop until authed** rule, and the draft table cannot appear while a prefilled MCP is still unauthenticated. When uncertain, ask one focused question rather than replaying the full questionnaire.
|
||||
|
||||
### Stage 3 — Draft table, validation, finish
|
||||
|
||||
Recap the draft as a compact Markdown table in plain language. Don't write a planning document, checklist, or "steps I'll take":
|
||||
|
||||
| Draft field | What will open in the editor |
|
||||
|-------------|------------------------------|
|
||||
| Name / description | Short plain-language value |
|
||||
| Trigger | What starts the automation |
|
||||
| Tools | Enabled capabilities |
|
||||
| Instructions | The prompt behavior, summarized |
|
||||
| Resolved settings | Repo / branch, Slack channel, service / project, schedule, and other picker-backed values |
|
||||
| To finish in editor | Settings deferred to the Automations UI; write "None" if nothing is deferred |
|
||||
|
||||
End with "Does this look correct?" Do not append a YAML or JSON block. After approval, run the internal **Validation check**, then send the finish handoff confirmation. A plain "yes" to the draft approves the draft, but it does not replace the final readiness confirmation.
|
||||
|
||||
#### Glass finish path (compliance)
|
||||
|
||||
When `cursor-app-control.open_automation` is available, there is exactly one finish path:
|
||||
|
||||
1. Show the Markdown draft table.
|
||||
2. Wait for the user to approve it.
|
||||
3. Tell the user which values, setup, or webhook/auth details must be finished in the Automations editor. Ask a direct readiness question, such as "Are you ready for me to open it for you?"
|
||||
4. After they confirm, open the Automations editor with the reviewed draft.
|
||||
|
||||
Do not offer save, browser, paste-link, skip, or fallback choices.
|
||||
|
||||
### Post-finish actions (agent-internal)
|
||||
|
||||
Before opening the editor or otherwise moving the user away from chat, send one short final handoff note with every deferred field and caveat the user needs after the handoff. Include all "To finish in editor" rows, integration setup notes, webhook/auth follow-ups, Slack DM/channel picker confirmations, Cloud compute notes, and any schedule that was intentionally left for the editor picker. End with a direct readiness question, such as "Are you ready for me to open it for you?" When the user says yes, use the selected finish path. Do not put these reminders after the open step; the user may not see chat once they leave.
|
||||
|
||||
- **Open the Automations editor with the draft** (Automations editor). Use only for new automations. Call `cursor-app-control.open_automation` with the reviewed WorkflowData JSON as `prefillWorkflowData`. Do not call backend automation tools, `open_resource`, a browser URL builder, or a `cursor://` URL for this bucket. If `open_automation` fails, explain the failure in plain language and stop.
|
||||
- **Agents Window required**. If neither `cursor-app-control.open_automation` nor `cursor-app-control.open_resource` is available, say "Please use this skill in the Agents Window." Do not draft, submit, paste a browser prefill URL, or switch paths automatically.
|
||||
|
||||
---
|
||||
|
||||
## Reference
|
||||
|
||||
### Discover before ask
|
||||
|
||||
Before asking the user for a picker-backed value (repo, Slack channel / DM, GitHub/GitLab PR / comment scope, PagerDuty service, Linear team, Sentry project, …), proactively check whether the associated integration MCP or CLI is available and authenticated, then fetch the relevant records. For MCP-backed integrations, the availability check must be the current user's actual MCP/tool catalog, not a remembered or guessed server name. Use the result to inform the next question: **1 match → inline confirm; 2 → inline either/or; 3+ → `AskQuestion` single-select.** Only ask freeform after scoped integration discovery is exhausted or the user picks deferral to the automations editor.
|
||||
|
||||
**Auth boundary.** Call integration list / search / read tools, `gh`, or `glab` when connected and authenticated. Do not use this path to list, get, inspect, create, update, finish, or prefill Cursor Automations.
|
||||
|
||||
- **MCP integrations used for an `mcp` automation action** follow the **MCP auth gate** above — stop, explain, and authenticate in chat before prefilling. Inline `mcp_auth` is supported in the Agents Window when listed for that server.
|
||||
- **Other integrations** (Slack channel discovery, PagerDuty services, `gh` / `glab`, etc.): if missing or unavailable, ask whether the user wants to set it up before continuing. If they say yes, guide setup and retry discovery after they confirm it is ready. If they say no, continue with the draft and say the user will need to finish that integration setup in the Automations editor afterwards. For these non-MCP-action integrations only, do not call `mcp_auth` without an explicit **Retry after setup** confirmation.
|
||||
|
||||
#### GitHub / GitLab repo scope
|
||||
|
||||
Accept natural repo nicknames; do not ask for `owner/repo` format first, and do not ask the user to list repos before trying scoped CLI discovery. Order:
|
||||
|
||||
1. **Exact or current repo.** If the user gave exact `owner/repo`, said "this repo", or the current checkout is the obvious target, use `gh repo view owner/repo --json defaultBranchRef,nameWithOwner` or `gh repo view --json defaultBranchRef,nameWithOwner` to fetch repo + default branch. For GitLab, use the equivalent `glab repo view` / project view command when available. Run auth status only if the exact lookup fails due to auth.
|
||||
2. **Several named candidates.** If the user named several repo candidates, do not run an unscoped search. Resolve exact `owner/repo` candidates with lookup, or run scoped discovery only when a shared owner/org/namespace, current checkout, or product context narrows the search. If no scoped lookup is available, use `AskQuestion` over the user-named repos plus **Pick in Automations UI** before any CLI lookup.
|
||||
3. **User needs to choose.** If the user needs to select a repo and the owner/org/namespace, nickname, current checkout, or product context scopes the search, proactively fetch candidates before asking: `gh search repos "<nickname> in:name" --json fullName,description --limit 10`, scoped `gh repo list <owner-or-org> --json nameWithOwner,description --limit 20`, or the equivalent scoped `glab repo list` / project search. Do this even when the next step is asking the user to pick one.
|
||||
4. **Present candidates.** Use discovery results or user-named candidate sets in the next question: 1 match → inline confirm; 2 → inline either/or; 3+ → `AskQuestion` over the returned or named repos plus **Pick in Automations UI**. When repo choice is ambiguous after search/list discovery, use `AskQuestion` over partial matches + UI deferral instead of a freeform repo question.
|
||||
5. **Confirm branch.** Use the lookup's default branch when available. If the automation requires a specific branch and discovery did not resolve it, ask for branch or offer the default branch explicitly.
|
||||
6. **Discovery failed or unavailable.** If `gh` / `glab` is missing, unauthenticated, unavailable, or the scoped lookup/search/list fails, then ask the user what repo and branch to use or whether to pick them in the Automations UI. Do not block on CLI setup unless the user chooses **Retry after setup**.
|
||||
|
||||
Guardrails: do not run broad private repo inventory or unscoped account/org sweeps. Keep `gh repo list` / `glab repo list` scoped to an owner/org/namespace or similarly narrow context. Do not use raw `git remote` output as the only source of truth.
|
||||
|
||||
#### Slack
|
||||
|
||||
Slack MCP discovery before channel question, every time `slackTrigger` / `slack` / `readSlack` is involved. **Specify now** means the agent runs discovery first — not "ask the user for IDs". 1 channel → inline confirm; 2 → inline either/or; 3+ → `AskQuestion` over returned channels (+ **Pick in Automations UI**). **Do not prefill with empty channels after Specify now without discovery or continue-without.** If discovery is blocked → **Retry after setup** / **Continue without MCP** / **Pick in Automations UI** inline.
|
||||
|
||||
Slack `channel` accepts `C…` / `G…` / `D…` IDs only — never `U…` member IDs. For Slack replies, offer **respond in the triggering thread** separately from **send to a specific channel or DM**. Empty `{}` actions are valid when the user picks **Select channels** in the editor; record the deferral in the draft table.
|
||||
|
||||
#### PagerDuty / Linear / Sentry
|
||||
|
||||
PagerDuty MCP list services before `serviceIds` scope: 1/2 inline; 3+ → `AskQuestion` over services. **Optional `serviceIds`** — otherwise defer to UI. Linear teams / projects and Sentry projects follow the same pattern: discover when MCP is connected; otherwise defer to the editor.
|
||||
|
||||
### YAML output shape (agent-internal)
|
||||
|
||||
Wire format matches the reviewed Automations draft passed to `open_automation` as `prefillWorkflowData` — canonical proto JSON with full enum names (e.g. `GIT_PULL_REQUEST_ACTION_OPENED`). PR scope lives on `git.pullRequest` (`repos` / `orgs`); `workflow.gitConfig` holds `repo` + `branch` for non-`git` triggers that need a checkout. Use `ignoreDraftPrs`, not `ignoreDraftPr`. Slack channel / DM IDs: `C…` / `G…` / `D…`.
|
||||
|
||||
Skeleton:
|
||||
|
||||
```yaml
|
||||
name: "My automation"
|
||||
description: "Optional description"
|
||||
workflow:
|
||||
triggers: []
|
||||
actions: []
|
||||
prompts: []
|
||||
model: ""
|
||||
agentOptions:
|
||||
skipInstall: false
|
||||
memoryEnabled: true
|
||||
```
|
||||
|
||||
Prompts use `|` block scalar (`>-` folding breaks bullets). Empty `{}` actions are valid when the field is UI-only. `mcp.server.name` is required when `mcp` is enabled, and the name must be the `serverName` field from the matched entry's `SERVER_METADATA.json` — not the folder / `serverIdentifier`. See the MCP existence gate for the eligibility filter and the no-prefix-invention rule.
|
||||
|
||||
**Trigger oneof keys are exhaustive.** Every entry in `workflow.triggers` must use exactly one of these top-level proto keys: `cron`, `git`, `slackTrigger`, `slackReactionAdded`, `slackChannelCreated`, `microsoftTeamsTrigger`, `microsoftTeamsChannelCreated`, `linear`, `webhook`, `pagerduty`, `sentry`. Never invent or paraphrase (`slackReaction`, `slack_reaction`, `slack`, `reactionAdded`, etc.) — the editor decodes triggers with `ignoreUnknownFields: true`, silently drops unknown keys, and renders the result as an unconfigurable "Configure trigger" card that blocks save. Empty `{}` trigger entries hit the same failure mode; never prefill a trigger you cannot fully name.
|
||||
|
||||
### Validation check (agent-internal)
|
||||
|
||||
After draft table approval: validate YAML vs checklist + proto (PR enums, `ignoreDraftPrs`, Slack ID prefixes, `gitConfig` presence when needed, `mcp.server.name` when `mcp` is enabled, MCP actions backed by authenticated usable catalog matches, and description text free of `__securitybot_metadata__` / `customInstruction` metadata markers). **Do not invent inline JSON-schema validators** or shell snippets for automation YAML — they drift from proto shape and can falsely fail valid drafts. If validation fails, explain the issue in plain language and ask what to change; do not paste the full YAML unless the user explicitly asked. **Do not use backend automation tools and do not shell out to repo-local scripts** — use `open_automation` for Automations editor handoff only.
|
||||
|
||||
---
|
||||
|
||||
## Appendix — Trigger selection tables
|
||||
|
||||
These labels are agent-only — never show ids to users. If a future structured picker is used, split rows before any option cap.
|
||||
|
||||
### Trigger category
|
||||
|
||||
**Prompt:** "When should this automation run?"
|
||||
|
||||
| Option label | Option id | Proto / YAML |
|
||||
|--------------|-----------|----------------|
|
||||
| On a schedule | `cron` | `cron` |
|
||||
| On a GitHub / GitLab event | `git` | `git` → specific event |
|
||||
| On a Slack event | `slack` | specific event: `slackTrigger` vs `slackChannelCreated` |
|
||||
| On a Linear event | `linear` | `linear` → specific event |
|
||||
| On a PagerDuty incident event | `pagerduty` | `pagerduty` → specific event |
|
||||
| On a Sentry issue event | `sentry` | `sentry` → specific event |
|
||||
| On an incoming HTTP webhook | `webhook` | `webhook` |
|
||||
|
||||
### Specific event (per category)
|
||||
|
||||
**`cron`** — Prompt: "Which schedule shape?"
|
||||
|
||||
| Option label | Option id | Notes |
|
||||
|--------------|-----------|-------|
|
||||
| Every hour | `cron_every_hour` | UI preset |
|
||||
| Every day | `cron_every_day` | preset |
|
||||
| Every week | `cron_every_week` | preset |
|
||||
| Custom cron expression | `cron_custom` | user supplies full cron |
|
||||
|
||||
**`git`** — Prompt: "Which Git event?"
|
||||
|
||||
| Option label | Option id | Maps to |
|
||||
|--------------|-----------|---------|
|
||||
| Draft pull request opened | `git_draft_opened` | `DRAFT_OPENED` |
|
||||
| Pull request opened | `git_pr_opened` | `OPENED` |
|
||||
| Code pushed to a pull request | `git_pr_pushed` | `PUSHED` |
|
||||
| Pull request merged | `git_pr_merged` | `MERGED` |
|
||||
| Comment added on pull request | `git_pr_commented` | `COMMENTED` |
|
||||
| Label change | `git_label` | label trigger |
|
||||
| New push to branch | `git_push` | push |
|
||||
| Checks completed | `git_ci` | `ciCompleted` |
|
||||
|
||||
**`slack`** — Prompt: "Which Slack trigger?"
|
||||
|
||||
| Option label | Option id | YAML |
|
||||
|--------------|-----------|------|
|
||||
| New message in channel | `slack_message` | `slackTrigger` |
|
||||
| Reaction added to message | `slack_reaction_added` | `slackReactionAdded` |
|
||||
| Channel created | `slack_channel_created` | `slackChannelCreated` |
|
||||
|
||||
**`slackReactionAdded` payload** — `{ channels: ["C…"], emojiName: "<name>" }`. `emojiName` is the Slack short name **without** surrounding colons (e.g. `thumbsup`, not `:thumbsup:`); the server normalizes Unicode emoji to the matching alias on save. Completion reactions are not supported on `slackReactionAdded` triggers (would recurse) and are silently dropped.
|
||||
|
||||
**Completion reaction on a Slack message trigger.** "React with `:foo:` when the agent finishes" is a completion-reaction option on `slackTrigger`, not a separate trigger. Put `slackCompletionReactionMode: SLACK_COMPLETION_REACTION_MODE_CUSTOM` and `slackCompletionReactionCustomEmoji: ":foo:"` (with surrounding colons) on the same `slackTrigger` entry. Do not create a `slackReactionAdded` trigger to express completion behavior.
|
||||
|
||||
**Disambiguate "react with …".** When the user says "react with X to trigger" the trigger is `slackReactionAdded` (`emojiName: "x"`, no colons). When the user says "react with X when done" / "upon completion" / "after success" the trigger is `slackTrigger` with the completion-reaction fields above. Ask one focused question when intent is ambiguous instead of guessing.
|
||||
|
||||
**`linear`** — Prompt: "Which Linear event?"
|
||||
|
||||
| Option label | Option id | Proto JSON |
|
||||
|--------------|-----------|------------|
|
||||
| Issue created | `linear_created` | `linear.issueCreated` |
|
||||
| Issue status changed | `linear_status` | `linear.statusChanged` |
|
||||
| End of cycle | `linear_cycle` | `linear.endOfCycle` |
|
||||
|
||||
**`pagerduty`** — Prompt: "Which PagerDuty incident event?"
|
||||
|
||||
| Option label | Option id | Proto JSON |
|
||||
|--------------|-----------|------------|
|
||||
| Incident triggered | `pagerduty_triggered` | `incidentTriggered: {}` |
|
||||
| Incident acknowledged | `pagerduty_ack` | `incidentAcknowledged: {}` |
|
||||
| Incident resolved | `pagerduty_resolved` | `incidentResolved: {}` |
|
||||
| Any incident event | `pagerduty_any` | `incidentAny: {}` |
|
||||
|
||||
Optional `serviceIds`. Proto may include `incidentEscalated` — only if user asks.
|
||||
|
||||
**`sentry`** — Prompt: "Which Sentry issue event?"
|
||||
|
||||
| Option label | Option id | Proto JSON |
|
||||
|--------------|-----------|------------|
|
||||
| Issue created | `sentry_created` | `issueCreated: {}` |
|
||||
| Issue resolved | `sentry_resolved` | `issueResolved: {}` |
|
||||
| Issue assigned | `sentry_assigned` | `issueAssigned: {}` |
|
||||
| Issue archived | `sentry_archived` | `issueArchived: {}` |
|
||||
| Issue unresolved | `sentry_unresolved` | `issueUnresolved: {}` |
|
||||
| Any issue event | `sentry_any` | `issueAny: {}` |
|
||||
|
||||
Optional `projectIds`.
|
||||
|
||||
**`webhook`** — skip specific-event; `webhook: {}`; user gets URL/auth after save.
|
||||
|
||||
---
|
||||
@@ -94,13 +94,15 @@ Before returning canvas code, verify:
|
||||
|
||||
## Introducing the canvas
|
||||
|
||||
When you create a canvas, add a short note in your chat response telling the user you created a canvas they can open beside the chat:
|
||||
Whenever you mention a canvas to the user — one you created, updated, or want them to open — **always** include a markdown link to that `.canvas.tsx` file using its full absolute path (for example, `[billing-review](/Users/<user>/.cursor/projects/<workspace>/canvases/billing-review.canvas.tsx)`). Use a short descriptive label as the link text; do not refer to a canvas by name or path alone without the link.
|
||||
|
||||
When you create a canvas, add a short note in your chat response telling the user they can open it beside the chat, with that link:
|
||||
|
||||
- **First canvas** — if no other `.canvas.tsx` files exist in the workspace's `canvases/` directory, include one sentence explaining what a canvas is.
|
||||
- **Unsolicited canvas** — if the user didn't ask for a canvas, include one sentence explaining why you chose it over plain text.
|
||||
|
||||
Both can apply at once; one or two sentences total is enough. Skip the intro for subsequent canvases.
|
||||
Both can apply at once; one or two sentences total is enough. Skip the intro for subsequent canvases unless you are mentioning that canvas again (still link it).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If a canvas appears blank or missing, the most common cause is that it was not written under `/Users/<user>/.cursor/projects/<workspace>/canvases/` exactly — re-save it to that path. Do not debug this by trying to create the managed directory manually; focus on correcting the file path instead. Users can click the canvas file path in the response to open it, just like any other file path in Cursor. When present, the canvas server writes a `<name>.canvas.status.json` sidecar after each build with `status`, `diagnostics`, or `error` fields you can read; the file is best-effort and may not exist, so don't block on it.
|
||||
If a canvas appears blank or missing, the most common cause is that it was not written under `/Users/<user>/.cursor/projects/<workspace>/canvases/` exactly — re-save it to that path. Do not debug this by trying to create the managed directory manually; focus on correcting the file path instead. Users can click the canvas file path in the response to open it, just like any other file path in Cursor. Every canvas edit returns a `Canvas TypeScript check` line in the tool result reporting the file's current type errors (or "no errors") — treat that as the authoritative diagnostics signal.
|
||||
|
||||
11
skills-cursor/canvas/sdk/callout-tone-icons.d.ts
vendored
Normal file
11
skills-cursor/canvas/sdk/callout-tone-icons.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { JSX } from "react";
|
||||
type CalloutToneIconGlyph = "info" | "warning" | "circles-check" | "exclamation-circle";
|
||||
type CalloutToneForIcon = "info" | "success" | "warning" | "danger" | "neutral";
|
||||
/** Maps `Callout` tone to the same cursor icons used by `@anysphere/ui` toasts. */
|
||||
export declare const calloutToneIconGlyph: Record<Exclude<CalloutToneForIcon, "neutral">, CalloutToneIconGlyph>;
|
||||
export declare function CalloutToneIcon({ tone, color }: {
|
||||
tone: CalloutToneForIcon;
|
||||
color: string;
|
||||
}): JSX.Element;
|
||||
export {};
|
||||
//# sourceMappingURL=callout-tone-icons.d.ts.map
|
||||
52
skills-cursor/canvas/sdk/canvas-tokens.d.ts
vendored
52
skills-cursor/canvas/sdk/canvas-tokens.d.ts
vendored
@@ -19,6 +19,7 @@ export declare const canvasPaletteDark: {
|
||||
readonly strokePrimary: "#E4E4E433";
|
||||
readonly strokeSecondary: "#E4E4E41F";
|
||||
readonly strokeTertiary: "#E4E4E414";
|
||||
readonly strokeFocused: "#E4E4E4";
|
||||
readonly accent: "#599CE7";
|
||||
readonly buttonBackground: "#599CE7";
|
||||
readonly buttonForeground: "#191c22";
|
||||
@@ -50,6 +51,7 @@ export declare const canvasPaletteLight: {
|
||||
readonly strokePrimary: "#14141433";
|
||||
readonly strokeSecondary: "#1414141F";
|
||||
readonly strokeTertiary: "#14141414";
|
||||
readonly strokeFocused: "#3685BF";
|
||||
readonly accent: "#3685BF";
|
||||
readonly buttonBackground: "#3685BF";
|
||||
readonly buttonForeground: "#FCFCFC";
|
||||
@@ -76,6 +78,7 @@ export interface CanvasPalette {
|
||||
readonly strokePrimary: string;
|
||||
readonly strokeSecondary: string;
|
||||
readonly strokeTertiary: string;
|
||||
readonly strokeFocused: string;
|
||||
readonly accent: string;
|
||||
readonly buttonBackground: string;
|
||||
readonly buttonForeground: string;
|
||||
@@ -115,24 +118,45 @@ export declare const chartPalette: {
|
||||
};
|
||||
/**
|
||||
* Shared category palette for canvas primitives that show categorical tints
|
||||
* (`Swatch`, `UsageBar` segments, etc.). Uses a coherent subset of
|
||||
* `chartPalette` so a category's color reads consistently across any
|
||||
* primitive that consumes it.
|
||||
* (`Swatch`, `UsageBar` segments, etc.). Hexes mirror the cursor core hues
|
||||
* from `packages/ui/src/tokens/themes/cursor-core/{dark,light}.ts` (via the
|
||||
* `text-{hue}-primary` semantic tokens); `gray` mirrors `text-tertiary`
|
||||
* (`mixTransparent base 54%`).
|
||||
*
|
||||
* The insertion order here is the canonical category order — primitives
|
||||
* that auto-assign colors (e.g. `UsageBar` segments without an explicit
|
||||
* `color`) cycle through these keys in order.
|
||||
*/
|
||||
export declare const categoryPaletteDark: {
|
||||
readonly gray: "#E4E4E48A";
|
||||
readonly purple: "#9386F2";
|
||||
readonly green: "#3FA266";
|
||||
readonly yellow: "#F1B467";
|
||||
readonly pink: "#B48EAD";
|
||||
readonly blue: "#7BAFE9";
|
||||
readonly orange: "#D08770";
|
||||
};
|
||||
export declare const categoryPaletteLight: {
|
||||
readonly gray: "#1414148A";
|
||||
readonly purple: "#7754D9";
|
||||
readonly green: "#1F8A65";
|
||||
readonly yellow: "#C08532";
|
||||
readonly pink: "#B8448B";
|
||||
readonly blue: "#3685BF";
|
||||
readonly orange: "#DB704B";
|
||||
};
|
||||
/** Legacy `colorPalette` name kept for back-compat; per-theme tables are `categoryPalette{Dark,Light}`. React consumers should read `useHostTheme().category` so the color flips with the host theme. */
|
||||
export declare const colorPalette: {
|
||||
readonly gray: "#8888A8E0";
|
||||
readonly purple: "#7B64B8F0";
|
||||
readonly green: "#1F8A65E8";
|
||||
readonly yellow: "#E8C030E0";
|
||||
readonly pink: "#C85898E0";
|
||||
readonly blue: "#2E79B5E0";
|
||||
readonly orange: "#F0A040E0";
|
||||
readonly gray: "#E4E4E48A";
|
||||
readonly purple: "#9386F2";
|
||||
readonly green: "#3FA266";
|
||||
readonly yellow: "#F1B467";
|
||||
readonly pink: "#B48EAD";
|
||||
readonly blue: "#7BAFE9";
|
||||
readonly orange: "#D08770";
|
||||
};
|
||||
export type Color = keyof typeof colorPalette;
|
||||
export type CategoryPalette = Readonly<Record<Color, string>>;
|
||||
/**
|
||||
* Auto-color rotation for `UsageBar` segments without an explicit `color`.
|
||||
* Decoupled from `colorPalette`'s declaration order so the palette can grow
|
||||
@@ -147,7 +171,7 @@ export declare const usageColorSequence: readonly Color[];
|
||||
* distinct hue families for maximum perceptual separation.
|
||||
*/
|
||||
export declare const chartColorSequence: readonly ["#1F8A65E8", "#70B0D8E0", "#5A6CC0F0", "#F0A040E0", "#C06028E0", "#E8C030E0", "#C85898E0", "#F0A088E0", "#7B64B8F0", "#7DCAB0E0", "#8888A8E0", "#2A9A8AE0"];
|
||||
declare function buildTokens(palette: CanvasPalette): {
|
||||
declare function buildTokens(palette: CanvasPalette, category: CategoryPalette): {
|
||||
bg: {
|
||||
editor: string;
|
||||
chrome: string;
|
||||
@@ -165,6 +189,7 @@ declare function buildTokens(palette: CanvasPalette): {
|
||||
primary: string;
|
||||
secondary: string;
|
||||
tertiary: string;
|
||||
focused: string;
|
||||
};
|
||||
fill: {
|
||||
primary: string;
|
||||
@@ -183,6 +208,7 @@ declare function buildTokens(palette: CanvasPalette): {
|
||||
stripAdded: string;
|
||||
stripRemoved: string;
|
||||
};
|
||||
category: Readonly<Record<"blue" | "gray" | "green" | "orange" | "pink" | "purple" | "yellow", string>>;
|
||||
};
|
||||
/** Semantic colors for components (spacing and radius live in `theme.ts`). */
|
||||
export declare const canvasTokens: {
|
||||
@@ -203,6 +229,7 @@ export declare const canvasTokens: {
|
||||
primary: string;
|
||||
secondary: string;
|
||||
tertiary: string;
|
||||
focused: string;
|
||||
};
|
||||
fill: {
|
||||
primary: string;
|
||||
@@ -221,6 +248,7 @@ export declare const canvasTokens: {
|
||||
stripAdded: string;
|
||||
stripRemoved: string;
|
||||
};
|
||||
category: Readonly<Record<"blue" | "gray" | "green" | "orange" | "pink" | "purple" | "yellow", string>>;
|
||||
};
|
||||
export declare const canvasTokensLight: {
|
||||
bg: {
|
||||
@@ -240,6 +268,7 @@ export declare const canvasTokensLight: {
|
||||
primary: string;
|
||||
secondary: string;
|
||||
tertiary: string;
|
||||
focused: string;
|
||||
};
|
||||
fill: {
|
||||
primary: string;
|
||||
@@ -258,6 +287,7 @@ export declare const canvasTokensLight: {
|
||||
stripAdded: string;
|
||||
stripRemoved: string;
|
||||
};
|
||||
category: Readonly<Record<"blue" | "gray" | "green" | "orange" | "pink" | "purple" | "yellow", string>>;
|
||||
};
|
||||
export type CanvasTokens = ReturnType<typeof buildTokens>;
|
||||
export {};
|
||||
|
||||
86
skills-cursor/canvas/sdk/chart-primitives.d.ts
vendored
86
skills-cursor/canvas/sdk/chart-primitives.d.ts
vendored
@@ -32,7 +32,41 @@ export type ChartSeries = {
|
||||
data: number[];
|
||||
tone?: ChartTone;
|
||||
};
|
||||
export type BarChartProps = {
|
||||
/**
|
||||
* A dashed marker line drawn across the plot at a fixed value — for targets,
|
||||
* SLOs, budgets, means, or limits. Drawn horizontally on line / vertical-bar
|
||||
* charts and vertically on `horizontal` bar charts; either way it marks the
|
||||
* value axis and is folded into the auto domain so it stays on-canvas.
|
||||
*/
|
||||
export type ChartReferenceLine = {
|
||||
/** Position on the value axis, in the same units as the series data. */
|
||||
value: number;
|
||||
/** Short label drawn in a chip at the line's end. */
|
||||
label?: string;
|
||||
/** Line color. Omit for a muted neutral; set to match other tonal elements. */
|
||||
tone?: ChartTone;
|
||||
};
|
||||
/**
|
||||
* Shared value-axis controls (the y-axis, or the x-axis on `horizontal` bar
|
||||
* charts). By default the axis starts at zero; override to zoom into a tight
|
||||
* range. On stacked / normalized bars these are ignored — those always start
|
||||
* at zero.
|
||||
*/
|
||||
type ValueAxisProps = {
|
||||
/**
|
||||
* Start the value axis at zero. Defaults to `true`. Set `false` to
|
||||
* auto-fit the axis to the data range — useful for tightly-clustered
|
||||
* series (e.g. uptime 99.0–99.9%) that a zero baseline would flatten.
|
||||
*/
|
||||
beginAtZero?: boolean;
|
||||
/** Explicit axis minimum. Overrides `beginAtZero`. */
|
||||
yMin?: number;
|
||||
/** Explicit axis maximum. */
|
||||
yMax?: number;
|
||||
/** Horizontal marker lines for targets / thresholds / means. */
|
||||
referenceLines?: ChartReferenceLine[];
|
||||
};
|
||||
export type BarChartProps = ValueAxisProps & {
|
||||
/** Category labels along the independent axis. */
|
||||
categories: string[];
|
||||
/** One or more data series. Values align by index with `categories`. */
|
||||
@@ -44,24 +78,42 @@ export type BarChartProps = {
|
||||
horizontal?: boolean;
|
||||
/** Show as 100% stacked (implies `stacked`). */
|
||||
normalized?: boolean;
|
||||
/** Suffix for y-axis tick labels (e.g. "%"). */
|
||||
/** Suffix for value labels (e.g. "%", " ms"). */
|
||||
valueSuffix?: string;
|
||||
/** Prefix for value labels (e.g. "$"). Ignored in `normalized` mode. */
|
||||
valuePrefix?: string;
|
||||
/**
|
||||
* Print each bar's value as a label. Defaults to auto: on for a single
|
||||
* series with ≤8 categories, off otherwise. Set `true` to force labels on
|
||||
* (e.g. grouped multi-series), or `false` to force them off. No effect on
|
||||
* `stacked` / `normalized` charts — use the hover tooltip there.
|
||||
*/
|
||||
showValues?: boolean;
|
||||
style?: CSSProperties;
|
||||
};
|
||||
export type LineChartProps = {
|
||||
export type LineChartProps = ValueAxisProps & {
|
||||
categories: string[];
|
||||
series: ChartSeries[];
|
||||
height?: number;
|
||||
/** Fill the area under each line with a soft tint. */
|
||||
fill?: boolean;
|
||||
/** Suffix for value labels (e.g. "%", " ms"). */
|
||||
valueSuffix?: string;
|
||||
/** Prefix for value labels (e.g. "$"). */
|
||||
valuePrefix?: string;
|
||||
/** Print the value next to every data point (≤20 categories). */
|
||||
showValues?: boolean;
|
||||
/** Draw a vertical guide through the cursor while hovering. Defaults to `true`. */
|
||||
showHoverGuide?: boolean;
|
||||
style?: CSSProperties;
|
||||
};
|
||||
export type PieChartProps = {
|
||||
data: Array<ChartDataPoint & {
|
||||
tone?: ChartTone;
|
||||
}>;
|
||||
/** Diameter in px. Defaults to 200. */
|
||||
size?: number;
|
||||
/** Render as a donut with the summed total shown in the hollow center. */
|
||||
donut?: boolean;
|
||||
style?: CSSProperties;
|
||||
};
|
||||
@@ -112,16 +164,25 @@ export type PieChartProps = {
|
||||
* ]}
|
||||
* stacked
|
||||
* />
|
||||
*
|
||||
* // Mark a target with a reference line. Grouped/single bars also accept
|
||||
* // `yMin` / `yMax` to frame the axis (stacked bars stay zero-based).
|
||||
* <BarChart
|
||||
* categories={["Mon", "Tue", "Wed", "Thu", "Fri"]}
|
||||
* series={[{ name: "Latency", data: [180, 210, 240, 200, 220] }]}
|
||||
* valueSuffix=" ms"
|
||||
* referenceLines={[{ value: 200, label: "Budget", tone: "warning" }]}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
export declare function BarChart({ categories, series, height, stacked, horizontal, normalized, valueSuffix, style }: BarChartProps): JSX.Element;
|
||||
export declare function BarChart({ categories, series, height, stacked, horizontal, normalized, valueSuffix, valuePrefix, showValues, beginAtZero, yMin, yMax, referenceLines, style }: BarChartProps): JSX.Element;
|
||||
/**
|
||||
* Multi-series line chart with optional area fill. Distilled from the
|
||||
* portal-website Highcharts analytics charts.
|
||||
*
|
||||
* Each series draws a polyline with dot markers at each data point.
|
||||
* Set `fill` to shade the area under every line. Hover over any category
|
||||
* column to see a tooltip with all series values at that point.
|
||||
* column to see a tooltip with all series values and a vertical cursor guide.
|
||||
*
|
||||
* This is **not** a time-series component — it does not parse dates.
|
||||
* Pass pre-formatted date strings as `categories` if plotting over time.
|
||||
@@ -157,9 +218,19 @@ export declare function BarChart({ categories, series, height, stacked, horizont
|
||||
* { name: "errors", data: [2, 4, 9, 3], tone: "danger" },
|
||||
* ]}
|
||||
* />
|
||||
*
|
||||
* // Zoom into a tight range and mark an SLO. `beginAtZero={false}`
|
||||
* // auto-fits the axis; `referenceLines` draws the target.
|
||||
* <LineChart
|
||||
* categories={["Mon", "Tue", "Wed", "Thu", "Fri"]}
|
||||
* series={[{ name: "Uptime", data: [99.91, 99.95, 99.7, 99.99, 99.96] }]}
|
||||
* valueSuffix="%"
|
||||
* beginAtZero={false}
|
||||
* referenceLines={[{ value: 99.9, label: "SLO", tone: "danger" }]}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
export declare function LineChart({ categories, series, height, fill, valueSuffix, style }: LineChartProps): JSX.Element;
|
||||
export declare function LineChart({ categories, series, height, fill, valueSuffix, valuePrefix, showValues, showHoverGuide, beginAtZero, yMin, yMax, referenceLines, style }: LineChartProps): JSX.Element;
|
||||
/**
|
||||
* Pie (or donut) chart with hover highlighting. Distilled from the
|
||||
* portal-website Highcharts analytics charts.
|
||||
@@ -171,7 +242,7 @@ export declare function LineChart({ categories, series, height, fill, valueSuffi
|
||||
*
|
||||
* Hovering a slice expands it outward and dims the others; hovering a legend
|
||||
* item does the same. A tooltip with value and percentage appears below the
|
||||
* chart. Set `donut` for a hollow center.
|
||||
* chart. Set `donut` for a hollow center that shows the summed total.
|
||||
*
|
||||
* **Do not** use for bar-style comparisons — use `BarChart` instead.
|
||||
*
|
||||
@@ -197,4 +268,5 @@ export declare function LineChart({ categories, series, height, fill, valueSuffi
|
||||
* ```
|
||||
*/
|
||||
export declare function PieChart({ data, size, donut, style }: PieChartProps): JSX.Element;
|
||||
export {};
|
||||
//# sourceMappingURL=chart-primitives.d.ts.map
|
||||
@@ -27,11 +27,13 @@ export type CollapsibleSectionProps = {
|
||||
trailing?: ReactNode;
|
||||
/** Body shown when expanded. */
|
||||
children?: ReactNode;
|
||||
/** When true, the section starts expanded (uncontrolled). */
|
||||
defaultOpen?: boolean;
|
||||
style?: CSSProperties;
|
||||
};
|
||||
/**
|
||||
* Borderless collapsible row with a structured header. Always starts closed
|
||||
* (uncontrolled, no `defaultOpen`).
|
||||
* Borderless collapsible row with a structured header. Starts closed unless
|
||||
* `defaultOpen` is set.
|
||||
*
|
||||
* Compose with `<Swatch>` in the `leading` slot for a colored category icon,
|
||||
* and put a token readout / pill / button in `trailing`. Body content is
|
||||
@@ -61,5 +63,5 @@ export type CollapsibleSectionProps = {
|
||||
* </CollapsibleSection>
|
||||
* ```
|
||||
*/
|
||||
export declare function CollapsibleSection({ title, leading, count, trailing, children, style }: CollapsibleSectionProps): JSX.Element;
|
||||
export declare function CollapsibleSection({ title, leading, count, trailing, children, defaultOpen, style }: CollapsibleSectionProps): JSX.Element;
|
||||
//# sourceMappingURL=collapsible-section.d.ts.map
|
||||
4
skills-cursor/canvas/sdk/hooks.d.ts
vendored
4
skills-cursor/canvas/sdk/hooks.d.ts
vendored
@@ -106,6 +106,10 @@ export type { CanvasAction };
|
||||
* appended after the mention. The canvas file is resolved from the
|
||||
* action route's `canvasId`; do not pass the path from canvas UI.
|
||||
*
|
||||
* **`openFile`** — Open an existing workspace file in the host IDE.
|
||||
* `path` may be workspace-relative or absolute. Optional `selection`
|
||||
* follows VS Code editor line/column fields.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* function AgentLink({ agentId, title }: { agentId: string; title: string }) {
|
||||
|
||||
6
skills-cursor/canvas/sdk/index.d.ts
vendored
6
skills-cursor/canvas/sdk/index.d.ts
vendored
@@ -11,10 +11,10 @@
|
||||
* - Run the pre-delivery self-check before returning code.
|
||||
*/
|
||||
/** Shared category color palette used by `Swatch`, `UsageBar`, etc. */
|
||||
export type { Color } from "./canvas-tokens.js";
|
||||
export { colorPalette, usageColorSequence } from "./canvas-tokens.js";
|
||||
export type { CategoryPalette, Color } from "./canvas-tokens.js";
|
||||
export { categoryPaletteDark, categoryPaletteLight, colorPalette, usageColorSequence, } from "./canvas-tokens.js";
|
||||
/** Charts. */
|
||||
export type { BarChartProps, ChartDataPoint, ChartSeries, ChartTone, LineChartProps, PieChartProps, } from "./chart-primitives.js";
|
||||
export type { BarChartProps, ChartDataPoint, ChartReferenceLine, ChartSeries, ChartTone, LineChartProps, PieChartProps, } from "./chart-primitives.js";
|
||||
export { BarChart, LineChart, PieChart } from "./chart-primitives.js";
|
||||
/** Borderless collapsible disclosure row with a structured header. */
|
||||
export type { CollapsibleSectionProps } from "./collapsible-section.js";
|
||||
|
||||
6
skills-cursor/canvas/sdk/swatch.d.ts
vendored
6
skills-cursor/canvas/sdk/swatch.d.ts
vendored
@@ -3,11 +3,11 @@
|
||||
* list/row decoration (category badges, the leading slot of
|
||||
* `CollapsibleSection`, etc.).
|
||||
*
|
||||
* Pulls colors from the shared `Color` palette so a category's swatch and
|
||||
* its `UsageBar` segment for the same `color` stay visually coherent.
|
||||
* Pulls colors from `useHostTheme().category` so a category's swatch and its
|
||||
* `UsageBar` segment for the same `color` stay visually coherent.
|
||||
*/
|
||||
import type { CSSProperties, JSX } from "react";
|
||||
import { type Color } from "./canvas-tokens.js";
|
||||
import type { Color } from "./canvas-tokens.js";
|
||||
export type SwatchProps = {
|
||||
/** One of the 7 shared category hues. Matches `UsageBar` segment colors. */
|
||||
color: Color;
|
||||
|
||||
25
skills-cursor/canvas/sdk/ui-primitives.d.ts
vendored
25
skills-cursor/canvas/sdk/ui-primitives.d.ts
vendored
@@ -108,7 +108,7 @@ export declare function Divider({ style }: DividerProps): JSX.Element;
|
||||
export declare function Spacer(): JSX.Element;
|
||||
/** Horizontal alignment for a table column. */
|
||||
export type TableColumnAlign = "left" | "center" | "right";
|
||||
/** Semantic tone for a table row — renders a translucent tinted background. */
|
||||
/** Semantic tone for a table row — marker dot in the first column. */
|
||||
export type TableRowTone = "success" | "danger" | "warning" | "info" | "neutral";
|
||||
export type TableProps = {
|
||||
/** Column titles, left to right. Column count is fixed by this array. */
|
||||
@@ -121,9 +121,9 @@ export type TableProps = {
|
||||
/** Optional alignment per column index (headers/rows). Defaults to left. */
|
||||
columnAlign?: Array<TableColumnAlign | undefined>;
|
||||
/**
|
||||
* Optional semantic tone per row index. Applies a translucent tinted
|
||||
* background — use for status highlighting (e.g. failing services, warnings).
|
||||
* Sparse: `undefined` entries are uncolored.
|
||||
* Optional semantic tone per row index. Renders a small colored dot before
|
||||
* the first column's content (no row fill or border). Sparse: `undefined`
|
||||
* entries are unstyled.
|
||||
*/
|
||||
rowTone?: Array<TableRowTone | undefined>;
|
||||
/** When true (default), bordered rounded shell with horizontal scroll if needed. */
|
||||
@@ -451,17 +451,14 @@ export type ButtonProps = {
|
||||
* ```
|
||||
*/
|
||||
export declare function Button({ children, variant, disabled, type, style, onClick }: ButtonProps): JSX.Element;
|
||||
/** @deprecated Pills always render neutral now; tones are ignored. */
|
||||
export type PillTone = "neutral" | "added" | "deleted" | "renamed" | "success" | "warning" | "info";
|
||||
export type PillSize = "sm" | "md";
|
||||
export type PillProps = {
|
||||
children?: ReactNode;
|
||||
/** Whether the pill is in its selected/active state (filled background). */
|
||||
active?: boolean;
|
||||
/**
|
||||
* Semantic tone. Recolors the border and text. When `active` is also
|
||||
* set, fills the background with the tone color at low opacity.
|
||||
* Defaults to `neutral` (current stroke/text tokens).
|
||||
*/
|
||||
/** @deprecated Ignored — pills always render with neutral styling. */
|
||||
tone?: PillTone;
|
||||
/**
|
||||
* Visual size. `"md"` (default) is the standard pill. `"sm"` is a
|
||||
@@ -497,7 +494,7 @@ export type PillProps = {
|
||||
* <Pill onClick={handlePlan} keyboardHint="⇧Tab">Plan new idea</Pill>
|
||||
* ```
|
||||
*/
|
||||
export declare function Pill({ children, active, tone, size, leadingContent, keyboardHint, disabled, title, style, onClick }: PillProps): JSX.Element;
|
||||
export declare function Pill({ children, active, size, leadingContent, keyboardHint, disabled, title, style, onClick }: PillProps): JSX.Element;
|
||||
export type StatTone = "success" | "danger" | "warning" | "info";
|
||||
export type StatProps = {
|
||||
/** The primary metric value (number, percentage, short string). */
|
||||
@@ -526,17 +523,17 @@ export type CalloutTone = "info" | "success" | "warning" | "danger" | "neutral";
|
||||
export type CalloutProps = {
|
||||
/** Body content. Plain strings, `<Text>`, `<Code>`, `<Link>`, or short lists. */
|
||||
children?: ReactNode;
|
||||
/** Semantic tone. Recolors the border, background tint, and title text. */
|
||||
/** Semantic tone. Selects a default leading icon when `icon` is omitted. */
|
||||
tone?: CalloutTone;
|
||||
/** Optional bold title line, shown above the body in the tone color. */
|
||||
/** Optional bold title line, shown above the body. */
|
||||
title?: ReactNode;
|
||||
/** Optional leading icon (emoji, inline SVG, or short text glyph). */
|
||||
icon?: ReactNode;
|
||||
style?: CSSProperties;
|
||||
};
|
||||
/**
|
||||
* Tinted, bordered notice block for warnings, tips, or short status messages
|
||||
* inline within a section.
|
||||
* Inline notice for warnings, tips, or short status messages. Each `tone`
|
||||
* renders a cursor icon matching `@anysphere/ui` toasts (override with `icon`).
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
---
|
||||
name: loop
|
||||
description: >-
|
||||
Run a prompt or skill on a recurring local interval using monitored background
|
||||
shell output. Use for /loop, polling status, recurring fixed-interval tasks,
|
||||
dynamic self-paced loops, local cron-like loops, or waking an agent
|
||||
periodically. Do not use for one-off tasks.
|
||||
Run a prompt or skill in this session on a recurring or variable interval
|
||||
(e.g. /loop 5m /foo).
|
||||
disabled-environments:
|
||||
- cloud
|
||||
---
|
||||
# Loop
|
||||
|
||||
Use monitored shell output when the goal is to wake the agent for recurring local work.
|
||||
|
||||
## Parse
|
||||
|
||||
Accept `/loop [interval] <prompt>`.
|
||||
@@ -23,6 +19,8 @@ Accept `/loop [interval] <prompt>`.
|
||||
|
||||
Use intervals like `30s`, `5m`, `2h`, `1d`. Convert unit words to short units.
|
||||
|
||||
Use monitored shell output to wake the agent for recurring local work.
|
||||
|
||||
## Fixed Schedule
|
||||
|
||||
```bash
|
||||
|
||||
67
skills-cursor/review-bugbot/SKILL.md
Normal file
67
skills-cursor/review-bugbot/SKILL.md
Normal file
@@ -0,0 +1,67 @@
|
||||
---
|
||||
name: review-bugbot
|
||||
description: Review code changes with Bugbot subagent.
|
||||
---
|
||||
# Review Bugbot
|
||||
|
||||
Use this skill when the user asks to run `/review-bugbot`.
|
||||
|
||||
Launch exactly one `bugbot` subagent with:
|
||||
|
||||
- `readonly: true`
|
||||
- `run_in_background: false` unless explicitly asked to run in background
|
||||
- `description: "Bugbot"`
|
||||
- `subagent_type: "bugbot"`
|
||||
|
||||
The review subagent computes the local diff from the repository path, so do not compute the diff yourself before launching it. The repository path should be the active workspace or repository root for the code the user wants reviewed.
|
||||
|
||||
By default, the review subagent infers the repository's actual base branch, such as `main`, when computing `branch changes`. In most cases, do not provide `Base Branch`. Only provide it if you know the current branch or PR should be compared against a specific branch other than the repository's default base branch, such as when you created the current branch from another branch.
|
||||
|
||||
Special case: if the user explicitly asks to review a specific PR or branch, make sure that target is checked out before launching the subagent:
|
||||
- Examples include `github.com/... /review`, `review {link}`, or `review {branch-name}`.
|
||||
- Resolve the provided PR link, PR number, or branch name to the PR head branch or named branch.
|
||||
- Check whether the target branch is already the currently checked out local branch. If it is, continue.
|
||||
- If a different branch is currently checked out, try to switch to the target branch.
|
||||
- If Git refuses to switch because local files would be overwritten, conflicts need resolution, or another checkout blocker occurs, explain the blocker and ask whether the user wants to stash local changes before retrying.
|
||||
- Only stash after the user confirms. If the stash succeeds, retry switching to the target branch.
|
||||
- Launch the review subagent only after the target branch is checked out locally.
|
||||
|
||||
Use this exact prompt shape:
|
||||
|
||||
```text
|
||||
Full Repository Path: <absolute repository path>
|
||||
Diff: <one of: "branch changes", "uncommitted changes", "natural language">
|
||||
Base Branch: <only include this line when reviewing branch changes against a known specific base branch>
|
||||
Change Description: <required only when Diff is "natural language"; list each changed file and what changed in it>
|
||||
Custom Instructions: <only include this line when the user gave specific review instructions>
|
||||
```
|
||||
|
||||
Default to `branch changes`, which reviews branch changes against the merge-base with the default/base branch, including committed, staged, and unstaged changes. If the user asks to review only uncommitted, local working tree, dirty, or not-yet-committed changes, use `uncommitted changes`.
|
||||
|
||||
If the review subagent fails before producing findings, inspect the failure text.
|
||||
|
||||
- If the failure is caused by calling the subagent incorrectly, such as a missing `Full Repository Path`, missing `Diff`, wrong prompt shape, or wrong subagent type, correct the invocation and retry it once immediately.
|
||||
- If the subagent reports it could not compute the diff (for example an empty diff, missing diff metadata, or that it could not compute the diff), retry once with `Diff: natural language`, omitting `Base Branch` and providing a `Change Description`. The subagent will read those files directly. Only use this as a last resort, after the regular diff-based review has failed because the diff could not be computed.
|
||||
|
||||
Write the `Change Description` as one block per changed file: a `<path> (added|modified|deleted|renamed)` header followed by bullet points of what changed. Mention line numbers or ranges inline where they help and you know them (for example `(L40-58)` or `around L120`); they are optional, not required on every bullet. Example:
|
||||
|
||||
```text
|
||||
src/auth/login.ts (modified):
|
||||
- rewrote validateSession (L40-58) to check token expiry before the DB lookup
|
||||
- removed the fallback that accepted empty tokens
|
||||
|
||||
src/auth/legacy.ts (deleted)
|
||||
|
||||
src/auth/mfa.ts (added):
|
||||
- new verifyMfaCode() (L1-30) that calls the TOTP service and rate-limits attempts
|
||||
```
|
||||
- For any other subagent failure, retry once with the same prompt shape.
|
||||
- If the same failure persists after the retry, stop. Briefly tell the user that the review subagent could not complete and include the short error or blocker. Do not keep retrying.
|
||||
|
||||
After the subagent finishes, summarize the result:
|
||||
|
||||
- If it reports that no diff was found or the diff is empty, tell the user in one sentence that there was no diff to review.
|
||||
- If it found no issues, give a one-line status such as "Bugbot found 2 findings / Bugbot found no bugs".
|
||||
- If it found issues, print a compact markdown table with one row per finding, sorted by severity (highest first), using exactly these columns: Severity, Location (file:line), Finding. Put the file and line in the location column as `file:line`.
|
||||
|
||||
Do not fix findings or rerun review unless the user explicitly asks for that next step.
|
||||
52
skills-cursor/review-security/SKILL.md
Normal file
52
skills-cursor/review-security/SKILL.md
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
name: review-security
|
||||
description: Review code changes with Security Review subagent.
|
||||
---
|
||||
# Review Security
|
||||
|
||||
Use this skill when the user asks to run `/review-security`.
|
||||
|
||||
Launch exactly one `security-review` subagent with:
|
||||
|
||||
- `readonly: true`
|
||||
- `run_in_background: false` unless explicitly asked to run in background
|
||||
- `description: "Security Review"`
|
||||
- `subagent_type: "security-review"`
|
||||
|
||||
The review subagent computes the local diff from the repository path, so do not compute the diff yourself before launching it. The repository path should be the active workspace or repository root for the code the user wants reviewed.
|
||||
|
||||
By default, the review subagent infers the repository's actual base branch, such as `main`, when computing `branch changes`. In most cases, do not provide `Base Branch`. Only provide it if you know the current branch or PR should be compared against a specific branch other than the repository's default base branch, such as when you created the current branch from another branch.
|
||||
|
||||
Special case: if the user explicitly asks to review a specific PR or branch, make sure that target is checked out before launching the subagent:
|
||||
- Examples include `github.com/... /review`, `review {link}`, or `review {branch-name}`.
|
||||
- Resolve the provided PR link, PR number, or branch name to the PR head branch or named branch.
|
||||
- Check whether the target branch is already the currently checked out local branch. If it is, continue.
|
||||
- If a different branch is currently checked out, try to switch to the target branch.
|
||||
- If Git refuses to switch because local files would be overwritten, conflicts need resolution, or another checkout blocker occurs, explain the blocker and ask whether the user wants to stash local changes before retrying.
|
||||
- Only stash after the user confirms. If the stash succeeds, retry switching to the target branch.
|
||||
- Launch the review subagent only after the target branch is checked out locally.
|
||||
|
||||
Use this exact prompt shape:
|
||||
|
||||
```text
|
||||
Full Repository Path: <absolute repository path>
|
||||
Diff: <one of: "branch changes", "uncommitted changes">
|
||||
Base Branch: <only include this line when reviewing branch changes against a known specific base branch>
|
||||
Custom Instructions: <only include this line when the user gave specific review instructions>
|
||||
```
|
||||
|
||||
Default to `branch changes`, which reviews branch changes against the merge-base with the default/base branch, including committed, staged, and unstaged changes. If the user asks to review only uncommitted, local working tree, dirty, or not-yet-committed changes, use `uncommitted changes`.
|
||||
|
||||
If the review subagent fails before producing findings, inspect the failure text.
|
||||
|
||||
- If the failure is caused by calling the subagent incorrectly, such as a missing `Full Repository Path`, missing `Diff`, wrong prompt shape, or wrong subagent type, correct the invocation and retry it once immediately.
|
||||
- For any other subagent failure, retry once with the same prompt shape.
|
||||
- If the same failure persists after the retry, stop. Briefly tell the user that the review subagent could not complete and include the short error or blocker. Do not keep retrying.
|
||||
|
||||
After the subagent finishes, summarize the result:
|
||||
|
||||
- If it reports that no diff was found or the diff is empty, tell the user in one sentence that there was no diff to review.
|
||||
- If it found no issues, give a one-line status such as "Security review found 2 findings / Security review found no issues".
|
||||
- If it found issues, print a compact markdown table with one row per finding, sorted by severity (highest first), using exactly these columns: Severity, Location (file:line), Finding. Put the file and line in the location column as `file:line`.
|
||||
|
||||
Do not fix findings or rerun review unless the user explicitly asks for that next step.
|
||||
16
skills-cursor/review/SKILL.md
Normal file
16
skills-cursor/review/SKILL.md
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
name: review
|
||||
description: Review code changes with the Bugbot or Security Review subagent.
|
||||
disable-model-invocation: true
|
||||
---
|
||||
# Review
|
||||
|
||||
Ask the user which review to run with the AskQuestion tool. If the AskQuestion tool is not available, ask the user directly. Provide exactly one single-select question with two options:
|
||||
|
||||
- `bugbot`: Bugbot (`/review-bugbot`)
|
||||
- `security`: Security Review (`/review-security`)
|
||||
|
||||
After the user chooses, run the matching review once:
|
||||
|
||||
- Bugbot: follow the `/review-bugbot` instructions.
|
||||
- Security Review: follow the `/review-security` instructions.
|
||||
@@ -40,7 +40,7 @@ Tool permission rules. Each entry is a string pattern.
|
||||
- `showStatusIndicators`: boolean (default: false) — show status indicators in the UI
|
||||
|
||||
### `channel` (optional)
|
||||
Release channel: `"prod"` | `"staging"` | `"lab"` | `"static"`
|
||||
Release channel: `"prod"` | `"lab"` | `"static"`
|
||||
|
||||
### `maxMode` (optional)
|
||||
boolean (default: false) — enable max mode for higher-quality model responses
|
||||
@@ -48,7 +48,7 @@ boolean (default: false) — enable max mode for higher-quality model responses
|
||||
### `approvalMode` (optional)
|
||||
Controls tool approval behavior:
|
||||
- `"allowlist"` (default) — require approval for tools not in the allow list
|
||||
- `"unrestricted"` — auto-approve all tool calls (yolo mode)
|
||||
- Run Everything — auto-approve all tool calls (same as `--force` / `--yolo`; set approval mode to the non-allowlist value)
|
||||
|
||||
### `sandbox` (optional)
|
||||
Sandbox execution environment settings:
|
||||
|
||||
Reference in New Issue
Block a user