@bridge_gpt/mcp-server 0.2.26 → 0.2.28

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 (70) hide show
  1. package/README.md +32 -24
  2. package/build/commands.generated.js +2 -2
  3. package/build/conductor/bridge-api-client.js +98 -1
  4. package/build/conductor/epic-reconcile.js +28 -0
  5. package/build/conductor/epic-runtime.js +28 -1
  6. package/build/conductor-bin.js +68 -9267
  7. package/build/conductor-claude-hook-bin.js +2 -172
  8. package/build/connect-github-api.js +9 -0
  9. package/build/connect-github.js +10 -0
  10. package/build/decision-page-template.js +2 -31
  11. package/build/doctor.js +2 -2
  12. package/build/env-flags.js +23 -0
  13. package/build/index.js +4699 -37043
  14. package/build/init.js +80 -56
  15. package/build/install-bridge.js +451 -153
  16. package/build/mcp-host-targets.js +12 -0
  17. package/build/readme.generated.js +1 -1
  18. package/build/setup-epic.js +198 -4
  19. package/build/start-tickets.js +25 -4
  20. package/build/tool-surface-gating.js +13 -2
  21. package/build/version.generated.js +1 -1
  22. package/package.json +3 -5
  23. package/design-assets/favicon/android-chrome-192x192.png +0 -0
  24. package/design-assets/favicon/android-chrome-512x512.png +0 -0
  25. package/design-assets/favicon/apple-touch-icon.png +0 -0
  26. package/design-assets/favicon/favicon-16x16.png +0 -0
  27. package/design-assets/favicon/favicon.ico +0 -0
  28. package/design-assets/favicon/site.webmanifest +0 -1
  29. package/public/css/main.min.css +0 -4971
  30. package/public/css/main.min.css.map +0 -1
  31. package/public/fonts/OFL.txt +0 -93
  32. package/public/fonts/SourceSansPro-Black.ttf +0 -0
  33. package/public/fonts/SourceSansPro-BlackItalic.ttf +0 -0
  34. package/public/fonts/SourceSansPro-Bold.ttf +0 -0
  35. package/public/fonts/SourceSansPro-BoldItalic.ttf +0 -0
  36. package/public/fonts/SourceSansPro-ExtraLight.ttf +0 -0
  37. package/public/fonts/SourceSansPro-ExtraLightItalic.ttf +0 -0
  38. package/public/fonts/SourceSansPro-Italic.ttf +0 -0
  39. package/public/fonts/SourceSansPro-Light.ttf +0 -0
  40. package/public/fonts/SourceSansPro-LightItalic.ttf +0 -0
  41. package/public/fonts/SourceSansPro-Regular.ttf +0 -0
  42. package/public/fonts/SourceSansPro-SemiBold.ttf +0 -0
  43. package/public/fonts/SourceSansPro-SemiBoldItalic.ttf +0 -0
  44. package/public/img/bridge-logo-160x51.webp +0 -0
  45. package/public/img/bridge-logo-300x92.webp +0 -0
  46. package/public/img/favicon/android-chrome-192x192.png +0 -0
  47. package/public/img/favicon/android-chrome-512x512.png +0 -0
  48. package/public/img/favicon/apple-touch-icon.png +0 -0
  49. package/public/img/favicon/favicon-16x16.png +0 -0
  50. package/public/img/favicon/favicon-32x32.png +0 -0
  51. package/public/img/favicon/favicon.ico +0 -0
  52. package/public/img/favicon/site.webmanifest +0 -1
  53. package/public/img/installation/bitbucket/app-password-1.png +0 -0
  54. package/public/img/installation/bitbucket/app-password-2.png +0 -0
  55. package/public/img/installation/bitbucket/create-token-1.png +0 -0
  56. package/public/img/installation/bitbucket/create-token-2.png +0 -0
  57. package/public/img/installation/bitbucket/webhook-1.png +0 -0
  58. package/public/img/installation/github/github-review-webhook.png +0 -0
  59. package/public/img/installation/jira/credentials/api-key.png +0 -0
  60. package/public/img/installation/jira/webhook/create-rule.png +0 -0
  61. package/public/img/installation/jira/webhook/project-settings.png +0 -0
  62. package/public/img/installation/jira/webhook/rule-create-1.png +0 -0
  63. package/public/img/installation/jira/webhook/rule-create-2.png +0 -0
  64. package/public/img/installation/jira/webhook/rule-create-3.png +0 -0
  65. package/public/img/installation/pinecone/pinecone-api-key.png +0 -0
  66. package/public/img/installation/pinecone/pinecone-index.png +0 -0
  67. package/public/js/main.min.js +0 -10409
  68. package/public/js/main.min.js.map +0 -1
  69. package/smoke-test/SMOKE-TEST.md +0 -560
  70. package/smoke-test/smoke-test-mcp.md +0 -23
