{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../src/inspectors/herdr/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAS,MAAM,oBAAoB,CAAC;AAE9D,MAAM,MAAM,cAAc,GACvB,mBAAmB,GACnB,2BAA2B,GAC3B,WAAW,GACX,WAAW,GACX,SAAS,GACT,kBAAkB,CAAC;AAEtB,MAAM,MAAM,WAAW,CAAC,CAAC,IACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GACrB;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE;QAAE,IAAI,EAAE,cAAc,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,CAAC;AAEtF,MAAM,WAAW,WAAW;IAC3B,GAAG,CAAC,CAAC,GAAG,OAAO,EACd,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GACtE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;CAC3B;AAED,KAAK,UAAU,GAAG,CACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,WAAW,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAA;CAAE,KAChE,YAAY,CAAC;AA4BlB,wBAAgB,iBAAiB,CAAC,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,UAAU,CAAA;CAAO,GAAG,WAAW,CAgGjG;AAED,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAGzE;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAE/D;AAED,wBAAsB,WAAW,CAChC,MAAM,EAAE,WAAW,EACnB,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,WAAW,CAAC;IAAE,OAAO,EAAE,YAAY,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAYtE","sourcesContent":["import { type ChildProcess, spawn } from \"node:child_process\";\n\nexport type HerdrErrorCode =\n\t| \"HERDR_UNAVAILABLE\"\n\t| \"HERDR_UNSUPPORTED_VERSION\"\n\t| \"PANE_GONE\"\n\t| \"NOT_FOUND\"\n\t| \"TIMEOUT\"\n\t| \"VALIDATION_ERROR\";\n\nexport type HerdrResult<T> =\n\t| { ok: true; data: T }\n\t| { ok: false; error: { code: HerdrErrorCode; message: string; details?: unknown } };\n\nexport interface HerdrClient {\n\trun<T = unknown>(\n\t\targs: string[],\n\t\toptions?: { timeoutMs?: number; signal?: AbortSignal; textOk?: boolean },\n\t): Promise<HerdrResult<T>>;\n}\n\ntype SpawnHerdr = (\n\tcommand: string,\n\targs: readonly string[],\n\toptions: { shell: false; windowsHide: true; env: NodeJS.ProcessEnv },\n) => ChildProcess;\n\nfunction error(code: HerdrErrorCode, message: string, details?: unknown): HerdrResult<never> {\n\treturn { ok: false, error: { code, message, ...(details !== undefined ? { details } : {}) } };\n}\n\nfunction parseLastJson(value: string): unknown | undefined {\n\tconst trimmed = value.trim();\n\tif (!trimmed) return undefined;\n\ttry {\n\t\treturn JSON.parse(trimmed) as unknown;\n\t} catch {}\n\tfor (const line of trimmed.split(/\\r?\\n/).reverse()) {\n\t\ttry {\n\t\t\treturn JSON.parse(line) as unknown;\n\t\t} catch {}\n\t}\n\treturn undefined;\n}\n\nfunction normalizeCode(raw: unknown): HerdrErrorCode {\n\tconst code = String(raw ?? \"\").toLowerCase();\n\tif (code.includes(\"timeout\") || code.includes(\"timed_out\")) return \"TIMEOUT\";\n\tif (code.includes(\"gone\")) return \"PANE_GONE\";\n\tif (code.includes(\"not_found\") || code.includes(\"not-found\") || code === \"no_such_pane\") return \"NOT_FOUND\";\n\treturn \"VALIDATION_ERROR\";\n}\n\nexport function createHerdrClient(options: { bin?: string; spawn?: SpawnHerdr } = {}): HerdrClient {\n\tconst bin = options.bin ?? process.env.HERDR_BIN ?? \"herdr\";\n\tconst spawnImpl = options.spawn ?? spawn;\n\treturn {\n\t\trun<T>(\n\t\t\targs: string[],\n\t\t\trunOptions: { timeoutMs?: number; signal?: AbortSignal; textOk?: boolean } = {},\n\t\t): Promise<HerdrResult<T>> {\n\t\t\treturn new Promise((resolve) => {\n\t\t\t\tlet child: ChildProcess;\n\t\t\t\ttry {\n\t\t\t\t\tchild = spawnImpl(bin, args, { shell: false, windowsHide: true, env: process.env });\n\t\t\t\t} catch (cause) {\n\t\t\t\t\tconst code = (cause as NodeJS.ErrnoException | undefined)?.code;\n\t\t\t\t\tresolve(\n\t\t\t\t\t\terror(\n\t\t\t\t\t\t\t\"HERDR_UNAVAILABLE\",\n\t\t\t\t\t\t\tcode === \"ENOENT\"\n\t\t\t\t\t\t\t\t? \"Herdr is not installed or is not on PATH. Install Herdr 0.7.5+ or set HERDR_BIN.\"\n\t\t\t\t\t\t\t\t: `Failed to start Herdr: ${cause instanceof Error ? cause.message : String(cause)}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet stdout = \"\";\n\t\t\t\tlet stderr = \"\";\n\t\t\t\tlet settled = false;\n\t\t\t\tconst finish = (result: HerdrResult<T>) => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\trunOptions.signal?.removeEventListener(\"abort\", abort);\n\t\t\t\t\tresolve(result);\n\t\t\t\t};\n\t\t\t\tconst abort = () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tchild.kill();\n\t\t\t\t\t} catch {}\n\t\t\t\t\tfinish(error(\"TIMEOUT\", `Herdr command '${args.join(\" \")}' was aborted.`));\n\t\t\t\t};\n\t\t\t\tconst timer = setTimeout(() => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tchild.kill();\n\t\t\t\t\t} catch {}\n\t\t\t\t\tfinish(\n\t\t\t\t\t\terror(\n\t\t\t\t\t\t\t\"TIMEOUT\",\n\t\t\t\t\t\t\t`Herdr command '${args.join(\" \")}' timed out after ${runOptions.timeoutMs ?? 15_000}ms.`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}, runOptions.timeoutMs ?? 15_000);\n\t\t\t\ttimer.unref?.();\n\t\t\t\tif (runOptions.signal?.aborted) abort();\n\t\t\t\telse runOptions.signal?.addEventListener(\"abort\", abort, { once: true });\n\t\t\t\tchild.stdout?.on(\"data\", (chunk) => {\n\t\t\t\t\tstdout += chunk.toString();\n\t\t\t\t});\n\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t});\n\t\t\t\tchild.on(\"error\", (cause) => {\n\t\t\t\t\tconst code = (cause as NodeJS.ErrnoException).code;\n\t\t\t\t\tfinish(\n\t\t\t\t\t\terror(\n\t\t\t\t\t\t\t\"HERDR_UNAVAILABLE\",\n\t\t\t\t\t\t\tcode === \"ENOENT\"\n\t\t\t\t\t\t\t\t? \"Herdr is not installed or is not on PATH. Install Herdr 0.7.5+ or set HERDR_BIN.\"\n\t\t\t\t\t\t\t\t: `Failed to run Herdr: ${cause.message}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t\tchild.on(\"close\", (exitCode) => {\n\t\t\t\t\tconst parsed = parseLastJson(stdout) ?? (exitCode === 0 ? undefined : parseLastJson(stderr));\n\t\t\t\t\tif (parsed && typeof parsed === \"object\" && !Array.isArray(parsed) && \"error\" in parsed) {\n\t\t\t\t\t\tconst raw = (parsed as { error?: { code?: unknown; message?: unknown } }).error;\n\t\t\t\t\t\tfinish(error(normalizeCode(raw?.code), String(raw?.message ?? \"Herdr command failed.\"), raw));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (exitCode === 0) {\n\t\t\t\t\t\tif (parsed !== undefined) {\n\t\t\t\t\t\t\tconst envelope = parsed as { result?: unknown };\n\t\t\t\t\t\t\tfinish({ ok: true, data: (envelope.result ?? parsed) as T });\n\t\t\t\t\t\t} else if (runOptions.textOk) finish({ ok: true, data: stdout.trim() as T });\n\t\t\t\t\t\telse finish({ ok: true, data: {} as T });\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst message =\n\t\t\t\t\t\tstderr\n\t\t\t\t\t\t\t.split(/\\r?\\n/)\n\t\t\t\t\t\t\t.find((line) => line.trim())\n\t\t\t\t\t\t\t?.trim() ?? `Herdr exited with code ${exitCode}.`;\n\t\t\t\t\tfinish(error(\"VALIDATION_ERROR\", message, { exitCode }));\n\t\t\t\t});\n\t\t\t});\n\t\t},\n\t};\n}\n\nexport interface HerdrVersion {\n\tmajor: number;\n\tminor: number;\n\tpatch: number;\n}\n\nexport function parseHerdrVersion(value: string): HerdrVersion | undefined {\n\tconst match = /(\\d+)\\.(\\d+)\\.(\\d+)/.exec(value);\n\treturn match ? { major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3]) } : undefined;\n}\n\nexport function supportsRawPanes(version: HerdrVersion): boolean {\n\treturn version.major > 0 || version.minor > 7 || (version.minor === 7 && version.patch >= 5);\n}\n\nexport async function detectHerdr(\n\tclient: HerdrClient,\n\tsignal?: AbortSignal,\n): Promise<HerdrResult<{ version: HerdrVersion; versionText: string }>> {\n\tconst result = await client.run<string>([\"--version\"], { timeoutMs: 3_000, signal, textOk: true });\n\tif (result.ok === false) return result;\n\tconst versionText = typeof result.data === \"string\" ? result.data : JSON.stringify(result.data);\n\tconst version = parseHerdrVersion(versionText);\n\tif (!version) return error(\"VALIDATION_ERROR\", `Could not parse the Herdr version from '${versionText}'.`);\n\tif (!supportsRawPanes(version))\n\t\treturn error(\n\t\t\t\"HERDR_UNSUPPORTED_VERSION\",\n\t\t\t`Herdr ${versionText} does not support raw inspector panes. Upgrade to Herdr 0.7.5 or newer.`,\n\t\t);\n\treturn { ok: true, data: { version, versionText } };\n}\n"]}