octocode-cli 1.3.1 → 1.5.1

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 (102) hide show
  1. package/README.md +193 -34
  2. package/out/chunks/chunk-7476PETK.js +309 -0
  3. package/out/chunks/chunk-CVNNNSMQ.js +26 -0
  4. package/out/chunks/chunk-OQBJTZWK.js +60 -0
  5. package/out/chunks/chunk-UCZCF3BQ.js +9 -0
  6. package/out/chunks/command-help-specs-JZXVSLZ5.js +8 -0
  7. package/out/chunks/commands-XBFPLHSQ.js +8 -0
  8. package/out/chunks/help-P7TCOYAJ.js +10 -0
  9. package/out/chunks/main-help-ULF5PAQY.js +10 -0
  10. package/out/chunks/prompts-5E6VKRX5.js +8 -0
  11. package/out/chunks/spinner-URV2OX6O.js +8 -0
  12. package/out/chunks/tool-command-M6VA7P2F.js +8 -0
  13. package/out/octocode-cli.js +1 -1
  14. package/package.json +5 -3
  15. package/skills/README.md +13 -1
  16. package/skills/agentic-flow-best-practices/SKILL.md +280 -0
  17. package/skills/agentic-flow-best-practices/references/agent-collaboration-patterns.md +75 -0
  18. package/skills/agentic-flow-best-practices/references/pr-review-agent-example.md +47 -0
  19. package/skills/agentic-flow-best-practices/references/resources.md +112 -0
  20. package/skills/octocode-chrome-devtools/README.md +541 -0
  21. package/skills/octocode-chrome-devtools/SKILL.md +197 -0
  22. package/skills/octocode-chrome-devtools/agents/openai.yaml +7 -0
  23. package/skills/octocode-chrome-devtools/references/CDP_AGENT_REFERENCE.md +401 -0
  24. package/skills/octocode-chrome-devtools/references/CHROME_FLAGS.md +234 -0
  25. package/skills/octocode-chrome-devtools/references/INTENTS.md +108 -0
  26. package/skills/octocode-chrome-devtools/references/INTENTS_AUTH.md +179 -0
  27. package/skills/octocode-chrome-devtools/references/INTENTS_AUTOMATION.md +214 -0
  28. package/skills/octocode-chrome-devtools/references/INTENTS_DEBUG.md +329 -0
  29. package/skills/octocode-chrome-devtools/references/INTENTS_ENVIRONMENT.md +237 -0
  30. package/skills/octocode-chrome-devtools/references/INTENTS_INSPECT.md +263 -0
  31. package/skills/octocode-chrome-devtools/references/INTENTS_STORAGE_CONSENT.md +214 -0
  32. package/skills/octocode-chrome-devtools/references/RECOVERY.md +39 -0
  33. package/skills/octocode-chrome-devtools/references/SCRIPT_PATTERNS.md +43 -0
  34. package/skills/octocode-chrome-devtools/references/SCRIPT_PATTERNS_ASYNC_WORKERS.md +345 -0
  35. package/skills/octocode-chrome-devtools/references/SCRIPT_PATTERNS_BROWSER.md +403 -0
  36. package/skills/octocode-chrome-devtools/references/SCRIPT_PATTERNS_OBSERVE.md +275 -0
  37. package/skills/octocode-chrome-devtools/references/SCRIPT_PATTERNS_SPECIAL.md +18 -0
  38. package/skills/octocode-chrome-devtools/scripts/cdp-runner.mjs +503 -0
  39. package/skills/octocode-chrome-devtools/scripts/cdp-sandbox.mjs +123 -0
  40. package/skills/octocode-chrome-devtools/scripts/cdp-template.mjs +81 -0
  41. package/skills/octocode-chrome-devtools/scripts/octocode-chrome-devtools.vpn.example.json +8 -0
  42. package/skills/octocode-chrome-devtools/scripts/open-browser.mjs +362 -0
  43. package/skills/octocode-chrome-devtools/scripts/sourcemap-resolver.mjs +193 -0
  44. package/skills/octocode-chrome-devtools/scripts/undercover.mjs +226 -0
  45. package/skills/octocode-design/README.md +2 -2
  46. package/skills/octocode-documentation-writer/README.md +1 -1
  47. package/skills/octocode-engineer/README.md +1 -1
  48. package/skills/octocode-engineer/SKILL.md +4 -2
  49. package/skills/octocode-engineer/references/output-files.md +3 -3
  50. package/skills/octocode-engineer/scripts/run.js +136 -136
  51. package/skills/octocode-engineer/src/reporting/summary-md.test.ts +48 -0
  52. package/skills/octocode-engineer/src/reporting/summary-md.ts +43 -2
  53. package/skills/octocode-install/SKILL.md +1 -1
  54. package/skills/octocode-pull-request-reviewer/README.md +5 -5
  55. package/skills/octocode-pull-request-reviewer/SKILL.md +1 -1
  56. package/skills/octocode-research/AGENTS.md +1 -1
  57. package/skills/octocode-research/README.md +2 -2
  58. package/skills/octocode-research/docs/ARCHITECTURE.md +1 -1
  59. package/skills/octocode-research/scripts/server.js +191 -246
  60. package/skills/octocode-research/src/routes/github.ts +4 -21
  61. package/skills/octocode-research/src/routes/local.ts +4 -21
  62. package/skills/octocode-research/src/utils/fileContentTransform.ts +44 -0
  63. package/skills/octocode-search-skill/SKILL.md +245 -229
  64. package/skills/octocode-search-skill/references/agent-skills-guide.md +177 -0
  65. package/skills/octocode-search-skill/references/discovery-surfaces.md +162 -0
  66. package/skills/octocode-search-skill/references/fetch-and-create-locally.md +57 -0
  67. package/skills/octocode-search-skill/references/install-reference.md +130 -0
  68. package/skills/octocode-search-skill/references/references-template.md +27 -0
  69. package/skills/octocode-search-skill/references/references.md +62 -0
  70. package/skills/octocode-slides/README.md +307 -0
  71. package/skills/octocode-slides/SKILL.md +410 -0
  72. package/skills/octocode-slides/references/01-brief.md +156 -0
  73. package/skills/octocode-slides/references/02-research.md +149 -0
  74. package/skills/octocode-slides/references/03-outline.md +172 -0
  75. package/skills/octocode-slides/references/04-design.md +301 -0
  76. package/skills/octocode-slides/references/05-implementation.md +213 -0
  77. package/skills/octocode-slides/references/06-review.md +258 -0
  78. package/skills/octocode-slides/references/animation.md +281 -0
  79. package/skills/octocode-slides/references/design-system.md +316 -0
  80. package/skills/octocode-slides/references/html-templates.md +673 -0
  81. package/skills/octocode-slides/references/image-generation.md +448 -0
  82. package/skills/octocode-slides/references/resources.md +840 -0
  83. package/skills/octocode-slides/references/slide-rules.md +541 -0
  84. package/skills/octocode-slides/references/wireframes.md +727 -0
  85. package/skills/octocode-slides/scripts/animation.js +182 -0
  86. package/skills/octocode-slides/scripts/base.css +353 -0
  87. package/skills/octocode-slides/scripts/base.html +655 -0
  88. package/skills/octocode-slides/scripts/generate_image.py +221 -0
  89. package/skills/octocode-slides/scripts/navbridge.js +79 -0
  90. package/skills/octocode-slides/scripts/presenter.js +316 -0
  91. package/skills/octocode-slides/scripts/slide.html +248 -0
  92. package/skills/octocode-stats/SKILL.md +73 -0
  93. package/skills/octocode-stats/assets/template.html +1332 -0
  94. package/skills/octocode-stats/scripts/build_dashboard.mjs +407 -0
  95. package/assets/example.png +0 -0
  96. package/out/chunks/chunk-QCY7Q7YW.js +0 -389
  97. package/out/chunks/command-help-specs-CQ3RBLP6.js +0 -8
  98. package/out/chunks/commands-OCTZP2TO.js +0 -51
  99. package/out/chunks/help-XPXP46ZT.js +0 -10
  100. package/out/chunks/main-help-35HX2UDQ.js +0 -10
  101. package/out/chunks/tool-command-HOSMVLNK.js +0 -8
  102. package/skills/octocode-search-skill/INSTALL_REFERENCE.md +0 -112
