@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.
Files changed (179) hide show
  1. package/dist/bin/agent-serve.js +73 -19
  2. package/dist/channels/slack/channel-watch.d.ts +6 -1
  3. package/dist/channels/slack/channel-watch.d.ts.map +1 -1
  4. package/dist/channels/slack/channel-watch.js +22 -1
  5. package/dist/channels/slack/cursor-account.d.ts +4 -0
  6. package/dist/channels/slack/cursor-account.d.ts.map +1 -1
  7. package/dist/channels/slack/cursor-account.js +12 -2
  8. package/dist/channels/slack/defaults.d.ts +10 -5
  9. package/dist/channels/slack/defaults.d.ts.map +1 -1
  10. package/dist/channels/slack/defaults.js +39 -17
  11. package/dist/channels/slack/dispatch.d.ts +18 -0
  12. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  13. package/dist/channels/slack/dispatch.js +141 -38
  14. package/dist/channels/slack/inbound.d.ts +13 -3
  15. package/dist/channels/slack/inbound.d.ts.map +1 -1
  16. package/dist/channels/slack/inbound.js +17 -9
  17. package/dist/channels/slack/index.d.ts +4 -0
  18. package/dist/channels/slack/index.d.ts.map +1 -1
  19. package/dist/channels/slack/index.js +4 -0
  20. package/dist/channels/slack/live-delivery.d.ts.map +1 -1
  21. package/dist/channels/slack/live-delivery.js +1 -0
  22. package/dist/channels/slack/manifest.d.ts.map +1 -1
  23. package/dist/channels/slack/manifest.js +3 -0
  24. package/dist/channels/slack/nudge-carrier.d.ts +19 -0
  25. package/dist/channels/slack/nudge-carrier.d.ts.map +1 -0
  26. package/dist/channels/slack/nudge-carrier.js +166 -0
  27. package/dist/channels/slack/nudge-store.d.ts +61 -0
  28. package/dist/channels/slack/nudge-store.d.ts.map +1 -0
  29. package/dist/channels/slack/nudge-store.js +266 -0
  30. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  31. package/dist/channels/slack/slack-channel.js +74 -25
  32. package/dist/channels/slack/stop.d.ts +14 -0
  33. package/dist/channels/slack/stop.d.ts.map +1 -0
  34. package/dist/channels/slack/stop.js +22 -0
  35. package/dist/channels/slack/thread-context.d.ts +81 -0
  36. package/dist/channels/slack/thread-context.d.ts.map +1 -0
  37. package/dist/channels/slack/thread-context.js +470 -0
  38. package/dist/channels/slack/types.d.ts +27 -0
  39. package/dist/channels/slack/types.d.ts.map +1 -1
  40. package/dist/docs/404.html +2 -2
  41. package/dist/docs/ab.html +4 -4
  42. package/dist/docs/assets/{app.DMboGKUD.js → app.BP8mAVMW.js} +1 -1
  43. package/dist/docs/assets/chunks/@localSearchIndexroot.DevOabKJ.js +1 -0
  44. package/dist/docs/assets/chunks/{VPLocalSearchBox.DkEqEnJU.js → VPLocalSearchBox.1FXIZbz8.js} +1 -1
  45. package/dist/docs/assets/chunks/{theme.ASugdMNm.js → theme.Dm1R02v9.js} +2 -2
  46. package/dist/docs/assets/example-agents_index.md.CwtWu5ix.js +2 -0
  47. package/dist/docs/assets/{example-agents_index.md.CRqJlnIf.lean.js → example-agents_index.md.CwtWu5ix.lean.js} +1 -1
  48. package/dist/docs/assets/example-agents_oncall.md.BG_sUMly.js +10 -0
  49. package/dist/docs/assets/example-agents_oncall.md.BG_sUMly.lean.js +1 -0
  50. package/dist/docs/assets/{guides_slack.md.CCwqHvSV.js → guides_slack.md.FWale6Ip.js} +4 -3
  51. package/dist/docs/assets/{guides_slack.md.CCwqHvSV.lean.js → guides_slack.md.FWale6Ip.lean.js} +1 -1
  52. package/dist/docs/assets/{reference_sessions.md.DdjWabnN.js → reference_sessions.md.DLd6mvbv.js} +2 -2
  53. package/dist/docs/assets/{reference_sessions.md.DdjWabnN.lean.js → reference_sessions.md.DLd6mvbv.lean.js} +1 -1
  54. package/dist/docs/assets/{storage.md.CVnInNiN.js → storage.md.Cu3MwM2a.js} +3 -2
  55. package/dist/docs/assets/{storage.md.CVnInNiN.lean.js → storage.md.Cu3MwM2a.lean.js} +1 -1
  56. package/dist/docs/building-with-agents.html +4 -4
  57. package/dist/docs/concepts.html +4 -4
  58. package/dist/docs/deployment.html +4 -4
  59. package/dist/docs/evals.html +4 -4
  60. package/dist/docs/example-agents/approval-buddy.html +4 -4
  61. package/dist/docs/example-agents/benny.html +5 -5
  62. package/dist/docs/example-agents/bugbot.html +5 -5
  63. package/dist/docs/example-agents/codebase-wiki.html +4 -4
  64. package/dist/docs/example-agents/codeowners-review.html +4 -4
  65. package/dist/docs/example-agents/concierge.html +4 -4
  66. package/dist/docs/example-agents/fsd.html +4 -4
  67. package/dist/docs/example-agents/index.html +6 -6
  68. package/dist/docs/example-agents/knowledge-base.html +4 -4
  69. package/dist/docs/example-agents/oncall.html +34 -0
  70. package/dist/docs/example-agents/security-reviewer.html +4 -4
  71. package/dist/docs/example-agents/slack-agent.html +4 -4
  72. package/dist/docs/example-agents/weather-agent.html +4 -4
  73. package/dist/docs/guides/agent-to-agent.html +4 -4
  74. package/dist/docs/guides/cloud-runtime.html +4 -4
  75. package/dist/docs/guides/github.html +4 -4
  76. package/dist/docs/guides/human-in-the-loop.html +4 -4
  77. package/dist/docs/guides/slack.html +7 -6
  78. package/dist/docs/guides/webhooks.html +4 -4
  79. package/dist/docs/hashmap.json +1 -1
  80. package/dist/docs/hillclimbing.html +4 -4
  81. package/dist/docs/index.html +4 -4
  82. package/dist/docs/quickstart.html +4 -4
  83. package/dist/docs/reference/agent-config.html +4 -4
  84. package/dist/docs/reference/channels.html +4 -4
  85. package/dist/docs/reference/cli.html +4 -4
  86. package/dist/docs/reference/connections.html +4 -4
  87. package/dist/docs/reference/hooks.html +4 -4
  88. package/dist/docs/reference/http-api.html +4 -4
  89. package/dist/docs/reference/instructions.html +4 -4
  90. package/dist/docs/reference/playground.html +4 -4
  91. package/dist/docs/reference/project-layout.html +4 -4
  92. package/dist/docs/reference/schedules.html +4 -4
  93. package/dist/docs/reference/sessions.html +5 -5
  94. package/dist/docs/reference/skills.html +4 -4
  95. package/dist/docs/reference/subagents.html +4 -4
  96. package/dist/docs/reference/tools.html +4 -4
  97. package/dist/docs/scaffolding-agents.html +4 -4
  98. package/dist/docs/storage.html +7 -6
  99. package/dist/docs/troubleshooting.html +4 -4
  100. package/dist/evals.d.ts +2 -2
  101. package/dist/internal/cli-ax.d.ts +23 -10
  102. package/dist/internal/cli-ax.d.ts.map +1 -1
  103. package/dist/internal/cli-ax.js +358 -55
  104. package/dist/internal/cli-mcp.d.ts +64 -0
  105. package/dist/internal/cli-mcp.d.ts.map +1 -0
  106. package/dist/internal/cli-mcp.js +570 -0
  107. package/dist/internal/distribution.d.ts.map +1 -1
  108. package/dist/internal/distribution.js +2 -0
  109. package/dist/internal/eval-run-store.d.ts +2 -0
  110. package/dist/internal/eval-run-store.d.ts.map +1 -1
  111. package/dist/internal/eval-run-store.js +4 -4
  112. package/dist/internal/evals-client.d.ts +96 -0
  113. package/dist/internal/evals-client.d.ts.map +1 -0
  114. package/dist/internal/evals-client.js +262 -0
  115. package/dist/internal/host-kv.d.ts +17 -0
  116. package/dist/internal/host-kv.d.ts.map +1 -0
  117. package/dist/internal/host-kv.js +77 -0
  118. package/dist/internal/init-project.js +3 -3
  119. package/dist/internal/server.d.ts.map +1 -1
  120. package/dist/internal/server.js +19 -2
  121. package/dist/internal/session-engine.d.ts +42 -7
  122. package/dist/internal/session-engine.d.ts.map +1 -1
  123. package/dist/internal/session-engine.js +247 -51
  124. package/dist/internal/storage-coordinator.d.ts +18 -1
  125. package/dist/internal/storage-coordinator.d.ts.map +1 -1
  126. package/dist/internal/storage-coordinator.js +43 -0
  127. package/dist/playground/assets/index-Bpr4Th4M.js +319 -0
  128. package/dist/playground/index.html +1 -1
  129. package/dist/storage-backends/file-kv.d.ts +42 -0
  130. package/dist/storage-backends/file-kv.d.ts.map +1 -0
  131. package/dist/storage-backends/file-kv.js +190 -0
  132. package/dist/storage-backends/postgres-kv.d.ts +77 -0
  133. package/dist/storage-backends/postgres-kv.d.ts.map +1 -0
  134. package/dist/storage-backends/postgres-kv.js +180 -0
  135. package/dist/storage.d.ts +10 -1
  136. package/dist/storage.d.ts.map +1 -1
  137. package/dist/storage.js +10 -1
  138. package/dist/types.d.ts +79 -0
  139. package/dist/types.d.ts.map +1 -1
  140. package/docs/example-agents/index.md +14 -9
  141. package/docs/example-agents/oncall.md +216 -0
  142. package/docs/guides/slack.md +11 -2
  143. package/docs/reference/sessions.md +13 -4
  144. package/docs/storage.md +27 -0
  145. package/package.json +15 -1
  146. package/skills/framework-map/SKILL.md +6 -4
  147. package/src/bin/agent-serve.ts +79 -18
  148. package/src/channels/slack/channel-watch.ts +28 -1
  149. package/src/channels/slack/cursor-account.ts +20 -0
  150. package/src/channels/slack/defaults.ts +51 -20
  151. package/src/channels/slack/dispatch.ts +215 -40
  152. package/src/channels/slack/inbound.ts +30 -10
  153. package/src/channels/slack/index.ts +4 -0
  154. package/src/channels/slack/live-delivery.ts +1 -0
  155. package/src/channels/slack/manifest.ts +3 -0
  156. package/src/channels/slack/nudge-carrier.ts +182 -0
  157. package/src/channels/slack/nudge-store.ts +308 -0
  158. package/src/channels/slack/slack-channel.ts +106 -31
  159. package/src/channels/slack/stop.ts +25 -0
  160. package/src/channels/slack/thread-context.ts +572 -0
  161. package/src/channels/slack/types.ts +27 -0
  162. package/src/evals.ts +2 -2
  163. package/src/internal/cli-ax.ts +466 -75
  164. package/src/internal/cli-mcp.ts +708 -0
  165. package/src/internal/distribution.ts +2 -0
  166. package/src/internal/eval-run-store.ts +5 -0
  167. package/src/internal/evals-client.ts +431 -0
  168. package/src/internal/host-kv.ts +85 -0
  169. package/src/internal/init-project.ts +3 -3
  170. package/src/internal/server.ts +43 -0
  171. package/src/internal/session-engine.ts +351 -50
  172. package/src/internal/storage-coordinator.ts +41 -0
  173. package/src/storage-backends/file-kv.ts +221 -0
  174. package/src/storage-backends/postgres-kv.ts +248 -0
  175. package/src/storage.ts +11 -1
  176. package/src/types.ts +83 -0
  177. package/dist/docs/assets/chunks/@localSearchIndexroot.O6eP7QZr.js +0 -1
  178. package/dist/docs/assets/example-agents_index.md.CRqJlnIf.js +0 -2
  179. package/dist/playground/assets/index-mux9aj5P.js +0 -319
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Durable Slack follow-up nudge store (Benny-style).
3
+ *
4
+ * Mid-turn inject and boundary resume share one exactly-once contract:
5
+ * pending nudges rename into delivered/ keyed by source message ts.
6
+ */
7
+ export interface SlackNudgeRecord {
8
+ id: string;
9
+ continuationKey: string;
10
+ sourceTs: string;
11
+ text: string;
12
+ author?: string;
13
+ createdAt: string;
14
+ /** Content hash for pending dedupe. */
15
+ contentHash: string;
16
+ }
17
+ export interface SlackNudgeAppendInput {
18
+ continuationKey: string;
19
+ sourceTs: string;
20
+ text: string;
21
+ author?: string;
22
+ }
23
+ export declare function formatSlackFollowupNudgeBlock(nudges: readonly SlackNudgeRecord[]): string | undefined;
24
+ /**
25
+ * Filesystem nudge store under `<root>/<continuation>/pending|delivered`.
26
+ */
27
+ export declare class SlackNudgeStore {
28
+ private readonly rootDir;
29
+ constructor(rootDir: string);
30
+ private continuationDir;
31
+ private pendingDir;
32
+ private deliveredDir;
33
+ private deliveredPath;
34
+ append(input: SlackNudgeAppendInput): Promise<boolean>;
35
+ listPending(continuationKey: string): Promise<SlackNudgeRecord[]>;
36
+ isDelivered(continuationKey: string, sourceTs: string): Promise<boolean>;
37
+ hasUndelivered(continuationKey: string): Promise<boolean>;
38
+ /**
39
+ * Atomically move all pending nudges to delivered and return them.
40
+ * Already-delivered source ts values are dropped (exactly-once).
41
+ */
42
+ drainForInject(continuationKey: string): Promise<SlackNudgeRecord[]>;
43
+ clear(continuationKey: string): Promise<void>;
44
+ /** Drain + format for tool/hook inject. */
45
+ drainFormatted(continuationKey: string): Promise<string | undefined>;
46
+ }
47
+ /**
48
+ * Durable ask claim store: one marker per `channelId:message.ts` so delayed
49
+ * Slack redelivery cannot start a second full answer.
50
+ */
51
+ export declare class SlackAskDedupeStore {
52
+ private readonly rootDir;
53
+ constructor(rootDir: string);
54
+ private markerPath;
55
+ /** Returns true the first time this ask is claimed. */
56
+ tryClaim(channelId: string, messageTs: string): Promise<boolean>;
57
+ /** Drop a claim so a failed delivery can be retried. */
58
+ release(channelId: string, messageTs: string): Promise<void>;
59
+ wasClaimed(channelId: string, messageTs: string): Promise<boolean>;
60
+ }
61
+ //# sourceMappingURL=nudge-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nudge-store.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/nudge-store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA+BD,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAClC,MAAM,GAAG,SAAS,CAoBpB;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC,YAAY,OAAO,EAAE,MAAM,EAE1B;IAED,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,aAAa;IAIf,MAAM,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,OAAO,CAAC,CAqC3D;IAEK,WAAW,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA6BtE;IAEK,WAAW,CACf,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAUlB;IAEK,cAAc,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE9D;IAED;;;OAGG;IACG,cAAc,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA8BzE;IAEK,KAAK,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKlD;IAED,2CAA2C;IACrC,cAAc,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAIzE;CACF;AAED;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC,YAAY,OAAO,EAAE,MAAM,EAE1B;IAED,OAAO,CAAC,UAAU;IAOlB,uDAAuD;IACjD,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAerE;IAED,wDAAwD;IAClD,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKjE;IAEK,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOvE;CACF"}
@@ -0,0 +1,266 @@
1
+ /**
2
+ * Durable Slack follow-up nudge store (Benny-style).
3
+ *
4
+ * Mid-turn inject and boundary resume share one exactly-once contract:
5
+ * pending nudges rename into delivered/ keyed by source message ts.
6
+ */
7
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
8
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
9
+ return new (P || (P = Promise))(function (resolve, reject) {
10
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
11
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
12
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
13
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
14
+ });
15
+ };
16
+ import { createHash, randomBytes } from "node:crypto";
17
+ import { mkdir, readdir, readFile, rename, rm, writeFile, } from "node:fs/promises";
18
+ import { join } from "node:path";
19
+ /**
20
+ * Map an arbitrary key onto a single path segment under the store root.
21
+ * Rejects empty / `.` / `..` and strips remaining dots so path traversal
22
+ * cannot escape `<stateRoot>/slack-nudges` (or `slack-asks`).
23
+ */
24
+ function safeKey(continuationKey) {
25
+ const trimmed = continuationKey.trim();
26
+ if (trimmed === "" || trimmed === "." || trimmed === "..") {
27
+ return "_empty";
28
+ }
29
+ const sanitized = trimmed
30
+ .replace(/[^a-zA-Z0-9._-]+/g, "_")
31
+ .replace(/^\.+/, "")
32
+ .replace(/\.+/g, "_")
33
+ .slice(0, 180);
34
+ if (sanitized === "" || sanitized === "." || sanitized === "..") {
35
+ return "_empty";
36
+ }
37
+ return sanitized;
38
+ }
39
+ function contentHash(text) {
40
+ return createHash("sha256").update(text).digest("hex").slice(0, 16);
41
+ }
42
+ function newNudgeId() {
43
+ return `nudge_${randomBytes(8).toString("hex")}`;
44
+ }
45
+ export function formatSlackFollowupNudgeBlock(nudges) {
46
+ if (nudges.length === 0) {
47
+ return undefined;
48
+ }
49
+ const lines = [
50
+ "<slack_followup>",
51
+ "New Slack follow-up(s) arrived while you were working. Incorporate them before your final reply. If an ask was already answered in-thread, ack briefly instead of re-answering.",
52
+ "",
53
+ ];
54
+ for (const nudge of nudges) {
55
+ const who = nudge.author === undefined || nudge.author === ""
56
+ ? "someone"
57
+ : nudge.author;
58
+ lines.push(`- ${who} @ ${nudge.sourceTs}:`);
59
+ lines.push(nudge.text.trim() === "" ? "(empty)" : nudge.text.trim());
60
+ lines.push("");
61
+ }
62
+ lines.push("</slack_followup>");
63
+ return lines.join("\n").trimEnd();
64
+ }
65
+ /**
66
+ * Filesystem nudge store under `<root>/<continuation>/pending|delivered`.
67
+ */
68
+ export class SlackNudgeStore {
69
+ constructor(rootDir) {
70
+ this.rootDir = rootDir;
71
+ }
72
+ continuationDir(continuationKey) {
73
+ return join(this.rootDir, safeKey(continuationKey));
74
+ }
75
+ pendingDir(continuationKey) {
76
+ return join(this.continuationDir(continuationKey), "pending");
77
+ }
78
+ deliveredDir(continuationKey) {
79
+ return join(this.continuationDir(continuationKey), "delivered");
80
+ }
81
+ deliveredPath(continuationKey, sourceTs) {
82
+ return join(this.deliveredDir(continuationKey), safeKey(sourceTs));
83
+ }
84
+ append(input) {
85
+ return __awaiter(this, void 0, void 0, function* () {
86
+ const continuationKey = input.continuationKey.trim();
87
+ const sourceTs = input.sourceTs.trim();
88
+ const text = input.text.trim();
89
+ if (continuationKey === "" || sourceTs === "" || text === "") {
90
+ return false;
91
+ }
92
+ if (yield this.isDelivered(continuationKey, sourceTs)) {
93
+ return false;
94
+ }
95
+ const pending = yield this.listPending(continuationKey);
96
+ const hash = contentHash(text);
97
+ if (pending.some((item) => item.sourceTs === sourceTs || item.contentHash === hash)) {
98
+ return false;
99
+ }
100
+ const record = Object.assign(Object.assign({ id: newNudgeId(), continuationKey,
101
+ sourceTs,
102
+ text }, (input.author === undefined || input.author === ""
103
+ ? {}
104
+ : { author: input.author })), { createdAt: new Date().toISOString(), contentHash: hash });
105
+ const dir = this.pendingDir(continuationKey);
106
+ yield mkdir(dir, { recursive: true });
107
+ const target = join(dir, `${record.id}.json`);
108
+ const tmp = `${target}.${process.pid}.tmp`;
109
+ yield writeFile(tmp, `${JSON.stringify(record)}\n`, "utf8");
110
+ yield rename(tmp, target);
111
+ return true;
112
+ });
113
+ }
114
+ listPending(continuationKey) {
115
+ return __awaiter(this, void 0, void 0, function* () {
116
+ const dir = this.pendingDir(continuationKey);
117
+ let names;
118
+ try {
119
+ names = yield readdir(dir);
120
+ }
121
+ catch (_a) {
122
+ return [];
123
+ }
124
+ const records = [];
125
+ for (const name of names) {
126
+ if (!name.endsWith(".json")) {
127
+ continue;
128
+ }
129
+ try {
130
+ const raw = yield readFile(join(dir, name), "utf8");
131
+ const parsed = JSON.parse(raw);
132
+ if (typeof parsed.id === "string" &&
133
+ typeof parsed.sourceTs === "string" &&
134
+ typeof parsed.text === "string") {
135
+ records.push(parsed);
136
+ }
137
+ }
138
+ catch (_b) {
139
+ // Skip corrupt pending files.
140
+ }
141
+ }
142
+ records.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
143
+ return records;
144
+ });
145
+ }
146
+ isDelivered(continuationKey, sourceTs) {
147
+ return __awaiter(this, void 0, void 0, function* () {
148
+ if (continuationKey.trim() === "" || sourceTs.trim() === "") {
149
+ return false;
150
+ }
151
+ try {
152
+ yield readFile(this.deliveredPath(continuationKey, sourceTs), "utf8");
153
+ return true;
154
+ }
155
+ catch (_a) {
156
+ return false;
157
+ }
158
+ });
159
+ }
160
+ hasUndelivered(continuationKey) {
161
+ return __awaiter(this, void 0, void 0, function* () {
162
+ return (yield this.listPending(continuationKey)).length > 0;
163
+ });
164
+ }
165
+ /**
166
+ * Atomically move all pending nudges to delivered and return them.
167
+ * Already-delivered source ts values are dropped (exactly-once).
168
+ */
169
+ drainForInject(continuationKey) {
170
+ return __awaiter(this, void 0, void 0, function* () {
171
+ const pending = yield this.listPending(continuationKey);
172
+ if (pending.length === 0) {
173
+ return [];
174
+ }
175
+ yield mkdir(this.deliveredDir(continuationKey), { recursive: true });
176
+ const delivered = [];
177
+ for (const record of pending) {
178
+ const pendingPath = join(this.pendingDir(continuationKey), `${record.id}.json`);
179
+ if (yield this.isDelivered(continuationKey, record.sourceTs)) {
180
+ yield rm(pendingPath, { force: true });
181
+ continue;
182
+ }
183
+ const dest = this.deliveredPath(continuationKey, record.sourceTs);
184
+ const tmp = `${dest}.${process.pid}.tmp`;
185
+ try {
186
+ yield writeFile(tmp, `${JSON.stringify(record)}\n`, "utf8");
187
+ yield rename(tmp, dest);
188
+ yield rm(pendingPath, { force: true });
189
+ delivered.push(record);
190
+ }
191
+ catch (_a) {
192
+ yield rm(tmp, { force: true }).catch(() => { });
193
+ // Race: another drain won — treat as delivered.
194
+ yield rm(pendingPath, { force: true }).catch(() => { });
195
+ }
196
+ }
197
+ return delivered;
198
+ });
199
+ }
200
+ clear(continuationKey) {
201
+ return __awaiter(this, void 0, void 0, function* () {
202
+ yield rm(this.continuationDir(continuationKey), {
203
+ recursive: true,
204
+ force: true,
205
+ });
206
+ });
207
+ }
208
+ /** Drain + format for tool/hook inject. */
209
+ drainFormatted(continuationKey) {
210
+ return __awaiter(this, void 0, void 0, function* () {
211
+ return formatSlackFollowupNudgeBlock(yield this.drainForInject(continuationKey));
212
+ });
213
+ }
214
+ }
215
+ /**
216
+ * Durable ask claim store: one marker per `channelId:message.ts` so delayed
217
+ * Slack redelivery cannot start a second full answer.
218
+ */
219
+ export class SlackAskDedupeStore {
220
+ constructor(rootDir) {
221
+ this.rootDir = rootDir;
222
+ }
223
+ markerPath(channelId, messageTs) {
224
+ return join(this.rootDir, `${safeKey(channelId)}__${safeKey(messageTs)}.claimed`);
225
+ }
226
+ /** Returns true the first time this ask is claimed. */
227
+ tryClaim(channelId, messageTs) {
228
+ return __awaiter(this, void 0, void 0, function* () {
229
+ if (channelId.trim() === "" || messageTs.trim() === "") {
230
+ return false;
231
+ }
232
+ const path = this.markerPath(channelId, messageTs);
233
+ yield mkdir(this.rootDir, { recursive: true });
234
+ try {
235
+ yield writeFile(path, `${new Date().toISOString()}\n`, {
236
+ encoding: "utf8",
237
+ flag: "wx",
238
+ });
239
+ return true;
240
+ }
241
+ catch (_a) {
242
+ return false;
243
+ }
244
+ });
245
+ }
246
+ /** Drop a claim so a failed delivery can be retried. */
247
+ release(channelId, messageTs) {
248
+ return __awaiter(this, void 0, void 0, function* () {
249
+ if (channelId.trim() === "" || messageTs.trim() === "") {
250
+ return;
251
+ }
252
+ yield rm(this.markerPath(channelId, messageTs), { force: true });
253
+ });
254
+ }
255
+ wasClaimed(channelId, messageTs) {
256
+ return __awaiter(this, void 0, void 0, function* () {
257
+ try {
258
+ yield readFile(this.markerPath(channelId, messageTs), "utf8");
259
+ return true;
260
+ }
261
+ catch (_a) {
262
+ return false;
263
+ }
264
+ });
265
+ }
266
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"slack-channel.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/slack-channel.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,iBAAiB,EAMlB,MAAM,gBAAgB,CAAC;AAuCxB,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAC1B,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,EAC7D,OAAO,GAAE,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,GAAG;IAChD,SAAS,CAAC,EAAE,oBAAoB,CAAC,IAAI,CAAC,CAAC;CACnC,GACL,iBAAiB,CAAC,iBAAiB,CAAC,CAyTtC"}
1
+ {"version":3,"file":"slack-channel.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/slack-channel.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,iBAAiB,EAMlB,MAAM,gBAAgB,CAAC;AAsCxB,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EAC1B,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,CAAC,IAAI,SAAS,MAAM,GAAG,MAAM,EAC7D,OAAO,GAAE,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,GAAG;IAChD,SAAS,CAAC,EAAE,oBAAoB,CAAC,IAAI,CAAC,CAAC;CACnC,GACL,iBAAiB,CAAC,iBAAiB,CAAC,CAqYtC"}
@@ -20,7 +20,7 @@ import { slackContinuationKey } from "./api.js";
20
20
  import { createChannelPostWatcher, resolveChannelNames, SlackChannelAllowlist, } from "./channel-watch.js";
