crawlio-browser 1.6.2 → 1.6.4

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.
@@ -1,64 +1,103 @@
1
1
  ---
2
2
  name: monitor
3
- description: "Monitor a URL for changes — baseline capture, re-capture, diff report"
4
- allowed-tools: Agent, Read, Write, Bash, Glob, Grep
5
- argument-hint: <url>
3
+ description: "Monitor a page for changes — capture baseline, recapture, diff, report what changed"
4
+ allowed-tools: mcp__crawlio-browser__search, mcp__crawlio-browser__execute, mcp__crawlio-browser__connect_tab
6
5
  ---
7
6
 
8
- # Monitor Investigation
9
-
10
- You are running a **monitor** investigation. Your goal is to capture a baseline snapshot of the target URL, re-capture it, and produce a `DiffReport` showing what changed between the two captures.
11
-
12
- ## Loop Definition
13
-
14
- Read `loops/monitor.json` to understand the phase sequence. The monitor loop has 3 phases:
15
-
16
- 1. **baseline** Spawn `crawlio-crawler` to capture the target URL. Record the `EVIDENCE_ID`.
17
- 2. **recapture** — Spawn `crawlio-crawler` again with the same URL. Record the second `EVIDENCE_ID`.
18
- 3. **diff** — Spawn `crawlio-differ` with both evidence IDs. It reads both `EvidenceEnvelope<PageEvidence>` files, compares them field by field across 10 dimensions, and writes an `EvidenceEnvelope<DiffReport>`.
19
-
20
- ## Execution
21
-
22
- 1. Read `loops/monitor.json` to confirm phase order.
23
- 2. Spawn `crawlio-crawler` for the baseline capture:
24
- ```
25
- Crawl <url> and write PageEvidence to .crawlio/evidence/.
26
- ```
27
- Record `EVIDENCE_ID=<baselineId>`.
28
-
29
- 3. Spawn `crawlio-crawler` for the recapture:
30
- ```
31
- Crawl <url> and write PageEvidence to .crawlio/evidence/.
32
- ```
33
- Record `EVIDENCE_ID=<currentId>`.
34
-
35
- 4. Spawn `crawlio-differ` with both evidence IDs:
36
- ```
37
- Compare baseline evidence <baselineId> against current evidence <currentId> for <url>.
38
- Read both from .crawlio/evidence/. Write EvidenceEnvelope<DiffReport> to .crawlio/evidence/.
39
- ```
40
- Record `EVIDENCE_ID=<diffId>`.
41
-
42
- 5. Read the DiffReport evidence and summarize changes for the user.
43
-
44
- ## Output Format
45
-
7
+ # Monitor — Change Detection
8
+
9
+ Capture a baseline snapshot, recapture later, diff the results. Report structural, content, technology, and performance changes as structured findings.
10
+
11
+ ## When to Use
12
+
13
+ - Tracking what changed on a page between two points in time
14
+ - Detecting content additions/removals, tech stack changes, performance regressions
15
+ - Verifying a deploy changed what was expected (and nothing else)
16
+
17
+ ## Protocol
18
+
19
+ 1. **search** for diff and snapshot commands: `search("diff snapshot")`
20
+ 2. **connect_tab** to the target URL
21
+ 3. **execute** Code Mode: baseline with `smart.snapshot()` + `smart.extractPage()`
22
+ 4. On recapture, diff and emit one `smart.finding()` per change dimension
23
+ 5. Return `smart.findings()` as the final output
24
+
25
+ ## Code Example
26
+
27
+ ```js
28
+ // 1. Baseline
29
+ const baselineSnap = await smart.snapshot();
30
+ const baseline = await smart.extractPage();
31
+ const baselineTech = await smart.detectTechnologies();
32
+
33
+ // ... user triggers recapture ...
34
+
35
+ // 2. Recapture + diff
36
+ const current = await smart.extractPage();
37
+ const currentTech = await smart.detectTechnologies();
38
+ const diff = await smart.diffSnapshots(baselineSnap.snapshot);
39
+
40
+ smart.finding({
41
+ claim: `${diff.additions} elements added, ${diff.removals} removed since baseline`,
42
+ evidence: [`additions: ${diff.additions}`, `removals: ${diff.removals}`, `unchanged: ${diff.unchanged}`],
43
+ sourceUrl: current.capture.url,
44
+ confidence: "high",
45
+ method: "diffSnapshots",
46
+ dimension: "structure"
47
+ });
48
+
49
+ if (diff.additions > 0 || diff.removals > 0) {
50
+ smart.finding({
51
+ claim: `Content changed: ${diff.additions + diff.removals} total mutations`,
52
+ evidence: diff.sample || [`${diff.additions} added`, `${diff.removals} removed`],
53
+ sourceUrl: current.capture.url, confidence: "high",
54
+ method: "diffSnapshots", dimension: "content"
55
+ });
56
+ }
57
+
58
+ // Technology changes
59
+ const oldTech = new Set(baselineTech.technologies?.map(t => t.name) || []);
60
+ const newTech = new Set(currentTech.technologies?.map(t => t.name) || []);
61
+ const added = [...newTech].filter(t => !oldTech.has(t));
62
+ const removed = [...oldTech].filter(t => !newTech.has(t));
63
+ if (added.length || removed.length) {
64
+ smart.finding({
65
+ claim: `Tech stack changed: +${added.length} -${removed.length}`,
66
+ evidence: [...added.map(t => `added: ${t}`), ...removed.map(t => `removed: ${t}`)],
67
+ sourceUrl: current.capture.url, confidence: "high",
68
+ method: "detectTechnologies", dimension: "technology"
69
+ });
70
+ }
71
+
72
+ // Performance regression check
73
+ const oldLcp = baseline.performance?.webVitals?.lcp;
74
+ const newLcp = current.performance?.webVitals?.lcp;
75
+ if (oldLcp && newLcp) {
76
+ const delta = newLcp - oldLcp;
77
+ smart.finding({
78
+ claim: delta > 100 ? `LCP regressed by ${delta}ms` : `LCP stable (delta: ${delta}ms)`,
79
+ evidence: [`baseline: ${oldLcp}ms`, `current: ${newLcp}ms`],
80
+ sourceUrl: current.capture.url, confidence: "high",
81
+ method: "extractPage", dimension: "performance"
82
+ });
83
+ }
84
+
85
+ await smart.scrollCapture();
86
+ return { findings: smart.findings(), diff: { added: diff.additions, removed: diff.removals } };
46
87
  ```
