@productbrain/mcp 0.0.1-beta.111 → 0.0.1-beta.122

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.
@@ -144,6 +144,22 @@ function trackCaptureClassifierAutoRouted(workspaceId, props) {
144
144
  function trackCaptureClassifierFallback(workspaceId, props) {
145
145
  trackCaptureClassifierEvent("mcp_capture_classifier_fallback", workspaceId, props);
146
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
+ }
147
163
  function trackKnowledgeGap(workspaceId, props) {
148
164
  if (!client) return;
149
165
  try {
@@ -251,6 +267,7 @@ export {
251
267
  trackCaptureClassifierEvaluated,
252
268
  trackCaptureClassifierAutoRouted,
253
269
  trackCaptureClassifierFallback,
270
+ trackChainEntryCommitted,
254
271
  trackKnowledgeGap,
255
272
  getPostHogClient,
256
273
  shutdownAnalytics,
@@ -258,4 +275,4 @@ export {
258
275
  resolveClient,
259
276
  writeClientConfig
260
277
  };
261
- //# sourceMappingURL=chunk-RQXM3TCI.js.map
278
+ //# sourceMappingURL=chunk-2ZWGQ6PK.js.map
@@ -0,0 +1 @@
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\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"]}
@@ -3,9 +3,10 @@ import {
3
3
  trackCaptureClassifierAutoRouted,
4
4
  trackCaptureClassifierEvaluated,
5
5
  trackCaptureClassifierFallback,
6
+ trackChainEntryCommitted,
6
7
  trackQualityVerdict,
7
8
  trackToolCall
8
- } from "./chunk-RQXM3TCI.js";
9
+ } from "./chunk-2ZWGQ6PK.js";
9
10
 
10
11
  // src/tools/smart-capture.ts
11
12
  import { z as z2 } from "zod";
@@ -570,6 +571,17 @@ function trackWriteTool(_tool) {
570
571
  // src/featureFlags.ts
571
572
  import { PostHog } from "posthog-node";
572
573
  var client = null;
574
+ var SERVER_FLAGS = {
575
+ "workspace-full-surface": { status: "active" },
576
+ "active-intelligence-shaping": { status: "active" },
577
+ "capture-without-thinking": { status: "active" },
578
+ "chainwork-enabled": { status: "active" },
579
+ "bet-203-roadmap-coordination": { status: "active" },
580
+ "bet-221-governance-at-scale": { status: "active" },
581
+ "bet-226-semantic-chunking": { status: "active" }
582
+ };
583
+ var REGISTERED_FLAGS_DEFAULT_ON = true;
584
+ var DEV_DEFAULT_ALL_ON = process.env.NODE_ENV === "development" && process.env.FLAGS_DEV_DEFAULT_ON === "true";
573
585
  var LOCAL_OVERRIDES = {
574
586
  // Uncomment for local dev without PostHog:
575
587
  // "workspace-full-surface": false,
@@ -597,6 +609,8 @@ function initFeatureFlags(posthogClient) {
597
609
  async function isFeatureEnabled(flag, workspaceId, workspaceSlug) {
598
610
  if (process.env.FEATURE_KILL_SWITCH === "true") return false;
599
611
  if (flag in LOCAL_OVERRIDES) return LOCAL_OVERRIDES[flag];
612
+ if (REGISTERED_FLAGS_DEFAULT_ON && flag in SERVER_FLAGS && SERVER_FLAGS[flag].status === "active") return true;
613
+ if (DEV_DEFAULT_ALL_ON) return true;
600
614
  if (!client) return false;
601
615
  try {
602
616
  const primary = await client.isFeatureEnabled(flag, workspaceId, {
@@ -968,12 +982,13 @@ var CLASSIFIABLE_COLLECTIONS = [
968
982
  "features",
969
983
  "architecture",
970
984
  "business-rules",
971
- "tracking-events",
985
+ // tracking-events: removed (Tier 1 Hierarchy — 0 entries, collection deprecated)
972
986
  "landscape",
973
987
  "standards",
974
988
  "principles",
975
989
  "assumptions",
976
- "bets"
990
+ "work-packages",
991
+ "patterns"
977
992
  ];
978
993
  var SIGNAL_WEIGHT = 10;
979
994
  var MIN_SCORE_FLOOR = 10;
@@ -1143,15 +1158,7 @@ var COLLECTION_SIGNALS = {
1143
1158
  "requires active session",
1144
1159
  "readiness excludes"
1145
1160
  ],
1146
- "tracking-events": [
1147
- "track",
1148
- "tracking",
1149
- "analytics",
1150
- "trigger",
1151
- "posthog",
1152
- "instrument",
1153
- "fires when"
1154
- ],
1161
+ // tracking-events: removed (Tier 1 Hierarchy — 0 entries, collection deprecated)
1155
1162
  landscape: [
1156
1163
  "competitor",
1157
1164
  "alternative tool",
@@ -1189,7 +1196,17 @@ var COLLECTION_SIGNALS = {
1189
1196
  "we assume",
1190
1197
  "needs validation"
1191
1198
  ],
1192
- bets: [
1199
+ patterns: [
1200
+ "pattern",
1201
+ "anti-pattern",
1202
+ "best practice",
1203
+ "reusable solution",
1204
+ "design pattern",
1205
+ "recurring solution",
1206
+ "template",
1207
+ "proven approach"
1208
+ ],
1209
+ "work-packages": [
1193
1210
  "appetite",
1194
1211
  "elements",
1195
1212
  "no-gos",
@@ -1493,7 +1510,8 @@ var PROFILES = /* @__PURE__ */ new Map([
1493
1510
  descriptionField: "rationale",
1494
1511
  defaults: [
1495
1512
  { key: "date", value: "today" },
1496
- { key: "decidedBy", value: "infer" }
1513
+ { key: "decidedBy", value: "infer" },
1514
+ { key: "confidence", value: "exploring" }
1497
1515
  ],
1498
1516
  recommendedRelationTypes: ["informs", "references", "replaces", "related_to"],
1499
1517
  inferField: (ctx) => {
@@ -1603,7 +1621,7 @@ var PROFILES = /* @__PURE__ */ new Map([
1603
1621
  COMMON_CHECKS.hasDescription
1604
1622
  ]
1605
1623
  }],
1606
- ["bets", {
1624
+ ["work-packages", {
1607
1625
  governedDraft: false,
1608
1626
  descriptionField: "description",
1609
1627
  defaults: [],
@@ -1953,7 +1971,7 @@ var batchCaptureSchema = z2.object({
1953
1971
  description: z2.string().describe("Full context / definition"),
1954
1972
  entryId: entryIdSchema,
1955
1973
  data: z2.record(z2.unknown()).optional().describe("Explicit field values (e.g. urgency, status, assignee). Merged with inferred values; user-provided wins."),
1956
- canonicalKey: z2.string().optional().describe("Semantic type (e.g. 'decision', 'tension', 'bet'). Enables bet-signal redirect in createEntry when collection is 'chains'.")
1974
+ canonicalKey: z2.string().optional().describe("Semantic type (e.g. 'decision', 'tension', 'work_package'). Enables work-package redirect in createEntry when collection is 'chains'.")
1957
1975
  })).min(1).max(50).describe("Array of entries to capture"),
1958
1976
  autoCommit: z2.boolean().optional().describe(
1959
1977
  "If true, commits created entries immediately after linking. If omitted, Open mode workspaces commit by default and consensus/role modes stay draft-first."
@@ -2338,9 +2356,9 @@ function registerSmartCaptureTools(server) {
2338
2356
  return buildCollectionRequiredResult();
2339
2357
  }
2340
2358
  if (resolvedCollection === "chains" && !canonicalKey && !explicitCollectionProvided && classifierMeta?.candidates?.some(
2341
- (c) => c.collection === "bets"
2359
+ (c) => c.collection === "work-packages"
2342
2360
  )) {
2343
- canonicalKey = "bet";
2361
+ canonicalKey = "work_package";
2344
2362
  }
2345
2363
  const tAfterClassify = Date.now();
2346
2364
  if (entryId && resolvedCollection !== "business-rules" && resolvedCollection !== "standards") {
@@ -2419,7 +2437,7 @@ Or use \`collections action=list\` to see available collections.`
2419
2437
  }
2420
2438
  }
2421
2439
  data[profile.descriptionField || "description"] = description;
2422
- const isBetCapture = canonicalKey === "bet" || resolvedCollection === "bets";
2440
+ const isBetCapture = canonicalKey === "work_package" || resolvedCollection === "work-packages";
2423
2441
  let entryWarnings = [];
2424
2442
  const shouldDecompose = (resolvedCollection === "strategy" || isBetCapture) && description.trim().length > 0;
2425
2443
  if (shouldDecompose) {
@@ -2431,7 +2449,7 @@ Or use \`collections action=list\` to see available collections.`
2431
2449
  entryName: name,
2432
2450
  description,
2433
2451
  existingData: data,
2434
- ...isBetCapture ? { canonicalKey: "bet" } : {}
2452
+ ...isBetCapture ? { canonicalKey: "work_package" } : {}
2435
2453
  }
2436
2454
  );
2437
2455
  if (decomposed?.decomposed) {
@@ -2671,6 +2689,12 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
2671
2689
  finalStatus = commitResult?.status === "proposal_created" ? "proposed" : "committed";
2672
2690
  if (finalStatus === "committed") {
2673
2691
  await recordSessionActivity({ entryModified: internalId });
2692
+ trackChainEntryCommitted(wsCtx.workspaceId, {
2693
+ entry_id: finalEntryId,
2694
+ collection: resolvedCollection,
2695
+ commit_method: "auto",
2696
+ surface: "mcp_capture"
2697
+ });
2674
2698
  }
2675
2699
  } catch (e) {
2676
2700
  commitError = e instanceof Error ? e.message : "unknown error";
@@ -2705,7 +2729,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
2705
2729
  }
2706
2730
  }
2707
2731
  }
2708
- const appUrl = process.env.PRODUCTBRAIN_APP_URL ?? "https://productbrain.io";
2732
+ const appUrl = process.env.PRODUCTBRAIN_APP_URL ?? "https://work.productbrain.io";
2709
2733
  const studioUrl = resolvedCollection === "chains" ? `${appUrl.replace(/\/$/, "")}/w/${wsCtx.workspaceSlug}/legacy/${internalId}` : void 0;
2710
2734
  if (studioUrl) {
2711
2735
  lines.push("");
@@ -3030,7 +3054,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
3030
3054
  if (v !== void 0 && v !== null && v !== "") data[k] = v;
3031
3055
  }
3032
3056
  }
3033
- const batchIsBet = resolvedSlug === "bets" || entry.canonicalKey === "bet";
3057
+ const batchIsBet = resolvedSlug === "work-packages" || entry.canonicalKey === "work_package";
3034
3058
  const shouldDecomposeBatch = (resolvedSlug === "strategy" || batchIsBet) && entry.description?.trim();
3035
3059
  let batchDecomposeWarning;
3036
3060
  if (shouldDecomposeBatch) {
@@ -3042,7 +3066,7 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
3042
3066
  entryName: entry.name,
3043
3067
  description: entry.description,
3044
3068
  existingData: data,
3045
- ...batchIsBet ? { canonicalKey: "bet" } : {}
3069
+ ...batchIsBet ? { canonicalKey: "work_package" } : {}
3046
3070
  }
3047
3071
  );
3048
3072
  if (decomposed?.decomposed) {
@@ -3116,6 +3140,12 @@ Use \`entries action=get\` to inspect the existing entry, or \`update-entry\` to
3116
3140
  finalStatus = commitResult?.status === "proposal_created" ? "proposed" : "committed";
3117
3141
  if (finalStatus === "committed") {
3118
3142
  await recordSessionActivity({ entryModified: internalId });
3143
+ trackChainEntryCommitted(wsCtx.workspaceId, {
3144
+ entry_id: finalEntryId,
3145
+ collection: resolvedSlug ?? void 0,
3146
+ commit_method: "auto",
3147
+ surface: "mcp_capture"
3148
+ });
3119
3149
  }
3120
3150
  } catch (error) {
3121
3151
  commitError = error instanceof Error ? error.message : String(error);
@@ -3577,6 +3607,7 @@ export {
3577
3607
  initToolSurface,
3578
3608
  trackWriteTool,
3579
3609
  initFeatureFlags,
3610
+ isFeatureEnabled,
3580
3611
  recordGap,
3581
3612
  getSessionGaps,
3582
3613
  getTopGaps,
@@ -3609,4 +3640,4 @@ export {
3609
3640
  formatRubricCoaching,
3610
3641
  formatRubricVerdictSection
3611
3642
  };
3612
- //# sourceMappingURL=chunk-DHBJFEAT.js.map
3643
+ //# sourceMappingURL=chunk-G4WJIWXX.js.map