@pingroom/cli 0.4.0 → 0.6.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.
- package/README.md +265 -7
- package/bin/pingroom.js +1744 -46
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -3,17 +3,135 @@
|
|
|
3
3
|
Send PingRoom pings — and ask a human a question and block for their answer —
|
|
4
4
|
from CI, scripts, and agents. Delivered as push straight to your phone.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
One dependency (`qrcode-terminal`, used only to draw the pairing QR). Works
|
|
7
|
+
anywhere Node ≥ 20 runs.
|
|
8
|
+
|
|
9
|
+
> **Release status:** npm currently serves 0.6.0. The automatic verified-phone
|
|
10
|
+
> activation flow and `pingroom activate` documented below are in the tested
|
|
11
|
+
> 0.6.1 release candidate on `main`; the public GitHub Action remains pinned to
|
|
12
|
+
> 0.6.0 until 0.6.1 is published and clean-install verified.
|
|
13
|
+
|
|
14
|
+
## Install and first run
|
|
15
|
+
|
|
16
|
+
Install globally, then connect:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install --global @pingroom/cli
|
|
20
|
+
pingroom
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Or use it without a global install:
|
|
7
24
|
|
|
8
25
|
```bash
|
|
9
|
-
npx @pingroom/cli
|
|
26
|
+
npx --yes @pingroom/cli
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Either command starts the same connection prompt. QR pairing stores the selected
|
|
30
|
+
account, credential, and delivery room in `~/.pingroom`; later commands reuse
|
|
31
|
+
them, so a local invocation needs neither `PINGROOM_TOKEN` nor `PINGROOM_ROOM`.
|
|
32
|
+
The email fallback stores the credential only. Setting
|
|
33
|
+
`pingroom config set default_room <invite-code>` enables room-addressed commands,
|
|
34
|
+
but private Agent Inbox and Handoff delivery require a connection approved with
|
|
35
|
+
a delivery room. Use QR pairing for the complete flow.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pingroom ping -m "Deploy succeeded ✅"
|
|
39
|
+
# or: npx --yes @pingroom/cli ping -m "Deploy succeeded ✅"
|
|
10
40
|
```
|
|
11
41
|
|
|
12
42
|
Commands: `ping` (send), `ask` (ask a human), `watch` (block on an existing
|
|
13
43
|
question), `list`, `cancel`, `handoff` (hand a decision to a specific human),
|
|
14
|
-
|
|
44
|
+
`handoffs` (list open or recent Handoffs), `live` (lock-screen progress card),
|
|
45
|
+
`hook` (Claude Code), `mcp` (client setup), `activate` (retry the Agent Inbox
|
|
46
|
+
test), `config`, and `logout`.
|
|
15
47
|
Run `pingroom --help` for the full reference.
|
|
16
48
|
|
|
49
|
+
## Connecting
|
|
50
|
+
|
|
51
|
+
Run `pingroom` (global install) or `npx --yes @pingroom/cli` (no install) with no
|
|
52
|
+
arguments. It prints a QR code — scan it with the PingRoom app and pick both the
|
|
53
|
+
account and the room the agent delivers to — or take the emailed-code fallback.
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
$ pingroom
|
|
57
|
+
Not connected. How do you want to connect?
|
|
58
|
+
1) Scan a QR code with the PingRoom app
|
|
59
|
+
2) Email me a code
|
|
60
|
+
Choose [1]:
|
|
61
|
+
|
|
62
|
+
[QR]
|
|
63
|
+
Or open: https://pingroom.io/app/agents/pair?token=…
|
|
64
|
+
Waiting for approval… ✓ Connected as @agt_ab12cd34ef → #Project X
|
|
65
|
+
Sending a test question to PingRoom…
|
|
66
|
+
Answer “PingRoom connected. Can you answer this?” on your phone.
|
|
67
|
+
✓ Test question answered (Yes). Agent Inbox is ready.
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
After QR approval, the CLI saves the active credential first, then sends one
|
|
71
|
+
idempotent onboarding Question and observes it through the Handoff wait API.
|
|
72
|
+
Short network and server failures are retried, and `Retry-After` is honored for
|
|
73
|
+
rate limits within the two-minute overall deadline. An answer alone is not
|
|
74
|
+
reported as success: the terminal response must also carry the server's exact
|
|
75
|
+
`activation_completed: true` stamp. On supporting server and mobile builds,
|
|
76
|
+
that stamp means the native phone returned the opaque proof carried in the push
|
|
77
|
+
before the human answer, and this CLI then observed the result. An answered
|
|
78
|
+
response whose stamp is false or missing is incomplete and is not retried as if
|
|
79
|
+
history could be rewritten. If the Question is still pending when the local
|
|
80
|
+
deadline elapses, or activation cannot start, the CLI prints the recovery
|
|
81
|
+
command and exits with the connection still saved and usable. A terminal test
|
|
82
|
+
without the stamp requires a current PingRoom app and a fresh numbered attempt;
|
|
83
|
+
run `pingroom activate` again with the saved connection.
|
|
84
|
+
|
|
85
|
+
Resume an open idempotent check with the saved QR credential:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pingroom activate
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
An incomplete explicit retry exits `1`; it never deletes or replaces the saved
|
|
92
|
+
credential. The command does not fall back to `PINGROOM_TOKEN`, an email-only
|
|
93
|
+
credential, or a credential without `pingroom:handoffs:create` and a
|
|
94
|
+
QR-selected delivery room. Email-code and other non-interactive credential
|
|
95
|
+
flows do not run the phone-response loop automatically.
|
|
96
|
+
|
|
97
|
+
There is deliberately no `login` command: being unconnected is a state the tool
|
|
98
|
+
resolves, not one you have to discover. Once connected, bare `pingroom` prints
|
|
99
|
+
that status line followed by the usual help.
|
|
100
|
+
|
|
101
|
+
The credential lands in `~/.pingroom/credentials.json` (mode `0600`, inside a
|
|
102
|
+
`0700` directory). `PINGROOM_HOME` moves that directory; `pingroom logout`
|
|
103
|
+
clears it.
|
|
104
|
+
|
|
105
|
+
**CI is unaffected.** `PINGROOM_TOKEN` in the environment always outranks the
|
|
106
|
+
stored credential, and a non-interactive shell never prompts and never draws a
|
|
107
|
+
QR — a command that needs a credential and has none fails with exit `2` pointing
|
|
108
|
+
at `PINGROOM_TOKEN`.
|
|
109
|
+
|
|
110
|
+
### Local settings
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
pingroom config set default_room ab12cd # fallback for --room
|
|
114
|
+
pingroom config set api_url https://api.pingroom.io
|
|
115
|
+
pingroom config get default_room
|
|
116
|
+
pingroom config list
|
|
117
|
+
pingroom config set api_url "" # an empty value clears the key
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Precedence, highest first:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
explicit flag > env var > ~/.pingroom/config.json > built-in default
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
So `--room` beats `PINGROOM_ROOM` beats `default_room` (and, last of all, the
|
|
127
|
+
room the credential was paired to); `--api` beats `PINGROOM_API_URL` beats
|
|
128
|
+
`api_url`.
|
|
129
|
+
|
|
130
|
+
A stored paired credential is bound to the API origin that issued it. An API
|
|
131
|
+
override can change the path on that origin, but the CLI refuses to send the
|
|
132
|
+
stored bearer to a different origin. For an intentional custom-host override,
|
|
133
|
+
provide that host's token explicitly with `--token` or `PINGROOM_TOKEN`.
|
|
134
|
+
|
|
17
135
|
## Getting a webhook URL
|
|
18
136
|
|
|
19
137
|
In the PingRoom app, open a room → **Connections → Incoming webhooks → Add**. Copy the
|
|
@@ -28,8 +146,11 @@ pingroom ping [options]
|
|
|
28
146
|
-t, --title <text> Ping title (<= 40 chars)
|
|
29
147
|
-a, --action <1-4> Quick-action slot to attribute the ping to
|
|
30
148
|
-d, --data <json> Extra JSON data, e.g. '{"commit":"abc123"}'
|
|
149
|
+
--url <https-url> Make the ping a tappable link (absolute http(s) URL)
|
|
150
|
+
--button-label <t> Link button text (<= 26 chars; requires --url)
|
|
31
151
|
--require-ack Keep the ping open until an eligible recipient acknowledges it
|
|
32
152
|
--ack-timeout <s> Ack deadline in seconds (requires --require-ack)
|
|
153
|
+
--attach <path> Attach a file; repeat for up to 10 (requires --token)
|
|
33
154
|
-w, --webhook <url> Room webhook URL (or env PINGROOM_WEBHOOK_URL)
|
|
34
155
|
--token <token> Agent access token (or env PINGROOM_TOKEN)
|
|
35
156
|
--room <code> Room invite code (used with --token)
|
|
@@ -48,9 +169,125 @@ pingroom ping -w "$PINGROOM_WEBHOOK_URL" -m "Production health check failed" \
|
|
|
48
169
|
Webhook timeouts accept 1–86400 seconds. Agent-token room pings accept
|
|
49
170
|
60–86400 seconds.
|
|
50
171
|
|
|
172
|
+
To attach a tappable link button (a "link ping"), add `--url` and optionally
|
|
173
|
+
`--button-label`. They fold into the structured `data` object as
|
|
174
|
+
`{"url": ..., "button_label": ...}` — the same convention accepted raw via
|
|
175
|
+
`--data`:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
pingroom ping -w "$PINGROOM_WEBHOOK_URL" -m "Build 512 ready" \
|
|
179
|
+
--url https://ci.example.com/builds/512 --button-label "Open build"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The URL must be absolute http(s) (≤ 2048 chars); the label caps at 26 chars.
|
|
183
|
+
|
|
184
|
+
To send the file itself rather than a link to it, use `--attach`. Each file is
|
|
185
|
+
uploaded separately and only the resulting ids ride the ping; recipients open
|
|
186
|
+
them from the ping, authenticated:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
pingroom ping --token "$PINGROOM_TOKEN" --room AB12 -m "Nightly report" \
|
|
190
|
+
--attach ./report.pdf --attach ./summary.md
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Accepted types are `md`, `pdf`, `html`, `txt`, `jpg`, `jpeg`, `png`, up to
|
|
194
|
+
20 MiB each and 10 per ping. `--attach` needs an agent token — a webhook ping
|
|
195
|
+
has no uploader identity to bind private files to — and the bound account must
|
|
196
|
+
hold Pro (otherwise the upload fails with `pro_required`). An upload that never
|
|
197
|
+
reaches a ping expires by itself after 24 hours.
|
|
198
|
+
|
|
51
199
|
Exit codes: `0` success · `1` delivery failed · `2` bad usage. So CI fails loudly if a
|
|
52
200
|
ping doesn't land.
|
|
53
201
|
|
|
202
|
+
## Live Activities (`pingroom live`)
|
|
203
|
+
|
|
204
|
+
A **live-status stream** is one long-running thing shown as a self-updating card
|
|
205
|
+
on the Lock Screen (iOS Live Activity / Dynamic Island, Android live update, and
|
|
206
|
+
a full inline card in the app). `start` opens it with one alert, `update` moves
|
|
207
|
+
it **silently**, `end` closes it with one completion alert.
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
pingroom live <start|update|end|get> [options]
|
|
211
|
+
|
|
212
|
+
-c, --correlation-id <id> The stream key — reuse it for every ping (required)
|
|
213
|
+
--template <name> start only: status | steps | progress | metrics |
|
|
214
|
+
countdown | question | matchup (fixed at creation)
|
|
215
|
+
--steps <a,b,c> start only: 2-8 comma-separated step labels
|
|
216
|
+
-m, --message <text> The card's live message line
|
|
217
|
+
--progress <0..1> Progress bar / Dynamic Island gauge
|
|
218
|
+
--step <n> Current step index (steps template)
|
|
219
|
+
--metric <label:value> Repeatable, up to 3 (metrics template)
|
|
220
|
+
--deadline-at <epoch> Countdown target (countdown template)
|
|
221
|
+
--eta-at <epoch> Live ETA (status/progress templates)
|
|
222
|
+
--prompt <text> The ask (question template)
|
|
223
|
+
--option <value:label> Repeatable, up to 4 (question template)
|
|
224
|
+
--left <label:value> Left side (matchup template)
|
|
225
|
+
--right <label:value> Right side (matchup template)
|
|
226
|
+
--center <text> Center score/clock, <= 40 (matchup template)
|
|
227
|
+
--accent-override <#rrggbb> Semantic accent for this frame
|
|
228
|
+
--failed end only: finish as failed instead of done
|
|
229
|
+
-t, --title <text> Card title (<= 40 chars)
|
|
230
|
+
-a, --action <1-4> Quick-action slot supplying the icon and sound
|
|
231
|
+
--require-ack Add an Acknowledge button
|
|
232
|
+
--ack-timeout <s> Ack deadline in seconds
|
|
233
|
+
-w, --webhook <url> Room webhook URL instead of a token
|
|
234
|
+
--token <token> Agent access token (or env PINGROOM_TOKEN)
|
|
235
|
+
--room <code> Room invite code (used with --token)
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Works with either an agent token (`--token`, needs the `pingroom:live:write`
|
|
239
|
+
scope) or a room's incoming webhook (`--webhook`, Pro) — both speak the same
|
|
240
|
+
`live_status` contract.
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
# Track a deploy end to end.
|
|
244
|
+
pingroom live start -c deploy-42 --template steps \
|
|
245
|
+
--steps "Build,Test,Deploy,Verify" -t "Release 1.4.0"
|
|
246
|
+
pingroom live update -c deploy-42 --step 2 -m "Deploying to prod"
|
|
247
|
+
pingroom live end -c deploy-42 -m "Shipped 1.4.0" # add --failed to fail it
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
All 7 templates are expressible:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
# question — up to 4 options. A bare token is both value and label.
|
|
254
|
+
pingroom live start -c q1 --template question \
|
|
255
|
+
--prompt "Deploy where?" --option prod:Production --option staging:Staging
|
|
256
|
+
|
|
257
|
+
# matchup — two sides plus a center score/clock.
|
|
258
|
+
pingroom live start -c game-3 --template matchup \
|
|
259
|
+
--left ARS:2 --right CHE:1 --center "68'"
|
|
260
|
+
|
|
261
|
+
# metrics — up to 3 counters.
|
|
262
|
+
pingroom live start -c host-1 --template metrics --metric "CPU:45%" --metric "RPS:1.2k"
|
|
263
|
+
|
|
264
|
+
# countdown — a large live timer.
|
|
265
|
+
pingroom live start -c win-9 --template countdown --deadline-at 1750003600
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
`--accent-override` takes `#rrggbb` **or** a bare `rrggbb` (case-insensitive;
|
|
269
|
+
it is normalized to lowercase with the `#` before it is sent). Pass it bare, or
|
|
270
|
+
quote it — an *unquoted* `#` starts a comment in `sh`, `bash` and `zsh`, which
|
|
271
|
+
eats the hex and the rest of the line, and the CLI then exits `2` with
|
|
272
|
+
`option --accent-override needs a value`:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
pingroom live update -c deploy-42 --accent-override e33122 # ok
|
|
276
|
+
pingroom live update -c deploy-42 --accent-override '#e33122' # ok
|
|
277
|
+
pingroom live update -c deploy-42 --accent-override #e33122 # shell eats it
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Always `end` a stream.** Terminal `done`/`failed` pings are never rate-limited
|
|
281
|
+
or quota-blocked, precisely so a card can't be metered into hanging open on
|
|
282
|
+
someone's Lock Screen. Abandoned streams are swept after ~15 minutes.
|
|
283
|
+
|
|
284
|
+
`--template` and `--steps` are fixed when the stream is created; passing them to
|
|
285
|
+
`update`/`end` is a usage error rather than a silent no-op. `pingroom live get`
|
|
286
|
+
(agent token only) reads a stream back — every stored field — so a restarted
|
|
287
|
+
producer reconciles instead of opening a duplicate.
|
|
288
|
+
|
|
289
|
+
Full protocol: <https://pingroom.io/liveactivities.md>
|
|
290
|
+
|
|
54
291
|
## GitHub Actions
|
|
55
292
|
|
|
56
293
|
```yaml
|
|
@@ -204,13 +441,19 @@ Print a ready-to-paste config:
|
|
|
204
441
|
|
|
205
442
|
```bash
|
|
206
443
|
pingroom hook --print-config
|
|
444
|
+
# no global install: npx --yes @pingroom/cli hook --print-config
|
|
207
445
|
```
|
|
208
446
|
|
|
209
|
-
|
|
210
|
-
|
|
447
|
+
If you have not connected yet, run `pingroom` (or `npx --yes @pingroom/cli`) and
|
|
448
|
+
scan the QR first. The hook reads the stored credential and the room selected
|
|
449
|
+
during pairing automatically. No environment variables are needed for a normal
|
|
450
|
+
local setup; merge the printed `hooks` block into `~/.claude/settings.json`.
|
|
451
|
+
|
|
452
|
+
Environment variables remain available for CI and other headless shells, and
|
|
453
|
+
take precedence over the paired values:
|
|
211
454
|
|
|
212
455
|
```bash
|
|
213
|
-
export PINGROOM_TOKEN="<your agent token>"
|
|
456
|
+
export PINGROOM_TOKEN="<your agent token>"
|
|
214
457
|
export PINGROOM_ROOM="<room invite code>"
|
|
215
458
|
```
|
|
216
459
|
|
|
@@ -230,8 +473,23 @@ blocks the agent. Because the `PreToolUse` hook holds the tool call open while i
|
|
|
230
473
|
waits for you, give it a generous `timeout` (the printed config uses 960s) and
|
|
231
474
|
tune the approval-question expiry with `--ttl <seconds>` (default 900).
|
|
232
475
|
|
|
476
|
+
## MCP client setup
|
|
477
|
+
|
|
478
|
+
Print the canonical remote endpoint, a copy-ready Claude Code command, Cursor
|
|
479
|
+
JSON, and the Claude Desktop custom-connector steps:
|
|
480
|
+
|
|
481
|
+
```bash
|
|
482
|
+
pingroom mcp
|
|
483
|
+
# no global install: npx --yes @pingroom/cli mcp
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
`pingroom mcp add claude-code` prints the exact `claude mcp add` command but does
|
|
487
|
+
not execute it or modify client configuration. After adding the server, use the
|
|
488
|
+
client's MCP controls to authenticate in the browser; no PingRoom API key is
|
|
489
|
+
pasted into its config.
|
|
490
|
+
|
|
233
491
|
For a fully typed client, use [`@pingroom/sdk`](https://www.npmjs.com/package/@pingroom/sdk).
|
|
234
|
-
See <https://pingroom.io/connect-mcp.md>
|
|
492
|
+
See <https://pingroom.io/connect-mcp.md> for the complete MCP and OAuth guide.
|
|
235
493
|
|
|
236
494
|
## License
|
|
237
495
|
|