@bridge_gpt/mcp-server 0.2.54 → 0.2.56
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 +45 -59
- package/build/agent-capabilities/types.js +4 -0
- package/build/agent-guidance.generated.js +3 -0
- package/build/agent-launchers/claude-executor-adapter.js +3 -0
- package/build/agent-notes.js +178 -0
- package/build/agent-registry.js +25 -5
- package/build/agent-utils.js +58 -0
- package/build/agents.generated.js +1 -1
- package/build/codex-launch-scope.js +49 -0
- package/build/codex-skill-adapter.js +58 -0
- package/build/command-host.js +9 -0
- package/build/command-provisioning.js +35 -4
- package/build/commands.generated.js +9 -8
- package/build/conductor/bridge-api-client.js +199 -6
- 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 +1 -1
- 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 +37 -6
- 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/store.js +2 -2
- package/build/conductor/supervisor-runtime.js +1 -1
- 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 +81 -18
- package/build/drive-epic.js +541 -115
- 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/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 +274 -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 +617 -168
- package/build/init.js +74 -9
- package/build/install-bridge-conductor.js +5 -5
- package/build/install-bridge.js +425 -79
- package/build/mcp-host-config.js +22 -60
- package/build/mcp-host-entry-adapter.js +18 -0
- package/build/mcp-host-targets.js +19 -32
- package/build/mcp-provisioning.js +1 -1
- package/build/mcp-registration-doctor.js +1 -1
- package/build/merge-pull-request.js +1 -1
- package/build/pipelines.generated.js +7 -7
- package/build/plan-epic-conductor-eligibility.js +1 -1
- package/build/plane/cli.js +36 -5
- package/build/plane/preflight.js +128 -12
- package/build/plane/shutdown.js +4 -4
- package/build/readiness-check.js +3 -3
- package/build/readme.generated.js +1 -1
- package/build/review-tickets.js +50 -35
- package/build/run-unit-tests-launcher.js +1 -1
- package/build/setup-epic.js +69 -31
- package/build/start-tickets-conductor.js +8 -7
- package/build/start-tickets.js +266 -48
- package/build/version.generated.js +3 -3
- package/build/worker-guard-hook-bin.js +1 -1
- package/docs/CONDUCTOR.md +8 -6
- package/package.json +5 -3
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.56", "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.56", "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.54", "serve"],
|
|
425
|
-
"tools": ["*"],
|
|
398
|
+
"args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.56", "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.56", "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.56", "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
|
|
|
@@ -1003,9 +985,9 @@ npx -y @bridge_gpt/mcp-server start-tickets [flags] KEY [KEY ...]
|
|
|
1003
985
|
| Flag | Default | Meaning |
|
|
1004
986
|
|---|---|---|
|
|
1005
987
|
| `--agent claude\|cursor-agent` | `claude` | Agent command to launch in each worktree |
|
|
1006
|
-
| `--workflow implement\|review-and-implement` | `implement` | Slash command each spawned worktree runs. `
|
|
988
|
+
| `--workflow implement\|review-and-implement` | `implement` | Slash command each spawned worktree runs. `review-and-implement` reviews the ticket, then hands approval to a fresh implementation session in the same worktree. `--auto` applies to both phases. |
|
|
1007
989
|
| `--rounds 1\|2` | unset | Review round count forwarded to the review phase. Review-only — valid only with `--workflow review-and-implement`. |
|
|
1008
|
-
| `--tier cheap\|basic\|premium` | unset (difficulty routing) | Coarse model-routing override. Bypasses **only** the per-ticket difficulty/tier lookup (`GET /jira/tickets/{KEY}/model-tier`) and applies this one tier to every ticket;
|
|
990
|
+
| `--tier cheap\|basic\|premium` | unset (difficulty routing) | Coarse model-routing override. Bypasses **only** the per-ticket difficulty/tier lookup (`GET /jira/tickets/{KEY}/model-tier`) and applies this one tier to every ticket; Claude/Cursor use their registry aliases and repository overrides, while Codex uses the authenticated Bridge catalog. It is **not** a raw `--model` alias and never carries an API key or credential. A malformed value fails open to premium routing when its alias is available. Used by the `/review-and-implement` handoff to reuse the review-time tier. |
|
|
1009
991
|
| `--terminal terminal\|iterm` | auto-detect via `$TERM_PROGRAM` | Override the macOS terminal app (honored on macOS only) |
|
|
1010
992
|
| `--dry-run` | off | Print intended actions; create no worktrees, open no tabs (any OS) |
|
|
1011
993
|
| `--branch KEY=BRANCH` | `feature/<KEY>` | Use a custom branch for that ticket (repeatable) |
|
|
@@ -1015,15 +997,17 @@ npx -y @bridge_gpt/mcp-server start-tickets [flags] KEY [KEY ...]
|
|
|
1015
997
|
| `--conductor` | off | Opt into the Conductor system (per-worker `BAPI_CONDUCTOR_*` env + Claude hook injection, lifecycle ledger events, and a supervisor peer tab). **Default off** — a plain run spawns `cd <worktree> && <agent> '/implement-ticket <KEY>'`. |
|
|
1016
998
|
| `-h`, `--help` | — | Show usage |
|
|
1017
999
|
|
|
1018
|
-
Each `KEY` must match `[A-Z]+-[0-9]+` (e.g., `BAPI-248`). The CLI creates/switches each worktree up front (throttled by `--max-parallel`), then opens one tab/session per successful worktree running the selected agent
|
|
1000
|
+
Each `KEY` must match `[A-Z]+-[0-9]+` (e.g., `BAPI-248`). The CLI creates/switches each worktree up front (throttled by `--max-parallel`), then opens one tab/session per successful worktree running the selected agent. Claude is the default. Cursor with `--auto` runs headlessly after a bounded authentication/readiness check; manual Cursor runs remain interactive for human review gates. To launch Cursor Agent instead of Claude Code:
|
|
1019
1001
|
|
|
1020
1002
|
```
|
|
1021
1003
|
npx -y @bridge_gpt/mcp-server start-tickets --agent cursor-agent BAPI-248
|
|
1022
1004
|
```
|
|
1023
1005
|
|
|
1024
|
-
**Difficulty-based model routing.** Before launching each agent, the CLI selects an implementation **model tier** from the ticket's `difficulty` (1-2 → cheap, 3-6 → basic, 7-10 → premium) and
|
|
1006
|
+
**Difficulty-based model routing.** Before launching each agent, the CLI selects an implementation **model tier** from the ticket's `difficulty` (1-2 → cheap, 3-6 → basic, 7-10 → premium) and may inject `--model` at the spawn boundary. The Python backend returns only the coarse tier (`GET /jira/tickets/{KEY}/model-tier`, computing + caching difficulty on demand). Claude and Cursor map that tier through their agent registry aliases; Cursor validates against `cursor-agent --list-models`. Routing is gated per repo by `difficulty_model_routing_enabled` (default **ON**). Claude/Cursor may use `difficulty_model_tier_overrides` (tier → alias) and retain their premium fallback behavior on an unknown tier or transient failure. When an alias cannot be validated, the CLI omits `--model` and launches the agent default. `--dry-run` resolves routing read-only to preview the command without creating worktrees or opening tabs.
|
|
1007
|
+
|
|
1008
|
+
For Codex, `GET /jira/codex-model-catalog?repo_name=...` is the sole tier-to-model authority. Bridge derives its three bare CLI IDs and SHA-256 mapping revision at request time from `MODEL_REGISTRY`; the launcher fetches and validates that catalog once per invocation. Repository `difficulty_model_tier_overrides` do not apply to Codex. A failed access, config, tier, catalog, revision, or alias check omits `--model` and launches the configured Codex default. The catalog expresses **Bridge provider policy only**: it cannot confirm that the local Codex login or subscription can use a model. The CLI has no supported non-interactive entitlement probe, so routing emits that limitation as a diagnostic and never uses Bridge's OpenAI API key as proof of local access.
|
|
1025
1009
|
|
|
1026
|
-
**Coarse `--tier` override.** Passing `--tier cheap|basic|premium` bypasses
|
|
1010
|
+
**Coarse `--tier` override.** Passing `--tier cheap|basic|premium` bypasses only the per-ticket difficulty lookup and applies that tier to every ticket. Claude/Cursor use the same alias resolution as normal routing; Codex uses the fetched catalog. It is never a raw model alias, and no API key or credential belongs in the spawned command. A malformed tier requests the premium fallback when its alias is available; otherwise the agent default launches. `/review-and-implement` uses this flag to hand its review-time tier snapshot to the fresh implementation session.
|
|
1027
1011
|
|
|
1028
1012
|
**Conductor observability (opt-in via `--conductor`, BAPI-394).** Conductor is **off by default**. With `--conductor`, a run mints a conductor `run_id`, emits events into the local ledger (`~/.config/bridge/events.db`), opens a supervisor peer tab, and (for Claude Code) injects a secret-free lifecycle hook into each worktree; it also sets `BRIDGE_MCP_PROFILE=conductor` so workers get the conductor MCP tools. Observability is best-effort — a conductor failure never blocks a spawn, and `--dry-run` performs no conductor side effects. (Epic-tick dispatch always enables conductor internally.) See **[CONDUCTOR.md](./docs/CONDUCTOR.md)** for the full observability, git-hook, done-gate, and auto-merge reference.
|
|
1029
1013
|
|
|
@@ -1176,7 +1160,7 @@ default, or, when it declares none, as an explicit recorded `no_ci_gate` mode.
|
|
|
1176
1160
|
> refusal rather than a silent winner.
|
|
1177
1161
|
|
|
1178
1162
|
An unattended run has two one-time **repository** prerequisites — consent
|
|
1179
|
-
(`
|
|
1163
|
+
(`unattended_epic_implementer_allowed`) and a verified notify webhook default — plus
|
|
1180
1164
|
confirmed default-branch review/CI workflows. Each is refused by name **before any
|
|
1181
1165
|
run row is created** (`target_not_allowed`, `webhook_unverified`,
|
|
1182
1166
|
`repository_readiness_unconfirmed`), and `drive-epic` readiness and `doctor` both
|
|
@@ -1190,7 +1174,7 @@ prerequisite.
|
|
|
1190
1174
|
> half alone would 422 every unattended run at `POST /jira/epic-runs/runs`.
|
|
1191
1175
|
> Deploying only the server half is safe and inert: it narrows two refusals and adds
|
|
1192
1176
|
> a first-approval stamp, and **rewrites no existing run**. No database migration and
|
|
1193
|
-
> no new environment variable is introduced — `config_projects.
|
|
1177
|
+
> no new environment variable is introduced — `config_projects.unattended_epic_implementer_allowed`
|
|
1194
1178
|
> and `epic_supervisor_setup.done_gate_config` already exist and are read as-is.
|
|
1195
1179
|
|
|
1196
1180
|
Once the plan is approved, the **server-side reconciler** picks the run up within ~30s. To execute claimed jobs on your machine, run `executor`:
|
|
@@ -1199,15 +1183,17 @@ Once the plan is approved, the **server-side reconciler** picks the run up withi
|
|
|
1199
1183
|
npx -y @bridge_gpt/mcp-server executor --repo <name>
|
|
1200
1184
|
```
|
|
1201
1185
|
|
|
1202
|
-
### `
|
|
1186
|
+
### `implement-epic`
|
|
1203
1187
|
|
|
1204
1188
|
The deterministic half of the `/conduct-epic` loop: it owns the epic branch, a
|
|
1205
1189
|
versioned local checkpoint, a per-epic lock, and the read-only probes the loop
|
|
1206
1190
|
decides on. It never creates or mutates an `epic_run` — that is the server-side
|
|
1207
1191
|
v2 reconciler's job, and `init` refuses to start when one is already active.
|
|
1192
|
+
This is EPIC-LEVEL orchestration, distinct from the ticket-level
|
|
1193
|
+
`implement-ticket` command.
|
|
1208
1194
|
|
|
1209
1195
|
```
|
|
1210
|
-
npx -y @bridge_gpt/mcp-server
|
|
1196
|
+
npx -y @bridge_gpt/mcp-server implement-epic <verb> [flags]
|
|
1211
1197
|
```
|
|
1212
1198
|
|
|
1213
1199
|
**Verbs**
|
|
@@ -1273,9 +1259,9 @@ appear in a command argument, in stdout/stderr, or in a journal line.
|
|
|
1273
1259
|
|
|
1274
1260
|
### Conductor (epic & multi-agent orchestration)
|
|
1275
1261
|
|
|
1276
|
-
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`, `
|
|
1262
|
+
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.)
|
|
1277
1263
|
|
|
1278
|
-
> The v1 `
|
|
1264
|
+
> 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.
|
|
1279
1265
|
|
|
1280
1266
|
## Custom Pipelines
|
|
1281
1267
|
|
|
@@ -5,6 +5,10 @@ export const AGENT_AUTH = {
|
|
|
5
5
|
note: "Claude Code authenticates via keychain/OAuth — cannot be verified from the environment.",
|
|
6
6
|
},
|
|
7
7
|
"cursor-agent": { kind: "env", varName: "CURSOR_API_KEY" },
|
|
8
|
+
codex: {
|
|
9
|
+
kind: "interactive",
|
|
10
|
+
note: "Codex authenticates via login/OAuth — cannot be verified from the environment.",
|
|
11
|
+
},
|
|
8
12
|
};
|
|
9
13
|
/** Default hard timeout per headless probe run (ms). The cursor `-p` hang bug is version-sensitive. */
|
|
10
14
|
export const DEFAULT_PROBE_TIMEOUT_MS = 90_000;
|
|
@@ -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),
|
|
@@ -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
|
@@ -26,7 +26,7 @@ export function isModelTier(value) {
|
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
28
|
* The registry: the ONLY place mapping an agent name to its command/spec. Seeded
|
|
29
|
-
* with
|
|
29
|
+
* with `claude` (default), `cursor-agent`, and `codex`. `as const satisfies` keeps
|
|
30
30
|
* the literal keys (so `AgentName` is a precise union) while type-checking each
|
|
31
31
|
* value against `AgentSpec`.
|
|
32
32
|
*/
|
|
@@ -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
|
|
@@ -105,6 +108,20 @@ export const AGENT_REGISTRY = {
|
|
|
105
108
|
premium: "claude-opus-4-8-thinking-high",
|
|
106
109
|
},
|
|
107
110
|
},
|
|
111
|
+
codex: {
|
|
112
|
+
name: "codex",
|
|
113
|
+
command: "codex",
|
|
114
|
+
promptArgStyle: "positional",
|
|
115
|
+
installHint: {
|
|
116
|
+
darwin: "npm install -g @openai/codex",
|
|
117
|
+
linux: "npm install -g @openai/codex",
|
|
118
|
+
win32: "npm install -g @openai/codex",
|
|
119
|
+
},
|
|
120
|
+
authNote: "Codex authenticates interactively on first run — follow its login prompt if asked.",
|
|
121
|
+
// The launch boundary validates a fresh Bridge catalog before injection.
|
|
122
|
+
supportsModelOverride: true,
|
|
123
|
+
modelFlag: "--model",
|
|
124
|
+
},
|
|
108
125
|
};
|
|
109
126
|
/** The default agent used when `--agent` is omitted. */
|
|
110
127
|
export const DEFAULT_AGENT_NAME = "claude";
|
|
@@ -127,7 +144,7 @@ export function resolveAgentSpec(name) {
|
|
|
127
144
|
return null;
|
|
128
145
|
return AGENT_REGISTRY[resolved];
|
|
129
146
|
}
|
|
130
|
-
/** Comma-delimited
|
|
147
|
+
/** Comma-delimited registry names for CLI validation errors (`claude, cursor-agent, codex`). */
|
|
131
148
|
export function formatValidAgentNames() {
|
|
132
149
|
return listAgentNames().join(", ");
|
|
133
150
|
}
|
|
@@ -151,10 +168,13 @@ export function resolveModelAlias(agent, tier, overrides) {
|
|
|
151
168
|
return null;
|
|
152
169
|
if (!tier)
|
|
153
170
|
return null;
|
|
171
|
+
// Codex has no static or repository-override model authority.
|
|
172
|
+
if (agent.name === "codex")
|
|
173
|
+
return null;
|
|
154
174
|
const override = overrides?.[tier];
|
|
155
175
|
const candidate = typeof override === "string" && override.trim().length > 0
|
|
156
176
|
? override.trim()
|
|
157
|
-
: agent.tierModels[tier];
|
|
177
|
+
: agent.tierModels?.[tier];
|
|
158
178
|
if (typeof candidate !== "string" || !isValidModelAlias(candidate))
|
|
159
179
|
return null;
|
|
160
180
|
if (agent.staticModelAliasAllowlist && !agent.staticModelAliasAllowlist.includes(candidate)) {
|
package/build/agent-utils.js
CHANGED
|
@@ -108,3 +108,61 @@ export function translateAgentToCopilot(frontmatter, body) {
|
|
|
108
108
|
const yaml = lines.join("\n");
|
|
109
109
|
return `---\n${yaml}\n---\n${body}`;
|
|
110
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Return the first meaningful line as a short, deterministic Copilot summary.
|
|
113
|
+
* Canonical command files deliberately have no required frontmatter, so their
|
|
114
|
+
* opening prose is the only source we can use without maintaining a second
|
|
115
|
+
* command catalog.
|
|
116
|
+
*/
|
|
117
|
+
function commandDescription(source, commandName) {
|
|
118
|
+
const line = source
|
|
119
|
+
.split(/\r?\n/)
|
|
120
|
+
.map((candidate) => candidate.trim())
|
|
121
|
+
.find((candidate) => candidate.length > 0 && candidate !== "$ARGUMENTS" && !candidate.startsWith("#"));
|
|
122
|
+
return line ?? `Run the Bridge ${commandName} workflow.`;
|
|
123
|
+
}
|
|
124
|
+
function commandBodyForPrompt(source) {
|
|
125
|
+
return source.replaceAll("$ARGUMENTS", "${input:task}");
|
|
126
|
+
}
|
|
127
|
+
function commandBodyForSkill(source) {
|
|
128
|
+
return source.replaceAll("$ARGUMENTS", "the text supplied after this slash command");
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Translate one packaged command into the two Copilot artifact formats Bridge
|
|
132
|
+
* supports today. Prompt files are for VS Code's Local agent; project skills
|
|
133
|
+
* are the Agent Host replacement. Both remain derived from the same canonical
|
|
134
|
+
* command body, never from a hand-maintained Copilot copy.
|
|
135
|
+
*/
|
|
136
|
+
export function translateCommandToCopilot(filename, source) {
|
|
137
|
+
const commandName = filename.replace(/\.md$/, "");
|
|
138
|
+
const description = commandDescription(source, commandName);
|
|
139
|
+
const prompt = [
|
|
140
|
+
"---",
|
|
141
|
+
`description: ${quoteYamlValue(description)}`,
|
|
142
|
+
"argument-hint: \"[task or ticket key]\"",
|
|
143
|
+
"tools:",
|
|
144
|
+
" - bridge/*",
|
|
145
|
+
"---",
|
|
146
|
+
"",
|
|
147
|
+
`# Bridge ${commandName} workflow`,
|
|
148
|
+
"",
|
|
149
|
+
"The user input is available as `${input:task}`. Follow the canonical workflow below.",
|
|
150
|
+
"",
|
|
151
|
+
commandBodyForPrompt(source),
|
|
152
|
+
].join("\n");
|
|
153
|
+
const skill = [
|
|
154
|
+
"---",
|
|
155
|
+
`name: ${commandName}`,
|
|
156
|
+
`description: ${quoteYamlValue(description)}`,
|
|
157
|
+
"argument-hint: \"[task or ticket key]\"",
|
|
158
|
+
"disable-model-invocation: true",
|
|
159
|
+
"---",
|
|
160
|
+
"",
|
|
161
|
+
`# Bridge ${commandName} workflow`,
|
|
162
|
+
"",
|
|
163
|
+
"Use the text supplied after this slash command as the workflow input. Follow the canonical workflow below.",
|
|
164
|
+
"",
|
|
165
|
+
commandBodyForSkill(source),
|
|
166
|
+
].join("\n");
|
|
167
|
+
return { prompt, skill };
|
|
168
|
+
}
|