@cursor/july 0.1.48 → 0.1.51

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.
Files changed (151) hide show
  1. package/AGENTS.md +3 -3
  2. package/README.md +7 -14
  3. package/dist/bin/agent-serve.js +22 -8
  4. package/dist/channels/slack/init.d.ts +2 -3
  5. package/dist/channels/slack/init.d.ts.map +1 -1
  6. package/dist/channels/slack/init.js +8 -43
  7. package/dist/channels/slack/manifest.d.ts +3 -3
  8. package/dist/channels/slack/manifest.js +3 -3
  9. package/dist/channels/slack/setup.d.ts +2 -11
  10. package/dist/channels/slack/setup.d.ts.map +1 -1
  11. package/dist/channels/slack/setup.js +26 -94
  12. package/dist/channels/slack/types.d.ts +3 -4
  13. package/dist/channels/slack/types.d.ts.map +1 -1
  14. package/dist/docs/404.html +2 -2
  15. package/dist/docs/ab.html +5 -5
  16. package/dist/docs/assets/{ab.md.hdxsvX5M.js → ab.md.DYjwREAP.js} +2 -2
  17. package/dist/docs/assets/{ab.md.hdxsvX5M.lean.js → ab.md.DYjwREAP.lean.js} +1 -1
  18. package/dist/docs/assets/{app.BC1P20xI.js → app.C51TX1Bw.js} +1 -1
  19. package/dist/docs/assets/chunks/@localSearchIndexroot.D2DpXdZN.js +1 -0
  20. package/dist/docs/assets/chunks/{VPLocalSearchBox.C_900xn2.js → VPLocalSearchBox.BB9HCJPq.js} +1 -1
  21. package/dist/docs/assets/chunks/{theme.CT135Jhh.js → theme.Dp-0SZcu.js} +2 -2
  22. package/dist/docs/assets/{deployment.md.Cdp4rTE4.js → deployment.md.B8kW-h7P.js} +1 -1
  23. package/dist/docs/assets/{evals.md.qeoGgPw0.js → evals.md.CVe_O75-.js} +3 -3
  24. package/dist/docs/assets/{evals.md.qeoGgPw0.lean.js → evals.md.CVe_O75-.lean.js} +1 -1
  25. package/dist/docs/assets/{example-agents_benny.md.l7JTmm8X.js → example-agents_benny.md.B-LIDGja.js} +1 -1
  26. package/dist/docs/assets/{example-agents_oncall.md.ZE0n6ZFN.js → example-agents_oncall.md.CBmyuAKc.js} +2 -2
  27. package/dist/docs/assets/{guides_human-in-the-loop.md.BWvT7UqY.js → guides_human-in-the-loop.md.Cf8kIIqC.js} +2 -2
  28. package/dist/docs/assets/{guides_human-in-the-loop.md.BWvT7UqY.lean.js → guides_human-in-the-loop.md.Cf8kIIqC.lean.js} +1 -1
  29. package/dist/docs/assets/{guides_slack.md.zriQpU_9.js → guides_slack.md.D2nTRu9M.js} +7 -12
  30. package/dist/docs/assets/guides_slack.md.D2nTRu9M.lean.js +1 -0
  31. package/dist/docs/assets/{reference_cli.md.BDmjPPAm.js → reference_cli.md.CGKfz_Yj.js} +3 -7
  32. package/dist/docs/assets/{reference_cli.md.BDmjPPAm.lean.js → reference_cli.md.CGKfz_Yj.lean.js} +1 -1
  33. package/dist/docs/assets/{reference_http-api.md.DGrw_wOu.js → reference_http-api.md.DMbdFGVQ.js} +1 -1
  34. package/dist/docs/assets/{storage.md.CJYd5YmN.js → storage.md.D8NQ389l.js} +3 -3
  35. package/dist/docs/assets/storage.md.D8NQ389l.lean.js +1 -0
  36. package/dist/docs/assets/{troubleshooting.md.CkgwmVI0.js → troubleshooting.md.C6n3wCr6.js} +1 -1
  37. package/dist/docs/building-with-agents.html +3 -3
  38. package/dist/docs/concepts.html +3 -3
  39. package/dist/docs/deployment.html +5 -5
  40. package/dist/docs/evals.html +6 -6
  41. package/dist/docs/example-agents/approval-buddy.html +3 -3
  42. package/dist/docs/example-agents/benny.html +5 -5
  43. package/dist/docs/example-agents/bugbot.html +3 -3
  44. package/dist/docs/example-agents/codebase-wiki.html +3 -3
  45. package/dist/docs/example-agents/codeowners-review.html +3 -3
  46. package/dist/docs/example-agents/concierge.html +3 -3
  47. package/dist/docs/example-agents/fsd.html +3 -3
  48. package/dist/docs/example-agents/index.html +3 -3
  49. package/dist/docs/example-agents/knowledge-base.html +3 -3
  50. package/dist/docs/example-agents/oncall.html +6 -6
  51. package/dist/docs/example-agents/security-reviewer.html +3 -3
  52. package/dist/docs/example-agents/slack-agent.html +3 -3
  53. package/dist/docs/example-agents/weather-agent.html +3 -3
  54. package/dist/docs/guides/agent-to-agent.html +3 -3
  55. package/dist/docs/guides/cloud-runtime.html +3 -3
  56. package/dist/docs/guides/github.html +3 -3
  57. package/dist/docs/guides/human-in-the-loop.html +5 -5
  58. package/dist/docs/guides/mcp-oauth.html +3 -3
  59. package/dist/docs/guides/opentelemetry.html +3 -3
  60. package/dist/docs/guides/slack.html +11 -16
  61. package/dist/docs/guides/webhooks.html +3 -3
  62. package/dist/docs/hashmap.json +1 -1
  63. package/dist/docs/hillclimbing.html +3 -3
  64. package/dist/docs/index.html +3 -3
  65. package/dist/docs/quickstart.html +3 -3
  66. package/dist/docs/reference/agent-config.html +3 -3
  67. package/dist/docs/reference/artifacts.html +3 -3
  68. package/dist/docs/reference/channels.html +3 -3
  69. package/dist/docs/reference/cli.html +6 -10
  70. package/dist/docs/reference/connections.html +3 -3
  71. package/dist/docs/reference/hooks.html +3 -3
  72. package/dist/docs/reference/http-api.html +5 -5
  73. package/dist/docs/reference/instructions.html +3 -3
  74. package/dist/docs/reference/playground.html +3 -3
  75. package/dist/docs/reference/project-layout.html +3 -3
  76. package/dist/docs/reference/prompt.html +3 -3
  77. package/dist/docs/reference/schedules.html +3 -3
  78. package/dist/docs/reference/sessions.html +3 -3
  79. package/dist/docs/reference/skills.html +3 -3
  80. package/dist/docs/reference/subagents.html +3 -3
  81. package/dist/docs/reference/tools.html +3 -3
  82. package/dist/docs/scaffolding-agents.html +3 -3
  83. package/dist/docs/storage.html +5 -5
  84. package/dist/docs/templates/triage.html +3 -3
  85. package/dist/docs/troubleshooting.html +5 -5
  86. package/dist/internal/cli-ax.js +3 -3
  87. package/dist/internal/cli-cursor.d.ts +18 -0
  88. package/dist/internal/cli-cursor.d.ts.map +1 -1
  89. package/dist/internal/cli-cursor.js +25 -0
  90. package/dist/internal/cli-slack.d.ts +3 -4
  91. package/dist/internal/cli-slack.d.ts.map +1 -1
  92. package/dist/internal/cli-slack.js +126 -325
  93. package/dist/internal/convert-automation/convert-workflow.js +2 -2
  94. package/dist/internal/event-log.d.ts +17 -0
  95. package/dist/internal/event-log.d.ts.map +1 -1
  96. package/dist/internal/event-log.js +32 -2
  97. package/dist/internal/process-memory-telemetry.d.ts +90 -0
  98. package/dist/internal/process-memory-telemetry.d.ts.map +1 -0
  99. package/dist/internal/process-memory-telemetry.js +259 -0
  100. package/dist/internal/server.d.ts.map +1 -1
  101. package/dist/internal/server.js +9 -10
  102. package/dist/internal/session-engine.d.ts +4 -0
  103. package/dist/internal/session-engine.d.ts.map +1 -1
  104. package/dist/internal/session-engine.js +19 -5
  105. package/dist/internal/slack-provision-client.d.ts +41 -6
  106. package/dist/internal/slack-provision-client.d.ts.map +1 -1
  107. package/dist/internal/slack-provision-client.js +53 -7
  108. package/dist/playground/assets/{index-DEVTyeOu.js → index-BKMz70wx.js} +41 -41
  109. package/dist/playground/assets/index-BmMrulSc.css +1 -0
  110. package/dist/playground/index.html +2 -2
  111. package/dist/storage.d.ts +36 -10
  112. package/dist/storage.d.ts.map +1 -1
  113. package/dist/storage.js +82 -6
  114. package/docs/ab.md +4 -3
  115. package/docs/deployment.md +1 -1
  116. package/docs/evals.md +10 -7
  117. package/docs/example-agents/benny.md +2 -3
  118. package/docs/example-agents/oncall.md +4 -5
  119. package/docs/guides/human-in-the-loop.md +1 -1
  120. package/docs/guides/slack.md +51 -112
  121. package/docs/reference/cli.md +14 -37
  122. package/docs/reference/http-api.md +4 -3
  123. package/docs/storage.md +38 -22
  124. package/docs/troubleshooting.md +2 -2
  125. package/package.json +1 -1
  126. package/skills/create-agent/SKILL.md +4 -5
  127. package/skills/setup-slack/SKILL.md +74 -132
  128. package/src/bin/agent-serve.ts +26 -9
  129. package/src/channels/slack/init.ts +10 -71
  130. package/src/channels/slack/manifest.ts +3 -3
  131. package/src/channels/slack/setup.ts +25 -103
  132. package/src/channels/slack/types.ts +3 -4
  133. package/src/internal/cli-ax.ts +3 -3
  134. package/src/internal/cli-cursor.ts +34 -0
  135. package/src/internal/cli-slack.ts +136 -394
  136. package/src/internal/convert-automation/convert-workflow.ts +2 -2
  137. package/src/internal/event-log.ts +45 -7
  138. package/src/internal/process-memory-telemetry.ts +373 -0
  139. package/src/internal/server.ts +13 -0
  140. package/src/internal/session-engine.ts +20 -1
  141. package/src/internal/slack-provision-client.ts +90 -9
  142. package/src/storage.ts +130 -11
  143. package/dist/docs/assets/chunks/@localSearchIndexroot.DV5SAHnQ.js +0 -1
  144. package/dist/docs/assets/guides_slack.md.zriQpU_9.lean.js +0 -1
  145. package/dist/docs/assets/storage.md.CJYd5YmN.lean.js +0 -1
  146. package/dist/playground/assets/index-CiCmH6R-.css +0 -1
  147. /package/dist/docs/assets/{deployment.md.Cdp4rTE4.lean.js → deployment.md.B8kW-h7P.lean.js} +0 -0
  148. /package/dist/docs/assets/{example-agents_benny.md.l7JTmm8X.lean.js → example-agents_benny.md.B-LIDGja.lean.js} +0 -0
  149. /package/dist/docs/assets/{example-agents_oncall.md.ZE0n6ZFN.lean.js → example-agents_oncall.md.CBmyuAKc.lean.js} +0 -0
  150. /package/dist/docs/assets/{reference_http-api.md.DGrw_wOu.lean.js → reference_http-api.md.DMbdFGVQ.lean.js} +0 -0
  151. /package/dist/docs/assets/{troubleshooting.md.CkgwmVI0.lean.js → troubleshooting.md.C6n3wCr6.lean.js} +0 -0
@@ -44,6 +44,7 @@ import {
44
44
  cmdSessions,
45
45
  cmdTrajectory,
46
46
  } from "../internal/cli-ax.js";
47
+ import { ensureCursorLogin } from "../internal/cli-cursor.js";
47
48
  import {
48
49
  cmdDelete,
49
50
  cmdDeploy,
@@ -150,11 +151,12 @@ Usage:
150
151
  ${CLI} github <subcommand> …
151
152
 
152
153
  Commands:
153
- serve Serve agents under /<slug>/... (index at /). On a TTY, press
154
- Enter to restart (re-executes this process so agent code, evals,
155
- and Vite reload).
154
+ serve Serve agents under /<slug>/... (index at /). Runs \`${CLI} login\`
155
+ when unsigned. On a TTY, press Enter to restart (re-executes this
156
+ process so agent code, evals, and Vite reload).
156
157
  dev Local development: same as \`${CLI} serve --dev\` (manual
157
158
  schedule/reminder dispatch, unsigned GitHub loopback, Vite HMR).
159
+ Also runs \`${CLI} login\` when unsigned.
158
160
  chat Interactive REPL against a running server (follow-ups keep the
159
161
  session + continuation token). Optional --message seeds the first
160
162
  turn then stays open on a TTY. --session reattaches (looks up the
@@ -271,8 +273,8 @@ Commands:
271
273
  secrets Manage deployment secrets: set (names only by default: hidden
272
274
  prompt or piped stdin; NAME=VALUE requires --from-argv), list
273
275
  (names + createdAt; never values), unset.
274
- slack Slack channel pack: create/destroy/icon (Cursor Add to Slack
275
- provisioning), init, manifests, doctor (see slack help).
276
+ slack Slack channel pack: create/destroy/icon (dashboard wizard),
277
+ doctor (see slack help).
276
278
  github GitHub webhook pack: forward live deliveries, events, doctor
277
279
  (wraps \`gh webhook forward\`; see github help).
278
280
 
@@ -1264,17 +1266,32 @@ async function main(argv: string[]): Promise<number> {
1264
1266
  noSchedules: values["no-schedules"] === true,
1265
1267
  };
1266
1268
 
1267
- const start = async (): Promise<AgentServeHandle> => {
1269
+ const start = async (): Promise<
1270
+ | { kind: "ready"; handle: AgentServeHandle }
1271
+ | { kind: "login-failed"; exitCode: number }
1272
+ > => {
1268
1273
  loadLocalEnv();
1274
+ // Model turns need a Cursor credential. Prompt login before listen
1275
+ // so the first playground turn does not fail with a late auth error.
1276
+ const loginExit = await ensureCursorLogin({
1277
+ apiKey: values["api-key"],
1278
+ });
1279
+ if (loginExit !== 0) {
1280
+ return { kind: "login-failed", exitCode: loginExit };
1281
+ }
1269
1282
  const next = await serve(serveDir, serveOptions);
1270
1283
  printServeBanner(next, bannerOpts);
1271
1284
  if (enterToRestart) {
1272
1285
  process.stdout.write(style.dim(" press Enter to restart\n"));
1273
1286
  }
1274
- return next;
1287
+ return { kind: "ready", handle: next };
1275
1288
  };
1276
1289
 
1277
- const handle = await start();
1290
+ const started = await start();
1291
+ if (started.kind === "login-failed") {
1292
+ return started.exitCode;
1293
+ }
1294
+ const handle = started.handle;
1278
1295
  let closing = false;
1279
1296
  let restartRequested = false;
1280
1297
 
@@ -1502,7 +1519,7 @@ function printServeBanner(
1502
1519
  }
1503
1520
  // `/` is only mounted when the playground host home is enabled.
1504
1521
  if (!opts.noPlayground) {
1505
- process.stdout.write(` home ${c.cyan(handle.url + "/")}\n`);
1522
+ process.stdout.write(` home ${c.cyan(`${handle.url}/`)}\n`);
1506
1523
  }
1507
1524
  // Dev is playground-first (Vite proxies the API). Keep API/route detail for
1508
1525
  // plain `serve`, where operators often curl the HTTP surface directly.
@@ -6,7 +6,6 @@ import { mkdir, writeFile } from "node:fs/promises";
6
6
  import { basename, join, resolve } from "node:path";
7
7
  import { PACKAGE_NAME } from "../../internal/distribution.js";
8
8
  import { envPrefixFromName, slackEnvKeys } from "./credentials.js";
9
- import { buildSlackManifestPair } from "./manifest.js";
10
9
 
11
10
  export interface InitSlackOptions {
12
11
  dir: string;
@@ -20,9 +19,8 @@ export interface InitSlackOptions {
20
19
  */
21
20
  envPrefix?: string;
22
21
  /**
23
- * Subscribe the generated manifests to `message.channels` +
24
- * `message.groups` for the opt-in channel watch
25
- * (`engagement.channelPosts` on `slackChannel`).
22
+ * Subscribe the generated app to `message.channels` + `message.groups`
23
+ * for the opt-in channel watch (`engagement.channelPosts`).
26
24
  */
27
25
  channelPosts?: boolean;
28
26
  }
@@ -38,7 +36,6 @@ export async function initSlackChannel(
38
36
  options: InitSlackOptions
39
37
  ): Promise<InitSlackResult> {
40
38
  const rootDir = resolve(options.dir);
41
- const name = options.name ?? basename(rootDir);
42
39
  const envPrefix =
43
40
  options.envPrefix === ""
44
41
  ? undefined
@@ -46,29 +43,22 @@ export async function initSlackChannel(
46
43
  const envKeys = slackEnvKeys(envPrefix);
47
44
  const written: string[] = [];
48
45
 
49
- const write = async (rel: string, contents: string): Promise<void> => {
50
- const abs = join(rootDir, rel);
51
- await mkdir(join(abs, ".."), { recursive: true });
52
- await writeFile(abs, contents, { flag: "wx" });
53
- written.push(rel);
54
- };
55
-
46
+ const abs = join(rootDir, "agent/channels/slack.ts");
47
+ await mkdir(join(abs, ".."), { recursive: true });
56
48
  const envPrefixLine =
57
49
  envPrefix === undefined
58
50
  ? ""
59
51
  : ` envPrefix: ${JSON.stringify(envPrefix)},\n`;
60
-
61
- await write(
62
- "agent/channels/slack.ts",
52
+ await writeFile(
53
+ abs,
63
54
  `import { slackChannel } from "${PACKAGE_NAME}/channels/slack";
64
55
 
65
56
  /**
66
57
  * Slack channel (Socket Mode).
67
58
  *
68
59
  * Tokens: ${envKeys.bot} + ${envKeys.app}
69
- * (see .agent-serve/slack/env.example).
70
60
  *
71
- * Full setup: agent-serve slack setup
61
+ * Full setup: agent-serve slack create --dir .
72
62
  */
73
63
  export default slackChannel({
74
64
  ${envPrefixLine} // Streaming and thinking steps default to true.
@@ -77,61 +67,10 @@ ${envPrefixLine} // Streaming and thinking steps default to true.
77
67
  { title: "Status", message: "What are you working on?" },
78
68
  ],
79
69
  });
