@nordbyte/nordrelay 0.8.1 → 0.8.2
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 +81 -1206
- package/dist/{access-control.js → access/access-control.js} +1 -1
- package/dist/{audit-log.js → access/audit-log.js} +2 -2
- 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} +164 -424
- 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/{channel-turn-service.js → channels/shared/channel-turn-service.js} +2 -2
- 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} +159 -294
- 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} +178 -427
- 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/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} +80 -9
- package/dist/{peer-types.js → peers/peer-types.js} +9 -0
- package/dist/peers/peer-web-proxy-contract.js +127 -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} +140 -53
- package/dist/runtime/relay-runtime-active-sessions.js +387 -0
- package/dist/runtime/relay-runtime-dashboard.js +201 -0
- package/dist/runtime/relay-runtime-prompt-queue-artifacts.js +307 -0
- package/dist/runtime/relay-runtime-sessions.js +623 -0
- package/dist/runtime/relay-runtime-types.js +1 -0
- package/dist/runtime/relay-runtime-updates-jobs.js +360 -0
- package/dist/runtime/relay-runtime.js +451 -0
- package/dist/runtime/runtime-cache.js +117 -0
- 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} +17 -3
- package/dist/web/web-api-types.js +1 -0
- package/dist/{web-dashboard-access-routes.js → web/web-dashboard-access-routes.js} +2 -2
- package/dist/{web-dashboard-assets.js → web/web-dashboard-assets.js} +24 -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} +37 -10
- package/dist/{web-dashboard-peer-routes.js → web/web-dashboard-peer-routes.js} +102 -7
- package/dist/web/web-dashboard-security.js +14 -0
- package/dist/{web-dashboard-session-routes.js → web/web-dashboard-session-routes.js} +12 -1
- package/dist/{web-dashboard.js → web/web-dashboard.js} +132 -48
- package/dist/web/web-performance.js +60 -0
- package/dist/web/web-rate-limit.js +19 -0
- package/dist/{web-state.js → web/web-state.js} +74 -5
- package/dist/webui-assets/dashboard.css +171 -10
- package/dist/webui-assets/dashboard.js +514 -48
- 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 +4 -3
- package/plugins/nordrelay/scripts/nordrelay.mjs +13 -4
- package/{launchd/start.sh → scripts/launchd-start.sh} +1 -1
- package/dist/relay-runtime.js +0 -1916
- package/dist/runtime-cache.js +0 -57
- /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/{relay-queue-service.js → runtime/relay-queue-service.js} +0 -0
- /package/dist/{web-api-types.js → runtime/relay-runtime-delegate.js} +0 -0
- /package/dist/{relay-runtime-helpers.js → runtime/relay-runtime-helpers.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/{prompt-store.js → state/prompt-store.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
- /package/dist/{web-dashboard-artifact-routes.js → web/web-dashboard-artifact-routes.js} +0 -0
- /package/dist/{web-dashboard-runtime-routes.js → web/web-dashboard-runtime-routes.js} +0 -0
- /package/dist/{web-dashboard-ui.js → web/web-dashboard-ui.js} +0 -0
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { ensureOutDir } from "../artifacts/artifacts.js";
|
|
3
|
+
import { buildFileInstructions, outboxPath, stageFile, } from "../artifacts/attachments.js";
|
|
4
|
+
import { CODEX_AGENT_CAPABILITIES, agentLabel, agentReasoningLabel, agentReasoningOptions, isAgentId, } from "../agents/shared/agent.js";
|
|
5
|
+
import { getExternalSnapshotForSession } from "../agents/shared/agent-activity.js";
|
|
6
|
+
import { listAgentAdapterDescriptors } from "../agents/shared/agent-adapter.js";
|
|
7
|
+
import { AgentUpdateManager } from "../agents/shared/agent-updates.js";
|
|
8
|
+
import { createAgentSessionService, enabledAgents } from "../agents/shared/agent-factory.js";
|
|
9
|
+
import { AuditLogStore } from "../access/audit-log.js";
|
|
10
|
+
import { BotPreferencesStore } from "../state/bot-preferences.js";
|
|
11
|
+
import { ChannelCommandService } from "../channels/shared/channel-command-service.js";
|
|
12
|
+
import { ChannelTurnService } from "../channels/shared/channel-turn-service.js";
|
|
13
|
+
import { activeSessionSourceForContextKey, ChannelMirrorRegistry } from "../channels/shared/channel-mirror-registry.js";
|
|
14
|
+
import { listThreads as listCodexThreads } from "../agents/codex/codex-state.js";
|
|
15
|
+
import { friendlyErrorText } from "../core/error-messages.js";
|
|
16
|
+
import { clearLogFile, getAgentUpdateLogPath, getConnectorHealth, getConnectorLogPath, getPackageVersion, getUpdateLogPath, getVersionChecks, readConnectorState, readFormattedLogTail, spawnConnectorRestart, spawnSelfUpdate } from "../support/operations.js";
|
|
17
|
+
import { PromptStore, toPromptEnvelope } from "../state/prompt-store.js";
|
|
18
|
+
import { UnifiedJobStore } from "../state/job-store.js";
|
|
19
|
+
import { buildRuntimeMetrics } from "./metrics.js";
|
|
20
|
+
import { RelayArtifactService } from "./relay-artifact-service.js";
|
|
21
|
+
import { RelayAuthService } from "./relay-auth-service.js";
|
|
22
|
+
import { RelayExternalActivityMonitor } from "./relay-external-activity-monitor.js";
|
|
23
|
+
import { RelayQueueService } from "./relay-queue-service.js";
|
|
24
|
+
import { RuntimeSnapshotCache } from "./runtime-cache.js";
|
|
25
|
+
import { activeSessionPriority, activityToUnifiedJob, agentUpdateStatusToUnified, dedupeJobs, hostLoginCommand, hostLogoutCommand, isPromptTerminalActivity, normalizeMimeType, promptActivityToUnifiedJob, shouldRefreshActiveSessions, taskToUnifiedJob, uploadFileDtos, } from "./relay-runtime-helpers.js";
|
|
26
|
+
import { RelayDashboardService } from "./relay-dashboard-service.js";
|
|
27
|
+
import { capabilitiesOf } from "../channels/shared/bot-rendering.js";
|
|
28
|
+
import { renderSessionInfoPlain, renderSessionUsageRows } from "../channels/shared/session-format.js";
|
|
29
|
+
import { SessionLockStore } from "../access/session-locks.js";
|
|
30
|
+
import { SessionRegistry } from "../state/session-registry.js";
|
|
31
|
+
import { createSupportBundle } from "../support/support-bundle.js";
|
|
32
|
+
import { transcribeAudio } from "../artifacts/voice.js";
|
|
33
|
+
import { WebActivityStore, WebChatStore, } from "../web/web-state.js";
|
|
34
|
+
import { evaluateWorkspacePolicy, filterAllowedWorkspaces } from "../core/workspace-policy.js";
|
|
35
|
+
export const WEB_CONTEXT_KEY = "web:dashboard";
|
|
36
|
+
const ACTIVE_CODEX_DISCOVERY_LIMIT = 200;
|
|
37
|
+
const ACTIVE_ACTIVITY_TTL_MS = 6 * 60 * 60 * 1000;
|
|
38
|
+
const MAX_WEB_SESSION_PAGE_SIZE = 50;
|
|
39
|
+
const MAX_CHAT_HISTORY = 250;
|
|
40
|
+
export async function relayRuntimeActiveSessions(runtime) {
|
|
41
|
+
const sessions = new Map();
|
|
42
|
+
const knownContexts = runtime.listKnownContextMetadata();
|
|
43
|
+
const preferences = new BotPreferencesStore(runtime.config.workspace, runtime.config.stateBackend);
|
|
44
|
+
const addActiveSession = (session) => {
|
|
45
|
+
const key = runtime.activeSessionKey(session);
|
|
46
|
+
const existing = sessions.get(key);
|
|
47
|
+
sessions.set(key, runtime.preferredActiveSession(existing, session));
|
|
48
|
+
};
|
|
49
|
+
if (runtime.currentProgress?.status === "running") {
|
|
50
|
+
addActiveSession({
|
|
51
|
+
...runtime.currentProgress,
|
|
52
|
+
contextKey: runtime.contextKey,
|
|
53
|
+
sourceContextKey: runtime.contextKey,
|
|
54
|
+
source: "web",
|
|
55
|
+
status: "running",
|
|
56
|
+
queueLength: runtime.queueService.length(),
|
|
57
|
+
queuePaused: runtime.queueService.isPaused(),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
for (const active of runtime.discoverRunningConnectorSessions()) {
|
|
61
|
+
addActiveSession(active);
|
|
62
|
+
}
|
|
63
|
+
for (const active of runtime.discoverActiveCodexSessions(knownContexts, preferences)) {
|
|
64
|
+
addActiveSession(active);
|
|
65
|
+
}
|
|
66
|
+
for (const meta of knownContexts) {
|
|
67
|
+
if (meta.contextKey === runtime.contextKey && runtime.currentProgress?.status === "running") {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const active = runtime.externalActiveSession(meta, knownContexts, preferences);
|
|
71
|
+
if (active) {
|
|
72
|
+
addActiveSession(active);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
sessions: [...sessions.values()].sort((left, right) => Date.parse(right.updatedAt) - Date.parse(left.updatedAt)),
|
|
77
|
+
updatedAt: new Date().toISOString(),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export async function relayRuntimeGetSession(runtime, deferThreadStart) {
|
|
81
|
+
return runtime.registry.getOrCreate(runtime.contextKey, { deferThreadStart });
|
|
82
|
+
}
|
|
83
|
+
export function relayRuntimeListKnownContextMetadata(runtime) {
|
|
84
|
+
const contexts = new Map();
|
|
85
|
+
const add = (meta) => {
|
|
86
|
+
if (meta?.contextKey) {
|
|
87
|
+
contexts.set(meta.contextKey, meta);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
for (const meta of runtime.registry.listContexts()) {
|
|
91
|
+
add(meta);
|
|
92
|
+
}
|
|
93
|
+
const sharedRegistry = new SessionRegistry(runtime.config);
|
|
94
|
+
try {
|
|
95
|
+
for (const meta of sharedRegistry.listContexts()) {
|
|
96
|
+
add(meta);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
sharedRegistry.disposeAll();
|
|
101
|
+
}
|
|
102
|
+
const current = runtime.registry.get(runtime.contextKey)?.getInfo();
|
|
103
|
+
if (current) {
|
|
104
|
+
add({
|
|
105
|
+
contextKey: runtime.contextKey,
|
|
106
|
+
agentId: current.agentId,
|
|
107
|
+
threadId: current.threadId,
|
|
108
|
+
workspace: current.workspace,
|
|
109
|
+
model: current.model,
|
|
110
|
+
reasoningEffort: current.reasoningEffort,
|
|
111
|
+
launchProfileId: current.nextLaunchProfileId ?? current.launchProfileId,
|
|
112
|
+
sessionPath: current.sessionPath,
|
|
113
|
+
updatedAt: Date.now(),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return [...contexts.values()];
|
|
117
|
+
}
|
|
118
|
+
export function relayRuntimeDiscoverRunningConnectorSessions(runtime) {
|
|
119
|
+
const active = [];
|
|
120
|
+
const terminal = new Set();
|
|
121
|
+
const now = Date.now();
|
|
122
|
+
for (const event of runtime.activityStore.list({ limit: 500 })) {
|
|
123
|
+
if (!event.threadId || !event.agentId || !event.contextKey) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const key = `${event.source}:${event.contextKey}:${event.agentId}:${event.threadId}`;
|
|
127
|
+
if (isPromptTerminalActivity(event)) {
|
|
128
|
+
terminal.add(key);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (event.type !== "prompt_started" || event.status !== "running" || event.source === "cli") {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (terminal.has(key)) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const startedMs = Date.parse(event.timestamp);
|
|
138
|
+
if (!Number.isFinite(startedMs) || now - startedMs > ACTIVE_ACTIVITY_TTL_MS) {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
active.push({
|
|
142
|
+
id: `${event.contextKey}:${event.id}`,
|
|
143
|
+
contextKey: event.contextKey,
|
|
144
|
+
sourceContextKey: event.contextKey,
|
|
145
|
+
source: event.source,
|
|
146
|
+
status: "running",
|
|
147
|
+
agentId: event.agentId,
|
|
148
|
+
agentLabel: event.agentId ? agentLabel(event.agentId) : undefined,
|
|
149
|
+
threadId: event.threadId,
|
|
150
|
+
workspace: event.workspace,
|
|
151
|
+
prompt: event.prompt,
|
|
152
|
+
startedAt: event.timestamp,
|
|
153
|
+
updatedAt: event.timestamp,
|
|
154
|
+
durationMs: Math.max(0, now - startedMs),
|
|
155
|
+
queueLength: runtime.promptStore.list(event.contextKey).length,
|
|
156
|
+
queuePaused: runtime.promptStore.isPaused(event.contextKey),
|
|
157
|
+
detail: event.actor?.label ? `Started by ${event.actor.label}` : undefined,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
return active;
|
|
161
|
+
}
|
|
162
|
+
export function relayRuntimeDiscoverActiveCodexSessions(runtime, knownContexts, preferences) {
|
|
163
|
+
if (!runtime.config.codexEnabled || !enabledAgents(runtime.config).includes("codex")) {
|
|
164
|
+
return [];
|
|
165
|
+
}
|
|
166
|
+
const capabilities = runtime.capabilitiesForAgent("codex");
|
|
167
|
+
if (!capabilities.externalActivity) {
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
const active = [];
|
|
171
|
+
const nowMs = Date.now();
|
|
172
|
+
const staleAfterMs = runtime.config.codexExternalBusyStaleMs;
|
|
173
|
+
for (const thread of listCodexThreads(ACTIVE_CODEX_DISCOVERY_LIMIT)) {
|
|
174
|
+
if (staleAfterMs > 0 && nowMs - thread.updatedAt.getTime() > staleAfterMs) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const meta = {
|
|
178
|
+
contextKey: `cli:codex:${thread.id}`,
|
|
179
|
+
agentId: "codex",
|
|
180
|
+
threadId: thread.id,
|
|
181
|
+
workspace: thread.cwd,
|
|
182
|
+
model: thread.model ?? undefined,
|
|
183
|
+
reasoningEffort: thread.reasoningEffort ?? undefined,
|
|
184
|
+
updatedAt: thread.updatedAt.getTime(),
|
|
185
|
+
};
|
|
186
|
+
const session = runtime.externalActiveSession(meta, knownContexts, preferences);
|
|
187
|
+
if (session) {
|
|
188
|
+
active.push(session);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return active;
|
|
192
|
+
}
|
|
193
|
+
export function relayRuntimeExternalActiveSession(runtime, meta, knownContexts, preferences) {
|
|
194
|
+
if (!meta.threadId) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
const agentId = isAgentId(meta.agentId) ? meta.agentId : runtime.config.defaultAgent;
|
|
198
|
+
if (!enabledAgents(runtime.config).includes(agentId)) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
const capabilities = runtime.capabilitiesForAgent(agentId);
|
|
202
|
+
if (!capabilities.externalActivity) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
if (agentId === "codex" &&
|
|
206
|
+
meta.updatedAt &&
|
|
207
|
+
runtime.config.codexExternalBusyStaleMs > 0 &&
|
|
208
|
+
Date.now() - meta.updatedAt > runtime.config.codexExternalBusyStaleMs) {
|
|
209
|
+
return null;
|
|
210
|
+
}
|
|
211
|
+
const snapshot = getExternalSnapshotForSession(runtime.sessionStubForMetadata(meta, agentId, capabilities), runtime.config, {
|
|
212
|
+
maxEvents: 8,
|
|
213
|
+
});
|
|
214
|
+
if (!snapshot?.activity.active) {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
const startedAt = snapshot.activity.startedAt?.toISOString() ?? new Date().toISOString();
|
|
218
|
+
const updatedAt = snapshot.activity.updatedAt?.toISOString() ?? new Date().toISOString();
|
|
219
|
+
const startedMs = Date.parse(startedAt);
|
|
220
|
+
const sourceContextKey = `cli:${snapshot.agentId}:${snapshot.threadId}`;
|
|
221
|
+
const mirrorChannels = runtime.mirrorRegistry.activeMirrorsForThread(snapshot.agentId, snapshot.threadId, knownContexts, preferences);
|
|
222
|
+
const queueLength = runtime.mirrorRegistry.queueLengthForExternalSource(sourceContextKey, mirrorChannels);
|
|
223
|
+
const mirrorDetail = mirrorChannels.length > 0
|
|
224
|
+
? `Mirroring: ${mirrorChannels.map((mirror) => `${mirror.source} ${mirror.mode}`).join(", ")}`
|
|
225
|
+
: "Mirroring: none";
|
|
226
|
+
return {
|
|
227
|
+
id: `${sourceContextKey}:${snapshot.activity.turnId ?? snapshot.threadId}`,
|
|
228
|
+
contextKey: sourceContextKey,
|
|
229
|
+
sourceContextKey,
|
|
230
|
+
source: "cli",
|
|
231
|
+
status: "external",
|
|
232
|
+
agentId: snapshot.agentId,
|
|
233
|
+
agentLabel: snapshot.agentLabel,
|
|
234
|
+
threadId: snapshot.threadId,
|
|
235
|
+
workspace: meta.workspace,
|
|
236
|
+
prompt: snapshot.latestUserMessage ?? undefined,
|
|
237
|
+
currentTool: snapshot.latestToolName ?? undefined,
|
|
238
|
+
lastTool: snapshot.latestToolName ?? undefined,
|
|
239
|
+
startedAt,
|
|
240
|
+
updatedAt,
|
|
241
|
+
durationMs: Number.isFinite(startedMs) ? Math.max(0, Date.now() - startedMs) : 0,
|
|
242
|
+
queueLength,
|
|
243
|
+
queuePaused: runtime.mirrorRegistry.queuePausedForExternalSource(sourceContextKey, mirrorChannels),
|
|
244
|
+
mirrorChannels,
|
|
245
|
+
detail: `${mirrorDetail} | ${snapshot.sourceLabel}: ${snapshot.sourcePath}`,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
export function relayRuntimeSessionStubForMetadata(runtime, meta, agentId, capabilities) {
|
|
249
|
+
const info = {
|
|
250
|
+
agentId,
|
|
251
|
+
agentLabel: agentLabel(agentId),
|
|
252
|
+
threadId: meta.threadId,
|
|
253
|
+
workspace: meta.workspace,
|
|
254
|
+
model: meta.model,
|
|
255
|
+
reasoningEffort: meta.reasoningEffort,
|
|
256
|
+
launchProfileId: meta.launchProfileId ?? runtime.config.defaultLaunchProfileId,
|
|
257
|
+
launchProfileLabel: meta.launchProfileId ?? runtime.config.defaultLaunchProfileId,
|
|
258
|
+
launchProfileBehavior: "-",
|
|
259
|
+
sandboxMode: "-",
|
|
260
|
+
approvalPolicy: "-",
|
|
261
|
+
fastMode: false,
|
|
262
|
+
unsafeLaunch: false,
|
|
263
|
+
sessionPath: meta.sessionPath,
|
|
264
|
+
capabilities,
|
|
265
|
+
};
|
|
266
|
+
return {
|
|
267
|
+
getInfo: () => info,
|
|
268
|
+
getActiveThreadId: () => meta.threadId,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
export function relayRuntimeCapabilitiesForAgent(runtime, agentId) {
|
|
272
|
+
return listAgentAdapterDescriptors().find((descriptor) => descriptor.id === agentId)?.capabilities ?? CODEX_AGENT_CAPABILITIES;
|
|
273
|
+
}
|
|
274
|
+
export function relayRuntimeActiveSessionKey(runtime, session) {
|
|
275
|
+
return session.threadId ? `${session.agentId ?? "unknown"}:${session.threadId}` : session.id;
|
|
276
|
+
}
|
|
277
|
+
export function relayRuntimePreferredActiveSession(runtime, existing, candidate) {
|
|
278
|
+
if (!existing) {
|
|
279
|
+
return candidate;
|
|
280
|
+
}
|
|
281
|
+
const existingPriority = activeSessionPriority(existing);
|
|
282
|
+
const candidatePriority = activeSessionPriority(candidate);
|
|
283
|
+
if (candidatePriority !== existingPriority) {
|
|
284
|
+
return candidatePriority > existingPriority ? candidate : existing;
|
|
285
|
+
}
|
|
286
|
+
return Date.parse(candidate.updatedAt) >= Date.parse(existing.updatedAt) ? candidate : existing;
|
|
287
|
+
}
|
|
288
|
+
export function relayRuntimeRecordActivity(runtime, input) {
|
|
289
|
+
return runtime.appendActivity(input);
|
|
290
|
+
}
|
|
291
|
+
export function relayRuntimeAppendActivity(runtime, input) {
|
|
292
|
+
const event = runtime.activityStore.append(runtime.enrichActivityInput(input));
|
|
293
|
+
runtime.broadcast({ type: "activity_update", events: runtime.activity({ limit: 50 }) });
|
|
294
|
+
return event;
|
|
295
|
+
}
|
|
296
|
+
export function relayRuntimeEnrichActivityInput(runtime, input) {
|
|
297
|
+
return runtime.enrichActivityFields(input);
|
|
298
|
+
}
|
|
299
|
+
export function relayRuntimeEnrichActivityEvent(runtime, event, info) {
|
|
300
|
+
return runtime.enrichActivityFields(event, info);
|
|
301
|
+
}
|
|
302
|
+
export function relayRuntimeEnrichActivityFields(runtime, event, info) {
|
|
303
|
+
if (!info) {
|
|
304
|
+
return !event.threadId && !event.workspace ? { ...event, workspace: runtime.config.workspace } : event;
|
|
305
|
+
}
|
|
306
|
+
if (event.threadId && info.threadId && event.threadId === info.threadId) {
|
|
307
|
+
return { ...event, workspace: event.workspace ?? info.workspace, agentId: event.agentId ?? info.agentId };
|
|
308
|
+
}
|
|
309
|
+
if (!event.threadId && !event.workspace) {
|
|
310
|
+
return { ...event, workspace: runtime.config.workspace };
|
|
311
|
+
}
|
|
312
|
+
return event;
|
|
313
|
+
}
|
|
314
|
+
export function relayRuntimeAppendAudit(runtime, input) {
|
|
315
|
+
return runtime.auditStore.append({ ...input, channelId: "web" });
|
|
316
|
+
}
|
|
317
|
+
export function relayRuntimeUpdateCurrentProgress(runtime, patch = {}) {
|
|
318
|
+
if (!runtime.currentProgress) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if ("currentTool" in patch) {
|
|
322
|
+
runtime.currentProgress.currentTool = patch.currentTool;
|
|
323
|
+
const { currentTool: _currentTool, ...rest } = patch;
|
|
324
|
+
Object.assign(runtime.currentProgress, rest);
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
Object.assign(runtime.currentProgress, patch);
|
|
328
|
+
}
|
|
329
|
+
runtime.currentProgress.durationMs = Date.now() - runtime.currentTurnStartedAt;
|
|
330
|
+
runtime.currentProgress.updatedAt = new Date().toISOString();
|
|
331
|
+
}
|
|
332
|
+
export function relayRuntimeAddCurrentTool(runtime, toolName) {
|
|
333
|
+
if (!runtime.currentProgress) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const existing = runtime.currentProgress.tools.find((tool) => tool.name === toolName);
|
|
337
|
+
if (existing) {
|
|
338
|
+
existing.count += 1;
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
runtime.currentProgress.tools.push({ name: toolName, count: 1 });
|
|
342
|
+
}
|
|
343
|
+
runtime.updateCurrentProgress({ currentTool: toolName, lastTool: toolName });
|
|
344
|
+
}
|
|
345
|
+
export function relayRuntimeBroadcastQueue(runtime) {
|
|
346
|
+
runtime.broadcast({ type: "queue_update", queue: runtime.queue(), paused: runtime.queuePaused() });
|
|
347
|
+
}
|
|
348
|
+
export function relayRuntimeBroadcastStatus(runtime, message, level = "info") {
|
|
349
|
+
runtime.broadcast({ type: "status", message, level, at: new Date().toISOString() });
|
|
350
|
+
}
|
|
351
|
+
export function relayRuntimeBroadcast(runtime, event) {
|
|
352
|
+
for (const subscriber of runtime.subscribers) {
|
|
353
|
+
try {
|
|
354
|
+
subscriber(event);
|
|
355
|
+
}
|
|
356
|
+
catch {
|
|
357
|
+
runtime.subscribers.delete(subscriber);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (shouldRefreshActiveSessions(event)) {
|
|
361
|
+
runtime.scheduleActiveSessionsBroadcast();
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
export function relayRuntimeScheduleActiveSessionsBroadcast(runtime) {
|
|
365
|
+
if (runtime.activeSessionsBroadcastTimer) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
const delayMs = Math.max(0, 1_000 - (Date.now() - runtime.activeSessionsLastBroadcastAt));
|
|
369
|
+
runtime.activeSessionsBroadcastTimer = setTimeout(() => {
|
|
370
|
+
runtime.activeSessionsBroadcastTimer = null;
|
|
371
|
+
runtime.activeSessionsLastBroadcastAt = Date.now();
|
|
372
|
+
void runtime.activeSessions()
|
|
373
|
+
.then((active) => runtime.broadcast({ type: "active_sessions_update", active }))
|
|
374
|
+
.catch(() => { });
|
|
375
|
+
}, delayMs);
|
|
376
|
+
runtime.activeSessionsBroadcastTimer.unref?.();
|
|
377
|
+
}
|
|
378
|
+
export function relayRuntimePublicInfo(runtime, session) {
|
|
379
|
+
const info = session.getInfo();
|
|
380
|
+
const agentId = info.agentId ?? "codex";
|
|
381
|
+
return {
|
|
382
|
+
...info,
|
|
383
|
+
agentId,
|
|
384
|
+
agentLabel: info.agentLabel ?? agentLabel(agentId),
|
|
385
|
+
capabilities: info.capabilities ?? CODEX_AGENT_CAPABILITIES,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { ensureOutDir } from "../artifacts/artifacts.js";
|
|
3
|
+
import { buildFileInstructions, outboxPath, stageFile, } from "../artifacts/attachments.js";
|
|
4
|
+
import { CODEX_AGENT_CAPABILITIES, agentLabel, agentReasoningLabel, agentReasoningOptions, isAgentId, } from "../agents/shared/agent.js";
|
|
5
|
+
import { getExternalSnapshotForSession } from "../agents/shared/agent-activity.js";
|
|
6
|
+
import { listAgentAdapterDescriptors } from "../agents/shared/agent-adapter.js";
|
|
7
|
+
import { AgentUpdateManager } from "../agents/shared/agent-updates.js";
|
|
8
|
+
import { createAgentSessionService, enabledAgents } from "../agents/shared/agent-factory.js";
|
|
9
|
+
import { AuditLogStore } from "../access/audit-log.js";
|
|
10
|
+
import { BotPreferencesStore } from "../state/bot-preferences.js";
|
|
11
|
+
import { ChannelCommandService } from "../channels/shared/channel-command-service.js";
|
|
12
|
+
import { ChannelTurnService } from "../channels/shared/channel-turn-service.js";
|
|
13
|
+
import { activeSessionSourceForContextKey, ChannelMirrorRegistry } from "../channels/shared/channel-mirror-registry.js";
|
|
14
|
+
import { listThreads as listCodexThreads } from "../agents/codex/codex-state.js";
|
|
15
|
+
import { friendlyErrorText } from "../core/error-messages.js";
|
|
16
|
+
import { clearLogFile, getAgentUpdateLogPath, getConnectorHealth, getConnectorLogPath, getPackageVersion, getUpdateLogPath, getVersionChecks, readConnectorState, readFormattedLogTail, spawnConnectorRestart, spawnSelfUpdate } from "../support/operations.js";
|
|
17
|
+
import { PromptStore, toPromptEnvelope } from "../state/prompt-store.js";
|
|
18
|
+
import { UnifiedJobStore } from "../state/job-store.js";
|
|
19
|
+
import { buildRuntimeMetrics } from "./metrics.js";
|
|
20
|
+
import { RelayArtifactService } from "./relay-artifact-service.js";
|
|
21
|
+
import { RelayAuthService } from "./relay-auth-service.js";
|
|
22
|
+
import { RelayExternalActivityMonitor } from "./relay-external-activity-monitor.js";
|
|
23
|
+
import { RelayQueueService } from "./relay-queue-service.js";
|
|
24
|
+
import { RuntimeSnapshotCache } from "./runtime-cache.js";
|
|
25
|
+
import { activeSessionPriority, activityToUnifiedJob, agentUpdateStatusToUnified, dedupeJobs, hostLoginCommand, hostLogoutCommand, isPromptTerminalActivity, normalizeMimeType, promptActivityToUnifiedJob, shouldRefreshActiveSessions, taskToUnifiedJob, uploadFileDtos, } from "./relay-runtime-helpers.js";
|
|
26
|
+
import { RelayDashboardService } from "./relay-dashboard-service.js";
|
|
27
|
+
import { capabilitiesOf } from "../channels/shared/bot-rendering.js";
|
|
28
|
+
import { renderSessionInfoPlain, renderSessionUsageRows } from "../channels/shared/session-format.js";
|
|
29
|
+
import { SessionLockStore } from "../access/session-locks.js";
|
|
30
|
+
import { SessionRegistry } from "../state/session-registry.js";
|
|
31
|
+
import { createSupportBundle } from "../support/support-bundle.js";
|
|
32
|
+
import { transcribeAudio } from "../artifacts/voice.js";
|
|
33
|
+
import { WebActivityStore, WebChatStore, } from "../web/web-state.js";
|
|
34
|
+
import { evaluateWorkspacePolicy, filterAllowedWorkspaces } from "../core/workspace-policy.js";
|
|
35
|
+
export const WEB_CONTEXT_KEY = "web:dashboard";
|
|
36
|
+
const ACTIVE_CODEX_DISCOVERY_LIMIT = 200;
|
|
37
|
+
const ACTIVE_ACTIVITY_TTL_MS = 6 * 60 * 60 * 1000;
|
|
38
|
+
const MAX_WEB_SESSION_PAGE_SIZE = 50;
|
|
39
|
+
const MAX_CHAT_HISTORY = 250;
|
|
40
|
+
export function relayRuntimeSubscribe(runtime, callback) {
|
|
41
|
+
runtime.subscribers.add(callback);
|
|
42
|
+
void runtime.snapshot().then((data) => callback({ type: "snapshot", data })).catch(() => { });
|
|
43
|
+
void runtime.chatHistory().then((messages) => callback({ type: "chat_history", messages })).catch(() => { });
|
|
44
|
+
void runtime.activeSessions().then((active) => callback({ type: "active_sessions_update", active })).catch(() => { });
|
|
45
|
+
callback({ type: "activity_update", events: runtime.activity({ limit: 50 }) });
|
|
46
|
+
return () => runtime.subscribers.delete(callback);
|
|
47
|
+
}
|
|
48
|
+
export async function relayRuntimeSnapshot(runtime) {
|
|
49
|
+
const session = await runtime.getSession(true);
|
|
50
|
+
const info = runtime.publicInfo(session);
|
|
51
|
+
return {
|
|
52
|
+
session: info,
|
|
53
|
+
sessionText: renderSessionInfoPlain(info),
|
|
54
|
+
queue: runtime.queue(),
|
|
55
|
+
queuePaused: runtime.queuePaused(),
|
|
56
|
+
processing: session.isProcessing(),
|
|
57
|
+
enabledAgents: enabledAgents(runtime.config),
|
|
58
|
+
workspaces: filterAllowedWorkspaces(session.listWorkspaces(), runtime.config),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export async function relayRuntimeStatus(runtime) {
|
|
62
|
+
const cliOptions = runtime.cliPathOptions();
|
|
63
|
+
const [health, versionChecks, snapshot] = await Promise.all([
|
|
64
|
+
getConnectorHealth(cliOptions),
|
|
65
|
+
getVersionChecks(cliOptions),
|
|
66
|
+
runtime.snapshot(),
|
|
67
|
+
]);
|
|
68
|
+
return {
|
|
69
|
+
health,
|
|
70
|
+
versionChecks,
|
|
71
|
+
snapshot,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export async function relayRuntimeBootstrapStatus(runtime) {
|
|
75
|
+
return {
|
|
76
|
+
health: {
|
|
77
|
+
version: await getPackageVersion(),
|
|
78
|
+
state: await readConnectorState(),
|
|
79
|
+
},
|
|
80
|
+
snapshot: await runtime.snapshot(),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export async function relayRuntimeVersion(runtime) {
|
|
84
|
+
return runtime.dashboardService.version();
|
|
85
|
+
}
|
|
86
|
+
export async function relayRuntimeDiagnostics(runtime) {
|
|
87
|
+
return runtime.dashboardService.diagnostics();
|
|
88
|
+
}
|
|
89
|
+
export async function relayRuntimeAdapterHealth(runtime) {
|
|
90
|
+
return runtime.dashboardService.adapterHealth();
|
|
91
|
+
}
|
|
92
|
+
export function relayRuntimePermissions(runtime) {
|
|
93
|
+
return {
|
|
94
|
+
mode: "users",
|
|
95
|
+
message: "Access is managed by NordRelay users, groups, Telegram identities, Telegram chat access records, Discord identities, and Discord channel access records.",
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export async function relayRuntimeMetrics(runtime) {
|
|
99
|
+
const [active, jobs] = await Promise.all([
|
|
100
|
+
runtime.activeSessions(),
|
|
101
|
+
runtime.jobs(),
|
|
102
|
+
]);
|
|
103
|
+
return buildRuntimeMetrics({
|
|
104
|
+
queueLength: runtime.queueService.length(),
|
|
105
|
+
queuePaused: runtime.queueService.isPaused(),
|
|
106
|
+
activeTurnCount: active.sessions.length,
|
|
107
|
+
jobs: jobs.jobs,
|
|
108
|
+
activity: runtime.activity({ limit: 500 }),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
export function relayRuntimeAudit(runtime, options = 50) {
|
|
112
|
+
return runtime.auditStore.list(options);
|
|
113
|
+
}
|
|
114
|
+
export async function relayRuntimeSupportBundle(runtime, actor) {
|
|
115
|
+
const bundle = await createSupportBundle({
|
|
116
|
+
config: runtime.config,
|
|
117
|
+
diagnostics: await runtime.diagnostics(),
|
|
118
|
+
adapterHealth: await runtime.adapterHealth(),
|
|
119
|
+
auditEvents: runtime.auditStore.list(100),
|
|
120
|
+
agentUpdateJobs: runtime.agentUpdates.list(),
|
|
121
|
+
source: "web",
|
|
122
|
+
});
|
|
123
|
+
runtime.appendActivity({
|
|
124
|
+
source: "web",
|
|
125
|
+
status: "info",
|
|
126
|
+
type: "diagnostics_bundle_exported",
|
|
127
|
+
threadId: null,
|
|
128
|
+
workspace: runtime.config.workspace,
|
|
129
|
+
actor,
|
|
130
|
+
detail: bundle.path,
|
|
131
|
+
});
|
|
132
|
+
runtime.appendAudit({
|
|
133
|
+
action: "command",
|
|
134
|
+
status: "ok",
|
|
135
|
+
contextKey: runtime.contextKey,
|
|
136
|
+
actor,
|
|
137
|
+
description: "export diagnostics bundle",
|
|
138
|
+
detail: bundle.path,
|
|
139
|
+
});
|
|
140
|
+
return bundle;
|
|
141
|
+
}
|
|
142
|
+
export async function relayRuntimeLogs(runtime, target = "connector", lines = 100) {
|
|
143
|
+
if (target === "update") {
|
|
144
|
+
return readFormattedLogTail(lines, getUpdateLogPath());
|
|
145
|
+
}
|
|
146
|
+
if (target === "agent-updates") {
|
|
147
|
+
return readFormattedLogTail(lines, getAgentUpdateLogPath());
|
|
148
|
+
}
|
|
149
|
+
return readFormattedLogTail(lines);
|
|
150
|
+
}
|
|
151
|
+
export function relayRuntimeClearLogs(runtime, target = "connector", actor) {
|
|
152
|
+
const result = clearLogFile(target === "update" ? getUpdateLogPath() : target === "agent-updates" ? getAgentUpdateLogPath() : getConnectorLogPath());
|
|
153
|
+
runtime.appendActivity({
|
|
154
|
+
source: "web",
|
|
155
|
+
status: "info",
|
|
156
|
+
type: "logs_cleared",
|
|
157
|
+
threadId: null,
|
|
158
|
+
workspace: runtime.config.workspace,
|
|
159
|
+
actor,
|
|
160
|
+
detail: `Cleared ${target} log.`,
|
|
161
|
+
});
|
|
162
|
+
runtime.appendAudit({
|
|
163
|
+
action: "command",
|
|
164
|
+
status: "ok",
|
|
165
|
+
contextKey: runtime.contextKey,
|
|
166
|
+
actor,
|
|
167
|
+
description: `clear ${target} log`,
|
|
168
|
+
detail: result.filePath,
|
|
169
|
+
});
|
|
170
|
+
return { ok: true, filePath: result.filePath, clearedAt: result.clearedAt.toISOString() };
|
|
171
|
+
}
|
|
172
|
+
export function relayRuntimeRestartConnector(runtime, actor) {
|
|
173
|
+
spawnConnectorRestart();
|
|
174
|
+
runtime.broadcastStatus("Restart requested. The dashboard may disconnect briefly.", "warn");
|
|
175
|
+
runtime.appendActivity({
|
|
176
|
+
source: "web",
|
|
177
|
+
status: "info",
|
|
178
|
+
type: "restart_requested",
|
|
179
|
+
threadId: null,
|
|
180
|
+
workspace: runtime.config.workspace,
|
|
181
|
+
actor,
|
|
182
|
+
detail: "Dashboard requested a connector restart.",
|
|
183
|
+
});
|
|
184
|
+
runtime.appendAudit({
|
|
185
|
+
action: "command",
|
|
186
|
+
status: "ok",
|
|
187
|
+
contextKey: runtime.contextKey,
|
|
188
|
+
actor,
|
|
189
|
+
description: "restart connector",
|
|
190
|
+
});
|
|
191
|
+
return { ok: true, message: "Restart requested." };
|
|
192
|
+
}
|
|
193
|
+
export function relayRuntimeDispose(runtime) {
|
|
194
|
+
if (runtime.externalMonitor) {
|
|
195
|
+
clearInterval(runtime.externalMonitor);
|
|
196
|
+
}
|
|
197
|
+
runtime.dashboardService.stopBackgroundRefresh();
|
|
198
|
+
runtime.agentUpdates.cancelAll();
|
|
199
|
+
runtime.registry.disposeAll();
|
|
200
|
+
runtime.subscribers.clear();
|
|
201
|
+
}
|