@paigy/harness 0.3.42 → 0.3.45

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.
Files changed (3) hide show
  1. package/dist/cli.js +109 -102
  2. package/dist/main.js +109 -102
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -23446,8 +23446,8 @@ var ZodIssueCode = util.arrayToEnum([
23446
23446
  "not_finite"
23447
23447
  ]);
23448
23448
  var quotelessJson = (obj) => {
23449
- const json3 = JSON.stringify(obj, null, 2);
23450
- return json3.replace(/"([^"]+)":/g, "$1:");
23449
+ const json = JSON.stringify(obj, null, 2);
23450
+ return json.replace(/"([^"]+)":/g, "$1:");
23451
23451
  };
23452
23452
  var ZodError = class _ZodError extends Error {
23453
23453
  get errors() {
@@ -27373,6 +27373,24 @@ function parentOf(pid) {
27373
27373
  return void 0;
27374
27374
  }
27375
27375
  }
27376
+ var CODEX_PARENT = /(^|\/)\.codex\/|CodexCLI\.app|(^|[\/\s])codex(\s|$)/;
27377
+ var codexParent;
27378
+ function underCodex() {
27379
+ if (codexParent !== void 0) return codexParent;
27380
+ codexParent = false;
27381
+ if (process.platform === "win32") return codexParent;
27382
+ for (const pid of ancestors()) {
27383
+ try {
27384
+ const command = execFileSync("ps", ["-o", "command=", "-p", String(pid)], { encoding: "utf8", timeout: 1e3 });
27385
+ if (CODEX_PARENT.test(command)) {
27386
+ codexParent = true;
27387
+ break;
27388
+ }
27389
+ } catch {
27390
+ }
27391
+ }
27392
+ return codexParent;
27393
+ }
27376
27394
  var lineage;
27377
27395
  function ancestors() {
27378
27396
  if (lineage) return lineage;
@@ -27430,7 +27448,8 @@ function parseSessionRecord(text) {
27430
27448
  return void 0;
27431
27449
  }
27432
27450
  function sessionId() {
27433
- return envSession("PAIGY_SESSION_ID") ?? claudeConversation() ?? envSession("CLAUDE_CODE_SESSION_ID") ?? envSession("CODEX_THREAD_ID") ?? envSession("CODEX_SESSION_ID") ?? WORKSPACE_ID;
27451
+ return envSession("PAIGY_SESSION_ID") ?? claudeConversation() ?? envSession("CLAUDE_CODE_SESSION_ID") ?? envSession("CODEX_THREAD_ID") ?? envSession("CODEX_SESSION_ID") ?? // A Codex thread that was handed no id is its own agent, not the folder's (`underCodex`).
27452
+ (underCodex() ? INSTANCE_ID : WORKSPACE_ID);
27434
27453
  }
27435
27454
  async function reach(url, init) {
27436
27455
  return send(url, init, sessionId());
@@ -29160,11 +29179,17 @@ var messageBase = {
29160
29179
  obligationIds: external_exports.array(id)
29161
29180
  };
29162
29181
  var BrainMessageSchema = external_exports.union([
29163
- external_exports.object({ ...messageBase, to: external_exports.object({ kind: external_exports.literal("user") }).strict() }).strict(),
29182
+ // A MESSAGE TO THE PERSON KEEPS ITS SENTENCES (turns.md): the talker writes them one by one, and each is
29183
+ // its own unit of speech (`<cycle>:<key>:<n>`). `text` is the same words joined, for every reader of a
29184
+ // message's words. Absent on results written before sentences.
29185
+ external_exports.object({ ...messageBase, to: external_exports.object({ kind: external_exports.literal("user") }).strict(), sentences: external_exports.array(external_exports.string().min(1)).min(1).optional() }).strict(),
29164
29186
  external_exports.object({
29165
29187
  ...messageBase,
29166
29188
  to: external_exports.object({ kind: external_exports.literal("agent"), agentId: external_exports.string().regex(/^agent:(?!paigy$)\S+$/) }).strict(),
29167
- call: external_exports.object({ callId: id, listen: external_exports.literal(true) }).strict().optional()
29189
+ call: external_exports.object({ callId: id, listen: external_exports.literal(true) }).strict().optional(),
29190
+ // THE PERSON ASKED TO BE CALLED BACK ONCE THIS AGENT'S WORK IS DONE (turns.md, step 0): the agent owes
29191
+ // the call, and its next contact about it rings them (`public.callbacks`).
29192
+ callback: external_exports.literal(true).optional()
29168
29193
  }).strict()
29169
29194
  ]);
29170
29195
  var BrainSearchSchema = external_exports.object({
@@ -29219,9 +29244,12 @@ var str2 = external_exports.string();
29219
29244
  var strs2 = external_exports.array(external_exports.string());
29220
29245
  var TalkerReplySchema = external_exports.object({
29221
29246
  /** What to say and send, messages to the person first: spoken in the order written. `to` is "user"
29222
- * or an agent's handle; `about` names handles; `blocks` is the item a question to an agent must be
29223
- * answered before ("" for none). */
29224
- messages: external_exports.array(external_exports.object({ key: str2, to: str2, text: str2, about: strs2, blocks: str2 }).strict()),
29247
+ * or an agent's handle; `sentences` is what a message to the person says, one short sentence each
29248
+ * ([] to an agent); `text` is what a message to an agent says ("" to the person); `about` names
29249
+ * handles; `blocks` is the item a question to an agent must be answered before ("" for none);
29250
+ * `callback` is true on a message to the agent doing work the person asked to be called back about
29251
+ * once it is done (false otherwise): that agent then owes the call (turns.md, step 0). */
29252
+ messages: external_exports.array(external_exports.object({ key: str2, to: str2, sentences: strs2, text: str2, about: strs2, blocks: str2, callback: external_exports.boolean() }).strict()),
29225
29253
  /** What the call does next: listen, hold (the person asked for a moment) or end (they asked to). */
29226
29254
  then: external_exports.enum(["listen", "hold", "end"]),
29227
29255
  /** The person's replies to items (replies, owner 2026-10-07): the item's handle, the chosen option
@@ -29345,42 +29373,6 @@ var LIVE_MS = 3 * 6e4;
29345
29373
  var WORKING_MS = 60 * 6e4;
29346
29374
  var WORKING_TIER_MS = 2 * 60 * 6e4;
29347
29375
  var RECENT_TIER_MS = 24 * 60 * 6e4;
29348
- var json = external_exports.lazy(() => external_exports.union([
29349
- external_exports.string(),
29350
- external_exports.number().finite(),
29351
- external_exports.boolean(),
29352
- external_exports.null(),
29353
- external_exports.array(json),
29354
- external_exports.record(json)
29355
- ]));
29356
- var clock = external_exports.number().int().nonnegative().safe();
29357
- var HeardEventSchema = external_exports.object({
29358
- eventId: external_exports.string().uuid(),
29359
- source: external_exports.enum(["phone", "bot"]),
29360
- sequence: clock,
29361
- kind: external_exports.string().min(1),
29362
- phoneAtMs: clock.optional(),
29363
- botAtMs: clock.optional(),
29364
- payload: external_exports.record(json)
29365
- }).strict();
29366
- var HeardCursorSchema = HeardEventSchema.pick({ source: true, sequence: true, eventId: true });
29367
- var HeardPageSchema = external_exports.object({
29368
- events: external_exports.array(HeardEventSchema).max(200),
29369
- next: HeardCursorSchema.nullable()
29370
- }).strict();
29371
- var MAX_EVENTS = 50;
29372
- var MAX_BYTES = 8e4;
29373
- var batchBytes = (events) => {
29374
- let bytes = 0;
29375
- for (const char of JSON.stringify({ events })) {
29376
- const point = char.codePointAt(0);
29377
- bytes += point < 128 ? 1 : point < 2048 ? 2 : point < 65536 ? 3 : 4;
29378
- }
29379
- return bytes;
29380
- };
29381
- var HeardBatchSchema = external_exports.object({
29382
- events: external_exports.array(HeardEventSchema).min(1).max(MAX_EVENTS)
29383
- }).strict().refine((value) => batchBytes(value.events) <= MAX_BYTES, "heard_batch_too_large");
29384
29376
  var ContextSchema = external_exports.object({
29385
29377
  title: external_exports.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
29386
29378
  description: external_exports.array(external_exports.string().min(1)).describe(
@@ -29705,6 +29697,10 @@ var AgendaTurnSchema = external_exports.object({
29705
29697
  /** The spoken sentences of the turn, in order. No count: how long a turn is is the brain's call
29706
29698
  * (owner, 2026-09-25), and a count here refused whole plans. */
29707
29699
  info: external_exports.array(external_exports.string().min(1)).default([]),
29700
+ /** THE ID OF EACH SENTENCE, when the plan names them (turns.md): a talker message's sentences are its
29701
+ * `info`, one piece each, and `units[i]` is the id the bot's line receipt carries for `info[i]`
29702
+ * (`<cycle>:<key>:<n>`), so what was heard is known per sentence. Absent on every other turn. */
29703
+ units: external_exports.array(external_exports.string().min(1)).optional(),
29708
29704
  question: external_exports.string().min(1).nullable(),
29709
29705
  /** True on the one turn carrying the agent's own declared question. */
29710
29706
  asks: external_exports.boolean().optional(),
@@ -29941,8 +29937,8 @@ var MissedCallSchema = external_exports.enum([
29941
29937
  "inbox",
29942
29938
  "dismiss"
29943
29939
  ]);
29944
- var clock2 = (h) => h === 0 ? "midnight" : h === 12 ? "noon" : h < 12 ? `${h} am` : `${h - 12} pm`;
29945
- var QUIET = ` Nothing rings from ${clock2(NIGHT.from)} to ${clock2(NIGHT.to)} your time; the count waits for morning.`;
29940
+ var clock = (h) => h === 0 ? "midnight" : h === 12 ? "noon" : h < 12 ? `${h} am` : `${h - 12} pm`;
29941
+ var QUIET = ` Nothing rings from ${clock(NIGHT.from)} to ${clock(NIGHT.to)} your time; the count waits for morning.`;
29946
29942
  var BrokerTuningSchema = external_exports.object({
29947
29943
  /** 'none' = skip the spoken ack after a mapped answer (power users find it slow). */
29948
29944
  ackVerbosity: external_exports.enum(["normal", "none"]).optional(),
@@ -30279,6 +30275,13 @@ var QueueItemSchema = external_exports.object({
30279
30275
  * can see (`replies`, `questions[].answeredAt`) miss a spontaneous note entirely — a `request`
30280
30276
  * Entry with no `about_id` is in neither. */
30281
30277
  lastPersonAt: external_exports.string().nullable().optional(),
30278
+ /** EACH SIDE'S NEWEST WORD IN THE LAST DAY (owner, 2026-10-13, the Work tab's order): the person's
30279
+ * (`yours`) and the agents' (`theirs`), each null when that side wrote nothing on it in 24 hours.
30280
+ * `latest` holds one Entry, so whichever side wrote first is hidden there; Work orders a Goal by
30281
+ * these two and draws the side it was placed by under its title. Optional, so hand-built queues
30282
+ * and a door older than 20261013045542 need not spell them. */
30283
+ yours: GoalLatestSchema.nullable().optional(),
30284
+ theirs: GoalLatestSchema.nullable().optional(),
30282
30285
  /** WHAT THIS ROW IS, IN TWELVE CHARACTERS (#2928) — the hash of every other field on it, stamped
30283
30286
  * by the one projection that builds the row (`apps/api/src/goal/queue.ts`). It is how the
30284
30287
  * incremental read knows a row has not moved: the phone echoes back the revs it holds
@@ -30552,10 +30555,20 @@ var CallRecapSchema = external_exports.object({
30552
30555
  title: external_exports.string(),
30553
30556
  owner: external_exports.string(),
30554
30557
  state: external_exports.string(),
30558
+ /** Presented Entry content and its author, separately from the current Goal owner. */
30559
+ items: external_exports.array(external_exports.object({ entryId: external_exports.string(), author: external_exports.string(), text: external_exports.string(), summary: external_exports.string().nullable() })).optional(),
30555
30560
  /** Whether the call put it to the person. An item it carried and never said has no row on the
30556
30561
  * review (owner, 2026-10-08: "why do we get the third one when it didn't happen in the call?"). */
30557
30562
  presented: external_exports.boolean(),
30558
- questions: external_exports.array(external_exports.object({ id: external_exports.string().uuid(), state: external_exports.string(), title: external_exports.string() })),
30563
+ /** Whether THIS call created it — the third way a call touches work, beside carrying a request
30564
+ * there and filing words there (owner, 2026-10-08, Goal `5b4b1a0a`: "Show the new work, keep my
30565
+ * words under it"). Created work is never carried, so it is never `presented`; without this the
30566
+ * row is dropped by the "only what happened on the call" filter. False on a database before
30567
+ * 20261013080133. */
30568
+ created: external_exports.boolean(),
30569
+ /** `request` is the Entry that asked it — what a line's `about` names when the line answered or put
30570
+ * it off. Optional: an older API sent none. */
30571
+ questions: external_exports.array(external_exports.object({ id: external_exports.string().uuid(), state: external_exports.string(), title: external_exports.string(), request: external_exports.string().optional() })),
30559
30572
  /** `words` is always what they SAID, verbatim — the record, never replaced. `summary` is what
30560
30573
  * the line says in ten words (owner, 2026-10-07): the filer's, or the talker's for the answer it
30561
30574
  * gave, so the row scans like a chosen option and their own words stay under it. Absent when
@@ -33451,11 +33464,17 @@ var messageBase2 = {
33451
33464
  obligationIds: external_exports.array(id2)
33452
33465
  };
33453
33466
  var BrainMessageSchema2 = external_exports.union([
33454
- external_exports.object({ ...messageBase2, to: external_exports.object({ kind: external_exports.literal("user") }).strict() }).strict(),
33467
+ // A MESSAGE TO THE PERSON KEEPS ITS SENTENCES (turns.md): the talker writes them one by one, and each is
33468
+ // its own unit of speech (`<cycle>:<key>:<n>`). `text` is the same words joined, for every reader of a
33469
+ // message's words. Absent on results written before sentences.
33470
+ external_exports.object({ ...messageBase2, to: external_exports.object({ kind: external_exports.literal("user") }).strict(), sentences: external_exports.array(external_exports.string().min(1)).min(1).optional() }).strict(),
33455
33471
  external_exports.object({
33456
33472
  ...messageBase2,
33457
33473
  to: external_exports.object({ kind: external_exports.literal("agent"), agentId: external_exports.string().regex(/^agent:(?!paigy$)\S+$/) }).strict(),
33458
- call: external_exports.object({ callId: id2, listen: external_exports.literal(true) }).strict().optional()
33474
+ call: external_exports.object({ callId: id2, listen: external_exports.literal(true) }).strict().optional(),
33475
+ // THE PERSON ASKED TO BE CALLED BACK ONCE THIS AGENT'S WORK IS DONE (turns.md, step 0): the agent owes
33476
+ // the call, and its next contact about it rings them (`public.callbacks`).
33477
+ callback: external_exports.literal(true).optional()
33459
33478
  }).strict()
33460
33479
  ]);
33461
33480
  var BrainSearchSchema2 = external_exports.object({
@@ -33510,9 +33529,12 @@ var str22 = external_exports.string();
33510
33529
  var strs22 = external_exports.array(external_exports.string());
33511
33530
  var TalkerReplySchema2 = external_exports.object({
33512
33531
  /** What to say and send, messages to the person first: spoken in the order written. `to` is "user"
33513
- * or an agent's handle; `about` names handles; `blocks` is the item a question to an agent must be
33514
- * answered before ("" for none). */
33515
- messages: external_exports.array(external_exports.object({ key: str22, to: str22, text: str22, about: strs22, blocks: str22 }).strict()),
33532
+ * or an agent's handle; `sentences` is what a message to the person says, one short sentence each
33533
+ * ([] to an agent); `text` is what a message to an agent says ("" to the person); `about` names
33534
+ * handles; `blocks` is the item a question to an agent must be answered before ("" for none);
33535
+ * `callback` is true on a message to the agent doing work the person asked to be called back about
33536
+ * once it is done (false otherwise): that agent then owes the call (turns.md, step 0). */
33537
+ messages: external_exports.array(external_exports.object({ key: str22, to: str22, sentences: strs22, text: str22, about: strs22, blocks: str22, callback: external_exports.boolean() }).strict()),
33516
33538
  /** What the call does next: listen, hold (the person asked for a moment) or end (they asked to). */
33517
33539
  then: external_exports.enum(["listen", "hold", "end"]),
33518
33540
  /** The person's replies to items (replies, owner 2026-10-07): the item's handle, the chosen option
@@ -33647,42 +33669,6 @@ var WORKING_MS2 = 60 * 6e4;
33647
33669
  var isWorking = (c, now) => !!c.lastWorkedAt && now - Date.parse(c.lastWorkedAt) < WORKING_MS2;
33648
33670
  var WORKING_TIER_MS2 = 2 * 60 * 6e4;
33649
33671
  var RECENT_TIER_MS2 = 24 * 60 * 6e4;
33650
- var json2 = external_exports.lazy(() => external_exports.union([
33651
- external_exports.string(),
33652
- external_exports.number().finite(),
33653
- external_exports.boolean(),
33654
- external_exports.null(),
33655
- external_exports.array(json2),
33656
- external_exports.record(json2)
33657
- ]));
33658
- var clock3 = external_exports.number().int().nonnegative().safe();
33659
- var HeardEventSchema2 = external_exports.object({
33660
- eventId: external_exports.string().uuid(),
33661
- source: external_exports.enum(["phone", "bot"]),
33662
- sequence: clock3,
33663
- kind: external_exports.string().min(1),
33664
- phoneAtMs: clock3.optional(),
33665
- botAtMs: clock3.optional(),
33666
- payload: external_exports.record(json2)
33667
- }).strict();
33668
- var HeardCursorSchema2 = HeardEventSchema2.pick({ source: true, sequence: true, eventId: true });
33669
- var HeardPageSchema2 = external_exports.object({
33670
- events: external_exports.array(HeardEventSchema2).max(200),
33671
- next: HeardCursorSchema2.nullable()
33672
- }).strict();
33673
- var MAX_EVENTS2 = 50;
33674
- var MAX_BYTES2 = 8e4;
33675
- var batchBytes2 = (events) => {
33676
- let bytes = 0;
33677
- for (const char of JSON.stringify({ events })) {
33678
- const point = char.codePointAt(0);
33679
- bytes += point < 128 ? 1 : point < 2048 ? 2 : point < 65536 ? 3 : 4;
33680
- }
33681
- return bytes;
33682
- };
33683
- var HeardBatchSchema2 = external_exports.object({
33684
- events: external_exports.array(HeardEventSchema2).min(1).max(MAX_EVENTS2)
33685
- }).strict().refine((value) => batchBytes2(value.events) <= MAX_BYTES2, "heard_batch_too_large");
33686
33672
  var ContextSchema2 = external_exports.object({
33687
33673
  title: external_exports.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
33688
33674
  description: external_exports.array(external_exports.string().min(1)).describe(
@@ -34007,6 +33993,10 @@ var AgendaTurnSchema2 = external_exports.object({
34007
33993
  /** The spoken sentences of the turn, in order. No count: how long a turn is is the brain's call
34008
33994
  * (owner, 2026-09-25), and a count here refused whole plans. */
34009
33995
  info: external_exports.array(external_exports.string().min(1)).default([]),
33996
+ /** THE ID OF EACH SENTENCE, when the plan names them (turns.md): a talker message's sentences are its
33997
+ * `info`, one piece each, and `units[i]` is the id the bot's line receipt carries for `info[i]`
33998
+ * (`<cycle>:<key>:<n>`), so what was heard is known per sentence. Absent on every other turn. */
33999
+ units: external_exports.array(external_exports.string().min(1)).optional(),
34010
34000
  question: external_exports.string().min(1).nullable(),
34011
34001
  /** True on the one turn carrying the agent's own declared question. */
34012
34002
  asks: external_exports.boolean().optional(),
@@ -34243,8 +34233,8 @@ var MissedCallSchema2 = external_exports.enum([
34243
34233
  "inbox",
34244
34234
  "dismiss"
34245
34235
  ]);
34246
- var clock22 = (h) => h === 0 ? "midnight" : h === 12 ? "noon" : h < 12 ? `${h} am` : `${h - 12} pm`;
34247
- var QUIET2 = ` Nothing rings from ${clock22(NIGHT2.from)} to ${clock22(NIGHT2.to)} your time; the count waits for morning.`;
34236
+ var clock2 = (h) => h === 0 ? "midnight" : h === 12 ? "noon" : h < 12 ? `${h} am` : `${h - 12} pm`;
34237
+ var QUIET2 = ` Nothing rings from ${clock2(NIGHT2.from)} to ${clock2(NIGHT2.to)} your time; the count waits for morning.`;
34248
34238
  var BrokerTuningSchema2 = external_exports.object({
34249
34239
  /** 'none' = skip the spoken ack after a mapped answer (power users find it slow). */
34250
34240
  ackVerbosity: external_exports.enum(["normal", "none"]).optional(),
@@ -34581,6 +34571,13 @@ var QueueItemSchema2 = external_exports.object({
34581
34571
  * can see (`replies`, `questions[].answeredAt`) miss a spontaneous note entirely — a `request`
34582
34572
  * Entry with no `about_id` is in neither. */
34583
34573
  lastPersonAt: external_exports.string().nullable().optional(),
34574
+ /** EACH SIDE'S NEWEST WORD IN THE LAST DAY (owner, 2026-10-13, the Work tab's order): the person's
34575
+ * (`yours`) and the agents' (`theirs`), each null when that side wrote nothing on it in 24 hours.
34576
+ * `latest` holds one Entry, so whichever side wrote first is hidden there; Work orders a Goal by
34577
+ * these two and draws the side it was placed by under its title. Optional, so hand-built queues
34578
+ * and a door older than 20261013045542 need not spell them. */
34579
+ yours: GoalLatestSchema2.nullable().optional(),
34580
+ theirs: GoalLatestSchema2.nullable().optional(),
34584
34581
  /** WHAT THIS ROW IS, IN TWELVE CHARACTERS (#2928) — the hash of every other field on it, stamped
34585
34582
  * by the one projection that builds the row (`apps/api/src/goal/queue.ts`). It is how the
34586
34583
  * incremental read knows a row has not moved: the phone echoes back the revs it holds
@@ -34852,10 +34849,20 @@ var CallRecapSchema2 = external_exports.object({
34852
34849
  title: external_exports.string(),
34853
34850
  owner: external_exports.string(),
34854
34851
  state: external_exports.string(),
34852
+ /** Presented Entry content and its author, separately from the current Goal owner. */
34853
+ items: external_exports.array(external_exports.object({ entryId: external_exports.string(), author: external_exports.string(), text: external_exports.string(), summary: external_exports.string().nullable() })).optional(),
34855
34854
  /** Whether the call put it to the person. An item it carried and never said has no row on the
34856
34855
  * review (owner, 2026-10-08: "why do we get the third one when it didn't happen in the call?"). */
34857
34856
  presented: external_exports.boolean(),
34858
- questions: external_exports.array(external_exports.object({ id: external_exports.string().uuid(), state: external_exports.string(), title: external_exports.string() })),
34857
+ /** Whether THIS call created it — the third way a call touches work, beside carrying a request
34858
+ * there and filing words there (owner, 2026-10-08, Goal `5b4b1a0a`: "Show the new work, keep my
34859
+ * words under it"). Created work is never carried, so it is never `presented`; without this the
34860
+ * row is dropped by the "only what happened on the call" filter. False on a database before
34861
+ * 20261013080133. */
34862
+ created: external_exports.boolean(),
34863
+ /** `request` is the Entry that asked it — what a line's `about` names when the line answered or put
34864
+ * it off. Optional: an older API sent none. */
34865
+ questions: external_exports.array(external_exports.object({ id: external_exports.string().uuid(), state: external_exports.string(), title: external_exports.string(), request: external_exports.string().optional() })),
34859
34866
  /** `words` is always what they SAID, verbatim — the record, never replaced. `summary` is what
34860
34867
  * the line says in ten words (owner, 2026-10-07): the filer's, or the talker's for the answer it
34861
34868
  * gave, so the row scans like a chosen option and their own words stay under it. Absent when
@@ -34962,9 +34969,9 @@ function limitIn(text, now) {
34962
34969
  if (!line) return null;
34963
34970
  const reset = resetOf(line, now);
34964
34971
  if (reset !== null && reset > now && reset - now <= FARTHEST_MS) {
34965
- return { until: reset + MARGIN_MS, resets: /resets\s+(?:at\s+)?(.+?)\s*(?:\(|$)/i.exec(line)?.[1]?.trim() ?? clock4(reset) };
34972
+ return { until: reset + MARGIN_MS, resets: /resets\s+(?:at\s+)?(.+?)\s*(?:\(|$)/i.exec(line)?.[1]?.trim() ?? clock3(reset) };
34966
34973
  }
34967
- return { until: now + RETRY_MS2, resets: clock4(now + RETRY_MS2) };
34974
+ return { until: now + RETRY_MS2, resets: clock3(now + RETRY_MS2) };
34968
34975
  }
34969
34976
  function resetOf(line, now) {
34970
34977
  const m = /resets\s+(?:at\s+)?(?:([a-z]{3})[a-z]*\s+(\d{1,2}),?\s+(?:at\s+)?)?(\d{1,2})(?::(\d{2}))?\s*(am|pm)\b(?:\s*\(([^)]+)\))?/i.exec(line);
@@ -35008,7 +35015,7 @@ function wallToEpoch(year, month, day, hour, minute, zone) {
35008
35015
  const first = wall - offset(wall);
35009
35016
  return wall - offset(first);
35010
35017
  }
35011
- function clock4(t) {
35018
+ function clock3(t) {
35012
35019
  return new Date(t).toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" }).replace(/\s?([AP])M$/i, (_, x) => `${x.toLowerCase()}m`);
35013
35020
  }
35014
35021
  var pausedLine = (limit) => `Paused by the usage limit until ${limit.resets}`;
@@ -35052,7 +35059,7 @@ function episodes(opts = {}) {
35052
35059
  episode.called = true;
35053
35060
  const rest = episode.paused.filter((n) => !episode.running.includes(n));
35054
35061
  const text = [
35055
- `Claude's usage limit paused ${names(episode.paused)} from ${clock4(episode.since)}.`,
35062
+ `Claude's usage limit paused ${names(episode.paused)} from ${clock3(episode.since)}.`,
35056
35063
  rest.length ? `It has reset: ${names(episode.running)} ${episode.running.length > 1 ? "are" : "is"} running again, and ${names(rest)} ${rest.length > 1 ? "haven't" : "hasn't"} started again yet.` : `It has reset, and ${episode.paused.length > 1 ? "they have all" : "it has"} carried on.`
35057
35064
  ].join(" ");
35058
35065
  void call(text).then(
@@ -35617,7 +35624,7 @@ async function send2(session, state, text) {
35617
35624
  }
35618
35625
  }
35619
35626
  async function pump(session, state, rail, opts) {
35620
- const clock5 = opts.beat ?? beat();
35627
+ const clock4 = opts.beat ?? beat();
35621
35628
  const now = opts.now ?? Date.now;
35622
35629
  const counts = { wake: 0, rest: 0, safety: 0, skipped: 0 };
35623
35630
  const tally = { noted: 0, seen: 0, announced: 0 };
@@ -35649,7 +35656,7 @@ async function pump(session, state, rail, opts) {
35649
35656
  counts.wake = counts.rest = counts.safety = counts.skipped = tally.noted = tally.seen = tally.announced = tally.paused = 0;
35650
35657
  since = now();
35651
35658
  }
35652
- cause = await clock5.next(state.asks?.size ? ASK_BEAT_MS : state.paused ? Math.max(1e3, Math.min(SAFETY_MS, state.paused.until - now())) : SAFETY_MS);
35659
+ cause = await clock4.next(state.asks?.size ? ASK_BEAT_MS : state.paused ? Math.max(1e3, Math.min(SAFETY_MS, state.paused.until - now())) : SAFETY_MS);
35653
35660
  if (!await opts.onIdle()) return;
35654
35661
  }
35655
35662
  }
@@ -35659,7 +35666,7 @@ function runHarness(opts) {
35659
35666
  let running = true;
35660
35667
  let tail = [];
35661
35668
  const state = { resting: true };
35662
- const clock5 = beat();
35669
+ const clock4 = beat();
35663
35670
  let session = null;
35664
35671
  const speaksAs = opts.session ?? opts.resume ?? sessionId();
35665
35672
  const instance = randomUUID4();
@@ -35720,7 +35727,7 @@ ${event.message}`, state, rail, { log: opts.log });
35720
35727
  stop2();
35721
35728
  return;
35722
35729
  } else if (carried) runningAgain();
35723
- clock5.nudge("rest");
35730
+ clock4.nudge("rest");
35724
35731
  }
35725
35732
  }
35726
35733
  session = startSession({
@@ -35739,13 +35746,13 @@ ${event.message}`, state, rail, { log: opts.log });
35739
35746
  },
35740
35747
  onEvent: (event) => void handle(event).catch((err) => opts.log(`\u26A0 ${err.message}`))
35741
35748
  });
35742
- void pump(session, state, rail, { onIdle: () => running, beat: clock5, initialPrompt: opts.prompt, log: opts.log, ...inbox ? { inbox } : {} }).catch(
35749
+ void pump(session, state, rail, { onIdle: () => running, beat: clock4, initialPrompt: opts.prompt, log: opts.log, ...inbox ? { inbox } : {} }).catch(
35743
35750
  (e) => opts.log(`\u26A0 conversation loop stopped: ${e.message}`)
35744
35751
  );
35745
35752
  opts.log(`\u25B6 started ${opts.harness} in ${opts.cwd} (${opts.mode} mode)`);
35746
35753
  function stop2() {
35747
35754
  running = false;
35748
- clock5.nudge("wake");
35755
+ clock4.nudge("wake");
35749
35756
  tail = [];
35750
35757
  cancelAsks(state);
35751
35758
  session?.stop();
@@ -35757,7 +35764,7 @@ ${event.message}`, state, rail, { log: opts.log });
35757
35764
  working: () => running && state.resting !== true,
35758
35765
  // Paused by a usage limit, the activity line says so: the quiet place the pause is shown.
35759
35766
  tail: () => state.paused ? [pausedLine(state.paused)] : [...tail],
35760
- nudge: () => clock5.nudge("wake"),
35767
+ nudge: () => clock4.nudge("wake"),
35761
35768
  stop: stop2
35762
35769
  };
35763
35770
  }
package/dist/main.js CHANGED
@@ -4858,8 +4858,8 @@ var ZodIssueCode = util.arrayToEnum([
4858
4858
  "not_finite"
4859
4859
  ]);
4860
4860
  var quotelessJson = (obj) => {
4861
- const json3 = JSON.stringify(obj, null, 2);
4862
- return json3.replace(/"([^"]+)":/g, "$1:");
4861
+ const json = JSON.stringify(obj, null, 2);
4862
+ return json.replace(/"([^"]+)":/g, "$1:");
4863
4863
  };
4864
4864
  var ZodError = class _ZodError extends Error {
4865
4865
  get errors() {
@@ -8669,6 +8669,24 @@ function parentOf(pid) {
8669
8669
  return void 0;
8670
8670
  }
8671
8671
  }
8672
+ var CODEX_PARENT = /(^|\/)\.codex\/|CodexCLI\.app|(^|[\/\s])codex(\s|$)/;
8673
+ var codexParent;
8674
+ function underCodex() {
8675
+ if (codexParent !== void 0) return codexParent;
8676
+ codexParent = false;
8677
+ if (process.platform === "win32") return codexParent;
8678
+ for (const pid of ancestors()) {
8679
+ try {
8680
+ const command = execFileSync("ps", ["-o", "command=", "-p", String(pid)], { encoding: "utf8", timeout: 1e3 });
8681
+ if (CODEX_PARENT.test(command)) {
8682
+ codexParent = true;
8683
+ break;
8684
+ }
8685
+ } catch {
8686
+ }
8687
+ }
8688
+ return codexParent;
8689
+ }
8672
8690
  var lineage;
8673
8691
  function ancestors() {
8674
8692
  if (lineage) return lineage;
@@ -8726,7 +8744,8 @@ function parseSessionRecord(text) {
8726
8744
  return void 0;
8727
8745
  }
8728
8746
  function sessionId() {
8729
- return envSession("PAIGY_SESSION_ID") ?? claudeConversation() ?? envSession("CLAUDE_CODE_SESSION_ID") ?? envSession("CODEX_THREAD_ID") ?? envSession("CODEX_SESSION_ID") ?? WORKSPACE_ID;
8747
+ return envSession("PAIGY_SESSION_ID") ?? claudeConversation() ?? envSession("CLAUDE_CODE_SESSION_ID") ?? envSession("CODEX_THREAD_ID") ?? envSession("CODEX_SESSION_ID") ?? // A Codex thread that was handed no id is its own agent, not the folder's (`underCodex`).
8748
+ (underCodex() ? INSTANCE_ID : WORKSPACE_ID);
8730
8749
  }
8731
8750
  async function reach(url, init) {
8732
8751
  return send(url, init, sessionId());
@@ -10453,11 +10472,17 @@ var messageBase = {
10453
10472
  obligationIds: external_exports.array(id)
10454
10473
  };
10455
10474
  var BrainMessageSchema = external_exports.union([
10456
- external_exports.object({ ...messageBase, to: external_exports.object({ kind: external_exports.literal("user") }).strict() }).strict(),
10475
+ // A MESSAGE TO THE PERSON KEEPS ITS SENTENCES (turns.md): the talker writes them one by one, and each is
10476
+ // its own unit of speech (`<cycle>:<key>:<n>`). `text` is the same words joined, for every reader of a
10477
+ // message's words. Absent on results written before sentences.
10478
+ external_exports.object({ ...messageBase, to: external_exports.object({ kind: external_exports.literal("user") }).strict(), sentences: external_exports.array(external_exports.string().min(1)).min(1).optional() }).strict(),
10457
10479
  external_exports.object({
10458
10480
  ...messageBase,
10459
10481
  to: external_exports.object({ kind: external_exports.literal("agent"), agentId: external_exports.string().regex(/^agent:(?!paigy$)\S+$/) }).strict(),
10460
- call: external_exports.object({ callId: id, listen: external_exports.literal(true) }).strict().optional()
10482
+ call: external_exports.object({ callId: id, listen: external_exports.literal(true) }).strict().optional(),
10483
+ // THE PERSON ASKED TO BE CALLED BACK ONCE THIS AGENT'S WORK IS DONE (turns.md, step 0): the agent owes
10484
+ // the call, and its next contact about it rings them (`public.callbacks`).
10485
+ callback: external_exports.literal(true).optional()
10461
10486
  }).strict()
10462
10487
  ]);
10463
10488
  var BrainSearchSchema = external_exports.object({
@@ -10512,9 +10537,12 @@ var str2 = external_exports.string();
10512
10537
  var strs2 = external_exports.array(external_exports.string());
10513
10538
  var TalkerReplySchema = external_exports.object({
10514
10539
  /** What to say and send, messages to the person first: spoken in the order written. `to` is "user"
10515
- * or an agent's handle; `about` names handles; `blocks` is the item a question to an agent must be
10516
- * answered before ("" for none). */
10517
- messages: external_exports.array(external_exports.object({ key: str2, to: str2, text: str2, about: strs2, blocks: str2 }).strict()),
10540
+ * or an agent's handle; `sentences` is what a message to the person says, one short sentence each
10541
+ * ([] to an agent); `text` is what a message to an agent says ("" to the person); `about` names
10542
+ * handles; `blocks` is the item a question to an agent must be answered before ("" for none);
10543
+ * `callback` is true on a message to the agent doing work the person asked to be called back about
10544
+ * once it is done (false otherwise): that agent then owes the call (turns.md, step 0). */
10545
+ messages: external_exports.array(external_exports.object({ key: str2, to: str2, sentences: strs2, text: str2, about: strs2, blocks: str2, callback: external_exports.boolean() }).strict()),
10518
10546
  /** What the call does next: listen, hold (the person asked for a moment) or end (they asked to). */
10519
10547
  then: external_exports.enum(["listen", "hold", "end"]),
10520
10548
  /** The person's replies to items (replies, owner 2026-10-07): the item's handle, the chosen option
@@ -10638,42 +10666,6 @@ var LIVE_MS = 3 * 6e4;
10638
10666
  var WORKING_MS = 60 * 6e4;
10639
10667
  var WORKING_TIER_MS = 2 * 60 * 6e4;
10640
10668
  var RECENT_TIER_MS = 24 * 60 * 6e4;
10641
- var json = external_exports.lazy(() => external_exports.union([
10642
- external_exports.string(),
10643
- external_exports.number().finite(),
10644
- external_exports.boolean(),
10645
- external_exports.null(),
10646
- external_exports.array(json),
10647
- external_exports.record(json)
10648
- ]));
10649
- var clock = external_exports.number().int().nonnegative().safe();
10650
- var HeardEventSchema = external_exports.object({
10651
- eventId: external_exports.string().uuid(),
10652
- source: external_exports.enum(["phone", "bot"]),
10653
- sequence: clock,
10654
- kind: external_exports.string().min(1),
10655
- phoneAtMs: clock.optional(),
10656
- botAtMs: clock.optional(),
10657
- payload: external_exports.record(json)
10658
- }).strict();
10659
- var HeardCursorSchema = HeardEventSchema.pick({ source: true, sequence: true, eventId: true });
10660
- var HeardPageSchema = external_exports.object({
10661
- events: external_exports.array(HeardEventSchema).max(200),
10662
- next: HeardCursorSchema.nullable()
10663
- }).strict();
10664
- var MAX_EVENTS = 50;
10665
- var MAX_BYTES = 8e4;
10666
- var batchBytes = (events) => {
10667
- let bytes = 0;
10668
- for (const char of JSON.stringify({ events })) {
10669
- const point = char.codePointAt(0);
10670
- bytes += point < 128 ? 1 : point < 2048 ? 2 : point < 65536 ? 3 : 4;
10671
- }
10672
- return bytes;
10673
- };
10674
- var HeardBatchSchema = external_exports.object({
10675
- events: external_exports.array(HeardEventSchema).min(1).max(MAX_EVENTS)
10676
- }).strict().refine((value) => batchBytes(value.events) <= MAX_BYTES, "heard_batch_too_large");
10677
10669
  var ContextSchema = external_exports.object({
10678
10670
  title: external_exports.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
10679
10671
  description: external_exports.array(external_exports.string().min(1)).describe(
@@ -10998,6 +10990,10 @@ var AgendaTurnSchema = external_exports.object({
10998
10990
  /** The spoken sentences of the turn, in order. No count: how long a turn is is the brain's call
10999
10991
  * (owner, 2026-09-25), and a count here refused whole plans. */
11000
10992
  info: external_exports.array(external_exports.string().min(1)).default([]),
10993
+ /** THE ID OF EACH SENTENCE, when the plan names them (turns.md): a talker message's sentences are its
10994
+ * `info`, one piece each, and `units[i]` is the id the bot's line receipt carries for `info[i]`
10995
+ * (`<cycle>:<key>:<n>`), so what was heard is known per sentence. Absent on every other turn. */
10996
+ units: external_exports.array(external_exports.string().min(1)).optional(),
11001
10997
  question: external_exports.string().min(1).nullable(),
11002
10998
  /** True on the one turn carrying the agent's own declared question. */
11003
10999
  asks: external_exports.boolean().optional(),
@@ -11234,8 +11230,8 @@ var MissedCallSchema = external_exports.enum([
11234
11230
  "inbox",
11235
11231
  "dismiss"
11236
11232
  ]);
11237
- var clock2 = (h) => h === 0 ? "midnight" : h === 12 ? "noon" : h < 12 ? `${h} am` : `${h - 12} pm`;
11238
- var QUIET = ` Nothing rings from ${clock2(NIGHT.from)} to ${clock2(NIGHT.to)} your time; the count waits for morning.`;
11233
+ var clock = (h) => h === 0 ? "midnight" : h === 12 ? "noon" : h < 12 ? `${h} am` : `${h - 12} pm`;
11234
+ var QUIET = ` Nothing rings from ${clock(NIGHT.from)} to ${clock(NIGHT.to)} your time; the count waits for morning.`;
11239
11235
  var BrokerTuningSchema = external_exports.object({
11240
11236
  /** 'none' = skip the spoken ack after a mapped answer (power users find it slow). */
11241
11237
  ackVerbosity: external_exports.enum(["normal", "none"]).optional(),
@@ -11572,6 +11568,13 @@ var QueueItemSchema = external_exports.object({
11572
11568
  * can see (`replies`, `questions[].answeredAt`) miss a spontaneous note entirely — a `request`
11573
11569
  * Entry with no `about_id` is in neither. */
11574
11570
  lastPersonAt: external_exports.string().nullable().optional(),
11571
+ /** EACH SIDE'S NEWEST WORD IN THE LAST DAY (owner, 2026-10-13, the Work tab's order): the person's
11572
+ * (`yours`) and the agents' (`theirs`), each null when that side wrote nothing on it in 24 hours.
11573
+ * `latest` holds one Entry, so whichever side wrote first is hidden there; Work orders a Goal by
11574
+ * these two and draws the side it was placed by under its title. Optional, so hand-built queues
11575
+ * and a door older than 20261013045542 need not spell them. */
11576
+ yours: GoalLatestSchema.nullable().optional(),
11577
+ theirs: GoalLatestSchema.nullable().optional(),
11575
11578
  /** WHAT THIS ROW IS, IN TWELVE CHARACTERS (#2928) — the hash of every other field on it, stamped
11576
11579
  * by the one projection that builds the row (`apps/api/src/goal/queue.ts`). It is how the
11577
11580
  * incremental read knows a row has not moved: the phone echoes back the revs it holds
@@ -11845,10 +11848,20 @@ var CallRecapSchema = external_exports.object({
11845
11848
  title: external_exports.string(),
11846
11849
  owner: external_exports.string(),
11847
11850
  state: external_exports.string(),
11851
+ /** Presented Entry content and its author, separately from the current Goal owner. */
11852
+ items: external_exports.array(external_exports.object({ entryId: external_exports.string(), author: external_exports.string(), text: external_exports.string(), summary: external_exports.string().nullable() })).optional(),
11848
11853
  /** Whether the call put it to the person. An item it carried and never said has no row on the
11849
11854
  * review (owner, 2026-10-08: "why do we get the third one when it didn't happen in the call?"). */
11850
11855
  presented: external_exports.boolean(),
11851
- questions: external_exports.array(external_exports.object({ id: external_exports.string().uuid(), state: external_exports.string(), title: external_exports.string() })),
11856
+ /** Whether THIS call created it — the third way a call touches work, beside carrying a request
11857
+ * there and filing words there (owner, 2026-10-08, Goal `5b4b1a0a`: "Show the new work, keep my
11858
+ * words under it"). Created work is never carried, so it is never `presented`; without this the
11859
+ * row is dropped by the "only what happened on the call" filter. False on a database before
11860
+ * 20261013080133. */
11861
+ created: external_exports.boolean(),
11862
+ /** `request` is the Entry that asked it — what a line's `about` names when the line answered or put
11863
+ * it off. Optional: an older API sent none. */
11864
+ questions: external_exports.array(external_exports.object({ id: external_exports.string().uuid(), state: external_exports.string(), title: external_exports.string(), request: external_exports.string().optional() })),
11852
11865
  /** `words` is always what they SAID, verbatim — the record, never replaced. `summary` is what
11853
11866
  * the line says in ten words (owner, 2026-10-07): the filer's, or the talker's for the answer it
11854
11867
  * gave, so the row scans like a chosen option and their own words stay under it. Absent when
@@ -14262,11 +14275,17 @@ var messageBase2 = {
14262
14275
  obligationIds: external_exports.array(id2)
14263
14276
  };
14264
14277
  var BrainMessageSchema2 = external_exports.union([
14265
- external_exports.object({ ...messageBase2, to: external_exports.object({ kind: external_exports.literal("user") }).strict() }).strict(),
14278
+ // A MESSAGE TO THE PERSON KEEPS ITS SENTENCES (turns.md): the talker writes them one by one, and each is
14279
+ // its own unit of speech (`<cycle>:<key>:<n>`). `text` is the same words joined, for every reader of a
14280
+ // message's words. Absent on results written before sentences.
14281
+ external_exports.object({ ...messageBase2, to: external_exports.object({ kind: external_exports.literal("user") }).strict(), sentences: external_exports.array(external_exports.string().min(1)).min(1).optional() }).strict(),
14266
14282
  external_exports.object({
14267
14283
  ...messageBase2,
14268
14284
  to: external_exports.object({ kind: external_exports.literal("agent"), agentId: external_exports.string().regex(/^agent:(?!paigy$)\S+$/) }).strict(),
14269
- call: external_exports.object({ callId: id2, listen: external_exports.literal(true) }).strict().optional()
14285
+ call: external_exports.object({ callId: id2, listen: external_exports.literal(true) }).strict().optional(),
14286
+ // THE PERSON ASKED TO BE CALLED BACK ONCE THIS AGENT'S WORK IS DONE (turns.md, step 0): the agent owes
14287
+ // the call, and its next contact about it rings them (`public.callbacks`).
14288
+ callback: external_exports.literal(true).optional()
14270
14289
  }).strict()
14271
14290
  ]);
14272
14291
  var BrainSearchSchema2 = external_exports.object({
@@ -14321,9 +14340,12 @@ var str22 = external_exports.string();
14321
14340
  var strs22 = external_exports.array(external_exports.string());
14322
14341
  var TalkerReplySchema2 = external_exports.object({
14323
14342
  /** What to say and send, messages to the person first: spoken in the order written. `to` is "user"
14324
- * or an agent's handle; `about` names handles; `blocks` is the item a question to an agent must be
14325
- * answered before ("" for none). */
14326
- messages: external_exports.array(external_exports.object({ key: str22, to: str22, text: str22, about: strs22, blocks: str22 }).strict()),
14343
+ * or an agent's handle; `sentences` is what a message to the person says, one short sentence each
14344
+ * ([] to an agent); `text` is what a message to an agent says ("" to the person); `about` names
14345
+ * handles; `blocks` is the item a question to an agent must be answered before ("" for none);
14346
+ * `callback` is true on a message to the agent doing work the person asked to be called back about
14347
+ * once it is done (false otherwise): that agent then owes the call (turns.md, step 0). */
14348
+ messages: external_exports.array(external_exports.object({ key: str22, to: str22, sentences: strs22, text: str22, about: strs22, blocks: str22, callback: external_exports.boolean() }).strict()),
14327
14349
  /** What the call does next: listen, hold (the person asked for a moment) or end (they asked to). */
14328
14350
  then: external_exports.enum(["listen", "hold", "end"]),
14329
14351
  /** The person's replies to items (replies, owner 2026-10-07): the item's handle, the chosen option
@@ -14458,42 +14480,6 @@ var WORKING_MS2 = 60 * 6e4;
14458
14480
  var isWorking = (c, now) => !!c.lastWorkedAt && now - Date.parse(c.lastWorkedAt) < WORKING_MS2;
14459
14481
  var WORKING_TIER_MS2 = 2 * 60 * 6e4;
14460
14482
  var RECENT_TIER_MS2 = 24 * 60 * 6e4;
14461
- var json2 = external_exports.lazy(() => external_exports.union([
14462
- external_exports.string(),
14463
- external_exports.number().finite(),
14464
- external_exports.boolean(),
14465
- external_exports.null(),
14466
- external_exports.array(json2),
14467
- external_exports.record(json2)
14468
- ]));
14469
- var clock3 = external_exports.number().int().nonnegative().safe();
14470
- var HeardEventSchema2 = external_exports.object({
14471
- eventId: external_exports.string().uuid(),
14472
- source: external_exports.enum(["phone", "bot"]),
14473
- sequence: clock3,
14474
- kind: external_exports.string().min(1),
14475
- phoneAtMs: clock3.optional(),
14476
- botAtMs: clock3.optional(),
14477
- payload: external_exports.record(json2)
14478
- }).strict();
14479
- var HeardCursorSchema2 = HeardEventSchema2.pick({ source: true, sequence: true, eventId: true });
14480
- var HeardPageSchema2 = external_exports.object({
14481
- events: external_exports.array(HeardEventSchema2).max(200),
14482
- next: HeardCursorSchema2.nullable()
14483
- }).strict();
14484
- var MAX_EVENTS2 = 50;
14485
- var MAX_BYTES2 = 8e4;
14486
- var batchBytes2 = (events) => {
14487
- let bytes = 0;
14488
- for (const char of JSON.stringify({ events })) {
14489
- const point = char.codePointAt(0);
14490
- bytes += point < 128 ? 1 : point < 2048 ? 2 : point < 65536 ? 3 : 4;
14491
- }
14492
- return bytes;
14493
- };
14494
- var HeardBatchSchema2 = external_exports.object({
14495
- events: external_exports.array(HeardEventSchema2).min(1).max(MAX_EVENTS2)
14496
- }).strict().refine((value) => batchBytes2(value.events) <= MAX_BYTES2, "heard_batch_too_large");
14497
14483
  var ContextSchema2 = external_exports.object({
14498
14484
  title: external_exports.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
14499
14485
  description: external_exports.array(external_exports.string().min(1)).describe(
@@ -14818,6 +14804,10 @@ var AgendaTurnSchema2 = external_exports.object({
14818
14804
  /** The spoken sentences of the turn, in order. No count: how long a turn is is the brain's call
14819
14805
  * (owner, 2026-09-25), and a count here refused whole plans. */
14820
14806
  info: external_exports.array(external_exports.string().min(1)).default([]),
14807
+ /** THE ID OF EACH SENTENCE, when the plan names them (turns.md): a talker message's sentences are its
14808
+ * `info`, one piece each, and `units[i]` is the id the bot's line receipt carries for `info[i]`
14809
+ * (`<cycle>:<key>:<n>`), so what was heard is known per sentence. Absent on every other turn. */
14810
+ units: external_exports.array(external_exports.string().min(1)).optional(),
14821
14811
  question: external_exports.string().min(1).nullable(),
14822
14812
  /** True on the one turn carrying the agent's own declared question. */
14823
14813
  asks: external_exports.boolean().optional(),
@@ -15054,8 +15044,8 @@ var MissedCallSchema2 = external_exports.enum([
15054
15044
  "inbox",
15055
15045
  "dismiss"
15056
15046
  ]);
15057
- var clock22 = (h) => h === 0 ? "midnight" : h === 12 ? "noon" : h < 12 ? `${h} am` : `${h - 12} pm`;
15058
- var QUIET2 = ` Nothing rings from ${clock22(NIGHT2.from)} to ${clock22(NIGHT2.to)} your time; the count waits for morning.`;
15047
+ var clock2 = (h) => h === 0 ? "midnight" : h === 12 ? "noon" : h < 12 ? `${h} am` : `${h - 12} pm`;
15048
+ var QUIET2 = ` Nothing rings from ${clock2(NIGHT2.from)} to ${clock2(NIGHT2.to)} your time; the count waits for morning.`;
15059
15049
  var BrokerTuningSchema2 = external_exports.object({
15060
15050
  /** 'none' = skip the spoken ack after a mapped answer (power users find it slow). */
15061
15051
  ackVerbosity: external_exports.enum(["normal", "none"]).optional(),
@@ -15392,6 +15382,13 @@ var QueueItemSchema2 = external_exports.object({
15392
15382
  * can see (`replies`, `questions[].answeredAt`) miss a spontaneous note entirely — a `request`
15393
15383
  * Entry with no `about_id` is in neither. */
15394
15384
  lastPersonAt: external_exports.string().nullable().optional(),
15385
+ /** EACH SIDE'S NEWEST WORD IN THE LAST DAY (owner, 2026-10-13, the Work tab's order): the person's
15386
+ * (`yours`) and the agents' (`theirs`), each null when that side wrote nothing on it in 24 hours.
15387
+ * `latest` holds one Entry, so whichever side wrote first is hidden there; Work orders a Goal by
15388
+ * these two and draws the side it was placed by under its title. Optional, so hand-built queues
15389
+ * and a door older than 20261013045542 need not spell them. */
15390
+ yours: GoalLatestSchema2.nullable().optional(),
15391
+ theirs: GoalLatestSchema2.nullable().optional(),
15395
15392
  /** WHAT THIS ROW IS, IN TWELVE CHARACTERS (#2928) — the hash of every other field on it, stamped
15396
15393
  * by the one projection that builds the row (`apps/api/src/goal/queue.ts`). It is how the
15397
15394
  * incremental read knows a row has not moved: the phone echoes back the revs it holds
@@ -15663,10 +15660,20 @@ var CallRecapSchema2 = external_exports.object({
15663
15660
  title: external_exports.string(),
15664
15661
  owner: external_exports.string(),
15665
15662
  state: external_exports.string(),
15663
+ /** Presented Entry content and its author, separately from the current Goal owner. */
15664
+ items: external_exports.array(external_exports.object({ entryId: external_exports.string(), author: external_exports.string(), text: external_exports.string(), summary: external_exports.string().nullable() })).optional(),
15666
15665
  /** Whether the call put it to the person. An item it carried and never said has no row on the
15667
15666
  * review (owner, 2026-10-08: "why do we get the third one when it didn't happen in the call?"). */
15668
15667
  presented: external_exports.boolean(),
15669
- questions: external_exports.array(external_exports.object({ id: external_exports.string().uuid(), state: external_exports.string(), title: external_exports.string() })),
15668
+ /** Whether THIS call created it — the third way a call touches work, beside carrying a request
15669
+ * there and filing words there (owner, 2026-10-08, Goal `5b4b1a0a`: "Show the new work, keep my
15670
+ * words under it"). Created work is never carried, so it is never `presented`; without this the
15671
+ * row is dropped by the "only what happened on the call" filter. False on a database before
15672
+ * 20261013080133. */
15673
+ created: external_exports.boolean(),
15674
+ /** `request` is the Entry that asked it — what a line's `about` names when the line answered or put
15675
+ * it off. Optional: an older API sent none. */
15676
+ questions: external_exports.array(external_exports.object({ id: external_exports.string().uuid(), state: external_exports.string(), title: external_exports.string(), request: external_exports.string().optional() })),
15670
15677
  /** `words` is always what they SAID, verbatim — the record, never replaced. `summary` is what
15671
15678
  * the line says in ten words (owner, 2026-10-07): the filer's, or the talker's for the answer it
15672
15679
  * gave, so the row scans like a chosen option and their own words stay under it. Absent when
@@ -16632,9 +16639,9 @@ function limitIn(text, now) {
16632
16639
  if (!line) return null;
16633
16640
  const reset = resetOf(line, now);
16634
16641
  if (reset !== null && reset > now && reset - now <= FARTHEST_MS) {
16635
- return { until: reset + MARGIN_MS, resets: /resets\s+(?:at\s+)?(.+?)\s*(?:\(|$)/i.exec(line)?.[1]?.trim() ?? clock4(reset) };
16642
+ return { until: reset + MARGIN_MS, resets: /resets\s+(?:at\s+)?(.+?)\s*(?:\(|$)/i.exec(line)?.[1]?.trim() ?? clock3(reset) };
16636
16643
  }
16637
- return { until: now + RETRY_MS2, resets: clock4(now + RETRY_MS2) };
16644
+ return { until: now + RETRY_MS2, resets: clock3(now + RETRY_MS2) };
16638
16645
  }
16639
16646
  function resetOf(line, now) {
16640
16647
  const m = /resets\s+(?:at\s+)?(?:([a-z]{3})[a-z]*\s+(\d{1,2}),?\s+(?:at\s+)?)?(\d{1,2})(?::(\d{2}))?\s*(am|pm)\b(?:\s*\(([^)]+)\))?/i.exec(line);
@@ -16678,7 +16685,7 @@ function wallToEpoch(year, month, day, hour, minute, zone) {
16678
16685
  const first = wall - offset(wall);
16679
16686
  return wall - offset(first);
16680
16687
  }
16681
- function clock4(t) {
16688
+ function clock3(t) {
16682
16689
  return new Date(t).toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" }).replace(/\s?([AP])M$/i, (_, x) => `${x.toLowerCase()}m`);
16683
16690
  }
16684
16691
  var pausedLine = (limit) => `Paused by the usage limit until ${limit.resets}`;
@@ -16722,7 +16729,7 @@ function episodes(opts = {}) {
16722
16729
  episode.called = true;
16723
16730
  const rest = episode.paused.filter((n) => !episode.running.includes(n));
16724
16731
  const text = [
16725
- `Claude's usage limit paused ${names(episode.paused)} from ${clock4(episode.since)}.`,
16732
+ `Claude's usage limit paused ${names(episode.paused)} from ${clock3(episode.since)}.`,
16726
16733
  rest.length ? `It has reset: ${names(episode.running)} ${episode.running.length > 1 ? "are" : "is"} running again, and ${names(rest)} ${rest.length > 1 ? "haven't" : "hasn't"} started again yet.` : `It has reset, and ${episode.paused.length > 1 ? "they have all" : "it has"} carried on.`
16727
16734
  ].join(" ");
16728
16735
  void call(text).then(
@@ -17287,7 +17294,7 @@ async function send2(session, state, text) {
17287
17294
  }
17288
17295
  }
17289
17296
  async function pump(session, state, rail, opts) {
17290
- const clock5 = opts.beat ?? beat();
17297
+ const clock4 = opts.beat ?? beat();
17291
17298
  const now = opts.now ?? Date.now;
17292
17299
  const counts = { wake: 0, rest: 0, safety: 0, skipped: 0 };
17293
17300
  const tally = { noted: 0, seen: 0, announced: 0 };
@@ -17319,7 +17326,7 @@ async function pump(session, state, rail, opts) {
17319
17326
  counts.wake = counts.rest = counts.safety = counts.skipped = tally.noted = tally.seen = tally.announced = tally.paused = 0;
17320
17327
  since = now();
17321
17328
  }
17322
- cause = await clock5.next(state.asks?.size ? ASK_BEAT_MS : state.paused ? Math.max(1e3, Math.min(SAFETY_MS, state.paused.until - now())) : SAFETY_MS);
17329
+ cause = await clock4.next(state.asks?.size ? ASK_BEAT_MS : state.paused ? Math.max(1e3, Math.min(SAFETY_MS, state.paused.until - now())) : SAFETY_MS);
17323
17330
  if (!await opts.onIdle()) return;
17324
17331
  }
17325
17332
  }
@@ -17329,7 +17336,7 @@ function runHarness(opts) {
17329
17336
  let running = true;
17330
17337
  let tail = [];
17331
17338
  const state = { resting: true };
17332
- const clock5 = beat();
17339
+ const clock4 = beat();
17333
17340
  let session = null;
17334
17341
  const speaksAs = opts.session ?? opts.resume ?? sessionId();
17335
17342
  const instance = randomUUID4();
@@ -17390,7 +17397,7 @@ ${event.message}`, state, rail, { log: opts.log });
17390
17397
  stop2();
17391
17398
  return;
17392
17399
  } else if (carried) runningAgain();
17393
- clock5.nudge("rest");
17400
+ clock4.nudge("rest");
17394
17401
  }
17395
17402
  }
17396
17403
  session = startSession({
@@ -17409,13 +17416,13 @@ ${event.message}`, state, rail, { log: opts.log });
17409
17416
  },
17410
17417
  onEvent: (event) => void handle(event).catch((err) => opts.log(`\u26A0 ${err.message}`))
17411
17418
  });
17412
- void pump(session, state, rail, { onIdle: () => running, beat: clock5, initialPrompt: opts.prompt, log: opts.log, ...inbox ? { inbox } : {} }).catch(
17419
+ void pump(session, state, rail, { onIdle: () => running, beat: clock4, initialPrompt: opts.prompt, log: opts.log, ...inbox ? { inbox } : {} }).catch(
17413
17420
  (e) => opts.log(`\u26A0 conversation loop stopped: ${e.message}`)
17414
17421
  );
17415
17422
  opts.log(`\u25B6 started ${opts.harness} in ${opts.cwd} (${opts.mode} mode)`);
17416
17423
  function stop2() {
17417
17424
  running = false;
17418
- clock5.nudge("wake");
17425
+ clock4.nudge("wake");
17419
17426
  tail = [];
17420
17427
  cancelAsks(state);
17421
17428
  session?.stop();
@@ -17427,7 +17434,7 @@ ${event.message}`, state, rail, { log: opts.log });
17427
17434
  working: () => running && state.resting !== true,
17428
17435
  // Paused by a usage limit, the activity line says so: the quiet place the pause is shown.
17429
17436
  tail: () => state.paused ? [pausedLine(state.paused)] : [...tail],
17430
- nudge: () => clock5.nudge("wake"),
17437
+ nudge: () => clock4.nudge("wake"),
17431
17438
  stop: stop2
17432
17439
  };
17433
17440
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paigy/harness",
3
- "version": "0.3.42",
3
+ "version": "0.3.45",
4
4
  "description": "Run Claude Code / Codex on this machine, bridged to Paigy — launchable from your phone.",
5
5
  "license": "MIT",
6
6
  "type": "module",