cssprobe-cli 0.2.6 → 0.2.7

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
@@ -2,9 +2,9 @@
2
2
 
3
3
  ## Project
4
4
 
5
- `cssprobe-cli` — Runtime CSS probe for layout/scroll/overflow/color/font inspection. Entrypoint: `bin/cssprobe-cli.js` → `require('../dist/index')`.
6
- Build: `npm run build` (= `tsc` + `esbuild` collector IIFE bundle + `tsx scripts/generate-help.ts`).
7
- Test: `npm test` (= `tsx --test tests/*.test.ts` — Node.js built-in test runner, 26 tests).
5
+ `cssprobe-cli` — Runtime CSS probe for layout/scroll/overflow/color/font inspection with session-based browser management. Entrypoint: `bin/cssprobe-cli.js` → `require('../dist/index')`.
6
+ Build: `npm run build` (= `tsc` + `esbuild` collector IIFE bundle + `esbuild` daemon entry + `tsx scripts/generate-help.ts`).
7
+ Test: `npm test` (= `tsx --test tests/*.test.ts` — Node.js built-in test runner, 45 tests).
8
8
  Dependencies: `playwright-core`, `zod`. Dev: `typescript`, `@types/node`, `tsx`, `esbuild`.
9
9
 
10
10
  ## Architecture
@@ -13,36 +13,73 @@ Dependencies: `playwright-core`, `zod`. Dev: `typescript`, `@types/node`, `tsx`,
13
13
  src/
14
14
  ├── index.ts # export { program } from './cli/program'
15
15
  ├── cli/
16
- │ ├── program.ts # Entry: minimist parse → dispatch → engine call
17
- │ ├── commands.ts # 10 command definitions — all Zod schemas
16
+ │ ├── program.ts # Entry: minimist parse → session command dispatch
17
+ │ ├── commands.ts # Command definitions — all Zod schemas
18
18
  │ ├── command.ts # declareCommand(), parseCommand() (Zod validation)
19
19
  │ ├── output.ts # TextOutput / JsonOutput strategy pattern
20
20
  │ └── minimist.ts # Arguments parser (forked from playwright-cli)
21
+ ├── daemon/
22
+ │ ├── session.ts # Session management (single session, Unix socket)
23
+ │ ├── daemon.ts # Daemon process: browser lifecycle + command execution
24
+ │ └── daemonEntry.ts # Daemon entry point (spawned as child process)
21
25
  ├── engine/
22
26
  │ ├── types.ts # Shared types: Snapshot, TreeNode, Finding, Confidence
23
27
  │ ├── collector.ts # Browser-side: DOM traversal, computed styles, declared values
24
28
  │ ├── analyzer.ts # Node-side: pure functions, confidence model, pattern detection
25
29
  │ └── renderer.ts # Markdown / JSON rendering
26
30
  ├── browser/
