@productbrain/mcp 0.0.1-beta.10 → 0.0.1-beta.1000

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.
@@ -1,92 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ MCP_NPX_PACKAGE,
3
4
  initAnalytics,
5
+ resolveClient,
4
6
  shutdownAnalytics,
5
7
  trackSetupCompleted,
6
- trackSetupStarted
7
- } from "./chunk-XBMI6QHR.js";
8
+ trackSetupStarted,
9
+ writeClientConfig
10
+ } from "./chunk-YMF3IQ5E.js";
8
11
 
9
12
  // src/cli/setup.ts
10
13
  import { execSync } from "child_process";
11
14
  import { createInterface } from "readline";
12
- import { existsSync as existsSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
13
- import { join as join2 } from "path";
14
-
15
- // src/cli/config-writer.ts
16
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
17
- import { join, dirname } from "path";
18
- import { homedir, platform } from "os";
19
- var SERVER_ENTRY_KEY = "Product Brain";
20
- var LEGACY_ENTRY_KEY = "productbrain";
21
- function buildServerEntry(apiKey) {
22
- return {
23
- command: "npx",
24
- args: ["-y", "@productbrain/mcp@beta"],
25
- env: { PRODUCTBRAIN_API_KEY: apiKey }
26
- };
27
- }
28
- function getCursorConfigPath() {
29
- return join(process.cwd(), ".cursor", "mcp.json");
30
- }
31
- function getClaudeDesktopConfigPath() {
32
- const os = platform();
33
- if (os === "darwin") {
34
- return join(
35
- homedir(),
36
- "Library",
37
- "Application Support",
38
- "Claude",
39
- "claude_desktop_config.json"
40
- );
41
- }
42
- if (os === "win32") {
43
- const appData = process.env.APPDATA ?? join(homedir(), "AppData", "Roaming");
44
- return join(appData, "Claude", "claude_desktop_config.json");
45
- }
46
- return null;
47
- }
48
- function resolveClient(name) {
49
- if (name === "Cursor") {
50
- return { name, configPath: getCursorConfigPath() };
51
- }
52
- const configPath = getClaudeDesktopConfigPath();
53
- return configPath ? { name, configPath } : null;
54
- }
55
- function readJsonSafe(path) {
56
- if (!existsSync(path)) return {};
57
- try {
58
- return JSON.parse(readFileSync(path, "utf-8"));
59
- } catch {
60
- return {};
61
- }
62
- }
63
- async function writeClientConfig(client, apiKey) {
64
- const config = readJsonSafe(client.configPath);
65
- const serversKey = "mcpServers";
66
- if (!config[serversKey]) config[serversKey] = {};
67
- if (config[serversKey][SERVER_ENTRY_KEY]) {
68
- return false;
69
- }
70
- if (config[serversKey][LEGACY_ENTRY_KEY]) {
71
- const legacy = config[serversKey][LEGACY_ENTRY_KEY];
72
- config[serversKey][SERVER_ENTRY_KEY] = {
73
- ...buildServerEntry(apiKey),
74
- env: { ...legacy.env, PRODUCTBRAIN_API_KEY: legacy.env?.PRODUCTBRAIN_API_KEY ?? apiKey }
75
- };
76
- delete config[serversKey][LEGACY_ENTRY_KEY];
77
- } else {
78
- config[serversKey][SERVER_ENTRY_KEY] = buildServerEntry(apiKey);
79
- }
80
- const dir = dirname(client.configPath);
81
- if (!existsSync(dir)) {
82
- mkdirSync(dir, { recursive: true });
83
- }
84
- writeFileSync(client.configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
85
- return true;
86
- }
87
-
88
- // src/cli/setup.ts
89
- var APP_URL = process.env.PRODUCTBRAIN_APP_URL ?? "https://productbrain.io";
15
+ import { existsSync, writeFileSync, mkdirSync } from "fs";
16
+ import { join } from "path";
17
+ var APP_URL = process.env.PRODUCTBRAIN_APP_URL ?? "https://work.productbrain.io";
90
18
  function bold(s) {
91
19
  return `\x1B[1m${s}\x1B[0m`;
92
20
  }
@@ -104,10 +32,10 @@ function log(msg) {
104
32
  `);
105
33
  }
106
34
  function openBrowser(url) {
107
- const platform2 = process.platform;
35
+ const platform = process.platform;
108
36
  try {
109
- if (platform2 === "darwin") execSync(`open "${url}"`);
110
- else if (platform2 === "win32") execSync(`start "" "${url}"`);
37
+ if (platform === "darwin") execSync(`open "${url}"`);
38
+ else if (platform === "win32") execSync(`start "" "${url}"`);
111
39
  else execSync(`xdg-open "${url}"`);
112
40
  } catch {
113
41
  log(dim(` Could not open browser automatically.`));
@@ -141,6 +69,25 @@ function promptChoice(question, choices) {
141
69
  });
142
70
  });
143
71
  }
72
+ var DEFAULT_CLOUD_URL = "https://gateway.productbrain.io";
73
+ async function verifyWorkspace(apiKey) {
74
+ const siteUrl = process.env.CONVEX_SITE_URL ?? process.env.PRODUCTBRAIN_URL ?? DEFAULT_CLOUD_URL;
75
+ try {
76
+ const res = await fetch(`${siteUrl.replace(/\/$/, "")}/api/aki`, {
77
+ method: "POST",
78
+ headers: {
79
+ "Content-Type": "application/json",
80
+ Authorization: `Bearer ${apiKey}`
81
+ },
82
+ body: JSON.stringify({ fn: "resolveWorkspace", args: {} })
83
+ });
84
+ if (!res.ok) return null;
85
+ const json = await res.json();
86
+ return json.data ?? null;
87
+ } catch {
88
+ return null;
89
+ }
90
+ }
144
91
  async function runSetup() {
145
92
  initAnalytics();
146
93
  trackSetupStarted();
@@ -165,8 +112,14 @@ async function runSetup() {
165
112
  await shutdownAnalytics();
166
113
  process.exit(1);
167
114
  }
168
- log(` ${green("\u2713")} Key received
169
- `);
115
+ log(` ${green("\u2713")} Key received`);
116
+ const workspace = await verifyWorkspace(apiKey);
117
+ if (workspace) {
118
+ log(` ${green("\u2713")} Connected to workspace: ${bold(workspace.name)} ${dim(`(${workspace.slug})`)}`);
119
+ } else {
120
+ log(` ${orange("!")} Could not verify workspace. Check your key at ${apiKeysUrl}`);
121
+ }
122
+ log("");
170
123
  const CLIENT_NAMES = ["Cursor", "Claude Desktop"];
171
124
  const options = [...CLIENT_NAMES, "Other"];
172
125
  const choice = await promptChoice("Where do you want to set up Product Brain?", options);
@@ -226,7 +179,7 @@ function printConfigSnippet(apiKey) {
226
179
  mcpServers: {
227
180
  "Product Brain": {
228
181
  command: "npx",
229
- args: ["-y", "@productbrain/mcp@beta"],
182
+ args: ["-y", MCP_NPX_PACKAGE],
230
183
  env: { PRODUCTBRAIN_API_KEY: apiKey }
231
184
  }
232
185
  }
@@ -262,22 +215,35 @@ Say **"Start PB"** or **"Start Product Brain"** to begin. This single call:
262
215
 
263
216
  ## Tool Workflow
264
217
 
265
- 1. **Start here**: \`orient\` or \`start\` \u2014 workspace context + next action
266
- 2. **Search**: \`search\` \u2014 find entries across all collections
267
- 3. **Drill in**: \`get-entry\` \u2014 full record with data, labels, relations
268
- 4. **Context**: \`gather-context\` \u2014 related knowledge around an entry or task
269
- 5. **Capture**: \`capture\` \u2014 create a draft with auto-linking + quality score
270
- 6. **Commit**: \`commit-entry\` \u2014 promote draft to SSOT (only when user confirms)
271
- 7. **Connect**: \`suggest-links\` then \`relate-entries\` to build the graph
218
+ 1. **Start here**: \`start\` \u2014 workspace context + next action
219
+ 2. **Search**: \`entries action=search\` \u2014 find entries across all collections
220
+ 3. **Drill in**: \`entries action=get\` \u2014 full record with data, labels, relations
221
+ 4. **Context**: \`context action=gather\` \u2014 related knowledge around an entry or task
222
+ 5. **Capture**: \`capture\` \u2014 create knowledge with auto-linking + quality score
223
+ 6. **Commit**: \`commit-entry\` \u2014 promote drafts to SSOT when confirmation is still required
224
+ 7. **Connect**: \`graph action=suggest\` then \`relations action=create\` to build the graph
225
+
226
+ ## Bulk Knowledge Input
227
+
228
+ When given a document or batch of knowledge to capture:
229
+ 1. Scan the input \u2014 identify all collections needed
230
+ 2. Call \`collections action=list\` \u2014 compare against what exists
231
+ 3. Propose missing collections to the user for confirmation
232
+ 4. Call \`collections action=create\` for each confirmed collection
233
+ 5. Then capture entries into the correct collections
234
+
235
+ Never stuff entries into the wrong collection. Never silently skip knowledge.
272
236
 
273
237
  ## Rules
274
238
 
275
- - Always capture as draft first. Only call \`commit-entry\` when the user confirms.
276
- - Use \`suggest-links\` after capturing to discover and create relations.
239
+ - In Open mode, user-authored captures can commit immediately unless the user asks to keep them as drafts.
240
+ - In consensus/role modes, only call \`commit-entry\` when the user confirms.
241
+ - Use \`graph action=suggest\` after capturing to discover and create relations.
242
+ - Collections are dynamic \u2014 use \`collections action=create\` when the workspace needs new ones.
277
243
  - When lost, fetch \`productbrain://orientation\` for the full system map.
278
244
  `;
279
245
  function isCursorProject() {
280
- return existsSync2(join2(process.cwd(), ".cursor")) || existsSync2(join2(process.cwd(), ".cursorignore"));
246
+ return existsSync(join(process.cwd(), ".cursor")) || existsSync(join(process.cwd(), ".cursorignore"));
281
247
  }
282
248
  async function offerCursorRulesInstall() {
283
249
  if (!isCursorProject()) return;
@@ -287,22 +253,22 @@ async function offerCursorRulesInstall() {
287
253
  log(dim(" Skipped rule install."));
288
254
  return;
289
255
  }
290
- const rulesDir = join2(process.cwd(), ".cursor", "rules");
291
- const rulePath = join2(rulesDir, CURSOR_RULE_FILENAME);
292
- if (existsSync2(rulePath)) {
256
+ const rulesDir = join(process.cwd(), ".cursor", "rules");
257
+ const rulePath = join(rulesDir, CURSOR_RULE_FILENAME);
258
+ if (existsSync(rulePath)) {
293
259
  log(` ${dim("\u2139")} Rule already exists at ${dim(rulePath)} \u2014 skipped`);
294
260
  return;
295
261
  }
296
- if (!existsSync2(rulesDir)) {
297
- mkdirSync2(rulesDir, { recursive: true });
262
+ if (!existsSync(rulesDir)) {
263
+ mkdirSync(rulesDir, { recursive: true });
298
264
  }
299
- writeFileSync2(rulePath, CURSOR_RULE_CONTENT, "utf-8");
265
+ writeFileSync(rulePath, CURSOR_RULE_CONTENT, "utf-8");
300
266
  log(` ${green("\u2713")} Installed rule at ${dim(rulePath)}`);
301
267
  }
302
268
  function buildDeeplink(apiKey) {
303
269
  const config = JSON.stringify({
304
270
  command: "npx",
305
- args: ["-y", "@productbrain/mcp@beta"],
271
+ args: ["-y", MCP_NPX_PACKAGE],
306
272
  env: { PRODUCTBRAIN_API_KEY: apiKey }
307
273
  });
308
274
  const encoded = Buffer.from(config).toString("base64url");
@@ -321,10 +287,11 @@ function printClaudeSnippet() {
321
287
  log("");
322
288
  log(` When Product Brain MCP is available, say "Start PB" at the beginning`);
323
289
  log(` of each session to orient to the workspace and unlock write tools.`);
324
- log(` Always capture as draft first; only commit when the user confirms.`);
290
+ log(` In Open mode, user-authored captures can commit immediately unless the user asks to keep drafts.`);
291
+ log(` In consensus/role modes, only commit when the user confirms.`);
325
292
  log("");
326
293
  }
327
294
  export {
328
295
  runSetup
329
296
  };
330
- //# sourceMappingURL=setup-6KVGMTRP.js.map
297
+ //# sourceMappingURL=setup-RYYXRDPB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/setup.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * `npx @productbrain/mcp@beta setup`\n *\n * Guided onboarding: get API key from the app, paste it, write MCP config,\n * and optionally install Cursor rules/skills (additive-only).\n */\n\nimport { execSync } from \"node:child_process\";\nimport { createInterface } from \"node:readline\";\nimport { existsSync, writeFileSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { resolveClient, writeClientConfig, MCP_NPX_PACKAGE, type McpClientInfo } from \"./config-writer.js\";\nimport { initAnalytics, trackSetupStarted, trackSetupCompleted, shutdownAnalytics } from \"../analytics.js\";\n\nconst APP_URL =\n process.env.PRODUCTBRAIN_APP_URL ?? \"https://work.productbrain.io\";\n\n// ── Helpers ─────────────────────────────────────────────────────────────\n\nfunction bold(s: string) {\n return `\\x1b[1m${s}\\x1b[0m`;\n}\nfunction green(s: string) {\n return `\\x1b[32m${s}\\x1b[0m`;\n}\nfunction dim(s: string) {\n return `\\x1b[2m${s}\\x1b[0m`;\n}\nfunction orange(s: string) {\n return `\\x1b[33m${s}\\x1b[0m`;\n}\n\nfunction log(msg: string) {\n process.stdout.write(`${msg}\\n`);\n}\n\nfunction openBrowser(url: string) {\n const platform = process.platform;\n try {\n if (platform === \"darwin\") execSync(`open \"${url}\"`);\n else if (platform === \"win32\") execSync(`start \"\" \"${url}\"`);\n else execSync(`xdg-open \"${url}\"`);\n } catch {\n log(dim(` Could not open browser automatically.`));\n log(` Open this URL manually: ${url}`);\n }\n}\n\nfunction prompt(question: string): Promise<string> {\n return new Promise((resolve) => {\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nfunction promptChoice(question: string, choices: string[]): Promise<number> {\n return new Promise((resolve) => {\n log(\"\");\n log(bold(question));\n choices.forEach((c, i) => log(` ${i + 1}) ${c}`));\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n rl.question(`\\n ${dim(\"Choice [1]:\")} `, (line) => {\n rl.close();\n const n = parseInt(line.trim(), 10);\n if (isNaN(n) || n < 1 || n > choices.length) {\n resolve(0);\n } else {\n resolve(n - 1);\n }\n });\n });\n}\n\n// ── Workspace Verification ───────────────────────────────────────────────\n\nconst DEFAULT_CLOUD_URL = \"https://gateway.productbrain.io\";\n\nasync function verifyWorkspace(\n apiKey: string,\n): Promise<{ name: string; slug: string } | null> {\n const siteUrl = process.env.CONVEX_SITE_URL\n ?? process.env.PRODUCTBRAIN_URL\n ?? DEFAULT_CLOUD_URL;\n\n try {\n const res = await fetch(`${siteUrl.replace(/\\/$/, \"\")}/api/aki`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ fn: \"resolveWorkspace\", args: {} }),\n });\n\n if (!res.ok) return null;\n const json = (await res.json()) as {\n data?: { name: string; slug: string } | null;\n error?: string;\n };\n return json.data ?? null;\n } catch {\n return null;\n }\n}\n\n// ── Main ────────────────────────────────────────────────────────────────\n\nexport async function runSetup() {\n initAnalytics();\n trackSetupStarted();\n\n log(\"\");\n log(bold(` Product${orange(\"Brain\")} Setup`));\n log(dim(\" Connect your AI assistant to your chain\\n\"));\n\n const apiKeysUrl = `${APP_URL}/settings/api-keys`;\n\n log(` ${dim(\"1. Get your API key from Settings → API Keys\")}`);\n log(` ${dim(apiKeysUrl)}\\n`);\n\n const openNow = await prompt(` Open this URL in your browser? [Y/n]: `);\n if (openNow.toLowerCase() !== \"n\" && openNow.toLowerCase() !== \"no\") {\n openBrowser(apiKeysUrl);\n }\n\n log(\"\");\n log(` ${dim(\"2. Generate a key (if you don't have one), then copy it.\\n\")}`);\n\n const apiKey = await prompt(` Paste your API key (pb_sk_...): `);\n\n if (!apiKey || !apiKey.startsWith(\"pb_sk_\")) {\n log(` ${orange(\"!\")} Invalid key format. Keys start with pb_sk_.`);\n log(` Get one at ${apiKeysUrl}\\n`);\n await shutdownAnalytics();\n process.exit(1);\n }\n\n log(` ${green(\"✓\")} Key received`);\n\n const workspace = await verifyWorkspace(apiKey);\n if (workspace) {\n log(` ${green(\"✓\")} Connected to workspace: ${bold(workspace.name)} ${dim(`(${workspace.slug})`)}`);\n } else {\n log(` ${orange(\"!\")} Could not verify workspace. Check your key at ${apiKeysUrl}`);\n }\n log(\"\");\n\n const CLIENT_NAMES = [\"Cursor\", \"Claude Desktop\"] as const;\n const options = [...CLIENT_NAMES, \"Other\"];\n\n const choice = await promptChoice(\"Where do you want to set up Product Brain?\", options);\n\n if (choice === 2) {\n printConfigSnippet(apiKey);\n trackSetupCompleted(\"Other\", \"snippet_shown\");\n } else {\n const client = resolveClient(CLIENT_NAMES[choice]);\n if (client) {\n const outcome = await writeConfig(client, apiKey);\n trackSetupCompleted(CLIENT_NAMES[choice], outcome);\n } else {\n log(` ${orange(\"!\")} ${CLIENT_NAMES[choice]} config path not available on this platform.`);\n printConfigSnippet(apiKey);\n trackSetupCompleted(CLIENT_NAMES[choice], \"write_error\");\n }\n }\n\n // Cursor-specific: offer to install rule (additive-only)\n if (choice === 0) {\n await offerCursorRulesInstall();\n printDeeplink(apiKey);\n }\n\n // Claude-specific: print snippet (never write to CLAUDE.md)\n if (choice === 1) {\n printClaudeSnippet();\n }\n\n log(\"\");\n log(\n ` ${green(\"✓\")} Done! Restart your AI assistant and try: ${bold('\"Start PB\"')}`,\n );\n printHelpLink();\n await shutdownAnalytics();\n}\n\nasync function writeConfig(\n client: McpClientInfo,\n apiKey: string,\n): Promise<\"config_written\" | \"config_existed\" | \"write_error\"> {\n try {\n const wrote = await writeClientConfig(client, apiKey);\n if (wrote) {\n log(` ${green(\"✓\")} Wrote config to ${dim(client.configPath)}`);\n return \"config_written\";\n } else {\n log(` ${dim(\"ℹ\")} ${client.name} already configured — skipped`);\n return \"config_existed\";\n }\n } catch (err: any) {\n log(` ${orange(\"!\")} Could not write ${client.name} config: ${err.message}`);\n printConfigSnippet(apiKey);\n return \"write_error\";\n }\n}\n\nfunction printHelpLink() {\n log(` ${dim(`Need help? See ${APP_URL}/settings/api-keys`)}`);\n log(\"\");\n}\n\nfunction printConfigSnippet(apiKey: string) {\n log(\"\");\n log(bold(\" Add this to your MCP client config:\\n\"));\n const snippet = JSON.stringify(\n {\n mcpServers: {\n \"Product Brain\": {\n command: \"npx\",\n args: [\"-y\", MCP_NPX_PACKAGE],\n env: { PRODUCTBRAIN_API_KEY: apiKey },\n },\n },\n },\n null,\n 2,\n );\n for (const line of snippet.split(\"\\n\")) {\n log(` ${line}`);\n }\n log(\"\");\n}\n\n// ── Cursor Rules/Skills Install (additive-only) ─────────────────────────\n\nconst CURSOR_RULE_FILENAME = \"product-brain.mdc\";\n\nconst CURSOR_RULE_CONTENT = `---\ndescription: Product Brain MCP — single source of truth for product knowledge\nglobs:\nalwaysApply: true\n---\n\n# Product Brain MCP\n\nProduct Brain is your product knowledge base. The Chain is the single source of truth.\n\nEvery entry is either a **draft** (captured but not committed) or **committed** (on the Chain, SSOT).\nCommitting to the Chain is the compounding act.\n\n## Quick Start\n\nSay **\"Start PB\"** or **\"Start Product Brain\"** to begin. This single call:\n- Orients you to the workspace (readiness, gaps, planned work)\n- Unlocks write tools for the session\n- Surfaces your next recommended action\n\n## Tool Workflow\n\n1. **Start here**: \\`start\\` — workspace context + next action\n2. **Search**: \\`entries action=search\\` — find entries across all collections\n3. **Drill in**: \\`entries action=get\\` — full record with data, labels, relations\n4. **Context**: \\`context action=gather\\` — related knowledge around an entry or task\n5. **Capture**: \\`capture\\` — create knowledge with auto-linking + quality score\n6. **Commit**: \\`commit-entry\\` — promote drafts to SSOT when confirmation is still required\n7. **Connect**: \\`graph action=suggest\\` then \\`relations action=create\\` to build the graph\n\n## Bulk Knowledge Input\n\nWhen given a document or batch of knowledge to capture:\n1. Scan the input — identify all collections needed\n2. Call \\`collections action=list\\` — compare against what exists\n3. Propose missing collections to the user for confirmation\n4. Call \\`collections action=create\\` for each confirmed collection\n5. Then capture entries into the correct collections\n\nNever stuff entries into the wrong collection. Never silently skip knowledge.\n\n## Rules\n\n- In Open mode, user-authored captures can commit immediately unless the user asks to keep them as drafts.\n- In consensus/role modes, only call \\`commit-entry\\` when the user confirms.\n- Use \\`graph action=suggest\\` after capturing to discover and create relations.\n- Collections are dynamic — use \\`collections action=create\\` when the workspace needs new ones.\n- When lost, fetch \\`productbrain://orientation\\` for the full system map.\n`;\n\nfunction isCursorProject(): boolean {\n return existsSync(join(process.cwd(), \".cursor\")) || existsSync(join(process.cwd(), \".cursorignore\"));\n}\n\nasync function offerCursorRulesInstall(): Promise<void> {\n if (!isCursorProject()) return;\n\n const answer = await prompt(`\\n Install Product Brain rule for Cursor? [Y/n]: `);\n if (answer.toLowerCase() === \"n\" || answer.toLowerCase() === \"no\") {\n log(dim(\" Skipped rule install.\"));\n return;\n }\n\n const rulesDir = join(process.cwd(), \".cursor\", \"rules\");\n const rulePath = join(rulesDir, CURSOR_RULE_FILENAME);\n\n if (existsSync(rulePath)) {\n log(` ${dim(\"ℹ\")} Rule already exists at ${dim(rulePath)} — skipped`);\n return;\n }\n\n if (!existsSync(rulesDir)) {\n mkdirSync(rulesDir, { recursive: true });\n }\n\n writeFileSync(rulePath, CURSOR_RULE_CONTENT, \"utf-8\");\n log(` ${green(\"✓\")} Installed rule at ${dim(rulePath)}`);\n}\n\nfunction buildDeeplink(apiKey: string): string {\n const config = JSON.stringify({\n command: \"npx\",\n args: [\"-y\", MCP_NPX_PACKAGE],\n env: { PRODUCTBRAIN_API_KEY: apiKey },\n });\n const encoded = Buffer.from(config).toString(\"base64url\");\n return `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(\"Product Brain\")}&config=${encoded}`;\n}\n\nfunction printDeeplink(apiKey: string): void {\n const link = buildDeeplink(apiKey);\n log(\"\");\n log(` ${dim(\"One-click install for Cursor (paste in browser):\")}`);\n log(` ${link}`);\n}\n\nfunction printClaudeSnippet(): void {\n log(\"\");\n log(bold(\" For Claude Code / CLAUDE.md:\"));\n log(dim(\" Add this line to your ~/.claude/CLAUDE.md:\"));\n log(\"\");\n log(` When Product Brain MCP is available, say \"Start PB\" at the beginning`);\n log(` of each session to orient to the workspace and unlock write tools.`);\n log(` In Open mode, user-authored captures can commit immediately unless the user asks to keep drafts.`);\n log(` In consensus/role modes, only commit when the user confirms.`);\n log(\"\");\n}\n"],"mappings":"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","names":[]}