| Age | Commit message (Collapse) | Author |
|
screenshots; release 0.15.54
- Check page visibility before trusted input: Chrome drops input to hidden pages (inactive tabs,
covered/minimized windows, macOS window tabs behind full screen). Type/key/hover/scroll/tap/drag
fail fast with the reason; click/fill use their DOM fallback immediately (or reject with
domFallback:false).
- Use an inactive tab instead of a new window for the automation target while the user's window is
full screen.
- chrome_type with uid/selector moves the caret to the end (moveToEndOfDocument) after its focus click.
- chrome_upload_file: labels/wrappers resolve to their file input, same-origin iframe search, and
intercepted file chooser for upload buttons (trusted click when visible, user-gesture click when
hidden); reject multiple paths for single-file inputs; no duplicate change event.
- Prune default-folder chrome_screenshot captures (7 days, newest 20 kept, retentionDays override).
- input.debug without a target no longer calls tabs.get(-1).
- New hidden-input unit suite.
|
|
Adapted from community forks (ardhiqii, kkunkunya, nihar-oracle, steimerbyte):
- Abort stalled /next long polls after 45s; time out, retry, and single-post results.
- Fall back to CDP Runtime.evaluate when chrome.scripting is refused (about:blank automation tabs).
- Load pi-chrome in same-process subagent sessions as a bridge client; client chrome_launch reports owner status.
- Add chrome_cdp (validated raw CDP passthrough, background-guarded, payload summarization) and chrome_cdp_targets.
- chrome_type reports before/after values, insertedAt, splice/unchanged warnings; add replace=true.
- includeSnapshot waits for navigations started by the action; tab.new reports the settled tab.
- CDP timeouts surface as timeouts and are not re-sent after the cleanup detach.
- Activate/deactivate chrome_find and chrome_inspect with the rest of the chrome_* tools.
- New unit suites: bridge-resilience, cdp-passthrough, type-evidence.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Stop pi-chrome from hijacking the user's active tab. Page/navigation actions
with no explicit target now route to a dedicated automation window owned by the
calling Pi session (falling back to a dedicated tab if a window can't be made),
instead of overwriting whatever the user has open.
- Session-scoped ownership: Map<sessionKey, target> in the service worker, keyed
by a sessionKey forwarded from index.ts, so concurrent sessions (one shared
extension) never fight over a window or close each other's tabs.
- Persistence: ownership mirrored to chrome.storage.session so a service-worker
restart re-hydrates and reuses the window instead of orphaning it. Cleared on
full browser restart; restored windows are then left alone (never reclaimed).
- getTabByParams default branch resolves the owned target; tab.activate/close/
group/ungroup pass createOwnedTarget:false so management never auto-creates a
throwaway tab or falls back to the user's active tab.
- Session-group integration: the dedicated-window tab still joins this session's
tab group, in its own window; grouping stays best-effort.
- Lifecycle: cleanup on /chrome revoke and real session end (not /reload);
fire-and-forget so it never blocks /quit, /reload, or shutdown.
- Tests: new test-suite/unit/automation-target.test.mjs (isolation, reuse,
concurrency, restart/reconnect re-hydration, guarded tab.*, group integration,
window->tab fallback, robust cleanup). Docs + CHANGELOG updated.
|
|
|
|
- chrome_snapshot returns a concise observation (layout, hints, actions, forms,
page map, query matches, diff) with mode/query/maxTextChars params
- new chrome_find (query -> ranked uids) and chrome_inspect (deep element context,
with page.inspect fallback)
- includeSnapshot on click/type/fill/key now embeds the formatted snapshot
- snapshot/inspect logic shipped as eval-free packaged snapshot_injected.js,
sharing window.__PI_CHROME_STATE__ (el- uid scheme) with existing input helpers
|
|
|
|
evaluate/snapshot/waitFor/initScript
- evaluateInTab/executeInTab now run through CDP Runtime.evaluate instead of
new Function() in MAIN world, so chrome_evaluate/chrome_snapshot work on pages
that block unsafe-eval (github.com, many bank/SaaS apps). Preserves value
markers (undefined/function/symbol/bigint/Error), DOMRect expansion, and the
expression/statement fallback; keeps {ok,value} error envelope.
- page.waitFor polls via service-worker-side CDP evaluation.
- chrome_navigate initScript uses Page.addScriptToEvaluateOnNewDocument.
- Add npm test (test-suite/unit/csp-eval.test.mjs) and in-browser regression
challenge 42 strict-csp-evaluate; update challenge 39 notes + docs/primer.
|
|
|
|
Reverts the pairing + signed-envelopes work (0.16.0-0.16.1), the
standalone daemon refactor (0.17.0-0.17.3), and assorted patches.
These were unpublished from npm; this commit restores the working
tree to match the v0.15.20 release so the branch tip and the npm
'latest' dist-tag are consistent again.
Tags v0.16.0 through v0.17.3 are preserved as recovery anchors;
the work is reachable via 'git checkout v0.17.3' if ever needed.
Tree-equivalent to v0.15.20.
|
|
Major security hardening of the Chrome bridge driven by red-team findings.
- Mandatory pairing via /chrome onboard (one-time per machine). Bridge pins exact
chrome-extension:// origin and derives HMAC keys via HKDF. Until paired, the
bridge returns idle responses and refuses to deliver commands.
- Signed envelopes on /next, /result, /command. HMAC-SHA256 over protocol version,
direction, method, path, extension ID, bridge ID, timestamp, fresh nonce, and
SHA-256 of the body. +/-30s clock window; 5-min LRU nonce replay defense on
both request and response directions; constant-time MAC compare.
- Peer Pi sessions sharing the bridge sign each /command with a broker HKDF key
(no bearer token transmitted) and verify the owner's signed response.
- Global loopback enforcement. PI_CHROME_BRIDGE_HOST=0.0.0.0 ignored unless
PI_CHROME_BRIDGE_DANGEROUS_REMOTE=1; loopback check still applies per-endpoint.
- Cross-process state coherence: fs.watch + per-request mtime check on
~/.config/pi/chrome-bridge.json. A peer Pi's unpair (or any external rm/edit)
propagates to the owner's in-memory state before the next privileged verify;
replay caches reset on key rotation.
- Body cap 1 MiB -> 413. Queue/pending/waiter caps. Malformed JSON -> 400.
Non-object JSON bodies -> 400 instead of being trusted.
- page.navigate initScript: try/finally around tabs.update, per-call onCommitted
listener with bounded commit-wait window, one-shot delete in global onCommitted.
No more stale init scripts firing on later unrelated navigations.
- crypto.randomUUID() command IDs.
- Manifest diet (dropped activeTab); added popup.html/popup.js for the pair UI.
UX:
- /chrome onboard runs install + pair in one interactive flow.
- /chrome help reorganized into First-time / Day-to-day / Maintenance.
- Status bar lights up as green dot only when authorized.
- Early console/network capture at document_start so boot-time React errors and
initial API calls aren't dropped (ported from DaniBedz/pi-chrome fork).
Docs:
- SECURITY.md threat model rewritten with in-scope / out-of-scope sections.
- README rewritten with the install-then-pair flow front and center.
- CHANGELOG 0.16.0 entry with full patch list.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
table, section reorder
|
|
|
|
status header
Reorganises the /chrome command surface:
/chrome status - one-line snapshot of connection + click mode + quiet mode
/chrome doctor - full health check (unchanged)
/chrome onboard - install extension (unchanged)
/chrome clicks - cycles auto -> on -> off -> auto when called with no args.
Explicit args (auto|off|on|status) still work.
/chrome quiet - toggles on/off when called with no args.
Explicit args (on|off|toggle|status) still work.
Removes the nested 'settings' wrapper. /chrome settings background/trusted
still functions as a hidden legacy alias but is no longer advertised.
Bare /chrome opens a picker with a one-line status header and cycle-target
labels: 'clicks: auto -> switch to on' / 'quiet: off -> switch to on'. No
second picker; one keypress flips the setting.
Argument autocomplete now returns full-path values (e.g. 'clicks auto') so
pi-tui's whole-argument replacement applies correctly. Top-level suggestions
show clicks / quiet / status / doctor / onboard with descriptions.
User-visible names match the descriptive copy:
- 'trusted' -> 'clicks' (matches 'real-looking clicks' / 'quiet clicks')
- 'background' -> 'quiet' (matches 'quiet mode' / 'watch mode')
README + agent prompt primer + internal hint strings updated.
|
|
Replaces /chrome-doctor, /chrome-onboard, /chrome-background,
/chrome-trusted with a single /chrome command that takes subcommands:
/chrome doctor (was /chrome-doctor)
/chrome onboard (was /chrome-onboard)
/chrome settings background [on|off] (was /chrome-background)
/chrome settings trusted [auto|off|on|status] (was /chrome-trusted)
Running /chrome with no arguments opens a picker. Argument auto-
completion walks the tree (e.g. type '/chrome se<Tab>' to land on
'settings', then '/chrome settings t<Tab>' to land on 'trusted').
All user-visible references (notify messages, doctor output, agent
prompt primer, README) updated to the new paths.
|
|
/chrome-background, /chrome-onboard, README
Replaces remaining jargon in every user-facing string:
- /chrome-doctor: 'Local bridge: mode=server, url=...' -> 'This pi
session is running the Chrome connection for this machine.'
'EXTENSION VERSION MISMATCH ...' -> 'The Chrome companion extension
is on an old version (X); this pi-chrome is Y.'
'chrome_evaluate("1+1") = 2' -> 'pi-chrome can run code in the
active Chrome tab.'
'navigator.webdriver=true on current tab — site fingerprinting may
flag automation.' -> 'Your Chrome is reporting itself as automated
to websites. Some sites use this signal to block sign-ins or bot
checks.'
- /chrome-background description + notify: drops 'silent/background
mode', frames as 'quiet mode' vs 'watch mode'.
- /chrome-onboard: walks through the click-by-click steps instead of
saying 'Developer mode -> Load unpacked'.
- session_start notify: drops 'Chrome profile bridge'; says 'pi-chrome
connected' / 'waiting for the Chrome companion to connect'.
- README 'Trusted-input mode (CDP)' section rewritten as 'Click modes'
with plain prose explaining quiet vs real-looking clicks and when
each fails.
Tool descriptions (seen by the agent) keep precise terminology.
|
|
Banner is themed by the user's Chrome (dark mode → dark grey for many
users), not always yellow. Use 'banner' alone or quote the actual
banner text 'Pi Chrome Connector started debugging this browser'.
|
|
Connector
Trusted-input mode default flips from 'off' to 'auto':
- Synthetic events still run first for every chrome_* call.
- If a click produced no page change AND the target's label looks like a
user-activation-gated affordance (play/copy/share/sign-in/etc), or the
page just emitted NotAllowedError / 'transient activation required',
the call is silently retried via chrome.debugger (CDP).
- Typing auto-retries when the input value didn't change at all
(editor rejected synthetic input).
- Result carries autoRetried=true + autoRetryReason + syntheticAttempt
so callers / agents see the upgrade happened.
- Yellow debugger banner now appears only for the retry, not every call.
Companion extension renamed 'Pi Existing Chrome Profile Bridge' →
'Pi Chrome Connector' (manifest, action title, SW client name, README,
slash-command notify strings). One-time chrome://extensions reload
needed to pick up the new name; auto-reload mechanism handles the rest.
/chrome-doctor explains the active mode and what smart-retry does.
/chrome-trusted picker shows 'auto (current)' first; on-mode now warned
as 'banner permanently visible'.
chrome_click / chrome_type tool descriptions explain auto-retry.
|
|
Add opt-in CDP path so chrome_* tools can dispatch browser-trusted input
(isTrusted=true, satisfies user-activation gates: clipboard, fullscreen,
file picker, autoplay). Default remains synthetic events; no behavior
change unless trusted mode is enabled.
Companion extension:
- new "debugger" permission in manifest (one-time re-approval prompt in
chrome://extensions on update)
- attach/detach lifecycle per tab with idle-detach (15s) and listener
for onDetach (incl. canceled_by_user)
- trustedClick / trustedHover / trustedType / trustedFill / trustedKey /
trustedScroll / trustedDrag use Input.dispatchMouseEvent +
Input.dispatchKeyEvent through chrome.debugger.sendCommand, reusing
humanized timing, in-rect coord variance, pointer continuity, Shift
chord for uppercase, per-key cadence
- trusted.mode / trusted.status bridge actions
Pi side:
- /chrome-trusted slash command (on / off / auto / status)
- trusted=true param on chrome_click, chrome_type, chrome_fill,
chrome_key, chrome_hover, chrome_drag, chrome_scroll
- /chrome-doctor probes chrome.debugger availability and reports current
trusted mode + attached tabs
- README documents trusted-input mode and tradeoffs
|
|
|
|
|