@bridge_gpt/mcp-server 0.2.60 → 0.2.65
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 +58 -11
- package/build/agent-launchers/claude-executor-adapter.js +134 -3
- package/build/agent-launchers/executor-adapter.js +54 -2
- package/build/agents.generated.js +10 -1
- package/build/bounded-wait.js +32 -1
- package/build/commands.generated.js +8 -7
- package/build/conductor/bridge-api-client.js +678 -14
- package/build/conductor/bring-up-facts.js +3 -1
- package/build/conductor/doctor.js +23 -14
- package/build/conductor/epic-child-continuation.js +324 -0
- package/build/conductor/epic-implementer-cli.js +142 -17
- package/build/conductor/git-hooks.js +529 -118
- package/build/conductor/hook-runtime-qualification.js +340 -0
- package/build/conductor/merge-execution-contract.js +30 -5
- package/build/conductor/merge-execution-eligibility.js +10 -9
- package/build/conductor/readiness-sections.js +104 -20
- package/build/conductor/readiness.js +129 -25
- package/build/conductor/recovery-cli.js +354 -13
- package/build/conductor/recovery-operations.js +251 -5
- package/build/conductor/repair-contract.js +8 -0
- package/build/conductor-bundle-artifacts.js +1 -0
- package/build/credential-store.js +194 -0
- package/build/docs.generated.js +2 -1
- package/build/doctor.js +161 -7
- package/build/drive-epic-key.js +12 -0
- package/build/drive-epic.js +1318 -111
- package/build/epic-coherence-input-cli.js +137 -0
- package/build/epic-coherence-input.js +920 -0
- package/build/epic-coherence-input.test-fixtures.js +175 -0
- package/build/epic-implementer-bin.js +35 -29
- package/build/epic-implementer-bundle-cli.js +14 -1
- package/build/epic-integration-pr.js +61 -15
- package/build/epic-launch-profile.js +464 -0
- package/build/epic-run-status.js +5 -0
- package/build/epic-shared/bridge-client.js +46 -4
- package/build/executor/cli.js +48 -0
- package/build/executor/completion-contract.js +423 -0
- package/build/executor/completion-supervision.js +286 -0
- package/build/executor/credentials.js +19 -1
- package/build/executor/deps.js +65 -1
- package/build/executor/env.js +6 -0
- package/build/executor/heartbeat.js +13 -3
- package/build/executor/http-client.js +117 -1
- package/build/executor/integration-job.js +759 -0
- package/build/executor/job-errors.js +48 -0
- package/build/executor/job-runner.js +1386 -35
- package/build/executor/job-types.js +10 -2
- package/build/executor/observation.js +114 -7
- package/build/executor/preflight.js +99 -0
- package/build/executor/process-containment.js +756 -0
- package/build/executor/process.js +235 -5
- package/build/executor/prompt-spec.js +262 -1
- package/build/executor/provider-checks.js +69 -0
- package/build/executor/rebase-finalization.js +351 -0
- package/build/executor/reconcile-overlap-job.js +77 -84
- package/build/executor/required-verification.js +313 -0
- package/build/executor/required-work-ledger.js +1121 -0
- package/build/executor/results.js +142 -0
- package/build/executor/resume-pre-spawn.js +87 -4
- package/build/executor/runner.js +246 -1
- package/build/executor/test-declaration.js +20 -0
- package/build/executor/types.js +55 -0
- package/build/executor/worker-command.js +49 -13
- package/build/executor/worker-finalization.js +88 -11
- package/build/executor/worker-guard-hook.js +29 -4
- package/build/executor/worktree.js +13 -0
- package/build/executor-launch.js +658 -0
- package/build/index.js +772 -954
- package/build/install-bridge-conductor.js +622 -40
- package/build/install-bridge.js +92 -16
- package/build/merge-pull-request.js +1 -1
- 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 +9 -8
- package/build/plan-discovery.js +137 -0
- package/build/plan-epic-implementer-eligibility.js +2 -2
- package/build/plane/cli.js +37 -3
- package/build/plane/member-logs.js +3 -0
- package/build/plane/member-roster.js +7 -1
- package/build/plane/shutdown.js +59 -1
- package/build/plane/supervisor.js +148 -0
- package/build/readme.generated.js +1 -1
- package/build/scripts/executor-protocol-contract-driver.js +13 -3
- package/build/setup-epic.js +130 -48
- package/build/version.generated.js +3 -3
- package/build/worker-guard-hook-bin.js +2 -2
- package/docs/CONDUCTOR.md +116 -2
- package/package.json +2 -1
package/build/install-bridge.js
CHANGED
|
@@ -325,7 +325,11 @@ export const INSTALL_BRIDGE_AGENT_PROMPT = "Run /install-bridge now, with no arg
|
|
|
325
325
|
"do' line. The server decides eligibility (repository state AND whether this caller can run the " +
|
|
326
326
|
"command), so do NOT apply a role rule or a learned-state rule of your own. Do NOT run the " +
|
|
327
327
|
"returned command yourself — only recommend it; running it is the human's next explicit " +
|
|
328
|
-
"invocation.
|
|
328
|
+
"invocation. When you recommend a command and `next_step.command_context` is a non-empty " +
|
|
329
|
+
"string, print it verbatim on its own line directly under the command — it is the server's " +
|
|
330
|
+
"explanation of what the command gives the human and how long it takes; do not reword, shorten, " +
|
|
331
|
+
"or extend it, and render nothing in its place when it is empty or missing. " +
|
|
332
|
+
"For other supporting context around a recommended command, use the manifest's own " +
|
|
329
333
|
"next_step.post_install_indexing and next_step.post_install_scheduler text rather than inventing " +
|
|
330
334
|
"an explanation for it. " +
|
|
331
335
|
"Never request, echo, or transport any credential — only ever direct the human to that " +
|
|
@@ -1943,21 +1947,34 @@ export async function resolveSignupEmail(options, deps) {
|
|
|
1943
1947
|
if (typeof fromEnv === "string" && fromEnv.trim().length > 0) {
|
|
1944
1948
|
return { ok: true, value: fromEnv.trim() };
|
|
1945
1949
|
}
|
|
1950
|
+
const entered = await promptForBoundedEmail(deps, "Email for Bridge workspace setup (required): ");
|
|
1951
|
+
if (entered === undefined)
|
|
1952
|
+
return { ok: false, error: "No email entered." };
|
|
1953
|
+
return { ok: true, value: entered };
|
|
1954
|
+
}
|
|
1955
|
+
/**
|
|
1956
|
+
* The bounded interactive email prompt shared by self-serve signup
|
|
1957
|
+
* ({@link resolveSignupEmail}) and invite redemption (BAPI-1263). Two reads at
|
|
1958
|
+
* most: the first answer, then ONE re-prompt after a single hint line. EOF
|
|
1959
|
+
* resolves as an empty value (promptLineViaReadline resolves "" on close), which
|
|
1960
|
+
* fails the shape check like any other blank answer, so it costs one re-prompt and
|
|
1961
|
+
* then fails cleanly rather than hanging. Returns the trimmed (case-preserved)
|
|
1962
|
+
* address, or `undefined` after two invalid answers. The answer is never echoed.
|
|
1963
|
+
* The caller guarantees `deps.promptLine` exists.
|
|
1964
|
+
*/
|
|
1965
|
+
async function promptForBoundedEmail(deps, promptText) {
|
|
1946
1966
|
const promptLine = deps.promptLine;
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
// resolves "" on close), which fails the shape check like any other blank
|
|
1950
|
-
// answer, so it costs one re-prompt and then fails cleanly rather than hanging.
|
|
1967
|
+
if (!promptLine)
|
|
1968
|
+
return undefined;
|
|
1951
1969
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
1952
|
-
const raw = await promptLine(
|
|
1970
|
+
const raw = await promptLine(promptText);
|
|
1953
1971
|
const entered = String(raw ?? "").trim();
|
|
1954
|
-
if (INSTALL_BRIDGE_SIGNUP_EMAIL_SHAPE.test(entered))
|
|
1955
|
-
return
|
|
1956
|
-
}
|
|
1972
|
+
if (INSTALL_BRIDGE_SIGNUP_EMAIL_SHAPE.test(entered))
|
|
1973
|
+
return entered;
|
|
1957
1974
|
if (attempt === 0)
|
|
1958
1975
|
deps.log(INSTALL_BRIDGE_SIGNUP_EMAIL_HINT);
|
|
1959
1976
|
}
|
|
1960
|
-
return
|
|
1977
|
+
return undefined;
|
|
1961
1978
|
}
|
|
1962
1979
|
/**
|
|
1963
1980
|
* Select the onboarding branch as pure logic (deterministic, no I/O, no prompt):
|
|
@@ -3428,15 +3445,21 @@ export function buildBootstrapExchangeUrl(baseUrl) {
|
|
|
3428
3445
|
* POST the bootstrap-invite exchange. The token and `key_secret` travel ONLY in
|
|
3429
3446
|
* the JSON request body (never a query string, never a header, never a log line).
|
|
3430
3447
|
* Bounded by the same 10s timeout as the connectivity ping.
|
|
3448
|
+
*
|
|
3449
|
+
* BAPI-1263: an optional nonempty `email` is appended as a fourth body field, used
|
|
3450
|
+
* only on the retry after an `email-required` refusal. Omitted or empty, the body is
|
|
3451
|
+
* the legacy three-field one, byte for byte.
|
|
3431
3452
|
*/
|
|
3432
|
-
export async function exchangeBootstrapInvite(deps, baseUrl, token, repoName, keySecret) {
|
|
3453
|
+
export async function exchangeBootstrapInvite(deps, baseUrl, token, repoName, keySecret, email) {
|
|
3433
3454
|
const url = buildBootstrapExchangeUrl(baseUrl);
|
|
3434
3455
|
let resp;
|
|
3435
3456
|
try {
|
|
3436
3457
|
resp = await deps.fetch(url, {
|
|
3437
3458
|
method: "POST",
|
|
3438
3459
|
headers: { "Content-Type": "application/json" },
|
|
3439
|
-
body: JSON.stringify(
|
|
3460
|
+
body: JSON.stringify(email
|
|
3461
|
+
? { token, repo_name: repoName, key_secret: keySecret, email }
|
|
3462
|
+
: { token, repo_name: repoName, key_secret: keySecret }),
|
|
3440
3463
|
signal: AbortSignal.timeout(10_000),
|
|
3441
3464
|
});
|
|
3442
3465
|
}
|
|
@@ -3490,12 +3513,42 @@ export async function exchangeBootstrapInvite(deps, baseUrl, token, repoName, ke
|
|
|
3490
3513
|
if (resp.status === 401) {
|
|
3491
3514
|
return { ok: false, kind: "invalid-invite", message: `The Bridge API rejected the bootstrap invite (HTTP ${resp.status}).` };
|
|
3492
3515
|
}
|
|
3516
|
+
if (resp.status === 426) {
|
|
3517
|
+
// Only the exact `email_required` refusal is recognized; any other, absent, or
|
|
3518
|
+
// unreadable 426 body stays on the generic failure path below. The message is
|
|
3519
|
+
// installer-owned — nothing from the response is propagated.
|
|
3520
|
+
let recognized = false;
|
|
3521
|
+
try {
|
|
3522
|
+
const body = (await resp.json());
|
|
3523
|
+
recognized = body?.detail?.error === "email_required";
|
|
3524
|
+
}
|
|
3525
|
+
catch {
|
|
3526
|
+
recognized = false;
|
|
3527
|
+
}
|
|
3528
|
+
if (recognized) {
|
|
3529
|
+
return {
|
|
3530
|
+
ok: false,
|
|
3531
|
+
kind: "email-required",
|
|
3532
|
+
message: "The Bridge API requires an email address to redeem this invite.",
|
|
3533
|
+
};
|
|
3534
|
+
}
|
|
3535
|
+
}
|
|
3493
3536
|
return {
|
|
3494
3537
|
ok: false,
|
|
3495
3538
|
kind: "failed",
|
|
3496
3539
|
message: `The bootstrap exchange failed (HTTP ${resp.status}). Verify BAPI_BASE_URL and try again.`,
|
|
3497
3540
|
};
|
|
3498
3541
|
}
|
|
3542
|
+
/** The invite-email prompt (BAPI-1263), shown once after an `email_required` refusal. */
|
|
3543
|
+
const INVITE_EMAIL_PROMPT = "Email for this Bridge invite (required): ";
|
|
3544
|
+
/** BAPI-1263: fixed, secret-free failures for the invite email recovery. */
|
|
3545
|
+
export const INVITE_EMAIL_REQUIRED_NON_INTERACTIVE_MESSAGE = "Error: this invite needs an email address, and there is no interactive terminal to ask for it. " +
|
|
3546
|
+
`The bootstrap invite has NOT been used. Re-run \`npx -y ${MCP_PACKAGE_NAME} install\` in an ` +
|
|
3547
|
+
"interactive terminal.";
|
|
3548
|
+
export const INVITE_EMAIL_INVALID_ANSWERS_MESSAGE = "Error: no valid email address was entered. The bootstrap invite has NOT been used. Re-run " +
|
|
3549
|
+
"install and enter an address like you@example.com.";
|
|
3550
|
+
export const INVITE_EMAIL_REPEATED_REFUSAL_MESSAGE = "Error: the Bridge API still requires an email address after one was entered. The bootstrap " +
|
|
3551
|
+
"invite has NOT been used. Re-run install, or contact support if this repeats.";
|
|
3499
3552
|
// ---------------------------------------------------------------------------
|
|
3500
3553
|
// Self-serve mint (BAPI-618): email -> invite token
|
|
3501
3554
|
// ---------------------------------------------------------------------------
|
|
@@ -6014,12 +6067,35 @@ export async function runInstallBridgeCli(argv, overrides = {}) {
|
|
|
6014
6067
|
// self-serve record — once more with a freshly minted token (R4-3).
|
|
6015
6068
|
let exchange;
|
|
6016
6069
|
let selfServeRefreshed = false;
|
|
6070
|
+
// BAPI-1263: the email typed after an `email_required` refusal. Run-local only —
|
|
6071
|
+
// never persisted, logged, or written to the pending record — and carried on
|
|
6072
|
+
// every later ordinary-invite exchange, including after a 409 rename.
|
|
6073
|
+
let inviteEmail;
|
|
6017
6074
|
for (;;) {
|
|
6018
|
-
exchange = await exchangeBootstrapInvite(deps, baseUrl, inviteToken, repoName, keySecret);
|
|
6075
|
+
exchange = await exchangeBootstrapInvite(deps, baseUrl, inviteToken, repoName, keySecret, inviteEmail);
|
|
6019
6076
|
// 409 repo_name_taken: the server ROLLED BACK, so the invite is NOT consumed and
|
|
6020
6077
|
// the SAME token can be retried under a new name — with the SAME pending secret,
|
|
6021
|
-
// re-pointed to that name.
|
|
6022
|
-
|
|
6078
|
+
// re-pointed to that name. The same loop handles an ordinary invite's 426
|
|
6079
|
+
// `email_required` (BAPI-1263), so a 409 on the email-bearing retry re-enters
|
|
6080
|
+
// the rename branch without an extra exchange request.
|
|
6081
|
+
while (!exchange.ok &&
|
|
6082
|
+
(exchange.kind === "repo-name-taken" ||
|
|
6083
|
+
(exchange.kind === "email-required" && !selfServeSignupMode))) {
|
|
6084
|
+
if (exchange.kind === "email-required") {
|
|
6085
|
+
if (inviteEmail !== undefined) {
|
|
6086
|
+
return fatal(INVITE_EMAIL_REPEATED_REFUSAL_MESSAGE);
|
|
6087
|
+
}
|
|
6088
|
+
if (!deps.isTTY || !deps.promptLine) {
|
|
6089
|
+
return fatal(INVITE_EMAIL_REQUIRED_NON_INTERACTIVE_MESSAGE);
|
|
6090
|
+
}
|
|
6091
|
+
const typedEmail = await promptForBoundedEmail(deps, INVITE_EMAIL_PROMPT);
|
|
6092
|
+
if (typedEmail === undefined) {
|
|
6093
|
+
return fatal(INVITE_EMAIL_INVALID_ANSWERS_MESSAGE);
|
|
6094
|
+
}
|
|
6095
|
+
inviteEmail = typedEmail;
|
|
6096
|
+
exchange = await exchangeBootstrapInvite(deps, baseUrl, inviteToken, repoName, keySecret, inviteEmail);
|
|
6097
|
+
continue;
|
|
6098
|
+
}
|
|
6023
6099
|
if (!deps.isTTY || !deps.promptLine) {
|
|
6024
6100
|
errorLog(`Error: ${exchange.message} Re-run with a different --repo (the bootstrap invite has NOT ` +
|
|
6025
6101
|
"been used).");
|
|
@@ -6046,7 +6122,7 @@ export async function runInstallBridgeCli(argv, overrides = {}) {
|
|
|
6046
6122
|
}
|
|
6047
6123
|
repoName = nextRepo;
|
|
6048
6124
|
// Same token, same key_secret — never regenerated inside the rename loop.
|
|
6049
|
-
exchange = await exchangeBootstrapInvite(deps, baseUrl, inviteToken, repoName, keySecret);
|
|
6125
|
+
exchange = await exchangeBootstrapInvite(deps, baseUrl, inviteToken, repoName, keySecret, inviteEmail);
|
|
6050
6126
|
}
|
|
6051
6127
|
if (exchange.ok)
|
|
6052
6128
|
break;
|
|
@@ -83,7 +83,7 @@ import { resolveLocalMergeMethod, runApprovedLocalMerge, resolveLocalMergeCreden
|
|
|
83
83
|
* The exact remediation for a `dry_run`. Fixed text, because a caller that has to
|
|
84
84
|
* infer WHICH setting to flip from a reason code guesses wrong.
|
|
85
85
|
*/
|
|
86
|
-
const DRY_RUN_HINT = "
|
|
86
|
+
const DRY_RUN_HINT = "auto_merge_enabled is off on the project default; turning it on grants merge authority, so the supervisor-config PUT refuses it (BAPI-1288) — an operator must enable it through the account-settings runbook";
|
|
87
87
|
/**
|
|
88
88
|
* Guidance for a post-dispatch transport failure. The action key makes the request
|
|
89
89
|
* idempotent, so repeating it verbatim is safe and is the ONLY safe move: the merge
|
|
@@ -131,3 +131,57 @@ export const MERGE_COMMAND_FETCH_RESPONSE_FIELDS = [
|
|
|
131
131
|
"execution",
|
|
132
132
|
"lease_expires_at",
|
|
133
133
|
];
|
|
134
|
+
/**
|
|
135
|
+
* The integration-action actor contract the rendered workflow's
|
|
136
|
+
* `integration` job consumes (BAPI-1259).
|
|
137
|
+
*
|
|
138
|
+
* A DEDICATED contract, deliberately not an extension of the merge-command
|
|
139
|
+
* fetch above: an integration action is never a child merge, and a workflow
|
|
140
|
+
* that could interpret one as the other would be one refactor away from
|
|
141
|
+
* merging an integration pull request. The routes are mounted under
|
|
142
|
+
* {@link INTEGRATION_ACTION_PATH_PREFIX} in `api/routes/__init__.py`.
|
|
143
|
+
*
|
|
144
|
+
* The dispatch inputs only wake and correlate: `action_key` carries the
|
|
145
|
+
* server-minted action id (`integ:{repo}:{hex}`) and `lease_owner` carries the
|
|
146
|
+
* server-minted per-claim token. Everything the job acts on — the operation,
|
|
147
|
+
* the exact epic branch, the expected heads — comes from the fetch response.
|
|
148
|
+
*/
|
|
149
|
+
export const INTEGRATION_ACTION_PATH_PREFIX = "/epic-integration-actions";
|
|
150
|
+
/** Re-read the approved work under the dispatched lease. */
|
|
151
|
+
export const INTEGRATION_ACTION_FETCH_PATH = INTEGRATION_ACTION_PATH_PREFIX + "/fetch";
|
|
152
|
+
/** Report bounded facts. Returns an acknowledgement only. */
|
|
153
|
+
export const INTEGRATION_ACTION_REPORT_PATH = INTEGRATION_ACTION_PATH_PREFIX + "/report";
|
|
154
|
+
/** The one protocol version the rendered job speaks (exact equality server-side). */
|
|
155
|
+
export const INTEGRATION_ACTION_PROTOCOL_VERSION = 1;
|
|
156
|
+
/** The dispatch `operation` value that selects the integration job. */
|
|
157
|
+
export const INTEGRATION_ACTION_WORKFLOW_OPERATION = "integration_action";
|
|
158
|
+
/** The dispatch `operation` default that selects the child-merge job. */
|
|
159
|
+
export const CHILD_MERGE_WORKFLOW_OPERATION = "child_merge";
|
|
160
|
+
/**
|
|
161
|
+
* The operations the WORKFLOW may perform. `correct` is absent on purpose: a
|
|
162
|
+
* correction needs a worker, which only a local or durable executor runs, so the
|
|
163
|
+
* server never issues one to the workflow and the job refuses one if it arrives.
|
|
164
|
+
*/
|
|
165
|
+
export const INTEGRATION_WORKFLOW_OPERATIONS = ["sync_base", "mark_ready"];
|
|
166
|
+
/** The request fields of the fetch, in the contract's own spelling. */
|
|
167
|
+
export const INTEGRATION_ACTION_FETCH_REQUEST_FIELDS = [
|
|
168
|
+
"protocol_version",
|
|
169
|
+
"repo_name",
|
|
170
|
+
"action_id",
|
|
171
|
+
"claim_token",
|
|
172
|
+
];
|
|
173
|
+
/** The response fields the rendered job reads from the fetch. */
|
|
174
|
+
export const INTEGRATION_ACTION_FETCH_RESPONSE_FIELDS = [
|
|
175
|
+
"protocol_version",
|
|
176
|
+
"action_id",
|
|
177
|
+
"operation",
|
|
178
|
+
"actor",
|
|
179
|
+
"repo_name",
|
|
180
|
+
"provider_repository",
|
|
181
|
+
"epic_key",
|
|
182
|
+
"epic_branch",
|
|
183
|
+
"base_branch",
|
|
184
|
+
"expected_epic_head_sha",
|
|
185
|
+
"expected_base_sha",
|
|
186
|
+
"pr_number",
|
|
187
|
+
];
|
|
@@ -33,11 +33,42 @@ export function canonicalMergeWorkflowSha() {
|
|
|
33
33
|
* Every Bridge-published historical rendering of the merge workflow, by Git blob
|
|
34
34
|
* SHA, with the contract version it declared.
|
|
35
35
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
36
|
+
* A future contract version adds its predecessor's SHA here, and only then can
|
|
37
|
+
* {@link classifyMergeWorkflowContent} return `managed_version_older`.
|
|
38
|
+
*
|
|
39
|
+
* ## Why a version-1 entry exists without a version bump (BAPI-1257)
|
|
40
|
+
*
|
|
41
|
+
* The first entry is a rendering that was published AS version 1 and then
|
|
42
|
+
* corrected WITHIN version 1. Its fork-origin guard read
|
|
43
|
+
* `jq -r '.isCrossRepository // true'`, and jq's `//` yields its right-hand side
|
|
44
|
+
* when the left is null OR FALSE — so a same-repository pull request, which
|
|
45
|
+
* every epic child is, read as `true` and the merge was refused as fork-origin.
|
|
46
|
+
* That rendering could never merge anything.
|
|
47
|
+
*
|
|
48
|
+
* The marker version is deliberately NOT bumped: the wire contract, the dispatch
|
|
49
|
+
* inputs and the command-fetch protocol are all unchanged, and
|
|
50
|
+
* `MERGE_WORKFLOW_EXPECTED_VERSION` is the server's deploy-ordering check, not a
|
|
51
|
+
* byte checksum. But without this entry a repository holding that rendering
|
|
52
|
+
* classifies as `modified_or_unrecognized`, and the installer's preflight hard
|
|
53
|
+
* refuses to touch a workflow Bridge does not recognise — leaving no automated
|
|
54
|
+
* path off a copy that cannot merge. Registering the superseded SHA restores it:
|
|
55
|
+
* the copy classifies `managed_version_older` and the installer opens its
|
|
56
|
+
* ordinary upgrade pull request.
|
|
57
|
+
*
|
|
58
|
+
* The SHA is the Git blob SHA of the complete superseded rendering, which is
|
|
59
|
+
* what {@link canonicalMergeWorkflowSha} computes for the current one.
|
|
60
|
+
*
|
|
61
|
+
* ## The version-1 entry added by BAPI-1259
|
|
62
|
+
*
|
|
63
|
+
* `0d44c814…` is the last version-1 rendering (the one BAPI-1257 corrected).
|
|
64
|
+
* Contract version 2 adds the `operation` input and the integration job, so a
|
|
65
|
+
* repository holding that rendering is an ordinary managed older version and
|
|
66
|
+
* the installer opens its upgrade pull request.
|
|
39
67
|
*/
|
|
40
|
-
export const MANAGED_MERGE_WORKFLOW_HISTORY = new Map(
|
|
68
|
+
export const MANAGED_MERGE_WORKFLOW_HISTORY = new Map([
|
|
69
|
+
["3d4956c9447223c37075069352cdd9aae2d561dc", 1],
|
|
70
|
+
["0d44c81436005beb3c314de1b98eaf972ef3b4db", 1],
|
|
71
|
+
]);
|
|
41
72
|
/**
|
|
42
73
|
* Classify an installed copy against the canonical bytes.
|
|
43
74
|
*
|