@geminixiang/mikan 1.0.0-beta.85 → 1.0.0-beta.86

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 (184) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +8 -8
  3. package/dist/adapters/commands/session-view.js +1 -1
  4. package/dist/adapters/commands/session-view.js.map +1 -1
  5. package/dist/adapters/discord/bot.d.ts.map +1 -1
  6. package/dist/adapters/discord/bot.js +1 -8
  7. package/dist/adapters/discord/bot.js.map +1 -1
  8. package/dist/adapters/github/activity.d.ts +3 -0
  9. package/dist/adapters/github/activity.d.ts.map +1 -0
  10. package/dist/adapters/github/activity.js +154 -0
  11. package/dist/adapters/github/activity.js.map +1 -0
  12. package/dist/adapters/github/bot.d.ts +10 -20
  13. package/dist/adapters/github/bot.d.ts.map +1 -1
  14. package/dist/adapters/github/bot.js +119 -342
  15. package/dist/adapters/github/bot.js.map +1 -1
  16. package/dist/adapters/github/client.d.ts +9 -19
  17. package/dist/adapters/github/client.d.ts.map +1 -1
  18. package/dist/adapters/github/client.js +28 -104
  19. package/dist/adapters/github/client.js.map +1 -1
  20. package/dist/adapters/github/context.d.ts.map +1 -1
  21. package/dist/adapters/github/context.js +29 -20
  22. package/dist/adapters/github/context.js.map +1 -1
  23. package/dist/adapters/github/github-ops.d.ts +2 -10
  24. package/dist/adapters/github/github-ops.d.ts.map +1 -1
  25. package/dist/adapters/github/github-ops.js +28 -91
  26. package/dist/adapters/github/github-ops.js.map +1 -1
  27. package/dist/adapters/github/policy.d.ts +19 -0
  28. package/dist/adapters/github/policy.d.ts.map +1 -0
  29. package/dist/adapters/github/policy.js +79 -0
  30. package/dist/adapters/github/policy.js.map +1 -0
  31. package/dist/adapters/github/tool-pack.d.ts +2 -2
  32. package/dist/adapters/github/tool-pack.d.ts.map +1 -1
  33. package/dist/adapters/github/tool-pack.js +4 -9
  34. package/dist/adapters/github/tool-pack.js.map +1 -1
  35. package/dist/adapters/github/tools/checks.d.ts.map +1 -1
  36. package/dist/adapters/github/tools/checks.js +6 -8
  37. package/dist/adapters/github/tools/checks.js.map +1 -1
  38. package/dist/adapters/github/tools/pr.d.ts.map +1 -1
  39. package/dist/adapters/github/tools/pr.js +7 -9
  40. package/dist/adapters/github/tools/pr.js.map +1 -1
  41. package/dist/adapters/github/types.d.ts +66 -67
  42. package/dist/adapters/github/types.d.ts.map +1 -1
  43. package/dist/adapters/github/types.js.map +1 -1
  44. package/dist/adapters/github/webhook.d.ts +2 -1
  45. package/dist/adapters/github/webhook.d.ts.map +1 -1
  46. package/dist/adapters/github/webhook.js +46 -4
  47. package/dist/adapters/github/webhook.js.map +1 -1
  48. package/dist/adapters/progressive-renderer.d.ts.map +1 -1
  49. package/dist/adapters/progressive-renderer.js +3 -0
  50. package/dist/adapters/progressive-renderer.js.map +1 -1
  51. package/dist/adapters/shared.d.ts +3 -1
  52. package/dist/adapters/shared.d.ts.map +1 -1
  53. package/dist/adapters/shared.js +45 -23
  54. package/dist/adapters/shared.js.map +1 -1
  55. package/dist/adapters/slack/blocks.d.ts.map +1 -1
  56. package/dist/adapters/slack/blocks.js +65 -2
  57. package/dist/adapters/slack/blocks.js.map +1 -1
  58. package/dist/adapters/slack/bot.d.ts +3 -0
  59. package/dist/adapters/slack/bot.d.ts.map +1 -1
  60. package/dist/adapters/slack/bot.js +76 -34
  61. package/dist/adapters/slack/bot.js.map +1 -1
  62. package/dist/adapters/slack/jev-context.js +2 -2
  63. package/dist/adapters/slack/jev-context.js.map +1 -1
  64. package/dist/adapters/slack/task-status.d.ts +3 -2
  65. package/dist/adapters/slack/task-status.d.ts.map +1 -1
  66. package/dist/adapters/slack/task-status.js +12 -15
  67. package/dist/adapters/slack/task-status.js.map +1 -1
  68. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  69. package/dist/adapters/telegram/bot.js +1 -8
  70. package/dist/adapters/telegram/bot.js.map +1 -1
  71. package/dist/adapters/web/admin/portal.js +1 -1
  72. package/dist/adapters/web/admin/portal.js.map +1 -1
  73. package/dist/adapters/web/admin/provider-models.d.ts.map +1 -1
  74. package/dist/adapters/web/admin/provider-models.js +10 -3
  75. package/dist/adapters/web/admin/provider-models.js.map +1 -1
  76. package/dist/adapters/web/login/portal.js +6 -1
  77. package/dist/adapters/web/login/portal.js.map +1 -1
  78. package/dist/adapters/web/server.d.ts.map +1 -1
  79. package/dist/adapters/web/server.js +5 -3
  80. package/dist/adapters/web/server.js.map +1 -1
  81. package/dist/adapters/web/session-view/portal.d.ts +2 -1
  82. package/dist/adapters/web/session-view/portal.d.ts.map +1 -1
  83. package/dist/adapters/web/session-view/portal.js +18 -27
  84. package/dist/adapters/web/session-view/portal.js.map +1 -1
  85. package/dist/cli/migrate.d.ts.map +1 -1
  86. package/dist/cli/migrate.js +1 -2
  87. package/dist/cli/migrate.js.map +1 -1
  88. package/dist/cli/onboard.d.ts +0 -1
  89. package/dist/cli/onboard.d.ts.map +1 -1
  90. package/dist/cli/onboard.js +1 -7
  91. package/dist/cli/onboard.js.map +1 -1
  92. package/dist/env-manifest.d.ts.map +1 -1
  93. package/dist/env-manifest.js +24 -22
  94. package/dist/env-manifest.js.map +1 -1
  95. package/dist/events/index.d.ts +1 -0
  96. package/dist/events/index.d.ts.map +1 -1
  97. package/dist/events/index.js +11 -0
  98. package/dist/events/index.js.map +1 -1
  99. package/dist/events/scheduler.d.ts.map +1 -1
  100. package/dist/events/scheduler.js +3 -0
  101. package/dist/events/scheduler.js.map +1 -1
  102. package/dist/file-guards.d.ts +7 -0
  103. package/dist/file-guards.d.ts.map +1 -1
  104. package/dist/file-guards.js +63 -1
  105. package/dist/file-guards.js.map +1 -1
  106. package/dist/harness/mcp.d.ts.map +1 -1
  107. package/dist/harness/mcp.js +75 -31
  108. package/dist/harness/mcp.js.map +1 -1
  109. package/dist/harness/models.js +2 -2
  110. package/dist/harness/models.js.map +1 -1
  111. package/dist/harness/open-connector.d.ts.map +1 -1
  112. package/dist/harness/open-connector.js +14 -7
  113. package/dist/harness/open-connector.js.map +1 -1
  114. package/dist/harness/presenter.d.ts.map +1 -1
  115. package/dist/harness/presenter.js +2 -0
  116. package/dist/harness/presenter.js.map +1 -1
  117. package/dist/harness/prompt.d.ts +1 -1
  118. package/dist/harness/prompt.d.ts.map +1 -1
  119. package/dist/harness/prompt.js +13 -31
  120. package/dist/harness/prompt.js.map +1 -1
  121. package/dist/harness/runner.d.ts.map +1 -1
  122. package/dist/harness/runner.js +6 -9
  123. package/dist/harness/runner.js.map +1 -1
  124. package/dist/harness/session.d.ts.map +1 -1
  125. package/dist/harness/session.js +6 -0
  126. package/dist/harness/session.js.map +1 -1
  127. package/dist/harness/tools/event.d.ts.map +1 -1
  128. package/dist/harness/tools/event.js +19 -2
  129. package/dist/harness/tools/event.js.map +1 -1
  130. package/dist/harness/tools/generate-image.d.ts.map +1 -1
  131. package/dist/harness/tools/generate-image.js +17 -3
  132. package/dist/harness/tools/generate-image.js.map +1 -1
  133. package/dist/harness/tools/jev-browser.d.ts +1 -2
  134. package/dist/harness/tools/jev-browser.d.ts.map +1 -1
  135. package/dist/harness/tools/jev-browser.js +75 -50
  136. package/dist/harness/tools/jev-browser.js.map +1 -1
  137. package/dist/index.d.ts +2 -2
  138. package/dist/index.d.ts.map +1 -1
  139. package/dist/index.js +2 -2
  140. package/dist/index.js.map +1 -1
  141. package/dist/main.js +34 -45
  142. package/dist/main.js.map +1 -1
  143. package/dist/memory-capture/index.d.ts.map +1 -1
  144. package/dist/memory-capture/index.js +3 -3
  145. package/dist/memory-capture/index.js.map +1 -1
  146. package/dist/migrations/index.d.ts.map +1 -1
  147. package/dist/migrations/index.js +2 -0
  148. package/dist/migrations/index.js.map +1 -1
  149. package/dist/migrations/office-sessions.d.ts +3 -0
  150. package/dist/migrations/office-sessions.d.ts.map +1 -0
  151. package/dist/migrations/office-sessions.js +70 -0
  152. package/dist/migrations/office-sessions.js.map +1 -0
  153. package/dist/office/index.d.ts +0 -1
  154. package/dist/office/index.d.ts.map +1 -1
  155. package/dist/office/index.js +3 -5
  156. package/dist/office/index.js.map +1 -1
  157. package/dist/runtime/conversation-runtime.js +12 -12
  158. package/dist/runtime/conversation-runtime.js.map +1 -1
  159. package/dist/sandbox/provisioner.d.ts +1 -1
  160. package/dist/sandbox/provisioner.d.ts.map +1 -1
  161. package/dist/sandbox/provisioner.js +20 -5
  162. package/dist/sandbox/provisioner.js.map +1 -1
  163. package/dist/sessions/chat-history-sync.d.ts.map +1 -1
  164. package/dist/sessions/chat-history-sync.js +28 -40
  165. package/dist/sessions/chat-history-sync.js.map +1 -1
  166. package/dist/sessions/store.d.ts +2 -3
  167. package/dist/sessions/store.d.ts.map +1 -1
  168. package/dist/sessions/store.js +8 -14
  169. package/dist/sessions/store.js.map +1 -1
  170. package/dist/sessions/types.d.ts +6 -5
  171. package/dist/sessions/types.d.ts.map +1 -1
  172. package/dist/sessions/types.js.map +1 -1
  173. package/dist/types.d.ts +0 -1
  174. package/dist/types.d.ts.map +1 -1
  175. package/dist/types.js.map +1 -1
  176. package/package.json +8 -6
  177. package/dist/adapters/github/repo.d.ts +0 -8
  178. package/dist/adapters/github/repo.d.ts.map +0 -1
  179. package/dist/adapters/github/repo.js +0 -92
  180. package/dist/adapters/github/repo.js.map +0 -1
  181. package/dist/adapters/github/tools/sync.d.ts +0 -13
  182. package/dist/adapters/github/tools/sync.d.ts.map +0 -1
  183. package/dist/adapters/github/tools/sync.js +0 -29
  184. package/dist/adapters/github/tools/sync.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -9,6 +9,42 @@ any release.
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [1.0.0-beta.86]
13
+
14
+ ### Breaking
15
+
16
+ - **The GitHub adapter now runs as a bound GitHub account driven by webhooks, and no longer uses a GitHub App or polling.** People mention it with autocomplete, assign it issues and pull requests, and request its review. Set `GITHUB_AGENT_TOKEN` (a fine-grained PAT of that account), `GITHUB_WEBHOOK_SECRET` (an organization or App webhook to `<LINK_URL>/github/webhook`), and `GITHUB_REPOS` (now required: `owner/repo` or `owner/*`); the link server must run. `GITHUB_APP_ID`, `GITHUB_INSTALLATION_ID`, `GITHUB_APP_PRIVATE_KEY`, `GITHUB_APP_PRIVATE_KEY_PATH`, and `GITHUB_POLL_INTERVAL` are removed, `@<app-slug>` no longer triggers, and `<state-dir>/github-sync.json` is no longer read and can be deleted. Deliveries are best effort: events sent while mikan is down are not replayed. See [ADR 0015](docs/adr/0015-github-agent-account-and-webhooks.md) and [Make mikan a GitHub teammate](src/content/docs/github-teammate-guide.md).
17
+ - **The GitHub adapter is restricted by default.** It answers only in private repositories listed in `GITHUB_REPOS`, only to people with write permission, and only comments and reads. `GITHUB_CAPABILITIES=triage,push` restores label and assignee management and pull requests; `GITHUB_PUBLIC_REPOS`, `GITHUB_USERS`, `GITHUB_MIN_PERMISSION`, and `GITHUB_TRIGGERS` narrow or widen who can trigger it and how.
18
+ - `github_checks` reads GitHub Actions jobs and commit statuses instead of check runs, because fine-grained PATs have no Checks permission. Check runs from third-party CI apps are no longer visible.
19
+ - **mikan no longer runs git for GitHub conversations.** Nothing is cloned into `<office>/repo`, and `github_sync` is removed. The agent clones, commits, and pushes inside its sandbox with the sandbox's GitHub credentials, and `github_pr` only opens a pull request for a branch the agent already pushed. What the agent can push is now bounded by that token, the account's repository role, and branch protection instead of mikan's `pi/*` rule; protect the default branch. GitHub conversations now trust `membership`, because only collaborators with write access can trigger them, so they receive `sandbox.defaultSharedVault` and settings-declared MCP servers like Slack conversations.
20
+ - **Session files move from `<workspace>/<office-key>/sessions/` to `<state-dir>/conversations/<office-key>/sessions/`, and sandboxes no longer see them.** Run `mikan migrate` before starting this version. The agent searches earlier history in `log.jsonl`, which stays in the office directory. See [ADR 0016](docs/adr/0016-host-sandbox-trust-boundary.md).
21
+ - Library API: `officeSessionsDir` and `resolveChannelSessionFile` are removed; use `office.sessionsDir` and `tryResolveCurrentSession(office.sessionsDir)`. `getThreadSessionFile` and `resolveParentSessionForThread` take the sessions directory, and the `ChatHistorySync` options and `registerThreadSession`/`hasMaterializedChatSession` take `office` instead of `conversationDir`.
22
+ - `jev_browser` no longer takes a `session` parameter. Each conversation thread has one browser that stays open across calls until `close: true`; a later `url` opens a new tab, and opening past three tabs closes the oldest inactive tabs and reports them in `closedOldTabs`. Model-named sessions each started another Chrome, and a few of them exhausted a 1 GB sandbox until every page load timed out.
23
+
24
+ ### Changed
25
+
26
+ - Pi is upgraded from 0.87 to 0.99 (`pi-agent-core`, `pi-ai`).
27
+ - MCP servers now connect through Pi's `@earendil-works/pi-mcp` client instead of the official `@modelcontextprotocol/sdk`, which is removed along with `zod`. Stdio servers still receive only a minimal inherited environment plus their configured `env`. When an HTTP server rejects the connection, the error now carries the status and the start of the server's response body.
28
+
29
+ ### Added
30
+
31
+ - GitHub issue and pull request conversations receive the default OpenConnector runtime token like Slack conversations, named `mikan:github:<conversation-id>`.
32
+
33
+ ### Fixed
34
+
35
+ - `models.json` follows `--state-dir` / `STATE_DIR` like `settings.json`; the daemon, `mikan migrate`, and `mikan onboard` no longer read or write `~/.mikan/models.json` for another state directory.
36
+ - A daemon adopts at startup only the sandbox containers that mount its own workspace, so two mikan instances sharing one Docker engine no longer stop each other's containers.
37
+ - The sandbox image now ships CJK fonts (`fonts-noto-cjk`, about 170 MB). Without them, `jev_browser` screenshots showed Chinese and Japanese text as blank space, and charts drawn in the sandbox could not use Chinese labels.
38
+ - Python packages in the sandbox go through uv. The system pip still refuses installs, but its message now names the uv commands to use (`uv run --with <package>`), so the agent recovers after one attempt instead of trying pip, venvs, and apt in turn. The docs no longer claim that `pip install --user` works.
39
+ - Creating or updating a periodic event now reports its next three runs in the event's timezone, so the agent no longer computes weekdays itself (it once announced a Monday reminder for a Tuesday). An invalid cron `schedule` or `timezone` is rejected before the event file is written instead of being saved and then skipped by the scheduler.
40
+ - `apt-get install` works inside managed sandbox containers again. The containers drop all capabilities, so apt's download sandbox user could not switch groups and every install failed; the image now runs apt downloads as root, and the image smoke test installs a package under the same hardening.
41
+ - Asking "好了嗎" at the moment a background task finishes no longer answers "還在處理" right beside the completion notice. Task status now trusts the recorded end of the run over the runtime's still-settling state.
42
+ - A Slack message whose acknowledgement was lost during a socket reconnect no longer runs twice. Slack redelivers such events; mikan now recognizes a message or mention it has already taken and ignores the copy. A failed acknowledgement is logged instead of surfacing as an unhandled promise rejection.
43
+ - A Slack app that is not an agent app no longer calls `assistant.threads.setSuggestedPrompts` and logs `not_agent_app` every time someone opens its DM; after the first refusal the call is skipped until restart.
44
+ - A long Slack answer that outgrew the native stream no longer shows up twice. The partial streamed message is deleted before the full answer is posted, and the notification text sent with it is capped at the 4,000 bytes `chat.update` accepts, so the edit no longer fails with `msg_too_long`.
45
+ - A long Slack answer with many headings no longer fails with `invalid_blocks` and an `Error:` line. Slack expands each heading of a markdown block into its own block and rejects a message with more than 50; when an answer would exceed that, its headings are sent as bold lines instead.
46
+ - MCP tools ask the model for a progress label like every built-in tool, so the Slack checklist shows a readable step (for example "確認 GitHub 連線") instead of `mcp__server__tool`. The label is not forwarded to the MCP server, and a tool that already has its own `label` argument is left unchanged.
47
+
12
48
  ## [1.0.0-beta.85]
