@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.
Files changed (3) hide show
  1. package/README.md +265 -7
  2. package/bin/pingroom.js +1744 -46
  3. 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
- Zero dependencies. Works anywhere Node 20 runs.
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 ping -w "$PINGROOM_WEBHOOK_URL" -m "Deploy succeeded ✅"
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
- and `handoffs` (list open or recent Handoffs).
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
- Then set your credentials and merge the printed `hooks` block into
210
- `~/.claude/settings.json`:
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>" # a room the agent belongs to
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> to connect Cursor, Claude Desktop, or Claude Code.
492
+ See <https://pingroom.io/connect-mcp.md> for the complete MCP and OAuth guide.
235
493
 
236
494
  ## License
237
495