@0xmaxma/claude-gateway 1.7.6 → 1.7.7
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.md +1 -1
- package/dist/agent/builtin-commands.d.ts +2 -1
- package/dist/agent/builtin-commands.d.ts.map +1 -1
- package/dist/agent/builtin-commands.js.map +1 -1
- package/dist/agent/incident.d.ts +1 -1
- package/dist/agent/incident.d.ts.map +1 -1
- package/dist/agent/runner.d.ts +7 -2
- package/dist/agent/runner.d.ts.map +1 -1
- package/dist/agent/runner.js +91 -7
- package/dist/agent/runner.js.map +1 -1
- package/dist/api/line-webhook-router.js +8 -8
- package/dist/api/line-webhook-router.js.map +1 -1
- package/dist/api/{line-pending-senders.d.ts → pending-senders.d.ts} +13 -13
- package/dist/api/pending-senders.d.ts.map +1 -0
- package/dist/api/pending-senders.js +128 -0
- package/dist/api/pending-senders.js.map +1 -0
- package/dist/api/router.d.ts.map +1 -1
- package/dist/api/router.js +296 -10
- package/dist/api/router.js.map +1 -1
- package/dist/api/slack-access.d.ts +74 -0
- package/dist/api/slack-access.d.ts.map +1 -0
- package/dist/api/slack-access.js +78 -0
- package/dist/api/slack-access.js.map +1 -0
- package/dist/api/slack-client.d.ts +68 -0
- package/dist/api/slack-client.d.ts.map +1 -0
- package/dist/api/slack-client.js +121 -0
- package/dist/api/slack-client.js.map +1 -0
- package/dist/api/slack-webhook-router.d.ts +34 -0
- package/dist/api/slack-webhook-router.d.ts.map +1 -0
- package/dist/api/slack-webhook-router.js +280 -0
- package/dist/api/slack-webhook-router.js.map +1 -0
- package/dist/api/webhooks-router.d.ts +18 -9
- package/dist/api/webhooks-router.d.ts.map +1 -1
- package/dist/api/webhooks-router.js +12 -7
- package/dist/api/webhooks-router.js.map +1 -1
- package/dist/cli-viewer/pairing-store.d.ts +3 -2
- package/dist/cli-viewer/pairing-store.d.ts.map +1 -1
- package/dist/cli-viewer/pairing-store.js +3 -5
- package/dist/cli-viewer/pairing-store.js.map +1 -1
- package/dist/history/types.d.ts +29 -1
- package/dist/history/types.d.ts.map +1 -1
- package/dist/history/types.js +32 -0
- package/dist/history/types.js.map +1 -1
- package/dist/session/compactor.d.ts +2 -1
- package/dist/session/compactor.d.ts.map +1 -1
- package/dist/session/compactor.js.map +1 -1
- package/dist/session/process.d.ts +3 -2
- package/dist/session/process.d.ts.map +1 -1
- package/dist/session/process.js +17 -6
- package/dist/session/process.js.map +1 -1
- package/dist/session/store.d.ts +14 -13
- package/dist/session/store.d.ts.map +1 -1
- package/dist/session/store.js +7 -2
- package/dist/session/store.js.map +1 -1
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/cli-viewer-ui.d.ts +2 -1
- package/dist/ui/cli-viewer-ui.d.ts.map +1 -1
- package/dist/ui/cli-viewer-ui.js.map +1 -1
- package/mcp/server.ts +2 -0
- package/mcp/tools/slack/module.ts +113 -0
- package/package.json +1 -1
- package/dist/api/line-pending-senders.d.ts.map +0 -1
- package/dist/api/line-pending-senders.js +0 -112
- package/dist/api/line-pending-senders.js.map +0 -1
package/dist/api/router.js
CHANGED
|
@@ -47,11 +47,36 @@ const runner_1 = require("../agent/runner");
|
|
|
47
47
|
const auth_1 = require("./auth");
|
|
48
48
|
const media_store_1 = require("../history/media-store");
|
|
49
49
|
const db_1 = require("../history/db");
|
|
50
|
+
const types_1 = require("../history/types");
|
|
50
51
|
const wizard_state_1 = require("./wizard-state");
|
|
51
|
-
const
|
|
52
|
+
const pending_senders_1 = require("./pending-senders");
|
|
52
53
|
const create_agent_prompts_1 = require("../agent/create-agent-prompts");
|
|
53
54
|
const MAX_MESSAGE_LENGTH = 10000;
|
|
54
55
|
const DEFAULT_TIMEOUT_MS = 60000;
|
|
56
|
+
/**
|
|
57
|
+
* Standalone `auth.test` call for the Slack connect flow's Save-time token
|
|
58
|
+
* check (see the PATCH /agents/:agentId handler below). Not SlackClient
|
|
59
|
+
* (src/api/slack-client.ts) — that class requires a logDir-backed logger,
|
|
60
|
+
* which this router has no other reason to plumb through for one validation
|
|
61
|
+
* call. form-urlencoded per slack-client.ts's own finding (JSON is not
|
|
62
|
+
* reliably parsed by every Slack Web API method).
|
|
63
|
+
*/
|
|
64
|
+
async function verifySlackBotToken(botToken) {
|
|
65
|
+
try {
|
|
66
|
+
const res = await fetch('https://slack.com/api/auth.test', {
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers: {
|
|
69
|
+
Authorization: `Bearer ${botToken}`,
|
|
70
|
+
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
const json = (await res.json());
|
|
74
|
+
return { ok: json.ok, error: json.error };
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
return { ok: false, error: err instanceof Error ? err.message : 'network error' };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
55
80
|
const AGENT_ID_RE = /^[a-z][a-z0-9_-]{1,31}$/;
|
|
56
81
|
const SAFE_FILENAME_RE = /^[a-zA-Z0-9._\-() ]+$/;
|
|
57
82
|
// session_id becomes a filesystem key (sessions/<id>.jsonl, .sessions/<id>/) so it
|
|
@@ -577,6 +602,18 @@ function createApiRouter(agentRunners, agentConfigs, apiKeys, configPath, models
|
|
|
577
602
|
// Pairing toggle (orthogonal to dm/groupPolicy). Absent ⇒ on; surface a
|
|
578
603
|
// concrete boolean so the UI toggle reflects the effective default.
|
|
579
604
|
line_pairing: cfg.line?.channelSecret ? (cfg.line?.pairing ?? true) : null,
|
|
605
|
+
// Slack — same shape/semantics as LINE above, field-for-field
|
|
606
|
+
// (dmPolicy/groupPolicy/requireMention/pairing), gated on
|
|
607
|
+
// signingSecret the way LINE gates on channelSecret.
|
|
608
|
+
slack_connected: !!cfg.slack?.signingSecret,
|
|
609
|
+
slack_token_preview: cfg.slack?.botToken ? maskToken(cfg.slack.botToken) : null,
|
|
610
|
+
slack_webhook_path: cfg.slack?.signingSecret ? `/webhooks/slack/${id}` : null,
|
|
611
|
+
slack_dm_policy: cfg.slack?.signingSecret ? (cfg.slack?.dmPolicy ?? null) : null,
|
|
612
|
+
slack_dm_allowlist: cfg.slack?.signingSecret ? (cfg.slack?.dmAllowlist ?? []) : null,
|
|
613
|
+
slack_group_policy: cfg.slack?.signingSecret ? (cfg.slack?.groupPolicy ?? null) : null,
|
|
614
|
+
slack_group_allowlist: cfg.slack?.signingSecret ? (cfg.slack?.groupAllowlist ?? []) : null,
|
|
615
|
+
slack_require_mention: cfg.slack?.signingSecret ? (cfg.slack?.requireMention ?? null) : null,
|
|
616
|
+
slack_pairing: cfg.slack?.signingSecret ? (cfg.slack?.pairing ?? true) : null,
|
|
580
617
|
}));
|
|
581
618
|
res.json({ agents });
|
|
582
619
|
});
|
|
@@ -1264,7 +1301,7 @@ function createApiRouter(agentRunners, agentConfigs, apiKeys, configPath, models
|
|
|
1264
1301
|
return;
|
|
1265
1302
|
}
|
|
1266
1303
|
const body = req.body;
|
|
1267
|
-
const { name, description, model, allow_tools, telegram_bot_token, discord_bot_token, line_channel_access_token, line_channel_secret, line_dm_policy, line_dm_allowlist, line_group_policy, line_group_allowlist, line_require_mention, line_pairing } = body;
|
|
1304
|
+
const { name, description, model, allow_tools, telegram_bot_token, discord_bot_token, line_channel_access_token, line_channel_secret, line_dm_policy, line_dm_allowlist, line_group_policy, line_group_allowlist, line_require_mention, line_pairing, slack_bot_token, slack_signing_secret, slack_dm_policy, slack_dm_allowlist, slack_group_policy, slack_group_allowlist, slack_require_mention, slack_pairing } = body;
|
|
1268
1305
|
if (name !== undefined && name !== null && typeof name !== 'string') {
|
|
1269
1306
|
res.status(400).json({ error: 'name must be a string or null' });
|
|
1270
1307
|
return;
|
|
@@ -1346,6 +1383,76 @@ function createApiRouter(agentRunners, agentConfigs, apiKeys, configPath, models
|
|
|
1346
1383
|
const lineAccessTouched = line_dm_policy !== undefined || line_dm_allowlist !== undefined ||
|
|
1347
1384
|
line_group_policy !== undefined || line_group_allowlist !== undefined || line_require_mention !== undefined ||
|
|
1348
1385
|
line_pairing !== undefined;
|
|
1386
|
+
// Slack — same validation shape as LINE above, field-for-field.
|
|
1387
|
+
if (slack_bot_token !== undefined && slack_bot_token !== null && typeof slack_bot_token !== 'string') {
|
|
1388
|
+
res.status(400).json({ error: 'slack_bot_token must be a string or null' });
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
if (slack_signing_secret !== undefined && slack_signing_secret !== null && typeof slack_signing_secret !== 'string') {
|
|
1392
|
+
res.status(400).json({ error: 'slack_signing_secret must be a string or null' });
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1395
|
+
// Slack needs BOTH credentials together, same as LINE's access token + secret pair.
|
|
1396
|
+
const slackTouched = slack_bot_token !== undefined || slack_signing_secret !== undefined;
|
|
1397
|
+
if (slackTouched) {
|
|
1398
|
+
const tok = typeof slack_bot_token === 'string' ? slack_bot_token.trim() : '';
|
|
1399
|
+
const sec = typeof slack_signing_secret === 'string' ? slack_signing_secret.trim() : '';
|
|
1400
|
+
const bothSet = tok !== '' && sec !== '';
|
|
1401
|
+
const bothClear = tok === '' && sec === '';
|
|
1402
|
+
if (!bothSet && !bothClear) {
|
|
1403
|
+
res.status(400).json({ error: 'slack_bot_token and slack_signing_secret must be provided together' });
|
|
1404
|
+
return;
|
|
1405
|
+
}
|
|
1406
|
+
// Reject a bad/expired token at Save time instead of persisting it silently
|
|
1407
|
+
// (the failure would otherwise only surface later, when the agent tries to
|
|
1408
|
+
// reply and gets a Slack API error). Mirrors openclaw's startup `auth.test`
|
|
1409
|
+
// call — see slack-client.ts's authTest() doc comment, which named this as
|
|
1410
|
+
// the intended Save-time check. A standalone fetch rather than SlackClient
|
|
1411
|
+
// itself: SlackClient's constructor requires a logDir-backed logger this
|
|
1412
|
+
// router has no other reason to plumb through for one validation call.
|
|
1413
|
+
if (bothSet) {
|
|
1414
|
+
const verify = await verifySlackBotToken(tok);
|
|
1415
|
+
if (!verify.ok) {
|
|
1416
|
+
res.status(400).json({
|
|
1417
|
+
error: `Invalid Slack bot token — auth.test failed: ${verify.error ?? 'unknown error'}`,
|
|
1418
|
+
});
|
|
1419
|
+
return;
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
if (slack_dm_policy !== undefined && slack_dm_policy !== null &&
|
|
1424
|
+
!(typeof slack_dm_policy === 'string' && ['open', 'allowlist', 'disabled'].includes(slack_dm_policy))) {
|
|
1425
|
+
res.status(400).json({ error: "slack_dm_policy must be 'open', 'allowlist', 'disabled', or null" });
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1428
|
+
if (slack_dm_allowlist !== undefined && slack_dm_allowlist !== null &&
|
|
1429
|
+
!(Array.isArray(slack_dm_allowlist) && slack_dm_allowlist.every((u) => typeof u === 'string'))) {
|
|
1430
|
+
res.status(400).json({ error: 'slack_dm_allowlist must be an array of strings or null' });
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
if (slack_group_policy !== undefined && slack_group_policy !== null &&
|
|
1434
|
+
!(typeof slack_group_policy === 'string' && ['open', 'allowlist', 'disabled'].includes(slack_group_policy))) {
|
|
1435
|
+
res.status(400).json({ error: "slack_group_policy must be 'open', 'allowlist', 'disabled', or null" });
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
if (slack_group_allowlist !== undefined && slack_group_allowlist !== null &&
|
|
1439
|
+
!(Array.isArray(slack_group_allowlist) && slack_group_allowlist.every((u) => typeof u === 'string'))) {
|
|
1440
|
+
res.status(400).json({ error: 'slack_group_allowlist must be an array of strings or null' });
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1443
|
+
if (slack_require_mention !== undefined && slack_require_mention !== null &&
|
|
1444
|
+
typeof slack_require_mention !== 'boolean') {
|
|
1445
|
+
res.status(400).json({ error: 'slack_require_mention must be a boolean or null' });
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
if (slack_pairing !== undefined && slack_pairing !== null &&
|
|
1449
|
+
typeof slack_pairing !== 'boolean') {
|
|
1450
|
+
res.status(400).json({ error: 'slack_pairing must be a boolean or null' });
|
|
1451
|
+
return;
|
|
1452
|
+
}
|
|
1453
|
+
const slackAccessTouched = slack_dm_policy !== undefined || slack_dm_allowlist !== undefined ||
|
|
1454
|
+
slack_group_policy !== undefined || slack_group_allowlist !== undefined || slack_require_mention !== undefined ||
|
|
1455
|
+
slack_pairing !== undefined;
|
|
1349
1456
|
try {
|
|
1350
1457
|
await writeAgentsToConfig(configPath, (agents) => {
|
|
1351
1458
|
const agent = agents.find((a) => a.id === agentId);
|
|
@@ -1439,6 +1546,62 @@ function createApiRouter(agentRunners, agentConfigs, apiKeys, configPath, models
|
|
|
1439
1546
|
}
|
|
1440
1547
|
}
|
|
1441
1548
|
}
|
|
1549
|
+
if (slackTouched) {
|
|
1550
|
+
const tok = typeof slack_bot_token === 'string' ? slack_bot_token.trim() : '';
|
|
1551
|
+
const sec = typeof slack_signing_secret === 'string' ? slack_signing_secret.trim() : '';
|
|
1552
|
+
if (tok === '' && sec === '') {
|
|
1553
|
+
delete agent.slack;
|
|
1554
|
+
}
|
|
1555
|
+
else {
|
|
1556
|
+
const existing = agent.slack;
|
|
1557
|
+
agent.slack = { ...(existing ?? {}), botToken: tok, signingSecret: sec };
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
// Access fields — merge into the existing slack block (re-read after the
|
|
1561
|
+
// credential block above, which may have just created or deleted it).
|
|
1562
|
+
// Skip silently when no slack channel exists; policy without credentials
|
|
1563
|
+
// is meaningless.
|
|
1564
|
+
if (slackAccessTouched) {
|
|
1565
|
+
const existing = agent.slack;
|
|
1566
|
+
if (existing) {
|
|
1567
|
+
if (slack_dm_policy !== undefined) {
|
|
1568
|
+
if (slack_dm_policy === null)
|
|
1569
|
+
delete existing.dmPolicy;
|
|
1570
|
+
else
|
|
1571
|
+
existing.dmPolicy = slack_dm_policy;
|
|
1572
|
+
}
|
|
1573
|
+
if (slack_dm_allowlist !== undefined) {
|
|
1574
|
+
if (slack_dm_allowlist === null)
|
|
1575
|
+
delete existing.dmAllowlist;
|
|
1576
|
+
else
|
|
1577
|
+
existing.dmAllowlist = slack_dm_allowlist;
|
|
1578
|
+
}
|
|
1579
|
+
if (slack_group_policy !== undefined) {
|
|
1580
|
+
if (slack_group_policy === null)
|
|
1581
|
+
delete existing.groupPolicy;
|
|
1582
|
+
else
|
|
1583
|
+
existing.groupPolicy = slack_group_policy;
|
|
1584
|
+
}
|
|
1585
|
+
if (slack_group_allowlist !== undefined) {
|
|
1586
|
+
if (slack_group_allowlist === null)
|
|
1587
|
+
delete existing.groupAllowlist;
|
|
1588
|
+
else
|
|
1589
|
+
existing.groupAllowlist = slack_group_allowlist;
|
|
1590
|
+
}
|
|
1591
|
+
if (slack_require_mention !== undefined) {
|
|
1592
|
+
if (slack_require_mention === null)
|
|
1593
|
+
delete existing.requireMention;
|
|
1594
|
+
else
|
|
1595
|
+
existing.requireMention = slack_require_mention;
|
|
1596
|
+
}
|
|
1597
|
+
if (slack_pairing !== undefined) {
|
|
1598
|
+
if (slack_pairing === null)
|
|
1599
|
+
delete existing.pairing;
|
|
1600
|
+
else
|
|
1601
|
+
existing.pairing = slack_pairing;
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1442
1605
|
});
|
|
1443
1606
|
}
|
|
1444
1607
|
catch (err) {
|
|
@@ -1561,11 +1724,74 @@ function createApiRouter(agentRunners, agentConfigs, apiKeys, configPath, models
|
|
|
1561
1724
|
// in-memory knock list so the discovery UI stops surfacing them.
|
|
1562
1725
|
if (Array.isArray(line_dm_allowlist)) {
|
|
1563
1726
|
for (const userId of line_dm_allowlist)
|
|
1564
|
-
(0,
|
|
1727
|
+
(0, pending_senders_1.clearPendingSender)('line', agentId, userId);
|
|
1565
1728
|
}
|
|
1566
1729
|
if (Array.isArray(line_group_allowlist)) {
|
|
1567
1730
|
for (const id of line_group_allowlist)
|
|
1568
|
-
(0,
|
|
1731
|
+
(0, pending_senders_1.clearPendingSender)('line', agentId, id);
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
if (slackTouched) {
|
|
1735
|
+
const tok = typeof slack_bot_token === 'string' ? slack_bot_token.trim() : '';
|
|
1736
|
+
const sec = typeof slack_signing_secret === 'string' ? slack_signing_secret.trim() : '';
|
|
1737
|
+
if (tok && sec) {
|
|
1738
|
+
cfg.slack = { ...(cfg.slack ?? {}), botToken: tok, signingSecret: sec };
|
|
1739
|
+
}
|
|
1740
|
+
else {
|
|
1741
|
+
delete cfg.slack;
|
|
1742
|
+
}
|
|
1743
|
+
// Slack is webhook-based — no receiver to start/stop. The webhook router
|
|
1744
|
+
// reads config live via runner.getAgentConfig(); just keep the runner's
|
|
1745
|
+
// copy in sync (same as LINE above).
|
|
1746
|
+
agentRunners.get(agentId)?.updateAgentConfig(cfg);
|
|
1747
|
+
}
|
|
1748
|
+
if (slackAccessTouched && cfg.slack) {
|
|
1749
|
+
if (slack_dm_policy !== undefined) {
|
|
1750
|
+
if (slack_dm_policy === null)
|
|
1751
|
+
delete cfg.slack.dmPolicy;
|
|
1752
|
+
else
|
|
1753
|
+
cfg.slack.dmPolicy = slack_dm_policy;
|
|
1754
|
+
}
|
|
1755
|
+
if (slack_dm_allowlist !== undefined) {
|
|
1756
|
+
if (slack_dm_allowlist === null)
|
|
1757
|
+
delete cfg.slack.dmAllowlist;
|
|
1758
|
+
else
|
|
1759
|
+
cfg.slack.dmAllowlist = slack_dm_allowlist;
|
|
1760
|
+
}
|
|
1761
|
+
if (slack_group_policy !== undefined) {
|
|
1762
|
+
if (slack_group_policy === null)
|
|
1763
|
+
delete cfg.slack.groupPolicy;
|
|
1764
|
+
else
|
|
1765
|
+
cfg.slack.groupPolicy = slack_group_policy;
|
|
1766
|
+
}
|
|
1767
|
+
if (slack_group_allowlist !== undefined) {
|
|
1768
|
+
if (slack_group_allowlist === null)
|
|
1769
|
+
delete cfg.slack.groupAllowlist;
|
|
1770
|
+
else
|
|
1771
|
+
cfg.slack.groupAllowlist = slack_group_allowlist;
|
|
1772
|
+
}
|
|
1773
|
+
if (slack_require_mention !== undefined) {
|
|
1774
|
+
if (slack_require_mention === null)
|
|
1775
|
+
delete cfg.slack.requireMention;
|
|
1776
|
+
else
|
|
1777
|
+
cfg.slack.requireMention = slack_require_mention;
|
|
1778
|
+
}
|
|
1779
|
+
if (slack_pairing !== undefined) {
|
|
1780
|
+
if (slack_pairing === null)
|
|
1781
|
+
delete cfg.slack.pairing;
|
|
1782
|
+
else
|
|
1783
|
+
cfg.slack.pairing = slack_pairing;
|
|
1784
|
+
}
|
|
1785
|
+
agentRunners.get(agentId)?.updateAgentConfig(cfg);
|
|
1786
|
+
// Anyone just added to an allowlist is now allowed — drop them from the
|
|
1787
|
+
// in-memory knock list so the discovery UI stops surfacing them.
|
|
1788
|
+
if (Array.isArray(slack_dm_allowlist)) {
|
|
1789
|
+
for (const userId of slack_dm_allowlist)
|
|
1790
|
+
(0, pending_senders_1.clearPendingSender)('slack', agentId, userId);
|
|
1791
|
+
}
|
|
1792
|
+
if (Array.isArray(slack_group_allowlist)) {
|
|
1793
|
+
for (const id of slack_group_allowlist)
|
|
1794
|
+
(0, pending_senders_1.clearPendingSender)('slack', agentId, id);
|
|
1569
1795
|
}
|
|
1570
1796
|
}
|
|
1571
1797
|
res.json({
|
|
@@ -1592,6 +1818,24 @@ function createApiRouter(agentRunners, agentConfigs, apiKeys, configPath, models
|
|
|
1592
1818
|
line_connected: !!cfg.line?.channelSecret,
|
|
1593
1819
|
line_token_preview: cfg.line?.channelAccessToken ? maskToken(cfg.line.channelAccessToken) : null,
|
|
1594
1820
|
line_webhook_path: cfg.line?.channelSecret ? `/webhooks/line/${agentId}` : null,
|
|
1821
|
+
line_dm_policy: cfg.line?.channelSecret ? (cfg.line?.dmPolicy ?? null) : null,
|
|
1822
|
+
line_dm_allowlist: cfg.line?.channelSecret ? (cfg.line?.dmAllowlist ?? []) : null,
|
|
1823
|
+
line_group_policy: cfg.line?.channelSecret ? (cfg.line?.groupPolicy ?? null) : null,
|
|
1824
|
+
line_group_allowlist: cfg.line?.channelSecret ? (cfg.line?.groupAllowlist ?? []) : null,
|
|
1825
|
+
line_require_mention: cfg.line?.channelSecret ? (cfg.line?.requireMention ?? null) : null,
|
|
1826
|
+
line_pairing: cfg.line?.channelSecret ? (cfg.line?.pairing ?? true) : null,
|
|
1827
|
+
// Slack — same shape/semantics as LINE above, mirrors the GET /agents
|
|
1828
|
+
// list response exactly (this PATCH response never carried these
|
|
1829
|
+
// fields at all before — the UI fell back to the next GET refetch).
|
|
1830
|
+
slack_connected: !!cfg.slack?.signingSecret,
|
|
1831
|
+
slack_token_preview: cfg.slack?.botToken ? maskToken(cfg.slack.botToken) : null,
|
|
1832
|
+
slack_webhook_path: cfg.slack?.signingSecret ? `/webhooks/slack/${agentId}` : null,
|
|
1833
|
+
slack_dm_policy: cfg.slack?.signingSecret ? (cfg.slack?.dmPolicy ?? null) : null,
|
|
1834
|
+
slack_dm_allowlist: cfg.slack?.signingSecret ? (cfg.slack?.dmAllowlist ?? []) : null,
|
|
1835
|
+
slack_group_policy: cfg.slack?.signingSecret ? (cfg.slack?.groupPolicy ?? null) : null,
|
|
1836
|
+
slack_group_allowlist: cfg.slack?.signingSecret ? (cfg.slack?.groupAllowlist ?? []) : null,
|
|
1837
|
+
slack_require_mention: cfg.slack?.signingSecret ? (cfg.slack?.requireMention ?? null) : null,
|
|
1838
|
+
slack_pairing: cfg.slack?.signingSecret ? (cfg.slack?.pairing ?? true) : null,
|
|
1595
1839
|
},
|
|
1596
1840
|
});
|
|
1597
1841
|
});
|
|
@@ -1804,7 +2048,7 @@ function createApiRouter(agentRunners, agentConfigs, apiKeys, configPath, models
|
|
|
1804
2048
|
res.status(404).json({ error: `Agent '${agentId}' not found` });
|
|
1805
2049
|
return;
|
|
1806
2050
|
}
|
|
1807
|
-
res.json({ senders: (0,
|
|
2051
|
+
res.json({ senders: (0, pending_senders_1.getPendingSenders)('line', agentId) });
|
|
1808
2052
|
});
|
|
1809
2053
|
/**
|
|
1810
2054
|
* DELETE /api/v1/agents/:agentId/line/pending/:senderId
|
|
@@ -1825,7 +2069,47 @@ function createApiRouter(agentRunners, agentConfigs, apiKeys, configPath, models
|
|
|
1825
2069
|
res.status(404).json({ error: `Agent '${agentId}' not found` });
|
|
1826
2070
|
return;
|
|
1827
2071
|
}
|
|
1828
|
-
(0,
|
|
2072
|
+
(0, pending_senders_1.clearPendingSender)('line', agentId, senderId);
|
|
2073
|
+
res.json({ ok: true });
|
|
2074
|
+
});
|
|
2075
|
+
/**
|
|
2076
|
+
* GET /api/v1/agents/:agentId/slack/pending
|
|
2077
|
+
* Recently denied Slack senders (Tier 1 allowlist discovery aid). Admin only.
|
|
2078
|
+
* Mirrors GET .../line/pending exactly, keyed under the 'slack' channel
|
|
2079
|
+
* namespace in the shared pending-senders store so LINE and Slack knocks on
|
|
2080
|
+
* the same agent never mix.
|
|
2081
|
+
*/
|
|
2082
|
+
router.get('/v1/agents/:agentId/slack/pending', auth, (req, res) => {
|
|
2083
|
+
const { agentId } = req.params;
|
|
2084
|
+
const apiKey = req.apiKey;
|
|
2085
|
+
if (!(0, auth_1.isAdmin)(apiKey)) {
|
|
2086
|
+
res.status(403).json({ error: 'Admin key required' });
|
|
2087
|
+
return;
|
|
2088
|
+
}
|
|
2089
|
+
if (!agentConfigs.has(agentId)) {
|
|
2090
|
+
res.status(404).json({ error: `Agent '${agentId}' not found` });
|
|
2091
|
+
return;
|
|
2092
|
+
}
|
|
2093
|
+
res.json({ senders: (0, pending_senders_1.getPendingSenders)('slack', agentId) });
|
|
2094
|
+
});
|
|
2095
|
+
/**
|
|
2096
|
+
* DELETE /api/v1/agents/:agentId/slack/pending/:senderId
|
|
2097
|
+
* Dismiss one knock from the in-memory pending list (admin only). Mirrors
|
|
2098
|
+
* DELETE .../line/pending/:senderId exactly. The id is a Slack user id (DM)
|
|
2099
|
+
* or channel id (channel/group/mpim), so no numeric validation.
|
|
2100
|
+
*/
|
|
2101
|
+
router.delete('/v1/agents/:agentId/slack/pending/:senderId', auth, (req, res) => {
|
|
2102
|
+
const apiKey = req.apiKey;
|
|
2103
|
+
if (!(0, auth_1.isAdmin)(apiKey)) {
|
|
2104
|
+
res.status(403).json({ error: 'Admin key required' });
|
|
2105
|
+
return;
|
|
2106
|
+
}
|
|
2107
|
+
const { agentId, senderId } = req.params;
|
|
2108
|
+
if (!agentConfigs.has(agentId)) {
|
|
2109
|
+
res.status(404).json({ error: `Agent '${agentId}' not found` });
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
2112
|
+
(0, pending_senders_1.clearPendingSender)('slack', agentId, senderId);
|
|
1829
2113
|
res.json({ ok: true });
|
|
1830
2114
|
});
|
|
1831
2115
|
/**
|
|
@@ -2267,8 +2551,8 @@ function createApiRouter(agentRunners, agentConfigs, apiKeys, configPath, models
|
|
|
2267
2551
|
return;
|
|
2268
2552
|
}
|
|
2269
2553
|
const { source, rawChatId } = parseHistoryChatId(chatId);
|
|
2270
|
-
if (
|
|
2271
|
-
res.status(400).json({ error: 'Sessions endpoint only supports telegram/discord/line chats' });
|
|
2554
|
+
if (!(0, types_1.isChatChannel)(source)) {
|
|
2555
|
+
res.status(400).json({ error: 'Sessions endpoint only supports telegram/discord/line/slack chats' });
|
|
2272
2556
|
return;
|
|
2273
2557
|
}
|
|
2274
2558
|
try {
|
|
@@ -2453,8 +2737,8 @@ function createApiRouter(agentRunners, agentConfigs, apiKeys, configPath, models
|
|
|
2453
2737
|
return;
|
|
2454
2738
|
}
|
|
2455
2739
|
const { source, rawChatId } = parseHistoryChatId(chatId);
|
|
2456
|
-
if (
|
|
2457
|
-
res.status(400).json({ error: 'Cross-channel messaging only supported for telegram/discord/line chats' });
|
|
2740
|
+
if (!(0, types_1.isChatChannel)(source)) {
|
|
2741
|
+
res.status(400).json({ error: 'Cross-channel messaging only supported for telegram/discord/line/slack chats' });
|
|
2458
2742
|
return;
|
|
2459
2743
|
}
|
|
2460
2744
|
const body = req.body;
|
|
@@ -3251,6 +3535,8 @@ function parseHistoryChatId(fullChatId) {
|
|
|
3251
3535
|
return { source: 'discord', rawChatId: fullChatId.slice(8) };
|
|
3252
3536
|
if (fullChatId.startsWith('line-'))
|
|
3253
3537
|
return { source: 'line', rawChatId: fullChatId.slice(5) };
|
|
3538
|
+
if (fullChatId.startsWith('slack-'))
|
|
3539
|
+
return { source: 'slack', rawChatId: fullChatId.slice(6) };
|
|
3254
3540
|
return { source: 'api', rawChatId: fullChatId };
|
|
3255
3541
|
}
|
|
3256
3542
|
//# sourceMappingURL=router.js.map
|