@@ -0,0 +1,237 @@
1
+ # CDP Environment And Runtime Intent Details
2
+
3
+ ## emulate
4
+
5
+ **Trigger phrases:** "mobile", "emulate device", "throttle network", "slow 3G", "offline", "fake location", "geolocation", "tablet", "responsive", "test on mobile", "iPhone", "Android", "viewport", "mobile UA"
6
+
7
+ **Purpose:** Override browser environment — device viewport, touch events, UA, network speed, geolocation — before running any other intent. All overrides are script-level and take effect before navigation.
8
+
9
+ **Domains:** No `enable` call needed for `Emulation.*`. For network throttling: `Network.enable` first. For geolocation: `Browser.grantPermissions` first.
10
+
11
+
12
+ ### Two-level emulation model
13
+
14
+ | Level | How | Controls |
15
+ |---|---|---|
16
+ | **Launch-level** | `open-browser.mjs --windowSize 390x844 --userAgent "<mobile-ua>"` | Window size, launch-time UA |
17
+ | **Script-level** | `Emulation.setDeviceMetricsOverride` + `setUserAgentOverride` + `setTouchEmulationEnabled` | Viewport, DPR, mobile mode, UA, touch, Sec-CH-UA hints |
18
+
19
+ **Prefer script-level emulation for accuracy** — it gives real mobile layout (media queries fire, `window.innerWidth` matches), real device pixel ratio, real touch events, and full UA hint spoofing. Launch-level `--windowSize` is useful for initial window dimensions before CDP attaches.
20
+
21
+
22
+ ### Device presets
23
+
24
+ Replace `<current-version>` / `<current-major>` with the installed Chrome version before running a copied Android preset.
25
+
26
+ | Device | Width | Height | DPR | User-Agent |
27
+ |---|---|---|---|---|
28
+ | iPhone 15 Pro | 393 | 852 | 3 | `Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Mobile/15E148 Safari/604.1` |
29
+ | iPhone 13 | 390 | 844 | 3 | `Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1` |
30
+ | Pixel 7 (Android) | 412 | 915 | 2.625 | `Mozilla/5.0 (Linux; Android 14; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/<current-version>.0.0.0 Mobile Safari/537.36` |
31
+ | Samsung Galaxy S23 | 360 | 780 | 3 | `Mozilla/5.0 (Linux; Android 13; SM-S911B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/<current-version>.0.0.0 Mobile Safari/537.36` |
32
+ | iPad Air (M2) | 820 | 1180 | 2 | `Mozilla/5.0 (iPad; CPU OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Mobile/15E148 Safari/604.1` |
33
+ | Desktop 1920 | 1920 | 1080 | 1 | _(use open-browser.mjs default — desktop UA)_ |
34
+
35
+
36
+
37
+ **Adaptive emulation recipe:**
38
+
39
+ Use launch flags for initial window shape only. Use script-level `Emulation.*` before navigation for viewport, DPR, touch, UA, and locale behavior. Replace UA/version hints with the installed browser version when spoofing Chrome.
40
+
41
+ ```js
42
+ const device = { width: 393, height: 852, dpr: 3, mobile: true };
43
+ await cdp.send('Page.enable', {});
44
+ await cdp.send('Network.enable', {});
45
+ await cdp.send('Emulation.setDeviceMetricsOverride', {
46
+ width: device.width, height: device.height,
47
+ deviceScaleFactor: device.dpr, mobile: device.mobile,
48
+ });
49
+ await cdp.send('Emulation.setTouchEmulationEnabled', { enabled: true, maxTouchPoints: 5 });
50
+ // Optional: setUserAgentOverride with current, realistic UA + hints.
51
+ await cdp.send('Page.navigate', { url: TARGET_URL });
52
+ ```
53
+
54
+ After load, verify `window.innerWidth`, `devicePixelRatio`, and horizontal overflow. Feature-detect browser APIs inside the page when emulating capabilities, not just viewport.
55
+
56
+ **Network throttling snippets:**
57
+ ```js
58
+ await cdp.send('Network.enable', {});
59
+
60
+ // Slow 3G
61
+ await cdp.send('Network.emulateNetworkConditions', {
62
+ offline: false, downloadThroughput: 50_000, uploadThroughput: 20_000, latency: 400,
63
+ });
64
+ console.log('[EMULATE] network: Slow 3G (50kb/s down, 400ms latency)');
65
+
66
+ // Fast 3G
67
+ await cdp.send('Network.emulateNetworkConditions', {
68
+ offline: false, downloadThroughput: 180_000, uploadThroughput: 84_000, latency: 100,
69
+ });
70
+
71
+ // Offline
72
+ await cdp.send('Network.emulateNetworkConditions', {
73
+ offline: true, downloadThroughput: 0, uploadThroughput: 0, latency: 0,
74
+ });
75
+
76
+ // Reset
77
+ await cdp.send('Network.emulateNetworkConditions', {
78
+ offline: false, downloadThroughput: -1, uploadThroughput: -1, latency: 0,
79
+ });
80
+ ```
81
+
82
+ **Geolocation:**
83
+ ```js
84
+ await cdp.send('Browser.grantPermissions', { permissions: ['geolocation'] });
85
+ await cdp.send('Emulation.setGeolocationOverride', { latitude: 40.7128, longitude: -74.0060, accuracy: 100 });
86
+ console.log('[EMULATE] geolocation: New York City');
87
+ ```
88
+
89
+ **Dark mode / media queries:**
90
+ ```js
91
+ await cdp.send('Emulation.setEmulatedMedia', {
92
+ features: [{ name: 'prefers-color-scheme', value: 'dark' }],
93
+ });
94
+ ```
95
+
96
+ **Output prefixes:** `[EMULATE]` `[METRIC]` `[FINDING]`
97
+
98
+ **`[FINDING]` conditions:**
99
+ - Layout breaks at mobile viewport → `[FINDING] LAYOUT_BREAK: horizontal scroll or overflow at ${width}px`
100
+ - Network throttle reveals slow resource → `[FINDING] SLOW_RESOURCE: ${url} took ${ms}ms on throttled connection`
101
+ - Offline triggers uncaught exception → `[FINDING] NO_OFFLINE_HANDLING: app crashes when offline`
102
+
103
+ **Ordering constraint:** `Emulation.*` overrides take effect on the next navigation. Call them before `Page.navigate` — media queries and viewport-dependent layout fire during the first parse, not on DOMContentLoaded.
104
+
105
+ **Combine with:** `screenshot` (capture mobile layout), `performance` (measure on throttled network), `debug` (find mobile-only errors), `scrape` (scrape mobile-rendered content).
106
+
107
+ ## inject
108
+
109
+ **Trigger phrases:** "inject script", "patch before load", "hook function", "override", "monkey-patch", "add script to page", "intercept before", "modify behavior", "bypass CSP", "add tracking"
110
+
111
+ **Purpose:** Inject JavaScript into every new document before any page script runs. Use for hooking functions, overriding globals, adding instrumentation, or bypassing checks.
112
+
113
+ **Domains:** `Page.enable`
114
+
115
+ **Key methods:**
116
+ - `Page.addScriptToEvaluateOnNewDocument({source})` → runs before page JS on every navigation
117
+ - `Page.removeScriptToEvaluateOnNewDocument({identifier})` → remove when done
118
+ - `Page.setBypassCSP({enabled:true})` → bypass Content-Security-Policy (required before injection on CSP-protected pages)
119
+
120
+ **Injection patterns:**
121
+ ```js
122
+ // Hook fetch to log all requests + bodies
123
+ const { identifier } = await cdp.send('Page.addScriptToEvaluateOnNewDocument', {
124
+ source: `
125
+ const _fetch = window.fetch;
126
+ window.fetch = async function(...args) {
127
+ const [url, init] = args;
128
+ console.log('[INJECTED:FETCH]', typeof url === 'string' ? url : url.url, init?.body?.slice?.(0,200));
129
+ return _fetch.apply(this, args);
130
+ };
131
+ `
132
+ });
133
+ console.log('[INJECT] fetch hook installed, identifier:', identifier);
134
+
135
+ // Hook XMLHttpRequest
136
+ await cdp.send('Page.addScriptToEvaluateOnNewDocument', {
137
+ source: `
138
+ const _open = XMLHttpRequest.prototype.open;
139
+ XMLHttpRequest.prototype.open = function(method, url) {
140
+ this._xhrUrl = url; this._xhrMethod = method;
141
+ console.log('[INJECTED:XHR]', method, url);
142
+ return _open.apply(this, arguments);
143
+ };
144
+ `
145
+ });
146
+
147
+ // Expose a debug channel back to CDP
148
+ await cdp.send('Runtime.addBinding', { name: '__cdpLog' });
149
+ // then cdp.on('Runtime.bindingCalled', ({name, payload}) => ...) to receive messages from injected code
150
+
151
+ // Override a specific function (e.g. disable analytics)
152
+ await cdp.send('Page.addScriptToEvaluateOnNewDocument', {
153
+ source: `Object.defineProperty(window, 'analytics', { get: () => ({ track: () => {}, page: () => {} }) });`
154
+ });
155
+
156
+ // Bypass CSP before injection
157
+ await cdp.send('Page.setBypassCSP', { enabled: true });
158
+ ```
159
+
160
+ **Cleanup:** Remove injected scripts after the session — they persist across navigations until removed.
161
+ ```js
162
+ await cdp.send('Page.removeScriptToEvaluateOnNewDocument', { identifier });
163
+ ```
164
+
165
+ **Output prefixes:** `[INJECT]` `[FINDING]`
166
+
167
+ **`[FINDING]` conditions:**
168
+ - Injected hook never fires → `[FINDING] INJECT_NO_CALLS: hook installed but never triggered`
169
+ - Page detects injection and shows error → `[FINDING] INJECTION_DETECTED: page responded to override`
170
+
171
+ **Combine with:** `debug` (observe injected logs), `network` (correlate injected fetch logs with CDP network events), `security` (hook crypto APIs to observe key usage).
172
+
173
+ ## monitor
174
+
175
+ **Trigger phrases:** "monitor", "watch", "keep watching", "check every N seconds", "poll", "alert me when", "watch for changes", "continuous", "long-running"
176
+
177
+ **Purpose:** Long-running observation loop — poll a page or condition repeatedly and emit findings when state changes. Useful for catching intermittent errors, watching a live dashboard, or waiting for an event.
178
+
179
+ **Domains:** `Network.enable`, `Runtime.enable`, `Log.enable` (others as needed)
180
+
181
+
182
+ **Adaptive monitor recipe:**
183
+
184
+ Monitor only the condition the user cares about. Use event listeners for async errors and one small `Runtime.evaluate` snapshot per interval.
185
+
186
+ ```js
187
+ export async function run(cdp) {
188
+ const INTERVAL_MS = 5000;
189
+ const DURATION_MS = 60000;
190
+ await cdp.send('Runtime.enable', {});
191
+ await cdp.send('Network.enable', {});
192
+ await cdp.send('Log.enable', {});
193
+
194
+ const queue = [];
195
+ cdp.on('Runtime.exceptionThrown', ({ exceptionDetails }) => queue.push(exceptionDetails.text));
196
+ cdp.on('Network.responseReceived', ({ response }) => {
197
+ if (response.status >= 400) queue.push(`HTTP ${response.status} ${response.url}`);
198
+ });
199
+
200
+ for (const end = Date.now() + DURATION_MS; Date.now() < end;) {
201
+ const { result } = await cdp.send('Runtime.evaluate', {
202
+ expression: `JSON.stringify({ url: location.href, title: document.title,
203
+ errorEls: document.querySelectorAll('.error,[aria-invalid="true"],[data-error]').length })`,
204
+ returnByValue: true,
205
+ });
206
+ console.log(`[MONITOR] ${result.value}`);
207
+ while (queue.length) console.log(`[FINDING] MONITOR_EVENT: ${queue.shift()}`);
208
+ await new Promise(r => setTimeout(r, INTERVAL_MS));
209
+ }
210
+ }
211
+ ```
212
+
213
+ Write a JSON log to `cdp.outputDir` only if the user needs an artifact. Increase duration or add screenshot/network details only after the first run shows they are useful.
214
+
215
+ **Output prefixes:** `[MONITOR]` `[FINDING]` `[METRIC]` `[ACTION]`
216
+
217
+ **`[FINDING]` conditions:**
218
+ - Error count increases between iterations → `[FINDING] MONITOR_ERROR: new error at ${elapsed}s`
219
+ - URL changes unexpectedly → `[FINDING] MONITOR_REDIRECT: URL changed to ${url} at ${elapsed}s`
220
+ - DOM error indicators appear → `[FINDING] MONITOR_DOM_ERROR: error elements appeared at ${elapsed}s`
221
+ - Page becomes unresponsive (evaluate times out) → `[FINDING] MONITOR_HANG: page unresponsive at ${elapsed}s`
222
+ - Network 4xx/5xx mid-session → `[FINDING] MONITOR_NETWORK_ERROR: HTTP ${status} at ${elapsed}s`
223
+
224
+ **Agent loop usage:**
225
+
226
+ ```
227
+ REASON → what condition am I watching for? how long?
228
+ MONITOR → set TARGET_URL + DURATION_MS, run script → read [MONITOR] + [FINDING] lines
229
+ OBSERVE → check === OBSERVE === block: changes, errors, redirects
230
+ ACT → follow [ACTION] lines: run debug on affected URL, inspect DOM errors
231
+ SAVE → change log auto-saved to cdp.outputDir/monitor-log.json
232
+ REPEAT → if condition not yet triggered, increase DURATION_MS and re-run
233
+ ```
234
+
235
+ Stop when: target condition observed OR `[ACTION] page is stable` with zero errors.
236
+
237
+ **Combine with:** `debug` (deep-dive on errors found), `screenshot` (capture state at each change), `network` (add network tracking).
@@ -0,0 +1,263 @@
1
+ # CDP Inspection Surface Intent Details
2
+
3
+ ## security
4
+
5
+ **Trigger phrases:** "security", "cookies", "tokens", "auth", "CSP", "headers", "data exfil", "what's being leaked", "credentials", "session", "localStorage", "is this safe"
6
+
7
+ **Domains:** `Network.enable`, `Runtime.enable`, `DOM.enable`, `Page.enable`
8
+
9
+ **Key events/methods:**
10
+ - `Network.getCookies({ urls: [TARGET_URL] })` → cookies scoped to the target URL only (use this — `getAllCookies` returns the entire browser jar and floods output with third-party ad cookies)
11
+ - `Network.requestWillBeSent` + `Network.getRequestPostData(requestId)` → actual POST bodies
12
+ - `Network.responseReceived` → inspect response headers: `Content-Security-Policy`, `Strict-Transport-Security`, `X-Frame-Options`, `X-Content-Type-Options`
13
+ - `Runtime.evaluate` → localStorage keys and sizes only; never emit stored values
14
+ - `Runtime.evaluate` → sessionStorage keys and sizes only; never emit stored values
15
+ - `DOMDebugger.getEventListeners({objectId})` → listeners on `document`, `window`, `input[type=password]` (get objectId via `Runtime.evaluate({expression:"document"})`)
16
+ - `Runtime.evaluate` → `Object.keys(Object.getPrototypeOf(Object.prototype))` → prototype pollution check
17
+
18
+ **Output prefixes:** `[SECURITY]` `[NETWORK]` `[FINDING]` `[METRIC]`
19
+
20
+ **`[FINDING]` conditions to emit:**
21
+ - Cookie missing `httpOnly` → `[FINDING] COOKIE_NO_HTTPONLY: ${name}`
22
+ - Cookie missing `secure` flag → `[FINDING] COOKIE_NO_SECURE: ${name}`
23
+ - Cookie `sameSite` is `None` without `secure` → `[FINDING] COOKIE_SAMESITE_NONE_INSECURE: ${name}`
24
+ - POST body contains `token`, `password`, `secret`, `apiKey`, `jwt` → `[FINDING] SENSITIVE_IN_POST: ${url}`
25
+ - Response missing `Content-Security-Policy` → `[FINDING] MISSING_CSP: ${url}`
26
+ - CSP contains `unsafe-eval` or `unsafe-inline` → `[FINDING] WEAK_CSP: ${directive} in ${url}`
27
+ - Response missing `Strict-Transport-Security` → `[FINDING] MISSING_HSTS: ${url}`
28
+ - Response missing `X-Frame-Options` → `[FINDING] MISSING_XFRAME: ${url}`
29
+ - `localStorage` key matches `token|auth|jwt|secret|key|password` → `[FINDING] SENSITIVE_IN_STORAGE: ${key}`
30
+ - `keydown`/`keyup` listener on `document` from third-party script URL → `[FINDING] POSSIBLE_KEYLOGGER: ${listenerUrl}`
31
+ - `copy`/`paste` listener on `document` → `[FINDING] CLIPBOARD_LISTENER: possible clipboard hijack`
32
+ - `Object.prototype` has unexpected own properties → `[FINDING] PROTOTYPE_POLLUTION: ${keys}`
33
+ - Request to unknown external domain → `[FINDING] DATA_EXFIL_SUSPECT: ${url}`
34
+
35
+ **Pattern:** See **Security Audit** in `SCRIPT_PATTERNS.md` and trim it to the specific security question.
36
+
37
+ ## websocket
38
+
39
+ **Trigger phrases:** "websocket", "WS", "socket", "real-time", "socket frames", "what's sent over WS"
40
+
41
+ **Domains:** `Network.enable`
42
+
43
+ **Key events/methods:**
44
+ - `Network.webSocketCreated` → `{requestId, url, initiator}` — WS object constructed (`new WebSocket(url)`) — **this is the correct creation event, not `requestWillBeSent`**
45
+ - `Network.webSocketHandshakeResponseReceived` → headers, status
46
+ - `Network.webSocketFrameSent` → `{requestId, timestamp, response: {payloadData, opcode}}` — opcode 1 = text, 2 = binary
47
+ - `Network.webSocketFrameReceived` → `{requestId, timestamp, response: {payloadData, opcode}}`
48
+ - `Network.webSocketClosed` → `{requestId, timestamp}`
49
+
50
+ **Output prefixes:** `[NETWORK]` `[FINDING]` `[METRIC]`
51
+
52
+ **`[FINDING]` conditions to emit:**
53
+ - WS endpoint on unknown third-party domain → `[FINDING] WS_UNKNOWN_HOST: ${url}`
54
+ - Frame payload contains `token`, `password`, `key` → `[FINDING] SENSITIVE_IN_WS_FRAME: ${url}` (value redacted)
55
+ - Base64-encoded payload (matches `/^[A-Za-z0-9+/]{40,}={0,2}$/`) → `[FINDING] WS_BASE64_FRAME: possible encoded data`
56
+ - Frame size > 100KB → `[FINDING] LARGE_WS_FRAME: ${kb}KB sent` *(threshold is a default — adjust for your protocol)*
57
+ - opcode === 2 → binary frame; base64-decode payload for inspection
58
+
59
+ **WS inside Web Workers:** `Network.webSocketCreated` does **not** fire on the main session for WebSockets opened inside a Web Worker or Shared Worker. To capture those, enable the `workers` intent first (`Target.setAutoAttach`), then call `cdp.send('Network.enable', {}, sessionId)` on each attached worker session. See the **workers** intent and **WebSocket inside Workers** pattern in `SCRIPT_PATTERNS.md`.
60
+
61
+ ## service-worker
62
+
63
+ **Trigger phrases:** "service worker", "SW lifecycle", "PWA worker", "offline cache", "push notifications", "background sync", "SW registered", "what service workers are running", "is there a service worker"
64
+
65
+ **Domains:** `ServiceWorker.enable` + `Target.setAutoAttach` (to receive the SW as an attachable target)
66
+
67
+ **Key events/methods:**
68
+ - `ServiceWorker.enable` — must call before navigation to receive SW events
69
+ - Event: `ServiceWorker.workerRegistrationUpdated` → `{registrations[]}` — fires when a SW registration is created or deleted; each `registration` has `{registrationId, scopeURL, isDeleted}`
70
+ - Event: `ServiceWorker.workerVersionUpdated` → `{versions[]}` — fires on **every state transition**; each `version` has `{registrationId, versionId, scriptURL, status, runningStatus}`:
71
+ - `status`: `"new"` → `"installing"` → `"installed"` → `"activating"` → `"activated"` → `"redundant"`
72
+ - `runningStatus`: `"stopped"` → `"starting"` → `"running"` → `"stopping"`
73
+ - `ServiceWorker.disable` — call at cleanup to stop receiving events
74
+
75
+ **SW methods (imperative):**
76
+ - `ServiceWorker.skipWaiting({scopeURL})` — force a waiting SW to activate immediately
77
+ - `ServiceWorker.updateRegistration({scopeURL})` — trigger a SW update check
78
+ - `ServiceWorker.unregister({scopeURL})` — unregister a SW
79
+
80
+ **Output prefixes:** `[SW]` `[FINDING]` `[MONITOR]`
81
+
82
+ **`[FINDING]` conditions to emit:**
83
+ - New registration for a non-extension scope → `[FINDING] SW_REGISTERED: ${scopeURL}`
84
+ - SW reaches `activated` state → `[FINDING] SW_ACTIVATED: ${scriptURL}`
85
+ - SW `isDeleted` = true (unregistered or evicted) → `[FINDING] SW_REMOVED: ${scopeURL}`
86
+ - SW script is on a third-party domain → `[FINDING] SW_THIRD_PARTY_SCRIPT: ${scriptURL}`
87
+
88
+ **Tip — navigator API for a point-in-time snapshot (after page load):**
89
+ ```js
90
+ const regs = await cdp.send('Runtime.evaluate', {
91
+ expression: `navigator.serviceWorker.getRegistrations().then(r=>JSON.stringify(r.map(x=>({scope:x.scope,state:(x.active||x.installing||x.waiting)?.state,script:(x.active||x.installing||x.waiting)?.scriptURL}))))`,
92
+ awaitPromise: true, returnByValue: false,
93
+ });
94
+ const sws = JSON.parse(regs.result.value ?? '[]');
95
+ ```
96
+ Use the CDP domain (`ServiceWorker.enable` + events) for **live lifecycle tracking**; use `navigator.serviceWorker.getRegistrations()` for a **snapshot** after load.
97
+
98
+ **Combine with:** `workers` (to attach to the SW target and capture its network traffic), `storage` (to read CacheStorage entries managed by the SW).
99
+
100
+ ## workers
101
+
102
+ **Trigger phrases:** "web worker", "shared worker", "worker thread", "background worker", "blob worker", "WS inside worker", "what workers are running", "worker targets", "worker network traffic"
103
+
104
+ **Domains:** `Target.setAutoAttach` + `Target.setDiscoverTargets` — must be called **before navigation**
105
+
106
+ **Key events/methods:**
107
+ - `Target.setAutoAttach({autoAttach: true, waitForDebuggerOnStart: false, flatten: true})` — auto-attach to all child targets (workers, service workers) with flat session model
108
+ - `Target.setDiscoverTargets({discover: true})` — emit `Target.targetCreated` for worker targets that Chrome discovers
109
+ - Event: `Target.attachedToTarget` → `{targetInfo, sessionId}` — fires when a worker is attached; `targetInfo.type` is one of `"worker"` (Web Worker), `"shared_worker"`, `"service_worker"`
110
+ - Event: `Target.targetCreated` → `{targetInfo}` — fires when a worker target is created (type = worker/shared_worker/service_worker)
111
+ - `Target.getTargets({})` → `{targetInfos[]}` — list all known targets including workers (use after page settles)
112
+ - `Target.detachFromTarget({sessionId})` — detach from a worker when done
113
+
114
+ **Enabling Network on a worker (flat session model):**
115
+
116
+ When `flatten: true` is set in `setAutoAttach`, worker sessions share the same WebSocket connection. Pass `sessionId` as the **third argument** to `cdp.send()` to route commands to that session:
117
+
118
+ ```js
119
+ cdp.on('Target.attachedToTarget', async ({ targetInfo, sessionId }) => {
120
+ if (!['worker', 'shared_worker', 'service_worker'].includes(targetInfo.type)) return;
121
+ console.log(`[WORKER] Attached: type=${targetInfo.type} url=${targetInfo.url || '(blob)'}`);
122
+ // Enable Network on this worker's session to capture its HTTP + WS traffic
123
+ await cdp.send('Network.enable', {}, sessionId);
124
+ // All Network events from this worker now carry { sessionId } in their metadata.
125
+ // Route them with a wrapper that filters by sessionId.
126
+ });
127
+ ```
128
+
129
+ **Routing worker events (filter by sessionId):**
130
+ ```js
131
+ // Generic: listen to an event on a specific worker session
132
+ function onWorkerEvent(event, workerSessionId, handler) {
133
+ cdp.on(event, (params, meta) => {
134
+ if (meta?.sessionId === workerSessionId) handler(params);
135
+ });
136
+ }
137
+ // Then:
138
+ onWorkerEvent('Network.webSocketCreated', sessionId, ({ requestId, url }) => {
139
+ console.log(`[WORKER] WS inside worker: ${url}`);
140
+ });
141
+ ```
142
+
143
+ **Output prefixes:** `[WORKER]` `[FINDING]` `[MONITOR]`
144
+
145
+ **`[FINDING]` conditions to emit:**
146
+ - Worker URL is a blob: URL → `[FINDING] WORKER_BLOB: ${url}` (expected but opaque; blob workers cannot be inspected via source)
147
+ - Shared Worker detected → `[FINDING] SHARED_WORKER: ${url}` (multi-tab communication channel)
148
+ - Service Worker detected → `[FINDING] SERVICE_WORKER_TARGET: ${url}` (complements service-worker intent)
149
+ - WS connection inside a worker → `[FINDING] WS_IN_WORKER: type=${type} url=${wsUrl}`
150
+
151
+ **Cleanup:**
152
+ ```js
153
+ await cdp.send('Target.setAutoAttach', { autoAttach: false, waitForDebuggerOnStart: false, flatten: true });
154
+ await cdp.send('Target.setDiscoverTargets', { discover: false });
155
+ ```
156
+
157
+ **Combine with:** `websocket` (capture WS frames inside workers), `service-worker` (track SW lifecycle alongside its target session), `network` (capture HTTP requests made by workers).
158
+
159
+ ## intercept
160
+
161
+ **Trigger phrases:** "intercept", "mock", "block request", "fake response", "modify request", "inject headers", "replace API response"
162
+
163
+ **Domains:** `Fetch.enable` (call before navigation, no explicit `enable` method — call `Fetch.enable` with `patterns`)
164
+
165
+ **Key events/methods:**
166
+ - `Fetch.enable({patterns:[{urlPattern:"*", requestStage:"Request"}]})` → intercept all requests
167
+ - Event: `Fetch.requestPaused` → `{requestId, request, responseStatusCode, responseHeaders}`
168
+ - `Fetch.continueRequest({requestId})` → pass through unchanged
169
+ - `Fetch.fulfillRequest({requestId, responseCode:200, body: btoa(JSON.stringify(mockData))})` → return mock
170
+ - `Fetch.continueRequest({requestId, headers:[...]})` → modify headers before continuing
171
+
172
+ **Output prefixes:** `[NETWORK]` `[FINDING]`
173
+
174
+ **Note:** `Fetch.enable` must be called **before** navigation. `body` in `fulfillRequest` must be base64-encoded.
175
+
176
+ ## screenshot
177
+
178
+ **Trigger phrases:** "screenshot", "capture", "take a photo", "visual", "PDF", "print page"
179
+
180
+ **Domains:** `Page.enable`
181
+
182
+ **Key events/methods:**
183
+ - `Page.captureScreenshot({format:"png"})` → `data` (base64) → write to `cdp.outputDir/screenshot-<slug>.png`
184
+ - `Page.printToPDF({printBackground:true})` → `data` (base64) → write to `cdp.outputDir/<slug>.pdf`
185
+ - Wait for `Page.loadEventFired` before capturing — capturing too early yields a blank or partial screenshot
186
+
187
+ **Output prefixes:** `[SCREENSHOT]`
188
+
189
+ **Write file pattern — use `cdp.outputDir` (sandbox-safe, cross-platform):**
190
+ ```js
191
+ const { writeFileSync } = await import('fs');
192
+ const { join } = await import('path');
193
+ const screenshotPath = join(cdp.outputDir, 'screenshot.png');
194
+ writeFileSync(screenshotPath, Buffer.from(data, 'base64'));
195
+ console.log(`[SCREENSHOT] ${screenshotPath}`);
196
+ ```
197
+
198
+ ## accessibility
199
+
200
+ **Trigger phrases:** "accessibility", "a11y", "aria", "screen reader", "wcag", "alt text", "labels"
201
+
202
+ **Domains:** `DOM.enable`, `Runtime.enable`, `Accessibility.enable`
203
+
204
+ **Key events/methods:**
205
+ - `Accessibility.getFullAXTree` → full semantic tree with `role`, `name`, `description`, `states`
206
+ - `Runtime.evaluate` → `img:not([alt])`, `input:not([aria-label])`, `button:empty`, `[role]` checks
207
+
208
+ **Output prefixes:** `[DOM]` `[FINDING]` `[METRIC]`
209
+
210
+ **`[FINDING]` conditions to emit:**
211
+ - AX node with `role:"img"` and empty `name` → `[FINDING] AX_MISSING_ALT: image has no accessible name`
212
+ - AX node with `role:"button"` and empty `name` → `[FINDING] AX_EMPTY_BUTTON`
213
+ - Input without label in AX tree → `[FINDING] AX_UNLABELED_INPUT`
214
+ - Page has no `role:"main"` landmark → `[FINDING] AX_NO_MAIN_LANDMARK`
215
+ - Heading order skips levels (h1 → h3) → `[FINDING] AX_HEADING_SKIP`
216
+
217
+ ## supply-chain
218
+
219
+ **Trigger phrases:** "third-party scripts", "external scripts", "CDN", "supply chain", "what scripts load", "external JS"
220
+
221
+ **Domains:** `Network.enable`, `Runtime.enable`, `Page.enable`
222
+
223
+ **Key events/methods:**
224
+ - `Network.requestWillBeSent` → filter for `.js` requests where origin ≠ page hostname
225
+ - `Network.responseReceived` → check `Subresource-Integrity` / `integrity` attribute presence
226
+ - `Runtime.evaluate` → `[...document.querySelectorAll('script[src]')].map(s=>({src:s.src,integrity:s.integrity||null}))` → list all script tags
227
+
228
+ **Output prefixes:** `[NETWORK]` `[SECURITY]` `[FINDING]` `[METRIC]`
229
+
230
+ **`[FINDING]` conditions to emit:**
231
+ - Third-party JS loaded without SRI hash → `[FINDING] NO_SRI: ${url}`
232
+ - Script from unknown CDN (not from well-known CDNs) → `[FINDING] UNKNOWN_CDN: ${url}`
233
+ - More than 10 distinct third-party domains → `[FINDING] HIGH_THIRD_PARTY_COUNT: ${n} external domains` *(adjust for your expected vendor count)*
234
+ - Script loaded over HTTP (not HTTPS) → `[FINDING] INSECURE_SCRIPT_LOAD: ${url}`
235
+ - `window` gains new property after third-party script loads → `[FINDING] WINDOW_POLLUTION: ${key} added by ${url}`
236
+
237
+ ## full-audit
238
+
239
+ **Trigger phrases:** "full audit", "everything", "all checks", "complete audit", "check it all"
240
+
241
+ **Domains:** Enable all: `Network.enable`, `Runtime.enable`, `Log.enable`, `Performance.enable`, `DOM.enable`, `CSS.enable`, `HeapProfiler.enable`, `Page.enable`
242
+
243
+ **Strategy:** Combine all intents above into one script. Run in this order:
244
+ 1. Enable all domains
245
+ 2. Attach all event listeners (network, console, exceptions, WS)
246
+ 3. Navigate to target
247
+ 4. Wait for `Page.loadEventFired`
248
+ 5. Run synchronous checks: `Performance.getMetrics`, DOM queries, `Network.getCookies({ urls: [TARGET_URL] })` (not `getAllCookies` — that returns the entire browser jar), localStorage key/size inventory, `DOMDebugger.getEventListeners`
249
+ 6. Wait 5–10s for async activity
250
+ 7. Emit `[METRIC]` summary for each category
251
+
252
+ **Output prefixes:** All of the above.
253
+
254
+ **Emit a summary block at the end:**
255
+ ```
256
+ [METRIC] === AUDIT SUMMARY ===
257
+ [METRIC] Network requests: N Errors: N
258
+ [METRIC] Console errors: N Exceptions: N
259
+ [METRIC] JS heap: NMB DOM nodes: N
260
+ [METRIC] Cookies: N Missing httpOnly: N
261
+ [METRIC] Missing CSP: yes/no Missing HSTS: yes/no
262
+ [METRIC] Third-party scripts: N Without SRI: N
263
+ ```