@bridge_gpt/mcp-server 0.2.26 → 0.2.27

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 (57) hide show
  1. package/build/commands.generated.js +1 -1
  2. package/build/conductor-bin.js +68 -9267
  3. package/build/conductor-claude-hook-bin.js +2 -172
  4. package/build/decision-page-template.js +2 -31
  5. package/build/index.js +4652 -37042
  6. package/build/init.js +80 -56
  7. package/build/install-bridge.js +36 -20
  8. package/build/version.generated.js +1 -1
  9. package/package.json +1 -3
  10. package/design-assets/favicon/android-chrome-192x192.png +0 -0
  11. package/design-assets/favicon/android-chrome-512x512.png +0 -0
  12. package/design-assets/favicon/apple-touch-icon.png +0 -0
  13. package/design-assets/favicon/favicon-16x16.png +0 -0
  14. package/design-assets/favicon/favicon.ico +0 -0
  15. package/design-assets/favicon/site.webmanifest +0 -1
  16. package/public/css/main.min.css +0 -4971
  17. package/public/css/main.min.css.map +0 -1
  18. package/public/fonts/OFL.txt +0 -93
  19. package/public/fonts/SourceSansPro-Black.ttf +0 -0
  20. package/public/fonts/SourceSansPro-BlackItalic.ttf +0 -0
  21. package/public/fonts/SourceSansPro-Bold.ttf +0 -0
  22. package/public/fonts/SourceSansPro-BoldItalic.ttf +0 -0
  23. package/public/fonts/SourceSansPro-ExtraLight.ttf +0 -0
  24. package/public/fonts/SourceSansPro-ExtraLightItalic.ttf +0 -0
  25. package/public/fonts/SourceSansPro-Italic.ttf +0 -0
  26. package/public/fonts/SourceSansPro-Light.ttf +0 -0
  27. package/public/fonts/SourceSansPro-LightItalic.ttf +0 -0
  28. package/public/fonts/SourceSansPro-Regular.ttf +0 -0
  29. package/public/fonts/SourceSansPro-SemiBold.ttf +0 -0
  30. package/public/fonts/SourceSansPro-SemiBoldItalic.ttf +0 -0
  31. package/public/img/bridge-logo-160x51.webp +0 -0
  32. package/public/img/bridge-logo-300x92.webp +0 -0
  33. package/public/img/favicon/android-chrome-192x192.png +0 -0
  34. package/public/img/favicon/android-chrome-512x512.png +0 -0
  35. package/public/img/favicon/apple-touch-icon.png +0 -0
  36. package/public/img/favicon/favicon-16x16.png +0 -0
  37. package/public/img/favicon/favicon-32x32.png +0 -0
  38. package/public/img/favicon/favicon.ico +0 -0
  39. package/public/img/favicon/site.webmanifest +0 -1
  40. package/public/img/installation/bitbucket/app-password-1.png +0 -0
  41. package/public/img/installation/bitbucket/app-password-2.png +0 -0
  42. package/public/img/installation/bitbucket/create-token-1.png +0 -0
  43. package/public/img/installation/bitbucket/create-token-2.png +0 -0
  44. package/public/img/installation/bitbucket/webhook-1.png +0 -0
  45. package/public/img/installation/github/github-review-webhook.png +0 -0
  46. package/public/img/installation/jira/credentials/api-key.png +0 -0
  47. package/public/img/installation/jira/webhook/create-rule.png +0 -0
  48. package/public/img/installation/jira/webhook/project-settings.png +0 -0
  49. package/public/img/installation/jira/webhook/rule-create-1.png +0 -0
  50. package/public/img/installation/jira/webhook/rule-create-2.png +0 -0
  51. package/public/img/installation/jira/webhook/rule-create-3.png +0 -0
  52. package/public/img/installation/pinecone/pinecone-api-key.png +0 -0
  53. package/public/img/installation/pinecone/pinecone-index.png +0 -0
  54. package/public/js/main.min.js +0 -10409
  55. package/public/js/main.min.js.map +0 -1
  56. package/smoke-test/SMOKE-TEST.md +0 -560
  57. package/smoke-test/smoke-test-mcp.md +0 -23
