@productbrain/mcp 0.0.1-beta.196 → 0.0.1-beta.1963
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.
- package/dist/{chunk-26IS4THT.js → chunk-P65NSWZE.js} +2291 -3422
- package/dist/chunk-P65NSWZE.js.map +1 -0
- package/dist/chunk-VFSXDXLC.js +1119 -0
- package/dist/chunk-VFSXDXLC.js.map +1 -0
- package/dist/cli/index.js +1 -1
- package/dist/http.js +294 -104
- package/dist/http.js.map +1 -1
- package/dist/index.js +8 -8
- package/dist/{setup-RYYXRDPB.js → setup-EALJFCQF.js} +18 -10
- package/dist/setup-EALJFCQF.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-26IS4THT.js.map +0 -1
- package/dist/chunk-YMF3IQ5E.js +0 -465
- package/dist/chunk-YMF3IQ5E.js.map +0 -1
- package/dist/setup-RYYXRDPB.js.map +0 -1
package/dist/chunk-YMF3IQ5E.js
DELETED
|
@@ -1,465 +0,0 @@
|
|
|
1
|
-
// src/analytics.ts
|
|
2
|
-
import { userInfo } from "os";
|
|
3
|
-
import { PostHog } from "posthog-node";
|
|
4
|
-
var client = null;
|
|
5
|
-
var distinctId = "anonymous";
|
|
6
|
-
var POSTHOG_HOST = "https://eu.i.posthog.com";
|
|
7
|
-
function log(msg) {
|
|
8
|
-
if (process.env.MCP_DEBUG === "1") {
|
|
9
|
-
process.stderr.write(msg);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
function getBuildTimeKey() {
|
|
13
|
-
try {
|
|
14
|
-
return "";
|
|
15
|
-
} catch {
|
|
16
|
-
return "";
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
function initAnalytics() {
|
|
20
|
-
const apiKey = process.env.POSTHOG_MCP_KEY || getBuildTimeKey();
|
|
21
|
-
if (!apiKey) {
|
|
22
|
-
log("[MCP-ANALYTICS] No PostHog key \u2014 tracking disabled (set SYNERGYOS_POSTHOG_KEY at build time for publish)\n");
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
client = new PostHog(apiKey, {
|
|
26
|
-
host: POSTHOG_HOST,
|
|
27
|
-
flushAt: 1,
|
|
28
|
-
flushInterval: 5e3,
|
|
29
|
-
featureFlagsPollingInterval: 3e4
|
|
30
|
-
});
|
|
31
|
-
distinctId = process.env.MCP_USER_ID || fallbackDistinctId();
|
|
32
|
-
log(`[MCP-ANALYTICS] Initialized \u2014 host=${POSTHOG_HOST} distinctId=${distinctId}
|
|
33
|
-
`);
|
|
34
|
-
}
|
|
35
|
-
function fallbackDistinctId() {
|
|
36
|
-
try {
|
|
37
|
-
return userInfo().username;
|
|
38
|
-
} catch {
|
|
39
|
-
return `os-${process.pid}`;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
function trackSessionStarted(workspaceId, serverVersion) {
|
|
43
|
-
if (!client) return;
|
|
44
|
-
client.capture({
|
|
45
|
-
distinctId,
|
|
46
|
-
event: "mcp_session_started",
|
|
47
|
-
properties: {
|
|
48
|
-
workspace_id: workspaceId,
|
|
49
|
-
server_version: serverVersion,
|
|
50
|
-
source: "mcp-server",
|
|
51
|
-
$groups: { workspace: workspaceId }
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
function trackToolCall(fn, status, durationMs, workspaceId, errorMsg) {
|
|
56
|
-
const properties = {
|
|
57
|
-
tool: fn,
|
|
58
|
-
status,
|
|
59
|
-
duration_ms: durationMs,
|
|
60
|
-
workspace_id: workspaceId,
|
|
61
|
-
source: "mcp-server",
|
|
62
|
-
$groups: { workspace: workspaceId }
|
|
63
|
-
};
|
|
64
|
-
if (errorMsg) properties.error = errorMsg;
|
|
65
|
-
if (!client) return;
|
|
66
|
-
client.capture({
|
|
67
|
-
distinctId,
|
|
68
|
-
event: "mcp_tool_called",
|
|
69
|
-
properties
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
function trackSetupStarted() {
|
|
73
|
-
if (!client) return;
|
|
74
|
-
client.capture({
|
|
75
|
-
distinctId,
|
|
76
|
-
event: "mcp_setup_started",
|
|
77
|
-
properties: {
|
|
78
|
-
source: "mcp-server",
|
|
79
|
-
platform: process.platform
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
function trackSetupCompleted(chosenClient, outcome) {
|
|
84
|
-
if (!client) return;
|
|
85
|
-
client.capture({
|
|
86
|
-
distinctId,
|
|
87
|
-
event: "mcp_setup_completed",
|
|
88
|
-
properties: {
|
|
89
|
-
client: chosenClient,
|
|
90
|
-
outcome,
|
|
91
|
-
source: "mcp-server",
|
|
92
|
-
platform: process.platform
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
function trackQualityVerdict(workspaceId, props) {
|
|
97
|
-
if (!client) return;
|
|
98
|
-
client.capture({
|
|
99
|
-
distinctId,
|
|
100
|
-
event: "quality_verdict_generated",
|
|
101
|
-
properties: {
|
|
102
|
-
...props,
|
|
103
|
-
workspace_id: workspaceId,
|
|
104
|
-
source_system: "mcp-server",
|
|
105
|
-
$groups: { workspace: workspaceId }
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
function trackQualityCheck(workspaceId, props) {
|
|
110
|
-
if (!client) return;
|
|
111
|
-
client.capture({
|
|
112
|
-
distinctId,
|
|
113
|
-
event: "quality_verdict_checked",
|
|
114
|
-
properties: {
|
|
115
|
-
...props,
|
|
116
|
-
workspace_id: workspaceId,
|
|
117
|
-
source_system: "mcp-server",
|
|
118
|
-
$groups: { workspace: workspaceId }
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
function trackCaptureClassifierEvent(event, workspaceId, props) {
|
|
123
|
-
if (!client) return;
|
|
124
|
-
try {
|
|
125
|
-
client.capture({
|
|
126
|
-
distinctId,
|
|
127
|
-
event,
|
|
128
|
-
properties: {
|
|
129
|
-
...props,
|
|
130
|
-
workspace_id: workspaceId,
|
|
131
|
-
source_system: "mcp-server",
|
|
132
|
-
$groups: { workspace: workspaceId }
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
} catch {
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
function trackCaptureClassifierEvaluated(workspaceId, props) {
|
|
139
|
-
trackCaptureClassifierEvent("mcp_capture_classifier_evaluated", workspaceId, props);
|
|
140
|
-
}
|
|
141
|
-
function trackCaptureClassifierAutoRouted(workspaceId, props) {
|
|
142
|
-
trackCaptureClassifierEvent("mcp_capture_classifier_auto_routed", workspaceId, props);
|
|
143
|
-
}
|
|
144
|
-
function trackCaptureClassifierFallback(workspaceId, props) {
|
|
145
|
-
trackCaptureClassifierEvent("mcp_capture_classifier_fallback", workspaceId, props);
|
|
146
|
-
}
|
|
147
|
-
function trackChainEntryCommitted(workspaceId, props) {
|
|
148
|
-
if (!client) return;
|
|
149
|
-
try {
|
|
150
|
-
client.capture({
|
|
151
|
-
distinctId,
|
|
152
|
-
event: "chain_entry_committed",
|
|
153
|
-
properties: {
|
|
154
|
-
workspace_id: workspaceId,
|
|
155
|
-
source_system: "mcp-server",
|
|
156
|
-
$groups: { workspace: workspaceId },
|
|
157
|
-
...props
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
} catch {
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
function trackKnowledgeGap(workspaceId, props) {
|
|
164
|
-
if (!client) return;
|
|
165
|
-
try {
|
|
166
|
-
client.capture({
|
|
167
|
-
distinctId,
|
|
168
|
-
event: "knowledge_gap_detected",
|
|
169
|
-
properties: {
|
|
170
|
-
...props,
|
|
171
|
-
query: props.query.slice(0, 200),
|
|
172
|
-
workspace_id: workspaceId,
|
|
173
|
-
source_system: "mcp-server",
|
|
174
|
-
$groups: { workspace: workspaceId }
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
} catch {
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
function trackCaptureQualityHints(workspaceId, props) {
|
|
181
|
-
if (!client) return;
|
|
182
|
-
try {
|
|
183
|
-
client.capture({
|
|
184
|
-
distinctId,
|
|
185
|
-
event: "mcp_capture_quality_hints",
|
|
186
|
-
properties: {
|
|
187
|
-
...props,
|
|
188
|
-
workspace_id: workspaceId,
|
|
189
|
-
source_system: "mcp-server",
|
|
190
|
-
$groups: { workspace: workspaceId }
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
} catch {
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
function trackCaptureRelationSuggestions(workspaceId, props) {
|
|
197
|
-
if (!client) return;
|
|
198
|
-
try {
|
|
199
|
-
client.capture({
|
|
200
|
-
distinctId,
|
|
201
|
-
event: "mcp_capture_relation_suggestions",
|
|
202
|
-
properties: {
|
|
203
|
-
...props,
|
|
204
|
-
workspace_id: workspaceId,
|
|
205
|
-
source_system: "mcp-server",
|
|
206
|
-
$groups: { workspace: workspaceId }
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
} catch {
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
function trackCollectionClassified(workspaceId, props) {
|
|
213
|
-
if (!client) return;
|
|
214
|
-
try {
|
|
215
|
-
client.capture({
|
|
216
|
-
distinctId,
|
|
217
|
-
event: "collection_classified",
|
|
218
|
-
properties: {
|
|
219
|
-
...props,
|
|
220
|
-
workspace_id: workspaceId,
|
|
221
|
-
source_system: "mcp-server",
|
|
222
|
-
$groups: { workspace: workspaceId }
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
} catch {
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
function trackFieldGuidanceApplied(workspaceId, props) {
|
|
229
|
-
if (!client) return;
|
|
230
|
-
try {
|
|
231
|
-
client.capture({
|
|
232
|
-
distinctId,
|
|
233
|
-
event: "field_guidance_applied",
|
|
234
|
-
properties: {
|
|
235
|
-
...props,
|
|
236
|
-
workspace_id: workspaceId,
|
|
237
|
-
source_system: "mcp-server",
|
|
238
|
-
$groups: { workspace: workspaceId }
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
} catch {
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
function trackFieldQualityWarning(workspaceId, props) {
|
|
245
|
-
if (!client) return;
|
|
246
|
-
try {
|
|
247
|
-
client.capture({
|
|
248
|
-
distinctId,
|
|
249
|
-
event: "field_quality_warning",
|
|
250
|
-
properties: {
|
|
251
|
-
...props,
|
|
252
|
-
workspace_id: workspaceId,
|
|
253
|
-
source_system: "mcp-server",
|
|
254
|
-
$groups: { workspace: workspaceId }
|
|
255
|
-
}
|
|
256
|
-
});
|
|
257
|
-
} catch {
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
function trackSessionCaptureRate(workspaceId, props) {
|
|
261
|
-
if (!client) return;
|
|
262
|
-
try {
|
|
263
|
-
client.capture({
|
|
264
|
-
distinctId,
|
|
265
|
-
event: "session_capture_rate",
|
|
266
|
-
properties: {
|
|
267
|
-
...props,
|
|
268
|
-
workspace_id: workspaceId,
|
|
269
|
-
source_system: "mcp-server",
|
|
270
|
-
$groups: { workspace: workspaceId }
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
|
-
} catch {
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
function trackZeroCaptureAuditFired(workspaceId, props) {
|
|
277
|
-
if (!client) return;
|
|
278
|
-
try {
|
|
279
|
-
client.capture({
|
|
280
|
-
distinctId,
|
|
281
|
-
event: "zero_capture_audit_fired",
|
|
282
|
-
properties: {
|
|
283
|
-
...props,
|
|
284
|
-
workspace_id: workspaceId,
|
|
285
|
-
source_system: "mcp-server",
|
|
286
|
-
$groups: { workspace: workspaceId }
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
} catch {
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
function trackCaptureContractMiss(workspaceId, props) {
|
|
293
|
-
if (!client) return;
|
|
294
|
-
try {
|
|
295
|
-
client.capture({
|
|
296
|
-
distinctId,
|
|
297
|
-
event: "capture_contract_miss",
|
|
298
|
-
properties: {
|
|
299
|
-
...props,
|
|
300
|
-
workspace_id: workspaceId,
|
|
301
|
-
source_system: "mcp-server",
|
|
302
|
-
$groups: { workspace: workspaceId }
|
|
303
|
-
}
|
|
304
|
-
});
|
|
305
|
-
} catch {
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
function trackWriteBackHintServed(workspaceId, props) {
|
|
309
|
-
if (!client) return;
|
|
310
|
-
try {
|
|
311
|
-
client.capture({
|
|
312
|
-
distinctId,
|
|
313
|
-
event: "write_back_hint_served",
|
|
314
|
-
properties: {
|
|
315
|
-
...props,
|
|
316
|
-
workspace_id: workspaceId,
|
|
317
|
-
source_system: "mcp-server",
|
|
318
|
-
$groups: { workspace: workspaceId }
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
} catch {
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
function trackCommitErrorByCode(workspaceId, props) {
|
|
325
|
-
if (!client) return;
|
|
326
|
-
try {
|
|
327
|
-
client.capture({
|
|
328
|
-
distinctId,
|
|
329
|
-
event: "commit_error_by_code",
|
|
330
|
-
properties: {
|
|
331
|
-
...props,
|
|
332
|
-
workspace_id: workspaceId,
|
|
333
|
-
source_system: "mcp-server",
|
|
334
|
-
$groups: { workspace: workspaceId }
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
} catch {
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
function trackClassifierDivergence(workspaceId, props) {
|
|
341
|
-
if (!client) return;
|
|
342
|
-
try {
|
|
343
|
-
client.capture({
|
|
344
|
-
distinctId,
|
|
345
|
-
event: "classifier_divergence",
|
|
346
|
-
properties: {
|
|
347
|
-
...props,
|
|
348
|
-
workspace_id: workspaceId,
|
|
349
|
-
source_system: "mcp-server",
|
|
350
|
-
$groups: { workspace: workspaceId }
|
|
351
|
-
}
|
|
352
|
-
});
|
|
353
|
-
} catch {
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
function getPostHogClient() {
|
|
357
|
-
return client;
|
|
358
|
-
}
|
|
359
|
-
async function shutdownAnalytics() {
|
|
360
|
-
await client?.shutdown();
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// src/cli/config-writer.ts
|
|
364
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
365
|
-
import { join, dirname } from "path";
|
|
366
|
-
import { homedir, platform } from "os";
|
|
367
|
-
var SERVER_ENTRY_KEY = "Product Brain";
|
|
368
|
-
var LEGACY_ENTRY_KEY = "productbrain";
|
|
369
|
-
var MCP_NPX_PACKAGE = "@productbrain/mcp@beta";
|
|
370
|
-
function buildServerEntry(apiKey) {
|
|
371
|
-
return {
|
|
372
|
-
command: "npx",
|
|
373
|
-
args: ["-y", MCP_NPX_PACKAGE],
|
|
374
|
-
env: { PRODUCTBRAIN_API_KEY: apiKey }
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
function getCursorConfigPath() {
|
|
378
|
-
return join(process.cwd(), ".cursor", "mcp.json");
|
|
379
|
-
}
|
|
380
|
-
function getClaudeDesktopConfigPath() {
|
|
381
|
-
const os = platform();
|
|
382
|
-
if (os === "darwin") {
|
|
383
|
-
return join(
|
|
384
|
-
homedir(),
|
|
385
|
-
"Library",
|
|
386
|
-
"Application Support",
|
|
387
|
-
"Claude",
|
|
388
|
-
"claude_desktop_config.json"
|
|
389
|
-
);
|
|
390
|
-
}
|
|
391
|
-
if (os === "win32") {
|
|
392
|
-
const appData = process.env.APPDATA ?? join(homedir(), "AppData", "Roaming");
|
|
393
|
-
return join(appData, "Claude", "claude_desktop_config.json");
|
|
394
|
-
}
|
|
395
|
-
return null;
|
|
396
|
-
}
|
|
397
|
-
function resolveClient(name) {
|
|
398
|
-
if (name === "Cursor") {
|
|
399
|
-
return { name, configPath: getCursorConfigPath() };
|
|
400
|
-
}
|
|
401
|
-
const configPath = getClaudeDesktopConfigPath();
|
|
402
|
-
return configPath ? { name, configPath } : null;
|
|
403
|
-
}
|
|
404
|
-
function readJsonSafe(path) {
|
|
405
|
-
if (!existsSync(path)) return {};
|
|
406
|
-
try {
|
|
407
|
-
return JSON.parse(readFileSync(path, "utf-8"));
|
|
408
|
-
} catch {
|
|
409
|
-
return {};
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
async function writeClientConfig(client2, apiKey) {
|
|
413
|
-
const config = readJsonSafe(client2.configPath);
|
|
414
|
-
const serversKey = "mcpServers";
|
|
415
|
-
if (!config[serversKey]) config[serversKey] = {};
|
|
416
|
-
if (config[serversKey][LEGACY_ENTRY_KEY]) {
|
|
417
|
-
const legacy = config[serversKey][LEGACY_ENTRY_KEY];
|
|
418
|
-
config[serversKey][SERVER_ENTRY_KEY] = {
|
|
419
|
-
...buildServerEntry(apiKey),
|
|
420
|
-
env: { ...legacy.env, PRODUCTBRAIN_API_KEY: legacy.env?.PRODUCTBRAIN_API_KEY ?? apiKey }
|
|
421
|
-
};
|
|
422
|
-
delete config[serversKey][LEGACY_ENTRY_KEY];
|
|
423
|
-
} else {
|
|
424
|
-
const existing = config[serversKey][SERVER_ENTRY_KEY];
|
|
425
|
-
config[serversKey][SERVER_ENTRY_KEY] = existing ? { ...existing, env: { ...existing.env, PRODUCTBRAIN_API_KEY: apiKey } } : buildServerEntry(apiKey);
|
|
426
|
-
}
|
|
427
|
-
const dir = dirname(client2.configPath);
|
|
428
|
-
if (!existsSync(dir)) {
|
|
429
|
-
mkdirSync(dir, { recursive: true });
|
|
430
|
-
}
|
|
431
|
-
writeFileSync(client2.configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
432
|
-
return true;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
export {
|
|
436
|
-
initAnalytics,
|
|
437
|
-
trackSessionStarted,
|
|
438
|
-
trackToolCall,
|
|
439
|
-
trackSetupStarted,
|
|
440
|
-
trackSetupCompleted,
|
|
441
|
-
trackQualityVerdict,
|
|
442
|
-
trackQualityCheck,
|
|
443
|
-
trackCaptureClassifierEvaluated,
|
|
444
|
-
trackCaptureClassifierAutoRouted,
|
|
445
|
-
trackCaptureClassifierFallback,
|
|
446
|
-
trackChainEntryCommitted,
|
|
447
|
-
trackKnowledgeGap,
|
|
448
|
-
trackCaptureQualityHints,
|
|
449
|
-
trackCaptureRelationSuggestions,
|
|
450
|
-
trackCollectionClassified,
|
|
451
|
-
trackFieldGuidanceApplied,
|
|
452
|
-
trackFieldQualityWarning,
|
|
453
|
-
trackSessionCaptureRate,
|
|
454
|
-
trackZeroCaptureAuditFired,
|
|
455
|
-
trackCaptureContractMiss,
|
|
456
|
-
trackWriteBackHintServed,
|
|
457
|
-
trackCommitErrorByCode,
|
|
458
|
-
trackClassifierDivergence,
|
|
459
|
-
getPostHogClient,
|
|
460
|
-
shutdownAnalytics,
|
|
461
|
-
MCP_NPX_PACKAGE,
|
|
462
|
-
resolveClient,
|
|
463
|
-
writeClientConfig
|
|
464
|
-
};
|
|
465
|
-
//# sourceMappingURL=chunk-YMF3IQ5E.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/analytics.ts","../src/cli/config-writer.ts"],"sourcesContent":["/**\n * PostHog analytics for SynergyOS maintainers — tracks MCP usage (sessions, tool calls).\n * Not user-facing. Key is injected at build time via SYNERGYOS_POSTHOG_KEY.\n * Override with POSTHOG_MCP_KEY for self-hosted deployments.\n */\n\nimport { userInfo } from \"node:os\";\nimport { PostHog } from \"posthog-node\";\n\nlet client: PostHog | null = null;\nlet distinctId = \"anonymous\";\n\nconst POSTHOG_HOST = \"https://eu.i.posthog.com\";\n\n/** Injected at build time: SYNERGYOS_POSTHOG_KEY env when running `npm run build`/publish. */\ndeclare const __SYNERGYOS_POSTHOG_KEY__: string;\n\n/** Only write to stderr when MCP_DEBUG=1 for quieter default DX. */\nfunction log(msg: string): void {\n if (process.env.MCP_DEBUG === \"1\") {\n process.stderr.write(msg);\n }\n}\n\nfunction getBuildTimeKey(): string {\n try {\n return __SYNERGYOS_POSTHOG_KEY__;\n } catch {\n // Not replaced by bundler (e.g. running via tsx in tests) — treat as absent.\n return \"\";\n }\n}\n\nexport function initAnalytics(): void {\n const apiKey = process.env.POSTHOG_MCP_KEY || getBuildTimeKey();\n if (!apiKey) {\n log(\"[MCP-ANALYTICS] No PostHog key — tracking disabled (set SYNERGYOS_POSTHOG_KEY at build time for publish)\\n\");\n return;\n }\n\n client = new PostHog(apiKey, {\n host: POSTHOG_HOST,\n flushAt: 1,\n flushInterval: 5000,\n featureFlagsPollingInterval: 30_000,\n });\n distinctId = process.env.MCP_USER_ID || fallbackDistinctId();\n\n log(`[MCP-ANALYTICS] Initialized — host=${POSTHOG_HOST} distinctId=${distinctId}\\n`);\n}\n\nfunction fallbackDistinctId(): string {\n try {\n return userInfo().username;\n } catch {\n return `os-${process.pid}`;\n }\n}\n\nexport function trackSessionStarted(\n workspaceId: string,\n serverVersion: string,\n): void {\n if (!client) return;\n client.capture({\n distinctId,\n event: \"mcp_session_started\",\n properties: {\n workspace_id: workspaceId,\n server_version: serverVersion,\n source: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n}\n\nexport function trackToolCall(\n fn: string,\n status: \"ok\" | \"error\",\n durationMs: number,\n workspaceId: string,\n errorMsg?: string,\n): void {\n const properties: Record<string, unknown> = {\n tool: fn,\n status,\n duration_ms: durationMs,\n workspace_id: workspaceId,\n source: \"mcp-server\",\n $groups: { workspace: workspaceId },\n };\n if (errorMsg) properties.error = errorMsg;\n\n if (!client) return;\n client.capture({\n distinctId,\n event: \"mcp_tool_called\",\n properties,\n });\n}\n\nexport function trackSetupStarted(): void {\n if (!client) return;\n client.capture({\n distinctId,\n event: \"mcp_setup_started\",\n properties: {\n source: \"mcp-server\",\n platform: process.platform,\n },\n });\n}\n\nexport function trackSetupCompleted(\n chosenClient: string,\n outcome: \"config_written\" | \"config_existed\" | \"snippet_shown\" | \"write_error\",\n): void {\n if (!client) return;\n client.capture({\n distinctId,\n event: \"mcp_setup_completed\",\n properties: {\n client: chosenClient,\n outcome,\n source: \"mcp-server\",\n platform: process.platform,\n },\n });\n}\n\nexport function trackQualityVerdict(\n workspaceId: string,\n props: {\n entry_id: string;\n entry_type: string;\n tier: string;\n context: string;\n passed: boolean;\n source: string;\n criteria_total: number;\n criteria_failed: number;\n llm_scheduled: boolean;\n },\n): void {\n if (!client) return;\n client.capture({\n distinctId,\n event: \"quality_verdict_generated\",\n properties: {\n ...props,\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n}\n\nexport function trackQualityCheck(\n workspaceId: string,\n props: {\n entry_id: string;\n entry_type: string;\n tier: string;\n passed: boolean;\n source: string;\n llm_status?: string;\n llm_duration_ms?: number;\n llm_error?: string;\n has_roger_martin: boolean;\n },\n): void {\n if (!client) return;\n client.capture({\n distinctId,\n event: \"quality_verdict_checked\",\n properties: {\n ...props,\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n}\n\nexport type ClassifierReasonCategory =\n | \"auto-routed\"\n | \"low-confidence\"\n | \"ambiguous\"\n | \"non-provisioned\";\n\ntype CaptureClassifierTelemetryProps = {\n predicted_collection: string;\n confidence: number;\n auto_routed: boolean;\n reason_category: ClassifierReasonCategory;\n explicit_collection_provided: boolean;\n};\n\nfunction trackCaptureClassifierEvent(\n event: \"mcp_capture_classifier_evaluated\" | \"mcp_capture_classifier_auto_routed\" | \"mcp_capture_classifier_fallback\",\n workspaceId: string,\n props: CaptureClassifierTelemetryProps,\n): void {\n if (!client) return;\n try {\n client.capture({\n distinctId,\n event,\n properties: {\n ...props,\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n } catch {\n // Analytics are advisory and must never break capture flow.\n }\n}\n\nexport function trackCaptureClassifierEvaluated(\n workspaceId: string,\n props: CaptureClassifierTelemetryProps,\n): void {\n trackCaptureClassifierEvent(\"mcp_capture_classifier_evaluated\", workspaceId, props);\n}\n\nexport function trackCaptureClassifierAutoRouted(\n workspaceId: string,\n props: CaptureClassifierTelemetryProps,\n): void {\n trackCaptureClassifierEvent(\"mcp_capture_classifier_auto_routed\", workspaceId, props);\n}\n\nexport function trackCaptureClassifierFallback(\n workspaceId: string,\n props: CaptureClassifierTelemetryProps,\n): void {\n trackCaptureClassifierEvent(\"mcp_capture_classifier_fallback\", workspaceId, props);\n}\n\n/** GLO-26 / TEN-156: every SSOT commit for PostHog funnels (split auto vs manual). */\nexport function trackChainEntryCommitted(\n workspaceId: string,\n props: {\n entry_id: string;\n collection?: string;\n commit_method: \"auto\" | \"manual\";\n surface:\n | \"mcp_commit_tool\"\n | \"mcp_capture\"\n | \"mcp_wrapup\";\n },\n): void {\n if (!client) return;\n try {\n client.capture({\n distinctId,\n event: \"chain_entry_committed\",\n properties: {\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n ...props,\n },\n });\n } catch {\n // Analytics must never break the tool path.\n }\n}\n\nexport function trackKnowledgeGap(\n workspaceId: string,\n props: {\n query: string;\n tool: string;\n action: string;\n gap_type: \"search_zero\" | \"context_task_empty\" | \"context_entry_isolated\" | \"context_graph_empty\";\n collection_scope?: string;\n },\n): void {\n if (!client) return;\n try {\n client.capture({\n distinctId,\n event: \"knowledge_gap_detected\",\n properties: {\n ...props,\n query: props.query.slice(0, 200),\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n } catch {\n // Analytics must never break the tool response path.\n }\n}\n\n// ── BET-272 S6 / STD-155: Capture intelligence observability ────────────────\n\n/** Fires when formative quality hints are returned at capture time. */\nexport function trackCaptureQualityHints(\n workspaceId: string,\n props: {\n collection: string;\n hint_count: number;\n hint_fields: string[];\n },\n): void {\n if (!client) return;\n try {\n client.capture({\n distinctId,\n event: \"mcp_capture_quality_hints\",\n properties: {\n ...props,\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n } catch {\n // Analytics must never break capture flow.\n }\n}\n\n/** Fires when relation suggestions are returned at capture time. */\nexport function trackCaptureRelationSuggestions(\n workspaceId: string,\n props: {\n collection: string;\n suggestion_count: number;\n relation_types: string[];\n avg_confidence: number;\n },\n): void {\n if (!client) return;\n try {\n client.capture({\n distinctId,\n event: \"mcp_capture_relation_suggestions\",\n properties: {\n ...props,\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n } catch {\n // Analytics must never break capture flow.\n }\n}\n\n// ── BET-288 S0: Collection classification confusion matrix telemetry ────────\n\n/**\n * Fires on every collection classification (auto-routed, fallback, explicit-provided).\n * Captures the full confusion signal: predicted collection, runner-up, thinkingLayer,\n * and confidence scores. This is the baseline measurement for BET-288 algorithm changes.\n */\nexport function trackCollectionClassified(\n workspaceId: string,\n props: {\n collection_slug: string;\n thinking_layer: string | null;\n confidence: number;\n classified_by: \"llm\" | \"heuristic\";\n confidence_tier: \"high\" | \"medium\" | \"low\";\n alternative_slug: string | null;\n alternative_confidence: number | null;\n explicit_collection_provided: boolean;\n auto_routed: boolean;\n },\n): void {\n if (!client) return;\n try {\n client.capture({\n distinctId,\n event: \"collection_classified\",\n properties: {\n ...props,\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n } catch {\n // Analytics must never break the capture flow.\n }\n}\n\n// ── BET-289 S5: Field-level writing guidance telemetry ────────────────────────\n\n/** Fires when field guidance is injected into a capture prompt or response. */\nexport function trackFieldGuidanceApplied(\n workspaceId: string,\n props: {\n collection: string;\n guided_field_count: number;\n },\n): void {\n if (!client) return;\n try {\n client.capture({\n distinctId,\n event: \"field_guidance_applied\",\n properties: {\n ...props,\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n } catch {\n // Analytics must never break the capture flow.\n }\n}\n\n/** Fires when commit-time heuristic detects field guidance violations. */\nexport function trackFieldQualityWarning(\n workspaceId: string,\n props: {\n warning_count: number;\n warning_types: string[];\n },\n): void {\n if (!client) return;\n try {\n client.capture({\n distinctId,\n event: \"field_quality_warning\",\n properties: {\n ...props,\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n } catch {\n // Analytics must never break the commit flow.\n }\n}\n\n/** Fires when skipGuidanceCheck is used to bypass guidance validation. */\nexport function trackFieldQualityOverride(\n workspaceId: string,\n): void {\n if (!client) return;\n try {\n client.capture({\n distinctId,\n event: \"field_quality_override\",\n properties: {\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n } catch {\n // Analytics must never break the commit flow.\n }\n}\n\n// ── WP-306 S3: Write-Back Measurement (capture rate insights) ──────────────\n\n/** Fires on session close to track session capture rate. */\nexport function trackSessionCaptureRate(\n workspaceId: string,\n props: {\n entries_created: number;\n entries_modified: number;\n relations_created: number;\n had_captures: boolean;\n },\n): void {\n if (!client) return;\n try {\n client.capture({\n distinctId,\n event: \"session_capture_rate\",\n properties: {\n ...props,\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n } catch {\n // Analytics must never break session closure.\n }\n}\n\n/** Fires when captureAudit is triggered (activity but no captures). */\nexport function trackZeroCaptureAuditFired(\n workspaceId: string,\n props: {\n suggestion_count: number;\n },\n): void {\n if (!client) return;\n try {\n client.capture({\n distinctId,\n event: \"zero_capture_audit_fired\",\n properties: {\n ...props,\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n } catch {\n // Analytics must never break wrapup flow.\n }\n}\n\n// ── WP-316 S1b: Capture contract observability ──────────────────────────────\n\n/** Fires when a capture-contract resource request references an unknown collection slug. */\nexport function trackCaptureContractMiss(\n workspaceId: string,\n props: {\n slug: string;\n },\n): void {\n if (!client) return;\n try {\n client.capture({\n distinctId,\n event: \"capture_contract_miss\",\n properties: {\n ...props,\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n } catch {\n // Analytics must never break the resource response path.\n }\n}\n\n/** Fires when writeBackHints are included in an orient response. */\nexport function trackWriteBackHintServed(\n workspaceId: string,\n props: {\n hint_count: number;\n has_task: boolean;\n },\n): void {\n if (!client) return;\n try {\n client.capture({\n distinctId,\n event: \"write_back_hint_served\",\n properties: {\n ...props,\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n } catch {\n // Analytics must never break orient flow.\n }\n}\n\n/**\n * WP-316 S1a: Fires when commit-entry fails with a structured error code.\n * Enables observability on which validation errors block commits most often.\n */\nexport function trackCommitErrorByCode(\n workspaceId: string,\n props: {\n error_code: string;\n missing_field_count: number;\n field_error_count: number;\n entry_id: string;\n },\n): void {\n if (!client) return;\n try {\n client.capture({\n distinctId,\n event: \"commit_error_by_code\",\n properties: {\n ...props,\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n } catch {\n // Analytics must never break the commit error path.\n }\n}\n\n// ── WP-316 S2: Classifier divergence tracking ─────────────────────────────\n\n/**\n * Fires when an agent provides an explicit collection that differs from the\n * classifier's top suggestion. Measures how often agents override the classifier\n * and whether those overrides are to known alternatives or completely off-roster.\n */\nexport function trackClassifierDivergence(\n workspaceId: string,\n props: {\n classifier_collection: string;\n agent_collection: string;\n classifier_confidence: number;\n classifier_tier: string;\n agent_in_candidates: boolean;\n },\n): void {\n if (!client) return;\n try {\n client.capture({\n distinctId,\n event: \"classifier_divergence\",\n properties: {\n ...props,\n workspace_id: workspaceId,\n source_system: \"mcp-server\",\n $groups: { workspace: workspaceId },\n },\n });\n } catch {\n // Analytics must never break the capture flow.\n }\n}\n\nexport function getPostHogClient(): PostHog | null {\n return client;\n}\n\nexport async function shutdownAnalytics(): Promise<void> {\n await client?.shutdown();\n}\n","/**\n * Multi-client MCP config detection and writer.\n *\n * Supports:\n * - Cursor: .cursor/mcp.json in cwd (project-level)\n * - Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)\n * %APPDATA%/Claude/claude_desktop_config.json (Windows)\n *\n * The writer reads existing config, merges the new server entry (never\n * overwrites existing entries), and writes back. Falls back to printing\n * a snippet for unsupported OS or unknown formats.\n */\n\nimport { existsSync, readFileSync, writeFileSync, mkdirSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { homedir, platform } from \"node:os\";\n\nexport interface McpClientInfo {\n name: string;\n configPath: string;\n}\n\nconst SERVER_ENTRY_KEY = \"Product Brain\";\nconst LEGACY_ENTRY_KEY = \"productbrain\";\n\n/**\n * Canonical npx package specifier. Update here when exiting beta.\n * Frontend mirror: src/lib/constants/mcp.ts\n * Business rule: BR-84 (Chain)\n */\nexport const MCP_NPX_PACKAGE = \"@productbrain/mcp@beta\";\n\nfunction buildServerEntry(apiKey: string) {\n return {\n command: \"npx\",\n args: [\"-y\", MCP_NPX_PACKAGE],\n env: { PRODUCTBRAIN_API_KEY: apiKey },\n };\n}\n\n// ── Detection ───────────────────────────────────────────────────────────\n\nfunction getCursorConfigPath(): string {\n return join(process.cwd(), \".cursor\", \"mcp.json\");\n}\n\nfunction getClaudeDesktopConfigPath(): string | null {\n const os = platform();\n if (os === \"darwin\") {\n return join(\n homedir(),\n \"Library\",\n \"Application Support\",\n \"Claude\",\n \"claude_desktop_config.json\",\n );\n }\n if (os === \"win32\") {\n const appData = process.env.APPDATA ?? join(homedir(), \"AppData\", \"Roaming\");\n return join(appData, \"Claude\", \"claude_desktop_config.json\");\n }\n // Linux: no official Claude Desktop location yet\n return null;\n}\n\nexport function resolveClient(name: \"Cursor\" | \"Claude Desktop\"): McpClientInfo | null {\n if (name === \"Cursor\") {\n return { name, configPath: getCursorConfigPath() };\n }\n const configPath = getClaudeDesktopConfigPath();\n return configPath ? { name, configPath } : null;\n}\n\n// ── Writing ─────────────────────────────────────────────────────────────\n\nfunction readJsonSafe(path: string): Record<string, any> {\n if (!existsSync(path)) return {};\n try {\n return JSON.parse(readFileSync(path, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\n/**\n * Write or merge the Product Brain server entry into a client config file.\n * Migrates legacy \"productbrain\" key to \"Product Brain\" when present.\n * Returns true if the config was written, false if already present.\n */\nexport async function writeClientConfig(\n client: McpClientInfo,\n apiKey: string,\n): Promise<boolean> {\n const config = readJsonSafe(client.configPath);\n\n const serversKey = \"mcpServers\";\n if (!config[serversKey]) config[serversKey] = {};\n\n // Migrate legacy \"productbrain\" key or update existing Product Brain with new API key\n if (config[serversKey][LEGACY_ENTRY_KEY]) {\n const legacy = config[serversKey][LEGACY_ENTRY_KEY];\n config[serversKey][SERVER_ENTRY_KEY] = {\n ...buildServerEntry(apiKey),\n env: { ...legacy.env, PRODUCTBRAIN_API_KEY: legacy.env?.PRODUCTBRAIN_API_KEY ?? apiKey },\n };\n delete config[serversKey][LEGACY_ENTRY_KEY];\n } else {\n const existing = config[serversKey][SERVER_ENTRY_KEY];\n config[serversKey][SERVER_ENTRY_KEY] = existing\n ? { ...existing, env: { ...existing.env, PRODUCTBRAIN_API_KEY: apiKey } }\n : buildServerEntry(apiKey);\n }\n\n const dir = dirname(client.configPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n writeFileSync(client.configPath, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n return true;\n}\n"],"mappings":"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","names":["client"]}
|
|
@@ -1 +0,0 @@
|
|
|
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":[]}
|