@bridge_gpt/mcp-server 0.2.67 → 0.2.68
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.
- package/README.md +178 -15
- package/build/agent-launchers/claude-executor-adapter.js +27 -0
- package/build/agents.generated.js +22 -2
- package/build/bitbucket-workspace-remote.js +136 -0
- package/build/bootstrap-project-identity.js +24 -0
- package/build/bridge-permissions.js +829 -0
- package/build/claude-settings.js +18 -0
- package/build/cli-help.js +21 -0
- package/build/command-assets-doctor.js +24 -70
- package/build/command-provisioning.js +29 -5
- package/build/commands.generated.js +8 -8
- package/build/conductor/bridge-api-client.js +714 -0
- package/build/conductor/command-drift-production.js +92 -0
- package/build/conductor/command-drift.js +89 -0
- package/build/conductor/doctor.js +69 -26
- package/build/conductor/epic-branch-ci-inspection.js +1375 -0
- package/build/conductor/epic-implementer-cli.js +76 -22
- package/build/conductor/gate-discovery.js +890 -0
- package/build/conductor/install-doctor.js +15 -3
- package/build/conductor/json-output.js +63 -0
- package/build/conductor/readiness-cli.js +95 -10
- package/build/conductor/readiness-sections.js +369 -3
- package/build/conductor/readiness.js +211 -8
- package/build/conductor/recovery-cli.js +110 -4
- package/build/conductor/recovery-operations.js +99 -1
- package/build/connect-bitbucket-api.js +41 -6
- package/build/connect-bitbucket.js +106 -33
- package/build/credential-store.js +207 -47
- package/build/docs.generated.js +57 -3
- package/build/doctor.js +92 -1
- package/build/drive-epic.js +45 -8
- package/build/epic-coherence-input.test-fixtures.js +4 -3
- package/build/epic-implementer-bin.js +1374 -25
- package/build/epic-workarounds-path.js +39 -0
- package/build/executor/cli.js +30 -0
- package/build/executor/completion-contract.js +18 -5
- package/build/executor/deps.js +4 -1
- package/build/executor/gate-qualification-job.js +499 -0
- package/build/executor/guarded-fast-forward-push.js +129 -0
- package/build/executor/integration-job.js +122 -8
- package/build/executor/job-errors.js +8 -1
- package/build/executor/job-runner.js +589 -47
- package/build/executor/likely-tests.js +290 -0
- package/build/executor/live-worker-registry.js +1 -1
- package/build/executor/observation.js +31 -2
- package/build/executor/packaged-recipe.js +106 -0
- package/build/executor/permissions.js +115 -28
- package/build/executor/platform.js +1 -1
- package/build/executor/preflight.js +61 -12
- package/build/executor/process-containment.js +36 -12
- package/build/executor/process.js +15 -7
- package/build/executor/prompt-spec.js +33 -1
- package/build/executor/recently-failed-tests-file.js +71 -0
- package/build/executor/reconcile-overlap-job.js +41 -23
- package/build/executor/required-verification.js +1 -1
- package/build/executor/required-work-ledger.js +105 -17
- package/build/executor/retirement.js +69 -0
- package/build/executor/runner.js +114 -11
- package/build/executor/test-clock.js +15 -0
- package/build/executor/types.js +32 -0
- package/build/executor/viewer-tabs.js +58 -8
- package/build/executor/worker-command.js +23 -7
- package/build/executor/worker-diagnostics.js +37 -0
- package/build/executor/worker-finalization.js +31 -5
- package/build/executor/worker-guard-hook.js +179 -25
- package/build/executor/worker-log.js +4 -3
- package/build/executor/worker-verification-guidance.js +37 -0
- package/build/executor/worktree.js +88 -11
- package/build/first-build-advisory.js +97 -0
- package/build/generated-assets-advisory.js +14 -0
- package/build/generated-assets-catalog.js +66 -0
- package/build/generated-assets-context.js +46 -0
- package/build/generated-assets-dependencies.js +26 -0
- package/build/generated-assets-doctor.js +50 -0
- package/build/generated-assets-health.js +65 -0
- package/build/generated-assets-host.js +17 -0
- package/build/generated-assets-inventory.js +17 -0
- package/build/generated-assets-paths.js +60 -0
- package/build/generated-assets-publisher.js +133 -0
- package/build/generated-assets-remedy.js +25 -0
- package/build/generated-assets-repair.js +72 -0
- package/build/generated-assets-session.js +71 -0
- package/build/generated-assets-test-support.js +35 -0
- package/build/index.js +964 -768
- package/build/init.js +54 -177
- package/build/install-bridge-conductor-gate.js +1372 -0
- package/build/install-bridge-conductor.js +289 -36
- package/build/install-bridge.js +544 -37
- package/build/mcp-install-state.js +50 -4
- package/build/merge-workflow-install.js +3 -4
- package/build/pipeline-utils.js +6 -2
- package/build/pipelines.generated.js +22 -142
- package/build/plan-execution-ledger.js +2 -32
- package/build/plane/manifest.js +16 -1
- package/build/plane/preflight.js +54 -1
- package/build/printed-remedy-commands.js +16 -1
- package/build/readme.generated.js +1 -1
- package/build/repair-assets.js +93 -0
- package/build/run-unit-tests-launcher.js +130 -49
- package/build/secret-redaction.js +33 -0
- package/build/setup-epic.js +108 -3
- package/build/start-tickets-prereqs.js +70 -16
- package/build/start-tickets.js +29 -5
- package/build/tool-surface-gating.js +36 -0
- package/build/upgrade-cli.js +55 -1
- package/build/version.generated.js +3 -3
- package/build/worker-guard-hook-bin.js +3 -2
- package/build/worker-guard-hook-main.js +1 -1
- package/build/worktree-core.js +15 -2
- package/docs/EPIC-IMPLEMENTER-INSTALL.md +30 -12
- package/docs/EPIC-IMPLEMENTER.md +68 -2
- package/package.json +3 -3
- package/pipelines/greenfield-setup.json +4 -128
- package/pipelines/implement-ticket.json +3 -2
|
@@ -36,7 +36,7 @@ import { buildConductorDoctorReport, formatConductorDoctorReport, } from "./doct
|
|
|
36
36
|
import { inspectBridgeApiProfileToken, } from "../mcp-host-config.js";
|
|
37
37
|
import { collectExecutorServiceDiagnostics, formatExecutorServiceDiagnosticsReport, } from "../doctor.js";
|
|
38
38
|
import { collectInstallStatusChecks, formatInstallStatusReport, } from "../install-doctor.js";
|
|
39
|
-
import { bringUpSafetySections, conductorHookTargetsSection, conductorLedgerLoadabilitySection, gitHubActionsMergeObservabilitySections, conductorProfileTokenSection, EPIC_IMPLEMENTER_PROFILE_TOKEN, detectConductorContext, executorObservationSection, executorProvisioningSection, executorServiceStateSection, githubActionsSection, mergeExecutionSections, githubCredentialsSection, inspectWorkflowPresence, reconcilerSection, supervisorSection, workflowSection, } from "./readiness-sections.js";
|
|
39
|
+
import { bringUpSafetySections, conductorHookTargetsSection, conductorLedgerLoadabilitySection, gitHubActionsMergeObservabilitySections, conductorProfileTokenSection, effectiveReviewModeIsRepositoryPolicy, epicBranchCiSections, EPIC_IMPLEMENTER_PROFILE_TOKEN, detectConductorContext, executorObservationSection, executorProvisioningSection, executorServiceStateSection, githubActionsSection, mergeExecutionSections, githubCredentialsSection, inspectWorkflowPresence, reconcilerSection, supervisorSection, workflowSection, } from "./readiness-sections.js";
|
|
40
40
|
import { ConductorBridgeApiError, fetchConductorReadiness, } from "./bridge-api-client.js";
|
|
41
41
|
/**
|
|
42
42
|
* Run one optional collector, containing any throw.
|
|
@@ -155,6 +155,11 @@ export async function runConductorInstallDoctor(deps) {
|
|
|
155
155
|
}
|
|
156
156
|
if (readiness) {
|
|
157
157
|
sections.push(...supervisorSection(readiness));
|
|
158
|
+
// BAPI-1405 — the three warn-only epic-branch CI rows, beside the gate
|
|
159
|
+
// profile they qualify. Never fatal, so they cannot change the exit code or
|
|
160
|
+
// the installer's pre-write abort. An older server renders them as
|
|
161
|
+
// "Unreported — upgrade the server", never as "no warning".
|
|
162
|
+
sections.push(...epicBranchCiSections(readiness.epic_branch_ci));
|
|
158
163
|
sections.push(githubCredentialsSection(readiness));
|
|
159
164
|
sections.push(githubActionsSection(readiness));
|
|
160
165
|
// BAPI-1135 — the shared "Merge execution eligibility" section, immediately
|
|
@@ -166,7 +171,12 @@ export async function runConductorInstallDoctor(deps) {
|
|
|
166
171
|
sections.push(...mergeExecutionSections(readiness));
|
|
167
172
|
}
|
|
168
173
|
const workflow = await inspectWorkflowPresence(deps.readWorkflowFile, deps.classifyWorkflowDrift);
|
|
169
|
-
|
|
174
|
+
// BAPI-1405 — when the server says the effective review mode is
|
|
175
|
+
// `repository_policy`, no review verdict is consumed, so the workflow row
|
|
176
|
+
// reports not-applicable instead of nagging. An older server keeps the
|
|
177
|
+
// caller's source exactly as before.
|
|
178
|
+
const effectiveReviewPolicySource = effectiveReviewModeIsRepositoryPolicy(readiness) ? "repository_policy" : deps.reviewPolicySource;
|
|
179
|
+
sections.push(workflowSection(workflow.presence, effectiveReviewPolicySource, workflow.driftDetail));
|
|
170
180
|
if (readiness) {
|
|
171
181
|
// BAPI-1153 — the "Bring-up safety" group, ahead of the repository-scoped
|
|
172
182
|
// reconciler/executor story: these three decide whether a plane can drive a
|
|
@@ -357,6 +367,8 @@ mergeExecutionSections, databaseMigrationCurrentSection, singleTransitionAuthori
|
|
|
357
367
|
// BAPI-1135 — both new section builders join the compatibility surface like
|
|
358
368
|
// every other one, so an existing importer of this module does not learn a
|
|
359
369
|
// second import path for them.
|
|
360
|
-
gitHubActionsMergeObservabilitySections,
|
|
370
|
+
gitHubActionsMergeObservabilitySections,
|
|
371
|
+
// BAPI-1405 — the epic-branch CI rows and their shared copy.
|
|
372
|
+
epicBranchCiSections, EPIC_BRANCH_CI_RERUN_INSTALL_ADVICE, EPIC_BRANCH_CI_SECTION_IDS, EPIC_BRANCH_CI_SECTION_LABELS, EPIC_BRANCH_CI_UNREPORTED_DETAIL, } from "./readiness-sections.js";
|
|
361
373
|
// BAPI-1153 — the bring-up remediations the three sections above render.
|
|
362
374
|
export { BRING_UP_RUNBOOK, BRING_UP_UNREPORTED_REMEDIATION, DATABASE_MIGRATION_BEHIND_REMEDIATION, DATABASE_MIGRATION_UNREADABLE_REMEDIATION, SECOND_RECONCILER_REMEDIATION, WORKER_HEARTBEAT_UNREADABLE_REMEDIATION, WORKER_NOT_PRESENT_REMEDIATION, } from "./bring-up-facts.js";
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Complete `--json` output for CLI commands (BAPI-1397, F3).
|
|
3
|
+
*
|
|
4
|
+
* The CLI ends through `process.exit(cliExitCode)` in `index.ts` as soon as a
|
|
5
|
+
* command returns its exit code. On macOS a piped stdout is asynchronous, so a
|
|
6
|
+
* large document written with `console.log` could still be queued when the
|
|
7
|
+
* process exited — a 72 KB `epic-status --json` reached its reader truncated.
|
|
8
|
+
*
|
|
9
|
+
* {@link writeJsonDocument} prints the already-serialized document through the
|
|
10
|
+
* same sink as before (so its bytes and the tests that capture `console.log` are
|
|
11
|
+
* unchanged) and then waits until stdout has handed every queued byte to the
|
|
12
|
+
* operating system before the command returns. It never changes a payload.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Wait until `stream` has flushed everything written to it so far.
|
|
16
|
+
*
|
|
17
|
+
* A writable stream completes writes in order, so the callback of a zero-length
|
|
18
|
+
* write runs only after every earlier write has completed. Resolves `true` once
|
|
19
|
+
* flushed and `false` when the stream reports an error (for example a reader
|
|
20
|
+
* that closed the pipe). Never throws and never leaves an `error` listener
|
|
21
|
+
* behind, so a closed pipe cannot become an uncaught exception.
|
|
22
|
+
*/
|
|
23
|
+
export function flushOutputStream(stream) {
|
|
24
|
+
return new Promise((resolve) => {
|
|
25
|
+
let settled = false;
|
|
26
|
+
const finish = (ok) => {
|
|
27
|
+
if (settled)
|
|
28
|
+
return;
|
|
29
|
+
settled = true;
|
|
30
|
+
stream.removeListener("error", onError);
|
|
31
|
+
resolve(ok);
|
|
32
|
+
};
|
|
33
|
+
const onError = () => finish(false);
|
|
34
|
+
stream.once("error", onError);
|
|
35
|
+
try {
|
|
36
|
+
stream.write("", (error) => finish(!error));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
finish(false);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/** Flush the real process stdout. */
|
|
44
|
+
export function flushProcessStdout() {
|
|
45
|
+
return flushOutputStream(process.stdout);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Print one already-serialized JSON document and wait for stdout to drain.
|
|
49
|
+
*
|
|
50
|
+
* Resolves `true` when the whole document was handed to the operating system,
|
|
51
|
+
* `false` when the output could not complete. The text is printed exactly as
|
|
52
|
+
* given, so no command's JSON shape changes.
|
|
53
|
+
*/
|
|
54
|
+
export async function writeJsonDocument(serialized, deps = {}) {
|
|
55
|
+
const log = deps.log ?? ((line) => console.log(line));
|
|
56
|
+
try {
|
|
57
|
+
log(serialized);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return (deps.flush ?? flushProcessStdout)();
|
|
63
|
+
}
|
|
@@ -35,7 +35,9 @@
|
|
|
35
35
|
import os from "node:os";
|
|
36
36
|
import { readFile as fsReadFile, stat as fsStat } from "node:fs/promises";
|
|
37
37
|
import { collectConductorReadinessGate, formatConductorReadinessGateReport, } from "./readiness.js";
|
|
38
|
-
import { readinessEndpointEnvironments, resolveConductorBridgeApiAccess, resolveEpicLaunchBridgeApiAccess } from "./bridge-api-client.js";
|
|
38
|
+
import { fetchEffectiveSupervisorSetup, readinessEndpointEnvironments, resolveConductorBridgeApiAccess, resolveEpicLaunchBridgeApiAccess, } from "./bridge-api-client.js";
|
|
39
|
+
import { createCommandDriftInspector } from "./command-drift-production.js";
|
|
40
|
+
import { flushProcessStdout, writeJsonDocument } from "./json-output.js";
|
|
39
41
|
import { validateHttpBaseUrl } from "../base-url.js";
|
|
40
42
|
import { claudeReviewWorkflowPath } from "../claude-review-workflow.js";
|
|
41
43
|
import { runDefaultPlanePreflight } from "../plane/cli.js";
|
|
@@ -46,13 +48,18 @@ export const READINESS_COLLECTION_NOTICE = "one or more readiness sources could
|
|
|
46
48
|
/** Usage text for `epic-implementer readiness`. */
|
|
47
49
|
export function getReadinessUsage() {
|
|
48
50
|
return [
|
|
49
|
-
"Usage: epic-implementer readiness [--json] [--no-deny-probe] [--base-url <url>]",
|
|
51
|
+
"Usage: epic-implementer readiness [--json] [--no-deny-probe] [--base-url <url>] [--epic-run-id <id>]",
|
|
50
52
|
"",
|
|
51
53
|
"Read-only ADVISORY report of every conductor prerequisite, consolidated from the",
|
|
52
54
|
"Bridge install checklist, the epic-implementer doctor, the plane preflight, and the",
|
|
53
55
|
"server conductor-readiness collector. Each prerequisite reports pass/warn/fail/skip",
|
|
54
56
|
"and, on a failure, exactly ONE named remediation.",
|
|
55
57
|
"",
|
|
58
|
+
"The claude-review workflow row is assessed for a NEW feature-branch run's first",
|
|
59
|
+
"approval: it is not applicable only when the server confirms no repository review",
|
|
60
|
+
"default is set. If that cannot be confirmed the row stays required. This report is",
|
|
61
|
+
"not a prediction or an authorization of any particular run.",
|
|
62
|
+
"",
|
|
56
63
|
"Remediations are NOT run automatically. This command changes nothing: it starts no",
|
|
57
64
|
"plane, approves no run, writes no file, and always exits 0 — `drive-epic` remains",
|
|
58
65
|
"the only route-selection gate and the server-side admission the only hard refusal.",
|
|
@@ -63,6 +70,9 @@ export function getReadinessUsage() {
|
|
|
63
70
|
" this command never spawns the deny-enforcement probe",
|
|
64
71
|
" --base-url <url> Select a read-only Bridge API endpoint for this report;",
|
|
65
72
|
" this does not authorize or supply a credential",
|
|
73
|
+
" --epic-run-id <id>",
|
|
74
|
+
" The epic run being attached. When the live plane is bound to",
|
|
75
|
+
" this run, its port and manifest rows pass with reason own_plane",
|
|
66
76
|
" --help Print this usage message",
|
|
67
77
|
].join("\n");
|
|
68
78
|
}
|
|
@@ -86,11 +96,64 @@ export function parseReadinessArgs(argv) {
|
|
|
86
96
|
return { error: "--base-url requires a valid HTTP(S) URL." };
|
|
87
97
|
parsed.baseUrl = valid.baseUrl;
|
|
88
98
|
}
|
|
99
|
+
else if (token === "--epic-run-id") {
|
|
100
|
+
const raw = argv[++index];
|
|
101
|
+
if (!raw || raw.startsWith("--") || raw.trim() === "") {
|
|
102
|
+
return { error: "--epic-run-id requires an epic run id." };
|
|
103
|
+
}
|
|
104
|
+
parsed.epicRunId = raw.trim();
|
|
105
|
+
}
|
|
89
106
|
else
|
|
90
107
|
return { error: `Unknown argument "${token}". Run "epic-implementer readiness --help" for usage.` };
|
|
91
108
|
}
|
|
92
109
|
return parsed;
|
|
93
110
|
}
|
|
111
|
+
const KNOWN_REVIEW_POLICY_SOURCES = [
|
|
112
|
+
"verdict_protocol",
|
|
113
|
+
"native_review_decision",
|
|
114
|
+
"none",
|
|
115
|
+
"repository_policy",
|
|
116
|
+
];
|
|
117
|
+
/**
|
|
118
|
+
* Choose the review-policy source the workflow row is judged under (BAPI-1406).
|
|
119
|
+
*
|
|
120
|
+
* `repository_policy` is selected ONLY when a successful, parseable response
|
|
121
|
+
* explicitly confirms the repository's effective review default is unset: the
|
|
122
|
+
* `review_policy` key is present and `null`. A stored default is respected, and
|
|
123
|
+
* an unknown or missing source falls back to `verdict_protocol`. Every other
|
|
124
|
+
* outcome — no access, a read failure, a malformed body, a missing key (an older
|
|
125
|
+
* server), an unrecognised value — returns `verdict_protocol`, so the workflow
|
|
126
|
+
* row stays required rather than falsely healthy.
|
|
127
|
+
*
|
|
128
|
+
* Read-only: one GET through the existing supervisor-setup client. This answers
|
|
129
|
+
* "what would a new feature-branch run's first approval resolve to", which is a
|
|
130
|
+
* prospective assessment and not a prediction or authorization of any run.
|
|
131
|
+
*/
|
|
132
|
+
export async function resolveReadinessReviewPolicySource(access, fetchImpl) {
|
|
133
|
+
if (access === null)
|
|
134
|
+
return "verdict_protocol";
|
|
135
|
+
try {
|
|
136
|
+
const setup = await fetchEffectiveSupervisorSetup(access, undefined, fetchImpl);
|
|
137
|
+
if (typeof setup !== "object" || setup === null || Array.isArray(setup)) {
|
|
138
|
+
return "verdict_protocol";
|
|
139
|
+
}
|
|
140
|
+
const record = setup;
|
|
141
|
+
if (!Object.prototype.hasOwnProperty.call(record, "review_policy")) {
|
|
142
|
+
return "verdict_protocol";
|
|
143
|
+
}
|
|
144
|
+
const reviewPolicy = record.review_policy;
|
|
145
|
+
if (reviewPolicy === null)
|
|
146
|
+
return "repository_policy";
|
|
147
|
+
if (typeof reviewPolicy !== "object" || Array.isArray(reviewPolicy)) {
|
|
148
|
+
return "verdict_protocol";
|
|
149
|
+
}
|
|
150
|
+
const source = reviewPolicy.source;
|
|
151
|
+
return KNOWN_REVIEW_POLICY_SOURCES.find((known) => known === source) ?? "verdict_protocol";
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return "verdict_protocol";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
94
157
|
/**
|
|
95
158
|
* Build the production report for `repoRoot`.
|
|
96
159
|
*
|
|
@@ -98,7 +161,7 @@ export function parseReadinessArgs(argv) {
|
|
|
98
161
|
* epic-implementer doctor's local inspections, and the same plane preflight
|
|
99
162
|
* `plane up` and `drive-epic` run. Nothing is re-implemented here.
|
|
100
163
|
*/
|
|
101
|
-
async function collectProductionReport(repoRoot, env, baseUrl) {
|
|
164
|
+
async function collectProductionReport(repoRoot, env, baseUrl, epicRunId) {
|
|
102
165
|
const { reportEnv, resolverEnv } = readinessEndpointEnvironments(env, baseUrl);
|
|
103
166
|
const accessResult = baseUrl === undefined
|
|
104
167
|
? await resolveConductorBridgeApiAccess({ env: reportEnv, cwd: repoRoot })
|
|
@@ -117,6 +180,7 @@ async function collectProductionReport(repoRoot, env, baseUrl) {
|
|
|
117
180
|
});
|
|
118
181
|
}
|
|
119
182
|
const access = accessResult.ok ? accessResult.access : null;
|
|
183
|
+
const reviewPolicySource = await resolveReadinessReviewPolicySource(access);
|
|
120
184
|
return collectConductorReadinessGate({
|
|
121
185
|
// Never guessed: an unresolved identity is reported as such rather than
|
|
122
186
|
// invented, and the repository ROOT is never placed in the report at all.
|
|
@@ -125,10 +189,11 @@ async function collectProductionReport(repoRoot, env, baseUrl) {
|
|
|
125
189
|
access,
|
|
126
190
|
accessError: accessResult.ok ? undefined : accessResult.error,
|
|
127
191
|
fetch: (...args) => fetch(...args),
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
// that
|
|
131
|
-
|
|
192
|
+
// BAPI-1406: the workflow row is judged under the review default the
|
|
193
|
+
// server CONFIRMS for a new feature-branch run's first approval, and under
|
|
194
|
+
// `verdict_protocol` whenever that cannot be established. This is a
|
|
195
|
+
// prospective assessment, not a prediction or authorization of any run.
|
|
196
|
+
reviewPolicySource,
|
|
132
197
|
readWorkflowFile: () => fsReadFile(claudeReviewWorkflowPath(repoRoot), "utf-8"),
|
|
133
198
|
projectRoot: repoRoot,
|
|
134
199
|
installDoctorDeps: {
|
|
@@ -143,12 +208,19 @@ async function collectProductionReport(repoRoot, env, baseUrl) {
|
|
|
143
208
|
},
|
|
144
209
|
// The deny-enforcement probe is never spawned from this command; the check
|
|
145
210
|
// is reported as an explicit skip naming `epic-implementer doctor` instead.
|
|
146
|
-
conductorDoctorDeps: {
|
|
211
|
+
conductorDoctorDeps: {
|
|
212
|
+
env: reportEnv,
|
|
213
|
+
skipDenyProbe: true,
|
|
214
|
+
// BAPI-1392: read-only, warn-only committed-command drift row.
|
|
215
|
+
inspectCommandDrift: createCommandDriftInspector({ env: reportEnv, cwd: repoRoot }),
|
|
216
|
+
},
|
|
147
217
|
// Provided ONLY for a target that names the local plane; otherwise the rows
|
|
148
218
|
// are skipped without any probe.
|
|
149
219
|
...(planeNotApplicable === null
|
|
150
220
|
? {
|
|
151
221
|
runPlanePreflight: () => runDefaultPlanePreflight(repoRoot, reportEnv),
|
|
222
|
+
// BAPI-1397 (F4): only for an applicable local plane.
|
|
223
|
+
...(epicRunId !== undefined ? { epicRunId } : {}),
|
|
152
224
|
}
|
|
153
225
|
: { planeNotApplicable }),
|
|
154
226
|
});
|
|
@@ -175,7 +247,8 @@ export async function runConductorReadinessCommand(argv, deps = {}) {
|
|
|
175
247
|
}
|
|
176
248
|
const cwd = deps.cwd ?? process.cwd();
|
|
177
249
|
const env = deps.env ?? process.env;
|
|
178
|
-
const collect = deps.collect ??
|
|
250
|
+
const collect = deps.collect ??
|
|
251
|
+
((repoRoot) => collectProductionReport(repoRoot, env, parsed.baseUrl, parsed.epicRunId));
|
|
179
252
|
const report = await collect(cwd);
|
|
180
253
|
// Fixed, sanitized, and stderr-only: never a credential, exception, header,
|
|
181
254
|
// body, subprocess output, or absolute path. It fires on a COLLECTION gap,
|
|
@@ -183,7 +256,19 @@ export async function runConductorReadinessCommand(argv, deps = {}) {
|
|
|
183
256
|
// every time an ordinary check fails teaches operators to ignore it.
|
|
184
257
|
if (report.unavailableSources.length > 0)
|
|
185
258
|
sinks.stderr(READINESS_COLLECTION_NOTICE);
|
|
186
|
-
|
|
259
|
+
if (parsed.json) {
|
|
260
|
+
// BAPI-1397 (F3): the document goes through the shared CLI writer, which waits
|
|
261
|
+
// for a piped stdout to drain. An injected sink is the caller's own boundary,
|
|
262
|
+
// so only the production stdout is flushed. Output completion never becomes a
|
|
263
|
+
// readiness verdict and never changes the advisory exit code.
|
|
264
|
+
await writeJsonDocument(JSON.stringify(report), {
|
|
265
|
+
log: sinks.stdout,
|
|
266
|
+
flush: deps.sinks ? async () => true : flushProcessStdout,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
sinks.stdout(formatConductorReadinessGateReport(report));
|
|
271
|
+
}
|
|
187
272
|
// Advisory: the exit code is a constant, never derived from a check status.
|
|
188
273
|
return 0;
|
|
189
274
|
}
|