/** * Public Coder Role run: admit → post-admission coordinator → settle Terminal result (#109 / #517). * #109: package-owned TDD method, default apply / explicit plan, shared #106 success interface. * #526: execution via RoleTurnHost; argv is Pi adapter internal. */ import type { DurablePrincipalAuthority, MethodBinding, RoleTurnKnownFailure, RoleTurnRequest, } from "../host-contracts.ts"; import { engineSessionMaterialFromOptions, pickEngineAxis } from "../package-resources/engine-material.ts"; import { loadPackagedMethodSkillMaterial, resolvePackagedMethodSkillPath, type PackagedMethodSkillProvenance, } from "../package-resources/method-skill.ts"; import { CliUsageError } from "./cli-errors.ts"; import { admitCoderInvocation, buildCoderTransportPrompt, type AdmittedCoderInvocation, } from "./invocation.ts"; import { buildAutoResumeContinuationPrompt, loadResumableCoderRun, markRunAdmitted, type PublicResumeRequest, } from "./run-lifecycle.ts"; import { presentStructuralRejection, trySettleCoderTerminalResult, } from "./settlement.ts"; import type { CliIo } from "./cli-io.ts"; import type { TerminalResult } from "./terminal.ts"; import { projectRoleTurnRequest, type RoleTurnRequestProjectionOptions, } from "./turn-request.ts"; import { presentControlledFailure, resolveResumeMethodMaterialAdapters, runPostAdmissionResumable, runPostAdmissionSeatResume, type PostAdmissionAdapters, type PostAdmissionEnv, resumeTurnRequestProjectionOptions, } from "./post-admission.ts"; export type CoderRunEnv = PostAdmissionEnv & { createRunId?: () => string; }; function coderMethods( phase: string, packageRoot: string, ): readonly MethodBinding[] { return phase === "apply" ? [{ kind: "skill", path: resolvePackagedMethodSkillPath(packageRoot, "tdd") }] : []; } /** Project admitted Coder invocation onto the host-neutral turn request. */ export function buildCoderTurnRequest( admitted: AdmittedCoderInvocation, options: RoleTurnRequestProjectionOptions, ): RoleTurnRequest { return projectRoleTurnRequest( admitted, { activation: { role: "coder", phase: admitted.phase, taskPath: admitted.taskPath, }, methods: coderMethods(admitted.phase, options.packageRoot), }, options, ); } function coderAdapters( methodProvenance?: PackagedMethodSkillProvenance, ): PostAdmissionAdapters { return { trySettle: (admitted, authority, scope) => trySettleCoderTerminalResult( admitted, authority, { ...(methodProvenance === undefined ? {} : { methodProvenance }), }, scope, ), }; } export async function runPublicCoder( argv: readonly string[], env: CoderRunEnv, io: CliIo, parseCoderArgv: (args: readonly string[]) => { phase: "plan" | "apply"; instruction: string; attachmentPaths: string[]; project?: string; }, ): Promise<{ exitCode: number; admitted?: AdmittedCoderInvocation; terminal?: TerminalResult; }> { let admitted: AdmittedCoderInvocation; try { const parsed = parseCoderArgv(argv); admitted = await admitCoderInvocation({ home: env.home, principalAuthority: env.principalAuthority, cwd: env.cwd, phase: parsed.phase, instruction: parsed.instruction, attachmentPaths: parsed.attachmentPaths, ...(parsed.project === undefined ? {} : { project: parsed.project }), ...(env.createRunId === undefined ? {} : { createRunId: env.createRunId }), ...(env.model === undefined ? {} : { model: env.model }), }); } catch (error) { if (error instanceof CliUsageError) { presentStructuralRejection(error, io); return { exitCode: 2 }; } throw error; } await markRunAdmitted(admitted, env.principalAuthority); let methodProvenance: PackagedMethodSkillProvenance | undefined; if (admitted.phase === "apply") { try { const material = await loadPackagedMethodSkillMaterial( env.packageRoot, "tdd", ); methodProvenance = material.provenance; } catch (error) { return (await presentControlledFailure( admitted, { timedOut: false, code: null, stderr: "", thrown: error, knownCause: "activation", }, coderAdapters(), env.principalAuthority, io, )) as { exitCode: number; admitted: AdmittedCoderInvocation; terminal: TerminalResult }; } } return await runPostAdmissionResumable({ admitted, env, io, buildInitialRequest: () => buildCoderTurnRequest(admitted, { packageRoot: env.packageRoot, home: env.home, agentDir: env.agentDir, ...(env.model === undefined ? {} : { model: env.model }), ...pickEngineAxis(env), ...(env.timeoutMs === undefined ? {} : { timeoutMs: env.timeoutMs }), ...(admitted.correlationId === undefined && env.correlationId === undefined ? {} : { correlationId: admitted.correlationId ?? env.correlationId }), continuation: { kind: "initial", prompt: buildCoderTransportPrompt( admitted, engineSessionMaterialFromOptions({ ...pickEngineAxis(env), packageRoot: env.packageRoot, }), ), }, }), buildResumeRequest: () => buildCoderTurnRequest(admitted, { packageRoot: env.packageRoot, home: env.home, agentDir: env.agentDir, ...(env.model === undefined ? {} : { model: env.model }), ...pickEngineAxis(env), ...(env.timeoutMs === undefined ? {} : { timeoutMs: env.timeoutMs }), ...(admitted.correlationId === undefined && env.correlationId === undefined ? {} : { correlationId: admitted.correlationId ?? env.correlationId }), continuation: { kind: "resume", prompt: buildAutoResumeContinuationPrompt({ packageRoot: env.packageRoot, ...pickEngineAxis(env), }), }, }), adapters: coderAdapters(methodProvenance), ...(env.engine === undefined ? {} : { effectiveEngine: env.engine }), }); } /** * Resume a previously admitted Coder Role run after a typed HTTP 429. * Restores role/phase/task/session identity; model override is temporary. */ export async function runPublicCoderResume( request: PublicResumeRequest, env: CoderRunEnv, io: CliIo, ): Promise<{ exitCode: number; admitted?: AdmittedCoderInvocation; terminal?: TerminalResult; }> { return await runPostAdmissionSeatResume({ request, env, io, load: (effective) => loadResumableCoderRun(env.home, effective.runId, env.principalAuthority), buildTurnRequest: (admitted, effective) => buildCoderTurnRequest( admitted, resumeTurnRequestProjectionOptions(admitted, effective, env), ), adapters: coderAdapters(), // Apply-only method; plan resume keeps empty provenance (same as initial). afterAdmittedLoad: (admitted) => resolveResumeMethodMaterialAdapters({ admitted, authority: env.principalAuthority, io, shouldLoad: admitted.phase === "apply", loadMaterial: () => loadPackagedMethodSkillMaterial(env.packageRoot, "tdd"), adaptersWith: (material) => coderAdapters(material.provenance), emptyAdapters: coderAdapters(), knownCause: "activation", }), ...(env.engine === undefined ? {} : { effectiveEngine: env.engine }), }); } // Re-export for tests that assert typed credential failure channel shape. export type { RoleTurnKnownFailure, PackagedMethodSkillProvenance };