@paigy/mcp 0.40.41 → 0.40.43

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.
@@ -7,21 +7,23 @@ import { homedir } from "os";
7
7
  import { join } from "path";
8
8
  import { randomUUID as randomUUID2 } from "crypto";
9
9
  import { setTimeout as sleep2 } from "timers/promises";
10
- import { z as z12 } from "zod";
10
+ import { z as z14 } from "zod";
11
11
  import { z } from "zod";
12
- import { z as z3 } from "zod";
12
+ import { z as z4 } from "zod";
13
13
  import { z as z2 } from "zod";
14
- import { z as z5 } from "zod";
14
+ import { z as z3 } from "zod";
15
+ import { z as z7 } from "zod";
15
16
  import { ZodFirstPartyTypeKind as ZodFirstPartyTypeKind3 } from "zod/v3";
16
17
  import { ZodFirstPartyTypeKind } from "zod/v3";
17
18
  import { ZodFirstPartyTypeKind as ZodFirstPartyTypeKind2 } from "zod/v3";
18
- import { z as z4 } from "zod";
19
+ import { z as z5 } from "zod";
19
20
  import { z as z6 } from "zod";
20
- import { z as z7 } from "zod";
21
21
  import { z as z8 } from "zod";
22
22
  import { z as z9 } from "zod";
23
23
  import { z as z10 } from "zod";
24
24
  import { z as z11 } from "zod";
25
+ import { z as z12 } from "zod";
26
+ import { z as z13 } from "zod";
25
27
  import { closeSync, existsSync, mkdirSync, openSync, readFileSync as readFileSync2, rmSync, statSync, writeFileSync } from "fs";
26
28
  import { homedir as homedir2 } from "os";
27
29
  import { join as join2 } from "path";
@@ -134,7 +136,7 @@ function parseSessionRecord(text) {
134
136
  return void 0;
135
137
  }
136
138
  function sessionId() {
137
- return envSession("PAIGY_SESSION_ID") ?? claudeConversation() ?? envSession("CLAUDE_CODE_SESSION_ID") ?? envSession("CODEX_THREAD_ID") ?? envSession("CODEX_SESSION_ID") ?? // A Codex thread that was handed no id is its own agent, not the folder's (`underCodex`).
139
+ return envSession("PAIGY_SESSION_ID") ?? claudeConversation() ?? envSession("CLAUDE_CODE_SESSION_ID") ?? envSession("GROK_SESSION_ID") ?? envSession("CODEX_THREAD_ID") ?? envSession("CODEX_SESSION_ID") ?? // A Codex thread that was handed no id is its own agent, not the folder's (`underCodex`).
138
140
  (underCodex() ? INSTANCE_ID : WORKSPACE_ID);
139
141
  }
