@bridge_gpt/mcp-server 0.2.53 → 0.2.55
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 +116 -56
- package/build/agent-guidance.generated.js +3 -0
- package/build/agent-launchers/claude-executor-adapter.js +3 -0
- package/build/agent-launchers/claude.js +3 -3
- package/build/agent-launchers/prompt.js +8 -11
- package/build/agent-notes.js +178 -0
- package/build/agent-registry.js +5 -2
- package/build/agent-utils.js +58 -0
- package/build/agents.generated.js +1 -1
- package/build/base-ref.js +33 -9
- package/build/bounded-wait.js +174 -0
- package/build/codex-skill-adapter.js +55 -0
- package/build/commands.generated.js +6 -5
- package/build/conductor/bridge-api-client.js +235 -14
- package/build/conductor/bring-up-facts.js +187 -0
- package/build/conductor/claude-hook.js +7 -5
- package/build/conductor/cli.js +28 -0
- package/build/conductor/doctor.js +80 -9
- package/build/conductor/epic-implementer-cli.js +1298 -0
- package/build/conductor/epic-runtime.js +134 -98
- package/build/conductor/errors.js +2 -2
- package/build/conductor/git-ci-types.js +1 -1
- package/build/conductor/git-hooks.js +28 -14
- package/build/conductor/install-doctor.js +11 -5
- package/build/conductor/readiness-cli.js +10 -10
- package/build/conductor/readiness-sections.js +58 -9
- package/build/conductor/readiness.js +120 -4
- package/build/conductor/recovery-cli.js +289 -10
- package/build/conductor/recovery-operations.js +125 -2
- package/build/conductor/repair-contract.js +58 -0
- package/build/conductor/run-branch.js +137 -0
- package/build/conductor/store.js +2 -2
- package/build/conductor/supervisor-runtime.js +1 -1
- package/build/conductor/test-run-branch-vectors.js +165 -0
- package/build/conductor-bin.js +2 -139
- package/build/conductor-claude-hook-bin.js +2 -2
- package/build/conductor-claude-hook-removed-stub-bin.js +31 -0
- package/build/conductor-removed-stub-bin.js +30 -0
- package/build/docs.generated.js +1 -1
- package/build/doctor.js +145 -18
- package/build/drive-epic.js +752 -90
- package/build/epic-implementer-bin.js +145 -0
- package/build/epic-implementer-bundle-cli.js +264 -0
- package/build/epic-implementer-claude-hook-bin.js +3 -0
- package/build/epic-integration-pr.js +5 -3
- package/build/executor/claim-scope.js +104 -0
- package/build/executor/cli.js +14 -25
- package/build/executor/env-file-guard.js +82 -3
- package/build/executor/env.js +6 -0
- package/build/executor/interrupted-worktree.js +60 -0
- package/build/executor/job-errors.js +45 -0
- package/build/executor/job-runner.js +334 -9
- package/build/executor/job-types.js +25 -9
- package/build/executor/merge-tree-classifier.js +171 -0
- package/build/executor/reconcile-overlap-governance.js +129 -0
- package/build/executor/reconcile-overlap-job.js +989 -0
- package/build/executor/reconcile-overlap-types.js +14 -0
- package/build/executor/spawn-job-driver.js +1 -0
- package/build/executor/types.js +2 -0
- package/build/executor/worker-finalization.js +25 -2
- package/build/executor/worker-guard-hook.js +15 -7
- package/build/implement-epic/bridge-client.js +773 -0
- package/build/implement-epic/checkpoint-store.js +542 -0
- package/build/implement-epic/cli.js +3158 -0
- package/build/implement-epic/cut-protocol.js +392 -0
- package/build/implement-epic/lock.js +302 -0
- package/build/implement-epic/pr-state.js +286 -0
- package/build/implement-epic/spawn.js +113 -0
- package/build/index.js +657 -481
- package/build/init.js +72 -8
- package/build/install-bridge-conductor.js +5 -5
- package/build/install-bridge.js +403 -70
- package/build/local-artifact-storage.js +130 -0
- package/build/mcp-host-config.js +22 -60
- package/build/mcp-host-entry-adapter.js +18 -0
- package/build/mcp-host-targets.js +1 -21
- package/build/merge-pull-request.js +1 -1
- package/build/pipelines.generated.js +23 -16
- package/build/plan-epic-conductor-eligibility.js +1 -1
- package/build/plane/cli.js +321 -41
- package/build/plane/manifest.js +209 -1
- package/build/plane/member-roster.js +70 -0
- package/build/plane/preflight.js +128 -12
- package/build/plane/shutdown.js +18 -5
- package/build/plane/status.js +35 -1
- package/build/plane/supervisor.js +546 -164
- package/build/plane/types.js +25 -2
- package/build/polling-policy.js +72 -0
- package/build/readiness-check.js +3 -3
- package/build/readme.generated.js +1 -1
- package/build/review-generation.js +219 -0
- package/build/run-unit-tests-launcher.js +6 -1
- package/build/setup-epic.js +567 -38
- package/build/start-tickets-conductor.js +8 -7
- package/build/ticket-key-utils.js +4 -3
- package/build/ticket-review-artifact-gate.js +461 -0
- package/build/upgrade-cli.js +5 -26
- package/build/version.generated.js +3 -3
- package/build/worker-guard-hook-bin.js +1 -1
- package/docs/CONDUCTOR.md +8 -6
- package/docs/install/mcp-tool-integrations.md +23 -1
- package/package.json +5 -3
- package/pipelines/review-ticket.json +17 -4
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured local artifact persistence primitives (BAPI-1121).
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS. `wait_for_ticket_review`'s generation-aware artifact gate
|
|
5
|
+
* (`ticket-review-artifact-gate.ts`) needs a write/removal outcome it can
|
|
6
|
+
* branch on — did the accepted clarify leg actually land on disk, did the
|
|
7
|
+
* withheld critique file actually get removed — without parsing a
|
|
8
|
+
* human-readable note string. The pre-existing `saveLocally` in `index.ts`
|
|
9
|
+
* returns exactly that kind of note, and every existing artifact tool (the
|
|
10
|
+
* six single-artifact request/get tools, the BAPI-342 heavy-read saves, the
|
|
11
|
+
* combined ticket-review fan-out) depends on its exact rendered shape. This
|
|
12
|
+
* module extracts the underlying write mechanics into one place, so both the
|
|
13
|
+
* legacy byte-compatible `saveLocally` and the new structured primitives the
|
|
14
|
+
* gate uses share a single implementation rather than diverging.
|
|
15
|
+
*
|
|
16
|
+
* WHY A SEPARATE MODULE. `index.ts` is the file every other module is
|
|
17
|
+
* imported INTO; a helper defined there cannot be imported back into a module
|
|
18
|
+
* `index.ts` itself imports without an import cycle. This module has no
|
|
19
|
+
* dependency on `index.ts`, so `index.ts` imports `saveLocally` from here
|
|
20
|
+
* (BAPI-1121) instead of defining it locally, and the artifact gate imports
|
|
21
|
+
* the structured primitives directly.
|
|
22
|
+
*/
|
|
23
|
+
import { writeFile, mkdir, rename, unlink } from "fs/promises";
|
|
24
|
+
import path from "path";
|
|
25
|
+
import { randomUUID } from "node:crypto";
|
|
26
|
+
/**
|
|
27
|
+
* Write `content` to `dir/filename` via per-file temporary staging followed by
|
|
28
|
+
* an atomic rename, so a concurrent reader can never observe a partially
|
|
29
|
+
* written file and a failed write never leaves a corrupt final artifact.
|
|
30
|
+
*
|
|
31
|
+
* The staging filename includes a random suffix so concurrent writes to the
|
|
32
|
+
* same final filename (unusual, but not prevented at this layer) cannot stage
|
|
33
|
+
* onto the same temporary path.
|
|
34
|
+
*
|
|
35
|
+
* Throws on failure — this is the shared low-level primitive both
|
|
36
|
+
* {@link saveLocally} (byte-compatible legacy notes) and
|
|
37
|
+
* {@link writeCanonicalArtifact} (sanitized structured outcome) wrap
|
|
38
|
+
* differently, because they render a failure to their callers in two
|
|
39
|
+
* deliberately different shapes.
|
|
40
|
+
*/
|
|
41
|
+
async function writeFileAtomic(dir, filename, content) {
|
|
42
|
+
const finalPath = path.join(dir, filename);
|
|
43
|
+
const stagingPath = path.join(dir, `.${filename}.${randomUUID()}.tmp`);
|
|
44
|
+
await mkdir(dir, { recursive: true });
|
|
45
|
+
try {
|
|
46
|
+
await writeFile(stagingPath, content, "utf-8");
|
|
47
|
+
await rename(stagingPath, finalPath);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
// Best-effort cleanup of an orphaned staging file. Cleanup failure (or the
|
|
51
|
+
// staging file never having been created) does not change the outcome
|
|
52
|
+
// that matters: the original write/rename error propagates below.
|
|
53
|
+
try {
|
|
54
|
+
await unlink(stagingPath);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Nothing to clean up, or cleanup itself failed — either way the
|
|
58
|
+
// original error is what the caller needs to see.
|
|
59
|
+
}
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
return finalPath;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Byte-compatible replacement for the pre-BAPI-1121 `saveLocally` in
|
|
66
|
+
* `index.ts`. Preserves the exact call shape (`dir`, `filename`, `content` ->
|
|
67
|
+
* a rendered note string) and the exact rendered success/failure notes every
|
|
68
|
+
* existing artifact-tool caller depends on — including the raw error suffix
|
|
69
|
+
* on failure, which existing tests assert verbatim. The only behavioral
|
|
70
|
+
* change is that the write is now staged-then-renamed rather than written
|
|
71
|
+
* in place, which is externally invisible on success and, on failure, means
|
|
72
|
+
* no partial file is ever left at `dir/filename` (an improvement, not a
|
|
73
|
+
* compatibility break).
|
|
74
|
+
*/
|
|
75
|
+
export async function saveLocally(dir, filename, content) {
|
|
76
|
+
try {
|
|
77
|
+
const finalPath = await writeFileAtomic(dir, filename, content);
|
|
78
|
+
return `\n\n---\nSaved to ${finalPath}`;
|
|
79
|
+
}
|
|
80
|
+
catch (writeErr) {
|
|
81
|
+
const filePath = path.join(dir, filename);
|
|
82
|
+
return `\n\n---\nNote: Failed to save file to ${filePath}: ${writeErr}`;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Structured canonical write for the generation-aware artifact gate. Returns
|
|
87
|
+
* `{ ok, path, message }` rather than throwing or requiring the caller to
|
|
88
|
+
* parse a note string. The public `message` is sanitized to the path and
|
|
89
|
+
* outcome only; any detailed local diagnostic (the underlying filesystem
|
|
90
|
+
* error) goes only to `console.error`, never through MCP.
|
|
91
|
+
*/
|
|
92
|
+
export async function writeCanonicalArtifact(dir, filename, content) {
|
|
93
|
+
const finalPath = path.join(dir, filename);
|
|
94
|
+
try {
|
|
95
|
+
await writeFileAtomic(dir, filename, content);
|
|
96
|
+
return { ok: true, path: finalPath, message: `Saved to ${finalPath}` };
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
console.error(`[local-artifact-storage] write failed for ${finalPath}:`, err);
|
|
100
|
+
return { ok: false, path: finalPath, message: `Failed to save file to ${finalPath}` };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Remove the exact canonical path for a withheld or stale artifact.
|
|
105
|
+
*
|
|
106
|
+
* Idempotent by design: an already-absent target (`ENOENT`) is reported as a
|
|
107
|
+
* SUCCESSFUL cleanup outcome, not an error — a retried removal, or a removal
|
|
108
|
+
* that runs after an earlier successful one, must never report failure. Only
|
|
109
|
+
* an actual removal failure (permissions, a directory at that path, etc.) is
|
|
110
|
+
* reported as `ok: false`.
|
|
111
|
+
*
|
|
112
|
+
* Removes exactly the given path — no globbing, no directory recursion, no
|
|
113
|
+
* inference of sibling files to clean up. The caller is responsible for
|
|
114
|
+
* passing the exact canonical target; this primitive never widens the blast
|
|
115
|
+
* radius of a removal on its own.
|
|
116
|
+
*/
|
|
117
|
+
export async function removeCanonicalArtifact(targetPath) {
|
|
118
|
+
try {
|
|
119
|
+
await unlink(targetPath);
|
|
120
|
+
return { ok: true, path: targetPath, message: `Removed ${targetPath}` };
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
const code = err?.code;
|
|
124
|
+
if (code === "ENOENT") {
|
|
125
|
+
return { ok: true, path: targetPath, message: `${targetPath} was already absent` };
|
|
126
|
+
}
|
|
127
|
+
console.error(`[local-artifact-storage] removal failed for ${targetPath}:`, err);
|
|
128
|
+
return { ok: false, path: targetPath, message: `Failed to remove ${targetPath}` };
|
|
129
|
+
}
|
|
130
|
+
}
|
package/build/mcp-host-config.js
CHANGED
|
@@ -9,17 +9,17 @@
|
|
|
9
9
|
* Write strategy per target comes from the data-only registry
|
|
10
10
|
* {@link file:./mcp-host-targets.ts}:
|
|
11
11
|
* - vendor-first — prefer the official vendor CLI, fall back to a safe direct
|
|
12
|
-
* write (Claude Code,
|
|
12
|
+
* write (Claude Code, Codex).
|
|
13
13
|
* - direct — merge-write the JSON file directly (Cursor, Copilot VS Code).
|
|
14
14
|
* - manual-instructions — never auto-write; emit redacted instructions
|
|
15
15
|
* (Windsurf).
|
|
16
16
|
*
|
|
17
17
|
* SECRET DISCIPLINE: the API key lives only inside the logical entry's `env`.
|
|
18
|
-
* When a verified vendor contract delivers it via argv (
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
18
|
+
* When a verified vendor contract delivers it via argv (neither expose a stdin
|
|
19
|
+
* channel), the argv is constructed and spawned INSIDE the vendor adapter and is
|
|
20
|
+
* never stringified, logged, previewed, returned, or interpolated into a
|
|
21
|
+
* warning. Structured outcomes and inspectors carry presence + launcher args
|
|
22
|
+
* only, never env values.
|
|
23
23
|
*
|
|
24
24
|
* TOML NOTE: there is no comment-preserving TOML library available, so Codex
|
|
25
25
|
* direct writes render a canonical document for a missing file, APPEND canonical
|
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
import { VERSION } from "./version.generated.js";
|
|
31
31
|
import { refreshBridgeApiPackageSpec } from "./init.js";
|
|
32
32
|
import { hostAdapterForTarget, } from "./mcp-host-targets.js";
|
|
33
|
+
import { adaptBridgeEntryForHostTarget, } from "./mcp-host-entry-adapter.js";
|
|
34
|
+
export { adaptBridgeEntryForHostTarget, } from "./mcp-host-entry-adapter.js";
|
|
33
35
|
import { LEGACY_SERVER_NAMES, MCP_SERVER_NAME, MCP_PACKAGE_NAME, RECOGNIZED_SERVER_NAMES, resolveRegistrationKey, } from "./mcp-identity.js";
|
|
34
36
|
/**
|
|
35
37
|
* The secret-free, repair-oriented detail every duplicate-registration outcome
|
|
@@ -64,31 +66,6 @@ export function resolveTargetAbsPath(target, ctx) {
|
|
|
64
66
|
return target.absPathResolver(ctx.homedir);
|
|
65
67
|
}
|
|
66
68
|
// ---------------------------------------------------------------------------
|
|
67
|
-
// Entry adaptation
|
|
68
|
-
// ---------------------------------------------------------------------------
|
|
69
|
-
/**
|
|
70
|
-
* Adapt the shared logical entry into a target's physical JSON entry: copy
|
|
71
|
-
* command/args/env, conditionally add the registry `transportType` as `type`,
|
|
72
|
-
* and merge `extraEntryKeys`. Claude Code omits `type`; Cursor/Copilot VS Code
|
|
73
|
-
* use `stdio`; Copilot CLI uses `local` + `tools: ["*"]`.
|
|
74
|
-
*/
|
|
75
|
-
export function adaptBridgeEntryForHostTarget(entry, target) {
|
|
76
|
-
const adapter = hostAdapterForTarget(target);
|
|
77
|
-
const physical = {};
|
|
78
|
-
if (adapter.transportType !== undefined) {
|
|
79
|
-
physical.type = adapter.transportType;
|
|
80
|
-
}
|
|
81
|
-
physical.command = entry.command;
|
|
82
|
-
physical.args = [...entry.args];
|
|
83
|
-
physical.env = { ...entry.env };
|
|
84
|
-
if (adapter.extraEntryKeys) {
|
|
85
|
-
for (const [k, v] of Object.entries(adapter.extraEntryKeys)) {
|
|
86
|
-
physical[k] = v;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return physical;
|
|
90
|
-
}
|
|
91
|
-
// ---------------------------------------------------------------------------
|
|
92
69
|
// JSON read / merge / write
|
|
93
70
|
// ---------------------------------------------------------------------------
|
|
94
71
|
function isEnoent(err) {
|
|
@@ -153,10 +130,17 @@ export function mergeJsonHostConfig(existing, target, adaptedEntry) {
|
|
|
153
130
|
// key, so a legacy registration's args are preserved exactly like a canonical
|
|
154
131
|
// one's.
|
|
155
132
|
const prior = root[writeKey];
|
|
133
|
+
const priorEntry = prior && typeof prior === "object" && !Array.isArray(prior)
|
|
134
|
+
? prior
|
|
135
|
+
: {};
|
|
156
136
|
const preservedArgs = prior && typeof prior === "object" && !Array.isArray(prior)
|
|
157
|
-
? refreshBridgeApiPackageSpec(
|
|
137
|
+
? refreshBridgeApiPackageSpec(priorEntry.args, currentLauncherSpec())
|
|
158
138
|
: null;
|
|
159
|
-
root[writeKey] =
|
|
139
|
+
root[writeKey] = {
|
|
140
|
+
...priorEntry,
|
|
141
|
+
...adaptedEntry,
|
|
142
|
+
...(preservedArgs ? { args: preservedArgs } : {}),
|
|
143
|
+
};
|
|
160
144
|
merged[adapter.topLevelKey] = root;
|
|
161
145
|
return { status: "merged", document: merged, registrationKey: writeKey };
|
|
162
146
|
}
|
|
@@ -467,7 +451,7 @@ export async function inspectHostEntry(target, ctx, deps) {
|
|
|
467
451
|
*
|
|
468
452
|
* Deliberately NOT derived from {@link file:./mcp-host-targets.ts}: the merge
|
|
469
453
|
* path's surface is these three files and nothing else, so an inspector built
|
|
470
|
-
* from the wider registry would report on Codex/
|
|
454
|
+
* from the wider registry would report on Codex/Windsurf hosts the writer never
|
|
471
455
|
* touches — and a report implying those hosts gained the token would be wrong.
|
|
472
456
|
*/
|
|
473
457
|
export const BRIDGE_PROFILE_TOKEN_CONFIGS = [
|
|
@@ -567,12 +551,12 @@ export async function inspectBridgeApiProfileToken(projectRoot, token, deps) {
|
|
|
567
551
|
* Whether a vendor kind's secret-delivery contract is VERIFIED. Only verified
|
|
568
552
|
* contracts are ever invoked; an uncertain contract falls back to a direct
|
|
569
553
|
* write rather than guessing argv. Verified from empirical probes (BAPI-635):
|
|
570
|
-
* claude `mcp add-json <name> <json>`
|
|
571
|
-
*
|
|
572
|
-
*
|
|
554
|
+
* claude `mcp add-json <name> <json>` delivers the secret through argv.
|
|
555
|
+
* Codex's contract is unverified (binary absent at authoring time) → never
|
|
556
|
+
* invoked; always direct-written.
|
|
573
557
|
*/
|
|
574
558
|
function isVendorContractVerified(kind) {
|
|
575
|
-
return kind === "claude-add-json"
|
|
559
|
+
return kind === "claude-add-json";
|
|
576
560
|
}
|
|
577
561
|
/**
|
|
578
562
|
* Build the vendor add invocation for a target. Returns `null` when the
|
|
@@ -597,28 +581,6 @@ function buildVendorInvocation(target, entry) {
|
|
|
597
581
|
args: ["mcp", "add-json", MCP_SERVER_NAME, json, "--scope", "project"],
|
|
598
582
|
};
|
|
599
583
|
}
|
|
600
|
-
if (vendor.kind === "copilot-add") {
|
|
601
|
-
// copilot mcp add <name> --tools "*" --env K=V ... -- <command> <args...>
|
|
602
|
-
// Env pairs (incl BAPI_API_KEY) are secret-bearing argv.
|
|
603
|
-
const envArgs = [];
|
|
604
|
-
for (const [k, v] of Object.entries(entry.env)) {
|
|
605
|
-
envArgs.push("--env", `${k}=${v}`);
|
|
606
|
-
}
|
|
607
|
-
return {
|
|
608
|
-
bin: vendor.bin,
|
|
609
|
-
args: [
|
|
610
|
-
"mcp",
|
|
611
|
-
"add",
|
|
612
|
-
MCP_SERVER_NAME,
|
|
613
|
-
"--tools",
|
|
614
|
-
"*",
|
|
615
|
-
...envArgs,
|
|
616
|
-
"--",
|
|
617
|
-
entry.command,
|
|
618
|
-
...entry.args,
|
|
619
|
-
],
|
|
620
|
-
};
|
|
621
|
-
}
|
|
622
584
|
return null;
|
|
623
585
|
}
|
|
624
586
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { hostAdapterForTarget, } from "./mcp-host-targets.js";
|
|
2
|
+
/**
|
|
3
|
+
* Applies only registry-owned physical fields at the host emission boundary.
|
|
4
|
+
* Logical entries remain portable across host formats.
|
|
5
|
+
*/
|
|
6
|
+
export function adaptBridgeEntryForHostTarget(entry, target) {
|
|
7
|
+
const adapter = hostAdapterForTarget(target);
|
|
8
|
+
const physical = {
|
|
9
|
+
command: entry.command,
|
|
10
|
+
args: [...entry.args],
|
|
11
|
+
env: { ...entry.env },
|
|
12
|
+
};
|
|
13
|
+
if (adapter.transportType !== undefined)
|
|
14
|
+
physical.type = adapter.transportType;
|
|
15
|
+
if (adapter.extraEntryKeys)
|
|
16
|
+
Object.assign(physical, adapter.extraEntryKeys);
|
|
17
|
+
return physical;
|
|
18
|
+
}
|
|
@@ -51,12 +51,6 @@ export const HOST_ADAPTERS = {
|
|
|
51
51
|
topLevelKey: "mcp_servers",
|
|
52
52
|
transportType: undefined, // TOML table shape has no `type`.
|
|
53
53
|
},
|
|
54
|
-
"copilot-cli": {
|
|
55
|
-
format: "json",
|
|
56
|
-
topLevelKey: "mcpServers",
|
|
57
|
-
transportType: "local",
|
|
58
|
-
extraEntryKeys: { tools: ["*"] },
|
|
59
|
-
},
|
|
60
54
|
};
|
|
61
55
|
/** Pure typed lookup from a target's declared {@link HostKind} to its adapter. */
|
|
62
56
|
export function hostAdapterForTarget(target) {
|
|
@@ -100,7 +94,7 @@ export const MCP_HOST_TARGETS = {
|
|
|
100
94
|
},
|
|
101
95
|
"copilot-vscode": {
|
|
102
96
|
id: "copilot-vscode",
|
|
103
|
-
label: "GitHub Copilot
|
|
97
|
+
label: "GitHub Copilot",
|
|
104
98
|
scope: "project",
|
|
105
99
|
relPath: ".vscode/mcp.json",
|
|
106
100
|
displayPath: ".vscode/mcp.json",
|
|
@@ -109,19 +103,6 @@ export const MCP_HOST_TARGETS = {
|
|
|
109
103
|
writeStrategy: "direct",
|
|
110
104
|
detect: (ctx) => ctx.exists(joinPath(ctx.cwd, ".vscode")),
|
|
111
105
|
},
|
|
112
|
-
"copilot-cli": {
|
|
113
|
-
id: "copilot-cli",
|
|
114
|
-
label: "GitHub Copilot CLI",
|
|
115
|
-
scope: "global",
|
|
116
|
-
absPathResolver: (homedir) => joinPath(homedir, ".copilot/mcp-config.json"),
|
|
117
|
-
displayPath: "~/.copilot/mcp-config.json",
|
|
118
|
-
hostKind: "copilot-cli",
|
|
119
|
-
vendorCli: { bin: "copilot", kind: "copilot-add" },
|
|
120
|
-
worktreeSupported: false,
|
|
121
|
-
writeStrategy: "vendor-first",
|
|
122
|
-
// No existing probe supports Copilot CLI; never a default.
|
|
123
|
-
detect: () => false,
|
|
124
|
-
},
|
|
125
106
|
codex: {
|
|
126
107
|
id: "codex",
|
|
127
108
|
label: "OpenAI Codex",
|
|
@@ -153,7 +134,6 @@ export const HOST_PLATFORM_ORDER = [
|
|
|
153
134
|
"claude-code",
|
|
154
135
|
"cursor",
|
|
155
136
|
"copilot-vscode",
|
|
156
|
-
"copilot-cli",
|
|
157
137
|
"codex",
|
|
158
138
|
"windsurf",
|
|
159
139
|
];
|
|
@@ -356,7 +356,7 @@ function withReviewWaiver(env, waiver) {
|
|
|
356
356
|
*
|
|
357
357
|
* So the waiver mirrors the Python seam field for field: `api/library/vcs/epic_observers.py`
|
|
358
358
|
* routes `sticky is None` to `PENDING` (waivable) and EVERY `"unknown"` to
|
|
359
|
-
* `UNKNOWN` (never waivable), and `
|
|
359
|
+
* `UNKNOWN` (never waivable), and `epic_implementer_merge_service` admits only `PENDING`.
|
|
360
360
|
* No new server field is needed to do this — `sticky_verdict` already carries the
|
|
361
361
|
* distinction on the wire, and `normalizeReviewSnapshot` already preserves it.
|
|
362
362
|
*
|