@paigy/mcp 0.40.31 → 0.40.32

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.
@@ -6,7 +6,7 @@ import {
6
6
  saveToken,
7
7
  setIdentity,
8
8
  sleep
9
- } from "./chunk-CULBHBFU.js";
9
+ } from "./chunk-QJCRISSA.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-AWI252HQ.js";
7
+ } from "./chunk-EU6NEQ2W.js";
8
8
  import {
9
9
  CODEX_ENV,
10
10
  agentName,
11
11
  withCodexEnv
12
- } from "./chunk-CULBHBFU.js";
12
+ } from "./chunk-QJCRISSA.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.";
@@ -686,6 +686,8 @@ function entryUnit(entry) {
686
686
  }
687
687
  var LIVE_MS = 3 * 6e4;
688
688
  var WORKING_MS = 60 * 6e4;
689
+ var WORKING_TIER_MS = 2 * 60 * 6e4;
690
+ var RECENT_TIER_MS = 24 * 60 * 6e4;
689
691
  var ContextSchema = z9.object({
690
692
  title: z9.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
691
693
  description: z9.array(z9.string().min(1)).describe(
@@ -1030,6 +1032,10 @@ var AgendaTurnSchema = z9.object({
1030
1032
  * so "who said that" survives the call, and it rides PER TURN because a coalesced call
1031
1033
  * speaks for several agents — the turn is the only place that knows which. */
1032
1034
  agentId: z9.string().optional(),
1035
+ /** ITS QUESTION IS ON THE TABLE (#3292): a talker line about a question the person owes. The walk tells
1036
+ * the phone (`asking`, so the agenda goes gold and its options show) without treating the line as a
1037
+ * question turn — the talker owns re-asking and the waits, so `question` stays null. */
1038
+ onTable: z9.boolean().optional(),
1033
1039
  select: SelectShapeSchema.optional(),
1034
1040
  options: z9.array(OptionSchema.omit({ id: true })).optional(),
1035
1041
  /* `pace` STOOD HERE (#826). A turn could carry seconds and the model chose them. The walk
@@ -1550,7 +1556,11 @@ var QueueItemSchema = z9.object({
1550
1556
  from: z9.enum(["person", "agent"]),
1551
1557
  said: z9.string(),
1552
1558
  at: z9.string(),
1553
- entryId: z9.string()
1559
+ entryId: z9.string(),
1560
+ /** ITS SUMMARY IN AT MOST TEN WORDS (owner, 2026-10-08: "the same switch to the more summarized sources
1561
+ * at the work tab top level screen too"): what the talker or filer wrote on the Entry; absent when
1562
+ * none was. The Work row reads it before `said`. */
1563
+ summary: z9.string().optional()
1554
1564
  }).nullable().optional(),
1555
1565
  /** WHEN THIS PERSON LAST PUT A HAND ON IT THEMSELVES (owner, Paigy Goal 16d18f51, 2026-09-30):
1556
1566
  * the newest Entry on the Goal they wrote, of any kind — a line they added, a reply to a note, an
@@ -1885,6 +1895,9 @@ var CallRecapSchema = z9.object({
1885
1895
  title: z9.string(),
1886
1896
  owner: z9.string(),
1887
1897
  state: z9.string(),
1898
+ /** Whether the call put it to the person. An item it carried and never said has no row on the
1899
+ * review (owner, 2026-10-08: "why do we get the third one when it didn't happen in the call?"). */
1900
+ presented: z9.boolean(),
1888
1901
  questions: z9.array(z9.object({ id: z9.string().uuid(), state: z9.string(), title: z9.string() })),
1889
1902
  /** `words` is always what they SAID, verbatim — the record, never replaced. `summary` is what
1890
1903
  * the line says in ten words (owner, 2026-10-07): the filer's, or the talker's for the answer it
@@ -1906,6 +1919,19 @@ var CallRecapSchema = z9.object({
1906
1919
  }))
1907
1920
  })),
1908
1921
  unfiled: z9.array(z9.object({ lineId: z9.string().uuid(), words: z9.string(), atMs: z9.number() })),
1922
+ /** THE PUBLIC TRANSCRIPT — every line said on the call, in the order it was said, and WHO SAID IT
1923
+ * (owner, 2026-10-08: "the public view should only have the lines and who said them, and that's
1924
+ * it"; `docs/brain/phase-three/modular.md` build step 3). `speaker` is the role: "user" is the
1925
+ * person, "agent" an agent speaking, named in `agent`. The timeline's action lines are ours, not
1926
+ * theirs, and are not here; nor is a sealed line, which the server has no words for. It stands
1927
+ * BESIDE `topics` and `unfiled` — what the call did with the words — never instead of them. */
1928
+ said: z9.array(z9.object({
1929
+ lineId: z9.string().uuid(),
1930
+ speaker: z9.enum(["user", "agent"]),
1931
+ agent: z9.object({ id: z9.string().nullable(), name: z9.string().nullable() }).nullable(),
1932
+ words: z9.string(),
1933
+ atMs: z9.number()
1934
+ })),
1909
1935
  more: z9.object({ lines: z9.number(), entries: z9.number(), topics: z9.number() })
1910
1936
  });
1911
1937
 
@@ -67,10 +67,47 @@ function claudeConversation() {
67
67
  if (!envSession("CLAUDE_CODE_SESSION_ID") || process.env.CLAUDE_CODE_CHILD_SESSION) return void 0;
68
68
  const dir = envSession("CLAUDE_CONFIG_DIR") ?? join(homedir(), ".claude");
69
69
  for (const pid of ancestors()) {
70
+ let text;
70
71
  try {
71
- const { sessionId: sessionId2 } = JSON.parse(readFileSync(join(dir, "sessions", `${pid}.json`), "utf8"));
72
- return typeof sessionId2 === "string" && sessionId2.trim() ? sessionId2 : void 0;
72
+ text = readFileSync(join(dir, "sessions", `${pid}.json`), "utf8");
73
73
  } catch {
74
+ continue;
75
+ }
76
+ const record = parseSessionRecord(text);
77
+ if (!record) continue;
78
+ return typeof record.sessionId === "string" && record.sessionId.trim() ? record.sessionId : void 0;
79
+ }
80
+ return void 0;
81
+ }
82
+ function parseSessionRecord(text) {
83
+ const object = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
84
+ try {
85
+ return object(JSON.parse(text));
86
+ } catch {
87
+ }
88
+ let depth = 0;
89
+ let start = -1;
90
+ let quoted = false;
91
+ let escaped = false;
92
+ for (let i = 0; i < text.length; i += 1) {
93
+ const c = text[i];
94
+ if (quoted) {
95
+ if (escaped) escaped = false;
96
+ else if (c === "\\") escaped = true;
97
+ else if (c === '"') quoted = false;
98
+ } else if (c === '"') quoted = true;
99
+ else if (c === "{") {
100
+ if (depth === 0) start = i;
101
+ depth += 1;
102
+ } else if (c === "}" && depth > 0) {
103
+ depth -= 1;
104
+ if (depth === 0) {
105
+ try {
106
+ return object(JSON.parse(text.slice(start, i + 1)));
107
+ } catch {
108
+ return void 0;
109
+ }
110
+ }
74
111
  }
75
112
  }
76
113
  return void 0;
@@ -2147,6 +2184,8 @@ function askUnits(request, entries) {
2147
2184
  }
2148
2185
  var LIVE_MS = 3 * 6e4;
2149
2186
  var WORKING_MS = 60 * 6e4;
2187
+ var WORKING_TIER_MS = 2 * 60 * 6e4;
2188
+ var RECENT_TIER_MS = 24 * 60 * 6e4;
2150
2189
  var ContextSchema = z9.object({
2151
2190
  title: z9.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
2152
2191
  description: z9.array(z9.string().min(1)).describe(
@@ -2498,6 +2537,10 @@ var AgendaTurnSchema = z9.object({
2498
2537
  * so "who said that" survives the call, and it rides PER TURN because a coalesced call
2499
2538
  * speaks for several agents — the turn is the only place that knows which. */
2500
2539
  agentId: z9.string().optional(),
2540
+ /** ITS QUESTION IS ON THE TABLE (#3292): a talker line about a question the person owes. The walk tells
2541
+ * the phone (`asking`, so the agenda goes gold and its options show) without treating the line as a
2542
+ * question turn — the talker owns re-asking and the waits, so `question` stays null. */
2543
+ onTable: z9.boolean().optional(),
2501
2544
  select: SelectShapeSchema.optional(),
2502
2545
  options: z9.array(OptionSchema.omit({ id: true })).optional(),
2503
2546
  /* `pace` STOOD HERE (#826). A turn could carry seconds and the model chose them. The walk
@@ -3018,7 +3061,11 @@ var QueueItemSchema = z9.object({
3018
3061
  from: z9.enum(["person", "agent"]),
3019
3062
  said: z9.string(),
3020
3063
  at: z9.string(),
3021
- entryId: z9.string()
3064
+ entryId: z9.string(),
3065
+ /** ITS SUMMARY IN AT MOST TEN WORDS (owner, 2026-10-08: "the same switch to the more summarized sources
3066
+ * at the work tab top level screen too"): what the talker or filer wrote on the Entry; absent when
3067
+ * none was. The Work row reads it before `said`. */
3068
+ summary: z9.string().optional()
3022
3069
  }).nullable().optional(),
3023
3070
  /** WHEN THIS PERSON LAST PUT A HAND ON IT THEMSELVES (owner, Paigy Goal 16d18f51, 2026-09-30):
3024
3071
  * the newest Entry on the Goal they wrote, of any kind — a line they added, a reply to a note, an
@@ -3355,6 +3402,9 @@ var CallRecapSchema = z9.object({
3355
3402
  title: z9.string(),
3356
3403
  owner: z9.string(),
3357
3404
  state: z9.string(),
3405
+ /** Whether the call put it to the person. An item it carried and never said has no row on the
3406
+ * review (owner, 2026-10-08: "why do we get the third one when it didn't happen in the call?"). */
3407
+ presented: z9.boolean(),
3358
3408
  questions: z9.array(z9.object({ id: z9.string().uuid(), state: z9.string(), title: z9.string() })),
3359
3409
  /** `words` is always what they SAID, verbatim — the record, never replaced. `summary` is what
3360
3410
  * the line says in ten words (owner, 2026-10-07): the filer's, or the talker's for the answer it
@@ -3376,6 +3426,19 @@ var CallRecapSchema = z9.object({
3376
3426
  }))
3377
3427
  })),
3378
3428
  unfiled: z9.array(z9.object({ lineId: z9.string().uuid(), words: z9.string(), atMs: z9.number() })),
3429
+ /** THE PUBLIC TRANSCRIPT — every line said on the call, in the order it was said, and WHO SAID IT
3430
+ * (owner, 2026-10-08: "the public view should only have the lines and who said them, and that's
3431
+ * it"; `docs/brain/phase-three/modular.md` build step 3). `speaker` is the role: "user" is the
3432
+ * person, "agent" an agent speaking, named in `agent`. The timeline's action lines are ours, not
3433
+ * theirs, and are not here; nor is a sealed line, which the server has no words for. It stands
3434
+ * BESIDE `topics` and `unfiled` — what the call did with the words — never instead of them. */
3435
+ said: z9.array(z9.object({
3436
+ lineId: z9.string().uuid(),
3437
+ speaker: z9.enum(["user", "agent"]),
3438
+ agent: z9.object({ id: z9.string().nullable(), name: z9.string().nullable() }).nullable(),
3439
+ words: z9.string(),
3440
+ atMs: z9.number()
3441
+ })),
3379
3442
  more: z9.object({ lines: z9.number(), entries: z9.number(), topics: z9.number() })
3380
3443
  });
3381
3444
  function sessionSlot(sessionId2) {
@@ -4387,6 +4450,7 @@ export {
4387
4450
  CODEX_ENV,
4388
4451
  BACKEND_URL,
4389
4452
  NETWORK_MSG,
4453
+ parseSessionRecord,
4390
4454
  sessionId,
4391
4455
  isNetworkError,
4392
4456
  reach,
@@ -36,6 +36,7 @@ import {
36
36
  manageGoals,
37
37
  overrideToken,
38
38
  parseDue,
39
+ parseSessionRecord,
39
40
  pendingEvents,
40
41
  pollToken,
41
42
  reach,
@@ -65,7 +66,7 @@ import {
65
66
  updateSlot,
66
67
  whoAmI,
67
68
  withCodexEnv
68
- } from "./chunk-CULBHBFU.js";
69
+ } from "./chunk-QJCRISSA.js";
69
70
  export {
70
71
  AGENT_TOOLS,
71
72
  AGENT_TOOL_NAMES,
@@ -104,6 +105,7 @@ export {
104
105
  manageGoals,
105
106
  overrideToken,
106
107
  parseDue,
108
+ parseSessionRecord,
107
109
  pendingEvents,
108
110
  pollToken,
109
111
  reach,
package/dist/enable.js CHANGED
@@ -3,9 +3,9 @@ import {
3
3
  PAIGY_TOOL_IDS,
4
4
  enablePaigyTools,
5
5
  installSessionListening
6
- } from "./chunk-NHPLQOQP.js";
7
- import "./chunk-AWI252HQ.js";
8
- import "./chunk-CULBHBFU.js";
6
+ } from "./chunk-5F3ND6WV.js";
7
+ import "./chunk-EU6NEQ2W.js";
8
+ import "./chunk-QJCRISSA.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-FAS3IB2F.js";
12
+ } from "./chunk-4YUPH4JS.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-NHPLQOQP.js";
20
+ } from "./chunk-5F3ND6WV.js";
21
21
  import {
22
22
  decideListen,
23
23
  existingListener,
24
24
  harnessDriven,
25
25
  listenerKey,
26
26
  wakeStatusPath
27
- } from "./chunk-AWI252HQ.js";
27
+ } from "./chunk-EU6NEQ2W.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-CULBHBFU.js";
48
+ } from "./chunk-QJCRISSA.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-AWI252HQ.js";
14
+ } from "./chunk-EU6NEQ2W.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-CULBHBFU.js";
23
+ } from "./chunk-QJCRISSA.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-FAS3IB2F.js";
6
+ } from "./chunk-4YUPH4JS.js";
7
7
  import {
8
8
  autoConfigureClients,
9
9
  claudeInstallHint,
10
10
  openBrowser
11
- } from "./chunk-NHPLQOQP.js";
12
- import "./chunk-AWI252HQ.js";
11
+ } from "./chunk-5F3ND6WV.js";
12
+ import "./chunk-EU6NEQ2W.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-CULBHBFU.js";
23
+ } from "./chunk-QJCRISSA.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-CULBHBFU.js";
4
+ } from "./chunk-QJCRISSA.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-2WLAZWSH.js");
32
+ const { receive } = await import("./dist-Z4KVBUBO.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-CULBHBFU.js";
10
+ } from "./chunk-QJCRISSA.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.31",
3
+ "version": "0.40.32",
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",