13
49
 
14
50
  ### Breaking
package/README.md CHANGED
@@ -22,7 +22,7 @@ mikan keeps the chat record, agent session, and execution runtime separate:
22
22
 
23
23
  - **Conversation office** is the unit everything else hangs off: one conversation's working area plus its own sandbox runtime. An office is identified by its platform and raw conversation id, and its directory is named by an office key (`v1-<platform>-<readable-id>-<hash>`), so two platforms can never collide on the same raw id.
24
24
  - **Chat / conversation data** is the platform-facing record: `log.jsonl`, attachments, and conversation files.
25
- - **Session orchestration** turns platform events into agent runs, handles top-level/thread scopes, and persists structured context under `sessions/*.jsonl`.
25
+ - **Session orchestration** turns platform events into agent runs, handles top-level/thread scopes, and persists structured context in host-only session files under the State dir.
26
26
  - **mikan agent harness** (`src/harness/`, built on pi-agent-core and pi-ai) owns run preparation, authorized prompts/tools, response presentation, and native Pi session integration. Pi handles the model/tool loop, persistence, compaction, retries, and cancellation.
27
27
  - **Sandbox runtime** is where tool commands execute: host, Docker container/image, or the experimental Cloudflare bridge.
28
28
  - **Vault** provides runtime credentials as env vars and mounted secret files.
@@ -94,9 +94,9 @@ SLACK_APP_TOKEN=xapp-...
94
94
  SLACK_BOT_TOKEN=xoxb-...
95
95
  TELEGRAM_BOT_TOKEN=123456:ABC-...
96
96
  DISCORD_BOT_TOKEN=MTI...
