cssprobe-cli 0.2.24 → 0.2.26

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/AGENTS.md CHANGED
@@ -47,7 +47,7 @@ src/
47
47
  - **Command dispatch**: `minimist` parse → `parseCommand()` Zod validate → session command execution via daemon socket.
48
48
  - **Output strategy**: `Output` interface → `TextOutput` (Markdown for inspect, tables for lists) / `JsonOutput` (machine-readable JSON).
49
49
  - **Config priority**: CLI flags → env vars → `~/.cssprobe-clirc` profiles. Switch with `-p <profile>`.
50
- - **State management**: `state-import` converts Netscape cookies. Session persists browser state until `close`.
50
+ - **State management**: `state-import` converts Netscape cookies; `state-save` persists the current session's cookies + localStorage after manual login. Session persists browser state until `close`.
51
51
  - **Browser discovery**: `findBrowserExecutable()` scans `~/Library/Caches/ms-playwright/chromium-*` for existing Chrome installations.
52
52
  - **Error format**: `Error: <message>` → JSON mode: `{ isError: true, error: "<message>" }` → `process.exit(1)`
53
53
 
@@ -72,14 +72,19 @@ src/
72
72
  ### Browser
73
73
  - `resize <width> <height>` — Resize browser viewport
74
74
  - `eval <expression>` — Evaluate JavaScript (browser context)
75
+ - Returns raw string values (not JSON-quoted) for string results
75
76
  - `playwright <call>` — Execute Playwright API call (Node.js context)
77
+ - Returns `{ ok: true, value: null, note: ... }` when the call returns no value; throws a clear error message on failure
76
78
  - `screenshot` — Take a screenshot
79
+ - `--out <path>` — Output file path (default: `~/.cssprobe-cli/screenshots/<timestamp>.png`)
77
80
 
78
81
  ### State
79
82
  - `state-import [file]` — Import cookies from Netscape format
80
83
  - `--out <file>` — Output state file path (default: `~/.cssprobe-cli/states/imported.json`)
81
84
  - `--name <name>` — Custom name for the state file (e.g. `mysite` or `mysite.json`)
82
85
  - `--merge <file>` — Existing state file to merge into
86
+ - `state-save` — Save current browser session state (cookies + localStorage)
87
+ - `--name <name>` — State file name (default: `session`)
83
88
 
84
89
  ### Config
85
90
  - `config-show` / `config-set` / `config-list` / `config-use` / `config-new` / `config-path`