27
- │ └── launcher.ts # Playwright wrapper: launch, navigate, inject collector, state loading
28
- └── config/
29
- ├── config.ts # Config loader (CLI → env → ~/.cssprobe-clirc profiles)
30
- └── helpGenerator.ts # Build-time: Zod schemas → dist/help.json
31
+ │ └── launcher.ts # Playwright wrapper: launch, navigate, inject collector
32
+ ├── config/
33
+ │ ├── config.ts # Config loader (CLI → env → ~/.cssprobe-clirc profiles)
34
+ │ └── helpGenerator.ts # Build-time: Zod schemas → dist/help.json
35
+ └── utils/
36
+ └── socketConnection.ts # Socket communication (adapted from playwright-cli)
31
37
  ```
32
38
 
33
39
  ## Key Patterns
34
40
 
41
+ - **Session-based architecture**: Inspired by playwright-cli. `open` starts a daemon process, subsequent commands connect via Unix socket. Single session (default) mode.
42
+ - **Daemon process**: Long-running background process that manages the browser and executes commands. Communicates via Unix domain socket.
35
43
  - **Three-layer engine**: `collector.ts` (browser, esbuild IIFE) → `analyzer.ts` (Node, pure functions) → `renderer.ts` (Markdown/JSON). Collector only gathers facts; analyzer does inference with confidence; renderer formats output.
36
44
  - **Collector bundling**: `collector.ts` is bundled by esbuild as an IIFE (`format: 'iife', globalName: '__cssprobe-cli'`). The launcher injects it via `page.addScriptTag({ content })`, then calls `window.__cssprobe-cli.collect(cfg)`.
37
45
  - **Confidence model**: Every `Finding` carries `confidence: 'DEFINITE' | 'INDEFINITE' | 'UNVERIFIABLE'`. Computed values = DEFINITE. Percent declarations = INDEFINITE. Missing/blocked declarations = UNVERIFIABLE.
38
46
  - **Command definition**: `declareCommand({ name, category, description, args?, options? })` — purely declarative, no execution logic.
39
- - **Command dispatch**: `minimist` parse → `parseCommand()` Zod validate → `switch(commandName)` → handler function.
47
+ - **Command dispatch**: `minimist` parse → `parseCommand()` Zod validate → session command execution via daemon socket.
40
48
  - **Output strategy**: `Output` interface → `TextOutput` (Markdown for inspect, tables for lists) / `JsonOutput` (machine-readable JSON).
41
49
  - **Config priority**: CLI flags → env vars → `~/.cssprobe-clirc` profiles. Switch with `-p <profile>`.
42
- - **State management**: `--state <file>` loads Playwright storage state (cookies + localStorage). `state-import` converts Netscape cookies. `login` does interactive login + save state.
50
+ - **State management**: `state-import` converts Netscape cookies. Session persists browser state until `close`.
43
51
  - **Browser discovery**: `findBrowserExecutable()` scans `~/Library/Caches/ms-playwright/chromium-*` for existing Chrome installations.
44
52
  - **Error format**: `Error: <message>` → JSON mode: `{ isError: true, error: "<message>" }` → `process.exit(1)`
45
53
 
54
+ ## Commands
55
+
56
+ ### Session Management
57
+ - `open [url]` — Open browser in session mode (non-blocking)
58
+ - `close` — Close the browser session
59
+ - `status` — Show current session status
60
+
61
+ ### CSS Inspection
62
+ - `inspect <selector>` — Inspect runtime CSS of a page element
63
+ - `tree <selector>` — Show DOM tree structure
64
+ - `layout <selector>` — Show ASCII layout diagram
65
+ - `findings <selector>` — Show only issues/warnings/errors
66
+
67
+ ### CSS Injection
68
+ - `inject-css <css>` — Inject CSS into the current page
69
+
70
+ ### Browser
71
+ - `screenshot` — Take a screenshot
72
+ - `eval <expression>` — Evaluate JavaScript
73
+
74
+ ### State
75
+ - `state-import [file]` — Import cookies from Netscape format
76
+
77
+ ### Config
78
+ - `config-show` / `config-set` / `config-list` / `config-use` / `config-new` / `config-path`
79
+
80
+ ### Skills
81
+ - `skill-install` / `skill-uninstall`
82
+
46
83
  ## Adding a Command
47
84
 
48
85
  1. Add `declareCommand({...})` in `src/cli/commands.ts` following the existing pattern
@@ -57,11 +94,42 @@ src/
57
94
  npm run build
58
95
  ├── 1. tsc # Compile TS → dist/ (includes .d.ts)
59
96
  ├── 2. esbuild collector.ts # Bundle browser-side code → dist/collector-bundle.js (IIFE)
60
- └── 3. tsx generate-help.ts # Zod schemas → dist/help.json
97
+ ├── 3. esbuild daemonEntry.ts # Bundle daemon entry → dist/daemonEntry.js (CJS)
98
+ └── 4. tsx generate-help.ts # Zod schemas → dist/help.json
61
99
  ```
62
100
 
63
101
  The collector bundle is a self-contained IIFE that exposes `window.__cssprobe-cli.collect(cfg)`. It runs entirely in the browser context — no Node imports.
64
102
 
