cli-jaw 2.2.9 → 2.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/README.ja.md +15 -0
  2. package/README.ko.md +15 -0
  3. package/README.md +19 -4
  4. package/dist/bin/cli-jaw.js +5 -1
  5. package/dist/bin/cli-jaw.js.map +1 -1
  6. package/dist/bin/commands/doctor.js +66 -1
  7. package/dist/bin/commands/doctor.js.map +1 -1
  8. package/dist/bin/commands/init.js +107 -8
  9. package/dist/bin/commands/init.js.map +1 -1
  10. package/dist/bin/commands/slack.js +190 -0
  11. package/dist/bin/commands/slack.js.map +1 -0
  12. package/dist/lib/upload.js +5 -1
  13. package/dist/lib/upload.js.map +1 -1
  14. package/dist/server.js +1 -0
  15. package/dist/server.js.map +1 -1
  16. package/dist/src/agent/alert-escalation.js +1 -1
  17. package/dist/src/agent/alert-escalation.js.map +1 -1
  18. package/dist/src/agent/codex-app-catalog.js +57 -0
  19. package/dist/src/agent/codex-app-catalog.js.map +1 -0
  20. package/dist/src/agent/codex-app-client.js +89 -7
  21. package/dist/src/agent/codex-app-client.js.map +1 -1
  22. package/dist/src/agent/pi-rpc-verdict.js +22 -0
  23. package/dist/src/agent/pi-rpc-verdict.js.map +1 -0
  24. package/dist/src/agent/pi-runtime.js +240 -0
  25. package/dist/src/agent/pi-runtime.js.map +1 -1
  26. package/dist/src/agent/runtime-pool.js +445 -0
  27. package/dist/src/agent/runtime-pool.js.map +1 -0
  28. package/dist/src/agent/spawn.js +395 -240
  29. package/dist/src/agent/spawn.js.map +1 -1
  30. package/dist/src/cli/command-context.js +5 -2
  31. package/dist/src/cli/command-context.js.map +1 -1
  32. package/dist/src/cli/commands.js +43 -39
  33. package/dist/src/cli/commands.js.map +1 -1
  34. package/dist/src/cli/handlers-runtime.js +15 -7
  35. package/dist/src/cli/handlers-runtime.js.map +1 -1
  36. package/dist/src/cli/handlers-search.js +1 -1
  37. package/dist/src/cli/handlers-search.js.map +1 -1
  38. package/dist/src/cli/handlers-skill-invoke.js +1 -1
  39. package/dist/src/cli/handlers-skill-invoke.js.map +1 -1
  40. package/dist/src/cli/handlers-workflows.js +1 -1
  41. package/dist/src/cli/handlers-workflows.js.map +1 -1
  42. package/dist/src/cli/handlers.js +1 -1
  43. package/dist/src/cli/handlers.js.map +1 -1
  44. package/dist/src/cli/opencodex-models.js +40 -7
  45. package/dist/src/cli/opencodex-models.js.map +1 -1
  46. package/dist/src/cli/registry-live.js +6 -5
  47. package/dist/src/cli/registry-live.js.map +1 -1
  48. package/dist/src/command-contract/catalog.js +4 -0
  49. package/dist/src/command-contract/catalog.js.map +1 -1
  50. package/dist/src/core/config.js +69 -4
  51. package/dist/src/core/config.js.map +1 -1
  52. package/dist/src/core/runtime-settings.js +17 -0
  53. package/dist/src/core/runtime-settings.js.map +1 -1
  54. package/dist/src/core/settings-merge.js +1 -1
  55. package/dist/src/core/settings-merge.js.map +1 -1
  56. package/dist/src/discord/bot.js +29 -14
  57. package/dist/src/discord/bot.js.map +1 -1
  58. package/dist/src/discord/commands.js +5 -4
  59. package/dist/src/discord/commands.js.map +1 -1
  60. package/dist/src/discord/discord-file.js +8 -2
  61. package/dist/src/discord/discord-file.js.map +1 -1
  62. package/dist/src/discord/forwarder.js +17 -19
  63. package/dist/src/discord/forwarder.js.map +1 -1
  64. package/dist/src/discord/send-only-client.js +9 -1
  65. package/dist/src/discord/send-only-client.js.map +1 -1
  66. package/dist/src/manager/dashboard-service.js +38 -1
  67. package/dist/src/manager/dashboard-service.js.map +1 -1
  68. package/dist/src/manager/telegram-hub/hub-bot.js +47 -29
  69. package/dist/src/manager/telegram-hub/hub-bot.js.map +1 -1
  70. package/dist/src/messaging/channel-health.js +32 -0
  71. package/dist/src/messaging/channel-health.js.map +1 -1
  72. package/dist/src/messaging/chunk.js +376 -0
  73. package/dist/src/messaging/chunk.js.map +1 -0
  74. package/dist/src/messaging/dedupe.js +104 -0
  75. package/dist/src/messaging/dedupe.js.map +1 -0
  76. package/dist/src/messaging/fold.js +210 -0
  77. package/dist/src/messaging/fold.js.map +1 -0
  78. package/dist/src/messaging/redact.js +577 -0
  79. package/dist/src/messaging/redact.js.map +1 -0
  80. package/dist/src/messaging/retry.js +76 -0
  81. package/dist/src/messaging/retry.js.map +1 -0
  82. package/dist/src/messaging/runtime.js +6 -3
  83. package/dist/src/messaging/runtime.js.map +1 -1
  84. package/dist/src/messaging/send.js +45 -15
  85. package/dist/src/messaging/send.js.map +1 -1
  86. package/dist/src/messaging/slack-target.js +50 -0
  87. package/dist/src/messaging/slack-target.js.map +1 -0
  88. package/dist/src/messaging/types.js.map +1 -1
  89. package/dist/src/orchestrator/pipeline.js +4 -4
  90. package/dist/src/orchestrator/pipeline.js.map +1 -1
  91. package/dist/src/routes/command.js +11 -7
  92. package/dist/src/routes/command.js.map +1 -1
  93. package/dist/src/routes/messaging.js +28 -12
  94. package/dist/src/routes/messaging.js.map +1 -1
  95. package/dist/src/routes/settings.js +22 -6
  96. package/dist/src/routes/settings.js.map +1 -1
  97. package/dist/src/slack/api.js +116 -0
  98. package/dist/src/slack/api.js.map +1 -0
  99. package/dist/src/slack/bot.js +262 -0
  100. package/dist/src/slack/bot.js.map +1 -0
  101. package/dist/src/slack/commands.js +98 -0
  102. package/dist/src/slack/commands.js.map +1 -0
  103. package/dist/src/slack/events.js +116 -0
  104. package/dist/src/slack/events.js.map +1 -0
  105. package/dist/src/slack/format.js +58 -0
  106. package/dist/src/slack/format.js.map +1 -0
  107. package/dist/src/slack/forwarder.js +57 -0
  108. package/dist/src/slack/forwarder.js.map +1 -0
  109. package/dist/src/slack/manifest.js +84 -0
  110. package/dist/src/slack/manifest.js.map +1 -0
  111. package/dist/src/slack/register.js +13 -0
  112. package/dist/src/slack/register.js.map +1 -0
  113. package/dist/src/slack/send-handler.js +41 -0
  114. package/dist/src/slack/send-handler.js.map +1 -0
  115. package/dist/src/slack/send-only-client.js +46 -0
  116. package/dist/src/slack/send-only-client.js.map +1 -0
  117. package/dist/src/slack/slack-file.js +72 -0
  118. package/dist/src/slack/slack-file.js.map +1 -0
  119. package/dist/src/slack/socket.js +341 -0
  120. package/dist/src/slack/socket.js.map +1 -0
  121. package/dist/src/telegram/bot.js +117 -37
  122. package/dist/src/telegram/bot.js.map +1 -1
  123. package/dist/src/telegram/elicitation-buttons.js +7 -2
  124. package/dist/src/telegram/elicitation-buttons.js.map +1 -1
  125. package/dist/src/telegram/forwarder.js +15 -7
  126. package/dist/src/telegram/forwarder.js.map +1 -1
  127. package/dist/src/telegram/rich-message.js +209 -24
  128. package/dist/src/telegram/rich-message.js.map +1 -1
  129. package/dist/src/telegram/telegram-file.js +35 -4
  130. package/dist/src/telegram/telegram-file.js.map +1 -1
  131. package/dist/src/telegram/voice.js +4 -3
  132. package/dist/src/telegram/voice.js.map +1 -1
  133. package/package.json +7 -1
  134. package/public/assets/providers/slack.svg +1 -0
  135. package/public/dist/assets/ChannelsDiscord-D9FLnZso.js +1 -0
  136. package/public/dist/assets/ChannelsSlack-ybvupgdK.js +1 -0
  137. package/public/dist/assets/ChannelsTelegram-BOCOPrBc.js +1 -0
  138. package/public/dist/assets/HealthBadge-megTlF4n.js +1 -0
  139. package/public/dist/assets/TransportStatusChips-CjEySMis.js +1 -0
  140. package/public/dist/assets/app-BGIAy4he.js +55 -0
  141. package/public/dist/assets/{bgtask-badge-CdBqBy1L.js → bgtask-badge-DXca8E7c.js} +1 -1
  142. package/public/dist/assets/bgtask-badge-GRSiNILQ.js +1 -0
  143. package/public/dist/assets/{employees-C8qufeJl.js → employees-BL4qMxJj.js} +1 -1
  144. package/public/dist/assets/iframe-renderer-BUSk0Rw9.js +1 -0
  145. package/public/dist/assets/{iframe-renderer-CZ67aeTO.js → iframe-renderer-DUI0LYBy.js} +2 -2
  146. package/public/dist/assets/{manager-CLXT60M5.js → manager-B-gpf-3j.js} +3 -3
  147. package/public/dist/assets/{memory-lWramLVw.js → memory-B_Y0L0KD.js} +1 -1
  148. package/public/dist/assets/memory-CX6YahTc.js +1 -0
  149. package/public/dist/assets/message-history-Det7u76S.js +1 -0
  150. package/public/dist/assets/{message-history-2NUN3UxM.js → message-history-Dl8dJzez.js} +1 -1
  151. package/public/dist/assets/{provider-icons-stsNmQKx.js → provider-icons-VDfahiUp.js} +3 -2
  152. package/public/dist/assets/{render-CsF-ojLe.js → render-BI1aqKoc.js} +1 -1
  153. package/public/dist/assets/{settings-BMLowRCh.js → settings-B0Sj4sUH.js} +1 -1
  154. package/public/dist/assets/settings-C7NutP6X.js +1 -0
  155. package/public/dist/assets/settings-core-CyX-px6_.js +100 -0
  156. package/public/dist/assets/settings-core-DVpFmrhY.js +1 -0
  157. package/public/dist/assets/{sidebar-gKjYLv49.js → sidebar-DOR9fTgN.js} +3 -3
  158. package/public/dist/assets/skills-BWhKreQ2.js +1 -0
  159. package/public/dist/assets/{skills-CKTbomdm.js → skills-wt0fkV9Y.js} +1 -1
  160. package/public/dist/assets/slash-commands-BZbqTg3v.js +20 -0
  161. package/public/dist/assets/slash-commands-Di4NDA4w.js +1 -0
  162. package/public/dist/assets/{trace-drawer-C3G4mmB1.js → trace-drawer-kMYzaVFW.js} +1 -1
  163. package/public/dist/assets/ui-BghexWrB.js +1 -0
  164. package/public/dist/assets/{ui-CVVC_flX.js → ui-D4D5HUfo.js} +1 -1
  165. package/public/dist/index.html +62 -1
  166. package/public/dist/manager/index.html +1 -1
  167. package/public/index.html +61 -0
  168. package/public/js/features/command-info.ts +1 -0
  169. package/public/js/features/help-content.ts +8 -0
  170. package/public/js/features/settings-channel.ts +5 -1
  171. package/public/js/features/settings-core.ts +2 -0
  172. package/public/js/features/settings-slack.ts +74 -0
  173. package/public/js/features/settings-types.ts +5 -1
  174. package/public/js/features/settings.ts +1 -0
  175. package/public/js/features/transport-status-row.ts +15 -3
  176. package/public/js/main.ts +19 -0
  177. package/public/js/provider-icons.ts +4 -1
  178. package/public/js/ws.ts +1 -1
  179. package/public/locales/en.json +21 -0
  180. package/public/locales/ja.json +21 -0
  181. package/public/locales/ko.json +21 -0
  182. package/public/locales/zh.json +21 -0
  183. package/public/manager/src/settings/SettingsShell.tsx +1 -0
  184. package/public/manager/src/settings/SettingsSidebar.tsx +1 -0
  185. package/public/manager/src/settings/pages/ChannelsSlack.tsx +323 -0
  186. package/public/manager/src/settings/pages/components/ActiveChannelToggle.tsx +2 -1
  187. package/public/manager/src/settings/pages/components/TransportStatusChips.tsx +13 -4
  188. package/public/manager/src/settings/types.ts +1 -0
  189. package/scripts/bundle-sidecar.sh +13 -4
  190. package/scripts/check-redaction-sinks.mjs +276 -0
  191. package/scripts/check-sidecar-prune-safety.mjs +167 -0
  192. package/scripts/pi-rpc-probe.mts +361 -0
  193. package/scripts/pick-gyp-python.sh +61 -0
  194. package/scripts/release-gates.mjs +97 -0
  195. package/scripts/release-preview.sh +8 -1
  196. package/scripts/release.sh +13 -2
  197. package/scripts/sync-electron-version.cjs +93 -0
  198. package/public/dist/assets/ChannelsDiscord-Bt1_rtNC.js +0 -1
  199. package/public/dist/assets/ChannelsTelegram-BLV0m1oq.js +0 -1
  200. package/public/dist/assets/TransportStatusChips-Bld0yXi7.js +0 -1
  201. package/public/dist/assets/app-iSJhsP20.js +0 -55
  202. package/public/dist/assets/bgtask-badge-CSkSsoB6.js +0 -1
  203. package/public/dist/assets/iframe-renderer-DXdo0YXN.js +0 -1
  204. package/public/dist/assets/memory-DeKUlD2M.js +0 -1
  205. package/public/dist/assets/message-history-CWTQ2woA.js +0 -1
  206. package/public/dist/assets/settings-CDjs7hTT.js +0 -1
  207. package/public/dist/assets/settings-core-Cs_oq-b3.js +0 -99
  208. package/public/dist/assets/settings-core-D-TOh1a6.js +0 -1
  209. package/public/dist/assets/skills-GuIfNASs.js +0 -1
  210. package/public/dist/assets/slash-commands-BtZa093n.js +0 -20
  211. package/public/dist/assets/slash-commands-DGJKfpMT.js +0 -1
  212. package/public/dist/assets/ui-DJg5Q_NJ.js +0 -1
  213. /package/public/dist/assets/{DashboardMeta-B7CVqXcU.js → DashboardMeta-DennaaA_.js} +0 -0
  214. /package/public/dist/assets/{Display-BF-rACK6.js → Display-hGuSn_W5.js} +0 -0
  215. /package/public/dist/assets/{Employees-D3hnciP0.js → Employees-B5YXk5ma.js} +0 -0
  216. /package/public/dist/assets/{Heartbeat-D4Pn5O3O.js → Heartbeat-vDGhPfct.js} +0 -0
  217. /package/public/dist/assets/{Mcp-SfytKWGX.js → Mcp-BHWnJ6SP.js} +0 -0
  218. /package/public/dist/assets/{Memory-DNxBOQ7N.js → Memory-B_UZ-iCA.js} +0 -0
  219. /package/public/dist/assets/{ModelProvider-CXwtlG7l.js → ModelProvider-CgUvs6pE.js} +0 -0
  220. /package/public/dist/assets/{Network-DISUhige.js → Network-AWpSkALD.js} +0 -0
  221. /package/public/dist/assets/{Profile-B8yBO3Ju.js → Profile-DnIE2ios.js} +0 -0
  222. /package/public/dist/assets/{Prompts-5lNQ5qOm.js → Prompts-B9aKLall.js} +0 -0
  223. /package/public/dist/assets/{SpeechKeys-BepaIHBa.js → SpeechKeys-K4Be_o7z.js} +0 -0
  224. /package/public/dist/assets/{TelegramHub--DNjRAwW.js → TelegramHub-CFwSkzHP.js} +0 -0
  225. /package/public/dist/assets/{TerminalPanel-DQovYfwz.js → TerminalPanel-CdlFZHAK.js} +0 -0
