@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
package/build/worktree-core.js
CHANGED
|
@@ -144,6 +144,13 @@ export async function isExistingBranchSafeToReuse(deps, branch, baseStartPoint)
|
|
|
144
144
|
* instead of being silently reused as-is. This stays executor-agnostic: no
|
|
145
145
|
* job-type logic lives here — the caller decides the start point, the stale
|
|
146
146
|
* guard, and the freshen behavior.
|
|
147
|
+
*
|
|
148
|
+
* BAPI-727: each of the two RESET paths is followed by an untracked-file cleanup
|
|
149
|
+
* (see {@link cleanUntrackedWorktree}). That coupling is what keeps `resume`
|
|
150
|
+
* excluded BY CONSTRUCTION rather than by a job-type check: the resume caller
|
|
151
|
+
* supplies neither `freshenFromOrigin` nor `alignExistingBranchTo`, so it reaches
|
|
152
|
+
* neither reset and therefore neither cleanup, and its unpushed local work is
|
|
153
|
+
* preserved exactly as before.
|
|
147
154
|
*/
|
|
148
155
|
/**
|
|
149
156
|
* Hard-reset the branch checked out in `worktreePath` onto `ref`. Returns null on
|
|
@@ -159,6 +166,64 @@ async function hardResetWorktree(deps, worktreePath, ref) {
|
|
|
159
166
|
}
|
|
160
167
|
return null;
|
|
161
168
|
}
|
|
169
|
+
/** The one fixed, sanitized diagnostic emitted for ANY cleanup failure. */
|
|
170
|
+
const CLEANUP_FAILURE_DIAGNOSTIC = "untracked-file cleanup did not complete; continuing with the reset worktree";
|
|
171
|
+
/**
|
|
172
|
+
* BAPI-727: remove untracked residue from a worktree that was just hard-reset.
|
|
173
|
+
*
|
|
174
|
+
* `git reset --hard` restores TRACKED files but leaves untracked ones in place, so
|
|
175
|
+
* a reused worktree carried a prior attempt's scratch files into the next run. This
|
|
176
|
+
* removes them with exactly `git clean -fd`.
|
|
177
|
+
*
|
|
178
|
+
* `-x` IS FORBIDDEN, and `-fdx` doubly so: ignored paths in a prepared worktree are
|
|
179
|
+
* precisely the executor-owned assets — `.mcp.json` / `.cursor/mcp.json`
|
|
180
|
+
* registrations, worker environment files, installed dependencies, worker logs, and
|
|
181
|
+
* the provisioned `.claude/commands/` assets. `-fdx` would destroy all of them.
|
|
182
|
+
*
|
|
183
|
+
* Note that `.claude/settings.local.json` is NOT ignored by this repository, so
|
|
184
|
+
* plain `-fd` may remove it on some hosts. That is safe only because of WHERE this
|
|
185
|
+
* runs: cleanup happens during worktree PREPARATION, before command assets, deny
|
|
186
|
+
* settings, MCP registrations/trust, and worker logging are provisioned again — so
|
|
187
|
+
* anything cleanup removes is re-created by the provisioning that follows it.
|
|
188
|
+
*
|
|
189
|
+
* Stale, non-ignored `.conductor/result.json` and `.conductor/critique.md` from a
|
|
190
|
+
* prior attempt are removed intentionally: a leftover verdict artifact read by a
|
|
191
|
+
* later attempt would be a prior run's answer presented as this one's.
|
|
192
|
+
*
|
|
193
|
+
* FAIL-OPEN. Pre-change behavior performed no cleanup at all, so being unable to
|
|
194
|
+
* clean must never change the worktree row or the job outcome. Every failure path —
|
|
195
|
+
* a non-zero exit, a thrown runner — emits the one fixed diagnostic and returns
|
|
196
|
+
* normally, and the throw is caught HERE so the outer `createWorktreeForTicket()`
|
|
197
|
+
* catch cannot convert it into `create-failed`.
|
|
198
|
+
*/
|
|
199
|
+
async function cleanUntrackedWorktree(deps, worktreePath) {
|
|
200
|
+
const emit = deps.onCleanupDiagnostic;
|
|
201
|
+
const report = (message) => {
|
|
202
|
+
if (emit)
|
|
203
|
+
emit(message);
|
|
204
|
+
};
|
|
205
|
+
try {
|
|
206
|
+
const result = await deps.runCommand("git", ["clean", "-fd"], { cwd: worktreePath });
|
|
207
|
+
// Report removals even when the command later failed: paths Git printed on
|
|
208
|
+
// stdout were genuinely removed, and losing that record would make a partial
|
|
209
|
+
// cleanup invisible. Only lines with Git's standard `Removing ` prefix are
|
|
210
|
+
// read; all other output is discarded rather than serialized.
|
|
211
|
+
for (const line of result.stdout.split(/\r?\n/)) {
|
|
212
|
+
if (!line.startsWith("Removing "))
|
|
213
|
+
continue;
|
|
214
|
+
const removed = line.slice("Removing ".length).trim();
|
|
215
|
+
if (removed.length > 0)
|
|
216
|
+
report(`removed untracked path: ${removed}`);
|
|
217
|
+
}
|
|
218
|
+
if (!commandSucceeded(result))
|
|
219
|
+
report(CLEANUP_FAILURE_DIAGNOSTIC);
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
// Never interpolate the thrown exception: a command-runner error message can
|
|
223
|
+
// carry an environment dump or an argv fragment.
|
|
224
|
+
report(CLEANUP_FAILURE_DIAGNOSTIC);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
162
227
|
/**
|
|
163
228
|
* BAPI-586: resolve the worktree's `HEAD^{commit}` and the `expected` ref/commit
|
|
164
229
|
* and confirm they are equal. Returns null when they match, or a bounded,
|
|
@@ -223,6 +288,10 @@ export async function createWorktreeForTicket(deps, key, branchOverrides, worktr
|
|
|
223
288
|
if (resetError) {
|
|
224
289
|
return { key, branch, status: "create-failed", error: resetError };
|
|
225
290
|
}
|
|
291
|
+
// BAPI-727: the reset restored tracked files; drop the untracked residue a
|
|
292
|
+
// prior attempt left behind. Only after a SUCCESSFUL reset — a failed reset
|
|
293
|
+
// returns above, so a worktree in an unknown state is never cleaned.
|
|
294
|
+
await cleanUntrackedWorktree(deps, worktreePath);
|
|
226
295
|
}
|
|
227
296
|
// BAPI-586 (fresh dispatch): a guard-approved pre-existing branch is an
|
|
228
297
|
// ancestor of base but may sit at an OLDER tip. Align it EXACTLY to the
|
|
@@ -235,6 +304,10 @@ export async function createWorktreeForTicket(deps, key, branchOverrides, worktr
|
|
|
235
304
|
if (resetError) {
|
|
236
305
|
return { key, branch, status: "create-failed", error: resetError };
|
|
237
306
|
}
|
|
307
|
+
// BAPI-727: same cleanup on the fresh-dispatch alignment path. The resulting
|
|
308
|
+
// fresh-dispatch order is: stale-branch guard, Worktrunk switch, hard reset,
|
|
309
|
+
// untracked clean, then `verifyHeadMatches` below.
|
|
310
|
+
await cleanUntrackedWorktree(deps, worktreePath);
|
|
238
311
|
}
|
|
239
312
|
// BAPI-586 (fresh dispatch): verify the worktree actually starts at the
|
|
240
313
|
// pinned base. If Worktrunk seeded from an unexpected sibling despite
|
package/docs/CONDUCTOR.md
CHANGED
|
@@ -25,6 +25,23 @@ v2 splits the old local tick into two halves:
|
|
|
25
25
|
| **Reconciler** | **Server-side**, on the Bridge API worker dyno, every 30s | Selects every epic run whose status is `active`, evaluates gates, and enqueues executor jobs. Nothing to install or schedule. |
|
|
26
26
|
| **Executor** | **Locally**, on your machine | Polls for jobs, claims them, spawns worker agents, heartbeats. This is the only piece you run. |
|
|
27
27
|
|
|
28
|
+
> **⚠️ For a run against a LOCAL server, do NOT use `npx`.** The npm-published
|
|
29
|
+
> package routinely lags `main` — that is the normal steady state right after any
|
|
30
|
+
> conductor ticket merges. When the server is built from a newer `main` it mints
|
|
31
|
+
> `prompt_spec` placeholders the older published executor rejects, and the job dies
|
|
32
|
+
> instantly with `ContractError.Prompt` (`prompt_spec for job N declares unsupported
|
|
33
|
+
> placeholder '…'`). Confirmed on the BAPI-716 run: published `0.2.34` vs. local
|
|
34
|
+
> `0.2.35`, over BAPI-699's `RELATED_CONTEXT`. Build and run the local tree so the
|
|
35
|
+
> executor and server come from the same commit:
|
|
36
|
+
>
|
|
37
|
+
> ```
|
|
38
|
+
> cd mcp_server && npm run build
|
|
39
|
+
> node mcp_server/build/index.js executor --repo <name>
|
|
40
|
+
> ```
|
|
41
|
+
|
|
42
|
+
For a run against a deployed server whose version you match, the published CLI is
|
|
43
|
+
fine:
|
|
44
|
+
|
|
28
45
|
```
|
|
29
46
|
npx -y @bridge_gpt/mcp-server executor --repo <name>
|
|
30
47
|
```
|
|
@@ -47,17 +64,126 @@ pipeline step. `setup-epic` validates it locally (unique ticket keys, resolvable
|
|
|
47
64
|
`depends_on`/edge references, acyclicity) before sending anything, so a malformed
|
|
48
65
|
plan fails legibly instead of as a bare HTTP 400.
|
|
49
66
|
|
|
67
|
+
Since BAPI-754 it then calls the server's **real** validator
|
|
68
|
+
(`POST /jira/epic-runs/plan/validate`) before creating anything, so a plan the
|
|
69
|
+
server would reject — a node missing `status`, say, which the local checks do not
|
|
70
|
+
cover — no longer creates a run and incurs an automation-start charge on its way
|
|
71
|
+
to failing.
|
|
72
|
+
|
|
50
73
|
It is **idempotent**: re-running it on an epic that already has a live run reuses
|
|
51
|
-
that run rather than minting a second one. Use `--dry-run` to
|
|
52
|
-
preview the calls without mutating anything
|
|
74
|
+
that run rather than minting a second one. Use `--dry-run` to run that
|
|
75
|
+
authoritative validation and preview the calls without mutating anything; add
|
|
76
|
+
`--local-only` to skip the server entirely, which reports
|
|
77
|
+
`partial (local checks only)` and is never a substitute for the server's verdict.
|
|
53
78
|
|
|
54
79
|
Once the plan is approved the run becomes `active`, the server-side reconciler
|
|
55
80
|
picks it up within ~30s, and your local `executor` starts claiming jobs.
|
|
56
81
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
82
|
+
### `touched_files` — optional, but declare it anyway
|
|
83
|
+
|
|
84
|
+
**Plan-time file-overlap serialization is live and on by default.**
|
|
85
|
+
`planner_file_overlap_serialization_enabled` (BAPI-495, defaulted on by BAPI-677 /
|
|
86
|
+
migration 0126, on `config_code_repositories`) makes overlapping siblings gain a
|
|
87
|
+
`depends_on`/edge on each other *before* the DAG is validated, hashed, and stored,
|
|
88
|
+
while siblings with disjoint files stay parallel.
|
|
89
|
+
|
|
90
|
+
`touched_files` is the plan-time metadata that pass reads. It is a **best-effort
|
|
91
|
+
prediction, never reconciled against the real diff**, so BAPI-722 made it optional.
|
|
92
|
+
Three outcomes, and the difference between the first two is the point
|
|
93
|
+
(`_extract_predicted_touched_files`, `api/library/db/epic_runs.py:3195`):
|
|
94
|
+
|
|
95
|
+
| In the node | Meaning | Result |
|
|
96
|
+
|---|---|---|
|
|
97
|
+
| Field **absent** | The node **opts out** of preemptive serialization | **Accepted.** Every pair involving it is skipped (`undeclared_pairs_skipped`); no edge is added in either direction |
|
|
98
|
+
| `"touched_files": []` | A deliberate "this ticket predicts no file overlap" | Accepted as a *declared* node with an empty set |
|
|
99
|
+
| Field present but **malformed** | A non-list, or a list holding a blank, absolute, or non-string path | **400** — `EpicRunConflictError(code="VALIDATION")` |
|
|
100
|
+
|
|
101
|
+
Only omission is relaxed. Data you *did* supply must be well-formed. Paths are
|
|
102
|
+
repo-root-relative.
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"plan_version": 1,
|
|
107
|
+
"nodes": [
|
|
108
|
+
{ "ticket_key": "BAPI-405", "status": "planned", "depends_on": [],
|
|
109
|
+
"touched_files": ["api/routes/jira_api.py"] }
|
|
110
|
+
],
|
|
111
|
+
"edges": []
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
> **`setup-epic --dry-run` warns on a missing `touched_files`, and that warning is
|
|
116
|
+
> a planning-quality signal, not a predicted failure.** The server accepts the
|
|
117
|
+
> plan. What you lose is scheduling protection: an undeclared node is never
|
|
118
|
+
> pre-serialized against its siblings.
|
|
119
|
+
|
|
120
|
+
Declare it anyway. Serialization only ever **adds** edges — it never removes an
|
|
121
|
+
authored one — so hand-authored `depends_on` and `touched_files` compose safely.
|
|
122
|
+
Author both: the edges as your reviewable statement of intent, `touched_files` so
|
|
123
|
+
the scheduler can catch overlaps you did not anticipate.
|
|
124
|
+
|
|
125
|
+
> **Serialization is a scheduling optimization, not a safety mechanism.** It avoids
|
|
126
|
+
> *dispatching* file-overlapping siblings in parallel; it does not resolve a
|
|
127
|
+
> conflict once one exists. The safety net is reactive and independent of any
|
|
128
|
+
> prediction: a PR that a sibling's merge turns `CONFLICTING` is observed live and
|
|
129
|
+
> routed to `JOB_TYPE_REBASE` (`_merge_entry_failure_requires_rebase` in the
|
|
130
|
+
> reconciler). That backstop covers declared and undeclared nodes alike — which is
|
|
131
|
+
> exactly why omitting `touched_files` is safe to accept.
|
|
132
|
+
|
|
133
|
+
## The conductor CI gate — `conductor-ci / gate` (BAPI-695)
|
|
134
|
+
|
|
135
|
+
**Before driving a run you want CI-gated, wire its policy.** The reconciler's
|
|
136
|
+
per-ticket `ci` gate reads **`policy_json.required_checks`** (a declared
|
|
137
|
+
`RunPolicy` key) and observes those check-run conclusions at the ticket PR's
|
|
138
|
+
**current head SHA**. If that list is empty, the observer short-circuits to
|
|
139
|
+
`PASSED` with `{"no_required_checks": true}` and **runs no CI at all** — the loop
|
|
140
|
+
merges on hand-verification only. `.github/workflows/conductor-ci.yml` publishes
|
|
141
|
+
the real, always-reporting required context **`conductor-ci / gate`**; set
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
"policy_json": { "required_checks": ["conductor-ci / gate"] }
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
on every run you want gated. The workflow existing is not enough — the context has
|
|
148
|
+
to be in the run policy.
|
|
149
|
+
|
|
150
|
+
> **Wire it at creation with `--policy-file` (BAPI-754).** There is still no
|
|
151
|
+
> `--required-checks` option, but `setup-epic --policy-file <path>` sends the
|
|
152
|
+
> **complete** run policy on the create that mints the run, so the run is born with
|
|
153
|
+
> `required_checks` already in force. A run created *without* a policy still starts
|
|
154
|
+
> with an **empty** `required_checks` and a `ci` gate that short-circuits to
|
|
155
|
+
> `PASSED` — and because `setup-epic` also approves the plan, making the run
|
|
156
|
+
> `active` and visible to the reconciler within ~30s, there is no comfortable window
|
|
157
|
+
> to fix that afterwards. Supply the policy file up front.
|
|
158
|
+
>
|
|
159
|
+
> To change the policy on a run that is already live, re-run with `--policy-file`:
|
|
160
|
+
> an identical policy is a no-op, and a divergent one is **refused** with a redacted
|
|
161
|
+
> diff unless you also pass `--replace-policy` (which applies it as a complete
|
|
162
|
+
> replacement).
|
|
163
|
+
|
|
164
|
+
> **This is NOT `done_gate_config`.** The per-run `policy_json.required_checks`
|
|
165
|
+
> read by the reconciler `ci` gate is a *different* surface from the supervisor
|
|
166
|
+
> `done_gate_config.required_ci_checks_green` documented under "Supervisor config"
|
|
167
|
+
> below. BAPI-695 wires only the former, per run; it does **not** change
|
|
168
|
+
> `done_gate_config` defaults, repo-default policy, or GitHub branch protection.
|
|
169
|
+
|
|
170
|
+
**Once gated, expect this behavior:**
|
|
171
|
+
|
|
172
|
+
- The `ci` gate now waits for `conductor-ci / gate` on the ticket PR's current head.
|
|
173
|
+
A complete **red** aggregator enters the bounded `ci_fix` remediation path; a
|
|
174
|
+
**missing or still-running** current-head context stays pending (never a hard
|
|
175
|
+
fail).
|
|
176
|
+
- A **green from an older head** can never satisfy the gate after a rebase or
|
|
177
|
+
force-push — the poll is bound to the current head SHA, and the workflow's per-PR
|
|
178
|
+
concurrency cancels the superseded run so the new head publishes a fresh context.
|
|
179
|
+
- Out-of-scope PRs (forks, `dependabot/*`, non-`feature/BAPI-*`) get an intentional
|
|
180
|
+
fast green — cost control, **not** proof the suites ran.
|
|
181
|
+
|
|
182
|
+
For the exact new-run/PATCH procedure (and the **whole-object `policy_json`
|
|
183
|
+
replacement** caution — GET, merge `required_checks` locally, PATCH the whole
|
|
184
|
+
object), and the immutable case-sensitive matching of the context string, see the
|
|
185
|
+
operator runbook, **§4a "Wire the conductor CI required check"**
|
|
186
|
+
([`docs/claude/epic-conductor-v2-operator-runbook.md`](../../docs/claude/epic-conductor-v2-operator-runbook.md)).
|
|
61
187
|
|
|
62
188
|
## Conductor observability (opt-in via `--conductor`, BAPI-394)
|
|
63
189
|
|
|
@@ -48,26 +48,31 @@ marked **— none**.
|
|
|
48
48
|
|
|
49
49
|
## Profiles (a form of BLOCK)
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
the active profile is **not registered at all** — an absolute block until the group is
|
|
51
|
+
Tool registration is gated by `BRIDGE_MCP_PROFILE` (comma-separated group list,
|
|
52
|
+
resolved once at startup by `mcp_server/src/mcp-profile.ts`). A tool outside the
|
|
53
|
+
active profile is **not registered at all** — an absolute block until the group is
|
|
55
54
|
activated. `core` is always implicitly included.
|
|
56
55
|
|
|
57
|
-
| Profile |
|
|
58
|
-
|
|
59
|
-
| `core` |
|
|
60
|
-
| `pipeline-authoring` |
|
|
61
|
-
| `conductor` |
|
|
62
|
-
| `sfcc` |
|
|
56
|
+
| Profile | Registered when |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `core` | always |
|
|
59
|
+
| `pipeline-authoring` | `BRIDGE_MCP_PROFILE` includes `pipeline-authoring` or `full` |
|
|
60
|
+
| `conductor` | includes `conductor` or `full` |
|
|
61
|
+
| `sfcc` | includes `sfcc` or `full` (2 diagnostics ship in `core`; the rest are gated) |
|
|
62
|
+
|
|
63
|
+
The `pipeline-authoring` tools live in `index.ts` alongside core, gated by
|
|
64
|
+
`ACTIVE_GROUPS.has("pipeline-authoring")`.
|
|
63
65
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
> **This document deliberately states no tool counts.** Counts drift on every
|
|
67
|
+
> ticket that adds or moves a tool, and nothing here is generated, so a number
|
|
68
|
+
> written down is a number that goes stale. For the authoritative surface, read
|
|
69
|
+
> `api/library/config/mcp_tool_catalog.json` (the committed catalog, kept in sync
|
|
70
|
+
> by `scripts/sync_mcp_tool_catalog.py --check`) or call `tools/list` against a
|
|
71
|
+
> running server. The per-tool rows below are what this document is for.
|
|
67
72
|
|
|
68
73
|
---
|
|
69
74
|
|
|
70
|
-
## Core profile
|
|
75
|
+
## Core profile
|
|
71
76
|
|
|
72
77
|
### Connectivity, config & setup — no integration deps
|
|
73
78
|
|
|
@@ -78,6 +83,8 @@ These are never gated (`NEVER_GATED_ROUTE_KEYS`) or run entirely locally.
|
|
|
78
83
|
| `ping` | — none |
|
|
79
84
|
| `get_project_standards` | — none |
|
|
80
85
|
| `get_my_role` | — none |
|
|
86
|
+
| `invite_member` | — none (mints a scoped key in the Bridge DB; admin-only) |
|
|
87
|
+
| `resolve_target_status` | — none (status resolution over the repo's configured mapping) |
|
|
81
88
|
| `config_field` (get/update/list) | — none |
|
|
82
89
|
| `get_install_manifest` | — none |
|
|
83
90
|
| `apply_install_manifest` | — none |
|
|
@@ -87,6 +94,7 @@ These are never gated (`NEVER_GATED_ROUTE_KEYS`) or run entirely locally.
|
|
|
87
94
|
| `track_ticket` | — none (Bridge DB tracking record) |
|
|
88
95
|
| `update_ticket_state` | — none (Bridge DB) |
|
|
89
96
|
| `get_ticket_state` | — none (Bridge DB) |
|
|
97
|
+
| `get_ticket_state_tree` | — none (Bridge DB; live projection over existing rows) |
|
|
90
98
|
| `get_ticket_model_tier` | — none (Bridge DB difficulty) |
|
|
91
99
|
| `get_pipeline_recipe` | — none (`LOCAL`, bundled recipes) |
|
|
92
100
|
| `generate_decision_page` | — none (`LOCAL` HTML) |
|
|
@@ -186,7 +194,7 @@ These orchestrate an idea → ticket → review → start chain, so they inherit
|
|
|
186
194
|
|
|
187
195
|
---
|
|
188
196
|
|
|
189
|
-
## `pipeline-authoring` profile
|
|
197
|
+
## `pipeline-authoring` profile
|
|
190
198
|
|
|
191
199
|
Profile-gated **[BLOCK]** to register at all. `run_pipeline` / `resume_pipeline`
|
|
192
200
|
additionally inherit the dependencies of whatever steps the invoked pipeline runs
|
|
@@ -203,7 +211,7 @@ Run state is persisted via the Bridge API.
|
|
|
203
211
|
|
|
204
212
|
---
|
|
205
213
|
|
|
206
|
-
## `conductor` profile
|
|
214
|
+
## `conductor` profile
|
|
207
215
|
|
|
208
216
|
Profile-gated **[BLOCK]** to register. Most operate on the **local** conductor ledger
|
|
209
217
|
(`~/.config/bridge/events.db`), so beyond the profile gate they have no remote
|
|
@@ -222,7 +230,7 @@ integration dependency.
|
|
|
222
230
|
|
|
223
231
|
---
|
|
224
232
|
|
|
225
|
-
## `sfcc` group
|
|
233
|
+
## `sfcc` group
|
|
226
234
|
|
|
227
235
|
### Always-on diagnostics (ship in `core`)
|
|
228
236
|
|
|
@@ -231,13 +239,13 @@ integration dependency.
|
|
|
231
239
|
| `sfcc_setup_status` | — none (its purpose is to report which SFCC prerequisites are missing) |
|
|
232
240
|
| `check_permissions` | SFCC OCAPI **[BLOCK]** (probes OCAPI; reports not-OK without access / version config) |
|
|
233
241
|
|
|
234
|
-
### Gated behind the `sfcc` group
|
|
242
|
+
### Gated behind the `sfcc` group
|
|
235
243
|
|
|
236
244
|
All are profile-gated **[BLOCK]** to register, and all require SFCC OCAPI creds +
|
|
237
245
|
`version` config + a reachable sandbox → SFCC OCAPI **[BLOCK]**. Writes are
|
|
238
246
|
sandbox-only and destructive.
|
|
239
247
|
|
|
240
|
-
**Reads
|
|
248
|
+
**Reads:**
|
|
241
249
|
|
|
242
250
|
| Tool | Dependencies (class) |
|
|
243
251
|
|---|---|
|
|
@@ -264,7 +272,7 @@ sandbox-only and destructive.
|
|
|
264
272
|
| `custom_object_definition_attribute_update` | Profile-gated **[BLOCK]** · SFCC OCAPI write **[BLOCK]** |
|
|
265
273
|
| `site_preference_values_set` | Profile-gated **[BLOCK]** · SFCC OCAPI write **[BLOCK]** |
|
|
266
274
|
|
|
267
|
-
**Logs
|
|
275
|
+
**Logs:**
|
|
268
276
|
|
|
269
277
|
| Tool | Dependencies (class) |
|
|
270
278
|
|---|---|
|
|
@@ -283,7 +291,7 @@ sandbox-only and destructive.
|
|
|
283
291
|
| **SFCC OCAPI** | `check_permissions` + all 16 SFCC read/write tools | — |
|
|
284
292
|
| **SFCC WebDAV logs** | `sfcc_log_query` | — |
|
|
285
293
|
| **Deep-research flag** | `request_deep_research`, `get_deep_research` | — |
|
|
286
|
-
| **Profile gating** | all `pipeline-authoring
|
|
294
|
+
| **Profile gating** | all `pipeline-authoring`, `conductor`, and gated `sfcc` tools | — |
|
|
287
295
|
|
|
288
296
|
## Notes & caveats
|
|
289
297
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bridge_gpt/mcp-server",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.37",
|
|
4
4
|
"description": "Bridge API MCP server — exposes Jira endpoints as MCP tools for Claude Code agents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -20,13 +20,16 @@
|
|
|
20
20
|
"docs/",
|
|
21
21
|
"LICENSE"
|
|
22
22
|
],
|
|
23
|
+
"//test": "The `test` script delegates to the bounded launcher (scripts/run-unit-tests.js → src/run-unit-tests-launcher.ts, BAPI-683), which discovers build/*.test.js at runtime and spawns them in size-bounded batches so the argv never exceeds Windows' ~8191-char command-line limit. Two determinism rules from the pre-launcher script are preserved INSIDE the launcher: (1) multi-file batches run WITHOUT --test-force-exit, because that flag makes node:test exit before aggregating per-subprocess summaries and the tally becomes nondeterministic (failures still surface and still set exit 1, but the count cannot be trusted as a completeness signal); (2) build/secret-safety.test.js leaks a handle that holds the event loop ~60s after its tests finish (they run in ~147ms), so the launcher quarantines it into its own single-file --test-force-exit invocation (FORCE_EXIT_QUARANTINE in src/run-unit-tests-launcher.ts) where the tally stays exact. Do NOT add --test-force-exit to batched invocations, and do NOT remove the quarantine, until the underlying handle leak is fixed.",
|
|
23
24
|
"scripts": {
|
|
24
|
-
"build": "node scripts/bundle-version.js && node scripts/bundle-readme.js && node scripts/bundle-pipelines.js && node scripts/bundle-commands.js && node scripts/bundle-agents.js && node scripts/bundle-docs.js && tsc && node scripts/bundle-esbuild.js",
|
|
25
|
+
"build": "node scripts/bundle-version.js && node scripts/bundle-readme.js && node scripts/bundle-pipelines.js && node scripts/bundle-commands.js && node scripts/bundle-agents.js && node scripts/bundle-docs.js && tsc && node scripts/sync-agent-mirrors.js && node scripts/bundle-esbuild.js",
|
|
25
26
|
"check:version-generated": "node scripts/bundle-version.js && node scripts/check-version-generated.js",
|
|
26
27
|
"postbuild": "node scripts/prepend-shebang.cjs",
|
|
27
28
|
"start": "node build/index.js",
|
|
28
|
-
"test": "
|
|
29
|
-
"test:
|
|
29
|
+
"test": "npm run test:normal && npm run test:module-mocks",
|
|
30
|
+
"test:normal": "node scripts/run-unit-tests.js normal",
|
|
31
|
+
"test:module-mocks": "node scripts/run-unit-tests.js module-mocks",
|
|
32
|
+
"test:integration": "node --test build/integration/refresh-main.integration.test.js build/integration/command-provisioning.integration.test.js build/integration/start-tickets.integration.test.js build/integration/start-tickets-tier-handoff.integration.test.js build/integration/doctor.integration.test.js build/integration/agent-capabilities.integration.test.js build/integration/conductor-producer.integration.test.js build/integration/conductor-message-relay.integration.test.js build/integration/executor-http-runner.integration.test.js build/integration/executor-job-behaviors.integration.test.js build/integration/executor-recovery-jobs.integration.test.js build/integration/executor-spec-review-prompt.integration.test.js build/integration/resume-pre-spawn.git.integration.test.js build/integration/worker-finalization-origin.integration.test.js build/integration/post-remediation-merge-ci-wait.integration.test.js build/integration/executor-merge-supervision.integration.test.js build/integration/attachment-binary-roundtrip.integration.test.js build/integration/dependent-ticket-fresh-base.integration.test.js build/integration/execute-plan-instructions.integration.test.js build/integration/implement-ticket-finalization-order.integration.test.js build/integration/conductor-bundle-artifacts.integration.test.js build/integration/install-bridge-repo-resolution.integration.test.js build/integration/capability-report-contract.integration.test.js build/integration/request-brainstorm-general.integration.test.js build/integration/request-council-trigger-drop.integration.test.js build/integration/install-bridge-onboarding-launch.integration.test.js build/integration/install-bridge-conductor.integration.test.js build/integration/install-bridge-failure-guards.integration.test.js build/integration/learn-repository-pipeline.integration.test.js build/integration/visual-diff-mcp.integration.test.js build/integration/executor-mcp-provisioning.integration.test.js build/integration/executor-worktree-reentry.integration.test.js build/integration/sfcc-read-error-contract.integration.test.js build/integration/sfcc-response-envelope.integration.test.js build/integration/sfcc-total-error-contract.integration.test.js build/integration/serve-stdio.integration.test.js build/integration/install-alias.integration.test.js build/integration/setup-epic-validation.integration.test.js build/integration/plane-cli.integration.test.js",
|
|
30
33
|
"test:smoke": "node --test build/integration/packaged-cli-smoke.test.js",
|
|
31
34
|
"canary:agent-capabilities": "npm run build && node scripts/agent-capabilities-canary.mjs",
|
|
32
35
|
"prepublishOnly": "node scripts/bundle-assets.js && npm run build && node scripts/verify-shebang.cjs"
|
|
@@ -52,8 +55,8 @@
|
|
|
52
55
|
"node": ">=18.0.0"
|
|
53
56
|
},
|
|
54
57
|
"overrides": {
|
|
55
|
-
"fast-uri": ">=
|
|
56
|
-
"hono": ">=4.
|
|
58
|
+
"fast-uri": ">=4.1.1",
|
|
59
|
+
"hono": ">=4.13.1",
|
|
57
60
|
"@hono/node-server": "^1.19.13",
|
|
58
61
|
"ip-address": ">=10.1.1"
|
|
59
62
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "implement-ticket",
|
|
3
|
-
"description": "Generate plan,
|
|
4
|
-
"variables": ["ticket_key", "docs_dir"],
|
|
3
|
+
"description": "Generate plan, produce artifacts, checkpoint them to origin, run the plan's remaining verification faithfully, commit, open PR, close post-PR gaps, and monitor CI. Re-entrant: recovery jobs (ci_fix/remediate/rebase) safely re-run this whole recipe from step 1 — the plan-generation step reuses a fresh existing plan (reused: true, no new run) and the produce phase recognizes work already recorded in the durable ledger instead of redoing it.",
|
|
4
|
+
"variables": ["ticket_key", "docs_dir", "provider"],
|
|
5
5
|
"steps": [
|
|
6
6
|
{
|
|
7
7
|
"type": "mcp_call",
|
|
@@ -18,12 +18,22 @@
|
|
|
18
18
|
"save_locally": true,
|
|
19
19
|
"provider": "{provider}"
|
|
20
20
|
},
|
|
21
|
-
"description": "Generate implementation plan"
|
|
21
|
+
"description": "Generate implementation plan. Re-entry-safe: a non-forced request against a fresh existing plan returns reused: true and runs nothing new — the expected fast path on recovery re-entry. force is reserved for deliberate regeneration; this step never sets it. On a GATEWAY_TIMEOUT/504 response, poll get_plan (or the response's recovery_get URL) until a terminal result — never reissue this step."
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"type": "agent_task",
|
|
25
25
|
"instruction_file": "execute-plan.md",
|
|
26
|
-
"description": "
|
|
26
|
+
"description": "Produce the plan's implementation artifacts"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"type": "agent_task",
|
|
30
|
+
"instruction_file": "checkpoint-work.md",
|
|
31
|
+
"description": "Checkpoint produced work to origin before verification begins"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"type": "agent_task",
|
|
35
|
+
"instruction_file": "execute-plan-verification.md",
|
|
36
|
+
"description": "Execute the plan's remaining review, test, and rendered-UI steps before the PR opens"
|
|
27
37
|
},
|
|
28
38
|
{
|
|
29
39
|
"type": "agent_task",
|
|
@@ -36,6 +46,11 @@
|
|
|
36
46
|
"instruction_file": "create-pr.md",
|
|
37
47
|
"description": "Create a pull request with a title derived from the commit subject"
|
|
38
48
|
},
|
|
49
|
+
{
|
|
50
|
+
"type": "agent_task",
|
|
51
|
+
"instruction_file": "verify-plan.md",
|
|
52
|
+
"description": "Close post-PR plan gaps and push any correction"
|
|
53
|
+
},
|
|
39
54
|
{
|
|
40
55
|
"type": "mcp_call",
|
|
41
56
|
"tool": "update_jira_status",
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypeScript-to-Python judgment adapter (BAPI-396, conductor C4).
|
|
3
|
-
*
|
|
4
|
-
* Lets the Node conductor CLI invoke the approved Python LLM boundary
|
|
5
|
-
* (`src.python.conductor.supervisor_judgment`) WITHOUT any direct model-provider
|
|
6
|
-
* code in TypeScript. The compact judgment request is passed to the Python
|
|
7
|
-
* module over stdin as JSON, the module is spawned with `shell: false` and a
|
|
8
|
-
* list of arguments (never a shell string), and stdout is validated through the
|
|
9
|
-
* shared {@link parseSupervisorJudgmentResponse}.
|
|
10
|
-
*
|
|
11
|
-
* Every boundary failure (missing Python, timeout, non-zero exit, malformed
|
|
12
|
-
* output) is converted to a SANITIZED {@link SupervisorJudgmentError}: the
|
|
13
|
-
* caller ({@link assessSupervisorCandidate}) catches it and degrades to a
|
|
14
|
-
* deterministic assessment. Secrets, stderr text, and stack traces are never
|
|
15
|
-
* placed in the thrown error.
|
|
16
|
-
*/
|
|
17
|
-
import { spawn as nodeSpawn } from "node:child_process";
|
|
18
|
-
import path from "node:path";
|
|
19
|
-
import { fileURLToPath } from "node:url";
|
|
20
|
-
import { SupervisorJudgmentError, parseSupervisorJudgmentResponse, } from "./supervisor-judgment.js";
|
|
21
|
-
/** The Python module the adapter invokes via `python -m <module>`. */
|
|
22
|
-
export const SUPERVISOR_JUDGMENT_PYTHON_MODULE = "src.python.conductor.supervisor_judgment";
|
|
23
|
-
function nonEmpty(value) {
|
|
24
|
-
return typeof value === "string" && value.trim().length > 0;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Resolve the Python executable. Prefers the explicit, safe env override
|
|
28
|
-
* `BAPI_CONDUCTOR_PYTHON`; otherwise falls back to `python3`. No shell string is
|
|
29
|
-
* ever constructed — the returned value is used as `spawn`'s `command` arg.
|
|
30
|
-
*/
|
|
31
|
-
export function resolveSupervisorJudgmentCommand(env = process.env) {
|
|
32
|
-
if (nonEmpty(env.BAPI_CONDUCTOR_PYTHON))
|
|
33
|
-
return env.BAPI_CONDUCTOR_PYTHON.trim();
|
|
34
|
-
return "python3";
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Resolve the working directory the Python module runs from (the repo root, so
|
|
38
|
-
* `src.python...` imports resolve). Prefers the explicit `BAPI_CONDUCTOR_PYTHON_CWD`
|
|
39
|
-
* override; otherwise derives the repo root relative to this compiled module
|
|
40
|
-
* (`<repo>/mcp_server/build/conductor/<file>.js` -> `<repo>`).
|
|
41
|
-
*/
|
|
42
|
-
export function resolveSupervisorJudgmentCwd(env = process.env) {
|
|
43
|
-
if (nonEmpty(env.BAPI_CONDUCTOR_PYTHON_CWD))
|
|
44
|
-
return env.BAPI_CONDUCTOR_PYTHON_CWD.trim();
|
|
45
|
-
const here = fileURLToPath(import.meta.url);
|
|
46
|
-
// dirname=conductor, ../=build, ../../=mcp_server, ../../../=repo root.
|
|
47
|
-
return path.resolve(path.dirname(here), "..", "..", "..");
|
|
48
|
-
}
|
|
49
|
-
/** Build the secret-free stdin payload for the Python module. */
|
|
50
|
-
function buildRequestPayload(request, env) {
|
|
51
|
-
const payload = {
|
|
52
|
-
run_id: request.run_id,
|
|
53
|
-
candidate: request.candidate,
|
|
54
|
-
worker: request.worker,
|
|
55
|
-
};
|
|
56
|
-
if (nonEmpty(env.BAPI_CONDUCTOR_REPO_NAME))
|
|
57
|
-
payload.repo_name = env.BAPI_CONDUCTOR_REPO_NAME.trim();
|
|
58
|
-
if (nonEmpty(env.BAPI_CONDUCTOR_RUN_ID))
|
|
59
|
-
payload.session_id = env.BAPI_CONDUCTOR_RUN_ID.trim();
|
|
60
|
-
return payload;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Spawn the Python judgment module and resolve with the validated response.
|
|
64
|
-
* Rejects with a sanitized {@link SupervisorJudgmentError} on any boundary
|
|
65
|
-
* failure. The request is passed over stdin (keeping payloads out of the process
|
|
66
|
-
* argument list); the timeout is `config.llm_timeout_ms`.
|
|
67
|
-
*/
|
|
68
|
-
export function requestPythonSupervisorJudgment(request, config, deps = {}) {
|
|
69
|
-
const spawnFn = deps.spawn ?? nodeSpawn;
|
|
70
|
-
const env = deps.env ?? process.env;
|
|
71
|
-
const command = resolveSupervisorJudgmentCommand(env);
|
|
72
|
-
const cwd = resolveSupervisorJudgmentCwd(env);
|
|
73
|
-
return new Promise((resolve, reject) => {
|
|
74
|
-
let settled = false;
|
|
75
|
-
let stdout = "";
|
|
76
|
-
let child;
|
|
77
|
-
try {
|
|
78
|
-
child = spawnFn(command, ["-m", SUPERVISOR_JUDGMENT_PYTHON_MODULE], {
|
|
79
|
-
cwd,
|
|
80
|
-
shell: false,
|
|
81
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
reject(new SupervisorJudgmentError("python judgment process could not be started"));
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
const finish = (fn, value) => {
|
|
89
|
-
if (settled)
|
|
90
|
-
return;
|
|
91
|
-
settled = true;
|
|
92
|
-
clearTimeout(timer);
|
|
93
|
-
fn(value);
|
|
94
|
-
};
|
|
95
|
-
// NOTE: the timer is intentionally NOT unref'd. It must keep the event loop
|
|
96
|
-
// alive so the timeout actually fires and rejects when the Python subprocess
|
|
97
|
-
// hangs (and so the deterministic degraded path is taken). The timer is
|
|
98
|
-
// always cleared in `finish`, so it never outlives a settled judgment.
|
|
99
|
-
const timer = setTimeout(() => {
|
|
100
|
-
try {
|
|
101
|
-
child.kill("SIGKILL");
|
|
102
|
-
}
|
|
103
|
-
catch {
|
|
104
|
-
/* best-effort */
|
|
105
|
-
}
|
|
106
|
-
finish(reject, new SupervisorJudgmentError("python judgment timed out"));
|
|
107
|
-
}, config.llm_timeout_ms);
|
|
108
|
-
child.on("error", () => finish(reject, new SupervisorJudgmentError("python judgment process error")));
|
|
109
|
-
child.stdout?.on("data", (chunk) => {
|
|
110
|
-
stdout += String(chunk);
|
|
111
|
-
});
|
|
112
|
-
child.on("close", (code) => {
|
|
113
|
-
if (code !== 0) {
|
|
114
|
-
finish(reject, new SupervisorJudgmentError("python judgment exited non-zero"));
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
try {
|
|
118
|
-
const parsed = parseSupervisorJudgmentResponse(stdout.trim());
|
|
119
|
-
finish(resolve, parsed);
|
|
120
|
-
}
|
|
121
|
-
catch {
|
|
122
|
-
finish(reject, new SupervisorJudgmentError("python judgment returned malformed output"));
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
try {
|
|
126
|
-
child.stdin?.write(JSON.stringify(buildRequestPayload(request, env)));
|
|
127
|
-
child.stdin?.end();
|
|
128
|
-
}
|
|
129
|
-
catch {
|
|
130
|
-
finish(reject, new SupervisorJudgmentError("python judgment stdin write failed"));
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Build the default injectable judgment client used by the runtime. The returned
|
|
136
|
-
* function matches {@link SupervisorJudgmentClient}; it forwards each request to
|
|
137
|
-
* {@link requestPythonSupervisorJudgment} with the resolved config/deps.
|
|
138
|
-
*/
|
|
139
|
-
export function createDefaultSupervisorJudgmentClient(config, deps = {}) {
|
|
140
|
-
return (request) => requestPythonSupervisorJudgment(request, config, deps);
|
|
141
|
-
}
|