@bridge_gpt/mcp-server 0.2.59 → 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 +181 -51
- package/build/agent-guidance.generated.js +1 -1
- package/build/agent-notes.js +7 -1
- package/build/commands.generated.js +6 -6
- package/build/conductor/bridge-api-client.js +406 -4
- package/build/conductor/doctor.js +255 -53
- package/build/conductor/epic-runtime.js +11 -2
- package/build/conductor/install-doctor.js +24 -2
- package/build/conductor/local-merge.js +319 -26
- package/build/conductor/merge-execution-contract.js +86 -0
- package/build/conductor/merge-execution-eligibility.js +130 -0
- package/build/conductor/readiness-sections.js +256 -16
- package/build/conductor/readiness.js +203 -29
- package/build/conductor/recovery-operations.js +8 -2
- package/build/connect-bitbucket-api.js +6 -1
- package/build/connect-bitbucket.js +398 -88
- package/build/credential-store.js +172 -0
- package/build/docs.generated.js +2 -2
- package/build/doctor.js +277 -15
- package/build/drive-epic.js +147 -12
- package/build/epic-implementer-bin.js +15 -15
- package/build/epic-implementer-claude-hook-bin.js +1 -1
- package/build/epic-implementer-env.js +43 -14
- package/build/epic-integration-pr.js +61 -15
- package/build/epic-launch-profile.js +455 -0
- package/build/executor/ci-rerun-job.js +269 -0
- package/build/executor/cli.js +40 -0
- package/build/executor/credentials.js +28 -1
- package/build/executor/env.js +60 -0
- package/build/executor/http-client.js +45 -1
- package/build/executor/index.js +21 -4
- package/build/executor/integration-job.js +759 -0
- package/build/executor/job-runner.js +218 -9
- package/build/executor/job-types.js +12 -2
- package/build/executor/merge-job.js +11 -2
- package/build/executor/observation.js +114 -7
- package/build/executor/runner.js +101 -1
- package/build/executor/service-lifecycle.js +136 -0
- package/build/executor/service-unit.js +427 -9
- package/build/executor/types.js +48 -0
- package/build/index.js +479 -240
- package/build/install-bridge-conductor.js +599 -14
- package/build/install-bridge.js +448 -46
- package/build/mcp-install-state.js +42 -4
- package/build/merge-pull-request.js +103 -10
- package/build/merge-workflow-codeowners.js +224 -0
- package/build/merge-workflow-config.js +187 -0
- package/build/merge-workflow-drift.js +97 -0
- package/build/merge-workflow-install.js +638 -0
- package/build/merge-workflow.js +956 -0
- package/build/pipelines.generated.js +3 -3
- package/build/plane/cli.js +24 -2
- package/build/plane/preflight.js +68 -0
- package/build/plane/supervisor.js +6 -0
- package/build/readme.generated.js +1 -1
- package/build/run-unit-tests-launcher.js +5 -0
- package/build/setup-epic.js +263 -38
- package/build/version.generated.js +3 -3
- package/package.json +3 -3
- package/build/conduct-epic/bridge-client.js +0 -773
- package/build/conduct-epic/checkpoint-store.js +0 -542
- package/build/conduct-epic/cli.js +0 -3145
- package/build/conduct-epic/cut-protocol.js +0 -392
- package/build/conduct-epic/lock.js +0 -302
- package/build/conduct-epic/pr-state.js +0 -286
- package/build/conduct-epic/spawn.js +0 -113
- package/build/conductor/cli.js +0 -1278
- package/build/conductor-bundle-cli.js +0 -256
- package/build/direct-ticket-tools.js +0 -70
- package/build/executor/reconcile-overlap-governance.js +0 -129
- package/build/implement-epic/bridge-client.js +0 -773
- package/build/implement-epic/checkpoint-store.js +0 -542
- package/build/implement-epic/cli.js +0 -3158
- package/build/implement-epic/cut-protocol.js +0 -392
- package/build/implement-epic/lock.js +0 -302
- package/build/implement-epic/pr-state.js +0 -286
- package/build/implement-epic/spawn.js +0 -113
- package/build/plan-epic-conductor-eligibility.js +0 -213
package/build/drive-epic.js
CHANGED
|
@@ -55,7 +55,9 @@
|
|
|
55
55
|
*/
|
|
56
56
|
import { readFile } from "node:fs/promises";
|
|
57
57
|
import { dirname, join } from "node:path";
|
|
58
|
-
import { ConductorBridgeApiError,
|
|
58
|
+
import { ConductorBridgeApiError, resolveEpicLaunchBridgeApiAccess, fetchConductorReadiness, fetchEpicRunState, safeDiagnosticMessage, } from "./conductor/bridge-api-client.js";
|
|
59
|
+
import { EPIC_LAUNCH_PROFILE_NAME_PATTERN, renderEpicLaunchCommand, shellQuote, } from "./epic-launch-profile.js";
|
|
60
|
+
import { validateHttpBaseUrl, describeBaseUrlRejection } from "./base-url.js";
|
|
59
61
|
import { BRING_UP_REFUSAL_MESSAGES, BRING_UP_RUNBOOK, firstBringUpRefusal, } from "./conductor/bring-up-facts.js";
|
|
60
62
|
import { runSetupEpicWorkflow, } from "./setup-epic.js";
|
|
61
63
|
import { formatPlaneDiagnostic, launchPlaneControlPlane, requestPlaneScopedLanes, runDefaultPlanePreflight, runPlaneCli, } from "./plane/cli.js";
|
|
@@ -161,6 +163,29 @@ export const V2_READINESS_REQUIREMENTS = [
|
|
|
161
163
|
remedy: "Run `install-bridge conductor` to install them, or pass --attended.",
|
|
162
164
|
satisfied: (r) => r.unattended?.repository_readiness_confirmed === true,
|
|
163
165
|
},
|
|
166
|
+
// BAPI-1135 — merge-execution eligibility is deliberately NOT a requirement here.
|
|
167
|
+
//
|
|
168
|
+
// It was one, and it made `drive-epic` refuse EVERY repository the moment it
|
|
169
|
+
// shipped. The requirement could only be keyed on repository facts, because
|
|
170
|
+
// this layer keeps the composed run policy opaque to itself — and no
|
|
171
|
+
// repository carries the merge workflow until epic child 4 lands it. So both
|
|
172
|
+
// states resolved the same way: an upgraded server reported
|
|
173
|
+
// `merge_workflow_present: false` (`not_eligible`), an older one reported no
|
|
174
|
+
// block at all (`could_not_verify`), and either made `selectConductor` return
|
|
175
|
+
// `not_ready` and `classifyV2Readiness` return `operator_blocked` — for
|
|
176
|
+
// `--attended`, `--into-base` and `local`-mode runs alike, with a remedy
|
|
177
|
+
// naming a flag that does not exist yet.
|
|
178
|
+
//
|
|
179
|
+
// That is exactly the failure `selectConductor`'s own docstring warns about,
|
|
180
|
+
// and it contradicts the compatibility guarantee the rest of this slice keeps:
|
|
181
|
+
// nothing changes for a run that does not declare `github_actions`.
|
|
182
|
+
//
|
|
183
|
+
// Eligibility is still enforced, at the three layers that can actually see the
|
|
184
|
+
// declared mode: `setup-epic`'s pre-create refusal (which reads the composed
|
|
185
|
+
// policy), the approval route's server-side gate, and — authoritatively — the
|
|
186
|
+
// before-merge preflight. Readiness still REPORTS the facts as diagnostic
|
|
187
|
+
// rows, which inform without blocking. Reinstating a requirement here belongs
|
|
188
|
+
// with child 4, once a repository can actually satisfy it.
|
|
164
189
|
];
|
|
165
190
|
/**
|
|
166
191
|
* The readiness facts a `plane up` can actually repair (BAPI-1054).
|
|
@@ -310,6 +335,18 @@ export function getDriveEpicUsage() {
|
|
|
310
335
|
" --review-policy <src> PER-RUN review policy source.",
|
|
311
336
|
" --replace-policy Authorize replacing a LIVE run's stored policy.",
|
|
312
337
|
"",
|
|
338
|
+
"Launch target (BAPI-1260) — decided BEFORE any authenticated request:",
|
|
339
|
+
" --launch-profile <name> Select the host-local launch profile guided setup",
|
|
340
|
+
" approved (`install conductor --launch-profile <name>`):",
|
|
341
|
+
" target, repository, mode, runtime, and policy and",
|
|
342
|
+
" credential references. The command setup prints",
|
|
343
|
+
" already selects it and runs in a fresh shell.",
|
|
344
|
+
" --base-url <url> Explicit Bridge API target. With a profile it must",
|
|
345
|
+
" agree with it — an override never rebinds a profile.",
|
|
346
|
+
"Without either, BAPI_BASE_URL is used; with none of the three, drive-epic",
|
|
347
|
+
"refuses. Nothing defaults to production — select it deliberately. A stored",
|
|
348
|
+
"credential is sent only to the endpoint setup approved it for.",
|
|
349
|
+
"",
|
|
313
350
|
" -h, --help Show this help",
|
|
314
351
|
].join("\n");
|
|
315
352
|
}
|
|
@@ -336,6 +373,9 @@ export function parseDriveEpicArgs(argv) {
|
|
|
336
373
|
let policyFile;
|
|
337
374
|
let reviewPolicy;
|
|
338
375
|
let replacePolicy = false;
|
|
376
|
+
// BAPI-1260 launch selection.
|
|
377
|
+
let launchProfile;
|
|
378
|
+
let baseUrl;
|
|
339
379
|
// BAPI-1009: validated with the SHARED validator setup-epic uses, so a name
|
|
340
380
|
// drive-epic accepts is exactly a name setup-epic accepts. A second rule here
|
|
341
381
|
// would let a name pass the router and fail the delegate.
|
|
@@ -371,7 +411,9 @@ export function parseDriveEpicArgs(argv) {
|
|
|
371
411
|
arg === "--repo" ||
|
|
372
412
|
arg === "--feature-branch" ||
|
|
373
413
|
arg === "--policy-file" ||
|
|
374
|
-
arg === "--review-policy"
|
|
414
|
+
arg === "--review-policy" ||
|
|
415
|
+
arg === "--launch-profile" ||
|
|
416
|
+
arg === "--base-url") {
|
|
375
417
|
const value = argv[i + 1];
|
|
376
418
|
if (value === undefined || value.startsWith("-")) {
|
|
377
419
|
return { status: "error", message: `${arg} requires a value.` };
|
|
@@ -384,6 +426,10 @@ export function parseDriveEpicArgs(argv) {
|
|
|
384
426
|
policyFile = value;
|
|
385
427
|
else if (arg === "--review-policy")
|
|
386
428
|
reviewPolicy = value;
|
|
429
|
+
else if (arg === "--launch-profile")
|
|
430
|
+
launchProfile = value;
|
|
431
|
+
else if (arg === "--base-url")
|
|
432
|
+
baseUrl = value;
|
|
387
433
|
else if (takeFeatureBranch(value) === null) {
|
|
388
434
|
return {
|
|
389
435
|
status: "error",
|
|
@@ -393,7 +439,7 @@ export function parseDriveEpicArgs(argv) {
|
|
|
393
439
|
i++;
|
|
394
440
|
continue;
|
|
395
441
|
}
|
|
396
|
-
const eq = arg.match(/^(--plan-file|--repo|--feature-branch|--policy-file|--review-policy)=(.*)$/);
|
|
442
|
+
const eq = arg.match(/^(--plan-file|--repo|--feature-branch|--policy-file|--review-policy|--launch-profile|--base-url)=(.*)$/);
|
|
397
443
|
if (eq) {
|
|
398
444
|
const value = eq[2];
|
|
399
445
|
if (eq[1] === "--feature-branch") {
|
|
@@ -414,6 +460,10 @@ export function parseDriveEpicArgs(argv) {
|
|
|
414
460
|
policyFile = value;
|
|
415
461
|
else if (eq[1] === "--review-policy")
|
|
416
462
|
reviewPolicy = value;
|
|
463
|
+
else if (eq[1] === "--launch-profile")
|
|
464
|
+
launchProfile = value;
|
|
465
|
+
else if (eq[1] === "--base-url")
|
|
466
|
+
baseUrl = value;
|
|
417
467
|
else
|
|
418
468
|
repo = value;
|
|
419
469
|
continue;
|
|
@@ -435,6 +485,22 @@ export function parseDriveEpicArgs(argv) {
|
|
|
435
485
|
"may be selected — remove whichever one you did not mean.",
|
|
436
486
|
};
|
|
437
487
|
}
|
|
488
|
+
// BAPI-1260 — the launch selection is validated for SHAPE here, before any
|
|
489
|
+
// side effect. Whether it agrees with the profile and the environment is
|
|
490
|
+
// decided by the target resolver, still before any authenticated request.
|
|
491
|
+
if (launchProfile !== undefined && !EPIC_LAUNCH_PROFILE_NAME_PATTERN.test(launchProfile)) {
|
|
492
|
+
return {
|
|
493
|
+
status: "error",
|
|
494
|
+
message: "--launch-profile must match [a-z0-9][a-z0-9._-]{0,62}.",
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
if (baseUrl !== undefined) {
|
|
498
|
+
const validated = validateHttpBaseUrl(baseUrl);
|
|
499
|
+
if (!validated.ok) {
|
|
500
|
+
return { status: "error", message: describeBaseUrlRejection("--base-url", validated.reason) };
|
|
501
|
+
}
|
|
502
|
+
baseUrl = validated.baseUrl;
|
|
503
|
+
}
|
|
438
504
|
if (positionals.length === 0) {
|
|
439
505
|
return { status: "error", message: "Missing required epic key." };
|
|
440
506
|
}
|
|
@@ -462,6 +528,8 @@ export function parseDriveEpicArgs(argv) {
|
|
|
462
528
|
...(policyFile ? { policyFile } : {}),
|
|
463
529
|
...(reviewPolicy ? { reviewPolicy } : {}),
|
|
464
530
|
...(replacePolicy ? { replacePolicy: true } : {}),
|
|
531
|
+
...(launchProfile ? { launchProfile } : {}),
|
|
532
|
+
...(baseUrl ? { baseUrl } : {}),
|
|
465
533
|
};
|
|
466
534
|
return { status: "ok", options };
|
|
467
535
|
}
|
|
@@ -514,7 +582,7 @@ export function selectConductor(readiness) {
|
|
|
514
582
|
* no quoting to get wrong.
|
|
515
583
|
*/
|
|
516
584
|
export function buildSetupEpicArgv(options) {
|
|
517
|
-
const { epicKey, planFile, repo, featureBranch, intoBase, attended, policyFile, reviewPolicy, replacePolicy, } = options;
|
|
585
|
+
const { epicKey, planFile, repo, featureBranch, intoBase, attended, policyFile, reviewPolicy, replacePolicy, launchProfile, baseUrl, } = options;
|
|
518
586
|
return [
|
|
519
587
|
"--epic-key",
|
|
520
588
|
epicKey,
|
|
@@ -528,6 +596,11 @@ export function buildSetupEpicArgv(options) {
|
|
|
528
596
|
...(policyFile ? ["--policy-file", policyFile] : []),
|
|
529
597
|
...(reviewPolicy ? ["--review-policy", reviewPolicy] : []),
|
|
530
598
|
...(replacePolicy ? ["--replace-policy"] : []),
|
|
599
|
+
// BAPI-1260 — the SAME launch selection, so setup-epic resolves the same
|
|
600
|
+
// target and bound credential drive-epic just did. Appended only when
|
|
601
|
+
// supplied, so every pre-existing argv stays byte-identical.
|
|
602
|
+
...(launchProfile ? ["--launch-profile", launchProfile] : []),
|
|
603
|
+
...(baseUrl ? ["--base-url", baseUrl] : []),
|
|
531
604
|
];
|
|
532
605
|
}
|
|
533
606
|
/**
|
|
@@ -538,8 +611,25 @@ export function buildSetupEpicArgv(options) {
|
|
|
538
611
|
* is only true once {@link runDriveEpicCli} has declined to delegate — so route
|
|
539
612
|
* first, render second.
|
|
540
613
|
*/
|
|
541
|
-
export function renderConductorHandoff(selection, epicKey
|
|
542
|
-
|
|
614
|
+
export function renderConductorHandoff(selection, epicKey,
|
|
615
|
+
/**
|
|
616
|
+
* BAPI-1260 — the selected launch profile and the options this invocation
|
|
617
|
+
* carried. With a profile, the re-run command selects it and carries every
|
|
618
|
+
* non-secret flag it needs, shell-quoted, so it runs unchanged in a fresh
|
|
619
|
+
* shell. The plan file is the one thing that cannot be filled in yet, and it
|
|
620
|
+
* is the only placeholder left.
|
|
621
|
+
*/
|
|
622
|
+
launch = { profile: null }) {
|
|
623
|
+
const invocation = launch.profile !== null
|
|
624
|
+
? renderEpicLaunchCommand(launch.profile, {
|
|
625
|
+
epicKey,
|
|
626
|
+
planFile: "<path>",
|
|
627
|
+
...(launch.options?.policyFile ? { policyFile: launch.options.policyFile } : {}),
|
|
628
|
+
...(launch.options?.attended ? { attended: true } : {}),
|
|
629
|
+
...(launch.options?.intoBase ? { intoBase: true } : {}),
|
|
630
|
+
...(launch.options?.featureBranch ? { featureBranch: launch.options.featureBranch } : {}),
|
|
631
|
+
}).replace(`${shellQuote("<path>")}`, "<path>")
|
|
632
|
+
: `npx -y ${MCP_PACKAGE_NAME} drive-epic ${epicKey} --plan-file <path>`;
|
|
543
633
|
return {
|
|
544
634
|
conductor: "v2",
|
|
545
635
|
invocation,
|
|
@@ -585,6 +675,16 @@ export function assertSingleConductorInvocation(text) {
|
|
|
585
675
|
throw new Error(`drive-epic emitted more than one conductor invocation (${named.join(", ")}). ` +
|
|
586
676
|
"Exactly one path may ever be presented.");
|
|
587
677
|
}
|
|
678
|
+
// BAPI-1260 — the entry point itself, too. A rendered handoff now carries a
|
|
679
|
+
// complete, runnable `drive-epic <KEY> ...` command; two DIFFERENT runnable
|
|
680
|
+
// commands (say, one per profile or target) would hand the reader a choice of
|
|
681
|
+
// authority just as surely as naming two conductors. The same command
|
|
682
|
+
// repeated is still one invocation.
|
|
683
|
+
const runnable = new Set((text.match(/\bdrive-epic\s+[A-Z][A-Z0-9]*-[0-9]+[^\n]*/g) ?? []).map((line) => line.trim()));
|
|
684
|
+
if (runnable.size > 1) {
|
|
685
|
+
throw new Error(`drive-epic emitted ${runnable.size} different runnable launch commands. ` +
|
|
686
|
+
"Exactly one path may ever be presented.");
|
|
687
|
+
}
|
|
588
688
|
}
|
|
589
689
|
/**
|
|
590
690
|
* Conservative bound on any single advisory field. Exists so malformed or
|
|
@@ -786,14 +886,31 @@ export function resolvePlaneReconcilerInstanceId(manifest, env, hostname) {
|
|
|
786
886
|
}
|
|
787
887
|
/** Terminal `epic_runs.status` values; every other status is a live run. */
|
|
788
888
|
const TERMINAL_EPIC_RUN_STATUSES = ["abandoned", "done"];
|
|
889
|
+
/** The BAPI-1260 launch selection carried by parsed options. */
|
|
890
|
+
function launchSelectionOf(options) {
|
|
891
|
+
return {
|
|
892
|
+
...(options.launchProfile ? { profileName: options.launchProfile } : {}),
|
|
893
|
+
...(options.baseUrl ? { baseUrl: options.baseUrl } : {}),
|
|
894
|
+
};
|
|
895
|
+
}
|
|
789
896
|
export function createDefaultDriveEpicDeps() {
|
|
790
897
|
return {
|
|
791
|
-
resolveAccess: async (repo, cwd) => {
|
|
792
|
-
|
|
898
|
+
resolveAccess: async (repo, cwd, launch) => {
|
|
899
|
+
// BAPI-1260: the target-first launch contract. The generic resolver's
|
|
900
|
+
// production default does not apply to an epic launch.
|
|
901
|
+
const result = await resolveEpicLaunchBridgeApiAccess(launch ?? {}, {
|
|
793
902
|
...(repo ? { repoName: repo } : {}),
|
|
794
903
|
...(cwd ? { cwd } : {}),
|
|
795
904
|
});
|
|
796
|
-
return result.ok
|
|
905
|
+
return result.ok
|
|
906
|
+
? { ok: true, access: result.access, profile: result.profile }
|
|
907
|
+
: { ok: false, error: result.error };
|
|
908
|
+
},
|
|
909
|
+
// Non-secret, and only ever a value the resolver just agreed with the
|
|
910
|
+
// environment on (a conflicting BAPI_BASE_URL was refused above), so the
|
|
911
|
+
// processes this command starts see the same target it resolved.
|
|
912
|
+
adoptLaunchTarget: (baseUrl) => {
|
|
913
|
+
process.env.BAPI_BASE_URL = baseUrl;
|
|
797
914
|
},
|
|
798
915
|
readReadiness: (access) => fetchConductorReadiness(access, globalThis.fetch),
|
|
799
916
|
runSetupEpic: (argv) => runSetupEpicWorkflow(argv),
|
|
@@ -864,12 +981,19 @@ export async function runDriveEpicCli(argv, overrides = {}) {
|
|
|
864
981
|
return 1;
|
|
865
982
|
}
|
|
866
983
|
const { epicKey, planFile, repo, featureBranch, intoBase } = parsed.options;
|
|
984
|
+
const launch = launchSelectionOf(parsed.options);
|
|
867
985
|
try {
|
|
868
986
|
// --- Resolve access. A missing credential is UNKNOWN, not not-ready. -----
|
|
869
|
-
|
|
987
|
+
// BAPI-1260: the TARGET is decided first — from --launch-profile,
|
|
988
|
+
// --base-url, and BAPI_BASE_URL — and only then is a credential bound to
|
|
989
|
+
// that target read. A missing or conflicting target refuses here, before
|
|
990
|
+
// any authenticated request; nothing defaults to production.
|
|
991
|
+
const accessResult = await deps.resolveAccess(repo, undefined, launch);
|
|
870
992
|
if (!accessResult.ok) {
|
|
871
993
|
return escalate(deps, epicKey, `conductor readiness could not be read: ${accessResult.error}`);
|
|
872
994
|
}
|
|
995
|
+
const launchProfile = accessResult.profile ?? null;
|
|
996
|
+
deps.adoptLaunchTarget?.(accessResult.access.baseUrl);
|
|
873
997
|
// --- Read readiness. Any failure here is UNKNOWN — with ONE exception. ---
|
|
874
998
|
let readiness;
|
|
875
999
|
try {
|
|
@@ -884,6 +1008,14 @@ export async function runDriveEpicCli(argv, overrides = {}) {
|
|
|
884
1008
|
// because there unknown is still fatal (R14).
|
|
885
1009
|
if (planFile !== undefined && err instanceof ConductorBridgeApiError && err.kind === "network") {
|
|
886
1010
|
const endpoint = planeEndpointForBaseUrl(deps, accessResult.access.baseUrl);
|
|
1011
|
+
// BAPI-1260 — only a SELECTED LOCAL plane is ever started here. A
|
|
1012
|
+
// profile approved for durable execution names an authority this
|
|
1013
|
+
// machine does not own, so a refused port is that authority being
|
|
1014
|
+
// down — never permission to launch a local replacement.
|
|
1015
|
+
if (endpoint !== null && launchProfile !== null && launchProfile.executionMode !== "local") {
|
|
1016
|
+
return escalate(deps, epicKey, `launch profile '${launchProfile.name}' selects durable execution, and its control plane is ` +
|
|
1017
|
+
"not answering; no local replacement was started");
|
|
1018
|
+
}
|
|
887
1019
|
if (endpoint !== null) {
|
|
888
1020
|
const probe = await deps.probePlanePort(endpoint.host, endpoint.port);
|
|
889
1021
|
if (probe.kind === "refused") {
|
|
@@ -1055,7 +1187,10 @@ export async function runDriveEpicCli(argv, overrides = {}) {
|
|
|
1055
1187
|
deps.errorLog(refusal);
|
|
1056
1188
|
return 1;
|
|
1057
1189
|
}
|
|
1058
|
-
const handoff = renderConductorHandoff(selection, epicKey
|
|
1190
|
+
const handoff = renderConductorHandoff(selection, epicKey, {
|
|
1191
|
+
profile: launchProfile,
|
|
1192
|
+
options: parsed.options,
|
|
1193
|
+
});
|
|
1059
1194
|
const text = handoff.lines.join("\n");
|
|
1060
1195
|
assertSingleConductorInvocation(text);
|
|
1061
1196
|
deps.log(text);
|
|
@@ -1264,7 +1399,7 @@ async function coldStartPlane(ctx) {
|
|
|
1264
1399
|
*/
|
|
1265
1400
|
async function attachToPlane(ctx, manifest, readiness) {
|
|
1266
1401
|
const { deps, epicKey } = ctx;
|
|
1267
|
-
const rooted = await deps.resolveAccess(ctx.options.repo, manifest.repoRoot);
|
|
1402
|
+
const rooted = await deps.resolveAccess(ctx.options.repo, manifest.repoRoot, launchSelectionOf(ctx.options));
|
|
1268
1403
|
if (!rooted.ok) {
|
|
1269
1404
|
return refuse(deps, [
|
|
1270
1405
|
`${epicKey}: cannot attach to the running plane — Bridge API credentials could not be ` +
|