{"version":3,"file":"remote-verification.d.ts","sourceRoot":"","sources":["../../../src/core/remote-execution/remote-verification.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,KAAK,EAA8B,sBAAsB,EAAE,MAAM,+CAA+C,CAAC;AAExH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAEvE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,MAAM,WAAW,yBAAyB;IACzC,MAAM,EAAE,mBAAmB,CAAC;IAC5B,MAAM,EAAE,qBAAqB,CAAC;IAC9B,yEAAyE;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,yBAAyB,GAAG,oBAAoB,CAkEzG;AAaD;;;;;GAKG;AACH,wBAAgB,qCAAqC,CACpD,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,yBAAyB,GAChC,sBAAsB,GAAG,SAAS,CA6BpC","sourcesContent":["/**\n * Remote Execution — remote verification (2.14.0).\n *\n * The central verifier remains authoritative, but its deterministic commands\n * run against the remote workspace so `node test.js` actually tests the file\n * the remote child edited on the target. This adapts the existing\n * `VerificationExecutor` contract to a remote command runner; `verify()` itself\n * is unchanged.\n */\n\nimport type { MissionRequest } from \"../mission-domain/mission-request.js\";\nimport type { ProcessMissionVerification, ProcessMissionVerifier } from \"../mission-domain/process-mission-executor.js\";\nimport type { VerificationSpec } from \"../reliability/types.js\";\nimport type { VerificationExecutor } from \"../reliability/verifier.js\";\nimport { verify } from \"../reliability/verifier.js\";\nimport type { RemoteExecutionTarget } from \"./remote-target-types.js\";\nimport type { RemoteCommandRunner } from \"./remote-transport.js\";\n\nexport interface RemoteVerificationOptions {\n\trunner: RemoteCommandRunner;\n\ttarget: RemoteExecutionTarget;\n\t/** Remote absolute working directory for relative verification paths. */\n\tcwd: string;\n\tcommandTimeoutMs?: number;\n\tsignal?: AbortSignal;\n}\n\n/**\n * Build a VerificationExecutor whose filesystem/process operations execute on\n * the remote target. `runCommand` uses the remote command runner; file/state\n * operations round-trip through the same runner via platform-neutral helpers.\n */\nexport function createRemoteVerificationExecutor(options: RemoteVerificationOptions): VerificationExecutor {\n\tconst cwd = options.cwd;\n\tconst timeout = options.commandTimeoutMs ?? 120_000;\n\n\tconst resolvePath = (p: string): string => {\n\t\tif (p.startsWith(\"/\") || /^[A-Za-z]:/.test(p)) return p;\n\t\treturn `${cwd.replace(/[\\\\/]+$/, \"\")}\\\\${p}`;\n\t};\n\n\treturn {\n\t\tasync runCommand(command, cwdOverride) {\n\t\t\tconst result = await options.runner.runCommand(options.target, command, cwdOverride ?? cwd, {\n\t\t\t\ttimeoutMs: timeout,\n\t\t\t\tsignal: options.signal,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\texitCode: result.exitCode === null ? 1 : result.exitCode,\n\t\t\t\tstdout: result.stdout,\n\t\t\t\tstderr: result.stderr,\n\t\t\t};\n\t\t},\n\n\t\tasync fileExists(p, cwdOverride) {\n\t\t\tconst result = await options.runner.runCommand(\n\t\t\t\toptions.target,\n\t\t\t\t`Test-Path -LiteralPath '${resolvePath(p)}'`,\n\t\t\t\tcwdOverride ?? cwd,\n\t\t\t\t{ timeoutMs: 30_000, signal: options.signal },\n\t\t\t);\n\t\t\treturn result.stdout.trim() === \"True\";\n\t\t},\n\n\t\tasync readFile(p, cwdOverride) {\n\t\t\tconst result = await options.runner.runCommand(\n\t\t\t\toptions.target,\n\t\t\t\t`Get-Content -LiteralPath '${resolvePath(p)}' -Raw`,\n\t\t\t\tcwdOverride ?? cwd,\n\t\t\t\t{ timeoutMs: 30_000, signal: options.signal },\n\t\t\t);\n\t\t\treturn result.stdout;\n\t\t},\n\n\t\tasync searchMatches(pattern, cwdOverride) {\n\t\t\tconst result = await options.runner.runCommand(\n\t\t\t\toptions.target,\n\t\t\t\t`Get-ChildItem -Recurse -File | Select-String -List -Pattern '${pattern}' | Select-Object -ExpandProperty Path`,\n\t\t\t\tcwdOverride ?? cwd,\n\t\t\t\t{ timeoutMs: 30_000, signal: options.signal },\n\t\t\t);\n\t\t\treturn result.stdout\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.map((line) => line.trim())\n\t\t\t\t.filter((line) => line.length > 0);\n\t\t},\n\n\t\tasync gitChangedPaths(cwdOverride) {\n\t\t\tconst result = await options.runner.runCommand(options.target, \"git diff --name-only\", cwdOverride ?? cwd, {\n\t\t\t\ttimeoutMs: 30_000,\n\t\t\t\tsignal: options.signal,\n\t\t\t});\n\t\t\treturn result.stdout\n\t\t\t\t.split(\"\\n\")\n\t\t\t\t.map((line) => line.trim())\n\t\t\t\t.filter((line) => line.length > 0);\n\t\t},\n\t};\n}\n\n/** Collect a mission's declared deterministic verification specs. */\nfunction collectVerificationSpecs(request: MissionRequest): { criterionId: string; spec: VerificationSpec }[] {\n\tconst specs: { criterionId: string; spec: VerificationSpec }[] = [];\n\tfor (const criterion of request.acceptanceCriteria) {\n\t\tif (criterion.verification) {\n\t\t\tspecs.push({ criterionId: criterion.id, spec: criterion.verification });\n\t\t}\n\t}\n\treturn specs;\n}\n\n/**\n * Build the remote acceptance-criteria verifier. Returns `undefined` when the\n * mission declares no verifiable criteria (so a clean exit-0 stays PARTIAL,\n * never SUCCEEDED). Identical semantics to the local worker verifier, but the\n * verification operations execute remotely.\n */\nexport function buildRemoteAcceptanceCriteriaVerifier(\n\trequest: MissionRequest,\n\toptions: RemoteVerificationOptions,\n): ProcessMissionVerifier | undefined {\n\tconst specs = collectVerificationSpecs(request);\n\tif (specs.length === 0) return undefined;\n\n\tconst executor = createRemoteVerificationExecutor(options);\n\n\treturn async (input): Promise<ProcessMissionVerification> => {\n\t\tif (input.outcome.exitCode !== 0 || input.outcome.launchError || input.outcome.timedOut) {\n\t\t\treturn { verified: false, summary: \"execution did not complete normally\" };\n\t\t}\n\n\t\tconst results = [];\n\t\tfor (const { criterionId, spec } of specs) {\n\t\t\tconst result = await verify(spec, executor, { criterionId, cwd: options.cwd });\n\t\t\tresults.push(result);\n\t\t}\n\n\t\tconst failed = results.filter((result) => !result.passed);\n\t\tconst verified = failed.length === 0;\n\t\treturn {\n\t\t\tverified,\n\t\t\tcriterionIds: results.map((result) => result.criterionId ?? result.kind),\n\t\t\tsummary: verified\n\t\t\t\t? `${results.length} verification spec(s) passed`\n\t\t\t\t: `${failed.length} verification spec(s) failed: ${failed\n\t\t\t\t\t\t.map((result) => result.evidence.summary)\n\t\t\t\t\t\t.join(\"; \")}`,\n\t\t};\n\t};\n}\n"]}