97
- GITHUB_APP_ID=123456
98
- GITHUB_INSTALLATION_ID=12345678
99
- GITHUB_APP_PRIVATE_KEY_PATH=/srv/mikan/github-app.pem
97
+ GITHUB_AGENT_TOKEN=github_pat_...
98
+ GITHUB_WEBHOOK_SECRET=...
99
+ GITHUB_REPOS=acme/*
100
100
  ```
101
101
 
102
102
  Tail logs with `pm2 logs mikan`; upgrade with `npm i -g @geminixiang/mikan`, check `mikan migrate --sandbox=<mode> --dry-run` for pending State migrations, then `pm2 reload mikan`. See [the deployment guide](src/content/docs/deployment.mdx) for sandbox images, graceful shutdown, and the health endpoint.
@@ -114,7 +114,7 @@ The working directory is optional: it defaults to `<state-dir>/workspace` (so `~
114
114
  - **Slack** — create a Socket Mode app using [src/content/docs/slack-bot-minimal-guide.md](src/content/docs/slack-bot-minimal-guide.md). The bot responds when `@mentioned` in channels and to all DMs.
115
115
  - **Telegram** — create a bot via [@BotFather](https://t.me/BotFather). The bot responds to private messages, `@mention`, and reply chains in groups.
116
116
  - **Discord** — create an application in the [Discord Developer Portal](https://discord.com/developers/applications), enable **Message Content Intent**, and invite it with message/file permissions.
117
- - **GitHub** — install a GitHub App (polling, no webhooks) and set `GITHUB_APP_ID`, `GITHUB_INSTALLATION_ID`, and a private key. One issue or PR is one conversation. See [src/content/docs/platform-adapters/github.md](src/content/docs/platform-adapters/github.md).
117
+ - **GitHub** — bind a regular GitHub account with a fine-grained PAT, point an organization webhook at `<LINK_URL>/github/webhook`, and list the repositories mikan answers in. People mention, assign, and request reviews from it like a teammate; one issue or PR is one conversation. See [src/content/docs/platform-adapters/github.md](src/content/docs/platform-adapters/github.md).
118
118
 
119
119
  Slack threads, Discord replies/threads, and Telegram reply chains are mapped to independent session scopes. See [src/content/docs/sessions.mdx](src/content/docs/sessions.mdx).
120
120
 
@@ -172,7 +172,8 @@ See [src/content/docs/configuration.md](src/content/docs/configuration.md) for a
172
172
  ├── office-registry.json
173
173
  ├── conversations/
174
174
  │ └── <office-key>/
175
- │ └── settings.json
175
+ │ ├── settings.json
176
+ │ └── sessions/
176
177
  └── vaults/
177
178
 
178
179
  <working-directory>/
@@ -186,8 +187,7 @@ See [src/content/docs/configuration.md](src/content/docs/configuration.md) for a
186
187
  ├── log.jsonl
187
188
  ├── attachments/
188
189
  ├── scratch/
189
- ├── skills/
190
- └── sessions/
190
+ └── skills/
191
191
  ```
192
192
 
193
193
  Office directories are named by office key (`v1-<platform>-<readable-id>-<hash>`) and are not reversible to a raw platform id, so `office-registry.json` records each office's `(platform, conversationId)`. `mikan office list` prints the registered offices. `mikan migrate` upgrades a 0.5.3 install to this layout; see [State migrations](src/content/docs/deployment.mdx).
@@ -16,7 +16,7 @@ export class SessionViewCommandHandler {
16
16
  await replySummaryPrivately(context, "Session", portalNotConfiguredLines("Session viewer"));
17
17
  return true;
18
18
  }
19
- const sessionFile = resolveExistingSessionFile(context.services.workspace.office(context.address).dir, context.sessionKey);
19
+ const sessionFile = resolveExistingSessionFile(context.services.workspace.office(context.address), context.sessionKey);
20
20
  if (!sessionFile) {
21
21
  await replySummaryPrivately(context, "Session", [
22
22
  "目前還沒有可查看的 session。",
@@ -1 +1 @@
1
- {"version":3,"file":"session-view.js","sourceRoot":"","sources":["../../../src/adapters/commands/session-view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE3D,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE7E,MAAM,qBAAqB,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;AAEtD,MAAM,OAAO,yBAAyB;IACpC,KAAK,CAAC,SAAS,CAAC,OAAuB;QACrC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,qBAAqB,CAAC;YAAE,OAAO,KAAK,CAAC;QAE5E,IAAI,CAAC,OAAO,CAAC,mBAAmB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YAC7D,MAAM,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE;gBAC9C,4CAA4C;aAC7C,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;YACpC,MAAM,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,wBAAwB,CAAC,gBAAgB,CAAC,CAAC,CAAC;YAC5F,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,WAAW,GAAG,0BAA0B,CAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,EACtD,OAAO,CAAC,UAAU,CACnB,CAAC;QACF,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE;gBAC9C,oBAAoB;gBACpB,2BAA2B;aAC5B,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG;aAC7B,gBAAgB,EAAE;aAClB,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;QAC5D,MAAM,gBAAgB,GAAG,YAAY,EAAE,QAAQ,IAAI,YAAY,EAAE,WAAW,CAAC;QAE7E,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,MAAM,CAAC;YAC1D,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,WAAW;YACX,gBAAgB;SACjB,CAAC,CAAC;QAEH,MAAM,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE;YAC9C,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,kBAAkB,KAAK,CAAC,KAAK,EAAE;YAChE,mBAAmB;SACpB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;CACF","sourcesContent":["import { resolveExistingSessionFile } from \"../web/session-view/portal.js\";\nimport { commandForms, matchCommand } from \"./manifest.js\";\nimport type { CommandContext, CommandHandler } from \"./types.js\";\nimport { portalNotConfiguredLines, replySummaryPrivately } from \"./utils.js\";\n\nconst SESSION_VIEW_COMMANDS = commandForms(\"session\");\n\nexport class SessionViewCommandHandler implements CommandHandler {\n async tryHandle(context: CommandContext): Promise<boolean> {\n if (!matchCommand(context.commandText, SESSION_VIEW_COMMANDS)) return false;\n\n if (!context.privateConversation && !context.bot.postPrivate) {\n await replySummaryPrivately(context, \"Session\", [\n \"為了保護對話內容,`/session` 目前只能在與機器人的私訊 / DM 中使用。\",\n ]);\n return true;\n }\n\n if (!context.services.portalBaseUrl) {\n await replySummaryPrivately(context, \"Session\", portalNotConfiguredLines(\"Session viewer\"));\n return true;\n }\n\n const sessionFile = resolveExistingSessionFile(\n context.services.workspace.office(context.address).dir,\n context.sessionKey,\n );\n if (!sessionFile) {\n await replySummaryPrivately(context, \"Session\", [\n \"目前還沒有可查看的 session。\",\n \"先和機器人對話一次,建立 session 後再試。\",\n ]);\n return true;\n }\n\n const platformUser = context.bot\n .getMessagingInfo()\n .users.find((user) => user.id === context.platformUserId);\n const platformUserName = platformUser?.userName || platformUser?.displayName;\n\n const token = context.services.sessionViewTokenStore.create({\n platform: context.platform,\n platformUserId: context.platformUserId,\n conversationId: context.conversationId,\n sessionKey: context.sessionKey,\n sessionFile,\n platformUserName,\n });\n\n await replySummaryPrivately(context, \"Session\", [\n `${context.services.portalBaseUrl}/session?token=${token.token}`,\n \"Expires: 24 hours\",\n ]);\n return true;\n }\n}\n"]}
1
+ {"version":3,"file":"session-view.js","sourceRoot":"","sources":["../../../src/adapters/commands/session-view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE3D,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE7E,MAAM,qBAAqB,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;AAEtD,MAAM,OAAO,yBAAyB;IACpC,KAAK,CAAC,SAAS,CAAC,OAAuB;QACrC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,qBAAqB,CAAC;YAAE,OAAO,KAAK,CAAC;QAE5E,IAAI,CAAC,OAAO,CAAC,mBAAmB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YAC7D,MAAM,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE;gBAC9C,4CAA4C;aAC7C,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC;YACpC,MAAM,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,wBAAwB,CAAC,gBAAgB,CAAC,CAAC,CAAC;YAC5F,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,WAAW,GAAG,0BAA0B,CAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAClD,OAAO,CAAC,UAAU,CACnB,CAAC;QACF,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE;gBAC9C,oBAAoB;gBACpB,2BAA2B;aAC5B,CAAC,CAAC;YACH,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG;aAC7B,gBAAgB,EAAE;aAClB,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;QAC5D,MAAM,gBAAgB,GAAG,YAAY,EAAE,QAAQ,IAAI,YAAY,EAAE,WAAW,CAAC;QAE7E,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,MAAM,CAAC;YAC1D,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,WAAW;YACX,gBAAgB;SACjB,CAAC,CAAC;QAEH,MAAM,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE;YAC9C,GAAG,OAAO,CAAC,QAAQ,CAAC,aAAa,kBAAkB,KAAK,CAAC,KAAK,EAAE;YAChE,mBAAmB;SACpB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;CACF","sourcesContent":["import { resolveExistingSessionFile } from \"../web/session-view/portal.js\";\nimport { commandForms, matchCommand } from \"./manifest.js\";\nimport type { CommandContext, CommandHandler } from \"./types.js\";\nimport { portalNotConfiguredLines, replySummaryPrivately } from \"./utils.js\";\n\nconst SESSION_VIEW_COMMANDS = commandForms(\"session\");\n\nexport class SessionViewCommandHandler implements CommandHandler {\n async tryHandle(context: CommandContext): Promise<boolean> {\n if (!matchCommand(context.commandText, SESSION_VIEW_COMMANDS)) return false;\n\n if (!context.privateConversation && !context.bot.postPrivate) {\n await replySummaryPrivately(context, \"Session\", [\n \"為了保護對話內容,`/session` 目前只能在與機器人的私訊 / DM 中使用。\",\n ]);\n return true;\n }\n\n if (!context.services.portalBaseUrl) {\n await replySummaryPrivately(context, \"Session\", portalNotConfiguredLines(\"Session viewer\"));\n return true;\n }\n\n const sessionFile = resolveExistingSessionFile(\n context.services.workspace.office(context.address),\n context.sessionKey,\n );\n if (!sessionFile) {\n await replySummaryPrivately(context, \"Session\", [\n \"目前還沒有可查看的 session。\",\n \"先和機器人對話一次,建立 session 後再試。\",\n ]);\n return true;\n }\n\n const platformUser = context.bot\n .getMessagingInfo()\n .users.find((user) => user.id === context.platformUserId);\n const platformUserName = platformUser?.userName || platformUser?.displayName;\n\n const token = context.services.sessionViewTokenStore.create({\n platform: context.platform,\n platformUserId: context.platformUserId,\n conversationId: context.conversationId,\n sessionKey: context.sessionKey,\n sessionFile,\n platformUserName,\n });\n\n await replySummaryPrivately(context, \"Session\", [\n `${context.services.portalBaseUrl}/session?token=${token.token}`,\n \"Expires: 24 hours\",\n ]);\n return true;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../../../src/adapters/discord/bot.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../../../src/adapters/discord/bot.ts"],"names":[],"mappings":"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"}
@@ -115,14 +115,7 @@ export class DiscordMessagingBot {
115
115
  enqueueEvent(event) {
116
116
  if (this.stopped)
117
117
  return false;
118
- const conversationId = event.address.conversationId;
119
- const queue = this.getQueue(conversationId);
120
- if (queue.size() >= 5) {
121
- log.logWarning(`Event queue full for ${conversationId}, discarding: ${event.text.substring(0, 50)}`);
122
- return false;
123
- }
124
- log.logInfo(`Enqueueing event for ${conversationId}: ${event.text.substring(0, 50)}`);
125
- return queue.enqueue(() => {
118
+ return this.getQueue(event.address.conversationId).offerEvent(event, () => {
126
119
  const context = createDiscordAdapters(event, this);
127
120
  return this.handler.handleEvent(event, this, context);
128
121
  });
@@ -1 +1 @@
1
- {"version":3,"file":"bot.js","sourceRoot":"","sources":["../../../src/adapters/discord/bot.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,WAAW,EACX,MAAM,EACN,MAAM,EACN,iBAAiB,EACjB,QAAQ,GAKT,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAWrC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAUrD,OAAO,KAAK,GAAG,MAAM,cAAc,CAAC;AACpC,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,EACjB,2BAA2B,EAC3B,iBAAiB,EACjB,uBAAuB,EACvB,uBAAuB,EACvB,SAAS,GACV,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,SAAS,oBAAoB,CAAC,GAAU;IACtC,IAAK,GAA2B,CAAC,MAAM,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAC7D,IAAK,GAA+B,CAAC,UAAU,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACrE,IAAI,GAAG,CAAC,IAAI,KAAK,gBAAgB;QAAE,OAAO,IAAI,CAAC;IAC/C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,YAAY,GAAG,CAAI,EAAoB,EAAc,EAAE,CAC3D,SAAS,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,oBAAoB,EAAE,CAAC,CAAC;AAEzD,MAAM,OAAO,mBAAmB;IAa9B,YAAY,OAA8B,EAAE,OAAmC;QARvE,cAAS,GAAkB,IAAI,CAAC;QAChC,YAAO,GAAG,KAAK,CAAC;QAChB,WAAM,GAAG,IAAI,GAAG,EAA+B,CAAC;QAChD,WAAM,GAAG,IAAI,sBAAsB,CAAC,SAAS,CAAC,CAAC;QAC/C,gBAAW,GAAW,CAAC,CAAC;QACxB,aAAQ,GAAG,IAAI,GAAG,EAAwC,CAAC;QAC3D,UAAK,GAAG,IAAI,GAAG,EAAiE,CAAC;QAGvF,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,MAAM;YACT,OAAO,CAAC,MAAM;gBACd,IAAI,MAAM,CAAC;oBACT,OAAO,EAAE;wBACP,iBAAiB,CAAC,MAAM;wBACxB,iBAAiB,CAAC,aAAa;wBAC/B,iBAAiB,CAAC,cAAc;wBAChC,iBAAiB,CAAC,cAAc;qBACjC;oBACD,QAAQ,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC;iBAC/C,CAAC,CAAC;IACP,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE;gBACzD,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;oBACjB,OAAO,EAAE,CAAC;oBACV,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAC9B,GAAG,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;gBAC5B,GAAG,CAAC,OAAO,CAAC,0BAA0B,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;gBAC9D,IAAI,CAAC,mBAAmB,EAAE,CAAC;gBAC3B,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBAC1B,IAAI,CAAC;oBACH,MAAM,WAAW,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CACxC,gBAAgB,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAC9D,MAAM,CAAC,MAAM,CACX;wBACE,IAAI,EAAE,KAAK,CAAC,IAAI;wBAChB,WAAW,EAAE,KAAK,CAAC,WAAW;qBAC/B,EACD,KAAK,CAAC,GAAG;wBACP,CAAC,CAAC;4BACE,OAAO,EAAE;gCACP;oCACE,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI;oCACpB,WAAW,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW;oCAClC,IAAI,EAAE,4BAA4B,CAAC,MAAe;oCAClD,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,QAAQ;iCAC7B;6BACF;yBACF;wBACH,CAAC,CAAC,EAAE,CACP,CACF,CACF,CAAC;gBACJ,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,GAAG,CAAC,UAAU,CAAC,2CAA2C,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;gBACjF,CAAC;gBACD,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACvC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC9C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACxB,CAAC;gBAAS,CAAC;YACT,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC1B,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAe,EAAE,IAAY;QAC7C,OAAO,YAAY,CAAC,KAAK,IAAI,EAAE;YAC7B,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAChD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;YACpD,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAe,EAAE,EAAU,EAAE,IAAY;QAC3D,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAe,EAAE,SAAiB,EAAE,KAAa;QACjE,MAAM,YAAY,CAAC,KAAK,IAAI,EAAE;YAC5B,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAChD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAC/C,MAAM,GAAG,CAAC,KAAK,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,YAAY,CAAC,KAAwB;QACnC,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAC/B,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC;QACpD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QAC5C,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YACtB,GAAG,CAAC,UAAU,CACZ,wBAAwB,cAAc,iBAAiB,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CACrF,CAAC;YACF,OAAO,KAAK,CAAC;QACf,CAAC;QACD,GAAG,CAAC,OAAO,CAAC,wBAAwB,cAAc,KAAK,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;QACtF,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;YACxB,MAAM,OAAO,GAAG,qBAAqB,CAAC,KAAqB,EAAE,IAAI,CAAC,CAAC;YACnE,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,gBAAgB;QACd,OAAO;YACL,IAAI,EAAE,SAAS;YACf,UAAU,EAAE,YAAY;YACxB,eAAe,EACb,oSAAoS;YACtS,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE;YAC/B,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE;YACzB,WAAW,EAAE;gBACX,gBAAgB,EAAE,KAAK;aACxB;SACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,SAAiB,EAAE,SAAiB,EAAE,IAAY;QACvE,OAAO,YAAY,CAAC,KAAK,IAAI,EAAE;YAC7B,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;YAClD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAC/C,MAAM,GAAG,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,SAAiB,EAAE,SAAiB,EAAE,IAAY;QAChE,OAAO,YAAY,CAAC,KAAK,IAAI,EAAE;YAC7B,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;YAClD,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YACvD,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;YAC/D,OAAO,IAAI,CAAC,EAAE,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,SAAiB,EAAE,iBAAyB,EAAE,IAAY;QAC3E,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;YACnE,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;gBAC1D,OAAO,YAAY,CAAC,KAAK,IAAI,EAAE;oBAC7B,MAAM,GAAG,GAAG,MAAO,MAAwB,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;oBAC3E,OAAO,GAAG,CAAC,EAAE,CAAC;gBAChB,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACV,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,iBAAiB,EAAE,IAAI,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,SAAiB,EAAE,SAAiB;QACzD,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;YAClD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAC/C,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;QACrB,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,SAAiB;QAChC,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;YAClD,MAAM,EAAE,CAAC,UAAU,EAAE,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,SAAiB,EAAE,QAAgB,EAAE,KAAc;QAClE,OAAO,YAAY,CAAC,KAAK,IAAI,EAAE;YAC7B,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;YAClD,MAAM,QAAQ,GAAG,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAC7C,MAAM,WAAW,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;YAC3C,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,MAAc,EAAE,IAAY;QAClD,OAAO,YAAY,CAAC,KAAK,IAAI,EAAE;YAC7B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACnD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;YACtD,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,eAAuB,EAAE,MAAc,EAAE,IAAY;QACrE,MAAM,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;IAED,cAAc;QACZ,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,WAAW;QACT,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,SAAS,CAAC,SAAiB,EAAE,KAAa;QACxC,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC5F,CAAC;IAED,cAAc,CAAC,SAAiB,EAAE,IAAY,EAAE,EAAU;QACxD,oBAAoB,CAClB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,EAChE,IAAI,EACJ,EAAE,CACH,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,kBAAkB,CACtB,SAAiB,EACjB,WAAyD;QAEzD,MAAM,KAAK,GAAyB,EAAE,CAAC;QACvC,KAAK,MAAM,UAAU,IAAI,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC;YAC9C,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;gBACrB,GAAG,CAAC,UAAU,CAAC,2CAA2C,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC;gBAC5E,SAAS;YACX,CAAC;YACD,KAAK,CAAC,IAAI,CAAC;gBACT,IAAI,EAAE,UAAU,CAAC,IAAI;gBACrB,QAAQ,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,iBAAiB,CAAC,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC;aACpE,CAAC,CAAC;QACL,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;QAChF,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,uBAAuB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACvE,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC;YAC7B,GAAG,CAAC,UAAU,CAAC,uCAAuC,EAAE,GAAG,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;QAC/F,CAAC;QACD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IACnF,CAAC;IAEO,QAAQ,CAAC,SAAiB;QAChC,IAAI,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,KAAK,GAAG,IAAI,mBAAmB,CAAC,SAAS,CAAC,CAAC;YAC3C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACpC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,iBAAiB,CAAC,SAAiB,EAAE,UAAkB;QAC7D,MAAM,OAAO,GAAG,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAC1D,MAAM,YAAY,GAAG,iBAAiB,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;QACvF,IAAI,YAAY;YAAE,OAAO,YAAY,CAAC;QACtC,IAAI,UAAU,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QAC1C,OAAO,2BAA2B,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5D,CAAC;IAEO,mBAAmB;QACzB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACtD,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBACpD,IAAI,OAAO,CAAC,WAAW,EAAE,IAAI,MAAM,IAAI,OAAO,EAAE,CAAC;oBAC/C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;gBACtF,CAAC;YACH,CAAC;YACD,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBAClD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE;oBACxB,EAAE,EAAE,MAAM,CAAC,EAAE;oBACb,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ;oBAC9B,WAAW,EAAE,MAAM,CAAC,WAAW;iBAChC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAEO,wBAAwB,CAAC,IAAY;QAC3C,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,IAAI,CAAC,SAAS,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5E,CAAC;IAEO,0BAA0B,CAAC,KAMlC;QACC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO;gBACL,cAAc,EAAE,KAAK,CAAC,SAAS;gBAC/B,QAAQ,EAAE,KAAK,CAAC,eAAe;aAChC,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO;gBACL,cAAc,EAAE,KAAK,CAAC,eAAe,IAAI,KAAK,CAAC,SAAS;gBACxD,QAAQ,EAAE,KAAK,CAAC,SAAS;aAC1B,CAAC;QACJ,CAAC;QAED,OAAO;YACL,cAAc,EAAE,KAAK,CAAC,SAAS;YAC/B,QAAQ,EAAE,KAAK,CAAC,eAAe;SAChC,CAAC;IACJ,CAAC;IAEO,0BAA0B,CAChC,WAAsC,EACtC,WAAmB,EACnB,UAAkB,EAClB,cAAsB;QAEtB,MAAM,IAAI,GAAG,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACzC,MAAM,kBAAkB,GAAG,CAAC,IAAI,CAAC;QAEjC,MAAM,OAAO,GAAG,yBAAyB,CAAC;YACxC,QAAQ,EAAE,SAAS;YACnB,cAAc;YACd,EAAE,EAAE,WAAW,CAAC,EAAE;YAClB,UAAU;YACV,gBAAgB,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ;YAC5C,MAAM;YACN,QAAQ;YACR,IAAI,EAAE,WAAW;YACjB,WAAW,EAAE,EAAE;SAChB,CAAC,CAAC;QAEH,MAAM,gBAAgB,GAAG,KAAK,EAAE,IAAY,EAAE,OAAO,GAAG,KAAK,EAAiB,EAAE;YAC9E,IAAI,WAAW,CAAC,OAAO,IAAI,WAAW,CAAC,QAAQ,EAAE,CAAC;gBAChD,IAAI,OAAO,EAAE,CAAC;oBACZ,MAAM,WAAW,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjD,CAAC;qBAAM,CAAC;oBACN,MAAM,WAAW,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAC/E,CAAC;gBACD,OAAO;YACT,CAAC;YAED,MAAM,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC5E,CAAC,CAAC;QAEF,MAAM,SAAS,GAA0B;YACvC,OAAO,EAAE,KAAK,EAAE,IAAY,EAAE,EAAE;gBAC9B,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC/B,CAAC;YACD,eAAe,EAAE,KAAK,EAAE,IAAY,EAAE,EAAE;gBACtC,MAAM,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACrC,CAAC;YACD,iBAAiB,EAAE,KAAK,EAAE,IAAY,EAAE,EAAE;gBACxC,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC/B,CAAC;YACD,iBAAiB,EAAE,KAAK,EAAE,MAAsB,EAAE,EAAE;gBAClD,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACvD,MAAM,SAAS,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,OAAO,MAAM,CAAC,MAAM,EAAE,CAAC;gBAC7G,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC;YACpC,CAAC;YACD,SAAS,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;YACzB,UAAU,EAAE,KAAK,EAAE,OAAgB,EAAE,EAAE;gBACrC,IAAI,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;oBAC7D,MAAM,WAAW,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAClE,CAAC;YACH,CAAC;YACD,UAAU,EAAE,KAAK,EAAE,QAAgB,EAAE,KAAc,EAAE,EAAE;gBACrD,MAAM,IAAI,CAAC,UAAU,CAAC,cAAc,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACzD,CAAC;YACD,cAAc,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC;SAC/B,CAAC;QAEF,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;IACpE,CAAC;IAEO,kBAAkB;QACxB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC,WAAW,EAAE,EAAE;YACvD,KAAK,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,uBAAuB,CAAC,WAAW,CAAC,CAAC,CAAC;QACxE,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,EAAE;YAC/C,KAAK,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,uBAAuB,CAAC,WAAuC;QAC3E,IAAI,CAAC,WAAW,CAAC,kBAAkB,EAAE;YAAE,OAAO;QAC9C,MAAM,aAAa,GAAG,gBAAgB,CAAC,IAAI,CACzC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,WAAW,CACnE,CAAC;QACF,IAAI,CAAC,aAAa;YAAE,OAAO;QAE3B,MAAM,IAAI,GAAG,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,0BAA0B,CAAC;YACnE,SAAS,EAAE,WAAW,CAAC,SAAS;YAChC,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE;YAC9B,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,KAAK;YAClD,eAAe,EACb,WAAW,CAAC,OAAO,IAAI,UAAU,IAAI,WAAW,CAAC,OAAO;gBACtD,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ;gBAC9B,CAAC,CAAC,IAAI;SACX,CAAC,CAAC;QACH,MAAM,UAAU,GAAG,qBAAqB,CAAC;YACvC,cAAc;YACd,gBAAgB,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ;YAC5C,SAAS,EAAE,WAAW,CAAC,EAAE;YACzB,kBAAkB,EAAE,IAAI;YACxB,QAAQ;SACT,CAAC,CAAC;QACH,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG;YAClC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE;YAC/D,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,WAAW,GAAG,UAAU;YAC5B,CAAC,CAAC,IAAI,WAAW,CAAC,WAAW,IAAI,UAAU,EAAE;YAC7C,CAAC,CAAC,IAAI,WAAW,CAAC,WAAW,EAAE,CAAC;QAElC,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE;YAC7B,IAAI,EAAE,IAAI,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC,WAAW,EAAE;YAC1D,EAAE,EAAE,WAAW,CAAC,EAAE;YAClB,QAAQ,EAAE,QAAQ,IAAI,SAAS;YAC/B,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE;YACzB,QAAQ,EAAE,WAAW,CAAC,IAAI,CAAC,QAAQ;YACnC,IAAI,EAAE,WAAW;YACjB,WAAW,EAAE,EAAE;YACf,cAAc,EAAE,KAAK;SACtB,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,IAAI,CAAC,0BAA0B,CAC7C,WAAW,EACX,WAAW,EACX,UAAU,EACV,cAAc,CACf,CAAC;QACF,IAAI,CAAC;YACH,IAAI,aAAa,CAAC,SAAS,EAAE,CAAC;gBAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;gBACtE,IAAI,UAAU,EAAE,CAAC;oBACf,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAC3B,mBAAmB,CAAC,SAAS,EAAE,cAAc,CAAC,EAC9C,UAAU,EACV,IAAI,CACL,CAAC;oBACF,MAAM,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC;gBACvE,CAAC;qBAAM,CAAC;oBACN,MAAM,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC,CAAC;gBACnE,CAAC;gBACD,OAAO;YACT,CAAC;YAED,MAAM,KAAK,GAAG,uBAAuB,CAAC;gBACpC,QAAQ,EAAE,SAAS;gBACnB,IAAI,EAAE,IAAI;gBACV,cAAc;gBACd,gBAAgB,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ;gBAC5C,EAAE,EAAE,WAAW,CAAC,EAAE;gBAClB,SAAS,EAAE,QAAQ;gBACnB,UAAU;gBACV,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE;gBACzB,IAAI,EAAE,WAAW;gBACjB,WAAW,EAAE,EAAE;aAChB,CAAC,CAAC;YAEH,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,UAAU,CAAC,6BAA6B,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;YACjE,IAAI,CAAC,WAAW,CAAC,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;gBAClD,MAAM,WAAW,CAAC,KAAK,CAAC;oBACtB,OAAO,EAAE,GAAG,WAAW,CAAC,WAAW,0CAA0C;oBAC7E,SAAS,EAAE,CAAC,IAAI;iBACjB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,mBAAmB,CAAC,GAA2B;QAC3D,IAAI,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC,WAAW;YAAE,OAAO;QACpD,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG;YAAE,OAAO;QAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,CAAC,EAAE,CAAC;QACjD,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QAC1C,MAAM,eAAe,GAAG,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC;QACjD,MAAM,aAAa,GAAG,UAAU,IAAI,CAAC,CAAC,eAAe,CAAC;QACtD,MAAM,WAAW,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;QACjE,MAAM,SAAS,GAAG,IAAI,IAAI,WAAW,IAAI,aAAa,CAAC;QAEvD,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,0BAA0B,CAAC;YACnE,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,OAAO,EAAE,CAAC,IAAI;YACd,QAAQ,EAAE,UAAU;YACpB,eAAe,EAAE,UAAU,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI;YACxE,eAAe;SAChB,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;QACrC,MAAM,KAAK,GAAG,GAAG,CAAC,EAAE,CAAC;QAErB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE;YACrB,EAAE,EAAE,MAAM;YACV,QAAQ;YACR,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,IAAI,QAAQ;SACjD,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;YAChE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,EAAE;gBAChC,EAAE,EAAE,cAAc;gBAClB,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,cAAc;aACzC,CAAC,CAAC;QACL,CAAC;QAED,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;QACpD,MAAM,UAAU,GAAG,qBAAqB,CAAC;YACvC,cAAc;YACd,gBAAgB;YAChB,SAAS,EAAE,KAAK;YAChB,kBAAkB,EAAE,IAAI;YACxB,QAAQ;SACT,CAAC,CAAC;QAEH,MAAM,WAAW,GAAG,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAE/D,MAAM,SAAS,GAAG,uBAAuB,CAAC;YACxC,QAAQ,EAAE,SAAS;YACnB,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;YAC7B,cAAc;YACd,gBAAgB;YAChB,EAAE,EAAE,KAAK;YACT,SAAS,EAAE,QAAQ;YACnB,UAAU;YACV,IAAI,EAAE,MAAM;YACZ,QAAQ;YACR,IAAI,EAAE,WAAW;SAClB,CAAiB,CAAC;QAEnB,MAAM,oBAAoB,CAAC;YACzB,SAAS;YACT,SAAS;YACT,SAAS,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE;YACpD,UAAU,EAAE,OAAO;YACnB,YAAY,EAAE;gBACZ,IAAI,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,EAAE;gBACjC,EAAE,EAAE,KAAK;gBACT,QAAQ,EAAE,CAAC,IAAI,IAAI,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;gBAClD,IAAI,EAAE,MAAM;gBACZ,QAAQ;gBACR,IAAI,EAAE,WAAW;gBACjB,cAAc,EAAE,KAAK;aACtB;YACD,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,KAAK,CAAC;YACrD,kBAAkB,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,cAAc,EAAE,GAAG,CAAC,WAAW,CAAC;YAClF,QAAQ,EAAE,UAAU;YACpB,OAAO,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;YAClE,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,GAAG,EAAE,IAAI;YACT,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,qBAAqB,CAAC,KAAK,EAAE,IAAI,CAAC;SAC7D,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAC5B,SAAiB;QAEjB,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACvD,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,WAAW,SAAS,wBAAwB,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,EAA2D,CAAC;IACrE,CAAC;CACF","sourcesContent":["import {\n ApplicationCommandOptionType,\n ChannelType,\n Client,\n Events,\n GatewayIntentBits,\n Partials,\n type TextChannel,\n type DMChannel,\n type NewsChannel,\n type ThreadChannel,\n} from \"discord.js\";\nimport { readFileSync } from \"node:fs\";\nimport { basename } from \"node:path\";\n\nimport type {\n ConversationContext,\n ConversationEvent,\n MessagingEventHandler,\n ConversationResponder,\n ChatToolResult,\n MessagingBot,\n MessagingInfo,\n} from \"../../types.js\";\nimport { discordTextPayload } from \"./components.js\";\nimport type {\n DiscordAttachmentSource,\n DiscordClient,\n DiscordCommandInteraction,\n DiscordEvent,\n DiscordIncomingInteraction,\n DiscordIncomingMessage,\n DiscordMessagingBotOptions,\n} from \"./types.js\";\nimport * as log from \"../../log.js\";\nimport {\n createConversationEvent,\n createConversationMessage,\n createOfficeAddress,\n} from \"../../office/index.js\";\nimport type { Workspace } from \"../../office/types.js\";\nimport { resolveChatSessionKey } from \"../../sessions/session-key.js\";\nimport { formatNothingRunning } from \"../messages.js\";\nimport {\n appendBotResponseLog,\n appendChannelLog,\n MessagingEventQueue,\n MessagingIntakeTracker,\n downloadUrlToFile,\n resolveOnlyScopedStopTarget,\n resolveStopTarget,\n saveIncomingAttachments,\n shortNameToUnicodeEmoji,\n withRetry,\n} from \"../shared.js\";\nimport type { IncomingAttachment } from \"../types.js\";\nimport { COMMAND_MANIFEST } from \"../commands/manifest.js\";\nimport { processMessageIntake } from \"../intake.js\";\nimport { createDiscordAdapters } from \"./context.js\";\nimport { errorMessage } from \"../../unknown-values.js\";\n\nfunction discordIsRateLimited(err: Error): boolean {\n if ((err as { status?: number }).status === 429) return true;\n if ((err as { httpStatus?: number }).httpStatus === 429) return true;\n if (err.name === \"RateLimitError\") return true;\n return false;\n}\n\nconst discordRetry = <T>(fn: () => Promise<T>): Promise<T> =>\n withRetry(fn, { isRateLimited: discordIsRateLimited });\n\nexport class DiscordMessagingBot implements MessagingBot {\n private client: DiscordClient;\n private handler: MessagingEventHandler;\n private token: string;\n private workspace: Workspace;\n private botUserId: string | null = null;\n private stopped = false;\n private queues = new Map<string, MessagingEventQueue>();\n private intake = new MessagingIntakeTracker(\"Discord\");\n private startupTime: number = 0;\n private channels = new Map<string, { id: string; name: string }>();\n private users = new Map<string, { id: string; userName: string; displayName: string }>();\n\n constructor(handler: MessagingEventHandler, options: DiscordMessagingBotOptions) {\n this.handler = handler;\n this.token = options.token;\n this.workspace = options.workspace;\n this.client =\n options.client ??\n new Client({\n intents: [\n GatewayIntentBits.Guilds,\n GatewayIntentBits.GuildMessages,\n GatewayIntentBits.MessageContent,\n GatewayIntentBits.DirectMessages,\n ],\n partials: [Partials.Channel, Partials.Message],\n });\n }\n\n async start(): Promise<void> {\n this.stopped = false;\n await new Promise<void>((resolve, reject) => {\n this.client.once(Events.ClientReady, async (readyClient) => {\n if (this.stopped) {\n resolve();\n return;\n }\n this.botUserId = readyClient.user.id;\n this.startupTime = Date.now();\n log.logConnected(\"Discord\");\n log.logInfo(`Discord bot started as ${readyClient.user.tag}`);\n this.loadCachedGuildData();\n this.setupEventHandlers();\n try {\n await readyClient.application.commands.set(\n COMMAND_MANIFEST.filter((entry) => entry.discord).map((entry) =>\n Object.assign(\n {\n name: entry.name,\n description: entry.description,\n },\n entry.arg\n ? {\n options: [\n {\n name: entry.arg.name,\n description: entry.arg.description,\n type: ApplicationCommandOptionType.String as const,\n required: entry.arg.required,\n },\n ],\n }\n : {},\n ),\n ),\n );\n } catch (err) {\n log.logWarning(\"Failed to register Discord slash commands\", errorMessage(err));\n }\n resolve();\n });\n this.client.once(Events.Error, reject);\n this.client.login(this.token).catch(reject);\n });\n }\n\n async stop(): Promise<void> {\n this.stopped = true;\n try {\n this.client.destroy();\n } finally {\n await this.intake.close();\n await Promise.all([...this.queues.values()].map((queue) => queue.close()));\n }\n }\n\n async postMessage(channel: string, text: string): Promise<string> {\n return discordRetry(async () => {\n const ch = await this.fetchTextChannel(channel);\n const msg = await ch.send(discordTextPayload(text));\n return msg.id;\n });\n }\n\n async updateMessage(channel: string, ts: string, text: string): Promise<void> {\n await this.updateMessageRaw(channel, ts, text);\n }\n\n async addReaction(channel: string, messageTs: string, emoji: string): Promise<void> {\n await discordRetry(async () => {\n const ch = await this.fetchTextChannel(channel);\n const msg = await ch.messages.fetch(messageTs);\n await msg.react(shortNameToUnicodeEmoji(emoji));\n });\n }\n\n enqueueEvent(event: ConversationEvent): boolean {\n if (this.stopped) return false;\n const conversationId = event.address.conversationId;\n const queue = this.getQueue(conversationId);\n if (queue.size() >= 5) {\n log.logWarning(\n `Event queue full for ${conversationId}, discarding: ${event.text.substring(0, 50)}`,\n );\n return false;\n }\n log.logInfo(`Enqueueing event for ${conversationId}: ${event.text.substring(0, 50)}`);\n return queue.enqueue(() => {\n const context = createDiscordAdapters(event as DiscordEvent, this);\n return this.handler.handleEvent(event, this, context);\n });\n }\n\n getMessagingInfo(): MessagingInfo {\n return {\n name: \"discord\",\n trustModel: \"membership\",\n formattingGuide:\n \"## Discord Formatting (Markdown)\\nBold: **text**, Italic: *text*, Code: `code`, Block: ```language\\ncode```\\nLinks: [text](url), Spoiler: ||text||, Headings: # ## ###\\nWrite ordinary Markdown, including tables — the adapter converts anything Discord cannot render. Use code blocks for code.\",\n channels: this.getAllChannels(),\n users: this.getAllUsers(),\n diagnostics: {\n showUsageSummary: false,\n },\n };\n }\n\n async updateMessageRaw(channelId: string, messageId: string, text: string): Promise<void> {\n return discordRetry(async () => {\n const ch = await this.fetchTextChannel(channelId);\n const msg = await ch.messages.fetch(messageId);\n await msg.edit(discordTextPayload(text));\n });\n }\n\n async postReply(channelId: string, replyToId: string, text: string): Promise<string> {\n return discordRetry(async () => {\n const ch = await this.fetchTextChannel(channelId);\n const replyTarget = await ch.messages.fetch(replyToId);\n const sent = await replyTarget.reply(discordTextPayload(text));\n return sent.id;\n });\n }\n\n async postInThread(channelId: string, threadOrMessageId: string, text: string): Promise<string> {\n try {\n const thread = await this.client.channels.fetch(threadOrMessageId);\n if (thread && (thread.isThread() || thread.isTextBased())) {\n return discordRetry(async () => {\n const msg = await (thread as ThreadChannel).send(discordTextPayload(text));\n return msg.id;\n });\n }\n } catch {}\n return this.postReply(channelId, threadOrMessageId, text);\n }\n\n async deleteMessageRaw(channelId: string, messageId: string): Promise<void> {\n try {\n const ch = await this.fetchTextChannel(channelId);\n const msg = await ch.messages.fetch(messageId);\n await msg.delete();\n } catch {}\n }\n\n async sendTyping(channelId: string): Promise<void> {\n try {\n const ch = await this.fetchTextChannel(channelId);\n await ch.sendTyping();\n } catch {}\n }\n\n async uploadFile(channelId: string, filePath: string, title?: string): Promise<void> {\n return discordRetry(async () => {\n const ch = await this.fetchTextChannel(channelId);\n const fileName = title ?? basename(filePath);\n const fileContent = readFileSync(filePath);\n await ch.send({ files: [{ attachment: fileContent, name: fileName }] });\n });\n }\n\n async sendDirectMessage(userId: string, text: string): Promise<string> {\n return discordRetry(async () => {\n const user = await this.client.users.fetch(userId);\n const msg = await user.send(discordTextPayload(text));\n return msg.id;\n });\n }\n\n async postPrivate(_conversationId: string, userId: string, text: string): Promise<void> {\n await this.sendDirectMessage(userId, text);\n }\n\n getAllChannels(): { id: string; name: string }[] {\n return Array.from(this.channels.values());\n }\n\n getAllUsers(): { id: string; userName: string; displayName: string }[] {\n return Array.from(this.users.values());\n }\n\n logToFile(channelId: string, entry: object): void {\n appendChannelLog(this.workspace.office(createOfficeAddress(\"discord\", channelId)), entry);\n }\n\n logBotResponse(channelId: string, text: string, ts: string): void {\n appendBotResponseLog(\n this.workspace.office(createOfficeAddress(\"discord\", channelId)),\n text,\n ts,\n );\n }\n\n async processAttachments(\n channelId: string,\n attachments: ReadonlyMap<string, DiscordAttachmentSource>,\n ): Promise<{ name: string; localPath: string }[]> {\n const items: IncomingAttachment[] = [];\n for (const attachment of attachments.values()) {\n if (!attachment.name) {\n log.logWarning(\"Discord attachment missing name, skipping\", attachment.url);\n continue;\n }\n items.push({\n name: attachment.name,\n download: (destPath) => downloadUrlToFile(attachment.url, destPath),\n });\n }\n\n const office = this.workspace.office(createOfficeAddress(\"discord\", channelId));\n const { saved, failed } = await saveIncomingAttachments(office, items);\n for (const failure of failed) {\n log.logWarning(`Failed to download Discord attachment`, `${failure.name}: ${failure.error}`);\n }\n return saved.map((item) => ({ name: item.original, localPath: item.localPath }));\n }\n\n private getQueue(channelId: string): MessagingEventQueue {\n let queue = this.queues.get(channelId);\n if (!queue) {\n queue = new MessagingEventQueue(\"Discord\");\n this.queues.set(channelId, queue);\n }\n return queue;\n }\n\n private resolveStopTarget(channelId: string, sessionKey: string): string | null {\n const address = createOfficeAddress(\"discord\", channelId);\n const directTarget = resolveStopTarget({ handler: this.handler, address, sessionKey });\n if (directTarget) return directTarget;\n if (sessionKey !== channelId) return null;\n return resolveOnlyScopedStopTarget(this.handler, address);\n }\n\n private loadCachedGuildData(): void {\n for (const guild of this.client.guilds.cache.values()) {\n for (const channel of guild.channels.cache.values()) {\n if (channel.isTextBased() && \"name\" in channel) {\n this.channels.set(channel.id, { id: channel.id, name: channel.name ?? channel.id });\n }\n }\n for (const member of guild.members.cache.values()) {\n this.users.set(member.id, {\n id: member.id,\n userName: member.user.username,\n displayName: member.displayName,\n });\n }\n }\n }\n\n private stripMessagingBotMention(text: string): string {\n if (!this.botUserId) return text;\n return text.replace(new RegExp(`<@!?${this.botUserId}>`, \"g\"), \"\").trim();\n }\n\n private resolveConversationContext(input: {\n channelId: string;\n inGuild: boolean;\n isThread: boolean;\n parentChannelId?: string | null;\n referencedMsgId?: string;\n }): { conversationId: string; threadTs?: string } {\n if (!input.inGuild) {\n return {\n conversationId: input.channelId,\n threadTs: input.referencedMsgId,\n };\n }\n\n if (input.isThread) {\n return {\n conversationId: input.parentChannelId ?? input.channelId,\n threadTs: input.channelId,\n };\n }\n\n return {\n conversationId: input.channelId,\n threadTs: input.referencedMsgId,\n };\n }\n\n private createSlashCommandAdapters(\n interaction: DiscordCommandInteraction,\n commandText: string,\n sessionKey: string,\n conversationId: string,\n ): ConversationContext {\n const isDM = !interaction.inGuild();\n const userId = interaction.user.id;\n const userName = interaction.user.username;\n const platform = this.getMessagingInfo();\n const shouldUseEphemeral = !isDM;\n\n const message = createConversationMessage({\n platform: \"discord\",\n conversationId,\n id: interaction.id,\n sessionKey,\n conversationKind: isDM ? \"direct\" : \"shared\",\n userId,\n userName,\n text: commandText,\n attachments: [],\n });\n\n const respondPrivately = async (text: string, replace = false): Promise<void> => {\n if (interaction.replied || interaction.deferred) {\n if (replace) {\n await interaction.editReply({ content: text });\n } else {\n await interaction.followUp({ content: text, ephemeral: shouldUseEphemeral });\n }\n return;\n }\n\n await interaction.reply({ content: text, ephemeral: shouldUseEphemeral });\n };\n\n const responder: ConversationResponder = {\n respond: async (text: string) => {\n await respondPrivately(text);\n },\n replaceResponse: async (text: string) => {\n await respondPrivately(text, true);\n },\n respondDiagnostic: async (text: string) => {\n await respondPrivately(text);\n },\n respondToolResult: async (result: ChatToolResult) => {\n const duration = (result.durationMs / 1000).toFixed(1);\n const formatted = `${result.isError ? \"Error\" : \"Done\"} ${result.toolName} (${duration}s)\\n${result.result}`;\n await respondPrivately(formatted);\n },\n setTyping: async () => {},\n setWorking: async (working: boolean) => {\n if (working && !interaction.replied && !interaction.deferred) {\n await interaction.deferReply({ ephemeral: shouldUseEphemeral });\n }\n },\n uploadFile: async (filePath: string, title?: string) => {\n await this.uploadFile(conversationId, filePath, title);\n },\n deleteResponse: async () => {},\n };\n\n return { address: message.address, message, responder, platform };\n }\n\n private setupEventHandlers(): void {\n this.client.on(Events.InteractionCreate, (interaction) => {\n void this.intake.run(() => this.handleInteractionCreate(interaction));\n });\n this.client.on(Events.MessageCreate, (message) => {\n void this.intake.run(() => this.handleMessageCreate(message));\n });\n }\n\n private async handleInteractionCreate(interaction: DiscordIncomingInteraction): Promise<void> {\n if (!interaction.isChatInputCommand()) return;\n const manifestEntry = COMMAND_MANIFEST.find(\n (entry) => entry.discord && entry.name === interaction.commandName,\n );\n if (!manifestEntry) return;\n\n const isDM = !interaction.inGuild();\n const { conversationId, threadTs } = this.resolveConversationContext({\n channelId: interaction.channelId,\n inGuild: interaction.inGuild(),\n isThread: interaction.channel?.isThread() ?? false,\n parentChannelId:\n interaction.channel && \"parentId\" in interaction.channel\n ? interaction.channel.parentId\n : null,\n });\n const sessionKey = resolveChatSessionKey({\n conversationId,\n conversationKind: isDM ? \"direct\" : \"shared\",\n messageId: interaction.id,\n persistentTopLevel: true,\n threadTs,\n });\n const commandArg = manifestEntry.arg\n ? interaction.options.getString(manifestEntry.arg.name)?.trim()\n : undefined;\n const commandText = commandArg\n ? `/${interaction.commandName} ${commandArg}`\n : `/${interaction.commandName}`;\n\n this.logToFile(conversationId, {\n date: new Date(interaction.createdTimestamp).toISOString(),\n ts: interaction.id,\n threadTs: threadTs || undefined,\n user: interaction.user.id,\n userName: interaction.user.username,\n text: commandText,\n attachments: [],\n isMessagingBot: false,\n });\n\n const context = this.createSlashCommandAdapters(\n interaction,\n commandText,\n sessionKey,\n conversationId,\n );\n try {\n if (manifestEntry.magicWord) {\n const stopTarget = this.resolveStopTarget(conversationId, sessionKey);\n if (stopTarget) {\n await this.handler.handleStop(\n createOfficeAddress(\"discord\", conversationId),\n stopTarget,\n this,\n );\n await context.responder.respond(\"Stopped the current conversation.\");\n } else {\n await context.responder.respond(formatNothingRunning(\"discord\"));\n }\n return;\n }\n\n const event = createConversationEvent({\n platform: \"discord\",\n type: \"dm\",\n conversationId,\n conversationKind: isDM ? \"direct\" : \"shared\",\n ts: interaction.id,\n thread_ts: threadTs,\n sessionKey,\n user: interaction.user.id,\n text: commandText,\n attachments: [],\n });\n\n await this.handler.handleEvent(event, this, context);\n } catch (err) {\n log.logWarning(\"Discord slash command error\", errorMessage(err));\n if (!interaction.replied && !interaction.deferred) {\n await interaction.reply({\n content: `${interaction.commandName} command failed. Please try again later.`,\n ephemeral: !isDM,\n });\n }\n }\n }\n\n private async handleMessageCreate(msg: DiscordIncomingMessage): Promise<void> {\n if (msg.createdTimestamp < this.startupTime) return;\n if (msg.author.bot) return;\n const isDM = msg.channel.type === ChannelType.DM;\n const isInThread = msg.channel.isThread();\n const referencedMsgId = msg.reference?.messageId;\n const isThreadReply = isInThread || !!referencedMsgId;\n const isMentioned = msg.mentions.users.has(this.botUserId ?? \"\");\n const addressed = isDM || isMentioned || isThreadReply;\n\n const { conversationId, threadTs } = this.resolveConversationContext({\n channelId: msg.channelId,\n inGuild: !isDM,\n isThread: isInThread,\n parentChannelId: \"parentId\" in msg.channel ? msg.channel.parentId : null,\n referencedMsgId,\n });\n const userId = msg.author.id;\n const userName = msg.author.username;\n const msgId = msg.id;\n\n this.users.set(userId, {\n id: userId,\n userName,\n displayName: msg.member?.displayName ?? userName,\n });\n\n if (!this.channels.has(conversationId) && \"name\" in msg.channel) {\n this.channels.set(conversationId, {\n id: conversationId,\n name: msg.channel.name ?? conversationId,\n });\n }\n\n const conversationKind = isDM ? \"direct\" : \"shared\";\n const sessionKey = resolveChatSessionKey({\n conversationId,\n conversationKind,\n messageId: msgId,\n persistentTopLevel: true,\n threadTs,\n });\n\n const cleanedText = this.stripMessagingBotMention(msg.content);\n\n const eventBase = createConversationEvent({\n platform: \"discord\",\n type: isDM ? \"dm\" : \"mention\",\n conversationId,\n conversationKind,\n ts: msgId,\n thread_ts: threadTs,\n sessionKey,\n user: userId,\n userName,\n text: cleanedText,\n }) as DiscordEvent;\n\n await processMessageIntake({\n eventBase,\n addressed,\n magicWord: { addressed, scopeFallback: \"top-level\" },\n busyPolicy: \"queue\",\n logEntryBase: {\n date: msg.createdAt.toISOString(),\n ts: msgId,\n threadTs: !isDM && threadTs ? threadTs : undefined,\n user: userId,\n userName,\n text: cleanedText,\n isMessagingBot: false,\n },\n log: (entry) => this.logToFile(conversationId, entry),\n processAttachments: () => this.processAttachments(conversationId, msg.attachments),\n queueKey: sessionKey,\n enqueue: (queueKey, work) => this.getQueue(queueKey).enqueue(work),\n handler: this.handler,\n bot: this,\n createContext: (event) => createDiscordAdapters(event, this),\n });\n }\n\n private async fetchTextChannel(\n channelId: string,\n ): Promise<TextChannel | DMChannel | NewsChannel | ThreadChannel> {\n const ch = await this.client.channels.fetch(channelId);\n if (!ch || !ch.isTextBased()) {\n throw new Error(`Channel ${channelId} is not a text channel`);\n }\n return ch as TextChannel | DMChannel | NewsChannel | ThreadChannel;\n }\n}\n"]}
1
+ {"version":3,"file":"bot.js","sourceRoot":"","sources":["../../../src/adapters/discord/bot.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ApplicationCommandOptionType,\n ChannelType,\n Client,\n Events,\n GatewayIntentBits,\n Partials,\n type TextChannel,\n type DMChannel,\n type NewsChannel,\n type ThreadChannel,\n} from \"discord.js\";\nimport { readFileSync } from \"node:fs\";\nimport { basename } from \"node:path\";\n\nimport type {\n ConversationContext,\n ConversationEvent,\n MessagingEventHandler,\n ConversationResponder,\n ChatToolResult,\n MessagingBot,\n MessagingInfo,\n} from \"../../types.js\";\nimport { discordTextPayload } from \"./components.js\";\nimport type {\n DiscordAttachmentSource,\n DiscordClient,\n DiscordCommandInteraction,\n DiscordEvent,\n DiscordIncomingInteraction,\n DiscordIncomingMessage,\n DiscordMessagingBotOptions,\n} from \"./types.js\";\nimport * as log from \"../../log.js\";\nimport {\n createConversationEvent,\n createConversationMessage,\n createOfficeAddress,\n} from \"../../office/index.js\";\nimport type { Workspace } from \"../../office/types.js\";\nimport { resolveChatSessionKey } from \"../../sessions/session-key.js\";\nimport { formatNothingRunning } from \"../messages.js\";\nimport {\n appendBotResponseLog,\n appendChannelLog,\n MessagingEventQueue,\n MessagingIntakeTracker,\n downloadUrlToFile,\n resolveOnlyScopedStopTarget,\n resolveStopTarget,\n saveIncomingAttachments,\n shortNameToUnicodeEmoji,\n withRetry,\n} from \"../shared.js\";\nimport type { IncomingAttachment } from \"../types.js\";\nimport { COMMAND_MANIFEST } from \"../commands/manifest.js\";\nimport { processMessageIntake } from \"../intake.js\";\nimport { createDiscordAdapters } from \"./context.js\";\nimport { errorMessage } from \"../../unknown-values.js\";\n\nfunction discordIsRateLimited(err: Error): boolean {\n if ((err as { status?: number }).status === 429) return true;\n if ((err as { httpStatus?: number }).httpStatus === 429) return true;\n if (err.name === \"RateLimitError\") return true;\n return false;\n}\n\nconst discordRetry = <T>(fn: () => Promise<T>): Promise<T> =>\n withRetry(fn, { isRateLimited: discordIsRateLimited });\n\nexport class DiscordMessagingBot implements MessagingBot {\n private client: DiscordClient;\n private handler: MessagingEventHandler;\n private token: string;\n private workspace: Workspace;\n private botUserId: string | null = null;\n private stopped = false;\n private queues = new Map<string, MessagingEventQueue>();\n private intake = new MessagingIntakeTracker(\"Discord\");\n private startupTime: number = 0;\n private channels = new Map<string, { id: string; name: string }>();\n private users = new Map<string, { id: string; userName: string; displayName: string }>();\n\n constructor(handler: MessagingEventHandler, options: DiscordMessagingBotOptions) {\n this.handler = handler;\n this.token = options.token;\n this.workspace = options.workspace;\n this.client =\n options.client ??\n new Client({\n intents: [\n GatewayIntentBits.Guilds,\n GatewayIntentBits.GuildMessages,\n GatewayIntentBits.MessageContent,\n GatewayIntentBits.DirectMessages,\n ],\n partials: [Partials.Channel, Partials.Message],\n });\n }\n\n async start(): Promise<void> {\n this.stopped = false;\n await new Promise<void>((resolve, reject) => {\n this.client.once(Events.ClientReady, async (readyClient) => {\n if (this.stopped) {\n resolve();\n return;\n }\n this.botUserId = readyClient.user.id;\n this.startupTime = Date.now();\n log.logConnected(\"Discord\");\n log.logInfo(`Discord bot started as ${readyClient.user.tag}`);\n this.loadCachedGuildData();\n this.setupEventHandlers();\n try {\n await readyClient.application.commands.set(\n COMMAND_MANIFEST.filter((entry) => entry.discord).map((entry) =>\n Object.assign(\n {\n name: entry.name,\n description: entry.description,\n },\n entry.arg\n ? {\n options: [\n {\n name: entry.arg.name,\n description: entry.arg.description,\n type: ApplicationCommandOptionType.String as const,\n required: entry.arg.required,\n },\n ],\n }\n : {},\n ),\n ),\n );\n } catch (err) {\n log.logWarning(\"Failed to register Discord slash commands\", errorMessage(err));\n }\n resolve();\n });\n this.client.once(Events.Error, reject);\n this.client.login(this.token).catch(reject);\n });\n }\n\n async stop(): Promise<void> {\n this.stopped = true;\n try {\n this.client.destroy();\n } finally {\n await this.intake.close();\n await Promise.all([...this.queues.values()].map((queue) => queue.close()));\n }\n }\n\n async postMessage(channel: string, text: string): Promise<string> {\n return discordRetry(async () => {\n const ch = await this.fetchTextChannel(channel);\n const msg = await ch.send(discordTextPayload(text));\n return msg.id;\n });\n }\n\n async updateMessage(channel: string, ts: string, text: string): Promise<void> {\n await this.updateMessageRaw(channel, ts, text);\n }\n\n async addReaction(channel: string, messageTs: string, emoji: string): Promise<void> {\n await discordRetry(async () => {\n const ch = await this.fetchTextChannel(channel);\n const msg = await ch.messages.fetch(messageTs);\n await msg.react(shortNameToUnicodeEmoji(emoji));\n });\n }\n\n enqueueEvent(event: ConversationEvent): boolean {\n if (this.stopped) return false;\n return this.getQueue(event.address.conversationId).offerEvent(event, () => {\n const context = createDiscordAdapters(event as DiscordEvent, this);\n return this.handler.handleEvent(event, this, context);\n });\n }\n\n getMessagingInfo(): MessagingInfo {\n return {\n name: \"discord\",\n trustModel: \"membership\",\n formattingGuide:\n \"## Discord Formatting (Markdown)\\nBold: **text**, Italic: *text*, Code: `code`, Block: ```language\\ncode```\\nLinks: [text](url), Spoiler: ||text||, Headings: # ## ###\\nWrite ordinary Markdown, including tables — the adapter converts anything Discord cannot render. Use code blocks for code.\",\n channels: this.getAllChannels(),\n users: this.getAllUsers(),\n diagnostics: {\n showUsageSummary: false,\n },\n };\n }\n\n async updateMessageRaw(channelId: string, messageId: string, text: string): Promise<void> {\n return discordRetry(async () => {\n const ch = await this.fetchTextChannel(channelId);\n const msg = await ch.messages.fetch(messageId);\n await msg.edit(discordTextPayload(text));\n });\n }\n\n async postReply(channelId: string, replyToId: string, text: string): Promise<string> {\n return discordRetry(async () => {\n const ch = await this.fetchTextChannel(channelId);\n const replyTarget = await ch.messages.fetch(replyToId);\n const sent = await replyTarget.reply(discordTextPayload(text));\n return sent.id;\n });\n }\n\n async postInThread(channelId: string, threadOrMessageId: string, text: string): Promise<string> {\n try {\n const thread = await this.client.channels.fetch(threadOrMessageId);\n if (thread && (thread.isThread() || thread.isTextBased())) {\n return discordRetry(async () => {\n const msg = await (thread as ThreadChannel).send(discordTextPayload(text));\n return msg.id;\n });\n }\n } catch {}\n return this.postReply(channelId, threadOrMessageId, text);\n }\n\n async deleteMessageRaw(channelId: string, messageId: string): Promise<void> {\n try {\n const ch = await this.fetchTextChannel(channelId);\n const msg = await ch.messages.fetch(messageId);\n await msg.delete();\n } catch {}\n }\n\n async sendTyping(channelId: string): Promise<void> {\n try {\n const ch = await this.fetchTextChannel(channelId);\n await ch.sendTyping();\n } catch {}\n }\n\n async uploadFile(channelId: string, filePath: string, title?: string): Promise<void> {\n return discordRetry(async () => {\n const ch = await this.fetchTextChannel(channelId);\n const fileName = title ?? basename(filePath);\n const fileContent = readFileSync(filePath);\n await ch.send({ files: [{ attachment: fileContent, name: fileName }] });\n });\n }\n\n async sendDirectMessage(userId: string, text: string): Promise<string> {\n return discordRetry(async () => {\n const user = await this.client.users.fetch(userId);\n const msg = await user.send(discordTextPayload(text));\n return msg.id;\n });\n }\n\n async postPrivate(_conversationId: string, userId: string, text: string): Promise<void> {\n await this.sendDirectMessage(userId, text);\n }\n\n getAllChannels(): { id: string; name: string }[] {\n return Array.from(this.channels.values());\n }\n\n getAllUsers(): { id: string; userName: string; displayName: string }[] {\n return Array.from(this.users.values());\n }\n\n logToFile(channelId: string, entry: object): void {\n appendChannelLog(this.workspace.office(createOfficeAddress(\"discord\", channelId)), entry);\n }\n\n logBotResponse(channelId: string, text: string, ts: string): void {\n appendBotResponseLog(\n this.workspace.office(createOfficeAddress(\"discord\", channelId)),\n text,\n ts,\n );\n }\n\n async processAttachments(\n channelId: string,\n attachments: ReadonlyMap<string, DiscordAttachmentSource>,\n ): Promise<{ name: string; localPath: string }[]> {\n const items: IncomingAttachment[] = [];\n for (const attachment of attachments.values()) {\n if (!attachment.name) {\n log.logWarning(\"Discord attachment missing name, skipping\", attachment.url);\n continue;\n }\n items.push({\n name: attachment.name,\n download: (destPath) => downloadUrlToFile(attachment.url, destPath),\n });\n }\n\n const office = this.workspace.office(createOfficeAddress(\"discord\", channelId));\n const { saved, failed } = await saveIncomingAttachments(office, items);\n for (const failure of failed) {\n log.logWarning(`Failed to download Discord attachment`, `${failure.name}: ${failure.error}`);\n }\n return saved.map((item) => ({ name: item.original, localPath: item.localPath }));\n }\n\n private getQueue(channelId: string): MessagingEventQueue {\n let queue = this.queues.get(channelId);\n if (!queue) {\n queue = new MessagingEventQueue(\"Discord\");\n this.queues.set(channelId, queue);\n }\n return queue;\n }\n\n private resolveStopTarget(channelId: string, sessionKey: string): string | null {\n const address = createOfficeAddress(\"discord\", channelId);\n const directTarget = resolveStopTarget({ handler: this.handler, address, sessionKey });\n if (directTarget) return directTarget;\n if (sessionKey !== channelId) return null;\n return resolveOnlyScopedStopTarget(this.handler, address);\n }\n\n private loadCachedGuildData(): void {\n for (const guild of this.client.guilds.cache.values()) {\n for (const channel of guild.channels.cache.values()) {\n if (channel.isTextBased() && \"name\" in channel) {\n this.channels.set(channel.id, { id: channel.id, name: channel.name ?? channel.id });\n }\n }\n for (const member of guild.members.cache.values()) {\n this.users.set(member.id, {\n id: member.id,\n userName: member.user.username,\n displayName: member.displayName,\n });\n }\n }\n }\n\n private stripMessagingBotMention(text: string): string {\n if (!this.botUserId) return text;\n return text.replace(new RegExp(`<@!?${this.botUserId}>`, \"g\"), \"\").trim();\n }\n\n private resolveConversationContext(input: {\n channelId: string;\n inGuild: boolean;\n isThread: boolean;\n parentChannelId?: string | null;\n referencedMsgId?: string;\n }): { conversationId: string; threadTs?: string } {\n if (!input.inGuild) {\n return {\n conversationId: input.channelId,\n threadTs: input.referencedMsgId,\n };\n }\n\n if (input.isThread) {\n return {\n conversationId: input.parentChannelId ?? input.channelId,\n threadTs: input.channelId,\n };\n }\n\n return {\n conversationId: input.channelId,\n threadTs: input.referencedMsgId,\n };\n }\n\n private createSlashCommandAdapters(\n interaction: DiscordCommandInteraction,\n commandText: string,\n sessionKey: string,\n conversationId: string,\n ): ConversationContext {\n const isDM = !interaction.inGuild();\n const userId = interaction.user.id;\n const userName = interaction.user.username;\n const platform = this.getMessagingInfo();\n const shouldUseEphemeral = !isDM;\n\n const message = createConversationMessage({\n platform: \"discord\",\n conversationId,\n id: interaction.id,\n sessionKey,\n conversationKind: isDM ? \"direct\" : \"shared\",\n userId,\n userName,\n text: commandText,\n attachments: [],\n });\n\n const respondPrivately = async (text: string, replace = false): Promise<void> => {\n if (interaction.replied || interaction.deferred) {\n if (replace) {\n await interaction.editReply({ content: text });\n } else {\n await interaction.followUp({ content: text, ephemeral: shouldUseEphemeral });\n }\n return;\n }\n\n await interaction.reply({ content: text, ephemeral: shouldUseEphemeral });\n };\n\n const responder: ConversationResponder = {\n respond: async (text: string) => {\n await respondPrivately(text);\n },\n replaceResponse: async (text: string) => {\n await respondPrivately(text, true);\n },\n respondDiagnostic: async (text: string) => {\n await respondPrivately(text);\n },\n respondToolResult: async (result: ChatToolResult) => {\n const duration = (result.durationMs / 1000).toFixed(1);\n const formatted = `${result.isError ? \"Error\" : \"Done\"} ${result.toolName} (${duration}s)\\n${result.result}`;\n await respondPrivately(formatted);\n },\n setTyping: async () => {},\n setWorking: async (working: boolean) => {\n if (working && !interaction.replied && !interaction.deferred) {\n await interaction.deferReply({ ephemeral: shouldUseEphemeral });\n }\n },\n uploadFile: async (filePath: string, title?: string) => {\n await this.uploadFile(conversationId, filePath, title);\n },\n deleteResponse: async () => {},\n };\n\n return { address: message.address, message, responder, platform };\n }\n\n private setupEventHandlers(): void {\n this.client.on(Events.InteractionCreate, (interaction) => {\n void this.intake.run(() => this.handleInteractionCreate(interaction));\n });\n this.client.on(Events.MessageCreate, (message) => {\n void this.intake.run(() => this.handleMessageCreate(message));\n });\n }\n\n private async handleInteractionCreate(interaction: DiscordIncomingInteraction): Promise<void> {\n if (!interaction.isChatInputCommand()) return;\n const manifestEntry = COMMAND_MANIFEST.find(\n (entry) => entry.discord && entry.name === interaction.commandName,\n );\n if (!manifestEntry) return;\n\n const isDM = !interaction.inGuild();\n const { conversationId, threadTs } = this.resolveConversationContext({\n channelId: interaction.channelId,\n inGuild: interaction.inGuild(),\n isThread: interaction.channel?.isThread() ?? false,\n parentChannelId:\n interaction.channel && \"parentId\" in interaction.channel\n ? interaction.channel.parentId\n : null,\n });\n const sessionKey = resolveChatSessionKey({\n conversationId,\n conversationKind: isDM ? \"direct\" : \"shared\",\n messageId: interaction.id,\n persistentTopLevel: true,\n threadTs,\n });\n const commandArg = manifestEntry.arg\n ? interaction.options.getString(manifestEntry.arg.name)?.trim()\n : undefined;\n const commandText = commandArg\n ? `/${interaction.commandName} ${commandArg}`\n : `/${interaction.commandName}`;\n\n this.logToFile(conversationId, {\n date: new Date(interaction.createdTimestamp).toISOString(),\n ts: interaction.id,\n threadTs: threadTs || undefined,\n user: interaction.user.id,\n userName: interaction.user.username,\n text: commandText,\n attachments: [],\n isMessagingBot: false,\n });\n\n const context = this.createSlashCommandAdapters(\n interaction,\n commandText,\n sessionKey,\n conversationId,\n );\n try {\n if (manifestEntry.magicWord) {\n const stopTarget = this.resolveStopTarget(conversationId, sessionKey);\n if (stopTarget) {\n await this.handler.handleStop(\n createOfficeAddress(\"discord\", conversationId),\n stopTarget,\n this,\n );\n await context.responder.respond(\"Stopped the current conversation.\");\n } else {\n await context.responder.respond(formatNothingRunning(\"discord\"));\n }\n return;\n }\n\n const event = createConversationEvent({\n platform: \"discord\",\n type: \"dm\",\n conversationId,\n conversationKind: isDM ? \"direct\" : \"shared\",\n ts: interaction.id,\n thread_ts: threadTs,\n sessionKey,\n user: interaction.user.id,\n text: commandText,\n attachments: [],\n });\n\n await this.handler.handleEvent(event, this, context);\n } catch (err) {\n log.logWarning(\"Discord slash command error\", errorMessage(err));\n if (!interaction.replied && !interaction.deferred) {\n await interaction.reply({\n content: `${interaction.commandName} command failed. Please try again later.`,\n ephemeral: !isDM,\n });\n }\n }\n }\n\n private async handleMessageCreate(msg: DiscordIncomingMessage): Promise<void> {\n if (msg.createdTimestamp < this.startupTime) return;\n if (msg.author.bot) return;\n const isDM = msg.channel.type === ChannelType.DM;\n const isInThread = msg.channel.isThread();\n const referencedMsgId = msg.reference?.messageId;\n const isThreadReply = isInThread || !!referencedMsgId;\n const isMentioned = msg.mentions.users.has(this.botUserId ?? \"\");\n const addressed = isDM || isMentioned || isThreadReply;\n\n const { conversationId, threadTs } = this.resolveConversationContext({\n channelId: msg.channelId,\n inGuild: !isDM,\n isThread: isInThread,\n parentChannelId: \"parentId\" in msg.channel ? msg.channel.parentId : null,\n referencedMsgId,\n });\n const userId = msg.author.id;\n const userName = msg.author.username;\n const msgId = msg.id;\n\n this.users.set(userId, {\n id: userId,\n userName,\n displayName: msg.member?.displayName ?? userName,\n });\n\n if (!this.channels.has(conversationId) && \"name\" in msg.channel) {\n this.channels.set(conversationId, {\n id: conversationId,\n name: msg.channel.name ?? conversationId,\n });\n }\n\n const conversationKind = isDM ? \"direct\" : \"shared\";\n const sessionKey = resolveChatSessionKey({\n conversationId,\n conversationKind,\n messageId: msgId,\n persistentTopLevel: true,\n threadTs,\n });\n\n const cleanedText = this.stripMessagingBotMention(msg.content);\n\n const eventBase = createConversationEvent({\n platform: \"discord\",\n type: isDM ? \"dm\" : \"mention\",\n conversationId,\n conversationKind,\n ts: msgId,\n thread_ts: threadTs,\n sessionKey,\n user: userId,\n userName,\n text: cleanedText,\n }) as DiscordEvent;\n\n await processMessageIntake({\n eventBase,\n addressed,\n magicWord: { addressed, scopeFallback: \"top-level\" },\n busyPolicy: \"queue\",\n logEntryBase: {\n date: msg.createdAt.toISOString(),\n ts: msgId,\n threadTs: !isDM && threadTs ? threadTs : undefined,\n user: userId,\n userName,\n text: cleanedText,\n isMessagingBot: false,\n },\n log: (entry) => this.logToFile(conversationId, entry),\n processAttachments: () => this.processAttachments(conversationId, msg.attachments),\n queueKey: sessionKey,\n enqueue: (queueKey, work) => this.getQueue(queueKey).enqueue(work),\n handler: this.handler,\n bot: this,\n createContext: (event) => createDiscordAdapters(event, this),\n });\n }\n\n private async fetchTextChannel(\n channelId: string,\n ): Promise<TextChannel | DMChannel | NewsChannel | ThreadChannel> {\n const ch = await this.client.channels.fetch(channelId);\n if (!ch || !ch.isTextBased()) {\n throw new Error(`Channel ${channelId} is not a text channel`);\n }\n return ch as TextChannel | DMChannel | NewsChannel | ThreadChannel;\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { GithubActivity, GithubWebhookDelivery } from "./types.js";
2
+ export declare function readGithubActivity(delivery: GithubWebhookDelivery, now?: string): GithubActivity | null;
3
+ //# sourceMappingURL=activity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../../../src/adapters/github/activity.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AA2HxE,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,qBAAqB,EAC/B,GAAG,SAA2B,GAC7B,cAAc,GAAG,IAAI,CAiDvB"}
@@ -0,0 +1,154 @@
1
+ import { Type } from "typebox";
2
+ import { Value } from "typebox/value";
3
+ import { GITHUB_ISSUE_BODY_TS, githubReviewCommentTs } from "./ids.js";
4
+ const User = Type.Object({ login: Type.String(), type: Type.String() });
5
+ const Repository = Type.Object({
6
+ name: Type.String(),
7
+ private: Type.Boolean(),
8
+ owner: Type.Object({ login: Type.String() }),
9
+ });
10
+ const IssueLike = Type.Object({
11
+ number: Type.Number(),
12
+ title: Type.String(),
13
+ body: Type.Union([Type.String(), Type.Null()]),
14
+ user: User,
15
+ created_at: Type.String(),
16
+ pull_request: Type.Optional(Type.Unknown()),
17
+ });
18
+ const Base = { repository: Repository, sender: User };
19
+ const IssuesPayload = Type.Object({
20
+ ...Base,
21
+ action: Type.String(),
22
+ issue: IssueLike,
23
+ assignee: Type.Optional(Type.Union([Type.Object({ login: Type.String() }), Type.Null()])),
24
+ });
25
+ const PullRequestPayload = Type.Object({
26
+ ...Base,
27
+ action: Type.String(),
28
+ pull_request: IssueLike,
29
+ assignee: Type.Optional(Type.Union([Type.Object({ login: Type.String() }), Type.Null()])),
30
+ requested_reviewer: Type.Optional(Type.Object({ login: Type.String() })),
31
+ });
32
+ const IssueCommentPayload = Type.Object({
33
+ ...Base,
34
+ action: Type.String(),
35
+ issue: IssueLike,
36
+ comment: Type.Object({
37
+ id: Type.Number(),
38
+ body: Type.String(),
39
+ user: User,
40
+ created_at: Type.String(),
41
+ }),
42
+ });
43
+ const ReviewCommentPayload = Type.Object({
44
+ ...Base,
45
+ action: Type.String(),
46
+ pull_request: IssueLike,
47
+ comment: Type.Object({
48
+ id: Type.Number(),
49
+ body: Type.String(),
50
+ user: User,
51
+ created_at: Type.String(),
52
+ path: Type.String(),
53
+ line: Type.Union([Type.Number(), Type.Null()]),
54
+ diff_hunk: Type.String(),
55
+ in_reply_to_id: Type.Optional(Type.Number()),
56
+ }),
57
+ });
58
+ function read(schema, payload) {
59
+ return Value.Check(schema, payload) ? payload : null;
60
+ }
61
+ function activityBase(payload, issue, isPr) {
62
+ return {
63
+ repo: {
64
+ owner: payload.repository.owner.login.toLowerCase(),
65
+ repo: payload.repository.name.toLowerCase(),
66
+ private: payload.repository.private,
67
+ },
68
+ number: issue.number,
69
+ isPr,
70
+ sender: { login: payload.sender.login, isBot: payload.sender.type === "Bot" },
71
+ issueTitle: issue.title,
72
+ issueBody: issue.body ?? "",
73
+ };
74
+ }
75
+ function issueText(issue) {
76
+ return `# ${issue.title}\n\n${issue.body ?? ""}`.trim();
77
+ }
78
+ function fromIssueOrPr(payload, issue, isPr, now) {
79
+ const base = activityBase(payload, issue, isPr);
80
+ const bodyTs = { ts: GITHUB_ISSUE_BODY_TS, text: issueText(issue) };
81
+ switch (payload.action) {
82
+ case "opened":
83
+ return { ...base, ...bodyTs, kind: "opened", target: null, createdAt: issue.created_at };
84
+ case "assigned":
85
+ return payload.assignee
86
+ ? { ...base, ...bodyTs, kind: "assigned", target: payload.assignee.login, createdAt: now }
87
+ : null;
88
+ case "review_requested":
89
+ return "requested_reviewer" in payload && payload.requested_reviewer
90
+ ? {
91
+ ...base,
92
+ ...bodyTs,
93
+ kind: "review_requested",
94
+ target: payload.requested_reviewer.login,
95
+ createdAt: now,
96
+ }
97
+ : null;
98
+ default:
99
+ return null;
100
+ }
101
+ }
102
+ export function readGithubActivity(delivery, now = new Date().toISOString()) {
103
+ switch (delivery.event) {
104
+ case "issues": {
105
+ const payload = read(IssuesPayload, delivery.payload);
106
+ return payload
107
+ ? fromIssueOrPr(payload, payload.issue, Boolean(payload.issue.pull_request), now)
108
+ : null;
109
+ }
110
+ case "pull_request": {
111
+ const payload = read(PullRequestPayload, delivery.payload);
112
+ return payload ? fromIssueOrPr(payload, payload.pull_request, true, now) : null;
113
+ }
114
+ case "issue_comment": {
115
+ const payload = read(IssueCommentPayload, delivery.payload);
116
+ if (!payload || payload.action !== "created")
117
+ return null;
118
+ return {
119
+ ...activityBase(payload, payload.issue, Boolean(payload.issue.pull_request)),
120
+ kind: "comment",
121
+ sender: { login: payload.comment.user.login, isBot: payload.comment.user.type === "Bot" },
122
+ target: null,
123
+ ts: String(payload.comment.id),
124
+ text: payload.comment.body,
125
+ createdAt: payload.comment.created_at,
126
+ };
127
+ }
128
+ case "pull_request_review_comment": {
129
+ const payload = read(ReviewCommentPayload, delivery.payload);
130
+ if (!payload || payload.action !== "created")
131
+ return null;
132
+ const { comment } = payload;
133
+ return {
134
+ ...activityBase(payload, payload.pull_request, true),
135
+ kind: "review_comment",
136
+ sender: { login: comment.user.login, isBot: comment.user.type === "Bot" },
137
+ target: null,
138
+ ts: githubReviewCommentTs(comment.id),
139
+ text: comment.body,
140
+ createdAt: comment.created_at,
141
+ review: {
142
+ commentId: comment.id,
143
+ path: comment.path,
144
+ line: comment.line,
145
+ diffHunk: comment.diff_hunk,
146
+ inReplyToId: comment.in_reply_to_id,
147
+ },
148
+ };
149
+ }
150
+ default:
151
+ return null;
152
+ }
153
+ }
154
+ //# sourceMappingURL=activity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity.js","sourceRoot":"","sources":["../../../src/adapters/github/activity.ts"],"names":[],"mappings":"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","sourcesContent":["import { Type, type Static, type TSchema } from \"typebox\";\nimport { Value } from \"typebox/value\";\nimport { GITHUB_ISSUE_BODY_TS, githubReviewCommentTs } from \"./ids.js\";\nimport type { GithubActivity, GithubWebhookDelivery } from \"./types.js\";\n\nconst User = Type.Object({ login: Type.String(), type: Type.String() });\n\nconst Repository = Type.Object({\n name: Type.String(),\n private: Type.Boolean(),\n owner: Type.Object({ login: Type.String() }),\n});\n\nconst IssueLike = Type.Object({\n number: Type.Number(),\n title: Type.String(),\n body: Type.Union([Type.String(), Type.Null()]),\n user: User,\n created_at: Type.String(),\n pull_request: Type.Optional(Type.Unknown()),\n});\n\nconst Base = { repository: Repository, sender: User };\n\nconst IssuesPayload = Type.Object({\n ...Base,\n action: Type.String(),\n issue: IssueLike,\n assignee: Type.Optional(Type.Union([Type.Object({ login: Type.String() }), Type.Null()])),\n});\n\nconst PullRequestPayload = Type.Object({\n ...Base,\n action: Type.String(),\n pull_request: IssueLike,\n assignee: Type.Optional(Type.Union([Type.Object({ login: Type.String() }), Type.Null()])),\n requested_reviewer: Type.Optional(Type.Object({ login: Type.String() })),\n});\n\nconst IssueCommentPayload = Type.Object({\n ...Base,\n action: Type.String(),\n issue: IssueLike,\n comment: Type.Object({\n id: Type.Number(),\n body: Type.String(),\n user: User,\n created_at: Type.String(),\n }),\n});\n\nconst ReviewCommentPayload = Type.Object({\n ...Base,\n action: Type.String(),\n pull_request: IssueLike,\n comment: Type.Object({\n id: Type.Number(),\n body: Type.String(),\n user: User,\n created_at: Type.String(),\n path: Type.String(),\n line: Type.Union([Type.Number(), Type.Null()]),\n diff_hunk: Type.String(),\n in_reply_to_id: Type.Optional(Type.Number()),\n }),\n});\n\nfunction read<T extends TSchema>(schema: T, payload: unknown): Static<T> | null {\n return Value.Check(schema, payload) ? payload : null;\n}\n\ntype IssueLikeValue = Static<typeof IssueLike>;\n\nfunction activityBase(\n payload: { repository: Static<typeof Repository>; sender: Static<typeof User> },\n issue: IssueLikeValue,\n isPr: boolean,\n): Omit<GithubActivity, \"kind\" | \"target\" | \"ts\" | \"text\" | \"createdAt\"> {\n return {\n repo: {\n owner: payload.repository.owner.login.toLowerCase(),\n repo: payload.repository.name.toLowerCase(),\n private: payload.repository.private,\n },\n number: issue.number,\n isPr,\n sender: { login: payload.sender.login, isBot: payload.sender.type === \"Bot\" },\n issueTitle: issue.title,\n issueBody: issue.body ?? \"\",\n };\n}\n\nfunction issueText(issue: IssueLikeValue): string {\n return `# ${issue.title}\\n\\n${issue.body ?? \"\"}`.trim();\n}\n\nfunction fromIssueOrPr(\n payload: Static<typeof IssuesPayload> | Static<typeof PullRequestPayload>,\n issue: IssueLikeValue,\n isPr: boolean,\n now: string,\n): GithubActivity | null {\n const base = activityBase(payload, issue, isPr);\n const bodyTs = { ts: GITHUB_ISSUE_BODY_TS, text: issueText(issue) };\n switch (payload.action) {\n case \"opened\":\n return { ...base, ...bodyTs, kind: \"opened\", target: null, createdAt: issue.created_at };\n case \"assigned\":\n return payload.assignee\n ? { ...base, ...bodyTs, kind: \"assigned\", target: payload.assignee.login, createdAt: now }\n : null;\n case \"review_requested\":\n return \"requested_reviewer\" in payload && payload.requested_reviewer\n ? {\n ...base,\n ...bodyTs,\n kind: \"review_requested\",\n target: payload.requested_reviewer.login,\n createdAt: now,\n }\n : null;\n default:\n return null;\n }\n}\n\nexport function readGithubActivity(\n delivery: GithubWebhookDelivery,\n now = new Date().toISOString(),\n): GithubActivity | null {\n switch (delivery.event) {\n case \"issues\": {\n const payload = read(IssuesPayload, delivery.payload);\n return payload\n ? fromIssueOrPr(payload, payload.issue, Boolean(payload.issue.pull_request), now)\n : null;\n }\n case \"pull_request\": {\n const payload = read(PullRequestPayload, delivery.payload);\n return payload ? fromIssueOrPr(payload, payload.pull_request, true, now) : null;\n }\n case \"issue_comment\": {\n const payload = read(IssueCommentPayload, delivery.payload);\n if (!payload || payload.action !== \"created\") return null;\n return {\n ...activityBase(payload, payload.issue, Boolean(payload.issue.pull_request)),\n kind: \"comment\",\n sender: { login: payload.comment.user.login, isBot: payload.comment.user.type === \"Bot\" },\n target: null,\n ts: String(payload.comment.id),\n text: payload.comment.body,\n createdAt: payload.comment.created_at,\n };\n }\n case \"pull_request_review_comment\": {\n const payload = read(ReviewCommentPayload, delivery.payload);\n if (!payload || payload.action !== \"created\") return null;\n const { comment } = payload;\n return {\n ...activityBase(payload, payload.pull_request, true),\n kind: \"review_comment\",\n sender: { login: comment.user.login, isBot: comment.user.type === \"Bot\" },\n target: null,\n ts: githubReviewCommentTs(comment.id),\n text: comment.body,\n createdAt: comment.created_at,\n review: {\n commentId: comment.id,\n path: comment.path,\n line: comment.line,\n diffHunk: comment.diff_hunk,\n inReplyToId: comment.in_reply_to_id,\n },\n };\n }\n default:\n return null;\n }\n}\n"]}
@@ -1,26 +1,21 @@
1
1
  import type { MessagingBot, MessagingEventHandler, MessagingInfo, ConversationEvent } from "../../types.js";
2
2
  import { GithubOps } from "./github-ops.js";
3
3
  import type { GithubConversationRef } from "../../office/types.js";
4
- import type { GithubApi, GithubBotConfig, GithubSyncState } from "./types.js";
4
+ import type { GithubAgentIdentity, GithubApi, GithubBotConfig, GithubCapability, GithubWebhookDelivery } from "./types.js";
5
5
  export declare const formatGithubContinuation: (partNum: number) => string;
6
6
  export declare class GithubMessagingBot implements MessagingBot {
7
7
  private readonly client;
8
8
  private readonly handler;
9
9
  private readonly config;
10
10
  readonly ops: GithubOps;
11
- private appSlug;
12
- private botEmail;
13
- private watchedRepos;
11
+ private identity;
14
12
  private queues;
15
- private repoState;
16
13
  private permissionCache;
14
+ private bodyTriggers;
17
15
  private stopped;
18
- private stopping;
19
- private activePoll;
20
- private pollPending;
21
- private pollIntervalTimer;
22
- private requestPollTimer;
23
16
  constructor(handler: MessagingEventHandler, config: GithubBotConfig, client?: GithubApi);
17
+ get capabilities(): ReadonlySet<GithubCapability>;
18
+ get agentIdentity(): GithubAgentIdentity | undefined;
24
19
  start(): Promise<void>;
25
20
  stop(): Promise<void>;
26
21
  postMessage(channel: string, text: string): Promise<string>;
@@ -33,14 +28,11 @@ export declare class GithubMessagingBot implements MessagingBot {
33
28
  logToFile(conversationId: string, entry: object): void;
34
29
  logBotResponse(conversationId: string, text: string, ts: string): void;
35
30
  private getQueue;
36
- requestPoll(debounceMs?: number): void;
37
- poll(): Promise<void>;
38
- private pollWatchedRepos;
39
- private pollRepo;
40
- private advanceFeed;
41
- private loadSyncState;
42
- syncStateSnapshot(): GithubSyncState;
43
- private persistSyncState;
31
+ receive(delivery: GithubWebhookDelivery): Promise<void>;
32
+ private isAgent;
33
+ private triggerOf;
34
+ private claimBodyTrigger;
35
+ private handleActivity;
44
36
  private mentionPattern;
45
37
  private isMentioned;
46
38
  private stripMention;
@@ -48,10 +40,8 @@ export declare class GithubMessagingBot implements MessagingBot {
48
40
  private isParticipating;
49
41
  private hasTriggerPermission;
50
42
  private handleIncoming;
51
- private prepareConversation;
52
43
  private formatReviewMessage;
53
44
  private reviewThreadContext;
54
45
  private logIssueContext;
55
- private ensureRepoClone;
56
46
  }
57
47
  //# sourceMappingURL=bot.d.ts.map