import crypto from "node:crypto"; import http from "node:http"; import express from "express"; import { WebSocketServer } from "ws"; const token = process.env.RUNNER_TOKEN || "test-runner-token-that-is-at-least-32-characters"; const tools = [ ["codex", "Codex", "OpenAI", "CX", "codex", "0.149.0"], ["claude", "Claude Code", "Anthropic", "CC", "claude", "2.1.241"], ["codebuddy", "CodeBuddy", "Tencent", "CB", "codebuddy", "2.137.1"], ["kimi", "Kimi CLI", "Moonshot AI", "KM", "kimi", "0.38.0"], ["opencode", "OpenCode", "SST / Open source", "OC", "opencode", "1.18.21"], ["qwen", "Qwen Code", "Alibaba", "QW", "qwen", "0.22.0"], ["dsh", "DeepSeek Harness", "DeepSeek", "DS", "dsh", "0.1.1-rc.2"], ].map(([id, name, vendor, mono, command, version]) => ({ id, name, vendor, mono, command, version, installed: true, status: "stopped", profiles: id === "dsh" ? ["headless"] : [] })); const sessions = []; const integrations = { ccSwitch: { installed: true, version: "cc-switch 5.10.2", initialized: true, apps: [ { id: "claude", toolId: "claude", name: "Claude Code", currentProviderId: "anthropic", providers: [{ id: "anthropic", name: "Anthropic", endpoint: "https://api.anthropic.com", active: true }, { id: "relay", name: "Team Relay", endpoint: "https://relay.example", active: false }] }, { id: "codex", toolId: "codex", name: "Codex", currentProviderId: "codex-official", providers: [{ id: "codex-official", name: "OpenAI Official", endpoint: null, active: true }] }, { id: "open-code", toolId: "opencode", name: "OpenCode", currentProviderId: "openrouter", providers: [{ id: "openrouter", name: "OpenRouter", endpoint: "https://openrouter.ai", active: true }] }, ], unsupportedToolIds: ["codebuddy", "kimi", "qwen", "dsh"], }, multica: { installed: true, version: "multica 0.1.53", daemon: { status: "stopped", supervision: { mode: "unsupervised" } }, config: { configured: false, serverUrl: null, appUrl: null, workspaceId: null }, supportedToolIds: ["claude", "codex", "codebuddy", "kimi", "opencode"], }, }; const app = express(); app.use(express.json()); app.use((req, res, next) => req.headers.authorization === `Bearer ${token}` ? next() : res.status(401).json({ error: "Unauthorized" })); app.get("/health", (_req, res) => res.json({ ok: true })); app.get("/tools", (_req, res) => res.json({ tools: tools.map((tool) => ({ ...tool, status: sessions.some((session) => session.tool === tool.id && session.status === "running") ? "running" : "stopped" })) })); app.get("/projects", (_req, res) => res.json({ projects: ["demo-app", "website"] })); app.get("/sessions", (_req, res) => res.json({ sessions })); app.get("/integrations", (_req, res) => res.json({ integrations })); app.get("/sessions/:id/output", (_req, res) => res.type("text/plain").send("AgentDock local QA session\r\n")); app.get("/sessions/:id/diff", (_req, res) => res.type("text/plain").send("diff --git a/src/app.js b/src/app.js\n--- a/src/app.js\n+++ b/src/app.js\n@@ -1 +1 @@\n-old\n+new\n")); app.post("/sessions", (req, res) => { const tool = tools.find((item) => item.id === req.body.tool); const session = { id: crypto.randomUUID(), tool: tool.id, toolName: tool.name, project: req.body.project || ".", purpose: req.body.purpose || "task", initialInput: req.body.initialInput || "", profile: req.body.profile || null, model: req.body.model || null, status: "running", pid: 4242, createdAt: new Date().toISOString(), endedAt: null, exitCode: null, signal: null }; sessions.unshift(session); res.status(201).json({ session }); }); app.post("/sessions/:id/input", (_req, res) => res.status(204).end()); app.post("/sessions/:id/resize", (_req, res) => res.status(204).end()); app.post("/sessions/:id/stop", (req, res) => { const session = sessions.find((item) => item.id === req.params.id); if (session) { session.status = "stopped"; session.endedAt = new Date().toISOString(); } res.status(204).end(); }); app.post("/integrations/cc-switch/:app/switch", (req, res) => { const appConfig = integrations.ccSwitch.apps.find((item) => item.id === req.params.app); if (!appConfig) return res.status(400).json({ error: "Unsupported CC Switch application" }); appConfig.currentProviderId = req.body.providerId; appConfig.providers.forEach((provider) => { provider.active = provider.id === req.body.providerId; }); res.json({ integrations }); }); app.post("/integrations/cc-switch/:app/import-live", (_req, res) => res.json({ integrations })); const server = http.createServer(app); const sockets = new WebSocketServer({ noServer: true }); server.on("upgrade", (request, socket, head) => { const url = new URL(request.url, "http://localhost"); const match = url.pathname.match(/^\/ws\/sessions\/([a-f0-9-]+)$/); if (!match || url.searchParams.get("token") !== token) return socket.destroy(); sockets.handleUpgrade(request, socket, head, (client) => { client.send(JSON.stringify({ type: "snapshot", data: "\u001b[36mAgentDock local QA session\u001b[0m\r\n$ CLI ready\r\n" })); client.on("message", (raw) => { const message = JSON.parse(raw.toString()); if (message.type === "input" && message.data.trim()) client.send(JSON.stringify({ type: "output", data: `\r\nreceived: ${message.data}` })); }); }); }); server.listen(4174, "127.0.0.1", () => console.log("mock runner listening on 4174"));