dembrandt 0.3.0 β†’ 0.5.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.
package/README.md CHANGED
@@ -1,420 +1,123 @@
1
- # 🎨 Dembrandt
1
+ # Dembrandt.
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/dembrandt.svg)](https://www.npmjs.com/package/dembrandt)
4
4
  [![npm downloads](https://img.shields.io/npm/dm/dembrandt.svg)](https://www.npmjs.com/package/dembrandt)
5
- [![license](https://img.shields.io/npm/l/dembrandt.svg)](https://github.com/thevangelist/dembrandt/blob/main/LICENSE)
5
+ [![license](https://img.shields.io/npm/l/dembrandt.svg)](https://github.com/dembrandt/dembrandt/blob/main/LICENSE)
6
6
 
7
- A CLI tool for extracting design tokens and brand assets from any website. Powered by Playwright with advanced bot detection avoidance.
7
+ Extract any website’s design system into design tokens in a few seconds: logo, colors, typography, borders, and more. One command.
8
8
 
9
9
  ![Dembrandt Demo](showcase.png)
10
10
 
11
- ## Quick Start
11
+ ## Install
12
12
 
13
13
  ```bash
14
- npx dembrandt stripe.com
14
+ npx dembrandt bmw.de
15
15
  ```
16
16
 
17
- No installation required! Extract design tokens from any website in seconds. Or install globally with `npm install -g dembrandt`.
17
+ Or install globally: `npm install -g dembrandt` then run `dembrandt bmw.de`
18
18
 
19
- ## What It Does
19
+ Requires Node.js 18+
20
20
 
21
- Dembrandt analyzes live websites and extracts their complete design system:
21
+ ## What to expect from extraction?
22
22
 
23
- - **Logo** β€” Logo detection (img/svg) with dimensions and source URL
24
- - **Favicons** β€” All favicon variants with sizes and types
25
- - **Colors** β€” Semantic colors, color palette with confidence scoring, CSS variables (both hex and RGB formats)
26
- - **Typography** β€” Font families, sizes, weights, line heights, font sources (Google Fonts, Adobe Fonts, custom)
27
- - **Spacing** β€” Margin and padding scales with grid system detection (4px/8px/custom)
28
- - **Border Radius** β€” Corner radius patterns with usage frequency
29
- - **Borders** β€” Border widths, styles (solid, dashed, dotted), and colors with confidence scoring
30
- - **Shadows** β€” Box shadow values for elevation systems
31
- - **Buttons** β€” Component styles with variants and states
32
- - **Inputs** β€” Form field styles (input, textarea, select)
33
- - **Links** β€” Link styles with hover states and decorations
34
- - **Breakpoints** β€” Responsive design breakpoints from media queries
35
- - **Icons** β€” Icon system detection (Font Awesome, Material Icons, SVG)
36
- - **Frameworks** β€” CSS framework detection (Tailwind, Bootstrap, Material-UI, Chakra)
37
-
38
- Perfect for competitive analysis, brand audits, or rebuilding a brand when you don't have design guidelines.
39
-
40
- ## Why It Matters
41
-
42
- **Designers** β€” Analyze competitor systems, document production tokens, audit brand consistency
43
-
44
- **Developers** β€” Migrate design tokens, reverse engineer components, validate implementations
45
-
46
- **Product Managers** β€” Track competitor evolution, quantify design debt, evaluate vendors
47
-
48
- **Marketing** β€” Audit competitor brands, plan rebrands, monitor brand compliance
49
-
50
- **Engineering Leaders** β€” Measure technical debt, plan migrations, assess acquisition targets
51
-
52
- ## How It Works
53
-
54
- Uses Playwright to render the page, extracts computed styles from the DOM, analyzes color usage and confidence, groups similar typography, detects spacing patterns, and returns actionable design tokens.
55
-
56
- ### Extraction Process
57
-
58
- 1. **Browser Launch** - Launches Chromium with stealth configuration
59
- 2. **Anti-Detection** - Injects scripts to bypass bot detection
60
- 3. **Navigation** - Navigates to target URL with retry logic
61
- 4. **Hydration** - Waits for SPAs to fully load (8s initial + 4s stabilization)
62
- 5. **Content Validation** - Verifies page content is substantial (>500 chars)
63
- 6. **Parallel Extraction** - Runs all extractors concurrently for speed
64
- 7. **Analysis** - Analyzes computed styles, DOM structure, and CSS variables
65
- 8. **Scoring** - Assigns confidence scores based on context and usage
66
-
67
- ### Color Confidence
68
-
69
- - **High** β€” Logo, brand elements, primary buttons
70
- - **Medium** β€” Interactive elements, icons, navigation
71
- - **Low** β€” Generic UI components (filtered from display)
72
-
73
- Only shows high and medium confidence colors in terminal. Full palette in JSON.
74
-
75
- ### Typography Detection
76
-
77
- Samples all heading levels (h1-h6), body text, buttons, links. Groups by font family, size, and weight. Detects Google Fonts, Adobe Fonts, custom @font-face.
78
-
79
- ### Framework Detection
80
-
81
- Recognizes Tailwind CSS, Bootstrap, Material-UI, and others by class patterns and CDN links.
82
-
83
- ## Installation
84
-
85
- ### Using npx (Recommended)
86
-
87
- No installation needed! Run directly with `npx`:
88
-
89
- ```bash
90
- npx dembrandt stripe.com
91
- ```
92
-
93
- The first run will automatically install Chromium (~170MB).
94
-
95
- ### Global Installation
96
-
97
- Install globally for repeated use:
98
-
99
- ```bash
100
- npm install -g dembrandt
101
- dembrandt stripe.com
102
- ```
103
-
104
- ### Prerequisites
105
-
106
- - Node.js 18 or higher
107
-
108
- ### Development Setup
109
-
110
- For contributors who want to work on dembrandt:
111
-
112
- ```bash
113
- git clone https://github.com/thevangelist/dembrandt.git
114
- cd dembrandt
115
- npm install
116
- npm link
117
- ```
23
+ - Colors (semantic, palette, CSS variables)
24
+ - Typography (fonts, sizes, weights, sources)
25
+ - Spacing (margin/padding scales)
26
+ - Borders (radius, widths, styles, colors)
27
+ - Shadows
28
+ - Components (buttons, badges, inputs, links)
29
+ - Breakpoints
30
+ - Icons & frameworks
118
31
 
119
32
  ## Usage
120
33
 
121
- ### Basic Usage
122
-
123
34
  ```bash
124
- # Using npx (no installation)
125
- npx dembrandt <url>
126
-
127
- # Or if installed globally
128
- dembrandt <url>
129
-
130
- # Examples
131
- dembrandt stripe.com
132
- dembrandt https://github.com
133
- dembrandt tailwindcss.com
35
+ dembrandt <url> # Basic extraction (terminal display only)
36
+ dembrandt bmw.de --json-only # Output raw JSON to terminal (no formatted display, no file save)
37
+ dembrandt bmw.de --save-output # Save JSON to output/bmw.de/YYYY-MM-DDTHH-MM-SS.json
38
+ dembrandt bmw.de --dtcg # Export in W3C Design Tokens (DTCG) format (auto-saves as .tokens.json)
39
+ dembrandt bmw.de --dark-mode # Extract colors from dark mode variant
40
+ dembrandt bmw.de --mobile # Use mobile viewport (390x844, iPhone 12/13/14/15) for responsive analysis
41
+ dembrandt bmw.de --slow # 3x longer timeouts (24s hydration) for JavaScript-heavy sites
42
+ dembrandt bmw.de --no-sandbox # Disable Chromium sandbox (required for Docker/CI)
134
43
  ```
135
44
 
136
- ### Options
45
+ Default: formatted terminal display only. Use `--save-output` to persist results as JSON files. Browser automatically retries in visible mode if headless extraction fails.
137
46
 
138
- **`--json-only`** - Output raw JSON to stdout instead of formatted terminal display
47
+ ### W3C Design Tokens (DTCG) Format
139
48
 
140
- ```bash
141
- dembrandt stripe.com --json-only > tokens.json
142
- ```
143
-
144
- Note: JSON is automatically saved to `output/domain.com/` regardless of this flag.
145
-
146
- **`-d, --debug`** - Run with visible browser and detailed logs
147
-
148
- ```bash
149
- dembrandt stripe.com --debug
150
- ```
151
-
152
- Useful for troubleshooting bot detection, timeouts, or extraction issues.
153
-
154
- **`--verbose-colors`** - Show medium and low confidence colors in terminal output
49
+ Use `--dtcg` to export in the standardized [W3C Design Tokens Community Group](https://www.designtokens.org/) format:
155
50
 
156
51
  ```bash
157
- dembrandt stripe.com --verbose-colors
52
+ dembrandt stripe.com --dtcg
53
+ # Saves to: output/stripe.com/TIMESTAMP.tokens.json
158
54
  ```
159
55
 
160
- By default, only high-confidence colors are shown. Use this flag to see all detected colors.
161
-
162
- **`--dark-mode`** - Extract colors from dark mode
56
+ Transform DTCG tokens to platform-specific formats using [Style Dictionary](https://styledictionary.com):
163
57
 
164
58
  ```bash
165
- dembrandt stripe.com --dark-mode
59
+ # Generate CSS variables, SCSS, JavaScript, TypeScript
60
+ npm run build:tokens
166
61
  ```
167
62
 
168
- Enables dark mode preference detection for sites that support it.
169
-
170
- **`--mobile`** - Extract from mobile viewport
171
-
172
- ```bash
173
- dembrandt stripe.com --mobile
174
- ```
175
-
176
- Simulates a mobile device viewport for responsive design token extraction.
177
-
178
- **`--slow`** - Use 3x longer timeouts for slow-loading sites
179
-
180
- ```bash
181
- dembrandt linkedin.com --slow
182
- ```
183
-
184
- Helpful for sites with heavy JavaScript, complex SPAs, or aggressive bot detection that need extra time to fully load.
185
-
186
- ## Output
187
-
188
- ### Automatic JSON Saves
189
-
190
- Every extraction is automatically saved to `output/domain.com/YYYY-MM-DDTHH-MM-SS.json` with:
191
-
192
- - Complete design token data
193
- - Timestamped for version tracking
194
- - Organized by domain
195
-
196
- Example: `output/stripe.com/2025-11-22T14-30-45.json`
197
-
198
- ### Terminal Output
199
-
200
- Clean, formatted tables showing:
201
-
202
- - Color palette with confidence ratings (with visual swatches)
203
- - CSS variables with color previews
204
- - Typography hierarchy with context
205
- - Spacing scale (4px/8px grid detection)
206
- - Shadow system
207
- - Button variants
208
- - Component style breakdowns
209
- - Framework and icon system detection
210
-
211
- ### JSON Output Format
212
-
213
- Complete extraction data for programmatic use:
214
-
215
- ```json
216
- {
217
- "url": "https://example.com",
218
- "extractedAt": "2025-11-22T...",
219
- "logo": { "source": "img", "url": "...", "width": 120, "height": 40 },
220
- "colors": {
221
- "semantic": { "primary": "#3b82f6", ... },
222
- "palette": [{ "color": "#3b82f6", "confidence": "high", "count": 45, "sources": [...] }],
223
- "cssVariables": { "--color-primary": "#3b82f6", ... }
224
- },
225
- "typography": {
226
- "styles": [{ "fontFamily": "Inter", "fontSize": "16px", "fontWeight": "400", ... }],
227
- "sources": { "googleFonts": [...], "adobeFonts": false, "customFonts": [...] }
228
- },
229
- "spacing": { "scaleType": "8px", "commonValues": [{ "px": "16px", "rem": "1rem", "count": 42 }, ...] },
230
- "borderRadius": { "values": [{ "value": "8px", "count": 15, "confidence": "high" }, ...] },
231
- "shadows": [{ "shadow": "0 2px 4px rgba(0,0,0,0.1)", "count": 8, "confidence": "high" }, ...],
232
- "components": {
233
- "buttons": [{ "backgroundColor": "...", "color": "...", "padding": "...", ... }],
234
- "inputs": [{ "type": "input", "border": "...", "borderRadius": "...", ... }]
235
- },
236
- "breakpoints": [{ "px": "768px" }, ...],
237
- "iconSystem": [{ "name": "Font Awesome", "type": "icon-font" }, ...],
238
- "frameworks": [{ "name": "Tailwind CSS", "confidence": "high", "evidence": "class patterns" }]
239
- }
240
- ```
241
-
242
- ## Examples
243
-
244
- ### Extract Design Tokens
245
-
246
- ```bash
247
- # Analyze a single site (auto-saves JSON to output/stripe.com/)
248
- dembrandt stripe.com
249
-
250
- # View saved JSON files
251
- ls output/stripe.com/
252
-
253
- # Output to stdout for piping
254
- dembrandt stripe.com --json-only | jq '.colors.semantic'
255
-
256
- # Debug mode for difficult sites
257
- dembrandt example.com --debug
258
- ```
259
-
260
- ### Compare Competitors
261
-
262
- ```bash
263
- # Extract tokens from multiple competitors (auto-saved to output/)
264
- for site in stripe.com square.com paypal.com; do
265
- dembrandt $site
266
- done
267
-
268
- # Compare color palettes from most recent extractions
269
- jq '.colors.palette[] | select(.confidence=="high")' output/stripe.com/2025-11-22T*.json output/square.com/2025-11-22T*.json
270
-
271
- # Compare semantic colors across competitors
272
- jq '.colors.semantic' output/*/2025-11-22T*.json
273
- ```
274
-
275
- ### Integration with Design Tools
276
-
277
- ```bash
278
- # Extract and convert to custom config format
279
- dembrandt mysite.com --json-only | jq '{
280
- colors: .colors.semantic,
281
- fontFamily: .typography.sources,
282
- spacing: .spacing.commonValues
283
- }' > design-tokens.json
284
-
285
- # Or use the built-in Tailwind CSS exporter (see lib/exporters.js)
286
- # Converts extracted tokens to Tailwind config format
287
- ```
63
+ Outputs CSS custom properties, SCSS variables, ES6 modules, and TypeScript definitions. See [STYLE-DICTIONARY.md](STYLE-DICTIONARY.md) for details.
288
64
 
289
65
  ## Use Cases
290
66
 
291
- ### Brand Audits
292
-
293
- Extract and document your company's current design system from production websites.
294
-
295
- ### Competitive Analysis
296
-
297
- Compare design systems across competitors to identify trends and opportunities.
298
-
299
- ### Design System Migration
67
+ - Brand audits & competitive analysis
68
+ - Design system documentation
69
+ - Reverse engineering brands
70
+ - Multi-site brand consolidation
300
71
 
301
- Document legacy design tokens before migrating to a new system.
302
-
303
- ### Reverse Engineering
304
-
305
- Rebuild a brand when original design guidelines are unavailable.
306
-
307
- ### Quality Assurance
308
-
309
- Verify design consistency across different pages and environments.
310
-
311
- ## Advanced Features
312
-
313
- ### Bot Detection Avoidance
314
-
315
- - Stealth mode with anti-detection scripts
316
- - Automatic fallback to visible browser on detection
317
- - Human-like interaction simulation (mouse movement, scrolling)
318
- - Custom user agent and browser fingerprinting
319
-
320
- ### Smart Retry Logic
321
-
322
- - Automatic retry on navigation failures (up to 2 attempts)
323
- - SPA hydration detection and waiting
324
- - Content validation to ensure page is fully loaded
325
- - Detailed progress logging at each step
326
-
327
- ### Comprehensive Logging
328
-
329
- - Real-time spinner with step-by-step progress
330
- - Detailed extraction metrics (colors found, styles detected, etc.)
331
- - Error context with URL, stage, and attempt information
332
- - Debug mode with full stack traces
333
-
334
- ## Troubleshooting
335
-
336
- ### Bot Detection Issues
337
-
338
- If you encounter timeouts or network errors:
339
-
340
- ```bash
341
- dembrandt example.com --debug
342
- ```
343
-
344
- This will automatically retry with a visible browser.
345
-
346
- ### Page Not Loading
347
-
348
- Some sites require longer load times. The tool waits 8 seconds for SPA hydration, but you can modify this in the source.
72
+ ## How It Works
349
73
 
350
- ### Empty Content
74
+ Uses Playwright to render the page, extracts computed styles from the DOM, analyzes color usage and confidence, groups similar typography, detects spacing patterns, and returns actionable design tokens.
351
75
 
352
- If content length is < 500 chars, the tool will automatically retry (up to 2 attempts).
76
+ ### Extraction Process
353
77
 
354
- ### Debug Mode
78
+ 1. Browser Launch - Launches Chromium with stealth configuration
79
+ 2. Anti-Detection - Injects scripts to bypass bot detection
80
+ 3. Navigation - Navigates to target URL with retry logic
81
+ 4. Hydration - Waits for SPAs to fully load (8s initial + 4s stabilization)
82
+ 5. Content Validation - Verifies page content is substantial (>500 chars)
83
+ 6. Parallel Extraction - Runs all extractors concurrently for speed
84
+ 7. Analysis - Analyzes computed styles, DOM structure, and CSS variables
85
+ 8. Scoring - Assigns confidence scores based on context and usage
355
86
 
356
- Use `--debug` to see:
87
+ ### Color Confidence
357
88
 
358
- - Browser launch confirmation
359
- - Step-by-step progress logs
360
- - Full error stack traces
361
- - Extraction metrics
89
+ - High β€” Logo, brand elements, primary buttons
90
+ - Medium β€” Interactive elements, icons, navigation
91
+ - Low β€” Generic UI components (filtered from display)
92
+ - Only shows high and medium confidence colors in terminal. Full palette in JSON.
362
93
 
363
94
  ## Limitations
364
95
 
365
- - Dark mode requires `--dark-mode` flag (not automatically detected)
96
+ - Dark mode requires --dark-mode flag (not automatically detected)
366
97
  - Hover/focus states extracted from CSS (not fully interactive)
367
98
  - Canvas/WebGL-rendered sites cannot be analyzed (e.g., Tesla, Apple Vision Pro demos)
368
99
  - JavaScript-heavy sites require hydration time (8s initial + 4s stabilization)
369
100
  - Some dynamically-loaded content may be missed
370
- - Default viewport is 1920x1080 (use `--mobile` for responsive analysis)
371
-
372
- ## Architecture
373
-
374
- ```
375
- dembrandt/
376
- β”œβ”€β”€ index.js # CLI entry point, command handling
377
- β”œβ”€β”€ lib/
378
- β”‚ β”œβ”€β”€ extractors.js # Core extraction logic with stealth mode
379
- β”‚ β”œβ”€β”€ display.js # Terminal output formatting
380
- β”‚ └── exporters.js # Export to Tailwind CSS config (NEW)
381
- β”œβ”€β”€ output/ # Auto-saved JSON extractions (gitignored)
382
- β”‚ β”œβ”€β”€ stripe.com/
383
- β”‚ β”‚ β”œβ”€β”€ 2025-11-22T14-30-45.json
384
- β”‚ β”‚ └── 2025-11-22T15-12-33.json
385
- β”‚ └── github.com/
386
- β”‚ └── 2025-11-22T14-35-12.json
387
- β”œβ”€β”€ package.json
388
- └── README.md
389
- ```
101
+ - Default viewport is 1920x1080 (use --mobile for 390x844 iPhone viewport)
390
102
 
391
103
  ## Ethics & Legality
392
104
 
393
105
  Dembrandt extracts publicly available design information (colors, fonts, spacing) from website DOMs for analysis purposes. This falls under fair use in most jurisdictions (USA's DMCA Β§ 1201(f), EU Software Directive 2009/24/EC) when used for competitive analysis, documentation, or learning.
394
106
 
395
- **Legal:** Analyzing public HTML/CSS is generally legal. Does not bypass protections or violate copyright. Check site ToS before mass extraction.
107
+ Legal: Analyzing public HTML/CSS is generally legal. Does not bypass protections or violate copyright. Check site ToS before mass extraction.
396
108
 
397
- **Ethical:** Use for inspiration and analysis, not direct copying. Respect servers (no mass crawling), give credit to sources, be transparent about data origin.
109
+ Ethical: Use for inspiration and analysis, not direct copying. Respect servers (no mass crawling), give credit to sources, be transparent about data origin.
398
110
 
399
111
  ## Contributing
400
112
 
401
- Issues and pull requests welcome. Please include:
113
+ Bugs you found? Weird websites that make it cry? Pull requests (even one-liners make me happy)?
402
114
 
403
- - Clear description of the issue/feature
404
- - Example URLs that demonstrate the problem
405
- - Expected vs actual behavior
115
+ Spam me in [Issues](https://github.com/dembrandt/dembrandt/issues) or PRs. I reply to everything.
406
116
 
407
- ## License
117
+ Let's keep the light alive together.
408
118
 
409
- MIT
119
+ @thevangelist
410
120
 
411
- ## Roadmap
121
+ ---
412
122
 
413
- - [x] Dark mode extraction (via `--dark-mode` flag)
414
- - [x] Mobile viewport support (via `--mobile` flag)
415
- - [x] Clickable terminal links for modern terminals
416
- - [?] Figma integration branch: `figma-integration`
417
- - [ ] Animation/transition detection
418
- - [ ] Interactive state capture (hover, focus, active)
419
- - [ ] Multi-page analysis
420
- - [ ] Configuration file support
123
+ MIT β€” do whatever you want with it.
package/index.js CHANGED
@@ -10,55 +10,49 @@
10
10
  import { program } from "commander";
11
11
  import chalk from "chalk";
12
12
  import ora from "ora";
13
- import { chromium } from "playwright";
13
+ import { chromium } from "playwright-core";
14
14
  import { extractBranding } from "./lib/extractors.js";
15
15
  import { displayResults } from "./lib/display.js";
16
+ import { toW3CFormat } from "./lib/w3c-exporter.js";
16
17
  import { writeFileSync, mkdirSync } from "fs";
17
18
  import { join } from "path";
18
19
 
19
20
  program
20
21
  .name("dembrandt")
21
22
  .description("Extract design tokens from any website")
22
- .version("1.0.0")
23
+ .version("0.5.0")
23
24
  .argument("<url>")
24
25
  .option("--json-only", "Output raw JSON")
25
- .option("-d, --debug", "Force visible browser")
26
- .option("--verbose-colors", "Show medium and low confidence colors")
26
+ .option("--save-output", "Save JSON file to output folder")
27
+ .option("--dtcg", "Export in W3C Design Tokens (DTCG) format")
27
28
  .option("--dark-mode", "Extract colors from dark mode")
28
29
  .option("--mobile", "Extract from mobile viewport")
29
30
  .option("--slow", "3x longer timeouts for slow-loading sites")
31
+ .option("--no-sandbox", "Disable browser sandbox (needed for Docker/CI)")
30
32
  .action(async (input, opts) => {
31
33
  let url = input;
32
- if (!url.match(/^https?:\/\//)) url = "https://" + url;
34
+ if (!url.startsWith("http://") && !url.startsWith("https://")) {
35
+ url = "https://" + url;
36
+ }
33
37
 
34
38
  const spinner = ora("Starting extraction...").start();
35
39
  let browser = null;
36
40
 
37
41
  try {
38
- let useHeaded = opts.debug;
42
+ let useHeaded = false;
39
43
  let result;
40
44
 
41
45
  while (true) {
42
- spinner.text = `Launching browser (${
43
- useHeaded ? "visible" : "headless"
44
- } mode)`;
46
+ spinner.text = `Launching browser (${useHeaded ? "visible" : "headless"
47
+ } mode)`;
48
+ const launchArgs = ["--disable-blink-features=AutomationControlled"];
49
+ if (opts.noSandbox) {
50
+ launchArgs.push("--no-sandbox", "--disable-setuid-sandbox");
51
+ }
45
52
  browser = await chromium.launch({
46
53
  headless: !useHeaded,
47
- args: [
48
- "--no-sandbox",
49
- "--disable-setuid-sandbox",
50
- "--disable-blink-features=AutomationControlled",
51
- ],
54
+ args: launchArgs,
52
55
  });
53
- if (opts.debug) {
54
- console.log(
55
- chalk.dim(
56
- ` βœ“ Browser launched in ${
57
- useHeaded ? "visible" : "headless"
58
- } mode`
59
- )
60
- );
61
- }
62
56
 
63
57
  try {
64
58
  result = await extractBranding(url, spinner, browser, {
@@ -93,8 +87,11 @@ program
93
87
 
94
88
  console.log();
95
89
 
96
- // Save JSON output automatically (unless --json-only)
97
- if (!opts.jsonOnly) {
90
+ // Convert to W3C format if requested
91
+ const outputData = opts.dtcg ? toW3CFormat(result) : result;
92
+
93
+ // Save JSON output if --save-output or --dtcg is specified
94
+ if ((opts.saveOutput || opts.dtcg) && !opts.jsonOnly) {
98
95
  try {
99
96
  const domain = new URL(url).hostname.replace("www.", "");
100
97
  const timestamp = new Date()
@@ -105,9 +102,10 @@ program
105
102
  const outputDir = join(process.cwd(), "output", domain);
106
103
  mkdirSync(outputDir, { recursive: true });
107
104
 
108
- const filename = `${timestamp}.json`;
105
+ const suffix = opts.dtcg ? '.tokens' : '';
106
+ const filename = `${timestamp}${suffix}.json`;
109
107
  const filepath = join(outputDir, filename);
110
- writeFileSync(filepath, JSON.stringify(result, null, 2));
108
+ writeFileSync(filepath, JSON.stringify(outputData, null, 2));
111
109
 
112
110
  console.log(
113
111
  chalk.dim(
@@ -125,29 +123,16 @@ program
125
123
 
126
124
  // Output to terminal
127
125
  if (opts.jsonOnly) {
128
- console.log(JSON.stringify(result, null, 2));
126
+ console.log(JSON.stringify(outputData, null, 2));
129
127
  } else {
130
128
  console.log();
131
- displayResults(result, { verboseColors: opts.verboseColors });
129
+ displayResults(result);
132
130
  }
133
131
  } catch (err) {
134
132
  spinner.fail("Failed");
135
133
  console.error(chalk.red("\nβœ— Extraction failed"));
136
134
  console.error(chalk.red(` Error: ${err.message}`));
137
135
  console.error(chalk.dim(` URL: ${url}`));
138
-
139
- if (opts.debug && err.stack) {
140
- console.error(chalk.dim("\nStack trace:"));
141
- console.error(chalk.dim(err.stack));
142
- }
143
-
144
- if (!opts.debug) {
145
- console.log(
146
- chalk.hex('#FFB86C')(
147
- "\nTip: Try with --debug flag for tough sites and detailed error logs"
148
- )
149
- );
150
- }
151
136
  process.exit(1);
152
137
  } finally {
153
138
  if (browser) await browser.close();