@bridge_gpt/mcp-server 0.2.31 → 0.2.32

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/build/doctor.js CHANGED
@@ -20,7 +20,7 @@ import os from "os";
20
20
  import path from "path";
21
21
  import { createDefaultStartTicketsDeps } from "./start-tickets.js";
22
22
  import { VERSION } from "./version.generated.js";
23
- import { collectInstallStatusChecks, formatInstallStatusReport, resolveInstallDoctorTarget, } from "./install-doctor.js";
23
+ import { collectInstallStatusChecks, formatInstallStatusReport, formatInstallStatusFallbackReport, resolveInstallDoctorTarget, } from "./install-doctor.js";
24
24
  import { parseDefaultOnEnvFlag } from "./env-flags.js";
25
25
  import { createBridgeApiUrls } from "./bridge-api-urls.js";
26
26
  import { probeToolSurface } from "./tool-surface-gating.js";
@@ -28,21 +28,37 @@ import { resolveBapiCredentials } from "./credential-store.js";
28
28
  import { DEFAULT_AGENT_NAME, resolveAgentSpec, isAgentName, formatValidAgentNames, } from "./agent-registry.js";
29
29
  import { getDoctorPrereqDescriptors, probePrerequisite, } from "./start-tickets-prereqs.js";
30
30
  import { resolveProfiles } from "./mcp-profile.js";
31
+ /**
32
+ * The report/usage title (BAPI-669, U9b). `doctor` diagnoses the whole Bridge
33
+ * install — install status, prerequisites, launcher cache, and tool surface — so it
34
+ * is no longer titled as a start-tickets-only tool. Defined once and shared by
35
+ * {@link getDoctorUsage} and {@link buildDoctorReportHeader} so the two cannot drift.
36
+ */
37
+ export const DOCTOR_REPORT_TITLE = "bridge doctor — read-only diagnostics";
31
38
  /** User-facing usage text for the read-only `doctor` subcommand. */
