@cursor/july 0.1.7 → 0.1.9
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 +31 -2
- 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/post-update-delivery.js +318 -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.COTN7wgo.js → app.Ciosf24M.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.D154Detj.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.BW3TBdT0.js → VPLocalSearchBox.BcRDly7n.js} +1 -1
- package/dist/docs/assets/chunks/{theme.BEJW0vE7.js → theme.CMpbjdfx.js} +2 -2
- package/dist/docs/assets/{deployment.md.BtfEsc9S.js → deployment.md.DC5-ImcM.js} +1 -1
- package/dist/docs/assets/{example-agents_approval-buddy.md.8R5phXb5.js → example-agents_approval-buddy.md.DFGBYLcc.js} +2 -2
- package/dist/docs/assets/{example-agents_approval-buddy.md.8R5phXb5.lean.js → example-agents_approval-buddy.md.DFGBYLcc.lean.js} +1 -1
- package/dist/docs/assets/example-agents_index.md.BPXjUtRB.js +2 -0
- package/dist/docs/assets/example-agents_index.md.BPXjUtRB.lean.js +1 -0
- 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/{example-agents_security-reviewer.md.D2rtwDTO.js → example-agents_security-reviewer.md.CE9v-aKm.js} +2 -2
- package/dist/docs/assets/{example-agents_security-reviewer.md.D2rtwDTO.lean.js → example-agents_security-reviewer.md.CE9v-aKm.lean.js} +1 -1
- 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.DRTdnFvd.js} +9 -2
- package/dist/docs/assets/{storage.md.CVnInNiN.lean.js → storage.md.DRTdnFvd.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 +6 -6
- package/dist/docs/evals.html +4 -4
- package/dist/docs/example-agents/approval-buddy.html +5 -5
- 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 +6 -6
- 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 +13 -6
- package/dist/docs/troubleshooting.html +4 -4
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +45 -18
- 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/deploy-client.d.ts +7 -1
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +3 -0
- package/dist/internal/deploy-source.d.ts +3 -0
- package/dist/internal/deploy-source.d.ts.map +1 -1
- package/dist/internal/deploy-source.js +25 -7
- package/dist/internal/discovery.js +1 -1
- package/dist/internal/distribution.d.ts.map +1 -1
- package/dist/internal/distribution.js +3 -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/hosting.d.ts +12 -2
- package/dist/internal/hosting.d.ts.map +1 -1
- package/dist/internal/hosting.js +21 -4
- package/dist/internal/json-dir-store.js +100 -0
- package/dist/internal/logs-client.d.ts +16 -2
- package/dist/internal/logs-client.d.ts.map +1 -1
- package/dist/internal/logs-client.js +51 -16
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +8 -0
- 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 +276 -66
- 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/internal/workspace.d.ts +19 -0
- package/dist/internal/workspace.d.ts.map +1 -1
- package/dist/internal/workspace.js +47 -13
- package/dist/playground/assets/{index-72vCOBWO.js → index-C0-QEG4O.js} +42 -42
- package/dist/playground/assets/index-z3JY9O2x.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted.d.ts +65 -0
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -0
- package/dist/storage-backends/cursor-hosted.js +203 -0
- 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 +82 -0
- package/dist/storage-backends/postgres-kv.d.ts.map +1 -0
- package/dist/storage-backends/postgres-kv.js +185 -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/.vitepress/cache/deps/package.json +3 -0
- package/docs/deployment.md +7 -3
- package/docs/example-agents/approval-buddy.md +1 -1
- package/docs/example-agents/index.md +15 -10
- package/docs/example-agents/oncall.md +216 -0
- package/docs/example-agents/security-reviewer.md +5 -5
- package/docs/guides/slack.md +11 -2
- package/docs/reference/sessions.md +13 -4
- package/docs/storage.md +41 -0
- package/package.json +22 -1
- package/skills/framework-map/SKILL.md +6 -4
- package/src/bin/agent-serve.ts +32 -2
- 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/internal/cli-deploy.ts +58 -20
- package/src/internal/cli-mcp.ts +708 -0
- package/src/internal/deploy-client.ts +11 -0
- package/src/internal/deploy-source.ts +24 -6
- package/src/internal/discovery.ts +1 -1
- package/src/internal/distribution.ts +3 -0
- package/src/internal/host-kv.ts +85 -0
- package/src/internal/hosting.ts +24 -4
- package/src/internal/logs-client.ts +67 -21
- package/src/internal/server.ts +31 -0
- package/src/internal/session-engine.ts +379 -61
- package/src/internal/storage-coordinator.ts +41 -0
- package/src/internal/workspace.ts +48 -11
- package/src/storage-backends/cursor-hosted.ts +246 -0
- package/src/storage-backends/file-kv.ts +221 -0
- package/src/storage-backends/postgres-kv.ts +253 -0
- package/src/storage.ts +11 -1
- package/src/types.ts +83 -0
- package/dist/docs/assets/chunks/@localSearchIndexroot.B7UcKvIn.js +0 -1
- package/dist/docs/assets/example-agents_index.md.CRqJlnIf.js +0 -2
- package/dist/docs/assets/example-agents_index.md.CRqJlnIf.lean.js +0 -1
- package/dist/internal/persistence-coordinator.d.ts +0 -127
- package/dist/internal/persistence-coordinator.d.ts.map +0 -1
- package/dist/persistence.d.ts +0 -184
- package/dist/persistence.d.ts.map +0 -1
- package/dist/playground/assets/index-BjnMwYoR.css +0 -1
- /package/dist/docs/assets/{deployment.md.BtfEsc9S.lean.js → deployment.md.DC5-ImcM.lean.js} +0 -0
package/dist/bin/agent-serve.js
CHANGED
|
@@ -65,6 +65,10 @@ Usage:
|
|
|
65
65
|
${CLI} call <tool> [--input <json>] [--dir <path> | --url <baseUrl> | --prod]
|
|
66
66
|
[--session <id>] [--slug <slug>] [--team <id>]
|
|
67
67
|
${CLI} init [dir] [--json]
|
|
68
|
+
${CLI} mcp --prod [--slug <slug>] [--team <id>] [--dir <path>]
|
|
69
|
+
| --url <baseUrl> [--bearer-token <t>]
|
|
70
|
+
${CLI} mcp install [--name <serverName>] [--print] [--json]
|
|
71
|
+
(same target flags as mcp)
|
|
68
72
|
${CLI} eval [--dir <path>] [evalId...] [--list] [--json]
|
|
69
73
|
[--tag <tag>]... [--verbose] [--timeout-ms <n>]
|
|
70
74
|
[--no-stream] [--no-wait]
|
|
@@ -134,6 +138,15 @@ Commands:
|
|
|
134
138
|
run login when unsigned, then print next steps. --json is
|
|
135
139
|
machine-readable and never blocks on login. No directory:
|
|
136
140
|
print the setup guide.
|
|
141
|
+
mcp Serve this agent's MCP endpoint over stdio for MCP clients
|
|
142
|
+
that spawn local servers (e.g. Cursor). Proxies
|
|
143
|
+
newline-delimited JSON-RPC to <target>/v1/mcp. --prod resolves
|
|
144
|
+
the hosted deployment with the signed-in Cursor account and
|
|
145
|
+
re-mints short-lived engine credentials as they expire;
|
|
146
|
+
--url targets a running server. stdout is reserved for the
|
|
147
|
+
MCP wire. \`mcp install\` writes the matching entry into
|
|
148
|
+
~/.cursor/mcp.json (--print to preview; --name to override
|
|
149
|
+
the server name).
|
|
137
150
|
eval Run filesystem evals under evals/**/*.eval.ts (streams on a TTY).
|
|
138
151
|
Default: ephemeral local harness against evals on disk. Pass
|
|
139
152
|
--prod to kick off the batch on the team's hosted deployment
|
|
@@ -390,8 +403,9 @@ function main(argv) {
|
|
|
390
403
|
});
|
|
391
404
|
const dir = (_h = values.dir) !== null && _h !== void 0 ? _h : ".";
|
|
392
405
|
// Best-effort, cached, and silent on failure. `update` does its own fresh
|
|
393
|
-
// lookup,
|
|
394
|
-
|
|
406
|
+
// lookup, --json runs stay quiet for machine consumers, and `mcp` skips it
|
|
407
|
+
// so MCP client spawns stay fast (stdout there is the protocol wire).
|
|
408
|
+
if (command !== "update" && command !== "mcp" && values.json !== true) {
|
|
395
409
|
yield warnIfOutdated();
|
|
396
410
|
}
|
|
397
411
|
switch (command) {
|
|
@@ -452,6 +466,21 @@ function main(argv) {
|
|
|
452
466
|
json: values.json,
|
|
453
467
|
});
|
|
454
468
|
}
|
|
469
|
+
case "mcp": {
|
|
470
|
+
const { cmdMcp } = yield import("../internal/cli-mcp.js");
|
|
471
|
+
return cmdMcp(positionals[0], {
|
|
472
|
+
dir,
|
|
473
|
+
slug: values.slug,
|
|
474
|
+
team: values.team,
|
|
475
|
+
apiKey: values["api-key"],
|
|
476
|
+
url: values.url,
|
|
477
|
+
prod: values.prod,
|
|
478
|
+
bearerToken: values["bearer-token"],
|
|
479
|
+
name: values.name,
|
|
480
|
+
print: values.print,
|
|
481
|
+
json: values.json,
|
|
482
|
+
});
|
|
483
|
+
}
|
|
455
484
|
case "login": {
|
|
456
485
|
const { cmdLogin } = yield import("../internal/cli-cursor.js");
|
|
457
486
|
return cmdLogin({
|
|
@@ -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
|
*/
|
|
@@ -40,6 +43,8 @@ export declare function createChannelPostWatcher(args: {
|
|
|
40
43
|
allowlist: SlackChannelAllowlist;
|
|
41
44
|
/** Bot user id (from `auth.test`) so bot mentions route via app_mention. */
|
|
42
45
|
getBotUserId: () => string | undefined;
|
|
46
|
+
/** This app's own `bot_id` (from `auth.test`) for self-post loop safety. */
|
|
47
|
+
getBotId?: () => string | undefined;
|
|
43
48
|
dispatch: (message: SlackMessage, eventId?: string) => void;
|
|
44
49
|
log?: SlackLog;
|
|
45
50
|
}): ChannelPostWatcher;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-watch.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/channel-watch.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"channel-watch.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/channel-watch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,KAAK,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAIzE,sEAAsE;AACtE,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAqB;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAE3C,YAAY,OAAO,EAAE,SAAS,MAAM,EAAE,EAerC;IAED,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAElC;IAED,eAAe,IAAI,MAAM,EAAE,CAE1B;IAED,uDAAuD;IACvD,kBAAkB,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAO9D;CACF;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,GAAG,GAAE,QAA0B,GAC9B,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAiC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,MAAM,CAAC,KAAK,EAAE,wBAAwB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACnE,2CAA2C;IAC3C,IAAI,IAAI,IAAI,CAAC;CACd;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAC7C,OAAO,EAAE,wBAAwB,CAAC;IAClC,SAAS,EAAE,qBAAqB,CAAC;IACjC,4EAA4E;IAC5E,YAAY,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACvC,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,GAAG,CAAC,EAAE,QAAQ,CAAC;CAChB,GAAG,kBAAkB,CA0HrB"}
|
|
@@ -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
|
*/
|
|
@@ -100,6 +103,7 @@ export function createChannelPostWatcher(args) {
|
|
|
100
103
|
var _a, _b;
|
|
101
104
|
const log = (_a = args.log) !== null && _a !== void 0 ? _a : defaultSlackLog;
|
|
102
105
|
const includeReplies = args.options.posts === "all";
|
|
106
|
+
const includeBotPosts = args.options.includeBotPosts === true;
|
|
103
107
|
const debounceMs = (_b = args.options.debounceMs) !== null && _b !== void 0 ? _b : 0;
|
|
104
108
|
const pending = new Map();
|
|
105
109
|
const pendingKey = (channelId, ts) => `${channelId}:${ts}`;
|
|
@@ -122,6 +126,7 @@ export function createChannelPostWatcher(args) {
|
|
|
122
126
|
}
|
|
123
127
|
return {
|
|
124
128
|
handle(event, eventId) {
|
|
129
|
+
var _a;
|
|
125
130
|
if (event.kind === "deleted") {
|
|
126
131
|
const key = pendingKey(event.channelId, event.ts);
|
|
127
132
|
const entry = pending.get(key);
|
|
@@ -151,6 +156,22 @@ export function createChannelPostWatcher(args) {
|
|
|
151
156
|
return skip("thread reply (posts: top-level)", message);
|
|
152
157
|
}
|
|
153
158
|
const botUserId = args.getBotUserId();
|
|
159
|
+
const author = message.author;
|
|
160
|
+
if ((author === null || author === void 0 ? void 0 : author.isBot) === true) {
|
|
161
|
+
if (!includeBotPosts) {
|
|
162
|
+
return skip("bot-authored post (includeBotPosts off)", message);
|
|
163
|
+
}
|
|
164
|
+
const selfBotId = (_a = args.getBotId) === null || _a === void 0 ? void 0 : _a.call(args);
|
|
165
|
+
if (selfBotId === undefined && botUserId === undefined) {
|
|
166
|
+
return skip("bot-authored post (bot identity unknown; loop safety)", message);
|
|
167
|
+
}
|
|
168
|
+
if ((selfBotId !== undefined && author.botId === selfBotId) ||
|
|
169
|
+
(botUserId !== undefined &&
|
|
170
|
+
author.userId !== "" &&
|
|
171
|
+
author.userId === botUserId)) {
|
|
172
|
+
return skip("own post (loop safety)", message);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
154
175
|
if (botUserId !== undefined && message.text.includes(`<@${botUserId}>`)) {
|
|
155
176
|
return skip("bot mention (app_mention path owns it)", message);
|
|
156
177
|
}
|
|
@@ -72,5 +72,9 @@ export declare function dispatchCursorSlackEnvelope(args: {
|
|
|
72
72
|
envelope: CursorSlackEnvelope;
|
|
73
73
|
send: SendMessageFn;
|
|
74
74
|
host: HostContext;
|
|
75
|
+
hasContinuationSession?: (continuationToken: string) => Promise<boolean>;
|
|
76
|
+
isContinuationBusy?: (continuationToken: string) => Promise<boolean>;
|
|
77
|
+
getContinuationLastBotMessageTs?: (continuationToken: string) => Promise<string | undefined>;
|
|
78
|
+
interruptContinuation?: (continuationToken: string) => Promise<boolean>;
|
|
75
79
|
}): Promise<void>;
|
|
76
80
|
//# sourceMappingURL=cursor-account.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor-account.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/cursor-account.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAEhB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAEpB;;;;GAIG;AACH,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IACjE,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;CAC7C;AAED,wBAAgB,8BAA8B,IAAI,wBAAwB,CAezE;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,sEAAsE;AACtE,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,0EAA0E;IAC1E,WAAW,EAAE,gBAAgB,CAAC;IAC9B,SAAS,EAAE,wBAAwB,CAAC;IACpC,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,mBAAmB,CAAC;IAClC,eAAe,EAAE,mBAAmB,CAAC;IACrC,MAAM,EAAE,MAAM,QAAQ,CAAC;CACxB;AAID,wBAAgB,iCAAiC,CAC/C,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,yBAAyB,GACjC,IAAI,CAEN;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,MAAM,GACjB,yBAAyB,GAAG,SAAS,CAEvC;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAAC,IAAI,EAAE;IACtD,OAAO,EAAE,yBAAyB,CAAC;IACnC,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"cursor-account.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/cursor-account.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAEhB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAEpB;;;;GAIG;AACH,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IACjE,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;CAC7C;AAED,wBAAgB,8BAA8B,IAAI,wBAAwB,CAezE;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,sEAAsE;AACtE,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,0EAA0E;IAC1E,WAAW,EAAE,gBAAgB,CAAC;IAC9B,SAAS,EAAE,wBAAwB,CAAC;IACpC,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,mBAAmB,CAAC;IAClC,eAAe,EAAE,mBAAmB,CAAC;IACrC,MAAM,EAAE,MAAM,QAAQ,CAAC;CACxB;AAID,wBAAgB,iCAAiC,CAC/C,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,yBAAyB,GACjC,IAAI,CAEN;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,MAAM,GACjB,yBAAyB,GAAG,SAAS,CAEvC;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAAC,IAAI,EAAE;IACtD,OAAO,EAAE,yBAAyB,CAAC;IACnC,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,sBAAsB,CAAC,EAAE,CAAC,iBAAiB,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,kBAAkB,CAAC,EAAE,CAAC,iBAAiB,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrE,+BAA+B,CAAC,EAAE,CAChC,iBAAiB,EAAE,MAAM,KACtB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACjC,qBAAqB,CAAC,EAAE,CAAC,iBAAiB,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACzE,GAAG,OAAO,CAAC,IAAI,CAAC,CA+DhB"}
|
|
@@ -81,8 +81,18 @@ export function dispatchCursorSlackEnvelope(args) {
|
|
|
81
81
|
const isDm = envelope.channelType === "im" || envelope.channelId.startsWith("D");
|
|
82
82
|
const kind = isDm ? "direct_message" : "app_mention";
|
|
83
83
|
const handler = isDm ? runtime.onDirectMessage : runtime.onAppMention;
|
|
84
|
-
yield dispatchInboundMessage(Object.assign({ kind,
|
|
84
|
+
yield dispatchInboundMessage(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ kind,
|
|
85
85
|
message,
|
|
86
|
-
handler, send: args.send, credentials: runtime.credentials, host: args.host, log }, (
|
|
86
|
+
handler, send: args.send, credentials: runtime.credentials, host: args.host, log }, (args.hasContinuationSession === undefined
|
|
87
|
+
? {}
|
|
88
|
+
: { hasContinuationSession: args.hasContinuationSession })), (args.isContinuationBusy === undefined
|
|
89
|
+
? {}
|
|
90
|
+
: { isContinuationBusy: args.isContinuationBusy })), (args.getContinuationLastBotMessageTs === undefined
|
|
91
|
+
? {}
|
|
92
|
+
: {
|
|
93
|
+
getContinuationLastBotMessageTs: args.getContinuationLastBotMessageTs,
|
|
94
|
+
})), (args.interruptContinuation === undefined
|
|
95
|
+
? {}
|
|
96
|
+
: { interruptContinuation: args.interruptContinuation })), (envelope.eventId === undefined ? {} : { eventId: envelope.eventId })));
|
|
87
97
|
});
|
|
88
98
|
}
|
|
@@ -4,13 +4,16 @@
|
|
|
4
4
|
import type { ChannelEventHandlers } from "../../types.js";
|
|
5
5
|
import { type SlackLog } from "./log.js";
|
|
6
6
|
import type { SlackChannelState, SlackCredentials, SlackMessageHandler, SlackSuggestedPrompt } from "./types.js";
|
|
7
|
-
|
|
8
|
-
export declare
|
|
7
|
+
/** Default mention/DM inbound handler (optional custom loading rotation). */
|
|
8
|
+
export declare function createDefaultOnInbound(loadingMessages?: readonly string[]): SlackMessageHandler;
|
|
9
9
|
/**
|
|
10
|
-
* Default watched-channel-post handler
|
|
11
|
-
*
|
|
12
|
-
* `engagement: "channel_post"`
|
|
10
|
+
* Default watched-channel-post handler (optional custom loading rotation).
|
|
11
|
+
* Same thread-scoped principal as mentions, tagged with
|
|
12
|
+
* `engagement: "channel_post"` for auth policies.
|
|
13
13
|
*/
|
|
14
|
+
export declare function createDefaultOnChannelPost(loadingMessages?: readonly string[]): SlackMessageHandler;
|
|
15
|
+
export declare const defaultOnAppMention: SlackMessageHandler;
|
|
16
|
+
export declare const defaultOnDirectMessage: SlackMessageHandler;
|
|
14
17
|
export declare const defaultOnChannelPost: SlackMessageHandler;
|
|
15
18
|
export interface BuildDefaultEventsOptions {
|
|
16
19
|
credentials?: SlackCredentials;
|
|
@@ -18,6 +21,8 @@ export interface BuildDefaultEventsOptions {
|
|
|
18
21
|
thinkingSteps?: boolean;
|
|
19
22
|
suggestedPrompts?: SlackSuggestedPrompt[];
|
|
20
23
|
suggestedPromptsTitle?: string;
|
|
24
|
+
/** Rotating assistant status lines; defaults to pack constants. */
|
|
25
|
+
loadingMessages?: readonly string[];
|
|
21
26
|
/** Resolved per-call so channel onStart can rebind the server logger. */
|
|
22
27
|
getLog?: () => SlackLog;
|
|
23
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/defaults.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAe3D,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAE1D,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/defaults.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAe3D,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAE1D,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAWpB,6EAA6E;AAC7E,wBAAgB,sBAAsB,CACpC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,GAClC,mBAAmB,CAOrB;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,GAClC,mBAAmB,CASrB;AAED,eAAO,MAAM,mBAAmB,EAAE,mBACR,CAAC;AAC3B,eAAO,MAAM,sBAAsB,EAAE,mBACX,CAAC;AAC3B,eAAO,MAAM,oBAAoB,EAAE,mBACL,CAAC;AAE/B,MAAM,WAAW,yBAAyB;IACxC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,oBAAoB,EAAE,CAAC;IAC1C,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mEAAmE;IACnE,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,QAAQ,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,GAAE,yBAA8B,GACtC,oBAAoB,CAAC,iBAAiB,CAAC,CAiYzC"}
|
|
@@ -17,23 +17,39 @@ import { SLACK_DEFAULT_LOADING_MESSAGES, SLACK_TYPING_MIN_GROWTH, SLACK_TYPING_M
|
|
|
17
17
|
import { createStreamDeliveryStrategy } from "./live-delivery.js";
|
|
18
18
|
import { defaultSlackLog } from "./log.js";
|
|
19
19
|
import { buildTaskChunkForResult, buildTaskChunksForCalls } from "./stream.js";
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
function resolveLoadingMessages(loadingMessages) {
|
|
21
|
+
if (loadingMessages !== undefined && loadingMessages.length > 0) {
|
|
22
|
+
return [...loadingMessages];
|
|
23
|
+
}
|
|
24
|
+
return [...SLACK_DEFAULT_LOADING_MESSAGES];
|
|
25
|
+
}
|
|
26
|
+
/** Default mention/DM inbound handler (optional custom loading rotation). */
|
|
27
|
+
export function createDefaultOnInbound(loadingMessages) {
|
|
28
|
+
const rotating = resolveLoadingMessages(loadingMessages);
|
|
29
|
+
return (ctx, message) => __awaiter(this, void 0, void 0, function* () {
|
|
30
|
+
yield ctx.thread.startTyping("Thinking…", rotating);
|
|
31
|
+
const auth = defaultSlackAuth(message, ctx);
|
|
32
|
+
return auth === null ? null : { auth };
|
|
33
|
+
});
|
|
34
|
+
}
|
|
27
35
|
/**
|
|
28
|
-
* Default watched-channel-post handler
|
|
29
|
-
*
|
|
30
|
-
* `engagement: "channel_post"`
|
|
36
|
+
* Default watched-channel-post handler (optional custom loading rotation).
|
|
37
|
+
* Same thread-scoped principal as mentions, tagged with
|
|
38
|
+
* `engagement: "channel_post"` for auth policies.
|
|
31
39
|
*/
|
|
32
|
-
export
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
40
|
+
export function createDefaultOnChannelPost(loadingMessages) {
|
|
41
|
+
const rotating = resolveLoadingMessages(loadingMessages);
|
|
42
|
+
return (ctx, message) => __awaiter(this, void 0, void 0, function* () {
|
|
43
|
+
yield ctx.thread.startTyping("Thinking…", rotating);
|
|
44
|
+
const auth = defaultSlackAuth(message, ctx, {
|
|
45
|
+
engagement: "channel_post",
|
|
46
|
+
});
|
|
47
|
+
return auth === null ? null : { auth };
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export const defaultOnAppMention = createDefaultOnInbound();
|
|
51
|
+
export const defaultOnDirectMessage = createDefaultOnInbound();
|
|
52
|
+
export const defaultOnChannelPost = createDefaultOnChannelPost();
|
|
37
53
|
/**
|
|
38
54
|
* Build default stream-event handlers (typing, streaming, replies).
|
|
39
55
|
* Streaming / thinking default to ON.
|
|
@@ -48,6 +64,7 @@ export function buildDefaultEvents(options = {}) {
|
|
|
48
64
|
const thinkingSteps = options.thinkingSteps !== false;
|
|
49
65
|
const suggestedPrompts = (_a = options.suggestedPrompts) !== null && _a !== void 0 ? _a : [];
|
|
50
66
|
const suggestedPromptsTitle = options.suggestedPromptsTitle;
|
|
67
|
+
const loadingMessages = resolveLoadingMessages(options.loadingMessages);
|
|
51
68
|
const botToken = credentials === null || credentials === void 0 ? void 0 : credentials.botToken;
|
|
52
69
|
const getLog = (_b = options.getLog) !== null && _b !== void 0 ? _b : (() => defaultSlackLog);
|
|
53
70
|
const strategy = createStreamDeliveryStrategy({ botToken, getLog });
|
|
@@ -61,6 +78,7 @@ export function buildDefaultEvents(options = {}) {
|
|
|
61
78
|
channel.state.streamTs = null;
|
|
62
79
|
channel.state.streamChannelId = null;
|
|
63
80
|
channel.state.lastPostedText = null;
|
|
81
|
+
// Keep lastBotMessageTs across turns — warm delta watermark.
|
|
64
82
|
channel.state.approvalMessageByCallId = {};
|
|
65
83
|
const state = channel.state;
|
|
66
84
|
if (state.channelId === null || state.threadTs === null) {
|
|
@@ -77,7 +95,7 @@ export function buildDefaultEvents(options = {}) {
|
|
|
77
95
|
channelId: state.channelId,
|
|
78
96
|
threadTs: state.threadTs,
|
|
79
97
|
status: "Working…",
|
|
80
|
-
loadingMessages
|
|
98
|
+
loadingMessages,
|
|
81
99
|
});
|
|
82
100
|
// Retry streaming each turn unless a prior call proved the feature
|
|
83
101
|
// unsupported for this workspace/app. Thinking stays on setStatus
|
|
@@ -143,7 +161,10 @@ export function buildDefaultEvents(options = {}) {
|
|
|
143
161
|
channelId: channel.state.channelId,
|
|
144
162
|
threadTs: channel.state.threadTs,
|
|
145
163
|
status,
|
|
146
|
-
loadingMessages: [
|
|
164
|
+
loadingMessages: [
|
|
165
|
+
status,
|
|
166
|
+
...loadingMessages.filter((message) => message !== status),
|
|
167
|
+
],
|
|
147
168
|
});
|
|
148
169
|
channel.state.lastReasoningTypingAtMs = now;
|
|
149
170
|
channel.state.lastReasoningTypingStatus = status;
|
|
@@ -285,6 +306,7 @@ export function buildDefaultEvents(options = {}) {
|
|
|
285
306
|
threadTs: state.threadTs,
|
|
286
307
|
});
|
|
287
308
|
channel.state.lastPostedText = event.data.text;
|
|
309
|
+
channel.state.lastBotMessageTs = posted.ts;
|
|
288
310
|
log.info("reply delivered via postMessage", {
|
|
289
311
|
channel: state.channelId,
|
|
290
312
|
thread_ts: state.threadTs,
|
|
@@ -23,6 +23,20 @@ export interface SlackInboundDispatchDeps {
|
|
|
23
23
|
directMessagesEnabled?: boolean;
|
|
24
24
|
/** Opt-in channel watch; absent = channel posts are ignored. */
|
|
25
25
|
channelWatch?: ChannelPostWatcher;
|
|
26
|
+
/**
|
|
27
|
+
* When set, full-thread hydration runs only for cold-start turns (no
|
|
28
|
+
* existing session). Warm turns load a `<slack_thread_delta>` instead.
|
|
29
|
+
*/
|
|
30
|
+
hasContinuationSession?: (continuationToken: string) => Promise<boolean>;
|
|
31
|
+
/** True when a turn is already running for this Slack continuation. */
|
|
32
|
+
isContinuationBusy?: (continuationToken: string) => Promise<boolean>;
|
|
33
|
+
/**
|
|
34
|
+
* Warm-delta watermark from session channel state (`lastBotMessageTs`).
|
|
35
|
+
* When absent, delta falls back to the last matching bot post in-thread.
|
|
36
|
+
*/
|
|
37
|
+
getContinuationLastBotMessageTs?: (continuationToken: string) => Promise<string | undefined>;
|
|
38
|
+
/** Cancel the active turn + clear coalesced nudges for this continuation. */
|
|
39
|
+
interruptContinuation?: (continuationToken: string) => Promise<boolean>;
|
|
26
40
|
}
|
|
27
41
|
export declare function dispatchInboundMessage(args: {
|
|
28
42
|
kind: "app_mention" | "direct_message" | "channel_post";
|
|
@@ -31,6 +45,10 @@ export declare function dispatchInboundMessage(args: {
|
|
|
31
45
|
send: SendMessageFn;
|
|
32
46
|
credentials: SlackCredentials | undefined;
|
|
33
47
|
host: HostContext;
|
|
48
|
+
hasContinuationSession?: (continuationToken: string) => Promise<boolean>;
|
|
49
|
+
isContinuationBusy?: (continuationToken: string) => Promise<boolean>;
|
|
50
|
+
getContinuationLastBotMessageTs?: (continuationToken: string) => Promise<string | undefined>;
|
|
51
|
+
interruptContinuation?: (continuationToken: string) => Promise<boolean>;
|
|
34
52
|
log?: SlackLog;
|
|
35
53
|
eventId?: string;
|
|
36
54
|
}): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/dispatch.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/dispatch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAa,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG5E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAO1D,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAM1D,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAEhB,YAAY,EACZ,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAIpB,uCAAuC;AACvC,wBAAgB,sBAAsB,CACpC,KAAK,GAAE,OAAO,CAAC,iBAAiB,CAAM,GACrC,iBAAiB,CAiBnB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IAC/C,YAAY,EAAE,mBAAmB,CAAC;IAClC,eAAe,EAAE,mBAAmB,CAAC;IACrC,WAAW,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC1C,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,qDAAqD;IACrD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uDAAuD;IACvD,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,gEAAgE;IAChE,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAClC;;;OAGG;IACH,sBAAsB,CAAC,EAAE,CAAC,iBAAiB,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,uEAAuE;IACvE,kBAAkB,CAAC,EAAE,CAAC,iBAAiB,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrE;;;OAGG;IACH,+BAA+B,CAAC,EAAE,CAChC,iBAAiB,EAAE,MAAM,KACtB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACjC,6EAA6E;IAC7E,qBAAqB,CAAC,EAAE,CAAC,iBAAiB,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACzE;AAiBD,wBAAsB,sBAAsB,CAAC,IAAI,EAAE;IACjD,IAAI,EAAE,aAAa,GAAG,gBAAgB,GAAG,cAAc,CAAC;IACxD,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,IAAI,EAAE,aAAa,CAAC;IACpB,WAAW,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC1C,IAAI,EAAE,WAAW,CAAC;IAClB,sBAAsB,CAAC,EAAE,CAAC,iBAAiB,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,kBAAkB,CAAC,EAAE,CAAC,iBAAiB,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrE,+BAA+B,CAAC,EAAE,CAChC,iBAAiB,EAAE,MAAM,KACtB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACjC,qBAAqB,CAAC,EAAE,CAAC,iBAAiB,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACxE,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+OhB;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,wBAAwB,GAC7B,OAAO,CAsGT"}
|
|
@@ -10,22 +10,31 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
11
11
|
});
|
|
12
12
|
};
|
|
13
|
-
import { SessionBusyError } from "../../internal/session-engine.js";
|
|
14
13
|
import { buildSlackBinding, slackContinuationKey } from "./api.js";
|
|
15
14
|
import { firstLineTitle, maybeSetThreadTitle } from "./assistant.js";
|
|
16
15
|
import { formatSlackContextBlock, parseAppMentionEvent, parseChannelMessageEvent, parseDirectMessageEvent, } from "./inbound.js";
|
|
17
16
|
import { defaultSlackLog } from "./log.js";
|
|
18
|
-
|
|
17
|
+
import { isWholeMessageStop } from "./stop.js";
|
|
18
|
+
import { loadSlackThreadContextBlock, loadSlackThreadDeltaBlock, } from "./thread-context.js";
|
|
19
|
+
const FOLLOWUP_TYPING = "Saw your follow-up…";
|
|
19
20
|
/** Blank per-session adapter state. */
|
|
20
21
|
export function emptySlackChannelState(patch = {}) {
|
|
21
|
-
return Object.assign({ channelId: null, threadTs: null, teamId: null, triggeringUserId: null, pendingToolCallMessage: null, lastReasoningTypingAtMs: null, lastReasoningTypingStatus: null, streamTs: null, streamChannelId: null, lastPostedText: null, streamingUnavailable: false, approvalMessageByCallId: {} }, patch);
|
|
22
|
+
return Object.assign({ channelId: null, threadTs: null, teamId: null, triggeringUserId: null, pendingToolCallMessage: null, lastReasoningTypingAtMs: null, lastReasoningTypingStatus: null, streamTs: null, streamChannelId: null, lastPostedText: null, lastBotMessageTs: null, streamingUnavailable: false, approvalMessageByCallId: {} }, patch);
|
|
23
|
+
}
|
|
24
|
+
function triggeringMergeMessage(message) {
|
|
25
|
+
var _a, _b;
|
|
26
|
+
return Object.assign(Object.assign(Object.assign({ ts: message.ts }, (((_a = message.author) === null || _a === void 0 ? void 0 : _a.userId) === undefined || message.author.userId === ""
|
|
27
|
+
? {}
|
|
28
|
+
: { user: message.author.userId })), (((_b = message.author) === null || _b === void 0 ? void 0 : _b.botId) === undefined
|
|
29
|
+
? {}
|
|
30
|
+
: { bot_id: message.author.botId })), { text: message.text });
|
|
22
31
|
}
|
|
23
32
|
export function dispatchInboundMessage(args) {
|
|
24
33
|
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
-
var _a, _b, _c, _d, _e, _f;
|
|
26
|
-
var
|
|
34
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
35
|
+
var _m, _o, _p, _q, _r, _s, _t, _u;
|
|
27
36
|
const { message, kind } = args;
|
|
28
|
-
const log = (
|
|
37
|
+
const log = (_m = args.log) !== null && _m !== void 0 ? _m : defaultSlackLog;
|
|
29
38
|
const binding = buildSlackBinding(Object.assign({ botToken: (_a = args.credentials) === null || _a === void 0 ? void 0 : _a.botToken, channelId: message.channelId, threadTs: message.threadTs, host: args.host, log }, (message.teamId === undefined ? {} : { teamId: message.teamId })));
|
|
30
39
|
log.info("inbound", {
|
|
31
40
|
kind,
|
|
@@ -36,9 +45,32 @@ export function dispatchInboundMessage(args) {
|
|
|
36
45
|
user: (_b = message.author) === null || _b === void 0 ? void 0 : _b.userId,
|
|
37
46
|
team: message.teamId,
|
|
38
47
|
});
|
|
48
|
+
const continuation = slackContinuationKey(message.channelId, message.threadTs);
|
|
49
|
+
// Whole-message stop: cancel active turn + clear nudges (Benny parity).
|
|
50
|
+
if (isWholeMessageStop(message.text) ||
|
|
51
|
+
isWholeMessageStop(message.markdown)) {
|
|
52
|
+
log.info("stop directive", {
|
|
53
|
+
kind,
|
|
54
|
+
channel: message.channelId,
|
|
55
|
+
thread_ts: message.threadTs,
|
|
56
|
+
continuation,
|
|
57
|
+
event_id: args.eventId,
|
|
58
|
+
});
|
|
59
|
+
yield (_c = args.host.slackNudges) === null || _c === void 0 ? void 0 : _c.clear(continuation);
|
|
60
|
+
const interrupted = args.interruptContinuation === undefined
|
|
61
|
+
? false
|
|
62
|
+
: yield args.interruptContinuation(continuation);
|
|
63
|
+
try {
|
|
64
|
+
yield binding.thread.startTyping(interrupted ? "Stopped." : "Nothing to stop.");
|
|
65
|
+
}
|
|
66
|
+
catch (_v) {
|
|
67
|
+
// best-effort status
|
|
68
|
+
}
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
39
71
|
if (message.ts === message.threadTs) {
|
|
40
72
|
yield maybeSetThreadTitle({
|
|
41
|
-
botToken: (
|
|
73
|
+
botToken: (_d = args.credentials) === null || _d === void 0 ? void 0 : _d.botToken,
|
|
42
74
|
channelId: message.channelId,
|
|
43
75
|
threadTs: message.threadTs,
|
|
44
76
|
title: firstLineTitle(message.markdown),
|
|
@@ -67,47 +99,90 @@ export function dispatchInboundMessage(args) {
|
|
|
67
99
|
});
|
|
68
100
|
return;
|
|
69
101
|
}
|
|
70
|
-
|
|
102
|
+
// Reply-once / delayed parent: claim channel:ts after the handler accepts.
|
|
103
|
+
const claimed = yield (_e = args.host.slackNudges) === null || _e === void 0 ? void 0 : _e.tryClaimAsk(message.channelId, message.ts);
|
|
104
|
+
if (claimed === false) {
|
|
105
|
+
log.info("inbound ask dedupe drop", {
|
|
106
|
+
kind,
|
|
107
|
+
channel: message.channelId,
|
|
108
|
+
message_ts: message.ts,
|
|
109
|
+
continuation,
|
|
110
|
+
event_id: args.eventId,
|
|
111
|
+
});
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const userText = (_o = decision.message) !== null && _o !== void 0 ? _o : message.markdown;
|
|
115
|
+
const excludeThreadTimestamps = [
|
|
116
|
+
message.ts,
|
|
117
|
+
...((_p = decision.excludeThreadTimestamps) !== null && _p !== void 0 ? _p : []),
|
|
118
|
+
];
|
|
119
|
+
const hasSession = args.hasContinuationSession === undefined
|
|
120
|
+
? false
|
|
121
|
+
: yield args.hasContinuationSession(continuation);
|
|
122
|
+
const mergeMessages = [triggeringMergeMessage(message)];
|
|
123
|
+
const afterTs = hasSession && args.getContinuationLastBotMessageTs !== undefined
|
|
124
|
+
? yield args.getContinuationLastBotMessageTs(continuation)
|
|
125
|
+
: undefined;
|
|
126
|
+
// Cold start: full <slack_thread>. Warm: <slack_thread_delta> since last
|
|
127
|
+
// agent post (session watermark), else last matching bot post in-thread.
|
|
128
|
+
const threadContext = hasSession
|
|
129
|
+
? yield loadSlackThreadDeltaBlock(Object.assign(Object.assign({ botToken: (_f = args.credentials) === null || _f === void 0 ? void 0 : _f.botToken, channelId: message.channelId, threadTs: message.threadTs }, (afterTs === undefined ? {} : { afterTs })), { excludeTs: excludeThreadTimestamps, mergeMessages,
|
|
130
|
+
log }))
|
|
131
|
+
: yield loadSlackThreadContextBlock({
|
|
132
|
+
botToken: (_g = args.credentials) === null || _g === void 0 ? void 0 : _g.botToken,
|
|
133
|
+
channelId: message.channelId,
|
|
134
|
+
threadTs: message.threadTs,
|
|
135
|
+
excludeTs: excludeThreadTimestamps,
|
|
136
|
+
mergeMessages,
|
|
137
|
+
log,
|
|
138
|
+
});
|
|
139
|
+
if (threadContext !== undefined) {
|
|
140
|
+
log.info(hasSession ? "thread delta loaded" : "thread context loaded", Object.assign({ kind, channel: message.channelId, thread_ts: message.threadTs, chars: threadContext.length, event_id: args.eventId }, (afterTs === undefined ? {} : { after_ts: afterTs })));
|
|
141
|
+
}
|
|
71
142
|
const prompt = [
|
|
72
|
-
formatSlackContextBlock(Object.assign(Object.assign({ userId: (
|
|
143
|
+
formatSlackContextBlock(Object.assign(Object.assign({ userId: (_q = (_h = message.author) === null || _h === void 0 ? void 0 : _h.userId) !== null && _q !== void 0 ? _q : "", channelId: message.channelId, threadTs: message.threadTs }, (((_j = message.author) === null || _j === void 0 ? void 0 : _j.userName) === undefined
|
|
73
144
|
? {}
|
|
74
145
|
: { userName: message.author.userName })), (message.teamId === undefined ? {} : { teamId: message.teamId }))),
|
|
75
|
-
...(
|
|
146
|
+
...(threadContext === undefined ? [] : [threadContext]),
|
|
147
|
+
...((_r = decision.context) !== null && _r !== void 0 ? _r : []),
|
|
76
148
|
"",
|
|
77
149
|
userText,
|
|
78
150
|
]
|
|
79
151
|
.filter((part) => part.length > 0)
|
|
80
152
|
.join("\n");
|
|
81
|
-
const
|
|
153
|
+
const sendOptions = {
|
|
154
|
+
auth: decision.auth,
|
|
155
|
+
continuationToken: continuation,
|
|
156
|
+
admission: "coalesce",
|
|
157
|
+
coalesceSourceTs: message.ts,
|
|
158
|
+
state: emptySlackChannelState({
|
|
159
|
+
channelId: message.channelId,
|
|
160
|
+
threadTs: message.threadTs,
|
|
161
|
+
teamId: (_s = message.teamId) !== null && _s !== void 0 ? _s : null,
|
|
162
|
+
triggeringUserId: (_t = (_k = message.author) === null || _k === void 0 ? void 0 : _k.userId) !== null && _t !== void 0 ? _t : null,
|
|
163
|
+
}),
|
|
164
|
+
title: (_u = decision.title) !== null && _u !== void 0 ? _u : `slack:${message.channelId}:${message.threadTs}`,
|
|
165
|
+
workspaceDir: decision.workspaceDir,
|
|
166
|
+
workspaceFiles: decision.workspaceFiles,
|
|
167
|
+
cloud: decision.cloud,
|
|
168
|
+
sdkAgentId: decision.sdkAgentId,
|
|
169
|
+
};
|
|
82
170
|
try {
|
|
83
|
-
const session = yield args.send(prompt,
|
|
84
|
-
|
|
85
|
-
continuationToken: continuation,
|
|
86
|
-
state: emptySlackChannelState({
|
|
87
|
-
channelId: message.channelId,
|
|
88
|
-
threadTs: message.threadTs,
|
|
89
|
-
teamId: (_l = message.teamId) !== null && _l !== void 0 ? _l : null,
|
|
90
|
-
triggeringUserId: (_m = (_f = message.author) === null || _f === void 0 ? void 0 : _f.userId) !== null && _m !== void 0 ? _m : null,
|
|
91
|
-
}),
|
|
92
|
-
title: (_o = decision.title) !== null && _o !== void 0 ? _o : `slack:${message.channelId}:${message.threadTs}`,
|
|
93
|
-
workspaceDir: decision.workspaceDir,
|
|
94
|
-
workspaceFiles: decision.workspaceFiles,
|
|
95
|
-
cloud: decision.cloud,
|
|
96
|
-
sdkAgentId: decision.sdkAgentId,
|
|
97
|
-
});
|
|
98
|
-
log.info("session start", {
|
|
171
|
+
const session = yield args.send(prompt, sendOptions);
|
|
172
|
+
log.info(session.coalesced === true ? "session coalesced" : "session start", {
|
|
99
173
|
kind,
|
|
100
174
|
session: session.id,
|
|
101
175
|
is_new: session.isNew,
|
|
176
|
+
coalesced: session.coalesced === true,
|
|
102
177
|
continuation,
|
|
103
178
|
channel: message.channelId,
|
|
104
179
|
thread_ts: message.threadTs,
|
|
105
180
|
event_id: args.eventId,
|
|
106
181
|
});
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (
|
|
110
|
-
log.info("session busy;
|
|
182
|
+
// Coalesce admits leave the active turn running; follow-ups drain into one
|
|
183
|
+
// boundary turn when it finishes (no mid-turn tool/hook inject).
|
|
184
|
+
if (session.coalesced === true) {
|
|
185
|
+
log.info("session busy; coalescing follow-up", {
|
|
111
186
|
kind,
|
|
112
187
|
channel: message.channelId,
|
|
113
188
|
thread_ts: message.threadTs,
|
|
@@ -115,17 +190,21 @@ export function dispatchInboundMessage(args) {
|
|
|
115
190
|
event_id: args.eventId,
|
|
116
191
|
});
|
|
117
192
|
try {
|
|
118
|
-
yield binding.thread.
|
|
193
|
+
yield binding.thread.startTyping(FOLLOWUP_TYPING);
|
|
119
194
|
}
|
|
120
|
-
catch (
|
|
121
|
-
log.error(`
|
|
195
|
+
catch (typingError) {
|
|
196
|
+
log.error(`follow-up typing failed: ${typingError instanceof Error
|
|
197
|
+
? typingError.message
|
|
198
|
+
: String(typingError)}`, {
|
|
122
199
|
channel: message.channelId,
|
|
123
200
|
thread_ts: message.threadTs,
|
|
124
201
|
event_id: args.eventId,
|
|
125
202
|
});
|
|
126
203
|
}
|
|
127
|
-
return;
|
|
128
204
|
}
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
yield (_l = args.host.slackNudges) === null || _l === void 0 ? void 0 : _l.releaseAsk(message.channelId, message.ts);
|
|
129
208
|
log.error(`${kind} delivery failed: ${error instanceof Error ? error.message : String(error)}`, {
|
|
130
209
|
channel: message.channelId,
|
|
131
210
|
thread_ts: message.threadTs,
|
|
@@ -160,7 +239,17 @@ export function dispatchInboundFromEventBody(body, deps) {
|
|
|
160
239
|
log.debug("inbound ignored (mentions disabled)", { event_id: eventId });
|
|
161
240
|
return false;
|
|
162
241
|
}
|
|
163
|
-
deps.waitUntil(dispatchInboundMessage(Object.assign({ kind: "app_mention", message: mention, handler: deps.onAppMention, send: deps.send, credentials: deps.credentials, host: deps.host, log }, (
|
|
242
|
+
deps.waitUntil(dispatchInboundMessage(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ kind: "app_mention", message: mention, handler: deps.onAppMention, send: deps.send, credentials: deps.credentials, host: deps.host, log }, (deps.hasContinuationSession === undefined
|
|
243
|
+
? {}
|
|
244
|
+
: { hasContinuationSession: deps.hasContinuationSession })), (deps.isContinuationBusy === undefined
|
|
245
|
+
? {}
|
|
246
|
+
: { isContinuationBusy: deps.isContinuationBusy })), (deps.getContinuationLastBotMessageTs === undefined
|
|
247
|
+
? {}
|
|
248
|
+
: {
|
|
249
|
+
getContinuationLastBotMessageTs: deps.getContinuationLastBotMessageTs,
|
|
250
|
+
})), (deps.interruptContinuation === undefined
|
|
251
|
+
? {}
|
|
252
|
+
: { interruptContinuation: deps.interruptContinuation })), (eventId === undefined ? {} : { eventId }))));
|
|
164
253
|
return true;
|
|
165
254
|
}
|
|
166
255
|
const dm = parseDirectMessageEvent(body);
|
|
@@ -171,11 +260,25 @@ export function dispatchInboundFromEventBody(body, deps) {
|
|
|
171
260
|
});
|
|
172
261
|
return false;
|
|
173
262
|
}
|
|
174
|
-
deps.waitUntil(dispatchInboundMessage(Object.assign({ kind: "direct_message", message: dm, handler: deps.onDirectMessage, send: deps.send, credentials: deps.credentials, host: deps.host, log }, (
|
|
263
|
+
deps.waitUntil(dispatchInboundMessage(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ kind: "direct_message", message: dm, handler: deps.onDirectMessage, send: deps.send, credentials: deps.credentials, host: deps.host, log }, (deps.hasContinuationSession === undefined
|
|
264
|
+
? {}
|
|
265
|
+
: { hasContinuationSession: deps.hasContinuationSession })), (deps.isContinuationBusy === undefined
|
|
266
|
+
? {}
|
|
267
|
+
: { isContinuationBusy: deps.isContinuationBusy })), (deps.getContinuationLastBotMessageTs === undefined
|
|
268
|
+
? {}
|
|
269
|
+
: {
|
|
270
|
+
getContinuationLastBotMessageTs: deps.getContinuationLastBotMessageTs,
|
|
271
|
+
})), (deps.interruptContinuation === undefined
|
|
272
|
+
? {}
|
|
273
|
+
: { interruptContinuation: deps.interruptContinuation })), (eventId === undefined ? {} : { eventId }))));
|
|
175
274
|
return true;
|
|
176
275
|
}
|
|
177
276
|
if (deps.channelWatch !== undefined) {
|
|
178
|
-
|
|
277
|
+
// Parse keeps bot-authored posts; the watcher enforces the per-channel
|
|
278
|
+
// policy (includeBotPosts, own-post loop safety) with skip logging.
|
|
279
|
+
const channelEvent = parseChannelMessageEvent(body, {
|
|
280
|
+
includeBotAuthored: true,
|
|
281
|
+
});
|
|
179
282
|
if (channelEvent !== null) {
|
|
180
283
|
return deps.channelWatch.handle(channelEvent, eventId);
|
|
181
284
|
}
|