@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
package/README.md
CHANGED
|
@@ -32,8 +32,7 @@ account — it will ask.
|
|
|
32
32
|
`--api-key` or `BAPI_API_KEY` — the installer writes that store, it does not read
|
|
33
33
|
it back.
|
|
34
34
|
- Writes outside your project root only when you pick a host whose configuration is
|
|
35
|
-
global: OpenAI Codex (`~/.codex/config.toml`)
|
|
36
|
-
(`~/.copilot/mcp-config.json`).
|
|
35
|
+
global: OpenAI Codex (`~/.codex/config.toml`).
|
|
37
36
|
|
|
38
37
|
**Prerequisites**
|
|
39
38
|
|
|
@@ -41,8 +40,8 @@ account — it will ask.
|
|
|
41
40
|
- **A project directory** — run the command from the folder your editor opens: your
|
|
42
41
|
repository root, the one containing `.git`. No `package.json` is required — SFCC
|
|
43
42
|
cartridge repos, Python, Go, Rust, and other non-Node projects work the same way.
|
|
44
|
-
- **An MCP-capable editor or CLI**: Claude Code, GitHub Copilot in VS Code,
|
|
45
|
-
|
|
43
|
+
- **An MCP-capable editor or CLI**: Claude Code, GitHub Copilot in VS Code, Cursor,
|
|
44
|
+
Windsurf, or OpenAI Codex.
|
|
46
45
|
- **No Bridge account needed.** The installer can create one for you from just an
|
|
47
46
|
email address.
|
|
48
47
|
|
|
@@ -87,13 +86,13 @@ npx -y @bridge_gpt/mcp-server install
|
|
|
87
86
|
a token:
|
|
88
87
|
|
|
89
88
|
```
|
|
90
|
-
1.
|
|
91
|
-
2.
|
|
89
|
+
1. I need a token
|
|
90
|
+
2. I already have a token
|
|
92
91
|
```
|
|
93
92
|
|
|
94
|
-
- Choose **
|
|
93
|
+
- Choose **1** if you have nothing yet. It asks for your email address and a name
|
|
95
94
|
for your new Bridge project, then creates both for you.
|
|
96
|
-
- Choose **
|
|
95
|
+
- Choose **2** if someone gave you a token — either a Bridge API key or an invite
|
|
97
96
|
code. Paste it at the hidden prompt; you do not have to say which kind it is,
|
|
98
97
|
because the installer recognizes it. Nothing is echoed as you type.
|
|
99
98
|
|
|
@@ -120,8 +119,8 @@ include a host the installer can launch, the run has to be on an interactive
|
|
|
120
119
|
terminal, and you have to accept the consent prompt (*"Bridge can configure and set
|
|
121
120
|
up this project for you automatically. Open a `<tool>` session to do that now?
|
|
122
121
|
(Y/n)"*). Claude Code is the only selection that launches on its own. A
|
|
123
|
-
Cursor-only, Copilot,
|
|
124
|
-
|
|
122
|
+
Cursor-only, Copilot, Codex, or Windsurf selection, a non-interactive run, or a
|
|
123
|
+
declined prompt all print the command to continue by hand instead. Pass
|
|
125
124
|
`--agent claude` or `--agent cursor-agent` to override the decision outright.
|
|
126
125
|
|
|
127
126
|
**7. Follow the next step the session shows you, if it shows one.** The installer
|
|
@@ -143,7 +142,7 @@ Want to see what would happen without changing anything? Add `--dry-run`.
|
|
|
143
142
|
|
|
144
143
|
| Path | What it is | Commit it? |
|
|
145
144
|
|---|---|---|
|
|
146
|
-
| `.claude/commands/`, `.cursor/commands/` | The
|
|
145
|
+
| `.claude/commands/`, `.cursor/commands/`, `.github/prompts/`, `.github/skills/` | The generated workflow commands for supported agent hosts | Yes |
|
|
147
146
|
| `.claude/agents/` and editor equivalents | Agent definitions used by those commands | Yes |
|
|
148
147
|
| `.bridge/config` | Your project manifest — the repository name and which MCP targets to provision. Deliberately secret-free | Yes |
|
|
149
148
|
| `.bridge/pipelines/`, `.bridge/instructions/` | Editable pipeline definitions | Yes |
|
|
@@ -173,8 +172,8 @@ Cursor's agent instead of Claude Code.
|
|
|
173
172
|
|
|
174
173
|
**Selecting Windsurf prints instructions instead of writing config.** Windsurf's
|
|
175
174
|
global `mcp_config.json` is never modified automatically; the installer reports the
|
|
176
|
-
entry for you to paste yourself. Codex
|
|
177
|
-
|
|
175
|
+
entry for you to paste yourself. Codex *is* written automatically, even though its
|
|
176
|
+
file is global too.
|
|
178
177
|
|
|
179
178
|
**Your key is stored for the tools that read the store.** The MCP server and the
|
|
180
179
|
shell-spawned tooling (`start-tickets` and its model routing) resolve it from
|
|
@@ -261,7 +260,7 @@ Creates a brand-new Bridge project for that address and your first admin key in
|
|
|
261
260
|
command. No account, no key, and no invite needed beforehand. The address labels
|
|
262
261
|
your new workspace and may receive a setup message; delivery is best-effort, so
|
|
263
262
|
nothing waits on it. The email is visible as you type (it is not a secret) and is
|
|
264
|
-
never written to a log. This is the same route as answering **
|
|
263
|
+
never written to a log. This is the same route as answering **1** at the prompt.
|
|
265
264
|
|
|
266
265
|
**You were sent an invite code.**
|
|
267
266
|
|
|
@@ -300,7 +299,7 @@ created or spent.
|
|
|
300
299
|
| `--invite [code]` | Redeem an invite code. Omit the value for the hidden prompt (recommended) |
|
|
301
300
|
| `--api-key <key>` | Use an existing Bridge API key |
|
|
302
301
|
| `--repo <name>` | Name the registered repository instead of resolving or asking for it |
|
|
303
|
-
| `--tools <list>` | Configure specific MCP hosts without the picker. Accepted IDs are exactly `claude-code`, `cursor`, `copilot-vscode`, `
|
|
302
|
+
| `--tools <list>` | Configure specific MCP hosts without the picker. Accepted IDs are exactly `claude-code`, `cursor`, `copilot-vscode`, `codex`, and `windsurf` (e.g. `claude-code,cursor`); any other value is a parse error |
|
|
304
303
|
| `--agent claude\|cursor-agent` | Which agent to open for the final configuration step. **No default** — without this flag the agent is derived from the hosts you selected, and an explicit value always wins, including for a host you did not select |
|
|
305
304
|
| `--dry-run` | Preview every step without writing, contacting Bridge, resolving or prompting for a credential, or opening anything. Genuinely inert: it returns before the project-root prompt, before the repository is resolved, and before any tool-selection prompt, so a value it cannot know locally (an unresolved repository name, an unselected tool) is shown as **not yet known** rather than guessed |
|
|
306
305
|
| `--force` | Overwrite an existing stored key without asking |
|
|
@@ -352,7 +351,7 @@ later boot.
|
|
|
352
351
|
"mcpServers": {
|
|
353
352
|
"bridge": {
|
|
354
353
|
"command": "npx",
|
|
355
|
-
"args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.
|
|
354
|
+
"args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.55", "serve"],
|
|
356
355
|
"env": {
|
|
357
356
|
"BAPI_BASE_URL": "https://bridgegpt-api.com",
|
|
358
357
|
"BAPI_REPO_NAME": "your-repo",
|
|
@@ -366,7 +365,7 @@ later boot.
|
|
|
366
365
|
</details>
|
|
367
366
|
|
|
368
367
|
<details>
|
|
369
|
-
<summary><strong>
|
|
368
|
+
<summary><strong>GitHub Copilot (.vscode/mcp.json)</strong></summary>
|
|
370
369
|
|
|
371
370
|
```json
|
|
372
371
|
{
|
|
@@ -374,7 +373,7 @@ later boot.
|
|
|
374
373
|
"bridge": {
|
|
375
374
|
"type": "stdio",
|
|
376
375
|
"command": "npx",
|
|
377
|
-
"args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.
|
|
376
|
+
"args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.55", "serve"],
|
|
378
377
|
"env": {
|
|
379
378
|
"BAPI_BASE_URL": "https://bridgegpt-api.com",
|
|
380
379
|
"BAPI_REPO_NAME": "your-repo",
|
|
@@ -396,33 +395,7 @@ later boot.
|
|
|
396
395
|
"bridge": {
|
|
397
396
|
"type": "stdio",
|
|
398
397
|
"command": "npx",
|
|
399
|
-
"args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.
|
|
400
|
-
"env": {
|
|
401
|
-
"BAPI_BASE_URL": "https://bridgegpt-api.com",
|
|
402
|
-
"BAPI_REPO_NAME": "your-repo",
|
|
403
|
-
"BAPI_API_KEY": "your-api-key",
|
|
404
|
-
"BAPI_DOCS_DIR": "docs/tmp"
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
```
|
|
410
|
-
</details>
|
|
411
|
-
|
|
412
|
-
<details>
|
|
413
|
-
<summary><strong>GitHub Copilot CLI (~/.copilot/mcp-config.json)</strong></summary>
|
|
414
|
-
|
|
415
|
-
Copilot CLI reads a single global file. The installer writes this one for you when
|
|
416
|
-
you select `copilot-cli`; the shape below is what it produces.
|
|
417
|
-
|
|
418
|
-
```json
|
|
419
|
-
{
|
|
420
|
-
"mcpServers": {
|
|
421
|
-
"bridge": {
|
|
422
|
-
"type": "local",
|
|
423
|
-
"command": "npx",
|
|
424
|
-
"args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.53", "serve"],
|
|
425
|
-
"tools": ["*"],
|
|
398
|
+
"args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.55", "serve"],
|
|
426
399
|
"env": {
|
|
427
400
|
"BAPI_BASE_URL": "https://bridgegpt-api.com",
|
|
428
401
|
"BAPI_REPO_NAME": "your-repo",
|
|
@@ -445,7 +418,7 @@ Windsurf only supports global MCP configuration.
|
|
|
445
418
|
"mcpServers": {
|
|
446
419
|
"bridge": {
|
|
447
420
|
"command": "npx",
|
|
448
|
-
"args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.
|
|
421
|
+
"args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.55", "serve"],
|
|
449
422
|
"env": {
|
|
450
423
|
"BAPI_BASE_URL": "https://bridgegpt-api.com",
|
|
451
424
|
"BAPI_REPO_NAME": "your-repo",
|
|
@@ -464,7 +437,7 @@ Windsurf only supports global MCP configuration.
|
|
|
464
437
|
```toml
|
|
465
438
|
[mcp_servers.bridge]
|
|
466
439
|
command = "npx"
|
|
467
|
-
args = ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.
|
|
440
|
+
args = ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.55", "serve"]
|
|
468
441
|
|
|
469
442
|
[mcp_servers.bridge.env]
|
|
470
443
|
BAPI_BASE_URL = "https://bridgegpt-api.com"
|
|
@@ -802,7 +775,16 @@ Repository and ticket housekeeping commands, beyond the tiers above. Implementat
|
|
|
802
775
|
| `/parse-repository` | Queue a background job to index the repository for Bridge AI agents |
|
|
803
776
|
| `/scan-tickets` | Sync recently-updated Jira tickets and backfill workflow timestamps |
|
|
804
777
|
|
|
805
|
-
>
|
|
778
|
+
> **GitHub Copilot modes.** On VS Code's Local agent, Bridge provisions one
|
|
779
|
+
> `.github/prompts/<command>.prompt.md` prompt per packaged command, including
|
|
780
|
+
> `/explore-ticket`. On VS Code Agent Host, prompt files are not loaded, so the
|
|
781
|
+
> installer provisions the same canonical command as a project skill at
|
|
782
|
+
> `.github/skills/<command>/SKILL.md`; invoke that skill by its slash-command
|
|
783
|
+
> name. Bridge does not claim Copilot CLI or cloud-agent workflow support from
|
|
784
|
+
> this scaffold alone. If either artifact is not discovered, use VS Code's Chat
|
|
785
|
+
> Customizations diagnostics, confirm the workspace is trusted, and invoke the
|
|
786
|
+
> workflow manually with its full instructions rather than assuming the slash
|
|
787
|
+
> command is available.
|
|
806
788
|
|
|
807
789
|
### Extra Capabilities
|
|
808
790
|
|
|
@@ -1090,12 +1072,54 @@ all, because an unknown owner is not the same as a not-ready one. No branch,
|
|
|
1090
1072
|
including every error path, ever offers you two paths.
|
|
1091
1073
|
|
|
1092
1074
|
`drive-epic` owns no branch behavior of its own — it forwards `--feature-branch
|
|
1093
|
-
<name
|
|
1094
|
-
below). With
|
|
1075
|
+
<name>`, `--into-base`, and `--attended` verbatim to `setup-epic`, which decides
|
|
1076
|
+
the strategy and the posture (see below). With none of them, a multi-ticket epic
|
|
1077
|
+
runs on `epic/<KEY>`, unattended.
|
|
1078
|
+
|
|
1079
|
+
**The composed bring-up is two-phase (BAPI-1102).** With `--plan-file` on a
|
|
1080
|
+
repository whose readiness is missing only the runtime facts, one invocation runs,
|
|
1081
|
+
in order: the **control plane** (Bridge API server + reconciler, each gated on its
|
|
1082
|
+
own readiness), then `setup-epic` to create and approve the run, then **executor
|
|
1083
|
+
lanes scoped to that run** with `--epic-run-id <run>`, then the **dead-man
|
|
1084
|
+
observer** last, then the ready banner. The order is forced: an executor lane must
|
|
1085
|
+
carry an explicit claim scope, and the run it is scoped to does not exist until the
|
|
1086
|
+
server is up and `setup-epic` has run.
|
|
1087
|
+
|
|
1088
|
+
A composed plane serves **exactly one** run; start a second plane for a second
|
|
1089
|
+
epic. If `setup-epic` fails, the control plane is left running and **no executor
|
|
1090
|
+
lane is spawned**. If the lanes fail to become ready, the control plane and the
|
|
1091
|
+
committed run are both left intact and the observer is not started — nothing is
|
|
1092
|
+
rolled back, because a local process that failed to start says nothing about
|
|
1093
|
+
whether the run is valid.
|
|
1094
|
+
|
|
1095
|
+
"Plane ready" reports **processes**, not dispatchability: if the run cuts an epic
|
|
1096
|
+
branch, the reconciler holds ticket dispatch until that branch's index scope
|
|
1097
|
+
finishes preparing.
|
|
1095
1098
|
|
|
1096
1099
|
Two conductors is a transitional state. When one is eliminated, `drive-epic` is
|
|
1097
1100
|
the only thing that changes.
|
|
1098
1101
|
|
|
1102
|
+
### `plane up` — claim scope is required
|
|
1103
|
+
|
|
1104
|
+
`plane up` starts the runtime on its own, and every executor lane it starts needs
|
|
1105
|
+
an explicit claim scope:
|
|
1106
|
+
|
|
1107
|
+
```
|
|
1108
|
+
npx -y @bridge_gpt/mcp-server plane up --epic-run-id <run-id> # repeatable
|
|
1109
|
+
npx -y @bridge_gpt/mcp-server plane up --repo-wide # or repository-wide
|
|
1110
|
+
```
|
|
1111
|
+
|
|
1112
|
+
The two are mutually exclusive. Asked to start lanes with neither, `plane up`
|
|
1113
|
+
**refuses before spawning anything**, in the executor's own words. That is not a
|
|
1114
|
+
new restriction — an executor started with no claim scope has refused to start
|
|
1115
|
+
since BAPI-1026 — it is that refusal moved to where it is actionable, instead of
|
|
1116
|
+
surfacing as a member crash and a full plane rollback.
|
|
1117
|
+
|
|
1118
|
+
`plane status` reports the lifecycle phase (control plane starting/ready, lanes
|
|
1119
|
+
starting/ready, observer active, plane ready) and the epic run the plane is bound
|
|
1120
|
+
to. `plane down` handles every intermediate phase: it stops the bound run first,
|
|
1121
|
+
then signals the recorded process group.
|
|
1122
|
+
|
|
1099
1123
|
### `setup-epic`
|
|
1100
1124
|
|
|
1101
1125
|
Bootstraps an Epic Conductor v2 run in one command — creates the epic run, stores the plan DAG, and approves it:
|
|
@@ -1118,21 +1142,56 @@ branch, matching plain `start-tickets`.
|
|
|
1118
1142
|
> name, or to force a branch for a single-node plan. Passing both is a parse error,
|
|
1119
1143
|
> refused before any file read, credential resolution, or network call.
|
|
1120
1144
|
|
|
1145
|
+
**A run that selects an epic branch is created UNATTENDED (BAPI-1102).** Its
|
|
1146
|
+
`policy_json` carries `posture: "unattended"` and `v2_auto_merge_enabled: true`, so
|
|
1147
|
+
child PRs merge into the epic branch without parking for a human at every gate. The
|
|
1148
|
+
**integration PR into the repository base branch stays human-gated.** The run's CI
|
|
1149
|
+
gate is stamped **server-side at first approval** — from your repository's declared
|
|
1150
|
+
default, or, when it declares none, as an explicit recorded `no_ci_gate` mode.
|
|
1151
|
+
|
|
1152
|
+
> **Behavior change (BAPI-1102).** Pass `--attended` to restore the previous
|
|
1153
|
+
> composition: `base_branch` plus an explicitly requested `--review-policy`, with no
|
|
1154
|
+
> posture and no auto-merge authorization. `--into-base`, single-node plans, and
|
|
1155
|
+
> branch-silent invocations are **unchanged** — they send no `policy_json` at all,
|
|
1156
|
+
> byte for byte as before. A `--policy-file` still supersedes composition entirely;
|
|
1157
|
+
> combining `--attended` with a file that declares `posture: "unattended"` is a named
|
|
1158
|
+
> refusal rather than a silent winner.
|
|
1159
|
+
|
|
1160
|
+
An unattended run has two one-time **repository** prerequisites — consent
|
|
1161
|
+
(`unattended_epic_implementer_allowed`) and a verified notify webhook default — plus
|
|
1162
|
+
confirmed default-branch review/CI workflows. Each is refused by name **before any
|
|
1163
|
+
run row is created** (`target_not_allowed`, `webhook_unverified`,
|
|
1164
|
+
`repository_readiness_unconfirmed`), and `drive-epic` readiness and `doctor` both
|
|
1165
|
+
list them with their current state. `notify.local_sink` does not satisfy the webhook
|
|
1166
|
+
prerequisite.
|
|
1167
|
+
|
|
1168
|
+
> **Rollout note.** The client-side default and the server-side admission,
|
|
1169
|
+
> stamping, and readiness changes must be released as **one compatible unit**. The
|
|
1170
|
+
> new default's shape (`v2_auto_merge_enabled: true` with no `required_checks`) is
|
|
1171
|
+
> exactly what the create route refused before BAPI-1102, so shipping the client
|
|
1172
|
+
> half alone would 422 every unattended run at `POST /jira/epic-runs/runs`.
|
|
1173
|
+
> Deploying only the server half is safe and inert: it narrows two refusals and adds
|
|
1174
|
+
> a first-approval stamp, and **rewrites no existing run**. No database migration and
|
|
1175
|
+
> no new environment variable is introduced — `config_projects.unattended_epic_implementer_allowed`
|
|
1176
|
+
> and `epic_supervisor_setup.done_gate_config` already exist and are read as-is.
|
|
1177
|
+
|
|
1121
1178
|
Once the plan is approved, the **server-side reconciler** picks the run up within ~30s. To execute claimed jobs on your machine, run `executor`:
|
|
1122
1179
|
|
|
1123
1180
|
```
|
|
1124
1181
|
npx -y @bridge_gpt/mcp-server executor --repo <name>
|
|
1125
1182
|
```
|
|
1126
1183
|
|
|
1127
|
-
### `
|
|
1184
|
+
### `implement-epic`
|
|
1128
1185
|
|
|
1129
1186
|
The deterministic half of the `/conduct-epic` loop: it owns the epic branch, a
|
|
1130
1187
|
versioned local checkpoint, a per-epic lock, and the read-only probes the loop
|
|
1131
1188
|
decides on. It never creates or mutates an `epic_run` — that is the server-side
|
|
1132
1189
|
v2 reconciler's job, and `init` refuses to start when one is already active.
|
|
1190
|
+
This is EPIC-LEVEL orchestration, distinct from the ticket-level
|
|
1191
|
+
`implement-ticket` command.
|
|
1133
1192
|
|
|
1134
1193
|
```
|
|
1135
|
-
npx -y @bridge_gpt/mcp-server
|
|
1194
|
+
npx -y @bridge_gpt/mcp-server implement-epic <verb> [flags]
|
|
1136
1195
|
```
|
|
1137
1196
|
|
|
1138
1197
|
**Verbs**
|
|
@@ -1198,9 +1257,9 @@ appear in a command argument, in stdout/stderr, or in a journal line.
|
|
|
1198
1257
|
|
|
1199
1258
|
### Conductor (epic & multi-agent orchestration)
|
|
1200
1259
|
|
|
1201
|
-
Conductor is an **opt-in, off-by-default** layer for epic supervision, inter-agent messaging, done-gate evaluation, local git-hook event producers, and conditional auto-merge. Its full reference — the v2 architecture (server-side reconciler + local executor), `setup-epic`, `
|
|
1260
|
+
Conductor is an **opt-in, off-by-default** layer for epic supervision, inter-agent messaging, done-gate evaluation, local git-hook event producers, and conditional auto-merge. Its full reference — the v2 architecture (server-side reconciler + local executor), `setup-epic`, `epic-implementer install-git-hooks`, the supervisor `done_gate_config` / `auto_merge_enabled` settings, and the observability stream — lives in **[CONDUCTOR.md](./docs/CONDUCTOR.md)**. (The event-ledger CLI was renamed from `conductor` to `epic-implementer`; the retained `conductor` bin name is now a fixed migration pointer.)
|
|
1202
1261
|
|
|
1203
|
-
> The v1 `
|
|
1262
|
+
> The v1 `epic-implementer epic-tick` command is **frozen** — it throws on every invocation. There is nothing to schedule locally, and `epic-implementer doctor` flags any epic-tick schedule left over from an earlier release so you can cancel it.
|
|
1204
1263
|
|
|
1205
1264
|
## Custom Pipelines
|
|
1206
1265
|
|
|
@@ -1487,17 +1546,18 @@ The full surface, for when you need the complete enumeration. Day-to-day, use [U
|
|
|
1487
1546
|
|
|
1488
1547
|
### MCP tools
|
|
1489
1548
|
|
|
1490
|
-
The authoritative tool catalog covers **
|
|
1549
|
+
The authoritative tool catalog covers **75 tools** (enumerated below). What's actually registered in a session depends on `BRIDGE_MCP_PROFILE`: the default `core` profile loads a trimmed subset, and the conductor/pipeline-authoring/SFCC tools are added only under their respective profiles (see [Environment Variables](#environment-variables)). Async AI tools follow a request/get pattern: call the `request_*` tool to kick off generation, then the matching `get_*` tool to retrieve the result (or pass `wait_for_result: true` to poll automatically).
|
|
1491
1550
|
|
|
1492
1551
|
- **Connectivity & identity** — `ping` (its JSON also carries `docs_dir`, `role`, and `customer_type`)
|
|
1493
1552
|
- **Team & access** — `invite_member` (admin-only; mints a scoped access key for a teammate on an already-configured project — the plaintext key is shown exactly once)
|
|
1494
1553
|
- **Jira tickets** — `get_tickets`, `get_ticket`, `create_ticket`, `update_ticket_description`, `add_comment`, `get_comments`
|
|
1495
1554
|
- **Attachments** — `attachment` (operations: `upload`, `download`, `list`)
|
|
1496
1555
|
- **AI generation (request/get)** — `request_plan_generation`/`get_plan`, `create_doc`/`get_doc` (design docs by `doc_type`: tdd/architecture/fsd/prd, where `architecture` is an alias of `tdd`), `request_ticket_review` (writes both `get_clarifying_questions` and `get_ticket_critique`), `request_reimplement_context`/`get_reimplement_context`, `request_council`/`get_council`, `request_deep_research`/`get_deep_research`
|
|
1556
|
+
- **Bounded waits** — `wait_for_ticket_review`, `wait_for_ci_checks`. Each call waits at most 240 s and returns `state: "ready" | "pending" | "error"`; `pending` is a normal, resumable result you call again on, never a failure. They exist so an agent can wait without a foreground `sleep` and without binding a long server-side operation to the 900 s MCP client deadline. `wait_for_ci_checks` reports only that checks are **terminal** — deciding pass or fail stays with the caller.
|
|
1497
1557
|
- **Other AI** — `second_opinion`, `generate_image`, `generate_decision_page`, `visual_diff` (deterministic pixel diff of a rendered URL vs a design comp)
|
|
1498
1558
|
- **Ticket lifecycle** — `track_ticket`, `update_ticket_state`, `get_ticket_state`, `get_ticket_state_tree` (live repo-wide lifecycle + dependency tree; read-only, no mutation parameter)
|
|
1499
1559
|
- **Jira status** — `update_jira_status` (pass `status: "auto"` to resolve the configured post-PR status server-side)
|
|
1500
|
-
- **Repository & CI** — `parse_repository` (`action`: `start`, `status`), `regenerate_directory_map`, `create_pull_request`, `merge_pull_request`, `resolve_ci_checks`, `poll_ci_checks`
|
|
1560
|
+
- **Repository & CI** — `parse_repository` (`action`: `start`, `status`), `regenerate_directory_map`, `create_pull_request`, `merge_pull_request`, `resolve_ci_checks`, `poll_ci_checks`, `wait_for_ci_checks` (the last two are hidden until `ci_check_config` resolves, and share one visibility gate)
|
|
1501
1561
|
- **Pipelines & automation** — `get_pipeline_recipe` (returns a fully resolved recipe the agent executes step-by-step)
|
|
1502
1562
|
- **Config** — `get_project_standards`, `config_field` (operations: `get`, `update`, `list`)
|
|
1503
1563
|
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// AUTO-GENERATED — do not edit manually. Regenerate with: npm run build
|
|
2
|
+
// This file is produced by scripts/bundle-agent-guidance.js from mcp_server/agent-guidance.md
|
|
3
|
+
export const AGENT_GUIDANCE = "### Get Project Standards (`get_project_standards`)\n\n**When to use it:** (Implementation | Refinement) Before writing or reviewing code, so the agent applies this project's recorded coding standards instead of generic defaults.\n\n**How to use it:** Call the `get_project_standards` MCP tool directly — it takes no required input and returns the project's recorded standards text.\n\n### Second Opinion (`second_opinion`)\n\n**When to use it:** (Architecture | Refinement | Implementation) Any time you want a quick sanity check on a plan, draft, or decision from a fresh perspective.\n\n**How to use it:** Ask your agent — \"Get a second opinion from Gemini on whether the BAPI-123 plan's migration step is safe to run against production.\"\n\n### Council (`request_council`)\n\n**When to use it:** (Architecture | Refinement) Early, when you want a spread of approaches — technical for how to build it, design for how it should look, discovery for what still needs figuring out before a real ticket exists, general for a quick brief-driven pass before the repository is indexed.\n\n**How to use it:** `/council <question>`\n\n### Review Ticket (`request_ticket_review`)\n\n**When to use it:** (Refinement) Right after a ticket is drafted, before anyone starts building — to surface gaps and tighten it.\n\n**How to use it:** `/review-tickets BAPI-123` (command only — \"review\" as free text is easily mistaken for a freehand agent review). A single key reviews inline in the current session — no terminal tab, no worktree. For several tickets at once, `/review-tickets BAPI-123 BAPI-456` opens one terminal tab per ticket and reviews them in parallel with no worktrees; every review flag applies, and `--review KEY=auto,rounds=N` sets per-ticket overrides.";
|
|
@@ -345,6 +345,9 @@ export function createClaudeExecutorAdapter(spec, deps = {}) {
|
|
|
345
345
|
if (input.workerBranch !== undefined) {
|
|
346
346
|
envOptions.workerBranch = input.workerBranch;
|
|
347
347
|
}
|
|
348
|
+
if (input.declaredTouchedFiles !== undefined) {
|
|
349
|
+
envOptions.declaredTouchedFiles = input.declaredTouchedFiles;
|
|
350
|
+
}
|
|
348
351
|
return {
|
|
349
352
|
executable: spec.command,
|
|
350
353
|
argv: buildClaudeArgv(input.prompt, input.modelAlias, input.mcpConfigPath, input.posture),
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Resolves the `claude` binary against the *explicitly supplied PATH* (not the
|
|
5
5
|
* ambient process default) and builds the launched-run invocation by delegating
|
|
6
|
-
* to the shared `renderScheduledPrompt` renderer (no hard-coded
|
|
6
|
+
* to the shared `renderScheduledPrompt` renderer (no hard-coded per-command
|
|
7
7
|
* prompt). It emits `{ exe, args: ["-p", prompt] }`. Claude Code has no
|
|
8
8
|
* working-directory flag, so the cwd is always set by the launching unit — this
|
|
9
9
|
* adapter must never add a working-directory argument to the invocation.
|
|
@@ -41,8 +41,8 @@ export async function resolveCommandOnPath(command, envPath, deps) {
|
|
|
41
41
|
return pathApi.normalize(candidate);
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
|
-
* Backward-compatibility shim for callers that quoted an idea-file path for
|
|
45
|
-
*
|
|
44
|
+
* Backward-compatibility shim for callers that quoted an idea-file path for the
|
|
45
|
+
* pre-rename automation prompt. Generalized prompt-token quoting now lives in
|
|
46
46
|
* `quotePromptToken`; this preserves the original quote semantics (always wrap in
|
|
47
47
|
* double quotes, escape embedded quotes) for any remaining path callers.
|
|
48
48
|
*/
|
|
@@ -32,15 +32,14 @@ function schemaSupportsAutoFlag(schema) {
|
|
|
32
32
|
* the normalized `input.args`, plus (only where the command can parse them)
|
|
33
33
|
* `--scheduled-at <ISO>` and `--auto`.
|
|
34
34
|
*
|
|
35
|
-
* `--scheduled-at` is appended for `
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* otherwise launchable command for no benefit.
|
|
35
|
+
* `--scheduled-at` is appended for `epic-tick` (BAPI-418), whose parser accepts
|
|
36
|
+
* it as a first-class argument. Every other command rejects unrecognized flags
|
|
37
|
+
* and halts (e.g. `start-tickets` stops on any unsupported flag), and the shared
|
|
38
|
+
* late-fire gate already embeds the scheduled time — so injecting `--scheduled-at`
|
|
39
|
+
* into their argv would break an otherwise launchable command for no benefit.
|
|
41
40
|
*
|
|
42
41
|
* `--auto` is appended when auto-approve is set AND the command supports it (its
|
|
43
|
-
* schema declares a boolean `--auto` flag, or it is `
|
|
42
|
+
* schema declares a boolean `--auto` flag, or it is `epic-tick`).
|
|
44
43
|
* It is never duplicated if already present in `input.args`.
|
|
45
44
|
*
|
|
46
45
|
* This is the SINGLE source of the delegated argv: both the rendered target
|
|
@@ -54,12 +53,10 @@ function buildAugmentedArgs(input) {
|
|
|
54
53
|
// epic-tick already accepts --scheduled-at (parseEpicTickArgs, cli.ts) so it
|
|
55
54
|
// receives the scheduled time as a structured arg for the late-fire decision,
|
|
56
55
|
// not just via the embedded gate text.
|
|
57
|
-
if (input.commandName === "
|
|
56
|
+
if (input.commandName === "epic-tick") {
|
|
58
57
|
args.push("--scheduled-at", input.runAtIso);
|
|
59
58
|
}
|
|
60
|
-
const supportsAuto = schemaSupportsAutoFlag(input.schema) ||
|
|
61
|
-
input.commandName === "full-automation" ||
|
|
62
|
-
input.commandName === "epic-tick";
|
|
59
|
+
const supportsAuto = schemaSupportsAutoFlag(input.schema) || input.commandName === "epic-tick";
|
|
63
60
|
const alreadyHasAuto = input.args.includes("--auto");
|
|
64
61
|
if (input.autoApprove && supportsAuto && !alreadyHasAuto) {
|
|
65
62
|
args.push("--auto");
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marker-scoped, opt-in cross-platform agent notes writer (BAPI-1207).
|
|
3
|
+
*
|
|
4
|
+
* Creates or refreshes a Bridge-owned region inside a consumer project's
|
|
5
|
+
* `AGENTS.md` (shared by Cursor, Copilot VS Code, Codex, and Claude Code) and,
|
|
6
|
+
* for Claude Code specifically, a pointer region inside `CLAUDE.md` — so a
|
|
7
|
+
* Claude-only selection never leaves a dangling `@AGENTS.md` reference. Every
|
|
8
|
+
* other byte in either file — content a person wrote by hand outside the
|
|
9
|
+
* marker pair — is preserved exactly.
|
|
10
|
+
*
|
|
11
|
+
* This module performs I/O only through the injected `readFile`/`writeFile`/
|
|
12
|
+
* `mkdir` seams, mirroring the rest of the install-flow dependency-injection
|
|
13
|
+
* convention (see `InstallBridgeDeps` in `install-bridge.ts`), and does no
|
|
14
|
+
* platform detection, credential handling, `.gitignore` mutation, or scaffold
|
|
15
|
+
* bookkeeping of its own — those stay the caller's responsibility.
|
|
16
|
+
*/
|
|
17
|
+
import path from "path";
|
|
18
|
+
/** The runtime marker pair this module owns inside a target notes file. */
|
|
19
|
+
export const BRIDGE_MCP_GUIDANCE_BEGIN_MARKER = "<!-- BEGIN BRIDGE MCP GUIDANCE -->";
|
|
20
|
+
export const BRIDGE_MCP_GUIDANCE_END_MARKER = "<!-- END BRIDGE MCP GUIDANCE -->";
|
|
21
|
+
/** Platforms whose shared notes file is AGENTS.md. Claude Code also gets CLAUDE.md. */
|
|
22
|
+
const AGENTS_MD_PLATFORMS = new Set([
|
|
23
|
+
"cursor",
|
|
24
|
+
"copilot-vscode",
|
|
25
|
+
"codex",
|
|
26
|
+
"claude-code",
|
|
27
|
+
]);
|
|
28
|
+
/**
|
|
29
|
+
* Pure projection from a selected-platform set to the physical notes files
|
|
30
|
+
* that selection implies. Never touches the filesystem or re-detects
|
|
31
|
+
* platforms — the caller supplies the already-selected set.
|
|
32
|
+
*/
|
|
33
|
+
export function resolveAgentNotesTargets(selectedPlatforms) {
|
|
34
|
+
const targets = new Set();
|
|
35
|
+
const unsupported = new Set();
|
|
36
|
+
for (const platform of selectedPlatforms) {
|
|
37
|
+
if (platform === "windsurf") {
|
|
38
|
+
unsupported.add(platform);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (AGENTS_MD_PLATFORMS.has(platform)) {
|
|
42
|
+
targets.add("AGENTS.md");
|
|
43
|
+
}
|
|
44
|
+
// Claude Code additionally gets a CLAUDE.md pointer — never a substitute
|
|
45
|
+
// for AGENTS.md, since @AGENTS.md would otherwise dangle.
|
|
46
|
+
if (platform === "claude-code") {
|
|
47
|
+
targets.add("CLAUDE.md");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const ordered = [];
|
|
51
|
+
if (targets.has("AGENTS.md"))
|
|
52
|
+
ordered.push("AGENTS.md");
|
|
53
|
+
if (targets.has("CLAUDE.md"))
|
|
54
|
+
ordered.push("CLAUDE.md");
|
|
55
|
+
return { targets: ordered, unsupportedPlatforms: [...unsupported] };
|
|
56
|
+
}
|
|
57
|
+
/** The one-line pointer note CLAUDE.md's owned region carries (BAPI-1207). */
|
|
58
|
+
const CLAUDE_NOTES_POINTER_NOTE = "Bridge MCP usage guidance is maintained in AGENTS.md — see the section above.";
|
|
59
|
+
function buildClaudeOwnedBody() {
|
|
60
|
+
return `@AGENTS.md\n\n${CLAUDE_NOTES_POINTER_NOTE}`;
|
|
61
|
+
}
|
|
62
|
+
function countOccurrences(text, marker) {
|
|
63
|
+
return text.split(marker).length - 1;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Locate the existing owned region in *text*, or classify why it cannot be
|
|
67
|
+
* located safely. A malformed topology (a missing half, a duplicate, reversed
|
|
68
|
+
* order, or a marker not on its own line) is reported rather than repaired —
|
|
69
|
+
* this module never appends a second region next to one it cannot parse.
|
|
70
|
+
*/
|
|
71
|
+
function scanMarkers(text) {
|
|
72
|
+
const beginCount = countOccurrences(text, BRIDGE_MCP_GUIDANCE_BEGIN_MARKER);
|
|
73
|
+
const endCount = countOccurrences(text, BRIDGE_MCP_GUIDANCE_END_MARKER);
|
|
74
|
+
if (beginCount === 0 && endCount === 0)
|
|
75
|
+
return { kind: "absent" };
|
|
76
|
+
if (beginCount === 0 || endCount === 0) {
|
|
77
|
+
return { kind: "malformed", reason: "missing half of the marker pair" };
|
|
78
|
+
}
|
|
79
|
+
if (beginCount > 1)
|
|
80
|
+
return { kind: "malformed", reason: "duplicate BEGIN marker" };
|
|
81
|
+
if (endCount > 1)
|
|
82
|
+
return { kind: "malformed", reason: "duplicate END marker" };
|
|
83
|
+
const beginIndex = text.indexOf(BRIDGE_MCP_GUIDANCE_BEGIN_MARKER);
|
|
84
|
+
const endIndex = text.indexOf(BRIDGE_MCP_GUIDANCE_END_MARKER);
|
|
85
|
+
if (endIndex < beginIndex)
|
|
86
|
+
return { kind: "malformed", reason: "markers are reversed" };
|
|
87
|
+
const afterBegin = beginIndex + BRIDGE_MCP_GUIDANCE_BEGIN_MARKER.length;
|
|
88
|
+
if (text[afterBegin] !== "\n") {
|
|
89
|
+
return { kind: "malformed", reason: "BEGIN marker is not on its own line" };
|
|
90
|
+
}
|
|
91
|
+
const contentStart = afterBegin + 1;
|
|
92
|
+
const lineStart = text.lastIndexOf("\n", endIndex - 1) + 1;
|
|
93
|
+
if (text.slice(lineStart, endIndex).trim().length > 0) {
|
|
94
|
+
return { kind: "malformed", reason: "END marker is not on its own line" };
|
|
95
|
+
}
|
|
96
|
+
return { kind: "present", contentStart, contentEnd: endIndex };
|
|
97
|
+
}
|
|
98
|
+
/** Replace only the bytes between valid existing markers; preserve everything else. */
|
|
99
|
+
function replaceRegion(text, contentStart, contentEnd, ownedBody) {
|
|
100
|
+
const normalized = ownedBody.trim() + "\n";
|
|
101
|
+
return text.slice(0, contentStart) + normalized + text.slice(contentEnd);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Append one fresh owned region at EOF, using the minimal separator needed
|
|
105
|
+
* for a clean markdown boundary. The existing prefix is never normalized —
|
|
106
|
+
* only the amount of new whitespace inserted before the region varies.
|
|
107
|
+
*/
|
|
108
|
+
function appendRegion(existingText, ownedBody) {
|
|
109
|
+
const region = `${BRIDGE_MCP_GUIDANCE_BEGIN_MARKER}\n${ownedBody.trim()}\n${BRIDGE_MCP_GUIDANCE_END_MARKER}\n`;
|
|
110
|
+
if (existingText.length === 0)
|
|
111
|
+
return region;
|
|
112
|
+
if (existingText.endsWith("\n\n"))
|
|
113
|
+
return existingText + region;
|
|
114
|
+
if (existingText.endsWith("\n"))
|
|
115
|
+
return existingText + "\n" + region;
|
|
116
|
+
return existingText + "\n\n" + region;
|
|
117
|
+
}
|
|
118
|
+
function isEnoent(err) {
|
|
119
|
+
return (typeof err === "object" &&
|
|
120
|
+
err !== null &&
|
|
121
|
+
"code" in err &&
|
|
122
|
+
err.code === "ENOENT");
|
|
123
|
+
}
|
|
124
|
+
async function writeOneTarget(target, options) {
|
|
125
|
+
const filePath = path.join(options.cwd, target);
|
|
126
|
+
let existing;
|
|
127
|
+
try {
|
|
128
|
+
existing = await options.readFile(filePath);
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
if (isEnoent(err)) {
|
|
132
|
+
existing = "";
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
return { target, status: "failed", reason: "could not read the existing file" };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const ownedBody = target === "AGENTS.md" ? options.guidance : buildClaudeOwnedBody();
|
|
139
|
+
const scan = scanMarkers(existing);
|
|
140
|
+
let merged;
|
|
141
|
+
if (scan.kind === "malformed") {
|
|
142
|
+
return {
|
|
143
|
+
target,
|
|
144
|
+
status: "failed",
|
|
145
|
+
reason: `existing marker region is malformed (${scan.reason})`,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
else if (scan.kind === "present") {
|
|
149
|
+
merged = replaceRegion(existing, scan.contentStart, scan.contentEnd, ownedBody);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
merged = appendRegion(existing, ownedBody);
|
|
153
|
+
}
|
|
154
|
+
if (merged === existing) {
|
|
155
|
+
return { target, status: "skipped", reason: "content already up to date" };
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
await options.mkdir(path.dirname(filePath), { recursive: true });
|
|
159
|
+
await options.writeFile(filePath, merged, { encoding: "utf-8" });
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return { target, status: "failed", reason: "could not write the file" };
|
|
163
|
+
}
|
|
164
|
+
return { target, status: "written" };
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Create or refresh the Bridge-owned notes region in every target the
|
|
168
|
+
* selected platforms resolve to. Each target is handled independently — a
|
|
169
|
+
* failure on one never rolls back or blocks a write already made to another.
|
|
170
|
+
*/
|
|
171
|
+
export async function writeAgentNotes(options) {
|
|
172
|
+
const { targets, unsupportedPlatforms } = resolveAgentNotesTargets(options.selectedPlatforms);
|
|
173
|
+
const files = [];
|
|
174
|
+
for (const target of targets) {
|
|
175
|
+
files.push(await writeOneTarget(target, options));
|
|
176
|
+
}
|
|
177
|
+
return { files, unsupportedPlatforms };
|
|
178
|
+
}
|
package/build/agent-registry.js
CHANGED
|
@@ -44,8 +44,11 @@ export const AGENT_REGISTRY = {
|
|
|
44
44
|
supportsModelOverride: true,
|
|
45
45
|
modelFlag: "--model",
|
|
46
46
|
// Claude family aliases float to the latest release and never drift, so they
|
|
47
|
-
// can be validated against a static allowlist.
|
|
48
|
-
|
|
47
|
+
// can be validated against a static allowlist. The `cheap` tier deliberately
|
|
48
|
+
// maps to `sonnet` (not `haiku`): even the lowest-difficulty tickets route to
|
|
49
|
+
// sonnet. `haiku` stays in the allowlist so a per-repo
|
|
50
|
+
// `difficulty_model_tier_overrides` may still opt back into it.
|
|
51
|
+
tierModels: { cheap: "sonnet", basic: "sonnet", premium: "opus" },
|
|
49
52
|
staticModelAliasAllowlist: ["haiku", "sonnet", "opus"],
|
|
50
53
|
// BAPI-781: the reference executor adapter. `managedCarriers` is EMPTY and
|
|
51
54
|
// `passthroughs` names only the operator's own OAuth variable — Bridge
|