21
21
  import { credentialsFromEnv, slackEnvKeys, tryResolveAppToken, tryResolveBotToken, } from "./credentials.js";
22
22
  import { createPendingSlackApiTransport, registerSlackCursorAccountRuntime, } from "./cursor-account.js";
23
- import { buildDefaultEvents, defaultOnAppMention, defaultOnChannelPost, defaultOnDirectMessage, } from "./defaults.js";
23
+ import { buildDefaultEvents, createDefaultOnChannelPost, createDefaultOnInbound, } from "./defaults.js";
24
24
  import { dispatchInboundFromEventBody, dispatchInboundMessage, emptySlackChannelState, } from "./dispatch.js";
25
25
  import { createEventIdDedupe } from "./event-id-dedupe.js";
26
26
  import { dispatchInteractiveFromPayload } from "./interactive.js";
@@ -82,9 +82,11 @@ export function slackChannel(options = {}) {
82
82
  ? { botToken: accountTransport }
83
83
  : ((_d = options.credentials) !== null && _d !== void 0 ? _d : credentialsFromEnv(options.envPrefix));
84
84
  const envKeys = slackEnvKeys(options.envPrefix);
85
- const onAppMention = (_e = options.onAppMention) !== null && _e !== void 0 ? _e : defaultOnAppMention;
86
- const onDirectMessage = (_f = options.onDirectMessage) !== null && _f !== void 0 ? _f : defaultOnDirectMessage;
87
- const onChannelPost = (_g = options.onChannelPost) !== null && _g !== void 0 ? _g : defaultOnChannelPost;
85
+ const loadingMessages = options.loadingMessages;
86
+ const defaultInbound = createDefaultOnInbound(loadingMessages);
87
+ const onAppMention = (_e = options.onAppMention) !== null && _e !== void 0 ? _e : defaultInbound;
88
+ const onDirectMessage = (_f = options.onDirectMessage) !== null && _f !== void 0 ? _f : defaultInbound;
89
+ const onChannelPost = (_g = options.onChannelPost) !== null && _g !== void 0 ? _g : createDefaultOnChannelPost(loadingMessages);
88
90
  const engagement = (_h = options.engagement) !== null && _h !== void 0 ? _h : {};
89
91
  const mentionsEnabled = engagement.mentions !== false;
90
92
  const directMessagesEnabled = engagement.directMessages !== false;
@@ -113,6 +115,7 @@ export function slackChannel(options = {}) {
113
115
  thinkingSteps: options.thinkingSteps,
114
116
  suggestedPrompts: options.suggestedPrompts,
115
117
  suggestedPromptsTitle: options.suggestedPromptsTitle,
118
+ loadingMessages,
116
119
  getLog,
117
120
  }));
