@productbrain/mcp 0.0.1-beta.40 → 0.0.1-beta.42

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.
@@ -4,7 +4,7 @@ import {
4
4
  trackCaptureClassifierFallback,
5
5
  trackQualityVerdict,
6
6
  trackToolCall
7
- } from "./chunk-P7ABQEFK.js";
7
+ } from "./chunk-6R67YS23.js";
8
8
 
9
9
  // src/tools/smart-capture.ts
10
10
  import { z } from "zod";
@@ -2321,4 +2321,4 @@ export {
2321
2321
  formatRubricCoaching,
2322
2322
  formatRubricVerdictSection
2323
2323
  };
2324
- //# sourceMappingURL=chunk-M264FY2V.js.map
2324
+ //# sourceMappingURL=chunk-4YKORBQX.js.map
@@ -9,8 +9,15 @@ function log(msg) {
9
9
  process.stderr.write(msg);
10
10
  }
11
11
  }
12
+ function getBuildTimeKey() {
13
+ try {
14
+ return "";
15
+ } catch {
16
+ return "";
17
+ }
18
+ }
12
19
  function initAnalytics() {
13
- const apiKey = process.env.POSTHOG_MCP_KEY || "";
20
+ const apiKey = process.env.POSTHOG_MCP_KEY || getBuildTimeKey();
14
21
  if (!apiKey) {
15
22
  log("[MCP-ANALYTICS] No PostHog key \u2014 tracking disabled (set SYNERGYOS_POSTHOG_KEY at build time for publish)\n");
16
23
  return;
@@ -158,4 +165,4 @@ export {
158
165
  getPostHogClient,
159
166
  shutdownAnalytics
160
167
  };
161
- //# sourceMappingURL=chunk-P7ABQEFK.js.map
168
+ //# sourceMappingURL=chunk-6R67YS23.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/analytics.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\nexport function getPostHogClient(): PostHog | null {\n return client;\n}\n\nexport async function shutdownAnalytics(): Promise<void> {\n await client?.shutdown();\n}\n"],"mappings":"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","names":[]}
@@ -25,11 +25,11 @@ import {
25
25
  startAgentSession,
26
26
  trackWriteTool,
27
27
  translateStaleToolNames
28
- } from "./chunk-M264FY2V.js";
28
+ } from "./chunk-4YKORBQX.js";
29
29
  import {
30
30
  trackQualityCheck,
31
31
  trackQualityVerdict
32
- } from "./chunk-P7ABQEFK.js";
32
+ } from "./chunk-6R67YS23.js";
33
33
 
34
34
  // src/server.ts
35
35
  import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -61,7 +61,7 @@ var updateEntrySchema = z.object({
61
61
  z.enum(["draft", "active", "deprecated", "archived"]),
62
62
  z.enum(["open", "pending", "decided", "proposed", "accepted", "needs-amendment", "withdrawn", "review", "in-progress", "conflict", "processing", "closed", "shaped", "bet", "building", "shipped"])
63
63
  ]).optional().describe("Lifecycle status: draft | active | deprecated | archived. **Workflow values (open, pending, decided\u2026) are deprecated here \u2014 use `workflowStatus` instead. Passing a workflow value as `status` will be auto-routed with a warning until 2026-09-03, then hard-errored.**"),
64
- workflowStatus: z.enum(["open", "pending", "proposed", "accepted", "needs-amendment", "withdrawn", "review", "in-progress", "decided", "conflict", "processing", "closed"]).optional().describe("Collection workflow state (e.g. 'open', 'pending', 'decided', 'conflict'). Validated against collection's allowed values."),
64
+ workflowStatus: z.enum(["open", "pending", "proposed", "accepted", "needs-amendment", "withdrawn", "review", "in-progress", "decided", "conflict", "processing", "closed", "shaped", "bet", "building", "shipped"]).optional().describe("Collection workflow state (e.g. 'open', 'pending', 'decided', 'conflict', 'building', 'shipped'). Validated against collection's allowed values."),
65
65
  data: z.record(z.unknown()).optional().describe("Fields to update (merged with existing data)"),