47
- ## Monitor: <url>
48
88
 
49
- ### Changes Detected
50
- - [List of DiffChange entries grouped by dimension]
89
+ ## Anti-Patterns
51
90
 
52
- ### Summary
53
- - Total changes: N
54
- - Breaking changes: N
55
- - Dimensions affected: [list]
91
+ - Do NOT use `sleep()` loops to poll for changes — capture baseline, wait for user signal, recapture
92
+ - Do NOT compare screenshots visually — use `smart.diffSnapshots()` for structural diff
93
+ - Do NOT use `location.href` — use `current.capture.url` from extractPage
94
+ - Always `search()` first to confirm diff commands exist
56
95
 
57
- ### Evidence Chain
58
- - Baseline: <baselineId> (quality: ...)
59
- - Current: <currentId> (quality: ...)
60
- - Diff: <diffId> (quality: ...)
96
+ ## Output
61
97
 
62
- ### Confidence
63
- - Overall: high/medium/low
64
- ```
98
+ The skill produces `Finding[]` via `smart.findings()`. Dimension tags:
99
+
100
+ - **structure** — DOM elements added or removed
101
+ - **content** — text and media mutations
102
+ - **technology** — frameworks added or removed
103
+ - **performance** — LCP, CLS, timing regressions or improvements
@@ -1,101 +1,117 @@
1
1
  ---
2
2
  name: test
3
- description: "Automated testing — accessibility, performance, security, SEO, and best-practices audits with testable flow discovery"
4
- allowed-tools: Agent, Read, Write, Bash, Glob, Grep
5
- argument-hint: <url>
3
+ description: "Test a page against quality assertions — accessibility, performance, security, SEO, mobile readiness"
4
+ allowed-tools: mcp__crawlio-browser__search, mcp__crawlio-browser__execute, mcp__crawlio-browser__connect_tab
6
5
  ---
7
6
 
8
- # Test Investigation
9
-
10
- You are running a **test** investigation. Your goal is to audit a target URL across accessibility, performance, security, SEO, and best-practices categories, discover testable user flows, and produce a `TestSuite` evidence report.
11
-
12
- ## Loop Definition
13
-
14
- Read `loops/test.json` to understand the phase sequence. The test loop has 5 phases:
15
-
16
- 1. **crawl** — Spawn `crawlio-crawler` to capture the target URL. Record the `EVIDENCE_ID`.
17
- 2. **analyze** — Spawn `crawlio-analyzer` with the crawl evidence ID. Identifies framework and rendering mode to inform test strategy.
18
- 3. **audit** — Spawn `crawlio-auditor` with the crawl evidence ID. Runs accessibility, performance, security, SEO, and best-practices checks.
19
- 4. **discover-flows** (optional) Spawn `crawlio-auditor` with the crawl evidence ID and flow discovery focus. Discovers testable user flows from navigation/forms.
20
- 5. **synthesize** — Spawn `crawlio-synthesizer` with all phase evidence to produce the final `TestSuite`.
21
-
22
- ## Execution
23
-
24
- 1. Read `loops/test.json` to confirm phase order.
25
- 2. Parse the user's argument: `<url>`.
26
- 3. Spawn `crawlio-crawler` to capture the page:
27
- ```
28
- Crawl <url> and write PageEvidence to .crawlio/evidence/.
29
- ```
30
- Record `EVIDENCE_ID=<crawlId>`.
31
-
32
- 4. Spawn `crawlio-analyzer` with the crawl evidence:
33
- ```
34
- Read PageEvidence from .crawlio/evidence/<crawlId>.json.
35
- Analyze framework, rendering mode, and component patterns.
36
- Write FrameworkEvidence to .crawlio/evidence/.
37
- Target URL: <url>
38
- ```
39
- Record `EVIDENCE_ID=<analyzeId>`.
40
-
41
- 5. Spawn `crawlio-auditor` to run audits:
42
- ```
43
- Read PageEvidence from .crawlio/evidence/<crawlId>.json.
44
- Run accessibility, performance, security, SEO, and best-practices audits.
45
- Discover testable user flows from navigation and forms.
46
- Write TestSuite evidence to .crawlio/evidence/.
47
- Target URL: <url>
48
- ```
49
- Record `EVIDENCE_ID=<auditId>`.
50
-
51
- 6. Spawn `crawlio-synthesizer` to produce the final TestSuite:
52
- ```
53
- Read all evidence: <crawlId>, <analyzeId>, <auditId>.
54
- Produce a TestSuite with audit results, discovered flows, and overall score.
55
- Write to .crawlio/evidence/.
56
- Target URL: <url>
57
- ```
58
- Record `EVIDENCE_ID=<suiteId>`.
59
-
60
- 7. Read the TestSuite evidence and summarize results for the user.
61
-
62
- ## Output Format
63
-
7
+ # Test — Quality Assertions
8
+
9
+ Run pass/fail assertions across accessibility, performance, security, SEO, and mobile readiness. Every assertion becomes a finding. Confidence auto-caps when data is missing.
10
+
11
+ ## When to Use
12
+
13
+ - Auditing accessibility, performance, security, SEO, or mobile readiness
14
+ - Running pass/fail assertions against quality thresholds
15
+
16
+ ## Protocol
17
+
18
+ 1. **search** for extraction commands: `search("extract page accessibility")`
19
+ 2. **connect_tab** to the target URL
20
+ 3. **execute** Code Mode: `smart.extractPage()` gathers all dimensions in one call
21
+ 4. Emit one `smart.finding()` per assertion — claim states pass or fail
22
+ 5. Return `smart.findings()` + `page.gaps`
23
+
24
+ ## Code Example
25
+
26
+ ```js
27
+ const page = await smart.extractPage();
28
+
29
+ // Accessibility
30
+ if (page.accessibility) {
31
+ smart.finding({
32
+ claim: page.accessibility.imagesWithoutAlt === 0
33
+ ? "All images have alt text"
34
+ : `${page.accessibility.imagesWithoutAlt} images missing alt text`,
35
+ evidence: [`imagesWithoutAlt: ${page.accessibility.imagesWithoutAlt}`, `nodeCount: ${page.accessibility.nodeCount}`],
36
+ sourceUrl: page.capture.url, confidence: "high",
37
+ method: "extractPage", dimension: "accessibility"
38
+ });
39
+ smart.finding({
40
+ claim: page.accessibility.landmarkCount > 0
41
+ ? `${page.accessibility.landmarkCount} ARIA landmarks found`
42
+ : "No ARIA landmarks — add banner, main, contentinfo",
43
+ evidence: [`landmarkCount: ${page.accessibility.landmarkCount}`],
44
+ sourceUrl: page.capture.url, confidence: "high",
45
+ method: "extractPage", dimension: "accessibility"
46
+ });
47
+ }
48
+
49
+ // Performance
50
+ if (page.performance) {
51
+ const lcp = page.performance.webVitals?.lcp;
52
+ const cls = page.performance.webVitals?.cls;
53
+ smart.finding({
54
+ claim: lcp && lcp < 2500 ? `LCP good (${lcp}ms)` : `LCP needs work (${lcp || "unknown"}ms)`,
55
+ evidence: [`LCP: ${lcp}ms`, `CLS: ${cls}`, `thresholds: LCP<2500, CLS<0.1`],
56
+ sourceUrl: page.capture.url, confidence: lcp ? "high" : "low",
57
+ method: "extractPage", dimension: "performance"
58
+ });
59
+ }
60
+
61
+ // Security
62
+ if (page.security) {
63
+ smart.finding({
64
+ claim: page.security.securityState === "secure"
65
+ ? "TLS connection is secure" : `Security state: ${page.security.securityState || "unknown"}`,
66
+ evidence: [`protocol: ${page.security.protocol || "unknown"}`],
67
+ sourceUrl: page.capture.url, confidence: "high",
68
+ method: "extractPage", dimension: "security"
69
+ });
70
+ }
71
+
72
+ // SEO
73
+ if (page.capture?.meta) {
74
+ const m = page.capture.meta;
75
+ smart.finding({
76
+ claim: m.title && m.description ? "Title + meta description present" : "SEO meta tags incomplete",
77
+ evidence: [`title: ${m.title || "missing"} (${m.title?.length || 0} chars)`,
78
+ `description: ${m.description || "missing"} (${m.description?.length || 0} chars)`],
79
+ sourceUrl: page.capture.url, confidence: "high",
80
+ method: "extractPage", dimension: "seo"
81
+ });
82
+ }
83
+
84
+ // Mobile readiness
85
+ if (page.mobileReadiness) {
86
+ smart.finding({
87
+ claim: page.mobileReadiness.hasViewportMeta ? "Viewport meta tag present" : "Missing viewport meta",
88
+ evidence: [`viewport: ${page.mobileReadiness.viewportContent || "none"}`],
89
+ sourceUrl: page.capture.url, confidence: "high",
90
+ method: "extractPage", dimension: "mobile-readiness"
91
+ });
92
+ }
93
+
94
+ // Tech stack
95
+ const tech = await smart.detectTechnologies();
96
+ if (tech.technologies?.length) {
97
+ smart.finding({
98
+ claim: `${tech.technologies.length} technologies detected`,
99
+ evidence: tech.technologies.map(t => t.name),
100
+ sourceUrl: page.capture.url, confidence: "high",
101
+ method: "detectTechnologies", dimension: "technology"
102
+ });
103
+ }
104
+
105
+ return { findings: smart.findings(), gaps: page.gaps };
64
106
  ```
65
- ## Test: <url>
66
-
67
- ### Summary
68
- - Score: [0-100]/100
69
- - Tests: [passed] passed, [failed] failed, [warnings] warnings
70
- - Flows: [count] testable flows discovered
71
-
72
- ### Accessibility
73
- - [audit results with pass/fail/warning status]
74
-
75
- ### Performance
76
- - [audit results with scores]
77
107
 
78
- ### Security
79
- - [audit results with pass/fail status]
108
+ ## Anti-Patterns
80
109
 
81
- ### SEO
82
- - [audit results]
110
+ - Do NOT use `smart.screenshot()` — extractPage captures everything needed
111
+ - Do NOT use `sleep()` to wait for metrics — extractPage handles page load
112
+ - Do NOT use `location.href` — use `page.capture.url`
113
+ - Always `search()` first if unsure which fields extractPage returns
83
114
 
84
- ### Best Practices
85
- - [audit results]
115
+ ## Output
86
116
 
87
- ### Discovered Flows
88
- - [list of testable flows with steps]
89
-
90
- ### Evidence Chain
91
- - Crawler: <crawlId> (quality: ...)
92
- - Analyzer: <analyzeId> (quality: ...)
93
- - Auditor: <auditId> (quality: ...)
94
- - Suite: <suiteId> (quality: ...)
95
-
96
- ### Coverage Gaps
97
- - [Any gaps from the investigation]
98
-
99
- ### Confidence
100
- - Overall: high/medium/low
101
- ```
117
+ The skill produces `Finding[]` via `smart.findings()`. Dimensions: **accessibility**, **performance**, **security**, **seo**, **mobile-readiness**, **technology**. When data is missing, confidence auto-caps to "low" and the gap appears in `page.gaps`.
@@ -29,7 +29,7 @@ await connect_tab({ url: "https://example.com" })
29
29
 
