@paigy/mcp 0.40.20 → 0.40.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-6C6CO7H3.js → chunk-2UEIJRRC.js} +82 -25
- package/dist/{chunk-6MEUSSRH.js → chunk-B7SEHASI.js} +2 -2
- package/dist/{chunk-YNKTKLQD.js → chunk-LRN27BMO.js} +1 -1
- package/dist/{chunk-RLN2B5IZ.js → chunk-OW65TWMX.js} +87 -26
- package/dist/{dist-33DA5X2G.js → dist-VVU24KB2.js} +1 -1
- package/dist/enable.js +3 -3
- package/dist/index.js +40 -4
- package/dist/listen.js +2 -2
- package/dist/onboard.js +4 -4
- package/dist/slot.js +1 -1
- package/dist/stalled.js +1 -1
- package/dist/statusline.js +1 -1
- package/package.json +1 -1
|
@@ -1592,7 +1592,7 @@ var GetGoalSchema = z3.object({
|
|
|
1592
1592
|
history: z3.boolean().optional(),
|
|
1593
1593
|
/** WHEN A READ HAS CONFUSED YOU. Adds `diagnosis`: every reader that already answers a question
|
|
1594
1594
|
* about this work, each answer attributed to the reader that gave it, and every disagreement
|
|
1595
|
-
* between two of them named. Off by default; `
|
|
1595
|
+
* between two of them named. Off by default; `docs/model/goal/diagnose-design.md`. */
|
|
1596
1596
|
diagnose: z3.boolean().optional()
|
|
1597
1597
|
}).strict();
|
|
1598
1598
|
var GET_GOAL_DESCRIPTION = "Read one Goal without claiming it: its 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. 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. Another account's Goals, and another agent's Goal that is not below one of yours, are not disclosed.\n\ndiagnose: true is for when a read has CONFUSED you \u2014 not for the working loop. It adds `diagnosis`, which asks every reader that already answers a question about your work and NAMES the reader behind every value, so you never guess which of two places to look: what state your work is really in (the stored `goals.state` beside the derived `goal_execution_state`, which can differ); whether anything is armed to ring and when (`ladder_candidates`, with the ladder's own last decision); whether a wake fired for you and what it did (durable `wake.*` events, beside when your process was last heard from); and what has reached you (`list_waiting` \u2014 review flags, unstarted work, open questions, the person's newest words). Read `diagnosis.disagreements` FIRST: each one is two readers giving different values for the same fact, with both values and both sources, and it never chooses between them \u2014 that is yours to do, from the Goal's own history. `diagnosis.looked` names every reader asked, including any that could not answer, so an empty answer is never confused with a broken one.";
|
|
@@ -1625,6 +1625,7 @@ function entryWords(entry) {
|
|
|
1625
1625
|
return entry.sources.map((source) => source.text).join("\n");
|
|
1626
1626
|
}
|
|
1627
1627
|
var LIVE_MS = 3 * 6e4;
|
|
1628
|
+
var WORKING_MS = 30 * 6e4;
|
|
1628
1629
|
var ContextSchema = z4.object({
|
|
1629
1630
|
title: z4.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
|
|
1630
1631
|
description: z4.array(z4.string().min(1)).describe(
|
|
@@ -1695,7 +1696,7 @@ var AttentionSchema = z4.object({
|
|
|
1695
1696
|
points: z4.array(z4.string()).nullable(),
|
|
1696
1697
|
/** Whether the ask blocks the sender — what lets arbitration escalate it on silence. */
|
|
1697
1698
|
blocking: z4.boolean(),
|
|
1698
|
-
/** Reserved (
|
|
1699
|
+
/** Reserved (docs/model/model.md lists it): a response deadline. No row column yet — a later Phase 2
|
|
1699
1700
|
* slice wires it; optional so today's rows/callers project cleanly. */
|
|
1700
1701
|
deadline: z4.string().datetime().nullable().optional()
|
|
1701
1702
|
});
|
|
@@ -1746,7 +1747,7 @@ var NotifyRequestFields = z4.object({
|
|
|
1746
1747
|
* derive agent-side before sealing, so the server only ever shapes plaintext). */
|
|
1747
1748
|
// 10k, not a sentence budget. What the human hears is bounded by the BROKER — it splits
|
|
1748
1749
|
// the ask into topics and gives each one at most three sentences and one question
|
|
1749
|
-
// (broker/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
|
|
1750
|
+
// (docs/brain/broker/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
|
|
1750
1751
|
// Owner, 2026-07-28: "our actual limitation on how long something is to the user should
|
|
1751
1752
|
// come from the broker splitting and summarizing." The cap that remains is a size guard.
|
|
1752
1753
|
ask: z4.string().min(1).max(1e4).optional().describe(
|
|
@@ -1823,7 +1824,7 @@ var UserAnswerSchema = z4.discriminatedUnion("kind", [
|
|
|
1823
1824
|
z4.object({ kind: z4.literal("clarify"), chunks: z4.array(z4.string()).min(1) }),
|
|
1824
1825
|
z4.object({ kind: z4.literal("confirm"), approved: z4.boolean() }),
|
|
1825
1826
|
z4.object({ kind: z4.literal("turns"), turns: z4.array(TurnSchema).min(1) }),
|
|
1826
|
-
/** An auto-answer derived from the user's PAST decisions (broker/precedent-design.md §2):
|
|
1827
|
+
/** An auto-answer derived from the user's PAST decisions (docs/brain/broker/precedent-design.md §2):
|
|
1827
1828
|
* delivered through the same settle/await path as a human answer, carrying the judge's
|
|
1828
1829
|
* derivation and the precedent ids it grew from. Always paired with a visible trail
|
|
1829
1830
|
* card the user can reply to — the broker never overrides the user. */
|
|
@@ -1872,7 +1873,7 @@ var AwaitItemSchema = z4.discriminatedUnion("type", [
|
|
|
1872
1873
|
* and now knows exactly which call to make. Absent when either half is missing —
|
|
1873
1874
|
* a sentence with a hole in it is worse than no sentence. */
|
|
1874
1875
|
note: z4.string().optional(),
|
|
1875
|
-
/** The call record rendered for THIS agent (`voice/record-design.md`): the words the
|
|
1876
|
+
/** The call record rendered for THIS agent (`docs/brain/voice/record-design.md`): the words the
|
|
1876
1877
|
* shaped answer was mapped from, filtered to its own claims. There is no second list
|
|
1877
1878
|
* of labels beside it — the acts went 2026-09-04 and `intents` went with them (owner,
|
|
1878
1879
|
* 2026-09-04): the agent reads the sentence and decides. */
|
|
@@ -1968,10 +1969,11 @@ var AgendaTurnSchema = z4.object({
|
|
|
1968
1969
|
agentId: z4.string().optional(),
|
|
1969
1970
|
select: SelectShapeSchema.optional(),
|
|
1970
1971
|
options: z4.array(OptionSchema.omit({ id: true })).optional(),
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1972
|
+
/* `pace` STOOD HERE (#826). A turn could carry seconds and the model chose them. The walk
|
|
1973
|
+
paces itself now — a short beat between the sentences of a turn, the longer one at its end
|
|
1974
|
+
(owner, 2026-09-30: "remove the bot deciding pace") — and it does that where the words are
|
|
1975
|
+
spoken, not where the plan is written, so nothing between the brain and the walk decides
|
|
1976
|
+
anything. A caller's own `beat_s` tuning is what it used to override. */
|
|
1975
1977
|
/** Whether the walk WAITS for an answer before moving on. Absent = derived as today
|
|
1976
1978
|
* (a question blocks, context flows). blocking:false on a question = ask and move
|
|
1977
1979
|
* on, the claim stays pending; blocking:true on context = hold for a reply. */
|
|
@@ -2006,7 +2008,7 @@ var InboxItemSchema = z4.object({
|
|
|
2006
2008
|
* instant the agent picks it up (#997). Absent = pre-trigger row; fall back to
|
|
2007
2009
|
* `createdAt`. */
|
|
2008
2010
|
agentStateAt: z4.string().datetime().optional(),
|
|
2009
|
-
/** THE QUESTIONS A CALL CARRIES — the call screen's agenda spine (walk/design.md §11, owner
|
|
2011
|
+
/** THE QUESTIONS A CALL CARRIES — the call screen's agenda spine (docs/clients/app/walk/design.md §11, owner
|
|
2010
2012
|
* 2026-09-22). One per DecisionNeed on the Call, in the Call's order, answered or open (a
|
|
2011
2013
|
* superseded or cancelled need is no longer a question anyone is asked). Present only on a
|
|
2012
2014
|
* Call's cards, and every card of that Call carries the same list: the call screen reads it
|
|
@@ -2067,7 +2069,7 @@ var InboxItemSchema = z4.object({
|
|
|
2067
2069
|
* off the same open list the card came from, so it clears when the Call does. A card is the
|
|
2068
2070
|
* backup for a call not taken; while the call has it, the call is where it is answered. */
|
|
2069
2071
|
onCall: z4.literal(true).optional(),
|
|
2070
|
-
/** THE RING, ON THE ITEM (walk/design.md §12 §17, #2251): the last ring on this card was
|
|
2072
|
+
/** THE RING, ON THE ITEM (docs/clients/app/walk/design.md §12 §17, #2251): the last ring on this card was
|
|
2071
2073
|
* declined, and what the ladder will do next — read off the cron's own row, never computed
|
|
2072
2074
|
* on the phone. Present only while a `declined` receipt stands on the card's last Call.
|
|
2073
2075
|
* The ladder is ACCOUNT-WIDE (#2259): `anchorAt` and `step` are the account's position;
|
|
@@ -2098,7 +2100,7 @@ var InboxItemSchema = z4.object({
|
|
|
2098
2100
|
"Labels for a select:'confirm' paige \u2014 'yesno' (Yes/No) or 'approve' (Approve/Deny). Ignored unless select is 'confirm'."
|
|
2099
2101
|
),
|
|
2100
2102
|
/** Real downstream work is stuck behind this one — set by the agent, independent of
|
|
2101
|
-
* urgency (see the main README's "premier use case" + notify/states.md). Drives the
|
|
2103
|
+
* urgency (see the main README's "premier use case" + docs/delivery/notify/states.md). Drives the
|
|
2102
2104
|
* inbox's blocking badge and the extra confirm step before dismissing it. */
|
|
2103
2105
|
blocking: z4.boolean().default(false),
|
|
2104
2106
|
/** The user's locked-in answer; present only for replied items (GET /api/replied/:id). */
|
|
@@ -2172,9 +2174,16 @@ var UserSettingsSchema = z4.object({
|
|
|
2172
2174
|
banner: z4.boolean(),
|
|
2173
2175
|
push: z4.boolean()
|
|
2174
2176
|
}),
|
|
2177
|
+
/** LockedIn / Default / DateNight on screen; the stored words are unchanged on purpose —
|
|
2178
|
+
* they are an enum on a live column across every account, and the rename is a rename of
|
|
2179
|
+
* what people read (owner, 2026-09-30). */
|
|
2175
2180
|
sessionMode: z4.enum(["default", "all_calls", "silent"]),
|
|
2176
|
-
|
|
2177
|
-
|
|
2181
|
+
/** DEAD, AND ACCEPTED ANYWAY (#2813). DateNight is inbox-only with no way back, so nothing
|
|
2182
|
+
* reads this. It stays OPTIONAL rather than deleted because a phone on the old bundle
|
|
2183
|
+
* PATCHes the whole settings object and would be refused for sending a key we stopped
|
|
2184
|
+
* wanting — the same trap `voiceMode` below already documents. #2813 drops the field and
|
|
2185
|
+
* its column once no installed build still sends it. */
|
|
2186
|
+
silentPush: z4.boolean().optional(),
|
|
2178
2187
|
/** Opt-in (default false) to using your content to improve Paigy and train models. */
|
|
2179
2188
|
improveConsent: z4.boolean(),
|
|
2180
2189
|
missedCall: MissedCallSchema.default("backoff_standard"),
|
|
@@ -2185,12 +2194,16 @@ var UserSettingsSchema = z4.object({
|
|
|
2185
2194
|
* must not silently reset this privacy choice. Absent = leave unchanged on
|
|
2186
2195
|
* write, 'hosted' on read (see store.ts). */
|
|
2187
2196
|
voiceMode: z4.enum(["hosted", "on_device"]).optional(),
|
|
2188
|
-
/** Talk — after you answer, the next step is read aloud (walk/design.md §6). ALWAYS ON until
|
|
2197
|
+
/** Talk — after you answer, the next step is read aloud (docs/clients/app/walk/design.md §6). ALWAYS ON until
|
|
2189
2198
|
* turned off (owner, 2026-09-18, #2249): a setting, not a per-walk toggle. Optional, NOT
|
|
2190
2199
|
* defaulted, for the same reason `voiceMode` is: a stale client PATCHing the full settings
|
|
2191
2200
|
* object must not silently turn it back on. Absent = leave unchanged on write, true on
|
|
2192
2201
|
* read (see store.ts). */
|
|
2193
2202
|
talk: z4.boolean().optional(),
|
|
2203
|
+
/** CALL DIAGNOSTICS (owner, 2026-10-01): the call report carries each listen and the bot's own
|
|
2204
|
+
* load timings. SERVER-SET, no UI — on for every account that existed on 2026-10-01, off for
|
|
2205
|
+
* newer ones (migration 20261001132859). Read-only here: the settings PATCH never writes it. */
|
|
2206
|
+
callDiagnostics: z4.boolean().optional(),
|
|
2194
2207
|
/** Per-user ring budget (#603): calls per rolling day before further calls
|
|
2195
2208
|
* degrade to banner. Absent = the global default (25). A number, never a
|
|
2196
2209
|
* bypass — every account keeps a ceiling. No UI; set per user for testing. */
|
|
@@ -2199,9 +2212,6 @@ var UserSettingsSchema = z4.object({
|
|
|
2199
2212
|
* slower speaker). No API-side semantics; the bot resolves each key with its
|
|
2200
2213
|
* own defaults. Set per user (no UI yet); absent = bot defaults. */
|
|
2201
2214
|
voiceTuning: z4.record(z4.string(), z4.union([z4.number(), z4.string()])).optional(),
|
|
2202
|
-
/** Opt-in to real-phone (PSTN) calls when the app can't ring. Optional, not
|
|
2203
|
-
* defaulted — an older client PATCHing the full object must not clobber it. */
|
|
2204
|
-
pstnCalls: z4.boolean().optional(),
|
|
2205
2215
|
/** The user's IANA timezone (e.g. "America/Bogota"), recorded by the app — it is the
|
|
2206
2216
|
* only party that knows it. REMINDERS are why it exists: "remind me at ten" becomes
|
|
2207
2217
|
* an absolute `due_at` only if we know whose ten. Optional and never defaulted, for
|
|
@@ -2245,7 +2255,7 @@ var ConnectionSummarySchema = z4.object({
|
|
|
2245
2255
|
/** The credential kind: "device" = a paired machine (mint-only — it hosts and mints, it
|
|
2246
2256
|
* never talks); "agent" = an identity that sends. The roster and devices surfaces split
|
|
2247
2257
|
* on this. Optional/absent reads as "agent" (a row predating the kind column). See
|
|
2248
|
-
*
|
|
2258
|
+
* docs/server/tokens/devices-vs-agents-design.md. */
|
|
2249
2259
|
kind: z4.enum(["device", "agent"]).optional(),
|
|
2250
2260
|
/** For an agent, the token id of the DEVICE that minted it — so agents group under their
|
|
2251
2261
|
* machine, and revoking a device cascades to them. Null on devices, and on unlinked
|
|
@@ -2263,7 +2273,7 @@ var ConnectionSummarySchema = z4.object({
|
|
|
2263
2273
|
* user on the agent's own page. null = no ceiling (today's behaviour for every
|
|
2264
2274
|
* connection). Android binds importance to a relationship rather than to each message,
|
|
2265
2275
|
* and that is the thing our roster could not say: "Marlow may always call me; Otto
|
|
2266
|
-
* never may" (navigation-design.md, gap 2). Clamped in `arbitrateLevel`, so it binds
|
|
2276
|
+
* never may" (docs/clients/app/party/navigation-design.md, gap 2). Clamped in `arbitrateLevel`, so it binds
|
|
2267
2277
|
* every surface at once and outranks even `sessionMode: all_calls` — a mode the user
|
|
2268
2278
|
* set once must not overrule a rule they set about one agent. */
|
|
2269
2279
|
reach: NotifyLevelSchema.nullable().optional(),
|
|
@@ -2274,7 +2284,14 @@ var ConnectionSummarySchema = z4.object({
|
|
|
2274
2284
|
/** Last presence heartbeat from a running agent process (POST /api/presence) — the
|
|
2275
2285
|
* desktop app while open. Null = never seen; stale = offline. */
|
|
2276
2286
|
lastSeenAt: z4.string().datetime().nullable().optional(),
|
|
2277
|
-
/**
|
|
2287
|
+
/** WORKING, NOT JUST CONNECTED (owner, 2026-09-30): the last time the agent itself acted on one of
|
|
2288
|
+
* its Goals — took its lease or recorded an operation (`tokens.last_worked_at`). Within
|
|
2289
|
+
* `WORKING_MS` it is working; otherwise it is connected but idle. Null = not seen working yet. */
|
|
2290
|
+
lastWorkedAt: z4.string().datetime().nullable().optional(),
|
|
2291
|
+
/** The oldest of its Goals that is `ready` for it — work handed to it that nobody has started.
|
|
2292
|
+
* With no work of its own for `WORKING_MS`, an agent sitting on this is not taking its work. */
|
|
2293
|
+
oldestReadyAt: z4.string().datetime().nullable().optional(),
|
|
2294
|
+
/** What a live desktop can run (docs/clients/desktop/companion.md §2.2), advertised on its heartbeat:
|
|
2278
2295
|
* harness availabilities + granted workspaces — the option set the phone's
|
|
2279
2296
|
* "new session" sheet offers. Absent for ordinary MCP agents. */
|
|
2280
2297
|
runtime: z4.object({
|
|
@@ -2282,7 +2299,12 @@ var ConnectionSummarySchema = z4.object({
|
|
|
2282
2299
|
* shows its age here (`apps/desktop/src/update.ts`). */
|
|
2283
2300
|
version: z4.string().optional(),
|
|
2284
2301
|
harnesses: z4.array(z4.object({ name: z4.string(), label: z4.string(), status: z4.string() })).optional(),
|
|
2285
|
-
workspaces: z4.array(z4.string()).optional()
|
|
2302
|
+
workspaces: z4.array(z4.string()).optional(),
|
|
2303
|
+
/** THE GIT REPOS IN THOSE FOLDERS (2026-10-01, Goal 26982211): each granted folder that is a
|
|
2304
|
+
* repo, and each repo directly inside one, with its `origin` remote. A session started for
|
|
2305
|
+
* work on `mauurda/paigy` opens in that repo rather than the folder above it, where the repo's
|
|
2306
|
+
* own AGENTS.md is never read (`workspaceForRepo`). Absent on hosts that predate it. */
|
|
2307
|
+
repos: z4.array(z4.object({ path: z4.string(), remote: z4.string() })).optional()
|
|
2286
2308
|
}).optional(),
|
|
2287
2309
|
/** The tail of this agent's working log, when a harness is driving it — the agent page's
|
|
2288
2310
|
* live strip. Absent for anything the desktop harness isn't running (a hatched identity
|
|
@@ -2365,7 +2387,7 @@ var QueueQuestionSchema = z4.object({
|
|
|
2365
2387
|
* for a settled question whose reply carried nothing readable. */
|
|
2366
2388
|
answer: z4.string().nullable().default(null),
|
|
2367
2389
|
/** The Goal this question belongs to — a step knows its Goal on its own, not only through
|
|
2368
|
-
* an `InboxItem`'s `communication.goalIds[0]` (walk/design.md §12 item 3).
|
|
2390
|
+
* an `InboxItem`'s `communication.goalIds[0]` (docs/clients/app/walk/design.md §12 item 3).
|
|
2369
2391
|
* READ BY `apps/client/src/walk/order.ts`, which stamps it onto every `WalkStep`: the walk's
|
|
2370
2392
|
* order, its route, home's trees and the list of steps all take a step's Goal from here, so
|
|
2371
2393
|
* this is the field they agree through rather than each re-deriving it from the row it
|
|
@@ -2457,7 +2479,19 @@ var QueueItemSchema = z4.object({
|
|
|
2457
2479
|
said: z4.string(),
|
|
2458
2480
|
at: z4.string(),
|
|
2459
2481
|
entryId: z4.string()
|
|
2460
|
-
}).nullable().optional()
|
|
2482
|
+
}).nullable().optional(),
|
|
2483
|
+
/** WHEN THIS PERSON LAST PUT A HAND ON IT THEMSELVES (owner, Paigy Goal 16d18f51, 2026-09-30):
|
|
2484
|
+
* the newest Entry on the Goal they wrote, of any kind — a line they added, a reply to a note, an
|
|
2485
|
+
* answer to a question, a voice note filed as work. Null when the only hands on it have been its
|
|
2486
|
+
* agent's; optional, so a hand-built queue (fixtures, the demo) and a door older than
|
|
2487
|
+
* 20260930222356 need not spell it — `work/list.ts`'s `yoursAt` keeps its other sources, so the
|
|
2488
|
+
* Work tab orders as it did before the migration rather than throwing on the missing key.
|
|
2489
|
+
*
|
|
2490
|
+
* It is a FACT, not a reconstruction: `latest` holds one Entry, so an agent's progress note a
|
|
2491
|
+
* minute after the person speaks erases their instant from it, and the durable traces the client
|
|
2492
|
+
* can see (`replies`, `questions[].answeredAt`) miss a spontaneous note entirely — a `request`
|
|
2493
|
+
* Entry with no `about_id` is in neither. */
|
|
2494
|
+
lastPersonAt: z4.string().nullable().optional()
|
|
2461
2495
|
});
|
|
2462
2496
|
var COLD_AFTER_MS = 3 * 24 * 60 * 60 * 1e3;
|
|
2463
2497
|
var NoteSourceSchema = z4.enum(["app", "call"]);
|
|
@@ -2487,7 +2521,7 @@ var NoteSchema = z4.object({
|
|
|
2487
2521
|
assignee: z4.string().nullable(),
|
|
2488
2522
|
/** The request thread minted at assignment; null until assigned. */
|
|
2489
2523
|
parentId: z4.string().nullable(),
|
|
2490
|
-
/** REMINDERS (reminders-design.md): the NOT-BEFORE this becomes eligible to ride a
|
|
2524
|
+
/** REMINDERS (docs/model/notes/reminders-design.md): the NOT-BEFORE this becomes eligible to ride a
|
|
2491
2525
|
* call — never a deadline. It only ever comes from the user's own words, so when it
|
|
2492
2526
|
* passes Paigy rings ONCE (#1293, owner 2026-08-26: a time said out loud is consent to
|
|
2493
2527
|
* a ring at that time); after that it rides like any other. Null = "the very next
|
|
@@ -2749,6 +2783,29 @@ var SnapshotSchema = z4.object({
|
|
|
2749
2783
|
computers: z4.array(ComputerRowSchema).nullable()
|
|
2750
2784
|
}).nullable()
|
|
2751
2785
|
});
|
|
2786
|
+
var CallRecapSchema = z4.object({
|
|
2787
|
+
call: z4.object({
|
|
2788
|
+
status: z4.string(),
|
|
2789
|
+
startedAt: z4.string(),
|
|
2790
|
+
durationMs: z4.number().nullable(),
|
|
2791
|
+
agents: z4.array(z4.object({ id: z4.string(), name: z4.string().nullable() }))
|
|
2792
|
+
}),
|
|
2793
|
+
topics: z4.array(z4.object({
|
|
2794
|
+
goalId: z4.string().uuid(),
|
|
2795
|
+
title: z4.string(),
|
|
2796
|
+
owner: z4.string(),
|
|
2797
|
+
state: z4.string(),
|
|
2798
|
+
questions: z4.array(z4.object({ id: z4.string().uuid(), state: z4.string(), title: z4.string() })),
|
|
2799
|
+
/** `words` is always what they SAID, verbatim — the record, never replaced. `headline` is
|
|
2800
|
+
* their answer on one line when the call's read wrote one (owner, 2026-10-01: "render them
|
|
2801
|
+
* summarized like a pre-made option is"), so the row scans like a chosen option and their
|
|
2802
|
+
* own words stay under it. Absent on every line stored before the read wrote them, and on
|
|
2803
|
+
* anything that is not an answer. */
|
|
2804
|
+
lines: z4.array(z4.object({ entryId: z4.string().uuid(), words: z4.string(), headline: z4.string().optional() }))
|
|
2805
|
+
})),
|
|
2806
|
+
unfiled: z4.array(z4.object({ lineId: z4.string().uuid(), words: z4.string(), atMs: z4.number() })),
|
|
2807
|
+
more: z4.object({ lines: z4.number(), entries: z4.number(), topics: z4.number() })
|
|
2808
|
+
});
|
|
2752
2809
|
function sessionSlot(sessionId2) {
|
|
2753
2810
|
const id = sessionId2 ?? sessionId();
|
|
2754
2811
|
return `session:${id.slice(0, 8)}`;
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
serverInstructions,
|
|
5
5
|
sessionStartHook,
|
|
6
6
|
withSessionStartHook
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-OW65TWMX.js";
|
|
8
8
|
import {
|
|
9
9
|
agentName
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2UEIJRRC.js";
|
|
11
11
|
|
|
12
12
|
// src/toolset.ts
|
|
13
13
|
var ONBOARD_DESCRIPTION = "Get this agent talking to Paigy \u2014 call it FIRST, before contact, and any time you're unsure who you are. One call, and it does whatever the situation needs: NOT SET UP \u2192 hatches an identity instantly if this machine holds a device credential (the user ran the Paigy desktop app or harness), otherwise starts the code ceremony; ALREADY SET UP \u2192 returns your current identity and offers the two things left to decide, renaming it or unpairing; 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 (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. If it returns a `user_code`, print it to the user immediately and call onboard again with the `device_code`. If it returns `enable_command`, PRINT that command for the user to run \u2014 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.";
|
|
@@ -124,7 +124,7 @@ var GetGoalSchema = z3.object({
|
|
|
124
124
|
history: z3.boolean().optional(),
|
|
125
125
|
/** WHEN A READ HAS CONFUSED YOU. Adds `diagnosis`: every reader that already answers a question
|
|
126
126
|
* about this work, each answer attributed to the reader that gave it, and every disagreement
|
|
127
|
-
* between two of them named. Off by default; `
|
|
127
|
+
* between two of them named. Off by default; `docs/model/goal/diagnose-design.md`. */
|
|
128
128
|
diagnose: z3.boolean().optional()
|
|
129
129
|
}).strict();
|
|
130
130
|
var GET_GOAL_DESCRIPTION = "Read one Goal without claiming it: its 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. 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. Another account's Goals, and another agent's Goal that is not below one of yours, are not disclosed.\n\ndiagnose: true is for when a read has CONFUSED you \u2014 not for the working loop. It adds `diagnosis`, which asks every reader that already answers a question about your work and NAMES the reader behind every value, so you never guess which of two places to look: what state your work is really in (the stored `goals.state` beside the derived `goal_execution_state`, which can differ); whether anything is armed to ring and when (`ladder_candidates`, with the ladder's own last decision); whether a wake fired for you and what it did (durable `wake.*` events, beside when your process was last heard from); and what has reached you (`list_waiting` \u2014 review flags, unstarted work, open questions, the person's newest words). Read `diagnosis.disagreements` FIRST: each one is two readers giving different values for the same fact, with both values and both sources, and it never chooses between them \u2014 that is yours to do, from the Goal's own history. `diagnosis.looked` names every reader asked, including any that could not answer, so an empty answer is never confused with a broken one.";
|
|
@@ -149,7 +149,11 @@ HOW TO ASK:
|
|
|
149
149
|
1. One question per ask. Five questions are five objects in \`asks\`, in one contact, so each can be answered on its own; one question with five parts settles nothing until all five are answered.
|
|
150
150
|
2. Name the Goal you are working on as the ask's \`parentId\`: the question goes onto that Goal and its answer comes back there. Without one, Paigy places it.
|
|
151
151
|
3. \`waiting: hard\` only for a decision you are blocked on; \`waiting: none\` for a question you can keep working around.
|
|
152
|
-
4. Never hold the process open with while-loops. For an open Call with a pending decision, follow its \`next\` with another bounded \`contact({deliveryId})\` tool call; a returned wait window is not a completed conversation. Otherwise, yield only with a working listener or scheduled wakeup, and collect answers with \`check_replies\` or \`claim_goal\` on that wake
|
|
152
|
+
4. Never hold the process open with while-loops. For an open Call with a pending decision, follow its \`next\` with another bounded \`contact({deliveryId})\` tool call; a returned wait window is not a completed conversation. Otherwise, yield only with a working listener or scheduled wakeup, and collect answers with \`check_replies\` or \`claim_goal\` on that wake.
|
|
153
|
+
5. One ask, one row. Never restate a question that is still waiting inside a new contact: keep waiting on the original, or the answer lands on one copy and the other stays open.
|
|
154
|
+
6. Read the Goal's conversation before asking. Never ask again what was answered or already shipped.
|
|
155
|
+
7. A question carries its options. Without them it reaches the person as a bare title nobody can answer.
|
|
156
|
+
8. A diagnosis says when, why and how it happens, then proposes one fix. Never options first.`;
|
|
153
157
|
}
|
|
154
158
|
function entryWords(entry) {
|
|
155
159
|
const content = entry.content;
|
|
@@ -167,6 +171,7 @@ function entryWords(entry) {
|
|
|
167
171
|
return entry.sources.map((source) => source.text).join("\n");
|
|
168
172
|
}
|
|
169
173
|
var LIVE_MS = 3 * 6e4;
|
|
174
|
+
var WORKING_MS = 30 * 6e4;
|
|
170
175
|
var ContextSchema = z4.object({
|
|
171
176
|
title: z4.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
|
|
172
177
|
description: z4.array(z4.string().min(1)).describe(
|
|
@@ -237,7 +242,7 @@ var AttentionSchema = z4.object({
|
|
|
237
242
|
points: z4.array(z4.string()).nullable(),
|
|
238
243
|
/** Whether the ask blocks the sender — what lets arbitration escalate it on silence. */
|
|
239
244
|
blocking: z4.boolean(),
|
|
240
|
-
/** Reserved (
|
|
245
|
+
/** Reserved (docs/model/model.md lists it): a response deadline. No row column yet — a later Phase 2
|
|
241
246
|
* slice wires it; optional so today's rows/callers project cleanly. */
|
|
242
247
|
deadline: z4.string().datetime().nullable().optional()
|
|
243
248
|
});
|
|
@@ -288,7 +293,7 @@ var NotifyRequestFields = z4.object({
|
|
|
288
293
|
* derive agent-side before sealing, so the server only ever shapes plaintext). */
|
|
289
294
|
// 10k, not a sentence budget. What the human hears is bounded by the BROKER — it splits
|
|
290
295
|
// the ask into topics and gives each one at most three sentences and one question
|
|
291
|
-
// (broker/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
|
|
296
|
+
// (docs/brain/broker/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
|
|
292
297
|
// Owner, 2026-07-28: "our actual limitation on how long something is to the user should
|
|
293
298
|
// come from the broker splitting and summarizing." The cap that remains is a size guard.
|
|
294
299
|
ask: z4.string().min(1).max(1e4).optional().describe(
|
|
@@ -365,7 +370,7 @@ var UserAnswerSchema = z4.discriminatedUnion("kind", [
|
|
|
365
370
|
z4.object({ kind: z4.literal("clarify"), chunks: z4.array(z4.string()).min(1) }),
|
|
366
371
|
z4.object({ kind: z4.literal("confirm"), approved: z4.boolean() }),
|
|
367
372
|
z4.object({ kind: z4.literal("turns"), turns: z4.array(TurnSchema).min(1) }),
|
|
368
|
-
/** An auto-answer derived from the user's PAST decisions (broker/precedent-design.md §2):
|
|
373
|
+
/** An auto-answer derived from the user's PAST decisions (docs/brain/broker/precedent-design.md §2):
|
|
369
374
|
* delivered through the same settle/await path as a human answer, carrying the judge's
|
|
370
375
|
* derivation and the precedent ids it grew from. Always paired with a visible trail
|
|
371
376
|
* card the user can reply to — the broker never overrides the user. */
|
|
@@ -414,7 +419,7 @@ var AwaitItemSchema = z4.discriminatedUnion("type", [
|
|
|
414
419
|
* and now knows exactly which call to make. Absent when either half is missing —
|
|
415
420
|
* a sentence with a hole in it is worse than no sentence. */
|
|
416
421
|
note: z4.string().optional(),
|
|
417
|
-
/** The call record rendered for THIS agent (`voice/record-design.md`): the words the
|
|
422
|
+
/** The call record rendered for THIS agent (`docs/brain/voice/record-design.md`): the words the
|
|
418
423
|
* shaped answer was mapped from, filtered to its own claims. There is no second list
|
|
419
424
|
* of labels beside it — the acts went 2026-09-04 and `intents` went with them (owner,
|
|
420
425
|
* 2026-09-04): the agent reads the sentence and decides. */
|
|
@@ -510,10 +515,11 @@ var AgendaTurnSchema = z4.object({
|
|
|
510
515
|
agentId: z4.string().optional(),
|
|
511
516
|
select: SelectShapeSchema.optional(),
|
|
512
517
|
options: z4.array(OptionSchema.omit({ id: true })).optional(),
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
518
|
+
/* `pace` STOOD HERE (#826). A turn could carry seconds and the model chose them. The walk
|
|
519
|
+
paces itself now — a short beat between the sentences of a turn, the longer one at its end
|
|
520
|
+
(owner, 2026-09-30: "remove the bot deciding pace") — and it does that where the words are
|
|
521
|
+
spoken, not where the plan is written, so nothing between the brain and the walk decides
|
|
522
|
+
anything. A caller's own `beat_s` tuning is what it used to override. */
|
|
517
523
|
/** Whether the walk WAITS for an answer before moving on. Absent = derived as today
|
|
518
524
|
* (a question blocks, context flows). blocking:false on a question = ask and move
|
|
519
525
|
* on, the claim stays pending; blocking:true on context = hold for a reply. */
|
|
@@ -548,7 +554,7 @@ var InboxItemSchema = z4.object({
|
|
|
548
554
|
* instant the agent picks it up (#997). Absent = pre-trigger row; fall back to
|
|
549
555
|
* `createdAt`. */
|
|
550
556
|
agentStateAt: z4.string().datetime().optional(),
|
|
551
|
-
/** THE QUESTIONS A CALL CARRIES — the call screen's agenda spine (walk/design.md §11, owner
|
|
557
|
+
/** THE QUESTIONS A CALL CARRIES — the call screen's agenda spine (docs/clients/app/walk/design.md §11, owner
|
|
552
558
|
* 2026-09-22). One per DecisionNeed on the Call, in the Call's order, answered or open (a
|
|
553
559
|
* superseded or cancelled need is no longer a question anyone is asked). Present only on a
|
|
554
560
|
* Call's cards, and every card of that Call carries the same list: the call screen reads it
|
|
@@ -609,7 +615,7 @@ var InboxItemSchema = z4.object({
|
|
|
609
615
|
* off the same open list the card came from, so it clears when the Call does. A card is the
|
|
610
616
|
* backup for a call not taken; while the call has it, the call is where it is answered. */
|
|
611
617
|
onCall: z4.literal(true).optional(),
|
|
612
|
-
/** THE RING, ON THE ITEM (walk/design.md §12 §17, #2251): the last ring on this card was
|
|
618
|
+
/** THE RING, ON THE ITEM (docs/clients/app/walk/design.md §12 §17, #2251): the last ring on this card was
|
|
613
619
|
* declined, and what the ladder will do next — read off the cron's own row, never computed
|
|
614
620
|
* on the phone. Present only while a `declined` receipt stands on the card's last Call.
|
|
615
621
|
* The ladder is ACCOUNT-WIDE (#2259): `anchorAt` and `step` are the account's position;
|
|
@@ -640,7 +646,7 @@ var InboxItemSchema = z4.object({
|
|
|
640
646
|
"Labels for a select:'confirm' paige \u2014 'yesno' (Yes/No) or 'approve' (Approve/Deny). Ignored unless select is 'confirm'."
|
|
641
647
|
),
|
|
642
648
|
/** Real downstream work is stuck behind this one — set by the agent, independent of
|
|
643
|
-
* urgency (see the main README's "premier use case" + notify/states.md). Drives the
|
|
649
|
+
* urgency (see the main README's "premier use case" + docs/delivery/notify/states.md). Drives the
|
|
644
650
|
* inbox's blocking badge and the extra confirm step before dismissing it. */
|
|
645
651
|
blocking: z4.boolean().default(false),
|
|
646
652
|
/** The user's locked-in answer; present only for replied items (GET /api/replied/:id). */
|
|
@@ -714,9 +720,16 @@ var UserSettingsSchema = z4.object({
|
|
|
714
720
|
banner: z4.boolean(),
|
|
715
721
|
push: z4.boolean()
|
|
716
722
|
}),
|
|
723
|
+
/** LockedIn / Default / DateNight on screen; the stored words are unchanged on purpose —
|
|
724
|
+
* they are an enum on a live column across every account, and the rename is a rename of
|
|
725
|
+
* what people read (owner, 2026-09-30). */
|
|
717
726
|
sessionMode: z4.enum(["default", "all_calls", "silent"]),
|
|
718
|
-
|
|
719
|
-
|
|
727
|
+
/** DEAD, AND ACCEPTED ANYWAY (#2813). DateNight is inbox-only with no way back, so nothing
|
|
728
|
+
* reads this. It stays OPTIONAL rather than deleted because a phone on the old bundle
|
|
729
|
+
* PATCHes the whole settings object and would be refused for sending a key we stopped
|
|
730
|
+
* wanting — the same trap `voiceMode` below already documents. #2813 drops the field and
|
|
731
|
+
* its column once no installed build still sends it. */
|
|
732
|
+
silentPush: z4.boolean().optional(),
|
|
720
733
|
/** Opt-in (default false) to using your content to improve Paigy and train models. */
|
|
721
734
|
improveConsent: z4.boolean(),
|
|
722
735
|
missedCall: MissedCallSchema.default("backoff_standard"),
|
|
@@ -727,12 +740,16 @@ var UserSettingsSchema = z4.object({
|
|
|
727
740
|
* must not silently reset this privacy choice. Absent = leave unchanged on
|
|
728
741
|
* write, 'hosted' on read (see store.ts). */
|
|
729
742
|
voiceMode: z4.enum(["hosted", "on_device"]).optional(),
|
|
730
|
-
/** Talk — after you answer, the next step is read aloud (walk/design.md §6). ALWAYS ON until
|
|
743
|
+
/** Talk — after you answer, the next step is read aloud (docs/clients/app/walk/design.md §6). ALWAYS ON until
|
|
731
744
|
* turned off (owner, 2026-09-18, #2249): a setting, not a per-walk toggle. Optional, NOT
|
|
732
745
|
* defaulted, for the same reason `voiceMode` is: a stale client PATCHing the full settings
|
|
733
746
|
* object must not silently turn it back on. Absent = leave unchanged on write, true on
|
|
734
747
|
* read (see store.ts). */
|
|
735
748
|
talk: z4.boolean().optional(),
|
|
749
|
+
/** CALL DIAGNOSTICS (owner, 2026-10-01): the call report carries each listen and the bot's own
|
|
750
|
+
* load timings. SERVER-SET, no UI — on for every account that existed on 2026-10-01, off for
|
|
751
|
+
* newer ones (migration 20261001132859). Read-only here: the settings PATCH never writes it. */
|
|
752
|
+
callDiagnostics: z4.boolean().optional(),
|
|
736
753
|
/** Per-user ring budget (#603): calls per rolling day before further calls
|
|
737
754
|
* degrade to banner. Absent = the global default (25). A number, never a
|
|
738
755
|
* bypass — every account keeps a ceiling. No UI; set per user for testing. */
|
|
@@ -741,9 +758,6 @@ var UserSettingsSchema = z4.object({
|
|
|
741
758
|
* slower speaker). No API-side semantics; the bot resolves each key with its
|
|
742
759
|
* own defaults. Set per user (no UI yet); absent = bot defaults. */
|
|
743
760
|
voiceTuning: z4.record(z4.string(), z4.union([z4.number(), z4.string()])).optional(),
|
|
744
|
-
/** Opt-in to real-phone (PSTN) calls when the app can't ring. Optional, not
|
|
745
|
-
* defaulted — an older client PATCHing the full object must not clobber it. */
|
|
746
|
-
pstnCalls: z4.boolean().optional(),
|
|
747
761
|
/** The user's IANA timezone (e.g. "America/Bogota"), recorded by the app — it is the
|
|
748
762
|
* only party that knows it. REMINDERS are why it exists: "remind me at ten" becomes
|
|
749
763
|
* an absolute `due_at` only if we know whose ten. Optional and never defaulted, for
|
|
@@ -787,7 +801,7 @@ var ConnectionSummarySchema = z4.object({
|
|
|
787
801
|
/** The credential kind: "device" = a paired machine (mint-only — it hosts and mints, it
|
|
788
802
|
* never talks); "agent" = an identity that sends. The roster and devices surfaces split
|
|
789
803
|
* on this. Optional/absent reads as "agent" (a row predating the kind column). See
|
|
790
|
-
*
|
|
804
|
+
* docs/server/tokens/devices-vs-agents-design.md. */
|
|
791
805
|
kind: z4.enum(["device", "agent"]).optional(),
|
|
792
806
|
/** For an agent, the token id of the DEVICE that minted it — so agents group under their
|
|
793
807
|
* machine, and revoking a device cascades to them. Null on devices, and on unlinked
|
|
@@ -805,7 +819,7 @@ var ConnectionSummarySchema = z4.object({
|
|
|
805
819
|
* user on the agent's own page. null = no ceiling (today's behaviour for every
|
|
806
820
|
* connection). Android binds importance to a relationship rather than to each message,
|
|
807
821
|
* and that is the thing our roster could not say: "Marlow may always call me; Otto
|
|
808
|
-
* never may" (navigation-design.md, gap 2). Clamped in `arbitrateLevel`, so it binds
|
|
822
|
+
* never may" (docs/clients/app/party/navigation-design.md, gap 2). Clamped in `arbitrateLevel`, so it binds
|
|
809
823
|
* every surface at once and outranks even `sessionMode: all_calls` — a mode the user
|
|
810
824
|
* set once must not overrule a rule they set about one agent. */
|
|
811
825
|
reach: NotifyLevelSchema.nullable().optional(),
|
|
@@ -816,7 +830,14 @@ var ConnectionSummarySchema = z4.object({
|
|
|
816
830
|
/** Last presence heartbeat from a running agent process (POST /api/presence) — the
|
|
817
831
|
* desktop app while open. Null = never seen; stale = offline. */
|
|
818
832
|
lastSeenAt: z4.string().datetime().nullable().optional(),
|
|
819
|
-
/**
|
|
833
|
+
/** WORKING, NOT JUST CONNECTED (owner, 2026-09-30): the last time the agent itself acted on one of
|
|
834
|
+
* its Goals — took its lease or recorded an operation (`tokens.last_worked_at`). Within
|
|
835
|
+
* `WORKING_MS` it is working; otherwise it is connected but idle. Null = not seen working yet. */
|
|
836
|
+
lastWorkedAt: z4.string().datetime().nullable().optional(),
|
|
837
|
+
/** The oldest of its Goals that is `ready` for it — work handed to it that nobody has started.
|
|
838
|
+
* With no work of its own for `WORKING_MS`, an agent sitting on this is not taking its work. */
|
|
839
|
+
oldestReadyAt: z4.string().datetime().nullable().optional(),
|
|
840
|
+
/** What a live desktop can run (docs/clients/desktop/companion.md §2.2), advertised on its heartbeat:
|
|
820
841
|
* harness availabilities + granted workspaces — the option set the phone's
|
|
821
842
|
* "new session" sheet offers. Absent for ordinary MCP agents. */
|
|
822
843
|
runtime: z4.object({
|
|
@@ -824,7 +845,12 @@ var ConnectionSummarySchema = z4.object({
|
|
|
824
845
|
* shows its age here (`apps/desktop/src/update.ts`). */
|
|
825
846
|
version: z4.string().optional(),
|
|
826
847
|
harnesses: z4.array(z4.object({ name: z4.string(), label: z4.string(), status: z4.string() })).optional(),
|
|
827
|
-
workspaces: z4.array(z4.string()).optional()
|
|
848
|
+
workspaces: z4.array(z4.string()).optional(),
|
|
849
|
+
/** THE GIT REPOS IN THOSE FOLDERS (2026-10-01, Goal 26982211): each granted folder that is a
|
|
850
|
+
* repo, and each repo directly inside one, with its `origin` remote. A session started for
|
|
851
|
+
* work on `mauurda/paigy` opens in that repo rather than the folder above it, where the repo's
|
|
852
|
+
* own AGENTS.md is never read (`workspaceForRepo`). Absent on hosts that predate it. */
|
|
853
|
+
repos: z4.array(z4.object({ path: z4.string(), remote: z4.string() })).optional()
|
|
828
854
|
}).optional(),
|
|
829
855
|
/** The tail of this agent's working log, when a harness is driving it — the agent page's
|
|
830
856
|
* live strip. Absent for anything the desktop harness isn't running (a hatched identity
|
|
@@ -907,7 +933,7 @@ var QueueQuestionSchema = z4.object({
|
|
|
907
933
|
* for a settled question whose reply carried nothing readable. */
|
|
908
934
|
answer: z4.string().nullable().default(null),
|
|
909
935
|
/** The Goal this question belongs to — a step knows its Goal on its own, not only through
|
|
910
|
-
* an `InboxItem`'s `communication.goalIds[0]` (walk/design.md §12 item 3).
|
|
936
|
+
* an `InboxItem`'s `communication.goalIds[0]` (docs/clients/app/walk/design.md §12 item 3).
|
|
911
937
|
* READ BY `apps/client/src/walk/order.ts`, which stamps it onto every `WalkStep`: the walk's
|
|
912
938
|
* order, its route, home's trees and the list of steps all take a step's Goal from here, so
|
|
913
939
|
* this is the field they agree through rather than each re-deriving it from the row it
|
|
@@ -999,7 +1025,19 @@ var QueueItemSchema = z4.object({
|
|
|
999
1025
|
said: z4.string(),
|
|
1000
1026
|
at: z4.string(),
|
|
1001
1027
|
entryId: z4.string()
|
|
1002
|
-
}).nullable().optional()
|
|
1028
|
+
}).nullable().optional(),
|
|
1029
|
+
/** WHEN THIS PERSON LAST PUT A HAND ON IT THEMSELVES (owner, Paigy Goal 16d18f51, 2026-09-30):
|
|
1030
|
+
* the newest Entry on the Goal they wrote, of any kind — a line they added, a reply to a note, an
|
|
1031
|
+
* answer to a question, a voice note filed as work. Null when the only hands on it have been its
|
|
1032
|
+
* agent's; optional, so a hand-built queue (fixtures, the demo) and a door older than
|
|
1033
|
+
* 20260930222356 need not spell it — `work/list.ts`'s `yoursAt` keeps its other sources, so the
|
|
1034
|
+
* Work tab orders as it did before the migration rather than throwing on the missing key.
|
|
1035
|
+
*
|
|
1036
|
+
* It is a FACT, not a reconstruction: `latest` holds one Entry, so an agent's progress note a
|
|
1037
|
+
* minute after the person speaks erases their instant from it, and the durable traces the client
|
|
1038
|
+
* can see (`replies`, `questions[].answeredAt`) miss a spontaneous note entirely — a `request`
|
|
1039
|
+
* Entry with no `about_id` is in neither. */
|
|
1040
|
+
lastPersonAt: z4.string().nullable().optional()
|
|
1003
1041
|
});
|
|
1004
1042
|
var COLD_AFTER_MS = 3 * 24 * 60 * 60 * 1e3;
|
|
1005
1043
|
var NoteSourceSchema = z4.enum(["app", "call"]);
|
|
@@ -1029,7 +1067,7 @@ var NoteSchema = z4.object({
|
|
|
1029
1067
|
assignee: z4.string().nullable(),
|
|
1030
1068
|
/** The request thread minted at assignment; null until assigned. */
|
|
1031
1069
|
parentId: z4.string().nullable(),
|
|
1032
|
-
/** REMINDERS (reminders-design.md): the NOT-BEFORE this becomes eligible to ride a
|
|
1070
|
+
/** REMINDERS (docs/model/notes/reminders-design.md): the NOT-BEFORE this becomes eligible to ride a
|
|
1033
1071
|
* call — never a deadline. It only ever comes from the user's own words, so when it
|
|
1034
1072
|
* passes Paigy rings ONCE (#1293, owner 2026-08-26: a time said out loud is consent to
|
|
1035
1073
|
* a ring at that time); after that it rides like any other. Null = "the very next
|
|
@@ -1289,6 +1327,29 @@ var SnapshotSchema = z4.object({
|
|
|
1289
1327
|
computers: z4.array(ComputerRowSchema).nullable()
|
|
1290
1328
|
}).nullable()
|
|
1291
1329
|
});
|
|
1330
|
+
var CallRecapSchema = z4.object({
|
|
1331
|
+
call: z4.object({
|
|
1332
|
+
status: z4.string(),
|
|
1333
|
+
startedAt: z4.string(),
|
|
1334
|
+
durationMs: z4.number().nullable(),
|
|
1335
|
+
agents: z4.array(z4.object({ id: z4.string(), name: z4.string().nullable() }))
|
|
1336
|
+
}),
|
|
1337
|
+
topics: z4.array(z4.object({
|
|
1338
|
+
goalId: z4.string().uuid(),
|
|
1339
|
+
title: z4.string(),
|
|
1340
|
+
owner: z4.string(),
|
|
1341
|
+
state: z4.string(),
|
|
1342
|
+
questions: z4.array(z4.object({ id: z4.string().uuid(), state: z4.string(), title: z4.string() })),
|
|
1343
|
+
/** `words` is always what they SAID, verbatim — the record, never replaced. `headline` is
|
|
1344
|
+
* their answer on one line when the call's read wrote one (owner, 2026-10-01: "render them
|
|
1345
|
+
* summarized like a pre-made option is"), so the row scans like a chosen option and their
|
|
1346
|
+
* own words stay under it. Absent on every line stored before the read wrote them, and on
|
|
1347
|
+
* anything that is not an answer. */
|
|
1348
|
+
lines: z4.array(z4.object({ entryId: z4.string().uuid(), words: z4.string(), headline: z4.string().optional() }))
|
|
1349
|
+
})),
|
|
1350
|
+
unfiled: z4.array(z4.object({ lineId: z4.string().uuid(), words: z4.string(), atMs: z4.number() })),
|
|
1351
|
+
more: z4.object({ lines: z4.number(), entries: z4.number(), topics: z4.number() })
|
|
1352
|
+
});
|
|
1292
1353
|
|
|
1293
1354
|
// src/listening.ts
|
|
1294
1355
|
import { chmodSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
package/dist/enable.js
CHANGED
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
PAIGY_TOOL_IDS,
|
|
4
4
|
enablePaigyTools,
|
|
5
5
|
installSessionListening
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-B7SEHASI.js";
|
|
7
|
+
import "./chunk-OW65TWMX.js";
|
|
8
|
+
import "./chunk-2UEIJRRC.js";
|
|
9
9
|
|
|
10
10
|
// src/enable.ts
|
|
11
11
|
function main() {
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
resolvePairing,
|
|
7
7
|
startPairing,
|
|
8
8
|
suggestedAgentName
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-LRN27BMO.js";
|
|
10
10
|
import {
|
|
11
11
|
ENABLE_COMMAND,
|
|
12
12
|
OnboardSchema,
|
|
@@ -15,11 +15,11 @@ import {
|
|
|
15
15
|
SERVER_INSTRUCTIONS,
|
|
16
16
|
TOOLS,
|
|
17
17
|
paigyToolsAllowlisted
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-B7SEHASI.js";
|
|
19
19
|
import {
|
|
20
20
|
decideListen,
|
|
21
21
|
listenerAlive
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-OW65TWMX.js";
|
|
23
23
|
import {
|
|
24
24
|
clearSurface,
|
|
25
25
|
writeSurface
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
sessionId,
|
|
40
40
|
slotName,
|
|
41
41
|
whoAmI
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-2UEIJRRC.js";
|
|
43
43
|
|
|
44
44
|
// src/index.ts
|
|
45
45
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -50,6 +50,40 @@ import {
|
|
|
50
50
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
51
51
|
import { fileURLToPath } from "url";
|
|
52
52
|
import qrcode from "qrcode-generator";
|
|
53
|
+
|
|
54
|
+
// src/survive.ts
|
|
55
|
+
function detail(cause) {
|
|
56
|
+
const stack = cause?.stack;
|
|
57
|
+
return stack ? stack : String(cause);
|
|
58
|
+
}
|
|
59
|
+
function guardTheProcess(proc, log) {
|
|
60
|
+
proc.on("unhandledRejection", (reason) => {
|
|
61
|
+
log(
|
|
62
|
+
`paigy: a promise failed with nobody waiting \u2014 the server stays up and its tools keep working (${detail(reason)})`
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
proc.on("uncaughtException", (error) => {
|
|
66
|
+
log(
|
|
67
|
+
`paigy: an error escaped every catch \u2014 the server stays up and its tools keep working (${detail(error)})`
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function traceTheTransport(transport2, log) {
|
|
72
|
+
const theirError = transport2.onerror;
|
|
73
|
+
transport2.onerror = (error) => {
|
|
74
|
+
log(`paigy: the stdio stream errored \u2014 the host may be dropping this server (${detail(error)})`);
|
|
75
|
+
theirError?.(error);
|
|
76
|
+
};
|
|
77
|
+
const theirClose = transport2.onclose;
|
|
78
|
+
transport2.onclose = () => {
|
|
79
|
+
log(
|
|
80
|
+
"paigy: the stdio stream closed \u2014 the host dropped this server, so its tools are gone from this session until the host restarts it (in Claude Code: `/mcp paigy reconnect`)"
|
|
81
|
+
);
|
|
82
|
+
theirClose?.();
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/index.ts
|
|
53
87
|
var JOIN_CAP_MS = 45e3;
|
|
54
88
|
function pairedResult(token, sas, note) {
|
|
55
89
|
clearSurface();
|
|
@@ -349,5 +383,7 @@ async function beat() {
|
|
|
349
383
|
}
|
|
350
384
|
void beat();
|
|
351
385
|
setInterval(() => void beat(), 6e4).unref();
|
|
386
|
+
guardTheProcess(process, (line) => console.error(line));
|
|
352
387
|
var transport = new StdioServerTransport();
|
|
388
|
+
traceTheTransport(transport, (line) => console.error(line));
|
|
353
389
|
await server.connect(transport);
|
package/dist/listen.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
entryWords,
|
|
4
4
|
removeListenMark,
|
|
5
5
|
writeListenMark
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-OW65TWMX.js";
|
|
7
7
|
import {
|
|
8
8
|
agentName,
|
|
9
9
|
checkReplies,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
getGoal,
|
|
12
12
|
slotName,
|
|
13
13
|
subscribeWake
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-2UEIJRRC.js";
|
|
15
15
|
|
|
16
16
|
// src/listen.ts
|
|
17
17
|
import { spawn } from "child_process";
|
package/dist/onboard.js
CHANGED
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
resolvePairing,
|
|
4
4
|
startPairing,
|
|
5
5
|
suggestedAgentName
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-LRN27BMO.js";
|
|
7
7
|
import {
|
|
8
8
|
autoConfigureClients,
|
|
9
9
|
claudeInstallHint,
|
|
10
10
|
openBrowser
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-B7SEHASI.js";
|
|
12
|
+
import "./chunk-OW65TWMX.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-
|
|
23
|
+
} from "./chunk-2UEIJRRC.js";
|
|
24
24
|
|
|
25
25
|
// src/onboard.ts
|
|
26
26
|
function reportRegistered() {
|
package/dist/slot.js
CHANGED
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 { checkReplies } = await import("./dist-
|
|
32
|
+
const { checkReplies } = await import("./dist-VVU24KB2.js");
|
|
33
33
|
const reply = stopReply((await checkReplies()).stalled ?? [], input.hook_event_name ?? "Stop");
|
|
34
34
|
if (!reply) return;
|
|
35
35
|
mkdirSync(dir, { recursive: true });
|
package/dist/statusline.js
CHANGED
package/package.json
CHANGED