extension 3.8.16 → 3.9.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ import type { ManifestSummary } from './manifest-summary';
2
+ export type PackageManagerName = 'pnpm' | 'yarn' | 'npm' | 'bun' | 'unknown';
3
+ export type FrameworkPrimary = 'react' | 'preact' | 'vue' | 'svelte' | 'solid' | 'angular' | 'unknown';
4
+ export type PermissionBucket = '0' | '1_3' | '4_10' | '11_plus';
5
+ export type ManifestSurface = 'background_only' | 'content_scripts' | 'action_popup' | 'devtools' | 'multi_surface' | 'other' | 'unknown';
6
+ export type ProjectProfile = {
7
+ package_manager: PackageManagerName;
8
+ framework_primary: FrameworkPrimary;
9
+ has_typescript: boolean;
10
+ is_monorepo: boolean;
11
+ has_next_dependency: boolean;
12
+ has_turbo_dependency: boolean;
13
+ manifest_surface: ManifestSurface;
14
+ permissions_bucket: PermissionBucket;
15
+ host_permissions_bucket: PermissionBucket;
16
+ };
17
+ export declare function collectProjectProfile(projectRoot: string, summary?: ManifestSummary | null): ProjectProfile | null;
@@ -1,2 +1,5 @@
1
1
  import { Telemetry } from './telemetry';
2
+ type KnownCommand = 'create' | 'dev' | 'start' | 'preview' | 'build' | 'install' | 'uninstall' | 'cleanup' | 'unknown';
2
3
  export declare const telemetry: Telemetry;
4
+ export declare function detectInvokedCommand(argv: string[]): KnownCommand;
5
+ export {};
@@ -0,0 +1,35 @@
1
+ import type { FrameworkPrimary, PackageManagerName } from './project-profile';
2
+ export type WorkflowCohort = 'local_only' | 'shipping' | 'automation_heavy';
3
+ type WorkflowProjectShape = {
4
+ packageManager?: PackageManagerName;
5
+ frameworkPrimary?: FrameworkPrimary;
6
+ hasNextDependency?: boolean;
7
+ hasTurboDependency?: boolean;
8
+ };
9
+ type WorkflowContext = {
10
+ command: 'create' | 'dev' | 'start' | 'preview' | 'build' | 'install' | 'uninstall';
11
+ isMultiBrowser?: boolean;
12
+ isRemoteInput?: boolean;
13
+ isWaitMode?: boolean;
14
+ isNoBrowserMode?: boolean;
15
+ usesMachineReadableOutput?: boolean;
16
+ sourceInspectionRequested?: boolean;
17
+ companionExtensionsProvided?: boolean;
18
+ artifactKind?: 'directory' | 'zip' | 'source_zip' | 'zip_and_source';
19
+ whereMode?: boolean;
20
+ } & WorkflowProjectShape;
21
+ type WorkflowReason = 'production_command' | 'multi_browser' | 'artifact_output' | 'companion_extensions' | 'headless_sync' | 'machine_readable_output' | 'source_inspection' | 'where_mode';
22
+ export type WorkflowProfile = {
23
+ workflow_cohort: WorkflowCohort;
24
+ has_shipping_intent: boolean;
25
+ has_automation_intent: boolean;
26
+ shipping_signal_count: number;
27
+ automation_signal_count: number;
28
+ primary_workflow_signal: WorkflowReason | 'none';
29
+ package_manager?: PackageManagerName;
30
+ framework_primary?: FrameworkPrimary;
31
+ has_next_dependency?: boolean;
32
+ has_turbo_dependency?: boolean;
33
+ };
34
+ export declare function collectWorkflowProfile(context: WorkflowContext): WorkflowProfile;
35
+ export {};
package/dist/cli.cjs CHANGED
@@ -111,6 +111,7 @@ Usage: extension [command] [options]
111
111
 
112
112
  Notes