80
- `
81
- );
82
-
83
- const pair = buildSlackManifestPair({
84
- name,
85
- // Scaffolded for hand-import at api.slack.com; managed_app_settings is
86
- // settable only with the manager app's user token.
87
- managedByCursor: false,
88
- ...(options.description === undefined
89
- ? {}
90
- : { description: options.description }),
91
- ...(options.channelPosts === true ? { channelPosts: true } : {}),
92
- });
93
-
94
- await write(
95
- ".agent-serve/slack/manifest.dev.json",
96
- `${JSON.stringify(pair.dev, null, 2)}\n`
97
- );
98
- await write(
99
- ".agent-serve/slack/manifest.prod.json",
100
- `${JSON.stringify(pair.prod, null, 2)}\n`
101
- );
102
-
103
- await write(
104
- ".agent-serve/slack/env.example",
105
- `# Copy to .env.local (or export in your shell). Use the *dev* Slack app
106
- # for local development; use the Prod app tokens in deployment secrets.
107
- #
108
- # Multi-agent serve needs a distinct Slack app (and token pair) per agent.
109
-
110
- ${envKeys.bot}=xoxb-...
111
- ${envKeys.app}=xapp-...
112
- `
113
- );
114
-
115
- await write(
116
- ".agent-serve/slack/setup-status.json",
117
- `${JSON.stringify(
118
- {
119
- updatedAt: new Date().toISOString(),
120
- envPrefix: envPrefix ?? null,
121
- envKeys,
122
- phases: {
123
- generate: true,
124
- createApps: false,
125
- install: false,
126
- env: false,
127
- serve: false,
128
- smoke: false,
129
- },
130
- },
131
- null,
132
- 2
133
- )}\n`
70
+ `,
71
+ { flag: "wx" }
134
72
  );
