extension 3.5.0 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,7 +13,6 @@ export declare const commandDescriptions: {
13
13
  readonly start: "Builds and starts the extension in production mode";
14
14
  readonly preview: "Previews the extension in production mode without building";
15
15
  readonly build: "Builds the extension for packaging/distribution";
16
- readonly cleanup: "Cleans up orphaned instances and frees unused ports";
17
16
  };
18
17
  export declare function unhandledError(err: unknown): string;
19
18
  export declare function updateFailed(err: any): string;
@@ -31,3 +30,38 @@ export declare function unsupportedBrowserFlag(value: string, supported: string[
31
30
  export declare function invalidLogsOptionPipe(value: string): string;
32
31
  export declare function invalidLogsOptionValue(value: string, allowed: string[]): string;
33
32
  export declare function programAIHelp(): string;
33
+ export type ProgramAIHelpJSON = {
34
+ version: string;
35
+ commands: Array<{
36
+ name: 'create' | 'dev' | 'start' | 'preview' | 'build';
37
+ summary: string;
38
+ supportsSourceInspection: boolean;
39
+ }>;
40
+ globalOptions: Array<{
41
+ name: '--ai-help' | '--format' | '--no-telemetry';
42
+ values?: string[];
43
+ default?: string;
44
+ description: string;
45
+ }>;
46
+ capabilities: {
47
+ sourceInspection: {
48
+ supportedIn: string[];
49
+ unsupportedIn: string[];
50
+ notes: string[];
51
+ };
52
+ logger: {
53
+ levels: string[];
54
+ formats: string[];
55
+ notes: string[];
56
+ };
57
+ managedDependencies: {
58
+ enforcement: string;
59
+ trigger: string;
60
+ action: string;
61
+ };
62
+ };
63
+ examples: string[];
64
+ };
65
+ export declare function programAIHelpJSON(version: string): ProgramAIHelpJSON;
66
+ export declare function invalidAIHelpFormat(value: string): string;
67
+ export declare function sourceInspectionNotSupported(command: 'start' | 'preview'): string;
package/dist/cli.cjs CHANGED
@@ -57,7 +57,7 @@ var __webpack_exports__ = {};
57
57
  return external_pintor_default().green('►►►');
58
58
  }
59
59
  const code = (text)=>external_pintor_default().blue(text);
60
- const arg = (text)=>external_pintor_default().gray(text);
60
+ const messages_arg = (text)=>external_pintor_default().gray(text);
61
61
  const fmt = {
62
62
  heading: (title)=>external_pintor_default().underline(external_pintor_default().blue(title)),
63
63
  label: (k)=>external_pintor_default().gray(k.toUpperCase()),
@@ -85,8 +85,7 @@ var __webpack_exports__ = {};
85
85
  dev: 'Starts the development server with hot reloading',
86
86
  start: 'Builds and starts the extension in production mode',
87
87
  preview: 'Previews the extension in production mode without building',
88
- build: 'Builds the extension for packaging/distribution',
89
- cleanup: 'Cleans up orphaned instances and frees unused ports'
88
+ build: 'Builds the extension for packaging/distribution'
90
89
  };
91
90
  function unhandledError(err) {
92
91
  const message = err instanceof Error ? err.stack || err.message : 'string' == typeof err ? err : fmt.truncate(err);
@@ -115,57 +114,70 @@ Example
115
114
  - ${code('extension create --help')} outputs information about the "create" command.
116
115
 
117
116
  Available Commands
118
- - ${code('extension create ' + arg('<project-name|project-path>'))}
117
+ - ${code('extension create ' + messages_arg('<project-name|project-path>'))}
119
118
  ${commandDescriptions.create}
120
119
 
121
- - ${code('extension dev ' + arg('[project-path|remote-url]'))}
120
+ - ${code('extension dev ' + messages_arg('[project-path|remote-url]'))}
122
121
  ${commandDescriptions.dev}
123
122
 
124
- - ${code('extension start ' + arg('[project-path|remote-url]'))}
123
+ - ${code('extension start ' + messages_arg('[project-path|remote-url]'))}
125
124
  ${commandDescriptions.start}
126
125
 
127
- - ${code('extension preview ' + arg('[project-path|remote-url]'))}
126
+ - ${code('extension preview ' + messages_arg('[project-path|remote-url]'))}
128
127
  ${commandDescriptions.preview}
129
128
 
130
- - ${code('extension build ' + arg('[project-path|remote-url]'))}
129
+ - ${code('extension build ' + messages_arg('[project-path|remote-url]'))}
131
130
  ${commandDescriptions.build}
132
131
 
133
- - ${code('extension cleanup')}
134
- ${commandDescriptions.cleanup}
135
-
136
132
  Common Options
137
- - ${code('--browser')} ${arg('<chrome|edge|firefox|chromium|chromium-based|gecko-based|firefox-based>')} Target browser/engine (default: chrome)
138
- - ${code('--profile')} ${arg('<path|boolean>')} Browser profile configuration
139
- - ${code('--polyfill')} ${arg('[boolean]')} Enable/disable cross-browser polyfill
133
+ - ${code('--browser')} ${messages_arg('<chrome|edge|firefox|chromium|chromium-based|gecko-based|firefox-based>')} Target browser/engine (default: chromium)
134
+ - ${code('--profile')} ${messages_arg('<path|boolean>')} Browser profile configuration
135
+ - ${code('--polyfill')} ${messages_arg('[boolean]')} Enable/disable cross-browser polyfill
140
136
  - ${code('--no-telemetry')} Disable anonymous telemetry for this run
141
- - ${code('--port')} ${arg('<number>')} Development server port (default: 8080)
142
- - ${code('--starting-url')} ${arg('<url>')} Initial URL to load in browser
143
- - ${code('--silent')} ${arg('[boolean]')} Suppress console output during build
137
+ - ${code('--ai-help')} Show AI-assistant oriented help and tips
138
+ - ${code('--format')} ${messages_arg('<pretty|json>')} Output format for ${code('--ai-help')} (default: pretty)
139
+ - ${code('--help')} Show help output
140
+ - ${code('--port')} ${messages_arg('<number>')} Development server port (default: 8080)
141
+ - ${code('--starting-url')} ${messages_arg('<url>')} Initial URL to load in browser
142
+ - ${code('--silent')} ${messages_arg('[boolean]')} Suppress console output during build
144
143
 
145
- Source Inspection
146
- - ${code('--source')} ${arg('<url|boolean>')} Open URL and print HTML after content scripts inject
147
- - When provided without a URL, falls back to ${arg('--starting-url')} or ${arg('https://example.com')}
148
- - Watch mode is enabled by default when ${code('--source')} is present
144
+ Source Inspection (dev command)
145
+ - ${code('--source')} ${messages_arg('<url|boolean>')} Open URL and print HTML after content scripts inject (dev only)
146
+ - When provided without a URL, falls back to ${messages_arg('--starting-url')} or ${messages_arg('https://example.com')}
147
+ - For ${code('extension dev')}, watch mode is enabled by default when ${code('--source')} is present
148
+ - ${messages_arg('Note:')} ${code('extension preview')} and ${code('extension start')} do not run source inspection in run-only preview mode.
149
+ - ${code('--watch-source')} ${messages_arg('[boolean]')} Re-print HTML on rebuilds or file changes
150
+ - ${code('--source-format')} ${messages_arg('<pretty|json|ndjson>')} Output format for page HTML (defaults to ${code('--log-format')} when present)
151
+ - ${code('--source-summary')} ${messages_arg('[boolean]')} Output a compact summary instead of full HTML
152
+ - ${code('--source-meta')} ${messages_arg('[boolean]')} Output page metadata (readyState, viewport, frames)
153
+ - ${code('--source-probe')} ${messages_arg('<selectors>')} Comma-separated CSS selectors to probe
154
+ - ${code('--source-tree')} ${messages_arg('<off|root-only>')} Output a compact extension root tree
155
+ - ${code('--source-console')} ${messages_arg('[boolean]')} Output console summary (best-effort)
156
+ - ${code('--source-dom')} ${messages_arg('[boolean]')} Output DOM snapshots and diffs
157
+ - ${code('--source-max-bytes')} ${messages_arg('<bytes>')} Limit HTML output size (0 disables truncation)
158
+ - ${code('--source-redact')} ${messages_arg('<off|safe|strict>')} Redact sensitive HTML content (default: safe for JSON/NDJSON)
159
+ - ${code('--source-include-shadow')} ${messages_arg('<off|open-only|all>')} Control Shadow DOM inclusion (default: open-only)
160
+ - ${code('--source-diff')} ${messages_arg('[boolean]')} Include diff metadata on watch updates
149
161
 
150
162
  Browser-Specific Options
151
- - ${code('--chromium-binary')} ${arg('<path>')} Custom Chromium binary path
152
- - ${code('--gecko-binary')}/${code('--firefox-binary')} ${arg('<path>')} Custom Firefox/Gecko binary path
163
+ - ${code('--chromium-binary')} ${messages_arg('<path>')} Custom Chromium binary path
164
+ - ${code('--gecko-binary')}/${code('--firefox-binary')} ${messages_arg('<path>')} Custom Firefox/Gecko binary path
153
165
 
154
166
  Build Options
155
- - ${code('--zip')} ${arg('[boolean]')} Create ZIP archive of built extension
156
- - ${code('--zip-source')} ${arg('[boolean]')} Include source files in ZIP
157
- - ${code('--zip-filename')} ${arg('<name>')} Custom ZIP filename
167
+ - ${code('--zip')} ${messages_arg('[boolean]')} Create ZIP archive of built extension
168
+ - ${code('--zip-source')} ${messages_arg('[boolean]')} Include source files in ZIP
169
+ - ${code('--zip-filename')} ${messages_arg('<name>')} Custom ZIP filename
158
170
 
159
171
  ${external_pintor_default().underline('Centralized Logger (terminal output)')}
160
172
  - The manager extension embeds a centralized logger that streams events to the CLI.
161
173
  - Enable and filter logs directly via ${code('extension dev')} flags:
162
- - ${code('--logs')} ${arg('<off|error|warn|info|debug|trace>')} Minimum level (default: info)
163
- - ${code('--log-context')} ${arg('<list|all>')} Contexts: background,content,page,sidebar,popup,options,devtools
164
- - ${code('--log-format')} ${arg('<pretty|json>')} Output format (default: pretty)
174
+ - ${code('--logs')} ${messages_arg('<off|error|warn|info|debug|trace>')} Minimum level (default: off)
175
+ - ${code('--log-context')} ${messages_arg('<list|all>')} Contexts: background,content,page,sidebar,popup,options,devtools
176
+ - ${code('--log-format')} ${messages_arg('<pretty|json|ndjson>')} Output format (default: pretty)
165
177
  - ${code('--no-log-timestamps')} Hide ISO timestamps in pretty output
166
178
  - ${code('--no-log-color')} Disable color in pretty output
167
- - ${code('--log-url')} ${arg('<substring|/regex/>')} Filter by event.url
168
- - ${code('--log-tab')} ${arg('<id>')} Filter by tabId
179
+ - ${code('--log-url')} ${messages_arg('<substring|/regex/>')} Filter by event.url
180
+ - ${code('--log-tab')} ${messages_arg('<id>')} Filter by tabId
169
181
  - Example: ${code('extension dev ./my-ext --logs=debug --log-context=all --log-format=pretty')}
170
182
 
171
183
  ${code('extension --help')}
@@ -179,6 +191,7 @@ ${external_pintor_default().underline('Path Resolution (important)')}
179
191
 
180
192
  AI Assistants
181
193
  - For AI-oriented guidance and deeper tips, run ${code('extension --ai-help')}
194
+ - For machine-readable AI guidance, run ${code('extension --ai-help --format json')}
182
195
 
183
196
  Report issues
184
197
  - ${external_pintor_default().underline('https://github.com/cezaraugusto/extension/issues/new')}`;
@@ -197,13 +210,13 @@ Browser-Specific Configuration
197
210
  Centralized Logger (for AI & CI)
198
211
  - Logs from all contexts are centralized by the manager extension and streamed to the CLI.
199
212
  - Prefer these flags to control terminal logs during ${code('extension dev')}:
200
- - ${code('--logs')} ${arg('<off|error|warn|info|debug|trace>')} Minimum level
201
- - ${code('--log-context')} ${arg('<list|all>')} Contexts to include
202
- - ${code('--log-format')} ${arg('<pretty|json>')} Pretty for humans; JSON for machines/NDJSON pipelines
203
- - ${code('--no-log-timestamps')} ${arg(' ')} Disable timestamps (pretty)
204
- - ${code('--no-log-color')} ${arg(' ')} Disable ANSI colors (pretty)
205
- - ${code('--log-url')} ${arg('<substring|/regex/>')} Filter by URL
206
- - ${code('--log-tab')} ${arg('<id>')} Filter by tabId
213
+ - ${code('--logs')} ${messages_arg('<off|error|warn|info|debug|trace>')} Minimum level
214
+ - ${code('--log-context')} ${messages_arg('<list|all>')} Contexts to include
215
+ - ${code('--log-format')} ${messages_arg('<pretty|json|ndjson>')} Pretty for humans; JSON for machines/NDJSON pipelines
216
+ - ${code('--no-log-timestamps')} ${messages_arg(' ')} Disable timestamps (pretty)
217
+ - ${code('--no-log-color')} ${messages_arg(' ')} Disable ANSI colors (pretty)
218
+ - ${code('--log-url')} ${messages_arg('<substring|/regex/>')} Filter by URL
219
+ - ${code('--log-tab')} ${messages_arg('<id>')} Filter by tabId
207
220
  - Good CI pattern: ${code('EXTENSION_AUTHOR_MODE=development EXTENSION_AUTO_EXIT_MS=6000 extension dev ./ext --logs=info --log-format=json')}
208
221
 
209
222
  Special Folders for Entrypoints
@@ -238,20 +251,20 @@ Shadow DOM for Content Scripts
238
251
  - Prevents style conflicts with host page
239
252
 
240
253
  Environment Variables
241
- - Use ${code(arg('EXTENSION_PUBLIC_*'))} prefix for variables accessible in extension code
254
+ - Use ${code(messages_arg('EXTENSION_PUBLIC_*'))} prefix for variables accessible in extension code
242
255
  - Supported in both ${code('process.env')} and ${code('import.meta.env')}
243
- - Environment file priority: ${external_pintor_default().underline(code(arg('.env.{browser}.{mode}')))} > ${external_pintor_default().underline(code(arg('.env.{browser}')))} > ${external_pintor_default().underline(code(arg('.env.{mode}')))} > ${external_pintor_default().underline(code(arg('.env')))}
244
- - Example: ${code(arg('EXTENSION_PUBLIC_API_KEY=your_key'))}
256
+ - Environment file priority: ${external_pintor_default().underline(code(messages_arg('.env.{browser}.{mode}')))} > ${external_pintor_default().underline(code(messages_arg('.env.{browser}')))} > ${external_pintor_default().underline(code(messages_arg('.env.{mode}')))} > ${external_pintor_default().underline(code(messages_arg('.env')))}
257
+ - Example: ${code(messages_arg('EXTENSION_PUBLIC_API_KEY=your_key'))}
245
258
 
246
259
  Available Templates
247
- - ${external_pintor_default().green('Frameworks')}: ${code(arg('react'))}, ${code(arg('preact'))}, ${code(arg('vue'))}, ${code(arg('svelte'))}
248
- - ${external_pintor_default().green('Languages')}: ${code(arg("javascript"))}, ${code(arg("typescript"))}
249
- - ${external_pintor_default().green('Contexts')}: ${code(arg('content'))} (content scripts), ${code(arg('new'))} (new tab), ${code(arg('action'))} (popup)
250
- - ${external_pintor_default().green('Styling')}: ${code(arg('tailwind'))}, ${code(arg('sass'))}, ${code(arg('less'))}
251
- - ${external_pintor_default().green('Configs')}: ${code(arg('eslint'))}, ${code(arg('prettier'))}, ${code(arg('stylelint'))}
260
+ - ${external_pintor_default().green('Frameworks')}: ${code(messages_arg('react'))}, ${code(messages_arg('preact'))}, ${code(messages_arg('vue'))}, ${code(messages_arg('svelte'))}
261
+ - ${external_pintor_default().green('Languages')}: ${code(messages_arg("javascript"))}, ${code(messages_arg("typescript"))}
262
+ - ${external_pintor_default().green('Contexts')}: ${code(messages_arg('content'))} (content scripts), ${code(messages_arg('new'))} (new tab), ${code(messages_arg('action'))} (popup)
263
+ - ${external_pintor_default().green('Styling')}: ${code(messages_arg('tailwind'))}, ${code(messages_arg('sass'))}, ${code(messages_arg('less'))}
264
+ - ${external_pintor_default().green('Configs')}: ${code(messages_arg('eslint'))}, ${code(messages_arg('prettier'))}, ${code(messages_arg('stylelint'))}
252
265
 
253
266
  Webpack/Rspack Configuration
254
- - Create ${external_pintor_default().underline(code(arg('extension.config.js')))} for custom webpack configuration
267
+ - Create ${external_pintor_default().underline(code(messages_arg('extension.config.js')))} for custom webpack configuration
255
268
  - Function receives base config, return modified config
256
269
  - Supports all webpack/rspack loaders and plugins
257
270
  - Example:
@@ -270,8 +283,8 @@ Managed Dependencies (Important)
270
283
  - If you truly need a different version, open an issue so we can evaluate a safe upgrade.
271
284
 
272
285
  Framework-Specific Configuration
273
- - Create ${external_pintor_default().underline(code(arg('vue.loader.js')))} for Vue-specific loader configuration
274
- - Create ${external_pintor_default().underline(code(arg('svelte.loader.js')))} for Svelte-specific loader configuration
286
+ - Create ${external_pintor_default().underline(code(messages_arg('vue.loader.js')))} for Vue-specific loader configuration
287
+ - Create ${external_pintor_default().underline(code(messages_arg('svelte.loader.js')))} for Svelte-specific loader configuration
275
288
  - Automatically detected and used by Extension.js
276
289
  - Example svelte.loader.js:
277
290
  ${code('module.exports = {')}
@@ -288,18 +301,32 @@ Hot Module Replacement (HMR)
288
301
  - Service workers, _locales and manifest changes reload the extension
289
302
 
290
303
  Source Inspection & Real-Time Monitoring
291
- - Use ${code('--source')} ${arg('<url|boolean>')} to inspect page HTML after content script injection
292
- - When no URL is provided, falls back to ${arg('--starting-url')} or ${arg('https://example.com')}
304
+ - Use ${code('extension dev --source')} ${messages_arg('<url|boolean>')} to inspect page HTML after content script injection
305
+ - When no URL is provided, falls back to ${messages_arg('--starting-url')} or ${messages_arg('https://example.com')}
293
306
  - Watch mode is enabled by default when ${code('--source')} is present
307
+ - Use ${code('--watch-source')} to re-print HTML on rebuilds or file changes
308
+ - Use ${code('--source-format')} ${messages_arg('<pretty|json|ndjson>')} for machine-friendly HTML output
309
+ - Use ${code('--source-summary')} to emit a compact JSON summary instead of full HTML
310
+ - Use ${code('--source-meta')} to emit page metadata (readyState, viewport, frames)
311
+ - Use ${code('--source-probe')} to probe CSS selectors for quick validation
312
+ - Use ${code('--source-tree')} to emit a compact extension root tree
313
+ - Use ${code('--source-console')} to emit a console summary (best-effort)
314
+ - Use ${code('--source-dom')} to emit DOM snapshots and diffs
315
+ - Use ${code('--source-redact')} ${messages_arg('<off|safe|strict>')} to redact sensitive content
316
+ - Use ${code('--source-max-bytes')} ${messages_arg('<bytes>')} to limit output size
317
+ - Use ${code('--source-diff')} ${messages_arg('[boolean]')} to emit diff metadata for watch updates
318
+ - Source events include frame context (frameId/frameUrl), and console summaries include best-effort script URLs.
319
+ - Action timeline events ${code('action_event')} report navigation, injection, rebuilds, snapshots, and reloads.
294
320
  - Automatically enables Chrome remote debugging (port 9222) when source inspection is active
295
321
  - Extracts Shadow DOM content from ${code('#extension-root')} or ${code('[data-extension-root=\"true\"]')} elements
296
322
  - Useful for debugging content script behavior and style injection
297
- - Example: ${code('extension dev --source=' + arg('https://example.com'))}
323
+ - Example: ${code('extension dev --source=' + messages_arg('https://example.com'))}
324
+ - ${messages_arg('Note:')} ${code('preview/start')} run in run-only mode and do not perform source inspection.
298
325
 
299
326
  Non-Destructive Testing in CI
300
327
  - Prefer ${code('EXTENSION_AUTHOR_MODE=development')} to copy local templates and avoid network.
301
328
  - Reuse Playwright's Chromium via ${code('--chromium-binary')} path when available.
302
- - Set ${code(arg('EXTENSION_AUTO_EXIT_MS'))} and ${code(arg('EXTENSION_FORCE_KILL_MS'))} for non-interactive dev sessions.
329
+ - Set ${code(messages_arg('EXTENSION_AUTO_EXIT_MS'))} and ${code(messages_arg('EXTENSION_FORCE_KILL_MS'))} for non-interactive dev sessions.
303
330
 
304
331
  File Watching & HMR Examples
305
332
  - Content script JS/TS changes trigger reinjection; CSS changes update styles live.
@@ -311,16 +338,121 @@ Troubleshooting
311
338
  - When ports conflict, pass ${code('--port 0')} to auto-select an available port.
312
339
 
313
340
  Non-Interactive / Auto Mode (CI)
314
- - Set ${code(arg('EXTENSION_AUTO_EXIT_MS'))} to enable self-termination after N milliseconds.
341
+ - Set ${code(messages_arg('EXTENSION_AUTO_EXIT_MS'))} to enable self-termination after N milliseconds.
315
342
  Useful when ${code('pnpm extension dev')} would otherwise hang under Rspack watch.
316
- Example: ${code(arg('EXTENSION_AUTO_EXIT_MS=6000'))} pnpm extension dev ./templates/react --browser chrome --source ${arg('https://example.com')}
317
- - Optional: ${code(arg('EXTENSION_FORCE_KILL_MS'))} to hard-exit after N ms as a fallback (defaults to auto-exit + 4000).
343
+ Example: ${code(messages_arg('EXTENSION_AUTO_EXIT_MS=6000'))} pnpm extension dev ./templates/react --browser chrome --source ${messages_arg('https://example.com')}
344
+ - Optional: ${code(messages_arg('EXTENSION_FORCE_KILL_MS'))} to hard-exit after N ms as a fallback (defaults to auto-exit + 4000).
318
345
 
319
346
  Cross-Browser Compatibility
320
347
  - Use ${code('--polyfill')} flag to enable webextension-polyfill
321
348
  - Automatically handles browser API differences
322
349
  - Supports Chrome, Edge, Firefox with single codebase`;
323
350
  }
351
+ function programAIHelpJSON(version) {
352
+ return {
353
+ version,
354
+ commands: [
355
+ {
356
+ name: 'create',
357
+ summary: commandDescriptions.create,
358
+ supportsSourceInspection: false
359
+ },
360
+ {
361
+ name: 'dev',
362
+ summary: commandDescriptions.dev,
363
+ supportsSourceInspection: true
364
+ },
365
+ {
366
+ name: 'start',
367
+ summary: commandDescriptions.start,
368
+ supportsSourceInspection: false
369
+ },
370
+ {
371
+ name: 'preview',
372
+ summary: commandDescriptions.preview,
373
+ supportsSourceInspection: false
374
+ },
375
+ {
376
+ name: 'build',
377
+ summary: commandDescriptions.build,
378
+ supportsSourceInspection: false
379
+ }
380
+ ],
381
+ globalOptions: [
382
+ {
383
+ name: '--ai-help',
384
+ description: 'Show AI-assistant oriented help and tips'
385
+ },
386
+ {
387
+ name: '--format',
388
+ values: [
389
+ 'pretty',
390
+ 'json'
391
+ ],
392
+ default: 'pretty',
393
+ description: 'Output format for --ai-help'
394
+ },
395
+ {
396
+ name: '--no-telemetry',
397
+ description: 'Disable anonymous telemetry for this run'
398
+ }
399
+ ],
400
+ capabilities: {
401
+ sourceInspection: {
402
+ supportedIn: [
403
+ 'dev'
404
+ ],
405
+ unsupportedIn: [
406
+ 'start',
407
+ 'preview',
408
+ 'build',
409
+ 'create'
410
+ ],
411
+ notes: [
412
+ '--source supports URL fallback to --starting-url or https://example.com',
413
+ 'run-only preview mode does not perform source inspection'
414
+ ]
415
+ },
416
+ logger: {
417
+ levels: [
418
+ 'off',
419
+ 'error',
420
+ 'warn',
421
+ 'info',
422
+ 'debug',
423
+ 'trace',
424
+ 'all'
425
+ ],
426
+ formats: [
427
+ 'pretty',
428
+ 'json',
429
+ 'ndjson'
430
+ ],
431
+ notes: [
432
+ 'centralized logger streams logs from multiple extension contexts',
433
+ '--logs defaults to off unless explicitly enabled'
434
+ ]
435
+ },
436
+ managedDependencies: {
437
+ enforcement: 'guarded',
438
+ trigger: 'when managed packages are declared in package.json and referenced in extension.config',
439
+ action: 'print an error and abort'
440
+ }
441
+ },
442
+ examples: [
443
+ 'extension --ai-help',
444
+ 'extension --ai-help --format json',
445
+ 'extension dev ./my-ext --source https://example.com --source-format json',
446
+ 'extension dev ./my-ext --logs=info --log-format=json'
447
+ ]
448
+ };
449
+ }
450
+ function invalidAIHelpFormat(value) {
451
+ return `${getLoggingPrefix('error')} Invalid value for ${code('--format')}: ${external_pintor_default().red(String(value))}\nAllowed values: ${messages_arg('pretty, json')}. Example: ${code('extension --ai-help --format json')}`;
452
+ }
453
+ function sourceInspectionNotSupported(command) {
454
+ return `${getLoggingPrefix('error')} ${code(`extension ${command}`)} currently runs in run-only preview mode and does not support source inspection.\nUse ${code('extension dev --source <url>')} for source inspection features.`;
455
+ }
324
456
  const external_semver_namespaceObject = require("semver");
325
457
  const external_node_fs_namespaceObject = require("node:fs");
326
458
  var external_node_fs_default = /*#__PURE__*/ __webpack_require__.n(external_node_fs_namespaceObject);
@@ -733,6 +865,84 @@ Cross-Browser Compatibility
733
865
  if (!hasExplicitSourceString) return hasStartingUrl ? String(startingUrl) : 'https://example.com';
734
866
  return String(source);
735
867
  }
