@bridge_gpt/mcp-server 0.2.55 → 0.2.56

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/init.js CHANGED
@@ -13,6 +13,7 @@ import { writeFile, mkdir, readFile, stat } from "fs/promises";
13
13
  import path from "path";
14
14
  import os from "os";
15
15
  import { COMMANDS } from "./commands.generated.js";
16
+ import { renderCommandForHost } from "./command-host.js";
16
17
  import { CODEX_SKILLS_DIR, codexSkillAssets } from "./codex-skill-adapter.js";
17
18
  import { AGENTS } from "./agents.generated.js";
18
19
  import { DOCS } from "./docs.generated.js";
@@ -770,7 +771,7 @@ export async function runInit(cwd, options = {}) {
770
771
  await mkdir(dir, { recursive: true });
771
772
  // Per-file read/compare/write runs concurrently; outcomes are applied to the
772
773
  // Sets afterward in entry order so the summary counts are unchanged.
773
- const outcomes = await Promise.all(commandEntries.map(([filename, content]) => scaffoldFile(path.join(dir, filename), content)));
774
+ const outcomes = await Promise.all(commandEntries.map(([filename, content]) => scaffoldFile(path.join(dir, filename), renderCommandForHost(filename, content, dir === path.join(cwd, ".cursor", "commands") ? "cursor" : "claude-code"))));
774
775
  commandEntries.forEach(([filename], i) => {
775
776
  const outcome = outcomes[i];
776
777
  if (outcome === "skipped") {
@@ -530,7 +530,7 @@ export function getInstallBridgeUsage(baseUrl = DEFAULT_BAPI_BASE_URL) {
530
530
  " prompting, or spawning anything. With --invite it",
531
531
  " also never calls the exchange endpoint and never",
532
532
  " generates or stores a secret.",
533
- " --agent claude|cursor-agent Explicit launch override for the post-install",
533
+ " --agent claude|cursor-agent|codex Explicit agent choice for post-install",
534
534
  " session — it always wins, and there is NO Claude",
535
535
  " default. Without it the launch tool is derived",
536
536
  " from your selection: Claude Code opens `claude`.",
@@ -539,9 +539,11 @@ export function getInstallBridgeUsage(baseUrl = DEFAULT_BAPI_BASE_URL) {
539
539
  " session); selecting Cursor writes .cursor/mcp.json",
540
540
  " and prints how to finish by running /install-bridge",
541
541
  " in a new Cursor session. A selection whose tools have",
542
- " no agentic CLI (e.g. Copilot) likewise opens nothing",
542
+ " no supported auto-launch path (e.g. Copilot) opens nothing",
543
543
  " and prints how to finish configuring later. Passing",
544
- " --agent cursor-agent still force-spawns it.",
544
+ " --agent cursor-agent still force-spawns it. Codex",
545
+ " is accepted only for manual continuation: neither",
546
+ " this bootstrap nor start-tickets launches it yet.",
545
547
  " -h, --help Show this help.",
546
548
  "",
547
549
  "Subcommands:",
@@ -2057,7 +2059,7 @@ async function resolveDryRunHostPlatforms(deps, options) {
2057
2059
  * Launch agents install-bridge will NEVER auto-spawn from a host SELECTION, even
2058
2060
  * though their CLI exists and the host's MCP config is still written normally.
2059
2061
  *
2060
- * `cursor-agent` is excluded: its FIRST-RUN workspace-trust handshake collapses
2062
+ * `cursor-agent` and `codex` are excluded. Cursor's FIRST-RUN workspace-trust handshake collapses
2061
2063
  * under our osascript-spawned launch — the "Workspace Trust Required" dialog
2062
2064
  * renders, then the process exits before a selection registers, so configuration
2063
2065
  * never runs (reproduced on a pristine, never-trusted workspace; the identical
@@ -2065,16 +2067,20 @@ async function resolveDryRunHostPlatforms(deps, options) {
2065
2067
  * cursor-agent's own behavior on an untrusted workspace and is not something our
2066
2068
  * launch can drive, so we treat Cursor as a no-auto-launch host: selecting it
2067
2069
  * still writes `.cursor/mcp.json`, then prints the manual `/install-bridge`
2068
- * continuation (same path as Copilot/Codex/Windsurf, which have no agentic CLI).
2070
+ * continuation. Codex does have an agentic CLI, but this workflow is a Claude
2071
+ * `/install-bridge` command and its native skill is not available until after
2072
+ * the bootstrap it would be asked to run completes.
2069
2073
  * An explicit `--agent cursor-agent` override still spawns it — a deliberate,
2070
2074
  * documented power-user opt-in that bypasses this selection guard.
2071
2075
  */
2072
- const SELECTION_NON_LAUNCHABLE_AGENTS = new Set(["cursor-agent"]);
2076
+ const SELECTION_NON_LAUNCHABLE_AGENTS = new Set(["cursor-agent", "codex"]);
2077
+ /** Agents whose interactive command surface cannot run the post-install recipe yet. */
2078
+ const INSTALL_BRIDGE_UNSUPPORTED_AGENTS = new Set(["codex"]);
2073
2079
  /**
2074
2080
  * Resolve the post-install launch decision from the selected host platforms and an
2075
2081
  * OPTIONAL explicit `--agent` override (BAPI-657). Pure and total:
2076
2082
  *
2077
- * - An explicit `--agent` is an ABSOLUTE override (ratified AC-4): a valid explicit
2083
+ * - An explicit supported `--agent` is an ABSOLUTE override: a valid explicit
2078
2084
  * agent always returns `spawn(agent)`, regardless of which tools were selected —
2079
2085
  * the flag is honored even for a host outside the selection, and it bypasses the
2080
2086
  * {@link SELECTION_NON_LAUNCHABLE_AGENTS} guard below.
@@ -2089,6 +2095,9 @@ const SELECTION_NON_LAUNCHABLE_AGENTS = new Set(["cursor-agent"]);
2089
2095
  */
2090
2096
  export function resolveInstallBridgeLaunchDecision(selectedPlatforms, explicitAgent) {
2091
2097
  if (explicitAgent) {
2098
+ if (INSTALL_BRIDGE_UNSUPPORTED_AGENTS.has(explicitAgent)) {
2099
+ return { kind: "manual", reason: "unsupported-agent-workflow" };
2100
+ }
2092
2101
  return { kind: "spawn", agent: explicitAgent };
2093
2102
  }
2094
2103
  if (selectedPlatforms.length === 0) {
@@ -3871,7 +3880,9 @@ function describePlannedLaunchAgent(launch) {
3871
3880
  }
3872
3881
  return launch.reason === "empty-selection"
3873
3882
  ? "none — no tools selected"
3874
- : "none — no launchable tool selected; manual continuation is printed";
3883
+ : launch.reason === "unsupported-agent-workflow"
3884
+ ? "none — selected agent cannot run the install-bridge workflow; manual continuation is printed"
3885
+ : "none — no launchable tool selected; manual continuation is printed";
3875
3886
  }
3876
3887
  /**
3877
3888
  * The Step 5 preview lines, shared by both previews so the launch description
@@ -3923,7 +3934,9 @@ function buildLaunchStepPreview(launch) {
3923
3934
  ...githubLines,
3924
3935
  launch.reason === "empty-selection"
3925
3936
  ? "Step 5 — no agent session: no tools were selected, so nothing is configured or opened; re-run and select at least one tool."
3926
- : "Step 5 — no automatic launch: no selected tool has an agentic CLI. The deterministic setup completes and copy-pasteable /install-bridge continuation is printed (your Bridge MCP tools stay limited until configured).",
3937
+ : launch.reason === "unsupported-agent-workflow"
3938
+ ? "Step 5 — no automatic launch: the selected agent cannot run the install-bridge workflow. The deterministic setup completes and manual continuation is printed."
3939
+ : "Step 5 — no automatic launch: no selected tool can auto-launch this workflow. The deterministic setup completes and copy-pasteable /install-bridge continuation is printed (your Bridge MCP tools stay limited until configured).",
3927
3940
  ];
3928
3941
  }
3929
3942
  /**
@@ -73,7 +73,7 @@ export const MCP_HOST_TARGETS = {
73
73
  hostKind: "claude-code-json",
74
74
  vendorCli: { bin: "claude", kind: "claude-add-json" },
75
75
  launchAgent: "claude",
76
- worktreeSupported: true,
76
+ capabilities: { mcpConfiguration: true, customCommands: true, worktreeProvisioning: true, sessionSpawning: true },
77
77
  writeStrategy: "vendor-first",
78
78
  // Claude Code is always a candidate default.
79
79
  detect: () => true,
@@ -86,7 +86,7 @@ export const MCP_HOST_TARGETS = {
86
86
  displayPath: ".cursor/mcp.json",
87
87
  hostKind: "cursor-json",
88
88
  launchAgent: "cursor-agent",
89
- worktreeSupported: true,
89
+ capabilities: { mcpConfiguration: true, customCommands: true, worktreeProvisioning: true, sessionSpawning: true },
90
90
  writeStrategy: "direct",
91
91
  detect: (ctx) => ctx.exists(joinPath(ctx.cwd, ".cursor")) ||
92
92
  typeof ctx.env.CURSOR_TRACE_DIR === "string" &&
@@ -99,7 +99,7 @@ export const MCP_HOST_TARGETS = {
99
99
  relPath: ".vscode/mcp.json",
100
100
  displayPath: ".vscode/mcp.json",
101
101
  hostKind: "vscode-json",
102
- worktreeSupported: false,
102
+ capabilities: { mcpConfiguration: true, customCommands: true, worktreeProvisioning: false, sessionSpawning: false },
103
103
  writeStrategy: "direct",
104
104
  detect: (ctx) => ctx.exists(joinPath(ctx.cwd, ".vscode")),
105
105
  },
@@ -111,7 +111,10 @@ export const MCP_HOST_TARGETS = {
111
111
  displayPath: "~/.codex/config.toml",
112
112
  hostKind: "codex-toml",
113
113
  vendorCli: { bin: "codex", kind: "codex-add" },
114
- worktreeSupported: false,
114
+ launchAgent: "codex",
115
+ // The launcher injects a per-process, worktree-bound MCP table. The global
116
+ // registration remains the ordinary interactive default.
117
+ capabilities: { mcpConfiguration: true, customCommands: true, worktreeProvisioning: true, sessionSpawning: true },
115
118
  writeStrategy: "vendor-first",
116
119
  detect: (ctx) => ctx.exists(joinPath(ctx.homedir, ".codex")),
117
120
  },
@@ -122,7 +125,7 @@ export const MCP_HOST_TARGETS = {
122
125
  absPathResolver: (homedir) => joinPath(homedir, ".codeium/windsurf/mcp_config.json"),
123
126
  displayPath: "~/.codeium/windsurf/mcp_config.json",
124
127
  hostKind: "claude-code-json", // Windsurf uses the Claude-compatible JSON shape.
125
- worktreeSupported: false,
128
+ capabilities: { mcpConfiguration: true, customCommands: false, worktreeProvisioning: false, sessionSpawning: false },
126
129
  // Preserve current behavior: never auto-modify the global Windsurf file.
127
130
  writeStrategy: "manual-instructions",
128
131
  detect: (ctx) => ctx.exists(joinPath(ctx.cwd, ".windsurf")) ||
@@ -153,18 +156,22 @@ export function getHostTarget(id) {
153
156
  return isHostPlatformId(id) ? MCP_HOST_TARGETS[id] : undefined;
154
157
  }
155
158
  /**
156
- * The centrally-registered launchable agent for a host platform, or `undefined`
157
- * when the platform has no supported agentic CLI (Copilot / Codex / Windsurf).
159
+ * The centrally-registered agent identity for a host platform, or `undefined`
160
+ * when the platform has no registered agent (Copilot / Windsurf).
158
161
  * Pure projection of the registry's {@link HostTargetDefinition.launchAgent}
159
- * metadata — the single source of truth for which selected tools can open a
160
- * post-install configuration session (BAPI-657).
162
+ * metadata. Callers must check workflow-specific capabilities before launching.
161
163
  */
162
164
  export function agentForPlatform(id) {
163
165
  return MCP_HOST_TARGETS[id].launchAgent;
164
166
  }
165
- /** The two worktree-supported targets, in stable order (Claude, Cursor). */
167
+ /** Hosts whose declared workflow capability permits worktree provisioning. */
166
168
  export function getWorktreeHostTargets() {
167
- return allHostTargets().filter((t) => t.worktreeSupported);
169
+ return allHostTargets().filter((t) => t.capabilities.worktreeProvisioning);
170
+ }
171
+ /** True only when a host has every capability needed for a spawned workflow. */
172
+ export function isRunnableHostTarget(target) {
173
+ const c = target.capabilities;
174
+ return c.mcpConfiguration && c.customCommands && c.worktreeProvisioning && c.sessionSpawning && target.launchAgent !== undefined;
168
175
  }
169
176
  /** Project-scoped JSON targets (used by init, launcher-token merge, doctor). */
170
177
  export function getProjectJsonTargets() {
@@ -138,7 +138,7 @@ export function buildMcpServerEntriesForManifest(manifest, absoluteWorktreePath,
138
138
  /** Both registration files written for every provisioned worktree. */
139
139
  export function getWorktreeMcpRegistrationTargets(worktreePath, platform) {
140
140
  const api = pathApiForProvisioningPlatform(platform);
141
- return getWorktreeHostTargets().map((target) => ({
141
+ return getWorktreeHostTargets().filter((target) => target.scope === "project").map((target) => ({
142
142
  filePath: api.join(worktreePath, target.relPath),
143
143
  topLevelKey: hostAdapterForTarget(target).topLevelKey,
144
144
  }));
@@ -104,7 +104,7 @@ export function isBridgeApiShimEntry(entry, worktreeRoot) {
104
104
  * to validate.
105
105
  */
106
106
  export async function probeWorktreeMcpRegistration(worktreeRoot, deps) {
107
- const targets = getWorktreeHostTargets().map((target) => ({
107
+ const targets = getWorktreeHostTargets().filter((target) => target.scope === "project").map((target) => ({
108
108
  filePath: path.join(worktreeRoot, target.relPath),
109
109
  topLevelKey: hostAdapterForTarget(target).topLevelKey,
110
110
  }));