@cursor/july 0.1.15 → 0.1.17
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 +9 -4
- package/dist/bin/agent-serve.js +60 -2
- package/dist/channels/slack/api.d.ts.map +1 -1
- package/dist/channels/slack/api.js +13 -3
- package/dist/channels/slack/auth.d.ts +7 -1
- package/dist/channels/slack/auth.d.ts.map +1 -1
- package/dist/channels/slack/auth.js +14 -0
- package/dist/channels/slack/blocks.d.ts +61 -0
- package/dist/channels/slack/blocks.d.ts.map +1 -0
- package/dist/channels/slack/blocks.js +90 -0
- package/dist/channels/slack/defaults.d.ts +2 -0
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +29 -3
- package/dist/channels/slack/dispatch.d.ts +3 -17
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/index.d.ts +1 -0
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +1 -0
- package/dist/channels/slack/interactive.d.ts +39 -3
- package/dist/channels/slack/interactive.d.ts.map +1 -1
- package/dist/channels/slack/interactive.js +152 -7
- package/dist/channels/slack/manifest.d.ts +3 -0
- package/dist/channels/slack/manifest.d.ts.map +1 -1
- package/dist/channels/slack/manifest.js +3 -0
- package/dist/channels/slack/setup.d.ts +4 -1
- package/dist/channels/slack/setup.d.ts.map +1 -1
- package/dist/channels/slack/setup.js +16 -2
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +24 -3
- package/dist/channels/slack/types.d.ts +77 -0
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/connections.d.ts +4 -1
- package/dist/connections.d.ts.map +1 -1
- package/dist/connections.js +4 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +3 -3
- package/dist/docs/assets/{app.DpdGZTLe.js → app.BbEXr2KO.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DCBsrfwP.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.IB-0QqIT.js → VPLocalSearchBox.DBEi4HDp.js} +1 -1
- package/dist/docs/assets/chunks/{theme.-fYBoNtR.js → theme.DGfptcHw.js} +2 -2
- package/dist/docs/assets/{example-agents_index.md.BPXjUtRB.js → example-agents_index.md.D2PEVSXl.js} +2 -2
- package/dist/docs/assets/{example-agents_index.md.BPXjUtRB.lean.js → example-agents_index.md.D2PEVSXl.lean.js} +1 -1
- package/dist/docs/assets/example-agents_security-reviewer.md.BZSNycMf.js +19 -0
- package/dist/docs/assets/{example-agents_security-reviewer.md.CE9v-aKm.lean.js → example-agents_security-reviewer.md.BZSNycMf.lean.js} +1 -1
- package/dist/docs/assets/{guides_mcp-oauth.md.DqmEOQY1.js → guides_mcp-oauth.md.Dd8EgSem.js} +3 -2
- package/dist/docs/assets/{guides_mcp-oauth.md.DqmEOQY1.lean.js → guides_mcp-oauth.md.Dd8EgSem.lean.js} +1 -1
- package/dist/docs/assets/{guides_slack.md.FWale6Ip.js → guides_slack.md.D_xFKlnF.js} +1 -1
- package/dist/docs/assets/{reference_connections.md.CsSr3rDz.js → reference_connections.md.B9Q3TOve.js} +12 -5
- package/dist/docs/assets/{reference_connections.md.CsSr3rDz.lean.js → reference_connections.md.B9Q3TOve.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +3 -3
- package/dist/docs/concepts.html +3 -3
- package/dist/docs/deployment.html +3 -3
- package/dist/docs/evals.html +3 -3
- package/dist/docs/example-agents/approval-buddy.html +3 -3
- package/dist/docs/example-agents/benny.html +3 -3
- package/dist/docs/example-agents/bugbot.html +3 -3
- package/dist/docs/example-agents/codebase-wiki.html +3 -3
- package/dist/docs/example-agents/codeowners-review.html +3 -3
- package/dist/docs/example-agents/concierge.html +3 -3
- package/dist/docs/example-agents/fsd.html +3 -3
- package/dist/docs/example-agents/index.html +5 -5
- package/dist/docs/example-agents/knowledge-base.html +3 -3
- package/dist/docs/example-agents/oncall.html +3 -3
- package/dist/docs/example-agents/security-reviewer.html +14 -14
- package/dist/docs/example-agents/slack-agent.html +3 -3
- package/dist/docs/example-agents/weather-agent.html +3 -3
- package/dist/docs/guides/agent-to-agent.html +3 -3
- package/dist/docs/guides/cloud-runtime.html +3 -3
- package/dist/docs/guides/github.html +3 -3
- package/dist/docs/guides/human-in-the-loop.html +3 -3
- package/dist/docs/guides/mcp-oauth.html +6 -5
- package/dist/docs/guides/slack.html +5 -5
- package/dist/docs/guides/webhooks.html +3 -3
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +3 -3
- package/dist/docs/index.html +3 -3
- package/dist/docs/quickstart.html +3 -3
- package/dist/docs/reference/agent-config.html +3 -3
- package/dist/docs/reference/channels.html +3 -3
- package/dist/docs/reference/cli.html +3 -3
- package/dist/docs/reference/connections.html +14 -7
- package/dist/docs/reference/hooks.html +3 -3
- package/dist/docs/reference/http-api.html +3 -3
- package/dist/docs/reference/instructions.html +3 -3
- package/dist/docs/reference/playground.html +3 -3
- package/dist/docs/reference/project-layout.html +3 -3
- package/dist/docs/reference/prompt.html +3 -3
- package/dist/docs/reference/schedules.html +3 -3
- package/dist/docs/reference/sessions.html +3 -3
- package/dist/docs/reference/skills.html +3 -3
- package/dist/docs/reference/subagents.html +3 -3
- package/dist/docs/reference/tools.html +3 -3
- package/dist/docs/scaffolding-agents.html +3 -3
- package/dist/docs/storage.html +3 -3
- package/dist/docs/troubleshooting.html +3 -3
- package/dist/evals/assertions.d.ts +190 -0
- package/dist/evals/assertions.d.ts.map +1 -0
- package/dist/evals/assertions.js +461 -0
- package/dist/evals/expect.d.ts +95 -0
- package/dist/evals/expect.d.ts.map +1 -0
- package/dist/evals/expect.js +194 -0
- package/dist/evals/judge.d.ts +133 -0
- package/dist/evals/judge.d.ts.map +1 -0
- package/dist/evals/judge.js +228 -0
- package/dist/evals/loaders.d.ts +51 -0
- package/dist/evals/loaders.d.ts.map +1 -0
- package/dist/evals/loaders.js +124 -0
- package/dist/evals/matchers.d.ts +95 -0
- package/dist/evals/matchers.d.ts.map +1 -0
- package/dist/evals/matchers.js +145 -0
- package/dist/evals/reporters.d.ts +70 -0
- package/dist/evals/reporters.d.ts.map +1 -0
- package/dist/evals/reporters.js +221 -0
- package/dist/evals/results.d.ts +103 -0
- package/dist/evals/results.d.ts.map +1 -0
- package/dist/evals/results.js +28 -0
- package/dist/evals/run-facts.d.ts +77 -0
- package/dist/evals/run-facts.d.ts.map +1 -0
- package/dist/evals/run-facts.js +187 -0
- package/dist/evals.d.ts +136 -31
- package/dist/evals.d.ts.map +1 -1
- package/dist/evals.js +76 -12
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/cli-ax.d.ts +27 -0
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +90 -12
- package/dist/internal/cli-mcp.d.ts +8 -0
- package/dist/internal/cli-mcp.d.ts.map +1 -1
- package/dist/internal/cli-mcp.js +98 -0
- package/dist/internal/cli-slack.d.ts +29 -1
- package/dist/internal/cli-slack.d.ts.map +1 -1
- package/dist/internal/cli-slack.js +777 -12
- package/dist/internal/deploy-client.d.ts +7 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +9 -0
- package/dist/internal/discovery.d.ts.map +1 -1
- package/dist/internal/discovery.js +29 -9
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +2 -0
- package/dist/internal/eval-judge-model.d.ts +59 -0
- package/dist/internal/eval-judge-model.d.ts.map +1 -0
- package/dist/internal/eval-judge-model.js +131 -0
- package/dist/internal/eval-run-store.d.ts.map +1 -1
- package/dist/internal/eval-run-store.js +12 -20
- package/dist/internal/eval-runner.d.ts +31 -25
- package/dist/internal/eval-runner.d.ts.map +1 -1
- package/dist/internal/eval-runner.js +332 -128
- package/dist/internal/evals-client.d.ts.map +1 -1
- package/dist/internal/evals-client.js +7 -3
- package/dist/internal/local-env.d.ts +8 -0
- package/dist/internal/local-env.d.ts.map +1 -0
- package/dist/internal/local-env.js +47 -0
- package/dist/internal/playground/static.d.ts +3 -0
- package/dist/internal/playground/static.d.ts.map +1 -1
- package/dist/internal/playground/static.js +3 -0
- package/dist/internal/run-client.d.ts +15 -0
- package/dist/internal/run-client.d.ts.map +1 -1
- package/dist/internal/run-client.js +3 -2
- package/dist/internal/sdk-runner.d.ts +36 -1
- package/dist/internal/sdk-runner.d.ts.map +1 -1
- package/dist/internal/sdk-runner.js +65 -25
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +10 -1
- package/dist/internal/session-engine.d.ts +18 -5
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +72 -19
- package/dist/internal/slack-provision-client.d.ts +130 -0
- package/dist/internal/slack-provision-client.d.ts.map +1 -0
- package/dist/internal/slack-provision-client.js +284 -0
- package/dist/playground/assets/cursor-icons-16-f_W_ogc-.woff2 +0 -0
- package/dist/playground/assets/index-CidizGZv.css +1 -0
- package/dist/playground/assets/index-DNqirsrK.js +85 -0
- package/dist/playground/index.html +2 -2
- package/dist/types.d.ts +70 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +26 -0
- package/docs/example-agents/index.md +1 -1
- package/docs/example-agents/security-reviewer.md +23 -21
- package/docs/guides/mcp-oauth.md +10 -5
- package/docs/guides/slack.md +3 -2
- package/docs/reference/connections.md +28 -18
- package/package.json +20 -2
- package/skills/create-agent/SKILL.md +15 -7
- package/skills/debug/SKILL.md +3 -1
- package/skills/mcp-auth/SKILL.md +1 -1
- package/skills/setup-slack/SKILL.md +173 -11
- package/src/bin/agent-serve.ts +63 -2
- package/src/channels/slack/api.ts +16 -3
- package/src/channels/slack/auth.ts +16 -1
- package/src/channels/slack/blocks.ts +139 -0
- package/src/channels/slack/defaults.ts +32 -4
- package/src/channels/slack/dispatch.ts +3 -18
- package/src/channels/slack/index.ts +1 -0
- package/src/channels/slack/interactive.ts +183 -19
- package/src/channels/slack/manifest.ts +3 -0
- package/src/channels/slack/setup.ts +16 -2
- package/src/channels/slack/slack-channel.ts +37 -6
- package/src/channels/slack/types.ts +89 -0
- package/src/connections.ts +4 -1
- package/src/evals/assertions.ts +704 -0
- package/src/evals/expect.ts +272 -0
- package/src/evals/judge.ts +346 -0
- package/src/evals/loaders.ts +113 -0
- package/src/evals/matchers.ts +246 -0
- package/src/evals/reporters.ts +274 -0
- package/src/evals/results.ts +132 -0
- package/src/evals/run-facts.ts +274 -0
- package/src/evals.ts +249 -42
- package/src/index.ts +2 -0
- package/src/internal/cli-ax.ts +134 -15
- package/src/internal/cli-mcp.ts +118 -5
- package/src/internal/cli-slack.ts +993 -15
- package/src/internal/deploy-client.ts +10 -0
- package/src/internal/discovery.ts +31 -5
- package/src/internal/distribution.ts +2 -0
- package/src/internal/eval-judge-model.ts +148 -0
- package/src/internal/eval-run-store.ts +10 -14
- package/src/internal/eval-runner.ts +466 -215
- package/src/internal/evals-client.ts +14 -2
- package/src/internal/local-env.ts +53 -0
- package/src/internal/playground/static.ts +3 -0
- package/src/internal/run-client.ts +17 -1
- package/src/internal/sdk-runner.ts +103 -22
- package/src/internal/server.ts +10 -0
- package/src/internal/session-engine.ts +89 -21
- package/src/internal/slack-provision-client.ts +438 -0
- package/src/types.ts +92 -4
- package/dist/channels/slack/post-update-delivery.d.ts +0 -85
- package/dist/channels/slack/post-update-delivery.d.ts.map +0 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.D2d8CfFS.js +0 -1
- package/dist/docs/assets/example-agents_security-reviewer.md.CE9v-aKm.js +0 -19
- package/dist/internal/json-dir-store.d.ts +0 -32
- package/dist/internal/json-dir-store.d.ts.map +0 -1
- package/dist/internal/persistence-coordinator.d.ts +0 -127
- package/dist/internal/persistence-coordinator.d.ts.map +0 -1
- package/dist/persistence.d.ts +0 -184
- package/dist/persistence.d.ts.map +0 -1
- package/dist/playground/assets/cursor-icons-16-CQ50JpfO.woff2 +0 -0
- package/dist/playground/assets/index-BVMOoiek.js +0 -86
- package/dist/playground/assets/index-DYmP4b--.css +0 -1
- /package/dist/docs/assets/{guides_slack.md.FWale6Ip.lean.js → guides_slack.md.D_xFKlnF.lean.js} +0 -0
|
@@ -61,7 +61,7 @@ questions, concrete options, the recommended option listed first and labeled
|
|
|
61
61
|
| --- | --- | --- |
|
|
62
62
|
| **Runtime** | `local` (default) · `cloud` | Local = Cursor SDK harness on this machine; server tools, skills, sandbox seeds, and tool approvals all work. Cloud = Cursor cloud agents; needs `cloud.repos`, no server tools/skills/sandbox seeds (instructions are prepended to the first prompt). Recommend local unless the purpose needs a repo checkout on a cloud VM. |
|
|
63
63
|
| **Model** | `grok-4.5` with `effort=high`, `fast=true` (default) · Other model id | Effort and fast are params, not id suffixes: `{ id: "grok-4.5", params: [{ id: "effort", value: "high" }, { id: "fast", value: "true" }] }` — the SDK rejects suffix-style ids. |
|
|
64
|
-
| **Channels** (multi) | playground + HTTP API only (always mounted) · Slack · GitHub webhooks · custom webhook · schedule (cron) | Slack
|
|
64
|
+
| **Channels** (multi) | playground + HTTP API only (always mounted) · Slack · GitHub webhooks · custom webhook · schedule (cron) | Slack has two connections: the Cursor-hosted connection (`cursorAccount: true` — zero Slack admin, recommended default) and a dedicated Socket Mode app (own bot user + one app/token pair per agent; needed for channel watching or approval buttons). When Slack is picked, resolve the connection with the Step 0 gate in `setup-slack/SKILL.md` — either fold its AskQuestion into this round or ask it before channel setup; default to Cursor-hosted when you cannot ask. GitHub verifies `X-Hub-Signature-256` when a secret is set. Discord/Teams packs do not exist yet — offer custom webhook instead. |
|
|
65
65
|
| **MCP connections** (multi) | none · remote server (URL + header auth) · local stdio server · Other | One file per server under `agent/mcp-connections/`; filename = server name; tokens via env vars, never hardcoded. MCP connections serve the model **and** host code (`ctx.host.mcp`, channel `host.mcp`). |
|
|
66
66
|
| **Capabilities** (multi) | server tools · agent tools (scripts) · skills · subagents · hooks · sandbox seed files · tool approvals (HITL) · evals (recommend) | Server tools, skills, sandbox seeds, approvals are local-runtime only. Agent tools (`execution: "agent"`) work on both runtimes. Always recommend at least one smoke eval. |
|
|
67
67
|
|
|
@@ -77,7 +77,7 @@ inventing:
|
|
|
77
77
|
|
|
78
78
|
| Purpose looks like | Proven shape |
|
|
79
79
|
| --- | --- |
|
|
80
|
-
| Slack chat assistant | minimal `slackChannel()`
|
|
80
|
+
| Slack chat assistant | minimal `slackChannel({ cursorAccount: true, agentName: "…" })` with suggested prompts; dedicated Socket Mode app only when the Step 0 gate picked it |
|
|
81
81
|
| PR review with host-prepared evidence | channel `callTool` prep into a trimmed workspace `pr/` tree |
|
|
82
82
|
| GitHub-webhook automation | `githubChannel()` hooks, per-PR debounce, replay fixtures |
|
|
83
83
|
| Domain assistant over live APIs / MCP | server + agent tools, a stdio MCP connection, a skill, a schedule |
|
|
@@ -98,6 +98,7 @@ Defaults that make first cuts good:
|
|
|
98
98
|
multi-line strings).
|
|
99
99
|
- **Env prefix** for Slack tokens = upper-snake slug (`my-agent` →
|
|
100
100
|
`MY_AGENT_SLACK_*`); `agentkit slack init` derives it for you.
|
|
101
|
+
Dedicated-app path only — the Cursor-hosted connection has no tokens.
|
|
101
102
|
- **Host prep beats model wandering:** when the purpose has a deterministic
|
|
102
103
|
setup step (fetch a PR, seed files), do it in the channel handler via
|
|
103
104
|
`callTool` / `workspaceFiles` rather than instructing the model to do it.
|
|
@@ -125,10 +126,14 @@ plan:
|
|
|
125
126
|
with the real tools.
|
|
126
127
|
4. Add the chosen `channels/`, `mcp-connections/`, `skills/`, `subagents/<id>/`
|
|
127
128
|
(needs `description`), `schedules/`, `hooks/`, `sandbox/workspace/`. For
|
|
128
|
-
Slack,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
Slack, follow the connection decided in the interview: Cursor-hosted is a
|
|
130
|
+
short hand-written `agent/channels/slack.ts`
|
|
131
|
+
(`slackChannel({ cursorAccount: true, agentName: "<Name>" })` — no
|
|
132
|
+
tokens, no manifests); for a dedicated Socket Mode app do not hand-write
|
|
133
|
+
the channel — `agentkit slack init --dir ./<slug> --name "<Name>"`
|
|
134
|
+
generates `agent/channels/slack.ts` (with the env prefix) plus manifests
|
|
135
|
+
and `env.example`; customize the generated file (e.g. `suggestedPrompts`)
|
|
136
|
+
afterwards.
|
|
132
137
|
5. `evals/evals.config.ts` — `defineEvalConfig({ maxConcurrency: 20 })`
|
|
133
138
|
(playground runs are memory-only unless you add `persistRuns`)
|
|
134
139
|
(`maxConcurrency` is required; hard-capped at 200 due to model provider
|
|
@@ -186,7 +191,10 @@ Each surface beyond the playground has a human gate — drive the user through
|
|
|
186
191
|
it, verify with doctor commands, and smoke-test before declaring victory.
|
|
187
192
|
|
|
188
193
|
- **Slack** — follow `packages/agent-serve/skills/setup-slack/SKILL.md` end
|
|
189
|
-
to end
|
|
194
|
+
to end, starting from its Step 0 connection gate. Cursor-hosted: sign in
|
|
195
|
+
(`agentkit login` / `CURSOR_API_KEY`) → serve → `@Cursor <AgentName>`
|
|
196
|
+
smoke. Dedicated app: init → human creates apps → doctor → `@mention`
|
|
197
|
+
smoke.
|
|
190
198
|
- **GitHub** — follow `packages/agent-serve/skills/github/SKILL.md`
|
|
191
199
|
(fixtures / replay / forward / `--cursor-events`).
|
|
192
200
|
- **Custom webhook** — `POST /<slug>/v1/channels/<id>/<route>`. Default
|
package/skills/debug/SKILL.md
CHANGED
|
@@ -53,7 +53,9 @@ curl -sN 'localhost:3000/<slug>/v1/session/<id>/stream?startIndex=0' | head -50
|
|
|
53
53
|
| `403` on stream/follow-up | Caller principal ≠ session owner. In dev, create and inspect with the same auth; beyond loopback pass `--bearer-token` and send it. |
|
|
54
54
|
| Works on localhost, 401/blocked through a tunnel or LAN | Default `localDevStrict()` auth only admits direct loopback, **rejects proxy-forwarding headers** (`X-Forwarded-For`, ...), and requires a loopback `Host`. Use `--bearer-token <secret>` (or authored `bearerAuth`) — `--allow-anonymous` only for trusted-network demos (and never with Cursor account MCP connections). |
|
|
55
55
|
| Channel route won't compile: body/query schema type error | `GET` requires a Zod `querySchema`, `POST`/`PUT`/`PATCH` a Zod `bodySchema` — plain JSON Schema objects don't type-check. Use `z.object({})` / `z.unknown()` for open surfaces. Empty POST bodies are coerced to `{}` before validation. |
|
|
56
|
-
| Slack channel prints `channel idle ... missing credentials` | Expected: tokens absent. Multi-agent needs `<PREFIX>_SLACK_BOT_TOKEN` + `<PREFIX>_SLACK_APP_TOKEN` per agent. `agentkit slack doctor --prefix <PREFIX>`. |
|
|
56
|
+
| Slack channel prints `channel idle ... missing credentials` | Expected: tokens absent (dedicated-app path). Multi-agent needs `<PREFIX>_SLACK_BOT_TOKEN` + `<PREFIX>_SLACK_APP_TOKEN` per agent. `agentkit slack doctor --prefix <PREFIX>`. |
|
|
57
|
+
| `serve` fails: `Slack channels using the Cursor account connection ... not signed in to Cursor` | Cursor-hosted Slack (`cursorAccount: true`) needs a signed-in host: `agentkit login` or `CURSOR_API_KEY`. No Slack tokens exist on this path — `slack doctor` doesn't apply. |
|
|
58
|
+
| `@Cursor <name>` in Slack gets Cursor's normal agent, not yours | Agent name mismatch or host not relaying. Names are single-token and matched case-insensitively; confirm the serve log `cursor-slack: relaying Slack for <AgentName>` and that the workspace's Cursor Slack integration is linked to the signed-in account. |
|
|
57
59
|
| Turn fails immediately with an API-key error | Model turns need `CURSOR_API_KEY`; everything structural (validate/info/call/serve bring-up) doesn't. |
|
|
58
60
|
| Server tools / skills / sandbox silently absent | Runtime is `cloud` — those are local-only. `validate` prints exactly this warning; read it. |
|
|
59
61
|
| `validate` clean, `run` works, CI typecheck fails | tsx never typechecked it. See invariant 3 in `framework-map/SKILL.md` (JSON-shaped tool returns; `type` not `interface`). |
|
package/skills/mcp-auth/SKILL.md
CHANGED
|
@@ -22,7 +22,7 @@ Docs: `docs/guides/mcp-oauth.md`, `docs/reference/connections.md`,
|
|
|
22
22
|
|
|
23
23
|
| Need | Use |
|
|
24
24
|
| --- | --- |
|
|
25
|
-
| Connector already in Cursor dashboard (Linear, Notion, …) | `defineConnection({ cursorAccount: true
|
|
25
|
+
| Connector already in Cursor dashboard (Linear, Notion, …) | `defineConnection({ cursorAccount: true })` or `servers: "*"` for every connected server; `servers: […]` to allowlist |
|
|
26
26
|
| Remote URL that speaks OAuth; host must hold tokens | `defineConnection({ url, oauth: true })` + this skill |
|
|
27
27
|
| Static bearer / API key | `headers` / env on a plain `{ url }` connection |
|
|
28
28
|
|
|
@@ -1,16 +1,138 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: agentkit-setup-slack
|
|
3
3
|
description: >-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
Put an agentkit agent in Slack. Covers the required connection decision
|
|
5
|
+
(Cursor-hosted connection vs dedicated Socket Mode Slack app) with an
|
|
6
|
+
AskQuestion gate, then both setup paths end to end — cursorAccount
|
|
7
|
+
sign-in + smoke, or manifests, tokens, doctor, smoke test, and opt-in
|
|
8
|
+
Slack tool approvals (HITL). Read this skill when wiring Slack for an
|
|
9
|
+
agentkit project.
|
|
7
10
|
---
|
|
8
11
|
|
|
9
12
|
# Setup Slack for agentkit
|
|
10
13
|
|
|
11
14
|
Use this skill when a human asks to wire Slack to an agentkit agent.
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
There are **two ways to connect**, and they differ mostly in setup cost:
|
|
17
|
+
|
|
18
|
+
- **Path A — Cursor-hosted connection**
|
|
19
|
+
(`slackChannel({ cursorAccount: true })`): rides the Cursor Slack
|
|
20
|
+
integration already installed in the workspace. No Slack app, no
|
|
21
|
+
manifests, no tokens, no Slack admin. Live in minutes.
|
|
22
|
+
- **Path B — Dedicated Slack app** (Socket Mode): the agent's own bot
|
|
23
|
+
user, created from generated manifests with an `xoxb-…` + `xapp-…`
|
|
24
|
+
token pair. Required for channel watching, approval buttons, or a
|
|
25
|
+
distinct bot handle. When the workspace is enrolled in Cursor's
|
|
26
|
+
**Add to Slack** (feature gate + a workspace-manager consent),
|
|
27
|
+
`agentkit slack create` provisions all of it in one command.
|
|
28
|
+
|
|
29
|
+
**Do not generate manifests or ask for tokens until the decision below
|
|
30
|
+
is made.** Defaulting into Path B buries the user in Slack admin work
|
|
31
|
+
(two app creations, token minting, env wiring) they may not need.
|
|
32
|
+
|
|
33
|
+
## Step 0 — Choose the connection (required gate)
|
|
34
|
+
|
|
35
|
+
Walk the user through the tradeoffs before touching files:
|
|
36
|
+
|
|
37
|
+
| | A: Cursor-hosted | B: Dedicated Slack app |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| Setup | Zero Slack admin — sign the host in (`agentkit login` / `CURSOR_API_KEY`) and serve | Enrolled in Cursor's Add to Slack: one `agentkit slack create` per env (app + install + tokens, signed-in host). Otherwise: a Slack admin creates **two** apps (dev + prod) from manifests, installs them, mints `xoxb-…` + `xapp-…` for each |
|
|
40
|
+
| Prereq | Cursor Slack integration installed in the workspace and linked to the Cursor account | Permission to create Slack apps; token storage/rotation is on you |
|
|
41
|
+
| How users reach it | `@Cursor <AgentName> …`, DMs to @Cursor, replies in claimed threads | Its own bot user: @mention, DM, channel invites |
|
|
42
|
+
| Identity | Posts as the Cursor app under the agent's name + icon | Own app name, avatar, and handle |
|
|
43
|
+
| Channel watching (dispatch without a mention) | Not available | `engagement.channelPosts` allowlist |
|
|
44
|
+
| Tool approvals / Block Kit interactivity | Not available (construction throws) | `toolApprovals: true` Approve/Deny cards |
|
|
45
|
+
| Reply delivery | Status while working, then one final post (no streaming edits) | Streaming replies with postMessage fallback |
|
|
46
|
+
| Multi-agent hosts | Any number of agents, unique `agentName` each, no extra Slack apps | One Slack app + token pair **per agent** |
|
|
47
|
+
|
|
48
|
+
Decision shortcuts — skip the question when the request already decides:
|
|
49
|
+
|
|
50
|
+
- Needs channel watching, Approve/Deny buttons, `onBlockAction`, or its
|
|
51
|
+
own bot user / handle → **Path B**. Say which requirement forced it.
|
|
52
|
+
- Workspace has no Cursor Slack integration and won't install it →
|
|
53
|
+
**Path B**.
|
|
54
|
+
- "Just get it into Slack", a first bring-up, or the user already said
|
|
55
|
+
to use the Cursor Slack integration, with none of the above → **Path A**.
|
|
56
|
+
|
|
57
|
+
### Collect the decision with AskQuestion
|
|
58
|
+
|
|
59
|
+
Otherwise ask — one single-select question via the `AskQuestion` tool,
|
|
60
|
+
recommended option first so one click accepts it:
|
|
61
|
+
|
|
62
|
+
- **Cursor-hosted Slack connection (recommended)** — zero Slack setup;
|
|
63
|
+
sign in and mention `@Cursor <AgentName>`. No channel watching or
|
|
64
|
+
approval buttons.
|
|
65
|
+
- **Dedicated Slack app (Socket Mode)** — own bot user, channel
|
|
66
|
+
watching, approval buttons; needs a Slack admin to create two apps
|
|
67
|
+
and mint tokens.
|
|
68
|
+
|
|
69
|
+
If `AskQuestion` is unavailable in your environment, or the user does
|
|
70
|
+
not answer, **default to Path A (Cursor-hosted)**: state the assumption
|
|
71
|
+
in one line and proceed. It is the reversible choice — a dedicated app
|
|
72
|
+
can be added later as a *second* channel file without losing anything.
|
|
73
|
+
Never mix both in one channel definition: `cursorAccount: true` rejects
|
|
74
|
+
`credentials` / `envPrefix` at construction.
|
|
75
|
+
|
|
76
|
+
## Path A — Cursor-hosted connection
|
|
77
|
+
|
|
78
|
+
Goal: mention `@Cursor <AgentName>` in the linked workspace and get a
|
|
79
|
+
threaded reply. No Slack app, no tokens, no manifests.
|
|
80
|
+
|
|
81
|
+
### A1 — Author the channel (agent)
|
|
82
|
+
|
|
83
|
+
Write `agent/channels/slack.ts` by hand — do **not** run
|
|
84
|
+
`agentkit slack init` (that scaffolds the Path B manifests + env):
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import { slackChannel } from "@cursor/july/channels/slack";
|
|
88
|
+
|
|
89
|
+
export default slackChannel({
|
|
90
|
+
cursorAccount: true,
|
|
91
|
+
agentName: "MyAgent", // single token, no whitespace; prefer PascalCase
|
|
92
|
+
agentIcon: { emoji: ":robot_face:" },
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`agentName` defaults from the mount slug (PascalCase) and must be a
|
|
97
|
+
single token — string literals with spaces fail typecheck; runtime
|
|
98
|
+
values throw at construction/serve. Names must be unique on the host;
|
|
99
|
+
an unmatched `@Cursor <name>` stays with Cursor's normal Slack agent.
|
|
100
|
+
|
|
101
|
+
### A2 — Sign in + serve (agent)
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
agentkit login # or export CURSOR_API_KEY
|
|
105
|
+
agentkit dev .
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Confirm log: `[agentkit] cursor-slack: relaying Slack for <AgentName> …`.
|
|
109
|
+
An unsigned host fails `serve` with a sign-in hint naming the channel.
|
|
110
|
+
|
|
111
|
+
### A3 — Smoke (human)
|
|
112
|
+
|
|
113
|
+
1. In the Slack workspace linked to the Cursor account, post
|
|
114
|
+
`@Cursor MyAgent <question>` (or DM @Cursor)
|
|
115
|
+
2. Confirm a working status while the turn runs, then a threaded reply
|
|
116
|
+
posted under the agent's name and icon
|
|
117
|
+
3. Reply in the thread without re-mentioning — it stays with the agent
|
|
118
|
+
|
|
119
|
+
### Path A limits (enforced at construction)
|
|
120
|
+
|
|
121
|
+
- `credentials` / `envPrefix` → throw (author a second channel file for
|
|
122
|
+
a dedicated app instead)
|
|
123
|
+
- `engagement.channelPosts`, `toolApprovals`, `interactivity`,
|
|
124
|
+
`onBlockAction` → throw (Socket Mode only)
|
|
125
|
+
- `engagement.mentions: false` / `directMessages: false` → throw (the
|
|
126
|
+
relay always delivers those)
|
|
127
|
+
- Streaming is forced off: rotating status while thinking, one final
|
|
128
|
+
reply post
|
|
129
|
+
|
|
130
|
+
When one of these limits becomes a real requirement, keep the
|
|
131
|
+
cursor-account channel and add a Path B channel file beside it.
|
|
132
|
+
|
|
133
|
+
## Path B — Dedicated Slack app (Socket Mode)
|
|
134
|
+
|
|
135
|
+
Goal:
|
|
14
136
|
|
|
15
137
|
- Importable **dev** and **prod** Slack app manifests (Socket Mode on)
|
|
16
138
|
- App-level Token (`xapp-…`, `connections:write`) + Bot token (`xoxb-…`)
|
|
@@ -18,10 +140,40 @@ Use this skill when a human asks to wire Slack to an agentkit agent.
|
|
|
18
140
|
- Thread ↔ session via `continuationToken = channelId:threadTs`
|
|
19
141
|
- One Slack app (token pair) **per agent** when serving multiple demos
|
|
20
142
|
|
|
21
|
-
## Phases
|
|
22
|
-
|
|
23
143
|
Update `.agent-serve/slack/setup-status.json` as you complete phases.
|
|
24
144
|
|
|
145
|
+
### Provisioned variant — `agentkit slack create` (primary when enrolled)
|
|
146
|
+
|
|
147
|
+
When the Slack workspace is enrolled in Cursor's **Add to Slack**
|
|
148
|
+
(the provisioning feature gate plus a workspace-manager consent), one
|
|
149
|
+
command collapses Phases 0–3 — manifest import, app creation, install,
|
|
150
|
+
and token minting:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
agentkit slack create --dir <agent> # dev app (default)
|
|
154
|
+
agentkit slack create --dir <agent> --prod # prod app
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`create` scaffolds `agent/channels/slack.ts` + the `.agent-serve/slack`
|
|
158
|
+
files when missing (never overwriting existing ones), runs the browser
|
|
159
|
+
consent flow when the workspace is not connected yet, provisions +
|
|
160
|
+
installs the app, writes `<PREFIX>_SLACK_BOT_TOKEN` /
|
|
161
|
+
`<PREFIX>_SLACK_APP_TOKEN` into `<dir>/.env.local` (replacing stale
|
|
162
|
+
lines), and finishes with `doctor`. It needs a signed-in host
|
|
163
|
+
(`agentkit login` / `CURSOR_API_KEY`). Pass `--slack-team <id>` when
|
|
164
|
+
several workspaces are connected. If the install lands in
|
|
165
|
+
`pending_admin_approval`, a Slack workspace admin must approve the
|
|
166
|
+
printed link — then re-run `create` to finish and mint the tokens.
|
|
167
|
+
`agentkit slack destroy` deletes the provisioned app (tokens left in
|
|
168
|
+
`.env.local` simply stop working). Skip to Phase 4 when `create`
|
|
169
|
+
succeeds — `dev`/`serve` load the agent's `.env.local` (real env wins).
|
|
170
|
+
Note: re-running `create` rebuilds the app manifest from the command's
|
|
171
|
+
flags, so any customization made outside the CLI resets to it.
|
|
172
|
+
|
|
173
|
+
If the command reports the feature gate is not enabled (the workspace
|
|
174
|
+
is not enrolled), fall back to the manual manifest-import flow below
|
|
175
|
+
(Phases 0–3).
|
|
176
|
+
|
|
25
177
|
### Phase 0 — Generate (agent)
|
|
26
178
|
|
|
27
179
|
```bash
|
|
@@ -92,7 +244,7 @@ Human:
|
|
|
92
244
|
|
|
93
245
|
## Features (defaults ON)
|
|
94
246
|
|
|
95
|
-
- Chat streaming (`chat.startStream` / `appendStream` / `stopStream`) with postMessage fallback
|
|
247
|
+
- Chat streaming (`chat.startStream` / `appendStream` / `stopStream`) with postMessage fallback (Path B; Path A posts one final reply)
|
|
96
248
|
- Thinking / task cards for tool calls
|
|
97
249
|
- `assistant.threads.setStatus` with rotating `loading_messages`
|
|
98
250
|
- Thread title + suggested prompts
|
|
@@ -101,7 +253,7 @@ Human:
|
|
|
101
253
|
|
|
102
254
|
If a Slack API is unavailable (`method_not_found` / `missing_scope`), the pack falls back to postMessage + setStatus.
|
|
103
255
|
|
|
104
|
-
## Engagement: mentions by default, channel watch opt-in
|
|
256
|
+
## Engagement: mentions by default, channel watch opt-in (Path B only)
|
|
105
257
|
|
|
106
258
|
The pack dispatches only on `app_mention` + DMs unless told otherwise —
|
|
107
259
|
summoned, never proactive. To watch channels (dispatch on new posts without
|
|
@@ -128,7 +280,7 @@ bot to each watched channel. Posts mentioning the bot stay on the
|
|
|
128
280
|
thread. `engagement.mentions` / `engagement.directMessages` can be set to
|
|
129
281
|
`false` to turn those surfaces off.
|
|
130
282
|
|
|
131
|
-
## Tool approvals over Slack (opt-in HITL)
|
|
283
|
+
## Tool approvals over Slack (opt-in HITL, Path B only)
|
|
132
284
|
|
|
133
285
|
Tools with `needsApproval` park until a human approves or denies. To route
|
|
134
286
|
that through Slack, set `toolApprovals: true` on `slackChannel` — it posts
|
|
@@ -163,15 +315,25 @@ Requirements and caveats:
|
|
|
163
315
|
|
|
164
316
|
## Notes
|
|
165
317
|
|
|
166
|
-
- Dev and prod are **separate Slack apps** (separate tokens).
|
|
167
|
-
|
|
318
|
+
- Dev and prod are **separate Slack apps** (separate tokens) on Path B.
|
|
319
|
+
Path A has no per-env app split — the host's Cursor account decides
|
|
320
|
+
where it relays.
|
|
321
|
+
- Socket Mode / the Cursor relay are outbound only — no Events HTTP /
|
|
322
|
+
Request URL path on either connection.
|
|
168
323
|
- Do not `await waitForCompletion()` inside Slack dispatch handlers — the pack uses `waitUntil`.
|
|
169
324
|
- Do not share one token pair across multiple agents in the same process.
|
|
170
325
|
|
|
171
326
|
## CLI reference
|
|
172
327
|
|
|
328
|
+
`slack create` / `destroy` / `init` / `manifest` / `doctor` are Path B
|
|
329
|
+
tooling; Path A needs only `login`.
|
|
330
|
+
|
|
173
331
|
```bash
|
|
174
332
|
agentkit slack setup
|
|
333
|
+
agentkit slack create --dir . # provision via Add to Slack (dev app)
|
|
334
|
+
agentkit slack create --dir . --prod # prod app
|
|
335
|
+
agentkit slack create --dir . --slack-team T0123ABCD
|
|
336
|
+
agentkit slack destroy --dir . [--prod] [--slack-team T0123ABCD]
|
|
175
337
|
agentkit slack init --dir . --name "My Agent"
|
|
176
338
|
agentkit slack init --dir . --no-prefix
|
|
177
339
|
agentkit slack init --dir . --channel-posts # + message.channels/groups events
|
package/src/bin/agent-serve.ts
CHANGED
|
@@ -56,6 +56,7 @@ import {
|
|
|
56
56
|
CLI_COMMAND_NAME as CLI,
|
|
57
57
|
packageVersion,
|
|
58
58
|
} from "../internal/distribution.js";
|
|
59
|
+
import { loadAgentLocalEnv } from "../internal/local-env.js";
|
|
59
60
|
import { clearTerminal, stdoutPalette } from "../internal/terminal-style.js";
|
|
60
61
|
import { cmdUpdate, warnIfOutdated } from "../internal/update-check.js";
|
|
61
62
|
import type { AgentProject, AgentServeHandle } from "../types.js";
|
|
@@ -100,7 +101,9 @@ Usage:
|
|
|
100
101
|
${CLI} mcp oauth <connection> [--dir <path>] [--store] [--slug <slug>]
|
|
101
102
|
${CLI} eval [--dir <path>] [evalId...] [--list] [--json]
|
|
102
103
|
[--tag <tag>]... [--verbose] [--timeout-ms <n>]
|
|
103
|
-
[--
|
|
104
|
+
[--strict] [--max-concurrency <n>]
|
|
105
|
+
[--junit <path>] [--artifacts <dir>|--no-artifacts]
|
|
106
|
+
[--skip-report] [--no-stream] [--no-wait]
|
|
104
107
|
[--prod | --url <baseUrl>] [--slug <slug>]
|
|
105
108
|
[--team <id>]
|
|
106
109
|
${CLI} eval status [runId] --prod|--url <baseUrl> [--dir <path>] [--json]
|
|
@@ -223,7 +226,8 @@ Commands:
|
|
|
223
226
|
secrets Manage deployment secrets: set (upsert by name; NAMEs without
|
|
224
227
|
=VALUE are prompted for with hidden input, or read from piped
|
|
225
228
|
stdin), list (names + createdAt; never values), unset.
|
|
226
|
-
slack Slack channel pack:
|
|
229
|
+
slack Slack channel pack: create/destroy/icon (Cursor Add to Slack
|
|
230
|
+
provisioning), init, manifests, doctor (see slack help).
|
|
227
231
|
github GitHub webhook pack: forward live deliveries, events, doctor
|
|
228
232
|
(wraps \`gh webhook forward\`; see github help).
|
|
229
233
|
|
|
@@ -320,6 +324,13 @@ Options:
|
|
|
320
324
|
--tag eval: only run cases with this tag (repeatable).
|
|
321
325
|
--list eval: print discovered cases without running.
|
|
322
326
|
--verbose eval: stream t.log lines and reply snippets.
|
|
327
|
+
--strict eval: a missed soft threshold (SCORED) also exits 1.
|
|
328
|
+
--max-concurrency eval: override evals.config.ts maxConcurrency.
|
|
329
|
+
--junit eval: write JUnit XML here for CI annotations.
|
|
330
|
+
--artifacts eval: run-artifact directory (default a timestamped dir
|
|
331
|
+
under <dir>/.agent-serve/evals/).
|
|
332
|
+
--no-artifacts eval: do not write run artifacts.
|
|
333
|
+
--skip-report eval: ignore reporters from evals.config.ts / eval files.
|
|
323
334
|
--no-stream run/eval: silence live progress on stderr (JSON still prints).
|
|
324
335
|
--json JSON output (init/info/chat/eval/logs/sessions/session/
|
|
325
336
|
github; run defaults to JSON). logs: NDJSON progress/log
|
|
@@ -433,10 +444,14 @@ async function main(argv: string[]): Promise<number> {
|
|
|
433
444
|
"base-url": { type: "string" },
|
|
434
445
|
print: { type: "boolean", default: false },
|
|
435
446
|
store: { type: "boolean", default: false },
|
|
447
|
+
remote: { type: "boolean", default: false },
|
|
436
448
|
transport: { type: "string" },
|
|
437
449
|
prefix: { type: "string" },
|
|
438
450
|
"no-prefix": { type: "boolean", default: false },
|
|
439
451
|
"channel-posts": { type: "boolean", default: false },
|
|
452
|
+
"slack-team": { type: "string" },
|
|
453
|
+
icon: { type: "string" },
|
|
454
|
+
force: { type: "boolean", default: false },
|
|
440
455
|
repo: { type: "string", multiple: true },
|
|
441
456
|
org: { type: "string" },
|
|
442
457
|
"cursor-events": { type: "boolean", default: false },
|
|
@@ -456,6 +471,12 @@ async function main(argv: string[]): Promise<number> {
|
|
|
456
471
|
all: { type: "boolean", default: false },
|
|
457
472
|
"cursor-events-repo": { type: "string", multiple: true },
|
|
458
473
|
"allow-domain": { type: "string", multiple: true },
|
|
474
|
+
strict: { type: "boolean", default: false },
|
|
475
|
+
junit: { type: "string" },
|
|
476
|
+
artifacts: { type: "string" },
|
|
477
|
+
"no-artifacts": { type: "boolean", default: false },
|
|
478
|
+
"skip-report": { type: "boolean", default: false },
|
|
479
|
+
"max-concurrency": { type: "string" },
|
|
459
480
|
},
|
|
460
481
|
});
|
|
461
482
|
const dir = values.dir ?? ".";
|
|
@@ -483,6 +504,13 @@ async function main(argv: string[]): Promise<number> {
|
|
|
483
504
|
prefix: values.prefix,
|
|
484
505
|
noPrefix: values["no-prefix"],
|
|
485
506
|
channelPosts: values["channel-posts"],
|
|
507
|
+
slackTeam: values["slack-team"],
|
|
508
|
+
prod: values.prod,
|
|
509
|
+
team: values.team,
|
|
510
|
+
apiKey: values["api-key"],
|
|
511
|
+
icon: values.icon,
|
|
512
|
+
force: values.force,
|
|
513
|
+
iconSource: positionals[0] === "icon" ? positionals[1] : undefined,
|
|
486
514
|
});
|
|
487
515
|
}
|
|
488
516
|
case "github": {
|
|
@@ -545,6 +573,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
545
573
|
print: values.print,
|
|
546
574
|
json: values.json,
|
|
547
575
|
store: values.store,
|
|
576
|
+
remote: values.remote,
|
|
548
577
|
oauthConnection: mcpSub === "oauth" ? positionals[1] : undefined,
|
|
549
578
|
});
|
|
550
579
|
}
|
|
@@ -754,6 +783,11 @@ async function main(argv: string[]): Promise<number> {
|
|
|
754
783
|
stateRoot: values["state-root"],
|
|
755
784
|
timeoutMs: parseTimeoutMs(values["timeout-ms"]),
|
|
756
785
|
stream: values["no-stream"] ? false : undefined,
|
|
786
|
+
strict: values.strict,
|
|
787
|
+
junit: values.junit,
|
|
788
|
+
artifacts: values["no-artifacts"] ? false : values.artifacts,
|
|
789
|
+
skipReport: values["skip-report"],
|
|
790
|
+
maxConcurrency: parseMaxConcurrency(values["max-concurrency"]),
|
|
757
791
|
})
|
|
758
792
|
);
|
|
759
793
|
}
|
|
@@ -1016,6 +1050,16 @@ async function main(argv: string[]): Promise<number> {
|
|
|
1016
1050
|
}
|
|
1017
1051
|
const dev = command === "dev" || values.dev === true;
|
|
1018
1052
|
const style = stdoutPalette();
|
|
1053
|
+
// Real env wins (loadEnvFile never overrides). Runs inside start()
|
|
1054
|
+
// so dev's Enter-restart picks up tokens written since boot.
|
|
1055
|
+
const loadLocalEnv = (): void => {
|
|
1056
|
+
const loadedEnvFiles = loadAgentLocalEnv(serveDir);
|
|
1057
|
+
if (loadedEnvFiles.length > 0) {
|
|
1058
|
+
process.stdout.write(
|
|
1059
|
+
`${style.dim(`env: loaded ${loadedEnvFiles.join(", ")}`)}\n`
|
|
1060
|
+
);
|
|
1061
|
+
}
|
|
1062
|
+
};
|
|
1019
1063
|
const serveOptions = {
|
|
1020
1064
|
port,
|
|
1021
1065
|
host: values.host,
|
|
@@ -1055,6 +1099,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
1055
1099
|
};
|
|
1056
1100
|
|
|
1057
1101
|
const start = async (): Promise<AgentServeHandle> => {
|
|
1102
|
+
loadLocalEnv();
|
|
1058
1103
|
const next = await serve(serveDir, serveOptions);
|
|
1059
1104
|
printServeBanner(next, bannerOpts);
|
|
1060
1105
|
if (enterToRestart) {
|
|
@@ -1179,6 +1224,11 @@ function axFromOptions(
|
|
|
1179
1224
|
once: partial.once,
|
|
1180
1225
|
rawEvents: partial.rawEvents,
|
|
1181
1226
|
print: partial.print,
|
|
1227
|
+
strict: partial.strict,
|
|
1228
|
+
junit: partial.junit,
|
|
1229
|
+
artifacts: partial.artifacts,
|
|
1230
|
+
skipReport: partial.skipReport,
|
|
1231
|
+
maxConcurrency: partial.maxConcurrency,
|
|
1182
1232
|
};
|
|
1183
1233
|
}
|
|
1184
1234
|
|
|
@@ -1217,6 +1267,17 @@ function parseTimeoutMs(value: string | undefined): number | undefined {
|
|
|
1217
1267
|
return n;
|
|
1218
1268
|
}
|
|
1219
1269
|
|
|
1270
|
+
function parseMaxConcurrency(value: string | undefined): number | undefined {
|
|
1271
|
+
if (value === undefined) {
|
|
1272
|
+
return undefined;
|
|
1273
|
+
}
|
|
1274
|
+
const n = Number.parseInt(value, 10);
|
|
1275
|
+
if (Number.isNaN(n) || n <= 0) {
|
|
1276
|
+
throw new Error(`invalid --max-concurrency: ${value}`);
|
|
1277
|
+
}
|
|
1278
|
+
return n;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1220
1281
|
/**
|
|
1221
1282
|
* Load mounts the same way `serve` does (multi-agent layout by default).
|
|
1222
1283
|
*/
|
|
@@ -350,7 +350,14 @@ export async function postMessage(args: {
|
|
|
350
350
|
base.thread_ts = args.threadTs;
|
|
351
351
|
}
|
|
352
352
|
const hasBlocks = args.blocks !== undefined && args.blocks.length > 0;
|
|
353
|
-
|
|
353
|
+
// User-group mentions (`<!subteam^…>`) and Slack mrkdwn links
|
|
354
|
+
// (`<https://…|label>`) only render correctly via mrkdwn `text`,
|
|
355
|
+
// not `markdown_text`.
|
|
356
|
+
const usePlainText =
|
|
357
|
+
args.plainText === true ||
|
|
358
|
+
hasBlocks ||
|
|
359
|
+
args.text.includes("<!subteam^") ||
|
|
360
|
+
/<https?:\/\/[^|>]+\|/.test(args.text);
|
|
354
361
|
|
|
355
362
|
let response: Record<string, unknown>;
|
|
356
363
|
if (usePlainText) {
|
|
@@ -451,8 +458,14 @@ export async function updateMessage(args: {
|
|
|
451
458
|
channel: args.channel,
|
|
452
459
|
ts: args.ts,
|
|
453
460
|
};
|
|
454
|
-
if (
|
|
455
|
-
|
|
461
|
+
if (
|
|
462
|
+
args.blocks !== undefined ||
|
|
463
|
+
args.plainText === true ||
|
|
464
|
+
args.text.includes("<!subteam^") ||
|
|
465
|
+
/<https?:\/\/[^|>]+\|/.test(args.text)
|
|
466
|
+
) {
|
|
467
|
+
// Blocks / plainText / user-group mentions / mrkdwn links force the
|
|
468
|
+
// legacy text path (same as postMessage).
|
|
456
469
|
return callSlackApiSoft({
|
|
457
470
|
botToken: args.botToken,
|
|
458
471
|
operation: "chat.update",
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { samePrincipal } from "../../internal/auth.js";
|
|
6
6
|
import type { AuthContext } from "../../types.js";
|
|
7
|
-
import type { SlackBinding, SlackMessage } from "./types.js";
|
|
7
|
+
import type { SlackBinding, SlackBlockAction, SlackMessage } from "./types.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Build a thread-scoped principal so any participant in the same Slack
|
|
@@ -88,6 +88,21 @@ export function buildSlackInteractiveApprovalAuth(args: {
|
|
|
88
88
|
return clickerAuth;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Default auth for an `onBlockAction` dispatch: the click's thread-scoped
|
|
93
|
+
* principal with the clicker in attributes, so replies in the same thread
|
|
94
|
+
* continue the session and the clicker is the attributable user.
|
|
95
|
+
*/
|
|
96
|
+
export function blockActionAuth(action: SlackBlockAction): AuthContext {
|
|
97
|
+
return buildSlackAuthContext({
|
|
98
|
+
channelId: action.channelId,
|
|
99
|
+
threadTs: action.threadTs,
|
|
100
|
+
teamId: action.teamId,
|
|
101
|
+
userId: action.userId,
|
|
102
|
+
userName: action.userName,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
91
106
|
export function defaultSlackAuth(
|
|
92
107
|
message: SlackMessage,
|
|
93
108
|
ctx: SlackBinding,
|