@paigy/harness 0.3.29 → 0.3.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/cli.js +204 -57
- package/dist/main.js +207 -60
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -24186,7 +24186,7 @@ async function subscribeWake(onNudge, opts = {}) {
|
|
|
24186
24186
|
}
|
|
24187
24187
|
};
|
|
24188
24188
|
}
|
|
24189
|
-
var import_undici, require2, BACKEND_URL, NETWORK_MSG, PROXY_ENV, agent, INSTANCE_ID, WORKSPACE_ID, envSession, lineage, ignoreOverride, defaultOptions, getDefaultOptions, getRefs, getRelativePath, parseCatchDef, integerDateParser, isJsonSchema7AllOfType, emojiRegex2, zodPatterns, ALPHA_NUMERIC, primitiveMappings, asAnyOf, parseOptionalDef, parsePipelineDef, parseReadonlyDef, selectParser, get$ref, addMeta, zodToJsonSchema, OPTIONS_MIN, OPTIONS_MAX, OptionSchema, OptionInputSchema, NIGHT, AskInputSchema, StartContactSchema, ContactSchema, CONTACT_SCHEMA, CONTACT_DESCRIPTION, CreateGoalSchema, CreateGoalToolSchema, CREATE_GOAL_DESCRIPTION, UpdateGoalSchema, UpdateGoalToolSchema, ClaimGoalSchema, GetGoalSchema, GET_GOAL_DESCRIPTION, UPDATE_GOAL_DESCRIPTION, CLAIM_GOAL_DESCRIPTION, CHECK_REPLIES_DESCRIPTION, CheckRepliesSchema, AGENT_TOOLS, AGENT_TOOL_NAMES, LIVE_MS, ContextSchema, ParticipantSchema, TransformSchema, VisualSchema, NotifyLevelSchema, SelectShapeSchema, ReceiptEventSchema, AttentionSchema, NotifyRequestFields, NotifyRequestSchema, NotifyStatusSchema, AgentStateSchema, TurnSchema, UserAnswerSchema, IntentSchema, RideAlongSchema, AwaitItemSchema, VoiceKeySchema, AgendaTurnSchema, CLAIM_STALE_MS, InboxItemSchema, APNS_TOKEN_RE, PushTokenSchema, MissedCallSchema, clock, QUIET, BrokerTuningSchema, UserSettingsSchema, HistoryWorkSchema, HistoryEntrySchema, HistoryPageSchema, ACTIVITY_LINES, ACTIVITY_LINE_MAX, AgentActivitySchema, ConnectionSummarySchema, LedgerItemSchema, AgentLedgerSchema, ReassignResultSchema, MoveRingSchema, MoveSchema, QueueQuestionSchema, QueueReplySchema, QueueItemSchema, COLD_AFTER_MS, NoteSourceSchema, NoteStatusSchema, NoteRepeatSchema, DecisionSchema, NoteSchema, TriageItemSchema, TriageAssignmentSchema, TriageStatusSchema, SubmitTriageSchema, TriageProposalSchema, AcceptTriageSchema, AcceptTriageResultSchema, DeliveryModeSchema, WAKE_EVENT, wakeChannel, RegisterDeliverySchema, OAuthStartSchema, DeliveryConfigSchema, HostDecisionSchema, WakeNudgeSchema, PairingStatusSchema, DeviceCodeSchema, DeviceInfoSchema, DeviceTokenSchema, SupportRequestSchema, NotificationFeedbackKindSchema, SlimOptionSchema, QuestionRowSchema, WorkStateSchema, WorkRowSchema, ComputerRowSchema, AgentRowSchema, SnapshotSchema, TOKEN_PATH, KEY_PATH, sleep, UnpairedError, RevokedError, ApiError, tokenOverride, authToken, AWAIT_WINDOW_MS, asked, NOT_SENT, HEARTBEAT_MS, RETRY_MS, JOIN, JOIN_TIMEOUT_MS, lines;
|
|
24189
|
+
var import_undici, require2, BACKEND_URL, NETWORK_MSG, PROXY_ENV, agent, INSTANCE_ID, WORKSPACE_ID, envSession, lineage, ignoreOverride, defaultOptions, getDefaultOptions, getRefs, getRelativePath, parseCatchDef, integerDateParser, isJsonSchema7AllOfType, emojiRegex2, zodPatterns, ALPHA_NUMERIC, primitiveMappings, asAnyOf, parseOptionalDef, parsePipelineDef, parseReadonlyDef, selectParser, get$ref, addMeta, zodToJsonSchema, OPTIONS_MIN, OPTIONS_MAX, OptionSchema, OptionInputSchema, NIGHT, AskInputSchema, StartContactSchema, ContactSchema, CONTACT_SCHEMA, CONTACT_DESCRIPTION, CreateGoalSchema, CreateGoalToolSchema, CREATE_GOAL_DESCRIPTION, UpdateGoalSchema, UpdateGoalToolSchema, ClaimGoalSchema, GetGoalSchema, GET_GOAL_DESCRIPTION, UPDATE_GOAL_DESCRIPTION, CLAIM_GOAL_DESCRIPTION, CHECK_REPLIES_DESCRIPTION, CheckRepliesSchema, AGENT_TOOLS, AGENT_TOOL_NAMES, LIVE_MS, WORKING_MS, ContextSchema, ParticipantSchema, TransformSchema, VisualSchema, NotifyLevelSchema, SelectShapeSchema, ReceiptEventSchema, AttentionSchema, NotifyRequestFields, NotifyRequestSchema, NotifyStatusSchema, AgentStateSchema, TurnSchema, UserAnswerSchema, IntentSchema, RideAlongSchema, AwaitItemSchema, VoiceKeySchema, AgendaTurnSchema, CLAIM_STALE_MS, InboxItemSchema, APNS_TOKEN_RE, PushTokenSchema, MissedCallSchema, clock, QUIET, BrokerTuningSchema, UserSettingsSchema, HistoryWorkSchema, HistoryEntrySchema, HistoryPageSchema, ACTIVITY_LINES, ACTIVITY_LINE_MAX, AgentActivitySchema, ConnectionSummarySchema, LedgerItemSchema, AgentLedgerSchema, ReassignResultSchema, MoveRingSchema, MoveSchema, QueueQuestionSchema, QueueReplySchema, QueueItemSchema, COLD_AFTER_MS, NoteSourceSchema, NoteStatusSchema, NoteRepeatSchema, DecisionSchema, NoteSchema, TriageItemSchema, TriageAssignmentSchema, TriageStatusSchema, SubmitTriageSchema, TriageProposalSchema, AcceptTriageSchema, AcceptTriageResultSchema, DeliveryModeSchema, WAKE_EVENT, wakeChannel, RegisterDeliverySchema, OAuthStartSchema, DeliveryConfigSchema, HostDecisionSchema, WakeNudgeSchema, PairingStatusSchema, DeviceCodeSchema, DeviceInfoSchema, DeviceTokenSchema, SupportRequestSchema, NotificationFeedbackKindSchema, SlimOptionSchema, QuestionRowSchema, WorkStateSchema, WorkRowSchema, ComputerRowSchema, AgentRowSchema, SnapshotSchema, CallRecapSchema, TOKEN_PATH, KEY_PATH, sleep, UnpairedError, RevokedError, ApiError, tokenOverride, authToken, AWAIT_WINDOW_MS, asked, NOT_SENT, HEARTBEAT_MS, RETRY_MS, JOIN, JOIN_TIMEOUT_MS, lines;
|
|
24190
24190
|
var init_dist = __esm({
|
|
24191
24191
|
"../../packages/sdk/dist/index.js"() {
|
|
24192
24192
|
"use strict";
|
|
@@ -24666,7 +24666,7 @@ var init_dist = __esm({
|
|
|
24666
24666
|
history: external_exports.boolean().optional(),
|
|
24667
24667
|
/** WHEN A READ HAS CONFUSED YOU. Adds `diagnosis`: every reader that already answers a question
|
|
24668
24668
|
* about this work, each answer attributed to the reader that gave it, and every disagreement
|
|
24669
|
-
* between two of them named. Off by default; `
|
|
24669
|
+
* between two of them named. Off by default; `docs/model/goal/diagnose-design.md`. */
|
|
24670
24670
|
diagnose: external_exports.boolean().optional()
|
|
24671
24671
|
}).strict();
|
|
24672
24672
|
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.";
|
|
@@ -24684,6 +24684,7 @@ var init_dist = __esm({
|
|
|
24684
24684
|
];
|
|
24685
24685
|
AGENT_TOOL_NAMES = AGENT_TOOLS.map((t) => t.name);
|
|
24686
24686
|
LIVE_MS = 3 * 6e4;
|
|
24687
|
+
WORKING_MS = 30 * 6e4;
|
|
24687
24688
|
ContextSchema = external_exports.object({
|
|
24688
24689
|
title: external_exports.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
|
|
24689
24690
|
description: external_exports.array(external_exports.string().min(1)).describe(
|
|
@@ -24754,7 +24755,7 @@ var init_dist = __esm({
|
|
|
24754
24755
|
points: external_exports.array(external_exports.string()).nullable(),
|
|
24755
24756
|
/** Whether the ask blocks the sender — what lets arbitration escalate it on silence. */
|
|
24756
24757
|
blocking: external_exports.boolean(),
|
|
24757
|
-
/** Reserved (
|
|
24758
|
+
/** Reserved (docs/model/model.md lists it): a response deadline. No row column yet — a later Phase 2
|
|
24758
24759
|
* slice wires it; optional so today's rows/callers project cleanly. */
|
|
24759
24760
|
deadline: external_exports.string().datetime().nullable().optional()
|
|
24760
24761
|
});
|
|
@@ -24805,7 +24806,7 @@ var init_dist = __esm({
|
|
|
24805
24806
|
* derive agent-side before sealing, so the server only ever shapes plaintext). */
|
|
24806
24807
|
// 10k, not a sentence budget. What the human hears is bounded by the BROKER — it splits
|
|
24807
24808
|
// the ask into topics and gives each one at most three sentences and one question
|
|
24808
|
-
// (broker/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
|
|
24809
|
+
// (docs/brain/broker/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
|
|
24809
24810
|
// Owner, 2026-07-28: "our actual limitation on how long something is to the user should
|
|
24810
24811
|
// come from the broker splitting and summarizing." The cap that remains is a size guard.
|
|
24811
24812
|
ask: external_exports.string().min(1).max(1e4).optional().describe(
|
|
@@ -24882,7 +24883,7 @@ var init_dist = __esm({
|
|
|
24882
24883
|
external_exports.object({ kind: external_exports.literal("clarify"), chunks: external_exports.array(external_exports.string()).min(1) }),
|
|
24883
24884
|
external_exports.object({ kind: external_exports.literal("confirm"), approved: external_exports.boolean() }),
|
|
24884
24885
|
external_exports.object({ kind: external_exports.literal("turns"), turns: external_exports.array(TurnSchema).min(1) }),
|
|
24885
|
-
/** An auto-answer derived from the user's PAST decisions (broker/precedent-design.md §2):
|
|
24886
|
+
/** An auto-answer derived from the user's PAST decisions (docs/brain/broker/precedent-design.md §2):
|
|
24886
24887
|
* delivered through the same settle/await path as a human answer, carrying the judge's
|
|
24887
24888
|
* derivation and the precedent ids it grew from. Always paired with a visible trail
|
|
24888
24889
|
* card the user can reply to — the broker never overrides the user. */
|
|
@@ -24931,7 +24932,7 @@ var init_dist = __esm({
|
|
|
24931
24932
|
* and now knows exactly which call to make. Absent when either half is missing —
|
|
24932
24933
|
* a sentence with a hole in it is worse than no sentence. */
|
|
24933
24934
|
note: external_exports.string().optional(),
|
|
24934
|
-
/** The call record rendered for THIS agent (`voice/record-design.md`): the words the
|
|
24935
|
+
/** The call record rendered for THIS agent (`docs/brain/voice/record-design.md`): the words the
|
|
24935
24936
|
* shaped answer was mapped from, filtered to its own claims. There is no second list
|
|
24936
24937
|
* of labels beside it — the acts went 2026-09-04 and `intents` went with them (owner,
|
|
24937
24938
|
* 2026-09-04): the agent reads the sentence and decides. */
|
|
@@ -25027,10 +25028,11 @@ var init_dist = __esm({
|
|
|
25027
25028
|
agentId: external_exports.string().optional(),
|
|
25028
25029
|
select: SelectShapeSchema.optional(),
|
|
25029
25030
|
options: external_exports.array(OptionSchema.omit({ id: true })).optional(),
|
|
25030
|
-
|
|
25031
|
-
|
|
25032
|
-
|
|
25033
|
-
|
|
25031
|
+
/* `pace` STOOD HERE (#826). A turn could carry seconds and the model chose them. The walk
|
|
25032
|
+
paces itself now — a short beat between the sentences of a turn, the longer one at its end
|
|
25033
|
+
(owner, 2026-09-30: "remove the bot deciding pace") — and it does that where the words are
|
|
25034
|
+
spoken, not where the plan is written, so nothing between the brain and the walk decides
|
|
25035
|
+
anything. A caller's own `beat_s` tuning is what it used to override. */
|
|
25034
25036
|
/** Whether the walk WAITS for an answer before moving on. Absent = derived as today
|
|
25035
25037
|
* (a question blocks, context flows). blocking:false on a question = ask and move
|
|
25036
25038
|
* on, the claim stays pending; blocking:true on context = hold for a reply. */
|
|
@@ -25065,7 +25067,7 @@ var init_dist = __esm({
|
|
|
25065
25067
|
* instant the agent picks it up (#997). Absent = pre-trigger row; fall back to
|
|
25066
25068
|
* `createdAt`. */
|
|
25067
25069
|
agentStateAt: external_exports.string().datetime().optional(),
|
|
25068
|
-
/** THE QUESTIONS A CALL CARRIES — the call screen's agenda spine (walk/design.md §11, owner
|
|
25070
|
+
/** THE QUESTIONS A CALL CARRIES — the call screen's agenda spine (docs/clients/app/walk/design.md §11, owner
|
|
25069
25071
|
* 2026-09-22). One per DecisionNeed on the Call, in the Call's order, answered or open (a
|
|
25070
25072
|
* superseded or cancelled need is no longer a question anyone is asked). Present only on a
|
|
25071
25073
|
* Call's cards, and every card of that Call carries the same list: the call screen reads it
|
|
@@ -25126,7 +25128,7 @@ var init_dist = __esm({
|
|
|
25126
25128
|
* off the same open list the card came from, so it clears when the Call does. A card is the
|
|
25127
25129
|
* backup for a call not taken; while the call has it, the call is where it is answered. */
|
|
25128
25130
|
onCall: external_exports.literal(true).optional(),
|
|
25129
|
-
/** THE RING, ON THE ITEM (walk/design.md §12 §17, #2251): the last ring on this card was
|
|
25131
|
+
/** THE RING, ON THE ITEM (docs/clients/app/walk/design.md §12 §17, #2251): the last ring on this card was
|
|
25130
25132
|
* declined, and what the ladder will do next — read off the cron's own row, never computed
|
|
25131
25133
|
* on the phone. Present only while a `declined` receipt stands on the card's last Call.
|
|
25132
25134
|
* The ladder is ACCOUNT-WIDE (#2259): `anchorAt` and `step` are the account's position;
|
|
@@ -25157,7 +25159,7 @@ var init_dist = __esm({
|
|
|
25157
25159
|
"Labels for a select:'confirm' paige \u2014 'yesno' (Yes/No) or 'approve' (Approve/Deny). Ignored unless select is 'confirm'."
|
|
25158
25160
|
),
|
|
25159
25161
|
/** Real downstream work is stuck behind this one — set by the agent, independent of
|
|
25160
|
-
* urgency (see the main README's "premier use case" + notify/states.md). Drives the
|
|
25162
|
+
* urgency (see the main README's "premier use case" + docs/delivery/notify/states.md). Drives the
|
|
25161
25163
|
* inbox's blocking badge and the extra confirm step before dismissing it. */
|
|
25162
25164
|
blocking: external_exports.boolean().default(false),
|
|
25163
25165
|
/** The user's locked-in answer; present only for replied items (GET /api/replied/:id). */
|
|
@@ -25231,9 +25233,16 @@ var init_dist = __esm({
|
|
|
25231
25233
|
banner: external_exports.boolean(),
|
|
25232
25234
|
push: external_exports.boolean()
|
|
25233
25235
|
}),
|
|
25236
|
+
/** LockedIn / Default / DateNight on screen; the stored words are unchanged on purpose —
|
|
25237
|
+
* they are an enum on a live column across every account, and the rename is a rename of
|
|
25238
|
+
* what people read (owner, 2026-09-30). */
|
|
25234
25239
|
sessionMode: external_exports.enum(["default", "all_calls", "silent"]),
|
|
25235
|
-
|
|
25236
|
-
|
|
25240
|
+
/** DEAD, AND ACCEPTED ANYWAY (#2813). DateNight is inbox-only with no way back, so nothing
|
|
25241
|
+
* reads this. It stays OPTIONAL rather than deleted because a phone on the old bundle
|
|
25242
|
+
* PATCHes the whole settings object and would be refused for sending a key we stopped
|
|
25243
|
+
* wanting — the same trap `voiceMode` below already documents. #2813 drops the field and
|
|
25244
|
+
* its column once no installed build still sends it. */
|
|
25245
|
+
silentPush: external_exports.boolean().optional(),
|
|
25237
25246
|
/** Opt-in (default false) to using your content to improve Paigy and train models. */
|
|
25238
25247
|
improveConsent: external_exports.boolean(),
|
|
25239
25248
|
missedCall: MissedCallSchema.default("backoff_standard"),
|
|
@@ -25244,12 +25253,16 @@ var init_dist = __esm({
|
|
|
25244
25253
|
* must not silently reset this privacy choice. Absent = leave unchanged on
|
|
25245
25254
|
* write, 'hosted' on read (see store.ts). */
|
|
25246
25255
|
voiceMode: external_exports.enum(["hosted", "on_device"]).optional(),
|
|
25247
|
-
/** Talk — after you answer, the next step is read aloud (walk/design.md §6). ALWAYS ON until
|
|
25256
|
+
/** Talk — after you answer, the next step is read aloud (docs/clients/app/walk/design.md §6). ALWAYS ON until
|
|
25248
25257
|
* turned off (owner, 2026-09-18, #2249): a setting, not a per-walk toggle. Optional, NOT
|
|
25249
25258
|
* defaulted, for the same reason `voiceMode` is: a stale client PATCHing the full settings
|
|
25250
25259
|
* object must not silently turn it back on. Absent = leave unchanged on write, true on
|
|
25251
25260
|
* read (see store.ts). */
|
|
25252
25261
|
talk: external_exports.boolean().optional(),
|
|
25262
|
+
/** CALL DIAGNOSTICS (owner, 2026-10-01): the call report carries each listen and the bot's own
|
|
25263
|
+
* load timings. SERVER-SET, no UI — on for every account that existed on 2026-10-01, off for
|
|
25264
|
+
* newer ones (migration 20261001132859). Read-only here: the settings PATCH never writes it. */
|
|
25265
|
+
callDiagnostics: external_exports.boolean().optional(),
|
|
25253
25266
|
/** Per-user ring budget (#603): calls per rolling day before further calls
|
|
25254
25267
|
* degrade to banner. Absent = the global default (25). A number, never a
|
|
25255
25268
|
* bypass — every account keeps a ceiling. No UI; set per user for testing. */
|
|
@@ -25258,9 +25271,6 @@ var init_dist = __esm({
|
|
|
25258
25271
|
* slower speaker). No API-side semantics; the bot resolves each key with its
|
|
25259
25272
|
* own defaults. Set per user (no UI yet); absent = bot defaults. */
|
|
25260
25273
|
voiceTuning: external_exports.record(external_exports.string(), external_exports.union([external_exports.number(), external_exports.string()])).optional(),
|
|
25261
|
-
/** Opt-in to real-phone (PSTN) calls when the app can't ring. Optional, not
|
|
25262
|
-
* defaulted — an older client PATCHing the full object must not clobber it. */
|
|
25263
|
-
pstnCalls: external_exports.boolean().optional(),
|
|
25264
25274
|
/** The user's IANA timezone (e.g. "America/Bogota"), recorded by the app — it is the
|
|
25265
25275
|
* only party that knows it. REMINDERS are why it exists: "remind me at ten" becomes
|
|
25266
25276
|
* an absolute `due_at` only if we know whose ten. Optional and never defaulted, for
|
|
@@ -25304,7 +25314,7 @@ var init_dist = __esm({
|
|
|
25304
25314
|
/** The credential kind: "device" = a paired machine (mint-only — it hosts and mints, it
|
|
25305
25315
|
* never talks); "agent" = an identity that sends. The roster and devices surfaces split
|
|
25306
25316
|
* on this. Optional/absent reads as "agent" (a row predating the kind column). See
|
|
25307
|
-
*
|
|
25317
|
+
* docs/server/tokens/devices-vs-agents-design.md. */
|
|
25308
25318
|
kind: external_exports.enum(["device", "agent"]).optional(),
|
|
25309
25319
|
/** For an agent, the token id of the DEVICE that minted it — so agents group under their
|
|
25310
25320
|
* machine, and revoking a device cascades to them. Null on devices, and on unlinked
|
|
@@ -25322,7 +25332,7 @@ var init_dist = __esm({
|
|
|
25322
25332
|
* user on the agent's own page. null = no ceiling (today's behaviour for every
|
|
25323
25333
|
* connection). Android binds importance to a relationship rather than to each message,
|
|
25324
25334
|
* and that is the thing our roster could not say: "Marlow may always call me; Otto
|
|
25325
|
-
* never may" (navigation-design.md, gap 2). Clamped in `arbitrateLevel`, so it binds
|
|
25335
|
+
* never may" (docs/clients/app/party/navigation-design.md, gap 2). Clamped in `arbitrateLevel`, so it binds
|
|
25326
25336
|
* every surface at once and outranks even `sessionMode: all_calls` — a mode the user
|
|
25327
25337
|
* set once must not overrule a rule they set about one agent. */
|
|
25328
25338
|
reach: NotifyLevelSchema.nullable().optional(),
|
|
@@ -25333,7 +25343,14 @@ var init_dist = __esm({
|
|
|
25333
25343
|
/** Last presence heartbeat from a running agent process (POST /api/presence) — the
|
|
25334
25344
|
* desktop app while open. Null = never seen; stale = offline. */
|
|
25335
25345
|
lastSeenAt: external_exports.string().datetime().nullable().optional(),
|
|
25336
|
-
/**
|
|
25346
|
+
/** WORKING, NOT JUST CONNECTED (owner, 2026-09-30): the last time the agent itself acted on one of
|
|
25347
|
+
* its Goals — took its lease or recorded an operation (`tokens.last_worked_at`). Within
|
|
25348
|
+
* `WORKING_MS` it is working; otherwise it is connected but idle. Null = not seen working yet. */
|
|
25349
|
+
lastWorkedAt: external_exports.string().datetime().nullable().optional(),
|
|
25350
|
+
/** The oldest of its Goals that is `ready` for it — work handed to it that nobody has started.
|
|
25351
|
+
* With no work of its own for `WORKING_MS`, an agent sitting on this is not taking its work. */
|
|
25352
|
+
oldestReadyAt: external_exports.string().datetime().nullable().optional(),
|
|
25353
|
+
/** What a live desktop can run (docs/clients/desktop/companion.md §2.2), advertised on its heartbeat:
|
|
25337
25354
|
* harness availabilities + granted workspaces — the option set the phone's
|
|
25338
25355
|
* "new session" sheet offers. Absent for ordinary MCP agents. */
|
|
25339
25356
|
runtime: external_exports.object({
|
|
@@ -25341,7 +25358,12 @@ var init_dist = __esm({
|
|
|
25341
25358
|
* shows its age here (`apps/desktop/src/update.ts`). */
|
|
25342
25359
|
version: external_exports.string().optional(),
|
|
25343
25360
|
harnesses: external_exports.array(external_exports.object({ name: external_exports.string(), label: external_exports.string(), status: external_exports.string() })).optional(),
|
|
25344
|
-
workspaces: external_exports.array(external_exports.string()).optional()
|
|
25361
|
+
workspaces: external_exports.array(external_exports.string()).optional(),
|
|
25362
|
+
/** THE GIT REPOS IN THOSE FOLDERS (2026-10-01, Goal 26982211): each granted folder that is a
|
|
25363
|
+
* repo, and each repo directly inside one, with its `origin` remote. A session started for
|
|
25364
|
+
* work on `mauurda/paigy` opens in that repo rather than the folder above it, where the repo's
|
|
25365
|
+
* own AGENTS.md is never read (`workspaceForRepo`). Absent on hosts that predate it. */
|
|
25366
|
+
repos: external_exports.array(external_exports.object({ path: external_exports.string(), remote: external_exports.string() })).optional()
|
|
25345
25367
|
}).optional(),
|
|
25346
25368
|
/** The tail of this agent's working log, when a harness is driving it — the agent page's
|
|
25347
25369
|
* live strip. Absent for anything the desktop harness isn't running (a hatched identity
|
|
@@ -25424,7 +25446,7 @@ var init_dist = __esm({
|
|
|
25424
25446
|
* for a settled question whose reply carried nothing readable. */
|
|
25425
25447
|
answer: external_exports.string().nullable().default(null),
|
|
25426
25448
|
/** The Goal this question belongs to — a step knows its Goal on its own, not only through
|
|
25427
|
-
* an `InboxItem`'s `communication.goalIds[0]` (walk/design.md §12 item 3).
|
|
25449
|
+
* an `InboxItem`'s `communication.goalIds[0]` (docs/clients/app/walk/design.md §12 item 3).
|
|
25428
25450
|
* READ BY `apps/client/src/walk/order.ts`, which stamps it onto every `WalkStep`: the walk's
|
|
25429
25451
|
* order, its route, home's trees and the list of steps all take a step's Goal from here, so
|
|
25430
25452
|
* this is the field they agree through rather than each re-deriving it from the row it
|
|
@@ -25516,7 +25538,19 @@ var init_dist = __esm({
|
|
|
25516
25538
|
said: external_exports.string(),
|
|
25517
25539
|
at: external_exports.string(),
|
|
25518
25540
|
entryId: external_exports.string()
|
|
25519
|
-
}).nullable().optional()
|
|
25541
|
+
}).nullable().optional(),
|
|
25542
|
+
/** WHEN THIS PERSON LAST PUT A HAND ON IT THEMSELVES (owner, Paigy Goal 16d18f51, 2026-09-30):
|
|
25543
|
+
* the newest Entry on the Goal they wrote, of any kind — a line they added, a reply to a note, an
|
|
25544
|
+
* answer to a question, a voice note filed as work. Null when the only hands on it have been its
|
|
25545
|
+
* agent's; optional, so a hand-built queue (fixtures, the demo) and a door older than
|
|
25546
|
+
* 20260930222356 need not spell it — `work/list.ts`'s `yoursAt` keeps its other sources, so the
|
|
25547
|
+
* Work tab orders as it did before the migration rather than throwing on the missing key.
|
|
25548
|
+
*
|
|
25549
|
+
* It is a FACT, not a reconstruction: `latest` holds one Entry, so an agent's progress note a
|
|
25550
|
+
* minute after the person speaks erases their instant from it, and the durable traces the client
|
|
25551
|
+
* can see (`replies`, `questions[].answeredAt`) miss a spontaneous note entirely — a `request`
|
|
25552
|
+
* Entry with no `about_id` is in neither. */
|
|
25553
|
+
lastPersonAt: external_exports.string().nullable().optional()
|
|
25520
25554
|
});
|
|
25521
25555
|
COLD_AFTER_MS = 3 * 24 * 60 * 60 * 1e3;
|
|
25522
25556
|
NoteSourceSchema = external_exports.enum(["app", "call"]);
|
|
@@ -25546,7 +25580,7 @@ var init_dist = __esm({
|
|
|
25546
25580
|
assignee: external_exports.string().nullable(),
|
|
25547
25581
|
/** The request thread minted at assignment; null until assigned. */
|
|
25548
25582
|
parentId: external_exports.string().nullable(),
|
|
25549
|
-
/** REMINDERS (reminders-design.md): the NOT-BEFORE this becomes eligible to ride a
|
|
25583
|
+
/** REMINDERS (docs/model/notes/reminders-design.md): the NOT-BEFORE this becomes eligible to ride a
|
|
25550
25584
|
* call — never a deadline. It only ever comes from the user's own words, so when it
|
|
25551
25585
|
* passes Paigy rings ONCE (#1293, owner 2026-08-26: a time said out loud is consent to
|
|
25552
25586
|
* a ring at that time); after that it rides like any other. Null = "the very next
|
|
@@ -25808,6 +25842,29 @@ var init_dist = __esm({
|
|
|
25808
25842
|
computers: external_exports.array(ComputerRowSchema).nullable()
|
|
25809
25843
|
}).nullable()
|
|
25810
25844
|
});
|
|
25845
|
+
CallRecapSchema = external_exports.object({
|
|
25846
|
+
call: external_exports.object({
|
|
25847
|
+
status: external_exports.string(),
|
|
25848
|
+
startedAt: external_exports.string(),
|
|
25849
|
+
durationMs: external_exports.number().nullable(),
|
|
25850
|
+
agents: external_exports.array(external_exports.object({ id: external_exports.string(), name: external_exports.string().nullable() }))
|
|
25851
|
+
}),
|
|
25852
|
+
topics: external_exports.array(external_exports.object({
|
|
25853
|
+
goalId: external_exports.string().uuid(),
|
|
25854
|
+
title: external_exports.string(),
|
|
25855
|
+
owner: external_exports.string(),
|
|
25856
|
+
state: external_exports.string(),
|
|
25857
|
+
questions: external_exports.array(external_exports.object({ id: external_exports.string().uuid(), state: external_exports.string(), title: external_exports.string() })),
|
|
25858
|
+
/** `words` is always what they SAID, verbatim — the record, never replaced. `headline` is
|
|
25859
|
+
* their answer on one line when the call's read wrote one (owner, 2026-10-01: "render them
|
|
25860
|
+
* summarized like a pre-made option is"), so the row scans like a chosen option and their
|
|
25861
|
+
* own words stay under it. Absent on every line stored before the read wrote them, and on
|
|
25862
|
+
* anything that is not an answer. */
|
|
25863
|
+
lines: external_exports.array(external_exports.object({ entryId: external_exports.string().uuid(), words: external_exports.string(), headline: external_exports.string().optional() }))
|
|
25864
|
+
})),
|
|
25865
|
+
unfiled: external_exports.array(external_exports.object({ lineId: external_exports.string().uuid(), words: external_exports.string(), atMs: external_exports.number() })),
|
|
25866
|
+
more: external_exports.object({ lines: external_exports.number(), entries: external_exports.number(), topics: external_exports.number() })
|
|
25867
|
+
});
|
|
25811
25868
|
TOKEN_PATH = join22(homedir22(), ".paigy", "token.json");
|
|
25812
25869
|
KEY_PATH = join22(homedir22(), ".paigy", "key.json");
|
|
25813
25870
|
sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
@@ -32989,7 +33046,7 @@ var GetGoalSchema2 = external_exports.object({
|
|
|
32989
33046
|
history: external_exports.boolean().optional(),
|
|
32990
33047
|
/** WHEN A READ HAS CONFUSED YOU. Adds `diagnosis`: every reader that already answers a question
|
|
32991
33048
|
* about this work, each answer attributed to the reader that gave it, and every disagreement
|
|
32992
|
-
* between two of them named. Off by default; `
|
|
33049
|
+
* between two of them named. Off by default; `docs/model/goal/diagnose-design.md`. */
|
|
32993
33050
|
diagnose: external_exports.boolean().optional()
|
|
32994
33051
|
}).strict();
|
|
32995
33052
|
var GET_GOAL_DESCRIPTION2 = "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.";
|
|
@@ -33022,6 +33079,7 @@ function entryWords(entry) {
|
|
|
33022
33079
|
return entry.sources.map((source) => source.text).join("\n");
|
|
33023
33080
|
}
|
|
33024
33081
|
var LIVE_MS2 = 3 * 6e4;
|
|
33082
|
+
var WORKING_MS2 = 30 * 6e4;
|
|
33025
33083
|
var ContextSchema2 = external_exports.object({
|
|
33026
33084
|
title: external_exports.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
|
|
33027
33085
|
description: external_exports.array(external_exports.string().min(1)).describe(
|
|
@@ -33092,7 +33150,7 @@ var AttentionSchema2 = external_exports.object({
|
|
|
33092
33150
|
points: external_exports.array(external_exports.string()).nullable(),
|
|
33093
33151
|
/** Whether the ask blocks the sender — what lets arbitration escalate it on silence. */
|
|
33094
33152
|
blocking: external_exports.boolean(),
|
|
33095
|
-
/** Reserved (
|
|
33153
|
+
/** Reserved (docs/model/model.md lists it): a response deadline. No row column yet — a later Phase 2
|
|
33096
33154
|
* slice wires it; optional so today's rows/callers project cleanly. */
|
|
33097
33155
|
deadline: external_exports.string().datetime().nullable().optional()
|
|
33098
33156
|
});
|
|
@@ -33143,7 +33201,7 @@ var NotifyRequestFields2 = external_exports.object({
|
|
|
33143
33201
|
* derive agent-side before sealing, so the server only ever shapes plaintext). */
|
|
33144
33202
|
// 10k, not a sentence budget. What the human hears is bounded by the BROKER — it splits
|
|
33145
33203
|
// the ask into topics and gives each one at most three sentences and one question
|
|
33146
|
-
// (broker/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
|
|
33204
|
+
// (docs/brain/broker/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
|
|
33147
33205
|
// Owner, 2026-07-28: "our actual limitation on how long something is to the user should
|
|
33148
33206
|
// come from the broker splitting and summarizing." The cap that remains is a size guard.
|
|
33149
33207
|
ask: external_exports.string().min(1).max(1e4).optional().describe(
|
|
@@ -33220,7 +33278,7 @@ var UserAnswerSchema2 = external_exports.discriminatedUnion("kind", [
|
|
|
33220
33278
|
external_exports.object({ kind: external_exports.literal("clarify"), chunks: external_exports.array(external_exports.string()).min(1) }),
|
|
33221
33279
|
external_exports.object({ kind: external_exports.literal("confirm"), approved: external_exports.boolean() }),
|
|
33222
33280
|
external_exports.object({ kind: external_exports.literal("turns"), turns: external_exports.array(TurnSchema2).min(1) }),
|
|
33223
|
-
/** An auto-answer derived from the user's PAST decisions (broker/precedent-design.md §2):
|
|
33281
|
+
/** An auto-answer derived from the user's PAST decisions (docs/brain/broker/precedent-design.md §2):
|
|
33224
33282
|
* delivered through the same settle/await path as a human answer, carrying the judge's
|
|
33225
33283
|
* derivation and the precedent ids it grew from. Always paired with a visible trail
|
|
33226
33284
|
* card the user can reply to — the broker never overrides the user. */
|
|
@@ -33269,7 +33327,7 @@ var AwaitItemSchema2 = external_exports.discriminatedUnion("type", [
|
|
|
33269
33327
|
* and now knows exactly which call to make. Absent when either half is missing —
|
|
33270
33328
|
* a sentence with a hole in it is worse than no sentence. */
|
|
33271
33329
|
note: external_exports.string().optional(),
|
|
33272
|
-
/** The call record rendered for THIS agent (`voice/record-design.md`): the words the
|
|
33330
|
+
/** The call record rendered for THIS agent (`docs/brain/voice/record-design.md`): the words the
|
|
33273
33331
|
* shaped answer was mapped from, filtered to its own claims. There is no second list
|
|
33274
33332
|
* of labels beside it — the acts went 2026-09-04 and `intents` went with them (owner,
|
|
33275
33333
|
* 2026-09-04): the agent reads the sentence and decides. */
|
|
@@ -33365,10 +33423,11 @@ var AgendaTurnSchema2 = external_exports.object({
|
|
|
33365
33423
|
agentId: external_exports.string().optional(),
|
|
33366
33424
|
select: SelectShapeSchema2.optional(),
|
|
33367
33425
|
options: external_exports.array(OptionSchema2.omit({ id: true })).optional(),
|
|
33368
|
-
|
|
33369
|
-
|
|
33370
|
-
|
|
33371
|
-
|
|
33426
|
+
/* `pace` STOOD HERE (#826). A turn could carry seconds and the model chose them. The walk
|
|
33427
|
+
paces itself now — a short beat between the sentences of a turn, the longer one at its end
|
|
33428
|
+
(owner, 2026-09-30: "remove the bot deciding pace") — and it does that where the words are
|
|
33429
|
+
spoken, not where the plan is written, so nothing between the brain and the walk decides
|
|
33430
|
+
anything. A caller's own `beat_s` tuning is what it used to override. */
|
|
33372
33431
|
/** Whether the walk WAITS for an answer before moving on. Absent = derived as today
|
|
33373
33432
|
* (a question blocks, context flows). blocking:false on a question = ask and move
|
|
33374
33433
|
* on, the claim stays pending; blocking:true on context = hold for a reply. */
|
|
@@ -33403,7 +33462,7 @@ var InboxItemSchema2 = external_exports.object({
|
|
|
33403
33462
|
* instant the agent picks it up (#997). Absent = pre-trigger row; fall back to
|
|
33404
33463
|
* `createdAt`. */
|
|
33405
33464
|
agentStateAt: external_exports.string().datetime().optional(),
|
|
33406
|
-
/** THE QUESTIONS A CALL CARRIES — the call screen's agenda spine (walk/design.md §11, owner
|
|
33465
|
+
/** THE QUESTIONS A CALL CARRIES — the call screen's agenda spine (docs/clients/app/walk/design.md §11, owner
|
|
33407
33466
|
* 2026-09-22). One per DecisionNeed on the Call, in the Call's order, answered or open (a
|
|
33408
33467
|
* superseded or cancelled need is no longer a question anyone is asked). Present only on a
|
|
33409
33468
|
* Call's cards, and every card of that Call carries the same list: the call screen reads it
|
|
@@ -33464,7 +33523,7 @@ var InboxItemSchema2 = external_exports.object({
|
|
|
33464
33523
|
* off the same open list the card came from, so it clears when the Call does. A card is the
|
|
33465
33524
|
* backup for a call not taken; while the call has it, the call is where it is answered. */
|
|
33466
33525
|
onCall: external_exports.literal(true).optional(),
|
|
33467
|
-
/** THE RING, ON THE ITEM (walk/design.md §12 §17, #2251): the last ring on this card was
|
|
33526
|
+
/** THE RING, ON THE ITEM (docs/clients/app/walk/design.md §12 §17, #2251): the last ring on this card was
|
|
33468
33527
|
* declined, and what the ladder will do next — read off the cron's own row, never computed
|
|
33469
33528
|
* on the phone. Present only while a `declined` receipt stands on the card's last Call.
|
|
33470
33529
|
* The ladder is ACCOUNT-WIDE (#2259): `anchorAt` and `step` are the account's position;
|
|
@@ -33495,7 +33554,7 @@ var InboxItemSchema2 = external_exports.object({
|
|
|
33495
33554
|
"Labels for a select:'confirm' paige \u2014 'yesno' (Yes/No) or 'approve' (Approve/Deny). Ignored unless select is 'confirm'."
|
|
33496
33555
|
),
|
|
33497
33556
|
/** Real downstream work is stuck behind this one — set by the agent, independent of
|
|
33498
|
-
* urgency (see the main README's "premier use case" + notify/states.md). Drives the
|
|
33557
|
+
* urgency (see the main README's "premier use case" + docs/delivery/notify/states.md). Drives the
|
|
33499
33558
|
* inbox's blocking badge and the extra confirm step before dismissing it. */
|
|
33500
33559
|
blocking: external_exports.boolean().default(false),
|
|
33501
33560
|
/** The user's locked-in answer; present only for replied items (GET /api/replied/:id). */
|
|
@@ -33569,9 +33628,16 @@ var UserSettingsSchema2 = external_exports.object({
|
|
|
33569
33628
|
banner: external_exports.boolean(),
|
|
33570
33629
|
push: external_exports.boolean()
|
|
33571
33630
|
}),
|
|
33631
|
+
/** LockedIn / Default / DateNight on screen; the stored words are unchanged on purpose —
|
|
33632
|
+
* they are an enum on a live column across every account, and the rename is a rename of
|
|
33633
|
+
* what people read (owner, 2026-09-30). */
|
|
33572
33634
|
sessionMode: external_exports.enum(["default", "all_calls", "silent"]),
|
|
33573
|
-
|
|
33574
|
-
|
|
33635
|
+
/** DEAD, AND ACCEPTED ANYWAY (#2813). DateNight is inbox-only with no way back, so nothing
|
|
33636
|
+
* reads this. It stays OPTIONAL rather than deleted because a phone on the old bundle
|
|
33637
|
+
* PATCHes the whole settings object and would be refused for sending a key we stopped
|
|
33638
|
+
* wanting — the same trap `voiceMode` below already documents. #2813 drops the field and
|
|
33639
|
+
* its column once no installed build still sends it. */
|
|
33640
|
+
silentPush: external_exports.boolean().optional(),
|
|
33575
33641
|
/** Opt-in (default false) to using your content to improve Paigy and train models. */
|
|
33576
33642
|
improveConsent: external_exports.boolean(),
|
|
33577
33643
|
missedCall: MissedCallSchema2.default("backoff_standard"),
|
|
@@ -33582,12 +33648,16 @@ var UserSettingsSchema2 = external_exports.object({
|
|
|
33582
33648
|
* must not silently reset this privacy choice. Absent = leave unchanged on
|
|
33583
33649
|
* write, 'hosted' on read (see store.ts). */
|
|
33584
33650
|
voiceMode: external_exports.enum(["hosted", "on_device"]).optional(),
|
|
33585
|
-
/** Talk — after you answer, the next step is read aloud (walk/design.md §6). ALWAYS ON until
|
|
33651
|
+
/** Talk — after you answer, the next step is read aloud (docs/clients/app/walk/design.md §6). ALWAYS ON until
|
|
33586
33652
|
* turned off (owner, 2026-09-18, #2249): a setting, not a per-walk toggle. Optional, NOT
|
|
33587
33653
|
* defaulted, for the same reason `voiceMode` is: a stale client PATCHing the full settings
|
|
33588
33654
|
* object must not silently turn it back on. Absent = leave unchanged on write, true on
|
|
33589
33655
|
* read (see store.ts). */
|
|
33590
33656
|
talk: external_exports.boolean().optional(),
|
|
33657
|
+
/** CALL DIAGNOSTICS (owner, 2026-10-01): the call report carries each listen and the bot's own
|
|
33658
|
+
* load timings. SERVER-SET, no UI — on for every account that existed on 2026-10-01, off for
|
|
33659
|
+
* newer ones (migration 20261001132859). Read-only here: the settings PATCH never writes it. */
|
|
33660
|
+
callDiagnostics: external_exports.boolean().optional(),
|
|
33591
33661
|
/** Per-user ring budget (#603): calls per rolling day before further calls
|
|
33592
33662
|
* degrade to banner. Absent = the global default (25). A number, never a
|
|
33593
33663
|
* bypass — every account keeps a ceiling. No UI; set per user for testing. */
|
|
@@ -33596,9 +33666,6 @@ var UserSettingsSchema2 = external_exports.object({
|
|
|
33596
33666
|
* slower speaker). No API-side semantics; the bot resolves each key with its
|
|
33597
33667
|
* own defaults. Set per user (no UI yet); absent = bot defaults. */
|
|
33598
33668
|
voiceTuning: external_exports.record(external_exports.string(), external_exports.union([external_exports.number(), external_exports.string()])).optional(),
|
|
33599
|
-
/** Opt-in to real-phone (PSTN) calls when the app can't ring. Optional, not
|
|
33600
|
-
* defaulted — an older client PATCHing the full object must not clobber it. */
|
|
33601
|
-
pstnCalls: external_exports.boolean().optional(),
|
|
33602
33669
|
/** The user's IANA timezone (e.g. "America/Bogota"), recorded by the app — it is the
|
|
33603
33670
|
* only party that knows it. REMINDERS are why it exists: "remind me at ten" becomes
|
|
33604
33671
|
* an absolute `due_at` only if we know whose ten. Optional and never defaulted, for
|
|
@@ -33642,7 +33709,7 @@ var ConnectionSummarySchema2 = external_exports.object({
|
|
|
33642
33709
|
/** The credential kind: "device" = a paired machine (mint-only — it hosts and mints, it
|
|
33643
33710
|
* never talks); "agent" = an identity that sends. The roster and devices surfaces split
|
|
33644
33711
|
* on this. Optional/absent reads as "agent" (a row predating the kind column). See
|
|
33645
|
-
*
|
|
33712
|
+
* docs/server/tokens/devices-vs-agents-design.md. */
|
|
33646
33713
|
kind: external_exports.enum(["device", "agent"]).optional(),
|
|
33647
33714
|
/** For an agent, the token id of the DEVICE that minted it — so agents group under their
|
|
33648
33715
|
* machine, and revoking a device cascades to them. Null on devices, and on unlinked
|
|
@@ -33660,7 +33727,7 @@ var ConnectionSummarySchema2 = external_exports.object({
|
|
|
33660
33727
|
* user on the agent's own page. null = no ceiling (today's behaviour for every
|
|
33661
33728
|
* connection). Android binds importance to a relationship rather than to each message,
|
|
33662
33729
|
* and that is the thing our roster could not say: "Marlow may always call me; Otto
|
|
33663
|
-
* never may" (navigation-design.md, gap 2). Clamped in `arbitrateLevel`, so it binds
|
|
33730
|
+
* never may" (docs/clients/app/party/navigation-design.md, gap 2). Clamped in `arbitrateLevel`, so it binds
|
|
33664
33731
|
* every surface at once and outranks even `sessionMode: all_calls` — a mode the user
|
|
33665
33732
|
* set once must not overrule a rule they set about one agent. */
|
|
33666
33733
|
reach: NotifyLevelSchema2.nullable().optional(),
|
|
@@ -33671,7 +33738,14 @@ var ConnectionSummarySchema2 = external_exports.object({
|
|
|
33671
33738
|
/** Last presence heartbeat from a running agent process (POST /api/presence) — the
|
|
33672
33739
|
* desktop app while open. Null = never seen; stale = offline. */
|
|
33673
33740
|
lastSeenAt: external_exports.string().datetime().nullable().optional(),
|
|
33674
|
-
/**
|
|
33741
|
+
/** WORKING, NOT JUST CONNECTED (owner, 2026-09-30): the last time the agent itself acted on one of
|
|
33742
|
+
* its Goals — took its lease or recorded an operation (`tokens.last_worked_at`). Within
|
|
33743
|
+
* `WORKING_MS` it is working; otherwise it is connected but idle. Null = not seen working yet. */
|
|
33744
|
+
lastWorkedAt: external_exports.string().datetime().nullable().optional(),
|
|
33745
|
+
/** The oldest of its Goals that is `ready` for it — work handed to it that nobody has started.
|
|
33746
|
+
* With no work of its own for `WORKING_MS`, an agent sitting on this is not taking its work. */
|
|
33747
|
+
oldestReadyAt: external_exports.string().datetime().nullable().optional(),
|
|
33748
|
+
/** What a live desktop can run (docs/clients/desktop/companion.md §2.2), advertised on its heartbeat:
|
|
33675
33749
|
* harness availabilities + granted workspaces — the option set the phone's
|
|
33676
33750
|
* "new session" sheet offers. Absent for ordinary MCP agents. */
|
|
33677
33751
|
runtime: external_exports.object({
|
|
@@ -33679,7 +33753,12 @@ var ConnectionSummarySchema2 = external_exports.object({
|
|
|
33679
33753
|
* shows its age here (`apps/desktop/src/update.ts`). */
|
|
33680
33754
|
version: external_exports.string().optional(),
|
|
33681
33755
|
harnesses: external_exports.array(external_exports.object({ name: external_exports.string(), label: external_exports.string(), status: external_exports.string() })).optional(),
|
|
33682
|
-
workspaces: external_exports.array(external_exports.string()).optional()
|
|
33756
|
+
workspaces: external_exports.array(external_exports.string()).optional(),
|
|
33757
|
+
/** THE GIT REPOS IN THOSE FOLDERS (2026-10-01, Goal 26982211): each granted folder that is a
|
|
33758
|
+
* repo, and each repo directly inside one, with its `origin` remote. A session started for
|
|
33759
|
+
* work on `mauurda/paigy` opens in that repo rather than the folder above it, where the repo's
|
|
33760
|
+
* own AGENTS.md is never read (`workspaceForRepo`). Absent on hosts that predate it. */
|
|
33761
|
+
repos: external_exports.array(external_exports.object({ path: external_exports.string(), remote: external_exports.string() })).optional()
|
|
33683
33762
|
}).optional(),
|
|
33684
33763
|
/** The tail of this agent's working log, when a harness is driving it — the agent page's
|
|
33685
33764
|
* live strip. Absent for anything the desktop harness isn't running (a hatched identity
|
|
@@ -33762,7 +33841,7 @@ var QueueQuestionSchema2 = external_exports.object({
|
|
|
33762
33841
|
* for a settled question whose reply carried nothing readable. */
|
|
33763
33842
|
answer: external_exports.string().nullable().default(null),
|
|
33764
33843
|
/** The Goal this question belongs to — a step knows its Goal on its own, not only through
|
|
33765
|
-
* an `InboxItem`'s `communication.goalIds[0]` (walk/design.md §12 item 3).
|
|
33844
|
+
* an `InboxItem`'s `communication.goalIds[0]` (docs/clients/app/walk/design.md §12 item 3).
|
|
33766
33845
|
* READ BY `apps/client/src/walk/order.ts`, which stamps it onto every `WalkStep`: the walk's
|
|
33767
33846
|
* order, its route, home's trees and the list of steps all take a step's Goal from here, so
|
|
33768
33847
|
* this is the field they agree through rather than each re-deriving it from the row it
|
|
@@ -33854,7 +33933,19 @@ var QueueItemSchema2 = external_exports.object({
|
|
|
33854
33933
|
said: external_exports.string(),
|
|
33855
33934
|
at: external_exports.string(),
|
|
33856
33935
|
entryId: external_exports.string()
|
|
33857
|
-
}).nullable().optional()
|
|
33936
|
+
}).nullable().optional(),
|
|
33937
|
+
/** WHEN THIS PERSON LAST PUT A HAND ON IT THEMSELVES (owner, Paigy Goal 16d18f51, 2026-09-30):
|
|
33938
|
+
* the newest Entry on the Goal they wrote, of any kind — a line they added, a reply to a note, an
|
|
33939
|
+
* answer to a question, a voice note filed as work. Null when the only hands on it have been its
|
|
33940
|
+
* agent's; optional, so a hand-built queue (fixtures, the demo) and a door older than
|
|
33941
|
+
* 20260930222356 need not spell it — `work/list.ts`'s `yoursAt` keeps its other sources, so the
|
|
33942
|
+
* Work tab orders as it did before the migration rather than throwing on the missing key.
|
|
33943
|
+
*
|
|
33944
|
+
* It is a FACT, not a reconstruction: `latest` holds one Entry, so an agent's progress note a
|
|
33945
|
+
* minute after the person speaks erases their instant from it, and the durable traces the client
|
|
33946
|
+
* can see (`replies`, `questions[].answeredAt`) miss a spontaneous note entirely — a `request`
|
|
33947
|
+
* Entry with no `about_id` is in neither. */
|
|
33948
|
+
lastPersonAt: external_exports.string().nullable().optional()
|
|
33858
33949
|
});
|
|
33859
33950
|
var COLD_AFTER_MS2 = 3 * 24 * 60 * 60 * 1e3;
|
|
33860
33951
|
var NoteSourceSchema2 = external_exports.enum(["app", "call"]);
|
|
@@ -33884,7 +33975,7 @@ var NoteSchema2 = external_exports.object({
|
|
|
33884
33975
|
assignee: external_exports.string().nullable(),
|
|
33885
33976
|
/** The request thread minted at assignment; null until assigned. */
|
|
33886
33977
|
parentId: external_exports.string().nullable(),
|
|
33887
|
-
/** REMINDERS (reminders-design.md): the NOT-BEFORE this becomes eligible to ride a
|
|
33978
|
+
/** REMINDERS (docs/model/notes/reminders-design.md): the NOT-BEFORE this becomes eligible to ride a
|
|
33888
33979
|
* call — never a deadline. It only ever comes from the user's own words, so when it
|
|
33889
33980
|
* passes Paigy rings ONCE (#1293, owner 2026-08-26: a time said out loud is consent to
|
|
33890
33981
|
* a ring at that time); after that it rides like any other. Null = "the very next
|
|
@@ -34144,6 +34235,29 @@ var SnapshotSchema2 = external_exports.object({
|
|
|
34144
34235
|
computers: external_exports.array(ComputerRowSchema2).nullable()
|
|
34145
34236
|
}).nullable()
|
|
34146
34237
|
});
|
|
34238
|
+
var CallRecapSchema2 = external_exports.object({
|
|
34239
|
+
call: external_exports.object({
|
|
34240
|
+
status: external_exports.string(),
|
|
34241
|
+
startedAt: external_exports.string(),
|
|
34242
|
+
durationMs: external_exports.number().nullable(),
|
|
34243
|
+
agents: external_exports.array(external_exports.object({ id: external_exports.string(), name: external_exports.string().nullable() }))
|
|
34244
|
+
}),
|
|
34245
|
+
topics: external_exports.array(external_exports.object({
|
|
34246
|
+
goalId: external_exports.string().uuid(),
|
|
34247
|
+
title: external_exports.string(),
|
|
34248
|
+
owner: external_exports.string(),
|
|
34249
|
+
state: external_exports.string(),
|
|
34250
|
+
questions: external_exports.array(external_exports.object({ id: external_exports.string().uuid(), state: external_exports.string(), title: external_exports.string() })),
|
|
34251
|
+
/** `words` is always what they SAID, verbatim — the record, never replaced. `headline` is
|
|
34252
|
+
* their answer on one line when the call's read wrote one (owner, 2026-10-01: "render them
|
|
34253
|
+
* summarized like a pre-made option is"), so the row scans like a chosen option and their
|
|
34254
|
+
* own words stay under it. Absent on every line stored before the read wrote them, and on
|
|
34255
|
+
* anything that is not an answer. */
|
|
34256
|
+
lines: external_exports.array(external_exports.object({ entryId: external_exports.string().uuid(), words: external_exports.string(), headline: external_exports.string().optional() }))
|
|
34257
|
+
})),
|
|
34258
|
+
unfiled: external_exports.array(external_exports.object({ lineId: external_exports.string().uuid(), words: external_exports.string(), atMs: external_exports.number() })),
|
|
34259
|
+
more: external_exports.object({ lines: external_exports.number(), entries: external_exports.number(), topics: external_exports.number() })
|
|
34260
|
+
});
|
|
34147
34261
|
|
|
34148
34262
|
// src/paigy/activity.ts
|
|
34149
34263
|
function shortenPaths(s) {
|
|
@@ -34878,7 +34992,7 @@ function ago(iso, now) {
|
|
|
34878
34992
|
init_catalog();
|
|
34879
34993
|
|
|
34880
34994
|
// src/workspaces.ts
|
|
34881
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
34995
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync as statSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
34882
34996
|
import { dirname as dirname2, join as join5, resolve as resolve2 } from "path";
|
|
34883
34997
|
import { homedir as homedir6 } from "os";
|
|
34884
34998
|
function workspacesFile() {
|
|
@@ -34913,11 +35027,42 @@ function resolveWakeDir(pinned, deps) {
|
|
|
34913
35027
|
}
|
|
34914
35028
|
return listWorkspaces(deps)[0];
|
|
34915
35029
|
}
|
|
35030
|
+
function originOf(dir) {
|
|
35031
|
+
try {
|
|
35032
|
+
if (!statSync3(join5(dir, ".git")).isDirectory()) return null;
|
|
35033
|
+
const config = readFileSync3(join5(dir, ".git", "config"), "utf8");
|
|
35034
|
+
const section = config.split(/^\[/m).find((s) => /^remote\s+"origin"\]/.test(s));
|
|
35035
|
+
return section?.match(/^\s*url\s*=\s*(.+)$/m)?.[1]?.trim() ?? null;
|
|
35036
|
+
} catch {
|
|
35037
|
+
return null;
|
|
35038
|
+
}
|
|
35039
|
+
}
|
|
35040
|
+
var MAX_CHILDREN = 300;
|
|
35041
|
+
var MAX_REPOS = 100;
|
|
35042
|
+
function listRepos(deps) {
|
|
35043
|
+
const repos = [];
|
|
35044
|
+
for (const root of listWorkspaces(deps)) {
|
|
35045
|
+
const own = originOf(root);
|
|
35046
|
+
if (own) repos.push({ path: root, remote: own });
|
|
35047
|
+
let children = [];
|
|
35048
|
+
try {
|
|
35049
|
+
children = readdirSync2(root, { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).map((d) => d.name).sort().slice(0, MAX_CHILDREN);
|
|
35050
|
+
} catch {
|
|
35051
|
+
}
|
|
35052
|
+
for (const name of children) {
|
|
35053
|
+
if (repos.length >= MAX_REPOS) return repos;
|
|
35054
|
+
const path = join5(root, name);
|
|
35055
|
+
const remote = originOf(path);
|
|
35056
|
+
if (remote) repos.push({ path, remote });
|
|
35057
|
+
}
|
|
35058
|
+
}
|
|
35059
|
+
return repos.slice(0, MAX_REPOS);
|
|
35060
|
+
}
|
|
34916
35061
|
|
|
34917
35062
|
// src/holder.ts
|
|
34918
35063
|
init_dist();
|
|
34919
35064
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
34920
|
-
import { readFileSync as readFileSync4, readdirSync as
|
|
35065
|
+
import { readFileSync as readFileSync4, readdirSync as readdirSync3 } from "fs";
|
|
34921
35066
|
import { homedir as homedir7 } from "os";
|
|
34922
35067
|
import { join as join6 } from "path";
|
|
34923
35068
|
function isAlive(pid) {
|
|
@@ -34950,7 +35095,7 @@ function holds(pid, procStart, deps) {
|
|
|
34950
35095
|
}
|
|
34951
35096
|
function localHolders(deps = {}) {
|
|
34952
35097
|
const dir = deps.dir ?? join6(process.env.CLAUDE_CONFIG_DIR?.trim() || join6(homedir7(), ".claude"), "sessions");
|
|
34953
|
-
const list = deps.list ?? ((d) =>
|
|
35098
|
+
const list = deps.list ?? ((d) => readdirSync3(d));
|
|
34954
35099
|
const read = deps.read ?? ((f) => readFileSync4(f, "utf8"));
|
|
34955
35100
|
const check = { alive: deps.alive ?? isAlive, started: deps.started ?? psStart };
|
|
34956
35101
|
const held = /* @__PURE__ */ new Map();
|
|
@@ -34978,7 +35123,7 @@ function localHolders(deps = {}) {
|
|
|
34978
35123
|
}
|
|
34979
35124
|
|
|
34980
35125
|
// src/owner.ts
|
|
34981
|
-
import { closeSync as closeSync2, openSync as openSync2, readSync, readdirSync as
|
|
35126
|
+
import { closeSync as closeSync2, openSync as openSync2, readSync, readdirSync as readdirSync4 } from "fs";
|
|
34982
35127
|
import { homedir as homedir8 } from "os";
|
|
34983
35128
|
import { join as join7 } from "path";
|
|
34984
35129
|
var HEAD_BYTES = 64e3;
|
|
@@ -34997,7 +35142,7 @@ function ownerSession(slot, deps = {}) {
|
|
|
34997
35142
|
if (!m) return null;
|
|
34998
35143
|
const prefix = m[1];
|
|
34999
35144
|
const root = deps.projectsDir ?? join7(homedir8(), ".claude", "projects");
|
|
35000
|
-
const list = deps.list ?? ((dir) =>
|
|
35145
|
+
const list = deps.list ?? ((dir) => readdirSync4(dir));
|
|
35001
35146
|
const head = deps.head ?? readHead;
|
|
35002
35147
|
let folders;
|
|
35003
35148
|
try {
|
|
@@ -35232,7 +35377,9 @@ function startHost(opts) {
|
|
|
35232
35377
|
void heartbeat({
|
|
35233
35378
|
version: VERSION,
|
|
35234
35379
|
harnesses: detectAll().map((a) => ({ name: a.name, label: a.label, status: a.status })),
|
|
35235
|
-
workspaces: listWorkspaces(opts.wsDeps)
|
|
35380
|
+
workspaces: listWorkspaces(opts.wsDeps),
|
|
35381
|
+
// The repos inside them, so a session started for work on one opens IN it (Goal 26982211).
|
|
35382
|
+
repos: listRepos(opts.wsDeps)
|
|
35236
35383
|
}, asHost).catch(() => {
|
|
35237
35384
|
});
|
|
35238
35385
|
void listenSlots().then(sweepSlots).catch(() => {
|