@bridge_gpt/mcp-server 0.2.46 → 0.2.49

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.
Files changed (39) hide show
  1. package/README.md +101 -85
  2. package/build/agent-capabilities/default-deps.js +2 -2
  3. package/build/agent-launchers/claude.js +10 -19
  4. package/build/agent-launchers/cursor.js +4 -12
  5. package/build/agent-launchers/prompt.js +117 -0
  6. package/build/commands.generated.js +16 -22
  7. package/build/conduct-epic/bridge-client.js +73 -0
  8. package/build/conduct-epic/cli.js +152 -6
  9. package/build/conductor/cli.js +6 -7
  10. package/build/conductor/doctor.js +13 -116
  11. package/build/conductor/tools.js +18 -349
  12. package/build/conductor-bin.js +6 -30
  13. package/build/docs.generated.js +1 -1
  14. package/build/executor/deps.js +1 -0
  15. package/build/executor/service-lifecycle.js +6 -6
  16. package/build/executor/service-unit.js +13 -16
  17. package/build/index.js +214 -755
  18. package/build/init.js +15 -17
  19. package/build/install-doctor.js +1 -1
  20. package/build/learn-tool-gating.js +283 -0
  21. package/build/mcp-profile.js +13 -3
  22. package/build/mcp-server-invocation.js +14 -0
  23. package/build/pipelines.generated.js +19 -139
  24. package/build/platform-escaping.js +72 -0
  25. package/build/readme.generated.js +1 -1
  26. package/build/review-tickets.js +1 -1
  27. package/build/run-unit-tests-launcher.js +0 -1
  28. package/build/sfcc/register.js +41 -31
  29. package/build/sfcc/registration-inventory.js +44 -20
  30. package/build/start-tickets-conductor.js +2 -2
  31. package/build/start-tickets.js +8 -38
  32. package/build/version.generated.js +2 -2
  33. package/docs/CONDUCTOR.md +10 -12
  34. package/docs/install/mcp-tool-integrations.md +9 -55
  35. package/package.json +1 -1
  36. package/pipelines/idea-to-ticket.json +2 -2
  37. package/pipelines/review-ticket.json +9 -8
  38. package/pipelines/check-ci-ticket.json +0 -36
  39. package/pipelines/pr-ticket.json +0 -24