@@ -0,0 +1,577 @@
1
+ // ─── Channel Credential Redaction ────────────────────
2
+ // One masker for every channel. Error strings cross channel boundaries — the
3
+ // unified send path collects results from all three — so per-channel maskers
4
+ // leak at the seams.
5
+ //
6
+ // Three sinks matter, in order of severity:
7
+ // 1. the chat room itself (Telegram/Discord reply text)
8
+ // 2. HTTP response bodies (`{ ok: false, error }` reaches /api callers)
9
+ // 3. log files
10
+ //
11
+ // Telegram is the sharp edge: its Bot API puts the token in the URL PATH
12
+ // (`https://api.telegram.org/bot<TOKEN>/method`), so the path is itself a
13
+ // credential, exactly like Slack's `upload_url`.
14
+ /** A language-tag-free guard: keep host, drop everything that identifies it. */
15
+ import { canonicalize } from './fold.js';
16
+ const REDACTED = '...redacted';
17
+ /**
18
+ * Characters copied while assembling redacted output, since the last reset.
19
+ *
20
+ * Exists for the complexity regression tests. Those used to assert a wall-clock
21
+ * budget, which measures the runner rather than the algorithm: the same fixture
22
+ * took 155 ms on a developer laptop and 777 ms on a CI runner, and running the
23
+ * suite in parallel moved it again. A counter of the work actually performed is
24
+ * the same number on every machine, so the test can state the real invariant —
25
+ * copy work stays proportional to input length — instead of a machine-specific
26
+ * millisecond bound.
27
+ *
28
+ * Incrementing one integer per emitted piece costs nothing measurable and is
29
+ * never read in production.
30
+ */
31
+ let charsCopied = 0;
32
+ /** Read the copy-work counter; test-only introspection. */
33
+ export function redactionCopyWork() {
34
+ return charsCopied;
35
+ }
36
+ /** Reset the copy-work counter; test-only introspection. */
37
+ export function resetRedactionCopyWork() {
38
+ charsCopied = 0;
39
+ }
40
+ /**
41
+ * Mask a Telegram bot token embedded in a URL path, whatever the host.
42
+ *
43
+ * Host and credential are separate concerns. A lookalike host such as
44
+ * `evil.telegram.org.attacker.dev` is deliberately left readable — hiding it
45
+ * would conceal a suspicious destination — but a real token sitting in its
46
+ * path must still go. Anchoring on the literal `/bot` rather than a word
47
+ * boundary matters: in `.../bot123456:SECRET` the character before the digits
48
+ * is `t`, so `\b` never matches.
49
+ */
50
+ function stripBotTokenFromPath(raw) {
51
+ // The separators may themselves be percent-encoded: a URL that travelled
52
+ // through a query parameter arrives as https%3A%2F%2F…%2Fbot<id>%3A<secret>.
53
+ return raw.replace(/(\/|%2F)(?:file(?:\/|%2F))?bots?(\d{6,12})(?::|%3A)[A-Za-z0-9_-]+/gi, (_m, slash, id) => `${slash}bot${id}:${REDACTED}`);
54
+ }
55
+ /**
56
+ * A `bot` prefix is proof of provenance: nothing but a Telegram credential is
57
+ * spelled `bot<digits>:<run>`. Because provenance is established, the secret's
58
+ * shape is not consulted — requiring a character mix would leak an
59
+ * all-uppercase token in full.
60
+ *
61
+ * The prefix has to stand alone. Excluding only a preceding letter was not
62
+ * enough — `my_bot123…` and `v2bot123…` are identifiers, not credentials — so
63
+ * the guard covers every identifier character.
64
+ */
65
+ const PREFIXED_TOKEN = new RegExp(`(?<![A-Za-z0-9_])bot(\\d{6,12})(?::|\uFF1A)[A-Za-z0-9_-]{20,}`, 'gi');
66
+ /**
67
+ * A Discord token's first segment is the bot's user id in base64url, so it
68
+ * decodes to a run of digits. An artifact id or checksum of the same dotted
69
+ * shape does not, which is what keeps ordinary diagnostics readable.
70
+ */
71
+ function decodesToSnowflake(segment) {
72
+ // The regex has no way to know where the token starts, so ordinary text
73
+ // running into it ("logabcdefMTIz…") is captured as part of the first
74
+ // segment. Try the trailing windows: a real header is 24 characters for an
75
+ // 18-digit id, but ids vary in length, so scan a small range from the end.
76
+ //
77
+ // Padding needs no special handling here — Node's base64 decoder tolerates
78
+ // it, so a `…Njc4==` segment still yields the id. What DOES matter is that
79
+ // the pattern above accepts the `=` characters in the first place; without
80
+ // that the whole match never forms.
81
+ for (let width = 20; width <= Math.min(32, segment.length); width += 1) {
82
+ const candidate = segment.slice(segment.length - width);
83
+ try {
84
+ const decoded = Buffer.from(candidate.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf8');
85
+ if (/^\d{15,}$/.test(decoded))
86
+ return true;
87
+ }
88
+ catch {
89
+ // Not valid base64 at this width; try the next.
90
+ }
91
+ }
92
+ return false;
93
+ }
94
+ /**
95
+ * Bot tokens anywhere in a string.
96
+ *
97
+ * Detection is anchored on the SECRET, not on what precedes it. Every earlier
98
+ * attempt anchored on the left — a word boundary, then a delimiter set, then a
99
+ * lookbehind — and each one was defeated by a spelling nobody had listed:
100
+ * `Bot`, `BOT`, a bare `/`, an ordinary letter, `%3A`. What actually identifies
101
+ * a Telegram credential is its shape: a bot id, a separator, and a long
102
+ * high-entropy run. Match that, and the left context stops mattering.
103
+ *
104
+ * Separators cover the literal colon, its percent-encoding at any nesting
105
+ * depth (`%3A`, `%253A`, …), the fullwidth colon that NFKC folds to `:`, and
106
+ * an intervening line break — a token wrapped across lines in a log is still a
107
+ * token once someone joins it back up.
108
+ */
109
+ // `%3A` encoded once is `%253A`, twice is `%25253A`: each round replaces the
110
+ // leading `%` with `%25`, so the nesting shows up as repeated `25` AFTER the
111
+ // first percent, not as repeated `%25` before it.
112
+ const TOKEN_SEPARATOR = '(?::|\uFF1A|%(?:25)*3A)';
113
+ // Zero-width formatting characters can sit between the id and the separator.
114
+ // They are invisible in a log yet vanish on paste, so a token split by one is
115
+ // still a working token.
116
+ const INVISIBLE = '[\\s\\u200B-\\u200D\\uFEFF]*';
117
+ // The id runs to the END of a digit run: with a longer run, take its last 6-12
118
+ // digits rather than refusing to match. A lookbehind that demands a non-digit
119
+ // lets `9` + a 12-digit id slip past as a 13-digit run.
120
+ const TOKEN_ANYWHERE = new RegExp(`(\\d{6,12})${INVISIBLE}${TOKEN_SEPARATOR}${INVISIBLE}([A-Za-z0-9_-]{30,})`, 'gi');
121
+ /**
122
+ * Provenance, not shape, decides how aggressive masking may be.
123
+ *
124
+ * Telegram documents its token only as opaque, so a rule like "the secret
125
+ * mixes upper case, lower case and digits" is an unwritten assumption: an
126
+ * all-uppercase token would ship in full. Every path where the surrounding
127
+ * text PROVES a credential — a Bot API URL, a `bot` prefix, an Authorization
128
+ * header — therefore masks on structure alone, without consulting the shape.
129
+ *
130
+ * The character mix survives in exactly one place: a bare `<digits>:<run>`
131
+ * pair in arbitrary prose, where there is no provenance and a build id or a
132
+ * checksum would otherwise be blanked. A false negative there costs nothing,
133
+ * because the same token inside any real Telegram context is caught above.
134
+ */
135
+ function mixesCharacterClasses(candidate) {
136
+ return /[A-Z]/.test(candidate) && /[a-z]/.test(candidate) && /\d/.test(candidate);
137
+ }
138
+ /**
139
+ * Find secrets in the CANONICAL form of the text, then remove those literal
140
+ * runs from the original.
141
+ *
142
+ * This is what stops the spelling arms race. A pattern matched against the raw
143
+ * string has to anticipate every encoding and every invisible character; a
144
+ * pattern matched against the folded string sees one shape. The secret run
145
+ * survives folding intact (its characters are base64url, which percent-decoding
146
+ * and control-stripping leave alone), so it can be located in the original by
147
+ * substring and blanked there.
148
+ */
149
+ function stripSecretsFoundInCanonicalForm(input) {
150
+ // Scan the folded form ALWAYS, not only when folding changed something. A
151
+ // string that is already canonical still needs this pass: the raw matchers
152
+ // downstream stop at the first prefixed token, so a secret repeated later
153
+ // in the same error string survived.
154
+ const folded = canonicalize(input);
155
+ // The fold gave up with escapes still unresolved. Something is nested
156
+ // deeply enough to outrun the budget, which nothing legitimate does, so
157
+ // blank whatever could be hiding a credential rather than pass the text
158
+ // through unread.
159
+ //
160
+ // Blanking only the runs that CONTAIN an escape is not enough: the fold
161
+ // also removes control characters, so an encoded prefix and its secret can
162
+ // sit on either side of a newline. The bot id is public, so leaving the
163
+ // secret half behind still hands over the credential. Any long run that
164
+ // either carries an escape or could BE a secret goes.
165
+ if (folded.exhausted) {
166
+ // Scope it: the escaped run itself, and any credential-shaped run near
167
+ // enough to be its other half. Blanking every long alphanumeric run
168
+ // erased ordinary identifiers — `release-build-20260802-darwin-arm64`
169
+ // among them — which hands an attacker a way to strip diagnostics by
170
+ // burying one deeply encoded string in the same message.
171
+ return input.replace(/\S{20,}/g, (run, offset) => {
172
+ if (/%|\\u|&#/.test(run))
173
+ return REDACTED;
174
+ // A Telegram secret is an unbroken base64url run. An ordinary long
175
+ // identifier is punctuated — `release-build-20260802-darwin-arm64`
176
+ // has hyphens — so requiring no separator keeps diagnostics while
177
+ // still covering the shape a credential takes.
178
+ if (!/^[A-Za-z0-9]{20,}$/.test(run))
179
+ return run;
180
+ return hasEscapeWithin(input, offset, run.length) ? REDACTED : run;
181
+ });
182
+ }
183
+ // Collect the SOURCE ranges each match came from. Deleting the matched
184
+ // literal instead fails in both directions: an escape spliced inside the
185
+ // secret means the literal is not in the source at all, and a run that
186
+ // legitimately appears elsewhere gets destroyed with it.
187
+ const ranges = [];
188
+ // The folded coordinates of each hit, kept alongside. Recovering them
189
+ // afterwards meant scanning the whole map per range, which is the other
190
+ // half of the quadratic cost.
191
+ const foldedRanges = [];
192
+ const record = (start, stop) => {
193
+ if (start >= stop)
194
+ return;
195
+ const from = folded.origin[start];
196
+ const to = folded.end[stop - 1];
197
+ if (from === undefined || to === undefined)
198
+ return;
199
+ ranges.push({ from, to });
200
+ foldedRanges.push({ foldedFrom: start, foldedTo: stop });
201
+ };
202
+ for (const match of folded.text.matchAll(PREFIXED_TOKEN)) {
203
+ const at = match.index ?? 0;
204
+ const separator = match[0].search(/[:\uFF1A]/);
205
+ if (separator < 0)
206
+ continue;
207
+ record(at + separator + 1, at + match[0].length);
208
+ }
209
+ for (const match of folded.text.matchAll(CANONICAL_URL_TOKEN)) {
210
+ const at = match.index ?? 0;
211
+ const secret = match[2];
212
+ if (!secret)
213
+ continue;
214
+ record(at + match[0].length - secret.length, at + match[0].length);
215
+ }
216
+ if (ranges.length === 0)
217
+ return input;
218
+ // A credential proven once in a message is a credential everywhere in it.
219
+ // The repeat search runs over the FOLDED text, so a second mention wrapped
220
+ // in a different encoding is caught too, and each hit is carried back by
221
+ // the same offset map.
222
+ //
223
+ // Unlike the first pass this ignores whether the run is glued to
224
+ // surrounding characters. The earlier "standalone only" rule existed to
225
+ // protect unrelated values that happened to share the run, but once the
226
+ // very same run has been proven a credential in this message, treating a
227
+ // later copy as coincidence is the wrong way to be wrong.
228
+ //
229
+ // Bounded work: scanning the whole text once per distinct secret is
230
+ // quadratic, and an attacker controls how many distinct token-shaped runs
231
+ // an error string contains. Both the number of secrets and the total
232
+ // search effort are capped; the first pass has already masked each
233
+ // credential where it was proven, so the cap only trims the extra sweep
234
+ // for repeats.
235
+ // Every proven secret, not the first N. Capping this was the same mistake
236
+ // as capping decode rounds: the 33rd credential's repeat went out in the
237
+ // clear. Cost is controlled by making the sweep a single pass over the
238
+ // text rather than one pass per secret.
239
+ const known = new Set();
240
+ let shortest = Number.POSITIVE_INFINITY;
241
+ for (const { foldedFrom, foldedTo } of foldedRanges) {
242
+ const run = folded.text.slice(foldedFrom, foldedTo);
243
+ if (run.length < 20)
244
+ continue;
245
+ known.add(run);
246
+ shortest = Math.min(shortest, run.length);
247
+ }
248
+ if (known.size > 0) {
249
+ // Group by prefix AND length, so a position tests at most one string
250
+ // per length rather than every secret sharing that prefix.
251
+ //
252
+ // Bucketing on the prefix alone still lets an attacker pile hundreds of
253
+ // secrets into one bucket and follow it with near-miss tails: 400 of
254
+ // them took sixteen seconds. Any structure whose per-position work
255
+ // grows with attacker-chosen input is not a security boundary.
256
+ const byPrefixAndLength = new Map();
257
+ const lengthsByPrefix = new Map();
258
+ for (const secret of known) {
259
+ const prefix = secret.slice(0, PROBE_WIDTH);
260
+ byPrefixAndLength.set(`${prefix}\u0000${secret.length}`, secret);
261
+ const lengths = lengthsByPrefix.get(prefix);
262
+ if (lengths) {
263
+ if (!lengths.includes(secret.length))
264
+ lengths.push(secret.length);
265
+ }
266
+ else {
267
+ lengthsByPrefix.set(prefix, [secret.length]);
268
+ }
269
+ }
270
+ for (let at = 0; at + shortest <= folded.text.length; at += 1) {
271
+ const prefix = folded.text.slice(at, at + PROBE_WIDTH);
272
+ const lengths = lengthsByPrefix.get(prefix);
273
+ if (!lengths)
274
+ continue;
275
+ for (const length of lengths) {
276
+ const candidate = byPrefixAndLength.get(`${prefix}\u0000${length}`);
277
+ if (candidate === undefined)
278
+ continue;
279
+ if (folded.text.slice(at, at + length) !== candidate)
280
+ continue;
281
+ record(at, at + length);
282
+ at += length - 1;
283
+ break;
284
+ }
285
+ }
286
+ }
287
+ // Build the output once, front to back.
288
+ //
289
+ // Splicing the string per range re-copied the whole text for every match,
290
+ // which is quadratic in the number of credentials — and an attacker picks
291
+ // that number. Measured on this fixture family: 4k credentials took 167 ms
292
+ // and 8k took 555 ms (3.3x for 2x input) while the scan itself stayed
293
+ // linear (43 ms → 79 ms). Collecting the pieces and joining once keeps the
294
+ // total copy work proportional to the text length.
295
+ //
296
+ // Overlapping ranges are MERGED rather than one being dropped. The old
297
+ // back-to-front loop kept the rightmost of two overlapping matches and
298
+ // discarded the other, which left the non-shared head of the discarded
299
+ // range in the clear — for a redactor, masking the union is the only
300
+ // direction that cannot leak. The union is bounded by the matches
301
+ // themselves, so ordinary text around them is untouched.
302
+ ranges.sort((a, b) => a.from - b.from || a.to - b.to);
303
+ const pieces = [];
304
+ let cursor = 0;
305
+ let openFrom = -1;
306
+ let openTo = -1;
307
+ const flush = () => {
308
+ if (openFrom < 0)
309
+ return;
310
+ pieces.push(input.slice(cursor, openFrom), REDACTED);
311
+ charsCopied += (openFrom - cursor) + REDACTED.length;
312
+ cursor = openTo;
313
+ openFrom = -1;
314
+ };
315
+ for (const { from, to } of ranges) {
316
+ if (openFrom >= 0 && from <= openTo) {
317
+ if (to > openTo)
318
+ openTo = to; // extend the merged run
319
+ continue;
320
+ }
321
+ flush();
322
+ openFrom = from;
323
+ openTo = to;
324
+ }
325
+ flush();
326
+ pieces.push(input.slice(cursor));
327
+ charsCopied += input.length - cursor;
328
+ return pieces.join('');
329
+ }
330
+ /** `/bot<id>:<secret>` inside a path, after folding. */
331
+ const CANONICAL_URL_TOKEN = /\/(?:file\/)?bots?(\d{6,12}):([A-Za-z0-9_-]{20,})/gi;
332
+ /**
333
+ * Mask query VALUES while keeping the keys, in one linear pass.
334
+ *
335
+ * A regex of the shape /([^&=]+)=([^&]*)/g backtracks quadratically when the
336
+ * query holds a long run with no `=` in it — a 100 KB URL took four seconds,
337
+ * which turns any logged string into a denial of service. Splitting on `&` and
338
+ * taking the first `=` per pair cannot backtrack at all.
339
+ */
340
+ function maskQueryValues(query) {
341
+ return query
342
+ .split('&')
343
+ .map((pair) => {
344
+ const eq = pair.indexOf('=');
345
+ return eq < 0 ? pair : `${pair.slice(0, eq)}=${REDACTED}`;
346
+ })
347
+ .join('&');
348
+ }
349
+ /**
350
+ * Redact channel credentials from any string before it reaches a log sink, an
351
+ * API response, or a chat message.
352
+ */
353
+ export function redactChannelSecrets(input) {
354
+ return stripSecretsFoundInCanonicalForm(input)
355
+ // Percent-encoded URLs never reach the URL parser below, so peel their
356
+ // credentials off first.
357
+ .replace(/https?%3A%2F%2F[^\s]+/gi, stripBotTokenFromPath)
358
+ // Slack bearer tokens: xoxb-, xoxp-, xoxa-, xoxs-, xapp-.
359
+ .replace(/x(?:ox[bpas]|app)-[A-Za-z0-9-]+/g, (m) => `${m.slice(0, 9)}${REDACTED}`)
360
+ // Discord bot tokens are three base64url segments separated by dots.
361
+ // No word boundary and no fixed first-segment length: `\b` fails when
362
+ // an ordinary letter abuts the token, and pinning the first segment to
363
+ // 23-28 characters misses a token that follows other text.
364
+ //
365
+ // The first segment is base64url of a snowflake id, so it decodes to
366
+ // digits — that is what separates a real token from an artifact id or
367
+ // a checksum of the same shape. Structure alone is not enough:
368
+ // `aaaa….bbbbb.cccc…` matches any three-run dotted string.
369
+ //
370
+ // KNOWN OVER-MASKING. A non-token whose first segment happens to be a
371
+ // base64url snowflake is redacted too. Nothing in the remaining
372
+ // segments distinguishes it: a real token's second segment is six
373
+ // base64url characters and its third is an opaque HMAC, both of which
374
+ // an artifact id can match exactly. Since a miss here publishes a bot
375
+ // token while a false hit costs one unreadable diagnostic, the tie goes
376
+ // to masking. The snowflake test already spares ordinary versions,
377
+ // checksums and build ids, which is where the real risk of over-masking
378
+ // was.
379
+ //
380
+ // Anchoring the whole match keeps it linear. Open-ended runs made the
381
+ // engine try every split of a long dotless string; 50 KB took two
382
+ // seconds, which the timing test caught.
383
+ .replace(
384
+ // The first segment may carry base64 padding when a log renders it
385
+ // that way; rejecting `=` would leave the token in the clear.
386
+ // `=` is padding, so it is meaningful only AFTER a segment. The
387
+ // leading guard must still allow it: `token=<token>` puts one
388
+ // immediately in front, and excluding it there dropped the match.
389
+ /(?<![A-Za-z0-9_.-])([A-Za-z0-9_-]{20,}={0,2})\.([A-Za-z0-9_-]{5,}={0,2})\.([A-Za-z0-9_-]{25,}={0,2})(?![A-Za-z0-9_.-])/g, (whole, header) => (decodesToSnowflake(header) ? REDACTED : whole))
390
+ // Prefixed tokens: provenance is certain, so shape does not matter.
391
+ .replace(PREFIXED_TOKEN, (_m, id) => `bot${id}:${REDACTED}`)
392
+ // Authorization header values, whichever scheme.
393
+ .replace(/\b(Bot|Bearer)\s+\S+/gi, (_m, scheme) => `${scheme} ${REDACTED}`)
394
+ // URLs. ONE pass: running two URL regexes would let the second parse a
395
+ // string the first already rewrote.
396
+ //
397
+ // Host matching goes through the URL parser rather than a regex on the
398
+ // raw text, so canonical-equivalent spellings cannot slip past:
399
+ // uppercase hosts, an explicit :443, a trailing dot, and userinfo
400
+ // (user:pass@) all normalize before the suffix check.
401
+ .replace(/https?:\/\/[^\s]+/gi, (raw) => {
402
+ let parsed;
403
+ try {
404
+ parsed = new URL(raw);
405
+ }
406
+ catch {
407
+ return stripBotTokenFromPath(raw);
408
+ }
409
+ const host = parsed.hostname.toLowerCase().replace(/\.$/, '');
410
+ const isSlack = host === 'slack.com' || host.endsWith('.slack.com');
411
+ const isTelegram = host === 'telegram.org' || host.endsWith('.telegram.org');
412
+ const isDiscord = host === 'discord.com' || host.endsWith('.discord.com')
413
+ || host === 'discordapp.com' || host.endsWith('.discordapp.com');
414
+ // For our own hosts the whole path is capability-bearing: Slack's
415
+ // upload_url is an opaque path, Telegram's carries the bot token,
416
+ // and Discord webhook URLs carry the webhook secret.
417
+ if (isSlack || isTelegram || isDiscord)
418
+ return `https://${parsed.host}/${REDACTED}`;
419
+ // Untrusted host: keep the URL readable, but never leave a
420
+ // credential in it.
421
+ //
422
+ // Being a URL is NOT provenance on its own — that reading blanked
423
+ // ordinary artifact paths like /build/<id>:<hash>/artifact. Only a
424
+ // `/bot<id>:<secret>` segment proves a Telegram credential here;
425
+ // anything else falls back to the shape heuristic, which spares a
426
+ // build id while still catching a real token.
427
+ const withoutToken = stripBotTokenFromPath(raw)
428
+ .replace(TOKEN_ANYWHERE, (whole, id, secret) => mixesCharacterClasses(secret) ? `${id}:${REDACTED}` : whole);
429
+ // Query VALUES go, keys stay: a diagnostic URL stays diagnosable
430
+ // while a signature does not survive.
431
+ const queryAt = withoutToken.indexOf('?');
432
+ if (queryAt < 0)
433
+ return withoutToken;
434
+ return withoutToken.slice(0, queryAt + 1) + maskQueryValues(withoutToken.slice(queryAt + 1));
435
+ })
436
+ // Bot tokens outside any URL, including percent-encoded separators and
437
+ // a Bot/BOT/bot prefix in any casing.
438
+ // Bare `<digits>:<run>` in arbitrary prose: no provenance, so the
439
+ // heuristic applies and an ordinary diagnostic stays readable.
440
+ .replace(TOKEN_ANYWHERE, (whole, id, secret) => mixesCharacterClasses(secret) ? `${id}:${REDACTED}` : whole);
441
+ }
442
+ /**
443
+ * Stringify anything that was thrown, without ever throwing.
444
+ *
445
+ * `JSON.stringify` rejects BigInt ("Do not know how to serialize a BigInt")
446
+ * and circular references; `String()` itself throws on a Symbol or an object
447
+ * whose `toString` throws. An error sink that can throw defeats the error
448
+ * handling it was added to protect.
449
+ */
450
+ function stringifyThrown(err, withStack) {
451
+ if (err instanceof Error) {
452
+ return withStack ? (err.stack ?? err.message) : err.message;
453
+ }
454
+ if (typeof err === 'string')
455
+ return err;
456
+ try {
457
+ return JSON.stringify(err) ?? String(err);
458
+ }
459
+ catch {
460
+ try {
461
+ return String(err);
462
+ }
463
+ catch {
464
+ return '[unrepresentable error]';
465
+ }
466
+ }
467
+ }
468
+ /**
469
+ * For text a USER will see: message only, credentials masked.
470
+ *
471
+ * Never includes the stack. A stack frame carries absolute source paths, and
472
+ * publishing the operator's directory layout to a chat room is its own leak.
473
+ */
474
+ export function userErrorText(err) {
475
+ return redactChannelSecrets(stringifyThrown(err, false));
476
+ }
477
+ /** For server logs: full stack, credentials masked. */
478
+ export function logErrorText(err) {
479
+ return redactChannelSecrets(stringifyThrown(err, true));
480
+ }
481
+ /**
482
+ * Last mile: mask the BODY of an outbound message, whatever produced it.
483
+ *
484
+ * Error paths were hardened first, but a credential does not only travel in an
485
+ * error. An agent that reads a config file, a command that echoes a URL, a
486
+ * forwarder relaying tool output — each puts ordinary text on the wire, and
487
+ * that text goes to a chat room where anyone in the channel can read it.
488
+ *
489
+ * Every transport calls this immediately before handing text to the vendor
490
+ * SDK, so there is one place to audit rather than one per call site.
491
+ */
492
+ export function redactOutboundText(text) {
493
+ return redactChannelSecrets(text);
494
+ }
495
+ /**
496
+ * Mask every string inside a structured outbound payload.
497
+ *
498
+ * Inline keyboards carry user-visible text in button labels and URLs, and
499
+ * those reach the room exactly like a message body. Walking the object beats
500
+ * enumerating fields, because the vendor's shape changes and a new field would
501
+ * silently go unmasked.
502
+ *
503
+ * Depth- and breadth-bounded: the input is attacker-influenced, and a
504
+ * recursive walk over it is a stack-overflow waiting to happen. Cycles are
505
+ * tracked so a self-referencing object cannot spin.
506
+ */
507
+ export function redactOutboundPayload(value, depth = 0, seen = new WeakMap()) {
508
+ if (typeof value === 'string')
509
+ return redactChannelSecrets(value);
510
+ if (value === null || typeof value !== 'object')
511
+ return value;
512
+ // A cache, not a visited-set. Returning the ORIGINAL for an object seen
513
+ // before means the second alias of a shared button object ships its secret
514
+ // untouched — the first reference was sanitized and the second was not.
515
+ const cached = seen.get(value);
516
+ if (cached !== undefined)
517
+ return cached;
518
+ // Past the depth limit, drop the subtree instead of returning it. Handing
519
+ // back the raw object is a leak; anything this deep in an outbound payload
520
+ // is not something a channel renders.
521
+ if (depth >= MAX_PAYLOAD_DEPTH)
522
+ return (Array.isArray(value) ? [] : {});
523
+ // Register the container BEFORE walking it, so a cycle resolves to the
524
+ // same sanitized object rather than recursing forever.
525
+ const out = Array.isArray(value) ? [] : {};
526
+ seen.set(value, out);
527
+ if (Array.isArray(value)) {
528
+ for (const item of value) {
529
+ out.push(redactOutboundPayload(item, depth + 1, seen));
530
+ }
531
+ return out;
532
+ }
533
+ for (const [key, item] of Object.entries(value)) {
534
+ out[key] = redactOutboundPayload(item, depth + 1, seen);
535
+ }
536
+ return out;
537
+ }
538
+ /** Deeper than any keyboard or media payload a channel actually renders. */
539
+ const MAX_PAYLOAD_DEPTH = 12;
540
+ /**
541
+ * True when an escaped run sits close enough to be the other half of a
542
+ * credential the fold could not finish resolving.
543
+ *
544
+ * Distance is measured to the escaped RUN, not to an escape character. A long
545
+ * `%2525…` chain is mostly digits, so a window around the neighbour can sit
546
+ * entirely inside it and still contain no `%` — which read as "no escape
547
+ * nearby" and let the secret through.
548
+ */
549
+ function hasEscapeWithin(input, offset, length) {
550
+ for (const match of input.matchAll(/\S{20,}/g)) {
551
+ if (!/%|\\u|&#/.test(match[0]))
552
+ continue;
553
+ const start = match.index ?? 0;
554
+ const stop = start + match[0].length;
555
+ const gapBefore = offset - stop;
556
+ const gapAfter = start - (offset + length);
557
+ if (gapBefore >= 0 && gapBefore <= EXHAUSTED_NEIGHBOURHOOD)
558
+ return true;
559
+ if (gapAfter >= 0 && gapAfter <= EXHAUSTED_NEIGHBOURHOOD)
560
+ return true;
561
+ }
562
+ return false;
563
+ }
564
+ /**
565
+ * How far to look for the escaped half. The fold strips control characters and
566
+ * whitespace, so the two halves can be a line break and a little punctuation
567
+ * apart — but not paragraphs apart, which is what keeps this from swallowing
568
+ * an unrelated identifier elsewhere in the message.
569
+ */
570
+ const EXHAUSTED_NEIGHBOURHOOD = 64;
571
+ /**
572
+ * Width of the prefix used to index known secrets. Every tracked run is at
573
+ * least 20 characters, so this always exists, and collisions across distinct
574
+ * credentials are rare enough that each position tests roughly one candidate.
575
+ */
576
+ const PROBE_WIDTH = 16;
577
+ //# sourceMappingURL=redact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../../../src/messaging/redact.ts"],"names":[],"mappings":"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"}