@bridge_gpt/mcp-server 0.2.60 → 0.2.62
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 +16 -8
- package/build/commands.generated.js +3 -3
- package/build/conductor/bridge-api-client.js +353 -2
- package/build/conductor/merge-execution-contract.js +30 -5
- package/build/conductor/merge-execution-eligibility.js +10 -9
- package/build/conductor/readiness-sections.js +99 -16
- package/build/conductor/readiness.js +108 -15
- package/build/credential-store.js +156 -0
- package/build/doctor.js +94 -6
- package/build/drive-epic.js +124 -12
- package/build/epic-implementer-bin.js +13 -13
- package/build/epic-integration-pr.js +61 -15
- package/build/epic-launch-profile.js +455 -0
- package/build/executor/cli.js +9 -0
- package/build/executor/credentials.js +17 -1
- package/build/executor/http-client.js +45 -1
- package/build/executor/integration-job.js +759 -0
- package/build/executor/job-runner.js +92 -9
- package/build/executor/observation.js +114 -7
- package/build/executor/runner.js +101 -1
- package/build/executor/types.js +43 -0
- package/build/index.js +338 -114
- package/build/install-bridge-conductor.js +398 -6
- package/build/install-bridge.js +92 -16
- package/build/merge-workflow-config.js +54 -0
- package/build/merge-workflow-drift.js +35 -4
- package/build/merge-workflow.js +386 -2
- package/build/pipelines.generated.js +1 -1
- package/build/plane/supervisor.js +6 -0
- package/build/readme.generated.js +1 -1
- package/build/setup-epic.js +103 -32
- package/build/version.generated.js +3 -3
- package/package.json +1 -1
package/build/setup-epic.js
CHANGED
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
import { readFile as fsReadFile, stat as fsStat } from "node:fs/promises";
|
|
79
79
|
import os from "node:os";
|
|
80
80
|
import { createProductionEpicIntegrationGhRunner, ensureEpicIntegrationPullRequest, formatEpicIntegrationPullRequestOutcome, } from "./epic-integration-pr.js";
|
|
81
|
-
import { approveEpicPlan, buildConductorJiraUrl, conductorGetHeaders, createEpicRunWithDisposition, fetchConductorReadiness, fetchEpicRunState, replaceEpicRunPolicy, resolveConductorBridgeApiAccess, storeEpicPlan, validateEpicPlan, ConductorBridgeApiError, } from "./conductor/bridge-api-client.js";
|
|
81
|
+
import { approveEpicPlan, buildConductorJiraUrl, conductorGetHeaders, createEpicRunWithDisposition, decodeCanonicalProvenance, fetchConductorReadiness, fetchEpicRunState, replaceEpicRunPolicy, resolveConductorBridgeApiAccess, resolveEpicLaunchBridgeApiAccess, storeEpicPlan, validateEpicPlan, ConductorBridgeApiError, } from "./conductor/bridge-api-client.js";
|
|
82
82
|
// BAPI-1133 (A2) — the single legacy-to-typed merge-execution-mode mapping and
|
|
83
83
|
// its total legacy resolver live in `merge-pull-request.ts` (no import cycle:
|
|
84
84
|
// that module never imports from `setup-epic.ts`). Reused here rather than
|
|
@@ -97,7 +97,7 @@ import { validateBranchName } from "./base-ref.js";
|
|
|
97
97
|
// conductor can drift on a field name or an endpoint shape. No MCP tool, no
|
|
98
98
|
// input-schema field, and no description changes.
|
|
99
99
|
import { getConfigFieldBaseBranch, getIndexScopeLifecycle, getParseStatus, } from "./epic-shared/bridge-client.js";
|
|
100
|
-
import { boundScopeLifecycleLabel, createExecFileRunCommand, ensureCommitResolvableLocally,
|
|
100
|
+
import { boundScopeLifecycleLabel, createExecFileRunCommand, ensureCommitResolvableLocally, performExactIndexScopeCut, pollIndexScopeLifecycle, readRemoteBranchHead, runGit, SCOPE_BOOTSTRAP_POLL_INTERVAL_MS, SCOPE_LIFECYCLE_LABELS, } from "./epic-shared/cut-protocol.js";
|
|
101
101
|
import { hashPlan } from "./conductor/plan.js";
|
|
102
102
|
import { BRING_UP_REFUSAL_MESSAGES, firstBringUpRefusal, } from "./conductor/bring-up-facts.js";
|
|
103
103
|
import { MCP_PACKAGE_NAME } from "./mcp-identity.js";
|
|
@@ -148,6 +148,16 @@ export const SETUP_EPIC_AUTO_MERGE_POLICY_KEY = "v2_auto_merge_enabled";
|
|
|
148
148
|
* neither changes merge execution until a later A2 child.
|
|
149
149
|
*/
|
|
150
150
|
export const SETUP_EPIC_MERGE_EXECUTION_MODE_POLICY_KEY = "merge_execution_mode";
|
|
151
|
+
/**
|
|
152
|
+
* BAPI-1259 — the opt-in for automatic integration-PR preparation. Written into
|
|
153
|
+
* the UNATTENDED epic-branch default only (fill-if-absent), so a run the
|
|
154
|
+
* operator starts unattended is prepared and handed off without a manual base
|
|
155
|
+
* merge or a manual un-draft. Attended runs, `--into-base` runs, and runs whose
|
|
156
|
+
* `--policy-file` already declares the key keep exactly what they had; a run
|
|
157
|
+
* approved before this key existed is never changed retroactively.
|
|
158
|
+
*/
|
|
159
|
+
export const SETUP_EPIC_INTEGRATION_PREPARATION_POLICY_KEY = "integration_preparation";
|
|
160
|
+
const SETUP_EPIC_INTEGRATION_PREPARATION_DEFAULT = { enabled: true };
|
|
151
161
|
/** Accepted `policy_json.review_policy.source` values (the `ReviewPolicy` surface). */
|
|
152
162
|
export const SETUP_EPIC_REVIEW_POLICY_SOURCES = [
|
|
153
163
|
"verdict_protocol",
|
|
@@ -249,6 +259,10 @@ export function getSetupEpicUsage() {
|
|
|
249
259
|
" sets no review policy of its own, so a value supplied",
|
|
250
260
|
" here always wins.",
|
|
251
261
|
" --json Emit a single JSON result object on stdout",
|
|
262
|
+
" --launch-profile <name> (BAPI-1260) Resolve the target, repository, and bound",
|
|
263
|
+
" credential from this host-local launch profile. Passed",
|
|
264
|
+
" by drive-epic; there is no production default with it.",
|
|
265
|
+
" --base-url <url> (BAPI-1260) Explicit target; must agree with the profile.",
|
|
252
266
|
" -h, --help Show this help",
|
|
253
267
|
"",
|
|
254
268
|
"Policy controls:",
|
|
@@ -349,6 +363,8 @@ export function parseSetupEpicArgs(argv) {
|
|
|
349
363
|
let localOnly = false;
|
|
350
364
|
let dryRun = false;
|
|
351
365
|
let json = false;
|
|
366
|
+
let launchProfile;
|
|
367
|
+
let baseUrl;
|
|
352
368
|
for (let i = 0; i < argv.length; i++) {
|
|
353
369
|
const arg = argv[i];
|
|
354
370
|
// `--policy-file=<path>` inline form (BAPI-754).
|
|
@@ -450,6 +466,19 @@ export function parseSetupEpicArgs(argv) {
|
|
|
450
466
|
i++;
|
|
451
467
|
break;
|
|
452
468
|
}
|
|
469
|
+
// BAPI-1260 — the launch selection forwarded by drive-epic.
|
|
470
|
+
case "--launch-profile":
|
|
471
|
+
case "--base-url": {
|
|
472
|
+
const v = takeValue(argv, i, arg);
|
|
473
|
+
if (v === null || v.trim() === "")
|
|
474
|
+
return { status: "error", message: `${arg} requires a value.` };
|
|
475
|
+
if (arg === "--launch-profile")
|
|
476
|
+
launchProfile = v.trim();
|
|
477
|
+
else
|
|
478
|
+
baseUrl = v.trim();
|
|
479
|
+
i++;
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
453
482
|
case "--into-base":
|
|
454
483
|
intoBase = true;
|
|
455
484
|
break;
|
|
@@ -531,6 +560,9 @@ export function parseSetupEpicArgs(argv) {
|
|
|
531
560
|
localOnly,
|
|
532
561
|
dryRun,
|
|
533
562
|
json,
|
|
563
|
+
// BAPI-1260 — only when supplied, so a legacy options object is unchanged.
|
|
564
|
+
...(launchProfile ? { launchProfile } : {}),
|
|
565
|
+
...(baseUrl ? { baseUrl } : {}),
|
|
534
566
|
},
|
|
535
567
|
};
|
|
536
568
|
}
|
|
@@ -1367,9 +1399,10 @@ export function requestedPolicyIsUnattended(policy, attended) {
|
|
|
1367
1399
|
* requested `review_policy`, and nothing else. Byte-identical to the
|
|
1368
1400
|
* pre-BAPI-1102 composition, which is precisely what the opt-out promises.
|
|
1369
1401
|
* * **Feature branch, default** → adds `posture: "unattended"`,
|
|
1370
|
-
* `v2_auto_merge_enabled: true`,
|
|
1402
|
+
* `v2_auto_merge_enabled: true`, (BAPI-1133, A2) `merge_execution_mode`
|
|
1371
1403
|
* when the caller resolved one — the server refuses an unattended auto-merge
|
|
1372
|
-
* policy that omits it
|
|
1404
|
+
* policy that omits it — and (BAPI-1259) `integration_preparation:
|
|
1405
|
+
* { enabled: true }`, so the run prepares its own integration PR.
|
|
1373
1406
|
*
|
|
1374
1407
|
* Deliberately absent from every shape:
|
|
1375
1408
|
*
|
|
@@ -1394,6 +1427,9 @@ export function composeDefaultSetupEpicPolicy(args) {
|
|
|
1394
1427
|
if (args.mergeExecutionMode !== undefined) {
|
|
1395
1428
|
policy[SETUP_EPIC_MERGE_EXECUTION_MODE_POLICY_KEY] = args.mergeExecutionMode;
|
|
1396
1429
|
}
|
|
1430
|
+
policy[SETUP_EPIC_INTEGRATION_PREPARATION_POLICY_KEY] = {
|
|
1431
|
+
...SETUP_EPIC_INTEGRATION_PREPARATION_DEFAULT,
|
|
1432
|
+
};
|
|
1397
1433
|
}
|
|
1398
1434
|
}
|
|
1399
1435
|
if (args.reviewPolicy !== undefined) {
|
|
@@ -1465,6 +1501,11 @@ export function applySetupEpicUnattendedDefault(policy, args) {
|
|
|
1465
1501
|
args.mergeExecutionMode !== undefined) {
|
|
1466
1502
|
composed[SETUP_EPIC_MERGE_EXECUTION_MODE_POLICY_KEY] = args.mergeExecutionMode;
|
|
1467
1503
|
}
|
|
1504
|
+
if (!(SETUP_EPIC_INTEGRATION_PREPARATION_POLICY_KEY in composed)) {
|
|
1505
|
+
composed[SETUP_EPIC_INTEGRATION_PREPARATION_POLICY_KEY] = {
|
|
1506
|
+
...SETUP_EPIC_INTEGRATION_PREPARATION_DEFAULT,
|
|
1507
|
+
};
|
|
1508
|
+
}
|
|
1468
1509
|
return composed;
|
|
1469
1510
|
}
|
|
1470
1511
|
/**
|
|
@@ -1654,14 +1695,51 @@ export function resolveEffectiveFeatureBranch(featureBranch, requestedPolicy) {
|
|
|
1654
1695
|
return trimmed;
|
|
1655
1696
|
}
|
|
1656
1697
|
/**
|
|
1657
|
-
*
|
|
1658
|
-
*
|
|
1698
|
+
* BAPI-1252: the operator sentence for each canonical refusal. Every one names
|
|
1699
|
+
* the situation and what to do; none names a SHA, generation, or server error.
|
|
1700
|
+
*/
|
|
1701
|
+
export function canonicalRefusalMessage(repoName, reason) {
|
|
1702
|
+
switch (reason) {
|
|
1703
|
+
case "canonical_capability_unsupported":
|
|
1704
|
+
return (`The Bridge server for ${repoName} did not report verified canonical index provenance ` +
|
|
1705
|
+
`(it predates this contract, or sent a value this CLI cannot verify). Upgrade the ` +
|
|
1706
|
+
`server; a cut is never authorized from the legacy indexed commit.`);
|
|
1707
|
+
case "canonical_index_unverified":
|
|
1708
|
+
return (`${SETUP_EPIC_PARSE_FIRST_MESSAGE}: the canonical index for ${repoName} has no verified ` +
|
|
1709
|
+
`generation (legacy, interrupted, or still-writing content is never trusted), so there ` +
|
|
1710
|
+
`is no commit to cut the feature branch at.`);
|
|
1711
|
+
case "canonical_source_missing":
|
|
1712
|
+
return (`${SETUP_EPIC_PARSE_FIRST_MESSAGE}: the last canonical parse of ${repoName} observed no ` +
|
|
1713
|
+
`source commit (for example it parsed a supplied directory), so its content cannot be ` +
|
|
1714
|
+
`verified. Re-parse it from its remote.`);
|
|
1715
|
+
case "canonical_manifest_mismatch":
|
|
1716
|
+
return (`The canonical index content for ${repoName} no longer matches its verified manifest ` +
|
|
1717
|
+
`and has been marked unverified. Re-parse the repository before cutting.`);
|
|
1718
|
+
case "canonical_generation_mismatch":
|
|
1719
|
+
case "canonical_index_advanced":
|
|
1720
|
+
return (`The canonical index for ${repoName} advanced while it was being checked. Retry once ` +
|
|
1721
|
+
`the current parse finishes.`);
|
|
1722
|
+
case "canonical_validity_unavailable":
|
|
1723
|
+
default:
|
|
1724
|
+
return (`The canonical validity for ${repoName} could not be read. Retry — this is not ` +
|
|
1725
|
+
`evidence the repository is unindexed.`);
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
/**
|
|
1729
|
+
* Read canonical parse truth and require AFFIRMATIVE verified provenance — the
|
|
1730
|
+
* commit `origin/<feature>` will be cut at (BAPI-1252).
|
|
1731
|
+
*
|
|
1732
|
+
* The cut commit is the server's VERIFIED canonical source SHA, decoded through
|
|
1733
|
+
* `decodeCanonicalProvenance`. Lifecycle fields (`status`, `indexed_commit_sha`)
|
|
1734
|
+
* are display history and are never consulted: a `succeeded` row can describe a
|
|
1735
|
+
* newer-created parse whose content the index does not hold. An absent field
|
|
1736
|
+
* (an older server), an unknown state, a read failure, or an unverified
|
|
1737
|
+
* generation all refuse before any branch or run mutation.
|
|
1659
1738
|
*
|
|
1660
1739
|
* Fails CLOSED (ratified R-2). The first line of every refusal is the exact
|
|
1661
|
-
* operator instruction; the closing
|
|
1662
|
-
* UNREADABLE status is kept distinct from an
|
|
1663
|
-
* is not evidence the repository is unindexed
|
|
1664
|
-
* re-index would send them to re-parse a repository that may be fine.
|
|
1740
|
+
* operator instruction; the closing line states what did NOT happen. An
|
|
1741
|
+
* UNREADABLE status is kept distinct from an unverified one — "could not read"
|
|
1742
|
+
* is not evidence the repository is unindexed.
|
|
1665
1743
|
*/
|
|
1666
1744
|
export async function readCanonicalParseTruth(access, fetchImpl) {
|
|
1667
1745
|
const notCreated = [
|
|
@@ -1678,30 +1756,14 @@ export async function readCanonicalParseTruth(access, fetchImpl) {
|
|
|
1678
1756
|
],
|
|
1679
1757
|
};
|
|
1680
1758
|
}
|
|
1681
|
-
|
|
1759
|
+
const evidence = decodeCanonicalProvenance(parse.value);
|
|
1760
|
+
if (!evidence.verified) {
|
|
1682
1761
|
return {
|
|
1683
1762
|
ok: false,
|
|
1684
|
-
lines: [
|
|
1685
|
-
`${SETUP_EPIC_PARSE_FIRST_MESSAGE}: the canonical index for ${access.repoName} has no ` +
|
|
1686
|
-
`successful parse (status: ${String(parse.value.status)}), so there is no commit to ` +
|
|
1687
|
-
`cut the feature branch at.`,
|
|
1688
|
-
...notCreated,
|
|
1689
|
-
],
|
|
1763
|
+
lines: [canonicalRefusalMessage(access.repoName, evidence.reason), ...notCreated],
|
|
1690
1764
|
};
|
|
1691
1765
|
}
|
|
1692
|
-
|
|
1693
|
-
if (indexed === null) {
|
|
1694
|
-
return {
|
|
1695
|
-
ok: false,
|
|
1696
|
-
lines: [
|
|
1697
|
-
`${SETUP_EPIC_PARSE_FIRST_MESSAGE}: the canonical index for ${access.repoName} published ` +
|
|
1698
|
-
`no commit for its last successful parse, so there is no commit to cut the feature ` +
|
|
1699
|
-
`branch at.`,
|
|
1700
|
-
...notCreated,
|
|
1701
|
-
],
|
|
1702
|
-
};
|
|
1703
|
-
}
|
|
1704
|
-
return { ok: true, cutCommitSha: indexed };
|
|
1766
|
+
return { ok: true, cutCommitSha: evidence.sourceCommitSha };
|
|
1705
1767
|
}
|
|
1706
1768
|
/** The strict subset of `SetupEpicDeps` the shared cut protocol consumes. */
|
|
1707
1769
|
function cutProtocolDeps(deps, runCommand) {
|
|
@@ -1936,7 +1998,10 @@ async function executeSetupEpic(argv, overrides, runIdSink) {
|
|
|
1936
1998
|
return 0;
|
|
1937
1999
|
}
|
|
1938
2000
|
// --- Resolve access ------------------------------------------------------
|
|
1939
|
-
|
|
2001
|
+
// BAPI-1260: a caller that selected the epic-launch contract (drive-epic
|
|
2002
|
+
// forwards --launch-profile / --base-url) gets the target-first resolver and
|
|
2003
|
+
// the bound credential; the legacy resolver is kept byte-for-byte otherwise.
|
|
2004
|
+
const accessDeps = {
|
|
1940
2005
|
env: deps.env,
|
|
1941
2006
|
cwd: deps.cwd,
|
|
1942
2007
|
homedir: deps.homedir,
|
|
@@ -1944,7 +2009,13 @@ async function executeSetupEpic(argv, overrides, runIdSink) {
|
|
|
1944
2009
|
readFile: deps.readFile,
|
|
1945
2010
|
stat: deps.stat,
|
|
1946
2011
|
repoName: opts.repo,
|
|
1947
|
-
}
|
|
2012
|
+
};
|
|
2013
|
+
const accessResult = opts.launchProfile !== undefined || opts.baseUrl !== undefined
|
|
2014
|
+
? await resolveEpicLaunchBridgeApiAccess({
|
|
2015
|
+
...(opts.launchProfile ? { profileName: opts.launchProfile } : {}),
|
|
2016
|
+
...(opts.baseUrl ? { baseUrl: opts.baseUrl } : {}),
|
|
2017
|
+
}, accessDeps)
|
|
2018
|
+
: await resolveConductorBridgeApiAccess(accessDeps);
|
|
1948
2019
|
if (!accessResult.ok) {
|
|
1949
2020
|
deps.errorLog(`Cannot reach the Bridge API: ${accessResult.error}`);
|
|
1950
2021
|
return 1;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// AUTO-GENERATED — do not edit manually. Regenerate with: npm run build
|
|
2
|
-
export const VERSION = "0.2.
|
|
3
|
-
export const BUILD_COMMIT = "
|
|
4
|
-
export const LAUNCHER_ARGS = ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.
|
|
2
|
+
export const VERSION = "0.2.62";
|
|
3
|
+
export const BUILD_COMMIT = "9351fac413bf";
|
|
4
|
+
export const LAUNCHER_ARGS = ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.62", "serve"];
|