extension 3.8.16 → 3.9.0-canary.231.7b387a7

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
  }
@@ -958,18 +1117,23 @@ Cross-Browser Compatibility
958
1117
  if (external_node_fs_namespaceObject.existsSync(readyPath)) try {
959
1118
  const payload = JSON.parse(external_node_fs_namespaceObject.readFileSync(readyPath, 'utf8'));
960
1119
  const isLive = isProcessLikelyAlive(payload.pid);
1120
+ const isFresh = isFreshContractPayload(payload, options.timeoutMs);
961
1121
  if (payload.command !== options.command) {
962
1122
  await new Promise((resolve)=>setTimeout(resolve, 250));
963
1123
  continue;
964
1124
  }
965
1125
  if (!isLive) {
966
- if ('start' !== options.command || !isFreshContractPayload(payload, options.timeoutMs)) {
1126
+ if ('start' !== options.command || !isFresh) {
967
1127
  await new Promise((resolve)=>setTimeout(resolve, 250));
968
1128
  continue;
969
1129
  }
970
1130
  }
971
1131
  if ('ready' === payload.status) return payload;
972
1132
  if ('error' === payload.status) {
1133
+ if (!isLive && 'start' !== options.command) {
1134
+ await new Promise((resolve)=>setTimeout(resolve, 250));
1135
+ continue;
1136
+ }
973
1137
  const detail = payload.message || payload.errors?.[0] || 'unknown error';
974
1138
  throw new Error(String(detail));
975
1139
  }
@@ -1121,15 +1285,43 @@ Cross-Browser Compatibility
1121
1285
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
1122
1286
  }
1123
1287
  const cmdStart = Date.now();
1288
+ const list = vendors(browser);
1289
+ const isRemoteInput = 'string' == typeof pathOrRemoteUrl && /^https?:/i.test(pathOrRemoteUrl);
1290
+ const projectProfile = collectProjectProfile(!isRemoteInput && pathOrRemoteUrl ? pathOrRemoteUrl : process.cwd());
1291
+ const workflowProfile = collectWorkflowProfile({
1292
+ command: 'dev',
1293
+ isMultiBrowser: list.length > 1,
1294
+ isRemoteInput: isRemoteInput,
1295
+ isWaitMode: Boolean(devOptions.wait),
1296
+ isNoBrowserMode: '1' === process.env.EXTENSION_CLI_NO_BROWSER,
1297
+ usesMachineReadableOutput: 'json' === devOptions.waitFormat || 'json' === devOptions.logFormat || 'ndjson' === devOptions.logFormat || 'json' === devOptions.sourceFormat || 'ndjson' === devOptions.sourceFormat,
1298
+ sourceInspectionRequested: Boolean(devOptions.source || devOptions.watchSource),
1299
+ companionExtensionsProvided: Boolean(devOptions.extensions),
1300
+ packageManager: projectProfile?.package_manager,
1301
+ frameworkPrimary: projectProfile?.framework_primary,
1302
+ hasNextDependency: projectProfile?.has_next_dependency,
1303
+ hasTurboDependency: projectProfile?.has_turbo_dependency
1304
+ });
1305
+ telemetry.track('workflow_profile', {
1306
+ command: 'dev',
1307
+ ...workflowProfile
1308
+ });
1124
1309
  telemetry.track('cli_command_start', {
1125
1310
  command: 'dev',
1126
- vendors: vendors(browser),
1311
+ vendors: list,
1312
+ browser_count: list.length,
1313
+ is_multi_browser: list.length > 1,
1314
+ is_remote_input: isRemoteInput,
1315
+ is_wait_mode: Boolean(devOptions.wait),
1316
+ is_no_browser_mode: '1' === process.env.EXTENSION_CLI_NO_BROWSER,
1127
1317
  polyfill_used: devOptions.polyfill?.toString() !== 'false',
1318
+ source_inspection_requested: Boolean(devOptions.source || devOptions.watchSource),
1319
+ companion_extensions_provided: Boolean(devOptions.extensions),
1128
1320
  log_level: devOptions.logLevel || 'off',
1129
1321
  log_format: devOptions.logFormat || 'pretty',
1130
- custom_binary_used: Boolean(devOptions.chromiumBinary || devOptions.geckoBinary)
1322
+ custom_binary_used: Boolean(devOptions.chromiumBinary || devOptions.geckoBinary),
1323
+ ...workflowProfile
1131
1324
  });
1132
- const list = vendors(browser);
1133
1325
  validateVendorsOrExit(list, (invalid, supported)=>{
1134
1326
  console.error(unsupportedBrowserFlag(invalid, supported));
1135
1327
  });
@@ -1152,7 +1344,8 @@ Cross-Browser Compatibility
1152
1344
  command: 'dev',
1153
1345
  duration_ms: Date.now() - cmdStart,
1154
1346
  success: true,
1155
- exit_code: 0
1347
+ exit_code: 0,
1348
+ ...workflowProfile
1156
1349
  });