30
30
  // Extract everything in one call
31
31
  const page = await smart.extractPage()
32
- // Returns: { capture, performance, security, fonts, meta }
32
+ // Returns: { capture, performance, security, fonts, meta, accessibility, mobileReadiness, gaps }
33
33
  ```
34
34
 
35
35
  For visual evidence, add `smart.scrollCapture()`:
@@ -63,12 +63,34 @@ const record = {
63
63
  security: page.security, // TLS, cert, mixed content
64
64
  fonts: page.fonts, // declared + computed
65
65
  meta: page.meta, // OG tags, structured data, headings, nav links
66
+ accessibility: page.accessibility, // node count, landmarks, images without alt, heading structure
67
+ mobileReadiness: page.mobileReadiness, // viewport meta, media queries, overflow
68
+ gaps: page.gaps, // what data failed — check before trusting null fields
66
69
  }
67
70
  ```
68
71
 
69
72
  ### Phase 3: Analyze
70
73
 
71
- Compare against a fixed rubric. Produce structured findings, not prose.
74
+ Compare against a fixed rubric. Produce validated findings using `smart.finding()`:
75
+
76
+ ```js
77
+ smart.finding({
78
+ claim: "Site loads 47 network requests with 2 failures",
79
+ evidence: ["network.total: 47", "network.failed: 2"],
80
+ sourceUrl: page.capture.url,
81
+ confidence: "high",
82
+ method: "extractPage",
83
+ dimension: "performance" // auto-caps confidence if perf data had gaps
84
+ })
85
+
86
+ // Retrieve all findings from this session
87
+ const allFindings = smart.findings()
88
+
89
+ // Reset for next research task
90
+ smart.clearFindings()
91
+ ```
92
+
93
+ If `extractPage()` reported gaps (e.g., performance metrics failed), findings with matching `dimension` get confidence automatically capped one level (high → medium, medium → low). Check `page.gaps` to understand what data is missing.
72
94
 
