@xopcai/xopc 0.0.129 → 0.0.131
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/dist/browser-ext/icons/icon-128.png +0 -0
- package/dist/browser-ext/icons/icon-16.png +0 -0
- package/dist/browser-ext/icons/icon-32.png +0 -0
- package/dist/browser-ext/icons/icon-48.png +0 -0
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/apple-touch-icon.png +0 -0
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DHzfg5D-.js → agent-avatar-dicebear-BJYeTxQ9.js} +1 -1
- package/dist/gateway/static/root/assets/agents-kVsY4Iz_.js +2 -0
- package/dist/gateway/static/root/assets/app-management-settings-panel-Bj8iJ-7d.js +1 -0
- package/dist/gateway/static/root/assets/{appearance-settings-bYeEj3IW.js → appearance-settings-6TjISbHB.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-DC4YwXLL.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-Dy6lsTHw.js → archive-plugin-2G62raBg.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-qOtBYR6Y.js → attachment-load-kLNJMEJh.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-BFH-RfaV.js → automation-suggestion-card-CpcZSSD8.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-MZ8m4bYP.js +4 -0
- package/dist/gateway/static/root/assets/{binary-plugins-DJvi_thc.js → binary-plugins-C_zSrWow.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-DlMnizlt.js → block-editor-D_PMrT-l.js} +4 -4
- package/dist/gateway/static/root/assets/browser-settings-page-C89wKfPd.js +8 -0
- package/dist/gateway/static/root/assets/capability-presets-api-CPFtajl7.js +1 -0
- package/dist/gateway/static/root/assets/{capability-presets-settings-panel-Dng8Grpv.js → capability-presets-settings-panel-DWw31-4v.js} +1 -1
- package/dist/gateway/static/root/assets/channel-recipient-api-BUi8syv2.js +1 -0
- package/dist/gateway/static/root/assets/channels-settings-DOYzcMAE.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-DCE-PgQF.js +2 -0
- package/dist/gateway/static/root/assets/desktop-pet-BYV16wez.js +1 -0
- package/dist/gateway/static/root/assets/{desktop-pet-settings-B-u63N4e.js → desktop-pet-settings-DGIaFqPR.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-8p1ehIHn.js → directory-picker-path-field-BEhDuShd.js} +1 -1
- package/dist/gateway/static/root/assets/dreaming-settings-BIkgLFDH.js +3 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-DJ1ABK95.js → extension-debug-page-BIjLZMAQ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CP9P2lGM.js → extension-page-Cxv4Bgj5.js} +1 -1
- package/dist/gateway/static/root/assets/extension-settings-page-DNd0tRFl.js +1 -0
- package/dist/gateway/static/root/assets/fetch-Bl7zMnmd.js +1 -0
- package/dist/gateway/static/root/assets/gateway-config-api-BiqKIkkp.js +1 -0
- package/dist/gateway/static/root/assets/gateway-settings-D_Cvasqi.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-CY5W2Pp4.js → gateway-startup-retry-CPOgTcpv.js} +1 -1
- package/dist/gateway/static/root/assets/{goal-create-dialog-2lPbGfp3.js → goal-create-dialog-DZ68qzpm.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-DF8QhTHH.js +4 -0
- package/dist/gateway/static/root/assets/goals-config-api-h26_-2Vm.js +1 -0
- package/dist/gateway/static/root/assets/goals-page-BzBKHZJg.js +2 -0
- package/dist/gateway/static/root/assets/goals-settings-BFG1uTI8.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-5vV8vTva.js +1 -0
- package/dist/gateway/static/root/assets/index-DOetFpTt.js +262 -0
- package/dist/gateway/static/root/assets/index-W4ogAiHt.css +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BrENZzM7.js → keyboard-shortcuts-settings-Dpx1ovO6.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-3QO3elfx.js +7 -0
- package/dist/gateway/static/root/assets/{markdown-split-BYF4ReGM.js → markdown-split-Ba4EsPkV.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-CpQDz-QJ.js → media-plugins-lA5rvtCq.js} +1 -1
- package/dist/gateway/static/root/assets/{messages-YzjnURPJ.js → messages-Bq4REfIj.js} +2 -2
- package/dist/gateway/static/root/assets/models-hub-panel-BBG87CHZ.js +2 -0
- package/dist/gateway/static/root/assets/notes-page-DrUGE-Hn.js +1 -0
- package/dist/gateway/static/root/assets/notes-workbench-eAIE8iKV.js +2 -0
- package/dist/gateway/static/root/assets/{page-tabs-RnYYOIWO.js → page-tabs-Cy7bX7Ce.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-CTRt06Ri.js → preview-open-alternatives-B9_iql49.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-Cwct6pCV.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-BXZlzV8t.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-C29EWM0P.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-c4pZeikq.js → save-bar-controls-nMloZ0mp.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-Cb6R7iuP.js → schedule-field-BuajpVNF.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-BqET_hEP.js → schema-form-IeXV_yQk.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-DHHVDqsy.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-hDvmobsT.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-DuOvqNsI.js → settings-collapsible-section-ByixWwvu.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-DptSsbWd.js → settings-form-section-C-5-n-jM.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-BlVfBCb9.js → settings-loading-skeleton-CTA5Gje4.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-DzqxeemF.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-layout-DVt69dJJ.js → settings-page-layout-DgFTf6nM.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-svpHcJ62.js +1 -0
- package/dist/gateway/static/root/assets/share-preview-page-IOjU69FC.js +2 -0
- package/dist/gateway/static/root/assets/shares-settings-Ddg8gHPN.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-DcNOEJsK.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-DoonnYRs.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-CW22OkZ4.js → system-settings-panel-BMDD7FXg.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-BqpGAKxV.js → typed-models-lib-DayamJ56.js} +1 -1
- package/dist/gateway/static/root/assets/use-channel-catalog-ChYwFiqo.js +1 -0
- package/dist/gateway/static/root/assets/{user-profile-settings-panel-CERVLuaW.js → user-profile-settings-panel-Dd0X3mPv.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-BnmysurA.js → utils-D9v9ZpK4.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-QXGvjTwa.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-CP-5OUYI.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-Ci9GSPnS.js → workflow-run-setup-panel-IidqhbUI.js} +2 -2
- package/dist/gateway/static/root/assets/{workflow-start-dialog-BhDj8pqH.js → workflow-start-dialog-BQQkr8YD.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-DtVIjVSX.js +18 -0
- package/dist/gateway/static/root/favicon-16x16.png +0 -0
- package/dist/gateway/static/root/favicon-32x32.png +0 -0
- package/dist/gateway/static/root/favicon-icon.svg +23 -1
- package/dist/gateway/static/root/favicon.ico +0 -0
- package/dist/gateway/static/root/favicon.png +0 -0
- package/dist/gateway/static/root/favicon.svg +20 -24
- package/dist/gateway/static/root/index.html +11 -11
- package/dist/gateway/static/root/logo-dark.svg +18 -23
- package/dist/gateway/static/root/logo.svg +18 -24
- package/dist/gateway/static/root/pwa-192x192.png +0 -0
- package/dist/gateway/static/root/pwa-512x512.png +0 -0
- package/dist/gateway/static/root/site.webmanifest +23 -0
- package/dist/package.js +1 -1
- package/dist/src/cli/commands/gateway/probe.js +6 -6
- package/dist/src/cli/commands/gateway/probe.js.map +1 -1
- package/dist/src/cli/commands/onboard.js +2 -2
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/cli/commands/tui.js +11 -4
- package/dist/src/cli/commands/tui.js.map +1 -1
- package/dist/src/cli/utils/gateway-client-options.d.ts +3 -0
- package/dist/src/cli/utils/gateway-client-options.js +2 -1
- package/dist/src/cli/utils/gateway-client-options.js.map +1 -1
- package/dist/src/cli/utils/gateway-client.d.ts +6 -3
- package/dist/src/cli/utils/gateway-client.js +14 -8
- package/dist/src/cli/utils/gateway-client.js.map +1 -1
- package/dist/src/gateway/credential.d.ts +9 -0
- package/dist/src/gateway/credential.js +16 -0
- package/dist/src/gateway/credential.js.map +1 -0
- package/dist/src/gateway/hono/app.d.ts +0 -1
- package/dist/src/gateway/hono/app.js +2 -9
- package/dist/src/gateway/hono/app.js.map +1 -1
- package/dist/src/gateway/hono/middleware/auth.d.ts +0 -2
- package/dist/src/gateway/hono/middleware/auth.js +46 -21
- package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +2 -27
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/server.js +1 -5
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/mcp/channel-bridge.d.ts +2 -1
- package/dist/src/mcp/channel-bridge.js +10 -6
- package/dist/src/mcp/channel-bridge.js.map +1 -1
- package/dist/src/mcp/channel-server.d.ts +2 -1
- package/dist/src/mcp/channel-server.js +1 -1
- package/dist/src/mcp/channel-server.js.map +1 -1
- package/dist/src/mcp/gateway-http-client.d.ts +3 -2
- package/dist/src/mcp/gateway-http-client.js +9 -7
- package/dist/src/mcp/gateway-http-client.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +3 -2
- package/dist/src/tui/backends/gateway-sse-backend.js +45 -41
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/tui-types.d.ts +3 -2
- package/dist/src/tui/tui-types.js.map +1 -1
- package/dist/src/tui/tui.js +1 -1
- package/dist/src/tui/tui.js.map +1 -1
- package/package.json +5 -2
- package/dist/gateway/static/root/assets/agents-CMxKKFQD.js +0 -2
- package/dist/gateway/static/root/assets/app-management-settings-panel-ptk9c5BN.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-DdZvDf5B.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-B8JTjkCr.js +0 -4
- package/dist/gateway/static/root/assets/browser-settings-page-slHLiZgi.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-api-D4q7vHVJ.js +0 -1
- package/dist/gateway/static/root/assets/channel-recipient-api-BrW5Kcgc.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-KIsISXw0.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-C5fx4Qs9.js +0 -2
- package/dist/gateway/static/root/assets/desktop-pet-Jmdn6q47.js +0 -1
- package/dist/gateway/static/root/assets/dreaming-settings-CCkKP-I4.js +0 -3
- package/dist/gateway/static/root/assets/extension-settings-page-DnhU-tx0.js +0 -1
- package/dist/gateway/static/root/assets/fetch-BMjlW0g1.js +0 -1
- package/dist/gateway/static/root/assets/gateway-config-api-CjxDn46s.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-TING7224.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-DHWVRafk.js +0 -4
- package/dist/gateway/static/root/assets/goals-config-api-BqhuxG8P.js +0 -1
- package/dist/gateway/static/root/assets/goals-page-CMk-9ZYN.js +0 -2
- package/dist/gateway/static/root/assets/goals-settings-BHzOAU_l.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-BQIm0P3V.js +0 -1
- package/dist/gateway/static/root/assets/index-C4k6QSXw.js +0 -257
- package/dist/gateway/static/root/assets/index-EKmpPvZj.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-BiL302Ve.js +0 -2
- package/dist/gateway/static/root/assets/models-hub-panel-CFPpl3Cq.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-BurgcdVZ.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-BAELRM_O.js +0 -2
- package/dist/gateway/static/root/assets/project-detail-page-iXX1Ceo2.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-GDVTFAY7.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BUrbUnwv.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CiOreA2k.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-C-qvptlu.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-xQx2Pkg5.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-DWB8VdLK.js +0 -1
- package/dist/gateway/static/root/assets/share-preview-page-8m_ACH0z.js +0 -2
- package/dist/gateway/static/root/assets/shares-settings-CgxfhNxI.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BBFUOxmf.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-bo695odu.js +0 -2
- package/dist/gateway/static/root/assets/url-DFGNSBNT.js +0 -1
- package/dist/gateway/static/root/assets/use-channel-catalog-CPdJ0o0i.js +0 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-Jr3jvPcB.js +0 -1
- package/dist/gateway/static/root/assets/work-item-detail-page-B-8rex4u.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-Brb3UGvs.js +0 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.js","names":[],"sources":["../../../../../src/gateway/hono/routes/sessions.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { buildSessionKey } from '../../../routing/session-key.js';\nimport { resolveProjectAgentId } from '../../../projects/index.js';\nimport type { SessionMetadataSeed } from '../../../storage/sqlite/index.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\nimport { createGatewayRouteLogger, logRouteError } from '../lib/route-logger.js';\nimport { messagesToClientHistory } from '../../../session/client-history.js';\nimport type { SessionType } from '../../../session/types.js';\nimport { computeUserRoundDeleteRange } from '../../../session/user-round-delete.js';\nimport { deleteMediaUrisNoLongerReferenced } from '../../../media/session-references.js';\nimport { respondStartupUnavailable } from '../lib/startup-unavailable.js';\nimport type { StartupUnavailableGatewayMethod } from '../../startup-readiness.js';\nimport { evictEmbeddedSessionRunner } from '../../../agent/embedded/session-runner.js';\n\nconst log = createGatewayRouteLogger('Sessions');\n\ntype SessionsStartupMethod = StartupUnavailableGatewayMethod;\n\nconst SESSION_TYPES = new Set<SessionType>(['chat', 'workflow-run', 'workflow-subagent', 'cron', 'heartbeat']);\nconst DEFAULT_SIDEBAR_STALE_DAYS = 60;\n\nfunction isSessionType(value: string): value is SessionType {\n return SESSION_TYPES.has(value as SessionType);\n}\n\nfunction ensureGatewayReadyForSessions(\n c: Parameters<typeof respondStartupUnavailable>[0],\n service: AuthenticatedRouteDeps['service'],\n method: SessionsStartupMethod,\n): Response | null {\n if (service.isGatewayReady()) {\n return null;\n }\n return respondStartupUnavailable(c, method);\n}\n\nfunction parsePositiveInt(value: string | undefined, fallback: number, max: number): number {\n const parsed = value ? Number.parseInt(value, 10) : fallback;\n if (!Number.isFinite(parsed)) return fallback;\n return Math.min(max, Math.max(1, parsed));\n}\n\nfunction parseOffset(value: string | undefined): number {\n const parsed = value ? Number.parseInt(value, 10) : 0;\n return Number.isFinite(parsed) ? Math.max(0, parsed) : 0;\n}\n\nfunction buildDirectSessionMetadata(params: {\n agentId: string;\n source: string;\n accountId: string;\n peerId: string;\n}): SessionMetadataSeed {\n return {\n sourceChannel: params.source,\n sourceChatId: [params.accountId, 'direct', params.peerId].join(':'),\n sessionType: 'chat',\n hiddenFromSessionList: true,\n routing: {\n agentId: params.agentId,\n source: params.source,\n accountId: params.accountId,\n peerKind: 'direct',\n peerId: params.peerId,\n },\n customData: {\n genericNewChatShell: params.source === 'webchat' && params.peerId.startsWith('chat_'),\n },\n };\n}\n\nfunction isGenericNewChatShell(session: {\n messageCount?: number;\n routing?: { agentId?: string; peerId?: string };\n projectId?: string;\n customData?: Record<string, unknown>;\n parentSessionKey?: string;\n workflowRunId?: string;\n workflowDefinitionId?: string;\n}, agentId: string, projectId: string | undefined): boolean {\n if (session.messageCount !== 0) return false;\n if (session.routing?.agentId !== agentId) return false;\n if (projectId ? session.projectId !== projectId : Boolean(session.projectId)) return false;\n if (session.parentSessionKey || session.workflowRunId || session.workflowDefinitionId) return false;\n if (session.customData?.genericNewChatShell === false) return false;\n const sourceBinding = session.customData?.sourceBinding;\n if (sourceBinding && typeof sourceBinding === 'object') return false;\n return Boolean(session.routing?.peerId?.startsWith('chat_'));\n}\n\nexport function registerSessionsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n // ========== Session REST API (/api/sessions) ==========\n\n authenticated.get('/api/sidebar/chat-list', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.list');\n if (blocked) {\n return blocked;\n }\n\n const projectLimit = parsePositiveInt(c.req.query('projectLimit'), 12, 50);\n const projectOffset = parseOffset(c.req.query('projectOffset'));\n const sessionPreviewLimit = parsePositiveInt(c.req.query('sessionPreviewLimit'), 5, 20);\n const inboxLimit = parsePositiveInt(c.req.query('inboxLimit'), 20, 100);\n const inboxOffset = parseOffset(c.req.query('inboxOffset'));\n const staleDays = parsePositiveInt(c.req.query('staleDays'), DEFAULT_SIDEBAR_STALE_DAYS, 3650);\n const updatedAfter = Date.now() - staleDays * 24 * 60 * 60 * 1000;\n const includeSessionKey = c.req.query('includeSessionKey')?.trim() || undefined;\n\n const projects = service.projects.listWithSidebarSessions({\n status: 'active',\n limit: projectLimit,\n offset: projectOffset,\n updatedAfter,\n includePinned: true,\n includeSessionKey,\n });\n const projectItems = await Promise.all(\n projects.items.map(async (project) => {\n const sessions = await service.sessions.listSessions({\n projectId: project.id,\n limit: sessionPreviewLimit,\n offset: 0,\n updatedAfter,\n includePinned: true,\n includeSessionKey,\n sortBy: 'updatedAt',\n sortOrder: 'desc',\n });\n return {\n project,\n sessions: sessions.items,\n sessionTotal: sessions.total,\n sessionHasMore: sessions.hasMore,\n };\n }),\n );\n const inbox = await service.sessions.listSessions({\n unassigned: true,\n limit: inboxLimit,\n offset: inboxOffset,\n updatedAfter,\n includePinned: true,\n includeSessionKey,\n sortBy: 'updatedAt',\n sortOrder: 'desc',\n });\n\n return c.json({\n ok: true,\n projects: {\n items: projectItems,\n total: projects.total,\n limit: projects.limit,\n offset: projects.offset,\n hasMore: projects.hasMore,\n },\n inbox,\n });\n });\n\n // POST /api/sessions - Create new session (reuses empty sessions)\n authenticated.post('/api/sessions', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const channel = body.channel || 'webchat';\n const projectId = typeof body.projectId === 'string' && body.projectId.trim() ? body.projectId.trim() : undefined;\n const routingCfg = service.currentConfig;\n if (projectId && !service.projects.get(projectId)) {\n return c.json({ ok: false, error: 'Project not found' }, 404);\n }\n const agentId = resolveProjectAgentId({\n config: routingCfg,\n projects: service.projects,\n explicitAgentId: typeof body.agentId === 'string' ? body.agentId : undefined,\n projectId,\n });\n\n // If a specific chat_id is provided, use it (for advanced use cases)\n // Otherwise, try to find and reuse an existing empty session\n if (body.chat_id) {\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: body.chat_id,\n });\n\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: buildDirectSessionMetadata({\n agentId,\n source: channel,\n accountId: 'default',\n peerId: body.chat_id,\n }),\n });\n if (projectId) {\n service.projects.attachSession(sessionKey, projectId);\n }\n const session = await service.sessions.getSession(sessionKey);\n return c.json({ session }, 201);\n }\n\n // Look for existing empty sessions to reuse\n const existingSessions = await service.sessions.listSessions({\n channel,\n includeHidden: true,\n limit: 50,\n sortBy: 'updatedAt',\n sortOrder: 'desc',\n });\n \n // Reuse an empty session only when it matches the requested agent (session key embeds agent id).\n const emptySession = existingSessions.items.find((s) => {\n return isGenericNewChatShell(s, agentId, projectId);\n });\n \n if (emptySession) {\n // Return existing empty session instead of creating a new one\n const session = await service.sessions.getSession(emptySession.key);\n return c.json({ session, reused: true }, 200);\n }\n \n // No empty session found, create a new one\n const chatId = `chat_${Date.now()}`;\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: chatId,\n });\n\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: buildDirectSessionMetadata({\n agentId,\n source: channel,\n accountId: 'default',\n peerId: chatId,\n }),\n });\n\n if (projectId) {\n service.projects.attachSession(sessionKey, projectId);\n }\n const session = await service.sessions.getSession(sessionKey);\n return c.json({ session }, 201);\n });\n\n // GET /api/sessions - List sessions\n authenticated.get('/api/sessions', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.list');\n if (blocked) {\n return blocked;\n }\n const query = c.req.query();\n const sessionTypes = query.types\n ?.split(',')\n .map((value) => value.trim())\n .filter(isSessionType);\n const result = await service.sessions.listSessions({\n status: query.status as any,\n search: query.search,\n channel: query.channel,\n sessionTypes: sessionTypes?.length ? sessionTypes : undefined,\n includeHidden: query.includeHidden === 'true',\n projectId: query.projectId,\n unassigned: query.unassigned === 'true',\n updatedAfter: query.updatedAfter ? parseInt(query.updatedAfter) : undefined,\n includePinned: query.includePinned === 'true',\n includeSessionKey: query.includeSessionKey,\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/sessions/stats - Get session stats (must be before /:key)\n authenticated.get('/api/sessions/stats', async (c) => {\n const result = await service.sessions.stats();\n return c.json(result);\n });\n\n // GET /api/sessions/chat-ids - Get unique chat IDs from sessions (must be before /:key)\n authenticated.get('/api/sessions/chat-ids', async (c) => {\n const channel = c.req.query('channel');\n const chatIds = await service.sessions.chatIds(channel || undefined);\n return c.json({ ok: true, payload: { chatIds } });\n });\n\n // GET /api/sessions/resolve?sessionId=... - Resolve OpenClaw-style session id to canonical key.\n authenticated.get('/api/sessions/resolve', async (c) => {\n const result = await service.sessions.resolveSession({\n sessionId: c.req.query('sessionId'),\n sessionKey: c.req.query('sessionKey') ?? c.req.query('key'),\n });\n if (!result) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: result });\n });\n\n // POST /api/sessions/resolve - Resolve by JSON body (`sessionId`, `sessionKey`, or `key`).\n authenticated.post('/api/sessions/resolve', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const result = await service.sessions.resolveSession({\n sessionId: typeof body.sessionId === 'string' ? body.sessionId : undefined,\n sessionKey: typeof body.sessionKey === 'string' ? body.sessionKey : undefined,\n key: typeof body.key === 'string' ? body.key : undefined,\n });\n if (!result) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: result });\n });\n\n // GET /api/sessions/:key/run — read-only active webchat agent run (for UI resume)\n authenticated.get('/api/sessions/:key/run', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.run');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: service.sessions.getActiveRun(key) });\n });\n\n // GET /api/sessions/:key/agent-config — resolved session agent settings (thinking, etc.)\n authenticated.get('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const payload = await service.sessions.getAgentConfig(key);\n return c.json({ ok: true, payload });\n });\n\n authenticated.patch('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const result = await service.sessions.patchAgentConfig(key, body);\n if (!result.ok) {\n return c.json({ ok: false, error: result.error }, 400);\n }\n return c.json({ ok: true });\n });\n\n // GET /api/sessions/:key/messages — flattened transcript for TUI / clients\n authenticated.get('/api/sessions/:key/messages', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.messages');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const limitRaw = c.req.query('limit');\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : undefined;\n const limit =\n parsedLimit !== undefined && Number.isFinite(parsedLimit)\n ? Math.min(500, Math.max(1, parsedLimit))\n : undefined;\n\n const before = c.req.query('before')?.trim();\n const offsetRaw = c.req.query('offset');\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n\n const result = await service.sessions.getMessagePage(key, {\n limit,\n offset,\n ...(before ? { before } : {}),\n });\n if (!result) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n\n const messages = messagesToClientHistory(result.session.messages, { limit });\n return c.json({\n ok: true,\n payload: { messages },\n pagination: result.pagination,\n });\n });\n\n // GET /api/sessions/:key/history — UI chat history page from the newest tail.\n authenticated.get('/api/sessions/:key/history', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const offsetRaw = c.req.query('offset');\n const limitRaw = c.req.query('limit');\n const before = c.req.query('before')?.trim();\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : 50;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n const limit = Number.isFinite(parsedLimit) ? Math.min(200, Math.max(1, parsedLimit)) : 50;\n const result = await service.sessions.getMessagePage(key, {\n offset,\n limit,\n ...(before ? { before } : {}),\n });\n\n if (!result) {\n return c.json({ error: 'Session not found' }, 404);\n }\n\n return c.json(result);\n });\n\n // GET /api/sessions/:key/timeline — row-backed conversation outline for Web / TUI navigation.\n authenticated.get('/api/sessions/:key/timeline', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const items = await service.sessions.getTimeline(key);\n if (!items) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, items });\n });\n\n // GET /api/sessions/:key/transcript/window — TUI-focused transcript slice around a row.\n authenticated.get('/api/sessions/:key/transcript/window', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const rowNumberRaw = c.req.query('rowNumber');\n const rowNumber = rowNumberRaw ? Number.parseInt(rowNumberRaw, 10) : NaN;\n if (!Number.isFinite(rowNumber) || rowNumber < 1) {\n return c.json({ ok: false, error: 'rowNumber must be a positive integer' }, 400);\n }\n const before = parsePositiveInt(c.req.query('before'), 80, 200);\n const after = parsePositiveInt(c.req.query('after'), 120, 200);\n const window = await service.sessions.getTranscriptWindow(key, { rowNumber, before, after });\n if (!window) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: window });\n });\n\n // POST /api/sessions/:key/transcript/context — append persisted-only `kind: 'context'` row (not in LLM context)\n authenticated.post('/api/sessions/:key/transcript/context', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const id = typeof body.id === 'string' && body.id.trim() ? body.id.trim() : undefined;\n const text = typeof body.text === 'string' ? body.text : undefined;\n const data =\n body.data !== undefined && typeof body.data === 'object' && body.data !== null && !Array.isArray(body.data)\n ? (body.data as Record<string, unknown>)\n : undefined;\n await service.sessionIndexInstance.appendTranscriptContextEntry(key, { id, text, data });\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/label — append label change for a transcript entry.\n authenticated.post('/api/sessions/:key/transcript/label', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const targetId = typeof body.targetId === 'string' ? body.targetId.trim() : '';\n if (!targetId) {\n return c.json({ ok: false, error: 'targetId is required' }, 400);\n }\n const label = typeof body.label === 'string' && body.label.trim() ? body.label.trim() : undefined;\n await service.sessionIndexInstance.appendTranscriptLabelEntry(key, { targetId, label });\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/custom — append extension state for TUI replay.\n authenticated.post('/api/sessions/:key/transcript/custom', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const customType = typeof body.customType === 'string' ? body.customType.trim() : '';\n if (!customType) {\n return c.json({ ok: false, error: 'customType is required' }, 400);\n }\n await service.sessionIndexInstance.appendTranscriptCustomEntry(key, {\n customType,\n data: body.data,\n });\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/custom-message — append visible extension custom message.\n authenticated.post('/api/sessions/:key/transcript/custom-message', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const customType = typeof body.customType === 'string' ? body.customType.trim() : '';\n if (!customType) {\n return c.json({ ok: false, error: 'customType is required' }, 400);\n }\n const content =\n typeof body.content === 'string' || Array.isArray(body.content) ? body.content : '';\n await service.sessionIndexInstance.appendTranscriptCustomMessageEntry(key, {\n customType,\n content,\n display: typeof body.display === 'boolean' ? body.display : undefined,\n details: body.details,\n });\n evictEmbeddedSessionRunner(key, 'gateway_custom_message_appended');\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/bash — append local TUI shell execution.\n authenticated.post('/api/sessions/:key/transcript/bash', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const command = typeof body.command === 'string' ? body.command.trim() : '';\n if (!command) {\n return c.json({ ok: false, error: 'command is required' }, 400);\n }\n await service.sessionIndexInstance.appendTranscriptBashExecutionEntry(key, {\n command,\n output: typeof body.output === 'string' ? body.output : '',\n exitCode: typeof body.exitCode === 'number' ? body.exitCode : body.exitCode === null ? null : undefined,\n signal: typeof body.signal === 'string' ? body.signal : body.signal === null ? null : undefined,\n excludeFromContext: body.excludeFromContext === true,\n truncated: body.truncated === true,\n fullOutputPath: typeof body.fullOutputPath === 'string' ? body.fullOutputPath : undefined,\n });\n evictEmbeddedSessionRunner(key, 'gateway_bash_execution_appended');\n return c.json({ ok: true });\n });\n\n // GET /api/sessions/:key/compaction/checkpoints — list pre-compaction snapshots (OpenClaw-style)\n authenticated.get('/api/sessions/:key/compaction/checkpoints', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const checkpoints = await service.sessions.listCompactionCheckpoints(key);\n return c.json({ ok: true, payload: { checkpoints } });\n });\n\n authenticated.get('/api/sessions/:key/compaction/checkpoints/:checkpointId', async (c) => {\n const key = c.req.param('key');\n const checkpointId = c.req.param('checkpointId');\n const checkpoint = await service.sessions.getCompactionCheckpoint(key, checkpointId);\n if (!checkpoint) {\n return c.json({ ok: false, error: 'Checkpoint not found' }, 404);\n }\n return c.json({ ok: true, payload: { checkpoint } });\n });\n\n authenticated.post('/api/sessions/:key/compaction/restore', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const checkpointId = typeof body.checkpointId === 'string' ? body.checkpointId.trim() : '';\n if (!checkpointId) {\n return c.json({ ok: false, error: 'checkpointId required' }, 400);\n }\n try {\n await service.sessions.restoreCompactionCheckpoint(key, checkpointId);\n } catch (err) {\n logRouteError(log, c, err, 'gateway.route.sessions', { operation: 'restoreCheckpoint', sessionKey: key });\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes('not found') || msg.includes('Invalid')) {\n return c.json({ ok: false, error: msg }, 404);\n }\n return c.json({ ok: false, error: msg }, 500);\n }\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, session });\n });\n\n authenticated.post('/api/sessions/:key/compaction/run', async (c) => {\n const key = c.req.param('key');\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const instructions = typeof body.instructions === 'string' ? body.instructions : undefined;\n const force = typeof body.force === 'boolean' ? body.force : true;\n const result = await service.sessions.runCompaction(key, { instructions, force });\n return c.json({ ok: true, payload: { result } });\n });\n\n // GET /api/sessions/:key - Get single session (must be after /stats and /chat-ids)\n authenticated.get('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const includeRaw = c.req.query('include') ?? '';\n const includeSet = new Set(\n includeRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n );\n const includeTranscript = includeSet.has('transcript');\n const includeTranscriptRows = includeSet.has('transcriptRows');\n const offsetRaw = c.req.query('offset');\n const limitRaw = c.req.query('limit');\n const hasPagingQuery = offsetRaw !== undefined || limitRaw !== undefined;\n\n if (hasPagingQuery) {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : 50;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n const limit = Number.isFinite(parsedLimit) ? Math.min(200, Math.max(1, parsedLimit)) : 50;\n const result = await service.sessions.getMessagePage(key, {\n offset,\n limit,\n includeTranscriptSummary: includeTranscript,\n includeTranscriptRows,\n });\n if (!result) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json(result);\n }\n\n const session = await service.sessions.getSession(key, {\n includeTranscriptSummary: includeTranscript,\n includeTranscriptRows,\n });\n if (!session) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json({ session });\n });\n\n // PATCH /api/sessions/:key - Partial metadata (name, tags, customData); OpenClaw-style patch subset\n authenticated.patch('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const patch: {\n name?: string;\n tags?: string[];\n replaceTags?: boolean;\n customData?: Record<string, unknown>;\n } = {};\n if (typeof body.name === 'string') {\n patch.name = body.name;\n }\n if (Array.isArray(body.tags)) {\n patch.tags = body.tags;\n }\n if (typeof body.replaceTags === 'boolean') {\n patch.replaceTags = body.replaceTags;\n }\n if (body.customData !== undefined && typeof body.customData === 'object' && body.customData !== null) {\n patch.customData = body.customData as Record<string, unknown>;\n }\n let requestedProjectId: string | null | undefined;\n if ('projectId' in body) {\n requestedProjectId = typeof body.projectId === 'string' && body.projectId.trim() ? body.projectId.trim() : null;\n if (requestedProjectId && !service.projects.get(requestedProjectId)) {\n return c.json({ ok: false, error: 'Project not found' }, 404);\n }\n }\n const result = await service.sessions.patch(key, patch);\n if (result.ok === false) {\n return c.json({ ok: false, error: result.error }, 404);\n }\n if (requestedProjectId !== undefined) {\n try {\n if (requestedProjectId) {\n service.projects.attachSession(key, requestedProjectId);\n } else {\n service.projects.detachSession(key);\n }\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n }\n\n const session = await service.sessions.getSession(key);\n return c.json({ ok: true, session });\n });\n\n // GET /api/sessions/:key/export - Export session (must be before /:key)\n authenticated.get('/api/sessions/:key/export', async (c) => {\n const key = c.req.param('key');\n const format = c.req.query('format') as any || 'json';\n const result = await service.sessions.export(key, format);\n return c.json(result);\n });\n\n authenticated.post('/api/sessions/import', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const targetKey = typeof body.targetKey === 'string' ? body.targetKey : '';\n const content = typeof body.content === 'string' ? body.content : '';\n if (!targetKey.trim()) {\n return c.json({ ok: false, error: 'targetKey is required' }, 400);\n }\n if (!content.trim()) {\n return c.json({ ok: false, error: 'content is required' }, 400);\n }\n try {\n const result = await service.sessions.importExport(targetKey, content);\n return c.json({ ok: true, ...result });\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: errorMessage }, 400);\n }\n });\n\n authenticated.post('/api/sessions/:key/btw', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const question = typeof body.question === 'string' ? body.question : '';\n const result = await service.sessions.btwQuery(key, question);\n return c.json(result);\n });\n\n authenticated.post('/api/sessions/:key/fork', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const targetKey = typeof body.targetKey === 'string' ? body.targetKey : '';\n if (!targetKey.trim()) {\n return c.json({ ok: false, error: 'targetKey is required' }, 400);\n }\n try {\n const result = await service.sessions.fork(key, targetKey);\n return c.json({ ok: true, ...result });\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: errorMessage }, 400);\n }\n });\n\n authenticated.post('/api/sessions/:key/fork-row', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const targetKey = typeof body.targetKey === 'string' ? body.targetKey : '';\n const throughRow = typeof body.throughRow === 'number' ? Math.trunc(body.throughRow) : NaN;\n if (!targetKey.trim()) {\n return c.json({ ok: false, error: 'targetKey is required' }, 400);\n }\n if (!Number.isFinite(throughRow) || throughRow < 1) {\n return c.json({ ok: false, error: 'throughRow must be a positive integer' }, 400);\n }\n try {\n const result = await service.sessions.forkRows(key, targetKey, { throughRow });\n return c.json({ ok: true, ...result });\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: errorMessage }, 400);\n }\n });\n\n // DELETE /api/sessions/:key/messages — delete LLM rows by range or by user turn.\n // `userRoundIndex` (0-based among user messages) removes the user row and every following\n // assistant / tool / toolResult row until the next user. Prefer this from the web console so\n // tool loops are not left orphaned after retry/delete.\n authenticated.delete('/api/sessions/:key/messages', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const loaded = await service.sessionIndexInstance.loadMessages(key);\n if (!loaded) {\n return c.json({ error: 'Session not found' }, 404);\n }\n\n let startIndex = typeof body.startIndex === 'number' ? body.startIndex : -1;\n let count = typeof body.count === 'number' ? body.count : 0;\n const userRoundIndex =\n typeof body.userRoundIndex === 'number' ? body.userRoundIndex : undefined;\n\n if (userRoundIndex !== undefined) {\n const range = computeUserRoundDeleteRange(loaded, userRoundIndex);\n if (!range) {\n return c.json({ error: 'User round index out of range' }, 400);\n }\n startIndex = range.startIndex;\n count = range.count;\n }\n\n if (startIndex < 0 || count <= 0) {\n return c.json({ error: 'Invalid startIndex or count' }, 400);\n }\n if (startIndex >= loaded.length) {\n return c.json({ error: 'Index out of range' }, 400);\n }\n const deleteCount = Math.min(count, loaded.length - startIndex);\n const removed = loaded.slice(startIndex, startIndex + deleteCount);\n const next = loaded.slice(0, startIndex).concat(loaded.slice(startIndex + deleteCount));\n await service.sessionIndexInstance.saveMessages(key, next);\n await deleteMediaUrisNoLongerReferenced({ removed, remaining: next });\n return c.json({ ok: true, deleted: deleteCount });\n });\n\n // POST /api/sessions/:key/reset - Reset session (archive transcript, new session id; keep key + overrides)\n authenticated.post('/api/sessions/:key/reset', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.reset');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const result = await service.sessions.reset(key);\n if (result.ok === false) {\n const status = result.error === 'Session not found' ? 404 : 400;\n return c.json({ ok: false, error: result.error }, status);\n }\n const session = await service.sessions.getSession(key);\n return c.json({\n ok: true,\n reset: true,\n sessionId: result.sessionId,\n previousSessionId: result.previousSessionId,\n session,\n });\n });\n\n // DELETE /api/sessions/:key - Delete session (removes key from index)\n authenticated.delete('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.delete(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/archive - Archive session\n authenticated.post('/api/sessions/:key/archive', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.archive(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unarchive - Unarchive session\n authenticated.post('/api/sessions/:key/unarchive', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.unarchive(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/pin - Pin session\n authenticated.post('/api/sessions/:key/pin', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.pin(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unpin - Unpin session\n authenticated.post('/api/sessions/:key/unpin', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.unpin(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/rename - Rename session\n authenticated.post('/api/sessions/:key/rename', async (c) => {\n const key = c.req.param('key');\n\n const body = await c.req.json();\n const { name } = body;\n const result = await service.sessions.rename(key, name);\n return c.json(result);\n });\n\n // ========== Subagent REST API (/api/subagents) ==========\n\n // GET /api/subagents - List subagent sessions\n authenticated.get('/api/subagents', async (c) => {\n const query = c.req.query();\n const result = await service.sessions.listSubagents({\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/subagents/:key - Get subagent session detail\n authenticated.get('/api/subagents/:key', async (c) => {\n const key = c.req.param('key');\n // Verify it's a subagent session\n if (!key.startsWith('subagent:')) {\n return c.json({ error: 'Not a subagent session' }, 400);\n }\n const includeRaw = c.req.query('include') ?? '';\n const includeSet = new Set(\n includeRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n );\n const session = await service.sessions.getSession(key, {\n includeTranscriptSummary: includeSet.has('transcript'),\n includeTranscriptRows: includeSet.has('transcriptRows'),\n });\n if (!session) {\n return c.json({ error: 'Subagent session not found' }, 404);\n }\n return c.json({ session });\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sessions.js","names":[],"sources":["../../../../../src/gateway/hono/routes/sessions.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { Hono } from 'hono';\n\nimport { buildSessionKey } from '../../../routing/session-key.js';\nimport { resolveProjectAgentId } from '../../../projects/index.js';\nimport type { SessionMetadataSeed } from '../../../storage/sqlite/index.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\nimport { createGatewayRouteLogger, logRouteError } from '../lib/route-logger.js';\nimport { messagesToClientHistory } from '../../../session/client-history.js';\nimport type { SessionType } from '../../../session/types.js';\nimport { computeUserRoundDeleteRange } from '../../../session/user-round-delete.js';\nimport { deleteMediaUrisNoLongerReferenced } from '../../../media/session-references.js';\nimport { respondStartupUnavailable } from '../lib/startup-unavailable.js';\nimport type { StartupUnavailableGatewayMethod } from '../../startup-readiness.js';\nimport { evictEmbeddedSessionRunner } from '../../../agent/embedded/session-runner.js';\n\nconst log = createGatewayRouteLogger('Sessions');\n\ntype SessionsStartupMethod = StartupUnavailableGatewayMethod;\n\nconst SESSION_TYPES = new Set<SessionType>(['chat', 'workflow-run', 'workflow-subagent', 'cron', 'heartbeat']);\nconst DEFAULT_SIDEBAR_STALE_DAYS = 60;\n\nfunction isSessionType(value: string): value is SessionType {\n return SESSION_TYPES.has(value as SessionType);\n}\n\nfunction ensureGatewayReadyForSessions(\n c: Parameters<typeof respondStartupUnavailable>[0],\n service: AuthenticatedRouteDeps['service'],\n method: SessionsStartupMethod,\n): Response | null {\n if (service.isGatewayReady()) {\n return null;\n }\n return respondStartupUnavailable(c, method);\n}\n\nfunction parsePositiveInt(value: string | undefined, fallback: number, max: number): number {\n const parsed = value ? Number.parseInt(value, 10) : fallback;\n if (!Number.isFinite(parsed)) return fallback;\n return Math.min(max, Math.max(1, parsed));\n}\n\nfunction parseOffset(value: string | undefined): number {\n const parsed = value ? Number.parseInt(value, 10) : 0;\n return Number.isFinite(parsed) ? Math.max(0, parsed) : 0;\n}\n\nfunction buildDirectSessionMetadata(params: {\n agentId: string;\n source: string;\n accountId: string;\n peerId: string;\n}): SessionMetadataSeed {\n return {\n sourceChannel: params.source,\n sourceChatId: [params.accountId, 'direct', params.peerId].join(':'),\n sessionType: 'chat',\n hiddenFromSessionList: true,\n routing: {\n agentId: params.agentId,\n source: params.source,\n accountId: params.accountId,\n peerKind: 'direct',\n peerId: params.peerId,\n },\n customData: {\n genericNewChatShell: params.source === 'webchat' && params.peerId.startsWith('chat_'),\n },\n };\n}\n\nexport function registerSessionsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n // ========== Session REST API (/api/sessions) ==========\n\n authenticated.get('/api/sidebar/chat-list', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.list');\n if (blocked) {\n return blocked;\n }\n\n const projectLimit = parsePositiveInt(c.req.query('projectLimit'), 12, 50);\n const projectOffset = parseOffset(c.req.query('projectOffset'));\n const sessionPreviewLimit = parsePositiveInt(c.req.query('sessionPreviewLimit'), 5, 20);\n const inboxLimit = parsePositiveInt(c.req.query('inboxLimit'), 20, 100);\n const inboxOffset = parseOffset(c.req.query('inboxOffset'));\n const staleDays = parsePositiveInt(c.req.query('staleDays'), DEFAULT_SIDEBAR_STALE_DAYS, 3650);\n const updatedAfter = Date.now() - staleDays * 24 * 60 * 60 * 1000;\n const includeSessionKey = c.req.query('includeSessionKey')?.trim() || undefined;\n\n const projects = service.projects.listWithSidebarSessions({\n status: 'active',\n limit: projectLimit,\n offset: projectOffset,\n updatedAfter,\n includePinned: true,\n includeSessionKey,\n });\n const projectItems = await Promise.all(\n projects.items.map(async (project) => {\n const sessions = await service.sessions.listSessions({\n projectId: project.id,\n limit: sessionPreviewLimit,\n offset: 0,\n updatedAfter,\n includePinned: true,\n includeSessionKey,\n sortBy: 'updatedAt',\n sortOrder: 'desc',\n });\n return {\n project,\n sessions: sessions.items,\n sessionTotal: sessions.total,\n sessionHasMore: sessions.hasMore,\n };\n }),\n );\n const inbox = await service.sessions.listSessions({\n unassigned: true,\n limit: inboxLimit,\n offset: inboxOffset,\n updatedAfter,\n includePinned: true,\n includeSessionKey,\n sortBy: 'updatedAt',\n sortOrder: 'desc',\n });\n\n return c.json({\n ok: true,\n projects: {\n items: projectItems,\n total: projects.total,\n limit: projects.limit,\n offset: projects.offset,\n hasMore: projects.hasMore,\n },\n inbox,\n });\n });\n\n // POST /api/sessions - Create a new session. Empty-shell reuse is a client concern.\n authenticated.post('/api/sessions', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const channel = body.channel || 'webchat';\n const projectId = typeof body.projectId === 'string' && body.projectId.trim() ? body.projectId.trim() : undefined;\n const routingCfg = service.currentConfig;\n if (projectId && !service.projects.get(projectId)) {\n return c.json({ ok: false, error: 'Project not found' }, 404);\n }\n const agentId = resolveProjectAgentId({\n config: routingCfg,\n projects: service.projects,\n explicitAgentId: typeof body.agentId === 'string' ? body.agentId : undefined,\n projectId,\n });\n\n // If a specific chat_id is provided, use it (for advanced use cases).\n if (body.chat_id) {\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: body.chat_id,\n });\n\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: buildDirectSessionMetadata({\n agentId,\n source: channel,\n accountId: 'default',\n peerId: body.chat_id,\n }),\n });\n if (projectId) {\n service.projects.attachSession(sessionKey, projectId);\n }\n const session = await service.sessions.getSession(sessionKey);\n return c.json({ session }, 201);\n }\n\n const chatId = `chat_${randomUUID()}`;\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: chatId,\n });\n\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: buildDirectSessionMetadata({\n agentId,\n source: channel,\n accountId: 'default',\n peerId: chatId,\n }),\n });\n\n if (projectId) {\n service.projects.attachSession(sessionKey, projectId);\n }\n const session = await service.sessions.getSession(sessionKey);\n return c.json({ session }, 201);\n });\n\n // GET /api/sessions - List sessions\n authenticated.get('/api/sessions', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.list');\n if (blocked) {\n return blocked;\n }\n const query = c.req.query();\n const sessionTypes = query.types\n ?.split(',')\n .map((value) => value.trim())\n .filter(isSessionType);\n const result = await service.sessions.listSessions({\n status: query.status as any,\n search: query.search,\n channel: query.channel,\n sessionTypes: sessionTypes?.length ? sessionTypes : undefined,\n includeHidden: query.includeHidden === 'true',\n projectId: query.projectId,\n unassigned: query.unassigned === 'true',\n updatedAfter: query.updatedAfter ? parseInt(query.updatedAfter) : undefined,\n includePinned: query.includePinned === 'true',\n includeSessionKey: query.includeSessionKey,\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/sessions/stats - Get session stats (must be before /:key)\n authenticated.get('/api/sessions/stats', async (c) => {\n const result = await service.sessions.stats();\n return c.json(result);\n });\n\n // GET /api/sessions/chat-ids - Get unique chat IDs from sessions (must be before /:key)\n authenticated.get('/api/sessions/chat-ids', async (c) => {\n const channel = c.req.query('channel');\n const chatIds = await service.sessions.chatIds(channel || undefined);\n return c.json({ ok: true, payload: { chatIds } });\n });\n\n // GET /api/sessions/resolve?sessionId=... - Resolve OpenClaw-style session id to canonical key.\n authenticated.get('/api/sessions/resolve', async (c) => {\n const result = await service.sessions.resolveSession({\n sessionId: c.req.query('sessionId'),\n sessionKey: c.req.query('sessionKey') ?? c.req.query('key'),\n });\n if (!result) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: result });\n });\n\n // POST /api/sessions/resolve - Resolve by JSON body (`sessionId`, `sessionKey`, or `key`).\n authenticated.post('/api/sessions/resolve', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const result = await service.sessions.resolveSession({\n sessionId: typeof body.sessionId === 'string' ? body.sessionId : undefined,\n sessionKey: typeof body.sessionKey === 'string' ? body.sessionKey : undefined,\n key: typeof body.key === 'string' ? body.key : undefined,\n });\n if (!result) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: result });\n });\n\n // GET /api/sessions/:key/run — read-only active webchat agent run (for UI resume)\n authenticated.get('/api/sessions/:key/run', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.run');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: service.sessions.getActiveRun(key) });\n });\n\n // GET /api/sessions/:key/agent-config — resolved session agent settings (thinking, etc.)\n authenticated.get('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const payload = await service.sessions.getAgentConfig(key);\n return c.json({ ok: true, payload });\n });\n\n authenticated.patch('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const result = await service.sessions.patchAgentConfig(key, body);\n if (!result.ok) {\n return c.json({ ok: false, error: result.error }, 400);\n }\n return c.json({ ok: true });\n });\n\n // GET /api/sessions/:key/messages — flattened transcript for TUI / clients\n authenticated.get('/api/sessions/:key/messages', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.messages');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const limitRaw = c.req.query('limit');\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : undefined;\n const limit =\n parsedLimit !== undefined && Number.isFinite(parsedLimit)\n ? Math.min(500, Math.max(1, parsedLimit))\n : undefined;\n\n const before = c.req.query('before')?.trim();\n const offsetRaw = c.req.query('offset');\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n\n const result = await service.sessions.getMessagePage(key, {\n limit,\n offset,\n ...(before ? { before } : {}),\n });\n if (!result) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n\n const messages = messagesToClientHistory(result.session.messages, { limit });\n return c.json({\n ok: true,\n payload: { messages },\n pagination: result.pagination,\n });\n });\n\n // GET /api/sessions/:key/history — UI chat history page from the newest tail.\n authenticated.get('/api/sessions/:key/history', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const offsetRaw = c.req.query('offset');\n const limitRaw = c.req.query('limit');\n const before = c.req.query('before')?.trim();\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : 50;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n const limit = Number.isFinite(parsedLimit) ? Math.min(200, Math.max(1, parsedLimit)) : 50;\n const result = await service.sessions.getMessagePage(key, {\n offset,\n limit,\n ...(before ? { before } : {}),\n });\n\n if (!result) {\n return c.json({ error: 'Session not found' }, 404);\n }\n\n return c.json(result);\n });\n\n // GET /api/sessions/:key/timeline — row-backed conversation outline for Web / TUI navigation.\n authenticated.get('/api/sessions/:key/timeline', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const items = await service.sessions.getTimeline(key);\n if (!items) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, items });\n });\n\n // GET /api/sessions/:key/transcript/window — TUI-focused transcript slice around a row.\n authenticated.get('/api/sessions/:key/transcript/window', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const rowNumberRaw = c.req.query('rowNumber');\n const rowNumber = rowNumberRaw ? Number.parseInt(rowNumberRaw, 10) : NaN;\n if (!Number.isFinite(rowNumber) || rowNumber < 1) {\n return c.json({ ok: false, error: 'rowNumber must be a positive integer' }, 400);\n }\n const before = parsePositiveInt(c.req.query('before'), 80, 200);\n const after = parsePositiveInt(c.req.query('after'), 120, 200);\n const window = await service.sessions.getTranscriptWindow(key, { rowNumber, before, after });\n if (!window) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, payload: window });\n });\n\n // POST /api/sessions/:key/transcript/context — append persisted-only `kind: 'context'` row (not in LLM context)\n authenticated.post('/api/sessions/:key/transcript/context', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const id = typeof body.id === 'string' && body.id.trim() ? body.id.trim() : undefined;\n const text = typeof body.text === 'string' ? body.text : undefined;\n const data =\n body.data !== undefined && typeof body.data === 'object' && body.data !== null && !Array.isArray(body.data)\n ? (body.data as Record<string, unknown>)\n : undefined;\n await service.sessionIndexInstance.appendTranscriptContextEntry(key, { id, text, data });\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/label — append label change for a transcript entry.\n authenticated.post('/api/sessions/:key/transcript/label', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const targetId = typeof body.targetId === 'string' ? body.targetId.trim() : '';\n if (!targetId) {\n return c.json({ ok: false, error: 'targetId is required' }, 400);\n }\n const label = typeof body.label === 'string' && body.label.trim() ? body.label.trim() : undefined;\n await service.sessionIndexInstance.appendTranscriptLabelEntry(key, { targetId, label });\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/custom — append extension state for TUI replay.\n authenticated.post('/api/sessions/:key/transcript/custom', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const customType = typeof body.customType === 'string' ? body.customType.trim() : '';\n if (!customType) {\n return c.json({ ok: false, error: 'customType is required' }, 400);\n }\n await service.sessionIndexInstance.appendTranscriptCustomEntry(key, {\n customType,\n data: body.data,\n });\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/custom-message — append visible extension custom message.\n authenticated.post('/api/sessions/:key/transcript/custom-message', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const customType = typeof body.customType === 'string' ? body.customType.trim() : '';\n if (!customType) {\n return c.json({ ok: false, error: 'customType is required' }, 400);\n }\n const content =\n typeof body.content === 'string' || Array.isArray(body.content) ? body.content : '';\n await service.sessionIndexInstance.appendTranscriptCustomMessageEntry(key, {\n customType,\n content,\n display: typeof body.display === 'boolean' ? body.display : undefined,\n details: body.details,\n });\n evictEmbeddedSessionRunner(key, 'gateway_custom_message_appended');\n return c.json({ ok: true });\n });\n\n // POST /api/sessions/:key/transcript/bash — append local TUI shell execution.\n authenticated.post('/api/sessions/:key/transcript/bash', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const command = typeof body.command === 'string' ? body.command.trim() : '';\n if (!command) {\n return c.json({ ok: false, error: 'command is required' }, 400);\n }\n await service.sessionIndexInstance.appendTranscriptBashExecutionEntry(key, {\n command,\n output: typeof body.output === 'string' ? body.output : '',\n exitCode: typeof body.exitCode === 'number' ? body.exitCode : body.exitCode === null ? null : undefined,\n signal: typeof body.signal === 'string' ? body.signal : body.signal === null ? null : undefined,\n excludeFromContext: body.excludeFromContext === true,\n truncated: body.truncated === true,\n fullOutputPath: typeof body.fullOutputPath === 'string' ? body.fullOutputPath : undefined,\n });\n evictEmbeddedSessionRunner(key, 'gateway_bash_execution_appended');\n return c.json({ ok: true });\n });\n\n // GET /api/sessions/:key/compaction/checkpoints — list pre-compaction snapshots (OpenClaw-style)\n authenticated.get('/api/sessions/:key/compaction/checkpoints', async (c) => {\n const key = c.req.param('key');\n const meta = await service.sessionIndexInstance.getSessionMetadata(key);\n if (!meta) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const checkpoints = await service.sessions.listCompactionCheckpoints(key);\n return c.json({ ok: true, payload: { checkpoints } });\n });\n\n authenticated.get('/api/sessions/:key/compaction/checkpoints/:checkpointId', async (c) => {\n const key = c.req.param('key');\n const checkpointId = c.req.param('checkpointId');\n const checkpoint = await service.sessions.getCompactionCheckpoint(key, checkpointId);\n if (!checkpoint) {\n return c.json({ ok: false, error: 'Checkpoint not found' }, 404);\n }\n return c.json({ ok: true, payload: { checkpoint } });\n });\n\n authenticated.post('/api/sessions/:key/compaction/restore', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const checkpointId = typeof body.checkpointId === 'string' ? body.checkpointId.trim() : '';\n if (!checkpointId) {\n return c.json({ ok: false, error: 'checkpointId required' }, 400);\n }\n try {\n await service.sessions.restoreCompactionCheckpoint(key, checkpointId);\n } catch (err) {\n logRouteError(log, c, err, 'gateway.route.sessions', { operation: 'restoreCheckpoint', sessionKey: key });\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes('not found') || msg.includes('Invalid')) {\n return c.json({ ok: false, error: msg }, 404);\n }\n return c.json({ ok: false, error: msg }, 500);\n }\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n return c.json({ ok: true, session });\n });\n\n authenticated.post('/api/sessions/:key/compaction/run', async (c) => {\n const key = c.req.param('key');\n const session = await service.sessions.getSession(key);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const instructions = typeof body.instructions === 'string' ? body.instructions : undefined;\n const force = typeof body.force === 'boolean' ? body.force : true;\n const result = await service.sessions.runCompaction(key, { instructions, force });\n return c.json({ ok: true, payload: { result } });\n });\n\n // GET /api/sessions/:key - Get single session (must be after /stats and /chat-ids)\n authenticated.get('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const includeRaw = c.req.query('include') ?? '';\n const includeSet = new Set(\n includeRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n );\n const includeTranscript = includeSet.has('transcript');\n const includeTranscriptRows = includeSet.has('transcriptRows');\n const offsetRaw = c.req.query('offset');\n const limitRaw = c.req.query('limit');\n const hasPagingQuery = offsetRaw !== undefined || limitRaw !== undefined;\n\n if (hasPagingQuery) {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.history');\n if (blocked) {\n return blocked;\n }\n const parsedOffset = offsetRaw ? Number.parseInt(offsetRaw, 10) : 0;\n const parsedLimit = limitRaw ? Number.parseInt(limitRaw, 10) : 50;\n const offset = Number.isFinite(parsedOffset) ? Math.max(0, parsedOffset) : 0;\n const limit = Number.isFinite(parsedLimit) ? Math.min(200, Math.max(1, parsedLimit)) : 50;\n const result = await service.sessions.getMessagePage(key, {\n offset,\n limit,\n includeTranscriptSummary: includeTranscript,\n includeTranscriptRows,\n });\n if (!result) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json(result);\n }\n\n const session = await service.sessions.getSession(key, {\n includeTranscriptSummary: includeTranscript,\n includeTranscriptRows,\n });\n if (!session) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json({ session });\n });\n\n // PATCH /api/sessions/:key - Partial metadata (name, tags, customData); OpenClaw-style patch subset\n authenticated.patch('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const patch: {\n name?: string;\n tags?: string[];\n replaceTags?: boolean;\n customData?: Record<string, unknown>;\n } = {};\n if (typeof body.name === 'string') {\n patch.name = body.name;\n }\n if (Array.isArray(body.tags)) {\n patch.tags = body.tags;\n }\n if (typeof body.replaceTags === 'boolean') {\n patch.replaceTags = body.replaceTags;\n }\n if (body.customData !== undefined && typeof body.customData === 'object' && body.customData !== null) {\n patch.customData = body.customData as Record<string, unknown>;\n }\n let requestedProjectId: string | null | undefined;\n if ('projectId' in body) {\n requestedProjectId = typeof body.projectId === 'string' && body.projectId.trim() ? body.projectId.trim() : null;\n if (requestedProjectId && !service.projects.get(requestedProjectId)) {\n return c.json({ ok: false, error: 'Project not found' }, 404);\n }\n }\n const result = await service.sessions.patch(key, patch);\n if (result.ok === false) {\n return c.json({ ok: false, error: result.error }, 404);\n }\n if (requestedProjectId !== undefined) {\n try {\n if (requestedProjectId) {\n service.projects.attachSession(key, requestedProjectId);\n } else {\n service.projects.detachSession(key);\n }\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n }\n\n const session = await service.sessions.getSession(key);\n return c.json({ ok: true, session });\n });\n\n // GET /api/sessions/:key/export - Export session (must be before /:key)\n authenticated.get('/api/sessions/:key/export', async (c) => {\n const key = c.req.param('key');\n const format = c.req.query('format') as any || 'json';\n const result = await service.sessions.export(key, format);\n return c.json(result);\n });\n\n authenticated.post('/api/sessions/import', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const targetKey = typeof body.targetKey === 'string' ? body.targetKey : '';\n const content = typeof body.content === 'string' ? body.content : '';\n if (!targetKey.trim()) {\n return c.json({ ok: false, error: 'targetKey is required' }, 400);\n }\n if (!content.trim()) {\n return c.json({ ok: false, error: 'content is required' }, 400);\n }\n try {\n const result = await service.sessions.importExport(targetKey, content);\n return c.json({ ok: true, ...result });\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: errorMessage }, 400);\n }\n });\n\n authenticated.post('/api/sessions/:key/btw', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const question = typeof body.question === 'string' ? body.question : '';\n const result = await service.sessions.btwQuery(key, question);\n return c.json(result);\n });\n\n authenticated.post('/api/sessions/:key/fork', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const targetKey = typeof body.targetKey === 'string' ? body.targetKey : '';\n if (!targetKey.trim()) {\n return c.json({ ok: false, error: 'targetKey is required' }, 400);\n }\n try {\n const result = await service.sessions.fork(key, targetKey);\n return c.json({ ok: true, ...result });\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: errorMessage }, 400);\n }\n });\n\n authenticated.post('/api/sessions/:key/fork-row', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const targetKey = typeof body.targetKey === 'string' ? body.targetKey : '';\n const throughRow = typeof body.throughRow === 'number' ? Math.trunc(body.throughRow) : NaN;\n if (!targetKey.trim()) {\n return c.json({ ok: false, error: 'targetKey is required' }, 400);\n }\n if (!Number.isFinite(throughRow) || throughRow < 1) {\n return c.json({ ok: false, error: 'throughRow must be a positive integer' }, 400);\n }\n try {\n const result = await service.sessions.forkRows(key, targetKey, { throughRow });\n return c.json({ ok: true, ...result });\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n return c.json({ ok: false, error: errorMessage }, 400);\n }\n });\n\n // DELETE /api/sessions/:key/messages — delete LLM rows by range or by user turn.\n // `userRoundIndex` (0-based among user messages) removes the user row and every following\n // assistant / tool / toolResult row until the next user. Prefer this from the web console so\n // tool loops are not left orphaned after retry/delete.\n authenticated.delete('/api/sessions/:key/messages', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const loaded = await service.sessionIndexInstance.loadMessages(key);\n if (!loaded) {\n return c.json({ error: 'Session not found' }, 404);\n }\n\n let startIndex = typeof body.startIndex === 'number' ? body.startIndex : -1;\n let count = typeof body.count === 'number' ? body.count : 0;\n const userRoundIndex =\n typeof body.userRoundIndex === 'number' ? body.userRoundIndex : undefined;\n\n if (userRoundIndex !== undefined) {\n const range = computeUserRoundDeleteRange(loaded, userRoundIndex);\n if (!range) {\n return c.json({ error: 'User round index out of range' }, 400);\n }\n startIndex = range.startIndex;\n count = range.count;\n }\n\n if (startIndex < 0 || count <= 0) {\n return c.json({ error: 'Invalid startIndex or count' }, 400);\n }\n if (startIndex >= loaded.length) {\n return c.json({ error: 'Index out of range' }, 400);\n }\n const deleteCount = Math.min(count, loaded.length - startIndex);\n const removed = loaded.slice(startIndex, startIndex + deleteCount);\n const next = loaded.slice(0, startIndex).concat(loaded.slice(startIndex + deleteCount));\n await service.sessionIndexInstance.saveMessages(key, next);\n await deleteMediaUrisNoLongerReferenced({ removed, remaining: next });\n return c.json({ ok: true, deleted: deleteCount });\n });\n\n // POST /api/sessions/:key/reset - Reset session (archive transcript, new session id; keep key + overrides)\n authenticated.post('/api/sessions/:key/reset', async (c) => {\n const blocked = ensureGatewayReadyForSessions(c, service, 'sessions.reset');\n if (blocked) {\n return blocked;\n }\n const key = c.req.param('key');\n const result = await service.sessions.reset(key);\n if (result.ok === false) {\n const status = result.error === 'Session not found' ? 404 : 400;\n return c.json({ ok: false, error: result.error }, status);\n }\n const session = await service.sessions.getSession(key);\n return c.json({\n ok: true,\n reset: true,\n sessionId: result.sessionId,\n previousSessionId: result.previousSessionId,\n session,\n });\n });\n\n // DELETE /api/sessions/:key - Delete session (removes key from index)\n authenticated.delete('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.delete(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/archive - Archive session\n authenticated.post('/api/sessions/:key/archive', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.archive(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unarchive - Unarchive session\n authenticated.post('/api/sessions/:key/unarchive', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.unarchive(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/pin - Pin session\n authenticated.post('/api/sessions/:key/pin', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.pin(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unpin - Unpin session\n authenticated.post('/api/sessions/:key/unpin', async (c) => {\n const key = c.req.param('key');\n const result = await service.sessions.unpin(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/rename - Rename session\n authenticated.post('/api/sessions/:key/rename', async (c) => {\n const key = c.req.param('key');\n\n const body = await c.req.json();\n const { name } = body;\n const result = await service.sessions.rename(key, name);\n return c.json(result);\n });\n\n // ========== Subagent REST API (/api/subagents) ==========\n\n // GET /api/subagents - List subagent sessions\n authenticated.get('/api/subagents', async (c) => {\n const query = c.req.query();\n const result = await service.sessions.listSubagents({\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/subagents/:key - Get subagent session detail\n authenticated.get('/api/subagents/:key', async (c) => {\n const key = c.req.param('key');\n // Verify it's a subagent session\n if (!key.startsWith('subagent:')) {\n return c.json({ error: 'Not a subagent session' }, 400);\n }\n const includeRaw = c.req.query('include') ?? '';\n const includeSet = new Set(\n includeRaw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean),\n );\n const session = await service.sessions.getSession(key, {\n includeTranscriptSummary: includeSet.has('transcript'),\n includeTranscriptRows: includeSet.has('transcriptRows'),\n });\n if (!session) {\n return c.json({ error: 'Subagent session not found' }, 404);\n }\n return c.json({ session });\n });\n}\n"],"mappings":"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"}
|
|
@@ -51,11 +51,7 @@ var GatewayServer = class {
|
|
|
51
51
|
});
|
|
52
52
|
const { configureTunnelFromGatewayConfig } = await import("../tunnel/gateway-lifecycle.js");
|
|
53
53
|
await configureTunnelFromGatewayConfig(this.service.currentConfig, { deferWellKnownFetch: true });
|
|
54
|
-
const
|
|
55
|
-
const app = createHonoApp({
|
|
56
|
-
service: this.service,
|
|
57
|
-
token: effectiveToken
|
|
58
|
-
});
|
|
54
|
+
const app = createHonoApp({ service: this.service });
|
|
59
55
|
const primaryHost = listenHosts[0] ?? bindHost;
|
|
60
56
|
const attachUpgrade = (server) => {
|
|
61
57
|
server.on("upgrade", (req, socket, head) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","names":[],"sources":["../../../src/gateway/server.ts"],"sourcesContent":["import { serve, type ServerType } from '@hono/node-server';\nimport type { IncomingMessage } from 'node:http';\nimport type { Socket } from 'node:net';\n\nimport { ensureXopcCliOnPath } from '../infra/path-env.js';\n\nensureXopcCliOnPath();\n\nimport type { GatewayBindMode } from '../config/schema.js';\nimport { resolveGatewayBindHost, resolveGatewayListenHosts } from '../config/gateway-bind.js';\nimport { resolveGatewayListenPlan } from './listen.js';\nimport { GatewayService } from './service.js';\nimport { createHonoApp } from './hono/app.js';\nimport { handleSiteShareUpgrade } from '../share/site-share-router.js';\n\nexport interface GatewayServerConfig {\n port: number;\n /** Resolved listen address (sync plan); re-validated async at start when possible. */\n bindHost: string;\n bind?: GatewayBindMode;\n customBindHost?: string;\n token?: string;\n verbose?: boolean;\n configPath?: string;\n enableHotReload?: boolean;\n}\n\nexport class GatewayServer {\n private server?: ServerType;\n private extraServers: ServerType[] = [];\n private config: GatewayServerConfig;\n private service: GatewayService;\n\n constructor(config: GatewayServerConfig) {\n this.config = config;\n this.service = new GatewayService({\n configPath: config.configPath,\n enableHotReload: config.enableHotReload,\n deferChannelConnectUntilAfterHttp: true,\n listenBind: config.bind,\n listenCustomBindHost: config.customBindHost,\n listenPort: config.port,\n });\n }\n\n async start(): Promise<void> {\n const cfg = this.service.currentConfig;\n const plan = resolveGatewayListenPlan({\n cfg,\n bindOverride: this.config.bind,\n });\n\n let bindHost: string;\n try {\n bindHost = await resolveGatewayBindHost({\n bindMode: plan.bindMode,\n customBindHost: plan.customBindHost ?? this.config.customBindHost,\n });\n } catch (err) {\n bindHost = plan.bindHost;\n if (plan.bindMode === 'custom') {\n throw err;\n }\n }\n\n if (plan.bindMode === 'custom') {\n const expected = plan.customBindHost?.trim();\n if (!expected || bindHost !== expected) {\n throw new Error(\n `gateway bind=custom requested ${expected ?? '(missing)'} but resolved ${bindHost}`,\n );\n }\n }\n\n const listenHosts = await resolveGatewayListenHosts(bindHost);\n console.log(`[GatewayServer] Starting gateway server on ${bindHost}:${this.config.port}...`);\n\n await this.service.start();\n this.service.registerGatewayShutdownForRestart(async () => {\n await this.stop();\n });\n\n const { configureTunnelFromGatewayConfig } = await import('../tunnel/gateway-lifecycle.js');\n await configureTunnelFromGatewayConfig(this.service.currentConfig, { deferWellKnownFetch: true });\n\n const
|
|
1
|
+
{"version":3,"file":"server.js","names":[],"sources":["../../../src/gateway/server.ts"],"sourcesContent":["import { serve, type ServerType } from '@hono/node-server';\nimport type { IncomingMessage } from 'node:http';\nimport type { Socket } from 'node:net';\n\nimport { ensureXopcCliOnPath } from '../infra/path-env.js';\n\nensureXopcCliOnPath();\n\nimport type { GatewayBindMode } from '../config/schema.js';\nimport { resolveGatewayBindHost, resolveGatewayListenHosts } from '../config/gateway-bind.js';\nimport { resolveGatewayListenPlan } from './listen.js';\nimport { GatewayService } from './service.js';\nimport { createHonoApp } from './hono/app.js';\nimport { handleSiteShareUpgrade } from '../share/site-share-router.js';\n\nexport interface GatewayServerConfig {\n port: number;\n /** Resolved listen address (sync plan); re-validated async at start when possible. */\n bindHost: string;\n bind?: GatewayBindMode;\n customBindHost?: string;\n token?: string;\n verbose?: boolean;\n configPath?: string;\n enableHotReload?: boolean;\n}\n\nexport class GatewayServer {\n private server?: ServerType;\n private extraServers: ServerType[] = [];\n private config: GatewayServerConfig;\n private service: GatewayService;\n\n constructor(config: GatewayServerConfig) {\n this.config = config;\n this.service = new GatewayService({\n configPath: config.configPath,\n enableHotReload: config.enableHotReload,\n deferChannelConnectUntilAfterHttp: true,\n listenBind: config.bind,\n listenCustomBindHost: config.customBindHost,\n listenPort: config.port,\n });\n }\n\n async start(): Promise<void> {\n const cfg = this.service.currentConfig;\n const plan = resolveGatewayListenPlan({\n cfg,\n bindOverride: this.config.bind,\n });\n\n let bindHost: string;\n try {\n bindHost = await resolveGatewayBindHost({\n bindMode: plan.bindMode,\n customBindHost: plan.customBindHost ?? this.config.customBindHost,\n });\n } catch (err) {\n bindHost = plan.bindHost;\n if (plan.bindMode === 'custom') {\n throw err;\n }\n }\n\n if (plan.bindMode === 'custom') {\n const expected = plan.customBindHost?.trim();\n if (!expected || bindHost !== expected) {\n throw new Error(\n `gateway bind=custom requested ${expected ?? '(missing)'} but resolved ${bindHost}`,\n );\n }\n }\n\n const listenHosts = await resolveGatewayListenHosts(bindHost);\n console.log(`[GatewayServer] Starting gateway server on ${bindHost}:${this.config.port}...`);\n\n await this.service.start();\n this.service.registerGatewayShutdownForRestart(async () => {\n await this.stop();\n });\n\n const { configureTunnelFromGatewayConfig } = await import('../tunnel/gateway-lifecycle.js');\n await configureTunnelFromGatewayConfig(this.service.currentConfig, { deferWellKnownFetch: true });\n\n const app = createHonoApp({ service: this.service });\n\n const primaryHost = listenHosts[0] ?? bindHost;\n const attachUpgrade = (server: ServerType): void => {\n // `@hono/node-server`'s `serve()` returns the underlying `http.Server`.\n const inner = server as unknown as {\n on(event: 'upgrade', listener: (req: IncomingMessage, socket: Socket, head: Buffer) => void): void;\n };\n inner.on('upgrade', (req, socket, head) => {\n try {\n handleSiteShareUpgrade(this.service, req, socket, head);\n } catch (err) {\n console.error('[GatewayServer] site-share upgrade error:', err);\n try {\n socket.destroy();\n } catch {\n /* ignore */\n }\n }\n });\n };\n\n this.server = serve(\n {\n fetch: app.fetch,\n port: this.config.port,\n hostname: primaryHost,\n },\n () => {\n console.log(`[GatewayServer] Gateway server running at http://${primaryHost}:${this.config.port}`);\n this.service.markHttpListening();\n void this.service.onHttpListening().catch((err) => {\n console.error('[GatewayServer] Deferred channel startup failed:', err);\n });\n },\n );\n attachUpgrade(this.server);\n\n for (const aliasHost of listenHosts.slice(1)) {\n const extra = serve({\n fetch: app.fetch,\n port: this.config.port,\n hostname: aliasHost,\n });\n attachUpgrade(extra);\n this.extraServers.push(extra);\n }\n }\n\n async close(opts?: { reason?: string; restartExpectedMs?: number | null }): Promise<void> {\n const reason = opts?.reason ?? 'gateway stopping';\n console.log(`[GatewayServer] Closing gateway server: ${reason}`);\n await this.stop();\n }\n\n async stop(): Promise<void> {\n console.log('[GatewayServer] Stopping gateway server...');\n\n const closeServer = async (server: ServerType | undefined) => {\n if (!server) {\n return;\n }\n const forceClose = setTimeout(() => {\n (server as { closeAllConnections?: () => void }).closeAllConnections?.();\n }, 2000);\n await new Promise<void>((resolve) => {\n server.close(() => {\n clearTimeout(forceClose);\n resolve();\n });\n });\n };\n\n await closeServer(this.server);\n this.server = undefined;\n\n for (const extra of this.extraServers) {\n await closeServer(extra);\n }\n this.extraServers = [];\n\n await this.service.stop();\n\n console.log('[GatewayServer] Gateway server stopped');\n }\n\n get isRunning(): boolean {\n return this.server !== undefined;\n }\n\n get serviceInstance(): GatewayService {\n return this.service;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Config } from '../config/schema.js';
|
|
2
2
|
import type { ApprovalDecision, ApprovalKind, ClaudeChannelMode, ConversationDescriptor, PendingApproval, QueueEvent, WaitFilter } from './channel-shared.js';
|
|
3
|
+
import { type GatewayCredential } from '../gateway/credential.js';
|
|
3
4
|
export declare class XopcChannelBridge {
|
|
4
5
|
private readonly cfg;
|
|
5
6
|
private readonly params;
|
|
@@ -11,7 +12,7 @@ export declare class XopcChannelBridge {
|
|
|
11
12
|
private eventsAbort;
|
|
12
13
|
constructor(cfg: Config, params: {
|
|
13
14
|
gatewayUrl?: string;
|
|
14
|
-
|
|
15
|
+
gatewayCredential?: GatewayCredential;
|
|
15
16
|
claudeChannelMode: ClaudeChannelMode;
|
|
16
17
|
verbose: boolean;
|
|
17
18
|
});
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createLogger } from "../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
3
|
import { init_loader, loadConfig } from "../config/loader.js";
|
|
4
|
+
import { gatewayCredentialAuthorization } from "../gateway/credential.js";
|
|
5
|
+
import { loadUndiciRuntimeDeps } from "../infra/undici-fetch.js";
|
|
4
6
|
import { toConversation } from "./channel-shared.js";
|
|
5
7
|
import { createGatewayHttpClientFromConfig, resolveGatewayHttpBaseUrl } from "./gateway-http-client.js";
|
|
6
|
-
import { loadUndiciRuntimeDeps } from "../infra/undici-fetch.js";
|
|
7
8
|
//#region src/mcp/channel-bridge.ts
|
|
8
9
|
init_loader();
|
|
9
10
|
init_logger();
|
|
@@ -26,7 +27,7 @@ var XopcChannelBridge = class {
|
|
|
26
27
|
this.client = createGatewayHttpClientFromConfig({
|
|
27
28
|
config: this.cfg,
|
|
28
29
|
gatewayUrl: this.params.gatewayUrl,
|
|
29
|
-
|
|
30
|
+
gatewayCredential: this.params.gatewayCredential
|
|
30
31
|
});
|
|
31
32
|
this.connectEvents();
|
|
32
33
|
}
|
|
@@ -47,14 +48,17 @@ var XopcChannelBridge = class {
|
|
|
47
48
|
const abort = new AbortController();
|
|
48
49
|
this.eventsAbort = abort;
|
|
49
50
|
const baseUrl = resolveGatewayHttpBaseUrl(this.cfg, this.params.gatewayUrl);
|
|
50
|
-
this.runEventsLoop(baseUrl, this.params.
|
|
51
|
+
this.runEventsLoop(baseUrl, this.params.gatewayCredential, abort.signal);
|
|
51
52
|
}
|
|
52
|
-
async runEventsLoop(baseUrl,
|
|
53
|
+
async runEventsLoop(baseUrl, credential, signal) {
|
|
53
54
|
const url = new URL(`${baseUrl}/api/events`);
|
|
54
|
-
|
|
55
|
+
const authorization = gatewayCredentialAuthorization(credential);
|
|
55
56
|
try {
|
|
56
57
|
const res = await loadUndiciRuntimeDeps().fetch(url.toString(), {
|
|
57
|
-
headers: {
|
|
58
|
+
headers: {
|
|
59
|
+
Accept: "text/event-stream",
|
|
60
|
+
...authorization ? { Authorization: authorization } : {}
|
|
61
|
+
},
|
|
58
62
|
signal
|
|
59
63
|
});
|
|
60
64
|
if (!res.ok || !res.body) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-bridge.js","names":[],"sources":["../../../src/mcp/channel-bridge.ts"],"sourcesContent":["import type { Config } from '../config/schema.js';\nimport { loadConfig } from '../config/loader.js';\nimport type {\n ApprovalDecision,\n ApprovalKind,\n ClaudeChannelMode,\n ConversationDescriptor,\n PendingApproval,\n QueueEvent,\n SessionRow,\n WaitFilter,\n} from './channel-shared.js';\nimport { toConversation } from './channel-shared.js';\nimport {\n createGatewayHttpClientFromConfig,\n resolveGatewayHttpBaseUrl,\n type GatewayHttpClient,\n} from './gateway-http-client.js';\nimport { loadUndiciRuntimeDeps } from '../infra/undici-fetch.js';\nimport { createLogger } from '../utils/logger.js';\n\nconst log = createLogger('Mcp:Bridge');\n\nconst QUEUE_LIMIT = 1000;\n\nexport class XopcChannelBridge {\n private client: GatewayHttpClient | null = null;\n private readonly queue: QueueEvent[] = [];\n private readonly pendingApprovals = new Map<string, PendingApproval>();\n private cursor = 0;\n private closed = false;\n private eventsAbort: AbortController | null = null;\n\n constructor(\n private readonly cfg: Config,\n private readonly params: {\n gatewayUrl?: string;\n gatewayToken?: string;\n claudeChannelMode: ClaudeChannelMode;\n verbose: boolean;\n },\n ) {}\n\n setServer(_server: unknown): void {\n void _server;\n }\n\n async start(): Promise<void> {\n log.info({ phase: 'mcp.bridge.connect' }, 'MCP channel bridge starting');\n this.client = createGatewayHttpClientFromConfig({\n config: this.cfg,\n gatewayUrl: this.params.gatewayUrl,\n gatewayToken: this.params.gatewayToken,\n });\n this.connectEvents();\n }\n\n async close(): Promise<void> {\n log.info({ phase: 'mcp.bridge.connect', queueSize: this.queue.length }, 'MCP channel bridge closing');\n this.closed = true;\n this.eventsAbort?.abort();\n this.eventsAbort = null;\n this.queue.length = 0;\n this.pendingApprovals.clear();\n }\n\n private connectEvents(): void {\n if (this.closed) {\n return;\n }\n this.eventsAbort?.abort();\n const abort = new AbortController();\n this.eventsAbort = abort;\n const baseUrl = resolveGatewayHttpBaseUrl(this.cfg, this.params.gatewayUrl);\n void this.runEventsLoop(baseUrl, this.params.gatewayToken, abort.signal);\n }\n\n private async runEventsLoop(\n baseUrl: string,\n token: string | undefined,\n signal: AbortSignal,\n ): Promise<void> {\n const url = new URL(`${baseUrl}/api/events`);\n if (token?.trim()) {\n url.searchParams.set('token', token.trim());\n }\n try {\n const res = await loadUndiciRuntimeDeps().fetch(url.toString(), {\n headers: { Accept: 'text/event-stream' },\n signal,\n });\n if (!res.ok || !res.body) {\n log.warn(\n {\n phase: 'mcp.bridge.sse',\n status: res.status,\n baseUrl,\n },\n `Gateway events SSE connect failed: HTTP ${res.status}`,\n );\n return;\n }\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n while (!this.closed && !signal.aborted) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n buffer += decoder.decode(value, { stream: true });\n let splitAt = buffer.indexOf('\\n\\n');\n while (splitAt >= 0) {\n this.handleSseChunk(buffer.slice(0, splitAt));\n buffer = buffer.slice(splitAt + 2);\n splitAt = buffer.indexOf('\\n\\n');\n }\n }\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n if (!signal.aborted && !this.closed) {\n log.warn(\n { err, errorMessage: em, phase: 'mcp.bridge.sse', baseUrl },\n `Gateway events SSE disconnected: ${em}`,\n );\n }\n }\n if (!this.closed && !signal.aborted) {\n await new Promise((resolve) => setTimeout(resolve, 2000));\n if (!this.closed) {\n this.connectEvents();\n }\n }\n }\n\n private handleSseChunk(chunk: string): void {\n let eventName = 'message';\n let data = '';\n for (const line of chunk.split('\\n')) {\n if (line.startsWith('event:')) {\n eventName = line.slice(6).trim();\n } else if (line.startsWith('data:')) {\n data += line.slice(5).trim();\n }\n }\n if (!data) {\n return;\n }\n try {\n const parsed = JSON.parse(data) as Record<string, unknown>;\n this.enqueueFromBroadcast({ type: eventName, ...parsed });\n } catch {\n this.enqueueFromBroadcast({ type: eventName, raw: data });\n }\n }\n\n private enqueueFromBroadcast(data: Record<string, unknown>): void {\n const type = String(data.type ?? data.event ?? '');\n if (!type) {\n return;\n }\n if (type.includes('message') || type.includes('session')) {\n this.pushEvent({\n cursor: ++this.cursor,\n type: 'message',\n sessionKey: String(data.sessionKey ?? data.key ?? ''),\n raw: data,\n });\n }\n }\n\n private pushEvent(event: QueueEvent): void {\n this.queue.push(event);\n while (this.queue.length > QUEUE_LIMIT) {\n this.queue.shift();\n }\n }\n\n async listConversations(args: {\n limit?: number;\n search?: string;\n channel?: string;\n }): Promise<ConversationDescriptor[]> {\n const client = this.client!;\n const query = new URLSearchParams();\n if (args.limit) query.set('limit', String(args.limit));\n if (args.search) query.set('search', args.search);\n if (args.channel) query.set('channel', args.channel);\n const qs = query.toString();\n const rows = await client.getJson<SessionRow[] | { sessions?: SessionRow[] }>(\n `/api/sessions${qs ? `?${qs}` : ''}`,\n );\n const sessions = Array.isArray(rows) ? rows : (rows.sessions ?? []);\n return sessions\n .map((row) => toConversation(row))\n .filter((c): c is ConversationDescriptor => c !== null);\n }\n\n async getConversation(sessionKey: string): Promise<ConversationDescriptor | null> {\n const client = this.client!;\n try {\n const row = await client.getJson<SessionRow>(`/api/sessions/${encodeURIComponent(sessionKey)}`);\n return toConversation(row);\n } catch {\n return null;\n }\n }\n\n async readMessages(\n sessionKey: string,\n limit: number,\n ): Promise<Array<Record<string, unknown>>> {\n const client = this.client!;\n const payload = await client.getJson<{ messages?: Array<Record<string, unknown>> }>(\n `/api/sessions/${encodeURIComponent(sessionKey)}/messages?limit=${limit}`,\n );\n return payload.messages ?? [];\n }\n\n pollEvents(\n filter: WaitFilter,\n limit: number,\n ): { events: QueueEvent[]; nextCursor: number } {\n const events = this.queue\n .filter((e) => e.cursor > filter.afterCursor)\n .filter((e) => !filter.sessionKey || ('sessionKey' in e && e.sessionKey === filter.sessionKey))\n .slice(0, limit);\n const nextCursor = events.length > 0 ? events[events.length - 1]!.cursor : filter.afterCursor;\n return { events, nextCursor };\n }\n\n async waitForEvent(filter: WaitFilter, timeoutMs: number): Promise<QueueEvent | null> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline && !this.closed) {\n const polled = this.pollEvents(filter, 1);\n if (polled.events.length > 0) {\n return polled.events[0] ?? null;\n }\n await new Promise((r) => setTimeout(r, 250));\n }\n return null;\n }\n\n async sendMessage(params: { sessionKey: string; text: string }): Promise<Record<string, unknown>> {\n const client = this.client!;\n return client.postJson('/api/agent', {\n sessionKey: params.sessionKey,\n message: params.text,\n });\n }\n\n listPendingApprovals(): PendingApproval[] {\n return Array.from(this.pendingApprovals.values());\n }\n\n async respondToApproval(params: {\n kind: ApprovalKind;\n id: string;\n decision: ApprovalDecision;\n }): Promise<Record<string, unknown>> {\n const client = this.client!;\n return client.postJson('/api/connectors/approvals/respond', params);\n }\n\n async handleClaudePermissionRequest(_params: {\n requestId: string;\n toolName: string;\n description: string;\n inputPreview: string;\n }): Promise<void> {\n void _params;\n }\n}\n\nexport function loadMcpServeConfig(): Config {\n return loadConfig();\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"channel-bridge.js","names":[],"sources":["../../../src/mcp/channel-bridge.ts"],"sourcesContent":["import type { Config } from '../config/schema.js';\nimport { loadConfig } from '../config/loader.js';\nimport type {\n ApprovalDecision,\n ApprovalKind,\n ClaudeChannelMode,\n ConversationDescriptor,\n PendingApproval,\n QueueEvent,\n SessionRow,\n WaitFilter,\n} from './channel-shared.js';\nimport { toConversation } from './channel-shared.js';\nimport {\n createGatewayHttpClientFromConfig,\n resolveGatewayHttpBaseUrl,\n type GatewayHttpClient,\n} from './gateway-http-client.js';\nimport { loadUndiciRuntimeDeps } from '../infra/undici-fetch.js';\nimport { createLogger } from '../utils/logger.js';\nimport { gatewayCredentialAuthorization, type GatewayCredential } from '../gateway/credential.js';\n\nconst log = createLogger('Mcp:Bridge');\n\nconst QUEUE_LIMIT = 1000;\n\nexport class XopcChannelBridge {\n private client: GatewayHttpClient | null = null;\n private readonly queue: QueueEvent[] = [];\n private readonly pendingApprovals = new Map<string, PendingApproval>();\n private cursor = 0;\n private closed = false;\n private eventsAbort: AbortController | null = null;\n\n constructor(\n private readonly cfg: Config,\n private readonly params: {\n gatewayUrl?: string;\n gatewayCredential?: GatewayCredential;\n claudeChannelMode: ClaudeChannelMode;\n verbose: boolean;\n },\n ) {}\n\n setServer(_server: unknown): void {\n void _server;\n }\n\n async start(): Promise<void> {\n log.info({ phase: 'mcp.bridge.connect' }, 'MCP channel bridge starting');\n this.client = createGatewayHttpClientFromConfig({\n config: this.cfg,\n gatewayUrl: this.params.gatewayUrl,\n gatewayCredential: this.params.gatewayCredential,\n });\n this.connectEvents();\n }\n\n async close(): Promise<void> {\n log.info({ phase: 'mcp.bridge.connect', queueSize: this.queue.length }, 'MCP channel bridge closing');\n this.closed = true;\n this.eventsAbort?.abort();\n this.eventsAbort = null;\n this.queue.length = 0;\n this.pendingApprovals.clear();\n }\n\n private connectEvents(): void {\n if (this.closed) {\n return;\n }\n this.eventsAbort?.abort();\n const abort = new AbortController();\n this.eventsAbort = abort;\n const baseUrl = resolveGatewayHttpBaseUrl(this.cfg, this.params.gatewayUrl);\n void this.runEventsLoop(baseUrl, this.params.gatewayCredential, abort.signal);\n }\n\n private async runEventsLoop(\n baseUrl: string,\n credential: GatewayCredential | undefined,\n signal: AbortSignal,\n ): Promise<void> {\n const url = new URL(`${baseUrl}/api/events`);\n const authorization = gatewayCredentialAuthorization(credential);\n try {\n const res = await loadUndiciRuntimeDeps().fetch(url.toString(), {\n headers: {\n Accept: 'text/event-stream',\n ...(authorization ? { Authorization: authorization } : {}),\n },\n signal,\n });\n if (!res.ok || !res.body) {\n log.warn(\n {\n phase: 'mcp.bridge.sse',\n status: res.status,\n baseUrl,\n },\n `Gateway events SSE connect failed: HTTP ${res.status}`,\n );\n return;\n }\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n while (!this.closed && !signal.aborted) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n buffer += decoder.decode(value, { stream: true });\n let splitAt = buffer.indexOf('\\n\\n');\n while (splitAt >= 0) {\n this.handleSseChunk(buffer.slice(0, splitAt));\n buffer = buffer.slice(splitAt + 2);\n splitAt = buffer.indexOf('\\n\\n');\n }\n }\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n if (!signal.aborted && !this.closed) {\n log.warn({ err, errorMessage: em, phase: 'mcp.bridge.sse', baseUrl }, `Gateway events SSE disconnected: ${em}`);\n }\n }\n if (!this.closed && !signal.aborted) {\n await new Promise((resolve) => setTimeout(resolve, 2000));\n if (!this.closed) {\n this.connectEvents();\n }\n }\n }\n\n private handleSseChunk(chunk: string): void {\n let eventName = 'message';\n let data = '';\n for (const line of chunk.split('\\n')) {\n if (line.startsWith('event:')) {\n eventName = line.slice(6).trim();\n } else if (line.startsWith('data:')) {\n data += line.slice(5).trim();\n }\n }\n if (!data) {\n return;\n }\n try {\n const parsed = JSON.parse(data) as Record<string, unknown>;\n this.enqueueFromBroadcast({ type: eventName, ...parsed });\n } catch {\n this.enqueueFromBroadcast({ type: eventName, raw: data });\n }\n }\n\n private enqueueFromBroadcast(data: Record<string, unknown>): void {\n const type = String(data.type ?? data.event ?? '');\n if (!type) {\n return;\n }\n if (type.includes('message') || type.includes('session')) {\n this.pushEvent({\n cursor: ++this.cursor,\n type: 'message',\n sessionKey: String(data.sessionKey ?? data.key ?? ''),\n raw: data,\n });\n }\n }\n\n private pushEvent(event: QueueEvent): void {\n this.queue.push(event);\n while (this.queue.length > QUEUE_LIMIT) {\n this.queue.shift();\n }\n }\n\n async listConversations(args: {\n limit?: number;\n search?: string;\n channel?: string;\n }): Promise<ConversationDescriptor[]> {\n const client = this.client!;\n const query = new URLSearchParams();\n if (args.limit) query.set('limit', String(args.limit));\n if (args.search) query.set('search', args.search);\n if (args.channel) query.set('channel', args.channel);\n const qs = query.toString();\n const rows = await client.getJson<SessionRow[] | { sessions?: SessionRow[] }>(`/api/sessions${qs ? `?${qs}` : ''}`);\n const sessions = Array.isArray(rows) ? rows : (rows.sessions ?? []);\n return sessions.map((row) => toConversation(row)).filter((c): c is ConversationDescriptor => c !== null);\n }\n\n async getConversation(sessionKey: string): Promise<ConversationDescriptor | null> {\n const client = this.client!;\n try {\n const row = await client.getJson<SessionRow>(`/api/sessions/${encodeURIComponent(sessionKey)}`);\n return toConversation(row);\n } catch {\n return null;\n }\n }\n\n async readMessages(sessionKey: string, limit: number): Promise<Array<Record<string, unknown>>> {\n const client = this.client!;\n const payload = await client.getJson<{\n messages?: Array<Record<string, unknown>>;\n }>(`/api/sessions/${encodeURIComponent(sessionKey)}/messages?limit=${limit}`);\n return payload.messages ?? [];\n }\n\n pollEvents(filter: WaitFilter, limit: number): { events: QueueEvent[]; nextCursor: number } {\n const events = this.queue\n .filter((e) => e.cursor > filter.afterCursor)\n .filter((e) => !filter.sessionKey || ('sessionKey' in e && e.sessionKey === filter.sessionKey))\n .slice(0, limit);\n const nextCursor = events.length > 0 ? events[events.length - 1]!.cursor : filter.afterCursor;\n return { events, nextCursor };\n }\n\n async waitForEvent(filter: WaitFilter, timeoutMs: number): Promise<QueueEvent | null> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline && !this.closed) {\n const polled = this.pollEvents(filter, 1);\n if (polled.events.length > 0) {\n return polled.events[0] ?? null;\n }\n await new Promise((r) => setTimeout(r, 250));\n }\n return null;\n }\n\n async sendMessage(params: { sessionKey: string; text: string }): Promise<Record<string, unknown>> {\n const client = this.client!;\n return client.postJson('/api/agent', {\n sessionKey: params.sessionKey,\n message: params.text,\n });\n }\n\n listPendingApprovals(): PendingApproval[] {\n return Array.from(this.pendingApprovals.values());\n }\n\n async respondToApproval(params: {\n kind: ApprovalKind;\n id: string;\n decision: ApprovalDecision;\n }): Promise<Record<string, unknown>> {\n const client = this.client!;\n return client.postJson('/api/connectors/approvals/respond', params);\n }\n\n async handleClaudePermissionRequest(_params: {\n requestId: string;\n toolName: string;\n description: string;\n inputPreview: string;\n }): Promise<void> {\n void _params;\n }\n}\n\nexport function loadMcpServeConfig(): Config {\n return loadConfig();\n}\n"],"mappings":"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"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import type { Config } from '../config/schema.js';
|
|
3
|
+
import type { GatewayCredential } from '../gateway/credential.js';
|
|
3
4
|
import { XopcChannelBridge } from './channel-bridge.js';
|
|
4
5
|
import { type ClaudeChannelMode } from './channel-shared.js';
|
|
5
6
|
export type XopcMcpServeOptions = {
|
|
6
7
|
gatewayUrl?: string;
|
|
7
|
-
|
|
8
|
+
gatewayCredential?: GatewayCredential;
|
|
8
9
|
config?: Config;
|
|
9
10
|
claudeChannelMode?: ClaudeChannelMode;
|
|
10
11
|
verbose?: boolean;
|
|
@@ -18,7 +18,7 @@ async function createXopcChannelMcpServer(opts = {}) {
|
|
|
18
18
|
}, capabilities ? { capabilities } : void 0);
|
|
19
19
|
const bridge = new XopcChannelBridge(cfg, {
|
|
20
20
|
gatewayUrl: opts.gatewayUrl,
|
|
21
|
-
|
|
21
|
+
gatewayCredential: opts.gatewayCredential,
|
|
22
22
|
claudeChannelMode,
|
|
23
23
|
verbose: opts.verbose ?? false
|
|
24
24
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-server.js","names":[],"sources":["../../../src/mcp/channel-server.ts"],"sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport type { Config } from '../config/schema.js';\nimport { loadConfig } from '../config/loader.js';\nimport { PACKAGE_VERSION } from '../package-version.js';\nimport { XopcChannelBridge } from './channel-bridge.js';\nimport { ClaudePermissionRequestSchema, type ClaudeChannelMode } from './channel-shared.js';\nimport { getChannelMcpCapabilities, registerChannelMcpTools } from './channel-tools.js';\n\nexport type XopcMcpServeOptions = {\n gatewayUrl?: string;\n
|
|
1
|
+
{"version":3,"file":"channel-server.js","names":[],"sources":["../../../src/mcp/channel-server.ts"],"sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport type { Config } from '../config/schema.js';\nimport { loadConfig } from '../config/loader.js';\nimport type { GatewayCredential } from '../gateway/credential.js';\nimport { PACKAGE_VERSION } from '../package-version.js';\nimport { XopcChannelBridge } from './channel-bridge.js';\nimport { ClaudePermissionRequestSchema, type ClaudeChannelMode } from './channel-shared.js';\nimport { getChannelMcpCapabilities, registerChannelMcpTools } from './channel-tools.js';\n\nexport type XopcMcpServeOptions = {\n gatewayUrl?: string;\n gatewayCredential?: GatewayCredential;\n config?: Config;\n claudeChannelMode?: ClaudeChannelMode;\n verbose?: boolean;\n};\n\nexport async function createXopcChannelMcpServer(opts: XopcMcpServeOptions = {}): Promise<{\n server: McpServer;\n bridge: XopcChannelBridge;\n start: () => Promise<void>;\n close: () => Promise<void>;\n}> {\n const cfg = opts.config ?? loadConfig();\n const claudeChannelMode = opts.claudeChannelMode ?? 'auto';\n const capabilities = getChannelMcpCapabilities(claudeChannelMode);\n const server = new McpServer({ name: 'xopc', version: PACKAGE_VERSION }, capabilities ? { capabilities } : undefined);\n const bridge = new XopcChannelBridge(cfg, {\n gatewayUrl: opts.gatewayUrl,\n gatewayCredential: opts.gatewayCredential,\n claudeChannelMode,\n verbose: opts.verbose ?? false,\n });\n bridge.setServer(server);\n\n server.server.setNotificationHandler(ClaudePermissionRequestSchema, async ({ params }) => {\n await bridge.handleClaudePermissionRequest({\n requestId: params.request_id,\n toolName: params.tool_name,\n description: params.description,\n inputPreview: params.input_preview,\n });\n });\n registerChannelMcpTools(server, bridge);\n\n return {\n server,\n bridge,\n start: async () => {\n await bridge.start();\n },\n close: async () => {\n await bridge.close();\n await server.close();\n },\n };\n}\n\nexport async function serveXopcChannelMcpImpl(opts: XopcMcpServeOptions = {}): Promise<void> {\n const { server, start, close } = await createXopcChannelMcpServer(opts);\n const transport = new StdioServerTransport();\n\n let shuttingDown = false;\n let resolveClosed!: () => void;\n const closed = new Promise<void>((resolve) => {\n resolveClosed = resolve;\n });\n\n const shutdown = () => {\n if (shuttingDown) {\n return;\n }\n shuttingDown = true;\n process.stdin.off('end', shutdown);\n process.stdin.off('close', shutdown);\n process.off('SIGINT', shutdown);\n process.off('SIGTERM', shutdown);\n transport['onclose'] = undefined;\n close().then(resolveClosed, resolveClosed);\n };\n\n transport['onclose'] = shutdown;\n process.stdin.once('end', shutdown);\n process.stdin.once('close', shutdown);\n process.once('SIGINT', shutdown);\n process.once('SIGTERM', shutdown);\n\n try {\n await server.connect(transport);\n await start();\n await closed;\n } finally {\n shutdown();\n await closed;\n }\n}\n"],"mappings":";;;;;;;;aAGiD;sBAEO;AAaxD,eAAsB,2BAA2B,OAA4B,EAAE,EAK5E;CACD,MAAM,MAAM,KAAK,UAAU,YAAY;CACvC,MAAM,oBAAoB,KAAK,qBAAqB;CACpD,MAAM,eAAe,0BAA0B,kBAAkB;CACjE,MAAM,SAAS,IAAI,UAAU;EAAE,MAAM;EAAQ,SAAS;EAAiB,EAAE,eAAe,EAAE,cAAc,GAAG,KAAA,EAAU;CACrH,MAAM,SAAS,IAAI,kBAAkB,KAAK;EACxC,YAAY,KAAK;EACjB,mBAAmB,KAAK;EACxB;EACA,SAAS,KAAK,WAAW;EAC1B,CAAC;AACF,QAAO,UAAU,OAAO;AAExB,QAAO,OAAO,uBAAuB,+BAA+B,OAAO,EAAE,aAAa;AACxF,QAAM,OAAO,8BAA8B;GACzC,WAAW,OAAO;GAClB,UAAU,OAAO;GACjB,aAAa,OAAO;GACpB,cAAc,OAAO;GACtB,CAAC;GACF;AACF,yBAAwB,QAAQ,OAAO;AAEvC,QAAO;EACL;EACA;EACA,OAAO,YAAY;AACjB,SAAM,OAAO,OAAO;;EAEtB,OAAO,YAAY;AACjB,SAAM,OAAO,OAAO;AACpB,SAAM,OAAO,OAAO;;EAEvB;;AAGH,eAAsB,wBAAwB,OAA4B,EAAE,EAAiB;CAC3F,MAAM,EAAE,QAAQ,OAAO,UAAU,MAAM,2BAA2B,KAAK;CACvE,MAAM,YAAY,IAAI,sBAAsB;CAE5C,IAAI,eAAe;CACnB,IAAI;CACJ,MAAM,SAAS,IAAI,SAAe,YAAY;AAC5C,kBAAgB;GAChB;CAEF,MAAM,iBAAiB;AACrB,MAAI,aACF;AAEF,iBAAe;AACf,UAAQ,MAAM,IAAI,OAAO,SAAS;AAClC,UAAQ,MAAM,IAAI,SAAS,SAAS;AACpC,UAAQ,IAAI,UAAU,SAAS;AAC/B,UAAQ,IAAI,WAAW,SAAS;AAChC,YAAU,aAAa,KAAA;AACvB,SAAO,CAAC,KAAK,eAAe,cAAc;;AAG5C,WAAU,aAAa;AACvB,SAAQ,MAAM,KAAK,OAAO,SAAS;AACnC,SAAQ,MAAM,KAAK,SAAS,SAAS;AACrC,SAAQ,KAAK,UAAU,SAAS;AAChC,SAAQ,KAAK,WAAW,SAAS;AAEjC,KAAI;AACF,QAAM,OAAO,QAAQ,UAAU;AAC/B,QAAM,OAAO;AACb,QAAM;WACE;AACR,YAAU;AACV,QAAM"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { Config } from '../config/schema.js';
|
|
2
|
+
import { type GatewayCredential } from '../gateway/credential.js';
|
|
2
3
|
export type GatewayHttpClientOptions = {
|
|
3
4
|
baseUrl: string;
|
|
4
|
-
|
|
5
|
+
credential?: GatewayCredential;
|
|
5
6
|
};
|
|
6
7
|
export declare class GatewayHttpClient {
|
|
7
8
|
private readonly opts;
|
|
@@ -14,5 +15,5 @@ export declare function resolveGatewayHttpBaseUrl(config: Config, override?: str
|
|
|
14
15
|
export declare function createGatewayHttpClientFromConfig(params: {
|
|
15
16
|
config?: Config;
|
|
16
17
|
gatewayUrl?: string;
|
|
17
|
-
|
|
18
|
+
gatewayCredential?: GatewayCredential;
|
|
18
19
|
}): GatewayHttpClient;
|
|
@@ -2,15 +2,16 @@ import { createLogger } from "../utils/logger/index.js";
|
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
3
|
import { init_loader, loadConfig } from "../config/loader.js";
|
|
4
4
|
import { resolveGatewayLocalClientHost } from "../config/gateway-bind.js";
|
|
5
|
+
import { createGatewayCredential, gatewayCredentialAuthorization } from "../gateway/credential.js";
|
|
5
6
|
import { fetch } from "undici";
|
|
6
7
|
//#region src/mcp/gateway-http-client.ts
|
|
7
8
|
init_loader();
|
|
8
9
|
init_logger();
|
|
9
10
|
const log = createLogger("Mcp:GatewayClient");
|
|
10
|
-
function
|
|
11
|
-
const
|
|
12
|
-
if (
|
|
13
|
-
return process.env.XOPC_GATEWAY_TOKEN
|
|
11
|
+
function resolveGatewayCredentialFromConfig(cfg) {
|
|
12
|
+
const auth = cfg.gateway?.auth;
|
|
13
|
+
if (auth?.mode === "password") return createGatewayCredential("password", auth.password);
|
|
14
|
+
if (auth?.mode === "token") return createGatewayCredential("token", auth.token ?? process.env.XOPC_GATEWAY_TOKEN);
|
|
14
15
|
}
|
|
15
16
|
var GatewayHttpClient = class {
|
|
16
17
|
constructor(opts) {
|
|
@@ -21,7 +22,8 @@ var GatewayHttpClient = class {
|
|
|
21
22
|
Accept: "application/json",
|
|
22
23
|
...extra
|
|
23
24
|
};
|
|
24
|
-
|
|
25
|
+
const authorization = gatewayCredentialAuthorization(this.opts.credential);
|
|
26
|
+
if (authorization) h.Authorization = authorization;
|
|
25
27
|
return h;
|
|
26
28
|
}
|
|
27
29
|
async getJson(path) {
|
|
@@ -67,10 +69,10 @@ function resolveGatewayHttpBaseUrl(config, override) {
|
|
|
67
69
|
}
|
|
68
70
|
function createGatewayHttpClientFromConfig(params) {
|
|
69
71
|
const cfg = params.config ?? loadConfig();
|
|
70
|
-
const
|
|
72
|
+
const credential = params.gatewayCredential ?? resolveGatewayCredentialFromConfig(cfg);
|
|
71
73
|
return new GatewayHttpClient({
|
|
72
74
|
baseUrl: resolveGatewayHttpBaseUrl(cfg, params.gatewayUrl),
|
|
73
|
-
|
|
75
|
+
credential
|
|
74
76
|
});
|
|
75
77
|
}
|
|
76
78
|
//#endregion
|