1157
1350
  return;
1158
1351
  }
@@ -1231,7 +1424,8 @@ Cross-Browser Compatibility
1231
1424
  command: 'dev',
1232
1425
  duration_ms: Date.now() - cmdStart,
1233
1426
  success: 0 === process.exitCode || null == process.exitCode,
1234
- exit_code: process.exitCode ?? 0
1427
+ exit_code: process.exitCode ?? 0,
1428
+ ...workflowProfile
1235
1429
  });
1236
1430
  });
1237
1431
  }
@@ -1248,12 +1442,38 @@ Cross-Browser Compatibility
1248
1442
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
1249
1443
  }
1250
1444
  const cmdStart = Date.now();
1445
+ const list = vendors(browser);
1446
+ const isRemoteInput = 'string' == typeof pathOrRemoteUrl && /^https?:/i.test(pathOrRemoteUrl);
1447
+ const projectProfile = collectProjectProfile(!isRemoteInput && pathOrRemoteUrl ? pathOrRemoteUrl : process.cwd());
1448
+ const workflowProfile = collectWorkflowProfile({
1449
+ command: 'start',
1450
+ isMultiBrowser: list.length > 1,
1451
+ isRemoteInput: isRemoteInput,
1452
+ isWaitMode: Boolean(startOptions.wait),
1453
+ isNoBrowserMode: '1' === process.env.EXTENSION_CLI_NO_BROWSER,
1454
+ usesMachineReadableOutput: 'json' === startOptions.waitFormat || 'json' === startOptions.logFormat || 'ndjson' === startOptions.logFormat,
1455
+ companionExtensionsProvided: Boolean(startOptions.extensions),
1456
+ packageManager: projectProfile?.package_manager,
1457
+ frameworkPrimary: projectProfile?.framework_primary,
1458
+ hasNextDependency: projectProfile?.has_next_dependency,
1459
+ hasTurboDependency: projectProfile?.has_turbo_dependency
1460
+ });
1461
+ telemetry.track('workflow_profile', {
1462
+ command: 'start',
1463
+ ...workflowProfile
1464
+ });
1251
1465
  telemetry.track('cli_command_start', {
1252
1466
  command: 'start',
1253
- vendors: vendors(browser),
1254
- polyfill_used: startOptions.polyfill?.toString() !== 'false'
1467
+ vendors: list,
1468
+ browser_count: list.length,
1469
+ is_multi_browser: list.length > 1,
1470
+ is_remote_input: isRemoteInput,
1471
+ is_wait_mode: Boolean(startOptions.wait),
1472
+ is_no_browser_mode: '1' === process.env.EXTENSION_CLI_NO_BROWSER,
1473
+ companion_extensions_provided: Boolean(startOptions.extensions),
1474
+ polyfill_used: startOptions.polyfill?.toString() !== 'false',
1475
+ ...workflowProfile
1255
1476
  });
1256
- const list = vendors(browser);
1257
1477
  validateVendorsOrExit(list, (invalid, supported)=>{
1258
1478
  console.error(unsupportedBrowserFlag(invalid, supported));
1259
1479
  });
@@ -1276,7 +1496,8 @@ Cross-Browser Compatibility
1276
1496
  command: 'start',
1277
1497
  duration_ms: Date.now() - cmdStart,
1278
1498
  success: true,
1279
- exit_code: 0
1499
+ exit_code: 0,
1500
+ ...workflowProfile
1280
1501
  });
1281
1502
  return;
1282
1503
  }
@@ -1351,7 +1572,8 @@ Cross-Browser Compatibility
1351
1572
  command: 'start',
1352
1573
  duration_ms: Date.now() - cmdStart,
1353
1574
  success: 0 === process.exitCode || null == process.exitCode,
1354
- exit_code: process.exitCode ?? 0
1575
+ exit_code: process.exitCode ?? 0,
1576
+ ...workflowProfile
1355
1577
  });
1356
1578
  });
1357
1579
  }
@@ -1368,11 +1590,35 @@ Cross-Browser Compatibility
1368
1590
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
1369
1591
  }
1370
1592
  const cmdStart = Date.now();