package/build/init.js CHANGED
@@ -33,9 +33,16 @@ export function buildBridgeApiEntry(cwd) {
33
33
  // where 0.2.6 persisted despite an upgrade). Pinning keeps the running
34
34
  // configuration predictable and visible in version control. The `install-bridge`
35
35
  // config write reuses this same entry so both install paths agree.
36
+ //
37
+ // `--prefer-offline` makes npx resolve the (immutable, exact-pinned) version
38
+ // from the local npm cache and skip the redundant registry-metadata round-trip
39
+ // on every boot, only hitting the network on a genuine cache miss (unlike
40
+ // `--offline`, it falls back automatically). It cannot resurrect a stale build
41
+ // — the BAPI-429 hazard above was specific to UNPINNED specs; here the exact
42
+ // `@${VERSION}` is immutable, so a cache hit is always the right build.
36
43
  return {
37
44
  command: "npx",
38
- args: ["-y", `@bridge_gpt/mcp-server@${VERSION}`],
45
+ args: ["-y", "--prefer-offline", `@bridge_gpt/mcp-server@${VERSION}`],
39
46
  env: {
40
47
  BAPI_BASE_URL: "https://bridgegpt-api.com",
41
48
  BAPI_REPO_NAME: "YOUR_REPO_NAME",
@@ -143,6 +150,32 @@ async function ensureGitignored(cwd, filePath) {
143
150
  mkdir: (p, options) => mkdir(p, options),
144
151
  });
145
152
  }
153
+ /**
154
+ * Read-compare-write a single scaffold file. Returns "skipped" when the target
155
+ * already holds identical bytes (no write), "overwritten" when it existed with
156
+ * different bytes, and "written" when it was absent. Optionally ensures `mkdirDir`
157
+ * exists first (used by the DOCS phase, whose targets span different subdirs).
158
+ *
159
+ * Extracted so the COMMANDS/DOCS/AGENTS phases can run their per-file work
160
+ * concurrently via Promise.all instead of one-await-at-a-time: on a slow disk the
161
+ * sequential syscalls dominated `runInit`. The caller applies each outcome to its
162
+ * summary Sets AFTER the batch, iterating the ordered results, so behavior and
163
+ * console output are byte-for-byte identical to the sequential version.
164
+ */
165
+ async function scaffoldFile(target, content, mkdirDir) {
166
+ if (mkdirDir !== undefined)
167
+ await mkdir(mkdirDir, { recursive: true });
168
+ let existed = false;
169
+ try {
170
+ const existing = await readFile(target, "utf-8");
171
+ if (existing === content)
172
+ return "skipped";
173
+ existed = true;
174
+ }
175
+ catch { /* file doesn't exist */ }
176
+ await writeFile(target, content, "utf-8");
177
+ return existed ? "overwritten" : "written";
178
+ }
146
179
  /**
147
180
  * Core initialization logic shared by --init and --upgrade.
148
181
  * Runs all scaffolding phases without calling process.exit().
@@ -272,22 +305,22 @@ export async function runInit(cwd) {
272
305
  const writtenFiles = new Set();
273
306
  const skippedFiles = new Set();
274
307
  const overwrittenFiles = new Set();
308
+ const commandEntries = Object.entries(COMMANDS);
275
309
  for (const dir of commandDirs) {
276
310
  await mkdir(dir, { recursive: true });
277
- for (const [filename, content] of Object.entries(COMMANDS)) {
278
- const target = path.join(dir, filename);
279
- try {
280
- const existing = await readFile(target, "utf-8");
281
- if (existing === content) {
282
- skippedFiles.add(filename);
283
- continue;
284
- }
285
- overwrittenFiles.add(filename);
311
+ // Per-file read/compare/write runs concurrently; outcomes are applied to the
312
+ // Sets afterward in entry order so the summary counts are unchanged.
313
+ const outcomes = await Promise.all(commandEntries.map(([filename, content]) => scaffoldFile(path.join(dir, filename), content)));
314
+ commandEntries.forEach(([filename], i) => {
315
+ const outcome = outcomes[i];
316
+ if (outcome === "skipped") {
317
+ skippedFiles.add(filename);
318
+ return;
286
319
  }
287
- catch { /* file doesn't exist */ }
288
- await writeFile(target, content, "utf-8");
320
+ if (outcome === "overwritten")
321
+ overwrittenFiles.add(filename);
289
322
  writtenFiles.add(filename);
290
- }
323
+ });
291
324
  }
292
325
  // A file written in any directory takes priority over skipped
293
326
  for (const f of writtenFiles)