@@ -87,7 +87,7 @@ export function formatBaseFetchFailureBox(baseBranch, error) {
87
87
  const title = "review-tickets: base-branch fetch failed";
88
88
  // The box always shows a dedicated Remediation line below. fetchAndResolveBaseSha's
89
89
  // own error text embeds the same remediation clause because it also has to stand
90
- // alone when surfaced outside a box (e.g. raw JSON from materialize_fresh_base) —
90
+ // alone when surfaced outside a box (e.g. raw JSON from fresh_base) —
91
91
  // strip it here so the boxed rendering doesn't say it twice.
92
92
  const reason = error
93
93
  .replace(/\s*Check your network and 'git remote get-url origin', or pass --no-refresh-base to skip\.?\s*$/i, "")
@@ -59,7 +59,6 @@ export const MODULE_MOCK_MANIFEST = [
59
59
  "build/conductor/security-regressions.test.js",
60
60
  "build/conductor/store-lifecycle.test.js",
61
61
  "build/conductor/store-queries.test.js",
62
- "build/conductor/tools-done-gate.test.js",
63
62
  "build/conductor/tools.test.js",
64
63
  "build/connect-github-api.test.js",
65
64
  "build/connect-github-dispatch.static.test.js",
@@ -14,8 +14,8 @@
14
14
  * exactly one place — `registerSfccTool`, the adapter below — and every other
15
15
  * registration in this module and in every child registrar goes through that
16
16
  * adapter. So the resolved-hostname sandbox check runs for all twenty tools:
17
- * the two always-on diagnostics, the eight reads (including the five with no
18
- * `instance` parameter at all), the nine writes, and `sfcc_log_query`. Asking
17
+ * the two diagnostics, the eight reads (including the five with no `instance`
18
+ * parameter at all), the nine writes, and `sfcc_log_query`. Asking
19
19
  * each handler to remember a check is what produced the unguarded reads in the
20
20
  * first place; wrapping the registrar removes the opportunity to forget.
21
21
  *
@@ -45,8 +45,10 @@ import { registerSfccLogQueryTool } from "./log-query.js";
45
45
  *
46
46
  * Call this once in index.ts, immediately after `registerConductorTools(registerTool)`.
47
47
  * Read and write surfaces are selected independently by `deps.includeReadTools`
48
- * and `deps.includeWriteTools`; the two always-on diagnostics register
49
- * regardless. Every path goes through `registerSfccTool`.
48
+ * and `deps.includeWriteTools`. Since BAPI-912 NO SFCC tool registers
49
+ * unconditionally: the two diagnostics belong to the read profile, so a session
50
+ * selecting neither group gets zero SFCC tools. Every path goes through
51
+ * `registerSfccTool`.
50
52
  */
51
53
  export function registerSfccTools(registerTool, deps) {
52
54
  const gateDeps = {
@@ -63,34 +65,42 @@ export function registerSfccTools(registerTool, deps) {
63
65
  * passed to a child registrar — `registration-boundary.test.ts` pins that.
64
66
  */
65
67
  const registerSfccTool = (name, config, handler) => registerTool(name, config, withSfccTargetBoundary(handler));
66
- // sfcc_setup_status aggregate prerequisite reporter.
67
- registerSfccTool("sfcc_setup_status", {
68
- description: "Report on every SFCC prerequisite: Bridge API key, repo name, version config, " +
69
- "dw.json presence/uniqueness, and AM token acquisition. Always-registered; " +
70
- "returns status without requiring full SFCC configuration to be complete.",
71
- inputSchema: z.object({}),
72
- annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
73
- }, buildSfccSetupStatusHandler(deps.buildGetUrl, deps.getGetHeaders, deps.repoName, deps.getResolvedApiKey));
74
- // check_permissions OCAPI access probe + settings JSON printer.
75
- const gatedCheckPermissions = withSfccGate(gateDeps, async (_args, credentials) => checkPermissionsTool(credentials));
76
- registerSfccTool("check_permissions", {
77
- description: "Probe SFCC OCAPI access via GET /system_object_definitions. " +
78
- "On 200: reports OK and the detected OCAPI version. " +
79
- "On 401/403: prints the exact OCAPI Settings JSON to paste in Business Manager " +
80
- "(read/search and mutation grants).",
81
- inputSchema: z.object({
82
- instance: z
83
- .string()
84
- .min(1)
85
- .optional()
86
- .describe("Sandbox hostname to use instead of dw.json. Still sandbox-validated."),
87
- }),
88
- annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
89
- }, gatedCheckPermissions);
90
- // The read profile — eight OCAPI reads plus sfcc_log_query — is gated behind
91
- // ACTIVE_GROUPS.has("sfcc") (BAPI-453). sfcc_setup_status and
92
- // check_permissions above remain always-on (D-4 decision).
68
+ // The read profile is gated behind ACTIVE_GROUPS.has("sfcc") (BAPI-453):
69
+ // the two diagnostics, the eight OCAPI reads, and sfcc_log_query.
70
+ //
71
+ // BAPI-912 (decision D1) moved sfcc_setup_status and check_permissions into
72
+ // this branch. They used to register unconditionally, which put ~187 tokens of
73
+ // SFCC surface on every non-SFCC session. The accepted consequence is that a
74
+ // non-SFCC session can no longer self-diagnose why SFCC tools are absent —
75
+ // `doctor` covers that — and, because `sfcc-write` does not imply `sfcc`
76
+ // (BAPI-817), an sfcc-write-only session does not get check_permissions.
77
+ // Registration order within this branch is load-bearing: the two diagnostics
78
+ // come first, then the eight OCAPI reads, then sfcc_log_query.
93
79
  if (deps.includeReadTools) {
80
+ // sfcc_setup_status — aggregate prerequisite reporter.
81
+ registerSfccTool("sfcc_setup_status", {
82
+ description: "Report on every SFCC prerequisite: Bridge API key, repo name, version config, " +
83
+ "dw.json presence/uniqueness, and AM token acquisition. " +
84
+ "Returns status without requiring full SFCC configuration to be complete.",
85
+ inputSchema: z.object({}),
86
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
87
+ }, buildSfccSetupStatusHandler(deps.buildGetUrl, deps.getGetHeaders, deps.repoName, deps.getResolvedApiKey));
88
+ // check_permissions — OCAPI access probe + settings JSON printer.
89
+ const gatedCheckPermissions = withSfccGate(gateDeps, async (_args, credentials) => checkPermissionsTool(credentials));
90
+ registerSfccTool("check_permissions", {
91
+ description: "Probe SFCC OCAPI access via GET /system_object_definitions. " +
92
+ "On 200: reports OK and the detected OCAPI version. " +
93
+ "On 401/403: prints the exact OCAPI Settings JSON to paste in Business Manager " +
94
+ "(read/search and mutation grants).",
95
+ inputSchema: z.object({
96
+ instance: z
97
+ .string()
98
+ .min(1)
99
+ .optional()
100
+ .describe("Sandbox hostname to use instead of dw.json. Still sandbox-validated."),
101
+ }),
102
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
103
+ }, gatedCheckPermissions);
94
104
  // system_object_list, system_object_get, system_object_attribute_search (BAPI-401 T1–T3)
95
105
  registerSystemObjectReadTools(registerSfccTool, {
96
106
  gateDeps,
@@ -11,17 +11,36 @@
11
11
  * worth of drift that no test caught (BAPI-816).
12
12
  *
13
13
  * `includeReadTools` is the legacy `SfccHostDeps` flag name (`register.ts`).
14
- * Since BAPI-817 it gates the READ profile only the eight OCAPI reads plus
15
- * the log-query toolwhile `includeWriteTools` independently gates the nine
16
- * writes. The name predates both surfaces and was kept for call-site stability.
14
+ * Since BAPI-817 it gates the READ profile only, and since BAPI-912 that profile
15
+ * also owns the two diagnosticsso it is now the two diagnostics, the eight
16
+ * OCAPI reads, and the log-query tool while `includeWriteTools` independently
17
+ * gates the nine writes. The name predates every one of those surfaces and was
18
+ * kept for call-site stability.
19
+ *
20
+ * BAPI-912 note: there is no longer any unconditionally registered SFCC tool. A
21
+ * session selecting neither group registers ZERO of the twenty names below. The
22
+ * former `SFCC_ALWAYS_REGISTERED_TOOL_NAMES` export is gone rather than renamed
23
+ * in place, because a constant whose name asserts unconditional registration is
24
+ * exactly the kind of drift BAPI-816 created this module to prevent.
17
25
  */
18
26
  import { SFCC_WRITE_TOOL_NAMES } from "./writes.js";
19
27
  /**
20
- * Registered unconditionally, regardless of `includeReadTools` (D-4 decision
21
- * in register.ts): the aggregate prerequisite reporter and the OCAPI access
22
- * probe.
28
+ * The two SFCC diagnostic tools: the aggregate prerequisite reporter and the
29
+ * OCAPI access probe.
30
+ *
31
+ * These registered unconditionally until BAPI-912 (decision D1) moved them into
32
+ * the `sfcc` READ profile. They are still worth naming as a pair — they are the
33
+ * only two SFCC tools that report on configuration rather than acting on an
34
+ * instance — but membership is now a property of `SFCC_READ_PROFILE_TOOL_NAMES`,
35
+ * where they are composed in first, matching registration order in `register.ts`.
36
+ *
37
+ * Consequence worth stating once here as well as in the README: because
38
+ * `sfcc-write` does not imply `sfcc` (BAPI-817), an `sfcc-write`-only session
39
+ * registers the nine mutation tools but NEITHER diagnostic — including
40
+ * `check_permissions`, which is what prints the mutation-grant OCAPI Settings
41
+ * JSON on a 401/403. Diagnosing write grants requires `sfcc,sfcc-write`.
23
42
  */
24
- export const SFCC_ALWAYS_REGISTERED_TOOL_NAMES = [
43
+ export const SFCC_DIAGNOSTIC_TOOL_NAMES = [
25
44
  "sfcc_setup_status",
26
45
  "check_permissions",
27
46
  ];
@@ -43,15 +62,17 @@ export const SFCC_READ_TOOL_NAMES = [
43
62
  /** The on-demand redacted/filtered log-query tool (BAPI-556 T7). */
44
63
  export const SFCC_LOG_QUERY_TOOL_NAME = "sfcc_log_query";
45
64
  /**
46
- * The `sfcc` READ profile: the eight OCAPI reads plus the log-query tool
47
- * (BAPI-817).
65
+ * The `sfcc` READ profile: the two diagnostics, the eight OCAPI reads, and the
66
+ * log-query tool (BAPI-817, extended by BAPI-912).
48
67
  *
49
- * This is the exact set `includeReadTools` registers. Every member is read-only
50
- * and carries read-only annotations; by construction no tool annotated
51
- * `WRITE_ANNOTATIONS` can appear here, which is what makes "enabling `sfcc`
52
- * cannot enable a mutation" checkable rather than merely intended.
68
+ * This is the exact set `includeReadTools` registers, in registration order.
69
+ * Every member is read-only and carries read-only annotations; by construction
70
+ * no tool annotated `WRITE_ANNOTATIONS` can appear here, which is what makes
71
+ * "enabling `sfcc` cannot enable a mutation" checkable rather than merely
72
+ * intended.
53
73
  */
54
74
  export const SFCC_READ_PROFILE_TOOL_NAMES = [
75
+ ...SFCC_DIAGNOSTIC_TOOL_NAMES,
55
76
  ...SFCC_READ_TOOL_NAMES,
56
77
  SFCC_LOG_QUERY_TOOL_NAME,
57
78
  ];
@@ -67,23 +88,26 @@ export const SFCC_WRITE_PROFILE_TOOL_NAMES = [
67
88
  /**
68
89
  * Every profile-gated tool, across both groups.
69
90
  *
70
- * Retained as the aggregate for consumers that care about "gated vs always-on"
71
- * rather than which group gates it but composed from the two profile
72
- * inventories above, never hand-maintained. Order matches registration order in
73
- * `register.ts`: the read branch runs first, then the write branch.
91
+ * Since BAPI-912 every SFCC tool is profile-gated, so this is the complete
92
+ * inventory and `SFCC_ALL_REGISTERED_TOOL_NAMES` below is an alias for it, kept
93
+ * because consumers read the two names to mean different questions. Composed
94
+ * from the two profile inventories above, never hand-maintained. Order matches
95
+ * registration order in `register.ts`: the read branch runs first (diagnostics,
96
+ * then the OCAPI reads, then the log query), and then the write branch.
74
97
  */
75
98
  export const SFCC_PROFILE_GATED_TOOL_NAMES = [
76
99
  ...SFCC_READ_PROFILE_TOOL_NAMES,
77
100
  ...SFCC_WRITE_PROFILE_TOOL_NAMES,
78
101
  ];
79
102
  /**
80
- * The complete SFCC registration surface: always-on plus both gated profiles.
103
+ * The complete SFCC registration surface: both gated profiles.
81
104
  *
82
105
  * This is the twenty-tool surface a `BRIDGE_MCP_PROFILE=sfcc,sfcc-write` (or
83
106
  * `full`) session exposes, and the iteration source for the boundary-coverage
84
- * test — so a newly added tool cannot silently evade that coverage.
107
+ * test — so a newly added tool cannot silently evade that coverage. Every name
108
+ * appears exactly once: since BAPI-912 the diagnostics are composed solely
109
+ * through the read profile, so there is no unconditional prefix to double-count.
85
110
  */
86
111
  export const SFCC_ALL_REGISTERED_TOOL_NAMES = [
87
- ...SFCC_ALWAYS_REGISTERED_TOOL_NAMES,
88
112
  ...SFCC_PROFILE_GATED_TOOL_NAMES,
89
113
  ];
@@ -135,8 +135,8 @@ const CONDUCTOR_TUNING_ENV_KEYS = [
135
135
  "BAPI_CONDUCTOR_BUSY_TIMEOUT_MS",
136
136
  "BAPI_CONDUCTOR_RETENTION_DAYS",
137
137
  "BAPI_CONDUCTOR_RETENTION_MAX_ROWS",
138
- // BAPI-397: per-type relay cooldown — forwarded only when explicitly set so a
139
- // worker's check_messages cooldown probe matches the supervisor's send config.
138
+ // BAPI-397: per-type relay cooldown — forwarded only when explicitly set so
139
+ // the supervisor's send config is honoured by the conductor store it writes to.
140
140
  "BAPI_CONDUCTOR_MESSAGE_COOLDOWN_MS",
141
141
  ];
142
142
  /** Truthy predicate for opt-in conductor boolean flags (`1` / `true`). */
@@ -132,7 +132,7 @@ export function getStartTicketsUsage() {
132
132
  " --base-branch BRANCH Cut new worktrees from BRANCH and refresh origin/BRANCH (default: main)",
133
133
  " --no-refresh-main Skip refresh of the configured base branch (default main); historical name retained for backward compatibility",
134
134
  " --max-parallel N Max worktrees to create concurrently (default: 3)",
135
- " --conductor Enable the Conductor system: per-worker hook injection + BAPI_CONDUCTOR_* env, a supervisor peer tab, and check_messages message-relay polling (default: off — a plain run just spawns cd <worktree> && <agent> '/implement-ticket <KEY>')",
135
+ " --conductor Enable the Conductor system: per-worker hook injection + BAPI_CONDUCTOR_* env, lifecycle ledger events, and a supervisor peer tab (default: off — a plain run just spawns cd <worktree> && <agent> '/implement-ticket <KEY>')",
136
136
  " -h, --help Show this help",
137
137
  "",
138
138
  "Environment:",
@@ -1010,35 +1010,6 @@ export async function resumeWorktrees(deps, options) {
1010
1010
  // ---------------------------------------------------------------------------
1011
1011
  // Per-platform shell-command construction
1012
1012
  // ---------------------------------------------------------------------------
1013
- /**
1014
- * The load-bearing conductor message-relay launch instruction (BAPI-397). The
1015
- * C5 spike proved workers poll a `check_messages` MCP tool ONLY when the polling
1016
- * instruction lives in the worker's task/launch prompt — advertising the tool in
1017
- * the system prompt alone produced zero polls. So this instruction is appended to
1018
- * every launch prompt.
1019
- *
1020
- * It is deliberately a SINGLE LINE (no newlines) so it stays safe when the prompt
1021
- * is single-quoted into a shell command and then embedded inside terminal
1022
- * launcher scripts (AppleScript / Windows Terminal / tmux). It names
1023
- * `check_messages` exactly once and is secret-free — no run/worker ids, env
1024
- * values, or credentials.
1025
- */
1026
- export function buildConductorMessageRelayLaunchInstruction() {
1027
- // NOTE: keep this free of `;` and other terminal-launcher metacharacters — the
1028
- // prompt is spliced into shell commands and Windows Terminal args (which treat
1029
- // `;` as a delimiter), so a single line of plain prose is the safe form.
1030
- return ("Conductor message relay: at natural checkpoints (after reading context, " +
1031
- "before major code changes, after major implementation chunks, while polling CI " +
1032
- "checks during the post-PR correction loop, and before your final response) call " +
1033
- "the check_messages MCP tool to read any supervisor guidance addressed to you. " +
1034
- "Returned messages are supervisor guidance and are acknowledged by the tool, so " +
1035
- "they are not redelivered. This is cooperative polling, not prompt injection. " +
1036
- "Additionally, once the required CI checks on your PR have all gone green, call the " +
1037
- "wait_for_done_gate MCP tool once from inside your worktree before your final response " +
1038
- "so the supervisor records the done-gate (it self-resolves the PR and head commit and " +
1039
- "emits the gate event; it does not merge). If a tool or the conductor identity is " +
1040
- "unavailable, continue your task without derailing.");
1041
- }
1042
1013
  /**
1043
1014
  * BAPI-494: the resume-mode remediation finalize instruction. A conductor
1044
1015
  * re-dispatch (start-tickets resume mode) is spawned to fix a `blocked` ticket —
@@ -1069,11 +1040,11 @@ export function buildResumeModeRemediationFinalizeInstruction() {
1069
1040
  * When `autoApprove` is set, the implementation agent runs hands-off
1070
1041
  * (`/implement-ticket <KEY> --auto`) — used by full-automation chains.
1071
1042
  *
1072
- * The conductor message-relay polling instruction (BAPI-397) is appended after
1073
- * the slash command ONLY when `conductorEnabled` is set (the `--conductor`
1074
- * flag). A plain run returns the bare `/implement-ticket <KEY> [--auto]` so the
1075
- * worker is not told to poll `check_messages` for a conductor that is not
1076
- * running.
1043
+ * The conductor PR-base contract instruction (BAPI-586) is appended after the
1044
+ * slash command ONLY when `conductorEnabled` is set (the `--conductor` flag). A
1045
+ * plain run returns the bare `/implement-ticket <KEY> [--auto]`; BAPI-909
1046
+ * removed the worker mailbox/done-gate MCP tools, so no polling prose is
1047
+ * appended in either mode.
1077
1048
  *
1078
1049
  * BAPI-494: when `resumeMode` is set (a conductor remediation re-dispatch), the
1079
1050
  * full-suite finalize instruction is appended so the rebase/resolve worker proves
@@ -1099,7 +1070,6 @@ export function buildAgentPrompt(key, opts = {}) {
1099
1070
  }
1100
1071
  const parts = [command];
1101
1072
  if (opts.conductorEnabled) {
1102
- parts.push(buildConductorMessageRelayLaunchInstruction());
1103
1073
  // BAPI-586: conductor implementation workers must open their PR against the
1104
1074
  // run base (injected as BAPI_BASE_BRANCH), never the repo default branch.
1105
1075
  // The launch INSTRUCTION stays conductor-only. BAPI-801 gave plain runs the
@@ -1164,7 +1134,7 @@ export function buildPowerShellAgentShellCommand(agent, key, worktreePath, autoA
1164
1134
  * dry-run fallback). The selected `agent` (never a module-level constant)
1165
1135
  * determines the launched command. An optional validated `modelAlias` is
1166
1136
  * injected as `--model` at the spawn boundary. `conductorEnabled` appends the
1167
- * BAPI-397 message-relay instruction to the prompt (opt-in via `--conductor`).
1137
+ * BAPI-586 PR-base contract instruction to the prompt (opt-in via `--conductor`).
1168
1138
  */
1169
1139
  export function buildAgentShellCommand(agent, key, worktreePath, platform = "darwin", autoApprove = false, modelAlias, conductorEnabled = false, resumeMode = false, workflow = "implement", reviewRounds, baseBranch) {
1170
1140
  if (platform === "win32")
@@ -1533,7 +1503,7 @@ export async function spawnUnsupportedPlatformTerminalTab(deps, _terminal, _shel
1533
1503
  * Why launch via a script file instead of embedding the command in the spawn?
1534
1504
  *
1535
1505
  * Each worker command grew from ~100 chars to >1 KB once the conductor identity
1536
- * env (BAPI-394) and the message-relay launch instruction (BAPI-397) were added.
1506
+ * env (BAPI-394) and the conductor launch instructions were added.
1537
1507
  * On macOS that whole string is escaped into an AppleScript literal and injected
1538
1508
  * via a `keystroke "t"` (Cmd-T) new-tab dance — a delivery path that is
1539
1509
  * length-, quoting-, and timing-sensitive (a long command racing a not-yet-ready
@@ -1,3 +1,3 @@
1
1
  // AUTO-GENERATED — do not edit manually. Regenerate with: npm run build
2
- export const VERSION = "0.2.46";
3
- export const BUILD_COMMIT = "9e67d5495def";
2
+ export const VERSION = "0.2.49";
3
+ export const BUILD_COMMIT = "ccff42dd5212";
package/docs/CONDUCTOR.md CHANGED
@@ -15,7 +15,7 @@ config. For the everyday `start-tickets` flags and cross-platform behavior, see
15
15
  **The v1 `conductor epic-tick` command is frozen.** It throws
16
16
  `EPIC_TICK_V1_FROZEN` on every invocation and advances nothing. There is nothing
17
17
  to schedule locally. If you have an epic-tick schedule registered from an earlier
18
- release, cancel it (`schedule-run cancel --id <id>`) — it is a dead timer.
18
+ release, remove it — it is a dead timer.
19
19
  `conductor doctor` flags one if it finds it.
20
20
 
21
21
  v2 splits the old local tick into two halves:
@@ -231,9 +231,8 @@ committed ref updates).
231
231
 
232
232
  Missing hooks do **not** prevent PR/CI gate evaluation — `conductor doctor` reads
233
233
  hook presence and managed-snippet status **read-only** (a new `git hooks` section /
234
- `git_hooks` JSON object alongside the ledger report), and the `wait_for_done_gate`
235
- MCP tool drives CI polling and gate evaluation regardless of whether hooks are
236
- installed.
234
+ `git_hooks` JSON object alongside the ledger report), and the reconciler drives CI
235
+ polling and gate evaluation regardless of whether hooks are installed.
237
236
 
238
237
  ## Supervisor config — where the done gate and auto-merge live
239
238
 
@@ -339,10 +338,10 @@ reports `already_merged` if the merge landed.
339
338
 
340
339
  ## Durable execution environment hardening (BAPI-527)
341
340
 
342
- Worker ledger tools are made **reliable again** — this is a robustness fix for the
343
- worker-facing tools, **not** a new primary completion backstop. The done gate and
344
- supervisor remain the authority; this change only stops the worker's own
345
- `check_messages` / `wait_for_done_gate` calls from failing.
341
+ Worker ledger operations are made **reliable again** — this is a robustness fix for
342
+ the worker-facing path, **not** a new primary completion backstop. The done gate and
343
+ supervisor remain the authority; this change only stops the worker's own ledger calls
344
+ from failing.
346
345
 
347
346
  **The invariant.** Worker-facing ledger operations run through `conductor-bin.js`
348
347
  executed **under the captured conductor Node** (`CONDUCTOR_NODE_PATH`). **The worker
@@ -382,10 +381,9 @@ the worker shell env injected at the spawn boundary and is **not** persisted int
382
381
  BAPI-527 adds three independent reliability guarantees. Each is a protective
383
382
  default; none changes the interactive (non-conductor) `start-tickets` contract.
384
383
 
385
- 1. **Ledger operations are isolated from the worker path.** Worker `check_messages`
386
- / `wait_for_done_gate` run the ledger op in a subprocess under
387
- `CONDUCTOR_NODE_PATH` (details above), so a Node ABI mismatch degrades a worker
388
- convenience, never the whole session.
384
+ 1. **Ledger operations are isolated from the worker path.** Worker-facing ledger
385
+ operations run in a subprocess under `CONDUCTOR_NODE_PATH` (details above), so a
386
+ Node ABI mismatch degrades a worker convenience, never the whole session.
389
387
 
390
388
  2. **Dispatch does not alter your branch.** Unattended/epic dispatch is
391
389
  **non-mutating**: it resolves the base with a fetch-only
@@ -81,25 +81,20 @@ These are never gated (`NEVER_GATED_ROUTE_KEYS`) or run entirely locally.
81
81
 
82
82
  | Tool | Dependencies (class) |
83
83
  |---|---|
84
- | `ping` | — none |
84
+ | `ping` | — none (also reports `docs_dir`, `role`, and `customer_type`) |
85
85
  | `get_project_standards` | — none |
86
- | `get_my_role` | — none |
87
86
  | `invite_member` | — none (mints a scoped key in the Bridge DB; admin-only) |
88
- | `resolve_target_status` | — none (status resolution over the repo's configured mapping) |
89
87
  | `config_field` (get/update/list) | — none |
90
88
  | `get_install_manifest` | — none |
91
89
  | `apply_install_manifest` | — none |
92
90
  | `persist_routing_credential` | — none (`LOCAL`) |
93
- | `get_docs_dir` | — none (`LOCAL`) |
94
- | `get_parse_status` | — none |
95
91
  | `track_ticket` | — none (Bridge DB tracking record) |
96
92
  | `update_ticket_state` | — none (Bridge DB) |
97
93
  | `get_ticket_state` | — none (Bridge DB) |
98
94
  | `get_ticket_state_tree` | — none (Bridge DB; live projection over existing rows) |
99
- | `get_ticket_model_tier` | — none (Bridge DB difficulty) |
100
95
  | `get_pipeline_recipe` | — none (`LOCAL`, bundled recipes) |
101
96
  | `generate_decision_page` | — none (`LOCAL` HTML) |
102
- | `cleanup_fresh_base` | — none (`LOCAL`) |
97
+ | `fresh_base` (`action: "cleanup"`) | — none (`LOCAL`) |
103
98
 
104
99
  ### Ticket CRUD — ticket backend
105
100
 
@@ -114,7 +109,6 @@ external integration.
114
109
  | `get_ticket` | Ticket backend **[BLOCK in jira mode]** |
115
110
  | `update_ticket_description` | Ticket backend **[BLOCK in jira mode]** |
116
111
  | `update_jira_status` | Ticket backend **[BLOCK in jira mode]** (local sets a fixed status) |
117
- | `get_jira_transitions` | Ticket backend **[BLOCK in jira mode]** (local returns fixed statuses) |
118
112
 
119
113
  Jira-only — no local-mode equivalent (comment threads and binary attachments are out of
120
114
  scope for local v1):
@@ -137,7 +131,6 @@ by tier.
137
131
  | Tool (request / retrieve) | Dependencies (class) |
138
132
  |---|---|
139
133
  | `request_plan_generation` / `get_plan` | Ticket backend [BLOCK in jira mode] · VCS **[BLOCK]** · Code index **[BLOCK]** |
140
- | `request_architecture` / `get_architecture` | Ticket backend [BLOCK in jira mode] · VCS **[BLOCK]** · Code index **[BLOCK]** |
141
134
  | `request_reimplement_context` / `get_reimplement_context` | Ticket backend [BLOCK in jira mode] · VCS **[BLOCK]** · Code index **[BLOCK]** |
142
135
  | `create_doc` / `get_doc` — `doc_type` ∈ {tdd, architecture} | Ticket backend [BLOCK in jira mode] · VCS **[BLOCK]** · Code index **[BLOCK]** |
143
136
 
@@ -145,10 +138,7 @@ by tier.
145
138
 
146
139
  | Tool (request / retrieve) | Dependencies (class) |
147
140
  |---|---|
148
- | `request_clarifying_questions` / `get_clarifying_questions` | Ticket backend [BLOCK in jira mode] · VCS **[DEGRADE]** · Code index **[DEGRADE]** |
149
- | `request_ticket_critique` / `get_ticket_critique` | Ticket backend [BLOCK in jira mode] · VCS **[DEGRADE]** · Code index **[DEGRADE]** |
150
141
  | `request_ticket_review` | Ticket backend [BLOCK in jira mode] · VCS **[DEGRADE]** · Code index **[DEGRADE]** |
151
- | `request_prd` / `get_prd` | Ticket backend [BLOCK in jira mode] · VCS **[DEGRADE]** · Code index **[DEGRADE]** |
152
142
  | `create_doc` / `get_doc` — `doc_type` ∈ {prd, fsd} | Ticket backend [BLOCK in jira mode] · VCS **[DEGRADE]** · Code index **[DEGRADE]** |
153
143
 
154
144
  **Estimation:**
@@ -182,7 +172,7 @@ by tier.
182
172
  | `merge_pull_request` | VCS **[BLOCK]** (Tier-1; protected server-decided merge) + local `gh` login **[BLOCK]** (the merge executes here — see below) |
183
173
  | `resolve_ci_checks` | VCS **[BLOCK]** (Tier-1) |
184
174
  | `poll_ci_checks` | VCS **[BLOCK]** (Tier-1); also **hidden until `ci_check_config` is resolved** (needs a prior `resolve_ci_checks`) |
185
- | `materialize_fresh_base` | VCS / git base ref **[BLOCK]** (Tier-1; materializes a pinned base tree) |
175
+ | `fresh_base` (`action: "materialize"`) | VCS / git base ref **[BLOCK]** (Tier-1; materializes a pinned base tree) |
186
176
 
187
177
  #### `merge_pull_request` — what the caller can observe
188
178
 
@@ -232,51 +222,15 @@ Constraints worth knowing before calling it:
232
222
  authoritative, so a tool-side pass followed by a server refusal is expected for a
233
223
  legacy approved comment that carries no head proof.
234
224
 
235
- ### Full-automation (composite)
236
-
237
- These orchestrate an idea → ticket → review → start chain, so they inherit the
238
- **strictest** dependency of every child step.
239
-
240
- | Tool | Dependencies (class) |
241
- |---|---|
242
- | `run_full_automation` | Ticket backend [BLOCK in jira mode] · VCS **[BLOCK]** · Code index **[BLOCK]** (via child plan/review steps) |
243
- | `resume_full_automation` | Same as `run_full_automation` |
244
-
245
- ---
246
-
247
- ## `pipeline-authoring` profile
248
-
249
- Profile-gated **[BLOCK]** to register at all. `run_pipeline` / `resume_pipeline`
250
- additionally inherit the dependencies of whatever steps the invoked pipeline runs
251
- (e.g. the `implement-ticket` pipeline pulls in ticket-backend + VCS + code-index deps).
252
- Run state is persisted via the Bridge API.
253
-
254
- | Tool | Dependencies (class) |
255
- |---|---|
256
- | `list_pipelines` | Profile-gated **[BLOCK]** |
257
- | `run_pipeline` | Profile-gated **[BLOCK]** · inherits invoked pipeline's step deps |
258
- | `resume_pipeline` | Profile-gated **[BLOCK]** · inherits invoked pipeline's step deps |
259
- | `list_pipeline_runs` | Profile-gated **[BLOCK]** |
260
- | `delete_pipeline_run` | Profile-gated **[BLOCK]** |
261
-
262
- ---
263
-
264
225
  ## `conductor` profile
265
226
 
266
- Profile-gated **[BLOCK]** to register. Most operate on the **local** conductor ledger
267
- (`~/.config/bridge/events.db`), so beyond the profile gate they have no remote
268
- integration dependency.
227
+ Profile-gated **[BLOCK]** to register. The local conductor ledger
228
+ (`~/.config/bridge/events.db`) is now driven by the `conductor` CLI and the git hooks
229
+ rather than by MCP tools, so only the epic snapshot remains registered here.
269
230
 
270
231
  | Tool | Dependencies (class) |
271
232
  |---|---|
272
- | `emit_event` | Profile-gated **[BLOCK]**; else `LOCAL` ledger |
273
- | `poll_events` | Profile-gated **[BLOCK]**; else `LOCAL` ledger |
274
- | `wait_for_event` | Profile-gated **[BLOCK]**; else `LOCAL` ledger |
275
- | `get_supervisor_snapshot` | Profile-gated **[BLOCK]**; else `LOCAL` ledger |
276
- | `send_message` | Profile-gated **[BLOCK]**; else `LOCAL` relay |
277
- | `check_messages` | Profile-gated **[BLOCK]**; else `LOCAL` relay |
278
233
  | `get_epic_snapshot` | Profile-gated **[BLOCK]** · Bridge API epic snapshot (Jira epic keys) |
279
- | `wait_for_done_gate` | Profile-gated **[BLOCK]** · VCS **[BLOCK]** (resolves PR number + head SHA) |
280
234
 
281
235
  ---
282
236
 
@@ -345,10 +299,10 @@ wanting both selects `sfcc,sfcc-write` (or `full`).
345
299
 
346
300
  | Integration | BLOCK without it | DEGRADE without it |
347
301
  |---|---|---|
348
- | **Ticket backend** (jira mode) | `create_ticket`, `get_ticket(s)`, `update_ticket_description`, `update_jira_status`, `get_jira_transitions`, and every AI generator (they read the ticket) | — |
302
+ | **Ticket backend** (jira mode) | `create_ticket`, `get_ticket(s)`, `update_ticket_description`, `update_jira_status`, and every AI generator (they read the ticket) | — |
349
303
  | **Jira (only)** | `get_comments`, `add_comment`, `attachment`, `estimate_epic` | — |
350
- | **Version control (VCS)** | `create_pull_request`, `merge_pull_request`, `resolve_ci_checks`, `poll_ci_checks`, `materialize_fresh_base`, `parse_repository`, `regenerate_directory_map`, `wait_for_done_gate`; **Tier-3** `request_plan_generation`/`get_plan`, `request_architecture`/`get_architecture`, `request_reimplement_context`/`get_reimplement_context`, `create_doc`(tdd/architecture) | **Tier-4** `request_clarifying_questions`, `request_ticket_critique`, `request_ticket_review`, `request_prd`, `create_doc`(prd/fsd) |
351
- | **Code index** (succeeded parse) | Tier-3 plan/architecture/reimplement/`create_doc`(tdd/architecture); `request_council` in `technical`/`discovery` modes | Tier-4 clarifying-questions/critique/review/prd/fsd |
304
+ | **Version control (VCS)** | `create_pull_request`, `merge_pull_request`, `resolve_ci_checks`, `poll_ci_checks`, `fresh_base`, `parse_repository`, `regenerate_directory_map`; **Tier-3** `request_plan_generation`/`get_plan`, `request_reimplement_context`/`get_reimplement_context`, `create_doc`(tdd/architecture) | **Tier-4** `request_ticket_review`, `create_doc`(prd/fsd) |
305
+ | **Code index** (succeeded parse) | Tier-3 plan/reimplement/`create_doc`(tdd/architecture); `request_council` in `technical`/`discovery` modes | Tier-4 review/prd/fsd |
352
306
  | **SFCC OCAPI** | `check_permissions` + every gated SFCC read and write tool | — |
353
307
  | **SFCC WebDAV logs** | `sfcc_log_query` | — |
354
308
  | **Deep-research flag** | `request_deep_research`, `get_deep_research` | — |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bridge_gpt/mcp-server",
3
- "version": "0.2.46",
3
+ "version": "0.2.49",
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",
@@ -20,9 +20,9 @@
20
20
  },
21
21
  {
22
22
  "type": "mcp_call",
23
- "tool": "get_docs_dir",
23
+ "tool": "ping",
24
24
  "params": {},
25
- "description": "Resolve the docs directory for run artifacts"
25
+ "description": "Resolve the docs directory for run artifacts: read docs_dir from the first (JSON) content item of this ping result"
26
26
  },
27
27
  {
28
28
  "type": "mcp_call",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "review-ticket",
3
- "description": "Review a ticket, evaluate suggestions for accuracy, and produce a combined review-and-resolution document with decision trees. A single request_ticket_review step runs the backend's resolved difficulty-adaptive review policy, which internally runs any second-opinion rounds server-side. Pass --rounds=1|2 to forward an explicit round count that forces the review shape (1 = single pass, 2 = full second-opinion review); omit it to let the backend policy executor decide adaptively.",
4
- "variables": ["ticket_key", "docs_dir", "base_branch", "base_sha", "no_refresh_base", "rounds"],
3
+ "description": "Review a ticket, evaluate suggestions for accuracy, and produce a combined review-and-resolution document with decision trees. A single request_ticket_review step runs the backend's resolved difficulty-adaptive review policy, which internally runs any second-opinion rounds server-side. Pass --rounds=1|2 to forward an explicit round count that forces the review shape (1 = single pass, 2 = full second-opinion review); omit it to let the backend policy executor decide adaptively. The round count is injected into the request_ticket_review step as a real integer by get_pipeline_recipe, not substituted as a recipe variable.",
4
+ "variables": ["ticket_key", "docs_dir", "base_branch", "base_sha", "no_refresh_base"],
5
5
  "steps": [
6
6
  {
7
7
  "type": "mcp_call",
@@ -16,8 +16,7 @@
16
16
  "ticket_number": "{ticket_key}",
17
17
  "wait_for_result": true,
18
18
  "save_locally": true,
19
- "provider": "{provider}",
20
- "rounds": "{rounds}"
19
+ "provider": "{provider}"
21
20
  },
22
21
  "description": "Generate combined clarify+critique review. The backend runs the resolved difficulty-adaptive policy (including any second-opinion rounds) server-side; an explicit rounds value (1|2) forces the shape.",
23
22
  "on_error": "warn_and_continue"
@@ -25,8 +24,9 @@
25
24
  {
26
25
  "type": "mcp_call",
27
26
  "id": "materialize-fresh-base",
28
- "tool": "materialize_fresh_base",
27
+ "tool": "fresh_base",
29
28
  "params": {
29
+ "action": "materialize",
30
30
  "base_branch": "{base_branch}",
31
31
  "base_sha": "{base_sha}",
32
32
  "no_refresh_base": "{no_refresh_base}"
@@ -47,11 +47,12 @@
47
47
  {
48
48
  "type": "mcp_call",
49
49
  "id": "cleanup-fresh-base",
50
- "tool": "cleanup_fresh_base",
50
+ "tool": "fresh_base",
51
51
  "params": {
52
- "fresh_base_root": "<the fresh_base_root path returned by the earlier materialize_fresh_base step's result>"
52
+ "action": "cleanup",
53
+ "fresh_base_root": "<the fresh_base_root path returned by the earlier fresh_base materialize step's result>"
53
54
  },
54
- "description": "Remove the temp workspace created by materialize_fresh_base. fresh_base_root is a RUNTIME value, not a static recipe variable: call this tool with the actual path string returned by the earlier materialize_fresh_base step's result, not the placeholder text shown in params above.",
55
+ "description": "Remove the temp workspace created by the earlier fresh_base materialize step. fresh_base_root is a RUNTIME value, not a static recipe variable: call this tool with the actual path string returned by that step's result, not the placeholder text shown in params above.",
55
56
  "on_error": "warn_and_continue"
56
57
  }
57
58
  ]
@@ -1,36 +0,0 @@
1
- {
2
- "name": "check-ci-ticket",
3
- "description": "Commit changes, create a pull request, and monitor CI checks.",
4
- "variables": ["ticket_key"],
5
- "steps": [
6
- {
7
- "type": "mcp_call",
8
- "tool": "ping",
9
- "params": {},
10
- "description": "Verify Bridge API connectivity"
11
- },
12
- {
13
- "type": "agent_task",
14
- "instruction_file": "commit-and-push.md",
15
- "description": "Stage, commit, and push changes",
16
- "requires_approval": true
17
- },
18
- {
19
- "type": "agent_task",
20
- "instruction_file": "create-pr.md",
21
- "description": "Create a pull request with a title derived from the commit subject"
22
- },
23
- {
24
- "type": "mcp_call",
25
- "tool": "config_field",
26
- "params": { "operation": "get", "field_name": "ci_followup_config" },
27
- "description": "Fetch repo-specific CI follow-up configuration",
28
- "on_error": "warn_and_continue"
29
- },
30
- {
31
- "type": "agent_task",
32
- "instruction_file": "monitor-ci-checks.md",
33
- "description": "Monitor CI checks and report results"
34
- }
35
- ]
36
- }