1593
+ const list = vendors(browser);
1594
+ const isRemoteInput = 'string' == typeof pathOrRemoteUrl && /^https?:/i.test(pathOrRemoteUrl);
1595
+ const projectProfile = collectProjectProfile(!isRemoteInput && pathOrRemoteUrl ? pathOrRemoteUrl : process.cwd());
1596
+ const workflowProfile = collectWorkflowProfile({
1597
+ command: 'preview',
1598
+ isMultiBrowser: list.length > 1,
1599
+ isRemoteInput: isRemoteInput,
1600
+ isNoBrowserMode: '1' === process.env.EXTENSION_CLI_NO_BROWSER,
1601
+ usesMachineReadableOutput: 'json' === previewOptions.logFormat || 'ndjson' === previewOptions.logFormat,
1602
+ companionExtensionsProvided: Boolean(previewOptions.extensions),
1603
+ packageManager: projectProfile?.package_manager,
1604
+ frameworkPrimary: projectProfile?.framework_primary,
1605
+ hasNextDependency: projectProfile?.has_next_dependency,
1606
+ hasTurboDependency: projectProfile?.has_turbo_dependency
1607
+ });
1608
+ telemetry.track('workflow_profile', {
1609
+ command: 'preview',
1610
+ ...workflowProfile
1611
+ });
1371
1612
  telemetry.track('cli_command_start', {
1372
1613
  command: 'preview',
1373
- vendors: vendors(browser)
1614
+ vendors: list,
1615
+ browser_count: list.length,
1616
+ is_multi_browser: list.length > 1,
1617
+ is_remote_input: isRemoteInput,
1618
+ is_no_browser_mode: '1' === process.env.EXTENSION_CLI_NO_BROWSER,
1619
+ companion_extensions_provided: Boolean(previewOptions.extensions),
1620
+ ...workflowProfile
1374
1621
  });
1375
- const list = vendors(browser);
1376
1622
  validateVendorsOrExit(list, (invalid, supported)=>{
1377
1623
  console.error(unsupportedBrowserFlag(invalid, supported));
1378
1624
  });
@@ -1450,7 +1696,8 @@ Cross-Browser Compatibility
1450
1696
  command: 'preview',
1451
1697
  duration_ms: Date.now() - cmdStart,
1452
1698
  success: 0 === process.exitCode || null == process.exitCode,
1453
- exit_code: process.exitCode ?? 0
1699
+ exit_code: process.exitCode ?? 0,
1700
+ ...workflowProfile
1454
1701
  });
1455
1702
  });
1456
1703
  }
@@ -1461,14 +1708,37 @@ Cross-Browser Compatibility
1461
1708
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
1462
1709
  }
1463
1710
  const cmdStart = Date.now();
1711
+ const list = vendors(browser);
1712
+ const isRemoteInput = 'string' == typeof pathOrRemoteUrl && /^https?:/i.test(pathOrRemoteUrl);
1713
+ const artifactKind = buildOptions.zipSource ? buildOptions.zip ? 'zip_and_source' : 'source_zip' : buildOptions.zip ? 'zip' : 'directory';
1714
+ const projectProfile = collectProjectProfile(!isRemoteInput && pathOrRemoteUrl ? pathOrRemoteUrl : process.cwd());
1715
+ const workflowProfile = collectWorkflowProfile({
1716
+ command: 'build',
1717
+ isMultiBrowser: list.length > 1,
1718
+ isRemoteInput: isRemoteInput,
1719
+ companionExtensionsProvided: Boolean(buildOptions.extensions),
1720
+ artifactKind,
1721
+ packageManager: projectProfile?.package_manager,
1722
+ frameworkPrimary: projectProfile?.framework_primary,
1723
+ hasNextDependency: projectProfile?.has_next_dependency,
1724
+ hasTurboDependency: projectProfile?.has_turbo_dependency
1725
+ });
1726
+ telemetry.track('workflow_profile', {
1727
+ command: 'build',
1728
+ ...workflowProfile
1729
+ });
1464
1730
  telemetry.track('cli_command_start', {
1465
1731
  command: 'build',
1466
- vendors: vendors(browser),
1732
+ vendors: list,
1733
+ browser_count: list.length,
1734
+ is_multi_browser: list.length > 1,
1735
+ is_remote_input: isRemoteInput,
1467
1736
  polyfill_used: buildOptions.polyfill || false,
1468
1737
  zip: buildOptions.zip || false,
1469
- zip_source: buildOptions.zipSource || false
1738
+ zip_source: buildOptions.zipSource || false,
1739
+ artifact_kind: artifactKind,
1740
+ ...workflowProfile
1470
1741
  });
1471
- const list = vendors(browser);
1472
1742
  validateVendorsOrExit(list, (invalid, supported)=>{
1473
1743
  console.error(unsupportedBrowserFlag(invalid, supported));
1474
1744
  });
@@ -1490,7 +1760,12 @@ Cross-Browser Compatibility
1490
1760
  extensions: parseExtensionsList(buildOptions.extensions)
1491
1761
  });
