Skip to content

Add CI check for telemetry tree-shaking validation#8623

Open
comfy-pr-bot wants to merge 3 commits intomainfrom
feature/add-ci-telemetry-tree-shaking-validation
Open

Add CI check for telemetry tree-shaking validation#8623
comfy-pr-bot wants to merge 3 commits intomainfrom
feature/add-ci-telemetry-tree-shaking-validation

Conversation

@comfy-pr-bot
Copy link
Member

@comfy-pr-bot comfy-pr-bot commented Feb 5, 2026

Summary

Adds a GitHub Actions workflow to prevent telemetry code from being accidentally shipped to OSS/local/desktop builds.

Context

Implementation

  • New workflow: .github/workflows/ci-telemetry-tree-shaking.yaml
  • Runs on PRs and pushes to main/dev branches
  • Builds the project and searches dist/ for telemetry patterns
  • Fails if any GTM/GA code found in compiled output
  • Provides clear error messages with fix instructions

How It Works

The CI check searches for these patterns in the compiled dist files:

  • googletagmanager - GTM domain references
  • gtm.js - GTM script file
  • analytics.js - GA script file
  • gtag(.config - gtag config calls (matches both single/double quotes)
  • gtag(.event - gtag event calls (matches both single/double quotes)

Example: What Gets Caught

If you accidentally add top-level telemetry code like:

// ❌ BAD: This will NOT be tree-shaken
export function initAnalytics() {
  const gtagId = 'googletagmanager.com/gtm.js?id=GTM-123'
  window.gtag('config', 'GA-123')
  window.gtag('event', 'page_view')
}

The CI will FAIL with:

dist/assets/index-DoyeA3s7.js:  const gtagId = "googletagmanager.com/gtm.js?id=GTM-123";
dist/assets/index-DoyeA3s7.js:  window.gtag("config", "GA-123");
dist/assets/index-DoyeA3s7.js:  window.gtag("event", "page_view");

❌ ERROR: Found GTM/GA code in dist files!

To fix this:
1. Use the TelemetryProvider pattern (see src/platform/telemetry/)
2. Call telemetry via useTelemetry() hook
3. Avoid top-level imports of GTM/GA libraries
4. Use conditional dynamic imports behind isCloud checks

What's Allowed

✅ Mixpanel is allowed - it uses conditional dynamic imports and only loads in cloud builds
✅ Source maps and credit files are excluded from checks

Testing

Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com

┆Issue is synchronized with this Notion page by Unito

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

🎭 Playwright Tests: ⚠️ Passed with flaky tests

Results: 507 passed, 0 failed, 2 flaky, 8 skipped (Total: 517)

❌ Failed Tests

📊 Browser Reports
  • chromium: View Report (✅ 495 / ❌ 0 / ⚠️ 2 / ⏭️ 8)
  • chromium-2x: View Report (✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • chromium-0.5x: View Report (✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • mobile-chrome: View Report (✅ 9 / ❌ 0 / ⚠️ 0 / ⏭️ 0)

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 02/06/2026, 02:19:46 PM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 5, 2026

📝 Walkthrough

Walkthrough

Adds a CI workflow to validate telemetry code is tree-shaken from builds, plus a deliberate telemetry violation in source (new src/test-telemetry-violation.ts and two calls from src/main.ts) used to exercise the validation.

Changes

Cohort / File(s) Summary
GitHub Actions CI Workflow
.github/workflows/ci-telemetry-tree-shaking.yaml
New workflow "CI: Telemetry Tree-Shaking Validation" triggered on PRs and pushes to main/dev*. Runs build and scans dist for GTM/GA telemetry patterns; fails with remediation guidance if violations found.
Application entry
src/main.ts
Adds two calls to initializeAnalytics() (test telemetry invocation) to intentionally introduce a telemetry usage for CI validation.
Telemetry test helper
src/test-telemetry-violation.ts
New file exporting initializeAnalytics() and augmenting Window.gtag; invokes window.gtag('config', ...) and window.gtag('event', ...) to preserve telemetry call paths for tree-shaking detection.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant GitHub as GitHub (Push/PR)
participant Actions as Actions Runner
participant Repo as Repository (checkout)
participant Builder as Build (pnpm)
participant Scanner as Telemetry Scanner

GitHub->>Actions: trigger workflow
Actions->>Repo: checkout code
Actions->>Builder: setup & run build
Builder->>Scanner: provide dist/
Scanner->>Scanner: scan for GTM/GA patterns
alt violations found
    Scanner->>Actions: fail job with error block
else no violations
    Scanner->>Actions: print success message
end

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through the code with a curious twitch,
I left a small beacon — a telemetry stitch,
The CI will scan, with a bright little bell,
Catching the traces where secrets might dwell,
Hooray for clean builds — now back to my itch!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 59.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add CI check for telemetry tree-shaking validation' clearly and specifically describes the main change: adding a GitHub Actions workflow to validate that telemetry code is properly tree-shaken.
Description check ✅ Passed The PR description comprehensively covers all required sections with clear context, implementation details, testing approach, and helpful examples of what gets caught.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/add-ci-telemetry-tree-shaking-validation

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.

@socket-security
Copy link

socket-security bot commented Feb 5, 2026

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

Bundle Size Report

Summary

  • Raw size: 20.2 MB baseline 20.2 MB — ⚪ 0 B
  • Gzip: 4.32 MB baseline 4.32 MB — ⚪ 0 B
  • Brotli: 3.34 MB baseline 3.34 MB — ⚪ 0 B
  • Bundles: 233 current • 233 baseline

Category Glance
Vendor & Third-Party ⚪ 0 B (9.37 MB) · Other ⚪ 0 B (7.1 MB) · Data & Services ⚪ 0 B (2.1 MB) · Graph Workspace ⚪ 0 B (840 kB) · Panels & Settings ⚪ 0 B (410 kB) · Utilities & Hooks ⚪ 0 B (234 kB) · + 5 more

Per-category breakdown
App Entry Points — 22.5 kB (baseline 22.5 kB) • ⚪ 0 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-Dj4QzKF0.js 22.5 kB 22.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Graph Workspace — 840 kB (baseline 840 kB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-BoT0juUT.js 840 kB 840 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Views & Navigation — 69 kB (baseline 69 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudAuthTimeoutView-BLck4lp7.js 4.91 kB 4.91 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudForgotPasswordView-Cg-UGqAM.js 5.56 kB 5.56 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudLayoutView-C2e08tqG.js 6.43 kB 6.43 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudLoginView-CJBh090I.js 10 kB 10 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudSignupView-lOHQ-z6C.js 7.38 kB 7.38 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudSorryContactSupportView-BPXBOTez.js 1.02 kB 1.02 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudSubscriptionRedirectView-T8B_rKuq.js 4.71 kB 4.71 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudSurveyView-CdvBA3Nl.js 15.8 kB 15.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/layout-ncetNFDR.js 296 B 296 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserCheckView-Cx7E6AFj.js 8.39 kB 8.39 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserSelectView-RGdfDzzz.js 4.49 kB 4.49 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Panels & Settings — 410 kB (baseline 410 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/AboutPanel-Btv4aEbD.js 8.62 kB 8.62 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/cloudRemoteConfig-3RjIrMkK.js 1.44 kB 1.44 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/config-HAvaVehF.js 1.01 kB 1.01 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ExtensionPanel-DSY9As5h.js 9.49 kB 9.49 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/KeybindingPanel-CFRnolTC.js 12.6 kB 12.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/LegacyCreditsPanel-e4I_EcQB.js 20.8 kB 20.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/refreshRemoteConfig-BgyiXDuv.js 1.13 kB 1.13 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/refreshRemoteConfig-DPKKOPo3.js 345 B 345 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/remoteConfig-CUBB_j_I.js 581 B 581 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SecretsPanel-C0Ccjtcq.js 21.5 kB 21.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ServerConfigPanel-DDW0HSo0.js 6.64 kB 6.64 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BgcR6REE.js 25 kB 25 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BmEXiKRV.js 32 kB 32 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BNs5rnMt.js 24.1 kB 24.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-C5jqELHS.js 23.6 kB 23.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CKCscONF.js 28.1 kB 28.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CzcL_U24.js 20.8 kB 20.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-D95NIw0v.js 26.8 kB 26.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DmYc-PH9.js 24.2 kB 24.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DQe4OZm2.js 25.7 kB 25.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-Dxocpd_-.js 20.3 kB 20.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-f2yAwEpW.js 23.3 kB 23.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SubscriptionPanel-DGXud9NC.js 18.8 kB 18.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserPanel-CQgjaEdm.js 6.28 kB 6.28 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WorkspacePanel-EC7DJYGe.js 26.9 kB 26.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
User & Accounts — 16 kB (baseline 16 kB) • ⚪ 0 B

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-B4tEzJ7G.js 3.4 kB 3.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/auth-Dcy-z73C.js 347 B 347 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/firebaseAuthStore-mq59gNxh.js 790 B 790 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/PasswordFields-BAi3GPM-.js 4.51 kB 4.51 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SignUpForm-BSpae2Cf.js 3.01 kB 3.01 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UpdatePasswordContent-L0JzGx5w.js 2.37 kB 2.37 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WorkspaceProfilePic-B0BztYjc.js 1.57 kB 1.57 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Editors & Dialogs — 3.47 kB (baseline 3.47 kB) • ⚪ 0 B

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useSubscriptionDialog-D-WmTKxp.js 783 B 783 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useSubscriptionDialog-Pm320iRZ.js 2.68 kB 2.68 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
UI Components — 37.8 kB (baseline 37.8 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/Button-ChqYCdrL.js 3 kB 3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudBadge-nZ5YFAbJ.js 1.2 kB 1.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/cloudFeedbackTopbarButton-DQlwc7nC.js 1.6 kB 1.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ComfyQueueButton-BCot3PGl.js 7.13 kB 7.13 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ComfyQueueButton-DlZg_exB.js 795 B 795 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SubscribeButton-DcXjUYdv.js 3.68 kB 3.68 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/TopbarBadge-BsZTG314.js 7.52 kB 7.52 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/UserAvatar-Dtdiv1Hu.js 1.17 kB 1.17 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useTerminalTabs-BkQJHR3C.js 9.9 kB 9.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetButton-DVfWCi_V.js 1.84 kB 1.84 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Data & Services — 2.1 MB (baseline 2.1 MB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/api-7EHTuGQP.js 641 kB 641 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/audioService-BouFc6he.js 1.73 kB 1.73 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/bootstrapStore-BddSu94k.js 2.13 kB 2.13 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/dialogService-9SmI0wfa.js 1.3 MB 1.3 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/dialogStore-D2gUGUn6.js 4.1 kB 4.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/keybindingService-oR8W5ZJk.js 6.58 kB 6.58 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/load3dService-CQbDlxIr.js 91.1 kB 91.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/releaseStore-DWAS8XnF.js 8.14 kB 8.14 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/releaseStore-FtDZWDtW.js 762 B 762 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/serverConfigStore-DB58Z5s2.js 2.32 kB 2.32 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/systemStatsStore-DpwWWYi1.js 12.3 kB 12.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/teamWorkspaceStore-u-xjun7f.js 27.1 kB 27.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/userStore-D-p_SVm_.js 1.85 kB 1.85 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Utilities & Hooks — 234 kB (baseline 234 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/_plugin-vue_export-helper-CAbbkOlw.js 315 B 315 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/audioUtils-8ftIr8xG.js 858 B 858 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/colorUtil-FW_Ghng2.js 7 kB 7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/envUtil-Djb4sHrV.js 524 B 524 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/markdownRendererUtil-Cc2LFa5s.js 1.56 kB 1.56 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/networkUtil-Du2a_n7V.js 1.07 kB 1.07 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SkeletonUtils-DwBAnKr-.js 133 B 133 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/subscriptionCheckoutUtil-D--An4VW.js 1.75 kB 1.75 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useConflictDetection-Cyk81ZLv.js 177 kB 177 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useCopyToClipboard-BCOSf9ef.js 1.57 kB 1.57 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useCurrentUser-BGbQUrcJ.js 724 B 724 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useErrorHandling-B-3BGL76.js 4.26 kB 4.26 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useExternalLink-DWs-fjHA.js 1.63 kB 1.63 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useLoad3d--JLfQ151.js 14.4 kB 14.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useLoad3d-Dn8tD2IX.js 861 B 861 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useLoad3dViewer-DLGsls-S.js 14.2 kB 14.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useLoad3dViewer-DXJ_mziW.js 840 B 840 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useSubscriptionActions-Cc97tziM.js 1.76 kB 1.76 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useSubscriptionCredits-08m0FdFr.js 1.07 kB 1.07 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/useWorkspaceUI-CTUia8rM.js 3.16 kB 3.16 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Vendor & Third-Party — 9.37 MB (baseline 9.37 MB) • ⚪ 0 B

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-axios-D0w6WYH0.js 71.6 kB 71.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-chart-CIdI9Yl4.js 399 kB 399 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-firebase-CLEC0CcJ.js 842 kB 842 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-i18n-C6_f776o.js 132 kB 132 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-markdown-BkVHYrKV.js 102 kB 102 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-other-DPcKX1Hx.js 2.16 MB 2.16 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-primevue-Dw8RivU1.js 1.74 MB 1.74 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-reka-ui-CPrt7lw0.js 240 kB 240 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-sentry-BVA5kbUC.js 183 kB 183 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-CJhOuqDg.js 1.8 MB 1.8 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-CvX7mojg.js 632 kB 632 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-core-BBP9kkTE.js 312 kB 312 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vueuse-CS5mlw4Q.js 111 kB 111 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-DOEEpxXk.js 398 kB 398 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-yjs-BtrvIr1x.js 143 kB 143 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-zod-gAWmQIF-.js 110 kB 110 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
Other — 7.1 MB (baseline 7.1 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/AnimationControls-bPyINTJI.js 4.61 kB 4.61 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ApiNodesSignInContent-SdEmJCMH.js 2.69 kB 2.69 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/AudioPreviewPlayer-CCaWnOVy.js 10.9 kB 10.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/auto-DjoqfnTX.js 1.7 kB 1.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/BaseViewTemplate-BnXUotno.js 1.75 kB 1.75 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/cloudBadges-CWO9dEw-.js 1.37 kB 1.37 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CloudRunButtonWrapper-H5A44p3r.js 1.67 kB 1.67 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/cloudSessionCookie-m6dX4uAQ.js 3.07 kB 3.07 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/cloudSubscription-i7pEWEr0.js 1.32 kB 1.32 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/comfy-logo-single-DCVL1uOL.js 198 B 198 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ComfyOrgHeader-32ZIoIYN.js 909 B 909 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BTIhwSf_.js 15.9 kB 15.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BxiMWv9a.js 14.6 kB 14.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BYGUQRX1.js 15.3 kB 15.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CtxsvHdf.js 15.2 kB 15.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-D4xkLWYG.js 14.4 kB 14.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-D7Ez6YeH.js 17.9 kB 17.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DFfk2Km5.js 15.4 kB 15.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-Ds7u8tBA.js 16.7 kB 16.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DuYqNMWX.js 16.7 kB 16.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-ovF76AYH.js 16.2 kB 16.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-tMQq9SrH.js 15.4 kB 15.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/core-BM-D68wz.js 71.4 kB 71.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CreateWorkspaceDialogContent-snzMBivf.js 5.58 kB 5.58 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/CurrentUserPopoverWorkspace-DF9LGjXS.js 19.7 kB 19.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/DeleteWorkspaceDialogContent-_OkqUp95.js 4.28 kB 4.28 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/EditWorkspaceDialogContent-BKBEkZsx.js 5.38 kB 5.38 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/FormItem-BnAJeA_N.js 20.2 kB 20.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/GlobalToast-BeqkcP-w.js 2.34 kB 2.34 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/graphHasMissingNodes-CIUysw1W.js 761 B 761 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/groupNode-C8t7IizW.js 70.9 kB 70.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/i18n-0PstQIzB.js 480 kB 480 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/i18n-BHeCxExo.js 199 B 199 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ImportFailedNodeContent-VPjQzi79.js 2.48 kB 2.48 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ImportFailedNodeFooter-D_BxHHK1.js 1.88 kB 1.88 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ImportFailedNodeHeader-DUns4_x2.js 1.08 kB 1.08 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/InviteMemberDialogContent-Dh_qcQkX.js 7.95 kB 7.95 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/LazyImage-Bir4uhOp.js 12.3 kB 12.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/LeaveWorkspaceDialogContent-BwYLn7bK.js 4.11 kB 4.11 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/load3d-a1oc6-Hh.js 14.8 kB 14.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Load3D-DHbJQGmW.js 16.2 kB 16.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Load3D-DRRU1QUy.js 1.04 kB 1.04 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Load3DConfiguration-D7iBFAe5.js 6.36 kB 6.36 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Load3DControls-BUbKM3pY.js 30.8 kB 30.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Load3dViewerContent-B-PGladc.js 961 B 961 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Load3dViewerContent-DrfrPW9b.js 23.2 kB 23.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-2HxSpwOp.js 133 kB 133 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-5vUvgJMx.js 155 kB 155 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B_En4SpT.js 148 kB 148 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BpnmNj1n.js 113 kB 113 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BuWOig7p.js 129 kB 129 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BYoy9XSQ.js 136 kB 136 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CKN_4E4Z.js 114 kB 114 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CN7pSufO.js 180 kB 180 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-dc7AuxCr.js 128 kB 128 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Dn8ME7jP.js 131 kB 131 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Dt6bQoC3.js 161 kB 161 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Media3DTop-DTYkrVtB.js 1.82 kB 1.82 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaAudioTop-AFmsiWi3.js 1.43 kB 1.43 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaImageTop-ATOoJCQr.js 1.75 kB 1.75 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MediaVideoTop-CQw3f2T6.js 2.23 kB 2.23 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MissingModelsWarning-BCIwifWU.js 16.1 kB 16.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MissingNodesContent-C7X5SzHK.js 6.14 kB 6.14 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MissingNodesFooter-INS5FJaH.js 4.8 kB 4.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/MissingNodesHeader-BOlbqJ0O.js 1.09 kB 1.09 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/mixpanel.module-Dq6XmUX_.js 92 B 92 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nightlyBadges-DmY3YJpU.js 1 kB 1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/NodeConflictDialogContent-pRvuOb4U.js 10.5 kB 10.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/NodeConflictFooter-Dh-VROp2.js 2.37 kB 2.37 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/NodeConflictHeader-DRxQs5TH.js 1.09 kB 1.09 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-_IXEWmm8.js 332 kB 332 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-4ZA9-QzB.js 361 kB 361 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BCF6YMp3.js 365 kB 365 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Bjx0mgI7.js 442 kB 442 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BS6wnxse.js 329 kB 329 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Ch6ZXz-h.js 375 kB 375 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-D18zvGhR.js 358 kB 358 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DDR1mCTO.js 405 kB 405 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DT6NpDBI.js 354 kB 354 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DyA4_B3a.js 361 kB 361 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-fPFi65f3.js 406 kB 406 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeTemplates-Dx8Vn6YL.js 9.33 kB 9.33 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/OBJLoader2WorkerModule-DTMpvldF.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/PanelTemplate-C1h0RxBM.js 1.2 kB 1.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Preview3d-BrC06JlD.js 4.82 kB 4.82 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/previousFullPath-DsBk66MD.js 665 B 665 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/RemoveMemberDialogContent-8Tq55Y_d.js 4.09 kB 4.09 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/RevokeInviteDialogContent-BGC99qW6.js 4 kB 4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/rolldown-runtime-Ca2S-reV.js 1.87 kB 1.87 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/saveMesh-BGVzMHF6.js 3.38 kB 3.38 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SelectValue-1KJOqzqF.js 8.94 kB 8.94 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SettingDialogContent-CDodO9RO.js 917 B 917 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SettingDialogContent-DEezyb5k.js 30.8 kB 30.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SettingDialogHeader-BHt-6Ao_.js 1.62 kB 1.62 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SettingDialogHeader-D5wathvf.js 244 B 244 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SignInContent-B35MPKl1.js 19 kB 19 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/signInSchema-DmfohtOF.js 1.53 kB 1.53 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/Slider-Bh_ZdHn9.js 3.52 kB 3.52 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/src-DAMctjF_.js 251 B 251 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SubscribeToRun-P00x3VuU.js 2.16 kB 2.16 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SubscriptionPanelContentWorkspace-Bh_La5tZ.js 15.8 kB 15.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SubscriptionPanelContentWorkspace-DMZ3tPiu.js 1.07 kB 1.07 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/SubscriptionRequiredDialogContent-DkD0XxhY.js 25.4 kB 25.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/TopUpCreditsDialogContent-pyD71Pkl.js 16.9 kB 16.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/types-VDank0gz.js 318 B 318 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/ValueControlPopover-BFj7wcD8.js 4.92 kB 4.92 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widget-RLUqfB5N.js 445 B 445 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-2w5BjjHm.js 3.94 kB 3.94 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetBoundingBox-Djm16aYN.js 131 B 131 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetChart-Dsp6bf_j.js 2.21 kB 2.21 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetColorPicker-jDbRm4n6.js 2.9 kB 2.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetGalleria-C8ikSQqn.js 3.61 kB 3.61 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCompare-B1RSu0_k.js 3.1 kB 3.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetImageCrop-fw5biYXq.js 22.3 kB 22.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetInputNumber-DwJ042Vx.js 392 B 392 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetInputNumber-tToPLxp8.js 15.8 kB 15.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetInputText-MXN3EUoN.js 1.85 kB 1.85 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetLayoutField-BcUSnWUK.js 1.95 kB 1.95 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetLegacy-t9yZZZku.js 747 B 747 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetMarkdown-wePHc2fh.js 2.88 kB 2.88 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-DyQHILEf.js 1.1 kB 1.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetRecordAudio-BMRt3gQd.js 17.2 kB 17.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetSelect-Dgd1FI-v.js 56.6 kB 56.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetTextarea-D07MktMK.js 3.14 kB 3.14 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetToggleSwitch-CoKD027B.js 2.5 kB 2.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetTypes-BCsKJASV.js 393 B 393 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/WidgetWithControl-_HbqmUtr.js 6.97 kB 6.97 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.github/workflows/ci-telemetry-tree-shaking.yaml:
- Around line 23-35: The script currently assumes dist/ exists which can cause
false passes; add an explicit existence check before the KEYWORDS loop (e.g.,
test for directory existence with [ -d dist ] or similar) and fail fast (echo a
clear error and exit non‑zero) if dist/ is missing or empty; update the block
around the KEYWORDS array and the for loop (referencing KEYWORDS and the grep -r
-i "$keyword" dist/ usage) so the script aborts immediately when dist/ is not
present.

@snomiao
Copy link
Member

snomiao commented Feb 6, 2026

Fixed in commit 0d1ebbac9:

  1. Added dist/ existence check: The script now validates that dist/ exists and is not empty before running keyword checks, preventing false passes if the build fails.

  2. Improved pattern matching: Updated to focus on GTM/GA code specifically rather than all telemetry. Mixpanel uses conditional dynamic imports and is expected to be present as a lazy-loaded chunk.

  3. Excluded false positives: Added exclusions for source maps, credit files, and uses more specific grep patterns to avoid matching unrelated code (e.g., 'gtag' matching 'toStringTag').

The check now passes on the current codebase, as GTM was properly removed in PR #8353.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.github/workflows/ci-telemetry-tree-shaking.yaml:
- Around line 47-53: The grep block is currently only matching single-quoted
gtag patterns (e.g. "gtag('config'"/"gtag('event'") and should accept either
single or double quotes; update the -e patterns used in the grep invocation that
reference "gtag('config'" and "gtag('event'" to a quote-agnostic BRE/ERE such as
matching gtag\( ['"]? config/event (i.e. allow either ' or " after the opening
parenthesis) and remove the now-unused --exclude='mixpanel.module-*.js' from the
grep command; target the existing grep invocation and the two gtag pattern
strings to implement this change.

@snomiao
Copy link
Member

snomiao commented Feb 6, 2026

✅ Addressed in commit 239e398

Updated the grep patterns to be quote-agnostic:

  • Changed gtag('config' to gtag(.config to match both single and double quotes
  • Changed gtag('event' to gtag(.event to match both single and double quotes
  • Removed unnecessary --exclude='mixpanel.module-*.js' since we're no longer searching for mixpanel patterns

The pattern gtag(.config uses BRE syntax where . matches any single character, so it will catch both gtag('config' and gtag("config") regardless of how the minifier normalizes quotes.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
src/locales/fa/nodeDefs.json (1)

6444-6461: ⚠️ Potential issue | 🔴 Critical

Fix schema inconsistency in FA locale Load3D entries.

The FA locale has three entries using empty-string keys ("": "..."):

  • "clear"
  • "upload 3d model"
  • "upload extra resources"

Other fields in the same Load3D node use "name" keys, and no other locale (EN, ES, ZH) uses empty-string keys anywhere. This schema mismatch will likely prevent proper label rendering in the UI. Change these entries to use "name" keys to match the rest of the structure:

"clear": {
  "name": "پاک‌سازی"
},
"upload 3d model": {
  "name": "بارگذاری مدل سه‌بعدی"
},
"upload extra resources": {
  "name": "بارگذاری منابع اضافی"
}
src/locales/ko/nodeDefs.json (1)

6435-6446: ⚠️ Potential issue | 🟡 Minor

Wrap string values as objects to maintain locale schema consistency.

Lines 6435, 6445-6446 use string values instead of the { "name": ... } object format used for other input labels in the same node and throughout the English reference. The English nodeDefs.json uses empty objects {} for these entries, while other entries like "model_file", "image", "width", and "height" consistently use { "name": "..." } format. These three entries should follow the same pattern:

🛠️ Suggested fix
-      "clear": "지우기",
+      "clear": { "name": "지우기" },
@@
-      "upload 3d model": "3D 모델 업로드",
-      "upload extra resources": "추가 리소스 업로드",
+      "upload 3d model": { "name": "3D 모델 업로드" },
+      "upload extra resources": { "name": "추가 리소스 업로드" },
src/locales/es/nodeDefs.json (1)

6435-6449: ⚠️ Potential issue | 🟡 Minor

Use the standard name field for Load3D labels.

Line 6435 and Lines 6445-6449 use {} / { "es": ... }, while other inputs in this file use { "name": ... }. If the UI reads only name, these labels may be ignored or fall back to English.

🛠️ Suggested alignment to the existing schema
-      "clear": {},
+      "clear": {
+        "name": "limpiar"
+      },
...
-      "upload 3d model": {
-        "es": "Subir modelo 3D"
-      },
+      "upload 3d model": {
+        "name": "Subir modelo 3D"
+      },
-      "upload extra resources": {
-        "es": "Subir recursos adicionales"
-      },
+      "upload extra resources": {
+        "name": "Subir recursos adicionales"
+      },
src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue (1)

240-240: ⚠️ Potential issue | 🟠 Major

Decrement/increment button clicks bypass clamping logic.

The @click handlers on lines 240 and 298 directly modify modelValue without clamping, unlike updateValueBy (line 152) and updateValue (line 70) which both clamp to [min, max]. If modelValue is within one stepValue of the boundary, these clicks will push the value past min/max.

Proposed fix: use updateValueBy for button clicks
-        `@click`="modelValue -= stepValue"
+        `@click`="updateValueBy(-stepValue)"
-        `@click`="modelValue += stepValue"
+        `@click`="updateValueBy(stepValue)"

Also applies to: 298-298

src/locales/ar/nodeDefs.json (1)

13957-13999: ⚠️ Potential issue | 🟡 Minor

Localize new parameter labels for Arabic UI (cfg_scale/top_k/top_p).
These name values remain raw keys while adjacent fields are translated, which will surface mixed-language labels in the UI.

🔧 Suggested localization tweak
       "cfg_scale": {
-        "name": "cfg_scale"
+        "name": "مقياس CFG"
       },
@@
       "top_k": {
-        "name": "top_k"
+        "name": "أعلى K"
       },
       "top_p": {
-        "name": "top_p"
+        "name": "أعلى P"
       }
🤖 Fix all issues with AI agents
In `@src/composables/graph/useGraphNodeManager.ts`:
- Line 173: The current cast of widget.options to IWidgetOptions<unknown[]>
hides a generic mismatch; update the code to preserve the options type by making
getSharedWidgetEnhancements generic (e.g. add a type parameter T extends
IWidgetOptions<unknown> and change the widget parameter to IBaseWidget<any, any,
T>) so SharedWidgetEnhancements receives the correct options type, or
alternatively change SharedWidgetEnhancements.options to IWidgetOptions<unknown>
to match the incoming widget.options; locate getSharedWidgetEnhancements,
SharedWidgetEnhancements, IWidgetOptions and IBaseWidget in the file and apply
one of these two fixes to remove the unsafe type assertion.

In `@src/platform/settings/settingStore.ts`:
- Around line 119-122: The get function uses a non-null assertion on
getDefaultValue(key) which can be undefined; update get (and references to
settingValues.value) to remove the `!` and explicitly handle the undefined path:
compute const val = settingValues.value[key] ?? getDefaultValue(key); if val is
undefined, either throw a clear error (or a dev-mode assertion) describing the
missing registered SettingParams/defaultValue for that key, otherwise return
_.cloneDeep(val) as Settings[K]; reference function get and getDefaultValue to
locate where to add the guard so callers never receive a lied-about non-null
value.

In
`@src/renderer/extensions/vueNodes/widgets/components/audio/AudioPreviewPlayer.vue`:
- Around line 208-220: The try/catch in handleDownload won't catch async errors
because downloadFile currently returns void and swallows errors inside
downloadViaBlobFetch; update the call chain so errors propagate: change
downloadFile (and/or where it calls downloadViaBlobFetch) to return a Promise
and rethrow or let the fetch error bubble up (remove the internal .catch that
only logs), then await downloadFile(modelValue.value) inside handleDownload so
the catch block can trigger toast.add on failure; reference downloadFile,
downloadViaBlobFetch, and handleDownload to locate the changes.
🧹 Nitpick comments (13)
src/platform/workflow/persistence/composables/useWorkflowPersistence.test.ts (1)

166-168: Consider using WorkflowDraftSnapshot here too for consistency.

Line 168 uses an inline type { data: string; isTemporary: boolean } which is a subset of WorkflowDraftSnapshot. Since you've already imported the type (line 7) and applied it on line 195, this cast could be unified as well.

♻️ Suggested change
     const drafts = JSON.parse(
       localStorage.getItem('Comfy.Workflow.Drafts') ?? '{}'
-    ) as Record<string, { data: string; isTemporary: boolean }>
+    ) as Record<string, WorkflowDraftSnapshot>
src/services/litegraphService.ts (1)

875-886: Pre-existing @ts-expect-error suppressions — not introduced by this change.

Lines 883 and 885 suppress type errors on graph.add(node) and return node. These are pre-existing and out of scope for this PR, but worth noting as future cleanup targets.

src/services/load3dService.ts (1)

167-175: Type assertion as ReturnType<T> is pragmatic but introduces a soundness gap.

The generic signature is a nice improvement for call-site ergonomics. Two observations:

  1. Mixed-caller scenario: Both getOrCreateViewer (async, line 153) and getOrCreateViewerSync share the same viewerInstances map. If the async version creates an instance first (typed as ReturnType<UseLoad3dViewerFn>), a subsequent getOrCreateViewerSync<T> call for the same node.id returns the existing instance cast to ReturnType<T>, which may not match the actual runtime type when T is a narrower subtype.

  2. Same node, different T: If two callers invoke getOrCreateViewerSync with different T for the same node, the second caller silently receives an instance created by the first, cast to the wrong type.

Neither is likely to bite in practice today, but consider documenting the invariant (one viewer factory per node) or using a runtime guard.

.github/workflows/ci-telemetry-tree-shaking.yaml (1)

13-21: Consider adding explicit permissions to the job.

The job only needs read access, but without an explicit permissions block it inherits the repository's default token permissions (which may be broader than needed).

🛡️ Suggested fix
 jobs:
   validate-tree-shaking:
     runs-on: ubuntu-latest
+    permissions:
+      contents: read
     steps:
       - uses: actions/checkout@v6
src/locales/fa/nodeDefs.json (1)

13976-14017: Optional: localize the new technical labels for consistency.
Most fields in this node are Persian; cfg_scale, temperature, top_k, top_p remain English. If full localization is desired, consider translating or adding Persian tooltips.

scripts/diff-i18n.ts (1)

78-78: console.warn for success/progress messages is unconventional.

Lines 78, 98, and 120 use console.warn for non-warning informational output ("Captured current locale files…", "Wrote diff to…", "Removed temp directory"). Typically console.warn signals a potential problem. If the intent is to write to stderr (to separate from stdout data), console.error or a dedicated logger is more conventional; otherwise console.log / console.info fits success messages better.

Also applies to: 98-98, 120-120

scripts/check-unused-i18n-keys.ts (1)

166-179: Downgrade from error to warning is intentional — verify this aligns with CI expectations.

Unused new i18n keys now produce console.warn output and exit with code 0 instead of 1. This means the pre-commit/CI check will no longer block on unused keys. If this script is used as a git hook or CI gate, confirm that a non-blocking warning is the desired behavior — otherwise genuinely unused keys could accumulate silently.

src/renderer/extensions/vueNodes/widgets/components/audio/AudioPreviewPlayer.test.ts (1)

8-12: Consider resetting mockToastAdd in a beforeEach hook for robustness.

Currently mockToastAdd is only reset in the error test (line 83). If tests are reordered or new tests are added that check toast calls, leaked state from prior tests could cause flaky failures.

♻️ Suggested improvement
+import { afterEach, describe, expect, it, vi } from 'vitest'
-import { describe, expect, it, vi } from 'vitest'

Add after the mock declarations:

afterEach(() => {
  mockToastAdd.mockReset()
})

And remove the inline vi.mocked(downloadFile).mockReset() on line 83 in favor of a centralized cleanup.

Also applies to: 68-84

src/renderer/extensions/vueNodes/widgets/components/WidgetInputText.test.ts (1)

14-24: Parameter type Partial<InputTextProps> doesn't match the cast target IWidgetOptions.

The options parameter is typed as Partial<InputTextProps> (PrimeVue) but cast to IWidgetOptions (litegraph). Since the widget actually consumes IWidgetOptions, consider aligning the parameter type to avoid a misleading API for future test authors.

Suggested fix
+import type { InputTextProps } from 'primevue/inputtext'
+
 const createMockWidget = (
     value: string = 'default',
-    options: Partial<InputTextProps> = {},
+    options: Partial<IWidgetOptions> = {},
     callback?: (value: string) => void
   ): SimplifiedWidget<string> => ({
     name: 'test_input',
     type: 'string',
     value,
     options: options as IWidgetOptions,
     callback
   })
src/composables/graph/useGraphNodeManager.ts (1)

432-435: Synchronous layout initialization replaces requestAnimationFrame — verify no downstream timing dependency.

Removing the rAF deferral for non-workflow-loading node additions is a sensible simplification that eliminates a race window (node could be deleted before the rAF callback fires). The existing guard on line 404 remains as a good defensive check.

Confirm that no other code relies on the one-frame delay for position/size to settle before layout creation.

src/renderer/extensions/vueNodes/widgets/components/WidgetInputNumberInput.vue (2)

70-73: Consider extracting effectiveMin/effectiveMax computed properties.

The pattern filteredProps.value.min ?? -Number.MAX_VALUE / filteredProps.value.max ?? Number.MAX_VALUE is duplicated in four places (updateValue, canDecrement/canIncrement, updateValueBy, handleMouseMove). Centralizing these as computed properties would eliminate duplication and guard against inconsistency.

Proposed refactor

Add near line 94:

+const effectiveMin = computed(() => filteredProps.value.min ?? -Number.MAX_VALUE)
+const effectiveMax = computed(() => filteredProps.value.max ?? Number.MAX_VALUE)

Then replace all occurrences, e.g.:

-  const max = filteredProps.value.max ?? Number.MAX_VALUE
-  const min = filteredProps.value.min ?? -Number.MAX_VALUE
-  modelValue.value = Math.min(max, Math.max(min, parsed))
+  modelValue.value = Math.min(effectiveMax.value, Math.max(effectiveMin.value, parsed))

Also applies to: 96-103, 153-155, 175-177


194-199: Hardcoded English tooltip string should use i18n.

Line 196 returns a raw English string for the tooltip. This should be localized via vue-i18n.

Proposed fix

Add a key to src/locales/en/main.json, then:

+const { t } = useI18n()
+
 const buttonTooltip = computed(() => {
   if (buttonsDisabled.value) {
-    return 'Increment/decrement disabled: value exceeds JavaScript precision limit (±2^53)'
+    return t('widgetInputNumber.precisionLimitTooltip')
   }
   return null
 })

As per coding guidelines: "Use vue-i18n in Composition API for any string literals. Place new translation entries in src/locales/en/main.json"

apps/desktop-ui/src/views/InstallView.stories.ts (1)

250-251: Accessing optional electronAPI without null check.

ElectronWindow.electronAPI is typed as optional (electronAPI?: ElectronAPI), but these lines access it without optional chaining. This works at runtime because the decorator sets it first, but strict TypeScript may flag it. Not a new issue since the PR just changed the cast type — noting for awareness.

Also applies to: 269-270

: undefined,
label: widget.label,
options: widget.options
options: widget.options as IWidgetOptions
Copy link
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:

# Find the IBaseWidget interface definition and its options property
rg -n "interface IBaseWidget" --type=ts -A 20

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 2867


🏁 Script executed:

# Search for IWidgetOptions definition and its structure
rg -n "interface IWidgetOptions" --type=ts -A 10

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 1893


🏁 Script executed:

# Check the actual context of line 173 in useGraphNodeManager.ts
sed -n '165,180p' src/composables/graph/useGraphNodeManager.ts | cat -n

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 673


🏁 Script executed:

# Get the function signature containing line 173
sed -n '150,175p' src/composables/graph/useGraphNodeManager.ts | cat -n

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 1127


🏁 Script executed:

# Check imports in the file to see which IWidgetOptions is being used
head -50 src/composables/graph/useGraphNodeManager.ts | cat -n

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 2114


🏁 Script executed:

# Find the SharedWidgetEnhancements interface definition
rg -n "interface SharedWidgetEnhancements" --type=ts -A 15

Repository: Comfy-Org/ComfyUI_frontend

Length of output: 1389


Type assertion reveals generic type parameter mismatch — consider preserving type information.

The cast from widget.options (typed as IWidgetOptions<unknown>) to IWidgetOptions<unknown[]>) is necessary due to the function receiving an untyped IBaseWidget. Instead of asserting, either:

  1. Make the function generic to preserve the options type:

    export function getSharedWidgetEnhancements<T extends IWidgetOptions<unknown>>(
      node: LGraphNode,
      widget: IBaseWidget<any, any, T>
    ): SharedWidgetEnhancements
  2. Or update SharedWidgetEnhancements.options to IWidgetOptions<unknown> to match the parameter type.

This avoids the assertion while improving type safety downstream.

🤖 Prompt for AI Agents
In `@src/composables/graph/useGraphNodeManager.ts` at line 173, The current cast
of widget.options to IWidgetOptions<unknown[]> hides a generic mismatch; update
the code to preserve the options type by making getSharedWidgetEnhancements
generic (e.g. add a type parameter T extends IWidgetOptions<unknown> and change
the widget parameter to IBaseWidget<any, any, T>) so SharedWidgetEnhancements
receives the correct options type, or alternatively change
SharedWidgetEnhancements.options to IWidgetOptions<unknown> to match the
incoming widget.options; locate getSharedWidgetEnhancements,
SharedWidgetEnhancements, IWidgetOptions and IBaseWidget in the file and apply
one of these two fixes to remove the unsafe type assertion.

Comment on lines 119 to 122
function get<K extends keyof Settings>(key: K): Settings[K] {
// Clone the value when returning to prevent external mutations
return _.cloneDeep(settingValues.value[key] ?? getDefaultValue(key))
return _.cloneDeep(settingValues.value[key] ?? getDefaultValue(key)!)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Non-null assertion ! on getDefaultValue(key) masks a real undefined path.

If get is called for a key that has no stored value and whose SettingParams haven't been registered yet (or has no defaultValue), getDefaultValue(key) returns undefined. The ! silences TypeScript but the caller receives undefined typed as Settings[K].

This is unlikely to crash (lodash/es-toolkit cloneDeep(undefined)undefined), but it's a type-level lie that could mislead callers. Consider a defensive guard or at minimum a dev-mode assertion so the condition is observable:

Suggested defensive guard
   function get<K extends keyof Settings>(key: K): Settings[K] {
-    return _.cloneDeep(settingValues.value[key] ?? getDefaultValue(key)!)
+    const value = settingValues.value[key] ?? getDefaultValue(key)
+    if (value === undefined && import.meta.env.DEV) {
+      console.warn(`Setting "${key}" accessed before registration or without a default value.`)
+    }
+    return _.cloneDeep(value) as Settings[K]
   }
📝 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
function get<K extends keyof Settings>(key: K): Settings[K] {
// Clone the value when returning to prevent external mutations
return _.cloneDeep(settingValues.value[key] ?? getDefaultValue(key))
return _.cloneDeep(settingValues.value[key] ?? getDefaultValue(key)!)
}
function get<K extends keyof Settings>(key: K): Settings[K] {
// Clone the value when returning to prevent external mutations
const value = settingValues.value[key] ?? getDefaultValue(key)
if (value === undefined && import.meta.env.DEV) {
console.warn(`Setting "${key}" accessed before registration or without a default value.`)
}
return _.cloneDeep(value) as Settings[K]
}
🤖 Prompt for AI Agents
In `@src/platform/settings/settingStore.ts` around lines 119 - 122, The get
function uses a non-null assertion on getDefaultValue(key) which can be
undefined; update get (and references to settingValues.value) to remove the `!`
and explicitly handle the undefined path: compute const val =
settingValues.value[key] ?? getDefaultValue(key); if val is undefined, either
throw a clear error (or a dev-mode assertion) describing the missing registered
SettingParams/defaultValue for that key, otherwise return _.cloneDeep(val) as
Settings[K]; reference function get and getDefaultValue to locate where to add
the guard so callers never receive a lied-about non-null value.

Comment on lines 208 to 220
const handleDownload = () => {
if (!modelValue.value) return
try {
downloadFile(modelValue.value)
} catch {
toast.add({
severity: 'error',
summary: t('g.error'),
detail: t('g.failedToDownloadFile'),
life: 3000
})
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

downloadFile in cloud mode swallows async errors — toast won't fire on fetch failure.

downloadFile returns void and internally fires downloadViaBlobFetch with its own .catch() that only logs to console. If the blob fetch fails in cloud mode, this try/catch won't catch it, so the user sees no error toast. This is consistent with how downloadFile is used elsewhere (e.g., useMediaAssetActions.ts), but worth noting as a gap for the audio player UX.

🤖 Prompt for AI Agents
In
`@src/renderer/extensions/vueNodes/widgets/components/audio/AudioPreviewPlayer.vue`
around lines 208 - 220, The try/catch in handleDownload won't catch async errors
because downloadFile currently returns void and swallows errors inside
downloadViaBlobFetch; update the call chain so errors propagate: change
downloadFile (and/or where it calls downloadViaBlobFetch) to return a Promise
and rethrow or let the fetch error bubble up (remove the internal .catch that
only logs), then await downloadFile(modelValue.value) inside handleDownload so
the catch block can trigger toast.add on failure; reference downloadFile,
downloadViaBlobFetch, and handleDownload to locate the changes.

snomiao and others added 3 commits February 6, 2026 06:31
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add dist/ directory existence check before running validation
- Update grep patterns to focus on GTM/GA code (not Mixpanel)
- Exclude source maps and credit files from search
- Use more specific patterns to avoid false positives (e.g., 'toStringTag')
- Mixpanel uses conditional dynamic imports and is expected in dist

Addresses CodeRabbit review feedback.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Use regex pattern 'gtag(.config' to match both single and double quotes
- Remove unnecessary --exclude='mixpanel.module-*.js' since we're not searching for mixpanel
- Ensures validation catches GTM code regardless of minifier quote normalization

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@snomiao snomiao force-pushed the feature/add-ci-telemetry-tree-shaking-validation branch from 239e398 to 97a038f Compare February 6, 2026 06:31
@snomiao snomiao marked this pull request as ready for review February 6, 2026 08:44
@snomiao snomiao requested a review from a team as a code owner February 6, 2026 08:44
Copilot AI review requested due to automatic review settings February 6, 2026 08:44
@dosubot dosubot bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Feb 6, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a GitHub Actions workflow to prevent telemetry code (specifically Google Tag Manager and Google Analytics) from being accidentally shipped in OSS/localhost/desktop builds. The workflow was motivated by PR #8311 which added GTM but wasn't properly tree-shaken, requiring a revert in PR #8353.

Changes:

  • New CI workflow that builds the project and greps dist/ for telemetry keywords
  • Validates that GTM/GA code is absent from built files
  • Provides clear error messages with remediation instructions when violations are found

Comment on lines +47 to +50
if grep -r -i --exclude='*.map' --exclude='CREDIT.txt' \
-e 'googletagmanager' \
-e 'gtm\.js' \
-e 'analytics\.js' \
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

The grep patterns for detecting gtag and analytics code have issues with special character handling:

  1. Lines 51-52: The patterns gtag(.config and gtag(.event won't match correctly because the parenthesis is a special regex character. Without the -E flag for extended regex, grep -e uses basic regex where ( needs to be escaped as \( or the pattern should be simplified.

  2. Line 49-50: The escaped dots \. in patterns like gtm\.js and analytics\.js are unnecessary for basic grep (and may not work as intended without -E).

Consider one of these fixes:

  • Add -E flag for extended regex and use proper escaping (e.g., gtag\(\.config, gtag\(\.event)
  • Simplify patterns to avoid special characters (e.g., use gtag.config or just gtag for broader matching)
  • Use -F flag for fixed string matching if exact literal matches are intended

The current patterns may fail to detect GTM/GA code that should be caught.

Suggested change
if grep -r -i --exclude='*.map' --exclude='CREDIT.txt' \
-e 'googletagmanager' \
-e 'gtm\.js' \
-e 'analytics\.js' \
if grep -rFi --exclude='*.map' --exclude='CREDIT.txt' \
-e 'googletagmanager' \
-e 'gtm.js' \
-e 'analytics.js' \

Copilot uses AI. Check for mistakes.
- name: Setup frontend
uses: ./.github/actions/setup-frontend
- name: Build project
run: pnpm build
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

The workflow doesn't explicitly set the DISTRIBUTION environment variable during the build step. While the vite.config.mts defaults to 'localhost' when DISTRIBUTION is unset (which is correct for OSS builds), it's safer to be explicit to prevent future issues or changes to default behavior.

Consider adding an explicit environment variable:

- name: Build project
  run: pnpm build
  env:
    DISTRIBUTION: localhost

This makes the intent clear and ensures the test validates the correct build configuration.

Suggested change
run: pnpm build
run: pnpm build
env:
DISTRIBUTION: localhost

Copilot uses AI. Check for mistakes.
Comment on lines +44 to +59
# Check for Google Tag Manager / Google Analytics
echo "Checking for GTM/GA code..."
# Exclude source maps and credit files
if grep -r -i --exclude='*.map' --exclude='CREDIT.txt' \
-e 'googletagmanager' \
-e 'gtm\.js' \
-e 'analytics\.js' \
-e 'gtag(.config' \
-e 'gtag(.event' \
dist/; then
echo "❌ ERROR: Found GTM/GA code in dist files!"
echo "Google Tag Manager / Google Analytics must be properly tree-shaken from OSS builds."
FOUND_VIOLATIONS=1
else
echo "✓ No GTM/GA code found"
fi
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

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

The workflow only checks for GTM/GA telemetry code but doesn't verify that Mixpanel code is properly lazy-loaded as expected. While the comment on line 25 mentions Mixpanel is expected in dist as a lazy chunk, the workflow doesn't validate this expectation.

Consider adding a check to ensure Mixpanel appears only as a dynamic import and not as a top-level import. This could prevent regressions where Mixpanel might be accidentally bundled instead of lazy-loaded:

For example, check that 'mixpanel-browser' appears only in specific lazy-loaded chunk patterns and not in main bundles.

Copilot uses AI. Check for mistakes.
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Feb 6, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@src/main.ts`:
- Line 18: Remove the test telemetry import and its invocation from the
production entry point: delete the static import line "import {
initializeAnalytics } from './test-telemetry-violation'" and remove the calls to
initializeAnalytics() (the invocation around lines 97–98) so the telemetry
module is not bundled; ensure there are no other direct references to
initializeAnalytics in src/main.ts and, if needed in future, load telemetry via
a guarded dynamic import or behind an isCloud check instead.

In `@src/test-telemetry-violation.ts`:
- Line 6: The function type for the gtag property currently uses a disallowed
any array in its rest parameter; update the signature (the gtag: (command:
string, ...args: any[]) => void declaration) to use unknown[] instead of any[]
(i.e., ...args: unknown[]) and adjust any downstream usages or type assertions
of gtag to narrow/validate the unknown values where they are consumed.
- Around line 1-18: The file src/test-telemetry-violation.ts intentionally
injects GTM/GA telemetry (symbols: initializeAnalytics, gtagId, window.gtag
usage) and must not be merged; remove this file from the branch (or move it to a
non-merge experimental branch/CI-only test) and delete any references to
initializeAnalytics from entry points such as src/main.ts so the telemetry
strings ('googletagmanager.com/gtm.js', gtag('config', ...), gtag('event', ...))
no longer appear in src/ or the build artifacts; ensure CI is validated against
the branch before merging and confirm no remaining imports or references remain.

src/main.ts Outdated
import '@/lib/litegraph/public/css/litegraph.css'
import router from '@/router'
import { useBootstrapStore } from '@/stores/bootstrapStore'
import { initializeAnalytics } from './test-telemetry-violation'
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Remove test telemetry import and invocation from the production entry point.

The import on line 18 and the call on lines 97–98 inject GTM/GA telemetry code into every build. Since initializeAnalytics is statically imported (not behind a dynamic import() or any isCloud guard), the bundler will include the telemetry strings in dist/, causing the new CI workflow to fail on every subsequent push to main.

These lines must be removed before merge.

-import { initializeAnalytics } from './test-telemetry-violation'
-// TEST: Intentional violation to test CI
-initializeAnalytics()
-

Also applies to: 97-98

🤖 Prompt for AI Agents
In `@src/main.ts` at line 18, Remove the test telemetry import and its invocation
from the production entry point: delete the static import line "import {
initializeAnalytics } from './test-telemetry-violation'" and remove the calls to
initializeAnalytics() (the invocation around lines 97–98) so the telemetry
module is not bundled; ensure there are no other direct references to
initializeAnalytics in src/main.ts and, if needed in future, load telemetry via
a guarded dynamic import or behind an isCloud check instead.

Comment on lines 1 to 18
// TEST: This file intentionally violates telemetry tree-shaking
// It will be caught by the CI check

declare global {
interface Window {
gtag: (command: string, ...args: any[]) => void
}
}

export function initializeAnalytics() {
// This top-level import will NOT be tree-shaken
const gtagId = 'googletagmanager.com/gtm.js?id=GTM-TEST123'

window.gtag('config', 'GA-TEST123')
window.gtag('event', 'page_view')

console.warn('Analytics initialized:', gtagId)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

This test violation file must not be merged into the production codebase.

This file intentionally introduces GTM/GA telemetry patterns (googletagmanager.com, gtag('config', ...), gtag('event', ...)) into src/, which will end up in dist/ and cause the new CI telemetry tree-shaking workflow to permanently fail on main. The commit message confirms this is a test artifact: "add intentional telemetry violation to test CI check."

To validate the CI workflow, either:

  1. Run the workflow against this branch (without merging), confirm it fails, then remove this file and the src/main.ts references before merge.
  2. Move the test to a separate, non-merge branch or a dedicated CI test matrix step that expects failure.

Additionally, shipping this file violates the repository's telemetry policy: GTM must be cloud-only and must never appear in OSS/local/desktop builds. Based on learnings, Google Tag Manager must be cloud-only and cannot be enabled in localhost or desktop distributions.

🤖 Prompt for AI Agents
In `@src/test-telemetry-violation.ts` around lines 1 - 18, The file
src/test-telemetry-violation.ts intentionally injects GTM/GA telemetry (symbols:
initializeAnalytics, gtagId, window.gtag usage) and must not be merged; remove
this file from the branch (or move it to a non-merge experimental branch/CI-only
test) and delete any references to initializeAnalytics from entry points such as
src/main.ts so the telemetry strings ('googletagmanager.com/gtm.js',
gtag('config', ...), gtag('event', ...)) no longer appear in src/ or the build
artifacts; ensure CI is validated against the branch before merging and confirm
no remaining imports or references remain.


declare global {
interface Window {
gtag: (command: string, ...args: any[]) => void
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

any type violates coding guidelines.

The ...args: any[] parameter uses any, which is disallowed. If this file is kept for any reason, use unknown[] instead.

-    gtag: (command: string, ...args: any[]) => void
+    gtag: (command: string, ...args: unknown[]) => void

As per coding guidelines: "Never use any type; use proper TypeScript types."

📝 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
gtag: (command: string, ...args: any[]) => void
gtag: (command: string, ...args: unknown[]) => void
🤖 Prompt for AI Agents
In `@src/test-telemetry-violation.ts` at line 6, The function type for the gtag
property currently uses a disallowed any array in its rest parameter; update the
signature (the gtag: (command: string, ...args: any[]) => void declaration) to
use unknown[] instead of any[] (i.e., ...args: unknown[]) and adjust any
downstream usages or type assertions of gtag to narrow/validate the unknown
values where they are consumed.

@snomiao snomiao force-pushed the feature/add-ci-telemetry-tree-shaking-validation branch from eabf9a5 to 97a038f Compare February 6, 2026 14:18
@dosubot dosubot bot added size:M This PR changes 30-99 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Feb 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants