pidge-cli 0.13.0 → 0.13.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/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.13.1 — 2026-06-26
4
+
5
+ Polish from an agent E2E (2026-06-26). No breaking changes.
6
+
7
+ - **fix:** the manifest-version nudge no longer scolds "your CLI is stale, UPDATE it".
8
+ pidge is a thin pipe — `--param KEY=VALUE` carries any new `/notify` field NOW, so a
9
+ server manifest bump almost never needs a CLI release. The nudge is reframed as "new
10
+ capabilities + how to use them today" and `KNOWN_MANIFEST_VERSION` is bumped 31 → 36
11
+ (the current server), silencing the false-positive on `@latest`. (#26)
12
+ - **fix:** the public manifest (#249-A) curl in that nudge drops the mandatory Bearer —
13
+ the catalog reads without a key; the Bearer is shown only as the optional way to also
14
+ see the channel's own config. (#26)
15
+ - **fix:** the realtime reconnect log no longer reads "realtime socket **socket** closed"
16
+ (doubled word) and the counter no longer sticks at "attempt 1/4" — it now shows a
17
+ monotonic "reconnect #N" so a connect→drop flap visibly advances instead of looking
18
+ like a stuck loop. (#25)
19
+
3
20
  ## 0.13.0 — 2026-06-25
4
21
 
5
22
  Template system (#246) — the agent now declares an intent TYPE; the server maps it to
package/bin/pidge.js CHANGED
@@ -504,7 +504,7 @@ function fetchT(url, opts = {}, timeoutMs = 30000) {
504
504
  // The server advertises its manifest version on every response. When it's newer
505
505
  // than what this CLI shipped knowing, nudge on stderr — the agent re-reads the
506
506
  // manifest (whats_new) and learns the new capabilities without polling.
507
- const KNOWN_MANIFEST_VERSION = 31;
507
+ const KNOWN_MANIFEST_VERSION = 36;
508
508
  const NAG_TTL_MS = 24 * 60 * 60 * 1000; // #241: at most one nag per 24 h
509
509
  let newsWarned = false;
510
510
 
@@ -541,9 +541,13 @@ function checkManifestNews(res) {
541
541
  }
542
542
  newsWarned = true;
543
543
  writeState({ manifestVersion: { value: ver, seenAt: new Date().toISOString() } });
544
- // #119: a pinned npx ref never updates itself give the CONCRETE command.
545
- // #243: show the AUTHENTICATED curl so re-reading the manifest doesn't 401.
546
- console.error(`pidge: the server has NEW capabilities (manifest v${ver}; this CLI knows v${KNOWN_MANIFEST_VERSION}) — re-read the contract: curl -H "Authorization: Bearer $PIDGE_TOKEN" $PIDGE_URL/api/v1/manifest (see whats_new), then UPDATE the CLI: npm i -g pidge-cli@latest (npx users: run npx pidge-cli@latest, a pinned ref never self-updates). Silence this with --quiet-nag or PIDGE_QUIET_NAG=1.`);
544
+ // #26: pidge is a THIN PIPE a server manifest bump almost never needs a CLI
545
+ // release, because --param carries any new /notify field NOW. So the nudge is
546
+ // "new capabilities + how to use them today", NOT "your CLI is stale, update it".
547
+ // #249-A: the manifest is PUBLIC — the curl reads the catalog without a key
548
+ // (a key only adds your channel's own config). Updating the CLI is the LAST,
549
+ // optional step (only to gain native flags), never the headline.
550
+ console.error(`pidge: the server has NEW capabilities (manifest v${ver}; this CLI knows v${KNOWN_MANIFEST_VERSION}) — pidge is a thin pipe, so you can use any new /notify field RIGHT NOW via --param KEY=VALUE. Read the catalog (whats_new) in the public manifest: curl $PIDGE_URL/api/v1/manifest (public; add -H "Authorization: Bearer $PIDGE_TOKEN" to also see your channel's config). Updating the CLI only matters to gain native flags: npx pidge-cli@latest (a pinned ref never self-updates). Silence this with --quiet-nag or PIDGE_QUIET_NAG=1.`);
547
551
  }
548
552
 
549
553
  // ---------------------------------------------------------------------------
@@ -641,7 +645,9 @@ function cableSubscribe({ channel, onUp, onFrame, onDown, base = BASE, token = T
641
645
  if (f.identifier === identifier && f.message) onFrame(f.message);
642
646
  };
643
647
  ws.onerror = () => { /* onclose follows with the code */ };
644
- ws.onclose = (e) => die(`socket closed (${e.code})`);
648
+ // #25: the reconnect log prefixes "realtime socket …", so the reason must NOT
649
+ // start with "socket" again (was "socket socket closed (1006)").
650
+ ws.onclose = (e) => die(`closed (${e.code})`);
645
651
  return { close: () => { closed = true; clearInterval(beatCheck); try { ws.close(); } catch { /* noop */ } } };
646
652
  }
647
653
 
@@ -651,7 +657,8 @@ function cableSubscribe({ channel, onUp, onFrame, onDown, base = BASE, token = T
651
657
  // `finish(reason)` to end the session (e.g. when the answer landed over HTTP).
652
658
  // Resolves 'deadline' | 'ws-unavailable'.
653
659
  async function cableSession({ channel, deadline, onUp, onFrame }) {
654
- let wsFails = 0;
660
+ let wsFails = 0; // consecutive drops SINCE the last healthy connect — the degrade gate
661
+ let wsReconnects = 0; // monotonic total this session — what we DISPLAY (never reset)
655
662
  while (Date.now() < deadline) {
656
663
  const outcome = await new Promise((resolve) => {
657
664
  let sub = null;
@@ -674,12 +681,17 @@ async function cableSession({ channel, deadline, onUp, onFrame }) {
674
681
  if (outcome === 'deadline') return 'deadline';
675
682
  if (!outcome.startsWith('down: ')) return outcome; // caller-driven finish (e.g. 'answered')
676
683
  wsFails++;
684
+ wsReconnects++;
677
685
  const MAX_WS_FAILS = 4; // then fall back to polling for the rest of the session
678
686
  if (wsFails >= MAX_WS_FAILS) return 'ws-unavailable';
679
687
  // env override = a test/ops hook (keeps the forced-1006 degrade test fast)
680
688
  const base = parseInt(process.env.PIDGE_WS_BACKOFF_MS || '2000', 10) || 2000;
681
689
  const backoff = Math.min(base * wsFails, base * 5);
682
- console.error(`pidge: realtime socket ${outcome.replace('down: ', '')} reconnecting in ${Math.round(backoff / 1000)}s (attempt ${wsFails}/${MAX_WS_FAILS})`);
690
+ // #25: show the MONOTONIC reconnect count, not the consecutive-fail counter
691
+ // a connect→drop FLAP resets wsFails (onUp forgives a healthy connect), so the
692
+ // old "attempt 1/4" repeated forever and looked like a stuck loop. The cumulative
693
+ // "#N" visibly advances; the polling fallback is spelled out so the ceiling is clear.
694
+ console.error(`pidge: realtime socket ${outcome.replace('down: ', '')} — reconnecting in ${Math.round(backoff / 1000)}s (reconnect #${wsReconnects}; falls back to polling after ${MAX_WS_FAILS} consecutive failures)`);
683
695
  await sleep(backoff);
684
696
  }
685
697
  return 'deadline';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pidge-cli",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "description": "Send rich, actionable iPhone notifications to a human and block until they answer. Built for AI agents.",
5
5
  "keywords": [
6
6
  "pidge",