@bridge_gpt/mcp-server 0.2.55 → 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 CHANGED
@@ -351,7 +351,7 @@ later boot.
351
351
  "mcpServers": {
352
352
  "bridge": {
353
353
  "command": "npx",
354
- "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.55", "serve"],
354
+ "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.56", "serve"],
355
355
  "env": {
356
356
  "BAPI_BASE_URL": "https://bridgegpt-api.com",
357
357
  "BAPI_REPO_NAME": "your-repo",
@@ -373,7 +373,7 @@ later boot.
373
373
  "bridge": {
374
374
  "type": "stdio",
375
375
  "command": "npx",
376
- "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.55", "serve"],
376
+ "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.56", "serve"],
377
377
  "env": {
378
378
  "BAPI_BASE_URL": "https://bridgegpt-api.com",
379
379
  "BAPI_REPO_NAME": "your-repo",
@@ -395,7 +395,7 @@ later boot.
395
395
  "bridge": {
396
396
  "type": "stdio",
397
397
  "command": "npx",
398
- "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.55", "serve"],
398
+ "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.56", "serve"],
399
399
  "env": {
400
400
  "BAPI_BASE_URL": "https://bridgegpt-api.com",
401
401
  "BAPI_REPO_NAME": "your-repo",
@@ -418,7 +418,7 @@ Windsurf only supports global MCP configuration.
418
418
  "mcpServers": {
419
419
  "bridge": {
420
420
  "command": "npx",
421
- "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.55", "serve"],
421
+ "args": ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.56", "serve"],
422
422
  "env": {
423
423
  "BAPI_BASE_URL": "https://bridgegpt-api.com",
424
424
  "BAPI_REPO_NAME": "your-repo",
@@ -437,7 +437,7 @@ Windsurf only supports global MCP configuration.
437
437
  ```toml
438
438
  [mcp_servers.bridge]
439
439
  command = "npx"
440
- args = ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.55", "serve"]
440
+ args = ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.56", "serve"]
441
441
 
442
442
  [mcp_servers.bridge.env]
443
443
  BAPI_BASE_URL = "https://bridgegpt-api.com"
@@ -985,9 +985,9 @@ npx -y @bridge_gpt/mcp-server start-tickets [flags] KEY [KEY ...]
985
985
  | Flag | Default | Meaning |
986
986
  |---|---|---|
987
987
  | `--agent claude\|cursor-agent` | `claude` | Agent command to launch in each worktree |
988
- | `--workflow implement\|review-and-implement` | `implement` | Slash command each spawned worktree runs. `implement` is byte-identical to today's `/implement-ticket <KEY> [--auto]`. `review-and-implement` spawns `/review-and-implement <KEY> [--auto] [--rounds=<n>]`, which runs `/review-ticket` then, after a per-ticket halt gate, `/implement-ticket` in the same session. `--auto` applies to the selected workflow as a whole. |
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. |
989
989
  | `--rounds 1\|2` | unset | Review round count forwarded to the review phase. Review-only — valid only with `--workflow review-and-implement`. |
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; the tier is still mapped to a model through the centralized agent registry and any configured `difficulty_model_tier_overrides`, then validated. It is **not** a raw `--model` alias and never carries an API key or credential. A malformed value fails open to premium routing. Used by the `/review-and-implement` handoff to reuse the review-time tier. |
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. |
991
991
  | `--terminal terminal\|iterm` | auto-detect via `$TERM_PROGRAM` | Override the macOS terminal app (honored on macOS only) |
992
992
  | `--dry-run` | off | Print intended actions; create no worktrees, open no tabs (any OS) |
993
993
  | `--branch KEY=BRANCH` | `feature/<KEY>` | Use a custom branch for that ticket (repeatable) |
@@ -997,15 +997,17 @@ npx -y @bridge_gpt/mcp-server start-tickets [flags] KEY [KEY ...]
997
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>'`. |
998
998
  | `-h`, `--help` | — | Show usage |
999
999
 
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's `'/implement-ticket <KEY>'` — `claude '/implement-ticket <KEY>'` by default, or `cursor-agent '/implement-ticket <KEY>'` with `--agent cursor-agent`. The `/implement-ticket <KEY>` prompt is unchanged for both agents. To launch Cursor Agent instead of Claude Code:
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:
1001
1001
 
1002
1002
  ```
1003
1003
  npx -y @bridge_gpt/mcp-server start-tickets --agent cursor-agent BAPI-248
1004
1004
  ```
1005
1005
 
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 injects it as a `--model` flag at the spawn boundary. The Python backend returns only the coarse tier (`GET /jira/tickets/{KEY}/model-tier`, computing + caching difficulty on demand); this CLI alone maps a tier to the agent-specific alias (`claude`: `haiku`/`sonnet`/`opus`; `cursor-agent`: version-suffixed strings validated against `cursor-agent --list-models`). It is gated per repo by `difficulty_model_routing_enabled` (default **ON**) with an optional `difficulty_model_tier_overrides` JSON map (tier → alias). Routing is **fail-open**: missing credentials, an evaluation failure/timeout, a backend `fallback`, an invalid/unavailable alias, an unadvertised Cursor model, or an agent without `--model` support all default to the **premium** (Opus) model — and when even the premium alias cannot be resolved/validated for the agent, `--model` is omitted (the agent uses its default) — each surfaced as a per-ticket warning rather than failing the spawn. `--dry-run` does **not** create worktrees or open tabs, but it **does** resolve routing read-only to preview the `--model` each tab would use.
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
1007
 
1008
- **Coarse `--tier` override.** Passing `--tier cheap|basic|premium` bypasses **only** the per-ticket difficulty lookup above and applies that one tier to every ticket; the tier is still resolved to an alias through the same agent registry + `difficulty_model_tier_overrides` and validated the same way (including the live `cursor-agent --list-models` check). It is never treated as a raw `--model` alias, and no API key or credential belongs in the spawned command (the CLI resolves credentials itself via `resolveBapiCredentials`). A malformed/unrecognized `--tier` value is **fail-open**: the CLI logs one concise warning and routes every ticket on the premium (Opus) fallback rather than aborting. `/review-and-implement` uses this flag to hand its review-time tier snapshot to the fresh implementation session.
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.
1009
+
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.
1009
1011
 
1010
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.
1011
1013
 
@@ -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;
@@ -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 exactly `claude` (default) and `cursor-agent`. `as const satisfies` keeps
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
  */
@@ -108,6 +108,20 @@ export const AGENT_REGISTRY = {
108
108
  premium: "claude-opus-4-8-thinking-high",
109
109
  },
110
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
+ },
111
125
  };
112
126
  /** The default agent used when `--agent` is omitted. */
113
127
  export const DEFAULT_AGENT_NAME = "claude";
@@ -130,7 +144,7 @@ export function resolveAgentSpec(name) {
130
144
  return null;
131
145
  return AGENT_REGISTRY[resolved];
132
146
  }
133
- /** Comma-delimited valid agent names for CLI validation errors (`claude, cursor-agent`). */
147
+ /** Comma-delimited registry names for CLI validation errors (`claude, cursor-agent, codex`). */
134
148
  export function formatValidAgentNames() {
135
149
  return listAgentNames().join(", ");
136
150
  }
@@ -154,10 +168,13 @@ export function resolveModelAlias(agent, tier, overrides) {
154
168
  return null;
155
169
  if (!tier)
156
170
  return null;
171
+ // Codex has no static or repository-override model authority.
172
+ if (agent.name === "codex")
173
+ return null;
157
174
  const override = overrides?.[tier];
158
175
  const candidate = typeof override === "string" && override.trim().length > 0
159
176
  ? override.trim()
160
- : agent.tierModels[tier];
177
+ : agent.tierModels?.[tier];
161
178
  if (typeof candidate !== "string" || !isValidModelAlias(candidate))
162
179
  return null;
163
180
  if (agent.staticModelAliasAllowlist && !agent.staticModelAliasAllowlist.includes(candidate)) {
@@ -0,0 +1,49 @@
1
+ /** Per-process Codex MCP scope, derived from the same manifest and shim as worktree provisioning. */
2
+ import { readBridgeConfig } from "./bridge-config.js";
3
+ import os from "node:os";
4
+ import { codexBridgeTableNames } from "./mcp-host-config.js";
5
+ import { MCP_HOST_TARGETS, resolveHostTargetPath } from "./mcp-host-targets.js";
6
+ import { buildMcpServerEntriesForManifest, normalizeWorktreePathForRegistration, } from "./mcp-provisioning.js";
7
+ import { MCP_SERVER_NAME } from "./mcp-identity.js";
8
+ function tomlEntry(entry) {
9
+ return `{ command = ${JSON.stringify(entry.command)}, args = [${entry.args.map((arg) => JSON.stringify(arg)).join(", ")}] }`;
10
+ }
11
+ /** A missing Bridge target is a launch failure, never a fallback to user-scoped config. */
12
+ export async function resolveCodexLaunchScope(root, deps, codexConfigPath = resolveHostTargetPath(MCP_HOST_TARGETS.codex, { cwd: root, homedir: os.homedir() })) {
13
+ const normalized = normalizeWorktreePathForRegistration(root, deps);
14
+ if (!normalized.ok)
15
+ return { ok: false, error: "Codex MCP scope unavailable: invalid repository path." };
16
+ let manifest;
17
+ try {
18
+ const read = await readBridgeConfig(normalized.path, { readFile: deps.readFile });
19
+ if (!read.ok)
20
+ return { ok: false, error: "Codex MCP scope unavailable: .bridge/config is missing or invalid." };
21
+ manifest = read.manifest;
22
+ }
23
+ catch {
24
+ return { ok: false, error: "Codex MCP scope unavailable: could not read .bridge/config." };
25
+ }
26
+ const built = buildMcpServerEntriesForManifest(manifest, normalized.path, deps.mcpServerInvocation, deps.bridgeApiBaseUrl);
27
+ const bridge = built.entries[MCP_SERVER_NAME];
28
+ if (!bridge)
29
+ return { ok: false, error: "Codex MCP scope unavailable: .bridge/config has no Bridge target." };
30
+ let existingConfig = "";
31
+ try {
32
+ existingConfig = await deps.readFile(codexConfigPath);
33
+ }
34
+ catch (error) {
35
+ if (error.code !== "ENOENT") {
36
+ return { ok: false, error: "Codex MCP scope unavailable: could not inspect Codex host config." };
37
+ }
38
+ }
39
+ const registeredNames = codexBridgeTableNames(existingConfig);
40
+ if (registeredNames.length > 1) {
41
+ return { ok: false, error: "Codex MCP scope unavailable: duplicate Bridge registrations in Codex host config." };
42
+ }
43
+ const bridgeKey = registeredNames[0] ?? MCP_SERVER_NAME;
44
+ const argv = ["-C", normalized.path];
45
+ for (const [name, entry] of Object.entries(built.entries)) {
46
+ argv.push("-c", `mcp_servers.${name === MCP_SERVER_NAME ? bridgeKey : name}=${tomlEntry(entry)}`);
47
+ }
48
+ return { ok: true, argv };
49
+ }
@@ -4,8 +4,8 @@
4
4
  * Codex discovers repository-local skills from `.agents/skills/<name>/SKILL.md`.
5
5
  * Bridge command sources use a standalone `$ARGUMENTS` marker, which is a
6
6
  * Claude/Cursor command convention rather than a Codex input variable. This
7
- * adapter replaces only that marker with the documented explicit-skill input
8
- * contract while retaining every other byte of the canonical workflow.
7
+ * adapter replaces that marker with the explicit-skill input contract and
8
+ * translates references to shipped slash commands into Codex skill names.
9
9
  */
10
10
  export const CODEX_SKILLS_DIR = ".agents/skills";
11
11
  function commandStem(filename) {
@@ -19,7 +19,7 @@ export function codexSkillNameForCommand(filename) {
19
19
  return `bridge-${commandStem(filename)}`;
20
20
  }
21
21
  /** Render the one Codex-native skill artifact for a canonical command. */
22
- export function renderCodexSkill(filename, command) {
22
+ export function renderCodexSkill(filename, command, knownCommands = [commandStem(filename)]) {
23
23
  const stem = commandStem(filename);
24
24
  const skillName = codexSkillNameForCommand(filename);
25
25
  const invocation = `$${skillName}`;
@@ -28,10 +28,12 @@ export function renderCodexSkill(filename, command) {
28
28
  `Treat the text after \`${invocation}\` in the user's message as this workflow's input.`,
29
29
  "If no input follows the invocation, follow the canonical workflow's existing usage/error behavior.",
30
30
  ].join("\n");
31
+ const commandPattern = new RegExp(`(?<![A-Za-z0-9_./-])/(${knownCommands.join("|")})(?=[^A-Za-z0-9-]|$)`, "g");
31
32
  const adaptedCommand = command
32
33
  .split("\n")
33
34
  .map((line) => (line.trim() === "$ARGUMENTS" ? inputContract : line))
34
- .join("\n");
35
+ .join("\n")
36
+ .replace(commandPattern, (_match, name) => `$bridge-${name}`);
35
37
  return {
36
38
  skillName,
37
39
  relativePath: `${CODEX_SKILLS_DIR}/${skillName}/SKILL.md`,
@@ -49,7 +51,8 @@ export function renderCodexSkill(filename, command) {
49
51
  }
50
52
  /** Build the complete, deterministically ordered Codex skill bundle. */
51
53
  export function codexSkillAssets(commands) {
54
+ const names = Object.keys(commands).map(commandStem).sort((a, b) => b.length - a.length);
52
55
  return Object.entries(commands)
53
56
  .sort(([left], [right]) => left.localeCompare(right))
54
- .map(([filename, command]) => renderCodexSkill(filename, command));
57
+ .map(([filename, command]) => renderCodexSkill(filename, command, names));
55
58
  }
@@ -0,0 +1,9 @@
1
+ /** Specialize the shared front-door command for a known installation host. */
2
+ export function renderCommandForHost(filename, content, host) {
3
+ if (filename !== "review-and-start.md" || host !== "cursor")
4
+ return content;
5
+ const marker = "**Command host default: none.**";
6
+ if (!content.includes(marker))
7
+ throw new Error("review-and-start host default marker is missing");
8
+ return content.replace(marker, "**Command host default: cursor.**");
9
+ }
@@ -26,9 +26,11 @@
26
26
  */
27
27
  import path from "path";
28
28
  import { COMMANDS } from "./commands.generated.js";
29
+ import { codexSkillAssets } from "./codex-skill-adapter.js";
29
30
  import { ensureGitInfoExcluded } from "./git-ignore-utils.js";
30
31
  /** The exact exclude entry appended for the command directory (POSIX-relative). */
31
32
  const COMMAND_DIR_EXCLUDE_ENTRY = ".claude/commands/";
33
+ const CODEX_SKILLS_EXCLUDE_ENTRY = ".agents/skills/";
32
34
  /** Bounded, secret-free error surfaced when the packaged bundle is empty. */
33
35
  const EMPTY_BUNDLE_ERROR = "Command provisioning failed: the packaged command bundle is empty — reinstall or rebuild the MCP server package.";
34
36
  /**
@@ -51,7 +53,7 @@ function isEnoentError(err) {
51
53
  * for an expected filesystem/Git failure, and never leaks raw exception text,
52
54
  * command output, or file contents.
53
55
  */
54
- export async function provisionCommandsForWorktree(worktreeRoot, deps) {
56
+ export async function provisionCommandsForWorktree(worktreeRoot, deps, includeCodexSkills = false) {
55
57
  const api = pathApiForCommandProvisioningPlatform(deps.platform);
56
58
  const normalizedRoot = api.isAbsolute(worktreeRoot)
57
59
  ? api.normalize(worktreeRoot)
@@ -97,6 +99,26 @@ export async function provisionCommandsForWorktree(worktreeRoot, deps) {
97
99
  "Command provisioning failed: could not write one or more packaged command assets.";
98
100
  }
99
101
  }
102
+ // Codex launch requires the full bundle. Fill only, preserving customer assets.
103
+ if (!fillError && includeCodexSkills) {
104
+ try {
105
+ for (const asset of codexSkillAssets(COMMANDS)) {
106
+ const target = api.join(normalizedRoot, asset.relativePath);
107
+ try {
108
+ await deps.readFile(target);
109
+ }
110
+ catch (err) {
111
+ if (!isEnoentError(err))
112
+ throw err;
113
+ await deps.mkdir(api.dirname(target), { recursive: true });
114
+ await deps.writeFile(target, asset.content);
115
+ }
116
+ }
117
+ }
118
+ catch {
119
+ fillError = "Command provisioning failed: could not write one or more Codex skill assets.";
120
+ }
121
+ }
100
122
  // Phase 3 — ALWAYS attempt exclusion, even after a partial or failed fill, so
101
123
  // partially bootstrapped files are never left visible to Git. The primary fill
102
124
  // failure is preserved if both the fill and the exclusion fail.
@@ -109,10 +131,19 @@ export async function provisionCommandsForWorktree(worktreeRoot, deps) {
109
131
  runCommand: deps.runCommand,
110
132
  platform: deps.platform,
111
133
  });
134
+ if (includeCodexSkills) {
135
+ await ensureGitInfoExcluded(normalizedRoot, CODEX_SKILLS_EXCLUDE_ENTRY, {
136
+ readFile: deps.readFile,
137
+ writeFile: deps.writeFile,
138
+ mkdir: deps.mkdir,
139
+ runCommand: deps.runCommand,
140
+ platform: deps.platform,
141
+ });
142
+ }
112
143
  }
113
144
  catch {
114
145
  excludeError =
115
- "Command provisioning failed: could not add '.claude/commands/' to the worktree Git exclude file.";
146
+ "Command provisioning failed: could not add generated command assets to the worktree Git exclude file.";
116
147
  }
117
148
  if (fillError)
118
149
  return { ok: false, error: fillError };
@@ -129,7 +160,7 @@ export async function provisionCommandsForWorktree(worktreeRoot, deps) {
129
160
  * proceed. A defensive per-row catch guarantees one unexpected failure cannot
130
161
  * abort later rows or reject the overall call.
131
162
  */
132
- export async function provisionCommandsForCreatedWorktrees(rows, deps) {
163
+ export async function provisionCommandsForCreatedWorktrees(rows, deps, includeCodexSkills = false) {
133
164
  const out = [];
134
165
  for (const row of rows) {
135
166
  if (row.status !== "created" || !row.path) {
@@ -137,7 +168,7 @@ export async function provisionCommandsForCreatedWorktrees(rows, deps) {
137
168
  continue;
138
169
  }
139
170
  try {
140
- const result = await provisionCommandsForWorktree(row.path, deps);
171
+ const result = await provisionCommandsForWorktree(row.path, deps, includeCodexSkills);
141
172
  if (result.ok) {
142
173
  out.push(row);
143
174
  }