@bridge_gpt/mcp-server 0.2.34 → 0.2.37
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 +490 -366
- package/build/agent-capabilities/probe-context.js +8 -1
- package/build/agent-capabilities/probes.js +7 -1
- package/build/agents.generated.js +1 -1
- package/build/base-url.js +79 -0
- package/build/bridge-api-urls.js +9 -0
- package/build/chain-orchestrator.js +93 -15
- package/build/claude-review-workflow.js +264 -0
- package/build/claude-user-config-doctor.js +317 -0
- package/build/cli-release.js +53 -0
- package/build/commands.generated.js +6 -5
- package/build/conductor/bridge-api-client.js +393 -4
- package/build/conductor/deny-enforcement-preflight.js +1 -0
- package/build/conductor/done-gate.js +44 -5
- package/build/conductor/epic-reconcile.js +6 -0
- package/build/conductor/install-doctor.js +462 -0
- package/build/conductor-bin.js +3 -3
- package/build/conductor-bundle-artifacts.js +37 -15
- package/build/credential-store.js +205 -4
- package/build/direct-ticket-tools.js +70 -0
- package/build/doctor.js +473 -81
- package/build/executor/cli.js +83 -6
- package/build/executor/credentials.js +39 -11
- package/build/executor/deps.js +32 -1
- package/build/executor/env.js +71 -28
- package/build/executor/heartbeat.js +138 -17
- package/build/executor/http-client.js +49 -8
- package/build/executor/index.js +4 -0
- package/build/executor/job-errors.js +4 -0
- package/build/executor/job-runner.js +530 -20
- package/build/executor/observation.js +130 -0
- package/build/executor/permissions.js +114 -8
- package/build/executor/preflight.js +127 -8
- package/build/executor/prompt-spec.js +51 -0
- package/build/executor/runner.js +23 -2
- package/build/executor/service-unit.js +876 -0
- package/build/executor/test-clock.js +75 -3
- package/build/executor/types.js +4 -18
- package/build/executor/worker-command.js +73 -12
- package/build/executor/worker-config-isolation.js +287 -0
- package/build/executor/worker-finalization.js +68 -14
- package/build/executor/worktree.js +46 -4
- package/build/index.js +1039 -237
- package/build/init.js +503 -111
- package/build/install-bridge-conductor.js +491 -0
- package/build/install-bridge.js +1188 -247
- package/build/install-reexec.js +233 -0
- package/build/launcher-config-inspection.js +351 -0
- package/build/mcp-host-config.js +11 -1
- package/build/mcp-install-state.js +32 -0
- package/build/mcp-invoke.js +49 -6
- package/build/mcp-provisioning.js +52 -13
- package/build/mcp-registration-doctor.js +14 -5
- package/build/notifications.js +553 -0
- package/build/pipeline-orchestrator.js +146 -4
- package/build/pipeline-utils.js +3 -0
- package/build/pipelines.generated.js +32 -13
- package/build/plan-execution-ledger.js +550 -0
- package/build/plan-phase-routing.js +272 -0
- package/build/plane/alembic-head.js +110 -0
- package/build/plane/build-freshness.js +167 -0
- package/build/plane/cli.js +480 -0
- package/build/plane/defaults.js +266 -0
- package/build/plane/manifest.js +377 -0
- package/build/plane/member-logs.js +147 -0
- package/build/plane/member-roster.js +147 -0
- package/build/plane/preflight.js +289 -0
- package/build/plane/shutdown.js +195 -0
- package/build/plane/status.js +125 -0
- package/build/plane/supervisor.js +569 -0
- package/build/plane/test-fakes.js +156 -0
- package/build/plane/types.js +75 -0
- package/build/readme.generated.js +1 -1
- package/build/run-unit-tests-launcher.js +259 -0
- package/build/setup-epic.js +772 -28
- package/build/sfcc/log-gate.js +38 -11
- package/build/sfcc/log-query.js +55 -15
- package/build/sfcc/ocapi-shape.js +51 -14
- package/build/sfcc/output.js +41 -11
- package/build/sfcc/permissions.js +24 -2
- package/build/sfcc/read-projection.js +181 -0
- package/build/sfcc/read-result.js +158 -0
- package/build/sfcc/reads-custom-object-def.js +29 -18
- package/build/sfcc/reads-site-preference.js +75 -29
- package/build/sfcc/reads-system-object.js +40 -34
- package/build/sfcc/sfcc-result.js +106 -0
- package/build/sfcc/tool-wrapper.js +56 -13
- package/build/sfcc/write-grants.js +45 -22
- package/build/sfcc/write-guard.js +21 -13
- package/build/sfcc/write-result.js +61 -14
- package/build/sfcc/write-tool-common.js +126 -32
- package/build/sfcc/writes-system-object.js +11 -50
- package/build/start-tickets-prereqs.js +129 -0
- package/build/start-tickets.js +17 -13
- package/build/ticket-backend-metadata.js +59 -0
- package/build/ticket-key-utils.js +92 -0
- package/build/tool-error-envelope.js +71 -0
- package/build/tool-surface-gating.js +72 -0
- package/build/update-status.js +102 -0
- package/build/upgrade-advice.js +47 -0
- package/build/upgrade-cli.js +412 -110
- package/build/version.generated.js +1 -1
- package/build/worktree-core.js +73 -0
- package/docs/CONDUCTOR.md +132 -6
- package/docs/install/mcp-tool-integrations.md +29 -21
- package/package.json +9 -6
- package/pipelines/implement-ticket.json +19 -4
- package/build/conductor/supervisor-judgment-python.js +0 -141
- package/build/conductor/supervisor-judgment.js +0 -215
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BAPI-683 — bounded, cross-platform launcher for the MCP server's compiled
|
|
3
|
+
* `node:test` suite.
|
|
4
|
+
*
|
|
5
|
+
* The previous `scripts.test` invocation enumerated every compiled test file
|
|
6
|
+
* as an explicit `node --test` command-line argument. Windows' CreateProcess
|
|
7
|
+
* command-line length limit (~8191 chars) made that argv too long once the
|
|
8
|
+
* suite grew past ~200 files (`The command line is too long.`, exit 1, before
|
|
9
|
+
* any test ran) — Linux/macOS have a much larger limit, so the same script
|
|
10
|
+
* kept passing there. This module discovers compiled test files at runtime
|
|
11
|
+
* and spawns them in size-bounded batches instead of expanding them ahead of
|
|
12
|
+
* time in package.json, so no single child invocation can approach the
|
|
13
|
+
* Windows ceiling regardless of how many test files exist.
|
|
14
|
+
*
|
|
15
|
+
* `scripts/run-unit-tests.js` is the thin CLI entrypoint that imports this
|
|
16
|
+
* compiled module; the logic lives here (under src/, built by tsc) so it can
|
|
17
|
+
* be unit-tested with node:test like every other module in this package.
|
|
18
|
+
*/
|
|
19
|
+
import { readdirSync } from "fs";
|
|
20
|
+
import { spawnSync } from "child_process";
|
|
21
|
+
import path from "path";
|
|
22
|
+
const DEFAULT_BUILD_DIR = "build";
|
|
23
|
+
// The Windows CreateProcess command-line limit is ~8191 characters. This
|
|
24
|
+
// budget stays well under it (accounting for execPath + node options +
|
|
25
|
+
// separators) so a single batch can never approach the real ceiling even on a
|
|
26
|
+
// longer install path. Kept OS-independent so batching is deterministic and
|
|
27
|
+
// stable across every CI runner and locally.
|
|
28
|
+
export const MAX_COMMAND_LENGTH = 6000;
|
|
29
|
+
// Explicit manifest: only tests that call node:test's `mock.module()` API
|
|
30
|
+
// need --experimental-test-module-mocks. Everything else discovered under
|
|
31
|
+
// build/ is eligible for the "normal" group automatically — new tests do NOT
|
|
32
|
+
// need to be registered anywhere else. Add an entry here only when a new test
|
|
33
|
+
// needs module mocking.
|
|
34
|
+
export const MODULE_MOCK_MANIFEST = [
|
|
35
|
+
"build/attachment-download.test.js",
|
|
36
|
+
"build/attachment-upload.test.js",
|
|
37
|
+
"build/automation-progress.test.js",
|
|
38
|
+
"build/conductor/cli-git-hooks.test.js",
|
|
39
|
+
"build/conductor/cli.test.js",
|
|
40
|
+
"build/conductor/git-inspection.test.js",
|
|
41
|
+
"build/conductor/paths.test.js",
|
|
42
|
+
"build/conductor/pr-ci-producer-emit-seam.test.js",
|
|
43
|
+
"build/conductor/security-regressions.test.js",
|
|
44
|
+
"build/conductor/store-lifecycle.test.js",
|
|
45
|
+
"build/conductor/store-queries.test.js",
|
|
46
|
+
"build/conductor/tools-done-gate.test.js",
|
|
47
|
+
"build/conductor/tools.test.js",
|
|
48
|
+
"build/connect-github-api.test.js",
|
|
49
|
+
"build/connect-github-dispatch.static.test.js",
|
|
50
|
+
"build/connect-github-handoff.test.js",
|
|
51
|
+
"build/connect-github.test.js",
|
|
52
|
+
"build/council-wait-recovery.test.js",
|
|
53
|
+
"build/index-artifacts.test.js",
|
|
54
|
+
"build/index-brainstorm-filenames.test.js",
|
|
55
|
+
"build/index-generate-decision-page.integration.test.js",
|
|
56
|
+
"build/index-generate-decision-page.test.js",
|
|
57
|
+
"build/index-heavy-read-truncation.test.js",
|
|
58
|
+
"build/index-output-path.test.js",
|
|
59
|
+
"build/index.review-rounds.test.js",
|
|
60
|
+
"build/recovery-formatting.test.js",
|
|
61
|
+
"build/sfcc/client.test.js",
|
|
62
|
+
"build/sfcc/permissions.test.js",
|
|
63
|
+
"build/sfcc/read-boundary.test.js",
|
|
64
|
+
"build/sfcc/reads-custom-object-def.test.js",
|
|
65
|
+
"build/sfcc/reads-site-preference.test.js",
|
|
66
|
+
"build/sfcc/reads-system-object.test.js",
|
|
67
|
+
"build/sfcc/register.test.js",
|
|
68
|
+
"build/sfcc/setup-status.test.js",
|
|
69
|
+
"build/sfcc/tool-wrapper.test.js",
|
|
70
|
+
"build/sfcc/write-gate-rejection.test.js",
|
|
71
|
+
"build/sfcc/writes-custom-object-def.test.js",
|
|
72
|
+
"build/sfcc/writes-site-preference.test.js",
|
|
73
|
+
"build/sfcc/writes-system-object.test.js",
|
|
74
|
+
"build/ticket-wait-recovery.test.js",
|
|
75
|
+
"build/visual-diff.attachment-adapter.test.js",
|
|
76
|
+
"build/visual-diff.registration.test.js",
|
|
77
|
+
"build/wait-for-result.test.js",
|
|
78
|
+
];
|
|
79
|
+
// Files that must run as their own single-file `node --test --test-force-exit`
|
|
80
|
+
// invocation instead of joining a multi-file batch. --test-force-exit makes
|
|
81
|
+
// the runner exit before it finishes aggregating per-subprocess summaries, so
|
|
82
|
+
// a multi-file batch run with it reports a nondeterministic (undercounted)
|
|
83
|
+
// test tally — failures still surface and still set exit 1, but the count
|
|
84
|
+
// cannot be trusted as a completeness signal. Batched invocations therefore
|
|
85
|
+
// run WITHOUT the flag; only the files listed here get it, each alone, where
|
|
86
|
+
// the tally stays exact. build/secret-safety.test.js is quarantined because it
|
|
87
|
+
// leaks a handle that holds the event loop ~60s after its tests finish (they
|
|
88
|
+
// run in ~147ms). Do NOT add --test-force-exit to batched invocations, and do
|
|
89
|
+
// NOT remove a file from this quarantine, until its underlying handle leak is
|
|
90
|
+
// fixed.
|
|
91
|
+
export const FORCE_EXIT_QUARANTINE = ["build/secret-safety.test.js"];
|
|
92
|
+
// build/integration/** is the separately-invoked MCP_INTEGRATION=1 suite (run
|
|
93
|
+
// via `npm run test:integration`) plus the packaged-CLI smoke test (`npm run
|
|
94
|
+
// test:smoke`) — neither runs as part of `npm test`. `measure-tools.test.js`
|
|
95
|
+
// is the one file under that directory that has always run as part of the
|
|
96
|
+
// normal unit suite.
|
|
97
|
+
const INTEGRATION_DIR_PREFIX = "build/integration/";
|
|
98
|
+
const INTEGRATION_DIR_ALLOWLIST = new Set(["build/integration/measure-tools.test.js"]);
|
|
99
|
+
// Pre-existing compiled test files that were not wired into ANY script before
|
|
100
|
+
// this launcher existed (discovered while building it). BAPI-683 preserves
|
|
101
|
+
// the exact current running test set rather than silently picking these up —
|
|
102
|
+
// see docs/BAPI-683-mcp-ci-windows-npm-test-launcher.md for the follow-up.
|
|
103
|
+
const KNOWN_UNREGISTERED_ORPHANS = new Set([
|
|
104
|
+
"build/conductor/conductor-runtime.integration.test.js",
|
|
105
|
+
"build/sfcc/register-site-preference.integration.test.js",
|
|
106
|
+
]);
|
|
107
|
+
/** Recursively lists compiled `*.test.js` files under `<root>/<buildDir>`, sorted and package-relative. */
|
|
108
|
+
export function discoverTestFiles(options) {
|
|
109
|
+
const { root, buildDir = DEFAULT_BUILD_DIR, fsImpl = { readdirSync } } = options;
|
|
110
|
+
const absoluteBuildDir = path.join(root, buildDir);
|
|
111
|
+
const results = [];
|
|
112
|
+
const walk = (dir) => {
|
|
113
|
+
let entries;
|
|
114
|
+
try {
|
|
115
|
+
entries = fsImpl.readdirSync(dir, { withFileTypes: true });
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
if (err?.code === "ENOENT")
|
|
119
|
+
return;
|
|
120
|
+
throw err;
|
|
121
|
+
}
|
|
122
|
+
for (const entry of entries) {
|
|
123
|
+
const full = path.join(dir, entry.name);
|
|
124
|
+
if (entry.isDirectory()) {
|
|
125
|
+
walk(full);
|
|
126
|
+
}
|
|
127
|
+
else if (entry.name.endsWith(".test.js")) {
|
|
128
|
+
results.push(path.relative(root, full).split(path.sep).join("/"));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
walk(absoluteBuildDir);
|
|
133
|
+
results.sort();
|
|
134
|
+
return results;
|
|
135
|
+
}
|
|
136
|
+
/** Throws if the module-mock or force-exit-quarantine manifest has drifted from the discovered build output. */
|
|
137
|
+
export function validateManifest(discovered) {
|
|
138
|
+
const discoveredSet = new Set(discovered);
|
|
139
|
+
const seen = new Set();
|
|
140
|
+
for (const entry of MODULE_MOCK_MANIFEST) {
|
|
141
|
+
if (seen.has(entry)) {
|
|
142
|
+
throw new Error(`run-unit-tests: duplicate module-mock manifest entry: ${entry}`);
|
|
143
|
+
}
|
|
144
|
+
seen.add(entry);
|
|
145
|
+
if (!discoveredSet.has(entry)) {
|
|
146
|
+
throw new Error(`run-unit-tests: module-mock manifest entry not found in build output: ${entry} ` +
|
|
147
|
+
`(rebuild with 'npm run build', or remove it from MODULE_MOCK_MANIFEST if the file was deleted/renamed)`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
for (const entry of FORCE_EXIT_QUARANTINE) {
|
|
151
|
+
if (seen.has(entry)) {
|
|
152
|
+
throw new Error(`run-unit-tests: quarantine entry duplicated or also present in the module-mock manifest: ${entry}`);
|
|
153
|
+
}
|
|
154
|
+
seen.add(entry);
|
|
155
|
+
if (!discoveredSet.has(entry)) {
|
|
156
|
+
throw new Error(`run-unit-tests: force-exit quarantine entry not found in build output: ${entry} ` +
|
|
157
|
+
`(rebuild with 'npm run build', or remove it from FORCE_EXIT_QUARANTINE if the file was deleted/renamed)`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/** Selects and validates the requested group's file list from the discovered inventory. */
|
|
162
|
+
export function selectTestGroup(mode, discovered) {
|
|
163
|
+
if (mode !== "normal" && mode !== "module-mocks") {
|
|
164
|
+
throw new Error(`run-unit-tests: unknown group "${mode}" (expected "normal" or "module-mocks")`);
|
|
165
|
+
}
|
|
166
|
+
validateManifest(discovered);
|
|
167
|
+
const moduleMockSet = new Set(MODULE_MOCK_MANIFEST);
|
|
168
|
+
const normal = discovered.filter((file) => {
|
|
169
|
+
if (moduleMockSet.has(file))
|
|
170
|
+
return false;
|
|
171
|
+
if (file.startsWith(INTEGRATION_DIR_PREFIX) && !INTEGRATION_DIR_ALLOWLIST.has(file))
|
|
172
|
+
return false;
|
|
173
|
+
if (KNOWN_UNREGISTERED_ORPHANS.has(file))
|
|
174
|
+
return false;
|
|
175
|
+
return true;
|
|
176
|
+
});
|
|
177
|
+
const overlap = normal.filter((file) => moduleMockSet.has(file));
|
|
178
|
+
if (overlap.length > 0) {
|
|
179
|
+
throw new Error(`run-unit-tests: file(s) present in both normal and module-mock groups: ${overlap.join(", ")}`);
|
|
180
|
+
}
|
|
181
|
+
const selected = mode === "normal" ? normal : [...MODULE_MOCK_MANIFEST];
|
|
182
|
+
if (selected.length === 0) {
|
|
183
|
+
throw new Error(`run-unit-tests: selected group "${mode}" is empty — refusing to run zero tests`);
|
|
184
|
+
}
|
|
185
|
+
return selected;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Greedily packs sorted file paths into batches whose serialized
|
|
189
|
+
* `execPath ...nodeOptions ...files` command length stays within `maxLength`.
|
|
190
|
+
* A single file that cannot fit even alone is rejected rather than spawned.
|
|
191
|
+
*/
|
|
192
|
+
export function partitionTestBatches(files, options = {}) {
|
|
193
|
+
const { execPath = process.execPath, nodeOptions = [], maxLength = MAX_COMMAND_LENGTH } = options;
|
|
194
|
+
const prefixLength = [execPath, ...nodeOptions].join(" ").length;
|
|
195
|
+
const batches = [];
|
|
196
|
+
let current = [];
|
|
197
|
+
let currentLength = prefixLength;
|
|
198
|
+
for (const file of files) {
|
|
199
|
+
const addition = 1 + file.length; // separating space + path
|
|
200
|
+
if (prefixLength + addition > maxLength) {
|
|
201
|
+
throw new Error(`run-unit-tests: "${file}" alone exceeds the command-length budget ` +
|
|
202
|
+
`(${prefixLength + addition} > ${maxLength} chars) — cannot batch it safely`);
|
|
203
|
+
}
|
|
204
|
+
if (current.length > 0 && currentLength + addition > maxLength) {
|
|
205
|
+
batches.push(current);
|
|
206
|
+
current = [];
|
|
207
|
+
currentLength = prefixLength;
|
|
208
|
+
}
|
|
209
|
+
current.push(file);
|
|
210
|
+
currentLength += addition;
|
|
211
|
+
}
|
|
212
|
+
if (current.length > 0) {
|
|
213
|
+
batches.push(current);
|
|
214
|
+
}
|
|
215
|
+
return batches;
|
|
216
|
+
}
|
|
217
|
+
/** Discovers, selects, batches, and spawns the requested test group; returns an aggregate exit code. */
|
|
218
|
+
export function runSelectedGroup(mode, options) {
|
|
219
|
+
// Validate the mode before touching the filesystem or spawning anything —
|
|
220
|
+
// an unknown group must fail fast with no discovery/spawn side effects.
|
|
221
|
+
if (mode !== "normal" && mode !== "module-mocks") {
|
|
222
|
+
throw new Error(`run-unit-tests: unknown group "${mode}" (expected "normal" or "module-mocks")`);
|
|
223
|
+
}
|
|
224
|
+
const { root, execPath = process.execPath, spawnFn = spawnSync, discoverFn = (opts) => discoverTestFiles(opts), log = console.log, } = options;
|
|
225
|
+
const discovered = discoverFn({ root });
|
|
226
|
+
const selected = selectTestGroup(mode, discovered);
|
|
227
|
+
// Split out the force-exit quarantine: those files run last, each as its own
|
|
228
|
+
// single-file spawn WITH --test-force-exit (exact tally, prompt exit despite
|
|
229
|
+
// the leaked handle). Every batched spawn runs WITHOUT the flag so its test
|
|
230
|
+
// tally stays deterministic — see FORCE_EXIT_QUARANTINE above.
|
|
231
|
+
const quarantineSet = new Set(FORCE_EXIT_QUARANTINE);
|
|
232
|
+
const batchable = selected.filter((file) => !quarantineSet.has(file));
|
|
233
|
+
const quarantined = selected.filter((file) => quarantineSet.has(file));
|
|
234
|
+
const extraFlags = mode === "module-mocks" ? ["--experimental-test-module-mocks"] : [];
|
|
235
|
+
const nodeOptions = [...extraFlags, "--test"];
|
|
236
|
+
const batches = partitionTestBatches(batchable, { execPath, nodeOptions });
|
|
237
|
+
log(`run-unit-tests: group="${mode}" files=${selected.length} batches=${batches.length}` +
|
|
238
|
+
(quarantined.length > 0 ? ` quarantined=${quarantined.length}` : ""));
|
|
239
|
+
let aggregateExit = 0;
|
|
240
|
+
const spawn = (args) => {
|
|
241
|
+
const result = spawnFn(execPath, args, {
|
|
242
|
+
cwd: root,
|
|
243
|
+
stdio: "inherit",
|
|
244
|
+
shell: false,
|
|
245
|
+
});
|
|
246
|
+
if ((result.status ?? 1) !== 0) {
|
|
247
|
+
aggregateExit = 1;
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
batches.forEach((batch, index) => {
|
|
251
|
+
log(`run-unit-tests: batch ${index + 1}/${batches.length} (${batch.length} file(s))`);
|
|
252
|
+
spawn([...nodeOptions, ...batch]);
|
|
253
|
+
});
|
|
254
|
+
quarantined.forEach((file, index) => {
|
|
255
|
+
log(`run-unit-tests: quarantined ${index + 1}/${quarantined.length} ${file} (single-file, --test-force-exit)`);
|
|
256
|
+
spawn([...nodeOptions, "--test-force-exit", file]);
|
|
257
|
+
});
|
|
258
|
+
return aggregateExit;
|
|
259
|
+
}
|