cssprobe-cli 0.1.0 → 0.1.2

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
@@ -24,10 +24,10 @@ cssprobe-cli skill-install
24
24
 
25
25
  ```bash
26
26
  # With explicit selector
27
- cssprobe-cli inspect https://example.com ".main-content"
27
+ cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout ".container"
28
28
 
29
29
  # Auto-detect root element
30
- cssprobe-cli inspect https://example.com
30
+ cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout
31
31
 
32
32
  # Local HTML file
33
33
  cssprobe-cli inspect ./test.html ".container"
@@ -49,8 +49,8 @@ cssprobe-cli inspect https://mysite.com/page ".target" --state ~/.cssprobe-cli/s
49
49
  ### 3. JSON Output
50
50
 
51
51
  ```bash
52
- cssprobe-cli inspect https://example.com ".content" --json
53
- cssprobe-cli --json inspect https://example.com ".content" | jq '.findings[] | {id, confidence, message}'
52
+ cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body --json
53
+ cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body --json | jq '.findings[] | {id, confidence, message}'
54
54
  ```
55
55
 
56
56
  ---
@@ -74,6 +74,12 @@ cssprobe-cli login <url> # Interactive login, save state
74
74
  cssprobe-cli state-import [file] # Import cookies from Netscape format
75
75
  ```
76
76
 
77
+ ### Inspection
78
+
79
+ ```bash
80
+ cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body
81
+ ```
82
+
77
83
  ### Configuration
78
84
 
79
85
  ```bash
@@ -101,10 +107,11 @@ Options:
101
107
  --headed Show browser window
102
108
  --browser <engine> chromium|firefox|webkit (default chromium)
103
109
  --zoom Run 1x/0.5x viewport diagnosis
104
- --depth <n> DOM tree depth (default 6)
110
+ --depth <n> DOM tree depth (default: auto)
105
111
  --max-nodes <n> Node count cap (default 60)
106
112
  --up-to <tag> Ancestor stop tag (default html)
107
113
  --state <file> Load saved state (cookies + localStorage)
114
+ --brief Compact output: tree sketch + warnings/errors only
108
115
  ```
109
116
 
110
117
  ---