118
121
  }
@@ -123,11 +126,21 @@ export function slackChannel(options = {}) {
123
126
  let socketHandle = null;
124
127
  let channelWatch;
125
128
  function inboundDeps(args) {
126
- return Object.assign({ send: args.send, waitUntil: args.waitUntil, onAppMention,
129
+ return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ send: args.send, waitUntil: args.waitUntil, onAppMention,
127
130
  onDirectMessage,
128
131
  credentials,
129
132
  eventIds, host: args.host, log: getLog(), mentionsEnabled,
130
- directMessagesEnabled }, (channelWatch === undefined ? {} : { channelWatch }));
133
+ directMessagesEnabled }, (args.hasContinuationSession === undefined
134
+ ? {}
135
+ : { hasContinuationSession: args.hasContinuationSession })), (args.isContinuationBusy === undefined
136
+ ? {}
137
+ : { isContinuationBusy: args.isContinuationBusy })), (args.getContinuationLastBotMessageTs === undefined
138
+ ? {}
139
+ : {
140
+ getContinuationLastBotMessageTs: args.getContinuationLastBotMessageTs,
141
+ })), (args.interruptContinuation === undefined
142
+ ? {}
143
+ : { interruptContinuation: args.interruptContinuation })), (channelWatch === undefined ? {} : { channelWatch }));
131
144
  }