868
+ function normalizeEnum(value, allowed) {
869
+ if (null == value) return;
870
+ const normalized = String(value).trim().toLowerCase();
871
+ if (!normalized) return;
872
+ return allowed.includes(normalized) ? normalized : void 0;
873
+ }
874
+ function normalizeSourceFormatOption(params) {
875
+ const allowed = [
876
+ 'pretty',
877
+ 'json',
878
+ 'ndjson'
879
+ ];
880
+ const sourceFormat = normalizeEnum(params.sourceFormat, allowed);
881
+ if (sourceFormat) return sourceFormat;
882
+ const logFormat = normalizeEnum(params.logFormat, allowed);
883
+ if (logFormat) return logFormat;
884
+ if (params.sourceEnabled) return 'json';
885
+ }
886
+ function normalizeSourceRedactOption(sourceRedact, sourceFormat) {
887
+ const allowed = [
888
+ 'off',
889
+ 'safe',
890
+ 'strict'
891
+ ];
892
+ const normalized = normalizeEnum(sourceRedact, allowed);
893
+ if (normalized) return normalized;
894
+ if (sourceFormat && 'pretty' !== sourceFormat) return 'safe';
895
+ return 'off';
896
+ }
897
+ function normalizeSourceMaxBytesOption(value) {
898
+ if (null == value) return;
899
+ const parsed = 'number' == typeof value ? value : Number(String(value).trim());
900
+ if (!Number.isFinite(parsed) || parsed < 0) return;
901
+ return Math.floor(parsed);
902
+ }
903
+ function normalizeSourceIncludeShadowOption(value, sourceEnabled) {
904
+ const allowed = [
905
+ 'off',
906
+ 'open-only',
907
+ 'all'
908
+ ];
909
+ const normalized = normalizeEnum(value, allowed);
910
+ if (normalized) return normalized;
911
+ if (sourceEnabled) return 'open-only';
912
+ }
913
+ function normalizeSourceMetaOption(value, sourceEnabled) {
914
+ if (void 0 !== value) return 0 === String(value).trim().length ? true : Boolean(value);
915
+ if (sourceEnabled) return true;
916
+ }
917
+ function normalizeSourceTreeOption(value, sourceEnabled) {
918
+ const allowed = [
919
+ 'off',
920
+ 'root-only'
921
+ ];
922
+ const normalized = normalizeEnum(value, allowed);
923
+ if (normalized) return normalized;
924
+ }
925
+ function normalizeSourceConsoleOption(value, sourceEnabled) {
926
+ if (void 0 !== value) return 0 === String(value).trim().length ? true : Boolean(value);
927
+ }
928
+ function normalizeSourceDomOption(value, watchSource) {
929
+ if (void 0 !== value) return 0 === String(value).trim().length ? true : Boolean(value);
930
+ if (watchSource) return true;
931
+ }
932
+ function normalizeSourceProbeOption(raw) {
933
+ if (null == raw) return;
934
+ if (Array.isArray(raw)) {
935
+ const values = raw.map((value)=>String(value).trim()).filter((value)=>value.length > 0);
936
+ return values.length > 0 ? values : void 0;
937
+ }
938
+ if (0 === String(raw).trim().length) return;
939
+ const values = String(raw).split(',').map((value)=>value.trim()).filter((value)=>value.length > 0);
940
+ return values.length > 0 ? values : void 0;
941
+ }
942
+ function normalizeSourceDiffOption(value, watchSource) {
943
+ if (void 0 !== value) return 0 === String(value).trim().length ? true : Boolean(value);
944
+ if (watchSource) return true;
945
+ }
736
946
  function parseLogContexts(raw) {
737
947
  if (!raw || 0 === String(raw).trim().length) return;
738
948
  if ('all' === String(raw).trim().toLowerCase()) return;
@@ -748,9 +958,14 @@ Cross-Browser Compatibility
748
958
  const values = String(raw).split(',').map((s)=>s.trim()).filter((s)=>s.length > 0).filter((c)=>allowed.includes(c));
749
959
  return values.length > 0 ? values : void 0;
750
960
  }
