@bridge_gpt/mcp-server 0.2.59 → 0.2.60

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 (71) hide show
  1. package/README.md +173 -51
  2. package/build/agent-guidance.generated.js +1 -1
  3. package/build/agent-notes.js +7 -1
  4. package/build/commands.generated.js +4 -4
  5. package/build/conductor/bridge-api-client.js +53 -2
  6. package/build/conductor/doctor.js +255 -53
  7. package/build/conductor/epic-runtime.js +11 -2
  8. package/build/conductor/install-doctor.js +24 -2
  9. package/build/conductor/local-merge.js +319 -26
  10. package/build/conductor/merge-execution-contract.js +61 -0
  11. package/build/conductor/merge-execution-eligibility.js +129 -0
  12. package/build/conductor/readiness-sections.js +159 -2
  13. package/build/conductor/readiness.js +95 -14
  14. package/build/conductor/recovery-operations.js +8 -2
  15. package/build/connect-bitbucket-api.js +6 -1
  16. package/build/connect-bitbucket.js +398 -88
  17. package/build/credential-store.js +16 -0
  18. package/build/docs.generated.js +2 -2
  19. package/build/doctor.js +183 -9
  20. package/build/drive-epic.js +23 -0
  21. package/build/epic-implementer-bin.js +10 -10
  22. package/build/epic-implementer-claude-hook-bin.js +1 -1
  23. package/build/epic-implementer-env.js +43 -14
  24. package/build/executor/ci-rerun-job.js +269 -0
  25. package/build/executor/cli.js +31 -0
  26. package/build/executor/credentials.js +11 -0
  27. package/build/executor/env.js +60 -0
  28. package/build/executor/index.js +21 -4
  29. package/build/executor/job-runner.js +126 -0
  30. package/build/executor/job-types.js +12 -2
  31. package/build/executor/merge-job.js +11 -2
  32. package/build/executor/service-lifecycle.js +136 -0
  33. package/build/executor/service-unit.js +427 -9
  34. package/build/executor/types.js +5 -0
  35. package/build/index.js +194 -179
  36. package/build/install-bridge-conductor.js +201 -8
  37. package/build/install-bridge.js +356 -30
  38. package/build/mcp-install-state.js +42 -4
  39. package/build/merge-pull-request.js +103 -10
  40. package/build/merge-workflow-codeowners.js +224 -0
  41. package/build/merge-workflow-config.js +133 -0
  42. package/build/merge-workflow-drift.js +66 -0
  43. package/build/merge-workflow-install.js +638 -0
  44. package/build/merge-workflow.js +572 -0
  45. package/build/pipelines.generated.js +2 -2
  46. package/build/plane/cli.js +24 -2
  47. package/build/plane/preflight.js +68 -0
  48. package/build/readme.generated.js +1 -1
  49. package/build/run-unit-tests-launcher.js +5 -0
  50. package/build/setup-epic.js +163 -9
  51. package/build/version.generated.js +3 -3
  52. package/package.json +3 -3
  53. package/build/conduct-epic/bridge-client.js +0 -773
  54. package/build/conduct-epic/checkpoint-store.js +0 -542
  55. package/build/conduct-epic/cli.js +0 -3145
  56. package/build/conduct-epic/cut-protocol.js +0 -392
  57. package/build/conduct-epic/lock.js +0 -302
  58. package/build/conduct-epic/pr-state.js +0 -286
  59. package/build/conduct-epic/spawn.js +0 -113
  60. package/build/conductor/cli.js +0 -1278
  61. package/build/conductor-bundle-cli.js +0 -256
  62. package/build/direct-ticket-tools.js +0 -70
  63. package/build/executor/reconcile-overlap-governance.js +0 -129
  64. package/build/implement-epic/bridge-client.js +0 -773
  65. package/build/implement-epic/checkpoint-store.js +0 -542
  66. package/build/implement-epic/cli.js +0 -3158
  67. package/build/implement-epic/cut-protocol.js +0 -392
  68. package/build/implement-epic/lock.js +0 -302
  69. package/build/implement-epic/pr-state.js +0 -286
  70. package/build/implement-epic/spawn.js +0 -113
  71. package/build/plan-epic-conductor-eligibility.js +0 -213
