@bridge_gpt/mcp-server 0.2.56 → 0.2.58
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 +23 -6
- package/build/codex-bridge-profile.js +155 -0
- package/build/codex-home.js +7 -0
- package/build/codex-launch-scope.js +23 -7
- package/build/commands.generated.js +2 -2
- package/build/cursor-agent-progress.js +72 -0
- package/build/doctor.js +8 -1
- package/build/epic-implementer-bin.js +4 -4
- package/build/index.js +98 -94
- package/build/install-bridge.js +48 -1
- package/build/install-doctor.js +1 -1
- package/build/mcp-host-config.js +4 -0
- package/build/mcp-host-targets.js +3 -0
- package/build/pipelines.generated.js +4 -4
- package/build/readme.generated.js +1 -1
- package/build/start-tickets.js +95 -24
- package/build/version.generated.js +3 -3
- package/package.json +1 -1
- package/pipelines/implement-ticket.json +2 -2
- package/pipelines/review-ticket.json +1 -1
package/build/start-tickets.js
CHANGED
|
@@ -58,9 +58,11 @@ import { readFile, writeFile, mkdir, mkdtemp, stat, lstat, symlink, unlink, copy
|
|
|
58
58
|
import os from "node:os";
|
|
59
59
|
import { createHash } from "node:crypto";
|
|
60
60
|
import path from "path";
|
|
61
|
+
import { fileURLToPath } from "node:url";
|
|
62
|
+
import { validateHttpBaseUrl } from "./base-url.js";
|
|
61
63
|
import { VERSION } from "./version.generated.js";
|
|
62
64
|
import { resolveBapiCredentials, getPrimaryCredentialStorePath, } from "./credential-store.js";
|
|
63
|
-
import { MCP_PACKAGE_NAME } from "./mcp-identity.js";
|
|
65
|
+
import { LEGACY_SERVER_NAMES, MCP_PACKAGE_NAME, MCP_SERVER_NAME } from "./mcp-identity.js";
|
|
64
66
|
// BAPI-941: the shared drift diagnostic formatter. The leaf drift module imports
|
|
65
67
|
// nothing from here, so this direction stays acyclic.
|
|
66
68
|
import { formatClaudeReviewWorkflowDriftDiagnostic } from "./claude-review-workflow-drift.js";
|
|
@@ -560,7 +562,7 @@ resumeMode = false, workflow = "implement", reviewRounds,
|
|
|
560
562
|
// conductor runs always, and (BAPI-801/BAPI-847) for every plain run whose base
|
|
561
563
|
// resolved, `main` included — and threaded (BAPI-593) into the spawned workflow
|
|
562
564
|
// command.
|
|
563
|
-
baseBranch) {
|
|
565
|
+
baseBranch, bridgeApiBaseUrlOverride) {
|
|
564
566
|
if (!isSupportedStartTicketsPlatform(deps.platform)) {
|
|
565
567
|
return { ok: false, error: unsupportedPlatformMessage(deps.platform) };
|
|
566
568
|
}
|
|
@@ -571,6 +573,7 @@ baseBranch) {
|
|
|
571
573
|
// conductor-only — a plain worker's prompt stays bare and learns the base from
|
|
572
574
|
// the env plus the create-PR instruction files.
|
|
573
575
|
const prBaseBranch = resolvePrBaseBranchEnvValue(conductorEnabled, baseBranch);
|
|
576
|
+
const bridgeApiBaseUrl = bridgeApiBaseUrlOverride ?? resolveSpawnBridgeApiBaseUrl(deps.env);
|
|
574
577
|
return {
|
|
575
578
|
ok: true,
|
|
576
579
|
config: {
|
|
@@ -580,7 +583,7 @@ baseBranch) {
|
|
|
580
583
|
// falls back to the basename-derived repo name (the 403 root cause), and
|
|
581
584
|
// (BAPI-586/BAPI-801) the run base so the spawned worker opens its PR
|
|
582
585
|
// against it. The base assignment stays outermost.
|
|
583
|
-
buildAgentShellCommand: (key, worktreePath, modelAlias, launchArgs) => prependBaseBranchEnvAssignment(prependRepoNameEnvAssignment(buildAgentShellCommand(agent, key, worktreePath, platform, autoApprove, modelAlias, conductorEnabled, resumeMode, workflow, reviewRounds, baseBranch, launchArgs), repoName, platform), prBaseBranch, platform),
|
|
586
|
+
buildAgentShellCommand: (key, worktreePath, modelAlias, launchArgs) => prependBaseBranchEnvAssignment(prependRepoNameEnvAssignment(buildAgentShellCommand(agent, key, worktreePath, platform, autoApprove, modelAlias, conductorEnabled, resumeMode, workflow, reviewRounds, baseBranch, launchArgs, bridgeApiBaseUrl), repoName, platform), prBaseBranch, platform),
|
|
584
587
|
spawnTerminalTab: deps.spawnTerminalTab,
|
|
585
588
|
},
|
|
586
589
|
};
|
|
@@ -610,6 +613,51 @@ export function prependRepoNameEnvAssignment(command, repoName, platform = "darw
|
|
|
610
613
|
}
|
|
611
614
|
return `export BAPI_REPO_NAME='${shSquoteInner(repoName)}' && ${command}`;
|
|
612
615
|
}
|
|
616
|
+
/** Carry the parent's non-secret Bridge endpoint into a newly opened terminal. */
|
|
617
|
+
export function prependBridgeApiBaseUrlEnvAssignment(command, baseUrl, platform = "darwin") {
|
|
618
|
+
if (!baseUrl)
|
|
619
|
+
return command;
|
|
620
|
+
if (platform === "win32") {
|
|
621
|
+
return `$env:BAPI_BASE_URL = ${powershellSquote(baseUrl)}; ${command}`;
|
|
622
|
+
}
|
|
623
|
+
return `export BAPI_BASE_URL='${shSquoteInner(baseUrl)}' && ${command}`;
|
|
624
|
+
}
|
|
625
|
+
/** Validate before placing an endpoint in a launch script or MCP registration. */
|
|
626
|
+
export function resolveSpawnBridgeApiBaseUrl(env) {
|
|
627
|
+
const raw = env.BAPI_BASE_URL;
|
|
628
|
+
if (!raw || !raw.trim())
|
|
629
|
+
return undefined;
|
|
630
|
+
const result = validateHttpBaseUrl(raw);
|
|
631
|
+
return result.ok ? result.baseUrl : undefined;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* A shell-spawned CLI cannot see the parent MCP process's environment. Read only
|
|
635
|
+
* the non-secret endpoint from the selected host's project registration when the
|
|
636
|
+
* shell did not inherit BAPI_BASE_URL (common for Cursor launched from the GUI).
|
|
637
|
+
*/
|
|
638
|
+
export async function resolveStartTicketsBridgeApiBaseUrl(deps, agent) {
|
|
639
|
+
const inherited = resolveSpawnBridgeApiBaseUrl(deps.env);
|
|
640
|
+
if (inherited)
|
|
641
|
+
return inherited;
|
|
642
|
+
const configPath = agent.name === "cursor-agent"
|
|
643
|
+
? path.join(deps.cwd, ".cursor", "mcp.json")
|
|
644
|
+
: path.join(deps.cwd, ".mcp.json");
|
|
645
|
+
try {
|
|
646
|
+
const raw = await (deps.readFile ?? ((filePath) => readFile(filePath, "utf-8")))(configPath);
|
|
647
|
+
const parsed = JSON.parse(raw);
|
|
648
|
+
const bridge = parsed.mcpServers?.[MCP_SERVER_NAME] ?? parsed.mcpServers?.[LEGACY_SERVER_NAMES[0]];
|
|
649
|
+
if (!bridge)
|
|
650
|
+
return undefined;
|
|
651
|
+
const args = Array.isArray(bridge.args) ? bridge.args : [];
|
|
652
|
+
const flagIndex = args.indexOf("--base-url");
|
|
653
|
+
const candidate = bridge.env?.BAPI_BASE_URL ?? (flagIndex >= 0 ? args[flagIndex + 1] : undefined);
|
|
654
|
+
const validated = validateHttpBaseUrl(candidate);
|
|
655
|
+
return validated.ok ? validated.baseUrl : undefined;
|
|
656
|
+
}
|
|
657
|
+
catch {
|
|
658
|
+
return undefined;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
613
661
|
/**
|
|
614
662
|
* BAPI-801/BAPI-847: decide the `BAPI_BASE_BRANCH` value a spawned worker's shell
|
|
615
663
|
* should carry — the single rule shared by the real spawn builder
|
|
@@ -1316,7 +1364,12 @@ export function buildAgentInvocationArgv(agent, prompt, modelAlias, launchArgsOr
|
|
|
1316
1364
|
if (agent.name === "codex" && Array.isArray(launchArgsOrCursorWorkspace))
|
|
1317
1365
|
argv.push(...launchArgsOrCursorWorkspace);
|
|
1318
1366
|
if (agent.name === "cursor-agent" && typeof launchArgsOrCursorWorkspace === "string" && launchArgsOrCursorWorkspace) {
|
|
1319
|
-
|
|
1367
|
+
// Cursor's text mode can buffer the entire headless turn. Route NDJSON
|
|
1368
|
+
// through our progress renderer, which prints assistant prose and tool
|
|
1369
|
+
// names without dumping tool arguments or results into the terminal.
|
|
1370
|
+
const progressScript = fileURLToPath(new URL("./cursor-agent-progress.js", import.meta.url));
|
|
1371
|
+
argv.splice(0, 1, "node", progressScript, "--", agent.command);
|
|
1372
|
+
argv.push("-p", "--output-format", "stream-json", "--trust", "--approve-mcps", "--force", "--workspace", launchArgsOrCursorWorkspace);
|
|
1320
1373
|
}
|
|
1321
1374
|
if (agent.supportsModelOverride &&
|
|
1322
1375
|
typeof modelAlias === "string" &&
|
|
@@ -1347,14 +1400,14 @@ export function buildAgentInvocation(agent, prompt, quote, modelAlias, launchArg
|
|
|
1347
1400
|
}
|
|
1348
1401
|
}
|
|
1349
1402
|
/** POSIX agent shell command: `cd '<path>' && <agent> [--model '<alias>'] '<prompt>'`. */
|
|
1350
|
-
export function buildPosixAgentShellCommand(agent, key, worktreePath, autoApprove = false, modelAlias, conductorEnabled = false, resumeMode = false, workflow = "implement", reviewRounds, baseBranch, launchArgs = []) {
|
|
1403
|
+
export function buildPosixAgentShellCommand(agent, key, worktreePath, autoApprove = false, modelAlias, conductorEnabled = false, resumeMode = false, workflow = "implement", reviewRounds, baseBranch, launchArgs = [], bridgeApiBaseUrl) {
|
|
1351
1404
|
const invocation = buildAgentInvocation(agent, buildAgentPrompt(key, { autoApprove, conductorEnabled, resumeMode, workflow, reviewRounds, baseBranch, agentName: agent.name }), (p) => `'${shSquoteInner(p)}'`, modelAlias, agent.name === "cursor-agent" && autoApprove ? worktreePath : launchArgs);
|
|
1352
|
-
return `cd '${shSquoteInner(worktreePath)}' && ${invocation}`;
|
|
1405
|
+
return `cd '${shSquoteInner(worktreePath)}' && ${prependBridgeApiBaseUrlEnvAssignment(invocation, bridgeApiBaseUrl, "darwin")}`;
|
|
1353
1406
|
}
|
|
1354
1407
|
/** PowerShell agent shell command: `Set-Location -LiteralPath '<path>'; <agent> [--model '<alias>'] '<prompt>'`. */
|
|
1355
|
-
export function buildPowerShellAgentShellCommand(agent, key, worktreePath, autoApprove = false, modelAlias, conductorEnabled = false, resumeMode = false, workflow = "implement", reviewRounds, baseBranch, launchArgs = []) {
|
|
1408
|
+
export function buildPowerShellAgentShellCommand(agent, key, worktreePath, autoApprove = false, modelAlias, conductorEnabled = false, resumeMode = false, workflow = "implement", reviewRounds, baseBranch, launchArgs = [], bridgeApiBaseUrl) {
|
|
1356
1409
|
const invocation = buildAgentInvocation(agent, buildAgentPrompt(key, { autoApprove, conductorEnabled, resumeMode, workflow, reviewRounds, baseBranch, agentName: agent.name }), powershellSquote, modelAlias, agent.name === "cursor-agent" && autoApprove ? worktreePath : launchArgs);
|
|
1357
|
-
return `Set-Location -LiteralPath ${powershellSquote(worktreePath)}; ${invocation}`;
|
|
1410
|
+
return `Set-Location -LiteralPath ${powershellSquote(worktreePath)}; ${prependBridgeApiBaseUrlEnvAssignment(invocation, bridgeApiBaseUrl, "win32")}`;
|
|
1358
1411
|
}
|
|
1359
1412
|
/**
|
|
1360
1413
|
* Build the shell command run inside each spawned tab/session, dispatched by
|
|
@@ -1364,10 +1417,10 @@ export function buildPowerShellAgentShellCommand(agent, key, worktreePath, autoA
|
|
|
1364
1417
|
* injected as `--model` at the spawn boundary. `conductorEnabled` appends the
|
|
1365
1418
|
* BAPI-586 PR-base contract instruction to the prompt (opt-in via `--conductor`).
|
|
1366
1419
|
*/
|
|
1367
|
-
export function buildAgentShellCommand(agent, key, worktreePath, platform = "darwin", autoApprove = false, modelAlias, conductorEnabled = false, resumeMode = false, workflow = "implement", reviewRounds, baseBranch, launchArgs = []) {
|
|
1420
|
+
export function buildAgentShellCommand(agent, key, worktreePath, platform = "darwin", autoApprove = false, modelAlias, conductorEnabled = false, resumeMode = false, workflow = "implement", reviewRounds, baseBranch, launchArgs = [], bridgeApiBaseUrl) {
|
|
1368
1421
|
if (platform === "win32")
|
|
1369
|
-
return buildPowerShellAgentShellCommand(agent, key, worktreePath, autoApprove, modelAlias, conductorEnabled, resumeMode, workflow, reviewRounds, baseBranch, launchArgs);
|
|
1370
|
-
return buildPosixAgentShellCommand(agent, key, worktreePath, autoApprove, modelAlias, conductorEnabled, resumeMode, workflow, reviewRounds, baseBranch, launchArgs);
|
|
1422
|
+
return buildPowerShellAgentShellCommand(agent, key, worktreePath, autoApprove, modelAlias, conductorEnabled, resumeMode, workflow, reviewRounds, baseBranch, launchArgs, bridgeApiBaseUrl);
|
|
1423
|
+
return buildPosixAgentShellCommand(agent, key, worktreePath, autoApprove, modelAlias, conductorEnabled, resumeMode, workflow, reviewRounds, baseBranch, launchArgs, bridgeApiBaseUrl);
|
|
1371
1424
|
}
|
|
1372
1425
|
/**
|
|
1373
1426
|
* Build the shell command run inside a spawned tab/session for an ARBITRARY
|
|
@@ -2008,7 +2061,7 @@ export function getDryRunPlatformDetails(agent, platform = process.platform, env
|
|
|
2008
2061
|
// buildAgentShellCommand/buildAgentPrompt path as a real spawn. A Codex
|
|
2009
2062
|
// dry-run has no created worktree to bind, so its preview omits the
|
|
2010
2063
|
// process-local -C/-c MCP scope that the real spawn resolves later.
|
|
2011
|
-
buildAgentShellCommand: (key, worktreePath, modelAlias, launchArgs) => prependBaseBranchEnvAssignment(prependRepoNameEnvAssignment(buildAgentShellCommand(agent, key, worktreePath, platform, autoApprove, modelAlias, conductorEnabled, false, workflow, reviewRounds, baseBranch, launchArgs), repoName, platform), resolvePrBaseBranchEnvValue(conductorEnabled, baseBranch), platform),
|
|
2064
|
+
buildAgentShellCommand: (key, worktreePath, modelAlias, launchArgs) => prependBaseBranchEnvAssignment(prependRepoNameEnvAssignment(buildAgentShellCommand(agent, key, worktreePath, platform, autoApprove, modelAlias, conductorEnabled, false, workflow, reviewRounds, baseBranch, launchArgs, resolveSpawnBridgeApiBaseUrl(env)), repoName, platform), resolvePrBaseBranchEnvValue(conductorEnabled, baseBranch), platform),
|
|
2012
2065
|
};
|
|
2013
2066
|
}
|
|
2014
2067
|
/**
|
|
@@ -2017,7 +2070,7 @@ export function getDryRunPlatformDetails(agent, platform = process.platform, env
|
|
|
2017
2070
|
* the `bapi` target. Lists both registration files and the version-pinned shim
|
|
2018
2071
|
* command. Pure formatting — implies no credentials and writes no files.
|
|
2019
2072
|
*/
|
|
2020
|
-
export function buildDryRunMcpProvisioningLines(worktreePath, platform = process.platform, mcpServerInvocation) {
|
|
2073
|
+
export function buildDryRunMcpProvisioningLines(worktreePath, platform = process.platform, mcpServerInvocation, bridgeApiBaseUrl) {
|
|
2021
2074
|
const api = platform === "win32" ? path.win32 : path.posix;
|
|
2022
2075
|
const mcpJson = api.join(worktreePath, ".mcp.json");
|
|
2023
2076
|
const cursorJson = api.join(worktreePath, ".cursor", "mcp.json");
|
|
@@ -2038,6 +2091,7 @@ export function buildDryRunMcpProvisioningLines(worktreePath, platform = process
|
|
|
2038
2091
|
`DRY-RUN: ${mcpJson}`,
|
|
2039
2092
|
`DRY-RUN: ${cursorJson}`,
|
|
2040
2093
|
`DRY-RUN: ${shim}`,
|
|
2094
|
+
...(bridgeApiBaseUrl ? [`DRY-RUN: bapi shim adds --base-url ${bridgeApiBaseUrl}`] : []),
|
|
2041
2095
|
];
|
|
2042
2096
|
}
|
|
2043
2097
|
/**
|
|
@@ -2062,7 +2116,7 @@ export function buildDryRunDetailLines(agent, key, branch, platform = process.pl
|
|
|
2062
2116
|
`DRY-RUN: ${worktrunkBinary} ${wtArgs.join(" ")}`,
|
|
2063
2117
|
`DRY-RUN: ${agentInvocation}`,
|
|
2064
2118
|
...(prBaseBranch ? [`DRY-RUN: PR base: ${prBaseBranch}`] : []),
|
|
2065
|
-
...buildDryRunMcpProvisioningLines("<worktree-path>", platform, mcpServerInvocation),
|
|
2119
|
+
...buildDryRunMcpProvisioningLines("<worktree-path>", platform, mcpServerInvocation, resolveSpawnBridgeApiBaseUrl(env)),
|
|
2066
2120
|
];
|
|
2067
2121
|
}
|
|
2068
2122
|
/**
|
|
@@ -2136,13 +2190,15 @@ export function formatSummaryReport(rows) {
|
|
|
2136
2190
|
* Provisioning needs real `fs/promises` ops (not part of the command-runner DI
|
|
2137
2191
|
* boundary), but inherits the platform and cwd from the orchestration deps.
|
|
2138
2192
|
*/
|
|
2139
|
-
export function buildMcpProvisioningDeps(deps) {
|
|
2193
|
+
export function buildMcpProvisioningDeps(deps, bridgeApiBaseUrlOverride) {
|
|
2140
2194
|
return {
|
|
2195
|
+
env: deps.env,
|
|
2141
2196
|
readFile: deps.readFile ?? ((filePath) => readFile(filePath, "utf-8")),
|
|
2142
2197
|
writeFile: deps.writeFile ?? ((filePath, data) => writeFile(filePath, data, "utf-8")),
|
|
2143
2198
|
mkdir: deps.mkdir ?? ((dirPath, options) => mkdir(dirPath, options)),
|
|
2144
2199
|
platform: deps.platform,
|
|
2145
2200
|
cwd: deps.cwd,
|
|
2201
|
+
bridgeApiBaseUrl: bridgeApiBaseUrlOverride ?? resolveSpawnBridgeApiBaseUrl(deps.env),
|
|
2146
2202
|
// Resolve how the worker MCP shim launches at dispatch time from the running
|
|
2147
2203
|
// conductor's own on-disk build (absolute-build-path primary, npm-channel
|
|
2148
2204
|
// fallback) — never from process.cwd(). `nodeExecutable` is kept as "node"
|
|
@@ -3199,6 +3255,7 @@ export async function orchestrateStartTickets(deps, options, overrides = {}) {
|
|
|
3199
3255
|
// Fail-open: an unresolved name is warned about loudly but never aborts the run.
|
|
3200
3256
|
const resolveRepoNameFn = overrides.resolveRepoName ?? resolveStartTicketsRepoName;
|
|
3201
3257
|
const resolvedRepoName = await resolveRepoNameFn(deps);
|
|
3258
|
+
const bridgeApiBaseUrl = await resolveStartTicketsBridgeApiBaseUrl(deps, agent);
|
|
3202
3259
|
if (!resolvedRepoName) {
|
|
3203
3260
|
overrides.repoNameWarningLog?.("Warning: could not resolve the repo name (set BAPI_REPO_NAME or add a valid " +
|
|
3204
3261
|
".bridge/config). Spawned worktrees may fall back to the directory name and " +
|
|
@@ -3211,7 +3268,7 @@ export async function orchestrateStartTickets(deps, options, overrides = {}) {
|
|
|
3211
3268
|
// epic.base_branch override applied above) so the spawned worker gets
|
|
3212
3269
|
// BAPI_BASE_BRANCH — every conductor worker, and a plain worker whose base
|
|
3213
3270
|
// is non-default.
|
|
3214
|
-
options.baseBranch);
|
|
3271
|
+
options.baseBranch, bridgeApiBaseUrl);
|
|
3215
3272
|
if (!platformConfig.ok)
|
|
3216
3273
|
return { ok: false, error: platformConfig.error };
|
|
3217
3274
|
// BAPI-527: resolve the base start point new worktrees are cut from BEFORE any
|
|
@@ -3261,7 +3318,7 @@ export async function orchestrateStartTickets(deps, options, overrides = {}) {
|
|
|
3261
3318
|
const provisionCommandsFn = overrides.provisionCommands ??
|
|
3262
3319
|
((rows, d) => provisionCommandsForCreatedWorktrees(rows, buildCommandProvisioningDeps(d), agent.name === "codex"));
|
|
3263
3320
|
const provisionFn = overrides.provisionMcpRegistrations ??
|
|
3264
|
-
((rows, d) => provisionMcpRegistrationsForCreatedWorktrees(rows, buildMcpProvisioningDeps(d)));
|
|
3321
|
+
((rows, d) => provisionMcpRegistrationsForCreatedWorktrees(rows, buildMcpProvisioningDeps(d, bridgeApiBaseUrl)));
|
|
3265
3322
|
const materializeFn = overrides.materializeFileCredentials ?? materializeFileCredentialsForCreatedWorktrees;
|
|
3266
3323
|
const detectTerminalFn = overrides.detectTerminal ?? detectTerminal;
|
|
3267
3324
|
const spawnTabsFn = overrides.spawnTabsForCreatedWorktrees ?? spawnTabsForCreatedWorktrees;
|
|
@@ -3376,14 +3433,20 @@ export async function orchestrateStartTickets(deps, options, overrides = {}) {
|
|
|
3376
3433
|
let scoped = stampIndexScopeOnRows(routed, indexScope);
|
|
3377
3434
|
if (agent.name === "codex") {
|
|
3378
3435
|
const mcpDeps = buildMcpProvisioningDeps(deps);
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3436
|
+
// Scope resolution can refresh one shared Codex profile. Serialize these
|
|
3437
|
+
// reads and writes so sibling worktrees cannot observe a half-written update.
|
|
3438
|
+
const resolved = [];
|
|
3439
|
+
for (const row of scoped) {
|
|
3440
|
+
if (row.status !== "created" || !row.path) {
|
|
3441
|
+
resolved.push(row);
|
|
3442
|
+
continue;
|
|
3443
|
+
}
|
|
3382
3444
|
const scope = await (overrides.resolveCodexScope ?? resolveCodexLaunchScope)(row.path, mcpDeps);
|
|
3383
|
-
|
|
3445
|
+
resolved.push(scope.ok
|
|
3384
3446
|
? { ...row, codexLaunchArgs: scope.argv }
|
|
3385
|
-
: { ...row, status: "spawn-failed", error: scope.error };
|
|
3386
|
-
}
|
|
3447
|
+
: { ...row, status: "spawn-failed", error: scope.error });
|
|
3448
|
+
}
|
|
3449
|
+
scoped = resolved;
|
|
3387
3450
|
}
|
|
3388
3451
|
const rows = await spawnTabsFn(deps, scoped, terminal, platformConfig.config.buildAgentShellCommand);
|
|
3389
3452
|
return { ok: true, rows };
|
|
@@ -3427,7 +3490,7 @@ export async function runStartTicketsCli(argv, overrides = {}) {
|
|
|
3427
3490
|
return 1;
|
|
3428
3491
|
}
|
|
3429
3492
|
const options = parsed.options;
|
|
3430
|
-
const
|
|
3493
|
+
const rawDeps = overrides.deps ?? createDefaultStartTicketsDeps();
|
|
3431
3494
|
const orchestrate = overrides.orchestrate ?? orchestrateStartTickets;
|
|
3432
3495
|
// The parser validates `--agent`, so this resolves to a real spec; the guard
|
|
3433
3496
|
// is defensive only.
|
|
@@ -3436,6 +3499,14 @@ export async function runStartTicketsCli(argv, overrides = {}) {
|
|
|
3436
3499
|
errorLog(`Error: Unknown agent: '${options.agentName}'. Launchable agents: ${formatStartTicketsAgentNames()}.`);
|
|
3437
3500
|
return 1;
|
|
3438
3501
|
}
|
|
3502
|
+
// The editor's MCP registration can have a local endpoint that its Bash tool
|
|
3503
|
+
// does not inherit. Use that endpoint for the CLI's own routing as well as for
|
|
3504
|
+
// its generated worktree registration and terminal command. Never mutate the
|
|
3505
|
+
// caller's environment or read/copy its API key from the registration.
|
|
3506
|
+
const bridgeApiBaseUrl = await resolveStartTicketsBridgeApiBaseUrl(rawDeps, agent);
|
|
3507
|
+
const deps = bridgeApiBaseUrl
|
|
3508
|
+
? { ...rawDeps, env: { ...rawDeps.env, BAPI_BASE_URL: bridgeApiBaseUrl } }
|
|
3509
|
+
: rawDeps;
|
|
3439
3510
|
// BAPI-642: a malformed `--tier` value is fail-open — emit ONE concise,
|
|
3440
3511
|
// secret-free warning and continue (routing applies the premium fallback). It
|
|
3441
3512
|
// never aborts the launch or changes the numeric exit code.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// AUTO-GENERATED — do not edit manually. Regenerate with: npm run build
|
|
2
|
-
export const VERSION = "0.2.
|
|
3
|
-
export const BUILD_COMMIT = "
|
|
4
|
-
export const LAUNCHER_ARGS = ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.
|
|
2
|
+
export const VERSION = "0.2.58";
|
|
3
|
+
export const BUILD_COMMIT = "e29c3f46e4eb";
|
|
4
|
+
export const LAUNCHER_ARGS = ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.58", "serve"];
|
package/package.json
CHANGED
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
"tool": "request_plan_generation",
|
|
15
15
|
"params": {
|
|
16
16
|
"ticket_number": "{ticket_key}",
|
|
17
|
-
"wait_for_result":
|
|
17
|
+
"wait_for_result": false,
|
|
18
18
|
"save_locally": true,
|
|
19
19
|
"provider": "{provider}"
|
|
20
20
|
},
|
|
21
|
-
"description": "
|
|
21
|
+
"description": "Submit implementation-plan generation without waiting through an MCP client deadline. Re-entry-safe: the backend reuses a fresh existing plan (reused: true, no new run). force is reserved for deliberate regeneration; this step never sets it. On a dropped connection or other ambiguous submission outcome, use get_plan to inspect the existing run — never reissue this step automatically."
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"type": "agent_task",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
{
|
|
31
31
|
"type": "agent_task",
|
|
32
32
|
"id": "wait-for-ticket-review",
|
|
33
|
-
"instruction": "FIRST, check whether a review was actually submitted. The previous step runs with `on_error: warn_and_continue`, so a rejected submission (a 402, 403 or 500 from the generate endpoint, or a dropped connection) lets the pipeline continue into this step. If that step returned an error message rather than its submission confirmation or a `recovery_get` envelope, do NOT wait: nothing is running, and `wait_for_ticket_review` cannot tell \"never submitted\" from \"still running\" \u2014 it would read `pending` in every window until the caller's own timeout. Treat a failed submission as a terminal failure, report the error the previous step gave, and take the verdict contract's `revise` path.\n\nOtherwise, wait for the review submitted by the previous step to finish, using repeated BOUNDED windows.\n\nCall `wait_for_ticket_review` with `ticket_number` set to the ticket key. Each call
|
|
33
|
+
"instruction": "FIRST, check whether a review was actually submitted. The previous step runs with `on_error: warn_and_continue`, so a rejected submission (a 402, 403 or 500 from the generate endpoint, or a dropped connection) lets the pipeline continue into this step. If that step returned an error message rather than its submission confirmation or a `recovery_get` envelope, do NOT wait: nothing is running, and `wait_for_ticket_review` cannot tell \"never submitted\" from \"still running\" \u2014 it would read `pending` in every window until the caller's own timeout. Treat a failed submission as a terminal failure, report the error the previous step gave, and take the verdict contract's `revise` path.\n\nOtherwise, wait for the review submitted by the previous step to finish, using repeated BOUNDED windows.\n\nCall `wait_for_ticket_review` with `ticket_number` set to the ticket key. Each call uses the default 20-second window (set `budget_ms: 20000` explicitly if needed); do not use a longer window, because some MCP clients time out before a pending result arrives. The tool returns a JSON body with a `state` field:\n\n- `state: \"pending\"` \u2014 NORMAL and expected. The review is still running. Call the tool again immediately. Do NOT sleep, do NOT poll in a shell loop, and do NOT re-run `request_ticket_review`: re-submitting starts a second billable multi-model review and abandons the one already in flight.\n- `state: \"ready\"` \u2014 the review is over. BAPI-1121: a ready result has ALREADY persisted exactly the accepted documents and reconciled the canonical source files \u2014 it writes every leg in `saved_legs` to its canonical path and removes the stale canonical file for every leg in `withheld_legs`. Do NOT call `get_clarifying_questions` or `get_ticket_critique` after a ready result; those retrieval calls were removed from this recipe because reading them again could reintroduce exactly the stale content the wait just withheld. Treat `saved_legs` as the authoritative source set for the next steps, not file presence.\n - `freshness_basis: \"generation\"` is the normal case: `advanced_legs`/`saved_legs` are current-review evidence, proven newer than the submission. Any leg in `withheld_legs` was delivered but NOT proven current \u2014 surface its `reason` (`generation_not_advanced` or `identity_unreadable`) as a visible warning; do not describe the result as an ordinary cost-saved one-leg review when a withholding occurred. A leg in `absent_legs` with `reason: \"not_delivered\"` is an ordinary policy omission (e.g. an Easy-ticket clarify-only review) unless its status also flags it as policy-expected, in which case call that out too.\n - `freshness_basis: \"terminality_only\"` means no submission baseline was available (e.g. a resumed session) \u2014 `advanced_legs` is empty by construction and `saved_legs` was accepted on terminal delivery alone. Surface this prominently as a DEGRADED-freshness warning: the saved artifact(s) may be indistinguishable from a prior attachment, and the downstream identity-footer agreement check is the remaining backstop. Retain this warning when reporting to the next steps rather than treating a `terminality_only` ready result as equivalent to a `generation`-backed one.\n - If the result instead carries `state: \"error\"` alongside a persistence failure (an `ARTIFACT_PERSISTENCE_FAILED` `error`/`status`/`message` envelope), HALT rather than proceeding with whatever files happen to exist on disk \u2014 report the failure; the accepted legs already on disk before the failure are named in the envelope and are not lost, but nothing new was persisted for this window.\n- `state: \"error\"` \u2014 terminal. Report the `reason` and stop; the review will not complete on its own. `UPSTREAM_TERMINAL` means the review failed or expired server-side \u2014 take the verdict contract's `revise` path; do NOT open another wait window and do NOT re-run `request_ticket_review`. `INVALID_RESPONSE` means the delivered document could not be read.\n\nKeep looping on `pending` for as long as this session's own budget allows. There is no iteration cap here: the bound is the caller's \u2014 for the conductor's spec-review worker that is the existing 120-minute job timeout, which produces the ordinary liveness outcome if the review never lands. Never fabricate a verdict or a review result from a pending state.",
|
|
34
34
|
"description": "Wait for the submitted review in repeated bounded windows; a ready result has already persisted the accepted documents and reconciled the canonical files (BAPI-1121). Resumable: a pending result is a normal observation, not a failure.",
|
|
35
35
|
"on_error": "halt"
|
|
36
36
|
},
|