@nordbyte/nordrelay 0.8.1 → 0.8.3
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/.env.example +9 -0
- package/README.md +84 -1205
- package/dist/{access-control.js → access/access-control.js} +1 -1
- package/dist/{audit-log.js → access/audit-log.js} +32 -15
- package/dist/{session-locks.js → access/session-locks.js} +1 -1
- package/dist/{user-management.js → access/user-management.js} +1 -1
- package/dist/{claude-code-cli.js → agents/claude-code/claude-code-cli.js} +2 -2
- package/dist/{claude-code-session.js → agents/claude-code/claude-code-session.js} +1 -1
- package/dist/{codex-cli.js → agents/codex/codex-cli.js} +14 -5
- package/dist/{codex-session.js → agents/codex/codex-session.js} +2 -4
- package/dist/{hermes-cli.js → agents/hermes/hermes-cli.js} +2 -2
- package/dist/{hermes-launch.js → agents/hermes/hermes-launch.js} +1 -1
- package/dist/{hermes-session.js → agents/hermes/hermes-session.js} +1 -1
- package/dist/{openclaw-cli.js → agents/openclaw/openclaw-cli.js} +2 -2
- package/dist/{openclaw-launch.js → agents/openclaw/openclaw-launch.js} +1 -1
- package/dist/{openclaw-session.js → agents/openclaw/openclaw-session.js} +1 -1
- package/dist/{pi-cli.js → agents/pi/pi-cli.js} +2 -2
- package/dist/{pi-launch.js → agents/pi/pi-launch.js} +1 -1
- package/dist/{pi-session.js → agents/pi/pi-session.js} +1 -1
- package/dist/{adapter-conformance.js → agents/shared/adapter-conformance.js} +2 -2
- package/dist/{agent-activity.js → agents/shared/agent-activity.js} +5 -5
- package/dist/agents/shared/agent-auth-commands.js +30 -0
- package/dist/{agent-factory.js → agents/shared/agent-factory.js} +5 -5
- package/dist/{agent-feature-matrix.js → agents/shared/agent-feature-matrix.js} +2 -2
- package/dist/{agent-updates.js → agents/shared/agent-updates.js} +7 -7
- package/dist/{discord-artifacts.js → channels/discord/discord-artifacts.js} +4 -4
- package/dist/{discord-bot.js → channels/discord/discord-bot.js} +176 -451
- package/dist/{discord-channel-runtime.js → channels/discord/discord-channel-runtime.js} +2 -2
- package/dist/{discord-command-surface.js → channels/discord/discord-command-surface.js} +3 -3
- package/dist/{bot-rendering.js → channels/shared/bot-rendering.js} +6 -6
- package/dist/{channel-actions.js → channels/shared/channel-actions.js} +4 -4
- package/dist/channels/shared/channel-bridge-controller.js +69 -0
- package/dist/channels/shared/channel-cli-artifacts.js +51 -0
- package/dist/{channel-command-service.js → channels/shared/channel-command-service.js} +51 -28
- package/dist/channels/shared/channel-external-mirror-controller.js +193 -0
- package/dist/channels/shared/channel-external-monitor.js +52 -0
- package/dist/{channel-mirror-registry.js → channels/shared/channel-mirror-registry.js} +14 -6
- package/dist/{channel-peer-prompt.js → channels/shared/channel-peer-prompt.js} +3 -3
- package/dist/channels/shared/channel-prompt-queue.js +37 -0
- package/dist/{channel-turn-service.js → channels/shared/channel-turn-service.js} +25 -11
- package/dist/{context-key.js → channels/shared/context-key.js} +1 -1
- package/dist/{session-format.js → channels/shared/session-format.js} +2 -2
- package/dist/{slack-artifacts.js → channels/slack/slack-artifacts.js} +4 -4
- package/dist/{slack-bot.js → channels/slack/slack-bot.js} +171 -309
- package/dist/{slack-channel-runtime.js → channels/slack/slack-channel-runtime.js} +2 -2
- package/dist/{slack-command-surface.js → channels/slack/slack-command-surface.js} +2 -2
- package/dist/{slack-diagnostics.js → channels/slack/slack-diagnostics.js} +2 -2
- package/dist/{bot-ui.js → channels/telegram/bot-ui.js} +1 -1
- package/dist/{bot.js → channels/telegram/bot.js} +195 -430
- package/dist/{telegram-access-commands.js → channels/telegram/telegram-access-commands.js} +3 -3
- package/dist/{telegram-access-middleware.js → channels/telegram/telegram-access-middleware.js} +4 -4
- package/dist/{telegram-agent-commands.js → channels/telegram/telegram-agent-commands.js} +9 -9
- package/dist/{telegram-artifact-commands.js → channels/telegram/telegram-artifact-commands.js} +4 -4
- package/dist/{telegram-channel-runtime.js → channels/telegram/telegram-channel-runtime.js} +2 -2
- package/dist/{telegram-command-menu.js → channels/telegram/telegram-command-menu.js} +1 -1
- package/dist/{telegram-diagnostics-command.js → channels/telegram/telegram-diagnostics-command.js} +7 -7
- package/dist/{telegram-general-commands.js → channels/telegram/telegram-general-commands.js} +4 -4
- package/dist/{telegram-operational-commands.js → channels/telegram/telegram-operational-commands.js} +5 -5
- package/dist/{telegram-output.js → channels/telegram/telegram-output.js} +2 -2
- package/dist/{telegram-preference-commands.js → channels/telegram/telegram-preference-commands.js} +3 -3
- package/dist/{telegram-queue-commands.js → channels/telegram/telegram-queue-commands.js} +6 -6
- package/dist/{telegram-support-command.js → channels/telegram/telegram-support-command.js} +4 -4
- package/dist/{telegram-update-commands.js → channels/telegram/telegram-update-commands.js} +5 -5
- package/dist/{config-metadata.js → core/config-metadata.js} +8 -0
- package/dist/{config.js → core/config.js} +11 -3
- package/dist/core/pagination.js +22 -0
- package/dist/index.js +27 -23
- package/dist/peers/peer-discovery-jobs.js +206 -0
- package/dist/peers/peer-discovery.js +223 -0
- package/dist/peers/peer-health-monitor.js +49 -0
- package/dist/{peer-identity.js → peers/peer-identity.js} +50 -1
- package/dist/{peer-runtime-service.js → peers/peer-runtime-service.js} +29 -7
- package/dist/{peer-server.js → peers/peer-server.js} +3 -2
- package/dist/{peer-store.js → peers/peer-store.js} +96 -9
- package/dist/{peer-types.js → peers/peer-types.js} +28 -0
- package/dist/peers/peer-web-proxy-contract.js +129 -0
- package/dist/{metrics.js → runtime/metrics.js} +5 -3
- package/dist/{relay-artifact-service.js → runtime/relay-artifact-service.js} +1 -1
- package/dist/runtime/relay-auth-service.js +63 -0
- package/dist/runtime/relay-dashboard-service.js +139 -0
- package/dist/{relay-external-activity-monitor.js → runtime/relay-external-activity-monitor.js} +155 -53
- package/dist/{relay-queue-service.js → runtime/relay-queue-service.js} +1 -0
- package/dist/runtime/relay-runtime-active-sessions.js +387 -0
- package/dist/runtime/relay-runtime-dashboard.js +204 -0
- package/dist/{relay-runtime-helpers.js → runtime/relay-runtime-helpers.js} +3 -0
- package/dist/runtime/relay-runtime-prompt-queue-artifacts.js +311 -0
- package/dist/runtime/relay-runtime-sessions.js +631 -0
- package/dist/runtime/relay-runtime-trace.js +92 -0
- package/dist/runtime/relay-runtime-types.js +1 -0
- package/dist/runtime/relay-runtime-updates-jobs.js +366 -0
- package/dist/runtime/relay-runtime.js +461 -0
- package/dist/runtime/runtime-cache.js +117 -0
- package/dist/{prompt-store.js → state/prompt-store.js} +13 -1
- package/dist/{session-registry.js → state/session-registry.js} +3 -3
- package/dist/{operations.js → support/operations.js} +7 -7
- package/dist/{support-bundle.js → support/support-bundle.js} +1 -1
- package/dist/{web-api-contract.js → web/web-api-contract.js} +19 -3
- package/dist/web/web-api-types.js +1 -0
- package/dist/{web-dashboard-access-routes.js → web/web-dashboard-access-routes.js} +17 -14
- package/dist/{web-dashboard-artifact-routes.js → web/web-dashboard-artifact-routes.js} +6 -2
- package/dist/{web-dashboard-assets.js → web/web-dashboard-assets.js} +25 -2
- package/dist/{web-dashboard-http.js → web/web-dashboard-http.js} +41 -5
- package/dist/{web-dashboard-pages.js → web/web-dashboard-pages.js} +95 -30
- package/dist/{web-dashboard-peer-routes.js → web/web-dashboard-peer-routes.js} +121 -7
- package/dist/{web-dashboard-runtime-routes.js → web/web-dashboard-runtime-routes.js} +8 -1
- package/dist/web/web-dashboard-security.js +14 -0
- package/dist/{web-dashboard-session-routes.js → web/web-dashboard-session-routes.js} +29 -13
- package/dist/web/web-dashboard-ui.js +56 -0
- package/dist/{web-dashboard.js → web/web-dashboard.js} +132 -48
- package/dist/web/web-performance.js +62 -0
- package/dist/web/web-rate-limit.js +19 -0
- package/dist/{web-state.js → web/web-state.js} +107 -9
- package/dist/webui-assets/dashboard.css +398 -49
- package/dist/webui-assets/dashboard.js +1239 -103
- package/dist/webui-assets/favicon.ico +0 -0
- package/dist/webui-assets/favicon.png +0 -0
- package/dist/webui-assets/logo.png +0 -0
- package/package.json +6 -3
- package/plugins/nordrelay/scripts/nordrelay.mjs +346 -12
- package/plugins/nordrelay/scripts/service-installer.mjs +183 -0
- package/{launchd/start.sh → scripts/launchd-start.sh} +1 -1
- package/scripts/postinstall.mjs +122 -0
- package/dist/relay-runtime.js +0 -1916
- package/dist/runtime-cache.js +0 -57
- package/dist/web-dashboard-ui.js +0 -20
- /package/dist/{user-management-crypto.js → access/user-management-crypto.js} +0 -0
- /package/dist/{user-management-normalize.js → access/user-management-normalize.js} +0 -0
- /package/dist/{user-management-types.js → access/user-management-types.js} +0 -0
- /package/dist/{claude-code-auth.js → agents/claude-code/claude-code-auth.js} +0 -0
- /package/dist/{claude-code-launch.js → agents/claude-code/claude-code-launch.js} +0 -0
- /package/dist/{claude-code-state.js → agents/claude-code/claude-code-state.js} +0 -0
- /package/dist/{codex-auth.js → agents/codex/codex-auth.js} +0 -0
- /package/dist/{codex-config.js → agents/codex/codex-config.js} +0 -0
- /package/dist/{codex-launch.js → agents/codex/codex-launch.js} +0 -0
- /package/dist/{codex-state.js → agents/codex/codex-state.js} +0 -0
- /package/dist/{hermes-api.js → agents/hermes/hermes-api.js} +0 -0
- /package/dist/{hermes-auth.js → agents/hermes/hermes-auth.js} +0 -0
- /package/dist/{hermes-state.js → agents/hermes/hermes-state.js} +0 -0
- /package/dist/{openclaw-auth.js → agents/openclaw/openclaw-auth.js} +0 -0
- /package/dist/{openclaw-gateway.js → agents/openclaw/openclaw-gateway.js} +0 -0
- /package/dist/{openclaw-state.js → agents/openclaw/openclaw-state.js} +0 -0
- /package/dist/{pi-auth.js → agents/pi/pi-auth.js} +0 -0
- /package/dist/{pi-rpc.js → agents/pi/pi-rpc.js} +0 -0
- /package/dist/{pi-state.js → agents/pi/pi-state.js} +0 -0
- /package/dist/{agent-adapter.js → agents/shared/agent-adapter.js} +0 -0
- /package/dist/{agent.js → agents/shared/agent.js} +0 -0
- /package/dist/{artifacts.js → artifacts/artifacts.js} +0 -0
- /package/dist/{attachments.js → artifacts/attachments.js} +0 -0
- /package/dist/{voice.js → artifacts/voice.js} +0 -0
- /package/dist/{discord-rate-limit.js → channels/discord/discord-rate-limit.js} +0 -0
- /package/dist/{channel-adapter.js → channels/shared/channel-adapter.js} +0 -0
- /package/dist/{relay-runtime-types.js → channels/shared/channel-bridge-state.js} +0 -0
- /package/dist/{channel-command-catalog.js → channels/shared/channel-command-catalog.js} +0 -0
- /package/dist/{channel-command-core.js → channels/shared/channel-command-core.js} +0 -0
- /package/dist/{channel-prompt-engine.js → channels/shared/channel-prompt-engine.js} +0 -0
- /package/dist/{channel-runtime.js → channels/shared/channel-runtime.js} +0 -0
- /package/dist/{channel-turn-lifecycle.js → channels/shared/channel-turn-lifecycle.js} +0 -0
- /package/dist/{slack-rate-limit.js → channels/slack/slack-rate-limit.js} +0 -0
- /package/dist/{telegram-command-types.js → channels/telegram/telegram-command-types.js} +0 -0
- /package/dist/{telegram-rate-limit.js → channels/telegram/telegram-rate-limit.js} +0 -0
- /package/dist/{activity-events.js → core/activity-events.js} +0 -0
- /package/dist/{error-messages.js → core/error-messages.js} +0 -0
- /package/dist/{format.js → core/format.js} +0 -0
- /package/dist/{logger.js → core/logger.js} +0 -0
- /package/dist/{redaction.js → core/redaction.js} +0 -0
- /package/dist/{settings-service.js → core/settings-service.js} +0 -0
- /package/dist/{settings-wizard-test.js → core/settings-wizard-test.js} +0 -0
- /package/dist/{workspace-policy.js → core/workspace-policy.js} +0 -0
- /package/dist/{peer-auth.js → peers/peer-auth.js} +0 -0
- /package/dist/{peer-client.js → peers/peer-client.js} +0 -0
- /package/dist/{peer-context.js → peers/peer-context.js} +0 -0
- /package/dist/{peer-readiness.js → peers/peer-readiness.js} +0 -0
- /package/dist/{web-api-types.js → runtime/relay-runtime-delegate.js} +0 -0
- /package/dist/{remote-prompt.js → runtime/remote-prompt.js} +0 -0
- /package/dist/{bot-preferences.js → state/bot-preferences.js} +0 -0
- /package/dist/{job-store.js → state/job-store.js} +0 -0
- /package/dist/{persistence.js → state/persistence.js} +0 -0
- /package/dist/{state-backend.js → state/state-backend.js} +0 -0
- /package/dist/{zip-writer.js → support/zip-writer.js} +0 -0
|
@@ -1,47 +1,49 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { App } from "@slack/bolt";
|
|
3
|
-
import { ADMIN_GROUP_ID } from "
|
|
4
|
-
import { agentLabel, agentReasoningLabel, agentReasoningOptions } from "
|
|
5
|
-
import { getAgentActivityLog, getExternalSnapshotForSession } from "
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
3
|
+
import { ADMIN_GROUP_ID } from "../../access/access-control.js";
|
|
4
|
+
import { agentLabel, agentReasoningLabel, agentReasoningOptions } from "../../agents/shared/agent.js";
|
|
5
|
+
import { getAgentActivityLog, getExternalSnapshotForSession } from "../../agents/shared/agent-activity.js";
|
|
6
|
+
import { hostAgentLoginCommand, hostAgentLogoutCommand } from "../../agents/shared/agent-auth-commands.js";
|
|
7
|
+
import { listAgentAdapterDescriptors } from "../../agents/shared/agent-adapter.js";
|
|
8
|
+
import { AgentUpdateManager } from "../../agents/shared/agent-updates.js";
|
|
9
|
+
import { enabledAgents } from "../../agents/shared/agent-factory.js";
|
|
10
|
+
import { ensureOutDir } from "../../artifacts/artifacts.js";
|
|
11
|
+
import { buildFileInstructions, outboxPath, stageFile } from "../../artifacts/attachments.js";
|
|
12
|
+
import { AuditLogStore } from "../../access/audit-log.js";
|
|
13
|
+
import { BotPreferencesStore } from "../../state/bot-preferences.js";
|
|
14
|
+
import { capabilitiesOf, filterActivityEvents, parseActivityOptions, renderPromptFailure, trimLine } from "../shared/bot-rendering.js";
|
|
15
|
+
import { parseAgentUpdateId, renderAgentUpdateJobAction, renderAgentUpdateJobsAction, renderAgentUpdateLogAction, renderAgentUpdatePickerAction, renderQueueListAction } from "../shared/channel-actions.js";
|
|
16
|
+
import { createChannelActivityRecorder, createChannelAuditRecorder, createChannelBusyStore, createChannelPermissionChecker, createChannelQueueStatusController, } from "../shared/channel-bridge-controller.js";
|
|
17
|
+
import { createSharedChannelCommandDispatcher } from "../shared/channel-command-core.js";
|
|
18
|
+
import { slackHelpCommandList } from "../shared/channel-command-catalog.js";
|
|
19
|
+
import { ChannelCommandService } from "../shared/channel-command-service.js";
|
|
20
|
+
import { createChannelPromptEngine } from "../shared/channel-prompt-engine.js";
|
|
21
|
+
import { queueChannelPromptIfBusy } from "../shared/channel-prompt-queue.js";
|
|
22
|
+
import { runChannelPeerPrompt } from "../shared/channel-peer-prompt.js";
|
|
23
|
+
import { deliverChannelAction } from "../shared/channel-runtime.js";
|
|
24
|
+
import { deliverChannelCliArtifacts } from "../shared/channel-cli-artifacts.js";
|
|
25
|
+
import { createChannelExternalMirrorController } from "../shared/channel-external-mirror-controller.js";
|
|
26
|
+
import { monitorChannelExternalContexts } from "../shared/channel-external-monitor.js";
|
|
27
|
+
import { isSlackContextKey, parseSlackContextKey, slackContextKey } from "../shared/context-key.js";
|
|
28
|
+
import { friendlyErrorText } from "../../core/error-messages.js";
|
|
29
|
+
import { spawnConnectorRestart, spawnSelfUpdate } from "../../support/operations.js";
|
|
30
|
+
import { RemoteRelayClient } from "../../peers/peer-client.js";
|
|
31
|
+
import { PromptStore, toPromptEnvelope } from "../../state/prompt-store.js";
|
|
32
|
+
import { RelayArtifactService } from "../../runtime/relay-artifact-service.js";
|
|
33
|
+
import { RelayAuthService } from "../../runtime/relay-auth-service.js";
|
|
34
|
+
import { configureRedaction, redactText } from "../../core/redaction.js";
|
|
35
|
+
import { renderSessionInfoPlain } from "../shared/session-format.js";
|
|
36
|
+
import { canWriteWithLock, SessionLockStore } from "../../access/session-locks.js";
|
|
37
|
+
import { SessionRegistry } from "../../state/session-registry.js";
|
|
36
38
|
import { createSlackArtifactCommandHandler, sendRecentSlackArtifacts } from "./slack-artifacts.js";
|
|
37
39
|
import { SlackBotChannelRuntime, actionFromSlackActionId, splitSlackMessage, trimSlackMessage } from "./slack-channel-runtime.js";
|
|
38
40
|
import { isUnauthenticatedSlackCommandAllowed, parseSlackMessageCommand, parseSlackSlashCommand, permissionForSlackAction, requiredPermissionForSlackCommand } from "./slack-command-surface.js";
|
|
39
41
|
import { collectSlackDiagnostics } from "./slack-diagnostics.js";
|
|
40
42
|
import { getSlackRateLimitMetrics } from "./slack-rate-limit.js";
|
|
41
|
-
import { transcribeAudio } from "
|
|
42
|
-
import { UserStore } from "
|
|
43
|
-
import { WebActivityStore } from "
|
|
44
|
-
import { evaluateWorkspacePolicy, filterAllowedWorkspaces } from "
|
|
43
|
+
import { transcribeAudio } from "../../artifacts/voice.js";
|
|
44
|
+
import { UserStore } from "../../access/user-management.js";
|
|
45
|
+
import { WebActivityStore } from "../../web/web-state.js";
|
|
46
|
+
import { evaluateWorkspacePolicy, filterAllowedWorkspaces } from "../../core/workspace-policy.js";
|
|
45
47
|
export { isUnauthenticatedSlackCommandAllowed, permissionForSlackAction, requiredPermissionForSlackCommand } from "./slack-command-surface.js";
|
|
46
48
|
const EDIT_DEBOUNCE_MS = 1500;
|
|
47
49
|
const TYPING_INTERVAL_MS = 4500;
|
|
@@ -70,24 +72,23 @@ export function createSlackBridge(config, registry) {
|
|
|
70
72
|
const lockStore = new SessionLockStore(config.workspace, config.stateBackend);
|
|
71
73
|
const userStore = new UserStore();
|
|
72
74
|
const artifactService = new RelayArtifactService(config);
|
|
75
|
+
const authService = new RelayAuthService(config);
|
|
73
76
|
const agentUpdates = new AgentUpdateManager();
|
|
74
77
|
const commandService = new ChannelCommandService(config);
|
|
75
|
-
const busyStates =
|
|
78
|
+
const busyStates = createChannelBusyStore();
|
|
76
79
|
const turnProgress = new Map();
|
|
77
80
|
const draining = new Set();
|
|
78
81
|
const picks = new Map();
|
|
79
82
|
const externalMirrors = new Map();
|
|
80
|
-
const queueStatusMessages =
|
|
83
|
+
const queueStatusMessages = createChannelQueueStatusController({
|
|
84
|
+
send: async (_contextKey, context, text) => (await runtime.sendMessage(context, { text, fallbackText: text })).messageId,
|
|
85
|
+
edit: async (_contextKey, context, messageId, text) => {
|
|
86
|
+
await runtime.editMessage(context, messageId, { text, fallbackText: text });
|
|
87
|
+
},
|
|
88
|
+
});
|
|
81
89
|
const remoteClient = new RemoteRelayClient();
|
|
82
90
|
let externalMonitor;
|
|
83
|
-
const getBusyState = (contextKey) =>
|
|
84
|
-
let state = busyStates.get(contextKey);
|
|
85
|
-
if (!state) {
|
|
86
|
-
state = { processing: false, switching: false };
|
|
87
|
-
busyStates.set(contextKey, state);
|
|
88
|
-
}
|
|
89
|
-
return state;
|
|
90
|
-
};
|
|
91
|
+
const getBusyState = (contextKey) => busyStates.get(contextKey);
|
|
91
92
|
const actorFor = (request) => ({
|
|
92
93
|
channel: "slack",
|
|
93
94
|
id: request.authUser?.user.id ?? `slack:${request.userId}`,
|
|
@@ -95,27 +96,19 @@ export function createSlackBridge(config, registry) {
|
|
|
95
96
|
username: request.authUser?.user.email ?? request.username,
|
|
96
97
|
channelUserId: request.userId,
|
|
97
98
|
});
|
|
98
|
-
const appendActivity = (
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
contextKey: input.contextKey ?? request.contextKey,
|
|
112
|
-
actor: input.actor ?? actorFor(request),
|
|
113
|
-
actorId: request.authUser?.user.id ?? request.userId,
|
|
114
|
-
actorRole: request.authUser?.groups.map((group) => group.name).join(", ") ?? "unauthenticated",
|
|
115
|
-
...input,
|
|
116
|
-
});
|
|
117
|
-
};
|
|
118
|
-
const hasPermission = (request, permission) => userStore.hasPermission(request.authUser, permission);
|
|
99
|
+
const appendActivity = createChannelActivityRecorder({
|
|
100
|
+
source: "slack",
|
|
101
|
+
workspace: config.workspace,
|
|
102
|
+
activityStore,
|
|
103
|
+
actorFor,
|
|
104
|
+
});
|
|
105
|
+
const audit = createChannelAuditRecorder({
|
|
106
|
+
channelId: "slack",
|
|
107
|
+
auditLog,
|
|
108
|
+
actorFor,
|
|
109
|
+
actorIdFor: (request) => request.userId,
|
|
110
|
+
});
|
|
111
|
+
const hasPermission = createChannelPermissionChecker(userStore);
|
|
119
112
|
const reply = async (request, content, options = {}) => {
|
|
120
113
|
if (options.ephemeral && request.respond) {
|
|
121
114
|
await request.respond({
|
|
@@ -213,7 +206,7 @@ export function createSlackBridge(config, registry) {
|
|
|
213
206
|
};
|
|
214
207
|
const commandArtifacts = createSlackArtifactCommandHandler(artifactDeps);
|
|
215
208
|
const getBusyReason = (contextKey) => {
|
|
216
|
-
const state = busyStates.
|
|
209
|
+
const state = busyStates.peek(contextKey);
|
|
217
210
|
const session = registry.get(contextKey);
|
|
218
211
|
if (state?.processing || state?.switching || session?.isProcessing()) {
|
|
219
212
|
return { busy: true, kind: "connector", state: state ?? getBusyState(contextKey) };
|
|
@@ -225,111 +218,7 @@ export function createSlackBridge(config, registry) {
|
|
|
225
218
|
return { busy: false, kind: "idle" };
|
|
226
219
|
};
|
|
227
220
|
const updateQueueStatusMessage = async (contextKey, context, text) => {
|
|
228
|
-
|
|
229
|
-
if (state.lastText === text && state.messageId) {
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
if (!state.messageId) {
|
|
233
|
-
const sent = await runtime.sendMessage(context, { text, fallbackText: text });
|
|
234
|
-
state.messageId = sent.messageId;
|
|
235
|
-
state.lastText = text;
|
|
236
|
-
queueStatusMessages.set(contextKey, state);
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
await runtime.editMessage(context, state.messageId, { text, fallbackText: text });
|
|
240
|
-
state.lastText = text;
|
|
241
|
-
queueStatusMessages.set(contextKey, state);
|
|
242
|
-
};
|
|
243
|
-
const sendExternalWorkingNotice = async (context, state, snapshot) => {
|
|
244
|
-
const turnKey = snapshot.activity.turnId ?? snapshot.activity.startedAt?.toISOString() ?? "unknown";
|
|
245
|
-
if (state.workingNoticeTurnKey === turnKey) {
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
const prompt = trimLine(snapshot.latestUserMessage ?? "", 250);
|
|
249
|
-
const text = prompt ? `*Working on* ${prompt}` : `*Working on* external ${snapshot.agentLabel} task...`;
|
|
250
|
-
await runtime.sendMessage(context, {
|
|
251
|
-
text,
|
|
252
|
-
fallbackText: prompt ? `Working on ${prompt}` : `Working on external ${snapshot.agentLabel} task...`,
|
|
253
|
-
});
|
|
254
|
-
state.workingNoticeTurnKey = turnKey;
|
|
255
|
-
};
|
|
256
|
-
const mirrorExternalSnapshot = async (contextKey, context, session, snapshot) => {
|
|
257
|
-
let state = externalMirrors.get(contextKey);
|
|
258
|
-
if (!state || state.threadId !== snapshot.threadId || state.rolloutPath !== snapshot.sourcePath) {
|
|
259
|
-
state = {
|
|
260
|
-
threadId: snapshot.threadId,
|
|
261
|
-
rolloutPath: snapshot.sourcePath,
|
|
262
|
-
lastLine: snapshot.lineCount,
|
|
263
|
-
turnId: snapshot.activity.turnId,
|
|
264
|
-
startedAt: snapshot.activity.startedAt,
|
|
265
|
-
};
|
|
266
|
-
externalMirrors.set(contextKey, state);
|
|
267
|
-
}
|
|
268
|
-
const mirrorMode = preferencesStore.get(contextKey).mirrorMode ?? config.slackMirrorMode;
|
|
269
|
-
if (snapshot.activity.active) {
|
|
270
|
-
state.turnId = snapshot.activity.turnId;
|
|
271
|
-
state.startedAt = snapshot.activity.startedAt;
|
|
272
|
-
if (mirrorMode !== "off") {
|
|
273
|
-
const now = Date.now();
|
|
274
|
-
if (!state.lastTypingAt || now - state.lastTypingAt >= TYPING_INTERVAL_MS) {
|
|
275
|
-
state.lastTypingAt = now;
|
|
276
|
-
await runtime.sendTyping(context).catch(() => { });
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
if (mirrorMode === "final") {
|
|
280
|
-
await sendExternalWorkingNotice(context, state, snapshot);
|
|
281
|
-
state.lastLine = Math.max(state.lastLine, snapshot.lineCount);
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
if (mirrorMode === "off") {
|
|
285
|
-
state.lastLine = Math.max(state.lastLine, snapshot.lineCount);
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
const status = renderExternalMirrorStatus(snapshot, promptStore.list(contextKey).length);
|
|
289
|
-
const now = Date.now();
|
|
290
|
-
const canUpdateStatus = !state.latestStatusAt || now - state.latestStatusAt >= config.slackMirrorMinUpdateMs;
|
|
291
|
-
if (!state.statusMessageId) {
|
|
292
|
-
const sent = await runtime.sendMessage(context, { text: status.plain, fallbackText: status.plain });
|
|
293
|
-
state.statusMessageId = sent.messageId;
|
|
294
|
-
state.latestStatusAt = now;
|
|
295
|
-
}
|
|
296
|
-
else if (state.latestStatus !== status.plain && canUpdateStatus) {
|
|
297
|
-
await runtime.editMessage(context, state.statusMessageId, { text: status.plain, fallbackText: status.plain });
|
|
298
|
-
state.latestStatusAt = now;
|
|
299
|
-
}
|
|
300
|
-
state.latestStatus = status.plain;
|
|
301
|
-
if (mirrorMode === "full") {
|
|
302
|
-
const newEvents = snapshot.events
|
|
303
|
-
.filter((event) => event.lineNumber > (state.latestMirroredEventLine ?? state.lastLine))
|
|
304
|
-
.slice(-6);
|
|
305
|
-
for (const event of newEvents) {
|
|
306
|
-
const rendered = renderExternalMirrorEvent(event);
|
|
307
|
-
if (rendered) {
|
|
308
|
-
await runtime.sendMessage(context, { text: rendered.plain, fallbackText: rendered.plain });
|
|
309
|
-
state.latestMirroredEventLine = event.lineNumber;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
state.lastLine = Math.max(state.lastLine, snapshot.lineCount);
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
|
-
const terminalEvent = [...snapshot.events].reverse().find((event) => event.kind === "task" && event.status && event.status !== "started");
|
|
317
|
-
if (terminalEvent) {
|
|
318
|
-
const finalAgent = snapshot.events.filter((event) => event.kind === "agent" && event.text).at(-1);
|
|
319
|
-
if (mirrorMode !== "off" && mirrorMode !== "status" && finalAgent?.text && finalAgent.lineNumber !== state.latestAgentLine) {
|
|
320
|
-
await runtime.sendMessage(context, {
|
|
321
|
-
text: `*${snapshot.agentLabel} CLI final answer:*`,
|
|
322
|
-
fallbackText: `${snapshot.agentLabel} CLI final answer:`,
|
|
323
|
-
});
|
|
324
|
-
for (const chunk of splitSlackMessage(finalAgent.text)) {
|
|
325
|
-
await runtime.sendMessage(context, { text: chunk, fallbackText: chunk });
|
|
326
|
-
}
|
|
327
|
-
state.latestAgentLine = finalAgent.lineNumber;
|
|
328
|
-
}
|
|
329
|
-
await deliverCliGeneratedArtifacts(contextKey, context, session, state.startedAt, terminalEvent.turnId);
|
|
330
|
-
}
|
|
331
|
-
state.workingNoticeTurnKey = undefined;
|
|
332
|
-
state.lastLine = Math.max(state.lastLine, snapshot.lineCount);
|
|
221
|
+
await queueStatusMessages.update(contextKey, context, text);
|
|
333
222
|
};
|
|
334
223
|
const ensureActiveThread = async (request, session) => {
|
|
335
224
|
if (!session.hasActiveThread()) {
|
|
@@ -337,63 +226,15 @@ export function createSlackBridge(config, registry) {
|
|
|
337
226
|
updateSession(request, session);
|
|
338
227
|
}
|
|
339
228
|
};
|
|
340
|
-
const checkAgentAuthStatus =
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
return checkHermesAuthStatus({ baseUrl: config.hermesApiBaseUrl, apiKey: config.hermesApiKey });
|
|
345
|
-
if (info.agentId === "openclaw")
|
|
346
|
-
return checkOpenClawAuthStatus({ gatewayUrl: config.openClawGatewayUrl, token: config.openClawGatewayToken, password: config.openClawGatewayPassword });
|
|
347
|
-
if (info.agentId === "claude-code")
|
|
348
|
-
return checkClaudeCodeAuthStatus(config.claudeCodeCliPath);
|
|
349
|
-
return checkAuthStatus(config.codexApiKey);
|
|
350
|
-
};
|
|
351
|
-
const checkLoginAuthStatus = async (info) => {
|
|
352
|
-
if (info.agentId === "hermes")
|
|
353
|
-
return checkHermesAuthStatus({ baseUrl: config.hermesApiBaseUrl, apiKey: config.hermesApiKey });
|
|
354
|
-
if (info.agentId === "claude-code")
|
|
355
|
-
return checkClaudeCodeAuthStatus(config.claudeCodeCliPath);
|
|
356
|
-
return checkAuthStatus(config.codexApiKey);
|
|
357
|
-
};
|
|
358
|
-
const startAgentLogin = (info) => {
|
|
359
|
-
if (info.agentId === "hermes")
|
|
360
|
-
return startHermesLogin(config.hermesCliPath);
|
|
361
|
-
if (info.agentId === "claude-code")
|
|
362
|
-
return startClaudeCodeLogin(config.claudeCodeCliPath);
|
|
363
|
-
if (info.agentId === "codex")
|
|
364
|
-
return startCodexLogin();
|
|
365
|
-
return Promise.resolve({ success: false, message: `${info.agentLabel} login is not managed by NordRelay. Run the agent login flow on the host.` });
|
|
366
|
-
};
|
|
367
|
-
const startAgentLogout = (info) => {
|
|
368
|
-
if (info.agentId === "hermes")
|
|
369
|
-
return startHermesLogout(config.hermesCliPath);
|
|
370
|
-
if (info.agentId === "claude-code")
|
|
371
|
-
return startClaudeCodeLogout(config.claudeCodeCliPath);
|
|
372
|
-
if (info.agentId === "codex")
|
|
373
|
-
return startCodexLogout();
|
|
374
|
-
return Promise.resolve({ success: false, message: `${info.agentLabel} logout is not managed by NordRelay. Run the agent logout flow on the host.` });
|
|
375
|
-
};
|
|
229
|
+
const checkAgentAuthStatus = (info) => authService.check(info);
|
|
230
|
+
const checkLoginAuthStatus = (info) => authService.check(info);
|
|
231
|
+
const startAgentLogin = (info) => authService.startLogin(info);
|
|
232
|
+
const startAgentLogout = (info) => authService.startLogout(info);
|
|
376
233
|
const hostLoginCommand = (info) => {
|
|
377
|
-
|
|
378
|
-
return `${config.hermesCliPath ?? "hermes"} login --no-browser`;
|
|
379
|
-
if (info.agentId === "claude-code")
|
|
380
|
-
return `${config.claudeCodeCliPath ?? "claude"} auth login`;
|
|
381
|
-
if (info.agentId === "pi")
|
|
382
|
-
return `${config.piCliPath ?? "pi"} auth login`;
|
|
383
|
-
if (info.agentId === "openclaw")
|
|
384
|
-
return `${config.openClawCliPath ?? "openclaw"} login`;
|
|
385
|
-
return "codex login --device-auth";
|
|
234
|
+
return hostAgentLoginCommand(config, info);
|
|
386
235
|
};
|
|
387
236
|
const hostLogoutCommand = (info) => {
|
|
388
|
-
|
|
389
|
-
return `${config.hermesCliPath ?? "hermes"} logout`;
|
|
390
|
-
if (info.agentId === "claude-code")
|
|
391
|
-
return `${config.claudeCodeCliPath ?? "claude"} auth logout`;
|
|
392
|
-
if (info.agentId === "pi")
|
|
393
|
-
return `${config.piCliPath ?? "pi"} auth logout`;
|
|
394
|
-
if (info.agentId === "openclaw")
|
|
395
|
-
return `${config.openClawCliPath ?? "openclaw"} logout`;
|
|
396
|
-
return "codex logout";
|
|
237
|
+
return hostAgentLogoutCommand(config, info);
|
|
397
238
|
};
|
|
398
239
|
const denyIfLocked = async (request) => {
|
|
399
240
|
const lock = lockStore.get(request.contextKey);
|
|
@@ -444,18 +285,17 @@ export function createSlackBridge(config, registry) {
|
|
|
444
285
|
if (!options.fromQueue && await denyIfLocked(request)) {
|
|
445
286
|
return;
|
|
446
287
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
audit(request, { action: "prompt_queued", status: "ok", promptId: item.id, description: item.description });
|
|
288
|
+
if (await queueChannelPromptIfBusy({
|
|
289
|
+
request,
|
|
290
|
+
envelope,
|
|
291
|
+
fromQueue: options.fromQueue,
|
|
292
|
+
promptStore,
|
|
293
|
+
busy: getBusyReason(request.contextKey),
|
|
294
|
+
actionPrefix: "slack",
|
|
295
|
+
reply,
|
|
296
|
+
appendActivity,
|
|
297
|
+
audit,
|
|
298
|
+
})) {
|
|
459
299
|
return;
|
|
460
300
|
}
|
|
461
301
|
const busyState = getBusyState(request.contextKey);
|
|
@@ -545,45 +385,76 @@ export function createSlackBridge(config, registry) {
|
|
|
545
385
|
}
|
|
546
386
|
};
|
|
547
387
|
const deliverCliGeneratedArtifacts = async (contextKey, context, session, startedAt, turnId) => {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
return;
|
|
566
|
-
}
|
|
567
|
-
const persisted = await persistWorkspaceArtifactReport(workspace, turnId, report).catch((error) => {
|
|
568
|
-
console.error("Failed to persist Slack CLI artifact report:", error);
|
|
569
|
-
return null;
|
|
388
|
+
await deliverChannelCliArtifacts({
|
|
389
|
+
config,
|
|
390
|
+
contextKey,
|
|
391
|
+
session,
|
|
392
|
+
startedAt,
|
|
393
|
+
turnId,
|
|
394
|
+
state: externalMirrors.get(contextKey),
|
|
395
|
+
autoSend: config.slackAutoSendArtifacts,
|
|
396
|
+
sendSummaryWhenAutoSendDisabled: true,
|
|
397
|
+
logPrefix: "Slack",
|
|
398
|
+
sendSummary: (summary) => runtime.sendMessage(context, { text: summary, fallbackText: summary }).then(() => { }),
|
|
399
|
+
sendArtifact: (artifact) => runtime.sendFile(context, { localPath: artifact.localPath, name: artifact.name }).then(() => { }).catch((error) => {
|
|
400
|
+
console.error(`Failed to send Slack CLI artifact ${artifact.name}:`, error);
|
|
401
|
+
}),
|
|
402
|
+
appendActivity: (input) => {
|
|
403
|
+
activityStore.append(input);
|
|
404
|
+
},
|
|
570
405
|
});
|
|
571
|
-
const summary = formatArtifactSummary(report.artifacts, report.skippedCount, report.omittedCount);
|
|
572
|
-
if (summary) {
|
|
573
|
-
await runtime.sendMessage(context, { text: summary, fallbackText: summary });
|
|
574
|
-
}
|
|
575
|
-
if (config.slackAutoSendArtifacts) {
|
|
576
|
-
for (const artifact of (persisted?.artifacts ?? report.artifacts).slice(0, 5)) {
|
|
577
|
-
await runtime.sendFile(context, { localPath: artifact.localPath, name: artifact.name }).catch((error) => {
|
|
578
|
-
console.error(`Failed to send Slack CLI artifact ${artifact.name}:`, error);
|
|
579
|
-
});
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
const info = session.getInfo();
|
|
583
|
-
activityStore.append({ source: "cli", status: "info", type: config.slackAutoSendArtifacts ? "artifacts_sent" : "artifacts_detected", contextKey, threadId: info.threadId, workspace: info.workspace, agentId: info.agentId, actor: { channel: "cli", label: `${info.agentLabel} CLI` }, detail: summary });
|
|
584
|
-
if (state)
|
|
585
|
-
state.artifactsDeliveredForTurnId = turnId;
|
|
586
406
|
};
|
|
407
|
+
const externalMirrorController = createChannelExternalMirrorController({
|
|
408
|
+
config,
|
|
409
|
+
states: externalMirrors,
|
|
410
|
+
typingIntervalMs: TYPING_INTERVAL_MS,
|
|
411
|
+
minUpdateMs: () => config.slackMirrorMinUpdateMs,
|
|
412
|
+
mirrorMode: (contextKey) => preferencesStore.get(contextKey).mirrorMode ?? config.slackMirrorMode,
|
|
413
|
+
queueLength: (contextKey) => promptStore.list(contextKey).length,
|
|
414
|
+
activityActor: (snapshot) => ({ channel: "cli", label: `${snapshot.agentLabel} CLI` }),
|
|
415
|
+
appendActivity: (input) => {
|
|
416
|
+
activityStore.append(input);
|
|
417
|
+
},
|
|
418
|
+
sendTyping: (_contextKey, context) => runtime.sendTyping(context).catch(() => { }),
|
|
419
|
+
sendWorkingNotice: async (_contextKey, context, state, snapshot, prompt) => {
|
|
420
|
+
const turnKey = snapshot.activity.turnId ?? snapshot.activity.startedAt?.toISOString() ?? "unknown";
|
|
421
|
+
if (state.workingNoticeTurnKey === turnKey) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
const text = prompt ? `*Working on* ${prompt}` : `*Working on* external ${snapshot.agentLabel} task...`;
|
|
425
|
+
await runtime.sendMessage(context, {
|
|
426
|
+
text,
|
|
427
|
+
fallbackText: prompt ? `Working on ${prompt}` : `Working on external ${snapshot.agentLabel} task...`,
|
|
428
|
+
});
|
|
429
|
+
state.workingNoticeTurnKey = turnKey;
|
|
430
|
+
},
|
|
431
|
+
sendStatus: async (_contextKey, context, _state, rendered) => {
|
|
432
|
+
const sent = await runtime.sendMessage(context, { text: rendered.plain, fallbackText: rendered.plain });
|
|
433
|
+
return sent.messageId;
|
|
434
|
+
},
|
|
435
|
+
editStatus: (_contextKey, context, _state, messageId, rendered) => runtime.editMessage(context, messageId, { text: rendered.plain, fallbackText: rendered.plain }),
|
|
436
|
+
sendEvent: (_contextKey, context, _state, rendered) => runtime.sendMessage(context, { text: rendered.plain, fallbackText: rendered.plain }).then(() => { }),
|
|
437
|
+
sendDone: (_contextKey, context, state, text) => {
|
|
438
|
+
if (state.statusMessageId) {
|
|
439
|
+
return runtime.editMessage(context, state.statusMessageId, { text, fallbackText: text });
|
|
440
|
+
}
|
|
441
|
+
return runtime.sendMessage(context, { text, fallbackText: text }).then(() => { });
|
|
442
|
+
},
|
|
443
|
+
sendFinalAnswer: async (_contextKey, context, _state, snapshot, text) => {
|
|
444
|
+
await runtime.sendMessage(context, {
|
|
445
|
+
text: `*${snapshot.agentLabel} CLI final answer:*`,
|
|
446
|
+
fallbackText: `${snapshot.agentLabel} CLI final answer:`,
|
|
447
|
+
});
|
|
448
|
+
for (const chunk of splitSlackMessage(text)) {
|
|
449
|
+
await runtime.sendMessage(context, { text: chunk, fallbackText: chunk });
|
|
450
|
+
}
|
|
451
|
+
},
|
|
452
|
+
deliverArtifacts: (contextKey, context, session, state, turnId) => deliverCliGeneratedArtifacts(contextKey, context, session, state.startedAt, turnId),
|
|
453
|
+
fullEventFilter: () => true,
|
|
454
|
+
fullEventLimit: 6,
|
|
455
|
+
requirePreviousForTerminal: false,
|
|
456
|
+
});
|
|
457
|
+
const mirrorExternalSnapshot = externalMirrorController.mirror;
|
|
587
458
|
const commandDispatcher = createSharedChannelCommandDispatcher({
|
|
588
459
|
transport: "slack",
|
|
589
460
|
bindings: [
|
|
@@ -1285,36 +1156,30 @@ export function createSlackBridge(config, registry) {
|
|
|
1285
1156
|
return id;
|
|
1286
1157
|
};
|
|
1287
1158
|
const monitorExternalContexts = async () => {
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
await updateQueueStatusMessage(contextKey, context, `Waiting for ${snapshot.agentLabel} CLI task... ${promptStore.list(contextKey).length} queued${promptStore.isPaused(contextKey) ? " (paused)" : ""}.`).catch(() => { });
|
|
1310
|
-
}
|
|
1311
|
-
continue;
|
|
1312
|
-
}
|
|
1313
|
-
if (promptStore.list(contextKey).length > 0 && !promptStore.isPaused(contextKey) && !session.isProcessing()) {
|
|
1314
|
-
await updateQueueStatusMessage(contextKey, context, `CLI task finished, running queued prompt 1/${promptStore.list(contextKey).length}.`).catch(() => { });
|
|
1159
|
+
await monitorChannelExternalContexts({
|
|
1160
|
+
config,
|
|
1161
|
+
registry,
|
|
1162
|
+
promptStore,
|
|
1163
|
+
isContextKey: isSlackContextKey,
|
|
1164
|
+
canSendSystemMessages: (contextKey) => canSendSystemMessagesToSlackContext(userStore, contextKey),
|
|
1165
|
+
isAllowed: (contextKey) => {
|
|
1166
|
+
const parsed = parseSlackContextKey(contextKey);
|
|
1167
|
+
return Boolean(parsed && isSlackTeamAllowed(parsed.teamId) && isSlackChannelAllowedByEnv(parsed.channelId));
|
|
1168
|
+
},
|
|
1169
|
+
contextForKey: (contextKey) => {
|
|
1170
|
+
const parsed = parseSlackContextKey(contextKey);
|
|
1171
|
+
return parsed ? { channelId: "slack", chatId: parsed.channelId, ...(parsed.threadTs ? { topicId: parsed.threadTs } : {}) } : null;
|
|
1172
|
+
},
|
|
1173
|
+
previousLastLine: (contextKey) => externalMirrors.get(contextKey)?.lastLine,
|
|
1174
|
+
mirrorSnapshot: mirrorExternalSnapshot,
|
|
1175
|
+
updateQueueStatus: updateQueueStatusMessage,
|
|
1176
|
+
drainQueue: async (contextKey, context) => {
|
|
1177
|
+
const parsed = parseSlackContextKey(contextKey);
|
|
1178
|
+
if (!parsed)
|
|
1179
|
+
return;
|
|
1315
1180
|
await drainQueue({ contextKey, context, userId: "system", channelId: parsed.channelId, teamId: parsed.teamId, isDirectMessage: false, source: "system" });
|
|
1316
|
-
}
|
|
1317
|
-
}
|
|
1181
|
+
},
|
|
1182
|
+
});
|
|
1318
1183
|
};
|
|
1319
1184
|
app.event("message", async ({ event }) => {
|
|
1320
1185
|
await handleMessage(event);
|
|
@@ -1456,6 +1321,3 @@ function inferMimeType(name) {
|
|
|
1456
1321
|
return "audio/webm";
|
|
1457
1322
|
return "application/octet-stream";
|
|
1458
1323
|
}
|
|
1459
|
-
function isQueuedPrompt(value) {
|
|
1460
|
-
return Boolean(value && typeof value === "object" && "id" in value && "contextKey" in value);
|
|
1461
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createReadStream } from "node:fs";
|
|
2
|
-
import { SlackChannelAdapter, } from "
|
|
3
|
-
import { redactText } from "
|
|
2
|
+
import { SlackChannelAdapter, } from "../shared/channel-adapter.js";
|
|
3
|
+
import { redactText } from "../../core/redaction.js";
|
|
4
4
|
import { slackRateLimiter } from "./slack-rate-limit.js";
|
|
5
5
|
const SLACK_TEXT_LIMIT = 40000;
|
|
6
6
|
const SLACK_SAFE_TEXT_LIMIT = 3500;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { permissionForCommand } from "
|
|
2
|
-
import { normalizeChannelCommandName, parseChannelCommand } from "
|
|
1
|
+
import { permissionForCommand } from "../../access/access-control.js";
|
|
2
|
+
import { normalizeChannelCommandName, parseChannelCommand } from "../shared/channel-runtime.js";
|
|
3
3
|
export function parseSlackMessageCommand(text) {
|
|
4
4
|
return parseChannelCommand(text, { allowBotMention: false });
|
|
5
5
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WebClient } from "@slack/web-api";
|
|
2
|
-
import { friendlyErrorText } from "
|
|
3
|
-
import { UserStore } from "
|
|
2
|
+
import { friendlyErrorText } from "../../core/error-messages.js";
|
|
3
|
+
import { UserStore } from "../../access/user-management.js";
|
|
4
4
|
export async function collectSlackDiagnostics(input) {
|
|
5
5
|
const { config } = input;
|
|
6
6
|
const checks = [];
|