@bridge_gpt/mcp-server 0.2.57 → 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.
@@ -58,6 +58,7 @@ 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";
61
62
  import { validateHttpBaseUrl } from "./base-url.js";
62
63
  import { VERSION } from "./version.generated.js";
63
64
  import { resolveBapiCredentials, getPrimaryCredentialStorePath, } from "./credential-store.js";
@@ -1363,7 +1364,12 @@ export function buildAgentInvocationArgv(agent, prompt, modelAlias, launchArgsOr
1363
1364
  if (agent.name === "codex" && Array.isArray(launchArgsOrCursorWorkspace))
1364
1365
  argv.push(...launchArgsOrCursorWorkspace);
1365
1366
  if (agent.name === "cursor-agent" && typeof launchArgsOrCursorWorkspace === "string" && launchArgsOrCursorWorkspace) {
1366
- argv.push("-p", "--output-format", "text", "--trust", "--approve-mcps", "--force", "--workspace", launchArgsOrCursorWorkspace);
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);
1367
1373
  }
1368
1374
  if (agent.supportsModelOverride &&
1369
1375
  typeof modelAlias === "string" &&
@@ -3427,14 +3433,20 @@ export async function orchestrateStartTickets(deps, options, overrides = {}) {
3427
3433
  let scoped = stampIndexScopeOnRows(routed, indexScope);
3428
3434
  if (agent.name === "codex") {
3429
3435
  const mcpDeps = buildMcpProvisioningDeps(deps);
3430
- scoped = await Promise.all(scoped.map(async (row) => {
3431
- if (row.status !== "created" || !row.path)
3432
- return row;
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
+ }
3433
3444
  const scope = await (overrides.resolveCodexScope ?? resolveCodexLaunchScope)(row.path, mcpDeps);
3434
- return scope.ok
3445
+ resolved.push(scope.ok
3435
3446
  ? { ...row, codexLaunchArgs: scope.argv }
3436
- : { ...row, status: "spawn-failed", error: scope.error };
3437
- }));
3447
+ : { ...row, status: "spawn-failed", error: scope.error });
3448
+ }
3449
+ scoped = resolved;
3438
3450
  }
3439
3451
  const rows = await spawnTabsFn(deps, scoped, terminal, platformConfig.config.buildAgentShellCommand);
3440
3452
  return { ok: true, rows };
@@ -1,4 +1,4 @@
1
1
  // AUTO-GENERATED — do not edit manually. Regenerate with: npm run build
2
- export const VERSION = "0.2.57";
3
- export const BUILD_COMMIT = "dcfa5632b4eb";
4
- export const LAUNCHER_ARGS = ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.57", "serve"];
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bridge_gpt/mcp-server",
3
- "version": "0.2.57",
3
+ "version": "0.2.58",
4
4
  "description": "Bridge API MCP server — exposes Jira endpoints as MCP tools for Claude Code agents",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -14,11 +14,11 @@
14
14
  "tool": "request_plan_generation",
15
15
  "params": {
16
16
  "ticket_number": "{ticket_key}",
17
- "wait_for_result": true,
17
+ "wait_for_result": false,
18
18
  "save_locally": true,
19
19
  "provider": "{provider}"
20
20
  },
21
- "description": "Generate implementation plan. Re-entry-safe: a non-forced request against a fresh existing plan returns reused: true and runs nothing new — the expected fast path on recovery re-entry. force is reserved for deliberate regeneration; this step never sets it. On a GATEWAY_TIMEOUT/504 response, poll get_plan (or the response's recovery_get URL) until a terminal result — never reissue this step."
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 occupies at most 240 seconds and 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.",
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
  },