103
+ ## Session Mode
104
+
105
+ cssprobe-cli uses a session-based architecture inspired by playwright-cli:
106
+
107
+ ```bash
108
+ # Open browser (starts daemon, non-blocking)
109
+ cssprobe-cli open https://example.com
110
+
111
+ # User operates manually in the browser...
112
+
113
+ # Run CSS diagnosis
114
+ cssprobe-cli inspect .sidebar --json
115
+ cssprobe-cli tree .content --depth 3
116
+ cssprobe-cli layout .header
117
+
118
+ # Inject CSS to test changes
119
+ cssprobe-cli inject-css ".sidebar { background: red; }"
120
+
121
+ # Close browser (stops daemon)
122
+ cssprobe-cli close
123
+ ```
124
+
125
+ ### How It Works
126
+
127
+ 1. `open` spawns a daemon process that manages the browser
128
+ 2. Daemon listens on a Unix socket at `~/Library/Caches/cssprobe-cli/daemon/<hash>/default.sock`
129
+ 3. Subsequent commands connect to the socket and send commands
130
+ 4. Daemon executes commands using Playwright's browser API
131
+ 5. `close` stops the daemon and closes the browser
132
+
65
133
  ## What Makes This Different from dom-report
66
134
 
67
135
  | | dom-report (old) | cssprobe-cli (new) |
@@ -72,6 +140,6 @@ The collector bundle is a self-contained IIFE that exposes `window.__cssprobe-cl
72
140
  | Output | Single markdown string | Markdown (default) / JSON (--json) |
73
141
  | Config | `window.__DOM_REPORT_CFG` global + eval two-step | CLI flags → env → rc file, one command |
74
142
  | ROOT_SELECTOR | Manual or eval probe | `--auto-root` auto-detection |
75
- | Tests | None | 26 unit tests (command, analyzer, output) |
76
- | Build | Regex stripping CJS module.exports | esbuild IIFE bundle, clean build |
77
- | Auth | None | `--state`, `login`, `state-import` |
143
+ | Tests | None | 45 unit tests (command, analyzer, output, renderer) |
144
+ | Build | Regex stripping CJS module.exports | esbuild IIFE + CJS bundle, clean build |
145
+ | Session | None (blocking commands) | Session-based daemon architecture |
package/README.md CHANGED
@@ -23,100 +23,137 @@ cssprobe-cli skill-install
23
23
  ### 1. Inspect a Page
24
24
 
25
25
  ```bash
26
- # With explicit selector
27
- cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout ".container"
26
+ # Open browser (non-blocking, starts daemon session)
27
+ cssprobe-cli open https://getbootstrap.com/docs/5.3/examples/checkout
28
28
 
29
- # Auto-detect root element
30
- cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout
29
+ # Inspect with CSS selector
30
+ cssprobe-cli inspect .container
31
31
 
32
- # Local HTML file
33
- cssprobe-cli inspect ./test.html ".container"
32
+ # Show DOM tree
33
+ cssprobe-cli tree .container --depth 3
34
+
35
+ # Show ASCII layout diagram
36
+ cssprobe-cli layout .container
37
+
38
+ # Show only issues/warnings
39
+ cssprobe-cli findings .container
40
+
41
+ # Close browser when done
42
+ cssprobe-cli close
34
43
  ```
35
44
 
36
45
  ### 2. Login-Protected Pages
37
46
 
38
47
  ```bash
39
- # Import cookies from browser export (Netscape format)
40
- cssprobe-cli state-import cookies.txt --out ~/.cssprobe-cli/states/mysite.json
48
+ # Open browser in headed mode
49
+ cssprobe-cli open https://mysite.com --headed
41
50
 
42
- # Or interactive login
43
- cssprobe-cli login https://mysite.com
51
+ # User manually logs in...
44
52
 
45
- # Then inspect with state
46
- cssprobe-cli inspect https://mysite.com/page ".target" --state ~/.cssprobe-cli/states/mysite.json
53
+ # Run diagnosis on authenticated page
54
+ cssprobe-cli inspect .dashboard
47
55
 