73
95
  ## Use Existing Tools — Not Manual Equivalents
74
96
 
@@ -128,9 +150,12 @@ When comparing sites, evaluate these dimensions:
128
150
 
129
151
  ### Prefer:
130
152
 
131
- - **One `extractPage()` per page** — it runs capture_page + perf + security + fonts + meta in parallel
132
- - **`comparePages()` for 2-site comparisons** — handles navigation + extraction for both sites
133
- - **Structured findings** — each with URL, extracted data, and confidence level
153
+ - **One `extractPage()` per page** — it runs 7 ops in parallel (capture + perf + security + fonts + meta + accessibility + mobile-readiness) with typed gaps
154
+ - **`comparePages()` for 2-site comparisons** — returns `{ siteA, siteB, scaffold }` with 11 fixed comparison dimensions
155
+ - **`smart.finding()` for validated findings** — enforces claim + evidence + sourceUrl + confidence + method schema
156
+ - **No `smart.screenshot()`** — it doesn't exist. Use `bridge.send({ type: 'take_screenshot' })` or `smart.scrollCapture()`
157
+ - **No `smart.snapshot({ compact: true })`** — compact option doesn't exist. Use `smart.snapshot()` or `{ interactive: true }`
158
+ - **No `location.href = "..."` for navigation** — use `smart.navigate(url)`. Direct assignment breaks CDP
134
159
 
135
160
  ## Example: Competitive Audit
136
161