@bridge_gpt/mcp-server 0.2.18 → 0.2.19

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.
Files changed (81) hide show
  1. package/CONDUCTOR.md +75 -0
  2. package/README.md +2 -2
  3. package/build/agent-capabilities/probe-context.js +13 -3
  4. package/build/agent-capabilities/probes.js +262 -11
  5. package/build/agent-capabilities/reporter.js +1 -0
  6. package/build/agents.generated.js +1 -1
  7. package/build/backend-warnings.js +44 -0
  8. package/build/claude-settings.js +129 -0
  9. package/build/commands.generated.js +1 -0
  10. package/build/conductor/bridge-api-client.js +7 -7
  11. package/build/conductor/cli.js +65 -12
  12. package/build/conductor/deny-enforcement-preflight.js +96 -0
  13. package/build/conductor/doctor.js +183 -2
  14. package/build/conductor/epic-reconcile.js +9 -1
  15. package/build/conductor/epic-runtime.js +403 -43
  16. package/build/conductor/epic-state.js +7 -0
  17. package/build/conductor/errors.js +115 -3
  18. package/build/conductor/event-accessors.js +28 -10
  19. package/build/conductor/merge-ledger.js +6 -4
  20. package/build/conductor/pr-ci-producer.js +17 -2
  21. package/build/conductor/producer-ledger.js +1 -1
  22. package/build/conductor/store.js +161 -18
  23. package/build/conductor/supervisor-merge.js +32 -5
  24. package/build/conductor/taxonomy.js +8 -0
  25. package/build/conductor/tools.js +28 -6
  26. package/build/conductor/worker-ledger-cli.js +244 -0
  27. package/build/conductor-bin.js +1884 -6917
  28. package/build/doctor.js +8 -0
  29. package/build/executor/cli.js +229 -0
  30. package/build/executor/credentials.js +65 -0
  31. package/build/executor/deps.js +117 -0
  32. package/build/executor/env.js +79 -0
  33. package/build/executor/heartbeat.js +59 -0
  34. package/build/executor/http-client.js +131 -0
  35. package/build/executor/index.js +10 -0
  36. package/build/executor/job-errors.js +55 -0
  37. package/build/executor/job-log-registry.js +110 -0
  38. package/build/executor/job-runner.js +688 -0
  39. package/build/executor/job-types.js +60 -0
  40. package/build/executor/merge-job.js +155 -0
  41. package/build/executor/observation.js +123 -0
  42. package/build/executor/permissions.js +79 -0
  43. package/build/executor/preflight.js +144 -0
  44. package/build/executor/process.js +81 -0
  45. package/build/executor/prompt-spec.js +235 -0
  46. package/build/executor/results.js +134 -0
  47. package/build/executor/resume-pre-spawn.js +179 -0
  48. package/build/executor/runner.js +98 -0
  49. package/build/executor/terminal-mutation.js +34 -0
  50. package/build/executor/test-clock.js +109 -0
  51. package/build/executor/types.js +18 -0
  52. package/build/executor/verdict-artifact.js +53 -0
  53. package/build/executor/viewer-tabs.js +78 -0
  54. package/build/executor/watch-cli.js +113 -0
  55. package/build/executor/worker-command.js +106 -0
  56. package/build/executor/worker-finalization.js +97 -0
  57. package/build/executor/worker-log.js +92 -0
  58. package/build/executor/worktree-gc.js +134 -0
  59. package/build/executor/worktree-inspection.js +86 -0
  60. package/build/executor/worktree.js +103 -0
  61. package/build/index.js +11222 -8544
  62. package/build/mcp-invoke.js +19 -3
  63. package/build/mcp-provisioning.js +31 -25
  64. package/build/mcp-registration-doctor.js +27 -7
  65. package/build/mcp-server-invocation.js +152 -0
  66. package/build/pipelines.generated.js +1 -1
  67. package/build/readme.generated.js +1 -1
  68. package/build/sfcc/reads-site-preference.js +52 -19
  69. package/build/start-tickets-conductor.js +25 -93
  70. package/build/start-tickets-prereqs.js +152 -1
  71. package/build/start-tickets.js +96 -158
  72. package/build/version.generated.js +1 -1
  73. package/build/visual-diff-worker.js +313 -0
  74. package/build/visual-diff.js +632 -0
  75. package/build/worktree-core.js +202 -0
  76. package/package.json +8 -4
  77. package/public/css/main.min.css +39 -0
  78. package/public/css/main.min.css.map +1 -1
  79. package/public/js/main.min.js +7924 -1
  80. package/public/js/main.min.js.map +1 -1
  81. package/smoke-test/SMOKE-TEST.md +2 -1
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Shared Worktrunk worktree primitives (BAPI-534).
3
+ *
4
+ * Extracted verbatim from `start-tickets.ts` so both the interactive
5
+ * `start-tickets` flow and the Epic Conductor v2 executor (`executor/worktree.ts`)
6
+ * call ONE implementation of the `wt switch` argument construction, branch
7
+ * inspection, and Worktrunk JSON path parsing — no duplicated switch logic.
8
+ *
9
+ * `start-tickets.ts` re-exports every symbol here so its pinned test imports
10
+ * (and the strict-equality assertions in `worktree-core.test.ts`) keep working.
11
+ *
12
+ * Import direction: this module imports the shared `StartTicketsDeps` /
13
+ * `BranchOverrides` / `SummaryRow` types from `start-tickets.js` as TYPE-ONLY
14
+ * imports (erased at runtime) plus the `commandSucceeded` value from
15
+ * `start-tickets-prereqs.js`. `start-tickets.ts` imports the VALUES here — a
16
+ * type-only back-edge keeps the runtime graph acyclic (mirrors the existing
17
+ * prereqs <-> start-tickets pattern).
18
+ */
19
+ import path from "path";
20
+ import { commandSucceeded } from "./start-tickets-prereqs.js";
21
+ /** Resolve the branch for a ticket: explicit override, else feature/<KEY>. */
22
+ export function resolveBranchForTicket(key, overrides) {
23
+ if (Object.prototype.hasOwnProperty.call(overrides, key)) {
24
+ return overrides[key];
25
+ }
26
+ return `feature/${key}`;
27
+ }
28
+ /** True only when `git show-ref --verify --quiet refs/heads/<branch>` exits 0. */
29
+ export async function branchExists(deps, branch) {
30
+ const result = await deps.runCommand("git", ["show-ref", "--verify", "--quiet", `refs/heads/${branch}`], { cwd: deps.cwd });
31
+ return commandSucceeded(result);
32
+ }
33
+ /**
34
+ * Build `wt switch` args. Include `--create` only when the branch does not yet
35
+ * exist. Always include `-y` (auto-approve): the CLI runs the Worktrunk binary
36
+ * via `execFile` with no TTY, so without `-y` the `pre-start` / `post-start`
37
+ * hook-approval prompts would have no input source and the call would hang or
38
+ * fail — this mirrors the deleted `scripts/start-tickets.sh`, which ran
39
+ * `wt switch -c -y`. Never includes `-x` — the CLI owns worktree creation and
40
+ * tab spawning separately. The args are platform-agnostic; only the binary
41
+ * differs (`wt` vs `git-wt`).
42
+ *
43
+ * `baseStartPoint` (BAPI-527) is the ref/commit new branches are cut from via
44
+ * Worktrunk's `-b <start-point>`. It may be a branch name (the interactive
45
+ * default, e.g. `"main"`) OR an immutable commit SHA resolved by the non-mutating
46
+ * conductor dispatch path ({@link fetchAndResolveBaseSha}) — Worktrunk's `-b`
47
+ * accepts either. Only used when `exists === false`; existing branches are reused
48
+ * as-is and never recreated from a start point.
49
+ */
50
+ export function buildWtSwitchArgs(branch, exists, baseStartPoint = "main") {
51
+ if (exists) {
52
+ return ["switch", "-y", branch, "--format=json"];
53
+ }
54
+ return ["switch", "--create", "-y", branch, "-b", baseStartPoint, "--format=json"];
55
+ }
56
+ /** Return the Node `path` API matching a platform (`win32` vs POSIX). */
57
+ export function pathApiForPlatform(platform) {
58
+ return platform === "win32" ? path.win32 : path.posix;
59
+ }
60
+ /**
61
+ * Extract a worktree path from Worktrunk JSON stdout. Accepts several common
62
+ * shapes defensively and resolves relative paths against `cwd` using the
63
+ * platform-correct path semantics (so Windows-style paths resolve correctly
64
+ * even when the test/host OS differs). Throws when no usable path can be
65
+ * extracted.
66
+ */
67
+ export function extractWorktreePath(stdout, cwd, platform = process.platform) {
68
+ let parsed;
69
+ try {
70
+ parsed = JSON.parse(stdout);
71
+ }
72
+ catch {
73
+ throw new Error(`Could not parse Worktrunk JSON output: ${stdout.slice(0, 200)}`);
74
+ }
75
+ const candidate = pickWorktreePathField(parsed);
76
+ if (!candidate) {
77
+ throw new Error(`Worktrunk JSON did not include a worktree path: ${stdout.slice(0, 200)}`);
78
+ }
79
+ const pathApi = pathApiForPlatform(platform);
80
+ return pathApi.isAbsolute(candidate) ? candidate : pathApi.resolve(cwd, candidate);
81
+ }
82
+ function pickWorktreePathField(parsed) {
83
+ if (!parsed || typeof parsed !== "object")
84
+ return undefined;
85
+ const obj = parsed;
86
+ if (typeof obj.path === "string")
87
+ return obj.path;
88
+ if (typeof obj.worktree_path === "string")
89
+ return obj.worktree_path;
90
+ if (typeof obj.directory === "string")
91
+ return obj.directory;
92
+ if (obj.worktree && typeof obj.worktree === "object") {
93
+ const nested = obj.worktree;
94
+ if (typeof nested.path === "string")
95
+ return nested.path;
96
+ }
97
+ return undefined;
98
+ }
99
+ /**
100
+ * F7: decide whether a PRE-EXISTING branch is safe to reuse as a conductor
101
+ * worktree base. A branch whose tip is an ancestor of the resolved base carries
102
+ * no commits beyond base (nothing stale to build on) and is safe. A branch with
103
+ * commits not on base is a leftover from a prior run — refuse it. Prefers the
104
+ * authoritative `origin/<base>` ref when present. Conservative: any inability to
105
+ * prove ancestry refuses (when in doubt, refuse).
106
+ *
107
+ * `baseStartPoint` (BAPI-527) is the SAME effective base new worktrees are cut
108
+ * from: a branch name for interactive dispatch, or the fetched immutable commit
109
+ * SHA for non-mutating conductor dispatch. When it is a SHA the `origin/<sha>`
110
+ * probe below naturally fails to resolve, so the ancestry check falls back to
111
+ * comparing the existing branch directly against that fetched SHA — never
112
+ * against the local `main` branch name.
113
+ */
114
+ export async function isExistingBranchSafeToReuse(deps, branch, baseStartPoint) {
115
+ let baseRef = baseStartPoint;
116
+ const originRef = `origin/${baseStartPoint}`;
117
+ const originExists = await deps.runCommand("git", ["rev-parse", "--verify", "--quiet", originRef], { cwd: deps.cwd });
118
+ if (commandSucceeded(originExists))
119
+ baseRef = originRef;
120
+ // `merge-base --is-ancestor <branch> <baseRef>` exits 0 iff <branch> is an
121
+ // ancestor of <baseRef> (a fresh branch at base counts as an ancestor).
122
+ const ancestor = await deps.runCommand("git", ["merge-base", "--is-ancestor", branch, baseRef], { cwd: deps.cwd });
123
+ if (commandSucceeded(ancestor))
124
+ return { safe: true };
125
+ return {
126
+ safe: false,
127
+ reason: `existing branch '${branch}' is not an ancestor of ${baseRef}; it carries commits not on the ` +
128
+ `resolved base (likely a leftover from a prior run). Refusing to reuse a stale worktree — delete it ` +
129
+ `(git worktree remove + git branch -D ${branch}) or rebase it onto ${baseRef}, then re-dispatch.`,
130
+ };
131
+ }
132
+ /**
133
+ * Create / switch the worktree for a single ticket using the resolved Worktrunk
134
+ * binary (`wt` on macOS/Linux, `git-wt` on Windows). Returns a `created` row on
135
+ * success (with key, branch, path) or a `create-failed` row on any expected
136
+ * failure — never throws for per-ticket problems.
137
+ *
138
+ * `baseStartPoint` is routed into `buildWtSwitchArgs` as Worktrunk's `-b` and is
139
+ * used ONLY when the branch does not yet exist locally. Executor RECOVERY callers
140
+ * (BAPI-542/BAPI-528, `executor/worktree.ts`) may pass `origin/<branch>` here so a
141
+ * missing local branch is recreated from the pushed PR branch rather than cut
142
+ * fresh off the base branch, and additionally pass `behavior.freshenFromOrigin`
143
+ * so an ALREADY-EXISTING local branch is hard-reset onto that same pushed ref
144
+ * instead of being silently reused as-is. This stays executor-agnostic: no
145
+ * job-type logic lives here — the caller decides the start point, the stale
146
+ * guard, and the freshen behavior.
147
+ */
148
+ export async function createWorktreeForTicket(deps, key, branchOverrides, worktrunkBinary, baseStartPoint = "main", guardStaleWorktree = false, behavior = {}) {
149
+ const branch = resolveBranchForTicket(key, branchOverrides);
150
+ try {
151
+ const exists = await branchExists(deps, branch);
152
+ // F7 (conductor dispatch): refuse a stale pre-existing branch rather than
153
+ // silently building the worker on leftover code. BAPI-527: the ancestry
154
+ // check compares against the SAME effective base start point (branch name or
155
+ // fetched SHA) that a NEW branch would be cut from below.
156
+ if (exists && guardStaleWorktree) {
157
+ const safety = await isExistingBranchSafeToReuse(deps, branch, baseStartPoint);
158
+ if (!safety.safe) {
159
+ return {
160
+ key,
161
+ branch,
162
+ status: "create-failed",
163
+ error: `stale worktree guard: ${safety.reason}`,
164
+ };
165
+ }
166
+ }
167
+ const args = buildWtSwitchArgs(branch, exists, baseStartPoint);
168
+ const result = await deps.runCommand(worktrunkBinary, args, { cwd: deps.cwd });
169
+ if (!commandSucceeded(result)) {
170
+ const reason = (result.stderr || result.stdout || "").trim();
171
+ return {
172
+ key,
173
+ branch,
174
+ status: "create-failed",
175
+ error: `${worktrunkBinary} ${args.join(" ")} failed${reason ? `: ${reason}` : ""}`,
176
+ };
177
+ }
178
+ const worktreePath = extractWorktreePath(result.stdout, deps.cwd, deps.platform);
179
+ // BAPI-528: freshen a REUSED existing branch onto the pushed ref. A new
180
+ // branch was already cut from `baseStartPoint` (recovery sets that to
181
+ // `origin/<branch>`), so this only applies when the local branch pre-existed.
182
+ // Run inside the switched worktree (the branch is checked out there).
183
+ if (exists && behavior.freshenFromOrigin) {
184
+ const resetArgs = ["reset", "--hard", behavior.freshenFromOrigin];
185
+ const reset = await deps.runCommand("git", resetArgs, { cwd: worktreePath });
186
+ if (!commandSucceeded(reset)) {
187
+ const reason = (reset.stderr || reset.stdout || "").trim();
188
+ return {
189
+ key,
190
+ branch,
191
+ status: "create-failed",
192
+ error: `git ${resetArgs.join(" ")} failed${reason ? `: ${reason}` : ""}`,
193
+ };
194
+ }
195
+ }
196
+ return { key, branch, status: "created", path: worktreePath };
197
+ }
198
+ catch (err) {
199
+ const message = err instanceof Error ? err.message : String(err);
200
+ return { key, branch, status: "create-failed", error: message };
201
+ }
202
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bridge_gpt/mcp-server",
3
- "version": "0.2.18",
3
+ "version": "0.2.19",
4
4
  "description": "Bridge API MCP server — exposes Jira endpoints as MCP tools for Claude Code agents",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -27,21 +27,25 @@
27
27
  "check:version-generated": "node scripts/bundle-version.js && node scripts/check-version-generated.js",
28
28
  "postbuild": "node scripts/prepend-shebang.cjs",
29
29
  "start": "node build/index.js",
30
- "test": "node --test --test-force-exit build/pipeline-utils.test.js build/update-check.test.js build/cli-upgrade.test.js build/decision-page-schema.test.js build/decision-page-template.test.js build/bundle-pipelines.test.js build/instructions-contract.test.js build/pipeline-orchestrator-persistence.test.js build/pipeline-orchestrator-execution.test.js build/pipeline-orchestrator-integration.test.js build/index-static.test.js build/config-fields.static.test.js build/index-resolvers.test.js build/index-project-root.test.js build/index-pipelines.test.js build/index.test.js build/bridge-config.test.js build/credential-store.test.js build/agent-config-credential-migration.test.js build/mcp-invoke.test.js build/mcp-provisioning.test.js build/third-party-mcp-targets.test.js build/git-ignore-utils.test.js build/credential-materialization.test.js build/mcp-registration-doctor.test.js build/secret-safety.test.js build/start-tickets.test.js build/review-tickets.test.js build/start-tickets-base-branch.test.js build/agent-registry.test.js build/agent-registry.model-routing.test.js build/start-tickets.shell-model-routing.test.js build/start-tickets.bridge-api-model-routing.test.js build/start-tickets.tier-fetch-model-routing.test.js build/start-tickets.resolve-model-routing.test.js build/start-tickets.orchestrate-model-routing.test.js build/start-tickets.routing-diagnostics.test.js build/start-tickets-repo.test.js build/start-tickets-credential-invariants.static.test.js build/credentials-cli.test.js build/start-tickets-prereqs.test.js build/regression-check.test.js build/doctor.test.js build/install-doctor.test.js build/install-bridge.test.js build/init.test.js build/resolveUploadAttachment.test.js build/package-static.test.js build/chain-utils.test.js build/chain-orchestrator.test.js build/scheduler-backends/types.test.js build/scheduler-backends/escaping.test.js build/scheduler-backends/launchd.test.js build/scheduler-backends/task-scheduler.test.js build/scheduler-backends/systemd-user.test.js build/scheduler-backends/at-fallback.test.js build/scheduler-backends/index.test.js build/command-catalog.test.js build/scheduled-prompt.test.js build/agent-launchers/claude.test.js build/agent-launchers/cursor.test.js build/agent-launchers/index.test.js build/schedule-store.test.js build/schedule-run.test.js build/agent-capabilities/cli.test.js build/agent-capabilities/runner.test.js build/agent-capabilities/probes.test.js build/agent-capabilities/reporter.test.js build/conductor/taxonomy-and-errors.test.js build/conductor/github-mergeability.test.js build/conductor/merge-conflict-routing.test.js build/conductor/redaction-normalization.test.js build/conductor/claude-hook.test.js build/conductor/git-ci-types.test.js build/conductor/done-gate.test.js build/conductor/git-ci-taxonomy-payload.test.js build/conductor/bridge-api-client.test.js build/conductor/plan.test.js build/conductor/producer-ledger.test.js build/conductor/spec-review-producer.test.js build/conductor/git-producer.test.js build/conductor/git-hooks.test.js build/conductor/store-migration.test.js build/conductor/pr-discovery.test.js build/conductor/pr-ci-producer.test.js build/conductor/pr-review-producer.test.js build/conductor/doctor.test.js build/conductor/index-poll-ci-producer.test.js build/start-tickets-conductor.test.js build/start-tickets-conductor.spawn.test.js build/conductor/supervisor-config.test.js build/conductor/supervisor-ledger.test.js build/conductor/supervisor-state-reducer.test.js build/conductor/supervisor-housekeeping-projection.test.js build/conductor/supervisor-escalation.test.js build/conductor/supervisor-retired-judgment.static.test.js build/conductor/supervisor-runtime.test.js build/conductor/supervisor-store-projection.test.js build/conductor/supervisor-cli.test.js build/conductor/supervisor-start-tickets.test.js build/conductor/supervisor-message-relay.test.js build/conductor/supervisor-state-message-events.test.js build/conductor/store-message-relay.test.js build/start-tickets-message-relay.test.js build/conductor/event-accessors.test.js build/conductor/merge-ledger.test.js build/conductor/local-merge.test.js build/conductor/supervisor-merge.test.js build/conductor/bridge-api-merge-client.test.js build/conductor/bridge-api-epic-client.test.js build/conductor/supervisor-merge-runtime-state.test.js build/conductor/epic-state.test.js build/conductor/epic-reconcile.test.js build/conductor/epic-runtime.test.js build/conductor/epic-tick-sequence.test.js build/conductor/epic-runtime-post-action.test.js build/conductor/file-scope-guard.test.js build/conductor/file-scope-guard.integration.test.js build/mcp-profile.test.js build/mcp-profile-registration.test.js build/tools-budget.test.js build/integration/measure-tools.test.js build/sfcc/config.test.js build/sfcc/ocapi-shape.test.js build/sfcc/output.test.js build/sfcc/credentials.test.js && node --experimental-test-module-mocks --test --test-force-exit build/index-heavy-read-truncation.test.js build/index-artifacts.test.js build/index-brainstorm-filenames.test.js build/index-output-path.test.js build/index-generate-decision-page.test.js build/index-generate-decision-page.integration.test.js build/conductor/paths.test.js build/conductor/store-lifecycle.test.js build/conductor/store-queries.test.js build/conductor/tools.test.js build/conductor/cli.test.js build/conductor/security-regressions.test.js build/conductor/git-inspection.test.js build/conductor/tools-done-gate.test.js build/conductor/cli-git-hooks.test.js build/sfcc/client.test.js build/sfcc/tool-wrapper.test.js build/sfcc/setup-status.test.js build/sfcc/permissions.test.js build/sfcc/register.test.js build/sfcc/reads-system-object.test.js build/sfcc/reads-custom-object-def.test.js build/sfcc/reads-site-preference.test.js",
31
- "test:integration": "node --test build/integration/refresh-main.integration.test.js build/integration/start-tickets.integration.test.js build/integration/doctor.integration.test.js build/integration/agent-capabilities.integration.test.js build/integration/conductor-producer.integration.test.js build/integration/conductor-message-relay.integration.test.js",
30
+ "test": "node --test --test-force-exit build/pipeline-utils.test.js build/backend-warnings.test.js build/update-check.test.js build/cli-upgrade.test.js build/decision-page-schema.test.js build/decision-page-template.test.js build/bundle-pipelines.test.js build/instructions-contract.test.js build/pipeline-orchestrator-persistence.test.js build/pipeline-orchestrator-execution.test.js build/pipeline-orchestrator-integration.test.js build/index-static.test.js build/config-fields.static.test.js build/index-resolvers.test.js build/index-project-root.test.js build/index-pipelines.test.js build/index.test.js build/bridge-config.test.js build/credential-store.test.js build/agent-config-credential-migration.test.js build/mcp-invoke.test.js build/mcp-provisioning.test.js build/mcp-server-invocation.test.js build/third-party-mcp-targets.test.js build/git-ignore-utils.test.js build/credential-materialization.test.js build/mcp-registration-doctor.test.js build/secret-safety.test.js build/start-tickets.test.js build/review-tickets.test.js build/start-tickets-base-branch.test.js build/agent-registry.test.js build/agent-registry.model-routing.test.js build/start-tickets.shell-model-routing.test.js build/start-tickets.bridge-api-model-routing.test.js build/start-tickets.tier-fetch-model-routing.test.js build/start-tickets.resolve-model-routing.test.js build/start-tickets.orchestrate-model-routing.test.js build/start-tickets.routing-diagnostics.test.js build/start-tickets-repo.test.js build/start-tickets-credential-invariants.static.test.js build/credentials-cli.test.js build/start-tickets-prereqs.test.js build/regression-check.test.js build/doctor.test.js build/install-doctor.test.js build/install-bridge.test.js build/init.test.js build/resolveUploadAttachment.test.js build/package-static.test.js build/chain-utils.test.js build/chain-orchestrator.test.js build/scheduler-backends/types.test.js build/scheduler-backends/escaping.test.js build/scheduler-backends/launchd.test.js build/scheduler-backends/task-scheduler.test.js build/scheduler-backends/systemd-user.test.js build/scheduler-backends/at-fallback.test.js build/scheduler-backends/index.test.js build/command-catalog.test.js build/scheduled-prompt.test.js build/agent-launchers/claude.test.js build/agent-launchers/cursor.test.js build/agent-launchers/index.test.js build/schedule-store.test.js build/schedule-run.test.js build/agent-capabilities/cli.test.js build/agent-capabilities/runner.test.js build/agent-capabilities/probes.test.js build/agent-capabilities/probe-context.test.js build/agent-capabilities/reporter.test.js build/conductor/taxonomy-and-errors.test.js build/conductor/github-mergeability.test.js build/conductor/merge-conflict-routing.test.js build/conductor/redaction-normalization.test.js build/conductor/claude-hook.test.js build/conductor/git-ci-types.test.js build/conductor/done-gate.test.js build/conductor/git-ci-taxonomy-payload.test.js build/conductor/bridge-api-client.test.js build/conductor/plan.test.js build/conductor/producer-ledger.test.js build/conductor/spec-review-producer.test.js build/conductor/git-producer.test.js build/conductor/git-hooks.test.js build/conductor/store-migration.test.js build/conductor/pr-discovery.test.js build/conductor/pr-ci-producer.test.js build/conductor/pr-review-producer.test.js build/conductor/doctor.test.js build/conductor/deny-enforcement-preflight.test.js build/conductor/errors.test.js build/conductor/store.test.js build/conductor/index-poll-ci-producer.test.js build/start-tickets-conductor.test.js build/start-tickets-conductor.spawn.test.js build/start-tickets-conductor-node-propagation.test.js build/start-tickets.non-mutating-base.test.js build/start-tickets-live-source-guard.test.js build/conductor/worker-ledger-cli.test.js build/conductor/supervisor-config.test.js build/conductor/supervisor-ledger.test.js build/conductor/supervisor-state-reducer.test.js build/conductor/supervisor-housekeeping-projection.test.js build/conductor/supervisor-escalation.test.js build/conductor/supervisor-retired-judgment.static.test.js build/conductor/supervisor-runtime.test.js build/conductor/supervisor-store-projection.test.js build/conductor/supervisor-cli.test.js build/conductor/supervisor-start-tickets.test.js build/conductor/supervisor-message-relay.test.js build/conductor/supervisor-state-message-events.test.js build/conductor/store-message-relay.test.js build/start-tickets-message-relay.test.js build/conductor/event-accessors.test.js build/conductor/merge-ledger.test.js build/conductor/deterministic-completion.static.test.js build/conductor/deterministic-completion.integration.test.js build/conductor/local-merge.test.js build/conductor/supervisor-merge.test.js build/conductor/bridge-api-merge-client.test.js build/conductor/bridge-api-epic-client.test.js build/conductor/supervisor-merge-runtime-state.test.js build/conductor/epic-state.test.js build/executor/claude-settings.test.js build/executor/cli.test.js build/executor/credentials.test.js build/executor/echo-acceptance.test.js build/executor/env.test.js build/executor/heartbeat.test.js build/executor/http-client.test.js build/executor/job-runner.test.js build/executor/job-runner.payload-timeout.test.js build/executor/worker-finalization.test.js build/executor/job-runner.static.test.js build/executor/prompt-spec.test.js build/executor/job-types.test.js build/executor/recovery-job.static.test.js build/executor/observation.test.js build/executor/permissions.test.js build/executor/preflight.test.js build/executor/process.test.js build/executor/results.test.js build/executor/runner.test.js build/executor/terminal-mutation.test.js build/executor/worker-command.test.js build/executor/worktree-core.test.js build/executor/worktree.test.js build/executor/job-errors.test.js build/executor/worktree-inspection.test.js build/executor/resume-pre-spawn.test.js build/executor/verdict-artifact.test.js build/executor/worker-log.test.js build/executor/job-log-registry.test.js build/executor/viewer-tabs.test.js build/executor/watch-cli.test.js build/executor/merge-job.test.js build/executor/worktree-gc.test.js build/executor/runner.job-behaviors.test.js build/conductor/cli-freeze.test.js build/conductor/epic-reconcile.test.js build/conductor/epic-runtime.test.js build/conductor/epic-tick-sequence.test.js build/conductor/epic-runtime-post-action.test.js build/conductor/file-scope-guard.test.js build/conductor/file-scope-guard.integration.test.js build/mcp-profile.test.js build/mcp-profile-registration.test.js build/tools-budget.test.js build/visual-diff-worker.test.js build/visual-diff.test.js build/integration/measure-tools.test.js build/sfcc/config.test.js build/sfcc/ocapi-shape.test.js build/sfcc/output.test.js build/sfcc/credentials.test.js && node --experimental-test-module-mocks --test --test-force-exit build/index-heavy-read-truncation.test.js build/index-artifacts.test.js build/index-brainstorm-filenames.test.js build/index-output-path.test.js build/index-generate-decision-page.test.js build/index-generate-decision-page.integration.test.js build/visual-diff.registration.test.js build/visual-diff.attachment-adapter.test.js build/attachment-download.test.js build/conductor/paths.test.js build/conductor/store-lifecycle.test.js build/conductor/store-queries.test.js build/conductor/tools.test.js build/conductor/cli.test.js build/conductor/security-regressions.test.js build/conductor/git-inspection.test.js build/conductor/tools-done-gate.test.js build/conductor/pr-ci-producer-emit-seam.test.js build/conductor/cli-git-hooks.test.js build/sfcc/client.test.js build/sfcc/tool-wrapper.test.js build/sfcc/setup-status.test.js build/sfcc/permissions.test.js build/sfcc/register.test.js build/sfcc/reads-system-object.test.js build/sfcc/reads-custom-object-def.test.js build/sfcc/reads-site-preference.test.js",
31
+ "test:integration": "node --test build/integration/refresh-main.integration.test.js build/integration/start-tickets.integration.test.js build/integration/doctor.integration.test.js build/integration/agent-capabilities.integration.test.js build/integration/conductor-producer.integration.test.js build/integration/conductor-message-relay.integration.test.js build/integration/executor-http-runner.integration.test.js build/integration/executor-job-behaviors.integration.test.js build/integration/executor-recovery-jobs.integration.test.js build/integration/executor-spec-review-prompt.integration.test.js build/integration/resume-pre-spawn.git.integration.test.js",
32
32
  "test:smoke": "node --test build/integration/packaged-cli-smoke.test.js",
33
33
  "prepublishOnly": "node scripts/bundle-assets.js && npm run build && node scripts/verify-shebang.cjs"
34
34
  },