48
- # Wait for user interaction before collecting (e.g. click a button to open a dialog)
49
- cssprobe-cli inspect https://mysite.com/page ".dialog" --state ~/.cssprobe-cli/states/mysite.json --wait
50
- ```
56
+ # Inject CSS to test changes
57
+ cssprobe-cli inject-css ".sidebar { background: #f0f0f0; }"
51
58
 
52
- ### 3. Interactive Mode
59
+ # Take screenshot
60
+ cssprobe-cli screenshot
53
61
 
54
- ```bash
55
- # Open browser and inspect interactively (REPL mode)
56
- cssprobe-cli interactive https://mysite.com --state ~/.cssprobe-cli/states/mysite.json
62
+ # Close when done
63
+ cssprobe-cli close
57
64
  ```
58
65
 
59
- Runtime commands:
60
- ```
61
- inspect> tree .dialog-A # DOM tree
62
- inspect> layout .sidebar-B # ASCII layout diagram
63
- inspect> sketch .content # Tree sketch (issues only)
64
- inspect> findings .modal # Findings only
65
- inspect> json .dialog-A # JSON output
66
- inspect> report .dialog-A # Full report
67
- inspect> .dialog-A # Shorthand for report
68
- inspect> navigate https://other.com # Navigate to new URL
69
- inspect> depth 10 # Set depth
70
- inspect> help # Show help
71
- inspect> quit # Exit
66
+ ### 3. Import Cookies
67
+
68
+ ```bash
69
+ # Import cookies from browser export (Netscape format)
70
+ cssprobe-cli state-import cookies.txt --out ~/.cssprobe-cli/states/mysite.json
72
71
  ```
73
72
 
74
73
  ### 4. JSON Output
75
74
 
76
75
  ```bash
77
- cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body --json
78
- cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body --json | jq '.findings[] | {id, confidence, message}'
76
+ cssprobe-cli open https://getbootstrap.com/docs/5.3/examples/checkout
77
+ cssprobe-cli inspect body --json
78
+ cssprobe-cli inspect body --json | jq '.findings[] | {id, confidence, message}'
79
+ cssprobe-cli close
79
80
  ```
80
81
 
81
82
  ---
82
83
 
83
- ## Output Modes
84
+ ## Session Mode
84
85
 
85
- | Flag | Output | Use Case |
86
- |------|--------|----------|
87
- | (default) | Markdown report with ancestor chain, DOM tree, findings | Terminal viewing |
88
- | `--json` | Structured JSON with snapshot, findings, confidence summary | Scripts, `jq` pipes, AI agent consumption |
89
- | `--brief` | Compact output: tree sketch + warnings/errors only | Quick overview |
90
- | `--layout` | ASCII layout diagram showing element positions and sizes | Visual layout inspection |
86
+ cssprobe-cli uses a session-based architecture for non-browser interaction:
87
+
88
+ ```bash
89
+ # Start session (opens browser, returns immediately)
90
+ cssprobe-cli open <url>
91
+
92
+ # Run commands (each command is independent, non-blocking)
93
+ cssprobe-cli inspect <selector>
94
+ cssprobe-cli tree <selector>
95
+ cssprobe-cli layout <selector>
96
+ cssprobe-cli findings <selector>
97
+ cssprobe-cli inject-css <css>
98
+ cssprobe-cli screenshot
99
+ cssprobe-cli eval <expression>
100
+
101
+ # Check session status
102
+ cssprobe-cli status
103
+
104
+ # End session (closes browser)
105
+ cssprobe-cli close
106
+ ```
91
107
 
92
108
  ---
93
109
 
94
110
  ## Commands
95
111
 
96
- ### Inspection
112
+ ### Session Management
113
+
114
+ ```bash
115
+ cssprobe-cli open [url] # Open browser in session mode (non-blocking)
116
+ cssprobe-cli close # Close browser session
117
+ cssprobe-cli status # Show session status
118
+ ```
119
+
120
+ ### CSS Inspection
121
+
122
+ ```bash
123
+ cssprobe-cli inspect <selector> # Full CSS diagnosis
124
+ cssprobe-cli tree <selector> # DOM tree structure
125
+ cssprobe-cli layout <selector> # ASCII layout diagram
126
+ cssprobe-cli findings <selector> # Only issues/warnings/errors
127
+ ```
128
+
129
+ ### CSS Injection
97
130
 
98
131
  ```bash
99
- cssprobe-cli inspect <url> [selector] # Inspect CSS layout
100
- cssprobe-cli interactive <url> # Interactive REPL mode
101
- cssprobe-cli login <url> # Interactive login, save state
102
- cssprobe-cli state-import [file] # Import cookies from Netscape format
132
+ cssprobe-cli inject-css <css> # Inject CSS into current page
103
133
  ```
