@cursor/july 0.1.6 → 0.1.8
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/dist/bin/agent-serve.js +73 -19
- package/dist/channels/slack/channel-watch.d.ts +6 -1
- package/dist/channels/slack/channel-watch.d.ts.map +1 -1
- package/dist/channels/slack/channel-watch.js +22 -1
- package/dist/channels/slack/cursor-account.d.ts +4 -0
- package/dist/channels/slack/cursor-account.d.ts.map +1 -1
- package/dist/channels/slack/cursor-account.js +12 -2
- package/dist/channels/slack/defaults.d.ts +10 -5
- package/dist/channels/slack/defaults.d.ts.map +1 -1
- package/dist/channels/slack/defaults.js +39 -17
- package/dist/channels/slack/dispatch.d.ts +18 -0
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +141 -38
- package/dist/channels/slack/inbound.d.ts +13 -3
- package/dist/channels/slack/inbound.d.ts.map +1 -1
- package/dist/channels/slack/inbound.js +17 -9
- package/dist/channels/slack/index.d.ts +4 -0
- package/dist/channels/slack/index.d.ts.map +1 -1
- package/dist/channels/slack/index.js +4 -0
- package/dist/channels/slack/live-delivery.d.ts.map +1 -1
- package/dist/channels/slack/live-delivery.js +1 -0
- package/dist/channels/slack/manifest.d.ts.map +1 -1
- package/dist/channels/slack/manifest.js +3 -0
- package/dist/channels/slack/nudge-carrier.d.ts +19 -0
- package/dist/channels/slack/nudge-carrier.d.ts.map +1 -0
- package/dist/channels/slack/nudge-carrier.js +166 -0
- package/dist/channels/slack/nudge-store.d.ts +61 -0
- package/dist/channels/slack/nudge-store.d.ts.map +1 -0
- package/dist/channels/slack/nudge-store.js +266 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +74 -25
- package/dist/channels/slack/stop.d.ts +14 -0
- package/dist/channels/slack/stop.d.ts.map +1 -0
- package/dist/channels/slack/stop.js +22 -0
- package/dist/channels/slack/thread-context.d.ts +81 -0
- package/dist/channels/slack/thread-context.d.ts.map +1 -0
- package/dist/channels/slack/thread-context.js +470 -0
- package/dist/channels/slack/types.d.ts +27 -0
- package/dist/channels/slack/types.d.ts.map +1 -1
- package/dist/docs/404.html +2 -2
- package/dist/docs/ab.html +4 -4
- package/dist/docs/assets/{app.DMboGKUD.js → app.BP8mAVMW.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.DevOabKJ.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.DkEqEnJU.js → VPLocalSearchBox.1FXIZbz8.js} +1 -1
- package/dist/docs/assets/chunks/{theme.ASugdMNm.js → theme.Dm1R02v9.js} +2 -2
- package/dist/docs/assets/example-agents_index.md.CwtWu5ix.js +2 -0
- package/dist/docs/assets/{example-agents_index.md.CRqJlnIf.lean.js → example-agents_index.md.CwtWu5ix.lean.js} +1 -1
- package/dist/docs/assets/example-agents_oncall.md.BG_sUMly.js +10 -0
- package/dist/docs/assets/example-agents_oncall.md.BG_sUMly.lean.js +1 -0
- package/dist/docs/assets/{guides_slack.md.CCwqHvSV.js → guides_slack.md.FWale6Ip.js} +4 -3
- package/dist/docs/assets/{guides_slack.md.CCwqHvSV.lean.js → guides_slack.md.FWale6Ip.lean.js} +1 -1
- package/dist/docs/assets/{reference_sessions.md.DdjWabnN.js → reference_sessions.md.DLd6mvbv.js} +2 -2
- package/dist/docs/assets/{reference_sessions.md.DdjWabnN.lean.js → reference_sessions.md.DLd6mvbv.lean.js} +1 -1
- package/dist/docs/assets/{storage.md.CVnInNiN.js → storage.md.Cu3MwM2a.js} +3 -2
- package/dist/docs/assets/{storage.md.CVnInNiN.lean.js → storage.md.Cu3MwM2a.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +4 -4
- package/dist/docs/concepts.html +4 -4
- package/dist/docs/deployment.html +4 -4
- package/dist/docs/evals.html +4 -4
- package/dist/docs/example-agents/approval-buddy.html +4 -4
- package/dist/docs/example-agents/benny.html +5 -5
- package/dist/docs/example-agents/bugbot.html +5 -5
- package/dist/docs/example-agents/codebase-wiki.html +4 -4
- package/dist/docs/example-agents/codeowners-review.html +4 -4
- package/dist/docs/example-agents/concierge.html +4 -4
- package/dist/docs/example-agents/fsd.html +4 -4
- package/dist/docs/example-agents/index.html +6 -6
- package/dist/docs/example-agents/knowledge-base.html +4 -4
- package/dist/docs/example-agents/oncall.html +34 -0
- package/dist/docs/example-agents/security-reviewer.html +4 -4
- package/dist/docs/example-agents/slack-agent.html +4 -4
- package/dist/docs/example-agents/weather-agent.html +4 -4
- package/dist/docs/guides/agent-to-agent.html +4 -4
- package/dist/docs/guides/cloud-runtime.html +4 -4
- package/dist/docs/guides/github.html +4 -4
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/slack.html +7 -6
- package/dist/docs/guides/webhooks.html +4 -4
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +4 -4
- package/dist/docs/index.html +4 -4
- package/dist/docs/quickstart.html +4 -4
- package/dist/docs/reference/agent-config.html +4 -4
- package/dist/docs/reference/channels.html +4 -4
- package/dist/docs/reference/cli.html +4 -4
- package/dist/docs/reference/connections.html +4 -4
- package/dist/docs/reference/hooks.html +4 -4
- package/dist/docs/reference/http-api.html +4 -4
- package/dist/docs/reference/instructions.html +4 -4
- package/dist/docs/reference/playground.html +4 -4
- package/dist/docs/reference/project-layout.html +4 -4
- package/dist/docs/reference/schedules.html +4 -4
- package/dist/docs/reference/sessions.html +5 -5
- package/dist/docs/reference/skills.html +4 -4
- package/dist/docs/reference/subagents.html +4 -4
- package/dist/docs/reference/tools.html +4 -4
- package/dist/docs/scaffolding-agents.html +4 -4
- package/dist/docs/storage.html +7 -6
- package/dist/docs/troubleshooting.html +4 -4
- package/dist/evals.d.ts +2 -2
- package/dist/internal/cli-ax.d.ts +23 -10
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +358 -55
- package/dist/internal/cli-mcp.d.ts +64 -0
- package/dist/internal/cli-mcp.d.ts.map +1 -0
- package/dist/internal/cli-mcp.js +570 -0
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +2 -0
- package/dist/internal/eval-run-store.d.ts +2 -0
- package/dist/internal/eval-run-store.d.ts.map +1 -1
- package/dist/internal/eval-run-store.js +4 -4
- package/dist/internal/evals-client.d.ts +96 -0
- package/dist/internal/evals-client.d.ts.map +1 -0
- package/dist/internal/evals-client.js +262 -0
- package/dist/internal/host-kv.d.ts +17 -0
- package/dist/internal/host-kv.d.ts.map +1 -0
- package/dist/internal/host-kv.js +77 -0
- package/dist/internal/init-project.js +3 -3
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +19 -2
- package/dist/internal/session-engine.d.ts +42 -7
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +247 -51
- package/dist/internal/storage-coordinator.d.ts +18 -1
- package/dist/internal/storage-coordinator.d.ts.map +1 -1
- package/dist/internal/storage-coordinator.js +43 -0
- package/dist/playground/assets/index-Bpr4Th4M.js +319 -0
- package/dist/playground/index.html +1 -1
- package/dist/storage-backends/file-kv.d.ts +42 -0
- package/dist/storage-backends/file-kv.d.ts.map +1 -0
- package/dist/storage-backends/file-kv.js +190 -0
- package/dist/storage-backends/postgres-kv.d.ts +77 -0
- package/dist/storage-backends/postgres-kv.d.ts.map +1 -0
- package/dist/storage-backends/postgres-kv.js +180 -0
- package/dist/storage.d.ts +10 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +10 -1
- package/dist/types.d.ts +79 -0
- package/dist/types.d.ts.map +1 -1
- package/docs/example-agents/index.md +14 -9
- package/docs/example-agents/oncall.md +216 -0
- package/docs/guides/slack.md +11 -2
- package/docs/reference/sessions.md +13 -4
- package/docs/storage.md +27 -0
- package/package.json +15 -1
- package/skills/framework-map/SKILL.md +6 -4
- package/src/bin/agent-serve.ts +79 -18
- package/src/channels/slack/channel-watch.ts +28 -1
- package/src/channels/slack/cursor-account.ts +20 -0
- package/src/channels/slack/defaults.ts +51 -20
- package/src/channels/slack/dispatch.ts +215 -40
- package/src/channels/slack/inbound.ts +30 -10
- package/src/channels/slack/index.ts +4 -0
- package/src/channels/slack/live-delivery.ts +1 -0
- package/src/channels/slack/manifest.ts +3 -0
- package/src/channels/slack/nudge-carrier.ts +182 -0
- package/src/channels/slack/nudge-store.ts +308 -0
- package/src/channels/slack/slack-channel.ts +106 -31
- package/src/channels/slack/stop.ts +25 -0
- package/src/channels/slack/thread-context.ts +572 -0
- package/src/channels/slack/types.ts +27 -0
- package/src/evals.ts +2 -2
- package/src/internal/cli-ax.ts +466 -75
- package/src/internal/cli-mcp.ts +708 -0
- package/src/internal/distribution.ts +2 -0
- package/src/internal/eval-run-store.ts +5 -0
- package/src/internal/evals-client.ts +431 -0
- package/src/internal/host-kv.ts +85 -0
- package/src/internal/init-project.ts +3 -3
- package/src/internal/server.ts +43 -0
- package/src/internal/session-engine.ts +351 -50
- package/src/internal/storage-coordinator.ts +41 -0
- package/src/storage-backends/file-kv.ts +221 -0
- package/src/storage-backends/postgres-kv.ts +248 -0
- package/src/storage.ts +11 -1
- package/src/types.ts +83 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.O6eP7QZr.js +0 -1
- package/dist/docs/assets/example-agents_index.md.CRqJlnIf.js +0 -2
- package/dist/playground/assets/index-mux9aj5P.js +0 -319
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cursor/july",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
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": {
|
|
@@ -124,6 +124,20 @@
|
|
|
124
124
|
"import": "./dist/storage.js",
|
|
125
125
|
"default": "./dist/storage.js"
|
|
126
126
|
},
|
|
127
|
+
"./storage/file-kv": {
|
|
128
|
+
"anysphere-source": "./src/storage-backends/file-kv.ts",
|
|
129
|
+
"bun": "./src/storage-backends/file-kv.ts",
|
|
130
|
+
"types": "./dist/storage-backends/file-kv.d.ts",
|
|
131
|
+
"import": "./dist/storage-backends/file-kv.js",
|
|
132
|
+
"default": "./dist/storage-backends/file-kv.js"
|
|
133
|
+
},
|
|
134
|
+
"./storage/postgres-kv": {
|
|
135
|
+
"anysphere-source": "./src/storage-backends/postgres-kv.ts",
|
|
136
|
+
"bun": "./src/storage-backends/postgres-kv.ts",
|
|
137
|
+
"types": "./dist/storage-backends/postgres-kv.d.ts",
|
|
138
|
+
"import": "./dist/storage-backends/postgres-kv.js",
|
|
139
|
+
"default": "./dist/storage-backends/postgres-kv.js"
|
|
140
|
+
},
|
|
127
141
|
"./package.json": {
|
|
128
142
|
"anysphere-source": "./package.json",
|
|
129
143
|
"bun": "./package.json",
|
|
@@ -97,10 +97,12 @@ Two handles, two owners:
|
|
|
97
97
|
- **sessionId** — runtime-owned handle for streaming/inspection
|
|
98
98
|
(`GET /v1/session/:id/stream?startIndex=N`, durable NDJSON replay).
|
|
99
99
|
|
|
100
|
-
A follow-up to a busy session **interrupts the in-flight turn**
|
|
101
|
-
for it to settle before the new turn sends.
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
A follow-up to a busy HTTP/MCP session **interrupts the in-flight turn**
|
|
101
|
+
and waits for it to settle before the new turn sends. Slack uses
|
|
102
|
+
**coalesce** instead (enqueue + boundary drain; see
|
|
103
|
+
`docs/reference/sessions.md`). `POST /v1/session/:id/stop` interrupts
|
|
104
|
+
without sending. Session-bound deterministic tool calls are rejected with
|
|
105
|
+
`409 session_busy` while a turn runs.
|
|
104
106
|
|
|
105
107
|
Key built-in routes (each agent, under `/<slug>` in multi-agent mode):
|
|
106
108
|
`POST /v1/session`, `POST /v1/session/:id`, `GET /v1/session/:id/stream`,
|
package/src/bin/agent-serve.ts
CHANGED
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
cmdCall,
|
|
30
30
|
cmdChat,
|
|
31
31
|
cmdEval,
|
|
32
|
+
cmdEvalStatus,
|
|
32
33
|
cmdInit,
|
|
33
34
|
cmdLogs,
|
|
34
35
|
cmdPlayground,
|
|
@@ -88,10 +89,17 @@ Usage:
|
|
|
88
89
|
${CLI} call <tool> [--input <json>] [--dir <path> | --url <baseUrl> | --prod]
|
|
89
90
|
[--session <id>] [--slug <slug>] [--team <id>]
|
|
90
91
|
${CLI} init [dir] [--json]
|
|
92
|
+
${CLI} mcp --prod [--slug <slug>] [--team <id>] [--dir <path>]
|
|
93
|
+
| --url <baseUrl> [--bearer-token <t>]
|
|
94
|
+
${CLI} mcp install [--name <serverName>] [--print] [--json]
|
|
95
|
+
(same target flags as mcp)
|
|
91
96
|
${CLI} eval [--dir <path>] [evalId...] [--list] [--json]
|
|
92
97
|
[--tag <tag>]... [--verbose] [--timeout-ms <n>]
|
|
93
|
-
[--no-stream] [--
|
|
98
|
+
[--no-stream] [--no-wait]
|
|
99
|
+
[--prod | --url <baseUrl>] [--slug <slug>]
|
|
94
100
|
[--team <id>]
|
|
101
|
+
${CLI} eval status [runId] --prod|--url <baseUrl> [--dir <path>] [--json]
|
|
102
|
+
[--slug <slug>] [--team <id>]
|
|
95
103
|
${CLI} info [--dir <path>] [--json]
|
|
96
104
|
${CLI} validate [--dir <path>]
|
|
97
105
|
${CLI} login [--api-key <key>] [--key-name <name>]
|
|
@@ -154,12 +162,29 @@ Commands:
|
|
|
154
162
|
run login when unsigned, then print next steps. --json is
|
|
155
163
|
machine-readable and never blocks on login. No directory:
|
|
156
164
|
print the setup guide.
|
|
165
|
+
mcp Serve this agent's MCP endpoint over stdio for MCP clients
|
|
166
|
+
that spawn local servers (e.g. Cursor). Proxies
|
|
167
|
+
newline-delimited JSON-RPC to <target>/v1/mcp. --prod resolves
|
|
168
|
+
the hosted deployment with the signed-in Cursor account and
|
|
169
|
+
re-mints short-lived engine credentials as they expire;
|
|
170
|
+
--url targets a running server. stdout is reserved for the
|
|
171
|
+
MCP wire. \`mcp install\` writes the matching entry into
|
|
172
|
+
~/.cursor/mcp.json (--print to preview; --name to override
|
|
173
|
+
the server name).
|
|
157
174
|
eval Run filesystem evals under evals/**/*.eval.ts (streams on a TTY).
|
|
158
|
-
|
|
159
|
-
--
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
175
|
+
Default: ephemeral local harness against evals on disk. Pass
|
|
176
|
+
--prod to kick off the batch on the team's hosted deployment
|
|
177
|
+
(slug from --slug or the directory name) via /v1/dev/evals/runs
|
|
178
|
+
so results appear in the playground and persist when the agent
|
|
179
|
+
declares an evals storage table; or --url for a running server
|
|
180
|
+
(same server-side path). With --prod/--url, pass --no-wait to
|
|
181
|
+
return the runId immediately without polling; check later with
|
|
182
|
+
\`${CLI} eval status <runId> --prod\` (omit runId to list recent
|
|
183
|
+
runs; exit 3 while still running). The status subcommand only
|
|
184
|
+
binds when --prod/--url is set, so an eval id named status still
|
|
185
|
+
runs locally. Pass evalId args to select: one datapoint
|
|
186
|
+
(weather/nyc), a whole file (weather → all cases in that file),
|
|
187
|
+
several of either, or omit to run all.
|
|
163
188
|
info Print the discovered agent surface (tools, skills, channels, ...).
|
|
164
189
|
validate Check the project(s) and exit non-zero on error diagnostics.
|
|
165
190
|
login Sign the host in to Cursor: browser sign-in mints a named,
|
|
@@ -194,7 +219,8 @@ Agent loop:
|
|
|
194
219
|
${CLI} validate --dir .
|
|
195
220
|
${CLI} info --dir . --json
|
|
196
221
|
${CLI} run --dir . --message "..."
|
|
197
|
-
${CLI} eval --
|
|
222
|
+
${CLI} eval --dir .
|
|
223
|
+
${CLI} eval --prod --dir .
|
|
198
224
|
${CLI} dev .
|
|
199
225
|
|
|
200
226
|
Options:
|
|
@@ -233,15 +259,14 @@ Options:
|
|
|
233
259
|
--prod chat/resume/run/call/eval/logs/sessions/session/playground:
|
|
234
260
|
use the team's hosted deployment. Slug from --slug or the
|
|
235
261
|
--dir basename. Mutually exclusive with --url. Requires
|
|
236
|
-
\`${CLI} login\`.
|
|
237
|
-
|
|
238
|
-
--local eval: run against an ephemeral local server instead of
|
|
239
|
-
the hosted deployment. Mutually exclusive with --url.
|
|
262
|
+
\`${CLI} login\`. For eval, this is how you opt into the
|
|
263
|
+
persisted server-side batch (default is local).
|
|
240
264
|
--once logs: print current progress / log buffer once and exit
|
|
241
265
|
(default is to follow).
|
|
242
266
|
--print playground: print the URL only; do not open a browser.
|
|
243
|
-
--no-wait deploy/stop: return right after the request is
|
|
244
|
-
instead of polling until a terminal status.
|
|
267
|
+
--no-wait deploy/stop/eval: return right after the request is
|
|
268
|
+
accepted instead of polling until a terminal status.
|
|
269
|
+
For eval, prints the runId (deployment / --url only).
|
|
245
270
|
--no-playground Disable the bundled web playground at /playground (also skips
|
|
246
271
|
auto-build / HMR).
|
|
247
272
|
--no-docs Disable the documentation site at /docs (also skips its
|
|
@@ -352,7 +377,6 @@ async function main(argv: string[]): Promise<number> {
|
|
|
352
377
|
"no-docs": { type: "boolean", default: false },
|
|
353
378
|
url: { type: "string" },
|
|
354
379
|
prod: { type: "boolean", default: false },
|
|
355
|
-
local: { type: "boolean", default: false },
|
|
356
380
|
message: { type: "string", multiple: true },
|
|
357
381
|
input: { type: "string" },
|
|
358
382
|
"messages-file": { type: "string" },
|
|
@@ -407,8 +431,9 @@ async function main(argv: string[]): Promise<number> {
|
|
|
407
431
|
const dir = values.dir ?? ".";
|
|
408
432
|
|
|
409
433
|
// Best-effort, cached, and silent on failure. `update` does its own fresh
|
|
410
|
-
// lookup,
|
|
411
|
-
|
|
434
|
+
// lookup, --json runs stay quiet for machine consumers, and `mcp` skips it
|
|
435
|
+
// so MCP client spawns stay fast (stdout there is the protocol wire).
|
|
436
|
+
if (command !== "update" && command !== "mcp" && values.json !== true) {
|
|
412
437
|
await warnIfOutdated();
|
|
413
438
|
}
|
|
414
439
|
|
|
@@ -475,6 +500,22 @@ async function main(argv: string[]): Promise<number> {
|
|
|
475
500
|
});
|
|
476
501
|
}
|
|
477
502
|
|
|
503
|
+
case "mcp": {
|
|
504
|
+
const { cmdMcp } = await import("../internal/cli-mcp.js");
|
|
505
|
+
return cmdMcp(positionals[0], {
|
|
506
|
+
dir,
|
|
507
|
+
slug: values.slug,
|
|
508
|
+
team: values.team,
|
|
509
|
+
apiKey: values["api-key"],
|
|
510
|
+
url: values.url,
|
|
511
|
+
prod: values.prod,
|
|
512
|
+
bearerToken: values["bearer-token"],
|
|
513
|
+
name: values.name,
|
|
514
|
+
print: values.print,
|
|
515
|
+
json: values.json,
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
|
|
478
519
|
case "login": {
|
|
479
520
|
const { cmdLogin } = await import("../internal/cli-cursor.js");
|
|
480
521
|
return cmdLogin({
|
|
@@ -624,6 +665,26 @@ async function main(argv: string[]): Promise<number> {
|
|
|
624
665
|
}
|
|
625
666
|
|
|
626
667
|
case "eval": {
|
|
668
|
+
// Remote status subcommand only when targeting --prod/--url. Otherwise
|
|
669
|
+
// the bare token "status" is a normal eval id (evals/status.eval.ts).
|
|
670
|
+
if (
|
|
671
|
+
positionals[0] === "status" &&
|
|
672
|
+
(values.prod === true || values.url !== undefined)
|
|
673
|
+
) {
|
|
674
|
+
return cmdEvalStatus(
|
|
675
|
+
positionals[1],
|
|
676
|
+
axFromOptions({
|
|
677
|
+
dir,
|
|
678
|
+
json: values.json,
|
|
679
|
+
url: values.url,
|
|
680
|
+
prod: values.prod,
|
|
681
|
+
team: values.team,
|
|
682
|
+
apiKey: values["api-key"],
|
|
683
|
+
slug: values.slug,
|
|
684
|
+
bearerToken: values["bearer-token"],
|
|
685
|
+
})
|
|
686
|
+
);
|
|
687
|
+
}
|
|
627
688
|
return cmdEval(
|
|
628
689
|
axFromOptions({
|
|
629
690
|
dir,
|
|
@@ -634,7 +695,7 @@ async function main(argv: string[]): Promise<number> {
|
|
|
634
695
|
tags: values.tag,
|
|
635
696
|
url: values.url,
|
|
636
697
|
prod: values.prod,
|
|
637
|
-
|
|
698
|
+
noWait: values["no-wait"],
|
|
638
699
|
team: values.team,
|
|
639
700
|
apiKey: values["api-key"],
|
|
640
701
|
slug: values.slug,
|
|
@@ -1052,7 +1113,7 @@ function axFromOptions(
|
|
|
1052
1113
|
toolInput: partial.toolInput,
|
|
1053
1114
|
url: partial.url,
|
|
1054
1115
|
prod: partial.prod,
|
|
1055
|
-
|
|
1116
|
+
noWait: partial.noWait,
|
|
1056
1117
|
team: partial.team,
|
|
1057
1118
|
apiKey: partial.apiKey,
|
|
1058
1119
|
fetchImpl: partial.fetchImpl,
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
* - Top-level posts only by default; thread replies never dispatch unless
|
|
7
7
|
* `posts: "all"` is configured.
|
|
8
8
|
* - Posts that @mention the bot are skipped here (the `app_mention` path
|
|
9
|
-
* owns them)
|
|
9
|
+
* owns them).
|
|
10
|
+
* - Bot-authored posts are dropped unless `includeBotPosts` is configured
|
|
11
|
+
* (alert feeds / webhook integrations); the watching bot's own posts are
|
|
12
|
+
* always dropped either way (loop safety).
|
|
10
13
|
* - An optional debounce window lets rapid edits settle: edits update the
|
|
11
14
|
* pending text, deleting the post cancels the dispatch.
|
|
12
15
|
*/
|
|
@@ -114,11 +117,14 @@ export function createChannelPostWatcher(args: {
|
|
|
114
117
|
allowlist: SlackChannelAllowlist;
|
|
115
118
|
/** Bot user id (from `auth.test`) so bot mentions route via app_mention. */
|
|
116
119
|
getBotUserId: () => string | undefined;
|
|
120
|
+
/** This app's own `bot_id` (from `auth.test`) for self-post loop safety. */
|
|
121
|
+
getBotId?: () => string | undefined;
|
|
117
122
|
dispatch: (message: SlackMessage, eventId?: string) => void;
|
|
118
123
|
log?: SlackLog;
|
|
119
124
|
}): ChannelPostWatcher {
|
|
120
125
|
const log = args.log ?? defaultSlackLog;
|
|
121
126
|
const includeReplies = args.options.posts === "all";
|
|
127
|
+
const includeBotPosts = args.options.includeBotPosts === true;
|
|
122
128
|
const debounceMs = args.options.debounceMs ?? 0;
|
|
123
129
|
const pending = new Map<
|
|
124
130
|
string,
|
|
@@ -185,6 +191,27 @@ export function createChannelPostWatcher(args: {
|
|
|
185
191
|
return skip("thread reply (posts: top-level)", message);
|
|
186
192
|
}
|
|
187
193
|
const botUserId = args.getBotUserId();
|
|
194
|
+
const author = message.author;
|
|
195
|
+
if (author?.isBot === true) {
|
|
196
|
+
if (!includeBotPosts) {
|
|
197
|
+
return skip("bot-authored post (includeBotPosts off)", message);
|
|
198
|
+
}
|
|
199
|
+
const selfBotId = args.getBotId?.();
|
|
200
|
+
if (selfBotId === undefined && botUserId === undefined) {
|
|
201
|
+
return skip(
|
|
202
|
+
"bot-authored post (bot identity unknown; loop safety)",
|
|
203
|
+
message
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
if (
|
|
207
|
+
(selfBotId !== undefined && author.botId === selfBotId) ||
|
|
208
|
+
(botUserId !== undefined &&
|
|
209
|
+
author.userId !== "" &&
|
|
210
|
+
author.userId === botUserId)
|
|
211
|
+
) {
|
|
212
|
+
return skip("own post (loop safety)", message);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
188
215
|
if (botUserId !== undefined && message.text.includes(`<@${botUserId}>`)) {
|
|
189
216
|
return skip("bot mention (app_mention path owns it)", message);
|
|
190
217
|
}
|
|
@@ -114,6 +114,12 @@ export async function dispatchCursorSlackEnvelope(args: {
|
|
|
114
114
|
envelope: CursorSlackEnvelope;
|
|
115
115
|
send: SendMessageFn;
|
|
116
116
|
host: HostContext;
|
|
117
|
+
hasContinuationSession?: (continuationToken: string) => Promise<boolean>;
|
|
118
|
+
isContinuationBusy?: (continuationToken: string) => Promise<boolean>;
|
|
119
|
+
getContinuationLastBotMessageTs?: (
|
|
120
|
+
continuationToken: string
|
|
121
|
+
) => Promise<string | undefined>;
|
|
122
|
+
interruptContinuation?: (continuationToken: string) => Promise<boolean>;
|
|
117
123
|
}): Promise<void> {
|
|
118
124
|
const { runtime, envelope } = args;
|
|
119
125
|
const log = runtime.getLog();
|
|
@@ -161,6 +167,20 @@ export async function dispatchCursorSlackEnvelope(args: {
|
|
|
161
167
|
credentials: runtime.credentials,
|
|
162
168
|
host: args.host,
|
|
163
169
|
log,
|
|
170
|
+
...(args.hasContinuationSession === undefined
|
|
171
|
+
? {}
|
|
172
|
+
: { hasContinuationSession: args.hasContinuationSession }),
|
|
173
|
+
...(args.isContinuationBusy === undefined
|
|
174
|
+
? {}
|
|
175
|
+
: { isContinuationBusy: args.isContinuationBusy }),
|
|
176
|
+
...(args.getContinuationLastBotMessageTs === undefined
|
|
177
|
+
? {}
|
|
178
|
+
: {
|
|
179
|
+
getContinuationLastBotMessageTs: args.getContinuationLastBotMessageTs,
|
|
180
|
+
}),
|
|
181
|
+
...(args.interruptContinuation === undefined
|
|
182
|
+
? {}
|
|
183
|
+
: { interruptContinuation: args.interruptContinuation }),
|
|
164
184
|
...(envelope.eventId === undefined ? {} : { eventId: envelope.eventId }),
|
|
165
185
|
});
|
|
166
186
|
}
|
|
@@ -26,28 +26,51 @@ import type {
|
|
|
26
26
|
SlackSuggestedPrompt,
|
|
27
27
|
} from "./types.js";
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
function resolveLoadingMessages(
|
|
30
|
+
loadingMessages: readonly string[] | undefined
|
|
31
|
+
): string[] {
|
|
32
|
+
if (loadingMessages !== undefined && loadingMessages.length > 0) {
|
|
33
|
+
return [...loadingMessages];
|
|
34
|
+
}
|
|
35
|
+
return [...SLACK_DEFAULT_LOADING_MESSAGES];
|
|
36
|
+
}
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
export
|
|
38
|
+
/** Default mention/DM inbound handler (optional custom loading rotation). */
|
|
39
|
+
export function createDefaultOnInbound(
|
|
40
|
+
loadingMessages?: readonly string[]
|
|
41
|
+
): SlackMessageHandler {
|
|
42
|
+
const rotating = resolveLoadingMessages(loadingMessages);
|
|
43
|
+
return async (ctx, message) => {
|
|
44
|
+
await ctx.thread.startTyping("Thinking…", rotating);
|
|
45
|
+
const auth = defaultSlackAuth(message, ctx);
|
|
46
|
+
return auth === null ? null : { auth };
|
|
47
|
+
};
|
|
48
|
+
}
|
|
37
49
|
|
|
38
50
|
/**
|
|
39
|
-
* Default watched-channel-post handler
|
|
40
|
-
*
|
|
41
|
-
* `engagement: "channel_post"`
|
|
51
|
+
* Default watched-channel-post handler (optional custom loading rotation).
|
|
52
|
+
* Same thread-scoped principal as mentions, tagged with
|
|
53
|
+
* `engagement: "channel_post"` for auth policies.
|
|
42
54
|
*/
|
|
43
|
-
export
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
export function createDefaultOnChannelPost(
|
|
56
|
+
loadingMessages?: readonly string[]
|
|
57
|
+
): SlackMessageHandler {
|
|
58
|
+
const rotating = resolveLoadingMessages(loadingMessages);
|
|
59
|
+
return async (ctx, message) => {
|
|
60
|
+
await ctx.thread.startTyping("Thinking…", rotating);
|
|
61
|
+
const auth = defaultSlackAuth(message, ctx, {
|
|
62
|
+
engagement: "channel_post",
|
|
63
|
+
});
|
|
64
|
+
return auth === null ? null : { auth };
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const defaultOnAppMention: SlackMessageHandler =
|
|
69
|
+
createDefaultOnInbound();
|
|
70
|
+
export const defaultOnDirectMessage: SlackMessageHandler =
|
|
71
|
+
createDefaultOnInbound();
|
|
72
|
+
export const defaultOnChannelPost: SlackMessageHandler =
|
|
73
|
+
createDefaultOnChannelPost();
|
|
51
74
|
|
|
52
75
|
export interface BuildDefaultEventsOptions {
|
|
53
76
|
credentials?: SlackCredentials;
|
|
@@ -55,6 +78,8 @@ export interface BuildDefaultEventsOptions {
|
|
|
55
78
|
thinkingSteps?: boolean;
|
|
56
79
|
suggestedPrompts?: SlackSuggestedPrompt[];
|
|
57
80
|
suggestedPromptsTitle?: string;
|
|
81
|
+
/** Rotating assistant status lines; defaults to pack constants. */
|
|
82
|
+
loadingMessages?: readonly string[];
|
|
58
83
|
/** Resolved per-call so channel onStart can rebind the server logger. */
|
|
59
84
|
getLog?: () => SlackLog;
|
|
60
85
|
}
|
|
@@ -74,6 +99,7 @@ export function buildDefaultEvents(
|
|
|
74
99
|
const thinkingSteps = options.thinkingSteps !== false;
|
|
75
100
|
const suggestedPrompts = options.suggestedPrompts ?? [];
|
|
76
101
|
const suggestedPromptsTitle = options.suggestedPromptsTitle;
|
|
102
|
+
const loadingMessages = resolveLoadingMessages(options.loadingMessages);
|
|
77
103
|
const botToken = credentials?.botToken;
|
|
78
104
|
const getLog = options.getLog ?? (() => defaultSlackLog);
|
|
79
105
|
const strategy = createStreamDeliveryStrategy({ botToken, getLog });
|
|
@@ -87,6 +113,7 @@ export function buildDefaultEvents(
|
|
|
87
113
|
channel.state.streamTs = null;
|
|
88
114
|
channel.state.streamChannelId = null;
|
|
89
115
|
channel.state.lastPostedText = null;
|
|
116
|
+
// Keep lastBotMessageTs across turns — warm delta watermark.
|
|
90
117
|
channel.state.approvalMessageByCallId = {};
|
|
91
118
|
|
|
92
119
|
const state = channel.state;
|
|
@@ -106,7 +133,7 @@ export function buildDefaultEvents(
|
|
|
106
133
|
channelId: state.channelId,
|
|
107
134
|
threadTs: state.threadTs,
|
|
108
135
|
status: "Working…",
|
|
109
|
-
loadingMessages
|
|
136
|
+
loadingMessages,
|
|
110
137
|
});
|
|
111
138
|
|
|
112
139
|
// Retry streaming each turn unless a prior call proved the feature
|
|
@@ -178,7 +205,10 @@ export function buildDefaultEvents(
|
|
|
178
205
|
channelId: channel.state.channelId,
|
|
179
206
|
threadTs: channel.state.threadTs,
|
|
180
207
|
status,
|
|
181
|
-
loadingMessages: [
|
|
208
|
+
loadingMessages: [
|
|
209
|
+
status,
|
|
210
|
+
...loadingMessages.filter((message) => message !== status),
|
|
211
|
+
],
|
|
182
212
|
});
|
|
183
213
|
channel.state.lastReasoningTypingAtMs = now;
|
|
184
214
|
channel.state.lastReasoningTypingStatus = status;
|
|
@@ -337,6 +367,7 @@ export function buildDefaultEvents(
|
|
|
337
367
|
threadTs: state.threadTs,
|
|
338
368
|
});
|
|
339
369
|
channel.state.lastPostedText = event.data.text;
|
|
370
|
+
channel.state.lastBotMessageTs = posted.ts;
|
|
340
371
|
log.info("reply delivered via postMessage", {
|
|
341
372
|
channel: state.channelId,
|
|
342
373
|
thread_ts: state.threadTs,
|