@vforsh/argus 0.4.0 → 0.5.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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/argus.js +1108 -558
- package/dist/cli/program.d.ts +11 -1
- package/dist/cli/program.d.ts.map +1 -1
- package/dist/cli/program.js +14 -9
- package/dist/cli/program.js.map +1 -1
- package/dist/cli/register/index.d.ts.map +1 -1
- package/dist/cli/register/index.js +2 -0
- package/dist/cli/register/index.js.map +1 -1
- package/dist/cli/register/sessionCommands.d.ts +3 -0
- package/dist/cli/register/sessionCommands.d.ts.map +1 -0
- package/dist/cli/register/sessionCommands.js +24 -0
- package/dist/cli/register/sessionCommands.js.map +1 -0
- package/dist/output/io.d.ts +7 -0
- package/dist/output/io.d.ts.map +1 -1
- package/dist/output/io.js +21 -2
- package/dist/output/io.js.map +1 -1
- package/dist/session/runSession.d.ts +15 -0
- package/dist/session/runSession.d.ts.map +1 -0
- package/dist/session/runSession.js +184 -0
- package/dist/session/runSession.js.map +1 -0
- package/dist/session/sessionArgv.d.ts +42 -0
- package/dist/session/sessionArgv.d.ts.map +1 -0
- package/dist/session/sessionArgv.js +224 -0
- package/dist/session/sessionArgv.js.map +1 -0
- package/dist/session/sessionDispatch.d.ts +21 -0
- package/dist/session/sessionDispatch.d.ts.map +1 -0
- package/dist/session/sessionDispatch.js +137 -0
- package/dist/session/sessionDispatch.js.map +1 -0
- package/dist/session/stdioCapture.d.ts +33 -0
- package/dist/session/stdioCapture.d.ts.map +1 -0
- package/dist/session/stdioCapture.js +56 -0
- package/dist/session/stdioCapture.js.map +1 -0
- package/dist/skill/argus/SKILL.md +29 -0
- package/dist/skill/argus/reference/SESSION.md +153 -0
- package/package.json +5 -5
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Session Transport
|
|
2
|
+
|
|
3
|
+
`argus session` serves many commands from one process over stdin/stdout. Use it when a harness
|
|
4
|
+
issues dozens of sequential commands against the same watcher: each one-shot `argus` invocation
|
|
5
|
+
pays Node startup plus watcher discovery (~100-200ms), and the session pays it once.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
argus session app
|
|
9
|
+
argus session app --request-timeout 30s
|
|
10
|
+
argus session app --reconnect
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The watcher id is resolved once and pinned. Every request runs the same Commander action the
|
|
14
|
+
one-shot CLI would run, with `--json` forced on, so payloads match `argus <cmd> --json` byte for
|
|
15
|
+
byte and a host can switch transports without changing how it parses results.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Framing
|
|
20
|
+
|
|
21
|
+
stdin takes one JSON object per line; stdout answers with one JSON object per line and nothing
|
|
22
|
+
else. Human output goes to stderr.
|
|
23
|
+
|
|
24
|
+
The first line is written before any request is read:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{ "type": "ready", "protocolVersion": 1, "argusVersion": "0.4.0", "watcher": { "id": "app", "host": "127.0.0.1", "port": 51733 } }
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Request
|
|
31
|
+
|
|
32
|
+
| Field | Type | Notes |
|
|
33
|
+
| --------- | ---------------- | ------------------------------------------------------------------ |
|
|
34
|
+
| `id` | string \| number | Optional; echoed on the response. Omit only if you match by order. |
|
|
35
|
+
| `cmd` | string | Command path, space-separated. Aliases work (`js`, `ext`, `wait`). |
|
|
36
|
+
| `args` | object | Named arguments. Mutually exclusive with `argv`. |
|
|
37
|
+
| `argv` | string[] | Raw CLI tokens. Mutually exclusive with `args`. |
|
|
38
|
+
| `timeout` | string \| number | Per-request watchdog (`"30s"`, or milliseconds). `0` disables. |
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{"id": 1, "cmd": "eval", "args": {"expression": "location.href"}}
|
|
42
|
+
{"id": 2, "cmd": "eval-until", "args": {"expression": "window.APP_READY", "totalTimeout": "30s"}}
|
|
43
|
+
{"id": 3, "cmd": "click", "args": {"selector": "button.submit"}}
|
|
44
|
+
{"id": 4, "cmd": "drag", "argv": ["--selector", "canvas", "--pos", "320,240", "--by", "80,-30"]}
|
|
45
|
+
{"id": 5, "cmd": "screenshot", "args": {"out": "./shot.png"}}
|
|
46
|
+
{"id": 6, "cmd": "dom tree", "args": {"selector": "body", "depth": 2}}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`args` keys are resolved against the command's own definition, so anything the CLI accepts is
|
|
50
|
+
reachable:
|
|
51
|
+
|
|
52
|
+
- **Options** match by camelCase name, long flag, or short flag: `totalTimeout`, `total-timeout`,
|
|
53
|
+
and `q` all work.
|
|
54
|
+
- **Positional arguments** match by their declared name (`key`/`value` for `storage local set`,
|
|
55
|
+
`role` for `locate role`) and are filled in declaration order. The leading watcher id is
|
|
56
|
+
injected for you.
|
|
57
|
+
- **An option wins over a positional of the same name.** `{"expression": "…"}` on `eval` becomes
|
|
58
|
+
`--expression`, the spelling the CLI already documents as equivalent to the positional.
|
|
59
|
+
- **Repeatable options** take an array: `{"arg": ["level=10", "mode=fast"]}`.
|
|
60
|
+
- **Switches** take a boolean: `{"all": true}`, `{"await": false}` (which sends `--no-await`).
|
|
61
|
+
|
|
62
|
+
### Response
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{"id": 1, "ok": true, "result": {"ok": true, "result": "https://app.example/", "type": "string", "exception": null}, "durationMs": 8}
|
|
66
|
+
{"id": 2, "ok": false, "error": {"message": "Total timeout exceeded (30s)", "code": "session_command_failed"}, "exitCode": 1, "durationMs": 30014}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- `result` is the command's `--json` document. A command that streams newline-delimited JSON
|
|
70
|
+
(`eval --interval`) yields an array plus `"stream": true`; output that is not JSON at all comes
|
|
71
|
+
back verbatim as a string plus `"raw": true`.
|
|
72
|
+
- `stderr` is present when the command wrote any, on success or failure. It is also mirrored to
|
|
73
|
+
the session's own stderr, so a human tailing the process still sees it live.
|
|
74
|
+
- `durationMs` is the wall-clock time the CLI spent on the request.
|
|
75
|
+
|
|
76
|
+
### Control requests
|
|
77
|
+
|
|
78
|
+
| `cmd` | Effect |
|
|
79
|
+
| ------ | ------------------------------------------------------------ |
|
|
80
|
+
| `ping` | Answers `{"pong": true, "watcher": "<id>"}` without any I/O. |
|
|
81
|
+
| `quit` | Answers, then closes the session with exit code 0. |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Semantics
|
|
86
|
+
|
|
87
|
+
**Ordering.** Requests are served strictly in submission order. Pipelining still pays off — the
|
|
88
|
+
host can keep writing while a command is in flight — but responses arrive in the order the
|
|
89
|
+
requests did.
|
|
90
|
+
|
|
91
|
+
**Timeouts.** A request that outlives its watchdog is answered with `session_request_timeout` and
|
|
92
|
+
the session moves on. The abandoned command keeps its own output buffer, so nothing it writes
|
|
93
|
+
later can land in a later response.
|
|
94
|
+
|
|
95
|
+
**Error isolation.** A malformed line, an unknown command, or a failing command answers
|
|
96
|
+
`ok: false` and the session stays up. The `error.code` values specific to this transport are
|
|
97
|
+
`session_invalid_request`, `session_unknown_command`, `session_command_rejected`,
|
|
98
|
+
`session_request_timeout`, and `session_command_failed`; a watcher-side failure carries its own
|
|
99
|
+
code through unchanged.
|
|
100
|
+
|
|
101
|
+
**Watcher loss.** By default the session is fail-fast: after a failed request it probes the
|
|
102
|
+
watcher, and if the watcher is gone it writes a notice to stderr and exits `1`. Pass `--reconnect`
|
|
103
|
+
to keep it alive instead — every request re-resolves the id through the registry, so a watcher
|
|
104
|
+
restarted under the same id (even on a new port) is picked up on the next request.
|
|
105
|
+
|
|
106
|
+
**Shutdown.** `{"cmd": "quit"}` or EOF on stdin exits `0`. Requests still queued on stdin when the
|
|
107
|
+
session exits — after a `quit`, or after watcher loss — are not answered; fail them on the host
|
|
108
|
+
side when the process exits.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Not available in a session
|
|
113
|
+
|
|
114
|
+
Commands that never return on their own, or that would read the stream the transport owns, are
|
|
115
|
+
refused with `session_command_rejected`:
|
|
116
|
+
|
|
117
|
+
- `start`, `chrome start`, `watcher start`, `watcher native-host` — daemons; run them as their own
|
|
118
|
+
process and point the session at the resulting watcher.
|
|
119
|
+
- `logs tail`, `net tail`, `net sse` — stream until interrupted.
|
|
120
|
+
- `session` — no nesting.
|
|
121
|
+
- Any request carrying `--stdin` or a `-` expression. Use `--file` or an inline expression.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Host sketch
|
|
126
|
+
|
|
127
|
+
```js
|
|
128
|
+
import { spawn } from 'node:child_process'
|
|
129
|
+
import readline from 'node:readline'
|
|
130
|
+
|
|
131
|
+
const proc = spawn('argus', ['session', 'app'], { stdio: ['pipe', 'pipe', 'inherit'] })
|
|
132
|
+
const lines = readline.createInterface({ input: proc.stdout })
|
|
133
|
+
const pending = new Map()
|
|
134
|
+
let nextId = 0
|
|
135
|
+
|
|
136
|
+
lines.on('line', (line) => {
|
|
137
|
+
const message = JSON.parse(line)
|
|
138
|
+
if (message.type === 'ready') return
|
|
139
|
+
pending.get(message.id)?.(message)
|
|
140
|
+
pending.delete(message.id)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
const run = (cmd, args) =>
|
|
144
|
+
new Promise((resolve) => {
|
|
145
|
+
const id = ++nextId
|
|
146
|
+
pending.set(id, resolve)
|
|
147
|
+
proc.stdin.write(`${JSON.stringify({ id, cmd, args })}\n`)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
await run('eval-until', { expression: 'window.APP_READY', totalTimeout: '30s' })
|
|
151
|
+
await run('click', { selector: 'button.start' })
|
|
152
|
+
proc.stdin.end()
|
|
153
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vforsh/argus",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/vforsh/argus.git",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@vforsh/argus-client": "^0.
|
|
34
|
-
"@vforsh/argus-core": "^0.
|
|
35
|
-
"@vforsh/argus-plugin-api": "^0.
|
|
36
|
-
"@vforsh/argus-watcher": "^0.
|
|
33
|
+
"@vforsh/argus-client": "^0.5.0",
|
|
34
|
+
"@vforsh/argus-core": "^0.5.0",
|
|
35
|
+
"@vforsh/argus-plugin-api": "^0.5.0",
|
|
36
|
+
"@vforsh/argus-watcher": "^0.5.0",
|
|
37
37
|
"commander": "14.0.2",
|
|
38
38
|
"esbuild": "0.25.12",
|
|
39
39
|
"prettier": "3.7.4"
|