35
35
  "dependencies": {
36
36
  "@modelcontextprotocol/sdk": "^1.29.0",
37
+ "pixelmatch": "^6.0.0",
38
+ "pngjs": "^7.0.0",
37
39
  "zod": "^4.4.3"
38
40
  },
39
41
  "optionalDependencies": {
40
- "better-sqlite3": "^12.11.1"
42
+ "better-sqlite3": "^12.11.1",
43
+ "playwright": "^1.51.1"
41
44
  },
42
45
  "devDependencies": {
43
46
  "@types/better-sqlite3": "^7.6.12",
44
47
  "@types/node": "^26.0.1",
48
+ "@types/pngjs": "^6.0.5",
45
49
  "esbuild": "^0.28.1",
46
50
  "typescript": "^6.0.3"
47
51
  },
@@ -494,6 +494,45 @@ textarea {
494
494
  line-height: 1.4;
495
495
  }
496
496
 
497
+ /* Structured server-sourced setup instructions (BAPI-515), rendered inside
498
+ .explanation-content by renderExplanationContent(). Scoped to this wrapper
499
+ only — the container above is left untouched. */
500
+ .explanation-content .setup-instructions {
501
+ display: flex;
502
+ flex-direction: column;
503
+ gap: 8px;
504
+ }
505
+
506
+ .explanation-content .setup-instructions-link {
507
+ color: var(--primary-color);
508
+ font-weight: 500;
509
+ text-decoration: underline;
510
+ overflow-wrap: anywhere;
511
+ }
512
+
513
+ .explanation-content .setup-instructions-link:hover {
514
+ color: var(--primary-dark);
515
+ }
516
+
517
+ .explanation-content .setup-instructions-link:focus-visible {
518
+ outline: 2px solid var(--primary-color);
519
+ outline-offset: 2px;
520
+ }
521
+
522
+ .explanation-content .setup-instructions-steps {
523
+ margin: 0;
524
+ padding-left: 20px;
525
+ }
526
+
527
+ .explanation-content .setup-instructions-steps li + li {
528
+ margin-top: 4px;
529
+ }
530
+
531
+ .explanation-content .setup-instructions-note {
532
+ margin: 0;
533
+ color: var(--secondary-color);
534
+ }
535
+
497
536
  /* Form error styling */
498
537
  .form-error {
499
538
  color: var(--error-color);