961
+ function parseExtensionsList(raw) {
962
+ if (!raw || 0 === String(raw).trim().length) return;
963
+ const values = String(raw).split(',').map((value)=>value.trim()).filter((value)=>value.length > 0);
964
+ return values.length > 0 ? values : void 0;
965
+ }
751
966
  const dev_require = (0, external_module_namespaceObject.createRequire)(__rslib_import_meta_url__);
752
967
  function registerDevCommand(program, telemetry) {
753
- program.command('dev').arguments('[project-path|remote-url]').usage('dev [project-path|remote-url] [options]').description(commandDescriptions.dev).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 <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false`').option('--no-open', 'do not open the browser automatically (default: open)').option('--no-runner', 'do not launch the browser runner (dev server still starts)').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('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). 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>', '[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('--source [url]', "[experimental] opens the provided URL in Chrome and prints the full, live HTML of the page after content scripts are injected").option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--author, --author-mode', '[internal] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...devOptions }) {
968
+ program.command('dev').arguments('[project-path|remote-url]').usage('dev [project-path|remote-url] [options]').description(commandDescriptions.dev).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 <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false`').option('--no-open', 'do not open the browser automatically (default: open)').option('--no-runner', 'do not launch the browser runner (dev server still starts)').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('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). 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('--source [url]', "[experimental] opens the provided URL in Chrome and prints the full, live HTML of the page after content scripts are injected").option('--watch-source [boolean]', '[experimental] re-print HTML on rebuilds or file changes (defaults to true when --source is present)', parseOptionalBoolean).option('--source-format <pretty|json|ndjson>', '[experimental] output format for source HTML (defaults to --log-format when present, otherwise JSON when --source is used)').option('--source-summary [boolean]', '[experimental] output a compact summary instead of full HTML', parseOptionalBoolean).option('--source-meta [boolean]', '[experimental] output page metadata (readyState, viewport, frames)', parseOptionalBoolean).option('--source-probe <selectors>', '[experimental] comma-separated CSS selectors to probe').option('--source-tree <off|root-only>', '[experimental] output a compact extension root tree').option('--source-console [boolean]', '[experimental] output console summary (best-effort)', parseOptionalBoolean).option('--source-dom [boolean]', '[experimental] output DOM snapshots and diffs (default: true when watch is enabled)', parseOptionalBoolean).option('--source-max-bytes <bytes>', '[experimental] limit HTML output size in bytes (0 disables truncation)').option('--source-redact <off|safe|strict>', '[experimental] redact sensitive content in HTML output (default: safe for JSON/NDJSON)').option('--source-include-shadow <off|open-only|all>', '[experimental] control Shadow DOM inclusion in HTML output (default: open-only)').option('--source-diff [boolean]', '[experimental] include diff metadata on watch updates (default: true when watch is enabled)', parseOptionalBoolean).option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--author, --author-mode', '[internal] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...devOptions }) {
754
969
  if (devOptions.author || devOptions['authorMode']) {
755
970
  process.env.EXTENSION_AUTHOR_MODE = 'true';
756
971
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
@@ -771,8 +986,25 @@ Cross-Browser Compatibility
771
986
  const normalizedSource = normalizeSourceOption(devOptions.source, devOptions.startingUrl);
772
987
  if (normalizedSource) {
773
988
  devOptions.source = normalizedSource;
774
- devOptions.watchSource = true;
989
+ if (void 0 === devOptions.watchSource) devOptions.watchSource = true;
775
990
  }
991
+ const sourceEnabled = Boolean(devOptions.source || devOptions.watchSource);
992
+ const normalizedSourceFormat = normalizeSourceFormatOption({
993
+ sourceFormat: devOptions.sourceFormat,
994
+ logFormat: devOptions.logFormat,
995
+ sourceEnabled
996
+ });
997
+ devOptions.sourceFormat = normalizedSourceFormat;
998
+ if (sourceEnabled && normalizedSourceFormat) process.env.EXTENSION_SOURCE_FORMAT = normalizedSourceFormat;
999
+ devOptions.sourceRedact = normalizeSourceRedactOption(devOptions.sourceRedact, normalizedSourceFormat);
1000
+ devOptions.sourceMeta = normalizeSourceMetaOption(devOptions.sourceMeta, sourceEnabled);
1001
+ devOptions.sourceProbe = normalizeSourceProbeOption(devOptions.sourceProbe);
1002
+ devOptions.sourceTree = normalizeSourceTreeOption(devOptions.sourceTree, sourceEnabled);
1003
+ devOptions.sourceConsole = normalizeSourceConsoleOption(devOptions.sourceConsole, sourceEnabled);
1004
+ devOptions.sourceDom = normalizeSourceDomOption(devOptions.sourceDom, devOptions.watchSource);
1005
+ devOptions.sourceMaxBytes = normalizeSourceMaxBytesOption(devOptions.sourceMaxBytes);
1006
+ devOptions.sourceIncludeShadow = normalizeSourceIncludeShadowOption(devOptions.sourceIncludeShadow, sourceEnabled);
1007
+ devOptions.sourceDiff = normalizeSourceDiffOption(devOptions.sourceDiff, devOptions.watchSource);
776
1008
  const { extensionDev } = dev_require('extension-develop');
777
1009
  for (const vendor of list){
778
1010
  const vendorStart = Date.now();
@@ -793,8 +1025,20 @@ Cross-Browser Compatibility
793
1025
  startingUrl: devOptions.startingUrl,
794
1026
  source: devOptions.source,
795
1027
  watchSource: devOptions.watchSource,
1028
+ sourceFormat: devOptions.sourceFormat,
1029
+ sourceSummary: devOptions.sourceSummary,
1030
+ sourceMeta: devOptions.sourceMeta,
1031
+ sourceProbe: devOptions.sourceProbe,
1032
+ sourceTree: devOptions.sourceTree,
1033
+ sourceConsole: devOptions.sourceConsole,
1034
+ sourceDom: devOptions.sourceDom,
1035
+ sourceMaxBytes: devOptions.sourceMaxBytes,
1036
+ sourceRedact: devOptions.sourceRedact,
1037
+ sourceIncludeShadow: devOptions.sourceIncludeShadow,
1038
+ sourceDiff: devOptions.sourceDiff,
796
1039
  install: devOptions.install,
797
1040
  noRunner: false === devOptions.runner,
1041
+ extensions: parseExtensionsList(devOptions.extensions),
798
1042
  logLevel: logsOption || devOptions.logLevel || 'off',
799
1043
  logContexts: parseLogContexts(logContextOption),
800
1044
  logFormat: devOptions.logFormat || 'pretty',
@@ -820,7 +1064,12 @@ Cross-Browser Compatibility
820
1064
  }
821
1065
  const start_require = (0, external_module_namespaceObject.createRequire)(__rslib_import_meta_url__);
822
1066
  function registerStartCommand(program, telemetry) {
823
- program.command('start').arguments('[project-path|remote-url]').usage('start [project-path|remote-url] [options]').description(commandDescriptions.start).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 <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `true`').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--no-runner', 'do not launch the browser runner (build still runs)').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). 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>', '[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('--source [url]', "[experimental] opens the provided URL in Chrome and prints the full, live HTML of the page after content scripts are injected").option('--install [boolean]', '[experimental] install project dependencies when missing', parseOptionalBoolean).option('--author, --author-mode', '[experimental] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...startOptions }) {
1067
+ program.command('start').arguments('[project-path|remote-url]').usage('start [project-path|remote-url] [options]').description(commandDescriptions.start).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 <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `true`').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--no-runner', 'do not launch the browser runner (build still runs)').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). 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('--source [url]', "[experimental] opens the provided URL in Chrome and prints the full, live HTML of the page after content scripts are injected").option('--watch-source [boolean]', '[experimental] re-print HTML on rebuilds or file changes', parseOptionalBoolean).option('--source-format <pretty|json|ndjson>', '[experimental] output format for source HTML (defaults to --log-format when present, otherwise JSON when --source is used)').option('--source-summary [boolean]', '[experimental] output a compact summary instead of full HTML', parseOptionalBoolean).option('--source-meta [boolean]', '[experimental] output page metadata (readyState, viewport, frames)', parseOptionalBoolean).option('--source-probe <selectors>', '[experimental] comma-separated CSS selectors to probe').option('--source-tree <off|root-only>', '[experimental] output a compact extension root tree').option('--source-console [boolean]', '[experimental] output console summary (best-effort)', parseOptionalBoolean).option('--source-dom [boolean]', '[experimental] output DOM snapshots and diffs (default: true when watch is enabled)', parseOptionalBoolean).option('--source-max-bytes <bytes>', '[experimental] limit HTML output size in bytes (0 disables truncation)').option('--source-redact <off|safe|strict>', '[experimental] redact sensitive content in HTML output (default: safe for JSON/NDJSON)').option('--source-include-shadow <off|open-only|all>', '[experimental] control Shadow DOM inclusion in HTML output (default: open-only)').option('--source-diff [boolean]', '[experimental] include diff metadata on watch updates (default: true when watch is enabled)', parseOptionalBoolean).option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--install [boolean]', '[experimental] install project dependencies when missing', parseOptionalBoolean).option('--author, --author-mode', '[experimental] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...startOptions }) {
1068
+ const hasSourceInspectionFlags = void 0 !== startOptions.source || void 0 !== startOptions.watchSource || void 0 !== startOptions.sourceFormat || void 0 !== startOptions.sourceSummary || void 0 !== startOptions.sourceMeta || void 0 !== startOptions.sourceProbe || void 0 !== startOptions.sourceTree || void 0 !== startOptions.sourceConsole || void 0 !== startOptions.sourceDom || void 0 !== startOptions.sourceMaxBytes || void 0 !== startOptions.sourceRedact || void 0 !== startOptions.sourceIncludeShadow || void 0 !== startOptions.sourceDiff;
1069
+ if (hasSourceInspectionFlags) {
1070
+ console.error(sourceInspectionNotSupported('start'));
1071
+ process.exit(1);
1072
+ }
824
1073
  if (startOptions.author || startOptions.authorMode) {
825
1074
  process.env.EXTENSION_AUTHOR_MODE = 'true';
826
1075
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
@@ -835,6 +1084,25 @@ Cross-Browser Compatibility
835
1084
  validateVendorsOrExit(list, (invalid, supported)=>{
836
1085
  console.error(unsupportedBrowserFlag(invalid, supported));
837
1086
  });
1087
+ const normalizedSource = normalizeSourceOption(startOptions.source, startOptions.startingUrl);
1088
+ if (normalizedSource) startOptions.source = normalizedSource;
1089
+ const sourceEnabled = Boolean(startOptions.source || startOptions.watchSource);
1090
+ const normalizedSourceFormat = normalizeSourceFormatOption({
1091
+ sourceFormat: startOptions.sourceFormat,
1092
+ logFormat: startOptions.logFormat,
1093
+ sourceEnabled
1094
+ });
1095
+ startOptions.sourceFormat = normalizedSourceFormat;
1096
+ if (sourceEnabled && normalizedSourceFormat) process.env.EXTENSION_SOURCE_FORMAT = normalizedSourceFormat;
1097
+ startOptions.sourceRedact = normalizeSourceRedactOption(startOptions.sourceRedact, normalizedSourceFormat);
1098
+ startOptions.sourceMeta = normalizeSourceMetaOption(startOptions.sourceMeta, sourceEnabled);
1099
+ startOptions.sourceProbe = normalizeSourceProbeOption(startOptions.sourceProbe);
1100
+ startOptions.sourceTree = normalizeSourceTreeOption(startOptions.sourceTree, sourceEnabled);
1101
+ startOptions.sourceConsole = normalizeSourceConsoleOption(startOptions.sourceConsole, sourceEnabled);
1102
+ startOptions.sourceDom = normalizeSourceDomOption(startOptions.sourceDom, startOptions.watchSource);
1103
+ startOptions.sourceMaxBytes = normalizeSourceMaxBytesOption(startOptions.sourceMaxBytes);
1104
+ startOptions.sourceIncludeShadow = normalizeSourceIncludeShadowOption(startOptions.sourceIncludeShadow, sourceEnabled);
1105
+ startOptions.sourceDiff = normalizeSourceDiffOption(startOptions.sourceDiff, startOptions.watchSource);
838
1106
  const { extensionStart } = start_require('extension-develop');
839
1107
  for (const vendor of list){
840
1108
  const vendorStart = Date.now();
@@ -855,8 +1123,20 @@ Cross-Browser Compatibility
855
1123
  port: startOptions.port,
856
1124
  install: startOptions.install,
857
1125
  noRunner: false === startOptions.runner,
1126
+ extensions: parseExtensionsList(startOptions.extensions),
858
1127
  source: 'string' == typeof startOptions.source ? startOptions.source : startOptions.source,
859
1128
  watchSource: startOptions.watchSource,
1129
+ sourceFormat: startOptions.sourceFormat,
1130
+ sourceSummary: startOptions.sourceSummary,
1131
+ sourceMeta: startOptions.sourceMeta,
1132
+ sourceProbe: startOptions.sourceProbe,
1133
+ sourceTree: startOptions.sourceTree,
1134
+ sourceConsole: startOptions.sourceConsole,
1135
+ sourceDom: startOptions.sourceDom,
1136
+ sourceMaxBytes: startOptions.sourceMaxBytes,
1137
+ sourceRedact: startOptions.sourceRedact,
1138
+ sourceIncludeShadow: startOptions.sourceIncludeShadow,
1139
+ sourceDiff: startOptions.sourceDiff,
860
1140
  logLevel: logsOption || startOptions.logLevel || 'off',
861
1141
  logContexts,
862
1142
  logFormat: startOptions.logFormat || 'pretty',
@@ -881,7 +1161,12 @@ Cross-Browser Compatibility
881
1161
  }
882
1162
  const preview_require = (0, external_module_namespaceObject.createRequire)(__rslib_import_meta_url__);
883
1163
  function registerPreviewCommand(program, telemetry) {
884
- program.command('preview').arguments('[project-name]').usage('preview [path-to-remote-extension] [options]').description(commandDescriptions.preview).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 <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--no-runner', 'do not launch the browser runner').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). 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>', '[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('--source [url]', "[experimental] opens the provided URL in Chrome and prints the full, live HTML of the page after content scripts are injected").option('--author, --author-mode', '[internal] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...previewOptions }) {
1164
+ program.command('preview').arguments('[project-name]').usage('preview [path-to-remote-extension] [options]').description(commandDescriptions.preview).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 <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--chromium-binary <path-to-binary>', 'specify a path to the Chromium binary. This option overrides the --browser setting. Defaults to the system default').option('--gecko-binary, --firefox-binary <path-to-binary>', 'specify a path to the Gecko binary. This option overrides the --browser setting. Defaults to the system default').option('--starting-url <url>', 'specify the starting URL for the browser. Defaults to `undefined`').option('--no-runner', 'do not launch the browser runner').option('--port <port>', 'specify the port to use for the development server. Defaults to `8080`').option('--log-context <list>', '[experimental] comma-separated contexts to include (background,content,page,sidebar,popup,options,devtools). 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('--source [url]', "[experimental] opens the provided URL in Chrome and prints the full, live HTML of the page after content scripts are injected").option('--watch-source [boolean]', '[experimental] re-print HTML on rebuilds or file changes', parseOptionalBoolean).option('--source-format <pretty|json|ndjson>', '[experimental] output format for source HTML (defaults to --log-format when present, otherwise JSON when --source is used)').option('--source-summary [boolean]', '[experimental] output a compact summary instead of full HTML', parseOptionalBoolean).option('--source-meta [boolean]', '[experimental] output page metadata (readyState, viewport, frames)', parseOptionalBoolean).option('--source-probe <selectors>', '[experimental] comma-separated CSS selectors to probe').option('--source-tree <off|root-only>', '[experimental] output a compact extension root tree').option('--source-console [boolean]', '[experimental] output console summary (best-effort)', parseOptionalBoolean).option('--source-dom [boolean]', '[experimental] output DOM snapshots and diffs (default: true when watch is enabled)', parseOptionalBoolean).option('--source-max-bytes <bytes>', '[experimental] limit HTML output size in bytes (0 disables truncation)').option('--source-redact <off|safe|strict>', '[experimental] redact sensitive content in HTML output (default: safe for JSON/NDJSON)').option('--source-include-shadow <off|open-only|all>', '[experimental] control Shadow DOM inclusion in HTML output (default: open-only)').option('--source-diff [boolean]', '[experimental] include diff metadata on watch updates (default: true when watch is enabled)', parseOptionalBoolean).option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--author, --author-mode', '[internal] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...previewOptions }) {
1165
+ const hasSourceInspectionFlags = void 0 !== previewOptions.source || void 0 !== previewOptions.watchSource || void 0 !== previewOptions.sourceFormat || void 0 !== previewOptions.sourceSummary || void 0 !== previewOptions.sourceMeta || void 0 !== previewOptions.sourceProbe || void 0 !== previewOptions.sourceTree || void 0 !== previewOptions.sourceConsole || void 0 !== previewOptions.sourceDom || void 0 !== previewOptions.sourceMaxBytes || void 0 !== previewOptions.sourceRedact || void 0 !== previewOptions.sourceIncludeShadow || void 0 !== previewOptions.sourceDiff;
1166
+ if (hasSourceInspectionFlags) {
1167
+ console.error(sourceInspectionNotSupported('preview'));
1168
+ process.exit(1);
1169
+ }
885
1170
  if (previewOptions.author || previewOptions['authorMode']) {
886
1171
  process.env.EXTENSION_AUTHOR_MODE = 'true';
887
1172
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
@@ -899,6 +1184,25 @@ Cross-Browser Compatibility
899
1184
  const isRemote = 'string' == typeof pathOrRemoteUrl && /^https?:/i.test(pathOrRemoteUrl);
900
1185
  if (isRemote) process.env.EXTJS_LIGHT = '1';
901
1186
  }
1187
+ const normalizedSource = normalizeSourceOption(previewOptions.source, previewOptions.startingUrl);
1188
+ if (normalizedSource) previewOptions.source = normalizedSource;
1189
+ const sourceEnabled = Boolean(previewOptions.source || previewOptions.watchSource);
1190
+ const normalizedSourceFormat = normalizeSourceFormatOption({
1191
+ sourceFormat: previewOptions.sourceFormat,
1192
+ logFormat: previewOptions.logFormat,
1193
+ sourceEnabled
1194
+ });
1195
+ previewOptions.sourceFormat = normalizedSourceFormat;
1196
+ if (sourceEnabled && normalizedSourceFormat) process.env.EXTENSION_SOURCE_FORMAT = normalizedSourceFormat;
1197
+ previewOptions.sourceRedact = normalizeSourceRedactOption(previewOptions.sourceRedact, normalizedSourceFormat);
1198
+ previewOptions.sourceMeta = normalizeSourceMetaOption(previewOptions.sourceMeta, sourceEnabled);
1199
+ previewOptions.sourceProbe = normalizeSourceProbeOption(previewOptions.sourceProbe);
1200
+ previewOptions.sourceTree = normalizeSourceTreeOption(previewOptions.sourceTree, sourceEnabled);
1201
+ previewOptions.sourceConsole = normalizeSourceConsoleOption(previewOptions.sourceConsole, sourceEnabled);
1202
+ previewOptions.sourceDom = normalizeSourceDomOption(previewOptions.sourceDom, previewOptions.watchSource);
1203
+ previewOptions.sourceMaxBytes = normalizeSourceMaxBytesOption(previewOptions.sourceMaxBytes);
1204
+ previewOptions.sourceIncludeShadow = normalizeSourceIncludeShadowOption(previewOptions.sourceIncludeShadow, sourceEnabled);
1205
+ previewOptions.sourceDiff = normalizeSourceDiffOption(previewOptions.sourceDiff, previewOptions.watchSource);
902
1206
  const { extensionPreview } = preview_require('extension-develop');
903
1207
  for (const vendor of list){
904
1208
  const vendorStart = Date.now();
@@ -918,8 +1222,20 @@ Cross-Browser Compatibility
918
1222
  startingUrl: previewOptions.startingUrl,
919
1223
  port: previewOptions.port,
920
1224
  noRunner: false === previewOptions.runner,
1225
+ extensions: parseExtensionsList(previewOptions.extensions),
921
1226
  source: 'string' == typeof previewOptions.source ? previewOptions.source : previewOptions.source,
922
1227
  watchSource: previewOptions.watchSource,
1228
+ sourceFormat: previewOptions.sourceFormat,
1229
+ sourceSummary: previewOptions.sourceSummary,
1230
+ sourceMeta: previewOptions.sourceMeta,
1231
+ sourceProbe: previewOptions.sourceProbe,
1232
+ sourceTree: previewOptions.sourceTree,
1233
+ sourceConsole: previewOptions.sourceConsole,
1234
+ sourceDom: previewOptions.sourceDom,
1235
+ sourceMaxBytes: previewOptions.sourceMaxBytes,
1236
+ sourceRedact: previewOptions.sourceRedact,
1237
+ sourceIncludeShadow: previewOptions.sourceIncludeShadow,
1238
+ sourceDiff: previewOptions.sourceDiff,
923
1239
  logLevel: logsOption || previewOptions.logLevel || 'off',
924
1240
  logContexts,
925
1241
  logFormat: previewOptions.logFormat || 'pretty',
@@ -943,7 +1259,7 @@ Cross-Browser Compatibility
943
1259
  });
