@alisaitteke/photoshop-mcp 1.3.0 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +3 -59
  2. package/dist/analytics/client-ip.d.ts +5 -0
  3. package/dist/analytics/client-ip.d.ts.map +1 -0
  4. package/dist/analytics/client-ip.js +39 -0
  5. package/dist/analytics/client-ip.js.map +1 -0
  6. package/dist/analytics/events.d.ts +2 -0
  7. package/dist/analytics/events.d.ts.map +1 -1
  8. package/dist/analytics/events.js +55 -8
  9. package/dist/analytics/events.js.map +1 -1
  10. package/dist/analytics/index.d.ts +9 -3
  11. package/dist/analytics/index.d.ts.map +1 -1
  12. package/dist/analytics/index.js +15 -1
  13. package/dist/analytics/index.js.map +1 -1
  14. package/dist/analytics/locale.d.ts +6 -0
  15. package/dist/analytics/locale.d.ts.map +1 -0
  16. package/dist/analytics/locale.js +19 -0
  17. package/dist/analytics/locale.js.map +1 -0
  18. package/dist/analytics/mcp-session.d.ts +12 -0
  19. package/dist/analytics/mcp-session.d.ts.map +1 -0
  20. package/dist/analytics/mcp-session.js +118 -0
  21. package/dist/analytics/mcp-session.js.map +1 -0
  22. package/dist/analytics/noop.d.ts +1 -0
  23. package/dist/analytics/noop.d.ts.map +1 -1
  24. package/dist/analytics/noop.js +3 -0
  25. package/dist/analytics/noop.js.map +1 -1
  26. package/dist/analytics/pageview.d.ts +3 -0
  27. package/dist/analytics/pageview.d.ts.map +1 -0
  28. package/dist/analytics/pageview.js +31 -0
  29. package/dist/analytics/pageview.js.map +1 -0
  30. package/dist/analytics/posthog-node.d.ts +3 -0
  31. package/dist/analytics/posthog-node.d.ts.map +1 -1
  32. package/dist/analytics/posthog-node.js +23 -1
  33. package/dist/analytics/posthog-node.js.map +1 -1
  34. package/dist/analytics/runtime-env.d.ts +5 -0
  35. package/dist/analytics/runtime-env.d.ts.map +1 -0
  36. package/dist/analytics/runtime-env.js +63 -0
  37. package/dist/analytics/runtime-env.js.map +1 -0
  38. package/dist/analytics/types.d.ts +2 -0
  39. package/dist/analytics/types.d.ts.map +1 -1
  40. package/dist/core/server.d.ts +2 -0
  41. package/dist/core/server.d.ts.map +1 -1
  42. package/dist/core/server.js +42 -6
  43. package/dist/core/server.js.map +1 -1
  44. package/dist/core/session.d.ts +1 -0
  45. package/dist/core/session.d.ts.map +1 -1
  46. package/dist/core/session.js +12 -1
  47. package/dist/core/session.js.map +1 -1
  48. package/dist/errors/envelope.d.ts +1 -1
  49. package/dist/errors/envelope.d.ts.map +1 -1
  50. package/dist/errors/envelope.js +37 -4
  51. package/dist/errors/envelope.js.map +1 -1
  52. package/dist/index.js +41 -5
  53. package/dist/index.js.map +1 -1
  54. package/dist/ui/cli.js +7 -1
  55. package/dist/ui/cli.js.map +1 -1
  56. package/dist/ui/server.d.ts.map +1 -1
  57. package/dist/ui/server.js +2 -1
  58. package/dist/ui/server.js.map +1 -1
  59. package/dist/ui/store/db.js +2 -2
  60. package/dist/ui/store/db.js.map +1 -1
  61. package/package.json +1 -1
  62. package/web/dist/assets/index-n0ymP-Cw.js +249 -0
  63. package/web/dist/index.html +1 -1
  64. package/web/dist/assets/index-BuJJLllx.js +0 -249
package/README.md CHANGED
@@ -644,65 +644,9 @@ MIT
644
644
 
645
645
  ## Anonymous Usage Analytics
646
646
 
