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.
- package/README.ja.md +15 -0
- package/README.ko.md +15 -0
- package/README.md +19 -4
- package/dist/bin/cli-jaw.js +5 -1
- package/dist/bin/cli-jaw.js.map +1 -1
- package/dist/bin/commands/doctor.js +66 -1
- package/dist/bin/commands/doctor.js.map +1 -1
- package/dist/bin/commands/init.js +107 -8
- package/dist/bin/commands/init.js.map +1 -1
- package/dist/bin/commands/slack.js +190 -0
- package/dist/bin/commands/slack.js.map +1 -0
- package/dist/lib/upload.js +5 -1
- package/dist/lib/upload.js.map +1 -1
- package/dist/server.js +1 -0
- package/dist/server.js.map +1 -1
- package/dist/src/agent/alert-escalation.js +1 -1
- package/dist/src/agent/alert-escalation.js.map +1 -1
- package/dist/src/agent/codex-app-catalog.js +57 -0
- package/dist/src/agent/codex-app-catalog.js.map +1 -0
- package/dist/src/agent/codex-app-client.js +89 -7
- package/dist/src/agent/codex-app-client.js.map +1 -1
- package/dist/src/agent/pi-rpc-verdict.js +22 -0
- package/dist/src/agent/pi-rpc-verdict.js.map +1 -0
- package/dist/src/agent/pi-runtime.js +240 -0
- package/dist/src/agent/pi-runtime.js.map +1 -1
- package/dist/src/agent/runtime-pool.js +445 -0
- package/dist/src/agent/runtime-pool.js.map +1 -0
- package/dist/src/agent/spawn.js +395 -240
- package/dist/src/agent/spawn.js.map +1 -1
- package/dist/src/cli/command-context.js +5 -2
- package/dist/src/cli/command-context.js.map +1 -1
- package/dist/src/cli/commands.js +43 -39
- package/dist/src/cli/commands.js.map +1 -1
- package/dist/src/cli/handlers-runtime.js +15 -7
- package/dist/src/cli/handlers-runtime.js.map +1 -1
- package/dist/src/cli/handlers-search.js +1 -1
- package/dist/src/cli/handlers-search.js.map +1 -1
- package/dist/src/cli/handlers-skill-invoke.js +1 -1
- package/dist/src/cli/handlers-skill-invoke.js.map +1 -1
- package/dist/src/cli/handlers-workflows.js +1 -1
- package/dist/src/cli/handlers-workflows.js.map +1 -1
- package/dist/src/cli/handlers.js +1 -1
- package/dist/src/cli/handlers.js.map +1 -1
- package/dist/src/cli/opencodex-models.js +40 -7
- package/dist/src/cli/opencodex-models.js.map +1 -1
- package/dist/src/cli/registry-live.js +6 -5
- package/dist/src/cli/registry-live.js.map +1 -1
- package/dist/src/command-contract/catalog.js +4 -0
- package/dist/src/command-contract/catalog.js.map +1 -1
- package/dist/src/core/config.js +69 -4
- package/dist/src/core/config.js.map +1 -1
- package/dist/src/core/runtime-settings.js +17 -0
- package/dist/src/core/runtime-settings.js.map +1 -1
- package/dist/src/core/settings-merge.js +1 -1
- package/dist/src/core/settings-merge.js.map +1 -1
- package/dist/src/discord/bot.js +29 -14
- package/dist/src/discord/bot.js.map +1 -1
- package/dist/src/discord/commands.js +5 -4
- package/dist/src/discord/commands.js.map +1 -1
- package/dist/src/discord/discord-file.js +8 -2
- package/dist/src/discord/discord-file.js.map +1 -1
- package/dist/src/discord/forwarder.js +17 -19
- package/dist/src/discord/forwarder.js.map +1 -1
- package/dist/src/discord/send-only-client.js +9 -1
- package/dist/src/discord/send-only-client.js.map +1 -1
- package/dist/src/manager/dashboard-service.js +38 -1
- package/dist/src/manager/dashboard-service.js.map +1 -1
- package/dist/src/manager/telegram-hub/hub-bot.js +47 -29
- package/dist/src/manager/telegram-hub/hub-bot.js.map +1 -1
- package/dist/src/messaging/channel-health.js +32 -0
- package/dist/src/messaging/channel-health.js.map +1 -1
- package/dist/src/messaging/chunk.js +376 -0
- package/dist/src/messaging/chunk.js.map +1 -0
- package/dist/src/messaging/dedupe.js +104 -0
- package/dist/src/messaging/dedupe.js.map +1 -0
- package/dist/src/messaging/fold.js +210 -0
- package/dist/src/messaging/fold.js.map +1 -0
- package/dist/src/messaging/redact.js +577 -0
- package/dist/src/messaging/redact.js.map +1 -0
- package/dist/src/messaging/retry.js +76 -0
- package/dist/src/messaging/retry.js.map +1 -0
- package/dist/src/messaging/runtime.js +6 -3
- package/dist/src/messaging/runtime.js.map +1 -1
- package/dist/src/messaging/send.js +45 -15
- package/dist/src/messaging/send.js.map +1 -1
- package/dist/src/messaging/slack-target.js +50 -0
- package/dist/src/messaging/slack-target.js.map +1 -0
- package/dist/src/messaging/types.js.map +1 -1
- package/dist/src/orchestrator/pipeline.js +4 -4
- package/dist/src/orchestrator/pipeline.js.map +1 -1
- package/dist/src/routes/command.js +11 -7
- package/dist/src/routes/command.js.map +1 -1
- package/dist/src/routes/messaging.js +28 -12
- package/dist/src/routes/messaging.js.map +1 -1
- package/dist/src/routes/settings.js +22 -6
- package/dist/src/routes/settings.js.map +1 -1
- package/dist/src/slack/api.js +116 -0
- package/dist/src/slack/api.js.map +1 -0
- package/dist/src/slack/bot.js +262 -0
- package/dist/src/slack/bot.js.map +1 -0
- package/dist/src/slack/commands.js +98 -0
- package/dist/src/slack/commands.js.map +1 -0
- package/dist/src/slack/events.js +116 -0
- package/dist/src/slack/events.js.map +1 -0
- package/dist/src/slack/format.js +58 -0
- package/dist/src/slack/format.js.map +1 -0
- package/dist/src/slack/forwarder.js +57 -0
- package/dist/src/slack/forwarder.js.map +1 -0
- package/dist/src/slack/manifest.js +84 -0
- package/dist/src/slack/manifest.js.map +1 -0
- package/dist/src/slack/register.js +13 -0
- package/dist/src/slack/register.js.map +1 -0
- package/dist/src/slack/send-handler.js +41 -0
- package/dist/src/slack/send-handler.js.map +1 -0
- package/dist/src/slack/send-only-client.js +46 -0
- package/dist/src/slack/send-only-client.js.map +1 -0
- package/dist/src/slack/slack-file.js +72 -0
- package/dist/src/slack/slack-file.js.map +1 -0
- package/dist/src/slack/socket.js +341 -0
- package/dist/src/slack/socket.js.map +1 -0
- package/dist/src/telegram/bot.js +117 -37
- package/dist/src/telegram/bot.js.map +1 -1
- package/dist/src/telegram/elicitation-buttons.js +7 -2
- package/dist/src/telegram/elicitation-buttons.js.map +1 -1
- package/dist/src/telegram/forwarder.js +15 -7
- package/dist/src/telegram/forwarder.js.map +1 -1
- package/dist/src/telegram/rich-message.js +209 -24
- package/dist/src/telegram/rich-message.js.map +1 -1
- package/dist/src/telegram/telegram-file.js +35 -4
- package/dist/src/telegram/telegram-file.js.map +1 -1
- package/dist/src/telegram/voice.js +4 -3
- package/dist/src/telegram/voice.js.map +1 -1
- package/package.json +7 -1
- package/public/assets/providers/slack.svg +1 -0
- package/public/dist/assets/ChannelsDiscord-D9FLnZso.js +1 -0
- package/public/dist/assets/ChannelsSlack-ybvupgdK.js +1 -0
- package/public/dist/assets/ChannelsTelegram-BOCOPrBc.js +1 -0
- package/public/dist/assets/HealthBadge-megTlF4n.js +1 -0
- package/public/dist/assets/TransportStatusChips-CjEySMis.js +1 -0
- package/public/dist/assets/app-BGIAy4he.js +55 -0
- package/public/dist/assets/{bgtask-badge-CdBqBy1L.js → bgtask-badge-DXca8E7c.js} +1 -1
- package/public/dist/assets/bgtask-badge-GRSiNILQ.js +1 -0
- package/public/dist/assets/{employees-C8qufeJl.js → employees-BL4qMxJj.js} +1 -1
- package/public/dist/assets/iframe-renderer-BUSk0Rw9.js +1 -0
- package/public/dist/assets/{iframe-renderer-CZ67aeTO.js → iframe-renderer-DUI0LYBy.js} +2 -2
- package/public/dist/assets/{manager-CLXT60M5.js → manager-B-gpf-3j.js} +3 -3
- package/public/dist/assets/{memory-lWramLVw.js → memory-B_Y0L0KD.js} +1 -1
- package/public/dist/assets/memory-CX6YahTc.js +1 -0
- package/public/dist/assets/message-history-Det7u76S.js +1 -0
- package/public/dist/assets/{message-history-2NUN3UxM.js → message-history-Dl8dJzez.js} +1 -1
- package/public/dist/assets/{provider-icons-stsNmQKx.js → provider-icons-VDfahiUp.js} +3 -2
- package/public/dist/assets/{render-CsF-ojLe.js → render-BI1aqKoc.js} +1 -1
- package/public/dist/assets/{settings-BMLowRCh.js → settings-B0Sj4sUH.js} +1 -1
- package/public/dist/assets/settings-C7NutP6X.js +1 -0
- package/public/dist/assets/settings-core-CyX-px6_.js +100 -0
- package/public/dist/assets/settings-core-DVpFmrhY.js +1 -0
- package/public/dist/assets/{sidebar-gKjYLv49.js → sidebar-DOR9fTgN.js} +3 -3
- package/public/dist/assets/skills-BWhKreQ2.js +1 -0
- package/public/dist/assets/{skills-CKTbomdm.js → skills-wt0fkV9Y.js} +1 -1
- package/public/dist/assets/slash-commands-BZbqTg3v.js +20 -0
- package/public/dist/assets/slash-commands-Di4NDA4w.js +1 -0
- package/public/dist/assets/{trace-drawer-C3G4mmB1.js → trace-drawer-kMYzaVFW.js} +1 -1
- package/public/dist/assets/ui-BghexWrB.js +1 -0
- package/public/dist/assets/{ui-CVVC_flX.js → ui-D4D5HUfo.js} +1 -1
- package/public/dist/index.html +62 -1
- package/public/dist/manager/index.html +1 -1
- package/public/index.html +61 -0
- package/public/js/features/command-info.ts +1 -0
- package/public/js/features/help-content.ts +8 -0
- package/public/js/features/settings-channel.ts +5 -1
- package/public/js/features/settings-core.ts +2 -0
- package/public/js/features/settings-slack.ts +74 -0
- package/public/js/features/settings-types.ts +5 -1
- package/public/js/features/settings.ts +1 -0
- package/public/js/features/transport-status-row.ts +15 -3
- package/public/js/main.ts +19 -0
- package/public/js/provider-icons.ts +4 -1
- package/public/js/ws.ts +1 -1
- package/public/locales/en.json +21 -0
- package/public/locales/ja.json +21 -0
- package/public/locales/ko.json +21 -0
- package/public/locales/zh.json +21 -0
- package/public/manager/src/settings/SettingsShell.tsx +1 -0
- package/public/manager/src/settings/SettingsSidebar.tsx +1 -0
- package/public/manager/src/settings/pages/ChannelsSlack.tsx +323 -0
- package/public/manager/src/settings/pages/components/ActiveChannelToggle.tsx +2 -1
- package/public/manager/src/settings/pages/components/TransportStatusChips.tsx +13 -4
- package/public/manager/src/settings/types.ts +1 -0
- package/scripts/bundle-sidecar.sh +13 -4
- package/scripts/check-redaction-sinks.mjs +276 -0
- package/scripts/check-sidecar-prune-safety.mjs +167 -0
- package/scripts/pi-rpc-probe.mts +361 -0
- package/scripts/pick-gyp-python.sh +61 -0
- package/scripts/release-gates.mjs +97 -0
- package/scripts/release-preview.sh +8 -1
- package/scripts/release.sh +13 -2
- package/scripts/sync-electron-version.cjs +93 -0
- package/public/dist/assets/ChannelsDiscord-Bt1_rtNC.js +0 -1
- package/public/dist/assets/ChannelsTelegram-BLV0m1oq.js +0 -1
- package/public/dist/assets/TransportStatusChips-Bld0yXi7.js +0 -1
- package/public/dist/assets/app-iSJhsP20.js +0 -55
- package/public/dist/assets/bgtask-badge-CSkSsoB6.js +0 -1
- package/public/dist/assets/iframe-renderer-DXdo0YXN.js +0 -1
- package/public/dist/assets/memory-DeKUlD2M.js +0 -1
- package/public/dist/assets/message-history-CWTQ2woA.js +0 -1
- package/public/dist/assets/settings-CDjs7hTT.js +0 -1
- package/public/dist/assets/settings-core-Cs_oq-b3.js +0 -99
- package/public/dist/assets/settings-core-D-TOh1a6.js +0 -1
- package/public/dist/assets/skills-GuIfNASs.js +0 -1
- package/public/dist/assets/slash-commands-BtZa093n.js +0 -20
- package/public/dist/assets/slash-commands-DGJKfpMT.js +0 -1
- package/public/dist/assets/ui-DJg5Q_NJ.js +0 -1
- /package/public/dist/assets/{DashboardMeta-B7CVqXcU.js → DashboardMeta-DennaaA_.js} +0 -0
- /package/public/dist/assets/{Display-BF-rACK6.js → Display-hGuSn_W5.js} +0 -0
- /package/public/dist/assets/{Employees-D3hnciP0.js → Employees-B5YXk5ma.js} +0 -0
- /package/public/dist/assets/{Heartbeat-D4Pn5O3O.js → Heartbeat-vDGhPfct.js} +0 -0
- /package/public/dist/assets/{Mcp-SfytKWGX.js → Mcp-BHWnJ6SP.js} +0 -0
- /package/public/dist/assets/{Memory-DNxBOQ7N.js → Memory-B_UZ-iCA.js} +0 -0
- /package/public/dist/assets/{ModelProvider-CXwtlG7l.js → ModelProvider-CgUvs6pE.js} +0 -0
- /package/public/dist/assets/{Network-DISUhige.js → Network-AWpSkALD.js} +0 -0
- /package/public/dist/assets/{Profile-B8yBO3Ju.js → Profile-DnIE2ios.js} +0 -0
- /package/public/dist/assets/{Prompts-5lNQ5qOm.js → Prompts-B9aKLall.js} +0 -0
- /package/public/dist/assets/{SpeechKeys-BepaIHBa.js → SpeechKeys-K4Be_o7z.js} +0 -0
- /package/public/dist/assets/{TelegramHub--DNjRAwW.js → TelegramHub-CFwSkzHP.js} +0 -0
- /package/public/dist/assets/{TerminalPanel-DQovYfwz.js → TerminalPanel-CdlFZHAK.js} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forwarder.js","sourceRoot":"","sources":["../../../src/telegram/forwarder.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"forwarder.js","sourceRoot":"","sources":["../../../src/telegram/forwarder.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,25 +1,201 @@
|
|
|
1
1
|
import { stripUndefined } from '../core/strip-undefined.js';
|
|
2
|
+
import { closeAndReopen, fenceReserve, hasFence, safeCut, scanOpenFence, widestFenceOpener } from '../messaging/chunk.js';
|
|
2
3
|
import { markdownToTelegramHtml, chunkTelegramMessage } from './forwarder.js';
|
|
4
|
+
import { redactOutboundText } from '../messaging/redact.js';
|
|
5
|
+
import { classifySendFailure, retryAfterMs, MAX_INLINE_RATE_LIMIT_MS } from '../messaging/retry.js';
|
|
3
6
|
export const RICH_MESSAGE_LIMIT = 32000;
|
|
4
7
|
const HTML_MESSAGE_LIMIT = 4096;
|
|
8
|
+
/**
|
|
9
|
+
* Send once, honouring what the failure actually was.
|
|
10
|
+
*
|
|
11
|
+
* The ladder used to catch everything, so a rate limit was answered by sending
|
|
12
|
+
* the same content twice more, immediately — and a network failure that may
|
|
13
|
+
* already have been accepted was answered by sending it again, which the user
|
|
14
|
+
* sees twice.
|
|
15
|
+
*
|
|
16
|
+
* Returns true when the caller should fall back to a simpler format. Throws
|
|
17
|
+
* when it should not: a long rate limit or an ambiguous failure is the
|
|
18
|
+
* caller's to report, not to paper over with another send.
|
|
19
|
+
*/
|
|
20
|
+
async function attemptSend(send) {
|
|
21
|
+
try {
|
|
22
|
+
await send();
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
const kind = classifySendFailure(err);
|
|
27
|
+
if (kind === 'format')
|
|
28
|
+
return true;
|
|
29
|
+
if (kind !== 'rate-limit')
|
|
30
|
+
throw err;
|
|
31
|
+
const wait = retryAfterMs(err);
|
|
32
|
+
if (wait <= 0 || wait > MAX_INLINE_RATE_LIMIT_MS)
|
|
33
|
+
throw err;
|
|
34
|
+
await new Promise((resolve) => setTimeout(resolve, wait));
|
|
35
|
+
// Retry the SAME form, once: waiting is what the server asked for, and
|
|
36
|
+
// switching format would add load rather than remove it.
|
|
37
|
+
try {
|
|
38
|
+
await send();
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
catch (retryErr) {
|
|
42
|
+
if (classifySendFailure(retryErr) === 'format')
|
|
43
|
+
return true;
|
|
44
|
+
throw retryErr;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
5
48
|
/** True when the running grammy build exposes sendRichMessage (Bot API 10.1+). */
|
|
6
49
|
export function supportsRichMessage(api) {
|
|
7
50
|
return typeof api.sendRichMessage === 'function';
|
|
8
51
|
}
|
|
9
|
-
/**
|
|
10
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Split markdown on paragraph > line boundaries without breaking code fences.
|
|
54
|
+
*
|
|
55
|
+
* When a fence has no candidate boundary inside it — one long code block, the
|
|
56
|
+
* common shape for agent output — the split lands mid-fence. Such a chunk is
|
|
57
|
+
* closed here and the next one reopens with the same language tag, so both
|
|
58
|
+
* render as code and keep their highlighting.
|
|
59
|
+
*/
|
|
60
|
+
export function chunkRichMarkdown(md, limit = RICH_MESSAGE_LIMIT, inherited = null) {
|
|
11
61
|
const raw = String(md || '');
|
|
12
|
-
if (raw.length <= limit)
|
|
62
|
+
if (raw.length <= limit && !inherited)
|
|
13
63
|
return [raw];
|
|
14
|
-
|
|
64
|
+
// Reserve room for the reopener/closer only when a fence is actually in
|
|
65
|
+
// play; otherwise the reserve costs an extra outbound message.
|
|
66
|
+
//
|
|
67
|
+
// The scan starts from the inherited fence: the remainder may close it and
|
|
68
|
+
// then open a WIDER one, and sizing the reserve from the inherited fence
|
|
69
|
+
// alone let that wider opener push a chunk past the limit.
|
|
70
|
+
const worst = widestFenceOpener(raw, inherited);
|
|
71
|
+
const fenced = inherited !== null || hasFence(raw);
|
|
72
|
+
const wanted = fenced ? fenceReserve(worst.lang, worst.marker) : 0;
|
|
73
|
+
// A delimiter can be wider than the whole budget — six backticks with a
|
|
74
|
+
// long language tag is still a valid opener. Reserving for it left one
|
|
75
|
+
// character of payload per chunk, so 400 characters became 406 messages.
|
|
76
|
+
// Fall back to a bare fence, exactly as chunkFenceAware does; the marker
|
|
77
|
+
// is then not reproduced, which costs formatting rather than delivery.
|
|
78
|
+
const reserve = wanted < limit ? wanted : (fenced ? fenceReserve('') : 0);
|
|
79
|
+
const budget = Math.max(1, limit - reserve);
|
|
80
|
+
const pieces = [];
|
|
15
81
|
let remaining = raw;
|
|
16
|
-
while (remaining.length >
|
|
17
|
-
|
|
18
|
-
|
|
82
|
+
while (remaining.length > budget) {
|
|
83
|
+
// Guarantee progress. findMarkdownSafeSplit can return 0 — safeCut
|
|
84
|
+
// refuses to divide a surrogate pair and backs off to the start when
|
|
85
|
+
// the budget cannot hold one — and a zero-length cut never consumes
|
|
86
|
+
// input, so the loop spins forever on a 43-character message.
|
|
87
|
+
let cut = findMarkdownSafeSplit(remaining, budget);
|
|
88
|
+
if (cut <= 0)
|
|
89
|
+
cut = safeCut(remaining, Math.max(1, Math.min(budget, remaining.length)));
|
|
90
|
+
if (cut <= 0)
|
|
91
|
+
cut = Math.min(2, remaining.length);
|
|
92
|
+
pieces.push(remaining.slice(0, cut));
|
|
93
|
+
remaining = remaining.slice(cut);
|
|
19
94
|
}
|
|
20
95
|
if (remaining.length > 0)
|
|
21
|
-
|
|
22
|
-
|
|
96
|
+
pieces.push(remaining);
|
|
97
|
+
// Pass the reserve as the ceiling: a marker wider than it would be
|
|
98
|
+
// reproduced verbatim and carry the chunk past the caller's limit.
|
|
99
|
+
return closeAndReopen(pieces, wanted < limit, inherited, reserve || undefined);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Chunk so that the first chunk still fits once the prefix is prepended.
|
|
103
|
+
* Only the first chunk carries the prefix, so only its budget is reduced.
|
|
104
|
+
*/
|
|
105
|
+
function chunkWithPrefixBudget(markdown, prefix, limit) {
|
|
106
|
+
if (!prefix)
|
|
107
|
+
return chunkRichMarkdown(markdown, limit);
|
|
108
|
+
const firstBudget = limit - prefix.length;
|
|
109
|
+
if (firstBudget <= 0)
|
|
110
|
+
return chunkRichMarkdown(markdown, limit);
|
|
111
|
+
if (markdown.length <= firstBudget)
|
|
112
|
+
return [markdown];
|
|
113
|
+
// Decide the seam FIRST, then build both sides from it once. Re-chunking an
|
|
114
|
+
// adjusted head discarded the closing fence the first pass had added, so
|
|
115
|
+
// the head went out unclosed and the remainder carried a stray marker.
|
|
116
|
+
const probe = chunkRichMarkdown(markdown, firstBudget);
|
|
117
|
+
const rawConsumed = consumedLength(probe[0] ?? '', markdown);
|
|
118
|
+
const consumed = avoidMidLineFenceHandoff(markdown, rawConsumed);
|
|
119
|
+
if (consumed >= markdown.length)
|
|
120
|
+
return [markdown];
|
|
121
|
+
const headSource = markdown.slice(0, consumed);
|
|
122
|
+
const rest = markdown.slice(consumed);
|
|
123
|
+
const inherited = scanOpenFence(headSource);
|
|
124
|
+
// One shared view of the fence state gives the head its closer and the
|
|
125
|
+
// remainder its reopener.
|
|
126
|
+
const head = closeAndReopen([headSource], true)[0] ?? headSource;
|
|
127
|
+
return [head, ...chunkRichMarkdown(rest, limit, inherited)];
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* A prefix at or past the limit leaves no room for content, and prepending it
|
|
131
|
+
* anyway guarantees the API rejects the message. Drop it so the body still
|
|
132
|
+
* gets delivered — every send path has to agree on this, or one of them ships
|
|
133
|
+
* the oversized version.
|
|
134
|
+
*/
|
|
135
|
+
function effectivePrefix(prefix, limit, body = '') {
|
|
136
|
+
if (!prefix)
|
|
137
|
+
return '';
|
|
138
|
+
// A fence must start its line. Prepending the prefix inline pushes an
|
|
139
|
+
// opening fence off column zero, so Telegram stops seeing it as a fence
|
|
140
|
+
// and the whole message renders as prose. Give the prefix its own line
|
|
141
|
+
// whenever the body opens with a delimiter.
|
|
142
|
+
const normalized = /^ {0,3}(?:`{3,}|~{3,})/.test(body) && !prefix.endsWith('\n')
|
|
143
|
+
? `${prefix}\n`
|
|
144
|
+
: prefix;
|
|
145
|
+
// Leave room for a whole code point, not just one code unit. With a single
|
|
146
|
+
// unit of budget, safeCut refuses to split an astral character and emits
|
|
147
|
+
// both halves, so prefix + payload lands one over the limit.
|
|
148
|
+
const firstCodePoint = [...body][0] ?? '';
|
|
149
|
+
const needed = Math.max(1, firstCodePoint.length);
|
|
150
|
+
return normalized.length + needed <= limit ? normalized : '';
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* A chunk boundary can turn a delimiter that sat MID-LINE in the source into
|
|
154
|
+
* the first thing on a line of the next message, where Telegram reads it as a
|
|
155
|
+
* fence. Back the split up to the last newline so the delimiter keeps the text
|
|
156
|
+
* that preceded it on its line.
|
|
157
|
+
*
|
|
158
|
+
* Returns the adjusted consumed length, or the original when no adjustment is
|
|
159
|
+
* possible (the whole head is one line — splitting it differently would not
|
|
160
|
+
* help).
|
|
161
|
+
*/
|
|
162
|
+
function avoidMidLineFenceHandoff(source, consumed) {
|
|
163
|
+
const before = source.slice(0, consumed);
|
|
164
|
+
// Only a mid-line delimiter is a problem: one that already started a line
|
|
165
|
+
// in the source is meant to be a fence.
|
|
166
|
+
if (before === '' || before.endsWith('\n'))
|
|
167
|
+
return consumed;
|
|
168
|
+
// Find where the delimiter run that touches the boundary begins. The
|
|
169
|
+
// boundary may fall inside it, so scan back over the delimiter characters.
|
|
170
|
+
let start = consumed;
|
|
171
|
+
const delimiterAt = (i) => source[i] === '`' || source[i] === '~';
|
|
172
|
+
while (start > 0 && delimiterAt(start - 1))
|
|
173
|
+
start -= 1;
|
|
174
|
+
let end = start;
|
|
175
|
+
while (end < source.length && delimiterAt(end))
|
|
176
|
+
end += 1;
|
|
177
|
+
if (end - start < 3)
|
|
178
|
+
return consumed;
|
|
179
|
+
// Carry the code point before the run into the next message so the
|
|
180
|
+
// delimiter is no longer the first thing on its line. It must be a whole
|
|
181
|
+
// code point: moving one UTF-16 unit splits an emoji across the seam.
|
|
182
|
+
if (start <= 0)
|
|
183
|
+
return consumed;
|
|
184
|
+
const prev = source.charCodeAt(start - 1);
|
|
185
|
+
const isLowSurrogate = prev >= 0xDC00 && prev <= 0xDFFF;
|
|
186
|
+
const step = isLowSurrogate && start >= 2 ? 2 : 1;
|
|
187
|
+
return start - step;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* How much of `source` the emitted chunk consumed. The chunker may have added
|
|
191
|
+
* a closing fence that is not part of the source, so a plain `.length` would
|
|
192
|
+
* skip real content.
|
|
193
|
+
*/
|
|
194
|
+
function consumedLength(chunk, source) {
|
|
195
|
+
if (source.startsWith(chunk))
|
|
196
|
+
return chunk.length;
|
|
197
|
+
const withoutClose = chunk.replace(/\n?(?:`{3,}|~{3,})$/, '');
|
|
198
|
+
return source.startsWith(withoutClose) ? withoutClose.length : chunk.length;
|
|
23
199
|
}
|
|
24
200
|
function findMarkdownSafeSplit(raw, limit) {
|
|
25
201
|
// Candidate boundaries, best first: blank line, then newline — never inside a code fence.
|
|
@@ -32,7 +208,9 @@ function findMarkdownSafeSplit(raw, limit) {
|
|
|
32
208
|
return i;
|
|
33
209
|
}
|
|
34
210
|
}
|
|
35
|
-
|
|
211
|
+
// Hard split as last resort — on a code-point boundary, so the cut never
|
|
212
|
+
// separates a surrogate pair and never consumes zero input.
|
|
213
|
+
return safeCut(raw, limit);
|
|
36
214
|
}
|
|
37
215
|
function insideCodeFence(raw, index) {
|
|
38
216
|
let fences = 0;
|
|
@@ -58,19 +236,24 @@ function richOpts(opts) {
|
|
|
58
236
|
* parse_mode:'HTML' (re-chunked at 4096), then tag-stripped plaintext. Never throws for
|
|
59
237
|
* a single bad chunk; rethrows only when every leg of the chain failed.
|
|
60
238
|
*/
|
|
61
|
-
export async function sendTelegramMarkdown(api, chatId,
|
|
62
|
-
|
|
239
|
+
export async function sendTelegramMarkdown(api, chatId, rawMarkdown, opts) {
|
|
240
|
+
// Last mile for every Telegram text send: this helper is the single entry
|
|
241
|
+
// point, so masking here cannot be bypassed by a caller that forgot.
|
|
242
|
+
const markdown = redactOutboundText(rawMarkdown);
|
|
243
|
+
const prefix = effectivePrefix(opts?.prefix ?? '', RICH_MESSAGE_LIMIT, markdown);
|
|
63
244
|
if (!supportsRichMessage(api)) {
|
|
64
245
|
await sendHtmlFallback(api, chatId, markdown, opts, prefix);
|
|
65
246
|
return;
|
|
66
247
|
}
|
|
67
|
-
|
|
248
|
+
// The prefix rides on the first chunk, so it has to come out of that
|
|
249
|
+
// chunk's budget. Chunking at the full limit and prepending afterwards
|
|
250
|
+
// pushed the first message past the API limit and forced a needless
|
|
251
|
+
// fallback.
|
|
252
|
+
const chunks = chunkWithPrefixBudget(markdown, prefix, RICH_MESSAGE_LIMIT);
|
|
68
253
|
for (let i = 0; i < chunks.length; i += 1) {
|
|
69
254
|
const withPrefix = i === 0 ? `${prefix}${chunks[i]}` : chunks[i];
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
255
|
+
const needsFallback = await attemptSend(() => api.sendRichMessage(chatId, { markdown: withPrefix }, richOpts(opts)));
|
|
256
|
+
if (needsFallback) {
|
|
74
257
|
await sendHtmlFallback(api, chatId, chunks[i], opts, i === 0 ? prefix : '');
|
|
75
258
|
}
|
|
76
259
|
}
|
|
@@ -80,14 +263,16 @@ async function sendHtmlFallback(api, chatId, mdChunk, opts, prefix) {
|
|
|
80
263
|
const htmlOpts = { ...base, parse_mode: 'HTML' };
|
|
81
264
|
// Plaintext leg: omit the options object entirely when empty (legacy wire shape).
|
|
82
265
|
const plainOpts = Object.keys(base).length > 0 ? base : undefined;
|
|
83
|
-
const
|
|
266
|
+
const html = markdownToTelegramHtml(mdChunk);
|
|
267
|
+
const safePrefix = effectivePrefix(prefix, HTML_MESSAGE_LIMIT, html);
|
|
268
|
+
const chunks = safePrefix
|
|
269
|
+
? chunkTelegramMessage(html, HTML_MESSAGE_LIMIT - safePrefix.length)
|
|
270
|
+
: chunkTelegramMessage(html, HTML_MESSAGE_LIMIT);
|
|
84
271
|
for (let i = 0; i < chunks.length; i += 1) {
|
|
85
|
-
const withPrefix = i === 0 ? `${
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
catch {
|
|
90
|
-
await api.sendMessage(chatId, withPrefix.replace(/<[^>]+>/g, ''), plainOpts);
|
|
272
|
+
const withPrefix = i === 0 ? `${safePrefix}${chunks[i]}` : chunks[i];
|
|
273
|
+
const needsPlain = await attemptSend(() => api.sendMessage(chatId, withPrefix, htmlOpts));
|
|
274
|
+
if (needsPlain) {
|
|
275
|
+
await attemptSend(() => api.sendMessage(chatId, withPrefix.replace(/<[^>]+>/g, ''), plainOpts));
|
|
91
276
|
}
|
|
92
277
|
}
|
|
93
278
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rich-message.js","sourceRoot":"","sources":["../../../src/telegram/rich-message.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"rich-message.js","sourceRoot":"","sources":["../../../src/telegram/rich-message.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { InputFile } from 'grammy';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import { stripUndefined } from '../core/strip-undefined.js';
|
|
4
4
|
import { log } from '../core/logger.js';
|
|
5
|
+
import { redactOutboundText, logErrorText, userErrorText } from '../messaging/redact.js';
|
|
5
6
|
function asTgErr(err) {
|
|
6
7
|
return (err && typeof err === 'object') ? err : {};
|
|
7
8
|
}
|
|
@@ -21,10 +22,16 @@ const MAX_TOTAL_WAIT_MS = 60_000; // cumulative wait cap
|
|
|
21
22
|
* Throws with descriptive message if exceeded.
|
|
22
23
|
*/
|
|
23
24
|
export function validateFileSize(filePath, type) {
|
|
25
|
+
// stat first: the early return on an unknown type skipped every check,
|
|
26
|
+
// so a zero-byte file went out whenever the caller passed a type this
|
|
27
|
+
// table does not list.
|
|
28
|
+
const stat = fs.statSync(filePath);
|
|
29
|
+
if (stat.size === 0) {
|
|
30
|
+
throw Object.assign(new Error('Refusing to send a zero-byte file'), { code: 'FILE_EMPTY', statusCode: 400 });
|
|
31
|
+
}
|
|
24
32
|
const limit = TELEGRAM_LIMITS[type];
|
|
25
33
|
if (!limit)
|
|
26
34
|
return;
|
|
27
|
-
const stat = fs.statSync(filePath);
|
|
28
35
|
if (stat.size > limit) {
|
|
29
36
|
const limitMB = (limit / 1024 / 1024).toFixed(0);
|
|
30
37
|
const actualMB = (stat.size / 1024 / 1024).toFixed(1);
|
|
@@ -61,9 +68,30 @@ export function classifyUpstreamError(err) {
|
|
|
61
68
|
/**
|
|
62
69
|
* Send a file to Telegram with exponential backoff retry.
|
|
63
70
|
* Creates a fresh InputFile per attempt (stream safety).
|
|
71
|
+
*
|
|
72
|
+
* Size validation happens HERE rather than at the call sites. Leaving it to
|
|
73
|
+
* callers meant the Telegram Hub, which calls this directly, uploaded
|
|
74
|
+
* zero-byte files while every other path refused them.
|
|
64
75
|
*/
|
|
65
76
|
export async function sendTelegramFile(bot, chatId, filePath, type, opts) {
|
|
66
|
-
|
|
77
|
+
// Validate here, not at the call sites. The Hub's outbound relay calls this
|
|
78
|
+
// transport directly and skipped the check, which is how an empty document
|
|
79
|
+
// still reached the API after the guard was added.
|
|
80
|
+
try {
|
|
81
|
+
validateFileSize(filePath, type);
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
const e = asTgErr(err);
|
|
85
|
+
return stripUndefined({
|
|
86
|
+
ok: false,
|
|
87
|
+
attempts: 0,
|
|
88
|
+
error: userErrorText(err),
|
|
89
|
+
statusCode: e.statusCode ?? 400,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
// Captions reach the room like any other text, so they take the same
|
|
93
|
+
// last-mile masking the message body does.
|
|
94
|
+
const caption = opts?.caption === undefined ? undefined : redactOutboundText(opts.caption);
|
|
67
95
|
const message_thread_id = opts?.threadId; // P0: thread file sends into their topic
|
|
68
96
|
let totalWaited = 0;
|
|
69
97
|
for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
|
|
@@ -89,10 +117,13 @@ export async function sendTelegramFile(bot, chatId, filePath, type, opts) {
|
|
|
89
117
|
const transient = isTransient(err);
|
|
90
118
|
if (!transient || attempt === MAX_RETRIES) {
|
|
91
119
|
const sc = transient ? classifyUpstreamError(err) : (e.error_code || e.statusCode || 500);
|
|
92
|
-
log.error(`[telegram:file] failed after ${attempt} attempt(s):`,
|
|
120
|
+
log.error(`[telegram:file] failed after ${attempt} attempt(s):`, logErrorText(err));
|
|
93
121
|
return stripUndefined({
|
|
94
122
|
ok: false, attempts: attempt,
|
|
95
|
-
|
|
123
|
+
// This object becomes an HTTP response body, so it is a
|
|
124
|
+
// credential sink in its own right — grammY puts the Bot
|
|
125
|
+
// API URL, token and all, in some error messages.
|
|
126
|
+
error: userErrorText(err) || 'unknown error',
|
|
96
127
|
retryAfter: e.error_code === 429 ? e.parameters?.retry_after : undefined,
|
|
97
128
|
statusCode: sc,
|
|
98
129
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"telegram-file.js","sourceRoot":"","sources":["../../../src/telegram/telegram-file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAY,MAAM,QAAQ,CAAC;AAC7C,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"telegram-file.js","sourceRoot":"","sources":["../../../src/telegram/telegram-file.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ import { saveUpload } from '../agent/spawn.js';
|
|
|
5
5
|
import { downloadTelegramFile, TELEGRAM_DOWNLOAD_LIMITS } from '../../lib/upload.js';
|
|
6
6
|
import { transcribeVoice } from '../../lib/stt.js';
|
|
7
7
|
import { log } from '../core/logger.js';
|
|
8
|
+
import { redactOutboundText, logErrorText, userErrorText } from '../messaging/redact.js';
|
|
8
9
|
export async function handleVoice(ctx, currentLocale, tgOrchestrate) {
|
|
9
10
|
const voice = ctx.message.voice;
|
|
10
11
|
log.info(`[tg:voice] ${ctx.chat.id}: ${voice.duration}s, ${voice.file_size} bytes`);
|
|
@@ -16,7 +17,7 @@ export async function handleVoice(ctx, currentLocale, tgOrchestrate) {
|
|
|
16
17
|
}));
|
|
17
18
|
const filePath = saveUpload(dlResult.buffer, `voice${dlResult.ext || '.ogg'}`);
|
|
18
19
|
const stt = await transcribeVoice(filePath, 'audio/ogg');
|
|
19
|
-
log.info(`[tg:voice] STT (${stt.engine}): ${stt.elapsed.toFixed(1)}s → "${stt.text.slice(0, 60)}"`);
|
|
20
|
+
log.info(`[tg:voice] STT (${stt.engine}): ${stt.elapsed.toFixed(1)}s → "${redactOutboundText(stt.text).slice(0, 60)}"`);
|
|
20
21
|
if (!stt.text.trim()) {
|
|
21
22
|
await ctx.reply(t('tg.voiceEmpty', {}, currentLocale()));
|
|
22
23
|
return;
|
|
@@ -24,8 +25,8 @@ export async function handleVoice(ctx, currentLocale, tgOrchestrate) {
|
|
|
24
25
|
await tgOrchestrate(ctx, stt.text, `🎤 ${stt.text.slice(0, 80)}`);
|
|
25
26
|
}
|
|
26
27
|
catch (err) {
|
|
27
|
-
log.error('[tg:voice:error]', err);
|
|
28
|
-
await ctx.reply(t('tg.voiceFail', { msg: err
|
|
28
|
+
log.error('[tg:voice:error]', logErrorText(err));
|
|
29
|
+
await ctx.reply(t('tg.voiceFail', { msg: userErrorText(err) }, currentLocale()));
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
//# sourceMappingURL=voice.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"voice.js","sourceRoot":"","sources":["../../../src/telegram/voice.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"voice.js","sourceRoot":"","sources":["../../../src/telegram/voice.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEzF,MAAM,CAAC,KAAK,UAAU,WAAW,CAC7B,GAAY,EACZ,aAA2B,EAC3B,aAA+E;IAE/E,MAAM,KAAK,GAAG,GAAG,CAAC,OAAQ,CAAC,KAAM,CAAC;IAClC,GAAG,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,IAAK,CAAC,EAAE,KAAK,KAAK,CAAC,QAAQ,MAAM,KAAK,CAAC,SAAS,QAAQ,CAAC,CAAC;IACrF,IAAI,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,cAAc,CAAC;YAClG,IAAI,EAAE,OAAO;YACb,QAAQ,EAAE,wBAAwB,CAAC,KAAK;YACxC,QAAQ,EAAE,KAAK,CAAC,SAAS;SAC5B,CAAC,CAAC,CAAC;QACJ,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,QAAQ,CAAC,GAAG,IAAI,MAAM,EAAE,CAAC,CAAC;QAE/E,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QACzD,GAAG,CAAC,IAAI,CAAC,mBAAmB,GAAG,CAAC,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;QAExH,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;YACnB,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,eAAe,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;YACzD,OAAO;QACX,CAAC;QACD,MAAM,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACpB,GAAG,CAAC,KAAK,CAAC,kBAAkB,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QACjD,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;IACrF,CAAC;AACL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cli-jaw",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.11",
|
|
4
4
|
"description": "Personal AI assistant powered by Pi, Antigravity, AI-E, Claude, Claude E, Codex, Codex App, Cursor, Grok, Kiro, OpenCode, and Copilot — Web, Terminal, Telegram, and Discord interfaces with 107 built-in skills",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -108,6 +108,12 @@
|
|
|
108
108
|
"gate:workflow-common-layer-no-sdk": "node scripts/release-gates.mjs workflow-common-layer-no-sdk",
|
|
109
109
|
"gate:doc-drift": "node scripts/release-gates.mjs doc-drift",
|
|
110
110
|
"gate:strict-baseline": "node scripts/release-gates.mjs strict-baseline",
|
|
111
|
+
"gate:redaction-sinks": "node scripts/release-gates.mjs redaction-sinks",
|
|
112
|
+
"gate:electron-version": "node scripts/release-gates.mjs electron-version",
|
|
113
|
+
"gate:gate-docs": "node scripts/release-gates.mjs gate-docs",
|
|
114
|
+
"gate:sidecar-prune-safety": "node scripts/release-gates.mjs sidecar-prune-safety",
|
|
115
|
+
"check:sidecar-prune-safety": "node scripts/check-sidecar-prune-safety.mjs",
|
|
116
|
+
"sync:electron-version": "node scripts/sync-electron-version.cjs",
|
|
111
117
|
"gate:all": "node scripts/release-gates.mjs",
|
|
112
118
|
"prepublishOnly": "npm run build && npm run build:frontend && npm run check:frontend-build-output",
|
|
113
119
|
"electron:dev": "concurrently -k -n jaw,electron \"node scripts/electron-dev-manager.mjs\" \"npm --prefix electron run dev\"",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><title>Slack</title><path d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as e}from"./rolldown-runtime-XQCOJYun.js";import{n as t,t as n}from"./jsx-runtime-gFMgZ0TQ.js";import{a as r,i,n as a,r as o,t as s}from"./page-shell-LF7vVVfG.js";import{a as c,n as l,o as u,s as d}from"./fields-zkeByFQW.js";import{t as f}from"./path-utils-LsJeDCKF.js";import{n as p,t as m}from"./TransportStatusChips-CjEySMis.js";import{n as h,t as g}from"./HealthBadge-megTlF4n.js";var _=e(t(),1),v=n(),y=[`channel`,`discord.enabled`,`discord.token`,`discord.guildId`,`discord.channelIds`,`discord.forwardAll`,`discord.allowBots`,`discord.mentionOnly`];function b(e){return e?/^\d{5,32}$/.test(e.trim()):!1}function x({port:e,client:t,dirty:n,registerSave:x}){let{state:S,refresh:C,setData:w}=r(t,`/api/settings`),[T,E]=(0,_.useState)(!1),[D,O]=(0,_.useState)(``),[k,A]=(0,_.useState)(``),[j,M]=(0,_.useState)([]),[N,P]=(0,_.useState)(!0),[F,I]=(0,_.useState)(!1),[L,R]=(0,_.useState)(!1);(0,_.useEffect)(()=>{if(S.kind!==`ready`)return;let e=S.data.discord||{};E(!!e.enabled),O(``),A(e.guildId??``),M(Array.isArray(e.channelIds)?[...e.channelIds]:[]),P(e.forwardAll!==!1),I(!!e.allowBots),R(!!e.mentionOnly)},[S]),(0,_.useEffect)(()=>()=>{for(let e of y)n.remove(e)},[n]);let z=(0,_.useCallback)((e,t)=>n.set(e,t),[n]),B=(0,_.useMemo)(()=>S.kind===`ready`&&S.data.discord||{},[S]),V=S.kind===`ready`?S.data.channel:void 0,H=(0,_.useCallback)(async()=>{let e=n.saveBundle();if(Object.keys(e).length===0)return;let r=f(e),i=await t.put(`/api/settings`,r),a=i&&typeof i==`object`&&`data`in i?i.data:i;n.clear(),w(a);let o=a.discord||{};E(!!o.enabled),O(``),A(o.guildId??``),M(Array.isArray(o.channelIds)?[...o.channelIds]:[]),P(o.forwardAll!==!1),I(!!o.allowBots),R(!!o.mentionOnly),await C()},[t,n,C,w]);if((0,_.useEffect)(()=>{if(x)return x(H),()=>x(null)},[x,H]),S.kind===`loading`)return(0,v.jsx)(a,{});if(S.kind===`offline`)return(0,v.jsx)(o,{port:e});if(S.kind===`error`)return(0,v.jsx)(s,{message:S.message});let U=B.token?B.token.slice(-4):``,W=B.token?`••••••••${U}`:`(empty)`,G=k&&!b(k)?`Guild ID must be a numeric snowflake.`:null,K=j.filter(e=>!b(e)),q=K.length>0?`Snowflake IDs only — invalid: ${K.join(`, `)}`:null;return(0,v.jsxs)(`form`,{className:`settings-page-form`,onSubmit:e=>{e.preventDefault(),H()},children:[(0,v.jsxs)(i,{title:`Channels`,hint:`Choose which channel receives inbound chat. Outbound send can still work on the other channel when configured.`,children:[(0,v.jsx)(p,{original:V,dirty:n,idPrefix:`dc-channel`}),(0,v.jsx)(m,{client:t,channel:`discord`})]}),(0,v.jsxs)(i,{title:`Discord`,hint:`Bot token, guild + channels, forwarding rules.`,children:[(0,v.jsx)(c,{id:`dc-enabled`,label:`Discord enabled`,value:T,onChange:e=>{E(e),z(`discord.enabled`,{value:e,original:!!B.enabled,valid:!0})}}),(0,v.jsx)(u,{id:`dc-token`,label:`Bot token`,value:D,placeholder:W,onChange:e=>{if(O(e),e.length===0){n.remove(`discord.token`);return}z(`discord.token`,{value:e,original:B.token??``,valid:!0})}}),(0,v.jsx)(d,{id:`dc-guildId`,label:`Guild ID`,value:k,placeholder:`123456789012345678`,error:G,onChange:e=>{A(e);let t=e.length===0||b(e);z(`discord.guildId`,{value:e,original:B.guildId??``,valid:t})}}),(0,v.jsx)(l,{id:`dc-channelIds`,label:`Channel IDs`,value:j,placeholder:`987654321098765432`,error:q,onChange:e=>{M(e);let t=e.every(b);z(`discord.channelIds`,{value:e,original:B.channelIds??[],valid:t})}}),(0,v.jsx)(c,{id:`dc-forwardAll`,label:`Forward all`,value:N,onChange:e=>{P(e),z(`discord.forwardAll`,{value:e,original:B.forwardAll!==!1,valid:!0})}}),(0,v.jsx)(c,{id:`dc-allowBots`,label:`Allow other bots`,value:F,onChange:e=>{I(e),z(`discord.allowBots`,{value:e,original:!!B.allowBots,valid:!0})}}),(0,v.jsx)(c,{id:`dc-mentionOnly`,label:`Mention only`,value:L,onChange:e=>{R(e),z(`discord.mentionOnly`,{value:e,original:!!B.mentionOnly,valid:!0})}})]}),(0,v.jsx)(i,{title:`Health`,hint:`Probes /api/health for Discord readiness. Degraded mode means the bot is missing the MESSAGE_CONTENT intent (slash commands only).`,children:(0,v.jsx)(g,{client:t,label:`Discord`,endpoint:`/api/health`,method:`GET`,interpret:h})})]})}export{x as default,b as isValidSnowflake};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as e}from"./rolldown-runtime-XQCOJYun.js";import{n as t,t as n}from"./jsx-runtime-gFMgZ0TQ.js";import{a as r,i,n as a,r as o,t as s}from"./page-shell-LF7vVVfG.js";import{a as c,n as l,o as u,s as d}from"./fields-zkeByFQW.js";import{t as f}from"./path-utils-LsJeDCKF.js";import{n as p,t as m}from"./TransportStatusChips-CjEySMis.js";var h=e(t(),1),g=n(),_=[`channel`,`slack.enabled`,`slack.botToken`,`slack.appToken`,`slack.teamId`,`slack.channelIds`,`slack.forwardAll`,`slack.allowBots`,`slack.mentionOnly`,`slack.replyInThread`];function v(e){return e?/^[CGD][A-Z0-9]{6,20}$/.test(e.trim().toUpperCase()):!1}function y({port:e,client:t,dirty:n,registerSave:y}){let{state:b,refresh:x,setData:S}=r(t,`/api/settings`),[C,w]=(0,h.useState)(!1),[T,E]=(0,h.useState)(``),[D,O]=(0,h.useState)(``),[k,A]=(0,h.useState)(``),[j,M]=(0,h.useState)([]),[N,P]=(0,h.useState)(!0),[F,I]=(0,h.useState)(!1),[L,R]=(0,h.useState)(!0),[z,B]=(0,h.useState)(!0),V=(0,h.useCallback)(e=>{w(!!e.enabled),E(``),O(``),A(e.teamId??``),M(Array.isArray(e.channelIds)?[...e.channelIds]:[]),P(e.forwardAll!==!1),I(!!e.allowBots),R(e.mentionOnly!==!1),B(e.replyInThread!==!1)},[]);(0,h.useEffect)(()=>{b.kind===`ready`&&V(b.data.slack||{})},[b,V]),(0,h.useEffect)(()=>()=>{for(let e of _)n.remove(e)},[n]);let H=(0,h.useCallback)((e,t)=>n.set(e,t),[n]),U=(0,h.useMemo)(()=>b.kind===`ready`&&b.data.slack||{},[b]),W=b.kind===`ready`?b.data.channel:void 0,G=(0,h.useCallback)(async()=>{let e=n.saveBundle();if(Object.keys(e).length===0)return;let r=f(e),i=await t.put(`/api/settings`,r),a=i&&typeof i==`object`&&`data`in i?i.data:i;n.clear(),S(a),V(a.slack||{}),await x()},[t,n,x,S,V]);if((0,h.useEffect)(()=>{if(y)return y(G),()=>y(null)},[y,G]),b.kind===`loading`)return(0,g.jsx)(a,{});if(b.kind===`offline`)return(0,g.jsx)(o,{port:e});if(b.kind===`error`)return(0,g.jsx)(s,{message:b.message});let K=e=>e?`••••••••${e.slice(-4)}`:`(empty)`,q=j.filter(e=>!v(e)),J=q.length>0?`Slack conversation IDs only (C…/G…/D…) — invalid: ${q.join(`, `)}`:null,Y=T&&!T.startsWith(`xoxb-`)?`Bot tokens start with xoxb-.`:null,X=D&&!D.startsWith(`xapp-`)?`App-level tokens start with xapp-.`:null,Z=U.enabled&&U.botToken&&!U.appToken?`Currently OUTBOUND-ONLY: the app-level token (xapp-) is missing, so no inbound Slack events can arrive.`:`Slack needs TWO tokens: a bot token (xoxb-) for the Web API and an app-level token (xapp-) for Socket Mode.`;return(0,g.jsxs)(`form`,{className:`settings-page-form`,onSubmit:e=>{e.preventDefault(),G()},children:[(0,g.jsxs)(i,{title:`Channels`,hint:`Choose which channel receives inbound chat. Outbound send can still work on the other channels when configured.`,children:[(0,g.jsx)(p,{original:W,dirty:n,idPrefix:`sl-channel`}),(0,g.jsx)(m,{client:t,channel:`slack`})]}),(0,g.jsxs)(i,{title:`Slack`,hint:Z,children:[(0,g.jsx)(c,{id:`sl-enabled`,label:`Slack enabled`,value:C,onChange:e=>{w(e),H(`slack.enabled`,{value:e,original:!!U.enabled,valid:!0})}}),(0,g.jsx)(u,{id:`sl-botToken`,label:`Bot token`,value:T,placeholder:K(U.botToken),error:Y,onChange:e=>{if(E(e),e.length===0){n.remove(`slack.botToken`);return}H(`slack.botToken`,{value:e,original:U.botToken??``,valid:e.startsWith(`xoxb-`)})}}),(0,g.jsx)(u,{id:`sl-appToken`,label:`App-level token`,value:D,placeholder:K(U.appToken),error:X,onChange:e=>{if(O(e),e.length===0){n.remove(`slack.appToken`);return}H(`slack.appToken`,{value:e,original:U.appToken??``,valid:e.startsWith(`xapp-`)})}}),(0,g.jsx)(d,{id:`sl-teamId`,label:`Team ID`,value:k,placeholder:`T01234567 (optional)`,onChange:e=>{A(e),H(`slack.teamId`,{value:e,original:U.teamId??``,valid:!0})}}),(0,g.jsx)(l,{id:`sl-channelIds`,label:`Channel IDs`,value:j,placeholder:`C01234567`,error:J,onChange:e=>{M(e),H(`slack.channelIds`,{value:e,original:U.channelIds??[],valid:e.every(v)})}}),(0,g.jsx)(c,{id:`sl-mentionOnly`,label:`Mention only`,value:L,onChange:e=>{R(e),H(`slack.mentionOnly`,{value:e,original:U.mentionOnly!==!1,valid:!0})}}),(0,g.jsx)(c,{id:`sl-replyInThread`,label:`Reply in thread`,value:z,onChange:e=>{B(e),H(`slack.replyInThread`,{value:e,original:U.replyInThread!==!1,valid:!0})}}),(0,g.jsx)(c,{id:`sl-forwardAll`,label:`Forward all`,value:N,onChange:e=>{P(e),H(`slack.forwardAll`,{value:e,original:U.forwardAll!==!1,valid:!0})}}),(0,g.jsx)(c,{id:`sl-allowBots`,label:`Allow bots`,value:F,onChange:e=>{I(e),H(`slack.allowBots`,{value:e,original:!!U.allowBots,valid:!0})}})]})]})}export{y as default,v as isValidSlackConversationId};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as e}from"./rolldown-runtime-XQCOJYun.js";import{n as t,t as n}from"./jsx-runtime-gFMgZ0TQ.js";import{a as r,i,n as a,r as o,t as s}from"./page-shell-LF7vVVfG.js";import{a as c,n as l,o as u}from"./fields-zkeByFQW.js";import{t as d}from"./path-utils-LsJeDCKF.js";import{n as f,t as p}from"./TransportStatusChips-CjEySMis.js";import{r as m,t as h}from"./HealthBadge-megTlF4n.js";var g=e(t(),1),_=n(),v=[`channel`,`telegram.enabled`,`telegram.token`,`telegram.allowedChatIds`,`telegram.forwardAll`,`telegram.mentionOnly`];function y(e){return e?/^-?\d+$/.test(e.trim()):!1}function b(e){let t=[],n=[];for(let r of e)y(r)?t.push(r.trim()):n.push(r);return{valid:t,invalid:n}}function x(e){return e?e.filter(e=>Number.isFinite(e)).map(e=>String(e)):[]}function S(e){let t=[];for(let n of e){if(!y(n))continue;let e=Number(n);Number.isFinite(e)&&t.push(e)}return t}function C({port:e,client:t,dirty:n,registerSave:C}){let{state:w,refresh:T,setData:E}=r(t,`/api/settings`),[D,O]=(0,g.useState)(!1),[k,A]=(0,g.useState)(``),[j,M]=(0,g.useState)([]),[N,P]=(0,g.useState)(!0),[F,I]=(0,g.useState)(!0);(0,g.useEffect)(()=>{if(w.kind!==`ready`)return;let e=w.data.telegram||{};O(!!e.enabled),A(``),M(x(e.allowedChatIds)),P(e.forwardAll!==!1),I(e.mentionOnly!==!1)},[w]),(0,g.useEffect)(()=>()=>{for(let e of v)n.remove(e)},[n]);let L=(0,g.useCallback)((e,t)=>n.set(e,t),[n]),R=(0,g.useMemo)(()=>w.kind===`ready`&&w.data.telegram||{},[w]),z=w.kind===`ready`?w.data.channel:void 0,B=(0,g.useCallback)(async()=>{let e=n.saveBundle();if(Object.keys(e).length===0)return;let r=d(e),i=await t.put(`/api/settings`,r),a=i&&typeof i==`object`&&`data`in i?i.data:i;n.clear(),E(a);let o=a.telegram||{};O(!!o.enabled),A(``),M(x(o.allowedChatIds)),P(o.forwardAll!==!1),I(o.mentionOnly!==!1),await T()},[t,n,T,E]);if((0,g.useEffect)(()=>{if(C)return C(B),()=>C(null)},[C,B]),w.kind===`loading`)return(0,_.jsx)(a,{});if(w.kind===`offline`)return(0,_.jsx)(o,{port:e});if(w.kind===`error`)return(0,_.jsx)(s,{message:w.message});let V=R.token?R.token.slice(-4):``,H=R.token?`••••••••${V}`:`(empty)`,{invalid:U}=b(j),W=U.length>0?`Numeric chat IDs only — invalid: ${U.join(`, `)}`:null;return(0,_.jsxs)(`form`,{className:`settings-page-form`,onSubmit:e=>{e.preventDefault(),B()},children:[(0,_.jsxs)(i,{title:`Channels`,hint:`Choose which channel receives inbound chat. Outbound send can still work on the other channel when configured.`,children:[(0,_.jsx)(f,{original:z,dirty:n,idPrefix:`tg-channel`}),(0,_.jsx)(p,{client:t,channel:`telegram`})]}),(0,_.jsxs)(i,{title:`Telegram`,hint:`Bot token, allow-list, and forwarding rules.`,children:[(0,_.jsx)(c,{id:`tg-enabled`,label:`Telegram enabled`,value:D,onChange:e=>{O(e),L(`telegram.enabled`,{value:e,original:!!R.enabled,valid:!0})}}),(0,_.jsx)(u,{id:`tg-token`,label:`Bot token`,value:k,placeholder:H,onChange:e=>{if(A(e),e.length===0){n.remove(`telegram.token`);return}L(`telegram.token`,{value:e,original:R.token??``,valid:!0})}}),(0,_.jsx)(l,{id:`tg-allowedChatIds`,label:`Allowed chat IDs`,value:j,placeholder:`123456789`,error:W,onChange:e=>{M(e);let t=e.every(y);L(`telegram.allowedChatIds`,{value:S(e),original:R.allowedChatIds??[],valid:t})}}),(0,_.jsx)(c,{id:`tg-forwardAll`,label:`Forward all responses`,value:N,onChange:e=>{P(e),L(`telegram.forwardAll`,{value:e,original:R.forwardAll!==!1,valid:!0})}}),(0,_.jsx)(c,{id:`tg-mentionOnly`,label:`Mention only`,value:F,onChange:e=>{I(e),L(`telegram.mentionOnly`,{value:e,original:R.mentionOnly!==!1,valid:!0})}})]}),(0,_.jsx)(i,{title:`Health`,hint:`Probe the bot to confirm token + connectivity. 404 means the instance hasn't shipped the probe endpoint yet.`,children:(0,_.jsx)(h,{client:t,label:`Telegram`,endpoint:`/api/telegram/probe`,method:`POST`,interpret:m})})]})}export{x as chatIdsToChips,S as chipsToChatIds,C as default,y as isValidChatId,b as partitionChatIds};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as e}from"./rolldown-runtime-XQCOJYun.js";import{n as t,t as n}from"./jsx-runtime-gFMgZ0TQ.js";import{t as r}from"./settings-client-CjbBShxm.js";var i=e(t(),1),a=n();function o({client:e,label:t,endpoint:n,method:o=`GET`,interpret:l,auto:u=!1}){let[d,f]=(0,i.useState)({kind:`idle`}),p=(0,i.useRef)(null),m=(0,i.useRef)(!0),h=(0,i.useCallback)(async()=>{p.current?.abort();let t=new AbortController;p.current=t,f({kind:`checking`});try{let r=o===`POST`?await e.post(n,{},{signal:t.signal}):await e.get(n,{signal:t.signal});if(!m.current||t.signal.aborted)return;f(l(r))}catch(e){if(!m.current||t.signal.aborted)return;if(e instanceof r&&e.status===404){f({kind:`unknown`,reason:`Probe endpoint not implemented on this instance.`});return}f({kind:`error`,reason:e instanceof Error?e.message:String(e)})}},[e,n,l,o]);return(0,i.useEffect)(()=>(m.current=!0,u&&h(),()=>{m.current=!1,p.current?.abort()}),[u,h]),(0,a.jsxs)(`div`,{className:`settings-health-badge`,role:`status`,"aria-live":`polite`,children:[(0,a.jsx)(`button`,{type:`button`,className:`settings-action settings-action-discard`,onClick:()=>void h(),disabled:d.kind===`checking`,children:d.kind===`checking`?`Checking…`:`Check ${t}`}),(0,a.jsx)(`span`,{className:`settings-health-pill is-${d.kind}`,children:s(d)}),c(d)?(0,a.jsx)(`span`,{className:`settings-health-detail`,children:c(d)}):null]})}function s(e){switch(e.kind){case`idle`:return`Not checked`;case`checking`:return`Checking`;case`ok`:return`Healthy`;case`degraded`:return`Degraded`;case`unknown`:return`Unknown`;case`error`:return`Error`}}function c(e){return e.kind===`ok`&&e.detail||e.kind===`degraded`?e.detail:e.kind===`unknown`||e.kind===`error`?e.reason:null}function l(e){if(!e||typeof e!=`object`)return{kind:`unknown`,reason:`Empty probe response.`};let t=e;if(t.ok===!0){let e=typeof t.username==`string`?t.username:void 0;return e?{kind:`ok`,detail:`@${e}`}:{kind:`ok`}}return{kind:`error`,reason:typeof t.error==`string`?t.error:`Probe failed.`}}function u(e){if(!e||typeof e!=`object`)return{kind:`unknown`,reason:`Empty health response.`};let t=e,n=t.discord&&typeof t.discord==`object`?t.discord:null;return n?n.ready===!0&&n.degraded!==!0?{kind:`ok`}:n.degraded===!0?{kind:`degraded`,detail:typeof n.degradedReason==`string`?n.degradedReason:`MESSAGE_CONTENT intent missing — slash commands only.`}:n.ready===!1?{kind:`error`,reason:typeof n.error==`string`?n.error:`Bot not connected.`}:{kind:`unknown`,reason:`Discord status indeterminate.`}:{kind:`unknown`,reason:`No discord block in /api/health.`}}export{u as n,l as r,o as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as e}from"./rolldown-runtime-XQCOJYun.js";import{n as t,t as n}from"./jsx-runtime-gFMgZ0TQ.js";var r=e(t(),1),i=n(),a=[{value:`telegram`,label:`Telegram`},{value:`discord`,label:`Discord`},{value:`slack`,label:`Slack`}];function o({original:e,dirty:t,idPrefix:n=`channel`}){let[o,s]=(0,r.useState)(e??`telegram`),c=(0,r.useCallback)(n=>{s(n),t.set(`channel`,{value:n,original:e??`telegram`,valid:!0})},[t,e]);return(0,i.jsxs)(`fieldset`,{className:`settings-field settings-field-active-channel`,"aria-label":`Active inbound channel`,children:[(0,i.jsx)(`legend`,{className:`settings-field-label`,children:`Active inbound channel (chat replies)`}),(0,i.jsx)(`div`,{className:`settings-active-channel-options`,role:`radiogroup`,children:a.map(e=>{let t=`${n}-${e.value}`,r=o===e.value;return(0,i.jsxs)(`label`,{htmlFor:t,className:`settings-radio`,children:[(0,i.jsx)(`input`,{id:t,type:`radio`,name:n,value:e.value,checked:r,onChange:()=>c(e.value)}),(0,i.jsx)(`span`,{children:e.label})]},e.value)})})]})}function s(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.configured==`boolean`&&typeof t.activeInbound==`boolean`&&typeof t.sendCapable==`boolean`}function c(e){if(!e||typeof e!=`object`)return null;let t=e.channels;if(!t||typeof t!=`object`)return null;let n=t,r=n.activeInbound;if(r!==`telegram`&&r!==`discord`&&r!==`slack`||!s(n.telegram)||!s(n.discord))return null;let i=s(n.slack)?n.slack:{configured:!1,activeInbound:!1,sendCapable:!1,reason:`unavailable`};return{activeInbound:r,telegram:n.telegram,discord:n.discord,slack:i}}function l(e){let t=[];return t.push(e.configured?`Configured`:`Not configured`),e.sendCapable&&t.push(`Send-capable`),e.activeInbound&&t.push(`Active inbound`),t}function u({client:e,channel:t}){let[n,a]=(0,r.useState)(null),[o,s]=(0,r.useState)(null),u=(0,r.useRef)(!0),d=(0,r.useCallback)(async()=>{try{let t=await e.get(`/api/health`);if(!u.current)return;let n=c(t);a(n),s(n?null:`Channel health unavailable on this instance.`)}catch(e){if(!u.current)return;a(null),s(e instanceof Error?e.message:String(e))}},[e]);(0,r.useEffect)(()=>(u.current=!0,d(),()=>{u.current=!1}),[d]);let f=n?.[t]??null,p=!!(f?.configured&&f.sendCapable&&!f.activeInbound);return(0,i.jsxs)(`div`,{className:`settings-transport-status`,role:`status`,"aria-live":`polite`,children:[o?(0,i.jsx)(`p`,{className:`settings-field-hint`,children:o}):null,f?(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(`div`,{className:`settings-transport-chips`,children:l(f).map(e=>(0,i.jsx)(`span`,{className:`settings-health-pill is-ok`,children:e},e))}),p?(0,i.jsx)(`p`,{className:`settings-field-hint`,children:`This transport is not receiving inbound messages, but send-only delivery remains available.`}):null]}):null,(0,i.jsx)(`button`,{type:`button`,className:`settings-action settings-action-discard`,onClick:()=>void d(),children:`Refresh transport status`})]})}export{o as n,u as t};
|