Skip to content

Feat/get config UI tracking#367

Merged
wonderwhy-er merged 7 commits into
mainfrom
feat/get-config-ui-tracking
Mar 3, 2026
Merged

Feat/get config UI tracking#367
wonderwhy-er merged 7 commits into
mainfrom
feat/get-config-ui-tracking

Conversation

@edgarsskore

@edgarsskore edgarsskore commented Mar 3, 2026

Copy link
Copy Markdown
Collaborator

User description

  • Harden telemetryEnabled handling so string values like "false" and "true" are normalized correctly in config writes.
  • Reuse shared telemetry-disable logic across capture paths so telemetry is consistently suppressed when disabled.
  • Add a regression test for telemetry flag handling.
  • Add/standardize UI event tracking plumbing for config editor and file preview, including call origin (ui vs llm) on set_config_value.
  • Merge latest main into feat/get-config-ui-tracking and resolve conflicts in UI app files while preserving branch behavior.

Summary by CodeRabbit

  • New Features

    • Enhanced UI event tracking and telemetry integration across config editor and file preview
    • Config changes now include origin metadata (UI vs system)
  • Bug Fixes

    • Robust boolean validation and conversion for configuration values (accepts string booleans)
    • More consistent telemetry opt-out handling and sanitized error messages to avoid leaking paths
  • Tests

    • Added comprehensive telemetry handling tests and regression coverage

CodeAnt-AI Description

Add reliable telemetry opt-out, UI event tracking, and robust boolean config inputs

What Changed

  • Telemetry flag values like "false" and "TRUE" are normalized so the system treats string "false"/"FALSE" as disabled; telemetry sending paths now respect that and stop sending after opt-out (a final opt-out event is emitted once when disabling).
  • Config editor and file preview emit structured UI tracking events (impressions, expand/collapse, success/failure) and include call origin so analytics can attribute changes to the UI versus other callers.
  • Setting boolean config values from the UI accepts string inputs "true"/"false" and returns a clear error message if the provided value is not a boolean after normalization.
  • A regression test suite verifies telemetry normalization and that telemetry paths honor string "false" values.

Impact

✅ Clearer config validation errors for boolean fields
✅ Fewer accidental telemetry sends after user opt-out
✅ Clearer analytics attribution for UI-driven config changes

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Introduce a dedicated config editor resource with structured get_config payloads and shared host-context/compact-row infrastructure so MCP UIs behave consistently across hosts while tightening config key validation and preview type coverage.
Validate blank numeric input, keep array modal open on save failures, bind tool-bridge listeners safely, and tune host-driven toggle styling/expansion behavior for embedded hosts.
Use config-manager telemetry flag helpers for GA/proxy gating and add a small regression test that verifies string 'false' handling across set_value and set_config_value.
Add a shared UI event tracker utility, wire config editor and file preview to it, and capture set_config_value call origin for telemetry analytics.
@codeant-ai

codeant-ai Bot commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

CodeAnt AI is reviewing your PR.


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@coderabbitai

coderabbitai Bot commented Mar 3, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR adds telemetry value normalization and disabled-state checks, integrates a reusable UI event tracker into the config editor and file preview, enforces boolean coercion/validation for config writes, records config call origin in telemetry, and adds tests covering telemetry behaviors.

Changes

Cohort / File(s) Summary
Telemetry core
src/config-manager.ts, src/utils/capture.ts
Added normalizeTelemetryEnabledValue() and isTelemetryDisabledValue() exports; replaced direct === false gating with isTelemetryDisabledValue(); default config explicitly includes telemetryEnabled: true.
Config tools & server
src/tools/config.ts, src/tools/schemas.ts, src/server.ts
setConfigValue now coerces "true"/"false" strings to booleans and rejects non-boolean values for boolean fields; SetConfigValueArgsSchema gains optional origin: z.enum(['ui','llm']); server adds call_origin to telemetry ('ui' vs 'llm').
UI event tracking & integration
src/ui/shared/ui-event-tracker.ts, src/ui/file-preview/src/app.ts, src/ui/config-editor/src/app.ts
New createUiEventTracker() factory and types; file-preview switched to tracker wrapper; config-editor wired to emit/track detailed UI events (updates, expansions, errors) and accepts a trackConfigUiEvent hook.
Tests
test/test-telemetry-handling.js
New test suite validating telemetry normalization, disabled-state checks, coercion paths for telemetryEnabled, and capture-path behavior for various truthy/falsey representations.