32
39
  export function getDoctorUsage() {
33
40
  return [
34
41
  "Usage:",
35
42
  " npx -y @bridge_gpt/mcp-server doctor [--agent <name>]",
36
43
  "",
37
- "Read-only diagnostics for the start-tickets CLI. It only checks your",
38
- "environment and prints manual install instructions it does not install",
39
- "anything, modify your system, or start the MCP server.",
44
+ // BAPI-669 (U9b): `doctor` is the general Bridge diagnostic command, not a
45
+ // start-tickets-only one and its report leads with install status, so the
46
+ // usage text describes it in that order too.
47
+ `${DOCTOR_REPORT_TITLE}. It only checks your environment and prints manual`,
48
+ "install instructions — it does not install anything, modify your system, or",
49
+ "start the MCP server.",
40
50
  "",
41
51
  "Flags:",
42
52
  " --agent claude|cursor-agent Agent to include in the prerequisite check (default: claude)",
43
53
  " -h, --help Show this help",
44
54
  "",
45
- "Checks (for the current OS): the start-tickets preflight prerequisites plus",
55
+ "The report opens with an advisory 'Install status' section (easy-install done",
56
+ "criteria): repo identity, credential resolution, server connectivity,",
57
+ "bootstrap-field completeness, integration credentials, and repository-indexing",
58
+ "state. It performs read-only GETs only and never affects the exit code.",
59
+ "",
60
+ "After that come the start-tickets prerequisite checks (for the current OS):",
61
+ "the start-tickets preflight prerequisites plus",
46
62
  "uv, the selected agent's command, Bridge API credential resolution, and",
47
63
  "worktree MCP registration reachability. Credential resolution reports the",
48
64
  "source it would use (env vs. store target bapi:<repo>); it never reads or",
@@ -50,11 +66,6 @@ export function getDoctorUsage() {
50
66
  "migrate a credential, use /install-bridge or the `credentials` subcommand —",
51
67
  "doctor stays strictly read-only.",
52
68
  "",
53
- "The report also includes an advisory 'Install status' section (easy-install",
54
- "done criteria): repo identity, credential resolution, server connectivity,",
55
- "bootstrap-field completeness, and repository-indexing state. It performs",
56
- "read-only GETs only and never affects the exit code.",
57
- "",
58
69
  "It also includes an advisory 'MCP tool surface' section (BAPI-641): what",
59
70
  "dynamic capability gating would advertise for this repo. It performs at most",
60
71
  "one read-only GET to /jira/mcp/tool-surface (none under the kill switch) and",
@@ -155,20 +166,31 @@ export async function collectDoctorResults(deps, agentName) {
155
166
  return { ok: true, results };
156
167
  }
157
168
  /**
158
- * Render the doctor report: platform + selected agent header, one found/missing
159
- * line per prerequisite, the exact manual install hint for each missing one
160
- * (framed as manual instructions only), and the selected agent's auth note
161
- * (especially the `cursor-agent login` reminder). Pure formatting no probing.
169
+ * The BROAD report header: title plus the run's platform / agent / profile
170
+ * metadata (BAPI-669, U9b). Split out from the prerequisite body so `runDoctorCli`
171
+ * has a clear insertion point for the Install-status section between the two — the
172
+ * ordering change is the whole point, and it must not require rewriting the
173
+ * prerequisite formatting below.
162
174
  */
163
- export function formatDoctorReport(platform, agent, collection) {
175
+ export function buildDoctorReportHeader(platform, agent) {
164
176
  const activeGroups = Array.from(resolveProfiles(process.env.BRIDGE_MCP_PROFILE)).join(", ");
165
- const lines = [
166
- "start-tickets doctor (read-only diagnostics)",
177
+ return [
178
+ DOCTOR_REPORT_TITLE,
167
179
  `Platform: ${platform}`,
168
180
  `Selected agent: ${agent.name} (command: ${agent.command})`,
169
181
  `Active MCP Groups: \`${activeGroups}\``,
170
182
  "",
171
183
  ];
184
+ }
185
+ /**
186
+ * The start-tickets PREREQUISITE section: one found/missing line per prerequisite,
187
+ * the exact manual install hint for each missing one (framed as manual instructions
188
+ * only), and the selected agent's auth note (especially the `cursor-agent login`
189
+ * reminder). Pure formatting — no probing. Byte-identical to what
190
+ * {@link formatDoctorReport} has always rendered below its header.
191
+ */
192
+ export function formatDoctorPrereqSection(platform, collection) {
193
+ const lines = [];
172
194
  if (!collection.ok) {
173
195
  lines.push(`Platform '${platform}' is unsupported. start-tickets supports darwin, win32, and linux.`);
174
196
  return lines.join("\n");
@@ -193,6 +215,17 @@ export function formatDoctorReport(platform, agent, collection) {
193
215
  lines.push("For conductor ledger/native-module diagnostics, run: conductor doctor");
194
216
  return lines.join("\n");
195
217
  }
218
+ /**
219
+ * Header + prerequisite section, composed. Retained as the single-call rendering
220
+ * used by direct callers and tests; `runDoctorCli` composes the two halves itself so
221
+ * it can slot Install status between them (BAPI-669, U9c).
222
+ */
223
+ export function formatDoctorReport(platform, agent, collection) {
224
+ return [
225
+ ...buildDoctorReportHeader(platform, agent),
226
+ formatDoctorPrereqSection(platform, collection),
227
+ ].join("\n");
228
+ }
196
229
  // ---------------------------------------------------------------------------
197
230
  // Launcher-cache diagnostics (BAPI-451 W3, E-4/E-9) — strictly read-only.
198
231
  //
@@ -504,25 +537,20 @@ export async function runDoctorCli(argv, overrides = {}) {
504
537
  const deps = overrides.deps ?? createDefaultStartTicketsDeps();
505
538
  const agent = resolveAgentSpec(parsed.options.agentName) ?? resolveAgentSpec(DEFAULT_AGENT_NAME);
506
539
  const collection = await collectDoctorResults(deps, parsed.options.agentName);
507
- log(formatDoctorReport(deps.platform, agent, collection));
508
- // Strictly read-only launcher-cache diagnostics (BAPI-451). Best-effort: a probe
509
- // failure never changes the doctor exit code (cold-start readiness is advisory,
510
- // not a hard prerequisite). The exit code remains driven by required prereqs.
511
- try {
512
- const launcherDeps = {
513
- cwd: overrides.launcherProbe?.cwd ?? deps.cwd,
514
- readFile: overrides.launcherProbe?.readFile ?? ((p) => readFile(p, "utf-8")),
515
- probeNpxNoInstall: overrides.launcherProbe?.probeNpxNoInstall ?? probeNpxNoInstallDefault,
516
- };
517
- const launcherInspections = await inspectLauncherCache(launcherDeps);
518
- log(formatLauncherCacheReport(launcherInspections));
519
- }
520
- catch {
521
- /* launcher-cache diagnostics are advisory; never block the doctor report */
522
- }
540
+ // ---- Section order (BAPI-669, U9c) ----
541
+ // Broad header Install status → start-tickets prerequisites → launcher cache →
542
+ // MCP tool surface. Install status renders FIRST and UNCONDITIONALLY: it answers
543
+ // "is this project actually set up?", which is what someone running `doctor` after
544
+ // an install is asking. There is deliberately no "invocation context" flag to gate
545
+ // the ordering on — the report has a single caller and carries no context, so
546
+ // always-first is both simpler and equivalent. The `installStatus: false` override
547
+ // remains a dependency-injection-only seam for hermetic tests; a normal CLI
548
+ // invocation never takes it.
549
+ log(buildDoctorReportHeader(deps.platform, agent).join("\n"));
523
550
  // Advisory install-status section (easy-install done criteria). Read-only GETs
524
551
  // only; any failure degrades to WARN/SKIP lines inside the section, and any
525
- // unexpected throw is swallowed the exit code is never affected.
552
+ // unexpected throw renders the sanitized fallback rather than dropping the
553
+ // report's first section — the exit code is never affected either way.
526
554
  if (overrides.installStatus !== false) {
527
555
  try {
528
556
  // Reuse fs deps injected on `deps` (doctor's credential probes place them
@@ -543,9 +571,26 @@ export async function runDoctorCli(argv, overrides = {}) {
543
571
  log(formatInstallStatusReport(checks));
544
572
  }
545
573
  catch {
546
- /* install-status diagnostics are advisory; never block the doctor report */
574
+ // Advisory, but never silently absent: the first section always renders.
575
+ log(formatInstallStatusFallbackReport());
547
576
  }
548
577
  }
578
+ log(formatDoctorPrereqSection(deps.platform, collection));
579
+ // Strictly read-only launcher-cache diagnostics (BAPI-451). Best-effort: a probe
580
+ // failure never changes the doctor exit code (cold-start readiness is advisory,
581
+ // not a hard prerequisite). The exit code remains driven by required prereqs.
582
+ try {
583
+ const launcherDeps = {
584
+ cwd: overrides.launcherProbe?.cwd ?? deps.cwd,
585
+ readFile: overrides.launcherProbe?.readFile ?? ((p) => readFile(p, "utf-8")),
586
+ probeNpxNoInstall: overrides.launcherProbe?.probeNpxNoInstall ?? probeNpxNoInstallDefault,
587
+ };
588
+ const launcherInspections = await inspectLauncherCache(launcherDeps);
589
+ log(formatLauncherCacheReport(launcherInspections));
590
+ }
591
+ catch {
592
+ /* launcher-cache diagnostics are advisory; never block the doctor report */
593
+ }
549
594
  // Advisory MCP tool-surface capability section (BAPI-641). Strictly read-only:
550
595
  // one 500 ms GET (or none, under the kill switch). Any timeout, malformed
551
596
  // response, or unexpected throw degrades to a "fail-open to full surface" line