@bridge_gpt/mcp-server 0.2.57 → 0.2.58

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.
@@ -0,0 +1,72 @@
1
+ /** Human-readable progress for headless Cursor runs without exposing tool payloads. */
2
+ import { spawn } from "node:child_process";
3
+ import { createInterface } from "node:readline";
4
+ import { fileURLToPath } from "node:url";
5
+ import path from "node:path";
6
+ /** Only render assistant prose and tool NAMES; tool arguments/results may contain secrets. */
7
+ export function formatCursorProgressEvent(event) {
8
+ if (event.type === "system" && event.subtype === "init") {
9
+ return "Cursor agent started. Progress will appear below.\n";
10
+ }
11
+ if (event.type === "assistant") {
12
+ const content = event.message?.content;
13
+ const prose = (Array.isArray(content) ? content : [])
14
+ .filter((item) => item && item.type === "text" && typeof item.text === "string")
15
+ .map((item) => item.text)
16
+ .join("");
17
+ return prose ? `${prose}\n` : null;
18
+ }
19
+ if (event.type === "tool_call" && event.subtype === "started") {
20
+ const call = event.tool_call;
21
+ const name = call && typeof call === "object" && !Array.isArray(call)
22
+ ? Object.keys(call)[0]
23
+ : undefined;
24
+ if (!name)
25
+ return "Working with a tool...\n";
26
+ const label = name.replace(/ToolCall$/, "").replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
27
+ return `Using ${label}...\n`;
28
+ }
29
+ return null;
30
+ }
31
+ async function main(argv) {
32
+ const args = argv[0] === "--" ? argv.slice(1) : argv;
33
+ if (args[0] !== "cursor-agent") {
34
+ process.stderr.write("cursor-agent-progress expects cursor-agent as its child command.\n");
35
+ return 2;
36
+ }
37
+ const child = spawn(args[0], args.slice(1), { stdio: ["inherit", "pipe", "inherit"] });
38
+ const forwardSignal = (signal) => child.kill(signal);
39
+ process.on("SIGINT", forwardSignal);
40
+ process.on("SIGTERM", forwardSignal);
41
+ const completion = new Promise((resolve) => {
42
+ child.once("close", (code, signal) => resolve(code ?? (signal ? 128 : 1)));
43
+ child.once("error", () => resolve(1));
44
+ });
45
+ const lines = createInterface({ input: child.stdout });
46
+ let sawAssistantText = false;
47
+ for await (const line of lines) {
48
+ let event;
49
+ try {
50
+ event = JSON.parse(line);
51
+ }
52
+ catch {
53
+ continue;
54
+ }
55
+ const rendered = formatCursorProgressEvent(event);
56
+ if (rendered) {
57
+ if (event.type === "assistant")
58
+ sawAssistantText = true;
59
+ process.stdout.write(rendered);
60
+ }
61
+ if (event.type === "result" && !sawAssistantText && typeof event.result === "string") {
62
+ process.stdout.write(`${event.result}\n`);
63
+ }
64
+ }
65
+ const exit = await completion;
66
+ process.off("SIGINT", forwardSignal);
67
+ process.off("SIGTERM", forwardSignal);
68
+ return exit;
69
+ }
70
+ if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
71
+ void main(process.argv.slice(2)).then((code) => { process.exitCode = code; });
72
+ }
package/build/doctor.js CHANGED
@@ -1748,7 +1748,9 @@ export async function runDoctorCli(argv, overrides = {}) {
1748
1748
  const profile = await inspectBridgeCodexProfile(codexHome(deps.env), readCodexFile);
1749
1749
  log(profile.status === "active"
1750
1750
  ? "Codex Bridge approval profile installed; spawned workers use --profile bridge."
1751
- : `Codex Bridge approval profile ${profile.status}; spawned workers use existing Codex approvals. Run install --tools=codex --codex-profile=on to opt in.`);
1751
+ : profile.status === "stale"
1752
+ ? "Codex Bridge approval profile is an older unmodified managed version; the next spawned worker refreshes it before launch."
1753
+ : `Codex Bridge approval profile ${profile.status}; spawned workers use existing Codex approvals. Run install --tools=codex --codex-profile=on to opt in.`);
1752
1754
  }
1753
1755
  log(formatDoctorPrereqSection(deps.platform, collection));
1754
1756
  // Executor-adapter section (BAPI-781). Advisory with respect to the EXIT CODE
@@ -118,7 +118,7 @@ ${managedBlock}
118
118
  AND json_extract(data_json, '$.details.action_key') = ?
119
119
  LIMIT 1`).get(eventType,actionKey)!==void 0}finally{db.close()}}async function hasTerminalMergeSucceeded(actionKey,deps={}){return lookupMergeEventByActionKey("merge.succeeded",actionKey,deps)}async function hasMergeDryRun(actionKey,deps={}){return lookupMergeEventByActionKey("merge.dry_run",actionKey,deps)}async function hasMergePendingApproval(actionKey,deps={}){return lookupMergeEventByActionKey("merge.pending_approval",actionKey,deps)}function isDuplicateConstraintError4(error){if(!error||typeof error!="object")return!1;let code=error.code;if(typeof code=="string"&&code.startsWith("SQLITE_CONSTRAINT"))return!0;let message=error.message;if(typeof message=="string"){let lowered=message.toLowerCase();if(lowered.includes("unique constraint")||lowered.includes("constraint failed"))return!0}return!1}async function emitMergeLedgerEventIfNew(input,deps={}){let emitEvent=deps.emitEvent??emitConductorEvent,eventId=makeMergeEventId(input.type,input.action_key),event={id:eventId,source:"conductor-supervisor",type:input.type,run_id:input.run_id??null,worker_id:input.worker_id??null,producer:"conductor-merge",observed_via:"supervisor",data:{summary:input.summary??`${input.type} ${input.action_key}`,status:input.status,reason:input.reason??void 0,details:input.details}};try{let result=await emitEvent(event);return{emitted:!0,event_id:eventId,event:result.event}}catch(error){if(isDuplicateConstraintError4(error))return{emitted:!1,reason:"duplicate"};throw error}}var init_merge_ledger=__esm({"src/conductor/merge-ledger.ts"(){"use strict";init_event_accessors();init_merge_identity();init_store()}});function buildMergeRequestFromGateEvent(identity){return{repo_name:identity.repo,pr_number:identity.pr_number,expected_head_sha:identity.head_sha,gate:{name:identity.gate_name,config_hash:identity.config_hash,required_checks:identity.required_checks},action_key:identity.action_key,gate_event:identity.gate_event}}function mapApiErrorReason(error){if(error instanceof ConductorBridgeApiError)switch(error.kind){case"timeout":return"api_timeout";case"network":return"api_network";case"unauthorized":return"api_unauthorized";case"server":case"http":return"api_unavailable";case"invalid-input":return"api_invalid"}return"api_network"}function resolveAttributionWorkerId(event,identity,resolve2){if(typeof event.worker_id=="string"&&event.worker_id.trim().length>0)return event.worker_id.trim();if(resolve2){let resolved=resolve2(event,identity);if(typeof resolved=="string"&&resolved.trim().length>0)return resolved.trim()}return null}async function processGateMetMerge(access,event,deps={}){let extract=deps.extractIdentity??extractMergeActionIdentityFromGateEvent,checkTerminal=deps.hasTerminal??hasTerminalMergeSucceeded,checkDryRun=deps.hasDryRun??hasMergeDryRun,checkPendingApproval=deps.hasPendingApproval??hasMergePendingApproval,mergeFn=deps.merge??mergePullRequestForGate,identity=extract(event);if(!identity)return{processed:!1,reason:"ineligible"};let actionKey=identity.action_key,attributionWorkerId=resolveAttributionWorkerId(event,identity,deps.resolveWorkerIdForGateEvent);if(await checkTerminal(actionKey))return{processed:!1,reason:"already_succeeded"};let baseDetails={action_key:actionKey,repo:identity.repo,pr_number:identity.pr_number,expected_head_sha:identity.head_sha,gate:identity.gate_identity},response;try{response=await mergeFn(access,buildMergeRequestFromGateEvent(identity))}catch(error){let reason=mapApiErrorReason(error);return await emitMergeLedgerEventIfNew({type:"merge.failed",action_key:actionKey,status:"failed",reason,details:baseDetails,run_id:event.run_id??null,worker_id:attributionWorkerId,summary:`merge.failed ${reason}`},{emitEvent:deps.emitEvent}),{processed:!0,outcome:"api_error",reason}}let emitted=[];for(let ledgerEvent of response.ledger_events??[]){if(ledgerEvent.type==="merge.dry_run"&&await checkDryRun(actionKey)){emitted.push({type:ledgerEvent.type,emitted:!1});continue}if(ledgerEvent.type==="merge.pending_approval"&&await checkPendingApproval(actionKey)){emitted.push({type:ledgerEvent.type,emitted:!1});continue}let result=await emitMergeLedgerEventIfNew({type:ledgerEvent.type,action_key:actionKey,status:ledgerEvent.status,reason:ledgerEvent.reason??null,details:ledgerEvent.details??baseDetails,run_id:event.run_id??null,worker_id:attributionWorkerId},{emitEvent:deps.emitEvent});emitted.push({type:ledgerEvent.type,emitted:result.emitted})}return{processed:!0,outcome:response.status,emitted}}var init_supervisor_merge=__esm({"src/conductor/supervisor-merge.ts"(){"use strict";init_bridge_api_client();init_merge_ledger()}});async function dispatchSupervisorNotification(epicRunId,candidate,assessment,idempotencyKey){let result=await resolveConductorBridgeApiAccess();if(!result.ok)return;let{access}=result,url=buildConductorJiraUrl(access.baseUrl,`/epic-runs/${encodeURIComponent(epicRunId)}/notifications`),payload={repo_name:access.repoName,idempotency_key:idempotencyKey,summary:{reason:candidate.reason,kind:candidate.kind,worker_id:candidate.worker_id??null,elapsed_ms:candidate.elapsed_ms,ticket_key:candidate.context?.ticket_key??null,classification:assessment.classification}},headers={"X-API-Key":access.apiKey,"Content-Type":"application/json"};try{await fetchConductorJsonPostWithTimeout(url,headers,JSON.stringify(payload),CONDUCTOR_FETCH_TIMEOUT_MS,fetch)}catch{}}var init_supervisor_notification=__esm({"src/conductor/supervisor-notification.ts"(){"use strict";init_bridge_api_client()}});var supervisor_runtime_exports={};__export(supervisor_runtime_exports,{runSupervisor:()=>runSupervisor});function deterministicAssessment(candidate){return{classification:"stuck",confidence:1,reason:candidate.reason}}function terminalStatus(state){return Object.values(state.workers).some(w=>w.state==="failed")?"failed":"complete"}async function processEscalations(state,config,deps){let now=deps.now(),candidates=findSupervisorEscalationCandidates(state,config,now);for(let candidate of candidates){let decision=shouldEmitEscalation(state,candidate,config,now);if(!decision.emit)continue;let idempotency={run_id:state.run_id,worker_id:candidate.worker_id,reason:candidate.reason,kind:candidate.kind,cooldown_window:decision.cooldown_window},idempotencyKey=makeSupervisorIdempotencyKey(idempotency),assessment=deterministicAssessment(candidate);state.latest_assessment=assessment;let outcome="skipped";try{outcome=(await deps.emitAssessment({run_id:state.run_id,worker_id:candidate.worker_id,assessment,details:{elapsed_ms:candidate.elapsed_ms,...candidate.context},idempotency})).emitted?"emitted":"duplicate"}catch{outcome="skipped"}if(recordEscalationResult(state,candidate,decision.cooldown_window,idempotencyKey,outcome,now),(outcome==="emitted"||outcome==="duplicate")&&candidate.worker_id)try{await sendSupervisorEscalationWorkerMessageIfNew(candidate,assessment,state,{sendMessage:deps.sendWorkerMessage})}catch{}if(outcome==="emitted"&&(deps.log(formatEscalationForTerminal(state.run_id,candidate)),deps.dispatchNotification))try{await deps.dispatchNotification(state.run_id,candidate,assessment,idempotencyKey)}catch{}}}async function runSupervisor(options,deps={}){let runId=typeof options.run_id=="string"?options.run_id.trim():"";if(runId.length===0)throw new ConductorValidationError("Supervisor requires exactly one non-empty --run-id.");let config=options.config??resolveSupervisorConfig(options.overrides??{}),now=deps.now??(()=>Date.now()),log=deps.log??(m=>process.stdout.write(`${m}
120
120
  `)),errorLog=deps.errorLog??(m=>process.stderr.write(`${m}