@@ -1,173 +1,3 @@
1
1
  #!/usr/bin/env node
2
-
3
- // src/conductor/claude-hook.ts
4
- import { spawnSync } from "node:child_process";
5
- import { readFileSync } from "node:fs";
6
- var CONDUCTOR_HOOK_EMIT_FAILED_WARNING = "Warning: conductor hook emit failed.";
7
- function resolveClaudeHookEventName(payload) {
8
- if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
9
- return null;
10
- }
11
- const record = payload;
12
- const candidates = ["hook_event_name", "hookEventName", "event_name", "event"];
13
- for (const key of candidates) {
14
- const value = record[key];
15
- if (typeof value === "string" && value.trim().length > 0) {
16
- return value.trim();
17
- }
18
- }
19
- return null;
20
- }
21
- function mapClaudeHookEventToSemanticType(eventName) {
22
- switch (eventName) {
23
- case "SessionStart":
24
- return "run.started";
25
- case "SessionEnd":
26
- return "run.stopped";
27
- case "Stop":
28
- return null;
29
- case "SubagentStop":
30
- return null;
31
- case "Notification":
32
- return "agent.notification";
33
- case "PreToolUse":
34
- return "tool.intent";
35
- default:
36
- return null;
37
- }
38
- }
39
- var REQUIRED_IDENTITY_ENV = [
40
- "BAPI_CONDUCTOR_RUN_ID",
41
- "BAPI_CONDUCTOR_WORKER_ID",
42
- "BAPI_CONDUCTOR_TICKET_KEY",
43
- "BAPI_CONDUCTOR_WORKTREE_PATH"
44
- ];
45
- function nonEmpty(value) {
46
- return typeof value === "string" && value.trim().length > 0;
47
- }
48
- function buildClaudeHookConductorEvent(payload, env) {
49
- const eventName = resolveClaudeHookEventName(payload);
50
- const type = mapClaudeHookEventToSemanticType(eventName);
51
- if (type === null) {
52
- return null;
53
- }
54
- if (env.BAPI_CONDUCTOR_ENABLED !== "1") {
55
- return null;
56
- }
57
- for (const key of REQUIRED_IDENTITY_ENV) {
58
- if (!nonEmpty(env[key])) {
59
- return null;
60
- }
61
- }
62
- const ticketKey = env.BAPI_CONDUCTOR_TICKET_KEY.trim();
63
- const worktreePath = env.BAPI_CONDUCTOR_WORKTREE_PATH.trim();
64
- const details = {
65
- ticket_key: ticketKey,
66
- worktree_path: worktreePath
67
- };
68
- if (nonEmpty(env.BAPI_CONDUCTOR_REPO_NAME)) {
69
- details.repo = env.BAPI_CONDUCTOR_REPO_NAME.trim();
70
- }
71
- const raw = payload !== null && typeof payload === "object" && !Array.isArray(payload) ? payload : { payload };
72
- return {
73
- source: "claude-code",
74
- type,
75
- subject: ticketKey,
76
- run_id: env.BAPI_CONDUCTOR_RUN_ID.trim(),
77
- worker_id: env.BAPI_CONDUCTOR_WORKER_ID.trim(),
78
- producer: "claude-code-hook",
79
- observed_via: "claude-code-hook",
80
- data: {
81
- details,
82
- raw
83
- }
84
- };
85
- }
86
- function buildConductorEmitEventArgs(event) {
87
- const args = ["--type", event.type, "--source", event.source];
88
- if (nonEmpty(event.subject ?? void 0)) args.push("--subject", event.subject);
89
- if (nonEmpty(event.run_id ?? void 0)) args.push("--run-id", event.run_id);
90
- if (nonEmpty(event.worker_id ?? void 0)) args.push("--worker-id", event.worker_id);
91
- if (nonEmpty(event.producer ?? void 0)) args.push("--producer", event.producer);
92
- if (nonEmpty(event.observed_via ?? void 0)) {
93
- args.push("--observed-via", event.observed_via);
94
- }
95
- args.push("--data-json-stdin", "--json");
96
- return args;
97
- }
98
- function resolveConductorEmitCommand(env, emitArgs) {
99
- const cliFile = env.BAPI_CONDUCTOR_CLI_FILE;
100
- if (nonEmpty(cliFile)) {
101
- return {
102
- command: process.execPath,
103
- args: [cliFile.trim(), "emit-event", ...emitArgs]
104
- };
105
- }
106
- const bin = nonEmpty(env.BAPI_CONDUCTOR_BIN) ? env.BAPI_CONDUCTOR_BIN.trim() : "conductor";
107
- return { command: bin, args: ["emit-event", ...emitArgs] };
108
- }
109
- var defaultConductorSpawn = (command, args, input) => {
110
- const result = spawnSync(command, args, {
111
- input,
112
- encoding: "utf-8",
113
- // Never use a shell: list args + stdin keep raw payloads/secrets out of any
114
- // shell-interpreted command string.
115
- shell: false
116
- });
117
- return { status: result.status, error: result.error };
118
- };
119
- function emitClaudeHookEventWithConductorCli(event, deps = {}) {
120
- const env = deps.env ?? process.env;
121
- const spawn = deps.spawn ?? defaultConductorSpawn;
122
- const emitArgs = buildConductorEmitEventArgs(event);
123
- const { command, args } = resolveConductorEmitCommand(env, emitArgs);
124
- const stdinPayload = JSON.stringify(event.data ?? {});
125
- try {
126
- const result = spawn(command, args, stdinPayload);
127
- if (result.error) return false;
128
- return result.status === 0;
129
- } catch {
130
- return false;
131
- }
132
- }
133
- function runClaudeConductorHookCli(deps = {}) {
134
- const env = deps.env ?? process.env;
135
- const readStdin = deps.readStdin ?? (() => readStdinSync());
136
- const warn = deps.warn ?? ((m) => process.stderr.write(`${m}
137
- `));
138
- let payload;
139
- try {
140
- const raw = readStdin();
141
- payload = JSON.parse(raw);
142
- } catch {
143
- warn(CONDUCTOR_HOOK_EMIT_FAILED_WARNING);
144
- return 0;
145
- }
146
- let event;
147
- try {
148
- event = buildClaudeHookConductorEvent(payload, env);
149
- } catch {
150
- warn(CONDUCTOR_HOOK_EMIT_FAILED_WARNING);
151
- return 0;
152
- }
153
- if (event === null) {
154
- return 0;
155
- }
156
- const ok = emitClaudeHookEventWithConductorCli(event, { env, spawn: deps.spawn });
157
- if (!ok) {
158
- warn(CONDUCTOR_HOOK_EMIT_FAILED_WARNING);
159
- }
160
- return 0;
161
- }
162
- function readStdinSync() {
163
- return readFileSync(0, "utf-8");
164
- }
165
-
166
- // src/conductor-claude-hook-bin.ts
167
- var exitCode = 0;
168
- try {
169
- exitCode = runClaudeConductorHookCli();
170
- } catch {
171
- exitCode = 0;
172
- }
173
- process.exit(exitCode);
2
+ import{spawnSync}from"node:child_process";import{readFileSync}from"node:fs";var CONDUCTOR_HOOK_EMIT_FAILED_WARNING="Warning: conductor hook emit failed.";function resolveClaudeHookEventName(payload){if(payload===null||typeof payload!="object"||Array.isArray(payload))return null;let record=payload,candidates=["hook_event_name","hookEventName","event_name","event"];for(let key of candidates){let value=record[key];if(typeof value=="string"&&value.trim().length>0)return value.trim()}return null}function mapClaudeHookEventToSemanticType(eventName){switch(eventName){case"SessionStart":return"run.started";case"SessionEnd":return"run.stopped";case"Stop":return null;case"SubagentStop":return null;case"Notification":return"agent.notification";case"PreToolUse":return"tool.intent";default:return null}}var REQUIRED_IDENTITY_ENV=["BAPI_CONDUCTOR_RUN_ID","BAPI_CONDUCTOR_WORKER_ID","BAPI_CONDUCTOR_TICKET_KEY","BAPI_CONDUCTOR_WORKTREE_PATH"];function nonEmpty(value){return typeof value=="string"&&value.trim().length>0}function buildClaudeHookConductorEvent(payload,env){let eventName=resolveClaudeHookEventName(payload),type=mapClaudeHookEventToSemanticType(eventName);if(type===null||env.BAPI_CONDUCTOR_ENABLED!=="1")return null;for(let key of REQUIRED_IDENTITY_ENV)if(!nonEmpty(env[key]))return null;let ticketKey=env.BAPI_CONDUCTOR_TICKET_KEY.trim(),worktreePath=env.BAPI_CONDUCTOR_WORKTREE_PATH.trim(),details={ticket_key:ticketKey,worktree_path:worktreePath};nonEmpty(env.BAPI_CONDUCTOR_REPO_NAME)&&(details.repo=env.BAPI_CONDUCTOR_REPO_NAME.trim());let raw=payload!==null&&typeof payload=="object"&&!Array.isArray(payload)?payload:{payload};return{source:"claude-code",type,subject:ticketKey,run_id:env.BAPI_CONDUCTOR_RUN_ID.trim(),worker_id:env.BAPI_CONDUCTOR_WORKER_ID.trim(),producer:"claude-code-hook",observed_via:"claude-code-hook",data:{details,raw}}}function buildConductorEmitEventArgs(event){let args=["--type",event.type,"--source",event.source];return nonEmpty(event.subject??void 0)&&args.push("--subject",event.subject),nonEmpty(event.run_id??void 0)&&args.push("--run-id",event.run_id),nonEmpty(event.worker_id??void 0)&&args.push("--worker-id",event.worker_id),nonEmpty(event.producer??void 0)&&args.push("--producer",event.producer),nonEmpty(event.observed_via??void 0)&&args.push("--observed-via",event.observed_via),args.push("--data-json-stdin","--json"),args}function resolveConductorEmitCommand(env,emitArgs){let cliFile=env.BAPI_CONDUCTOR_CLI_FILE;return nonEmpty(cliFile)?{command:process.execPath,args:[cliFile.trim(),"emit-event",...emitArgs]}:{command:nonEmpty(env.BAPI_CONDUCTOR_BIN)?env.BAPI_CONDUCTOR_BIN.trim():"conductor",args:["emit-event",...emitArgs]}}var defaultConductorSpawn=(command,args,input)=>{let result=spawnSync(command,args,{input,encoding:"utf-8",shell:!1});return{status:result.status,error:result.error}};function emitClaudeHookEventWithConductorCli(event,deps={}){let env=deps.env??process.env,spawn=deps.spawn??defaultConductorSpawn,emitArgs=buildConductorEmitEventArgs(event),{command,args}=resolveConductorEmitCommand(env,emitArgs),stdinPayload=JSON.stringify(event.data??{});try{let result=spawn(command,args,stdinPayload);return result.error?!1:result.status===0}catch{return!1}}function runClaudeConductorHookCli(deps={}){let env=deps.env??process.env,readStdin=deps.readStdin??(()=>readStdinSync()),warn=deps.warn??(m=>process.stderr.write(`${m}
3
+ `)),payload;try{let raw=readStdin();payload=JSON.parse(raw)}catch{return warn(CONDUCTOR_HOOK_EMIT_FAILED_WARNING),0}let event;try{event=buildClaudeHookConductorEvent(payload,env)}catch{return warn(CONDUCTOR_HOOK_EMIT_FAILED_WARNING),0}return event===null||emitClaudeHookEventWithConductorCli(event,{env,spawn:deps.spawn})||warn(CONDUCTOR_HOOK_EMIT_FAILED_WARNING),0}function readStdinSync(){return readFileSync(0,"utf-8")}var exitCode=0;try{exitCode=runClaudeConductorHookCli()}catch{exitCode=0}process.exit(exitCode);
@@ -59,7 +59,7 @@ function hasDisplayText(value) {
59
59
  // ---------------------------------------------------------------------------
60
60
  // Template
61
61
  // ---------------------------------------------------------------------------
62
- const DEFAULT_ASSETS = { faviconBase64: "", logoBase64: "", fontsRelPath: "" };
62
+ const DEFAULT_ASSETS = { faviconBase64: "", logoBase64: "" };
63
63
  export function generateDecisionPageHtml(data, assets = DEFAULT_ASSETS) {
64
64
  const { ticket_key, actionable_items, clear_improvements } = data;
65
65
  const hasDecisions = actionable_items.length > 0;
@@ -73,7 +73,6 @@ export function generateDecisionPageHtml(data, assets = DEFAULT_ASSETS) {
73
73
  const faviconLink = assets.faviconBase64
74
74
  ? `<link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,${assets.faviconBase64}">`
75
75
  : "";
76
- const fontFaces = assets.fontsRelPath ? renderFontFaces(assets.fontsRelPath) : "";
77
76
  // The has-decisions intro is an overridable label; the no-decisions copy is a
78
77
  // fixed constant. For review_decisions pages the MCP handler short-circuits
79
78
  // before rendering when there are no decisions, so that branch is reachable
@@ -93,7 +92,6 @@ export function generateDecisionPageHtml(data, assets = DEFAULT_ASSETS) {
93
92
  <title>${escapeHtml(effectiveLabels.title)}: ${escapeHtml(ticket_key)}</title>
94
93
  ${faviconLink}
95
94
  <style>
96
- ${fontFaces}
97
95
  :root {
98
96
  --primary-color: #E2624B;
99
97
  --primary-dark: #C51616;
@@ -112,7 +110,7 @@ ${fontFaces}
112
110
  }
113
111
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
114
112
  body {
115
- font-family: 'Source Sans Pro', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
113
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
116
114
  background-color: var(--background-color);
117
115
  color: var(--text-color);
118
116
  line-height: 1.5;
@@ -541,33 +539,6 @@ ${needsForm ? renderScript(data, isPlanning) : ""}
541
539
  </html>`;
542
540
  }
543
541
  // ---------------------------------------------------------------------------
544
- // Font faces
545
- // ---------------------------------------------------------------------------
546
- // fontsRelPath comes from server-controlled env vars, so this is not an
547
- // injection vector — but a deploy path containing a single quote or backslash
548
- // would silently break CSS parsing and stop fonts from loading. Escape both
549
- // so the url('...') stays well-formed regardless of deploy layout.
550
- function escapeCssUrl(value) {
551
- return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
552
- }
553
- function renderFontFaces(fontsRelPath) {
554
- const weights = [
555
- { weight: "400", style: "normal", file: "SourceSansPro-Regular.ttf" },
556
- { weight: "400", style: "italic", file: "SourceSansPro-Italic.ttf" },
557
- { weight: "600", style: "normal", file: "SourceSansPro-SemiBold.ttf" },
558
- { weight: "600", style: "italic", file: "SourceSansPro-SemiBoldItalic.ttf" },
559
- { weight: "700", style: "normal", file: "SourceSansPro-Bold.ttf" },
560
- { weight: "700", style: "italic", file: "SourceSansPro-BoldItalic.ttf" },
561
- ];
562
- const safePath = escapeCssUrl(fontsRelPath);
563
- return weights.map(({ weight, style, file }) => ` @font-face {
564
- font-family: 'Source Sans Pro';
565
- src: url('${safePath}/${escapeCssUrl(file)}') format('truetype');
566
- font-weight: ${weight};
567
- font-style: ${style};
568
- }`).join("\n");
569
- }
570
- // ---------------------------------------------------------------------------
571
542
  // Section renderers
572
543
  // ---------------------------------------------------------------------------
573
544
  function renderHeader(assets) {