113
113
  - All high-level commands offer their own \`--help\` with usage and flag lists.
114
+ - Telemetry is anonymous and privacy-safe by default; see ${code('TELEMETRY.md')} for the full contract.
114
115
 
115
116
  Example
116
117
  - ${code('extension create --help')} outputs information about the "create" command.
@@ -625,8 +626,8 @@ Cross-Browser Compatibility
625
626
  const DEFAULT_FLUSH_AT = Number(process.env.EXTENSION_TELEMETRY_FLUSH_AT || 10);
626
627
  const DEFAULT_FLUSH_INTERVAL = Number(process.env.EXTENSION_TELEMETRY_FLUSH_INTERVAL || 2000);
627
628
  const DEFAULT_TIMEOUT_MS = Number(process.env.EXTENSION_TELEMETRY_TIMEOUT_MS || 200);
628
- const DEFAULT_POSTHOG_KEY = 'phc_Np5x3Jg3h2V7kTFtNch2uz6QBaWDycQpIidzX5PetaN';
629
- const DEFAULT_POSTHOG_HOST = 'https://us.i.posthog.com';
629
+ const DEFAULT_POSTHOG_KEY = process.env.POSTHOG_KEY || 'phc_Np5x3Jg3h2V7kTFtNch2uz6QBaWDycQpIidzX5PetaN';
630
+ const DEFAULT_POSTHOG_HOST = process.env.POSTHOG_HOST || 'https://us.i.posthog.com';
630
631
  class Telemetry {
631
632
  track(event, props = {}) {
632
633
  if (this.disabled || !this.storage) return;
@@ -708,7 +709,7 @@ Cross-Browser Compatibility
708
709
  arch: process.arch,
709
710
  node: process.versions.node,
710
711
  is_ci: isCI(),
711
- schema_version: 1
712
+ schema_version: 2
712
713
  };
713
714
  this.apiKey = init.apiKey || DEFAULT_POSTHOG_KEY;
714
715
  this.host = init.host || DEFAULT_POSTHOG_HOST;
@@ -756,6 +757,110 @@ Cross-Browser Compatibility
756
757
  has_action_popup: hasActionPopup
757
758
  };
758
759
  }
760
+ function safeReadJson(filePath) {
761
+ try {
762
+ if (!external_node_fs_default().existsSync(filePath)) return null;
763
+ return JSON.parse(external_node_fs_default().readFileSync(filePath, 'utf8'));
764
+ } catch {
765
+ return null;
766
+ }
767
+ }
768
+ function findNearestPackageJson(startPath) {
769
+ let current = external_node_path_default().resolve(startPath);
770
+ for(let i = 0; i < 6; i += 1){
771
+ const candidate = external_node_path_default().join(current, 'package.json');
772
+ if (external_node_fs_default().existsSync(candidate)) return candidate;
773
+ const parent = external_node_path_default().dirname(current);
774
+ if (parent === current) break;
775
+ current = parent;
776
+ }
777
+ return null;
778
+ }
779
+ function getDependencies(pkg) {
780
+ return {
781
+ ...pkg.dependencies || {},
782
+ ...pkg.devDependencies || {},
783
+ ...pkg.peerDependencies || {}
784
+ };
785
+ }
786
+ function hasDependency(pkg, dependencyId) {
787
+ const deps = getDependencies(pkg);
788
+ return Boolean(deps[dependencyId]);
789
+ }
790
+ function detectPackageManager(projectRoot, pkg) {
791
+ const declared = String(pkg.packageManager || '').trim().toLowerCase();
792
+ if (declared.startsWith('pnpm@')) return 'pnpm';
793
+ if (declared.startsWith('yarn@')) return 'yarn';
794
+ if (declared.startsWith('npm@')) return 'npm';
795
+ if (declared.startsWith('bun@')) return 'bun';
796
+ if (external_node_fs_default().existsSync(external_node_path_default().join(projectRoot, 'pnpm-lock.yaml'))) return 'pnpm';
797
+ if (external_node_fs_default().existsSync(external_node_path_default().join(projectRoot, 'yarn.lock'))) return 'yarn';
798
+ if (external_node_fs_default().existsSync(external_node_path_default().join(projectRoot, 'package-lock.json'))) return 'npm';
799
+ if (external_node_fs_default().existsSync(external_node_path_default().join(projectRoot, 'bun.lockb'))) return 'bun';
800
+ if (external_node_fs_default().existsSync(external_node_path_default().join(projectRoot, 'bun.lock'))) return 'bun';
801
+ const userAgent = String(process.env.npm_config_user_agent || '').toLowerCase();
802
+ if (userAgent.includes('pnpm')) return 'pnpm';
803
+ if (userAgent.includes('yarn')) return 'yarn';
804
+ if (userAgent.includes('bun')) return 'bun';
805
+ if (userAgent.includes('npm')) return 'npm';
806
+ return 'unknown';
807
+ }
808
+ function detectFrameworkPrimary(pkg) {
809
+ if (hasDependency(pkg, 'preact')) return 'preact';
810
+ if (hasDependency(pkg, 'react')) return 'react';
811
+ if (hasDependency(pkg, 'vue')) return 'vue';
812
+ if (hasDependency(pkg, 'svelte')) return 'svelte';
813
+ if (hasDependency(pkg, 'solid-js')) return 'solid';
814
+ if (hasDependency(pkg, '@angular/core')) return 'angular';
815
+ return 'unknown';
816
+ }
817
+ function detectMonorepo(projectRoot, pkg) {
818
+ return Boolean(pkg.workspaces || external_node_fs_default().existsSync(external_node_path_default().join(projectRoot, 'pnpm-workspace.yaml')) || external_node_fs_default().existsSync(external_node_path_default().join(projectRoot, 'turbo.json')));
819
+ }
820
+ function toPermissionBucket(count) {
821
+ if (count <= 0) return '0';
822
+ if (count <= 3) return '1_3';
823
+ if (count <= 10) return '4_10';
824
+ return '11_plus';
825
+ }
826
+ function toManifestSurface(summary) {
827
+ if (!summary) return 'unknown';
828
+ const surfaces = [
829
+ summary.has_action_popup,
830
+ summary.has_devtools_page,
831
+ summary.content_scripts_count > 0,
832
+ 'none' !== summary.background_type
833
+ ].filter(Boolean).length;
834
+ if (surfaces > 1) return 'multi_surface';
835
+ if (summary.has_action_popup) return 'action_popup';
836
+ if (summary.has_devtools_page) return 'devtools';
837
+ if (summary.content_scripts_count > 0) return "content_scripts";
838
+ if ('none' !== summary.background_type) return 'background_only';
839
+ return 'other';
840
+ }
841
+ function collectProjectProfile(projectRoot, summary) {
842
+ const packageJsonPath = findNearestPackageJson(projectRoot);
843
+ const pkg = (packageJsonPath ? safeReadJson(packageJsonPath) : null) || {
844
+ dependencies: {},
845
+ devDependencies: {},
846
+ peerDependencies: {}
847
+ };
848
+ const resolvedRoot = packageJsonPath ? external_node_path_default().dirname(packageJsonPath) : projectRoot;
849
+ const hasPackageSignals = Boolean(packageJsonPath);
850
+ const hasManifestSignals = Boolean(summary);
851
+ if (!hasPackageSignals && !hasManifestSignals) return null;
852
+ return {
853
+ package_manager: detectPackageManager(resolvedRoot, pkg),
854
+ framework_primary: detectFrameworkPrimary(pkg),
855
+ has_typescript: hasDependency(pkg, "typescript") || external_node_fs_default().existsSync(external_node_path_default().join(resolvedRoot, 'tsconfig.json')),
856
+ is_monorepo: detectMonorepo(resolvedRoot, pkg),
857
+ has_next_dependency: hasDependency(pkg, 'next'),
858
+ has_turbo_dependency: hasDependency(pkg, 'turbo') || external_node_fs_default().existsSync(external_node_path_default().join(resolvedRoot, 'turbo.json')),
859
+ manifest_surface: toManifestSurface(summary),
860
+ permissions_bucket: toPermissionBucket(summary?.permissions_count || 0),
861
+ host_permissions_bucket: toPermissionBucket(summary?.host_permissions_count || 0)
862
+ };
863
+ }
759
864
  function isTelemetryDisabledFromArgs(argv) {
760
865
  return argv.includes('--no-telemetry');
761
866
  }
@@ -787,28 +892,37 @@ Cross-Browser Compatibility
787
892
  version: getCliPackageJson().version,
788
893
  disabled: telemetryDisabled
789
894
  });
790
- if (!telemetryDisabled) {
791
- const startedAt = Date.now();
792
- let shutdownTracked = false;
895
+ function detectInvokedCommand(argv) {
793
896
  const known = new Set([
794
897
  'create',
795
898
  'dev',
796
899
  'start',
797
900
  'preview',
798
901
  'build',
799
- 'cleanup'
902
+ 'install',
903
+ 'uninstall',
904
+ 'cleanup',
905
+ 'unknown'
800
906
  ]);
801
- const invoked = process.argv.slice(2).find((a)=>known.has(a)) || 'unknown';
907
+ return argv.slice(2).find((a)=>known.has(a)) || 'unknown';
908
+ }
909
+ if (!telemetryDisabled) {
910
+ const startedAt = Date.now();
911
+ let shutdownTracked = false;
912
+ const invoked = detectInvokedCommand(process.argv);
802
913
  telemetry_cli_telemetry.track('cli_boot', {
803
914
  command_guess: invoked
804
915
  });
805
916
  const manifestPath = findManifestJson(process.cwd());
806
- if (manifestPath) {
917
+ let manifestSummary = null;
918
+ if (manifestPath) try {
807
919
  const raw = external_fs_default().readFileSync(manifestPath, 'utf8');
808
920
  const json = JSON.parse(raw);
809
- const summary = summarizeManifest(json);
810
- telemetry_cli_telemetry.track('manifest_summary', summary);
811
- }
921
+ manifestSummary = summarizeManifest(json);
922
+ telemetry_cli_telemetry.track('manifest_summary', manifestSummary);
923
+ } catch {}
924
+ const projectProfile = collectProjectProfile(process.cwd(), manifestSummary);
925
+ if (projectProfile) telemetry_cli_telemetry.track('project_profile', projectProfile);
812
926
  process.on('beforeExit', async function() {
813
927
  if (shutdownTracked) return;
814
928
  shutdownTracked = true;
@@ -833,6 +947,37 @@ Cross-Browser Compatibility
833
947
  });
834
948
  }
835
949
  const external_module_namespaceObject = require("module");
950
+ function primaryReason(automationReasons, shippingReasons) {
951
+ if (automationReasons.length > 0) return automationReasons[0];
952
+ if (shippingReasons.length > 0) return shippingReasons[0];
953
+ return 'none';
954
+ }
955
+ function collectWorkflowProfile(context) {
956
+ const shippingReasons = [];
957
+ const automationReasons = [];
958
+ if ('build' === context.command || 'start' === context.command || 'preview' === context.command) shippingReasons.push('production_command');
959
+ if (context.isMultiBrowser) shippingReasons.push('multi_browser');
960
+ if ('zip' === context.artifactKind || 'source_zip' === context.artifactKind || 'zip_and_source' === context.artifactKind) shippingReasons.push('artifact_output');
961
+ if (context.companionExtensionsProvided) shippingReasons.push('companion_extensions');
962
+ if (context.isWaitMode || context.isNoBrowserMode) automationReasons.push('headless_sync');
963
+ if (context.usesMachineReadableOutput) automationReasons.push('machine_readable_output');
964
+ if (context.sourceInspectionRequested) automationReasons.push('source_inspection');
965
+ if (context.whereMode) automationReasons.push('where_mode');
966
+ const hasAutomationIntent = automationReasons.length > 0;
967
+ const hasShippingIntent = shippingReasons.length > 0;
968
+ return {
969
+ workflow_cohort: hasAutomationIntent ? 'automation_heavy' : hasShippingIntent ? 'shipping' : 'local_only',
970
+ has_shipping_intent: hasShippingIntent,
971
+ has_automation_intent: hasAutomationIntent,
972
+ shipping_signal_count: shippingReasons.length,
973
+ automation_signal_count: automationReasons.length,
974
+ primary_workflow_signal: primaryReason(automationReasons, shippingReasons),
975
+ package_manager: context.packageManager,
976
+ framework_primary: context.frameworkPrimary,
977
+ has_next_dependency: context.hasNextDependency,
978
+ has_turbo_dependency: context.hasTurboDependency
979
+ };
980
+ }
836
981
  require("node:url");
837
982
  function parseOptionalBoolean(value) {
838
983
  if (void 0 === value) return true;
@@ -871,10 +1016,22 @@ Cross-Browser Compatibility
871
1016
  function registerCreateCommand(program, telemetry) {
872
1017
  program.command('create').arguments('<project-name|project-path>').usage('create <project-name|project-path> [options]').description(commandDescriptions.create).option('-t, --template <template-name>', 'specify a template for the created project').option('--install [boolean]', 'whether or not to install the dependencies after creating the project (enabled by default)', parseOptionalBoolean, true).action(async function(pathOrRemoteUrl, { template, install }) {
873
1018
  const startedAt = Date.now();
1019
+ const templateValue = String(template || 'default');
1020
+ const isRemoteTemplate = /^https?:/i.test(templateValue);
1021
+ const workflowProfile = collectWorkflowProfile({
1022
+ command: 'create',
1023
+ isRemoteInput: isRemoteTemplate
1024
+ });
1025
+ telemetry.track('workflow_profile', {
1026
+ command: 'create',
1027
+ ...workflowProfile
1028
+ });
874
1029
  telemetry.track('cli_command_start', {
875
1030
  command: 'create',
876
- template: template || 'default',
877
- install: Boolean(install)
1031
+ template: templateValue,
1032
+ template_source: isRemoteTemplate ? 'remote' : 'built_in',
1033
+ install: Boolean(install),
1034
+ ...workflowProfile
878
1035
  });
879
1036
  try {
880
1037
  if (!process.env.EXTENSION_CREATE_DEVELOP_ROOT) try {
@@ -896,14 +1053,16 @@ Cross-Browser Compatibility
896
1053
  command: 'create',
897
1054
  duration_ms: Date.now() - startedAt,
898
1055
  success: true,
899
- exit_code: 0
1056
+ exit_code: 0,
1057
+ ...workflowProfile
900
1058
  });
901
1059
  } catch (err) {
902
1060
  telemetry.track('cli_command_finish', {
903
1061
  command: 'create',
904
1062
  duration_ms: Date.now() - startedAt,
905
1063
  success: false,
906
- exit_code: 1
1064
+ exit_code: 1,
1065
+ ...workflowProfile
907
1066
  });
908
1067
  throw err;
909
1068
  }
@@ -1121,15 +1280,43 @@ Cross-Browser Compatibility
1121
1280
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
1122
1281
  }
1123
1282
  const cmdStart = Date.now();
1283
+ const list = vendors(browser);
1284
+ const isRemoteInput = 'string' == typeof pathOrRemoteUrl && /^https?:/i.test(pathOrRemoteUrl);
1285
+ const projectProfile = collectProjectProfile(!isRemoteInput && pathOrRemoteUrl ? pathOrRemoteUrl : process.cwd());
1286
+ const workflowProfile = collectWorkflowProfile({
1287
+ command: 'dev',
1288
+ isMultiBrowser: list.length > 1,
1289
+ isRemoteInput: isRemoteInput,
1290
+ isWaitMode: Boolean(devOptions.wait),
1291
+ isNoBrowserMode: '1' === process.env.EXTENSION_CLI_NO_BROWSER,
1292
+ usesMachineReadableOutput: 'json' === devOptions.waitFormat || 'json' === devOptions.logFormat || 'ndjson' === devOptions.logFormat || 'json' === devOptions.sourceFormat || 'ndjson' === devOptions.sourceFormat,
1293
+ sourceInspectionRequested: Boolean(devOptions.source || devOptions.watchSource),
1294
+ companionExtensionsProvided: Boolean(devOptions.extensions),
1295
+ packageManager: projectProfile?.package_manager,
1296
+ frameworkPrimary: projectProfile?.framework_primary,
1297
+ hasNextDependency: projectProfile?.has_next_dependency,
1298
+ hasTurboDependency: projectProfile?.has_turbo_dependency
1299
+ });
1300
+ telemetry.track('workflow_profile', {
1301
+ command: 'dev',
1302
+ ...workflowProfile
1303
+ });
1124
1304
  telemetry.track('cli_command_start', {
1125
1305
  command: 'dev',
1126
- vendors: vendors(browser),
1306
+ vendors: list,
1307
+ browser_count: list.length,
1308
+ is_multi_browser: list.length > 1,
1309
+ is_remote_input: isRemoteInput,
1310
+ is_wait_mode: Boolean(devOptions.wait),
1311
+ is_no_browser_mode: '1' === process.env.EXTENSION_CLI_NO_BROWSER,
1127
1312
  polyfill_used: devOptions.polyfill?.toString() !== 'false',
1313
+ source_inspection_requested: Boolean(devOptions.source || devOptions.watchSource),
1314
+ companion_extensions_provided: Boolean(devOptions.extensions),
1128
1315
  log_level: devOptions.logLevel || 'off',
1129
1316
  log_format: devOptions.logFormat || 'pretty',
1130
- custom_binary_used: Boolean(devOptions.chromiumBinary || devOptions.geckoBinary)
1317
+ custom_binary_used: Boolean(devOptions.chromiumBinary || devOptions.geckoBinary),
1318
+ ...workflowProfile
1131
1319
  });
1132
- const list = vendors(browser);
1133
1320
  validateVendorsOrExit(list, (invalid, supported)=>{
1134
1321
  console.error(unsupportedBrowserFlag(invalid, supported));
1135
1322
  });
@@ -1152,7 +1339,8 @@ Cross-Browser Compatibility
1152
1339
  command: 'dev',
1153
1340
  duration_ms: Date.now() - cmdStart,
1154
1341
  success: true,
1155
- exit_code: 0
1342
+ exit_code: 0,
1343
+ ...workflowProfile
1156
1344
  });
1157
1345
  return;
1158
1346
  }
@@ -1231,7 +1419,8 @@ Cross-Browser Compatibility
1231
1419
  command: 'dev',
1232
1420
  duration_ms: Date.now() - cmdStart,
1233
1421
  success: 0 === process.exitCode || null == process.exitCode,
1234
- exit_code: process.exitCode ?? 0
1422
+ exit_code: process.exitCode ?? 0,
1423
+ ...workflowProfile
1235
1424
  });
1236
1425
  });
1237
1426
  }
@@ -1248,12 +1437,38 @@ Cross-Browser Compatibility
1248
1437
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
1249
1438
  }
1250
1439
  const cmdStart = Date.now();
1440
+ const list = vendors(browser);
1441
+ const isRemoteInput = 'string' == typeof pathOrRemoteUrl && /^https?:/i.test(pathOrRemoteUrl);
1442
+ const projectProfile = collectProjectProfile(!isRemoteInput && pathOrRemoteUrl ? pathOrRemoteUrl : process.cwd());
1443
+ const workflowProfile = collectWorkflowProfile({
1444
+ command: 'start',
1445
+ isMultiBrowser: list.length > 1,
1446
+ isRemoteInput: isRemoteInput,
1447
+ isWaitMode: Boolean(startOptions.wait),
1448
+ isNoBrowserMode: '1' === process.env.EXTENSION_CLI_NO_BROWSER,
1449
+ usesMachineReadableOutput: 'json' === startOptions.waitFormat || 'json' === startOptions.logFormat || 'ndjson' === startOptions.logFormat,
1450
+ companionExtensionsProvided: Boolean(startOptions.extensions),
1451
+ packageManager: projectProfile?.package_manager,
1452
+ frameworkPrimary: projectProfile?.framework_primary,
1453
+ hasNextDependency: projectProfile?.has_next_dependency,
1454
+ hasTurboDependency: projectProfile?.has_turbo_dependency
1455
+ });
1456
+ telemetry.track('workflow_profile', {
1457
+ command: 'start',
1458
+ ...workflowProfile
1459
+ });
1251
1460
  telemetry.track('cli_command_start', {
1252
1461
  command: 'start',
1253
- vendors: vendors(browser),
1254
- polyfill_used: startOptions.polyfill?.toString() !== 'false'
1462
+ vendors: list,
1463
+ browser_count: list.length,
1464
+ is_multi_browser: list.length > 1,
1465
+ is_remote_input: isRemoteInput,
1466
+ is_wait_mode: Boolean(startOptions.wait),
1467
+ is_no_browser_mode: '1' === process.env.EXTENSION_CLI_NO_BROWSER,
1468
+ companion_extensions_provided: Boolean(startOptions.extensions),
1469
+ polyfill_used: startOptions.polyfill?.toString() !== 'false',
1470
+ ...workflowProfile
1255
1471
  });
1256
- const list = vendors(browser);
1257
1472
  validateVendorsOrExit(list, (invalid, supported)=>{
1258
1473
  console.error(unsupportedBrowserFlag(invalid, supported));
1259
1474
  });
@@ -1276,7 +1491,8 @@ Cross-Browser Compatibility
1276
1491
  command: 'start',
1277
1492
  duration_ms: Date.now() - cmdStart,
1278
1493
  success: true,
1279
- exit_code: 0
1494
+ exit_code: 0,
1495
+ ...workflowProfile
1280
1496
  });
1281
1497
  return;
1282
1498
  }
@@ -1351,7 +1567,8 @@ Cross-Browser Compatibility
1351
1567
  command: 'start',
1352
1568
  duration_ms: Date.now() - cmdStart,
1353
1569
  success: 0 === process.exitCode || null == process.exitCode,
1354
- exit_code: process.exitCode ?? 0
1570
+ exit_code: process.exitCode ?? 0,
1571
+ ...workflowProfile
1355
1572
  });
1356
1573
  });
1357
1574
  }
@@ -1368,11 +1585,35 @@ Cross-Browser Compatibility
1368
1585
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
1369
1586
  }
1370
1587
  const cmdStart = Date.now();
1588
+ const list = vendors(browser);
1589
+ const isRemoteInput = 'string' == typeof pathOrRemoteUrl && /^https?:/i.test(pathOrRemoteUrl);
1590
+ const projectProfile = collectProjectProfile(!isRemoteInput && pathOrRemoteUrl ? pathOrRemoteUrl : process.cwd());
1591
+ const workflowProfile = collectWorkflowProfile({
1592
+ command: 'preview',
1593
+ isMultiBrowser: list.length > 1,
1594
+ isRemoteInput: isRemoteInput,
1595
+ isNoBrowserMode: '1' === process.env.EXTENSION_CLI_NO_BROWSER,
1596
+ usesMachineReadableOutput: 'json' === previewOptions.logFormat || 'ndjson' === previewOptions.logFormat,
1597
+ companionExtensionsProvided: Boolean(previewOptions.extensions),
1598
+ packageManager: projectProfile?.package_manager,
1599
+ frameworkPrimary: projectProfile?.framework_primary,
1600
+ hasNextDependency: projectProfile?.has_next_dependency,
1601
+ hasTurboDependency: projectProfile?.has_turbo_dependency
1602
+ });
1603
+ telemetry.track('workflow_profile', {
1604
+ command: 'preview',
1605
+ ...workflowProfile
1606
+ });
1371
1607
  telemetry.track('cli_command_start', {
1372
1608
  command: 'preview',
1373
- vendors: vendors(browser)
1609
+ vendors: list,
1610
+ browser_count: list.length,
1611
+ is_multi_browser: list.length > 1,
1612
+ is_remote_input: isRemoteInput,
1613
+ is_no_browser_mode: '1' === process.env.EXTENSION_CLI_NO_BROWSER,
1614
+ companion_extensions_provided: Boolean(previewOptions.extensions),
1615
+ ...workflowProfile
1374
1616
  });
1375
- const list = vendors(browser);
1376
1617
  validateVendorsOrExit(list, (invalid, supported)=>{
1377
1618
  console.error(unsupportedBrowserFlag(invalid, supported));
1378
1619
  });
@@ -1450,7 +1691,8 @@ Cross-Browser Compatibility
1450
1691
  command: 'preview',
1451
1692
  duration_ms: Date.now() - cmdStart,
1452
1693
  success: 0 === process.exitCode || null == process.exitCode,
1453
- exit_code: process.exitCode ?? 0
1694
+ exit_code: process.exitCode ?? 0,
1695
+ ...workflowProfile
1454
1696
  });
1455
1697
  });
1456
1698
  }
@@ -1461,14 +1703,37 @@ Cross-Browser Compatibility
1461
1703
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
1462
1704
  }
1463
1705
  const cmdStart = Date.now();
1706
+ const list = vendors(browser);
1707
+ const isRemoteInput = 'string' == typeof pathOrRemoteUrl && /^https?:/i.test(pathOrRemoteUrl);
1708
+ const artifactKind = buildOptions.zipSource ? buildOptions.zip ? 'zip_and_source' : 'source_zip' : buildOptions.zip ? 'zip' : 'directory';
1709
+ const projectProfile = collectProjectProfile(!isRemoteInput && pathOrRemoteUrl ? pathOrRemoteUrl : process.cwd());
1710
+ const workflowProfile = collectWorkflowProfile({
1711
+ command: 'build',
1712
+ isMultiBrowser: list.length > 1,
1713
+ isRemoteInput: isRemoteInput,
1714
+ companionExtensionsProvided: Boolean(buildOptions.extensions),
1715
+ artifactKind,
1716
+ packageManager: projectProfile?.package_manager,
1717
+ frameworkPrimary: projectProfile?.framework_primary,
1718
+ hasNextDependency: projectProfile?.has_next_dependency,
1719
+ hasTurboDependency: projectProfile?.has_turbo_dependency
1720
+ });
1721
+ telemetry.track('workflow_profile', {
1722
+ command: 'build',
1723
+ ...workflowProfile
1724
+ });
1464
1725
  telemetry.track('cli_command_start', {
1465
1726
  command: 'build',
1466
- vendors: vendors(browser),
1727
+ vendors: list,
1728
+ browser_count: list.length,
1729
+ is_multi_browser: list.length > 1,
1730
+ is_remote_input: isRemoteInput,
1467
1731
  polyfill_used: buildOptions.polyfill || false,
1468
1732
  zip: buildOptions.zip || false,
1469
- zip_source: buildOptions.zipSource || false
1733
+ zip_source: buildOptions.zipSource || false,
1734
+ artifact_kind: artifactKind,
1735
+ ...workflowProfile
1470
1736
  });
1471
- const list = vendors(browser);
1472
1737
  validateVendorsOrExit(list, (invalid, supported)=>{
1473
1738
  console.error(unsupportedBrowserFlag(invalid, supported));
1474
1739
  });
@@ -1490,7 +1755,12 @@ Cross-Browser Compatibility
1490
1755
  extensions: parseExtensionsList(buildOptions.extensions)
1491
1756
  });
1492
1757
  telemetry.track('cli_build_summary', {
1493
- ...buildSummary
1758
+ ...buildSummary,
1759
+ browser_count: list.length,
1760
+ is_multi_browser: list.length > 1,
1761
+ is_remote_input: isRemoteInput,
1762
+ artifact_kind: artifactKind,
1763
+ ...workflowProfile
1494
1764
  });
1495
1765
  telemetry.track('cli_vendor_finish', {
1496
1766
  command: 'build',
@@ -1502,7 +1772,8 @@ Cross-Browser Compatibility
1502
1772
  command: 'build',
1503
1773
  duration_ms: Date.now() - cmdStart,
1504
1774
  success: 0 === process.exitCode || null == process.exitCode,
1505
- exit_code: process.exitCode ?? 0
1775
+ exit_code: process.exitCode ?? 0,
1776
+ ...workflowProfile
1506
1777
  });
1507
1778
  });
1508
1779
  }
@@ -1541,13 +1812,25 @@ Cross-Browser Compatibility
1541
1812
  const startedAt = Date.now();
1542
1813
  const selectedBrowser = options.browser || browserArg || 'chromium';
1543
1814
  const browserList = vendors(selectedBrowser);
1815
+ const workflowProfile = collectWorkflowProfile({
1816
+ command: 'install',
1817
+ isMultiBrowser: browserList.length > 1,
1818
+ whereMode: Boolean(options.where)
1819
+ });
1544
1820
  validateVendorsOrExit(browserList, (invalid, supported)=>{
1545
1821
  console.error(unsupportedBrowserFlag(invalid, supported));
1546
1822
  });
1823
+ telemetry.track('workflow_profile', {
1824
+ command: 'install',
1825
+ ...workflowProfile
1826
+ });
1547
1827
  telemetry.track('cli_command_start', {
1548
1828
  command: 'install',
1549
1829
  vendors: browserList,
1550
- where: Boolean(options.where)
1830
+ browser_count: browserList.length,
1831
+ is_multi_browser: browserList.length > 1,
1832
+ where: Boolean(options.where),
1833
+ ...workflowProfile
1551
1834
  });
1552
1835
  try {
1553
1836
  if (options.where) {
@@ -1564,14 +1847,16 @@ Cross-Browser Compatibility
1564
1847
  command: 'install',
1565
1848
  duration_ms: Date.now() - startedAt,
1566
1849
  success: true,
1567
- exit_code: 0
1850
+ exit_code: 0,
1851
+ ...workflowProfile
1568
1852
  });
1569
1853
  } catch (err) {
1570
1854
  telemetry.track('cli_command_finish', {
1571
1855
  command: 'install',
1572
1856
  duration_ms: Date.now() - startedAt,
1573
1857
  success: false,
1574
- exit_code: 1
1858
+ exit_code: 1,
1859
+ ...workflowProfile
1575
1860
  });
1576
1861
  throw err;
1577
1862
  }
@@ -1579,11 +1864,20 @@ Cross-Browser Compatibility
1579
1864
  program.command('uninstall').usage('uninstall <browser-name> | uninstall --all | uninstall --where').description(commandDescriptions.uninstall).option('--browser <browser-name>', 'browser to uninstall').option('--all', 'remove all managed browser binaries').option('--where', 'print the resolved managed browser cache root').argument('[browser-name]').action(async function(browserArg, { browser, all, where }) {
1580
1865
  const startedAt = Date.now();
1581
1866
  const target = browserArg || browser;
1867
+ const workflowProfile = collectWorkflowProfile({
1868
+ command: 'uninstall',
1869
+ whereMode: Boolean(where)
1870
+ });
1871
+ telemetry.track('workflow_profile', {
1872
+ command: 'uninstall',
1873
+ ...workflowProfile
1874
+ });
1582
1875
  telemetry.track('cli_command_start', {
1583
1876
  command: 'uninstall',
1584
1877
  browser: target,
1585
1878
  all: Boolean(all),
1586
- where: Boolean(where)
1879
+ where: Boolean(where),
1880
+ ...workflowProfile
1587
1881
  });
1588
1882
  try {
1589
1883
  if (where) {
@@ -1612,14 +1906,16 @@ Cross-Browser Compatibility
1612
1906
  command: 'uninstall',
1613
1907
  duration_ms: Date.now() - startedAt,
1614
1908
  success: true,
1615
- exit_code: 0
1909
+ exit_code: 0,
1910
+ ...workflowProfile
1616
1911
  });
1617
1912
  } catch (err) {
1618
1913
  telemetry.track('cli_command_finish', {
1619
1914
  command: 'uninstall',
1620
1915
  duration_ms: Date.now() - startedAt,
1621
1916
  success: false,
1622
- exit_code: 1
1917
+ exit_code: 1,
1918
+ ...workflowProfile
1623
1919
  });
1624
1920
  throw err;
1625
1921
  }
package/package.json CHANGED
@@ -33,7 +33,7 @@
33
33
  "extension": "./bin/extension.cjs"
34
34
  },
35
35
  "name": "extension",
36
- "version": "3.8.16",
36
+ "version": "3.9.0-next.0",
37
37
  "description": "Create cross-browser extensions with no build configuration.",
38
38
  "homepage": "https://extension.js.org/",
39
39
  "bugs": {
@@ -90,9 +90,9 @@
90
90
  "@types/chrome": "^0.1.33",
91
91
  "@types/node": "^25.2.0",
92
92
  "@types/webextension-polyfill": "0.12.4",
93
- "extension-create": "3.8.16",
94
- "extension-develop": "3.8.16",
95
- "extension-install": "3.8.16",
93
+ "extension-create": "3.9.0-next.0",
94
+ "extension-develop": "3.9.0-next.0",
95
+ "extension-install": "3.9.0-next.0",
96
96
  "commander": "^14.0.3",
97
97
  "pintor": "0.3.0",
98
98
  "semver": "^7.7.3",