121
- `)),waitForEvent=deps.waitForEvent??waitForConductorEvent,getSnapshot=deps.getSnapshot??getSupervisorSnapshot,upsertProjection=deps.upsertProjection??upsertSupervisorProjection,emitAssessment=deps.emitAssessment??emitSupervisorAssessmentIfNew,sendMessage=deps.sendWorkerMessage??sendWorkerMessage,resolveBridgeAccess=deps.resolveBridgeAccess??(()=>resolveConductorBridgeApiAccess()),processMerge=deps.processMerge??processGateMetMerge,dispatchNotification=deps.dispatchNotification??dispatchSupervisorNotification,bridgeAccess=null,bridgeAccessResolved=!1,processGateMetMerges=async events=>{let eligible=events.filter(e=>extractMergeActionIdentityFromGateEvent(e)!==null);if(eligible.length!==0){if(!bridgeAccessResolved){bridgeAccessResolved=!0;try{let result=await resolveBridgeAccess();bridgeAccess=result.ok?result.access:null,result.ok||errorLog(`[supervisor] run=${runId} auto-merge disabled: ${result.kind}`)}catch{bridgeAccess=null}}if(bridgeAccess)for(let event of eligible)try{await processMerge(bridgeAccess,event)}catch{}}},persist=async state2=>{try{await upsertProjection(toSupervisorProjectionInput(state2))}catch{}},state;try{let snapshot=await getSnapshot(runId);state=hydrateSupervisorRunStateFromSnapshot(snapshot,runId,config,now())}catch{return{run_id:runId,status:"failed",exit_code:2,reason:"supervisor failed to load initial snapshot",last_seq:0,worker_count:0}}let sinceSeq=state.last_seq>0?state.last_seq+1:1,iterationCap=Math.max(1e3,Math.ceil(config.global_timeout_ms/Math.max(1,config.wake_interval_ms))+16);try{applySupervisorHousekeeping(state,config,now());for(let iteration=0;iteration<iterationCap;iteration+=1){if(isSupervisorRunTerminal(state))return state.status=terminalStatus(state),await persist(state),log(`[supervisor] run=${runId} complete status=${state.status} workers=${Object.keys(state.workers).length}`),{run_id:runId,status:state.status,exit_code:0,reason:"all workers terminal",last_seq:state.last_seq,worker_count:Object.keys(state.workers).length};if(hasSupervisorGlobalTimeoutElapsed(state,now()))return state.status="timed_out",await persist(state),errorLog(`[supervisor] run=${runId} global timeout elapsed`),{run_id:runId,status:"timed_out",exit_code:2,reason:"global timeout elapsed",last_seq:state.last_seq,worker_count:Object.keys(state.workers).length};let waitResult=await waitForEvent({since_seq:sinceSeq,filter:{run_id:runId},data_mode:"full",timeout_ms:config.wake_interval_ms,limit:config.poll_limit});if(waitResult.events.length>0){let sorted=[...waitResult.events].sort((a,b)=>a.seq-b.seq);for(let event of sorted)applyConductorEventToSupervisorState(state,event,now());sinceSeq=sorted[sorted.length-1].seq+1,await processGateMetMerges(sorted)}applySupervisorHousekeeping(state,config,now()),await processEscalations(state,config,{emitAssessment,sendWorkerMessage:sendMessage,log,now,dispatchNotification}),await persist(state)}return state.status="timed_out",await persist(state),{run_id:runId,status:"timed_out",exit_code:2,reason:"supervisor iteration cap reached",last_seq:state.last_seq,worker_count:Object.keys(state.workers).length}}catch{state.status="failed";try{await upsertProjection(toSupervisorProjectionInput(state))}catch{}return errorLog(`[supervisor] run=${runId} failed unexpectedly`),{run_id:runId,status:"failed",exit_code:2,reason:"supervisor failed unexpectedly",last_seq:state.last_seq,worker_count:Object.keys(state.workers).length}}}var init_supervisor_runtime=__esm({"src/conductor/supervisor-runtime.ts"(){"use strict";init_store();init_supervisor_ledger();init_supervisor_message_relay();init_supervisor_config();init_supervisor_state();init_supervisor_escalation();init_supervisor_ledger();init_bridge_api_client();init_merge_ledger();init_supervisor_merge();init_supervisor_notification();init_errors()}});import path7 from"path";function buildSetupUrl(baseUrl){return`${baseUrl.replace(/\/+$/,"")}/setup`}async function resolveInstallDoctorTarget(deps){let envRepo=deps.env.BAPI_REPO_NAME?.trim(),envBase=deps.env.BAPI_BASE_URL?.trim(),repoName=envRepo&&envRepo.length>0?envRepo:null,repoSource=repoName?"env":null,baseUrl=envBase&&envBase.length>0?envBase:null;if(!repoName||!baseUrl)for(let{relPath,topLevelKey}of MCP_CONFIG_ENV_TARGETS){let raw;try{raw=await deps.readFile(path7.join(deps.cwd,relPath))}catch{continue}let parsed;try{parsed=JSON.parse(raw)}catch{continue}let servers=parsed&&typeof parsed=="object"?parsed[topLevelKey]:void 0,registrationKey=existingRegistrationKey(servers),envBlock=registrationKey!==null?servers[registrationKey]?.env:void 0;if(envBlock&&(!repoName&&typeof envBlock.BAPI_REPO_NAME=="string"&&envBlock.BAPI_REPO_NAME.trim()&&(repoName=envBlock.BAPI_REPO_NAME.trim(),repoSource="config"),!baseUrl&&typeof envBlock.BAPI_BASE_URL=="string"&&envBlock.BAPI_BASE_URL.trim()&&(baseUrl=envBlock.BAPI_BASE_URL.trim()),repoName&&baseUrl))break}return{repoName,repoSource,baseUrl:baseUrl??DEFAULT_BASE_URL}}function classifyProbeFailure(error){let name=error?.name;return name==="TimeoutError"||name==="AbortError"?"request timed out":"request unavailable"}async function probeGet(deps,url,apiKey){try{let resp=await deps.fetch(url,{headers:{"X-API-Key":apiKey},signal:AbortSignal.timeout(PROBE_TIMEOUT_MS)}),body=null;try{body=await resp.json()}catch{}return{ok:!0,status:resp.status,body}}catch(e){return{ok:!1,error:classifyProbeFailure(e)}}}function summarizeManifestGroups(body){if(!body||typeof body!="object")return null;let groups=body.groups;if(!Array.isArray(groups))return null;let total=0,unset=[];for(let group of groups){let fields=group?.fields;if(Array.isArray(fields))for(let field of fields){let name=field?.field_name;typeof name=="string"&&(total+=1,field.is_set||unset.push(name))}}return{total,unset}}function summarizeIntegrations(body){if(!body||typeof body!="object")return null;let integrations=body.integrations;if(!Array.isArray(integrations))return null;let total=0,unconfigured=[];for(let item of integrations){let label=item?.label;typeof label=="string"&&(total+=1,item.is_configured||unconfigured.push(label))}return{total,unconfigured}}function readGithubConfiguredFlag(body){if(!body||typeof body!="object")return null;let integrations=body.integrations;if(!Array.isArray(integrations))return null;for(let item of integrations){if(item?.id!=="github_app")continue;let configured=item.is_configured;return typeof configured=="boolean"?configured:null}return null}async function collectInstallStatusChecks(deps){let checks=[],loginResult=await detectClaudeLogin({homedir:deps.homedir,readFile:deps.readFile});checks.push({id:"claude-login",label:"Claude login",status:loginResult.detected?"PASS":"INFO",detail:formatClaudeLoginAdvisory(loginResult)});let target=await resolveInstallDoctorTarget(deps);if(!target.repoName)return checks.push({id:"identity",label:"Repository identity",status:"SKIP",detail:"no BAPI_REPO_NAME in the environment or project-local MCP configs",remediation:"run install-bridge (or set BAPI_REPO_NAME) to configure this project."}),checks;checks.push({id:"identity",label:"Repository identity",status:"PASS",detail:`${target.repoName} (from ${target.repoSource}), base URL ${target.baseUrl}`});let setupUrl=buildSetupUrl(target.baseUrl),credDeps={env:deps.env,homedir:deps.homedir,platform:deps.platform,readFile:deps.readFile,stat:deps.stat,stderr:()=>{}},cred=await resolveBapiCredentials(target.repoName,credDeps);if(!cred.ok){checks.push({id:"credential",label:"Bridge API credential",status:"WARN",detail:`not resolved (${cred.kind})`,remediation:"set BAPI_API_KEY or persist it via /install-bridge / the credentials subcommand; until then the remaining install checks are skipped."});for(let[id,label]of[["connectivity","Server connectivity"],["bootstrap","Bootstrap config fields"],["indexing","Repository indexing"]])checks.push({id,label,status:"SKIP",detail:"no credential resolved"});return checks}checks.push({id:"credential",label:"Bridge API credential",status:"PASS",detail:`resolved from ${cred.credentials.source} (value never read into the report)`});let apiKey=cred.credentials.apiKey,repoQuery=`repo_name=${encodeURIComponent(target.repoName)}`,ping=await probeGet(deps,`${target.baseUrl}/jira/ping?${repoQuery}`,apiKey);ping.ok?ping.status===200?checks.push({id:"connectivity",label:"Server connectivity",status:"PASS",detail:"ping OK"}):ping.status===401||ping.status===403?checks.push({id:"connectivity",label:"Server connectivity",status:"WARN",detail:`the server rejected the resolved key (HTTP ${ping.status})`,remediation:"the key may have been rotated \u2014 re-run install-bridge with a current key."}):ping.status===404?checks.push({id:"connectivity",label:"Server connectivity",status:"WARN",detail:`the server does not know repo '${target.repoName}' (HTTP 404)`,remediation:`create the project at ${setupUrl} (setup UI), or check BAPI_REPO_NAME spelling.`}):checks.push({id:"connectivity",label:"Server connectivity",status:"WARN",detail:`unexpected HTTP ${ping.status} from /jira/ping`,remediation:"the server answered but not with a status this check understands \u2014 re-run doctor; if it persists the Bridge API is unhealthy and no install fact below can be trusted."}):checks.push({id:"connectivity",label:"Server connectivity",status:"WARN",detail:`unreachable (${ping.error})`,remediation:`check ${target.baseUrl} and your network, then re-run doctor.`});let manifest=await probeGet(deps,`${target.baseUrl}/jira/config/install-manifest?${repoQuery}`,apiKey);if(!manifest.ok)checks.push({id:"bootstrap",label:"Bootstrap config fields",status:"WARN",detail:`manifest unreachable (${manifest.error})`,remediation:`check ${target.baseUrl} and your network, then re-run doctor.`});else if(manifest.status===404)checks.push({id:"bootstrap",label:"Bootstrap config fields",status:"WARN",detail:"no configuration row found for this repository",remediation:`create the project at ${setupUrl} (setup UI), then run /install-bridge.`});else if(manifest.status===200){let summary=summarizeManifestGroups(manifest.body);summary?summary.unset.length===0?checks.push({id:"bootstrap",label:"Bootstrap config fields",status:"PASS",detail:`${summary.total}/${summary.total} bootstrap fields set`}):checks.push({id:"bootstrap",label:"Bootstrap config fields",status:"WARN",detail:`${summary.total-summary.unset.length}/${summary.total} set; unset: ${summary.unset.join(", ")}`,remediation:"run /install-bridge to derive the unset fields (intentionally-unset fields are fine to leave)."}):checks.push({id:"bootstrap",label:"Bootstrap config fields",status:"WARN",detail:"manifest response had an unexpected shape",remediation:"the manifest could not be read, so no bootstrap field state is known \u2014 re-run doctor, then run /install-bridge to re-derive the project configuration."})}else checks.push({id:"bootstrap",label:"Bootstrap config fields",status:"WARN",detail:`unexpected HTTP ${manifest.status} from the install manifest`,remediation:"the manifest endpoint answered with an unrecognized status \u2014 re-run doctor; if it persists, re-run /install-bridge for this repository."});if(manifest.ok&&manifest.status===200){let integrations=summarizeIntegrations(manifest.body);integrations===null?checks.push({id:"integrations",label:"Integration credentials",status:"SKIP",detail:"the manifest response carried no integrations checklist"}):integrations.unconfigured.length===0?checks.push({id:"integrations",label:"Integration credentials",status:"PASS",detail:`${integrations.total}/${integrations.total} configured`}):checks.push({id:"integrations",label:"Integration credentials",status:"WARN",detail:`not configured: ${integrations.unconfigured.join(", ")}`,remediation:`a human configures these at ${setupUrl} (setup UI \u2192 project settings) \u2014 Bridge API never accepts integration secrets through an agent or MCP tool.`})}else checks.push({id:"integrations",label:"Integration credentials",status:"SKIP",detail:"manifest unavailable"});if(manifest.ok&&manifest.status===200){let github=readGithubConfiguredFlag(manifest.body);github===null?checks.push({id:"github",label:"GitHub connection",status:"SKIP",detail:"the manifest response carried no GitHub integration entry"}):github?checks.push({id:"github",label:"GitHub connection",status:"PASS",detail:"a GitHub repository is connected to this project"}):checks.push({id:"github",label:"GitHub connection",status:"WARN",detail:"no GitHub repository is connected to this project",remediation:`run 'npx -y ${MCP_PACKAGE_NAME}@latest connect-github --repo ${target.repoName}'.`})}else checks.push({id:"github",label:"GitHub connection",status:"SKIP",detail:"manifest unavailable"});let parse=await probeGet(deps,`${target.baseUrl}/jira/parse-status?${repoQuery}`,apiKey);if(!parse.ok||parse.status!==200)checks.push({id:"indexing",label:"Repository indexing",status:"SKIP",detail:parse.ok?`HTTP ${parse.status} from /jira/parse-status`:`unreachable (${parse.error})`});else if(parse.body?.status==="in_progress"){let startedAt=parse.body.started_at;checks.push({id:"indexing",label:"Repository indexing",status:"INFO",detail:`parse job in progress${typeof startedAt=="string"?` (started ${startedAt})`:""}`})}else checks.push({id:"indexing",label:"Repository indexing",status:"INFO",detail:'no parse job currently running \u2014 if this repository has never been indexed, queue one with /parse-repository (monitor with parse_repository action "status").'});return checks}function projectInstallStatus(check){return check.status==="PASS"?{status:"pass"}:check.status==="WARN"?{status:"warn",...check.remediation?{remediation:check.remediation}:{}}:check.status==="INFO"?check.id==="claude-login"?{status:"warn",remediation:INSTALL_CLAUDE_LOGIN_REMEDIATION}:{status:"pass"}:check.id==="identity"?{status:"fail",remediation:check.remediation??INSTALL_IDENTITY_REMEDIATION}:{status:"skip",...check.remediation?{remediation:check.remediation}:{}}}function mapInstallStatusChecksToReadinessChecks(checks,collectorUnavailable=!1){let byId=new Map;for(let check of checks??[])byId.has(check.id)||byId.set(check.id,check);return INSTALL_READINESS_DESCRIPTORS.map(({id,label})=>{let source=byId.get(id);if(!source)return collectorUnavailable?createReadinessCheck({id:`install.${id}`,source:"install",label,status:"fail",detail:INSTALL_UNAVAILABLE_DETAIL,remediation:INSTALL_UNAVAILABLE_REMEDIATION}):createReadinessCheck({id:`install.${id}`,source:"install",label,status:"skip",detail:INSTALL_NOT_COLLECTED_DETAIL});let projected=projectInstallStatus(source);return createReadinessCheckSafely({id:`install.${id}`,source:"install",label:source.label||label,status:projected.status,...source.detail?{detail:source.detail}:{},...projected.status==="pass"?{}:projected.remediation?{remediation:projected.remediation}:projected.status==="fail"?{remediation:INSTALL_IDENTITY_REMEDIATION}:{}})})}var DEFAULT_BASE_URL,MCP_CONFIG_ENV_TARGETS,PROBE_TIMEOUT_MS,INSTALL_READINESS_DESCRIPTORS,INSTALL_IDENTITY_REMEDIATION,INSTALL_CLAUDE_LOGIN_REMEDIATION,INSTALL_NOT_COLLECTED_DETAIL,INSTALL_UNAVAILABLE_DETAIL,INSTALL_UNAVAILABLE_REMEDIATION,init_install_doctor=__esm({"src/install-doctor.ts"(){"use strict";init_readiness_check();init_credential_store();init_claude_login();init_mcp_host_targets();init_mcp_identity();DEFAULT_BASE_URL="https://bridgegpt-api.com";MCP_CONFIG_ENV_TARGETS=getProjectJsonTargets().map(target=>({relPath:target.relPath,topLevelKey:hostAdapterForTarget(target).topLevelKey})),PROBE_TIMEOUT_MS=5e3;INSTALL_READINESS_DESCRIPTORS=[{id:"claude-login",label:"Claude login"},{id:"identity",label:"Repository identity"},{id:"credential",label:"Bridge API credential"},{id:"connectivity",label:"Server connectivity"},{id:"bootstrap",label:"Bootstrap config fields"},{id:"integrations",label:"Integration credentials"},{id:"github",label:"GitHub connection"},{id:"indexing",label:"Repository indexing"}],INSTALL_IDENTITY_REMEDIATION="run /install-bridge (or set BAPI_REPO_NAME) to configure this project; without a repository identity no server-side conductor fact can be resolved.",INSTALL_CLAUDE_LOGIN_REMEDIATION="run `claude login` on the host that will run conductor workers; Bridge stores no Anthropic credential and cannot confirm this for you.",INSTALL_NOT_COLLECTED_DETAIL="not collected \u2014 an earlier install prerequisite stopped the checklist",INSTALL_UNAVAILABLE_DETAIL="unknown \u2014 the install-status checklist could not be collected at all",INSTALL_UNAVAILABLE_REMEDIATION="run `doctor` to collect the advisory install-status checklist directly; this prerequisite's state is unknown, not healthy."}});function planeCheckPassed(check,label,detail){return{diagnostic:null,outcomes:[{check,id:check,label,status:"pass",...detail?{detail}:{}}]}}function planeCheckFinding(diagnostic,label,detail){return{diagnostic,outcomes:[{check:diagnostic.check,id:diagnostic.check,label,status:diagnostic.severity==="blocking"?"fail":"warn",detail,...diagnostic.remediation?{remediation:diagnostic.remediation}:{}}]}}var PLANE_MANIFEST_SUPPORTED_SCHEMA_VERSIONS,PLANE_RUNTIME_DIR,PLANE_MANIFEST_FILENAME,PLANE_RUNTIME_LOG_FILENAME,PLANE_RUNTIME_LOG_PATH,PLANE_SERVER_HOST,PLANE_SERVER_PORT,PLANE_SERVER_BASE_URL,PLANE_SERVER_PORT_ENV_VAR,PLANE_LIFECYCLE_PHASES,init_types2=__esm({"src/plane/types.ts"(){"use strict";PLANE_MANIFEST_SUPPORTED_SCHEMA_VERSIONS=[1,2,3],PLANE_RUNTIME_DIR=".bridge/plane",PLANE_MANIFEST_FILENAME="plane.json",PLANE_RUNTIME_LOG_FILENAME="runtime.log",PLANE_RUNTIME_LOG_PATH=`${PLANE_RUNTIME_DIR}/${PLANE_RUNTIME_LOG_FILENAME}`,PLANE_SERVER_HOST="127.0.0.1",PLANE_SERVER_PORT=8e3,PLANE_SERVER_BASE_URL=`http://${PLANE_SERVER_HOST}:${PLANE_SERVER_PORT}`,PLANE_SERVER_PORT_ENV_VAR="BAPI_PLANE_PORT";PLANE_LIFECYCLE_PHASES=["control-plane-starting","control-plane-ready","lanes-starting","lanes-ready","ready","lanes-failed"]}});import path8 from"path";function isRelevantSourceFile(name){return!(!name.endsWith(".ts")||name.endsWith(".generated.ts"))}async function findNewestSourceMtime(srcDir,deps){let newest=null,walk=async dir=>{let entries;try{entries=await deps.fs.readdir(dir)}catch(err){return sanitize(err)}for(let entry of entries){if(entry.isDirectory()){if(EXCLUDED_DIR_NAMES.has(entry.name))continue;let error2=await walk(path8.join(dir,entry.name));if(error2)return error2;continue}if(!(!entry.isFile()||!isRelevantSourceFile(entry.name)))try{let stat3=await deps.fs.stat(path8.join(dir,entry.name));(newest===null||stat3.mtimeMs>newest)&&(newest=stat3.mtimeMs)}catch(err){return sanitize(err)}}return null},error=await walk(srcDir);return error?{ok:!1,error}:{ok:!0,mtimeMs:newest}}async function findBuildMtime(executorEntrypoint,deps){try{return{ok:!0,mtimeMs:(await deps.fs.stat(executorEntrypoint)).mtimeMs}}catch(err){return{ok:!1,error:sanitize(err)}}}async function checkPlaneBuildFreshness(repoRoot,deps){let label="Executor build freshness",packageRoot=path8.join(repoRoot,"mcp_server"),buildDir=path8.join(packageRoot,"build"),executorEntrypoint=path8.join(buildDir,"index.js"),srcDir=path8.join(packageRoot,"src"),buildMtime=await findBuildMtime(executorEntrypoint,deps);if(!buildMtime.ok)return planeCheckFinding({check:"executor-build",severity:"blocking",message:`the executor build entrypoint is missing or unreadable at mcp_server/build/index.js \u2014 run \`${PLANE_BUILD_REMEDIATION}\``,remediation:PLANE_BUILD_FIX_REMEDIATION},label,"the executor build entrypoint is missing or unreadable");let sourceMtime=await findNewestSourceMtime(srcDir,deps);return sourceMtime.ok?sourceMtime.mtimeMs!==null&&sourceMtime.mtimeMs>buildMtime.mtimeMs?planeCheckFinding({check:"executor-build",severity:"blocking",message:`mcp_server/build/ is STALE \u2014 a source file under mcp_server/src is newer than mcp_server/build/index.js, so executors would run old code. Run \`${PLANE_BUILD_REMEDIATION}\``,remediation:PLANE_BUILD_FIX_REMEDIATION},label,"mcp_server/build/ is stale \u2014 a source file is newer than the build entrypoint"):planeCheckPassed("executor-build",label,"the executor build is present and current"):planeCheckFinding({check:"executor-build",severity:"blocking",message:`could not read mcp_server/src to compare against the build (${sourceMtime.error}) \u2014 run \`${PLANE_BUILD_REMEDIATION}\``,remediation:PLANE_BUILD_FIX_REMEDIATION},label,`the executor sources could not be read for comparison (${sourceMtime.error})`)}function checkPlaneRuntimeEntrypoint(resolution){let label="Runtime re-exec entrypoint";return resolution.ok?planeCheckPassed("runtime-entrypoint",label,"the executing build can re-enter itself"):planeCheckFinding({check:"runtime-entrypoint",severity:"blocking",message:PLANE_RUNTIME_ENTRYPOINT_REFUSAL,remediation:PLANE_BUILD_FIX_REMEDIATION},label,"the currently executing MCP build could not be re-entered")}function sanitize(err){let code=err?.code;return typeof code=="string"?code:"unreadable"}var PLANE_BUILD_REMEDIATION,EXCLUDED_DIR_NAMES,PLANE_BUILD_FIX_REMEDIATION,PLANE_RUNTIME_ENTRYPOINT_REFUSAL,init_build_freshness=__esm({"src/plane/build-freshness.ts"(){"use strict";init_types2();PLANE_BUILD_REMEDIATION="cd mcp_server && npm run build",EXCLUDED_DIR_NAMES=new Set(["node_modules","build"]);PLANE_BUILD_FIX_REMEDIATION="run `cd mcp_server && npm run build` to rebuild the executor entrypoint, then retry.";PLANE_RUNTIME_ENTRYPOINT_REFUSAL=`the currently executing MCP build could not be re-entered \u2014 \`plane up\` re-execs this package's own compiled entrypoint to create the detached runtime, and no existing entrypoint belonging to it could be found. Run \`${PLANE_BUILD_REMEDIATION}\` and retry from the rebuilt CLI.`}});import path9 from"path";function resolveRepositoryAlembicCommand(repoRoot,platform){return platform==="win32"?path9.join(repoRoot,".venv","Scripts","alembic.exe"):path9.join(repoRoot,".venv","bin","alembic")}function parseAlembicRevisions(output){let revisions=new Set;for(let rawLine of output.split(/\r?\n/)){let line=rawLine.trim();if(line.length===0||LOG_LINE_PATTERN.test(line))continue;let token=line.split(/\s+/)[0];!token||NON_REVISION_TOKENS.has(token.toLowerCase())||REVISION_PATTERN.test(token)&&revisions.add(token)}return revisions.size===0?null:[...revisions].sort()}async function checkAlembicHead(repoRoot,deps){let alembic=resolveRepositoryAlembicCommand(repoRoot,deps.platform);if(!await deps.fileExists(alembic))return unverified("the repository virtualenv Alembic executable was not found","the repository virtualenv Alembic executable was not found");let heads=await deps.execFile(alembic,["-c","alembic.ini","heads"],{cwd:repoRoot});if(!heads.ok)return unverified(`\`alembic heads\` did not complete (${heads.error})`,"`alembic heads` did not complete");let current=await deps.execFile(alembic,["-c","alembic.ini","current"],{cwd:repoRoot});if(!current.ok)return unverified(`\`alembic current\` did not complete (${current.error})`,"`alembic current` did not complete");let headRevisions=parseAlembicRevisions(heads.stdout),currentRevisions=parseAlembicRevisions(current.stdout);return headRevisions===null||currentRevisions===null?unverified("Alembic output did not contain a readable revision","Alembic output did not contain a readable revision"):headRevisions.length===currentRevisions.length&&headRevisions.every((rev,i)=>rev===currentRevisions[i])?planeCheckPassed("alembic-head",ALEMBIC_CHECK_LABEL,"the database is at the repository migration head"):planeCheckFinding({check:"alembic-head",severity:"blocking",message:`the database is not at the migration head \u2014 heads [${headRevisions.join(", ")}], current [${currentRevisions.join(", ")}]. A database behind the head blocks conductor dispatch. Run \`${PLANE_ALEMBIC_REMEDIATION}\``,remediation:PLANE_ALEMBIC_MISMATCH_REMEDIATION},ALEMBIC_CHECK_LABEL,`database at [${currentRevisions.join(", ")}], repository head [${headRevisions.join(", ")}]`)}function unverified(messageDetail,outcomeDetail){let diagnostic={check:"alembic-head",severity:"warning",message:`${PLANE_ALEMBIC_UNVERIFIED_PREFIX}: ${messageDetail}. Startup continues \u2014 verify with \`alembic -c alembic.ini heads\` and \`alembic -c alembic.ini current\` if a run later reports CONTRACT_MIGRATION_BEHIND.`,remediation:PLANE_ALEMBIC_UNVERIFIED_REMEDIATION};return planeCheckFinding(diagnostic,ALEMBIC_CHECK_LABEL,`${PLANE_ALEMBIC_UNVERIFIED_PREFIX}: ${outcomeDetail}`)}var PLANE_ALEMBIC_REMEDIATION,PLANE_ALEMBIC_UNVERIFIED_PREFIX,PLANE_ALEMBIC_MISMATCH_REMEDIATION,PLANE_ALEMBIC_UNVERIFIED_REMEDIATION,LOG_LINE_PATTERN,REVISION_PATTERN,NON_REVISION_TOKENS,ALEMBIC_CHECK_LABEL,init_alembic_head=__esm({"src/plane/alembic-head.ts"(){"use strict";init_types2();PLANE_ALEMBIC_REMEDIATION="alembic -c alembic.ini upgrade head",PLANE_ALEMBIC_UNVERIFIED_PREFIX="could not verify database migration head",PLANE_ALEMBIC_MISMATCH_REMEDIATION=`run \`${PLANE_ALEMBIC_REMEDIATION}\` to bring the database up to the migration head, then retry.`,PLANE_ALEMBIC_UNVERIFIED_REMEDIATION="verify by hand with `alembic -c alembic.ini heads` and `alembic -c alembic.ini current`; startup continues, and the server reports CONTRACT_MIGRATION_BEHIND at dispatch if the database is behind.";LOG_LINE_PATTERN=/^(INFO|WARNING|ERROR|DEBUG|CRITICAL)\b|\[alembic/i,REVISION_PATTERN=/^[0-9A-Za-z][0-9A-Za-z_.-]*$/,NON_REVISION_TOKENS=new Set(["head","heads","base","none","(head)"]);ALEMBIC_CHECK_LABEL="Database migration head"}});import path10 from"path";function getPlanePaths(repoRoot){let planeDir=path10.join(repoRoot,".bridge","plane");return{planeDir,manifestPath:path10.join(planeDir,PLANE_MANIFEST_FILENAME),logPathFor:member=>path10.join(planeDir,`${member}.log`)}}function relativeLogPathFor(member){return`${PLANE_RUNTIME_DIR}/${member}.log`}function isNonBlankTrimmedString(value){return typeof value=="string"&&value.trim().length>0&&value===value.trim()}function isPlaneMemberName(value){return typeof value!="string"?!1:value==="server"||value==="worker"||value==="observer"?!0:/^executor-[1-9][0-9]*$/.test(value)}function isPositiveInteger(value){return typeof value=="number"&&Number.isSafeInteger(value)&&value>0}function isIsoTimestamp(value){return typeof value=="string"&&value.length>0&&!Number.isNaN(Date.parse(value))}function parsePlaneManifest(value){if(typeof value!="object"||value===null||Array.isArray(value))return{ok:!1,error:"manifest is not an object"};let record=value;for(let key of Object.keys(record))if(!MANIFEST_KEYS.has(key))return{ok:!1,error:`manifest has an unsupported field '${key}'`};if(typeof record.schemaVersion!="number"||!PLANE_MANIFEST_SUPPORTED_SCHEMA_VERSIONS.includes(record.schemaVersion))return{ok:!1,error:`manifest schema version ${JSON.stringify(record.schemaVersion)} is not supported (this build reads ${PLANE_MANIFEST_SUPPORTED_SCHEMA_VERSIONS.join(", ")}). A manifest from a NEWER build must be wound down with that build's \`plane down\``};if(typeof record.planeId!="string"||!/^[0-9a-f-]{8,}$/i.test(record.planeId))return{ok:!1,error:"manifest plane identity is missing or malformed"};if(typeof record.repoRoot!="string"||record.repoRoot.length===0)return{ok:!1,error:"manifest repository root is missing"};if(!isPositiveInteger(record.supervisorPid))return{ok:!1,error:"manifest supervisor pid is not a positive integer"};if(!isPositiveInteger(record.supervisorPgid))return{ok:!1,error:"manifest supervisor process-group id is not a positive integer"};if(!isIsoTimestamp(record.createdAt)||!isIsoTimestamp(record.updatedAt))return{ok:!1,error:"manifest timestamps are missing or malformed"};if(!Array.isArray(record.members)||record.members.length===0)return{ok:!1,error:"manifest members are missing"};if(record.epicRunId!==void 0&&!isNonBlankTrimmedString(record.epicRunId))return{ok:!1,error:"manifest epic run id is malformed"};if(record.lifecycle!==void 0&&!LIFECYCLE_PHASES.has(record.lifecycle))return{ok:!1,error:"manifest lifecycle phase is malformed"};let laneScope=parseManifestLaneScope(record.laneScope);if(!laneScope.ok)return{ok:!1,error:laneScope.error};let members=[],unrecognizedMemberNames=[],seen=new Set;for(let raw of record.members){if(typeof raw!="object"||raw===null||Array.isArray(raw))return{ok:!1,error:"manifest member is not an object"};let member=raw;for(let key of Object.keys(member))if(!MEMBER_KEYS.has(key))return{ok:!1,error:`manifest member has an unsupported field '${key}'`};if(typeof member.name!="string"||member.name.length===0)return{ok:!1,error:"manifest member name is missing or not a string"};if(!isPlaneMemberName(member.name)){unrecognizedMemberNames.includes(member.name)||unrecognizedMemberNames.push(member.name);continue}if(seen.has(member.name))return{ok:!1,error:`manifest lists member '${member.name}' more than once`};if(seen.add(member.name),member.pid!==null&&!isPositiveInteger(member.pid))return{ok:!1,error:`manifest member '${member.name}' has an invalid pid`};if(typeof member.state!="string"||!VALID_STATES.has(member.state))return{ok:!1,error:`manifest member '${member.name}' has an invalid state`};if(member.exitCode!==null&&!Number.isSafeInteger(member.exitCode))return{ok:!1,error:`manifest member '${member.name}' has an invalid exit code`};if(member.exitSignal!==null&&typeof member.exitSignal!="string")return{ok:!1,error:`manifest member '${member.name}' has an invalid exit signal`};if(member.logPath!==relativeLogPathFor(member.name))return{ok:!1,error:`manifest member '${member.name}' has an unexpected log path`};members.push({name:member.name,pid:member.pid,state:member.state,exitCode:member.exitCode,exitSignal:member.exitSignal,logPath:member.logPath})}return members.length===0?{ok:!1,error:`manifest lists no member this build recognizes (unrecognized: ${unrecognizedMemberNames.join(", ")}). It was written by a newer build; wind the plane down with that build's \`plane down\``}:{ok:!0,unrecognizedMemberNames,manifest:{schemaVersion:record.schemaVersion,planeId:record.planeId,repoRoot:record.repoRoot,supervisorPid:record.supervisorPid,supervisorPgid:record.supervisorPgid,createdAt:record.createdAt,updatedAt:record.updatedAt,members,...record.epicRunId!==void 0?{epicRunId:record.epicRunId}:{},...record.lifecycle!==void 0?{lifecycle:record.lifecycle}:{},...laneScope.scope!==void 0?{laneScope:laneScope.scope}:{}}}}function parseManifestLaneScope(value){if(value===void 0)return{ok:!0};if(typeof value!="object"||value===null||Array.isArray(value))return{ok:!1,error:"manifest lane scope is not an object"};let record=value;if(record.kind==="repo-wide")return Object.keys(record).length!==1?{ok:!1,error:"manifest lane scope has unsupported fields"}:{ok:!0,scope:{kind:"repo-wide"}};if(record.kind!=="epic-runs")return{ok:!1,error:"manifest lane scope kind is malformed"};if(Object.keys(record).length!==2||!Array.isArray(record.epicRunIds))return{ok:!1,error:"manifest lane scope epic run ids are malformed"};let ids=record.epicRunIds;return ids.length===0||!ids.every(id=>isNonBlankTrimmedString(id))?{ok:!1,error:"manifest lane scope epic run ids are malformed"}:{ok:!0,scope:{kind:"epic-runs",epicRunIds:ids}}}function planeManifestLifecycle(manifest){return manifest.lifecycle??"ready"}async function readPlaneManifest(repoRoot,fs2){let{manifestPath}=getPlanePaths(repoRoot),raw;try{raw=await fs2.readFile(manifestPath)}catch(err){let code=err?.code;return code==="ENOENT"?{kind:"missing"}:{kind:"unreadable",error:typeof code=="string"?code:"read failed"}}let parsed;try{parsed=JSON.parse(raw)}catch{return{kind:"malformed",error:"manifest is not valid JSON"}}let result=parsePlaneManifest(parsed);return result.ok?{kind:"valid",manifest:result.manifest,unrecognizedMemberNames:result.unrecognizedMemberNames}:{kind:"malformed",error:result.error}}function isProcessAlive(pid,kill){if(!isPositiveInteger(pid))return"unknown";try{return kill(pid,0),"alive"}catch(err){let code=err?.code;return code==="ESRCH"?"dead":code==="EPERM"?"alive":"unknown"}}function probeManifestMembers(manifest,proc){return manifest.members.map(member=>member.state==="exited"||member.pid===null?{member,liveness:"dead"}:{member,liveness:proc.isAlive(member.pid)})}function manifestHasLiveProcess(manifest,proc){return proc.isAlive(manifest.supervisorPid)!=="dead"?!0:probeManifestMembers(manifest,proc).some(probe=>probe.liveness!=="dead")}var VALID_STATES,MANIFEST_KEYS,LIFECYCLE_PHASES,MEMBER_KEYS,init_manifest=__esm({"src/plane/manifest.ts"(){"use strict";init_types2();VALID_STATES=new Set(["spawning","running","ready","exited"]),MANIFEST_KEYS=new Set(["schemaVersion","planeId","repoRoot","supervisorPid","supervisorPgid","createdAt","updatedAt","members","epicRunId","lifecycle","laneScope"]),LIFECYCLE_PHASES=new Set(PLANE_LIFECYCLE_PHASES);MEMBER_KEYS=new Set(["name","pid","state","exitCode","exitSignal","logPath"])}});import path11 from"path";function classifyLivePlaneForAttach(repoRoot,manifest,proc){if(manifest.repoRoot!==repoRoot)return{kind:"foreign-root"};let lifecycle=planeManifestLifecycle(manifest),probes=probeManifestMembers(manifest,proc),memberAlive=name=>probes.some(probe=>probe.member.name===name&&probe.liveness==="alive");return!memberAlive("server")||!memberAlive("worker")?{kind:"not-attachable",lifecycle}:lifecycle==="control-plane-ready"?{kind:"attachable",manifest}:BOUND_RUN_ATTACHABLE_PHASES.includes(lifecycle)&&manifest.epicRunId!==void 0&&manifest.laneScope!==void 0?{kind:"attachable",manifest}:{kind:"not-attachable",lifecycle}}async function runPlanePreflight(repoRoot,deps){let diagnostics=[],outcomes=[],add=diagnostic=>{diagnostic&&diagnostics.push(diagnostic)},record=report=>(add(report.diagnostic),outcomes.push(...report.outcomes),report);if(record(await checkRepositoryRoot(repoRoot,deps)).diagnostic){for(let[check,id,label]of ROOT_DEPENDENT_CHECKS)outcomes.push({check,id,label,status:"skip",detail:PLANE_ROOT_DEPENDENT_SKIP_DETAIL});return{ok:!1,diagnostics,outcomes}}record(await checkRepositoryWorktree(repoRoot,deps)),record(await checkClaudeLogin(deps));let credentials=await checkBridgeCredentials(repoRoot,deps);outcomes.push(...credentials.outcomes);for(let advisory of credentials.advisories)add(advisory);credentials.ok||add(credentials.diagnostic),record(await checkPlaneBuildFreshness(repoRoot,{fs:deps.fs}));let runtimeEntrypoint=deps.resolveRuntimeEntrypoint();record(checkPlaneRuntimeEntrypoint(runtimeEntrypoint));let observations={};if(deps.endpoint.ok){let port=await checkServerPort(deps,deps.endpoint.endpoint);record(port),observations.serverPort=port.probe}else record(planeCheckFinding({check:"server-port",severity:"blocking",message:deps.endpoint.message,remediation:PLANE_SERVER_ENDPOINT_REMEDIATION},"Local server port","the configured local server endpoint could not be resolved"));record(await checkAlembicHead(repoRoot,{execFile:deps.execFile,fileExists:filePath=>fileExists(filePath,deps.fs),platform:deps.platform}));let existing=await checkExistingPlane(repoRoot,deps);return record(existing),observations.existingPlane=existing.observation,diagnostics.filter(d=>d.severity==="blocking").length>0||!credentials.ok||!runtimeEntrypoint.ok||!deps.endpoint.ok?{ok:!1,diagnostics,outcomes,observations}:{ok:!0,diagnostics,outcomes,observations,context:{repoRoot,repoName:credentials.repoName,endpoint:deps.endpoint.endpoint,executorEntrypoint:path11.join(repoRoot,"mcp_server","build","index.js"),runtimeEntrypoint:runtimeEntrypoint.entrypoint,bridgeApiKey:credentials.apiKey,bridgeCredentialSource:credentials.source}}}async function checkRepositoryRoot(repoRoot,deps){let label="Repository root";if(!path11.isAbsolute(repoRoot))return planeCheckFinding({check:"repository-root",severity:"blocking",message:"the repository root could not be resolved to an absolute path",remediation:PLANE_REPOSITORY_ROOT_REMEDIATION},label,"the repository root could not be resolved to an absolute path");let missing=[];for(let file of REQUIRED_REPO_FILES)await fileExists(path11.join(repoRoot,file),deps.fs)||missing.push(file);return await fileExists(path11.join(repoRoot,"mcp_server"),deps.fs)||missing.push("mcp_server/"),missing.length===0?planeCheckPassed("repository-root",label,"all Bridge API root marker files are present"):planeCheckFinding({check:"repository-root",severity:"blocking",message:`this does not look like the Bridge API repository root \u2014 missing ${missing.join(", ")}. Run \`plane up\` from the repository root.`,remediation:PLANE_REPOSITORY_ROOT_REMEDIATION},label,`missing root marker(s): ${missing.join(", ")}`)}async function checkRepositoryWorktree(repoRoot,deps){let label="Git work tree",result=await deps.execFile("git",["rev-parse","--is-inside-work-tree"],{cwd:repoRoot});return!result.ok||result.stdout.trim()!=="true"?planeCheckFinding({check:"worktree-presence",severity:"blocking",message:`${repoRoot} is not inside a Git work tree (git rev-parse --is-inside-work-tree did not report 'true'). No worktree was created \u2014 ${PLANE_WORKTREE_REMEDIATION}`,remediation:PLANE_WORKTREE_REMEDIATION},label,"this directory is not inside a Git work tree"):planeCheckPassed("worktree-presence",label,"inside a Git work tree")}async function checkClaudeLogin(deps){let label="Claude login",result=await detectClaudeLogin({homedir:deps.homedir,readFile:deps.fs.readFile});return result.detected?planeCheckPassed("claude-login",label,"a local Claude login marker was detected"):planeCheckFinding({check:"claude-login",severity:"warning",message:formatClaudeLoginAdvisory(result),remediation:PLANE_CLAUDE_LOGIN_REMEDIATION},label,"no local Claude login marker was detected")}function credentialPermissionsOutcome(advisories){return advisories.length===0?{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.permissions,label:"Bridge credential file permissions",status:"pass",detail:"the credential resolver raised no permission advisory"}:{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.permissions,label:"Bridge credential file permissions",status:"warn",detail:`the credential resolver raised ${advisories.length} permission advisory line(s)`,remediation:PLANE_CREDENTIAL_PERMISSIONS_REMEDIATION}}async function checkBridgeCredentials(repoRoot,deps){let repo=await deps.resolveRepoName({env:deps.env,cwd:repoRoot,readFile:deps.fs.readFile});if(!repo.ok)return{ok:!1,advisories:[],diagnostic:{check:"bridge-credentials",severity:"blocking",message:"the Bridge repository identity could not be resolved \u2014 set BAPI_REPO_NAME or add a valid .bridge/config at the repository root.",remediation:PLANE_REPO_IDENTITY_REMEDIATION},outcomes:[{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.identity,label:"Bridge repository identity",status:"fail",detail:"the Bridge repository identity could not be resolved",remediation:PLANE_REPO_IDENTITY_REMEDIATION},{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.credential,label:"Bridge API credential",status:"skip",detail:"not resolved \u2014 there is no repository identity to resolve a credential for"},credentialPermissionsOutcome([])]};let warnings=createResolverWarningBuffer(),result;try{result=await deps.resolveCredentials(repo.repoName,{env:deps.env,homedir:deps.homedir,platform:deps.platform,readFile:deps.fs.readFile,stat:async filePath=>{let statResult=await deps.fs.stat(filePath);return{mode:statResult.mode!==void 0?statResult.mode:511}},stderr:warnings.write})}catch{let advisories2=warnings.drain();return{ok:!1,advisories:advisories2,diagnostic:{check:"bridge-credentials",severity:"blocking",message:`Bridge credentials for target bapi:${repo.repoName} could not be resolved (resolver unavailable).`,remediation:PLANE_CREDENTIAL_REMEDIATION},outcomes:[identityResolvedOutcome(),{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.credential,label:"Bridge API credential",status:"fail",detail:"the credential resolver was unavailable",remediation:PLANE_CREDENTIAL_REMEDIATION},credentialPermissionsOutcome(advisories2)]}}if(!result.ok){let advisories2=warnings.drain();return{ok:!1,advisories:advisories2,diagnostic:{check:"bridge-credentials",severity:"blocking",message:`Bridge credentials for target bapi:${repo.repoName} could not be resolved (${result.kind}). Set BAPI_API_KEY in this shell, or store it with \`mcp-server credentials\`. A spawned shell never sees .mcp.json env.`,remediation:PLANE_CREDENTIAL_REMEDIATION},outcomes:[identityResolvedOutcome(),{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.credential,label:"Bridge API credential",status:"fail",detail:`no Bridge API credential resolved (${result.kind})`,remediation:PLANE_CREDENTIAL_REMEDIATION},credentialPermissionsOutcome(advisories2)]}}let advisories=warnings.drain();return{ok:!0,repoName:repo.repoName,apiKey:result.credentials.apiKey,source:result.credentials.source,advisories,outcomes:[identityResolvedOutcome(),{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.credential,label:"Bridge API credential",status:"pass",detail:`resolved from ${result.credentials.source} (the value is never read into a report)`},credentialPermissionsOutcome(advisories)]}}function identityResolvedOutcome(){return{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.identity,label:"Bridge repository identity",status:"pass",detail:"the Bridge repository identity resolved"}}function createResolverWarningBuffer(){let lines=[],pending="",push=line=>{let trimmed=line.replace(/\r$/,"");trimmed.length!==0&&lines.push(trimmed)};return{write:message=>{pending+=message;let segments=pending.split(`
121
+ `)),waitForEvent=deps.waitForEvent??waitForConductorEvent,getSnapshot=deps.getSnapshot??getSupervisorSnapshot,upsertProjection=deps.upsertProjection??upsertSupervisorProjection,emitAssessment=deps.emitAssessment??emitSupervisorAssessmentIfNew,sendMessage=deps.sendWorkerMessage??sendWorkerMessage,resolveBridgeAccess=deps.resolveBridgeAccess??(()=>resolveConductorBridgeApiAccess()),processMerge=deps.processMerge??processGateMetMerge,dispatchNotification=deps.dispatchNotification??dispatchSupervisorNotification,bridgeAccess=null,bridgeAccessResolved=!1,processGateMetMerges=async events=>{let eligible=events.filter(e=>extractMergeActionIdentityFromGateEvent(e)!==null);if(eligible.length!==0){if(!bridgeAccessResolved){bridgeAccessResolved=!0;try{let result=await resolveBridgeAccess();bridgeAccess=result.ok?result.access:null,result.ok||errorLog(`[supervisor] run=${runId} auto-merge disabled: ${result.kind}`)}catch{bridgeAccess=null}}if(bridgeAccess)for(let event of eligible)try{await processMerge(bridgeAccess,event)}catch{}}},persist=async state2=>{try{await upsertProjection(toSupervisorProjectionInput(state2))}catch{}},state;try{let snapshot=await getSnapshot(runId);state=hydrateSupervisorRunStateFromSnapshot(snapshot,runId,config,now())}catch{return{run_id:runId,status:"failed",exit_code:2,reason:"supervisor failed to load initial snapshot",last_seq:0,worker_count:0}}let sinceSeq=state.last_seq>0?state.last_seq+1:1,iterationCap=Math.max(1e3,Math.ceil(config.global_timeout_ms/Math.max(1,config.wake_interval_ms))+16);try{applySupervisorHousekeeping(state,config,now());for(let iteration=0;iteration<iterationCap;iteration+=1){if(isSupervisorRunTerminal(state))return state.status=terminalStatus(state),await persist(state),log(`[supervisor] run=${runId} complete status=${state.status} workers=${Object.keys(state.workers).length}`),{run_id:runId,status:state.status,exit_code:0,reason:"all workers terminal",last_seq:state.last_seq,worker_count:Object.keys(state.workers).length};if(hasSupervisorGlobalTimeoutElapsed(state,now()))return state.status="timed_out",await persist(state),errorLog(`[supervisor] run=${runId} global timeout elapsed`),{run_id:runId,status:"timed_out",exit_code:2,reason:"global timeout elapsed",last_seq:state.last_seq,worker_count:Object.keys(state.workers).length};let waitResult=await waitForEvent({since_seq:sinceSeq,filter:{run_id:runId},data_mode:"full",timeout_ms:config.wake_interval_ms,limit:config.poll_limit});if(waitResult.events.length>0){let sorted=[...waitResult.events].sort((a,b)=>a.seq-b.seq);for(let event of sorted)applyConductorEventToSupervisorState(state,event,now());sinceSeq=sorted[sorted.length-1].seq+1,await processGateMetMerges(sorted)}applySupervisorHousekeeping(state,config,now()),await processEscalations(state,config,{emitAssessment,sendWorkerMessage:sendMessage,log,now,dispatchNotification}),await persist(state)}return state.status="timed_out",await persist(state),{run_id:runId,status:"timed_out",exit_code:2,reason:"supervisor iteration cap reached",last_seq:state.last_seq,worker_count:Object.keys(state.workers).length}}catch{state.status="failed";try{await upsertProjection(toSupervisorProjectionInput(state))}catch{}return errorLog(`[supervisor] run=${runId} failed unexpectedly`),{run_id:runId,status:"failed",exit_code:2,reason:"supervisor failed unexpectedly",last_seq:state.last_seq,worker_count:Object.keys(state.workers).length}}}var init_supervisor_runtime=__esm({"src/conductor/supervisor-runtime.ts"(){"use strict";init_store();init_supervisor_ledger();init_supervisor_message_relay();init_supervisor_config();init_supervisor_state();init_supervisor_escalation();init_supervisor_ledger();init_bridge_api_client();init_merge_ledger();init_supervisor_merge();init_supervisor_notification();init_errors()}});import path7 from"path";function buildSetupUrl(baseUrl){return`${baseUrl.replace(/\/+$/,"")}/setup`}async function resolveInstallDoctorTarget(deps){let envRepo=deps.env.BAPI_REPO_NAME?.trim(),envBase=deps.env.BAPI_BASE_URL?.trim(),repoName=envRepo&&envRepo.length>0?envRepo:null,repoSource=repoName?"env":null,baseUrl=envBase&&envBase.length>0?envBase:null;if(!repoName||!baseUrl)for(let{relPath,topLevelKey}of MCP_CONFIG_ENV_TARGETS){let raw;try{raw=await deps.readFile(path7.join(deps.cwd,relPath))}catch{continue}let parsed;try{parsed=JSON.parse(raw)}catch{continue}let servers=parsed&&typeof parsed=="object"?parsed[topLevelKey]:void 0,registrationKey=existingRegistrationKey(servers),envBlock=registrationKey!==null?servers[registrationKey]?.env:void 0;if(envBlock&&(!repoName&&typeof envBlock.BAPI_REPO_NAME=="string"&&envBlock.BAPI_REPO_NAME.trim()&&(repoName=envBlock.BAPI_REPO_NAME.trim(),repoSource="config"),!baseUrl&&typeof envBlock.BAPI_BASE_URL=="string"&&envBlock.BAPI_BASE_URL.trim()&&(baseUrl=envBlock.BAPI_BASE_URL.trim()),repoName&&baseUrl))break}return{repoName,repoSource,baseUrl:(baseUrl??DEFAULT_BASE_URL).replace(/\/+$/,"")}}function classifyProbeFailure(error){let name=error?.name;return name==="TimeoutError"||name==="AbortError"?"request timed out":"request unavailable"}async function probeGet(deps,url,apiKey){try{let resp=await deps.fetch(url,{headers:{"X-API-Key":apiKey},signal:AbortSignal.timeout(PROBE_TIMEOUT_MS)}),body=null;try{body=await resp.json()}catch{}return{ok:!0,status:resp.status,body}}catch(e){return{ok:!1,error:classifyProbeFailure(e)}}}function summarizeManifestGroups(body){if(!body||typeof body!="object")return null;let groups=body.groups;if(!Array.isArray(groups))return null;let total=0,unset=[];for(let group of groups){let fields=group?.fields;if(Array.isArray(fields))for(let field of fields){let name=field?.field_name;typeof name=="string"&&(total+=1,field.is_set||unset.push(name))}}return{total,unset}}function summarizeIntegrations(body){if(!body||typeof body!="object")return null;let integrations=body.integrations;if(!Array.isArray(integrations))return null;let total=0,unconfigured=[];for(let item of integrations){let label=item?.label;typeof label=="string"&&(total+=1,item.is_configured||unconfigured.push(label))}return{total,unconfigured}}function readGithubConfiguredFlag(body){if(!body||typeof body!="object")return null;let integrations=body.integrations;if(!Array.isArray(integrations))return null;for(let item of integrations){if(item?.id!=="github_app")continue;let configured=item.is_configured;return typeof configured=="boolean"?configured:null}return null}async function collectInstallStatusChecks(deps){let checks=[],loginResult=await detectClaudeLogin({homedir:deps.homedir,readFile:deps.readFile});checks.push({id:"claude-login",label:"Claude login",status:loginResult.detected?"PASS":"INFO",detail:formatClaudeLoginAdvisory(loginResult)});let target=await resolveInstallDoctorTarget(deps);if(!target.repoName)return checks.push({id:"identity",label:"Repository identity",status:"SKIP",detail:"no BAPI_REPO_NAME in the environment or project-local MCP configs",remediation:"run install-bridge (or set BAPI_REPO_NAME) to configure this project."}),checks;checks.push({id:"identity",label:"Repository identity",status:"PASS",detail:`${target.repoName} (from ${target.repoSource}), base URL ${target.baseUrl}`});let setupUrl=buildSetupUrl(target.baseUrl),credDeps={env:deps.env,homedir:deps.homedir,platform:deps.platform,readFile:deps.readFile,stat:deps.stat,stderr:()=>{}},cred=await resolveBapiCredentials(target.repoName,credDeps);if(!cred.ok){checks.push({id:"credential",label:"Bridge API credential",status:"WARN",detail:`not resolved (${cred.kind})`,remediation:"set BAPI_API_KEY or persist it via /install-bridge / the credentials subcommand; until then the remaining install checks are skipped."});for(let[id,label]of[["connectivity","Server connectivity"],["bootstrap","Bootstrap config fields"],["indexing","Repository indexing"]])checks.push({id,label,status:"SKIP",detail:"no credential resolved"});return checks}checks.push({id:"credential",label:"Bridge API credential",status:"PASS",detail:`resolved from ${cred.credentials.source} (value never read into the report)`});let apiKey=cred.credentials.apiKey,repoQuery=`repo_name=${encodeURIComponent(target.repoName)}`,ping=await probeGet(deps,`${target.baseUrl}/jira/ping?${repoQuery}`,apiKey);ping.ok?ping.status===200?checks.push({id:"connectivity",label:"Server connectivity",status:"PASS",detail:"ping OK"}):ping.status===401||ping.status===403?checks.push({id:"connectivity",label:"Server connectivity",status:"WARN",detail:`the server rejected the resolved key (HTTP ${ping.status})`,remediation:"the key may have been rotated \u2014 re-run install-bridge with a current key."}):ping.status===404?checks.push({id:"connectivity",label:"Server connectivity",status:"WARN",detail:`the server does not know repo '${target.repoName}' (HTTP 404)`,remediation:`create the project at ${setupUrl} (setup UI), or check BAPI_REPO_NAME spelling.`}):checks.push({id:"connectivity",label:"Server connectivity",status:"WARN",detail:`unexpected HTTP ${ping.status} from /jira/ping`,remediation:"the server answered but not with a status this check understands \u2014 re-run doctor; if it persists the Bridge API is unhealthy and no install fact below can be trusted."}):checks.push({id:"connectivity",label:"Server connectivity",status:"WARN",detail:`unreachable (${ping.error})`,remediation:`check ${target.baseUrl} and your network, then re-run doctor.`});let manifest=await probeGet(deps,`${target.baseUrl}/jira/config/install-manifest?${repoQuery}`,apiKey);if(!manifest.ok)checks.push({id:"bootstrap",label:"Bootstrap config fields",status:"WARN",detail:`manifest unreachable (${manifest.error})`,remediation:`check ${target.baseUrl} and your network, then re-run doctor.`});else if(manifest.status===404)checks.push({id:"bootstrap",label:"Bootstrap config fields",status:"WARN",detail:"no configuration row found for this repository",remediation:`create the project at ${setupUrl} (setup UI), then run /install-bridge.`});else if(manifest.status===200){let summary=summarizeManifestGroups(manifest.body);summary?summary.unset.length===0?checks.push({id:"bootstrap",label:"Bootstrap config fields",status:"PASS",detail:`${summary.total}/${summary.total} bootstrap fields set`}):checks.push({id:"bootstrap",label:"Bootstrap config fields",status:"WARN",detail:`${summary.total-summary.unset.length}/${summary.total} set; unset: ${summary.unset.join(", ")}`,remediation:"run /install-bridge to derive the unset fields (intentionally-unset fields are fine to leave)."}):checks.push({id:"bootstrap",label:"Bootstrap config fields",status:"WARN",detail:"manifest response had an unexpected shape",remediation:"the manifest could not be read, so no bootstrap field state is known \u2014 re-run doctor, then run /install-bridge to re-derive the project configuration."})}else checks.push({id:"bootstrap",label:"Bootstrap config fields",status:"WARN",detail:`unexpected HTTP ${manifest.status} from the install manifest`,remediation:"the manifest endpoint answered with an unrecognized status \u2014 re-run doctor; if it persists, re-run /install-bridge for this repository."});if(manifest.ok&&manifest.status===200){let integrations=summarizeIntegrations(manifest.body);integrations===null?checks.push({id:"integrations",label:"Integration credentials",status:"SKIP",detail:"the manifest response carried no integrations checklist"}):integrations.unconfigured.length===0?checks.push({id:"integrations",label:"Integration credentials",status:"PASS",detail:`${integrations.total}/${integrations.total} configured`}):checks.push({id:"integrations",label:"Integration credentials",status:"WARN",detail:`not configured: ${integrations.unconfigured.join(", ")}`,remediation:`a human configures these at ${setupUrl} (setup UI \u2192 project settings) \u2014 Bridge API never accepts integration secrets through an agent or MCP tool.`})}else checks.push({id:"integrations",label:"Integration credentials",status:"SKIP",detail:"manifest unavailable"});if(manifest.ok&&manifest.status===200){let github=readGithubConfiguredFlag(manifest.body);github===null?checks.push({id:"github",label:"GitHub connection",status:"SKIP",detail:"the manifest response carried no GitHub integration entry"}):github?checks.push({id:"github",label:"GitHub connection",status:"PASS",detail:"a GitHub repository is connected to this project"}):checks.push({id:"github",label:"GitHub connection",status:"WARN",detail:"no GitHub repository is connected to this project",remediation:`run 'npx -y ${MCP_PACKAGE_NAME}@latest connect-github --repo ${target.repoName}'.`})}else checks.push({id:"github",label:"GitHub connection",status:"SKIP",detail:"manifest unavailable"});let parse=await probeGet(deps,`${target.baseUrl}/jira/parse-status?${repoQuery}`,apiKey);if(!parse.ok||parse.status!==200)checks.push({id:"indexing",label:"Repository indexing",status:"SKIP",detail:parse.ok?`HTTP ${parse.status} from /jira/parse-status`:`unreachable (${parse.error})`});else if(parse.body?.status==="in_progress"){let startedAt=parse.body.started_at;checks.push({id:"indexing",label:"Repository indexing",status:"INFO",detail:`parse job in progress${typeof startedAt=="string"?` (started ${startedAt})`:""}`})}else checks.push({id:"indexing",label:"Repository indexing",status:"INFO",detail:'no parse job currently running \u2014 if this repository has never been indexed, queue one with /parse-repository (monitor with parse_repository action "status").'});return checks}function projectInstallStatus(check){return check.status==="PASS"?{status:"pass"}:check.status==="WARN"?{status:"warn",...check.remediation?{remediation:check.remediation}:{}}:check.status==="INFO"?check.id==="claude-login"?{status:"warn",remediation:INSTALL_CLAUDE_LOGIN_REMEDIATION}:{status:"pass"}:check.id==="identity"?{status:"fail",remediation:check.remediation??INSTALL_IDENTITY_REMEDIATION}:{status:"skip",...check.remediation?{remediation:check.remediation}:{}}}function mapInstallStatusChecksToReadinessChecks(checks,collectorUnavailable=!1){let byId=new Map;for(let check of checks??[])byId.has(check.id)||byId.set(check.id,check);return INSTALL_READINESS_DESCRIPTORS.map(({id,label})=>{let source=byId.get(id);if(!source)return collectorUnavailable?createReadinessCheck({id:`install.${id}`,source:"install",label,status:"fail",detail:INSTALL_UNAVAILABLE_DETAIL,remediation:INSTALL_UNAVAILABLE_REMEDIATION}):createReadinessCheck({id:`install.${id}`,source:"install",label,status:"skip",detail:INSTALL_NOT_COLLECTED_DETAIL});let projected=projectInstallStatus(source);return createReadinessCheckSafely({id:`install.${id}`,source:"install",label:source.label||label,status:projected.status,...source.detail?{detail:source.detail}:{},...projected.status==="pass"?{}:projected.remediation?{remediation:projected.remediation}:projected.status==="fail"?{remediation:INSTALL_IDENTITY_REMEDIATION}:{}})})}var DEFAULT_BASE_URL,MCP_CONFIG_ENV_TARGETS,PROBE_TIMEOUT_MS,INSTALL_READINESS_DESCRIPTORS,INSTALL_IDENTITY_REMEDIATION,INSTALL_CLAUDE_LOGIN_REMEDIATION,INSTALL_NOT_COLLECTED_DETAIL,INSTALL_UNAVAILABLE_DETAIL,INSTALL_UNAVAILABLE_REMEDIATION,init_install_doctor=__esm({"src/install-doctor.ts"(){"use strict";init_readiness_check();init_credential_store();init_claude_login();init_mcp_host_targets();init_mcp_identity();DEFAULT_BASE_URL="https://bridgegpt-api.com";MCP_CONFIG_ENV_TARGETS=getProjectJsonTargets().map(target=>({relPath:target.relPath,topLevelKey:hostAdapterForTarget(target).topLevelKey})),PROBE_TIMEOUT_MS=5e3;INSTALL_READINESS_DESCRIPTORS=[{id:"claude-login",label:"Claude login"},{id:"identity",label:"Repository identity"},{id:"credential",label:"Bridge API credential"},{id:"connectivity",label:"Server connectivity"},{id:"bootstrap",label:"Bootstrap config fields"},{id:"integrations",label:"Integration credentials"},{id:"github",label:"GitHub connection"},{id:"indexing",label:"Repository indexing"}],INSTALL_IDENTITY_REMEDIATION="run /install-bridge (or set BAPI_REPO_NAME) to configure this project; without a repository identity no server-side conductor fact can be resolved.",INSTALL_CLAUDE_LOGIN_REMEDIATION="run `claude login` on the host that will run conductor workers; Bridge stores no Anthropic credential and cannot confirm this for you.",INSTALL_NOT_COLLECTED_DETAIL="not collected \u2014 an earlier install prerequisite stopped the checklist",INSTALL_UNAVAILABLE_DETAIL="unknown \u2014 the install-status checklist could not be collected at all",INSTALL_UNAVAILABLE_REMEDIATION="run `doctor` to collect the advisory install-status checklist directly; this prerequisite's state is unknown, not healthy."}});function planeCheckPassed(check,label,detail){return{diagnostic:null,outcomes:[{check,id:check,label,status:"pass",...detail?{detail}:{}}]}}function planeCheckFinding(diagnostic,label,detail){return{diagnostic,outcomes:[{check:diagnostic.check,id:diagnostic.check,label,status:diagnostic.severity==="blocking"?"fail":"warn",detail,...diagnostic.remediation?{remediation:diagnostic.remediation}:{}}]}}var PLANE_MANIFEST_SUPPORTED_SCHEMA_VERSIONS,PLANE_RUNTIME_DIR,PLANE_MANIFEST_FILENAME,PLANE_RUNTIME_LOG_FILENAME,PLANE_RUNTIME_LOG_PATH,PLANE_SERVER_HOST,PLANE_SERVER_PORT,PLANE_SERVER_BASE_URL,PLANE_SERVER_PORT_ENV_VAR,PLANE_LIFECYCLE_PHASES,init_types2=__esm({"src/plane/types.ts"(){"use strict";PLANE_MANIFEST_SUPPORTED_SCHEMA_VERSIONS=[1,2,3],PLANE_RUNTIME_DIR=".bridge/plane",PLANE_MANIFEST_FILENAME="plane.json",PLANE_RUNTIME_LOG_FILENAME="runtime.log",PLANE_RUNTIME_LOG_PATH=`${PLANE_RUNTIME_DIR}/${PLANE_RUNTIME_LOG_FILENAME}`,PLANE_SERVER_HOST="127.0.0.1",PLANE_SERVER_PORT=8e3,PLANE_SERVER_BASE_URL=`http://${PLANE_SERVER_HOST}:${PLANE_SERVER_PORT}`,PLANE_SERVER_PORT_ENV_VAR="BAPI_PLANE_PORT";PLANE_LIFECYCLE_PHASES=["control-plane-starting","control-plane-ready","lanes-starting","lanes-ready","ready","lanes-failed"]}});import path8 from"path";function isRelevantSourceFile(name){return!(!name.endsWith(".ts")||name.endsWith(".generated.ts"))}async function findNewestSourceMtime(srcDir,deps){let newest=null,walk=async dir=>{let entries;try{entries=await deps.fs.readdir(dir)}catch(err){return sanitize(err)}for(let entry of entries){if(entry.isDirectory()){if(EXCLUDED_DIR_NAMES.has(entry.name))continue;let error2=await walk(path8.join(dir,entry.name));if(error2)return error2;continue}if(!(!entry.isFile()||!isRelevantSourceFile(entry.name)))try{let stat3=await deps.fs.stat(path8.join(dir,entry.name));(newest===null||stat3.mtimeMs>newest)&&(newest=stat3.mtimeMs)}catch(err){return sanitize(err)}}return null},error=await walk(srcDir);return error?{ok:!1,error}:{ok:!0,mtimeMs:newest}}async function findBuildMtime(executorEntrypoint,deps){try{return{ok:!0,mtimeMs:(await deps.fs.stat(executorEntrypoint)).mtimeMs}}catch(err){return{ok:!1,error:sanitize(err)}}}async function checkPlaneBuildFreshness(repoRoot,deps){let label="Executor build freshness",packageRoot=path8.join(repoRoot,"mcp_server"),buildDir=path8.join(packageRoot,"build"),executorEntrypoint=path8.join(buildDir,"index.js"),srcDir=path8.join(packageRoot,"src"),buildMtime=await findBuildMtime(executorEntrypoint,deps);if(!buildMtime.ok)return planeCheckFinding({check:"executor-build",severity:"blocking",message:`the executor build entrypoint is missing or unreadable at mcp_server/build/index.js \u2014 run \`${PLANE_BUILD_REMEDIATION}\``,remediation:PLANE_BUILD_FIX_REMEDIATION},label,"the executor build entrypoint is missing or unreadable");let sourceMtime=await findNewestSourceMtime(srcDir,deps);return sourceMtime.ok?sourceMtime.mtimeMs!==null&&sourceMtime.mtimeMs>buildMtime.mtimeMs?planeCheckFinding({check:"executor-build",severity:"blocking",message:`mcp_server/build/ is STALE \u2014 a source file under mcp_server/src is newer than mcp_server/build/index.js, so executors would run old code. Run \`${PLANE_BUILD_REMEDIATION}\``,remediation:PLANE_BUILD_FIX_REMEDIATION},label,"mcp_server/build/ is stale \u2014 a source file is newer than the build entrypoint"):planeCheckPassed("executor-build",label,"the executor build is present and current"):planeCheckFinding({check:"executor-build",severity:"blocking",message:`could not read mcp_server/src to compare against the build (${sourceMtime.error}) \u2014 run \`${PLANE_BUILD_REMEDIATION}\``,remediation:PLANE_BUILD_FIX_REMEDIATION},label,`the executor sources could not be read for comparison (${sourceMtime.error})`)}function checkPlaneRuntimeEntrypoint(resolution){let label="Runtime re-exec entrypoint";return resolution.ok?planeCheckPassed("runtime-entrypoint",label,"the executing build can re-enter itself"):planeCheckFinding({check:"runtime-entrypoint",severity:"blocking",message:PLANE_RUNTIME_ENTRYPOINT_REFUSAL,remediation:PLANE_BUILD_FIX_REMEDIATION},label,"the currently executing MCP build could not be re-entered")}function sanitize(err){let code=err?.code;return typeof code=="string"?code:"unreadable"}var PLANE_BUILD_REMEDIATION,EXCLUDED_DIR_NAMES,PLANE_BUILD_FIX_REMEDIATION,PLANE_RUNTIME_ENTRYPOINT_REFUSAL,init_build_freshness=__esm({"src/plane/build-freshness.ts"(){"use strict";init_types2();PLANE_BUILD_REMEDIATION="cd mcp_server && npm run build",EXCLUDED_DIR_NAMES=new Set(["node_modules","build"]);PLANE_BUILD_FIX_REMEDIATION="run `cd mcp_server && npm run build` to rebuild the executor entrypoint, then retry.";PLANE_RUNTIME_ENTRYPOINT_REFUSAL=`the currently executing MCP build could not be re-entered \u2014 \`plane up\` re-execs this package's own compiled entrypoint to create the detached runtime, and no existing entrypoint belonging to it could be found. Run \`${PLANE_BUILD_REMEDIATION}\` and retry from the rebuilt CLI.`}});import path9 from"path";function resolveRepositoryAlembicCommand(repoRoot,platform){return platform==="win32"?path9.join(repoRoot,".venv","Scripts","alembic.exe"):path9.join(repoRoot,".venv","bin","alembic")}function parseAlembicRevisions(output){let revisions=new Set;for(let rawLine of output.split(/\r?\n/)){let line=rawLine.trim();if(line.length===0||LOG_LINE_PATTERN.test(line))continue;let token=line.split(/\s+/)[0];!token||NON_REVISION_TOKENS.has(token.toLowerCase())||REVISION_PATTERN.test(token)&&revisions.add(token)}return revisions.size===0?null:[...revisions].sort()}async function checkAlembicHead(repoRoot,deps){let alembic=resolveRepositoryAlembicCommand(repoRoot,deps.platform);if(!await deps.fileExists(alembic))return unverified("the repository virtualenv Alembic executable was not found","the repository virtualenv Alembic executable was not found");let heads=await deps.execFile(alembic,["-c","alembic.ini","heads"],{cwd:repoRoot});if(!heads.ok)return unverified(`\`alembic heads\` did not complete (${heads.error})`,"`alembic heads` did not complete");let current=await deps.execFile(alembic,["-c","alembic.ini","current"],{cwd:repoRoot});if(!current.ok)return unverified(`\`alembic current\` did not complete (${current.error})`,"`alembic current` did not complete");let headRevisions=parseAlembicRevisions(heads.stdout),currentRevisions=parseAlembicRevisions(current.stdout);return headRevisions===null||currentRevisions===null?unverified("Alembic output did not contain a readable revision","Alembic output did not contain a readable revision"):headRevisions.length===currentRevisions.length&&headRevisions.every((rev,i)=>rev===currentRevisions[i])?planeCheckPassed("alembic-head",ALEMBIC_CHECK_LABEL,"the database is at the repository migration head"):planeCheckFinding({check:"alembic-head",severity:"blocking",message:`the database is not at the migration head \u2014 heads [${headRevisions.join(", ")}], current [${currentRevisions.join(", ")}]. A database behind the head blocks conductor dispatch. Run \`${PLANE_ALEMBIC_REMEDIATION}\``,remediation:PLANE_ALEMBIC_MISMATCH_REMEDIATION},ALEMBIC_CHECK_LABEL,`database at [${currentRevisions.join(", ")}], repository head [${headRevisions.join(", ")}]`)}function unverified(messageDetail,outcomeDetail){let diagnostic={check:"alembic-head",severity:"warning",message:`${PLANE_ALEMBIC_UNVERIFIED_PREFIX}: ${messageDetail}. Startup continues \u2014 verify with \`alembic -c alembic.ini heads\` and \`alembic -c alembic.ini current\` if a run later reports CONTRACT_MIGRATION_BEHIND.`,remediation:PLANE_ALEMBIC_UNVERIFIED_REMEDIATION};return planeCheckFinding(diagnostic,ALEMBIC_CHECK_LABEL,`${PLANE_ALEMBIC_UNVERIFIED_PREFIX}: ${outcomeDetail}`)}var PLANE_ALEMBIC_REMEDIATION,PLANE_ALEMBIC_UNVERIFIED_PREFIX,PLANE_ALEMBIC_MISMATCH_REMEDIATION,PLANE_ALEMBIC_UNVERIFIED_REMEDIATION,LOG_LINE_PATTERN,REVISION_PATTERN,NON_REVISION_TOKENS,ALEMBIC_CHECK_LABEL,init_alembic_head=__esm({"src/plane/alembic-head.ts"(){"use strict";init_types2();PLANE_ALEMBIC_REMEDIATION="alembic -c alembic.ini upgrade head",PLANE_ALEMBIC_UNVERIFIED_PREFIX="could not verify database migration head",PLANE_ALEMBIC_MISMATCH_REMEDIATION=`run \`${PLANE_ALEMBIC_REMEDIATION}\` to bring the database up to the migration head, then retry.`,PLANE_ALEMBIC_UNVERIFIED_REMEDIATION="verify by hand with `alembic -c alembic.ini heads` and `alembic -c alembic.ini current`; startup continues, and the server reports CONTRACT_MIGRATION_BEHIND at dispatch if the database is behind.";LOG_LINE_PATTERN=/^(INFO|WARNING|ERROR|DEBUG|CRITICAL)\b|\[alembic/i,REVISION_PATTERN=/^[0-9A-Za-z][0-9A-Za-z_.-]*$/,NON_REVISION_TOKENS=new Set(["head","heads","base","none","(head)"]);ALEMBIC_CHECK_LABEL="Database migration head"}});import path10 from"path";function getPlanePaths(repoRoot){let planeDir=path10.join(repoRoot,".bridge","plane");return{planeDir,manifestPath:path10.join(planeDir,PLANE_MANIFEST_FILENAME),logPathFor:member=>path10.join(planeDir,`${member}.log`)}}function relativeLogPathFor(member){return`${PLANE_RUNTIME_DIR}/${member}.log`}function isNonBlankTrimmedString(value){return typeof value=="string"&&value.trim().length>0&&value===value.trim()}function isPlaneMemberName(value){return typeof value!="string"?!1:value==="server"||value==="worker"||value==="observer"?!0:/^executor-[1-9][0-9]*$/.test(value)}function isPositiveInteger(value){return typeof value=="number"&&Number.isSafeInteger(value)&&value>0}function isIsoTimestamp(value){return typeof value=="string"&&value.length>0&&!Number.isNaN(Date.parse(value))}function parsePlaneManifest(value){if(typeof value!="object"||value===null||Array.isArray(value))return{ok:!1,error:"manifest is not an object"};let record=value;for(let key of Object.keys(record))if(!MANIFEST_KEYS.has(key))return{ok:!1,error:`manifest has an unsupported field '${key}'`};if(typeof record.schemaVersion!="number"||!PLANE_MANIFEST_SUPPORTED_SCHEMA_VERSIONS.includes(record.schemaVersion))return{ok:!1,error:`manifest schema version ${JSON.stringify(record.schemaVersion)} is not supported (this build reads ${PLANE_MANIFEST_SUPPORTED_SCHEMA_VERSIONS.join(", ")}). A manifest from a NEWER build must be wound down with that build's \`plane down\``};if(typeof record.planeId!="string"||!/^[0-9a-f-]{8,}$/i.test(record.planeId))return{ok:!1,error:"manifest plane identity is missing or malformed"};if(typeof record.repoRoot!="string"||record.repoRoot.length===0)return{ok:!1,error:"manifest repository root is missing"};if(!isPositiveInteger(record.supervisorPid))return{ok:!1,error:"manifest supervisor pid is not a positive integer"};if(!isPositiveInteger(record.supervisorPgid))return{ok:!1,error:"manifest supervisor process-group id is not a positive integer"};if(!isIsoTimestamp(record.createdAt)||!isIsoTimestamp(record.updatedAt))return{ok:!1,error:"manifest timestamps are missing or malformed"};if(!Array.isArray(record.members)||record.members.length===0)return{ok:!1,error:"manifest members are missing"};if(record.epicRunId!==void 0&&!isNonBlankTrimmedString(record.epicRunId))return{ok:!1,error:"manifest epic run id is malformed"};if(record.lifecycle!==void 0&&!LIFECYCLE_PHASES.has(record.lifecycle))return{ok:!1,error:"manifest lifecycle phase is malformed"};let laneScope=parseManifestLaneScope(record.laneScope);if(!laneScope.ok)return{ok:!1,error:laneScope.error};let members=[],unrecognizedMemberNames=[],seen=new Set;for(let raw of record.members){if(typeof raw!="object"||raw===null||Array.isArray(raw))return{ok:!1,error:"manifest member is not an object"};let member=raw;for(let key of Object.keys(member))if(!MEMBER_KEYS.has(key))return{ok:!1,error:`manifest member has an unsupported field '${key}'`};if(typeof member.name!="string"||member.name.length===0)return{ok:!1,error:"manifest member name is missing or not a string"};if(!isPlaneMemberName(member.name)){unrecognizedMemberNames.includes(member.name)||unrecognizedMemberNames.push(member.name);continue}if(seen.has(member.name))return{ok:!1,error:`manifest lists member '${member.name}' more than once`};if(seen.add(member.name),member.pid!==null&&!isPositiveInteger(member.pid))return{ok:!1,error:`manifest member '${member.name}' has an invalid pid`};if(typeof member.state!="string"||!VALID_STATES.has(member.state))return{ok:!1,error:`manifest member '${member.name}' has an invalid state`};if(member.exitCode!==null&&!Number.isSafeInteger(member.exitCode))return{ok:!1,error:`manifest member '${member.name}' has an invalid exit code`};if(member.exitSignal!==null&&typeof member.exitSignal!="string")return{ok:!1,error:`manifest member '${member.name}' has an invalid exit signal`};if(member.logPath!==relativeLogPathFor(member.name))return{ok:!1,error:`manifest member '${member.name}' has an unexpected log path`};members.push({name:member.name,pid:member.pid,state:member.state,exitCode:member.exitCode,exitSignal:member.exitSignal,logPath:member.logPath})}return members.length===0?{ok:!1,error:`manifest lists no member this build recognizes (unrecognized: ${unrecognizedMemberNames.join(", ")}). It was written by a newer build; wind the plane down with that build's \`plane down\``}:{ok:!0,unrecognizedMemberNames,manifest:{schemaVersion:record.schemaVersion,planeId:record.planeId,repoRoot:record.repoRoot,supervisorPid:record.supervisorPid,supervisorPgid:record.supervisorPgid,createdAt:record.createdAt,updatedAt:record.updatedAt,members,...record.epicRunId!==void 0?{epicRunId:record.epicRunId}:{},...record.lifecycle!==void 0?{lifecycle:record.lifecycle}:{},...laneScope.scope!==void 0?{laneScope:laneScope.scope}:{}}}}function parseManifestLaneScope(value){if(value===void 0)return{ok:!0};if(typeof value!="object"||value===null||Array.isArray(value))return{ok:!1,error:"manifest lane scope is not an object"};let record=value;if(record.kind==="repo-wide")return Object.keys(record).length!==1?{ok:!1,error:"manifest lane scope has unsupported fields"}:{ok:!0,scope:{kind:"repo-wide"}};if(record.kind!=="epic-runs")return{ok:!1,error:"manifest lane scope kind is malformed"};if(Object.keys(record).length!==2||!Array.isArray(record.epicRunIds))return{ok:!1,error:"manifest lane scope epic run ids are malformed"};let ids=record.epicRunIds;return ids.length===0||!ids.every(id=>isNonBlankTrimmedString(id))?{ok:!1,error:"manifest lane scope epic run ids are malformed"}:{ok:!0,scope:{kind:"epic-runs",epicRunIds:ids}}}function planeManifestLifecycle(manifest){return manifest.lifecycle??"ready"}async function readPlaneManifest(repoRoot,fs2){let{manifestPath}=getPlanePaths(repoRoot),raw;try{raw=await fs2.readFile(manifestPath)}catch(err){let code=err?.code;return code==="ENOENT"?{kind:"missing"}:{kind:"unreadable",error:typeof code=="string"?code:"read failed"}}let parsed;try{parsed=JSON.parse(raw)}catch{return{kind:"malformed",error:"manifest is not valid JSON"}}let result=parsePlaneManifest(parsed);return result.ok?{kind:"valid",manifest:result.manifest,unrecognizedMemberNames:result.unrecognizedMemberNames}:{kind:"malformed",error:result.error}}function isProcessAlive(pid,kill){if(!isPositiveInteger(pid))return"unknown";try{return kill(pid,0),"alive"}catch(err){let code=err?.code;return code==="ESRCH"?"dead":code==="EPERM"?"alive":"unknown"}}function probeManifestMembers(manifest,proc){return manifest.members.map(member=>member.state==="exited"||member.pid===null?{member,liveness:"dead"}:{member,liveness:proc.isAlive(member.pid)})}function manifestHasLiveProcess(manifest,proc){return proc.isAlive(manifest.supervisorPid)!=="dead"?!0:probeManifestMembers(manifest,proc).some(probe=>probe.liveness!=="dead")}var VALID_STATES,MANIFEST_KEYS,LIFECYCLE_PHASES,MEMBER_KEYS,init_manifest=__esm({"src/plane/manifest.ts"(){"use strict";init_types2();VALID_STATES=new Set(["spawning","running","ready","exited"]),MANIFEST_KEYS=new Set(["schemaVersion","planeId","repoRoot","supervisorPid","supervisorPgid","createdAt","updatedAt","members","epicRunId","lifecycle","laneScope"]),LIFECYCLE_PHASES=new Set(PLANE_LIFECYCLE_PHASES);MEMBER_KEYS=new Set(["name","pid","state","exitCode","exitSignal","logPath"])}});import path11 from"path";function classifyLivePlaneForAttach(repoRoot,manifest,proc){if(manifest.repoRoot!==repoRoot)return{kind:"foreign-root"};let lifecycle=planeManifestLifecycle(manifest),probes=probeManifestMembers(manifest,proc),memberAlive=name=>probes.some(probe=>probe.member.name===name&&probe.liveness==="alive");return!memberAlive("server")||!memberAlive("worker")?{kind:"not-attachable",lifecycle}:lifecycle==="control-plane-ready"?{kind:"attachable",manifest}:BOUND_RUN_ATTACHABLE_PHASES.includes(lifecycle)&&manifest.epicRunId!==void 0&&manifest.laneScope!==void 0?{kind:"attachable",manifest}:{kind:"not-attachable",lifecycle}}async function runPlanePreflight(repoRoot,deps){let diagnostics=[],outcomes=[],add=diagnostic=>{diagnostic&&diagnostics.push(diagnostic)},record=report=>(add(report.diagnostic),outcomes.push(...report.outcomes),report);if(record(await checkRepositoryRoot(repoRoot,deps)).diagnostic){for(let[check,id,label]of ROOT_DEPENDENT_CHECKS)outcomes.push({check,id,label,status:"skip",detail:PLANE_ROOT_DEPENDENT_SKIP_DETAIL});return{ok:!1,diagnostics,outcomes}}record(await checkRepositoryWorktree(repoRoot,deps)),record(await checkClaudeLogin(deps));let credentials=await checkBridgeCredentials(repoRoot,deps);outcomes.push(...credentials.outcomes);for(let advisory of credentials.advisories)add(advisory);credentials.ok||add(credentials.diagnostic),record(await checkPlaneBuildFreshness(repoRoot,{fs:deps.fs}));let runtimeEntrypoint=deps.resolveRuntimeEntrypoint();record(checkPlaneRuntimeEntrypoint(runtimeEntrypoint));let observations={};if(deps.endpoint.ok){let port=await checkServerPort(deps,deps.endpoint.endpoint);record(port),observations.serverPort=port.probe}else record(planeCheckFinding({check:"server-port",severity:"blocking",message:deps.endpoint.message,remediation:PLANE_SERVER_ENDPOINT_REMEDIATION},"Local server port","the configured local server endpoint could not be resolved"));record(await checkAlembicHead(repoRoot,{execFile:deps.execFile,fileExists:filePath=>fileExists(filePath,deps.fs),platform:deps.platform}));let existing=await checkExistingPlane(repoRoot,deps);return record(existing),observations.existingPlane=existing.observation,diagnostics.filter(d=>d.severity==="blocking").length>0||!credentials.ok||!runtimeEntrypoint.ok||!deps.endpoint.ok?{ok:!1,diagnostics,outcomes,observations}:{ok:!0,diagnostics,outcomes,observations,context:{repoRoot,repoName:credentials.repoName,endpoint:deps.endpoint.endpoint,executorEntrypoint:path11.join(repoRoot,"mcp_server","build","index.js"),runtimeEntrypoint:runtimeEntrypoint.entrypoint,bridgeApiKey:credentials.apiKey,bridgeCredentialSource:credentials.source}}}async function checkRepositoryRoot(repoRoot,deps){let label="Repository root";if(!path11.isAbsolute(repoRoot))return planeCheckFinding({check:"repository-root",severity:"blocking",message:"the repository root could not be resolved to an absolute path",remediation:PLANE_REPOSITORY_ROOT_REMEDIATION},label,"the repository root could not be resolved to an absolute path");let missing=[];for(let file of REQUIRED_REPO_FILES)await fileExists(path11.join(repoRoot,file),deps.fs)||missing.push(file);return await fileExists(path11.join(repoRoot,"mcp_server"),deps.fs)||missing.push("mcp_server/"),missing.length===0?planeCheckPassed("repository-root",label,"all Bridge API root marker files are present"):planeCheckFinding({check:"repository-root",severity:"blocking",message:`this does not look like the Bridge API repository root \u2014 missing ${missing.join(", ")}. Run \`plane up\` from the repository root.`,remediation:PLANE_REPOSITORY_ROOT_REMEDIATION},label,`missing root marker(s): ${missing.join(", ")}`)}async function checkRepositoryWorktree(repoRoot,deps){let label="Git work tree",result=await deps.execFile("git",["rev-parse","--is-inside-work-tree"],{cwd:repoRoot});return!result.ok||result.stdout.trim()!=="true"?planeCheckFinding({check:"worktree-presence",severity:"blocking",message:`${repoRoot} is not inside a Git work tree (git rev-parse --is-inside-work-tree did not report 'true'). No worktree was created \u2014 ${PLANE_WORKTREE_REMEDIATION}`,remediation:PLANE_WORKTREE_REMEDIATION},label,"this directory is not inside a Git work tree"):planeCheckPassed("worktree-presence",label,"inside a Git work tree")}async function checkClaudeLogin(deps){let label="Claude login",result=await detectClaudeLogin({homedir:deps.homedir,readFile:deps.fs.readFile});return result.detected?planeCheckPassed("claude-login",label,"a local Claude login marker was detected"):planeCheckFinding({check:"claude-login",severity:"warning",message:formatClaudeLoginAdvisory(result),remediation:PLANE_CLAUDE_LOGIN_REMEDIATION},label,"no local Claude login marker was detected")}function credentialPermissionsOutcome(advisories){return advisories.length===0?{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.permissions,label:"Bridge credential file permissions",status:"pass",detail:"the credential resolver raised no permission advisory"}:{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.permissions,label:"Bridge credential file permissions",status:"warn",detail:`the credential resolver raised ${advisories.length} permission advisory line(s)`,remediation:PLANE_CREDENTIAL_PERMISSIONS_REMEDIATION}}async function checkBridgeCredentials(repoRoot,deps){let repo=await deps.resolveRepoName({env:deps.env,cwd:repoRoot,readFile:deps.fs.readFile});if(!repo.ok)return{ok:!1,advisories:[],diagnostic:{check:"bridge-credentials",severity:"blocking",message:"the Bridge repository identity could not be resolved \u2014 set BAPI_REPO_NAME or add a valid .bridge/config at the repository root.",remediation:PLANE_REPO_IDENTITY_REMEDIATION},outcomes:[{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.identity,label:"Bridge repository identity",status:"fail",detail:"the Bridge repository identity could not be resolved",remediation:PLANE_REPO_IDENTITY_REMEDIATION},{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.credential,label:"Bridge API credential",status:"skip",detail:"not resolved \u2014 there is no repository identity to resolve a credential for"},credentialPermissionsOutcome([])]};let warnings=createResolverWarningBuffer(),result;try{result=await deps.resolveCredentials(repo.repoName,{env:deps.env,homedir:deps.homedir,platform:deps.platform,readFile:deps.fs.readFile,stat:async filePath=>{let statResult=await deps.fs.stat(filePath);return{mode:statResult.mode!==void 0?statResult.mode:511}},stderr:warnings.write})}catch{let advisories2=warnings.drain();return{ok:!1,advisories:advisories2,diagnostic:{check:"bridge-credentials",severity:"blocking",message:`Bridge credentials for target bapi:${repo.repoName} could not be resolved (resolver unavailable).`,remediation:PLANE_CREDENTIAL_REMEDIATION},outcomes:[identityResolvedOutcome(),{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.credential,label:"Bridge API credential",status:"fail",detail:"the credential resolver was unavailable",remediation:PLANE_CREDENTIAL_REMEDIATION},credentialPermissionsOutcome(advisories2)]}}if(!result.ok){let advisories2=warnings.drain();return{ok:!1,advisories:advisories2,diagnostic:{check:"bridge-credentials",severity:"blocking",message:`Bridge credentials for target bapi:${repo.repoName} could not be resolved (${result.kind}). Set BAPI_API_KEY in this shell, or store it with \`mcp-server credentials\`. A spawned shell never sees .mcp.json env.`,remediation:PLANE_CREDENTIAL_REMEDIATION},outcomes:[identityResolvedOutcome(),{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.credential,label:"Bridge API credential",status:"fail",detail:`no Bridge API credential resolved (${result.kind})`,remediation:PLANE_CREDENTIAL_REMEDIATION},credentialPermissionsOutcome(advisories2)]}}let advisories=warnings.drain();return{ok:!0,repoName:repo.repoName,apiKey:result.credentials.apiKey,source:result.credentials.source,advisories,outcomes:[identityResolvedOutcome(),{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.credential,label:"Bridge API credential",status:"pass",detail:`resolved from ${result.credentials.source} (the value is never read into a report)`},credentialPermissionsOutcome(advisories)]}}function identityResolvedOutcome(){return{check:"bridge-credentials",id:PLANE_CREDENTIAL_OUTCOME_IDS.identity,label:"Bridge repository identity",status:"pass",detail:"the Bridge repository identity resolved"}}function createResolverWarningBuffer(){let lines=[],pending="",push=line=>{let trimmed=line.replace(/\r$/,"");trimmed.length!==0&&lines.push(trimmed)};return{write:message=>{pending+=message;let segments=pending.split(`
122
122
  `);pending=segments.pop()??"";for(let segment of segments)push(segment)},drain:()=>(pending.length>0&&(push(pending),pending=""),lines.map(message=>({check:"bridge-credentials",severity:"warning",message})))}}async function checkServerPort(deps,endpoint){let report=await checkServerPortReport(deps,endpoint);return{...report.report,probe:report.probe}}async function checkServerPortReport(deps,endpoint){let label="Local server port",target=`${endpoint.host}:${endpoint.port}`,result=await deps.probePort(endpoint.host,endpoint.port,PLANE_PORT_PROBE_TIMEOUT_MS);return result.kind==="refused"?{report:planeCheckPassed("server-port",label,`${target} is free`),probe:"refused"}:result.kind==="connected"?{report:planeCheckFinding({check:"server-port",severity:"blocking",message:`${target} is already accepting connections. That port may belong to a SIBLING WORKTREE's server \u2014 check before you kill it. Stop the existing server (or wind down its plane) and retry, or set ${PLANE_SERVER_PORT_ENV_VAR} to a free port.`,remediation:PLANE_SERVER_PORT_OCCUPIED_REMEDIATION},label,`${target} is already accepting connections`),probe:"connected"}:{report:planeCheckFinding({check:"server-port",severity:"warning",message:`could not determine whether ${target} is free (${result.error}); startup continues and uvicorn will fail loudly if the port is taken.`,remediation:PLANE_SERVER_PORT_UNKNOWN_REMEDIATION},label,`could not determine whether ${target} is free`),probe:"error"}}async function checkExistingPlane(repoRoot,deps){let label="Existing plane",read=await readPlaneManifest(repoRoot,deps.fs);return read.kind==="missing"?{...planeCheckPassed("existing-plane",label,"no plane manifest is present"),observation:{kind:"none"}}:read.kind!=="valid"?{...planeCheckFinding({check:"existing-plane",severity:"blocking",message:`an existing .bridge/plane/plane.json could not be validated (${read.error}). No process was signalled and the file was left untouched \u2014 inspect it, then remove it by hand if no plane is running.`,remediation:PLANE_MANIFEST_UNREADABLE_REMEDIATION},label,"an existing plane manifest could not be validated"),observation:{kind:"unvalidated"}}:deps.ownPlaneId!==void 0&&read.manifest.planeId===deps.ownPlaneId?{...planeCheckPassed("existing-plane",label,"the existing manifest carries this launch's own plane id"),observation:{kind:"own-plane"}}:manifestHasLiveProcess(read.manifest,deps.proc)?{...planeCheckFinding({check:"existing-plane",severity:"blocking",message:`a plane is already running (supervisor pid ${read.manifest.supervisorPid}). Run \`plane status\` to inspect it, or \`plane down\` to wind it down first.`,remediation:PLANE_ALREADY_RUNNING_REMEDIATION},label,"a plane is already running for this repository"),observation:classifyLivePlaneForAttach(repoRoot,read.manifest,deps.proc)}:{observation:{kind:"stale"},diagnostic:{check:"existing-plane",severity:"warning",message:"a previous plane manifest is present but every recorded process is gone; it will be replaced after a final liveness re-check."},outcomes:[{check:"existing-plane",id:"existing-plane",label,status:"warn",detail:"a stale plane manifest is present and will be replaced after a liveness re-check"}]}}async function fileExists(filePath,fs2){try{return await fs2.stat(filePath),!0}catch{return!1}}function mapPlanePreflightToReadinessChecks(result){let byId=new Map;for(let outcome of result?.outcomes??[])byId.has(outcome.id)||byId.set(outcome.id,outcome);return PLANE_READINESS_DESCRIPTORS.map(({id,label})=>{let outcome=byId.get(id);return outcome?createReadinessCheckSafely({id:`plane.${id}`,source:"plane",label:outcome.label||label,status:outcome.status,...outcome.detail?{detail:outcome.detail}:{},...outcome.status==="fail"?{remediation:outcome.remediation??PLANE_UNREPORTED_REMEDIATION}:outcome.status!=="pass"&&outcome.remediation?{remediation:outcome.remediation}:{}}):createReadinessCheck({id:`plane.${id}`,source:"plane",label,status:"fail",detail:PLANE_UNREPORTED_DETAIL,remediation:PLANE_UNREPORTED_REMEDIATION})})}var REQUIRED_REPO_FILES,BOUND_RUN_ATTACHABLE_PHASES,PLANE_ATTACHABLE_BASE_URL_REMEDIATION,PLANE_REPOSITORY_ROOT_REMEDIATION,PLANE_REPO_IDENTITY_REMEDIATION,PLANE_CREDENTIAL_REMEDIATION,PLANE_CREDENTIAL_PERMISSIONS_REMEDIATION,PLANE_CLAUDE_LOGIN_REMEDIATION,PLANE_SERVER_PORT_OCCUPIED_REMEDIATION,PLANE_SERVER_PORT_UNKNOWN_REMEDIATION,PLANE_SERVER_ENDPOINT_REMEDIATION,PLANE_MANIFEST_UNREADABLE_REMEDIATION,PLANE_ALREADY_RUNNING_REMEDIATION,PLANE_CREDENTIAL_OUTCOME_IDS,PLANE_ROOT_DEPENDENT_SKIP_DETAIL,ROOT_DEPENDENT_CHECKS,PLANE_PORT_PROBE_TIMEOUT_MS,PLANE_WORKTREE_REMEDIATION,PLANE_READINESS_DESCRIPTORS,PLANE_UNREPORTED_DETAIL,PLANE_UNREPORTED_REMEDIATION,init_preflight=__esm({"src/plane/preflight.ts"(){"use strict";init_types2();init_build_freshness();init_alembic_head();init_manifest();init_claude_login();init_readiness_check();REQUIRED_REPO_FILES=["main.py","worker.py","alembic.ini"],BOUND_RUN_ATTACHABLE_PHASES=["lanes-starting","lanes-ready","ready"];PLANE_ATTACHABLE_BASE_URL_REMEDIATION=`do not stop it \u2014 point BAPI_BASE_URL at the plane endpoint (http://127.0.0.1:<port>, the port ${PLANE_SERVER_PORT_ENV_VAR} or the default, with no trailing slash) and run drive-epic again to attach.`,PLANE_REPOSITORY_ROOT_REMEDIATION="run `plane up` from the Bridge API repository root (the directory holding main.py, worker.py, and alembic.ini).",PLANE_REPO_IDENTITY_REMEDIATION="set BAPI_REPO_NAME in this shell, or add a valid .bridge/config at the repository root.",PLANE_CREDENTIAL_REMEDIATION="set BAPI_API_KEY in this shell, or store it with `mcp-server credentials`; a spawned shell never sees .mcp.json env.",PLANE_CREDENTIAL_PERMISSIONS_REMEDIATION="restrict the Bridge credentials file to owner-only permissions (chmod 600), then rerun.",PLANE_CLAUDE_LOGIN_REMEDIATION="run `claude login` on this host so plane members inherit an authenticated session; startup continues either way.",PLANE_SERVER_PORT_OCCUPIED_REMEDIATION=`stop the server that owns the port (or wind down its plane) and retry, or set ${PLANE_SERVER_PORT_ENV_VAR} to a free port \u2014 the port may belong to a SIBLING WORKTREE.`,PLANE_SERVER_PORT_UNKNOWN_REMEDIATION=`retry, or set ${PLANE_SERVER_PORT_ENV_VAR} to a port you know is free; startup continues and uvicorn fails loudly if the port is taken.`,PLANE_SERVER_ENDPOINT_REMEDIATION=`set ${PLANE_SERVER_PORT_ENV_VAR} to a valid port number (1-65535), or unset it to use the default.`,PLANE_MANIFEST_UNREADABLE_REMEDIATION="inspect .bridge/plane/plane.json and remove it by hand once you have confirmed no plane is running; preflight signalled no process and changed no file.",PLANE_ALREADY_RUNNING_REMEDIATION="run `plane status` to inspect the running plane, or `plane down` to wind it down first.",PLANE_CREDENTIAL_OUTCOME_IDS={identity:"repo-identity",credential:"bridge-credentials",permissions:"credential-permissions"},PLANE_ROOT_DEPENDENT_SKIP_DETAIL="not run \u2014 every remaining check is relative to a valid repository root",ROOT_DEPENDENT_CHECKS=[["worktree-presence","worktree-presence","Git work tree"],["claude-login","claude-login","Claude login"],["bridge-credentials",PLANE_CREDENTIAL_OUTCOME_IDS.identity,"Bridge repository identity"],["bridge-credentials",PLANE_CREDENTIAL_OUTCOME_IDS.credential,"Bridge API credential"],["bridge-credentials",PLANE_CREDENTIAL_OUTCOME_IDS.permissions,"Bridge credential file permissions"],["executor-build","executor-build","Executor build freshness"],["runtime-entrypoint","runtime-entrypoint","Runtime re-exec entrypoint"],["server-port","server-port","Local server port"],["alembic-head","alembic-head","Database migration head"],["existing-plane","existing-plane","Existing plane"]],PLANE_PORT_PROBE_TIMEOUT_MS=1500;PLANE_WORKTREE_REMEDIATION="cd into the intended worktree (or create it with `git worktree add`) and rerun.";PLANE_READINESS_DESCRIPTORS=[{id:"repository-root",label:"Repository root"},{id:"worktree-presence",label:"Git work tree"},{id:"claude-login",label:"Claude login"},{id:"repo-identity",label:"Bridge repository identity"},{id:"bridge-credentials",label:"Bridge API credential"},{id:"credential-permissions",label:"Bridge credential file permissions"},{id:"executor-build",label:"Executor build freshness"},{id:"runtime-entrypoint",label:"Runtime re-exec entrypoint"},{id:"server-port",label:"Local server port"},{id:"alembic-head",label:"Database migration head"},{id:"existing-plane",label:"Existing plane"}],PLANE_UNREPORTED_DETAIL="not reported \u2014 the plane preflight produced no outcome for this prerequisite",PLANE_UNREPORTED_REMEDIATION="run `plane up` (or `epic-implementer readiness` again) to re-collect the plane preflight; this prerequisite's state is unknown, not healthy."}});var init_version_generated=__esm({"src/version.generated.ts"(){"use strict"}});var init_command_host=__esm({"src/command-host.ts"(){"use strict"}});var init_codex_skill_adapter=__esm({"src/codex-skill-adapter.ts"(){"use strict"}});var init_agents_generated=__esm({"src/agents.generated.ts"(){"use strict"}});var init_docs_generated=__esm({"src/docs.generated.ts"(){"use strict"}});var init_agent_utils=__esm({"src/agent-utils.ts"(){"use strict"}});var init_git_ignore_utils=__esm({"src/git-ignore-utils.ts"(){"use strict"}});var init_mcp_host_entry_adapter=__esm({"src/mcp-host-entry-adapter.ts"(){"use strict";init_mcp_host_targets()}});var init_init=__esm({"src/init.ts"(){"use strict";init_commands_generated();init_command_host();init_codex_skill_adapter();init_agents_generated();init_docs_generated();init_version_generated();init_agent_utils();init_bridge_config();init_git_ignore_utils();init_credential_store();init_launcher_config_inspection();init_mcp_identity();init_mcp_host_entry_adapter();init_mcp_host_targets()}});function joinPath2(base,rel){let b=base.endsWith("/")?base.slice(0,-1):base,r=rel.startsWith("/")?rel.slice(1):rel;return`${b}/${r}`}function isEnoent(err){return typeof err=="object"&&err!==null&&err.code==="ENOENT"}async function readJsonHostConfig(path15,deps){let raw;try{raw=await deps.readFile(path15)}catch(err){return isEnoent(err)?{state:"missing"}:{state:"read-error",message:"config could not be read"}}let parsed;try{parsed=JSON.parse(raw)}catch{return{state:"invalid"}}return typeof parsed!="object"||parsed===null||Array.isArray(parsed)?{state:"invalid"}:{state:"valid",value:parsed}}function escapeRegExp(value){return value.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function storedProfileTokens(value){return typeof value!="string"?[]:value.split(",").map(t=>t.trim()).filter(t=>t.length>0)}function entryProfileTokens(entry){if(!entry||typeof entry!="object"||Array.isArray(entry))return null;let env=entry.env,stored=env&&typeof env=="object"&&!Array.isArray(env)?env.BRIDGE_MCP_PROFILE:void 0;return storedProfileTokens(stored)}async function inspectOneProfileConfig(projectRoot,target,token,deps){let read=await readJsonHostConfig(joinPath2(projectRoot,target.path),deps);if(read.state==="missing")return{path:target.path,state:"absent"};if(read.state!=="valid")return{path:target.path,state:"unreadable"};let root=read.value[target.topLevelKey];if(!root||typeof root!="object"||Array.isArray(root))return{path:target.path,state:"no-bridge-entry"};let servers=root,tokenSets=RECOGNIZED_SERVER_NAMES.filter(name=>Object.prototype.hasOwnProperty.call(servers,name)).map(name=>entryProfileTokens(servers[name])).filter(tokens=>tokens!==null);return tokenSets.length===0?{path:target.path,state:"no-bridge-entry"}:{path:target.path,state:tokenSets.some(tokens=>tokens.includes(token))?"token-present":"token-absent"}}async function inspectBridgeApiProfileToken(projectRoot,token,deps){let configs=[];for(let target of BRIDGE_PROFILE_TOKEN_CONFIGS)configs.push(await inspectOneProfileConfig(projectRoot,target,token,deps));return{token,configs,tokenPresent:configs.some(c=>c.state==="token-present"),bridgeEntryPresent:configs.some(c=>c.state==="token-present"||c.state==="token-absent")}}var DUPLICATE_REGISTRATION_DETAIL,BRIDGE_TABLE_PATTERNS,BRIDGE_PROFILE_TOKEN_CONFIGS,init_mcp_host_config=__esm({"src/mcp-host-config.ts"(){"use strict";init_version_generated();init_codex_home();init_init();init_mcp_host_targets();init_mcp_host_entry_adapter();init_mcp_host_entry_adapter();init_mcp_identity();DUPLICATE_REGISTRATION_DETAIL=`both \`${MCP_SERVER_NAME}\` and \`${LEGACY_SERVER_NAMES.join("`, `")}\` are registered here; confirm which one to keep, remove the other manually, then re-run. Nothing was changed.`;BRIDGE_TABLE_PATTERNS=RECOGNIZED_SERVER_NAMES.map(name=>({name,pattern:new RegExp(`^[ \\t]*\\[mcp_servers\\.${escapeRegExp(name)}(\\.[^\\]]*)?\\][ \\t]*$`,"m")})),BRIDGE_PROFILE_TOKEN_CONFIGS=[{path:".mcp.json",topLevelKey:"mcpServers"},{path:".vscode/mcp.json",topLevelKey:"servers"},{path:".cursor/mcp.json",topLevelKey:"mcpServers"}]}});var init_base_url=__esm({"src/base-url.ts"(){"use strict"}});var init_command_provisioning=__esm({"src/command-provisioning.ts"(){"use strict";init_commands_generated();init_codex_skill_adapter();init_git_ignore_utils()}});var init_ticket_key_utils=__esm({"src/ticket-key-utils.ts"(){"use strict"}});var init_codex_bridge_profile=__esm({"src/codex-bridge-profile.ts"(){"use strict";init_mcp_host_config();init_mcp_identity();init_codex_home()}});var init_codex_launch_scope=__esm({"src/codex-launch-scope.ts"(){"use strict";init_bridge_config();init_mcp_host_config();init_codex_home();init_codex_bridge_profile();init_mcp_provisioning();init_mcp_identity()}});var init_claude_settings=__esm({"src/claude-settings.ts"(){"use strict"}});var init_start_tickets_conductor=__esm({"src/start-tickets-conductor.ts"(){"use strict";init_claude_settings();init_file_scope_guard();init_mcp_profile();init_start_tickets_repo()}});var WORKER_BRANCH_ENV_VAR,init_pr_base_contract=__esm({"src/pr-base-contract.ts"(){"use strict";WORKER_BRANCH_ENV_VAR="BAPI_WORKER_BRANCH"}});var INDEX_SCOPE_ENV_VAR,INDEX_SCOPE_CONFIGURATION_ERROR,init_index_scope_contract=__esm({"src/index-scope-contract.ts"(){"use strict";INDEX_SCOPE_ENV_VAR="BAPI_INDEX_SCOPE",INDEX_SCOPE_CONFIGURATION_ERROR=`${INDEX_SCOPE_ENV_VAR} is not a valid index-scope declaration. Expected a server-minted scope identity; the value was not logged.`}});var init_env_file_link=__esm({"src/env-file-link.ts"(){"use strict";init_worktree_core()}});var init_base_ref=__esm({"src/base-ref.ts"(){"use strict";init_claude_review_workflow_drift_probe();init_start_tickets_prereqs();init_claude_review_workflow_drift_probe()}});var STALE_LAUNCH_SCRIPT_MAX_AGE_MS,init_start_tickets=__esm({"src/start-tickets.ts"(){"use strict";init_base_url();init_version_generated();init_credential_store();init_mcp_identity();init_claude_review_workflow_drift();init_start_tickets_repo();init_mcp_provisioning();init_command_provisioning();init_mcp_server_invocation();init_ticket_key_utils();init_start_tickets_prereqs();init_agent_registry();init_mcp_host_targets();init_codex_launch_scope();init_start_tickets_conductor();init_bridge_api_client();init_pr_base_contract();init_index_scope_contract();init_worktree_core();init_env_file_link();init_base_ref();STALE_LAUNCH_SCRIPT_MAX_AGE_MS=1440*60*1e3}});var REQUIRED_ADAPTER_CAPABILITIES,init_executor_adapter=__esm({"src/agent-launchers/executor-adapter.ts"(){"use strict";REQUIRED_ADAPTER_CAPABILITIES=Object.freeze(["executable","platform","headlessInvocation","mcpScoping","mcpInitParsing","auth","authFailureDetection","denyEnforcement","redaction","lifecycle"])}});var init_executor_adapter_inspection=__esm({"src/agent-launchers/executor-adapter-inspection.ts"(){"use strict";init_executor_adapter()}});var WORKER_SENTINEL_DATABASE_NAME,WORKER_SENTINEL_DATABASE_URL,WORKER_SENTINEL_DATABASE_ENV_KEYS,EXPLICIT_DENY_KEYS,init_env=__esm({"src/executor/env.ts"(){"use strict";init_pr_base_contract();init_file_scope_guard();init_index_scope_contract();WORKER_SENTINEL_DATABASE_NAME="bridge_worker_no_database",WORKER_SENTINEL_DATABASE_URL=`postgresql://${WORKER_SENTINEL_DATABASE_NAME}@127.0.0.1:1/${WORKER_SENTINEL_DATABASE_NAME}`,WORKER_SENTINEL_DATABASE_ENV_KEYS=["DATABASE_URL","POSTGRES_DATABASE","POSTGRES_DB","PGDATABASE"],EXPLICIT_DENY_KEYS=["BRIDGE_MCP_PROFILE","CONDUCTOR_NODE_PATH","BAPI_API_KEY","ANTHROPIC_API_KEY","CLAUDE_CODE_OAUTH_TOKEN","OPENAI_API_KEY","GITHUB_TOKEN","GH_TOKEN","CLAUDE_CONFIG_DIR","XDG_CONFIG_HOME",INDEX_SCOPE_ENV_VAR,WORKER_BRANCH_ENV_VAR,...WORKER_SENTINEL_DATABASE_ENV_KEYS]}});var init_observation=__esm({"src/executor/observation.ts"(){"use strict"}});var init_job_errors=__esm({"src/executor/job-errors.ts"(){"use strict";init_observation()}});var init_permissions=__esm({"src/executor/permissions.ts"(){"use strict";init_claude_settings()}});var WORKER_GUARD_REASON_PREFIX,WORKER_GUARD_MALFORMED_LINE,init_worker_guard_hook=__esm({"src/executor/worker-guard-hook.ts"(){"use strict";WORKER_GUARD_REASON_PREFIX="bridge worker guard",WORKER_GUARD_MALFORMED_LINE=`${WORKER_GUARD_REASON_PREFIX}: payload could not be read; continuing fail-open`}});var init_process=__esm({"src/executor/process.ts"(){"use strict"}});var init_platform=__esm({"src/executor/platform.ts"(){"use strict";init_process()}});var init_claude_executor_adapter=__esm({"src/agent-launchers/claude-executor-adapter.ts"(){"use strict";init_agent_registry();init_claude_user_config_doctor();init_deny_enforcement_preflight();init_env();init_job_errors();init_permissions();init_worker_guard_hook();init_platform();init_observation();init_executor_adapter();init_mcp_identity()}});var init_executor_adapter_registry=__esm({"src/agent-launchers/executor-adapter-registry.ts"(){"use strict";init_agent_registry();init_claude_executor_adapter();init_executor_adapter()}});var init_env_flags=__esm({"src/env-flags.ts"(){"use strict"}});var init_bridge_api_urls=__esm({"src/bridge-api-urls.ts"(){"use strict"}});import{getMethodLiteral}from"@modelcontextprotocol/sdk/server/zod-json-schema-compat.js";var init_tool_surface_gating=__esm({"src/tool-surface-gating.ts"(){"use strict"}});var init_bridge_client=__esm({"src/implement-epic/bridge-client.ts"(){"use strict";init_bridge_api_client()}});var init_checkpoint_store=__esm({"src/implement-epic/checkpoint-store.ts"(){"use strict"}});var init_lock=__esm({"src/implement-epic/lock.ts"(){"use strict"}});var init_job_types=__esm({"src/executor/job-types.ts"(){"use strict"}});var init_worker_command=__esm({"src/executor/worker-command.ts"(){"use strict";init_job_errors();init_job_types()}});var init_worker_containment_diagnostic=__esm({"src/worker-containment-diagnostic.ts"(){"use strict";init_worker_command()}});var init_agent_identity=__esm({"src/executor/agent-identity.ts"(){"use strict";init_agent_registry()}});var init_claim_scope=__esm({"src/executor/claim-scope.ts"(){"use strict"}});import{execFile as execFile2,spawn}from"node:child_process";import{promisify}from"node:util";var execFileAsync,MAX_COMMAND_BUFFER,init_deps=__esm({"src/executor/deps.ts"(){"use strict";init_mcp_server_invocation();execFileAsync=promisify(execFile2),MAX_COMMAND_BUFFER=10*1024*1024}});var DEFAULT_BAPI_BASE_URL,EXECUTOR_BASE_URL_REQUIRED_MESSAGE,init_credentials=__esm({"src/executor/credentials.ts"(){"use strict";init_credential_store();init_base_url();DEFAULT_BAPI_BASE_URL="https://bridgegpt-api.com",EXECUTOR_BASE_URL_REQUIRED_MESSAGE=`no Bridge API base URL configured for the executor: pass --base-url <url> or set BAPI_BASE_URL (production is ${DEFAULT_BAPI_BASE_URL}). The executor never defaults to production.`}});var init_types3=__esm({"src/executor/types.ts"(){"use strict"}});var init_http_client=__esm({"src/executor/http-client.ts"(){"use strict";init_types3();init_bridge_api_client()}});var init_preflight2=__esm({"src/executor/preflight.ts"(){"use strict";init_types();init_executor_adapter_inspection();init_executor_adapter_registry();init_agent_identity();init_credentials()}});var init_heartbeat=__esm({"src/executor/heartbeat.ts"(){"use strict";init_process();init_types3()}});function normalizeGhMergeabilityValue(value){if(typeof value!="string")return null;let trimmed=value.trim();return trimmed.length===0?null:trimmed.toUpperCase()}function parseGhPrMergeabilityFields(record){return{mergeable:normalizeGhMergeabilityValue(record.mergeable),mergeStateStatus:normalizeGhMergeabilityValue(record.mergeStateStatus)}}function isPrMergeConflict(mergeability){return mergeability.mergeable==="CONFLICTING"||mergeability.mergeStateStatus==="DIRTY"}function isLikelyGhMergeConflictOutput(output){if(!output)return!1;let stdout=typeof output.stdout=="string"?output.stdout:"",stderr=typeof output.stderr=="string"?output.stderr:"",haystack=`${stdout}