104
134
 
105
- ### Inspection
135
+ ### Browser
106
136
 
107
137
  ```bash
108
- cssprobe-cli inspect https://getbootstrap.com/docs/5.3/examples/checkout body
138
+ cssprobe-cli screenshot # Take screenshot
139
+ cssprobe-cli eval <expression> # Evaluate JavaScript
140
+ ```
141
+
142
+ ### State
143
+
144
+ ```bash
145
+ cssprobe-cli state-import [file] # Import cookies from Netscape format
109
146
  ```
110
147
 
111
148
  ### Configuration
112
149
 
113
150
  ```bash
114
- cssprobe-cli config-show # Show current config
115
- cssprobe-cli config-set <key> <value> # Set config value
116
- cssprobe-cli config-list # List all profiles
117
- cssprobe-cli config-use <name> # Switch active profile
118
- cssprobe-cli config-new <name> # Create new profile
119
- cssprobe-cli config-path # Show config file path
151
+ cssprobe-cli config-show # Show current config
152
+ cssprobe-cli config-set <key> <value> # Set config value
153
+ cssprobe-cli config-list # List all profiles
154
+ cssprobe-cli config-use <name> # Switch active profile
155
+ cssprobe-cli config-new <name> # Create new profile
156
+ cssprobe-cli config-path # Show config file path
120
157
  ```
121
158
 
122
159
  ---
@@ -124,25 +161,41 @@ cssprobe-cli config-path # Show config file path
124
161
  ## inspect Options
125
162
 
126
163
  ```bash
127
- cssprobe-cli inspect <url> [selector] [options]
164
+ cssprobe-cli inspect <selector> [options]
128
165
 
129
166
  Arguments:
130
- <url> URL, file:// path, or local HTML file
131
- [selector] CSS selector for root (auto-detected if omitted)
167
+ <selector> CSS selector for root element
132
168
 
133
169
  Options:
134
170
  --json Output structured JSON
135
- --headed Show browser window
136
- --browser <engine> chromium|firefox|webkit (default chromium)
137
- --zoom Run 1x/0.5x viewport diagnosis
138
- --depth <n> DOM tree depth (default: auto)
139
- --max-nodes <n> Node count cap (default 60)
140
- --up-to <tag> Ancestor stop tag (default html)
141
- --state <file> Load saved state (cookies + localStorage)
142
171
  --brief Compact output: tree sketch + warnings/errors only
143
- --layout ASCII layout diagram showing element positions and sizes
144
- --wait Wait for user interaction before collecting (implies --headed)
145
- --viewport <WxH> Viewport size (e.g. 375x812, default 1280x720)
172
+ --layout ASCII layout diagram
173
+ --depth <n> DOM tree depth (default: auto, max 20)
174
+ ```
175
+
176
+ ---
177
+
178
+ ## tree Options
179
+
180
+ ```bash
181
+ cssprobe-cli tree <selector> [options]
182
+
183
+ Arguments:
184
+ <selector> CSS selector for root element
185
+
186
+ Options:
187
+ --depth <n> Tree depth (default: auto, max 20)
188
+ ```
189
+
190
+ ---
191
+
192
+ ## inject-css
193
+
194
+ ```bash
195
+ cssprobe-cli inject-css <css>
196
+
197
+ Arguments:
198
+ <css> CSS code to inject into the current page
146
199
  ```
147
200
 
148
201
  ---
@@ -248,8 +301,8 @@ cssprobe-cli skill-uninstall
248
301
 
249
302
  ```bash
250
303
  npm install
251
- npm run build # tsc + esbuild collector bundle + generate help.json
252
- npm test # Run unit tests
304
+ npm run build # tsc + esbuild collector + daemon entry + generate help.json
305
+ npm test # Run unit tests (45 tests)
253
306
  npx tsc --noEmit # Type check only
254
307
  ```
255
308
 
@@ -1,3 +1,4 @@
1
+ import { type Page } from 'playwright-core';
1
2
  import type { Snapshot, CollectConfig } from '../engine/types';
