@cursor/july 0.1.10 → 0.1.11

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 (194) hide show
  1. package/AGENTS.md +1 -0
  2. package/dist/bin/agent-serve.js +17 -3
  3. package/dist/channels/github/github-channel.d.ts.map +1 -1
  4. package/dist/channels/github/github-channel.js +2 -1
  5. package/dist/channels/github/types.d.ts +4 -0
  6. package/dist/channels/github/types.d.ts.map +1 -1
  7. package/dist/channels/slack/cursor-account.d.ts.map +1 -1
  8. package/dist/channels/slack/cursor-account.js +1 -1
  9. package/dist/channels/slack/dispatch.d.ts +13 -0
  10. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  11. package/dist/channels/slack/dispatch.js +36 -11
  12. package/dist/channels/slack/eval-directive.d.ts +63 -0
  13. package/dist/channels/slack/eval-directive.d.ts.map +1 -0
  14. package/dist/channels/slack/eval-directive.js +283 -0
  15. package/dist/channels/slack/index.d.ts +1 -0
  16. package/dist/channels/slack/index.d.ts.map +1 -1
  17. package/dist/channels/slack/index.js +1 -0
  18. package/dist/channels/slack/post-update-delivery.js +318 -0
  19. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  20. package/dist/channels/slack/slack-channel.js +4 -2
  21. package/dist/channels/slack/types.d.ts +7 -0
  22. package/dist/channels/slack/types.d.ts.map +1 -1
  23. package/dist/connections.d.ts +10 -5
  24. package/dist/connections.d.ts.map +1 -1
  25. package/dist/connections.js +10 -5
  26. package/dist/docs/404.html +2 -2
  27. package/dist/docs/ab.html +4 -4
  28. package/dist/docs/assets/{app.CY2buaEE.js → app.BcXUGca7.js} +1 -1
  29. package/dist/docs/assets/chunks/@localSearchIndexroot.BIbvK8M1.js +1 -0
  30. package/dist/docs/assets/chunks/{VPLocalSearchBox.Ix954SFJ.js → VPLocalSearchBox.CWur6XGZ.js} +1 -1
  31. package/dist/docs/assets/chunks/{theme.PDwuJbyi.js → theme.BnvulOX2.js} +2 -2
  32. package/dist/docs/assets/{deployment.md.DC5-ImcM.js → deployment.md.TecHo0_2.js} +3 -3
  33. package/dist/docs/assets/{deployment.md.DC5-ImcM.lean.js → deployment.md.TecHo0_2.lean.js} +1 -1
  34. package/dist/docs/assets/guides_mcp-oauth.md.DqmEOQY1.js +29 -0
  35. package/dist/docs/assets/guides_mcp-oauth.md.DqmEOQY1.lean.js +1 -0
  36. package/dist/docs/assets/{index.md.COiu-1jL.js → index.md.t0TM2Qzz.js} +3 -3
  37. package/dist/docs/assets/{index.md.COiu-1jL.lean.js → index.md.t0TM2Qzz.lean.js} +1 -1
  38. package/dist/docs/assets/{reference_cli.md.CjfiV2Q-.js → reference_cli.md.B74NrVzb.js} +3 -3
  39. package/dist/docs/assets/{reference_cli.md.CjfiV2Q-.lean.js → reference_cli.md.B74NrVzb.lean.js} +1 -1
  40. package/dist/docs/assets/{reference_connections.md.FbWupyzW.js → reference_connections.md.CsSr3rDz.js} +8 -3
  41. package/dist/docs/assets/{reference_connections.md.FbWupyzW.lean.js → reference_connections.md.CsSr3rDz.lean.js} +1 -1
  42. package/dist/docs/assets/reference_prompt.md.BaiweQxE.js +1 -0
  43. package/dist/docs/assets/reference_prompt.md.BaiweQxE.lean.js +1 -0
  44. package/dist/docs/assets/{reference_tools.md.CqgJroI0.js → reference_tools.md.BRSDnTbN.js} +16 -3
  45. package/dist/docs/assets/{reference_tools.md.CqgJroI0.lean.js → reference_tools.md.BRSDnTbN.lean.js} +1 -1
  46. package/dist/docs/assets/{troubleshooting.md.DkovjS7h.js → troubleshooting.md.CmQkmnzC.js} +1 -1
  47. package/dist/docs/assets/{troubleshooting.md.DkovjS7h.lean.js → troubleshooting.md.CmQkmnzC.lean.js} +1 -1
  48. package/dist/docs/building-with-agents.html +4 -4
  49. package/dist/docs/concepts.html +4 -4
  50. package/dist/docs/deployment.html +7 -7
  51. package/dist/docs/evals.html +4 -4
  52. package/dist/docs/example-agents/approval-buddy.html +4 -4
  53. package/dist/docs/example-agents/benny.html +4 -4
  54. package/dist/docs/example-agents/bugbot.html +4 -4
  55. package/dist/docs/example-agents/codebase-wiki.html +4 -4
  56. package/dist/docs/example-agents/codeowners-review.html +4 -4
  57. package/dist/docs/example-agents/concierge.html +4 -4
  58. package/dist/docs/example-agents/fsd.html +4 -4
  59. package/dist/docs/example-agents/index.html +4 -4
  60. package/dist/docs/example-agents/knowledge-base.html +4 -4
  61. package/dist/docs/example-agents/oncall.html +4 -4
  62. package/dist/docs/example-agents/security-reviewer.html +4 -4
  63. package/dist/docs/example-agents/slack-agent.html +4 -4
  64. package/dist/docs/example-agents/weather-agent.html +4 -4
  65. package/dist/docs/guides/agent-to-agent.html +4 -4
  66. package/dist/docs/guides/cloud-runtime.html +4 -4
  67. package/dist/docs/guides/github.html +4 -4
  68. package/dist/docs/guides/human-in-the-loop.html +4 -4
  69. package/dist/docs/guides/mcp-oauth.html +53 -0
  70. package/dist/docs/guides/slack.html +4 -4
  71. package/dist/docs/guides/webhooks.html +4 -4
  72. package/dist/docs/hashmap.json +1 -1
  73. package/dist/docs/hillclimbing.html +4 -4
  74. package/dist/docs/index.html +6 -6
  75. package/dist/docs/quickstart.html +4 -4
  76. package/dist/docs/reference/agent-config.html +4 -4
  77. package/dist/docs/reference/channels.html +4 -4
  78. package/dist/docs/reference/cli.html +6 -6
  79. package/dist/docs/reference/connections.html +12 -7
  80. package/dist/docs/reference/hooks.html +4 -4
  81. package/dist/docs/reference/http-api.html +4 -4
  82. package/dist/docs/reference/instructions.html +4 -4
  83. package/dist/docs/reference/playground.html +4 -4
  84. package/dist/docs/reference/project-layout.html +4 -4
  85. package/dist/docs/reference/prompt.html +33 -0
  86. package/dist/docs/reference/schedules.html +4 -4
  87. package/dist/docs/reference/sessions.html +4 -4
  88. package/dist/docs/reference/skills.html +5 -5
  89. package/dist/docs/reference/subagents.html +4 -4
  90. package/dist/docs/reference/tools.html +20 -7
  91. package/dist/docs/scaffolding-agents.html +4 -4
  92. package/dist/docs/storage.html +4 -4
  93. package/dist/docs/troubleshooting.html +5 -5
  94. package/dist/evals.d.ts +39 -0
  95. package/dist/evals.d.ts.map +1 -1
  96. package/dist/index.d.ts +3 -1
  97. package/dist/index.d.ts.map +1 -1
  98. package/dist/index.js +2 -1
  99. package/dist/internal/cli-mcp-oauth.d.ts +16 -0
  100. package/dist/internal/cli-mcp-oauth.d.ts.map +1 -0
  101. package/dist/internal/cli-mcp-oauth.js +194 -0
  102. package/dist/internal/cli-mcp.d.ts +4 -1
  103. package/dist/internal/cli-mcp.d.ts.map +1 -1
  104. package/dist/internal/cli-mcp.js +19 -1
  105. package/dist/internal/corp-ca.d.ts +9 -0
  106. package/dist/internal/corp-ca.d.ts.map +1 -0
  107. package/dist/internal/corp-ca.js +44 -0
  108. package/dist/internal/cursor/account-mcp.d.ts +17 -4
  109. package/dist/internal/cursor/account-mcp.d.ts.map +1 -1
  110. package/dist/internal/cursor/account-mcp.js +105 -17
  111. package/dist/internal/discovery.d.ts.map +1 -1
  112. package/dist/internal/discovery.js +64 -10
  113. package/dist/internal/distribution.d.ts.map +1 -1
  114. package/dist/internal/distribution.js +1 -0
  115. package/dist/internal/json-dir-store.js +100 -0
  116. package/dist/internal/logs-client.js +1 -1
  117. package/dist/internal/mcp-host.d.ts.map +1 -1
  118. package/dist/internal/mcp-host.js +49 -26
  119. package/dist/internal/mcp-oauth.d.ts +88 -0
  120. package/dist/internal/mcp-oauth.d.ts.map +1 -0
  121. package/dist/internal/mcp-oauth.js +385 -0
  122. package/dist/internal/resolved-connections.d.ts.map +1 -1
  123. package/dist/internal/resolved-connections.js +4 -1
  124. package/dist/internal/sdk-runner.d.ts +9 -0
  125. package/dist/internal/sdk-runner.d.ts.map +1 -1
  126. package/dist/internal/sdk-runner.js +28 -2
  127. package/dist/internal/server.d.ts.map +1 -1
  128. package/dist/internal/server.js +13 -5
  129. package/dist/internal/session-engine.d.ts +7 -9
  130. package/dist/internal/session-engine.d.ts.map +1 -1
  131. package/dist/internal/session-engine.js +96 -64
  132. package/dist/internal/sessions-client.d.ts.map +1 -1
  133. package/dist/internal/sessions-client.js +2 -1
  134. package/dist/internal/stream-progress.d.ts.map +1 -1
  135. package/dist/internal/stream-progress.js +8 -4
  136. package/dist/internal/turn-governor.d.ts +54 -0
  137. package/dist/internal/turn-governor.d.ts.map +1 -0
  138. package/dist/internal/turn-governor.js +111 -0
  139. package/dist/playground/assets/{index-C0-QEG4O.js → index-BIGLubwK.js} +46 -46
  140. package/dist/playground/assets/{index-z3JY9O2x.css → index-C17ZQKDG.css} +1 -1
  141. package/dist/playground/index.html +2 -2
  142. package/dist/prompt.d.ts +39 -0
  143. package/dist/prompt.d.ts.map +1 -0
  144. package/dist/prompt.js +70 -0
  145. package/dist/types.d.ts +78 -5
  146. package/dist/types.d.ts.map +1 -1
  147. package/dist/types.js +6 -0
  148. package/docs/.vitepress/cache/deps/package.json +3 -0
  149. package/docs/README.md +4 -0
  150. package/docs/deployment.md +6 -1
  151. package/docs/guides/mcp-oauth.md +157 -0
  152. package/docs/reference/cli.md +28 -0
  153. package/docs/reference/connections.md +28 -0
  154. package/docs/reference/prompt.md +47 -0
  155. package/docs/reference/tools.md +21 -0
  156. package/docs/troubleshooting.md +11 -0
  157. package/package.json +9 -2
  158. package/skills/create-agent/SKILL.md +7 -3
  159. package/skills/framework-map/SKILL.md +1 -0
  160. package/skills/mcp-auth/SKILL.md +138 -0
  161. package/src/bin/agent-serve.ts +20 -3
  162. package/src/channels/github/github-channel.ts +2 -0
  163. package/src/channels/github/types.ts +4 -0
  164. package/src/channels/slack/cursor-account.ts +2 -0
  165. package/src/channels/slack/dispatch.ts +49 -0
  166. package/src/channels/slack/eval-directive.ts +348 -0
  167. package/src/channels/slack/index.ts +1 -0
  168. package/src/channels/slack/slack-channel.ts +3 -0
  169. package/src/channels/slack/types.ts +7 -0
  170. package/src/connections.ts +10 -5
  171. package/src/evals.ts +43 -0
  172. package/src/index.ts +3 -0
  173. package/src/internal/cli-mcp-oauth.ts +254 -0
  174. package/src/internal/cli-mcp.ts +25 -2
  175. package/src/internal/cursor/account-mcp.ts +153 -41
  176. package/src/internal/discovery.ts +70 -8
  177. package/src/internal/distribution.ts +1 -0
  178. package/src/internal/logs-client.ts +1 -1
  179. package/src/internal/mcp-host.ts +33 -9
  180. package/src/internal/mcp-oauth.ts +496 -0
  181. package/src/internal/resolved-connections.ts +6 -1
  182. package/src/internal/sdk-runner.ts +37 -1
  183. package/src/internal/server.ts +13 -5
  184. package/src/internal/session-engine.ts +115 -74
  185. package/src/internal/sessions-client.ts +2 -1
  186. package/src/internal/stream-progress.ts +8 -0
  187. package/src/internal/turn-governor.ts +145 -0
  188. package/src/prompt.ts +83 -0
  189. package/src/types.ts +76 -6
  190. package/dist/docs/assets/chunks/@localSearchIndexroot.OfDZ5CXg.js +0 -1
  191. package/dist/internal/persistence-coordinator.d.ts +0 -127
  192. package/dist/internal/persistence-coordinator.d.ts.map +0 -1
  193. package/dist/persistence.d.ts +0 -184
  194. package/dist/persistence.d.ts.map +0 -1
