cssprobe-cli 0.1.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.
Files changed (44) hide show
  1. package/AGENTS.md +77 -0
  2. package/LICENSE +21 -0
  3. package/README.md +218 -0
  4. package/bin/cssprobe-cli.js +6 -0
  5. package/dist/browser/launcher.d.ts +25 -0
  6. package/dist/browser/launcher.js +213 -0
  7. package/dist/cli/command.d.ts +27 -0
  8. package/dist/cli/command.js +84 -0
  9. package/dist/cli/commands.d.ts +42 -0
  10. package/dist/cli/commands.js +166 -0
  11. package/dist/cli/minimist.d.ts +9 -0
  12. package/dist/cli/minimist.js +120 -0
  13. package/dist/cli/output.d.ts +26 -0
  14. package/dist/cli/output.js +80 -0
  15. package/dist/cli/program.d.ts +1 -0
  16. package/dist/cli/program.js +381 -0
  17. package/dist/collector-bundle.js +342 -0
  18. package/dist/config/config.d.ts +23 -0
  19. package/dist/config/config.js +128 -0
  20. package/dist/config/helpGenerator.d.ts +10 -0
  21. package/dist/config/helpGenerator.js +156 -0
  22. package/dist/engine/analyzer.d.ts +2 -0
  23. package/dist/engine/analyzer.js +385 -0
  24. package/dist/engine/collector.d.ts +3 -0
  25. package/dist/engine/collector.js +291 -0
  26. package/dist/engine/renderer.d.ts +3 -0
  27. package/dist/engine/renderer.js +159 -0
  28. package/dist/engine/types.d.ts +130 -0
  29. package/dist/engine/types.js +4 -0
  30. package/dist/help.json +107 -0
  31. package/dist/index.d.ts +1 -0
  32. package/dist/index.js +6 -0
  33. package/dist/installer/index.d.ts +3 -0
  34. package/dist/installer/index.js +12 -0
  35. package/dist/installer/skill-template.d.ts +9 -0
  36. package/dist/installer/skill-template.js +274 -0
  37. package/dist/installer/targets/registry.d.ts +9 -0
  38. package/dist/installer/targets/registry.js +121 -0
  39. package/dist/installer/targets/shared.d.ts +9 -0
  40. package/dist/installer/targets/shared.js +112 -0
  41. package/dist/installer/targets/types.d.ts +22 -0
  42. package/dist/installer/targets/types.js +3 -0
  43. package/docs/guide/installation.md +230 -0
  44. package/package.json +51 -0
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ // Renderer — pure functions: Snapshot + Finding[] → Markdown or JSON.
3
+ // No browser or filesystem access.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.renderMarkdown = renderMarkdown;
6
+ exports.renderJSON = renderJSON;
7
+ // ─── Node rendering (DOM tree) ───
8
+ function renderNode(node, indent) {
9
+ const lines = [];
10
+ if (!node)
11
+ return lines;
12
+ const cls = node.classes.length ? `.${node.classes.join('.')}` : '';
13
+ const id = node.id ? `#${node.id}` : '';
14
+ const repeat = node.repeat ? ` \u00D7${node.repeat}` : '';
15
+ const m = node.metrics;
16
+ const s = node.shape || {};
17
+ const flag = [];
18
+ if (node.flags.overflowsViewport)
19
+ flag.push('\u26A0viewport-overflow');
20
+ if (node.flags.overflowsParent)
21
+ flag.push('\u26A0parent-overflow');
22
+ if (m.clientHeight === 0 && m.offsetHeight === 0)
23
+ flag.push('\u26A0collapsed(0px)');
24
+ if (node.flags.scrollable)
25
+ flag.push('\u2714scrollable');
26
+ if (node.flags.hasScrollY && !node.flags.scrollable) {
27
+ flag.push(`\u26A0overflow(${m.scrollHeight}>${m.clientHeight})but-overflow=${node.props.overflowY}`);
28
+ }
29
+ if (node.containingBlockModifiers.length) {
30
+ flag.push(`CB:${node.containingBlockModifiers.join(' ')}`);
31
+ }
32
+ const styleHint = node.inlineStyle ? ` style="${node.inlineStyle}"` : '';
33
+ const h = node.props.height;
34
+ const heightStr = h === 'auto' ? `auto\u2192${m.offsetHeight}px` : `${h}`;
35
+ const w = node.props.width;
36
+ const widthStr = w === 'auto' ? `auto\u2192${m.clientWidth}px` : `${w}`;
37
+ const mhStr = node.declared && node.declared['max-height'] ? ` maxH:${node.declared['max-height'].map(x => x.value).join(';')}` : '';
38
+ const shapeStr = s.role ? `[${s.role}${s.scrollTag ? ' ' + s.scrollTag : ''} h:${s.heightStrategy} w:${s.widthStrategy}]` : '';
39
+ lines.push(`${' '.repeat(indent)}<${node.tag}${id}${cls}${styleHint}${repeat}> ${shapeStr} [${node.props.position},${node.props.display},h:${heightStr},w:${widthStr}${mhStr}] rect(${m.rect.width}\u00D7${m.rect.height}) bottom=${m.rectBottom} scroll=${m.clientHeight}/${m.scrollHeight}` +
40
+ (flag.length ? ` ${flag.join(' ')}` : '') +
41
+ (node.text ? ` \u300C${node.text.slice(0, 30)}\u300D` : ''));
42
+ for (const child of node.children) {
43
+ lines.push(...renderNode(child, indent + 1));
44
+ }
45
+ return lines;
46
+ }
47
+ function renderAncestors(chain) {
48
+ return chain.map(a => {
49
+ const dh = a.declared && a.declared.height ? a.declared.height.map(x => `${x.selector}\u2192${x.value}`).join('; ') : 'auto';
50
+ const dw = a.declared && a.declared.width ? a.declared.width.map(x => `${x.selector}\u2192${x.value}`).join('; ') : 'auto';
51
+ const mh = a.declared && a.declared['max-height'] ? a.declared['max-height'].map(x => `${x.selector}\u2192${x.value}`).join('; ') : null;
52
+ const maxPart = mh ? ` max-height:${mh}` : '';
53
+ const s = a.shape || {};
54
+ const shapeStr = s.role ? `[${s.role}${s.scrollTag ? ' ' + s.scrollTag : ''} h:${s.heightStrategy} w:${s.widthStrategy}]` : '';
55
+ return `${a.label} ${shapeStr} [${a.props.position},${a.props.display}] h:${dh}${maxPart} w:${dw} \u2192 ${a.metrics.clientWidth}\u00D7${a.metrics.offsetHeight}` +
56
+ (a.containingBlockModifiers.length ? ` CB:${a.containingBlockModifiers.join(' ')}` : '') +
57
+ (a.inlineStyle ? ` style="${a.inlineStyle}"` : '');
58
+ });
59
+ }
60
+ // ─── Findings rendering ───
61
+ const CONF_BADGE = {
62
+ DEFINITE: 'DEFINITE',
63
+ INDEFINITE: 'INDEFINITE',
64
+ UNVERIFIABLE: 'UNVERIFIABLE',
65
+ };
66
+ function renderFindings(findings) {
67
+ const lines = [];
68
+ lines.push('## Findings');
69
+ if (findings.length === 0) {
70
+ lines.push('- 无异常发现');
71
+ return lines;
72
+ }
73
+ for (const f of findings) {
74
+ const badge = `[${CONF_BADGE[f.confidence]}]`;
75
+ const loc = f.location ? ` @ ${f.location}` : '';
76
+ lines.push(`- ${f.level === 'error' ? '\u26A0' : f.level === 'warning' ? '\u26A0' : '\u2714'} ${f.message} ${badge}${loc}`);
77
+ for (const ev of f.evidence.slice(0, 3)) {
78
+ if (ev.type === 'computed') {
79
+ lines.push(` - computed ${ev.property}: ${ev.value}`);
80
+ }
81
+ else if (ev.type === 'declared') {
82
+ lines.push(` - declared ${ev.property}: ${ev.value} (${ev.source || '?'})${ev.accessible ? '' : ' [inaccessible]'}`);
83
+ }
84
+ }
85
+ }
86
+ return lines;
87
+ }
88
+ function confidenceSummary(findings) {
89
+ const counts = findings.reduce((acc, f) => {
90
+ acc[f.confidence] = (acc[f.confidence] || 0) + 1;
91
+ return acc;
92
+ }, {});
93
+ const parts = [
94
+ `DEFINITE ${counts.DEFINITE || 0}`,
95
+ `INDEFINITE ${counts.INDEFINITE || 0}`,
96
+ `UNVERIFIABLE ${counts.UNVERIFIABLE || 0}`,
97
+ ];
98
+ return parts.join(' | ');
99
+ }
100
+ // ─── Markdown ───
101
+ function renderMarkdown(snapshot, findings) {
102
+ const lines = [];
103
+ const vp = snapshot.viewport ? `${snapshot.viewport.width}\u00D7${snapshot.viewport.height}` : 'unknown';
104
+ lines.push('# cssprobe-cli report');
105
+ lines.push(`viewport: ${vp} | root: ${snapshot.rootSelector} | nodes: ${snapshot.nodeCount}`);
106
+ lines.push(`confidence: ${confidenceSummary(findings)}`);
107
+ if (snapshot.error) {
108
+ lines.push('');
109
+ lines.push(`\u26A0 ${snapshot.error}`);
110
+ if (snapshot.candidates && snapshot.candidates.length) {
111
+ lines.push(`Similar nodes: ${snapshot.candidates.join(', ')}`);
112
+ }
113
+ return lines.join('\n');
114
+ }
115
+ lines.push('');
116
+ lines.push(`## Ancestor chain (root\u2192${snapshot.upTo})`);
117
+ lines.push('```');
118
+ lines.push(...renderAncestors(snapshot.ancestors));
119
+ lines.push('```');
120
+ 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));
127
+ if (snapshot.crossOriginBlocked && snapshot.crossOriginBlocked > 0) {
128
+ lines.push('');
129
+ lines.push('## Cross-origin limitation');
130
+ 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.`);
131
+ if (snapshot.blockedSheetUrls && snapshot.blockedSheetUrls.length > 0) {
132
+ lines.push(`Blocked: ${snapshot.blockedSheetUrls.join(', ')}`);
133
+ }
134
+ }
135
+ return lines.join('\n');
136
+ }
137
+ // ─── JSON ───
138
+ function renderJSON(snapshot, findings) {
139
+ const counts = findings.reduce((acc, f) => {
140
+ acc[f.confidence] = (acc[f.confidence] || 0) + 1;
141
+ return acc;
142
+ }, {});
143
+ return {
144
+ meta: {
145
+ rootSelector: snapshot.rootSelector,
146
+ viewport: snapshot.viewport,
147
+ nodeCount: snapshot.nodeCount,
148
+ crossOriginBlocked: snapshot.crossOriginBlocked,
149
+ blockedSheetUrls: snapshot.blockedSheetUrls,
150
+ },
151
+ snapshot: snapshot.error ? { error: snapshot.error, candidates: snapshot.candidates } : snapshot,
152
+ findings,
153
+ summary: {
154
+ total: findings.length,
155
+ confidence: { DEFINITE: counts.DEFINITE || 0, INDEFINITE: counts.INDEFINITE || 0, UNVERIFIABLE: counts.UNVERIFIABLE || 0 },
156
+ },
157
+ };
158
+ }
159
+ //# sourceMappingURL=renderer.js.map
@@ -0,0 +1,130 @@
1
+ export interface Rect {
2
+ x: number;
3
+ y: number;
4
+ width: number;
5
+ height: number;
6
+ }
7
+ export interface Metrics {
8
+ rect: Rect;
9
+ rectBottom: number;
10
+ rectRight: number;
11
+ offsetHeight: number;
12
+ clientHeight: number;
13
+ scrollHeight: number;
14
+ clientWidth: number;
15
+ scrollWidth: number;
16
+ }
17
+ export interface Flags {
18
+ overflowsViewport: boolean;
19
+ overflowsParent: boolean;
20
+ hasScrollY: boolean;
21
+ hasScrollX: boolean;
22
+ scrollable: boolean;
23
+ }
24
+ /** A declared value found in a stylesheet rule, with provenance. */
25
+ export interface DeclaredValue {
26
+ selector: string;
27
+ value: string;
28
+ href: string;
29
+ /** Whether the owning stylesheet was readable (cross-origin sheets are not). */
30
+ accessible: boolean;
31
+ }
32
+ export interface NodeProps {
33
+ position: string;
34
+ display: string;
35
+ height: string;
36
+ width: string;
37
+ minHeight: string;
38
+ maxHeight: string;
39
+ overflowY: string;
40
+ overflowX: string;
41
+ boxSizing: string;
42
+ flexDirection: string;
43
+ flexGrow: string;
44
+ flexShrink: string;
45
+ flexBasis: string;
46
+ minWidth?: string;
47
+ opacity?: string;
48
+ visibility?: string;
49
+ zIndex?: string;
50
+ margin?: string;
51
+ padding?: string;
52
+ transform?: string;
53
+ filter?: string;
54
+ perspective?: string;
55
+ willChange?: string;
56
+ contain?: string;
57
+ [key: string]: string | undefined;
58
+ }
59
+ export interface ShapeInfo {
60
+ role: string;
61
+ scrollTag: string;
62
+ heightStrategy: string;
63
+ widthStrategy: string;
64
+ isFlexChild: boolean;
65
+ }
66
+ export interface TreeNode {
67
+ tag: string;
68
+ id: string | null;
69
+ classes: string[];
70
+ inlineStyle: string | null;
71
+ text: string;
72
+ props: NodeProps;
73
+ declared: Record<string, DeclaredValue[]>;
74
+ shape: ShapeInfo;
75
+ metrics: Metrics;
76
+ flags: Flags;
77
+ containingBlockModifiers: string[];
78
+ children: TreeNode[];
79
+ repeat?: number;
80
+ }
81
+ export interface AncestorNode {
82
+ label: string;
83
+ props: NodeProps;
84
+ metrics: Metrics;
85
+ flags: Flags;
86
+ declared: Record<string, DeclaredValue[]>;
87
+ shape: ShapeInfo;
88
+ containingBlockModifiers: string[];
89
+ inlineStyle: string | null;
90
+ }
91
+ export interface CollectConfig {
92
+ rootSelector: string;
93
+ upTo: string;
94
+ downDepth: number;
95
+ maxNodes: number;
96
+ }
97
+ export interface ViewportSize {
98
+ width: number;
99
+ height: number;
100
+ }
101
+ export interface Snapshot {
102
+ rootSelector: string;
103
+ upTo: string;
104
+ downDepth: number;
105
+ maxNodes: number;
106
+ nodeCount: number;
107
+ viewport: ViewportSize;
108
+ ancestors: AncestorNode[];
109
+ tree: TreeNode | null;
110
+ crossOriginBlocked: number;
111
+ blockedSheetUrls: string[];
112
+ error?: string;
113
+ candidates?: string[];
114
+ }
115
+ export type Confidence = 'DEFINITE' | 'INDEFINITE' | 'UNVERIFIABLE';
116
+ export interface Evidence {
117
+ type: 'computed' | 'declared' | 'pattern';
118
+ property?: string;
119
+ value?: string;
120
+ source?: string;
121
+ accessible?: boolean;
122
+ }
123
+ export interface Finding {
124
+ id: string;
125
+ level: 'info' | 'warning' | 'error';
126
+ message: string;
127
+ confidence: Confidence;
128
+ evidence: Evidence[];
129
+ location?: string;
130
+ }
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ // ─── Shared types: contract between collector (browser), analyzer (node), renderer (node) ───
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ //# sourceMappingURL=types.js.map
package/dist/help.json ADDED
@@ -0,0 +1,107 @@
1
+ {
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
+ "commands": {
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",
6
+ "flags": {
7
+ "json": "boolean",
8
+ "headed": "boolean",
9
+ "browser": "string",
10
+ "zoom": "boolean",
11
+ "depth": "string",
12
+ "max-nodes": "string",
13
+ "up-to": "string",
14
+ "state": "string"
15
+ },
16
+ "args": [
17
+ "url",
18
+ "selector"
19
+ ]
20
+ },
21
+ "login": {
22
+ "help": "cssprobe-cli login <url>\n\nOpen browser for interactive login, then save state for later use\n\nArguments:\n <url> url, file:// path, or local html file path\nOptions:\n --browser browser engine (default chromium)\n --out output state file path (default: ~/.cssprobe-cli/states/<domain>.json)\n\nGlobal options:\n --json output as JSON\n --profile, -p <name> use named profile",
23
+ "flags": {
24
+ "browser": "string",
25
+ "out": "string"
26
+ },
27
+ "args": [
28
+ "url"
29
+ ]
30
+ },
31
+ "state-import": {
32
+ "help": "cssprobe-cli state-import [file]\n\nImport cookies from Netscape format file into a Playwright state file\n\nArguments:\n [file] netscape cookie file path (reads from stdin if omitted)\nOptions:\n --out output state file path (default: ~/.cssprobe-cli/states/imported.json)\n --merge existing state file to merge into\n\nGlobal options:\n --json output as JSON\n --profile, -p <name> use named profile",
33
+ "flags": {
34
+ "out": "string",
35
+ "merge": "string"
36
+ },
37
+ "args": [
38
+ "file"
39
+ ]
40
+ },
41
+ "config-show": {
42
+ "help": "cssprobe-cli config-show \n\nShow current configuration\n\nOptions:\n --profile profile name",
43
+ "flags": {
44
+ "profile": "string"
45
+ },
46
+ "args": []
47
+ },
48
+ "config-set": {
49
+ "help": "cssprobe-cli config-set <key> <value>\n\nSet a configuration value\n\nArguments:\n <key> config key (browser, depth, headed)\n <value> config value\nOptions:\n --profile profile name",
50
+ "flags": {
51
+ "profile": "string"
52
+ },
53
+ "args": [
54
+ "key",
55
+ "value"
56
+ ]
57
+ },
58
+ "config-list": {
59
+ "help": "cssprobe-cli config-list \n\nList all profiles\n",
60
+ "flags": {},
61
+ "args": []
62
+ },
63
+ "config-use": {
64
+ "help": "cssprobe-cli config-use <name>\n\nSwitch active profile\n\nArguments:\n <name> profile name",
65
+ "flags": {},
66
+ "args": [
67
+ "name"
68
+ ]
69
+ },
70
+ "config-new": {
71
+ "help": "cssprobe-cli config-new <name>\n\nCreate a new profile\n\nArguments:\n <name> profile name",
72
+ "flags": {},
73
+ "args": [
74
+ "name"
75
+ ]
76
+ },
77
+ "config-path": {
78
+ "help": "cssprobe-cli config-path \n\nShow configuration file path\n",
79
+ "flags": {},
80
+ "args": []
81
+ },
82
+ "skill-install": {
83
+ "help": "cssprobe-cli skill-install \n\nInstall Agent Skill for cssprobe-cli (teaches agents how to use the CLI)\n\nOptions:\n --target agent target: auto, all, opencode, claude, codex, cursor, hermes, gemini (default: auto)\n --local install to current directory instead of home\n --path custom base directory (overrides home/current)\n\nGlobal options:\n --json output as JSON\n --profile, -p <name> use named profile",
84
+ "flags": {
85
+ "target": "string",
86
+ "local": "boolean",
87
+ "path": "string"
88
+ },
89
+ "args": []
90
+ },
91
+ "skill-uninstall": {
92
+ "help": "cssprobe-cli skill-uninstall \n\nRemove Agent Skill for cssprobe-cli\n\nOptions:\n --target agent target: auto, all, opencode, claude, codex, cursor, hermes, gemini (default: auto)\n --local remove from current directory instead of home\n --path custom base directory\n\nGlobal options:\n --json output as JSON\n --profile, -p <name> use named profile",
93
+ "flags": {
94
+ "target": "string",
95
+ "local": "boolean",
96
+ "path": "string"
97
+ },
98
+ "args": []
99
+ }
100
+ },
101
+ "booleanOptions": [
102
+ "json",
103
+ "headed",
104
+ "zoom",
105
+ "local"
106
+ ]
107
+ }
@@ -0,0 +1 @@
1
+ export { program } from './cli/program';
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.program = void 0;
4
+ var program_1 = require("./cli/program");
5
+ Object.defineProperty(exports, "program", { enumerable: true, get: function () { return program_1.program; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,3 @@
1
+ export { buildSkillMd, buildPitfallsMd } from './skill-template';
2
+ export { ALL_TARGETS, getTarget, listTargetIds, resolveTargetFlag } from './targets/registry';
3
+ export type { AgentTarget, Location, TargetId, WriteResult } from './targets/types';
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveTargetFlag = exports.listTargetIds = exports.getTarget = exports.ALL_TARGETS = exports.buildPitfallsMd = exports.buildSkillMd = void 0;
4
+ var skill_template_1 = require("./skill-template");
5
+ Object.defineProperty(exports, "buildSkillMd", { enumerable: true, get: function () { return skill_template_1.buildSkillMd; } });
6
+ Object.defineProperty(exports, "buildPitfallsMd", { enumerable: true, get: function () { return skill_template_1.buildPitfallsMd; } });
7
+ var registry_1 = require("./targets/registry");
8
+ Object.defineProperty(exports, "ALL_TARGETS", { enumerable: true, get: function () { return registry_1.ALL_TARGETS; } });
9
+ Object.defineProperty(exports, "getTarget", { enumerable: true, get: function () { return registry_1.getTarget; } });
10
+ Object.defineProperty(exports, "listTargetIds", { enumerable: true, get: function () { return registry_1.listTargetIds; } });
11
+ Object.defineProperty(exports, "resolveTargetFlag", { enumerable: true, get: function () { return registry_1.resolveTargetFlag; } });
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * cssprobe-cli-cli Agent Skill templates.
3
+ *
4
+ * Installed into agent-specific skill directories via `cssprobe-cli-cli skill-install`.
5
+ * Teaches agents how to use cssprobe-cli-cli for runtime CSS inspection — layout,
6
+ * scroll, overflow, colors, backgrounds, fonts — with confidence levels.
7
+ */
8
+ export declare function buildSkillMd(): string;
9
+ export declare function buildPitfallsMd(): string;