73
+ written.push("agent/channels/slack.ts");
135
74
 
136
75
  return { rootDir, files: written, envPrefix, envKeys };
137
76
  }
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Generate importable Slack app manifests (dev + prod).
2
+ * Generate Slack app manifests (dev + prod) for Cursor-managed provision.
3
3
  *
4
- * Import at https://api.slack.com/apps -> Create New App -> From a manifest.
5
- * Always Socket Mode no Events Request URL.
4
+ * Always Socket Mode. No Events Request URL. Humans do not paste these
5
+ * at api.slack.com; `slack create` sends them through the dashboard wizard.
6
6
  *
7
7
  * Mirrored by backend/server/src/agentServe/agentServeSlackManifest.ts (the
8
8
  * backend cannot import this published package); keep the twins in lockstep.
@@ -1,111 +1,33 @@
1
1
  /**
2
2
  * Slack setup guide printed by `agent-serve slack setup`.
3
3
  *
4
- * Mirrors the Cursor skill at skills/setup-slack/SKILL.md: connection
5
- * decision first (Cursor-hosted vs dedicated Socket Mode app), then the
6
- * dedicated-app phases. {@link SLACK_SETUP_PHASES} stays the dedicated-app
7
- * checklist — its ids key `.agent-serve/slack/setup-status.json`.
4
+ * Two products: Cursor-hosted (`cursorAccount`) vs a dedicated Socket
5
+ * Mode app via `slack create` (dashboard wizard).
8
6
  */