@@ -0,0 +1,348 @@
1
+ /**
2
+ * Built-in Slack `eval` directive — run playground evals from a mention/DM
3
+ * without per-agent custom handlers (parity with CLI / playground runs).
4
+ *
5
+ * Examples (after stripping @mentions / cursorAccount agent name):
6
+ * eval
7
+ * eval triage/open-incidents smoke
8
+ * eval --tag oncall
9
+ * eval list
10
+ * eval status
11
+ * eval help
12
+ */
13
+
14
+ import type { EvalRunSnapshot, HostEvalsApi } from "../../evals.js";
15
+ import {
16
+ EvalRunConflictError,
17
+ EvalRunEmptyError,
18
+ } from "../../internal/eval-run-store.js";
19
+ import { stripLeadingSlackMentions } from "./stop.js";
20
+ import type { SlackBinding } from "./types.js";
21
+
22
+ const EVAL_POLL_MS = 2_000;
23
+ const TYPING_STATUS_MAX = 50;
24
+
25
+ export type SlackEvalDirective =
26
+ | { kind: "help" }
27
+ | { kind: "list" }
28
+ | { kind: "status" }
29
+ | { kind: "run"; filterIds?: string[]; tags?: string[] };
30
+
31
+ function escapeRegExp(value: string): string {
32
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
33
+ }
34
+
35
+ /**
36
+ * Normalize inbound Slack text for directive parsing: strip leading
37
+ * `<@U…>` mentions, leading `@U…` markdown mentions, and an optional
38
+ * cursorAccount agentName prefix (`OncallBuddy eval …`).
39
+ */
40
+ export function normalizeSlackEvalDirectiveBody(
41
+ text: string,
42
+ options?: { agentName?: string }
43
+ ): string {
44
+ let body = stripLeadingSlackMentions(text);
45
+ // markdown form from slackTextToMarkdown / cursorAccount envelopes
46
+ while (/^@[A-Za-z0-9._-]+\s+/.test(body)) {
47
+ body = body.replace(/^@[A-Za-z0-9._-]+\s+/, "").trim();
48
+ }
49
+ const agentName = options?.agentName?.trim();
50
+ if (agentName !== undefined && agentName.length > 0) {
51
+ const prefix = new RegExp(`^${escapeRegExp(agentName)}\\s+`, "i");
52
+ body = body.replace(prefix, "").trim();
53
+ }
54
+ return body;
55
+ }
56
+
57
+ /**
58
+ * Parse a Slack eval directive. Returns null when the message is not an
59
+ * eval command (falls through to the normal agent handler).
60
+ */
61
+ export function parseSlackEvalDirective(
62
+ text: string,
63
+ options?: { agentName?: string }
64
+ ): SlackEvalDirective | null {
65
+ const body = normalizeSlackEvalDirectiveBody(text, options);
66
+ if (body.length === 0) {
67
+ return null;
68
+ }
69
+ const tokens = body.split(/\s+/).filter((t) => t.length > 0);
70
+ if (tokens.length === 0 || !/^eval$/i.test(tokens[0] ?? "")) {
71
+ return null;
72
+ }
73
+
74
+ const rest = tokens.slice(1);
75
+ if (rest.length === 0) {
76
+ return { kind: "run" };
77
+ }
78
+
79
+ const head = (rest[0] ?? "").toLowerCase();
80
+ if (
81
+ rest.length === 1 &&
82
+ (head === "help" || head === "-h" || head === "--help")
83
+ ) {
84
+ return { kind: "help" };
85
+ }
86
+ if (rest.length === 1 && (head === "list" || head === "ls")) {
87
+ return { kind: "list" };
88
+ }
89
+ if (rest.length === 1 && head === "status") {
90
+ return { kind: "status" };
91
+ }
92
+
93
+ const filterIds: string[] = [];
94
+ const tags: string[] = [];
95
+ for (let i = 0; i < rest.length; i++) {
96
+ const tok = rest[i] ?? "";
97
+ if (tok === "--tag" || tok === "-t") {
98
+ const value = rest[i + 1];
99
+ if (value === undefined || value.length === 0) {
100
+ return { kind: "help" };
101
+ }
102
+ tags.push(value);
103
+ i += 1;
104
+ continue;
105
+ }
106
+ if (tok.startsWith("--tag=")) {
107
+ const value = tok.slice("--tag=".length);
108
+ if (value.length === 0) {
109
+ return { kind: "help" };
110
+ }
111
+ tags.push(value);
112
+ continue;
113
+ }
114
+ if (tok.startsWith("-t=") && tok.length > 3) {
115
+ tags.push(tok.slice(3));
116
+ continue;
117
+ }
118
+ if (tok.startsWith("-")) {
119
+ // Unknown flag — surface help rather than treating as an eval id.
120
+ return { kind: "help" };
121
+ }
122
+ filterIds.push(tok);
123
+ }
124
+
125
+ const run: SlackEvalDirective = { kind: "run" };
126
+ if (filterIds.length > 0) {
127
+ run.filterIds = filterIds;
128
+ }
129
+ if (tags.length > 0) {
130
+ run.tags = tags;
131
+ }
132
+ return run;
133
+ }
134
+
135
+ /** True when either raw Slack text or markdown form is an eval directive. */
136
+ export function isSlackEvalDirective(
137
+ text: string,
138
+ markdown: string,
139
+ options?: { agentName?: string }
140
+ ): boolean {
141
+ return (
142
+ parseSlackEvalDirective(text, options) !== null ||
143
+ parseSlackEvalDirective(markdown, options) !== null
144
+ );
145
+ }
146
+
147
+ export function formatSlackEvalHelp(): string {
148
+ return [
149
+ "*Eval commands* (same batches as the playground / `agentkit eval --prod`):",
150
+ "• `eval` — run all evals",
151
+ "• `eval <id> [id…]` — run specific eval ids",
152
+ "• `eval --tag <tag>` — run evals with a tag (`-t` also works)",
153
+ "• `eval list` — list available evals",
154
+ "• `eval status` — show the active or latest eval run",
155
+ "• `eval help` — this message",
156
+ ].join("\n");
157
+ }
158
+
159
+ export function formatSlackEvalList(
160
+ evals: Array<{
161
+ id: string;
162
+ description?: string;
163
+ tags?: string[];
164
+ }>
165
+ ): string {
166
+ if (evals.length === 0) {
167
+ return "No evals found under `evals/`.";
168
+ }
169
+ const lines = [`*${evals.length} eval(s):*`];
170
+ for (const item of evals) {
171
+ const tags =
172
+ item.tags === undefined || item.tags.length === 0
173
+ ? ""
174
+ : ` _[${item.tags.join(", ")}]_`;
175
+ const desc =
176
+ item.description === undefined || item.description === ""
177
+ ? ""
178
+ : ` — ${item.description}`;
179
+ lines.push(`• \`${item.id}\`${tags}${desc}`);
180
+ }
181
+ return lines.join("\n");
182
+ }
183
+
184
+ export function formatSlackEvalRunSummary(run: EvalRunSnapshot): string {
185
+ const { summary } = run;
186
+ const statusLabel =
187
+ run.status === "completed"
188
+ ? "completed"
189
+ : run.status === "failed"
190
+ ? "failed"
191
+ : "running";
192
+ const lines = [
193
+ `*Eval run* \`${run.runId}\` — *${statusLabel}*`,
194
+ `• ${summary.passed} passed, ${summary.failed} failed, ${summary.total} total` +
195
+ (summary.done < summary.total
196
+ ? ` (${summary.done}/${summary.total} done)`
197
+ : ""),
198
+ ];
199
+ if (run.error !== undefined && run.error !== "") {
200
+ lines.push(`• error: ${run.error}`);
201
+ }
202
+ for (const c of run.cases) {
203
+ const mark =
204
+ c.status !== "done"
205
+ ? c.status === "running"
206
+ ? "RUN "
207
+ : "…. "
208
+ : c.ok === true
209
+ ? "PASS"
210
+ : "FAIL";
211
+ const dur =
212
+ c.durationMs === undefined
213
+ ? ""
214
+ : ` (${(c.durationMs / 1000).toFixed(1)}s)`;
215
+ const err =
216
+ c.ok === false && c.error !== undefined && c.error !== ""
217
+ ? ` — ${c.error}`
218
+ : "";
219
+ lines.push(`\`${mark}\` \`${c.id}\`${dur}${err}`);
220
+ }
221
+ return lines.join("\n");
222
+ }
223
+
224
+ function truncateTyping(status: string): string {
225
+ if (status.length <= TYPING_STATUS_MAX) {
226
+ return status;
227
+ }
228
+ return `${status.slice(0, TYPING_STATUS_MAX - 1)}…`;
229
+ }
230
+
231
+ async function sleep(ms: number): Promise<void> {
232
+ await new Promise((resolve) => {
233
+ setTimeout(resolve, ms);
234
+ });
235
+ }
236
+
237
+ async function safeTyping(
238
+ binding: SlackBinding,
239
+ status: string
240
+ ): Promise<void> {
241
+ try {
242
+ await binding.thread.startTyping(truncateTyping(status));
243
+ } catch {
244
+ // best-effort status
245
+ }
246
+ }
247
+
248
+ async function safePost(binding: SlackBinding, text: string): Promise<void> {
249
+ try {
250
+ await binding.thread.post(text);
251
+ } catch {
252
+ // best-effort reply
253
+ }
254
+ }
255
+
256
+ /**
257
+ * Handle a parsed Slack eval directive against {@link HostEvalsApi}.
258
+ * Posts results in-thread; does not start an agent turn.
259
+ */
260
+ export async function handleSlackEvalDirective(args: {
261
+ directive: SlackEvalDirective;
262
+ evals: HostEvalsApi;
263
+ binding: SlackBinding;
264
+ /** Override poll interval (tests). */
265
+ pollMs?: number;
266
+ }): Promise<void> {
267
+ const { directive, evals, binding } = args;
268
+ const pollMs = args.pollMs ?? EVAL_POLL_MS;
269
+
270
+ if (directive.kind === "help") {
271
+ await safePost(binding, formatSlackEvalHelp());
272
+ return;
273
+ }
274
+
275
+ if (directive.kind === "list") {
276
+ const listed = await evals.list();
277
+ await safePost(binding, formatSlackEvalList(listed.evals));
278
+ return;
279
+ }
280
+
281
+ if (directive.kind === "status") {
282
+ const { runs, activeRunId } = await evals.listRunsWithActive();
283
+ const run =
284
+ (activeRunId === undefined ? undefined : await evals.get(activeRunId)) ??
285
+ runs[0];
286
+ if (run === undefined) {
287
+ await safePost(binding, "No eval runs yet. Try `eval list` then `eval`.");
288
+ return;
289
+ }
290
+ await safePost(binding, formatSlackEvalRunSummary(run));
291
+ return;
292
+ }
293
+
294
+ await safeTyping(binding, "Starting evals…");
295
+ let run: EvalRunSnapshot;
296
+ try {
297
+ run = await evals.start({
298
+ filterIds: directive.filterIds,
299
+ tags: directive.tags,
300
+ });
301
+ } catch (error) {
302
+ if (error instanceof EvalRunConflictError) {
303
+ const active = await evals.get(error.activeRunId);
304
+ await safePost(
305
+ binding,
306
+ active === undefined
307
+ ? `An eval run is already in progress (\`${error.activeRunId}\`).`
308
+ : `An eval run is already in progress:\n${formatSlackEvalRunSummary(active)}`
309
+ );
310
+ return;
311
+ }
312
+ if (error instanceof EvalRunEmptyError) {
313
+ await safePost(
314
+ binding,
315
+ "No matching evals. Try `eval list` or `eval help`."
316
+ );
317
+ return;
318
+ }
319
+ const message = error instanceof Error ? error.message : String(error);
320
+ await safePost(binding, `Failed to start evals: ${message}`);
321
+ return;
322
+ }
323
+
324
+ await safePost(
325
+ binding,
326
+ `Started eval run \`${run.runId}\` (${run.summary.total} case(s)).`
327
+ );
328
+
329
+ while (run.status === "running") {
330
+ await safeTyping(
331
+ binding,
332
+ `Evals ${run.summary.done}/${run.summary.total}…`
333
+ );
334
+ await sleep(pollMs);
335
+ const next = await evals.get(run.runId);
336
+ if (next === undefined) {
337
+ await safePost(
338
+ binding,
339
+ `Eval run \`${run.runId}\` disappeared before completion.`
340
+ );
341
+ return;
342
+ }
343
+ run = next;
344
+ }
345
+
346
+ await safePost(binding, formatSlackEvalRunSummary(run));
347
+ await safeTyping(binding, "Evals done.");
348
+ }
@@ -29,6 +29,7 @@ export * from "./cursor-account.js";
29
29
  export * from "./defaults.js";