Sequence Diagram(s)

sequenceDiagram
    participant UI as UI Config Editor
    participant Controller as Config Controller
    participant Tracker as UiEventTracker
    participant Tool as ToolCaller
    participant Server as Server/Config Manager
    participant Telemetry as Telemetry Proxy

    UI->>Controller: user updates config
    Controller->>Tracker: trackConfigUiEvent('config_update', params)
    Tracker->>Tool: callTool('track_ui_event', {...baseParams, ...params})
    Tool->>Server: call set_config_value(args + origin)
    Server->>Server: normalize/store config (normalizeTelemetryEnabledValue)
    Server->>Telemetry: capture event (gated via isTelemetryDisabledValue)
    alt success
        Server-->>Controller: update success
        Controller->>Tracker: trackConfigUiEvent('config_update_success')
    else failure
        Server-->>Controller: error
        Controller->>Tracker: trackConfigUiEvent('config_update_failed', {error: sanitized})
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped through code with nimble paws,

Normalized flags and tightened laws,
"false" became false, events took flight,
Origins recorded, errors polite,
A little rabbit cheers—telemetry's bright!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Feat/get config UI tracking' is vague and uses generic formatting conventions (Feat/ prefix) that don't clearly convey the main changes, which involve telemetry hardening, config validation, and UI event tracking. Use a more descriptive title that highlights the primary change, such as 'Improve telemetry handling and add UI event tracking for config changes' or 'Harden telemetry state handling and enhance config editor analytics'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/get-config-ui-tracking

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Mar 3, 2026
@codeant-ai

codeant-ai Bot commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Sequence Diagram

Shows the core flow where a user updates a config via the UI; the Config Editor calls set_config_value (marked as originating from the UI), the server applies the change via ConfigManager which normalizes boolean telemetry inputs and emits a final telemetry opt-out event that is gated by telemetry helpers.

sequenceDiagram
    participant User
    participant ConfigEditor
    participant Server
    participant ConfigManager
    participant Capture

    User->>ConfigEditor: Save config (telemetryEnabled = "false")
    ConfigEditor->>Server: callTool set_config_value { key, value, origin: "ui" }
    Server->>ConfigManager: setValue(key="telemetryEnabled", value="false")
    ConfigManager->>ConfigManager: normalizeTelemetryEnabledValue -> false
    alt telemetry transitioning to disabled
        ConfigManager->>Capture: capture('server_telemetry_opt_out', { prev_value, reason })
        Capture->>Capture: isTelemetryDisabledValue checks config; gates sending
    end
    ConfigManager-->>Server: setValue result
    Server-->>ConfigEditor: success (updated config)
Loading

Generated by CodeAnt AI

@codeant-ai

codeant-ai Bot commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Nitpicks 🔍

🔒 No security issues identified
⚡ Recommended areas for review

  • Telemetry Opt-out Capture
    The code sends a telemetry event when users opt out and includes prev_value drawn directly from config.
    Ensure that the captured prev_value cannot leak sensitive data (or complex objects), and that opt-out is only reported once.
    Consider sanitizing/whitelisting what is sent and race conditions when reading/writing the config concurrently.

  • Telemetry Sanitation
    The new sanitizeTelemetryErrorMessage improves redaction of path-like strings but the regexes may not cover every path format (UNC paths, some Windows patterns) or other sensitive tokens (emails, tokens). Incomplete redaction could leak PII/secrets when error messages are sent to telemetry. Verify redaction rules and consider stricter whitelisting or additional patterns.

  • Telemetry Source Trust
    A new call_origin field is populated from args.origin and recorded in telemetry.
    This value is user-controlled (incoming request data) — verify you are whitelisting/validating it to avoid spoofed telemetry or accidental PII/metadata leakage.

  • Model Context Change
    syncModelContext now early-returns when !change and no longer sends the full entries snapshot (the snapshot was removed). Confirm hosts that expected full snapshots are not relying on the previous behavior. Also validate that the call to app.updateModelContext happens only when app is initialized (the function references app declared later) and consider defensive checks or ordering.

  • Input Normalization
    The newly added normalization helpers accept only string forms of boolean values.
    Validate whether other forms (e.g. numeric '1'/'0', 'yes'/'no', actual booleans) need canonicalization to avoid inconsistent config state.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/ui/shared/ui-event-tracker.ts (1)

