{"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../../../src/core/evaluation/launcher.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,uBAAuB,GAAG,yBAAyB,GAAG,mBAAmB,CAAC;AACnG,MAAM,MAAM,cAAc,GAAG,iBAAiB,GAAG,YAAY,GAAG,SAAS,CAAC;AAE1E,MAAM,WAAW,yBAAyB;IACzC,WAAW,EAAE,aAAa,GAAG,cAAc,GAAG,iBAAiB,GAAG,qBAAqB,CAAC;IACxF,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,cAAc,CAAC;IAC9B,UAAU,EAAE,UAAU,CAAC;CACvB;AAED,MAAM,WAAW,2BAA2B;IAC3C,UAAU,EAAE,UAAU,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,MAAM,EAAE,cAAc,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IAClC,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,uBAAuB,+BAA+B,CAAC;AAKpE,eAAO,MAAM,kBAAkB,2CAA4C,CAAC;AAa5E,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAI7D;AAMD;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA4BjG;AAED,uEAAuE;AACvE,wBAAgB,wBAAwB,IAAI;IAC3C,WAAW,EAAE,yBAAyB,CAAC,aAAa,CAAC,CAAC;IACtD,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CACjB,CAWA;AAED,MAAM,WAAW,sBAAsB;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE;QAAE,cAAc,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,cAAc,CAAA;KAAE,CAAC;IACpG,0DAA0D;IAC1D,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,GAAE,sBAA2B,GAClC,OAAO,CAAC,2BAA2B,CAAC,CAyDtC;AAED,wBAAsB,+BAA+B,CACpD,OAAO,GAAE,sBAA2B,GAClC,OAAO,CAAC,yBAAyB,CAAC,CAqBpC","sourcesContent":["import { realpath, stat } from \"node:fs/promises\";\nimport { basename, isAbsolute, resolve } from \"node:path\";\nimport { sha256 } from \"./identity.js\";\n\n/**\n * The identity of the executable that starts the Jensen evaluation candidate.\n * The launcher is authorized by *identity* (a validated absolute path to the\n * verified runtime executable), never by its display basename. Renaming the\n * binary must not change its identity, and an unrelated executable that merely\n * shares the basename must not inherit launcher authority.\n */\nexport type LauncherId = \"jensen_source_runtime\" | \"jensen_compiled_runtime\" | \"external_explicit\";\nexport type LauncherSource = \"current_process\" | \"configured\" | \"fixture\";\n\nexport interface RuntimeExecutableIdentity {\n\truntimeKind: \"node_source\" | \"bun_compiled\" | \"native_packaged\" | \"configured_external\";\n\trequestedPath: string;\n\tresolvedPath: string;\n\trealPath?: string;\n\tbasename: string;\n\tplatform: string;\n\tfileIdentity?: string;\n\tcontentHash?: string;\n\ttrustedOrigin: LauncherSource;\n\tlauncherId: LauncherId;\n}\n\nexport interface EvaluationCandidateLauncher {\n\tlauncherId: LauncherId;\n\texecutablePath: string;\n\texecutableIdentity: string;\n\tinvocationPrefix: string[];\n\tsource: LauncherSource;\n\ttrustedByRuntime: boolean;\n}\n\n/**\n * A logical capability mapped to a resolved executable identity. The mapping\n * separates a capability name (for example \"node\") from the actual resolved\n * executable path, so a capability never confers trust on every executable\n * whose basename happens to match.\n */\nexport interface AuthorizedExecutable {\n\tcapabilityId: string;\n\tresolvedPath: string;\n\tallowedArguments?: string[];\n\teffectClass: string;\n\tsource: string;\n}\n\nexport interface ResolvedExecutable {\n\trequestedPath: string;\n\tresolvedPath: string;\n\trealPath?: string;\n\tbasename: string;\n\texists: boolean;\n\texecutable: boolean;\n\tresolutionError?: string;\n}\n\nexport const JENSEN_CANDIDATE_MARKER = \".jensen-candidate-complete\";\n\n// Structured probe used as the sandbox candidate when running through a\n// compiled (Bun) runtime. It must be deterministic, non-interactive and free of\n// provider or browser machinery so it can run inside a bare sandbox root.\nexport const SANDBOX_SELF_PROBE = [\"eval\", \"self-probe\", \"--json\"] as const;\n\nconst isWindows = process.platform === \"win32\";\n\n/** Normalize path separators for comparison (backslash -> slash). */\nfunction normalizeSeparators(value: string): string {\n\treturn value.replace(/\\\\/g, \"/\");\n}\n\nfunction normalizeComponent(value: string): string {\n\treturn normalizeSeparators(value);\n}\n\n/** Case-insensitive path comparison on Windows, case-sensitive elsewhere. */\nexport function samePath(left: string, right: string): boolean {\n\tconst a = normalizeComponent(resolve(left));\n\tconst b = normalizeComponent(resolve(right));\n\treturn isWindows ? a.toLowerCase() === b.toLowerCase() : a === b;\n}\n\nfunction executableBasename(path: string): string {\n\treturn basename(path).replace(/\\.exe$/i, \"\");\n}\n\n/**\n * Resolve the identity of a command/executable path. Relative commands are\n * resolved against the provided working directory. realpath is applied to\n * follow symlinks where the target exists.\n */\nexport async function resolveExecutable(command: string, cwd: string): Promise<ResolvedExecutable> {\n\tconst requestedPath = command;\n\tconst candidate = isAbsolute(command) ? command : resolve(cwd, command);\n\tlet realPath: string | undefined;\n\tlet exists = false;\n\tlet executable = false;\n\tlet resolutionError: string | undefined;\n\ttry {\n\t\trealPath = await realpath(candidate);\n\t\texists = true;\n\t\ttry {\n\t\t\tconst stats = await stat(realPath);\n\t\t\texecutable = stats.isFile();\n\t\t} catch (error: unknown) {\n\t\t\tresolutionError = error instanceof Error ? error.message : \"stat failed\";\n\t\t}\n\t} catch (error: unknown) {\n\t\tresolutionError = error instanceof Error ? error.message : \"resolve failed\";\n\t}\n\treturn {\n\t\trequestedPath,\n\t\tresolvedPath: candidate,\n\t\trealPath,\n\t\tbasename: executableBasename(candidate),\n\t\texists,\n\t\texecutable,\n\t\tresolutionError,\n\t};\n}\n\n/** Determine the current runtime kind from the running environment. */\nexport function detectCurrentRuntimeKind(): {\n\truntimeKind: RuntimeExecutableIdentity[\"runtimeKind\"];\n\texecutablePath: string;\n\tbasename: string;\n} {\n\tconst execPath = process.execPath;\n\tconst name = executableBasename(execPath);\n\tconst isBun =\n\t\ttypeof process !== \"undefined\" && \"isBun\" in process && (process as { isBun?: boolean }).isBun === true;\n\tif (isBun) return { runtimeKind: \"bun_compiled\", executablePath: execPath, basename: name };\n\tif (name === \"node\" || name === \"nodejs\")\n\t\treturn { runtimeKind: \"node_source\", executablePath: execPath, basename: name };\n\t// Ambiguous host executable; treat node-detected hosts as source and the\n\t// fallback as a compiled/native launcher.\n\treturn { runtimeKind: \"native_packaged\", executablePath: execPath, basename: name };\n}\n\nexport interface ResolveLauncherOptions {\n\tcwd?: string;\n\t/** Configured external launcher; only honored when explicitly provided. */\n\tconfiguredExternal?: { executablePath: string; invocationPrefix: string[]; source: LauncherSource };\n\t/** Enable the current-process launcher (default true). */\n\tuseCurrentProcess?: boolean;\n}\n\n/**\n * Resolve the trusted candidate launcher. The current-process launcher is\n * derived from the verified running executable. An external launcher is only\n * used when explicitly configured with an absolute path.\n */\nexport async function resolveCandidateLauncher(\n\toptions: ResolveLauncherOptions = {},\n): Promise<EvaluationCandidateLauncher> {\n\tconst cwd = options.cwd ?? process.cwd();\n\tif (options.configuredExternal) {\n\t\tconst external = options.configuredExternal;\n\t\tif (!isAbsolute(external.executablePath))\n\t\t\tthrow new Error(`external candidate launcher must use an absolute path: ${external.executablePath}`);\n\t\tconst identity = await resolveExecutable(external.executablePath, cwd);\n\t\tif (!identity.exists || !identity.executable)\n\t\t\tthrow new Error(\n\t\t\t\t`external candidate launcher does not exist or is not executable: ${external.executablePath}${\n\t\t\t\t\tidentity.resolutionError ? ` (${identity.resolutionError})` : \"\"\n\t\t\t\t}`,\n\t\t\t);\n\t\tconst executablePath = identity.realPath ?? identity.resolvedPath;\n\t\treturn {\n\t\t\tlauncherId: \"external_explicit\",\n\t\t\texecutablePath,\n\t\t\texecutableIdentity: `external:${basename(executablePath)}@${sha256(executablePath).slice(0, 12)}`,\n\t\t\tinvocationPrefix: [...external.invocationPrefix],\n\t\t\tsource: external.source,\n\t\t\ttrustedByRuntime: true,\n\t\t};\n\t}\n\tconst kind = detectCurrentRuntimeKind();\n\tconst identity = await resolveExecutable(kind.executablePath, cwd);\n\tconst executablePath = identity.realPath ?? identity.resolvedPath;\n\tif (!identity.exists || !identity.executable)\n\t\tthrow new Error(\n\t\t\t`current process executable is not a usable launcher: ${kind.executablePath}${\n\t\t\t\tidentity.resolutionError ? ` (${identity.resolutionError})` : \"\"\n\t\t\t}`,\n\t\t);\n\tconst launcherId: LauncherId =\n\t\tkind.runtimeKind === \"node_source\"\n\t\t\t? \"jensen_source_runtime\"\n\t\t\t: kind.runtimeKind === \"bun_compiled\"\n\t\t\t\t? \"jensen_compiled_runtime\"\n\t\t\t\t: \"external_explicit\";\n\t// Source runtimes accept an inline `-e` probe; compiled/native runtimes use\n\t// the bundled deterministic self-probe subcommand.\n\tconst invocationPrefix =\n\t\tkind.runtimeKind === \"node_source\"\n\t\t\t? [\n\t\t\t\t\t\"-e\",\n\t\t\t\t\t\"const fs=require('node:fs');const p=process.cwd()+'/.jensen-candidate-complete';fs.writeFileSync(p,'candidate');process.stdout.write(process.cwd());\",\n\t\t\t\t]\n\t\t\t: [...SANDBOX_SELF_PROBE];\n\treturn {\n\t\tlauncherId,\n\t\texecutablePath,\n\t\texecutableIdentity: `${basename(executablePath)}@${launcherId}.${process.platform}-${process.arch}.${sha256(\n\t\t\texecutablePath,\n\t\t).slice(0, 12)}`,\n\t\tinvocationPrefix,\n\t\tsource: \"current_process\",\n\t\ttrustedByRuntime: true,\n\t};\n}\n\nexport async function createRuntimeExecutableIdentity(\n\toptions: ResolveLauncherOptions = {},\n): Promise<RuntimeExecutableIdentity> {\n\tconst cwd = options.cwd ?? process.cwd();\n\tconst kind = detectCurrentRuntimeKind();\n\tconst identity = await resolveExecutable(kind.executablePath, cwd);\n\treturn {\n\t\truntimeKind: kind.runtimeKind,\n\t\trequestedPath: kind.executablePath,\n\t\tresolvedPath: identity.resolvedPath,\n\t\trealPath: identity.realPath,\n\t\tbasename: kind.basename,\n\t\tplatform: `${process.platform}-${process.arch}`,\n\t\tfileIdentity: identity.realPath ? basename(identity.realPath) : undefined,\n\t\tcontentHash: identity.exists ? sha256(identity.realPath ?? identity.resolvedPath) : undefined,\n\t\ttrustedOrigin: \"current_process\",\n\t\tlauncherId:\n\t\t\tkind.runtimeKind === \"node_source\"\n\t\t\t\t? \"jensen_source_runtime\"\n\t\t\t\t: kind.runtimeKind === \"bun_compiled\"\n\t\t\t\t\t? \"jensen_compiled_runtime\"\n\t\t\t\t\t: \"external_explicit\",\n\t};\n}\n"]}