30
30
  export * from "./dispatch.js";
31
31
  export * from "./doctor.js";
32
+ export * from "./eval-directive.js";
32
33
  export * from "./event-id-dedupe.js";
33
34
  export * from "./inbound.js";
34
35
  export * from "./init.js";
@@ -138,6 +138,7 @@ export function slackChannel<const Name extends string = string>(
138
138
  const engagement = options.engagement ?? {};
139
139
  const mentionsEnabled = engagement.mentions !== false;
140
140
  const directMessagesEnabled = engagement.directMessages !== false;
141
+ const evalCommandsEnabled = options.evalCommands !== false;
141
142
  const channelPosts = engagement.channelPosts;
142
143
  if (channelPosts !== undefined) {
143
144
  const entries = channelPosts.allow.filter((entry) => entry.trim() !== "");
@@ -204,6 +205,7 @@ export function slackChannel<const Name extends string = string>(
204
205
  log: getLog(),
205
206
  mentionsEnabled,
206
207
  directMessagesEnabled,
208
+ evalCommandsEnabled,
207
209
  ...(args.hasContinuationSession === undefined
208
210
  ? {}
209
211
  : { hasContinuationSession: args.hasContinuationSession }),
@@ -342,6 +344,7 @@ export function slackChannel<const Name extends string = string>(
342
344
  credentials,
343
345
  host: args.host,
344
346
  log: getLog(),
347
+ evalCommandsEnabled,
345
348
  ...(args.hasContinuationSession === undefined
346
349
  ? {}
347
350
  : {
@@ -382,6 +382,13 @@ export interface SlackChannelOptions {
382
382
  * entry at 50 chars). Defaults to Thinking… / Working on it… / Almost there….
383
383
  */
384
384
  loadingMessages?: string[];
385
+ /**
386
+ * Built-in Slack `eval` / `eval list` / `eval status` directive that runs
387
+ * playground eval batches (`host.evals` / `/v1/dev/evals/runs`) without an
388
+ * agent turn. Defaults to `true`. Set `false` to leave `eval …` for the
389
+ * model handler instead.
390
+ */
391
+ evalCommands?: boolean;
385
392
  /** Optional teardown (e.g. stop example-local debouncers). Runs after Socket Mode stops. */
386
393
  onStop?: () => void | Promise<void>;
387
394
  }
@@ -2,11 +2,9 @@
2
2
  * `defineConnection` — authored at `agent/mcp-connections/<name>.ts`.
3
3
  *
4
4
  * A connection gives tools from an external MCP server. The filename
5
- * becomes the connection (server) name. Every connection is always
6
- * available in three places:
7
- * - the Cursor agent (local harness or cloud), via SDK `mcpServers`
8
- * - the agent-serve host, via `ctx.host.mcp` on in-process tools
9
- * - channel / schedule handlers, via `args.host.mcp`
5
+ * becomes the connection (server) name. Available to the agent (SDK
6
+ * `mcpServers`), host (`ctx.host.mcp`), and channel/schedule handlers.
7
+ * Pass `hostOnly: true` to keep it off the model (still on `host.mcp`).
10
8
  *
11
9
  * ```ts
12
10
  * import { defineConnection } from "@anysphere/agent-serve/connections";
@@ -15,6 +13,13 @@
15
13
  * url: "https://mcp.linear.app/mcp",
16
14
  * headers: { authorization: `Bearer ${process.env.LINEAR_TOKEN}` },
17
15
  * });
16
+ *
17
+ * // privileged connector, model cannot call directly:
18
+ * export default defineConnection({
19
+ * cursorAccount: true,
20
+ * servers: ["anytool"],
21
+ * hostOnly: true,
22
+ * });
18
23
  * ```
19
24
  *
20
25
  * A **Cursor account MCP connection** exposes the MCP connectors the operator
package/src/evals.ts CHANGED
@@ -315,6 +315,49 @@ export interface EvalRunSnapshot {
315
315
  };
316
316
  }
317
317
 
318
+ /** One discovered eval datapoint as returned by {@link HostEvalsApi.list}. */
319
+ export interface HostEvalListItem {
320
+ id: string;
321
+ fileId: string;
322
+ description?: string;
323
+ tags?: string[];
324
+ }
325
+
326
+ /** Config slice returned with {@link HostEvalsApi.list}. */
327
+ export interface HostEvalListConfig {
328
+ maxConcurrency?: number;
329
+ timeoutMs?: number;
330
+ maxPlaygroundRuns: number;
331
+ /** True when `agent/storage.ts` declares an `evals` table. */
332
+ durableRuns: boolean;
333
+ }
334
+
335
+ /** Input for {@link HostEvalsApi.start} (same filters as `POST /v1/dev/evals/runs`). */
336
+ export interface HostStartEvalRunInput {
337
+ filterIds?: string[];
338
+ tags?: string[];
339
+ /** Per-case timeout override (same semantics as CLI `--timeout-ms`). */
340
+ timeoutMs?: number;
341
+ }
342
+
343
+ /**
344
+ * Host-facing playground eval batches — the same surface as
345
+ * `/v1/dev/evals*` and `agentkit eval --prod`. Attached to
346
+ * {@link import("./types.js").HostContext.evals} by `serve`.
347
+ */
348
+ export interface HostEvalsApi {
349
+ list(): Promise<{
350
+ evals: HostEvalListItem[];
351
+ config: HostEvalListConfig;
352
+ }>;
353
+ get(runId: string): Promise<EvalRunSnapshot | undefined>;
354
+ listRunsWithActive(): Promise<{
355
+ runs: EvalRunSnapshot[];
356
+ activeRunId?: string;
357
+ }>;
358
+ start(input?: HostStartEvalRunInput): Promise<EvalRunSnapshot>;
359
+ }
360
+
318
361
  export interface EvalConfigFile {
319
362
  timeoutMs?: number;
320
363
  /**
package/src/index.ts CHANGED
@@ -89,6 +89,8 @@ export {
89
89
  UnknownSessionError,
90
90
  UnknownToolError,
91
91
  } from "./internal/session-engine.js";
92
+ export type { PromptTag } from "./prompt.js";
93
+ export { prompt } from "./prompt.js";
92
94
  export type {
93
95
  ReminderBusyPolicy,
94
96
  ReminderCreateInput,
@@ -127,6 +129,7 @@ export {
127
129
  isCursorAccountTransport,
128
130
  isPeerConnectionTransport,
129
131
  isSymbolicConnectionTransport,
132
+ MAX_RUNNING_TURNS_LIMIT,
130
133
  } from "./types.js";
131
134
 
132
135
  /**