123
123
  ${stderr}`.toLowerCase();return haystack.trim().length===0?!1:MERGE_CONFLICT_OUTPUT_SIGNATURES.some(sig=>haystack.includes(sig))}var MERGE_CONFLICT_OUTPUT_SIGNATURES,init_github_mergeability=__esm({"src/conductor/github-mergeability.ts"(){"use strict";MERGE_CONFLICT_OUTPUT_SIGNATURES=["merge conflict","merge conflicts","conflicting","conflict with the base branch","not possible to fast-forward","non-fast-forward","not mergeable","is not mergeable","cannot be cleanly created","would create a merge conflict"]}});function normalizeSelectorCheckName(value){if(typeof value!="string")return null;let trimmed=value.trim();return trimmed.length>0?trimmed:null}function parseTimestamp(value){if(typeof value!="string")return null;let trimmed=value.trim();if(trimmed.length===0)return null;let millis=Date.parse(trimmed);return Number.isNaN(millis)?null:millis}function parseRecencyId(record){let candidates=[record.recency_id,record.id,record.check_suite_id],suite=record.check_suite;suite!==null&&typeof suite=="object"&&candidates.push(suite.id);for(let candidate of candidates){if(typeof candidate=="number"&&Number.isFinite(candidate))return candidate;if(typeof candidate=="string"&&INTEGER_TEXT.test(candidate.trim()))return Number.parseInt(candidate.trim(),10)}return null}function recencyKey(record){let started=parseTimestamp(record.started_at),completed=parseTimestamp(record.completed_at),id=parseRecencyId(record);return[started!==null?[1,started]:[0,0],completed!==null?[1,completed]:[0,0],id!==null?[1,id]:[0,0]]}function compareRecency(a,b){let ka=recencyKey(a),kb=recencyKey(b);for(let i=0;i<ka.length;i+=1){if(ka[i][0]!==kb[i][0])return ka[i][0]-kb[i][0];if(ka[i][1]!==kb[i][1])return ka[i][1]<kb[i][1]?-1:1}return 0}function outcomeKey(record){let status=typeof record.status=="string"?record.status.toLowerCase():"",conclusion=typeof record.conclusion=="string"?record.conclusion.toLowerCase():"";return status+" "+conclusion}function looksSuccessful(record){let conclusion=typeof record.conclusion=="string"?record.conclusion.toLowerCase():"",status=typeof record.status=="string"?record.status.toLowerCase():"",bucket=typeof record.bucket=="string"?record.bucket.toLowerCase():"";return record.green===!0||conclusion==="success"||status==="success"||bucket==="pass"}function selectLatestChecks(records){let grouped=new Map,order=[];for(let record of records){if(record===null||typeof record!="object"||Array.isArray(record))continue;let name=normalizeSelectorCheckName(record.name);if(name===null)continue;let bucket=grouped.get(name);bucket===void 0?(grouped.set(name,[record]),order.push(name)):bucket.push(record)}let selected=[],ambiguousNames=new Set;for(let name of order){let candidates=grouped.get(name);if(candidates.length===1){selected.push(candidates[0]);continue}let best=candidates[0];for(let i=1;i<candidates.length;i+=1)compareRecency(candidates[i],best)>0&&(best=candidates[i]);let tied=candidates.filter(c=>compareRecency(c,best)===0);tied.length>1&&new Set(tied.map(outcomeKey)).size>1&&(ambiguousNames.add(name),best=tied.find(c=>!looksSuccessful(c))??tied[0]),selected.push(best)}return{selected,ambiguousNames}}function selectLatestChecksByName(records){let{selected,ambiguousNames}=selectLatestChecks(records),byName=new Map;for(let record of selected){let name=normalizeSelectorCheckName(record.name);name===null||ambiguousNames.has(name)||byName.set(name,record)}return{byName,ambiguousNames}}var INTEGER_TEXT,init_latest_check_selector=__esm({"src/conductor/latest-check-selector.ts"(){"use strict";INTEGER_TEXT=/^[0-9]+$/}});import{spawn as spawn2}from"child_process";function defaultSleep(ms){return new Promise(resolve2=>setTimeout(resolve2,ms))}function sanitizeWaitMs(value,fallback){return typeof value=="number"&&Number.isFinite(value)&&value>=0?Math.floor(value):fallback}function resolveLocalMergeMethod(value){return typeof value=="string"&&MERGE_METHODS.has(value)?value:"squash"}async function defaultRunCommand(cmd,args,env,signal){return await new Promise(resolve2=>{let settled=!1,timedOut=!1,stdout="",stderr="",child=spawn2(cmd,args,{env:{...process.env,...env}}),killChild=()=>{try{child.kill("SIGKILL")}catch{}},timer=setTimeout(()=>{timedOut=!0,killChild()},DEFAULT_COMMAND_TIMEOUT_MS),onAbort=()=>{timedOut=!0,killChild()},finish=result=>{settled||(settled=!0,clearTimeout(timer),signal&&signal.removeEventListener("abort",onAbort),resolve2(result))};signal&&(signal.aborted?onAbort():signal.addEventListener("abort",onAbort)),child.stdout?.setEncoding("utf8"),child.stderr?.setEncoding("utf8"),child.stdout?.on("data",chunk=>{stdout+=chunk}),child.stderr?.on("data",chunk=>{stderr+=chunk}),child.on("error",()=>{finish({status:null,stdout,stderr,timedOut})}),child.on("close",(code,sig)=>{finish({status:code,stdout,stderr,timedOut:timedOut||sig==="SIGKILL"||sig==="SIGTERM"})})})}function buildResponse(request,status,reason,terminal,ledgerEvents){return{action_key:request.action_key,repo_name:request.repo_name,pr_number:request.pr_number,expected_head_sha:request.expected_head_sha,status,reason,terminal,ledger_events:ledgerEvents}}function isNeutralCheckRecord(record){if(!record)return!1;let conclusion=typeof record.conclusion=="string"?record.conclusion.trim().toLowerCase():"";return NEUTRAL_CHECK_CONCLUSIONS.has(conclusion)}function allRequiredChecksGreen(pollResponse,requiredChecks){if(pollResponse===null||typeof pollResponse!="object")return!1;let obj=pollResponse,maybeDetail=obj.detail;maybeDetail&&typeof maybeDetail=="object"&&(Array.isArray(maybeDetail.checks)||"all_passed"in maybeDetail)&&(obj=maybeDetail);let rawChecks=Array.isArray(obj.checks)?obj.checks:[];if(requiredChecks.length===0)return obj.all_passed===!0;let meaningfulNames=new Set;for(let record of rawChecks){if(record===null||typeof record!="object"||Array.isArray(record))continue;let name=normalizeSelectorCheckName(record.name);name!==null&&!isNeutralCheckRecord(record)&&meaningfulNames.add(name)}let arbitrated=rawChecks.filter(record=>{if(record===null||typeof record!="object"||Array.isArray(record))return!0;let name=normalizeSelectorCheckName(record.name);return name===null?!0:!(isNeutralCheckRecord(record)&&meaningfulNames.has(name))}),{byName}=selectLatestChecksByName(arbitrated),isGreen=c=>{if(!c)return!1;let conclusion=typeof c.conclusion=="string"?c.conclusion.toLowerCase():"",status=typeof c.status=="string"?c.status.toLowerCase():"",bucket=typeof c.bucket=="string"?c.bucket.toLowerCase():"";return c.green===!0||conclusion==="success"||status==="success"||bucket==="pass"||isNeutralCheckRecord(c)};return requiredChecks.every(name=>isGreen(byName.get(name)))}function extractMergeCommitOid(parsed){let mc=parsed?.mergeCommit;if(mc&&typeof mc=="object"&&typeof mc.oid=="string")return mc.oid}function isMergedAtExpectedHead(state,headOid,expectedSha){return typeof state=="string"&&state.toUpperCase()==="MERGED"&&typeof headOid=="string"&&headOid.toLowerCase()===expectedSha.toLowerCase()}function readBoundedRefName(value){if(typeof value!="string")return;let trimmed=value.trim();return trimmed.length>0?trimmed:void 0}async function readPrMergeState(run,ghEnv,pr,json=PR_STATE_JSON){let view=await run("gh",["pr","view",String(pr),"--json",json],ghEnv);if(view.timedOut)return{ok:!1,reason:"gh_pr_view_timeout"};if(view.status!==0)return{ok:!1,reason:"gh_pr_view_failed"};try{let parsed=JSON.parse(view.stdout);return{ok:!0,headOid:parsed.headRefOid,state:parsed.state,mergeCommitOid:extractMergeCommitOid(parsed),baseRefName:readBoundedRefName(parsed.baseRefName),headRefName:readBoundedRefName(parsed.headRefName),raw:parsed}}catch{return{ok:!1,reason:"gh_pr_view_unparseable"}}}function buildAlreadyMergedResponse(request,baseDetails,mergeCommitSha){let details={...baseDetails,already_merged:!0,...mergeCommitSha?{merge_commit_sha:mergeCommitSha}:{}};return buildResponse(request,"succeeded",null,!0,[{type:"merge.succeeded",status:"succeeded",details}])}function ciPollFailureDetailFromError(err){if(!(err instanceof ConductorBridgeApiError))return;let kind=err.kind;if(kind!=="timeout"&&kind!=="network"&&kind!=="unauthorized"&&kind!=="server"&&kind!=="http")return;let detail={kind,diagnostic:safeDiagnosticMessage(err,"ci_poll_failed")};return typeof err.status=="number"&&Number.isInteger(err.status)&&(detail.status=err.status),detail}function ciPollFailureReasonFromDetail(detail){if(!detail)return"ci_poll_failed";switch(detail.kind){case"timeout":return"ci_poll_timeout";case"network":return"ci_poll_network";case"unauthorized":return"ci_poll_unauthorized";case"server":return"ci_poll_server";case"http":return typeof detail.status=="number"&&Number.isInteger(detail.status)?`ci_poll_http_${detail.status}`:"ci_poll_http"}}function isAmbiguousCiPollFailureReason(reason){return reason.startsWith("ci_poll_")}async function waitForRequiredChecksGreen(pollCi,access,expectedSha,requiredChecks,timeoutMs,pollIntervalMs,sleep2,now,signal){let start=now();for(;;){if(signal?.aborted)return{ok:!1,reason:"merge_aborted"};let pollResponse;try{pollResponse=await pollCi(access,expectedSha)}catch(err){let pollFailure=ciPollFailureDetailFromError(err);return{ok:!1,reason:ciPollFailureReasonFromDetail(pollFailure),pollFailure}}if(allRequiredChecksGreen(pollResponse,requiredChecks))return{ok:!0};if(now()-start>=timeoutMs)return{ok:!1,reason:"ci_not_green"};if(await sleep2(pollIntervalMs),signal?.aborted)return{ok:!1,reason:"merge_aborted"}}}function makeLocalMergeExecutor(options={},deps={}){let method=resolveLocalMergeMethod(options.method),expectedBaseBranch=readBoundedRefName(options.expectedBaseBranch),expectedHeadBranch=readBoundedRefName(options.expectedHeadBranch),rawRun=deps.runCommand??defaultRunCommand,run=(cmd,args,env)=>Promise.resolve(rawRun(cmd,args,env,deps.signal)),pollCi=deps.pollCi??pollCiChecksForCommit,sleep2=deps.sleep??defaultSleep,now=deps.now??(()=>Date.now()),signal=deps.signal,ciWaitTimeoutMs=sanitizeWaitMs(options.ciWaitTimeoutMs,DEFAULT_CI_WAIT_TIMEOUT_MS),ciWaitPollIntervalMs=sanitizeWaitMs(options.ciWaitPollIntervalMs,DEFAULT_CI_WAIT_POLL_INTERVAL_MS),ghEnv={...deps.env,GH_PROMPT_DISABLED:"1",GH_NO_UPDATE_NOTIFIER:"1"};return async(access,request)=>{let pr=request.pr_number,expectedSha=request.expected_head_sha,requiredChecks=request.gate?.required_checks??[],baseDetails={action_key:request.action_key,repo:request.repo_name,pr_number:pr,expected_head_sha:expectedSha,merge_method:method,executor:"local"},fail=(reason,pollFailure)=>{let details=pollFailure?{...baseDetails,poll_error:{kind:pollFailure.kind,...typeof pollFailure.status=="number"?{status:pollFailure.status}:{},diagnostic:pollFailure.diagnostic}}:baseDetails;return buildResponse(request,"failed",reason,!1,[{type:"merge.failed",status:"failed",reason,details}])},verifyMergedStateAfterAmbiguousFailure=async()=>{let read=await readPrMergeState(run,ghEnv,pr);return read.ok&&isMergedAtExpectedHead(read.state,read.headOid,expectedSha)?buildAlreadyMergedResponse(request,baseDetails,read.mergeCommitOid):null};if(signal?.aborted)return fail("merge_aborted");if(options.approvalRequired)return buildResponse(request,"pending_approval","local_merge_approval_required",!1,[{type:"merge.pending_approval",status:"pending_approval",reason:"local_merge_approval_required",details:baseDetails}]);let firstRead=await readPrMergeState(run,ghEnv,pr);if(!firstRead.ok){let verified=await verifyMergedStateAfterAmbiguousFailure();return verified||fail(firstRead.reason)}if(isMergedAtExpectedHead(firstRead.state,firstRead.headOid,expectedSha))return buildAlreadyMergedResponse(request,baseDetails,firstRead.mergeCommitOid);let firstRefMismatch=findRefMismatch(expectedBaseBranch,expectedHeadBranch,firstRead);if(firstRefMismatch)return buildRefMismatchResponse(request,baseDetails,firstRefMismatch);if(typeof firstRead.headOid!="string"||firstRead.headOid.toLowerCase()!==expectedSha.toLowerCase())return fail("head_drift");if(typeof firstRead.state=="string"&&firstRead.state.toUpperCase()!=="OPEN")return fail("pr_not_open");if(!options.skipCiWait){let ciWait=await waitForRequiredChecksGreen(pollCi,access,expectedSha,requiredChecks,ciWaitTimeoutMs,ciWaitPollIntervalMs,sleep2,now,signal);if(!ciWait.ok){if(isAmbiguousCiPollFailureReason(ciWait.reason)){let verified=await verifyMergedStateAfterAmbiguousFailure();if(verified)return verified}return fail(ciWait.reason,ciWait.pollFailure)}let secondRead=await readPrMergeState(run,ghEnv,pr);if(!secondRead.ok){let verified=await verifyMergedStateAfterAmbiguousFailure();return verified||fail(secondRead.reason)}if(isMergedAtExpectedHead(secondRead.state,secondRead.headOid,expectedSha))return buildAlreadyMergedResponse(request,baseDetails,secondRead.mergeCommitOid);let secondRefMismatch=findRefMismatch(expectedBaseBranch,expectedHeadBranch,secondRead);if(secondRefMismatch)return buildRefMismatchResponse(request,baseDetails,secondRefMismatch);if(typeof secondRead.headOid!="string"||secondRead.headOid.toLowerCase()!==expectedSha.toLowerCase())return fail("head_drift");if(typeof secondRead.state=="string"&&secondRead.state.toUpperCase()!=="OPEN")return fail("pr_not_open")}if(signal?.aborted)return fail("merge_aborted");let merge=await run("gh",["pr","merge",String(pr),`--${method}`,"--match-head-commit",expectedSha],ghEnv);if(merge.status!==0){if(merge.timedOut){let verified=await verifyMergedStateAfterAmbiguousFailure();if(verified)return verified;let reason="gh_merge_timeout";return buildResponse(request,"failed",reason,!1,[{type:"merge.attempted",status:"attempted",details:baseDetails},{type:"merge.failed",status:"failed",reason,details:baseDetails}])}if(isLikelyGhMergeConflictOutput(merge))return buildConflictResponse(request,baseDetails,expectedSha,{mergeable:null,mergeStateStatus:null});let recheck=await readPrMergeState(run,ghEnv,pr,PR_STATE_MERGEABILITY_JSON);if(recheck.ok){if(isMergedAtExpectedHead(recheck.state,recheck.headOid,expectedSha))return buildAlreadyMergedResponse(request,baseDetails,recheck.mergeCommitOid);let mergeability={mergeable:null,mergeStateStatus:null};try{mergeability=parseGhPrMergeabilityFields(recheck.raw)}catch{}if(isPrMergeConflict(mergeability))return buildConflictResponse(request,baseDetails,expectedSha,mergeability)}let mergeFailReason="gh_merge_failed";return buildResponse(request,"failed",mergeFailReason,!1,[{type:"merge.attempted",status:"attempted",details:baseDetails},{type:"merge.failed",status:"failed",reason:mergeFailReason,details:baseDetails}])}let mergeCommitSha,post=await run("gh",["pr","view",String(pr),"--json","mergeCommit"],ghEnv);if(post.status===0)try{mergeCommitSha=extractMergeCommitOid(JSON.parse(post.stdout))}catch{}let succeededDetails={...baseDetails,...mergeCommitSha?{merge_commit_sha:mergeCommitSha}:{}};return buildResponse(request,"succeeded",null,!0,[{type:"merge.attempted",status:"attempted",details:baseDetails},{type:"merge.succeeded",status:"succeeded",details:succeededDetails}])}}function buildConflictResponse(request,baseDetails,expectedSha,mergeability){let reason="gh_merge_conflict",conflictDetails={...baseDetails,head_sha:expectedSha,...mergeability.mergeable?{mergeable:mergeability.mergeable}:{},...mergeability.mergeStateStatus?{mergeStateStatus:mergeability.mergeStateStatus}:{}};return buildResponse(request,"failed",reason,!1,[{type:"merge.attempted",status:"attempted",details:baseDetails},{type:"merge.conflict",status:"failed",reason,details:conflictDetails}])}function findRefMismatch(expectedBaseBranch,expectedHeadBranch,actual){if(expectedBaseBranch!==void 0&&actual.baseRefName!==expectedBaseBranch)return{field:"base",expected:expectedBaseBranch,actual:actual.baseRefName??""};if(expectedHeadBranch!==void 0&&actual.headRefName!==expectedHeadBranch)return{field:"head",expected:expectedHeadBranch,actual:actual.headRefName??""}}function buildRefMismatchResponse(request,baseDetails,mismatch){let reason="ref_mismatch",details={...baseDetails,mismatched_field:mismatch.field,[`expected_${mismatch.field}_branch`]:mismatch.expected,[`actual_${mismatch.field}_branch`]:mismatch.actual,message:`No provider merge was attempted: the pull request's current ${mismatch.field} branch does not match the run's expected ${mismatch.field} branch. Rebuild or cherry-pick the change against the expected run base rather than retargeting the pull request in the GitHub UI.`};return buildResponse(request,"failed",reason,!1,[{type:"merge.failed",status:"failed",reason,details}])}async function preflightLocalGh(run,ghEnv){let version;try{version=await run("gh",["--version"],ghEnv)}catch{return{ok:!1,reason:"local_gh_unavailable"}}if(version.status!==0)return{ok:!1,reason:"local_gh_unavailable"};let auth;try{auth=await run("gh",["auth","status"],ghEnv)}catch{return{ok:!1,reason:"local_gh_unauthenticated"}}return auth.status!==0?{ok:!1,reason:"local_gh_unauthenticated"}:{ok:!0}}async function runApprovedLocalMerge(request,options={},deps={}){let ghEnv={...deps.env,GH_PROMPT_DISABLED:"1",GH_NO_UPDATE_NOTIFIER:"1"},rawRun=deps.runCommand??defaultRunCommand,preflight=await preflightLocalGh((cmd,args,env)=>Promise.resolve(rawRun(cmd,args,env,deps.signal)),ghEnv);return preflight.ok?makeLocalMergeExecutor({method:options.method,skipCiWait:!0},deps)({get baseUrl(){throw new Error("runApprovedLocalMerge must not poll CI")},get apiKey(){throw new Error("runApprovedLocalMerge must not poll CI")},get repoName(){throw new Error("runApprovedLocalMerge must not poll CI")}},request):buildResponse(request,"failed",preflight.reason,!1,[{type:"merge.failed",status:"failed",reason:preflight.reason,details:{action_key:request.action_key,repo:request.repo_name,pr_number:request.pr_number,expected_head_sha:request.expected_head_sha,executor:"local"}}])}var MERGE_METHODS,PR_STATE_JSON,PR_STATE_MERGEABILITY_JSON,DEFAULT_COMMAND_TIMEOUT_MS,DEFAULT_CI_WAIT_TIMEOUT_MS,DEFAULT_CI_WAIT_POLL_INTERVAL_MS,NEUTRAL_CHECK_CONCLUSIONS,init_local_merge=__esm({"src/conductor/local-merge.ts"(){"use strict";init_bridge_api_client();init_github_mergeability();init_latest_check_selector();MERGE_METHODS=new Set(["squash","merge","rebase"]),PR_STATE_JSON="headRefOid,state,mergeCommit,baseRefName,headRefName",PR_STATE_MERGEABILITY_JSON="headRefOid,state,mergeCommit,mergeable,mergeStateStatus,baseRefName,headRefName",DEFAULT_COMMAND_TIMEOUT_MS=6e4,DEFAULT_CI_WAIT_TIMEOUT_MS=18e4,DEFAULT_CI_WAIT_POLL_INTERVAL_MS=5e3;NEUTRAL_CHECK_CONCLUSIONS=new Set(["skipped","neutral"])}});var init_epic_integration_pr=__esm({"src/epic-integration-pr.ts"(){"use strict"}});var init_base_branch=__esm({"src/executor/base-branch.ts"(){"use strict";init_base_ref()}});var init_merge_job=__esm({"src/executor/merge-job.ts"(){"use strict";init_local_merge();init_bridge_api_client();init_epic_integration_pr();init_job_errors();init_base_branch()}});var init_worktree_inspection=__esm({"src/executor/worktree-inspection.ts"(){"use strict";init_job_errors()}});var init_resume_pre_spawn=__esm({"src/executor/resume-pre-spawn.ts"(){"use strict";init_worktree_core();init_job_errors();init_worktree_inspection()}});var init_prompt_spec=__esm({"src/executor/prompt-spec.ts"(){"use strict";init_job_errors()}});var init_results=__esm({"src/executor/results.ts"(){"use strict"}});var init_terminal_mutation=__esm({"src/executor/terminal-mutation.ts"(){"use strict";init_types3()}});var init_verdict_artifact=__esm({"src/executor/verdict-artifact.ts"(){"use strict";init_job_errors();init_worktree_inspection()}});var init_stale_artifacts=__esm({"src/executor/stale-artifacts.ts"(){"use strict";init_verdict_artifact();init_worktree_inspection()}});var init_env_file_guard=__esm({"src/executor/env-file-guard.ts"(){"use strict";init_worktree_inspection()}});var init_worker_log=__esm({"src/executor/worker-log.ts"(){"use strict";init_worktree_inspection()}});var init_worktree_lock=__esm({"src/executor/worktree-lock.ts"(){"use strict";init_worktree_inspection()}});var init_job_log_registry=__esm({"src/executor/job-log-registry.ts"(){"use strict";init_worktree_inspection()}});var init_viewer_tabs=__esm({"src/executor/viewer-tabs.ts"(){"use strict";init_start_tickets()}});var init_interrupted_worktree=__esm({"src/executor/interrupted-worktree.ts"(){"use strict"}});var init_merge_tree_classifier=__esm({"src/executor/merge-tree-classifier.ts"(){"use strict";init_file_scope_guard()}});var init_reconcile_overlap_governance=__esm({"src/executor/reconcile-overlap-governance.ts"(){"use strict"}});var init_reconcile_overlap_types=__esm({"src/executor/reconcile-overlap-types.ts"(){"use strict"}});var init_worker_finalization=__esm({"src/executor/worker-finalization.ts"(){"use strict";init_job_errors();init_job_types()}});var init_reconcile_overlap_job=__esm({"src/executor/reconcile-overlap-job.ts"(){"use strict";init_bridge_api_client();init_file_scope_guard();init_local_merge();init_env();init_job_errors();init_merge_tree_classifier();init_reconcile_overlap_governance();init_reconcile_overlap_types();init_worker_finalization()}});var init_index_scope=__esm({"src/executor/index-scope.ts"(){"use strict";init_index_scope_contract()}});var init_worktree=__esm({"src/executor/worktree.ts"(){"use strict";init_base_ref();init_claude_review_workflow_drift();init_start_tickets_prereqs();init_worktree_core();init_command_provisioning()}});var REQUIRED_MCP_REGISTRATION_MISSING_MESSAGE,init_job_runner=__esm({"src/executor/job-runner.ts"(){"use strict";init_heartbeat();init_job_errors();init_merge_job();init_observation();init_mcp_provisioning();init_executor_adapter_registry();init_executor_adapter();init_agent_identity();init_process();init_resume_pre_spawn();init_prompt_spec();init_start_tickets_conductor();init_results();init_terminal_mutation();init_stale_artifacts();init_env_file_guard();init_verdict_artifact();init_worker_log();init_worktree_lock();init_job_log_registry();init_viewer_tabs();init_job_types();init_interrupted_worktree();init_reconcile_overlap_job();init_base_branch();init_index_scope();init_worker_finalization();init_worktree();init_pr_base_contract();init_worker_command();init_observation();init_mcp_identity();REQUIRED_MCP_REGISTRATION_MISSING_MESSAGE=`the required '${MCP_SERVER_NAME}' MCP registration is missing or unreadable in the prepared worktree; a worker loads MCP servers strictly from that file, so refusing to spawn a worker that would run without Bridge tools`}});var init_live_worker_registry=__esm({"src/executor/live-worker-registry.ts"(){"use strict"}});var EXECUTOR_WORKTREE_GC_IDLE_MS,init_worktree_gc=__esm({"src/executor/worktree-gc.ts"(){"use strict";init_worktree_inspection();EXECUTOR_WORKTREE_GC_IDLE_MS=1440*60*1e3}});var init_runner=__esm({"src/executor/runner.ts"(){"use strict";init_preflight2();init_job_runner();init_job_log_registry();init_live_worker_registry();init_worktree_gc();init_base_ref();init_epic_integration_pr()}});var init_watch_cli=__esm({"src/executor/watch-cli.ts"(){"use strict";init_job_log_registry()}});var init_cli=__esm({"src/executor/cli.ts"(){"use strict";init_version_generated();init_start_tickets_prereqs();init_start_tickets_repo();init_agent_identity();init_claim_scope();init_deps();init_credentials();init_http_client();init_platform();init_runner();init_watch_cli()}});function executorLaunchdDirForHome(homeDir){return pathApiForPlatform("darwin").join(homeDir,...LAUNCHD_DIR_SEGMENTS)}function executorSystemdDirForHome(homeDir){return pathApiForPlatform("linux").join(homeDir,...SYSTEMD_DIR_SEGMENTS)}function executorIdFromLaunchdFilename(filename){if(!filename.startsWith(EXECUTOR_LAUNCHD_LABEL_PREFIX)||!filename.endsWith(EXECUTOR_LAUNCHD_FILENAME_SUFFIX))return null;let id=filename.slice(EXECUTOR_LAUNCHD_LABEL_PREFIX.length,filename.length-EXECUTOR_LAUNCHD_FILENAME_SUFFIX.length);return id.length>0?id:null}function executorIdFromSystemdFilename(filename){if(!filename.startsWith(EXECUTOR_SYSTEMD_UNIT_PREFIX)||!filename.endsWith(EXECUTOR_SYSTEMD_UNIT_SUFFIX))return null;let id=filename.slice(EXECUTOR_SYSTEMD_UNIT_PREFIX.length,filename.length-EXECUTOR_SYSTEMD_UNIT_SUFFIX.length);return id.length>0?id:null}function xmlUnescape(value){return value.replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&apos;/g,"'").replace(/&amp;/g,"&")}function readArgumentContract(args){let repos=[],executorId=null;for(let i=0;i<args.length;i++)args[i]==="--repo"&&typeof args[i+1]=="string"?repos.push(args[++i]):args[i]==="--executor-id"&&typeof args[i+1]=="string"&&(executorId=args[++i]);return{repos,executorId}}function inspectLaunchdPlist(content){let problems=[],envMatch=content.match(new RegExp(`<key>${EXECUTOR_SERVICE_BASE_URL_ENV}</key>\\s*<string>([^<]*)</string>`)),baseUrl=envMatch?xmlUnescape(envMatch[1]):null;baseUrl===null&&problems.push(`no ${EXECUTOR_SERVICE_BASE_URL_ENV} entry found in the plist`);let arrayMatch=content.match(/<key>ProgramArguments<\/key>\s*<array>([\s\S]*?)<\/array>/),args=[];arrayMatch?args=Array.from(arrayMatch[1].matchAll(/<string>([^<]*)<\/string>/g)).map(m=>xmlUnescape(m[1])):problems.push("no ProgramArguments array found in the plist");let{repos,executorId}=readArgumentContract(args);return{ok:problems.length===0,baseUrl,repos,executorId,problems}}function splitSystemdTokens(value){let tokens=[],current="",inQuotes=!1,started=!1;for(let i=0;i<value.length;i++){let ch=value[i];ch==="\\"&&i+1<value.length?(current+=value[++i],started=!0):ch==="%"&&value[i+1]==="%"?(current+="%",i++,started=!0):ch==='"'?(inQuotes=!inQuotes,started=!0):!inQuotes&&/\s/.test(ch)?(started&&tokens.push(current),current="",started=!1):(current+=ch,started=!0)}return started&&tokens.push(current),tokens}function inspectSystemdService(content){let problems=[],lines=content.split(/\r?\n/),envLine=lines.find(l=>l.startsWith(`Environment=${EXECUTOR_SERVICE_BASE_URL_ENV}=`)),baseUrl=null;if(envLine){let raw=envLine.slice(`Environment=${EXECUTOR_SERVICE_BASE_URL_ENV}=`.length);baseUrl=splitSystemdTokens(raw)[0]??null}(baseUrl===null||baseUrl.length===0)&&(baseUrl=null,problems.push(`no ${EXECUTOR_SERVICE_BASE_URL_ENV} directive found in the unit`));let execLine=lines.find(l=>l.startsWith("ExecStart=")),args=[];execLine?args=splitSystemdTokens(execLine.slice(10)):problems.push("no ExecStart directive found in the unit");let{repos,executorId}=readArgumentContract(args);return{ok:problems.length===0,baseUrl,repos,executorId,problems}}function inspectExecutorServiceArtifact(kind,content){try{return kind==="launchd-plist"?inspectLaunchdPlist(content):inspectSystemdService(content)}catch{return{ok:!1,baseUrl:null,repos:[],executorId:null,problems:["unit content could not be parsed"]}}}var EXECUTOR_LAUNCHD_LABEL_PREFIX,EXECUTOR_LAUNCHD_FILENAME_SUFFIX,EXECUTOR_SYSTEMD_UNIT_PREFIX,EXECUTOR_SYSTEMD_UNIT_SUFFIX,EXECUTOR_SERVICE_BASE_URL_ENV,LAUNCHD_DIR_SEGMENTS,SYSTEMD_DIR_SEGMENTS,init_service_unit=__esm({"src/executor/service-unit.ts"(){"use strict";init_platform_escaping();init_worktree_core();init_mcp_server_invocation();init_cli();init_credentials();EXECUTOR_LAUNCHD_LABEL_PREFIX="com.bridge-gpt.executor.",EXECUTOR_LAUNCHD_FILENAME_SUFFIX=".plist",EXECUTOR_SYSTEMD_UNIT_PREFIX="bridge-gpt-executor-",EXECUTOR_SYSTEMD_UNIT_SUFFIX=".service",EXECUTOR_SERVICE_BASE_URL_ENV="BAPI_BASE_URL",LAUNCHD_DIR_SEGMENTS=["Library","LaunchAgents"],SYSTEMD_DIR_SEGMENTS=[".config","systemd","user"]}});var init_service_lifecycle=__esm({"src/executor/service-lifecycle.ts"(){"use strict";init_platform_escaping()}});var init_install_preflight=__esm({"src/executor/install-preflight.ts"(){"use strict";init_claude_login();init_platform()}});var init_executor=__esm({"src/executor/index.ts"(){"use strict";init_cli();init_runner();init_service_unit();init_service_lifecycle();init_install_preflight();init_watch_cli()}});var init_stale_worktree_doctor=__esm({"src/stale-worktree-doctor.ts"(){"use strict";init_worktree_core()}});import path12 from"path";function resolveExecutorServiceConvention(platform,homeDir){return platform==="darwin"?{dir:executorLaunchdDirForHome(homeDir),kind:"launchd-plist",idFromFilename:executorIdFromLaunchdFilename}:platform==="linux"?{dir:executorSystemdDirForHome(homeDir),kind:"systemd-service",idFromFilename:executorIdFromSystemdFilename}:null}async function probeRepoCredential(repo,deps,credDeps){let target=`bapi:${repo}`,resolve2=deps.resolveCredentials??resolveBapiCredentials;try{let result=await resolve2(repo,credDeps);return result.ok?{repo,target,resolved:!0,source:String(result.credentials.source)}:{repo,target,resolved:!1,kind:String(result.kind)}}catch{return{repo,target,resolved:!1,kind:"unavailable"}}}async function collectExecutorServiceDiagnostics(deps){if(deps.platform==="win32")return{status:"skipped",reason:"Windows executor services are set up manually through Task Scheduler, so there is no generated unit to enumerate (`executor install-service` prints the command line instead)."};let convention=resolveExecutorServiceConvention(deps.platform,deps.homedir());if(!convention)return{status:"skipped",reason:`platform '${deps.platform}' has no generated executor service format.`};let entries;try{entries=await deps.readdir(convention.dir)}catch{return{status:"skipped",reason:`no executor service units found (${convention.dir} is absent or unreadable).`}}let matching=entries.filter(name=>convention.idFromFilename(name)!==null).sort((a,b)=>a<b?-1:a>b?1:0);if(matching.length===0)return{status:"skipped",reason:`no executor service units found in ${convention.dir}.`};let credDeps={env:deps.env,homedir:deps.homedir,platform:deps.platform,readFile:deps.readFile,stat:deps.stat,stderr:()=>{}},pathApi=path12.posix,units=[],warnings=[];for(let name of matching){let unitPath=pathApi.join(convention.dir,name),executorId=convention.idFromFilename(name)??name;try{await deps.stat(unitPath)}catch{warnings.push(`${unitPath}: disappeared or became unreadable during collection.`);continue}let content;try{content=await deps.readFile(unitPath)}catch{units.push({path:unitPath,executorId,baseUrl:null,baseUrlClass:"missing",repos:[],credentials:[],warnings:["unit could not be read; its configuration cannot be verified."]});continue}let inspection=inspectExecutorServiceArtifact(convention.kind,content),unitWarnings=[...inspection.problems],baseUrlClass;inspection.baseUrl?inspection.baseUrl.replace(/\/+$/,"")===DEFAULT_BAPI_BASE_URL?(baseUrlClass="production-default",unitWarnings.push(`${EXECUTOR_SERVICE_BASE_URL_ENV} points at production (${DEFAULT_BAPI_BASE_URL}) \u2014 legal, but worth confirming this host is meant to serve production jobs.`)):baseUrlClass="configured":(baseUrlClass="missing",unitWarnings.push(`no ${EXECUTOR_SERVICE_BASE_URL_ENV} in the unit \u2014 the executor requires an explicit base URL and will fail to start.`));let distinctRepos=Array.from(new Set(inspection.repos)),credentials=[];for(let repo of distinctRepos)credentials.push(await probeRepoCredential(repo,deps,credDeps));units.push({path:unitPath,executorId,baseUrl:inspection.baseUrl,baseUrlClass,repos:inspection.repos,credentials,warnings:unitWarnings})}return{status:"collected",units,warnings}}var LEGACY_REGISTRATION_INFO_TEXT,init_doctor2=__esm({"src/doctor.ts"(){"use strict";init_start_tickets();init_version_generated();init_install_doctor();init_codex_bridge_profile();init_executor_adapter_inspection();init_executor_adapter_registry();init_env_flags();init_bridge_api_urls();init_tool_surface_gating();init_credential_store();init_bridge_api_client();init_bridge_client();init_checkpoint_store();init_lock();init_start_tickets_repo();init_worker_containment_diagnostic();init_launcher_config_inspection();init_mcp_identity();init_agent_registry();init_start_tickets_prereqs();init_mcp_profile();init_executor();init_credentials();init_claude_login();init_base_ref();init_manifest();init_ticket_key_utils();init_worktree_core();init_stale_worktree_doctor();LEGACY_REGISTRATION_INFO_TEXT=`This registration remains supported. New installs use \`${MCP_SERVER_NAME}\`. No action is required.`}});function unreported(id){return{id,state:"unreported",detail:UNREPORTED_DETAIL,remediation:BRING_UP_UNREPORTED_REMEDIATION,refusal:"bring-up-facts-unreported"}}function classifyDatabaseMigration(bringUp){let id="database-migration-current";return bringUp===null?unreported(id):bringUp.migration_readable?bringUp.database_migration_current?{id,state:"ok",detail:"the database is at (or ahead of) the code migration head"}:{id,state:"bad",detail:"the database is BEHIND the server's code migration head",remediation:DATABASE_MIGRATION_BEHIND_REMEDIATION,refusal:"database-migration-behind"}:{id,state:"unreadable",detail:"the migration state could not be read (unknown, not confirmed behind)",remediation:DATABASE_MIGRATION_UNREADABLE_REMEDIATION,refusal:"database-migration-unreadable"}}function classifyWorkerPresent(bringUp){let id="worker-present";return bringUp===null?unreported(id):bringUp.heartbeat_readable?bringUp.worker_present?{id,state:"ok",detail:"a reconciler heartbeat is fresh"}:{id,state:"bad",detail:"0 fresh reconcilers \u2014 no worker is running against this deployment",remediation:WORKER_NOT_PRESENT_REMEDIATION,refusal:"worker-not-present"}:{id,state:"unreadable",detail:"the reconciler heartbeat could not be read (unknown, not confirmed absent)",remediation:WORKER_HEARTBEAT_UNREADABLE_REMEDIATION,refusal:"worker-heartbeat-unreadable"}}function classifySingleTransitionAuthority(bringUp){let id="single-transition-authority";return bringUp===null?unreported(id):bringUp.heartbeat_readable?bringUp.fresh_reconciler_count>=2?{id,state:"bad",detail:"2+ fresh reconcilers \u2014 more than one transition authority is ticking",remediation:SECOND_RECONCILER_REMEDIATION,refusal:"second-reconciler-detected"}:bringUp.fresh_reconciler_count===0?{id,state:"bad",detail:"0 fresh reconcilers \u2014 no transition authority is ticking",remediation:WORKER_NOT_PRESENT_REMEDIATION,refusal:"worker-not-present"}:{id,state:"ok",detail:"exactly 1 fresh reconciler"}:{id,state:"unreadable",detail:"the reconciler heartbeat could not be read (unknown, not confirmed)",remediation:WORKER_HEARTBEAT_UNREADABLE_REMEDIATION,refusal:"worker-heartbeat-unreadable"}}function classifyBringUpFacts(bringUp){return[classifyDatabaseMigration(bringUp),classifyWorkerPresent(bringUp),classifySingleTransitionAuthority(bringUp)]}function capitalize(text){return text.length===0?text:text[0].toUpperCase()+text.slice(1)}var BRING_UP_RUNBOOK,BRING_UP_UNREPORTED_REMEDIATION,DATABASE_MIGRATION_UNREADABLE_REMEDIATION,DATABASE_MIGRATION_BEHIND_REMEDIATION,WORKER_HEARTBEAT_UNREADABLE_REMEDIATION,WORKER_NOT_PRESENT_REMEDIATION,SECOND_RECONCILER_REMEDIATION,UNREPORTED_DETAIL,BRING_UP_REFUSAL_MESSAGES,init_bring_up_facts=__esm({"src/conductor/bring-up-facts.ts"(){"use strict";BRING_UP_RUNBOOK="docs/claude/epic-conductor-v2-operator-runbook.md",BRING_UP_UNREPORTED_REMEDIATION="upgrade the Bridge API deploy to a build that reports the bring-up safety facts; their state is unknown here, not healthy.",DATABASE_MIGRATION_UNREADABLE_REMEDIATION=`retry; the migration state could not be read, which is not the same as confirmed-behind. If it persists, check the applied revision with \`alembic current\` (${BRING_UP_RUNBOOK} \xA73d).`,DATABASE_MIGRATION_BEHIND_REMEDIATION=`confirm the applied revision with \`alembic current\` (not \`alembic heads\`, which reads the migration scripts), apply this checkout's migrations with \`alembic -c alembic.ini upgrade head\`, then retry (${BRING_UP_RUNBOOK} \xA73d).`,WORKER_HEARTBEAT_UNREADABLE_REMEDIATION="retry once the Bridge API database is reachable; the reconciler heartbeat could not be read, so worker presence is unknown, not confirmed absent.",WORKER_NOT_PRESENT_REMEDIATION=`start a worker (\`python worker.py\`, or bring up a local plane) \u2014 a server started with DISABLE_SCHEDULER=true runs none. Create and approve only against a server that has a worker (${BRING_UP_RUNBOOK} \xA73d).`,SECOND_RECONCILER_REMEDIATION=`find and stop the extra reconciler: check \`ps aux | grep worker.py\` for a reparented survivor of an earlier plane (${BRING_UP_RUNBOOK} \xA76), and note that a dev server started without DISABLE_SCHEDULER=true runs a reconciler too. A reconciler stopped in the last 120 seconds still counts \u2014 heartbeat rows are not deleted on shutdown \u2014 so wait and retry.`,UNREPORTED_DETAIL="not reported by this Bridge API deploy";BRING_UP_REFUSAL_MESSAGES={"bring-up-facts-unreported":"the Bridge API did not report the bring-up safety facts (database migration, worker presence, single reconciler), so none of them could be confirmed. "+capitalize(BRING_UP_UNREPORTED_REMEDIATION),"database-migration-unreadable":"database migration: the server could not read whether its database is at the migration head, so this is unknown, not confirmed behind. "+capitalize(DATABASE_MIGRATION_UNREADABLE_REMEDIATION),"database-migration-behind":"database migration: the server's database is BEHIND its code's migration head, so the code would run against a schema that was never applied. "+capitalize(DATABASE_MIGRATION_BEHIND_REMEDIATION),"worker-heartbeat-unreadable":"worker presence: the durable reconciler heartbeat could not be read, so whether a worker is running is unknown, not confirmed absent. "+capitalize(WORKER_HEARTBEAT_UNREADABLE_REMEDIATION),"worker-not-present":"worker presence: no reconciler heartbeat is fresh, so nothing would drive this run. "+capitalize(WORKER_NOT_PRESENT_REMEDIATION),"second-reconciler-detected":"single transition authority: two or more reconcilers are ticking the shared database, and two transition authorities wedge an epic. "+capitalize(SECOND_RECONCILER_REMEDIATION)}}});function supervisorSection(readiness){let s=readiness.supervisor,sections=[];if(!s.setup_present||!s.config_present){let missing=[s.setup_present?null:"setup",s.config_present?null:"config"].filter(Boolean).join(" and ");sections.push({id:"supervisor-configuration",label:"Supervisor configuration",status:"degraded",detail:`project-default supervisor ${missing} absent`,remediation:"bootstrap writes the safe project-default posture."})}else sections.push({id:"supervisor-configuration",label:"Supervisor configuration",status:"ok",detail:`setup=${s.setup_source}, config=${s.config_source}`});sections.push(s.required_checks_empty?{id:"supervisor-required-checks",label:"Supervisor required CI checks",status:"degraded",detail:"required-check list is EMPTY \u2014 the done gate would pass unconditionally",remediation:"bootstrap writes a non-empty required-check list into done_gate_config."}:{id:"supervisor-required-checks",label:"Supervisor required CI checks",status:"ok",detail:`${s.required_checks_count} required check(s) configured`});let alignment=s.review_policy_alignment;return alignment!==null&&(alignment.status==="divergent"||alignment.status==="invalid"?sections.push({id:"supervisor-review-alignment",label:"Supervisor review-policy alignment",status:"degraded",detail:alignment.explanation,remediation:alignment.status==="invalid"?"fix the done gate's review_state condition \u2014 review configuration exists but cannot be read, so the merge path refuses rather than merges.":`set the repository review-policy default and the done gate's review_state condition to the same signal, or confirm the difference is intended \u2014 see ${CONDUCTOR_OPERATOR_RUNBOOK_POINTER}.`}):sections.push({id:"supervisor-review-alignment",label:"Supervisor review-policy alignment",status:"ok",detail:alignment.explanation})),sections}function githubCredentialsSection(readiness){let g=readiness.github;if(g.credentials_complete)return{id:"github-credentials",label:"GitHub App credentials",status:"ok",detail:"owner, repository id, and installation id all resolved"};let missing=[g.owner_resolved?null:"owner",g.repo_id_resolved?null:"repository id",g.installation_id_resolved?null:"installation id"].filter(Boolean).join(", ");return{id:"github-credentials",label:"GitHub App credentials",status:"degraded",detail:g.credentials_readable?`incomplete: ${missing} unresolved`:"no GitHub credential row for this repository",remediation:"connect GitHub from the Bridge setup UI (`install-bridge connect-github`)."}}function githubActionsSection(readiness){let g=readiness.github;return g.actions_write?{id:"github-actions-permission",label:"GitHub App actions permission",status:"ok",detail:"actions: write"}:g.actions_probe_succeeded?{id:"github-actions-permission",label:"GitHub App actions permission",status:"degraded",detail:`actions: ${g.actions_permission_level}`,remediation:"grant the GitHub App `actions: write`; the conductor's workflow rerun lane fails open on 403 without it."}:{id:"github-actions-permission",label:"GitHub App actions permission",status:"degraded",detail:"permission could not be checked",remediation:"re-run once credentials resolve; the workflow rerun lane fails open on 403 until this reads `write`."}}function reconcilerSection(readiness){let r=readiness.reconciler;return r.liveness_readable?r.stale?{id:"reconciler-liveness",label:"Reconciler tick liveness",status:"degraded",detail:r.last_tick_at===null?"no reconciler tick recorded for this repository":`last tick ${r.last_tick_age_seconds}s ago (threshold ${readiness.thresholds.reconciler_stale_after_seconds}s)`,remediation:"start the reconciler (`epic-implementer epic-tick` schedule) for this repository."}:{id:"reconciler-liveness",label:"Reconciler tick liveness",status:"ok",detail:`last tick ${r.last_tick_age_seconds}s ago across ${r.active_run_count} active run(s)`}:{id:"reconciler-liveness",label:"Reconciler tick liveness",status:"degraded",detail:"liveness could not be read",remediation:"retry once the Bridge API is reachable; reconciler liveness is unknown here, which is not the same as confirmed-stale."}}function bringUpSection(verdict){let base={id:verdict.id,label:BRING_UP_SECTION_LABELS[verdict.id]};return verdict.state==="ok"?{...base,status:"ok",detail:verdict.detail}:{...base,status:"degraded",detail:verdict.detail,...verdict.remediation?{remediation:verdict.remediation}:{}}}function databaseMigrationCurrentSection(readiness){return bringUpSection(classifyDatabaseMigration(readiness.bring_up??null))}function workerPresentSection(readiness){return bringUpSection(classifyWorkerPresent(readiness.bring_up??null))}function singleTransitionAuthoritySection(readiness){return bringUpSection(classifySingleTransitionAuthority(readiness.bring_up??null))}function bringUpSafetySections(readiness){return[databaseMigrationCurrentSection(readiness),workerPresentSection(readiness),singleTransitionAuthoritySection(readiness)]}function workflowSection(presence,reviewPolicySource,driftDetail){return presence==="present"?{id:"claude-review-workflow",label:"claude-review workflow",status:"ok",detail:driftDetail?`.github/workflows/claude-review.yml present \u2014 ${driftDetail}`:".github/workflows/claude-review.yml present"}:presence==="drifted"?{id:"claude-review-workflow",label:"claude-review workflow",status:"degraded",detail:driftDetail??".github/workflows/claude-review.yml differs from the repository default branch",remediation:CLAUDE_REVIEW_WORKFLOW_DRIFT_REMEDIATION}:reviewPolicySource==="native_review_decision"||reviewPolicySource==="none"?{id:"claude-review-workflow",label:"claude-review workflow",status:"ok",detail:`not applicable for review policy '${reviewPolicySource}'`}:{id:"claude-review-workflow",label:"claude-review workflow",status:"degraded",detail:presence==="unreadable"?".github/workflows/claude-review.yml could not be read":".github/workflows/claude-review.yml absent",remediation:"the selected review policy consumes the sticky verdict this workflow emits; install the template."}}function executorProvisioningSection(diagnostics){let base={id:"executor-provisioning",label:"Executor provisioning"};if(diagnostics===null)return{...base,status:"degraded",detail:"executor service-unit diagnostics could not be collected",remediation:EXECUTOR_INSTALL_SERVICE_REMEDIATION};if(diagnostics.status==="skipped")return{...base,status:"degraded",detail:diagnostics.reason,remediation:EXECUTOR_INSTALL_SERVICE_REMEDIATION};let unhealthy=diagnostics.units.filter(unit=>unit.warnings.length>0||unit.credentials.some(cred=>!cred.resolved)),ids=diagnostics.units.map(unit=>unit.executorId).join(", ");return unhealthy.length===0&&diagnostics.warnings.length===0?{...base,status:"ok",detail:`${diagnostics.units.length} generated service unit(s) found (${ids}); unit presence only \u2014 see the service-state and observation sections`}:{...base,status:"degraded",detail:`${diagnostics.units.length} generated service unit(s) found (${ids}), but ${unhealthy.length} unit(s) carry warnings or unresolved credentials \u2014 see the embedded executor-provisioning report`,remediation:EXECUTOR_INSTALL_SERVICE_REMEDIATION}}function executorServiceStateSection(observations,unitsDiscovered,inspectorAvailable){let base={id:"executor-service-state",label:"Executor service state"};if(!unitsDiscovered)return{...base,status:"degraded",detail:"no generated unit to inspect, so no service state was collected",remediation:EXECUTOR_INSTALL_SERVICE_REMEDIATION};if(!inspectorAvailable||observations.length===0)return{...base,status:"degraded",detail:"local service state could not be collected on this host",remediation:EXECUTOR_SERVICE_START_REMEDIATION};let rendered=[...observations].sort((a,b)=>a.executorId<b.executorId?-1:a.executorId>b.executorId?1:0).map(o=>`${o.executorId}=${o.state}`).join(", ");return observations.every(o=>o.state==="active")?{...base,status:"ok",detail:`service state: ${rendered}`}:{...base,status:"degraded",detail:`service state: ${rendered}`,remediation:EXECUTOR_SERVICE_START_REMEDIATION}}function executorObservationSection(readiness){let base={id:"executor-observation",label:"Executor server observation"};if(readiness===null||!readiness.executor.liveness_readable)return{...base,status:"degraded",detail:"server executor observation is unknown (readiness could not be read)",remediation:"retry once the Bridge API is reachable; no readiness claim is made from local state."};let e=readiness.executor,seen=e.last_seen_at===null?"never seen":`last seen ${e.last_seen_at} (${e.last_seen_age_seconds}s ago)`;return e.ready===!0?{...base,status:"ok",detail:`executor_ready \u2014 ${seen}`}:e.ready===!1?{...base,status:"degraded",detail:`observed but stale/not ready \u2014 ${seen}`,remediation:EXECUTOR_SERVICE_START_REMEDIATION}:{...base,status:"degraded",detail:`never observed by the server \u2014 ${seen}`,remediation:EXECUTOR_SERVICE_START_REMEDIATION}}function detectConductorContext(legacyConductor,profile){return legacyConductor?.mcp_profile?.conductor_context_detected===!0||profile?.tokenPresent===!0}function conductorProfileTokenSection(profile,conductorContext){let base={id:"conductor-profile-token",label:"MCP conductor profile token"};if(profile===null)return{...base,status:"degraded",detail:"the host MCP profile token could not be inspected",remediation:CONDUCTOR_PROFILE_TOKEN_REMEDIATION};let carrying=profile.configs.filter(c=>c.state==="token-present").map(c=>c.path),scope="inspected .mcp.json, .vscode/mcp.json, .cursor/mcp.json only (Codex and Copilot host configuration is not inspected)";if(carrying.length>0)return{...base,status:"ok",detail:`\`${profile.token}\` present in ${carrying.join(", ")}; ${scope}`};let detail=profile.bridgeEntryPresent?`no supported host config carries the \`${profile.token}\` token; ${scope}`:`no supported host config carries a Bridge entry; ${scope}`,remediation=profile.bridgeEntryPresent?CONDUCTOR_PROFILE_TOKEN_REMEDIATION:CONDUCTOR_PROFILE_TOKEN_NO_ENTRY_REMEDIATION;return conductorContext?{...base,status:"degraded",detail,remediation}:{...base,status:"ok",detail:`advisory \u2014 ${detail}`,remediation}}function conductorHookTargetsSection(legacyConductor,conductorContext){let base={id:"conductor-hook-targets",label:"Conductor hook targets"};if(legacyConductor==null)return{...base,status:"degraded",detail:"hook targets could not be derived (the epic-implementer doctor was not collected)",remediation:CONDUCTOR_HOOK_TARGET_REMEDIATION};let hooks=legacyConductor.git_hooks;if(hooks===void 0)return{...base,status:"degraded",detail:"hook targets could not be derived (the epic-implementer doctor reported no hook state)",remediation:CONDUCTOR_HOOK_TARGET_REMEDIATION};if(!hooks.is_worktree)return{...base,status:"ok",detail:"advisory \u2014 not a git worktree, so no managed conductor hooks apply"};let usable=name=>{let hook=(hooks.hooks??[]).find(h=>h.name===name);return hook!==void 0&&hook.exists&&hook.managed_block_present&&hook.embedded_bin_is_file},rendered=MANAGED_HOOK_NAMES.map(name=>`${name}=${usable(name)}`).join(", ");if(MANAGED_HOOK_NAMES.every(name=>usable(name)))return{...base,status:"ok",detail:`managed hooks usable: ${rendered}`};let detail=`managed hooks usable: ${rendered}`;return conductorContext?{...base,status:"degraded",detail,remediation:CONDUCTOR_HOOK_TARGET_REMEDIATION}:{...base,status:"ok",detail:`advisory \u2014 ${detail}`,remediation:CONDUCTOR_HOOK_TARGET_REMEDIATION}}function conductorLedgerLoadabilitySection(legacyConductor){let base={id:"conductor-ledger-loadability",label:"Conductor ledger loadability"};if(legacyConductor==null)return{...base,status:"degraded",detail:"ledger loadability could not be derived (the epic-implementer doctor was not collected)",remediation:CONDUCTOR_LEDGER_LOADABILITY_REMEDIATION};let inspection=legacyConductor.native_ledger;if(inspection===void 0)return{...base,status:"degraded",detail:"ledger loadability could not be derived (the epic-implementer doctor reported no native-ledger state)",remediation:CONDUCTOR_LEDGER_LOADABILITY_REMEDIATION};let availability=describeNativeLedgerAvailability(inspection);return availability.status==="available"?{...base,status:"ok",detail:"ledger available \u2014 the native binding loads"}:{...base,status:"degraded",detail:`ledger degraded \u2014 ${availability.module} did not load (NODE_MODULE_VERSION ${availability.nodeModulesAbi}, failure: ${availability.failureKind})`,remediation:CONDUCTOR_LEDGER_LOADABILITY_REMEDIATION}}async function inspectWorkflowPresence(readWorkflowFile,classifyWorkflowDrift){let local=await inspectWorkflowLocalPresence(readWorkflowFile);if(local!=="present"||!classifyWorkflowDrift)return{presence:local};try{let classification=await classifyWorkflowDrift();return classification.state==="drifted"?{presence:"drifted",driftDetail:summarizeClaudeReviewWorkflowDrift(classification)}:classification.state==="unverified"?{presence:"present",driftDetail:summarizeClaudeReviewWorkflowDrift(classification)}:{presence:"present"}}catch{return{presence:"present"}}}async function inspectWorkflowLocalPresence(readWorkflowFile){try{return await readWorkflowFile(),"present"}catch(err){return err?.code==="ENOENT"?"absent":"unreadable"}}var CONDUCTOR_OPERATOR_RUNBOOK_POINTER,CONDUCTOR_PROFILE_TOKEN,CONDUCTOR_PROFILE_TOKEN_NO_ENTRY_REMEDIATION,CONDUCTOR_PROFILE_TOKEN_REMEDIATION,CONDUCTOR_HOOK_TARGET_REMEDIATION,CONDUCTOR_LEDGER_LOADABILITY_REMEDIATION,EXECUTOR_INSTALL_SERVICE_REMEDIATION,EXECUTOR_SERVICE_START_REMEDIATION,BRING_UP_SECTION_LABELS,init_readiness_sections=__esm({"src/conductor/readiness-sections.ts"(){"use strict";init_git_hooks();init_mcp_identity();init_claude_review_workflow_drift();init_doctor();init_bring_up_facts();CONDUCTOR_OPERATOR_RUNBOOK_POINTER="docs/claude/epic-conductor-v2-operator-runbook.md",CONDUCTOR_PROFILE_TOKEN="conductor",CONDUCTOR_PROFILE_TOKEN_NO_ENTRY_REMEDIATION=`no supported host MCP config carries a Bridge entry \u2014 run \`npx ${MCP_PACKAGE_NAME} install\` to register one, then re-run \`install conductor\`.`,CONDUCTOR_PROFILE_TOKEN_REMEDIATION="re-run `install conductor` and accept the tool-visibility consent; the conductor tools become visible after the MCP client is restarted.",CONDUCTOR_HOOK_TARGET_REMEDIATION="re-run `install conductor` and accept the local-observability consent, or run `epic-implementer install-git-hooks` directly.",CONDUCTOR_LEDGER_LOADABILITY_REMEDIATION="`better-sqlite3` is an optionalDependency npm silently skips on a build failure \u2014 reinstall it for this Node runtime to restore local conductor observability.",EXECUTOR_INSTALL_SERVICE_REMEDIATION=`generate a persistent unit with \`install conductor --executor-id <id>\` or \`executor install-service\` (or run the executor by hand) \u2014 see ${CONDUCTOR_OPERATOR_RUNBOOK_POINTER}.`,EXECUTOR_SERVICE_START_REMEDIATION=`start the service (re-run \`install conductor\` and accept the start consent, or run the printed launchctl/systemctl command by hand) \u2014 see ${CONDUCTOR_OPERATOR_RUNBOOK_POINTER}.`;BRING_UP_SECTION_LABELS={"database-migration-current":"Database migration","worker-present":"Worker present","single-transition-authority":"Single transition authority"}}});import{readdir as fsReaddir,readFile as fsReadFile,stat as fsStat}from"node:fs/promises";import os5 from"node:os";async function settle(collect){if(!collect)return{value:null,failed:!1};try{return{value:await collect(),failed:!1}}catch{return{value:null,failed:!0}}}async function runConductorInstallDoctor(deps){let sections=[],buildConductor=deps.buildConductorReport??buildConductorDoctorReport,collectInstall=deps.collectInstallChecks??(deps.installDoctorDeps?()=>collectInstallStatusChecks(deps.installDoctorDeps):null),[conductorSettled,executorPreflightSettled,installChecksSettled]=await Promise.all([settle(()=>buildConductor(deps.conductorDoctorDeps)),settle(deps.collectExecutorPreflight?()=>deps.collectExecutorPreflight():null),settle(collectInstall)]),legacyConductor=conductorSettled.value??null;conductorSettled.failed&&sections.push({id:"conductor-ledger",label:"Conductor ledger doctor",status:"degraded",detail:"the local epic-implementer doctor could not be built",remediation:"run `epic-implementer doctor` directly to see why the local ledger report failed."});let legacyExecutorPreflight=executorPreflightSettled.value??null;executorPreflightSettled.failed&&sections.push({id:"executor-preflight",label:"Executor preflight",status:"degraded",detail:"the executor preflight could not be collected",remediation:"re-run this command; if it persists, run `executor` directly to surface the preflight failure."});let legacyInstallChecks=installChecksSettled.value??null;installChecksSettled.failed&&sections.push({id:"install-status",label:"Bridge install status",status:"degraded",detail:"the install-status checklist could not be collected",remediation:"run `doctor` to collect the advisory install-status checklist on its own."});let readiness=null;if(!deps.access)sections.push({id:"bridge-access",label:"Bridge API access",status:"fatal",detail:deps.accessError??"Bridge API repository/credential could not be resolved",remediation:"run `install-bridge` (or set BAPI_API_KEY) for this repository."});else try{readiness=await fetchConductorReadiness(deps.access,deps.fetch)}catch(err){let kind=err instanceof ConductorBridgeApiError?err.kind:"network",fatalKind=kind==="unauthorized"||kind==="invalid-input";sections.push({id:"server-readiness",label:"Server readiness",status:fatalKind?"fatal":"degraded",detail:kind==="unauthorized"?"Bridge API rejected the credential for this repository":kind==="invalid-input"?"the readiness response failed shape validation":"the readiness endpoint could not be reached",remediation:fatalKind?"re-check the API key and repository, then re-run.":"retry; the local sections above are unaffected."})}readiness&&(sections.push(...supervisorSection(readiness)),sections.push(githubCredentialsSection(readiness)),sections.push(githubActionsSection(readiness)));let workflow=await inspectWorkflowPresence(deps.readWorkflowFile,deps.classifyWorkflowDrift);sections.push(workflowSection(workflow.presence,deps.reviewPolicySource,workflow.driftDetail)),readiness&&(sections.push(...bringUpSafetySections(readiness)),sections.push(reconcilerSection(readiness)));let collectServiceUnits=deps.collectExecutorServiceUnits??(()=>collectExecutorServiceDiagnostics({platform:process.platform,env:process.env,homedir:os5.homedir,readdir:dirPath=>fsReaddir(dirPath),readFile:filePath=>fsReadFile(filePath,"utf-8"),stat:filePath=>fsStat(filePath)})),executorService=null;try{executorService=await collectServiceUnits()}catch{}sections.push(executorProvisioningSection(executorService));let discoveredUnits=executorService!==null&&executorService.status!=="skipped"?executorService.units:[],executorServiceStates=[];if(deps.inspectExecutorServiceState&&discoveredUnits.length>0)for(let unit of discoveredUnits)try{let state=await deps.inspectExecutorServiceState({executorId:unit.executorId});executorServiceStates.push({executorId:unit.executorId,state})}catch{executorServiceStates.push({executorId:unit.executorId,state:"unknown"})}sections.push(executorServiceStateSection(executorServiceStates,discoveredUnits.length>0,!!deps.inspectExecutorServiceState)),sections.push(executorObservationSection(readiness));let inspectProfile=deps.inspectProfileToken??((projectRoot,token)=>inspectBridgeApiProfileToken(projectRoot,token,{readFile:filePath=>fsReadFile(filePath,"utf-8")})),profileToken=null;try{profileToken=await inspectProfile(deps.projectRoot??process.cwd(),CONDUCTOR_PROFILE_TOKEN)}catch{}let conductorContext=detectConductorContext(legacyConductor,profileToken);return sections.push(conductorProfileTokenSection(profileToken,conductorContext)),sections.push(conductorHookTargetsSection(legacyConductor,conductorContext)),sections.push(conductorLedgerLoadabilitySection(legacyConductor)),{legacyConductor,legacyExecutorPreflight,legacyInstallChecks,executorService,executorServiceStates,readiness,sections}}var init_install_doctor2=__esm({"src/conductor/install-doctor.ts"(){"use strict";init_doctor();init_mcp_host_config();init_doctor2();init_install_doctor();init_readiness_sections();init_bridge_api_client();init_readiness_sections();init_bring_up_facts()}});function mapServerReadinessToChecks(readiness,failure="unreachable"){if(readiness===null){let copy=SERVER_FAILURE_COPY[failure];return SERVER_READINESS_DESCRIPTORS.map(({id,label})=>createReadinessCheck({id:`server.${id}`,source:"server",label,status:"fail",detail:copy.detail,remediation:copy.remediation}))}let s=readiness.supervisor,g=readiness.github,r=readiness.reconciler,e=readiness.executor,outcomes=[];outcomes.push(s.setup_present?{id:"supervisor-setup",status:"pass",detail:`stored (source: ${s.setup_source})`}:{id:"supervisor-setup",status:"fail",detail:"no supervisor setup is stored for this repository",remediation:SERVER_REMEDIATIONS.supervisorSetup}),outcomes.push(s.config_present?{id:"supervisor-config",status:"pass",detail:`stored (source: ${s.config_source})`}:{id:"supervisor-config",status:"fail",detail:"no supervisor configuration is stored for this repository",remediation:SERVER_REMEDIATIONS.supervisorConfig}),outcomes.push(s.required_checks_empty?{id:"supervisor-required-checks",status:"warn",detail:"the required-check list is EMPTY \u2014 the done gate would pass unconditionally",remediation:SERVER_REMEDIATIONS.requiredChecks}:{id:"supervisor-required-checks",status:"pass",detail:`${s.required_checks_count} required check(s) configured`}),outcomes.push({id:"auto-merge",status:"pass",detail:s.auto_merge_enabled?"auto-merge enabled":"auto-merge disabled (operator posture)"}),outcomes.push(s.merge_approval_required_set?{id:"merge-approval",status:"pass",detail:"merge-approval requirement is set explicitly"}:{id:"merge-approval",status:"warn",detail:"the merge-approval requirement is unset, so the merge path falls back to its default",remediation:SERVER_REMEDIATIONS.mergeApproval}),outcomes.push(reviewPolicyOutcome(readiness)),outcomes.push(g.credentials_complete?{id:"github-credentials",status:"pass",detail:"owner, repository id, and installation id all resolved"}:{id:"github-credentials",status:"fail",detail:g.credentials_readable?`incomplete: ${[g.owner_resolved?null:"owner",g.repo_id_resolved?null:"repository id",g.installation_id_resolved?null:"installation id"].filter(Boolean).join(", ")} unresolved`:"no GitHub credential row exists for this repository",remediation:SERVER_REMEDIATIONS.githubCredentials}),outcomes.push(githubActionsOutcome(readiness)),outcomes.push(...bringUpOutcomes(readiness)),outcomes.push(reconcilerOutcome(readiness)),outcomes.push(executorOutcome(readiness)),outcomes.push(reviewWorkflowOutcome(readiness)),outcomes.push(ciWorkflowOutcome(readiness)),outcomes.push(...unattendedOutcomes(readiness));let byId=new Map(outcomes.map(outcome=>[outcome.id,outcome]));return SERVER_READINESS_DESCRIPTORS.map(({id,label})=>{let outcome=byId.get(id);return outcome?createReadinessCheckSafely({id:`server.${id}`,source:"server",label,status:outcome.status,detail:outcome.detail,...outcome.status==="pass"?{}:{remediation:outcome.remediation??SERVER_REMEDIATIONS.olderServer}}):createReadinessCheck({id:`server.${id}`,source:"server",label,status:"fail",detail:"this server fact was not reported",remediation:SERVER_REMEDIATIONS.olderServer})})}function bringUpOutcomes(readiness){return classifyBringUpFacts(readiness.bring_up??null).map(verdict=>verdict.state==="ok"?{id:verdict.id,status:"pass",detail:verdict.detail}:{id:verdict.id,status:"fail",detail:verdict.detail,remediation:verdict.remediation??SERVER_REMEDIATIONS.olderServer})}function unattendedOutcomes(readiness){let u=readiness.unattended;return u===null?["unattended-consent","unattended-notify-default","repository-workflow-readiness"].map(id=>({id,status:"fail",detail:"this server fact was not reported",remediation:SERVER_REMEDIATIONS.olderServer})):[u.conductor_allowed?{id:"unattended-consent",status:"pass",detail:"this repository has consented to unattended conductor runs"}:{id:"unattended-consent",status:"warn",detail:"unattended_epic_implementer_allowed is NOT set \u2014 an unattended run will be refused before it is created",remediation:SERVER_REMEDIATIONS.unattendedConsent},u.notify_webhook_default_declared?{id:"unattended-notify-default",status:"pass",detail:u.notify_webhook_default_verified===!0?"a notify webhook default is declared and verified":"a notify webhook default is declared (verified at approval, not here)"}:{id:"unattended-notify-default",status:"warn",detail:"no repository notify webhook default is declared \u2014 an unattended run needs an escalation channel, and no column supplies a repository default today, so the run must declare notify.webhook_url itself",remediation:SERVER_REMEDIATIONS.unattendedNotifyDefault},u.repository_readiness_confirmed?{id:"repository-workflow-readiness",status:"pass",detail:"the review and conductor-CI workflows are both confirmed"}:{id:"repository-workflow-readiness",status:"warn",detail:"the review and conductor-CI workflows are not both confirmed \u2014 an unattended auto-merging run will be refused",remediation:SERVER_REMEDIATIONS.repositoryWorkflowReadiness}]}function reviewPolicyOutcome(readiness){let s=readiness.supervisor,alignment=s.review_policy_alignment;return alignment!==null?alignment.status==="divergent"||alignment.status==="invalid"?{id:"review-policy",status:"warn",detail:alignment.explanation,remediation:SERVER_REMEDIATIONS.reviewPolicyDivergent}:{id:"review-policy",status:"pass",detail:alignment.explanation}:s.review_policy_present?{id:"review-policy",status:"pass",detail:"a repository review-policy default is stored (alignment not reported by this server)"}:{id:"review-policy",status:"warn",detail:"no repository review-policy default is stored",remediation:SERVER_REMEDIATIONS.reviewPolicyMissing}}function githubActionsOutcome(readiness){let g=readiness.github;return g.actions_write?{id:"github-actions-permission",status:"pass",detail:"actions: write"}:g.actions_probe_succeeded?{id:"github-actions-permission",status:"warn",detail:`actions: ${g.actions_permission_level}`,remediation:SERVER_REMEDIATIONS.actionsMissing}:{id:"github-actions-permission",status:"fail",detail:"the actions permission could not be checked (this is not a confirmed absence)",remediation:SERVER_REMEDIATIONS.actionsProbeFailed}}function reconcilerOutcome(readiness){let r=readiness.reconciler;return r.liveness_readable?r.stale?{id:"reconciler-liveness",status:"fail",detail:r.last_tick_at===null?"no reconciler tick has been recorded for this repository":`last tick ${r.last_tick_age_seconds}s ago (server threshold ${readiness.thresholds.reconciler_stale_after_seconds}s)`,remediation:SERVER_REMEDIATIONS.reconcilerStale}:{id:"reconciler-liveness",status:"pass",detail:`last tick ${r.last_tick_age_seconds}s ago across ${r.active_run_count} active run(s)`}:{id:"reconciler-liveness",status:"fail",detail:"reconciler liveness could not be read",remediation:SERVER_REMEDIATIONS.reconcilerUnreadable}}function executorOutcome(readiness){let e=readiness.executor;return e.liveness_readable?e.ready===!0?{id:"executor-readiness",status:"pass",detail:`executor ready \u2014 last seen ${e.last_seen_age_seconds}s ago`}:e.ready===!1?{id:"executor-readiness",status:"fail",detail:`observed but not ready \u2014 last seen ${e.last_seen_age_seconds}s ago (server threshold ${readiness.thresholds.executor_stale_after_seconds}s)`,remediation:SERVER_REMEDIATIONS.executorStale}:{id:"executor-readiness",status:"fail",detail:"never observed by the server",remediation:SERVER_REMEDIATIONS.executorNeverSeen}:{id:"executor-readiness",status:"fail",detail:"executor liveness could not be read",remediation:SERVER_REMEDIATIONS.executorUnreadable}}function reviewWorkflowOutcome(readiness){let w=readiness.review_workflow;return w===null?{id:"review-workflow",status:"fail",detail:"this Bridge API deploy did not report the review-workflow facts",remediation:SERVER_REMEDIATIONS.olderServer}:w.probe_succeeded?w.emits_run_id&&w.emits_reviewed_sha?{id:"review-workflow",status:"pass",detail:"the default branch's review workflow emits both protocol markers"}:{id:"review-workflow",status:"fail",detail:`missing marker(s): ${[w.emits_run_id?null:"run id",w.emits_reviewed_sha?null:"reviewed SHA"].filter(Boolean).join(", ")}`,remediation:SERVER_REMEDIATIONS.reviewWorkflowIncomplete}:{id:"review-workflow",status:"fail",detail:w.workflow_present?"the review workflow is present but could not be evaluated":"the review workflow could not be found or read on the default branch",remediation:SERVER_REMEDIATIONS.reviewWorkflowUnknown}}function ciWorkflowOutcome(readiness){let c=readiness.conductor_ci_workflow;return c===null?{id:"conductor-ci-workflow",status:"fail",detail:"this Bridge API deploy did not report the conductor-CI workflow facts",remediation:SERVER_REMEDIATIONS.olderServer}:c.probe_succeeded?c.migration_guard_present?{id:"conductor-ci-workflow",status:"pass",detail:"the default branch's conductor CI workflow runs the migration guard"}:{id:"conductor-ci-workflow",status:"warn",detail:"the conductor CI workflow does not run the migration guard",remediation:SERVER_REMEDIATIONS.ciWorkflowMissingGuard}:{id:"conductor-ci-workflow",status:"fail",detail:c.workflow_present?"the conductor CI workflow is present but could not be evaluated":"the conductor CI workflow could not be found or read on the default branch",remediation:SERVER_REMEDIATIONS.ciWorkflowUnknown}}function sectionStatus(status){return status==="fatal"?"fail":status==="degraded"?"warn":"pass"}function mapInstallSectionsToReadinessChecks(sections){let checks=[],seen=new Set;for(let section of sections??[]){if(INSTALL_SECTION_IDS_OWNED_ELSEWHERE.has(section.id)||seen.has(section.id))continue;seen.add(section.id);let status=sectionStatus(section.status);checks.push(createReadinessCheckSafely({id:`conductor.install-section-${section.id}`,source:"conductor",label:section.label,status,detail:section.detail,...status==="pass"?{}:{remediation:section.remediation??"run `install conductor` for this repository to re-provision this capability."}}))}return checks}async function collectConductorReadinessGate(deps){let[installReport,planeResult]=await Promise.all([runInstallDoctorSafely(deps),runPlaneSafely(deps)]),unavailableSources=[];installReport===null&&unavailableSources.push("install","conductor","server"),deps.runPlanePreflight&&planeResult===null&&unavailableSources.push("plane");let checks=[...mapInstallStatusChecksToReadinessChecks(installReport?.legacyInstallChecks??null,installReport===null),...mapConductorDoctorReportToReadinessChecks(installReport?.legacyConductor??null),...mapInstallSectionsToReadinessChecks(installReport?.sections??null),...mapPlanePreflightToReadinessChecks(planeResult),...mapServerReadinessToChecks(installReport?.readiness??null,classifyServerFailure(installReport))],validated=validateReadinessChecks(checks);return{schemaVersion:CONDUCTOR_READINESS_GATE_SCHEMA_VERSION,advisory:CONDUCTOR_READINESS_ADVISORY_NOTICE,repoName:deps.repoName??null,unavailableSources,checks:validated,summary:summarizeReadinessChecks(validated)}}async function runInstallDoctorSafely(deps){try{return deps.runInstallDoctor?await deps.runInstallDoctor():deps.installDoctor?await runConductorInstallDoctor(deps.conductorDoctorDeps?{...deps.installDoctor,conductorDoctorDeps:deps.conductorDoctorDeps}:deps.installDoctor):null}catch{return null}}async function runPlaneSafely(deps){if(!deps.runPlanePreflight)return null;try{return await deps.runPlanePreflight()}catch{return null}}function classifyServerFailure(report){if(report===null)return"unreachable";let sections=report.sections??[];if(sections.some(section=>section.id==="bridge-access"))return"identity-unresolved";let serverSection=sections.find(section=>section.id==="server-readiness");return serverSection?serverSection.detail.includes("rejected the credential")?"unauthorized":serverSection.detail.includes("shape validation")?"invalid-response":"unreachable":"unreachable"}function readinessTag(status){return status==="fail"?"\u2717 FAIL":status==="warn"?"! WARN":status==="skip"?"- SKIP":"\u2713 PASS"}function formatConductorReadinessGateReport(report){let lines=["Conductor readiness (advisory)","\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550",`schema version: ${report.schemaVersion}`,`repository: ${report.repoName??"unresolved"}`,""];for(let source of["install","conductor","plane","server"]){let group=report.checks.filter(check=>check.source===source);if(group.length!==0){lines.push(`[${source}]`);for(let check of group)lines.push(` ${readinessTag(check.status)} ${check.label} (${check.id})`),check.detail&&lines.push(` ${check.detail}`),check.remediation&&lines.push(` \u2192 ${check.remediation}`);lines.push("")}}let{pass,warn,fail,skip}=report.summary;return lines.push(`summary: ${pass} pass, ${warn} warn, ${fail} fail, ${skip} skip`),report.unavailableSources.length>0&&lines.push(`sources that could not be collected: ${report.unavailableSources.join(", ")} (their prerequisites above are reported as failures, not as passes)`),lines.push(""),lines.push(report.advisory),lines.join(`
124
124
  `)}var CONDUCTOR_READINESS_GATE_SCHEMA_VERSION,CONDUCTOR_READINESS_ADVISORY_NOTICE,SERVER_READINESS_DESCRIPTORS,SERVER_FAILURE_COPY,SERVER_REMEDIATIONS,INSTALL_SECTION_IDS_OWNED_ELSEWHERE,init_readiness=__esm({"src/conductor/readiness.ts"(){"use strict";init_doctor();init_install_doctor();init_preflight();init_install_doctor2();init_readiness_sections();init_bring_up_facts();init_readiness_check();CONDUCTOR_READINESS_GATE_SCHEMA_VERSION=1,CONDUCTOR_READINESS_ADVISORY_NOTICE="Advisory only. This report never blocks bring-up, approval, or a run, and never changes an exit code. Remediations are operator actions and are never executed automatically. drive-epic's V2_READINESS_REQUIREMENTS remains the only hard route-selection predicate, and the server-side admission remains the only hard refusal.",SERVER_READINESS_DESCRIPTORS=[{id:"supervisor-setup",label:"Supervisor setup"},{id:"supervisor-config",label:"Supervisor configuration"},{id:"supervisor-required-checks",label:"Supervisor required CI checks"},{id:"auto-merge",label:"Auto-merge posture"},{id:"merge-approval",label:"Merge approval configuration"},{id:"review-policy",label:"Review policy"},{id:"github-credentials",label:"GitHub App credentials"},{id:"github-actions-permission",label:"GitHub App actions permission"},{id:"database-migration-current",label:BRING_UP_SECTION_LABELS["database-migration-current"]},{id:"worker-present",label:BRING_UP_SECTION_LABELS["worker-present"]},{id:"single-transition-authority",label:BRING_UP_SECTION_LABELS["single-transition-authority"]},{id:"reconciler-liveness",label:"Reconciler tick liveness"},{id:"executor-readiness",label:"Executor server observation"},{id:"review-workflow",label:"Review workflow protocol"},{id:"conductor-ci-workflow",label:"Conductor CI migration guard"},{id:"unattended-consent",label:"Repository unattended consent"},{id:"unattended-notify-default",label:"Verified notify webhook default"},{id:"repository-workflow-readiness",label:"Repository workflow readiness"}],SERVER_FAILURE_COPY={"identity-unresolved":{detail:"no server facts were read \u2014 the repository identity or credential could not be resolved",remediation:"run /install-bridge (or set BAPI_REPO_NAME and BAPI_API_KEY) for this repository, then re-run."},unauthorized:{detail:"the Bridge API rejected the credential for this repository",remediation:"re-check the API key and repository name, then re-run; the key may have been rotated."},"invalid-response":{detail:"the readiness response failed shape validation, so no server fact can be trusted",remediation:"re-run; if it persists the Bridge API deploy is inconsistent with this CLI version."},unreachable:{detail:"the readiness endpoint could not be reached",remediation:"check network reachability to the Bridge API and re-run; the local checks above are unaffected."}},SERVER_REMEDIATIONS={supervisorSetup:"run `install conductor` (or `setup-epic`) for this repository to write the project-default supervisor posture.",supervisorConfig:"run `install conductor` for this repository to write the project-default supervisor configuration.",requiredChecks:"configure a non-empty required-check list in done_gate_config; an empty list makes the done gate pass unconditionally.",mergeApproval:"set the merge-approval requirement explicitly in the supervisor configuration rather than leaving it unset.",reviewPolicyMissing:"set the repository review-policy default so the merge path and the code_review gate read the same signal.",reviewPolicyDivergent:"align the repository review-policy default with the done gate's review_state condition, or confirm the difference is intended.",githubCredentials:"connect GitHub from the Bridge setup UI (`install-bridge connect-github`) so owner, repository id, and installation id all resolve.",actionsProbeFailed:"re-run once credentials resolve; the permission could not be checked, which is not the same as confirmed-missing.",actionsMissing:"grant the GitHub App `actions: write`; without it the conductor's workflow rerun lane fails open on 403.",reconcilerUnreadable:"retry once the Bridge API is reachable; reconciler liveness is unknown here, not confirmed stale.",reconcilerStale:"start the reconciler for this repository (the `epic-implementer epic-tick` schedule) so ticks resume.",executorUnreadable:"retry once the Bridge API is reachable; no executor readiness claim is ever made from local state.",executorNeverSeen:"provision and start an executor (`install conductor --executor-id <id>` or `executor install-service`); readiness comes only from a live server observation.",executorStale:"restart the executor service; it was observed once and has gone quiet past the server's staleness threshold.",reviewWorkflowUnknown:"re-run; the default branch's review workflow could not be evaluated, which is not the same as it being absent.",reviewWorkflowIncomplete:"install the claude-review workflow template on the default branch so it emits both the run id and the reviewed SHA the verdict protocol reads.",ciWorkflowUnknown:"re-run; the default branch's conductor CI workflow could not be evaluated, which is not the same as the guard being absent.",ciWorkflowMissingGuard:"add the migration-guard job to the conductor CI workflow on the default branch so migrations are checked before a merge.",olderServer:"upgrade the Bridge API deploy so it reports this fact; its state is unknown here, not healthy.",unattendedConsent:"set `unattended_epic_implementer_allowed` for this repository (docs/claude/account-settings-operator-runbook.md), or run setup with --attended.",unattendedNotifyDefault:"supply a --policy-file declaring notify.webhook_url, or run setup with --attended; an unattended run must have a working escalation channel, and notify.local_sink is not one.",repositoryWorkflowReadiness:"run `install-bridge conductor` so the review and conductor-CI workflows are confirmed on the default branch, or run setup with --attended."};INSTALL_SECTION_IDS_OWNED_ELSEWHERE=new Set(["supervisor-configuration","supervisor-required-checks","supervisor-review-alignment","github-credentials","github-actions-permission","reconciler-liveness","executor-observation","server-readiness","bridge-access","conductor-ledger","conductor-ledger-loadability","install-status"])}});function joinCwd(cwd,rel){return`${cwd.endsWith("/")?cwd.slice(0,-1):cwd}/${rel}`}function claudeReviewWorkflowPath(cwd){return joinCwd(cwd,CLAUDE_REVIEW_WORKFLOW_RELPATH)}var VERDICT_CHECK_SCRIPT,init_claude_review_workflow=__esm({"src/claude-review-workflow.ts"(){"use strict";init_claude_review_workflow_drift();VERDICT_CHECK_SCRIPT=[" // Contract: docs/claude/claude-review-verdict-contract.md \xA71-\xA74."," const VERDICT = /claude-review-verdict:\\s*(approved|changes_requested)/i;"," const RUN_ID = /run[-_]id:\\s*(\\d+)/i;"," const REVIEWED_SHA = /Reviewed-SHA:\\s*([0-9A-Za-z._-]+)/i;"," const FULL_SHA = /^[0-9a-f]{40}$/;"," const APPROVED_WORD = /\\bapproved\\b/i;"," const CHANGES_WORD = /\\bchanges.requested\\b/i;"," const expected = String(process.env.EXPECTED_HEAD || '').trim().toLowerCase();",""," // Ambiguity (both verdict words) or absence (neither) yields"," // 'unknown', never 'approved'."," const verdictOf = (body) => {"," const token = VERDICT.exec(body);"," if (token) return token[1].toLowerCase();"," const a = APPROVED_WORD.test(body);"," const c = CHANGES_WORD.test(body);"," if (a && !c) return 'approved';"," if (c && !a) return 'changes_requested';"," return 'unknown';"," };"," const declaredSha = (body) => {"," const m = REVIEWED_SHA.exec(body);"," return m ? m[1].trim().toLowerCase() : null;"," };",""," // \xA72 eligibility: the structured token, or the loose marker."," // Malformed entries are skipped rather than throwing \u2014 one odd"," // comment must not fail the job for a reason unrelated to review."," const build = (comments) => comments.reduce((acc, c, index) => {"," if (!c || typeof c !== 'object') return acc;"," const body = typeof c.body === 'string' ? c.body : '';"," const hasToken = VERDICT.test(body);"," if (!hasToken && body.indexOf('claude-review') === -1) return acc;"," const run = RUN_ID.exec(body);"," const raw = c.updated_at || c.created_at;"," const ts = typeof raw === 'string' ? Date.parse(raw) : NaN;"," acc.push({"," runId: run ? parseInt(run[1], 10) : 0,"," index,"," body,"," hasToken,"," ts: Number.isNaN(ts) ? null : ts,"," });"," return acc;"," }, []);",""," // \xA73 legacy rank: (has a usable timestamp, that instant, carries the"," // token). The array index is deliberately EXCLUDED so a genuine"," // two-verdict contradiction stays detectable instead of being"," // silently resolved as 'whichever came last'."," const rankOf = (c) => [c.ts !== null ? 1 : 0, c.ts === null ? 0 : c.ts, c.hasToken ? 1 : 0];"," const cmpRank = (a, b) => {"," const x = rankOf(a);"," const y = rankOf(b);"," for (let i = 0; i < x.length; i++) {"," if (x[i] !== y[i]) return x[i] < y[i] ? -1 : 1;"," }"," return 0;"," };",""," // \xA73 conflict: equal-ranked candidates that DISAGREE and share one"," // valid Reviewed-SHA. Duplicate upserts of the same verdict are not"," // a conflict, and candidates without shared provenance never proved"," // they examined the same code."," const conflicts = (tied) => {"," if (new Set(tied.map((c) => verdictOf(c.body))).size < 2) return false;"," const shas = new Set("," tied.map((c) => declaredSha(c.body)).filter((s) => s && FULL_SHA.test(s)),"," );"," if (shas.size !== 1) return false;"," const bound = tied.filter((c) => shas.has(declaredSha(c.body)));"," return new Set(bound.map((c) => verdictOf(c.body))).size >= 2;"," };",""," const resolve = (comments) => {"," const candidates = build(comments);"," if (candidates.length === 0) return { valid: false, reason: 'review_verdict_absent' };"," let tied;"," if (candidates.some((c) => c.runId > 0)) {"," const top = Math.max(...candidates.map((c) => c.runId));"," tied = candidates.filter((c) => c.runId === top);"," } else {"," const best = candidates.reduce((a, b) => (cmpRank(a, b) >= 0 ? a : b));"," tied = candidates.filter((c) => cmpRank(c, best) === 0);"," }"," if (conflicts(tied)) return { valid: false, reason: 'review_verdict_conflict' };"," const winner = tied.reduce((a, b) => (a.index >= b.index ? a : b));"," const declared = declaredSha(winner.body);"," if (declared === null) return { valid: false, reason: 'review_verdict_no_head_proof' };"," if (declared !== expected) {"," return {"," valid: false,"," reason: FULL_SHA.test(declared) ? 'review_verdict_stale_head' : 'review_verdict_malformed_sha',"," };"," }"," const verdict = verdictOf(winner.body);"," if (verdict !== 'approved' && verdict !== 'changes_requested') {"," return { valid: false, reason: 'review_verdict_unknown_token' };"," }"," return { valid: true, reason: 'review_verdict_resolved', verdict };"," };",""," if (!FULL_SHA.test(expected)) {"," core.setOutput('status', 'unavailable');"," core.setOutput('valid', 'false');"," core.setOutput('reason', 'checker_invalid_expected_head');"," return;"," }",""," // Bounded, read-only propagation loop: a verdict posted seconds ago"," // may not be visible to the comments API yet, and calling that"," // 'absent' would spend another paid review for nothing."," let outcome = { valid: false, reason: 'checker_not_run' };"," let status = 'unavailable';"," for (let attempt = 1; attempt <= 4; attempt++) {"," let comments;"," try {"," comments = await github.paginate(github.rest.issues.listComments, {"," owner: context.repo.owner,"," repo: context.repo.repo,"," issue_number: Number(process.env.PR_NUMBER),"," per_page: 100,"," });"," } catch (err) {"," status = 'unavailable';"," outcome = { valid: false, reason: 'comment_fetch_failed' };"," await new Promise((r) => setTimeout(r, 10000));"," continue;"," }"," status = 'checked';"," outcome = resolve(comments);"," const retryable ="," outcome.reason === 'review_verdict_absent' ||"," outcome.reason === 'review_verdict_stale_head';"," if (outcome.valid || !retryable || attempt === 4) break;"," await new Promise((r) => setTimeout(r, 10000));"," }"," core.setOutput('status', status);"," core.setOutput('valid', outcome.valid ? 'true' : 'false');"," core.setOutput('reason', outcome.reason);"," core.info('Verdict check: valid=' + outcome.valid + ' reason=' + outcome.reason);"].join(`