@holdpoint/live-daemon 0.1.0-alpha.5 → 0.1.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -133,7 +133,7 @@ async function readHealthyDaemonLock(homeDir) {
133
133
  // src/server.ts
134
134
  import { createServer as createServer2 } from "http";
135
135
  import { randomUUID as randomUUID2 } from "crypto";
136
- import { createReadStream, existsSync as existsSync4 } from "fs";
136
+ import { createReadStream, existsSync as existsSync4, renameSync, writeFileSync as writeFileSync2 } from "fs";
137
137
  import { dirname, extname, join as join3, resolve as resolve3, sep } from "path";
138
138
  import { fileURLToPath, URL } from "url";
139
139
  import {
@@ -142,6 +142,7 @@ import {
142
142
  EventV1Schema as EventV1Schema2,
143
143
  EventsBatchSchema
144
144
  } from "@holdpoint/live-protocol";
145
+ import { parseHoldpointYaml } from "@holdpoint/yaml-core";
145
146
  import { WebSocket, WebSocketServer } from "ws";
146
147
 
147
148
  // src/auth.ts
@@ -181,6 +182,17 @@ async function readJsonBody(req) {
181
182
  if (chunks.length === 0) return null;
182
183
  return JSON.parse(Buffer.concat(chunks).toString("utf8"));
183
184
  }
185
+ async function readTextBody(req, maxBytes = 512e3) {
186
+ const chunks = [];
187
+ let total = 0;
188
+ for await (const chunk of req) {
189
+ const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
190
+ total += buf.length;
191
+ if (total > maxBytes) throw new Error("Request body too large");
192
+ chunks.push(buf);
193
+ }
194
+ return Buffer.concat(chunks).toString("utf8");
195
+ }
184
196
  function authorizeRequest(req, res, token, port) {
185
197
  const origin = req.headers.origin;
186
198
  if (origin && origin !== `http://127.0.0.1:${port}`) {
@@ -703,7 +715,6 @@ function matchesSubscription(subscription, event) {
703
715
  // src/server.ts
704
716
  var __dirname = dirname(fileURLToPath(import.meta.url));
705
717
  var LIVE_UI_DIR = join3(__dirname, "live-ui");
706
- var BUILDER_UI_DIR = join3(__dirname, "builder-ui");
707
718
  var CONTENT_SECURITY_POLICY = "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; connect-src 'self' ws: http:; object-src 'none'; base-uri 'none'; frame-ancestors 'none'";
708
719
  var MIME = {
709
720
  ".css": "text/css; charset=utf-8",
@@ -791,10 +802,10 @@ function resolveUiFilePath(uiDir, requestedPath) {
791
802
  return existsSync4(join3(uiDir, "index.html")) ? join3(uiDir, "index.html") : null;
792
803
  }
793
804
  function normalizeUiPath(path) {
794
- if (!path) return "/live/";
795
- if (path === "/live" || path.startsWith("/live/")) return "/live/";
796
- if (path === "/builder" || path.startsWith("/builder/")) return "/builder/";
797
- return "/live/";
805
+ if (path === "/builder" || path?.startsWith("/builder/")) {
806
+ return { pathname: "/live/", tab: "checks" };
807
+ }
808
+ return { pathname: "/live/" };
798
809
  }
799
810
  function registerProjectFromAuthUrl(url, registeredProjects) {
800
811
  const hash = url.searchParams.get("project");
@@ -1013,14 +1024,17 @@ async function startLiveServer(options) {
1013
1024
  return;
1014
1025
  }
1015
1026
  registerProjectFromAuthUrl(url, registered);
1016
- const redirectPath = normalizeUiPath(url.searchParams.get("path"));
1027
+ const redirectTarget = normalizeUiPath(url.searchParams.get("path"));
1017
1028
  const redirectUrl = new URL(`http://${host}:${actualPort}`);
1018
- redirectUrl.pathname = redirectPath;
1029
+ redirectUrl.pathname = redirectTarget.pathname;
1019
1030
  for (const [key, value] of url.searchParams.entries()) {
1020
1031
  if (key !== "token" && key !== "path") {
1021
1032
  redirectUrl.searchParams.set(key, value);
1022
1033
  }
1023
1034
  }
1035
+ if (redirectTarget.tab) {
1036
+ redirectUrl.searchParams.set("tab", redirectTarget.tab);
1037
+ }
1024
1038
  writeUiAuthCookie(res, state.token);
1025
1039
  res.writeHead(302, {
1026
1040
  location: redirectUrl.toString(),
@@ -1071,6 +1085,47 @@ async function startLiveServer(options) {
1071
1085
  createReadStream(reportsPath).pipe(res);
1072
1086
  return;
1073
1087
  }
1088
+ if (req.method === "PUT" && url.pathname === "/__holdpoint/checks") {
1089
+ if (!authorizeRequest(req, res, state.token, actualPort)) {
1090
+ return;
1091
+ }
1092
+ const project = getProjectForRequest(url, registered);
1093
+ if (!project) {
1094
+ writeJson(res, 404, { ok: false, error: "Project not registered for this UI session" });
1095
+ return;
1096
+ }
1097
+ const checksPath = resolve3(project.root, "checks.yaml");
1098
+ if (!isWithinRoot(checksPath, project.root)) {
1099
+ writeJson(res, 400, { ok: false, error: "Invalid checks path" });
1100
+ return;
1101
+ }
1102
+ let body;
1103
+ try {
1104
+ body = await readTextBody(req);
1105
+ } catch {
1106
+ writeJson(res, 413, { ok: false, error: "checks.yaml is too large" });
1107
+ return;
1108
+ }
1109
+ try {
1110
+ parseHoldpointYaml(body);
1111
+ } catch (parseError) {
1112
+ writeJson(res, 422, {
1113
+ ok: false,
1114
+ error: `Invalid checks.yaml: ${parseError.message}`
1115
+ });
1116
+ return;
1117
+ }
1118
+ try {
1119
+ const tmpPath = `${checksPath}.holdpoint-tmp-${randomUUID2().slice(0, 8)}`;
1120
+ writeFileSync2(tmpPath, body, "utf8");
1121
+ renameSync(tmpPath, checksPath);
1122
+ } catch (writeError) {
1123
+ writeJson(res, 500, { ok: false, error: writeError.message });
1124
+ return;
1125
+ }
1126
+ writeJson(res, 200, { ok: true });
1127
+ return;
1128
+ }
1074
1129
  if (url.pathname.startsWith("/v1/") && !authorizeRequest(req, res, state.token, actualPort)) {
1075
1130
  return;
1076
1131
  }
@@ -1165,28 +1220,30 @@ async function startLiveServer(options) {
1165
1220
  res.end();
1166
1221
  return;
1167
1222
  }
1168
- if (url.pathname === "/live" || url.pathname === "/builder") {
1169
- res.writeHead(302, { location: `${url.pathname}/`, "cache-control": "no-store" });
1223
+ if (url.pathname === "/builder" || url.pathname.startsWith("/builder/")) {
1224
+ const target = new URL("/live/", `http://${host}:${actualPort}`);
1225
+ for (const [key, value] of url.searchParams.entries()) target.searchParams.set(key, value);
1226
+ target.searchParams.set("tab", "checks");
1227
+ res.writeHead(302, {
1228
+ location: `${target.pathname}${target.search}`,
1229
+ "cache-control": "no-store"
1230
+ });
1231
+ res.end();
1232
+ return;
1233
+ }
1234
+ if (url.pathname === "/live") {
1235
+ res.writeHead(302, { location: "/live/", "cache-control": "no-store" });
1170
1236
  res.end();
1171
1237
  return;
1172
1238
  }
1173
- const uiRoute = url.pathname.startsWith("/builder/") ? {
1174
- appName: "Holdpoint Builder",
1175
- dir: BUILDER_UI_DIR,
1176
- path: url.pathname.replace(/^\/builder\/?/, "")
1177
- } : url.pathname.startsWith("/live/") ? {
1178
- appName: "Holdpoint Live",
1179
- dir: LIVE_UI_DIR,
1180
- path: url.pathname.replace(/^\/live\/?/, "")
1181
- } : null;
1182
- if (!uiRoute) {
1239
+ if (!url.pathname.startsWith("/live/")) {
1183
1240
  res.writeHead(302, { location: "/live/", "cache-control": "no-store" });
1184
1241
  res.end();
1185
1242
  return;
1186
1243
  }
1187
- const filePath = resolveUiFilePath(uiRoute.dir, uiRoute.path);
1244
+ const filePath = resolveUiFilePath(LIVE_UI_DIR, url.pathname.replace(/^\/live\/?/, ""));
1188
1245
  if (!filePath) {
1189
- servePlaceholder(res, uiRoute.appName);
1246
+ servePlaceholder(res, "Holdpoint Live");
1190
1247
  return;
1191
1248
  }
1192
1249
  serveUiAsset(res, filePath);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/singleton.ts","../src/server.ts","../src/auth.ts","../src/store.ts","../src/conflict-tracker.ts","../src/project-identity.ts","../src/router.ts","../src/index.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { createServer } from \"node:net\";\nimport os from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport { z } from \"zod\";\n\nexport const DaemonLockSchema = z.object({\n version: z.string().min(1),\n pid: z.number().int().positive(),\n port: z.number().int().positive(),\n token: z.string().min(1),\n started_at: z.number().int().nonnegative(),\n host: z.string().min(1),\n});\n\nexport type DaemonLock = z.infer<typeof DaemonLockSchema>;\n\nexport function resolveHoldpointHome(homeDir?: string): string {\n return resolve(homeDir ?? process.env.HOLDPOINT_HOME ?? join(os.homedir(), \".holdpoint\"));\n}\n\nexport function ensureHoldpointHome(homeDir?: string): string {\n const root = resolveHoldpointHome(homeDir);\n mkdirSync(root, { recursive: true, mode: 0o700 });\n return root;\n}\n\nexport function getDaemonLockPath(homeDir?: string): string {\n return join(resolveHoldpointHome(homeDir), \"daemon.lock\");\n}\n\nexport function readDaemonLock(homeDir?: string): DaemonLock | null {\n const lockPath = getDaemonLockPath(homeDir);\n if (!existsSync(lockPath)) return null;\n try {\n return DaemonLockSchema.parse(JSON.parse(readFileSync(lockPath, \"utf8\")));\n } catch {\n return null;\n }\n}\n\nexport function isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function findFreePort(host = \"127.0.0.1\"): Promise<number> {\n return await new Promise<number>((resolvePromise, reject) => {\n const server = createServer();\n server.listen(0, host, () => {\n const address = server.address();\n if (!address || typeof address === \"string\") {\n server.close();\n reject(new Error(\"Expected TCP address\"));\n return;\n }\n const { port } = address;\n server.close((err) => {\n if (err) reject(err);\n else resolvePromise(port);\n });\n });\n server.on(\"error\", reject);\n });\n}\n\nexport function createDaemonLock(port: number, version: string): DaemonLock {\n return {\n version,\n pid: process.pid,\n port,\n token: randomBytes(32).toString(\"hex\"),\n started_at: Date.now(),\n host: `${os.platform()}-${os.arch()}`,\n };\n}\n\nexport function writeDaemonLockExclusive(lock: DaemonLock, homeDir?: string): void {\n ensureHoldpointHome(homeDir);\n writeFileSync(getDaemonLockPath(homeDir), JSON.stringify(lock, null, 2) + \"\\n\", {\n encoding: \"utf8\",\n flag: \"wx\",\n mode: 0o600,\n });\n}\n\nexport function removeDaemonLock(homeDir?: string, expectedToken?: string): void {\n const lockPath = getDaemonLockPath(homeDir);\n if (!existsSync(lockPath)) return;\n if (expectedToken) {\n const lock = readDaemonLock(homeDir);\n if (!lock || lock.token !== expectedToken) {\n return;\n }\n }\n try {\n unlinkSync(lockPath);\n } catch {\n /* ignore cleanup races */\n }\n}\n\nasync function fetchHealth(port: number, timeoutMs: number): Promise<boolean> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: controller.signal,\n });\n return response.ok;\n } catch {\n return false;\n } finally {\n clearTimeout(timeout);\n }\n}\n\nexport async function waitForDaemonHealthy(\n lock: DaemonLock,\n timeoutMs = 5_000,\n pollMs = 100,\n): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (await fetchHealth(lock.port, Math.min(pollMs, timeoutMs))) {\n return true;\n }\n await new Promise((resolvePromise) => setTimeout(resolvePromise, pollMs));\n }\n return false;\n}\n\nexport async function readHealthyDaemonLock(homeDir?: string): Promise<DaemonLock | null> {\n const lock = readDaemonLock(homeDir);\n if (!lock) return null;\n if (!isProcessAlive(lock.pid)) {\n removeDaemonLock(homeDir);\n return null;\n }\n if (!(await waitForDaemonHealthy(lock, 300, 100))) {\n removeDaemonLock(homeDir);\n return null;\n }\n return lock;\n}\n","import { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\nimport { createReadStream, existsSync } from \"node:fs\";\nimport { dirname, extname, join, resolve, sep } from \"node:path\";\nimport { fileURLToPath, URL } from \"node:url\";\nimport type { EventV1, ServerMessage } from \"@holdpoint/live-protocol\";\nimport {\n ClientMessageSchema,\n ControlRequestSchema,\n EventV1Schema,\n EventsBatchSchema,\n} from \"@holdpoint/live-protocol\";\nimport { WebSocket, WebSocketServer, type RawData } from \"ws\";\nimport {\n authorizeRequest,\n authorizeWebSocket,\n readJsonBody,\n writeJson,\n writeUiAuthCookie,\n} from \"./auth.js\";\nimport { matchesSubscription, type Subscription } from \"./router.js\";\nimport type { LiveStore } from \"./store.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst LIVE_UI_DIR = join(__dirname, \"live-ui\");\nconst BUILDER_UI_DIR = join(__dirname, \"builder-ui\");\nconst CONTENT_SECURITY_POLICY =\n \"default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; connect-src 'self' ws: http:; object-src 'none'; base-uri 'none'; frame-ancestors 'none'\";\nconst MIME: Record<string, string> = {\n \".css\": \"text/css; charset=utf-8\",\n \".html\": \"text/html; charset=utf-8\",\n \".ico\": \"image/x-icon\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".png\": \"image/png\",\n \".svg\": \"image/svg+xml\",\n};\n\nexport interface StartLiveServerOptions {\n host?: string;\n port: number;\n token: string;\n version: string;\n startedAt: number;\n store: LiveStore;\n}\n\nexport interface RunningLiveServer {\n host: string;\n port: number;\n close(): Promise<void>;\n closed: Promise<void>;\n}\n\ninterface RegisteredProject {\n hash: string;\n name?: string;\n root: string;\n}\n\nfunction sendSocketMessage(socket: WebSocket, message: ServerMessage): void {\n socket.send(JSON.stringify(message));\n}\n\nfunction decodeRawData(raw: RawData): string {\n if (typeof raw === \"string\") return raw;\n if (raw instanceof Buffer) return raw.toString(\"utf8\");\n if (Array.isArray(raw)) return Buffer.concat(raw).toString(\"utf8\");\n return Buffer.from(new Uint8Array(raw)).toString(\"utf8\");\n}\n\nfunction getEventsForScope(\n store: LiveStore,\n subscription: Subscription,\n sinceSeq: number,\n): EventV1[] {\n switch (subscription.scope) {\n case \"all\":\n return store.getAllEvents(sinceSeq);\n case \"project\":\n return subscription.key ? store.getProjectEvents(subscription.key, sinceSeq) : [];\n case \"session\":\n return subscription.key ? store.getSessionEvents(subscription.key, sinceSeq) : [];\n }\n}\n\nfunction buildControlStateEvent(\n session: {\n project_hash: string;\n engine: string;\n session_id: string;\n cwd: string;\n caps?: EventV1[\"caps\"];\n },\n controlOnline: boolean,\n): EventV1 {\n return {\n v: 1,\n id: randomUUID(),\n ts: Date.now(),\n engine: session.engine,\n session_id: session.session_id,\n project_hash: session.project_hash,\n cwd: session.cwd,\n caps: {\n ...(session.caps ?? {}),\n can_control: session.caps?.can_control ?? true,\n control_online: controlOnline,\n },\n type: \"meta\",\n payload: {\n kind: controlOnline ? \"control_socket_registered\" : \"control_socket_disconnected\",\n },\n };\n}\n\nfunction servePlaceholder(res: ServerResponse, appName = \"Holdpoint Live\"): void {\n res.writeHead(200, {\n \"cache-control\": \"no-store\",\n \"content-security-policy\": CONTENT_SECURITY_POLICY,\n \"content-type\": \"text/html; charset=utf-8\",\n });\n res.end(\n `<!doctype html><title>${appName}</title><body style=\"font-family:system-ui;background:#0b0f14;color:#f5f1e8;padding:32px\"><h1>${appName}</h1><p>UI assets were not found in this build. Rebuild the monorepo with <code>pnpm turbo build</code>.</p></body>`,\n );\n}\n\nfunction serveUiAsset(res: ServerResponse, filePath: string): void {\n const mime = MIME[extname(filePath)] ?? \"application/octet-stream\";\n const headers: Record<string, string> = {\n \"cache-control\": \"no-store\",\n \"content-type\": mime,\n };\n if (filePath.endsWith(\".html\")) {\n headers[\"content-security-policy\"] = CONTENT_SECURITY_POLICY;\n }\n res.writeHead(200, headers);\n createReadStream(filePath).pipe(res);\n}\n\nfunction isWithinRoot(candidate: string, root: string): boolean {\n return candidate === root || candidate.startsWith(root + sep);\n}\n\nfunction resolveUiFilePath(uiDir: string, requestedPath: string): string | null {\n const requested = requestedPath === \"\" || requestedPath === \"/\" ? \"index.html\" : requestedPath;\n const candidate = resolve(uiDir, requested.replace(/^\\//, \"\"));\n if (!isWithinRoot(candidate, uiDir)) {\n return null;\n }\n if (existsSync(candidate)) {\n return candidate;\n }\n return existsSync(join(uiDir, \"index.html\")) ? join(uiDir, \"index.html\") : null;\n}\n\nfunction normalizeUiPath(path: string | null): \"/live/\" | \"/builder/\" {\n if (!path) return \"/live/\";\n if (path === \"/live\" || path.startsWith(\"/live/\")) return \"/live/\";\n if (path === \"/builder\" || path.startsWith(\"/builder/\")) return \"/builder/\";\n return \"/live/\";\n}\n\nfunction registerProjectFromAuthUrl(\n url: URL,\n registeredProjects: Map<string, RegisteredProject>,\n): void {\n const hash = url.searchParams.get(\"project\");\n const root = url.searchParams.get(\"root\");\n if (!hash || !root || root.includes(\"\\0\")) {\n return;\n }\n const name = url.searchParams.get(\"name\");\n registeredProjects.set(hash, {\n hash,\n ...(name ? { name } : {}),\n root: resolve(root),\n });\n}\n\nfunction getProjectForRequest(\n url: URL,\n registeredProjects: Map<string, RegisteredProject>,\n): RegisteredProject | null {\n const hash = url.searchParams.get(\"project\");\n if (hash) {\n return registeredProjects.get(hash) ?? null;\n }\n if (registeredProjects.size === 1) {\n return [...registeredProjects.values()][0] ?? null;\n }\n return null;\n}\n\nexport async function startLiveServer(options: StartLiveServerOptions): Promise<RunningLiveServer> {\n const host = options.host ?? \"127.0.0.1\";\n const subscriptions = new Map<WebSocket, Subscription[]>();\n const controlSockets = new Map<string, WebSocket>();\n const socketControlKeys = new Map<WebSocket, Set<string>>();\n const registeredProjects = new Map<string, RegisteredProject>();\n const server = createServer((req, res) => {\n void handleRequest(req, res, options, subscriptions, registeredProjects).catch(\n (error: unknown) => {\n writeJson(res, 500, { ok: false, error: (error as Error).message });\n },\n );\n });\n const wss = new WebSocketServer({ noServer: true });\n\n const broadcastEvent = (event: EventV1): void => {\n for (const [socket, socketSubscriptions] of subscriptions.entries()) {\n if (socket.readyState !== WebSocket.OPEN) continue;\n if (socketSubscriptions.some((subscription) => matchesSubscription(subscription, event))) {\n sendSocketMessage(socket, { type: \"event\", event });\n }\n }\n };\n\n const ingestAndBroadcast = async (event: EventV1): Promise<EventV1[]> => {\n const accepted = await options.store.ingest(event);\n for (const acceptedEvent of accepted) {\n broadcastEvent(acceptedEvent);\n }\n return accepted;\n };\n\n const emitControlState = async (sessionKey: string, controlOnline: boolean): Promise<void> => {\n const summary = options.store.getSessionSummary(sessionKey);\n if (!summary) return;\n await ingestAndBroadcast(buildControlStateEvent(summary, controlOnline));\n };\n\n const registerControlSocket = async (sessionKey: string, socket: WebSocket): Promise<void> => {\n const previous = controlSockets.get(sessionKey);\n if (previous && previous !== socket) {\n socketControlKeys.get(previous)?.delete(sessionKey);\n }\n controlSockets.set(sessionKey, socket);\n const keys = socketControlKeys.get(socket) ?? new Set<string>();\n keys.add(sessionKey);\n socketControlKeys.set(socket, keys);\n await emitControlState(sessionKey, true);\n };\n\n const unregisterControlSocket = async (sessionKey: string, socket: WebSocket): Promise<void> => {\n if (controlSockets.get(sessionKey) !== socket) return;\n controlSockets.delete(sessionKey);\n const keys = socketControlKeys.get(socket);\n keys?.delete(sessionKey);\n if (keys && keys.size === 0) {\n socketControlKeys.delete(socket);\n }\n await emitControlState(sessionKey, false);\n };\n\n const unregisterSocketControls = async (socket: WebSocket): Promise<void> => {\n const keys = [...(socketControlKeys.get(socket) ?? [])];\n for (const sessionKey of keys) {\n await unregisterControlSocket(sessionKey, socket);\n }\n };\n\n wss.on(\"connection\", (socket: WebSocket) => {\n subscriptions.set(socket, []);\n socket.on(\"message\", (raw: RawData) => {\n void (async () => {\n let message: unknown;\n try {\n message = JSON.parse(decodeRawData(raw));\n } catch {\n sendSocketMessage(socket, {\n type: \"error\",\n code: \"invalid_json\",\n message: \"Expected JSON message\",\n });\n return;\n }\n\n const parsed = ClientMessageSchema.safeParse(message);\n if (!parsed.success) {\n sendSocketMessage(socket, {\n type: \"error\",\n code: \"invalid_message\",\n message: parsed.error.issues[0]?.message ?? \"Invalid message\",\n });\n return;\n }\n\n switch (parsed.data.type) {\n case \"subscribe\": {\n if (parsed.data.scope !== \"all\" && !parsed.data.key) {\n sendSocketMessage(socket, {\n type: \"error\",\n code: \"missing_key\",\n message: \"Expected a key for session/project subscriptions\",\n });\n return;\n }\n\n const subscription =\n parsed.data.key !== undefined\n ? { scope: parsed.data.scope, key: parsed.data.key }\n : { scope: parsed.data.scope };\n const next = subscriptions.get(socket) ?? [];\n next.push(subscription);\n subscriptions.set(socket, next);\n\n const backlog = getEventsForScope(\n options.store,\n subscription,\n parsed.data.since_seq ?? 0,\n );\n if (backlog.length > 0) {\n sendSocketMessage(socket, { type: \"events_batch\", events: backlog });\n }\n sendSocketMessage(socket, {\n type: \"ack\",\n for: parsed.data.scope === \"all\" ? \"all\" : (parsed.data.key ?? parsed.data.scope),\n });\n break;\n }\n case \"register_control\": {\n await registerControlSocket(parsed.data.session_key, socket);\n sendSocketMessage(socket, { type: \"ack\", for: parsed.data.session_key });\n break;\n }\n case \"unsubscribe\": {\n const key = parsed.data.key;\n const next = (subscriptions.get(socket) ?? []).filter(\n (subscription) => subscription.key !== key,\n );\n subscriptions.set(socket, next);\n sendSocketMessage(socket, { type: \"ack\", for: key });\n break;\n }\n case \"publish_event\": {\n const accepted = await options.store.ingest(parsed.data.event);\n for (const event of accepted) {\n broadcastEvent(event);\n }\n sendSocketMessage(socket, { type: \"ack\", for: parsed.data.event.id });\n break;\n }\n case \"ping\":\n sendSocketMessage(socket, { type: \"pong\" });\n break;\n }\n })();\n });\n\n socket.on(\"close\", () => {\n subscriptions.delete(socket);\n void unregisterSocketControls(socket).catch(() => {});\n });\n });\n\n server.on(\"upgrade\", (req, socket, head) => {\n const url = new URL(req.url ?? \"/\", `http://${host}:${options.port}`);\n if (url.pathname !== \"/v1/stream\" || !authorizeWebSocket(req, options.token, options.port)) {\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n\n wss.handleUpgrade(req, socket, head, (ws: WebSocket) => {\n wss.emit(\"connection\", ws, req);\n });\n });\n\n await new Promise<void>((resolvePromise, reject) => {\n server.listen(options.port, host, resolvePromise);\n server.on(\"error\", reject);\n });\n\n const address = server.address();\n if (!address || typeof address === \"string\") {\n throw new Error(\"Expected TCP address\");\n }\n const actualPort = address.port;\n\n const closed = new Promise<void>((resolvePromise, reject) => {\n server.on(\"close\", () => resolvePromise());\n server.on(\"error\", reject);\n });\n\n async function close(): Promise<void> {\n for (const socket of subscriptions.keys()) {\n socket.close();\n }\n await new Promise<void>((resolvePromise, reject) => {\n wss.close((err?: Error) => (err ? reject(err) : resolvePromise()));\n });\n await new Promise<void>((resolvePromise, reject) => {\n server.close((err) => (err ? reject(err) : resolvePromise()));\n });\n }\n\n async function handleRequest(\n req: IncomingMessage,\n res: ServerResponse,\n state: StartLiveServerOptions,\n _subscriptions: Map<WebSocket, Subscription[]>,\n registered: Map<string, RegisteredProject>,\n ): Promise<void> {\n const url = new URL(req.url ?? \"/\", `http://${host}:${actualPort}`);\n if (req.method === \"GET\" && url.pathname === \"/health\") {\n writeJson(res, 200, { ok: true, version: state.version, started_at: state.startedAt });\n return;\n }\n\n if (req.method === \"GET\" && url.pathname === \"/__holdpoint/live-auth\") {\n if (url.searchParams.get(\"token\") !== state.token) {\n writeJson(res, 401, { ok: false, error: \"Unauthorized\" });\n return;\n }\n\n registerProjectFromAuthUrl(url, registered);\n\n const redirectPath = normalizeUiPath(url.searchParams.get(\"path\"));\n const redirectUrl = new URL(`http://${host}:${actualPort}`);\n redirectUrl.pathname = redirectPath;\n for (const [key, value] of url.searchParams.entries()) {\n if (key !== \"token\" && key !== \"path\") {\n redirectUrl.searchParams.set(key, value);\n }\n }\n writeUiAuthCookie(res, state.token);\n res.writeHead(302, {\n location: redirectUrl.toString(),\n \"cache-control\": \"no-store\",\n });\n res.end();\n return;\n }\n\n if (req.method === \"GET\" && url.pathname === \"/__holdpoint/initial-yaml\") {\n if (!authorizeRequest(req, res, state.token, actualPort)) {\n return;\n }\n const project = getProjectForRequest(url, registered);\n if (!project) {\n writeJson(res, 404, { ok: false, error: \"Project not registered for this UI session\" });\n return;\n }\n const checksPath = resolve(project.root, \"checks.yaml\");\n if (!isWithinRoot(checksPath, project.root) || !existsSync(checksPath)) {\n writeJson(res, 404, { ok: false, error: \"checks.yaml not found for this project\" });\n return;\n }\n res.writeHead(200, {\n \"cache-control\": \"no-store\",\n \"content-type\": \"text/yaml; charset=utf-8\",\n });\n createReadStream(checksPath).pipe(res);\n return;\n }\n\n if (req.method === \"GET\" && url.pathname === \"/__holdpoint/initial-reports\") {\n if (!authorizeRequest(req, res, state.token, actualPort)) {\n return;\n }\n const project = getProjectForRequest(url, registered);\n if (!project) {\n writeJson(res, 404, { ok: false, error: \"Project not registered for this UI session\" });\n return;\n }\n const reportsPath = resolve(project.root, \".holdpoint\", \"check-reports.json\");\n if (!isWithinRoot(reportsPath, project.root) || !existsSync(reportsPath)) {\n writeJson(res, 404, { ok: false, error: \"No check reports found for this project\" });\n return;\n }\n res.writeHead(200, {\n \"cache-control\": \"no-store\",\n \"content-type\": \"application/json; charset=utf-8\",\n });\n createReadStream(reportsPath).pipe(res);\n return;\n }\n\n if (url.pathname.startsWith(\"/v1/\") && !authorizeRequest(req, res, state.token, actualPort)) {\n return;\n }\n\n if (req.method === \"POST\" && url.pathname === \"/v1/events\") {\n const event = EventV1Schema.parse(await readJsonBody(req));\n const accepted = await ingestAndBroadcast(event);\n writeJson(res, 200, { ok: true, accepted: accepted.length });\n return;\n }\n\n if (req.method === \"POST\" && url.pathname === \"/v1/events/batch\") {\n const events = EventsBatchSchema.parse(await readJsonBody(req));\n const accepted: EventV1[] = [];\n for (const event of events) {\n accepted.push(...(await ingestAndBroadcast(event)));\n }\n writeJson(res, 200, { ok: true, accepted: accepted.length });\n return;\n }\n\n if (req.method === \"POST\" && url.pathname === \"/v1/control\") {\n const request = ControlRequestSchema.parse(await readJsonBody(req));\n const session = state.store.getSessionSummary(request.session_key);\n if (!session) {\n writeJson(res, 404, { ok: false, error: \"Session not found\" });\n return;\n }\n\n const controlSocket = controlSockets.get(request.session_key);\n if (!controlSocket || controlSocket.readyState !== WebSocket.OPEN) {\n writeJson(res, 409, { ok: false, error: \"Control socket not connected\" });\n return;\n }\n\n await ingestAndBroadcast({\n v: 1,\n id: randomUUID(),\n ts: Date.now(),\n engine: session.engine,\n session_id: session.session_id,\n project_hash: session.project_hash,\n cwd: session.cwd,\n type: \"control\",\n payload: request.command,\n });\n sendSocketMessage(controlSocket, {\n type: \"control\",\n session_key: request.session_key,\n command: request.command,\n });\n writeJson(res, 200, { ok: true, delivered: true });\n return;\n }\n\n if (req.method === \"GET\" && url.pathname === \"/v1/projects\") {\n writeJson(res, 200, { projects: state.store.listProjects() });\n return;\n }\n\n if (req.method === \"GET\" && url.pathname === \"/v1/sessions\") {\n const projectHash = url.searchParams.get(\"project_hash\") ?? undefined;\n writeJson(res, 200, { sessions: state.store.listSessions(projectHash) });\n return;\n }\n\n if (\n req.method === \"GET\" &&\n url.pathname.startsWith(\"/v1/sessions/\") &&\n url.pathname.endsWith(\"/events\")\n ) {\n const sessionKey = decodeURIComponent(\n url.pathname.replace(\"/v1/sessions/\", \"\").replace(/\\/events$/, \"\"),\n );\n const sinceSeq = Number(\n url.searchParams.get(\"since_seq\") ?? url.searchParams.get(\"since\") ?? \"0\",\n );\n const limit = Number(url.searchParams.get(\"limit\") ?? \"500\");\n writeJson(res, 200, {\n session_key: sessionKey,\n since_seq: Number.isFinite(sinceSeq) ? sinceSeq : 0,\n max_seq: state.store.getSessionLatestSeq(sessionKey),\n events: state.store.getSessionEvents(\n sessionKey,\n Number.isFinite(sinceSeq) ? sinceSeq : 0,\n Number.isFinite(limit) ? limit : 500,\n ),\n });\n return;\n }\n\n if (req.method === \"DELETE\" && url.pathname.startsWith(\"/v1/sessions/\")) {\n const sessionKey = decodeURIComponent(url.pathname.replace(\"/v1/sessions/\", \"\"));\n const removed = await state.store.purgeSession(sessionKey);\n writeJson(\n res,\n removed ? 200 : 404,\n removed ? { ok: true } : { ok: false, error: \"Session not found\" },\n );\n return;\n }\n\n if (req.method === \"GET\") {\n if (url.pathname === \"/\") {\n res.writeHead(302, { location: \"/live/\", \"cache-control\": \"no-store\" });\n res.end();\n return;\n }\n\n if (url.pathname === \"/live\" || url.pathname === \"/builder\") {\n res.writeHead(302, { location: `${url.pathname}/`, \"cache-control\": \"no-store\" });\n res.end();\n return;\n }\n\n const uiRoute = url.pathname.startsWith(\"/builder/\")\n ? {\n appName: \"Holdpoint Builder\",\n dir: BUILDER_UI_DIR,\n path: url.pathname.replace(/^\\/builder\\/?/, \"\"),\n }\n : url.pathname.startsWith(\"/live/\")\n ? {\n appName: \"Holdpoint Live\",\n dir: LIVE_UI_DIR,\n path: url.pathname.replace(/^\\/live\\/?/, \"\"),\n }\n : null;\n\n if (!uiRoute) {\n res.writeHead(302, { location: \"/live/\", \"cache-control\": \"no-store\" });\n res.end();\n return;\n }\n\n const filePath = resolveUiFilePath(uiRoute.dir, uiRoute.path);\n if (!filePath) {\n servePlaceholder(res, uiRoute.appName);\n return;\n }\n serveUiAsset(res, filePath);\n return;\n }\n\n writeJson(res, 404, { ok: false, error: \"Not found\" });\n }\n\n return {\n host,\n port: actualPort,\n close,\n closed,\n };\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nexport const LIVE_UI_COOKIE = \"holdpoint_live_token\";\n\nfunction parseCookies(raw: string | undefined): Map<string, string> {\n const cookies = new Map<string, string>();\n if (!raw) {\n return cookies;\n }\n\n for (const part of raw.split(\";\")) {\n const [name, ...valueParts] = part.trim().split(\"=\");\n if (!name) continue;\n cookies.set(name, decodeURIComponent(valueParts.join(\"=\")));\n }\n\n return cookies;\n}\n\nfunction getRequestToken(req: IncomingMessage): string | null {\n const auth = req.headers.authorization;\n if (auth?.startsWith(\"Bearer \")) {\n return auth.slice(\"Bearer \".length);\n }\n\n return parseCookies(req.headers.cookie).get(LIVE_UI_COOKIE) ?? null;\n}\n\nexport function writeJson(\n res: ServerResponse,\n statusCode: number,\n body: unknown,\n headers: Record<string, string> = {},\n): void {\n res.writeHead(statusCode, {\n \"cache-control\": \"no-store\",\n \"content-type\": \"application/json; charset=utf-8\",\n ...headers,\n });\n res.end(JSON.stringify(body));\n}\n\nexport async function readJsonBody(req: IncomingMessage): Promise<unknown> {\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));\n }\n if (chunks.length === 0) return null;\n return JSON.parse(Buffer.concat(chunks).toString(\"utf8\"));\n}\n\nexport function authorizeRequest(\n req: IncomingMessage,\n res: ServerResponse,\n token: string,\n port: number,\n): boolean {\n const origin = req.headers.origin;\n if (origin && origin !== `http://127.0.0.1:${port}`) {\n writeJson(res, 403, { ok: false, error: \"Origin not allowed\" });\n return false;\n }\n\n if (getRequestToken(req) !== token) {\n writeJson(res, 401, { ok: false, error: \"Unauthorized\" });\n return false;\n }\n\n return true;\n}\n\nexport function authorizeWebSocket(req: IncomingMessage, token: string, port: number): boolean {\n const origin = req.headers.origin;\n if (origin && origin !== `http://127.0.0.1:${port}`) {\n return false;\n }\n\n if (getRequestToken(req) === token) {\n return true;\n }\n\n const raw = req.headers[\"sec-websocket-protocol\"];\n const protocols = (typeof raw === \"string\" ? [raw] : [])\n .flatMap((entry) => entry.split(\",\"))\n .map((entry) => entry.trim())\n .filter(Boolean);\n\n return protocols.includes(`holdpoint-${token}`);\n}\n\nexport function writeUiAuthCookie(res: ServerResponse, token: string): void {\n res.setHeader(\n \"set-cookie\",\n `${LIVE_UI_COOKIE}=${encodeURIComponent(token)}; Path=/; HttpOnly; SameSite=Strict; Max-Age=3600`,\n );\n}\n","import { appendFile, mkdir, readFile, readdir, rm, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { EventV1, ProjectSummary, SessionSummary } from \"@holdpoint/live-protocol\";\nimport { EventV1Schema } from \"@holdpoint/live-protocol\";\nimport { ConflictTracker } from \"./conflict-tracker.js\";\nimport { identifyProject } from \"./project-identity.js\";\n\ninterface StoredProject extends ProjectSummary {\n root: string;\n}\n\ninterface StoredSession extends SessionSummary {\n events: EventV1[];\n filePath: string;\n}\n\nfunction sessionFileName(engine: string, sessionId: string): string {\n return `${encodeURIComponent(engine)}-${encodeURIComponent(sessionId)}.jsonl`;\n}\n\n/** Best-effort error formatter for the replayPending log lines. */\nfunction describeError(err: unknown): string {\n if (err instanceof Error) return err.message || err.name;\n return String(err);\n}\n\nasync function readJsonl(filePath: string): Promise<EventV1[]> {\n const raw = await readFile(filePath, \"utf8\");\n return raw\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(Boolean)\n .flatMap((line) => {\n try {\n return [EventV1Schema.parse(JSON.parse(line))];\n } catch {\n return [];\n }\n });\n}\n\nexport function buildSessionKey(\n event: Pick<EventV1, \"project_hash\" | \"engine\" | \"session_id\">,\n): string {\n return `${event.project_hash}:${event.engine}:${event.session_id}`;\n}\n\nexport class LiveStore {\n private readonly homeDir: string;\n private readonly projects = new Map<string, StoredProject>();\n private readonly sessions = new Map<string, StoredSession>();\n private readonly projectIdentityCache = new Map<string, ReturnType<typeof identifyProject>>();\n private readonly conflictTracker = new ConflictTracker();\n private nextSeq = 1;\n\n private constructor(homeDir: string) {\n this.homeDir = homeDir;\n }\n\n static async create(homeDir: string): Promise<LiveStore> {\n const store = new LiveStore(homeDir);\n await store.hydrate();\n return store;\n }\n\n async replayPending(): Promise<void> {\n const pendingDir = join(this.homeDir, \"spool\", \"pending\");\n if (!existsSync(pendingDir)) return;\n let entries: string[];\n try {\n entries = await readdir(pendingDir);\n } catch (err) {\n // Pending dir disappeared between existsSync and readdir, or\n // permissions changed underneath us. Not worth crashing for.\n console.error(`[holdpoint] failed to read pending dir: ${describeError(err)}`);\n return;\n }\n for (const entry of entries.filter((name) => name.endsWith(\".jsonl\"))) {\n const filePath = join(pendingDir, entry);\n let events: EventV1[] = [];\n try {\n events = await readJsonl(filePath);\n } catch (err) {\n console.error(`[holdpoint] failed to read pending file ${entry}: ${describeError(err)}`);\n }\n // Per-event try/catch — one malformed payload (e.g. a project_hash\n // pointing at a now-deleted cwd) must not poison the whole replay\n // and brick daemon startup forever. Failed events are logged and\n // dropped; the file is removed unconditionally at the end so a bad\n // payload can't loop on every restart.\n for (const event of events) {\n try {\n await this.ingest(event);\n } catch (err) {\n console.error(`[holdpoint] dropped pending event from ${entry}: ${describeError(err)}`);\n }\n }\n try {\n await rm(filePath, { force: true });\n } catch (err) {\n // Failing to delete the file means we'll re-process it next\n // startup; everything we just did was idempotent so that's\n // tolerable. Log so it's visible if it keeps happening.\n console.error(`[holdpoint] failed to remove pending file ${entry}: ${describeError(err)}`);\n }\n }\n }\n\n async ingestMany(events: EventV1[]): Promise<EventV1[]> {\n const accepted: EventV1[] = [];\n for (const event of events) {\n accepted.push(...(await this.ingest(event)));\n }\n return accepted;\n }\n\n async ingest(event: EventV1): Promise<EventV1[]> {\n const accepted: EventV1[] = [];\n const storedPrimary = await this.persistEvent(event);\n accepted.push(storedPrimary);\n\n for (const derivedEvent of this.conflictTracker.handleEvent(storedPrimary)) {\n accepted.push(await this.persistEvent(derivedEvent));\n }\n\n return accepted;\n }\n\n listProjects(): ProjectSummary[] {\n return [...this.projects.values()].sort((a, b) => b.last_active - a.last_active);\n }\n\n listSessions(projectHash?: string): SessionSummary[] {\n return [...this.sessions.values()]\n .filter((session) => !projectHash || session.project_hash === projectHash)\n .sort((a, b) => b.last_event_at - a.last_event_at)\n .map(({ events: _events, filePath: _filePath, ...summary }) => summary);\n }\n\n getSessionEvents(sessionKey: string, sinceSeq = 0, limit = 500): EventV1[] {\n const session = this.sessions.get(sessionKey);\n if (!session) return [];\n return session.events.filter((event) => (event.seq ?? 0) > sinceSeq).slice(-limit);\n }\n\n getProjectEvents(projectHash: string, sinceSeq = 0, limit = 500): EventV1[] {\n return [...this.sessions.values()]\n .filter((session) => session.project_hash === projectHash)\n .flatMap((session) => session.events)\n .filter((event) => (event.seq ?? 0) > sinceSeq)\n .sort((left, right) => (left.seq ?? 0) - (right.seq ?? 0))\n .slice(-limit);\n }\n\n getAllEvents(sinceSeq = 0, limit = 1_000): EventV1[] {\n return [...this.sessions.values()]\n .flatMap((session) => session.events)\n .filter((event) => (event.seq ?? 0) > sinceSeq)\n .sort((left, right) => (left.seq ?? 0) - (right.seq ?? 0))\n .slice(-limit);\n }\n\n getLatestSeq(projectHash?: string): number {\n const sessions = [...this.sessions.values()].filter(\n (session) => !projectHash || session.project_hash === projectHash,\n );\n return sessions.reduce((maxSeq, session) => Math.max(maxSeq, session.last_seq ?? 0), 0);\n }\n\n getSessionLatestSeq(sessionKey: string): number {\n return this.sessions.get(sessionKey)?.last_seq ?? 0;\n }\n\n getSessionSummary(sessionKey: string): SessionSummary | null {\n const session = this.sessions.get(sessionKey);\n if (!session) return null;\n return {\n key: session.key,\n project_hash: session.project_hash,\n engine: session.engine,\n session_id: session.session_id,\n cwd: session.cwd,\n last_event_at: session.last_event_at,\n last_seq: session.last_seq,\n event_count: session.event_count,\n caps: session.caps,\n };\n }\n\n async purgeSession(sessionKey: string): Promise<boolean> {\n const session = this.sessions.get(sessionKey);\n if (!session) return false;\n this.sessions.delete(sessionKey);\n await rm(session.filePath, { force: true });\n\n const project = this.projects.get(session.project_hash);\n if (!project) {\n return true;\n }\n\n const remainingSessions = [...this.sessions.values()].filter(\n (candidate) => candidate.project_hash === session.project_hash,\n );\n if (remainingSessions.length === 0) {\n this.projects.delete(session.project_hash);\n return true;\n }\n\n project.session_count = remainingSessions.length;\n project.last_active = remainingSessions.reduce(\n (latest, candidate) => Math.max(latest, candidate.last_event_at),\n 0,\n );\n\n const projectDir = join(this.homeDir, \"sessions\", session.project_hash);\n await writeFile(join(projectDir, \"meta.json\"), JSON.stringify(project, null, 2) + \"\\n\", {\n encoding: \"utf8\",\n mode: 0o600,\n });\n return true;\n }\n\n private async persistEvent(event: EventV1): Promise<EventV1> {\n const storedEvent: EventV1 = {\n ...event,\n seq: event.seq ?? this.nextSeq++,\n };\n\n this.upsertProject(storedEvent);\n const session = this.upsertSession(storedEvent);\n const projectDir = join(this.homeDir, \"sessions\", storedEvent.project_hash);\n await mkdir(projectDir, { recursive: true, mode: 0o700 });\n await appendFile(session.filePath, JSON.stringify(storedEvent) + \"\\n\", {\n encoding: \"utf8\",\n mode: 0o600,\n });\n await writeFile(\n join(projectDir, \"meta.json\"),\n JSON.stringify(this.projects.get(storedEvent.project_hash), null, 2) + \"\\n\",\n { encoding: \"utf8\", mode: 0o600 },\n );\n\n return storedEvent;\n }\n\n private upsertProject(event: EventV1): void {\n const identity = this.getProjectIdentity(event.cwd);\n const existing = this.projects.get(event.project_hash);\n const sessionCount = existing?.session_count ?? 0;\n this.projects.set(event.project_hash, {\n project_hash: event.project_hash,\n name: existing?.name ?? identity.name,\n root: existing?.root ?? identity.root,\n last_active: Math.max(existing?.last_active ?? 0, event.ts),\n session_count: sessionCount,\n });\n }\n\n private upsertSession(event: EventV1): StoredSession {\n const key = buildSessionKey(event);\n const existing = this.sessions.get(key);\n const filePath =\n existing?.filePath ??\n join(\n this.homeDir,\n \"sessions\",\n event.project_hash,\n sessionFileName(event.engine, event.session_id),\n );\n const events = [...(existing?.events ?? []), event];\n const session: StoredSession = {\n key,\n project_hash: event.project_hash,\n engine: event.engine,\n session_id: event.session_id,\n cwd: event.cwd,\n last_event_at: event.ts,\n last_seq: event.seq,\n event_count: events.length,\n caps: event.caps ?? existing?.caps,\n events,\n filePath,\n };\n this.sessions.set(key, session);\n\n const project = this.projects.get(event.project_hash);\n if (project) {\n project.session_count = [...this.sessions.values()].filter(\n (candidate) => candidate.project_hash === event.project_hash,\n ).length;\n project.last_active = Math.max(project.last_active, event.ts);\n }\n\n return session;\n }\n\n private getProjectIdentity(cwd: string): ReturnType<typeof identifyProject> {\n const cached = this.projectIdentityCache.get(cwd);\n if (cached) {\n return cached;\n }\n const identity = identifyProject(cwd);\n this.projectIdentityCache.set(cwd, identity);\n return identity;\n }\n\n private async hydrate(): Promise<void> {\n const sessionsRoot = join(this.homeDir, \"sessions\");\n if (!existsSync(sessionsRoot)) return;\n\n const projectEntries = await readdir(sessionsRoot, { withFileTypes: true });\n for (const projectDirEntry of projectEntries) {\n if (!projectDirEntry.isDirectory()) continue;\n const projectHash = projectDirEntry.name;\n const projectDir = join(sessionsRoot, projectHash);\n const files = await readdir(projectDir);\n let loadedProject: StoredProject | undefined;\n const metaPath = join(projectDir, \"meta.json\");\n if (existsSync(metaPath)) {\n try {\n loadedProject = JSON.parse(await readFile(metaPath, \"utf8\")) as StoredProject;\n } catch {\n loadedProject = undefined;\n }\n }\n\n for (const file of files.filter((entry) => entry.endsWith(\".jsonl\"))) {\n const filePath = join(projectDir, file);\n const rawEvents = await readJsonl(filePath);\n if (rawEvents.length === 0) continue;\n\n const events = rawEvents\n .sort((left, right) => {\n const leftSeq = left.seq ?? 0;\n const rightSeq = right.seq ?? 0;\n if (leftSeq !== rightSeq) return leftSeq - rightSeq;\n return left.ts - right.ts;\n })\n .map((event) => {\n const seq = event.seq ?? this.nextSeq++;\n this.nextSeq = Math.max(this.nextSeq, seq + 1);\n return {\n ...event,\n seq,\n };\n });\n\n const first = events[0];\n const last = events[events.length - 1];\n if (!first || !last) continue;\n const key = buildSessionKey(first);\n this.sessions.set(key, {\n key,\n project_hash: first.project_hash,\n engine: first.engine,\n session_id: first.session_id,\n cwd: first.cwd,\n last_event_at: last.ts,\n last_seq: last.seq,\n event_count: events.length,\n caps: last.caps,\n events,\n filePath,\n });\n\n if (!loadedProject) {\n const identity = this.getProjectIdentity(first.cwd);\n loadedProject = {\n project_hash: first.project_hash,\n name: identity.name,\n root: identity.root,\n last_active: last.ts,\n session_count: 0,\n };\n } else {\n loadedProject.last_active = Math.max(loadedProject.last_active, last.ts);\n }\n }\n\n if (loadedProject) {\n loadedProject.session_count = [...this.sessions.values()].filter(\n (session) => session.project_hash === projectHash,\n ).length;\n this.projects.set(projectHash, loadedProject);\n }\n }\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync, realpathSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { EventV1 } from \"@holdpoint/live-protocol\";\n\nconst DEFAULT_LOCK_TTL_MS = 30_000;\n\ninterface FileLock {\n sessionKey: string;\n engine: string;\n sessionId: string;\n expiresAt: number;\n}\n\ntype LockEvent = Extract<EventV1, { type: \"tool_pre\" | \"tool_post\" | \"tool_failure\" }>;\n\nfunction buildSessionKey(event: Pick<EventV1, \"project_hash\" | \"engine\" | \"session_id\">): string {\n return `${event.project_hash}:${event.engine}:${event.session_id}`;\n}\n\nfunction normalizeWriteTarget(cwd: string, target: string): string {\n const resolved = resolve(cwd, target);\n return existsSync(resolved) ? realpathSync.native(resolved) : resolved;\n}\n\nfunction getWriteTargets(event: LockEvent, activeTargets: Map<string, string[]>): string[] {\n const toolKey = `${buildSessionKey(event)}:${event.payload.tool_use_id}`;\n if (event.type === \"tool_pre\") {\n return (event.payload.write_targets ?? []).map((target: string) =>\n normalizeWriteTarget(event.cwd, target),\n );\n }\n\n return (\n (event.type === \"tool_post\"\n ? event.payload.write_targets?.map((target: string) =>\n normalizeWriteTarget(event.cwd, target),\n )\n : undefined) ??\n activeTargets.get(toolKey) ??\n []\n );\n}\n\nexport class ConflictTracker {\n private readonly lockTtlMs: number;\n private readonly locksByProject = new Map<string, Map<string, FileLock>>();\n private readonly activeTargets = new Map<string, string[]>();\n private readonly emittedConflicts = new Map<string, number>();\n\n constructor(lockTtlMs = DEFAULT_LOCK_TTL_MS) {\n this.lockTtlMs = lockTtlMs;\n }\n\n handleEvent(event: EventV1): EventV1[] {\n switch (event.type) {\n case \"tool_pre\":\n return this.handleToolPre(event);\n case \"tool_post\":\n case \"tool_failure\":\n this.releaseLocks(event);\n return [];\n default:\n return [];\n }\n }\n\n private handleToolPre(event: Extract<EventV1, { type: \"tool_pre\" }>): EventV1[] {\n const sessionKey = buildSessionKey(event);\n const toolKey = `${sessionKey}:${event.payload.tool_use_id}`;\n const writeTargets = getWriteTargets(event, this.activeTargets);\n if (writeTargets.length === 0) {\n return [];\n }\n\n this.activeTargets.set(toolKey, writeTargets);\n const projectLocks = this.getProjectLocks(event.project_hash);\n this.pruneExpiredLocks(projectLocks, event.ts);\n\n const conflicts: EventV1[] = [];\n for (const filePath of writeTargets) {\n const existing = projectLocks.get(filePath);\n if (!existing) {\n projectLocks.set(filePath, {\n sessionKey,\n engine: event.engine,\n sessionId: event.session_id,\n expiresAt: event.ts + this.lockTtlMs,\n });\n continue;\n }\n\n if (existing.sessionKey === sessionKey) {\n existing.expiresAt = event.ts + this.lockTtlMs;\n continue;\n }\n\n const dedupeKey = `${event.project_hash}:${filePath}:${existing.sessionKey}:${sessionKey}`;\n const previousEmission = this.emittedConflicts.get(dedupeKey) ?? 0;\n if (previousEmission > event.ts) {\n continue;\n }\n\n this.emittedConflicts.set(dedupeKey, event.ts + this.lockTtlMs);\n conflicts.push({\n v: 1,\n id: randomUUID(),\n ts: event.ts,\n engine: event.engine,\n session_id: event.session_id,\n project_hash: event.project_hash,\n cwd: event.cwd,\n type: \"conflict\",\n payload: {\n kind: \"file_write\",\n file_path: filePath,\n holder: {\n engine: existing.engine,\n session_id: existing.sessionId,\n },\n requester: {\n engine: event.engine,\n session_id: event.session_id,\n },\n },\n });\n }\n\n return conflicts;\n }\n\n private releaseLocks(event: Extract<EventV1, { type: \"tool_post\" | \"tool_failure\" }>): void {\n const sessionKey = buildSessionKey(event);\n const toolKey = `${sessionKey}:${event.payload.tool_use_id}`;\n const projectLocks = this.getProjectLocks(event.project_hash);\n const writeTargets = getWriteTargets(event, this.activeTargets);\n\n for (const filePath of writeTargets) {\n const existing = projectLocks.get(filePath);\n if (existing?.sessionKey === sessionKey) {\n projectLocks.delete(filePath);\n }\n }\n\n this.activeTargets.delete(toolKey);\n this.pruneExpiredLocks(projectLocks, event.ts);\n }\n\n private getProjectLocks(projectHash: string): Map<string, FileLock> {\n let existing = this.locksByProject.get(projectHash);\n if (!existing) {\n existing = new Map<string, FileLock>();\n this.locksByProject.set(projectHash, existing);\n }\n return existing;\n }\n\n private pruneExpiredLocks(projectLocks: Map<string, FileLock>, now: number): void {\n for (const [filePath, lock] of projectLocks.entries()) {\n if (lock.expiresAt <= now) {\n projectLocks.delete(filePath);\n }\n }\n\n for (const [key, expiresAt] of this.emittedConflicts.entries()) {\n if (expiresAt <= now) {\n this.emittedConflicts.delete(key);\n }\n }\n }\n}\n","import { execFileSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { realpathSync } from \"node:fs\";\nimport { basename } from \"node:path\";\n\nexport interface ProjectIdentity {\n hash: string;\n name: string;\n root: string;\n}\n\nfunction sha12(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\").slice(0, 12);\n}\n\nexport function identifyProject(cwd: string): ProjectIdentity {\n // Three layers of fallback, in order of preference:\n // 1. git rev-parse --show-toplevel + realpath — canonical: matches\n // whatever git considers the repo root, normalised through symlinks.\n // 2. realpath(cwd) — cwd exists but isn't\n // a git repo (or git binary missing); use the resolved cwd as root.\n // 3. raw cwd string — cwd doesn't exist\n // on disk anymore (deleted/renamed project; common when replaying\n // old pending events from `~/.holdpoint/spool/pending`). The daemon\n // still needs a stable identity so the event can be stored and\n // surfaced; the hash/name are based on the literal path.\n //\n // This function MUST NOT throw. The daemon's startup replay loop ingests\n // historical events from disk and crashing here used to brick startup\n // entirely whenever a project path had been renamed since the events\n // were spooled — see https://github.com/holdpoint-dev/holdpoint/issues\n // (daemon-unavailable on stale pending events).\n let root: string;\n try {\n root = realpathSync(\n execFileSync(\"git\", [\"rev-parse\", \"--show-toplevel\"], {\n cwd,\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim(),\n );\n } catch {\n try {\n root = realpathSync(cwd);\n } catch {\n // cwd doesn't exist on disk — use the raw path string as identity.\n root = cwd;\n }\n }\n return {\n hash: sha12(root),\n name: basename(root) || root,\n root,\n };\n}\n","import type { EventV1 } from \"@holdpoint/live-protocol\";\nimport { buildSessionKey } from \"./store.js\";\n\nexport interface Subscription {\n scope: \"project\" | \"session\" | \"all\";\n key?: string;\n}\n\nexport function matchesSubscription(subscription: Subscription, event: EventV1): boolean {\n switch (subscription.scope) {\n case \"all\":\n return true;\n case \"project\":\n return subscription.key === event.project_hash;\n case \"session\":\n return subscription.key === buildSessionKey(event);\n }\n}\n","import {\n removeDaemonLock,\n createDaemonLock,\n findFreePort,\n readHealthyDaemonLock,\n type DaemonLock,\n writeDaemonLockExclusive,\n resolveHoldpointHome,\n} from \"./singleton.js\";\nimport { startLiveServer, type RunningLiveServer } from \"./server.js\";\nimport { LiveStore } from \"./store.js\";\n\nexport class DaemonAlreadyRunningError extends Error {\n readonly info: DaemonLock;\n\n constructor(info: DaemonLock) {\n super(`Holdpoint daemon already running on port ${info.port}`);\n this.info = info;\n }\n}\n\nexport interface StartDaemonProcessOptions {\n homeDir?: string;\n port?: number;\n version: string;\n}\n\nexport interface StartedDaemon {\n info: DaemonLock;\n server: RunningLiveServer;\n store: LiveStore;\n close(): Promise<void>;\n closed: Promise<void>;\n}\n\nexport async function startDaemonProcess(\n options: StartDaemonProcessOptions,\n): Promise<StartedDaemon> {\n const existing = await readHealthyDaemonLock(options.homeDir);\n if (existing) {\n throw new DaemonAlreadyRunningError(existing);\n }\n\n const port = options.port ?? (await findFreePort());\n const info = createDaemonLock(port, options.version);\n writeDaemonLockExclusive(info, options.homeDir);\n\n const store = await LiveStore.create(resolveHoldpointHome(options.homeDir));\n await store.replayPending();\n\n let server: RunningLiveServer;\n try {\n server = await startLiveServer({\n port,\n token: info.token,\n version: options.version,\n startedAt: info.started_at,\n store,\n });\n } catch (error) {\n removeDaemonLock(options.homeDir, info.token);\n throw error;\n }\n\n let closed = false;\n const cleanup = async (): Promise<void> => {\n if (closed) return;\n closed = true;\n removeDaemonLock(options.homeDir, info.token);\n await server.close();\n };\n\n const onSignal = (): void => {\n void cleanup().finally(() => process.exit(0));\n };\n\n process.once(\"SIGTERM\", onSignal);\n process.once(\"SIGINT\", onSignal);\n\n return {\n info,\n server,\n store,\n close: cleanup,\n closed: server.closed.finally(() => {\n process.off(\"SIGTERM\", onSignal);\n process.off(\"SIGINT\", onSignal);\n }),\n };\n}\n\nexport {\n createDaemonLock,\n ensureHoldpointHome,\n findFreePort,\n getDaemonLockPath,\n isProcessAlive,\n readDaemonLock,\n readHealthyDaemonLock,\n removeDaemonLock,\n resolveHoldpointHome,\n waitForDaemonHealthy,\n writeDaemonLockExclusive,\n} from \"./singleton.js\";\nexport { identifyProject } from \"./project-identity.js\";\nexport { startLiveServer } from \"./server.js\";\nexport { buildSessionKey, LiveStore } from \"./store.js\";\nexport type { ProjectIdentity } from \"./project-identity.js\";\nexport type { RunningLiveServer } from \"./server.js\";\nexport type { DaemonLock } from \"./singleton.js\";\n"],"mappings":"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","names":["createServer","randomUUID","existsSync","join","resolve","EventV1Schema","existsSync","join","existsSync","resolve","realpathSync","buildSessionKey","join","existsSync","buildSessionKey","join","randomUUID","resolve","existsSync","createServer","EventV1Schema"]}
1
+ {"version":3,"sources":["../src/singleton.ts","../src/server.ts","../src/auth.ts","../src/store.ts","../src/conflict-tracker.ts","../src/project-identity.ts","../src/router.ts","../src/index.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { createServer } from \"node:net\";\nimport os from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport { z } from \"zod\";\n\nexport const DaemonLockSchema = z.object({\n version: z.string().min(1),\n pid: z.number().int().positive(),\n port: z.number().int().positive(),\n token: z.string().min(1),\n started_at: z.number().int().nonnegative(),\n host: z.string().min(1),\n});\n\nexport type DaemonLock = z.infer<typeof DaemonLockSchema>;\n\nexport function resolveHoldpointHome(homeDir?: string): string {\n return resolve(homeDir ?? process.env.HOLDPOINT_HOME ?? join(os.homedir(), \".holdpoint\"));\n}\n\nexport function ensureHoldpointHome(homeDir?: string): string {\n const root = resolveHoldpointHome(homeDir);\n mkdirSync(root, { recursive: true, mode: 0o700 });\n return root;\n}\n\nexport function getDaemonLockPath(homeDir?: string): string {\n return join(resolveHoldpointHome(homeDir), \"daemon.lock\");\n}\n\nexport function readDaemonLock(homeDir?: string): DaemonLock | null {\n const lockPath = getDaemonLockPath(homeDir);\n if (!existsSync(lockPath)) return null;\n try {\n return DaemonLockSchema.parse(JSON.parse(readFileSync(lockPath, \"utf8\")));\n } catch {\n return null;\n }\n}\n\nexport function isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function findFreePort(host = \"127.0.0.1\"): Promise<number> {\n return await new Promise<number>((resolvePromise, reject) => {\n const server = createServer();\n server.listen(0, host, () => {\n const address = server.address();\n if (!address || typeof address === \"string\") {\n server.close();\n reject(new Error(\"Expected TCP address\"));\n return;\n }\n const { port } = address;\n server.close((err) => {\n if (err) reject(err);\n else resolvePromise(port);\n });\n });\n server.on(\"error\", reject);\n });\n}\n\nexport function createDaemonLock(port: number, version: string): DaemonLock {\n return {\n version,\n pid: process.pid,\n port,\n token: randomBytes(32).toString(\"hex\"),\n started_at: Date.now(),\n host: `${os.platform()}-${os.arch()}`,\n };\n}\n\nexport function writeDaemonLockExclusive(lock: DaemonLock, homeDir?: string): void {\n ensureHoldpointHome(homeDir);\n writeFileSync(getDaemonLockPath(homeDir), JSON.stringify(lock, null, 2) + \"\\n\", {\n encoding: \"utf8\",\n flag: \"wx\",\n mode: 0o600,\n });\n}\n\nexport function removeDaemonLock(homeDir?: string, expectedToken?: string): void {\n const lockPath = getDaemonLockPath(homeDir);\n if (!existsSync(lockPath)) return;\n if (expectedToken) {\n const lock = readDaemonLock(homeDir);\n if (!lock || lock.token !== expectedToken) {\n return;\n }\n }\n try {\n unlinkSync(lockPath);\n } catch {\n /* ignore cleanup races */\n }\n}\n\nasync function fetchHealth(port: number, timeoutMs: number): Promise<boolean> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: controller.signal,\n });\n return response.ok;\n } catch {\n return false;\n } finally {\n clearTimeout(timeout);\n }\n}\n\nexport async function waitForDaemonHealthy(\n lock: DaemonLock,\n timeoutMs = 5_000,\n pollMs = 100,\n): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (await fetchHealth(lock.port, Math.min(pollMs, timeoutMs))) {\n return true;\n }\n await new Promise((resolvePromise) => setTimeout(resolvePromise, pollMs));\n }\n return false;\n}\n\nexport async function readHealthyDaemonLock(homeDir?: string): Promise<DaemonLock | null> {\n const lock = readDaemonLock(homeDir);\n if (!lock) return null;\n if (!isProcessAlive(lock.pid)) {\n removeDaemonLock(homeDir);\n return null;\n }\n if (!(await waitForDaemonHealthy(lock, 300, 100))) {\n removeDaemonLock(homeDir);\n return null;\n }\n return lock;\n}\n","import { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\nimport { createReadStream, existsSync, renameSync, writeFileSync } from \"node:fs\";\nimport { dirname, extname, join, resolve, sep } from \"node:path\";\nimport { fileURLToPath, URL } from \"node:url\";\nimport type { EventV1, ServerMessage } from \"@holdpoint/live-protocol\";\nimport {\n ClientMessageSchema,\n ControlRequestSchema,\n EventV1Schema,\n EventsBatchSchema,\n} from \"@holdpoint/live-protocol\";\nimport { parseHoldpointYaml } from \"@holdpoint/yaml-core\";\nimport { WebSocket, WebSocketServer, type RawData } from \"ws\";\nimport {\n authorizeRequest,\n authorizeWebSocket,\n readJsonBody,\n readTextBody,\n writeJson,\n writeUiAuthCookie,\n} from \"./auth.js\";\nimport { matchesSubscription, type Subscription } from \"./router.js\";\nimport type { LiveStore } from \"./store.js\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst LIVE_UI_DIR = join(__dirname, \"live-ui\");\nconst CONTENT_SECURITY_POLICY =\n \"default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; connect-src 'self' ws: http:; object-src 'none'; base-uri 'none'; frame-ancestors 'none'\";\nconst MIME: Record<string, string> = {\n \".css\": \"text/css; charset=utf-8\",\n \".html\": \"text/html; charset=utf-8\",\n \".ico\": \"image/x-icon\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".png\": \"image/png\",\n \".svg\": \"image/svg+xml\",\n};\n\nexport interface StartLiveServerOptions {\n host?: string;\n port: number;\n token: string;\n version: string;\n startedAt: number;\n store: LiveStore;\n}\n\nexport interface RunningLiveServer {\n host: string;\n port: number;\n close(): Promise<void>;\n closed: Promise<void>;\n}\n\ninterface RegisteredProject {\n hash: string;\n name?: string;\n root: string;\n}\n\nfunction sendSocketMessage(socket: WebSocket, message: ServerMessage): void {\n socket.send(JSON.stringify(message));\n}\n\nfunction decodeRawData(raw: RawData): string {\n if (typeof raw === \"string\") return raw;\n if (raw instanceof Buffer) return raw.toString(\"utf8\");\n if (Array.isArray(raw)) return Buffer.concat(raw).toString(\"utf8\");\n return Buffer.from(new Uint8Array(raw)).toString(\"utf8\");\n}\n\nfunction getEventsForScope(\n store: LiveStore,\n subscription: Subscription,\n sinceSeq: number,\n): EventV1[] {\n switch (subscription.scope) {\n case \"all\":\n return store.getAllEvents(sinceSeq);\n case \"project\":\n return subscription.key ? store.getProjectEvents(subscription.key, sinceSeq) : [];\n case \"session\":\n return subscription.key ? store.getSessionEvents(subscription.key, sinceSeq) : [];\n }\n}\n\nfunction buildControlStateEvent(\n session: {\n project_hash: string;\n engine: string;\n session_id: string;\n cwd: string;\n caps?: EventV1[\"caps\"];\n },\n controlOnline: boolean,\n): EventV1 {\n return {\n v: 1,\n id: randomUUID(),\n ts: Date.now(),\n engine: session.engine,\n session_id: session.session_id,\n project_hash: session.project_hash,\n cwd: session.cwd,\n caps: {\n ...(session.caps ?? {}),\n can_control: session.caps?.can_control ?? true,\n control_online: controlOnline,\n },\n type: \"meta\",\n payload: {\n kind: controlOnline ? \"control_socket_registered\" : \"control_socket_disconnected\",\n },\n };\n}\n\nfunction servePlaceholder(res: ServerResponse, appName = \"Holdpoint Live\"): void {\n res.writeHead(200, {\n \"cache-control\": \"no-store\",\n \"content-security-policy\": CONTENT_SECURITY_POLICY,\n \"content-type\": \"text/html; charset=utf-8\",\n });\n res.end(\n `<!doctype html><title>${appName}</title><body style=\"font-family:system-ui;background:#0b0f14;color:#f5f1e8;padding:32px\"><h1>${appName}</h1><p>UI assets were not found in this build. Rebuild the monorepo with <code>pnpm turbo build</code>.</p></body>`,\n );\n}\n\nfunction serveUiAsset(res: ServerResponse, filePath: string): void {\n const mime = MIME[extname(filePath)] ?? \"application/octet-stream\";\n const headers: Record<string, string> = {\n \"cache-control\": \"no-store\",\n \"content-type\": mime,\n };\n if (filePath.endsWith(\".html\")) {\n headers[\"content-security-policy\"] = CONTENT_SECURITY_POLICY;\n }\n res.writeHead(200, headers);\n createReadStream(filePath).pipe(res);\n}\n\nfunction isWithinRoot(candidate: string, root: string): boolean {\n return candidate === root || candidate.startsWith(root + sep);\n}\n\nfunction resolveUiFilePath(uiDir: string, requestedPath: string): string | null {\n const requested = requestedPath === \"\" || requestedPath === \"/\" ? \"index.html\" : requestedPath;\n const candidate = resolve(uiDir, requested.replace(/^\\//, \"\"));\n if (!isWithinRoot(candidate, uiDir)) {\n return null;\n }\n if (existsSync(candidate)) {\n return candidate;\n }\n return existsSync(join(uiDir, \"index.html\")) ? join(uiDir, \"index.html\") : null;\n}\n\n/**\n * The Builder is now a tab inside the unified Live UI, so any `/builder` intent\n * folds into `/live/` with a `tab=checks` hint instead of a separate app.\n */\nfunction normalizeUiPath(path: string | null): { pathname: \"/live/\"; tab?: \"checks\" } {\n if (path === \"/builder\" || path?.startsWith(\"/builder/\")) {\n return { pathname: \"/live/\", tab: \"checks\" };\n }\n return { pathname: \"/live/\" };\n}\n\nfunction registerProjectFromAuthUrl(\n url: URL,\n registeredProjects: Map<string, RegisteredProject>,\n): void {\n const hash = url.searchParams.get(\"project\");\n const root = url.searchParams.get(\"root\");\n if (!hash || !root || root.includes(\"\\0\")) {\n return;\n }\n const name = url.searchParams.get(\"name\");\n registeredProjects.set(hash, {\n hash,\n ...(name ? { name } : {}),\n root: resolve(root),\n });\n}\n\nfunction getProjectForRequest(\n url: URL,\n registeredProjects: Map<string, RegisteredProject>,\n): RegisteredProject | null {\n const hash = url.searchParams.get(\"project\");\n if (hash) {\n return registeredProjects.get(hash) ?? null;\n }\n if (registeredProjects.size === 1) {\n return [...registeredProjects.values()][0] ?? null;\n }\n return null;\n}\n\nexport async function startLiveServer(options: StartLiveServerOptions): Promise<RunningLiveServer> {\n const host = options.host ?? \"127.0.0.1\";\n const subscriptions = new Map<WebSocket, Subscription[]>();\n const controlSockets = new Map<string, WebSocket>();\n const socketControlKeys = new Map<WebSocket, Set<string>>();\n const registeredProjects = new Map<string, RegisteredProject>();\n const server = createServer((req, res) => {\n void handleRequest(req, res, options, subscriptions, registeredProjects).catch(\n (error: unknown) => {\n writeJson(res, 500, { ok: false, error: (error as Error).message });\n },\n );\n });\n const wss = new WebSocketServer({ noServer: true });\n\n const broadcastEvent = (event: EventV1): void => {\n for (const [socket, socketSubscriptions] of subscriptions.entries()) {\n if (socket.readyState !== WebSocket.OPEN) continue;\n if (socketSubscriptions.some((subscription) => matchesSubscription(subscription, event))) {\n sendSocketMessage(socket, { type: \"event\", event });\n }\n }\n };\n\n const ingestAndBroadcast = async (event: EventV1): Promise<EventV1[]> => {\n const accepted = await options.store.ingest(event);\n for (const acceptedEvent of accepted) {\n broadcastEvent(acceptedEvent);\n }\n return accepted;\n };\n\n const emitControlState = async (sessionKey: string, controlOnline: boolean): Promise<void> => {\n const summary = options.store.getSessionSummary(sessionKey);\n if (!summary) return;\n await ingestAndBroadcast(buildControlStateEvent(summary, controlOnline));\n };\n\n const registerControlSocket = async (sessionKey: string, socket: WebSocket): Promise<void> => {\n const previous = controlSockets.get(sessionKey);\n if (previous && previous !== socket) {\n socketControlKeys.get(previous)?.delete(sessionKey);\n }\n controlSockets.set(sessionKey, socket);\n const keys = socketControlKeys.get(socket) ?? new Set<string>();\n keys.add(sessionKey);\n socketControlKeys.set(socket, keys);\n await emitControlState(sessionKey, true);\n };\n\n const unregisterControlSocket = async (sessionKey: string, socket: WebSocket): Promise<void> => {\n if (controlSockets.get(sessionKey) !== socket) return;\n controlSockets.delete(sessionKey);\n const keys = socketControlKeys.get(socket);\n keys?.delete(sessionKey);\n if (keys && keys.size === 0) {\n socketControlKeys.delete(socket);\n }\n await emitControlState(sessionKey, false);\n };\n\n const unregisterSocketControls = async (socket: WebSocket): Promise<void> => {\n const keys = [...(socketControlKeys.get(socket) ?? [])];\n for (const sessionKey of keys) {\n await unregisterControlSocket(sessionKey, socket);\n }\n };\n\n wss.on(\"connection\", (socket: WebSocket) => {\n subscriptions.set(socket, []);\n socket.on(\"message\", (raw: RawData) => {\n void (async () => {\n let message: unknown;\n try {\n message = JSON.parse(decodeRawData(raw));\n } catch {\n sendSocketMessage(socket, {\n type: \"error\",\n code: \"invalid_json\",\n message: \"Expected JSON message\",\n });\n return;\n }\n\n const parsed = ClientMessageSchema.safeParse(message);\n if (!parsed.success) {\n sendSocketMessage(socket, {\n type: \"error\",\n code: \"invalid_message\",\n message: parsed.error.issues[0]?.message ?? \"Invalid message\",\n });\n return;\n }\n\n switch (parsed.data.type) {\n case \"subscribe\": {\n if (parsed.data.scope !== \"all\" && !parsed.data.key) {\n sendSocketMessage(socket, {\n type: \"error\",\n code: \"missing_key\",\n message: \"Expected a key for session/project subscriptions\",\n });\n return;\n }\n\n const subscription =\n parsed.data.key !== undefined\n ? { scope: parsed.data.scope, key: parsed.data.key }\n : { scope: parsed.data.scope };\n const next = subscriptions.get(socket) ?? [];\n next.push(subscription);\n subscriptions.set(socket, next);\n\n const backlog = getEventsForScope(\n options.store,\n subscription,\n parsed.data.since_seq ?? 0,\n );\n if (backlog.length > 0) {\n sendSocketMessage(socket, { type: \"events_batch\", events: backlog });\n }\n sendSocketMessage(socket, {\n type: \"ack\",\n for: parsed.data.scope === \"all\" ? \"all\" : (parsed.data.key ?? parsed.data.scope),\n });\n break;\n }\n case \"register_control\": {\n await registerControlSocket(parsed.data.session_key, socket);\n sendSocketMessage(socket, { type: \"ack\", for: parsed.data.session_key });\n break;\n }\n case \"unsubscribe\": {\n const key = parsed.data.key;\n const next = (subscriptions.get(socket) ?? []).filter(\n (subscription) => subscription.key !== key,\n );\n subscriptions.set(socket, next);\n sendSocketMessage(socket, { type: \"ack\", for: key });\n break;\n }\n case \"publish_event\": {\n const accepted = await options.store.ingest(parsed.data.event);\n for (const event of accepted) {\n broadcastEvent(event);\n }\n sendSocketMessage(socket, { type: \"ack\", for: parsed.data.event.id });\n break;\n }\n case \"ping\":\n sendSocketMessage(socket, { type: \"pong\" });\n break;\n }\n })();\n });\n\n socket.on(\"close\", () => {\n subscriptions.delete(socket);\n void unregisterSocketControls(socket).catch(() => {});\n });\n });\n\n server.on(\"upgrade\", (req, socket, head) => {\n const url = new URL(req.url ?? \"/\", `http://${host}:${options.port}`);\n if (url.pathname !== \"/v1/stream\" || !authorizeWebSocket(req, options.token, options.port)) {\n socket.write(\"HTTP/1.1 401 Unauthorized\\r\\n\\r\\n\");\n socket.destroy();\n return;\n }\n\n wss.handleUpgrade(req, socket, head, (ws: WebSocket) => {\n wss.emit(\"connection\", ws, req);\n });\n });\n\n await new Promise<void>((resolvePromise, reject) => {\n server.listen(options.port, host, resolvePromise);\n server.on(\"error\", reject);\n });\n\n const address = server.address();\n if (!address || typeof address === \"string\") {\n throw new Error(\"Expected TCP address\");\n }\n const actualPort = address.port;\n\n const closed = new Promise<void>((resolvePromise, reject) => {\n server.on(\"close\", () => resolvePromise());\n server.on(\"error\", reject);\n });\n\n async function close(): Promise<void> {\n for (const socket of subscriptions.keys()) {\n socket.close();\n }\n await new Promise<void>((resolvePromise, reject) => {\n wss.close((err?: Error) => (err ? reject(err) : resolvePromise()));\n });\n await new Promise<void>((resolvePromise, reject) => {\n server.close((err) => (err ? reject(err) : resolvePromise()));\n });\n }\n\n async function handleRequest(\n req: IncomingMessage,\n res: ServerResponse,\n state: StartLiveServerOptions,\n _subscriptions: Map<WebSocket, Subscription[]>,\n registered: Map<string, RegisteredProject>,\n ): Promise<void> {\n const url = new URL(req.url ?? \"/\", `http://${host}:${actualPort}`);\n if (req.method === \"GET\" && url.pathname === \"/health\") {\n writeJson(res, 200, { ok: true, version: state.version, started_at: state.startedAt });\n return;\n }\n\n if (req.method === \"GET\" && url.pathname === \"/__holdpoint/live-auth\") {\n if (url.searchParams.get(\"token\") !== state.token) {\n writeJson(res, 401, { ok: false, error: \"Unauthorized\" });\n return;\n }\n\n registerProjectFromAuthUrl(url, registered);\n\n const redirectTarget = normalizeUiPath(url.searchParams.get(\"path\"));\n const redirectUrl = new URL(`http://${host}:${actualPort}`);\n redirectUrl.pathname = redirectTarget.pathname;\n for (const [key, value] of url.searchParams.entries()) {\n if (key !== \"token\" && key !== \"path\") {\n redirectUrl.searchParams.set(key, value);\n }\n }\n if (redirectTarget.tab) {\n redirectUrl.searchParams.set(\"tab\", redirectTarget.tab);\n }\n writeUiAuthCookie(res, state.token);\n res.writeHead(302, {\n location: redirectUrl.toString(),\n \"cache-control\": \"no-store\",\n });\n res.end();\n return;\n }\n\n if (req.method === \"GET\" && url.pathname === \"/__holdpoint/initial-yaml\") {\n if (!authorizeRequest(req, res, state.token, actualPort)) {\n return;\n }\n const project = getProjectForRequest(url, registered);\n if (!project) {\n writeJson(res, 404, { ok: false, error: \"Project not registered for this UI session\" });\n return;\n }\n const checksPath = resolve(project.root, \"checks.yaml\");\n if (!isWithinRoot(checksPath, project.root) || !existsSync(checksPath)) {\n writeJson(res, 404, { ok: false, error: \"checks.yaml not found for this project\" });\n return;\n }\n res.writeHead(200, {\n \"cache-control\": \"no-store\",\n \"content-type\": \"text/yaml; charset=utf-8\",\n });\n createReadStream(checksPath).pipe(res);\n return;\n }\n\n if (req.method === \"GET\" && url.pathname === \"/__holdpoint/initial-reports\") {\n if (!authorizeRequest(req, res, state.token, actualPort)) {\n return;\n }\n const project = getProjectForRequest(url, registered);\n if (!project) {\n writeJson(res, 404, { ok: false, error: \"Project not registered for this UI session\" });\n return;\n }\n const reportsPath = resolve(project.root, \".holdpoint\", \"check-reports.json\");\n if (!isWithinRoot(reportsPath, project.root) || !existsSync(reportsPath)) {\n writeJson(res, 404, { ok: false, error: \"No check reports found for this project\" });\n return;\n }\n res.writeHead(200, {\n \"cache-control\": \"no-store\",\n \"content-type\": \"application/json; charset=utf-8\",\n });\n createReadStream(reportsPath).pipe(res);\n return;\n }\n\n if (req.method === \"PUT\" && url.pathname === \"/__holdpoint/checks\") {\n if (!authorizeRequest(req, res, state.token, actualPort)) {\n return;\n }\n const project = getProjectForRequest(url, registered);\n if (!project) {\n writeJson(res, 404, { ok: false, error: \"Project not registered for this UI session\" });\n return;\n }\n const checksPath = resolve(project.root, \"checks.yaml\");\n if (!isWithinRoot(checksPath, project.root)) {\n writeJson(res, 400, { ok: false, error: \"Invalid checks path\" });\n return;\n }\n let body: string;\n try {\n body = await readTextBody(req);\n } catch {\n writeJson(res, 413, { ok: false, error: \"checks.yaml is too large\" });\n return;\n }\n try {\n // Validate against the schema so the dashboard can never write a\n // checks.yaml that would break the gate for this repo.\n parseHoldpointYaml(body);\n } catch (parseError) {\n writeJson(res, 422, {\n ok: false,\n error: `Invalid checks.yaml: ${(parseError as Error).message}`,\n });\n return;\n }\n try {\n // Write atomically via a temp file + rename so a crash mid-write can't\n // leave a half-written checks.yaml on disk.\n const tmpPath = `${checksPath}.holdpoint-tmp-${randomUUID().slice(0, 8)}`;\n writeFileSync(tmpPath, body, \"utf8\");\n renameSync(tmpPath, checksPath);\n } catch (writeError) {\n writeJson(res, 500, { ok: false, error: (writeError as Error).message });\n return;\n }\n writeJson(res, 200, { ok: true });\n return;\n }\n\n if (url.pathname.startsWith(\"/v1/\") && !authorizeRequest(req, res, state.token, actualPort)) {\n return;\n }\n\n if (req.method === \"POST\" && url.pathname === \"/v1/events\") {\n const event = EventV1Schema.parse(await readJsonBody(req));\n const accepted = await ingestAndBroadcast(event);\n writeJson(res, 200, { ok: true, accepted: accepted.length });\n return;\n }\n\n if (req.method === \"POST\" && url.pathname === \"/v1/events/batch\") {\n const events = EventsBatchSchema.parse(await readJsonBody(req));\n const accepted: EventV1[] = [];\n for (const event of events) {\n accepted.push(...(await ingestAndBroadcast(event)));\n }\n writeJson(res, 200, { ok: true, accepted: accepted.length });\n return;\n }\n\n if (req.method === \"POST\" && url.pathname === \"/v1/control\") {\n const request = ControlRequestSchema.parse(await readJsonBody(req));\n const session = state.store.getSessionSummary(request.session_key);\n if (!session) {\n writeJson(res, 404, { ok: false, error: \"Session not found\" });\n return;\n }\n\n const controlSocket = controlSockets.get(request.session_key);\n if (!controlSocket || controlSocket.readyState !== WebSocket.OPEN) {\n writeJson(res, 409, { ok: false, error: \"Control socket not connected\" });\n return;\n }\n\n await ingestAndBroadcast({\n v: 1,\n id: randomUUID(),\n ts: Date.now(),\n engine: session.engine,\n session_id: session.session_id,\n project_hash: session.project_hash,\n cwd: session.cwd,\n type: \"control\",\n payload: request.command,\n });\n sendSocketMessage(controlSocket, {\n type: \"control\",\n session_key: request.session_key,\n command: request.command,\n });\n writeJson(res, 200, { ok: true, delivered: true });\n return;\n }\n\n if (req.method === \"GET\" && url.pathname === \"/v1/projects\") {\n writeJson(res, 200, { projects: state.store.listProjects() });\n return;\n }\n\n if (req.method === \"GET\" && url.pathname === \"/v1/sessions\") {\n const projectHash = url.searchParams.get(\"project_hash\") ?? undefined;\n writeJson(res, 200, { sessions: state.store.listSessions(projectHash) });\n return;\n }\n\n if (\n req.method === \"GET\" &&\n url.pathname.startsWith(\"/v1/sessions/\") &&\n url.pathname.endsWith(\"/events\")\n ) {\n const sessionKey = decodeURIComponent(\n url.pathname.replace(\"/v1/sessions/\", \"\").replace(/\\/events$/, \"\"),\n );\n const sinceSeq = Number(\n url.searchParams.get(\"since_seq\") ?? url.searchParams.get(\"since\") ?? \"0\",\n );\n const limit = Number(url.searchParams.get(\"limit\") ?? \"500\");\n writeJson(res, 200, {\n session_key: sessionKey,\n since_seq: Number.isFinite(sinceSeq) ? sinceSeq : 0,\n max_seq: state.store.getSessionLatestSeq(sessionKey),\n events: state.store.getSessionEvents(\n sessionKey,\n Number.isFinite(sinceSeq) ? sinceSeq : 0,\n Number.isFinite(limit) ? limit : 500,\n ),\n });\n return;\n }\n\n if (req.method === \"DELETE\" && url.pathname.startsWith(\"/v1/sessions/\")) {\n const sessionKey = decodeURIComponent(url.pathname.replace(\"/v1/sessions/\", \"\"));\n const removed = await state.store.purgeSession(sessionKey);\n writeJson(\n res,\n removed ? 200 : 404,\n removed ? { ok: true } : { ok: false, error: \"Session not found\" },\n );\n return;\n }\n\n if (req.method === \"GET\") {\n if (url.pathname === \"/\") {\n res.writeHead(302, { location: \"/live/\", \"cache-control\": \"no-store\" });\n res.end();\n return;\n }\n\n // The Builder is now the \"Checks\" tab of the unified UI. Fold every\n // `/builder` request into `/live/?tab=checks`, preserving other params.\n if (url.pathname === \"/builder\" || url.pathname.startsWith(\"/builder/\")) {\n const target = new URL(\"/live/\", `http://${host}:${actualPort}`);\n for (const [key, value] of url.searchParams.entries()) target.searchParams.set(key, value);\n target.searchParams.set(\"tab\", \"checks\");\n res.writeHead(302, {\n location: `${target.pathname}${target.search}`,\n \"cache-control\": \"no-store\",\n });\n res.end();\n return;\n }\n\n if (url.pathname === \"/live\") {\n res.writeHead(302, { location: \"/live/\", \"cache-control\": \"no-store\" });\n res.end();\n return;\n }\n\n if (!url.pathname.startsWith(\"/live/\")) {\n res.writeHead(302, { location: \"/live/\", \"cache-control\": \"no-store\" });\n res.end();\n return;\n }\n\n const filePath = resolveUiFilePath(LIVE_UI_DIR, url.pathname.replace(/^\\/live\\/?/, \"\"));\n if (!filePath) {\n servePlaceholder(res, \"Holdpoint Live\");\n return;\n }\n serveUiAsset(res, filePath);\n return;\n }\n\n writeJson(res, 404, { ok: false, error: \"Not found\" });\n }\n\n return {\n host,\n port: actualPort,\n close,\n closed,\n };\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nexport const LIVE_UI_COOKIE = \"holdpoint_live_token\";\n\nfunction parseCookies(raw: string | undefined): Map<string, string> {\n const cookies = new Map<string, string>();\n if (!raw) {\n return cookies;\n }\n\n for (const part of raw.split(\";\")) {\n const [name, ...valueParts] = part.trim().split(\"=\");\n if (!name) continue;\n cookies.set(name, decodeURIComponent(valueParts.join(\"=\")));\n }\n\n return cookies;\n}\n\nfunction getRequestToken(req: IncomingMessage): string | null {\n const auth = req.headers.authorization;\n if (auth?.startsWith(\"Bearer \")) {\n return auth.slice(\"Bearer \".length);\n }\n\n return parseCookies(req.headers.cookie).get(LIVE_UI_COOKIE) ?? null;\n}\n\nexport function writeJson(\n res: ServerResponse,\n statusCode: number,\n body: unknown,\n headers: Record<string, string> = {},\n): void {\n res.writeHead(statusCode, {\n \"cache-control\": \"no-store\",\n \"content-type\": \"application/json; charset=utf-8\",\n ...headers,\n });\n res.end(JSON.stringify(body));\n}\n\nexport async function readJsonBody(req: IncomingMessage): Promise<unknown> {\n const chunks: Buffer[] = [];\n for await (const chunk of req) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));\n }\n if (chunks.length === 0) return null;\n return JSON.parse(Buffer.concat(chunks).toString(\"utf8\"));\n}\n\n/** Read a raw request body as UTF-8 text, capped to guard against runaways. */\nexport async function readTextBody(req: IncomingMessage, maxBytes = 512_000): Promise<string> {\n const chunks: Buffer[] = [];\n let total = 0;\n for await (const chunk of req) {\n const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));\n total += buf.length;\n if (total > maxBytes) throw new Error(\"Request body too large\");\n chunks.push(buf);\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n\nexport function authorizeRequest(\n req: IncomingMessage,\n res: ServerResponse,\n token: string,\n port: number,\n): boolean {\n const origin = req.headers.origin;\n if (origin && origin !== `http://127.0.0.1:${port}`) {\n writeJson(res, 403, { ok: false, error: \"Origin not allowed\" });\n return false;\n }\n\n if (getRequestToken(req) !== token) {\n writeJson(res, 401, { ok: false, error: \"Unauthorized\" });\n return false;\n }\n\n return true;\n}\n\nexport function authorizeWebSocket(req: IncomingMessage, token: string, port: number): boolean {\n const origin = req.headers.origin;\n if (origin && origin !== `http://127.0.0.1:${port}`) {\n return false;\n }\n\n if (getRequestToken(req) === token) {\n return true;\n }\n\n const raw = req.headers[\"sec-websocket-protocol\"];\n const protocols = (typeof raw === \"string\" ? [raw] : [])\n .flatMap((entry) => entry.split(\",\"))\n .map((entry) => entry.trim())\n .filter(Boolean);\n\n return protocols.includes(`holdpoint-${token}`);\n}\n\nexport function writeUiAuthCookie(res: ServerResponse, token: string): void {\n res.setHeader(\n \"set-cookie\",\n `${LIVE_UI_COOKIE}=${encodeURIComponent(token)}; Path=/; HttpOnly; SameSite=Strict; Max-Age=3600`,\n );\n}\n","import { appendFile, mkdir, readFile, readdir, rm, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { EventV1, ProjectSummary, SessionSummary } from \"@holdpoint/live-protocol\";\nimport { EventV1Schema } from \"@holdpoint/live-protocol\";\nimport { ConflictTracker } from \"./conflict-tracker.js\";\nimport { identifyProject } from \"./project-identity.js\";\n\ninterface StoredProject extends ProjectSummary {\n root: string;\n}\n\ninterface StoredSession extends SessionSummary {\n events: EventV1[];\n filePath: string;\n}\n\nfunction sessionFileName(engine: string, sessionId: string): string {\n return `${encodeURIComponent(engine)}-${encodeURIComponent(sessionId)}.jsonl`;\n}\n\n/** Best-effort error formatter for the replayPending log lines. */\nfunction describeError(err: unknown): string {\n if (err instanceof Error) return err.message || err.name;\n return String(err);\n}\n\nasync function readJsonl(filePath: string): Promise<EventV1[]> {\n const raw = await readFile(filePath, \"utf8\");\n return raw\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter(Boolean)\n .flatMap((line) => {\n try {\n return [EventV1Schema.parse(JSON.parse(line))];\n } catch {\n return [];\n }\n });\n}\n\nexport function buildSessionKey(\n event: Pick<EventV1, \"project_hash\" | \"engine\" | \"session_id\">,\n): string {\n return `${event.project_hash}:${event.engine}:${event.session_id}`;\n}\n\nexport class LiveStore {\n private readonly homeDir: string;\n private readonly projects = new Map<string, StoredProject>();\n private readonly sessions = new Map<string, StoredSession>();\n private readonly projectIdentityCache = new Map<string, ReturnType<typeof identifyProject>>();\n private readonly conflictTracker = new ConflictTracker();\n private nextSeq = 1;\n\n private constructor(homeDir: string) {\n this.homeDir = homeDir;\n }\n\n static async create(homeDir: string): Promise<LiveStore> {\n const store = new LiveStore(homeDir);\n await store.hydrate();\n return store;\n }\n\n async replayPending(): Promise<void> {\n const pendingDir = join(this.homeDir, \"spool\", \"pending\");\n if (!existsSync(pendingDir)) return;\n let entries: string[];\n try {\n entries = await readdir(pendingDir);\n } catch (err) {\n // Pending dir disappeared between existsSync and readdir, or\n // permissions changed underneath us. Not worth crashing for.\n console.error(`[holdpoint] failed to read pending dir: ${describeError(err)}`);\n return;\n }\n for (const entry of entries.filter((name) => name.endsWith(\".jsonl\"))) {\n const filePath = join(pendingDir, entry);\n let events: EventV1[] = [];\n try {\n events = await readJsonl(filePath);\n } catch (err) {\n console.error(`[holdpoint] failed to read pending file ${entry}: ${describeError(err)}`);\n }\n // Per-event try/catch — one malformed payload (e.g. a project_hash\n // pointing at a now-deleted cwd) must not poison the whole replay\n // and brick daemon startup forever. Failed events are logged and\n // dropped; the file is removed unconditionally at the end so a bad\n // payload can't loop on every restart.\n for (const event of events) {\n try {\n await this.ingest(event);\n } catch (err) {\n console.error(`[holdpoint] dropped pending event from ${entry}: ${describeError(err)}`);\n }\n }\n try {\n await rm(filePath, { force: true });\n } catch (err) {\n // Failing to delete the file means we'll re-process it next\n // startup; everything we just did was idempotent so that's\n // tolerable. Log so it's visible if it keeps happening.\n console.error(`[holdpoint] failed to remove pending file ${entry}: ${describeError(err)}`);\n }\n }\n }\n\n async ingestMany(events: EventV1[]): Promise<EventV1[]> {\n const accepted: EventV1[] = [];\n for (const event of events) {\n accepted.push(...(await this.ingest(event)));\n }\n return accepted;\n }\n\n async ingest(event: EventV1): Promise<EventV1[]> {\n const accepted: EventV1[] = [];\n const storedPrimary = await this.persistEvent(event);\n accepted.push(storedPrimary);\n\n for (const derivedEvent of this.conflictTracker.handleEvent(storedPrimary)) {\n accepted.push(await this.persistEvent(derivedEvent));\n }\n\n return accepted;\n }\n\n listProjects(): ProjectSummary[] {\n return [...this.projects.values()].sort((a, b) => b.last_active - a.last_active);\n }\n\n listSessions(projectHash?: string): SessionSummary[] {\n return [...this.sessions.values()]\n .filter((session) => !projectHash || session.project_hash === projectHash)\n .sort((a, b) => b.last_event_at - a.last_event_at)\n .map(({ events: _events, filePath: _filePath, ...summary }) => summary);\n }\n\n getSessionEvents(sessionKey: string, sinceSeq = 0, limit = 500): EventV1[] {\n const session = this.sessions.get(sessionKey);\n if (!session) return [];\n return session.events.filter((event) => (event.seq ?? 0) > sinceSeq).slice(-limit);\n }\n\n getProjectEvents(projectHash: string, sinceSeq = 0, limit = 500): EventV1[] {\n return [...this.sessions.values()]\n .filter((session) => session.project_hash === projectHash)\n .flatMap((session) => session.events)\n .filter((event) => (event.seq ?? 0) > sinceSeq)\n .sort((left, right) => (left.seq ?? 0) - (right.seq ?? 0))\n .slice(-limit);\n }\n\n getAllEvents(sinceSeq = 0, limit = 1_000): EventV1[] {\n return [...this.sessions.values()]\n .flatMap((session) => session.events)\n .filter((event) => (event.seq ?? 0) > sinceSeq)\n .sort((left, right) => (left.seq ?? 0) - (right.seq ?? 0))\n .slice(-limit);\n }\n\n getLatestSeq(projectHash?: string): number {\n const sessions = [...this.sessions.values()].filter(\n (session) => !projectHash || session.project_hash === projectHash,\n );\n return sessions.reduce((maxSeq, session) => Math.max(maxSeq, session.last_seq ?? 0), 0);\n }\n\n getSessionLatestSeq(sessionKey: string): number {\n return this.sessions.get(sessionKey)?.last_seq ?? 0;\n }\n\n getSessionSummary(sessionKey: string): SessionSummary | null {\n const session = this.sessions.get(sessionKey);\n if (!session) return null;\n return {\n key: session.key,\n project_hash: session.project_hash,\n engine: session.engine,\n session_id: session.session_id,\n cwd: session.cwd,\n last_event_at: session.last_event_at,\n last_seq: session.last_seq,\n event_count: session.event_count,\n caps: session.caps,\n };\n }\n\n async purgeSession(sessionKey: string): Promise<boolean> {\n const session = this.sessions.get(sessionKey);\n if (!session) return false;\n this.sessions.delete(sessionKey);\n await rm(session.filePath, { force: true });\n\n const project = this.projects.get(session.project_hash);\n if (!project) {\n return true;\n }\n\n const remainingSessions = [...this.sessions.values()].filter(\n (candidate) => candidate.project_hash === session.project_hash,\n );\n if (remainingSessions.length === 0) {\n this.projects.delete(session.project_hash);\n return true;\n }\n\n project.session_count = remainingSessions.length;\n project.last_active = remainingSessions.reduce(\n (latest, candidate) => Math.max(latest, candidate.last_event_at),\n 0,\n );\n\n const projectDir = join(this.homeDir, \"sessions\", session.project_hash);\n await writeFile(join(projectDir, \"meta.json\"), JSON.stringify(project, null, 2) + \"\\n\", {\n encoding: \"utf8\",\n mode: 0o600,\n });\n return true;\n }\n\n private async persistEvent(event: EventV1): Promise<EventV1> {\n const storedEvent: EventV1 = {\n ...event,\n seq: event.seq ?? this.nextSeq++,\n };\n\n this.upsertProject(storedEvent);\n const session = this.upsertSession(storedEvent);\n const projectDir = join(this.homeDir, \"sessions\", storedEvent.project_hash);\n await mkdir(projectDir, { recursive: true, mode: 0o700 });\n await appendFile(session.filePath, JSON.stringify(storedEvent) + \"\\n\", {\n encoding: \"utf8\",\n mode: 0o600,\n });\n await writeFile(\n join(projectDir, \"meta.json\"),\n JSON.stringify(this.projects.get(storedEvent.project_hash), null, 2) + \"\\n\",\n { encoding: \"utf8\", mode: 0o600 },\n );\n\n return storedEvent;\n }\n\n private upsertProject(event: EventV1): void {\n const identity = this.getProjectIdentity(event.cwd);\n const existing = this.projects.get(event.project_hash);\n const sessionCount = existing?.session_count ?? 0;\n this.projects.set(event.project_hash, {\n project_hash: event.project_hash,\n name: existing?.name ?? identity.name,\n root: existing?.root ?? identity.root,\n last_active: Math.max(existing?.last_active ?? 0, event.ts),\n session_count: sessionCount,\n });\n }\n\n private upsertSession(event: EventV1): StoredSession {\n const key = buildSessionKey(event);\n const existing = this.sessions.get(key);\n const filePath =\n existing?.filePath ??\n join(\n this.homeDir,\n \"sessions\",\n event.project_hash,\n sessionFileName(event.engine, event.session_id),\n );\n const events = [...(existing?.events ?? []), event];\n const session: StoredSession = {\n key,\n project_hash: event.project_hash,\n engine: event.engine,\n session_id: event.session_id,\n cwd: event.cwd,\n last_event_at: event.ts,\n last_seq: event.seq,\n event_count: events.length,\n caps: event.caps ?? existing?.caps,\n events,\n filePath,\n };\n this.sessions.set(key, session);\n\n const project = this.projects.get(event.project_hash);\n if (project) {\n project.session_count = [...this.sessions.values()].filter(\n (candidate) => candidate.project_hash === event.project_hash,\n ).length;\n project.last_active = Math.max(project.last_active, event.ts);\n }\n\n return session;\n }\n\n private getProjectIdentity(cwd: string): ReturnType<typeof identifyProject> {\n const cached = this.projectIdentityCache.get(cwd);\n if (cached) {\n return cached;\n }\n const identity = identifyProject(cwd);\n this.projectIdentityCache.set(cwd, identity);\n return identity;\n }\n\n private async hydrate(): Promise<void> {\n const sessionsRoot = join(this.homeDir, \"sessions\");\n if (!existsSync(sessionsRoot)) return;\n\n const projectEntries = await readdir(sessionsRoot, { withFileTypes: true });\n for (const projectDirEntry of projectEntries) {\n if (!projectDirEntry.isDirectory()) continue;\n const projectHash = projectDirEntry.name;\n const projectDir = join(sessionsRoot, projectHash);\n const files = await readdir(projectDir);\n let loadedProject: StoredProject | undefined;\n const metaPath = join(projectDir, \"meta.json\");\n if (existsSync(metaPath)) {\n try {\n loadedProject = JSON.parse(await readFile(metaPath, \"utf8\")) as StoredProject;\n } catch {\n loadedProject = undefined;\n }\n }\n\n for (const file of files.filter((entry) => entry.endsWith(\".jsonl\"))) {\n const filePath = join(projectDir, file);\n const rawEvents = await readJsonl(filePath);\n if (rawEvents.length === 0) continue;\n\n const events = rawEvents\n .sort((left, right) => {\n const leftSeq = left.seq ?? 0;\n const rightSeq = right.seq ?? 0;\n if (leftSeq !== rightSeq) return leftSeq - rightSeq;\n return left.ts - right.ts;\n })\n .map((event) => {\n const seq = event.seq ?? this.nextSeq++;\n this.nextSeq = Math.max(this.nextSeq, seq + 1);\n return {\n ...event,\n seq,\n };\n });\n\n const first = events[0];\n const last = events[events.length - 1];\n if (!first || !last) continue;\n const key = buildSessionKey(first);\n this.sessions.set(key, {\n key,\n project_hash: first.project_hash,\n engine: first.engine,\n session_id: first.session_id,\n cwd: first.cwd,\n last_event_at: last.ts,\n last_seq: last.seq,\n event_count: events.length,\n caps: last.caps,\n events,\n filePath,\n });\n\n if (!loadedProject) {\n const identity = this.getProjectIdentity(first.cwd);\n loadedProject = {\n project_hash: first.project_hash,\n name: identity.name,\n root: identity.root,\n last_active: last.ts,\n session_count: 0,\n };\n } else {\n loadedProject.last_active = Math.max(loadedProject.last_active, last.ts);\n }\n }\n\n if (loadedProject) {\n loadedProject.session_count = [...this.sessions.values()].filter(\n (session) => session.project_hash === projectHash,\n ).length;\n this.projects.set(projectHash, loadedProject);\n }\n }\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport { existsSync, realpathSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport type { EventV1 } from \"@holdpoint/live-protocol\";\n\nconst DEFAULT_LOCK_TTL_MS = 30_000;\n\ninterface FileLock {\n sessionKey: string;\n engine: string;\n sessionId: string;\n expiresAt: number;\n}\n\ntype LockEvent = Extract<EventV1, { type: \"tool_pre\" | \"tool_post\" | \"tool_failure\" }>;\n\nfunction buildSessionKey(event: Pick<EventV1, \"project_hash\" | \"engine\" | \"session_id\">): string {\n return `${event.project_hash}:${event.engine}:${event.session_id}`;\n}\n\nfunction normalizeWriteTarget(cwd: string, target: string): string {\n const resolved = resolve(cwd, target);\n return existsSync(resolved) ? realpathSync.native(resolved) : resolved;\n}\n\nfunction getWriteTargets(event: LockEvent, activeTargets: Map<string, string[]>): string[] {\n const toolKey = `${buildSessionKey(event)}:${event.payload.tool_use_id}`;\n if (event.type === \"tool_pre\") {\n return (event.payload.write_targets ?? []).map((target: string) =>\n normalizeWriteTarget(event.cwd, target),\n );\n }\n\n return (\n (event.type === \"tool_post\"\n ? event.payload.write_targets?.map((target: string) =>\n normalizeWriteTarget(event.cwd, target),\n )\n : undefined) ??\n activeTargets.get(toolKey) ??\n []\n );\n}\n\nexport class ConflictTracker {\n private readonly lockTtlMs: number;\n private readonly locksByProject = new Map<string, Map<string, FileLock>>();\n private readonly activeTargets = new Map<string, string[]>();\n private readonly emittedConflicts = new Map<string, number>();\n\n constructor(lockTtlMs = DEFAULT_LOCK_TTL_MS) {\n this.lockTtlMs = lockTtlMs;\n }\n\n handleEvent(event: EventV1): EventV1[] {\n switch (event.type) {\n case \"tool_pre\":\n return this.handleToolPre(event);\n case \"tool_post\":\n case \"tool_failure\":\n this.releaseLocks(event);\n return [];\n default:\n return [];\n }\n }\n\n private handleToolPre(event: Extract<EventV1, { type: \"tool_pre\" }>): EventV1[] {\n const sessionKey = buildSessionKey(event);\n const toolKey = `${sessionKey}:${event.payload.tool_use_id}`;\n const writeTargets = getWriteTargets(event, this.activeTargets);\n if (writeTargets.length === 0) {\n return [];\n }\n\n this.activeTargets.set(toolKey, writeTargets);\n const projectLocks = this.getProjectLocks(event.project_hash);\n this.pruneExpiredLocks(projectLocks, event.ts);\n\n const conflicts: EventV1[] = [];\n for (const filePath of writeTargets) {\n const existing = projectLocks.get(filePath);\n if (!existing) {\n projectLocks.set(filePath, {\n sessionKey,\n engine: event.engine,\n sessionId: event.session_id,\n expiresAt: event.ts + this.lockTtlMs,\n });\n continue;\n }\n\n if (existing.sessionKey === sessionKey) {\n existing.expiresAt = event.ts + this.lockTtlMs;\n continue;\n }\n\n const dedupeKey = `${event.project_hash}:${filePath}:${existing.sessionKey}:${sessionKey}`;\n const previousEmission = this.emittedConflicts.get(dedupeKey) ?? 0;\n if (previousEmission > event.ts) {\n continue;\n }\n\n this.emittedConflicts.set(dedupeKey, event.ts + this.lockTtlMs);\n conflicts.push({\n v: 1,\n id: randomUUID(),\n ts: event.ts,\n engine: event.engine,\n session_id: event.session_id,\n project_hash: event.project_hash,\n cwd: event.cwd,\n type: \"conflict\",\n payload: {\n kind: \"file_write\",\n file_path: filePath,\n holder: {\n engine: existing.engine,\n session_id: existing.sessionId,\n },\n requester: {\n engine: event.engine,\n session_id: event.session_id,\n },\n },\n });\n }\n\n return conflicts;\n }\n\n private releaseLocks(event: Extract<EventV1, { type: \"tool_post\" | \"tool_failure\" }>): void {\n const sessionKey = buildSessionKey(event);\n const toolKey = `${sessionKey}:${event.payload.tool_use_id}`;\n const projectLocks = this.getProjectLocks(event.project_hash);\n const writeTargets = getWriteTargets(event, this.activeTargets);\n\n for (const filePath of writeTargets) {\n const existing = projectLocks.get(filePath);\n if (existing?.sessionKey === sessionKey) {\n projectLocks.delete(filePath);\n }\n }\n\n this.activeTargets.delete(toolKey);\n this.pruneExpiredLocks(projectLocks, event.ts);\n }\n\n private getProjectLocks(projectHash: string): Map<string, FileLock> {\n let existing = this.locksByProject.get(projectHash);\n if (!existing) {\n existing = new Map<string, FileLock>();\n this.locksByProject.set(projectHash, existing);\n }\n return existing;\n }\n\n private pruneExpiredLocks(projectLocks: Map<string, FileLock>, now: number): void {\n for (const [filePath, lock] of projectLocks.entries()) {\n if (lock.expiresAt <= now) {\n projectLocks.delete(filePath);\n }\n }\n\n for (const [key, expiresAt] of this.emittedConflicts.entries()) {\n if (expiresAt <= now) {\n this.emittedConflicts.delete(key);\n }\n }\n }\n}\n","import { execFileSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { realpathSync } from \"node:fs\";\nimport { basename } from \"node:path\";\n\nexport interface ProjectIdentity {\n hash: string;\n name: string;\n root: string;\n}\n\nfunction sha12(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\").slice(0, 12);\n}\n\nexport function identifyProject(cwd: string): ProjectIdentity {\n // Three layers of fallback, in order of preference:\n // 1. git rev-parse --show-toplevel + realpath — canonical: matches\n // whatever git considers the repo root, normalised through symlinks.\n // 2. realpath(cwd) — cwd exists but isn't\n // a git repo (or git binary missing); use the resolved cwd as root.\n // 3. raw cwd string — cwd doesn't exist\n // on disk anymore (deleted/renamed project; common when replaying\n // old pending events from `~/.holdpoint/spool/pending`). The daemon\n // still needs a stable identity so the event can be stored and\n // surfaced; the hash/name are based on the literal path.\n //\n // This function MUST NOT throw. The daemon's startup replay loop ingests\n // historical events from disk and crashing here used to brick startup\n // entirely whenever a project path had been renamed since the events\n // were spooled — see https://github.com/holdpoint-dev/holdpoint/issues\n // (daemon-unavailable on stale pending events).\n let root: string;\n try {\n root = realpathSync(\n execFileSync(\"git\", [\"rev-parse\", \"--show-toplevel\"], {\n cwd,\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim(),\n );\n } catch {\n try {\n root = realpathSync(cwd);\n } catch {\n // cwd doesn't exist on disk — use the raw path string as identity.\n root = cwd;\n }\n }\n return {\n hash: sha12(root),\n name: basename(root) || root,\n root,\n };\n}\n","import type { EventV1 } from \"@holdpoint/live-protocol\";\nimport { buildSessionKey } from \"./store.js\";\n\nexport interface Subscription {\n scope: \"project\" | \"session\" | \"all\";\n key?: string;\n}\n\nexport function matchesSubscription(subscription: Subscription, event: EventV1): boolean {\n switch (subscription.scope) {\n case \"all\":\n return true;\n case \"project\":\n return subscription.key === event.project_hash;\n case \"session\":\n return subscription.key === buildSessionKey(event);\n }\n}\n","import {\n removeDaemonLock,\n createDaemonLock,\n findFreePort,\n readHealthyDaemonLock,\n type DaemonLock,\n writeDaemonLockExclusive,\n resolveHoldpointHome,\n} from \"./singleton.js\";\nimport { startLiveServer, type RunningLiveServer } from \"./server.js\";\nimport { LiveStore } from \"./store.js\";\n\nexport class DaemonAlreadyRunningError extends Error {\n readonly info: DaemonLock;\n\n constructor(info: DaemonLock) {\n super(`Holdpoint daemon already running on port ${info.port}`);\n this.info = info;\n }\n}\n\nexport interface StartDaemonProcessOptions {\n homeDir?: string;\n port?: number;\n version: string;\n}\n\nexport interface StartedDaemon {\n info: DaemonLock;\n server: RunningLiveServer;\n store: LiveStore;\n close(): Promise<void>;\n closed: Promise<void>;\n}\n\nexport async function startDaemonProcess(\n options: StartDaemonProcessOptions,\n): Promise<StartedDaemon> {\n const existing = await readHealthyDaemonLock(options.homeDir);\n if (existing) {\n throw new DaemonAlreadyRunningError(existing);\n }\n\n const port = options.port ?? (await findFreePort());\n const info = createDaemonLock(port, options.version);\n writeDaemonLockExclusive(info, options.homeDir);\n\n const store = await LiveStore.create(resolveHoldpointHome(options.homeDir));\n await store.replayPending();\n\n let server: RunningLiveServer;\n try {\n server = await startLiveServer({\n port,\n token: info.token,\n version: options.version,\n startedAt: info.started_at,\n store,\n });\n } catch (error) {\n removeDaemonLock(options.homeDir, info.token);\n throw error;\n }\n\n let closed = false;\n const cleanup = async (): Promise<void> => {\n if (closed) return;\n closed = true;\n removeDaemonLock(options.homeDir, info.token);\n await server.close();\n };\n\n const onSignal = (): void => {\n void cleanup().finally(() => process.exit(0));\n };\n\n process.once(\"SIGTERM\", onSignal);\n process.once(\"SIGINT\", onSignal);\n\n return {\n info,\n server,\n store,\n close: cleanup,\n closed: server.closed.finally(() => {\n process.off(\"SIGTERM\", onSignal);\n process.off(\"SIGINT\", onSignal);\n }),\n };\n}\n\nexport {\n createDaemonLock,\n ensureHoldpointHome,\n findFreePort,\n getDaemonLockPath,\n isProcessAlive,\n readDaemonLock,\n readHealthyDaemonLock,\n removeDaemonLock,\n resolveHoldpointHome,\n waitForDaemonHealthy,\n writeDaemonLockExclusive,\n} from \"./singleton.js\";\nexport { identifyProject } from \"./project-identity.js\";\nexport { startLiveServer } from \"./server.js\";\nexport { buildSessionKey, LiveStore } from \"./store.js\";\nexport type { ProjectIdentity } from \"./project-identity.js\";\nexport type { RunningLiveServer } from \"./server.js\";\nexport type { DaemonLock } from \"./singleton.js\";\n"],"mappings":"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","names":["createServer","randomUUID","existsSync","writeFileSync","join","resolve","EventV1Schema","existsSync","join","existsSync","resolve","realpathSync","buildSessionKey","join","existsSync","buildSessionKey","join","randomUUID","resolve","existsSync","createServer","writeFileSync","EventV1Schema"]}