@@ -13,6 +13,8 @@ export declare class BrowserLauncher {
13
13
  constructor(options?: LauncherOptions);
14
14
  open(url: string): Promise<void>;
15
15
  collect(cfg: CollectConfig): Promise<Snapshot>;
16
+ /** Measure the DOM tree depth from a root selector to the deepest leaf. */
17
+ measureDepth(selector: string): Promise<number>;
16
18
  /** Scan the page for likely root elements (modals, dialogs, scroll containers). */
17
19
  autoDetectRoot(): Promise<string[]>;
18
20
  /**
@@ -106,6 +106,25 @@ class BrowserLauncher {
106
106
  }, cfg);
107
107
  return snapshot;
108
108
  }
109
+ /** Measure the DOM tree depth from a root selector to the deepest leaf. */
110
+ async measureDepth(selector) {
111
+ if (!this.page)
112
+ throw new Error('Browser not opened. Call open() first.');
113
+ return this.page.evaluate((sel) => {
114
+ const root = document.querySelector(sel);
115
+ if (!root)
116
+ return 0;
117
+ let maxDepth = 0;
118
+ const walk = (el, depth) => {
119
+ if (depth > maxDepth)
120
+ maxDepth = depth;
121
+ for (const child of Array.from(el.children))
122
+ walk(child, depth + 1);
123
+ };
124
+ walk(root, 0);
125
+ return maxDepth;
126
+ }, selector);
127
+ }
109
128
  /** Scan the page for likely root elements (modals, dialogs, scroll containers). */
110
129
  async autoDetectRoot() {
111
130
  if (!this.page)
@@ -21,6 +21,7 @@ export declare const inspectCommand: import("./command").CommandSchema<z.ZodObje
21
21
  'max-nodes': z.ZodOptional<z.ZodEffects<z.ZodNumber, number, unknown>>;
22
22
  'up-to': z.ZodOptional<z.ZodString>;
23
23
  state: z.ZodOptional<z.ZodString>;
24
+ brief: z.ZodOptional<z.ZodBoolean>;
24
25
  }, "strip", z.ZodTypeAny, {
25
26
  json?: boolean | undefined;
26
27
  headed?: boolean | undefined;
@@ -30,6 +31,7 @@ export declare const inspectCommand: import("./command").CommandSchema<z.ZodObje
30
31
  'max-nodes'?: number | undefined;
31
32
  'up-to'?: string | undefined;
32
33
  state?: string | undefined;
34
+ brief?: boolean | undefined;
33
35
  }, {
34
36
  json?: boolean | undefined;
35
37
  headed?: boolean | undefined;
@@ -39,4 +41,5 @@ export declare const inspectCommand: import("./command").CommandSchema<z.ZodObje
39
41
  'max-nodes'?: unknown;
40
42
  'up-to'?: string | undefined;
41
43
  state?: string | undefined;
44
+ brief?: boolean | undefined;
42
45
  }>>;
@@ -58,10 +58,11 @@ const inspect = (0, command_1.declareCommand)({
58
58
  headed: z.boolean().optional().describe('show the browser window'),
59
59
  browser: z.enum(['chromium', 'firefox', 'webkit']).optional().describe('browser engine (default chromium)'),
60
60
  zoom: z.boolean().optional().describe('run 1x/0.5x viewport diagnosis'),
61
- depth: numberArg.optional().describe('DOM tree depth (default 6)'),
61
+ depth: numberArg.optional().describe('DOM tree depth (default: auto, max 20)'),
62
62
  'max-nodes': numberArg.optional().describe('node count cap (default 60)'),
63
63
  'up-to': z.string().optional().describe('ancestor stop tag (default html)'),
64
64
  state: z.string().optional().describe('path to saved state file (cookies + localStorage)'),
65
+ brief: z.boolean().optional().describe('compact output: tree sketch + warnings/errors only'),
65
66
  }),
66
67
  });