9
7
 
10
- export interface SlackSetupPhase {
11
- id: string;
12
- actor: "agent" | "human";
13
- title: string;
14
- steps: string[];
15
- }
8
+ export function formatSlackSetupGuide(): string {
9
+ return `agent-serve — Slack setup
16
10
 
17
- export const SLACK_SETUP_PHASES: SlackSetupPhase[] = [
18
- {
19
- id: "generate",
20
- actor: "agent",
21
- title: "Generate channel + manifests",
22
- steps: [
23
- "agent-serve slack init --dir . --name My Agent",
24
- "Manifests default to Socket Mode (no public Request URL).",
25
- ],
26
- },
27
- {
28
- id: "createApps",
29
- actor: "human",
30
- title: "Create two Slack apps from manifests",
31
- steps: [
32
- "Open https://api.slack.com/apps -> Create New App from a manifest",
33
- "Paste .agent-serve/slack/manifest.dev.json -> create the *dev* app",
34
- "Repeat with manifest.prod.json for the *prod* app",
35
- ],
36
- },
37
- {
38
- id: "install",
39
- actor: "human",
40
- title: "Install + mint App-Level Token",
41
- steps: [
42
- "Install to Workspace; copy Bot User OAuth Token (xoxb-...)",
43
- "App-Level Tokens: create token with connections:write; copy xapp-...",
44
- ],
45
- },
46
- {
47
- id: "env",
48
- actor: "agent",
49
- title: "Wire environment",
50
- steps: [
51
- "Write per-agent tokens into .env.local (see .agent-serve/slack/env.example)",
52
- "Multi-agent: <PREFIX>_SLACK_BOT_TOKEN + <PREFIX>_SLACK_APP_TOKEN",
53
- "Single agent: SLACK_BOT_TOKEN + SLACK_APP_TOKEN (--no-prefix)",
54
- "agent-serve slack doctor --prefix <PREFIX>",
55
- ],
56
- },
57
- {
58
- id: "serve",
59
- actor: "agent",
60
- title: "Serve",
61
- steps: [
62
- "agent-serve serve --dir . --dev",
63
- "Confirm log: [agent-sdk/slack] Socket Mode connected",
64
- ],
65
- },
66
- {
67
- id: "smoke",
68
- actor: "human",
69
- title: "Smoke test",
70
- steps: [
71
- "Invite the bot to a channel",
72
- "@mention it or DM it",
73
- "Confirm logs: inbound → session start → reply delivered",
74
- "Confirm streaming reply and rotating status",
75
- ],
76
- },
77
- ];
11
+ Two products. Pick one.
78
12
 
79
- export function formatSlackSetupGuide(): string {
80
- const lines: string[] = [
81
- "agent-serve Slack setup",
82
- "",
83
- "Two connections exist; decide before running the phases below.",
84
- "",
85
- " A) Cursor-hosted connection (recommended default, zero Slack admin):",
86
- ' slackChannel({ cursorAccount: true, agentName: "MyAgent" })',
87
- " Sign in (agent-serve login / CURSOR_API_KEY), serve, then mention",
88
- ' "@Cursor MyAgent ..." in the linked workspace. No app, no tokens.',
89
- " B) Dedicated Slack app (Socket Mode) the phases below. Choose it",
90
- " when you need your own bot user, channel watching",
91
- " (engagement.channelPosts), or approval buttons / interactivity.",
92
- "",
93
- "Phases 0-5 cover connection B only.",
94
- "Goal: importable dev + prod Slack apps over Socket Mode (no public URL).",
95
- "App-Level Token (xapp-...) + Bot Token (xoxb-...) required.",
96
- "",
97
- ];
98
- for (const [index, phase] of SLACK_SETUP_PHASES.entries()) {
99
- lines.push(`## Phase ${index} — ${phase.title} (${phase.actor})`);
100
- for (const step of phase.steps) {
101
- lines.push(` - ${step}`);
102
- }
103
- lines.push("");
104
- }
105
- lines.push("Status file: .agent-serve/slack/setup-status.json");
106
- lines.push(
107
- "Skill (Cursor): packages/agent-serve/skills/setup-slack/SKILL.md"
108
- );
109
- lines.push("");
110
- return lines.join("\n");
13
+ A) Cursor-hosted (recommended default, zero Slack admin):
14
+ slackChannel({ cursorAccount: true, agentName: "MyAgent" })
15
+ Sign in (agent-serve login / CURSOR_API_KEY), serve, then mention
16
+ "@Cursor MyAgent ..." in the linked workspace. No app, no tokens.
17
+
18
+ B) Dedicated Slack app (Socket Mode):
19
+ agent-serve slack create --dir .
20
+ Opens the signed-in Cursor dashboard wizard. Finish Slack consent
21
+ and the bot name there. The CLI writes tokens into .env.local.
22
+ Use this when you need your own bot user, channel watching
23
+ (engagement.channelPosts), or approval buttons.
24
+
25
+ Do not paste a manifest at api.slack.com. \`slack init\` is removed.
26
+
27
+ Then:
28
+ - agent-serve serve --dir . --dev
29
+ - Invite the bot (Path B) or mention @Cursor <name> (Path A)
30
+
31
+ Skill: packages/agent-serve/skills/setup-slack/SKILL.md
32
+ `;
111
33
  }