140
142
  function isNetworkError(e) {
@@ -1619,21 +1621,35 @@ function capRefusals(text, units2, field) {
1619
1621
  function refuseOverCaps(text, units2, field, ctx) {
1620
1622
  for (const { path, message, ...params } of capRefusals(text, units2, field)) ctx.addIssue({ code: z2.ZodIssueCode.custom, path, message, params });
1621
1623
  }
1624
+ var SHIPPED = ["phone", "calls", "server", "store", "agents"];
1625
+ var CAUSES_MAX = 10;
1626
+ var shipped = z3.enum(SHIPPED, {
1627
+ errorMap: () => ({ message: `shipped_unknown: one of ${SHIPPED.join(", ")}.` })
1628
+ }).optional().describe(
1629
+ "Only when this reports a result that LANDED somewhere the person can see it: phone (an app update reached their phone), calls (the voice bot), server, store (the App Store) or agents (the MCP or SDK). Leave it out for work in progress."
1630
+ );
1631
+ var causedBy = z3.array(
1632
+ z3.string().trim().regex(/^[0-9a-fA-F-]{8,36}$/, "cause_not_found: an Entry id, or the short id get_goals prints for the person's words.")
1633
+ ).min(1).max(CAUSES_MAX, `too_many_causes: at most ${CAUSES_MAX}.`).optional().describe(
1634
+ `The person's own words this acts on: the ids (or the short ids get_goals prints) of their answers or notes that led to it, at most ${CAUSES_MAX}. Their app shows each result under the words that caused it, so name every one this follows from. An id that is not their words is refused by name (cause_not_found, cause_ambiguous) and nothing is written.`
1635
+ );
1622
1636
  var COMPLETION_MESSAGE_MAX = 50;
1623
- var CompletionSchema = z3.object({
1624
- goalId: z3.string().uuid().describe("The existing Goal to complete."),
1625
- message: z3.string().trim().min(1).max(COMPLETION_MESSAGE_MAX, "completion_message_too_long: at most 50 characters; put detail in units.").describe("Completion headline, at most 50 characters."),
1626
- units: z3.array(UnitInputSchema.extend({
1627
- title: z3.string().trim().min(1).max(UNIT_TITLE_MAX),
1628
- body: z3.string().trim().min(1).max(UNIT_BODY_MAX)
1637
+ var CompletionSchema = z4.object({
1638
+ goalId: z4.string().uuid().describe("The existing Goal to complete."),
1639
+ message: z4.string().trim().min(1).max(COMPLETION_MESSAGE_MAX, "completion_message_too_long: at most 50 characters; put detail in units.").describe("Completion headline, at most 50 characters: the one thing that would go wrong or stay unclear later if they missed it."),
1640
+ units: z4.array(UnitInputSchema.extend({
1641
+ title: z4.string().trim().min(1).max(UNIT_TITLE_MAX),
1642
+ body: z4.string().trim().min(1).max(UNIT_BODY_MAX)
1629
1643
  })).max(UNITS_MAX).optional().describe("Suggest initial state, changes, current state with verification and limits, and next steps / leftover work with its owner when useful. One idea per unit; omit unnecessary sections."),
1630
- reply: z3.string().trim().min(1).max(OPTION_LABEL_MAX).describe("One acknowledgement in the person's voice, at most 50 characters. Acknowledgement alone requests no follow-up and does not claim they tested the work."),
1631
- options: z3.array(z3.object({
1632
- label: z3.string().trim().min(1).max(OPTION_LABEL_MAX),
1633
- hint: z3.string().trim().min(1).max(OPTION_HINT_MAX)
1634
- }).strict()).max(5).optional().describe("Optional next steps the person may initiate: label (50 characters) and consequence in hint (200). Selecting one acknowledges the report and requests that step from its author; it never reopens this Goal.")
1644
+ reply: z4.string().trim().min(1).max(OPTION_LABEL_MAX).describe("One acknowledgement in the person's voice, at most 50 characters. Acknowledgement alone requests no follow-up and does not claim they tested the work."),
1645
+ options: z4.array(z4.object({
1646
+ label: z4.string().trim().min(1).max(OPTION_LABEL_MAX),
1647
+ hint: z4.string().trim().min(1).max(OPTION_HINT_MAX)
1648
+ }).strict()).max(5).optional().describe("Optional next steps the person may initiate: label (50 characters) and consequence in hint (200). Selecting one acknowledges the report and requests that step from its author; it never reopens this Goal."),
1649
+ causedBy,
1650
+ shipped
1635
1651
  }).strict();
1636
- var CompleteChangeSchema = CompletionSchema.extend({ kind: z3.literal("complete") });
1652
+ var CompleteChangeSchema = CompletionSchema.omit({ causedBy: true, shipped: true }).extend({ kind: z4.literal("complete") });
1637
1653
  var ASKING_RULES = `HOW TO ASK:
1638
1654
  1. One question per object in \`questions\`, so each is answered on its own.
1639
1655
  2. \`goalId\` names the existing Goal it is about (create one with manage_goals first); the answer comes back there.
@@ -1643,7 +1659,7 @@ var ASKING_RULES = `HOW TO ASK:
1643
1659
  6. Read the Goal before asking; never re-ask what was answered or shipped. \`replied\` means they chose no option: it is still yours to settle.
1644
1660
  7. Give options when you have them. Each label names its choice in full (never "Option 2"); never add "Other". \`pickMode\`: one (default), many, rank.
1645
1661
  8. A diagnosis says when, why and how it happens, then proposes one fix.
1646
- 9. Give a report its \`reply\`: one line in THEIR voice for THAT report, so you learn whether they verified it or only received it. Required when it reaches them or completes a Goal.`;
1662
+ 9. Give a report its \`reply\`: one line in THEIR voice for THAT report, so you learn whether they verified it or only received it. Required when it is delivered or its Goal is done.`;
1647
1663
  function draft2020(node) {
1648
1664
  if (Array.isArray(node)) return node.map(draft2020);
1649
1665
  if (node && typeof node === "object") {
@@ -1673,25 +1689,68 @@ function mcpInputSchema(s) {
1673
1689
  delete schema.$schema;
1674
1690
  return draft2020(schema);
1675
1691
  }
1676
- var questionHandle = z4.string().trim().regex(/^[0-9a-fA-F-]{8,36}$/, "a question id, whole or its first eight characters");
1677
- var NodeRef = z4.object({
1678
- type: z4.enum(["goal", "question"]),
1679
- id: z4.string().uuid()
1692
+ var questionHandle = z5.string().trim().regex(/^[0-9a-fA-F-]{8,36}$/, "a question id, whole or its first eight characters");
1693
+ var NodeRef = z5.object({
1694
+ type: z5.enum(["goal", "question"]),
1695
+ id: z5.string().uuid()
1680
1696
  }).strict().describe("A Goal or a Question, by its id.");
1681
- var BlockedAction = z4.enum(["start", "complete", "answer"]).describe("What waits: starting or completing a Goal, or answering a Question.");
1682
- var reason = z4.string().trim().min(1).max(500).describe("Why, as an explanation, never as policy.");
1697
+ var BlockedAction = z5.enum(["start", "complete", "answer"]).describe("What waits: starting or completing a Goal, or answering a Question.");
1698
+ var reason = z5.string().trim().min(1).max(500).describe("Why, as an explanation, never as policy.");
1683
1699
  var actionFits = (b) => b.blocked.type === "goal" === (b.action !== "answer");
1684
1700
  var ACTION_FITS = "a goal is blocked from start or complete; a question from answer";
1685
- var userExplicitlyRequested = z4.enum(["any", "call"]).optional().describe(
1701
+ var userExplicitlyRequested = z5.enum(["any", "call"]).optional().describe(
1686
1702
  `Only what the person said about THIS message, in so many words: "any" when they asked you to send it to them ("send it to my phone", "message me the result"), "call" when they asked to be called about it. It is then delivered (a call rings for the whole contact, and carries everything waiting on them); omitted, an update is only recorded as the Goal's progress unless the person needs it. Never set it to make a message louder.`
1687
1703
  );
1688
- var units = z4.array(UnitInputSchema).optional().describe(
1689
- `The context this message needs, as up to ${UNITS_MAX} units in reading order, each {title, body}: a title of at most ${UNIT_TITLE_MAX} characters and a body of at most ${UNIT_BODY_MAX}. One idea per unit. Leave it out when the main text says it all. Over a cap is refused by name (ask_too_long, too_many_units, unit_title_too_long, unit_body_too_long) and nothing is sent.`
1704
+ var units = z5.array(UnitInputSchema).optional().describe(
1705
+ `The context this message needs, as up to ${UNITS_MAX} units in reading order, each {title, body}: a title of at most ${UNIT_TITLE_MAX} characters and a body of at most ${UNIT_BODY_MAX}. One idea per unit: context they may open, never something they must hear. Leave it out when the main text says it all. Over a cap is refused by name (ask_too_long, too_many_units, unit_title_too_long, unit_body_too_long) and nothing is sent.`
1690
1706
  );
1691
- var UpdateInputSchema = z4.object({
1692
- message: z4.string().trim().min(1).describe(`The one point, at most ${ASK_MAX} characters; the context goes in units.`),
1693
- goalIds: z4.array(z4.string().uuid()).min(1).max(10).describe("The Goals it is about, each one that exists: the one it is mainly about first."),
1707
+ var KIND_IDS = { "handing": "none", "replaced-by": "goal", "blocked-by": "node", "asking": "none", "found": "none" };
1708
+ var KIND_GRAMMAR = "handing, replaced-by <goalId>, blocked-by <goalId|questionId>, asking, found";
1709
+ var uuid = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
1710
+ var handle = /^[0-9a-fA-F-]{8,36}$/;
1711
+ function refuseKind(u, ctx) {
1712
+ if (!u.kind) return;
1713
+ const refuse = (refusal, kind, message) => ctx.addIssue({ code: z5.ZodIssueCode.custom, path: ["kind"], params: { refusal, kind }, message });
1714
+ const [name, ...rest] = u.kind.trim().split(/\s+/);
1715
+ const shape = KIND_IDS[name];
1716
+ if (!shape) {
1717
+ refuse("kind_unknown", name, `kind_unknown: "${name}" is not a kind. One of: ${KIND_GRAMMAR}.`);
1718
+ return;
1719
+ }
1720
+ const id2 = rest.join(" ");
1721
+ if (shape === "none" && id2) {
1722
+ refuse("kind_takes_no_id", name, `kind_takes_no_id: "${name}" is the whole kind, so drop the "${id2}" after it.`);
1723
+ }
1724
+ if (shape !== "none" && !(shape === "goal" ? uuid.test(id2) : handle.test(id2))) {
1725
+ refuse("kind_needs_id", name, shape === "goal" ? `kind_needs_id: "${name}" names the Goal it is about, as "${name} <goalId>".` : `kind_needs_id: "${name}" names the Goal or Question it is about, as "${name} <goalId|questionId>".`);
1726
+ }
1727
+ if (name === "asking") {
1728
+ refuse("kind_is_a_question", name, 'kind_is_a_question: "asking" owes them an answer, so send it in `questions`, where it opens one.');
1729
+ }
1730
+ if (u.userExplicitlyRequested) {
1731
+ refuse("kind_not_for_the_person", name, `kind_not_for_the_person: "${name}" is written for the other agents on the Goal, and userExplicitlyRequested delivers these words to the person. Split it: one message for them, one for the agent.`);
1732
+ }
1733
+ }
1734
+ var UpdateInputSchema = z5.object({
1735
+ // ONE LOAD-BEARING POINT PER REPORT (owner, 2026-10-27 14:10 on call, Goal 1b1750e9, settling
1736
+ // #3633's pacing: "one point at a time is better, but make sure that it's [load-]bearing ... if
1737
+ // there is a lot of key points that I need to be aware of ... meaning something bad would happen
1738
+ // if I didn't know them or I wouldn't be able to understand something in the future ... They
1739
+ // should go separately. Basically, it should be like one load-bearing thing per report").
1740
+ //
1741
+ // The call's half of that ruling shipped in #3771: the talker settles an item only once the
1742
+ // transcript shows he heard its load-bearing point. This is the author's half, and without it the
1743
+ // talker has to guess which of a report's parts was load-bearing. Measured 2026-11-01 on prod:
1744
+ // 458 of 866 reports in 21 days carried two or more units, and since the pacing shipped on 10-23
1745
+ // only 18 of 72 units that reached a call were ever said -- so a point written as a unit has about
1746
+ // a one-in-four chance of being heard, and one ok after the headline settles the whole report.
1747
+ // Hence the wording, not a `mustHear` flag (the-heard-record.md P3): he asked for less mechanism
1748
+ // and more judgment from the agent, so a point he must not miss is simply its own report.
1749
+ message: z5.string().trim().min(1).describe(`The one point, at most ${ASK_MAX} characters: the one thing that would go wrong or stay unclear later if they missed it, said as what changed for them, in their words ("The screen reader speaks Spanish too", not "Merged #3896"). A second point like that is its own update; the rest goes in units.`),
1750
+ goalIds: z5.array(z5.string().uuid()).min(1).max(10).describe("The Goals it is about, each one that exists: the one it is mainly about first."),
1694
1751
  units,
1752
+ causedBy,
1753
+ shipped,
1695
1754
  // A REPORT KEEPS ITS TAP (#2799, #3260; owner, 2026-10-08, settling #2776: "keep the reports open
1696
1755
  // until the user acknowledges them"). A report asks nothing, so it opens no Question -- but it
1697
1756
  // still waits to be acknowledged, and it carries the ONE tap that closes it. Never a decision: the
@@ -1712,23 +1771,30 @@ var UpdateInputSchema = z4.object({
1712
1771
  // `options` and this field are one job: the list is deleted, not deprecated (ONE JOB, ONE
1713
1772
  // MECHANISM). It rides the door as the report's single stored option (`storedOption`,
1714
1773
  // `apps/api/src/goal/router.ts`), so no reader below the door learns a second shape.
1715
- reply: z4.string().trim().min(1).describe(
1774
+ reply: z5.string().trim().min(1).describe(
1716
1775
  `What this report's button says instead of "Got it", at most ${OPTION_LABEL_MAX} characters, written in THEIR voice for THIS report ("Sounds good, I'll test later") -- the care you give a question's options, so what they tap tells you whether they verified your work or only received it. One tap sends exactly these words back to you. Words that would CHANGE what happens next are a question, not a reply to a report: it still asks nothing and still owes you no answer. The reply is required for requested delivery and completed Goals; ordinary progress may omit it.`
1717
1776
  ).optional(),
1777
+ // THE KIND, WHICH WAS THE FIRST LINE OF THE MESSAGE UNTIL NOW (`KIND_IDS` above). Optional on
1778
+ // purpose: every agent writing updates today sends none, and a door that refused them would turn a
1779
+ // convention nobody was obliged to follow into a 400 on live traffic.
1780
+ kind: z5.string().trim().min(1).optional().describe(
1781
+ `What an agent writing on ANOTHER agent's Goal expects of its reader, as one token: ${KIND_GRAMMAR}. \`handing\` the work is yours now, nothing is asked; \`replaced-by <goalId>\` this Goal is dead and that one carries its work; \`blocked-by <goalId|questionId>\` I cannot go on until that moves, no action unless you own it; \`found\` evidence on your Goal, nothing is asked and nothing has changed. \`asking\` is a question, so it belongs in \`questions\`, not here. It is written for the other agents on the Goal, never the person, so it does not go with userExplicitlyRequested; leave it out for your own progress. Refused by name (kind_unknown, kind_needs_id, kind_takes_no_id, kind_is_a_question, kind_not_for_the_person).`
1782
+ ),
1718
1783
  userExplicitlyRequested
1719
1784
  }).strict().superRefine((u, ctx) => {
1720
1785
  if (u.userExplicitlyRequested && !u.reply) {
1721
1786
  ctx.addIssue({
1722
- code: z4.ZodIssueCode.custom,
1787
+ code: z5.ZodIssueCode.custom,
1723
1788
  path: ["reply"],
1724
1789
  params: { refusal: "reply_required" },
1725
1790
  message: "reply_required: an update requested for delivery needs one reply, written in the person\u2019s voice for this report."
1726
1791
  });
1727
1792
  }
1728
1793
  refuseOverCaps(u.message, u.units, "message", ctx);
1794
+ refuseKind(u, ctx);
1729
1795
  if (u.reply && u.reply.length > OPTION_LABEL_MAX) {
1730
1796
  ctx.addIssue({
1731
- code: z4.ZodIssueCode.custom,
1797
+ code: z5.ZodIssueCode.custom,
1732
1798
  path: ["reply"],
1733
1799
  params: { refusal: "reply_too_long", length: u.reply.length, cap: OPTION_LABEL_MAX },
1734
1800
  message: `reply_too_long: the reply is ${u.reply.length} characters; the cap is ${OPTION_LABEL_MAX}. It is a button's words, so say it in a breath.`
@@ -1736,83 +1802,114 @@ var UpdateInputSchema = z4.object({
1736
1802
  }
1737
1803
  });
1738
1804
  var questionFields = {
1739
- question: z4.string().trim().min(1).describe(
1805
+ question: z5.string().trim().min(1).describe(
1740
1806
  `ONE question, in at most ${ASK_MAX} characters, and only what is needed to answer it; the context goes in units. Several questions are several objects, one each: an answer settles the one question it was given, so a person who answers the part of a bundled question that interested them settles nothing and is asked again. Separate questions cost nothing: ANY contact for a person already on a call JOINS that call, so several arrive as one call.`
1741
1807
  ),
1742
- goalId: z4.string().uuid().describe("The Goal the question is about, which must exist (create it with manage_goals first). Its answer comes back there."),
1808
+ goalId: z5.string().uuid().describe("The Goal the question is about, which must exist (create it with manage_goals first). Its answer comes back there."),
1743
1809
  units,
1744
- options: z4.array(OptionInputSchema).min(1).max(6).optional().describe("The choices, when you have them. Each label stands on its own, at most 50 characters; a hint, at most 200. They can always answer in their own words, so no 'Other' or 'None of these'."),
1810
+ options: z5.array(OptionInputSchema).min(1).max(6).optional().describe("The choices, when you have them. Each label stands on its own and differs from the others (duplicate_option_label), at most 50 characters; a hint, at most 200. They can always answer in their own words, so no 'Other' or 'None of these'."),
1745
1811
  // HOW THE OPTIONS ARE ANSWERED, SAID BY THE AGENT (owner, 2026-10-02: "one and many makes sense";
1746
1812
  // brain_prompts.md §1: structured agent questions need no model). The app draws all three.
1747
- pickMode: z4.enum(["one", "many", "rank"]).optional().describe(
1748
- 'How the options are answered: "one" (the default) a pick, for alternatives; "many" a checklist, for independent options they may want several of; "rank" an order of all of them. Only with options.'
1813
+ pickMode: z5.enum(["one", "many", "rank"]).optional().describe(
1814
+ 'How the options are answered: "one" (the default) a pick, for alternatives; "many" a checklist, for independent options they may want several of; "rank" an order of all of them. Only with options; "many" and "rank" need at least two (too_few_options).'
1749
1815
  ),
1750
1816
  // WHAT THE QUESTION HOLDS UP (brain_prompts.md §2.1): replaces `waiting: 'hard'`. A question that
1751
1817
  // blocks work asks for a call (the person's settings and ring cooldowns still decide).
1752
- workItBlocks: z4.array(z4.object({ blocked: NodeRef, action: BlockedAction, reason: reason.optional() }).strict().refine(actionFits, ACTION_FITS)).min(1).max(10).optional().describe(
1818
+ workItBlocks: z5.array(z5.object({ blocked: NodeRef, action: BlockedAction, reason: reason.optional() }).strict().refine(actionFits, ACTION_FITS)).min(1).max(10).optional().describe(
1753
1819
  "The work that cannot go on until this is answered: a Goal's start or completion, or another Question's answer. Only for work truly blocked; it asks for a call. Leave it out for a question you can keep working around."
1754
1820
  ),
1755
1821
  userExplicitlyRequested
1756
1822
  };
1757
1823
  var refineQuestion = (q, ctx) => {
1758
1824
  refuseOverCaps(q.question, q.units, "question", ctx);
1759
- if (q.pickMode && !q.options) ctx.addIssue({ code: z4.ZodIssueCode.custom, path: ["pickMode"], message: "pickMode comes only with options" });
1825
+ if (q.pickMode && !q.options) ctx.addIssue({ code: z5.ZodIssueCode.custom, path: ["pickMode"], message: "pickMode comes only with options" });
1826
+ refuseThinOptions(q, ctx);
1760
1827
  const ids = (q.options ?? []).map((o) => o.id);
1761
1828
  if (ids.some((id2) => id2) && (ids.some((id2) => !id2) || new Set(ids).size !== ids.length)) {
1762
- ctx.addIssue({ code: z4.ZodIssueCode.custom, path: ["options"], message: "give every option a distinct id, or none" });
1829
+ ctx.addIssue({ code: z5.ZodIssueCode.custom, path: ["options"], message: "give every option a distinct id, or none" });
1763
1830
  }
1764
1831
  };
1765
- var QuestionInputSchema = z4.object({
1766
- questionId: z4.string().uuid().optional().describe("Optional: your own stable id for this question (a UUID), so a resend is the same question. Minted for you when omitted; the result returns it."),
1832
+ var MIN_LIST_OPTIONS = 2;
1833
+ function refuseThinOptions(q, ctx) {
1834
+ const options = q.options ?? [];
1835
+ if ((q.pickMode === "many" || q.pickMode === "rank") && options.length < MIN_LIST_OPTIONS) {
1836
+ ctx.addIssue({
1837
+ code: z5.ZodIssueCode.custom,
1838
+ path: ["options"],
1839
+ params: { refusal: "too_few_options", length: options.length, min: MIN_LIST_OPTIONS },
1840
+ message: `too_few_options: pickMode "${q.pickMode}" needs at least ${MIN_LIST_OPTIONS} options; this question has ${options.length}. Add the other choices, or leave pickMode out.`
1841
+ });
1842
+ }
1843
+ const seen = /* @__PURE__ */ new Map();
1844
+ options.forEach((o, index) => {
1845
+ const key2 = o.label.trim().toLowerCase();
1846
+ const first = seen.get(key2);
1847
+ if (first === void 0) {
1848
+ seen.set(key2, index);
1849
+ return;
1850
+ }
1851
+ ctx.addIssue({
1852
+ code: z5.ZodIssueCode.custom,
1853
+ path: ["options", index, "label"],
1854
+ params: { refusal: "duplicate_option_label", index, first },
1855
+ message: `duplicate_option_label: options[${index}] repeats the label of options[${first}]. Each option names a different choice.`
1856
+ });
1857
+ });
1858
+ }
1859
+ var QuestionInputSchema = z5.object({
1860
+ questionId: z5.string().uuid().optional().describe("Optional: your own stable id for this question (a UUID), so a resend is the same question. Minted for you when omitted; the result returns it."),
1767
1861
  ...questionFields
1768
1862
  }).strict().superRefine(refineQuestion);
1769
- var QuestionWireSchema = z4.object({ questionId: z4.string().uuid(), ...questionFields }).strict().superRefine(refineQuestion);
1770
- var AnswerInputSchema = z4.object({
1863
+ var QuestionWireSchema = z5.object({ questionId: z5.string().uuid(), ...questionFields }).strict().superRefine(refineQuestion);
1864
+ var AnswerInputSchema = z5.object({
1771
1865
  questionId: questionHandle.describe("The Question you answer: its id as the event or the conversation shows it (8 characters or whole)."),
1772
- answer: z4.object({
1773
- text: z4.string().trim().min(1).describe(`Your answer in your own words, at most ${ASK_MAX} characters; the context goes in units.`),
1774
- selectedOptionIds: z4.array(z4.string().trim().min(1)).min(1).max(6).optional().describe("The ids of the options you choose, when the Question offered options (in order, for a ranking).")
1866
+ answer: z5.object({
1867
+ text: z5.string().trim().min(1).describe(`Your answer in your own words, at most ${ASK_MAX} characters; the context goes in units.`),
1868
+ selectedOptionIds: z5.array(z5.string().trim().min(1)).min(1).max(6).optional().describe("The ids of the options you choose, when the Question offered options (in order, for a ranking).")
1775
1869
  }).strict(),
1776
1870
  units
1777
1871
  }).strict().superRefine((a, ctx) => refuseOverCaps(a.answer.text, a.units, "text", ctx));
1778
- var QuestionDependencySchema = z4.object({
1872
+ var QuestionDependencySchema = z5.object({
1779
1873
  questionId: questionHandle.describe("A Question you asked."),
1780
- change: z4.enum(["add", "remove"]),
1874
+ change: z5.enum(["add", "remove"]),
1781
1875
  blocked: NodeRef,
1782
1876
  action: BlockedAction,
1783
1877
  reason: reason.optional()
1784
1878
  }).strict().refine(actionFits, ACTION_FITS);
1785
1879
  var sendFields = {
1786
- completions: z4.array(CompletionSchema).min(1).max(20).optional().describe(
1880
+ completions: z5.array(CompletionSchema).min(1).max(20).optional().describe(
1787
1881
  "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
1882
  ),
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, 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."
1883
+ updates: z5.array(UpdateInputSchema).min(1).max(20).optional().describe(
1884
+ "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, with its `kind`.\n\nONE LOAD-BEARING POINT PER REPORT: the message is the point they must not miss; a second point that would go wrong or stay unclear later if they missed it is its own update, never a unit."
1791
1885
  ),
1792
- answers: z4.array(AnswerInputSchema).min(1).max(20).optional().describe("Answers to Questions addressed to you."),
1793
- withdrawQuestionIds: z4.array(questionHandle).min(1).max(10).optional().describe(
1886
+ answers: z5.array(AnswerInputSchema).min(1).max(20).optional().describe("Answers to Questions addressed to you."),
1887
+ withdrawQuestionIds: z5.array(questionHandle).min(1).max(10).optional().describe(
1794
1888
  "Questions you asked that no longer need an answer: you acted on them yourself, they no longer matter, or you asked wrongly. Each is cancelled, not answered: its card closes and nothing rings for it."
1795
1889
  ),
1796
- questionDependencies: z4.array(QuestionDependencySchema).min(1).max(20).optional().describe(
1890
+ bumpQuestionIds: z5.array(questionHandle).min(1).max(10).optional().describe(
1891
+ "Your own questions still waiting on the person that you want them to notice again. Each moves back to the top of its card with one new notification; nothing is resent and no second card is made."
1892
+ ),
1893
+ questionDependencies: z5.array(QuestionDependencySchema).min(1).max(20).optional().describe(
1797
1894
  "Add or remove what a Question you asked holds up, after asking it."
1798
1895
  )
1799
1896
  };
1800
- var ContactSchema = z4.object({
1897
+ var ContactSchema = z5.object({
1801
1898
  ...sendFields,
1802
- questions: z4.array(QuestionInputSchema).min(1).max(20).optional().describe("Questions for the person, one per object, each sent exactly as written, with no reading in between."),
1899
+ questions: z5.array(QuestionInputSchema).min(1).max(20).optional().describe("Questions for the person, one per object, each sent exactly as written, with no reading in between."),
1803
1900
  /** RECEIVING (2I, I2; brain_prompts.md §2.2): the events this agent handled. */
1804
- ackEventIds: z4.array(z4.string().uuid()).min(1).max(100).optional().describe(
1901
+ ackEventIds: z5.array(z5.string().uuid()).min(1).max(100).optional().describe(
1805
1902
  "The exact eventIds of the events you have handled: an acknowledgment (ACK). Reading alone acknowledges nothing, so an event comes back until you acknowledge it; after that the next batch can come. Each recipient acknowledges separately, for itself only. A Question you owe is answered (answers), never acknowledged away."
1806
1903
  ),
1807
- wait: z4.boolean().optional().describe(
1904
+ wait: z5.boolean().optional().describe(
1808
1905
  "Only controls when this returns. Sending: false (the default) returns at once; true waits up to about 45 seconds for a response to what you sent. Sending nothing: true (the default) waits up to about 45 seconds for anything addressed to you; false returns what is waiting now. It does not mean work is blocked, set urgency, or ask for a call. `waitOutcome` says which happened: `available`, `expired` (nothing arrived; wait again without sending again), or `not_waited`."
1809
1906
  )
1810
1907
  }).strict();
1811
- var sendsAnything = (c) => !!(c.completions?.length || c.updates?.length || c.questions?.length || c.answers?.length || c.withdrawQuestionIds?.length || c.questionDependencies?.length);
1812
- var ContactWireSchema = z4.object({
1813
- operationId: z4.string().uuid(),
1908
+ var sendsAnything = (c) => !!(c.completions?.length || c.updates?.length || c.questions?.length || c.answers?.length || c.withdrawQuestionIds?.length || c.bumpQuestionIds?.length || c.questionDependencies?.length);
1909
+ var ContactWireSchema = z5.object({
1910
+ operationId: z5.string().uuid(),
1814
1911
  ...sendFields,
1815
- questions: z4.array(QuestionWireSchema).min(1).max(20).optional()
1912
+ questions: z5.array(QuestionWireSchema).min(1).max(20).optional()
1816
1913
  }).strict().refine(sendsAnything, "a contact sends at least one update, question, answer, withdrawal or question dependency");
1817
1914
  var CONTACT_SCHEMA = { type: "object", ...mcpInputSchema(ContactSchema) };
1818
1915
  var CONTACT_DESCRIPTION = "Send to and receive from the person: completions, updates, questions, answers to questions addressed to you, withdrawals, and what a question holds up. Every Goal named must exist: an unknown one refuses the whole contact. Each item applies on its own: read `results`, where a failed one names why.\n\n" + ASKING_RULES + `
@@ -1822,13 +1919,42 @@ LENGTH: the question, message or answer is the one point, at most ${ASK_MAX} cha
1822
1919
  UPDATES ask nothing. One reaches the person only when they asked for it, it answers something they said, or its Goal is done; else it is kept as progress. One that reaches them joins an open report card or a live call.
1823
1920
 
1824
1921
  RECEIVING: contact({}) waits ~45 s; contact({wait:false}) returns \`events\` at once. Confirm the ones you handled with contact({ackEventIds}).`;
1825
- var CreateGoalSchema = z5.object({
1826
- outcome: z5.string().trim().min(1).max(1e4),
1922
+ var GUIDE = '# Paigy\n\nThe user is remote. Reach them only through Paigy\'s tools, never the terminal. The server\'s own instructions and each tool\'s description are the contract: read them. Every read ends in `next`, the one step to take.\n\nThis same guide is inside the MCP: the `help` tool (whole, or one `topic`) and the `/mcp__paigy__help` prompt. `/mcp__paigy__welcome` starts a session.\n\nHosted (no machine): skip Pairing and Listening; answers wake you.\n\n## Pairing\n\n- Call `configure` first. With a device credential on this machine it hatches you at once.\n- Otherwise print its `user_message` to the user, then do what the result says:\n - `awaiting_approval`: call `configure` again with its `device_code` in the same turn. On `pending`, call again.\n - `awaiting_confirmation`: end your turn with the code as your whole reply; call `configure` with the `device_code` next turn. Calling it in the same turn drops the code.\n- When it returns `enable_command`, print it for the user to run. Do not run it yourself.\n- `configure({ logOut: true })` logs out only this agent, and only when the user asks.\n\n## Listening\n\n- Call `listen` once per session.\n - `listening`: done.\n - `receiving`: a listener runs but cannot wake you. Do not start a second.\n - `unpaired`: call `configure`.\n - `start`: run its `command` exactly, now.\n- Claude Code: run it with the **Monitor** tool, never a background Bash command. Start it again whenever the monitor expires.\n- Codex: run its `command` as a long-running background process. It queues each answer into this thread (`CODEX_THREAD_ID`).\n- Grok: run it with the **monitor** tool, never a background shell command. Start it again whenever the monitor expires.\n- With no `listen` tool, run `npx -y -p @paigy/mcp@latest paigy-listen --brief` the same way.\n- One listener per session. A `paigy-listen` in `ps` belongs to another session; ask `listen`, never `ps`.\n- Each line it prints is work: receive, read the Goal, act.\n\n## Receiving\n\n- On startup and after every wake or listener line: `contact({ wait: false })`.\n- Events: `question` (you owe an answer: send `answers`), `update` (something new on your Goal: an answer, a reply, a review), `instruction` (work sent to you).\n- Read the Goal with `get_goals` before acting. An answer arrives as an `update` event and lands on the question\'s Goal. A question reading `replied` means they chose no option: settle it from their words.\n- Acknowledge each event you handled: `contact({ ackEventIds })`. Reading acknowledges nothing; events repeat until acknowledged. A `question` event is answered, never acknowledged away.\n- `contact({ wait: true })` waits about 45 s. On `expired`, wait again without re-sending, or stop. No while-loops: while any Call is open, keep receiving through empty windows; otherwise stop at one empty window.\n\n## Asking\n\n- One question per object in `questions`, at most 80 characters. Context goes in `units`: at most 12, title \u226450, body \u2264200, one idea each.\n- `goalId` names an existing Goal. Create it with `manage_goals` first.\n- Give options when you have them: up to 6, label \u226450 naming the choice in full, `hint` \u2264200 saying what it does. Never "Other" or "Option 2". `pickMode`: `one` (default), `many`, `rank`.\n- `workItBlocks` only when you are truly stopped: it asks for a call.\n- Read the Goal before asking. Never re-ask an open or answered question, or one whose work shipped.\n- Take back a question that no longer matters: `withdrawQuestionIds`.\n- An answer you give (`answers`) is at most 80 characters.\n\n## Updates and completions\n\n- An update (`updates`: `message` \u226480, `goalIds`) asks nothing. It reaches the user only when they asked for it, when it answers something they said, or when its Goal is done; otherwise it stays on the Goal as progress.\n- Updates never complete a Goal.\n- One load-bearing point per report: `message` is the point they must not miss, and a second point that would go wrong or stay unclear later if they missed it is its own update. `units` are context they may open, never something they must hear.\n- `reply` is the button in the user\'s voice instead of "Got it", \u226450 characters ("Sounds good, I\'ll test later"). Required (`reply_required`) when the update is delivered on request (`userExplicitlyRequested`) or any Goal it names is already done.\n- Set `userExplicitlyRequested` only to relay the user\'s own words: `"any"` for "send it to me", `"call"` for "call me". Never to make a message louder.\n- Finish with a completion (`contact.completions`, or `manage_goals` kind `complete`): `goalId`, `message` \u226450, `reply` \u226450, optional `units`, optional next-step `options` {label, hint}. It closes and reports in one step. Say only what your evidence supports.\n- Read `results`: each item applies on its own, and a failed one names why.\n\n## Goals\n\n- `manage_goals` `changes`, applied in order:\n - `create`: `title` (1-5 words) and `outcome` (one paragraph, \u2264500). More work is child Goals: `parentGoalId`. New ids come back in `results[i].goalId`.\n - `assign`: `ownerId`, a participant as `check_activity` shows it.\n - `defer`: `until`. You are woken when it passes. This is how you follow up later.\n - `dependency`: `add`/`remove`; `goalId` waits on `dependsOnGoalId` to `start` or `complete`.\n - `edit`, `move`, `state` (open, completed, canceled).\n- Any open question on a Goal, anyone\'s, blocks its completion (`goal_blocked`). Before completing, withdraw yours, finish or move its required children, and clear its dependencies.\n- On `goal_revision_conflict`, read the Goal again and reconsider.\n- Before overlapping work, read `check_activity` and the Goal\'s other contributors. Every Goal of your person is open to you; your first write puts you on it.\n- `search` finds earlier words, Goals and answers. Nothing found is not proof of absence.\n\n## Calls\n\n- Call only when the user asked: `userExplicitlyRequested: "call"` on that item. A question with `workItBlocks` may ring too.\n- Any contact while the user is on a call joins that call (`joinedCall` in `results`). Several questions arrive as one call.\n- While any Call is open, keep receiving.\n- An open Call Delivery is not proof it rang. `get_delivery` reads a Call\'s state, and with `transcript: true` what was said.\n';
1923
+ var HELP_TOPICS = ["pairing", "listening", "receiving", "asking", "updates", "goals", "calls"];
1924
+ var unknownTopic = (topic) => `unknown_topic: ${JSON.stringify(topic)} is not a section of the guide. Topics: ${HELP_TOPICS.join(", ")}; or omit topic for the whole guide.`;
1925
+ var HelpSchema = z6.object({
1926
+ topic: z6.enum(HELP_TOPICS, { errorMap: (_issue, ctx) => ({ message: unknownTopic(ctx.data) }) }).optional().describe("One section of the guide. Omit it for the whole guide.")
1927
+ }).strict();
1928
+ var HELP_DESCRIPTION = "Start here: how to use Paigy, in full \u2014 pairing, listening, receiving, asking, updates and completions, Goals and calls. Pass a topic for one section. Read-only; needs no setup.";
1929
+ function section(topic) {
1930
+ const parts = GUIDE.split(/^(?=## )/m);
1931
+ const found = parts.find((p) => p.slice(3).toLowerCase().startsWith(topic));
1932
+ if (!found) throw new Error(`help_section_missing: the guide has no "## ${topic}" section`);
1933
+ return found.trim() + "\n";
1934
+ }
1935
+ function helpView({ topic }) {
1936
+ return {
1937
+ topic: topic ?? "all",
1938
+ guide: topic ? section(topic) : GUIDE,
1939
+ topics: [...HELP_TOPICS],
1940
+ next: "Not set up? Call configure. Then contact({wait:false}) for the work addressed to you."
1941
+ };
1942
+ }
1943
+ var AGENT_PROMPTS = [
1944
+ {
1945
+ name: "help",
1946
+ description: "How to use Paigy: the whole guide, or one topic of it.",
1947
+ arguments: [{ name: "topic", description: `One section: ${HELP_TOPICS.join(", ")}. Omit it for the whole guide.`, required: false }]
1948
+ },
1949
+ { name: "welcome", description: "Start here: who you are on Paigy, then listen and collect your open work." }
1950
+ ];
1951
+ var CreateGoalSchema = z7.object({
1952
+ outcome: z7.string().trim().min(1).max(1e4),
1827
1953
  /** The work's NAME (#2115) — one to five words, how a person refers to it out loud ("the night
1828
1954
  * rings"). Omit it and the brain writes one at admission from the outcome. */
1829
- title: z5.string().trim().min(1).max(80).optional(),
1830
- ownerParticipant: z5.string().trim().min(1).optional(),
1831
- idempotencyKey: z5.string().trim().min(1).max(200),
1955
+ title: z7.string().trim().min(1).max(80).optional(),
1956
+ ownerParticipant: z7.string().trim().min(1).optional(),
1957
+ idempotencyKey: z7.string().trim().min(1).max(200),
1832
1958
  /** THE GOAL THIS ONE BELONGS UNDER (owner, 2026-09-15: "the ask I gave for the design doc
1833
1959
  * didn't get created as a child goal of the voice UI goal, which is how it should've
1834
1960
  * worked"). It could not have been: this door took no parent, so the only route was
@@ -1836,63 +1962,63 @@ var CreateGoalSchema = z5.object({
1836
1962
  * took the short one. The hierarchy has been modelled since Goals existed and had been used
1837
1963
  * ZERO times in 2,031 of them. Absent, the server judges it against the caller's open Goals
1838
1964
  * (`apps/api/src/goal/intake.ts`). The writer refuses a Goal belonging to another account. */
1839
- parentGoalId: z5.string().uuid().optional(),
1965
+ parentGoalId: z7.string().uuid().optional(),
1840
1966
  /** The repository or project identifier this Goal belongs to (#2280) — e.g. "owner/repo" or
1841
1967
  * repo name. Delegated work inherits this from its parent Goal when omitted. */
1842
- repo: z5.string().trim().min(1).max(200).optional()
1968
+ repo: z7.string().trim().min(1).max(200).optional()
1843
1969
  });
1844
- var UpdateGoalSchema = z5.object({
1845
- revision: z5.number().int().positive(),
1846
- changes: z5.object({
1847
- outcome: z5.string().trim().min(1).max(1e4).optional(),
1970
+ var UpdateGoalSchema = z7.object({
1971
+ revision: z7.number().int().positive(),
1972
+ changes: z7.object({
1973
+ outcome: z7.string().trim().min(1).max(1e4).optional(),
1848
1974
  /** The work's NAME (#2115) — one to five words, how a person refers to it out loud. The
1849
1975
  * brain writes one at admission; this is the owner saying it better. Null clears it. */
1850
- title: z5.string().trim().min(1).max(80).nullable().optional(),
1851
- ownerParticipant: z5.string().trim().min(1).optional(),
1852
- parentGoalId: z5.string().uuid().nullable().optional(),
1853
- dependencies: z5.array(z5.object({ goalId: z5.string().uuid(), gate: z5.enum(["start", "finish"]) }).strict()).optional(),
1854
- children: z5.array(z5.object({ outcome: z5.string().trim().min(1).max(1e4), ownerParticipant: z5.string().trim().min(1), gate: z5.enum(["start", "finish"]).optional() }).strict()).optional(),
1855
- state: z5.enum(["active", "done", "cancelled"]).optional(),
1856
- progress: z5.string().trim().min(1).max(1e4).optional(),
1857
- reviewed: z5.literal(true).optional(),
1858
- dueAt: z5.string().datetime({ offset: true }).nullable().optional()
1976
+ title: z7.string().trim().min(1).max(80).nullable().optional(),
1977
+ ownerParticipant: z7.string().trim().min(1).optional(),
1978
+ parentGoalId: z7.string().uuid().nullable().optional(),
1979
+ dependencies: z7.array(z7.object({ goalId: z7.string().uuid(), gate: z7.enum(["start", "finish"]) }).strict()).optional(),
1980
+ children: z7.array(z7.object({ outcome: z7.string().trim().min(1).max(1e4), ownerParticipant: z7.string().trim().min(1), gate: z7.enum(["start", "finish"]).optional() }).strict()).optional(),
1981
+ state: z7.enum(["active", "done", "cancelled"]).optional(),
1982
+ progress: z7.string().trim().min(1).max(1e4).optional(),
1983
+ reviewed: z7.literal(true).optional(),
1984
+ dueAt: z7.string().datetime({ offset: true }).nullable().optional()
1859
1985
  }).strict().refine((v) => Object.keys(v).length > 0),
1860
- reason: z5.string().trim().min(1).max(2e3),
1861
- operationId: z5.string().uuid().optional()
1986
+ reason: z7.string().trim().min(1).max(2e3),
1987
+ operationId: z7.string().uuid().optional()
1862
1988
  }).strict();
1863
- var changedGoal = z5.string().uuid().describe("The Goal to change, as a read shows it.");
1864
- var goalTitle = z5.string().trim().min(1).max(80).describe("The Goal's short display name: one to five words, how a person refers to it out loud.");
1989
+ var changedGoal = z7.string().uuid().describe("The Goal to change, as a read shows it.");
1990
+ var goalTitle = z7.string().trim().min(1).max(80).describe("The Goal's short display name: one to five words, how a person refers to it out loud.");
1865
1991
  var GOAL_OUTCOME_MAX = 500;
1866
- var goalOutcome = z5.string().trim().min(1).max(GOAL_OUTCOME_MAX, `outcome_too_long: a Goal's outcome is one paragraph, at most ${GOAL_OUTCOME_MAX} characters; split the rest into child Goals (create with parentGoalId).`).describe(`The desired result, one paragraph of at most ${GOAL_OUTCOME_MAX} characters. More than that is more work: create child Goals under it (parentGoalId). There is no third description field.`);
1867
- var CreateChange = z5.object({
1868
- kind: z5.literal("create"),
1992
+ var goalOutcome = z7.string().trim().min(1).max(GOAL_OUTCOME_MAX, `outcome_too_long: a Goal's outcome is one paragraph, at most ${GOAL_OUTCOME_MAX} characters; split the rest into child Goals (create with parentGoalId).`).describe(`The desired result, one paragraph of at most ${GOAL_OUTCOME_MAX} characters. More than that is more work: create child Goals under it (parentGoalId). There is no third description field.`);
1993
+ var CreateChange = z7.object({
1994
+ kind: z7.literal("create"),
1869
1995
  title: goalTitle,
1870
1996
  outcome: goalOutcome,
1871
- ownerId: z5.string().trim().min(1).optional().describe("Who owns the work: an agent's participant (as check_activity shows it) or the person's. Omitted: you."),
1872
- parentGoalId: z5.string().uuid().optional().describe("The Goal it belongs under. Omitted: a root."),
1873
- sourceEntryIds: z5.array(z5.string().uuid()).max(20).optional().describe("The whole Entries the work came from, ones you can read.")
1997
+ ownerId: z7.string().trim().min(1).optional().describe("Who owns the work: an agent's participant (as check_activity shows it) or the person's. Omitted: you."),
1998
+ parentGoalId: z7.string().uuid().optional().describe("The Goal it belongs under. Omitted: a root."),
1999
+ sourceEntryIds: z7.array(z7.string().uuid()).max(20).optional().describe("The whole Entries the work came from, ones you can read.")
1874
2000
  }).strict();
1875
- var EditChange = z5.object({ kind: z5.literal("edit"), goalId: changedGoal, title: goalTitle.optional(), outcome: goalOutcome.optional() }).strict();
1876
- var StateChange = z5.object({ kind: z5.literal("state"), goalId: changedGoal, state: z5.enum(["open", "completed", "canceled"]).describe(
2001
+ var EditChange = z7.object({ kind: z7.literal("edit"), goalId: changedGoal, title: goalTitle.optional(), outcome: goalOutcome.optional() }).strict();
2002
+ var StateChange = z7.object({ kind: z7.literal("state"), goalId: changedGoal, state: z7.enum(["open", "completed", "canceled"]).describe(
1877
2003
  "completed: the Goal's own work is done now (refused while required children are open); open: reopen it; canceled: it will not be done."
1878
2004
  ) }).strict();
1879
- var AssignChange = z5.object({ kind: z5.literal("assign"), goalId: changedGoal, ownerId: z5.string().trim().min(1).describe("The new owner's participant.") }).strict();
1880
- var DeferChange = z5.object({ kind: z5.literal("defer"), goalId: changedGoal, until: z5.string().datetime({ offset: true }).nullable().describe(
2005
+ var AssignChange = z7.object({ kind: z7.literal("assign"), goalId: changedGoal, ownerId: z7.string().trim().min(1).describe("The new owner's participant.") }).strict();
2006
+ var DeferChange = z7.object({ kind: z7.literal("defer"), goalId: changedGoal, until: z7.string().datetime({ offset: true }).nullable().describe(
1881
2007
  "Postpone it until this instant: it waits until then, and its owner is woken when it passes (a promise to follow up later). null takes the postponement back."
1882
2008
  ) }).strict();
1883
- var MoveChange = z5.object({ kind: z5.literal("move"), goalId: changedGoal, parentGoalId: z5.string().uuid().nullable().describe(
2009
+ var MoveChange = z7.object({ kind: z7.literal("move"), goalId: changedGoal, parentGoalId: z7.string().uuid().nullable().describe(
1884
2010
  "Its new parent, or null for a root. Only this Goal moves; its new parent's other children stay."
1885
2011
  ) }).strict();
1886
- var DependencyChange = z5.object({
1887
- kind: z5.literal("dependency"),
1888
- change: z5.enum(["add", "remove"]),
2012
+ var DependencyChange = z7.object({
2013
+ kind: z7.literal("dependency"),
2014
+ change: z7.enum(["add", "remove"]),
1889
2015
  goalId: changedGoal,
1890
- dependsOnGoalId: z5.string().uuid().describe("The Goal it waits on."),
1891
- action: z5.enum(["start", "complete"]).describe("What waits: starting goalId, or completing it."),
1892
- reason: z5.string().trim().min(1).max(250).optional().describe("Why, at most 250 characters, as an explanation, never as policy.")
2016
+ dependsOnGoalId: z7.string().uuid().describe("The Goal it waits on."),
2017
+ action: z7.enum(["start", "complete"]).describe("What waits: starting goalId, or completing it."),
2018
+ reason: z7.string().trim().min(1).max(250).optional().describe("Why, at most 250 characters, as an explanation, never as policy.")
1893
2019
  }).strict();
1894
- var read = { revision: z5.number().int().positive().optional() };
1895
- var GoalChangeSchema = z5.discriminatedUnion("kind", [
2020
+ var read = { revision: z7.number().int().positive().optional() };
2021
+ var GoalChangeSchema = z7.discriminatedUnion("kind", [
1896
2022
  CreateChange,
1897
2023
  CompleteChangeSchema.extend(read),
1898
2024
  EditChange.extend(read),
@@ -1904,216 +2030,220 @@ var GoalChangeSchema = z5.discriminatedUnion("kind", [
1904
2030
  ]);
1905
2031
  var editNames = (changes, ctx) => changes.forEach((c, i) => {
1906
2032
  if (c.kind === "edit" && c.title === void 0 && c.outcome === void 0) {
1907
- ctx.addIssue({ code: z5.ZodIssueCode.custom, path: ["changes", i], message: "an edit supplies title, outcome, or both" });
2033
+ ctx.addIssue({ code: z7.ZodIssueCode.custom, path: ["changes", i], message: "an edit supplies title, outcome, or both" });
1908
2034
  }
1909
2035
  });
1910
- var ManageGoalsSchema = z5.object({
1911
- requestId: z5.string().uuid().optional(),
1912
- changes: z5.array(GoalChangeSchema).min(1).max(50)
2036
+ var ManageGoalsSchema = z7.object({
2037
+ requestId: z7.string().uuid().optional(),
2038
+ changes: z7.array(GoalChangeSchema).min(1).max(50)
1913
2039
  }).strict().superRefine((v, ctx) => editNames(v.changes, ctx));
1914
- var ManageGoalsToolSchema = z5.object({
1915
- changes: z5.array(z5.discriminatedUnion("kind", [CreateChange, CompleteChangeSchema, EditChange, StateChange, AssignChange, DeferChange, MoveChange, DependencyChange])).min(1).max(50).describe("The changes, applied in order, each on its own.")
2040
+ var ManageGoalsToolSchema = z7.object({
2041
+ changes: z7.array(z7.discriminatedUnion("kind", [CreateChange, CompleteChangeSchema, EditChange, StateChange, AssignChange, DeferChange, MoveChange, DependencyChange])).min(1).max(50).describe("The changes, applied in order, each on its own.")
1916
2042
  }).strict().superRefine((v, ctx) => editNames(v.changes, ctx));
1917
2043
  var MANAGE_GOALS_DESCRIPTION = "Create, edit, assign, organize or close work. Every change here changes Goals; answering, withdrawing or asking Questions stays in contact. Each change applies independently: a refused one names why (`results[i].error`, e.g. goal_revision_conflict, goal_children_open, goal_not_found) and the rest still apply, so read every result: a partial result is never a complete success. Kinds: complete (goalId, message capped at 50 characters, units, reply, optional next-step options {label, hint}) closes and reports atomically, exactly as contact.completions; create (title, outcome, ownerId, parentGoalId, sourceEntryIds) returns the new Goal's id in `results[i].goalId`, in the order requested, to use in later calls (an outcome is one paragraph, at most 500 characters: split more into child Goals with parentGoalId); edit (title and/or outcome); state (open, completed, canceled); assign (ownerId); defer (until: the Goal waits until then and its owner is woken when it passes; null takes it back); move (parentGoalId, or null for a root: only this Goal moves); dependency (add or remove: goalId waits on dependsOnGoalId to start or to complete). A Goal cannot be completed while its required children or dependencies remain open: finish or move them first. Finishing the children does not prove the parent's own work is done. An edit applies at the version you last read: if someone changed the Goal since, it is refused as goal_revision_conflict, so read it again (get_goals) and reconsider. You may change any Goal of your person; a change puts you on it. Returns `ok` (every change applied), `results` per change (applied or failed), and `goals`, each changed Goal's id, state, title, outcome and revision.";
1918
- var GetGoalsSchema = z5.object({
1919
- goalIds: z5.array(z5.string().uuid()).min(1).max(10).describe("The Goals to read, in order; one to ten IDs."),
2044
+ var GetGoalsSchema = z7.object({
2045
+ goalIds: z7.array(z7.string().uuid()).min(1).max(10).describe("The Goals to read, in order; one to ten IDs."),
1920
2046
  /** Every entry in full. Without it the read carries the person's words, open questions and your
1921
2047
  * newest entry, and counts what it left out (`apps/api/src/goal/collapse.ts`). */
1922
- history: z5.boolean().optional()
2048
+ history: z7.boolean().optional()
1923
2049
  }).strict();
1924
- var GetDeliverySchema = z5.object({
1925
- deliveryId: z5.string().uuid().describe("The Delivery id returned by contact or receive."),
2050
+ var GetDeliverySchema = z7.object({
2051
+ deliveryId: z7.string().uuid().describe("The Delivery id returned by contact or receive."),
1926
2052
  // 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.")
2053
+ transcript: z7.boolean().optional().describe("For a Call: also return what was said on it, one page of spoken lines."),
2054
+ after: z7.string().max(40).optional().describe("With transcript: the next value the previous page returned, to read the next page.")
1929
2055
  }).strict();
1930
2056
  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.";
1931
2057
  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.";
1932
- var SearchToolSchema = z5.object({
1933
- query: z5.string().trim().min(1).max(500),
1934
- types: z5.array(z5.enum(["entry", "goal", "answer"])).min(1).optional(),
1935
- goalId: z5.string().uuid().optional(),
1936
- limit: z5.number().int().min(1).max(20).optional()
2058
+ var SearchToolSchema = z7.object({
2059
+ query: z7.string().trim().min(1).max(500),
2060
+ types: z7.array(z7.enum(["entry", "goal", "answer"])).min(1).optional(),
2061
+ goalId: z7.string().uuid().optional(),
2062
+ limit: z7.number().int().min(1).max(20).optional()
1937
2063
  }).strict();
1938
2064
  var SEARCH_DESCRIPTION = "Search your person's history across all of their agents: Entries (what anyone said or wrote, typed or spoken on a call), Goals (by title and outcome) and replies -- the person's answers, acknowledgements and deferrals (type answer; found by their summary, by the question or report they reply to, or by the words that gave them). query is words to look for; records sharing more of its words rank first, and exact names work. types narrows it to entry, goal and/or answer (default: all three). goalId searches under one Goal: its Entries, the replies to its items, and it and its immediate children. limit is matches per type, 1 to 20 (default 8). Read-only. Each match carries its whole saved words, its ID and its links (a reply carries its kind -- answered, acknowledged or deferred -- whether it is closed (a deferral is not), its summary in under ten words, its question or report, the choice made and the Entries that support it); `omitted` counts what matched but was left out, so narrow the words or add a goalId to see it. Nothing found is not proof that nothing exists; a refused search says why. Sealed (encrypted) content is never searched or returned.";
1939
- var ConfigureIdentitySchema = z5.object({}).strict();
2065
+ var READS = { readOnlyHint: true, destructiveHint: false, openWorldHint: false };
2066
+ var SENDS = { readOnlyHint: false, destructiveHint: true, openWorldHint: false };
2067
+ var ConfigureIdentitySchema = z7.object({}).strict();
1940
2068
  var CONFIGURE_IDENTITY_DESCRIPTION = "Read this authenticated agent\u2019s current name, voice and token ID. Read-only; no arguments. Pairing, renaming and logout are available only through the local configure driver.";
1941
- var CheckActivitySchema = z5.object({}).strict();
2069
+ var CheckActivitySchema = z7.object({}).strict();
1942
2070
  var FEEDBACK_TEXT_MAX = 5e4;
1943
- var SendFeedbackSchema = z5.object({
1944
- text: z5.string().trim().min(1).max(FEEDBACK_TEXT_MAX).describe(`The report, in markdown: what happened, what was expected, how to reproduce it, versions, evidence. At most ${FEEDBACK_TEXT_MAX} characters.`),
1945
- title: z5.string().trim().min(1).max(200).optional().describe("One line naming it."),
1946
- kind: z5.enum(["bug", "idea", "other"]).default("other").describe("bug: something Paigy does wrong. idea: something it should do. other: anything else.")
2071
+ var SendFeedbackSchema = z7.object({
2072
+ text: z7.string().trim().min(1).max(FEEDBACK_TEXT_MAX).describe(`The report, in markdown: what happened, what was expected, how to reproduce it, versions, evidence. At most ${FEEDBACK_TEXT_MAX} characters.`),
2073
+ title: z7.string().trim().min(1).max(200).optional().describe("One line naming it."),
2074
+ kind: z7.enum(["bug", "idea", "other"]).default("other").describe("bug: something Paigy does wrong. idea: something it should do. other: anything else.")
1947
2075
  }).strict();
1948
2076
  var SEND_FEEDBACK_DESCRIPTION = "Send feedback about Paigy itself (a bug report, an idea) straight to the Paigy team. Send it only when the person asked you to, or agreed when you offered: it goes to Paigy, never to the person, and nobody answers it here. Not for your work or a question for the person: use contact for those. Returns whether it was stored.";
1949
2077
  var AGENT_TOOLS = [
1950
- { name: "configure", description: CONFIGURE_IDENTITY_DESCRIPTION, inputSchema: mcpInputSchema(ConfigureIdentitySchema) },
1951
- { name: "contact", description: CONTACT_DESCRIPTION, inputSchema: CONTACT_SCHEMA },
1952
- { name: "manage_goals", description: MANAGE_GOALS_DESCRIPTION, inputSchema: mcpInputSchema(ManageGoalsToolSchema) },
1953
- { name: "get_delivery", description: GET_DELIVERY_DESCRIPTION, inputSchema: mcpInputSchema(GetDeliverySchema) },
1954
- { name: "get_goals", description: GET_GOALS_DESCRIPTION, inputSchema: mcpInputSchema(GetGoalsSchema) },
1955
- { name: "search", description: SEARCH_DESCRIPTION, inputSchema: mcpInputSchema(SearchToolSchema) },
1956
- { name: "check_activity", description: "Read your person's agents that contributed in the last 24 hours, newest first: at most 30 agents and their five most recently touched Goals, with their latest entry headline and time. Use get_goals to read a Goal and its other contributors before starting overlapping work. Read-only; no arguments.", inputSchema: mcpInputSchema(CheckActivitySchema) },
1957
- { name: "send_feedback", description: SEND_FEEDBACK_DESCRIPTION, inputSchema: mcpInputSchema(SendFeedbackSchema) }
2078
+ { name: "configure", title: "Who am I", annotations: READS, description: CONFIGURE_IDENTITY_DESCRIPTION, inputSchema: mcpInputSchema(ConfigureIdentitySchema) },
2079
+ { name: "contact", title: "Contact the person", annotations: SENDS, description: CONTACT_DESCRIPTION, inputSchema: CONTACT_SCHEMA },
2080
+ { name: "manage_goals", title: "Manage Goals", annotations: SENDS, description: MANAGE_GOALS_DESCRIPTION, inputSchema: mcpInputSchema(ManageGoalsToolSchema) },
2081
+ { name: "get_delivery", title: "Read a delivery", annotations: READS, description: GET_DELIVERY_DESCRIPTION, inputSchema: mcpInputSchema(GetDeliverySchema) },
2082
+ { name: "get_goals", title: "Read Goals", annotations: READS, description: GET_GOALS_DESCRIPTION, inputSchema: mcpInputSchema(GetGoalsSchema) },
2083
+ { name: "search", title: "Search history", annotations: READS, description: SEARCH_DESCRIPTION, inputSchema: mcpInputSchema(SearchToolSchema) },
2084
+ { name: "check_activity", title: "Recent agent activity", annotations: READS, description: "Read your person's agents that contributed in the last 24 hours, newest first: at most 30 agents and their five most recently touched Goals, with their latest entry headline and time. Use get_goals to read a Goal and its other contributors before starting overlapping work. Read-only; no arguments.", inputSchema: mcpInputSchema(CheckActivitySchema) },
2085
+ { name: "send_feedback", title: "Send feedback to Paigy", annotations: SENDS, description: SEND_FEEDBACK_DESCRIPTION, inputSchema: mcpInputSchema(SendFeedbackSchema) },
2086
+ // THE GUIDE FROM INSIDE THE MCP (owner, 2026-10-27): the skill's text, needing no identity (`help.ts`).
2087
+ { name: "help", title: "Paigy guide", annotations: READS, description: HELP_DESCRIPTION, inputSchema: mcpInputSchema(HelpSchema) }
1958
2088
  ];
1959
2089
  var AGENT_TOOL_NAMES = AGENT_TOOLS.map((t) => t.name);
1960
- var id = z6.string().uuid();
1961
- var key = z6.string().min(1).max(40);
1962
- var participant = z6.string().regex(/^(human|agent):.+$/, "a participant ID such as agent:<uuid>");
1963
- var SourceSchema = z6.object({ entryId: id }).strict();
1964
- var ResultRefSchema = z6.union([z6.object({ id }).strict(), z6.object({ local: key }).strict()]);
1965
- var NodeRefSchema = z6.object({ type: z6.enum(["goal", "question"]), id }).strict();
1966
- var DependencySchema = z6.object({
2090
+ var id = z8.string().uuid();
2091
+ var key = z8.string().min(1).max(40);
2092
+ var participant = z8.string().regex(/^(human|agent):.+$/, "a participant ID such as agent:<uuid>");
2093
+ var SourceSchema = z8.object({ entryId: id }).strict();
2094
+ var ResultRefSchema = z8.union([z8.object({ id }).strict(), z8.object({ local: key }).strict()]);
2095
+ var NodeRefSchema = z8.object({ type: z8.enum(["goal", "question"]), id }).strict();
2096
+ var DependencySchema = z8.object({
1967
2097
  blocker: NodeRefSchema,
1968
2098
  blocked: NodeRefSchema,
1969
- action: z6.enum(["start", "complete", "answer"]),
1970
- reason: z6.string().max(500).optional()
2099
+ action: z8.enum(["start", "complete", "answer"]),
2100
+ reason: z8.string().max(500).optional()
1971
2101
  }).strict();
1972
- var goalState = z6.enum(["open", "completed", "canceled"]);
2102
+ var goalState = z8.enum(["open", "completed", "canceled"]);
1973
2103
  var existingGoalChanges = [
1974
- z6.object({ kind: z6.literal("edit"), goalId: id, title: z6.string().min(1).max(120).optional(), outcome: z6.string().min(1).optional() }).strict().refine((c) => c.title !== void 0 || c.outcome !== void 0, "an edit changes the title or the outcome"),
1975
- z6.object({ kind: z6.literal("state"), goalId: id, state: goalState }).strict(),
1976
- z6.object({ kind: z6.literal("assign"), goalId: id, ownerId: participant }).strict(),
1977
- z6.object({ kind: z6.literal("defer"), goalId: id, until: z6.string().datetime().nullable() }).strict(),
1978
- z6.object({ kind: z6.literal("move"), goalId: id, parentGoalId: id.nullable() }).strict(),
1979
- z6.object({
1980
- kind: z6.literal("dependency"),
1981
- change: z6.enum(["add", "remove"]),
2104
+ z8.object({ kind: z8.literal("edit"), goalId: id, title: z8.string().min(1).max(120).optional(), outcome: z8.string().min(1).optional() }).strict().refine((c) => c.title !== void 0 || c.outcome !== void 0, "an edit changes the title or the outcome"),
2105
+ z8.object({ kind: z8.literal("state"), goalId: id, state: goalState }).strict(),
2106
+ z8.object({ kind: z8.literal("assign"), goalId: id, ownerId: participant }).strict(),
2107
+ z8.object({ kind: z8.literal("defer"), goalId: id, until: z8.string().datetime().nullable() }).strict(),
2108
+ z8.object({ kind: z8.literal("move"), goalId: id, parentGoalId: id.nullable() }).strict(),
2109
+ z8.object({
2110
+ kind: z8.literal("dependency"),
2111
+ change: z8.enum(["add", "remove"]),
1982
2112
  goalId: id,
1983
2113
  dependsOnGoalId: id,
1984
- action: z6.enum(["start", "complete"]),
1985
- reason: z6.string().max(500).optional()
2114
+ action: z8.enum(["start", "complete"]),
2115
+ reason: z8.string().max(500).optional()
1986
2116
  }).strict()
1987
2117
  ];
1988
- var BrainGoalChangeSchema = z6.union([
2118
+ var BrainGoalChangeSchema = z8.union([
1989
2119
  // newSession: Paigy starts a session to own it (owner, 2026-10-06); until it has, the person owns it.
1990
- z6.object({
1991
- kind: z6.literal("create"),
1992
- outcome: z6.string().min(1),
1993
- title: z6.string().min(1).max(120),
2120
+ z8.object({
2121
+ kind: z8.literal("create"),
2122
+ outcome: z8.string().min(1),
2123
+ title: z8.string().min(1).max(120),
1994
2124
  ownerId: participant,
1995
2125
  parentGoal: ResultRefSchema.nullable(),
1996
- newSession: z6.literal(true).optional()
2126
+ newSession: z8.literal(true).optional()
1997
2127
  }).strict(),
1998
2128
  ...existingGoalChanges
1999
2129
  ]);
2000
- var option = z6.object({ id: z6.string().min(1).max(40), label: z6.string().min(1), hint: z6.string().optional() }).strict();
2001
- var QuestionChangeSchema = z6.union([
2002
- z6.object({
2003
- kind: z6.literal("create"),
2004
- text: z6.string().min(1),
2005
- summary: z6.string().optional(),
2130
+ var option = z8.object({ id: z8.string().min(1).max(40), label: z8.string().min(1), hint: z8.string().optional() }).strict();
2131
+ var QuestionChangeSchema = z8.union([
2132
+ z8.object({
2133
+ kind: z8.literal("create"),
2134
+ text: z8.string().min(1),
2135
+ summary: z8.string().optional(),
2006
2136
  answererId: participant,
2007
2137
  goal: ResultRefSchema.optional(),
2008
- blocks: z6.array(z6.object({ question: ResultRefSchema }).strict()),
2009
- options: z6.array(option).min(2).optional(),
2010
- pickMode: z6.enum(["one", "many", "rank"]).optional()
2138
+ blocks: z8.array(z8.object({ question: ResultRefSchema }).strict()),
2139
+ options: z8.array(option).min(2).optional(),
2140
+ pickMode: z8.enum(["one", "many", "rank"]).optional()
2011
2141
  }).strict().refine((c) => c.options === void 0 === (c.pickMode === void 0), "options and pickMode come together"),
2012
- z6.object({ kind: z6.literal("edit"), questionId: id, text: z6.string().min(1) }).strict(),
2013
- z6.object({ kind: z6.literal("assign"), questionId: id, answererId: participant }).strict(),
2014
- z6.object({ kind: z6.literal("withdraw"), questionId: id }).strict(),
2015
- z6.object({ kind: z6.literal("dependency"), change: z6.enum(["add", "remove"]), edge: DependencySchema }).strict()
2142
+ z8.object({ kind: z8.literal("edit"), questionId: id, text: z8.string().min(1) }).strict(),
2143
+ z8.object({ kind: z8.literal("assign"), questionId: id, answererId: participant }).strict(),
2144
+ z8.object({ kind: z8.literal("withdraw"), questionId: id }).strict(),
2145
+ z8.object({ kind: z8.literal("dependency"), change: z8.enum(["add", "remove"]), edge: DependencySchema }).strict()
2016
2146
  ]);
2017
- var lessonScope = z6.union([
2018
- z6.object({ kind: z6.literal("user") }).strict(),
2019
- z6.object({ kind: z6.literal("goal"), goal: ResultRefSchema }).strict()
2147
+ var lessonScope = z8.union([
2148
+ z8.object({ kind: z8.literal("user") }).strict(),
2149
+ z8.object({ kind: z8.literal("goal"), goal: ResultRefSchema }).strict()
2020
2150
  ]);
2021
- var LessonChangeSchema = z6.union([
2022
- z6.object({ kind: z6.literal("remember"), text: z6.string().min(1), scope: lessonScope }).strict(),
2023
- z6.object({ kind: z6.literal("revise"), lessonId: id, text: z6.string().min(1), scope: lessonScope }).strict(),
2024
- z6.object({ kind: z6.literal("withdraw"), lessonId: id }).strict()
2151
+ var LessonChangeSchema = z8.union([
2152
+ z8.object({ kind: z8.literal("remember"), text: z8.string().min(1), scope: lessonScope }).strict(),
2153
+ z8.object({ kind: z8.literal("revise"), lessonId: id, text: z8.string().min(1), scope: lessonScope }).strict(),
2154
+ z8.object({ kind: z8.literal("withdraw"), lessonId: id }).strict()
2025
2155
  ]);
2026
- var BrainNextSchema = z6.object({
2027
- instructions: z6.array(z6.object({ entryKeys: z6.array(key).min(1) }).strict()),
2028
- say: z6.array(key),
2029
- then: z6.enum(["listen", "hold", "end", "none"]),
2030
- waitFor: z6.array(ResultRefSchema),
2031
- reason: z6.string()
2156
+ var BrainNextSchema = z8.object({
2157
+ instructions: z8.array(z8.object({ entryKeys: z8.array(key).min(1) }).strict()),
2158
+ say: z8.array(key),
2159
+ then: z8.enum(["listen", "hold", "end", "none"]),
2160
+ waitFor: z8.array(ResultRefSchema),
2161
+ reason: z8.string()
2032
2162
  }).strict();
2033
2163
  var messageBase = {
2034
2164
  key,
2035
- text: z6.string().min(1),
2036
- goals: z6.array(ResultRefSchema),
2037
- questions: z6.array(ResultRefSchema),
2038
- entryKeys: z6.array(key),
2039
- obligationIds: z6.array(id)
2165
+ text: z8.string().min(1),
2166
+ goals: z8.array(ResultRefSchema),
2167
+ questions: z8.array(ResultRefSchema),
2168
+ entryKeys: z8.array(key),
2169
+ obligationIds: z8.array(id)
2040
2170
  };
2041
- var BrainMessageSchema = z6.union([
2171
+ var BrainMessageSchema = z8.union([
2042
2172
  // A MESSAGE TO THE PERSON KEEPS ITS SENTENCES (turns.md): the talker writes them one by one, and each is
2043
2173
  // its own unit of speech (`<cycle>:<key>:<n>`). `text` is the same words joined, for every reader of a
2044
2174
  // message's words. Absent on results written before sentences.
2045
- z6.object({
2175
+ z8.object({
2046
2176
  ...messageBase,
2047
- to: z6.object({ kind: z6.literal("user") }).strict(),
2048
- sentences: z6.array(z6.string().min(1)).min(1).optional(),
2177
+ to: z8.object({ kind: z8.literal("user") }).strict(),
2178
+ sentences: z8.array(z8.string().min(1)).min(1).optional(),
2049
2179
  // THE REPORTS IT TELLS, BY THEIR OWN IDENTITY (call 9d1c096c, 2026-10-15): the talker's message names the report
2050
2180
  // Entries it speaks of, so the plan's line names that report rather than re-finding it by its Goal. Absent on
2051
2181
  // results written before it.
2052
- tells: z6.array(z6.object({ id }).strict()).optional()
2182
+ tells: z8.array(z8.object({ id }).strict()).optional()
2053
2183
  }).strict(),
2054
- z6.object({
2184
+ z8.object({
2055
2185
  ...messageBase,
2056
- to: z6.object({ kind: z6.literal("agent"), agentId: z6.string().regex(/^agent:(?!paigy$)\S+$/) }).strict(),
2057
- call: z6.object({ callId: id, listen: z6.literal(true) }).strict().optional(),
2186
+ to: z8.object({ kind: z8.literal("agent"), agentId: z8.string().regex(/^agent:(?!paigy$)\S+$/) }).strict(),
2187
+ call: z8.object({ callId: id, listen: z8.literal(true) }).strict().optional(),
2058
2188
  // WHAT IT ASKS THE AGENT, IN UNDER TEN WORDS (owner, 2026-10-15: "Yes, add the summary"): the talker's own, stored
2059
2189
  // as the sent Entry's summary, which the recap's "Sent to <agent>: …" row shows. Absent on results written before it.
2060
- summary: z6.string().optional(),
2190
+ summary: z8.string().optional(),
2061
2191
  // THE PERSON ASKED TO BE CALLED BACK ONCE THIS AGENT'S WORK IS DONE (turns.md, step 0): the agent owes
2062
2192
  // the call, and its next contact about it rings them (`public.callbacks`).
2063
- callback: z6.literal(true).optional()
2193
+ callback: z8.literal(true).optional()
2064
2194
  }).strict()
2065
2195
  ]);
2066
- var BrainSearchSchema = z6.object({
2067
- query: z6.string().min(1).max(500),
2068
- within: z6.array(z6.enum(["entries", "goals", "answers"])).min(1),
2196
+ var BrainSearchSchema = z8.object({
2197
+ query: z8.string().min(1).max(500),
2198
+ within: z8.array(z8.enum(["entries", "goals", "answers"])).min(1),
2069
2199
  goalId: id.optional()
2070
2200
  }).strict();
2071
- var BrainResultSchema = z6.object({
2072
- messages: z6.array(BrainMessageSchema),
2073
- entries: z6.array(z6.object({ key, sources: z6.array(SourceSchema).min(1), goals: z6.array(ResultRefSchema), summary: z6.string().optional() }).strict()),
2074
- questions: z6.array(z6.object({ key, entryKeys: z6.array(key), change: QuestionChangeSchema }).strict()),
2075
- answers: z6.array(z6.object({
2201
+ var BrainResultSchema = z8.object({
2202
+ messages: z8.array(BrainMessageSchema),
2203
+ entries: z8.array(z8.object({ key, sources: z8.array(SourceSchema).min(1), goals: z8.array(ResultRefSchema), summary: z8.string().optional() }).strict()),
2204
+ questions: z8.array(z8.object({ key, entryKeys: z8.array(key), change: QuestionChangeSchema }).strict()),
2205
+ answers: z8.array(z8.object({
2076
2206
  question: ResultRefSchema,
2077
- entryKeys: z6.array(key).min(1),
2078
- summary: z6.string(),
2079
- selectedOptionIds: z6.array(z6.string().min(1)).optional()
2207
+ entryKeys: z8.array(key).min(1),
2208
+ summary: z8.string(),
2209
+ selectedOptionIds: z8.array(z8.string().min(1)).optional()
2080
2210
  }).strict()),
2081
- goals: z6.array(z6.object({ key, entryKeys: z6.array(key), change: BrainGoalChangeSchema }).strict()),
2082
- feedback: z6.array(z6.object({ entryKeys: z6.array(key).min(1) }).strict()),
2083
- lessons: z6.array(z6.object({ entryKeys: z6.array(key).min(1), change: LessonChangeSchema }).strict()),
2211
+ goals: z8.array(z8.object({ key, entryKeys: z8.array(key), change: BrainGoalChangeSchema }).strict()),
2212
+ feedback: z8.array(z8.object({ entryKeys: z8.array(key).min(1) }).strict()),
2213
+ lessons: z8.array(z8.object({ entryKeys: z8.array(key).min(1), change: LessonChangeSchema }).strict()),
2084
2214
  next: BrainNextSchema,
2085
2215
  search: BrainSearchSchema.optional()
2086
2216
  }).strict();
2087
- var str2 = z6.string();
2088
- var strs = z6.array(z6.string());
2089
- var CompactResultSchema = z6.object({
2090
- next: z6.object({ say: strs, then: z6.enum(["listen", "hold", "end", "none"]), waitFor: strs, reason: str2, instructions: strs }).strict(),
2091
- messages: z6.array(z6.object({ key: str2, to: str2, text: str2, about: strs, entries: strs, owed: strs, inviteToCall: z6.boolean() }).strict()),
2092
- entries: z6.array(z6.object({ key: str2, from: str2, on: strs }).strict()),
2093
- answers: z6.array(z6.object({ question: str2, entries: strs, summary: str2, picked: strs }).strict()),
2094
- changes: z6.array(z6.object({
2217
+ var str2 = z8.string();
2218
+ var strs = z8.array(z8.string());
2219
+ var CompactResultSchema = z8.object({
2220
+ next: z8.object({ say: strs, then: z8.enum(["listen", "hold", "end", "none"]), waitFor: strs, reason: str2, instructions: strs }).strict(),
2221
+ messages: z8.array(z8.object({ key: str2, to: str2, text: str2, about: strs, entries: strs, owed: strs, inviteToCall: z8.boolean() }).strict()),
2222
+ entries: z8.array(z8.object({ key: str2, from: str2, on: strs }).strict()),
2223
+ answers: z8.array(z8.object({ question: str2, entries: strs, summary: str2, picked: strs }).strict()),
2224
+ changes: z8.array(z8.object({
2095
2225
  key: str2,
2096
- what: z6.enum(["goal", "question", "lesson"]),
2097
- op: z6.enum(["create", "edit", "assign", "open", "complete", "cancel", "defer", "move", "block", "unblock", "withdraw", "remember", "revise"]),
2226
+ what: z8.enum(["goal", "question", "lesson"]),
2227
+ op: z8.enum(["create", "edit", "assign", "open", "complete", "cancel", "defer", "move", "block", "unblock", "withdraw", "remember", "revise"]),
2098
2228
  id: str2,
2099
2229
  text: str2,
2100
2230
  title: str2,
2101
2231
  who: str2,
2102
2232
  under: str2,
2103
- gate: z6.enum(["start", "complete", "answer", "none"]),
2104
- options: z6.array(z6.object({ id: str2, label: str2 }).strict()),
2105
- pick: z6.enum(["one", "many", "rank", "words"]),
2233
+ gate: z8.enum(["start", "complete", "answer", "none"]),
2234
+ options: z8.array(z8.object({ id: str2, label: str2 }).strict()),
2235
+ pick: z8.enum(["one", "many", "rank", "words"]),
2106
2236
  entries: strs
2107
2237
  }).strict()),
2108
- feedback: z6.array(strs),
2109
- search: z6.object({ query: str2, within: strs, goal: str2 }).strict()
2238
+ feedback: z8.array(strs),
2239
+ search: z8.object({ query: str2, within: strs, goal: str2 }).strict()
2110
2240
  }).strict();
2111
2241
  var COMPACT_RESULT_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
2112
2242
  zodToJsonSchema(CompactResultSchema, { $refStrategy: "none" })
2113
2243
  );
2114
- var str3 = z7.string();
2115
- var strs2 = z7.array(z7.string());
2116
- var TalkerReplySchema = z7.object({
2244
+ var str3 = z9.string();
2245
+ var strs2 = z9.array(z9.string());
2246
+ var TalkerReplySchema = z9.object({
2117
2247
  /** What to say and send, messages to the person first: spoken in the order written. `to` is "user"
2118
2248
  * or an agent's handle; `sentences` is what a message to the person says, one short sentence each
2119
2249
  * ([] to an agent); `text` is what a message to an agent says ("" to the person); `summary` is what it
@@ -2122,36 +2252,36 @@ var TalkerReplySchema = z7.object({
2122
2252
  * handles; `blocks` is the item a question to an agent must be answered before ("" for none);
2123
2253
  * `callback` is true on a message to the agent doing work the person asked to be called back about
2124
2254
  * once it is done (false otherwise): that agent then owes the call (turns.md, step 0). */
2125
- messages: z7.array(z7.object({ key: str3, to: str3, sentences: strs2, text: str3, summary: str3, about: strs2, blocks: str3, callback: z7.boolean() }).strict()),
2255
+ messages: z9.array(z9.object({ key: str3, to: str3, sentences: strs2, text: str3, summary: str3, about: strs2, blocks: str3, callback: z9.boolean() }).strict()),
2126
2256
  /** What the call does next: listen, hold (the person asked for a moment) or end (they asked to). */
2127
- then: z7.enum(["listen", "hold", "end"]),
2257
+ then: z9.enum(["listen", "hold", "end"]),
2128
2258
  /** The person's replies to items (replies, owner 2026-10-07): the item's handle, the chosen option
2129
2259
  * IDs, the line handles, how they replied in under ten words (keeping any condition), and `defer`:
2130
2260
  * "" when their words settle the item, else what a reply that puts it off waits for -- "call" (the
2131
2261
  * end of this call), a question's handle (that question's answer) or an ISO time. */
2132
- replies: z7.array(z7.object({ item: str3, options: strs2, lines: strs2, summary: str3, defer: str3 }).strict()),
2262
+ replies: z9.array(z9.object({ item: str3, options: strs2, lines: strs2, summary: str3, defer: str3 }).strict()),
2133
2263
  /** The line handles that tell the talker how to run this call; they last until it ends and reach no agent. */
2134
2264
  instruction: strs2,
2135
2265
  /** The line handles the filer acts on, and the only ones it reads (3e): new work, a change to existing
2136
2266
  * work, feedback on Paigy, anything said to an agent, and any rule meant to outlast the call. */
2137
2267
  file: strs2,
2138
2268
  /** Evidence to fetch for a second round: a search, an item's full text, or an agent by name. */
2139
- need: z7.object({ kind: z7.enum(["search", "item", "agent", ""]), text: str3 }).strict(),
2269
+ need: z9.object({ kind: z9.enum(["search", "item", "agent", ""]), text: str3 }).strict(),
2140
2270
  /** The handle of the item to explain ("" for none). */
2141
2271
  explain: str3
2142
2272
  }).strict();
2143
2273
  var TALKER_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
2144
2274
  zodToJsonSchema(TalkerReplySchema, { $refStrategy: "none" })
2145
2275
  );
2146
- var str4 = z8.string();
2147
- var strs3 = z8.array(z8.string());
2148
- var FilerReplySchema = z8.object({
2276
+ var str4 = z10.string();
2277
+ var strs3 = z10.array(z10.string());
2278
+ var FilerReplySchema = z10.object({
2149
2279
  /** Which Goals each new line goes on: a line's handle, Goal handles (or keys of new Goals: a line that asks
2150
2280
  * for new work goes on the Goal it creates, owner 2026-10-26), and what the line says in at most twenty
2151
2281
  * words (owner, 2026-10-26: "bump it from 10 to 20 words"). */
2152
- filed: z8.array(z8.object({ line: str4, goals: strs3, summary: str4 }).strict()),
2153
- goals: z8.array(z8.object({
2154
- op: z8.enum(["create", "edit", "complete", "cancel", "reopen", "assign", "defer", "move", "block", "unblock"]),
2282
+ filed: z10.array(z10.object({ line: str4, goals: strs3, summary: str4 }).strict()),
2283
+ goals: z10.array(z10.object({
2284
+ op: z10.enum(["create", "edit", "complete", "cancel", "reopen", "assign", "defer", "move", "block", "unblock"]),
2155
2285
  key: str4,
2156
2286
  goal: str4,
2157
2287
  title: str4,
@@ -2160,33 +2290,33 @@ var FilerReplySchema = z8.object({
2160
2290
  under: str4,
2161
2291
  until: str4,
2162
2292
  on: str4,
2163
- gate: z8.enum(["start", "complete", "answer", ""]),
2293
+ gate: z10.enum(["start", "complete", "answer", ""]),
2164
2294
  why: str4
2165
2295
  }).strict()),
2166
- questions: z8.array(z8.object({
2167
- op: z8.enum(["create", "edit", "assign", "withdraw"]),
2296
+ questions: z10.array(z10.object({
2297
+ op: z10.enum(["create", "edit", "assign", "withdraw"]),
2168
2298
  key: str4,
2169
2299
  question: str4,
2170
2300
  text: str4,
2171
2301
  summary: str4,
2172
2302
  to: str4,
2173
2303
  goal: str4,
2174
- options: z8.array(z8.object({ id: str4, label: str4 }).strict()),
2175
- pick: z8.enum(["one", "many", "rank", "words", ""]),
2304
+ options: z10.array(z10.object({ id: str4, label: str4 }).strict()),
2305
+ pick: z10.enum(["one", "many", "rank", "words", ""]),
2176
2306
  blocks: str4
2177
2307
  }).strict()),
2178
- lessons: z8.array(z8.object({ op: z8.enum(["remember", "revise", "withdraw"]), lesson: str4, text: str4, scope: str4 }).strict()),
2308
+ lessons: z10.array(z10.object({ op: z10.enum(["remember", "revise", "withdraw"]), lesson: str4, text: str4, scope: str4 }).strict()),
2179
2309
  /** Line handles whose words comment on Paigy itself. */
2180
2310
  feedback: strs3
2181
2311
  }).strict();
2182
2312
  var FILER_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
2183
2313
  zodToJsonSchema(FilerReplySchema, { $refStrategy: "none" })
2184
2314
  );
2185
- var ExplainerReplySchema = z9.object({
2315
+ var ExplainerReplySchema = z11.object({
2186
2316
  /** The explanation, as sentences, spoken in order. */
2187
- say: z9.array(z9.string()),
2317
+ say: z11.array(z11.string()),
2188
2318
  /** Questions to an agent about gaps in what it read: the agent's handle and the question. */
2189
- followUps: z9.array(z9.object({ to: z9.string(), text: z9.string() }).strict())
2319
+ followUps: z11.array(z11.object({ to: z11.string(), text: z11.string() }).strict())
2190
2320
  }).strict();
2191
2321
  var EXPLAINER_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
2192
2322
  zodToJsonSchema(ExplainerReplySchema, { $refStrategy: "none" })
@@ -2209,49 +2339,49 @@ var DISTILLER_DEFECTS = [
2209
2339
  "dropped"
2210
2340
  // something it had to say never played and was never said later (owner, 2026-10-08, call 65433a9d)
2211
2341
  ];
2212
- var DistillerReplySchema = z10.object({
2213
- defects: z10.array(z10.object({
2214
- kind: z10.enum(DISTILLER_DEFECTS),
2342
+ var DistillerReplySchema = z12.object({
2343
+ defects: z12.array(z12.object({
2344
+ kind: z12.enum(DISTILLER_DEFECTS),
2215
2345
  /** The handles of the lines it shows in. */
2216
- lines: z10.array(z10.string()),
2346
+ lines: z12.array(z12.string()),
2217
2347
  /** The handle of the record it concerns, or "". */
2218
- about: z10.string(),
2348
+ about: z12.string(),
2219
2349
  /** One plain sentence, in words, never handles: it is what the feedback row keeps. */
2220
- why: z10.string()
2350
+ why: z12.string()
2221
2351
  }).strict())
2222
2352
  }).strict();
2223
2353
  var DISTILLER_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
2224
2354
  zodToJsonSchema(DistillerReplySchema, { $refStrategy: "none" })
2225
2355
  );
2226
2356
  var TIDY_AUDIENCES = ["talker", "filer", "agents"];
2227
- var TidyReplySchema = z10.object({
2228
- lessons: z10.array(z10.object({
2229
- lesson: z10.string(),
2230
- op: z10.enum(["keep", "revise", "withdraw"]),
2231
- text: z10.string(),
2232
- for: z10.enum([...TIDY_AUDIENCES, ""]),
2233
- into: z10.string()
2357
+ var TidyReplySchema = z12.object({
2358
+ lessons: z12.array(z12.object({
2359
+ lesson: z12.string(),
2360
+ op: z12.enum(["keep", "revise", "withdraw"]),
2361
+ text: z12.string(),
2362
+ for: z12.enum([...TIDY_AUDIENCES, ""]),
2363
+ into: z12.string()
2234
2364
  }).strict())
2235
2365
  }).strict();
2236
2366
  var TIDY_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
2237
2367
  zodToJsonSchema(TidyReplySchema, { $refStrategy: "none" })
2238
2368
  );
2239
- var HandoutReplySchema = z11.object({
2240
- assign: z11.array(z11.object({
2369
+ var HandoutReplySchema = z13.object({
2370
+ assign: z13.array(z13.object({
2241
2371
  /** The Goal's handle (G). */
2242
- goal: z11.string(),
2372
+ goal: z13.string(),
2243
2373
  /** The agent's handle (A). */
2244
- to: z11.string(),
2374
+ to: z13.string(),
2245
2375
  /** At most ten words, naming the Goal of theirs it is most like: the reason the hand-out records. */
2246
- why: z11.string()
2376
+ why: z13.string()
2247
2377
  }).strict()),
2248
2378
  /** The Goals no listed agent's work is even loosely like: Paigy starts a session for them (owner, 2026-10-24,
2249
2379
  * Goal 37603006, "One per family of related Goals"). */
2250
- new: z11.array(z11.object({
2380
+ new: z13.array(z13.object({
2251
2381
  /** The Goal's handle (G). */
2252
- goal: z11.string(),
2382
+ goal: z13.string(),
2253
2383
  /** At most ten words: why nothing active fits it. */
2254
- why: z11.string()
2384
+ why: z13.string()
2255
2385
  }).strict())
2256
2386
  }).strict();
2257
2387
  var HANDOUT_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
@@ -2292,20 +2422,20 @@ var LIVE_MS = 3 * 6e4;
2292
2422
  var WORKING_MS = 60 * 6e4;
2293
2423
  var WORKING_TIER_MS = 2 * 60 * 6e4;
2294
2424
  var RECENT_TIER_MS = 24 * 60 * 6e4;
2295
- var ContextSchema = z12.object({
2296
- title: z12.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
2297
- description: z12.array(z12.string().min(1)).describe(
2425
+ var ContextSchema = z14.object({
2426
+ title: z14.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
2427
+ description: z14.array(z14.string().min(1)).describe(
2298
2428
  "Semantic chunks of detail (each a standalone, non-empty piece). The user can select chunks to ask you to expand. MAY BE EMPTY: a claim whose whole content is its heading \u2014 a single sentence \u2014 has no body, and saying so beats repeating the heading underneath itself. That repeat is what `min(1)` used to force, at 2x the storage, with every reader subtracting it back out at render time."
2299
2429
  ),
2300
2430
  /** THE ASK'S UNITS (3c): its context as titled units, in order. The app lists the titles and opens
2301
2431
  * a body on a tap. Absent on an ask sent without units, which renders as before. */
2302
- units: z12.array(z12.object({ title: z12.string(), body: z12.string() })).optional()
2432
+ units: z14.array(z14.object({ title: z14.string(), body: z14.string() })).optional()
2303
2433
  });
2304
- var ParticipantSchema = z12.object({
2305
- kind: z12.enum(["human", "agent"]),
2306
- id: z12.string()
2434
+ var ParticipantSchema = z14.object({
2435
+ kind: z14.enum(["human", "agent"]),
2436
+ id: z14.string()
2307
2437
  });
2308
- var TransformSchema = z12.enum([
2438
+ var TransformSchema = z14.enum([
2309
2439
  "structure",
2310
2440
  // shape intent into an answer contract; pick channel/urgency — broker `ask`, `select` shapes, `points`
2311
2441
  "request_more",
@@ -2328,13 +2458,13 @@ var PAIGY_SELF = { kind: "agent", id: "paigy" };
2328
2458
  function isPaigy(ref) {
2329
2459
  return ref === participantRef(PAIGY_SELF);
2330
2460
  }
2331
- var VisualSchema = z12.object({
2332
- url: z12.string().url(),
2333
- label: z12.string().optional()
2461
+ var VisualSchema = z14.object({
2462
+ url: z14.string().url(),
2463
+ label: z14.string().optional()
2334
2464
  });
2335
- var NotifyLevelSchema = z12.enum(["inbox", "push", "banner", "call"]);
2336
- var SelectShapeSchema = z12.enum(["one", "many", "rank", "confirm", "text"]);
2337
- var ReceiptEventSchema = z12.enum([
2465
+ var NotifyLevelSchema = z14.enum(["inbox", "push", "banner", "call"]);
2466
+ var SelectShapeSchema = z14.enum(["one", "many", "rank", "confirm", "text"]);
2467
+ var ReceiptEventSchema = z14.enum([
2338
2468
  "delivered",
2339
2469
  // the bundle reached the recipient at some level
2340
2470
  "seen",
@@ -2364,47 +2494,47 @@ var ReceiptEventSchema = z12.enum([
2364
2494
  // be rewound by a writer that forgot to advance it.
2365
2495
  "restarted"
2366
2496
  ]);
2367
- var AttentionSchema = z12.object({
2497
+ var AttentionSchema = z14.object({
2368
2498
  urgency: NotifyLevelSchema,
2369
2499
  /** The required answer shape, or null for a plain notify that asks nothing back. */
2370
2500
  select: SelectShapeSchema.nullable(),
2371
2501
  /** Coverage contract (#396) — points the answer must address; null = none declared. */
2372
- points: z12.array(z12.string()).nullable(),
2502
+ points: z14.array(z14.string()).nullable(),
2373
2503
  /** Whether the ask blocks the sender — what lets arbitration escalate it on silence. */
2374
- blocking: z12.boolean(),
2504
+ blocking: z14.boolean(),
2375
2505
  /** Reserved (docs/model/model.md lists it): a response deadline. No row column yet — a later Phase 2
2376
2506
  * slice wires it; optional so today's rows/callers project cleanly. */
2377
- deadline: z12.string().datetime().nullable().optional()
2507
+ deadline: z14.string().datetime().nullable().optional()
2378
2508
  });
2379
- var NotifyRequestFields = z12.object({
2509
+ var NotifyRequestFields = z14.object({
2380
2510
  /** Plaintext message content. Present on the plaintext path (today's shape);
2381
2511
  * ABSENT on the E2EE path, where the sealed `envelope` below carries it. The
2382
2512
  * superRefine at the bottom enforces exactly one of the two. */
2383
2513
  context: ContextSchema.optional(),
2384
- options: z12.array(OptionSchema.omit({ id: true }).extend({ label: z12.string().trim().min(1).max(1e3) }).strict()).min(OPTIONS_MIN).max(OPTIONS_MAX).optional().describe(
2514
+ options: z14.array(OptionSchema.omit({ id: true }).extend({ label: z14.string().trim().min(1).max(1e3) }).strict()).min(OPTIONS_MIN).max(OPTIONS_MAX).optional().describe(
2385
2515
  "The choices, in order \u2014 required when select is 'one'/'many'/'rank', omitted otherwise. Ids are assigned automatically by position ('1', '2', \u2026); the user's answer references them as optionId(s)."
2386
2516
  ),
2387
- points: z12.array(z12.string().min(1)).optional().describe(
2517
+ points: z14.array(z14.string().min(1)).optional().describe(
2388
2518
  "The distinct things you need answered, each a short phrase \u2014 on a call the broker keeps the conversation going until each is addressed, and the reply reports which were covered, so a half-answer is never silently returned as final. Omit for single-part asks."
2389
2519
  ),
2390
- visuals: z12.array(VisualSchema).optional().describe(
2520
+ visuals: z14.array(VisualSchema).optional().describe(
2391
2521
  "Images attached to the message itself \u2014 context for the whole question (a screenshot, a chart). For a preview on one selectable choice, use that option's `html`/`image` instead."
2392
2522
  ),
2393
2523
  /** Git repo the agent is working in ("owner/name"). Local MCP fills this from the checkout — omit unless overriding. */
2394
- repo: z12.string().optional(),
2524
+ repo: z14.string().optional(),
2395
2525
  /** Git branch the agent is on. Local MCP fills this from the checkout — omit unless overriding. */
2396
- branch: z12.string().optional(),
2526
+ branch: z14.string().optional(),
2397
2527
  /** Continue an existing conversation — the id of any notification in it (its root
2398
2528
  * is the conversation's identity). Omitted = start a new conversation. Renamed
2399
2529
  * from `parentId` (2026-08-03): one linkage system, the parent; the API edge
2400
2530
  * still accepts the old name from older clients. */
2401
- parentId: z12.string().uuid().optional(),
2531
+ parentId: z14.string().uuid().optional(),
2402
2532
  /** The durable outcome this contact advances. Optional during the notification-to-Work
2403
2533
  * migration; when present, a blocking ask creates a DecisionNeed for this Work. */
2404
- workId: z12.string().uuid().optional(),
2534
+ workId: z14.string().uuid().optional(),
2405
2535
  /** Target Goal scope. During staged migration this is accepted by the shared contract but
2406
2536
  * target delivery activation remains model-gated; workId and goalId are mutually exclusive. */
2407
- goalId: z12.string().uuid().optional(),
2537
+ goalId: z14.string().uuid().optional(),
2408
2538
  urgency: NotifyLevelSchema.default("inbox").describe(
2409
2539
  "The level you're requesting \u2014 the user's account permissions + session mode can lower it. 'inbox' (default) = sits silently in the inbox for the user to get to. 'push' = a quiet passive push (lands in Notification Center, no sound) \u2014 a gentle heads-up. 'banner' = a time-sensitive banner/lock-screen push with sound (a 'paige') they tap to open \u2014 use when you need them soon-ish but it's not worth ringing them. 'call' = rings the user's phone now (a CallKit voice call) \u2014 use only when you genuinely need them in the moment (blocked and waiting, time-sensitive). context.title is what they see on the banner/ring, so make it specific."
2410
2540
  ),
@@ -2412,7 +2542,7 @@ var NotifyRequestFields = z12.object({
2412
2542
  * visible and marks it needs_input. Renamed from the old `parentId` (2026-08-03)
2413
2543
  * when `parentId` became the conversation handle: `parentId` says WHERE, this
2414
2544
  * says HOW. */
2415
- clarifies: z12.string().optional(),
2545
+ clarifies: z14.string().optional(),
2416
2546
  select: SelectShapeSchema.optional().describe(
2417
2547
  "How the user answers \u2014 required on the fully-shaped form, pick the shape that fits the question: 'one' = pick one option, 'many' = pick several, 'rank' = pick & order (each needs `options`); 'confirm' = yes/no or approve/deny; 'text' = free-form reply only (status updates, open questions). 'confirm' and 'text' take no options. Omit only when sending the simplified `ask` form \u2014 the broker picks the shape."
2418
2548
  ),
@@ -2426,20 +2556,20 @@ var NotifyRequestFields = z12.object({
2426
2556
  // (docs/history/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
2427
2557
  // Owner, 2026-07-28: "our actual limitation on how long something is to the user should
2428
2558
  // come from the broker splitting and summarizing." The cap that remains is a size guard.
2429
- ask: z12.string().min(1).max(1e4).optional().describe(
2559
+ ask: z14.string().min(1).max(1e4).optional().describe(
2430
2560
  'SIMPLIFIED FORM \u2014 state in plain prose what you need to learn from the user and why it matters now (e.g. "I need to know whether to deploy the auth fix \u2014 tests are green, staging verified"). Write as much as the situation needs (up to 10k characters) \u2014 Paigy breaks it into topics and reads it back a few sentences at a time; do NOT pre-summarize it into one line. Paigy derives the title, answer shape, options, and delivery channel for you. Mutually exclusive with context/select/options \u2014 send one form or the other.'
2431
2561
  ),
2432
- needs: z12.array(z12.string().min(1)).optional().describe(
2562
+ needs: z14.array(z14.string().min(1)).optional().describe(
2433
2563
  "With `ask` only: the distinct things you need answered when the ask is multi-part \u2014 becomes the coverage contract (`points`), so a half-answer is never silently final."
2434
2564
  ),
2435
- urgencyHint: z12.enum(["whenever", "soon", "now"]).optional().describe(
2565
+ urgencyHint: z14.enum(["whenever", "soon", "now"]).optional().describe(
2436
2566
  "With `ask` only: how urgently you need the answer \u2014 'whenever' (inbox), 'soon' (worth a heads-up), 'now' (you're blocked this minute). A hint, not a command: the user's settings still have the final word."
2437
2567
  ),
2438
2568
  /** #575: the ONE self-report that replaces urgencyHint + blocking — what happens
2439
2569
  * to the agent's work while it waits. Normalized server-side into those two
2440
2570
  * fields (normalizeWaiting) so everything downstream is untouched; explicit
2441
2571
  * urgencyHint/blocking win when both are sent. */
2442
- waiting: z12.enum(["none", "soft", "hard"]).optional().describe(
2572
+ waiting: z14.enum(["none", "soft", "hard"]).optional().describe(
2443
2573
  "With `ask`: what happens to your work while you wait. 'none' = you're just informing the user. 'soft' = you'd like an answer but can keep working. 'hard' = you are stopped until they answer (reaches them urgently and escalates to a real phone call if unanswered). Replaces urgencyHint + blocking \u2014 send this one field."
2444
2574
  ),
2445
2575
  /** Δ9b (#895): HOLD this claim so the sender can correct the plan before anyone is
@@ -2447,98 +2577,98 @@ var NotifyRequestFields = z12.object({
2447
2577
  * holding by default would charge every quiet claim that minute before any agent could
2448
2578
  * correct anything. Ignored for `waiting: 'hard'`: a blocking ask rings on what we have,
2449
2579
  * and the enrichment can still land mid-call (#781 re-plans the unspoken tail). */
2450
- confirm: z12.boolean().optional().describe(
2580
+ confirm: z14.boolean().optional().describe(
2451
2581
  "Hold this one so you can correct the plan before the user is interrupted. The response comes back with `held: true` and the plan; POST the confirm route to release it (with options/visuals/urgency corrections, or nothing at all). If you never do, it is announced anyway a couple of minutes later. Ignored when waiting is 'hard'."
2452
2582
  ),
2453
2583
  /** #575: a RELAY of the user's explicitly stated preference, never the agent's
2454
2584
  * choice. Outranks waiting in both directions: 'call' rings even for a
2455
2585
  * waiting:'none' "call me when it's done"; 'message' never rings even for
2456
2586
  * waiting:'hard'. */
2457
- channel: z12.enum(["call", "message"]).optional().describe(
2587
+ channel: z14.enum(["call", "message"]).optional().describe(
2458
2588
  "Only if the user explicitly said how to reach them \u2014 'call me' \u2192 'call', 'just message/text me' \u2192 'message'. Omit otherwise; Paigy picks."
2459
2589
  ),
2460
- confirmStyle: z12.enum(["yesno", "approve"]).default("yesno").describe(
2590
+ confirmStyle: z14.enum(["yesno", "approve"]).default("yesno").describe(
2461
2591
  "Labels for a select:'confirm' paige \u2014 'yesno' (Yes/No) or 'approve' (Approve/Deny). Ignored unless select is 'confirm'."
2462
2592
  ),
2463
- blocking: z12.boolean().default(false).describe(
2593
+ blocking: z14.boolean().default(false).describe(
2464
2594
  "Set true when real downstream work is stuck behind this specific decision \u2014 you can't make meaningful progress until it's answered. This is the real signal for how urgently the user should be reached; it's what the premier use case (an agent that stays unblocked instead of going idle) depends on. Independent of `urgency`: a `banner`-level question can still be `blocking` (something IS stuck, just not time-critical enough to ring for immediately) \u2014 if it goes unanswered a while, Paigy escalates it to a real call using this flag rather than guessing from how many other things happen to be pending. Leave false for anything you could work around, defer, or where other useful work exists meanwhile."
2465
2595
  )
2466
2596
  });
2467
2597
  var NotifyRequestSchema = NotifyRequestFields.superRefine((r, ctx) => {
2468
- if (r.workId && r.goalId) ctx.addIssue({ code: z12.ZodIssueCode.custom, path: ["goalId"], message: "pass goalId or workId, not both" });
2598
+ if (r.workId && r.goalId) ctx.addIssue({ code: z14.ZodIssueCode.custom, path: ["goalId"], message: "pass goalId or workId, not both" });
2469
2599
  if (r.ask !== void 0) {
2470
2600
  for (const f of ["context", "select", "points"]) {
2471
2601
  if (r[f] !== void 0)
2472
- ctx.addIssue({ code: z12.ZodIssueCode.custom, path: [f], message: `the simplified \`ask\` form takes no ${f} \u2014 the broker derives the answer shape from your prose. Drop ${f} and say it in \`ask\` instead ("should I\u2026" for approve/deny, "which of these\u2026" for a pick), passing \`options\` when you're offering concrete alternatives.` });
2602
+ ctx.addIssue({ code: z14.ZodIssueCode.custom, path: [f], message: `the simplified \`ask\` form takes no ${f} \u2014 the broker derives the answer shape from your prose. Drop ${f} and say it in \`ask\` instead ("should I\u2026" for approve/deny, "which of these\u2026" for a pick), passing \`options\` when you're offering concrete alternatives.` });
2473
2603
  }
2474
2604
  return;
2475
2605
  }
2476
2606
  if (r.needs !== void 0 || r.urgencyHint !== void 0)
2477
- ctx.addIssue({ code: z12.ZodIssueCode.custom, path: ["needs"], message: "needs/urgencyHint belong to the simplified `ask` form \u2014 with a shaped request use points/urgency" });
2607
+ ctx.addIssue({ code: z14.ZodIssueCode.custom, path: ["needs"], message: "needs/urgencyHint belong to the simplified `ask` form \u2014 with a shaped request use points/urgency" });
2478
2608
  if (!r.context)
2479
- ctx.addIssue({ code: z12.ZodIssueCode.custom, path: ["context"], message: "context is required (plaintext path)" });
2609
+ ctx.addIssue({ code: z14.ZodIssueCode.custom, path: ["context"], message: "context is required (plaintext path)" });
2480
2610
  if (!r.select)
2481
- ctx.addIssue({ code: z12.ZodIssueCode.custom, path: ["select"], message: "select is required on the shaped form" });
2611
+ ctx.addIssue({ code: z14.ZodIssueCode.custom, path: ["select"], message: "select is required on the shaped form" });
2482
2612
  const needsOptions = r.select === "one" || r.select === "many" || r.select === "rank";
2483
2613
  if (needsOptions && !r.options?.length)
2484
- ctx.addIssue({ code: z12.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' requires options` });
2614
+ ctx.addIssue({ code: z14.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' requires options` });
2485
2615
  if (!needsOptions && r.options?.length)
2486
- ctx.addIssue({ code: z12.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' takes no options` });
2616
+ ctx.addIssue({ code: z14.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' takes no options` });
2487
2617
  });
2488
- var NotifyStatusSchema = z12.enum(["pending", "answered", "ignored"]);
2489
- var AgentStateSchema = z12.enum(["idle", "in_progress", "completed", "needs_input"]);
2490
- var TurnSchema = z12.object({
2491
- prompt: z12.string(),
2492
- reply: z12.string()
2618
+ var NotifyStatusSchema = z14.enum(["pending", "answered", "ignored"]);
2619
+ var AgentStateSchema = z14.enum(["idle", "in_progress", "completed", "needs_input"]);
2620
+ var TurnSchema = z14.object({
2621
+ prompt: z14.string(),
2622
+ reply: z14.string()
2493
2623
  });
2494
- var UserAnswerSchema = z12.discriminatedUnion("kind", [
2495
- z12.object({ kind: z12.literal("option"), optionId: z12.string(), label: z12.string().optional() }),
2496
- z12.object({ kind: z12.literal("text"), text: z12.string() }),
2497
- z12.object({ kind: z12.literal("ignored") }),
2498
- z12.object({ kind: z12.literal("multi"), optionIds: z12.array(z12.string()), labels: z12.array(z12.string()).optional() }),
2499
- z12.object({ kind: z12.literal("ranked"), optionIds: z12.array(z12.string()), labels: z12.array(z12.string()).optional() }),
2500
- z12.object({ kind: z12.literal("clarify"), chunks: z12.array(z12.string()).min(1) }),
2501
- z12.object({ kind: z12.literal("confirm"), approved: z12.boolean() }),
2502
- z12.object({ kind: z12.literal("turns"), turns: z12.array(TurnSchema).min(1) }),
2624
+ var UserAnswerSchema = z14.discriminatedUnion("kind", [
2625
+ z14.object({ kind: z14.literal("option"), optionId: z14.string(), label: z14.string().optional() }),
2626
+ z14.object({ kind: z14.literal("text"), text: z14.string() }),
2627
+ z14.object({ kind: z14.literal("ignored") }),
2628
+ z14.object({ kind: z14.literal("multi"), optionIds: z14.array(z14.string()), labels: z14.array(z14.string()).optional() }),
2629
+ z14.object({ kind: z14.literal("ranked"), optionIds: z14.array(z14.string()), labels: z14.array(z14.string()).optional() }),
2630
+ z14.object({ kind: z14.literal("clarify"), chunks: z14.array(z14.string()).min(1) }),
2631
+ z14.object({ kind: z14.literal("confirm"), approved: z14.boolean() }),
2632
+ z14.object({ kind: z14.literal("turns"), turns: z14.array(TurnSchema).min(1) }),
2503
2633
  /** An auto-answer derived from the user's PAST decisions (docs/history/precedent-design.md §2):
2504
2634
  * delivered through the same settle/await path as a human answer, carrying the judge's
2505
2635
  * derivation and the precedent ids it grew from. Always paired with a visible trail
2506
2636
  * card the user can reply to — the broker never overrides the user. */
2507
- z12.object({ kind: z12.literal("precedent"), answer: z12.string(), derivation: z12.string(), sources: z12.array(z12.string()).min(1) })
2637
+ z14.object({ kind: z14.literal("precedent"), answer: z14.string(), derivation: z14.string(), sources: z14.array(z14.string()).min(1) })
2508
2638
  ]);
2509
- var IntentSchema = z12.object({
2639
+ var IntentSchema = z14.object({
2510
2640
  // The full vocabulary the bot's mapper emits (mapper.INTENT_KINDS) — the schema lagged
2511
2641
  // it by two ("detail", "feedback"), and because the settle handler parsed the array
2512
2642
  // all-or-nothing, ONE feedback act silently dropped EVERY intent on the call,
2513
2643
  // questions included. Found auditing five calls' stored feedback, 2026-08-01.
2514
- kind: z12.enum(["defer", "delegate", "channel", "question", "detail", "feedback", "command", "control"]),
2515
- detail: z12.string(),
2644
+ kind: z14.enum(["defer", "delegate", "channel", "question", "detail", "feedback", "command", "control"]),
2645
+ detail: z14.string(),
2516
2646
  /** Defer only: seconds until the callback the caller asked for, when something upstream
2517
2647
  * already read the time. Nothing sets it today (#397 documented an MCP parser that was
2518
2648
  * never written) — the API reads the defer's `detail` itself with `notes/when.ts`
2519
2649
  * (`parseDelay`, #1292), and a value here simply wins over that reading. */
2520
- dueInSeconds: z12.number().int().positive().optional(),
2650
+ dueInSeconds: z14.number().int().positive().optional(),
2521
2651
  /** Feedback only (#812): WHICH failure the complaint names — typed by the mapper that
2522
2652
  * already read the utterance, so `signals.kind` stops defaulting to
2523
2653
  * 'other' on every row. A table that records that something was wrong and nothing
2524
2654
  * about what cannot answer "is the bot looping less this week?". */
2525
- fault: z12.enum(["loop", "unanswered", "overridden", "misheard", "slow", "other"]).optional()
2655
+ fault: z14.enum(["loop", "unanswered", "overridden", "misheard", "slow", "other"]).optional()
2526
2656
  });
2527
- var RideAlongSchema = z12.object({
2657
+ var RideAlongSchema = z14.object({
2528
2658
  /** The note this came from — assign/clarify/close it through /api/notes/:id. */
2529
- noteId: z12.string(),
2659
+ noteId: z14.string(),
2530
2660
  /** What to do, in the owner's own words (the note's headline). Never model-rewritten. */
2531
- text: z12.string(),
2661
+ text: z14.string(),
2532
2662
  /** The thread to report back on, when the note was dispatched over the request rail. */
2533
- parentId: z12.string().nullable()
2663
+ parentId: z14.string().nullable()
2534
2664
  });
2535
- var AwaitItemSchema = z12.discriminatedUnion("type", [
2536
- z12.object({
2537
- type: z12.literal("reply"),
2538
- parentId: z12.string(),
2539
- notificationId: z12.string(),
2540
- workId: z12.string().uuid().optional(),
2541
- decisionId: z12.string().uuid().optional(),
2665
+ var AwaitItemSchema = z14.discriminatedUnion("type", [
2666
+ z14.object({
2667
+ type: z14.literal("reply"),
2668
+ parentId: z14.string(),
2669
+ notificationId: z14.string(),
2670
+ workId: z14.string().uuid().optional(),
2671
+ decisionId: z14.string().uuid().optional(),
2542
2672
  answer: UserAnswerSchema,
2543
2673
  /** WHAT THE AGENT CANNOT KNOW FROM THE FIELDS BESIDE IT (owner, 2026-09-04, issue
2544
2674
  * #1537). One line, built from the record: the ask and the caller's reply VERBATIM,
@@ -2548,109 +2678,109 @@ var AwaitItemSchema = z12.discriminatedUnion("type", [
2548
2678
  * "call me back after you merge" in their own words decides for itself what to do,
2549
2679
  * and now knows exactly which call to make. Absent when either half is missing —
2550
2680
  * a sentence with a hole in it is worse than no sentence. */
2551
- note: z12.string().optional(),
2681
+ note: z14.string().optional(),
2552
2682
  /** The call record rendered for THIS agent (`docs/brain/voice/record-design.md`): the words the
2553
2683
  * shaped answer was mapped from, filtered to its own claims. There is no second list
2554
2684
  * of labels beside it — the acts went 2026-09-04 and `intents` went with them (owner,
2555
2685
  * 2026-09-04): the agent reads the sentence and decides. */
2556
- transcript: z12.string().optional(),
2686
+ transcript: z14.string().optional(),
2557
2687
  /** Coverage report (#396), when the ask declared `points`: which of them this
2558
2688
  * answer addressed. Missing points = re-ask or proceed knowingly partial. */
2559
- covered: z12.array(z12.string()).optional(),
2689
+ covered: z14.array(z14.string()).optional(),
2560
2690
  /** Ride-alongs (RideAlongSchema) — pending work for you, attached to the moment you
2561
2691
  * became free. Only `reply` and `idle` carry it: those are the two outcomes that
2562
2692
  * END a wait. `remind`, `superseded` and `turn` are mid-flight, and handing an
2563
2693
  * agent a side-quest while it is still holding the line is how the main thing gets
2564
2694
  * dropped. Absent/empty = nothing owed. */
2565
- also: z12.array(RideAlongSchema).optional()
2695
+ also: z14.array(RideAlongSchema).optional()
2566
2696
  }),
2567
- z12.object({
2568
- type: z12.literal("remind"),
2569
- parentId: z12.string(),
2570
- notificationId: z12.string(),
2571
- remindAt: z12.string().datetime({ offset: true }),
2697
+ z14.object({
2698
+ type: z14.literal("remind"),
2699
+ parentId: z14.string(),
2700
+ notificationId: z14.string(),
2701
+ remindAt: z14.string().datetime({ offset: true }),
2572
2702
  /** Seconds until remindAt, server-computed — pass straight to ScheduleWakeup. */
2573
- remindInSeconds: z12.number()
2703
+ remindInSeconds: z14.number()
2574
2704
  }),
2575
2705
  /** The awaited ask was REPLACED by a newer notification on its thread (e.g. a
2576
2706
  * post-feedback revision, #633) — the user will never answer this id. Stop
2577
2707
  * awaiting it; the live ask is the thread's newest turn (await that one, or
2578
2708
  * re-orient via contact({})). */
2579
- z12.object({
2580
- type: z12.literal("superseded"),
2581
- parentId: z12.string(),
2582
- notificationId: z12.string()
2709
+ z14.object({
2710
+ type: z14.literal("superseded"),
2711
+ parentId: z14.string(),
2712
+ notificationId: z14.string()
2583
2713
  }),
2584
2714
  /** A LIVE call's turn, streamed as it lands (#783). PROVISIONAL: the user can still
2585
2715
  * revise any of these until the final reply arrives — partial = intelligence,
2586
2716
  * settled = authorization. Use it to PREPARE (fetch, draft, warm), never to act
2587
2717
  * irreversibly. If `acts` carries a question aimed at you and you know the answer,
2588
2718
  * contact on the same thread right away — the caller hears it on the same call. */
2589
- z12.object({
2590
- type: z12.literal("partial"),
2591
- notificationId: z12.string(),
2592
- inFlight: z12.literal(true),
2593
- turn: z12.object({
2594
- idx: z12.number(),
2595
- prompt: z12.string(),
2596
- reply: z12.string(),
2597
- acts: z12.array(IntentSchema).nullable().optional()
2719
+ z14.object({
2720
+ type: z14.literal("partial"),
2721
+ notificationId: z14.string(),
2722
+ inFlight: z14.literal(true),
2723
+ turn: z14.object({
2724
+ idx: z14.number(),
2725
+ prompt: z14.string(),
2726
+ reply: z14.string(),
2727
+ acts: z14.array(IntentSchema).nullable().optional()
2598
2728
  })
2599
2729
  }),
2600
- z12.object({
2601
- type: z12.literal("idle"),
2602
- also: z12.array(RideAlongSchema).optional(),
2730
+ z14.object({
2731
+ type: z14.literal("idle"),
2732
+ also: z14.array(RideAlongSchema).optional(),
2603
2733
  /** Is a call live for this agent's user right now? The SDK polls the partial stream
2604
2734
  * (#783) between idle ticks ONLY while this is not `false` — a partial can only exist
2605
2735
  * during a live call, and polling for one on a banner/message was a wasted HTTP call +
2606
2736
  * 3 queries on every idle tick of every waiting agent (~80% of all traffic at scale).
2607
2737
  * Absent = an older API → the SDK keeps polling, exactly as before. */
2608
- inFlight: z12.boolean().optional()
2738
+ inFlight: z14.boolean().optional()
2609
2739
  })
2610
2740
  ]);
2611
- var VoiceKeySchema = z12.enum(["rachel", "george", "jessica", "brian", "lily"]);
2612
- var AgendaTurnSchema = z12.object({
2741
+ var VoiceKeySchema = z14.enum(["rachel", "george", "jessica", "brian", "lily"]);
2742
+ var AgendaTurnSchema = z14.object({
2613
2743
  /** THE TURN'S IDENTITY (the first-sentence stream, 2026-09-09): the brain call that wrote
2614
2744
  * it and its place in that reply — `<brainCallId>:<index>`, with `:p` on the first
2615
2745
  * sentence a re-plan publishes ahead of the rest. A turn is spoken once, by this id: the
2616
2746
  * completion of a streamed re-plan carries the published sentence again, and the walk
2617
2747
  * drops what it already said by identity, never by the API's guess of what was polled.
2618
2748
  * Absent on plans nothing streams (a ring plan, a floor). */
2619
- id: z12.string().optional(),
2749
+ id: z14.string().optional(),
2620
2750
  /** Twin coverage (#1089): sibling claim ids this asking turn's answer ALSO settles —
2621
2751
  * the planner declares duplicates instead of asking them twice. */
2622
- coveredIds: z12.array(z12.string()).optional(),
2752
+ coveredIds: z14.array(z14.string()).optional(),
2623
2753
  /** The spoken sentences of the turn, in order. No count: how long a turn is is the brain's call
2624
2754
  * (owner, 2026-09-25), and a count here refused whole plans. */
2625
- info: z12.array(z12.string().min(1)).default([]),
2755
+ info: z14.array(z14.string().min(1)).default([]),
2626
2756
  /** THE ID OF EACH SENTENCE, when the plan names them (turns.md): a talker message's sentences are its
2627
2757
  * `info`, one piece each, and `units[i]` is the id the bot's line receipt carries for `info[i]`
2628
2758
  * (`<cycle>:<key>:<n>`), so what was heard is known per sentence. Absent on every other turn. */
2629
- units: z12.array(z12.string().min(1)).optional(),
2630
- question: z12.string().min(1).nullable(),
2759
+ units: z14.array(z14.string().min(1)).optional(),
2760
+ question: z14.string().min(1).nullable(),
2631
2761
  /** True on the one turn carrying the agent's own declared question. */
2632
- asks: z12.boolean().optional(),
2762
+ asks: z14.boolean().optional(),
2633
2763
  /** The claim this turn belongs to (#781) — the RETURN identity: answers route by it.
2634
2764
  * Absent on a single-claim plan (the session's own claim) and on shared context turns,
2635
2765
  * which route nothing. */
2636
- claimId: z12.string().optional(),
2766
+ claimId: z14.string().optional(),
2637
2767
  /** The claim's voice key (#462) — the OUTBOUND identity, audible who-is-asking. */
2638
- voice: z12.string().optional(),
2768
+ voice: z14.string().optional(),
2639
2769
  /** The claim's AGENT NAME (#838) — the spoken identity. A voice alone doesn't say
2640
2770
  * whose request this is: an item that folded in from another agent arrived as a bare
2641
2771
  * non-sequitur ("First real production sign-in is yours to make whenever you want.")
2642
2772
  * and the owner answered "What?". The bot names the agent before its first turn. */
2643
- agent: z12.string().optional(),
2773
+ agent: z14.string().optional(),
2644
2774
  /** The claim's agent by ID — the pairing's connection id (`notifications.token_id`), the
2645
2775
  * same id a face is minted from. A name is not an identity: two pairings may be called
2646
2776
  * "Claude", and a name cannot be joined on. The record's entries carry it (`agent_id`)
2647
2777
  * so "who said that" survives the call, and it rides PER TURN because a coalesced call
2648
2778
  * speaks for several agents — the turn is the only place that knows which. */
2649
- agentId: z12.string().optional(),
2779
+ agentId: z14.string().optional(),
2650
2780
  /** ITS QUESTION IS ON THE TABLE (#3292): a talker line about a question the person owes. The walk tells
2651
2781
  * the phone (`asking`, so the agenda goes gold and its options show) without treating the line as a
2652
2782
  * question turn — the talker owns re-asking and the waits, so `question` stays null. */
2653
- onTable: z12.boolean().optional(),
2783
+ onTable: z14.boolean().optional(),
2654
2784
  /** THE CARRIED ITEM THIS LINE TELLS (Goal 2a1e50eb, owner 2026-10-14: "Build the whole design") — a
2655
2785
  * request the Call carries that asks NOTHING: a report, a progress note, another agent's waiting news.
2656
2786
  * Its request Entry id, so the phone can make that agenda row the current one while it is read
@@ -2660,14 +2790,14 @@ var AgendaTurnSchema = z12.object({
2660
2790
  * record tags the line with it (`workId`) — and an answer must never route to an Entry that asks
2661
2791
  * nothing. Absent on a turn speaking for a question (`claimId` says that) and on one speaking for no
2662
2792
  * carried item at all (an opener, a sign-off, Paigy's own line). */
2663
- telling: z12.string().optional(),
2793
+ telling: z14.string().optional(),
2664
2794
  /** PAIGY'S OWN LINE (owner, 2026-10-15; calls ed2cbdce, ad50ad25): a turn that speaks for no item -- an
2665
2795
  * opener, a sign-off, a reply about nothing an agent asked or told -- is recorded as Paigy's, not as the
2666
2796
  * agent that rang. Absent on every turn that speaks for an item (`agentId` names whose), and on plans
2667
2797
  * from before it: a bot that does not know it records the ringing agent, as before. */
2668
- speaksFor: z12.literal("paigy").optional(),
2798
+ speaksFor: z14.literal("paigy").optional(),
2669
2799
  select: SelectShapeSchema.optional(),
2670
- options: z12.array(OptionSchema.omit({ id: true })).optional(),
2800
+ options: z14.array(OptionSchema.omit({ id: true })).optional(),
2671
2801
  /* `pace` STOOD HERE (#826). A turn could carry seconds and the model chose them. The walk
2672
2802
  paces itself now — a short beat between the sentences of a turn, the longer one at its end
2673
2803
  (owner, 2026-09-30: "remove the bot deciding pace") — and it does that where the words are
@@ -2676,58 +2806,58 @@ var AgendaTurnSchema = z12.object({
2676
2806
  /** Whether the walk WAITS for an answer before moving on. Absent = derived as today
2677
2807
  * (a question blocks, context flows). blocking:false on a question = ask and move
2678
2808
  * on, the claim stays pending; blocking:true on context = hold for a reply. */
2679
- blocking: z12.boolean().optional(),
2809
+ blocking: z14.boolean().optional(),
2680
2810
  /** SPOKEN ONLY IF THEY SAY NOTHING (owner, 2026-10-01, call 812de935: "you're gonna re-ask, but it
2681
2811
  * shouldn't be the same words … more like, hey, are you still there, or are you able to answer, or
2682
2812
  * would you need more information"). The walk holds this turn out of its queue; at the queue's end it
2683
2813
  * listens for the last word, and only if that listen is silent is this turn said and asked. If they
2684
2814
  * speak, it is dropped and their words are taken like any reply. */
2685
- ifSilent: z12.boolean().optional()
2815
+ ifSilent: z14.boolean().optional()
2686
2816
  });
2687
2817
  var CLAIM_STALE_MS = 30 * 6e4;
2688
- var CallQuestionSchema = z12.object({
2689
- id: z12.string(),
2690
- entryId: z12.string(),
2691
- title: z12.string(),
2692
- state: z12.enum(["open", "answered"]),
2693
- answer: z12.string().nullable(),
2818
+ var CallQuestionSchema = z14.object({
2819
+ id: z14.string(),
2820
+ entryId: z14.string(),
2821
+ title: z14.string(),
2822
+ state: z14.enum(["open", "answered"]),
2823
+ answer: z14.string().nullable(),
2694
2824
  /** WHO ASKED IT (owner, 2026-09-23, Goal a345e906: each agenda row wears its agent's face) — the
2695
2825
  * request Entry's author, as the same three facts the item's own `tokenId`/`name`/`voice`
2696
2826
  * carry for the call's one agent, so the phone draws it with the same seed. Absent when the
2697
2827
  * author is not an agent this account holds (unpaired since, or a person). */
2698
- agent: z12.object({ tokenId: z12.string(), name: z12.string(), voice: VoiceKeySchema.optional() }).optional(),
2828
+ agent: z14.object({ tokenId: z14.string(), name: z14.string(), voice: VoiceKeySchema.optional() }).optional(),
2699
2829
  /** ITS OPTIONS, WHEN THERE IS SOMETHING TO SEE (owner, 2026-09-25: "Yes, add it"): the options
2700
2830
  * its need offers, exactly as its own card carries them, present only when one of them has a
2701
2831
  * preview (`html` or `image`). The call screen opens them from the agenda row, so a preview is
2702
2832
  * never re-sent as a second card to be seen mid-call. Words-only options are `choices`. */
2703
- options: z12.array(OptionSchema).optional(),
2833
+ options: z14.array(OptionSchema).optional(),
2704
2834
  /** ITS OPTIONS WHEN THEY ARE WORDS (owner, 2026-10-02, on a call: "whenever there are pre-made
2705
2835
  * options … now for a checklist, we should also show them on the screen"; design C, 2026-10-08):
2706
2836
  * numbered chips above the call's controls, so a checklist is never only something read aloud. A
2707
2837
  * field of its own so `options` keeps meaning "previews": a phone on an older bundle opens the
2708
2838
  * preview layout for any `options`, and must see exactly what it did. */
2709
- choices: z12.array(OptionSchema).optional(),
2839
+ choices: z14.array(OptionSchema).optional(),
2710
2840
  /** HOW MANY MAY BE PICKED, beside its `choices`: one, any (`many`) or an order (`rank`). */
2711
- select: z12.enum(["one", "many", "rank"]).optional()
2841
+ select: z14.enum(["one", "many", "rank"]).optional()
2712
2842
  });
2713
- var InboxItemSchema = z12.object({
2714
- id: z12.string(),
2715
- tokenId: z12.string().optional(),
2843
+ var InboxItemSchema = z14.object({
2844
+ id: z14.string(),
2845
+ tokenId: z14.string().optional(),
2716
2846
  status: NotifyStatusSchema,
2717
2847
  context: ContextSchema,
2718
- options: z12.array(OptionSchema).optional(),
2848
+ options: z14.array(OptionSchema).optional(),
2719
2849
  /** The ask's declared coverage points (#396), when the agent sent them. */
2720
- points: z12.array(z12.string()).optional(),
2850
+ points: z14.array(z14.string()).optional(),
2721
2851
  /** Does this claim want an ANSWER, or is it telling you something? Written per row from
2722
2852
  * `requestAsks` — the agent's own declaration, not a guess. `false` is what earns a card
2723
2853
  * its acknowledge affordance: without it a status update offers a text box and a dismiss,
2724
2854
  * and neither of those is "got it" (owner, 2026-08-10). */
2725
- asks: z12.boolean().optional(),
2855
+ asks: z14.boolean().optional(),
2726
2856
  /** When a live process last pulsed for this row's agent — the liveness input for
2727
2857
  * "working requires a pulse" (#928): the list said "Working…" from agent_state alone
2728
2858
  * while the party called the same dead claim stalled. Absent = no token/no data,
2729
2859
  * which must never CLAIM stalled. */
2730
- lastSeenAt: z12.string().optional(),
2860
+ lastSeenAt: z14.string().optional(),
2731
2861
  /** WHEN THE AGENT LAST SAID ANYTHING ABOUT THIS CLAIM — the newest `agent_state` row in
2732
2862
  * the `notification_events` ledger (trigger-written since 20260621010000, so every row a
2733
2863
  * user can see has one). The age input for `CLAIM_STALE_MS`, and it has to be this rather
@@ -2737,7 +2867,7 @@ var InboxItemSchema = z12.object({
2737
2867
  * work. Reading the row's birth as the claim's age brands that "No update in 8h" the
2738
2868
  * instant the agent picks it up (#997). Absent = pre-trigger row; fall back to
2739
2869
  * `createdAt`. */
2740
- agentStateAt: z12.string().datetime().optional(),
2870
+ agentStateAt: z14.string().datetime().optional(),
2741
2871
  /** THE QUESTIONS A CALL CARRIES — the call screen's agenda spine (docs/clients/app/walk/design.md §11, owner
2742
2872
  * 2026-09-22). One per DecisionNeed on the Call, in the Call's order, answered or open (a
2743
2873
  * superseded or cancelled need is no longer a question anyone is asked). Present only on a
@@ -2751,40 +2881,39 @@ var InboxItemSchema = z12.object({
2751
2881
  * `turn` topic (`asking`, `settled`), because the bot never sees a DecisionNeed id. `title` is
2752
2882
  * the card's own concise heading; `answer` the accepted answer in words, null while open. It
2753
2883
  * REPLACED `agenda` (turns), which nothing ever filled. */
2754
- questions: z12.array(CallQuestionSchema).optional(),
2884
+ questions: z14.array(CallQuestionSchema).optional(),
2755
2885
  /** The same call carrying order, including request Entries with no DecisionNeed as reports.
2756
2886
  * Additive: questions stays decision-only for every other surface and older bundles. */
2757
- callItems: z12.array(CallQuestionSchema.extend({ state: z12.enum(["open", "answered", "report"]), acknowledged: z12.boolean().optional() })).optional(),
2758
- visuals: z12.array(VisualSchema).optional(),
2887
+ callItems: z14.array(CallQuestionSchema.extend({ state: z14.enum(["open", "answered", "report"]), acknowledged: z14.boolean().optional() })).optional(),
2888
+ visuals: z14.array(VisualSchema).optional(),
2759
2889
  /** The connected agent's name (the single pairing name — user-typed, or the
2760
2890
  * agent's suggestion, or a default silly name). */
2761
- name: z12.string(),
2891
+ name: z14.string(),
2762
2892
  /** The pairing's assigned voice (#462); absent = the default voice. */
2763
2893
  voice: VoiceKeySchema.optional(),
2764
- repo: z12.string().optional(),
2765
- branch: z12.string().optional(),
2766
- createdAt: z12.string().datetime(),
2767
- snoozedUntil: z12.string().datetime().optional(),
2894
+ repo: z14.string().optional(),
2895
+ branch: z14.string().optional(),
2896
+ createdAt: z14.string().datetime(),
2897
+ snoozedUntil: z14.string().datetime().optional(),
2898
+ /** A past card the person dismissed that Restore can take back (#2699): its newest close is their
2899
+ * dismissal, with what it withdrew recorded (`private.restore_delivery`). Absent on everything else —
2900
+ * a put-off, a card an ended Goal or a settled question closed, and every open card. */
2901
+ restorable: z14.boolean().optional(),
2768
2902
  agentState: AgentStateSchema.default("idle"),
2769
2903
  /** Whose action the item is waiting on: "you" = an agent asked you (the default,
2770
2904
  * every agent→user notification); "agent" = you sent a request and it's awaiting the
2771
2905
  * agent (held in the inbox until the agent replies on the thread). */
2772
- turn: z12.enum(["you", "agent"]).default("you"),
2906
+ turn: z14.enum(["you", "agent"]).default("you"),
2773
2907
  /** Hard error reason on an awaiting request (turn="agent") — the wake failed to reach
2774
2908
  * the agent (provider-agnostic; set server-side). Absent = no hard error. Drives the inbox
2775
2909
  * error badge + Retry. */
2776
- error: z12.string().optional(),
2777
- /** WHEN THIS AGENT WORK WENT QUIET (turn="agent"), by the one rule (`coldSince`: three days
2778
- * with nothing said), or absent while it is not stalled. The inbox's stalled badge reads
2779
- * this and nothing else (2026-09-23: a 3-minute age rule badged every live Goal stalled,
2780
- * and "dismiss the stalled ones" cancelled 37 pieces of live work). */
2781
- cold: z12.string().datetime().optional(),
2782
- clarifies: z12.string().optional(),
2910
+ error: z14.string().optional(),
2911
+ clarifies: z14.string().optional(),
2783
2912
  /** THIS CARD'S QUESTION IS ON A LIVE CALL (owner, 2026-09-24: "Mark it while the call is
2784
2913
  * live"). Present only while an open Call Delivery carries the card's request Entry — read
2785
2914
  * off the same open list the card came from, so it clears when the Call does. A card is the
2786
2915
  * backup for a call not taken; while the call has it, the call is where it is answered. */
2787
- onCall: z12.literal(true).optional(),
2916
+ onCall: z14.literal(true).optional(),
2788
2917
  /** THE RING, ON THE ITEM (docs/clients/app/walk/design.md §12 §17, #2251): the last ring on this card was
2789
2918
  * declined, and what the ladder will do next — read off the cron's own row, never computed
2790
2919
  * on the phone. Present only while a `declined` receipt stands on the card's last Call.
@@ -2794,31 +2923,31 @@ var InboxItemSchema = z12.object({
2794
2923
  * It replaced `gaveUp` (deleted 2026-09-22): "the ladder spent" was a boolean the projection
2795
2924
  * never set, and it is `nextRingAt === null` here — the party's *Missed you* (`party/dress.ts`)
2796
2925
  * and the roster's `unreached` read `declinedAt`, and stand while it does. */
2797
- ring: z12.object({
2798
- declinedAt: z12.string().datetime(),
2799
- anchorAt: z12.string().datetime(),
2800
- nextRingAt: z12.string().datetime().nullable(),
2801
- step: z12.number().int()
2926
+ ring: z14.object({
2927
+ declinedAt: z14.string().datetime(),
2928
+ anchorAt: z14.string().datetime(),
2929
+ nextRingAt: z14.string().datetime().nullable(),
2930
+ step: z14.number().int()
2802
2931
  }).optional(),
2803
2932
  /** Why this arrived the way it did, read back off the delivery receipt (`notify/why.ts`).
2804
2933
  * Absent for anything never delivered through a push, and for older rows written before
2805
2934
  * the reason was recorded. Deliberately a debug affordance, shown small (owner,
2806
2935
  * 2026-08-07) — its real job is to give "this didn't need a call" something to be
2807
2936
  * feedback ABOUT. */
2808
- why: z12.object({
2937
+ why: z14.object({
2809
2938
  asked: NotifyLevelSchema,
2810
2939
  got: NotifyLevelSchema,
2811
- because: z12.enum(["unresponsive", "dismissed", "not_permitted", "silent", "coalesced", "agent_capped", "unplanned", "learned_raise"]).optional(),
2812
- line: z12.string()
2940
+ because: z14.enum(["unresponsive", "dismissed", "not_permitted", "silent", "coalesced", "agent_capped", "unplanned", "learned_raise"]).optional(),
2941
+ line: z14.string()
2813
2942
  }).optional(),
2814
- select: z12.enum(["one", "many", "rank", "confirm", "text"]).default("one"),
2815
- confirmStyle: z12.enum(["yesno", "approve"]).default("yesno").describe(
2943
+ select: z14.enum(["one", "many", "rank", "confirm", "text"]).default("one"),
2944
+ confirmStyle: z14.enum(["yesno", "approve"]).default("yesno").describe(
2816
2945
  "Labels for a select:'confirm' paige \u2014 'yesno' (Yes/No) or 'approve' (Approve/Deny). Ignored unless select is 'confirm'."
2817
2946
  ),
2818
2947
  /** Real downstream work is stuck behind this one — set by the agent, independent of
2819
2948
  * urgency (see the main README's "premier use case" + docs/history/notify-states.md). Drives the
2820
2949
  * inbox's blocking badge and the extra confirm step before dismissing it. */
2821
- blocking: z12.boolean().default(false),
2950
+ blocking: z14.boolean().default(false),
2822
2951
  /** WHAT FREED THIS QUESTION (owner, 2026-10-16, Goal 2383ef14: "we don't really show the question
2823
2952
  * at the top until the question it could reply to with is resolved. And then we show it again
2824
2953
  * with the context of the other thing that was resolved"; asked how it should carry that, "The
@@ -2826,20 +2955,25 @@ var InboxItemSchema = z12.object({
2826
2955
  * (`private.ask_back`) and drops out of the front while it waits; when it comes back, the card
2827
2956
  * draws their question and the answer it got ABOVE the ask, as one card. Absent on a question
2828
2957
  * nothing ever held back. */
2829
- freedBy: z12.object({
2830
- questionId: z12.string(),
2831
- asked: z12.string(),
2832
- answer: z12.string(),
2833
- answeredAt: z12.string(),
2958
+ freedBy: z14.object({
2959
+ questionId: z14.string(),
2960
+ asked: z14.string(),
2961
+ answer: z14.string(),
2962
+ answeredAt: z14.string(),
2834
2963
  /** The answer in ten words, when the talker wrote one beside it. */
2835
- summary: z12.string().optional()
2964
+ summary: z14.string().optional()
2836
2965
  }).optional(),
2837
2966
  /** WHAT THIS CARD ANSWERS (owner, 2026-10-27, Goal 81b6a9d6: "this reads very clearly as an answer to
2838
2967
  * something I asked, but I don't see the question… To show the question near the top of the card").
2839
2968
  * An agent's card that is its answer to one of the person's own questions carries that question's
2840
2969
  * words, drawn above it as "You asked" (`public.questions_answered_by`, read beside the card read).
2841
2970
  * 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(),
2971
+ answering: z14.object({ asked: z14.string() }).optional(),
2972
+ /** WHEN ITS AGENT LAST BUMPED THIS QUESTION (#2855, `contact`'s `bumpQuestionIds`): the agent asked
2973
+ * the person to notice it again, and For you puts it first, the latest bump on top
2974
+ * (`question/order.ts`). Absent on a question never bumped, and on every card from an API older
2975
+ * than the bump. */
2976
+ bumpedAt: z14.string().optional(),
2843
2977
  /** The user's locked-in answer; present only for replied items (GET /api/replied/:id). */
2844
2978
  answer: UserAnswerSchema.optional(),
2845
2979
  /** THE TARGET FACTS A CARD RENDERS (#1796 point 5, 2026-09-11): the Delivery it is a view of,
@@ -2847,17 +2981,17 @@ var InboxItemSchema = z12.object({
2847
2981
  * for a request that asks nothing), whether its content is sealed, and that Goal's state. The
2848
2982
  * answer writer (`POST /api/entries`) and the disposition (`close_delivery`) take their ids from
2849
2983
  * here. The server projects it (`apps/api/src/inbox/project.ts`); a client never builds it. */
2850
- communication: z12.object({
2851
- deliveryId: z12.string(),
2852
- kind: z12.enum(["notification", "call"]),
2853
- entryId: z12.string(),
2854
- goalIds: z12.array(z12.string()),
2855
- decisionNeedId: z12.string().optional(),
2856
- sealed: z12.boolean(),
2857
- goalState: z12.string().optional(),
2984
+ communication: z14.object({
2985
+ deliveryId: z14.string(),
2986
+ kind: z14.enum(["notification", "call"]),
2987
+ entryId: z14.string(),
2988
+ goalIds: z14.array(z14.string()),
2989
+ decisionNeedId: z14.string().optional(),
2990
+ sealed: z14.boolean(),
2991
+ goalState: z14.string().optional(),
2858
2992
  /** THAT GOAL'S NAME (#2416) — what Activity's row is headed by, since a row there is one Goal
2859
2993
  * and the cards it holds sit behind it. Stamped by the same read as `goalState`. */
2860
- goalTitle: z12.string().optional()
2994
+ goalTitle: z14.string().optional()
2861
2995
  }).optional(),
2862
2996
  /** WHAT THIS CARD IS, IN TWELVE CHARACTERS (#3019) — the hash of every other field on it, stamped
2863
2997
  * by the one read that serves the open list (`apps/api/src/inbox/project.ts` `inboxFor`). It is
@@ -2866,30 +3000,30 @@ var InboxItemSchema = z12.object({
2866
3000
  *
2867
3001
  * THE PAYLOAD'S OWN HASH, NEVER A STAMP ON THE WORK — the same mechanism as `QueueItem.rev`
2868
3002
  * (#2928) and an entry's (#3018), for the same reason: a card shows facts no `updated_at` of its
2869
- * own moves (its Goal's state and name, how cold the work behind it has gone, whether a ring is
3003
+ * own moves (its Goal's state and name, whether a ring is
2870
3004
  * live). Optional, so a fixture, the demo and the archive lens need not spell one, and a card
2871
3005
  * with no rev is simply always re-sent. */
2872
- rev: z12.string().optional()
3006
+ rev: z14.string().optional()
2873
3007
  });
2874
3008
  var APNS_TOKEN_RE = /^[0-9a-fA-F]{64}$/;
2875
- var PushTokenSchema = z12.object({
2876
- voipToken: z12.string().min(1).optional(),
2877
- alertToken: z12.string().min(1).optional(),
2878
- fcmToken: z12.string().min(1).optional(),
2879
- platform: z12.enum(["ios", "android"])
3009
+ var PushTokenSchema = z14.object({
3010
+ voipToken: z14.string().min(1).optional(),
3011
+ alertToken: z14.string().min(1).optional(),
3012
+ fcmToken: z14.string().min(1).optional(),
3013
+ platform: z14.enum(["ios", "android"])
2880
3014
  }).superRefine((v, ctx) => {
2881
3015
  if (v.platform !== "ios") return;
2882
3016
  for (const field of ["voipToken", "alertToken"]) {
2883
3017
  const token = v[field];
2884
3018
  if (token === void 0 || APNS_TOKEN_RE.test(token)) continue;
2885
3019
  ctx.addIssue({
2886
- code: z12.ZodIssueCode.custom,
3020
+ code: z14.ZodIssueCode.custom,
2887
3021
  path: [field],
2888
3022
  message: `not an APNs device token (want 64 hex chars, got ${token.length})`
2889
3023
  });
2890
3024
  }
2891
3025
  });
2892
- var MissedCallSchema = z12.enum([
3026
+ var MissedCallSchema = z14.enum([
2893
3027
  "retry_10m",
2894
3028
  "retry_30m",
2895
3029
  "retry_60m",
@@ -2902,31 +3036,31 @@ var MissedCallSchema = z12.enum([
2902
3036
  var clock = (h) => h === 0 ? "midnight" : h === 12 ? "noon" : h < 12 ? `${h} am` : `${h - 12} pm`;
2903
3037
  var QUIET = ` Nothing rings from ${clock(NIGHT.from)} to ${clock(NIGHT.to)} your time; the count waits for morning.`;
2904
3038
  var THEIR_QUIET = ` Nothing rings from ${clock(NIGHT.from)} to ${clock(NIGHT.to)} their time; the count waits for morning.`;
2905
- var BrokerTuningSchema = z12.object({
3039
+ var BrokerTuningSchema = z14.object({
2906
3040
  /** 'none' = skip the spoken ack after a mapped answer (power users find it slow). */
2907
- ackVerbosity: z12.enum(["normal", "none"]).optional(),
3041
+ ackVerbosity: z14.enum(["normal", "none"]).optional(),
2908
3042
  /** How readily the mapper asks its one clarification: 'low' = only when truly
2909
3043
  * uninterpretable, 'high' = whenever not fully certain. */
2910
- clarifyEagerness: z12.enum(["low", "normal", "high"]).optional(),
3044
+ clarifyEagerness: z14.enum(["low", "normal", "high"]).optional(),
2911
3045
  /** The user's own shorthand: when they say `say`, they mean `mean`. */
2912
- phrasebook: z12.array(z12.object({ say: z12.string().min(1).max(60), mean: z12.string().min(1).max(120) })).max(24).optional(),
3046
+ phrasebook: z14.array(z14.object({ say: z14.string().min(1).max(60), mean: z14.string().min(1).max(120) })).max(24).optional(),
2913
3047
  /** The language calls are PLANNED in, when the account has chosen one (#1272). Absent —
2914
3048
  * which is every account today — means the agent's own words decide, per ask: a call
2915
3049
  * about an English ask opens in English. This is the only thing that overrides that,
2916
3050
  * and a live caller who switches language mid-call still outranks it (broker/lang.ts).
2917
3051
  * Set per user (no UI yet), like `voiceTuning`. */
2918
- language: z12.enum(["en", "es"]).optional()
3052
+ language: z14.enum(["en", "es"]).optional()
2919
3053
  });
2920
- var UserSettingsSchema = z12.object({
2921
- permissions: z12.object({
2922
- call: z12.boolean(),
2923
- banner: z12.boolean(),
2924
- push: z12.boolean()
3054
+ var UserSettingsSchema = z14.object({
3055
+ permissions: z14.object({
3056
+ call: z14.boolean(),
3057
+ banner: z14.boolean(),
3058
+ push: z14.boolean()
2925
3059
  }),
2926
3060
  /** LockedIn / Default / DateNight on screen; the stored words are unchanged on purpose —
2927
3061
  * they are an enum on a live column across every account, and the rename is a rename of
2928
3062
  * what people read (owner, 2026-09-30). */
2929
- sessionMode: z12.enum(["default", "all_calls", "silent"]),
3063
+ sessionMode: z14.enum(["default", "all_calls", "silent"]),
2930
3064
  /** `silentPush` lived here until #2813 and is now GONE, field and column both. It was kept as an
2931
3065
  * optional long after DateNight stopped reading it, on the theory that a phone on an older
2932
3066
  * bundle PATCHing the whole settings object would be REFUSED for sending a key we had stopped
@@ -2935,7 +3069,7 @@ var UserSettingsSchema = z12.object({
2935
3069
  * an old bundle's `silentPush` is accepted and ignored. Worth remembering before keeping the
2936
3070
  * next dead field for the same reason. */
2937
3071
  /** Opt-in (default false) to using your content to improve Paigy and train models. */
2938
- improveConsent: z12.boolean(),
3072
+ improveConsent: z14.boolean(),
2939
3073
  missedCall: MissedCallSchema.default("backoff_standard"),
2940
3074
  /** Where voice audio is processed. 'hosted' (default) = Paigy's voice services
2941
3075
  * (ElevenLabs TTS, faster-whisper STT, the call bot); 'on_device' = the phone
@@ -2943,17 +3077,14 @@ var UserSettingsSchema = z12.object({
2943
3077
  * Optional, NOT defaulted: a stale client PATCHing the full settings object
2944
3078
  * must not silently reset this privacy choice. Absent = leave unchanged on
2945
3079
  * write, 'hosted' on read (see store.ts). */
2946
- voiceMode: z12.enum(["hosted", "on_device"]).optional(),
2947
- /** Talk — after you answer, the next step is read aloud (docs/clients/app/walk/design.md §6). ALWAYS ON until
2948
- * turned off (owner, 2026-09-18, #2249): a setting, not a per-walk toggle. Optional, NOT
2949
- * defaulted, for the same reason `voiceMode` is: a stale client PATCHing the full settings
2950
- * object must not silently turn it back on. Absent = leave unchanged on write, true on
2951
- * read (see store.ts). */
2952
- talk: z12.boolean().optional(),
3080
+ voiceMode: z14.enum(["hosted", "on_device"]).optional(),
3081
+ /** `talk` lived here until #2373: it gated auto-play, which went in #2374. An older bundle's
3082
+ * `talk` is stripped like `silentPush` was, and the `user_settings.talk` column went in
3083
+ * 20261028142255. */
2953
3084
  /** CALL DIAGNOSTICS (owner, 2026-10-01): the call report carries each listen and the bot's own
2954
3085
  * load timings. SERVER-SET, no UI — on for every account that existed on 2026-10-01, off for
2955
3086
  * newer ones (migration 20261001132859). Read-only here: the settings PATCH never writes it. */
2956
- callDiagnostics: z12.boolean().optional(),
3087
+ callDiagnostics: z14.boolean().optional(),
2957
3088
  /** Per-user ring budget (#603): calls per rolling day before further calls
2958
3089
  * degrade to banner. Absent = the global default (25). A number, never a
2959
3090
  * bypass — every account keeps a ceiling. No UI; set per user for testing. */
@@ -2961,7 +3092,7 @@ var UserSettingsSchema = z12.object({
2961
3092
  * payload['tuning'] (e.g. { silence_s: 3.5 } — a longer pause window for a
2962
3093
  * slower speaker). No API-side semantics; the bot resolves each key with its
2963
3094
  * own defaults. Set per user (no UI yet); absent = bot defaults. */
2964
- voiceTuning: z12.record(z12.string(), z12.union([z12.number(), z12.string()])).optional(),
3095
+ voiceTuning: z14.record(z14.string(), z14.union([z14.number(), z14.string()])).optional(),
2965
3096
  /** The user's IANA timezone (e.g. "America/Bogota"), recorded by the app — it is the
2966
3097
  * only party that knows it. REMINDERS are why it exists: "remind me at ten" becomes
2967
3098
  * an absolute `due_at` only if we know whose ten. Optional and never defaulted, for
@@ -2970,71 +3101,71 @@ var UserSettingsSchema = z12.object({
2970
3101
  * that failure reads as the reminder rail being unreliable rather than as a missing
2971
3102
  * setting. Absent = a spoken time can't be landed, so the reminder rides the next
2972
3103
  * call — honest about what we know. */
2973
- timezone: z12.string().min(1).max(64).optional(),
3104
+ timezone: z14.string().min(1).max(64).optional(),
2974
3105
  /** Rung-2 broker tuning (#381). Optional and NOT defaulted, same stale-client
2975
3106
  * clobber guard as voiceMode: absent = leave unchanged on write. */
2976
3107
  broker: BrokerTuningSchema.optional()
2977
3108
  });
2978
- var GoalLatestSchema = z12.object({
2979
- from: z12.enum(["person", "agent"]),
2980
- said: z12.string(),
2981
- at: z12.string(),
2982
- entryId: z12.string(),
3109
+ var GoalLatestSchema = z14.object({
3110
+ from: z14.enum(["person", "agent"]),
3111
+ said: z14.string(),
3112
+ at: z14.string(),
3113
+ entryId: z14.string(),
2983
3114
  /** ITS SUMMARY IN AT MOST TEN WORDS (owner, 2026-10-08: "the same switch to the more summarized sources
2984
3115
  * at the work tab top level screen too"): what the talker or filer wrote on the Entry; absent when
2985
3116
  * none was. The Work row reads it before `said`. */
2986
- summary: z12.string().optional(),
3117
+ summary: z14.string().optional(),
2987
3118
  /** AN AGENT'S UPDATE OR QUESTION AS ITS UNITS' TITLES (owner, 2026-10-08: "send the 50 chars from the title
2988
3119
  * of each unit"): each at most 50 characters, in order; absent when it has none. */
2989
- titles: z12.array(z12.string()).optional(),
3120
+ titles: z14.array(z14.string()).optional(),
2990
3121
  /** A PROGRESS NOTE'S ONE POINT ("An agent's progress note -> maybe let's cap it at 200 chars"): the
2991
3122
  * update's own line, before its units; the row caps it at 200. Absent on anything else. */
2992
- line: z12.string().optional()
3123
+ line: z14.string().optional()
2993
3124
  });
2994
- var HistoryWorkSchema = z12.object({
2995
- id: z12.string(),
2996
- title: z12.string(),
2997
- state: z12.enum(["done", "cancelled"]),
3125
+ var HistoryWorkSchema = z14.object({
3126
+ id: z14.string(),
3127
+ title: z14.string(),
3128
+ state: z14.enum(["done", "cancelled"]),
2998
3129
  /** Who held it (`agent:<tokenId>` or `human:<userId>`). */
2999
- assignee: z12.string(),
3130
+ assignee: z14.string(),
3000
3131
  latest: GoalLatestSchema.nullable().optional()
3001
3132
  });
3002
- var HistoryEntrySchema = z12.union([
3003
- z12.object({ at: z12.string(), card: InboxItemSchema }),
3004
- z12.object({ at: z12.string(), work: HistoryWorkSchema })
3133
+ var HistoryEntrySchema = z14.union([
3134
+ z14.object({ at: z14.string(), card: InboxItemSchema }),
3135
+ z14.object({ at: z14.string(), work: HistoryWorkSchema })
3005
3136
  ]);
3006
- var HistoryPageSchema = z12.object({
3007
- entries: z12.array(HistoryEntrySchema),
3008
- next: z12.string().nullable()
3137
+ var HistoryPageSchema = z14.object({
3138
+ entries: z14.array(HistoryEntrySchema),
3139
+ next: z14.string().nullable()
3009
3140
  });
3010
3141
  var ACTIVITY_LINES = 2;
3011
3142
  var ACTIVITY_LINE_MAX = 80;
3012
- var AgentActivitySchema = z12.object({
3143
+ var AgentActivitySchema = z14.object({
3013
3144
  /** Oldest first, so the newest line is last — the one that replaces in place. */
3014
- lines: z12.array(z12.string().max(ACTIVITY_LINE_MAX)).max(ACTIVITY_LINES),
3145
+ lines: z14.array(z14.string().max(ACTIVITY_LINE_MAX)).max(ACTIVITY_LINES),
3015
3146
  /** When the harness observed this tail. Its own timestamp, not the heartbeat's: a beat
3016
3147
  * that carries an UNCHANGED tail must not make a stalled agent look like it just moved. */
3017
- at: z12.string().datetime()
3148
+ at: z14.string().datetime()
3018
3149
  });
3019
- var ConnectionSummarySchema = z12.object({
3150
+ var ConnectionSummarySchema = z14.object({
3020
3151
  /** The connection = the agent's token id (used to address a request). */
3021
- id: z12.string(),
3152
+ id: z14.string(),
3022
3153
  /** The credential kind: "device" = a paired machine (mint-only — it hosts and mints, it
3023
3154
  * never talks); "agent" = an identity that sends. The roster and devices surfaces split
3024
3155
  * on this. Optional/absent reads as "agent" (a row predating the kind column). See
3025
3156
  * docs/server/tokens/devices-vs-agents-design.md. */
3026
- kind: z12.enum(["device", "agent"]).optional(),
3157
+ kind: z14.enum(["device", "agent"]).optional(),
3027
3158
  /** For an agent, the token id of the DEVICE that minted it — so agents group under their
3028
3159
  * machine, and revoking a device cascades to them. Null on devices, and on unlinked
3029
3160
  * agents (provider-managed, hatched by another agent, or minted before the link existed);
3030
3161
  * a phone-launched agent is linked to the computer it runs on since #1602. */
3031
- mintedByDevice: z12.string().nullable().optional(),
3032
- device: z12.string().nullable(),
3162
+ mintedByDevice: z14.string().nullable().optional(),
3163
+ device: z14.string().nullable(),
3033
3164
  /** The agent's display name (the single pairing name). */
3034
- name: z12.string(),
3165
+ name: z14.string(),
3035
3166
  /** For a managed connection, the provider key (e.g. "cma") that agentOrigin maps to a
3036
3167
  * label; null for a local connection. Sourced from the token's provider, not the name. */
3037
- provider: z12.string().nullable(),
3168
+ provider: z14.string().nullable(),
3038
3169
  /** The pairing's assigned voice (#462); null = the default voice. */
3039
3170
  voice: VoiceKeySchema.nullable(),
3040
3171
  /** The LOUDEST this agent may ever reach you — a ceiling on `NOTIFY_LADDER`, set by the
@@ -3045,34 +3176,40 @@ var ConnectionSummarySchema = z12.object({
3045
3176
  * every surface at once and outranks even `sessionMode: all_calls` — a mode the user
3046
3177
  * set once must not overrule a rule they set about one agent. */
3047
3178
  reach: NotifyLevelSchema.nullable().optional(),
3048
- createdAt: z12.string().datetime(),
3179
+ createdAt: z14.string().datetime(),
3049
3180
  /** Most recent notification on this connection, either direction. Null = no contact yet.
3050
3181
  * Drives the agents-page recency grouping (Today / This week / …). */
3051
- lastContactAt: z12.string().datetime().nullable(),
3182
+ lastContactAt: z14.string().datetime().nullable(),
3052
3183
  /** Last presence heartbeat from a running agent process (POST /api/presence) — the
3053
3184
  * desktop app while open. Null = never seen; stale = offline. */
3054
- lastSeenAt: z12.string().datetime().nullable().optional(),
3185
+ lastSeenAt: z14.string().datetime().nullable().optional(),
3055
3186
  /** WORKING, NOT JUST CONNECTED (owner, 2026-09-30): the last time the agent itself acted on one of
3056
3187
  * its Goals — wrote on one or recorded an operation (`tokens.last_worked_at`). Within
3057
3188
  * `WORKING_MS` it is working; otherwise it is connected but idle. Null = not seen working yet. */
3058
- lastWorkedAt: z12.string().datetime().nullable().optional(),
3189
+ lastWorkedAt: z14.string().datetime().nullable().optional(),
3190
+ /** A TERMINAL SESSION'S ONLY PULSE (`tokens.listened_at`): `paigy-listen` stamps it on every sweep
3191
+ * (90 s). It is deliberately NOT presence — `last_seen_at` is the desktop host's beat, and a
3192
+ * listener orphaned from a dead conversation must not light the live dot — but it is the one fact
3193
+ * that says a terminal session's process is UP, which is why the wake already reads it
3194
+ * (`wake.ts`, `listener`). Null = no listener sweeping. */
3195
+ listenedAt: z14.string().datetime().nullable().optional(),
3059
3196
  /** The oldest of its Goals that is `ready` for it — work handed to it that nobody has started.
3060
3197
  * With no work of its own for `WORKING_MS`, an agent sitting on this is not taking its work. */
3061
- oldestReadyAt: z12.string().datetime().nullable().optional(),
3198
+ oldestReadyAt: z14.string().datetime().nullable().optional(),
3062
3199
  /** What a live desktop can run (docs/clients/desktop/companion.md §2.2), advertised on its heartbeat:
3063
3200
  * harness availabilities + granted workspaces — the option set the phone's
3064
3201
  * "new session" sheet offers. Absent for ordinary MCP agents. */
3065
- runtime: z12.object({
3202
+ runtime: z14.object({
3066
3203
  /** The @paigy/harness this host is running — a machine the self-update has not reached
3067
3204
  * shows its age here (`apps/desktop/src/update.ts`). */
3068
- version: z12.string().optional(),
3069
- harnesses: z12.array(z12.object({ name: z12.string(), label: z12.string(), status: z12.string(), models: z12.array(z12.string()).optional() })).optional(),
3070
- workspaces: z12.array(z12.string()).optional(),
3205
+ version: z14.string().optional(),
3206
+ harnesses: z14.array(z14.object({ name: z14.string(), label: z14.string(), status: z14.string(), models: z14.array(z14.string()).optional() })).optional(),
3207
+ workspaces: z14.array(z14.string()).optional(),
3071
3208
  /** THE GIT REPOS IN THOSE FOLDERS (2026-10-01, Goal 26982211): each granted folder that is a
3072
3209
  * repo, and each repo directly inside one, with its `origin` remote. A session started for
3073
3210
  * work on `mauurda/paigy` opens in that repo rather than the folder above it, where the repo's
3074
3211
  * own AGENTS.md is never read (`workspaceForRepo`). Absent on hosts that predate it. */
3075
- repos: z12.array(z12.object({ path: z12.string(), remote: z12.string() })).optional()
3212
+ repos: z14.array(z14.object({ path: z14.string(), remote: z14.string() })).optional()
3076
3213
  }).optional(),
3077
3214
  /** The tail of this agent's working log, when a harness is driving it — the agent page's
3078
3215
  * live strip. Absent for anything the desktop harness isn't running (a hatched identity
@@ -3081,151 +3218,151 @@ var ConnectionSummarySchema = z12.object({
3081
3218
  activity: AgentActivitySchema.optional(),
3082
3219
  /** True = a provider-managed agent running in the provider's cloud (e.g. Anthropic CMA);
3083
3220
  * false = a local MCP connection running on the user's computer (Claude Code/Codex/…). */
3084
- managed: z12.boolean()
3221
+ managed: z14.boolean()
3085
3222
  });
3086
- var LedgerItemSchema = z12.object({ id: z12.string(), parentId: z12.string(), title: z12.string(), createdAt: z12.string() });
3087
- var AgentLedgerSchema = z12.object({
3223
+ var LedgerItemSchema = z14.object({ id: z14.string(), parentId: z14.string(), title: z14.string(), createdAt: z14.string() });
3224
+ var AgentLedgerSchema = z14.object({
3088
3225
  /** Null when the agent has not named itself yet — never a placeholder (owner, 2026-10-01). */
3089
- agent: z12.object({ id: z12.string(), name: z12.string().nullable(), revokedAt: z12.string().nullable() }),
3226
+ agent: z14.object({ id: z14.string(), name: z14.string().nullable(), revokedAt: z14.string().nullable() }),
3090
3227
  /** Its own questions you have not answered. */
3091
- asks: z12.array(LedgerItemSchema),
3228
+ asks: z14.array(LedgerItemSchema),
3092
3229
  /** Its questions you answered that nobody acted on — still owed to somebody. */
3093
- answered: z12.array(LedgerItemSchema),
3230
+ answered: z14.array(LedgerItemSchema),
3094
3231
  /** Requests you sent it that it never took. */
3095
- requests: z12.array(LedgerItemSchema),
3096
- goals: z12.array(z12.object({ id: z12.string(), outcome: z12.string(), state: z12.string() })),
3097
- callbacks: z12.array(z12.object({ id: z12.string(), parentId: z12.string(), trigger: z12.string(), note: z12.string(), dueAt: z12.string().nullable() }))
3232
+ requests: z14.array(LedgerItemSchema),
3233
+ goals: z14.array(z14.object({ id: z14.string(), outcome: z14.string(), state: z14.string() })),
3234
+ callbacks: z14.array(z14.object({ id: z14.string(), parentId: z14.string(), trigger: z14.string(), note: z14.string(), dueAt: z14.string().nullable() }))
3098
3235
  });
3099
- var ReassignResultSchema = z12.object({
3100
- moved: z12.object({ asks: z12.number(), answered: z12.number(), requests: z12.number(), goals: z12.number(), callbacks: z12.number() }),
3101
- parentId: z12.string().nullable()
3236
+ var ReassignResultSchema = z14.object({
3237
+ moved: z14.object({ asks: z14.number(), answered: z14.number(), requests: z14.number(), goals: z14.number(), callbacks: z14.number() }),
3238
+ parentId: z14.string().nullable()
3102
3239
  });
3103
- var LessonStateSchema = z12.enum(["active", "proposed", "retired"]);
3104
- var LessonViewSchema = z12.object({
3105
- id: z12.string(),
3106
- text: z12.string(),
3240
+ var LessonStateSchema = z14.enum(["active", "proposed", "retired"]);
3241
+ var LessonViewSchema = z14.object({
3242
+ id: z14.string(),
3243
+ text: z14.string(),
3107
3244
  state: LessonStateSchema,
3108
3245
  /** The Goal it is scoped to; null = the whole account. */
3109
- scopeGoalId: z12.string().nullable(),
3110
- goalTitle: z12.string().nullable(),
3111
- version: z12.number(),
3112
- pinned: z12.boolean(),
3246
+ scopeGoalId: z14.string().nullable(),
3247
+ goalTitle: z14.string().nullable(),
3248
+ version: z14.number(),
3249
+ pinned: z14.boolean(),
3113
3250
  /** When the person last wrote its text themselves. */
3114
- editedAt: z12.string().nullable(),
3115
- createdAt: z12.string(),
3116
- updatedAt: z12.string(),
3251
+ editedAt: z14.string().nullable(),
3252
+ createdAt: z14.string(),
3253
+ updatedAt: z14.string(),
3117
3254
  /** The Entries it came from, oldest first; `words` is null when an Entry has none to show (sealed). */
3118
- sources: z12.array(z12.object({ entryId: z12.string(), words: z12.string().nullable(), at: z12.string() }))
3255
+ sources: z14.array(z14.object({ entryId: z14.string(), words: z14.string().nullable(), at: z14.string() }))
3119
3256
  });
3120
- var QueueQuestionSchema = z12.object({
3257
+ var QueueQuestionSchema = z14.object({
3121
3258
  /** The decision need's id — what an answer is accepted against. */
3122
- id: z12.string(),
3259
+ id: z14.string(),
3123
3260
  /** The words that were asked, from the request Entry that asked them. */
3124
- question: z12.string(),
3261
+ question: z14.string(),
3125
3262
  /** Where it was asked — which is where the ruling goes (`POST /api/entries`). Null only
3126
3263
  * for a need whose request Entry is carried by no interactive Delivery, which nothing
3127
3264
  * can answer. */
3128
- deliveryId: z12.string().nullable().default(null),
3265
+ deliveryId: z14.string().nullable().default(null),
3129
3266
  /** The Entry the ruling is about. */
3130
- aboutId: z12.string().nullable().default(null),
3267
+ aboutId: z14.string().nullable().default(null),
3131
3268
  /** Empty for a free-text question. */
3132
- options: z12.array(OptionSchema).default([]),
3133
- select: z12.enum(["one", "many", "rank", "confirm", "text"]).default("text"),
3134
- askedAt: z12.string(),
3269
+ options: z14.array(OptionSchema).default([]),
3270
+ select: z14.enum(["one", "many", "rank", "confirm", "text"]).default("text"),
3271
+ askedAt: z14.string(),
3135
3272
  /** Null while the question is open — which is how the page tells the two apart. */
3136
- answeredAt: z12.string().nullable().default(null),
3273
+ answeredAt: z14.string().nullable().default(null),
3137
3274
  /** The ruling in the person's own words, from the contribution that replied — not the
3138
3275
  * option id, which is not something anyone reads back. Null while it is open, and null
3139
3276
  * for a settled question whose reply carried nothing readable. */
3140
- answer: z12.string().nullable().default(null),
3277
+ answer: z14.string().nullable().default(null),
3141
3278
  /** The Goal this question belongs to — a step knows its Goal on its own, not only through
3142
3279
  * an `InboxItem`'s `communication.goalIds[0]` (docs/clients/app/walk/design.md §12 item 3).
3143
3280
  * READ BY `apps/client/src/walk/order.ts`, which stamps it onto every `WalkStep`: the walk's
3144
3281
  * order, its route, home's trees and the list of steps all take a step's Goal from here, so
3145
3282
  * this is the field they agree through rather than each re-deriving it from the row it
3146
3283
  * arrived under. Required because the API projects it on every need it sends. */
3147
- goalId: z12.string(),
3284
+ goalId: z14.string(),
3148
3285
  /** True only while an unmet START gate holds the Goal — a Goal that merely waits to
3149
3286
  * *finish* does not stop a person from answering (owner, 2026-09-16: "per need gate from
3150
3287
  * the API"; §4's dashed node). Not the same fact as `QueueItem.blocked`, which counts any
3151
3288
  * gate at all. */
3152
- blocked: z12.boolean().default(false)
3289
+ blocked: z14.boolean().default(false)
3153
3290
  });
3154
- var QueueReplySchema = z12.object({
3291
+ var QueueReplySchema = z14.object({
3155
3292
  /** The card this note was (`deliveryId:requestEntryId`, minted by the server like every card
3156
3293
  * id) — so the phone can tell a reply it just sent from one the queue already carries, and the
3157
3294
  * walk can name it in its zoom. */
3158
- id: z12.string(),
3295
+ id: z14.string(),
3159
3296
  /** The Goal the note is on. */
3160
- goalId: z12.string(),
3297
+ goalId: z14.string(),
3161
3298
  /** What the note said. */
3162
- note: z12.string(),
3299
+ note: z14.string(),
3163
3300
  /** Where it was carried — where a second reply goes (`POST /api/entries`, #2252). */
3164
- deliveryId: z12.string(),
3165
- requestEntryId: z12.string(),
3166
- askedAt: z12.string(),
3301
+ deliveryId: z14.string(),
3302
+ requestEntryId: z14.string(),
3303
+ askedAt: z14.string(),
3167
3304
  /** When the person last replied — the window's start. */
3168
- repliedAt: z12.string(),
3305
+ repliedAt: z14.string(),
3169
3306
  /** The person's latest words about it; null when there is nothing readable in them. */
3170
- reply: z12.string().nullable()
3307
+ reply: z14.string().nullable()
3171
3308
  });
3172
- var QueueItemSchema = z12.object({
3173
- id: z12.string(),
3309
+ var QueueItemSchema = z14.object({
3310
+ id: z14.string(),
3174
3311
  /** One-line headline — the first sentence of the outcome. */
3175
- title: z12.string(),
3312
+ title: z14.string(),
3176
3313
  /** The outcome in full, verbatim: the person's own words are what an assignee sees. */
3177
- intent: z12.string(),
3314
+ intent: z14.string(),
3178
3315
  /** `ready` | `active` | `waiting` | `done` | `cancelled`, straight off the Goal. */
3179
- state: z12.string(),
3316
+ state: z14.string(),
3180
3317
  /** Who holds it (a participant ref); null when nobody does yet. */
3181
- assignee: z12.string().nullable().default(null),
3318
+ assignee: z14.string().nullable().default(null),
3182
3319
  /** What the agent last said it was doing; null if it has said nothing. */
3183
- progress: z12.string().nullable().default(null),
3320
+ progress: z14.string().nullable().default(null),
3184
3321
  /** HOME'S LINE FOR THAT NOTE (owner, 2026-09-23): a few plain words one read wrote from `progress`,
3185
3322
  * served only while it was written for the current note. Null means show the Goal's name. */
3186
- progressLine: z12.string().nullable().optional(),
3187
- reviewPending: z12.boolean().default(false),
3188
- dueAt: z12.string().nullable().default(null),
3323
+ progressLine: z14.string().nullable().optional(),
3324
+ reviewPending: z14.boolean().default(false),
3325
+ dueAt: z14.string().nullable().default(null),
3189
3326
  /** WHEN ITS OWNER SAID DONE WHILE CHILDREN WERE OPEN (#2704): its own work is finished and it closes
3190
3327
  * with its last open child. Null otherwise; optional, so hand-built queues need not spell it. */
3191
- finishedAt: z12.string().nullable().optional(),
3328
+ finishedAt: z14.string().nullable().optional(),
3192
3329
  /** The Goal this one was opened under; null at the root. */
3193
- parentGoalId: z12.string().nullable().default(null),
3330
+ parentGoalId: z14.string().nullable().default(null),
3194
3331
  /** Goals opened under this one — only those the same list holds. */
3195
- childGoalIds: z12.array(z12.string()).default([]),
3332
+ childGoalIds: z14.array(z14.string()).default([]),
3196
3333
  /** Goals this one waits on (start or finish gates). */
3197
- dependencyGoalIds: z12.array(z12.string()).default([]),
3334
+ dependencyGoalIds: z14.array(z14.string()).default([]),
3198
3335
  /** True while any gate is on a Goal that is not done — the walk draws it dashed. */
3199
- blocked: z12.boolean().default(false),
3336
+ blocked: z14.boolean().default(false),
3200
3337
  /** Its questions: every OPEN one, and at most ten settled, newest settled first
3201
3338
  * (20260929133308) — the page decides which of them to show. NOT the whole set: `asked` and
3202
3339
  * `answered` are, and a settled one's words are a line (280 characters), its body read when the
3203
3340
  * question is opened. Never a CANCELLED one (withdrawn, dismissed, or its Goal or call ended): it
3204
3341
  * asks nothing of anyone (#3723). */
3205
- questions: z12.array(QueueQuestionSchema).default([]),
3342
+ questions: z14.array(QueueQuestionSchema).default([]),
3206
3343
  /** HOW MANY QUESTIONS THIS WORK HAS ASKED, and how many are answered — the Goal's own totals,
3207
3344
  * bounded at 100 server-side. A tally counted off `questions` is a wrong number that looks
3208
3345
  * right once the cap bites (`walk/trees.ts` `tallyOf`). Optional, and defaulted from the array
3209
3346
  * by the projection, so hand-built queues (fixtures, the demo) need not spell them. A cancelled
3210
3347
  * question is not asked (#3725). */
3211
- asked: z12.number().optional(),
3212
- answered: z12.number().optional(),
3348
+ asked: z14.number().optional(),
3349
+ answered: z14.number().optional(),
3213
3350
  /** Every note on it the person replied to (`QueueReplySchema`) — the page decides which to show.
3214
3351
  * Optional, not defaulted: absent is none, and every hand-built queue (fixtures, the demo) need
3215
3352
  * not spell an empty list. */
3216
- replies: z12.array(QueueReplySchema).optional(),
3353
+ replies: z14.array(QueueReplySchema).optional(),
3217
3354
  /** The repository or project identifier this Goal belongs to (#2280), null if untracked. */
3218
- repo: z12.string().nullable().optional(),
3219
- createdAt: z12.string(),
3220
- updatedAt: z12.string().nullable().default(null),
3355
+ repo: z14.string().nullable().optional(),
3356
+ createdAt: z14.string(),
3357
+ updatedAt: z14.string().nullable().default(null),
3221
3358
  /** When its owner last SAID something about it (the newest `progress` Entry: a contact update kept
3222
3359
  * as progress). `updatedAt` moves for reasons nobody chose — a
3223
3360
  * state recomputed, a review flag — so it cannot tell work in hand from work gone quiet. */
3224
- lastProgressAt: z12.string().nullable().optional(),
3361
+ lastProgressAt: z14.string().nullable().optional(),
3225
3362
  /** WHEN AN AGENT LAST ACTED ON IT (owner, 2026-10-27: "Move it now", Goal 567258dc): its newest agent write, an
3226
3363
  * Entry or a Goal change, Paigy's excluded (`goals.worked_at`). What keeps work an agent is writing on from
3227
3364
  * reading as gone quiet (`coldSince`); absent on a door that does not carry it. */
3228
- workedAt: z12.string().nullable().optional(),
3365
+ workedAt: z14.string().nullable().optional(),
3229
3366
  /** THE GOAL'S NEWEST WORD, FROM EITHER SIDE (owner, 2026-09-27): the newest Entry on it, of any
3230
3367
  * kind — what the person added ("Add to this"), their reply, the agent's ask or its progress
3231
3368
  * note. A progress note is an Entry, so this is already the newer of the two: the person's note
@@ -3244,7 +3381,7 @@ var QueueItemSchema = z12.object({
3244
3381
  * minute after the person speaks erases their instant from it, and the durable traces the client
3245
3382
  * can see (`replies`, `questions[].answeredAt`) miss a spontaneous note entirely — a `request`
3246
3383
  * Entry with no `about_id` is in neither. */
3247
- lastPersonAt: z12.string().nullable().optional(),
3384
+ lastPersonAt: z14.string().nullable().optional(),
3248
3385
  /** EACH SIDE'S NEWEST WORD IN THE LAST DAY (owner, 2026-10-13, the Work tab's order): the person's
3249
3386
  * (`yours`) and the agents' (`theirs`), each null when that side wrote nothing on it in 24 hours.
3250
3387
  * `latest` holds one Entry, so whichever side wrote first is hidden there; Work orders a Goal by
@@ -3262,40 +3399,40 @@ var QueueItemSchema = z12.object({
3262
3399
  * the row shows that no `updated_at` moves for (`active` lapsing, a dependency's state, a
3263
3400
  * sibling appearing in `childGoalIds`) cannot go unnoticed. Optional because a hand-built
3264
3401
  * queue (a fixture, the demo) spells none, and a row with no rev is simply always re-sent. */
3265
- rev: z12.string().optional()
3402
+ rev: z14.string().optional()
3266
3403
  });
3267
- var QueueDeltaSchema = z12.object({
3268
- ids: z12.array(z12.string()),
3269
- items: z12.array(QueueItemSchema)
3404
+ var QueueDeltaSchema = z14.object({
3405
+ ids: z14.array(z14.string()),
3406
+ items: z14.array(QueueItemSchema)
3270
3407
  });
3271
3408
  var COLD_AFTER_MS = 3 * 24 * 60 * 60 * 1e3;
3272
- var NoteSourceSchema = z12.enum(["app", "call"]);
3273
- var NoteStatusSchema = z12.enum(["open", "assigned", "in_progress", "done"]);
3274
- var NoteRepeatSchema = z12.enum(["once", "until_done"]);
3275
- var DecisionSchema = z12.object({
3276
- id: z12.string(),
3409
+ var NoteSourceSchema = z14.enum(["app", "call"]);
3410
+ var NoteStatusSchema = z14.enum(["open", "assigned", "in_progress", "done"]);
3411
+ var NoteRepeatSchema = z14.enum(["once", "until_done"]);
3412
+ var DecisionSchema = z14.object({
3413
+ id: z14.string(),
3277
3414
  /** The note this decision refines; null = recorded on a bare thread (the
3278
3415
  * extensibility seam — any conversation can accrue decisions). */
3279
- noteId: z12.string().nullable(),
3416
+ noteId: z14.string().nullable(),
3280
3417
  /** What was ambiguous — the broker's (or the user's own) question. */
3281
- question: z12.string(),
3418
+ question: z14.string(),
3282
3419
  /** The user's ruling; null while the question is open. */
3283
- answer: z12.string().nullable(),
3284
- decidedAt: z12.string().nullable(),
3285
- createdAt: z12.string()
3420
+ answer: z14.string().nullable(),
3421
+ decidedAt: z14.string().nullable(),
3422
+ createdAt: z14.string()
3286
3423
  });
3287
- var NoteSchema = z12.object({
3288
- id: z12.string(),
3424
+ var NoteSchema = z14.object({
3425
+ id: z14.string(),
3289
3426
  /** One-line headline (broker-titled; deterministic floor). */
3290
- title: z12.string(),
3427
+ title: z14.string(),
3291
3428
  /** The original intent, verbatim — assignees always see the user's own words. */
3292
- intent: z12.string(),
3429
+ intent: z14.string(),
3293
3430
  source: NoteSourceSchema,
3294
3431
  status: NoteStatusSchema,
3295
3432
  /** Who it was assigned to (a participant ref, 'agent:<tokenId>'); null = unassigned. */
3296
- assignee: z12.string().nullable(),
3433
+ assignee: z14.string().nullable(),
3297
3434
  /** The request thread minted at assignment; null until assigned. */
3298
- parentId: z12.string().nullable(),
3435
+ parentId: z14.string().nullable(),
3299
3436
  /** REMINDERS (docs/model/notes/reminders-design.md): the NOT-BEFORE this becomes eligible to ride a
3300
3437
  * call — never a deadline. It only ever comes from the user's own words, so when it
3301
3438
  * passes Paigy rings ONCE (#1293, owner 2026-08-26: a time said out loud is consent to
@@ -3304,102 +3441,102 @@ var NoteSchema = z12.object({
3304
3441
  // Defaulted, not required: a Note from an API deploy older than the reminders
3305
3442
  // migration has none of these, and the defaults ARE what it means — no not-before,
3306
3443
  // one ride, never ridden. Parsing must not fail across a rolling deploy.
3307
- dueAt: z12.string().nullable().default(null),
3444
+ dueAt: z14.string().nullable().default(null),
3308
3445
  repeat: NoteRepeatSchema.default("once"),
3309
3446
  /** How many calls have already carried it — the fatigue cap counts rides, not days. */
3310
- rides: z12.number().int().default(0),
3311
- lastRideAt: z12.string().nullable().default(null),
3312
- createdAt: z12.string()
3447
+ rides: z14.number().int().default(0),
3448
+ lastRideAt: z14.string().nullable().default(null),
3449
+ createdAt: z14.string()
3313
3450
  });
3314
- var DeliveryModeSchema = z12.enum(["poll", "self_hosted"]);
3451
+ var DeliveryModeSchema = z14.enum(["poll", "self_hosted"]);
3315
3452
  var WAKE_EVENT = "wake";
3316
3453
  var wakeChannel = (tokenId) => `wake:${tokenId}`;
3317
- var RegisterDeliverySchema = z12.object({ mode: DeliveryModeSchema });
3318
- var OAuthStartSchema = z12.object({
3319
- provider: z12.enum(["cma"]),
3320
- returnTo: z12.string().min(1)
3454
+ var RegisterDeliverySchema = z14.object({ mode: DeliveryModeSchema });
3455
+ var OAuthStartSchema = z14.object({
3456
+ provider: z14.enum(["cma"]),
3457
+ returnTo: z14.string().min(1)
3321
3458
  });
3322
- var DeliveryConfigSchema = z12.object({
3323
- tokenId: z12.string(),
3459
+ var DeliveryConfigSchema = z14.object({
3460
+ tokenId: z14.string(),
3324
3461
  mode: DeliveryModeSchema,
3325
3462
  /** null when the deployment has no anon key configured. `self_hosted` is then REFUSED
3326
3463
  * (503 `self_hosted_unavailable`) rather than registered, so a self_hosted config always
3327
3464
  * carries credentials; only a `poll` registration can come back with null here. */
3328
- realtime: z12.object({ url: z12.string(), anonKey: z12.string() }).nullable()
3465
+ realtime: z14.object({ url: z14.string(), anonKey: z14.string() }).nullable()
3329
3466
  });
3330
- var HostDecisionSchema = z12.object({
3467
+ var HostDecisionSchema = z14.object({
3331
3468
  /** The agent's token id: the row's `recipient`. */
3332
- agent: z12.string().uuid(),
3333
- decision: z12.enum(["stood_back", "took_over"]),
3469
+ agent: z14.string().uuid(),
3470
+ decision: z14.enum(["stood_back", "took_over"]),
3334
3471
  /** The work it was about: the Goal waiting on that agent next (`claimable` on its `contact({})` read). */
3335
- goalId: z12.string().uuid().nullable().optional(),
3472
+ goalId: z14.string().uuid().nullable().optional(),
3336
3473
  /** When the server last heard from the agent, as the host read it: the presence it stood back for. */
3337
- seenAt: z12.string().datetime().nullable().optional(),
3474
+ seenAt: z14.string().datetime().nullable().optional(),
3338
3475
  /** When that work last moved (`claimable.since` on an agent's `contact({})` read), the fact the bound is judged on. */
3339
- since: z12.string().datetime().nullable().optional(),
3476
+ since: z14.string().datetime().nullable().optional(),
3340
3477
  /** What the host said, in its log's own words: why it stood back, or what the take-over did. */
3341
- said: z12.string().max(300).optional()
3478
+ said: z14.string().max(300).optional()
3342
3479
  });
3343
- var WakeNudgeSchema = z12.object({
3344
- kind: z12.enum(["reply", "request", "callback"]),
3345
- notificationId: z12.string().optional(),
3346
- parentId: z12.string()
3480
+ var WakeNudgeSchema = z14.object({
3481
+ kind: z14.enum(["reply", "request", "callback"]),
3482
+ notificationId: z14.string().optional(),
3483
+ parentId: z14.string()
3347
3484
  });
3348
- var PairingStatusSchema = z12.enum(["pending", "approved", "denied", "expired"]);
3349
- var DeviceCodeSchema = z12.object({
3350
- device_code: z12.string(),
3351
- user_code: z12.string(),
3352
- verification_uri: z12.string().url(),
3353
- verification_uri_complete: z12.string().url(),
3354
- interval: z12.number(),
3355
- expires_in: z12.number()
3485
+ var PairingStatusSchema = z14.enum(["pending", "approved", "denied", "expired"]);
3486
+ var DeviceCodeSchema = z14.object({
3487
+ device_code: z14.string(),
3488
+ user_code: z14.string(),
3489
+ verification_uri: z14.string().url(),
3490
+ verification_uri_complete: z14.string().url(),
3491
+ interval: z14.number(),
3492
+ expires_in: z14.number()
3356
3493
  });
3357
- var DeviceInfoSchema = z12.object({
3358
- code: z12.string(),
3494
+ var DeviceInfoSchema = z14.object({
3495
+ code: z14.string(),
3359
3496
  /** The agent's suggested name (from /device/code) — shown on the approval screen,
3360
3497
  * pre-filling the name field the human can edit. */
3361
- name: z12.string(),
3498
+ name: z14.string(),
3362
3499
  /** @deprecated Legacy alias of `name` for the pre-#531 embedded bundle in App Store
3363
3500
  * build 35, whose DeviceFlow renders `info.agent.slice(0, 2)` — without this a FRESH
3364
3501
  * install crashes on the pairing screen on first launch, before the OTA lands
3365
3502
  * (seen live: PAIGY-5T, 2026-07-21). Remove once a newer binary is the floor. */
3366
- agent: z12.string().optional(),
3367
- device: z12.string().nullable(),
3503
+ agent: z14.string().optional(),
3504
+ device: z14.string().nullable(),
3368
3505
  status: PairingStatusSchema
3369
3506
  });
3370
- var DeviceTokenSchema = z12.object({
3371
- access_token: z12.string(),
3507
+ var DeviceTokenSchema = z14.object({
3508
+ access_token: z14.string(),
3372
3509
  /** The pairing's single name (user-typed at approval, the agent's suggestion, or
3373
3510
  * a default silly name). */
3374
- name: z12.string(),
3375
- device: z12.string().nullable(),
3511
+ name: z14.string(),
3512
+ device: z14.string().nullable(),
3376
3513
  /** The pairing's assigned voice, cached so the desktop can seed the SAME face the phone
3377
3514
  * draws — voice is the third ingredient of a hatchling's build (party/traits.ts). */
3378
- voice: z12.string().nullable().optional(),
3515
+ voice: z14.string().nullable().optional(),
3379
3516
  /** The token's server-side id — the face's COLOUR anchor, and the only seed ingredient
3380
3517
  * that survives a rename. Cached by the host's identity beat. */
3381
- token_id: z12.string().nullable().optional(),
3518
+ token_id: z14.string().nullable().optional(),
3382
3519
  /** WHERE this identity works — the folder a wake should land it in. Written by the host
3383
3520
  * at spawn and by `paigy-harness handoff` from a live terminal. Without it every wake
3384
3521
  * landed in the FIRST granted workspace and the agent rediscovered its own repo from
3385
3522
  * the thread each time (host.ts, live catch 2026-08-06 — prompt-papered until now). */
3386
- workspace: z12.string().nullable().optional(),
3523
+ workspace: z14.string().nullable().optional(),
3387
3524
  /** Local host recovery must preserve the launch's runtime and Paigy identity. */
3388
- harness: z12.enum(["claude", "codex", "agy"]).optional(),
3389
- session_id: z12.string().uuid().optional(),
3525
+ harness: z14.enum(["claude", "codex", "agy", "grok"]).optional(),
3526
+ session_id: z14.string().uuid().optional(),
3390
3527
  /** A conversation the host must not resume: its context is full, so every turn fails
3391
3528
  * ("Prompt is too long"). Written when a run hits it (`run.ts` `onFull`); the host skips a slot
3392
3529
  * whose resumable session is this one, so its Goals reach the dead-agent handoff instead of a
3393
3530
  * copy that types the person's words into a turn that cannot run (Calls, 2026-10-06). */
3394
- full_session: z12.string().optional(),
3395
- uik_pub: z12.string().nullable().optional()
3531
+ full_session: z14.string().optional(),
3532
+ uik_pub: z14.string().nullable().optional()
3396
3533
  });
3397
- var SupportRequestSchema = z12.object({
3398
- email: z12.string().email().max(320),
3399
- message: z12.string().trim().min(1).max(5e3),
3400
- name: z12.string().trim().max(120).optional()
3534
+ var SupportRequestSchema = z14.object({
3535
+ email: z14.string().email().max(320),
3536
+ message: z14.string().trim().min(1).max(5e3),
3537
+ name: z14.string().trim().max(120).optional()
3401
3538
  });
3402
- var NotificationFeedbackKindSchema = z12.enum([
3539
+ var NotificationFeedbackKindSchema = z14.enum([
3403
3540
  "break_down",
3404
3541
  // "This should be more than one ask — break it down."
3405
3542
  "regenerate_options",
@@ -3414,136 +3551,133 @@ var NotificationFeedbackKindSchema = z12.enum([
3414
3551
  // anything else — the note carries it.
3415
3552
  ]);
3416
3553
  var SlimOptionSchema = OptionSchema.omit({ html: true });
3417
- var QuestionRowSchema = z12.object({
3554
+ var QuestionRowSchema = z14.object({
3418
3555
  /** The card's id (`deliveryId:needId`, or `deliveryId:entryId` for an update), as the inbox mints it. */
3419
- id: z12.string(),
3420
- deliveryId: z12.string(),
3421
- entryId: z12.string(),
3556
+ id: z14.string(),
3557
+ deliveryId: z14.string(),
3558
+ entryId: z14.string(),
3422
3559
  /** The decision it waits on; null for an update, which asks nothing. */
3423
- needId: z12.string().nullable(),
3424
- goalIds: z12.array(z12.string()),
3560
+ needId: z14.string().nullable(),
3561
+ goalIds: z14.array(z14.string()),
3425
3562
  /** The name of the work it is about, when the read could word it. */
3426
- goalTitle: z12.string().optional(),
3427
- tokenId: z12.string().optional(),
3428
- name: z12.string(),
3429
- title: z12.string(),
3430
- body: z12.string(),
3431
- select: z12.enum(["one", "many", "rank", "confirm", "text"]),
3432
- options: z12.array(SlimOptionSchema),
3433
- hasPreview: z12.boolean(),
3434
- blocking: z12.boolean(),
3435
- askedAt: z12.string().datetime(),
3563
+ goalTitle: z14.string().optional(),
3564
+ tokenId: z14.string().optional(),
3565
+ name: z14.string(),
3566
+ title: z14.string(),
3567
+ body: z14.string(),
3568
+ select: z14.enum(["one", "many", "rank", "confirm", "text"]),
3569
+ options: z14.array(SlimOptionSchema),
3570
+ hasPreview: z14.boolean(),
3571
+ blocking: z14.boolean(),
3572
+ askedAt: z14.string().datetime(),
3436
3573
  ring: InboxItemSchema.shape.ring,
3437
- onCall: z12.literal(true).optional(),
3438
- sealed: z12.boolean()
3574
+ onCall: z14.literal(true).optional(),
3575
+ sealed: z14.boolean()
3439
3576
  });
3440
- var WorkStateSchema = z12.enum(["ready", "active", "waiting", "done", "cancelled"]);
3441
- var WorkRowSchema = z12.object({
3442
- id: z12.string(),
3443
- parentId: z12.string().nullable(),
3444
- title: z12.string(),
3577
+ var WorkStateSchema = z14.enum(["ready", "active", "waiting", "done", "cancelled"]);
3578
+ var WorkRowSchema = z14.object({
3579
+ id: z14.string(),
3580
+ parentId: z14.string().nullable(),
3581
+ title: z14.string(),
3445
3582
  /** Straight off the Goal. */
3446
3583
  state: WorkStateSchema,
3447
- owner: z12.string().nullable(),
3448
- revision: z12.number().int(),
3584
+ owner: z14.string().nullable(),
3585
+ revision: z14.number().int(),
3449
3586
  /** Open questions on it, counted to 100. */
3450
- waiting: z12.number().int(),
3587
+ waiting: z14.number().int(),
3451
3588
  /** Held by a gate on work that is not done. */
3452
- blocked: z12.boolean(),
3453
- lastProgressAt: z12.string().datetime().nullable(),
3589
+ blocked: z14.boolean(),
3590
+ lastProgressAt: z14.string().datetime().nullable(),
3454
3591
  /** The line written for its newest progress note, else that note's first words. */
3455
- line: z12.string().nullable(),
3592
+ line: z14.string().nullable(),
3456
3593
  /** Work directly under it, counted to 100; the list carries up to 12 of them. */
3457
- children: z12.number().int(),
3458
- createdAt: z12.string().datetime(),
3459
- updatedAt: z12.string().datetime(),
3594
+ children: z14.number().int(),
3595
+ createdAt: z14.string().datetime(),
3596
+ updatedAt: z14.string().datetime(),
3460
3597
  /** When anything at or under it last moved — the order the list is in. */
3461
- activeAt: z12.string().datetime(),
3598
+ activeAt: z14.string().datetime(),
3462
3599
  /** A sealed outcome has no title here; the work's page opens it. */
3463
- sealed: z12.boolean()
3600
+ sealed: z14.boolean()
3464
3601
  });
3465
3602
  var ComputerRowSchema = ConnectionSummarySchema.omit({ activity: true });
3466
3603
  var AgentRowSchema = ComputerRowSchema.extend({
3467
3604
  /** Open questions it is asking the person, over every open card; null when that read failed. */
3468
- asking: z12.number().int().nullable(),
3469
- oldestAskAt: z12.string().datetime().nullable(),
3605
+ asking: z14.number().int().nullable(),
3606
+ oldestAskAt: z14.string().datetime().nullable(),
3470
3607
  /** Up to three of the live Goals it holds, oldest first (the order it picks them up), and how
3471
3608
  * many in all among the account's 200 most recently active agent-held live Goals
3472
3609
  * (`agent_holds`); null when that read failed. */
3473
- holds: z12.array(z12.object({ id: z12.string(), title: z12.string() })).nullable(),
3474
- held: z12.number().int().nullable(),
3475
- /** The earliest instant any Goal it holds went quiet, by the one rule (`coldSince`); null
3476
- * while none has, or when that read failed. */
3477
- cold: z12.string().datetime().nullable(),
3610
+ holds: z14.array(z14.object({ id: z14.string(), title: z14.string() })).nullable(),
3611
+ held: z14.number().int().nullable(),
3478
3612
  /** The newest line of its working log, and when the harness saw it. */
3479
- line: z12.string().nullable(),
3480
- lineAt: z12.string().datetime().nullable()
3613
+ line: z14.string().nullable(),
3614
+ lineAt: z14.string().datetime().nullable()
3481
3615
  });
3482
- var SnapshotSchema = z12.object({
3616
+ var SnapshotSchema = z14.object({
3483
3617
  /** The API's clock, taken before the first read: what a later delta will start from. */
3484
- at: z12.string().datetime(),
3485
- questions: z12.object({
3618
+ at: z14.string().datetime(),
3619
+ questions: z14.object({
3486
3620
  /** The newest 30 open cards, questions before updates. */
3487
- items: z12.array(QuestionRowSchema),
3621
+ items: z14.array(QuestionRowSchema),
3488
3622
  /** Every open question, and apart from them every update, and what was put off. */
3489
- total: z12.number().int(),
3490
- updates: z12.number().int(),
3491
- putOff: z12.number().int()
3623
+ total: z14.number().int(),
3624
+ updates: z14.number().int(),
3625
+ putOff: z14.number().int()
3492
3626
  }).nullable(),
3493
- agents: z12.object({
3627
+ agents: z14.object({
3494
3628
  /** Up to 60, most recently seen first. */
3495
- items: z12.array(AgentRowSchema),
3496
- more: z12.boolean()
3629
+ items: z14.array(AgentRowSchema),
3630
+ more: z14.boolean()
3497
3631
  }).nullable(),
3498
- work: z12.object({
3632
+ work: z14.object({
3499
3633
  /** The 60 most recently active roots, each followed by up to 12 children; 240 rows at most. */
3500
- items: z12.array(WorkRowSchema),
3634
+ items: z14.array(WorkRowSchema),
3501
3635
  /** How much work is behind each of the Work tab's four filters, each counted to 100, read with
3502
3636
  * the rows. `work_list` (20260928023533) owns the predicates: Live is `ready`, `active` or
3503
3637
  * `waiting`; Waiting on you is live work with an open question or an unmet gate; Not started
3504
3638
  * is `ready`; Done is `done` or `cancelled`. */
3505
- counts: z12.object({ live: z12.number().int(), waiting: z12.number().int(), notStarted: z12.number().int(), done: z12.number().int() })
3639
+ counts: z14.object({ live: z14.number().int(), waiting: z14.number().int(), notStarted: z14.number().int(), done: z14.number().int() })
3506
3640
  }).nullable(),
3507
- you: z12.object({
3641
+ you: z14.object({
3508
3642
  settings: UserSettingsSchema,
3509
- callable: z12.boolean(),
3643
+ callable: z14.boolean(),
3510
3644
  /** Up to 20 paired computers; null when the roster read failed. */
3511
- computers: z12.array(ComputerRowSchema).nullable()
3645
+ computers: z14.array(ComputerRowSchema).nullable()
3512
3646
  }).nullable()
3513
3647
  });
3514
- var CallRecapSchema = z12.object({
3515
- call: z12.object({
3516
- status: z12.string(),
3517
- startedAt: z12.string(),
3518
- durationMs: z12.number().nullable(),
3648
+ var CallRecapSchema = z14.object({
3649
+ call: z14.object({
3650
+ status: z14.string(),
3651
+ startedAt: z14.string(),
3652
+ durationMs: z14.number().nullable(),
3519
3653
  /** Bot-clock pickup offset; absent before the timestamp release, null before its report lands. */
3520
- pickupMs: z12.number().nullable().optional(),
3654
+ pickupMs: z14.number().nullable().optional(),
3521
3655
  /** STILL FILING (20261026182117): the call has not ended on the server, or it has and a brain cycle on it is
3522
3656
  * still pending, the next writer, which may still settle, file or start something. What the close itself
3523
3657
  * waits for (`private.close_call`). `status` cannot say it: nothing writes "finalizing", and a call reads
3524
3658
  * "open" until the sweep closes it, after nothing is pending. Absent from an API before it. */
3525
- filing: z12.boolean().optional(),
3526
- agents: z12.array(z12.object({ id: z12.string(), name: z12.string().nullable() }))
3659
+ filing: z14.boolean().optional(),
3660
+ agents: z14.array(z14.object({ id: z14.string(), name: z14.string().nullable() }))
3527
3661
  }),
3528
- topics: z12.array(z12.object({
3529
- goalId: z12.string().uuid(),
3530
- title: z12.string(),
3531
- owner: z12.string(),
3532
- state: z12.string(),
3662
+ topics: z14.array(z14.object({
3663
+ goalId: z14.string().uuid(),
3664
+ title: z14.string(),
3665
+ owner: z14.string(),
3666
+ state: z14.string(),
3533
3667
  /** Presented Entry content and its author, separately from the current Goal owner. */
3534
- items: z12.array(z12.object({ entryId: z12.string(), author: z12.string(), text: z12.string(), summary: z12.string().nullable(), acknowledged: z12.boolean().optional() })).optional(),
3668
+ items: z14.array(z14.object({ entryId: z14.string(), author: z14.string(), text: z14.string(), summary: z14.string().nullable(), acknowledged: z14.boolean().optional() })).optional(),
3535
3669
  /** Whether the call put it to the person. An item it carried and never said has no row on the
3536
3670
  * review (owner, 2026-10-08: "why do we get the third one when it didn't happen in the call?"). */
3537
- presented: z12.boolean(),
3671
+ presented: z14.boolean(),
3538
3672
  /** Whether THIS call created it — the third way a call touches work, beside carrying a request
3539
3673
  * there and filing words there (owner, 2026-10-08, Goal `5b4b1a0a`: "Show the new work, keep my
3540
3674
  * words under it"). Created work is never carried, so it is never `presented`; without this the
3541
3675
  * row is dropped by the "only what happened on the call" filter. False on a database before
3542
3676
  * 20261013080133. */
3543
- created: z12.boolean(),
3677
+ created: z14.boolean(),
3544
3678
  /** `request` is the Entry that asked it — what a line's `about` names when the line answered or put
3545
3679
  * it off. Optional: an older API sent none. */
3546
- questions: z12.array(z12.object({ id: z12.string().uuid(), state: z12.string(), title: z12.string(), request: z12.string().optional() })),
3680
+ questions: z14.array(z14.object({ id: z14.string().uuid(), state: z14.string(), title: z14.string(), request: z14.string().optional() })),
3547
3681
  /** `words` is always what they SAID, verbatim — the record, never replaced. `summary` is what
3548
3682
  * the line says in ten words (owner, 2026-10-07): the filer's, or the talker's for the answer it
3549
3683
  * gave, so the row scans like a chosen option and their own words stay under it. Absent when
@@ -3553,34 +3687,34 @@ var CallRecapSchema = z12.object({
3553
3687
  /** `reply` is the reply the line makes up (an answer, an ok, a deferral), so one reply is one row
3554
3688
  * however many lines it cites; `at` is the call lines it came from, so a filed line an answer already
3555
3689
  * said is not drawn again (owner, 2026-10-07: "fix them all"); `replyKind` says which replies are answers. */
3556
- lines: z12.array(z12.object({
3557
- entryId: z12.string().uuid(),
3558
- words: z12.string(),
3559
- summary: z12.string().optional(),
3560
- about: z12.string().nullable().optional(),
3561
- reply: z12.string().nullable().optional(),
3562
- replyKind: z12.string().nullable().optional(),
3563
- at: z12.array(z12.number()).optional()
3690
+ lines: z14.array(z14.object({
3691
+ entryId: z14.string().uuid(),
3692
+ words: z14.string(),
3693
+ summary: z14.string().optional(),
3694
+ about: z14.string().nullable().optional(),
3695
+ reply: z14.string().nullable().optional(),
3696
+ replyKind: z14.string().nullable().optional(),
3697
+ at: z14.array(z14.number()).optional()
3564
3698
  }))
3565
3699
  })),
3566
- unfiled: z12.array(z12.object({ lineId: z12.string().uuid(), words: z12.string(), atMs: z12.number() })),
3700
+ unfiled: z14.array(z14.object({ lineId: z14.string().uuid(), words: z14.string(), atMs: z14.number() })),
3567
3701
  /** THE PUBLIC TRANSCRIPT — every line said on the call, in the order it was said, and WHO SAID IT
3568
3702
  * (owner, 2026-10-08: "the public view should only have the lines and who said them, and that's
3569
3703
  * it"; `docs/brain/phase-three/modular.md` build step 3). `speaker` is the role: "user" is the
3570
3704
  * person, "agent" an agent speaking, named in `agent`. The timeline's action lines are ours, not
3571
3705
  * theirs, and are not here; nor is a sealed line, which the server has no words for. It stands
3572
3706
  * BESIDE `topics` and `unfiled` — what the call did with the words — never instead of them. */
3573
- said: z12.array(z12.object({
3574
- lineId: z12.string().uuid(),
3575
- speaker: z12.enum(["user", "agent"]),
3576
- agent: z12.object({ id: z12.string().nullable(), name: z12.string().nullable() }).nullable(),
3577
- words: z12.string(),
3578
- atMs: z12.number()
3707
+ said: z14.array(z14.object({
3708
+ lineId: z14.string().uuid(),
3709
+ speaker: z14.enum(["user", "agent"]),
3710
+ agent: z14.object({ id: z14.string().nullable(), name: z14.string().nullable() }).nullable(),
3711
+ words: z14.string(),
3712
+ atMs: z14.number()
3579
3713
  })),
3580
3714
  /** 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() }),
3715
+ more: z14.object({ lines: z14.number(), entries: z14.number(), topics: z14.number(), settles: z14.number().optional() }),
3582
3716
  /** Last stored position on this page when another exists; absent before paging shipped. */
3583
- next: z12.number().int().nonnegative().nullable().optional(),
3717
+ next: z14.number().int().nonnegative().nullable().optional(),
3584
3718
  /** THE CALL AS ONE LIST OF ROWS (owner, 2026-10-14: "we only really want a thing like transcript but
3585
3719
  * built from the summaries", then "the transcript tabs should show the same but with full words").
3586
3720
  * Both tabs draw these rows, in this order: Summary from `summary`, Transcript from `words`.
@@ -3591,32 +3725,32 @@ var CallRecapSchema = z12.object({
3591
3725
  * `by` is the row's real author, never inferred from `kind`: a relay Paigy sent to an agent is
3592
3726
  * Paigy's, not the person's. Optional and additive (owner: "make sure whatever you do is backward
3593
3727
  * compatible"): an API before it sends none, and the screen falls back to `topics` and `said`. */
3594
- timeline: z12.array(z12.object({
3595
- id: z12.string(),
3596
- position: z12.number(),
3597
- atMs: z12.number(),
3598
- kind: z12.enum(["put", "said", "did"]),
3599
- by: z12.object({ participant: z12.string().nullable(), agentId: z12.string().nullable(), name: z12.string().nullable() }),
3600
- goalId: z12.string().uuid().nullable(),
3601
- requestId: z12.string().nullable(),
3602
- summary: z12.string().nullable(),
3603
- words: z12.string(),
3728
+ timeline: z14.array(z14.object({
3729
+ id: z14.string(),
3730
+ position: z14.number(),
3731
+ atMs: z14.number(),
3732
+ kind: z14.enum(["put", "said", "did"]),
3733
+ by: z14.object({ participant: z14.string().nullable(), agentId: z14.string().nullable(), name: z14.string().nullable() }),
3734
+ goalId: z14.string().uuid().nullable(),
3735
+ requestId: z14.string().nullable(),
3736
+ summary: z14.string().nullable(),
3737
+ words: z14.string(),
3604
3738
  /** Paigy's sentences folded into this row: on a `put` row, what it said putting the item to the
3605
3739
  * person (before their next row); on a `said` row, what it said in reply (until their next row).
3606
3740
  * `atMs` is when each was said; optional, absent before 2026-10-14's fix. */
3607
- spoken: z12.array(z12.object({ lineId: z12.string(), words: z12.string(), atMs: z12.number().optional() })),
3741
+ spoken: z14.array(z14.object({ lineId: z14.string(), words: z14.string(), atMs: z14.number().optional() })),
3608
3742
  /** On a `said` row: the work these words were filed on, and whether they answered (recorded) a
3609
3743
  * question. They replace the "Filed on ..." and "Recorded: ..." rows that repeated the person's own
3610
3744
  * summary (Brain, 2026-10-14). Optional: absent from an API before it. */
3611
- filedOn: z12.array(z12.object({ goalId: z12.string().uuid(), title: z12.string() })).optional(),
3612
- recorded: z12.boolean().optional(),
3613
- settled: z12.object({ requestId: z12.string(), answer: z12.string() }).nullable().optional(),
3614
- acknowledged: z12.boolean().optional(),
3745
+ filedOn: z14.array(z14.object({ goalId: z14.string().uuid(), title: z14.string() })).optional(),
3746
+ recorded: z14.boolean().optional(),
3747
+ settled: z14.object({ requestId: z14.string(), answer: z14.string() }).nullable().optional(),
3748
+ acknowledged: z14.boolean().optional(),
3615
3749
  /** On a `put` row: still waiting for the person's answer (not settled, not answered, not put off).
3616
3750
  * The server's judgement; the screen draws "Still waiting for your answer" from it. Optional: absent
3617
3751
  * from an API before it, where the screen falls back to its own reading. */
3618
- waiting: z12.boolean().optional(),
3619
- lineIds: z12.array(z12.string())
3752
+ waiting: z14.boolean().optional(),
3753
+ lineIds: z14.array(z14.string())
3620
3754
  })).optional(),
3621
3755
  /** THE RECAP (owner, 2026-10-26: "the transcript should just be the entries that settled or
3622
3756
  * acknowledged the items; that's it"). Each item the person's words settled on this call, in the
@@ -3628,13 +3762,13 @@ var CallRecapSchema = z12.object({
3628
3762
  * with `requestId` null and the Goal's name as `title`; a started Goal may have no `lines` yet. `kind`
3629
3763
  * is a string, not an enum, so a later kind never fails an older build's parse; `requestId` is the
3630
3764
  * 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() }))
3765
+ settles: z14.array(z14.object({
3766
+ requestId: z14.string().nullable(),
3767
+ kind: z14.string(),
3768
+ by: z14.object({ participant: z14.string(), agentId: z14.string().nullable(), name: z14.string() }),
3769
+ goalId: z14.string().uuid().nullable(),
3770
+ title: z14.string(),
3771
+ lines: z14.array(z14.object({ lineId: z14.string(), words: z14.string(), atMs: z14.number() }))
3638
3772
  })).optional()
3639
3773
  });
3640
3774
  function sessionSlot(sessionId2) {
@@ -3981,6 +4115,10 @@ async function checkActivity(opts = {}) {
3981
4115
  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.`;
3982
4116
  var APPLIED = "Applied; nothing was sent to the person.";
3983
4117
  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.";
4118
+ function citeOf(receipt) {
4119
+ if (!receipt.uncited?.length) return {};
4120
+ return { uncited: receipt.uncited, ...receipt.cite ? { cite: receipt.cite } : {} };
4121
+ }
3984
4122
  async function readDelivery(deliveryId, opts = {}) {
3985
4123
  const query = opts.transcript ? `?transcript=1${opts.after ? `&after=${encodeURIComponent(opts.after)}` : ""}` : "";
3986
4124
  const res = await ensureAuthed(await (opts.reach ?? reach)(`${BACKEND_URL}/api/deliveries/${encodeURIComponent(deliveryId)}${query}`, {
@@ -4008,6 +4146,7 @@ async function contact(input, opts = {}) {
4008
4146
  ...questions ? { questions } : {},
4009
4147
  ...parsed.answers ? { answers: parsed.answers } : {},
4010
4148
  ...parsed.withdrawQuestionIds ? { withdrawQuestionIds: parsed.withdrawQuestionIds } : {},
4149
+ ...parsed.bumpQuestionIds ? { bumpQuestionIds: parsed.bumpQuestionIds } : {},
4011
4150
  ...parsed.questionDependencies ? { questionDependencies: parsed.questionDependencies } : {}
4012
4151
  })
4013
4152
  }));
@@ -4021,7 +4160,7 @@ async function contact(input, opts = {}) {
4021
4160
  const demoted = askedCall && receipt.channel && receipt.channel !== "call" ? DEMOTED : void 0;
4022
4161
  const acked = acknowledged ? { acknowledged } : {};
4023
4162
  if (!deliveries.length) {
4024
- return { sent: false, ok, results, ...recorded.length ? { recorded } : {}, message: recorded.length ? NOT_SENT : APPLIED, waitOutcome: "not_waited", ...acked };
4163
+ return { sent: false, ok, results, ...recorded.length ? { recorded } : {}, message: recorded.length ? NOT_SENT : APPLIED, waitOutcome: "not_waited", ...acked, ...citeOf(receipt) };
4025
4164
  }
4026
4165
  const lead = deliveries.find((d) => d.kind === "question") ?? deliveries[0];
4027
4166
  const read3 = async (signal2) => {
@@ -4036,7 +4175,10 @@ async function contact(input, opts = {}) {
4036
4175
  // IT WENT ONTO A CALL ALREADY HAPPENING (owner, 2026-09-28): the view words it as that call.
4037
4176
  ...lead.joinedCall ? { joinedCall: true } : {},
4038
4177
  ...demoted ? { demoted } : {},
4039
- ...acked
4178
+ ...acked,
4179
+ ...receipt.ringPolicy ? { ringPolicy: receipt.ringPolicy, ...receipt.message ? { ringHeld: receipt.message } : {} } : {},
4180
+ ...receipt.recheckAt ? { recheckAt: receipt.recheckAt } : {},
4181
+ ...citeOf(receipt)
4040
4182
  };
4041
4183
  };
4042
4184
  const settled = (d) => d.state === "closed" || d.answers.length > 0 || d.entries.some((e) => e.kind === "contribution" && !entryUnit(e));
@@ -4150,7 +4292,7 @@ function stateOf(state, answer, decided2, withdrawn) {
4150
4292
  if (withdrawn && state === "answered") return "closed";
4151
4293
  return state === "answered" && answer && decided2 === void 0 ? "replied" : state;
4152
4294
  }
4153
- var handle = (entryId) => entryId.slice(0, 8);
4295
+ var handle2 = (entryId) => entryId.slice(0, 8);
4154
4296
  function conversation(e) {
4155
4297
  const answers = new Map((e.answers ?? []).map((a) => [a.decisionNeedId, a]));
4156
4298
  const shown = new Set((e.entries ?? []).map((entry) => entry.entryId));
@@ -4171,14 +4313,14 @@ function conversation(e) {
4171
4313
  const owed = need?.state === "open" && entry.authorParticipant.startsWith("human:");
4172
4314
  const re = thread(entry);
4173
4315
  return compact({
4174
- id: repliedTo.has(entry.entryId) || owed ? handle(entry.entryId) : void 0,
4316
+ id: repliedTo.has(entry.entryId) || owed ? handle2(entry.entryId) : void 0,
4175
4317
  from: who(entry.authorParticipant),
4176
4318
  at: at(entry.createdAt),
4177
4319
  said: sealed ? "[encrypted]" : entryWords(entry).trim(),
4178
4320
  caveat: entry.callOngoing ? "Call ongoing; what the person decides may change." : void 0,
4179
4321
  via: viaLine(entry.via),
4180
4322
  units: askUnits(entry, e.entries ?? []).map((u) => `${u.title}: ${u.body}`),
4181
- re: re ? handle(re) : void 0,
4323
+ re: re ? handle2(re) : void 0,
4182
4324
  options,
4183
4325
  decision: need ? compact({ state: stateOf(need.state, answer, decision, need.withdrawn), answer: decision, via: viaLine(answer?.via) }) : void 0
4184
4326
  });
@@ -4240,7 +4382,7 @@ var JOINED_CALL = "This joined the call the person is ALREADY ON \u2014 no ring,
4240
4382
  function failures(results) {
4241
4383
  const failed = (results ?? []).filter((r) => r.status === "failed");
4242
4384
  if (!failed.length) return void 0;
4243
- const plural = { update: "updates", completion: "completions", question: "questions", answer: "answers", withdraw: "withdrawQuestionIds", dependency: "questionDependencies" };
4385
+ const plural = { update: "updates", completion: "completions", question: "questions", answer: "answers", withdraw: "withdrawQuestionIds", bump: "bumpQuestionIds", dependency: "questionDependencies" };
4244
4386
  return `${failed.length} of ${(results ?? []).length} items did not apply; the rest did: ` + failed.map((r) => `${plural[r.kind]}[${r.index}] ${r.error}${r.detail ? ` (${r.detail})` : ""}`).join("; ") + ".";
4245
4387
  }
4246
4388
  var itemsView = (results) => (results ?? []).map((r) => compact({
@@ -4301,9 +4443,17 @@ function deliveryView(d) {
4301
4443
  callOutcome: d.callOutcome,
4302
4444
  waitOutcome: d.waitOutcome,
4303
4445
  acknowledged: d.acknowledged?.filter((a) => a.acknowledged).map((a) => a.eventId),
4446
+ // THE CALL IT PLACED WILL BE HELD (owner, 2026-10-27): the person's ring policy, and when the phone rings.
4447
+ ringPolicy: d.ringPolicy,
4448
+ // NO CALL WAS PLACED; THE ASKS WAIT ON THEIR CARDS (owner, 2026-10-27, Goal 2d147edd): when to check back.
4449
+ recheckAt: d.recheckAt,
4450
+ // THEIR WORDS NO UPDATE HAS NAMED YET (projects-design.md): the ids to put in causedBy next time.
4451
+ uncited: d.uncited,
4304
4452
  next: [
4305
4453
  failures(d.results),
4306
- d.joinedCall ? `${JOINED_CALL}${d.message ? ` ${d.message}` : ""}` : d.kind === "notification" ? `${d.demoted ? `${d.demoted} ` : ""}${d.joinedCard ? `Added to the open report card on its Goal; no new push was sent. ${answers}` : answers}` : pending ? `${d.demoted ? `${d.demoted} ` : ""}Decision pending on this call. ${d.waitOutcome === "expired" ? "Nothing was said in the window. " : ""}Wait for the answer with contact({wait:true}) \u2014 one bounded window each time, and never resend the question. While the Call is open, keep waiting window after window: a quiet window is the call still going, and the person may give you follow-ups or instructions on it. Once the Call has ended, stop waiting, leave any question open, and collect the answer with contact({wait:false}) or get_goals on your next wake. ${d.message ?? ""}`.trim() : d.message
4454
+ d.ringHeld,
4455
+ d.joinedCall ? `${JOINED_CALL}${d.message ? ` ${d.message}` : ""}` : d.recheckAt && d.ringHeld ? void 0 : d.kind === "notification" ? `${d.demoted ? `${d.demoted} ` : ""}${d.joinedCard ? `Added to the open report card on its Goal; no new push was sent. ${answers}` : answers}` : pending ? `${d.demoted ? `${d.demoted} ` : ""}Decision pending on this call. ${d.waitOutcome === "expired" ? "Nothing was said in the window. " : ""}Wait for the answer with contact({wait:true}) \u2014 one bounded window each time, and never resend the question. While the Call is open, keep waiting window after window: a quiet window is the call still going, and the person may give you follow-ups or instructions on it. Once the Call has ended, stop waiting, leave any question open, and collect the answer with contact({wait:false}) or get_goals on your next wake. ${d.message ?? ""}`.trim() : d.message,
4456
+ d.cite
4307
4457
  ].filter(Boolean).join(" ")
4308
4458
  });
4309
4459
  }
@@ -4314,7 +4464,9 @@ function notSentView(n) {
4314
4464
  results: itemsView(n.results),
4315
4465
  recorded: n.recorded,
4316
4466
  acknowledged: n.acknowledged?.filter((a) => a.acknowledged).map((a) => a.eventId),
4317
- next: [failures(n.results), n.message].filter(Boolean).join(" ")
4467
+ // THEIR WORDS NO UPDATE HAS NAMED YET (projects-design.md): the ids to put in causedBy next time.
4468
+ uncited: n.uncited,
4469
+ next: [failures(n.results), n.message, n.cite].filter(Boolean).join(" ")
4318
4470
  });
4319
4471
  }
4320
4472
  function quietDays(items, now) {
@@ -4460,6 +4612,11 @@ async function runTool(name, args, opts) {
4460
4612
  }
4461
4613
  case "search":
4462
4614
  return searchRecords(SearchToolSchema.parse(input), client);
4615
+ case "help": {
4616
+ const asked2 = HelpSchema.safeParse(input);
4617
+ if (!asked2.success) throw new Error(asked2.error.issues[0].message);
4618
+ return helpView(asked2.data);
4619
+ }
4463
4620
  default:
4464
4621
  throw new Error(`Unknown tool: ${name}`);
4465
4622
  }
@@ -4749,6 +4906,8 @@ export {
4749
4906
  acknowledge,
4750
4907
  pendingEvents,
4751
4908
  receiveContact,
4909
+ viaLine,
4910
+ decided,
4752
4911
  runTool,
4753
4912
  subscribeWake,
4754
4913
  parseDue,