132
145
  const definition = defineChannel({
133
146
  auth: [allowAll()],
@@ -156,6 +169,7 @@ export function slackChannel(options = {}) {
156
169
  });
157
170
  return send(input.message, {
158
171
  auth: input.auth,
172
+ admission: "coalesce",
159
173
  continuationToken: slackContinuationKey(channelId, threadTs),
160
174
  state: emptySlackChannelState({
161
175
  channelId,
@@ -190,12 +204,15 @@ export function slackChannel(options = {}) {
190
204
  if (channelPosts !== undefined) {
191
205
  const allowlist = new SlackChannelAllowlist(channelPosts.allow);
192
206
  let botUserId;
207
+ let botId;
193
208
  try {
194
209
  const { WebClient } = yield import("@slack/web-api");
195
210
  const client = new WebClient(botToken);
196
211
  const identity = yield client.auth.test();
197
212
  botUserId =
198
213
  typeof identity.user_id === "string" ? identity.user_id : undefined;
214
+ botId =
215
+ typeof identity.bot_id === "string" ? identity.bot_id : undefined;
199
216
  const names = allowlist.unresolvedNames();
200
217
  if (names.length > 0) {
201
218
  allowlist.applyResolvedNames(yield resolveChannelNames(client, names, getLog()));
@@ -206,30 +223,60 @@ export function slackChannel(options = {}) {
206
223
  error: error instanceof Error ? error.message : String(error),
207
224
  });
208
225
  }
209
- channelWatch = createChannelPostWatcher({
210
- options: channelPosts,
211
- allowlist,
212
- getBotUserId: () => botUserId,
213
- log: getLog(),
214
- dispatch: (message, eventId) => {
215
- args.waitUntil(dispatchInboundMessage(Object.assign({ kind: "channel_post", message, handler: onChannelPost, send: args.send, credentials, host: args.host, log: getLog() }, (eventId === undefined ? {} : { eventId }))));
216
- },
217
- });
218
- getLog().info("channel watch enabled", {
219
- channels: channelPosts.allow.join(","),
220
- posts: (_b = channelPosts.posts) !== null && _b !== void 0 ? _b : "top-level",
221
- debounce_ms: (_c = channelPosts.debounceMs) !== null && _c !== void 0 ? _c : 0,
222
- });
226
+ if (channelPosts.includeBotPosts === true &&
227
+ botUserId === undefined &&
228
+ botId === undefined) {
229
+ getLog().error("channel watch disabled", {
230
+ reason: "includeBotPosts requires bot identity from auth.test (loop safety)",
231
+ });
232
+ }
233
+ else {
234
+ channelWatch = createChannelPostWatcher({
235
+ options: channelPosts,
236
+ allowlist,
237
+ getBotUserId: () => botUserId,
238
+ getBotId: () => botId,
239
+ log: getLog(),
240
+ dispatch: (message, eventId) => {
241
+ args.waitUntil(dispatchInboundMessage(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ kind: "channel_post", message, handler: onChannelPost, send: args.send, credentials, host: args.host, log: getLog() }, (args.hasContinuationSession === undefined
242
+ ? {}
243
+ : {
244
+ hasContinuationSession: args.hasContinuationSession,
245
+ })), (args.isContinuationBusy === undefined
246
+ ? {}
247
+ : { isContinuationBusy: args.isContinuationBusy })), (args.getContinuationLastBotMessageTs === undefined
248
+ ? {}
249
+ : {
250
+ getContinuationLastBotMessageTs: args.getContinuationLastBotMessageTs,
251
+ })), (args.interruptContinuation === undefined
252
+ ? {}
253
+ : {
254
+ interruptContinuation: args.interruptContinuation,
255
+ })), (eventId === undefined ? {} : { eventId }))));
256
+ },
257
+ });
258
+ getLog().info("channel watch enabled", {
259
+ channels: channelPosts.allow.join(","),
260
+ posts: (_b = channelPosts.posts) !== null && _b !== void 0 ? _b : "top-level",
261
+ debounce_ms: (_c = channelPosts.debounceMs) !== null && _c !== void 0 ? _c : 0,
262
+ });
263
+ }
223
264
  }