944
1260
  }
945
1261
  function registerBuildCommand(program, telemetry) {
946
- program.command('build').arguments('[project-name]').usage('build [path-to-remote-extension] [options]').description(commandDescriptions.build).option('--browser <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false`').option('--zip [boolean]', 'whether or not to compress the extension into a ZIP file. Defaults to `false`').option('--zip-source [boolean]', 'whether or not to include the source files in the ZIP file. Defaults to `false`').option('--zip-filename <string>', 'specify the name of the ZIP file. Defaults to the extension name and version').option('--silent [boolean]', 'whether or not to open the browser automatically. Defaults to `false`').option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--author, --author-mode', '[internal] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...buildOptions }) {
1262
+ program.command('build').arguments('[project-name]').usage('build [path-to-remote-extension] [options]').description(commandDescriptions.build).option('--browser <chrome | chromium | edge | firefox | chromium-based | gecko-based | firefox-based>', 'specify a browser/engine to run. Defaults to `chromium`').option('--polyfill [boolean]', 'whether or not to apply the cross-browser polyfill. Defaults to `false`').option('--zip [boolean]', 'whether or not to compress the extension into a ZIP file. Defaults to `false`').option('--zip-source [boolean]', 'whether or not to include the source files in the ZIP file. Defaults to `false`').option('--zip-filename <string>', 'specify the name of the ZIP file. Defaults to the extension name and version').option('--silent [boolean]', 'whether or not to open the browser automatically. Defaults to `false`').option('--install [boolean]', '[internal] install project dependencies when missing', parseOptionalBoolean).option('--extensions <list>', 'comma-separated list of companion extensions or store URLs to load').option('--author, --author-mode', '[internal] enable maintainer diagnostics (does not affect user runtime logs)').action(async function(pathOrRemoteUrl, { browser = 'chromium', ...buildOptions }) {
947
1263
  if (buildOptions.author || buildOptions['authorMode']) {
948
1264
  process.env.EXTENSION_AUTHOR_MODE = 'true';
949
1265
  if (!process.env.EXTENSION_VERBOSE) process.env.EXTENSION_VERBOSE = '1';
@@ -974,7 +1290,8 @@ Cross-Browser Compatibility
974
1290
  zipSource: buildOptions.zipSource,
975
1291
  zipFilename: buildOptions.zipFilename,
976
1292
  silent: buildOptions.silent,
977
- install: buildOptions.install
1293
+ install: buildOptions.install,
1294
+ extensions: parseExtensionsList(buildOptions.extensions)
978
1295
  });
979
1296
  telemetry.track('cli_build_summary', {
980
1297
  ...buildSummary
@@ -1003,19 +1320,35 @@ Cross-Browser Compatibility
1003
1320
  }
1004
1321
  }
1005
1322
  process.env.EXTENSION_DEVELOP_VERSION = developVersion();
1323
+ function resolveAIHelpFormatFromArgv(argv) {
1324
+ const equalArg = argv.find((arg)=>arg.startsWith('--format='));
1325
+ if (equalArg) return equalArg.slice(9);
1326
+ const formatIndex = argv.indexOf('--format');
1327
+ if (formatIndex >= 0) return argv[formatIndex + 1] || '';
1328
+ return 'pretty';
1329
+ }
1006
1330
  check_updates_checkUpdates().then((updateMessage)=>{
1007
1331
  if (!updateMessage) return;
1008
1332
  if ('true' === process.env.EXTENSION_CLI_BANNER_PRINTED) return void console.log(updateMessage.message);
1009
1333
  process.env.EXTENSION_CLI_UPDATE_SUFFIX = updateMessage.suffix;
1010
1334
  });
1011
1335
  const extensionJs = external_commander_namespaceObject.program;
1012
- extensionJs.name(cliPackageJson.name).description(cliPackageJson.description).version(cliPackageJson.version).option('--no-telemetry', 'disable anonymous telemetry for this run').option('--ai-help', 'show AI-assistant oriented help and tips').addHelpText('after', programUserHelp()).showHelpAfterError(true).showSuggestionAfterError(true);
1336
+ extensionJs.name(cliPackageJson.name).description(cliPackageJson.description).version(cliPackageJson.version).option('--no-telemetry', 'disable anonymous telemetry for this run').option('--ai-help', 'show AI-assistant oriented help and tips').option('--format <pretty|json>', 'output format for --ai-help', 'pretty').addHelpText('after', programUserHelp()).showHelpAfterError(true).showSuggestionAfterError(true);
1013
1337
  registerCreateCommand(extensionJs, telemetry_cli_telemetry);
1014
1338
  registerDevCommand(extensionJs, telemetry_cli_telemetry);
1015
1339
  registerStartCommand(extensionJs, telemetry_cli_telemetry);
1016
1340
  registerPreviewCommand(extensionJs, telemetry_cli_telemetry);
1017
1341
  registerBuildCommand(extensionJs, telemetry_cli_telemetry);
1018
1342
  extensionJs.on('option:ai-help', function() {
1343
+ const format = resolveAIHelpFormatFromArgv(process.argv).trim().toLowerCase();
1344
+ if ('json' === format) {
1345
+ console.log(JSON.stringify(programAIHelpJSON(cliPackageJson.version), null, 2));
1346
+ process.exit(0);
1347
+ }
1348
+ if ('pretty' !== format) {
1349
+ console.error(invalidAIHelpFormat(format));
1350
+ process.exit(1);
1351
+ }
1019
1352
  console.log(programAIHelp());
1020
1353
  process.exit(0);
1021
1354
  });
@@ -1,2 +1,22 @@
1
1
  export declare function normalizeSourceOption(source: boolean | string | undefined, startingUrl?: string): string | undefined;
2
+ export type SourceFormat = 'pretty' | 'json' | 'ndjson';
3
+ export type SourceRedact = 'off' | 'safe' | 'strict';
4
+ export type SourceIncludeShadow = 'off' | 'open-only' | 'all';
5
+ export type SourceTreeMode = 'off' | 'root-only';
6
+ export type SourceDomMode = 'off' | 'on';
7
+ export declare function normalizeSourceFormatOption(params: {
8
+ sourceFormat?: string;
9
+ logFormat?: string;
10
+ sourceEnabled?: boolean;
11
+ }): SourceFormat | undefined;
12
+ export declare function normalizeSourceRedactOption(sourceRedact: string | undefined, sourceFormat: SourceFormat | undefined): SourceRedact;
13
+ export declare function normalizeSourceMaxBytesOption(value: string | number | undefined): number | undefined;
14
+ export declare function normalizeSourceIncludeShadowOption(value: string | undefined, sourceEnabled: boolean): SourceIncludeShadow | undefined;
15
+ export declare function normalizeSourceMetaOption(value: boolean | string | undefined, sourceEnabled: boolean): boolean | undefined;
16
+ export declare function normalizeSourceTreeOption(value: string | undefined, sourceEnabled: boolean): SourceTreeMode | undefined;
17
+ export declare function normalizeSourceConsoleOption(value: boolean | string | undefined, sourceEnabled: boolean): boolean | undefined;
18
+ export declare function normalizeSourceDomOption(value: boolean | string | undefined, watchSource: boolean | undefined): boolean | undefined;
19
+ export declare function normalizeSourceProbeOption(raw: string | string[] | undefined): string[] | undefined;
20
+ export declare function normalizeSourceDiffOption(value: boolean | string | undefined, watchSource: boolean | undefined): boolean | undefined;
2
21
  export declare function parseLogContexts(raw: string | undefined): Array<'background' | 'content' | 'page' | 'sidebar' | 'popup' | 'options' | 'devtools'> | undefined;
22
+ export declare function parseExtensionsList(raw: string | undefined): string[] | undefined;
package/package.json CHANGED
@@ -33,7 +33,7 @@
33
33
  "extension": "./bin/extension.cjs"
34
34
  },
35
35
  "name": "extension",
36
- "version": "3.5.0",
36
+ "version": "3.6.0",
37
37
  "description": "Create cross-browser extensions with no build configuration.",
38
38
  "homepage": "https://extension.js.org/",
39
39
  "bugs": {
@@ -90,8 +90,8 @@
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.5.0",
94
- "extension-develop": "^3.5.0",
93
+ "extension-create": "^3.6.0",
94
+ "extension-develop": "^3.6.0",
95
95
  "commander": "^14.0.3",
96
96
  "pintor": "0.3.0",
97
97
  "semver": "^7.7.3",