66
66
  order: z.number().optional().describe("New sort order"),
67
67
  canonicalKey: z.string().optional().describe("Semantic type (e.g. 'decision', 'tension'). Only changeable on draft/uncommitted entries."),
@@ -195,7 +195,7 @@ ${formatted}` }]
195
195
  },
196
196
  async ({ entryId }) => {
197
197
  requireWriteAccess();
198
- const { runContradictionCheck } = await import("./smart-capture-GH4CXVVX.js");
198
+ const { runContradictionCheck } = await import("./smart-capture-TD5M4WFE.js");
199
199
  const entry = await mcpQuery("chain.getEntry", { entryId });
200
200
  if (!entry) {
201
201
  return {
@@ -4121,6 +4121,7 @@ async function handleStart2(args) {
4121
4121
  const sc = orient?.strategicContext;
4122
4122
  const parts = [];
4123
4123
  if (sc?.vision) parts.push(`Vision: ${sc.vision}`);
4124
+ if (sc?.purpose) parts.push(`Purpose: ${sc.purpose}`);
4124
4125
  if (sc?.activeBetCount) parts.push(`${sc.activeBetCount} active bet(s)`);
4125
4126
  if (sc?.activeTensionCount) parts.push(`${sc.activeTensionCount} open tension(s)`);
4126
4127
  if (orient?.activeBets?.length) {
@@ -4403,6 +4404,7 @@ async function handleRespond(args) {
4403
4404
  persist("problem_clarity", "problem", 50);
4404
4405
  persist("appetite", "appetite", 20);
4405
4406
  persist("architecture", "architecture", 50);
4407
+ persist("done_when", "done_when", 30);
4406
4408
  if (!refreshedData._overlapIds) {
4407
4409
  fieldUpdates._overlapIds = overlapIds.length > 0 ? overlapIds.join(",") : "_checked";
4408
4410
  }
@@ -4448,6 +4450,21 @@ async function handleRespond(args) {
4448
4450
  relatedTensions: chainSurfaced.filter((e) => e.collection === "tensions").map((e) => ({ entryId: e.entryId, name: e.name }))
4449
4451
  };
4450
4452
  buildContract = generateBuildContract(contractCtx);
4453
+ if (refreshedData.buildContract !== buildContract) {
4454
+ try {
4455
+ await mcpMutation("chain.updateEntry", {
4456
+ entryId: betId,
4457
+ data: { buildContract },
4458
+ changeNote: "Updated build contract from shaping session"
4459
+ });
4460
+ await recordSessionActivity({ entryModified: refreshedBet?._id ?? betEntry._id });
4461
+ } catch (updErr) {
4462
+ captureErrors.push({
4463
+ operation: "update",
4464
+ detail: `buildContract field: ${updErr instanceof Error ? updErr.message : String(updErr)}`
4465
+ });
4466
+ }
4467
+ }
4451
4468
  }
4452
4469
  let commitBlockers;
4453
4470
  if (captureReady) {
@@ -4735,7 +4752,6 @@ ${directive}` : ""
4735
4752
  async function handleCommitConstellation(args) {
4736
4753
  requireWriteAccess();
4737
4754
  const betId = args.betEntryId;
4738
- const operationId = args.operationId ?? `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
4739
4755
  if (!betId) {
4740
4756
  return {
4741
4757
  content: [{ type: "text", text: "`betEntryId` is required for commit-constellation action." }]
@@ -4748,6 +4764,7 @@ async function handleCommitConstellation(args) {
4748
4764
  };
4749
4765
  }
4750
4766
  const betData = betEntry.data ?? {};
4767
+ const operationId = args.operationId ?? `${betId}:${getAgentSessionId() ?? "sessionless"}:${betEntry.status}:${betEntry.currentVersion ?? 0}`;
4751
4768
  const relations = await mcpQuery("chain.listEntryRelations", {
4752
4769
  entryId: betId
4753
4770
  });
@@ -4784,7 +4801,7 @@ async function handleCommitConstellation(args) {
4784
4801
  }
4785
4802
  let contradictionWarnings = [];
4786
4803
  try {
4787
- const { runContradictionCheck } = await import("./smart-capture-GH4CXVVX.js");
4804
+ const { runContradictionCheck } = await import("./smart-capture-TD5M4WFE.js");
4788
4805
  const descField = betData.problem ?? betData.description ?? "";
4789
4806
  contradictionWarnings = await runContradictionCheck(
4790
4807
  betEntry.name ?? betId,
@@ -4823,6 +4840,7 @@ No constellation entries were committed.`
4823
4840
  await recordSessionActivity({ entryModified: entryId });
4824
4841
  }
