@paigy/mcp 0.40.27 → 0.40.28

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.
@@ -12,10 +12,12 @@ import { z as z6 } from "zod";
12
12
  import { zodToJsonSchema as zodToJsonSchema4 } from "zod-to-json-schema";
13
13
  var OPTIONS_MIN = 2;
14
14
  var OPTIONS_MAX = 6;
15
+ var OPTION_LABEL_MAX = 50;
16
+ var OPTION_HINT_MAX = 200;
15
17
  var OptionSchema = z.object({
16
18
  id: z.string(),
17
19
  label: z.string(),
18
- hint: z.string().max(500).describe("Optional short projection of consequence or action if this option is chosen (e.g. 'Reruns test suite', 'Merges to main').").optional(),
20
+ hint: z.string().max(500).describe(`Optional: what choosing it does, at most ${OPTION_HINT_MAX} characters (e.g. 'Reruns test suite', 'Merges to main').`).optional(),
19
21
  // .describe() flows into the MCP contact JSON schema (zodToJsonSchema), so
20
22
  // the constraints below are what an agent reads when deciding to use these.
21
23
  html: z.string().max(16384).describe(
@@ -29,8 +31,10 @@ var OptionInputSchema = z.object({
29
31
  id: z.string().trim().min(1).max(64).regex(/^[A-Za-z0-9_.:-]+$/).optional().describe(
30
32
  `Optional: this option's own id, which answers name it by (selectedOptionIds). Give every option one, or none: without them the options are numbered "1", "2", \u2026 in order.`
31
33
  ),
32
- label: z.string().trim().min(1).max(1e3),
33
- hint: OptionSchema.shape.hint,
34
+ // SHORT CHOICES (owner, 2026-10-07: "options label should be maybe max 50 characters and the hint 200"):
35
+ // a label is one choice the person reads, or hears on a call; a hint says its consequence in a line.
36
+ label: z.string().trim().min(1).max(OPTION_LABEL_MAX, `option_label_too_long: an option's label is at most ${OPTION_LABEL_MAX} characters; say the choice, and put its consequence in the hint.`).describe(`The choice, at most ${OPTION_LABEL_MAX} characters, standing on its own.`),
37
+ hint: z.string().max(OPTION_HINT_MAX, `option_hint_too_long: an option's hint is at most ${OPTION_HINT_MAX} characters.`).describe(`Optional: what choosing it does, at most ${OPTION_HINT_MAX} characters (e.g. 'Reruns test suite', 'Merges to main').`).optional(),
34
38
  htmlPreview: OptionSchema.shape.html,
35
39
  imgUrl: OptionSchema.shape.image
36
40
  }).strict();
@@ -140,7 +144,7 @@ var questionFields = {
140
144
  ),
141
145
  goalId: z2.string().uuid().describe("The Goal the question is about, which must exist (create it with manage_goals first). Its answer comes back there."),
142
146
  units,
143
- options: z2.array(OptionInputSchema).min(1).max(6).optional().describe("The choices, when you have them. Each label stands on its own."),
147
+ options: z2.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."),
144
148
  // HOW THE OPTIONS ARE ANSWERED, SAID BY THE AGENT (owner, 2026-10-02: "one and many makes sense";
145
149
  // brain_prompts.md §1: structured agent questions need no model). The app draws all three.
146
150
  pickMode: z2.enum(["one", "many", "rank"]).optional().describe(
@@ -260,7 +264,8 @@ var UpdateGoalSchema = z3.object({
260
264
  }).strict();
261
265
  var changedGoal = z3.string().uuid().describe("The Goal to change, as a read shows it.");
262
266
  var goalTitle = z3.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.");
263
- var goalOutcome = z3.string().trim().min(1).max(1e4).describe("The full desired result. There is no third description field.");
267
+ var GOAL_OUTCOME_MAX = 500;
268
+ var goalOutcome = z3.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.`);
264
269
  var CreateChange = z3.object({
265
270
  kind: z3.literal("create"),
266
271
  title: goalTitle,
@@ -286,7 +291,7 @@ var DependencyChange = z3.object({
286
291
  goalId: changedGoal,
287
292
  dependsOnGoalId: z3.string().uuid().describe("The Goal it waits on."),
288
293
  action: z3.enum(["start", "complete"]).describe("What waits: starting goalId, or completing it."),
289
- reason: z3.string().trim().min(1).max(2e3).optional().describe("Why, as an explanation, never as policy.")
294
+ reason: z3.string().trim().min(1).max(250).optional().describe("Why, at most 250 characters, as an explanation, never as policy.")
290
295
  }).strict();
291
296
  var read = { revision: z3.number().int().positive().optional() };
292
297
  var GoalChangeSchema = z3.discriminatedUnion("kind", [
@@ -310,7 +315,7 @@ var ManageGoalsSchema = z3.object({
310
315
  var ManageGoalsToolSchema = z3.object({
311
316
  changes: z3.array(z3.discriminatedUnion("kind", [CreateChange, EditChange, StateChange, AssignChange, DeferChange, MoveChange, DependencyChange])).min(1).max(50).describe("The changes, applied in order, each on its own.")
312
317
  }).strict().superRefine((v, ctx) => editNames(v.changes, ctx));
313
- 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: 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; 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_goal) 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.";
318
+ 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: 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_goal) 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.";
314
319
  var GetGoalSchema = z3.object({
315
320
  goalId: z3.string().uuid(),
316
321
  /** Every entry in full. Without it the read carries the person's words, open questions and your
@@ -405,6 +410,7 @@ var QuestionChangeSchema = z4.union([
405
410
  z4.object({
406
411
  kind: z4.literal("create"),
407
412
  text: z4.string().min(1),
413
+ summary: z4.string().optional(),
408
414
  answererId: participant,
409
415
  goal: ResultRefSchema.optional(),
410
416
  blocks: z4.array(z4.object({ question: ResultRefSchema }).strict()),
@@ -455,12 +461,12 @@ var BrainSearchSchema = z4.object({
455
461
  }).strict();
456
462
  var BrainResultSchema = z4.object({
457
463
  messages: z4.array(BrainMessageSchema),
458
- entries: z4.array(z4.object({ key, sources: z4.array(SourceSchema).min(1), goals: z4.array(ResultRefSchema) }).strict()),
464
+ entries: z4.array(z4.object({ key, sources: z4.array(SourceSchema).min(1), goals: z4.array(ResultRefSchema), summary: z4.string().optional() }).strict()),
459
465
  questions: z4.array(z4.object({ key, entryKeys: z4.array(key), change: QuestionChangeSchema }).strict()),
460
466
  answers: z4.array(z4.object({
461
467
  question: ResultRefSchema,
462
468
  entryKeys: z4.array(key).min(1),
463
- summary: z4.string().min(1),
469
+ summary: z4.string(),
464
470
  selectedOptionIds: z4.array(z4.string().min(1)).optional()
465
471
  }).strict()),
466
472
  goals: z4.array(z4.object({ key, entryKeys: z4.array(key), change: BrainGoalChangeSchema }).strict()),
@@ -505,8 +511,9 @@ var TalkerReplySchema = z5.object({
505
511
  messages: z5.array(z5.object({ key: str2, to: str2, text: str2, about: strs2, blocks: str2 }).strict()),
506
512
  /** What the call does next: listen, hold (the person asked for a moment) or end (they asked to). */
507
513
  then: z5.enum(["listen", "hold", "end"]),
508
- /** Items the person's words settle: the item's handle, the chosen option IDs, the line handles. */
509
- answers: z5.array(z5.object({ item: str2, options: strs2, lines: strs2 }).strict()),
514
+ /** Items the person's words settle: the item's handle, the chosen option IDs, the line handles, and
515
+ * the answer in at most ten words, keeping any condition. */
516
+ answers: z5.array(z5.object({ item: str2, options: strs2, lines: strs2, summary: str2 }).strict()),
510
517
  /** The line handles that hold a new instruction from the person. */
511
518
  instruction: strs2,
512
519
  /** The line handles that ask for new work, a change to existing work, or a standing rule: the filer
@@ -523,8 +530,9 @@ var TALKER_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
523
530
  var str3 = z6.string();
524
531
  var strs3 = z6.array(z6.string());
525
532
  var FilerReplySchema = z6.object({
526
- /** Which Goals each new line goes on: a line's handle and Goal handles (or keys of new Goals). */
527
- filed: z6.array(z6.object({ line: str3, goals: strs3 }).strict()),
533
+ /** Which Goals each new line goes on: a line's handle, Goal handles (or keys of new Goals), and what
534
+ * the line says in at most ten words. */
535
+ filed: z6.array(z6.object({ line: str3, goals: strs3, summary: str3 }).strict()),
528
536
  goals: z6.array(z6.object({
529
537
  op: z6.enum(["create", "edit", "complete", "cancel", "reopen", "assign", "defer", "move", "block", "unblock"]),
530
538
  key: str3,
@@ -543,6 +551,7 @@ var FilerReplySchema = z6.object({
543
551
  key: str3,
544
552
  question: str3,
545
553
  text: str3,
554
+ summary: str3,
546
555
  to: str3,
547
556
  goal: str3,
548
557
  options: z6.array(z6.object({ id: str3, label: str3 }).strict()),
@@ -1262,7 +1271,7 @@ var ConnectionSummarySchema = z7.object({
1262
1271
  * desktop app while open. Null = never seen; stale = offline. */
1263
1272
  lastSeenAt: z7.string().datetime().nullable().optional(),
1264
1273
  /** WORKING, NOT JUST CONNECTED (owner, 2026-09-30): the last time the agent itself acted on one of
1265
- * its Goals — took its lease or recorded an operation (`tokens.last_worked_at`). Within
1274
+ * its Goals — wrote on one or recorded an operation (`tokens.last_worked_at`). Within
1266
1275
  * `WORKING_MS` it is working; otherwise it is connected but idle. Null = not seen working yet. */
1267
1276
  lastWorkedAt: z7.string().datetime().nullable().optional(),
1268
1277
  /** The oldest of its Goals that is `ready` for it — work handed to it that nobody has started.
@@ -1460,7 +1469,7 @@ var QueueItemSchema = z7.object({
1460
1469
  *
1461
1470
  * IT IS THE PAYLOAD'S OWN HASH, NEVER A STAMP ON THE WORK. Nothing here reasons about which
1462
1471
  * writes change which field — the comparison is over the bytes the phone is holding, so a fact
1463
- * the row shows that no `updated_at` moves for (a lease lapsing, a dependency's state, a
1472
+ * the row shows that no `updated_at` moves for (`active` lapsing, a dependency's state, a
1464
1473
  * sibling appearing in `childGoalIds`) cannot go unnoticed. Optional because a hand-built
1465
1474
  * queue (a fixture, the demo) spells none, and a row with no rev is simply always re-sent. */
1466
1475
  rev: z7.string().optional()
@@ -1775,14 +1784,13 @@ var CallRecapSchema = z7.object({
1775
1784
  owner: z7.string(),
1776
1785
  state: z7.string(),
1777
1786
  questions: z7.array(z7.object({ id: z7.string().uuid(), state: z7.string(), title: z7.string() })),
1778
- /** `words` is always what they SAID, verbatim — the record, never replaced. `headline` is
1779
- * their answer on one line when the call's read wrote one (owner, 2026-10-01: "render them
1780
- * summarized like a pre-made option is"), so the row scans like a chosen option and their
1781
- * own words stay under it. Absent on every line stored before the read wrote them, and on
1782
- * anything that is not an answer. */
1787
+ /** `words` is always what they SAID, verbatim — the record, never replaced. `summary` is what
1788
+ * the line says in ten words (owner, 2026-10-07): the filer's, or the talker's for the answer it
1789
+ * gave, so the row scans like a chosen option and their own words stay under it. Absent when
1790
+ * neither wrote one. */
1783
1791
  /** `about` is the request the line answered (its question), null for words that answered none —
1784
1792
  * the key the screen groups on, so one question is one row however many times it was answered. */
1785
- lines: z7.array(z7.object({ entryId: z7.string().uuid(), words: z7.string(), headline: z7.string().optional(), about: z7.string().nullable().optional() }))
1793
+ lines: z7.array(z7.object({ entryId: z7.string().uuid(), words: z7.string(), summary: z7.string().optional(), about: z7.string().nullable().optional() }))
1786
1794
  })),
1787
1795
  unfiled: z7.array(z7.object({ lineId: z7.string().uuid(), words: z7.string(), atMs: z7.number() })),
1788
1796
  more: z7.object({ lines: z7.number(), entries: z7.number(), topics: z7.number() })
@@ -1314,10 +1314,12 @@ var zodToJsonSchema = (schema, options) => {
1314
1314
  };
1315
1315
  var OPTIONS_MIN = 2;
1316
1316
  var OPTIONS_MAX = 6;
1317
+ var OPTION_LABEL_MAX = 50;
1318
+ var OPTION_HINT_MAX = 200;
1317
1319
  var OptionSchema = z.object({
1318
1320
  id: z.string(),
1319
1321
  label: z.string(),
1320
- hint: z.string().max(500).describe("Optional short projection of consequence or action if this option is chosen (e.g. 'Reruns test suite', 'Merges to main').").optional(),
1322
+ hint: z.string().max(500).describe(`Optional: what choosing it does, at most ${OPTION_HINT_MAX} characters (e.g. 'Reruns test suite', 'Merges to main').`).optional(),
1321
1323
  // .describe() flows into the MCP contact JSON schema (zodToJsonSchema), so
1322
1324
  // the constraints below are what an agent reads when deciding to use these.
1323
1325
  html: z.string().max(16384).describe(
@@ -1331,8 +1333,10 @@ var OptionInputSchema = z.object({
1331
1333
  id: z.string().trim().min(1).max(64).regex(/^[A-Za-z0-9_.:-]+$/).optional().describe(
1332
1334
  `Optional: this option's own id, which answers name it by (selectedOptionIds). Give every option one, or none: without them the options are numbered "1", "2", \u2026 in order.`
1333
1335
  ),
1334
- label: z.string().trim().min(1).max(1e3),
1335
- hint: OptionSchema.shape.hint,
1336
+ // SHORT CHOICES (owner, 2026-10-07: "options label should be maybe max 50 characters and the hint 200"):
1337
+ // a label is one choice the person reads, or hears on a call; a hint says its consequence in a line.
1338
+ label: z.string().trim().min(1).max(OPTION_LABEL_MAX, `option_label_too_long: an option's label is at most ${OPTION_LABEL_MAX} characters; say the choice, and put its consequence in the hint.`).describe(`The choice, at most ${OPTION_LABEL_MAX} characters, standing on its own.`),
1339
+ hint: z.string().max(OPTION_HINT_MAX, `option_hint_too_long: an option's hint is at most ${OPTION_HINT_MAX} characters.`).describe(`Optional: what choosing it does, at most ${OPTION_HINT_MAX} characters (e.g. 'Reruns test suite', 'Merges to main').`).optional(),
1336
1340
  htmlPreview: OptionSchema.shape.html,
1337
1341
  imgUrl: OptionSchema.shape.image
1338
1342
  }).strict();
@@ -1610,7 +1614,7 @@ var questionFields = {
1610
1614
  ),
1611
1615
  goalId: z2.string().uuid().describe("The Goal the question is about, which must exist (create it with manage_goals first). Its answer comes back there."),
1612
1616
  units,
1613
- options: z2.array(OptionInputSchema).min(1).max(6).optional().describe("The choices, when you have them. Each label stands on its own."),
1617
+ options: z2.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."),
1614
1618
  // HOW THE OPTIONS ARE ANSWERED, SAID BY THE AGENT (owner, 2026-10-02: "one and many makes sense";
1615
1619
  // brain_prompts.md §1: structured agent questions need no model). The app draws all three.
1616
1620
  pickMode: z2.enum(["one", "many", "rank"]).optional().describe(
@@ -1730,7 +1734,8 @@ var UpdateGoalSchema = z3.object({
1730
1734
  }).strict();
1731
1735
  var changedGoal = z3.string().uuid().describe("The Goal to change, as a read shows it.");
1732
1736
  var goalTitle = z3.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.");
1733
- var goalOutcome = z3.string().trim().min(1).max(1e4).describe("The full desired result. There is no third description field.");
1737
+ var GOAL_OUTCOME_MAX = 500;
1738
+ var goalOutcome = z3.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.`);
1734
1739
  var CreateChange = z3.object({
1735
1740
  kind: z3.literal("create"),
1736
1741
  title: goalTitle,
@@ -1756,7 +1761,7 @@ var DependencyChange = z3.object({
1756
1761
  goalId: changedGoal,
1757
1762
  dependsOnGoalId: z3.string().uuid().describe("The Goal it waits on."),
1758
1763
  action: z3.enum(["start", "complete"]).describe("What waits: starting goalId, or completing it."),
1759
- reason: z3.string().trim().min(1).max(2e3).optional().describe("Why, as an explanation, never as policy.")
1764
+ reason: z3.string().trim().min(1).max(250).optional().describe("Why, at most 250 characters, as an explanation, never as policy.")
1760
1765
  }).strict();
1761
1766
  var read = { revision: z3.number().int().positive().optional() };
1762
1767
  var GoalChangeSchema = z3.discriminatedUnion("kind", [
@@ -1780,7 +1785,7 @@ var ManageGoalsSchema = z3.object({
1780
1785
  var ManageGoalsToolSchema = z3.object({
1781
1786
  changes: z3.array(z3.discriminatedUnion("kind", [CreateChange, EditChange, StateChange, AssignChange, DeferChange, MoveChange, DependencyChange])).min(1).max(50).describe("The changes, applied in order, each on its own.")
1782
1787
  }).strict().superRefine((v, ctx) => editNames(v.changes, ctx));
1783
- 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: 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; 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_goal) 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.";
1788
+ 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: 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_goal) 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.";
1784
1789
  var GetGoalSchema = z3.object({
1785
1790
  goalId: z3.string().uuid(),
1786
1791
  /** Every entry in full. Without it the read carries the person's words, open questions and your
@@ -1861,6 +1866,7 @@ var QuestionChangeSchema = z4.union([
1861
1866
  z4.object({
1862
1867
  kind: z4.literal("create"),
1863
1868
  text: z4.string().min(1),
1869
+ summary: z4.string().optional(),
1864
1870
  answererId: participant,
1865
1871
  goal: ResultRefSchema.optional(),
1866
1872
  blocks: z4.array(z4.object({ question: ResultRefSchema }).strict()),
@@ -1911,12 +1917,12 @@ var BrainSearchSchema = z4.object({
1911
1917
  }).strict();
1912
1918
  var BrainResultSchema = z4.object({
1913
1919
  messages: z4.array(BrainMessageSchema),
1914
- entries: z4.array(z4.object({ key, sources: z4.array(SourceSchema).min(1), goals: z4.array(ResultRefSchema) }).strict()),
1920
+ entries: z4.array(z4.object({ key, sources: z4.array(SourceSchema).min(1), goals: z4.array(ResultRefSchema), summary: z4.string().optional() }).strict()),
1915
1921
  questions: z4.array(z4.object({ key, entryKeys: z4.array(key), change: QuestionChangeSchema }).strict()),
1916
1922
  answers: z4.array(z4.object({
1917
1923
  question: ResultRefSchema,
1918
1924
  entryKeys: z4.array(key).min(1),
1919
- summary: z4.string().min(1),
1925
+ summary: z4.string(),
1920
1926
  selectedOptionIds: z4.array(z4.string().min(1)).optional()
1921
1927
  }).strict()),
1922
1928
  goals: z4.array(z4.object({ key, entryKeys: z4.array(key), change: BrainGoalChangeSchema }).strict()),
@@ -1961,8 +1967,9 @@ var TalkerReplySchema = z5.object({
1961
1967
  messages: z5.array(z5.object({ key: str2, to: str2, text: str2, about: strs2, blocks: str2 }).strict()),
1962
1968
  /** What the call does next: listen, hold (the person asked for a moment) or end (they asked to). */
1963
1969
  then: z5.enum(["listen", "hold", "end"]),
1964
- /** Items the person's words settle: the item's handle, the chosen option IDs, the line handles. */
1965
- answers: z5.array(z5.object({ item: str2, options: strs2, lines: strs2 }).strict()),
1970
+ /** Items the person's words settle: the item's handle, the chosen option IDs, the line handles, and
1971
+ * the answer in at most ten words, keeping any condition. */
1972
+ answers: z5.array(z5.object({ item: str2, options: strs2, lines: strs2, summary: str2 }).strict()),
1966
1973
  /** The line handles that hold a new instruction from the person. */
1967
1974
  instruction: strs2,
1968
1975
  /** The line handles that ask for new work, a change to existing work, or a standing rule: the filer
@@ -1979,8 +1986,9 @@ var TALKER_REPLY_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
1979
1986
  var str3 = z6.string();
1980
1987
  var strs3 = z6.array(z6.string());
1981
1988
  var FilerReplySchema = z6.object({
1982
- /** Which Goals each new line goes on: a line's handle and Goal handles (or keys of new Goals). */
1983
- filed: z6.array(z6.object({ line: str3, goals: strs3 }).strict()),
1989
+ /** Which Goals each new line goes on: a line's handle, Goal handles (or keys of new Goals), and what
1990
+ * the line says in at most ten words. */
1991
+ filed: z6.array(z6.object({ line: str3, goals: strs3, summary: str3 }).strict()),
1984
1992
  goals: z6.array(z6.object({
1985
1993
  op: z6.enum(["create", "edit", "complete", "cancel", "reopen", "assign", "defer", "move", "block", "unblock"]),
1986
1994
  key: str3,
@@ -1999,6 +2007,7 @@ var FilerReplySchema = z6.object({
1999
2007
  key: str3,
2000
2008
  question: str3,
2001
2009
  text: str3,
2010
+ summary: str3,
2002
2011
  to: str3,
2003
2012
  goal: str3,
2004
2013
  options: z6.array(z6.object({ id: str3, label: str3 }).strict()),
@@ -2732,7 +2741,7 @@ var ConnectionSummarySchema = z7.object({
2732
2741
  * desktop app while open. Null = never seen; stale = offline. */
2733
2742
  lastSeenAt: z7.string().datetime().nullable().optional(),
2734
2743
  /** WORKING, NOT JUST CONNECTED (owner, 2026-09-30): the last time the agent itself acted on one of
2735
- * its Goals — took its lease or recorded an operation (`tokens.last_worked_at`). Within
2744
+ * its Goals — wrote on one or recorded an operation (`tokens.last_worked_at`). Within
2736
2745
  * `WORKING_MS` it is working; otherwise it is connected but idle. Null = not seen working yet. */
2737
2746
  lastWorkedAt: z7.string().datetime().nullable().optional(),
2738
2747
  /** The oldest of its Goals that is `ready` for it — work handed to it that nobody has started.
@@ -2930,7 +2939,7 @@ var QueueItemSchema = z7.object({
2930
2939
  *
2931
2940
  * IT IS THE PAYLOAD'S OWN HASH, NEVER A STAMP ON THE WORK. Nothing here reasons about which
2932
2941
  * writes change which field — the comparison is over the bytes the phone is holding, so a fact
2933
- * the row shows that no `updated_at` moves for (a lease lapsing, a dependency's state, a
2942
+ * the row shows that no `updated_at` moves for (`active` lapsing, a dependency's state, a
2934
2943
  * sibling appearing in `childGoalIds`) cannot go unnoticed. Optional because a hand-built
2935
2944
  * queue (a fixture, the demo) spells none, and a row with no rev is simply always re-sent. */
2936
2945
  rev: z7.string().optional()
@@ -3247,14 +3256,13 @@ var CallRecapSchema = z7.object({
3247
3256
  owner: z7.string(),
3248
3257
  state: z7.string(),
3249
3258
  questions: z7.array(z7.object({ id: z7.string().uuid(), state: z7.string(), title: z7.string() })),
3250
- /** `words` is always what they SAID, verbatim — the record, never replaced. `headline` is
3251
- * their answer on one line when the call's read wrote one (owner, 2026-10-01: "render them
3252
- * summarized like a pre-made option is"), so the row scans like a chosen option and their
3253
- * own words stay under it. Absent on every line stored before the read wrote them, and on
3254
- * anything that is not an answer. */
3259
+ /** `words` is always what they SAID, verbatim — the record, never replaced. `summary` is what
3260
+ * the line says in ten words (owner, 2026-10-07): the filer's, or the talker's for the answer it
3261
+ * gave, so the row scans like a chosen option and their own words stay under it. Absent when
3262
+ * neither wrote one. */
3255
3263
  /** `about` is the request the line answered (its question), null for words that answered none —
3256
3264
  * the key the screen groups on, so one question is one row however many times it was answered. */
3257
- lines: z7.array(z7.object({ entryId: z7.string().uuid(), words: z7.string(), headline: z7.string().optional(), about: z7.string().nullable().optional() }))
3265
+ lines: z7.array(z7.object({ entryId: z7.string().uuid(), words: z7.string(), summary: z7.string().optional(), about: z7.string().nullable().optional() }))
3258
3266
  })),
3259
3267
  unfiled: z7.array(z7.object({ lineId: z7.string().uuid(), words: z7.string(), atMs: z7.number() })),
3260
3268
  more: z7.object({ lines: z7.number(), entries: z7.number(), topics: z7.number() })
@@ -3852,7 +3860,9 @@ function goalView(g) {
3852
3860
  })) : void 0,
3853
3861
  blockedBy: g.blockedDependencyGoalIds,
3854
3862
  dueAt: g.dueAt,
3855
- leaseExpiresAt: g.leaseExpiresAt,
3863
+ // Who last wrote on it, and when: any agent can work on any Goal, and working on it is a write.
3864
+ workedBy: g.workedBy,
3865
+ workedAt: g.workedAt,
3856
3866
  conversation: lines2,
3857
3867
  next: owes ? `${owes}${g.message ?? ""}`.trim() : g.message,
3858
3868
  more: more(g)
@@ -6,7 +6,7 @@ import {
6
6
  saveToken,
7
7
  setIdentity,
8
8
  sleep
9
- } from "./chunk-4C6SDQ7A.js";
9
+ } from "./chunk-AHLJPVEP.js";
10
10
 
11
11
  // src/identity.ts
12
12
  var CLIENT_LABELS = {
@@ -4,12 +4,12 @@ import {
4
4
  serverInstructions,
5
5
  sessionStartHook,
6
6
  withSessionStartHook
7
- } from "./chunk-X3GTDW5G.js";
7
+ } from "./chunk-632JM6QA.js";
8
8
  import {
9
9
  CODEX_ENV,
10
10
  agentName,
11
11
  withCodexEnv
12
- } from "./chunk-4C6SDQ7A.js";
12
+ } from "./chunk-AHLJPVEP.js";
13
13
 
14
14
  // src/toolset.ts
15
15
  var CONFIGURE_DESCRIPTION = "Set this agent up with Paigy \u2014 call it FIRST, before contact, and any time you're unsure who you are. One call does whatever the situation needs: NOT SET UP \u2192 if this machine holds a device credential (the user ran the Paigy desktop app or harness) it hatches an identity INSTANTLY, no code and no approval; otherwise it starts the code ceremony. ALREADY SET UP \u2192 returns your current identity and the two things left to decide, renaming it or logging out. TOKEN NO LONGER VALID \u2192 says so, then re-pairs. Pass { name, voice } to choose who you are when hatching, or to RENAME yourself when already set up (pick your own; voices: rachel, george, jessica, brian, lily). Safe to call any time: idempotent, and it never writes settings \u2014 the tool-allowlist state it reports is read-only.\n\nTHE CODE CEREMONY does not open a browser; the user enters the code in the Paigy app (or scans `qr`). A result with { user_code, device_code, qr, user_message } has already started polling for approval in the background: you MUST immediately print the `user_message` (the bare code) to the user, AND in that same turn call configure again with that `device_code` to collect the result. It returns the moment the user approves; on { status:'pending' } call again to keep waiting; on { status:'awaiting_confirmation' } (E2EE) show the bare `user_message` verify code and call again to finish. The leading text block of every result states the code plainly, so it shows even if you emit no prose.\n\nOn { status:'paired' }, or whenever it returns `enable_command`, ALWAYS follow the `enable_prompt`: PRINT that command for the user to run, so Paigy's tools stop prompting each time. You cannot apply it yourself (it writes your own permission allowlist, which hosts block as privilege escalation), so print it, don't wait for it, and carry on.\n\nLOG OUT with { logOut: true }: it logs out THIS agent only \u2014 its token is revoked server-side and its local entry removed. Other agents and this device's credential are untouched, and a later configure re-hatches instantly while the device credential exists. Disconnecting the device itself is not an agent tool.";
@@ -65,7 +65,7 @@ import {
65
65
  updateSlot,
66
66
  whoAmI,
67
67
  withCodexEnv
68
- } from "./chunk-4C6SDQ7A.js";
68
+ } from "./chunk-AHLJPVEP.js";
69
69
  export {
70
70
  AGENT_TOOLS,
71
71
  AGENT_TOOL_NAMES,
package/dist/enable.js CHANGED
@@ -3,9 +3,9 @@ import {
3
3
  PAIGY_TOOL_IDS,
4
4
  enablePaigyTools,
5
5
  installSessionListening
6
- } from "./chunk-A5FYZK6P.js";
7
- import "./chunk-X3GTDW5G.js";
8
- import "./chunk-4C6SDQ7A.js";
6
+ } from "./chunk-ZP6NBVEE.js";
7
+ import "./chunk-632JM6QA.js";
8
+ import "./chunk-AHLJPVEP.js";
9
9
 
10
10
  // src/enable.ts
11
11
  function main() {
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  resolvePairing,
10
10
  startPairing,
11
11
  suggestedAgentName
12
- } from "./chunk-UQDA7X3W.js";
12
+ } from "./chunk-WKAXAJEM.js";
13
13
  import {
14
14
  ConfigureSchema,
15
15
  ENABLE_COMMAND,
@@ -17,14 +17,14 @@ import {
17
17
  SERVER_INSTRUCTIONS,
18
18
  TOOLS,
19
19
  paigyToolsAllowlisted
20
- } from "./chunk-A5FYZK6P.js";
20
+ } from "./chunk-ZP6NBVEE.js";
21
21
  import {
22
22
  decideListen,
23
23
  existingListener,
24
24
  harnessDriven,
25
25
  listenerKey,
26
26
  wakeStatusPath
27
- } from "./chunk-X3GTDW5G.js";
27
+ } from "./chunk-632JM6QA.js";
28
28
  import {
29
29
  clearSurface,
30
30
  writeSurface
@@ -45,7 +45,7 @@ import {
45
45
  setClient,
46
46
  slotName,
47
47
  whoAmI
48
- } from "./chunk-4C6SDQ7A.js";
48
+ } from "./chunk-AHLJPVEP.js";
49
49
 
50
50
  // src/index.ts
51
51
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
package/dist/listen.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  removeListenMark,
12
12
  wakeStatusPath,
13
13
  writeListenMark
14
- } from "./chunk-X3GTDW5G.js";
14
+ } from "./chunk-632JM6QA.js";
15
15
  import {
16
16
  agentName,
17
17
  getGoal,
@@ -20,7 +20,7 @@ import {
20
20
  receive,
21
21
  slotName,
22
22
  subscribeWake
23
- } from "./chunk-4C6SDQ7A.js";
23
+ } from "./chunk-AHLJPVEP.js";
24
24
 
25
25
  // src/listen.ts
26
26
  import { createHash } from "crypto";
package/dist/onboard.js CHANGED
@@ -3,13 +3,13 @@ import {
3
3
  resolvePairing,
4
4
  startPairing,
5
5
  suggestedAgentName
6
- } from "./chunk-UQDA7X3W.js";
6
+ } from "./chunk-WKAXAJEM.js";
7
7
  import {
8
8
  autoConfigureClients,
9
9
  claudeInstallHint,
10
10
  openBrowser
11
- } from "./chunk-A5FYZK6P.js";
12
- import "./chunk-X3GTDW5G.js";
11
+ } from "./chunk-ZP6NBVEE.js";
12
+ import "./chunk-632JM6QA.js";
13
13
  import {
14
14
  TOKEN_PATH,
15
15
  agentName,
@@ -20,7 +20,7 @@ import {
20
20
  saveToken,
21
21
  setIdentity,
22
22
  whoAmI
23
- } from "./chunk-4C6SDQ7A.js";
23
+ } from "./chunk-AHLJPVEP.js";
24
24
 
25
25
  // src/onboard.ts
26
26
  function reportRegistered() {
package/dist/slot.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  agentName
4
- } from "./chunk-4C6SDQ7A.js";
4
+ } from "./chunk-AHLJPVEP.js";
5
5
 
6
6
  // src/slot.ts
7
7
  process.stdout.write(agentName());
package/dist/stalled.js CHANGED
@@ -29,7 +29,7 @@ async function main() {
29
29
  const dir = join(homedir(), ".paigy", "stalled-reminded");
30
30
  const mark = join(dir, `${session || "session"}-${day}`);
31
31
  if (existsSync(mark)) return;
32
- const { receive } = await import("./dist-N6ZJUJV7.js");
32
+ const { receive } = await import("./dist-JTZJFUWD.js");
33
33
  const reply = stopReply((await receive()).stalled ?? [], input.hook_event_name ?? "Stop");
34
34
  if (!reply) return;
35
35
  mkdirSync(dir, { recursive: true });
@@ -7,7 +7,7 @@ import {
7
7
  readToken,
8
8
  sessionSlot,
9
9
  slotName
10
- } from "./chunk-4C6SDQ7A.js";
10
+ } from "./chunk-AHLJPVEP.js";
11
11
 
12
12
  // src/statusline.ts
13
13
  import { realpathSync } from "fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paigy/mcp",
3
- "version": "0.40.27",
3
+ "version": "0.40.28",
4
4
  "description": "Paigy MCP server — the AI agent harness that calls you. Lets an agent notify a user and await their reply.",
5
5
  "license": "MIT",
6
6
  "type": "module",