35-38: Protect base telemetry context from accidental overrides.

Per-event params currently override baseParams. For stable context fields, prefer base params taking precedence.

♻️ Proposed adjustment
         params: {
-            ...baseParams,
             ...normalizeUiEventParams(params),
+            ...baseParams,
         },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/shared/ui-event-tracker.ts` around lines 35 - 38, The merge currently
spreads baseParams then normalizeUiEventParams(params) so per-event fields can
override the shared context; update the merge in the params construction inside
ui-event-tracker.ts to ensure baseParams have precedence (i.e., merge per-event
params first then baseParams or use Object.assign with per-event then base),
referencing the existing symbols baseParams and normalizeUiEventParams(params)
and the params object so stable context fields from baseParams cannot be
accidentally overridden by per-event values.
src/ui/config-editor/src/app.ts (1)

465-483: Consider emitting config_update_success only after refresh succeeds.

Current ordering can report success even when the follow-up refresh fails and UI shows an error.

♻️ Proposed adjustment
-            trackConfigUiEvent?.('config_update_success', {
-                tool_name: 'set_config_value',
-                ...buildConfigUpdateTelemetryParams({
-                    configKey: selected.key,
-                    valueType: selected.valueType,
-                }),
-            });
-
             const refreshed = await callTool('get_config', {});
             if (isToolErrorResult(refreshed)) {
                 const errorMessage = extractToolText(refreshed) ?? 'Value was updated but config refresh failed.';
                 return {
                     ok: false,
                     tooltip: {
                         message: errorMessage,
                         tone: 'error',
                     },
                 };
             }
@@
+            trackConfigUiEvent?.('config_update_success', {
+                tool_name: 'set_config_value',
+                ...buildConfigUpdateTelemetryParams({
+                    configKey: selected.key,
+                    valueType: selected.valueType,
+                }),
+            });
+
             return {
                 ok: true,
             };

Also applies to: 496-499

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/config-editor/src/app.ts` around lines 465 - 483, Move the telemetry
success emission so it only runs after the config refresh succeeds: call
callTool('get_config', {}) and check with isToolErrorResult(refreshed) and
extractToolText(refreshed) first, and only if the refresh is not an error invoke
trackConfigUiEvent('config_update_success', { tool_name: 'set_config_value',
...buildConfigUpdateTelemetryParams({ configKey: selected.key, valueType:
selected.valueType }) }). Apply the same change to the other occurrence that
currently emits success before refresh (the block using trackConfigUiEvent,
callTool, isToolErrorResult, and extractToolText around the second update path).
test/test-telemetry-handling.js (1)

26-53: Consider expanding coercion tests beyond the 'false' path.

Current tests validate one branch only. Add 'true' and invalid-string cases to lock behavior for both success and error paths.