4825
4842
  const lines = [];
4843
+ const hasIssues = result.failedIds.length > 0 || result.conflictIds.length > 0;
4826
4844
  if (result.proposalCreated) {
4827
4845
  const linkedCount = result.committedIds.filter((id) => id !== betId).length;
4828
4846
  lines.push(
@@ -4833,10 +4851,10 @@ No constellation entries were committed.`
4833
4851
  );
4834
4852
  } else {
4835
4853
  lines.push(
4836
- `# Published`,
4854
+ hasIssues ? `# Published with issues` : `# Published`,
4837
4855
  "",
4838
4856
  `**${result.committedIds.length} entries** committed to the Chain, **${result.totalRelations} connections** preserved.`,
4839
- `\`${betId}\` and its full constellation are now source of truth.`
4857
+ hasIssues ? `\`${betId}\` was partially committed. Review conflicts/failed entries below before considering the constellation complete.` : `\`${betId}\` and its full constellation are now source of truth.`
4840
4858
  );
4841
4859
  }
4842
4860
  if (contradictionWarnings.length > 0) {
@@ -8061,6 +8079,7 @@ function registerHealthTools(server) {
8061
8079
  if (orientEntries?.strategicContext) {
8062
8080
  const sc = orientEntries.strategicContext;
8063
8081
  if (sc.vision) lines.push(`Vision: ${sc.vision}`);
8082
+ if (sc.purpose) lines.push(`Purpose: ${sc.purpose}`);
8064
8083
  if (sc.productAreaCount != null && sc.productAreaCount > 0) {
8065
8084
  lines.push(`Product areas (${sc.productAreaCount}): ${(sc.productAreas ?? []).join(", ")}`);
8066
8085
  }
@@ -8156,6 +8175,7 @@ function registerHealthTools(server) {
8156
8175
  const sc = orientEntries.strategicContext;
8157
8176
  lines.push("## Strategic Context");
8158
8177
  if (sc.vision) lines.push(`**Vision:** ${sc.vision}`);
8178
+ if (sc.purpose) lines.push(`**Purpose:** ${sc.purpose}`);
8159
8179
  if (sc.productAreaCount != null && sc.productAreaCount > 0) {
8160
8180
  lines.push(`**Product areas (${sc.productAreaCount}):** ${(sc.productAreas ?? []).join(", ")}`);
8161
8181
  }
@@ -9106,6 +9126,8 @@ Description field: ${wf.kbOutputTemplate.descriptionField}
9106
9126
  const orient = await mcpQuery("chain.getOrientEntries", {});
9107
9127
  const sc = orient?.strategicContext;
9108
9128
  if (sc?.vision) strategicContext += `**Vision:** ${sc.vision}
9129
+ `;
9130
+ if (sc?.purpose) strategicContext += `**Purpose:** ${sc.purpose}
9109
9131
  `;
9110
9132
  if (sc?.currentBet) strategicContext += `**Current bet:** ${sc.currentBet}
9111
9133
  `;
@@ -9671,4 +9693,4 @@ export {
9671
9693
  SERVER_VERSION,
9672
9694
  createProductBrainServer
9673
9695
  };
9674
- //# sourceMappingURL=chunk-6WVRGNJU.js.map
9696
+ //# sourceMappingURL=chunk-X7DON33G.js.map