chrome-devtools-mcp 0.20.2 → 0.21.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.
@@ -4,11 +4,99 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
  import process from 'node:process';
7
+ import { DAEMON_CLIENT_NAME } from '../daemon/utils.js';
7
8
  import { logger } from '../logger.js';
8
9
  import { FilePersistence } from './persistence.js';
9
- import { WatchdogMessageType, OsType } from './types.js';
10
+ import { McpClient, WatchdogMessageType, OsType, } from './types.js';
10
11
  import { WatchdogClient } from './WatchdogClient.js';
11
12
  const MS_PER_DAY = 24 * 60 * 60 * 1000;
13
+ const PARAM_BLOCKLIST = new Set(['uid']);
14
+ const SUPPORTED_ZOD_TYPES = [
15
+ 'ZodString',
16
+ 'ZodNumber',
17
+ 'ZodBoolean',
18
+ 'ZodArray',
19
+ 'ZodEnum',
20
+ ];
21
+ function isZodType(type) {
22
+ return SUPPORTED_ZOD_TYPES.includes(type);
23
+ }
24
+ function getZodType(zodType) {
25
+ const def = zodType._def;
26
+ const typeName = def.typeName;
27
+ if (typeName === 'ZodOptional' ||
28
+ typeName === 'ZodDefault' ||
29
+ typeName === 'ZodNullable') {
30
+ return getZodType(def.innerType);
31
+ }
32
+ if (typeName === 'ZodEffects') {
33
+ return getZodType(def.schema);
34
+ }
35
+ if (isZodType(typeName)) {
36
+ return typeName;
37
+ }
38
+ throw new Error(`Unsupported zod type for tool parameter: ${typeName}`);
39
+ }
40
+ function transformName(zodType, name) {
41
+ if (zodType === 'ZodString') {
42
+ return `${name}_length`;
43
+ }
44
+ else if (zodType === 'ZodArray') {
45
+ return `${name}_count`;
46
+ }
47
+ else {
48
+ return name;
49
+ }
50
+ }
51
+ function transformValue(zodType, value) {
52
+ if (zodType === 'ZodString') {
53
+ return value.length;
54
+ }
55
+ else if (zodType === 'ZodArray') {
56
+ return value.length;
57
+ }
58
+ else {
59
+ return value;
60
+ }
61
+ }
62
+ function hasEquivalentType(zodType, value) {
63
+ if (zodType === 'ZodString') {
64
+ return typeof value === 'string';
65
+ }
66
+ else if (zodType === 'ZodArray') {
67
+ return Array.isArray(value);
68
+ }
69
+ else if (zodType === 'ZodNumber') {
70
+ return typeof value === 'number';
71
+ }
72
+ else if (zodType === 'ZodBoolean') {
73
+ return typeof value === 'boolean';
74
+ }
75
+ else if (zodType === 'ZodEnum') {
76
+ return (typeof value === 'string' ||
77
+ typeof value === 'number' ||
78
+ typeof value === 'boolean');
79
+ }
80
+ else {
81
+ return false;
82
+ }
83
+ }
84
+ export function sanitizeParams(params, schema) {
85
+ const transformed = {};
86
+ for (const [name, value] of Object.entries(params)) {
87
+ if (PARAM_BLOCKLIST.has(name)) {
88
+ continue;
89
+ }
90
+ const zodType = getZodType(schema[name]);
91
+ if (!hasEquivalentType(zodType, value)) {
92
+ throw new Error(`parameter ${name} has type ${zodType} but value ${value} is not of equivalent type`);
93
+ }
94
+ const transformedName = transformName(zodType, name);
95
+ const transformedValue = transformValue(zodType, value);
96
+ transformed[transformedName] = transformedValue;
97
+ }
98
+ return transformed;
99
+ }
12
100
  function detectOsType() {
13
101
  switch (process.platform) {
14
102
  case 'win32':
@@ -24,6 +112,7 @@ function detectOsType() {
24
112
  export class ClearcutLogger {
25
113
  #persistence;
26
114
  #watchdog;
115
+ #mcpClient;
27
116
  constructor(options) {
28
117
  this.#persistence = options.persistence ?? new FilePersistence();
29
118
  this.#watchdog =
@@ -37,11 +126,37 @@ export class ClearcutLogger {
37
126
  clearcutForceFlushIntervalMs: options.clearcutForceFlushIntervalMs,
38
127
  clearcutIncludePidHeader: options.clearcutIncludePidHeader,
39
128
  });
129
+ this.#mcpClient = McpClient.MCP_CLIENT_UNSPECIFIED;
130
+ }
131
+ setClientName(clientName) {
132
+ const lowerName = clientName.toLowerCase();
133
+ if (lowerName.includes('claude')) {
134
+ this.#mcpClient = McpClient.MCP_CLIENT_CLAUDE_CODE;
135
+ }
136
+ else if (lowerName.includes('gemini')) {
137
+ this.#mcpClient = McpClient.MCP_CLIENT_GEMINI_CLI;
138
+ }
139
+ else if (clientName === DAEMON_CLIENT_NAME) {
140
+ this.#mcpClient = McpClient.MCP_CLIENT_DT_MCP_CLI;
141
+ }
142
+ else if (lowerName.includes('openclaw')) {
143
+ this.#mcpClient = McpClient.MCP_CLIENT_OPENCLAW;
144
+ }
145
+ else if (lowerName.includes('codex')) {
146
+ this.#mcpClient = McpClient.MCP_CLIENT_CODEX;
147
+ }
148
+ else if (lowerName.includes('antigravity')) {
149
+ this.#mcpClient = McpClient.MCP_CLIENT_ANTIGRAVITY;
150
+ }
151
+ else {
152
+ this.#mcpClient = McpClient.MCP_CLIENT_OTHER;
153
+ }
40
154
  }
41
155
  async logToolInvocation(args) {
42
156
  this.#watchdog.send({
43
157
  type: WatchdogMessageType.LOG_EVENT,
44
158
  payload: {
159
+ mcp_client: this.#mcpClient,
45
160
  tool_invocation: {
46
161
  tool_name: args.toolName,
47
162
  success: args.success,
@@ -54,6 +169,7 @@ export class ClearcutLogger {
54
169
  this.#watchdog.send({
55
170
  type: WatchdogMessageType.LOG_EVENT,
56
171
  payload: {
172
+ mcp_client: this.#mcpClient,
57
173
  server_start: {
58
174
  flag_usage: flagUsage,
59
175
  },
@@ -74,6 +190,7 @@ export class ClearcutLogger {
74
190
  this.#watchdog.send({
75
191
  type: WatchdogMessageType.LOG_EVENT,
76
192
  payload: {
193
+ mcp_client: this.#mcpClient,
77
194
  daily_active: {
78
195
  days_since_last_active: daysSince,
79
196
  },
@@ -24,6 +24,11 @@ export var McpClient;
24
24
  McpClient[McpClient["MCP_CLIENT_UNSPECIFIED"] = 0] = "MCP_CLIENT_UNSPECIFIED";
25
25
  McpClient[McpClient["MCP_CLIENT_CLAUDE_CODE"] = 1] = "MCP_CLIENT_CLAUDE_CODE";
26
26
  McpClient[McpClient["MCP_CLIENT_GEMINI_CLI"] = 2] = "MCP_CLIENT_GEMINI_CLI";
27
+ McpClient[McpClient["MCP_CLIENT_DT_MCP_CLI"] = 4] = "MCP_CLIENT_DT_MCP_CLI";
28
+ McpClient[McpClient["MCP_CLIENT_OPENCLAW"] = 5] = "MCP_CLIENT_OPENCLAW";
29
+ McpClient[McpClient["MCP_CLIENT_CODEX"] = 6] = "MCP_CLIENT_CODEX";
30
+ McpClient[McpClient["MCP_CLIENT_ANTIGRAVITY"] = 7] = "MCP_CLIENT_ANTIGRAVITY";
31
+ McpClient[McpClient["MCP_CLIENT_OTHER"] = 3] = "MCP_CLIENT_OTHER";
27
32
  })(McpClient || (McpClient = {}));
28
33
  // IPC types for messages between the main process and the
29
34
  // telemetry watchdog process.