67
68
  const login = (0, command_1.declareCommand)({
@@ -100,12 +100,20 @@ async function handleInspect(command, cmdEntry, args, output) {
100
100
  const url = parsed.url;
101
101
  const selector = parsed.selector;
102
102
  const zoom = !!parsed.zoom;
103
- const depth = parsed.depth || config.depth;
103
+ const depthRaw = parsed.depth;
104
+ let depth;
105
+ if (depthRaw === 'auto' || depthRaw === undefined) {
106
+ depth = 0; // placeholder, resolved after browser opens
107
+ }
108
+ else {
109
+ depth = Number(depthRaw);
110
+ }
104
111
  const maxNodes = parsed['max-nodes'] || 60;
105
112
  const upTo = parsed['up-to'] || 'html';
106
113
  const headed = !!parsed.headed || config.headed;
107
114
  const browser = parsed.browser || config.browser;
108
115
  const state = parsed.state || undefined;
116
+ const brief = !!parsed.brief;
109
117
  if (!url)
110
118
  output.error('URL is required. Usage: cssprobe-cli inspect <url> [selector]');
111
119
  // Auto-detect root selector if not provided
@@ -119,22 +127,28 @@ async function handleInspect(command, cmdEntry, args, output) {
119
127
  rootSelector = detected;
120
128
  console.error(`Auto-detected root: ${rootSelector}`);
121
129
  }
130
+ const launcher = new launcher_1.BrowserLauncher({ browser, headed, state });
131
+ await launcher.open(url);
132
+ // Resolve auto depth
133
+ if (depth === 0) {
134
+ const measured = await launcher.measureDepth(rootSelector);
135
+ depth = Math.min(measured, 20) || 6;
136
+ console.error(`Auto-detected depth: ${measured} (using ${depth})`);
137
+ }
122
138
  const collectCfg = {
123
139
  rootSelector,
124
140
  upTo,
125
141
  downDepth: depth,
126
142
  maxNodes,
127
143
  };
128
- const launcher = new launcher_1.BrowserLauncher({ browser, headed, state });
129
- await launcher.open(url);
130
144
  const snapshot = await launcher.collect(collectCfg);
131
145
  await launcher.close();
132
146
  const findings = (0, analyzer_1.analyze)(snapshot);
133
147
  if (output.json) {
134
- console.log(output.format((0, renderer_1.renderJSON)(snapshot, findings)));
148
+ console.log(output.format((0, renderer_1.renderJSON)(snapshot, findings, brief)));
135
149
  }
136
150
  else {
137
- console.log((0, renderer_1.renderMarkdown)(snapshot, findings));
151
+ console.log((0, renderer_1.renderMarkdown)(snapshot, findings, brief));
138
152
  }
139
153
  }
140
154
  catch (e) {
@@ -1,3 +1,3 @@
1
1
  import type { Snapshot, Finding } from './types';
2
- export declare function renderMarkdown(snapshot: Snapshot, findings: Finding[]): string;
3
- export declare function renderJSON(snapshot: Snapshot, findings: Finding[]): object;
2
+ export declare function renderMarkdown(snapshot: Snapshot, findings: Finding[], brief?: boolean): string;
3
+ export declare function renderJSON(snapshot: Snapshot, findings: Finding[], brief?: boolean): object;
@@ -4,6 +4,12 @@
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.renderMarkdown = renderMarkdown;
6
6
  exports.renderJSON = renderJSON;
7
+ // ─── Node label (matches analyzer.ts nodeLabel) ───
8
+ function nodeLabel(node) {
9
+ const cls = node.classes.length ? `.${node.classes.join('.')}` : '';
10
+ const id = node.id ? `#${node.id}` : '';
11
+ return `${node.tag}${id}${cls}`;
12
+ }
7
13
  // ─── Node rendering (DOM tree) ───
8
14
  function renderNode(node, indent) {
9
15
  const lines = [];
@@ -57,6 +63,79 @@ function renderAncestors(chain) {
57
63
  (a.inlineStyle ? ` style="${a.inlineStyle}"` : '');
58
64
  });
59
65
  }
66
+ function buildSketchTree(node, issueLabels) {
67
+ if (!node)
68
+ return null;
69
+ const label = nodeLabel(node);
70
+ const s = node.shape || {};
71
+ const shapeStr = s.role ? `[${s.role} h:${s.heightStrategy} w:${s.widthStrategy}]` : '';
72
+ const flags = [];
73
+ if (node.flags.overflowsParent)
74
+ flags.push('\u26A0parent-overflow');
75
+ if (node.flags.overflowsViewport)
76
+ flags.push('\u26A0viewport-overflow');
77
+ if (node.metrics.clientHeight === 0 && node.metrics.offsetHeight === 0)
78
+ flags.push('\u26A0collapsed');
79
+ if (node.flags.scrollable)
80
+ flags.push('\u2714scrollable');
81
+ if (node.containingBlockModifiers.length)
82
+ flags.push(`CB:${node.containingBlockModifiers.join(' ')}`);
83
+ const hasIssue = issueLabels.has(label) || flags.length > 0;
84
+ const children = [];
85
+ let omitted = 0;
86
+ for (const child of node.children) {
87
+ const sketchChild = buildSketchTree(child, issueLabels);
88
+ if (!sketchChild)
89
+ continue;
90
+ if (sketchChild.hasIssue || hasDescendantIssue(sketchChild)) {
91
+ children.push(sketchChild);
92
+ }
93
+ else {
94
+ omitted++;
95
+ }
96
+ }
97
+ return { label, shape: shapeStr, flags, children, hasIssue, omitted };
98
+ }
99
+ function hasDescendantIssue(node) {
100
+ if (node.hasIssue)
101
+ return true;
102
+ return node.children.some(c => hasDescendantIssue(c));
103
+ }
104
+ function renderSketchNode(node, prefix, isLast) {
105
+ const lines = [];
106
+ const connector = isLast ? '\u2514\u2500 ' : '\u251C\u2500 ';
107
+ const flagStr = node.flags.length ? ` ${node.flags.join(' ')}` : '';
108
+ const issueMark = node.hasIssue && node.flags.length === 0 ? ' \u26A0' : '';
109
+ lines.push(`${prefix}${connector}${node.label} ${node.shape}${flagStr}${issueMark}`);
110
+ const childPrefix = prefix + (isLast ? ' ' : '\u2502 ');
111
+ const totalChildren = node.children.length + (node.omitted > 0 ? 1 : 0);
112
+ for (let i = 0; i < node.children.length; i++) {
113
+ lines.push(...renderSketchNode(node.children[i], childPrefix, i === totalChildren - 1));
114
+ }
115
+ if (node.omitted > 0) {
116
+ const omConnector = '\u2514\u2500 ';
117
+ lines.push(`${childPrefix}${omConnector}... (${node.omitted} subtrees omitted)`);
118
+ }
119
+ return lines;
120
+ }
121
+ function renderSketch(tree, findings) {
122
+ if (!tree)
123
+ return ['(empty tree)'];
124
+ const issueLabels = new Set();
125
+ for (const f of findings) {
126
+ if (f.level === 'warning' || f.level === 'error') {
127
+ if (f.location)
128
+ issueLabels.add(f.location);
129
+ }
130
+ }
131
+ const sketchRoot = buildSketchTree(tree, issueLabels);
132
+ if (!sketchRoot)
133
+ return ['(empty tree)'];
134
+ if (!hasDescendantIssue(sketchRoot) && !sketchRoot.hasIssue) {
135
+ return [`${sketchRoot.label} ${sketchRoot.shape} (no issues found in tree)`];
136
+ }
137
+ return renderSketchNode(sketchRoot, '', true);
138
+ }
60
139
  // ─── Findings rendering ───
61
140
  const CONF_BADGE = {
62
141
  DEFINITE: 'DEFINITE',
@@ -85,6 +164,22 @@ function renderFindings(findings) {
85
164
  }
86
165
  return lines;
87
166
  }
167
+ function renderBriefFindings(findings) {
168
+ const lines = [];
169
+ lines.push('## Findings');
170
+ const important = findings.filter(f => f.level === 'warning' || f.level === 'error');
171
+ if (important.length === 0) {
172
+ lines.push('- No warnings or errors');
173
+ return lines;
174
+ }
175
+ for (const f of important) {
176
+ const badge = `[${CONF_BADGE[f.confidence]}]`;
177
+ const loc = f.location ? ` @ ${f.location}` : '';
178
+ const icon = f.level === 'error' ? '\u26A0' : '\u26A0';
179
+ lines.push(`- ${icon} ${f.message} ${badge}${loc}`);
180
+ }
181
+ return lines;
182
+ }
88
183
  function confidenceSummary(findings) {
89
184
  const counts = findings.reduce((acc, f) => {
90
185
  acc[f.confidence] = (acc[f.confidence] || 0) + 1;
@@ -98,7 +193,7 @@ function confidenceSummary(findings) {
98
193
  return parts.join(' | ');
99
194
  }
100
195
  // ─── Markdown ───
101
- function renderMarkdown(snapshot, findings) {
196
+ function renderMarkdown(snapshot, findings, brief = false) {
102
197
  const lines = [];
103
198
  const vp = snapshot.viewport ? `${snapshot.viewport.width}\u00D7${snapshot.viewport.height}` : 'unknown';
104
199
  lines.push('# cssprobe-cli report');
@@ -117,13 +212,22 @@ function renderMarkdown(snapshot, findings) {
117
212
  lines.push('```');
118
213
  lines.push(...renderAncestors(snapshot.ancestors));
119
214
  lines.push('```');
215
+ if (brief) {
216
+ lines.push('');
217
+ lines.push('## Tree Sketch (issues only)');
218
+ lines.push('```');
219
+ lines.push(...renderSketch(snapshot.tree, findings));
220
+ lines.push('```');
221
+ }
222
+ else {
223
+ lines.push('');
224
+ lines.push(`## DOM tree (${snapshot.downDepth} levels deep)`);
225
+ lines.push('```');
226
+ lines.push(...renderNode(snapshot.tree, 0));
227
+ lines.push('```');
228
+ }
120
229
  lines.push('');
121
- lines.push(`## DOM tree (${snapshot.downDepth} levels deep)`);
122
- lines.push('```');
123
- lines.push(...renderNode(snapshot.tree, 0));
124
- lines.push('```');
125
- lines.push('');
126
- lines.push(...renderFindings(findings));
230
+ lines.push(...(brief ? renderBriefFindings(findings) : renderFindings(findings)));
127
231
  if (snapshot.crossOriginBlocked && snapshot.crossOriginBlocked > 0) {
128
232
  lines.push('');
129
233
  lines.push('## Cross-origin limitation');
@@ -135,19 +239,42 @@ function renderMarkdown(snapshot, findings) {
135
239
  return lines.join('\n');
136
240
  }
137
241
  // ─── JSON ───
138
- function renderJSON(snapshot, findings) {
242
+ function renderJSON(snapshot, findings, brief = false) {
139
243
  const counts = findings.reduce((acc, f) => {
140
244
  acc[f.confidence] = (acc[f.confidence] || 0) + 1;
141
245
  return acc;
142
246
  }, {});
247
+ const meta = {
248
+ rootSelector: snapshot.rootSelector,
249
+ viewport: snapshot.viewport,
250
+ nodeCount: snapshot.nodeCount,
251
+ crossOriginBlocked: snapshot.crossOriginBlocked,
252
+ blockedSheetUrls: snapshot.blockedSheetUrls,
253
+ };
254
+ if (brief) {
255
+ const important = findings.filter(f => f.level === 'warning' || f.level === 'error');
256
+ const briefFindings = important.map(f => ({
257
+ id: f.id,
258
+ level: f.level,
259
+ message: f.message,
260
+ confidence: f.confidence,
261
+ location: f.location,
262
+ evidence: f.evidence.slice(0, 1),
263
+ }));
264
+ return {
265
+ meta,
266
+ snapshot: { rootSelector: snapshot.rootSelector, nodeCount: snapshot.nodeCount, downDepth: snapshot.downDepth },
267
+ findings: briefFindings,
268
+ summary: {
269
+ total: findings.length,
270
+ warnings: important.filter(f => f.level === 'warning').length,
271
+ errors: important.filter(f => f.level === 'error').length,
272
+ confidence: { DEFINITE: counts.DEFINITE || 0, INDEFINITE: counts.INDEFINITE || 0, UNVERIFIABLE: counts.UNVERIFIABLE || 0 },
273
+ },
274
+ };
275
+ }
143
276
  return {
144
- meta: {
145
- rootSelector: snapshot.rootSelector,
146
- viewport: snapshot.viewport,
147
- nodeCount: snapshot.nodeCount,
148
- crossOriginBlocked: snapshot.crossOriginBlocked,
149
- blockedSheetUrls: snapshot.blockedSheetUrls,
150
- },
277
+ meta,
151
278
  snapshot: snapshot.error ? { error: snapshot.error, candidates: snapshot.candidates } : snapshot,
152
279
  findings,
153
280
  summary: {
package/dist/help.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "global": "Usage: cssprobe-cli <command> [args] [options]\n\n\nInspection:\n inspect <url> [selector] inspect the runtime css of a page (layout, scroll, colors, fonts, backgrounds)\n login <url> open browser for interactive login, then save state for later use\n state-import [file] import cookies from netscape format file into a playwright state file\n\nConfiguration:\n config-show show current configuration\n config-set <key> <value> set a configuration value\n config-list list all profiles\n config-use <name> switch active profile\n config-new <name> create a new profile\n config-path show configuration file path\n\nAgent Skills:\n skill-install install agent skill for cssprobe-cli (teaches agents how to use the cli)\n skill-uninstall remove agent skill for cssprobe-cli\n\nGlobal options:\n --help [command] print help\n --json output response as JSON\n --raw output only the result value\n --version print version\n -p, --profile <name> use named profile (or CSSPROBE_PROFILE env)",
3
3
  "commands": {
4
4
  "inspect": {
5
- "help": "cssprobe-cli inspect <url> [selector]\n\nInspect the runtime CSS of a page (layout, scroll, colors, fonts, backgrounds)\n\nArguments:\n <url> url, file:// path, or local html file path\n [selector] css selector for the root element (auto-detected if omitted)\nOptions:\n --json output structured json instead of markdown\n --headed show the browser window\n --browser browser engine (default chromium)\n --zoom run 1x/0.5x viewport diagnosis\n --depth dom tree depth (default 6)\n --max-nodes node count cap (default 60)\n --up-to ancestor stop tag (default html)\n --state path to saved state file (cookies + localstorage)\n\nGlobal options:\n --json output as JSON\n --profile, -p <name> use named profile",
5
+ "help": "cssprobe-cli inspect <url> [selector]\n\nInspect the runtime CSS of a page (layout, scroll, colors, fonts, backgrounds)\n\nArguments:\n <url> url, file:// path, or local html file path\n [selector] css selector for the root element (auto-detected if omitted)\nOptions:\n --json output structured json instead of markdown\n --headed show the browser window\n --browser browser engine (default chromium)\n --zoom run 1x/0.5x viewport diagnosis\n --depth dom tree depth (default: auto, max 20)\n --max-nodes node count cap (default 60)\n --up-to ancestor stop tag (default html)\n --state path to saved state file (cookies + localstorage)\n --brief compact output: tree sketch + warnings/errors only\n\nGlobal options:\n --json output as JSON\n --profile, -p <name> use named profile",
6
6
  "flags": {
7
7
  "json": "boolean",
8
8
  "headed": "boolean",
@@ -11,7 +11,8 @@
11
11
  "depth": "string",
12
12
  "max-nodes": "string",
13
13
  "up-to": "string",
14
- "state": "string"
14
+ "state": "string",
15
+ "brief": "boolean"
15
16
  },
16
17
  "args": [
17
18
  "url",
@@ -102,6 +103,7 @@
102
103
  "json",
103
104
  "headed",
104
105
  "zoom",
106
+ "brief",
105
107
  "local"
106
108
  ]
107
109
  }
@@ -40,7 +40,7 @@ function buildSkillMd() {
40
40
  'npx playwright install chromium',
41
41
  BT3,
42
42
  '',
43
- 'Verify: ' + BT + 'cssprobe-cli-cli inspect https://example.com "body" --json | head -5' + BT,
43
+ 'Verify: ' + BT + 'cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body --json | head -5' + BT,
44
44
  '',
45
45
  '## Command Discovery',
46
46
  '',
@@ -56,10 +56,10 @@ function buildSkillMd() {
56
56
  '',
57
57
  BT3 + 'bash',
58
58
  '# With explicit selector',
59
- 'cssprobe-cli-cli inspect https://example.com ".main-content"',
59
+ 'cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body',
60
60
  '',
61
61
  '# Auto-detect root element (picks modal/dialog/scroll-container)',
62
- 'cssprobe-cli inspect https://example.com',
62
+ 'cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout',
63
63
  '',
64
64
  '# Local HTML file',
65
65
  'cssprobe-cli inspect ./test.html ".container"',
@@ -101,8 +101,8 @@ function buildSkillMd() {
101
101
  'Always pass ' + BT + '--json' + BT + ' when consuming output programmatically:',
102
102
  '',
103
103
  BT3 + 'bash',
104
- 'cssprobe-cli inspect https://example.com ".content" --json',
105
- 'cssprobe-cli --json inspect https://example.com ".content" | jq ' + BT + "'.findings[] | {id, confidence, message}'" + BT,
104
+ 'cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body --json',
105
+ 'cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body --json | jq ' + BT + "'.findings[] | {id, confidence, message}'" + BT,
106
106
  BT3,
107
107
  '',
108
108
  'Without ' + BT + '--json' + BT + ', output is a Markdown report with ancestor chain,',
@@ -134,7 +134,7 @@ function buildSkillMd() {
134
134
  ' --headed Show browser window',
135
135
  ' --browser <engine> chromium|firefox|webkit (default chromium)',
136
136
  ' --zoom Run 1x/0.5x viewport diagnosis',
137
- ' --depth <n> DOM tree depth (default 6)',
137
+ ' --depth <n> DOM tree depth (default: auto)',
138
138
  ' --max-nodes <n> Node count cap (default 60)',
139
139
  ' --up-to <tag> Ancestor stop tag (default html)',
140
140
  ' --state <file> Load saved state (cookies + localStorage)',
@@ -176,10 +176,10 @@ function buildSkillMd() {
176
176
  '',
177
177
  BT3 + 'bash',
178
178
  '# Auto-detect and analyze',
179
- 'cssprobe-cli inspect https://example.com',
179
+ 'cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout',
180
180
  '',
181
181
  '# Look for findings with level "warning" or "error"',
182
- 'cssprobe-cli --json inspect https://example.com | jq ' + BT + "'.findings[] | select(.level != \"info\")'" + BT,
182
+ 'cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body --json | jq ' + BT + "'.findings[] | select(.level != \"info\")'" + BT,
183
183
  BT3,
184
184
  '',
185
185
  '### 3. Inspect with authentication',
@@ -196,7 +196,7 @@ function buildSkillMd() {
196
196
  '',
197
197
  BT3 + 'bash',
198
198
  '# Use --zoom to compare 1x vs 0.5x viewport',
199
- 'cssprobe-cli inspect https://example.com ".content" --zoom',
199
+ 'cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body --zoom',
200
200
  BT3,
201
201
  '',
202
202
  '## Anti-patterns',
@@ -27,7 +27,7 @@ npm install -g cssprobe-cli
27
27
  Or run without installing (slower but zero setup):
28
28
 
29
29
  ```bash
30
- npx cssprobe-cli inspect https://example.com ".content"
30
+ npx cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body
31
31
  ```
32
32
 
33
33
  Verify:
@@ -55,7 +55,7 @@ npx playwright install chromium
55
55
  Verify:
56
56
 
57
57
  ```bash
58
- cssprobe-cli inspect https://example.com "body" --json | head -5
58
+ cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body --json | head -5
59
59
  ```
60
60
 
61
61
  JSON output = it works. `Browser not installed` = run the install command above.
@@ -68,10 +68,10 @@ JSON output = it works. `Browser not installed` = run the install command above.
68
68
 
69
69
  ```bash
70
70
  # With explicit selector
71
- cssprobe-cli inspect https://example.com ".main-content"
71
+ cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body
72
72
 
73
73
  # Auto-detect root element
74
- cssprobe-cli inspect https://example.com
74
+ cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout
75
75
 
76
76
  # Local HTML file
77
77
  cssprobe-cli inspect ./test.html ".container"
@@ -80,8 +80,8 @@ cssprobe-cli inspect ./test.html ".container"
80
80
  ### JSON Output (for programmatic consumption)
81
81
 
82
82
  ```bash
83
- cssprobe-cli inspect https://example.com ".content" --json
84
- cssprobe-cli --json inspect https://example.com ".content" | jq '.findings[] | {id, confidence, message}'
83
+ cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body --json
84
+ cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body --json | jq '.findings[] | {id, confidence, message}'
85
85
  ```
86
86
 
87
87
  ---
@@ -218,7 +218,7 @@ Priority (highest to lowest):
218
218
  For agents that trust copy-paste:
219
219
 
220
220
  ```bash
221
- npm install -g cssprobe-cli && npx playwright install chromium && cssprobe-cli inspect https://example.com "body"
221
+ npm install -g cssprobe-cli && npx playwright install chromium && cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body
222
222
  ```
223
223
 
224
224
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cssprobe-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Runtime CSS probe — inspect layout, colors, backgrounds, fonts and more in a live browser. AI agents and shell automation.",
5
5
  "keywords": [
6
6
  "css",