224
265
  const socketOptions = {
225
266
  appToken,
226
267
  logger: (line) => getLog().write(line),
227
268
  onEvent: (payload) => {
228
- dispatchInboundFromEventBody(payload, inboundDeps({
229
- send: args.send,
230
- waitUntil: args.waitUntil,
231
- host: args.host,
232
- }));
269
+ dispatchInboundFromEventBody(payload, inboundDeps(Object.assign(Object.assign(Object.assign(Object.assign({ send: args.send, waitUntil: args.waitUntil, host: args.host }, (args.hasContinuationSession === undefined
270
+ ? {}
271
+ : { hasContinuationSession: args.hasContinuationSession })), (args.isContinuationBusy === undefined
272
+ ? {}
273
+ : { isContinuationBusy: args.isContinuationBusy })), (args.getContinuationLastBotMessageTs === undefined
274
+ ? {}
275
+ : {
276
+ getContinuationLastBotMessageTs: args.getContinuationLastBotMessageTs,
277
+ })), (args.interruptContinuation === undefined
278
+ ? {}
279
+ : { interruptContinuation: args.interruptContinuation }))));
233
280
  },
234
281
  };
235
282
  if (routeInteractive) {
@@ -264,11 +311,13 @@ export function slackChannel(options = {}) {
264
311
  });
