@bridge_gpt/mcp-server 0.1.17 → 0.2.0
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 +333 -197
- package/build/agent-capabilities/cli.js +152 -0
- package/build/agent-capabilities/default-deps.js +45 -0
- package/build/agent-capabilities/probe-context.js +111 -0
- package/build/agent-capabilities/probes.js +278 -0
- package/build/agent-capabilities/reporter.js +50 -0
- package/build/agent-capabilities/runner.js +56 -0
- package/build/agent-capabilities/types.js +10 -0
- package/build/agent-launchers/claude.js +4 -4
- package/build/agents.generated.js +1 -1
- package/build/brainstorm-files.js +89 -0
- package/build/bridge-config.js +404 -0
- package/build/chain-orchestrator.js +247 -33
- package/build/commands.generated.js +5 -5
- package/build/credential-materialization.js +128 -0
- package/build/credential-store.js +232 -0
- package/build/decision-page-schema.js +39 -6
- package/build/decision-page-template.js +54 -18
- package/build/doctor.js +18 -2
- package/build/git-ignore-utils.js +63 -0
- package/build/index.js +1510 -560
- package/build/mcp-invoke.js +417 -0
- package/build/mcp-provisioning.js +249 -0
- package/build/mcp-registration-doctor.js +96 -0
- package/build/pipeline-orchestrator.js +9 -1
- package/build/pipeline-utils.js +33 -0
- package/build/pipelines.generated.js +36 -5
- package/build/schedule-run.js +6 -6
- package/build/start-tickets-prereqs.js +90 -1
- package/build/start-tickets.js +106 -14
- package/build/third-party-mcp-targets.js +75 -0
- package/build/version.generated.js +1 -1
- package/package.json +3 -3
- package/pipelines/full-automation.json +3 -1
- package/pipelines/implement-ticket.json +28 -2
- package/smoke-test/SMOKE-TEST.md +4 -2
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
* the runtime graph stays acyclic — `start-tickets.ts` imports values FROM here,
|
|
14
14
|
* never the reverse.
|
|
15
15
|
*/
|
|
16
|
+
import { resolveBapiCredentials } from "./credential-store.js";
|
|
17
|
+
import { readBridgeConfig } from "./bridge-config.js";
|
|
18
|
+
import { probeWorktreeMcpRegistration } from "./mcp-registration-doctor.js";
|
|
16
19
|
// ---------------------------------------------------------------------------
|
|
17
20
|
// Constants (moved here from start-tickets.ts so both consumers share them)
|
|
18
21
|
// ---------------------------------------------------------------------------
|
|
@@ -250,6 +253,87 @@ function agentDescriptor(agent) {
|
|
|
250
253
|
function uvDescriptor() {
|
|
251
254
|
return commandDescriptor("uv", "uv", UV_INSTALL_HINTS);
|
|
252
255
|
}
|
|
256
|
+
/** Secret-free remediation hint shared by the credential-resolution descriptor. */
|
|
257
|
+
const CREDENTIAL_RESOLUTION_HINT = 'Set BAPI_API_KEY in the environment, or add it under "bapi:<repo_name>" in ' +
|
|
258
|
+
"~/.config/bridge/credentials.json.";
|
|
259
|
+
const CREDENTIAL_RESOLUTION_INSTALL_HINTS = {
|
|
260
|
+
darwin: CREDENTIAL_RESOLUTION_HINT,
|
|
261
|
+
linux: CREDENTIAL_RESOLUTION_HINT,
|
|
262
|
+
win32: CREDENTIAL_RESOLUTION_HINT,
|
|
263
|
+
};
|
|
264
|
+
/**
|
|
265
|
+
* Doctor-only, strictly read-only probe: can the Bridge API credentials be
|
|
266
|
+
* resolved for the current repo? Resolves repo identity from `BAPI_REPO_NAME`
|
|
267
|
+
* first, then `.bridge/config`, then asks the credential resolver. Reports only
|
|
268
|
+
* the SOURCE CLASS (env vs. store) — NEVER the resolved key value.
|
|
269
|
+
*/
|
|
270
|
+
export function credentialResolutionDescriptor() {
|
|
271
|
+
return {
|
|
272
|
+
id: "bapi-credentials",
|
|
273
|
+
label: "Bridge API credential resolution",
|
|
274
|
+
installHint: CREDENTIAL_RESOLUTION_INSTALL_HINTS,
|
|
275
|
+
probe: async (deps) => {
|
|
276
|
+
const { readFile, stat, homedir } = deps;
|
|
277
|
+
if (!readFile || !stat || !homedir) {
|
|
278
|
+
return { found: false, detail: "credential probe unavailable (no read-only filesystem access)" };
|
|
279
|
+
}
|
|
280
|
+
let repoName = (deps.env.BAPI_REPO_NAME ?? "").trim();
|
|
281
|
+
if (repoName.length === 0) {
|
|
282
|
+
const read = await readBridgeConfig(deps.cwd, { readFile });
|
|
283
|
+
if (read.ok) {
|
|
284
|
+
repoName = read.manifest.repoName;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
return {
|
|
288
|
+
found: false,
|
|
289
|
+
detail: "cannot determine repo identity (set BAPI_REPO_NAME or add a valid .bridge/config). " +
|
|
290
|
+
CREDENTIAL_RESOLUTION_HINT,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const result = await resolveBapiCredentials(repoName, {
|
|
295
|
+
env: deps.env,
|
|
296
|
+
homedir,
|
|
297
|
+
platform: deps.platform,
|
|
298
|
+
readFile,
|
|
299
|
+
stat,
|
|
300
|
+
});
|
|
301
|
+
if (result.ok) {
|
|
302
|
+
const via = result.credentials.source === "env" ? "env" : "store";
|
|
303
|
+
return { found: true, detail: `credentials resolvable via ${via}` };
|
|
304
|
+
}
|
|
305
|
+
return { found: false, detail: CREDENTIAL_RESOLUTION_HINT };
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
/** Secret-free remediation hint shared by the worktree-MCP descriptor. */
|
|
310
|
+
const WORKTREE_MCP_HINT = "Re-run start-tickets to provision the worktree MCP registration " +
|
|
311
|
+
"(.mcp.json / .cursor/mcp.json pointing at the mcp-invoke shim).";
|
|
312
|
+
const WORKTREE_MCP_INSTALL_HINTS = {
|
|
313
|
+
darwin: WORKTREE_MCP_HINT,
|
|
314
|
+
linux: WORKTREE_MCP_HINT,
|
|
315
|
+
win32: WORKTREE_MCP_HINT,
|
|
316
|
+
};
|
|
317
|
+
/**
|
|
318
|
+
* Doctor-only, strictly read-only probe: does the current worktree's generated
|
|
319
|
+
* MCP registration point at the Bridge API `mcp-invoke` shim? Inspects
|
|
320
|
+
* `.mcp.json` / `.cursor/mcp.json` under `deps.cwd` without spawning anything.
|
|
321
|
+
*/
|
|
322
|
+
export function worktreeMcpReachabilityDescriptor() {
|
|
323
|
+
return {
|
|
324
|
+
id: "worktree-mcp-registration",
|
|
325
|
+
label: "Worktree MCP registration reachability",
|
|
326
|
+
installHint: WORKTREE_MCP_INSTALL_HINTS,
|
|
327
|
+
probe: async (deps) => {
|
|
328
|
+
const { readFile } = deps;
|
|
329
|
+
if (!readFile) {
|
|
330
|
+
return { found: false, detail: "registration probe unavailable (no read-only filesystem access)" };
|
|
331
|
+
}
|
|
332
|
+
const result = await probeWorktreeMcpRegistration(deps.cwd, { readFile });
|
|
333
|
+
return { found: result.found, detail: result.detail };
|
|
334
|
+
},
|
|
335
|
+
};
|
|
336
|
+
}
|
|
253
337
|
/**
|
|
254
338
|
* The exact existing live-preflight requirement set per platform, plus the git
|
|
255
339
|
* work-tree custom check appended after the command checks. This is the ONLY
|
|
@@ -286,7 +370,12 @@ export function getPreflightPrereqDescriptors(platform, env) {
|
|
|
286
370
|
* additive (BAPI-302/303 regression-safe).
|
|
287
371
|
*/
|
|
288
372
|
export function getDoctorOnlyPrereqDescriptors(_platform, _env, agent) {
|
|
289
|
-
return [
|
|
373
|
+
return [
|
|
374
|
+
uvDescriptor(),
|
|
375
|
+
agentDescriptor(agent),
|
|
376
|
+
credentialResolutionDescriptor(),
|
|
377
|
+
worktreeMcpReachabilityDescriptor(),
|
|
378
|
+
];
|
|
290
379
|
}
|
|
291
380
|
/**
|
|
292
381
|
* The doctor's full descriptor set: the preflight descriptors (verbatim) plus
|
package/build/start-tickets.js
CHANGED
|
@@ -53,7 +53,10 @@
|
|
|
53
53
|
* unit-testable on Linux CI without spawning real commands or terminals.
|
|
54
54
|
*/
|
|
55
55
|
import { execFile } from "child_process";
|
|
56
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
56
57
|
import path from "path";
|
|
58
|
+
import { VERSION } from "./version.generated.js";
|
|
59
|
+
import { provisionMcpRegistrationsForCreatedWorktrees, } from "./mcp-provisioning.js";
|
|
57
60
|
// Per-OS prerequisite knowledge + low-level command probes live in the shared
|
|
58
61
|
// prereqs module so `runPreflight` (enforce) and the read-only `doctor` (render)
|
|
59
62
|
// can never drift. `start-tickets.ts` imports VALUES from there; the prereqs
|
|
@@ -75,6 +78,10 @@ export const DEFAULT_MAX_PARALLEL = 3;
|
|
|
75
78
|
export const DEFAULT_TMUX_SESSION_PREFIX = "bridge-start-tickets";
|
|
76
79
|
/** Environment variable overriding the tmux session-name prefix. */
|
|
77
80
|
export const TMUX_SESSION_OVERRIDE_ENV = "BAPI_TMUX_SESSION";
|
|
81
|
+
/** Return a copy of `row` with `warning` appended; never mutates the input. */
|
|
82
|
+
export function appendSummaryRowWarning(row, warning) {
|
|
83
|
+
return { ...row, warnings: [...(row.warnings ?? []), warning] };
|
|
84
|
+
}
|
|
78
85
|
// ---------------------------------------------------------------------------
|
|
79
86
|
// Usage / argument parsing
|
|
80
87
|
// ---------------------------------------------------------------------------
|
|
@@ -227,7 +234,7 @@ export function parseStartTicketsArgs(argv) {
|
|
|
227
234
|
dryRun = true;
|
|
228
235
|
continue;
|
|
229
236
|
}
|
|
230
|
-
if (arg === "--auto
|
|
237
|
+
if (arg === "--auto") {
|
|
231
238
|
autoApprove = true;
|
|
232
239
|
continue;
|
|
233
240
|
}
|
|
@@ -789,10 +796,10 @@ export async function createWorktrees(deps, options, worktrunkBinary) {
|
|
|
789
796
|
/**
|
|
790
797
|
* The starter prompt handed to the selected agent. Identical for every agent.
|
|
791
798
|
* When `autoApprove` is set, the implementation agent runs hands-off
|
|
792
|
-
* (`/implement-ticket <KEY> --auto
|
|
799
|
+
* (`/implement-ticket <KEY> --auto`) — used by full-automation chains.
|
|
793
800
|
*/
|
|
794
801
|
export function buildAgentPrompt(key, opts = {}) {
|
|
795
|
-
return `/implement-ticket ${key}${opts.autoApprove ? " --auto
|
|
802
|
+
return `/implement-ticket ${key}${opts.autoApprove ? " --auto" : ""}`;
|
|
796
803
|
}
|
|
797
804
|
/**
|
|
798
805
|
* Build the agent invocation (`<command> <quotedPrompt>`) for the agent's prompt
|
|
@@ -1111,10 +1118,31 @@ export function getDryRunPlatformDetails(agent, platform = process.platform, env
|
|
|
1111
1118
|
buildAgentShellCommand: (key, worktreePath) => buildAgentShellCommand(agent, key, worktreePath, platform, autoApprove),
|
|
1112
1119
|
};
|
|
1113
1120
|
}
|
|
1121
|
+
/**
|
|
1122
|
+
* Build the dry-run preview of the secret-free MCP provisioning that
|
|
1123
|
+
* `start-tickets` would perform for a worktree whose `.bridge/config` includes
|
|
1124
|
+
* the `bapi` target. Lists both registration files and the version-pinned shim
|
|
1125
|
+
* command. Pure formatting — implies no credentials and writes no files.
|
|
1126
|
+
*/
|
|
1127
|
+
export function buildDryRunMcpProvisioningLines(worktreePath, platform = process.platform) {
|
|
1128
|
+
const api = platform === "win32" ? path.win32 : path.posix;
|
|
1129
|
+
const mcpJson = api.join(worktreePath, ".mcp.json");
|
|
1130
|
+
const cursorJson = api.join(worktreePath, ".cursor", "mcp.json");
|
|
1131
|
+
const shim = `npx -y @bridge_gpt/mcp-server@${VERSION} mcp-invoke --target <target> --project-root ${worktreePath}`;
|
|
1132
|
+
return [
|
|
1133
|
+
"DRY-RUN: MCP provisioning (target-driven from .bridge/config — bapi plus any",
|
|
1134
|
+
"DRY-RUN: supported Tier-2 target such as sfcc): would write a secret-free shim",
|
|
1135
|
+
"DRY-RUN: entry per target to",
|
|
1136
|
+
`DRY-RUN: ${mcpJson}`,
|
|
1137
|
+
`DRY-RUN: ${cursorJson}`,
|
|
1138
|
+
`DRY-RUN: ${shim}`,
|
|
1139
|
+
];
|
|
1140
|
+
}
|
|
1114
1141
|
/**
|
|
1115
1142
|
* Build the user-facing dry-run detail lines for one ticket, rendering the
|
|
1116
|
-
* platform-correct Worktrunk binary
|
|
1117
|
-
* platform formatting only — no
|
|
1143
|
+
* platform-correct Worktrunk binary, the selected agent's shell command, and
|
|
1144
|
+
* the secret-free MCP provisioning preview. Pure platform formatting only — no
|
|
1145
|
+
* preflight, no routing failures.
|
|
1118
1146
|
*/
|
|
1119
1147
|
export function buildDryRunDetailLines(agent, key, branch, platform = process.platform, env = process.env, baseBranch = "main", autoApprove = false) {
|
|
1120
1148
|
const { worktrunkBinary, buildAgentShellCommand: build } = getDryRunPlatformDetails(agent, platform, env, autoApprove);
|
|
@@ -1124,6 +1152,7 @@ export function buildDryRunDetailLines(agent, key, branch, platform = process.pl
|
|
|
1124
1152
|
`DRY-RUN: ${key} -> branch=${branch}`,
|
|
1125
1153
|
`DRY-RUN: ${worktrunkBinary} ${wtArgs.join(" ")}`,
|
|
1126
1154
|
`DRY-RUN: ${agentInvocation}`,
|
|
1155
|
+
...buildDryRunMcpProvisioningLines("<worktree-path>", platform),
|
|
1127
1156
|
];
|
|
1128
1157
|
}
|
|
1129
1158
|
/**
|
|
@@ -1140,13 +1169,30 @@ export function formatSummaryReport(rows) {
|
|
|
1140
1169
|
line += ` path=${row.path}`;
|
|
1141
1170
|
lines.push(line);
|
|
1142
1171
|
}
|
|
1143
|
-
|
|
1144
|
-
|
|
1172
|
+
// Warnings section: create/spawn-failed row errors AND any non-fatal
|
|
1173
|
+
// per-row provisioning warnings. Identical error/warning text for the same
|
|
1174
|
+
// row is emitted only once.
|
|
1175
|
+
const warningLines = [];
|
|
1176
|
+
for (const row of rows) {
|
|
1177
|
+
const messages = [];
|
|
1178
|
+
if (row.status === "create-failed" || row.status === "spawn-failed") {
|
|
1179
|
+
messages.push(row.error ?? row.status);
|
|
1180
|
+
}
|
|
1181
|
+
for (const warning of row.warnings ?? []) {
|
|
1182
|
+
messages.push(warning);
|
|
1183
|
+
}
|
|
1184
|
+
const seen = new Set();
|
|
1185
|
+
for (const message of messages) {
|
|
1186
|
+
if (seen.has(message))
|
|
1187
|
+
continue;
|
|
1188
|
+
seen.add(message);
|
|
1189
|
+
warningLines.push(` ${row.key}: ${message}`);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
if (warningLines.length > 0) {
|
|
1145
1193
|
lines.push("");
|
|
1146
1194
|
lines.push("Warnings:");
|
|
1147
|
-
|
|
1148
|
-
lines.push(` ${row.key}: ${row.error ?? row.status}`);
|
|
1149
|
-
}
|
|
1195
|
+
lines.push(...warningLines);
|
|
1150
1196
|
}
|
|
1151
1197
|
return lines.join("\n");
|
|
1152
1198
|
}
|
|
@@ -1158,7 +1204,38 @@ export function formatSummaryReport(rows) {
|
|
|
1158
1204
|
* using the platform-correct shell builder. Global preflight/refresh failures
|
|
1159
1205
|
* are returned as `{ ok: false }`; per-ticket failures stay in the rows.
|
|
1160
1206
|
*/
|
|
1161
|
-
|
|
1207
|
+
/**
|
|
1208
|
+
* Build the `mcp-provisioning` filesystem boundary from `StartTicketsDeps`.
|
|
1209
|
+
* Provisioning needs real `fs/promises` ops (not part of the command-runner DI
|
|
1210
|
+
* boundary), but inherits the platform and cwd from the orchestration deps.
|
|
1211
|
+
*/
|
|
1212
|
+
export function buildMcpProvisioningDeps(deps) {
|
|
1213
|
+
return {
|
|
1214
|
+
readFile: (filePath) => readFile(filePath, "utf-8"),
|
|
1215
|
+
writeFile: (filePath, data) => writeFile(filePath, data, "utf-8"),
|
|
1216
|
+
mkdir: (dirPath, options) => mkdir(dirPath, options),
|
|
1217
|
+
platform: deps.platform,
|
|
1218
|
+
cwd: deps.cwd,
|
|
1219
|
+
};
|
|
1220
|
+
}
|
|
1221
|
+
/**
|
|
1222
|
+
* Tier-3 file-credential materialization seam.
|
|
1223
|
+
*
|
|
1224
|
+
* The committed `.bridge/config` schema does not (yet) declare file-credential
|
|
1225
|
+
* entries — Tier-3 file materialization is a gated seam (see
|
|
1226
|
+
* `credential-materialization.ts`, whose Windows worktree-visible copy remains
|
|
1227
|
+
* disabled pending the open context-vs-server-only design decision). With no
|
|
1228
|
+
* file-credential configuration there is nothing to materialize, so the default
|
|
1229
|
+
* is a safe pass-through. The seam exists so `orchestrateStartTickets` calls it
|
|
1230
|
+
* in the correct order — AFTER MCP registration provisioning and BEFORE tab
|
|
1231
|
+
* spawning — once the schema and the design decision are resolved. Per-row
|
|
1232
|
+
* failures must mark only the affected row `spawn-failed`; normal symlinks are
|
|
1233
|
+
* never torn down on completion.
|
|
1234
|
+
*/
|
|
1235
|
+
export async function materializeFileCredentialsForCreatedWorktrees(rows, _deps) {
|
|
1236
|
+
return rows;
|
|
1237
|
+
}
|
|
1238
|
+
export async function orchestrateStartTickets(deps, options, overrides = {}) {
|
|
1162
1239
|
if (options.dryRun) {
|
|
1163
1240
|
return { ok: true, rows: buildDryRunResults(options.keys, options.branchOverrides) };
|
|
1164
1241
|
}
|
|
@@ -1183,9 +1260,24 @@ export async function orchestrateStartTickets(deps, options) {
|
|
|
1183
1260
|
});
|
|
1184
1261
|
if (!refresh.ok)
|
|
1185
1262
|
return { ok: false, error: refresh.error };
|
|
1186
|
-
const
|
|
1187
|
-
const
|
|
1188
|
-
|
|
1263
|
+
const createWorktreesFn = overrides.createWorktrees ?? createWorktrees;
|
|
1264
|
+
const provisionFn = overrides.provisionMcpRegistrations ??
|
|
1265
|
+
((rows, d) => provisionMcpRegistrationsForCreatedWorktrees(rows, buildMcpProvisioningDeps(d)));
|
|
1266
|
+
const materializeFn = overrides.materializeFileCredentials ?? materializeFileCredentialsForCreatedWorktrees;
|
|
1267
|
+
const detectTerminalFn = overrides.detectTerminal ?? detectTerminal;
|
|
1268
|
+
const spawnTabsFn = overrides.spawnTabsForCreatedWorktrees ?? spawnTabsForCreatedWorktrees;
|
|
1269
|
+
const created = await createWorktreesFn(deps, options, platformConfig.config.worktrunkBinary);
|
|
1270
|
+
// Synchronously provision secret-free worktree MCP registrations after
|
|
1271
|
+
// worktree creation and before launching the agent tab. Per-worktree
|
|
1272
|
+
// provisioning failures mark only that row `spawn-failed` (skipped by the
|
|
1273
|
+
// spawn step below) — they never abort the whole run.
|
|
1274
|
+
const provisioned = await provisionFn(created, deps);
|
|
1275
|
+
// Materialize any Tier-3 file credentials AFTER MCP registration provisioning
|
|
1276
|
+
// and BEFORE tab spawning (currently a pass-through seam; see
|
|
1277
|
+
// materializeFileCredentialsForCreatedWorktrees).
|
|
1278
|
+
const materialized = await materializeFn(provisioned, deps);
|
|
1279
|
+
const terminal = detectTerminalFn(options.terminal, deps.env);
|
|
1280
|
+
const rows = await spawnTabsFn(deps, materialized, terminal, platformConfig.config.buildAgentShellCommand);
|
|
1189
1281
|
return { ok: true, rows };
|
|
1190
1282
|
}
|
|
1191
1283
|
/** Platform-specific guidance printed when one or more tabs fail to spawn. */
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier-2 third-party MCP target metadata + atomic env injection.
|
|
3
|
+
*
|
|
4
|
+
* Known third-party MCP targets (e.g. Salesforce `b2c-dx-mcp` via `sfcc`) are
|
|
5
|
+
* declared here as additive, data-only definitions: each names the secret env
|
|
6
|
+
* keys it needs. Provisioning and `mcp-invoke` consume these definitions without
|
|
7
|
+
* any target-specific branching, so adding a future Tier-2 target is a matter of
|
|
8
|
+
* adding one entry to the registry below.
|
|
9
|
+
*
|
|
10
|
+
* Credential resolution is delegated to the generic
|
|
11
|
+
* {@link resolveCredentialBundle}; the resulting env overlay is ATOMIC — either
|
|
12
|
+
* every required key resolves or the whole overlay fails. A half overlay (one of
|
|
13
|
+
* an `SFCC_CLIENT_ID`/`SFCC_CLIENT_SECRET` pair) is never returned. No secret
|
|
14
|
+
* value ever appears in an error message.
|
|
15
|
+
*/
|
|
16
|
+
import { resolveCredentialBundle, } from "./credential-store.js";
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Registry — additive; add a new entry to support a new Tier-2 target.
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
const THIRD_PARTY_TARGETS = {
|
|
21
|
+
sfcc: {
|
|
22
|
+
target: "sfcc",
|
|
23
|
+
requiredEnvKeys: ["SFCC_CLIENT_ID", "SFCC_CLIENT_SECRET"],
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
/** Return the definition for a supported Tier-2 target, or `undefined`. */
|
|
27
|
+
export function getThirdPartyTargetDefinition(target) {
|
|
28
|
+
return THIRD_PARTY_TARGETS[target];
|
|
29
|
+
}
|
|
30
|
+
/** List all supported Tier-2 target identifiers. */
|
|
31
|
+
export function getSupportedThirdPartyTargets() {
|
|
32
|
+
return Object.keys(THIRD_PARTY_TARGETS);
|
|
33
|
+
}
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Manifest entry validation
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
/**
|
|
38
|
+
* Validate that a parsed manifest entry for a Tier-2 target declares everything
|
|
39
|
+
* needed to launch it: a non-empty `command`, an `args` array, and a non-empty
|
|
40
|
+
* `secret_bundle`. Errors name only the missing field, never any value.
|
|
41
|
+
*/
|
|
42
|
+
export function validateThirdPartyTargetManifestEntry(entry) {
|
|
43
|
+
if (entry.command === undefined || entry.command.trim().length === 0) {
|
|
44
|
+
return { ok: false, error: `target '${entry.target}' requires a non-empty command` };
|
|
45
|
+
}
|
|
46
|
+
if (entry.args === undefined) {
|
|
47
|
+
return { ok: false, error: `target '${entry.target}' requires an args array` };
|
|
48
|
+
}
|
|
49
|
+
if (entry.secretBundle === undefined || entry.secretBundle.trim().length === 0) {
|
|
50
|
+
return { ok: false, error: `target '${entry.target}' requires a non-empty secret_bundle` };
|
|
51
|
+
}
|
|
52
|
+
return { ok: true };
|
|
53
|
+
}
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Atomic env resolution
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
/**
|
|
58
|
+
* Resolve the complete env overlay a Tier-2 target needs from its secret bundle.
|
|
59
|
+
* Delegates to {@link resolveCredentialBundle}; because that resolver fails
|
|
60
|
+
* unless every required key resolves, the returned overlay is atomic — there is
|
|
61
|
+
* no code path that returns a partial set of the target's secrets. Parent env
|
|
62
|
+
* values override store values key-by-key (handled by the generic resolver).
|
|
63
|
+
* Errors are secret-free and name the missing key(s).
|
|
64
|
+
*/
|
|
65
|
+
export async function resolveThirdPartyTargetEnv(definition, secretBundle, deps) {
|
|
66
|
+
const result = await resolveCredentialBundle(secretBundle, definition.requiredEnvKeys, deps);
|
|
67
|
+
if (!result.ok) {
|
|
68
|
+
return { ok: false, error: result.error };
|
|
69
|
+
}
|
|
70
|
+
const env = {};
|
|
71
|
+
for (const key of definition.requiredEnvKeys) {
|
|
72
|
+
env[key] = result.values[key];
|
|
73
|
+
}
|
|
74
|
+
return { ok: true, env };
|
|
75
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// AUTO-GENERATED — do not edit manually. Regenerate with: npm run build
|
|
2
|
-
export const VERSION = "0.
|
|
2
|
+
export const VERSION = "0.2.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bridge_gpt/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
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,8 +20,8 @@
|
|
|
20
20
|
"build": "node scripts/bundle-version.js && node scripts/bundle-pipelines.js && node scripts/bundle-commands.js && node scripts/bundle-agents.js && tsc",
|
|
21
21
|
"postbuild": "node scripts/prepend-shebang.cjs",
|
|
22
22
|
"start": "node build/index.js",
|
|
23
|
-
"test": "node --test build/pipeline-utils.test.js build/update-check.test.js build/cli-upgrade.test.js build/decision-page-schema.test.js build/decision-page-template.test.js build/bundle-pipelines.test.js build/instructions-contract.test.js build/pipeline-orchestrator-persistence.test.js build/pipeline-orchestrator-execution.test.js build/pipeline-orchestrator-integration.test.js build/index-static.test.js build/start-tickets.test.js build/start-tickets-base-branch.test.js build/agent-registry.test.js build/start-tickets-prereqs.test.js build/doctor.test.js build/package-static.test.js build/chain-utils.test.js build/chain-orchestrator.test.js build/scheduler-backends/types.test.js build/scheduler-backends/escaping.test.js build/scheduler-backends/launchd.test.js build/scheduler-backends/task-scheduler.test.js build/scheduler-backends/systemd-user.test.js build/scheduler-backends/at-fallback.test.js build/scheduler-backends/index.test.js build/agent-launchers/claude.test.js build/agent-launchers/index.test.js build/schedule-store.test.js build/schedule-run.test.js",
|
|
24
|
-
"test:integration": "node --test build/integration/refresh-main.integration.test.js build/integration/start-tickets.integration.test.js build/integration/doctor.integration.test.js",
|
|
23
|
+
"test": "node --test build/pipeline-utils.test.js build/update-check.test.js build/cli-upgrade.test.js build/decision-page-schema.test.js build/decision-page-template.test.js build/bundle-pipelines.test.js build/instructions-contract.test.js build/pipeline-orchestrator-persistence.test.js build/pipeline-orchestrator-execution.test.js build/pipeline-orchestrator-integration.test.js build/index-static.test.js build/index-resolvers.test.js build/index-project-root.test.js build/index-pipelines.test.js build/index.test.js build/bridge-config.test.js build/credential-store.test.js build/mcp-invoke.test.js build/mcp-provisioning.test.js build/third-party-mcp-targets.test.js build/git-ignore-utils.test.js build/credential-materialization.test.js build/mcp-registration-doctor.test.js build/secret-safety.test.js build/start-tickets.test.js build/start-tickets-base-branch.test.js build/agent-registry.test.js build/start-tickets-prereqs.test.js build/doctor.test.js build/package-static.test.js build/chain-utils.test.js build/chain-orchestrator.test.js build/scheduler-backends/types.test.js build/scheduler-backends/escaping.test.js build/scheduler-backends/launchd.test.js build/scheduler-backends/task-scheduler.test.js build/scheduler-backends/systemd-user.test.js build/scheduler-backends/at-fallback.test.js build/scheduler-backends/index.test.js build/agent-launchers/claude.test.js build/agent-launchers/index.test.js build/schedule-store.test.js build/schedule-run.test.js build/agent-capabilities/cli.test.js build/agent-capabilities/runner.test.js build/agent-capabilities/probes.test.js build/agent-capabilities/reporter.test.js && node --experimental-test-module-mocks --test build/index-heavy-read-truncation.test.js build/index-artifacts.test.js build/index-brainstorm-filenames.test.js build/index-output-path.test.js build/index-generate-decision-page.test.js build/index-generate-decision-page.integration.test.js",
|
|
24
|
+
"test:integration": "node --test build/integration/refresh-main.integration.test.js build/integration/start-tickets.integration.test.js build/integration/doctor.integration.test.js build/integration/agent-capabilities.integration.test.js",
|
|
25
25
|
"prepublishOnly": "npm run build && node scripts/verify-shebang.cjs"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
@@ -20,13 +20,15 @@
|
|
|
20
20
|
"auto_approve_external": "{auto_approve}"
|
|
21
21
|
},
|
|
22
22
|
"outputs": {
|
|
23
|
+
"child_ticket_keys": "child_ticket_keys",
|
|
24
|
+
"epic_parent_key": "epic_parent_key",
|
|
23
25
|
"created_ticket_keys": "created_ticket_keys"
|
|
24
26
|
}
|
|
25
27
|
},
|
|
26
28
|
{
|
|
27
29
|
"pipeline_name": "review-ticket",
|
|
28
30
|
"description": "Review each created ticket (one child pipeline run per ticket).",
|
|
29
|
-
"fan_out_input": "
|
|
31
|
+
"fan_out_input": "child_ticket_keys",
|
|
30
32
|
"fan_out_variable": "ticket_key",
|
|
31
33
|
"variables": {
|
|
32
34
|
"ticket_key": "{ticket_key}"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"type": "agent_task",
|
|
25
|
-
"instruction_file": "execute-plan.md",
|
|
25
|
+
"instruction_file": "execute-plan-sectioned.md",
|
|
26
26
|
"description": "Execute the implementation plan"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
@@ -58,5 +58,31 @@
|
|
|
58
58
|
"instruction_file": "monitor-ci-checks.md",
|
|
59
59
|
"description": "Monitor CI checks and report results"
|
|
60
60
|
}
|
|
61
|
-
]
|
|
61
|
+
],
|
|
62
|
+
"tiered_executor_policy": {
|
|
63
|
+
"supported_hosts": ["claude_code"],
|
|
64
|
+
"sequential_only": true,
|
|
65
|
+
"tier_model_mapping": {
|
|
66
|
+
"cheap": "haiku",
|
|
67
|
+
"basic": "sonnet",
|
|
68
|
+
"premium": "opus"
|
|
69
|
+
},
|
|
70
|
+
"final_review_policy": {
|
|
71
|
+
"default": "premium_whole_diff_when_below_coordinator_tier_touched_code",
|
|
72
|
+
"skip_when": "entire_run_inline_default_at_coordinator_tier"
|
|
73
|
+
},
|
|
74
|
+
"escalation_policy": {
|
|
75
|
+
"max_section_escalations": 1,
|
|
76
|
+
"allowed_hops": {
|
|
77
|
+
"cheap": "basic",
|
|
78
|
+
"basic": "premium"
|
|
79
|
+
},
|
|
80
|
+
"final_review_fix_reverify_passes": 1
|
|
81
|
+
},
|
|
82
|
+
"budget_policy": {
|
|
83
|
+
"cache_hit_rate_source": "measurement_spike_go_marker",
|
|
84
|
+
"default_cache_hit_rate": 0.0,
|
|
85
|
+
"abort_mode": "inline_default"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
62
88
|
}
|
package/smoke-test/SMOKE-TEST.md
CHANGED
|
@@ -445,12 +445,12 @@ and raw protocol noise.** Sensitive values are redacted.
|
|
|
445
445
|
|
|
446
446
|
---
|
|
447
447
|
|
|
448
|
-
## Full
|
|
448
|
+
## Full 55-Tool Smoke Tier Matrix
|
|
449
449
|
|
|
450
450
|
Every registered MCP tool appears **exactly once** below with its smoke tier.
|
|
451
451
|
Tier 4 (mutating/hazardous) tools are **deferred in v1**.
|
|
452
452
|
|
|
453
|
-
Coverage reconciliation: **8 + 18 + 1 +
|
|
453
|
+
Coverage reconciliation: **8 + 18 + 1 + 10 + 18 = 55**.
|
|
454
454
|
|
|
455
455
|
| Tier | Tool | Default action / expected-empty / special handling |
|
|
456
456
|
|---|---|---|
|
|
@@ -482,6 +482,7 @@ Coverage reconciliation: **8 + 18 + 1 + 9 + 17 = 53**.
|
|
|
482
482
|
| Tier 1 | `get_pipeline_recipe` | Read-only; needs a pipeline name. |
|
|
483
483
|
| Tier 2 | `generate_decision_page` | Local-only file-write canary; always run with the verbatim payload above. |
|
|
484
484
|
| Tier 3 | `second_opinion` | Synchronous, token-costing; opt-in. |
|
|
485
|
+
| Tier 3 | `generate_image` | Synchronous, token/credit-costing; spends provider credits; opt-in. |
|
|
485
486
|
| Tier 3 | `request_plan_generation` | Async (ticket-key based); retrieve with `get_plan`; opt-in. |
|
|
486
487
|
| Tier 3 | `request_architecture` | Async (ticket-key based); retrieve with `get_architecture`; opt-in. |
|
|
487
488
|
| Tier 3 | `request_clarifying_questions` | Async (ticket-key based); retrieve with `get_clarifying_questions`; opt-in. |
|
|
@@ -507,3 +508,4 @@ Coverage reconciliation: **8 + 18 + 1 + 9 + 17 = 53**.
|
|
|
507
508
|
| Tier 4 | `regenerate_directory_map` | Hazardous; deferred in v1. |
|
|
508
509
|
| Tier 4 | `run_full_automation` | Orchestration (dispatches mutating child pipelines / spawns worktrees); deferred in v1. |
|
|
509
510
|
| Tier 4 | `resume_full_automation` | Orchestration; deferred in v1. |
|
|
511
|
+
| Tier 4 | `record_tiered_section_metric` | Writes server-side telemetry state (tiered_section_metrics row); deferred in v1. |
|