@@ -312,20 +345,21 @@ export async function runInit(cwd) {
312
345
  // project root; content is never secret.
313
346
  const docsWritten = new Set();
314
347
  const docsSkipped = new Set();
315
- for (const [relTarget, content] of Object.entries(DOCS)) {
348
+ const docEntries = Object.entries(DOCS);
349
+ // Each doc target may live in a different subdir, so mkdir(dirname) happens
350
+ // per-file inside scaffoldFile. Outcomes applied in entry order below preserve
351
+ // the insertion order of the joined summary list.
352
+ const docOutcomes = await Promise.all(docEntries.map(([relTarget, content]) => {
316
353
  const target = path.join(cwd, relTarget);
317
- await mkdir(path.dirname(target), { recursive: true });
318
- try {
319
- const existing = await readFile(target, "utf-8");
320
- if (existing === content) {
321
- docsSkipped.add(relTarget);
322
- continue;
323
- }
324
- }
325
- catch { /* file doesn't exist */ }
326
- await writeFile(target, content, "utf-8");
327
- docsWritten.add(relTarget);
328
- }
354
+ return scaffoldFile(target, content, path.dirname(target));
355
+ }));
356
+ docEntries.forEach(([relTarget], i) => {
357
+ // DOCS tracks only written vs skipped; an overwrite counts as written.
358
+ if (docOutcomes[i] === "skipped")
359
+ docsSkipped.add(relTarget);
360
+ else
361
+ docsWritten.add(relTarget);
362
+ });
329
363
  const docsTotal = Object.keys(DOCS).length;
330
364
  if (docsTotal > 0) {
331
365
  console.log(`\nDocumentation: scaffolded ${docsTotal} doc asset${docsTotal === 1 ? "" : "s"}`);
@@ -341,42 +375,32 @@ export async function runInit(cwd) {
341
375
  // Always scaffold to .claude/agents/
342
376
  const claudeAgentsDir = path.join(cwd, ".claude", "agents");
343
377
  await mkdir(claudeAgentsDir, { recursive: true });
344
- for (const [key, agent] of Object.entries(AGENTS)) {
345
- const filename = `${key}.md`;
346
- const content = reconstructAgentMarkdown(agent.frontmatter, agent.body);
347
- const target = path.join(claudeAgentsDir, filename);
348
- try {
349
- const existing = await readFile(target, "utf-8");
350
- if (existing === content) {
378
+ const agentEntries = Object.entries(AGENTS);
379
+ // Apply a batch of ordered outcomes to the agent Sets (same branches as the
380
+ // original per-file loop: skipped → skipped; overwritten → overwritten+written;
381
+ // written written).
382
+ const applyAgentOutcomes = (filenames, outcomes) => {
383
+ filenames.forEach((filename, i) => {
384
+ const outcome = outcomes[i];
385
+ if (outcome === "skipped") {
351
386
  agentSkipped.add(filename);
352
- continue;
387
+ return;
353
388
  }
354
- agentOverwritten.add(filename);
355
- }
356
- catch { /* file doesn't exist */ }
357
- await writeFile(target, content, "utf-8");
358
- agentWritten.add(filename);
359
- }
389
+ if (outcome === "overwritten")
390
+ agentOverwritten.add(filename);
391
+ agentWritten.add(filename);
392
+ });
393
+ };
394
+ const claudeAgentFilenames = agentEntries.map(([key]) => `${key}.md`);
395
+ const claudeAgentOutcomes = await Promise.all(agentEntries.map(([key, agent]) => scaffoldFile(path.join(claudeAgentsDir, `${key}.md`), reconstructAgentMarkdown(agent.frontmatter, agent.body))));
396
+ applyAgentOutcomes(claudeAgentFilenames, claudeAgentOutcomes);
360
397
  // Scaffold to .github/agents/ for VS Code / Copilot
361
398
  if (ideDetection.vscode) {
362
399
  const copilotAgentsDir = path.join(cwd, ".github", "agents");
363
400
  await mkdir(copilotAgentsDir, { recursive: true });
364
- for (const [key, agent] of Object.entries(AGENTS)) {
365
- const filename = `${key}.agent.md`;
366
- const content = translateAgentToCopilot(agent.frontmatter, agent.body);
367
- const target = path.join(copilotAgentsDir, filename);
368
- try {
369
- const existing = await readFile(target, "utf-8");
370
- if (existing === content) {
371
- agentSkipped.add(filename);
372
- continue;
373
- }
374
- agentOverwritten.add(filename);
375
- }
376
- catch { /* file doesn't exist */ }
377
- await writeFile(target, content, "utf-8");
378
- agentWritten.add(filename);
379
- }
401
+ const copilotAgentFilenames = agentEntries.map(([key]) => `${key}.agent.md`);
402
+ const copilotAgentOutcomes = await Promise.all(agentEntries.map(([key, agent]) => scaffoldFile(path.join(copilotAgentsDir, `${key}.agent.md`), translateAgentToCopilot(agent.frontmatter, agent.body))));
403
+ applyAgentOutcomes(copilotAgentFilenames, copilotAgentOutcomes);
380
404
  }
381
405
  // TODO: Add Cursor agent scaffolding when Cursor publishes a formal agent spec
382
406
  // A file written in any directory takes priority over skipped