package/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # Changelog
2
+
3
+ All notable changes are documented on the [GitHub Releases](https://github.com/mack-peng/cssprobe-cli/releases) page.
4
+
5
+ ## [0.2.26] - 2026-09-16
6
+
7
+ ### Added
8
+ - npm / stars badges, star CTA and `llms.txt` for agent discovery
9
+ - Cross-link to companion tool `cssgraph`
10
+
11
+ See [releases](https://github.com/mack-peng/cssprobe-cli/releases) for the complete history.
package/README.md CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  Runtime CSS probe — inspect layout, scroll, colors, backgrounds, fonts and more in a live browser. Built for both humans and AI agents.
4
4
 
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D22.5.0-brightgreen.svg)](https://nodejs.org/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D22.5.0-brightgreen.svg)](https://nodejs.org/) [![npm version](https://img.shields.io/npm/v/cssprobe-cli.svg)](https://www.npmjs.com/package/cssprobe-cli) [![npm downloads](https://img.shields.io/npm/dm/cssprobe-cli.svg)](https://www.npmjs.com/package/cssprobe-cli) [![GitHub stars](https://img.shields.io/github/stars/mack-peng/cssprobe-cli?style=social)](https://github.com/mack-peng/cssprobe-cli/stargazers)
6
+
7
+ > Static + runtime CSS diagnosis for AI agents — pair with [cssgraph](https://github.com/mack-peng/cssgraph) (the CSS knowledge graph) for the full picture.
6
8
 
7
9
  ---
8
10
 
@@ -104,7 +106,7 @@ cssprobe-cli open https://mysite.com --headed
104
106
  # User manually logs in...
105
107
 
106
108
  # Save session state for future use
107
- cssprobe-cli playwright "page.context().storageState({path: 'state.json'})"
109
+ cssprobe-cli state-save --name mysite
108
110
 
109
111
  # Reopen with saved state (no login needed)
110
112
  cssprobe-cli open https://mysite.com --state state.json --headed
@@ -158,13 +160,14 @@ cssprobe-cli inspect body --json | jq '.findings[] | {id, confidence, message}'
158
160
  | `resize <width> <height>` | Resize browser viewport |
159
161
  | `eval <expression>` | Evaluate JavaScript (browser context) |
160
162
  | `playwright <call>` | Execute Playwright API (Node.js context) |
161
- | `screenshot` | Take screenshot |
163
+ | `screenshot` | Take screenshot (saves to ~/.cssprobe-cli/screenshots/, --out to override) |
162
164
 
163
165
  ### State
164
166
 
165
167
  | Command | Description |
166
168
  |---------|-------------|
167
169
  | `state-import <file>` | Import cookies from Netscape format |
170
+ | `state-save` | Save current browser session state (cookies + localStorage) |
168
171
 
169
172
  ### Configuration
170
173
 
@@ -193,6 +196,34 @@ The report header shows: `confidence: DEFINITE 8 | INDEFINITE 0 | UNVERIFIABLE 1
193
196
 
194
197
  ---
195
198
 
199
+ ## Complementary Tool: cssgraph
200
+
201
+ cssprobe-cli is a **runtime** CSS probe — it opens a real browser and reads what is actually rendered. For **static** questions about the source code — where is `.btn-primary` defined, what cascades over it, which components reference it, what would change if I edited it — use [cssgraph](https://github.com/mack-peng/cssgraph), a local SQLite knowledge graph of every className, property, variable, and at-rule in your stylesheets. The two tools complement each other:
202
+
203
+ | | cssgraph (static) | cssprobe-cli (runtime) |
204
+ |---|---|---|
205
+ | Analyzes | source code (CSS/SCSS/Less + JSX/TSX + templates) | live browser (computed styles + DOM) |
206
+ | Answers | where a class is defined, cascade, impact, unused CSS | actual rendered layout, overflow, scroll, height chains |
207
+ | When | before/without a browser | after static analysis, to verify at runtime |
208
+ | Usage | `cssgraph init` + `explore`/`rule`/`impact` | `open` + `inspect`/`layout`/`findings` |
209
+
210
+ **Recommended workflow for a style problem** — go static first, then verify at runtime:
211
+
212
+ ```bash
213
+ # 1. Static: find the definitions, cascade, and blast radius (cssgraph)
214
+ cssgraph explore .btn-primary
215
+ cssgraph cascade .btn-primary
216
+
217
+ # 2. Runtime: confirm what actually renders (cssprobe-cli)
218
+ cssprobe-cli open https://example.com
219
+ cssprobe-cli inspect .btn-primary
220
+ cssprobe-cli findings .btn-primary
221
+ ```
222
+
223
+ Install: `npm install -g cssgraph` (requires Node.js >= 22.5.0). It exposes 12 MCP tools (`cssgraph_explore`, `cssgraph_rule`, `cssgraph_impact`, …) plus CLI commands. See [npm](https://www.npmjs.com/package/cssgraph) / [GitHub](https://github.com/mack-peng/cssgraph).
224
+
225
+ ---
226
+
196
227
  ## Configuration
197
228
 
198
229
  ```bash
@@ -240,6 +271,12 @@ npm test # Run unit tests (58 tests)
240
271
  npx tsc --noEmit # Type check only
241
272
  ```
242
273
 
274
+ ## If cssprobe-cli is useful
275
+
276
+ A ⭐ star helps other developers discover it — and tells us to keep shipping.
277
+
278
+ ---
279
+
243
280
  ## License
244
281
 
245
282
  MIT
@@ -129,6 +129,7 @@ const screenshot = (0, command_1.declareCommand)({
129
129
  description: 'Take a screenshot of the current page',
130
130
  options: z.object({
131
131
  'full-page': z.boolean().optional().describe('take screenshot of the full scrollable page'),
132
+ out: z.string().optional().describe('output file path (default: ~/.cssprobe-cli/screenshots/<timestamp>.png)'),
132
133
  }),
133
134
  });
134
135
  const resize = (0, command_1.declareCommand)({
@@ -298,12 +298,41 @@ async function handleSessionCommand(commandName, command, args, output) {
298
298
  if (args.json)
299
299
  runArgs.json = true;
300
300
  const result = await session.run(runArgs);
301
+ // Screenshot: save the base64 data URL to a file and report the path
302
+ if (commandName === 'screenshot' && typeof result.text === 'string' && result.text.startsWith('data:image/png;base64,')) {
303
+ const saved = saveScreenshotFile(result.text, parsed.out);
304
+ if (output.json) {
305
+ console.log(JSON.stringify({ saved }, null, 2));
306
+ }
307
+ else {
308
+ console.log(`Screenshot saved: ${saved}`);
309
+ }
310
+ return;
311
+ }
301
312
  console.log(result.text);
302
313
  }
303
314
  catch (e) {
304
315
  output.error(e instanceof Error ? e.message : String(e));
305
316
  }
306
317
  }
318
+ function saveScreenshotFile(dataUrl, out) {
319
+ const base64 = dataUrl.replace(/^data:image\/png;base64,/, '');
320
+ const buffer = Buffer.from(base64, 'base64');
321
+ const resolvedOut = out
322
+ ? path_1.default.resolve(out)
323
+ : (() => {
324
+ const dir = path_1.default.join(os_1.default.homedir(), '.cssprobe-cli', 'screenshots');
325
+ if (!fs_1.default.existsSync(dir))
326
+ fs_1.default.mkdirSync(dir, { recursive: true });
327
+ const ts = new Date().toISOString().replace(/[:.]/g, '-');
328
+ return path_1.default.join(dir, `screenshot-${ts}.png`);
329
+ })();
330
+ const dir = path_1.default.dirname(resolvedOut);
331
+ if (!fs_1.default.existsSync(dir))
332
+ fs_1.default.mkdirSync(dir, { recursive: true });
333
+ fs_1.default.writeFileSync(resolvedOut, buffer);
334
+ return resolvedOut;
335
+ }
307
336
  // ── config commands ──
308
337
  function handleConfigCommands(commandName, command, args, output) {
309
338
  try {
@@ -124,8 +124,8 @@ var __cssprobe_cli = (() => {
124
124
  } catch (_e) {
125
125
  accessible = false;
126
126
  crossOriginBlocked.count++;
127
- const short = (sheet.href || "unknown").split("/").pop() || "unknown";
128
- if (!blockedSheetUrls.includes(short)) blockedSheetUrls.push(short);
127
+ const href = (sheet.href || "unknown").replace(/^https?:\/\//, "");
128
+ if (!blockedSheetUrls.includes(href)) blockedSheetUrls.push(href);
129
129
  continue;
130
130
  }
131
131
  if (!rules) continue;
@@ -174,6 +174,10 @@ async function executeCommand(launcher, args) {
174
174
  if (!page)
175
175
  throw new Error('Browser is not open. Run: cssprobe-cli open <url>');
176
176
  const result = await page.evaluate(expression);
177
+ if (typeof result === 'string')
178
+ return { text: result };
179
+ if (result === undefined)
180
+ return { text: 'undefined' };
177
181
  return { text: JSON.stringify(result, null, 2) };
178
182
  }
179
183
  case 'resize': {
@@ -198,6 +202,8 @@ async function executeCommand(launcher, args) {
198
202
  const asyncFunction = new AsyncFunction('page', 'browser', `return ${call}`);
199
203
  const browser = page.context().browser();
200
204
  const result = await asyncFunction(page, browser);
205
+ if (result === undefined)
206
+ return { text: JSON.stringify({ ok: true, value: null, note: 'call returned no value' }) };
201
207
  return { text: JSON.stringify(result, null, 2) };
202
208
  }
203
209
  case 'state-save': {
@@ -38,9 +38,9 @@ function matchDeclarations(el, wantedProps, crossOriginBlocked, blockedSheetUrls
38
38
  catch (_e) {
39
39
  accessible = false;
40
40
  crossOriginBlocked.count++;
41
- const short = (sheet.href || 'unknown').split('/').pop() || 'unknown';
42
- if (!blockedSheetUrls.includes(short))
43
- blockedSheetUrls.push(short);
41
+ const href = (sheet.href || 'unknown').replace(/^https?:\/\//, '');
42
+ if (!blockedSheetUrls.includes(href))
43
+ blockedSheetUrls.push(href);
44
44
  continue;
45
45
  }
46
46
  if (!rules)
@@ -53,9 +53,9 @@ function renderMarkdown(snapshot, findings, brief = false, layout = false) {
53
53
  if (snapshot.crossOriginBlocked && snapshot.crossOriginBlocked > 0) {
54
54
  lines.push('');
55
55
  lines.push('## Cross-origin limitation');
56
- lines.push(`\u26A0 ${snapshot.crossOriginBlocked} stylesheet(s) blocked by browser security (SecurityError). Declared values from these sheets are marked UNVERIFIABLE \u2014 computed values from getComputedStyle() are still accurate.`);
56
+ lines.push(`\u26A0 ${snapshot.crossOriginBlocked} stylesheet(s) from CDN/cross-origin were blocked by browser security (SecurityError). Declared values from these sheets are marked UNVERIFIABLE \u2014 computed styles from getComputedStyle() are still accurate.`);
57
57
  if (snapshot.blockedSheetUrls && snapshot.blockedSheetUrls.length > 0) {
58
- lines.push(`Blocked: ${snapshot.blockedSheetUrls.join(', ')}`);
58
+ lines.push(`Blocked (from CDN/cross-origin): ${snapshot.blockedSheetUrls.join(', ')}`);
59
59
  }
60
60
  }
61
61
  return lines.join('\n');
package/dist/help.json CHANGED
@@ -90,9 +90,10 @@
90
90
  ]
91
91
  },
92
92
  "screenshot": {
93
- "help": "cssprobe-cli screenshot \n\nTake a screenshot of the current page\n\nOptions:\n --full-page take screenshot of the full scrollable page\n\nGlobal options:\n --json output as JSON\n --profile, -p <name> use named profile",
93
+ "help": "cssprobe-cli screenshot \n\nTake a screenshot of the current page\n\nOptions:\n --full-page take screenshot of the full scrollable page\n --out output file path (default: ~/.cssprobe-cli/screenshots/<timestamp>.png)\n\nGlobal options:\n --json output as JSON\n --profile, -p <name> use named profile",
94
94
  "flags": {
95
- "full-page": "boolean"
95
+ "full-page": "boolean",
96
+ "out": "string"
96
97
  },
97
98
  "args": []
98
99
  },
@@ -387,7 +387,8 @@ CLI 输出: {"success":true}
387
387
 
388
388
  | 旧命令 | 新命令 | 说明 |
389
389
  |--------|--------|------|
390
- | `login <url>` | `open <url>` → 手动登录 → `save-state` | 流程变化 |
390
+ | `login <url>` | `open <url>` → 手动登录 → `state-save` | 流程变化 |
391
391
  | `inspect <url> --wait` | `open <url>` → 手动操作 → `inspect <selector>` | 流程变化 |
392
392
  | `interactive <url>` | `open <url>` → 多次 `inspect`/`tree`/`inject-css` | 流程变化 |
393
393
  | `state-import` | 保留 | 不变 |
394
+ | `state-save` | 新增 | 保存当前会话 cookies + localStorage |
@@ -88,7 +88,7 @@ cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body --
88
88
 
89
89
  ## Step 4: Login-Protected Pages
90
90
 
91
- Many pages require authentication. cssprobe-cli supports three approaches:
91
+ Many pages require authentication. cssprobe-cli supports these approaches:
92
92
 
93
93
  ### Option A: Import Cookies from Browser Export
94
94
 
@@ -114,13 +114,26 @@ cssprobe-cli open https://mysite.com --headed
114
114
  cssprobe-cli inspect .target
115
115
  ```
116
116
 
117
- ### Option C: Merge Cookies into Existing State
117
+ ### Option C: Interactive Login + Save State (recommended for reuse)
118
+
119
+ ```bash
120
+ cssprobe-cli open https://mysite.com --headed
121
+ # Browser opens -> complete login manually
122
+ cssprobe-cli state-save --name mysite
123
+ # Saves to ~/.cssprobe-cli/states/mysite.json
124
+
125
+ # Later, reuse the saved state
126
+ cssprobe-cli open https://mysite.com --state ~/.cssprobe-cli/states/mysite.json
127
+ cssprobe-cli inspect .target
128
+ ```
129
+
130
+ ### Option D: Merge Cookies into Existing State
118
131
 
119
132
  ```bash
120
133
  cssprobe-cli state-import new-cookies.txt --merge existing-state.json --out updated.json
121
134
  ```
122
135
 
123
- ### Option D: Open with Saved State
136
+ ### Option E: Open with Saved State
124
137
 
125
138
  ```bash
126
139
  # Import cookies first
@@ -217,10 +230,10 @@ confidence: DEFINITE 8 | INDEFINITE 0 | UNVERIFIABLE 1
217
230
  → Run `npm run build` in the cssprobe-cli project directory.
218
231
 
219
232
  **Cross-origin stylesheet blocked**
220
- → This is expected. Declared values from blocked sheets are marked UNVERIFIABLE. Computed values from getComputedStyle() are still accurate.
233
+ → This is expected. The report lists blocked stylesheet URLs (from CDN/cross-origin) with full paths. Declared values from those sheets are marked UNVERIFIABLE, but computed values from getComputedStyle() are still accurate.
221
234
 
222
235
  **Page needs login**
223
- → Use `cssprobe-cli open <url> --headed` for interactive login, or `cssprobe-cli state-import cookies.txt --name mysite` to import cookies.
236
+ → Use `cssprobe-cli open <url> --headed` for interactive login, then `cssprobe-cli state-save --name mysite` to save the session, or `cssprobe-cli state-import cookies.txt --name mysite` to import cookies.
224
237
 
225
238
  ---
226
239
 
@@ -251,6 +264,33 @@ npm install -g cssprobe-cli && npx playwright install chromium && cssprobe-cli i
251
264
 
252
265
  ---
253
266
 
267
+ ## Complementary Tool: cssgraph
268
+
269
+ cssprobe-cli answers **runtime** questions — what a page actually renders. For **static** questions about the source — where a class is defined, what cascades over it, which components reference it, what a change would affect — install [cssgraph](https://github.com/mack-peng/cssgraph). It builds a local SQLite knowledge graph of every className, property, variable, and at-rule from your stylesheets (CSS/SCSS/Less + JSX/TSX + templates), 100% local.
270
+
271
+ ```bash
272
+ npm install -g cssgraph # requires Node.js >= 22.5.0
273
+ cd your-project
274
+ cssgraph init # build the knowledge graph
275
+ ```
276
+
277
+ **Work together — static first, runtime to verify:**
278
+
279
+ ```bash
280
+ # 1. Static (cssgraph): locate definitions, cascade, impact
281
+ cssgraph explore .modal
282
+ cssgraph rule ".modal > .content"
283
+
284
+ # 2. Runtime (cssprobe-cli): confirm actual rendering
285
+ cssprobe-cli open https://example.com
286
+ cssprobe-cli inspect .modal
287
+ cssprobe-cli findings .modal
288
+ ```
289
+
290
+ cssgraph also ships an MCP server with 12 tools (`cssgraph_explore`, `cssgraph_callers`, `cssgraph_impact`, `cssgraph_rule`, …) so an agent can answer static CSS questions in one call. See [npm](https://www.npmjs.com/package/cssgraph) / [GitHub](https://github.com/mack-peng/cssgraph).
291
+
292
+ ---
293
+
254
294
  ## Done
255
295
 
256
296
  You now have programmatic control over CSS inspection. Analyze layout, detect overflow, check scroll behavior, verify anchors — all from a terminal an agent can automate.
package/llms.txt ADDED
@@ -0,0 +1,14 @@
1
+ # cssprobe-cli
2
+
3
+ > Runtime CSS probe — inspect layout, scroll, colors, backgrounds, fonts in a live browser. Returns DOM tree, ASCII layout diagram and confidence-classified findings for humans and AI agents.
4
+
5
+ ## Documentation
6
+
7
+ - [README](https://raw.githubusercontent.com/mack-peng/cssprobe-cli/main/README.md): overview, quick start, configuration
8
+ - [Installation guide](https://raw.githubusercontent.com/mack-peng/cssprobe-cli/main/docs/guide/installation.md): agent-friendly install and skill wiring (Claude Code, Cursor, Codex, …)
9
+ - [npm package](https://www.npmjs.com/package/cssprobe-cli): `npm install -g cssprobe-cli`
10
+
11
+ ## Optional
12
+
13
+ - [GitHub repository](https://github.com/mack-peng/cssprobe-cli): source code, issues, releases
14
+ - [cssgraph](https://github.com/mack-peng/cssgraph): companion static CSS knowledge graph for AI agents
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cssprobe-cli",
3
- "version": "0.2.24",
3
+ "version": "0.2.26",
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",
@@ -30,7 +30,9 @@
30
30
  "docs",
31
31
  "README.md",
32
32
  "LICENSE",
33
- "AGENTS.md"
33
+ "AGENTS.md",
34
+ "CHANGELOG.md",
35
+ "llms.txt"
34
36
  ],
35
37
  "engines": {
36
38
  "node": ">=18"