@paigy/mcp 0.40.40 → 0.40.41

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 CHANGED
@@ -109,19 +109,20 @@ Or add the entry to `~/.gemini/settings.json`:
109
109
 
110
110
  Then pair: `PAIGY_AGENT=gemini npx -p @paigy/mcp@latest paigy-mcp-onboard`.
111
111
 
112
- > `PAIGY_AGENT` names the agent AND keys its token slot (defaults to
113
- > `mcp-agent`). Each client reads only its own slot, so pair with the same
114
- > `PAIGY_AGENT` the client's config uses — and set it per client so you can
115
- > tell your connected agents apart.
112
+ > `PAIGY_AGENT` names the agent AND keys its token slot. Without it, each session gets a private slot
113
+ > (`session:<id>`); the shared `mcp-agent` default went on 2026-08-07. Each client reads only its own slot, so pair with the same
114
+ > `PAIGY_AGENT` the client's config uses. A fixed `PAIGY_AGENT` makes every session of that client one agent: two running at once
115
+ > collide, and the copy set aside is refused `holder_conflict` when it acts (#2933). `paigy-harness setup` wires clients without it,
116
+ > so each session hatches its own identity.
116
117
 
117
118
  ## Tools
118
119
 
119
120
  One catalog, on every transport (2026-09-11): the agent tools are `AGENT_TOOLS` in
120
- `packages/schema/src/tools.ts` — contact, manage_goals, get_goals, search, check_activity,
121
- send_feedback — and both this server and the hosted MCP
121
+ `packages/schema/src/tools.ts` (configure, contact, manage_goals, get_delivery, get_goals, search, check_activity,
122
+ send_feedback), and both this server and the hosted MCP
122
123
  (`apps/api/src/mcp`) publish that list and dispatch it through the SDK's one `runTool`.
123
- This server adds only `configure`, the one identity tool, which pairs, reports who you are,
124
- renames and logs this agent out (`logOut: true`) over the token file this machine holds, and listen.
124
+ This server extends `configure`, the one identity tool, which on the hosted MCP only reports who you are: here it also pairs,
125
+ renames and logs this agent out (`logOut: true`) over the token file this machine holds. It adds `listen`.
125
126
  `onboard` is now `configure`; `pair` and `unpair` are folded into it (2026-10-07). See the [SDK contract](../../packages/sdk/README.md) for the
126
127
  contact shape. Sending returns immediately unless it asks to `wait`: `wait: true` holds one
127
128
  cancellable ~45-second window here for a response to what was sent (the hosted transport
@@ -145,9 +146,8 @@ time. Bookkeeping (`operationId`, the manage request id, the revision an edit wa
145
146
  minted here, never asked of the model. Retired
146
147
  reply-lease/ACK/work/callback tools and hidden notification aliases are rejected.
147
148
 
148
- The standalone listener below is still a **legacy host and target-release blocker**.
149
- Its old reply intake must migrate before enabling it against the target runtime; it is
150
- not a compatibility fallback for target MCP tools.
149
+ Until 2026-09-13 the standalone listener below was a legacy host with its own reply intake. Since #1957 it reads
150
+ the same `receive` as `contact({})`, as the next section says.
151
151
 
152
152
  ## Configuration
153
153
 
@@ -305,12 +305,12 @@ machine is paired and this session's identity is minted by its first tool call;
305
305
 
306
306
  ## Publishing (maintainers)
307
307
 
308
- Tool input schemas are generated from zod in `src/schema.ts` as draft-2020-12 JSON
308
+ Tool input schemas are generated from zod by `mcpInputSchema` (`packages/schema/src/mcp-schema.ts`) as draft-2020-12 JSON
309
309
  Schema, and `src/schema.test.ts` guards that every tool stays valid (strict clients
310
310
  like the Anthropic API reject anything else). **A schema fix only reaches agents once
311
311
  a new version is published to npm** — 0.8.0 once shipped *without* a committed fix and
312
- 400'd strict clients for weeks. So after any change under `src/schema*` or the tool
313
- definitions: **bump the version and `pnpm publish`** (don't rely on the commit alone).
312
+ 400'd strict clients for weeks. So after any change to the tool schemas (`packages/schema`) or the tool
313
+ definitions: **bump the version in `apps/mcp/package.json`**; publishing is `pnpm release` from the repo root, which the owner runs (`docs/infra/releasing.md`). Don't rely on the commit alone.
314
314
  Install recipes pin `@paigy/mcp@latest` so a fresh `npx` picks up the new version; if a
315
315
  stale one sticks, `rm -rf ~/.npm/_npx` and restart the client.
316
316
 
@@ -7,7 +7,7 @@ import {
7
7
  saveToken,
8
8
  setIdentity,
9
9
  sleep
10
- } from "./chunk-V4OVLFMP.js";
10
+ } from "./chunk-CPDYOHSY.js";
11
11
 
12
12
  // src/identity.ts
13
13
  var CLIENT_LABELS = {
@@ -1517,16 +1517,16 @@ function parseWhen(said2, tz, nowMs, read22 = "earliest") {
1517
1517
  let hour = null;
1518
1518
  let minute = 0;
1519
1519
  const spoken = new RegExp(`\\bat\\s+(${Object.keys(SPOKEN_HOUR).join("|")})\\b`, "i").exec(text);
1520
- const clock2 = CLOCK.exec(text);
1520
+ const clock22 = CLOCK.exec(text);
1521
1521
  if (spoken) {
1522
1522
  hour = SPOKEN_HOUR[spoken[1].toLowerCase()];
1523
- } else if (clock2 && (clock2[3] || /\bat\s/i.test(clock2[0]))) {
1524
- hour = Number(clock2[1]);
1525
- minute = clock2[2] ? Number(clock2[2]) : 0;
1523
+ } else if (clock22 && (clock22[3] || /\bat\s/i.test(clock22[0]))) {
1524
+ hour = Number(clock22[1]);
1525
+ minute = clock22[2] ? Number(clock22[2]) : 0;
1526
1526
  if (hour > 23 || minute > 59) return null;
1527
1527
  }
1528
1528
  if (hour !== null) {
1529
- const mer = clock2?.[3]?.toLowerCase().replace(/\./g, "") ?? "";
1529
+ const mer = clock22?.[3]?.toLowerCase().replace(/\./g, "") ?? "";
1530
1530
  const pmWord = /\b(p\.?m\.?|afternoon|evening|tonight|at night)\b/i.test(text);
1531
1531
  const amWord = /\b(a\.?m\.?|morning)\b/i.test(text);
1532
1532
  if (mer.startsWith("p") || pmWord && !amWord) {
@@ -1787,7 +1787,7 @@ var sendFields = {
1787
1787
  "COMPLETIONS close and report in one operation, the same contract as manage_goals kind:complete: closure and the report commit together or neither does. Required children and dependencies must already be finished. options suggest next steps: a tap acknowledges the report and requests that step, and never reopens the Goal (follow-up work needs a new one). No reviewer rejudges it: say only what your evidence supports. Ordinary updates never close a Goal."
1788
1788
  ),
1789
1789
  updates: z4.array(UpdateInputSchema).min(1).max(20).optional().describe(
1790
- "News: progress, findings, a result. An update asks nothing. It reaches the person only when they asked for it (userExplicitlyRequested), when it answers something they said, or once its Goal is done; otherwise it is recorded as the Goal's progress and nobody is notified."
1790
+ "News: progress, findings, a result. An update asks nothing. It reaches the person only when they asked for it (userExplicitlyRequested), when it answers something they said, or once its Goal is done; otherwise it is recorded as the Goal's progress, which the person is not told. Every update reaches the other agents that wrote on its Goal in the last hour: to tell another agent something, write it as an update on that agent's Goal."
1791
1791
  ),
1792
1792
  answers: z4.array(AnswerInputSchema).min(1).max(20).optional().describe("Answers to Questions addressed to you."),
1793
1793
  withdrawQuestionIds: z4.array(questionHandle).min(1).max(10).optional().describe(
@@ -1922,9 +1922,12 @@ var GetGoalsSchema = z5.object({
1922
1922
  history: z5.boolean().optional()
1923
1923
  }).strict();
1924
1924
  var GetDeliverySchema = z5.object({
1925
- deliveryId: z5.string().uuid().describe("The Delivery id returned by contact or receive.")
1925
+ deliveryId: z5.string().uuid().describe("The Delivery id returned by contact or receive."),
1926
+ // WHAT WAS SAID ON A CALL (owner, 2026-10-26, Goal c743f4a4: "A flag on get_delivery", "Any of my agents").
1927
+ transcript: z5.boolean().optional().describe("For a Call: also return what was said on it, one page of spoken lines."),
1928
+ after: z5.string().max(40).optional().describe("With transcript: the next value the previous page returned, to read the next page.")
1926
1929
  }).strict();
1927
- var GET_DELIVERY_DESCRIPTION = "Read a Delivery in full: its whole ask, units, options and answers, plus current callState and callOutcome for a Call. Any agent of the same account may read it; another account is not disclosed. Reading never acknowledges or resends anything. Use this after a call or when receive names a Call you are waiting on.";
1930
+ var GET_DELIVERY_DESCRIPTION = "Read a Delivery in full: its whole ask, units, options and answers, plus current callState and callOutcome for a Call. For a Call, transcript: true adds what was said: each spoken line in order, who said it, and when from pickup, a page at a time. A line from the room, not the person, is marked room. Any agent of the same account may read it; another account is not disclosed. Reading never acknowledges or resends anything. Use this after a call or when receive names a Call you are waiting on.";
1928
1931
  var GET_GOALS_DESCRIPTION = "Read one to ten Goals by goalIds, returned in the same order under goals (a read never puts you on them). history applies to every requested Goal. A refused read fails the call with its original refusal; no partial result is presented as complete. Each Goal includes its ten most recent other contributors (names, latest entry headlines and times), outcome, state, revision, progress, blockers, the conversation on it (each question with its options and what was decided), `next`, the one step to take, and `more`, where to read further. A question in that conversation reads `open` (nothing yet), `answered` (a choice was made, and `answer` carries it), `replied` (they said something and the read settled the question on their words \u2014 NO option of yours was chosen, and the words are the reply line beside it, so read that before you act), or `closed`. The conversation carries everything the person said, every open question and your newest entry; your older entries are left out and counted \u2014 history: true reads every entry in full. Every Goal of your person is readable, whichever of their agents owns it; another account's Goals are not disclosed.";
1929
1932
  var SearchToolSchema = z5.object({
1930
1933
  query: z5.string().trim().min(1).max(500),
@@ -2143,8 +2146,9 @@ var TALKER_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
2143
2146
  var str4 = z8.string();
2144
2147
  var strs3 = z8.array(z8.string());
2145
2148
  var FilerReplySchema = z8.object({
2146
- /** Which Goals each new line goes on: a line's handle, Goal handles (or keys of new Goals), and what
2147
- * the line says in at most ten words. */
2149
+ /** Which Goals each new line goes on: a line's handle, Goal handles (or keys of new Goals: a line that asks
2150
+ * for new work goes on the Goal it creates, owner 2026-10-26), and what the line says in at most twenty
2151
+ * words (owner, 2026-10-26: "bump it from 10 to 20 words"). */
2148
2152
  filed: z8.array(z8.object({ line: str4, goals: strs3, summary: str4 }).strict()),
2149
2153
  goals: z8.array(z8.object({
2150
2154
  op: z8.enum(["create", "edit", "complete", "cancel", "reopen", "assign", "defer", "move", "block", "unblock"]),
@@ -2419,7 +2423,7 @@ var NotifyRequestFields = z12.object({
2419
2423
  * derive agent-side before sealing, so the server only ever shapes plaintext). */
2420
2424
  // 10k, not a sentence budget. What the human hears is bounded by the BROKER — it splits
2421
2425
  // the ask into topics and gives each one at most three sentences and one question
2422
- // (docs/brain/broker/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
2426
+ // (docs/history/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
2423
2427
  // Owner, 2026-07-28: "our actual limitation on how long something is to the user should
2424
2428
  // come from the broker splitting and summarizing." The cap that remains is a size guard.
2425
2429
  ask: z12.string().min(1).max(1e4).optional().describe(
@@ -2496,7 +2500,7 @@ var UserAnswerSchema = z12.discriminatedUnion("kind", [
2496
2500
  z12.object({ kind: z12.literal("clarify"), chunks: z12.array(z12.string()).min(1) }),
2497
2501
  z12.object({ kind: z12.literal("confirm"), approved: z12.boolean() }),
2498
2502
  z12.object({ kind: z12.literal("turns"), turns: z12.array(TurnSchema).min(1) }),
2499
- /** An auto-answer derived from the user's PAST decisions (docs/brain/broker/precedent-design.md §2):
2503
+ /** An auto-answer derived from the user's PAST decisions (docs/history/precedent-design.md §2):
2500
2504
  * delivered through the same settle/await path as a human answer, carrying the judge's
2501
2505
  * derivation and the precedent ids it grew from. Always paired with a visible trail
2502
2506
  * card the user can reply to — the broker never overrides the user. */
@@ -2812,7 +2816,7 @@ var InboxItemSchema = z12.object({
2812
2816
  "Labels for a select:'confirm' paige \u2014 'yesno' (Yes/No) or 'approve' (Approve/Deny). Ignored unless select is 'confirm'."
2813
2817
  ),
2814
2818
  /** Real downstream work is stuck behind this one — set by the agent, independent of
2815
- * urgency (see the main README's "premier use case" + docs/delivery/notify/states.md). Drives the
2819
+ * urgency (see the main README's "premier use case" + docs/history/notify-states.md). Drives the
2816
2820
  * inbox's blocking badge and the extra confirm step before dismissing it. */
2817
2821
  blocking: z12.boolean().default(false),
2818
2822
  /** WHAT FREED THIS QUESTION (owner, 2026-10-16, Goal 2383ef14: "we don't really show the question
@@ -2830,6 +2834,12 @@ var InboxItemSchema = z12.object({
2830
2834
  /** The answer in ten words, when the talker wrote one beside it. */
2831
2835
  summary: z12.string().optional()
2832
2836
  }).optional(),
2837
+ /** WHAT THIS CARD ANSWERS (owner, 2026-10-27, Goal 81b6a9d6: "this reads very clearly as an answer to
2838
+ * something I asked, but I don't see the question… To show the question near the top of the card").
2839
+ * An agent's card that is its answer to one of the person's own questions carries that question's
2840
+ * words, drawn above it as "You asked" (`public.questions_answered_by`, read beside the card read).
2841
+ * Absent on every card that answers nothing of theirs, and on a held question, which has `freedBy`. */
2842
+ answering: z12.object({ asked: z12.string() }).optional(),
2833
2843
  /** The user's locked-in answer; present only for replied items (GET /api/replied/:id). */
2834
2844
  answer: UserAnswerSchema.optional(),
2835
2845
  /** THE TARGET FACTS A CARD RENDERS (#1796 point 5, 2026-09-11): the Delivery it is a view of,
@@ -2891,6 +2901,7 @@ var MissedCallSchema = z12.enum([
2891
2901
  ]);
2892
2902
  var clock = (h) => h === 0 ? "midnight" : h === 12 ? "noon" : h < 12 ? `${h} am` : `${h - 12} pm`;
2893
2903
  var QUIET = ` Nothing rings from ${clock(NIGHT.from)} to ${clock(NIGHT.to)} your time; the count waits for morning.`;
2904
+ var THEIR_QUIET = ` Nothing rings from ${clock(NIGHT.from)} to ${clock(NIGHT.to)} their time; the count waits for morning.`;
2894
2905
  var BrokerTuningSchema = z12.object({
2895
2906
  /** 'none' = skip the spoken ack after a mapped answer (power users find it slow). */
2896
2907
  ackVerbosity: z12.enum(["normal", "none"]).optional(),
@@ -3015,7 +3026,8 @@ var ConnectionSummarySchema = z12.object({
3015
3026
  kind: z12.enum(["device", "agent"]).optional(),
3016
3027
  /** For an agent, the token id of the DEVICE that minted it — so agents group under their
3017
3028
  * machine, and revoking a device cascades to them. Null on devices, and on unlinked
3018
- * agents (phone-launched, provider-managed, or minted before the link existed). */
3029
+ * agents (provider-managed, hatched by another agent, or minted before the link existed);
3030
+ * a phone-launched agent is linked to the computer it runs on since #1602. */
3019
3031
  mintedByDevice: z12.string().nullable().optional(),
3020
3032
  device: z12.string().nullable(),
3021
3033
  /** The agent's display name (the single pairing name). */
@@ -3029,7 +3041,7 @@ var ConnectionSummarySchema = z12.object({
3029
3041
  * user on the agent's own page. null = no ceiling (today's behaviour for every
3030
3042
  * connection). Android binds importance to a relationship rather than to each message,
3031
3043
  * and that is the thing our roster could not say: "Marlow may always call me; Otto
3032
- * never may" (docs/clients/app/party/navigation-design.md, gap 2). Clamped in `arbitrateLevel`, so it binds
3044
+ * never may" (docs/history/party-navigation-design.md, gap 2). Clamped in `arbitrateLevel`, so it binds
3033
3045
  * every surface at once and outranks even `sessionMode: all_calls` — a mode the user
3034
3046
  * set once must not overrule a rule they set about one agent. */
3035
3047
  reach: NotifyLevelSchema.nullable().optional(),
@@ -3188,12 +3200,14 @@ var QueueItemSchema = z12.object({
3188
3200
  /** Its questions: every OPEN one, and at most ten settled, newest settled first
3189
3201
  * (20260929133308) — the page decides which of them to show. NOT the whole set: `asked` and
3190
3202
  * `answered` are, and a settled one's words are a line (280 characters), its body read when the
3191
- * question is opened. */
3203
+ * question is opened. Never a CANCELLED one (withdrawn, dismissed, or its Goal or call ended): it
3204
+ * asks nothing of anyone (#3723). */
3192
3205
  questions: z12.array(QueueQuestionSchema).default([]),
3193
3206
  /** HOW MANY QUESTIONS THIS WORK HAS ASKED, and how many are answered — the Goal's own totals,
3194
3207
  * bounded at 100 server-side. A tally counted off `questions` is a wrong number that looks
3195
3208
  * right once the cap bites (`walk/trees.ts` `tallyOf`). Optional, and defaulted from the array
3196
- * by the projection, so hand-built queues (fixtures, the demo) need not spell them. */
3209
+ * by the projection, so hand-built queues (fixtures, the demo) need not spell them. A cancelled
3210
+ * question is not asked (#3725). */
3197
3211
  asked: z12.number().optional(),
3198
3212
  answered: z12.number().optional(),
3199
3213
  /** Every note on it the person replied to (`QueueReplySchema`) — the page decides which to show.
@@ -3208,6 +3222,10 @@ var QueueItemSchema = z12.object({
3208
3222
  * as progress). `updatedAt` moves for reasons nobody chose — a
3209
3223
  * state recomputed, a review flag — so it cannot tell work in hand from work gone quiet. */
3210
3224
  lastProgressAt: z12.string().nullable().optional(),
3225
+ /** WHEN AN AGENT LAST ACTED ON IT (owner, 2026-10-27: "Move it now", Goal 567258dc): its newest agent write, an
3226
+ * Entry or a Goal change, Paigy's excluded (`goals.worked_at`). What keeps work an agent is writing on from
3227
+ * reading as gone quiet (`coldSince`); absent on a door that does not carry it. */
3228
+ workedAt: z12.string().nullable().optional(),
3211
3229
  /** THE GOAL'S NEWEST WORD, FROM EITHER SIDE (owner, 2026-09-27): the newest Entry on it, of any
3212
3230
  * kind — what the person added ("Add to this"), their reply, the agent's ask or its progress
3213
3231
  * note. A progress note is an Entry, so this is already the newer of the two: the person's note
@@ -3500,6 +3518,11 @@ var CallRecapSchema = z12.object({
3500
3518
  durationMs: z12.number().nullable(),
3501
3519
  /** Bot-clock pickup offset; absent before the timestamp release, null before its report lands. */
3502
3520
  pickupMs: z12.number().nullable().optional(),
3521
+ /** STILL FILING (20261026182117): the call has not ended on the server, or it has and a brain cycle on it is
3522
+ * still pending, the next writer, which may still settle, file or start something. What the close itself
3523
+ * waits for (`private.close_call`). `status` cannot say it: nothing writes "finalizing", and a call reads
3524
+ * "open" until the sweep closes it, after nothing is pending. Absent from an API before it. */
3525
+ filing: z12.boolean().optional(),
3503
3526
  agents: z12.array(z12.object({ id: z12.string(), name: z12.string().nullable() }))
3504
3527
  }),
3505
3528
  topics: z12.array(z12.object({
@@ -3554,7 +3577,8 @@ var CallRecapSchema = z12.object({
3554
3577
  words: z12.string(),
3555
3578
  atMs: z12.number()
3556
3579
  })),
3557
- more: z12.object({ lines: z12.number(), entries: z12.number(), topics: z12.number() }),
3580
+ /** What did not fit, counted. `settles` counts items past the recap's 100; absent before 20261026165518. */
3581
+ more: z12.object({ lines: z12.number(), entries: z12.number(), topics: z12.number(), settles: z12.number().optional() }),
3558
3582
  /** Last stored position on this page when another exists; absent before paging shipped. */
3559
3583
  next: z12.number().int().nonnegative().nullable().optional(),
3560
3584
  /** THE CALL AS ONE LIST OF ROWS (owner, 2026-10-14: "we only really want a thing like transcript but
@@ -3593,6 +3617,24 @@ var CallRecapSchema = z12.object({
3593
3617
  * from an API before it, where the screen falls back to its own reading. */
3594
3618
  waiting: z12.boolean().optional(),
3595
3619
  lineIds: z12.array(z12.string())
3620
+ })).optional(),
3621
+ /** THE RECAP (owner, 2026-10-26: "the transcript should just be the entries that settled or
3622
+ * acknowledged the items; that's it"). Each item the person's words settled on this call, in the
3623
+ * order they said them: who asked it (`by`), the item in its agent's words (`title`), and only the
3624
+ * words of theirs that settled it (`lines`: each line once, verbatim, with when it was said on the
3625
+ * bot clock like `said[].atMs`). Built from their replies, not from what the call put, so an item
3626
+ * settled without being put is still here. Beside them (owner: "List them too, with the words that
3627
+ * said them"), each Goal his words told something (`kind` "told") or the call started ("started"),
3628
+ * with `requestId` null and the Goal's name as `title`; a started Goal may have no `lines` yet. `kind`
3629
+ * is a string, not an enum, so a later kind never fails an older build's parse; `requestId` is the
3630
+ * request the words settled. On the first page only; absent from an API before it. */
3631
+ settles: z12.array(z12.object({
3632
+ requestId: z12.string().nullable(),
3633
+ kind: z12.string(),
3634
+ by: z12.object({ participant: z12.string(), agentId: z12.string().nullable(), name: z12.string() }),
3635
+ goalId: z12.string().uuid().nullable(),
3636
+ title: z12.string(),
3637
+ lines: z12.array(z12.object({ lineId: z12.string(), words: z12.string(), atMs: z12.number() }))
3596
3638
  })).optional()
3597
3639
  });
3598
3640
  function sessionSlot(sessionId2) {
@@ -3936,11 +3978,12 @@ async function checkActivity(opts = {}) {
3936
3978
  if (!res.ok) await fail("check_activity", res);
3937
3979
  return await res.json();
3938
3980
  }
3939
- var NOT_SENT = `Recorded as the Goal's progress, not sent: nobody was notified. The person is told only a question, an answer to one they asked you, and what you say once the Goal is done. To close the work, send contact.completions or manage_goals kind:complete with the shared completion report, closing and reporting together. If the person asked you, in so many words, to send them this, send it again with userExplicitlyRequested: "any" on that update.`;
3981
+ var NOT_SENT = `Recorded as the Goal's progress, not sent to the person; the other agents that wrote on the Goal in the last hour are told. The person is told only a question, an answer to one they asked you, and what you say once the Goal is done. To close the work, send contact.completions or manage_goals kind:complete with the shared completion report, closing and reporting together. If the person asked you, in so many words, to send them this, send it again with userExplicitlyRequested: "any" on that update.`;
3940
3982
  var APPLIED = "Applied; nothing was sent to the person.";
3941
3983
  var DEMOTED = "Delivered as a card, not a call: the person's settings do not allow a call right now (silent, quiet hours, or a mode). It has reached them; do not send it again.";
3942
3984
  async function readDelivery(deliveryId, opts = {}) {
3943
- const res = await ensureAuthed(await (opts.reach ?? reach)(`${BACKEND_URL}/api/deliveries/${encodeURIComponent(deliveryId)}`, {
3985
+ const query = opts.transcript ? `?transcript=1${opts.after ? `&after=${encodeURIComponent(opts.after)}` : ""}` : "";
3986
+ const res = await ensureAuthed(await (opts.reach ?? reach)(`${BACKEND_URL}/api/deliveries/${encodeURIComponent(deliveryId)}${query}`, {
3944
3987
  headers: { authorization: `Bearer ${authToken(opts.token) ?? ""}` },
3945
3988
  signal: opts.signal
3946
3989
  }));
@@ -4177,7 +4220,11 @@ function goalView(g) {
4177
4220
  subtree: g.subtree?.length ? g.subtree.map((c) => compact({
4178
4221
  goal: `${" ".repeat(c.depth - 1)}${c.title} (${c.state})`,
4179
4222
  goalId: c.goalId,
4180
- questions: c.questions.length ? c.questions.map((q) => q.answer ? `${q.question} \u2192 ${q.answer}` : `${q.question} \u2192 (open)`) : void 0
4223
+ // AN ANSWERED QUESTION NEVER READS OPEN (2026-10-27, Goal b5f1fc27): an answer given on a call,
4224
+ // an option pick or a spoken reply, has an instant on the list's row and no words there, and
4225
+ // it read "(open)". Seven answered questions read that way, and an agent reading them would
4226
+ // ask the owner again. The words are on the Goal's own read.
4227
+ questions: c.questions.length ? c.questions.map((q) => `${q.question} \u2192 ${q.answer || (q.answeredAt ? "(answered: read this Goal for the answer)" : "(open)")}`) : void 0
4181
4228
  })) : void 0,
4182
4229
  blockedBy: g.blockedDependencyGoalIds,
4183
4230
  dueAt: g.dueAt,
@@ -4205,7 +4252,8 @@ var itemsView = (results) => (results ?? []).map((r) => compact({
4205
4252
  error: r.error,
4206
4253
  detail: r.detail
4207
4254
  }));
4208
- function deliveryReadView(d) {
4255
+ function deliveryReadView(d, asked2 = {}) {
4256
+ const t = d.transcript;
4209
4257
  return compact({
4210
4258
  deliveryId: d.deliveryId,
4211
4259
  kind: d.kind,
@@ -4214,9 +4262,20 @@ function deliveryReadView(d) {
4214
4262
  conversation: conversation(d),
4215
4263
  callState: d.callState,
4216
4264
  callOutcome: d.callOutcome ?? (d.kind === "call" ? d.message : void 0),
4217
- next: d.callState && d.callState !== "ended" ? "Keep receiving with contact({wait:true}) while this Call is open, even after an empty window. Do not resend the ask." : "Answers and follow-ups are on their Goals; receive on your next wake. This read acknowledges nothing."
4265
+ // WHAT WAS SAID (owner, 2026-10-26): each line as "m:ss", who said it, and the words; `for` and `room` only
4266
+ // when they are true of the line, so a short call reads as the call did.
4267
+ transcript: t ? compact({
4268
+ timedFrom: t.pickupKnown ? "pickup" : "the call's start",
4269
+ lines: t.lines.map((l) => compact({ at: clock2(l.atMs), by: l.by, for: l.for ?? void 0, room: l.room || void 0, words: l.words })),
4270
+ next: t.next ?? void 0
4271
+ }) : void 0,
4272
+ next: t?.next ? `Read the next page of the transcript with get_delivery({deliveryId: "${d.deliveryId}", transcript: true, after: "${t.next}"}).` : asked2.transcript && !t ? d.kind === "call" ? "This API sent no transcript: it is older than the transcript, or the call has none it can show." : "Only a Call has a transcript." : d.callState && d.callState !== "ended" ? "Keep receiving with contact({wait:true}) while this Call is open, even after an empty window. Do not resend the ask." : "Answers and follow-ups are on their Goals; receive on your next wake. This read acknowledges nothing."
4218
4273
  });
4219
4274
  }
4275
+ function clock2(ms) {
4276
+ const s = Math.max(0, Math.floor(ms / 1e3));
4277
+ return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`;
4278
+ }
4220
4279
  function deliveryView(d) {
4221
4280
  const answers = "Answers land on the Goal: collect them with contact({wait:true}) or get_goals. Do not resend it.";
4222
4281
  const pending = d.state === "open" && d.decisionNeeds.some((n) => n.state === "open");
@@ -4296,6 +4355,8 @@ function receivedView(r, now = Date.now()) {
4296
4355
  // on startup and after a wake (contact({wait:false}), and every hosted receive), never on a window of a
4297
4356
  // held wait, which would repeat them window after window.
4298
4357
  houseRules: r.waitOutcome === "not_waited" ? w.houseRules : void 0,
4358
+ // THEIR RING POLICY, ONE FOR EVERY AGENT (owner, 2026-10-27, Goal 6faa6a51), on the same reads as the house rules.
4359
+ ringPolicy: r.waitOutcome === "not_waited" ? w.ringPolicy : void 0,
4299
4360
  next: [
4300
4361
  r.events.length ? `Handle each event, then acknowledge the ones you handled: contact({ ackEventIds: [${r.events.filter((e) => e.kind !== "question").map((e) => `"${e.eventId}"`).join(", ")}] }).` : w.claimable || assigned.length || rings.length || w.calls?.some((c) => c.callState !== "ended") ? "No messages." : "Nothing is waiting.",
4301
4362
  ...owed.length ? [`You owe ${owed.length === 1 ? "an answer" : `${owed.length} answers`}: contact({ answers: [{ questionId: "<questionId>", answer: { text: <your answer> } }] }) for each question; a question is answered, never acknowledged.`] : [],
@@ -4380,8 +4441,16 @@ async function runTool(name, args, opts) {
4380
4441
  for (const g of managed.goals ?? []) remember(client.token, g.goalId, g.revision);
4381
4442
  return managedView(managed, changes);
4382
4443
  }
4383
- case "get_delivery":
4384
- return deliveryReadView(await readDelivery(GetDeliverySchema.parse(input).deliveryId, { ...client, signal }));
4444
+ case "get_delivery": {
4445
+ const asked2 = GetDeliverySchema.parse(input);
4446
+ return deliveryReadView(
4447
+ await readDelivery(
4448
+ asked2.deliveryId,
4449
+ { ...client, signal, ...asked2.transcript ? { transcript: true, ...asked2.after ? { after: asked2.after } : {} } : {} }
4450
+ ),
4451
+ { transcript: asked2.transcript === true }
4452
+ );
4453
+ }
4385
4454
  case "get_goals": {
4386
4455
  const { goalIds, history } = GetGoalsSchema.parse(input);
4387
4456
  const rows = await getGoals(goalIds, client, { history });
@@ -264,7 +264,7 @@ var sendFields = {
264
264
  "COMPLETIONS close and report in one operation, the same contract as manage_goals kind:complete: closure and the report commit together or neither does. Required children and dependencies must already be finished. options suggest next steps: a tap acknowledges the report and requests that step, and never reopens the Goal (follow-up work needs a new one). No reviewer rejudges it: say only what your evidence supports. Ordinary updates never close a Goal."
265
265
  ),
266
266
  updates: z4.array(UpdateInputSchema).min(1).max(20).optional().describe(
267
- "News: progress, findings, a result. An update asks nothing. It reaches the person only when they asked for it (userExplicitlyRequested), when it answers something they said, or once its Goal is done; otherwise it is recorded as the Goal's progress and nobody is notified."
267
+ "News: progress, findings, a result. An update asks nothing. It reaches the person only when they asked for it (userExplicitlyRequested), when it answers something they said, or once its Goal is done; otherwise it is recorded as the Goal's progress, which the person is not told. Every update reaches the other agents that wrote on its Goal in the last hour: to tell another agent something, write it as an update on that agent's Goal."
268
268
  ),
269
269
  answers: z4.array(AnswerInputSchema).min(1).max(20).optional().describe("Answers to Questions addressed to you."),
270
270
  withdrawQuestionIds: z4.array(questionHandle).min(1).max(10).optional().describe(
@@ -399,9 +399,12 @@ var GetGoalsSchema = z5.object({
399
399
  history: z5.boolean().optional()
400
400
  }).strict();
401
401
  var GetDeliverySchema = z5.object({
402
- deliveryId: z5.string().uuid().describe("The Delivery id returned by contact or receive.")
402
+ deliveryId: z5.string().uuid().describe("The Delivery id returned by contact or receive."),
403
+ // WHAT WAS SAID ON A CALL (owner, 2026-10-26, Goal c743f4a4: "A flag on get_delivery", "Any of my agents").
404
+ transcript: z5.boolean().optional().describe("For a Call: also return what was said on it, one page of spoken lines."),
405
+ after: z5.string().max(40).optional().describe("With transcript: the next value the previous page returned, to read the next page.")
403
406
  }).strict();
404
- var GET_DELIVERY_DESCRIPTION = "Read a Delivery in full: its whole ask, units, options and answers, plus current callState and callOutcome for a Call. Any agent of the same account may read it; another account is not disclosed. Reading never acknowledges or resends anything. Use this after a call or when receive names a Call you are waiting on.";
407
+ var GET_DELIVERY_DESCRIPTION = "Read a Delivery in full: its whole ask, units, options and answers, plus current callState and callOutcome for a Call. For a Call, transcript: true adds what was said: each spoken line in order, who said it, and when from pickup, a page at a time. A line from the room, not the person, is marked room. Any agent of the same account may read it; another account is not disclosed. Reading never acknowledges or resends anything. Use this after a call or when receive names a Call you are waiting on.";
405
408
  var GET_GOALS_DESCRIPTION = "Read one to ten Goals by goalIds, returned in the same order under goals (a read never puts you on them). history applies to every requested Goal. A refused read fails the call with its original refusal; no partial result is presented as complete. Each Goal includes its ten most recent other contributors (names, latest entry headlines and times), outcome, state, revision, progress, blockers, the conversation on it (each question with its options and what was decided), `next`, the one step to take, and `more`, where to read further. A question in that conversation reads `open` (nothing yet), `answered` (a choice was made, and `answer` carries it), `replied` (they said something and the read settled the question on their words \u2014 NO option of yours was chosen, and the words are the reply line beside it, so read that before you act), or `closed`. The conversation carries everything the person said, every open question and your newest entry; your older entries are left out and counted \u2014 history: true reads every entry in full. Every Goal of your person is readable, whichever of their agents owns it; another account's Goals are not disclosed.";
406
409
  var SearchToolSchema = z5.object({
407
410
  query: z5.string().trim().min(1).max(500),
@@ -626,8 +629,9 @@ var TALKER_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
626
629
  var str4 = z8.string();
627
630
  var strs3 = z8.array(z8.string());
628
631
  var FilerReplySchema = z8.object({
629
- /** Which Goals each new line goes on: a line's handle, Goal handles (or keys of new Goals), and what
630
- * the line says in at most ten words. */
632
+ /** Which Goals each new line goes on: a line's handle, Goal handles (or keys of new Goals: a line that asks
633
+ * for new work goes on the Goal it creates, owner 2026-10-26), and what the line says in at most twenty
634
+ * words (owner, 2026-10-26: "bump it from 10 to 20 words"). */
631
635
  filed: z8.array(z8.object({ line: str4, goals: strs3, summary: str4 }).strict()),
632
636
  goals: z8.array(z8.object({
633
637
  op: z8.enum(["create", "edit", "complete", "cancel", "reopen", "assign", "defer", "move", "block", "unblock"]),
@@ -888,7 +892,7 @@ var NotifyRequestFields = z12.object({
888
892
  * derive agent-side before sealing, so the server only ever shapes plaintext). */
889
893
  // 10k, not a sentence budget. What the human hears is bounded by the BROKER — it splits
890
894
  // the ask into topics and gives each one at most three sentences and one question
891
- // (docs/brain/broker/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
895
+ // (docs/history/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
892
896
  // Owner, 2026-07-28: "our actual limitation on how long something is to the user should
893
897
  // come from the broker splitting and summarizing." The cap that remains is a size guard.
894
898
  ask: z12.string().min(1).max(1e4).optional().describe(
@@ -965,7 +969,7 @@ var UserAnswerSchema = z12.discriminatedUnion("kind", [
965
969
  z12.object({ kind: z12.literal("clarify"), chunks: z12.array(z12.string()).min(1) }),
966
970
  z12.object({ kind: z12.literal("confirm"), approved: z12.boolean() }),
967
971
  z12.object({ kind: z12.literal("turns"), turns: z12.array(TurnSchema).min(1) }),
968
- /** An auto-answer derived from the user's PAST decisions (docs/brain/broker/precedent-design.md §2):
972
+ /** An auto-answer derived from the user's PAST decisions (docs/history/precedent-design.md §2):
969
973
  * delivered through the same settle/await path as a human answer, carrying the judge's
970
974
  * derivation and the precedent ids it grew from. Always paired with a visible trail
971
975
  * card the user can reply to — the broker never overrides the user. */
@@ -1281,7 +1285,7 @@ var InboxItemSchema = z12.object({
1281
1285
  "Labels for a select:'confirm' paige \u2014 'yesno' (Yes/No) or 'approve' (Approve/Deny). Ignored unless select is 'confirm'."
1282
1286
  ),
1283
1287
  /** Real downstream work is stuck behind this one — set by the agent, independent of
1284
- * urgency (see the main README's "premier use case" + docs/delivery/notify/states.md). Drives the
1288
+ * urgency (see the main README's "premier use case" + docs/history/notify-states.md). Drives the
1285
1289
  * inbox's blocking badge and the extra confirm step before dismissing it. */
1286
1290
  blocking: z12.boolean().default(false),
1287
1291
  /** WHAT FREED THIS QUESTION (owner, 2026-10-16, Goal 2383ef14: "we don't really show the question
@@ -1299,6 +1303,12 @@ var InboxItemSchema = z12.object({
1299
1303
  /** The answer in ten words, when the talker wrote one beside it. */
1300
1304
  summary: z12.string().optional()
1301
1305
  }).optional(),
1306
+ /** WHAT THIS CARD ANSWERS (owner, 2026-10-27, Goal 81b6a9d6: "this reads very clearly as an answer to
1307
+ * something I asked, but I don't see the question… To show the question near the top of the card").
1308
+ * An agent's card that is its answer to one of the person's own questions carries that question's
1309
+ * words, drawn above it as "You asked" (`public.questions_answered_by`, read beside the card read).
1310
+ * Absent on every card that answers nothing of theirs, and on a held question, which has `freedBy`. */
1311
+ answering: z12.object({ asked: z12.string() }).optional(),
1302
1312
  /** The user's locked-in answer; present only for replied items (GET /api/replied/:id). */
1303
1313
  answer: UserAnswerSchema.optional(),
1304
1314
  /** THE TARGET FACTS A CARD RENDERS (#1796 point 5, 2026-09-11): the Delivery it is a view of,
@@ -1360,6 +1370,7 @@ var MissedCallSchema = z12.enum([
1360
1370
  ]);
1361
1371
  var clock = (h) => h === 0 ? "midnight" : h === 12 ? "noon" : h < 12 ? `${h} am` : `${h - 12} pm`;
1362
1372
  var QUIET = ` Nothing rings from ${clock(NIGHT.from)} to ${clock(NIGHT.to)} your time; the count waits for morning.`;
1373
+ var THEIR_QUIET = ` Nothing rings from ${clock(NIGHT.from)} to ${clock(NIGHT.to)} their time; the count waits for morning.`;
1363
1374
  var BrokerTuningSchema = z12.object({
1364
1375
  /** 'none' = skip the spoken ack after a mapped answer (power users find it slow). */
1365
1376
  ackVerbosity: z12.enum(["normal", "none"]).optional(),
@@ -1484,7 +1495,8 @@ var ConnectionSummarySchema = z12.object({
1484
1495
  kind: z12.enum(["device", "agent"]).optional(),
1485
1496
  /** For an agent, the token id of the DEVICE that minted it — so agents group under their
1486
1497
  * machine, and revoking a device cascades to them. Null on devices, and on unlinked
1487
- * agents (phone-launched, provider-managed, or minted before the link existed). */
1498
+ * agents (provider-managed, hatched by another agent, or minted before the link existed);
1499
+ * a phone-launched agent is linked to the computer it runs on since #1602. */
1488
1500
  mintedByDevice: z12.string().nullable().optional(),
1489
1501
  device: z12.string().nullable(),
1490
1502
  /** The agent's display name (the single pairing name). */
@@ -1498,7 +1510,7 @@ var ConnectionSummarySchema = z12.object({
1498
1510
  * user on the agent's own page. null = no ceiling (today's behaviour for every
1499
1511
  * connection). Android binds importance to a relationship rather than to each message,
1500
1512
  * and that is the thing our roster could not say: "Marlow may always call me; Otto
1501
- * never may" (docs/clients/app/party/navigation-design.md, gap 2). Clamped in `arbitrateLevel`, so it binds
1513
+ * never may" (docs/history/party-navigation-design.md, gap 2). Clamped in `arbitrateLevel`, so it binds
1502
1514
  * every surface at once and outranks even `sessionMode: all_calls` — a mode the user
1503
1515
  * set once must not overrule a rule they set about one agent. */
1504
1516
  reach: NotifyLevelSchema.nullable().optional(),
@@ -1657,12 +1669,14 @@ var QueueItemSchema = z12.object({
1657
1669
  /** Its questions: every OPEN one, and at most ten settled, newest settled first
1658
1670
  * (20260929133308) — the page decides which of them to show. NOT the whole set: `asked` and
1659
1671
  * `answered` are, and a settled one's words are a line (280 characters), its body read when the
1660
- * question is opened. */
1672
+ * question is opened. Never a CANCELLED one (withdrawn, dismissed, or its Goal or call ended): it
1673
+ * asks nothing of anyone (#3723). */
1661
1674
  questions: z12.array(QueueQuestionSchema).default([]),
1662
1675
  /** HOW MANY QUESTIONS THIS WORK HAS ASKED, and how many are answered — the Goal's own totals,
1663
1676
  * bounded at 100 server-side. A tally counted off `questions` is a wrong number that looks
1664
1677
  * right once the cap bites (`walk/trees.ts` `tallyOf`). Optional, and defaulted from the array
1665
- * by the projection, so hand-built queues (fixtures, the demo) need not spell them. */
1678
+ * by the projection, so hand-built queues (fixtures, the demo) need not spell them. A cancelled
1679
+ * question is not asked (#3725). */
1666
1680
  asked: z12.number().optional(),
1667
1681
  answered: z12.number().optional(),
1668
1682
  /** Every note on it the person replied to (`QueueReplySchema`) — the page decides which to show.
@@ -1677,6 +1691,10 @@ var QueueItemSchema = z12.object({
1677
1691
  * as progress). `updatedAt` moves for reasons nobody chose — a
1678
1692
  * state recomputed, a review flag — so it cannot tell work in hand from work gone quiet. */
1679
1693
  lastProgressAt: z12.string().nullable().optional(),
1694
+ /** WHEN AN AGENT LAST ACTED ON IT (owner, 2026-10-27: "Move it now", Goal 567258dc): its newest agent write, an
1695
+ * Entry or a Goal change, Paigy's excluded (`goals.worked_at`). What keeps work an agent is writing on from
1696
+ * reading as gone quiet (`coldSince`); absent on a door that does not carry it. */
1697
+ workedAt: z12.string().nullable().optional(),
1680
1698
  /** THE GOAL'S NEWEST WORD, FROM EITHER SIDE (owner, 2026-09-27): the newest Entry on it, of any
1681
1699
  * kind — what the person added ("Add to this"), their reply, the agent's ask or its progress
1682
1700
  * note. A progress note is an Entry, so this is already the newer of the two: the person's note
@@ -1967,6 +1985,11 @@ var CallRecapSchema = z12.object({
1967
1985
  durationMs: z12.number().nullable(),
1968
1986
  /** Bot-clock pickup offset; absent before the timestamp release, null before its report lands. */
1969
1987
  pickupMs: z12.number().nullable().optional(),
1988
+ /** STILL FILING (20261026182117): the call has not ended on the server, or it has and a brain cycle on it is
1989
+ * still pending, the next writer, which may still settle, file or start something. What the close itself
1990
+ * waits for (`private.close_call`). `status` cannot say it: nothing writes "finalizing", and a call reads
1991
+ * "open" until the sweep closes it, after nothing is pending. Absent from an API before it. */
1992
+ filing: z12.boolean().optional(),
1970
1993
  agents: z12.array(z12.object({ id: z12.string(), name: z12.string().nullable() }))
1971
1994
  }),
1972
1995
  topics: z12.array(z12.object({
@@ -2021,7 +2044,8 @@ var CallRecapSchema = z12.object({
2021
2044
  words: z12.string(),
2022
2045
  atMs: z12.number()
2023
2046
  })),
2024
- more: z12.object({ lines: z12.number(), entries: z12.number(), topics: z12.number() }),
2047
+ /** What did not fit, counted. `settles` counts items past the recap's 100; absent before 20261026165518. */
2048
+ more: z12.object({ lines: z12.number(), entries: z12.number(), topics: z12.number(), settles: z12.number().optional() }),
2025
2049
  /** Last stored position on this page when another exists; absent before paging shipped. */
2026
2050
  next: z12.number().int().nonnegative().nullable().optional(),
2027
2051
  /** THE CALL AS ONE LIST OF ROWS (owner, 2026-10-14: "we only really want a thing like transcript but
@@ -2060,6 +2084,24 @@ var CallRecapSchema = z12.object({
2060
2084
  * from an API before it, where the screen falls back to its own reading. */
2061
2085
  waiting: z12.boolean().optional(),
2062
2086
  lineIds: z12.array(z12.string())
2087
+ })).optional(),
2088
+ /** THE RECAP (owner, 2026-10-26: "the transcript should just be the entries that settled or
2089
+ * acknowledged the items; that's it"). Each item the person's words settled on this call, in the
2090
+ * order they said them: who asked it (`by`), the item in its agent's words (`title`), and only the
2091
+ * words of theirs that settled it (`lines`: each line once, verbatim, with when it was said on the
2092
+ * bot clock like `said[].atMs`). Built from their replies, not from what the call put, so an item
2093
+ * settled without being put is still here. Beside them (owner: "List them too, with the words that
2094
+ * said them"), each Goal his words told something (`kind` "told") or the call started ("started"),
2095
+ * with `requestId` null and the Goal's name as `title`; a started Goal may have no `lines` yet. `kind`
2096
+ * is a string, not an enum, so a later kind never fails an older build's parse; `requestId` is the
2097
+ * request the words settled. On the first page only; absent from an API before it. */
2098
+ settles: z12.array(z12.object({
2099
+ requestId: z12.string().nullable(),
2100
+ kind: z12.string(),
2101
+ by: z12.object({ participant: z12.string(), agentId: z12.string().nullable(), name: z12.string() }),
2102
+ goalId: z12.string().uuid().nullable(),
2103
+ title: z12.string(),
2104
+ lines: z12.array(z12.object({ lineId: z12.string(), words: z12.string(), atMs: z12.number() }))
2063
2105
  })).optional()
2064
2106
  });
2065
2107
 
@@ -5,12 +5,12 @@ import {
5
5
  serverInstructions,
6
6
  sessionStartHook,
7
7
  withSessionStartHook
8
- } from "./chunk-H2EBILBE.js";
8
+ } from "./chunk-NYSDESST.js";
9
9
  import {
10
10
  CODEX_ENV,
11
11
  agentName,
12
12
  withCodexEnv
13
- } from "./chunk-V4OVLFMP.js";
13
+ } from "./chunk-CPDYOHSY.js";
14
14
 
15
15
  // src/toolset.ts
16
16
  var CONFIGURE_DESCRIPTION = "Set this agent up with Paigy \u2014 call it FIRST, before contact, and any time you're unsure who you are. One call does whatever the situation needs: NOT SET UP \u2192 if this machine holds a device credential (the user ran the Paigy desktop app or harness) it hatches an identity INSTANTLY, no code and no approval; otherwise it starts the code ceremony. ALREADY SET UP \u2192 returns your current identity and the two things left to decide, renaming it or logging out. TOKEN NO LONGER VALID \u2192 says so, then re-pairs. Pass { name, voice } to choose who you are when hatching, or to RENAME yourself when already set up (pick your own; voices: rachel, george, jessica, brian, lily). Safe to call any time: idempotent, and it never writes settings.\n\nTHE CODE CEREMONY does not open a browser; the user enters the code in the Paigy app (or scans `qr`). A result with { user_code, device_code, qr, user_message } has already started polling for approval in the background: you MUST immediately print the `user_message` (the bare code) to the user, AND in that same turn call configure again with that `device_code` to collect the result. It returns the moment the user approves; on { status:'pending' } call again to keep waiting; on { status:'awaiting_confirmation' } (E2EE) show the bare `user_message` verify code and call again to finish. Every result's first text block states the code plainly.\n\nOn { status:'paired' }, or whenever it returns `enable_command`, ALWAYS follow the `enable_prompt`: PRINT that command for the user to run, so Paigy's tools stop prompting each time. You cannot apply it yourself (it writes your own permission allowlist, which hosts block as privilege escalation), so print it, don't wait for it, and carry on.\n\nLOG OUT with { logOut: true }: it logs out THIS agent only \u2014 its token is revoked server-side and its local entry removed. Other agents and this device's credential are untouched, and a later configure re-hatches instantly while the device credential exists. Disconnecting the device itself is not an agent tool.";
@@ -63,7 +63,7 @@ import {
63
63
  updateSlot,
64
64
  whoAmI,
65
65
  withCodexEnv
66
- } from "./chunk-V4OVLFMP.js";
66
+ } from "./chunk-CPDYOHSY.js";
67
67
  export {
68
68
  AGENT_TOOLS,
69
69
  AGENT_TOOL_NAMES,
package/dist/enable.js CHANGED
@@ -3,9 +3,9 @@ import {
3
3
  PAIGY_TOOL_IDS,
4
4
  enablePaigyTools,
5
5
  installSessionListening
6
- } from "./chunk-PKJJSHLW.js";
7
- import "./chunk-H2EBILBE.js";
8
- import "./chunk-V4OVLFMP.js";
6
+ } from "./chunk-UVVW32KH.js";
7
+ import "./chunk-NYSDESST.js";
8
+ import "./chunk-CPDYOHSY.js";
9
9
 
10
10
  // src/enable.ts
11
11
  function main() {
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  resolvePairing,
11
11
  startPairing,
12
12
  suggestedAgentName
13
- } from "./chunk-6FG3PZR2.js";
13
+ } from "./chunk-AX55W57P.js";
14
14
  import {
15
15
  ConfigureSchema,
16
16
  ENABLE_COMMAND,
@@ -18,7 +18,7 @@ import {
18
18
  SERVER_INSTRUCTIONS,
19
19
  TOOLS,
20
20
  paigyToolsAllowlisted
21
- } from "./chunk-PKJJSHLW.js";
21
+ } from "./chunk-UVVW32KH.js";
22
22
  import {
23
23
  ReachTeller,
24
24
  decideListen,
@@ -29,7 +29,7 @@ import {
29
29
  listenerKey,
30
30
  wakeStatusPath,
31
31
  withReach
32
- } from "./chunk-H2EBILBE.js";
32
+ } from "./chunk-NYSDESST.js";
33
33
  import {
34
34
  clearSurface,
35
35
  writeSurface
@@ -50,7 +50,7 @@ import {
50
50
  setClient,
51
51
  slotName,
52
52
  whoAmI
53
- } from "./chunk-V4OVLFMP.js";
53
+ } from "./chunk-CPDYOHSY.js";
54
54
 
55
55
  // src/index.ts
56
56
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
@@ -199,7 +199,7 @@ function pairStartResult(start, loggedOut) {
199
199
  qr.make();
200
200
  const link = start.verificationUri;
201
201
  const ascii = qr.createASCII(1, 2);
202
- const door = "in Paigy \u2192 Devices \u2192 Connect a computer";
202
+ const door = "in Paigy \u2192 You \u203A Computers \u2192 Connect a computer";
203
203
  const userMessage = loggedOut ? `**Your machine was logged out.** Reconnect and every agent here pairs itself again \u2014 no more codes.
204
204
 
205
205
  **[Reconnect this machine](${link})**
package/dist/listen.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  removeListenMark,
12
12
  wakeStatusPath,
13
13
  writeListenMark
14
- } from "./chunk-H2EBILBE.js";
14
+ } from "./chunk-NYSDESST.js";
15
15
  import {
16
16
  agentName,
17
17
  getGoals,
@@ -20,7 +20,7 @@ import {
20
20
  receive,
21
21
  slotName,
22
22
  subscribeWake
23
- } from "./chunk-V4OVLFMP.js";
23
+ } from "./chunk-CPDYOHSY.js";
24
24
 
25
25
  // src/listen.ts
26
26
  import { createHash } from "crypto";
@@ -174,8 +174,8 @@ function brief(waiting, reason, as, goalId) {
174
174
  const said = newestSaid(lead) || ("about" in lead ? lead.about : "");
175
175
  const shown = said.length > 160 ? `${said.slice(0, 160)}\u2026` : said;
176
176
  const goal = waiting.goal?.goalId ?? lead.goalIds[0];
177
- const act = ` \xB7 get_goals({goalIds:["${goal}"]}) to read it in full, then contact to answer; nothing is acknowledged until contact({ackEventIds})`;
178
- return `Paigy \xB7 ${reason} \xB7 ${waiting.deliveries.length} waiting \xB7 lead ${lead.deliveryId} on Goal ${goal}: "${shown}"${mine}${fresh}${stalled}${act}`;
177
+ const act = goal ? ` \xB7 get_goals({goalIds:["${goal}"]}) to read it in full, then contact to answer; nothing is acknowledged until contact({ackEventIds})` : " \xB7 nothing is acknowledged until contact({ackEventIds})";
178
+ return `Paigy \xB7 ${reason} \xB7 ${waiting.deliveries.length} waiting \xB7 lead ${lead.deliveryId}${goal ? ` on Goal ${goal}` : ""}: "${shown}"${mine}${fresh}${stalled}${act}`;
179
179
  }
180
180
  function launchEnv(waiting, reason, goalId) {
181
181
  const env = { PAIGY_WORK: JSON.stringify(waiting), PAIGY_EVENT: reason };
package/dist/onboard.js CHANGED
@@ -3,14 +3,14 @@ import {
3
3
  resolvePairing,
4
4
  startPairing,
5
5
  suggestedAgentName
6
- } from "./chunk-6FG3PZR2.js";
6
+ } from "./chunk-AX55W57P.js";
7
7
  import {
8
8
  autoConfigureClients,
9
9
  claudeInstallHint,
10
10
  openBrowser,
11
11
  removeOldGeminiHooks
12
- } from "./chunk-PKJJSHLW.js";
13
- import "./chunk-H2EBILBE.js";
12
+ } from "./chunk-UVVW32KH.js";
13
+ import "./chunk-NYSDESST.js";
14
14
  import {
15
15
  TOKEN_PATH,
16
16
  agentName,
@@ -21,7 +21,7 @@ import {
21
21
  saveToken,
22
22
  setIdentity,
23
23
  whoAmI
24
- } from "./chunk-V4OVLFMP.js";
24
+ } from "./chunk-CPDYOHSY.js";
25
25
 
26
26
  // src/onboard.ts
27
27
  function reportRegistered() {
package/dist/slot.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  agentName
4
- } from "./chunk-V4OVLFMP.js";
4
+ } from "./chunk-CPDYOHSY.js";
5
5
 
6
6
  // src/slot.ts
7
7
  process.stdout.write(agentName());
package/dist/stalled.js CHANGED
@@ -33,7 +33,7 @@ async function main() {
33
33
  const dir = join(homedir(), ".paigy", "stalled-reminded");
34
34
  const mark = join(dir, `${session || "session"}-${day}`);
35
35
  if (existsSync(mark)) return;
36
- const { receive } = await import("./dist-EJWDUF5J.js");
36
+ const { receive } = await import("./dist-VYRT3PHE.js");
37
37
  const reply = stopReply((await receive()).stalled ?? []);
38
38
  if (!reply) return;
39
39
  mkdirSync(dir, { recursive: true });
@@ -7,7 +7,7 @@ import {
7
7
  readToken,
8
8
  sessionSlot,
9
9
  slotName
10
- } from "./chunk-V4OVLFMP.js";
10
+ } from "./chunk-CPDYOHSY.js";
11
11
 
12
12
  // src/statusline.ts
13
13
  import { realpathSync } from "fs";
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@paigy/mcp",
3
- "version": "0.40.40",
3
+ "mcpName": "io.github.paigy-ai/mcp",
4
+ "version": "0.40.41",
4
5
  "description": "Paigy MCP server — the AI agent harness that calls you. Lets an agent notify a user and await their reply.",
5
6
  "license": "MIT",
6
7
  "type": "module",