2
3
  export interface LauncherOptions {
3
4
  browser?: string;
@@ -32,5 +33,7 @@ export declare class BrowserLauncher {
32
33
  * Returns the path to the saved state file.
33
34
  */
34
35
  loginAndSave(url: string, statePath: string): Promise<string>;
36
+ /** Get the current page object. */
37
+ getPage(): Page | null;
35
38
  close(): Promise<void>;
36
39
  }
@@ -247,6 +247,10 @@ class BrowserLauncher {
247
247
  console.error(` State saved to: ${resolvedPath}`);
248
248
  return resolvedPath;
249
249
  }
250
+ /** Get the current page object. */
251
+ getPage() {
252
+ return this.page;
253
+ }
250
254
  async close() {
251
255
  if (this.context)
252
256
  await this.context.close().catch(() => { });
@@ -1,6 +1,6 @@
1
1
  import * as z from 'zod';
2
2
  import type zodType from 'zod';
3
- export type Category = 'core' | 'config' | 'skill';
3
+ export type Category = 'core' | 'config' | 'skill' | 'cssprobe' | 'export';
4
4
  export interface HelpEntry {
5
5
  help: string;
6
6
  flags: Record<string, 'boolean' | 'string'>;
@@ -4,51 +4,24 @@ export declare const commands: {
4
4
  [k: string]: AnyCommandSchema;
5
5
  };
6
6
  export declare const inspectCommand: import("./command").CommandSchema<z.ZodObject<{
7
- url: z.ZodString;
8
- selector: z.ZodOptional<z.ZodString>;
7
+ selector: z.ZodString;
9
8
  }, "strip", z.ZodTypeAny, {
10
- url: string;
11
- selector?: string | undefined;
9
+ selector: string;
12
10
  }, {
13
- url: string;
14
- selector?: string | undefined;
11
+ selector: string;
15
12
  }>, z.ZodObject<{
16
13
  json: z.ZodOptional<z.ZodBoolean>;
17
- headed: z.ZodOptional<z.ZodBoolean>;
18
- browser: z.ZodOptional<z.ZodEnum<["chromium", "firefox", "webkit"]>>;
19
- zoom: z.ZodOptional<z.ZodBoolean>;
20
- depth: z.ZodOptional<z.ZodEffects<z.ZodNumber, number, unknown>>;
21
- 'max-nodes': z.ZodOptional<z.ZodEffects<z.ZodNumber, number, unknown>>;
22
- 'up-to': z.ZodOptional<z.ZodString>;
23
- state: z.ZodOptional<z.ZodString>;
24
14
  brief: z.ZodOptional<z.ZodBoolean>;
25
15
  layout: z.ZodOptional<z.ZodBoolean>;
26
- wait: z.ZodOptional<z.ZodBoolean>;
27
- viewport: z.ZodOptional<z.ZodString>;
16
+ depth: z.ZodOptional<z.ZodEffects<z.ZodNumber, number, unknown>>;
28
17
  }, "strip", z.ZodTypeAny, {
29
18
  json?: boolean | undefined;
30
- headed?: boolean | undefined;
31
- browser?: "chromium" | "firefox" | "webkit" | undefined;
32
- zoom?: boolean | undefined;
33
- depth?: number | undefined;
34
- 'max-nodes'?: number | undefined;
35
- 'up-to'?: string | undefined;
36
- state?: string | undefined;
37
19
  brief?: boolean | undefined;
38
20
  layout?: boolean | undefined;
39
- wait?: boolean | undefined;
40
- viewport?: string | undefined;
21
+ depth?: number | undefined;
41
22
  }, {
42
23
  json?: boolean | undefined;
43
- headed?: boolean | undefined;
44
- browser?: "chromium" | "firefox" | "webkit" | undefined;
45
- zoom?: boolean | undefined;
46
- depth?: unknown;
47
- 'max-nodes'?: unknown;
48
- 'up-to'?: string | undefined;
49
- state?: string | undefined;
50
24
  brief?: boolean | undefined;
51
25
  layout?: boolean | undefined;
52
- wait?: boolean | undefined;
53
- viewport?: string | undefined;
26
+ depth?: unknown;
54
27
  }>>;