Suggested additions
 async function testConfigManagerCoercion() {
   console.log('\n--- Test: configManager telemetry coercion ---');

   await configManager.updateConfig({ telemetryEnabled: false });
   await configManager.setValue('telemetryEnabled', 'false');

   const telemetryEnabled = await configManager.getValue('telemetryEnabled');
   assert.strictEqual(telemetryEnabled, false);
   assert.strictEqual(typeof telemetryEnabled, 'boolean');
+
+  await configManager.setValue('telemetryEnabled', 'true');
+  const telemetryEnabledTrue = await configManager.getValue('telemetryEnabled');
+  assert.strictEqual(telemetryEnabledTrue, true);
+  assert.strictEqual(typeof telemetryEnabledTrue, 'boolean');

   console.log('ok: configManager coercion');
 }
 async function testSetConfigValueCoercion() {
   console.log('\n--- Test: set_config_value telemetry coercion ---');

   await configManager.updateConfig({ telemetryEnabled: false });
   const response = await setConfigValue({ key: 'telemetryEnabled', value: 'false' });

   assert.ok(response);
   assert.notStrictEqual(response.isError, true);

   const telemetryEnabled = await configManager.getValue('telemetryEnabled');
   assert.strictEqual(telemetryEnabled, false);
   assert.strictEqual(typeof telemetryEnabled, 'boolean');
+
+  const responseTrue = await setConfigValue({ key: 'telemetryEnabled', value: 'true' });
+  assert.notStrictEqual(responseTrue.isError, true);
+  assert.strictEqual(await configManager.getValue('telemetryEnabled'), true);
+
+  const responseInvalid = await setConfigValue({ key: 'telemetryEnabled', value: 'disabled' });
+  assert.strictEqual(responseInvalid.isError, true);

   console.log('ok: set_config_value coercion');
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/test-telemetry-handling.js` around lines 26 - 53, Add test cases for
both the true path and invalid-string error path to the existing coercion tests:
within testConfigManagerCoercion and testSetConfigValueCoercion (and/or new
tests named e.g., testConfigManagerCoercion_true and
testConfigManagerCoercion_invalid), set telemetryEnabled to 'true' and assert
the resulting value is boolean true, then set telemetryEnabled to an invalid
string (like 'notabool') and assert the code either returns an error or
preserves the prior value depending on intended behavior; for setConfigValue use
the same three inputs ('false', 'true', and an invalid string) and assert
response.isError and configManager.getValue results accordingly so both success
and error branches are covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/test-telemetry-handling.js`:
- Around line 56-57: The test currently assigns originalConfig = await
configManager.getConfig() which is only a shallow copy and allows nested
arrays/objects (e.g., blockedCommands) to be mutated by tests; replace the
shallow snapshot with a deep defensive clone by calling structuredClone on the
value returned from configManager.getConfig() (and likewise use structuredClone
when preparing the restore at setConfig/restore code around originalConfig) so
the test's originalConfig is immutable to nested mutations.
- Around line 77-86: The direct comparison of import.meta.url to
`file://${process.argv[1]}` can fail due to URL encoding and platform path
differences; update the entrypoint check to convert import.meta.url with
fileURLToPath and normalize both sides with path.resolve before comparing.
Specifically, import and use fileURLToPath from 'url' and path.resolve from
'path', then compare path.resolve(fileURLToPath(import.meta.url)) ===
path.resolve(process.argv[1]) (the block surrounding runTests() should remain
the same) so the check is robust across platforms and encoded characters.

---

Nitpick comments:
In `@src/ui/config-editor/src/app.ts`:
- Around line 465-483: Move the telemetry success emission so it only runs after
the config refresh succeeds: call callTool('get_config', {}) and check with
isToolErrorResult(refreshed) and extractToolText(refreshed) first, and only if
the refresh is not an error invoke trackConfigUiEvent('config_update_success', {
tool_name: 'set_config_value', ...buildConfigUpdateTelemetryParams({ configKey:
selected.key, valueType: selected.valueType }) }). Apply the same change to the
other occurrence that currently emits success before refresh (the block using
trackConfigUiEvent, callTool, isToolErrorResult, and extractToolText around the
second update path).

In `@src/ui/shared/ui-event-tracker.ts`:
- Around line 35-38: The merge currently spreads baseParams then
normalizeUiEventParams(params) so per-event fields can override the shared
context; update the merge in the params construction inside ui-event-tracker.ts
to ensure baseParams have precedence (i.e., merge per-event params first then
baseParams or use Object.assign with per-event then base), referencing the
existing symbols baseParams and normalizeUiEventParams(params) and the params
object so stable context fields from baseParams cannot be accidentally
overridden by per-event values.

In `@test/test-telemetry-handling.js`:
- Around line 26-53: Add test cases for both the true path and invalid-string
error path to the existing coercion tests: within testConfigManagerCoercion and
testSetConfigValueCoercion (and/or new tests named e.g.,
testConfigManagerCoercion_true and testConfigManagerCoercion_invalid), set
telemetryEnabled to 'true' and assert the resulting value is boolean true, then
set telemetryEnabled to an invalid string (like 'notabool') and assert the code
either returns an error or preserves the prior value depending on intended
behavior; for setConfigValue use the same three inputs ('false', 'true', and an
invalid string) and assert response.isError and configManager.getValue results
accordingly so both success and error branches are covered.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e02a65f and a7ebb7b.

📒 Files selected for processing (9)
  • src/config-manager.ts
  • src/server.ts
  • src/tools/config.ts
  • src/tools/schemas.ts
  • src/ui/config-editor/src/app.ts
  • src/ui/file-preview/src/app.ts
  • src/ui/shared/ui-event-tracker.ts
  • src/utils/capture.ts
  • test/test-telemetry-handling.js

Comment on lines +56 to +57
const originalConfig = await configManager.getConfig();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

fd 'config-manager' --type f

Repository: wonderwhy-er/DesktopCommanderMCP

Length of output: 97


🏁 Script executed:

cat -n src/config-manager.ts | head -150

Repository: wonderwhy-er/DesktopCommanderMCP

Length of output: 5884


🏁 Script executed:

rg -n "getConfig|updateConfig|saveConfig" src/config-manager.ts

Repository: wonderwhy-er/DesktopCommanderMCP

Length of output: 376


🏁 Script executed:

sed -n '191,200p' src/config-manager.ts

Repository: wonderwhy-er/DesktopCommanderMCP

Length of output: 300


🏁 Script executed:

cat -n test/test-telemetry-handling.js | sed -n '50,85p'

Repository: wonderwhy-er/DesktopCommanderMCP

Length of output: 1308


🏁 Script executed:

sed -n '242,260p' src/config-manager.ts

Repository: wonderwhy-er/DesktopCommanderMCP

Length of output: 574


🏁 Script executed:

cat -n test/test-telemetry-handling.js | sed -n '1,55p'

Repository: wonderwhy-er/DesktopCommanderMCP

Length of output: 2432


Use structuredClone() to defensively snapshot config and prevent reference-mutation leakage.

getConfig() returns a shallow copy ({ ...this.config }), so nested objects and arrays like blockedCommands remain as references to the original. If any test mutates these nested structures, the snapshot in originalConfig would also be mutated, making the restore at line 73 ineffective. Use structuredClone() for a deep copy that protects against this.

Suggested hardening
 export default async function runTests() {
-  const originalConfig = await configManager.getConfig();
+  const originalConfig = structuredClone(await configManager.getConfig());

Also applies to: 73-74

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/test-telemetry-handling.js` around lines 56 - 57, The test currently
assigns originalConfig = await configManager.getConfig() which is only a shallow
copy and allows nested arrays/objects (e.g., blockedCommands) to be mutated by
tests; replace the shallow snapshot with a deep defensive clone by calling
structuredClone on the value returned from configManager.getConfig() (and
likewise use structuredClone when preparing the restore at setConfig/restore
code around originalConfig) so the test's originalConfig is immutable to nested
mutations.

Comment on lines +77 to +86
if (import.meta.url === `file://${process.argv[1]}`) {
runTests()
.then((success) => {
process.exit(success ? 0 : 1);
})
.catch((error) => {
console.error('Unhandled error:', error);
process.exit(1);
});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n test/test-telemetry-handling.js | head -100

Repository: wonderwhy-er/DesktopCommanderMCP

Length of output: 3479


🌐 Web query:

Node.js ESM import.meta.url comparison process.argv[1] platform issues

💡 Result:

Why import.meta.url vs process.argv[1] can be flaky across platforms

  • They’re different “kinds” of identifiers: import.meta.url is a file: URL string, while process.argv[1] is an absolute filesystem path string (Node resolves it via path.resolve). (2ality.com)
  • URL encoding vs raw paths: ESM modules are resolved/cached as URLs, so characters may be percent-encoded in import.meta.url (e.g. #%23), while process.argv[1] is not. (nodejs.org)
  • Windows-specific traps:
    • If you do new URL(import.meta.url).pathname, you’ll often get a leading slash like /C:/..., which is not a valid Windows path; use fileURLToPath() instead. (bero.dev)
    • file: URLs with hostnames can map to UNC paths (\\server\share\...). (r2.nodejs.org)
  • “Main module” detection edge cases: comparing strings can fail if the script is invoked in different ways (e.g., extensionless invocation, wrappers, etc.). (stackoverflow.com)

Recommended solutions

1) Best (Node.js ≥ v24.2.0): import.meta.main

Node now provides a built-in boolean for “is this the entry point?” (nodejs.org)

if (import.meta.main) {
  // run as: node yourfile.mjs
}

2) Portable workaround (older Node): normalize to the same representation

Convert the CLI path to a file URL (or convert import.meta.url to a path) before comparing:

import { pathToFileURL, fileURLToPath } from 'node:url';
import { resolve } from 'node:path';

const isMain =
  process.argv[1] &&
  import.meta.url === pathToFileURL(resolve(process.argv[1])).href;
// or:
// resolve(process.argv[1]) === fileURLToPath(import.meta.url)

This avoids Windows pathname pitfalls and compares like-with-like. (2ality.com)

Citations:


Use path-normalized direct-execution check for ESM entrypoints.

Line 77 directly compares import.meta.url (a file: URL with potential percent-encoding) against a constructed URL string, which can fail across platforms and with URL-encoded characters (e.g., #%23). Normalize both to resolved filesystem paths using fileURLToPath() + path.resolve().

Suggested fix
 import assert from 'assert';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
@@
-if (import.meta.url === `file://${process.argv[1]}`) {
+const isDirectRun =
+  typeof process.argv[1] === 'string' &&
+  path.resolve(fileURLToPath(import.meta.url)) === path.resolve(process.argv[1]);
+
+if (isDirectRun) {
   runTests()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (import.meta.url === `file://${process.argv[1]}`) {
runTests()
.then((success) => {
process.exit(success ? 0 : 1);
})
.catch((error) => {
console.error('Unhandled error:', error);
process.exit(1);
});
}
const isDirectRun =
typeof process.argv[1] === 'string' &&
path.resolve(fileURLToPath(import.meta.url)) === path.resolve(process.argv[1]);
if (isDirectRun) {
runTests()
.then((success) => {
process.exit(success ? 0 : 1);
})
.catch((error) => {
console.error('Unhandled error:', error);
process.exit(1);
});
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/test-telemetry-handling.js` around lines 77 - 86, The direct comparison
of import.meta.url to `file://${process.argv[1]}` can fail due to URL encoding
and platform path differences; update the entrypoint check to convert
import.meta.url with fileURLToPath and normalize both sides with path.resolve
before comparing. Specifically, import and use fileURLToPath from 'url' and
path.resolve from 'path', then compare
path.resolve(fileURLToPath(import.meta.url)) === path.resolve(process.argv[1])
(the block surrounding runTests() should remain the same) so the check is robust
across platforms and encoded characters.

@codeant-ai

codeant-ai Bot commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

CodeAnt AI finished reviewing your PR.

@codeant-ai

codeant-ai Bot commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

CodeAnt AI is running Incremental review


Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@codeant-ai codeant-ai Bot added size:L This PR changes 100-499 lines, ignoring generated files and removed size:L This PR changes 100-499 lines, ignoring generated files labels Mar 3, 2026
@codeant-ai

codeant-ai Bot commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Sequence Diagram

Shows the main success path when the UI updates a config (including origin marking) and how telemetry opt-out is normalized and emits a final opt-out event that is gated by the telemetry-disabled helper added in this PR.

sequenceDiagram
    participant UI
    participant Server
    participant ConfigManager
    participant CaptureService

    UI->>Server: callTool set_config_value { key, value, origin: "ui" }
    Server->>ConfigManager: setValue(key, value) (preserves origin metadata)
    ConfigManager->>ConfigManager: normalizeTelemetryEnabledValue(value) (coerce "true"/"false")
    alt value becomes disabled (false)
        ConfigManager->>CaptureService: capture('server_telemetry_opt_out', { prev_value })
        CaptureService-->>ConfigManager: (checks isTelemetryDisabledValue and sends if allowed)
    end
    ConfigManager-->>Server: OK (value saved)
    Server-->>UI: success response
Loading

Generated by CodeAnt AI

@codeant-ai

codeant-ai Bot commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

CodeAnt AI Incremental review completed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants