@cursor/july 0.1.52 → 0.1.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -0
- package/README.md +4 -2
- package/dist/bin/agent-serve.js +2 -0
- package/dist/channels/slack/init.d.ts +16 -3
- package/dist/channels/slack/init.d.ts.map +1 -1
- package/dist/channels/slack/init.js +92 -18
- package/dist/channels/slack/manifest.d.ts +8 -0
- package/dist/channels/slack/manifest.d.ts.map +1 -1
- package/dist/channels/slack/manifest.js +17 -0
- package/dist/channels/slack/setup.d.ts +26 -1
- package/dist/channels/slack/setup.d.ts.map +1 -1
- package/dist/channels/slack/setup.js +107 -25
- package/dist/docs/404.html +3 -3
- package/dist/docs/ab.html +6 -6
- package/dist/docs/assets/{app.Cbeq6FOy.js → app.DAKcDclS.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.C4uxzYEU.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.Bmb8QjCI.js → VPLocalSearchBox.BNIaCSfG.js} +2 -2
- package/dist/docs/assets/chunks/{theme.BLNMeCRL.js → theme.B47GzJjc.js} +2 -2
- package/dist/docs/assets/{guides_slack.md.D2nTRu9M.js → guides_slack.md.DP4H75WP.js} +8 -6
- package/dist/docs/assets/guides_slack.md.DP4H75WP.lean.js +1 -0
- package/dist/docs/assets/{reference_cli.md.CGKfz_Yj.js → reference_cli.md.-V6J7Cl8.js} +7 -3
- package/dist/docs/assets/{reference_cli.md.CGKfz_Yj.lean.js → reference_cli.md.-V6J7Cl8.lean.js} +1 -1
- package/dist/docs/assets/{style.CK3hwt6q.css → style.kTsvp4pE.css} +1 -1
- package/dist/docs/assets/{troubleshooting.md.C6n3wCr6.js → troubleshooting.md.CuVztCKs.js} +1 -1
- package/dist/docs/building-with-agents.html +6 -6
- package/dist/docs/concepts.html +6 -6
- package/dist/docs/deployment.html +6 -6
- package/dist/docs/evals.html +6 -6
- package/dist/docs/example-agents/approval-buddy.html +6 -6
- package/dist/docs/example-agents/benny.html +6 -6
- package/dist/docs/example-agents/bugbot.html +6 -6
- package/dist/docs/example-agents/codebase-wiki.html +6 -6
- package/dist/docs/example-agents/codeowners-review.html +6 -6
- package/dist/docs/example-agents/concierge.html +6 -6
- package/dist/docs/example-agents/fsd.html +6 -6
- package/dist/docs/example-agents/index.html +6 -6
- package/dist/docs/example-agents/knowledge-base.html +6 -6
- package/dist/docs/example-agents/oncall.html +6 -6
- package/dist/docs/example-agents/security-reviewer.html +6 -6
- package/dist/docs/example-agents/slack-agent.html +6 -6
- package/dist/docs/example-agents/weather-agent.html +6 -6
- package/dist/docs/guides/agent-to-agent.html +6 -6
- package/dist/docs/guides/cloud-runtime.html +6 -6
- package/dist/docs/guides/github.html +6 -6
- package/dist/docs/guides/human-in-the-loop.html +6 -6
- package/dist/docs/guides/mcp-oauth.html +6 -6
- package/dist/docs/guides/opentelemetry.html +6 -6
- package/dist/docs/guides/slack.html +14 -12
- package/dist/docs/guides/webhooks.html +6 -6
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +6 -6
- package/dist/docs/index.html +6 -6
- package/dist/docs/quickstart.html +6 -6
- package/dist/docs/reference/agent-config.html +6 -6
- package/dist/docs/reference/artifacts.html +6 -6
- package/dist/docs/reference/channels.html +6 -6
- package/dist/docs/reference/cli.html +13 -9
- package/dist/docs/reference/connections.html +6 -6
- package/dist/docs/reference/hooks.html +6 -6
- package/dist/docs/reference/http-api.html +6 -6
- package/dist/docs/reference/instructions.html +6 -6
- package/dist/docs/reference/playground.html +5 -5
- package/dist/docs/reference/project-layout.html +6 -6
- package/dist/docs/reference/prompt.html +6 -6
- package/dist/docs/reference/schedules.html +6 -6
- package/dist/docs/reference/sessions.html +6 -6
- package/dist/docs/reference/skills.html +6 -6
- package/dist/docs/reference/subagents.html +6 -6
- package/dist/docs/reference/tools.html +6 -6
- package/dist/docs/scaffolding-agents.html +5 -5
- package/dist/docs/storage.html +6 -6
- package/dist/docs/templates/triage.html +6 -6
- package/dist/docs/troubleshooting.html +6 -6
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +8 -18
- package/dist/internal/cli-slack-manual.d.ts +20 -0
- package/dist/internal/cli-slack-manual.d.ts.map +1 -0
- package/dist/internal/cli-slack-manual.js +106 -0
- package/dist/internal/cli-slack.d.ts +5 -2
- package/dist/internal/cli-slack.d.ts.map +1 -1
- package/dist/internal/cli-slack.js +18 -69
- package/dist/internal/deploy-client.d.ts +7 -10
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +1 -3
- package/dist/internal/deploy-source.d.ts +1 -1
- package/dist/internal/deploy-source.js +1 -1
- package/dist/internal/process-memory-telemetry.d.ts +3 -4
- package/dist/internal/process-memory-telemetry.d.ts.map +1 -1
- package/dist/internal/process-memory-telemetry.js +4 -17
- package/dist/playground/assets/{index-BKMz70wx.js → index-BHAPd9KT.js} +31 -31
- package/dist/playground/assets/index-DpKH0HcT.css +1 -0
- package/dist/playground/index.html +2 -2
- package/docs/guides/slack.md +52 -7
- package/docs/reference/cli.md +29 -6
- package/docs/troubleshooting.md +1 -1
- package/package.json +1 -1
- package/skills/create-agent/SKILL.md +1 -0
- package/skills/setup-slack/SKILL.md +99 -7
- package/src/bin/agent-serve.ts +2 -0
- package/src/channels/slack/init.ts +130 -20
- package/src/channels/slack/manifest.ts +27 -0
- package/src/channels/slack/setup.ts +124 -23
- package/src/internal/cli-deploy.ts +8 -22
- package/src/internal/cli-slack-manual.ts +127 -0
- package/src/internal/cli-slack.ts +18 -70
- package/src/internal/deploy-client.ts +8 -13
- package/src/internal/deploy-source.ts +1 -1
- package/src/internal/process-memory-telemetry.ts +5 -24
- package/dist/docs/assets/chunks/@localSearchIndexroot.TzAgoWLl.js +0 -1
- package/dist/docs/assets/guides_slack.md.D2nTRu9M.lean.js +0 -1
- package/dist/playground/assets/index-BmMrulSc.css +0 -1
- /package/dist/docs/assets/{troubleshooting.md.C6n3wCr6.lean.js → troubleshooting.md.CuVztCKs.lean.js} +0 -0
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
/>
|
|
9
9
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
10
10
|
<title>agent-serve playground</title>
|
|
11
|
-
<script type="module" crossorigin src="./assets/index-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
11
|
+
<script type="module" crossorigin src="./assets/index-BHAPd9KT.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="./assets/index-DpKH0HcT.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="root"></div>
|
package/docs/guides/slack.md
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Slack"
|
|
3
|
-
description: "Put the agent in Slack: Cursor-hosted connection
|
|
3
|
+
description: "Put the agent in Slack: Cursor-hosted connection, a dedicated Socket Mode app via the dashboard wizard, or a manual manifest import."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Slack agents
|
|
7
7
|
|
|
8
8
|
The Slack channel puts your agent in Slack. Two products: the Cursor-hosted
|
|
9
9
|
connection (`cursorAccount: true`), or a dedicated Socket Mode app created
|
|
10
|
-
in the dashboard wizard (`agent-sdk slack create`).
|
|
10
|
+
in the dashboard wizard (`agent-sdk slack create`). To own the Slack app
|
|
11
|
+
yourself, run `agent-sdk slack init --manual` and paste the manifests at
|
|
12
|
+
[api.slack.com](https://api.slack.com/apps). Socket Mode has no
|
|
11
13
|
public Request URL. Replies stream in threads, with tool "thinking" steps,
|
|
12
14
|
suggested prompts, and opt-in approval buttons.
|
|
13
15
|
|
|
@@ -103,8 +105,8 @@ For a dedicated Socket Mode bot, run `agent-sdk slack create`. The CLI
|
|
|
103
105
|
opens the signed-in Cursor dashboard wizard. Slack consent, bot name,
|
|
104
106
|
and admin-approval wait happen there. Tokens are stored as deployment
|
|
105
107
|
secrets and written to `.env.local`. They are never shown. Do not paste
|
|
106
|
-
a manifest at [api.slack.com](https://api.slack.com/apps)
|
|
107
|
-
|
|
108
|
+
a manifest at [api.slack.com](https://api.slack.com/apps) unless you
|
|
109
|
+
are on the [manual setup](#manual-setup) path.
|
|
108
110
|
|
|
109
111
|
Bots that already have tokens in `.env.local` keep working. Skip the
|
|
110
112
|
wizard unless you want a Cursor-managed app.
|
|
@@ -177,6 +179,46 @@ Thinking… status, then a threaded streaming reply, with correlated
|
|
|
177
179
|
server logs (`inbound kind=app_mention`, `session start`,
|
|
178
180
|
`reply delivered via stream|postMessage`).
|
|
179
181
|
|
|
182
|
+
### Manual setup
|
|
183
|
+
|
|
184
|
+
`slack init --manual` is for a Slack app you own at api.slack.com. You
|
|
185
|
+
paste the generated manifests and mint tokens yourself. Use this when
|
|
186
|
+
you want an unmanaged app, or when the dashboard wizard is not an
|
|
187
|
+
option.
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
agent-sdk slack init --manual --dir . --name "My Agent"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
That writes `agent/channels/slack.ts`, importable manifests at
|
|
194
|
+
`.agent-serve/slack/manifest.{dev,prod}.json`, `env.example`, and
|
|
195
|
+
`setup-status.json`. `--no-prefix` uses shared `SLACK_*` variables on
|
|
196
|
+
a single-agent host. `--prefix CUSTOM` overrides the directory-derived
|
|
197
|
+
prefix. `--channel-posts` subscribes the manifests to channel-post
|
|
198
|
+
events.
|
|
199
|
+
|
|
200
|
+
`slack manifest --env both` regenerates the JSON files without
|
|
201
|
+
touching the channel file.
|
|
202
|
+
|
|
203
|
+
#### Create the apps
|
|
204
|
+
|
|
205
|
+
This phase needs someone with permission to create Slack apps.
|
|
206
|
+
|
|
207
|
+
1. Open [api.slack.com/apps](https://api.slack.com/apps) → **Create New
|
|
208
|
+
App** → **From a manifest**.
|
|
209
|
+
2. Paste `manifest.dev.json` and create the dev app.
|
|
210
|
+
3. Repeat with `manifest.prod.json`. Dev and prod are separate Slack
|
|
211
|
+
apps with separate tokens.
|
|
212
|
+
|
|
213
|
+
#### Install and mint tokens
|
|
214
|
+
|
|
215
|
+
For each app: **Install to Workspace** and copy the Bot User OAuth Token
|
|
216
|
+
(`xoxb-…`). Then under **Basic Information → App-Level Tokens** create a
|
|
217
|
+
token with scope `connections:write` and copy it (`xapp-…`).
|
|
218
|
+
|
|
219
|
+
Put the pair in `.env.local` using the names from `env.example`, then
|
|
220
|
+
run `slack doctor` and serve as [above](#wire-the-env-and-verify).
|
|
221
|
+
|
|
180
222
|
## Choose when the agent engages
|
|
181
223
|
|
|
182
224
|
Mentions and DMs are on by default. Watching channels means dispatching
|
|
@@ -203,8 +245,9 @@ export default slackChannel({
|
|
|
203
245
|
|
|
204
246
|
Channel watching needs the `message.channels` / `message.groups` events
|
|
205
247
|
on the Slack app (Socket Mode only; not available with
|
|
206
|
-
`cursorAccount: true`). Pass `--channel-posts` on `slack create
|
|
207
|
-
bot must also be a member of each watched
|
|
248
|
+
`cursorAccount: true`). Pass `--channel-posts` on `slack create` or
|
|
249
|
+
`slack init --manual`. The bot must also be a member of each watched
|
|
250
|
+
channel.
|
|
208
251
|
|
|
209
252
|
Set `includeBotPosts: true` when the posts worth watching come from bots:
|
|
210
253
|
alert feeds, webhook integrations, or other agents posting notes. The
|
|
@@ -274,11 +317,13 @@ Two habits matter most.
|
|
|
274
317
|
The `slack` subcommands cover setup end to end.
|
|
275
318
|
|
|
276
319
|
```bash
|
|
277
|
-
agent-sdk slack setup # two-product chooser
|
|
320
|
+
agent-sdk slack setup # two-product chooser plus manual phases
|
|
278
321
|
agent-sdk slack create --dir . # dashboard wizard (dev app)
|
|
279
322
|
agent-sdk slack create --dir . --prod # prod app
|
|
280
323
|
agent-sdk slack destroy --dir . # delete the provisioned app
|
|
281
324
|
agent-sdk slack icon ./icon.png --dir . # set the provisioned app's icon
|
|
325
|
+
agent-sdk slack init --manual --dir . # manifests to paste at api.slack.com
|
|
326
|
+
agent-sdk slack manifest --env both # regenerate those JSON files
|
|
282
327
|
agent-sdk slack doctor --prefix MY_AGENT # token / connectivity checks
|
|
283
328
|
```
|
|
284
329
|
|
package/docs/reference/cli.md
CHANGED
|
@@ -574,9 +574,10 @@ directory name. Deployment slugs contain lowercase letters, digits, `_`,
|
|
|
574
574
|
or `-`, with a maximum of 64 characters. For a directory with several
|
|
575
575
|
agents, select one with `--slug`, deploy all with `--all`, or choose from
|
|
576
576
|
the TTY prompt. Non-interactive callers must pass `--slug` or `--all`.
|
|
577
|
-
If `--dir` contains no agent project or child agents, `deploy`
|
|
578
|
-
|
|
579
|
-
|
|
577
|
+
If `--dir` contains no agent project or child agents, `deploy` requires
|
|
578
|
+
`--slug` (or a slug derived from the directory name) and an https git
|
|
579
|
+
repository URL (`--repo`, or inferred from `origin` when `--dir` is an
|
|
580
|
+
agent project). `--all` fails when there is no agent project.
|
|
580
581
|
|
|
581
582
|
The command infers `--repo`, `--ref`, and `--path` from the current Git
|
|
582
583
|
checkout when possible. Explicit flags take precedence. `--repo` must
|
|
@@ -777,10 +778,15 @@ agent-sdk slack destroy [--dir <path>] [--prod] [--slack-team <T…>]
|
|
|
777
778
|
[--team <id>] [--json]
|
|
778
779
|
agent-sdk slack icon <https-url-or-file> [--dir <path>] [--prod]
|
|
779
780
|
[--slack-team <T…>] [--team <id>] [--json]
|
|
781
|
+
agent-sdk slack init --manual [--dir <path>] [--name <name>]
|
|
782
|
+
[--prefix <prefix> | --no-prefix] [--channel-posts]
|
|
783
|
+
agent-sdk slack manifest [--dir <path>] [--name <name>]
|
|
784
|
+
[--env dev|prod|both] [--channel-posts] [--print]
|
|
780
785
|
agent-sdk slack doctor [--dir <path>] [--prefix <prefix> | --no-prefix] [--json]
|
|
781
786
|
```
|
|
782
787
|
|
|
783
|
-
`slack setup` prints the two-product chooser
|
|
788
|
+
`slack setup` prints the two-product chooser plus the `--manual` setup
|
|
789
|
+
checklist. It doesn't change files.
|
|
784
790
|
|
|
785
791
|
`slack create` opens the signed-in Cursor dashboard wizard. Finish Slack
|
|
786
792
|
consent and the bot name there. The CLI writes the token pair into
|
|
@@ -800,8 +806,25 @@ stop working.
|
|
|
800
806
|
`slack icon` sets the provisioned app's icon from an https image URL or
|
|
801
807
|
a local png, jpg, or gif file of at most 512KB.
|
|
802
808
|
|
|
803
|
-
`slack init`
|
|
804
|
-
`slack create
|
|
809
|
+
`slack init` without `--manual` exits non-zero and writes no files. Use
|
|
810
|
+
`slack create` for the dashboard wizard. `slack init --manual` writes
|
|
811
|
+
the channel file, development and production manifests, `env.example`,
|
|
812
|
+
and setup status under the project. You paste those manifests at
|
|
813
|
+
api.slack.com. The command refuses to overwrite a target file. If a
|
|
814
|
+
collision occurs, it exits non-zero; files created earlier in the run
|
|
815
|
+
remain. The token prefix defaults to the directory basename normalized
|
|
816
|
+
to uppercase snake case. Explicit `--prefix` values use the same
|
|
817
|
+
normalization. For example, `pr-approver` becomes
|
|
818
|
+
`PR_APPROVER_SLACK_BOT_TOKEN`. `--no-prefix` uses shared
|
|
819
|
+
`SLACK_BOT_TOKEN` and `SLACK_APP_TOKEN`. `--channel-posts` subscribes
|
|
820
|
+
the manifests to channel-post events. The command always prints a JSON
|
|
821
|
+
summary.
|
|
822
|
+
|
|
823
|
+
`slack manifest` regenerates selected manifest files. `--env` defaults
|
|
824
|
+
to `both`, and `--name` defaults to the directory name. `--print` writes
|
|
825
|
+
the manifest JSON to stdout instead of changing files. With the default
|
|
826
|
+
`--env both`, it prints development JSON, a `--- prod ---` separator,
|
|
827
|
+
then production JSON.
|
|
805
828
|
|
|
806
829
|
`slack doctor` checks both tokens, Socket Mode connectivity, and
|
|
807
830
|
Slack's `auth.test`. It exits non-zero when any check fails.
|
package/docs/troubleshooting.md
CHANGED
|
@@ -59,7 +59,7 @@ Match your symptom below. Keep the commands as `agent-sdk`; see
|
|
|
59
59
|
|
|
60
60
|
| What you see | What to do |
|
|
61
61
|
| --- | --- |
|
|
62
|
-
| Logs show `channel idle … missing credentials` | Expected when tokens are missing. Run `agent-sdk slack create --dir <agent>` to provision the app and write the tokens, or set `<PREFIX>_SLACK_BOT_TOKEN` and `<PREFIX>_SLACK_APP_TOKEN` per agent
|
|
62
|
+
| Logs show `channel idle … missing credentials` | Expected when tokens are missing. Run `agent-sdk slack create --dir <agent>` to provision the app and write the tokens, or `agent-sdk slack init --manual --dir <agent>` and paste the manifests at api.slack.com. Then set `<PREFIX>_SLACK_BOT_TOKEN` and `<PREFIX>_SLACK_APP_TOKEN` per agent and run `agent-sdk slack doctor --prefix <PREFIX>`. |
|
|
63
63
|
| `slack create` reports the app needs admin approval | Open Slack's **Request approval** page (the CLI prints the link; the same URL is **Send a reminder** after you submit). Managed install does not file the request. Keep the CLI running, then click **Retry** in the dashboard after an admin approves. |
|
|
64
64
|
| The bot ignores ordinary channel posts | Default engagement is mentions and DMs only. Enable `engagement.channelPosts` with an allowlist, and subscribe the app to `message.channels` / `message.groups`. |
|
|
65
65
|
| Approve / Deny buttons do nothing | Channels that post approval cards need `toolApprovals: true`. Recreate the app with `slack create` if interactivity is off. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cursor/july",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.53",
|
|
4
4
|
"description": "(early alpha) Filesystem-first framework for defining Cursor agents as markdown and TypeScript and serving them over channels with the Cursor SDK.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"repository": {
|
|
@@ -161,6 +161,7 @@ plan:
|
|
|
161
161
|
tokens, no manifests); for a dedicated Socket Mode app do not hand-write
|
|
162
162
|
the channel — `agent-sdk slack create --dir ./<slug> --name "<Name>"`
|
|
163
163
|
opens the dashboard wizard (env prefix from the directory name);
|
|
164
|
+
for a Slack app they own at api.slack.com, `agent-sdk slack init --manual --dir ./<slug> --name "<Name>"`;
|
|
164
165
|
customize `agent/channels/slack.ts` afterwards (e.g. `suggestedPrompts`).
|
|
165
166
|
5. `evals/evals.config.ts` — `defineEvalConfig({ maxConcurrency: 20 })`
|
|
166
167
|
(playground runs are memory-only unless you add `persistRuns`)
|
|
@@ -23,10 +23,11 @@ There are **two ways to connect**:
|
|
|
23
23
|
`.env.local` and as deployment secrets. Required for channel watching,
|
|
24
24
|
approval buttons, or a distinct bot handle.
|
|
25
25
|
|
|
26
|
-
Do not generate manifests or ask anyone to paste tokens
|
|
26
|
+
Do not generate manifests or ask anyone to paste tokens unless they
|
|
27
|
+
asked for a custom Slack app (`slack init --manual`). Defaulting into
|
|
27
28
|
Path B buries the user in Slack admin work they may not need.
|
|
28
29
|
|
|
29
|
-
Existing
|
|
30
|
+
Existing bots that already have `<PREFIX>_SLACK_BOT_TOKEN` and
|
|
30
31
|
`_SLACK_APP_TOKEN` in `.env.local` keep working. Do not force them onto
|
|
31
32
|
the wizard.
|
|
32
33
|
|
|
@@ -51,6 +52,8 @@ Decision shortcuts; skip the question when the request already decides:
|
|
|
51
52
|
own bot user / handle → **Path B**. Say which requirement forced it.
|
|
52
53
|
- Workspace has no Cursor Slack integration and won't install it →
|
|
53
54
|
**Path B**.
|
|
55
|
+
- Asked for a custom Slack app they own at api.slack.com, or to paste a
|
|
56
|
+
manifest → **Path C** (`slack init --manual`).
|
|
54
57
|
- "Just get it into Slack", a first bring-up, or the user already said
|
|
55
58
|
to use the Cursor Slack integration, with none of the above → **Path A**.
|
|
56
59
|
|
|
@@ -160,7 +163,8 @@ install does not file the request. After an admin approves, click
|
|
|
160
163
|
**Retry** in the wizard.
|
|
161
164
|
|
|
162
165
|
`create` scaffolds `agent/channels/slack.ts` when missing. Do not paste
|
|
163
|
-
a manifest at api.slack.com. `slack init`
|
|
166
|
+
a manifest at api.slack.com for this path. `slack init` without
|
|
167
|
+
`--manual` hard-errors; see Path C for a hand-imported app.
|
|
164
168
|
|
|
165
169
|
Existing tokens in `.env.local` keep working. Skip the wizard for those
|
|
166
170
|
agents unless you want a Cursor-managed app.
|
|
@@ -196,6 +200,88 @@ app. It keeps the Slack app id and replaces the manifest and tokens.
|
|
|
196
200
|
`agent-sdk slack destroy` deletes the provisioned app. Tokens left in
|
|
197
201
|
`.env.local` simply stop working.
|
|
198
202
|
|
|
203
|
+
## Path C — Manual Slack app (`slack init --manual`)
|
|
204
|
+
|
|
205
|
+
Use this when the user wants a Slack app they own at api.slack.com, not
|
|
206
|
+
a Cursor-managed app. Not the default. Do not offer it unless they
|
|
207
|
+
asked for a custom/unmanaged app or already have one. Update
|
|
208
|
+
`.agent-serve/slack/setup-status.json` as you complete phases.
|
|
209
|
+
|
|
210
|
+
### Phase 0 — Generate (agent)
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
agent-sdk slack init --manual --dir . --name "My Agent"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Creates:
|
|
217
|
+
|
|
218
|
+
- `agent/channels/slack.ts` with `envPrefix` from the directory name
|
|
219
|
+
- `.agent-serve/slack/manifest.{dev,prod}.json`
|
|
220
|
+
- `.agent-serve/slack/env.example` (`<PREFIX>_SLACK_BOT_TOKEN` / `_APP_TOKEN`)
|
|
221
|
+
- `.agent-serve/slack/setup-status.json`
|
|
222
|
+
|
|
223
|
+
Use `--no-prefix` for the shared `SLACK_BOT_TOKEN` / `SLACK_APP_TOKEN`
|
|
224
|
+
globals (single-agent only). Use `--prefix CUSTOM` to override the
|
|
225
|
+
default prefix. `--channel-posts` subscribes the manifests to
|
|
226
|
+
`message.channels` / `message.groups`.
|
|
227
|
+
|
|
228
|
+
These files omit `settings.managed_app_settings`. Slack accepts that
|
|
229
|
+
block only from a manager app's user token, so it belongs to
|
|
230
|
+
`slack create`, not to a manifest a human pastes in.
|
|
231
|
+
|
|
232
|
+
### Phase 1 — Create apps (human)
|
|
233
|
+
|
|
234
|
+
1. Open https://api.slack.com/apps → **Create New App** → **From a manifest**
|
|
235
|
+
2. Paste `manifest.dev.json` → create the *dev* app
|
|
236
|
+
3. Repeat with `manifest.prod.json` for prod
|
|
237
|
+
|
|
238
|
+
Stop and ask the human to complete this gate.
|
|
239
|
+
|
|
240
|
+
### Phase 2 — Install + tokens (human)
|
|
241
|
+
|
|
242
|
+
For each app:
|
|
243
|
+
|
|
244
|
+
1. **Install to Workspace** — copy Bot User OAuth Token (`xoxb-…`)
|
|
245
|
+
2. **Basic Information → App-Level Tokens** — Create Token with scope
|
|
246
|
+
`connections:write` → copy (`xapp-…`)
|
|
247
|
+
|
|
248
|
+
### Phase 3 — Env (agent)
|
|
249
|
+
|
|
250
|
+
Write into `.env.local` (dev app), using the keys from `env.example`:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
MY_AGENT_SLACK_BOT_TOKEN=xoxb-…
|
|
254
|
+
MY_AGENT_SLACK_APP_TOKEN=xapp-…
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
agent-sdk slack doctor --prefix MY_AGENT
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Stop when `app_token`, `connections_open`, `bot_token`, and `auth_test`
|
|
262
|
+
are green.
|
|
263
|
+
|
|
264
|
+
### Phase 4 — Serve + smoke (agent + human)
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
agent-sdk dev .
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Confirm log: `[agent-sdk/slack] Socket Mode connected`.
|
|
271
|
+
|
|
272
|
+
When tokens are missing the channel logs
|
|
273
|
+
`channel idle reason=missing credentials need=…` and `serve` continues.
|
|
274
|
+
|
|
275
|
+
Human:
|
|
276
|
+
|
|
277
|
+
1. Invite the bot to a channel
|
|
278
|
+
2. `@mention` it (or DM)
|
|
279
|
+
3. Confirm Thinking… / Working… typing and a threaded reply
|
|
280
|
+
4. Server logs should show correlated lines (`event_id`, `session`, `channel`, `thread_ts`):
|
|
281
|
+
- `inbound kind=app_mention …`
|
|
282
|
+
- `session start …`
|
|
283
|
+
- `reply delivered via postMessage|stream …`
|
|
284
|
+
|
|
199
285
|
## Features (defaults ON)
|
|
200
286
|
|
|
201
287
|
- Chat streaming (`chat.startStream` / `appendStream` / `stopStream`) with postMessage fallback (Path B; Path A posts one final reply)
|
|
@@ -226,8 +312,8 @@ export default slackChannel({
|
|
|
226
312
|
});
|
|
227
313
|
```
|
|
228
314
|
|
|
229
|
-
Pass `--channel-posts` on `slack create` so the
|
|
230
|
-
subscribes to `message.channels` / `message.groups`. Invite the bot to
|
|
315
|
+
Pass `--channel-posts` on `slack create` or `slack init --manual` so the
|
|
316
|
+
app subscribes to `message.channels` / `message.groups`. Invite the bot to
|
|
231
317
|
each watched channel. Posts mentioning the bot stay on the
|
|
232
318
|
`app_mention` path; watch sessions reuse the thread-scoped principal with an
|
|
233
319
|
`engagement: "channel_post"` attribute, so a later mention continues the
|
|
@@ -278,8 +364,10 @@ Requirements and caveats:
|
|
|
278
364
|
|
|
279
365
|
## CLI reference
|
|
280
366
|
|
|
281
|
-
Path B tooling is `create` / `destroy` / `icon` / `doctor`. Path
|
|
282
|
-
|
|
367
|
+
Path B tooling is `create` / `destroy` / `icon` / `doctor`. Path C is
|
|
368
|
+
`init --manual` / `manifest` / `doctor`. Path A needs only `login`.
|
|
369
|
+
`slack setup` prints this chooser. `slack init` hard-errors unless
|
|
370
|
+
`--manual`.
|
|
283
371
|
|
|
284
372
|
```bash
|
|
285
373
|
agent-sdk slack setup
|
|
@@ -287,5 +375,9 @@ agent-sdk slack create --dir . # dashboard wizard (dev app)
|
|
|
287
375
|
agent-sdk slack create --dir . --prod # prod app
|
|
288
376
|
agent-sdk slack create --dir . --slack-team T0123ABCD
|
|
289
377
|
agent-sdk slack destroy --dir . [--prod] [--slack-team T0123ABCD]
|
|
378
|
+
agent-sdk slack init --manual --dir . --name "My Agent"
|
|
379
|
+
agent-sdk slack init --manual --dir . --no-prefix
|
|
380
|
+
agent-sdk slack init --manual --dir . --channel-posts
|
|
381
|
+
agent-sdk slack manifest --env both
|
|
290
382
|
agent-sdk slack doctor --prefix MY_AGENT
|
|
291
383
|
```
|
package/src/bin/agent-serve.ts
CHANGED
|
@@ -535,6 +535,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
535
535
|
"slack-team": { type: "string" },
|
|
536
536
|
icon: { type: "string" },
|
|
537
537
|
force: { type: "boolean", default: false },
|
|
538
|
+
manual: { type: "boolean", default: false },
|
|
538
539
|
repo: { type: "string", multiple: true },
|
|
539
540
|
org: { type: "string" },
|
|
540
541
|
"cursor-events": { type: "boolean", default: false },
|
|
@@ -599,6 +600,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
599
600
|
apiKey: values["api-key"],
|
|
600
601
|
icon: values.icon,
|
|
601
602
|
force: values.force,
|
|
603
|
+
manual: values.manual,
|
|
602
604
|
iconSource: positionals[0] === "icon" ? positionals[1] : undefined,
|
|
603
605
|
});
|
|
604
606
|
}
|
|
@@ -1,26 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Scaffold a Slack channel into an agent-serve project.
|
|
3
|
+
*
|
|
4
|
+
* `initSlackChannel` is the create-safe writer: `agent/channels/slack.ts`
|
|
5
|
+
* only. DIY manifests for paste at api.slack.com live in
|
|
6
|
+
* {@link initSlackManual} so `slack create` cannot reach them.
|
|
3
7
|
*/
|
|
4
8
|
|
|
5
9
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
6
10
|
import { basename, join, resolve } from "node:path";
|
|
7
11
|
import { PACKAGE_NAME } from "../../internal/distribution.js";
|
|
8
12
|
import { envPrefixFromName, slackEnvKeys } from "./credentials.js";
|
|
13
|
+
import {
|
|
14
|
+
buildSlackManifestPair,
|
|
15
|
+
slackManifestFileEntries,
|
|
16
|
+
} from "./manifest.js";
|
|
17
|
+
import { initialSlackSetupStatus } from "./setup.js";
|
|
9
18
|
|
|
10
19
|
export interface InitSlackOptions {
|
|
11
20
|
dir: string;
|
|
12
21
|
/** Display name for the Slack app. Defaults to directory basename. */
|
|
13
22
|
name?: string;
|
|
14
|
-
description?: string;
|
|
15
23
|
/**
|
|
16
24
|
* Env prefix for tokens (`MY_AGENT` → `MY_AGENT_SLACK_BOT_TOKEN`). Defaults to
|
|
17
25
|
* the directory basename so multi-agent serve can mount several Slack bots.
|
|
18
26
|
* Pass `""` to use the shared `SLACK_BOT_TOKEN` / `SLACK_APP_TOKEN` globals.
|
|
19
27
|
*/
|
|
20
28
|
envPrefix?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface InitSlackManualOptions extends InitSlackOptions {
|
|
32
|
+
description?: string;
|
|
21
33
|
/**
|
|
22
|
-
* Subscribe the generated
|
|
23
|
-
* for the opt-in channel watch
|
|
34
|
+
* Subscribe the generated manifests to `message.channels` +
|
|
35
|
+
* `message.groups` for the opt-in channel watch
|
|
36
|
+
* (`engagement.channelPosts` on `slackChannel`).
|
|
24
37
|
*/
|
|
25
38
|
channelPosts?: boolean;
|
|
26
39
|
}
|
|
@@ -32,33 +45,61 @@ export interface InitSlackResult {
|
|
|
32
45
|
envKeys: { bot: string; app: string };
|
|
33
46
|
}
|
|
34
47
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
48
|
+
interface SlackInitTarget {
|
|
49
|
+
rootDir: string;
|
|
50
|
+
name: string;
|
|
51
|
+
envPrefix: string | undefined;
|
|
52
|
+
envKeys: { bot: string; app: string };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function resolveSlackInitTarget(options: InitSlackOptions): SlackInitTarget {
|
|
38
56
|
const rootDir = resolve(options.dir);
|
|
39
57
|
const envPrefix =
|
|
40
58
|
options.envPrefix === ""
|
|
41
59
|
? undefined
|
|
42
60
|
: (options.envPrefix ?? envPrefixFromName(basename(rootDir)));
|
|
43
|
-
|
|
44
|
-
|
|
61
|
+
return {
|
|
62
|
+
rootDir,
|
|
63
|
+
name: options.name ?? basename(rootDir),
|
|
64
|
+
envPrefix,
|
|
65
|
+
envKeys: slackEnvKeys(envPrefix),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
45
68
|
|
|
46
|
-
|
|
69
|
+
async function writeExclusive(
|
|
70
|
+
rootDir: string,
|
|
71
|
+
rel: string,
|
|
72
|
+
contents: string
|
|
73
|
+
): Promise<void> {
|
|
74
|
+
const abs = join(rootDir, rel);
|
|
47
75
|
await mkdir(join(abs, ".."), { recursive: true });
|
|
76
|
+
await writeFile(abs, contents, { flag: "wx" });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function slackChannelSource(
|
|
80
|
+
target: SlackInitTarget,
|
|
81
|
+
kind: "create" | "manual"
|
|
82
|
+
): string {
|
|
48
83
|
const envPrefixLine =
|
|
49
|
-
envPrefix === undefined
|
|
84
|
+
target.envPrefix === undefined
|
|
50
85
|
? ""
|
|
51
|
-
: ` envPrefix: ${JSON.stringify(envPrefix)},\n`;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
86
|
+
: ` envPrefix: ${JSON.stringify(target.envPrefix)},\n`;
|
|
87
|
+
const tokenLines =
|
|
88
|
+
kind === "manual"
|
|
89
|
+
? ` * Tokens: ${target.envKeys.bot} + ${target.envKeys.app}\n * (see .agent-serve/slack/env.example).`
|
|
90
|
+
: ` * Tokens: ${target.envKeys.bot} + ${target.envKeys.app}`;
|
|
91
|
+
const setupLine =
|
|
92
|
+
kind === "manual"
|
|
93
|
+
? " * Full setup: agent-serve slack setup"
|
|
94
|
+
: " * Full setup: agent-serve slack create --dir .";
|
|
95
|
+
return `import { slackChannel } from "${PACKAGE_NAME}/channels/slack";
|
|
55
96
|
|
|
56
97
|
/**
|
|
57
98
|
* Slack channel (Socket Mode).
|
|
58
99
|
*
|
|
59
|
-
|
|
100
|
+
${tokenLines}
|
|
60
101
|
*
|
|
61
|
-
|
|
102
|
+
${setupLine}
|
|
62
103
|
*/
|
|
63
104
|
export default slackChannel({
|
|
64
105
|
${envPrefixLine} // Streaming and thinking steps default to true.
|
|
@@ -67,10 +108,79 @@ ${envPrefixLine} // Streaming and thinking steps default to true.
|
|
|
67
108
|
{ title: "Status", message: "What are you working on?" },
|
|
68
109
|
],
|
|
69
110
|
});
|
|
70
|
-
|
|
71
|
-
|
|
111
|
+
`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Create-safe: write `agent/channels/slack.ts` only. */
|
|
115
|
+
export async function initSlackChannel(
|
|
116
|
+
options: InitSlackOptions
|
|
117
|
+
): Promise<InitSlackResult> {
|
|
118
|
+
const target = resolveSlackInitTarget(options);
|
|
119
|
+
await writeExclusive(
|
|
120
|
+
target.rootDir,
|
|
121
|
+
"agent/channels/slack.ts",
|
|
122
|
+
slackChannelSource(target, "create")
|
|
123
|
+
);
|
|
124
|
+
return {
|
|
125
|
+
rootDir: target.rootDir,
|
|
126
|
+
files: ["agent/channels/slack.ts"],
|
|
127
|
+
envPrefix: target.envPrefix,
|
|
128
|
+
envKeys: target.envKeys,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* `slack init --manual`: channel file plus DIY manifests
|
|
134
|
+
* (`managedByCursor: false`), env.example, and setup-status.json.
|
|
135
|
+
*/
|
|
136
|
+
export async function initSlackManual(
|
|
137
|
+
options: InitSlackManualOptions
|
|
138
|
+
): Promise<InitSlackResult> {
|
|
139
|
+
const target = resolveSlackInitTarget(options);
|
|
140
|
+
const files: string[] = [];
|
|
141
|
+
const write = async (rel: string, contents: string): Promise<void> => {
|
|
142
|
+
await writeExclusive(target.rootDir, rel, contents);
|
|
143
|
+
files.push(rel);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
await write("agent/channels/slack.ts", slackChannelSource(target, "manual"));
|
|
147
|
+
|
|
148
|
+
const pair = buildSlackManifestPair({
|
|
149
|
+
name: target.name,
|
|
150
|
+
managedByCursor: false,
|
|
151
|
+
description: options.description,
|
|
152
|
+
channelPosts: options.channelPosts,
|
|
153
|
+
});
|
|
154
|
+
for (const file of slackManifestFileEntries(pair)) {
|
|
155
|
+
await write(`.agent-serve/slack/${file.name}`, file.contents);
|
|
156
|
+
}
|
|
157
|
+
await write(
|
|
158
|
+
".agent-serve/slack/env.example",
|
|
159
|
+
`# Copy to .env.local (or export in your shell). Use the *dev* Slack app
|
|
160
|
+
# for local development; use the Prod app tokens in deployment secrets.
|
|
161
|
+
#
|
|
162
|
+
# Multi-agent serve needs a distinct Slack app (and token pair) per agent.
|
|
163
|
+
|
|
164
|
+
${target.envKeys.bot}=xoxb-...
|
|
165
|
+
${target.envKeys.app}=xapp-...
|
|
166
|
+
`
|
|
167
|
+
);
|
|
168
|
+
await write(
|
|
169
|
+
".agent-serve/slack/setup-status.json",
|
|
170
|
+
`${JSON.stringify(
|
|
171
|
+
initialSlackSetupStatus({
|
|
172
|
+
envPrefix: target.envPrefix,
|
|
173
|
+
envKeys: target.envKeys,
|
|
174
|
+
}),
|
|
175
|
+
null,
|
|
176
|
+
2
|
|
177
|
+
)}\n`
|
|
72
178
|
);
|
|
73
|
-
written.push("agent/channels/slack.ts");
|
|
74
179
|
|
|
75
|
-
return {
|
|
180
|
+
return {
|
|
181
|
+
rootDir: target.rootDir,
|
|
182
|
+
files,
|
|
183
|
+
envPrefix: target.envPrefix,
|
|
184
|
+
envKeys: target.envKeys,
|
|
185
|
+
};
|
|
76
186
|
}
|
|
@@ -212,3 +212,30 @@ export function buildSlackManifestPair(
|
|
|
212
212
|
prod: buildSlackManifest({ ...options, env: "prod" }),
|
|
213
213
|
};
|
|
214
214
|
}
|
|
215
|
+
|
|
216
|
+
/** Relative names under `.agent-serve/slack/`. */
|
|
217
|
+
export function slackManifestFileEntries(
|
|
218
|
+
pair: { dev: SlackAppManifest; prod: SlackAppManifest },
|
|
219
|
+
env: "dev" | "prod" | "both" = "both"
|
|
220
|
+
): ReadonlyArray<{
|
|
221
|
+
name: "manifest.dev.json" | "manifest.prod.json";
|
|
222
|
+
contents: string;
|
|
223
|
+
}> {
|
|
224
|
+
const files: Array<{
|
|
225
|
+
name: "manifest.dev.json" | "manifest.prod.json";
|
|
226
|
+
contents: string;
|
|
227
|
+
}> = [];
|
|
228
|
+
if (env === "dev" || env === "both") {
|
|
229
|
+
files.push({
|
|
230
|
+
name: "manifest.dev.json",
|
|
231
|
+
contents: `${JSON.stringify(pair.dev, null, 2)}\n`,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
if (env === "prod" || env === "both") {
|
|
235
|
+
files.push({
|
|
236
|
+
name: "manifest.prod.json",
|
|
237
|
+
contents: `${JSON.stringify(pair.prod, null, 2)}\n`,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
return files;
|
|
241
|
+
}
|