@@ -65,6 +65,11 @@ export const MODULE_MOCK_MANIFEST = [
65
65
  "build/conductor/store-lifecycle.test.js",
66
66
  "build/conductor/store-queries.test.js",
67
67
  "build/conductor/tools.test.js",
68
+ // BAPI-1247: drives offerBitbucketConnection to a chosen structured outcome by
69
+ // mocking the shared connect flow at install-bridge.ts's import site, which needs
70
+ // --experimental-test-module-mocks. Kept apart from install-bridge.test.js so that
71
+ // 346-test file stays in the NORMAL lane.
72
+ "build/connect-bitbucket-handoff.test.js",
68
73
  "build/connect-github-api.test.js",
69
74
  "build/connect-github-dispatch.static.test.js",
70
75
  "build/connect-github-handoff.test.js",
@@ -78,7 +78,14 @@
78
78
  import { readFile as fsReadFile, stat as fsStat } from "node:fs/promises";
79
79
  import os from "node:os";
80
80
  import { createProductionEpicIntegrationGhRunner, ensureEpicIntegrationPullRequest, formatEpicIntegrationPullRequestOutcome, } from "./epic-integration-pr.js";
81
- import { approveEpicPlan, createEpicRunWithDisposition, fetchConductorReadiness, fetchEpicRunState, replaceEpicRunPolicy, resolveConductorBridgeApiAccess, storeEpicPlan, validateEpicPlan, ConductorBridgeApiError, } from "./conductor/bridge-api-client.js";
81
+ import { approveEpicPlan, buildConductorJiraUrl, conductorGetHeaders, createEpicRunWithDisposition, fetchConductorReadiness, fetchEpicRunState, replaceEpicRunPolicy, resolveConductorBridgeApiAccess, storeEpicPlan, validateEpicPlan, ConductorBridgeApiError, } from "./conductor/bridge-api-client.js";
82
+ // BAPI-1133 (A2) — the single legacy-to-typed merge-execution-mode mapping and
83
+ // its total legacy resolver live in `merge-pull-request.ts` (no import cycle:
84
+ // that module never imports from `setup-epic.ts`). Reused here rather than
85
+ // reimplemented so the mapping stays single-defined.
86
+ import { mapLegacyMergeExecutionModeToPolicyMode, resolveMergeExecutionMode, } from "./merge-pull-request.js";
87
+ import { MERGE_EXECUTION_INELIGIBLE, MERGE_EXECUTION_MODE_GITHUB_ACTIONS, MERGE_WORKFLOW_REMEDY_COMMAND, } from "./conductor/merge-execution-contract.js";
88
+ import { classifyMergeExecutionEligibility } from "./conductor/merge-execution-eligibility.js";
82
89
  import { resolveTrackedPaths } from "./git-reachability.js";
83
90
  import { validateBranchName } from "./base-ref.js";
84
91
  // Reused from the implement-epic client on purpose: adding a second wrapper under
@@ -128,6 +135,19 @@ export const SETUP_EPIC_UNATTENDED_POSTURE_REFUSED_CODE = "UNATTENDED_POSTURE_RE
128
135
  * which is what the observed BAPI-1085 run did.
129
136
  */
130
137
  export const SETUP_EPIC_AUTO_MERGE_POLICY_KEY = "v2_auto_merge_enabled";
138
+ /**
139
+ * The `policy_json` key declaring the typed merge-execution mode (BAPI-1133, A2).
140
+ *
141
+ * Composed into the unattended default alongside `posture` and
142
+ * {@link SETUP_EPIC_AUTO_MERGE_POLICY_KEY}, in the SAME fill-if-absent branch,
143
+ * because the server's `RunPolicy` refuses an unattended auto-merge policy that
144
+ * omits it (`merge_execution_mode_unconfigured`). `setup-epic` is the only
145
+ * IMPLICIT writer of this key — any other client may still submit it explicitly
146
+ * as operator policy, and an explicitly supplied value here is never overwritten.
147
+ * Declaring `github_actions` or `machine_token` is intent only in this slice:
148
+ * neither changes merge execution until a later A2 child.
149
+ */
150
+ export const SETUP_EPIC_MERGE_EXECUTION_MODE_POLICY_KEY = "merge_execution_mode";
131
151
  /** Accepted `policy_json.review_policy.source` values (the `ReviewPolicy` surface). */
132
152
  export const SETUP_EPIC_REVIEW_POLICY_SOURCES = [
133
153
  "verdict_protocol",
@@ -169,12 +189,15 @@ export function getSetupEpicUsage() {
169
189
  "repository base branch, matching plain start-tickets semantics.",
170
190
  "",
171
191
  "Posture (default): a run that selects an epic branch is created UNATTENDED —",
172
- "posture: unattended and v2_auto_merge_enabled: true — and the server stamps its",
173
- "CI gate at first approval from the repository default, or records an explicit",
174
- "no-CI-gate mode when the repository declares none. Child PRs merge into the epic",
175
- "branch; the INTEGRATION PR into the repository base branch stays human-gated.",
176
- "Pass --attended to opt out. A run that selects no epic branch (--into-base, or a",
177
- "single-node plan) is unchanged and composes no posture at all.",
192
+ "posture: unattended, v2_auto_merge_enabled: true, and merge_execution_mode",
193
+ "(declared automatically from the repository's configured merge execution; a",
194
+ "policy declaration only — it does not change merge execution in this release)",
195
+ "— and the server stamps its CI gate at first approval from the repository",
196
+ "default, or records an explicit no-CI-gate mode when the repository declares",
197
+ "none. Child PRs merge into the epic branch; the INTEGRATION PR into the",
198
+ "repository base branch stays human-gated. Pass --attended to opt out. A run",
199
+ "that selects no epic branch (--into-base, or a single-node plan) is unchanged",
200
+ "and composes no posture at all.",
178
201
  "",
179
202
  "Unattended runs have TWO one-time repository prerequisites, refused by name",
180
203
  "before any run is created: repository consent (unattended_epic_implementer_allowed) and",
@@ -1244,6 +1267,66 @@ export function evaluateSetupEpicBringUpPrerequisites(readiness) {
1244
1267
  return null;
1245
1268
  return { reason, message: `${BRING_UP_REFUSAL_MESSAGES[reason]} ${NO_RUN_WAS_CREATED}` };
1246
1269
  }
1270
+ /**
1271
+ * Read the composed policy's typed `merge_execution_mode`, if it declares one.
1272
+ *
1273
+ * Strict equality against the mirrored constant, matching the server's own guard
1274
+ * (`preflight._strict_github_actions_mode`). A missing key, a non-string, and
1275
+ * any other mode all answer `false`, so nothing but an explicit declaration
1276
+ * opens the gate.
1277
+ */
1278
+ export function policyDeclaresGitHubActionsMerge(policy) {
1279
+ if (policy === undefined || policy === null)
1280
+ return false;
1281
+ return policy.merge_execution_mode === MERGE_EXECUTION_MODE_GITHUB_ACTIONS;
1282
+ }
1283
+ /**
1284
+ * Evaluate merge-execution eligibility against a readiness report.
1285
+ *
1286
+ * Pure and total. Returns `null` — no refusal — for every policy that does not
1287
+ * declare `github_actions` mode, without reading the report at all.
1288
+ *
1289
+ * Uses {@link classifyMergeExecutionEligibility}, the same classifier readiness
1290
+ * and `drive-epic` read, so all three agree on the status AND on the first
1291
+ * blocker. A client that classified the block itself here would eventually
1292
+ * disagree with the row an operator had just been shown.
1293
+ *
1294
+ * BOTH `not_eligible` and `could_not_verify` return
1295
+ * `merge_execution_ineligible`. One code, because the operator's next action is
1296
+ * the same and splitting it would put the burden of telling "not proven" from
1297
+ * "proven absent" on the person least able to check. The MESSAGE keeps the
1298
+ * capability category explicit, so the distinction survives where it is
1299
+ * actionable.
1300
+ *
1301
+ * The message is built from the shared remedy constant, ends with the exact
1302
+ * standalone sentence `No run was created.`, and carries no GitHub payload, URL,
1303
+ * branch name, workflow source, credential, or exception text.
1304
+ */
1305
+ export function evaluateSetupEpicMergeExecutionPrerequisites(readiness, requestedPolicy) {
1306
+ if (!policyDeclaresGitHubActionsMerge(requestedPolicy))
1307
+ return null;
1308
+ if (readiness === null) {
1309
+ return {
1310
+ reason: MERGE_EXECUTION_INELIGIBLE,
1311
+ message: "this run declares merge_execution_mode: github_actions, and the Bridge API " +
1312
+ "conductor readiness report could not be read, so the repository's merge " +
1313
+ "capability could not be confirmed. Retry once the server is reachable, or " +
1314
+ `resolve it with \`${MERGE_WORKFLOW_REMEDY_COMMAND}\`. ${NO_RUN_WAS_CREATED}`,
1315
+ };
1316
+ }
1317
+ const verdict = classifyMergeExecutionEligibility(readiness);
1318
+ if (verdict.status === "eligible")
1319
+ return null;
1320
+ const category = verdict.status === "could_not_verify"
1321
+ ? "could not be confirmed"
1322
+ : "is not sufficient";
1323
+ return {
1324
+ reason: MERGE_EXECUTION_INELIGIBLE,
1325
+ message: "this run declares merge_execution_mode: github_actions, and this repository's " +
1326
+ `merge capability ${category}: ${verdict.detail}. Resolve it with ` +
1327
+ `\`${MERGE_WORKFLOW_REMEDY_COMMAND}\`, then re-run. ${NO_RUN_WAS_CREATED}`,
1328
+ };
1329
+ }
1247
1330
  /**
1248
1331
  * Does the policy this invocation will actually send request unattended operation?
1249
1332
  *
@@ -1283,8 +1366,10 @@ export function requestedPolicyIsUnattended(policy, attended) {
1283
1366
  * * **Feature branch, `--attended`** → `base_branch` plus an explicitly
1284
1367
  * requested `review_policy`, and nothing else. Byte-identical to the
1285
1368
  * pre-BAPI-1102 composition, which is precisely what the opt-out promises.
1286
- * * **Feature branch, default** → adds `posture: "unattended"` and
1287
- * `v2_auto_merge_enabled: true`.
1369
+ * * **Feature branch, default** → adds `posture: "unattended"`,
1370
+ * `v2_auto_merge_enabled: true`, and (BAPI-1133, A2) `merge_execution_mode`
1371
+ * when the caller resolved one — the server refuses an unattended auto-merge
1372
+ * policy that omits it.
1288
1373
  *
1289
1374
  * Deliberately absent from every shape:
1290
1375
  *
@@ -1306,6 +1391,9 @@ export function composeDefaultSetupEpicPolicy(args) {
1306
1391
  if (!args.attended) {
1307
1392
  policy.posture = SETUP_EPIC_UNATTENDED_POSTURE;
1308
1393
  policy[SETUP_EPIC_AUTO_MERGE_POLICY_KEY] = true;
1394
+ if (args.mergeExecutionMode !== undefined) {
1395
+ policy[SETUP_EPIC_MERGE_EXECUTION_MODE_POLICY_KEY] = args.mergeExecutionMode;
1396
+ }
1309
1397
  }
1310
1398
  }
1311
1399
  if (args.reviewPolicy !== undefined) {
@@ -1346,6 +1434,14 @@ export function composeDefaultSetupEpicPolicy(args) {
1346
1434
  * * **`v2_auto_merge_enabled` already present** → left exactly as the file set
1347
1435
  * it, including `false`. Filling the posture does not overwrite an explicit
1348
1436
  * merge decision.
1437
+ * * **`merge_execution_mode` already present** (BAPI-1133, A2) → left exactly
1438
+ * as the file set it, valid or not. An explicitly present but invalid mode is
1439
+ * NOT silently repaired here; it is forwarded unchanged so the server's
1440
+ * secret-safe typed validation rejects it. Absent, it is filled from the
1441
+ * caller's already-resolved {@link TypedMergeExecutionMode} in the same
1442
+ * fill-if-absent branch that stamps `posture` and
1443
+ * {@link SETUP_EPIC_AUTO_MERGE_POLICY_KEY} — the server refuses an
1444
+ * unattended auto-merge policy that omits it.
1349
1445
  *
1350
1446
  * Pure: it returns a new object and never mutates the input. It is applied on the
1351
1447
  * CREATE path only. A reused live run reconciles the file against its STORED
@@ -1365,6 +1461,10 @@ export function applySetupEpicUnattendedDefault(policy, args) {
1365
1461
  if (!(SETUP_EPIC_AUTO_MERGE_POLICY_KEY in composed)) {
1366
1462
  composed[SETUP_EPIC_AUTO_MERGE_POLICY_KEY] = true;
1367
1463
  }
1464
+ if (!(SETUP_EPIC_MERGE_EXECUTION_MODE_POLICY_KEY in composed) &&
1465
+ args.mergeExecutionMode !== undefined) {
1466
+ composed[SETUP_EPIC_MERGE_EXECUTION_MODE_POLICY_KEY] = args.mergeExecutionMode;
1467
+ }
1368
1468
  return composed;
1369
1469
  }
1370
1470
  /**
@@ -1873,6 +1973,27 @@ async function executeSetupEpic(argv, overrides, runIdSink) {
1873
1973
  // `base_branch` is honored exactly as `--feature-branch` would be. A malformed
1874
1974
  // or unknown policy field is left for the server's strict validation.
1875
1975
  const effectiveFeatureBranch = resolveEffectiveFeatureBranch(featureBranch, requestedPolicy);
1976
+ // --- Typed merge-execution-mode declaration (BAPI-1133, A2) ---------------
1977
+ // Resolved ONCE, here, before either composer runs, so the composer functions
1978
+ // stay pure and synchronous. Gated on the exact predicate both composers'
1979
+ // OWN fill-if-absent branches use — `!attended`, a feature branch selected,
1980
+ // and (for the file path) no `posture` already declared — so this never
1981
+ // performs the new configuration read for `--attended` or `--into-base` runs,
1982
+ // and never for a file that already answered the posture question itself.
1983
+ const unattendedDefaultEligible = !opts.attended &&
1984
+ effectiveFeatureBranch !== undefined &&
1985
+ (requestedPolicy === undefined || !("posture" in requestedPolicy));
1986
+ let declaredMergeExecutionMode;
1987
+ if (unattendedDefaultEligible) {
1988
+ const mergeExecutionModeResolverDeps = {
1989
+ repoName: access.repoName,
1990
+ buildGetUrl: (path, params) => buildConductorJiraUrl(access.baseUrl, path, params),
1991
+ getHeaders: async () => conductorGetHeaders(access),
1992
+ fetchImpl: deps.fetch,
1993
+ };
1994
+ const effectiveLegacyMode = await resolveMergeExecutionMode(mergeExecutionModeResolverDeps);
1995
+ declaredMergeExecutionMode = mapLegacyMergeExecutionModeToPolicyMode(effectiveLegacyMode);
1996
+ }
1876
1997
  // --- The policy the CREATE path will send (BAPI-1102) ---------------------
1877
1998
  // Composed HERE, as soon as both of its inputs exist, so the one object that
1878
1999
  // gets reported, gated, and sent is the same object throughout. It is consumed
@@ -1883,12 +2004,30 @@ async function executeSetupEpic(argv, overrides, runIdSink) {
1883
2004
  ? applySetupEpicUnattendedDefault(requestedPolicy, {
1884
2005
  featureBranch: effectiveFeatureBranch,
1885
2006
  attended: opts.attended,
2007
+ mergeExecutionMode: declaredMergeExecutionMode,
1886
2008
  })
1887
2009
  : composeDefaultSetupEpicPolicy({
1888
2010
  featureBranch,
1889
2011
  attended: opts.attended,
1890
2012
  reviewPolicy: opts.reviewPolicy,
2013
+ mergeExecutionMode: declaredMergeExecutionMode,
1891
2014
  });
2015
+ // BAPI-1133 (A2). Reported only when THIS command stamped the key — i.e. it
2016
+ // is present in the composed policy and was absent from whatever the
2017
+ // operator supplied — as low-emphasis policy metadata, mirroring the
2018
+ // existing posture/auto-merge reporting rather than adding a new prompt,
2019
+ // wizard, or runtime status. An explicitly declared mode (CLI-composed
2020
+ // policy already carrying the key) is never reported here as if it were
2021
+ // this command's decision.
2022
+ const mergeExecutionModeStamped = declaredMergeExecutionMode !== undefined &&
2023
+ composedForCreate[SETUP_EPIC_MERGE_EXECUTION_MODE_POLICY_KEY] === declaredMergeExecutionMode &&
2024
+ (requestedPolicy === undefined ||
2025
+ !(SETUP_EPIC_MERGE_EXECUTION_MODE_POLICY_KEY in requestedPolicy));
2026
+ if (mergeExecutionModeStamped) {
2027
+ say(`Policy: merge_execution_mode: ${declaredMergeExecutionMode} (declared automatically ` +
2028
+ `for the unattended default; policy metadata only — no dispatch, actuation, eligibility, ` +
2029
+ `containment, or escalation behavior until a later A2 child)`);
2030
+ }
1892
2031
  if (requestedPolicy !== undefined) {
1893
2032
  // The posture is stated for the FILE path too, and read off the composed
1894
2033
  // object rather than re-derived. The `--policy-file` invocation is the one
@@ -2430,6 +2569,21 @@ async function executeSetupEpic(argv, overrides, runIdSink) {
2430
2569
  deps.errorLog(`setup-epic REFUSED (${bringUpRefusal.reason}): ${bringUpRefusal.message}`);
2431
2570
  return 1;
2432
2571
  }
2572
+ // BAPI-1135 — merge-execution eligibility, AFTER the universal bring-up
2573
+ // blockers (an unreadable readiness report and a behind database make this
2574
+ // question moot) and BEFORE the unattended prerequisites and every
2575
+ // approval check below. That position is what keeps readiness, this gate,
2576
+ // and the approval refusal naming the SAME first blocker.
2577
+ //
2578
+ // Outside the `requestedPolicyIsUnattended` branch on purpose: an
2579
+ // `--attended` run that declares `github_actions` mode is gated too. The
2580
+ // evaluator itself returns null for every policy that does not declare the
2581
+ // mode, so no other run's behavior changes.
2582
+ const mergeExecutionRefusal = evaluateSetupEpicMergeExecutionPrerequisites(readiness, composedForCreate);
2583
+ if (mergeExecutionRefusal !== null) {
2584
+ deps.errorLog(`setup-epic REFUSED (${mergeExecutionRefusal.reason}): ${mergeExecutionRefusal.message}`);
2585
+ return 1;
2586
+ }
2433
2587
  if (requestedPolicyIsUnattended(composedForCreate, opts.attended)) {
2434
2588
  // The COMPOSED policy, not the flags: a --policy-file declaring
2435
2589
  // notify.webhook_url satisfies the escalation-channel prerequisite, and
@@ -1,4 +1,4 @@
1
1
  // AUTO-GENERATED — do not edit manually. Regenerate with: npm run build
2
- export const VERSION = "0.2.59";
3
- export const BUILD_COMMIT = "6caab78d0b75";
4
- export const LAUNCHER_ARGS = ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.59", "serve"];
2
+ export const VERSION = "0.2.60";
3
+ export const BUILD_COMMIT = "1920a31997d2";
4
+ export const LAUNCHER_ARGS = ["-y", "--prefer-offline", "@bridge_gpt/mcp-server@0.2.60", "serve"];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bridge_gpt/mcp-server",
3
- "version": "0.2.59",
3
+ "version": "0.2.60",
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",
@@ -26,7 +26,7 @@
26
26
  "//test": "The `test` script delegates to the bounded launcher (scripts/run-unit-tests.js → src/run-unit-tests-launcher.ts, BAPI-683), which discovers build/*.test.js at runtime and spawns them in size-bounded batches so the argv never exceeds Windows' ~8191-char command-line limit. Two determinism rules from the pre-launcher script are preserved INSIDE the launcher: (1) multi-file batches run WITHOUT --test-force-exit, because that flag makes node:test exit before aggregating per-subprocess summaries and the tally becomes nondeterministic (failures still surface and still set exit 1, but the count cannot be trusted as a completeness signal); (2) build/secret-safety.test.js leaks a handle that holds the event loop ~60s after its tests finish (they run in ~147ms), so the launcher quarantines it into its own single-file --test-force-exit invocation (FORCE_EXIT_QUARANTINE in src/run-unit-tests-launcher.ts) where the tally stays exact. Do NOT add --test-force-exit to batched invocations, and do NOT remove the quarantine, until the underlying handle leak is fixed.",
27
27
  "//version": "BAPI-930: fired by `npm version <level>` AFTER npm rewrites package.json's version field, so the bumped version and the repinned README land in the SAME commit. A bump performed by hand-editing package.json instead of running `npm version` bypasses this hook entirely and must repin manually via `node scripts/sync-readme-host-examples.js` — the `--check` wired into `build` below is the backstop that catches that case.",
28
28
  "scripts": {
29
- "build": "node scripts/bundle-version.js && node scripts/sync-readme-host-examples.js --check && node scripts/validate-packaged-command-references.js && node scripts/bundle-readme.js && node scripts/bundle-pipelines.js && node scripts/bundle-commands.js && node scripts/bundle-agents.js && node scripts/bundle-docs.js && node scripts/bundle-agent-guidance.js && tsc && node scripts/sync-agent-mirrors.js && node scripts/bundle-esbuild.js",
29
+ "build": "node scripts/bundle-version.js && node scripts/sync-readme-host-examples.js --check && node scripts/validate-packaged-command-references.js && node scripts/bundle-readme.js && node scripts/bundle-pipelines.js && node scripts/bundle-commands.js && node scripts/bundle-agents.js && node scripts/bundle-docs.js && node scripts/bundle-agent-guidance.js && tsc && node scripts/sync-readme-merge-workflow.js --check && node scripts/sync-agent-mirrors.js && node scripts/bundle-esbuild.js",
30
30
  "version": "node scripts/sync-readme-host-examples.js --write && git add -- README.md package.json package-lock.json && git commit -m \"chore(mcp-server): release $npm_package_version\" && git tag \"mcp-server/v$npm_package_version\"",
31
31
  "check:version-generated": "node scripts/bundle-version.js && node scripts/check-version-generated.js",
32
32
  "assert:release-identity": "node scripts/assert-release-identity.js",
@@ -51,7 +51,7 @@
51
51
  "playwright": "^1.51.1"
52
52
  },
53
53
  "devDependencies": {
54
- "@types/better-sqlite3": "^7.6.12",
54
+ "@types/better-sqlite3": "^9.6.0",
55
55
  "@types/node": "^26.0.1",
56
56
  "@types/pngjs": "^6.0.5",
57
57
  "esbuild": "^0.28.1",