pendingyou 0.25.0 → 0.26.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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.26.0 (2026-10-07)
4
+
5
+ - A session that sat idle past its sign-in's 15-minute access token hears its answers again. The next message's
6
+ hand-off started the background refresh, waited 1.2 seconds for it and gave up, often just before it landed, so an
7
+ answered card went unannounced. Now the hand-off and the session start's pickup wait for an expired token until 0.9
8
+ seconds before their 3-second deadline, leaving room to ask for answers; a token with seconds left still waits 1.2.
9
+ - Never silent: when the hand-off or the session start's pickup can't check for answers (Pending You unreachable, a
10
+ server error, or the sign-in still being refreshed), they add “Pending You couldn't check for answers just now: call
11
+ list_pending before you go on.” instead of only the plain reminder.
12
+
3
13
  ## 0.25.0 (2026-10-06)
4
14
 
5
15
  - An answer reaches only the session that asked. The hooks asked Pending You for their folder's answers and open
package/dist/api.js CHANGED
@@ -5,6 +5,8 @@ import { OAuthError, refresh } from "./oauth.js";
5
5
  const EARLY_MS = 60_000;
6
6
  export const SOON_MS = 5 * 60_000;
7
7
  export const REFRESH_WAIT_MS = 1200;
8
+ export const HOOK_DEADLINE_MS = 3000;
9
+ export const ANSWERS_ROOM_MS = 900;
8
10
  const USABLE_MS = 10_000;
9
11
  export class SignInNeeded extends Error {
10
12
  name = 'SignInNeeded';
@@ -72,7 +74,7 @@ export async function refreshInBackground(io, origin, force, app = DEFAULT_APP)
72
74
  await refreshStored(io, origin, stored, { force, earlyMs: SOON_MS }, app);
73
75
  return true;
74
76
  }
