@bridge_gpt/mcp-server 0.2.69 → 0.2.70
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 +140 -292
- package/build/agent-launchers/claude-executor-adapter.js +17 -4
- package/build/agents.generated.js +4 -4
- package/build/artifact-diff.js +110 -0
- package/build/bin-entrypoint.js +36 -0
- package/build/bridge-permissions.js +23 -4
- package/build/claude-review-workflow-drift.js +3 -3
- package/build/codex-bridge-profile.js +1 -1
- package/build/commands.generated.js +6 -6
- package/build/conductor/bridge-api-client.js +598 -19
- package/build/conductor/bring-up-facts.js +9 -9
- package/build/conductor/doctor.js +466 -18
- package/build/conductor/epic-child-continuation.js +54 -3
- package/build/conductor/epic-implementer-cli.js +132 -34
- package/build/conductor/epic-runtime.js +2 -2
- package/build/conductor/epic-state.js +1 -1
- package/build/conductor/hook-runtime-qualification.js +1 -1
- package/build/conductor/install-doctor.js +4 -2
- package/build/conductor/launch-need-probes.js +337 -0
- package/build/conductor/local-merge.js +241 -56
- package/build/conductor/merge-credential.js +172 -0
- package/build/conductor/merge-execution-eligibility.js +1 -1
- package/build/conductor/merged-child-check.js +95 -0
- package/build/conductor/plan-trim.js +30 -0
- package/build/conductor/pr-ci-producer.js +1 -1
- package/build/conductor/readiness-cli.js +11 -6
- package/build/conductor/readiness-prerequisites.js +41 -0
- package/build/conductor/readiness-sections.js +345 -55
- package/build/conductor/readiness.js +99 -87
- package/build/conductor/recovery-cli.js +606 -21
- package/build/conductor/recovery-operations.js +306 -7
- package/build/conductor/repair-contract.js +47 -2
- package/build/conductor/repository-workflow-remedy.js +8 -6
- package/build/conductor/stored-merge-credential.js +76 -0
- package/build/conductor/stored-merge-token-probe.js +28 -0
- package/build/conductor/temporary-plan.js +50 -0
- package/build/conductor/wait-run-cli.js +759 -0
- package/build/conductor/worker-database-doctor-inspector.js +49 -0
- package/build/conductor-bin.js +2 -2
- package/build/conductor-claude-hook-bin.js +2 -2
- package/build/conductor-claude-hook-removed-stub-bin.js +2 -5
- package/build/conductor-removed-stub-bin.js +2 -5
- package/build/credential-store.js +356 -13
- package/build/docs.generated.js +26 -13
- package/build/doctor.js +94 -32
- package/build/drive-epic-help.js +212 -0
- package/build/drive-epic.js +1840 -373
- package/build/epic-ci-workflow-drift.js +77 -0
- package/build/epic-ci-workflow-install.js +183 -0
- package/build/epic-ci-workflow.js +157 -0
- package/build/epic-contract-context.js +326 -0
- package/build/epic-implementer-bin.js +57 -41
- package/build/epic-implementer-claude-hook-bin.js +2 -2
- package/build/escalation-reachability.js +134 -0
- package/build/executor/cleanup-report.js +99 -0
- package/build/executor/cli.js +12 -1
- package/build/executor/completion-contract.js +66 -11
- package/build/executor/completion-supervision.js +99 -0
- package/build/executor/delivery-outcome.js +179 -0
- package/build/executor/deps.js +3 -0
- package/build/executor/env.js +71 -0
- package/build/executor/failure-reason-codes.js +126 -0
- package/build/executor/heartbeat.js +38 -0
- package/build/executor/http-client.js +72 -0
- package/build/executor/integration-job.js +298 -5
- package/build/executor/job-errors.js +36 -6
- package/build/executor/job-runner.js +720 -36
- package/build/executor/likely-tests.js +36 -2
- package/build/executor/merge-job.js +145 -2
- package/build/executor/observation.js +73 -4
- package/build/executor/permissions.js +193 -97
- package/build/executor/preflight.js +14 -3
- package/build/executor/process-containment.js +28 -2
- package/build/executor/prompt-spec.js +50 -5
- package/build/executor/rebase-finalization.js +38 -3
- package/build/executor/reconcile-overlap-job.js +35 -7
- package/build/executor/required-work-ledger.js +236 -81
- package/build/executor/resume-pre-spawn.js +38 -1
- package/build/executor/runner.js +91 -3
- package/build/executor/test-clock.js +8 -0
- package/build/executor/types.js +37 -2
- package/build/executor/worker-cli-launcher.js +259 -0
- package/build/executor/worker-command.js +41 -4
- package/build/executor/worker-database-target.js +91 -0
- package/build/executor/worker-database.js +908 -0
- package/build/executor/worker-finalization.js +106 -0
- package/build/executor/worker-guard-hook.js +203 -0
- package/build/executor/worker-resources.js +47 -0
- package/build/executor/worker-verification-guidance.js +15 -2
- package/build/executor/worktree.js +303 -15
- package/build/executor-launch.js +11 -1
- package/build/generated-assets-doctor.js +9 -1
- package/build/generated-assets-health.js +13 -4
- package/build/generated-assets-legacy.js +39 -0
- package/build/generated-assets-paths.js +12 -1
- package/build/generated-assets-repair.js +4 -1
- package/build/generated-assets-test-support.js +12 -0
- package/build/github-remote.js +33 -0
- package/build/github-sign-in.js +62 -0
- package/build/index.js +1067 -536
- package/build/init.js +39 -1
- package/build/install-bridge-conductor-gate.js +78 -0
- package/build/install-bridge-conductor-setup.js +413 -0
- package/build/install-bridge-conductor.js +1226 -267
- package/build/install-bridge.js +376 -60
- package/build/mcp-install-state.js +8 -2
- package/build/merge-pull-request.js +6 -0
- package/build/merge-workflow-install.js +763 -345
- package/build/phase-result-artifacts.js +75 -20
- package/build/pipeline-orchestrator.js +247 -4
- package/build/pipelines.generated.js +35 -35
- package/build/plan-discovery.js +15 -2
- package/build/plan-execution-ledger.js +306 -17
- package/build/plan-phase-routing.js +48 -13
- package/build/plane/cli.js +105 -51
- package/build/plane/defaults.js +3 -0
- package/build/plane/plane-freshness.js +294 -0
- package/build/plane/schema-compatibility.js +137 -0
- package/build/plane/shutdown-deps.js +38 -0
- package/build/plane/shutdown.js +83 -8
- package/build/plane/terminal-run-cleanup.js +303 -0
- package/build/printed-remedy-commands.js +26 -4
- package/build/readiness-check.js +6 -2
- package/build/readiness-prerequisites.generated.js +532 -0
- package/build/readme.generated.js +1 -1
- package/build/setup-epic.js +400 -30
- package/build/shared-resources.generated.js +5 -0
- package/build/start-tickets.js +28 -15
- package/build/test-command-detection.js +247 -0
- package/build/test-command-validation.js +73 -0
- package/build/testing-config-client.js +150 -0
- package/build/ticket-delivery-artifacts.js +258 -0
- package/build/ticket-delivery-enrollment.js +306 -0
- package/build/ticket-delivery.js +205 -0
- package/build/ticket-review-summary.js +14 -0
- package/build/upgrade-cli.js +13 -0
- package/build/v2-readiness-requirements.js +552 -0
- package/build/version.generated.js +3 -3
- package/build/worker-guard-hook-bin.js +2 -2
- package/build/worktree-core.js +22 -7
- package/docs/BRIDGE-DIRECTORY-README.md +48 -0
- package/docs/EPIC-IMPLEMENTER-INSTALL.md +12 -867
- package/docs/EPIC-IMPLEMENTER.md +104 -63
- package/docs/epic-implementer/getting-started.md +131 -0
- package/docs/epic-implementer/self-hosting.md +133 -0
- package/package.json +3 -3
- package/pipelines/idea-to-ticket.json +1 -1
- package/pipelines/implement-ticket.json +8 -8
- package/pipelines/review-ticket.json +2 -2
- package/design-assets/favicon/favicon-32x32.png +0 -0
- package/design-assets/just-logo-rough-draft.png +0 -0
package/build/doctor.js
CHANGED
|
@@ -56,6 +56,7 @@ import { resolveProfiles } from "./mcp-profile.js";
|
|
|
56
56
|
import { executorLaunchdDirForHome, executorSystemdDirForHome, executorIdFromLaunchdFilename, executorIdFromSystemdFilename, inspectExecutorServiceArtifact, inspectExecutorServiceDurability, EXECUTOR_SERVICE_BASE_URL_ENV, } from "./executor/index.js";
|
|
57
57
|
import { DEFAULT_BAPI_BASE_URL } from "./executor/credentials.js";
|
|
58
58
|
import { detectClaudeLogin, formatClaudeLoginAdvisory } from "./claude-login.js";
|
|
59
|
+
import { checkGithubSignIn, githubSignInRemedy, } from "./github-sign-in.js";
|
|
59
60
|
import { validateBranchName } from "./base-ref.js";
|
|
60
61
|
import { readPlaneManifest } from "./plane/manifest.js";
|
|
61
62
|
import { validateTicketKey } from "./ticket-key-utils.js";
|
|
@@ -77,9 +78,9 @@ export function getDoctorUsage() {
|
|
|
77
78
|
` npx -y ${MCP_PACKAGE_NAME} doctor --stale-branch <KEY> [--stale-branch <KEY> ...] \\`,
|
|
78
79
|
" --stale-branch-base <ref> [--branch KEY=BRANCH ...]",
|
|
79
80
|
"",
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
81
|
+
// `doctor` is the general Bridge diagnostic command, not a start-tickets-only
|
|
82
|
+
// one — and its report leads with install status, so the usage text
|
|
83
|
+
// describes it in that order too.
|
|
83
84
|
`${DOCTOR_REPORT_TITLE}. It only checks your environment and prints manual`,
|
|
84
85
|
"install instructions — it does not install anything, modify your system, or",
|
|
85
86
|
"start the MCP server.",
|
|
@@ -88,16 +89,23 @@ export function getDoctorUsage() {
|
|
|
88
89
|
"Flags:",
|
|
89
90
|
" --agent claude|cursor-agent|codex Agent to include in the prerequisite check (default: claude)",
|
|
90
91
|
" --stale-branch KEY Add a ticket to the read-only stale-ticket-branch check (repeatable); requires --stale-branch-base",
|
|
91
|
-
" --stale-branch-base REF The base ref that check measures ancestry against, e.g. epic/
|
|
92
|
+
" --stale-branch-base REF The base ref that check measures ancestry against, e.g. epic/PROJ-902 (required with --stale-branch; never defaulted)",
|
|
92
93
|
" --branch KEY=BRANCH Diagnose BRANCH instead of feature/KEY for that ticket (repeatable); same override rule start-tickets uses",
|
|
94
|
+
" --advanced Also show Python and self-host diagnostics: the `uv` check and the",
|
|
95
|
+
" local plane credential section. Without it doctor runs no `uv`,",
|
|
96
|
+
" Alembic, or Python check, so it works on a repository in any language.",
|
|
93
97
|
" -h, --help Show this help",
|
|
94
98
|
"",
|
|
99
|
+
"A 'Getting started' section follows Install status: your Claude sign-in (it reads only",
|
|
100
|
+
"~/.claude.json) and your GitHub CLI sign-in (one `gh auth status`, ten seconds at most).",
|
|
101
|
+
"Each one that is not ready names its fix. It never changes the exit code.",
|
|
102
|
+
"",
|
|
95
103
|
"The report opens with an advisory 'Install status' section (easy-install done",
|
|
96
104
|
"criteria): repo identity, credential resolution, server connectivity,",
|
|
97
105
|
"bootstrap-field completeness, integration credentials, and repository-indexing",
|
|
98
106
|
"state. It performs read-only GETs only and never affects the exit code.",
|
|
99
107
|
"",
|
|
100
|
-
"Next comes an advisory 'Project identity and root' section
|
|
108
|
+
"Next comes an advisory 'Project identity and root' section: whether",
|
|
101
109
|
"each BAPI_PROJECT_ROOT (from the environment and the project MCP configs) names",
|
|
102
110
|
"a real project folder the server will use, and whether .bridge/config's",
|
|
103
111
|
"repo_name matches each project MCP config's BAPI_REPO_NAME. It only reads",
|
|
@@ -105,7 +113,7 @@ export function getDoctorUsage() {
|
|
|
105
113
|
"",
|
|
106
114
|
"After that come the start-tickets prerequisite checks (for the current OS):",
|
|
107
115
|
"the start-tickets preflight prerequisites plus",
|
|
108
|
-
"
|
|
116
|
+
"the selected agent's command (and uv with --advanced), Bridge API credential resolution, and",
|
|
109
117
|
"worktree MCP registration reachability, and a read-only check of whether the",
|
|
110
118
|
`Claude user config (~/.claude.json) registers a '${MCP_SERVER_NAME}' MCP server that`,
|
|
111
119
|
"could shadow the registration provisioned into a worker worktree. That check",
|
|
@@ -116,14 +124,8 @@ export function getDoctorUsage() {
|
|
|
116
124
|
"migrate a credential, use /install-bridge or the `credentials` subcommand —",
|
|
117
125
|
"doctor stays strictly read-only.",
|
|
118
126
|
"",
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// replaced per-job config-directory isolation with --strict-mcp-config argv
|
|
122
|
-
// scoping, and BAPI-791 deleted that doctor section together with the whole
|
|
123
|
-
// worker-auth strategy vocabulary. The section it described exists in no
|
|
124
|
-
// doctor output, so the claim is removed rather than reworded.
|
|
125
|
-
"It includes an advisory 'Worker containment' section (BAPI-1019) reporting the",
|
|
126
|
-
"DECLARED posture a conductor worker runs under: that the executor strips this",
|
|
127
|
+
"It includes an advisory 'Worker containment' section reporting the DECLARED",
|
|
128
|
+
"posture an Epic Implementer worker runs under: that the executor strips this",
|
|
127
129
|
"checkout's .env* files from a worker's worktree as the last step before spawn",
|
|
128
130
|
"(refusing to spawn with ContractError.WorkerEnvFilePresent when it cannot",
|
|
129
131
|
"confirm they are gone), that a worker's database environment names a target",
|
|
@@ -132,14 +134,13 @@ export function getDoctorUsage() {
|
|
|
132
134
|
"reports constants rather than measurements, so it never claims a live check",
|
|
133
135
|
"ran and never changes the exit code.",
|
|
134
136
|
"",
|
|
135
|
-
"MCP containment is still not reported here. A
|
|
136
|
-
"
|
|
137
|
-
"
|
|
138
|
-
"
|
|
139
|
-
"
|
|
140
|
-
"proof; see docs/claude/worker-config-isolation-drill.md.",
|
|
137
|
+
"MCP containment is still not reported here. A worker is scoped at spawn time",
|
|
138
|
+
"with `--strict-mcp-config --mcp-config <file>`, and the executor asserts that",
|
|
139
|
+
"scope per spawn from the worker's own system/init event — failing the job with",
|
|
140
|
+
"ContractError.McpSurfaceMismatch on a confirmed leak. That per-spawn assertion,",
|
|
141
|
+
"not a doctor health line, is the containment proof.",
|
|
141
142
|
"",
|
|
142
|
-
"It also includes an advisory 'Local CLI launcher' section
|
|
143
|
+
"It also includes an advisory 'Local CLI launcher' section: whether",
|
|
143
144
|
"the BAPI_MCP_CLI override is set, and whether the launcher it names can be",
|
|
144
145
|
"executed. When the override is unset, NO launcher probe runs at all. When it",
|
|
145
146
|
"is set, doctor runs that launcher exactly once with a single appended",
|
|
@@ -149,7 +150,7 @@ export function getDoctorUsage() {
|
|
|
149
150
|
"is rejected without running anything. The whole section is advisory: a",
|
|
150
151
|
"missing, malformed, or unrunnable override never changes the exit code.",
|
|
151
152
|
"",
|
|
152
|
-
"It also includes an advisory 'MCP tool surface' section
|
|
153
|
+
"It also includes an advisory 'MCP tool surface' section: what",
|
|
153
154
|
"dynamic capability gating would advertise for this repo. It performs at most",
|
|
154
155
|
"one read-only GET to /jira/mcp/tool-surface (none under the kill switch) and",
|
|
155
156
|
"is advisory/fail-open — a timeout or malformed response is reported as",
|
|
@@ -157,7 +158,7 @@ export function getDoctorUsage() {
|
|
|
157
158
|
"ignore notifications/tools/list_changed must reconnect or start a new MCP",
|
|
158
159
|
"session to observe surface changes; no project MCP config change is required.",
|
|
159
160
|
"",
|
|
160
|
-
"It also includes an advisory 'Executor provisioning' section
|
|
161
|
+
"It also includes an advisory 'Executor provisioning' section: the",
|
|
161
162
|
"generated executor service units on this host. It enumerates them read-only by",
|
|
162
163
|
"fixed convention — ~/Library/LaunchAgents/com.bridge-gpt.executor.*.plist on",
|
|
163
164
|
"macOS, ~/.config/systemd/user/bridge-gpt-executor-*.service on Linux (Windows",
|
|
@@ -168,20 +169,20 @@ export function getDoctorUsage() {
|
|
|
168
169
|
"is advisory: missing, malformed, or credential-less units never change the exit code.",
|
|
169
170
|
"",
|
|
170
171
|
"It also includes an advisory '/drive-epic-run permission rules' section",
|
|
171
|
-
"
|
|
172
|
+
"whether the project permissions.allow rules and the optional user",
|
|
172
173
|
"autoMode entries (added through /drive-epic-run or the bridge-permissions",
|
|
173
174
|
"subcommand, never by install) are PRESENT, MISSING, or DRIFTED (for",
|
|
174
175
|
"example after the BAPI_MCP_CLI launcher changed). It reads .claude/settings.local.json,",
|
|
175
176
|
"~/.claude/settings.json, and .bridge/bridge-permissions.json, writes nothing,",
|
|
176
177
|
"and never changes the exit code.",
|
|
177
178
|
"",
|
|
178
|
-
"
|
|
179
|
+
"Local ledger / native-module diagnostics (the SQLite ledger's native",
|
|
179
180
|
"binding load status and Node-version skew) live under a separate command:",
|
|
180
181
|
" epic-implementer doctor",
|
|
181
182
|
"That command is likewise strictly read-only — it does not install, rebuild,",
|
|
182
183
|
"migrate, or write ledger files.",
|
|
183
184
|
"",
|
|
184
|
-
"It also includes an OPT-IN advisory 'Stale ticket branches' section
|
|
185
|
+
"It also includes an OPT-IN advisory 'Stale ticket branches' section,",
|
|
185
186
|
"and only when you pass --stale-branch: for each named ticket it reports whether",
|
|
186
187
|
"that ticket's branch would be REFUSED by the stale-branch guard that",
|
|
187
188
|
"`start-tickets --guard-stale-branch` (and --conductor, which implies it) runs —",
|
|
@@ -195,7 +196,7 @@ export function getDoctorUsage() {
|
|
|
195
196
|
"",
|
|
196
197
|
"The 'operational advisories' section also reports RETIRED local drive helpers",
|
|
197
198
|
"(~/.local/bin/bapi-runtime-up, ~/.local/bin/bapi-drive) when they are still on",
|
|
198
|
-
"this machine
|
|
199
|
+
"this machine. That is a PATH-PRESENCE check only: doctor does not",
|
|
199
200
|
"run, read, source, chmod, or delete either file, and cannot remove them for you",
|
|
200
201
|
"— they are outside this repository, so their removal is an operator step. The",
|
|
201
202
|
"row is advisory and never changes the exit code.",
|
|
@@ -222,6 +223,7 @@ export function parseDoctorArgs(argv) {
|
|
|
222
223
|
const staleBranchKeys = [];
|
|
223
224
|
let staleBranchBase = null;
|
|
224
225
|
const staleBranchOverrides = {};
|
|
226
|
+
let advanced = false;
|
|
225
227
|
for (let i = 0; i < argv.length; i++) {
|
|
226
228
|
const arg = argv[i];
|
|
227
229
|
if (arg === "--fix" || arg.startsWith("--fix=")) {
|
|
@@ -300,6 +302,10 @@ export function parseDoctorArgs(argv) {
|
|
|
300
302
|
staleBranchOverrides[overrideKey] = branchName;
|
|
301
303
|
continue;
|
|
302
304
|
}
|
|
305
|
+
if (arg === "--advanced") {
|
|
306
|
+
advanced = true;
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
303
309
|
if (arg === "--agent" || arg.startsWith("--agent=")) {
|
|
304
310
|
let value;
|
|
305
311
|
if (arg.startsWith("--agent=")) {
|
|
@@ -354,7 +360,13 @@ export function parseDoctorArgs(argv) {
|
|
|
354
360
|
}
|
|
355
361
|
return {
|
|
356
362
|
status: "ok",
|
|
357
|
-
options: {
|
|
363
|
+
options: {
|
|
364
|
+
agentName,
|
|
365
|
+
staleBranchKeys,
|
|
366
|
+
staleBranchBase,
|
|
367
|
+
staleBranchOverrides,
|
|
368
|
+
...(advanced ? { advanced: true } : {}),
|
|
369
|
+
},
|
|
358
370
|
};
|
|
359
371
|
}
|
|
360
372
|
/**
|
|
@@ -363,13 +375,19 @@ export function parseDoctorArgs(argv) {
|
|
|
363
375
|
* missing earlier prerequisite never hides a later one. Returns a structured
|
|
364
376
|
* unsupported-platform result (no probes) for unsupported OSes; never throws.
|
|
365
377
|
*/
|
|
366
|
-
export async function collectDoctorResults(deps, agentName) {
|
|
378
|
+
export async function collectDoctorResults(deps, agentName, options = { advanced: true }) {
|
|
367
379
|
// agentName is type-guaranteed valid by the parser; resolve is defensive.
|
|
368
380
|
const agent = resolveAgentSpec(agentName) ?? resolveAgentSpec(DEFAULT_AGENT_NAME);
|
|
369
381
|
const descriptorsResult = getDoctorPrereqDescriptors(deps.platform, deps.env, agent);
|
|
370
382
|
if (!descriptorsResult.ok) {
|
|
371
383
|
return { ok: false, unsupported: true, error: descriptorsResult.error };
|
|
372
384
|
}
|
|
385
|
+
// BAPI-1461: the default view drops the Python/self-host descriptors BEFORE any
|
|
386
|
+
// probe runs, so a non-Python repository never spawns `uv`. The descriptor
|
|
387
|
+
// table itself is unchanged; `--advanced` keeps them.
|
|
388
|
+
const descriptors = options.advanced === true
|
|
389
|
+
? descriptorsResult.descriptors
|
|
390
|
+
: descriptorsResult.descriptors.filter((d) => !ADVANCED_ONLY_DESCRIPTOR_IDS.has(d.id));
|
|
373
391
|
// Augment with read-only filesystem deps so the doctor-only credential and
|
|
374
392
|
// worktree-MCP-registration probes can run. These are intentionally NOT part
|
|
375
393
|
// of StartTicketsDeps (live preflight never reads files); doctor injects them
|
|
@@ -385,11 +403,17 @@ export async function collectDoctorResults(deps, agentName) {
|
|
|
385
403
|
homedir: injected.homedir ?? os.homedir,
|
|
386
404
|
};
|
|
387
405
|
const results = [];
|
|
388
|
-
for (const descriptor of
|
|
406
|
+
for (const descriptor of descriptors) {
|
|
389
407
|
results.push(await probePrerequisite(probeDeps, descriptor));
|
|
390
408
|
}
|
|
391
409
|
return { ok: true, results };
|
|
392
410
|
}
|
|
411
|
+
/**
|
|
412
|
+
* BAPI-1461 — doctor-only descriptors shown only with `--advanced`, matched by
|
|
413
|
+
* their stable descriptor id. `uv` serves bridge-api's own Python tooling, not a
|
|
414
|
+
* customer repository.
|
|
415
|
+
*/
|
|
416
|
+
export const ADVANCED_ONLY_DESCRIPTOR_IDS = new Set(["uv"]);
|
|
393
417
|
/** The production checker, bound so it can neither read nor populate the cache. */
|
|
394
418
|
export function createDoctorVersionChecker(env) {
|
|
395
419
|
return () => checkForUpdate({ env, readCache: false, writeCache: false });
|
|
@@ -1780,6 +1804,24 @@ export function formatOperationalAdvisoryReport(diagnostic) {
|
|
|
1780
1804
|
lines.push(" runs NO command probe, repairs no scheduler, and never changes the exit code.");
|
|
1781
1805
|
return lines.join("\n");
|
|
1782
1806
|
}
|
|
1807
|
+
/**
|
|
1808
|
+
* BAPI-1461 — render the "Getting started" section: the Claude sign-in and the
|
|
1809
|
+
* GitHub CLI sign-in, each ready or with its one fix. Both are needed for a
|
|
1810
|
+
* first epic; neither line carries any value read from disk or from `gh`.
|
|
1811
|
+
*/
|
|
1812
|
+
export function formatGettingStartedReport(claude, github) {
|
|
1813
|
+
const lines = ["", "Getting started (needed for your first epic)"];
|
|
1814
|
+
lines.push(claude.detected
|
|
1815
|
+
? " ready Claude sign-in"
|
|
1816
|
+
: " needs action Claude sign-in — run `claude login`");
|
|
1817
|
+
const remedy = githubSignInRemedy(github);
|
|
1818
|
+
lines.push(remedy === null
|
|
1819
|
+
? " ready GitHub sign-in"
|
|
1820
|
+
: github === "unavailable"
|
|
1821
|
+
? ` could not verify GitHub sign-in — ${remedy}`
|
|
1822
|
+
: ` needs action GitHub sign-in — ${remedy}`);
|
|
1823
|
+
return lines.join("\n");
|
|
1824
|
+
}
|
|
1783
1825
|
/** Collect the permission-rules inspection. Reads only; never writes. */
|
|
1784
1826
|
export async function collectBridgePermissionsDiagnostic(deps) {
|
|
1785
1827
|
return inspectBridgePermissions({ cwd: deps.cwd, homeDir: deps.homeDir, env: deps.env }, { readFile: deps.readFile });
|
|
@@ -1959,7 +2001,8 @@ export async function runDoctorCli(argv, overrides = {}) {
|
|
|
1959
2001
|
}
|
|
1960
2002
|
const deps = overrides.deps ?? createDefaultStartTicketsDeps();
|
|
1961
2003
|
const agent = resolveAgentSpec(parsed.options.agentName) ?? resolveAgentSpec(DEFAULT_AGENT_NAME);
|
|
1962
|
-
const
|
|
2004
|
+
const advanced = parsed.options.advanced === true;
|
|
2005
|
+
const collection = await collectDoctorResults(deps, parsed.options.agentName, { advanced });
|
|
1963
2006
|
// ---- Section order (BAPI-669, U9c) ----
|
|
1964
2007
|
// Broad header → Install status → Project identity and root (BAPI-1318) →
|
|
1965
2008
|
// start-tickets prerequisites → launcher cache → MCP tool surface. Install status renders FIRST and UNCONDITIONALLY: it answers
|
|
@@ -2017,6 +2060,24 @@ export async function runDoctorCli(argv, overrides = {}) {
|
|
|
2017
2060
|
log(formatInstallStatusFallbackReport());
|
|
2018
2061
|
}
|
|
2019
2062
|
}
|
|
2063
|
+
// BAPI-1461: "Getting started" — the two sign-ins a first epic needs, right
|
|
2064
|
+
// after Install status. Read-only (one file read, one bounded `gh auth status`)
|
|
2065
|
+
// and advisory: it never changes the exit code. With injected deps it runs only
|
|
2066
|
+
// when its own seam is supplied, so a faked machine never reaches real `gh`.
|
|
2067
|
+
if (overrides.signIn !== false && (overrides.deps === undefined || overrides.signIn !== undefined)) {
|
|
2068
|
+
try {
|
|
2069
|
+
const injectedFs = deps;
|
|
2070
|
+
const claude = await detectClaudeLogin({
|
|
2071
|
+
homedir: overrides.signIn?.homedir ?? injectedFs.homedir ?? os.homedir,
|
|
2072
|
+
readFile: overrides.signIn?.readFile ?? injectedFs.readFile ?? ((p) => readFile(p, "utf-8")),
|
|
2073
|
+
});
|
|
2074
|
+
const github = await checkGithubSignIn(overrides.signIn?.runGh);
|
|
2075
|
+
log(formatGettingStartedReport(claude, github));
|
|
2076
|
+
}
|
|
2077
|
+
catch {
|
|
2078
|
+
log(formatGettingStartedReport({ detected: false }, "unavailable"));
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2020
2081
|
// Advisory "Project identity and root" section (BAPI-1318). Read-only: it
|
|
2021
2082
|
// validates each explicit BAPI_PROJECT_ROOT the way the server does and
|
|
2022
2083
|
// compares .bridge/config's repo_name with each project MCP config. Placed
|
|
@@ -2279,7 +2340,8 @@ export async function runDoctorCli(argv, overrides = {}) {
|
|
|
2279
2340
|
// every section above, never affects the exit code: `plane up` enforces these
|
|
2280
2341
|
// same invariants at the point where they actually block, and an ordinary MCP
|
|
2281
2342
|
// user who never runs a conductor plane should not see a failing doctor.
|
|
2282
|
-
|
|
2343
|
+
// BAPI-1461: a self-host diagnostic, so it runs only with --advanced.
|
|
2344
|
+
if (advanced && overrides.planeCredentials !== false) {
|
|
2283
2345
|
try {
|
|
2284
2346
|
const injectedFs = deps;
|
|
2285
2347
|
const planeDeps = {
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Help text for `drive-epic`, in two parts.
|
|
3
|
+
*
|
|
4
|
+
* Basic help (`-h` / `--help`) is what a customer needs to launch an epic.
|
|
5
|
+
* Advanced help (`--help-advanced`) holds the material only an owner who runs
|
|
6
|
+
* their own Bridge server needs: the local plane and its port, the composed
|
|
7
|
+
* bring-up, durable hosts, repository-wide executors, and launch profiles.
|
|
8
|
+
*
|
|
9
|
+
* This module is pure. It reads no files, resolves no credentials, opens no
|
|
10
|
+
* network connection, starts no process, and imports nothing from
|
|
11
|
+
* `drive-epic.ts`, so `parseDriveEpicArgs` can return either text before any
|
|
12
|
+
* side effect. It imports only two neutral constants.
|
|
13
|
+
*/
|
|
14
|
+
import { CONDUCTOR_DEFAULT_BASE_URL } from "./conductor/bridge-api-client.js";
|
|
15
|
+
import { PLANE_SERVER_PORT_ENV_VAR } from "./plane/types.js";
|
|
16
|
+
/** Shown on the last line of basic help. */
|
|
17
|
+
const ADVANCED_HELP_POINTER = "Owners who run their own Bridge server: drive-epic --help-advanced";
|
|
18
|
+
export function getDriveEpicUsage() {
|
|
19
|
+
return [
|
|
20
|
+
"Usage: mcp-server drive-epic [options] <EPIC>",
|
|
21
|
+
"",
|
|
22
|
+
"Launches one epic. Reads this project's readiness from Bridge API and picks",
|
|
23
|
+
"exactly one path for you — it never asks you to choose. A refusal names the",
|
|
24
|
+
"missing item and its fix, and creates nothing.",
|
|
25
|
+
"",
|
|
26
|
+
"Arguments:",
|
|
27
|
+
" <EPIC> Epic key, matches [A-Z]+-[0-9]+ (e.g. PROJ-123)",
|
|
28
|
+
"",
|
|
29
|
+
"Finding the plan: without --plan-file, drive-epic searches",
|
|
30
|
+
"{docs_dir}/epic-plans/*/epic-plan.meta.json for a file naming this epic",
|
|
31
|
+
"({\"epic_key\": \"<KEY>\"}), where docs_dir is BAPI_DOCS_DIR or docs/tmp",
|
|
32
|
+
"resolved against the Git top level. Exactly one match with a sibling",
|
|
33
|
+
"epic-plan.dag.json is used as if you had passed --plan-file, and its path is",
|
|
34
|
+
"printed before anything is created. It never guesses: no match, two or more",
|
|
35
|
+
"matches, or an unusable meta file stops with the paths it found and creates",
|
|
36
|
+
"nothing. /define-tickets writes these files; `emit-epic-implementer-bundle",
|
|
37
|
+
"finalize` writes them for a plan from /plan-epic. A supplied --plan-file",
|
|
38
|
+
"always wins.",
|
|
39
|
+
"",
|
|
40
|
+
"Branch strategy: a plan with two or more nodes defaults to a dedicated",
|
|
41
|
+
"epic/<KEY> branch. Child PRs target it, and one draft integration PR targets",
|
|
42
|
+
"the repository base branch. The flags below only override that default.",
|
|
43
|
+
"",
|
|
44
|
+
"Unattended by default: a run on an epic branch merges child PRs into that",
|
|
45
|
+
"branch on its own. The integration PR into the base branch always stays",
|
|
46
|
+
"human-gated. Pass --attended to opt out. An unattended run needs consent",
|
|
47
|
+
"(on by default, switched on the Setup page of the Bridge admin panel), an",
|
|
48
|
+
"escalation channel (a verified notify webhook or your account email), and",
|
|
49
|
+
"confirmed review and CI workflows on the default branch. Readiness lists each",
|
|
50
|
+
"with its state, and a missing one is refused by name before a run is created.",
|
|
51
|
+
"",
|
|
52
|
+
"Every run gets an executor: once the run is created, drive-epic starts one in",
|
|
53
|
+
"the background from this checkout's Git top level. It claims only that run's",
|
|
54
|
+
"jobs, logs to .bridge/executors/<run>.log, and exits when the run is done.",
|
|
55
|
+
"Running again for the same live run starts no second one. If it fails to",
|
|
56
|
+
"start, the run is left intact and the log path and the command to start it",
|
|
57
|
+
"by hand are printed.",
|
|
58
|
+
"",
|
|
59
|
+
"Run it from a Git work tree inside the target repository. Preconditions are",
|
|
60
|
+
"checked, never repaired: each failure names the fix. Fix it and rerun.",
|
|
61
|
+
"",
|
|
62
|
+
"Options:",
|
|
63
|
+
" --plan-file <path> Plan DAG sidecar. Optional: without it, drive-epic finds",
|
|
64
|
+
" the plan by epic key (see above).",
|
|
65
|
+
" --repo <name> Repo name (default: BAPI_REPO_NAME or .bridge/config)",
|
|
66
|
+
" --feature-branch <name> Override the derived epic/<KEY> name. Forwarded",
|
|
67
|
+
" verbatim, never interpreted here.",
|
|
68
|
+
" --into-base Opt out of the epic-branch default: children target the",
|
|
69
|
+
" repository base branch. Cannot be combined with",
|
|
70
|
+
" --feature-branch.",
|
|
71
|
+
" --attended Opt out of the unattended default. Forwarded verbatim to",
|
|
72
|
+
" setup, which owns what it composes.",
|
|
73
|
+
"",
|
|
74
|
+
"Policy (forwarded verbatim; drive-epic interprets none of it):",
|
|
75
|
+
" --policy-file <path> JSON file holding the COMPLETE run policy.",
|
|
76
|
+
" --review-policy <src> Per-run review policy source.",
|
|
77
|
+
" --replace-policy Authorize replacing a LIVE run's stored policy.",
|
|
78
|
+
" --verification-handoff proceed|block",
|
|
79
|
+
" The owner's verification hand-off choice for a NEW run.",
|
|
80
|
+
" --verification-handoff-exception <TICKET>:<e2e_tests|rendered_ui_review>",
|
|
81
|
+
" Repeatable. With `block`, keeps verification a blocker",
|
|
82
|
+
" for that ticket and class.",
|
|
83
|
+
"",
|
|
84
|
+
"Target:",
|
|
85
|
+
" --base-url <url> Explicit Bridge API target. Without it, BAPI_BASE_URL is",
|
|
86
|
+
` used; with neither, drive-epic targets production`,
|
|
87
|
+
` (${CONDUCTOR_DEFAULT_BASE_URL}) and uses the stored`,
|
|
88
|
+
" bapi:<repo> key when one is available. A stored key",
|
|
89
|
+
" approved for a different endpoint is never sent.",
|
|
90
|
+
"",
|
|
91
|
+
"Preview:",
|
|
92
|
+
" --dry-run Read-only launch preview. Resolves the target, reads",
|
|
93
|
+
" readiness and the epic's live run, discovers the plan,",
|
|
94
|
+
" and runs setup's own dry-run validation. It shows what a",
|
|
95
|
+
" real run WOULD do (create a run, reuse the epic's live run,",
|
|
96
|
+
" refuse, or stop) and creates nothing. Exit 0 when it would",
|
|
97
|
+
" create or reuse a run, 1 when it would refuse or stop.",
|
|
98
|
+
" --json With --dry-run only: print exactly one JSON document on",
|
|
99
|
+
" stdout and nothing else. Alone, it is a parse error.",
|
|
100
|
+
"",
|
|
101
|
+
"Already-merged children: when a NEW run is created, drive-epic leaves out plan",
|
|
102
|
+
"children that are provably already merged. A child with a merged PR but no",
|
|
103
|
+
"delivery record is only 'probably done' and runs unless you confirm it.",
|
|
104
|
+
"Anything uncertain runs. Skipped children are recorded for audit only.",
|
|
105
|
+
" --keep-child <KEY> Repeatable. Run this child even if it is already merged.",
|
|
106
|
+
" --skip-child <KEY> Repeatable. Leave this child out. Refused unless the",
|
|
107
|
+
" child is currently done or probably done.",
|
|
108
|
+
" --no-merged-check Do not look for already-merged children. Cannot be",
|
|
109
|
+
" combined with --skip-child.",
|
|
110
|
+
"",
|
|
111
|
+
" -h, --help Show this help",
|
|
112
|
+
" --help-advanced Show the owner-only options",
|
|
113
|
+
"",
|
|
114
|
+
ADVANCED_HELP_POINTER,
|
|
115
|
+
].join("\n");
|
|
116
|
+
}
|
|
117
|
+
export function getDriveEpicAdvancedUsage() {
|
|
118
|
+
return [
|
|
119
|
+
"Usage: mcp-server drive-epic [options] <EPIC> (advanced help)",
|
|
120
|
+
"",
|
|
121
|
+
"Owner-only material for people who run their own Bridge server, or who host",
|
|
122
|
+
"epic launches on a durable machine. Hosted customers do not need any of it:",
|
|
123
|
+
"see `drive-epic --help` for the normal launch options.",
|
|
124
|
+
"",
|
|
125
|
+
"Reconciler liveness is read from the deployment's heartbeat. Against a target",
|
|
126
|
+
"that is not this machine's local plane (production, say), drive-epic never",
|
|
127
|
+
"touches a local plane: a target with no live reconciler is refused by name.",
|
|
128
|
+
"",
|
|
129
|
+
"Composed bring-up: with --plan-file, drive-epic starts the Epic Implementer",
|
|
130
|
+
"runtime for you against the local plane endpoint, when readiness is missing",
|
|
131
|
+
"ONLY the reconciler. It brings up the CONTROL PLANE first (server and",
|
|
132
|
+
"reconciler), creates and approves the run, then starts executor lanes SCOPED",
|
|
133
|
+
"to that run, and starts the dead-man observer last — one invocation, no",
|
|
134
|
+
"manual `plane up` first. A report missing supervisor setup, supervisor",
|
|
135
|
+
"configuration, GitHub App credentials, or an unattended prerequisite is NOT",
|
|
136
|
+
"started: those are owner-owned, and drive-epic exits with that one named",
|
|
137
|
+
"reason instead.",
|
|
138
|
+
"",
|
|
139
|
+
"The plane port: with --plan-file and BAPI_BASE_URL naming the local plane",
|
|
140
|
+
`endpoint (127.0.0.1, port ${PLANE_SERVER_PORT_ENV_VAR} or the default),`,
|
|
141
|
+
"drive-epic handles the port one of three ways, and never asks you to choose:",
|
|
142
|
+
" - cold start: nothing listens there — it brings the plane up, then creates",
|
|
143
|
+
" the run;",
|
|
144
|
+
" - attach: this repository's own healthy plane is there — it creates the run",
|
|
145
|
+
" against that plane and starts NO second server or reconciler;",
|
|
146
|
+
" - refusal: anything else holds the port (another listener, a manifest for a",
|
|
147
|
+
" different repository, an unreadable manifest, a plane that cannot take a",
|
|
148
|
+
" run) — one named reason, and nothing is started.",
|
|
149
|
+
"One epic per plane — for its LANES: a plane's lanes serve the one run it is",
|
|
150
|
+
"bound to. A second run attaches to the same plane's reconciler and gets its own",
|
|
151
|
+
"run-scoped executor instead. A plane whose bound run cannot be read is refused",
|
|
152
|
+
"as plane-already-bound. Concurrent planes on one database are not supported.",
|
|
153
|
+
"Executor lanes and run-scoped executors are always scoped to the one run with",
|
|
154
|
+
"--epic-run-id, on every path.",
|
|
155
|
+
"",
|
|
156
|
+
"Run-scoped executors and durable hosts: a durable launch profile starts no",
|
|
157
|
+
"run-scoped executor. It requires a fresh --repo-wide executor instead, which",
|
|
158
|
+
"covers the repository. A plane's own lane is that run's executor, so none is",
|
|
159
|
+
"started beside it. Checks that need no run happen FIRST, so a refusal before",
|
|
160
|
+
"the run is created creates nothing.",
|
|
161
|
+
"",
|
|
162
|
+
"A live run beside a FOUND plan: when the epic already has a live run and the",
|
|
163
|
+
"plan came from discovery rather than --plan-file, drive-epic attaches to the",
|
|
164
|
+
"live run first. The found plan is reported as \"Found, unused\", is not treated",
|
|
165
|
+
"as approved input, and its file is left untouched. A plan you pass with",
|
|
166
|
+
"--plan-file keeps its create-path behavior unchanged.",
|
|
167
|
+
"",
|
|
168
|
+
"A live run with no plan: when the epic already has a live run and no plan was",
|
|
169
|
+
"supplied or found, drive-epic does not create anything. It makes sure that run",
|
|
170
|
+
"has an executor (reusing a live one, never starting a second) and shows it. A",
|
|
171
|
+
"durable launch profile starts none and relies on its host's confirmed",
|
|
172
|
+
"repo-wide executor; a plane already bound to the run needs none. An epic with",
|
|
173
|
+
"several active runs, or a run that cannot be read, is refused by name.",
|
|
174
|
+
"",
|
|
175
|
+
"Repository-wide executors: `install conductor --executor-id <id> --repo-wide`",
|
|
176
|
+
"provisions a persistent executor that claims jobs for every run in the",
|
|
177
|
+
"repository. A durable host needs one before it can launch.",
|
|
178
|
+
"",
|
|
179
|
+
"Launch target — decided BEFORE any authenticated request:",
|
|
180
|
+
" --launch-profile <name> Select the host-local launch profile guided setup",
|
|
181
|
+
" approved (`install conductor --launch-profile <name>`):",
|
|
182
|
+
" target, repository, mode, runtime, and policy and",
|
|
183
|
+
" credential references. Useful for a local or other",
|
|
184
|
+
" non-production server and for durable hosts.",
|
|
185
|
+
" --base-url <url> Explicit Bridge API target. With a profile it must",
|
|
186
|
+
" agree with it — an override never rebinds a profile.",
|
|
187
|
+
"BAPI_EPIC_LAUNCH_PROFILE selects a host-local launch profile for epic",
|
|
188
|
+
"launches. --launch-profile takes precedence. For an environment-selected",
|
|
189
|
+
"profile, BAPI_BASE_URL remains the general CLI endpoint and does not",
|
|
190
|
+
"conflict with the epic launch target; --base-url still must agree.",
|
|
191
|
+
"Without either, BAPI_BASE_URL is used. With none of the three, drive-epic",
|
|
192
|
+
`targets production (${CONDUCTOR_DEFAULT_BASE_URL}) and uses the`,
|
|
193
|
+
"stored bapi:<repo> key when one is available. A stored key approved for a",
|
|
194
|
+
"different endpoint is never sent; an unapproved key is sent only to",
|
|
195
|
+
"production.",
|
|
196
|
+
"",
|
|
197
|
+
"Local-plane freshness:",
|
|
198
|
+
" Before a launch CREATES a run on this machine's plane, drive-epic checks that the",
|
|
199
|
+
" plane's pinned snapshot is not behind origin/main and that the database is at the",
|
|
200
|
+
" migration head. A CONFIRMED problem refuses before any setup or run creation; evidence",
|
|
201
|
+
" it cannot read is a warning. Attaching to a run that already exists only warns.",
|
|
202
|
+
" --allow-stale-plane Override for ONE invocation: bypasses only those two",
|
|
203
|
+
" refusals. It repairs nothing, is not persisted, and does not",
|
|
204
|
+
" bypass readiness, authentication, ownership, or admission.",
|
|
205
|
+
" Valid with or without --dry-run.",
|
|
206
|
+
" --dry-run may run `git fetch` (it updates remote-tracking refs) but changes no checkout",
|
|
207
|
+
" contents, plane configuration, database state, or run state.",
|
|
208
|
+
"",
|
|
209
|
+
" -h, --help Show the basic help",
|
|
210
|
+
" --help-advanced Show this help",
|
|
211
|
+
].join("\n");
|
|
212
|
+
}
|