@bridge_gpt/mcp-server 0.2.45 → 0.2.48
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 +103 -86
- package/build/agent-capabilities/default-deps.js +2 -2
- package/build/agent-launchers/claude.js +10 -19
- package/build/agent-launchers/cursor.js +4 -12
- package/build/agent-launchers/prompt.js +117 -0
- package/build/agents.generated.js +1 -1
- package/build/commands.generated.js +16 -22
- package/build/conduct-epic/bridge-client.js +73 -0
- package/build/conduct-epic/cli.js +152 -6
- package/build/conductor/cli.js +6 -7
- package/build/conductor/doctor.js +13 -116
- package/build/conductor/tools.js +18 -349
- package/build/conductor-bin.js +6 -30
- package/build/docs.generated.js +2 -2
- package/build/executor/deps.js +1 -0
- package/build/executor/service-lifecycle.js +6 -6
- package/build/executor/service-unit.js +13 -16
- package/build/index.js +253 -759
- package/build/init.js +15 -17
- package/build/install-doctor.js +1 -1
- package/build/learn-tool-gating.js +283 -0
- package/build/mcp-profile.js +13 -3
- package/build/mcp-server-invocation.js +14 -0
- package/build/pipelines.generated.js +20 -140
- package/build/platform-escaping.js +72 -0
- package/build/readme.generated.js +1 -1
- package/build/review-tickets.js +1 -1
- package/build/run-unit-tests-launcher.js +0 -1
- package/build/sfcc/register.js +41 -31
- package/build/sfcc/registration-inventory.js +44 -20
- package/build/start-tickets-conductor.js +2 -2
- package/build/start-tickets.js +8 -38
- package/build/tool-surface-gating.js +9 -3
- package/build/update-status.js +15 -0
- package/build/version.generated.js +2 -2
- package/docs/CONDUCTOR.md +10 -12
- package/docs/install/mcp-tool-integrations.md +9 -55
- package/package.json +2 -2
- package/pipelines/idea-to-ticket.json +2 -2
- package/pipelines/review-ticket.json +9 -8
- package/pipelines/check-ci-ticket.json +0 -36
- package/pipelines/pr-ticket.json +0 -24
package/build/review-tickets.js
CHANGED
|
@@ -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
|
|
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",
|
package/build/sfcc/register.js
CHANGED
|
@@ -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
|
|
18
|
-
*
|
|
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
|
|
49
|
-
*
|
|
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
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
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
|
|
15
|
-
* the
|
|
16
|
-
*
|
|
14
|
+
* Since BAPI-817 it gates the READ profile only, and since BAPI-912 that profile
|
|
15
|
+
* also owns the two diagnostics — so 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
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
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
|
|
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
|
|
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
|
|
50
|
-
* and carries read-only annotations; by construction
|
|
51
|
-
* `WRITE_ANNOTATIONS` can appear here, which is what makes
|
|
52
|
-
* cannot enable a mutation" checkable rather than merely
|
|
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
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
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:
|
|
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
|
|
139
|
-
//
|
|
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`). */
|
package/build/start-tickets.js
CHANGED
|
@@ -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,
|
|
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
|
|
1073
|
-
*
|
|
1074
|
-
*
|
|
1075
|
-
*
|
|
1076
|
-
*
|
|
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-
|
|
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
|
|
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
|
|
@@ -399,9 +399,15 @@ const ADVISORY_HOST_TOOL = "ping";
|
|
|
399
399
|
* CALL `ping` — reading its description during ordinary discovery is enough,
|
|
400
400
|
* which is the precise gap the ticket describes.
|
|
401
401
|
*
|
|
402
|
-
* The description text is appended at RUNTIME only
|
|
403
|
-
*
|
|
404
|
-
* guard `mcp_server/src/index.ts` are unaffected
|
|
402
|
+
* The description text is appended at RUNTIME only, over the `ping` description
|
|
403
|
+
* from the static tool catalog. That static catalog is untouched, so the
|
|
404
|
+
* description prose pins that guard `mcp_server/src/index.ts` are unaffected —
|
|
405
|
+
* but a LIVE `tools/list` capture DOES include this decoration whenever the
|
|
406
|
+
* update status is stale, and so is NOT automatically safe for tools-budget
|
|
407
|
+
* measurement. Budget measurements stay repository-owned only because their
|
|
408
|
+
* child process explicitly disables the update check via
|
|
409
|
+
* `BAPI_MCP_UPDATE_CHECK_ENABLED=false` (BAPI-917) — see
|
|
410
|
+
* `mcp_server/src/integration/measure-tools.ts`.
|
|
405
411
|
*
|
|
406
412
|
* Fail-open: if the advisory cannot be produced, the original result is returned
|
|
407
413
|
* byte-for-byte.
|
package/build/update-status.js
CHANGED
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
* - **non-blocking** — started at boot, never awaited before `connect`;
|
|
16
16
|
* - **fail-open** — a null, malformed, rejected, or not-newer result yields
|
|
17
17
|
* no advisory and no warning, and never throws.
|
|
18
|
+
*
|
|
19
|
+
* The manager is default-on. Passing `enabled: false` (BAPI-917) makes it
|
|
20
|
+
* permanently `NOT_STALE` from the moment `start()` returns, without ever
|
|
21
|
+
* invoking the checker, touching the update cache, or making a registry
|
|
22
|
+
* request — used so a hermetic measurement capture cannot be perturbed by
|
|
23
|
+
* runtime update state.
|
|
18
24
|
*/
|
|
19
25
|
import { checkForUpdate } from "./update-check.js";
|
|
20
26
|
import { formatUpdateAdvice, formatToolSurfaceUpdateAdvisory } from "./upgrade-advice.js";
|
|
@@ -27,6 +33,7 @@ const NOT_STALE = { stale: false };
|
|
|
27
33
|
export function createUpdateStatusManager(options = {}) {
|
|
28
34
|
const check = options.check ?? checkForUpdate;
|
|
29
35
|
const warn = options.warn ?? ((message) => console.error(message));
|
|
36
|
+
const enabled = options.enabled !== false;
|
|
30
37
|
let started = false;
|
|
31
38
|
let settled = null;
|
|
32
39
|
let settledPromise = null;
|
|
@@ -51,6 +58,14 @@ export function createUpdateStatusManager(options = {}) {
|
|
|
51
58
|
if (started)
|
|
52
59
|
return;
|
|
53
60
|
started = true;
|
|
61
|
+
if (!enabled) {
|
|
62
|
+
// Disabled: settle immediately, without ever invoking `check`, warning,
|
|
63
|
+
// or scheduling a checker operation. `whenSettled()` stays usable — it
|
|
64
|
+
// just resolves to the same already-known conclusion.
|
|
65
|
+
settled = NOT_STALE;
|
|
66
|
+
settledPromise = Promise.resolve(NOT_STALE);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
54
69
|
settledPromise = (async () => {
|
|
55
70
|
let status;
|
|
56
71
|
try {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// AUTO-GENERATED — do not edit manually. Regenerate with: npm run build
|
|
2
|
-
export const VERSION = "0.2.
|
|
3
|
-
export const BUILD_COMMIT = "
|
|
2
|
+
export const VERSION = "0.2.48";
|
|
3
|
+
export const BUILD_COMMIT = "682b50a8f5ff-dirty";
|
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,
|
|
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
|
|
235
|
-
|
|
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
|
|
343
|
-
worker-facing
|
|
344
|
-
supervisor remain the authority; this change only stops the worker's own
|
|
345
|
-
|
|
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
|
|
386
|
-
|
|
387
|
-
|
|
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
|
-
| `
|
|
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
|
-
| `
|
|
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.
|
|
267
|
-
(`~/.config/bridge/events.db`)
|
|
268
|
-
|
|
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`,
|
|
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`, `
|
|
351
|
-
| **Code index** (succeeded parse) | Tier-3 plan/
|
|
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.
|
|
3
|
+
"version": "0.2.48",
|
|
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",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
],
|
|
23
23
|
"//test": "The `test` script delegates to the bounded launcher (scripts/run-unit-tests.js → src/run-unit-tests-launcher.ts, BAPI-683), which discovers build/*.test.js at runtime and spawns them in size-bounded batches so the argv never exceeds Windows' ~8191-char command-line limit. Two determinism rules from the pre-launcher script are preserved INSIDE the launcher: (1) multi-file batches run WITHOUT --test-force-exit, because that flag makes node:test exit before aggregating per-subprocess summaries and the tally becomes nondeterministic (failures still surface and still set exit 1, but the count cannot be trusted as a completeness signal); (2) build/secret-safety.test.js leaks a handle that holds the event loop ~60s after its tests finish (they run in ~147ms), so the launcher quarantines it into its own single-file --test-force-exit invocation (FORCE_EXIT_QUARANTINE in src/run-unit-tests-launcher.ts) where the tally stays exact. Do NOT add --test-force-exit to batched invocations, and do NOT remove the quarantine, until the underlying handle leak is fixed.",
|
|
24
24
|
"scripts": {
|
|
25
|
-
"build": "node scripts/bundle-version.js && node scripts/bundle-readme.js && node scripts/bundle-pipelines.js && node scripts/bundle-commands.js && node scripts/bundle-agents.js && node scripts/bundle-docs.js && tsc && node scripts/sync-agent-mirrors.js && node scripts/bundle-esbuild.js",
|
|
25
|
+
"build": "node scripts/bundle-version.js && node scripts/validate-packaged-command-references.js && node scripts/bundle-readme.js && node scripts/bundle-pipelines.js && node scripts/bundle-commands.js && node scripts/bundle-agents.js && node scripts/bundle-docs.js && tsc && node scripts/sync-agent-mirrors.js && node scripts/bundle-esbuild.js",
|
|
26
26
|
"check:version-generated": "node scripts/bundle-version.js && node scripts/check-version-generated.js",
|
|
27
27
|
"postbuild": "node scripts/prepend-shebang.cjs",
|
|
28
28
|
"start": "node build/index.js",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
"type": "mcp_call",
|
|
23
|
-
"tool": "
|
|
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",
|