@geminixiang/mikan 0.3.0 โ 0.3.1
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/CHANGELOG.md +14 -0
- package/dist/adapter.d.ts +5 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js.map +1 -1
- package/dist/adapters/discord/context.d.ts +0 -1
- package/dist/adapters/discord/context.d.ts.map +1 -1
- package/dist/adapters/discord/context.js +62 -84
- package/dist/adapters/discord/context.js.map +1 -1
- package/dist/adapters/shared.d.ts +1 -2
- package/dist/adapters/shared.d.ts.map +1 -1
- package/dist/adapters/shared.js +3 -2
- package/dist/adapters/shared.js.map +1 -1
- package/dist/adapters/slack/bot.d.ts +9 -34
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +374 -358
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/context.d.ts +0 -1
- package/dist/adapters/slack/context.d.ts.map +1 -1
- package/dist/adapters/slack/context.js +110 -113
- package/dist/adapters/slack/context.js.map +1 -1
- package/dist/adapters/slack/session.d.ts +0 -3
- package/dist/adapters/slack/session.d.ts.map +1 -1
- package/dist/adapters/slack/session.js +2 -8
- package/dist/adapters/slack/session.js.map +1 -1
- package/dist/adapters/slack/thread-manager.d.ts +0 -1
- package/dist/adapters/slack/thread-manager.d.ts.map +1 -1
- package/dist/adapters/slack/thread-manager.js +1 -4
- package/dist/adapters/slack/thread-manager.js.map +1 -1
- package/dist/adapters/slack/tools/block-kit.d.ts +16 -0
- package/dist/adapters/slack/tools/block-kit.d.ts.map +1 -0
- package/dist/adapters/slack/tools/block-kit.js +105 -0
- package/dist/adapters/slack/tools/block-kit.js.map +1 -0
- package/dist/adapters/telegram/context.d.ts +0 -1
- package/dist/adapters/telegram/context.d.ts.map +1 -1
- package/dist/adapters/telegram/context.js +44 -54
- package/dist/adapters/telegram/context.js.map +1 -1
- package/dist/admin/portal.d.ts.map +1 -1
- package/dist/admin/portal.js +2 -3
- package/dist/admin/portal.js.map +1 -1
- package/dist/agent.d.ts +0 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +47 -80
- package/dist/agent.js.map +1 -1
- package/dist/commands/admin.d.ts +0 -3
- package/dist/commands/admin.d.ts.map +1 -1
- package/dist/commands/admin.js +5 -30
- package/dist/commands/admin.js.map +1 -1
- package/dist/commands/session-view.d.ts.map +1 -1
- package/dist/commands/session-view.js +4 -17
- package/dist/commands/session-view.js.map +1 -1
- package/dist/commands/types.d.ts +3 -2
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/types.js.map +1 -1
- package/dist/commands/utils.d.ts +3 -1
- package/dist/commands/utils.d.ts.map +1 -1
- package/dist/commands/utils.js +15 -5
- package/dist/commands/utils.js.map +1 -1
- package/dist/context.d.ts +0 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +1 -23
- package/dist/context.js.map +1 -1
- package/dist/html.d.ts +2 -0
- package/dist/html.d.ts.map +1 -0
- package/dist/html.js +4 -0
- package/dist/html.js.map +1 -0
- package/dist/login/index.d.ts +2 -1
- package/dist/login/index.d.ts.map +1 -1
- package/dist/login/index.js.map +1 -1
- package/dist/login/portal.d.ts.map +1 -1
- package/dist/login/portal.js +2 -3
- package/dist/login/portal.js.map +1 -1
- package/dist/portal-shell.d.ts +2 -2
- package/dist/portal-shell.d.ts.map +1 -1
- package/dist/portal-shell.js +11 -16
- package/dist/portal-shell.js.map +1 -1
- package/dist/sandbox/cloudflare.d.ts +0 -2
- package/dist/sandbox/cloudflare.d.ts.map +1 -1
- package/dist/sandbox/cloudflare.js +2 -2
- package/dist/sandbox/cloudflare.js.map +1 -1
- package/dist/sandbox/container.d.ts +0 -3
- package/dist/sandbox/container.d.ts.map +1 -1
- package/dist/sandbox/container.js +3 -3
- package/dist/sandbox/container.js.map +1 -1
- package/dist/sandbox/firecracker.d.ts +0 -2
- package/dist/sandbox/firecracker.d.ts.map +1 -1
- package/dist/sandbox/firecracker.js +2 -2
- package/dist/sandbox/firecracker.js.map +1 -1
- package/dist/sandbox/host.d.ts +0 -2
- package/dist/sandbox/host.d.ts.map +1 -1
- package/dist/sandbox/host.js +2 -2
- package/dist/sandbox/host.js.map +1 -1
- package/dist/sandbox/image.d.ts +0 -2
- package/dist/sandbox/image.d.ts.map +1 -1
- package/dist/sandbox/image.js +2 -2
- package/dist/sandbox/image.js.map +1 -1
- package/dist/sandbox/index.d.ts +1 -6
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +0 -5
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/path-context.d.ts +0 -1
- package/dist/sandbox/path-context.d.ts.map +1 -1
- package/dist/sandbox/path-context.js +1 -1
- package/dist/sandbox/path-context.js.map +1 -1
- package/dist/sentry.d.ts +2 -2
- package/dist/sentry.d.ts.map +1 -1
- package/dist/sentry.js.map +1 -1
- package/dist/session-view/portal.d.ts.map +1 -1
- package/dist/session-view/portal.js +2 -8
- package/dist/session-view/portal.js.map +1 -1
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/vault-routing.d.ts +0 -1
- package/dist/vault-routing.d.ts.map +1 -1
- package/dist/vault-routing.js +1 -4
- package/dist/vault-routing.js.map +1 -1
- package/dist/vault.d.ts +2 -1
- package/dist/vault.d.ts.map +1 -1
- package/dist/vault.js.map +1 -1
- package/package.json +3 -1
package/dist/admin/portal.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"portal.js","sourceRoot":"","sources":["../../src/admin/portal.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync, readFileSync, rmSync, statSync } from \"fs\";\nimport type { IncomingMessage, ServerResponse } from \"http\";\nimport { homedir } from \"os\";\nimport { join, resolve as pathResolve, sep as pathSep } from \"path\";\nimport { AuthStorage, ModelRegistry } from \"@earendil-works/pi-coding-agent\";\nimport type { Bot, PlatformName, RunningSession } from \"../adapter.js\";\nimport {\n loadAgentConfig,\n loadAgentConfigForConversation,\n loadConversationAutoReplyConfig,\n saveAgentConfig,\n saveConversationAutoReplyConfig,\n saveConversationModelConfig,\n saveConversationSandboxConfig,\n type AgentConfig,\n} from \"../config.js\";\nimport { renderPortalShell } from \"../portal-shell.js\";\nimport type { SandboxConfig } from \"../sandbox/index.js\";\nimport { resolveExistingSessionFile } from \"../session-view/service.js\";\nimport type { InMemorySessionViewTokenStore } from \"../session-view/store.js\";\nimport { PRODUCT_NAME } from \"../ui-copy.js\";\nimport { resolveActorVaultKey } from \"../vault-routing.js\";\nimport { sharedVaultKey, type VaultManager } from \"../vault.js\";\nimport type { AdminToken, InMemoryAdminTokenStore } from \"./store.js\";\n\n// โโ Types โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nexport interface AdminRuntimeBridge {\n getRunningSessions(): RunningSession[];\n switchConversationModel(conversationId: string, provider: string, model: string): boolean;\n}\n\nexport interface AdminServices {\n vaultManager: VaultManager;\n linkTokenStore: {\n create(\n platform: PlatformName,\n platformUserId: string,\n conversationId: string,\n vaultId: string,\n providerId: string,\n ): { token: string };\n };\n sessionViewTokenStore?: InMemorySessionViewTokenStore;\n adminTokenStore: InMemoryAdminTokenStore;\n portalBaseUrl?: string;\n workingDir?: string;\n sandbox?: SandboxConfig;\n runtime?: AdminRuntimeBridge;\n botsByPlatform?: Partial<Record<PlatformName, Bot>>;\n}\n\n// โโ Handler โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nexport function handleAdminRequest(\n req: IncomingMessage,\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n): boolean {\n if (!url.pathname.startsWith(\"/admin\")) return false;\n\n if (req.method === \"GET\" && url.pathname === \"/admin\") {\n const provided = url.searchParams.get(\"token\") ?? \"\";\n const token = services.adminTokenStore.peek(provided);\n if (!token) {\n res.writeHead(403, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(\n renderAdminErrorPage(\n \"Admin link is missing, invalid, or expired. Send `/admin` to the bot to get a fresh link.\",\n ),\n );\n return true;\n }\n res.writeHead(200, {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n });\n res.end(renderAdminPage(token));\n return true;\n }\n\n if (url.pathname.startsWith(\"/admin/api/\")) {\n routeApiRequest(req, res, url, services);\n return true;\n }\n\n return false;\n}\n\n// โโ API routing โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nfunction routeApiRequest(\n req: IncomingMessage,\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n): void {\n if (req.method === \"GET\") {\n const token = services.adminTokenStore.peek(url.searchParams.get(\"token\") ?? \"\");\n if (!token) {\n jsonRes(res, 403, { error: \"Unauthorized\" });\n return;\n }\n if (url.pathname === \"/admin/api/me\") {\n serveMe(res, token);\n return;\n }\n if (url.pathname === \"/admin/api/conversations\") {\n serveConversationsList(res, services);\n return;\n }\n if (url.pathname === \"/admin/api/conversation-state\") {\n serveConversationState(res, url, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/settings/global\") {\n serveGlobalSettings(res);\n return;\n }\n if (url.pathname === \"/admin/api/models\") {\n void serveModelsList(res);\n return;\n }\n if (url.pathname === \"/admin/api/workspace/tree\") {\n serveWorkspaceTree(res, url, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/workspace/file\") {\n serveWorkspaceFile(res, url, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/skills\") {\n serveSkillsList(res, url, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/skills/file\") {\n serveSkillFile(res, url, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/events\") {\n serveEventsList(res, services);\n return;\n }\n if (url.pathname === \"/admin/api/events/file\") {\n serveEventsFile(res, url, services);\n return;\n }\n if (url.pathname === \"/admin/api/conversations/events\") {\n serveConversationEventsList(res, url, services, token);\n return;\n }\n jsonRes(res, 404, { error: \"Not found\" });\n return;\n }\n\n if (req.method === \"POST\") {\n void readJsonBody(req, res, (body) => {\n const rawToken = typeof body.token === \"string\" ? body.token : \"\";\n const token = services.adminTokenStore.peek(rawToken);\n if (!token) {\n jsonRes(res, 403, { error: \"Unauthorized\" });\n return;\n }\n if (url.pathname === \"/admin/api/conversations/model\") {\n serveConversationModelUpdate(res, body, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/conversations/sandbox\") {\n serveConversationSandboxUpdate(res, body, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/conversations/auto-reply\") {\n serveConversationAutoReplyUpdate(res, body, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/conversations/session-link\") {\n serveConversationSessionLink(res, body, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/conversations/login-link\") {\n serveConversationLoginLink(res, body, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/conversations/events/delete\") {\n serveConversationEventDelete(res, body, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/settings/model\") {\n serveGlobalModelUpdate(res, body);\n return;\n }\n if (url.pathname === \"/admin/api/settings/sandbox\") {\n serveGlobalSandboxUpdate(res, body);\n return;\n }\n jsonRes(res, 404, { error: \"Not found\" });\n });\n return;\n }\n\n jsonRes(res, 405, { error: \"Method not allowed\" });\n}\n\n// โโ Scope helpers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nfunction resolveTargetConversation(\n body: Record<string, unknown>,\n token: AdminToken,\n): { conversationId: string; error?: string } {\n const requested = typeof body.conversationId === \"string\" ? body.conversationId.trim() : \"\";\n if (!requested) return { conversationId: token.conversationId };\n if (requested === token.conversationId) return { conversationId: requested };\n if (requested.includes(\"/\") || requested.includes(\"..\")) {\n return { conversationId: requested, error: \"Invalid conversationId.\" };\n }\n return { conversationId: requested };\n}\n\nfunction requireAdminWorkingDir(res: ServerResponse, services: AdminServices): string | null {\n if (!services.workingDir) {\n jsonRes(res, 503, { error: \"Working directory not available\" });\n return null;\n }\n return services.workingDir;\n}\n\n// โโ API handlers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nfunction serveMe(res: ServerResponse, token: AdminToken): void {\n jsonRes(res, 200, {\n platform: token.platform,\n platformUserId: token.platformUserId,\n platformUserName: token.platformUserName ?? null,\n conversationId: token.conversationId,\n expiresAt: token.expiresAt,\n });\n}\n\nconst SETTINGS_FILES = new Set([\"settings.json\", \"auto-reply\", \"auto-reply.disabled\"]);\n\nfunction listConversationDirs(workingDir: string): string[] {\n if (!existsSync(workingDir)) return [];\n const skip = new Set([\"vaults\", \"skills\", \"events\", \"node_modules\", \".git\"]);\n return readdirSync(workingDir, { withFileTypes: true })\n .filter((entry) => entry.isDirectory() && !entry.name.startsWith(\".\") && !skip.has(entry.name))\n .map((entry) => entry.name)\n .filter((name) => {\n const dir = join(workingDir, name);\n try {\n const items = readdirSync(dir);\n return items.some((item) => SETTINGS_FILES.has(item) || item.endsWith(\".jsonl\"));\n } catch {\n return false;\n }\n })\n .toSorted((a, b) => a.localeCompare(b));\n}\n\nfunction conversationLastActivity(workingDir: string, conversationId: string): number | null {\n const dir = join(workingDir, conversationId);\n if (!existsSync(dir)) return null;\n let latest = 0;\n const visit = (path: string, depth: number): void => {\n if (depth > 3) return;\n let entries;\n try {\n entries = readdirSync(path, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const full = join(path, entry.name);\n if (entry.isDirectory()) {\n visit(full, depth + 1);\n continue;\n }\n try {\n const stats = statSync(full);\n if (stats.mtimeMs > latest) latest = stats.mtimeMs;\n } catch {\n // ignore\n }\n }\n };\n visit(dir, 0);\n return latest > 0 ? latest : null;\n}\n\nfunction conversationDisplayLabel(services: AdminServices, conversationId: string): string {\n for (const [platform, bot] of Object.entries(services.botsByPlatform ?? {})) {\n const channel = bot?.getPlatformInfo().channels.find((c) => c.id === conversationId);\n if (channel) return `${platform}:#${channel.name}:${conversationId}`;\n }\n return conversationId;\n}\n\nfunction serveConversationsList(res: ServerResponse, services: AdminServices): void {\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n\n const ids = listConversationDirs(workingDir);\n\n const runningKeys = new Set<string>(\n services.runtime?.getRunningSessions().map((s) => s.sessionKey) ?? [],\n );\n\n const conversations = ids.map((conversationId) => {\n const lastActivity = conversationLastActivity(workingDir, conversationId);\n const running = Array.from(runningKeys).some(\n (key) => key === conversationId || key.startsWith(`${conversationId}:`),\n );\n return {\n conversationId,\n label: conversationDisplayLabel(services, conversationId),\n running,\n lastActivityAt: lastActivity,\n };\n });\n\n jsonRes(res, 200, { conversations });\n}\n\nfunction serveConversationState(\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n token: AdminToken,\n): void {\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n\n const requested = url.searchParams.get(\"conversationId\")?.trim() ?? \"\";\n const conversationId = requested || token.conversationId;\n if (conversationId.includes(\"/\") || conversationId.includes(\"..\")) {\n jsonRes(res, 400, { error: \"Invalid conversationId\" });\n return;\n }\n\n const dir = join(workingDir, conversationId);\n let modelConfig: AgentConfig | null = null;\n try {\n modelConfig = loadAgentConfigForConversation(dir);\n } catch {\n modelConfig = null;\n }\n const autoReply = loadConversationAutoReplyConfig(dir);\n\n jsonRes(res, 200, {\n conversationId,\n provider: modelConfig?.provider ?? null,\n model: modelConfig?.model ?? null,\n thinkingLevel: modelConfig?.thinkingLevel ?? null,\n sandboxImageWorkspaceMount: modelConfig?.sandboxImageWorkspaceMount ?? null,\n autoReplyEnabled: autoReply.enabled,\n autoReplyRules: autoReply.rules,\n });\n}\n\nfunction serveGlobalSettings(res: ServerResponse): void {\n try {\n const config = loadAgentConfig();\n jsonRes(res, 200, {\n provider: config.provider,\n model: config.model,\n thinkingLevel: config.thinkingLevel,\n sandboxCpus: config.sandboxCpus ?? null,\n sandboxMemory: config.sandboxMemory ?? null,\n sandboxBoostCpus: config.sandboxBoostCpus ?? null,\n sandboxBoostMemory: config.sandboxBoostMemory ?? null,\n sandboxImageWorkspaceMount: config.sandboxImageWorkspaceMount ?? null,\n defaultSharedVault: config.defaultSharedVault ?? null,\n });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nasync function serveModelsList(res: ServerResponse): Promise<void> {\n try {\n const authStorage = AuthStorage.create(join(homedir(), \".pi\", \"mikan\", \"auth.json\"));\n const registry = ModelRegistry.create(authStorage);\n const models = (await registry.getAvailable()).map((model) => ({\n provider: model.provider,\n id: model.id,\n name: model.name ?? model.id,\n reasoning: model.reasoning,\n input: model.input,\n contextWindow: model.contextWindow,\n maxTokens: model.maxTokens,\n }));\n jsonRes(res, 200, { models });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nconst VALID_THINKING_LEVELS = new Set([\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"]);\n\nfunction serveConversationModelUpdate(\n res: ServerResponse,\n body: Record<string, unknown>,\n services: AdminServices,\n token: AdminToken,\n): void {\n const provider = typeof body.provider === \"string\" ? body.provider.trim() : \"\";\n const model = typeof body.model === \"string\" ? body.model.trim() : \"\";\n const thinkingLevel =\n typeof body.thinkingLevel === \"string\" && VALID_THINKING_LEVELS.has(body.thinkingLevel)\n ? (body.thinkingLevel as AgentConfig[\"thinkingLevel\"])\n : undefined;\n\n if (!provider || !model) {\n jsonRes(res, 400, { error: \"Missing provider or model\" });\n return;\n }\n const scope = resolveTargetConversation(body, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const dir = join(workingDir, scope.conversationId);\n\n try {\n saveConversationModelConfig(dir, {\n provider,\n model,\n ...(thinkingLevel ? { thinkingLevel } : {}),\n });\n let runtimeSwitched: boolean | null = null;\n if (services.runtime) {\n runtimeSwitched = services.runtime.switchConversationModel(\n scope.conversationId,\n provider,\n model,\n );\n }\n jsonRes(res, 200, { ok: true, runtimeSwitched });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nfunction serveConversationSandboxUpdate(\n res: ServerResponse,\n body: Record<string, unknown>,\n services: AdminServices,\n token: AdminToken,\n): void {\n const workspaceMount = body.workspaceMount;\n if (workspaceMount !== \"private\" && workspaceMount !== \"full\") {\n jsonRes(res, 400, { error: \"workspaceMount must be 'private' or 'full'\" });\n return;\n }\n const scope = resolveTargetConversation(body, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const dir = join(workingDir, scope.conversationId);\n try {\n saveConversationSandboxConfig(dir, { imageWorkspaceMount: workspaceMount });\n jsonRes(res, 200, { ok: true });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nfunction serveConversationAutoReplyUpdate(\n res: ServerResponse,\n body: Record<string, unknown>,\n services: AdminServices,\n token: AdminToken,\n): void {\n const enabled = body.enabled === true;\n const rules = Array.isArray(body.rules)\n ? body.rules.filter((r): r is string => typeof r === \"string\")\n : undefined;\n const scope = resolveTargetConversation(body, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const dir = join(workingDir, scope.conversationId);\n try {\n const existing = loadConversationAutoReplyConfig(dir);\n saveConversationAutoReplyConfig(dir, {\n enabled,\n rules: rules ?? existing.rules,\n });\n jsonRes(res, 200, { ok: true });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nfunction serveConversationSessionLink(\n res: ServerResponse,\n body: Record<string, unknown>,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveTargetConversation(body, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n if (!services.sessionViewTokenStore) {\n jsonRes(res, 503, { error: \"Session view token store not available\" });\n return;\n }\n if (!services.portalBaseUrl) {\n jsonRes(res, 503, {\n error: \"Portal URL not configured. Set MIKAN_LINK_URL to enable link generation.\",\n });\n return;\n }\n\n const sessionFile = resolveExistingSessionFile(\n workingDir,\n scope.conversationId,\n scope.conversationId,\n );\n if (!sessionFile) {\n jsonRes(res, 404, { error: \"No session file found for this conversation\" });\n return;\n }\n\n try {\n const { token: viewToken } = services.sessionViewTokenStore.create(\n token.platform,\n token.platformUserId,\n scope.conversationId,\n scope.conversationId,\n sessionFile,\n token.platformUserName,\n );\n const url = `${services.portalBaseUrl}/session?token=${encodeURIComponent(viewToken)}`;\n jsonRes(res, 200, { ok: true, url });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nfunction serveConversationLoginLink(\n res: ServerResponse,\n body: Record<string, unknown>,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveTargetConversation(body, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n if (!services.portalBaseUrl) {\n jsonRes(res, 503, { error: \"Portal URL not configured.\" });\n return;\n }\n if (!services.sandbox) {\n jsonRes(res, 503, { error: \"Sandbox config not available.\" });\n return;\n }\n const sharedName = typeof body.sharedVault === \"string\" ? body.sharedVault.trim() : \"\";\n let vaultId: string;\n if (sharedName) {\n const key = sharedVaultKey(sharedName);\n if (!key) {\n jsonRes(res, 400, { error: \"Invalid shared vault name\" });\n return;\n }\n vaultId = key;\n } else {\n try {\n vaultId = resolveActorVaultKey(services.sandbox, token.platformUserId, scope.conversationId);\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n return;\n }\n }\n try {\n const { token: linkToken } = services.linkTokenStore.create(\n token.platform,\n token.platformUserId,\n scope.conversationId,\n vaultId,\n \"\",\n );\n const url = `${services.portalBaseUrl}/link?token=${encodeURIComponent(linkToken)}`;\n jsonRes(res, 200, { ok: true, url, vaultId });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nfunction serveGlobalModelUpdate(res: ServerResponse, body: Record<string, unknown>): void {\n const provider = typeof body.provider === \"string\" ? body.provider.trim() : \"\";\n const model = typeof body.model === \"string\" ? body.model.trim() : \"\";\n const thinkingLevel =\n typeof body.thinkingLevel === \"string\" && VALID_THINKING_LEVELS.has(body.thinkingLevel)\n ? (body.thinkingLevel as AgentConfig[\"thinkingLevel\"])\n : undefined;\n\n if (!provider || !model) {\n jsonRes(res, 400, { error: \"Missing provider or model\" });\n return;\n }\n\n try {\n saveAgentConfig({\n provider,\n model,\n ...(thinkingLevel ? { thinkingLevel } : {}),\n });\n jsonRes(res, 200, { ok: true });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nfunction serveGlobalSandboxUpdate(res: ServerResponse, body: Record<string, unknown>): void {\n const cpus = typeof body.cpus === \"string\" ? body.cpus.trim() : \"\";\n const memory = typeof body.memory === \"string\" ? body.memory.trim() : \"\";\n const boostCpus = typeof body.boostCpus === \"string\" ? body.boostCpus.trim() : \"\";\n const boostMemory = typeof body.boostMemory === \"string\" ? body.boostMemory.trim() : \"\";\n const workspaceMount = body.workspaceMount;\n const validMount = workspaceMount === \"private\" || workspaceMount === \"full\";\n\n const update: Partial<AgentConfig> = {};\n if (cpus) update.sandboxCpus = cpus;\n if (memory) update.sandboxMemory = memory;\n if (boostCpus) update.sandboxBoostCpus = boostCpus;\n if (boostMemory) update.sandboxBoostMemory = boostMemory;\n if (validMount) update.sandboxImageWorkspaceMount = workspaceMount as \"private\" | \"full\";\n\n if (Object.keys(update).length === 0) {\n jsonRes(res, 400, { error: \"No valid sandbox fields provided\" });\n return;\n }\n\n try {\n saveAgentConfig(update);\n jsonRes(res, 200, { ok: true });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\n// โโ Workspace โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nconst WORKSPACE_TREE_MAX_DEPTH = 4;\nconst WORKSPACE_TREE_MAX_ENTRIES = 800;\nconst PREVIEW_FILE_MAX_BYTES = 256 * 1024;\n\nconst WORKSPACE_TOP_FILES = new Set([\"auto-reply\", \"auto-reply.disabled\"]);\nconst WORKSPACE_TOP_DIRS = new Set([\"scratch\"]);\n\n/**\n * Limit what the admin UI can browse under a conversation directory.\n * Allowed: top-level \"scratch/\" subtree, and the two auto-reply marker files.\n */\nfunction isWorkspacePathAllowed(rel: string): boolean {\n if (rel === \"\") return true;\n const segments = rel.split(\"/\").filter(Boolean);\n if (segments.length === 0) return true;\n const first = segments[0];\n if (segments.length === 1) {\n return WORKSPACE_TOP_DIRS.has(first) || WORKSPACE_TOP_FILES.has(first);\n }\n return WORKSPACE_TOP_DIRS.has(first);\n}\n\nfunction resolveConversationFromQuery(\n url: URL,\n token: AdminToken,\n): { conversationId: string; error?: string } {\n const requested = (url.searchParams.get(\"conversationId\") ?? \"\").trim();\n if (!requested) return { conversationId: token.conversationId };\n if (requested === token.conversationId) return { conversationId: requested };\n if (requested.includes(\"/\") || requested.includes(\"..\")) {\n return { conversationId: requested, error: \"Invalid conversationId.\" };\n }\n return { conversationId: requested };\n}\n\ninterface SafePathResult {\n absolute: string;\n error?: string;\n}\n\nfunction safeJoinUnderRoot(rootDir: string, relative: string): SafePathResult {\n if (relative.startsWith(\"/\") || relative.includes(\"\\0\")) {\n return { absolute: \"\", error: \"Invalid path\" };\n }\n if (relative.split(/[\\\\/]+/).some((part) => part === \"..\" || part === \"\")) {\n if (relative !== \"\") return { absolute: \"\", error: \"Invalid path\" };\n }\n const target = pathResolve(rootDir, relative);\n const rootAbs = pathResolve(rootDir);\n if (target !== rootAbs && !target.startsWith(rootAbs + pathSep)) {\n return { absolute: \"\", error: \"Path escapes conversation directory\" };\n }\n return { absolute: target };\n}\n\ninterface TreeNode {\n name: string;\n path: string;\n type: \"dir\" | \"file\";\n size?: number;\n mtimeMs?: number;\n children?: TreeNode[];\n truncated?: boolean;\n}\n\nfunction buildTree(startDir: string, relPrefix: string): TreeNode | null {\n let counter = { value: 0 };\n const walk = (dir: string, rel: string, depth: number): TreeNode | null => {\n if (counter.value >= WORKSPACE_TREE_MAX_ENTRIES) return null;\n let stats;\n try {\n stats = statSync(dir);\n } catch {\n return null;\n }\n const name = rel === \"\" ? \".\" : (rel.split(/[\\\\/]/).pop() ?? rel);\n if (!stats.isDirectory()) {\n counter.value += 1;\n return {\n name,\n path: rel,\n type: \"file\",\n size: stats.size,\n mtimeMs: stats.mtimeMs,\n };\n }\n counter.value += 1;\n if (depth >= WORKSPACE_TREE_MAX_DEPTH) {\n return { name, path: rel, type: \"dir\", truncated: true };\n }\n let entries;\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return { name, path: rel, type: \"dir\" };\n }\n const children: TreeNode[] = [];\n let truncated = false;\n for (const entry of entries.toSorted((a, b) => {\n if (a.isDirectory() !== b.isDirectory()) return a.isDirectory() ? -1 : 1;\n return a.name.localeCompare(b.name);\n })) {\n const childRel = rel === \"\" ? entry.name : `${rel}/${entry.name}`;\n if (!isWorkspacePathAllowed(childRel)) continue;\n if (counter.value >= WORKSPACE_TREE_MAX_ENTRIES) {\n truncated = true;\n break;\n }\n const node = walk(join(dir, entry.name), childRel, depth + 1);\n if (node) children.push(node);\n }\n return {\n name,\n path: rel,\n type: \"dir\",\n children,\n ...(truncated ? { truncated: true } : {}),\n };\n };\n const node = walk(startDir, relPrefix, 0);\n return node;\n}\n\nfunction serveWorkspaceTree(\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveConversationFromQuery(url, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const convDir = join(workingDir, scope.conversationId);\n if (!existsSync(convDir)) {\n jsonRes(res, 200, { conversationId: scope.conversationId, tree: null });\n return;\n }\n const requestedSub = (url.searchParams.get(\"path\") ?? \"\").trim();\n if (!isWorkspacePathAllowed(requestedSub)) {\n jsonRes(res, 403, { error: \"Workspace path is not exposed\" });\n return;\n }\n const startSafe = safeJoinUnderRoot(convDir, requestedSub);\n if (startSafe.error) {\n jsonRes(res, 400, { error: startSafe.error });\n return;\n }\n const tree = buildTree(startSafe.absolute, requestedSub);\n jsonRes(res, 200, {\n conversationId: scope.conversationId,\n root: requestedSub || \".\",\n tree,\n });\n}\n\nconst BINARY_PROBE_BYTES = 4096;\n\nfunction looksTextual(buf: Buffer): boolean {\n const limit = Math.min(buf.length, BINARY_PROBE_BYTES);\n for (let i = 0; i < limit; i++) {\n const byte = buf[i];\n if (byte === 0) return false;\n if (byte < 9) return false;\n if (byte === 11 || byte === 12) return false;\n if (byte > 13 && byte < 32) return false;\n }\n return true;\n}\n\nfunction servePreviewFile(\n res: ServerResponse,\n absolutePath: string,\n metadata: Record<string, unknown>,\n notFoundMessage: string,\n): void {\n let stats;\n try {\n stats = statSync(absolutePath);\n } catch {\n jsonRes(res, 404, { error: notFoundMessage });\n return;\n }\n if (!stats.isFile()) {\n jsonRes(res, 400, { error: \"Not a file\" });\n return;\n }\n if (stats.size > PREVIEW_FILE_MAX_BYTES) {\n jsonRes(res, 413, {\n error: \"File too large to preview\",\n size: stats.size,\n limit: PREVIEW_FILE_MAX_BYTES,\n });\n return;\n }\n let buf: Buffer;\n try {\n buf = readFileSync(absolutePath);\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n return;\n }\n if (!looksTextual(buf)) {\n jsonRes(res, 200, {\n ...metadata,\n size: stats.size,\n mtimeMs: stats.mtimeMs,\n binary: true,\n content: null,\n });\n return;\n }\n jsonRes(res, 200, {\n ...metadata,\n size: stats.size,\n mtimeMs: stats.mtimeMs,\n binary: false,\n content: buf.toString(\"utf-8\"),\n });\n}\n\nfunction serveWorkspaceFile(\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveConversationFromQuery(url, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const requestedPath = (url.searchParams.get(\"path\") ?? \"\").trim();\n if (!requestedPath) {\n jsonRes(res, 400, { error: \"Missing path\" });\n return;\n }\n if (!isWorkspacePathAllowed(requestedPath)) {\n jsonRes(res, 403, { error: \"Workspace path is not exposed\" });\n return;\n }\n const convDir = join(workingDir, scope.conversationId);\n const safe = safeJoinUnderRoot(convDir, requestedPath);\n if (safe.error) {\n jsonRes(res, 400, { error: safe.error });\n return;\n }\n servePreviewFile(res, safe.absolute, { path: requestedPath }, \"File not found\");\n}\n\n// โโ Skills โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\ninterface SkillEntry {\n name: string;\n description: string;\n source: \"global\" | \"conversation\";\n path: string;\n directory: string;\n}\n\nfunction parseSkillFrontmatter(filePath: string): { name?: string; description?: string } {\n let text: string;\n try {\n text = readFileSync(filePath, \"utf-8\");\n } catch {\n return {};\n }\n if (!text.startsWith(\"---\")) return {};\n const end = text.indexOf(\"\\n---\", 3);\n if (end < 0) return {};\n const block = text.slice(3, end);\n const out: { name?: string; description?: string } = {};\n for (const line of block.split(\"\\n\")) {\n const colon = line.indexOf(\":\");\n if (colon < 0) continue;\n const key = line.slice(0, colon).trim().toLowerCase();\n let value = line.slice(colon + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n if (key === \"name\") out.name = value;\n if (key === \"description\") out.description = value;\n }\n return out;\n}\n\nfunction readSkillsFromDir(skillsDir: string, source: SkillEntry[\"source\"]): SkillEntry[] {\n if (!existsSync(skillsDir)) return [];\n const out: SkillEntry[] = [];\n let entries;\n try {\n entries = readdirSync(skillsDir, { withFileTypes: true });\n } catch {\n return [];\n }\n for (const entry of entries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\")) continue;\n const skillMd = join(skillsDir, entry.name, \"SKILL.md\");\n if (!existsSync(skillMd)) continue;\n const meta = parseSkillFrontmatter(skillMd);\n out.push({\n name: meta.name ?? entry.name,\n description: meta.description ?? \"\",\n source,\n path: skillMd,\n directory: entry.name,\n });\n }\n return out.toSorted((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction serveSkillsList(\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveConversationFromQuery(url, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const global = readSkillsFromDir(join(workingDir, \"skills\"), \"global\");\n const conversation = readSkillsFromDir(\n join(workingDir, scope.conversationId, \"skills\"),\n \"conversation\",\n );\n jsonRes(res, 200, {\n conversationId: scope.conversationId,\n skills: [...global, ...conversation],\n });\n}\n\nfunction serveSkillFile(\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveConversationFromQuery(url, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n\n const source = (url.searchParams.get(\"source\") ?? \"\").trim();\n const directory = (url.searchParams.get(\"directory\") ?? \"\").trim();\n if (source !== \"global\" && source !== \"conversation\") {\n jsonRes(res, 400, { error: \"Invalid skill source\" });\n return;\n }\n if (\n !directory ||\n directory.includes(\"/\") ||\n directory.includes(\"\\\\\") ||\n directory.includes(\"..\")\n ) {\n jsonRes(res, 400, { error: \"Invalid skill directory\" });\n return;\n }\n\n const skillsRoot =\n source === \"global\"\n ? join(workingDir, \"skills\")\n : join(workingDir, scope.conversationId, \"skills\");\n const safe = safeJoinUnderRoot(skillsRoot, join(directory, \"SKILL.md\"));\n if (safe.error) {\n jsonRes(res, 400, { error: safe.error });\n return;\n }\n\n servePreviewFile(res, safe.absolute, { source, directory }, \"Skill file not found\");\n}\n\n// โโ Events โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nconst EVENTS_FILE_MAX_BYTES = 64 * 1024;\n\ninterface EventSummary {\n name: string;\n size: number;\n mtimeMs: number;\n type: string | null;\n platform: string | null;\n conversationId: string | null;\n text: string | null;\n at: string | null;\n schedule: string | null;\n timezone: string | null;\n}\n\nfunction listAllEvents(workingDir: string): EventSummary[] {\n const dir = join(workingDir, \"events\");\n if (!existsSync(dir)) return [];\n let entries;\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return [];\n }\n return entries\n .filter((e) => e.isFile() && e.name.endsWith(\".json\"))\n .map((e): EventSummary | null => {\n const filePath = join(dir, e.name);\n let stats;\n try {\n stats = statSync(filePath);\n } catch {\n return null;\n }\n let parsed: unknown = null;\n try {\n parsed = JSON.parse(readFileSync(filePath, \"utf-8\"));\n } catch {\n // Keep entry; just omit parsed fields.\n }\n const meta = parsed && typeof parsed === \"object\" ? (parsed as Record<string, unknown>) : {};\n // events.ts accepts `channelId` as a legacy alias for `conversationId`.\n const conversationId =\n typeof meta.conversationId === \"string\"\n ? meta.conversationId\n : typeof meta.channelId === \"string\"\n ? meta.channelId\n : null;\n return {\n name: e.name,\n size: stats.size,\n mtimeMs: stats.mtimeMs,\n type: typeof meta.type === \"string\" ? meta.type : null,\n platform: typeof meta.platform === \"string\" ? meta.platform : null,\n conversationId,\n text: typeof meta.text === \"string\" ? meta.text : null,\n at: typeof meta.at === \"string\" ? meta.at : null,\n schedule: typeof meta.schedule === \"string\" ? meta.schedule : null,\n timezone: typeof meta.timezone === \"string\" ? meta.timezone : null,\n };\n })\n .filter((e): e is EventSummary => e !== null)\n .toSorted((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction serveEventsList(res: ServerResponse, services: AdminServices): void {\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n jsonRes(res, 200, { events: listAllEvents(workingDir) });\n}\n\n/** Per-conversation listing โ filter all events by conversationId match. */\nfunction serveConversationEventsList(\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveConversationFromQuery(url, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const events = listAllEvents(workingDir).filter((e) => e.conversationId === scope.conversationId);\n jsonRes(res, 200, { conversationId: scope.conversationId, events });\n}\n\nfunction serveEventsFile(res: ServerResponse, url: URL, services: AdminServices): void {\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const name = (url.searchParams.get(\"name\") ?? \"\").trim();\n if (!name || name.includes(\"/\") || name.includes(\"\\\\\") || name.includes(\"..\")) {\n jsonRes(res, 400, { error: \"Invalid name\" });\n return;\n }\n const filePath = join(workingDir, \"events\", name);\n let stats;\n try {\n stats = statSync(filePath);\n } catch {\n jsonRes(res, 404, { error: \"Not found\" });\n return;\n }\n if (!stats.isFile()) {\n jsonRes(res, 400, { error: \"Not a file\" });\n return;\n }\n if (stats.size > EVENTS_FILE_MAX_BYTES) {\n jsonRes(res, 413, { error: \"File too large\" });\n return;\n }\n let raw: string;\n try {\n raw = readFileSync(filePath, \"utf-8\");\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n return;\n }\n jsonRes(res, 200, { name, content: raw });\n}\n\n/** Delete a single event file scoped to the caller's conversation. */\nfunction serveConversationEventDelete(\n res: ServerResponse,\n body: Record<string, unknown>,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveTargetConversation(body, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const name = typeof body.name === \"string\" ? body.name.trim() : \"\";\n if (!name || name.includes(\"/\") || name.includes(\"\\\\\") || name.includes(\"..\")) {\n jsonRes(res, 400, { error: \"Invalid name\" });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const filePath = join(workingDir, \"events\", name);\n let raw: string;\n try {\n raw = readFileSync(filePath, \"utf-8\");\n } catch {\n jsonRes(res, 404, { error: \"Event not found\" });\n return;\n }\n let parsed: Record<string, unknown> = {};\n try {\n const j = JSON.parse(raw);\n if (j && typeof j === \"object\") parsed = j as Record<string, unknown>;\n } catch {\n // Malformed events cannot be associated with a conversation below.\n }\n const eventConvId =\n typeof parsed.conversationId === \"string\"\n ? parsed.conversationId\n : typeof parsed.channelId === \"string\"\n ? parsed.channelId\n : null;\n if (eventConvId !== scope.conversationId) {\n jsonRes(res, 403, { error: \"Event does not belong to this conversation.\" });\n return;\n }\n try {\n rmSync(filePath, { force: true });\n jsonRes(res, 200, { ok: true });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\n// โโ Utilities โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nfunction jsonRes(res: ServerResponse, status: number, body: unknown): void {\n res.writeHead(status, {\n \"Content-Type\": \"application/json; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n });\n res.end(JSON.stringify(body));\n}\n\nasync function readJsonBody(\n req: IncomingMessage,\n res: ServerResponse,\n callback: (body: Record<string, unknown>) => void,\n): Promise<void> {\n let data = \"\";\n let tooLarge = false;\n\n await new Promise<void>((resolve) => {\n req.on(\"data\", (chunk: Buffer) => {\n if (tooLarge) return;\n data += chunk.toString();\n if (data.length > 32 * 1024) {\n tooLarge = true;\n res.writeHead(413);\n res.end();\n req.destroy();\n }\n });\n req.on(\"end\", resolve);\n req.on(\"error\", resolve);\n });\n\n if (tooLarge) return;\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(data) as Record<string, unknown>;\n } catch {\n jsonRes(res, 400, { error: \"Invalid JSON\" });\n return;\n }\n\n callback(parsed);\n}\n\nfunction esc(s: string): string {\n return s.replace(\n /[&<>\"']/g,\n (c) => ({ \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\", \"'\": \"'\" })[c]!,\n );\n}\n\n// โโ HTML โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nfunction renderAdminPage(token: AdminToken): string {\n const userLabel = token.platformUserName ?? token.platformUserId;\n const body = `<nav class=\"tab-nav\" role=\"tablist\" aria-label=\"Admin sections\">\n <button class=\"tab-btn active\" role=\"tab\" aria-selected=\"true\" aria-controls=\"panel-conversation\" data-tab=\"conversation\">Conversation</button>\n <button class=\"tab-btn\" role=\"tab\" aria-selected=\"false\" aria-controls=\"panel-global\" data-tab=\"global\">Global</button>\n </nav>\n\n <div class=\"tab-panel active\" id=\"panel-conversation\">\n <section class=\"card sect\" id=\"sect-settings\" data-section=\"settings\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Settings</p>\n <h2 class=\"card-title\">ๆจกๅ / Thinking / Auto-reply / Workspace mount</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadSettings()\">โป</button>\n </header>\n <div id=\"settings-content\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n </section>\n\n <section class=\"card sect\" id=\"sect-workspace\" data-section=\"workspace\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Workspace</p>\n <h2 class=\"card-title\">ๆชๆก็่ฆฝ (ๅช่ฎ)</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadWorkspace()\">โป</button>\n </header>\n <div class=\"workspace-split\">\n <div id=\"workspace-tree\" class=\"workspace-tree\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n <div id=\"workspace-preview\" class=\"workspace-preview\"><div class=\"placeholder-msg\">Click a file to preview</div></div>\n </div>\n </section>\n\n <section class=\"card sect\" id=\"sect-skills\" data-section=\"skills\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Skills</p>\n <h2 class=\"card-title\">ๅฏ็จ็ skills</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadSkills()\">โป</button>\n </header>\n <div class=\"workspace-split\">\n <div id=\"skills-content\" class=\"workspace-tree\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n <div id=\"skills-preview\" class=\"workspace-preview\"><div class=\"placeholder-msg\">Click a skill to preview SKILL.md</div></div>\n </div>\n </section>\n\n <section class=\"card sect\" id=\"sect-vault\" data-section=\"vault\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Vault</p>\n <h2 class=\"card-title\">่ฉฒๅฐ่ฉฑ็ๆ่ญ</h2>\n </div>\n <button class=\"primary-action-btn\" onclick=\"openLogin()\">Open login form</button>\n </header>\n <div id=\"vault-link-result\" class=\"link-result\" style=\"display:none\"></div>\n <iframe id=\"login-frame\" class=\"portal-frame\" title=\"Login\" style=\"display:none\"></iframe>\n </section>\n\n <section class=\"card sect\" id=\"sect-events\" data-section=\"events\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Events</p>\n <h2 class=\"card-title\">้่ฏๆญคๅฐ่ฉฑ็ events</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadConversationEvents()\">โป</button>\n </header>\n <div id=\"events-content\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n </section>\n\n <section class=\"card sect\" id=\"sect-session\" data-section=\"session\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Session View</p>\n <h2 class=\"card-title\">ๅฐ่ฉฑๆญทๅฒๆชข่ฆ</h2>\n </div>\n <button class=\"primary-action-btn\" onclick=\"openSessionView()\">Open session view</button>\n </header>\n <div id=\"session-link-result\" class=\"link-result\" style=\"display:none\"></div>\n <iframe id=\"session-frame\" class=\"portal-frame\" title=\"Session View\" style=\"display:none\"></iframe>\n </section>\n </div>\n\n <div class=\"tab-panel\" id=\"panel-global\">\n <section class=\"card sect\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">All Conversations</p>\n <h2 class=\"card-title\">ๆๆๅฐ่ฉฑ</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadAllConversations()\">โป</button>\n </header>\n <div id=\"all-conv-content\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n </section>\n\n <section class=\"card sect\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Global Settings</p>\n <h2 class=\"card-title\">ๅ
จๅ้ ่จญ</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadGlobalSettings()\">โป</button>\n </header>\n <div id=\"global-settings-content\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n </section>\n\n <section class=\"card sect\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Global Skills</p>\n <h2 class=\"card-title\">ๅ
จๅ skills</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadGlobalSkills()\">โป</button>\n </header>\n <div id=\"global-skills-content\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n </section>\n\n <section class=\"card sect\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Global Events</p>\n <h2 class=\"card-title\">ๅ
จๅ events.json</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadEvents()\">โป</button>\n </header>\n <div id=\"global-events-content\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n </section>\n </div>`;\n\n const script = `\n const adminToken = ${JSON.stringify(token.token)};\n const defaultConversationId = ${JSON.stringify(token.conversationId)};\n let activeConversationId = defaultConversationId;\n let availableModels = [];\n let modelsLoaded = false;\n\n // โโ Helpers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n function escHtml(str) {\n return String(str).replace(/[&<>\"']/g, (c) => (\n {'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]\n ));\n }\n function escAttr(str) {\n return String(str).replace(/[\"'&<>]/g, (c) => (\n {'\"':'"',\"'\":''','&':'&','<':'<','>':'>'}[c]\n ));\n }\n async function copyToClipboard(text) {\n try { await navigator.clipboard.writeText(text); } catch { prompt('Copy this link:', text); }\n }\n async function apiGet(path) {\n const url = path + (path.includes('?') ? '&' : '?') + 'token=' + encodeURIComponent(adminToken);\n const r = await fetch(url);\n const data = await r.json();\n if (!r.ok) throw new Error(data.error || ('HTTP ' + r.status));\n return data;\n }\n async function apiPost(path, body) {\n const r = await fetch(path, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ token: adminToken, ...body }),\n });\n const data = await r.json();\n if (!r.ok) throw new Error(data.error || ('HTTP ' + r.status));\n return data;\n }\n async function loadModels() {\n try {\n const data = await apiGet('/admin/api/models');\n availableModels = Array.isArray(data.models) ? data.models : [];\n } catch (err) {\n console.error('Failed to load models', err);\n availableModels = [];\n } finally {\n modelsLoaded = true;\n }\n }\n function modelRef(provider, model) {\n return provider && model ? provider + '/' + model : '';\n }\n function parseModelRef(value) {\n const slash = value.indexOf('/');\n if (slash <= 0 || slash === value.length - 1) return { provider: '', model: '' };\n return { provider: value.slice(0, slash), model: value.slice(slash + 1) };\n }\n function renderModelOptions(currentProvider, currentModel) {\n const current = modelRef(currentProvider, currentModel);\n const seen = new Set();\n const options = [];\n if (current) {\n seen.add(current);\n options.push('<option value=\"' + escAttr(current) + '\">' + escHtml(current + ' (current)') + '</option>');\n }\n for (const model of availableModels) {\n const ref = modelRef(model.provider, model.id);\n if (!ref || seen.has(ref)) continue;\n seen.add(ref);\n const details = [model.name && model.name !== model.id ? model.name : '', model.reasoning ? 'thinking' : '', Array.isArray(model.input) && model.input.includes('image') ? 'image' : '']\n .filter(Boolean)\n .join(' ยท ');\n options.push('<option value=\"' + escAttr(ref) + '\">' + escHtml(details ? ref + ' โ ' + details : ref) + '</option>');\n }\n if (options.length === 0) {\n return '<option value=\"\">No available models</option>';\n }\n return options.join('');\n }\n\n // โโ Tab switching โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n const tabBtns = document.querySelectorAll('.tab-btn');\n const tabPanels = document.querySelectorAll('.tab-panel');\n\n function switchTab(tabId) {\n tabBtns.forEach((btn) => {\n const active = btn.dataset.tab === tabId;\n btn.classList.toggle('active', active);\n btn.setAttribute('aria-selected', active ? 'true' : 'false');\n });\n tabPanels.forEach((panel) => panel.classList.toggle('active', panel.id === 'panel-' + tabId));\n if (tabId === 'global') initGlobal();\n }\n tabBtns.forEach((btn) => btn.addEventListener('click', () => switchTab(btn.dataset.tab)));\n\n // โโ Conversation switcher โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n async function initConvSwitcher() {\n const sel = document.getElementById('conv-switcher');\n try {\n const data = await apiGet('/admin/api/conversations');\n sel.innerHTML = data.conversations.map((c) => {\n const label = (c.label || c.conversationId) + (c.running ? ' (running)' : '');\n const selected = c.conversationId === defaultConversationId ? ' selected' : '';\n return '<option value=\"' + escAttr(c.conversationId) + '\"' + selected + '>' + escHtml(label) + '</option>';\n }).join('');\n sel.addEventListener('change', () => setActiveConversation(sel.value));\n } catch (err) {\n console.error('Failed to load conversations', err);\n }\n }\n\n function setActiveConversation(id) {\n activeConversationId = id;\n const sel = document.getElementById('conv-switcher');\n if (sel && sel.value !== id) sel.value = id;\n // Reset all conversation sections.\n loadSettings();\n loadWorkspace();\n loadSkills();\n loadConversationEvents();\n openLogin(true);\n openSessionView(true);\n }\n\n // โโ Settings โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n async function loadSettings() {\n const container = document.getElementById('settings-content');\n container.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n if (!modelsLoaded) await loadModels();\n try {\n const data = await apiGet('/admin/api/conversation-state?conversationId=' + encodeURIComponent(activeConversationId));\n container.innerHTML = renderSettings(data);\n } catch (err) {\n container.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n function renderSettings(data) {\n const thinking = ['off','minimal','low','medium','high','xhigh'];\n const thinkingOpts = thinking.map((t) =>\n '<option value=\"' + t + '\"' + (data.thinkingLevel === t ? ' selected' : '') + '>' + t + '</option>'\n ).join('');\n const mounts = ['private','full'];\n const mountOpts = mounts.map((m) =>\n '<option value=\"' + m + '\"' + (data.sandboxImageWorkspaceMount === m ? ' selected' : '') + '>' + m + '</option>'\n ).join('');\n const rulesText = (data.autoReplyRules || []).join('\\\\n');\n return [\n '<div class=\"config-grid\">',\n '<div class=\"config-block\">',\n '<h3 class=\"card-subtitle\">Model</h3>',\n '<div class=\"config-row config-row-stack\"><label>Model</label><select id=\"m-model-ref\">' + renderModelOptions(data.provider, data.model) + '</select></div>',\n '<div class=\"config-row\"><label>Thinking</label><select id=\"m-thinking\">' + thinkingOpts + '</select></div>',\n '<button class=\"primary-action-btn\" onclick=\"saveModel(this)\">Save model</button>',\n '<div id=\"model-save-result\" class=\"inline-result\" style=\"display:none\"></div>',\n '</div>',\n '<div class=\"config-block\">',\n '<h3 class=\"card-subtitle\">Auto-reply</h3>',\n '<div class=\"config-row\"><label>Enabled</label><label class=\"toggle\"><input type=\"checkbox\" id=\"a-enabled\"' + (data.autoReplyEnabled ? ' checked' : '') + '> on</label></div>',\n '<div class=\"config-row config-row-stack\"><label>Rules</label><textarea id=\"a-rules\" rows=\"5\" placeholder=\"ไธ่กไธๆข่ฆๅ\">' + escHtml(rulesText) + '</textarea></div>',\n '<button class=\"primary-action-btn\" onclick=\"saveAutoReply(this)\">Save auto-reply</button>',\n '<div id=\"auto-save-result\" class=\"inline-result\" style=\"display:none\"></div>',\n '</div>',\n '<div class=\"config-block\">',\n '<h3 class=\"card-subtitle\">Workspace mount</h3>',\n '<div class=\"config-row\"><label>Mode</label><select id=\"m-mount\">' + mountOpts + '</select></div>',\n '<button class=\"primary-action-btn\" onclick=\"saveMount(this)\">Save mount</button>',\n '<div id=\"mount-save-result\" class=\"inline-result\" style=\"display:none\"></div>',\n '</div>',\n '</div>',\n ].join('');\n }\n\n async function saveModel(btn) {\n const selectedModel = parseModelRef(document.getElementById('m-model-ref').value.trim());\n const provider = selectedModel.provider;\n const model = selectedModel.model;\n const thinkingLevel = document.getElementById('m-thinking').value;\n const result = document.getElementById('model-save-result');\n if (!provider || !model) {\n result.style.display = 'block'; result.className = 'inline-result err';\n result.textContent = 'Provider and model are required';\n return;\n }\n btn.disabled = true; btn.textContent = 'Savingโฆ'; result.style.display = 'none';\n try {\n const data = await apiPost('/admin/api/conversations/model', {\n conversationId: activeConversationId, provider, model, thinkingLevel,\n });\n result.style.display = 'block'; result.className = 'inline-result ok';\n result.textContent = data.runtimeSwitched === false\n ? 'Saved โ running session pinned; new model applies on next start.'\n : 'Saved โ';\n } catch (err) {\n result.style.display = 'block'; result.className = 'inline-result err';\n result.textContent = err.message;\n } finally {\n btn.disabled = false; btn.textContent = 'Save model';\n }\n }\n\n async function saveAutoReply(btn) {\n const enabled = document.getElementById('a-enabled').checked;\n const rules = document.getElementById('a-rules').value.split('\\\\n').map((s) => s.trim()).filter(Boolean);\n const result = document.getElementById('auto-save-result');\n btn.disabled = true; btn.textContent = 'Savingโฆ'; result.style.display = 'none';\n try {\n await apiPost('/admin/api/conversations/auto-reply', {\n conversationId: activeConversationId, enabled, rules,\n });\n result.style.display = 'block'; result.className = 'inline-result ok'; result.textContent = 'Saved โ';\n } catch (err) {\n result.style.display = 'block'; result.className = 'inline-result err'; result.textContent = err.message;\n } finally {\n btn.disabled = false; btn.textContent = 'Save auto-reply';\n }\n }\n\n async function saveMount(btn) {\n const workspaceMount = document.getElementById('m-mount').value;\n const result = document.getElementById('mount-save-result');\n btn.disabled = true; btn.textContent = 'Savingโฆ'; result.style.display = 'none';\n try {\n await apiPost('/admin/api/conversations/sandbox', {\n conversationId: activeConversationId, workspaceMount,\n });\n result.style.display = 'block'; result.className = 'inline-result ok'; result.textContent = 'Saved โ';\n } catch (err) {\n result.style.display = 'block'; result.className = 'inline-result err'; result.textContent = err.message;\n } finally {\n btn.disabled = false; btn.textContent = 'Save mount';\n }\n }\n\n // โโ Workspace โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n async function loadWorkspace() {\n const treeEl = document.getElementById('workspace-tree');\n const previewEl = document.getElementById('workspace-preview');\n treeEl.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n previewEl.innerHTML = '<div class=\"placeholder-msg\">Click a file to preview</div>';\n try {\n const data = await apiGet('/admin/api/workspace/tree?conversationId=' + encodeURIComponent(activeConversationId));\n if (!data.tree) {\n treeEl.innerHTML = '<div class=\"empty-state\">No files</div>';\n return;\n }\n treeEl.innerHTML = '<ul class=\"tree-root\">' + renderTreeChildren(data.tree) + '</ul>';\n } catch (err) {\n treeEl.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n function renderTreeChildren(node) {\n if (node.type === 'file') {\n return '<li><button class=\"tree-file\" onclick=\"previewFile(\\\\'' + escAttr(node.path) + '\\\\')\">' + escHtml(node.name) + '</button></li>';\n }\n if (!node.children || node.children.length === 0) {\n return '<li><span class=\"tree-dir empty\">' + escHtml(node.name || '.') + '/</span></li>';\n }\n const inner = node.children.map((c) =>\n c.type === 'file'\n ? '<li><button class=\"tree-file\" onclick=\"previewFile(\\\\'' + escAttr(c.path) + '\\\\')\">' + escHtml(c.name) + '</button></li>'\n : '<li><details open><summary class=\"tree-dir\">' + escHtml(c.name) + '/</summary><ul>' + renderTreeChildren(c) + '</ul></details></li>'\n ).join('');\n return inner;\n }\n\n function renderPreviewFileResult(previewEl, label, data) {\n if (data.binary) {\n previewEl.innerHTML = '<div class=\"preview-meta\">' + escHtml(label) + ' ยท ' + data.size + ' bytes ยท binary</div><div class=\"placeholder-msg\">Binary file โ preview not available</div>';\n return;\n }\n previewEl.innerHTML =\n '<div class=\"preview-meta\">' + escHtml(label) + ' ยท ' + data.size + ' bytes</div>' +\n '<pre class=\"preview-body\">' + escHtml(data.content || '') + '</pre>';\n }\n\n async function previewFile(path) {\n const previewEl = document.getElementById('workspace-preview');\n previewEl.innerHTML = '<div class=\"loading-msg\">Loading ' + escHtml(path) + 'โฆ</div>';\n try {\n const data = await apiGet('/admin/api/workspace/file?conversationId=' + encodeURIComponent(activeConversationId) + '&path=' + encodeURIComponent(path));\n renderPreviewFileResult(previewEl, path, data);\n } catch (err) {\n previewEl.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n // โโ Skills โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n async function loadSkills() {\n const container = document.getElementById('skills-content');\n const previewEl = document.getElementById('skills-preview');\n container.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n if (previewEl) previewEl.innerHTML = '<div class=\"placeholder-msg\">Click a skill to preview SKILL.md</div>';\n try {\n const data = await apiGet('/admin/api/skills?conversationId=' + encodeURIComponent(activeConversationId));\n if (data.skills.length === 0) {\n container.innerHTML = '<div class=\"empty-state\">No skills available</div>';\n return;\n }\n container.innerHTML = '<div class=\"skills-list\">' +\n data.skills.map((s) =>\n '<button class=\"skill-row skill-row-btn\" data-skill-source=\"' + escAttr(s.source) + '\" data-skill-directory=\"' + escAttr(s.directory) + '\" data-skill-name=\"' + escAttr(s.name) + '\">' +\n '<div class=\"skill-name\">' + escHtml(s.name) + '<span class=\"skill-source skill-source-' + s.source + '\">' + s.source + '</span></div>' +\n (s.description ? '<div class=\"skill-desc\">' + escHtml(s.description) + '</div>' : '') +\n '</button>'\n ).join('') + '</div>';\n\n } catch (err) {\n container.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n async function previewSkill(source, directory, name) {\n const previewEl = document.getElementById('skills-preview');\n if (!source || !directory) {\n previewEl.innerHTML = '<div class=\"err-msg\">Missing skill source or directory</div>';\n return;\n }\n previewEl.innerHTML = '<div class=\"loading-msg\">Loading ' + escHtml(name || directory) + 'โฆ</div>';\n try {\n const data = await apiGet('/admin/api/skills/file?conversationId=' + encodeURIComponent(activeConversationId) + '&source=' + encodeURIComponent(source) + '&directory=' + encodeURIComponent(directory));\n renderPreviewFileResult(previewEl, source + '/' + directory + '/SKILL.md', data);\n } catch (err) {\n previewEl.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n document.getElementById('skills-content').addEventListener('click', (event) => {\n const btn = event.target.closest('[data-skill-source]');\n if (!btn) return;\n previewSkill(btn.dataset.skillSource, btn.dataset.skillDirectory, btn.dataset.skillName);\n });\n\n // โโ Vault (Login link) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n async function openLogin(silent) {\n const result = document.getElementById('vault-link-result');\n const frame = document.getElementById('login-frame');\n if (silent) { frame.removeAttribute('src'); frame.style.display = 'none'; result.style.display = 'none'; return; }\n result.style.display = 'block'; result.className = 'link-result loading'; result.textContent = 'Generating linkโฆ';\n try {\n const data = await apiPost('/admin/api/conversations/login-link', { conversationId: activeConversationId });\n result.className = 'link-result ok';\n result.innerHTML =\n '<span class=\"link-vault\">vault: <code>' + escHtml(data.vaultId) + '</code></span>' +\n '<a href=\"' + escAttr(data.url) + '\" target=\"_blank\" rel=\"noopener\">' + escHtml(data.url) + '</a>' +\n '<button class=\"copy-link-btn\" onclick=\"copyToClipboard(' + JSON.stringify(data.url) + ')\">Copy</button>';\n frame.src = data.url; frame.style.display = 'block';\n } catch (err) {\n result.className = 'link-result err'; result.textContent = err.message;\n frame.removeAttribute('src'); frame.style.display = 'none';\n }\n }\n\n // โโ Session View โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n async function openSessionView(silent) {\n const result = document.getElementById('session-link-result');\n const frame = document.getElementById('session-frame');\n if (silent) { frame.removeAttribute('src'); frame.style.display = 'none'; result.style.display = 'none'; return; }\n result.style.display = 'block'; result.className = 'link-result loading'; result.textContent = 'Generating linkโฆ';\n try {\n const data = await apiPost('/admin/api/conversations/session-link', { conversationId: activeConversationId });\n result.className = 'link-result ok';\n result.innerHTML =\n '<a href=\"' + escAttr(data.url) + '\" target=\"_blank\" rel=\"noopener\">' + escHtml(data.url) + '</a>' +\n '<button class=\"copy-link-btn\" onclick=\"copyToClipboard(' + JSON.stringify(data.url) + ')\">Copy</button>';\n frame.src = data.url; frame.style.display = 'block';\n } catch (err) {\n result.className = 'link-result err'; result.textContent = err.message;\n frame.removeAttribute('src'); frame.style.display = 'none';\n }\n }\n\n // โโ Events โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n async function loadConversationEvents() {\n const container = document.getElementById('events-content');\n if (!container) return;\n container.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n try {\n const data = await apiGet('/admin/api/conversations/events?conversationId=' + encodeURIComponent(activeConversationId));\n if (data.events.length === 0) {\n container.innerHTML = '<div class=\"empty-state\">ๆฒๆ้่ฏๆญคๅฐ่ฉฑ็ event</div>';\n return;\n }\n container.innerHTML = '<div class=\"events-list\">' +\n data.events.map((e) => renderEventRow(e, true)).join('') + '</div>';\n } catch (err) {\n container.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n async function loadEvents() {\n const container = document.getElementById('global-events-content');\n if (!container) return;\n container.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n try {\n const data = await apiGet('/admin/api/events');\n if (data.events.length === 0) {\n container.innerHTML = '<div class=\"empty-state\">No events scheduled</div>';\n return;\n }\n container.innerHTML = '<div class=\"events-list\">' +\n data.events.map((e) => renderEventRow(e, false)).join('') + '</div>';\n } catch (err) {\n container.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n function renderEventRow(e, allowDelete) {\n const meta = [e.type, e.platform, e.conversationId, e.schedule || e.at]\n .filter(Boolean).map(escHtml).join(' ยท ');\n const preview = e.text ? '<div class=\"event-text\">' + escHtml(e.text.length > 240 ? e.text.slice(0, 237) + 'โฆ' : e.text) + '</div>' : '';\n const deleteBtn = allowDelete\n ? '<button class=\"event-delete-btn\" onclick=\"deleteEvent(\\\\'' + escAttr(e.name) + '\\\\', this)\">Delete</button>'\n : '';\n return '<div class=\"event-row\">' +\n '<div class=\"event-row-top\">' +\n '<div class=\"event-name\"><code>' + escHtml(e.name) + '</code></div>' +\n deleteBtn +\n '</div>' +\n '<div class=\"event-meta\">' + meta + '</div>' +\n preview +\n '</div>';\n }\n\n async function deleteEvent(name, btn) {\n if (!confirm('Delete event \"' + name + '\"?')) return;\n btn.disabled = true; btn.textContent = 'Deletingโฆ';\n try {\n await apiPost('/admin/api/conversations/events/delete', {\n conversationId: activeConversationId, name,\n });\n await loadConversationEvents();\n } catch (err) {\n btn.disabled = false; btn.textContent = 'Delete';\n alert(err.message);\n }\n }\n\n // โโ Global section โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n let globalLoaded = false;\n function initGlobal() {\n if (globalLoaded) return;\n globalLoaded = true;\n loadAllConversations();\n loadGlobalSettings();\n loadGlobalSkills();\n loadEvents();\n }\n\n async function loadAllConversations() {\n const container = document.getElementById('all-conv-content');\n container.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n try {\n const data = await apiGet('/admin/api/conversations');\n if (data.conversations.length === 0) {\n container.innerHTML = '<div class=\"empty-state\">No conversations found</div>';\n return;\n }\n container.innerHTML = '<div class=\"conv-list\">' + data.conversations.map((c) => {\n const last = c.lastActivityAt ? new Date(c.lastActivityAt).toLocaleString() : 'โ';\n return '<button class=\"conv-row-btn\" onclick=\"setActiveConversation(\\\\'' + escAttr(c.conversationId) + '\\\\'); switchTab(\\\\'conversation\\\\');\">' +\n '<span class=\"conv-id\">' + escHtml(c.label || c.conversationId) + '</span>' +\n (c.running ? '<span class=\"status-pill running\">running</span>' : '') +\n '<span class=\"conv-last\">' + escHtml(last) + '</span>' +\n '</button>';\n }).join('') + '</div>';\n } catch (err) {\n container.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n async function loadGlobalSettings() {\n const container = document.getElementById('global-settings-content');\n container.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n if (!modelsLoaded) await loadModels();\n try {\n const data = await apiGet('/admin/api/settings/global');\n container.innerHTML = renderGlobalSettings(data);\n } catch (err) {\n container.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n function renderGlobalSettings(data) {\n const thinking = ['off','minimal','low','medium','high','xhigh'];\n const thinkingOpts = thinking.map((t) =>\n '<option value=\"' + t + '\"' + (data.thinkingLevel === t ? ' selected' : '') + '>' + t + '</option>'\n ).join('');\n const mounts = ['private','full'];\n const mountOpts = mounts.map((m) =>\n '<option value=\"' + m + '\"' + (data.sandboxImageWorkspaceMount === m ? ' selected' : '') + '>' + m + '</option>'\n ).join('');\n return [\n '<div class=\"config-grid\">',\n '<div class=\"config-block\">',\n '<h3 class=\"card-subtitle\">Default model</h3>',\n '<div class=\"config-row config-row-stack\"><label>Model</label><select id=\"g-model-ref\">' + renderModelOptions(data.provider, data.model) + '</select></div>',\n '<div class=\"config-row\"><label>Thinking</label><select id=\"g-thinking\">' + thinkingOpts + '</select></div>',\n '<button class=\"primary-action-btn\" onclick=\"saveGlobalModel(this)\">Save model</button>',\n '<div id=\"g-model-result\" class=\"inline-result\" style=\"display:none\"></div>',\n '</div>',\n '<div class=\"config-block\">',\n '<h3 class=\"card-subtitle\">Sandbox limits</h3>',\n '<div class=\"config-row\"><label>CPUs</label><input id=\"g-cpus\" placeholder=\"0.5\" value=\"' + escAttr(data.sandboxCpus || '') + '\"></div>',\n '<div class=\"config-row\"><label>Memory</label><input id=\"g-mem\" placeholder=\"1g\" value=\"' + escAttr(data.sandboxMemory || '') + '\"></div>',\n '<div class=\"config-row\"><label>Boost CPUs</label><input id=\"g-bcpus\" placeholder=\"2\" value=\"' + escAttr(data.sandboxBoostCpus || '') + '\"></div>',\n '<div class=\"config-row\"><label>Boost Mem</label><input id=\"g-bmem\" placeholder=\"4g\" value=\"' + escAttr(data.sandboxBoostMemory || '') + '\"></div>',\n '<div class=\"config-row\"><label>Mount</label><select id=\"g-mount\">' + mountOpts + '</select></div>',\n '<button class=\"primary-action-btn\" onclick=\"saveGlobalSandbox(this)\">Save sandbox</button>',\n '<div id=\"g-sandbox-result\" class=\"inline-result\" style=\"display:none\"></div>',\n '</div>',\n '</div>',\n ].join('');\n }\n\n async function saveGlobalModel(btn) {\n const selectedModel = parseModelRef(document.getElementById('g-model-ref').value.trim());\n const provider = selectedModel.provider;\n const model = selectedModel.model;\n const thinkingLevel = document.getElementById('g-thinking').value;\n const result = document.getElementById('g-model-result');\n if (!provider || !model) {\n result.style.display = 'block'; result.className = 'inline-result err';\n result.textContent = 'Provider and model are required'; return;\n }\n btn.disabled = true; btn.textContent = 'Savingโฆ'; result.style.display = 'none';\n try {\n await apiPost('/admin/api/settings/model', { provider, model, thinkingLevel });\n result.style.display = 'block'; result.className = 'inline-result ok'; result.textContent = 'Saved โ';\n } catch (err) {\n result.style.display = 'block'; result.className = 'inline-result err'; result.textContent = err.message;\n } finally {\n btn.disabled = false; btn.textContent = 'Save model';\n }\n }\n\n async function saveGlobalSandbox(btn) {\n const cpus = document.getElementById('g-cpus').value.trim();\n const memory = document.getElementById('g-mem').value.trim();\n const boostCpus = document.getElementById('g-bcpus').value.trim();\n const boostMemory = document.getElementById('g-bmem').value.trim();\n const workspaceMount = document.getElementById('g-mount').value;\n const result = document.getElementById('g-sandbox-result');\n btn.disabled = true; btn.textContent = 'Savingโฆ'; result.style.display = 'none';\n try {\n await apiPost('/admin/api/settings/sandbox', { cpus, memory, boostCpus, boostMemory, workspaceMount });\n result.style.display = 'block'; result.className = 'inline-result ok'; result.textContent = 'Saved โ';\n } catch (err) {\n result.style.display = 'block'; result.className = 'inline-result err'; result.textContent = err.message;\n } finally {\n btn.disabled = false; btn.textContent = 'Save sandbox';\n }\n }\n\n async function loadGlobalSkills() {\n const container = document.getElementById('global-skills-content');\n container.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n try {\n // Reuse skills endpoint scoped to a conversation that doesn't have any of its own; the global half is what we want.\n const data = await apiGet('/admin/api/skills?conversationId=' + encodeURIComponent(activeConversationId));\n const globals = data.skills.filter((s) => s.source === 'global');\n if (globals.length === 0) {\n container.innerHTML = '<div class=\"empty-state\">No global skills</div>';\n return;\n }\n container.innerHTML = '<div class=\"skills-list\">' + globals.map((s) =>\n '<div class=\"skill-row\"><div class=\"skill-name\">' + escHtml(s.name) + '</div>' +\n (s.description ? '<div class=\"skill-desc\">' + escHtml(s.description) + '</div>' : '') + '</div>'\n ).join('') + '</div>';\n } catch (err) {\n container.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n // โโ Init โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n initConvSwitcher();\n loadModels().finally(() => {\n loadSettings();\n loadWorkspace();\n loadSkills();\n loadConversationEvents();\n });\n `;\n\n return renderPortalShell({\n activeView: \"admin\",\n pageTitle: \"Admin\",\n identity: { primary: token.platform, secondary: userLabel },\n conversationSwitcher: { currentId: token.conversationId },\n body,\n extraStyles: adminViewStyles,\n inlineScript: script,\n });\n}\n\nfunction renderAdminErrorPage(message: string): string {\n return renderPortalShell({\n activeView: \"admin\",\n pageTitle: \"Admin\",\n body: `<section class=\"card\" style=\"text-align:center;padding:40px 32px\">\n <p class=\"eyebrow\">${PRODUCT_NAME} admin</p>\n <h1 class=\"page-title\" style=\"margin:12px 0 16px\">Access Denied</h1>\n <div class=\"err-msg\">${esc(message)}</div>\n </section>`,\n });\n}\n\n// โโ Styles โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nconst adminViewStyles = `\n .tab-nav {\n display: flex; gap: 6px; padding: 6px;\n border: 1px solid var(--border); border-radius: 16px;\n background: rgba(255,255,255,0.72); backdrop-filter: blur(8px);\n overflow-x: auto; scrollbar-width: none;\n }\n .tab-nav::-webkit-scrollbar { display: none; }\n .tab-btn {\n flex: 1; min-width: 80px; padding: 10px 16px;\n border: none; border-radius: 10px; background: transparent;\n color: var(--muted);\n font: 500 0.88rem/1.2 'DM Sans', sans-serif;\n cursor: pointer; white-space: nowrap;\n transition: background 140ms, color 140ms;\n }\n .tab-btn:hover { background: rgba(0,0,0,0.04); color: var(--text); }\n .tab-btn.active { background: var(--text); color: #fafafa; font-weight: 600; }\n .tab-btn:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }\n\n .tab-panel { display: none; flex-direction: column; gap: 14px; }\n .tab-panel.active { display: flex; }\n\n .card-desc { color: var(--muted); font-size: 0.9rem; line-height: 1.55; margin-bottom: 12px; }\n\n .link-result {\n margin-top: 12px; padding: 10px 14px; border-radius: 10px;\n display: flex; gap: 10px; align-items: center; flex-wrap: wrap;\n font-size: 0.84rem;\n }\n .link-result.ok { background: var(--ok-bg); border: 1px solid var(--ok-border); }\n .link-result.err { background: var(--err-bg); border: 1px solid var(--err-border); color: var(--err-text); }\n .link-result.loading { background: rgba(0,0,0,0.025); border: 1px solid var(--border); color: var(--muted); }\n .link-result a {\n color: var(--ok-text);\n font-family: 'JetBrains Mono', ui-monospace, monospace;\n font-size: 0.78rem; word-break: break-all; flex: 1; min-width: 0;\n }\n .link-vault { color: var(--muted); font-size: 0.78rem; flex-shrink: 0; }\n .copy-link-btn {\n padding: 5px 12px; border: 1px solid var(--ok-border); border-radius: 7px;\n background: rgba(255,255,255,0.7); color: var(--ok-text);\n font: 500 0.78rem/1.2 'DM Sans', sans-serif;\n cursor: pointer; flex-shrink: 0;\n }\n\n .portal-frame {\n width: 100%; min-height: 720px;\n border: 1px solid var(--border); border-radius: 14px; background: #fff;\n }\n\n .config-grid {\n display: grid; grid-template-columns: 1fr 1fr; gap: 18px;\n }\n .config-block { display: flex; flex-direction: column; gap: 10px; }\n .config-row { display: grid; grid-template-columns: 110px 1fr; gap: 10px; align-items: center; }\n .config-row.config-row-stack { grid-template-columns: 1fr; }\n .config-row label { font-size: 0.82rem; color: var(--muted); }\n .config-row input, .config-row select, .config-row textarea {\n padding: 7px 10px; border: 1px solid var(--border); border-radius: 8px;\n font-family: inherit; font-size: 0.84rem; width: 100%;\n }\n .config-row textarea {\n font-family: 'JetBrains Mono', ui-monospace, monospace;\n resize: vertical;\n }\n .toggle { display: inline-flex; align-items: center; gap: 8px; font-size: 0.84rem; }\n\n .inline-result {\n padding: 8px 12px; border-radius: 8px; font-size: 0.82rem; margin-top: 4px;\n }\n .inline-result.ok { background: var(--ok-bg); color: var(--ok-text); border: 1px solid var(--ok-border); }\n .inline-result.err { background: var(--err-bg); color: var(--err-text); border: 1px solid var(--err-border); }\n\n /* โโ Sections (Conversation page stack) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\n .sect-head {\n display: flex; align-items: flex-start; justify-content: space-between;\n gap: 12px; margin-bottom: 14px; flex-wrap: wrap;\n }\n .sect-head .card-title { margin-bottom: 0; }\n .sect-disabled { opacity: 0.7; }\n\n .refresh-btn {\n flex-shrink: 0; padding: 6px 12px;\n border: 1px solid var(--border); border-radius: 10px;\n background: rgba(0,0,0,0.025); color: var(--muted);\n font: 500 0.84rem/1.2 'DM Sans', sans-serif; cursor: pointer;\n }\n .refresh-btn:hover { background: rgba(0,0,0,0.06); color: var(--text); }\n\n /* โโ Workspace โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\n .workspace-split {\n display: grid; grid-template-columns: 260px 1fr; gap: 14px;\n min-height: 360px;\n }\n .workspace-tree {\n border: 1px solid var(--border); border-radius: 12px; padding: 10px;\n background: rgba(0,0,0,0.02); overflow: auto; max-height: 480px;\n font-family: 'JetBrains Mono', ui-monospace, monospace;\n font-size: 0.78rem;\n }\n .workspace-tree ul { list-style: none; padding-left: 12px; margin: 0; }\n .workspace-tree .tree-root { padding-left: 0; }\n .workspace-tree details { margin: 1px 0; }\n .workspace-tree summary { cursor: pointer; padding: 2px 4px; border-radius: 4px; }\n .workspace-tree summary:hover { background: rgba(0,0,0,0.05); }\n .tree-dir { color: var(--text); font-weight: 600; }\n .tree-dir.empty { color: var(--subtle); font-weight: 400; }\n .tree-file {\n display: block; width: 100%; text-align: left;\n background: transparent; border: none; cursor: pointer;\n padding: 2px 4px; border-radius: 4px;\n font-family: inherit; font-size: inherit; color: var(--muted);\n }\n .tree-file:hover { background: rgba(0,0,0,0.05); color: var(--text); }\n\n .workspace-preview {\n border: 1px solid var(--border); border-radius: 12px;\n background: #fff; padding: 12px; overflow: auto; max-height: 480px;\n }\n .preview-meta {\n font-size: 0.74rem; color: var(--subtle);\n margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px solid var(--border);\n font-family: 'JetBrains Mono', ui-monospace, monospace;\n }\n .preview-body {\n margin: 0; white-space: pre-wrap; word-break: break-word;\n font-family: 'JetBrains Mono', ui-monospace, monospace;\n font-size: 0.78rem; color: var(--text);\n }\n .placeholder-msg { color: var(--subtle); font-size: 0.86rem; padding: 24px 8px; text-align: center; }\n\n /* โโ Skills โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\n .skills-list { display: flex; flex-direction: column; gap: 8px; }\n .skill-row {\n padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px;\n background: rgba(0,0,0,0.02);\n }\n .skill-row-btn {\n width: 100%; text-align: left; cursor: pointer; font-family: inherit;\n }\n .skill-row-btn:hover { background: rgba(0,0,0,0.05); }\n .skill-name {\n font-weight: 650; font-size: 0.9rem; color: var(--text);\n display: flex; align-items: center; gap: 8px; flex-wrap: wrap;\n }\n .skill-source {\n padding: 1px 8px; border-radius: 999px; font-size: 0.7rem;\n font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;\n }\n .skill-source-global { background: rgba(59,130,246,0.1); color: #1d4ed8; }\n .skill-source-conversation { background: rgba(217,119,6,0.1); color: var(--accent); }\n .skill-desc { color: var(--muted); font-size: 0.82rem; margin-top: 4px; line-height: 1.5; }\n\n /* โโ Events โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\n .events-list { display: flex; flex-direction: column; gap: 8px; }\n .event-row {\n padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px;\n background: rgba(0,0,0,0.02);\n }\n .event-row-top {\n display: flex; align-items: center; justify-content: space-between;\n gap: 10px;\n }\n .event-name { min-width: 0; flex: 1; word-break: break-all; }\n .event-name code { font-size: 0.82rem; background: transparent; padding: 0; }\n .event-meta { font-size: 0.74rem; color: var(--muted); margin-top: 3px; }\n .event-text {\n font-size: 0.82rem; color: var(--text); margin-top: 6px;\n font-family: 'JetBrains Mono', ui-monospace, monospace;\n white-space: pre-wrap; word-break: break-word;\n }\n .event-delete-btn {\n flex-shrink: 0; padding: 4px 10px;\n border-radius: 7px; border: 1px solid rgba(185, 28, 28, 0.18);\n background: rgba(0,0,0,0.03); color: var(--err-text);\n font: 500 0.76rem/1.2 'DM Sans', sans-serif; cursor: pointer;\n }\n .event-delete-btn:hover:not(:disabled) {\n background: var(--err-bg); border-color: rgba(185, 28, 28, 0.28);\n }\n .event-delete-btn:disabled { opacity: 0.5; cursor: wait; }\n\n /* โโ All Conversations list โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\n .conv-list { display: flex; flex-direction: column; gap: 6px; }\n .conv-row-btn {\n display: flex; align-items: center; gap: 12px;\n padding: 10px 14px; border: 1px solid var(--border); border-radius: 10px;\n background: rgba(0,0,0,0.02); cursor: pointer; text-align: left;\n transition: background 120ms, border-color 120ms;\n }\n .conv-row-btn:hover { background: rgba(0,0,0,0.05); border-color: rgba(0,0,0,0.14); }\n .conv-id { flex: 1; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 0.84rem; }\n .conv-last { color: var(--subtle); font-size: 0.78rem; }\n\n .status-pill {\n display: inline-flex; padding: 2px 9px; border-radius: 999px;\n font-size: 0.7rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;\n }\n .status-pill.running { background: var(--ok-bg); color: var(--ok-text); border: 1px solid var(--ok-border); }\n\n @media (max-width: 640px) {\n .tab-btn { padding: 9px 12px; font-size: 0.82rem; min-width: 60px; }\n .config-grid { grid-template-columns: 1fr; }\n .config-row { grid-template-columns: 1fr; gap: 4px; }\n .portal-frame { min-height: 520px; }\n .workspace-split { grid-template-columns: 1fr; }\n .workspace-tree, .workspace-preview { max-height: 260px; }\n }\n`;\n"]}
|
|
1
|
+
{"version":3,"file":"portal.js","sourceRoot":"","sources":["../../src/admin/portal.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync, readFileSync, rmSync, statSync } from \"fs\";\nimport type { IncomingMessage, ServerResponse } from \"http\";\nimport { homedir } from \"os\";\nimport { join, resolve as pathResolve, sep as pathSep } from \"path\";\nimport { AuthStorage, ModelRegistry } from \"@earendil-works/pi-coding-agent\";\nimport type { Bot, PlatformName, RunningSession } from \"../adapter.js\";\nimport {\n loadAgentConfig,\n loadAgentConfigForConversation,\n loadConversationAutoReplyConfig,\n saveAgentConfig,\n saveConversationAutoReplyConfig,\n saveConversationModelConfig,\n saveConversationSandboxConfig,\n type AgentConfig,\n} from \"../config.js\";\nimport { escapeHtml } from \"../html.js\";\nimport { renderPortalShell } from \"../portal-shell.js\";\nimport type { SandboxConfig } from \"../sandbox/index.js\";\nimport { resolveExistingSessionFile } from \"../session-view/service.js\";\nimport type { InMemorySessionViewTokenStore } from \"../session-view/store.js\";\nimport { PRODUCT_NAME } from \"../ui-copy.js\";\nimport { resolveActorVaultKey } from \"../vault-routing.js\";\nimport { sharedVaultKey, type VaultManager } from \"../vault.js\";\nimport type { AdminToken, InMemoryAdminTokenStore } from \"./store.js\";\n\n// โโ Types โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nexport interface AdminRuntimeBridge {\n getRunningSessions(): RunningSession[];\n switchConversationModel(conversationId: string, provider: string, model: string): boolean;\n}\n\nexport interface AdminServices {\n vaultManager: VaultManager;\n linkTokenStore: {\n create(\n platform: PlatformName,\n platformUserId: string,\n conversationId: string,\n vaultId: string,\n providerId: string,\n ): { token: string };\n };\n sessionViewTokenStore?: InMemorySessionViewTokenStore;\n adminTokenStore: InMemoryAdminTokenStore;\n portalBaseUrl?: string;\n workingDir?: string;\n sandbox?: SandboxConfig;\n runtime?: AdminRuntimeBridge;\n botsByPlatform?: Partial<Record<PlatformName, Bot>>;\n}\n\n// โโ Handler โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nexport function handleAdminRequest(\n req: IncomingMessage,\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n): boolean {\n if (!url.pathname.startsWith(\"/admin\")) return false;\n\n if (req.method === \"GET\" && url.pathname === \"/admin\") {\n const provided = url.searchParams.get(\"token\") ?? \"\";\n const token = services.adminTokenStore.peek(provided);\n if (!token) {\n res.writeHead(403, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(\n renderAdminErrorPage(\n \"Admin link is missing, invalid, or expired. Send `/admin` to the bot to get a fresh link.\",\n ),\n );\n return true;\n }\n res.writeHead(200, {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n });\n res.end(renderAdminPage(token));\n return true;\n }\n\n if (url.pathname.startsWith(\"/admin/api/\")) {\n routeApiRequest(req, res, url, services);\n return true;\n }\n\n return false;\n}\n\n// โโ API routing โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nfunction routeApiRequest(\n req: IncomingMessage,\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n): void {\n if (req.method === \"GET\") {\n const token = services.adminTokenStore.peek(url.searchParams.get(\"token\") ?? \"\");\n if (!token) {\n jsonRes(res, 403, { error: \"Unauthorized\" });\n return;\n }\n if (url.pathname === \"/admin/api/me\") {\n serveMe(res, token);\n return;\n }\n if (url.pathname === \"/admin/api/conversations\") {\n serveConversationsList(res, services);\n return;\n }\n if (url.pathname === \"/admin/api/conversation-state\") {\n serveConversationState(res, url, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/settings/global\") {\n serveGlobalSettings(res);\n return;\n }\n if (url.pathname === \"/admin/api/models\") {\n void serveModelsList(res);\n return;\n }\n if (url.pathname === \"/admin/api/workspace/tree\") {\n serveWorkspaceTree(res, url, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/workspace/file\") {\n serveWorkspaceFile(res, url, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/skills\") {\n serveSkillsList(res, url, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/skills/file\") {\n serveSkillFile(res, url, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/events\") {\n serveEventsList(res, services);\n return;\n }\n if (url.pathname === \"/admin/api/events/file\") {\n serveEventsFile(res, url, services);\n return;\n }\n if (url.pathname === \"/admin/api/conversations/events\") {\n serveConversationEventsList(res, url, services, token);\n return;\n }\n jsonRes(res, 404, { error: \"Not found\" });\n return;\n }\n\n if (req.method === \"POST\") {\n void readJsonBody(req, res, (body) => {\n const rawToken = typeof body.token === \"string\" ? body.token : \"\";\n const token = services.adminTokenStore.peek(rawToken);\n if (!token) {\n jsonRes(res, 403, { error: \"Unauthorized\" });\n return;\n }\n if (url.pathname === \"/admin/api/conversations/model\") {\n serveConversationModelUpdate(res, body, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/conversations/sandbox\") {\n serveConversationSandboxUpdate(res, body, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/conversations/auto-reply\") {\n serveConversationAutoReplyUpdate(res, body, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/conversations/session-link\") {\n serveConversationSessionLink(res, body, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/conversations/login-link\") {\n serveConversationLoginLink(res, body, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/conversations/events/delete\") {\n serveConversationEventDelete(res, body, services, token);\n return;\n }\n if (url.pathname === \"/admin/api/settings/model\") {\n serveGlobalModelUpdate(res, body);\n return;\n }\n if (url.pathname === \"/admin/api/settings/sandbox\") {\n serveGlobalSandboxUpdate(res, body);\n return;\n }\n jsonRes(res, 404, { error: \"Not found\" });\n });\n return;\n }\n\n jsonRes(res, 405, { error: \"Method not allowed\" });\n}\n\n// โโ Scope helpers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nfunction resolveTargetConversation(\n body: Record<string, unknown>,\n token: AdminToken,\n): { conversationId: string; error?: string } {\n const requested = typeof body.conversationId === \"string\" ? body.conversationId.trim() : \"\";\n if (!requested) return { conversationId: token.conversationId };\n if (requested === token.conversationId) return { conversationId: requested };\n if (requested.includes(\"/\") || requested.includes(\"..\")) {\n return { conversationId: requested, error: \"Invalid conversationId.\" };\n }\n return { conversationId: requested };\n}\n\nfunction requireAdminWorkingDir(res: ServerResponse, services: AdminServices): string | null {\n if (!services.workingDir) {\n jsonRes(res, 503, { error: \"Working directory not available\" });\n return null;\n }\n return services.workingDir;\n}\n\n// โโ API handlers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nfunction serveMe(res: ServerResponse, token: AdminToken): void {\n jsonRes(res, 200, {\n platform: token.platform,\n platformUserId: token.platformUserId,\n platformUserName: token.platformUserName ?? null,\n conversationId: token.conversationId,\n expiresAt: token.expiresAt,\n });\n}\n\nconst SETTINGS_FILES = new Set([\"settings.json\", \"auto-reply\", \"auto-reply.disabled\"]);\n\nfunction listConversationDirs(workingDir: string): string[] {\n if (!existsSync(workingDir)) return [];\n const skip = new Set([\"vaults\", \"skills\", \"events\", \"node_modules\", \".git\"]);\n return readdirSync(workingDir, { withFileTypes: true })\n .filter((entry) => entry.isDirectory() && !entry.name.startsWith(\".\") && !skip.has(entry.name))\n .map((entry) => entry.name)\n .filter((name) => {\n const dir = join(workingDir, name);\n try {\n const items = readdirSync(dir);\n return items.some((item) => SETTINGS_FILES.has(item) || item.endsWith(\".jsonl\"));\n } catch {\n return false;\n }\n })\n .toSorted((a, b) => a.localeCompare(b));\n}\n\nfunction conversationLastActivity(workingDir: string, conversationId: string): number | null {\n const dir = join(workingDir, conversationId);\n if (!existsSync(dir)) return null;\n let latest = 0;\n const visit = (path: string, depth: number): void => {\n if (depth > 3) return;\n let entries;\n try {\n entries = readdirSync(path, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const full = join(path, entry.name);\n if (entry.isDirectory()) {\n visit(full, depth + 1);\n continue;\n }\n try {\n const stats = statSync(full);\n if (stats.mtimeMs > latest) latest = stats.mtimeMs;\n } catch {\n // ignore\n }\n }\n };\n visit(dir, 0);\n return latest > 0 ? latest : null;\n}\n\nfunction conversationDisplayLabel(services: AdminServices, conversationId: string): string {\n for (const [platform, bot] of Object.entries(services.botsByPlatform ?? {})) {\n const channel = bot?.getPlatformInfo().channels.find((c) => c.id === conversationId);\n if (channel) return `${platform}:#${channel.name}:${conversationId}`;\n }\n return conversationId;\n}\n\nfunction serveConversationsList(res: ServerResponse, services: AdminServices): void {\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n\n const ids = listConversationDirs(workingDir);\n\n const runningKeys = new Set<string>(\n services.runtime?.getRunningSessions().map((s) => s.sessionKey) ?? [],\n );\n\n const conversations = ids.map((conversationId) => {\n const lastActivity = conversationLastActivity(workingDir, conversationId);\n const running = Array.from(runningKeys).some(\n (key) => key === conversationId || key.startsWith(`${conversationId}:`),\n );\n return {\n conversationId,\n label: conversationDisplayLabel(services, conversationId),\n running,\n lastActivityAt: lastActivity,\n };\n });\n\n jsonRes(res, 200, { conversations });\n}\n\nfunction serveConversationState(\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n token: AdminToken,\n): void {\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n\n const requested = url.searchParams.get(\"conversationId\")?.trim() ?? \"\";\n const conversationId = requested || token.conversationId;\n if (conversationId.includes(\"/\") || conversationId.includes(\"..\")) {\n jsonRes(res, 400, { error: \"Invalid conversationId\" });\n return;\n }\n\n const dir = join(workingDir, conversationId);\n let modelConfig: AgentConfig | null = null;\n try {\n modelConfig = loadAgentConfigForConversation(dir);\n } catch {\n modelConfig = null;\n }\n const autoReply = loadConversationAutoReplyConfig(dir);\n\n jsonRes(res, 200, {\n conversationId,\n provider: modelConfig?.provider ?? null,\n model: modelConfig?.model ?? null,\n thinkingLevel: modelConfig?.thinkingLevel ?? null,\n sandboxImageWorkspaceMount: modelConfig?.sandboxImageWorkspaceMount ?? null,\n autoReplyEnabled: autoReply.enabled,\n autoReplyRules: autoReply.rules,\n });\n}\n\nfunction serveGlobalSettings(res: ServerResponse): void {\n try {\n const config = loadAgentConfig();\n jsonRes(res, 200, {\n provider: config.provider,\n model: config.model,\n thinkingLevel: config.thinkingLevel,\n sandboxCpus: config.sandboxCpus ?? null,\n sandboxMemory: config.sandboxMemory ?? null,\n sandboxBoostCpus: config.sandboxBoostCpus ?? null,\n sandboxBoostMemory: config.sandboxBoostMemory ?? null,\n sandboxImageWorkspaceMount: config.sandboxImageWorkspaceMount ?? null,\n defaultSharedVault: config.defaultSharedVault ?? null,\n });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nasync function serveModelsList(res: ServerResponse): Promise<void> {\n try {\n const authStorage = AuthStorage.create(join(homedir(), \".pi\", \"mikan\", \"auth.json\"));\n const registry = ModelRegistry.create(authStorage);\n const models = (await registry.getAvailable()).map((model) => ({\n provider: model.provider,\n id: model.id,\n name: model.name ?? model.id,\n reasoning: model.reasoning,\n input: model.input,\n contextWindow: model.contextWindow,\n maxTokens: model.maxTokens,\n }));\n jsonRes(res, 200, { models });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nconst VALID_THINKING_LEVELS = new Set([\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"]);\n\nfunction serveConversationModelUpdate(\n res: ServerResponse,\n body: Record<string, unknown>,\n services: AdminServices,\n token: AdminToken,\n): void {\n const provider = typeof body.provider === \"string\" ? body.provider.trim() : \"\";\n const model = typeof body.model === \"string\" ? body.model.trim() : \"\";\n const thinkingLevel =\n typeof body.thinkingLevel === \"string\" && VALID_THINKING_LEVELS.has(body.thinkingLevel)\n ? (body.thinkingLevel as AgentConfig[\"thinkingLevel\"])\n : undefined;\n\n if (!provider || !model) {\n jsonRes(res, 400, { error: \"Missing provider or model\" });\n return;\n }\n const scope = resolveTargetConversation(body, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const dir = join(workingDir, scope.conversationId);\n\n try {\n saveConversationModelConfig(dir, {\n provider,\n model,\n ...(thinkingLevel ? { thinkingLevel } : {}),\n });\n let runtimeSwitched: boolean | null = null;\n if (services.runtime) {\n runtimeSwitched = services.runtime.switchConversationModel(\n scope.conversationId,\n provider,\n model,\n );\n }\n jsonRes(res, 200, { ok: true, runtimeSwitched });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nfunction serveConversationSandboxUpdate(\n res: ServerResponse,\n body: Record<string, unknown>,\n services: AdminServices,\n token: AdminToken,\n): void {\n const workspaceMount = body.workspaceMount;\n if (workspaceMount !== \"private\" && workspaceMount !== \"full\") {\n jsonRes(res, 400, { error: \"workspaceMount must be 'private' or 'full'\" });\n return;\n }\n const scope = resolveTargetConversation(body, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const dir = join(workingDir, scope.conversationId);\n try {\n saveConversationSandboxConfig(dir, { imageWorkspaceMount: workspaceMount });\n jsonRes(res, 200, { ok: true });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nfunction serveConversationAutoReplyUpdate(\n res: ServerResponse,\n body: Record<string, unknown>,\n services: AdminServices,\n token: AdminToken,\n): void {\n const enabled = body.enabled === true;\n const rules = Array.isArray(body.rules)\n ? body.rules.filter((r): r is string => typeof r === \"string\")\n : undefined;\n const scope = resolveTargetConversation(body, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const dir = join(workingDir, scope.conversationId);\n try {\n const existing = loadConversationAutoReplyConfig(dir);\n saveConversationAutoReplyConfig(dir, {\n enabled,\n rules: rules ?? existing.rules,\n });\n jsonRes(res, 200, { ok: true });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nfunction serveConversationSessionLink(\n res: ServerResponse,\n body: Record<string, unknown>,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveTargetConversation(body, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n if (!services.sessionViewTokenStore) {\n jsonRes(res, 503, { error: \"Session view token store not available\" });\n return;\n }\n if (!services.portalBaseUrl) {\n jsonRes(res, 503, {\n error: \"Portal URL not configured. Set MIKAN_LINK_URL to enable link generation.\",\n });\n return;\n }\n\n const sessionFile = resolveExistingSessionFile(\n workingDir,\n scope.conversationId,\n scope.conversationId,\n );\n if (!sessionFile) {\n jsonRes(res, 404, { error: \"No session file found for this conversation\" });\n return;\n }\n\n try {\n const { token: viewToken } = services.sessionViewTokenStore.create(\n token.platform,\n token.platformUserId,\n scope.conversationId,\n scope.conversationId,\n sessionFile,\n token.platformUserName,\n );\n const url = `${services.portalBaseUrl}/session?token=${encodeURIComponent(viewToken)}`;\n jsonRes(res, 200, { ok: true, url });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nfunction serveConversationLoginLink(\n res: ServerResponse,\n body: Record<string, unknown>,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveTargetConversation(body, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n if (!services.portalBaseUrl) {\n jsonRes(res, 503, { error: \"Portal URL not configured.\" });\n return;\n }\n if (!services.sandbox) {\n jsonRes(res, 503, { error: \"Sandbox config not available.\" });\n return;\n }\n const sharedName = typeof body.sharedVault === \"string\" ? body.sharedVault.trim() : \"\";\n let vaultId: string;\n if (sharedName) {\n const key = sharedVaultKey(sharedName);\n if (!key) {\n jsonRes(res, 400, { error: \"Invalid shared vault name\" });\n return;\n }\n vaultId = key;\n } else {\n try {\n vaultId = resolveActorVaultKey(services.sandbox, token.platformUserId, scope.conversationId);\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n return;\n }\n }\n try {\n const { token: linkToken } = services.linkTokenStore.create(\n token.platform,\n token.platformUserId,\n scope.conversationId,\n vaultId,\n \"\",\n );\n const url = `${services.portalBaseUrl}/link?token=${encodeURIComponent(linkToken)}`;\n jsonRes(res, 200, { ok: true, url, vaultId });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nfunction serveGlobalModelUpdate(res: ServerResponse, body: Record<string, unknown>): void {\n const provider = typeof body.provider === \"string\" ? body.provider.trim() : \"\";\n const model = typeof body.model === \"string\" ? body.model.trim() : \"\";\n const thinkingLevel =\n typeof body.thinkingLevel === \"string\" && VALID_THINKING_LEVELS.has(body.thinkingLevel)\n ? (body.thinkingLevel as AgentConfig[\"thinkingLevel\"])\n : undefined;\n\n if (!provider || !model) {\n jsonRes(res, 400, { error: \"Missing provider or model\" });\n return;\n }\n\n try {\n saveAgentConfig({\n provider,\n model,\n ...(thinkingLevel ? { thinkingLevel } : {}),\n });\n jsonRes(res, 200, { ok: true });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\nfunction serveGlobalSandboxUpdate(res: ServerResponse, body: Record<string, unknown>): void {\n const cpus = typeof body.cpus === \"string\" ? body.cpus.trim() : \"\";\n const memory = typeof body.memory === \"string\" ? body.memory.trim() : \"\";\n const boostCpus = typeof body.boostCpus === \"string\" ? body.boostCpus.trim() : \"\";\n const boostMemory = typeof body.boostMemory === \"string\" ? body.boostMemory.trim() : \"\";\n const workspaceMount = body.workspaceMount;\n const validMount = workspaceMount === \"private\" || workspaceMount === \"full\";\n\n const update: Partial<AgentConfig> = {};\n if (cpus) update.sandboxCpus = cpus;\n if (memory) update.sandboxMemory = memory;\n if (boostCpus) update.sandboxBoostCpus = boostCpus;\n if (boostMemory) update.sandboxBoostMemory = boostMemory;\n if (validMount) update.sandboxImageWorkspaceMount = workspaceMount as \"private\" | \"full\";\n\n if (Object.keys(update).length === 0) {\n jsonRes(res, 400, { error: \"No valid sandbox fields provided\" });\n return;\n }\n\n try {\n saveAgentConfig(update);\n jsonRes(res, 200, { ok: true });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\n// โโ Workspace โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nconst WORKSPACE_TREE_MAX_DEPTH = 4;\nconst WORKSPACE_TREE_MAX_ENTRIES = 800;\nconst PREVIEW_FILE_MAX_BYTES = 256 * 1024;\n\nconst WORKSPACE_TOP_FILES = new Set([\"auto-reply\", \"auto-reply.disabled\"]);\nconst WORKSPACE_TOP_DIRS = new Set([\"scratch\"]);\n\n/**\n * Limit what the admin UI can browse under a conversation directory.\n * Allowed: top-level \"scratch/\" subtree, and the two auto-reply marker files.\n */\nfunction isWorkspacePathAllowed(rel: string): boolean {\n if (rel === \"\") return true;\n const segments = rel.split(\"/\").filter(Boolean);\n if (segments.length === 0) return true;\n const first = segments[0];\n if (segments.length === 1) {\n return WORKSPACE_TOP_DIRS.has(first) || WORKSPACE_TOP_FILES.has(first);\n }\n return WORKSPACE_TOP_DIRS.has(first);\n}\n\nfunction resolveConversationFromQuery(\n url: URL,\n token: AdminToken,\n): { conversationId: string; error?: string } {\n const requested = (url.searchParams.get(\"conversationId\") ?? \"\").trim();\n if (!requested) return { conversationId: token.conversationId };\n if (requested === token.conversationId) return { conversationId: requested };\n if (requested.includes(\"/\") || requested.includes(\"..\")) {\n return { conversationId: requested, error: \"Invalid conversationId.\" };\n }\n return { conversationId: requested };\n}\n\ninterface SafePathResult {\n absolute: string;\n error?: string;\n}\n\nfunction safeJoinUnderRoot(rootDir: string, relative: string): SafePathResult {\n if (relative.startsWith(\"/\") || relative.includes(\"\\0\")) {\n return { absolute: \"\", error: \"Invalid path\" };\n }\n if (relative.split(/[\\\\/]+/).some((part) => part === \"..\" || part === \"\")) {\n if (relative !== \"\") return { absolute: \"\", error: \"Invalid path\" };\n }\n const target = pathResolve(rootDir, relative);\n const rootAbs = pathResolve(rootDir);\n if (target !== rootAbs && !target.startsWith(rootAbs + pathSep)) {\n return { absolute: \"\", error: \"Path escapes conversation directory\" };\n }\n return { absolute: target };\n}\n\ninterface TreeNode {\n name: string;\n path: string;\n type: \"dir\" | \"file\";\n size?: number;\n mtimeMs?: number;\n children?: TreeNode[];\n truncated?: boolean;\n}\n\nfunction buildTree(startDir: string, relPrefix: string): TreeNode | null {\n let counter = { value: 0 };\n const walk = (dir: string, rel: string, depth: number): TreeNode | null => {\n if (counter.value >= WORKSPACE_TREE_MAX_ENTRIES) return null;\n let stats;\n try {\n stats = statSync(dir);\n } catch {\n return null;\n }\n const name = rel === \"\" ? \".\" : (rel.split(/[\\\\/]/).pop() ?? rel);\n if (!stats.isDirectory()) {\n counter.value += 1;\n return {\n name,\n path: rel,\n type: \"file\",\n size: stats.size,\n mtimeMs: stats.mtimeMs,\n };\n }\n counter.value += 1;\n if (depth >= WORKSPACE_TREE_MAX_DEPTH) {\n return { name, path: rel, type: \"dir\", truncated: true };\n }\n let entries;\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return { name, path: rel, type: \"dir\" };\n }\n const children: TreeNode[] = [];\n let truncated = false;\n for (const entry of entries.toSorted((a, b) => {\n if (a.isDirectory() !== b.isDirectory()) return a.isDirectory() ? -1 : 1;\n return a.name.localeCompare(b.name);\n })) {\n const childRel = rel === \"\" ? entry.name : `${rel}/${entry.name}`;\n if (!isWorkspacePathAllowed(childRel)) continue;\n if (counter.value >= WORKSPACE_TREE_MAX_ENTRIES) {\n truncated = true;\n break;\n }\n const node = walk(join(dir, entry.name), childRel, depth + 1);\n if (node) children.push(node);\n }\n return {\n name,\n path: rel,\n type: \"dir\",\n children,\n ...(truncated ? { truncated: true } : {}),\n };\n };\n const node = walk(startDir, relPrefix, 0);\n return node;\n}\n\nfunction serveWorkspaceTree(\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveConversationFromQuery(url, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const convDir = join(workingDir, scope.conversationId);\n if (!existsSync(convDir)) {\n jsonRes(res, 200, { conversationId: scope.conversationId, tree: null });\n return;\n }\n const requestedSub = (url.searchParams.get(\"path\") ?? \"\").trim();\n if (!isWorkspacePathAllowed(requestedSub)) {\n jsonRes(res, 403, { error: \"Workspace path is not exposed\" });\n return;\n }\n const startSafe = safeJoinUnderRoot(convDir, requestedSub);\n if (startSafe.error) {\n jsonRes(res, 400, { error: startSafe.error });\n return;\n }\n const tree = buildTree(startSafe.absolute, requestedSub);\n jsonRes(res, 200, {\n conversationId: scope.conversationId,\n root: requestedSub || \".\",\n tree,\n });\n}\n\nconst BINARY_PROBE_BYTES = 4096;\n\nfunction looksTextual(buf: Buffer): boolean {\n const limit = Math.min(buf.length, BINARY_PROBE_BYTES);\n for (let i = 0; i < limit; i++) {\n const byte = buf[i];\n if (byte === 0) return false;\n if (byte < 9) return false;\n if (byte === 11 || byte === 12) return false;\n if (byte > 13 && byte < 32) return false;\n }\n return true;\n}\n\nfunction servePreviewFile(\n res: ServerResponse,\n absolutePath: string,\n metadata: Record<string, unknown>,\n notFoundMessage: string,\n): void {\n let stats;\n try {\n stats = statSync(absolutePath);\n } catch {\n jsonRes(res, 404, { error: notFoundMessage });\n return;\n }\n if (!stats.isFile()) {\n jsonRes(res, 400, { error: \"Not a file\" });\n return;\n }\n if (stats.size > PREVIEW_FILE_MAX_BYTES) {\n jsonRes(res, 413, {\n error: \"File too large to preview\",\n size: stats.size,\n limit: PREVIEW_FILE_MAX_BYTES,\n });\n return;\n }\n let buf: Buffer;\n try {\n buf = readFileSync(absolutePath);\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n return;\n }\n if (!looksTextual(buf)) {\n jsonRes(res, 200, {\n ...metadata,\n size: stats.size,\n mtimeMs: stats.mtimeMs,\n binary: true,\n content: null,\n });\n return;\n }\n jsonRes(res, 200, {\n ...metadata,\n size: stats.size,\n mtimeMs: stats.mtimeMs,\n binary: false,\n content: buf.toString(\"utf-8\"),\n });\n}\n\nfunction serveWorkspaceFile(\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveConversationFromQuery(url, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const requestedPath = (url.searchParams.get(\"path\") ?? \"\").trim();\n if (!requestedPath) {\n jsonRes(res, 400, { error: \"Missing path\" });\n return;\n }\n if (!isWorkspacePathAllowed(requestedPath)) {\n jsonRes(res, 403, { error: \"Workspace path is not exposed\" });\n return;\n }\n const convDir = join(workingDir, scope.conversationId);\n const safe = safeJoinUnderRoot(convDir, requestedPath);\n if (safe.error) {\n jsonRes(res, 400, { error: safe.error });\n return;\n }\n servePreviewFile(res, safe.absolute, { path: requestedPath }, \"File not found\");\n}\n\n// โโ Skills โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\ninterface SkillEntry {\n name: string;\n description: string;\n source: \"global\" | \"conversation\";\n path: string;\n directory: string;\n}\n\nfunction parseSkillFrontmatter(filePath: string): { name?: string; description?: string } {\n let text: string;\n try {\n text = readFileSync(filePath, \"utf-8\");\n } catch {\n return {};\n }\n if (!text.startsWith(\"---\")) return {};\n const end = text.indexOf(\"\\n---\", 3);\n if (end < 0) return {};\n const block = text.slice(3, end);\n const out: { name?: string; description?: string } = {};\n for (const line of block.split(\"\\n\")) {\n const colon = line.indexOf(\":\");\n if (colon < 0) continue;\n const key = line.slice(0, colon).trim().toLowerCase();\n let value = line.slice(colon + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n if (key === \"name\") out.name = value;\n if (key === \"description\") out.description = value;\n }\n return out;\n}\n\nfunction readSkillsFromDir(skillsDir: string, source: SkillEntry[\"source\"]): SkillEntry[] {\n if (!existsSync(skillsDir)) return [];\n const out: SkillEntry[] = [];\n let entries;\n try {\n entries = readdirSync(skillsDir, { withFileTypes: true });\n } catch {\n return [];\n }\n for (const entry of entries) {\n if (!entry.isDirectory() || entry.name.startsWith(\".\")) continue;\n const skillMd = join(skillsDir, entry.name, \"SKILL.md\");\n if (!existsSync(skillMd)) continue;\n const meta = parseSkillFrontmatter(skillMd);\n out.push({\n name: meta.name ?? entry.name,\n description: meta.description ?? \"\",\n source,\n path: skillMd,\n directory: entry.name,\n });\n }\n return out.toSorted((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction serveSkillsList(\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveConversationFromQuery(url, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const global = readSkillsFromDir(join(workingDir, \"skills\"), \"global\");\n const conversation = readSkillsFromDir(\n join(workingDir, scope.conversationId, \"skills\"),\n \"conversation\",\n );\n jsonRes(res, 200, {\n conversationId: scope.conversationId,\n skills: [...global, ...conversation],\n });\n}\n\nfunction serveSkillFile(\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveConversationFromQuery(url, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n\n const source = (url.searchParams.get(\"source\") ?? \"\").trim();\n const directory = (url.searchParams.get(\"directory\") ?? \"\").trim();\n if (source !== \"global\" && source !== \"conversation\") {\n jsonRes(res, 400, { error: \"Invalid skill source\" });\n return;\n }\n if (\n !directory ||\n directory.includes(\"/\") ||\n directory.includes(\"\\\\\") ||\n directory.includes(\"..\")\n ) {\n jsonRes(res, 400, { error: \"Invalid skill directory\" });\n return;\n }\n\n const skillsRoot =\n source === \"global\"\n ? join(workingDir, \"skills\")\n : join(workingDir, scope.conversationId, \"skills\");\n const safe = safeJoinUnderRoot(skillsRoot, join(directory, \"SKILL.md\"));\n if (safe.error) {\n jsonRes(res, 400, { error: safe.error });\n return;\n }\n\n servePreviewFile(res, safe.absolute, { source, directory }, \"Skill file not found\");\n}\n\n// โโ Events โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nconst EVENTS_FILE_MAX_BYTES = 64 * 1024;\n\ninterface EventSummary {\n name: string;\n size: number;\n mtimeMs: number;\n type: string | null;\n platform: string | null;\n conversationId: string | null;\n text: string | null;\n at: string | null;\n schedule: string | null;\n timezone: string | null;\n}\n\nfunction listAllEvents(workingDir: string): EventSummary[] {\n const dir = join(workingDir, \"events\");\n if (!existsSync(dir)) return [];\n let entries;\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return [];\n }\n return entries\n .filter((e) => e.isFile() && e.name.endsWith(\".json\"))\n .map((e): EventSummary | null => {\n const filePath = join(dir, e.name);\n let stats;\n try {\n stats = statSync(filePath);\n } catch {\n return null;\n }\n let parsed: unknown = null;\n try {\n parsed = JSON.parse(readFileSync(filePath, \"utf-8\"));\n } catch {\n // Keep entry; just omit parsed fields.\n }\n const meta = parsed && typeof parsed === \"object\" ? (parsed as Record<string, unknown>) : {};\n // events.ts accepts `channelId` as a legacy alias for `conversationId`.\n const conversationId =\n typeof meta.conversationId === \"string\"\n ? meta.conversationId\n : typeof meta.channelId === \"string\"\n ? meta.channelId\n : null;\n return {\n name: e.name,\n size: stats.size,\n mtimeMs: stats.mtimeMs,\n type: typeof meta.type === \"string\" ? meta.type : null,\n platform: typeof meta.platform === \"string\" ? meta.platform : null,\n conversationId,\n text: typeof meta.text === \"string\" ? meta.text : null,\n at: typeof meta.at === \"string\" ? meta.at : null,\n schedule: typeof meta.schedule === \"string\" ? meta.schedule : null,\n timezone: typeof meta.timezone === \"string\" ? meta.timezone : null,\n };\n })\n .filter((e): e is EventSummary => e !== null)\n .toSorted((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction serveEventsList(res: ServerResponse, services: AdminServices): void {\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n jsonRes(res, 200, { events: listAllEvents(workingDir) });\n}\n\n/** Per-conversation listing โ filter all events by conversationId match. */\nfunction serveConversationEventsList(\n res: ServerResponse,\n url: URL,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveConversationFromQuery(url, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const events = listAllEvents(workingDir).filter((e) => e.conversationId === scope.conversationId);\n jsonRes(res, 200, { conversationId: scope.conversationId, events });\n}\n\nfunction serveEventsFile(res: ServerResponse, url: URL, services: AdminServices): void {\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const name = (url.searchParams.get(\"name\") ?? \"\").trim();\n if (!name || name.includes(\"/\") || name.includes(\"\\\\\") || name.includes(\"..\")) {\n jsonRes(res, 400, { error: \"Invalid name\" });\n return;\n }\n const filePath = join(workingDir, \"events\", name);\n let stats;\n try {\n stats = statSync(filePath);\n } catch {\n jsonRes(res, 404, { error: \"Not found\" });\n return;\n }\n if (!stats.isFile()) {\n jsonRes(res, 400, { error: \"Not a file\" });\n return;\n }\n if (stats.size > EVENTS_FILE_MAX_BYTES) {\n jsonRes(res, 413, { error: \"File too large\" });\n return;\n }\n let raw: string;\n try {\n raw = readFileSync(filePath, \"utf-8\");\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n return;\n }\n jsonRes(res, 200, { name, content: raw });\n}\n\n/** Delete a single event file scoped to the caller's conversation. */\nfunction serveConversationEventDelete(\n res: ServerResponse,\n body: Record<string, unknown>,\n services: AdminServices,\n token: AdminToken,\n): void {\n const scope = resolveTargetConversation(body, token);\n if (scope.error) {\n jsonRes(res, 403, { error: scope.error });\n return;\n }\n const name = typeof body.name === \"string\" ? body.name.trim() : \"\";\n if (!name || name.includes(\"/\") || name.includes(\"\\\\\") || name.includes(\"..\")) {\n jsonRes(res, 400, { error: \"Invalid name\" });\n return;\n }\n const workingDir = requireAdminWorkingDir(res, services);\n if (!workingDir) return;\n const filePath = join(workingDir, \"events\", name);\n let raw: string;\n try {\n raw = readFileSync(filePath, \"utf-8\");\n } catch {\n jsonRes(res, 404, { error: \"Event not found\" });\n return;\n }\n let parsed: Record<string, unknown> = {};\n try {\n const j = JSON.parse(raw);\n if (j && typeof j === \"object\") parsed = j as Record<string, unknown>;\n } catch {\n // Malformed events cannot be associated with a conversation below.\n }\n const eventConvId =\n typeof parsed.conversationId === \"string\"\n ? parsed.conversationId\n : typeof parsed.channelId === \"string\"\n ? parsed.channelId\n : null;\n if (eventConvId !== scope.conversationId) {\n jsonRes(res, 403, { error: \"Event does not belong to this conversation.\" });\n return;\n }\n try {\n rmSync(filePath, { force: true });\n jsonRes(res, 200, { ok: true });\n } catch (err) {\n jsonRes(res, 500, { error: err instanceof Error ? err.message : String(err) });\n }\n}\n\n// โโ Utilities โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nfunction jsonRes(res: ServerResponse, status: number, body: unknown): void {\n res.writeHead(status, {\n \"Content-Type\": \"application/json; charset=utf-8\",\n \"Cache-Control\": \"no-store\",\n });\n res.end(JSON.stringify(body));\n}\n\nasync function readJsonBody(\n req: IncomingMessage,\n res: ServerResponse,\n callback: (body: Record<string, unknown>) => void,\n): Promise<void> {\n let data = \"\";\n let tooLarge = false;\n\n await new Promise<void>((resolve) => {\n req.on(\"data\", (chunk: Buffer) => {\n if (tooLarge) return;\n data += chunk.toString();\n if (data.length > 32 * 1024) {\n tooLarge = true;\n res.writeHead(413);\n res.end();\n req.destroy();\n }\n });\n req.on(\"end\", resolve);\n req.on(\"error\", resolve);\n });\n\n if (tooLarge) return;\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(data) as Record<string, unknown>;\n } catch {\n jsonRes(res, 400, { error: \"Invalid JSON\" });\n return;\n }\n\n callback(parsed);\n}\n\nconst esc = escapeHtml;\n\n// โโ HTML โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nfunction renderAdminPage(token: AdminToken): string {\n const userLabel = token.platformUserName ?? token.platformUserId;\n const body = `<nav class=\"tab-nav\" role=\"tablist\" aria-label=\"Admin sections\">\n <button class=\"tab-btn active\" role=\"tab\" aria-selected=\"true\" aria-controls=\"panel-conversation\" data-tab=\"conversation\">Conversation</button>\n <button class=\"tab-btn\" role=\"tab\" aria-selected=\"false\" aria-controls=\"panel-global\" data-tab=\"global\">Global</button>\n </nav>\n\n <div class=\"tab-panel active\" id=\"panel-conversation\">\n <section class=\"card sect\" id=\"sect-settings\" data-section=\"settings\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Settings</p>\n <h2 class=\"card-title\">ๆจกๅ / Thinking / Auto-reply / Workspace mount</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadSettings()\">โป</button>\n </header>\n <div id=\"settings-content\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n </section>\n\n <section class=\"card sect\" id=\"sect-workspace\" data-section=\"workspace\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Workspace</p>\n <h2 class=\"card-title\">ๆชๆก็่ฆฝ (ๅช่ฎ)</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadWorkspace()\">โป</button>\n </header>\n <div class=\"workspace-split\">\n <div id=\"workspace-tree\" class=\"workspace-tree\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n <div id=\"workspace-preview\" class=\"workspace-preview\"><div class=\"placeholder-msg\">Click a file to preview</div></div>\n </div>\n </section>\n\n <section class=\"card sect\" id=\"sect-skills\" data-section=\"skills\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Skills</p>\n <h2 class=\"card-title\">ๅฏ็จ็ skills</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadSkills()\">โป</button>\n </header>\n <div class=\"workspace-split\">\n <div id=\"skills-content\" class=\"workspace-tree\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n <div id=\"skills-preview\" class=\"workspace-preview\"><div class=\"placeholder-msg\">Click a skill to preview SKILL.md</div></div>\n </div>\n </section>\n\n <section class=\"card sect\" id=\"sect-vault\" data-section=\"vault\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Vault</p>\n <h2 class=\"card-title\">่ฉฒๅฐ่ฉฑ็ๆ่ญ</h2>\n </div>\n <button class=\"primary-action-btn\" onclick=\"openLogin()\">Open login form</button>\n </header>\n <div id=\"vault-link-result\" class=\"link-result\" style=\"display:none\"></div>\n <iframe id=\"login-frame\" class=\"portal-frame\" title=\"Login\" style=\"display:none\"></iframe>\n </section>\n\n <section class=\"card sect\" id=\"sect-events\" data-section=\"events\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Events</p>\n <h2 class=\"card-title\">้่ฏๆญคๅฐ่ฉฑ็ events</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadConversationEvents()\">โป</button>\n </header>\n <div id=\"events-content\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n </section>\n\n <section class=\"card sect\" id=\"sect-session\" data-section=\"session\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Session View</p>\n <h2 class=\"card-title\">ๅฐ่ฉฑๆญทๅฒๆชข่ฆ</h2>\n </div>\n <button class=\"primary-action-btn\" onclick=\"openSessionView()\">Open session view</button>\n </header>\n <div id=\"session-link-result\" class=\"link-result\" style=\"display:none\"></div>\n <iframe id=\"session-frame\" class=\"portal-frame\" title=\"Session View\" style=\"display:none\"></iframe>\n </section>\n </div>\n\n <div class=\"tab-panel\" id=\"panel-global\">\n <section class=\"card sect\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">All Conversations</p>\n <h2 class=\"card-title\">ๆๆๅฐ่ฉฑ</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadAllConversations()\">โป</button>\n </header>\n <div id=\"all-conv-content\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n </section>\n\n <section class=\"card sect\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Global Settings</p>\n <h2 class=\"card-title\">ๅ
จๅ้ ่จญ</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadGlobalSettings()\">โป</button>\n </header>\n <div id=\"global-settings-content\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n </section>\n\n <section class=\"card sect\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Global Skills</p>\n <h2 class=\"card-title\">ๅ
จๅ skills</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadGlobalSkills()\">โป</button>\n </header>\n <div id=\"global-skills-content\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n </section>\n\n <section class=\"card sect\">\n <header class=\"sect-head\">\n <div>\n <p class=\"eyebrow\">Global Events</p>\n <h2 class=\"card-title\">ๅ
จๅ events.json</h2>\n </div>\n <button class=\"refresh-btn\" onclick=\"loadEvents()\">โป</button>\n </header>\n <div id=\"global-events-content\"><div class=\"loading-msg\">Loadingโฆ</div></div>\n </section>\n </div>`;\n\n const script = `\n const adminToken = ${JSON.stringify(token.token)};\n const defaultConversationId = ${JSON.stringify(token.conversationId)};\n let activeConversationId = defaultConversationId;\n let availableModels = [];\n let modelsLoaded = false;\n\n // โโ Helpers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n function escHtml(str) {\n return String(str).replace(/[&<>\"']/g, (c) => (\n {'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]\n ));\n }\n function escAttr(str) {\n return String(str).replace(/[\"'&<>]/g, (c) => (\n {'\"':'"',\"'\":''','&':'&','<':'<','>':'>'}[c]\n ));\n }\n async function copyToClipboard(text) {\n try { await navigator.clipboard.writeText(text); } catch { prompt('Copy this link:', text); }\n }\n async function apiGet(path) {\n const url = path + (path.includes('?') ? '&' : '?') + 'token=' + encodeURIComponent(adminToken);\n const r = await fetch(url);\n const data = await r.json();\n if (!r.ok) throw new Error(data.error || ('HTTP ' + r.status));\n return data;\n }\n async function apiPost(path, body) {\n const r = await fetch(path, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ token: adminToken, ...body }),\n });\n const data = await r.json();\n if (!r.ok) throw new Error(data.error || ('HTTP ' + r.status));\n return data;\n }\n async function loadModels() {\n try {\n const data = await apiGet('/admin/api/models');\n availableModels = Array.isArray(data.models) ? data.models : [];\n } catch (err) {\n console.error('Failed to load models', err);\n availableModels = [];\n } finally {\n modelsLoaded = true;\n }\n }\n function modelRef(provider, model) {\n return provider && model ? provider + '/' + model : '';\n }\n function parseModelRef(value) {\n const slash = value.indexOf('/');\n if (slash <= 0 || slash === value.length - 1) return { provider: '', model: '' };\n return { provider: value.slice(0, slash), model: value.slice(slash + 1) };\n }\n function renderModelOptions(currentProvider, currentModel) {\n const current = modelRef(currentProvider, currentModel);\n const seen = new Set();\n const options = [];\n if (current) {\n seen.add(current);\n options.push('<option value=\"' + escAttr(current) + '\">' + escHtml(current + ' (current)') + '</option>');\n }\n for (const model of availableModels) {\n const ref = modelRef(model.provider, model.id);\n if (!ref || seen.has(ref)) continue;\n seen.add(ref);\n const details = [model.name && model.name !== model.id ? model.name : '', model.reasoning ? 'thinking' : '', Array.isArray(model.input) && model.input.includes('image') ? 'image' : '']\n .filter(Boolean)\n .join(' ยท ');\n options.push('<option value=\"' + escAttr(ref) + '\">' + escHtml(details ? ref + ' โ ' + details : ref) + '</option>');\n }\n if (options.length === 0) {\n return '<option value=\"\">No available models</option>';\n }\n return options.join('');\n }\n\n // โโ Tab switching โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n const tabBtns = document.querySelectorAll('.tab-btn');\n const tabPanels = document.querySelectorAll('.tab-panel');\n\n function switchTab(tabId) {\n tabBtns.forEach((btn) => {\n const active = btn.dataset.tab === tabId;\n btn.classList.toggle('active', active);\n btn.setAttribute('aria-selected', active ? 'true' : 'false');\n });\n tabPanels.forEach((panel) => panel.classList.toggle('active', panel.id === 'panel-' + tabId));\n if (tabId === 'global') initGlobal();\n }\n tabBtns.forEach((btn) => btn.addEventListener('click', () => switchTab(btn.dataset.tab)));\n\n // โโ Conversation switcher โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n async function initConvSwitcher() {\n const sel = document.getElementById('conv-switcher');\n try {\n const data = await apiGet('/admin/api/conversations');\n sel.innerHTML = data.conversations.map((c) => {\n const label = (c.label || c.conversationId) + (c.running ? ' (running)' : '');\n const selected = c.conversationId === defaultConversationId ? ' selected' : '';\n return '<option value=\"' + escAttr(c.conversationId) + '\"' + selected + '>' + escHtml(label) + '</option>';\n }).join('');\n sel.addEventListener('change', () => setActiveConversation(sel.value));\n } catch (err) {\n console.error('Failed to load conversations', err);\n }\n }\n\n function setActiveConversation(id) {\n activeConversationId = id;\n const sel = document.getElementById('conv-switcher');\n if (sel && sel.value !== id) sel.value = id;\n // Reset all conversation sections.\n loadSettings();\n loadWorkspace();\n loadSkills();\n loadConversationEvents();\n openLogin(true);\n openSessionView(true);\n }\n\n // โโ Settings โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n async function loadSettings() {\n const container = document.getElementById('settings-content');\n container.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n if (!modelsLoaded) await loadModels();\n try {\n const data = await apiGet('/admin/api/conversation-state?conversationId=' + encodeURIComponent(activeConversationId));\n container.innerHTML = renderSettings(data);\n } catch (err) {\n container.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n function renderSettings(data) {\n const thinking = ['off','minimal','low','medium','high','xhigh'];\n const thinkingOpts = thinking.map((t) =>\n '<option value=\"' + t + '\"' + (data.thinkingLevel === t ? ' selected' : '') + '>' + t + '</option>'\n ).join('');\n const mounts = ['private','full'];\n const mountOpts = mounts.map((m) =>\n '<option value=\"' + m + '\"' + (data.sandboxImageWorkspaceMount === m ? ' selected' : '') + '>' + m + '</option>'\n ).join('');\n const rulesText = (data.autoReplyRules || []).join('\\\\n');\n return [\n '<div class=\"config-grid\">',\n '<div class=\"config-block\">',\n '<h3 class=\"card-subtitle\">Model</h3>',\n '<div class=\"config-row config-row-stack\"><label>Model</label><select id=\"m-model-ref\">' + renderModelOptions(data.provider, data.model) + '</select></div>',\n '<div class=\"config-row\"><label>Thinking</label><select id=\"m-thinking\">' + thinkingOpts + '</select></div>',\n '<button class=\"primary-action-btn\" onclick=\"saveModel(this)\">Save model</button>',\n '<div id=\"model-save-result\" class=\"inline-result\" style=\"display:none\"></div>',\n '</div>',\n '<div class=\"config-block\">',\n '<h3 class=\"card-subtitle\">Auto-reply</h3>',\n '<div class=\"config-row\"><label>Enabled</label><label class=\"toggle\"><input type=\"checkbox\" id=\"a-enabled\"' + (data.autoReplyEnabled ? ' checked' : '') + '> on</label></div>',\n '<div class=\"config-row config-row-stack\"><label>Rules</label><textarea id=\"a-rules\" rows=\"5\" placeholder=\"ไธ่กไธๆข่ฆๅ\">' + escHtml(rulesText) + '</textarea></div>',\n '<button class=\"primary-action-btn\" onclick=\"saveAutoReply(this)\">Save auto-reply</button>',\n '<div id=\"auto-save-result\" class=\"inline-result\" style=\"display:none\"></div>',\n '</div>',\n '<div class=\"config-block\">',\n '<h3 class=\"card-subtitle\">Workspace mount</h3>',\n '<div class=\"config-row\"><label>Mode</label><select id=\"m-mount\">' + mountOpts + '</select></div>',\n '<button class=\"primary-action-btn\" onclick=\"saveMount(this)\">Save mount</button>',\n '<div id=\"mount-save-result\" class=\"inline-result\" style=\"display:none\"></div>',\n '</div>',\n '</div>',\n ].join('');\n }\n\n async function saveModel(btn) {\n const selectedModel = parseModelRef(document.getElementById('m-model-ref').value.trim());\n const provider = selectedModel.provider;\n const model = selectedModel.model;\n const thinkingLevel = document.getElementById('m-thinking').value;\n const result = document.getElementById('model-save-result');\n if (!provider || !model) {\n result.style.display = 'block'; result.className = 'inline-result err';\n result.textContent = 'Provider and model are required';\n return;\n }\n btn.disabled = true; btn.textContent = 'Savingโฆ'; result.style.display = 'none';\n try {\n const data = await apiPost('/admin/api/conversations/model', {\n conversationId: activeConversationId, provider, model, thinkingLevel,\n });\n result.style.display = 'block'; result.className = 'inline-result ok';\n result.textContent = data.runtimeSwitched === false\n ? 'Saved โ running session pinned; new model applies on next start.'\n : 'Saved โ';\n } catch (err) {\n result.style.display = 'block'; result.className = 'inline-result err';\n result.textContent = err.message;\n } finally {\n btn.disabled = false; btn.textContent = 'Save model';\n }\n }\n\n async function saveAutoReply(btn) {\n const enabled = document.getElementById('a-enabled').checked;\n const rules = document.getElementById('a-rules').value.split('\\\\n').map((s) => s.trim()).filter(Boolean);\n const result = document.getElementById('auto-save-result');\n btn.disabled = true; btn.textContent = 'Savingโฆ'; result.style.display = 'none';\n try {\n await apiPost('/admin/api/conversations/auto-reply', {\n conversationId: activeConversationId, enabled, rules,\n });\n result.style.display = 'block'; result.className = 'inline-result ok'; result.textContent = 'Saved โ';\n } catch (err) {\n result.style.display = 'block'; result.className = 'inline-result err'; result.textContent = err.message;\n } finally {\n btn.disabled = false; btn.textContent = 'Save auto-reply';\n }\n }\n\n async function saveMount(btn) {\n const workspaceMount = document.getElementById('m-mount').value;\n const result = document.getElementById('mount-save-result');\n btn.disabled = true; btn.textContent = 'Savingโฆ'; result.style.display = 'none';\n try {\n await apiPost('/admin/api/conversations/sandbox', {\n conversationId: activeConversationId, workspaceMount,\n });\n result.style.display = 'block'; result.className = 'inline-result ok'; result.textContent = 'Saved โ';\n } catch (err) {\n result.style.display = 'block'; result.className = 'inline-result err'; result.textContent = err.message;\n } finally {\n btn.disabled = false; btn.textContent = 'Save mount';\n }\n }\n\n // โโ Workspace โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n async function loadWorkspace() {\n const treeEl = document.getElementById('workspace-tree');\n const previewEl = document.getElementById('workspace-preview');\n treeEl.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n previewEl.innerHTML = '<div class=\"placeholder-msg\">Click a file to preview</div>';\n try {\n const data = await apiGet('/admin/api/workspace/tree?conversationId=' + encodeURIComponent(activeConversationId));\n if (!data.tree) {\n treeEl.innerHTML = '<div class=\"empty-state\">No files</div>';\n return;\n }\n treeEl.innerHTML = '<ul class=\"tree-root\">' + renderTreeChildren(data.tree) + '</ul>';\n } catch (err) {\n treeEl.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n function renderTreeChildren(node) {\n if (node.type === 'file') {\n return '<li><button class=\"tree-file\" onclick=\"previewFile(\\\\'' + escAttr(node.path) + '\\\\')\">' + escHtml(node.name) + '</button></li>';\n }\n if (!node.children || node.children.length === 0) {\n return '<li><span class=\"tree-dir empty\">' + escHtml(node.name || '.') + '/</span></li>';\n }\n const inner = node.children.map((c) =>\n c.type === 'file'\n ? '<li><button class=\"tree-file\" onclick=\"previewFile(\\\\'' + escAttr(c.path) + '\\\\')\">' + escHtml(c.name) + '</button></li>'\n : '<li><details open><summary class=\"tree-dir\">' + escHtml(c.name) + '/</summary><ul>' + renderTreeChildren(c) + '</ul></details></li>'\n ).join('');\n return inner;\n }\n\n function renderPreviewFileResult(previewEl, label, data) {\n if (data.binary) {\n previewEl.innerHTML = '<div class=\"preview-meta\">' + escHtml(label) + ' ยท ' + data.size + ' bytes ยท binary</div><div class=\"placeholder-msg\">Binary file โ preview not available</div>';\n return;\n }\n previewEl.innerHTML =\n '<div class=\"preview-meta\">' + escHtml(label) + ' ยท ' + data.size + ' bytes</div>' +\n '<pre class=\"preview-body\">' + escHtml(data.content || '') + '</pre>';\n }\n\n async function previewFile(path) {\n const previewEl = document.getElementById('workspace-preview');\n previewEl.innerHTML = '<div class=\"loading-msg\">Loading ' + escHtml(path) + 'โฆ</div>';\n try {\n const data = await apiGet('/admin/api/workspace/file?conversationId=' + encodeURIComponent(activeConversationId) + '&path=' + encodeURIComponent(path));\n renderPreviewFileResult(previewEl, path, data);\n } catch (err) {\n previewEl.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n // โโ Skills โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n async function loadSkills() {\n const container = document.getElementById('skills-content');\n const previewEl = document.getElementById('skills-preview');\n container.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n if (previewEl) previewEl.innerHTML = '<div class=\"placeholder-msg\">Click a skill to preview SKILL.md</div>';\n try {\n const data = await apiGet('/admin/api/skills?conversationId=' + encodeURIComponent(activeConversationId));\n if (data.skills.length === 0) {\n container.innerHTML = '<div class=\"empty-state\">No skills available</div>';\n return;\n }\n container.innerHTML = '<div class=\"skills-list\">' +\n data.skills.map((s) =>\n '<button class=\"skill-row skill-row-btn\" data-skill-source=\"' + escAttr(s.source) + '\" data-skill-directory=\"' + escAttr(s.directory) + '\" data-skill-name=\"' + escAttr(s.name) + '\">' +\n '<div class=\"skill-name\">' + escHtml(s.name) + '<span class=\"skill-source skill-source-' + s.source + '\">' + s.source + '</span></div>' +\n (s.description ? '<div class=\"skill-desc\">' + escHtml(s.description) + '</div>' : '') +\n '</button>'\n ).join('') + '</div>';\n\n } catch (err) {\n container.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n async function previewSkill(source, directory, name) {\n const previewEl = document.getElementById('skills-preview');\n if (!source || !directory) {\n previewEl.innerHTML = '<div class=\"err-msg\">Missing skill source or directory</div>';\n return;\n }\n previewEl.innerHTML = '<div class=\"loading-msg\">Loading ' + escHtml(name || directory) + 'โฆ</div>';\n try {\n const data = await apiGet('/admin/api/skills/file?conversationId=' + encodeURIComponent(activeConversationId) + '&source=' + encodeURIComponent(source) + '&directory=' + encodeURIComponent(directory));\n renderPreviewFileResult(previewEl, source + '/' + directory + '/SKILL.md', data);\n } catch (err) {\n previewEl.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n document.getElementById('skills-content').addEventListener('click', (event) => {\n const btn = event.target.closest('[data-skill-source]');\n if (!btn) return;\n previewSkill(btn.dataset.skillSource, btn.dataset.skillDirectory, btn.dataset.skillName);\n });\n\n // โโ Vault (Login link) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n async function openLogin(silent) {\n const result = document.getElementById('vault-link-result');\n const frame = document.getElementById('login-frame');\n if (silent) { frame.removeAttribute('src'); frame.style.display = 'none'; result.style.display = 'none'; return; }\n result.style.display = 'block'; result.className = 'link-result loading'; result.textContent = 'Generating linkโฆ';\n try {\n const data = await apiPost('/admin/api/conversations/login-link', { conversationId: activeConversationId });\n result.className = 'link-result ok';\n result.innerHTML =\n '<span class=\"link-vault\">vault: <code>' + escHtml(data.vaultId) + '</code></span>' +\n '<a href=\"' + escAttr(data.url) + '\" target=\"_blank\" rel=\"noopener\">' + escHtml(data.url) + '</a>' +\n '<button class=\"copy-link-btn\" onclick=\"copyToClipboard(' + JSON.stringify(data.url) + ')\">Copy</button>';\n frame.src = data.url; frame.style.display = 'block';\n } catch (err) {\n result.className = 'link-result err'; result.textContent = err.message;\n frame.removeAttribute('src'); frame.style.display = 'none';\n }\n }\n\n // โโ Session View โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n async function openSessionView(silent) {\n const result = document.getElementById('session-link-result');\n const frame = document.getElementById('session-frame');\n if (silent) { frame.removeAttribute('src'); frame.style.display = 'none'; result.style.display = 'none'; return; }\n result.style.display = 'block'; result.className = 'link-result loading'; result.textContent = 'Generating linkโฆ';\n try {\n const data = await apiPost('/admin/api/conversations/session-link', { conversationId: activeConversationId });\n result.className = 'link-result ok';\n result.innerHTML =\n '<a href=\"' + escAttr(data.url) + '\" target=\"_blank\" rel=\"noopener\">' + escHtml(data.url) + '</a>' +\n '<button class=\"copy-link-btn\" onclick=\"copyToClipboard(' + JSON.stringify(data.url) + ')\">Copy</button>';\n frame.src = data.url; frame.style.display = 'block';\n } catch (err) {\n result.className = 'link-result err'; result.textContent = err.message;\n frame.removeAttribute('src'); frame.style.display = 'none';\n }\n }\n\n // โโ Events โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n async function loadConversationEvents() {\n const container = document.getElementById('events-content');\n if (!container) return;\n container.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n try {\n const data = await apiGet('/admin/api/conversations/events?conversationId=' + encodeURIComponent(activeConversationId));\n if (data.events.length === 0) {\n container.innerHTML = '<div class=\"empty-state\">ๆฒๆ้่ฏๆญคๅฐ่ฉฑ็ event</div>';\n return;\n }\n container.innerHTML = '<div class=\"events-list\">' +\n data.events.map((e) => renderEventRow(e, true)).join('') + '</div>';\n } catch (err) {\n container.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n async function loadEvents() {\n const container = document.getElementById('global-events-content');\n if (!container) return;\n container.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n try {\n const data = await apiGet('/admin/api/events');\n if (data.events.length === 0) {\n container.innerHTML = '<div class=\"empty-state\">No events scheduled</div>';\n return;\n }\n container.innerHTML = '<div class=\"events-list\">' +\n data.events.map((e) => renderEventRow(e, false)).join('') + '</div>';\n } catch (err) {\n container.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n function renderEventRow(e, allowDelete) {\n const meta = [e.type, e.platform, e.conversationId, e.schedule || e.at]\n .filter(Boolean).map(escHtml).join(' ยท ');\n const preview = e.text ? '<div class=\"event-text\">' + escHtml(e.text.length > 240 ? e.text.slice(0, 237) + 'โฆ' : e.text) + '</div>' : '';\n const deleteBtn = allowDelete\n ? '<button class=\"event-delete-btn\" onclick=\"deleteEvent(\\\\'' + escAttr(e.name) + '\\\\', this)\">Delete</button>'\n : '';\n return '<div class=\"event-row\">' +\n '<div class=\"event-row-top\">' +\n '<div class=\"event-name\"><code>' + escHtml(e.name) + '</code></div>' +\n deleteBtn +\n '</div>' +\n '<div class=\"event-meta\">' + meta + '</div>' +\n preview +\n '</div>';\n }\n\n async function deleteEvent(name, btn) {\n if (!confirm('Delete event \"' + name + '\"?')) return;\n btn.disabled = true; btn.textContent = 'Deletingโฆ';\n try {\n await apiPost('/admin/api/conversations/events/delete', {\n conversationId: activeConversationId, name,\n });\n await loadConversationEvents();\n } catch (err) {\n btn.disabled = false; btn.textContent = 'Delete';\n alert(err.message);\n }\n }\n\n // โโ Global section โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n let globalLoaded = false;\n function initGlobal() {\n if (globalLoaded) return;\n globalLoaded = true;\n loadAllConversations();\n loadGlobalSettings();\n loadGlobalSkills();\n loadEvents();\n }\n\n async function loadAllConversations() {\n const container = document.getElementById('all-conv-content');\n container.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n try {\n const data = await apiGet('/admin/api/conversations');\n if (data.conversations.length === 0) {\n container.innerHTML = '<div class=\"empty-state\">No conversations found</div>';\n return;\n }\n container.innerHTML = '<div class=\"conv-list\">' + data.conversations.map((c) => {\n const last = c.lastActivityAt ? new Date(c.lastActivityAt).toLocaleString() : 'โ';\n return '<button class=\"conv-row-btn\" onclick=\"setActiveConversation(\\\\'' + escAttr(c.conversationId) + '\\\\'); switchTab(\\\\'conversation\\\\');\">' +\n '<span class=\"conv-id\">' + escHtml(c.label || c.conversationId) + '</span>' +\n (c.running ? '<span class=\"status-pill running\">running</span>' : '') +\n '<span class=\"conv-last\">' + escHtml(last) + '</span>' +\n '</button>';\n }).join('') + '</div>';\n } catch (err) {\n container.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n async function loadGlobalSettings() {\n const container = document.getElementById('global-settings-content');\n container.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n if (!modelsLoaded) await loadModels();\n try {\n const data = await apiGet('/admin/api/settings/global');\n container.innerHTML = renderGlobalSettings(data);\n } catch (err) {\n container.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n function renderGlobalSettings(data) {\n const thinking = ['off','minimal','low','medium','high','xhigh'];\n const thinkingOpts = thinking.map((t) =>\n '<option value=\"' + t + '\"' + (data.thinkingLevel === t ? ' selected' : '') + '>' + t + '</option>'\n ).join('');\n const mounts = ['private','full'];\n const mountOpts = mounts.map((m) =>\n '<option value=\"' + m + '\"' + (data.sandboxImageWorkspaceMount === m ? ' selected' : '') + '>' + m + '</option>'\n ).join('');\n return [\n '<div class=\"config-grid\">',\n '<div class=\"config-block\">',\n '<h3 class=\"card-subtitle\">Default model</h3>',\n '<div class=\"config-row config-row-stack\"><label>Model</label><select id=\"g-model-ref\">' + renderModelOptions(data.provider, data.model) + '</select></div>',\n '<div class=\"config-row\"><label>Thinking</label><select id=\"g-thinking\">' + thinkingOpts + '</select></div>',\n '<button class=\"primary-action-btn\" onclick=\"saveGlobalModel(this)\">Save model</button>',\n '<div id=\"g-model-result\" class=\"inline-result\" style=\"display:none\"></div>',\n '</div>',\n '<div class=\"config-block\">',\n '<h3 class=\"card-subtitle\">Sandbox limits</h3>',\n '<div class=\"config-row\"><label>CPUs</label><input id=\"g-cpus\" placeholder=\"0.5\" value=\"' + escAttr(data.sandboxCpus || '') + '\"></div>',\n '<div class=\"config-row\"><label>Memory</label><input id=\"g-mem\" placeholder=\"1g\" value=\"' + escAttr(data.sandboxMemory || '') + '\"></div>',\n '<div class=\"config-row\"><label>Boost CPUs</label><input id=\"g-bcpus\" placeholder=\"2\" value=\"' + escAttr(data.sandboxBoostCpus || '') + '\"></div>',\n '<div class=\"config-row\"><label>Boost Mem</label><input id=\"g-bmem\" placeholder=\"4g\" value=\"' + escAttr(data.sandboxBoostMemory || '') + '\"></div>',\n '<div class=\"config-row\"><label>Mount</label><select id=\"g-mount\">' + mountOpts + '</select></div>',\n '<button class=\"primary-action-btn\" onclick=\"saveGlobalSandbox(this)\">Save sandbox</button>',\n '<div id=\"g-sandbox-result\" class=\"inline-result\" style=\"display:none\"></div>',\n '</div>',\n '</div>',\n ].join('');\n }\n\n async function saveGlobalModel(btn) {\n const selectedModel = parseModelRef(document.getElementById('g-model-ref').value.trim());\n const provider = selectedModel.provider;\n const model = selectedModel.model;\n const thinkingLevel = document.getElementById('g-thinking').value;\n const result = document.getElementById('g-model-result');\n if (!provider || !model) {\n result.style.display = 'block'; result.className = 'inline-result err';\n result.textContent = 'Provider and model are required'; return;\n }\n btn.disabled = true; btn.textContent = 'Savingโฆ'; result.style.display = 'none';\n try {\n await apiPost('/admin/api/settings/model', { provider, model, thinkingLevel });\n result.style.display = 'block'; result.className = 'inline-result ok'; result.textContent = 'Saved โ';\n } catch (err) {\n result.style.display = 'block'; result.className = 'inline-result err'; result.textContent = err.message;\n } finally {\n btn.disabled = false; btn.textContent = 'Save model';\n }\n }\n\n async function saveGlobalSandbox(btn) {\n const cpus = document.getElementById('g-cpus').value.trim();\n const memory = document.getElementById('g-mem').value.trim();\n const boostCpus = document.getElementById('g-bcpus').value.trim();\n const boostMemory = document.getElementById('g-bmem').value.trim();\n const workspaceMount = document.getElementById('g-mount').value;\n const result = document.getElementById('g-sandbox-result');\n btn.disabled = true; btn.textContent = 'Savingโฆ'; result.style.display = 'none';\n try {\n await apiPost('/admin/api/settings/sandbox', { cpus, memory, boostCpus, boostMemory, workspaceMount });\n result.style.display = 'block'; result.className = 'inline-result ok'; result.textContent = 'Saved โ';\n } catch (err) {\n result.style.display = 'block'; result.className = 'inline-result err'; result.textContent = err.message;\n } finally {\n btn.disabled = false; btn.textContent = 'Save sandbox';\n }\n }\n\n async function loadGlobalSkills() {\n const container = document.getElementById('global-skills-content');\n container.innerHTML = '<div class=\"loading-msg\">Loadingโฆ</div>';\n try {\n // Reuse skills endpoint scoped to a conversation that doesn't have any of its own; the global half is what we want.\n const data = await apiGet('/admin/api/skills?conversationId=' + encodeURIComponent(activeConversationId));\n const globals = data.skills.filter((s) => s.source === 'global');\n if (globals.length === 0) {\n container.innerHTML = '<div class=\"empty-state\">No global skills</div>';\n return;\n }\n container.innerHTML = '<div class=\"skills-list\">' + globals.map((s) =>\n '<div class=\"skill-row\"><div class=\"skill-name\">' + escHtml(s.name) + '</div>' +\n (s.description ? '<div class=\"skill-desc\">' + escHtml(s.description) + '</div>' : '') + '</div>'\n ).join('') + '</div>';\n } catch (err) {\n container.innerHTML = '<div class=\"err-msg\">' + escHtml(err.message) + '</div>';\n }\n }\n\n // โโ Init โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n initConvSwitcher();\n loadModels().finally(() => {\n loadSettings();\n loadWorkspace();\n loadSkills();\n loadConversationEvents();\n });\n `;\n\n return renderPortalShell({\n activeView: \"admin\",\n pageTitle: \"Admin\",\n identity: { primary: token.platform, secondary: userLabel },\n conversationSwitcher: { currentId: token.conversationId },\n body,\n extraStyles: adminViewStyles,\n inlineScript: script,\n });\n}\n\nfunction renderAdminErrorPage(message: string): string {\n return renderPortalShell({\n activeView: \"admin\",\n pageTitle: \"Admin\",\n body: `<section class=\"card\" style=\"text-align:center;padding:40px 32px\">\n <p class=\"eyebrow\">${PRODUCT_NAME} admin</p>\n <h1 class=\"page-title\" style=\"margin:12px 0 16px\">Access Denied</h1>\n <div class=\"err-msg\">${esc(message)}</div>\n </section>`,\n });\n}\n\n// โโ Styles โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nconst adminViewStyles = `\n .tab-nav {\n display: flex; gap: 6px; padding: 6px;\n border: 1px solid var(--border); border-radius: 16px;\n background: rgba(255,255,255,0.72); backdrop-filter: blur(8px);\n overflow-x: auto; scrollbar-width: none;\n }\n .tab-nav::-webkit-scrollbar { display: none; }\n .tab-btn {\n flex: 1; min-width: 80px; padding: 10px 16px;\n border: none; border-radius: 10px; background: transparent;\n color: var(--muted);\n font: 500 0.88rem/1.2 'DM Sans', sans-serif;\n cursor: pointer; white-space: nowrap;\n transition: background 140ms, color 140ms;\n }\n .tab-btn:hover { background: rgba(0,0,0,0.04); color: var(--text); }\n .tab-btn.active { background: var(--text); color: #fafafa; font-weight: 600; }\n .tab-btn:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }\n\n .tab-panel { display: none; flex-direction: column; gap: 14px; }\n .tab-panel.active { display: flex; }\n\n .card-desc { color: var(--muted); font-size: 0.9rem; line-height: 1.55; margin-bottom: 12px; }\n\n .link-result {\n margin-top: 12px; padding: 10px 14px; border-radius: 10px;\n display: flex; gap: 10px; align-items: center; flex-wrap: wrap;\n font-size: 0.84rem;\n }\n .link-result.ok { background: var(--ok-bg); border: 1px solid var(--ok-border); }\n .link-result.err { background: var(--err-bg); border: 1px solid var(--err-border); color: var(--err-text); }\n .link-result.loading { background: rgba(0,0,0,0.025); border: 1px solid var(--border); color: var(--muted); }\n .link-result a {\n color: var(--ok-text);\n font-family: 'JetBrains Mono', ui-monospace, monospace;\n font-size: 0.78rem; word-break: break-all; flex: 1; min-width: 0;\n }\n .link-vault { color: var(--muted); font-size: 0.78rem; flex-shrink: 0; }\n .copy-link-btn {\n padding: 5px 12px; border: 1px solid var(--ok-border); border-radius: 7px;\n background: rgba(255,255,255,0.7); color: var(--ok-text);\n font: 500 0.78rem/1.2 'DM Sans', sans-serif;\n cursor: pointer; flex-shrink: 0;\n }\n\n .portal-frame {\n width: 100%; min-height: 720px;\n border: 1px solid var(--border); border-radius: 14px; background: #fff;\n }\n\n .config-grid {\n display: grid; grid-template-columns: 1fr 1fr; gap: 18px;\n }\n .config-block { display: flex; flex-direction: column; gap: 10px; }\n .config-row { display: grid; grid-template-columns: 110px 1fr; gap: 10px; align-items: center; }\n .config-row.config-row-stack { grid-template-columns: 1fr; }\n .config-row label { font-size: 0.82rem; color: var(--muted); }\n .config-row input, .config-row select, .config-row textarea {\n padding: 7px 10px; border: 1px solid var(--border); border-radius: 8px;\n font-family: inherit; font-size: 0.84rem; width: 100%;\n }\n .config-row textarea {\n font-family: 'JetBrains Mono', ui-monospace, monospace;\n resize: vertical;\n }\n .toggle { display: inline-flex; align-items: center; gap: 8px; font-size: 0.84rem; }\n\n .inline-result {\n padding: 8px 12px; border-radius: 8px; font-size: 0.82rem; margin-top: 4px;\n }\n .inline-result.ok { background: var(--ok-bg); color: var(--ok-text); border: 1px solid var(--ok-border); }\n .inline-result.err { background: var(--err-bg); color: var(--err-text); border: 1px solid var(--err-border); }\n\n /* โโ Sections (Conversation page stack) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\n .sect-head {\n display: flex; align-items: flex-start; justify-content: space-between;\n gap: 12px; margin-bottom: 14px; flex-wrap: wrap;\n }\n .sect-head .card-title { margin-bottom: 0; }\n .sect-disabled { opacity: 0.7; }\n\n .refresh-btn {\n flex-shrink: 0; padding: 6px 12px;\n border: 1px solid var(--border); border-radius: 10px;\n background: rgba(0,0,0,0.025); color: var(--muted);\n font: 500 0.84rem/1.2 'DM Sans', sans-serif; cursor: pointer;\n }\n .refresh-btn:hover { background: rgba(0,0,0,0.06); color: var(--text); }\n\n /* โโ Workspace โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\n .workspace-split {\n display: grid; grid-template-columns: 260px 1fr; gap: 14px;\n min-height: 360px;\n }\n .workspace-tree {\n border: 1px solid var(--border); border-radius: 12px; padding: 10px;\n background: rgba(0,0,0,0.02); overflow: auto; max-height: 480px;\n font-family: 'JetBrains Mono', ui-monospace, monospace;\n font-size: 0.78rem;\n }\n .workspace-tree ul { list-style: none; padding-left: 12px; margin: 0; }\n .workspace-tree .tree-root { padding-left: 0; }\n .workspace-tree details { margin: 1px 0; }\n .workspace-tree summary { cursor: pointer; padding: 2px 4px; border-radius: 4px; }\n .workspace-tree summary:hover { background: rgba(0,0,0,0.05); }\n .tree-dir { color: var(--text); font-weight: 600; }\n .tree-dir.empty { color: var(--subtle); font-weight: 400; }\n .tree-file {\n display: block; width: 100%; text-align: left;\n background: transparent; border: none; cursor: pointer;\n padding: 2px 4px; border-radius: 4px;\n font-family: inherit; font-size: inherit; color: var(--muted);\n }\n .tree-file:hover { background: rgba(0,0,0,0.05); color: var(--text); }\n\n .workspace-preview {\n border: 1px solid var(--border); border-radius: 12px;\n background: #fff; padding: 12px; overflow: auto; max-height: 480px;\n }\n .preview-meta {\n font-size: 0.74rem; color: var(--subtle);\n margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px solid var(--border);\n font-family: 'JetBrains Mono', ui-monospace, monospace;\n }\n .preview-body {\n margin: 0; white-space: pre-wrap; word-break: break-word;\n font-family: 'JetBrains Mono', ui-monospace, monospace;\n font-size: 0.78rem; color: var(--text);\n }\n .placeholder-msg { color: var(--subtle); font-size: 0.86rem; padding: 24px 8px; text-align: center; }\n\n /* โโ Skills โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\n .skills-list { display: flex; flex-direction: column; gap: 8px; }\n .skill-row {\n padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px;\n background: rgba(0,0,0,0.02);\n }\n .skill-row-btn {\n width: 100%; text-align: left; cursor: pointer; font-family: inherit;\n }\n .skill-row-btn:hover { background: rgba(0,0,0,0.05); }\n .skill-name {\n font-weight: 650; font-size: 0.9rem; color: var(--text);\n display: flex; align-items: center; gap: 8px; flex-wrap: wrap;\n }\n .skill-source {\n padding: 1px 8px; border-radius: 999px; font-size: 0.7rem;\n font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;\n }\n .skill-source-global { background: rgba(59,130,246,0.1); color: #1d4ed8; }\n .skill-source-conversation { background: rgba(217,119,6,0.1); color: var(--accent); }\n .skill-desc { color: var(--muted); font-size: 0.82rem; margin-top: 4px; line-height: 1.5; }\n\n /* โโ Events โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\n .events-list { display: flex; flex-direction: column; gap: 8px; }\n .event-row {\n padding: 10px 12px; border: 1px solid var(--border); border-radius: 10px;\n background: rgba(0,0,0,0.02);\n }\n .event-row-top {\n display: flex; align-items: center; justify-content: space-between;\n gap: 10px;\n }\n .event-name { min-width: 0; flex: 1; word-break: break-all; }\n .event-name code { font-size: 0.82rem; background: transparent; padding: 0; }\n .event-meta { font-size: 0.74rem; color: var(--muted); margin-top: 3px; }\n .event-text {\n font-size: 0.82rem; color: var(--text); margin-top: 6px;\n font-family: 'JetBrains Mono', ui-monospace, monospace;\n white-space: pre-wrap; word-break: break-word;\n }\n .event-delete-btn {\n flex-shrink: 0; padding: 4px 10px;\n border-radius: 7px; border: 1px solid rgba(185, 28, 28, 0.18);\n background: rgba(0,0,0,0.03); color: var(--err-text);\n font: 500 0.76rem/1.2 'DM Sans', sans-serif; cursor: pointer;\n }\n .event-delete-btn:hover:not(:disabled) {\n background: var(--err-bg); border-color: rgba(185, 28, 28, 0.28);\n }\n .event-delete-btn:disabled { opacity: 0.5; cursor: wait; }\n\n /* โโ All Conversations list โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */\n\n .conv-list { display: flex; flex-direction: column; gap: 6px; }\n .conv-row-btn {\n display: flex; align-items: center; gap: 12px;\n padding: 10px 14px; border: 1px solid var(--border); border-radius: 10px;\n background: rgba(0,0,0,0.02); cursor: pointer; text-align: left;\n transition: background 120ms, border-color 120ms;\n }\n .conv-row-btn:hover { background: rgba(0,0,0,0.05); border-color: rgba(0,0,0,0.14); }\n .conv-id { flex: 1; font-family: 'JetBrains Mono', ui-monospace, monospace; font-size: 0.84rem; }\n .conv-last { color: var(--subtle); font-size: 0.78rem; }\n\n .status-pill {\n display: inline-flex; padding: 2px 9px; border-radius: 999px;\n font-size: 0.7rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase;\n }\n .status-pill.running { background: var(--ok-bg); color: var(--ok-text); border: 1px solid var(--ok-border); }\n\n @media (max-width: 640px) {\n .tab-btn { padding: 9px 12px; font-size: 0.82rem; min-width: 60px; }\n .config-grid { grid-template-columns: 1fr; }\n .config-row { grid-template-columns: 1fr; gap: 4px; }\n .portal-frame { min-height: 520px; }\n .workspace-split { grid-template-columns: 1fr; }\n .workspace-tree, .workspace-preview { max-height: 260px; }\n }\n`;\n"]}
|