pendingyou 0.18.0 → 0.20.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 +39 -0
- package/README.md +12 -0
- package/dist/apps/codex-wake.js +12 -2
- package/dist/format.js +23 -0
- package/dist/stopcheck.js +71 -7
- package/dist/version.js +1 -1
- package/mod/.claude-plugin/plugin.json +1 -1
- package/mod/README.md +1 -1
- package/mod/hooks/wake.js +21 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.20.0 (2026-10-06)
|
|
4
|
+
|
|
5
|
+
- “I’ll handle it”: a card you ended yourself in Pending You says so, and tells the agent to stand down. An answer can
|
|
6
|
+
now carry `handled`: `self` (you'll do it yourself) or `leave` (nobody does it), with or without your note, and its
|
|
7
|
+
words in `said` (“I’ll do it myself”, “Leave it”, then the note). Wherever the command line hands an answer over
|
|
8
|
+
(`hold`, the session-start and next-message hooks, the wake mod in Claude Code, and the listeners that wake Codex,
|
|
9
|
+
OpenCode and Pi), it says which instead of “Act on it”:
|
|
10
|
+
- `self`: don't act on it, don't draft or send anything for it, and don't follow up.
|
|
11
|
+
- `leave`: nobody does it, so an email or a task gets no reply and no follow-up, and nothing is archived or deleted
|
|
12
|
+
unless the person's rules say so.
|
|
13
|
+
- Either way: if the note asks for one thing, do just that; then `ack_answer` with an outcome like “Left to you”, and
|
|
14
|
+
never post it again. No “reply_in_thread with reopen” hint for these.
|
|
15
|
+
`watch` passes `handled` on with the rest of the request. An answer without it, from an older Pending You, reads as
|
|
16
|
+
before.
|
|
17
|
+
- Hooks run the copy `init` installed: run `npx pendingyou@latest init` once to switch.
|
|
18
|
+
|
|
19
|
+
## 0.19.0 (2026-10-06)
|
|
20
|
+
|
|
21
|
+
- The Stop check lets a turn end on a recap of cards already waiting on you. It asked the agent to go on whenever its
|
|
22
|
+
last message had something for you and the turn posted no card, so a closing line like “Two cards are waiting on
|
|
23
|
+
you: CLI 0.18.0 (publish it) and the Herdr check (does the amber title show in the sidebar?).” was asked to go on,
|
|
24
|
+
and Claude Code showed each of those as a “Stop hook error”. Now:
|
|
25
|
+
- A recap counts as posted, for what it says: a sentence that says its cards wait on you (“Two cards are waiting on
|
|
26
|
+
you: …”, “the card is still open for your answer”, “both cards are in your queue”, “… (both cards).”), or a heading
|
|
27
|
+
that does, or names your cards (“**Cards waiting for you:**”, “Your open cards:”), with the list under it.
|
|
28
|
+
Anything else in the message for you is checked as before, so a new ask beside a recap still goes on a card. Cards
|
|
29
|
+
that aren't said to wait on you (“the two cards line up”, “add a credit card”) are no recap.
|
|
30
|
+
- So does a card said to be coming, or one an item already is: “a card is coming”, “there'll be a card”, “I'll
|
|
31
|
+
create a card”, “that one is already a card”, as “I'll send you a card” and “it's on a card” already did.
|
|
32
|
+
- Anything else for you, in a message that talks about cards (not a credit card, a SIM card or a card number), is
|
|
33
|
+
taken as a recap while this folder has a card waiting on you: one request (this folder's open cards, the one the
|
|
34
|
+
next-message hook makes), made only for such a message and given up after 1.5 seconds. None open: the agent is
|
|
35
|
+
asked to go on, as before. A permission prompt's card doesn't count. When Pending You can't say (offline, slow, an
|
|
36
|
+
older server), the turn ends.
|
|
37
|
+
- Everything else is as before: an ask to type something here, a question handed to the agent, once a turn at most,
|
|
38
|
+
quiet when not signed in, silent on any error, the 3-second deadline. Codex's, OpenCode's and Pi's Stop checks do
|
|
39
|
+
the same, each asking for its own app's cards.
|
|
40
|
+
- Hooks run the copy `init` installed: run `npx pendingyou@latest init` once to switch.
|
|
41
|
+
|
|
3
42
|
## 0.18.0 (2026-10-05)
|
|
4
43
|
|
|
5
44
|
- Presence says which terminal: in a Herdr pane (`HERDR_ENV=1` with `HERDR_BIN_PATH` and `HERDR_PANE_ID`), every
|
package/README.md
CHANGED
|
@@ -205,6 +205,13 @@ can", "waiting on you" and the like; or a list under a heading like "Your part",
|
|
|
205
205
|
you" or "Left for you". It lets the turn end when the message says nothing needs a card ("No card needed.", "Nothing
|
|
206
206
|
needs your attention.", "There's nothing waiting on you.").
|
|
207
207
|
|
|
208
|
+
Since 0.19.0 it also lets the turn end on a recap of cards already waiting on you. A sentence that says its cards wait
|
|
209
|
+
on you ("Two cards are waiting on you: …", "… (both cards).") covers what it asks, and so does a heading that does
|
|
210
|
+
("Cards waiting for you:") over its list; anything else for you in the message is checked as before, so a new ask
|
|
211
|
+
beside a recap still goes on a card. And anything else for you, in a message that talks about cards, is taken as a
|
|
212
|
+
recap while this folder has a card waiting on you: only such a message costs a request (this folder's open cards,
|
|
213
|
+
given up after 1.5 seconds), and when Pending You can't say, the turn ends.
|
|
214
|
+
|
|
208
215
|
Since 0.9.0 it also catches a message asking you to type or reply something in Claude Code's own chat ("Reply “yes,
|
|
209
216
|
erase disk12” here", "To confirm, type `yes`", "Confirm here"). Some steps an agent takes only on your own words in
|
|
210
217
|
its conversation, never on a card answer; that's fine, but then a card has to send you there. Unless a card posted in
|
|
@@ -342,6 +349,11 @@ next message brings any answer with it too.
|
|
|
342
349
|
When you're at the terminal, Claude Code asks you there and puts the same question in Pending You at once; the
|
|
343
350
|
first answer wins. If you answer in the terminal, it withdraws the card and the hold ends by itself.
|
|
344
351
|
|
|
352
|
+
**When you'll handle it yourself (0.20.0).** A card you end with “I’ll handle it” in Pending You (“I’ll do it myself”,
|
|
353
|
+
or “Leave it”) reaches the agent the same ways, saying which: instead of acting on it, it's told to stand down (nothing
|
|
354
|
+
done, drafted, sent or followed up for it; with “Leave it”, an email or a task gets no reply), to pick it up with
|
|
355
|
+
`ack_answer` and an outcome like “Left to you”, and never to post it again.
|
|
356
|
+
|
|
345
357
|
**Finishing setup by itself (0.11.0).** In `init`'s copy of the mod, a few seconds after a session you're at opens
|
|
346
358
|
(never `claude -p`), it asks Pending You whether Claude Code is set up here (`whoami`, once Pending You's tools are
|
|
347
359
|
allowed and the server has connected). When it isn't, it starts one turn once the session is idle: “Finish setting up
|
package/dist/apps/codex-wake.js
CHANGED
|
@@ -5,7 +5,7 @@ import { getJson, SignInNeeded, Unavailable } from "../api.js";
|
|
|
5
5
|
import { DEFAULT_ORIGIN } from "../args.js";
|
|
6
6
|
import { connectionMachine, readCredential } from "../credentials.js";
|
|
7
7
|
import { configDir, readJson, withLock, writeWhole } from "../files.js";
|
|
8
|
-
import { clip, delegatedOf, isClosed, noticeOf } from "../format.js";
|
|
8
|
+
import { clip, delegatedOf, handledOf, isClosed, noticeOf } from "../format.js";
|
|
9
9
|
import { chooseThread, goesBy, HANDED_FOR_MS, handedCard, handedMessage, namesAnotherComputer, } from "../handed.js";
|
|
10
10
|
import { clearHerdr, herdrTarget, isUrgency, PANE_ID, reportCommand, writeHerdr, } from "../herdr.js";
|
|
11
11
|
import { macName, tailscaleName } from "../remote.js";
|
|
@@ -399,6 +399,16 @@ function line(heard, card) {
|
|
|
399
399
|
case 'resolved':
|
|
400
400
|
return null;
|
|
401
401
|
case 'answered':
|
|
402
|
+
if (handledOf(heard) === 'self')
|
|
403
|
+
return [
|
|
404
|
+
`your person will handle ${titled} themselves`,
|
|
405
|
+
`call ${get} to read it, don’t act on it, then ack_answer with its version and an outcome like “Left to you”`,
|
|
406
|
+
];
|
|
407
|
+
if (handledOf(heard) === 'leave')
|
|
408
|
+
return [
|
|
409
|
+
`your person said to leave ${titled}`,
|
|
410
|
+
`call ${get} to read it, do nothing for it (no reply, no follow-up), then ack_answer with its version and an outcome like “Left it”`,
|
|
411
|
+
];
|
|
402
412
|
return [
|
|
403
413
|
`your person answered ${titled}`,
|
|
404
414
|
`call ${get}, act on their words, then ack_answer with its version and a one-line outcome`,
|
|
@@ -418,7 +428,7 @@ export function wakeMessage(ready) {
|
|
|
418
428
|
});
|
|
419
429
|
if (lines.length === 0)
|
|
420
430
|
return null;
|
|
421
|
-
const asked = lines.some(({ heard }) => heard.turn === 'agent' && heard.status !== 'expired' && !noticeOf(heard));
|
|
431
|
+
const asked = lines.some(({ heard }) => heard.turn === 'agent' && heard.status !== 'expired' && !noticeOf(heard) && !handledOf(heard));
|
|
422
432
|
const reopen = asked
|
|
423
433
|
? ' If they asked you something or you need more from them, reply_in_thread with reopen instead.'
|
|
424
434
|
: '';
|
package/dist/format.js
CHANGED
|
@@ -7,6 +7,11 @@ export function noticeOf(heard) {
|
|
|
7
7
|
return null;
|
|
8
8
|
return { kind, from };
|
|
9
9
|
}
|
|
10
|
+
export function handledOf(heard) {
|
|
11
|
+
const given = heard.handled;
|
|
12
|
+
return given === 'self' || given === 'leave' ? given : null;
|
|
13
|
+
}
|
|
14
|
+
const HANDLED_SAID = { self: 'I’ll do it myself', leave: 'Leave it' };
|
|
10
15
|
export const HANDED_PREFIX = 'Pending You: your person handed you';
|
|
11
16
|
export const HANDED_REPLY = 'on the question handed to you';
|
|
12
17
|
export const HANDED_TALK_TODO = 'If you know now, answer_delegated with your answer and how you know; if you need more, reply_in_thread to “asker”; if it’s your person’s to decide, reply_in_thread with escalate true; if not, hand_back with what you checked.';
|
|
@@ -113,6 +118,14 @@ function describeNotice(heard, notice) {
|
|
|
113
118
|
...(cut ? [`(Cut short: get_request ${id} has all of it.)`] : []),
|
|
114
119
|
];
|
|
115
120
|
}
|
|
121
|
+
function standDown(heard, handled) {
|
|
122
|
+
const ack = `ack_answer with requestId ${heard.requestId}, name ${named(heard)}, expectedVersion ${heard.version}`;
|
|
123
|
+
const noted = Boolean(heard.said?.trim() && heard.said.trim() !== HANDLED_SAID[handled]);
|
|
124
|
+
const note = noted ? '; if their note asks you for one thing, do just that' : '';
|
|
125
|
+
return handled === 'self'
|
|
126
|
+
? `Stand down: don’t act on it, don’t draft or send anything for it, and don’t follow up${note}. Then call ${ack} and an outcome like “Left to you”. Never post it again.`
|
|
127
|
+
: `Stand down: nobody does it, so an email or a task gets no reply and no follow-up, and nothing is archived or deleted unless their rules say so${note}. Then call ${ack} and an outcome like “Left it”. Never post it again.`;
|
|
128
|
+
}
|
|
116
129
|
export function describe(heard, again) {
|
|
117
130
|
const id = heard.requestId;
|
|
118
131
|
const delegated = delegatedOf(heard);
|
|
@@ -131,6 +144,16 @@ export function describe(heard, again) {
|
|
|
131
144
|
const lines = [];
|
|
132
145
|
switch (heard.status) {
|
|
133
146
|
case 'answered': {
|
|
147
|
+
const handled = handledOf(heard);
|
|
148
|
+
if (handled) {
|
|
149
|
+
const answer = clip(heard.said ?? HANDLED_SAID[handled], MAX_ANSWER);
|
|
150
|
+
cut ||= answer.cut;
|
|
151
|
+
lines.push(`Pending You: ${id} is answered: ${handled === 'self' ? 'your person will do it themselves' : 'your person said to leave it'}.`, question, `Answer: ${answer.text}`);
|
|
152
|
+
if (wrote.length)
|
|
153
|
+
lines.push(`They also wrote: ${wrote.join(' ')}`);
|
|
154
|
+
lines.push(standDown(heard, handled));
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
134
157
|
if (heard.answers?.length) {
|
|
135
158
|
lines.push(`Pending You: ${id} is answered, all ${heard.answers.length} questions.`, question);
|
|
136
159
|
for (const [index, each] of heard.answers.entries()) {
|
package/dist/stopcheck.js
CHANGED
|
@@ -5,17 +5,35 @@ import { APP_NAMES, DEFAULT_APP } from "./apps/ids.js";
|
|
|
5
5
|
import { asksToTypeHere, cardFits, confirmReason, sessionLink } from "./confirm.js";
|
|
6
6
|
import { readCredential } from "./credentials.js";
|
|
7
7
|
import { isHandedWake } from "./format.js";
|
|
8
|
-
import { isPromptApp, settlePrompts, subagentsRunning } from "./permission.js";
|
|
8
|
+
import { isPermissionCard, isPromptApp, settlePrompts, subagentsRunning } from "./permission.js";
|
|
9
9
|
import { folderForms } from "./pickup.js";
|
|
10
10
|
export const READ_CAP = 4 * 1024 * 1024;
|
|
11
11
|
const CHUNK = 64 * 1024;
|
|
12
12
|
export const STOP_REASON = 'Items for your person are in chat but not in Pending You: post them as cards (ask in both places), or say they don’t need one.';
|
|
13
13
|
export const DELEGATED_REASON = 'Your person handed you that question to answer, not to ask them back: answer_delegated if you know, or hand_back with what you checked, unless you already did. Never post it as a card of your own.';
|
|
14
14
|
const POSTING_TOOL = /^mcp__.+__(post_request|update_request|reply_in_thread|answer_delegated|hand_back)$/;
|
|
15
|
-
const OPEN_TIME_BOX_MS = 1500;
|
|
15
|
+
export const OPEN_TIME_BOX_MS = 1500;
|
|
16
16
|
const OPEN_CARDS = 5;
|
|
17
17
|
const CARD_TEXT = 20_000;
|
|
18
|
-
const SAYS_POSTED =
|
|
18
|
+
const SAYS_POSTED = new RegExp([
|
|
19
|
+
String.raw `\b(posted|put|added|raised|filed)\b[^.\n]{0,60}\b(cards?|pending ?you)\b`,
|
|
20
|
+
String.raw `\bon (a|the|its|their|your|that|this) cards?\b`,
|
|
21
|
+
String.raw `\b(in|to|through|via|on) pending ?you\b`,
|
|
22
|
+
String.raw `\bpending ?you cards?\b`,
|
|
23
|
+
String.raw `\b(i|we|you)(?:(?:'|’)ll| will)\s+(?:\w+\s+)?(post|send|put|add|raise|file|get|see|find|make|create|open)\b[^.\n]{0,40}\bcards?\b`,
|
|
24
|
+
String.raw `\balready (?:a |on (?:a )?)?cards?\b`,
|
|
25
|
+
String.raw `\bcards? (?:is|are|will be) (?:coming|on (?:its|their|the) way)\b(?! (?:together|along))`,
|
|
26
|
+
String.raw `\bcards? (?:will|to) follow\b`,
|
|
27
|
+
String.raw `\bthere(?:(?:'|’)ll| will) be (?:a |another |one )?cards?\b`,
|
|
28
|
+
].join('|'), 'i');
|
|
29
|
+
const RECAP = new RegExp([
|
|
30
|
+
String.raw `\bcards?\b[^.!?\n]{0,40}?\b(?:(?:waiting|pending|open|parked|queued|left)\b[^.!?\n]{0,20}?\b(?:on|for)\s+your?|in\s+your\s+queue)\b`,
|
|
31
|
+
String.raw `\b(?:waiting|pending|parked)\s+(?:on|for)\s+you\b[^.!?\n]{0,30}?\b(?:as|in)\s+(?:(?:a|two|both|three|its|their|the|separate)\s+)?cards?\b`,
|
|
32
|
+
String.raw `\((?:(?:both|all|two|three|each)\s+)?(?:(?:are|is|on|as)\s+)?(?:a\s+|(?:its|their)\s+own\s+)?cards?(?:\s+(?:already|too))?\)`,
|
|
33
|
+
].join('|'), 'i');
|
|
34
|
+
const CARDS_HEADING = /\b(?:your|open|pending|waiting)\s+(?:(?:open|pending|waiting)\s+)?cards\b/i;
|
|
35
|
+
const SENTENCE_END = /(?<=[.!?])\s+/;
|
|
36
|
+
const OTHER_CARDS = /\b(?:credit|debit|payment|gift|sim|sd|business|graphics|video|sound|network|memory|smart)\s+cards?\b|\bcards?\s+(?:numbers?|readers?|details|holders?)\b/gi;
|
|
19
37
|
const STEPS_FOR_THEM = /\b(you(?:'|’)ll need to|you will need to|you(?:'|’)ll have to|you will have to|your (?:next )?steps?\b|can you|could you|would you mind|please (?:run|confirm|approve|check|add|set|sign|create|open|paste|reply|send|choose|pick|decide|let me know)|in your terminal|only you can|(?<!\b(?:no|nothing|none|not)\b[^.,;:!?\n]{0,40})waiting (?:on|for) you|(?<!\bif (?:it|he|she|they|that|this|anything|something|someone|anyone|one) )needs? you to|over to you|parked for you|when you(?:'|’)re ready|up to you|your call\b|is yours\b|say the word|let me know (?:which|whether)|tell me (?:which|whether)|needs? your (?:ok|okay|approval|decision|sign-?off|go-ahead))/i;
|
|
20
38
|
const SAYS_NO_CARD = /\bno (?:new |more |further )?cards? (?:is |are )?(?:needed|necessary|required)\b|\b(?:doesn(?:'|’)t|don(?:'|’)t|does not|do not|won(?:'|’)t|will not) need (?:a |any )?(?:new )?cards?\b|\bnothing (?:here |else |more |now )?(?:needs|requires) your (?:attention|input|action|answer)\b|\b(?:nothing|no cards?)\b[^.,;:!?\n]{0,40}\b(?:waiting|pending) (?:on|for) you\b/i;
|
|
21
39
|
const FOR_THEM_HEADING = /\b(your part|your steps?|your to-?dos?|your turn|your call|for you|waiting on you|left for you|parked for you|needs you|over to you|what you need to do|you(?:'|’)ll need)\b/i;
|
|
@@ -47,8 +65,7 @@ function headingOf(line) {
|
|
|
47
65
|
return null;
|
|
48
66
|
return /^\s*#/.test(line) || bare.endsWith(':') || /^\s*\*\*.+\*\*\s*$/.test(line) ? bare : null;
|
|
49
67
|
}
|
|
50
|
-
|
|
51
|
-
const plain = plainText(text);
|
|
68
|
+
function itemsIn(plain) {
|
|
52
69
|
const lines = plain.split('\n');
|
|
53
70
|
for (let index = 0; index < lines.length; index++) {
|
|
54
71
|
const heading = headingOf(lines[index]);
|
|
@@ -65,8 +82,50 @@ export function itemsForPerson(text) {
|
|
|
65
82
|
return 'question';
|
|
66
83
|
return null;
|
|
67
84
|
}
|
|
85
|
+
export function itemsForPerson(text) {
|
|
86
|
+
return itemsIn(plainText(text));
|
|
87
|
+
}
|
|
88
|
+
function listEnd(lines, index) {
|
|
89
|
+
let end = index;
|
|
90
|
+
for (let next = index + 1; next < lines.length; next++) {
|
|
91
|
+
const line = lines[next];
|
|
92
|
+
if (!line.trim()) {
|
|
93
|
+
if (end === index && next - index >= 3)
|
|
94
|
+
return index;
|
|
95
|
+
}
|
|
96
|
+
else if (LIST_ITEM.test(line) || (end > index && /^\s/.test(line)))
|
|
97
|
+
end = next;
|
|
98
|
+
else
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
return end;
|
|
102
|
+
}
|
|
103
|
+
function withoutRecaps(plain) {
|
|
104
|
+
const lines = plain.split('\n');
|
|
105
|
+
const kept = [];
|
|
106
|
+
for (let index = 0; index < lines.length; index++) {
|
|
107
|
+
const line = lines[index];
|
|
108
|
+
const heading = headingOf(line);
|
|
109
|
+
if (heading && (RECAP.test(heading) || CARDS_HEADING.test(heading))) {
|
|
110
|
+
const end = listEnd(lines, index);
|
|
111
|
+
if (end > index) {
|
|
112
|
+
index = end;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
kept.push(line
|
|
117
|
+
.split(SENTENCE_END)
|
|
118
|
+
.filter((sentence) => !RECAP.test(sentence))
|
|
119
|
+
.join(' '));
|
|
120
|
+
}
|
|
121
|
+
return kept.join('\n');
|
|
122
|
+
}
|
|
123
|
+
export function itemsOutsideRecaps(text) {
|
|
124
|
+
return itemsIn(withoutRecaps(plainText(text)));
|
|
125
|
+
}
|
|
68
126
|
export const saysPosted = (text) => SAYS_POSTED.test(plainText(text));
|
|
69
127
|
export const saysNoCard = (text) => SAYS_NO_CARD.test(plainText(text));
|
|
128
|
+
export const mentionsCards = (text) => /\bcards?\b/i.test(plainText(text).replace(OTHER_CARDS, ''));
|
|
70
129
|
function wordsIn(value, max = CARD_TEXT) {
|
|
71
130
|
const found = [];
|
|
72
131
|
let left = max;
|
|
@@ -306,18 +365,23 @@ export async function stopcheck(io, options) {
|
|
|
306
365
|
return 0;
|
|
307
366
|
return asksToTypeHere(text) || itemsForPerson(text) ? block(DELEGATED_REASON) : 0;
|
|
308
367
|
}
|
|
368
|
+
const cwd = typeof input.cwd === 'string' && input.cwd ? input.cwd : io.cwd;
|
|
309
369
|
const ask = asksToTypeHere(text);
|
|
310
370
|
if (ask) {
|
|
311
371
|
if (saysNoCard(text) || turn.cards.some((card) => cardFits(card, ask.words, 'posted')))
|
|
312
372
|
return 0;
|
|
313
|
-
const cwd = typeof input.cwd === 'string' && input.cwd ? input.cwd : io.cwd;
|
|
314
373
|
const open = await openTitles(io, options.origin, cwd, app);
|
|
315
374
|
if (open ? open.some((title) => cardFits(title, ask.words, 'open')) : saysPosted(text))
|
|
316
375
|
return 0;
|
|
317
376
|
return block(confirmReason(ask.words, sessionLink(io.env), APP_NAMES[app]));
|
|
318
377
|
}
|
|
319
|
-
if (turn.posted || saysPosted(text) || saysNoCard(text) || !
|
|
378
|
+
if (turn.posted || saysPosted(text) || saysNoCard(text) || !itemsOutsideRecaps(text))
|
|
320
379
|
return 0;
|
|
380
|
+
if (mentionsCards(text)) {
|
|
381
|
+
const open = await openTitles(io, options.origin, cwd, app);
|
|
382
|
+
if (open === null || open.some((title) => !isPermissionCard(title)))
|
|
383
|
+
return 0;
|
|
384
|
+
}
|
|
321
385
|
return block(STOP_REASON);
|
|
322
386
|
}
|
|
323
387
|
catch {
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.
|
|
1
|
+
export const VERSION = '0.20.0';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pendingyou-wake",
|
|
3
3
|
"displayName": "Pending You",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.33.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.
|
|
7
|
+
Generated from recordplane/pendingyou (packages/claude-plugin/src/wake) with Pending You’s guide 2.33.0; send changes there.
|
package/mod/hooks/wake.js
CHANGED
|
@@ -116,7 +116,15 @@ export function stateOf(output) {
|
|
|
116
116
|
const version = count(output.version);
|
|
117
117
|
if (!status || !turn || version === undefined)
|
|
118
118
|
return null;
|
|
119
|
-
|
|
119
|
+
const given = isObject(output.answer) ? output.answer.handled : output.handled;
|
|
120
|
+
const handled = given === 'self' || given === 'leave' ? given : undefined;
|
|
121
|
+
return {
|
|
122
|
+
status,
|
|
123
|
+
turn,
|
|
124
|
+
version,
|
|
125
|
+
cursor: typeof output.cursor === 'string' ? output.cursor : '',
|
|
126
|
+
...(handled ? { handled } : {}),
|
|
127
|
+
};
|
|
120
128
|
}
|
|
121
129
|
export const emptyBook = (now = 0) => ({ v: 1, updatedAt: now, cards: {} });
|
|
122
130
|
export function readBook(value) {
|
|
@@ -368,6 +376,16 @@ function line(card) {
|
|
|
368
376
|
case 'resolved':
|
|
369
377
|
return [`${titled(card)} is already handled`, 'nothing to do'];
|
|
370
378
|
case 'answered':
|
|
379
|
+
if (state.handled === 'self')
|
|
380
|
+
return [
|
|
381
|
+
`your person will handle ${titled(card)} themselves`,
|
|
382
|
+
`call ${get} to read it, don’t act on it, then ack_answer with its version and an outcome like “Left to you”`,
|
|
383
|
+
];
|
|
384
|
+
if (state.handled === 'leave')
|
|
385
|
+
return [
|
|
386
|
+
`your person said to leave ${titled(card)}`,
|
|
387
|
+
`call ${get} to read it, do nothing for it (no reply, no follow-up), then ack_answer with its version and an outcome like “Left it”`,
|
|
388
|
+
];
|
|
371
389
|
return [
|
|
372
390
|
`your person answered ${titled(card)}`,
|
|
373
391
|
`call ${get}, act on their words, then ack_answer with its version and a one-line outcome`,
|
|
@@ -388,7 +406,8 @@ const capital = (sentence) => sentence.charAt(0).toUpperCase() + sentence.slice(
|
|
|
388
406
|
export function wakeText(cards) {
|
|
389
407
|
const asked = cards.some((card) => card.state?.turn === 'agent' &&
|
|
390
408
|
!isClosed(card.state.status) &&
|
|
391
|
-
card.state.status !== 'delegated'
|
|
409
|
+
card.state.status !== 'delegated' &&
|
|
410
|
+
!card.state.handled);
|
|
392
411
|
const reopen = asked
|
|
393
412
|
? ' If they asked you something or you need more from them, reply_in_thread with reopen instead.'
|
|
394
413
|
: '';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pendingyou",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.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",
|