@alisaitteke/photoshop-mcp 1.2.0 → 1.3.0

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 (98) hide show
  1. package/README.md +94 -2
  2. package/dist/analytics/beta-telemetry.d.ts +11 -0
  3. package/dist/analytics/beta-telemetry.d.ts.map +1 -0
  4. package/dist/analytics/beta-telemetry.js +47 -0
  5. package/dist/analytics/beta-telemetry.js.map +1 -0
  6. package/dist/analytics/config.d.ts +6 -0
  7. package/dist/analytics/config.d.ts.map +1 -0
  8. package/dist/analytics/config.js +23 -0
  9. package/dist/analytics/config.js.map +1 -0
  10. package/dist/analytics/context.d.ts +2 -0
  11. package/dist/analytics/context.d.ts.map +1 -0
  12. package/dist/analytics/context.js +13 -0
  13. package/dist/analytics/context.js.map +1 -0
  14. package/dist/analytics/events.d.ts +3 -0
  15. package/dist/analytics/events.d.ts.map +1 -0
  16. package/dist/analytics/events.js +75 -0
  17. package/dist/analytics/events.js.map +1 -0
  18. package/dist/analytics/identity.d.ts +9 -0
  19. package/dist/analytics/identity.d.ts.map +1 -0
  20. package/dist/analytics/identity.js +166 -0
  21. package/dist/analytics/identity.js.map +1 -0
  22. package/dist/analytics/index.d.ts +10 -0
  23. package/dist/analytics/index.d.ts.map +1 -0
  24. package/dist/analytics/index.js +31 -0
  25. package/dist/analytics/index.js.map +1 -0
  26. package/dist/analytics/launch-method.d.ts +4 -0
  27. package/dist/analytics/launch-method.d.ts.map +1 -0
  28. package/dist/analytics/launch-method.js +33 -0
  29. package/dist/analytics/launch-method.js.map +1 -0
  30. package/dist/analytics/noop.d.ts +6 -0
  31. package/dist/analytics/noop.d.ts.map +1 -0
  32. package/dist/analytics/noop.js +9 -0
  33. package/dist/analytics/noop.js.map +1 -0
  34. package/dist/analytics/posthog-node.d.ts +9 -0
  35. package/dist/analytics/posthog-node.d.ts.map +1 -0
  36. package/dist/analytics/posthog-node.js +36 -0
  37. package/dist/analytics/posthog-node.js.map +1 -0
  38. package/dist/analytics/provider.d.ts +5 -0
  39. package/dist/analytics/provider.d.ts.map +1 -0
  40. package/dist/analytics/provider.js +27 -0
  41. package/dist/analytics/provider.js.map +1 -0
  42. package/dist/analytics/types.d.ts +23 -0
  43. package/dist/analytics/types.d.ts.map +1 -0
  44. package/dist/analytics/types.js +2 -0
  45. package/dist/analytics/types.js.map +1 -0
  46. package/dist/core/server.d.ts +1 -0
  47. package/dist/core/server.d.ts.map +1 -1
  48. package/dist/core/server.js +3 -0
  49. package/dist/core/server.js.map +1 -1
  50. package/dist/index.js +31 -0
  51. package/dist/index.js.map +1 -1
  52. package/dist/platform/macos-detector.js +4 -4
  53. package/dist/platform/macos-detector.js.map +1 -1
  54. package/dist/platform/macos-executor.js +1 -1
  55. package/dist/platform/macos-executor.js.map +1 -1
  56. package/dist/platform/windows-detector.js +4 -4
  57. package/dist/platform/windows-detector.js.map +1 -1
  58. package/dist/platform/windows-executor.js +2 -2
  59. package/dist/platform/windows-executor.js.map +1 -1
  60. package/dist/ui/agent/action-plan.d.ts +19 -0
  61. package/dist/ui/agent/action-plan.d.ts.map +1 -0
  62. package/dist/ui/agent/action-plan.js +552 -0
  63. package/dist/ui/agent/action-plan.js.map +1 -0
  64. package/dist/ui/agent/api-key.d.ts.map +1 -1
  65. package/dist/ui/agent/api-key.js +22 -4
  66. package/dist/ui/agent/api-key.js.map +1 -1
  67. package/dist/ui/agent/claude-account.d.ts.map +1 -1
  68. package/dist/ui/agent/claude-account.js +26 -12
  69. package/dist/ui/agent/claude-account.js.map +1 -1
  70. package/dist/ui/agent/gemini-account.d.ts.map +1 -1
  71. package/dist/ui/agent/gemini-account.js +14 -4
  72. package/dist/ui/agent/gemini-account.js.map +1 -1
  73. package/dist/ui/agent/shared.d.ts +26 -1
  74. package/dist/ui/agent/shared.d.ts.map +1 -1
  75. package/dist/ui/agent/shared.js +61 -0
  76. package/dist/ui/agent/shared.js.map +1 -1
  77. package/dist/ui/agent.d.ts +1 -0
  78. package/dist/ui/agent.d.ts.map +1 -1
  79. package/dist/ui/agent.js +36 -0
  80. package/dist/ui/agent.js.map +1 -1
  81. package/dist/ui/cli.js +10 -1
  82. package/dist/ui/cli.js.map +1 -1
  83. package/dist/ui/config.d.ts +6 -1
  84. package/dist/ui/config.d.ts.map +1 -1
  85. package/dist/ui/config.js +1 -12
  86. package/dist/ui/config.js.map +1 -1
  87. package/dist/ui/server.d.ts.map +1 -1
  88. package/dist/ui/server.js +102 -6
  89. package/dist/ui/server.js.map +1 -1
  90. package/dist/ui/store/chats.d.ts +11 -0
  91. package/dist/ui/store/chats.d.ts.map +1 -1
  92. package/dist/ui/store/chats.js.map +1 -1
  93. package/package.json +4 -2
  94. package/web/dist/assets/index-BgiXf1Jy.css +1 -0
  95. package/web/dist/assets/index-BuJJLllx.js +249 -0
  96. package/web/dist/index.html +9 -3
  97. package/web/dist/assets/index-BN0tu4e6.css +0 -1
  98. package/web/dist/assets/index-Cf7sH5RM.js +0 -138