265
312
  },
266
313
  onStop: () => __awaiter(this, void 0, void 0, function* () {
314
+ var _a;
267
315
  getLog().info("channel stop");
268
316
  channelWatch === null || channelWatch === void 0 ? void 0 : channelWatch.stop();
269
317
  channelWatch = undefined;
270
318
  yield socketHandle === null || socketHandle === void 0 ? void 0 : socketHandle.stop();
271
319
  socketHandle = null;
320
+ yield (_a = options.onStop) === null || _a === void 0 ? void 0 : _a.call(options);
272
321
  }),
273
322
  });
274
323
  if (accountTransport !== undefined) {
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Whole-message Slack "stop" directive (Benny parity).
3
+ *
4
+ * A message whose body is only `@bot stop` / `stop` cancels the active turn.
5
+ * The word "stop" embedded in a longer message is not a directive.
6
+ */
7
+ /** Strip leading Slack user mentions and surrounding whitespace. */
8
+ export declare function stripLeadingSlackMentions(text: string): string;
9
+ /**
10
+ * True when the message (after stripping @mentions) is exactly `stop`
11
+ * (case-insensitive).
12
+ */
13
+ export declare function isWholeMessageStop(text: string): boolean;
14
+ //# sourceMappingURL=stop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/stop.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,oEAAoE;AACpE,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Whole-message Slack "stop" directive (Benny parity).
3
+ *
4
+ * A message whose body is only `@bot stop` / `stop` cancels the active turn.
5
+ * The word "stop" embedded in a longer message is not a directive.
6
+ */
7
+ const MENTION_RE = /^<@[A-Z0-9]+>\s*/i;
8
+ /** Strip leading Slack user mentions and surrounding whitespace. */
9
+ export function stripLeadingSlackMentions(text) {
10
+ let current = text.trim();
11
+ while (MENTION_RE.test(current)) {
12
+ current = current.replace(MENTION_RE, "").trim();
13
+ }
14
+ return current;
15
+ }
16
+ /**
17
+ * True when the message (after stripping @mentions) is exactly `stop`
18
+ * (case-insensitive).
19
+ */
20
+ export function isWholeMessageStop(text) {
21
+ return stripLeadingSlackMentions(text).toLowerCase() === "stop";
22
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Fetch prior Slack thread messages and format them for the model prompt.
3
+ *
4
+ * Cold-start mentions (`@agent what happened here?`) only carry the mention
5
+ * text; the parent alert / earlier replies live in `conversations.replies`.
6
+ */
7
+ import { type SlackLog } from "./log.js";
8
+ import type { SlackBotToken } from "./types.js";
9
+ /** Keep the thread root plus the newest replies when over the fetch cap. */
10
+ export declare function trimThreadMessagesForPrompt(messages: JsonRecord[], options: {
11
+ threadTs: string;
12
+ limit: number;
13
+ excludeTs?: string | readonly string[];
14
+ }): JsonRecord[];
15
+ type JsonRecord = Record<string, unknown>;
16
+ /** Pull readable text out of Slack attachment / Block Kit payloads. */
17
+ export declare function slackApiMessageBody(message: JsonRecord): string;
18
+ /** True when `ts` is strictly after `afterTs`. */
19
+ export declare function isSlackTsAfter(ts: string, afterTs: string): boolean;
20
+ /**
21
+ * Merge triggering messages (by ts) into a replies window when Slack lag
22
+ * omits them from `conversations.replies`.
23
+ */
24
+ export declare function mergeThreadMessagesByTs(messages: JsonRecord[], extras: readonly JsonRecord[]): JsonRecord[];
25
+ /**
26
+ * Latest bot-authored message ts in a thread (own posts), used as the warm
27
+ * delta watermark when channel state has not recorded one yet.
28
+ */
29
+ export declare function findLastBotMessageTs(messages: readonly JsonRecord[], options?: {
30
+ botUserId?: string;
31
+ botId?: string;
32
+ }): string | undefined;
33
+ /** Messages strictly after `afterTs`, excluding listed timestamps. */
34
+ export declare function selectThreadDeltaMessages(messages: JsonRecord[], options: {
35
+ afterTs?: string;
36
+ excludeTs?: string | readonly string[];
37
+ }): JsonRecord[];
38
+ export declare function formatSlackThreadContextBlock(messages: JsonRecord[], options?: {
39
+ threadTs?: string;
40
+ excludeTs?: string | readonly string[];
41
+ maxChars?: number;
42
+ }): string | undefined;
43
+ export declare function formatSlackThreadDeltaBlock(messages: JsonRecord[], options?: {
44
+ excludeTs?: string | readonly string[];
45
+ afterTs?: string;
46
+ maxChars?: number;
47
+ }): string | undefined;
48
+ /**
49
+ * Load prior messages in a Slack thread and return a prompt context block.
50
+ * Soft-fails (returns undefined) when credentials are missing or the API errors.
51
+ */
52
+ export declare function loadSlackThreadContextBlock(args: {
53
+ botToken: SlackBotToken | undefined;
54
+ channelId: string;
55
+ threadTs: string;
56
+ excludeTs?: string | readonly string[];
57
+ log?: SlackLog;
58
+ limit?: number;
59
+ maxChars?: number;
60
+ /** Extra messages merged by ts when Slack replies lag (Benny parity). */
61
+ mergeMessages?: readonly JsonRecord[];
62
+ }): Promise<string | undefined>;
63
+ /**
64
+ * Warm-turn delta: messages since the last bot post (or all new replies when
65
+ * the watermark is unknown), with optional merge-by-ts for the triggering ask.
66
+ */
67
+ export declare function loadSlackThreadDeltaBlock(args: {
68
+ botToken: SlackBotToken | undefined;
69
+ channelId: string;
70
+ threadTs: string;
71
+ /** Watermark from channel state (`lastBotMessageTs`). */
72
+ afterTs?: string;
73
+ excludeTs?: string | readonly string[];
74
+ log?: SlackLog;
75
+ maxChars?: number;
76
+ mergeMessages?: readonly JsonRecord[];
77
+ botUserId?: string;
78
+ botId?: string;
79
+ }): Promise<string | undefined>;
80
+ export {};
81
+ //# sourceMappingURL=thread-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread-context.d.ts","sourceRoot":"","sources":["../../../src/channels/slack/thread-context.ts"],"names":[],"mappings":"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"}