75
- async function hookToken(io, origin, force, signal, app) {
77
+ async function hookToken(io, origin, force, signal, app, expiredWaitMs) {
76
78
  const stored = await readCredential(io, origin, app);
77
79
  if (!stored)
78
80
  throw new SignInNeeded(false);
@@ -83,7 +85,8 @@ async function hookToken(io, origin, force, signal, app) {
83
85
  io.background(refreshArgs(origin, app, force));
84
86
  if (!force && left > USABLE_MS)
85
87
  return stored.accessToken;
86
- const until = io.now() + REFRESH_WAIT_MS;
88
+ const wait = !force && left <= 0 && expiredWaitMs !== undefined ? expiredWaitMs : REFRESH_WAIT_MS;
89
+ const until = io.now() + wait;
87
90
  while (io.now() < until && !signal?.aborted) {
88
91
  await io.sleep(50, signal);
89
92
  const current = await readCredential(io, origin, app);
@@ -133,6 +136,7 @@ export function getJson(io, origin, path, timeoutMs, signal, options = {}) {
133
136
  export function sendJson(io, origin, path, body, timeoutMs, options = {}) {
134
137
  return callJson(io, origin, path, { body }, timeoutMs, undefined, options);
135
138
  }
139
+ export const expiredWait = (uptime) => Math.max(0, HOOK_DEADLINE_MS - ANSWERS_ROOM_MS - uptime);
136
140
  async function callJson(io, origin, path, send, timeoutMs, signal, options = {}) {
137
141
  const app = options.app ?? DEFAULT_APP;
138
142
  for (let attempt = 0;; attempt++) {
@@ -140,7 +144,7 @@ async function callJson(io, origin, path, send, timeoutMs, signal, options = {})
140
144
  try {
141
145
  token =
142
146
  options.hook && io.background
143
- ? await hookToken(io, origin, attempt > 0, signal, app)
147
+ ? await hookToken(io, origin, attempt > 0, signal, app, options.patient && io.uptime ? expiredWait(io.uptime()) : undefined)
144
148
  : await freshToken(io, origin, attempt > 0, app);
145
149
  }
146
150
  catch (error) {
package/dist/main.js CHANGED
@@ -1,4 +1,4 @@
1
- import { refreshInBackground, SignInNeeded, Unavailable } from "./api.js";
1
+ import { HOOK_DEADLINE_MS, refreshInBackground, SignInNeeded, Unavailable } from "./api.js";
2
2
  import { listen, listenHanded, posted } from "./apps/codex-wake.js";
3
3
  import { DEFAULT_APP } from "./apps/ids.js";
4
4
  import { appModule } from "./apps/registry.js";
@@ -101,7 +101,7 @@ async function run(io, command, hook = { fallback: '' }) {
101
101
  return (await import("./app-login.js")).appCommand(io, command);
102
102
  }
103
103
  }
104
- export const HOOK_DEADLINE_MS = 3000;
104
+ export { HOOK_DEADLINE_MS };
105
105
  async function runHook(io, command) {
106
106
  const hook = { fallback: '' };
107
107
  const controller = new AbortController();
package/dist/pickup.js CHANGED
@@ -1,4 +1,4 @@
1
- import { getJson, SignInNeeded } from "./api.js";
1
+ import { getJson, SignInNeeded, Unavailable } from "./api.js";
2
2
  import { computerNames, hearsOnly, keepListening, markHandedTurn, sessionFor, threadCards, threadNames, touchThread, } from "./apps/codex-wake.js";
3
3
  import { APP_NAMES, DEFAULT_APP } from "./apps/ids.js";
4
4
  import { connectionMachine, readCredential } from "./credentials.js";
@@ -17,6 +17,7 @@ const TIME_BOX_MS = { pickup: 2500, handoff: 2000 };
17
17
  export const ANSWERS_ASKED = 20;
18
18
  export const ANSWERS_SHOWN = 5;
19
19
  export const REMINDER = 'Pending You: anything you need from your person also goes on a card.';
20
+ export const UNCHECKED = "Pending You couldn't check for answers just now: call list_pending before you go on.";
20
21
  export const OPEN_SHOWN = 3;
21
22
  export const OPEN_TITLE = 50;
22
23
  export const OPEN_NAME = 24;
@@ -200,6 +201,7 @@ export async function pickup(io, options, hook = { fallback: '' }) {
200
201
  ]);
201
202
  const { status, body } = await getJson(io, origin, `/mcp/cli/answers?${query}`, TIME_BOX_MS[mode], io.signal, {
202
203
  hook: true,
204
+ patient: true,
203
205
  app,
204
206
  });
205
207
  if (status !== 200)
@@ -292,6 +294,8 @@ export async function pickup(io, options, hook = { fallback: '' }) {
292
294
  io.out(`Pending You: this computer’s pendingyou sign-in has ended, so answers can’t wake ${APP_NAMES[app]}. Ask your person to run \`npx pendingyou login${app === DEFAULT_APP ? '' : ` --app ${app}`}\`.\n`);
293
295
  if (error instanceof SignInNeeded)
294
296
  line = null;
297
+ if (error instanceof Unavailable)
298
+ line = [line, UNCHECKED].filter(Boolean).join('\n');
295
299
  return 0;
296
300
  }
297
301
  finally {
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = '0.25.0';
1
+ export const VERSION = '0.26.0';
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pendingyou-wake",
3
3
  "displayName": "Pending You",
4
- "version": "2.37.0",
4
+ "version": "2.38.0",
5
5
  "description": "Wakes Claude Code when your person answers a Pending You card it posted, even while it sits idle. Installed by `npx pendingyou init`.",
6
6
  "author": {
7
7
  "name": "RecordPlane",
package/mod/README.md CHANGED
@@ -4,4 +4,4 @@ The pendingyou command line’s copy of the Pending You plugin’s wake mod, for
4
4
 
5
5
  In each session it learns the cards the session posts to Pending You, checks them through the session’s own Pending You connection, and starts a turn when your person answers, writes back or a fallback comes due, or hands the session a question from another of their assistants (CLI 0.14.0), even while it sits idle. It answers `npx pendingyou hold` itself, so nothing waits in the background, and shows “2 waiting on you” under the prompt, after the plugin’s name. With the Pending You plugin installed too, only one copy acts.
6
6
 
7
- Generated from recordplane/pendingyou (packages/claude-plugin/src/wake) with Pending You’s guide 2.37.0; send changes there.
7
+ Generated from recordplane/pendingyou (packages/claude-plugin/src/wake) with Pending You’s guide 2.38.0; send changes there.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pendingyou",
3
- "version": "0.25.0",
3
+ "version": "0.26.0",
4
4
  "description": "Pending You for your coding agents: one command sets up Claude Code, Codex, OpenCode and Pi to ask you through Pending You and hear your answers, even while they sit idle.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://www.pendingyou.com",