@cursor/july 0.1.114 → 0.2.0
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/channels/slack/inbound.d.ts +7 -0
- package/dist/channels/slack/inbound.d.ts.map +1 -1
- package/dist/channels/slack/inbound.js +23 -0
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +83 -4
- package/dist/docs/404.html +2 -2
- package/dist/docs/assets/{app.BqkJwOZ-.js → app.9eAtsjAM.js} +4 -4
- package/dist/docs/assets/chunks/@localSearchIndexroot.DjNBgxTF.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.BJAi2KiV.js → VPLocalSearchBox.C9s69nxj.js} +1 -1
- package/dist/docs/assets/chunks/{arc.BZpXTgvV.js → arc.DmWDRaF-.js} +1 -1
- package/dist/docs/assets/chunks/{architectureDiagram-Q4EWVU46.WYI-7F-Y.js → architectureDiagram-Q4EWVU46.BE1Wj4f3.js} +1 -1
- package/dist/docs/assets/chunks/{baseUniq.CZaUPpg0.js → baseUniq.pmEZGnWu.js} +1 -1
- package/dist/docs/assets/chunks/{blockDiagram-DXYQGD6D.D6UES2pD.js → blockDiagram-DXYQGD6D.D6mM-5XN.js} +1 -1
- package/dist/docs/assets/chunks/{c4Diagram-AHTNJAMY.cwebIe4i.js → c4Diagram-AHTNJAMY.ZQYTPC1b.js} +1 -1
- package/dist/docs/assets/chunks/channel.BNF8VK-B.js +1 -0
- package/dist/docs/assets/chunks/{chunk-4BX2VUAB.fVyFnjxg.js → chunk-4BX2VUAB.CKJ7gaK8.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-4TB4RGXK.BanufG1c.js → chunk-4TB4RGXK.CL61HnvB.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-55IACEB6.VaSMz5-2.js → chunk-55IACEB6.DsA4XA1m.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-EDXVE4YY.CN2diZOM.js → chunk-EDXVE4YY.BODHCHFW.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-FMBD7UC4.g4ivypu3.js → chunk-FMBD7UC4.D6NBaZTa.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-OYMX7WX6.GZXKn9JJ.js → chunk-OYMX7WX6.BLPuqFXg.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-QZHKN3VN.itXxJZCd.js → chunk-QZHKN3VN.BFs_ML8Z.js} +1 -1
- package/dist/docs/assets/chunks/{chunk-YZCP3GAM.-rw2GfvX.js → chunk-YZCP3GAM.BDjuFyZv.js} +1 -1
- package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.iViHzfrK.js +1 -0
- package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.iViHzfrK.js +1 -0
- package/dist/docs/assets/chunks/clone.CJoR2BBM.js +1 -0
- package/dist/docs/assets/chunks/{cose-bilkent-S5V4N54A.CmaI5br0.js → cose-bilkent-S5V4N54A.D85HNEsi.js} +1 -1
- package/dist/docs/assets/chunks/{dagre-KV5264BT.4wY9S4Kt.js → dagre-KV5264BT.V463KlSF.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-5BDNPKRD.Pc3c0u9W.js → diagram-5BDNPKRD.DhBDu1ab.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-G4DWMVQ6.CYrWz-nj.js → diagram-G4DWMVQ6.v6sC68zl.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-MMDJMWI5.Bgj5hukb.js → diagram-MMDJMWI5.DhHsdXYv.js} +1 -1
- package/dist/docs/assets/chunks/{diagram-TYMM5635.DGMEXalS.js → diagram-TYMM5635.BPWNSFZc.js} +1 -1
- package/dist/docs/assets/chunks/{erDiagram-SMLLAGMA.GepTV9Im.js → erDiagram-SMLLAGMA.Cq0wTMPL.js} +1 -1
- package/dist/docs/assets/chunks/{flowDiagram-DWJPFMVM.DVKywg3j.js → flowDiagram-DWJPFMVM.MveMtucC.js} +1 -1
- package/dist/docs/assets/chunks/{ganttDiagram-T4ZO3ILL.C7qt9Mlo.js → ganttDiagram-T4ZO3ILL.BzKfGUSf.js} +1 -1
- package/dist/docs/assets/chunks/{gitGraphDiagram-UUTBAWPF.U30_r82P.js → gitGraphDiagram-UUTBAWPF.OToXTSW_.js} +1 -1
- package/dist/docs/assets/chunks/{graph.CyyMyAWv.js → graph.D82tam-l.js} +1 -1
- package/dist/docs/assets/chunks/{infoDiagram-42DDH7IO.Dn9ACW3y.js → infoDiagram-42DDH7IO.DzFlRmcE.js} +1 -1
- package/dist/docs/assets/chunks/{ishikawaDiagram-UXIWVN3A.DlIdIGOA.js → ishikawaDiagram-UXIWVN3A.CVPRJiKe.js} +1 -1
- package/dist/docs/assets/chunks/{journeyDiagram-VCZTEJTY.DZj4vy4E.js → journeyDiagram-VCZTEJTY.CQvNTfQC.js} +1 -1
- package/dist/docs/assets/chunks/{kanban-definition-6JOO6SKY.Dl63eMUV.js → kanban-definition-6JOO6SKY.BwywywUl.js} +1 -1
- package/dist/docs/assets/chunks/{layout.BLHZLWPH.js → layout.C4BkPPba.js} +1 -1
- package/dist/docs/assets/chunks/{linear.aXKGKaNw.js → linear.FoSfGKD4.js} +1 -1
- package/dist/docs/assets/chunks/{min.zWnFcpcc.js → min.yLh8jqfl.js} +1 -1
- package/dist/docs/assets/chunks/{mindmap-definition-QFDTVHPH.Qs4MQBea.js → mindmap-definition-QFDTVHPH.C9Dq2_CN.js} +1 -1
- package/dist/docs/assets/chunks/{pieDiagram-DEJITSTG.BmPHgsk7.js → pieDiagram-DEJITSTG.CiGyBcES.js} +1 -1
- package/dist/docs/assets/chunks/{quadrantDiagram-34T5L4WZ.D5MQ3gwA.js → quadrantDiagram-34T5L4WZ.1FWea9nj.js} +1 -1
- package/dist/docs/assets/chunks/{requirementDiagram-MS252O5E.CkdUFrO7.js → requirementDiagram-MS252O5E.B1q7ntiV.js} +1 -1
- package/dist/docs/assets/chunks/{sankeyDiagram-XADWPNL6.KZrljrAV.js → sankeyDiagram-XADWPNL6.Cpr4oU_k.js} +1 -1
- package/dist/docs/assets/chunks/{sequenceDiagram-FGHM5R23.XMoEW-Lx.js → sequenceDiagram-FGHM5R23.CUK68STn.js} +1 -1
- package/dist/docs/assets/chunks/{stateDiagram-FHFEXIEX.BmTzePLj.js → stateDiagram-FHFEXIEX.zU0yL2m4.js} +1 -1
- package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.nV8Nl-td.js +1 -0
- package/dist/docs/assets/chunks/{theme.BfQzpxsg.js → theme.DhnKd0CD.js} +2 -2
- package/dist/docs/assets/chunks/{timeline-definition-GMOUNBTQ.Dug0oamp.js → timeline-definition-GMOUNBTQ.CNYoXo3F.js} +1 -1
- package/dist/docs/assets/chunks/{vennDiagram-DHZGUBPP.BOTHrEFu.js → vennDiagram-DHZGUBPP.DFWH3G9s.js} +1 -1
- package/dist/docs/assets/chunks/{wardley-RL74JXVD.DXy2i1LS.js → wardley-RL74JXVD.Do4PwzeN.js} +1 -1
- package/dist/docs/assets/chunks/{wardleyDiagram-NUSXRM2D.CoXKdfi6.js → wardleyDiagram-NUSXRM2D.7WLkqM7s.js} +1 -1
- package/dist/docs/assets/chunks/{xychartDiagram-5P7HB3ND.DXoSCjAW.js → xychartDiagram-5P7HB3ND.-SyUNgWw.js} +1 -1
- package/dist/docs/assets/{guides_slack.md.Bo96y42E.js → guides_slack.md.DVjNyqq5.js} +3 -3
- package/dist/docs/assets/{guides_slack.md.Bo96y42E.lean.js → guides_slack.md.DVjNyqq5.lean.js} +1 -1
- package/dist/docs/assets/reference_cli.md.BvnQM8wd.js +97 -0
- package/dist/docs/assets/reference_cli.md.BvnQM8wd.lean.js +1 -0
- package/dist/docs/building-with-agents.html +35 -35
- package/dist/docs/deployment.html +35 -35
- package/dist/docs/evals.html +35 -35
- package/dist/docs/guides/agent-to-agent.html +35 -35
- package/dist/docs/guides/bitbucket.html +35 -35
- package/dist/docs/guides/cloud-agents.html +35 -35
- package/dist/docs/guides/convert-automation.html +35 -35
- package/dist/docs/guides/github.html +35 -35
- package/dist/docs/guides/gitlab.html +35 -35
- package/dist/docs/guides/grokbot-agents.html +35 -35
- package/dist/docs/guides/hooks.html +35 -35
- package/dist/docs/guides/improve.html +35 -35
- package/dist/docs/guides/jev.html +35 -35
- package/dist/docs/guides/mcp-oauth.html +35 -35
- package/dist/docs/guides/opentelemetry.html +35 -35
- package/dist/docs/guides/slack.html +37 -37
- package/dist/docs/guides/slack.md +7 -0
- package/dist/docs/guides/webhooks.html +35 -35
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +35 -35
- package/dist/docs/index.html +35 -35
- package/dist/docs/llms-full.txt +690 -751
- package/dist/docs/llms.txt +1 -1
- package/dist/docs/quickstart.html +35 -35
- package/dist/docs/reference/agent-config.html +35 -35
- package/dist/docs/reference/artifacts.html +35 -35
- package/dist/docs/reference/channels.html +35 -35
- package/dist/docs/reference/cli.html +127 -125
- package/dist/docs/reference/cli.md +685 -753
- package/dist/docs/reference/connections.html +35 -35
- package/dist/docs/reference/evals.html +35 -35
- package/dist/docs/reference/extensions.html +35 -35
- package/dist/docs/reference/hooks.html +35 -35
- package/dist/docs/reference/http-api.html +35 -35
- package/dist/docs/reference/instructions.html +35 -35
- package/dist/docs/reference/playground.html +35 -35
- package/dist/docs/reference/project-layout.html +35 -35
- package/dist/docs/reference/prompt.html +35 -35
- package/dist/docs/reference/schedules.html +35 -35
- package/dist/docs/reference/sessions.html +35 -35
- package/dist/docs/reference/skills.html +35 -35
- package/dist/docs/reference/subagents.html +35 -35
- package/dist/docs/reference/tools.html +35 -35
- package/dist/docs/templates/agentic-owners.html +35 -35
- package/dist/docs/templates/pr-autofixer.html +35 -35
- package/dist/docs/templates/security-reviewer.html +35 -35
- package/dist/docs/templates/thermo-quality-review.html +35 -35
- package/dist/docs/templates/thermo-review.html +35 -35
- package/dist/docs/templates/triage.html +35 -35
- package/dist/docs/troubleshooting.html +35 -35
- package/dist/internal/cli-deploy.d.ts.map +1 -1
- package/dist/internal/cli-deploy.js +9 -1
- package/dist/internal/deploy-client.d.ts +6 -0
- package/dist/internal/deploy-client.d.ts.map +1 -1
- package/dist/internal/deploy-client.js +3 -0
- package/dist/internal/discovery/agent-config.d.ts +3 -1
- package/dist/internal/discovery/agent-config.d.ts.map +1 -1
- package/dist/internal/discovery/agent-config.js +7 -4
- package/dist/internal/framework-storage-selection.d.ts +1 -1
- package/dist/internal/framework-storage-selection.d.ts.map +1 -1
- package/dist/internal/platform-timers.d.ts.map +1 -1
- package/dist/internal/platform-timers.js +20 -2
- package/dist/internal/reminder-runner.d.ts +79 -1
- package/dist/internal/reminder-runner.d.ts.map +1 -1
- package/dist/internal/reminder-runner.js +276 -44
- package/dist/internal/server.d.ts.map +1 -1
- package/dist/internal/server.js +7 -0
- package/dist/memory.d.ts +4 -0
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +28 -4
- package/dist/playground/assets/index-DLwnR9ys.css +1 -0
- package/dist/playground/index.html +2 -2
- package/dist/types.d.ts +16 -9
- package/dist/types.d.ts.map +1 -1
- package/docs/guides/slack.md +7 -0
- package/docs/reference/cli.md +686 -754
- package/package.json +1 -1
- package/src/channels/slack/inbound.ts +24 -0
- package/src/channels/slack/slack-channel.ts +123 -1
- package/src/internal/cli-deploy.ts +12 -1
- package/src/internal/deploy-client.ts +9 -0
- package/src/internal/discovery/agent-config.ts +8 -6
- package/src/internal/framework-storage-selection.ts +1 -1
- package/src/internal/platform-timers.ts +24 -2
- package/src/internal/reminder-runner.ts +426 -63
- package/src/internal/server.ts +8 -0
- package/src/memory.ts +37 -3
- package/src/types.ts +16 -9
- package/dist/docs/assets/chunks/@localSearchIndexroot.BnSgidYE.js +0 -1
- package/dist/docs/assets/chunks/channel.DdM5EfNW.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-6PBFFD2Q.CjfGHeg2.js +0 -1
- package/dist/docs/assets/chunks/classDiagram-v2-HSJHXN6E.CjfGHeg2.js +0 -1
- package/dist/docs/assets/chunks/clone.wSOICb_f.js +0 -1
- package/dist/docs/assets/chunks/stateDiagram-v2-QKLJ7IA2.Cu5X28zZ.js +0 -1
- package/dist/docs/assets/reference_cli.md.DLWDz9ij.js +0 -95
- package/dist/docs/assets/reference_cli.md.DLWDz9ij.lean.js +0 -1
- package/dist/playground/assets/index-C61EWMBK.css +0 -1
- /package/dist/playground/assets/{index-CrMWlgUU.js → index-CX6oTKwz.js} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cursor/july",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "(early alpha) Filesystem-first framework for defining Cursor agents as markdown and TypeScript and serving them over channels with the Cursor SDK.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"repository": {
|
|
@@ -218,6 +218,30 @@ export function parseAssistantThreadStarted(
|
|
|
218
218
|
};
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
+
/**
|
|
222
|
+
* The receiving app's own bot user id from an Events API envelope. Slack
|
|
223
|
+
* stamps `authorizations[]` on every `event_callback` with the installed
|
|
224
|
+
* bot user the delivery is for, so a hosted guest learns its identity from
|
|
225
|
+
* the verified body without an `auth.test` round trip.
|
|
226
|
+
*/
|
|
227
|
+
export function parseEventBodyBotUserId(body: unknown): string | undefined {
|
|
228
|
+
const root = asRecord(body);
|
|
229
|
+
if (root === null || root.type !== "event_callback") {
|
|
230
|
+
return undefined;
|
|
231
|
+
}
|
|
232
|
+
if (!Array.isArray(root.authorizations)) {
|
|
233
|
+
return undefined;
|
|
234
|
+
}
|
|
235
|
+
for (const entry of root.authorizations) {
|
|
236
|
+
const authorization = asRecord(entry);
|
|
237
|
+
const userId = asString(authorization?.user_id);
|
|
238
|
+
if (userId !== undefined && userId !== "") {
|
|
239
|
+
return userId;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
|
|
221
245
|
/**
|
|
222
246
|
* Parse DM / IM messages. More generous than a strict channel_type check:
|
|
223
247
|
* accepts `channel_type === "im"` or channel ids starting with `D`, and
|
|
@@ -25,10 +25,12 @@ import {
|
|
|
25
25
|
} from "../../internal/continuation-identity.js";
|
|
26
26
|
import { AGENT_SERVE_GENERATION_ENV_VAR } from "../../internal/cursor-relay-core.js";
|
|
27
27
|
import { attachHostedAdmissionAdapter } from "../../internal/hosted-admission-adapter.js";
|
|
28
|
+
import type { HostedAdmissionPlatformHandoff } from "../../internal/hosted-delivery-protocol.js";
|
|
28
29
|
import type {
|
|
29
30
|
ArtifactsApi,
|
|
30
31
|
ChannelDefinition,
|
|
31
32
|
ChannelEventHandlers,
|
|
33
|
+
ChannelHandlerArgs,
|
|
32
34
|
HostContext,
|
|
33
35
|
JsonValue,
|
|
34
36
|
ReceiveInput,
|
|
@@ -68,6 +70,10 @@ import {
|
|
|
68
70
|
slackWakeChannelState,
|
|
69
71
|
} from "./dispatch.js";
|
|
70
72
|
import { createEventIdDedupe, type EventIdDedupe } from "./event-id-dedupe.js";
|
|
73
|
+
import {
|
|
74
|
+
parseChannelMessageEvent,
|
|
75
|
+
parseEventBodyBotUserId,
|
|
76
|
+
} from "./inbound.js";
|
|
71
77
|
import {
|
|
72
78
|
dispatchBlockAction,
|
|
73
79
|
dispatchInteractiveFromPayload,
|
|
@@ -245,6 +251,113 @@ export function slackChannel(
|
|
|
245
251
|
let channelWatch: ChannelPostWatcher | undefined;
|
|
246
252
|
let botMentionGate: SlackBotMentionGate | undefined;
|
|
247
253
|
|
|
254
|
+
// Hosted admission never runs the Socket Mode branch of `onStart`, so the
|
|
255
|
+
// channel watch is built per delivery there. The allowlist and its `#name`
|
|
256
|
+
// resolution are shared across the pod; the bot's identity comes from the
|
|
257
|
+
// verified envelope.
|
|
258
|
+
let hostedAllowlist: SlackChannelAllowlist | undefined;
|
|
259
|
+
let hostedAllowlistReady: Promise<void> | undefined;
|
|
260
|
+
|
|
261
|
+
async function resolveHostedAllowlistNames(
|
|
262
|
+
allowlist: SlackChannelAllowlist
|
|
263
|
+
): Promise<void> {
|
|
264
|
+
const names = allowlist.unresolvedNames();
|
|
265
|
+
if (names.length === 0) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
try {
|
|
269
|
+
const botToken = await tryResolveBotToken(credentials);
|
|
270
|
+
if (botToken === undefined) {
|
|
271
|
+
getLog().error("channel watch setup degraded", {
|
|
272
|
+
error: "no bot token; #name entries stay unresolved",
|
|
273
|
+
});
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const { WebClient } = await import("@slack/web-api");
|
|
277
|
+
allowlist.applyResolvedNames(
|
|
278
|
+
await resolveChannelNames(new WebClient(botToken), names, getLog())
|
|
279
|
+
);
|
|
280
|
+
} catch (error) {
|
|
281
|
+
getLog().error("channel watch setup degraded", {
|
|
282
|
+
error: error instanceof Error ? error.message : String(error),
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Only a channel post needs the watcher, so mentions and DMs never wait on
|
|
289
|
+
* it, and a channel already matched by id never waits on `#name` resolution.
|
|
290
|
+
*/
|
|
291
|
+
async function hostedChannelWatch(
|
|
292
|
+
payload: unknown,
|
|
293
|
+
args: ChannelHandlerArgs,
|
|
294
|
+
platformHandoff: HostedAdmissionPlatformHandoff | undefined
|
|
295
|
+
): Promise<ChannelPostWatcher | undefined> {
|
|
296
|
+
if (channelPosts === undefined) {
|
|
297
|
+
return undefined;
|
|
298
|
+
}
|
|
299
|
+
const channelEvent = parseChannelMessageEvent(payload, {
|
|
300
|
+
includeBotAuthored: true,
|
|
301
|
+
});
|
|
302
|
+
if (channelEvent === null || channelEvent.kind === "deleted") {
|
|
303
|
+
return undefined;
|
|
304
|
+
}
|
|
305
|
+
hostedAllowlist ??= new SlackChannelAllowlist(channelPosts.allow);
|
|
306
|
+
if (
|
|
307
|
+
!hostedAllowlist.matches(channelEvent.message.channelId) &&
|
|
308
|
+
hostedAllowlist.unresolvedNames().length > 0
|
|
309
|
+
) {
|
|
310
|
+
hostedAllowlistReady ??= resolveHostedAllowlistNames(hostedAllowlist);
|
|
311
|
+
await hostedAllowlistReady;
|
|
312
|
+
}
|
|
313
|
+
const botUserId = parseEventBodyBotUserId(payload);
|
|
314
|
+
return createChannelPostWatcher({
|
|
315
|
+
// Admission answers before a debounce timer could fire; edits arrive
|
|
316
|
+
// as their own deliveries and the edge drops them.
|
|
317
|
+
options: { ...channelPosts, debounceMs: 0 },
|
|
318
|
+
allowlist: hostedAllowlist,
|
|
319
|
+
getBotUserId: () => botUserId,
|
|
320
|
+
log: getLog(),
|
|
321
|
+
dispatch: (message, eventId) => {
|
|
322
|
+
args.waitUntil(
|
|
323
|
+
dispatchInboundMessage({
|
|
324
|
+
kind: "channel_post",
|
|
325
|
+
message,
|
|
326
|
+
handler: onChannelPost,
|
|
327
|
+
propagateHandlerErrors: true,
|
|
328
|
+
send: args.send,
|
|
329
|
+
credentials,
|
|
330
|
+
host: args.host,
|
|
331
|
+
artifacts: args.artifacts,
|
|
332
|
+
log: getLog(),
|
|
333
|
+
evalCommandsEnabled,
|
|
334
|
+
followUpStatus,
|
|
335
|
+
ack: reply.ack,
|
|
336
|
+
blockExternals,
|
|
337
|
+
continuation: options.continuation,
|
|
338
|
+
...(args.hasContinuationSession === undefined
|
|
339
|
+
? {}
|
|
340
|
+
: { hasContinuationSession: args.hasContinuationSession }),
|
|
341
|
+
...(args.isContinuationBusy === undefined
|
|
342
|
+
? {}
|
|
343
|
+
: { isContinuationBusy: args.isContinuationBusy }),
|
|
344
|
+
...(args.getContinuationLastBotMessageTs === undefined
|
|
345
|
+
? {}
|
|
346
|
+
: {
|
|
347
|
+
getContinuationLastBotMessageTs:
|
|
348
|
+
args.getContinuationLastBotMessageTs,
|
|
349
|
+
}),
|
|
350
|
+
...(args.interruptContinuation === undefined
|
|
351
|
+
? {}
|
|
352
|
+
: { interruptContinuation: args.interruptContinuation }),
|
|
353
|
+
...(eventId === undefined ? {} : { eventId }),
|
|
354
|
+
...(platformHandoff === undefined ? {} : { platformHandoff }),
|
|
355
|
+
})
|
|
356
|
+
);
|
|
357
|
+
},
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
248
361
|
function inboundDeps(args: {
|
|
249
362
|
send: SendMessageFn;
|
|
250
363
|
waitUntil: (promise: Promise<unknown>) => void;
|
|
@@ -260,7 +373,10 @@ export function slackChannel(
|
|
|
260
373
|
) => Promise<string | undefined>;
|
|
261
374
|
interruptContinuation?: (continuationToken: string) => Promise<boolean>;
|
|
262
375
|
platformHandoff?: SlackInboundDispatchDeps["platformHandoff"];
|
|
376
|
+
/** Per-delivery watcher (hosted); the Socket Mode watcher otherwise. */
|
|
377
|
+
channelWatch?: ChannelPostWatcher;
|
|
263
378
|
}): SlackInboundDispatchDeps {
|
|
379
|
+
const watch = args.channelWatch ?? channelWatch;
|
|
264
380
|
return {
|
|
265
381
|
send: args.send,
|
|
266
382
|
continuation: options.continuation,
|
|
@@ -299,7 +415,7 @@ export function slackChannel(
|
|
|
299
415
|
...(args.interruptContinuation === undefined
|
|
300
416
|
? {}
|
|
301
417
|
: { interruptContinuation: args.interruptContinuation }),
|
|
302
|
-
...(
|
|
418
|
+
...(watch === undefined ? {} : { channelWatch: watch }),
|
|
303
419
|
...(botMentionGate === undefined ? {} : { botMentionGate }),
|
|
304
420
|
suggestedPrompts: options.suggestedPrompts,
|
|
305
421
|
suggestedPromptsTitle: options.suggestedPromptsTitle,
|
|
@@ -661,6 +777,11 @@ export function slackChannel(
|
|
|
661
777
|
// would otherwise swallow the control plane's own retry of a delivery
|
|
662
778
|
// that failed after the id was marked handled.
|
|
663
779
|
dispatch: async ({ payload, args, platformHandoff }) => {
|
|
780
|
+
const hostedWatch = await hostedChannelWatch(
|
|
781
|
+
payload,
|
|
782
|
+
args,
|
|
783
|
+
platformHandoff
|
|
784
|
+
);
|
|
664
785
|
const dispatched = dispatchInboundFromEventBody(
|
|
665
786
|
payload,
|
|
666
787
|
inboundDeps({
|
|
@@ -675,6 +796,7 @@ export function slackChannel(
|
|
|
675
796
|
getContinuationLastBotMessageTs: args.getContinuationLastBotMessageTs,
|
|
676
797
|
interruptContinuation: args.interruptContinuation,
|
|
677
798
|
...(platformHandoff === undefined ? {} : { platformHandoff }),
|
|
799
|
+
...(hostedWatch === undefined ? {} : { channelWatch: hostedWatch }),
|
|
678
800
|
})
|
|
679
801
|
);
|
|
680
802
|
return skipped(dispatched ? "not_engaged" : "not_dispatchable");
|
|
@@ -1658,11 +1658,18 @@ export async function cmdStop(
|
|
|
1658
1658
|
}
|
|
1659
1659
|
const cancellation =
|
|
1660
1660
|
"cancellation" in accepted ? accepted.cancellation : undefined;
|
|
1661
|
+
// The backend escalates a publisher's stop of a multi-tenant app to the
|
|
1662
|
+
// application-level suspension; say so, and how to undo it.
|
|
1663
|
+
const stoppedGlobally = "scope" in accepted && accepted.scope === "global";
|
|
1661
1664
|
if (ctx.noWait) {
|
|
1662
1665
|
if (ctx.json) {
|
|
1663
1666
|
ctx.out(`${JSON.stringify(accepted, null, 2)}\n`);
|
|
1664
1667
|
} else {
|
|
1665
|
-
ctx.out(
|
|
1668
|
+
ctx.out(
|
|
1669
|
+
stoppedGlobally
|
|
1670
|
+
? `Stop accepted for ${slug} across all tenants (status: ${accepted.status}).\n`
|
|
1671
|
+
: `Stop accepted for ${slug} (status: ${accepted.status}).\n`
|
|
1672
|
+
);
|
|
1666
1673
|
}
|
|
1667
1674
|
return cancellation?.failed === 0 || cancellation === undefined ? 0 : 1;
|
|
1668
1675
|
}
|
|
@@ -1681,6 +1688,10 @@ export async function cmdStop(
|
|
|
1681
1688
|
}
|
|
1682
1689
|
if (ctx.json) {
|
|
1683
1690
|
ctx.out(`${JSON.stringify(detail, null, 2)}\n`);
|
|
1691
|
+
} else if (stoppedGlobally) {
|
|
1692
|
+
ctx.out(
|
|
1693
|
+
`Stopped ${slug} across all tenants (team ${ctx.teamId}); resume with \`${CLI} start ${slug} --global\`.\n`
|
|
1694
|
+
);
|
|
1684
1695
|
} else {
|
|
1685
1696
|
ctx.out(`Stopped ${slug} (team ${ctx.teamId}).\n`);
|
|
1686
1697
|
}
|
|
@@ -295,6 +295,12 @@ export interface AgentkitStopAccepted {
|
|
|
295
295
|
applicationId: string;
|
|
296
296
|
releaseId: string;
|
|
297
297
|
status: string;
|
|
298
|
+
/**
|
|
299
|
+
* `"global"` when the backend escalated the stop to the application-level
|
|
300
|
+
* suspension — the default for a multi-tenant app stopped by its
|
|
301
|
+
* publisher. Resume needs `start <slug> --global`.
|
|
302
|
+
*/
|
|
303
|
+
scope?: "global";
|
|
298
304
|
cancellation?: AgentkitCancelRunsResult;
|
|
299
305
|
}
|
|
300
306
|
|
|
@@ -471,6 +477,9 @@ const agentkitStopAcceptedSchema = z
|
|
|
471
477
|
applicationId: z.string().min(1),
|
|
472
478
|
releaseId: z.string().min(1),
|
|
473
479
|
status: z.string(),
|
|
480
|
+
// Tolerate scope values a newer backend may add: parse only "global",
|
|
481
|
+
// drop anything else rather than failing the stop response.
|
|
482
|
+
scope: z.literal("global").optional().catch(undefined),
|
|
474
483
|
cancellation: agentkitCancelRunsResultSchema.optional(),
|
|
475
484
|
})
|
|
476
485
|
.passthrough();
|
|
@@ -33,16 +33,18 @@ export function runtimeArchitectureCompatibilityError(agent: {
|
|
|
33
33
|
: undefined;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/** Author-facing default when {@link AgentConfig.architecture} is omitted. */
|
|
37
|
+
export const DEFAULT_AGENT_ARCHITECTURE: AgentArchitecture = "v2";
|
|
38
|
+
|
|
36
39
|
export function resolveArchitecture(
|
|
37
40
|
ctx: DiscoveryContext,
|
|
38
41
|
agentDir: string,
|
|
39
42
|
architecture: AgentArchitecture | undefined
|
|
40
43
|
): AgentArchitecture | undefined {
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
) {
|
|
44
|
+
if (architecture === undefined) {
|
|
45
|
+
return DEFAULT_AGENT_ARCHITECTURE;
|
|
46
|
+
}
|
|
47
|
+
if (architecture === "v1" || architecture === "v2") {
|
|
46
48
|
return architecture;
|
|
47
49
|
}
|
|
48
50
|
ctx.diagnostics.push({
|
|
@@ -55,7 +57,7 @@ export function resolveArchitecture(
|
|
|
55
57
|
|
|
56
58
|
/**
|
|
57
59
|
* `persistent: true` selects the long-lived-pod hosting mode of v2. It has
|
|
58
|
-
* no meaning on v1 (resident engine)
|
|
60
|
+
* no meaning on v1 (resident engine).
|
|
59
61
|
*/
|
|
60
62
|
export function resolvePersistent(
|
|
61
63
|
ctx: DiscoveryContext,
|
|
@@ -66,7 +66,7 @@ import { resolveAgentV2Hosting } from "./v2-hosting.js";
|
|
|
66
66
|
export interface FrameworkStorageSelectionInput {
|
|
67
67
|
/** `agent/storage.ts`, when the author wrote one (v1 only: discovery rejects it on v2). */
|
|
68
68
|
readonly authored: StorageDefinition | undefined;
|
|
69
|
-
/** {@link AgentConfig.architecture};
|
|
69
|
+
/** {@link AgentConfig.architecture}; discovery fills `"v2"` when omitted. */
|
|
70
70
|
readonly architecture?: AgentArchitecture | undefined;
|
|
71
71
|
/** Environment override for tests; defaults to `process.env`. */
|
|
72
72
|
readonly env?: Record<string, string | undefined>;
|
|
@@ -236,6 +236,28 @@ async function timedWorkJsonFetch(
|
|
|
236
236
|
});
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
+
const CP_ERROR_BODY_LIMIT = 512;
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Read failures carry status and a bounded body: the guest logs them once
|
|
243
|
+
* per process, and a 405 body names the route the caller should be on.
|
|
244
|
+
*/
|
|
245
|
+
async function reminderCpReadError(
|
|
246
|
+
what: string,
|
|
247
|
+
response: Response
|
|
248
|
+
): Promise<Error> {
|
|
249
|
+
let body = "";
|
|
250
|
+
try {
|
|
251
|
+
body = (await response.text()).trim();
|
|
252
|
+
} catch {
|
|
253
|
+
// Status-only detail.
|
|
254
|
+
}
|
|
255
|
+
const detail = body === "" ? "" : ` ${body.slice(0, CP_ERROR_BODY_LIMIT)}`;
|
|
256
|
+
return new Error(
|
|
257
|
+
`reminder CP ${what} failed: HTTP ${response.status}${detail}`
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
239
261
|
/**
|
|
240
262
|
* Cursor-hosted HTTP ReminderControlPlane for architecture v2.
|
|
241
263
|
* Speaks factory `/internal/agentsdk/reminders` (ELB → factory ECS).
|
|
@@ -275,7 +297,7 @@ export function createCursorHostedReminderControlPlane(
|
|
|
275
297
|
return undefined;
|
|
276
298
|
}
|
|
277
299
|
if (!response.ok) {
|
|
278
|
-
throw
|
|
300
|
+
throw await reminderCpReadError("get", response);
|
|
279
301
|
}
|
|
280
302
|
const parsed: unknown = await response.json();
|
|
281
303
|
return isReminderRecord(parsed) ? parsed : undefined;
|
|
@@ -287,7 +309,7 @@ export function createCursorHostedReminderControlPlane(
|
|
|
287
309
|
`${AGENTSDK_REMINDERS_PREFIX}/reminders`
|
|
288
310
|
);
|
|
289
311
|
if (!response.ok) {
|
|
290
|
-
throw
|
|
312
|
+
throw await reminderCpReadError("list", response);
|
|
291
313
|
}
|
|
292
314
|
const parsed: unknown = await response.json();
|
|
293
315
|
if (
|