@bridge_gpt/mcp-server 0.2.66 → 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 +421 -83
- package/build/agent-capabilities/probes.js +15 -5
- package/build/agent-launchers/claude-executor-adapter.js +70 -16
- package/build/agent-launchers/executor-adapter.js +7 -4
- 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/bounded-wait.js +67 -10
- 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 +12 -12
- package/build/conductor/bridge-api-client.js +857 -1
- package/build/conductor/bring-up-facts.js +1 -1
- package/build/conductor/command-drift-production.js +92 -0
- package/build/conductor/command-drift.js +89 -0
- package/build/conductor/doctor.js +72 -29
- package/build/conductor/epic-branch-ci-inspection.js +1375 -0
- package/build/conductor/epic-implementer-cli.js +98 -28
- package/build/conductor/errors.js +4 -3
- package/build/conductor/gate-discovery.js +890 -0
- package/build/conductor/guided-repair.js +6 -2
- package/build/conductor/hook-runtime-qualification.js +1 -1
- package/build/conductor/install-doctor.js +15 -3
- package/build/conductor/json-output.js +63 -0
- package/build/conductor/merge-execution-contract.js +27 -8
- package/build/conductor/merge-execution-eligibility.js +3 -2
- package/build/conductor/pr-ci-producer.js +1 -1
- package/build/conductor/readiness-cli.js +113 -12
- package/build/conductor/readiness-sections.js +410 -9
- package/build/conductor/readiness.js +388 -33
- package/build/conductor/recovery-cli.js +310 -12
- package/build/conductor/recovery-operations.js +167 -3
- package/build/conductor/repair-contract.js +54 -3
- package/build/conductor/repository-workflow-remedy.js +125 -0
- package/build/conductor/tools.js +2 -2
- package/build/conductor-bundle-artifacts.js +8 -0
- 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 +62 -3
- package/build/doctor.js +92 -1
- package/build/drive-epic-key.js +6 -5
- package/build/drive-epic.js +129 -61
- package/build/epic-coherence-input.js +2 -1
- package/build/epic-coherence-input.test-fixtures.js +4 -3
- package/build/epic-implementer-bin.js +1379 -28
- package/build/epic-implementer-bundle-cli.js +2 -2
- package/build/epic-workarounds-path.js +39 -0
- package/build/executor/cli.js +33 -2
- package/build/executor/completion-contract.js +66 -10
- package/build/executor/completion-supervision.js +4 -0
- package/build/executor/deps.js +4 -1
- package/build/executor/env.js +19 -0
- package/build/executor/gate-qualification-job.js +499 -0
- package/build/executor/guarded-fast-forward-push.js +129 -0
- package/build/executor/heartbeat.js +1 -1
- package/build/executor/http-client.js +20 -0
- package/build/executor/integration-job.js +122 -8
- package/build/executor/job-errors.js +33 -1
- package/build/executor/job-runner.js +813 -87
- package/build/executor/likely-tests.js +290 -0
- package/build/executor/live-worker-registry.js +1 -1
- package/build/executor/observation.js +37 -3
- 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 +112 -26
- 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 +111 -18
- package/build/executor/resume-pre-spawn.js +2 -0
- package/build/executor/retirement.js +69 -0
- package/build/executor/runner.js +122 -13
- package/build/executor/service-unit.js +7 -1
- 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 +113 -34
- package/build/executor/worker-guard-hook.js +316 -58
- package/build/executor/worker-log.js +4 -3
- package/build/executor/worker-verification-guidance.js +37 -0
- package/build/executor/worktree.js +166 -8
- 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 +1224 -1054
- package/build/init.js +54 -177
- package/build/install-bridge-conductor-gate.js +1372 -0
- package/build/install-bridge-conductor.js +296 -41
- package/build/install-bridge.js +547 -40
- package/build/mcp-install-state.js +50 -4
- package/build/merge-workflow-install.js +3 -4
- package/build/phase-context-git-probe.js +68 -0
- package/build/phase-result-artifacts.js +173 -5
- package/build/pipeline-utils.js +6 -2
- package/build/pipelines.generated.js +34 -160
- package/build/plan-execution-ledger.js +2 -32
- package/build/plane/alembic-head.js +12 -3
- package/build/plane/base-worktree-guard.js +147 -0
- package/build/plane/cli.js +217 -17
- package/build/plane/code-snapshot.js +468 -0
- package/build/plane/defaults.js +48 -3
- package/build/plane/endpoint.js +41 -0
- package/build/plane/manifest.js +136 -2
- package/build/plane/member-roster.js +94 -19
- package/build/plane/preflight.js +83 -2
- package/build/plane/process-cwd.js +67 -0
- package/build/plane/restart.js +542 -0
- package/build/plane/shutdown.js +31 -0
- package/build/plane/status.js +143 -8
- package/build/plane/supervisor.js +586 -179
- package/build/plane/types.js +54 -2
- package/build/printed-remedy-commands.js +52 -0
- package/build/readiness-check.js +1 -1
- package/build/readme.generated.js +1 -1
- package/build/repair-assets.js +93 -0
- package/build/review-generation.js +22 -0
- package/build/run-unit-tests-launcher.js +130 -49
- package/build/secret-redaction.js +33 -0
- package/build/setup-epic.js +152 -22
- package/build/sfcc/config.js +9 -0
- package/build/sfcc/credentials.js +100 -38
- package/build/sfcc/hostname.js +67 -0
- package/build/sfcc/permissions.js +17 -13
- package/build/sfcc/register.js +1 -1
- package/build/sfcc/tool-wrapper.js +39 -43
- package/build/sfcc/write-grants.js +17 -11
- package/build/sfcc/write-result.js +4 -3
- package/build/sfcc/writes-site-preference.js +20 -8
- package/build/start-tickets-prereqs.js +70 -16
- package/build/start-tickets.js +208 -36
- package/build/tool-error-envelope.js +61 -0
- package/build/tool-surface-gating.js +36 -0
- package/build/upgrade-cli.js +55 -1
- package/build/version.generated.js +3 -3
- package/build/visual-diff.js +22 -1
- package/build/worker-guard-hook-bin.js +4 -6
- package/build/worker-guard-hook-main.js +47 -0
- package/build/worktree-core.js +145 -6
- package/docs/EPIC-IMPLEMENTER-INSTALL.md +867 -0
- package/docs/EPIC-IMPLEMENTER.md +728 -0
- package/docs/install/mcp-tool-integrations.md +24 -15
- package/docs/install/sfcc-integration.md +12 -4
- package/package.json +3 -3
- package/pipelines/greenfield-setup.json +4 -128
- package/pipelines/implement-ticket.json +3 -2
- package/pipelines/plan-epic.json +0 -5
- package/pipelines/review-ticket.json +1 -1
- package/docs/CONDUCTOR.md +0 -605
- package/pipelines/idea-to-pr.json +0 -49
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** The pinned operator runbook every remedy below points into. */
|
|
2
|
-
export const BRING_UP_RUNBOOK = "docs/
|
|
2
|
+
export const BRING_UP_RUNBOOK = "docs/epic-implementer/operator-runbook.md";
|
|
3
3
|
/**
|
|
4
4
|
* The client-derived refusal vocabulary, IN REFUSAL ORDER.
|
|
5
5
|
*
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Production boundaries for the pure command-drift probe (BAPI-1392).
|
|
3
|
+
*
|
|
4
|
+
* `command-drift.ts` is dependency-injected and imports no `fs` or
|
|
5
|
+
* `child_process`; this module is where those effects live. Two boundaries:
|
|
6
|
+
*
|
|
7
|
+
* - the Git boundary, a list-argument `git` runner (never a shell) that can pass
|
|
8
|
+
* the packaged UTF-8 bytes on stdin for `git hash-object --stdin`; and
|
|
9
|
+
* - the profile boundary, which resolves repo-scoped Bridge access through the
|
|
10
|
+
* shared credential resolver and reads the confirmed gate profile through the
|
|
11
|
+
* existing `fetchConductorGateProfile` — no second profile reader.
|
|
12
|
+
*
|
|
13
|
+
* Everything here is read-only. Raw Git output, error text and credentials are
|
|
14
|
+
* never surfaced: a failure is a thrown marker the probe maps to a closed reason.
|
|
15
|
+
*/
|
|
16
|
+
import { spawnSync } from "node:child_process";
|
|
17
|
+
import { COMMANDS } from "../commands.generated.js";
|
|
18
|
+
import { probeCommandDrift, } from "./command-drift.js";
|
|
19
|
+
/** Bounded timeout for one Git subprocess. */
|
|
20
|
+
const GIT_TIMEOUT_MS = 5_000;
|
|
21
|
+
const BLOB_ID = /^[0-9a-f]{40}([0-9a-f]{24})?$/;
|
|
22
|
+
export function createGitRunner(cwd) {
|
|
23
|
+
return (args, input) => {
|
|
24
|
+
const result = spawnSync("git", args, {
|
|
25
|
+
cwd,
|
|
26
|
+
input,
|
|
27
|
+
encoding: "utf-8",
|
|
28
|
+
timeout: GIT_TIMEOUT_MS,
|
|
29
|
+
stdio: [input === undefined ? "ignore" : "pipe", "pipe", "ignore"],
|
|
30
|
+
});
|
|
31
|
+
if (result.error)
|
|
32
|
+
return { status: null, stdout: "" };
|
|
33
|
+
return { status: result.status, stdout: typeof result.stdout === "string" ? result.stdout : "" };
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** The Git boundary. Throws when Git is unavailable; "no tracked copy" is a value. */
|
|
37
|
+
export function createCommandDriftGit(run) {
|
|
38
|
+
let headState;
|
|
39
|
+
const ensureRepository = () => {
|
|
40
|
+
if (headState)
|
|
41
|
+
return headState;
|
|
42
|
+
const inside = run(["rev-parse", "--git-dir"]);
|
|
43
|
+
if (inside.status !== 0)
|
|
44
|
+
throw new Error("git-unavailable");
|
|
45
|
+
// A repository with no commit yet has no HEAD, so nothing is tracked at HEAD.
|
|
46
|
+
headState = run(["rev-parse", "--verify", "--quiet", "HEAD"]).status === 0 ? "commit" : "no-commit";
|
|
47
|
+
return headState;
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
async trackedBlob(path) {
|
|
51
|
+
if (ensureRepository() === "no-commit")
|
|
52
|
+
return { tracked: false };
|
|
53
|
+
const result = run(["rev-parse", "--verify", "--quiet", `HEAD:${path}`]);
|
|
54
|
+
if (result.status === null)
|
|
55
|
+
throw new Error("git-unavailable");
|
|
56
|
+
const id = result.stdout.trim();
|
|
57
|
+
return result.status === 0 && BLOB_ID.test(id) ? { tracked: true, blobId: id } : { tracked: false };
|
|
58
|
+
},
|
|
59
|
+
async hashObject(content) {
|
|
60
|
+
ensureRepository();
|
|
61
|
+
const result = run(["hash-object", "--stdin"], content);
|
|
62
|
+
const id = result.stdout.trim();
|
|
63
|
+
if (result.status !== 0 || !BLOB_ID.test(id))
|
|
64
|
+
throw new Error("git-unavailable");
|
|
65
|
+
return id;
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Build the production drift inspector: resolve Bridge access, read the confirmed
|
|
71
|
+
* profile's `customized_commands` (an unconfirmed repository has none), and probe
|
|
72
|
+
* Git. Never throws; an unresolved credential or failed read is a `warn`.
|
|
73
|
+
*/
|
|
74
|
+
export function createCommandDriftInspector(options) {
|
|
75
|
+
return () => probeCommandDrift({
|
|
76
|
+
catalog: COMMANDS,
|
|
77
|
+
git: createCommandDriftGit(options.runGit ?? createGitRunner(options.cwd)),
|
|
78
|
+
fetchCustomizedCommands: async () => {
|
|
79
|
+
// Lazy: keeps the credential/HTTP graph out of the static imports, as the
|
|
80
|
+
// doctor's other credentialed inspections do.
|
|
81
|
+
const client = await import("./bridge-api-client.js");
|
|
82
|
+
const resolved = await client.resolveConductorBridgeApiAccess({
|
|
83
|
+
env: options.env,
|
|
84
|
+
cwd: options.cwd,
|
|
85
|
+
});
|
|
86
|
+
if (!resolved.ok)
|
|
87
|
+
throw new Error("profile-unavailable");
|
|
88
|
+
const read = await client.fetchConductorGateProfile(resolved.access, ((url, init) => (options.fetch ?? fetch)(url, init)));
|
|
89
|
+
return read.profile?.customized_commands ?? [];
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/** Stable row id shared by `doctor` and `readiness`. */
|
|
2
|
+
export const COMMAND_DRIFT_ROW_ID = "command-drift";
|
|
3
|
+
export const COMMAND_DRIFT_ROW_LABEL = "Committed command drift";
|
|
4
|
+
/** Group-level remedy for divergent, non-customized commands. */
|
|
5
|
+
export const COMMAND_DRIFT_DIVERGENT_REMEDIATION = "run `/upgrade-bridge` and commit the refreshed commands, or mark the command customized in the gate profile";
|
|
6
|
+
/** Remedy when the check itself could not be completed. */
|
|
7
|
+
export const COMMAND_DRIFT_UNASSESSABLE_REMEDIATION = "restore Bridge profile access and Git access for this repository, then rerun `epic-implementer doctor`";
|
|
8
|
+
const SAFE_COMMAND_FILE = /^([a-z][a-z0-9-]*)\.md$/;
|
|
9
|
+
/** The repository-relative path of a packaged command's tracked copy. */
|
|
10
|
+
export function commandDriftTrackedPath(name) {
|
|
11
|
+
return `.claude/commands/${name}.md`;
|
|
12
|
+
}
|
|
13
|
+
/** Run the probe. Never throws and never returns a `fail`. */
|
|
14
|
+
export async function probeCommandDrift(deps) {
|
|
15
|
+
let customized;
|
|
16
|
+
try {
|
|
17
|
+
customized = new Set(await deps.fetchCustomizedCommands());
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return { status: "warn", kind: "unassessable", reason: "profile-unavailable" };
|
|
21
|
+
}
|
|
22
|
+
const names = [];
|
|
23
|
+
for (const key of Object.keys(deps.catalog)) {
|
|
24
|
+
const match = SAFE_COMMAND_FILE.exec(key);
|
|
25
|
+
if (match)
|
|
26
|
+
names.push(match[1]);
|
|
27
|
+
}
|
|
28
|
+
names.sort();
|
|
29
|
+
const divergent = [];
|
|
30
|
+
const customizedDivergent = [];
|
|
31
|
+
try {
|
|
32
|
+
for (const name of names) {
|
|
33
|
+
const tracked = await deps.git.trackedBlob(commandDriftTrackedPath(name));
|
|
34
|
+
if (!tracked.tracked)
|
|
35
|
+
continue;
|
|
36
|
+
const packaged = await deps.git.hashObject(deps.catalog[`${name}.md`]);
|
|
37
|
+
if (packaged === tracked.blobId)
|
|
38
|
+
continue;
|
|
39
|
+
(customized.has(name) ? customizedDivergent : divergent).push(name);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return { status: "warn", kind: "unassessable", reason: "git-unavailable" };
|
|
44
|
+
}
|
|
45
|
+
if (divergent.length === 0)
|
|
46
|
+
return { status: "pass", customizedDivergent };
|
|
47
|
+
return { status: "warn", kind: "divergent", divergent, customizedDivergent };
|
|
48
|
+
}
|
|
49
|
+
function commandList(names) {
|
|
50
|
+
return names.map((n) => `/${n}`).join(", ");
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The ONE projection of a probe result into a report row, shared by `doctor` and
|
|
54
|
+
* `readiness` so wording, ordering and remediation are decided once. The status
|
|
55
|
+
* vocabulary is the readiness one, and only `pass` or `warn` is ever produced.
|
|
56
|
+
*/
|
|
57
|
+
export function projectCommandDriftRow(result) {
|
|
58
|
+
const base = { id: COMMAND_DRIFT_ROW_ID, label: COMMAND_DRIFT_ROW_LABEL };
|
|
59
|
+
if (result.status === "pass") {
|
|
60
|
+
return {
|
|
61
|
+
...base,
|
|
62
|
+
status: "pass",
|
|
63
|
+
detail: "committed Bridge commands match the packaged copies" +
|
|
64
|
+
(result.customizedDivergent.length > 0
|
|
65
|
+
? `; customized, not a warning: ${commandList(result.customizedDivergent)}`
|
|
66
|
+
: ""),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (result.kind === "divergent") {
|
|
70
|
+
return {
|
|
71
|
+
...base,
|
|
72
|
+
status: "warn",
|
|
73
|
+
detail: `divergent / likely stale: ${commandList(result.divergent)}` +
|
|
74
|
+
(result.customizedDivergent.length > 0
|
|
75
|
+
? `; customized, not a warning: ${commandList(result.customizedDivergent)}`
|
|
76
|
+
: ""),
|
|
77
|
+
remediation: COMMAND_DRIFT_DIVERGENT_REMEDIATION,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const reason = result.reason === "profile-unavailable"
|
|
81
|
+
? "the gate profile could not be read"
|
|
82
|
+
: "Git could not be inspected";
|
|
83
|
+
return {
|
|
84
|
+
...base,
|
|
85
|
+
status: "warn",
|
|
86
|
+
detail: `Could not check command drift: ${reason}`,
|
|
87
|
+
remediation: COMMAND_DRIFT_UNASSESSABLE_REMEDIATION,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -15,6 +15,7 @@ import { detectClaudeLogin, formatClaudeLoginAdvisory } from "../claude-login.js
|
|
|
15
15
|
import { inspectConductorGitHooks } from "./git-hooks.js";
|
|
16
16
|
import { MERGE_WORKFLOW_IDENTIFIER } from "./merge-execution-contract.js";
|
|
17
17
|
import { resolveMcpShimInvocationForRuntime, resolvePackageRootFromModuleUrl, } from "../mcp-server-invocation.js";
|
|
18
|
+
import { projectCommandDriftRow } from "./command-drift.js";
|
|
18
19
|
import { MCP_PACKAGE_NAME } from "../mcp-identity.js";
|
|
19
20
|
import { resolveProfiles } from "../mcp-profile.js";
|
|
20
21
|
import { createReadinessCheck, createReadinessCheckSafely, } from "../readiness-check.js";
|
|
@@ -694,6 +695,9 @@ export async function buildConductorDoctorReport(deps = {}) {
|
|
|
694
695
|
homedir: deps.claudeLoginDeps?.homedir ?? os.homedir,
|
|
695
696
|
readFile: deps.claudeLoginDeps?.readFile ?? ((p) => readFileAsync(p, "utf-8")),
|
|
696
697
|
});
|
|
698
|
+
const command_drift = deps.inspectCommandDrift
|
|
699
|
+
? await inspectCommandDriftSafe(deps.inspectCommandDrift)
|
|
700
|
+
: undefined;
|
|
697
701
|
return {
|
|
698
702
|
ledger,
|
|
699
703
|
git_hooks: inspectHooks(deps.hooksDeps),
|
|
@@ -704,8 +708,18 @@ export async function buildConductorDoctorReport(deps = {}) {
|
|
|
704
708
|
deny_enforcement,
|
|
705
709
|
claude_login,
|
|
706
710
|
repair_credentials: await inspectRepairVerbCredentials(deps.env ?? process.env, deps.resolveRepairAccess),
|
|
711
|
+
...(command_drift ? { command_drift } : {}),
|
|
707
712
|
};
|
|
708
713
|
}
|
|
714
|
+
/** Run the drift inspector, containing any throw as an unassessable `warn`. */
|
|
715
|
+
async function inspectCommandDriftSafe(inspect) {
|
|
716
|
+
try {
|
|
717
|
+
return await inspect();
|
|
718
|
+
}
|
|
719
|
+
catch {
|
|
720
|
+
return { status: "warn", kind: "unassessable", reason: "git-unavailable" };
|
|
721
|
+
}
|
|
722
|
+
}
|
|
709
723
|
/**
|
|
710
724
|
* Run the GitHub Actions merge inspector, containing any throw as degraded data.
|
|
711
725
|
*
|
|
@@ -822,9 +836,9 @@ export function formatConductorDoctorReport(report) {
|
|
|
822
836
|
lines.push(` - ${w}`);
|
|
823
837
|
}
|
|
824
838
|
lines.push("");
|
|
825
|
-
lines.push("Epic
|
|
826
|
-
lines.push("locally. To execute claimed jobs on this machine, run:");
|
|
827
|
-
lines.push(` npx -y ${MCP_PACKAGE_NAME} executor --repo <name>`);
|
|
839
|
+
lines.push("The Epic Implementer reconciles epics server-side — nothing to schedule");
|
|
840
|
+
lines.push("locally. To execute a run's claimed jobs on this machine, run:");
|
|
841
|
+
lines.push(` npx -y ${MCP_PACKAGE_NAME} executor --repo <name> --epic-run-id <run-id>`);
|
|
828
842
|
lines.push("");
|
|
829
843
|
lines.push("MCP Profile (optional, local)");
|
|
830
844
|
lines.push("─────────────────────────────");
|
|
@@ -940,6 +954,17 @@ export function formatConductorDoctorReport(report) {
|
|
|
940
954
|
}
|
|
941
955
|
lines.push("");
|
|
942
956
|
lines.push(formatClaudeLoginAdvisory(claude_login));
|
|
957
|
+
// BAPI-1392 — the same projected row `readiness` shows, last in both reports.
|
|
958
|
+
// Warn-only: it never changes this command's exit code.
|
|
959
|
+
if (report.command_drift) {
|
|
960
|
+
const row = projectCommandDriftRow(report.command_drift);
|
|
961
|
+
lines.push("");
|
|
962
|
+
lines.push("Committed command drift (advisory)");
|
|
963
|
+
lines.push("──────────────────────────────────");
|
|
964
|
+
lines.push(`${row.id}: ${row.status === "pass" ? "[OK]" : "[WARNING]"} ${row.detail ?? ""}`);
|
|
965
|
+
if (row.remediation)
|
|
966
|
+
lines.push(` → ${row.remediation}`);
|
|
967
|
+
}
|
|
943
968
|
return lines.join("\n");
|
|
944
969
|
}
|
|
945
970
|
// ---------------------------------------------------------------------------
|
|
@@ -1136,33 +1161,51 @@ export function mapConductorDoctorReportToReadinessChecks(report) {
|
|
|
1136
1161
|
record(outcome);
|
|
1137
1162
|
record(denyEnforcementOutcome(report));
|
|
1138
1163
|
record(claudeLoginOutcome(report));
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1164
|
+
// BAPI-1392 — appended AFTER the fixed descriptor set and only when the drift
|
|
1165
|
+
// inspection ran. It is deliberately not a descriptor: an uncollected
|
|
1166
|
+
// descriptor reports as a `fail`, and this row is warn-only by contract.
|
|
1167
|
+
const driftChecks = report?.command_drift
|
|
1168
|
+
? (() => {
|
|
1169
|
+
const row = projectCommandDriftRow(report.command_drift);
|
|
1170
|
+
return [
|
|
1171
|
+
createReadinessCheckSafely({
|
|
1172
|
+
id: `conductor.${row.id}`,
|
|
1173
|
+
source: "conductor",
|
|
1174
|
+
label: row.label,
|
|
1175
|
+
status: row.status,
|
|
1176
|
+
...(row.detail ? { detail: row.detail } : {}),
|
|
1177
|
+
...(row.remediation ? { remediation: row.remediation } : {}),
|
|
1178
|
+
}),
|
|
1179
|
+
];
|
|
1180
|
+
})()
|
|
1181
|
+
: [];
|
|
1182
|
+
return [...CONDUCTOR_READINESS_DESCRIPTORS.map(({ id, label }) => {
|
|
1183
|
+
const outcome = collected.get(id);
|
|
1184
|
+
if (!outcome) {
|
|
1185
|
+
// Unknown, and unknown is never healthy: a prerequisite whose owning
|
|
1186
|
+
// inspection did not report is a failure with a restoring remediation.
|
|
1187
|
+
return createReadinessCheck({
|
|
1188
|
+
id: `conductor.${id}`,
|
|
1189
|
+
source: "conductor",
|
|
1190
|
+
label,
|
|
1191
|
+
status: "fail",
|
|
1192
|
+
detail: CONDUCTOR_UNCOLLECTED_DETAIL,
|
|
1193
|
+
remediation: CONDUCTOR_UNCOLLECTED_REMEDIATION,
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
return createReadinessCheckSafely({
|
|
1145
1197
|
id: `conductor.${id}`,
|
|
1146
1198
|
source: "conductor",
|
|
1147
|
-
label,
|
|
1148
|
-
status:
|
|
1149
|
-
detail:
|
|
1150
|
-
|
|
1199
|
+
label: outcome.label || label,
|
|
1200
|
+
status: outcome.status,
|
|
1201
|
+
...(outcome.detail ? { detail: outcome.detail } : {}),
|
|
1202
|
+
// Same fallback as the plane adapter: a real failure must never be
|
|
1203
|
+
// downgraded into a generic "unreadable check" for want of a fix line.
|
|
1204
|
+
...(outcome.status === "fail"
|
|
1205
|
+
? { remediation: outcome.remediation ?? CONDUCTOR_UNCOLLECTED_REMEDIATION }
|
|
1206
|
+
: outcome.status !== "pass" && outcome.remediation
|
|
1207
|
+
? { remediation: outcome.remediation }
|
|
1208
|
+
: {}),
|
|
1151
1209
|
});
|
|
1152
|
-
}
|
|
1153
|
-
return createReadinessCheckSafely({
|
|
1154
|
-
id: `conductor.${id}`,
|
|
1155
|
-
source: "conductor",
|
|
1156
|
-
label: outcome.label || label,
|
|
1157
|
-
status: outcome.status,
|
|
1158
|
-
...(outcome.detail ? { detail: outcome.detail } : {}),
|
|
1159
|
-
// Same fallback as the plane adapter: a real failure must never be
|
|
1160
|
-
// downgraded into a generic "unreadable check" for want of a fix line.
|
|
1161
|
-
...(outcome.status === "fail"
|
|
1162
|
-
? { remediation: outcome.remediation ?? CONDUCTOR_UNCOLLECTED_REMEDIATION }
|
|
1163
|
-
: outcome.status !== "pass" && outcome.remediation
|
|
1164
|
-
? { remediation: outcome.remediation }
|
|
1165
|
-
: {}),
|
|
1166
|
-
});
|
|
1167
|
-
});
|
|
1210
|
+
}), ...driftChecks];
|
|
1168
1211
|
}
|