@agentconnect.md/setup 1.37.0-rc.3 → 1.37.0-rc.4

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/index.js CHANGED
@@ -36023,20 +36023,6 @@ const ZodRecord = /*@__PURE__*/ $constructor("ZodRecord", (inst, def) => {
36023
36023
  inst.keyType = def.keyType;
36024
36024
  inst.valueType = def.valueType;
36025
36025
  });
36026
- function record$1(keyType, valueType, params) {
36027
- if (!valueType || !valueType._zod) return new ZodRecord({
36028
- type: "record",
36029
- keyType: string(),
36030
- valueType: keyType,
36031
- ...normalizeParams(valueType)
36032
- });
36033
- return new ZodRecord({
36034
- type: "record",
36035
- keyType,
36036
- valueType,
36037
- ...normalizeParams(params)
36038
- });
36039
- }
36040
36026
  function partialRecord(keyType, valueType, params) {
36041
36027
  const k = clone(keyType);
36042
36028
  k._zod.values = void 0;
@@ -36293,1115 +36279,16 @@ function number(params) {
36293
36279
  return /* @__PURE__ */ _coercedNumber(ZodNumber, params);
36294
36280
  }
36295
36281
  //#endregion
36296
- //#region ../protocol/dist/envelope.js
36282
+ //#region ../protocol/dist/slack-app-manifest.js
36297
36283
  var import_fastify = /* @__PURE__ */ __toESM(require_fastify(), 1);
36298
- object({
36299
- v: literal(1),
36300
- id: string().uuid(),
36301
- ts: string().datetime(),
36302
- type: string(),
36303
- corr: string().uuid().optional(),
36304
- payload: unknown()
36305
- });
36306
- object({
36307
- epoch: number$1().int(),
36308
- agentId: string().uuid().optional(),
36309
- launchId: string().uuid().optional()
36310
- });
36311
- /**
36312
- * Builds the envelope schema for one frame `type` — the `type` literal plus the
36313
- * typed payload — so a wire's discriminated union infers `payload` precisely.
36314
- * Shared by the daemon↔CP union (`frame.ts`) and the relay wire unions
36315
- * (`frames/relay-cp.ts` / `frames/relay-daemon.ts`), which are deliberately
36316
- * SEPARATE unions over the same envelope shape (shared-bot-relay.md §8).
36317
- */
36318
- function frameSchema(type, payload) {
36319
- return object({
36320
- v: literal(1),
36321
- id: string().uuid(),
36322
- ts: string().datetime(),
36323
- type: literal(type),
36324
- corr: string().uuid().optional(),
36325
- payload
36326
- });
36327
- }
36328
- const ErrorFrame = object({
36329
- code: _enum([
36330
- "UNKNOWN_FRAME",
36331
- "FRAME_TOO_LARGE",
36332
- "PROTOCOL_STATE",
36333
- "BAD_PAYLOAD",
36334
- "AUTH_FAILED",
36335
- "ATTESTATION_INVALID",
36336
- "STALE_EPOCH",
36337
- "STALE_LAUNCH",
36338
- "NO_SESSION",
36339
- "SCOPE_DENIED",
36340
- "DELEGATION_DENIED",
36341
- "INVOCATION_CONFLICT",
36342
- "LEASE_EXPIRED",
36343
- "LEASE_DENIED",
36344
- "RATE_LIMITED",
36345
- "CONFLICT",
36346
- "INTERNAL"
36347
- ]),
36348
- message: string(),
36349
- retryable: boolean(),
36350
- details: record$1(string(), unknown()).optional()
36351
- });
36352
- //#endregion
36353
- //#region ../protocol/dist/frames/route.js
36354
- const Platform = string().min(1);
36355
- const SessionKey = object({
36356
- platform: Platform,
36357
- channel: string(),
36358
- thread: string().optional()
36359
- });
36360
- /** Trigger-matching rule for a binding (protocol §5.1). */
36361
- const BindRule = object({ match: discriminatedUnion("kind", [
36362
- object({ kind: literal("mention") }),
36363
- object({ kind: literal("dm") }),
36364
- object({
36365
- kind: literal("keyword"),
36366
- value: string()
36367
- }),
36368
- object({ kind: literal("auto") })
36369
- ]) });
36370
- object({
36371
- sessionKey: SessionKey,
36372
- agentId: string().uuid(),
36373
- workspaceId: string().uuid(),
36374
- bindRules: array(BindRule).default([])
36375
- });
36376
- object({
36377
- ok: boolean(),
36378
- sessionKey: SessionKey,
36379
- reason: string().optional()
36380
- });
36381
- object({
36382
- routingEpoch: number$1().int(),
36383
- rules: array(object({
36384
- match: unknown(),
36385
- agentId: string().uuid()
36386
- }))
36387
- });
36388
- object({
36389
- scope: union([
36390
- object({
36391
- kind: literal("agent"),
36392
- agentId: string().uuid()
36393
- }),
36394
- object({ kind: literal("daemon") }),
36395
- object({
36396
- kind: literal("session"),
36397
- sessionKey: SessionKey
36398
- })
36399
- ]),
36400
- deadline: string().datetime()
36401
- });
36402
- object({
36403
- remaining: number$1().int(),
36404
- drained: array(SessionKey)
36405
- });
36406
- object({ released: array(SessionKey) });
36407
- //#endregion
36408
- //#region ../protocol/dist/frames/integration.js
36409
- /**
36410
- * Platform integration distribution (C→D) — the Slack "install" flow.
36411
- *
36412
- * The Control Plane is the source of truth for platform integrations and pushes
36413
- * them to the daemon that owns the integration's agent (`integration/upsert`, and
36414
- * the reconcile snapshot `RegisterOk.integrations[]`). The daemon opens the Socket
36415
- * Mode connection from the delivered config (see slack/connection.ts).
36416
- *
36417
- * SECURITY: `integration/upsert` and `RegisterOk.integrations[]` carry PLAINTEXT
36418
- * platform tokens (botToken/appToken/appSecret). These payloads MUST NEVER be
36419
- * logged — no body dump on decode error, no register/ok snapshot debug dump.
36420
- * CP-owned integrations live only in daemon MEMORY and are re-converged on
36421
- * reconnect; hand-authored agents keep tokens in their own `agent.json` (the
36422
- * same trust boundary as the daemon process).
36423
- *
36424
- * `signingSecret` is intentionally absent: Socket Mode authenticates with the
36425
- * app-level token, so the daemon never needs a signing secret.
36426
- */
36427
- /** Trigger match — mirrors the daemon BindRuleConfig.match (agents/agent-schema.ts). */
36428
- const BindMatch = discriminatedUnion("kind", [
36429
- object({ kind: literal("mention") }),
36430
- object({ kind: literal("dm") }),
36431
- object({
36432
- kind: literal("keyword"),
36433
- value: string()
36434
- }),
36435
- object({ kind: literal("auto") })
36436
- ]);
36437
- /** One channel/thread trigger binding — mirrors the daemon BindRuleConfig. */
36438
- const IntegrationBindRule = object({
36439
- channel: string().optional(),
36440
- thread: string().optional(),
36441
- match: BindMatch
36442
- });
36443
- object({
36444
- botToken: string(),
36445
- appToken: string().optional(),
36446
- appId: string().optional(),
36447
- shareable: boolean().default(false),
36448
- botUserId: string().optional()
36449
- });
36450
- object({ botToken: string() });
36451
- object({
36452
- botToken: string(),
36453
- applicationId: string().optional()
36454
- });
36455
- /**
36456
- * The Feishu / Lark config payload — the long-connection WebSocket
36457
- * (`@larksuiteoapi/node-sdk` `WSClient`) + REST client. A Feishu self-built app
36458
- * authenticates with an `appId` + `appSecret` PAIR — the SDK exchanges them for a
36459
- * short-lived `tenant_access_token` internally (no Slack-style app-level token, no
36460
- * signing secret). `appId` is a semi-public identifier (`cli_…`); `appSecret` is
36461
- * plaintext secret material — NEVER log it. `botOpenId` is the bot's own open_id
36462
- * for @-mention routing; lazily resolved by the daemon via `bot/info` if absent.
36463
- *
36464
- * The envelope's `mode` decides the transport: `direct` opens the SDK long
36465
- * connection on the daemon; `shared` keeps only the authenticated REST client
36466
- * (callbacks arrive through the relay, pre-addressed over rd/*).
36467
- *
36468
- * `region` selects the open-platform gateway the daemon SDK (and CP verifier)
36469
- * talk to — `'feishu'` = mainland China (`open.feishu.cn`, the SDK default) vs
36470
- * `'lark'` = international (`open.larksuite.com`). Same app model, different host;
36471
- * an app is registered in exactly one region. Defaults to `'feishu'` so existing
36472
- * installs are unaffected.
36473
- */
36474
- const FeishuRegion = _enum(["feishu", "lark"]);
36475
- object({
36476
- appId: string(),
36477
- appSecret: string(),
36478
- botOpenId: string().optional(),
36479
- region: FeishuRegion.default("feishu")
36480
- });
36481
- /**
36482
- * §6.4 core routing ENVELOPE (integration-plugin-architecture.md D4): the knobs CORE
36483
- * reads — routing, gating, ingress mode — platform-independent. This is the ONLY
36484
- * carrier of these knobs on the wire: the opaque per-platform `config` payload
36485
- * never duplicates them (the daemon reads routing exclusively from here).
36486
- */
36487
- const IntegrationCoreEnvelope = object({
36488
- mode: _enum(["direct", "shared"]).default("direct"),
36489
- bindRules: array(IntegrationBindRule).default([]),
36490
- mutedChannels: array(string()).default([]),
36491
- gated: boolean().default(false)
36492
- });
36493
- object({
36494
- integrationId: string().uuid(),
36495
- agentId: string().uuid(),
36496
- platform: Platform,
36497
- core: IntegrationCoreEnvelope,
36498
- config: unknown().optional()
36499
- });
36500
- object({ integrationId: string().uuid() });
36501
- /**
36502
- * One conversation the bot participates in (metadata only — no messages).
36503
- * `kind` distinguishes member channels from direct conversations (resource-
36504
- * visibility.md §14.3): absent = 'channel' for wire compatibility. DM rows
36505
- * (`kind: 'im'`, Slack "D…" ids) are reported for every integration on first
36506
- * inbound DM; their `name` is the counterpart's display name. Group DMs
36507
- * (`kind: 'mpim'`, Slack multi-person DMs) are reported on observation the same
36508
- * way — never enumerated, because Slack does not list them as bot membership —
36509
- * but they behave like a channel: several humans share the room, so the agent
36510
- * stays mention-gated there rather than answering every message.
36511
- *
36512
- * `spaceId`/`space` identify the container the conversation lives in — a Discord
36513
- * GUILD, which a bot in several servers needs for the channel to be identifiable at
36514
- * all (every server has a "#general"). The ID is the identity: two distinct guilds
36515
- * may carry the SAME name, so grouping on the name alone would merge them and hide
36516
- * the ambiguity it was meant to resolve. `space` is the display label only. Both are
36517
- * absent on platforms with one implicit container per bot (Slack workspace, Telegram,
36518
- * Feishu tenant) and on DM rows.
36519
- */
36520
- const IntegrationChannel = object({
36521
- id: string(),
36522
- name: string().optional(),
36523
- spaceId: string().optional(),
36524
- space: string().optional(),
36525
- isPrivate: boolean().optional(),
36526
- kind: _enum([
36527
- "channel",
36528
- "im",
36529
- "mpim"
36530
- ]).optional()
36531
- });
36532
- object({
36533
- integrationId: string().uuid(),
36534
- channels: array(IntegrationChannel),
36535
- authoritative: boolean().optional(),
36536
- removed: array(string()).optional()
36537
- });
36538
- /**
36539
- * What a leave targets. Platforms disagree about what a bot can withdraw from, and
36540
- * the difference is not cosmetic — so the caller has to say which it means rather
36541
- * than the daemon guessing from an id:
36542
- *
36543
- * - `conversation` — one channel/group the bot is a member of (Slack
36544
- * `conversations.leave`, Telegram `leaveChat`).
36545
- * - `space` — the whole container. Discord has no per-channel membership for a
36546
- * bot at all: it is in a GUILD and sees that guild's channels through
36547
- * permissions, so the only thing it can leave is the entire server. That is a
36548
- * much larger action than leaving one channel and must be requested as such.
36549
- */
36550
- const IntegrationLeaveTarget = discriminatedUnion("kind", [object({
36551
- kind: literal("conversation"),
36552
- channel: string().min(1)
36553
- }), object({
36554
- kind: literal("space"),
36555
- spaceId: string().min(1)
36556
- })]);
36557
- object({
36558
- integrationId: string().uuid(),
36559
- target: IntegrationLeaveTarget
36560
- });
36561
- object({
36562
- integrationId: string().uuid(),
36563
- channels: array(string()).min(1)
36564
- });
36565
- object({
36566
- ok: boolean(),
36567
- error: string().optional()
36568
- });
36569
- //#endregion
36570
- //#region ../protocol/dist/frames/cron.js
36571
- /**
36572
- * Cron sinks to the daemon (D5) — protocol §5.4.
36573
- *
36574
- * A cron periodically triggers ONE AGENT with a synthetic prompt (`trigger`) to
36575
- * carry out some work. The CP owns the definition; the daemon owns firing +
36576
- * last-run persistence, so crons fire even when the CP is down. On receipt the
36577
- * daemon persists the def into the owning agent's `agent.json` `crons[]` (the
36578
- * single source of truth, same model as integrations) — surviving a restart
36579
- * with the CP down.
36580
- *
36581
- * `target` is OPTIONAL output routing: when present, the daemon posts the
36582
- * trigger as a real message in that channel and the agent's session replies in
36583
- * its thread; when absent the fire is headless (the agent works with no
36584
- * platform output).
36585
- */
36586
- const CronTarget = object({
36587
- platform: Platform.default("slack"),
36588
- channel: string(),
36589
- integrationId: string().uuid().optional()
36590
- });
36591
- object({
36592
- cronId: string().uuid(),
36593
- agentId: string().uuid(),
36594
- schedule: string(),
36595
- timezone: string().min(1),
36596
- target: CronTarget.optional(),
36597
- trigger: string(),
36598
- enabled: boolean().default(true)
36599
- });
36600
- object({ cronId: string().uuid() });
36601
- /**
36602
- * `cron/report` (D→C EVT, fire-and-forget) — one CP-owned cron fired. The
36603
- * daemon stamps the fire into its local store first (it stays authoritative,
36604
- * §5.4) and reports it here so the console's `lastRunAt` converges; the CP
36605
- * upsert is latest-wins, so the daemon re-asserting its stored stamps on
36606
- * reconnect (fires while the CP was unreachable) is idempotent and can never
36607
- * regress the value. Hand-authored (no-origin) crons are never reported.
36608
- *
36609
- * Reports are keyed by `(cronId, firedAt)`: the FIRE report (no `status`)
36610
- * opens the run, an optional SESSION report attaches the ACP session as soon
36611
- * as it is initialized, and the COMPLETION report (with `status` + outcome
36612
- * fields) closes the run once the dispatched turn ends. A completion without
36613
- * a prior fire report (CP was down at fire time) still creates the run row.
36614
- */
36615
- const CronRunStatus = _enum(["success", "failed"]);
36616
- object({
36617
- cronId: string().uuid(),
36618
- agentId: string().uuid(),
36619
- firedAt: string().datetime(),
36620
- status: CronRunStatus.optional(),
36621
- durationMs: number$1().int().nonnegative().optional(),
36622
- sessionId: string().optional(),
36623
- reason: string().optional()
36624
- });
36625
- object({ cronId: string().uuid() });
36626
- //#endregion
36627
- //#region ../protocol/dist/frames/collab.js
36628
- /**
36629
- * Bot-AGNOSTIC agent-collaboration routing snapshot (agent-collaboration §2.3 / §6.2 / §6.5).
36630
- *
36631
- * The existing shared-bot `members` table is keyed by botId (`BotAssignment`) and
36632
- * CANNOT address an agent on a DIFFERENT bot / arbitrary channel. This snapshot is
36633
- * the fix: it maps a channel — `(orgId, platform, channelId)` — to the per-agent
36634
- * placement + call policy the relay needs to route a cross-daemon `rd/agentmsg` and
36635
- * the target daemon needs to terminal-verify a remote caller.
36636
- *
36637
- * It carries NO message body — pure routing/policy metadata, like the rest of the
36638
- * control plane. The SAME shape is distributed two ways (§6.5):
36639
- * - CP→relay over the `rc/*` wire (`rc/collab-routes`) — the relay routes
36640
- * `toAgentId` → owning `daemonId` and authorizes the caller/target policy.
36641
- * - CP→daemon over the daemon↔CP wire — as a `register/ok` field (reconnect
36642
- * baseline) + a `collaboration/routes` EVT (hot push) — so the OWNING daemon of
36643
- * the target can terminal-verify (defense in depth, §2.5 #4) the remote caller's
36644
- * org/channel/placement against its OWN copy, never trusting the relay's claim
36645
- * blindly.
36646
- *
36647
- * FOLLOW-UP (scoped down in P2, see PR description): the full versioned lifecycle
36648
- * of §6.5 — per-entry tombstones, TTL/expiry after a CP disconnect, and
36649
- * fail-closed-on-stale — is NOT fully implemented here. `generation` is present as
36650
- * the version hook and the snapshot is FULL-REPLACE (converge-don't-diff, same as
36651
- * `register/ok`), which is enough to route + authorize on a live CP. TTL-expiry and
36652
- * tombstone semantics are a follow-up within this phase.
36653
- */
36654
- /** One agent's placement + call policy within a channel. `daemonId` is the owning
36655
- * daemon the relay forwards to; `integrationId` is the DEFINITE reply integration
36656
- * (§6.2 — no fallback to "first connection"). */
36657
- const CollabAgentPlacement = object({
36658
- agentId: string().uuid(),
36659
- daemonId: string().uuid(),
36660
- integrationId: string().uuid().optional(),
36661
- /** Public Slack app id (`A…`) for this agent's bot. Receivers use it to recognize
36662
- * AgentConnect-authored platform messages — the first half of verifying an
36663
- * authorship claim (send-message-routing-rework.md §4). */
36664
- botAppId: string().optional(),
36665
- /** Public platform member id this agent's bot posts as (Slack `U…`) — the id a
36666
- * `<@…>` mention resolves to. With {@link botShared} and `name` it is the complete
36667
- * input for the conversation-specific mention ADDRESS
36668
- * (send-message-routing-rework.md §8.5), which both directions need: rendering an
36669
- * exact address to post, and resolving an inbound mention back to an agent.
36670
- * Public metadata, never a credential. */
36671
- botUserId: string().optional(),
36672
- /** True when {@link botUserId} backs MORE THAN ONE agent (a shared bot). The bot user
36673
- * id alone then cannot identify an agent, so its address carries the agent slug too
36674
- * (`<@U_SHARED> reviewer`) and a BARE mention of it addresses no specific agent —
36675
- * which is why a shared bot with no exact author claim fails closed at ingress (§4)
36676
- * and why a bare shared-bot mention from an agent must not fall back to the channel
36677
- * default (§6). */
36678
- botShared: boolean().optional(),
36679
- callPolicy: _enum(["all", "selected"]).default("all"),
36680
- allowedCallerAgentIds: array(string()).default([]),
36681
- /** Caller-side authorization. Effective A→B access requires A's outbound
36682
- * policy to admit B and B's inbound call policy to admit A. */
36683
- outboundPolicy: _enum(["all", "selected"]).default("all"),
36684
- allowedTargetAgentIds: array(string()).default([]),
36685
- name: string().optional(),
36686
- displayName: string().optional()
36687
- });
36688
- /**
36689
- * One agent's placement + call policy carried OUTSIDE any channel — the org-scoped
36690
- * peer directory entry.
36691
- *
36692
- * Every structure on the CP→daemon and CP→relay wires is channel-keyed, so an agent
36693
- * with NO IM integration (webchat, hook, dream, memory-only) never appears in any
36694
- * `channels[]` entry at all. The channel-keyed snapshot structurally cannot express
36695
- * "which agents exist in this org", which is precisely the input channel-free
36696
- * authorization needs: discovery and A2A authorization depend only on the directional
36697
- * call policy (`outboundPolicy`/`allowedTargetAgentIds` on the caller,
36698
- * `callPolicy`/`allowedCallerAgentIds` on the target), org-scoped, with channel
36699
- * demoted to an optional filter. Hence the flat list below.
36700
- */
36701
- const CollabOrgAgent = CollabAgentPlacement.extend({ orgId: string().min(1) });
36702
- /** All agents present in one channel, across daemons. `orgId` scopes routing +
36703
- * authorization: a cross-org caller/target pair never resolves (§2.5 — cross-org
36704
- * rejected). */
36705
- const CollabChannelRoute = object({
36706
- orgId: string().min(1),
36707
- platform: Platform,
36708
- channelId: string().min(1),
36709
- agents: array(CollabAgentPlacement)
36710
- });
36711
- /**
36712
- * The full collaboration snapshot — FULL-REPLACE (converge-don't-diff): the
36713
- * recipient replaces its whole table with `channels`. `generation` monotonically
36714
- * increases per source so a recipient can ignore a stale re-order (version hook for
36715
- * the §6.5 lifecycle follow-up).
36716
- */
36717
- const CollabRoutesSnapshot = object({
36718
- generation: number$1().int().nonnegative().default(0),
36719
- channels: array(CollabChannelRoute).default([]),
36720
- /**
36721
- * FLAT org-scoped directory, alongside (not instead of) `channels`. It is the only
36722
- * place an integration-less agent can appear — see `CollabOrgAgent` — and therefore
36723
- * the authorization input for channel-free A2A. `default([])` keeps a snapshot from
36724
- * an older CP (which advertises no `agent-directory-org-scope-v1`) decodable.
36725
- */
36726
- agents: array(CollabOrgAgent).default([]),
36727
- /**
36728
- * §6.1 origin-kind classification for the platform ids the EMITTER knows — how an
36729
- * older peer classifies an id a newer CP introduces (its own built-in seed only
36730
- * covers ids its build shipped with). Consumers overlay these entries on their
36731
- * seed; an id classified by neither defaults to `'chat'`, the fail-closed answer
36732
- * wherever placements matter (`coordsDecision`). Both fields read as open strings
36733
- * per the S1a rule. `default([])` keeps a pre-S1b snapshot decodable.
36734
- */
36735
- platformKinds: array(object({
36736
- platformId: string().min(1),
36737
- originKind: string().min(1)
36738
- })).default([])
36739
- });
36740
- //#endregion
36741
- //#region ../protocol/dist/frames/hook.js
36742
- /** Decimal wire form for Prisma/GitHub bigint values. */
36743
- const HookBigIntString = string().regex(/^(?:0|[1-9]\d*)$/);
36744
- /** The highest formal-review event one hook permits. */
36745
- const HookReviewPolicy = _enum([
36746
- "off",
36747
- "comment",
36748
- "request_changes",
36749
- "full"
36750
- ]);
36751
- /** External run-reporting transport. `status` is reserved for the later R3. */
36752
- const HookReportingMode = _enum([
36753
- "off",
36754
- "check",
36755
- "status"
36756
- ]);
36757
- /** R2a only admits informational; `required` remains a fail-closed future mode. */
36758
- const HookGateMode = _enum(["informational", "required"]);
36759
- /**
36760
- * Exact config + dispatch identity captured when the CP compiles a hook fire.
36761
- *
36762
- * The relay-facing frames expose these fields individually at top level so an
36763
- * older CP/relay can omit them without making the whole fire undecodable. A
36764
- * consumer MUST have every field before enabling review/reporting; absence is
36765
- * not filled with a revision and therefore fails closed. Action-time RPCs use
36766
- * this complete object so a partially rolled-out tuple cannot authorize an
36767
- * effect.
36768
- */
36769
- const HookConfigSnapshot = object({
36770
- configRevision: HookBigIntString,
36771
- dispatchRevision: HookBigIntString,
36772
- dispatchDaemonId: string().uuid(),
36773
- reviewPolicy: HookReviewPolicy,
36774
- reportingMode: HookReportingMode,
36775
- gateMode: HookGateMode
36776
- });
36777
- /** Optional top-level form used only on rolling-compatible delivery frames. */
36778
- const OptionalHookConfigSnapshot = HookConfigSnapshot.partial();
36779
- /**
36780
- * Trusted, body-free GitHub subject/revision metadata. It is deliberately
36781
- * separate from HookContext: HookContext contains attacker-authored prompt
36782
- * excerpts, whereas this object is cut from a signature-verified payload and
36783
- * fenced to the CP-compiled numeric repo/installation rule.
36784
- *
36785
- * `headSha` is absent for PR issue_comment deliveries because GitHub omits the
36786
- * revision there; the daemon resolves it before `hook/start`. R2a informational
36787
- * checks use `reportSha=headSha` once known. Review-comment deliveries may also
36788
- * identify the triggering comment and its normalized thread root; both remain
36789
- * optional so mixed-version relay/daemon rollouts continue to decode.
36790
- */
36791
- const GithubHookMetadata = object({
36792
- repoId: HookBigIntString,
36793
- repoFullName: string().min(1),
36794
- sourceInstallationId: HookBigIntString,
36795
- subjectKind: _enum(["issue", "pull_request"]),
36796
- pullNumber: number$1().int().positive().optional(),
36797
- headSha: string().min(1).optional(),
36798
- baseSha: string().min(1).optional(),
36799
- reportSha: string().min(1).optional(),
36800
- headRepoFullName: string().min(1).optional(),
36801
- mergeCommitSha: string().min(1).optional(),
36802
- isDraft: boolean().optional(),
36803
- baseChanged: boolean().optional(),
36804
- explicitReviewRequest: boolean().optional(),
36805
- reviewCommentId: HookBigIntString.optional(),
36806
- reviewThreadRootCommentId: HookBigIntString.optional()
36807
- }).superRefine((value, ctx) => {
36808
- if (value.subjectKind === "pull_request" && value.pullNumber === void 0) ctx.addIssue({
36809
- code: "custom",
36810
- path: ["pullNumber"],
36811
- message: "pullNumber is required for a pull_request subject"
36812
- });
36813
- if (value.reportSha !== void 0 && value.headSha === void 0) ctx.addIssue({
36814
- code: "custom",
36815
- path: ["reportSha"],
36816
- message: "reportSha requires an authoritative headSha"
36817
- });
36818
- if (value.reportSha !== void 0 && value.headSha !== void 0 && value.reportSha !== value.headSha) ctx.addIssue({
36819
- code: "custom",
36820
- path: ["reportSha"],
36821
- message: "R2a reports only the authoritative pull head SHA"
36822
- });
36823
- });
36824
- const HookReviewEvent = _enum([
36825
- "COMMENT",
36826
- "REQUEST_CHANGES",
36827
- "APPROVE"
36828
- ]);
36829
- const HookReviewVerdict = _enum([
36830
- "pass",
36831
- "fail",
36832
- "neutral"
36833
- ]);
36834
- /** Short machine code only; raw GitHub/runtime exception text never crosses to reporting. */
36835
- const HookReviewResultCode = string().min(1).max(100).regex(/^[a-z0-9_:-]+$/);
36836
- /**
36837
- * Body-free outcome of one reserved formal-review attempt.
36838
- *
36839
- * `not_submitted` is only legal after a deterministic no-effect failure and
36840
- * lets the CP release the reservation. An uncertain POST remains `ambiguous`
36841
- * until marker reconciliation proves whether GitHub created it.
36842
- */
36843
- const HookReviewResult = discriminatedUnion("state", [
36844
- object({
36845
- state: literal("submitted"),
36846
- reviewId: string().min(1),
36847
- event: HookReviewEvent,
36848
- verdict: HookReviewVerdict,
36849
- commitId: string().min(1)
36850
- }),
36851
- object({
36852
- state: literal("not_submitted"),
36853
- code: HookReviewResultCode
36854
- }),
36855
- object({
36856
- state: literal("ambiguous"),
36857
- code: HookReviewResultCode
36858
- })
36859
- ]);
36860
- /** Body-free identity of the daemon's one fallback GitHub comment. */
36861
- const GithubPublishedComment = object({
36862
- kind: _enum(["issue_comment", "review_comment"]),
36863
- commentId: HookBigIntString
36864
- });
36865
- object({
36866
- source: _enum(["webhook", "github"]),
36867
- event: string().optional(),
36868
- action: string().optional(),
36869
- repo: string().optional(),
36870
- number: number$1().int().optional(),
36871
- title: string().optional(),
36872
- senderLogin: string().optional(),
36873
- senderAvatarUrl: string().url().optional(),
36874
- authorAssociation: string().optional(),
36875
- labels: array(string()).optional(),
36876
- htmlUrl: string().optional(),
36877
- bodyExcerpt: string().optional(),
36878
- body: string().optional(),
36879
- truncated: boolean().optional()
36880
- });
36881
- object({
36882
- hookId: string().uuid(),
36883
- agentId: string().uuid(),
36884
- deliveryKey: string().min(1),
36885
- ...OptionalHookConfigSnapshot.shape,
36886
- event: string().min(1).optional(),
36887
- github: GithubHookMetadata.optional(),
36888
- status: _enum(["success", "failed"]),
36889
- durationMs: number$1().int().nonnegative().optional(),
36890
- sessionId: string().optional(),
36891
- reason: string().optional(),
36892
- reviewAttemptId: string().uuid().optional(),
36893
- reviewResult: HookReviewResult.optional(),
36894
- publishedComment: GithubPublishedComment.optional()
36895
- }).superRefine((report, ctx) => {
36896
- if (report.reviewAttemptId === void 0 !== (report.reviewResult === void 0)) ctx.addIssue({
36897
- code: "custom",
36898
- path: report.reviewAttemptId === void 0 ? ["reviewAttemptId"] : ["reviewResult"],
36899
- message: "reviewAttemptId and reviewResult must be reported together"
36900
- });
36901
- if (report.publishedComment && report.reviewResult?.state === "submitted") ctx.addIssue({
36902
- code: "custom",
36903
- path: ["publishedComment"],
36904
- message: "a submitted formal review and fallback comment are mutually exclusive"
36905
- });
36906
- });
36907
- object({
36908
- hookId: string().uuid(),
36909
- agentId: string().uuid(),
36910
- deliveryKey: string().min(1),
36911
- sessionId: string().min(1).optional(),
36912
- event: string().min(1).optional(),
36913
- github: GithubHookMetadata,
36914
- ...HookConfigSnapshot.shape
36915
- });
36916
- object({ accepted: literal(true) });
36917
- object({
36918
- hookId: string().uuid(),
36919
- deliveryKey: string().min(1),
36920
- attemptId: string().uuid(),
36921
- requestedEvent: HookReviewEvent,
36922
- requestedVerdict: HookReviewVerdict,
36923
- snapshot: HookConfigSnapshot
36924
- });
36925
- object({
36926
- attemptId: string().uuid(),
36927
- token: string().min(1),
36928
- ttlSec: number$1().int().positive(),
36929
- expiresAt: string().datetime(),
36930
- repoId: HookBigIntString,
36931
- repoFullName: string().min(1),
36932
- pullNumber: number$1().int().positive(),
36933
- expectedHeadSha: string().min(1),
36934
- expectedBaseSha: string().min(1)
36935
- });
36936
- object({
36937
- hookId: string().uuid(),
36938
- deliveryKey: string().min(1),
36939
- attemptId: string().uuid(),
36940
- snapshot: HookConfigSnapshot,
36941
- result: HookReviewResult
36942
- });
36943
- object({ accepted: literal(true) });
36944
- //#endregion
36945
- //#region ../protocol/dist/frames/remote-mcp.js
36946
- /** Non-secret entitlement carried CP → relay → daemon after webchat verification. */
36947
- const WebchatRemoteMcpEntitlement = object({
36948
- authorityId: string().uuid(),
36949
- authorityGeneration: number$1().int().positive(),
36950
- expiresAt: string().datetime()
36951
- }).strict();
36952
- const DescriptorFence = object({
36953
- authorityId: string().uuid(),
36954
- authorityGeneration: number$1().int().positive(),
36955
- conversationId: string().uuid(),
36956
- descriptorInstanceId: string().uuid(),
36957
- grantRevision: number$1().int().positive()
36958
- }).strict();
36959
- object({
36960
- authorityId: string().uuid(),
36961
- authorityGeneration: number$1().int().positive(),
36962
- conversationId: string().uuid(),
36963
- descriptorInstanceId: string().uuid()
36964
- }).strict();
36965
- DescriptorFence.extend({
36966
- grantId: string().uuid(),
36967
- token: string().min(32),
36968
- expiresAt: string().datetime(),
36969
- mcpUrl: string().url()
36970
- }).strict();
36971
- DescriptorFence.extend({ grantId: string().uuid() }).strict().extend({ activated: boolean() }).strict();
36972
- object({
36973
- authorityId: string().uuid(),
36974
- authorityGeneration: number$1().int().positive(),
36975
- conversationId: string().uuid(),
36976
- reason: _enum([
36977
- "session_closed",
36978
- "session_expired",
36979
- "agent_detached",
36980
- "feature_disabled",
36981
- "security"
36982
- ])
36983
- }).strict().pick({
36984
- authorityId: true,
36985
- authorityGeneration: true,
36986
- conversationId: true
36987
- }).extend({ revoked: boolean() }).strict();
36988
- //#endregion
36989
- //#region ../protocol/dist/frames/relay-cp.js
36990
- const RcAuth = object({
36991
- method: _enum(["token", "apikey"]),
36992
- credential: string().min(1)
36993
- });
36994
- const RcDeploymentConfig = object({
36995
- revision: number$1().int().nonnegative(),
36996
- githubWebhookSecret: string().min(1).optional()
36997
- });
36998
- const RcAuthOk = object({
36999
- heartbeatSec: number$1().int(),
37000
- serverTime: string().datetime(),
37001
- deploymentConfig: RcDeploymentConfig.optional()
37002
- });
37003
- const RcRegister = object({
37004
- name: string().min(1),
37005
- daemonUrl: string().min(1)
37006
- });
37007
- const RcRegistered = object({ relayId: string().uuid() });
37008
- const RcHeartbeat = object({});
37009
- const RcVerify = discriminatedUnion("kind", [object({
37010
- kind: literal("daemon-key"),
37011
- credential: string().min(1)
37012
- }), object({
37013
- kind: literal("webchat-token"),
37014
- credential: string().min(1),
37015
- conversationBinding: literal("v1").optional()
37016
- })]);
37017
- const RcWebchatParticipant = object({
37018
- agentId: string().uuid(),
37019
- daemonId: string().uuid().optional(),
37020
- primary: boolean().optional()
37021
- });
37022
- const RcVerifyResult = object({
37023
- ok: boolean(),
37024
- reason: string().optional(),
37025
- orgId: string().optional(),
37026
- daemonId: string().uuid().optional(),
37027
- userId: string().optional(),
37028
- user: string().optional(),
37029
- agentId: string().uuid().optional(),
37030
- conversationId: string().uuid().optional(),
37031
- participants: array(RcWebchatParticipant).max(16).optional(),
37032
- remoteMcp: WebchatRemoteMcpEntitlement.optional()
37033
- });
37034
- const RcGithubHookFence = object({
37035
- hookId: string().uuid(),
37036
- configRevision: HookBigIntString,
37037
- dispatchRevision: HookBigIntString
37038
- }).strict();
37039
- const RcGithubCommentAuthz = object({
37040
- hookId: string().uuid(),
37041
- installationId: string().regex(/^[1-9]\d*$/),
37042
- repoId: string().regex(/^[1-9]\d*$/),
37043
- repoFullName: string().regex(/^[^/\s]+\/[^/\s]+$/),
37044
- senderLogin: string().min(1),
37045
- subjectAuthorLogin: string().min(1).optional(),
37046
- configRevision: HookBigIntString,
37047
- dispatchRevision: HookBigIntString,
37048
- siblingFences: array(RcGithubHookFence).min(1).optional()
37049
- }).strict();
37050
- const RcGithubCommentAuthzResult = object({ allowed: boolean() }).strict();
37051
- const GithubNumericId = string().regex(/^[1-9]\d*$/);
37052
- const RcGithubRerequest = union([object({
37053
- checkRunId: GithubNumericId,
37054
- repoId: GithubNumericId,
37055
- headSha: string().min(1),
37056
- deliveryKey: string().min(1).max(200),
37057
- includeBaseSha: literal(true).optional()
37058
- }).strict(), object({
37059
- scope: literal("suite"),
37060
- appId: GithubNumericId,
37061
- installationId: GithubNumericId,
37062
- repoId: GithubNumericId,
37063
- headSha: string().min(1),
37064
- deliveryKey: string().min(1).max(200)
37065
- }).strict()]);
37066
- const RcGithubRerequestTarget = object({
37067
- hookId: string().uuid(),
37068
- pullNumber: number$1().int().positive(),
37069
- baseSha: string().min(1),
37070
- configRevision: HookBigIntString,
37071
- dispatchRevision: HookBigIntString
37072
- }).strict();
37073
- const RcGithubRerequestResult = union([
37074
- object({ allowed: literal(false) }).strict(),
37075
- object({
37076
- allowed: literal(true),
37077
- hookId: string().uuid(),
37078
- pullNumber: number$1().int().positive(),
37079
- baseSha: string().min(1).optional(),
37080
- configRevision: HookBigIntString,
37081
- dispatchRevision: HookBigIntString
37082
- }).strict(),
37083
- object({
37084
- allowed: literal(true),
37085
- targets: array(RcGithubRerequestTarget).min(1)
37086
- }).strict()
37087
- ]);
37088
- const RcHookAssign = object({
37089
- hookId: string().uuid(),
37090
- kind: _enum(["webhook", "github"]),
37091
- agentId: string().uuid(),
37092
- daemonId: string().uuid(),
37093
- ...OptionalHookConfigSnapshot.shape,
37094
- sessionMode: _enum([
37095
- "perDelivery",
37096
- "perThread",
37097
- "shared"
37098
- ]),
37099
- target: CronTarget.optional(),
37100
- webhook: object({
37101
- urlToken: string().min(1),
37102
- hmacSecret: string().optional()
37103
- }).optional(),
37104
- github: object({
37105
- repoId: string(),
37106
- repoFullName: string(),
37107
- sessionKeyPrefix: string().min(1).optional(),
37108
- events: array(string()),
37109
- labelFilter: array(string()),
37110
- commentFamilies: array(_enum(["issues", "pull_request"])).optional(),
37111
- mentionOnly: boolean(),
37112
- appSlug: string().optional(),
37113
- agentName: string().optional(),
37114
- installationIds: array(string())
37115
- }).optional()
37116
- }).superRefine((rule, ctx) => {
37117
- if (rule.dispatchDaemonId !== void 0 && rule.dispatchDaemonId !== rule.daemonId) ctx.addIssue({
37118
- code: "custom",
37119
- path: ["dispatchDaemonId"],
37120
- message: "dispatchDaemonId must equal daemonId on a compiled rule"
37121
- });
37122
- });
37123
- const RcHookRemove = object({ hookId: string().uuid() });
37124
- const RcRunReport = object({
37125
- hookId: string().uuid(),
37126
- deliveryKey: string().min(1),
37127
- firedAt: string().datetime(),
37128
- agentId: string().uuid(),
37129
- daemonId: string().uuid().optional(),
37130
- ...OptionalHookConfigSnapshot.shape,
37131
- event: string().min(1).optional(),
37132
- github: GithubHookMetadata.optional(),
37133
- status: _enum(["accepted", "failed"]),
37134
- reason: string().optional()
37135
- }).superRefine((report, ctx) => {
37136
- if (report.daemonId !== void 0 && report.dispatchDaemonId !== void 0 && report.daemonId !== report.dispatchDaemonId) ctx.addIssue({
37137
- code: "custom",
37138
- path: ["dispatchDaemonId"],
37139
- message: "dispatchDaemonId must equal daemonId on a delivery report"
37140
- });
37141
- });
37142
- const RcGithubInstallation = object({
37143
- installationId: string().min(1),
37144
- action: string().min(1)
37145
- });
37146
- const RcDaemonRevoke = object({ daemonId: string().uuid() });
37147
36284
  /** App-level Slack message shortcut for opening the controls of the session that
37148
36285
  * owns the selected message's conversation. Direct apps receive it over Socket
37149
- * Mode; shared apps receive the same callback through the relay HTTP edge. */
36286
+ * Mode; shared apps receive the same callback through the relay HTTP edge.
36287
+ *
36288
+ * Declared to Slack by {@link buildSlackAppManifest} below, which is why it lives
36289
+ * here rather than beside the runtime Block Kit action ids in `frames/relay-cp.ts`:
36290
+ * those name controls on messages we post, this one names a manifest feature. */
37150
36291
  const SLACK_MANAGE_SESSION_SHORTCUT_CALLBACK_ID = "ac_manage_session";
37151
- /** One short choice from the compact Slack status overflow. Slack caps option
37152
- * values at 150 characters; the longer session target rides in `block_id`. */
37153
- const SlackStatusOverflowAction = _enum([
37154
- "switch-agent",
37155
- "manage",
37156
- "cancel"
37157
- ]);
37158
- object({
37159
- v: literal(1),
37160
- action: SlackStatusOverflowAction,
37161
- target: string().min(1)
37162
- }).strict();
37163
- object({
37164
- v: literal(1),
37165
- agentId: string().min(1),
37166
- integrationId: string().min(1),
37167
- sessionKey: string().min(1)
37168
- }).strict();
37169
- const AttributedRoute = object({
37170
- agentId: string().uuid(),
37171
- daemonId: string().uuid(),
37172
- integrationId: string().uuid(),
37173
- scope: object({
37174
- channel: string().optional(),
37175
- thread: string().optional()
37176
- }).optional(),
37177
- match: BindMatch
37178
- });
37179
- const RcBotSecrets = union([
37180
- object({
37181
- botToken: string(),
37182
- signingSecret: string()
37183
- }).catchall(unknown()),
37184
- object({
37185
- verificationToken: string(),
37186
- encryptKey: string().optional()
37187
- }).catchall(unknown()),
37188
- record$1(string(), unknown())
37189
- ]);
37190
- const RcAgentDirEntry = object({
37191
- agentId: string().uuid(),
37192
- name: string(),
37193
- daemonId: string().uuid(),
37194
- integrationId: string().uuid().optional()
37195
- });
37196
- const RcBotAssign = object({
37197
- botId: string().uuid(),
37198
- platform: Platform,
37199
- originKind: string().min(1).optional(),
37200
- credentialRevision: number$1().int().nonnegative().optional(),
37201
- secrets: RcBotSecrets,
37202
- ingress: unknown().optional(),
37203
- members: array(object({
37204
- daemonId: string().uuid(),
37205
- agentIds: array(string().uuid())
37206
- })),
37207
- agents: array(RcAgentDirEntry).default([]),
37208
- routes: array(AttributedRoute),
37209
- defaultAgentId: string().uuid().optional(),
37210
- defaultDaemonId: string().uuid().optional(),
37211
- gatedAgentIds: array(string().uuid()).default([]),
37212
- mutedChannels: array(string()).default([]),
37213
- gatedOffChannels: array(string()).default([]),
37214
- noticeAuthority: string().uuid().optional(),
37215
- noticedDmConversations: array(string()).default([])
37216
- });
37217
- const RcBotUnassign = object({
37218
- botId: string().uuid(),
37219
- credentialRevision: number$1().int().nonnegative().optional()
37220
- });
37221
- const RcRoutes = object({
37222
- botId: string().uuid(),
37223
- members: array(object({
37224
- daemonId: string().uuid(),
37225
- agentIds: array(string().uuid())
37226
- })),
37227
- agents: array(RcAgentDirEntry).default([]),
37228
- routes: array(AttributedRoute),
37229
- defaultAgentId: string().uuid().optional(),
37230
- defaultDaemonId: string().uuid().optional(),
37231
- gatedAgentIds: array(string().uuid()).default([]),
37232
- mutedChannels: array(string()).default([]),
37233
- gatedOffChannels: array(string()).default([]),
37234
- noticeAuthority: string().uuid().optional(),
37235
- noticedDmConversations: array(string()).default([])
37236
- });
37237
- const RcAssign = object({
37238
- botId: string().uuid(),
37239
- sessionKey: string().min(1),
37240
- agentId: string().uuid(),
37241
- daemonId: string().uuid()
37242
- });
37243
- const RcParticipantAssign = object({
37244
- botId: string().uuid(),
37245
- sessionKey: string().min(1),
37246
- agentId: string().uuid(),
37247
- daemonId: string().uuid()
37248
- });
37249
- const RcSetChannelAgent = object({
37250
- botId: string().uuid(),
37251
- channelId: string().min(1),
37252
- agentId: string().uuid()
37253
- });
37254
- const RcBotChannels = object({
37255
- botId: string().uuid(),
37256
- channels: array(IntegrationChannel)
37257
- });
37258
- const RcNoticePosted = object({
37259
- botId: string().uuid(),
37260
- channel: string().min(1)
37261
- });
37262
- const RcBotRevoked = object({
37263
- botId: string().uuid(),
37264
- reason: _enum(["app_uninstalled", "tokens_revoked"]),
37265
- credentialRevision: number$1().int().nonnegative().optional(),
37266
- eventAtMs: number$1().int().nonnegative().optional()
37267
- });
37268
- const RcBotRevokedOk = object({
37269
- botId: string().uuid(),
37270
- applied: boolean()
37271
- });
37272
- /** `type` string → payload schema for the relay↔CP wire. */
37273
- const RELAY_CP_SCHEMAS = {
37274
- "rc/auth": RcAuth,
37275
- "rc/auth/ok": RcAuthOk,
37276
- "rc/register": RcRegister,
37277
- "rc/registered": RcRegistered,
37278
- "rc/heartbeat": RcHeartbeat,
37279
- "rc/verify": RcVerify,
37280
- "rc/verify/ok": RcVerifyResult,
37281
- "rc/github-comment-authz": RcGithubCommentAuthz,
37282
- "rc/github-comment-authz/ok": RcGithubCommentAuthzResult,
37283
- "rc/github-rerequest": RcGithubRerequest,
37284
- "rc/github-rerequest/ok": RcGithubRerequestResult,
37285
- "rc/hook-assign": RcHookAssign,
37286
- "rc/hook-remove": RcHookRemove,
37287
- "rc/run-report": RcRunReport,
37288
- "rc/github-installation": RcGithubInstallation,
37289
- "rc/daemon-revoke": RcDaemonRevoke,
37290
- "rc/bot-assign": RcBotAssign,
37291
- "rc/bot-unassign": RcBotUnassign,
37292
- "rc/routes": RcRoutes,
37293
- "rc/assign": RcAssign,
37294
- "rc/participant-assign": RcParticipantAssign,
37295
- "rc/set-channel-agent": RcSetChannelAgent,
37296
- "rc/bot-channels": RcBotChannels,
37297
- "rc/bot-conversation": object({
37298
- botId: string().uuid(),
37299
- conversation: IntegrationChannel
37300
- }),
37301
- "rc/bot-revoked": RcBotRevoked,
37302
- "rc/bot-revoked/ok": RcBotRevokedOk,
37303
- "rc/notice-posted": RcNoticePosted,
37304
- "rc/thread-assign": object({
37305
- botId: string().uuid(),
37306
- sessionKey: string().min(1),
37307
- agentId: string().uuid(),
37308
- daemonId: string().uuid()
37309
- }),
37310
- "rc/thread-participant": object({
37311
- botId: string().uuid(),
37312
- sessionKey: string().min(1),
37313
- agentId: string().uuid(),
37314
- daemonId: string().uuid()
37315
- }),
37316
- "rc/thread-lookup": object({
37317
- botId: string().uuid(),
37318
- sessionKey: string().min(1)
37319
- }),
37320
- "rc/thread-lookup/ok": object({
37321
- botId: string().uuid(),
37322
- sessionKey: string().min(1),
37323
- target: object({
37324
- agentId: string().uuid(),
37325
- daemonId: string().uuid()
37326
- }).nullable(),
37327
- participants: array(object({
37328
- agentId: string().uuid(),
37329
- daemonId: string().uuid()
37330
- })).default([])
37331
- }),
37332
- "rc/collab-routes": CollabRoutesSnapshot,
37333
- "rc/mcp-assign": object({
37334
- providerId: string().uuid(),
37335
- upstreamUrl: string(),
37336
- headers: array(object({
37337
- name: string(),
37338
- value: string()
37339
- })).default([]),
37340
- grantKeyHashes: array(string().min(1)).min(1)
37341
- }),
37342
- "rc/mcp-unassign": object({
37343
- providerId: string().uuid(),
37344
- grantKeyHash: string().optional()
37345
- }),
37346
- "rc/memoryconnection-assign": object({
37347
- connectionId: string().uuid(),
37348
- revision: number$1().int().positive(),
37349
- upstreamUrl: string().url().max(2048),
37350
- headers: array(object({
37351
- name: string().min(1).max(128),
37352
- value: string().max(16 * 1024)
37353
- })).max(64).default([]),
37354
- grantKeyHashes: array(string().regex(/^[a-f0-9]{64}$/)).min(1).max(64)
37355
- }),
37356
- "rc/memoryconnection-unassign": object({
37357
- connectionId: string().uuid(),
37358
- revision: number$1().int().positive(),
37359
- grantKeyHash: string().regex(/^[a-f0-9]{64}$/).optional()
37360
- }),
37361
- error: ErrorFrame
37362
- };
37363
- Object.keys(RELAY_CP_SCHEMAS);
37364
- discriminatedUnion("type", [
37365
- frameSchema("rc/auth", RELAY_CP_SCHEMAS["rc/auth"]),
37366
- frameSchema("rc/auth/ok", RELAY_CP_SCHEMAS["rc/auth/ok"]),
37367
- frameSchema("rc/register", RELAY_CP_SCHEMAS["rc/register"]),
37368
- frameSchema("rc/registered", RELAY_CP_SCHEMAS["rc/registered"]),
37369
- frameSchema("rc/heartbeat", RELAY_CP_SCHEMAS["rc/heartbeat"]),
37370
- frameSchema("rc/verify", RELAY_CP_SCHEMAS["rc/verify"]),
37371
- frameSchema("rc/verify/ok", RELAY_CP_SCHEMAS["rc/verify/ok"]),
37372
- frameSchema("rc/github-comment-authz", RELAY_CP_SCHEMAS["rc/github-comment-authz"]),
37373
- frameSchema("rc/github-comment-authz/ok", RELAY_CP_SCHEMAS["rc/github-comment-authz/ok"]),
37374
- frameSchema("rc/github-rerequest", RELAY_CP_SCHEMAS["rc/github-rerequest"]),
37375
- frameSchema("rc/github-rerequest/ok", RELAY_CP_SCHEMAS["rc/github-rerequest/ok"]),
37376
- frameSchema("rc/hook-assign", RELAY_CP_SCHEMAS["rc/hook-assign"]),
37377
- frameSchema("rc/hook-remove", RELAY_CP_SCHEMAS["rc/hook-remove"]),
37378
- frameSchema("rc/run-report", RELAY_CP_SCHEMAS["rc/run-report"]),
37379
- frameSchema("rc/github-installation", RELAY_CP_SCHEMAS["rc/github-installation"]),
37380
- frameSchema("rc/daemon-revoke", RELAY_CP_SCHEMAS["rc/daemon-revoke"]),
37381
- frameSchema("rc/bot-assign", RELAY_CP_SCHEMAS["rc/bot-assign"]),
37382
- frameSchema("rc/bot-unassign", RELAY_CP_SCHEMAS["rc/bot-unassign"]),
37383
- frameSchema("rc/routes", RELAY_CP_SCHEMAS["rc/routes"]),
37384
- frameSchema("rc/assign", RELAY_CP_SCHEMAS["rc/assign"]),
37385
- frameSchema("rc/participant-assign", RELAY_CP_SCHEMAS["rc/participant-assign"]),
37386
- frameSchema("rc/set-channel-agent", RELAY_CP_SCHEMAS["rc/set-channel-agent"]),
37387
- frameSchema("rc/bot-channels", RELAY_CP_SCHEMAS["rc/bot-channels"]),
37388
- frameSchema("rc/bot-conversation", RELAY_CP_SCHEMAS["rc/bot-conversation"]),
37389
- frameSchema("rc/bot-revoked", RELAY_CP_SCHEMAS["rc/bot-revoked"]),
37390
- frameSchema("rc/bot-revoked/ok", RELAY_CP_SCHEMAS["rc/bot-revoked/ok"]),
37391
- frameSchema("rc/notice-posted", RELAY_CP_SCHEMAS["rc/notice-posted"]),
37392
- frameSchema("rc/thread-assign", RELAY_CP_SCHEMAS["rc/thread-assign"]),
37393
- frameSchema("rc/thread-participant", RELAY_CP_SCHEMAS["rc/thread-participant"]),
37394
- frameSchema("rc/thread-lookup", RELAY_CP_SCHEMAS["rc/thread-lookup"]),
37395
- frameSchema("rc/thread-lookup/ok", RELAY_CP_SCHEMAS["rc/thread-lookup/ok"]),
37396
- frameSchema("rc/collab-routes", RELAY_CP_SCHEMAS["rc/collab-routes"]),
37397
- frameSchema("rc/mcp-assign", RELAY_CP_SCHEMAS["rc/mcp-assign"]),
37398
- frameSchema("rc/mcp-unassign", RELAY_CP_SCHEMAS["rc/mcp-unassign"]),
37399
- frameSchema("rc/memoryconnection-assign", RELAY_CP_SCHEMAS["rc/memoryconnection-assign"]),
37400
- frameSchema("rc/memoryconnection-unassign", RELAY_CP_SCHEMAS["rc/memoryconnection-unassign"]),
37401
- frameSchema("error", RELAY_CP_SCHEMAS["error"])
37402
- ]);
37403
- //#endregion
37404
- //#region ../protocol/dist/slack-app-manifest.js
37405
36292
  /** Public platform profile copy. Never derive this from an Agent description. */
37406
36293
  const PLATFORM_APP_DESCRIPTION = "AI agent powered by AgentConnect.";
37407
36294
  const SLACK_BOT_SCOPES = [