extension 4.1.34 → 4.1.35

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.
package/dist/cli.cjs CHANGED
@@ -508,7 +508,8 @@ var __webpack_modules__ = {
508
508
  var _helpers_messaging__rspack_import_9 = __webpack_require__("./helpers/messaging.ts");
509
509
  var _run_firefox_firefox_launch_librewolf_overrides__rspack_import_10 = __webpack_require__("./browsers/run-firefox/firefox-launch/librewolf-overrides.ts");
510
510
  var _browser_family__rspack_import_11 = __webpack_require__("./browsers/browsers-lib/browser-family.ts");
511
- var _output_binaries_resolver__rspack_import_12 = __webpack_require__("./browsers/browsers-lib/output-binaries-resolver.ts");
511
+ var _official_chrome__rspack_import_12 = __webpack_require__("./browsers/browsers-lib/official-chrome.ts");
512
+ var _output_binaries_resolver__rspack_import_13 = __webpack_require__("./browsers/browsers-lib/output-binaries-resolver.ts");
512
513
  const require1 = (0, node_module__rspack_import_1.createRequire)(__rslib_import_meta_url__);
513
514
  function getLoggingPrefix(type) {
514
515
  return (0, _helpers_messaging__rspack_import_9.Pl)(type);
@@ -592,7 +593,7 @@ var __webpack_modules__ = {
592
593
  if (opts?.pinned) return '';
593
594
  const managedKey = 'chromium' === browser || 'chromium-based' === browser ? 'chromium' : 'chrome' === browser || 'edge' === browser || 'firefox' === browser ? browser : void 0;
594
595
  if (managedKey) try {
595
- const managed = (0, _output_binaries_resolver__rspack_import_12.kI)({}, managedKey);
596
+ const managed = (0, _output_binaries_resolver__rspack_import_13.kI)({}, managedKey);
596
597
  if (managed && node_fs__rspack_import_0.existsSync(managed)) {
597
598
  if ('chromium' === managedKey) return (0, chromium_location__rspack_import_5.getChromiumVersion)(managed) || 'Chromium';
598
599
  if ('chrome' === managedKey) return (0, chrome_location2__rspack_import_4.getChromeVersion)(managed) || 'Chrome';
@@ -603,22 +604,23 @@ var __webpack_modules__ = {
603
604
  try {
604
605
  if ('chromium' === browser || 'chromium-based' === browser) {
605
606
  const p = chromium_location__rspack_import_5_default()(true, {
606
- env: (0, _output_binaries_resolver__rspack_import_12.Gg)('chromium')
607
+ env: (0, _output_binaries_resolver__rspack_import_13.Gg)('chromium')
607
608
  });
608
609
  if (p && 'string' == typeof p && node_fs__rspack_import_0.existsSync(p)) return (0, chromium_location__rspack_import_5.getChromiumVersion)(p) || 'Chromium';
609
610
  } else if ('chrome' === browser) {
610
611
  const p = chrome_location2__rspack_import_4_default()(true, {
611
- env: (0, _output_binaries_resolver__rspack_import_12.Gg)('chrome')
612
+ env: (0, _output_binaries_resolver__rspack_import_13.Gg)('chrome')
612
613
  });
614
+ if (p && 'string' == typeof p && (0, _official_chrome__rspack_import_12.g)(p)) return '';
613
615
  if (p && 'string' == typeof p && node_fs__rspack_import_0.existsSync(p)) return (0, chrome_location2__rspack_import_4.getChromeVersion)(p) || 'Chrome';
614
616
  } else if ('edge' === browser) {
615
617
  const p = edge_location__rspack_import_6_default()(true, {
616
- env: (0, _output_binaries_resolver__rspack_import_12.Gg)('edge')
618
+ env: (0, _output_binaries_resolver__rspack_import_13.Gg)('edge')
617
619
  });
618
620
  if (p && 'string' == typeof p && node_fs__rspack_import_0.existsSync(p)) return (0, edge_location__rspack_import_6.getEdgeVersion)(p) || 'Microsoft Edge';
619
621
  } else if ('firefox' === browser) {
620
622
  const p = firefox_location2__rspack_import_7_default()(true, {
621
- env: (0, _output_binaries_resolver__rspack_import_12.Gg)('firefox')
623
+ env: (0, _output_binaries_resolver__rspack_import_13.Gg)('firefox')
622
624
  });
623
625
  if (p && 'string' == typeof p && node_fs__rspack_import_0.existsSync(p)) return (0, firefox_location2__rspack_import_7.getFirefoxVersion)(p) || 'Firefox';
624
626
  }
@@ -1340,6 +1342,24 @@ var __webpack_modules__ = {
1340
1342
  c: ()=>manifestDeclaresNewtabOverride
1341
1343
  });
1342
1344
  },
1345
+ "./browsers/browsers-lib/official-chrome.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1346
+ var _wsl_support__rspack_import_0 = __webpack_require__("./browsers/browsers-lib/wsl-support.ts");
1347
+ function looksOfficialChromeBinaryPath(bin) {
1348
+ const p = String(bin || '');
1349
+ if (!p) return false;
1350
+ if (/\/Applications\/Google Chrome(?: (?:Beta|Dev|Canary))?\.app\/Contents\/MacOS\/Google Chrome/i.test(p)) return true;
1351
+ if (/\\Google\\Chrome\\Application\\chrome\.exe$/i.test(p)) return true;
1352
+ if (/\/opt\/google\/chrome\//i.test(p)) return true;
1353
+ if (/\/google-chrome(?:-stable)?$/i.test(p)) return true;
1354
+ return false;
1355
+ }
1356
+ function isRefusedOfficialChrome(bin) {
1357
+ return looksOfficialChromeBinaryPath(bin) && !(0, _wsl_support__rspack_import_0.EV)();
1358
+ }
1359
+ __webpack_require__.d(__webpack_exports__, {
1360
+ g: ()=>isRefusedOfficialChrome
1361
+ });
1362
+ },
1343
1363
  "./browsers/browsers-lib/output-binaries-resolver.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1344
1364
  var node_fs__rspack_import_0 = __webpack_require__("node:fs");
1345
1365
  var node_path__rspack_import_1 = __webpack_require__("node:path");
@@ -1796,11 +1816,12 @@ var __webpack_modules__ = {
1796
1816
  var external_node_fs_ = __webpack_require__("node:fs");
1797
1817
  var external_node_path_ = __webpack_require__("node:path");
1798
1818
  var messaging = __webpack_require__("./helpers/messaging.ts");
1819
+ var rename_with_retry = __webpack_require__("./browsers/browsers-lib/rename-with-retry.ts");
1799
1820
  function writeJsonAtomic(filePath, value) {
1800
1821
  const tmpPath = `${filePath}.tmp-${process.pid}`;
1801
1822
  try {
1802
1823
  external_node_fs_.writeFileSync(tmpPath, JSON.stringify(value, null, 2), 'utf-8');
1803
- external_node_fs_.renameSync(tmpPath, filePath);
1824
+ (0, rename_with_retry.O)(tmpPath, filePath);
1804
1825
  return true;
1805
1826
  } catch {
1806
1827
  try {
@@ -1892,7 +1913,10 @@ var __webpack_modules__ = {
1892
1913
  if ('number' == typeof details?.browserPid && Number.isFinite(details.browserPid)) ready.browserPid = details.browserPid;
1893
1914
  if ('number' == typeof details?.launcherPid && Number.isFinite(details.launcherPid)) ready.launcherPid = details.launcherPid;
1894
1915
  const extensionId = String(details?.extensionId || '').trim();
1895
- if (extensionId) ready.extensionId = extensionId;
1916
+ if (extensionId && 'browser' !== ready.extensionIdSource) {
1917
+ ready.extensionId = extensionId;
1918
+ ready.extensionIdSource = 'derived';
1919
+ }
1896
1920
  const binary = String(details?.binary || '').trim();
1897
1921
  if (binary) ready.binary = binary;
1898
1922
  const provenance = String(details?.binaryProvenance || '').trim();
@@ -1954,8 +1978,9 @@ var __webpack_modules__ = {
1954
1978
  const readyPath = readyPathFor(extensionOutputPath);
1955
1979
  if (!external_node_fs_.existsSync(readyPath)) return;
1956
1980
  const ready = JSON.parse(external_node_fs_.readFileSync(readyPath, 'utf-8'));
1957
- if (ready.extensionId === id) return;
1981
+ if (ready.extensionId === id && 'browser' === ready.extensionIdSource) return;
1958
1982
  ready.extensionId = id;
1983
+ ready.extensionIdSource = 'browser';
1959
1984
  writeJsonAtomic(readyPath, ready);
1960
1985
  } catch {}
1961
1986
  }
@@ -2014,6 +2039,42 @@ var __webpack_modules__ = {
2014
2039
  } catch {}
2015
2040
  }
2016
2041
  },
2042
+ "./browsers/browsers-lib/rename-with-retry.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
2043
+ var node_fs__rspack_import_0 = __webpack_require__("node:fs");
2044
+ const RETRYABLE_RENAME_CODES = new Set([
2045
+ 'EPERM',
2046
+ 'EACCES',
2047
+ 'EBUSY'
2048
+ ]);
2049
+ const RENAME_RETRY_DELAYS_MS = [
2050
+ 10,
2051
+ 20,
2052
+ 40,
2053
+ 80,
2054
+ 160,
2055
+ 320
2056
+ ];
2057
+ function sleepSync(ms) {
2058
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
2059
+ }
2060
+ function renameSyncWithRetry(from, to, options = {}) {
2061
+ const platform = options.platform ?? process.platform;
2062
+ const rename = options.rename ?? node_fs__rspack_import_0.renameSync;
2063
+ const sleep = options.sleep ?? sleepSync;
2064
+ for(let attempt = 0;; attempt++)try {
2065
+ rename(from, to);
2066
+ return;
2067
+ } catch (error) {
2068
+ const code = error?.code;
2069
+ const delay = RENAME_RETRY_DELAYS_MS[attempt];
2070
+ if ('win32' !== platform || !code || !RETRYABLE_RENAME_CODES.has(code) || void 0 === delay) throw error;
2071
+ sleep(delay);
2072
+ }
2073
+ }
2074
+ __webpack_require__.d(__webpack_exports__, {
2075
+ O: ()=>renameSyncWithRetry
2076
+ });
2077
+ },
2017
2078
  "./browsers/browsers-lib/resolve-live-pid.ts" (__unused_rspack_module, __webpack_exports__, __webpack_require__) {
2018
2079
  var node_child_process__rspack_import_0 = __webpack_require__("node:child_process");
2019
2080
  var node_fs__rspack_import_1 = __webpack_require__("node:fs");
@@ -2467,22 +2528,33 @@ var __webpack_modules__ = {
2467
2528
  }
2468
2529
  function mergeChromiumFeatureSwitches(flags) {
2469
2530
  const merged = [];
2531
+ const prefixes = [
2532
+ '--enable-features=',
2533
+ '--disable-features='
2534
+ ];
2470
2535
  const featureValues = {
2471
2536
  '--enable-features=': [],
2472
2537
  '--disable-features=': []
2473
2538
  };
2539
+ const featureName = (value)=>value.split(/[<:]/)[0].trim();
2474
2540
  for (const flag of flags){
2475
- const prefix = Object.keys(featureValues).find((p)=>flag.startsWith(p));
2541
+ const prefix = prefixes.find((p)=>flag.startsWith(p));
2476
2542
  if (!prefix) {
2477
2543
  merged.push(flag);
2478
2544
  continue;
2479
2545
  }
2480
2546
  for (const value of flag.slice(prefix.length).split(',')){
2481
2547
  const trimmed = value.trim();
2482
- if (trimmed && !featureValues[prefix].includes(trimmed)) featureValues[prefix].push(trimmed);
2548
+ if (!trimmed) continue;
2549
+ const name = featureName(trimmed);
2550
+ for (const other of prefixes)featureValues[other] = featureValues[other].filter((existing)=>featureName(existing) !== name);
2551
+ featureValues[prefix].push(trimmed);
2483
2552
  }
2484
2553
  }
2485
- for (const [prefix, values] of Object.entries(featureValues))if (values.length) merged.push(`${prefix}${values.join(',')}`);
2554
+ for (const prefix of prefixes){
2555
+ const values = featureValues[prefix];
2556
+ if (values.length) merged.push(`${prefix}${values.join(',')}`);
2557
+ }
2486
2558
  return merged;
2487
2559
  }
2488
2560
  async function findAvailablePortNear(startPort, maxAttempts = 20, host = '127.0.0.1') {
@@ -3267,8 +3339,8 @@ var __webpack_modules__ = {
3267
3339
  var messaging = __webpack_require__("./helpers/messaging.ts");
3268
3340
  var banner = __webpack_require__("./browsers/browsers-lib/banner.ts");
3269
3341
  var browser_family = __webpack_require__("./browsers/browsers-lib/browser-family.ts");
3270
- const external_node_readline_namespaceObject = require("node:readline");
3271
- var external_node_readline_default = /*#__PURE__*/ __webpack_require__.n(external_node_readline_namespaceObject);
3342
+ var external_node_readline_ = __webpack_require__("node:readline");
3343
+ var external_node_readline_default = /*#__PURE__*/ __webpack_require__.n(external_node_readline_);
3272
3344
  var browser_install_outcome = __webpack_require__("./helpers/browser-install-outcome.ts");
3273
3345
  var messages = __webpack_require__("./browsers/browsers-lib/messages.ts");
3274
3346
  var output_binaries_resolver = __webpack_require__("./browsers/browsers-lib/output-binaries-resolver.ts");
@@ -3547,6 +3619,7 @@ var __webpack_modules__ = {
3547
3619
  return false;
3548
3620
  }
3549
3621
  }
3622
+ var official_chrome = __webpack_require__("./browsers/browsers-lib/official-chrome.ts");
3550
3623
  var pinned_binary = __webpack_require__("./browsers/browsers-lib/pinned-binary.ts");
3551
3624
  var process_teardown = __webpack_require__("./browsers/browsers-lib/process-teardown.ts");
3552
3625
  var ready_message = __webpack_require__("./browsers/browsers-lib/ready-message.ts");
@@ -4280,15 +4353,6 @@ var __webpack_modules__ = {
4280
4353
  }
4281
4354
  if (!binaryPinnedByFlag) browserBinaryLocation = preferRealChromeBinary(browserBinaryLocation);
4282
4355
  const getBrowserVersionLine = (bin)=>(0, version_probe.yO)(bin, String(browser || ''));
4283
- const looksOfficialChromeBinaryPath = (bin)=>{
4284
- const p = String(bin || '');
4285
- if (!p) return false;
4286
- if (/\/Applications\/Google Chrome(?: (?:Beta|Dev|Canary))?\.app\/Contents\/MacOS\/Google Chrome/i.test(p)) return true;
4287
- if (/\\Google\\Chrome\\Application\\chrome\.exe$/i.test(p)) return true;
4288
- if (/\/opt\/google\/chrome\//i.test(p)) return true;
4289
- if (/\/google-chrome(?:-stable)?$/i.test(p)) return true;
4290
- return false;
4291
- };
4292
4356
  const managedCacheRoot = output_binaries_resolver.LB(compilation);
4293
4357
  const managedEnvFor = (b)=>(0, locator_env.i)(process.env, output_binaries_resolver.$4(String(managedCacheRoot), b));
4294
4358
  const isAuthorMode = (0, messaging._o)();
@@ -4302,7 +4366,7 @@ var __webpack_modules__ = {
4302
4366
  if (!located) throw new Error(getInstallGuidanceText('chrome'));
4303
4367
  const normalized = normalizePath(located || null);
4304
4368
  if (isUsableBinary(normalized)) {
4305
- if (looksOfficialChromeBinaryPath(normalized) && !(0, wsl_support.EV)()) {
4369
+ if ((0, official_chrome.g)(normalized)) {
4306
4370
  printInstallGuidance(getInstallGuidanceText('chrome'), browser);
4307
4371
  return null;
4308
4372
  }
@@ -4316,7 +4380,7 @@ var __webpack_modules__ = {
4316
4380
  }) || null;
4317
4381
  const normalized = normalizePath(candidate || null);
4318
4382
  if (normalized) {
4319
- if (looksOfficialChromeBinaryPath(normalized) && !(0, wsl_support.EV)()) {
4383
+ if ((0, official_chrome.g)(normalized)) {
4320
4384
  printInstallGuidance(getInstallGuidanceText('chrome'), browser);
4321
4385
  candidate = null;
4322
4386
  }
@@ -5883,7 +5947,10 @@ var __webpack_modules__ = {
5883
5947
  await client.connect(port);
5884
5948
  this.client = client;
5885
5949
  this.invalidateConnectionScopedCaches();
5886
- client.on('reconnected', ()=>this.invalidateConnectionScopedCaches());
5950
+ client.on('reconnected', ()=>{
5951
+ this.invalidateConnectionScopedCaches();
5952
+ if (this.loggingAttached) attachConsoleListeners(client);
5953
+ });
5887
5954
  return client;
5888
5955
  } catch (error) {
5889
5956
  if (isErrorWithCode('ECONNREFUSED', error)) {
@@ -6836,6 +6903,7 @@ var __webpack_modules__ = {
6836
6903
  var node_fs__rspack_import_0 = __webpack_require__("node:fs");
6837
6904
  var node_path__rspack_import_1 = __webpack_require__("node:path");
6838
6905
  var _browsers_lib_output_binaries_resolver__rspack_import_2 = __webpack_require__("./browsers/browsers-lib/output-binaries-resolver.ts");
6906
+ var _browsers_lib_rename_with_retry__rspack_import_3 = __webpack_require__("./browsers/browsers-lib/rename-with-retry.ts");
6839
6907
  const MANAGED_GECKO_POLICIES = {
6840
6908
  DisableAppUpdate: true
6841
6909
  };
@@ -6916,7 +6984,9 @@ var __webpack_modules__ = {
6916
6984
  recursive: true
6917
6985
  });
6918
6986
  fs.writeFileSync(tempPath, `${JSON.stringify(next, null, 2)}\n`, 'utf8');
6919
- fs.renameSync(tempPath, policyPath);
6987
+ (0, _browsers_lib_rename_with_retry__rspack_import_3.O)(tempPath, policyPath, {
6988
+ rename: (from, to)=>fs.renameSync(from, to)
6989
+ });
6920
6990
  return {
6921
6991
  status: 'written',
6922
6992
  policyPath
@@ -10163,6 +10233,7 @@ function describeButton(b) {
10163
10233
  E_POLYFILL_NOT_FOUND: 'E_POLYFILL_NOT_FOUND',
10164
10234
  E_LOCALES_LAYOUT: 'E_LOCALES_LAYOUT',
10165
10235
  E_WAR_INVALID: 'E_WAR_INVALID',
10236
+ E_DEV_SESSION_DIST_SHARED: 'E_DEV_SESSION_DIST_SHARED',
10166
10237
  E_BACKGROUND_REQUIRED: 'E_BACKGROUND_REQUIRED',
10167
10238
  E_CONTENT_SCRIPT_SYNTAX: 'E_CONTENT_SCRIPT_SYNTAX',
10168
10239
  E_NO_ENTRYPOINTS: 'E_NO_ENTRYPOINTS',
@@ -10379,113 +10450,8 @@ function describeButton(b) {
10379
10450
  "./index.ts" (__unused_rspack_module, __unused_rspack___webpack_exports__, __webpack_require__) {
10380
10451
  var external_node_fs_ = __webpack_require__("node:fs");
10381
10452
  var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_);
10382
- const MIN_NODE_MAJOR = 22;
10383
- const MIN_NODE_MINOR = 12;
10384
- const MIN_DENO_MAJOR = 2;
10385
- const MIN_DENO_MINOR = 5;
10386
- const MIN_BUN_MAJOR = 1;
10387
- const MIN_BUN_MINOR = 2;
10388
- const BLOCKED_DENO_VERSIONS = [
10389
- '2.8.0'
10390
- ];
10391
- function meetsFloor(version, major, minor) {
10392
- const [actualMajor, actualMinor] = version.split('.').map((part)=>parseInt(part, 10));
10393
- if (!Number.isFinite(actualMajor)) return true;
10394
- if (actualMajor !== major) return actualMajor > major;
10395
- return (Number.isFinite(actualMinor) ? actualMinor : 0) >= minor;
10396
- }
10397
- function isSupportedNodeVersion(version) {
10398
- return meetsFloor(version, MIN_NODE_MAJOR, MIN_NODE_MINOR);
10399
- }
10400
- function isSupportedDenoVersion(version) {
10401
- if (BLOCKED_DENO_VERSIONS.includes(version)) return false;
10402
- return meetsFloor(version, MIN_DENO_MAJOR, MIN_DENO_MINOR);
10403
- }
10404
- function isSupportedBunVersion(version) {
10405
- return meetsFloor(version, MIN_BUN_MAJOR, MIN_BUN_MINOR);
10406
- }
10407
- function detectBunVersion(versions = process.versions) {
10408
- const bunVersion = versions.bun;
10409
- return 'string' == typeof bunVersion && bunVersion.length > 0 ? bunVersion : void 0;
10410
- }
10411
- function detectDenoVersion(versions = process.versions) {
10412
- const denoVersion = versions.deno;
10413
- return 'string' == typeof denoVersion && denoVersion.length > 0 ? denoVersion : void 0;
10414
- }
10415
- function unsupportedDenoVersionMessage(version) {
10416
- if (BLOCKED_DENO_VERSIONS.includes(version)) return `[Extension.js] Deno ${version} cannot load node:querystring inside the bundler, so every build fails on it. Deno fixed that in 2.8.1. Run deno upgrade to build the extension on Deno.`;
10417
- return `[Extension.js] Requires Deno >= ${MIN_DENO_MAJOR}.${MIN_DENO_MINOR} (you are on ${version}). Run deno upgrade, or run the extension CLI on Node.js >= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR} instead.`;
10418
- }
10419
- function unsupportedBunVersionMessage(version) {
10420
- return `[Extension.js] Requires Bun >= ${MIN_BUN_MAJOR}.${MIN_BUN_MINOR} (you are on ${version}). Run bun upgrade, or run the extension CLI on Node.js >= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR} instead.`;
10421
- }
10422
- function unsupportedNodeVersionMessage(version) {
10423
- return `[Extension.js] Requires Node.js >= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR} (you are on ${version}). Upgrade Node.js to run the extension CLI.`;
10424
- }
10425
- function wantsJsonOutput(argv) {
10426
- const inline = argv.find((arg)=>arg.startsWith('--output='));
10427
- const index = argv.indexOf('--output');
10428
- const spaced = index >= 0 ? argv[index + 1] : void 0;
10429
- const value = inline ? inline.slice(9) : spaced;
10430
- return 'json' === String(value || '').trim().toLowerCase();
10431
- }
10432
- function commandFromArgv(argv) {
10433
- for(let index = 2; index < argv.length; index += 1)if ('--output' === argv[index]) index += 1;
10434
- else if (!argv[index].startsWith('-')) return argv[index];
10435
- return 'extension';
10436
- }
10437
- function unsupportedNodeVersionFrame(version, argv) {
10438
- if (!wantsJsonOutput(argv)) return;
10439
- return {
10440
- schema: 1,
10441
- ok: false,
10442
- command: commandFromArgv(argv),
10443
- status: 'usage',
10444
- value: null,
10445
- error: {
10446
- code: 'E_NODE_VERSION',
10447
- message: unsupportedNodeVersionMessage(version).replace('[Extension.js] ', ''),
10448
- name: 'CliError'
10449
- },
10450
- warnings: []
10451
- };
10452
- }
10453
- function writeFrame(frame) {
10454
- try {
10455
- external_node_fs_default().writeSync(1, `${JSON.stringify(frame)}\n`);
10456
- } catch {
10457
- console.log(JSON.stringify(frame));
10458
- }
10459
- }
10460
- function enforceSupportedNodeVersion(version = process.versions.node, bunVersion = detectBunVersion(), denoVersion = detectDenoVersion(), argv = process.argv) {
10461
- if (denoVersion) {
10462
- if (isSupportedDenoVersion(denoVersion)) return;
10463
- console.error(unsupportedDenoVersionMessage(denoVersion));
10464
- process.exit(1);
10465
- return;
10466
- }
10467
- if (bunVersion) {
10468
- if (isSupportedBunVersion(bunVersion)) return;
10469
- console.error(unsupportedBunVersionMessage(bunVersion));
10470
- process.exit(1);
10471
- return;
10472
- }
10473
- if (isSupportedNodeVersion(version)) return;
10474
- console.error(unsupportedNodeVersionMessage(version));
10475
- const frame = unsupportedNodeVersionFrame(version, argv);
10476
- if (frame) writeFrame(frame);
10477
- process.exit(1);
10478
- }
10479
- enforceSupportedNodeVersion();
10480
- const external_commander_namespaceObject = require("commander");
10481
10453
  var external_node_path_ = __webpack_require__("node:path");
10482
10454
  var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_);
10483
- var browser_family = __webpack_require__("./browsers/browsers-lib/browser-family.ts");
10484
- var evaluate_extension_document = __webpack_require__("./browsers/run-firefox/rdp/evaluate-extension-document.ts");
10485
- var emulator_session = __webpack_require__("./helpers/emulator-session.ts");
10486
- var external_pintor_ = __webpack_require__("pintor");
10487
- var external_pintor_default = /*#__PURE__*/ __webpack_require__.n(external_pintor_);
10488
- var browser_install_outcome = __webpack_require__("./helpers/browser-install-outcome.ts");
10489
10455
  let cachedPackageJson = null;
10490
10456
  function getCliPackageJson() {
10491
10457
  if (cachedPackageJson) return cachedPackageJson;
@@ -10501,7 +10467,27 @@ function describeButton(b) {
10501
10467
  }
10502
10468
  throw new Error('Extension.js CLI package.json not found.');
10503
10469
  }
10504
- var messaging = __webpack_require__("./helpers/messaging.ts");
10470
+ const KNOWN_COMMANDS = new Set([
10471
+ 'build',
10472
+ 'capabilities',
10473
+ 'create',
10474
+ 'dev',
10475
+ 'doctor',
10476
+ 'eval',
10477
+ 'inspect',
10478
+ 'install',
10479
+ 'logs',
10480
+ 'navigate',
10481
+ 'open',
10482
+ 'preview',
10483
+ 'publish',
10484
+ 'reload',
10485
+ 'start',
10486
+ 'storage',
10487
+ 'telemetry',
10488
+ 'uninstall',
10489
+ 'unknown'
10490
+ ]);
10505
10491
  var external_node_child_process_ = __webpack_require__("node:child_process");
10506
10492
  var external_node_crypto_ = __webpack_require__("node:crypto");
10507
10493
  var external_node_crypto_default = /*#__PURE__*/ __webpack_require__.n(external_node_crypto_);
@@ -10523,6 +10509,31 @@ function describeButton(b) {
10523
10509
  if ('string' != typeof value) return;
10524
10510
  return CATALOG_CODE.test(value) ? value : void 0;
10525
10511
  }
10512
+ const BROWSER_INSTALL_OUTCOMES = new Set([
10513
+ 'offered',
10514
+ 'accepted',
10515
+ 'declined',
10516
+ 'failed'
10517
+ ]);
10518
+ const INSTALLABLE_BROWSERS = new Set([
10519
+ 'chrome',
10520
+ 'chromium',
10521
+ 'edge',
10522
+ 'firefox'
10523
+ ]);
10524
+ const DEPS_INSTALL_OUTCOMES = new Set([
10525
+ 'skipped',
10526
+ 'installed',
10527
+ 'failed'
10528
+ ]);
10529
+ const MAX_INSTALL_SECONDS = 86400;
10530
+ function fixedWord(value, allowed) {
10531
+ return 'string' == typeof value && allowed.has(value) ? value : void 0;
10532
+ }
10533
+ function wholeSeconds(value) {
10534
+ if ('number' != typeof value || !Number.isInteger(value)) return;
10535
+ return value >= 0 && value <= MAX_INSTALL_SECONDS ? value : void 0;
10536
+ }
10526
10537
  function smallExitCode(value) {
10527
10538
  if ('number' != typeof value || !Number.isInteger(value)) return;
10528
10539
  return value >= 0 && value <= 255 ? value : void 0;
@@ -10773,6 +10784,16 @@ function describeButton(b) {
10773
10784
  if (code) enforcedProps.code = code;
10774
10785
  const exitCode = smallExitCode(props.exit_code);
10775
10786
  if (void 0 !== exitCode) enforcedProps.exit_code = exitCode;
10787
+ const browserInstall = fixedWord(props.browser_install, BROWSER_INSTALL_OUTCOMES);
10788
+ if (browserInstall) enforcedProps.browser_install = browserInstall;
10789
+ const installBrowser = fixedWord(props.browser_install_browser, INSTALLABLE_BROWSERS);
10790
+ if (installBrowser) enforcedProps.browser_install_browser = installBrowser;
10791
+ const browserSeconds = wholeSeconds(props.browser_install_seconds);
10792
+ if (void 0 !== browserSeconds) enforcedProps.browser_install_seconds = browserSeconds;
10793
+ const depsInstall = fixedWord(props.deps_install, DEPS_INSTALL_OUTCOMES);
10794
+ if (depsInstall) enforcedProps.deps_install = depsInstall;
10795
+ const depsSeconds = wholeSeconds(props.deps_install_seconds);
10796
+ if (void 0 !== depsSeconds) enforcedProps.deps_install_seconds = depsSeconds;
10776
10797
  const payload = {
10777
10798
  event,
10778
10799
  properties: {
@@ -10929,8 +10950,223 @@ function describeButton(b) {
10929
10950
  if (!Number.isFinite(n)) return min;
10930
10951
  return Math.min(Math.max(n, min), max);
10931
10952
  }
10953
+ const MIN_NODE_MAJOR = 22;
10954
+ const MIN_NODE_MINOR = 12;
10955
+ const MIN_DENO_MAJOR = 2;
10956
+ const MIN_DENO_MINOR = 5;
10957
+ const MIN_BUN_MAJOR = 1;
10958
+ const MIN_BUN_MINOR = 2;
10959
+ const BLOCKED_DENO_VERSIONS = [
10960
+ '2.8.0'
10961
+ ];
10962
+ function meetsFloor(version, major, minor) {
10963
+ const [actualMajor, actualMinor] = version.split('.').map((part)=>parseInt(part, 10));
10964
+ if (!Number.isFinite(actualMajor)) return true;
10965
+ if (actualMajor !== major) return actualMajor > major;
10966
+ return (Number.isFinite(actualMinor) ? actualMinor : 0) >= minor;
10967
+ }
10968
+ function isSupportedNodeVersion(version) {
10969
+ return meetsFloor(version, MIN_NODE_MAJOR, MIN_NODE_MINOR);
10970
+ }
10971
+ function isSupportedDenoVersion(version) {
10972
+ if (BLOCKED_DENO_VERSIONS.includes(version)) return false;
10973
+ return meetsFloor(version, MIN_DENO_MAJOR, MIN_DENO_MINOR);
10974
+ }
10975
+ function isSupportedBunVersion(version) {
10976
+ return meetsFloor(version, MIN_BUN_MAJOR, MIN_BUN_MINOR);
10977
+ }
10978
+ function detectBunVersion(versions = process.versions) {
10979
+ const bunVersion = versions.bun;
10980
+ return 'string' == typeof bunVersion && bunVersion.length > 0 ? bunVersion : void 0;
10981
+ }
10982
+ function detectDenoVersion(versions = process.versions) {
10983
+ const denoVersion = versions.deno;
10984
+ return 'string' == typeof denoVersion && denoVersion.length > 0 ? denoVersion : void 0;
10985
+ }
10986
+ function unsupportedDenoVersionMessage(version) {
10987
+ if (BLOCKED_DENO_VERSIONS.includes(version)) return `[Extension.js] Deno ${version} cannot load node:querystring inside the bundler, so every build fails on it. Deno fixed that in 2.8.1. Run deno upgrade to build the extension on Deno.`;
10988
+ return `[Extension.js] Requires Deno >= ${MIN_DENO_MAJOR}.${MIN_DENO_MINOR} (you are on ${version}). Run deno upgrade, or run the extension CLI on Node.js >= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR} instead.`;
10989
+ }
10990
+ function unsupportedBunVersionMessage(version) {
10991
+ return `[Extension.js] Requires Bun >= ${MIN_BUN_MAJOR}.${MIN_BUN_MINOR} (you are on ${version}). Run bun upgrade, or run the extension CLI on Node.js >= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR} instead.`;
10992
+ }
10993
+ function unsupportedNodeVersionMessage(version) {
10994
+ return `[Extension.js] Requires Node.js >= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR} (you are on ${version}). Upgrade Node.js to run the extension CLI.`;
10995
+ }
10996
+ function wantsJsonOutput(argv) {
10997
+ const inline = argv.find((arg)=>arg.startsWith('--output='));
10998
+ const index = argv.indexOf('--output');
10999
+ const spaced = index >= 0 ? argv[index + 1] : void 0;
11000
+ const value = inline ? inline.slice(9) : spaced;
11001
+ return 'json' === String(value || '').trim().toLowerCase();
11002
+ }
11003
+ function commandFromArgv(argv) {
11004
+ for(let index = 2; index < argv.length; index += 1)if ('--output' === argv[index]) index += 1;
11005
+ else if (!argv[index].startsWith('-')) return argv[index];
11006
+ return 'extension';
11007
+ }
11008
+ function unsupportedNodeVersionFrame(version, argv) {
11009
+ if (!wantsJsonOutput(argv)) return;
11010
+ return {
11011
+ schema: 1,
11012
+ ok: false,
11013
+ command: commandFromArgv(argv),
11014
+ status: 'usage',
11015
+ value: null,
11016
+ error: {
11017
+ code: 'E_NODE_VERSION',
11018
+ message: unsupportedNodeVersionMessage(version).replace('[Extension.js] ', ''),
11019
+ name: 'CliError'
11020
+ },
11021
+ warnings: []
11022
+ };
11023
+ }
11024
+ const UNSUPPORTED_RUNTIME_FLUSH_MS = 1500;
11025
+ function reportUnsupportedRuntime(argv = process.argv) {
11026
+ try {
11027
+ const consent = resolveTelemetryConsent(argv);
11028
+ if (!consent.enabled || 'default' === consent.source) return;
11029
+ const verb = commandFromArgv(argv);
11030
+ const command = KNOWN_COMMANDS.has(verb) ? verb : 'unknown';
11031
+ const version = String(getCliPackageJson().version || '0.0.0');
11032
+ const telemetry = new Telemetry({
11033
+ app: 'extension',
11034
+ version
11035
+ });
11036
+ telemetry.track('command_failed', {
11037
+ command,
11038
+ success: false,
11039
+ version,
11040
+ code: 'E_NODE_VERSION',
11041
+ exit_code: 1
11042
+ });
11043
+ telemetry.flushSync(UNSUPPORTED_RUNTIME_FLUSH_MS);
11044
+ } catch {}
11045
+ }
11046
+ function writeFrame(frame) {
11047
+ try {
11048
+ external_node_fs_default().writeSync(1, `${JSON.stringify(frame)}\n`);
11049
+ } catch {
11050
+ console.log(JSON.stringify(frame));
11051
+ }
11052
+ }
11053
+ function enforceSupportedNodeVersion(version = process.versions.node, bunVersion = detectBunVersion(), denoVersion = detectDenoVersion(), argv = process.argv) {
11054
+ if (denoVersion) {
11055
+ if (isSupportedDenoVersion(denoVersion)) return;
11056
+ console.error(unsupportedDenoVersionMessage(denoVersion));
11057
+ reportUnsupportedRuntime(argv);
11058
+ process.exit(1);
11059
+ return;
11060
+ }
11061
+ if (bunVersion) {
11062
+ if (isSupportedBunVersion(bunVersion)) return;
11063
+ console.error(unsupportedBunVersionMessage(bunVersion));
11064
+ reportUnsupportedRuntime(argv);
11065
+ process.exit(1);
11066
+ return;
11067
+ }
11068
+ if (isSupportedNodeVersion(version)) return;
11069
+ console.error(unsupportedNodeVersionMessage(version));
11070
+ const frame = unsupportedNodeVersionFrame(version, argv);
11071
+ if (frame) writeFrame(frame);
11072
+ reportUnsupportedRuntime(argv);
11073
+ process.exit(1);
11074
+ }
11075
+ enforceSupportedNodeVersion();
11076
+ const external_commander_namespaceObject = require("commander");
11077
+ var browser_family = __webpack_require__("./browsers/browsers-lib/browser-family.ts");
11078
+ var evaluate_extension_document = __webpack_require__("./browsers/run-firefox/rdp/evaluate-extension-document.ts");
11079
+ var emulator_session = __webpack_require__("./helpers/emulator-session.ts");
11080
+ var external_pintor_ = __webpack_require__("pintor");
11081
+ var external_pintor_default = /*#__PURE__*/ __webpack_require__.n(external_pintor_);
11082
+ var browser_install_outcome = __webpack_require__("./helpers/browser-install-outcome.ts");
11083
+ function scanArgvValue(argv, flag) {
11084
+ const equalArg = argv.find((arg)=>arg.startsWith(`${flag}=`));
11085
+ if (equalArg) return equalArg.slice(flag.length + 1);
11086
+ const flagIndex = argv.indexOf(flag);
11087
+ if (flagIndex >= 0) return argv[flagIndex + 1] || '';
11088
+ }
11089
+ function collectValuedLongFlags(program) {
11090
+ const flags = new Set();
11091
+ const visit = (command)=>{
11092
+ for (const option of command.options)if (option.long && (option.required || option.optional)) flags.add(option.long);
11093
+ for (const sub of command.commands)visit(sub);
11094
+ };
11095
+ visit(program);
11096
+ return flags;
11097
+ }
11098
+ function resolveCommandIndex(argv, valuedFlags) {
11099
+ for(let i = 2; i < argv.length; i += 1){
11100
+ const arg = argv[i];
11101
+ if (arg.startsWith('-')) {
11102
+ if (valuedFlags.has(arg)) i += 1;
11103
+ continue;
11104
+ }
11105
+ return i;
11106
+ }
11107
+ return -1;
11108
+ }
11109
+ function resolveCommandFromArgv(argv, valuedFlags = new Set()) {
11110
+ const index = resolveCommandIndex(argv, valuedFlags);
11111
+ return index < 0 ? void 0 : argv[index];
11112
+ }
11113
+ function movePreCommandOutputArgv(argv, valuedFlags = new Set()) {
11114
+ const commandIndex = resolveCommandIndex(argv, valuedFlags);
11115
+ if (commandIndex < 0) return argv;
11116
+ const index = argv.findIndex((arg, i)=>i >= 2 && i < commandIndex && ('--output' === arg || arg.startsWith('--output=')));
11117
+ if (index < 0) return argv;
11118
+ const next = [
11119
+ ...argv
11120
+ ];
11121
+ const value = next[index + 1];
11122
+ const takesValue = '--output' === next[index] && void 0 !== value && !value.startsWith('-') && index + 1 < commandIndex;
11123
+ const tokens = next.splice(index, takesValue ? 2 : 1);
11124
+ next.splice(commandIndex - tokens.length + 1, 0, ...tokens);
11125
+ return next;
11126
+ }
11127
+ function rewriteOutputAliasArgv(argv, valuedFlags = new Set()) {
11128
+ const index = argv.findIndex((arg)=>'--format' === arg || arg.startsWith('--format='));
11129
+ if (index < 0) return {
11130
+ argv,
11131
+ rewritten: false
11132
+ };
11133
+ const next = [
11134
+ ...argv
11135
+ ];
11136
+ const tokens = [];
11137
+ if (next[index].startsWith('--format=')) {
11138
+ tokens.push(`--output=${next[index].slice(9)}`);
11139
+ next.splice(index, 1);
11140
+ } else {
11141
+ tokens.push('--output');
11142
+ const value = next[index + 1];
11143
+ next.splice(index, void 0 === value || value.startsWith('-') ? 1 : 2);
11144
+ if (void 0 !== value && !value.startsWith('-')) tokens.push(value);
11145
+ }
11146
+ const command = resolveCommandFromArgv(next, valuedFlags);
11147
+ const commandIndex = command ? next.indexOf(command, 2) : -1;
11148
+ if (commandIndex >= index) next.splice(commandIndex + 1, 0, ...tokens);
11149
+ else next.splice(index, 0, ...tokens);
11150
+ return {
11151
+ argv: next,
11152
+ rewritten: true
11153
+ };
11154
+ }
11155
+ let dependency_install_outcome_record = null;
11156
+ function recordDependencyInstall(outcome, seconds) {
11157
+ dependency_install_outcome_record = {
11158
+ outcome,
11159
+ ...'number' == typeof seconds && Number.isFinite(seconds) && seconds >= 0 ? {
11160
+ seconds: Math.round(seconds)
11161
+ } : {}
11162
+ };
11163
+ }
11164
+ function readDependencyInstall() {
11165
+ return dependency_install_outcome_record;
11166
+ }
11167
+ var messaging = __webpack_require__("./helpers/messaging.ts");
10932
11168
  const TEMPLATE_CORPUS_REPO = 'extension-js/examples';
10933
- const TEMPLATE_CORPUS_REF = '1f964a2d9fb820a1ec4730590caa357d8717744f';
11169
+ const TEMPLATE_CORPUS_REF = '4753cbd121dac8784f4cb5c515b773f87ebff3b4';
10934
11170
  const TEMPLATE_CORPUS_SLUGS = [
10935
11171
  'action',
10936
11172
  'action-locales',
@@ -11214,36 +11450,9 @@ function describeButton(b) {
11214
11450
  ''
11215
11451
  ].join('\n');
11216
11452
  }
11217
- const KNOWN_COMMANDS = new Set([
11218
- 'build',
11219
- 'capabilities',
11220
- 'create',
11221
- 'dev',
11222
- 'doctor',
11223
- 'eval',
11224
- 'inspect',
11225
- 'install',
11226
- 'logs',
11227
- 'navigate',
11228
- 'open',
11229
- 'preview',
11230
- 'publish',
11231
- 'reload',
11232
- 'start',
11233
- 'storage',
11234
- 'telemetry',
11235
- 'uninstall',
11236
- 'unknown'
11237
- ]);
11238
- function detectInvokedCommand(argv) {
11239
- for(let i = 2; i < argv.length; i += 1){
11240
- const arg = argv[i];
11241
- if (!(!arg || arg.startsWith('-'))) {
11242
- if (KNOWN_COMMANDS.has(arg)) return arg;
11243
- break;
11244
- }
11245
- }
11246
- return 'unknown';
11453
+ function detectInvokedCommand(argv, valuedFlags = new Set()) {
11454
+ const arg = resolveCommandFromArgv(argv, valuedFlags);
11455
+ return arg && KNOWN_COMMANDS.has(arg) ? arg : 'unknown';
11247
11456
  }
11248
11457
  function readArgValue(argv, names) {
11249
11458
  for(let i = 2; i < argv.length; i += 1){
@@ -11282,6 +11491,7 @@ function describeButton(b) {
11282
11491
  }
11283
11492
  } : {};
11284
11493
  if ('create' !== command) return installContext;
11494
+ const deps = readDependencyInstall();
11285
11495
  return {
11286
11496
  ...installContext,
11287
11497
  template: advertisedTemplateName(readArgValue(argv, [
@@ -11290,26 +11500,35 @@ function describeButton(b) {
11290
11500
  ])),
11291
11501
  source: createSourceTag(readArgValue(argv, [
11292
11502
  '--source'
11293
- ]))
11503
+ ])),
11504
+ ...deps ? {
11505
+ deps_install: deps.outcome
11506
+ } : {},
11507
+ ...deps?.seconds === void 0 ? {} : {
11508
+ deps_install_seconds: deps.seconds
11509
+ }
11294
11510
  };
11295
11511
  }
11296
- const consent = resolveTelemetryConsent(process.argv);
11297
- const invoked = detectInvokedCommand(process.argv);
11512
+ const telemetry_cli_consent = resolveTelemetryConsent(process.argv);
11513
+ let invoked = detectInvokedCommand(process.argv);
11298
11514
  const telemetry_cli_version = String(getCliPackageJson().version || '0.0.0');
11299
- const telemetry = new Telemetry({
11515
+ const telemetry_cli_telemetry = new Telemetry({
11300
11516
  app: 'extension',
11301
11517
  version: telemetry_cli_version,
11302
- disabled: !consent.enabled
11518
+ disabled: !telemetry_cli_consent.enabled
11303
11519
  });
11304
11520
  function getTelemetryConsent() {
11305
- return consent;
11521
+ return telemetry_cli_consent;
11306
11522
  }
11307
11523
  function invokedCommand() {
11308
11524
  return invoked;
11309
11525
  }
11526
+ function resolveInvokedCommand(argv, valuedFlags) {
11527
+ invoked = detectInvokedCommand(argv, valuedFlags);
11528
+ }
11310
11529
  function setTelemetryConsent(value) {
11311
11530
  const ok = writeConsent(value);
11312
- if ('disabled' === value) telemetry.disable();
11531
+ if ('disabled' === value) telemetry_cli_telemetry.disable();
11313
11532
  const storage = resolveTelemetryStorage();
11314
11533
  return {
11315
11534
  ok,
@@ -11327,14 +11546,14 @@ function describeButton(b) {
11327
11546
  function markCommandSessionStart(command = invoked) {
11328
11547
  if (tracked || sessionStarted) return;
11329
11548
  sessionStarted = true;
11330
- telemetry.track('command_executed', {
11549
+ telemetry_cli_telemetry.track('command_executed', {
11331
11550
  command,
11332
11551
  success: true,
11333
11552
  version: telemetry_cli_version,
11334
11553
  session: 'started',
11335
11554
  ...telemetryCommandContext(command)
11336
11555
  });
11337
- telemetry.flush();
11556
+ telemetry_cli_telemetry.flush();
11338
11557
  }
11339
11558
  function hasTrackedSessionStart() {
11340
11559
  return sessionStarted;
@@ -11342,7 +11561,7 @@ function describeButton(b) {
11342
11561
  function markCommandSuccess(command = invoked) {
11343
11562
  if (sessionStarted) return;
11344
11563
  if (!markTracked()) return;
11345
- telemetry.track('command_executed', {
11564
+ telemetry_cli_telemetry.track('command_executed', {
11346
11565
  command,
11347
11566
  success: true,
11348
11567
  version: telemetry_cli_version,
@@ -11362,7 +11581,7 @@ function describeButton(b) {
11362
11581
  if (!markTracked()) return;
11363
11582
  const code = telemetryFailureCode(details.code);
11364
11583
  const exitCode = telemetryExitCode(details.exitCode);
11365
- telemetry.track('command_failed', {
11584
+ telemetry_cli_telemetry.track('command_failed', {
11366
11585
  command,
11367
11586
  success: false,
11368
11587
  version: telemetry_cli_version,
@@ -11375,22 +11594,26 @@ function describeButton(b) {
11375
11594
  ...telemetryCommandContext(command)
11376
11595
  });
11377
11596
  }
11597
+ function reportCommandFailureNow(details = {}) {
11598
+ markCommandFailure(void 0, details);
11599
+ telemetry_cli_telemetry.flushSync(CRASH_FLUSH_TIMEOUT_MS);
11600
+ }
11378
11601
  function printOptOutNoticeIfFirstRun() {
11379
- if (!consent.enabled || 'default' !== consent.source) return;
11602
+ if (!telemetry_cli_consent.enabled || 'default' !== telemetry_cli_consent.source) return;
11380
11603
  if (!claimFirstRunNotice()) return;
11381
11604
  console.error(`${external_pintor_default().gray('⏵⏵⏵')} Extension.js collects anonymous, opt-out telemetry (two events: ${external_pintor_default().cyan('command_executed')} + ${external_pintor_default().cyan('command_failed')}). Disable with ${external_pintor_default().cyan('extension telemetry disable')}, ${external_pintor_default().cyan('EXTENSION_TELEMETRY=0')}, or ${external_pintor_default().cyan('--no-telemetry')}. See docs/TELEMETRY.md.`);
11382
11605
  }
11383
- if (consent.enabled) {
11606
+ if (telemetry_cli_consent.enabled) {
11384
11607
  printOptOutNoticeIfFirstRun();
11385
11608
  process.on('beforeExit', async ()=>{
11386
11609
  if (!tracked) if ((process.exitCode ?? 0) === 0) markCommandSuccess();
11387
11610
  else markCommandFailure();
11388
- await telemetry.flush();
11611
+ await telemetry_cli_telemetry.flush();
11389
11612
  });
11390
11613
  process.on('uncaughtExceptionMonitor', ()=>{
11391
11614
  markCommandFailure();
11392
- if (process.listenerCount('uncaughtException') > 0) return void telemetry.flush();
11393
- telemetry.flushSync(CRASH_FLUSH_TIMEOUT_MS);
11615
+ if (process.listenerCount('uncaughtException') > 0) return void telemetry_cli_telemetry.flush();
11616
+ telemetry_cli_telemetry.flushSync(CRASH_FLUSH_TIMEOUT_MS);
11394
11617
  });
11395
11618
  }
11396
11619
  const TELEMETRY_FLUSH_TIMEOUT_MS = 500;
@@ -11403,11 +11626,20 @@ function describeButton(b) {
11403
11626
  });
11404
11627
  } catch {}
11405
11628
  }
11629
+ function exitWithFailure(code, exitCode = 1) {
11630
+ try {
11631
+ reportCommandFailureNow({
11632
+ code,
11633
+ exitCode
11634
+ });
11635
+ } catch {}
11636
+ process.exit(exitCode);
11637
+ }
11406
11638
  async function exitAfterDrain(code) {
11407
11639
  markOutcomeForExit(code);
11408
11640
  try {
11409
11641
  await Promise.race([
11410
- telemetry.flush(),
11642
+ telemetry_cli_telemetry.flush(),
11411
11643
  new Promise((resolve)=>setTimeout(resolve, TELEMETRY_FLUSH_TIMEOUT_MS).unref?.())
11412
11644
  ]);
11413
11645
  } catch {}
@@ -11569,7 +11801,7 @@ function describeButton(b) {
11569
11801
  positionals: [
11570
11802
  {
11571
11803
  name: 'project-name|project-path',
11572
- required: true
11804
+ required: false
11573
11805
  }
11574
11806
  ],
11575
11807
  description: 'Create a new extension from a template (React, TypeScript, Vue, Svelte, etc.)',
@@ -11882,6 +12114,12 @@ function describeButton(b) {
11882
12114
  message
11883
12115
  };
11884
12116
  }
12117
+ function createNeedsProjectName(command) {
12118
+ return `${getLoggingPrefix('error')} A project name is required.\nRun ${messages_code(command)} to start one.`;
12119
+ }
12120
+ function createProjectNameQuestion(defaultName) {
12121
+ return `Project name ${messages_arg(`(${defaultName})`)}: `;
12122
+ }
11885
12123
  function programUserHelp() {
11886
12124
  return `\n${getLoggingPrefix('info')} ${external_pintor_default().underline('Help center for the Extension.js program')}
11887
12125
 
@@ -11922,6 +12160,7 @@ Build options
11922
12160
  - ${messages_code('--zip')} ${messages_arg('[boolean]')} Create ZIP archive of built extension
11923
12161
  - ${messages_code('--zip-source')} ${messages_arg('[boolean]')} Include source files in ZIP
11924
12162
  - ${messages_code('--zip-filename')} ${messages_arg('<name>')} Custom ZIP filename
12163
+ - ${messages_code('--out-dir')} ${messages_arg('<path>')} Write the build to <path>/<browser> instead of dist/<browser>
11925
12164
  - ${messages_code('--no-addon-lint')} Skip the addons.mozilla.org lint of Firefox builds (runs when addons-linter is installed)
11926
12165
  - ${messages_code('--no-minify')} Ship readable first-party code (the default for ${messages_code('--browser=opera')}, whose store rejects minified code)
11927
12166
 
@@ -12620,75 +12859,39 @@ Cross-browser compatibility
12620
12859
  function isLogEventLike(value) {
12621
12860
  return Boolean(value) && 'object' == typeof value && !Array.isArray(value);
12622
12861
  }
12623
- const LEVEL_ORDER = [
12862
+ const LEVEL_FILTERS = [
12863
+ 'off',
12624
12864
  'error',
12625
12865
  'warn',
12626
12866
  'info',
12627
12867
  'debug',
12628
- 'trace'
12629
- ];
12630
- const LEVEL_FILTERS = [
12631
- 'off',
12632
- ...LEVEL_ORDER,
12868
+ 'trace',
12633
12869
  'all'
12634
12870
  ];
12871
+ function logRuleFrom(bridge) {
12872
+ return bridge;
12873
+ }
12635
12874
  function knownContextsFrom(bridge) {
12636
12875
  const published = bridge?.LOG_CONTEXTS;
12637
12876
  return Array.isArray(published) ? published.map(String) : [
12638
12877
  ...LOG_CONTEXTS
12639
12878
  ];
12640
12879
  }
12641
- function levelRank(level) {
12642
- const l = 'log' === level ? 'info' : level;
12643
- const i = LEVEL_ORDER.indexOf(l);
12644
- return -1 === i ? LEVEL_ORDER.length : i;
12645
- }
12646
- function levelFilterFrom(value) {
12647
- const text = String(value || 'all').trim().toLowerCase();
12648
- const level = 'log' === text ? 'info' : text;
12649
- return LEVEL_FILTERS.includes(level) ? level : void 0;
12650
- }
12651
12880
  function contextNamesFrom(value) {
12652
12881
  return String(value || '').split(',').map((name)=>name.trim()).filter(Boolean);
12653
12882
  }
12654
- function contextFilterFrom(names) {
12655
- if (0 === names.length) return null;
12656
- if (names.some((name)=>'all' === name.toLowerCase())) return null;
12657
- return new Set(names);
12658
- }
12659
- function makeUrlMatcher(pattern) {
12660
- const hasGlob = pattern.includes('*');
12661
- let re = null;
12662
- if (hasGlob) {
12663
- const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
12664
- re = new RegExp(escaped);
12665
- }
12666
- return (event)=>{
12667
- const candidates = [
12668
- event.url,
12669
- event.hostname
12670
- ].filter((v)=>'string' == typeof v);
12671
- if (0 === candidates.length) return false;
12672
- return candidates.some((c)=>re ? re.test(c) : c.includes(pattern));
12883
+ function makeFilter(opts, since, tabId, helpers, rule) {
12884
+ const query = {
12885
+ context: opts.context,
12886
+ level: opts.level,
12887
+ signalsOnly: opts.signalsOnly,
12888
+ url: opts.url,
12889
+ tab: tabId
12673
12890
  };
12674
- }
12675
- function makeFilter(opts, since, tabId, helpers) {
12676
- const minLevel = levelFilterFrom(opts.level) ?? 'all';
12677
- const contexts = contextFilterFrom(contextNamesFrom(opts.context));
12678
- const urlMatches = opts.url ? makeUrlMatcher(opts.url) : null;
12679
12891
  return (event)=>{
12680
12892
  if (!event || 'object' != typeof event) return false;
12681
- if ('header' === event.type) return false;
12682
- if ('off' === minLevel) return false;
12683
- if (opts.signalsOnly && 'dx.signal' !== event.eventType) return false;
12684
- if (contexts && !contexts.has(String(event.context))) return false;
12685
- if ('all' !== minLevel) {
12686
- if (levelRank(String(event.level || '')) > levelRank(minLevel)) return false;
12687
- }
12688
12893
  if (since && !helpers.isAfterSince(event, since)) return false;
12689
- if (urlMatches && !urlMatches(event)) return false;
12690
- if (void 0 !== tabId && event.tabId !== tabId) return false;
12691
- return true;
12894
+ return rule.matchesLogQuery(event, query);
12692
12895
  };
12693
12896
  }
12694
12897
  function resolveFormat(opts) {
@@ -12739,6 +12942,7 @@ Cross-browser compatibility
12739
12942
  const browser = options.browser || 'chromium';
12740
12943
  const format = resolveFormat(options);
12741
12944
  const helpers = sinceHelpersFrom(bridge);
12945
+ const rule = logRuleFrom(bridge);
12742
12946
  const since = helpers.parseLogSince(options.since);
12743
12947
  const tab = parsePositiveInt('--tab', options.tab);
12744
12948
  if (!tab.ok) {
@@ -12748,13 +12952,13 @@ Cross-browser compatibility
12748
12952
  message: tab.message,
12749
12953
  name: 'CliError'
12750
12954
  }));
12751
- process.exit(1);
12955
+ exitWithFailure(messaging.Lp.E_FLAG_VALUE_INVALID);
12752
12956
  }
12753
12957
  if (null != options.since && '' !== options.since && void 0 === since) refuseUsage(format, `extension logs --since expects a sequence number or an ISO timestamp, got: ${options.since}`);
12754
12958
  const knownContexts = knownContextsFrom(bridge);
12755
12959
  const unknownContexts = contextNamesFrom(options.context).filter((name)=>'all' !== name.toLowerCase() && !knownContexts.includes(name));
12756
12960
  if (unknownContexts.length > 0) refuseUsage(format, `extension logs --context expects a comma-separated list of ${knownContexts.join(', ')} or all, got: ${unknownContexts.join(', ')}`);
12757
- if (void 0 === levelFilterFrom(options.level)) refuseUsage(format, `extension logs --level expects one of ${LEVEL_FILTERS.join(', ')}, got: ${options.level}`);
12961
+ if (void 0 === rule.parseLogLevelFilter(options.level)) refuseUsage(format, `extension logs --level expects one of ${rule.LOG_LEVEL_FILTERS.join(', ')}, got: ${options.level}`);
12758
12962
  const emulatorRefusal = (0, emulator_session.MC)(bridge, projectPath, browser, 'logs');
12759
12963
  if (emulatorRefusal) {
12760
12964
  console.error(emulatorRefusal);
@@ -12763,9 +12967,9 @@ Cross-browser compatibility
12763
12967
  message: emulatorRefusal,
12764
12968
  name: 'CliError'
12765
12969
  }));
12766
- process.exit(1);
12970
+ exitWithFailure(messaging.Lp.E_COMMAND_UNSUPPORTED_FOR_TARGET);
12767
12971
  }
12768
- const matches = makeFilter(options, since ?? null, tab.value, helpers);
12972
+ const matches = makeFilter(options, since ?? null, tab.value, helpers, rule);
12769
12973
  if (options.signalsOnly) console.error("extension logs --signals-only: no signals emitter ships in this build, so dev sessions record no dx.signal events and this filter will print nothing.");
12770
12974
  if (options.follow) return void await followLogs(projectPath, browser, format, matches);
12771
12975
  const file = sessionLogsPath(bridge, projectPath, browser);
@@ -12778,10 +12982,10 @@ Cross-browser compatibility
12778
12982
  message,
12779
12983
  name: 'CliError'
12780
12984
  }));
12781
- process.exit(1);
12985
+ exitWithFailure(messaging.Lp.E_LOGS_NOT_FOUND);
12782
12986
  }
12783
12987
  const lines = external_node_fs_default().readFileSync(file, 'utf-8').split('\n').filter(Boolean);
12784
- const noticeGaps = 'off' !== levelFilterFrom(options.level);
12988
+ const noticeGaps = 'off' !== rule.parseLogLevelFilter(options.level);
12785
12989
  for (const line of lines){
12786
12990
  const event = parseLogLine(line);
12787
12991
  if (event) {
@@ -12805,7 +13009,7 @@ Cross-browser compatibility
12805
13009
  message,
12806
13010
  name: 'CliError'
12807
13011
  }));
12808
- process.exit(1);
13012
+ exitWithFailure(messaging.Lp.E_INVALID_OPTION);
12809
13013
  }
12810
13014
  async function followLogs(projectPath, browser, format, matches) {
12811
13015
  const bridge = await loadExtensionDevelopBridgeModule();
@@ -12819,7 +13023,7 @@ Cross-browser compatibility
12819
13023
  message,
12820
13024
  name: 'CliError'
12821
13025
  }));
12822
- process.exit(1);
13026
+ exitWithFailure(messaging.Lp.E_SESSION_NOT_FOUND);
12823
13027
  }
12824
13028
  let settle = ()=>{};
12825
13029
  const settled = new Promise((resolve)=>{
@@ -13022,7 +13226,7 @@ Cross-browser compatibility
13022
13226
  hint: frame.hint
13023
13227
  } : {}
13024
13228
  }));
13025
- process.exit(1);
13229
+ exitWithFailure(frame?.code);
13026
13230
  }
13027
13231
  function positiveIntFlag(flag, raw, frame) {
13028
13232
  const parsed = parsePositiveInt(flag, raw);
@@ -13131,7 +13335,9 @@ Cross-browser compatibility
13131
13335
  name: 'Error',
13132
13336
  message: 'command failed'
13133
13337
  };
13338
+ const { error } = buildActEnvelope(command, result);
13134
13339
  console.error(`${err.name}: ${err.message}${err.engine ? ` (engine: ${err.engine})` : ''}`);
13340
+ if (error?.hint) console.error(error.hint);
13135
13341
  }
13136
13342
  function bridgeErrorCode(result) {
13137
13343
  const raw = result?.error || {};
@@ -13301,6 +13507,13 @@ Cross-browser compatibility
13301
13507
  Object.assign(result, input.augment(projectPath, browser, result));
13302
13508
  } catch {}
13303
13509
  printResult(result, input.opts.output, input.command, input.pretty);
13510
+ if (!result.ok) {
13511
+ const { error } = buildActEnvelope(input.command, result);
13512
+ markCommandFailure(void 0, {
13513
+ code: error?.code,
13514
+ exitCode: 1
13515
+ });
13516
+ }
13304
13517
  await exitAfterDrain(result.ok ? 0 : 1);
13305
13518
  }
13306
13519
  function targetFrom(opts, command, fallback = 'background') {
@@ -13506,59 +13719,6 @@ Cross-browser compatibility
13506
13719
  var safari_launch = __webpack_require__("./browsers/run-safari/safari-launch/index.ts");
13507
13720
  var safari_config = __webpack_require__("./browsers/run-safari/safari-launch/safari-config.ts");
13508
13721
  var safari_packager = __webpack_require__("./browsers/run-safari/safari-packager.ts");
13509
- function scanArgvValue(argv, flag) {
13510
- const equalArg = argv.find((arg)=>arg.startsWith(`${flag}=`));
13511
- if (equalArg) return equalArg.slice(flag.length + 1);
13512
- const flagIndex = argv.indexOf(flag);
13513
- if (flagIndex >= 0) return argv[flagIndex + 1] || '';
13514
- }
13515
- function collectValuedLongFlags(program) {
13516
- const flags = new Set();
13517
- const visit = (command)=>{
13518
- for (const option of command.options)if (option.long && (option.required || option.optional)) flags.add(option.long);
13519
- for (const sub of command.commands)visit(sub);
13520
- };
13521
- visit(program);
13522
- return flags;
13523
- }
13524
- function resolveCommandFromArgv(argv, valuedFlags = new Set()) {
13525
- for(let i = 2; i < argv.length; i += 1){
13526
- const arg = argv[i];
13527
- if (arg.startsWith('-')) {
13528
- if (valuedFlags.has(arg)) i += 1;
13529
- continue;
13530
- }
13531
- return arg;
13532
- }
13533
- }
13534
- function rewriteOutputAliasArgv(argv, valuedFlags = new Set()) {
13535
- const index = argv.findIndex((arg)=>'--format' === arg || arg.startsWith('--format='));
13536
- if (index < 0) return {
13537
- argv,
13538
- rewritten: false
13539
- };
13540
- const next = [
13541
- ...argv
13542
- ];
13543
- const tokens = [];
13544
- if (next[index].startsWith('--format=')) {
13545
- tokens.push(`--output=${next[index].slice(9)}`);
13546
- next.splice(index, 1);
13547
- } else {
13548
- tokens.push('--output');
13549
- const value = next[index + 1];
13550
- next.splice(index, void 0 === value || value.startsWith('-') ? 1 : 2);
13551
- if (void 0 !== value && !value.startsWith('-')) tokens.push(value);
13552
- }
13553
- const command = resolveCommandFromArgv(next, valuedFlags);
13554
- const commandIndex = command ? next.indexOf(command, 2) : -1;
13555
- if (commandIndex >= index) next.splice(commandIndex + 1, 0, ...tokens);
13556
- else next.splice(index, 0, ...tokens);
13557
- return {
13558
- argv: next,
13559
- rewritten: true
13560
- };
13561
- }
13562
13722
  const FRAMED_FLAG = 'extensionEnvelopePrinted';
13563
13723
  function markErrorFramed(err) {
13564
13724
  if (err && 'object' == typeof err) try {
@@ -13622,6 +13782,10 @@ Cross-browser compatibility
13622
13782
  return messaging.Pr.fail(command, 'usage', error);
13623
13783
  }
13624
13784
  const SUGGESTION_PATTERN = /\(Did you mean (one of )?(.+)\?\)/;
13785
+ const PROJECT_START_VERBS = new Set([
13786
+ 'init',
13787
+ 'new'
13788
+ ]);
13625
13789
  function sentenceCase(input) {
13626
13790
  const trimmed = input.trim();
13627
13791
  const capitalized = trimmed.charAt(0).toUpperCase() + trimmed.slice(1);
@@ -13641,7 +13805,8 @@ Cross-browser compatibility
13641
13805
  if (!label) label = sentenceCase(message.split('\n')[0]);
13642
13806
  const helpTarget = 'options' === noun && command && 'extension' !== command ? `extension ${command}` : 'extension';
13643
13807
  const suggestion = SUGGESTION_PATTERN.exec(message);
13644
- const remedy = suggestion ? `Did you mean ${suggestion[1] || ''}${external_pintor_default().blue(suggestion[2])}?` : `Run ${external_pintor_default().blue(`${helpTarget} --help`)} to see the ${noun}.`;
13808
+ const startsAProject = 'commander.unknownCommand' === commanderCode && PROJECT_START_VERBS.has(String(refs?.command));
13809
+ const remedy = startsAProject ? `Run ${external_pintor_default().blue('extension create my-extension')} to start a new extension.` : suggestion ? `Did you mean ${suggestion[1] || ''}${external_pintor_default().blue(suggestion[2])}?` : `Run ${external_pintor_default().blue(`${helpTarget} --help`)} to see the ${noun}.`;
13645
13810
  return `${(0, messaging.Pl)('error')} ${label}\n${remedy}`;
13646
13811
  }
13647
13812
  function isUsageCode(code) {
@@ -13788,10 +13953,10 @@ Cross-browser compatibility
13788
13953
  }
13789
13954
  function failAndExit(asJson, status, error) {
13790
13955
  if (asJson) console.log(JSON.stringify(messaging.Pr.fail('build', status, error)));
13791
- process.exit(1);
13956
+ exitWithFailure(error.code);
13792
13957
  }
13793
13958
  function registerBuildCommand(program) {
13794
- program.command('build').arguments('[project-name]').usage('[path-to-remote-extension] [options]').description(commandDescriptions.build).option(`--browser <${vendors.I9}>`, 'specify a browser/engine to run. Defaults to `chromium`. `safari` builds a Safari app via Xcode (macOS only)').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false` (`dev` and `start` default to `true`)', vendors.sJ).option('--no-polyfill', 'disable the cross-browser polyfill').option('--zip [boolean]', 'whether or not to compress the extension into a ZIP file. Defaults to `false`', vendors.sJ).option('--zip-source [boolean]', 'whether or not to include the source files in the ZIP file. Defaults to `false`', vendors.sJ).option('--zip-filename <string>', 'specify the name of the ZIP file, the browser name is appended. Defaults to the extension name and version').option('--silent [boolean]', 'suppress the build summary output. Defaults to `false`', vendors.sJ).option('--addon-lint [boolean]', 'check Firefox builds against addons.mozilla.org rules with addons-linter when it is installed. Findings print as warnings. Defaults to `true`', vendors.sJ).option('--no-addon-lint', 'skip the addons.mozilla.org lint of Firefox builds').option('--minify [boolean]', 'minify first-party code in production builds. Defaults to `true`, and to `false` for `opera`, whose store rejects minified code', vendors.sJ).option('--no-minify', 'ship readable first-party code, the Opera Add-ons review requirement').option('--install [boolean]', '[internal] install project dependencies when missing', vendors.sJ).option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--mode <development|production|none>', 'bundler mode override (also sets NODE_ENV). Defaults to `production`').option('--open [boolean]', 'open the built Safari app after packaging (safari targets only). Defaults to `false`', vendors.sJ).option('--app-name <name>', 'override the Safari app name (safari targets only). Defaults to the manifest `name`').option('--bundle-id <reverse.dns>', 'set a user-owned Safari bundle identifier (safari targets only). Defaults to a generated dev.extensionjs.* id shared by every build of the same source, so set your own before the first submission').option('--development-team <id>', 'sign the Safari app with an Apple Developer team id (safari targets only). Without it the build is ad-hoc signed, which Safari loads locally with no per-launch toggle. Use a team id for a stable identity you can distribute').option('--macos-only [boolean]', 'generate a macOS-only Safari Xcode project (safari targets only). Pass `false` for a universal macOS + iOS project. Defaults to `true`', vendors.sJ).option('--force-regenerate', 'regenerate the Safari Xcode project even when up to date (safari targets only)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).action(async (pathOrRemoteUrl, { browser: cliBrowser, ...buildOptions })=>{
13959
+ program.command('build').arguments('[project-name]').usage('[path-to-remote-extension] [options]').description(commandDescriptions.build).option(`--browser <${vendors.I9}>`, 'specify a browser/engine to run. Defaults to `chromium`. `safari` builds a Safari app via Xcode (macOS only)').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false` (`dev` and `start` default to `true`)', vendors.sJ).option('--no-polyfill', 'disable the cross-browser polyfill').option('--zip [boolean]', 'whether or not to compress the extension into a ZIP file. Defaults to `false`', vendors.sJ).option('--zip-source [boolean]', 'whether or not to include the source files in the ZIP file. Defaults to `false`', vendors.sJ).option('--zip-filename <string>', 'specify the name of the ZIP file, the browser name is appended. Defaults to the extension name and version').option('--out-dir <path>', 'write the build to `<path>/<browser>` instead of `dist/<browser>`, relative to the project root, so it can run beside a dev session that serves `dist`').option('--silent [boolean]', 'suppress the build summary output. Defaults to `false`', vendors.sJ).option('--addon-lint [boolean]', 'check Firefox builds against addons.mozilla.org rules with addons-linter when it is installed. Findings print as warnings. Defaults to `true`', vendors.sJ).option('--no-addon-lint', 'skip the addons.mozilla.org lint of Firefox builds').option('--minify [boolean]', 'minify first-party code in production builds. Defaults to `true`, and to `false` for `opera`, whose store rejects minified code', vendors.sJ).option('--no-minify', 'ship readable first-party code, the Opera Add-ons review requirement').option('--install [boolean]', '[internal] install project dependencies when missing', vendors.sJ).option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--mode <development|production|none>', 'bundler mode override (also sets NODE_ENV). Defaults to `production`').option('--open [boolean]', 'open the built Safari app after packaging (safari targets only). Defaults to `false`', vendors.sJ).option('--app-name <name>', 'override the Safari app name (safari targets only). Defaults to the manifest `name`').option('--bundle-id <reverse.dns>', 'set a user-owned Safari bundle identifier (safari targets only). Defaults to a generated dev.extensionjs.* id shared by every build of the same source, so set your own before the first submission').option('--development-team <id>', 'sign the Safari app with an Apple Developer team id (safari targets only). Without it the build is ad-hoc signed, which Safari loads locally with no per-launch toggle. Use a team id for a stable identity you can distribute').option('--macos-only [boolean]', 'generate a macOS-only Safari Xcode project (safari targets only). Pass `false` for a universal macOS + iOS project. Defaults to `true`', vendors.sJ).option('--force-regenerate', 'regenerate the Safari Xcode project even when up to date (safari targets only)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).action(async (pathOrRemoteUrl, { browser: cliBrowser, ...buildOptions })=>{
13795
13960
  const browser = cliBrowser ?? await resolveConfigBrowser(pathOrRemoteUrl || process.cwd(), 'build') ?? 'chromium';
13796
13961
  if (buildOptions.debug || buildOptions.author || buildOptions.authorMode) {
13797
13962
  process.env.EXTENSION_DEBUG = '1';
@@ -13890,6 +14055,7 @@ Cross-browser compatibility
13890
14055
  zip: buildOptions.zip,
13891
14056
  zipSource: buildOptions.zipSource,
13892
14057
  zipFilename: buildOptions.zipFilename,
14058
+ outDir: buildOptions.outDir,
13893
14059
  silent: buildOptions.silent,
13894
14060
  addonLint: buildOptions.addonLint,
13895
14061
  minify: buildOptions.minify,
@@ -13921,7 +14087,7 @@ Cross-browser compatibility
13921
14087
  hint: "Fix the error above and run build again.",
13922
14088
  truncated: true === truncated
13923
14089
  })));
13924
- process.exit(1);
14090
+ exitWithFailure(declaredErrorCode(error) ?? messaging.Lp.E_COMPILE);
13925
14091
  }
13926
14092
  if (asJson) console.log(JSON.stringify(messaging.Pr.ok('build', 'built', {
13927
14093
  projectPath: pathOrRemoteUrl,
@@ -13998,6 +14164,45 @@ Cross-browser compatibility
13998
14164
  await exitAfterDrain(0);
13999
14165
  });
14000
14166
  }
14167
+ var external_node_readline_ = __webpack_require__("node:readline");
14168
+ var external_node_readline_default = /*#__PURE__*/ __webpack_require__.n(external_node_readline_);
14169
+ const DEFAULT_PROJECT_NAME = 'my-extension';
14170
+ function project_name_prompt_isCI() {
14171
+ const v = process.env;
14172
+ return Boolean(v.CI || v.GITHUB_ACTIONS || v.GITLAB_CI || v.BUILDKITE || v.CIRCLECI || v.TRAVIS);
14173
+ }
14174
+ function canPromptForProjectName() {
14175
+ if (process.env.VITEST || process.env.VITEST_WORKER_ID) return false;
14176
+ if (project_name_prompt_isCI()) return false;
14177
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
14178
+ }
14179
+ function askProjectName(question) {
14180
+ return new Promise((resolve)=>{
14181
+ const rl = external_node_readline_default().createInterface({
14182
+ input: process.stdin,
14183
+ output: process.stdout
14184
+ });
14185
+ let settled = false;
14186
+ const finish = (answer)=>{
14187
+ if (settled) return;
14188
+ settled = true;
14189
+ try {
14190
+ rl.close();
14191
+ } catch {}
14192
+ resolve(answer);
14193
+ };
14194
+ rl.question(question, (answer)=>{
14195
+ const name = String(answer || '').trim();
14196
+ finish(name || DEFAULT_PROJECT_NAME);
14197
+ });
14198
+ rl.on('SIGINT', ()=>finish(null));
14199
+ rl.on('close', ()=>finish(null));
14200
+ });
14201
+ }
14202
+ function createCommandFor(template) {
14203
+ const name = String(template || '').trim() || 'react';
14204
+ return `npx extension@latest create ${DEFAULT_PROJECT_NAME} --template=${name}`;
14205
+ }
14001
14206
  const create_require = (0, external_node_module_.createRequire)(__rslib_import_meta_url__);
14002
14207
  const CREATE_ERROR_NEEDLES = {
14003
14208
  E_DESTINATION_NOT_EMPTY: [
@@ -14033,11 +14238,37 @@ Cross-browser compatibility
14033
14238
  for (const [code, needles] of Object.entries(CREATE_ERROR_NEEDLES))if (needles.some((needle)=>message.includes(needle))) return code;
14034
14239
  return messaging.Lp.E_INTERNAL;
14035
14240
  }
14241
+ async function resolveProjectName(template, asJson) {
14242
+ if (!asJson && canPromptForProjectName()) {
14243
+ const answer = await askProjectName(createProjectNameQuestion(DEFAULT_PROJECT_NAME));
14244
+ if (answer) return answer;
14245
+ markCommandFailure(void 0, {
14246
+ code: messaging.Lp.E_INTERRUPTED,
14247
+ exitCode: 130
14248
+ });
14249
+ await exitAfterDrain(130);
14250
+ return;
14251
+ }
14252
+ const command = createCommandFor(template);
14253
+ markCommandFailure(void 0, {
14254
+ code: messaging.Lp.E_ARGS,
14255
+ exitCode: 1
14256
+ });
14257
+ console.error(createNeedsProjectName(command));
14258
+ if (asJson) console.log(JSON.stringify(messaging.Pr.fail('create', 'usage', {
14259
+ code: messaging.Lp.E_ARGS,
14260
+ message: `A project name is required. Run ${command} to start one.`,
14261
+ name: 'CliError'
14262
+ })));
14263
+ await exitAfterDrain(1);
14264
+ }
14036
14265
  function registerCreateCommand(program) {
14037
- program.command('create').arguments('<project-name|project-path>').usage('<project-name|project-path> [options]').description(commandDescriptions.create).option('-t, --template <template-name>', `catalog name, GitHub URL, or ZIP URL to scaffold from; every catalog name is listed below (default: ${DEFAULT_TEMPLATE})`).option('--install [boolean]', 'whether or not to install the dependencies after creating the project (disabled by default, pass --install to opt in)', vendors.sJ, false).option('--source <source>', 'attribution tag for where this create was initiated (e.g. cli, templates); recorded in anonymous telemetry only').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addHelpText('after', renderCreateTemplateHelp()).action(async (pathOrRemoteUrl, { template, install, output })=>{
14266
+ program.command('create').arguments('[project-name|project-path]').usage('<project-name|project-path> [options]').description(commandDescriptions.create).option('-t, --template <template-name>', `catalog name, GitHub URL, or ZIP URL to scaffold from; every catalog name is listed below (default: ${DEFAULT_TEMPLATE})`).option('--install [boolean]', 'whether or not to install the dependencies after creating the project (disabled by default, pass --install to opt in)', vendors.sJ, false).option('--source <source>', 'attribution tag for where this create was initiated (e.g. cli, templates); recorded in anonymous telemetry only').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addHelpText('after', renderCreateTemplateHelp()).action(async (projectInput, { template, install, output })=>{
14038
14267
  const asJson = isJsonOutput({
14039
14268
  output
14040
14269
  });
14270
+ const pathOrRemoteUrl = projectInput || await resolveProjectName(template, asJson);
14271
+ if (!pathOrRemoteUrl) return;
14041
14272
  if (!process.env.EXTENSION_CREATE_DEVELOP_ROOT) try {
14042
14273
  process.env.EXTENSION_CREATE_DEVELOP_ROOT = resolveExtensionDevelopRoot();
14043
14274
  } catch {
@@ -14065,6 +14296,7 @@ Cross-browser compatibility
14065
14296
  cliVersion: getCliPackageJson().version
14066
14297
  });
14067
14298
  } catch (error) {
14299
+ if (createErrorCode(error) === messaging.Lp.E_DEPENDENCY_INSTALL) recordDependencyInstall('failed');
14068
14300
  markCommandFailure(void 0, {
14069
14301
  code: createErrorCode(error),
14070
14302
  exitCode: 1
@@ -14077,6 +14309,7 @@ Cross-browser compatibility
14077
14309
  await exitAfterDrain(1);
14078
14310
  return;
14079
14311
  }
14312
+ recordDependencyInstall(result?.depsInstalled ? 'installed' : 'skipped', result?.installSeconds);
14080
14313
  if (asJson) console.log(JSON.stringify(messaging.Pr.ok('create', 'created', {
14081
14314
  projectPath: result?.projectPath ?? pathOrRemoteUrl,
14082
14315
  projectName: result?.projectName,
@@ -14398,7 +14631,7 @@ Cross-browser compatibility
14398
14631
  if (asJson) printFrame(messaging.Pr.fail('dev', status, error, hint ? {
14399
14632
  hint
14400
14633
  } : {}));
14401
- process.exit(1);
14634
+ exitWithFailure(error.code);
14402
14635
  }
14403
14636
  function resolveRequestedPort(value) {
14404
14637
  const parsed = 'number' == typeof value ? value : Number.parseInt(String(value ?? ''), 10);
@@ -14599,7 +14832,7 @@ Cross-browser compatibility
14599
14832
  }, {
14600
14833
  hint: 'Fix the error above and run dev again.'
14601
14834
  }));
14602
- process.exit(1);
14835
+ exitWithFailure(code);
14603
14836
  }
14604
14837
  }
14605
14838
  });
@@ -15817,7 +16050,7 @@ Cross-browser compatibility
15817
16050
  hint
15818
16051
  } : {}
15819
16052
  }));
15820
- process.exit(1);
16053
+ exitWithFailure(code);
15821
16054
  }
15822
16055
  function accessibilityHint(host) {
15823
16056
  return `Open System Settings ▸ Privacy & Security ▸ Accessibility, add ${host}, and run again.`;
@@ -15990,7 +16223,7 @@ Cross-browser compatibility
15990
16223
  if (asJson) start_printFrame(messaging.Pr.fail('start', status, error, hint ? {
15991
16224
  hint
15992
16225
  } : {}));
15993
- process.exit(1);
16226
+ exitWithFailure(error.code);
15994
16227
  }
15995
16228
  function registerStartCommand(program) {
15996
16229
  program.command('start').arguments('[project-path|remote-url]').usage('[project-path|remote-url] [options]').description(commandDescriptions.start).addHelpText('after', "\nAdditional options:\n --no-browser stop the browser launch, the build still runs\n --wait wait for ready contract and exit, pair with --output json for machine output\n" + BROWSER_LAUNCH_HELP_FOOTER).option('--profile <path-to-file | boolean>', 'what path to use for the browser profile. A boolean value of false sets the profile to the default user profile. Defaults to a fresh profile').option(`--browser <${vendors.DB}>`, 'specify a browser/engine to run. Defaults to `chromium`').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `true` (`build` defaults to `false`)', vendors.sJ).option('--no-polyfill', 'disable the cross-browser polyfill').option('--no-open', NO_OPEN_FLAG_DESCRIPTION).option('--enable-extension', 'turn the extension on in Safari Settings through macOS Accessibility (safari targets only, and start has no Safari path yet)').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').addOption(geckoBinaryOption()).addOption(firefoxBinaryAliasOption()).option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--host <host>', 'specify the host to bind the dev server to. Use 0.0.0.0 for Docker/devcontainers. Defaults to `127.0.0.1`').option('--public-host <host>', 'accepted for parity with `dev`. `start` serves nothing, so this has no effect').option('--log-context <list>', `[experimental] comma-separated contexts to include (${LOG_CONTEXTS.join(',')}). Use \`all\` to include all contexts (default)`).option('--logs <off|error|warn|info|debug|trace|all>', '[experimental] minimum centralized logger level to display in terminal (default: off)').option('--log-format <pretty|json|ndjson>', '[experimental] output format for logger events. Defaults to `pretty`').option('--no-log-timestamps', 'disable ISO timestamps in pretty output').option('--no-log-color', 'disable color in pretty output').option('--log-url <pattern>', '[experimental] only show logs where event.url matches this substring or regex (/re/i)').option('--log-tab <id>', 'only show logs for a specific tabId (number)').option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--allow-control', 'open the agent-bridge control channel on the production run for bounded act (storage/reload/open). The browser loads a copy of the build with the control producer added; dist/ is unchanged').option('--allow-eval', 'additionally enable `extension eval` on the production run (implies --allow-control, runs arbitrary code in a context, writes a 0600 session token)').option('--install [boolean]', '[internal] install project dependencies when missing', vendors.sJ).option('--wait [boolean]', 'wait for dist/extension-js/<browser>/ready.json and exit', vendors.sJ).option('--wait-timeout <ms>', 'timeout in milliseconds when using --wait (default: 60000)').option('--output <pretty|json>', 'result format. Use json for a schema-1 envelope on stdout').addOption(new external_commander_namespaceObject.Option('--wait-format <pretty|json>').hideHelp()).addOption(new external_commander_namespaceObject.Option('--debug', 'print maintainer diagnostics alongside normal output')).addOption(new external_commander_namespaceObject.Option('--author, --author-mode', 'deprecated alias for --debug').hideHelp()).action(async (pathOrRemoteUrl, options, command)=>{
@@ -16097,7 +16330,7 @@ Cross-browser compatibility
16097
16330
  }, {
16098
16331
  hint: 'Fix the error above and run start again.'
16099
16332
  }));
16100
- process.exit(1);
16333
+ exitWithFailure(declaredErrorCode(error) ?? messaging.Lp.E_COMPILE);
16101
16334
  }
16102
16335
  if (noBrowser) continue;
16103
16336
  const { extensionPreview } = await loadExtensionDevelopPreviewModule();
@@ -16230,7 +16463,7 @@ Cross-browser compatibility
16230
16463
  async function flushTelemetryWithin(ms) {
16231
16464
  try {
16232
16465
  await Promise.race([
16233
- telemetry.flush(),
16466
+ telemetry_cli_telemetry.flush(),
16234
16467
  new Promise((resolve)=>setTimeout(resolve, ms).unref?.())
16235
16468
  ]);
16236
16469
  } catch {}
@@ -16293,13 +16526,13 @@ Cross-browser compatibility
16293
16526
  if (cli_failure_wantsJsonOutput(argv)) writeStdoutFrame(earlyExitEnvelope(index_resolveCommandFromArgv(argv) || 'extension', code, plainMessage, {
16294
16527
  flag
16295
16528
  }));
16296
- process.exit(1);
16529
+ exitWithFailure(code);
16297
16530
  }
16298
16531
  function applyOutputAliasArgvShim(argv) {
16299
16532
  if (argv.includes('--ai-help')) return argv;
16300
16533
  const { argv: next, rewritten } = rewriteOutputAliasArgv(argv, valuedLongFlags);
16301
16534
  if (rewritten) warnDeprecatedOutputAlias('--format');
16302
- return next;
16535
+ return movePreCommandOutputArgv(next, valuedLongFlags);
16303
16536
  }
16304
16537
  function applyNoBrowserArgvShim(argv) {
16305
16538
  const hasNoRunner = argv.includes('--no-runner');
@@ -16346,6 +16579,7 @@ Cross-browser compatibility
16346
16579
  registerDoctorCommand(extensionJs);
16347
16580
  registerCapabilitiesCommand(extensionJs);
16348
16581
  valuedLongFlags = collectValuedLongFlags(extensionJs);
16582
+ resolveInvokedCommand(process.argv, valuedLongFlags);
16349
16583
  function runAIHelp() {
16350
16584
  const format = resolveAIHelpFormatFromArgv(process.argv).trim().toLowerCase();
16351
16585
  if ('json' === format) {
@@ -16379,7 +16613,7 @@ Cross-browser compatibility
16379
16613
  const exitCode = commanderExitCode(err);
16380
16614
  if (0 === exitCode) process.exit(0);
16381
16615
  markCommandFailure(void 0, {
16382
- code: messaging.Lp.E_ARGS,
16616
+ code: codeForCommanderError(String(err.code)),
16383
16617
  exitCode
16384
16618
  });
16385
16619
  console.error(commanderHumanError(err, commandName));
@@ -16434,6 +16668,9 @@ Cross-browser compatibility
16434
16668
  "node:path" (module) {
16435
16669
  module.exports = require("node:path");
16436
16670
  },
16671
+ "node:readline" (module) {
16672
+ module.exports = require("node:readline");
16673
+ },
16437
16674
  pintor (module) {
16438
16675
  module.exports = require("pintor");
16439
16676
  },