647
- This project collects **anonymous, aggregated usage events** to understand how the
648
- MCP server and standalone UI are used and to improve the product. Analytics are
649
- **enabled by default** and can be turned off at any time.
650
-
651
- ### What we collect
652
-
653
- - App version, operating system, and Node.js version
654
- - Startup signals (MCP server or UI server started, Photoshop detected or not)
655
- - Setup funnel events (provider chosen, auth method, validation success/failure
656
- codes — not credentials)
657
- - Generic UI events (app loaded, onboarding completed)
658
-
659
- Events use a random anonymous identifier stored locally at
660
- `~/.photoshop-mcp/` (SQLite `kv` table and/or `analytics-store.json`). We do
661
- **not** call `identify()` — no person profiles are created for anonymous usage
662
- (`person_profiles: identified_only`).
663
-
664
- ### What we do **not** collect (unless you opt into beta team sharing)
665
-
666
- - API keys or OAuth tokens
667
- - Chat messages, prompts, or model responses **by default**
668
- - Photoshop document or layer names, file paths, or image content
669
- - CLI account labels, email addresses, or other account identifiers
670
- - Tool call arguments or results
671
-
672
- ### Beta team content sharing (opt-in)
673
-
674
- On first launch of the standalone UI, you are asked whether you want to **join the
675
- beta team**. This is separate from anonymous usage analytics above.
676
-
677
- If you accept:
678
-
679
- - Your **prompts**, **assistant responses**, **reasoning text**, and **tool names**
680
- (not arguments or results) may be sent to PostHog after each chat turn
681
- - Content is truncated for very long messages
682
- - Requires anonymous analytics to remain enabled
683
-
684
- If you decline, no chat content is logged. You can change this later in
685
- **Settings → General → Privacy → Beta team content sharing**.
686
-
687
- Existing installs that have not answered yet are prompted once on the next launch.
688
-
689
- ### Processor and hosting
690
-
691
- Analytics are processed by [PostHog](https://posthog.com/). Events are sent to a
692
- managed reverse proxy at `https://a.alisait.com`; the PostHog project UI is
693
- hosted in the EU (`https://eu.posthog.com`). See the
694
- [PostHog privacy policy](https://posthog.com/privacy) for how PostHog handles
695
- data on their side.
696
-
697
- ### How to opt out
698
-
699
- 1. **Standalone UI:** Settings → General → Privacy → set **Anonymous usage
700
- analytics** to **Off** (also disables beta content sharing).
701
- 2. **Beta content only:** Settings → General → Privacy → set **Beta team content
702
- sharing** to **Off** (anonymous analytics can stay on).
703
- 3. **Environment variable:** set `POSTHOG_DISABLED=1` before starting
704
- `photoshop-mcp` or `photoshop-mcp-ui` (disables all analytics for that
705
- process and persists opt-out in local storage).
647
+ Anonymous, aggregated usage events are collected by default to improve the
648
+ product. You can opt out at any time. Full details:
649
+ [`docs/anonymous-usage-analytics.md`](docs/anonymous-usage-analytics.md).
706
650
 
707
651
  ## Acknowledgments
708
652
 
@@ -0,0 +1,5 @@
1
+ /** Best-effort client IP from an incoming HTTP request (may be loopback for local UI). */
2
+ export declare function resolveClientIp(headers: Headers): string | undefined;
3
+ /** GeoIP enrichment only makes sense for a routable public client address. */
4
+ export declare function isPublicClientIp(ip: string | undefined): boolean;
5
+ //# sourceMappingURL=client-ip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-ip.d.ts","sourceRoot":"","sources":["../../src/analytics/client-ip.ts"],"names":[],"mappings":"AAYA,0FAA0F;AAC1F,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAapE;AAED,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAGhE"}
@@ -0,0 +1,39 @@
1
+ function isLoopbackOrPrivateIp(ip) {
2
+ const normalized = ip.trim().toLowerCase();
3
+ if (!normalized)
4
+ return true;
5
+ if (normalized === '::1' || normalized === 'localhost')
6
+ return true;
7
+ if (normalized.startsWith('127.'))
8
+ return true;
9
+ if (normalized.startsWith('10.'))
10
+ return true;
11
+ if (normalized.startsWith('192.168.'))
12
+ return true;
13
+ if (/^172\.(1[6-9]|2\d|3[01])\./.test(normalized))
14
+ return true;
15
+ if (normalized.startsWith('fc') || normalized.startsWith('fd'))
16
+ return true;
17
+ return false;
18
+ }
19
+ /** Best-effort client IP from an incoming HTTP request (may be loopback for local UI). */
20
+ export function resolveClientIp(headers) {
21
+ const candidates = [
22
+ headers.get('cf-connecting-ip'),
23
+ headers.get('x-real-ip'),
24
+ ...(headers.get('x-forwarded-for')?.split(',') ?? []),
25
+ ];
26
+ for (const raw of candidates) {
27
+ const ip = raw?.trim();
28
+ if (ip)
29
+ return ip;
30
+ }
31
+ return undefined;
32
+ }
33
+ /** GeoIP enrichment only makes sense for a routable public client address. */
34
+ export function isPublicClientIp(ip) {
35
+ if (!ip)
36
+ return false;
37
+ return !isLoopbackOrPrivateIp(ip);
38
+ }
39
+ //# sourceMappingURL=client-ip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-ip.js","sourceRoot":"","sources":["../../src/analytics/client-ip.ts"],"names":[],"mappings":"AAAA,SAAS,qBAAqB,CAAC,EAAU;IACvC,MAAM,UAAU,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAC7B,IAAI,UAAU,KAAK,KAAK,IAAI,UAAU,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IACpE,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,IAAI,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,IAAI,UAAU,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,4BAA4B,CAAC,IAAI,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/D,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5E,OAAO,KAAK,CAAC;AACf,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,eAAe,CAAC,OAAgB;IAC9C,MAAM,UAAU,GAAG;QACjB,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;QAC/B,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;QACxB,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;KACtD,CAAC;IAEF,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,MAAM,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC;QACvB,IAAI,EAAE;YAAE,OAAO,EAAE,CAAC;IACpB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,gBAAgB,CAAC,EAAsB;IACrD,IAAI,CAAC,EAAE;QAAE,OAAO,KAAK,CAAC;IACtB,OAAO,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC;AACpC,CAAC"}
@@ -1,3 +1,5 @@
1
1
  export declare function sanitizeAnalyticsProperties(properties: Record<string, unknown> | undefined): Record<string, string | number | boolean>;
2
2
  export declare function buildRuntimeProperties(properties: Record<string, unknown> | undefined): Record<string, string | number | boolean>;
3
+ /** Person-profile fields merged on PostHog identify() — includes install-level hardware signals. */
4
+ export declare function buildPersonIdentifyProperties(properties?: Record<string, unknown>): Record<string, string | number | boolean>;
3
5
  //# sourceMappingURL=events.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/analytics/events.ts"],"names":[],"mappings":"AAiDA,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC9C,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAc3C;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC9C,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAS3C"}
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/analytics/events.ts"],"names":[],"mappings":"AA6FA,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC9C,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAa3C;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC9C,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAO3C;AAED,oGAAoG;AACpG,wBAAgB,6BAA6B,CAC3C,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAK3C"}
@@ -1,5 +1,6 @@
1
1
  import { getServerAnalyticsContext } from './context.js';
2
2
  import { getLaunchMethod } from './launch-method.js';
3
+ import { buildAnonymousRuntimeEnv, getTotalRamGb } from './runtime-env.js';
3
4
  const BLOCKED_PROPERTY_KEYS = new Set([
4
5
  'api_key',
5
6
  'apikey',
@@ -29,6 +30,7 @@ const ALLOWED_PROPERTY_KEYS = new Set([
29
30
  'ok',
30
31
  'error_code',
31
32
  'photoshop_detected',
33
+ 'photoshop_connected',
32
34
  'action_plan_enabled',
33
35
  'event_source',
34
36
  'port',
@@ -43,33 +45,78 @@ const ALLOWED_PROPERTY_KEYS = new Set([
43
45
  'beta_telemetry_opt_in',
44
46
  'theme',
45
47
  'launch_method',
48
+ 'browser_language',
49
+ 'browser_timezone',
50
+ 'browser_locale_region',
51
+ 'system_locale',
52
+ 'system_locale_region',
53
+ 'system_locale_language',
54
+ 'system_timezone',
55
+ 'os_type',
56
+ 'os_release',
57
+ 'cpu_count',
58
+ 'memory_gb',
59
+ 'total_ram_gb',
60
+ 'photoshop_version',
61
+ 'node_major',
62
+ 'is_electron',
63
+ 'photoshop_path_configured',
64
+ 'custom_data_dir_configured',
65
+ 'tool_name',
66
+ 'duration_ms',
67
+ 'usage_surface',
68
+ 'shutdown_reason',
69
+ 'tools_registered_count',
70
+ 'prompt_name',
71
+ 'tools_called_count',
72
+ 'tools_error_count',
73
+ 'unique_tools_count',
74
+ 'tool_usage_summary',
75
+ 'error_codes_summary',
76
+ 'batch_flush_reason',
46
77
  ]);
78
+ const POSTHOG_RESERVED_PROPERTY_KEYS = new Set([
79
+ '$current_url',
80
+ '$pathname',
81
+ '$screen_name',
82
+ ]);
83
+ function isAllowedAnalyticsPropertyKey(key) {
84
+ const normalized = key.toLowerCase();
85
+ if (BLOCKED_PROPERTY_KEYS.has(normalized))
86
+ return false;
87
+ if (ALLOWED_PROPERTY_KEYS.has(normalized))
88
+ return true;
89
+ return POSTHOG_RESERVED_PROPERTY_KEYS.has(key);
90
+ }
47
91
  export function sanitizeAnalyticsProperties(properties) {
48
92
  if (!properties)
49
93
  return {};
50
94
  const out = {};
51
95
  for (const [key, value] of Object.entries(properties)) {
52
- const normalized = key.toLowerCase();
53
- if (BLOCKED_PROPERTY_KEYS.has(normalized))
54
- continue;
55
- if (!ALLOWED_PROPERTY_KEYS.has(normalized))
96
+ if (!isAllowedAnalyticsPropertyKey(key))
56
97
  continue;
57
98
  if (value === null || value === undefined)
58
99
  continue;
59
100
  if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
60
- out[normalized] = value;
101
+ const outKey = POSTHOG_RESERVED_PROPERTY_KEYS.has(key) ? key : key.toLowerCase();
102
+ out[outKey] = value;
61
103
  }
62
104
  }
63
105
  return out;
64
106
  }
65
107
  export function buildRuntimeProperties(properties) {
66
108
  return {
67
- os: process.platform,
68
- arch: process.arch,
69
- node_version: process.version,
109
+ ...buildAnonymousRuntimeEnv(),
70
110
  launch_method: getLaunchMethod(),
71
111
  ...getServerAnalyticsContext(),
72
112
  ...sanitizeAnalyticsProperties(properties),
73
113
  };
74
114
  }
115
+ /** Person-profile fields merged on PostHog identify() — includes install-level hardware signals. */
116
+ export function buildPersonIdentifyProperties(properties) {
117
+ return buildRuntimeProperties({
118
+ total_ram_gb: getTotalRamGb(),
119
+ ...properties,
120
+ });
121
+ }
75
122
  //# sourceMappingURL=events.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/analytics/events.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;IACpC,SAAS;IACT,QAAQ;IACR,KAAK;IACL,OAAO;IACP,QAAQ;IACR,UAAU;IACV,OAAO;IACP,eAAe;IACf,UAAU;IACV,MAAM;IACN,WAAW;IACX,UAAU;IACV,SAAS;IACT,SAAS;IACT,QAAQ;IACR,SAAS;IACT,YAAY;CACb,CAAC,CAAC;AAEH,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;IACpC,aAAa;IACb,IAAI;IACJ,MAAM;IACN,cAAc;IACd,aAAa;IACb,aAAa;IACb,IAAI;IACJ,YAAY;IACZ,oBAAoB;IACpB,qBAAqB;IACrB,cAAc;IACd,MAAM;IACN,MAAM;IACN,SAAS;IACT,UAAU;IACV,iBAAiB;IACjB,WAAW;IACX,UAAU;IACV,cAAc;IACd,mBAAmB;IACnB,uBAAuB;IACvB,OAAO;IACP,eAAe;CAChB,CAAC,CAAC;AAEH,MAAM,UAAU,2BAA2B,CACzC,UAA+C;IAE/C,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC;IAE3B,MAAM,GAAG,GAA8C,EAAE,CAAC;IAC1D,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACtD,MAAM,UAAU,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;QACrC,IAAI,qBAAqB,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,SAAS;QACpD,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,UAAU,CAAC;YAAE,SAAS;QACrD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QACpD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;YACzF,GAAG,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,UAA+C;IAE/C,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,QAAQ;QACpB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,YAAY,EAAE,OAAO,CAAC,OAAO;QAC7B,aAAa,EAAE,eAAe,EAAE;QAChC,GAAG,yBAAyB,EAAE;QAC9B,GAAG,2BAA2B,CAAC,UAAU,CAAC;KAC3C,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/analytics/events.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,16 @@
1
1
  import { captureBetaChatTurn } from './beta-telemetry.js';
2
2
  import { getBetaTelemetryState, setBetaTelemetryChoice } from './identity.js';
3
+ import { endMcpAnalyticsSession, recordMcpToolCall, startMcpAnalyticsSession } from './mcp-session.js';
4
+ import { captureMcpPageleave, captureMcpPageview } from './pageview.js';
3
5
  import { getAnalytics, resetAnalyticsProvider } from './provider.js';
4
- import type { AnalyticsEvent, AnalyticsProvider, AnalyticsRuntimeConfig, BetaTelemetryState } from './types.js';
6
+ import type { AnalyticsEvent, AnalyticsProvider, AnalyticsRuntimeConfig, BetaTelemetryState, UsageSurface } from './types.js';
7
+ export type { McpShutdownReason } from './mcp-session.js';
8
+ /** Persist the install ID and register one anonymous PostHog person per process. */
9
+ export declare function ensureAnalyticsIdentity(): void;
5
10
  export declare function capture(name: string, properties?: Record<string, unknown>): void;
11
+ export declare function identifyAnalyticsPerson(properties?: Record<string, unknown>): void;
6
12
  export declare function shutdownAnalytics(): Promise<void>;
7
13
  export declare function getAnalyticsRuntimeConfig(): AnalyticsRuntimeConfig;
8
- export { captureBetaChatTurn, getAnalytics, getBetaTelemetryState, resetAnalyticsProvider, setBetaTelemetryChoice, };
9
- export type { AnalyticsEvent, AnalyticsProvider, AnalyticsRuntimeConfig, BetaTelemetryState };
14
+ export { captureBetaChatTurn, captureMcpPageleave, captureMcpPageview, endMcpAnalyticsSession, getAnalytics, getBetaTelemetryState, recordMcpToolCall, resetAnalyticsProvider, setBetaTelemetryChoice, startMcpAnalyticsSession, };
15
+ export type { AnalyticsEvent, AnalyticsProvider, AnalyticsRuntimeConfig, BetaTelemetryState, UsageSurface, };
10
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analytics/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAQ1D,OAAO,EACL,qBAAqB,EAGrB,sBAAsB,EACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAA2B,MAAM,eAAe,CAAC;AAC9F,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAEpB,wBAAgB,OAAO,CACrB,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,IAAI,CAMN;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEvD;AAED,wBAAgB,yBAAyB,IAAI,sBAAsB,CAYlE;AAED,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,qBAAqB,EACrB,sBAAsB,EACtB,sBAAsB,GACvB,CAAC;AACF,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analytics/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAQ1D,OAAO,EACL,qBAAqB,EAGrB,sBAAsB,EACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAA2B,MAAM,eAAe,CAAC;AAC9F,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,kBAAkB,EAClB,YAAY,EACb,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,oFAAoF;AACpF,wBAAgB,uBAAuB,IAAI,IAAI,CAI9C;AAED,wBAAgB,OAAO,CACrB,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,IAAI,CAMN;AAED,wBAAgB,uBAAuB,CACrC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,IAAI,CAGN;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEvD;AAED,wBAAgB,yBAAyB,IAAI,sBAAsB,CAYlE;AAED,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,GACzB,CAAC;AACF,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,kBAAkB,EAClB,YAAY,GACb,CAAC"}
@@ -2,7 +2,16 @@ import { captureBetaChatTurn } from './beta-telemetry.js';
2
2
  import { hasPostHogKey, resolvePostHogApiHost, resolvePostHogKey, resolvePostHogUiHost, } from './config.js';
3
3
  import { buildRuntimeProperties } from './events.js';
4
4
  import { getBetaTelemetryState, getOrCreateDistinctId, isAnalyticsEnabled, setBetaTelemetryChoice, } from './identity.js';
5
+ import { endMcpAnalyticsSession, recordMcpToolCall, startMcpAnalyticsSession, } from './mcp-session.js';
6
+ import { captureMcpPageleave, captureMcpPageview } from './pageview.js';
5
7
  import { getAnalytics, resetAnalyticsProvider, shutdownAnalyticsClient } from './provider.js';
8
+ /** Persist the install ID and register one anonymous PostHog person per process. */
9
+ export function ensureAnalyticsIdentity() {
10
+ if (!isAnalyticsEnabled() || !hasPostHogKey())
11
+ return;
12
+ getOrCreateDistinctId();
13
+ getAnalytics();
14
+ }
6
15
  export function capture(name, properties) {
7
16
  if (!isAnalyticsEnabled() || !hasPostHogKey())
8
17
  return;
@@ -11,6 +20,11 @@ export function capture(name, properties) {
11
20
  properties: buildRuntimeProperties(properties),
12
21
  });
13
22
  }
23
+ export function identifyAnalyticsPerson(properties) {
24
+ if (!isAnalyticsEnabled() || !hasPostHogKey())
25
+ return;
26
+ getAnalytics().identify(properties);
27
+ }
14
28
  export async function shutdownAnalytics() {
15
29
  await shutdownAnalyticsClient();
16
30
  }
@@ -27,5 +41,5 @@ export function getAnalyticsRuntimeConfig() {
27
41
  betaTelemetryPromptAnswered: beta.betaTelemetryPromptAnswered,
28
42
  };
29
43
  }
30
- export { captureBetaChatTurn, getAnalytics, getBetaTelemetryState, resetAnalyticsProvider, setBetaTelemetryChoice, };
44
+ export { captureBetaChatTurn, captureMcpPageleave, captureMcpPageview, endMcpAnalyticsSession, getAnalytics, getBetaTelemetryState, recordMcpToolCall, resetAnalyticsProvider, setBetaTelemetryChoice, startMcpAnalyticsSession, };
31
45
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analytics/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAQ9F,MAAM,UAAU,OAAO,CACrB,IAAY,EACZ,UAAoC;IAEpC,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,aAAa,EAAE;QAAE,OAAO;IACtD,YAAY,EAAE,CAAC,OAAO,CAAC;QACrB,IAAI;QACJ,UAAU,EAAE,sBAAsB,CAAC,UAAU,CAAC;KAC/C,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,uBAAuB,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,yBAAyB;IACvC,MAAM,OAAO,GAAG,kBAAkB,EAAE,IAAI,aAAa,EAAE,CAAC;IACxD,MAAM,IAAI,GAAG,qBAAqB,EAAE,CAAC;IACrC,OAAO;QACL,OAAO;QACP,GAAG,EAAE,iBAAiB,EAAE;QACxB,OAAO,EAAE,qBAAqB,EAAE;QAChC,MAAM,EAAE,oBAAoB,EAAE;QAC9B,UAAU,EAAE,qBAAqB,EAAE;QACnC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;QAC3C,2BAA2B,EAAE,IAAI,CAAC,2BAA2B;KAC9D,CAAC;AACJ,CAAC;AAED,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,qBAAqB,EACrB,sBAAsB,EACtB,sBAAsB,GACvB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analytics/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAU9F,oFAAoF;AACpF,MAAM,UAAU,uBAAuB;IACrC,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,aAAa,EAAE;QAAE,OAAO;IACtD,qBAAqB,EAAE,CAAC;IACxB,YAAY,EAAE,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,OAAO,CACrB,IAAY,EACZ,UAAoC;IAEpC,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,aAAa,EAAE;QAAE,OAAO;IACtD,YAAY,EAAE,CAAC,OAAO,CAAC;QACrB,IAAI;QACJ,UAAU,EAAE,sBAAsB,CAAC,UAAU,CAAC;KAC/C,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,UAAoC;IAEpC,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,aAAa,EAAE;QAAE,OAAO;IACtD,YAAY,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,uBAAuB,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,yBAAyB;IACvC,MAAM,OAAO,GAAG,kBAAkB,EAAE,IAAI,aAAa,EAAE,CAAC;IACxD,MAAM,IAAI,GAAG,qBAAqB,EAAE,CAAC;IACrC,OAAO;QACL,OAAO;QACP,GAAG,EAAE,iBAAiB,EAAE;QACxB,OAAO,EAAE,qBAAqB,EAAE;QAChC,MAAM,EAAE,oBAAoB,EAAE;QAC9B,UAAU,EAAE,qBAAqB,EAAE;QACnC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;QAC3C,2BAA2B,EAAE,IAAI,CAAC,2BAA2B;KAC9D,CAAC;AACJ,CAAC;AAED,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,GACzB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare function getSystemLocale(): string;
2
+ /** Region subtag from a BCP-47 locale (e.g. en-US -> US, tr-TR -> TR). */
3
+ export declare function resolveLocaleRegion(locale: string): string | undefined;
4
+ /** Primary language subtag from a BCP-47 locale (e.g. en-US -> en, tr-TR -> tr). */
5
+ export declare function resolveLocaleLanguage(locale: string): string | undefined;
6
+ //# sourceMappingURL=locale.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale.d.ts","sourceRoot":"","sources":["../../src/analytics/locale.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,IAAI,MAAM,CAMxC;AAED,0EAA0E;AAC1E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGtE;AAED,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGxE"}
@@ -0,0 +1,19 @@
1
+ export function getSystemLocale() {
2
+ try {
3
+ return Intl.DateTimeFormat().resolvedOptions().locale;
4
+ }
5
+ catch {
6
+ return 'unknown';
7
+ }
8
+ }
9
+ /** Region subtag from a BCP-47 locale (e.g. en-US -> US, tr-TR -> TR). */
10
+ export function resolveLocaleRegion(locale) {
11
+ const match = locale.trim().match(/-([A-Za-z]{2})\b/);
12
+ return match?.[1]?.toUpperCase();
13
+ }
14
+ /** Primary language subtag from a BCP-47 locale (e.g. en-US -> en, tr-TR -> tr). */
15
+ export function resolveLocaleLanguage(locale) {
16
+ const primary = locale.trim().split('-')[0]?.toLowerCase();
17
+ return primary || undefined;
18
+ }
19
+ //# sourceMappingURL=locale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale.js","sourceRoot":"","sources":["../../src/analytics/locale.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,cAAc,EAAE,CAAC,eAAe,EAAE,CAAC,MAAM,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACtD,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;AACnC,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,qBAAqB,CAAC,MAAc;IAClD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;IAC3D,OAAO,OAAO,IAAI,SAAS,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,12 @@
1
+ export type McpShutdownReason = 'sigint' | 'sigterm' | 'error' | 'stdio_closed';
2
+ export type McpToolBatchFlushReason = 'idle' | 'shutdown';
3
+ export declare function flushMcpToolBatch(reason: McpToolBatchFlushReason): void;
4
+ export declare function startMcpAnalyticsSession(): void;
5
+ export declare function recordMcpToolCall(params: {
6
+ toolName: string;
7
+ ok: boolean;
8
+ errorCode?: string;
9
+ durationMs: number;
10
+ }): void;
11
+ export declare function endMcpAnalyticsSession(reason: McpShutdownReason): void;
12
+ //# sourceMappingURL=mcp-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-session.d.ts","sourceRoot":"","sources":["../../src/analytics/mcp-session.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,cAAc,CAAC;AAChF,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,UAAU,CAAC;AA6D1D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,uBAAuB,GAAG,IAAI,CA4BvE;AAUD,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,IAAI,CAuBP;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CActE"}
@@ -0,0 +1,118 @@
1
+ import { hasPostHogKey } from './config.js';
2
+ import { buildRuntimeProperties } from './events.js';
3
+ import { isAnalyticsEnabled } from './identity.js';
4
+ import { captureMcpPageleave } from './pageview.js';
5
+ import { getAnalytics } from './provider.js';
6
+ /** Flush batched tool usage after this idle gap (proxy for end of an agent turn). */
7
+ const IDLE_FLUSH_MS = 30_000;
8
+ const MAX_SUMMARY_LENGTH = 4_000;
9
+ let startedAt = null;
10
+ let toolBatch = new Map();
11
+ let idleFlushTimer = null;
12
+ function captureMcpEvent(name, properties) {
13
+ if (!isAnalyticsEnabled() || !hasPostHogKey())
14
+ return;
15
+ getAnalytics().capture({
16
+ name,
17
+ properties: buildRuntimeProperties(properties),
18
+ });
19
+ }
20
+ function clearIdleFlushTimer() {
21
+ if (!idleFlushTimer)
22
+ return;
23
+ clearTimeout(idleFlushTimer);
24
+ idleFlushTimer = null;
25
+ }
26
+ function formatUsageSummary(batch) {
27
+ const parts = [...batch.entries()]
28
+ .sort((a, b) => b[1].ok + b[1].fail - (a[1].ok + a[1].fail))
29
+ .map(([name, entry]) => `${name}:${entry.ok + entry.fail}`);
30
+ let summary = parts.join(',');
31
+ if (summary.length > MAX_SUMMARY_LENGTH) {
32
+ summary = `${summary.slice(0, MAX_SUMMARY_LENGTH)}…`;
33
+ }
34
+ return summary;
35
+ }
36
+ function formatErrorCodesSummary(batch) {
37
+ const totals = new Map();
38
+ for (const entry of batch.values()) {
39
+ for (const [code, count] of entry.errors) {
40
+ totals.set(code, (totals.get(code) ?? 0) + count);
41
+ }
42
+ }
43
+ if (totals.size === 0)
44
+ return undefined;
45
+ return [...totals.entries()]
46
+ .sort((a, b) => b[1] - a[1])
47
+ .map(([code, count]) => `${code}:${count}`)
48
+ .join(',');
49
+ }
50
+ export function flushMcpToolBatch(reason) {
51
+ if (toolBatch.size === 0)
52
+ return;
53
+ let toolsCalledCount = 0;
54
+ let toolsErrorCount = 0;
55
+ let totalDurationMs = 0;
56
+ for (const entry of toolBatch.values()) {
57
+ toolsCalledCount += entry.ok + entry.fail;
58
+ toolsErrorCount += entry.fail;
59
+ totalDurationMs += entry.durationMs;
60
+ }
61
+ const errorCodesSummary = formatErrorCodesSummary(toolBatch);
62
+ captureMcpEvent('mcp_tool_batch', {
63
+ tools_called_count: toolsCalledCount,
64
+ tools_error_count: toolsErrorCount,
65
+ unique_tools_count: toolBatch.size,
66
+ tool_usage_summary: formatUsageSummary(toolBatch),
67
+ ...(errorCodesSummary ? { error_codes_summary: errorCodesSummary } : {}),
68
+ batch_flush_reason: reason,
69
+ duration_ms: totalDurationMs,
70
+ event_source: 'mcp',
71
+ });
72
+ toolBatch.clear();
73
+ clearIdleFlushTimer();
74
+ }
75
+ function scheduleIdleFlush() {
76
+ clearIdleFlushTimer();
77
+ idleFlushTimer = setTimeout(() => {
78
+ idleFlushTimer = null;
79
+ flushMcpToolBatch('idle');
80
+ }, IDLE_FLUSH_MS);
81
+ }
82
+ export function startMcpAnalyticsSession() {
83
+ startedAt = Date.now();
84
+ }
85
+ export function recordMcpToolCall(params) {
86
+ const existing = toolBatch.get(params.toolName) ?? {
87
+ ok: 0,
88
+ fail: 0,
89
+ errors: new Map(),
90
+ durationMs: 0,
91
+ };
92
+ if (params.ok) {
93
+ existing.ok += 1;
94
+ }
95
+ else {
96
+ existing.fail += 1;
97
+ if (params.errorCode) {
98
+ existing.errors.set(params.errorCode, (existing.errors.get(params.errorCode) ?? 0) + 1);
99
+ }
100
+ }
101
+ existing.durationMs += params.durationMs;
102
+ toolBatch.set(params.toolName, existing);
103
+ scheduleIdleFlush();
104
+ }
105
+ export function endMcpAnalyticsSession(reason) {
106
+ flushMcpToolBatch('shutdown');
107
+ const durationMs = startedAt !== null ? Date.now() - startedAt : 0;
108
+ captureMcpPageleave(durationMs, reason);
109
+ captureMcpEvent('mcp_session_ended', {
110
+ duration_ms: durationMs,
111
+ shutdown_reason: reason,
112
+ event_source: 'mcp',
113
+ });
114
+ startedAt = null;
115
+ toolBatch.clear();
116
+ clearIdleFlushTimer();
117
+ }
118
+ //# sourceMappingURL=mcp-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-session.js","sourceRoot":"","sources":["../../src/analytics/mcp-session.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import type { AnalyticsEvent, AnalyticsProvider } from './types.js';
2
2
  export declare class NoopAnalyticsProvider implements AnalyticsProvider {
3
3
  capture(_event: AnalyticsEvent): void;
4
+ identify(_properties?: Record<string, unknown>): void;
4
5
  shutdown(): Promise<void>;
5
6
  }
6
7
  //# sourceMappingURL=noop.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"noop.d.ts","sourceRoot":"","sources":["../../src/analytics/noop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpE,qBAAa,qBAAsB,YAAW,iBAAiB;IAC7D,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAI/B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAGhC"}
1
+ {"version":3,"file":"noop.d.ts","sourceRoot":"","sources":["../../src/analytics/noop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpE,qBAAa,qBAAsB,YAAW,iBAAiB;IAC7D,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI;IAIrC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI/C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAGhC"}
@@ -2,6 +2,9 @@ export class NoopAnalyticsProvider {
2
2
  capture(_event) {
3
3
  // intentionally empty
4
4
  }
5
+ identify(_properties) {
6
+ // intentionally empty
7
+ }
5
8
  async shutdown() {
6
9
  // intentionally empty
7
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"noop.js","sourceRoot":"","sources":["../../src/analytics/noop.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,qBAAqB;IAChC,OAAO,CAAC,MAAsB;QAC5B,sBAAsB;IACxB,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,sBAAsB;IACxB,CAAC;CACF"}
1
+ {"version":3,"file":"noop.js","sourceRoot":"","sources":["../../src/analytics/noop.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,qBAAqB;IAChC,OAAO,CAAC,MAAsB;QAC5B,sBAAsB;IACxB,CAAC;IAED,QAAQ,CAAC,WAAqC;QAC5C,sBAAsB;IACxB,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,sBAAsB;IACxB,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ export declare function captureMcpPageview(): void;
2
+ export declare function captureMcpPageleave(durationMs: number, reason: string): void;
3
+ //# sourceMappingURL=pageview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pageview.d.ts","sourceRoot":"","sources":["../../src/analytics/pageview.ts"],"names":[],"mappings":"AAkBA,wBAAgB,kBAAkB,IAAI,IAAI,CAOzC;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAQ5E"}
@@ -0,0 +1,31 @@
1
+ import { hasPostHogKey } from './config.js';
2
+ import { buildRuntimeProperties } from './events.js';
3
+ import { isAnalyticsEnabled } from './identity.js';
4
+ import { getAnalytics } from './provider.js';
5
+ const MCP_VIRTUAL_URL = 'photoshop-mcp://mcp';
6
+ function capturePageEvent(name, properties) {
7
+ if (!isAnalyticsEnabled() || !hasPostHogKey())
8
+ return;
9
+ getAnalytics().capture({
10
+ name,
11
+ properties: buildRuntimeProperties(properties),
12
+ });
13
+ }
14
+ export function captureMcpPageview() {
15
+ capturePageEvent('$pageview', {
16
+ $current_url: MCP_VIRTUAL_URL,
17
+ $pathname: '/mcp',
18
+ usage_surface: 'mcp',
19
+ event_source: 'mcp',
20
+ });
21
+ }
22
+ export function captureMcpPageleave(durationMs, reason) {
23
+ capturePageEvent('$pageleave', {
24
+ $current_url: MCP_VIRTUAL_URL,
25
+ duration_ms: durationMs,
26
+ shutdown_reason: reason,
27
+ usage_surface: 'mcp',
28
+ event_source: 'mcp',
29
+ });
30
+ }
31
+ //# sourceMappingURL=pageview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pageview.js","sourceRoot":"","sources":["../../src/analytics/pageview.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,eAAe,GAAG,qBAAqB,CAAC;AAE9C,SAAS,gBAAgB,CACvB,IAAY,EACZ,UAAmC;IAEnC,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,aAAa,EAAE;QAAE,OAAO;IACtD,YAAY,EAAE,CAAC,OAAO,CAAC;QACrB,IAAI;QACJ,UAAU,EAAE,sBAAsB,CAAC,UAAU,CAAC;KAC/C,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,gBAAgB,CAAC,WAAW,EAAE;QAC5B,YAAY,EAAE,eAAe;QAC7B,SAAS,EAAE,MAAM;QACjB,aAAa,EAAE,KAAK;QACpB,YAAY,EAAE,KAAK;KACpB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,UAAkB,EAAE,MAAc;IACpE,gBAAgB,CAAC,YAAY,EAAE;QAC7B,YAAY,EAAE,eAAe;QAC7B,WAAW,EAAE,UAAU;QACvB,eAAe,EAAE,MAAM;QACvB,aAAa,EAAE,KAAK;QACpB,YAAY,EAAE,KAAK;KACpB,CAAC,CAAC;AACL,CAAC"}
@@ -2,7 +2,10 @@ import type { AnalyticsEvent, AnalyticsProvider } from './types.js';
2
2
  export declare class PostHogNodeProvider implements AnalyticsProvider {
3
3
  private client;
4
4
  private logger;
5
+ private distinctId;
5
6
  constructor();
7
+ private identifyPerson;
8
+ identify(properties?: Record<string, unknown>): void;
6
9
  capture(event: AnalyticsEvent): void;
7
10
  shutdown(): Promise<void>;
8
11
  }
@@ -1 +1 @@
1
- {"version":3,"file":"posthog-node.d.ts","sourceRoot":"","sources":["../../src/analytics/posthog-node.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpE,qBAAa,mBAAoB,YAAW,iBAAiB;IAC3D,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,MAAM,CAA2B;;IAUzC,OAAO,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAY9B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAOhC"}
1
+ {"version":3,"file":"posthog-node.d.ts","sourceRoot":"","sources":["../../src/analytics/posthog-node.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpE,qBAAa,mBAAoB,YAAW,iBAAiB;IAC3D,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,UAAU,CAAS;;IAc3B,OAAO,CAAC,cAAc;IAItB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAYpD,OAAO,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAa9B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAOhC"}