package/README.md CHANGED
@@ -1,15 +1,16 @@
1
1
  # Photoshop MCP Server
2
2
 
3
- *v1.1+ — recipe workflows, fewer round-trips, snappier sessions.*
3
+ *v1.1+ — recipe workflows, fewer round-trips, snappier sessions. Standalone UI ships **Action Plan (beta)** for plan-then-execute runs.*
4
4
 
5
5
  > **Note:** This is an unofficial, community-maintained project and is not affiliated with or endorsed by Adobe Inc.
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/@alisaitteke/photoshop-mcp.svg)](https://www.npmjs.com/package/@alisaitteke/photoshop-mcp)
8
+ [![Action Plan](https://img.shields.io/badge/Action%20Plan-beta-amber.svg)](#action-plan-beta)
8
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
10
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue.svg)](https://www.typescriptlang.org/)
10
11
  [![Platform](https://img.shields.io/badge/Platform-Windows%20%7C%20macOS-lightgrey.svg)]()
11
12
 
12
- A Model Context Protocol (MCP) server that enables AI assistants like Claude and Cursor to control Adobe Photoshop programmatically. This allows you to create designs, manipulate images, and automate Photoshop workflows through natural language commands while working in your IDE — or through the bundled **standalone web UI**, which supports both API keys and CLI subscription accounts (Claude Code / Gemini CLI).
13
+ A Model Context Protocol (MCP) server that enables AI assistants like Claude and Cursor to control Adobe Photoshop programmatically. This allows you to create designs, manipulate images, and automate Photoshop workflows through natural language commands while working in your IDE — or through the bundled **standalone web UI**, which supports both API keys and CLI subscription accounts (Claude Code / Gemini CLI). The UI also offers an opt-in **Action Plan (beta)** mode that plans every Photoshop step in one LLM call, then runs them in a single pass.
13
14
 
14
15
  ## 🖥️ Standalone UI (no IDE required)
15
16
 
@@ -52,6 +53,29 @@ CLI subscription account (Anthropic and Google):
52
53
  You can switch auth method per provider in Settings without losing the other
53
54
  credential (e.g. keep an API key while trying CLI account, then switch back).
54
55
 
56
+ ### Action Plan (beta)
57
+
58
+ An optional execution mode in the standalone web UI for **API key auth only**
59
+ (`cli_account` always uses the default agentic flow). Turn it on with the
60
+ **Action Plan** toggle next to the model selector in the composer.
61
+
62
+ Instead of a per-step ReAct loop (model → tool → model → tool …), Action Plan:
63
+
64
+ 1. Makes **one** planning LLM call that outputs an ordered todo list of
65
+ Photoshop MCP tool calls with parameters.
66
+ 2. Executes those tools **directly** in sequence — no extra model round-trips
67
+ between steps.
68
+ 3. On a failed step or unresolved dependency, runs a bounded **repair** loop
69
+ (re-plans only the remaining steps, up to 3 times).
70
+
71
+ The plan appears as a live todo list above the tool-call cards, with per-step
72
+ status (`pending` → `running` → `done` / `error`). Plans are persisted in chat
73
+ history so they survive reload. The toggle is off by default; the existing
74
+ agentic flow is unchanged when Action Plan is disabled.
75
+
76
+ Good for multi-step prompts such as *"remove the background and export for web"*
77
+ where you want fewer model calls and faster end-to-end execution.
78
+
55
79
  ### What happens on first launch
56
80
 
57
81
  1. Pick a provider and choose **API key** or **Uses your account**.
@@ -426,6 +450,8 @@ Never guess — read get_state after a failure and propose the next single step.
426
450
 
427
451
  - **Standalone web UI** — local chat interface (`photoshop-mcp-ui`); API key or CLI
428
452
  subscription auth per provider (Anthropic, Google)
453
+ - **Action Plan (beta)** — opt-in plan-then-execute mode in the web UI (API key
454
+ only): one planning call, direct tool execution, bounded repair on failure
429
455
  - **Works on both Windows and macOS**
430
456
  - **Supports Photoshop 2012-2025+**
431
457
  - **ExtendScript API**: Universal compatibility via AppleScript/COM automation
@@ -499,6 +525,10 @@ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_
499
525
 
500
526
  - `PHOTOSHOP_PATH`: (Optional) Specify custom Photoshop installation path
501
527
  - `LOG_LEVEL`: Logging level (0=DEBUG, 1=INFO, 2=WARN, 3=ERROR)
528
+ - `POSTHOG_DISABLED`: Set to `1` or `true` to disable anonymous usage analytics entirely
529
+ - `POSTHOG_KEY`: (Optional) Override the PostHog project key used for analytics
530
+ - `POSTHOG_API_HOST`: (Optional) PostHog ingest host (default: `https://a.alisait.com`)
531
+ - `POSTHOG_UI_HOST`: (Optional) PostHog UI host for dashboard links (default: `https://eu.posthog.com`)
502
532
 
503
533
  ## Available Tools
504
534
 
@@ -612,6 +642,68 @@ Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) before
612
642
 
613
643
  MIT
614
644
 
645
+ ## Anonymous Usage Analytics
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).
706
+
615
707
  ## Acknowledgments
616
708
 
617
709
  - Built with the [Model Context Protocol SDK](https://github.com/modelcontextprotocol/sdk)
@@ -0,0 +1,11 @@
1
+ export interface BetaChatTurnInput {
2
+ providerId: string;
3
+ model: string;
4
+ authMethod: string;
5
+ userPrompt: string;
6
+ assistantText: string;
7
+ assistantReasoning?: string;
8
+ toolNames: string[];
9
+ }
10
+ export declare function captureBetaChatTurn(input: BetaChatTurnInput): void;
11
+ //# sourceMappingURL=beta-telemetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"beta-telemetry.d.ts","sourceRoot":"","sources":["../../src/analytics/beta-telemetry.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAYD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAgClE"}
@@ -0,0 +1,47 @@
1
+ import { isAnalyticsEnabled, isBetaTelemetryOptIn } from './identity.js';
2
+ import { getLaunchMethod } from './launch-method.js';
3
+ import { getAnalytics } from './provider.js';
4
+ const MAX_TEXT_LENGTH = 16_000;
5
+ const TRUNCATION_SUFFIX = '…[truncated]';
6
+ function truncateText(value) {
7
+ if (!value)
8
+ return undefined;
9
+ if (value.length <= MAX_TEXT_LENGTH)
10
+ return value;
11
+ return `${value.slice(0, MAX_TEXT_LENGTH)}${TRUNCATION_SUFFIX}`;
12
+ }
13
+ function uniqueToolNames(names) {
14
+ return [...new Set(names.map((name) => name.trim()).filter(Boolean))];
15
+ }
16
+ export function captureBetaChatTurn(input) {
17
+ if (!isAnalyticsEnabled() || !isBetaTelemetryOptIn())
18
+ return;
19
+ const assistantText = input.assistantText.trim();
20
+ const assistantReasoning = input.assistantReasoning?.trim() ?? '';
21
+ const hasAssistantContent = assistantText.length > 0 ||
22
+ assistantReasoning.length > 0 ||
23
+ input.toolNames.length > 0;
24
+ if (!hasAssistantContent)
25
+ return;
26
+ const toolNames = uniqueToolNames(input.toolNames);
27
+ getAnalytics().capture({
28
+ name: 'beta_chat_turn',
29
+ properties: {
30
+ os: process.platform,
31
+ arch: process.arch,
32
+ node_version: process.version,
33
+ launch_method: getLaunchMethod(),
34
+ event_source: 'server',
35
+ provider_id: input.providerId,
36
+ auth_method: input.authMethod,
37
+ model: input.model,
38
+ user_prompt: truncateText(input.userPrompt.trim()) ?? '',
39
+ assistant_text: truncateText(assistantText) ?? '',
40
+ ...(assistantReasoning
41
+ ? { assistant_reasoning: truncateText(assistantReasoning) }
42
+ : {}),
43
+ ...(toolNames.length > 0 ? { tool_names: toolNames.join(',') } : {}),
44
+ },
45
+ });
46
+ }
47
+ //# sourceMappingURL=beta-telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"beta-telemetry.js","sourceRoot":"","sources":["../../src/analytics/beta-telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,eAAe,GAAG,MAAM,CAAC;AAC/B,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAYzC,SAAS,YAAY,CAAC,KAAyB;IAC7C,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,IAAI,KAAK,CAAC,MAAM,IAAI,eAAe;QAAE,OAAO,KAAK,CAAC;IAClD,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,GAAG,iBAAiB,EAAE,CAAC;AAClE,CAAC;AAED,SAAS,eAAe,CAAC,KAAe;IACtC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAwB;IAC1D,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,oBAAoB,EAAE;QAAE,OAAO;IAE7D,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;IACjD,MAAM,kBAAkB,GAAG,KAAK,CAAC,kBAAkB,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAClE,MAAM,mBAAmB,GACvB,aAAa,CAAC,MAAM,GAAG,CAAC;QACxB,kBAAkB,CAAC,MAAM,GAAG,CAAC;QAC7B,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,mBAAmB;QAAE,OAAO;IAEjC,MAAM,SAAS,GAAG,eAAe,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAEnD,YAAY,EAAE,CAAC,OAAO,CAAC;QACrB,IAAI,EAAE,gBAAgB;QACtB,UAAU,EAAE;YACV,EAAE,EAAE,OAAO,CAAC,QAAQ;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,YAAY,EAAE,OAAO,CAAC,OAAO;YAC7B,aAAa,EAAE,eAAe,EAAE;YAChC,YAAY,EAAE,QAAQ;YACtB,WAAW,EAAE,KAAK,CAAC,UAAU;YAC7B,WAAW,EAAE,KAAK,CAAC,UAAU;YAC7B,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,WAAW,EAAE,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;YACxD,cAAc,EAAE,YAAY,CAAC,aAAa,CAAC,IAAI,EAAE;YACjD,GAAG,CAAC,kBAAkB;gBACpB,CAAC,CAAC,EAAE,mBAAmB,EAAE,YAAY,CAAC,kBAAkB,CAAC,EAAE;gBAC3D,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACrE;KACF,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare function isPostHogDisabledByEnv(): boolean;
2
+ export declare function resolvePostHogKey(): string;
3
+ export declare function resolvePostHogApiHost(): string;
4
+ export declare function resolvePostHogUiHost(): string;
5
+ export declare function hasPostHogKey(): boolean;
6
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/analytics/config.ts"],"names":[],"mappings":"AASA,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,aAAa,IAAI,OAAO,CAEvC"}
@@ -0,0 +1,23 @@
1
+ const DEFAULT_POSTHOG_KEY = 'phc_mejq4ZZ8jTNZPiusjh7vHyPzWYinzsDwVJW43SM5FEcg';
2
+ const DEFAULT_API_HOST = 'https://a.alisait.com';
3
+ const DEFAULT_UI_HOST = 'https://eu.posthog.com';
4
+ function envTruthy(name) {
5
+ const value = process.env[name]?.trim().toLowerCase();
6
+ return value === '1' || value === 'true' || value === 'yes';
7
+ }
8
+ export function isPostHogDisabledByEnv() {
9
+ return envTruthy('POSTHOG_DISABLED');
10
+ }
11
+ export function resolvePostHogKey() {
12
+ return process.env.POSTHOG_KEY?.trim() || DEFAULT_POSTHOG_KEY;
13
+ }
14
+ export function resolvePostHogApiHost() {
15
+ return process.env.POSTHOG_API_HOST?.trim() || DEFAULT_API_HOST;
16
+ }
17
+ export function resolvePostHogUiHost() {
18
+ return process.env.POSTHOG_UI_HOST?.trim() || DEFAULT_UI_HOST;
19
+ }
20
+ export function hasPostHogKey() {
21
+ return resolvePostHogKey().length > 0;
22
+ }
23
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/analytics/config.ts"],"names":[],"mappings":"AAAA,MAAM,mBAAmB,GAAG,kDAAkD,CAAC;AAC/E,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AACjD,MAAM,eAAe,GAAG,wBAAwB,CAAC;AAEjD,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACtD,OAAO,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,OAAO,SAAS,CAAC,kBAAkB,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,mBAAmB,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,EAAE,IAAI,gBAAgB,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,IAAI,eAAe,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,iBAAiB,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AACxC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function getServerAnalyticsContext(): Record<string, boolean>;
2
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/analytics/context.ts"],"names":[],"mappings":"AAGA,wBAAgB,yBAAyB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASnE"}
@@ -0,0 +1,13 @@
1
+ import { loadConfig } from '../ui/config.js';
2
+ import { isAnalyticsEnabled, isBetaTelemetryOptIn } from './identity.js';
3
+ export function getServerAnalyticsContext() {
4
+ const config = loadConfig();
5
+ const analyticsEnabled = isAnalyticsEnabled();
6
+ return {
7
+ privacy_mode: !analyticsEnabled,
8
+ analytics_enabled: analyticsEnabled,
9
+ beta_telemetry_opt_in: isBetaTelemetryOptIn(),
10
+ action_plan_enabled: Boolean(config.actionPlanBeta),
11
+ };
12
+ }
13
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/analytics/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAEzE,MAAM,UAAU,yBAAyB;IACvC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,gBAAgB,GAAG,kBAAkB,EAAE,CAAC;IAC9C,OAAO;QACL,YAAY,EAAE,CAAC,gBAAgB;QAC/B,iBAAiB,EAAE,gBAAgB;QACnC,qBAAqB,EAAE,oBAAoB,EAAE;QAC7C,mBAAmB,EAAE,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC;KACpD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function sanitizeAnalyticsProperties(properties: Record<string, unknown> | undefined): Record<string, string | number | boolean>;
2
+ export declare function buildRuntimeProperties(properties: Record<string, unknown> | undefined): Record<string, string | number | boolean>;
3
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,75 @@
1
+ import { getServerAnalyticsContext } from './context.js';
2
+ import { getLaunchMethod } from './launch-method.js';
3
+ const BLOCKED_PROPERTY_KEYS = new Set([
4
+ 'api_key',
5
+ 'apikey',
6
+ 'key',
7
+ 'token',
8
+ 'secret',
9
+ 'password',
10
+ 'email',
11
+ 'account_label',
12
+ 'cli_path',
13
+ 'path',
14
+ 'file_path',
15
+ 'filepath',
16
+ 'message',
17
+ 'content',
18
+ 'prompt',
19
+ 'chat_id',
20
+ 'session_id',
21
+ ]);
22
+ const ALLOWED_PROPERTY_KEYS = new Set([
23
+ 'app_version',
24
+ 'os',
25
+ 'arch',
26
+ 'node_version',
27
+ 'provider_id',
28
+ 'auth_method',
29
+ 'ok',
30
+ 'error_code',
31
+ 'photoshop_detected',
32
+ 'action_plan_enabled',
33
+ 'event_source',
34
+ 'port',
35
+ 'host',
36
+ 'no_open',
37
+ 'has_auth',
38
+ 'has_custom_path',
39
+ 'opted_out',
40
+ 'opted_in',
41
+ 'privacy_mode',
42
+ 'analytics_enabled',
43
+ 'beta_telemetry_opt_in',
44
+ 'theme',
45
+ 'launch_method',
46
+ ]);
47
+ export function sanitizeAnalyticsProperties(properties) {
48
+ if (!properties)
49
+ return {};
50
+ const out = {};
51
+ 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))
56
+ continue;
57
+ if (value === null || value === undefined)
58
+ continue;
59
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
60
+ out[normalized] = value;
61
+ }
62
+ }
63
+ return out;
64
+ }
65
+ export function buildRuntimeProperties(properties) {
66
+ return {
67
+ os: process.platform,
68
+ arch: process.arch,
69
+ node_version: process.version,
70
+ launch_method: getLaunchMethod(),
71
+ ...getServerAnalyticsContext(),
72
+ ...sanitizeAnalyticsProperties(properties),
73
+ };
74
+ }
75
+ //# sourceMappingURL=events.js.map
@@ -0,0 +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"}
@@ -0,0 +1,9 @@
1
+ import type { BetaTelemetryState } from './types.js';
2
+ export declare function getOrCreateDistinctId(): string;
3
+ export declare function isAnalyticsOptedOut(): boolean;
4
+ export declare function setAnalyticsOptOut(optedOut: boolean): void;
5
+ export declare function isAnalyticsEnabled(): boolean;
6
+ export declare function getBetaTelemetryState(): BetaTelemetryState;
7
+ export declare function isBetaTelemetryOptIn(): boolean;
8
+ export declare function setBetaTelemetryChoice(optedIn: boolean): void;
9
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/analytics/identity.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAwFrD,wBAAgB,qBAAqB,IAAI,MAAM,CAsB9C;AAED,wBAAgB,mBAAmB,IAAI,OAAO,CAO7C;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAI1D;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAqBD,wBAAgB,qBAAqB,IAAI,kBAAkB,CAW1D;AAED,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAS7D"}
@@ -0,0 +1,166 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { getPhotoshopMcpHomeDir } from '../lib/export-paths.js';
5
+ import { kvGet, kvSet } from '../ui/store/kv.js';
6
+ import { isPostHogDisabledByEnv } from './config.js';
7
+ const DISTINCT_ID_KEY = 'analytics_distinct_id';
8
+ const OPT_OUT_KEY = 'analytics_opt_out';
9
+ const BETA_TELEMETRY_OPT_IN_KEY = 'beta_telemetry_opt_in';
10
+ const BETA_TELEMETRY_PROMPT_ANSWERED_KEY = 'beta_telemetry_prompt_answered';
11
+ const STORE_FILE = 'analytics-store.json';
12
+ let memoryDistinctId = null;
13
+ let dbAvailable = null;
14
+ function getStorePath() {
15
+ return join(getPhotoshopMcpHomeDir(), STORE_FILE);
16
+ }
17
+ function readFileStore() {
18
+ try {
19
+ const raw = readFileSync(getStorePath(), 'utf8');
20
+ return JSON.parse(raw);
21
+ }
22
+ catch {
23
+ return {};
24
+ }
25
+ }
26
+ function writeFileStore(store) {
27
+ const dir = getPhotoshopMcpHomeDir();
28
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
29
+ writeFileSync(getStorePath(), JSON.stringify(store), { mode: 0o600 });
30
+ }
31
+ function canUseKv() {
32
+ if (dbAvailable === false)
33
+ return false;
34
+ try {
35
+ kvGet('__analytics_probe__');
36
+ dbAvailable = true;
37
+ return true;
38
+ }
39
+ catch {
40
+ dbAvailable = false;
41
+ return false;
42
+ }
43
+ }
44
+ function readDistinctIdFromKv() {
45
+ if (!canUseKv())
46
+ return undefined;
47
+ try {
48
+ return kvGet(DISTINCT_ID_KEY);
49
+ }
50
+ catch {
51
+ dbAvailable = false;
52
+ return undefined;
53
+ }
54
+ }
55
+ function writeDistinctIdToKv(id) {
56
+ if (!canUseKv())
57
+ return;
58
+ try {
59
+ kvSet(DISTINCT_ID_KEY, id);
60
+ }
61
+ catch {
62
+ dbAvailable = false;
63
+ }
64
+ }
65
+ function readOptOutFromKv() {
66
+ if (!canUseKv())
67
+ return undefined;
68
+ try {
69
+ return kvGet(OPT_OUT_KEY);
70
+ }
71
+ catch {
72
+ dbAvailable = false;
73
+ return undefined;
74
+ }
75
+ }
76
+ function writeOptOutToKv(optedOut) {
77
+ if (!canUseKv())
78
+ return;
79
+ try {
80
+ kvSet(OPT_OUT_KEY, optedOut);
81
+ }
82
+ catch {
83
+ dbAvailable = false;
84
+ }
85
+ }
86
+ export function getOrCreateDistinctId() {
87
+ if (memoryDistinctId)
88
+ return memoryDistinctId;
89
+ const fromKv = readDistinctIdFromKv();
90
+ if (fromKv) {
91
+ memoryDistinctId = fromKv;
92
+ return fromKv;
93
+ }
94
+ const fromFile = readFileStore().distinctId;
95
+ if (fromFile) {
96
+ memoryDistinctId = fromFile;
97
+ writeDistinctIdToKv(fromFile);
98
+ return fromFile;
99
+ }
100
+ const id = randomUUID();
101
+ memoryDistinctId = id;
102
+ writeDistinctIdToKv(id);
103
+ const store = readFileStore();
104
+ writeFileStore({ ...store, distinctId: id });
105
+ return id;
106
+ }
107
+ export function isAnalyticsOptedOut() {
108
+ if (isPostHogDisabledByEnv())
109
+ return true;
110
+ const fromKv = readOptOutFromKv();
111
+ if (fromKv !== undefined)
112
+ return fromKv;
113
+ return readFileStore().optedOut === true;
114
+ }
115
+ export function setAnalyticsOptOut(optedOut) {
116
+ writeOptOutToKv(optedOut);
117
+ const store = readFileStore();
118
+ writeFileStore({ ...store, optedOut });
119
+ }
120
+ export function isAnalyticsEnabled() {
121
+ return !isAnalyticsOptedOut();
122
+ }
123
+ function readBooleanFromKv(key) {
124
+ if (!canUseKv())
125
+ return undefined;
126
+ try {
127
+ return kvGet(key);
128
+ }
129
+ catch {
130
+ dbAvailable = false;
131
+ return undefined;
132
+ }
133
+ }
134
+ function writeBooleanToKv(key, value) {
135
+ if (!canUseKv())
136
+ return;
137
+ try {
138
+ kvSet(key, value);
139
+ }
140
+ catch {
141
+ dbAvailable = false;
142
+ }
143
+ }
144
+ export function getBetaTelemetryState() {
145
+ const fromKvOptIn = readBooleanFromKv(BETA_TELEMETRY_OPT_IN_KEY);
146
+ const fromKvAnswered = readBooleanFromKv(BETA_TELEMETRY_PROMPT_ANSWERED_KEY);
147
+ const fileStore = readFileStore();
148
+ return {
149
+ betaTelemetryOptIn: fromKvOptIn ?? fileStore.betaTelemetryOptIn ?? false,
150
+ betaTelemetryPromptAnswered: fromKvAnswered ?? fileStore.betaTelemetryPromptAnswered ?? false,
151
+ };
152
+ }
153
+ export function isBetaTelemetryOptIn() {
154
+ return getBetaTelemetryState().betaTelemetryOptIn;
155
+ }
156
+ export function setBetaTelemetryChoice(optedIn) {
157
+ writeBooleanToKv(BETA_TELEMETRY_OPT_IN_KEY, optedIn);
158
+ writeBooleanToKv(BETA_TELEMETRY_PROMPT_ANSWERED_KEY, true);
159
+ const store = readFileStore();
160
+ writeFileStore({
161
+ ...store,
162
+ betaTelemetryOptIn: optedIn,
163
+ betaTelemetryPromptAnswered: true,
164
+ });
165
+ }
166
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/analytics/identity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { captureBetaChatTurn } from './beta-telemetry.js';
2
+ import { getBetaTelemetryState, setBetaTelemetryChoice } from './identity.js';
3
+ import { getAnalytics, resetAnalyticsProvider } from './provider.js';
4
+ import type { AnalyticsEvent, AnalyticsProvider, AnalyticsRuntimeConfig, BetaTelemetryState } from './types.js';
5
+ export declare function capture(name: string, properties?: Record<string, unknown>): void;
6
+ export declare function shutdownAnalytics(): Promise<void>;
7
+ export declare function getAnalyticsRuntimeConfig(): AnalyticsRuntimeConfig;
8
+ export { captureBetaChatTurn, getAnalytics, getBetaTelemetryState, resetAnalyticsProvider, setBetaTelemetryChoice, };
9
+ export type { AnalyticsEvent, AnalyticsProvider, AnalyticsRuntimeConfig, BetaTelemetryState };
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,31 @@
1
+ import { captureBetaChatTurn } from './beta-telemetry.js';
2
+ import { hasPostHogKey, resolvePostHogApiHost, resolvePostHogKey, resolvePostHogUiHost, } from './config.js';
3
+ import { buildRuntimeProperties } from './events.js';
4
+ import { getBetaTelemetryState, getOrCreateDistinctId, isAnalyticsEnabled, setBetaTelemetryChoice, } from './identity.js';
5
+ import { getAnalytics, resetAnalyticsProvider, shutdownAnalyticsClient } from './provider.js';
6
+ export function capture(name, properties) {
7
+ if (!isAnalyticsEnabled() || !hasPostHogKey())
8
+ return;
9
+ getAnalytics().capture({
10
+ name,
11
+ properties: buildRuntimeProperties(properties),
12
+ });
13
+ }
14
+ export async function shutdownAnalytics() {
15
+ await shutdownAnalyticsClient();
16
+ }
17
+ export function getAnalyticsRuntimeConfig() {
18
+ const enabled = isAnalyticsEnabled() && hasPostHogKey();
19
+ const beta = getBetaTelemetryState();
20
+ return {
21
+ enabled,
22
+ key: resolvePostHogKey(),
23
+ apiHost: resolvePostHogApiHost(),
24
+ uiHost: resolvePostHogUiHost(),
25
+ distinctId: getOrCreateDistinctId(),
26
+ betaTelemetryOptIn: beta.betaTelemetryOptIn,
27
+ betaTelemetryPromptAnswered: beta.betaTelemetryPromptAnswered,
28
+ };
29
+ }
30
+ export { captureBetaChatTurn, getAnalytics, getBetaTelemetryState, resetAnalyticsProvider, setBetaTelemetryChoice, };
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"}
@@ -0,0 +1,4 @@
1
+ export type LaunchMethod = 'npx' | 'npm' | 'node' | 'unknown';
2
+ export declare function resolveLaunchMethod(env?: NodeJS.ProcessEnv, argv?: string[]): LaunchMethod;
3
+ export declare function getLaunchMethod(): LaunchMethod;
4
+ //# sourceMappingURL=launch-method.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launch-method.d.ts","sourceRoot":"","sources":["../../src/analytics/launch-method.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;AAuB9D,wBAAgB,mBAAmB,CACjC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,IAAI,GAAE,MAAM,EAAiB,GAC5B,YAAY,CAWd;AAED,wBAAgB,eAAe,IAAI,YAAY,CAK9C"}
@@ -0,0 +1,33 @@
1
+ let cachedLaunchMethod = null;
2
+ function isNpxInvocation(npmExecPath, npmCommand) {
3
+ if (npmCommand === 'exec' || npmCommand === 'exec-run')
4
+ return true;
5
+ const normalizedPath = npmExecPath.toLowerCase();
6
+ return (normalizedPath.includes('/npx/') ||
7
+ normalizedPath.includes('\\npx\\') ||
8
+ /(?:^|[/\\])npx(?:\.cmd)?$/i.test(npmExecPath));
9
+ }
10
+ function isNpmScriptInvocation(npmCommand) {
11
+ return (npmCommand === 'run-script' ||
12
+ npmCommand === 'run' ||
13
+ Boolean(process.env.npm_lifecycle_event?.trim()));
14
+ }
15
+ export function resolveLaunchMethod(env = process.env, argv = process.argv) {
16
+ const npmExecPath = env.npm_execpath?.trim() ?? '';
17
+ const npmCommand = env.npm_command?.trim() ?? '';
18
+ if (isNpxInvocation(npmExecPath, npmCommand))
19
+ return 'npx';
20
+ if (isNpmScriptInvocation(npmCommand))
21
+ return 'npm';
22
+ const execPath = argv[0]?.trim() ?? '';
23
+ if (/node|tsx|bun/i.test(execPath))
24
+ return 'node';
25
+ return 'unknown';
26
+ }
27
+ export function getLaunchMethod() {
28
+ if (!cachedLaunchMethod) {
29
+ cachedLaunchMethod = resolveLaunchMethod();
30
+ }
31
+ return cachedLaunchMethod;
32
+ }
33
+ //# sourceMappingURL=launch-method.js.map