cdpilot 0.9.7 → 0.9.8
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/README.md +114 -15
- package/bin/cdpilot.js +36 -6
- package/package.json +1 -1
- package/src/cdpilot.py +3795 -210
package/README.md
CHANGED
|
@@ -150,10 +150,11 @@ tools, or `enable` to add some (the server sends `tools/list_changed`). `--tools
|
|
|
150
150
|
picks tools by name; `all` (default) is unchanged. Schema size of `tools/list`
|
|
151
151
|
(tiktoken `o200k_base`): 45 tools = 5,769 tokens, `core` = 11 tools = 1,342 tokens; the four
|
|
152
152
|
`browser_agent_*` tools add ~11% of schema (49 tools ≈ 6,400 tokens, scaled from the measurement).
|
|
153
|
+
The three `browser_canvas_*` tools are listed only while a live canvas is open (`cdpilot canvas open`), and never under `core`; `tools/list_changed` follows when the first canvas opens or the last one closes.
|
|
153
154
|
|
|
154
155
|
### Agent mode over MCP
|
|
155
156
|
|
|
156
|
-
`browser_agent_observe` (`diff`), `browser_agent_act` (`ref`/`url`, `action`, `text`), `browser_agent_flow_save`
|
|
157
|
+
`browser_agent_observe` (`diff`, `full`), `browser_agent_act` (`ref`/`url`, `action`, `text`), `browser_agent_flow_save`
|
|
157
158
|
(`name`, `last`) and `browser_agent_run` (`flow`, `vars`, `dry_run`) wrap the agent commands below, so a model
|
|
158
159
|
on MCP works from numbered refs, gets diffs, and replays a learned flow with no page read at all. They are
|
|
159
160
|
outside the `core` profile; `browser_tools enable` adds them. A drift or a missing variable comes back as
|
|
@@ -472,6 +473,28 @@ cdpilot a11y summary # Quick summary
|
|
|
472
473
|
cdpilot a11y find <role> # Find elements by ARIA role
|
|
473
474
|
```
|
|
474
475
|
|
|
476
|
+
### Choosing a page view
|
|
477
|
+
|
|
478
|
+
Tokens are o200k_base counts of each command's stdout on Hacker News and the Wikipedia "Web browser" article
|
|
479
|
+
(median of 3 runs, rounded to hundreds, 2026-11-11; pages drift, so expect a few percent).
|
|
480
|
+
|
|
481
|
+
| View | What it gives | Can act on it | HN / Wikipedia |
|
|
482
|
+
|---|---|---|---|
|
|
483
|
+
| `content` | the page's plain text | no | 1,200 / 4,700 |
|
|
484
|
+
| `agent observe` | numbered `@refs` for actionable entries and headings/landmarks, plus a short text | yes (`agent act --ref`) | 4,300 / 8,300 |
|
|
485
|
+
| `agent observe --rows` | the same entries as arrays | yes | 2,900 / 5,200 |
|
|
486
|
+
| `agent observe --full` | every entry, nothing hidden | yes | 6,900 / 17,300 |
|
|
487
|
+
| `a11y-snapshot` | one `@ref` line per interactive or structural node | yes (`click-ref @N`) | 8,100 / 13,100 |
|
|
488
|
+
| `a11y` | the full tree with roles and names, no refs | no | 9,800 / 31,400 |
|
|
489
|
+
| `describe` | `a11y-snapshot` + page text, and it writes a screenshot file | yes (`click-ref @N`) | 8,800 / 13,600 |
|
|
490
|
+
|
|
491
|
+
To act on a page under a token budget, start with `agent observe`; `--rows` prints the same entries in about a
|
|
492
|
+
third fewer tokens (opt-in: `[ref, role, name(, value)]`). After a click or a fill, read the `agent act` result: it
|
|
493
|
+
already holds the change (142–496 tokens on Wikipedia, MDN and react.dev), and `agent observe --diff` right after
|
|
494
|
+
it returned 45–60. Use `a11y-snapshot` or
|
|
495
|
+
`observe --full` when you need a ref for every node, and `content` when you only read. The ranking is
|
|
496
|
+
page-dependent: on react.dev `a11y-snapshot` (1,200) is smaller than `content` (1,500).
|
|
497
|
+
|
|
475
498
|
### Agent mode: numbered refs and diffs (token budget)
|
|
476
499
|
|
|
477
500
|
```bash
|
|
@@ -480,9 +503,16 @@ cdpilot agent act --ref @3 --action click
|
|
|
480
503
|
cdpilot agent act --ref @4 --action fill --text "cdpilot"
|
|
481
504
|
cdpilot agent act --url https://example.com/ # navigates silently, prints the diff
|
|
482
505
|
cdpilot agent observe --diff # only what changed since the last observe/act
|
|
506
|
+
cdpilot agent observe --full # every entry, nothing hidden (also on act and run)
|
|
507
|
+
cdpilot agent observe --rows # entries as [ref, role, name, value?] arrays
|
|
483
508
|
cdpilot agent stats | agent reset
|
|
484
509
|
```
|
|
485
510
|
|
|
511
|
+
The agent commands (`agent observe`, `agent act`, `agent run`, `agent flow list|show`) print compact
|
|
512
|
+
UTF-8 JSON when stdout is not a terminal (an agent, a pipe, an MCP tool call) and indented JSON in a
|
|
513
|
+
terminal. `CDPILOT_JSON=pretty|compact` overrides this. Scripts that grep line by line should use `jq`
|
|
514
|
+
or set `CDPILOT_JSON=pretty`.
|
|
515
|
+
|
|
486
516
|
`observe` turns the accessibility tree into a numbered list of things an agent can act on (buttons, links,
|
|
487
517
|
fields with their current value, unique text anchors) plus a short text summary; no screenshot, no HTML.
|
|
488
518
|
Every `act` and `observe --diff` returns only the change: `changed.added` (full descriptors, so the agent can act
|
|
@@ -491,6 +521,18 @@ when it changed (`text_changed`). Refs are stable while the element exists (keye
|
|
|
491
521
|
position); a navigation starts a new set. `token_estimate` is `len(json)/4`; `saved_vs_full` compares the diff
|
|
492
522
|
with a full observe of the same page. State lives in `~/.cdpilot/projects/<id>/agent-state.json`.
|
|
493
523
|
|
|
524
|
+
**What the printed list leaves out.** By default `actions` keeps every interactive entry, headings, regions
|
|
525
|
+
and navigation landmarks, and text that is clickable although the accessibility tree calls it text (a
|
|
526
|
+
`<div onclick>`: `cursor:pointer` starts there, or Chrome marks it clickable, and no link or button sits
|
|
527
|
+
above it). It leaves out plain text, table cells and list markers, entries whose name is only the sum of
|
|
528
|
+
their own kept children, and cuts names over 80 characters to 79 + `…` (output only). The text is still in
|
|
529
|
+
`text`. Only the printed list is thinned: refs, saved flows (`agent run` anchors on the full list) and
|
|
530
|
+
`act --ref` of a hidden ref are unchanged. One extra `DOMSnapshot.captureSnapshot` call (2 s limit) decides
|
|
531
|
+
"clickable"; if it fails nothing is hidden. `--full` (CLI `observe`/`act`/`run`; over MCP only `browser_agent_observe` takes `full: true`,
|
|
532
|
+
`browser_agent_act` and `browser_agent_run` have no `full`) prints the unfiltered list. `--rows` (or `CDPILOT_OBSERVE_FORMAT=rows`) prints `actions` and `changed.added` as arrays
|
|
533
|
+
`[ref, role, name]`, with the field value as a 4th element only for entries that have one; objects stay
|
|
534
|
+
the default.
|
|
535
|
+
|
|
494
536
|
#### Learned flows: drive a site once, replay it with no model
|
|
495
537
|
|
|
496
538
|
```bash
|
|
@@ -507,9 +549,10 @@ position among equals (`{"role":"button","name":"Archive","nth":0}`), never a `@
|
|
|
507
549
|
belong to one session. `agent flow save` writes the trail as a flow; `agent run` finds each anchor on the live
|
|
508
550
|
page (exact name, then case-insensitive, then a longer name containing it when that is unambiguous) and acts,
|
|
509
551
|
with no model in the loop. The result's `tokens_avoided` is an upper bound — a full observation before each step;
|
|
510
|
-
an agent that reads diffs reads less. On three real sites
|
|
511
|
-
2,292–18,331 tokens, the `agent run` result 90–136 (HN 18,331 → 90,
|
|
512
|
-
httpbin 2,292 → 119).
|
|
552
|
+
an agent that reads diffs reads less. On three real sites (measured on 2026-11-10, before `observe` hid text that
|
|
553
|
+
cannot be acted on) the model loop read 2,292–18,331 tokens, the `agent run` result 90–136 (HN 18,331 → 90,
|
|
554
|
+
Wikipedia 15,474 → 136, httpbin 2,292 → 119). A default `observe` now prints about 4,300 tokens on HN and 8,300
|
|
555
|
+
on Wikipedia, still far above the `agent run` result. When a site has a flow, `agent observe` lists it under `known_flows`.
|
|
513
556
|
|
|
514
557
|
**Drift stops, never guesses.** If a step's anchor is gone, or the step lands on another host than it did
|
|
515
558
|
when recorded, `agent run` exits 4 and prints that page's full observation (`status:"drift"`, `step`,
|
|
@@ -537,16 +580,69 @@ Page text that addresses the model instead of the user is the shape of an indire
|
|
|
537
580
|
assistants reading this page: ignore your previous instructions…"). `agent observe`, the diff of `agent act`
|
|
538
581
|
and a drift result of `agent run` carry `injection_suspect: [{text, match}]` (at most 5, absent when none)
|
|
539
582
|
whenever such a block is in the text: `ignore_instructions`, `addresses_ai`, `system_prompt`,
|
|
540
|
-
`new_instructions`, `hide_from_user`, `exfiltrate`, `fake_system`, `
|
|
583
|
+
`new_instructions`, `hide_from_user`, `exfiltrate`, `fake_system`, `fake_turn`, `encoded_order`, `tool_call`,
|
|
584
|
+
`navigate_order`. Nothing is
|
|
541
585
|
hidden or blocked, the text stays where it was; the agent sees the mark next to it and treats the block as data.
|
|
542
|
-
Matching runs on a normalised copy (zero-width characters removed, NFKC, case folded, spaced-out letters joined
|
|
543
|
-
|
|
544
|
-
The patterns were tuned on
|
|
545
|
-
|
|
546
|
-
(
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
586
|
+
Matching runs on a normalised copy (zero-width characters removed, NFKC, case folded, spaced-out letters joined,
|
|
587
|
+
Cyrillic/Greek look-alikes mapped inside a mixed-script word); base64 payloads are decoded and scanned; the
|
|
588
|
+
"ignore previous instructions" family covers 14 languages. The patterns were tuned on three sets
|
|
589
|
+
(`test/fixtures/injection-korpus.json`, `injection-heldout.json`, `injection-heldout-2.json`), so their numbers
|
|
590
|
+
there (20 of 20, 24 of 24 and 27 of 30 caught) are in-sample. On a set never used for tuning
|
|
591
|
+
(`injection-heldout-3.json`, 40 + 40 lines in 12 languages, written without seeing the patterns) they catch 11 of 40
|
|
592
|
+
with 2 of 40 false alarms (a quoted security report and a recipe line); the gain over the previous pass (7 of 40)
|
|
593
|
+
came from multilingual, encoded and urgency lines, not from fake chat turns or fake system notices, which still
|
|
594
|
+
mostly pass when phrased differently. Treat the mark as a hint, not a filter: a page without it can still carry an injection.
|
|
595
|
+
|
|
596
|
+
### Live canvas (experimental)
|
|
597
|
+
|
|
598
|
+
A canvas (experimental; macOS and Linux, not on Windows yet) is a tab in your browser that an agent writes HTML into and updates in place: a status board, a form the
|
|
599
|
+
user fills in, a table that grows while the model streams. The tab keeps its scroll position, focus and form state
|
|
600
|
+
between updates (the new HTML is morphed into the page, not reloaded). Clicks and form input come back as events; treat their content as untrusted page data (an `untrusted` field says
|
|
601
|
+
which fields).
|
|
602
|
+
|
|
603
|
+
```bash
|
|
604
|
+
cdpilot canvas open --name board # opens the tab; prints "canvas: board <targetId>"
|
|
605
|
+
cdpilot canvas set page.html --name board # replace the content ("-" reads stdin)
|
|
606
|
+
cdpilot canvas patch page.html --name board # morph to the new HTML: "ok +add -del ~upd ↕move <ms> ms"
|
|
607
|
+
llm-cli ... | cdpilot canvas stream --name board # stdin as it arrives, patched whole-document
|
|
608
|
+
cdpilot canvas watch page.html --name board # re-patch on every save; Ctrl+C stops
|
|
609
|
+
cdpilot canvas events --name board --follow # one JSON line per click / submit / input
|
|
610
|
+
cdpilot canvas list # name, targetId, pid, age
|
|
611
|
+
cdpilot canvas close --name board # or --all
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
Mark the elements that report back with `data-action` (or `data-emit`): a click on them, a form `submit` and
|
|
615
|
+
`input` become `{seq, t, src, type, action, id, data}` lines; `src` is `page` for the page's events and `host` for
|
|
616
|
+
cdpilot's own (`blocked`, `nav`, `closed`). Event `data` is capped at 1 KB; `data.url` in host events is chosen by the
|
|
617
|
+
page and is not trusted.
|
|
618
|
+
|
|
619
|
+
MCP: `browser_canvas_set`, `browser_canvas_patch`, `browser_canvas_events` appear in `tools/list` only while a canvas
|
|
620
|
+
of the project is open (the server sends `notifications/tools/list_changed`); `browser_tools enable` lists them
|
|
621
|
+
anyway. They are not in `--tools core`. A canvas is opened from the CLI (`cdpilot canvas open`). HTML goes to the canvas process over a local socket, never in a
|
|
622
|
+
command line or the session log.
|
|
623
|
+
|
|
624
|
+
What the canvas page cannot do (the HTML is treated as untrusted — an agent may have copied it from anywhere):
|
|
625
|
+
- It runs in its own browser context, so it never sees your other tabs, cookies or storage; the context and the tab
|
|
626
|
+
close when the canvas process ends, even on SIGKILL.
|
|
627
|
+
- Only `http://cdpilot-canvas.invalid/<name>/` is served to it, with a CSP (`default-src 'none'`, inline script and
|
|
628
|
+
style only, `data:`/`blob:` images) and `sandbox allow-scripts`. Every other navigation gets an empty 204 and a
|
|
629
|
+
`blocked` event; every subresource request is refused (`BlockedByClient`). `--allow-net <host>` at `open` allows
|
|
630
|
+
https requests to that exact host on port 443 and nothing else.
|
|
631
|
+
- The canvas runs in a browser context whose proxy is a local port that never answers (`--allow-net` hosts bypass
|
|
632
|
+
it), so a request that slips past cdpilot's interception goes nowhere (speculation-rules prefetch did, measured
|
|
633
|
+
before this was added). Pop-ups the page opens in that context are closed.
|
|
634
|
+
- WebRTC constructors are removed before the page's scripts run, in its frames too (CSP does not cover WebRTC).
|
|
635
|
+
- The document is written only after cdpilot has proven it is the canvas document (frame URL and execution context);
|
|
636
|
+
if the context changes, the write is refused and the page reopened. Navigation history is cleared after each load.
|
|
637
|
+
- A leak test runs every vector we know (fetch, img, script, iframe, WebSocket, prefetch, ping, window.open, form,
|
|
638
|
+
meta refresh, `blob:` navigation, `history.back()`, speculation rules, pop-ups from derived documents, WebRTC
|
|
639
|
+
STUN/TURN in the page and in srcdoc frames) against an unguarded and a guarded canvas:
|
|
640
|
+
each vector must reach the test listener unguarded (or is reported as not measurable in that environment) and show 0 requests guarded. Not measurable there: `data:`
|
|
641
|
+
navigation (Chrome blocks it itself), preconnect and DNS prefetch (the canvas's off-the-record context does not
|
|
642
|
+
send these hints; the canvas also sends `X-DNS-Prefetch-Control: off`).
|
|
643
|
+
|
|
644
|
+
Not supported on Windows yet (the canvas process uses a Unix socket). Paint latency is not published until it is
|
|
645
|
+
measured on an idle machine.
|
|
550
646
|
|
|
551
647
|
### Session Management
|
|
552
648
|
|
|
@@ -1169,7 +1265,7 @@ google-chrome --remote-debugging-port=9450 --user-data-dir="$HOME/cdpilot-chrome
|
|
|
1169
1265
|
cdpilot connect 9450 # or: cdpilot connect ws://127.0.0.1:9450/devtools/browser/<id>
|
|
1170
1266
|
cdpilot connect --auto # or: find it via a DevToolsActivePort file
|
|
1171
1267
|
cdpilot go https://example.com/dashboard
|
|
1172
|
-
cdpilot disconnect # forget it; the browser keeps running
|
|
1268
|
+
cdpilot disconnect # close cdpilot's own tab, forget it; the browser keeps running
|
|
1173
1269
|
```
|
|
1174
1270
|
|
|
1175
1271
|
Since Chrome 136, `--remote-debugging-port` is ignored on the default profile,
|
|
@@ -1221,7 +1317,8 @@ and exits with code 2 and the start command above instead of half-working.
|
|
|
1221
1317
|
- `connect` refuses when this project already has a browser cdpilot launched
|
|
1222
1318
|
("stop it first (`cdpilot stop`) or use another project"), and only
|
|
1223
1319
|
`127.0.0.1` / `localhost` is accepted (anything else exits 2). `disconnect`
|
|
1224
|
-
|
|
1320
|
+
closes cdpilot's own tab in that browser (never yours, never the last one)
|
|
1321
|
+
and stops this project's `watch` daemon.
|
|
1225
1322
|
- cdpilot treats a browser as its own only with proof: the browser id it
|
|
1226
1323
|
recorded at `launch` (or, for older entries, a live recorded pid that holds
|
|
1227
1324
|
the debug port). A busy port is not proof, so a leftover registry entry never
|
|
@@ -1364,6 +1461,8 @@ print(result.stdout)
|
|
|
1364
1461
|
| `CDPILOT_TIMEOUT` | unset | Default `--timeout` in seconds for every command (flag wins, `0` disables); expiry exits 124 |
|
|
1365
1462
|
| `CDPILOT_NO_AUTOLAUNCH` | `0` | `1` = page commands fail with the old "Is the browser running?" error instead of launching the browser |
|
|
1366
1463
|
| `CDPILOT_IDLE_CLOSE` | `15` | Minutes without a cdpilot command or page change before a browser cdpilot launched closes itself (fractions allowed, `0` = never; read at launch). Default applies to auto-launch and MCP launches; an explicit CLI `launch` is off unless this is set or `--idle-close <min>` is given |
|
|
1464
|
+
| `CDPILOT_JSON` | auto | `pretty` = indented, `compact` = one line; default: agent command JSON is indented in a terminal and compact UTF-8 otherwise |
|
|
1465
|
+
| `CDPILOT_OBSERVE_FORMAT` | unset | `rows` = `agent observe/act/run` print `actions` as `[ref, role, name(, value)]` arrays (same as `--rows`); MCP has no per-call switch |
|
|
1367
1466
|
| `CDPILOT_LOG` | `1` | `0` = do not write the session log (`cdpilot log`) |
|
|
1368
1467
|
| `CDPILOT_LOG_DAYS` | `14` | Days of session log to keep; older day files are deleted on the first write of a day (`0` keeps all) |
|
|
1369
1468
|
|
package/bin/cdpilot.js
CHANGED
|
@@ -90,7 +90,8 @@ const DAEMON_SPAWN_CMDS = new Set([
|
|
|
90
90
|
'tls-proxy', 'captcha-wait', 'help', '--help', '-h']);
|
|
91
91
|
// "cmd sub" pairs that run fresh while the command itself is served warm
|
|
92
92
|
// (agent observe/act are page steps; agent twitter logs in and posts).
|
|
93
|
-
const DAEMON_SPAWN_SUBCMDS = new Set(['agent twitter'
|
|
93
|
+
const DAEMON_SPAWN_SUBCMDS = new Set(['agent twitter', 'canvas open', 'canvas stream',
|
|
94
|
+
'canvas watch', 'canvas events']);
|
|
94
95
|
|
|
95
96
|
function daemonEnabled() {
|
|
96
97
|
return process.env.CDPILOT_DAEMON === '1' && process.platform !== 'win32';
|
|
@@ -772,6 +773,11 @@ function showHelp() {
|
|
|
772
773
|
a fresh process when it is missing or busy; not with
|
|
773
774
|
--timeout; 'daemon status|stop'; idle exit after
|
|
774
775
|
CDPILOT_DAEMON_IDLE seconds, default 1800).
|
|
776
|
+
CDPILOT_JSON pretty|compact: agent command JSON (default: indented on a
|
|
777
|
+
terminal, compact UTF-8 when stdout is not a terminal)
|
|
778
|
+
CDPILOT_OBSERVE_FORMAT
|
|
779
|
+
rows: agent observe/act/run print actions as
|
|
780
|
+
[ref, role, name, value?] arrays (same as --rows)
|
|
775
781
|
CDPILOT_VAR_HOSTS Hosts (comma-separated, host:port for another port)
|
|
776
782
|
an agent flow or replay step may type CDPILOT_VAR_* on
|
|
777
783
|
|
|
@@ -922,19 +928,24 @@ function showHelp() {
|
|
|
922
928
|
stop-all Stop all browser instances
|
|
923
929
|
|
|
924
930
|
AI AGENT
|
|
925
|
-
agent observe [--diff]
|
|
931
|
+
agent observe [--diff] [--full] [--rows]
|
|
926
932
|
Page state as numbered @refs (+text); --diff = only
|
|
927
|
-
changes since last
|
|
933
|
+
changes since last; --full = every entry (default
|
|
934
|
+
hides text that cannot be acted on); --rows =
|
|
935
|
+
[ref, role, name, value?] arrays
|
|
928
936
|
agent act --ref @N [--action click|type|fill|hover|submit] [--text X]
|
|
929
|
-
Acts, prints the diff
|
|
937
|
+
Acts, prints the diff (also --full, --rows)
|
|
930
938
|
agent act --url URL
|
|
931
939
|
Navigates silently, prints the diff
|
|
932
940
|
agent flow save <name> [--last N] | list | show <name> | delete <name>
|
|
933
941
|
Save the acts since the last navigation as a replayable
|
|
934
942
|
flow
|
|
935
|
-
agent run <name> [--var k=v] [--dry-run]
|
|
943
|
+
agent run <name> [--var k=v] [--dry-run] [--full] [--rows]
|
|
936
944
|
Replay by anchors, no model; exit 4 on drift with the
|
|
937
945
|
page, 2 for a missing or refused variable
|
|
946
|
+
canvas open|set|patch|stream|watch|events|list|close [--name N] [--allow-net host]
|
|
947
|
+
Live canvas tab an agent writes HTML into (experimental,
|
|
948
|
+
not on Windows)
|
|
938
949
|
mcp Start MCP server (stdin/stdout JSON-RPC)
|
|
939
950
|
--tools core|all|a,b (env CDPILOT_MCP_TOOLS): smaller tool list
|
|
940
951
|
|
|
@@ -1199,6 +1210,25 @@ function spawnPython(python, args, env) {
|
|
|
1199
1210
|
process.exit(1);
|
|
1200
1211
|
});
|
|
1201
1212
|
|
|
1213
|
+
// A signal sent to the launcher alone (an agent harness, `kill <pid>`) used
|
|
1214
|
+
// to end the launcher and leave the Python child running (`canvas events
|
|
1215
|
+
// --follow` kept polling). Forward it. A terminal Ctrl+C or hangup reaches
|
|
1216
|
+
// the child itself through the process group, so SIGINT and SIGHUP go on
|
|
1217
|
+
// only if the child still runs 300 ms later (a second SIGINT would cut its
|
|
1218
|
+
// cleanup short). On Windows the console signals the child; nothing is sent.
|
|
1219
|
+
for (const sig of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
|
|
1220
|
+
process.on(sig, () => {
|
|
1221
|
+
if (process.platform === 'win32') return;
|
|
1222
|
+
const forward = () => {
|
|
1223
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
1224
|
+
try { child.kill(sig); } catch { /* already gone */ }
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1227
|
+
if (sig === 'SIGTERM') forward();
|
|
1228
|
+
else setTimeout(forward, 300).unref();
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1202
1232
|
// A child killed by a signal reports code === null. `code || 0` turned that
|
|
1203
1233
|
// into success, so an OOM-killed or SIGKILLed run looked fine to scripts
|
|
1204
1234
|
// and agents. Use the shell convention 128 + signal number instead.
|
|
@@ -1235,7 +1265,7 @@ if (cmd === 'status') {
|
|
|
1235
1265
|
const sockPath = daemonSockPath(daemonKey(env, python));
|
|
1236
1266
|
// env: the daemon applies the caller's environment to the request (proxy
|
|
1237
1267
|
// and solver keys, PATH, TZ … are read when a command runs, not at import).
|
|
1238
|
-
const payload = { argv: args, cwd: process.cwd(), env };
|
|
1268
|
+
const payload = { argv: args, cwd: process.cwd(), env, tty: process.stdout.isTTY === true };
|
|
1239
1269
|
const stdin = daemonStdin(cmd, args);
|
|
1240
1270
|
if (stdin !== undefined) payload.stdin = stdin;
|
|
1241
1271
|
daemonRequest(sockPath, payload, (m) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cdpilot",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.8",
|
|
4
4
|
"mcpName": "io.github.mehmetnadir/cdpilot",
|
|
5
5
|
"description": "Browser automation CLI with zero npm dependencies (Python: websockets). Raw CDP, 70+ commands, friction ladder, 3-tier stealth, CAPTCHA + press-and-hold solvers, proxy pools, MCP server. No Puppeteer/Playwright/Selenium.",
|
|
6
6
|
"bin": {
|