@@ -421,7 +421,7 @@ export interface SlackEngagementOptions {
421
421
  /**
422
422
  * Opt-in channel watch (see {@link SlackChannelPostsOptions}). Requires
423
423
  * the Slack app to subscribe to `message.channels` / `message.groups`
424
- * (`slack init --channel-posts`, or add the events to an existing app).
424
+ * (`slack create --channel-posts`).
425
425
  */
426
426
  channelPosts?: SlackChannelPostsOptions;
427
427
  /**
@@ -650,9 +650,8 @@ export interface SlackManifestOptions {
650
650
  suggestedPrompts?: Array<{ title: string; message: string }>;
651
651
  /**
652
652
  * Emit `settings.managed_app_settings`. Defaults to `true` — Cursor
653
- * provisions these apps through its manager app. Pass `false` for a
654
- * manifest a human pastes into api.slack.com: only a manager user token
655
- * may set that block.
653
+ * provisions these apps through its manager app. Pass `false` when the
654
+ * caller is not a manager user token.
656
655
  */
657
656
  managedByCursor?: boolean;
658
657
  }
@@ -20,7 +20,7 @@ import type {
20
20
  import { serve } from "../index.js";
21
21
  import type { AgentServeHandle } from "../types.js";
22
22
  import { lookupSessionContinuation, runChat } from "./chat-client.js";
23
- import { cmdLogin } from "./cli-cursor.js";
23
+ import { ensureCursorLogin } from "./cli-cursor.js";
24
24
  import { resolveDeployAuth } from "./cli-deploy.js";
25
25
  import { resolveApiKey } from "./cursor/credentials.js";
26
26
  import { CLI_COMMAND_NAME, PACKAGE_NAME } from "./distribution.js";
@@ -392,8 +392,8 @@ export async function cmdInit(options: AxCliOptions): Promise<number> {
392
392
 
393
393
  let loginExit = 0;
394
394
  if (!signedIn) {
395
- process.stdout.write("Signing you in to Cursor\n\n");
396
- loginExit = await cmdLogin({});
395
+ // init always offers the browser flow (the --json path above skipped it).
396
+ loginExit = await ensureCursorLogin({ interactive: true });
397
397
  signedIn = loginExit === 0 && (await resolveApiKey()) !== undefined;
398
398
  process.stdout.write("\n");
399
399
  }
@@ -145,6 +145,40 @@ export async function cmdLogin(options: CursorCliOptions): Promise<number> {
145
145
  return 0;
146
146
  }
147
147
 
148
+ /**
149
+ * Gate for commands that need a Cursor credential before they can do useful
150
+ * work (`serve`, `dev`, interactive `init`). Already-signed-in hosts
151
+ * (`--api-key` / `CURSOR_API_KEY` / stored login) return immediately.
152
+ * Otherwise an interactive host runs {@link cmdLogin}; a non-interactive
153
+ * one (CI, Docker) fails fast with {@link SIGN_IN_HINT} instead of polling
154
+ * a browser that will never open.
155
+ */
156
+ export async function ensureCursorLogin(
157
+ options: {
158
+ apiKey?: string;
159
+ /**
160
+ * Run the browser login flow when unsigned. Defaults to stderr being a
161
+ * TTY.
162
+ */
163
+ interactive?: boolean;
164
+ /** Test seam. */
165
+ login?: (options: CursorCliOptions) => Promise<number>;
166
+ } = {}
167
+ ): Promise<number> {
168
+ const resolved = await resolveApiKey({ apiKey: options.apiKey });
169
+ if (resolved !== undefined) {
170
+ return 0;
171
+ }
172
+ const interactive = options.interactive ?? process.stderr.isTTY === true;
173
+ if (!interactive) {
174
+ process.stderr.write(`Not signed in to Cursor. ${SIGN_IN_HINT}\n`);
175
+ return 1;
176
+ }
177
+ process.stdout.write("Signing you in to Cursor\n\n");
178
+ const login = options.login ?? cmdLogin;
179
+ return login({});
180
+ }
181
+
148
182
  export async function cmdLogout(): Promise<number> {
149
183
  const stored = await readStoredCredentials();
150
184
  const removed = await clearStoredCredentials();