1492
1762
  telemetry.track('cli_build_summary', {
1493
- ...buildSummary
1763
+ ...buildSummary,
1764
+ browser_count: list.length,
1765
+ is_multi_browser: list.length > 1,
1766
+ is_remote_input: isRemoteInput,
1767
+ artifact_kind: artifactKind,
1768
+ ...workflowProfile
1494
1769
  });
1495
1770
  telemetry.track('cli_vendor_finish', {
1496
1771
  command: 'build',
@@ -1502,7 +1777,8 @@ Cross-Browser Compatibility
1502
1777
  command: 'build',
1503
1778
  duration_ms: Date.now() - cmdStart,
1504
1779
  success: 0 === process.exitCode || null == process.exitCode,
1505
- exit_code: process.exitCode ?? 0
1780
+ exit_code: process.exitCode ?? 0,
1781
+ ...workflowProfile
1506
1782
  });
1507
1783
  });
1508
1784
  }
@@ -1541,13 +1817,25 @@ Cross-Browser Compatibility
1541
1817
  const startedAt = Date.now();
1542
1818
  const selectedBrowser = options.browser || browserArg || 'chromium';
1543
1819
  const browserList = vendors(selectedBrowser);
1820
+ const workflowProfile = collectWorkflowProfile({
1821
+ command: 'install',
1822
+ isMultiBrowser: browserList.length > 1,
1823
+ whereMode: Boolean(options.where)
1824
+ });
1544
1825
  validateVendorsOrExit(browserList, (invalid, supported)=>{
1545
1826
  console.error(unsupportedBrowserFlag(invalid, supported));
1546
1827
  });
1828
+ telemetry.track('workflow_profile', {
1829
+ command: 'install',
1830
+ ...workflowProfile
1831
+ });
1547
1832
  telemetry.track('cli_command_start', {
1548
1833
  command: 'install',
1549
1834
  vendors: browserList,
1550
- where: Boolean(options.where)
1835
+ browser_count: browserList.length,
1836
+ is_multi_browser: browserList.length > 1,
1837
+ where: Boolean(options.where),
1838
+ ...workflowProfile
1551
1839
  });
1552
1840
  try {
1553
1841
  if (options.where) {
@@ -1564,14 +1852,16 @@ Cross-Browser Compatibility
1564
1852
  command: 'install',
1565
1853
  duration_ms: Date.now() - startedAt,
1566
1854
  success: true,
1567
- exit_code: 0
1855
+ exit_code: 0,
1856
+ ...workflowProfile
1568
1857
  });
1569
1858
  } catch (err) {
1570
1859
  telemetry.track('cli_command_finish', {
1571
1860
  command: 'install',
1572
1861
  duration_ms: Date.now() - startedAt,
1573
1862
  success: false,
1574
- exit_code: 1
1863
+ exit_code: 1,
1864
+ ...workflowProfile
1575
1865
  });
1576
1866
  throw err;
1577
1867
  }
@@ -1579,11 +1869,20 @@ Cross-Browser Compatibility
1579
1869
  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
1870
  const startedAt = Date.now();
1581
1871
  const target = browserArg || browser;
1872
+ const workflowProfile = collectWorkflowProfile({
1873
+ command: 'uninstall',
1874
+ whereMode: Boolean(where)
1875
+ });
1876
+ telemetry.track('workflow_profile', {
1877
+ command: 'uninstall',
1878
+ ...workflowProfile
1879
+ });
1582
1880
  telemetry.track('cli_command_start', {
1583
1881
  command: 'uninstall',
1584
1882
  browser: target,
1585
1883
  all: Boolean(all),
1586
- where: Boolean(where)
1884
+ where: Boolean(where),
1885
+ ...workflowProfile
1587
1886
  });
1588
1887
  try {
1589
1888
  if (where) {
@@ -1612,14 +1911,16 @@ Cross-Browser Compatibility
1612
1911
  command: 'uninstall',
1613
1912
  duration_ms: Date.now() - startedAt,
1614
1913
  success: true,
1615
- exit_code: 0
1914
+ exit_code: 0,
1915
+ ...workflowProfile
1616
1916
  });
1617
1917
  } catch (err) {
1618
1918
  telemetry.track('cli_command_finish', {
1619
1919
  command: 'uninstall',
1620
1920
  duration_ms: Date.now() - startedAt,
1621
1921
  success: false,
1622
- exit_code: 1
1922
+ exit_code: 1,
1923
+ ...workflowProfile
1623
1924
  });
1624
1925
  throw err;
1625
1926
  }
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-canary.231.7b387a7",
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-canary.231.7b387a7",
94
+ "extension-develop": "3.9.0-canary.231.7b387a7",
95
+ "extension-install": "3.9.0-canary.231.7b387a7",
96
96
  "commander": "^14.0.3",
97
97
  "pintor": "0.3.0",
98
98
  "semver": "^7.7.3",