@paigy/mcp 0.35.0 → 0.36.0

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.
@@ -1,9 +1,13 @@
1
1
  // ../../packages/sdk/dist/index.js
2
2
  import { createRequire as __sdkCreateRequire } from "module";
3
3
  import { randomUUID } from "crypto";
4
+ import { z as z2 } from "zod";
4
5
  import { z } from "zod";
6
+ import { ZodFirstPartyTypeKind as ZodFirstPartyTypeKind3 } from "zod/v3";
7
+ import { ZodFirstPartyTypeKind } from "zod/v3";
8
+ import { ZodFirstPartyTypeKind as ZodFirstPartyTypeKind2 } from "zod/v3";
9
+ import { createHash } from "crypto";
5
10
  import { closeSync, existsSync, mkdirSync, openSync, readFileSync, rmSync, statSync, writeFileSync } from "fs";
6
- import { randomUUID as randomUUID2 } from "crypto";
7
11
  import { homedir } from "os";
8
12
  import { join } from "path";
9
13
  var require2 = __sdkCreateRequire(import.meta.url);
@@ -336,17 +340,17 @@ var require_nacl_fast = __commonJS({
336
340
  }
337
341
  var sigma = new Uint8Array([101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107]);
338
342
  function crypto_stream_salsa20_xor(c, cpos, m, mpos, b, n, k) {
339
- var z2 = new Uint8Array(16), x = new Uint8Array(64);
343
+ var z3 = new Uint8Array(16), x = new Uint8Array(64);
340
344
  var u, i;
341
- for (i = 0; i < 16; i++) z2[i] = 0;
342
- for (i = 0; i < 8; i++) z2[i] = n[i];
345
+ for (i = 0; i < 16; i++) z3[i] = 0;
346
+ for (i = 0; i < 8; i++) z3[i] = n[i];
343
347
  while (b >= 64) {
344
- crypto_core_salsa20(x, z2, k, sigma);
348
+ crypto_core_salsa20(x, z3, k, sigma);
345
349
  for (i = 0; i < 64; i++) c[cpos + i] = m[mpos + i] ^ x[i];
346
350
  u = 1;
347
351
  for (i = 8; i < 16; i++) {
348
- u = u + (z2[i] & 255) | 0;
349
- z2[i] = u & 255;
352
+ u = u + (z3[i] & 255) | 0;
353
+ z3[i] = u & 255;
350
354
  u >>>= 8;
351
355
  }
352
356
  b -= 64;
@@ -354,30 +358,30 @@ var require_nacl_fast = __commonJS({
354
358
  mpos += 64;
355
359
  }
356
360
  if (b > 0) {
357
- crypto_core_salsa20(x, z2, k, sigma);
361
+ crypto_core_salsa20(x, z3, k, sigma);
358
362
  for (i = 0; i < b; i++) c[cpos + i] = m[mpos + i] ^ x[i];
359
363
  }
360
364
  return 0;
361
365
  }
362
366
  function crypto_stream_salsa20(c, cpos, b, n, k) {
363
- var z2 = new Uint8Array(16), x = new Uint8Array(64);
367
+ var z3 = new Uint8Array(16), x = new Uint8Array(64);
364
368
  var u, i;
365
- for (i = 0; i < 16; i++) z2[i] = 0;
366
- for (i = 0; i < 8; i++) z2[i] = n[i];
369
+ for (i = 0; i < 16; i++) z3[i] = 0;
370
+ for (i = 0; i < 8; i++) z3[i] = n[i];
367
371
  while (b >= 64) {
368
- crypto_core_salsa20(x, z2, k, sigma);
372
+ crypto_core_salsa20(x, z3, k, sigma);
369
373
  for (i = 0; i < 64; i++) c[cpos + i] = x[i];
370
374
  u = 1;
371
375
  for (i = 8; i < 16; i++) {
372
- u = u + (z2[i] & 255) | 0;
373
- z2[i] = u & 255;
376
+ u = u + (z3[i] & 255) | 0;
377
+ z3[i] = u & 255;
374
378
  u >>>= 8;
375
379
  }
376
380
  b -= 64;
377
381
  cpos += 64;
378
382
  }
379
383
  if (b > 0) {
380
- crypto_core_salsa20(x, z2, k, sigma);
384
+ crypto_core_salsa20(x, z3, k, sigma);
381
385
  for (i = 0; i < b; i++) c[cpos + i] = x[i];
382
386
  }
383
387
  return 0;
@@ -1257,12 +1261,12 @@ var require_nacl_fast = __commonJS({
1257
1261
  for (a = 0; a < 16; a++) o[a] = c[a];
1258
1262
  }
1259
1263
  function crypto_scalarmult(q, n, p) {
1260
- var z2 = new Uint8Array(32);
1264
+ var z3 = new Uint8Array(32);
1261
1265
  var x = new Float64Array(80), r, i;
1262
1266
  var a = gf(), b = gf(), c = gf(), d = gf(), e = gf(), f = gf();
1263
- for (i = 0; i < 31; i++) z2[i] = n[i];
1264
- z2[31] = n[31] & 127 | 64;
1265
- z2[0] &= 248;
1267
+ for (i = 0; i < 31; i++) z3[i] = n[i];
1268
+ z3[31] = n[31] & 127 | 64;
1269
+ z3[0] &= 248;
1266
1270
  unpack25519(x, p);
1267
1271
  for (i = 0; i < 16; i++) {
1268
1272
  b[i] = x[i];
@@ -1270,7 +1274,7 @@ var require_nacl_fast = __commonJS({
1270
1274
  }
1271
1275
  a[0] = d[0] = 1;
1272
1276
  for (i = 254; i >= 0; --i) {
1273
- r = z2[i >>> 3] >>> (i & 7) & 1;
1277
+ r = z3[i >>> 3] >>> (i & 7) & 1;
1274
1278
  sel25519(a, b, r);
1275
1279
  sel25519(c, d, r);
1276
1280
  A(e, a, c);
@@ -2271,6 +2275,12 @@ async function proxy() {
2271
2275
  }
2272
2276
  var INSTANCE_ID = randomUUID();
2273
2277
  var SESSION_ID = process.env.PAIGY_SESSION_ID ?? process.env.CLAUDE_CODE_SESSION_ID ?? INSTANCE_ID;
2278
+ function sessionId() {
2279
+ return SESSION_ID;
2280
+ }
2281
+ function isNetworkError(e) {
2282
+ return e instanceof Error && e.message.startsWith(NETWORK_MSG);
2283
+ }
2274
2284
  async function reach(url, init) {
2275
2285
  try {
2276
2286
  const headers = {
@@ -2283,73 +2293,1300 @@ async function reach(url, init) {
2283
2293
  throw new Error(`${NETWORK_MSG} (${e?.message ?? String(e)})`);
2284
2294
  }
2285
2295
  }
2286
- var TITLE_MAX = 90;
2287
- var CHUNKS_MAX = 8;
2288
- var CHUNK_MAX = 300;
2289
- var ASK_MAX = 1e4;
2290
- var OPTION_MAX = 80;
2291
- var NEEDS_MAX = 6;
2292
- var UNSPEAKABLE = /```/;
2293
- function normalizeSpeech(req) {
2294
- const flat = (s) => s.replace(/\s+/g, " ").trim();
2296
+ var ignoreOverride = /* @__PURE__ */ Symbol("Let zodToJsonSchema decide on which parser to use");
2297
+ var defaultOptions = {
2298
+ name: void 0,
2299
+ $refStrategy: "root",
2300
+ basePath: ["#"],
2301
+ effectStrategy: "input",
2302
+ pipeStrategy: "all",
2303
+ dateStrategy: "format:date-time",
2304
+ mapStrategy: "entries",
2305
+ removeAdditionalStrategy: "passthrough",
2306
+ allowedAdditionalProperties: true,
2307
+ rejectedAdditionalProperties: false,
2308
+ definitionPath: "definitions",
2309
+ target: "jsonSchema7",
2310
+ strictUnions: false,
2311
+ definitions: {},
2312
+ errorMessages: false,
2313
+ markdownDescription: false,
2314
+ patternStrategy: "escape",
2315
+ applyRegexFlags: false,
2316
+ emailStrategy: "format:email",
2317
+ base64Strategy: "contentEncoding:base64",
2318
+ nameStrategy: "ref",
2319
+ openAiAnyTypeName: "OpenAiAnyType"
2320
+ };
2321
+ var getDefaultOptions = (options) => typeof options === "string" ? {
2322
+ ...defaultOptions,
2323
+ name: options
2324
+ } : {
2325
+ ...defaultOptions,
2326
+ ...options
2327
+ };
2328
+ var getRefs = (options) => {
2329
+ const _options = getDefaultOptions(options);
2330
+ const currentPath = _options.name !== void 0 ? [..._options.basePath, _options.definitionPath, _options.name] : _options.basePath;
2331
+ return {
2332
+ ..._options,
2333
+ flags: { hasReferencedOpenAiAnyType: false },
2334
+ currentPath,
2335
+ propertyPath: void 0,
2336
+ seen: new Map(Object.entries(_options.definitions).map(([name, def]) => [
2337
+ def._def,
2338
+ {
2339
+ def: def._def,
2340
+ path: [..._options.basePath, _options.definitionPath, name],
2341
+ // Resolution of references will be forced even though seen, so it's ok that the schema is undefined here for now.
2342
+ jsonSchema: void 0
2343
+ }
2344
+ ]))
2345
+ };
2346
+ };
2347
+ function addErrorMessage(res, key, errorMessage, refs) {
2348
+ if (!refs?.errorMessages)
2349
+ return;
2350
+ if (errorMessage) {
2351
+ res.errorMessage = {
2352
+ ...res.errorMessage,
2353
+ [key]: errorMessage
2354
+ };
2355
+ }
2356
+ }
2357
+ function setResponseValueAndErrors(res, key, value, errorMessage, refs) {
2358
+ res[key] = value;
2359
+ addErrorMessage(res, key, errorMessage, refs);
2360
+ }
2361
+ var getRelativePath = (pathA, pathB) => {
2362
+ let i = 0;
2363
+ for (; i < pathA.length && i < pathB.length; i++) {
2364
+ if (pathA[i] !== pathB[i])
2365
+ break;
2366
+ }
2367
+ return [(pathA.length - i).toString(), ...pathB.slice(i)].join("/");
2368
+ };
2369
+ function parseAnyDef(refs) {
2370
+ if (refs.target !== "openAi") {
2371
+ return {};
2372
+ }
2373
+ const anyDefinitionPath = [
2374
+ ...refs.basePath,
2375
+ refs.definitionPath,
2376
+ refs.openAiAnyTypeName
2377
+ ];
2378
+ refs.flags.hasReferencedOpenAiAnyType = true;
2379
+ return {
2380
+ $ref: refs.$refStrategy === "relative" ? getRelativePath(anyDefinitionPath, refs.currentPath) : anyDefinitionPath.join("/")
2381
+ };
2382
+ }
2383
+ function parseArrayDef(def, refs) {
2384
+ const res = {
2385
+ type: "array"
2386
+ };
2387
+ if (def.type?._def && def.type?._def?.typeName !== ZodFirstPartyTypeKind.ZodAny) {
2388
+ res.items = parseDef(def.type._def, {
2389
+ ...refs,
2390
+ currentPath: [...refs.currentPath, "items"]
2391
+ });
2392
+ }
2393
+ if (def.minLength) {
2394
+ setResponseValueAndErrors(res, "minItems", def.minLength.value, def.minLength.message, refs);
2395
+ }
2396
+ if (def.maxLength) {
2397
+ setResponseValueAndErrors(res, "maxItems", def.maxLength.value, def.maxLength.message, refs);
2398
+ }
2399
+ if (def.exactLength) {
2400
+ setResponseValueAndErrors(res, "minItems", def.exactLength.value, def.exactLength.message, refs);
2401
+ setResponseValueAndErrors(res, "maxItems", def.exactLength.value, def.exactLength.message, refs);
2402
+ }
2403
+ return res;
2404
+ }
2405
+ function parseBigintDef(def, refs) {
2406
+ const res = {
2407
+ type: "integer",
2408
+ format: "int64"
2409
+ };
2410
+ if (!def.checks)
2411
+ return res;
2412
+ for (const check of def.checks) {
2413
+ switch (check.kind) {
2414
+ case "min":
2415
+ if (refs.target === "jsonSchema7") {
2416
+ if (check.inclusive) {
2417
+ setResponseValueAndErrors(res, "minimum", check.value, check.message, refs);
2418
+ } else {
2419
+ setResponseValueAndErrors(res, "exclusiveMinimum", check.value, check.message, refs);
2420
+ }
2421
+ } else {
2422
+ if (!check.inclusive) {
2423
+ res.exclusiveMinimum = true;
2424
+ }
2425
+ setResponseValueAndErrors(res, "minimum", check.value, check.message, refs);
2426
+ }
2427
+ break;
2428
+ case "max":
2429
+ if (refs.target === "jsonSchema7") {
2430
+ if (check.inclusive) {
2431
+ setResponseValueAndErrors(res, "maximum", check.value, check.message, refs);
2432
+ } else {
2433
+ setResponseValueAndErrors(res, "exclusiveMaximum", check.value, check.message, refs);
2434
+ }
2435
+ } else {
2436
+ if (!check.inclusive) {
2437
+ res.exclusiveMaximum = true;
2438
+ }
2439
+ setResponseValueAndErrors(res, "maximum", check.value, check.message, refs);
2440
+ }
2441
+ break;
2442
+ case "multipleOf":
2443
+ setResponseValueAndErrors(res, "multipleOf", check.value, check.message, refs);
2444
+ break;
2445
+ }
2446
+ }
2447
+ return res;
2448
+ }
2449
+ function parseBooleanDef() {
2450
+ return {
2451
+ type: "boolean"
2452
+ };
2453
+ }
2454
+ function parseBrandedDef(_def, refs) {
2455
+ return parseDef(_def.type._def, refs);
2456
+ }
2457
+ var parseCatchDef = (def, refs) => {
2458
+ return parseDef(def.innerType._def, refs);
2459
+ };
2460
+ function parseDateDef(def, refs, overrideDateStrategy) {
2461
+ const strategy = overrideDateStrategy ?? refs.dateStrategy;
2462
+ if (Array.isArray(strategy)) {
2463
+ return {
2464
+ anyOf: strategy.map((item, i) => parseDateDef(def, refs, item))
2465
+ };
2466
+ }
2467
+ switch (strategy) {
2468
+ case "string":
2469
+ case "format:date-time":
2470
+ return {
2471
+ type: "string",
2472
+ format: "date-time"
2473
+ };
2474
+ case "format:date":
2475
+ return {
2476
+ type: "string",
2477
+ format: "date"
2478
+ };
2479
+ case "integer":
2480
+ return integerDateParser(def, refs);
2481
+ }
2482
+ }
2483
+ var integerDateParser = (def, refs) => {
2484
+ const res = {
2485
+ type: "integer",
2486
+ format: "unix-time"
2487
+ };
2488
+ if (refs.target === "openApi3") {
2489
+ return res;
2490
+ }
2491
+ for (const check of def.checks) {
2492
+ switch (check.kind) {
2493
+ case "min":
2494
+ setResponseValueAndErrors(
2495
+ res,
2496
+ "minimum",
2497
+ check.value,
2498
+ // This is in milliseconds
2499
+ check.message,
2500
+ refs
2501
+ );
2502
+ break;
2503
+ case "max":
2504
+ setResponseValueAndErrors(
2505
+ res,
2506
+ "maximum",
2507
+ check.value,
2508
+ // This is in milliseconds
2509
+ check.message,
2510
+ refs
2511
+ );
2512
+ break;
2513
+ }
2514
+ }
2515
+ return res;
2516
+ };
2517
+ function parseDefaultDef(_def, refs) {
2518
+ return {
2519
+ ...parseDef(_def.innerType._def, refs),
2520
+ default: _def.defaultValue()
2521
+ };
2522
+ }
2523
+ function parseEffectsDef(_def, refs) {
2524
+ return refs.effectStrategy === "input" ? parseDef(_def.schema._def, refs) : parseAnyDef(refs);
2525
+ }
2526
+ function parseEnumDef(def) {
2527
+ return {
2528
+ type: "string",
2529
+ enum: Array.from(def.values)
2530
+ };
2531
+ }
2532
+ var isJsonSchema7AllOfType = (type) => {
2533
+ if ("type" in type && type.type === "string")
2534
+ return false;
2535
+ return "allOf" in type;
2536
+ };
2537
+ function parseIntersectionDef(def, refs) {
2538
+ const allOf = [
2539
+ parseDef(def.left._def, {
2540
+ ...refs,
2541
+ currentPath: [...refs.currentPath, "allOf", "0"]
2542
+ }),
2543
+ parseDef(def.right._def, {
2544
+ ...refs,
2545
+ currentPath: [...refs.currentPath, "allOf", "1"]
2546
+ })
2547
+ ].filter((x) => !!x);
2548
+ let unevaluatedProperties = refs.target === "jsonSchema2019-09" ? { unevaluatedProperties: false } : void 0;
2549
+ const mergedAllOf = [];
2550
+ allOf.forEach((schema) => {
2551
+ if (isJsonSchema7AllOfType(schema)) {
2552
+ mergedAllOf.push(...schema.allOf);
2553
+ if (schema.unevaluatedProperties === void 0) {
2554
+ unevaluatedProperties = void 0;
2555
+ }
2556
+ } else {
2557
+ let nestedSchema = schema;
2558
+ if ("additionalProperties" in schema && schema.additionalProperties === false) {
2559
+ const { additionalProperties, ...rest } = schema;
2560
+ nestedSchema = rest;
2561
+ } else {
2562
+ unevaluatedProperties = void 0;
2563
+ }
2564
+ mergedAllOf.push(nestedSchema);
2565
+ }
2566
+ });
2567
+ return mergedAllOf.length ? {
2568
+ allOf: mergedAllOf,
2569
+ ...unevaluatedProperties
2570
+ } : void 0;
2571
+ }
2572
+ function parseLiteralDef(def, refs) {
2573
+ const parsedType = typeof def.value;
2574
+ if (parsedType !== "bigint" && parsedType !== "number" && parsedType !== "boolean" && parsedType !== "string") {
2575
+ return {
2576
+ type: Array.isArray(def.value) ? "array" : "object"
2577
+ };
2578
+ }
2579
+ if (refs.target === "openApi3") {
2580
+ return {
2581
+ type: parsedType === "bigint" ? "integer" : parsedType,
2582
+ enum: [def.value]
2583
+ };
2584
+ }
2585
+ return {
2586
+ type: parsedType === "bigint" ? "integer" : parsedType,
2587
+ const: def.value
2588
+ };
2589
+ }
2590
+ var emojiRegex = void 0;
2591
+ var zodPatterns = {
2592
+ /**
2593
+ * `c` was changed to `[cC]` to replicate /i flag
2594
+ */
2595
+ cuid: /^[cC][^\s-]{8,}$/,
2596
+ cuid2: /^[0-9a-z]+$/,
2597
+ ulid: /^[0-9A-HJKMNP-TV-Z]{26}$/,
2598
+ /**
2599
+ * `a-z` was added to replicate /i flag
2600
+ */
2601
+ email: /^(?!\.)(?!.*\.\.)([a-zA-Z0-9_'+\-\.]*)[a-zA-Z0-9_+-]@([a-zA-Z0-9][a-zA-Z0-9\-]*\.)+[a-zA-Z]{2,}$/,
2602
+ /**
2603
+ * Constructed a valid Unicode RegExp
2604
+ *
2605
+ * Lazily instantiate since this type of regex isn't supported
2606
+ * in all envs (e.g. React Native).
2607
+ *
2608
+ * See:
2609
+ * https://github.com/colinhacks/zod/issues/2433
2610
+ * Fix in Zod:
2611
+ * https://github.com/colinhacks/zod/commit/9340fd51e48576a75adc919bff65dbc4a5d4c99b
2612
+ */
2613
+ emoji: () => {
2614
+ if (emojiRegex === void 0) {
2615
+ emojiRegex = RegExp("^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$", "u");
2616
+ }
2617
+ return emojiRegex;
2618
+ },
2619
+ /**
2620
+ * Unused
2621
+ */
2622
+ uuid: /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/,
2623
+ /**
2624
+ * Unused
2625
+ */
2626
+ ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,
2627
+ ipv4Cidr: /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/,
2628
+ /**
2629
+ * Unused
2630
+ */
2631
+ ipv6: /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/,
2632
+ ipv6Cidr: /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,
2633
+ base64: /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/,
2634
+ base64url: /^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/,
2635
+ nanoid: /^[a-zA-Z0-9_-]{21}$/,
2636
+ jwt: /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/
2637
+ };
2638
+ function parseStringDef(def, refs) {
2639
+ const res = {
2640
+ type: "string"
2641
+ };
2642
+ if (def.checks) {
2643
+ for (const check of def.checks) {
2644
+ switch (check.kind) {
2645
+ case "min":
2646
+ setResponseValueAndErrors(res, "minLength", typeof res.minLength === "number" ? Math.max(res.minLength, check.value) : check.value, check.message, refs);
2647
+ break;
2648
+ case "max":
2649
+ setResponseValueAndErrors(res, "maxLength", typeof res.maxLength === "number" ? Math.min(res.maxLength, check.value) : check.value, check.message, refs);
2650
+ break;
2651
+ case "email":
2652
+ switch (refs.emailStrategy) {
2653
+ case "format:email":
2654
+ addFormat(res, "email", check.message, refs);
2655
+ break;
2656
+ case "format:idn-email":
2657
+ addFormat(res, "idn-email", check.message, refs);
2658
+ break;
2659
+ case "pattern:zod":
2660
+ addPattern(res, zodPatterns.email, check.message, refs);
2661
+ break;
2662
+ }
2663
+ break;
2664
+ case "url":
2665
+ addFormat(res, "uri", check.message, refs);
2666
+ break;
2667
+ case "uuid":
2668
+ addFormat(res, "uuid", check.message, refs);
2669
+ break;
2670
+ case "regex":
2671
+ addPattern(res, check.regex, check.message, refs);
2672
+ break;
2673
+ case "cuid":
2674
+ addPattern(res, zodPatterns.cuid, check.message, refs);
2675
+ break;
2676
+ case "cuid2":
2677
+ addPattern(res, zodPatterns.cuid2, check.message, refs);
2678
+ break;
2679
+ case "startsWith":
2680
+ addPattern(res, RegExp(`^${escapeLiteralCheckValue(check.value, refs)}`), check.message, refs);
2681
+ break;
2682
+ case "endsWith":
2683
+ addPattern(res, RegExp(`${escapeLiteralCheckValue(check.value, refs)}$`), check.message, refs);
2684
+ break;
2685
+ case "datetime":
2686
+ addFormat(res, "date-time", check.message, refs);
2687
+ break;
2688
+ case "date":
2689
+ addFormat(res, "date", check.message, refs);
2690
+ break;
2691
+ case "time":
2692
+ addFormat(res, "time", check.message, refs);
2693
+ break;
2694
+ case "duration":
2695
+ addFormat(res, "duration", check.message, refs);
2696
+ break;
2697
+ case "length":
2698
+ setResponseValueAndErrors(res, "minLength", typeof res.minLength === "number" ? Math.max(res.minLength, check.value) : check.value, check.message, refs);
2699
+ setResponseValueAndErrors(res, "maxLength", typeof res.maxLength === "number" ? Math.min(res.maxLength, check.value) : check.value, check.message, refs);
2700
+ break;
2701
+ case "includes": {
2702
+ addPattern(res, RegExp(escapeLiteralCheckValue(check.value, refs)), check.message, refs);
2703
+ break;
2704
+ }
2705
+ case "ip": {
2706
+ if (check.version !== "v6") {
2707
+ addFormat(res, "ipv4", check.message, refs);
2708
+ }
2709
+ if (check.version !== "v4") {
2710
+ addFormat(res, "ipv6", check.message, refs);
2711
+ }
2712
+ break;
2713
+ }
2714
+ case "base64url":
2715
+ addPattern(res, zodPatterns.base64url, check.message, refs);
2716
+ break;
2717
+ case "jwt":
2718
+ addPattern(res, zodPatterns.jwt, check.message, refs);
2719
+ break;
2720
+ case "cidr": {
2721
+ if (check.version !== "v6") {
2722
+ addPattern(res, zodPatterns.ipv4Cidr, check.message, refs);
2723
+ }
2724
+ if (check.version !== "v4") {
2725
+ addPattern(res, zodPatterns.ipv6Cidr, check.message, refs);
2726
+ }
2727
+ break;
2728
+ }
2729
+ case "emoji":
2730
+ addPattern(res, zodPatterns.emoji(), check.message, refs);
2731
+ break;
2732
+ case "ulid": {
2733
+ addPattern(res, zodPatterns.ulid, check.message, refs);
2734
+ break;
2735
+ }
2736
+ case "base64": {
2737
+ switch (refs.base64Strategy) {
2738
+ case "format:binary": {
2739
+ addFormat(res, "binary", check.message, refs);
2740
+ break;
2741
+ }
2742
+ case "contentEncoding:base64": {
2743
+ setResponseValueAndErrors(res, "contentEncoding", "base64", check.message, refs);
2744
+ break;
2745
+ }
2746
+ case "pattern:zod": {
2747
+ addPattern(res, zodPatterns.base64, check.message, refs);
2748
+ break;
2749
+ }
2750
+ }
2751
+ break;
2752
+ }
2753
+ case "nanoid": {
2754
+ addPattern(res, zodPatterns.nanoid, check.message, refs);
2755
+ }
2756
+ case "toLowerCase":
2757
+ case "toUpperCase":
2758
+ case "trim":
2759
+ break;
2760
+ default:
2761
+ /* @__PURE__ */ ((_) => {
2762
+ })(check);
2763
+ }
2764
+ }
2765
+ }
2766
+ return res;
2767
+ }
2768
+ function escapeLiteralCheckValue(literal, refs) {
2769
+ return refs.patternStrategy === "escape" ? escapeNonAlphaNumeric(literal) : literal;
2770
+ }
2771
+ var ALPHA_NUMERIC = new Set("ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789");
2772
+ function escapeNonAlphaNumeric(source) {
2773
+ let result = "";
2774
+ for (let i = 0; i < source.length; i++) {
2775
+ if (!ALPHA_NUMERIC.has(source[i])) {
2776
+ result += "\\";
2777
+ }
2778
+ result += source[i];
2779
+ }
2780
+ return result;
2781
+ }
2782
+ function addFormat(schema, value, message, refs) {
2783
+ if (schema.format || schema.anyOf?.some((x) => x.format)) {
2784
+ if (!schema.anyOf) {
2785
+ schema.anyOf = [];
2786
+ }
2787
+ if (schema.format) {
2788
+ schema.anyOf.push({
2789
+ format: schema.format,
2790
+ ...schema.errorMessage && refs.errorMessages && {
2791
+ errorMessage: { format: schema.errorMessage.format }
2792
+ }
2793
+ });
2794
+ delete schema.format;
2795
+ if (schema.errorMessage) {
2796
+ delete schema.errorMessage.format;
2797
+ if (Object.keys(schema.errorMessage).length === 0) {
2798
+ delete schema.errorMessage;
2799
+ }
2800
+ }
2801
+ }
2802
+ schema.anyOf.push({
2803
+ format: value,
2804
+ ...message && refs.errorMessages && { errorMessage: { format: message } }
2805
+ });
2806
+ } else {
2807
+ setResponseValueAndErrors(schema, "format", value, message, refs);
2808
+ }
2809
+ }
2810
+ function addPattern(schema, regex, message, refs) {
2811
+ if (schema.pattern || schema.allOf?.some((x) => x.pattern)) {
2812
+ if (!schema.allOf) {
2813
+ schema.allOf = [];
2814
+ }
2815
+ if (schema.pattern) {
2816
+ schema.allOf.push({
2817
+ pattern: schema.pattern,
2818
+ ...schema.errorMessage && refs.errorMessages && {
2819
+ errorMessage: { pattern: schema.errorMessage.pattern }
2820
+ }
2821
+ });
2822
+ delete schema.pattern;
2823
+ if (schema.errorMessage) {
2824
+ delete schema.errorMessage.pattern;
2825
+ if (Object.keys(schema.errorMessage).length === 0) {
2826
+ delete schema.errorMessage;
2827
+ }
2828
+ }
2829
+ }
2830
+ schema.allOf.push({
2831
+ pattern: stringifyRegExpWithFlags(regex, refs),
2832
+ ...message && refs.errorMessages && { errorMessage: { pattern: message } }
2833
+ });
2834
+ } else {
2835
+ setResponseValueAndErrors(schema, "pattern", stringifyRegExpWithFlags(regex, refs), message, refs);
2836
+ }
2837
+ }
2838
+ function stringifyRegExpWithFlags(regex, refs) {
2839
+ if (!refs.applyRegexFlags || !regex.flags) {
2840
+ return regex.source;
2841
+ }
2842
+ const flags = {
2843
+ i: regex.flags.includes("i"),
2844
+ m: regex.flags.includes("m"),
2845
+ s: regex.flags.includes("s")
2846
+ // `.` matches newlines
2847
+ };
2848
+ const source = flags.i ? regex.source.toLowerCase() : regex.source;
2849
+ let pattern = "";
2850
+ let isEscaped = false;
2851
+ let inCharGroup = false;
2852
+ let inCharRange = false;
2853
+ for (let i = 0; i < source.length; i++) {
2854
+ if (isEscaped) {
2855
+ pattern += source[i];
2856
+ isEscaped = false;
2857
+ continue;
2858
+ }
2859
+ if (flags.i) {
2860
+ if (inCharGroup) {
2861
+ if (source[i].match(/[a-z]/)) {
2862
+ if (inCharRange) {
2863
+ pattern += source[i];
2864
+ pattern += `${source[i - 2]}-${source[i]}`.toUpperCase();
2865
+ inCharRange = false;
2866
+ } else if (source[i + 1] === "-" && source[i + 2]?.match(/[a-z]/)) {
2867
+ pattern += source[i];
2868
+ inCharRange = true;
2869
+ } else {
2870
+ pattern += `${source[i]}${source[i].toUpperCase()}`;
2871
+ }
2872
+ continue;
2873
+ }
2874
+ } else if (source[i].match(/[a-z]/)) {
2875
+ pattern += `[${source[i]}${source[i].toUpperCase()}]`;
2876
+ continue;
2877
+ }
2878
+ }
2879
+ if (flags.m) {
2880
+ if (source[i] === "^") {
2881
+ pattern += `(^|(?<=[\r
2882
+ ]))`;
2883
+ continue;
2884
+ } else if (source[i] === "$") {
2885
+ pattern += `($|(?=[\r
2886
+ ]))`;
2887
+ continue;
2888
+ }
2889
+ }
2890
+ if (flags.s && source[i] === ".") {
2891
+ pattern += inCharGroup ? `${source[i]}\r
2892
+ ` : `[${source[i]}\r
2893
+ ]`;
2894
+ continue;
2895
+ }
2896
+ pattern += source[i];
2897
+ if (source[i] === "\\") {
2898
+ isEscaped = true;
2899
+ } else if (inCharGroup && source[i] === "]") {
2900
+ inCharGroup = false;
2901
+ } else if (!inCharGroup && source[i] === "[") {
2902
+ inCharGroup = true;
2903
+ }
2904
+ }
2905
+ try {
2906
+ new RegExp(pattern);
2907
+ } catch {
2908
+ console.warn(`Could not convert regex pattern at ${refs.currentPath.join("/")} to a flag-independent form! Falling back to the flag-ignorant source`);
2909
+ return regex.source;
2910
+ }
2911
+ return pattern;
2912
+ }
2913
+ function parseRecordDef(def, refs) {
2914
+ if (refs.target === "openAi") {
2915
+ console.warn("Warning: OpenAI may not support records in schemas! Try an array of key-value pairs instead.");
2916
+ }
2917
+ if (refs.target === "openApi3" && def.keyType?._def.typeName === ZodFirstPartyTypeKind2.ZodEnum) {
2918
+ return {
2919
+ type: "object",
2920
+ required: def.keyType._def.values,
2921
+ properties: def.keyType._def.values.reduce((acc, key) => ({
2922
+ ...acc,
2923
+ [key]: parseDef(def.valueType._def, {
2924
+ ...refs,
2925
+ currentPath: [...refs.currentPath, "properties", key]
2926
+ }) ?? parseAnyDef(refs)
2927
+ }), {}),
2928
+ additionalProperties: refs.rejectedAdditionalProperties
2929
+ };
2930
+ }
2931
+ const schema = {
2932
+ type: "object",
2933
+ additionalProperties: parseDef(def.valueType._def, {
2934
+ ...refs,
2935
+ currentPath: [...refs.currentPath, "additionalProperties"]
2936
+ }) ?? refs.allowedAdditionalProperties
2937
+ };
2938
+ if (refs.target === "openApi3") {
2939
+ return schema;
2940
+ }
2941
+ if (def.keyType?._def.typeName === ZodFirstPartyTypeKind2.ZodString && def.keyType._def.checks?.length) {
2942
+ const { type, ...keyType } = parseStringDef(def.keyType._def, refs);
2943
+ return {
2944
+ ...schema,
2945
+ propertyNames: keyType
2946
+ };
2947
+ } else if (def.keyType?._def.typeName === ZodFirstPartyTypeKind2.ZodEnum) {
2948
+ return {
2949
+ ...schema,
2950
+ propertyNames: {
2951
+ enum: def.keyType._def.values
2952
+ }
2953
+ };
2954
+ } else if (def.keyType?._def.typeName === ZodFirstPartyTypeKind2.ZodBranded && def.keyType._def.type._def.typeName === ZodFirstPartyTypeKind2.ZodString && def.keyType._def.type._def.checks?.length) {
2955
+ const { type, ...keyType } = parseBrandedDef(def.keyType._def, refs);
2956
+ return {
2957
+ ...schema,
2958
+ propertyNames: keyType
2959
+ };
2960
+ }
2961
+ return schema;
2962
+ }
2963
+ function parseMapDef(def, refs) {
2964
+ if (refs.mapStrategy === "record") {
2965
+ return parseRecordDef(def, refs);
2966
+ }
2967
+ const keys = parseDef(def.keyType._def, {
2968
+ ...refs,
2969
+ currentPath: [...refs.currentPath, "items", "items", "0"]
2970
+ }) || parseAnyDef(refs);
2971
+ const values = parseDef(def.valueType._def, {
2972
+ ...refs,
2973
+ currentPath: [...refs.currentPath, "items", "items", "1"]
2974
+ }) || parseAnyDef(refs);
2295
2975
  return {
2296
- ...req,
2297
- ...req.ask !== void 0 ? { ask: flat(req.ask) } : {},
2298
- ...req.context ? {
2299
- context: {
2300
- ...req.context,
2301
- title: flat(req.context.title),
2302
- description: req.context.description.map(flat)
2976
+ type: "array",
2977
+ maxItems: 125,
2978
+ items: {
2979
+ type: "array",
2980
+ items: [keys, values],
2981
+ minItems: 2,
2982
+ maxItems: 2
2983
+ }
2984
+ };
2985
+ }
2986
+ function parseNativeEnumDef(def) {
2987
+ const object = def.values;
2988
+ const actualKeys = Object.keys(def.values).filter((key) => {
2989
+ return typeof object[object[key]] !== "number";
2990
+ });
2991
+ const actualValues = actualKeys.map((key) => object[key]);
2992
+ const parsedTypes = Array.from(new Set(actualValues.map((values) => typeof values)));
2993
+ return {
2994
+ type: parsedTypes.length === 1 ? parsedTypes[0] === "string" ? "string" : "number" : ["string", "number"],
2995
+ enum: actualValues
2996
+ };
2997
+ }
2998
+ function parseNeverDef(refs) {
2999
+ return refs.target === "openAi" ? void 0 : {
3000
+ not: parseAnyDef({
3001
+ ...refs,
3002
+ currentPath: [...refs.currentPath, "not"]
3003
+ })
3004
+ };
3005
+ }
3006
+ function parseNullDef(refs) {
3007
+ return refs.target === "openApi3" ? {
3008
+ enum: ["null"],
3009
+ nullable: true
3010
+ } : {
3011
+ type: "null"
3012
+ };
3013
+ }
3014
+ var primitiveMappings = {
3015
+ ZodString: "string",
3016
+ ZodNumber: "number",
3017
+ ZodBigInt: "integer",
3018
+ ZodBoolean: "boolean",
3019
+ ZodNull: "null"
3020
+ };
3021
+ function parseUnionDef(def, refs) {
3022
+ if (refs.target === "openApi3")
3023
+ return asAnyOf(def, refs);
3024
+ const options = def.options instanceof Map ? Array.from(def.options.values()) : def.options;
3025
+ if (options.every((x) => x._def.typeName in primitiveMappings && (!x._def.checks || !x._def.checks.length))) {
3026
+ const types = options.reduce((types2, x) => {
3027
+ const type = primitiveMappings[x._def.typeName];
3028
+ return type && !types2.includes(type) ? [...types2, type] : types2;
3029
+ }, []);
3030
+ return {
3031
+ type: types.length > 1 ? types : types[0]
3032
+ };
3033
+ } else if (options.every((x) => x._def.typeName === "ZodLiteral" && !x.description)) {
3034
+ const types = options.reduce((acc, x) => {
3035
+ const type = typeof x._def.value;
3036
+ switch (type) {
3037
+ case "string":
3038
+ case "number":
3039
+ case "boolean":
3040
+ return [...acc, type];
3041
+ case "bigint":
3042
+ return [...acc, "integer"];
3043
+ case "object":
3044
+ if (x._def.value === null)
3045
+ return [...acc, "null"];
3046
+ case "symbol":
3047
+ case "undefined":
3048
+ case "function":
3049
+ default:
3050
+ return acc;
3051
+ }
3052
+ }, []);
3053
+ if (types.length === options.length) {
3054
+ const uniqueTypes = types.filter((x, i, a) => a.indexOf(x) === i);
3055
+ return {
3056
+ type: uniqueTypes.length > 1 ? uniqueTypes : uniqueTypes[0],
3057
+ enum: options.reduce((acc, x) => {
3058
+ return acc.includes(x._def.value) ? acc : [...acc, x._def.value];
3059
+ }, [])
3060
+ };
3061
+ }
3062
+ } else if (options.every((x) => x._def.typeName === "ZodEnum")) {
3063
+ return {
3064
+ type: "string",
3065
+ enum: options.reduce((acc, x) => [
3066
+ ...acc,
3067
+ ...x._def.values.filter((x2) => !acc.includes(x2))
3068
+ ], [])
3069
+ };
3070
+ }
3071
+ return asAnyOf(def, refs);
3072
+ }
3073
+ var asAnyOf = (def, refs) => {
3074
+ const anyOf = (def.options instanceof Map ? Array.from(def.options.values()) : def.options).map((x, i) => parseDef(x._def, {
3075
+ ...refs,
3076
+ currentPath: [...refs.currentPath, "anyOf", `${i}`]
3077
+ })).filter((x) => !!x && (!refs.strictUnions || typeof x === "object" && Object.keys(x).length > 0));
3078
+ return anyOf.length ? { anyOf } : void 0;
3079
+ };
3080
+ function parseNullableDef(def, refs) {
3081
+ if (["ZodString", "ZodNumber", "ZodBigInt", "ZodBoolean", "ZodNull"].includes(def.innerType._def.typeName) && (!def.innerType._def.checks || !def.innerType._def.checks.length)) {
3082
+ if (refs.target === "openApi3") {
3083
+ return {
3084
+ type: primitiveMappings[def.innerType._def.typeName],
3085
+ nullable: true
3086
+ };
3087
+ }
3088
+ return {
3089
+ type: [
3090
+ primitiveMappings[def.innerType._def.typeName],
3091
+ "null"
3092
+ ]
3093
+ };
3094
+ }
3095
+ if (refs.target === "openApi3") {
3096
+ const base2 = parseDef(def.innerType._def, {
3097
+ ...refs,
3098
+ currentPath: [...refs.currentPath]
3099
+ });
3100
+ if (base2 && "$ref" in base2)
3101
+ return { allOf: [base2], nullable: true };
3102
+ return base2 && { ...base2, nullable: true };
3103
+ }
3104
+ const base = parseDef(def.innerType._def, {
3105
+ ...refs,
3106
+ currentPath: [...refs.currentPath, "anyOf", "0"]
3107
+ });
3108
+ return base && { anyOf: [base, { type: "null" }] };
3109
+ }
3110
+ function parseNumberDef(def, refs) {
3111
+ const res = {
3112
+ type: "number"
3113
+ };
3114
+ if (!def.checks)
3115
+ return res;
3116
+ for (const check of def.checks) {
3117
+ switch (check.kind) {
3118
+ case "int":
3119
+ res.type = "integer";
3120
+ addErrorMessage(res, "type", check.message, refs);
3121
+ break;
3122
+ case "min":
3123
+ if (refs.target === "jsonSchema7") {
3124
+ if (check.inclusive) {
3125
+ setResponseValueAndErrors(res, "minimum", check.value, check.message, refs);
3126
+ } else {
3127
+ setResponseValueAndErrors(res, "exclusiveMinimum", check.value, check.message, refs);
3128
+ }
3129
+ } else {
3130
+ if (!check.inclusive) {
3131
+ res.exclusiveMinimum = true;
3132
+ }
3133
+ setResponseValueAndErrors(res, "minimum", check.value, check.message, refs);
3134
+ }
3135
+ break;
3136
+ case "max":
3137
+ if (refs.target === "jsonSchema7") {
3138
+ if (check.inclusive) {
3139
+ setResponseValueAndErrors(res, "maximum", check.value, check.message, refs);
3140
+ } else {
3141
+ setResponseValueAndErrors(res, "exclusiveMaximum", check.value, check.message, refs);
3142
+ }
3143
+ } else {
3144
+ if (!check.inclusive) {
3145
+ res.exclusiveMaximum = true;
3146
+ }
3147
+ setResponseValueAndErrors(res, "maximum", check.value, check.message, refs);
3148
+ }
3149
+ break;
3150
+ case "multipleOf":
3151
+ setResponseValueAndErrors(res, "multipleOf", check.value, check.message, refs);
3152
+ break;
3153
+ }
3154
+ }
3155
+ return res;
3156
+ }
3157
+ function parseObjectDef(def, refs) {
3158
+ const forceOptionalIntoNullable = refs.target === "openAi";
3159
+ const result = {
3160
+ type: "object",
3161
+ properties: {}
3162
+ };
3163
+ const required = [];
3164
+ const shape = def.shape();
3165
+ for (const propName in shape) {
3166
+ let propDef = shape[propName];
3167
+ if (propDef === void 0 || propDef._def === void 0) {
3168
+ continue;
3169
+ }
3170
+ let propOptional = safeIsOptional(propDef);
3171
+ if (propOptional && forceOptionalIntoNullable) {
3172
+ if (propDef._def.typeName === "ZodOptional") {
3173
+ propDef = propDef._def.innerType;
3174
+ }
3175
+ if (!propDef.isNullable()) {
3176
+ propDef = propDef.nullable();
2303
3177
  }
2304
- } : {}
3178
+ propOptional = false;
3179
+ }
3180
+ const parsedDef = parseDef(propDef._def, {
3181
+ ...refs,
3182
+ currentPath: [...refs.currentPath, "properties", propName],
3183
+ propertyPath: [...refs.currentPath, "properties", propName]
3184
+ });
3185
+ if (parsedDef === void 0) {
3186
+ continue;
3187
+ }
3188
+ result.properties[propName] = parsedDef;
3189
+ if (!propOptional) {
3190
+ required.push(propName);
3191
+ }
3192
+ }
3193
+ if (required.length) {
3194
+ result.required = required;
3195
+ }
3196
+ const additionalProperties = decideAdditionalProperties(def, refs);
3197
+ if (additionalProperties !== void 0) {
3198
+ result.additionalProperties = additionalProperties;
3199
+ }
3200
+ return result;
3201
+ }
3202
+ function decideAdditionalProperties(def, refs) {
3203
+ if (def.catchall._def.typeName !== "ZodNever") {
3204
+ return parseDef(def.catchall._def, {
3205
+ ...refs,
3206
+ currentPath: [...refs.currentPath, "additionalProperties"]
3207
+ });
3208
+ }
3209
+ switch (def.unknownKeys) {
3210
+ case "passthrough":
3211
+ return refs.allowedAdditionalProperties;
3212
+ case "strict":
3213
+ return refs.rejectedAdditionalProperties;
3214
+ case "strip":
3215
+ return refs.removeAdditionalStrategy === "strict" ? refs.allowedAdditionalProperties : refs.rejectedAdditionalProperties;
3216
+ }
3217
+ }
3218
+ function safeIsOptional(schema) {
3219
+ try {
3220
+ return schema.isOptional();
3221
+ } catch {
3222
+ return true;
3223
+ }
3224
+ }
3225
+ var parseOptionalDef = (def, refs) => {
3226
+ if (refs.currentPath.toString() === refs.propertyPath?.toString()) {
3227
+ return parseDef(def.innerType._def, refs);
3228
+ }
3229
+ const innerSchema = parseDef(def.innerType._def, {
3230
+ ...refs,
3231
+ currentPath: [...refs.currentPath, "anyOf", "1"]
3232
+ });
3233
+ return innerSchema ? {
3234
+ anyOf: [
3235
+ {
3236
+ not: parseAnyDef(refs)
3237
+ },
3238
+ innerSchema
3239
+ ]
3240
+ } : parseAnyDef(refs);
3241
+ };
3242
+ var parsePipelineDef = (def, refs) => {
3243
+ if (refs.pipeStrategy === "input") {
3244
+ return parseDef(def.in._def, refs);
3245
+ } else if (refs.pipeStrategy === "output") {
3246
+ return parseDef(def.out._def, refs);
3247
+ }
3248
+ const a = parseDef(def.in._def, {
3249
+ ...refs,
3250
+ currentPath: [...refs.currentPath, "allOf", "0"]
3251
+ });
3252
+ const b = parseDef(def.out._def, {
3253
+ ...refs,
3254
+ currentPath: [...refs.currentPath, "allOf", a ? "1" : "0"]
3255
+ });
3256
+ return {
3257
+ allOf: [a, b].filter((x) => x !== void 0)
3258
+ };
3259
+ };
3260
+ function parsePromiseDef(def, refs) {
3261
+ return parseDef(def.type._def, refs);
3262
+ }
3263
+ function parseSetDef(def, refs) {
3264
+ const items = parseDef(def.valueType._def, {
3265
+ ...refs,
3266
+ currentPath: [...refs.currentPath, "items"]
3267
+ });
3268
+ const schema = {
3269
+ type: "array",
3270
+ uniqueItems: true,
3271
+ items
3272
+ };
3273
+ if (def.minSize) {
3274
+ setResponseValueAndErrors(schema, "minItems", def.minSize.value, def.minSize.message, refs);
3275
+ }
3276
+ if (def.maxSize) {
3277
+ setResponseValueAndErrors(schema, "maxItems", def.maxSize.value, def.maxSize.message, refs);
3278
+ }
3279
+ return schema;
3280
+ }
3281
+ function parseTupleDef(def, refs) {
3282
+ if (def.rest) {
3283
+ return {
3284
+ type: "array",
3285
+ minItems: def.items.length,
3286
+ items: def.items.map((x, i) => parseDef(x._def, {
3287
+ ...refs,
3288
+ currentPath: [...refs.currentPath, "items", `${i}`]
3289
+ })).reduce((acc, x) => x === void 0 ? acc : [...acc, x], []),
3290
+ additionalItems: parseDef(def.rest._def, {
3291
+ ...refs,
3292
+ currentPath: [...refs.currentPath, "additionalItems"]
3293
+ })
3294
+ };
3295
+ } else {
3296
+ return {
3297
+ type: "array",
3298
+ minItems: def.items.length,
3299
+ maxItems: def.items.length,
3300
+ items: def.items.map((x, i) => parseDef(x._def, {
3301
+ ...refs,
3302
+ currentPath: [...refs.currentPath, "items", `${i}`]
3303
+ })).reduce((acc, x) => x === void 0 ? acc : [...acc, x], [])
3304
+ };
3305
+ }
3306
+ }
3307
+ function parseUndefinedDef(refs) {
3308
+ return {
3309
+ not: parseAnyDef(refs)
2305
3310
  };
2306
3311
  }
2307
- function lintNotify(req) {
2308
- const problems = [];
2309
- if (req.ask !== void 0) {
2310
- if (req.ask.length > ASK_MAX)
2311
- problems.push(`ask is ${req.ask.length} chars \u2014 state the need and why it matters now in \u2264${ASK_MAX}; move detail into a smaller follow-up`);
2312
- if (UNSPEAKABLE.test(req.ask))
2313
- problems.push("ask contains a code fence \u2014 write it as plain prose (it may be read aloud on a call)");
2314
- for (const n of req.needs ?? []) {
2315
- if (n.length > OPTION_MAX) problems.push(`need "${n.slice(0, 40)}\u2026" is too long \u2014 each need is a short phrase (\u2264${OPTION_MAX} chars)`);
3312
+ function parseUnknownDef(refs) {
3313
+ return parseAnyDef(refs);
3314
+ }
3315
+ var parseReadonlyDef = (def, refs) => {
3316
+ return parseDef(def.innerType._def, refs);
3317
+ };
3318
+ var selectParser = (def, typeName, refs) => {
3319
+ switch (typeName) {
3320
+ case ZodFirstPartyTypeKind3.ZodString:
3321
+ return parseStringDef(def, refs);
3322
+ case ZodFirstPartyTypeKind3.ZodNumber:
3323
+ return parseNumberDef(def, refs);
3324
+ case ZodFirstPartyTypeKind3.ZodObject:
3325
+ return parseObjectDef(def, refs);
3326
+ case ZodFirstPartyTypeKind3.ZodBigInt:
3327
+ return parseBigintDef(def, refs);
3328
+ case ZodFirstPartyTypeKind3.ZodBoolean:
3329
+ return parseBooleanDef();
3330
+ case ZodFirstPartyTypeKind3.ZodDate:
3331
+ return parseDateDef(def, refs);
3332
+ case ZodFirstPartyTypeKind3.ZodUndefined:
3333
+ return parseUndefinedDef(refs);
3334
+ case ZodFirstPartyTypeKind3.ZodNull:
3335
+ return parseNullDef(refs);
3336
+ case ZodFirstPartyTypeKind3.ZodArray:
3337
+ return parseArrayDef(def, refs);
3338
+ case ZodFirstPartyTypeKind3.ZodUnion:
3339
+ case ZodFirstPartyTypeKind3.ZodDiscriminatedUnion:
3340
+ return parseUnionDef(def, refs);
3341
+ case ZodFirstPartyTypeKind3.ZodIntersection:
3342
+ return parseIntersectionDef(def, refs);
3343
+ case ZodFirstPartyTypeKind3.ZodTuple:
3344
+ return parseTupleDef(def, refs);
3345
+ case ZodFirstPartyTypeKind3.ZodRecord:
3346
+ return parseRecordDef(def, refs);
3347
+ case ZodFirstPartyTypeKind3.ZodLiteral:
3348
+ return parseLiteralDef(def, refs);
3349
+ case ZodFirstPartyTypeKind3.ZodEnum:
3350
+ return parseEnumDef(def);
3351
+ case ZodFirstPartyTypeKind3.ZodNativeEnum:
3352
+ return parseNativeEnumDef(def);
3353
+ case ZodFirstPartyTypeKind3.ZodNullable:
3354
+ return parseNullableDef(def, refs);
3355
+ case ZodFirstPartyTypeKind3.ZodOptional:
3356
+ return parseOptionalDef(def, refs);
3357
+ case ZodFirstPartyTypeKind3.ZodMap:
3358
+ return parseMapDef(def, refs);
3359
+ case ZodFirstPartyTypeKind3.ZodSet:
3360
+ return parseSetDef(def, refs);
3361
+ case ZodFirstPartyTypeKind3.ZodLazy:
3362
+ return () => def.getter()._def;
3363
+ case ZodFirstPartyTypeKind3.ZodPromise:
3364
+ return parsePromiseDef(def, refs);
3365
+ case ZodFirstPartyTypeKind3.ZodNaN:
3366
+ case ZodFirstPartyTypeKind3.ZodNever:
3367
+ return parseNeverDef(refs);
3368
+ case ZodFirstPartyTypeKind3.ZodEffects:
3369
+ return parseEffectsDef(def, refs);
3370
+ case ZodFirstPartyTypeKind3.ZodAny:
3371
+ return parseAnyDef(refs);
3372
+ case ZodFirstPartyTypeKind3.ZodUnknown:
3373
+ return parseUnknownDef(refs);
3374
+ case ZodFirstPartyTypeKind3.ZodDefault:
3375
+ return parseDefaultDef(def, refs);
3376
+ case ZodFirstPartyTypeKind3.ZodBranded:
3377
+ return parseBrandedDef(def, refs);
3378
+ case ZodFirstPartyTypeKind3.ZodReadonly:
3379
+ return parseReadonlyDef(def, refs);
3380
+ case ZodFirstPartyTypeKind3.ZodCatch:
3381
+ return parseCatchDef(def, refs);
3382
+ case ZodFirstPartyTypeKind3.ZodPipeline:
3383
+ return parsePipelineDef(def, refs);
3384
+ case ZodFirstPartyTypeKind3.ZodFunction:
3385
+ case ZodFirstPartyTypeKind3.ZodVoid:
3386
+ case ZodFirstPartyTypeKind3.ZodSymbol:
3387
+ return void 0;
3388
+ default:
3389
+ return /* @__PURE__ */ ((_) => void 0)(typeName);
3390
+ }
3391
+ };
3392
+ function parseDef(def, refs, forceResolution = false) {
3393
+ const seenItem = refs.seen.get(def);
3394
+ if (refs.override) {
3395
+ const overrideResult = refs.override?.(def, refs, seenItem, forceResolution);
3396
+ if (overrideResult !== ignoreOverride) {
3397
+ return overrideResult;
2316
3398
  }
2317
- if ((req.needs?.length ?? 0) > NEEDS_MAX)
2318
- problems.push(`${req.needs?.length} needs \u2014 cap at ${NEEDS_MAX}; a call can't cover more in one conversation, split the rest into a second ask`);
2319
- return problems;
2320
3399
  }
2321
- const spoken = req.urgency === "call" || req.urgency === "banner";
2322
- if (req.context) {
2323
- if (req.context.title.length > TITLE_MAX)
2324
- problems.push(`title is ${req.context.title.length} chars \u2014 shorten to \u2264${TITLE_MAX} (it's what shows on the banner / gets spoken on a ring)`);
2325
- if (UNSPEAKABLE.test(req.context.title))
2326
- problems.push("title contains a code fence \u2014 one plain-prose line");
2327
- if (req.context.description.length > CHUNKS_MAX)
2328
- problems.push(`${req.context.description.length} description chunks \u2014 cap at ${CHUNKS_MAX}; merge or drop the rest`);
2329
- for (const [i, chunk] of req.context.description.entries()) {
2330
- if (chunk.length > CHUNK_MAX)
2331
- problems.push(`description[${i}] is ${chunk.length} chars \u2014 split it into standalone points of \u2264${CHUNK_MAX}`);
3400
+ if (seenItem && !forceResolution) {
3401
+ const seenSchema = get$ref(seenItem, refs);
3402
+ if (seenSchema !== void 0) {
3403
+ return seenSchema;
2332
3404
  }
2333
- if (spoken && UNSPEAKABLE.test(req.context.description.join(" ")))
2334
- problems.push("urgency is 'call'/'banner' but the description has a code fence \u2014 rewrite in spoken register (it will be read aloud)");
2335
3405
  }
2336
- for (const o of req.options ?? []) {
2337
- if (o.label.length > OPTION_MAX)
2338
- problems.push(`option label "${o.label.slice(0, 40)}\u2026" is ${o.label.length} chars \u2014 labels must read at a glance (\u2264${OPTION_MAX}); move detail into the description`);
3406
+ const newItem = { def, path: refs.currentPath, jsonSchema: void 0 };
3407
+ refs.seen.set(def, newItem);
3408
+ const jsonSchemaOrGetter = selectParser(def, def.typeName, refs);
3409
+ const jsonSchema = typeof jsonSchemaOrGetter === "function" ? parseDef(jsonSchemaOrGetter(), refs) : jsonSchemaOrGetter;
3410
+ if (jsonSchema) {
3411
+ addMeta(def, refs, jsonSchema);
3412
+ }
3413
+ if (refs.postProcess) {
3414
+ const postProcessResult = refs.postProcess(jsonSchema, def, refs);
3415
+ newItem.jsonSchema = jsonSchema;
3416
+ return postProcessResult;
3417
+ }
3418
+ newItem.jsonSchema = jsonSchema;
3419
+ return jsonSchema;
3420
+ }
3421
+ var get$ref = (item, refs) => {
3422
+ switch (refs.$refStrategy) {
3423
+ case "root":
3424
+ return { $ref: item.path.join("/") };
3425
+ case "relative":
3426
+ return { $ref: getRelativePath(refs.currentPath, item.path) };
3427
+ case "none":
3428
+ case "seen": {
3429
+ if (item.path.length < refs.currentPath.length && item.path.every((value, index) => refs.currentPath[index] === value)) {
3430
+ console.warn(`Recursive reference detected at ${refs.currentPath.join("/")}! Defaulting to any`);
3431
+ return parseAnyDef(refs);
3432
+ }
3433
+ return refs.$refStrategy === "seen" ? parseAnyDef(refs) : void 0;
3434
+ }
3435
+ }
3436
+ };
3437
+ var addMeta = (def, refs, jsonSchema) => {
3438
+ if (def.description) {
3439
+ jsonSchema.description = def.description;
3440
+ if (refs.markdownDescription) {
3441
+ jsonSchema.markdownDescription = def.description;
3442
+ }
3443
+ }
3444
+ return jsonSchema;
3445
+ };
3446
+ var zodToJsonSchema = (schema, options) => {
3447
+ const refs = getRefs(options);
3448
+ let definitions = typeof options === "object" && options.definitions ? Object.entries(options.definitions).reduce((acc, [name2, schema2]) => ({
3449
+ ...acc,
3450
+ [name2]: parseDef(schema2._def, {
3451
+ ...refs,
3452
+ currentPath: [...refs.basePath, refs.definitionPath, name2]
3453
+ }, true) ?? parseAnyDef(refs)
3454
+ }), {}) : void 0;
3455
+ const name = typeof options === "string" ? options : options?.nameStrategy === "title" ? void 0 : options?.name;
3456
+ const main = parseDef(schema._def, name === void 0 ? refs : {
3457
+ ...refs,
3458
+ currentPath: [...refs.basePath, refs.definitionPath, name]
3459
+ }, false) ?? parseAnyDef(refs);
3460
+ const title = typeof options === "object" && options.name !== void 0 && options.nameStrategy === "title" ? options.name : void 0;
3461
+ if (title !== void 0) {
3462
+ main.title = title;
3463
+ }
3464
+ if (refs.flags.hasReferencedOpenAiAnyType) {
3465
+ if (!definitions) {
3466
+ definitions = {};
3467
+ }
3468
+ if (!definitions[refs.openAiAnyTypeName]) {
3469
+ definitions[refs.openAiAnyTypeName] = {
3470
+ // Skipping "object" as no properties can be defined and additionalProperties must be "false"
3471
+ type: ["string", "number", "integer", "boolean", "array", "null"],
3472
+ items: {
3473
+ $ref: refs.$refStrategy === "relative" ? "1" : [
3474
+ ...refs.basePath,
3475
+ refs.definitionPath,
3476
+ refs.openAiAnyTypeName
3477
+ ].join("/")
3478
+ }
3479
+ };
3480
+ }
3481
+ }
3482
+ const combined = name === void 0 ? definitions ? {
3483
+ ...main,
3484
+ [refs.definitionPath]: definitions
3485
+ } : main : {
3486
+ $ref: [
3487
+ ...refs.$refStrategy === "relative" ? [] : refs.basePath,
3488
+ refs.definitionPath,
3489
+ name
3490
+ ].join("/"),
3491
+ [refs.definitionPath]: {
3492
+ ...definitions,
3493
+ [name]: main
3494
+ }
3495
+ };
3496
+ if (refs.target === "jsonSchema7") {
3497
+ combined.$schema = "http://json-schema.org/draft-07/schema#";
3498
+ } else if (refs.target === "jsonSchema2019-09" || refs.target === "openAi") {
3499
+ combined.$schema = "https://json-schema.org/draft/2019-09/schema#";
3500
+ }
3501
+ if (refs.target === "openAi" && ("anyOf" in combined || "oneOf" in combined || "allOf" in combined || "type" in combined && Array.isArray(combined.type))) {
3502
+ console.warn("Warning: OpenAI may not support schemas with unions as roots! Try wrapping it in an object property.");
3503
+ }
3504
+ return combined;
3505
+ };
3506
+ var OPTIONS_MIN = 2;
3507
+ var OPTIONS_MAX = 6;
3508
+ var MISSED_CALL_PLAN = {
3509
+ retry_10m: { kind: "every", minutes: 10 },
3510
+ retry_30m: { kind: "every", minutes: 30 },
3511
+ retry_60m: { kind: "every", minutes: 60 },
3512
+ backoff_gentle: { kind: "at", minutes: [30, 120, 360] },
3513
+ backoff_standard: { kind: "at", minutes: [10, 30, 120] },
3514
+ backoff_aggressive: { kind: "at", minutes: [5, 15, 45] },
3515
+ inbox: { kind: "once" },
3516
+ dismiss: { kind: "grace", minutes: 2 }
3517
+ };
3518
+ function draft2020(node) {
3519
+ if (Array.isArray(node)) return node.map(draft2020);
3520
+ if (node && typeof node === "object") {
3521
+ const o = node;
3522
+ for (const [excl, lim] of [["exclusiveMinimum", "minimum"], ["exclusiveMaximum", "maximum"]]) {
3523
+ if (typeof o[excl] === "boolean") {
3524
+ if (o[excl] === true && typeof o[lim] === "number") {
3525
+ o[excl] = o[lim];
3526
+ delete o[lim];
3527
+ } else delete o[excl];
3528
+ }
3529
+ }
3530
+ for (const k of Object.keys(o)) o[k] = draft2020(o[k]);
3531
+ return o;
2339
3532
  }
2340
- return problems;
3533
+ return node;
3534
+ }
3535
+ function mcpInputSchema(s) {
3536
+ const schema = zodToJsonSchema(s, { target: "jsonSchema2019-09", $refStrategy: "none" });
3537
+ delete schema.$schema;
3538
+ return draft2020(schema);
2341
3539
  }
2342
- var ContextSchema = z.object({
2343
- title: z.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
2344
- description: z.array(z.string().min(1)).describe(
3540
+ var CreateGoalSchema = z.object({
3541
+ outcome: z.string().trim().min(1).max(1e4),
3542
+ ownerParticipant: z.string().trim().min(1).optional(),
3543
+ idempotencyKey: z.string().trim().min(1).max(200)
3544
+ });
3545
+ var fmtMin = (m) => m >= 60 ? `${m / 60} hr` : `${m} min`;
3546
+ var STANDARD_MEANS = (() => {
3547
+ const plan = MISSED_CALL_PLAN.backoff_standard;
3548
+ const mins = plan.kind === "at" ? plan.minutes : [];
3549
+ const parts = mins.map(fmtMin);
3550
+ const list = parts.length > 1 ? `${parts.slice(0, -1).join(", ")} and ${parts[parts.length - 1]}` : parts[0] ?? "";
3551
+ return `Rings again ${list} after the missed call, then leaves it in your inbox`;
3552
+ })();
3553
+ function contactSchemaFrom(fields) {
3554
+ const surface = z.object({
3555
+ ask: fields.ask.describe(
3556
+ `What to tell the user, or what you need to find out from them. Plain prose \u2014 as long as it needs to be (up to 10k characters); Paigy splits it into topics and reads back a few sentences at a time, so do NOT compress a briefing into one line. May be spoken aloud on a call, so write natural speech and name things (not IDs). Contact at exactly two moments: BLOCKED on a decision only they can make, or DONE (one short report \u2014 what shipped, how you verified it, what you flagged). DONE IS SAID ONCE: "all set", "nothing open on my end", "that thread is complete" are the same report in new words, and each one reaches them separately (live 2026-08-12: three of them in three minutes). After the first, you are finished speaking; if they acknowledge it, stop rather than confirming the acknowledgement. Progress is never a contact: set_work_state carries it, and working narration stays in your own terminal \u2014 the user sees you're working without being interrupted by it.`
3557
+ ),
3558
+ waiting: fields.waiting.describe(
3559
+ "What happens to your work while you wait. 'none': you're just informing them. 'soft': you'd like an answer but can keep working. 'hard': you are STOPPED until they answer \u2014 reaches them urgently and escalates to a real phone call if unanswered."
3560
+ ),
3561
+ options: fields.options.describe(
3562
+ `The choices the user picks from, when you have them \u2014 ${OPTIONS_MIN} to ${OPTIONS_MAX}, drawn from your own sentence.`
3563
+ ),
3564
+ channel: fields.channel.describe(
3565
+ "Relay how the user explicitly said to reach them ('call me' \u2192 'call', 'just message/text me' \u2192 'message'), or use 'call' when promoting the same quiet ask after it becomes a substantial blocker. Omit otherwise; Paigy picks."
3566
+ ),
3567
+ parentId: fields.parentId.describe(
3568
+ "To continue an earlier conversation, pass the parentId a previous contact or reply returned. Omit to start a new one."
3569
+ ),
3570
+ workId: fields.workId.describe(
3571
+ "The durable Work this contact advances. Pass the workId from check_replies or a prior reply when asking for a decision that blocks that work."
3572
+ )
3573
+ });
3574
+ const out = mcpInputSchema(surface);
3575
+ out.required = ["ask"];
3576
+ return out;
3577
+ }
3578
+ var CONTACT_DESCRIPTION = `Reach the user through Paigy \u2014 tell them something, or ask and get their answer. State what you need in \`ask\`, say what happens to your work while you wait in \`waiting\`, and Paigy handles the rest (channel, phrasing, answer format). If the user explicitly asks you to CALL them, send waiting:'hard' and say so in the ask. Returns { notificationId, parentId, workId?, decisionId? } \u2014 pass notificationId to the reply path named by the returned \`message\`, and parentId to a later contact to continue the conversation. When it rang, the reply also carries { ifMissed: { mode, means } }: what the user's own policy does with a call they don't take ("${STANDARD_MEANS}"), so a no-answer tells you how long to wait before coming back. THREADING REPLACES: a threaded follow-up SUPERSEDES your earlier pending items on that thread \u2014 right for updates to one ask, WRONG for a checklist (send independent to-dos un-threaded). A threaded re-send with IDENTICAL content escalates the pending ask in place. If a reply comes back as {kind:'clarify', chunks:[...]}, the user wants more detail \u2014 contact again on the SAME parentId with an expanded ask. BLOCKED ON A DECISION for existing work? Pass that work's \`workId\`; the reply returns the same workId plus a decisionId, so the answer resumes the right outcome. ONE ASK, ONE ROW: never restate a still-pending ask's question inside a NEW contact (e.g. weaving it into a briefing) \u2014 the whole answer settles on the new row and the original can never receive it. Keep waiting on the original (a live call reads every pending ask out separately, each answer routes to its own row), and use \`needs\` for a genuinely multi-part NEW ask. ANSWERABLE, NOT JUST ASKED: when the reply comes back carrying \`plan.units[].needs\`, that unit asked for something it gave the user no way to answer \u2014 'options' means it posed a choice with nothing to choose from, 'visuals' means it asked about something to look at with nothing to look at. Send it again on the SAME parentId with ${OPTIONS_MIN}-${OPTIONS_MAX} options (or the image), drawn from your own sentence. Paigy will not add them for you: a shape it guessed wrong cannot be undone, and you are the one who knows what the real alternatives are. \`units\` reports WHAT BECAME OF YOUR PROSE \u2014 { kept, raw, why }: how many topics Paigy compressed for delivery, how many kept your exact words, and the reason when it kept them (e.g. 'no_output' = compression produced nothing usable, so the user got your raw sentence). It needs no action and is not an error \u2014 read it only when the delivered wording matters to you; a high \`raw\` count means the user is hearing you verbatim.`;
3579
+ var ContextSchema = z2.object({
3580
+ title: z2.string().min(1).describe("One-line headline of what you need (required, non-empty)."),
3581
+ description: z2.array(z2.string().min(1)).describe(
2345
3582
  "Semantic chunks of detail (each a standalone, non-empty piece). The user can select chunks to ask you to expand. MAY BE EMPTY: a claim whose whole content is its heading \u2014 a single sentence \u2014 has no body, and saying so beats repeating the heading underneath itself. That repeat is what `min(1)` used to force, at 2x the storage, with every reader subtracting it back out at render time."
2346
3583
  )
2347
3584
  });
2348
- var ParticipantSchema = z.object({
2349
- kind: z.enum(["human", "agent"]),
2350
- id: z.string()
3585
+ var ParticipantSchema = z2.object({
3586
+ kind: z2.enum(["human", "agent"]),
3587
+ id: z2.string()
2351
3588
  });
2352
- var TransformSchema = z.enum([
3589
+ var TransformSchema = z2.enum([
2353
3590
  "structure",
2354
3591
  // shape intent into an answer contract; pick channel/urgency — broker `ask`, `select` shapes, `points`
2355
3592
  "request_more",
@@ -2365,25 +3602,25 @@ var TransformSchema = z.enum([
2365
3602
  "summarize"
2366
3603
  // reduce volume, keep decision value — 30-turn cap, spoken briefing
2367
3604
  ]);
2368
- var OptionSchema = z.object({
2369
- id: z.string(),
2370
- label: z.string(),
3605
+ var OptionSchema = z2.object({
3606
+ id: z2.string(),
3607
+ label: z2.string(),
2371
3608
  // .describe() flows into the MCP contact JSON schema (zodToJsonSchema), so
2372
3609
  // the constraints below are what an agent reads when deciding to use these.
2373
- html: z.string().max(16384).describe(
3610
+ html: z2.string().max(16384).describe(
2374
3611
  "Optional sandboxed HTML/CSS preview for a visual 'pick one' (shown in the option card). Untrusted-sandboxed: NO JavaScript, NO external network or images \u2014 inline CSS and data: URIs only; <=16KB. Use for layout/CSS mockups, tables, diffs. For a hosted image use `image` instead."
2375
3612
  ).optional(),
2376
- image: z.string().url().describe(
3613
+ image: z2.string().url().describe(
2377
3614
  "Optional image URL rendered as the option's preview (plain image, not sandboxed). For agent-generated HTML/CSS mockups, use `html` instead."
2378
3615
  ).optional()
2379
3616
  });
2380
- var VisualSchema = z.object({
2381
- url: z.string().url(),
2382
- label: z.string().optional()
3617
+ var VisualSchema = z2.object({
3618
+ url: z2.string().url(),
3619
+ label: z2.string().optional()
2383
3620
  });
2384
- var NotifyLevelSchema = z.enum(["inbox", "push", "banner", "call"]);
2385
- var SelectShapeSchema = z.enum(["one", "many", "rank", "confirm", "text"]);
2386
- var ReceiptEventSchema = z.enum([
3621
+ var NotifyLevelSchema = z2.enum(["inbox", "push", "banner", "call"]);
3622
+ var SelectShapeSchema = z2.enum(["one", "many", "rank", "confirm", "text"]);
3623
+ var ReceiptEventSchema = z2.enum([
2387
3624
  "delivered",
2388
3625
  // the bundle reached the recipient at some level
2389
3626
  "seen",
@@ -2413,41 +3650,44 @@ var ReceiptEventSchema = z.enum([
2413
3650
  // be rewound by a writer that forgot to advance it.
2414
3651
  "restarted"
2415
3652
  ]);
2416
- var AttentionSchema = z.object({
3653
+ var AttentionSchema = z2.object({
2417
3654
  urgency: NotifyLevelSchema,
2418
3655
  /** The required answer shape, or null for a plain notify that asks nothing back. */
2419
3656
  select: SelectShapeSchema.nullable(),
2420
3657
  /** Coverage contract (#396) — points the answer must address; null = none declared. */
2421
- points: z.array(z.string()).nullable(),
3658
+ points: z2.array(z2.string()).nullable(),
2422
3659
  /** Whether the ask blocks the sender — what lets arbitration escalate it on silence. */
2423
- blocking: z.boolean(),
3660
+ blocking: z2.boolean(),
2424
3661
  /** Reserved (MODEL.md lists it): a response deadline. No row column yet — a later Phase 2
2425
3662
  * slice wires it; optional so today's rows/callers project cleanly. */
2426
- deadline: z.string().datetime().nullable().optional()
3663
+ deadline: z2.string().datetime().nullable().optional()
2427
3664
  });
2428
- var NotifyRequestSchema = z.object({
3665
+ var NotifyRequestFields = z2.object({
2429
3666
  /** Plaintext message content. Present on the plaintext path (today's shape);
2430
3667
  * ABSENT on the E2EE path, where the sealed `envelope` below carries it. The
2431
3668
  * superRefine at the bottom enforces exactly one of the two. */
2432
3669
  context: ContextSchema.optional(),
2433
- options: z.array(OptionSchema.omit({ id: true })).min(1).optional().describe(
3670
+ options: z2.array(OptionSchema.omit({ id: true })).min(OPTIONS_MIN).max(OPTIONS_MAX).optional().describe(
2434
3671
  "The choices, in order \u2014 required when select is 'one'/'many'/'rank', omitted otherwise. Ids are assigned automatically by position ('1', '2', \u2026); the user's answer references them as optionId(s)."
2435
3672
  ),
2436
- points: z.array(z.string().min(1)).optional().describe(
3673
+ points: z2.array(z2.string().min(1)).optional().describe(
2437
3674
  "The distinct things you need answered, each a short phrase \u2014 on a call the broker keeps the conversation going until each is addressed, and the reply reports which were covered, so a half-answer is never silently returned as final. Omit for single-part asks."
2438
3675
  ),
2439
- visuals: z.array(VisualSchema).optional().describe(
3676
+ visuals: z2.array(VisualSchema).optional().describe(
2440
3677
  "Images attached to the message itself \u2014 context for the whole question (a screenshot, a chart). For a preview on one selectable choice, use that option's `html`/`image` instead."
2441
3678
  ),
2442
3679
  /** Git repo the agent is working in ("owner/name"). Local MCP fills this from the checkout — omit unless overriding. */
2443
- repo: z.string().optional(),
3680
+ repo: z2.string().optional(),
2444
3681
  /** Git branch the agent is on. Local MCP fills this from the checkout — omit unless overriding. */
2445
- branch: z.string().optional(),
3682
+ branch: z2.string().optional(),
2446
3683
  /** Continue an existing conversation — the id of any notification in it (its root
2447
3684
  * is the conversation's identity). Omitted = start a new conversation. Renamed
2448
3685
  * from `parentId` (2026-08-03): one linkage system, the parent; the API edge
2449
3686
  * still accepts the old name from older clients. */
2450
- parentId: z.string().uuid().optional(),
3687
+ parentId: z2.string().uuid().optional(),
3688
+ /** The durable outcome this contact advances. Optional during the notification-to-Work
3689
+ * migration; when present, a blocking ask creates a DecisionNeed for this Work. */
3690
+ workId: z2.string().uuid().optional(),
2451
3691
  urgency: NotifyLevelSchema.default("inbox").describe(
2452
3692
  "The level you're requesting \u2014 the user's account permissions + session mode can lower it. 'inbox' (default) = sits silently in the inbox for the user to get to. 'push' = a quiet passive push (lands in Notification Center, no sound) \u2014 a gentle heads-up. 'banner' = a time-sensitive banner/lock-screen push with sound (a 'paige') they tap to open \u2014 use when you need them soon-ish but it's not worth ringing them. 'call' = rings the user's phone now (a CallKit voice call) \u2014 use only when you genuinely need them in the moment (blocked and waiting, time-sensitive). context.title is what they see on the banner/ring, so make it specific."
2453
3693
  ),
@@ -2455,7 +3695,7 @@ var NotifyRequestSchema = z.object({
2455
3695
  * visible and marks it needs_input. Renamed from the old `parentId` (2026-08-03)
2456
3696
  * when `parentId` became the conversation handle: `parentId` says WHERE, this
2457
3697
  * says HOW. */
2458
- clarifies: z.string().optional(),
3698
+ clarifies: z2.string().optional(),
2459
3699
  /** E2EE (text lane): when the pairing is E2EE, the sealed replacements for the
2460
3700
  * plaintext content fields, keyed by field name. FINALIZED wire shape (was
2461
3701
  * provisional in the storage PR): a per-field map `{ context?, options?,
@@ -2468,10 +3708,10 @@ var NotifyRequestSchema = z.object({
2468
3708
  * notifications.envelope and relays it blindly; it never decrypts. Absent =
2469
3709
  * today's plaintext path (context/options/visuals carry the cleartext).
2470
3710
  * z.lazy because EnvelopeSchema is declared further down (E2EE section). */
2471
- envelope: z.object({
2472
- context: z.lazy(() => EnvelopeSchema).optional(),
2473
- options: z.lazy(() => EnvelopeSchema).optional(),
2474
- visuals: z.lazy(() => EnvelopeSchema).optional()
3711
+ envelope: z2.object({
3712
+ context: z2.lazy(() => EnvelopeSchema).optional(),
3713
+ options: z2.lazy(() => EnvelopeSchema).optional(),
3714
+ visuals: z2.lazy(() => EnvelopeSchema).optional()
2475
3715
  }).optional(),
2476
3716
  select: SelectShapeSchema.optional().describe(
2477
3717
  "How the user answers \u2014 required on the fully-shaped form, pick the shape that fits the question: 'one' = pick one option, 'many' = pick several, 'rank' = pick & order (each needs `options`); 'confirm' = yes/no or approve/deny; 'text' = free-form reply only (status updates, open questions). 'confirm' and 'text' take no options. Omit only when sending the simplified `ask` form \u2014 the broker picks the shape."
@@ -2486,20 +3726,20 @@ var NotifyRequestSchema = z.object({
2486
3726
  // (broker/agenda-design.md) — not by a wire cap the agent has to pre-summarize under.
2487
3727
  // Owner, 2026-07-28: "our actual limitation on how long something is to the user should
2488
3728
  // come from the broker splitting and summarizing." The cap that remains is a size guard.
2489
- ask: z.string().min(1).max(1e4).optional().describe(
3729
+ ask: z2.string().min(1).max(1e4).optional().describe(
2490
3730
  'SIMPLIFIED FORM \u2014 state in plain prose what you need to learn from the user and why it matters now (e.g. "I need to know whether to deploy the auth fix \u2014 tests are green, staging verified"). Write as much as the situation needs (up to 10k characters) \u2014 Paigy breaks it into topics and reads it back a few sentences at a time; do NOT pre-summarize it into one line. Paigy derives the title, answer shape, options, and delivery channel for you. Mutually exclusive with context/select/options \u2014 send one form or the other.'
2491
3731
  ),
2492
- needs: z.array(z.string().min(1)).optional().describe(
3732
+ needs: z2.array(z2.string().min(1)).optional().describe(
2493
3733
  "With `ask` only: the distinct things you need answered when the ask is multi-part \u2014 becomes the coverage contract (`points`), so a half-answer is never silently final."
2494
3734
  ),
2495
- urgencyHint: z.enum(["whenever", "soon", "now"]).optional().describe(
3735
+ urgencyHint: z2.enum(["whenever", "soon", "now"]).optional().describe(
2496
3736
  "With `ask` only: how urgently you need the answer \u2014 'whenever' (inbox), 'soon' (worth a heads-up), 'now' (you're blocked this minute). A hint, not a command: the user's settings still have the final word."
2497
3737
  ),
2498
3738
  /** #575: the ONE self-report that replaces urgencyHint + blocking — what happens
2499
3739
  * to the agent's work while it waits. Normalized server-side into those two
2500
3740
  * fields (normalizeWaiting) so everything downstream is untouched; explicit
2501
3741
  * urgencyHint/blocking win when both are sent. */
2502
- waiting: z.enum(["none", "soft", "hard"]).optional().describe(
3742
+ waiting: z2.enum(["none", "soft", "hard"]).optional().describe(
2503
3743
  "With `ask`: what happens to your work while you wait. 'none' = you're just informing the user. 'soft' = you'd like an answer but can keep working. 'hard' = you are stopped until they answer (reaches them urgently and escalates to a real phone call if unanswered). Replaces urgencyHint + blocking \u2014 send this one field."
2504
3744
  ),
2505
3745
  /** Δ9b (#895): HOLD this claim so the sender can correct the plan before anyone is
@@ -2507,57 +3747,58 @@ var NotifyRequestSchema = z.object({
2507
3747
  * holding by default would charge every quiet claim that minute before any agent could
2508
3748
  * correct anything. Ignored for `waiting: 'hard'`: a blocking ask rings on what we have,
2509
3749
  * and the enrichment can still land mid-call (#781 re-plans the unspoken tail). */
2510
- confirm: z.boolean().optional().describe(
3750
+ confirm: z2.boolean().optional().describe(
2511
3751
  "Hold this one so you can correct the plan before the user is interrupted. The response comes back with `held: true` and the plan; POST the confirm route to release it (with options/visuals/urgency corrections, or nothing at all). If you never do, it is announced anyway a couple of minutes later. Ignored when waiting is 'hard'."
2512
3752
  ),
2513
3753
  /** #575: a RELAY of the user's explicitly stated preference, never the agent's
2514
3754
  * choice. Outranks waiting in both directions: 'call' rings even for a
2515
3755
  * waiting:'none' "call me when it's done"; 'message' never rings even for
2516
3756
  * waiting:'hard'. */
2517
- channel: z.enum(["call", "message"]).optional().describe(
3757
+ channel: z2.enum(["call", "message"]).optional().describe(
2518
3758
  "Only if the user explicitly said how to reach them \u2014 'call me' \u2192 'call', 'just message/text me' \u2192 'message'. Omit otherwise; Paigy picks."
2519
3759
  ),
2520
- confirmStyle: z.enum(["yesno", "approve"]).default("yesno").describe(
3760
+ confirmStyle: z2.enum(["yesno", "approve"]).default("yesno").describe(
2521
3761
  "Labels for a select:'confirm' paige \u2014 'yesno' (Yes/No) or 'approve' (Approve/Deny). Ignored unless select is 'confirm'."
2522
3762
  ),
2523
- blocking: z.boolean().default(false).describe(
3763
+ blocking: z2.boolean().default(false).describe(
2524
3764
  "Set true when real downstream work is stuck behind this specific decision \u2014 you can't make meaningful progress until it's answered. This is the real signal for how urgently the user should be reached; it's what the premier use case (an agent that stays unblocked instead of going idle) depends on. Independent of `urgency`: a `banner`-level question can still be `blocking` (something IS stuck, just not time-critical enough to ring for immediately) \u2014 if it goes unanswered a while, Paigy escalates it to a real call using this flag rather than guessing from how many other things happen to be pending. Leave false for anything you could work around, defer, or where other useful work exists meanwhile."
2525
3765
  )
2526
- }).superRefine((r, ctx) => {
3766
+ });
3767
+ var NotifyRequestSchema = NotifyRequestFields.superRefine((r, ctx) => {
2527
3768
  const sealed = !!r.envelope;
2528
3769
  if (sealed) {
2529
3770
  if (!r.envelope?.context)
2530
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["envelope", "context"], message: "sealed request must include envelope.context" });
3771
+ ctx.addIssue({ code: z2.ZodIssueCode.custom, path: ["envelope", "context"], message: "sealed request must include envelope.context" });
2531
3772
  for (const f of ["context", "options", "visuals"]) {
2532
3773
  if (r[f] !== void 0)
2533
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: [f], message: `E2EE request must not carry plaintext ${f} \u2014 it's sealed in envelope.${f}` });
3774
+ ctx.addIssue({ code: z2.ZodIssueCode.custom, path: [f], message: `E2EE request must not carry plaintext ${f} \u2014 it's sealed in envelope.${f}` });
2534
3775
  }
2535
3776
  if (r.points !== void 0)
2536
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["points"], message: "E2EE request must not carry plaintext points" });
3777
+ ctx.addIssue({ code: z2.ZodIssueCode.custom, path: ["points"], message: "E2EE request must not carry plaintext points" });
2537
3778
  if (r.ask !== void 0)
2538
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["ask"], message: "E2EE request must not carry a plaintext ask \u2014 derive the shape agent-side and seal it" });
3779
+ ctx.addIssue({ code: z2.ZodIssueCode.custom, path: ["ask"], message: "E2EE request must not carry a plaintext ask \u2014 derive the shape agent-side and seal it" });
2539
3780
  if (r.needs !== void 0)
2540
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["needs"], message: "E2EE request must not carry plaintext needs" });
3781
+ ctx.addIssue({ code: z2.ZodIssueCode.custom, path: ["needs"], message: "E2EE request must not carry plaintext needs" });
2541
3782
  return;
2542
3783
  }
2543
3784
  if (r.ask !== void 0) {
2544
3785
  for (const f of ["context", "select", "points"]) {
2545
3786
  if (r[f] !== void 0)
2546
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: [f], message: `the simplified \`ask\` form takes no ${f} \u2014 the broker derives the answer shape from your prose. Drop ${f} and say it in \`ask\` instead ("should I\u2026" for approve/deny, "which of these\u2026" for a pick), passing \`options\` when you're offering concrete alternatives.` });
3787
+ ctx.addIssue({ code: z2.ZodIssueCode.custom, path: [f], message: `the simplified \`ask\` form takes no ${f} \u2014 the broker derives the answer shape from your prose. Drop ${f} and say it in \`ask\` instead ("should I\u2026" for approve/deny, "which of these\u2026" for a pick), passing \`options\` when you're offering concrete alternatives.` });
2547
3788
  }
2548
3789
  return;
2549
3790
  }
2550
3791
  if (r.needs !== void 0 || r.urgencyHint !== void 0)
2551
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["needs"], message: "needs/urgencyHint belong to the simplified `ask` form \u2014 with a shaped request use points/urgency" });
3792
+ ctx.addIssue({ code: z2.ZodIssueCode.custom, path: ["needs"], message: "needs/urgencyHint belong to the simplified `ask` form \u2014 with a shaped request use points/urgency" });
2552
3793
  if (!r.context)
2553
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["context"], message: "context is required (plaintext path)" });
3794
+ ctx.addIssue({ code: z2.ZodIssueCode.custom, path: ["context"], message: "context is required (plaintext path)" });
2554
3795
  if (!r.select)
2555
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["select"], message: "select is required on the shaped form" });
3796
+ ctx.addIssue({ code: z2.ZodIssueCode.custom, path: ["select"], message: "select is required on the shaped form" });
2556
3797
  const needsOptions = r.select === "one" || r.select === "many" || r.select === "rank";
2557
3798
  if (needsOptions && !r.options?.length)
2558
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' requires options` });
3799
+ ctx.addIssue({ code: z2.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' requires options` });
2559
3800
  if (!needsOptions && r.options?.length)
2560
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' takes no options` });
3801
+ ctx.addIssue({ code: z2.ZodIssueCode.custom, path: ["options"], message: `select:'${r.select}' takes no options` });
2561
3802
  });
2562
3803
  function normalizeWaiting(req) {
2563
3804
  if (!req.waiting) return req;
@@ -2614,61 +3855,70 @@ function deriveAsk(req) {
2614
3855
  ...needs?.length ? { points: needs } : {}
2615
3856
  };
2616
3857
  }
2617
- var NotifyStatusSchema = z.enum(["pending", "answered", "ignored"]);
2618
- var AgentStateSchema = z.enum(["idle", "in_progress", "completed", "needs_input"]);
2619
- var SetTaskStateSchema = z.object({
2620
- state: z.enum(["in_progress", "completed", "needs_input"])
3858
+ var NotifyStatusSchema = z2.enum(["pending", "answered", "ignored"]);
3859
+ var AgentStateSchema = z2.enum(["idle", "in_progress", "completed", "needs_input"]);
3860
+ var SetTaskStateSchema = z2.object({
3861
+ state: z2.enum(["in_progress", "completed", "needs_input"])
3862
+ });
3863
+ var SetWorkStateSchema = z2.object({
3864
+ workId: z2.string().uuid().optional(),
3865
+ notificationId: z2.string().optional(),
3866
+ state: SetTaskStateSchema.shape.state
3867
+ }).refine((value) => Number(Boolean(value.workId)) + Number(Boolean(value.notificationId)) === 1, {
3868
+ message: "exactly one of workId or notificationId is required"
2621
3869
  });
2622
- var TurnSchema = z.object({
2623
- prompt: z.string(),
2624
- reply: z.string()
3870
+ var TurnSchema = z2.object({
3871
+ prompt: z2.string(),
3872
+ reply: z2.string()
2625
3873
  });
2626
- var UserAnswerSchema = z.discriminatedUnion("kind", [
2627
- z.object({ kind: z.literal("option"), optionId: z.string(), label: z.string().optional() }),
2628
- z.object({ kind: z.literal("text"), text: z.string() }),
2629
- z.object({ kind: z.literal("ignored") }),
2630
- z.object({ kind: z.literal("multi"), optionIds: z.array(z.string()), labels: z.array(z.string()).optional() }),
2631
- z.object({ kind: z.literal("ranked"), optionIds: z.array(z.string()), labels: z.array(z.string()).optional() }),
2632
- z.object({ kind: z.literal("clarify"), chunks: z.array(z.string()).min(1) }),
2633
- z.object({ kind: z.literal("confirm"), approved: z.boolean() }),
2634
- z.object({ kind: z.literal("turns"), turns: z.array(TurnSchema).min(1) }),
3874
+ var UserAnswerSchema = z2.discriminatedUnion("kind", [
3875
+ z2.object({ kind: z2.literal("option"), optionId: z2.string(), label: z2.string().optional() }),
3876
+ z2.object({ kind: z2.literal("text"), text: z2.string() }),
3877
+ z2.object({ kind: z2.literal("ignored") }),
3878
+ z2.object({ kind: z2.literal("multi"), optionIds: z2.array(z2.string()), labels: z2.array(z2.string()).optional() }),
3879
+ z2.object({ kind: z2.literal("ranked"), optionIds: z2.array(z2.string()), labels: z2.array(z2.string()).optional() }),
3880
+ z2.object({ kind: z2.literal("clarify"), chunks: z2.array(z2.string()).min(1) }),
3881
+ z2.object({ kind: z2.literal("confirm"), approved: z2.boolean() }),
3882
+ z2.object({ kind: z2.literal("turns"), turns: z2.array(TurnSchema).min(1) }),
2635
3883
  /** An auto-answer derived from the user's PAST decisions (broker/precedent-design.md §2):
2636
3884
  * delivered through the same settle/await path as a human answer, carrying the judge's
2637
3885
  * derivation and the precedent ids it grew from. Always paired with a visible trail
2638
3886
  * card the user can reply to — the broker never overrides the user. */
2639
- z.object({ kind: z.literal("precedent"), answer: z.string(), derivation: z.string(), sources: z.array(z.string()).min(1) })
3887
+ z2.object({ kind: z2.literal("precedent"), answer: z2.string(), derivation: z2.string(), sources: z2.array(z2.string()).min(1) })
2640
3888
  ]);
2641
- var IntentSchema = z.object({
3889
+ var IntentSchema = z2.object({
2642
3890
  // The full vocabulary the bot's mapper emits (mapper.INTENT_KINDS) — the schema lagged
2643
3891
  // it by two ("detail", "feedback"), and because the settle handler parsed the array
2644
3892
  // all-or-nothing, ONE feedback act silently dropped EVERY intent on the call,
2645
3893
  // questions included. Found auditing five calls' stored feedback, 2026-08-01.
2646
- kind: z.enum(["defer", "delegate", "channel", "question", "detail", "feedback", "command", "control"]),
2647
- detail: z.string(),
3894
+ kind: z2.enum(["defer", "delegate", "channel", "question", "detail", "feedback", "command", "control"]),
3895
+ detail: z2.string(),
2648
3896
  /** Defer only: seconds until the callback the caller asked for, when something upstream
2649
3897
  * already read the time. Nothing sets it today (#397 documented an MCP parser that was
2650
3898
  * never written) — the API reads the defer's `detail` itself with `notes/when.ts`
2651
3899
  * (`parseDelay`, #1292), and a value here simply wins over that reading. */
2652
- dueInSeconds: z.number().int().positive().optional(),
3900
+ dueInSeconds: z2.number().int().positive().optional(),
2653
3901
  /** Feedback only (#812): WHICH failure the complaint names — typed by the mapper that
2654
3902
  * already read the utterance, so `feedback_from_call.kind` stops defaulting to
2655
3903
  * 'other' on every row. A table that records that something was wrong and nothing
2656
3904
  * about what cannot answer "is the bot looping less this week?". */
2657
- fault: z.enum(["loop", "unanswered", "overridden", "misheard", "slow", "other"]).optional()
3905
+ fault: z2.enum(["loop", "unanswered", "overridden", "misheard", "slow", "other"]).optional()
2658
3906
  });
2659
- var RideAlongSchema = z.object({
3907
+ var RideAlongSchema = z2.object({
2660
3908
  /** The note this came from — assign/clarify/close it through /api/notes/:id. */
2661
- noteId: z.string(),
3909
+ noteId: z2.string(),
2662
3910
  /** What to do, in the owner's own words (the note's headline). Never model-rewritten. */
2663
- text: z.string(),
3911
+ text: z2.string(),
2664
3912
  /** The thread to report back on, when the note was dispatched over the request rail. */
2665
- parentId: z.string().nullable()
3913
+ parentId: z2.string().nullable()
2666
3914
  });
2667
- var AwaitItemSchema = z.discriminatedUnion("type", [
2668
- z.object({
2669
- type: z.literal("reply"),
2670
- parentId: z.string(),
2671
- notificationId: z.string(),
3915
+ var AwaitItemSchema = z2.discriminatedUnion("type", [
3916
+ z2.object({
3917
+ type: z2.literal("reply"),
3918
+ parentId: z2.string(),
3919
+ notificationId: z2.string(),
3920
+ workId: z2.string().uuid().optional(),
3921
+ decisionId: z2.string().uuid().optional(),
2672
3922
  answer: UserAnswerSchema,
2673
3923
  /** E2EE: present when the answer is sealed. The server relays the opaque answer
2674
3924
  * envelope + the plaintext `ignored` status hint; the receiving agent OPENS it
@@ -2676,126 +3926,146 @@ var AwaitItemSchema = z.discriminatedUnion("type", [
2676
3926
  * against `ignored` as tampering. Absent = today's plaintext answer (in `answer`).
2677
3927
  * On a sealed reply the plaintext `answer` is a placeholder (kind reflects only
2678
3928
  * the `ignored` bit) — never the real content, which stays sealed. */
2679
- sealed: z.lazy(() => SealedAnswerSchema).optional(),
2680
- /** Broker extras (#381), present when the answer was mapped from a call: next
2681
- * steps the user attached ("call me after lunch" → defer — act on it via
2682
- * schedule_callback) and the raw words the shaped answer was mapped from. */
2683
- intents: z.array(IntentSchema).optional(),
2684
- transcript: z.string().optional(),
3929
+ sealed: z2.lazy(() => SealedAnswerSchema).optional(),
3930
+ /** WHAT THE AGENT CANNOT KNOW FROM THE FIELDS BESIDE IT (owner, 2026-09-04, issue
3931
+ * #1537). One line, built from the record: the ask and the caller's reply VERBATIM,
3932
+ * the notification they belong to, and the `contact` call that reaches the person
3933
+ * again, spelled with its real arguments. It restates nothing — deleting the brain's
3934
+ * acts deleted the paraphrase, and this is not it coming back: an agent that reads
3935
+ * "call me back after you merge" in their own words decides for itself what to do,
3936
+ * and now knows exactly which call to make. Absent when either half is missing —
3937
+ * a sentence with a hole in it is worse than no sentence. */
3938
+ note: z2.string().optional(),
3939
+ /** The call record rendered for THIS agent (`voice/record-design.md`): the words the
3940
+ * shaped answer was mapped from, filtered to its own claims. There is no second list
3941
+ * of labels beside it — the acts went 2026-09-04 and `intents` went with them (owner,
3942
+ * 2026-09-04): the agent reads the sentence and decides. */
3943
+ transcript: z2.string().optional(),
2685
3944
  /** Coverage report (#396), when the ask declared `points`: which of them this
2686
3945
  * answer addressed. Missing points = re-ask or proceed knowingly partial. */
2687
- covered: z.array(z.string()).optional(),
3946
+ covered: z2.array(z2.string()).optional(),
2688
3947
  /** Ride-alongs (RideAlongSchema) — pending work for you, attached to the moment you
2689
3948
  * became free. Only `reply` and `idle` carry it: those are the two outcomes that
2690
3949
  * END a wait. `remind`, `superseded` and `turn` are mid-flight, and handing an
2691
3950
  * agent a side-quest while it is still holding the line is how the main thing gets
2692
3951
  * dropped. Absent/empty = nothing owed. */
2693
- also: z.array(RideAlongSchema).optional()
3952
+ also: z2.array(RideAlongSchema).optional()
2694
3953
  }),
2695
- z.object({
2696
- type: z.literal("remind"),
2697
- parentId: z.string(),
2698
- notificationId: z.string(),
2699
- remindAt: z.string().datetime({ offset: true }),
3954
+ z2.object({
3955
+ type: z2.literal("remind"),
3956
+ parentId: z2.string(),
3957
+ notificationId: z2.string(),
3958
+ remindAt: z2.string().datetime({ offset: true }),
2700
3959
  /** Seconds until remindAt, server-computed — pass straight to ScheduleWakeup. */
2701
- remindInSeconds: z.number()
3960
+ remindInSeconds: z2.number()
2702
3961
  }),
2703
3962
  /** The awaited ask was REPLACED by a newer notification on its thread (e.g. a
2704
3963
  * post-feedback revision, #633) — the user will never answer this id. Stop
2705
3964
  * awaiting it; the live ask is the thread's newest turn (await that one, or
2706
3965
  * re-orient via get_thread / check_replies). */
2707
- z.object({
2708
- type: z.literal("superseded"),
2709
- parentId: z.string(),
2710
- notificationId: z.string()
3966
+ z2.object({
3967
+ type: z2.literal("superseded"),
3968
+ parentId: z2.string(),
3969
+ notificationId: z2.string()
2711
3970
  }),
2712
3971
  /** A LIVE call's turn, streamed as it lands (#783). PROVISIONAL: the user can still
2713
3972
  * revise any of these until the final reply arrives — partial = intelligence,
2714
3973
  * settled = authorization. Use it to PREPARE (fetch, draft, warm), never to act
2715
3974
  * irreversibly. If `acts` carries a question aimed at you and you know the answer,
2716
3975
  * contact on the same thread right away — the caller hears it on the same call. */
2717
- z.object({
2718
- type: z.literal("partial"),
2719
- notificationId: z.string(),
2720
- inFlight: z.literal(true),
2721
- turn: z.object({
2722
- idx: z.number(),
2723
- prompt: z.string(),
2724
- reply: z.string(),
2725
- acts: z.array(IntentSchema).nullable().optional()
3976
+ z2.object({
3977
+ type: z2.literal("partial"),
3978
+ notificationId: z2.string(),
3979
+ inFlight: z2.literal(true),
3980
+ turn: z2.object({
3981
+ idx: z2.number(),
3982
+ prompt: z2.string(),
3983
+ reply: z2.string(),
3984
+ acts: z2.array(IntentSchema).nullable().optional()
2726
3985
  })
2727
3986
  }),
2728
- z.object({ type: z.literal("idle"), also: z.array(RideAlongSchema).optional() })
3987
+ z2.object({ type: z2.literal("idle"), also: z2.array(RideAlongSchema).optional() })
2729
3988
  ]);
2730
- var CallbackTriggerSchema = z.enum(["on_done", "on_blocked", "scheduled"]);
2731
- var ScheduleCallbackSchema = z.object({
2732
- parentId: z.string().describe("The thread to call back on (from a prior contact / reply / request)."),
3989
+ var CallbackTriggerSchema = z2.enum(["on_done", "on_blocked", "scheduled"]);
3990
+ var ScheduleCallbackSchema = z2.object({
3991
+ parentId: z2.string().describe("The thread to call back on (from a prior contact / reply / request)."),
2733
3992
  trigger: CallbackTriggerSchema,
2734
- dueInSeconds: z.number().int().positive().optional().describe("For 'scheduled' only: how many seconds from now to fire."),
2735
- note: z.string().optional().describe("What to tell the user when you follow up.")
3993
+ dueInSeconds: z2.number().int().positive().optional().describe("For 'scheduled' only: how many seconds from now to fire."),
3994
+ note: z2.string().optional().describe("What to tell the user when you follow up.")
2736
3995
  });
2737
- var PendingRepliesSchema = z.object({
2738
- replies: z.array(
2739
- z.object({
2740
- parentId: z.string(),
2741
- notificationId: z.string(),
3996
+ var PendingRepliesSchema = z2.object({
3997
+ replies: z2.array(
3998
+ z2.object({
3999
+ parentId: z2.string(),
4000
+ notificationId: z2.string(),
4001
+ workId: z2.string().uuid().optional(),
4002
+ decisionId: z2.string().uuid().optional(),
2742
4003
  answer: UserAnswerSchema,
2743
4004
  /** E2EE: the sealed answer (opaque envelope + plaintext `ignored` hint) when the
2744
4005
  * pairing is E2EE — the agent opens it and re-derives the real answer. Absent =
2745
4006
  * plaintext answer (in `answer`). See AwaitItemSchema's reply variant. */
2746
- sealed: z.lazy(() => SealedAnswerSchema).optional(),
2747
- /** Broker extras (#381): next steps the user attached to a call-mapped answer
2748
- * ("call me after lunch" → defer — act on it via schedule_callback) and the
2749
- * raw words the shaped answer was mapped from. */
2750
- intents: z.array(IntentSchema).optional(),
2751
- transcript: z.string().optional(),
4007
+ sealed: z2.lazy(() => SealedAnswerSchema).optional(),
4008
+ /** The call record rendered for THIS agent: the raw words the shaped answer was
4009
+ * mapped from, filtered to its own claims. See AwaitItemSchema's reply variant. */
4010
+ transcript: z2.string().optional(),
2752
4011
  /** Coverage report (#396): which declared `points` this answer addressed. */
2753
- covered: z.array(z.string()).optional()
4012
+ covered: z2.array(z2.string()).optional()
2754
4013
  })
2755
4014
  ),
2756
- pending: z.array(
2757
- z.object({ parentId: z.string(), notificationId: z.string(), createdAt: z.string() })
4015
+ pending: z2.array(
4016
+ z2.object({ parentId: z2.string(), notificationId: z2.string(), createdAt: z2.string() })
2758
4017
  ),
2759
4018
  /** WHO YOU ARE on this account (field report 2026-08-28): the name and device the user
2760
4019
  * sees for this session's identity. From inside a session there was no way to find out —
2761
4020
  * `pair` with no arguments can HATCH a fresh identity, so it is not a safe probe — and an
2762
4021
  * agent that cannot tell which agent it is cannot tell whether work addressed to
2763
4022
  * "Reta" was addressed to it. Absent only for a token with no pairing behind it. */
2764
- you: z.object({ name: z.string(), device: z.string().nullable(), tokenId: z.string() }).optional(),
4023
+ you: z2.object({ name: z2.string(), device: z2.string().nullable(), tokenId: z2.string() }).optional(),
2765
4024
  /** User-initiated requests addressed to this agent; act on them and reply via
2766
4025
  * contact on the same parentId. Keeps reappearing until you call
2767
- * set_task_state on its notificationId. */
2768
- requests: z.array(
2769
- z.object({
2770
- parentId: z.string(),
2771
- notificationId: z.string(),
2772
- text: z.string(),
2773
- createdAt: z.string(),
4026
+ * set_work_state on its workId (or notificationId once while bootstrapping). */
4027
+ requests: z2.array(
4028
+ z2.object({
4029
+ parentId: z2.string(),
4030
+ notificationId: z2.string(),
4031
+ workId: z2.string().uuid().optional(),
4032
+ text: z2.string(),
4033
+ createdAt: z2.string(),
2774
4034
  /** The user seeded this request with a past conversation — call get_thread on it
2775
4035
  * FIRST and treat the transcript as prior context (#57/#251). */
2776
- contextParentId: z.string().optional(),
4036
+ contextParentId: z2.string().optional(),
2777
4037
  /** STRANDED (field report 2026-08-28): this request was addressed to ANOTHER agent on
2778
4038
  * the account — the name here — which has not been seen since it landed, so nobody
2779
4039
  * came for it. Handed to you because you are the session that is here. Take it like
2780
- * any request (set_task_state claims it, reply with contact on its parentId), and say
4040
+ * any request (set_work_state claims it, reply with contact on its parentId), and say
2781
4041
  * whose it was, because the user chose that agent on purpose. */
2782
- stranded: z.string().optional()
4042
+ stranded: z2.string().optional()
2783
4043
  })
2784
4044
  ),
4045
+ /** Durable outcomes currently owned by this agent. This is the Work-native queue; flat
4046
+ * notification lists remain during migration so old clients keep their existing view. */
4047
+ work: z2.array(z2.object({
4048
+ workId: z2.string().uuid(),
4049
+ parentId: z2.string().optional(),
4050
+ objective: z2.string().nullable(),
4051
+ state: z2.enum(["active", "blocked", "waiting_external"]),
4052
+ blockedOn: z2.array(z2.string().uuid()),
4053
+ updatedAt: z2.string()
4054
+ })).optional(),
2785
4055
  /** Callbacks you owe the user that are now DUE (you said you'd follow up when done,
2786
4056
  * if blocked, or at a time that has passed). Re-surfaced every sweep until you
2787
4057
  * fulfill one by calling contact on its parentId. */
2788
4058
  /** Ride-alongs (RideAlongSchema): notes assigned to this agent that no wake could
2789
4059
  * reach. Same array the contact/await replies carry — one queue, every carrier. */
2790
- also: z.array(RideAlongSchema).optional(),
2791
- owedCallbacks: z.array(
2792
- z.object({ parentId: z.string(), trigger: CallbackTriggerSchema, note: z.string() })
4060
+ also: z2.array(RideAlongSchema).optional(),
4061
+ owedCallbacks: z2.array(
4062
+ z2.object({ parentId: z2.string(), trigger: CallbackTriggerSchema, note: z2.string() })
2793
4063
  ),
2794
4064
  /** Work (either direction) you reported in_progress a while ago and never reported
2795
4065
  * completed — likely left half-done by this session or a prior one that crashed or
2796
- * went idle. Report a real state (set_task_state) or continue the work. */
2797
- stalled: z.array(
2798
- z.object({ parentId: z.string(), notificationId: z.string(), title: z.string().nullable(), startedAt: z.string() })
4066
+ * went idle. Report a real state (set_work_state) or continue the work. */
4067
+ stalled: z2.array(
4068
+ z2.object({ parentId: z2.string(), notificationId: z2.string(), title: z2.string().nullable(), startedAt: z2.string() })
2799
4069
  ),
2800
4070
  /** The queue rail (#614, pending/design.md): the same replies + requests, grouped by
2801
4071
  * thread and ordered oldest-thread-first, so you work ONE thread at a time — fold all of
@@ -2804,123 +4074,125 @@ var PendingRepliesSchema = z.object({
2804
4074
  * ride the next turn. `items` are that thread's replies/requests in arrival order; the
2805
4075
  * full payload for each is in the flat `replies`/`requests` arrays (matched by
2806
4076
  * notificationId). Derived, never stored — a crashed agent recomputes it exactly. */
2807
- threads: z.array(
2808
- z.object({
2809
- parentId: z.string(),
2810
- busy: z.boolean(),
2811
- items: z.array(
2812
- z.object({
2813
- kind: z.enum(["reply", "request"]),
2814
- notificationId: z.string(),
2815
- at: z.string()
4077
+ threads: z2.array(
4078
+ z2.object({
4079
+ parentId: z2.string(),
4080
+ busy: z2.boolean(),
4081
+ items: z2.array(
4082
+ z2.object({
4083
+ kind: z2.enum(["reply", "request"]),
4084
+ notificationId: z2.string(),
4085
+ at: z2.string()
2816
4086
  })
2817
4087
  )
2818
4088
  })
2819
4089
  )
2820
4090
  });
2821
- var NotifyResponseSchema = z.object({
2822
- notificationId: z.string(),
4091
+ var NotifyResponseSchema = z2.object({
4092
+ notificationId: z2.string(),
4093
+ workId: z2.string().uuid().optional(),
4094
+ decisionId: z2.string().uuid().optional(),
2823
4095
  status: NotifyStatusSchema,
2824
- createdAt: z.string().datetime(),
4096
+ createdAt: z2.string().datetime(),
2825
4097
  answer: UserAnswerSchema.optional(),
2826
- answeredAt: z.string().datetime().optional(),
4098
+ answeredAt: z2.string().datetime().optional(),
2827
4099
  /** Ride-alongs for THIS agent — pending work it should pick up when it's done with
2828
4100
  * what it came for. Present on any reply, because an unwakeable agent's only
2829
4101
  * reliable moment is one it initiated. Absent/empty = nothing owed. */
2830
- also: z.array(RideAlongSchema).optional()
4102
+ also: z2.array(RideAlongSchema).optional()
2831
4103
  });
2832
- var NotifyPlanUnitSchema = z.object({
2833
- notificationId: z.string(),
4104
+ var NotifyPlanUnitSchema = z2.object({
4105
+ notificationId: z2.string(),
2834
4106
  /** The unit's own heading, so the agent can tell which of its paragraphs this became. */
2835
- title: z.string(),
4107
+ title: z2.string(),
2836
4108
  /** How loudly this unit was arbitrated to arrive — per unit, which is the point of units. */
2837
4109
  level: NotifyLevelSchema,
2838
4110
  /** Answered from something the user already decided: nobody is interrupted, and a trail card
2839
4111
  * says so. The agent should not wait on this one. */
2840
- settled: z.literal(true).optional(),
4112
+ settled: z2.literal(true).optional(),
2841
4113
  /** What this unit would need to be answerable and does not carry (#894). A PROPOSAL to the
2842
4114
  * agent — nothing here changed the ask, and ignoring it costs nothing. */
2843
- needs: z.array(z.enum(["options", "visuals"])).optional(),
4115
+ needs: z2.array(z2.enum(["options", "visuals"])).optional(),
2844
4116
  /** The SHAPE the broker would give this unit, for the agent to ratify (#886/#894). The
2845
4117
  * split layer reads prose and can see that a paragraph is a yes/no or a pick-one — but a
2846
4118
  * broker that DECIDES that destroys the only fact separating a statement from a real ask
2847
4119
  * (#731), so it is offered, never applied: the unit is stored `text` until the agent
2848
4120
  * confirms the shape (POST /notify/:id/confirm). Ignoring it costs nothing. */
2849
- proposal: z.object({
4121
+ proposal: z2.object({
2850
4122
  select: SelectShapeSchema,
2851
- options: z.array(z.object({ label: z.string().min(1) })).optional()
4123
+ options: z2.array(z2.object({ label: z2.string().min(1) })).optional()
2852
4124
  }).optional(),
2853
4125
  /** What the broker READ this unit as wanting from the human (#952 layer 2): a `decision`
2854
4126
  * between alternatives, an `approval` the agent is blocked on, or `knowledge` it just
2855
4127
  * needs to know. Reported so the agent can correct a misread the same way it ratifies a
2856
4128
  * shape — the read RAISES (a decision always asks) and never silences a question the
2857
4129
  * agent declared (#731, #923). */
2858
- wants: z.enum(["decision", "approval", "knowledge"]).optional()
4130
+ wants: z2.enum(["decision", "approval", "knowledge"]).optional()
2859
4131
  });
2860
- var NotifyPlanSchema = z.object({
2861
- units: z.array(NotifyPlanUnitSchema),
4132
+ var NotifyPlanSchema = z2.object({
4133
+ units: z2.array(NotifyPlanUnitSchema),
2862
4134
  /** Which unit is this arrival's ONE interruption (units-design.md D23). Absent means nobody
2863
4135
  * was interrupted — every unit was either settled or quiet enough to sit in the inbox. */
2864
- speaks: z.string().optional()
4136
+ speaks: z2.string().optional()
2865
4137
  });
2866
- var UserResponseSchema = z.object({
2867
- requestId: z.string(),
4138
+ var UserResponseSchema = z2.object({
4139
+ requestId: z2.string(),
2868
4140
  answer: UserAnswerSchema,
2869
- answeredAt: z.string().datetime(),
2870
- intents: z.array(IntentSchema).optional(),
2871
- transcript: z.string().optional(),
4141
+ answeredAt: z2.string().datetime(),
4142
+ transcript: z2.string().optional(),
2872
4143
  /** E2EE: the sealed answer (opaque envelope + plaintext `ignored` hint) when the item was
2873
4144
  * E2EE-sealed. Present → the server persists it opaquely and branches status on `ignored`;
2874
4145
  * the plaintext `answer` is a placeholder (`{ kind: "ignored" }`) the server ignores for a
2875
4146
  * sealed row. Absent = today's plaintext answer, unchanged. */
2876
- sealed: z.lazy(() => SealedAnswerSchema).optional(),
4147
+ sealed: z2.lazy(() => SealedAnswerSchema).optional(),
2877
4148
  /** Coverage report (#396): which of the ask's declared `points` were addressed. */
2878
- covered: z.array(z.string()).optional()
4149
+ covered: z2.array(z2.string()).optional()
2879
4150
  });
2880
- var VoiceKeySchema = z.enum(["rachel", "george", "jessica", "brian", "lily"]);
2881
- var AgendaTurnSchema = z.object({
4151
+ var VoiceKeySchema = z2.enum(["rachel", "george", "jessica", "brian", "lily"]);
4152
+ var AgendaTurnSchema = z2.object({
2882
4153
  /** Twin coverage (#1089): sibling claim ids this asking turn's answer ALSO settles —
2883
4154
  * the planner declares duplicates instead of asking them twice. */
2884
- coveredIds: z.array(z.string()).optional(),
4155
+ coveredIds: z2.array(z2.string()).optional(),
2885
4156
  /** At most three short spoken sentences. Capped because a turn is a breath: a 1031-char
2886
4157
  * line went out on 2026-07-28 and the caller could not answer it at all. */
2887
- info: z.array(z.string().min(1)).max(3).default([]),
2888
- question: z.string().min(1).nullable(),
4158
+ info: z2.array(z2.string().min(1)).max(3).default([]),
4159
+ question: z2.string().min(1).nullable(),
2889
4160
  /** True on the one turn carrying the agent's own declared question. */
2890
- asks: z.boolean().optional(),
4161
+ asks: z2.boolean().optional(),
2891
4162
  /** The claim this turn belongs to (#781) — the RETURN identity: answers route by it.
2892
4163
  * Absent on a single-claim plan (the session's own claim) and on shared context turns,
2893
4164
  * which route nothing. */
2894
- claimId: z.string().optional(),
4165
+ claimId: z2.string().optional(),
2895
4166
  /** The claim's voice key (#462) — the OUTBOUND identity, audible who-is-asking. */
2896
- voice: z.string().optional(),
4167
+ voice: z2.string().optional(),
2897
4168
  /** The claim's AGENT NAME (#838) — the spoken identity. A voice alone doesn't say
2898
4169
  * whose request this is: an item that folded in from another agent arrived as a bare
2899
4170
  * non-sequitur ("First real production sign-in is yours to make whenever you want.")
2900
4171
  * and the owner answered "What?". The bot names the agent before its first turn. */
2901
- agent: z.string().optional(),
4172
+ agent: z2.string().optional(),
4173
+ /** The claim's agent by ID — the pairing's connection id (`notifications.token_id`), the
4174
+ * same id a face is minted from. A name is not an identity: two pairings may be called
4175
+ * "Claude", and a name cannot be joined on. The record's entries carry it (`agent_id`)
4176
+ * so "who said that" survives the call, and it rides PER TURN because a coalesced call
4177
+ * speaks for several agents — the turn is the only place that knows which. */
4178
+ agentId: z2.string().optional(),
2902
4179
  select: SelectShapeSchema.optional(),
2903
- options: z.array(OptionSchema.omit({ id: true })).optional(),
2904
- /** The seat was satisfied by the call's own ACCOUNT (replan-design.md, user_info): the
2905
- * caller already answered this claim in an earlier utterance, quoted here VERBATIM —
2906
- * the bot speaks the turn's short confirmation, posts these words as the claim's
2907
- * answer, and never re-asks. Grounded at parse time: an invented settle is #796. */
2908
- settle: z.string().optional(),
4180
+ options: z2.array(OptionSchema.omit({ id: true })).optional(),
2909
4181
  /** Pacing (#826, owner 2026-08-03: "how fast we move through them ... are parameters"):
2910
4182
  * seconds the floor stays open after this turn speaks. Absent = the bot's defaults
2911
4183
  * (the beat for context, the answer window for asks). Clamped bot-side. */
2912
- pace: z.number().positive().optional(),
4184
+ pace: z2.number().positive().optional(),
2913
4185
  /** Whether the walk WAITS for an answer before moving on. Absent = derived as today
2914
4186
  * (a question blocks, context flows). blocking:false on a question = ask and move
2915
4187
  * on, the claim stays pending; blocking:true on context = hold for a reply. */
2916
- blocking: z.boolean().optional()
4188
+ blocking: z2.boolean().optional()
2917
4189
  });
2918
4190
  var CLAIM_STALE_MS = 30 * 6e4;
2919
- var InboxItemSchema = z.object({
2920
- id: z.string(),
4191
+ var InboxItemSchema = z2.object({
4192
+ id: z2.string(),
2921
4193
  /** The conversation thread + connection this item lives on. Present on the replied
2922
4194
  * detail — they power History's "Continue" / "New session from this" (#57/#251). */
2923
- parentId: z.string().optional(),
4195
+ parentId: z2.string().optional(),
2924
4196
  /** THE ARRIVAL this row is one unit of (`notifications.ask_id` → `asks`). A claim is one
2925
4197
  * arrival and its units are N rows of it, so this — not `parentId` — is what makes a
2926
4198
  * multi-part notification one thing on screen. The thread is the whole CONVERSATION: it
@@ -2928,13 +4200,13 @@ var InboxItemSchema = z.object({
2928
4200
  * unrelated updates as a single "12-part request". Absent on rows written before the
2929
4201
  * `asks` table, and on anything that never went through `notify` — both fall back to the
2930
4202
  * thread, which is what the client did for all rows until now. */
2931
- askId: z.string().optional(),
4203
+ askId: z2.string().optional(),
2932
4204
  /** WHERE this unit sat in the message it was cut from (`notifications.seq`). The batch
2933
4205
  * shares one `created_at` to the microsecond, so without it the author's order is
2934
4206
  * unrecoverable client-side — a four-paragraph briefing rendered opening-paragraph-last
2935
4207
  * (live 2026-08-10, D35). The API already orders by it; this lets a reader that
2936
4208
  * re-sorts (grouping, filtering) put an arrival back in the order it was written. */
2937
- seq: z.number().int().optional(),
4209
+ seq: z2.number().int().optional(),
2938
4210
  /** HOW MANY units the arrival was cut into. A device reads a LENS, never the arrival —
2939
4211
  * `/api/inbox` serves `open`, so the units already settled are gone from it — and a client
2940
4212
  * counting what it can see is counting what is LEFT. Walking a three-unit ask on the answer
@@ -2943,13 +4215,13 @@ var InboxItemSchema = z.object({
2943
4215
  * server that can still see every row states it. Absent on any row with no `askId`: a
2944
4216
  * unit knows WHICH ask it came from and WHERE it sat in it, and how many there were is
2945
4217
  * the one part of its own arrival a single row cannot answer. */
2946
- units: z.number().int().positive().optional(),
2947
- tokenId: z.string().optional(),
4218
+ units: z2.number().int().positive().optional(),
4219
+ tokenId: z2.string().optional(),
2948
4220
  status: NotifyStatusSchema,
2949
4221
  context: ContextSchema,
2950
- options: z.array(OptionSchema).optional(),
4222
+ options: z2.array(OptionSchema).optional(),
2951
4223
  /** The ask's declared coverage points (#396), when the agent sent them. */
2952
- points: z.array(z.string()).optional(),
4224
+ points: z2.array(z2.string()).optional(),
2953
4225
  /** The call's AGENDA (broker/agenda-design.md): the ordered turns it is made of, built at
2954
4226
  * ring/enqueue time. Replaces the condensed line + index-aligned phrased points, which
2955
4227
  * between them could not express a call as a sequence. `question: null` is a real turn —
@@ -2958,12 +4230,12 @@ var InboxItemSchema = z.object({
2958
4230
  * `requestAsks` — the agent's own declaration, not a guess. `false` is what earns a card
2959
4231
  * its acknowledge affordance: without it a status update offers a text box and a dismiss,
2960
4232
  * and neither of those is "got it" (owner, 2026-08-10). */
2961
- asks: z.boolean().optional(),
4233
+ asks: z2.boolean().optional(),
2962
4234
  /** When a live process last pulsed for this row's agent — the liveness input for
2963
4235
  * "working requires a pulse" (#928): the list said "Working…" from agent_state alone
2964
4236
  * while the party called the same dead claim stalled. Absent = no token/no data,
2965
4237
  * which must never CLAIM stalled. */
2966
- lastSeenAt: z.string().optional(),
4238
+ lastSeenAt: z2.string().optional(),
2967
4239
  /** WHEN THE AGENT LAST SAID ANYTHING ABOUT THIS CLAIM — the newest `agent_state` row in
2968
4240
  * the `notification_events` ledger (trigger-written since 20260621010000, so every row a
2969
4241
  * user can see has one). The age input for `CLAIM_STALE_MS`, and it has to be this rather
@@ -2973,56 +4245,53 @@ var InboxItemSchema = z.object({
2973
4245
  * work. Reading the row's birth as the claim's age brands that "No update in 8h" the
2974
4246
  * instant the agent picks it up (#997). Absent = pre-trigger row; fall back to
2975
4247
  * `createdAt`. */
2976
- agentStateAt: z.string().datetime().optional(),
2977
- agenda: z.array(AgendaTurnSchema).optional(),
2978
- /** On a replied detail (#397): the next steps the user attached to the answer
2979
- * ("call back after lunch") — shown so they can see the commitment was captured. */
2980
- intents: z.array(IntentSchema).optional(),
2981
- visuals: z.array(VisualSchema).optional(),
4248
+ agentStateAt: z2.string().datetime().optional(),
4249
+ agenda: z2.array(AgendaTurnSchema).optional(),
4250
+ visuals: z2.array(VisualSchema).optional(),
2982
4251
  /** The connected agent's name (the single pairing name — user-typed, or the
2983
4252
  * agent's suggestion, or a default silly name). */
2984
- name: z.string(),
4253
+ name: z2.string(),
2985
4254
  /** The pairing's assigned voice (#462); absent = the default voice. */
2986
4255
  voice: VoiceKeySchema.optional(),
2987
- repo: z.string().optional(),
2988
- branch: z.string().optional(),
2989
- createdAt: z.string().datetime(),
2990
- snoozedUntil: z.string().datetime().optional(),
4256
+ repo: z2.string().optional(),
4257
+ branch: z2.string().optional(),
4258
+ createdAt: z2.string().datetime(),
4259
+ snoozedUntil: z2.string().datetime().optional(),
2991
4260
  agentState: AgentStateSchema.default("idle"),
2992
4261
  /** Whose action the item is waiting on: "you" = an agent asked you (the default,
2993
4262
  * every agent→user notification); "agent" = you sent a request and it's awaiting the
2994
4263
  * agent (held in the inbox until the agent replies on the thread). */
2995
- turn: z.enum(["you", "agent"]).default("you"),
4264
+ turn: z2.enum(["you", "agent"]).default("you"),
2996
4265
  /** Hard error reason on an awaiting request (turn="agent") — the wake failed to reach
2997
4266
  * the agent (provider-agnostic; set server-side). Absent = no hard error, though the
2998
4267
  * client may still flag a stall by age. Drives the inbox error badge + Retry. */
2999
- error: z.string().optional(),
3000
- clarifies: z.string().optional(),
4268
+ error: z2.string().optional(),
4269
+ clarifies: z2.string().optional(),
3001
4270
  /** The ring ladder ran out while this was still pending — we tried to reach you and
3002
4271
  * STOPPED trying (`arbitration/arbitrate.ts` `nextRing` → `stop`). Distinct from an
3003
4272
  * agent with nothing to say, which the roster drew identically until now: "nothing to
3004
4273
  * say" and "gave up saying it" are opposite situations wearing the same face
3005
4274
  * (navigation-design.md, gap 1). False for anything that never rang. */
3006
- gaveUp: z.boolean().default(false),
4275
+ gaveUp: z2.boolean().default(false),
3007
4276
  /** Why this arrived the way it did, read back off the delivery receipt (`notify/why.ts`).
3008
4277
  * Absent for anything never delivered through a push, and for older rows written before
3009
4278
  * the reason was recorded. Deliberately a debug affordance, shown small (owner,
3010
4279
  * 2026-08-07) — its real job is to give "this didn't need a call" something to be
3011
4280
  * feedback ABOUT. */
3012
- why: z.object({
4281
+ why: z2.object({
3013
4282
  asked: NotifyLevelSchema,
3014
4283
  got: NotifyLevelSchema,
3015
- because: z.enum(["unresponsive", "dismissed", "not_permitted", "silent", "coalesced", "agent_capped", "unplanned", "learned_raise"]).optional(),
3016
- line: z.string()
4284
+ because: z2.enum(["unresponsive", "dismissed", "not_permitted", "silent", "coalesced", "agent_capped", "unplanned", "learned_raise"]).optional(),
4285
+ line: z2.string()
3017
4286
  }).optional(),
3018
- select: z.enum(["one", "many", "rank", "confirm", "text"]).default("one"),
3019
- confirmStyle: z.enum(["yesno", "approve"]).default("yesno").describe(
4287
+ select: z2.enum(["one", "many", "rank", "confirm", "text"]).default("one"),
4288
+ confirmStyle: z2.enum(["yesno", "approve"]).default("yesno").describe(
3020
4289
  "Labels for a select:'confirm' paige \u2014 'yesno' (Yes/No) or 'approve' (Approve/Deny). Ignored unless select is 'confirm'."
3021
4290
  ),
3022
4291
  /** Real downstream work is stuck behind this one — set by the agent, independent of
3023
4292
  * urgency (see the main README's "premier use case" + notify/states.md). Drives the
3024
4293
  * inbox's blocking badge and the extra confirm step before dismissing it. */
3025
- blocking: z.boolean().default(false),
4294
+ blocking: z2.boolean().default(false),
3026
4295
  /** The user's locked-in answer; present only for replied items (GET /api/replied/:id). */
3027
4296
  answer: UserAnswerSchema.optional(),
3028
4297
  /** E2EE (text lane): the sealed content this item carries when the pairing is E2EE, in
@@ -3031,39 +4300,39 @@ var InboxItemSchema = z.object({
3031
4300
  * NotifyRequest.envelope. The native app decrypts it locally via openNotification;
3032
4301
  * web / an un-enrolled device can't and renders a locked placeholder. Absent = today's
3033
4302
  * plaintext item (context carries the cleartext), so plaintext items are unchanged. */
3034
- envelope: z.object({
3035
- context: z.lazy(() => EnvelopeSchema).optional(),
3036
- options: z.lazy(() => EnvelopeSchema).optional(),
3037
- visuals: z.lazy(() => EnvelopeSchema).optional()
4303
+ envelope: z2.object({
4304
+ context: z2.lazy(() => EnvelopeSchema).optional(),
4305
+ options: z2.lazy(() => EnvelopeSchema).optional(),
4306
+ visuals: z2.lazy(() => EnvelopeSchema).optional()
3038
4307
  }).optional(),
3039
4308
  /** E2EE: the agent's device X25519 public key to seal the user's answer BACK to (the
3040
4309
  * sender the phone replies to). Sourced server-side from this item's pairing credential.
3041
4310
  * Present only alongside `envelope`; the phone seals via sealAnswer(answer, this, id). */
3042
- agentX25519: z.string().optional()
4311
+ agentX25519: z2.string().optional()
3043
4312
  });
3044
- var SnoozeRequestSchema = z.object({
3045
- requestId: z.string(),
3046
- until: z.string().datetime()
4313
+ var SnoozeRequestSchema = z2.object({
4314
+ requestId: z2.string(),
4315
+ until: z2.string().datetime()
3047
4316
  });
3048
4317
  var APNS_TOKEN_RE = /^[0-9a-fA-F]{64}$/;
3049
- var PushTokenSchema = z.object({
3050
- voipToken: z.string().min(1).optional(),
3051
- alertToken: z.string().min(1).optional(),
3052
- fcmToken: z.string().min(1).optional(),
3053
- platform: z.enum(["ios", "android"])
4318
+ var PushTokenSchema = z2.object({
4319
+ voipToken: z2.string().min(1).optional(),
4320
+ alertToken: z2.string().min(1).optional(),
4321
+ fcmToken: z2.string().min(1).optional(),
4322
+ platform: z2.enum(["ios", "android"])
3054
4323
  }).superRefine((v, ctx) => {
3055
4324
  if (v.platform !== "ios") return;
3056
4325
  for (const field of ["voipToken", "alertToken"]) {
3057
4326
  const token = v[field];
3058
4327
  if (token === void 0 || APNS_TOKEN_RE.test(token)) continue;
3059
4328
  ctx.addIssue({
3060
- code: z.ZodIssueCode.custom,
4329
+ code: z2.ZodIssueCode.custom,
3061
4330
  path: [field],
3062
4331
  message: `not an APNs device token (want 64 hex chars, got ${token.length})`
3063
4332
  });
3064
4333
  }
3065
4334
  });
3066
- var MissedCallSchema = z.enum([
4335
+ var MissedCallSchema = z2.enum([
3067
4336
  "retry_10m",
3068
4337
  "retry_30m",
3069
4338
  "retry_60m",
@@ -3073,32 +4342,32 @@ var MissedCallSchema = z.enum([
3073
4342
  "inbox",
3074
4343
  "dismiss"
3075
4344
  ]);
3076
- var BrokerTuningSchema = z.object({
4345
+ var BrokerTuningSchema = z2.object({
3077
4346
  /** 'none' = skip the spoken ack after a mapped answer (power users find it slow). */
3078
- ackVerbosity: z.enum(["normal", "none"]).optional(),
4347
+ ackVerbosity: z2.enum(["normal", "none"]).optional(),
3079
4348
  /** How readily the mapper asks its one clarification: 'low' = only when truly
3080
4349
  * uninterpretable, 'high' = whenever not fully certain. */
3081
- clarifyEagerness: z.enum(["low", "normal", "high"]).optional(),
4350
+ clarifyEagerness: z2.enum(["low", "normal", "high"]).optional(),
3082
4351
  /** The user's own shorthand: when they say `say`, they mean `mean`. */
3083
- phrasebook: z.array(z.object({ say: z.string().min(1).max(60), mean: z.string().min(1).max(120) })).max(24).optional(),
4352
+ phrasebook: z2.array(z2.object({ say: z2.string().min(1).max(60), mean: z2.string().min(1).max(120) })).max(24).optional(),
3084
4353
  /** The language calls are PLANNED in, when the account has chosen one (#1272). Absent —
3085
4354
  * which is every account today — means the agent's own words decide, per ask: a call
3086
4355
  * about an English ask opens in English. This is the only thing that overrides that,
3087
4356
  * and a live caller who switches language mid-call still outranks it (broker/lang.ts).
3088
4357
  * Set per user (no UI yet), like `voiceTuning`. */
3089
- language: z.enum(["en", "es"]).optional()
4358
+ language: z2.enum(["en", "es"]).optional()
3090
4359
  });
3091
- var UserSettingsSchema = z.object({
3092
- permissions: z.object({
3093
- call: z.boolean(),
3094
- banner: z.boolean(),
3095
- push: z.boolean()
4360
+ var UserSettingsSchema = z2.object({
4361
+ permissions: z2.object({
4362
+ call: z2.boolean(),
4363
+ banner: z2.boolean(),
4364
+ push: z2.boolean()
3096
4365
  }),
3097
- sessionMode: z.enum(["default", "all_calls", "silent"]),
3098
- silentPush: z.boolean(),
3099
- autoCallback: z.boolean(),
4366
+ sessionMode: z2.enum(["default", "all_calls", "silent"]),
4367
+ silentPush: z2.boolean(),
4368
+ autoCallback: z2.boolean(),
3100
4369
  /** Opt-in (default false) to using your content to improve Paigy and train models. */
3101
- improveConsent: z.boolean(),
4370
+ improveConsent: z2.boolean(),
3102
4371
  missedCall: MissedCallSchema.default("backoff_standard"),
3103
4372
  /** Where voice audio is processed. 'hosted' (default) = Paigy's voice services
3104
4373
  * (ElevenLabs TTS, faster-whisper STT, the call bot); 'on_device' = the phone
@@ -3106,7 +4375,7 @@ var UserSettingsSchema = z.object({
3106
4375
  * Optional, NOT defaulted: a stale client PATCHing the full settings object
3107
4376
  * must not silently reset this privacy choice. Absent = leave unchanged on
3108
4377
  * write, 'hosted' on read (see store.ts). */
3109
- voiceMode: z.enum(["hosted", "on_device"]).optional(),
4378
+ voiceMode: z2.enum(["hosted", "on_device"]).optional(),
3110
4379
  /** Per-user ring budget (#603): calls per rolling day before further calls
3111
4380
  * degrade to banner. Absent = the global default (25). A number, never a
3112
4381
  * bypass — every account keeps a ceiling. No UI; set per user for testing. */
@@ -3114,10 +4383,10 @@ var UserSettingsSchema = z.object({
3114
4383
  * payload['tuning'] (e.g. { silence_s: 3.5 } — a longer pause window for a
3115
4384
  * slower speaker). No API-side semantics; the bot resolves each key with its
3116
4385
  * own defaults. Set per user (no UI yet); absent = bot defaults. */
3117
- voiceTuning: z.record(z.string(), z.union([z.number(), z.string()])).optional(),
4386
+ voiceTuning: z2.record(z2.string(), z2.union([z2.number(), z2.string()])).optional(),
3118
4387
  /** Opt-in to real-phone (PSTN) calls when the app can't ring. Optional, not
3119
4388
  * defaulted — an older client PATCHing the full object must not clobber it. */
3120
- pstnCalls: z.boolean().optional(),
4389
+ pstnCalls: z2.boolean().optional(),
3121
4390
  /** The user's IANA timezone (e.g. "America/Bogota"), recorded by the app — it is the
3122
4391
  * only party that knows it. REMINDERS are why it exists: "remind me at ten" becomes
3123
4392
  * an absolute `due_at` only if we know whose ten. Optional and never defaulted, for
@@ -3126,50 +4395,50 @@ var UserSettingsSchema = z.object({
3126
4395
  * that failure reads as the reminder rail being unreliable rather than as a missing
3127
4396
  * setting. Absent = a spoken time can't be landed, so the reminder rides the next
3128
4397
  * call — honest about what we know. */
3129
- timezone: z.string().min(1).max(64).optional(),
4398
+ timezone: z2.string().min(1).max(64).optional(),
3130
4399
  /** Account E2EE state (text lane): 'off' (default) = today's plaintext; 'on' =
3131
4400
  * content is sealed end-to-end between the local agent and the phone. Like
3132
4401
  * voiceMode, OPTIONAL and NOT defaulted so a stale client PATCHing the full
3133
4402
  * settings object without it can't silently flip the account's E2EE state.
3134
4403
  * Absent = leave unchanged on write, 'off' on read (see store.ts). The demo
3135
4404
  * account is plaintext by construction and refuses any non-'off' value. */
3136
- e2eeMode: z.enum(["off", "on"]).optional(),
4405
+ e2eeMode: z2.enum(["off", "on"]).optional(),
3137
4406
  /** Rung-2 broker tuning (#381). Optional and NOT defaulted, same stale-client
3138
4407
  * clobber guard as voiceMode: absent = leave unchanged on write. */
3139
4408
  broker: BrokerTuningSchema.optional()
3140
4409
  });
3141
- var HistoryItemSchema = z.object({
3142
- id: z.string(),
3143
- parentId: z.string(),
4410
+ var HistoryItemSchema = z2.object({
4411
+ id: z2.string(),
4412
+ parentId: z2.string(),
3144
4413
  /** 'user' = a request you sent; 'agent' = a notification an agent sent you. */
3145
- initiator: z.enum(["user", "agent"]),
3146
- title: z.string(),
4414
+ initiator: z2.enum(["user", "agent"]),
4415
+ title: z2.string(),
3147
4416
  /** The agent on the other end (its name). */
3148
- name: z.string(),
3149
- createdAt: z.string(),
4417
+ name: z2.string(),
4418
+ createdAt: z2.string(),
3150
4419
  /** When the agent fetched your request (user→agent only). */
3151
- agentAckedAt: z.string().nullable(),
4420
+ agentAckedAt: z2.string().nullable(),
3152
4421
  /** When you answered the agent's notification (agent→user only). */
3153
- humanAckedAt: z.string().nullable()
4422
+ humanAckedAt: z2.string().nullable()
3154
4423
  });
3155
4424
  var ACTIVITY_LINES = 2;
3156
4425
  var ACTIVITY_LINE_MAX = 80;
3157
- var AgentActivitySchema = z.object({
4426
+ var AgentActivitySchema = z2.object({
3158
4427
  /** Oldest first, so the newest line is last — the one that replaces in place. */
3159
- lines: z.array(z.string().max(ACTIVITY_LINE_MAX)).max(ACTIVITY_LINES),
4428
+ lines: z2.array(z2.string().max(ACTIVITY_LINE_MAX)).max(ACTIVITY_LINES),
3160
4429
  /** When the harness observed this tail. Its own timestamp, not the heartbeat's: a beat
3161
4430
  * that carries an UNCHANGED tail must not make a stalled agent look like it just moved. */
3162
- at: z.string().datetime()
4431
+ at: z2.string().datetime()
3163
4432
  });
3164
- var ConnectionSummarySchema = z.object({
4433
+ var ConnectionSummarySchema = z2.object({
3165
4434
  /** The connection = the agent's token id (used to address a request). */
3166
- id: z.string(),
3167
- device: z.string().nullable(),
4435
+ id: z2.string(),
4436
+ device: z2.string().nullable(),
3168
4437
  /** The agent's display name (the single pairing name). */
3169
- name: z.string(),
4438
+ name: z2.string(),
3170
4439
  /** For a managed connection, the provider key (e.g. "cma") that agentOrigin maps to a
3171
4440
  * label; null for a local connection. Sourced from the token's provider, not the name. */
3172
- provider: z.string().nullable(),
4441
+ provider: z2.string().nullable(),
3173
4442
  /** The pairing's assigned voice (#462); null = the default voice. */
3174
4443
  voice: VoiceKeySchema.nullable(),
3175
4444
  /** The LOUDEST this agent may ever reach you — a ceiling on `NOTIFY_LADDER`, set by the
@@ -3180,19 +4449,19 @@ var ConnectionSummarySchema = z.object({
3180
4449
  * every surface at once and outranks even `sessionMode: all_calls` — a mode the user
3181
4450
  * set once must not overrule a rule they set about one agent. */
3182
4451
  reach: NotifyLevelSchema.nullable().optional(),
3183
- createdAt: z.string().datetime(),
4452
+ createdAt: z2.string().datetime(),
3184
4453
  /** Most recent notification on this connection, either direction. Null = no contact yet.
3185
4454
  * Drives the agents-page recency grouping (Today / This week / …). */
3186
- lastContactAt: z.string().datetime().nullable(),
4455
+ lastContactAt: z2.string().datetime().nullable(),
3187
4456
  /** Last presence heartbeat from a running agent process (POST /api/presence) — the
3188
4457
  * desktop app while open. Null = never seen; stale = offline. */
3189
- lastSeenAt: z.string().datetime().nullable().optional(),
4458
+ lastSeenAt: z2.string().datetime().nullable().optional(),
3190
4459
  /** What a live desktop can run (companion.md §2.2), advertised on its heartbeat:
3191
4460
  * harness availabilities + granted workspaces — the option set the phone's
3192
4461
  * "new session" sheet offers. Absent for ordinary MCP agents. */
3193
- runtime: z.object({
3194
- harnesses: z.array(z.object({ name: z.string(), label: z.string(), status: z.string() })).optional(),
3195
- workspaces: z.array(z.string()).optional()
4462
+ runtime: z2.object({
4463
+ harnesses: z2.array(z2.object({ name: z2.string(), label: z2.string(), status: z2.string() })).optional(),
4464
+ workspaces: z2.array(z2.string()).optional()
3196
4465
  }).optional(),
3197
4466
  /** The tail of this agent's working log, when a harness is driving it — the agent page's
3198
4467
  * live strip. Absent for anything the desktop harness isn't running (a hatched identity
@@ -3201,98 +4470,103 @@ var ConnectionSummarySchema = z.object({
3201
4470
  activity: AgentActivitySchema.optional(),
3202
4471
  /** True = a provider-managed agent running in the provider's cloud (e.g. Anthropic CMA);
3203
4472
  * false = a local MCP connection running on the user's computer (Claude Code/Codex/…). */
3204
- managed: z.boolean()
4473
+ managed: z2.boolean()
3205
4474
  });
3206
- var MoveRingSchema = z.enum(["home", "travels", "retired", "quarantined"]);
3207
- var MoveSchema = z.object({
3208
- id: z.string(),
4475
+ var MoveRingSchema = z2.enum(["home", "travels", "retired", "quarantined"]);
4476
+ var MoveSchema = z2.object({
4477
+ id: z2.string(),
3209
4478
  /** The reusable question, as distill normalized it. */
3210
- question: z.string(),
4479
+ question: z2.string(),
3211
4480
  /** The operative ruling. Editable by the user (PATCH) — which resets the ledger. */
3212
- answer: z.string(),
4481
+ answer: z2.string(),
3213
4482
  /** The user's stated reason, when they gave one. Null = inherently narrow: the judge is
3214
4483
  * told so, and the ruling only derives essentially the same question in the same scope. */
3215
- rationale: z.string().nullable(),
4484
+ rationale: z2.string().nullable(),
3216
4485
  /** Where the ruling lives: a repo/workspace, or 'global'. */
3217
- scope: z.string(),
4486
+ scope: z2.string(),
3218
4487
  ring: MoveRingSchema,
3219
4488
  /** True = the user pinned it with `always` (travel granted by hand, not by evidence). */
3220
- pinned: z.boolean(),
4489
+ pinned: z2.boolean(),
3221
4490
  /** True = a pin the user placed was BROKEN by later counter-evidence. Surfaced so the
3222
4491
  * break is visible instead of a pin silently disappearing. */
3223
- pinBroken: z.boolean(),
4492
+ pinBroken: z2.boolean(),
3224
4493
  /** When the ruling was distilled. */
3225
- learnedAt: z.string(),
4494
+ learnedAt: z2.string(),
3226
4495
  /** Last time it answered an ask. Null = never fired. */
3227
- lastUsedAt: z.string().nullable(),
4496
+ lastUsedAt: z2.string().nullable(),
3228
4497
  /** How many asks it has answered. Instrumentation — deliberately NOT an input to the
3229
4498
  * evidence curve: firing says the question keeps arising, not that the ruling is right. */
3230
- usedCount: z.number(),
4499
+ usedCount: z2.number(),
3231
4500
  /** Ledger: outcomes that said it held up. Saturating — the tenth is worth almost nothing. */
3232
- confirms: z.number(),
4501
+ confirms: z2.number(),
3233
4502
  /** Ledger: contradictions, in signal units (a full override = 1, weaker signals less).
3234
4503
  * Linear and priced above the entire confirmation budget, so any full counter wins. */
3235
- counters: z.number(),
4504
+ counters: z2.number(),
3236
4505
  /** The agent that asked the question this move came from, when known. Null for a move
3237
4506
  * distilled from a clarify ruling (those carry no agent) or one whose source rows are gone. */
3238
- learnedFrom: z.object({ id: z.string(), name: z.string() }).nullable()
4507
+ learnedFrom: z2.object({ id: z2.string(), name: z2.string() }).nullable()
3239
4508
  });
3240
- var CreateRequestSchema = z.object({
4509
+ var CreateRequestSchema = z2.object({
3241
4510
  /** The connection (token id) to send to, from GET /api/tokens. */
3242
- tokenId: z.string(),
4511
+ tokenId: z2.string(),
3243
4512
  /** The user's message to the agent. */
3244
- text: z.string().min(1),
4513
+ text: z2.string().min(1),
3245
4514
  /** Land the request on an existing conversation thread (History → "Continue")
3246
4515
  * instead of minting a fresh one. Must belong to the requesting user. */
3247
- parentId: z.string().optional(),
4516
+ parentId: z2.string().optional(),
3248
4517
  /** Point the agent at a past conversation (possibly with a different agent) as
3249
4518
  * starting context (History → "New session from this"). A reference, not a copy —
3250
4519
  * the agent reads it via get_thread. Must belong to the requesting user. */
3251
- contextParentId: z.string().optional()
4520
+ contextParentId: z2.string().optional()
3252
4521
  });
3253
- var HandoffSchema = z.object({
4522
+ var HandoffSchema = z2.object({
4523
+ /** Move this existing outcome to `target` without reminting it. Requires `target`. */
4524
+ workId: z2.string().uuid().optional(),
3254
4525
  /** Land the note on an existing thread; omitted mints a fresh one. */
3255
- parentId: z.string().uuid().optional(),
4526
+ parentId: z2.string().uuid().optional(),
3256
4527
  /** One-line headline of the working context handed off. */
3257
- title: z.string().min(1),
4528
+ title: z2.string().min(1),
3258
4529
  /** The brief — standalone notes the successor reads (what was done, what's left, links). */
3259
- notes: z.array(z.string().min(1)).min(1),
4530
+ notes: z2.array(z2.string().min(1)).min(1),
3260
4531
  /** A sibling connection to dispatch directly to (token id or agent nickname). Same-account
3261
4532
  * only; omit to leave the thread for the user to hand off in the app. */
3262
- target: z.string().optional(),
4533
+ target: z2.string().optional(),
3263
4534
  /** Write the note as a RECAP (kind:'recap', #617): a summary turn that supersedes the
3264
4535
  * thread's earlier turns for rehydration — get_thread returns the latest recap + only
3265
4536
  * the turns after it. Handoff-to-a-successor and handoff-to-yourself-later are the
3266
4537
  * same primitive; a recap is one whose audience includes you. */
3267
- recap: z.boolean().optional()
4538
+ recap: z2.boolean().optional()
4539
+ }).refine((value) => !value.workId || Boolean(value.target), {
4540
+ message: "target is required when handing off Work",
4541
+ path: ["target"]
3268
4542
  });
3269
- var NoteSourceSchema = z.enum(["app", "call"]);
3270
- var NoteStatusSchema = z.enum(["open", "assigned", "in_progress", "done"]);
3271
- var NoteRepeatSchema = z.enum(["once", "until_done"]);
3272
- var DecisionSchema = z.object({
3273
- id: z.string(),
4543
+ var NoteSourceSchema = z2.enum(["app", "call"]);
4544
+ var NoteStatusSchema = z2.enum(["open", "assigned", "in_progress", "done"]);
4545
+ var NoteRepeatSchema = z2.enum(["once", "until_done"]);
4546
+ var DecisionSchema = z2.object({
4547
+ id: z2.string(),
3274
4548
  /** The note this decision refines; null = recorded on a bare thread (the
3275
4549
  * extensibility seam — any conversation can accrue decisions). */
3276
- noteId: z.string().nullable(),
4550
+ noteId: z2.string().nullable(),
3277
4551
  /** What was ambiguous — the broker's (or the user's own) question. */
3278
- question: z.string(),
4552
+ question: z2.string(),
3279
4553
  /** The user's ruling; null while the question is open. */
3280
- answer: z.string().nullable(),
3281
- decidedAt: z.string().nullable(),
3282
- createdAt: z.string()
4554
+ answer: z2.string().nullable(),
4555
+ decidedAt: z2.string().nullable(),
4556
+ createdAt: z2.string()
3283
4557
  });
3284
- var NoteSchema = z.object({
3285
- id: z.string(),
4558
+ var NoteSchema = z2.object({
4559
+ id: z2.string(),
3286
4560
  /** One-line headline (broker-titled; deterministic floor). */
3287
- title: z.string(),
4561
+ title: z2.string(),
3288
4562
  /** The original intent, verbatim — assignees always see the user's own words. */
3289
- intent: z.string(),
4563
+ intent: z2.string(),
3290
4564
  source: NoteSourceSchema,
3291
4565
  status: NoteStatusSchema,
3292
4566
  /** Who it was assigned to (a participant ref, 'agent:<tokenId>'); null = unassigned. */
3293
- assignee: z.string().nullable(),
4567
+ assignee: z2.string().nullable(),
3294
4568
  /** The request thread minted at assignment; null until assigned. */
3295
- parentId: z.string().nullable(),
4569
+ parentId: z2.string().nullable(),
3296
4570
  /** REMINDERS (reminders-design.md): the NOT-BEFORE this becomes eligible to ride a
3297
4571
  * call — never a deadline. It only ever comes from the user's own words, so when it
3298
4572
  * passes Paigy rings ONCE (#1293, owner 2026-08-26: a time said out loud is consent to
@@ -3301,200 +4575,200 @@ var NoteSchema = z.object({
3301
4575
  // Defaulted, not required: a Note from an API deploy older than the reminders
3302
4576
  // migration has none of these, and the defaults ARE what it means — no not-before,
3303
4577
  // one ride, never ridden. Parsing must not fail across a rolling deploy.
3304
- dueAt: z.string().nullable().default(null),
4578
+ dueAt: z2.string().nullable().default(null),
3305
4579
  repeat: NoteRepeatSchema.default("once"),
3306
4580
  /** How many calls have already carried it — the fatigue cap counts rides, not days. */
3307
- rides: z.number().int().default(0),
3308
- lastRideAt: z.string().nullable().default(null),
3309
- createdAt: z.string()
4581
+ rides: z2.number().int().default(0),
4582
+ lastRideAt: z2.string().nullable().default(null),
4583
+ createdAt: z2.string()
3310
4584
  });
3311
- var CreateNoteSchema = z.object({
4585
+ var CreateNoteSchema = z2.object({
3312
4586
  /** The intent, in the user's own words. Stored verbatim; the broker only titles it. */
3313
- text: z.string().min(1).max(4e3),
4587
+ text: z2.string().min(1).max(4e3),
3314
4588
  /** Capture it as a REMINDER — a note assigned to the user themselves, which rides
3315
4589
  * their next call instead of being handed to an agent. Everything else about the
3316
4590
  * note is identical; this is the one parameter that separates the two. */
3317
- forMe: z.boolean().optional(),
4591
+ forMe: z2.boolean().optional(),
3318
4592
  /** The not-before, when the user already said one. Absent = the very next call. */
3319
- dueAt: z.string().datetime().optional(),
4593
+ dueAt: z2.string().datetime().optional(),
3320
4594
  repeat: NoteRepeatSchema.optional()
3321
4595
  });
3322
- var RecordDecisionSchema = z.object({
4596
+ var RecordDecisionSchema = z2.object({
3323
4597
  /** An open decision (from /clarify) to answer. */
3324
- decisionId: z.string().optional(),
4598
+ decisionId: z2.string().optional(),
3325
4599
  /** For an ad-hoc decision: what was ambiguous. Required without `decisionId`. */
3326
- question: z.string().min(1).max(500).optional(),
4600
+ question: z2.string().min(1).max(500).optional(),
3327
4601
  /** The ruling. */
3328
- answer: z.string().min(1).max(2e3)
4602
+ answer: z2.string().min(1).max(2e3)
3329
4603
  }).refine((d) => d.decisionId || d.question, { message: "decisionId or question required" });
3330
- var AssignNoteSchema = z.object({
4604
+ var AssignNoteSchema = z2.object({
3331
4605
  /** An EXISTING agent: token id or nickname. Omit when spawning fresh. */
3332
- target: z.string().min(1).optional(),
4606
+ target: z2.string().min(1).optional(),
3333
4607
  /** Spawn a NEW session for this note (companion.md §2.2): the assignee doesn't
3334
4608
  * exist yet — mint it on a live desktop that advertises the harness+workspace,
3335
4609
  * named after the note. The brief arrives as its opening request. */
3336
- spawn: z.object({
3337
- hostTokenId: z.string().uuid(),
3338
- harness: z.string().min(1),
3339
- workspace: z.string().min(1)
4610
+ spawn: z2.object({
4611
+ hostTokenId: z2.string().uuid(),
4612
+ harness: z2.string().min(1),
4613
+ workspace: z2.string().min(1)
3340
4614
  }).optional()
3341
4615
  }).refine((a) => !!a.target !== !!a.spawn, { message: "exactly one of target or spawn" });
3342
- var TriageVerdictSchema = z.enum(["keep", "stale", "close", "assign"]);
3343
- var TriageItemSchema = z.object({
3344
- noteId: z.string(),
4616
+ var TriageVerdictSchema = z2.enum(["keep", "stale", "close", "assign"]);
4617
+ var TriageItemSchema = z2.object({
4618
+ noteId: z2.string(),
3345
4619
  /** The note's headline at run time. */
3346
- title: z.string(),
4620
+ title: z2.string(),
3347
4621
  /** WHY, in one short human line, evidence first — this is read on a phone underneath
3348
4622
  * the note's title: "no movement in 34 days", "worked 3 notes in this repo this week".
3349
4623
  * Never a model's reasoning transcript, never an id. */
3350
- why: z.string()
4624
+ why: z2.string()
3351
4625
  });
3352
- var TriageAssignmentSchema = z.object({
4626
+ var TriageAssignmentSchema = z2.object({
3353
4627
  /** The agent's token id — what `dispatchNote` resolves and what a request is addressed to. */
3354
- agent: z.string(),
4628
+ agent: z2.string(),
3355
4629
  /** Its display name at run time (the name on the hatchling's card). Denormalized for the
3356
4630
  * same reason as `title`: the card must render from the proposal alone. */
3357
- agentName: z.string(),
3358
- notes: z.array(TriageItemSchema)
4631
+ agentName: z2.string(),
4632
+ notes: z2.array(TriageItemSchema)
3359
4633
  });
3360
- var TriageStatusSchema = z.enum(["open", "superseded", "dismissed"]);
3361
- var SubmitTriageSchema = z.object({
4634
+ var TriageStatusSchema = z2.enum(["open", "superseded", "dismissed"]);
4635
+ var SubmitTriageSchema = z2.object({
3362
4636
  /** Which runtime judged: "ollama" (inference never left the machine) or a harness the
3363
4637
  * user already runs under their own credentials ("claude" / "codex" / "agy"). Recorded
3364
4638
  * so the phone can say where the content went — an unattributed privacy claim is worth
3365
4639
  * nothing, and #1106's promise is precisely "Paigy's servers never see this". */
3366
- provider: z.string().min(1).max(60),
4640
+ provider: z2.string().min(1).max(60),
3367
4641
  /** The concrete model when the provider names one (an ollama tag); null otherwise. */
3368
- model: z.string().max(200).nullable().optional(),
4642
+ model: z2.string().max(200).nullable().optional(),
3369
4643
  /** How many open notes the run actually looked at — the denominator on the phone
3370
4644
  * ("6 of 50"), and the honest answer to "did it read the whole queue?". */
3371
- reviewed: z.number().int().min(0).max(1e4).default(0),
3372
- close: z.array(TriageItemSchema).max(200).default([]),
3373
- stale: z.array(TriageItemSchema).max(200).default([]),
3374
- assign: z.array(TriageAssignmentSchema).max(50).default([])
4645
+ reviewed: z2.number().int().min(0).max(1e4).default(0),
4646
+ close: z2.array(TriageItemSchema).max(200).default([]),
4647
+ stale: z2.array(TriageItemSchema).max(200).default([]),
4648
+ assign: z2.array(TriageAssignmentSchema).max(50).default([])
3375
4649
  });
3376
4650
  var TriageProposalSchema = SubmitTriageSchema.extend({
3377
- id: z.string(),
3378
- runAt: z.string(),
4651
+ id: z2.string(),
4652
+ runAt: z2.string(),
3379
4653
  status: TriageStatusSchema,
3380
- model: z.string().nullable().default(null)
4654
+ model: z2.string().nullable().default(null)
3381
4655
  });
3382
- var AcceptTriageSchema = z.discriminatedUnion("group", [
3383
- z.object({ group: z.literal("close"), noteIds: z.array(z.string()).max(200).optional() }),
3384
- z.object({ group: z.literal("stale"), noteIds: z.array(z.string()).max(200).optional() }),
3385
- z.object({
3386
- group: z.literal("assign"),
3387
- agent: z.string().min(1),
3388
- noteIds: z.array(z.string()).max(200).optional()
4656
+ var AcceptTriageSchema = z2.discriminatedUnion("group", [
4657
+ z2.object({ group: z2.literal("close"), noteIds: z2.array(z2.string()).max(200).optional() }),
4658
+ z2.object({ group: z2.literal("stale"), noteIds: z2.array(z2.string()).max(200).optional() }),
4659
+ z2.object({
4660
+ group: z2.literal("assign"),
4661
+ agent: z2.string().min(1),
4662
+ noteIds: z2.array(z2.string()).max(200).optional()
3389
4663
  })
3390
4664
  ]);
3391
- var AcceptTriageResultSchema = z.object({
3392
- accepted: z.array(z.string()),
3393
- failed: z.array(z.object({ noteId: z.string(), reason: z.string() }))
4665
+ var AcceptTriageResultSchema = z2.object({
4666
+ accepted: z2.array(z2.string()),
4667
+ failed: z2.array(z2.object({ noteId: z2.string(), reason: z2.string() }))
3394
4668
  });
3395
- var DeliveryModeSchema = z.enum(["poll", "self_hosted"]);
3396
- var RegisterDeliverySchema = z.object({ mode: DeliveryModeSchema });
3397
- var OAuthStartSchema = z.object({
3398
- provider: z.enum(["cma"]),
3399
- returnTo: z.string().min(1)
4669
+ var DeliveryModeSchema = z2.enum(["poll", "self_hosted"]);
4670
+ var RegisterDeliverySchema = z2.object({ mode: DeliveryModeSchema });
4671
+ var OAuthStartSchema = z2.object({
4672
+ provider: z2.enum(["cma"]),
4673
+ returnTo: z2.string().min(1)
3400
4674
  });
3401
- var DeliveryConfigSchema = z.object({
3402
- tokenId: z.string(),
4675
+ var DeliveryConfigSchema = z2.object({
4676
+ tokenId: z2.string(),
3403
4677
  mode: DeliveryModeSchema,
3404
4678
  /** null when the server has no SUPABASE_ANON_KEY set — the listener then falls
3405
4679
  * back to its own PAIGY_SUPABASE_URL / PAIGY_SUPABASE_ANON_KEY env. */
3406
- realtime: z.object({ url: z.string(), anonKey: z.string() }).nullable()
4680
+ realtime: z2.object({ url: z2.string(), anonKey: z2.string() }).nullable()
3407
4681
  });
3408
- var StatusSchema = z.object({
3409
- name: z.string(),
3410
- sessionMode: z.enum(["default", "all_calls", "silent"]),
4682
+ var StatusSchema = z2.object({
4683
+ name: z2.string(),
4684
+ sessionMode: z2.enum(["default", "all_calls", "silent"]),
3411
4685
  /** A phone is registered for push/ring (any push token on the account). */
3412
- phone: z.boolean()
4686
+ phone: z2.boolean()
3413
4687
  });
3414
- var EnvelopeRecipientSchema = z.object({
3415
- keyId: z.string(),
3416
- epk: z.string(),
3417
- wnonce: z.string(),
3418
- wrap: z.string()
4688
+ var EnvelopeRecipientSchema = z2.object({
4689
+ keyId: z2.string(),
4690
+ epk: z2.string(),
4691
+ wnonce: z2.string(),
4692
+ wrap: z2.string()
3419
4693
  });
3420
- var EnvelopeHeaderSchema = z.object({
3421
- field: z.enum(["context", "options", "visuals", "answer"]),
3422
- kind: z.string(),
3423
- senderRole: z.enum(["agent", "user"]),
3424
- recipientKeyIds: z.array(z.string()),
3425
- seq: z.number().int().nonnegative()
4694
+ var EnvelopeHeaderSchema = z2.object({
4695
+ field: z2.enum(["context", "options", "visuals", "answer"]),
4696
+ kind: z2.string(),
4697
+ senderRole: z2.enum(["agent", "user"]),
4698
+ recipientKeyIds: z2.array(z2.string()),
4699
+ seq: z2.number().int().nonnegative()
3426
4700
  });
3427
- var EnvelopeSchema = z.object({
3428
- v: z.literal(1),
3429
- alg: z.literal("x25519-xsalsa20poly1305"),
3430
- msgId: z.string(),
4701
+ var EnvelopeSchema = z2.object({
4702
+ v: z2.literal(1),
4703
+ alg: z2.literal("x25519-xsalsa20poly1305"),
4704
+ msgId: z2.string(),
3431
4705
  hdr: EnvelopeHeaderSchema,
3432
- recipients: z.array(EnvelopeRecipientSchema).min(1),
3433
- nonce: z.string(),
3434
- ct: z.string()
4706
+ recipients: z2.array(EnvelopeRecipientSchema).min(1),
4707
+ nonce: z2.string(),
4708
+ ct: z2.string()
3435
4709
  });
3436
- var SealedAnswerSchema = z.object({
3437
- ignored: z.boolean(),
4710
+ var SealedAnswerSchema = z2.object({
4711
+ ignored: z2.boolean(),
3438
4712
  envelope: EnvelopeSchema
3439
4713
  });
3440
- var DeviceCredentialSchema = z.object({
3441
- deviceId: z.string(),
3442
- kind: z.enum(["phone", "web", "agent"]),
3443
- x25519Pub: z.string(),
3444
- ed25519Pub: z.string(),
3445
- sig: z.string()
4714
+ var DeviceCredentialSchema = z2.object({
4715
+ deviceId: z2.string(),
4716
+ kind: z2.enum(["phone", "web", "agent"]),
4717
+ x25519Pub: z2.string(),
4718
+ ed25519Pub: z2.string(),
4719
+ sig: z2.string()
3446
4720
  });
3447
- var DeviceRosterSchema = z.object({
3448
- uikPub: z.string(),
3449
- devices: z.array(DeviceCredentialSchema)
4721
+ var DeviceRosterSchema = z2.object({
4722
+ uikPub: z2.string(),
4723
+ devices: z2.array(DeviceCredentialSchema)
3450
4724
  });
3451
- var WakeNudgeSchema = z.object({
3452
- kind: z.enum(["reply", "request", "callback"]),
3453
- notificationId: z.string().optional(),
3454
- parentId: z.string()
4725
+ var WakeNudgeSchema = z2.object({
4726
+ kind: z2.enum(["reply", "request", "callback"]),
4727
+ notificationId: z2.string().optional(),
4728
+ parentId: z2.string()
3455
4729
  });
3456
- var PairingStatusSchema = z.enum(["pending", "approved", "denied", "expired"]);
3457
- var PairingRevealSchema = z.object({
3458
- x25519: z.string(),
3459
- ed25519: z.string(),
3460
- nonce: z.string()
4730
+ var PairingStatusSchema = z2.enum(["pending", "approved", "denied", "expired"]);
4731
+ var PairingRevealSchema = z2.object({
4732
+ x25519: z2.string(),
4733
+ ed25519: z2.string(),
4734
+ nonce: z2.string()
3461
4735
  });
3462
- var DeviceCodeRequestSchema = z.object({
4736
+ var DeviceCodeRequestSchema = z2.object({
3463
4737
  /** The agent's suggested name for the pairing — the human sees it pre-filled at
3464
4738
  * approval and can override. Optional; blank → a default silly name server-side. */
3465
- suggestedName: z.string().optional(),
4739
+ suggestedName: z2.string().optional(),
3466
4740
  /** Legacy alias for suggestedName (older MCPs sent `agent`). Accepted for
3467
4741
  * back-compat; `suggestedName` wins when both are present. ponytail: drop once no
3468
4742
  * pre-`name` MCP is in the wild. */
3469
- agent: z.union([z.string(), z.object({ name: z.string().optional() })]).optional(),
3470
- device: z.string().optional(),
3471
- proto: z.string().optional(),
4743
+ agent: z2.union([z2.string(), z2.object({ name: z2.string().optional() })]).optional(),
4744
+ device: z2.string().optional(),
4745
+ proto: z2.string().optional(),
3472
4746
  // compiled-in tag, e.g. "paigy-pair-v2|sas=24"
3473
- commitment: z.string().optional()
4747
+ commitment: z2.string().optional()
3474
4748
  // agent's Ca
3475
4749
  });
3476
- var DeviceCodeSchema = z.object({
3477
- device_code: z.string(),
3478
- user_code: z.string(),
3479
- verification_uri: z.string().url(),
3480
- verification_uri_complete: z.string().url(),
3481
- interval: z.number(),
3482
- expires_in: z.number()
4750
+ var DeviceCodeSchema = z2.object({
4751
+ device_code: z2.string(),
4752
+ user_code: z2.string(),
4753
+ verification_uri: z2.string().url(),
4754
+ verification_uri_complete: z2.string().url(),
4755
+ interval: z2.number(),
4756
+ expires_in: z2.number()
3483
4757
  });
3484
- var DeviceInfoSchema = z.object({
3485
- code: z.string(),
4758
+ var DeviceInfoSchema = z2.object({
4759
+ code: z2.string(),
3486
4760
  /** The agent's suggested name (from /device/code) — shown on the approval screen,
3487
4761
  * pre-filling the name field the human can edit. */
3488
- name: z.string(),
4762
+ name: z2.string(),
3489
4763
  /** @deprecated Legacy alias of `name` for the pre-#531 embedded bundle in App Store
3490
4764
  * build 35, whose DeviceFlow renders `info.agent.slice(0, 2)` — without this a FRESH
3491
4765
  * install crashes on the pairing screen on first launch, before the OTA lands
3492
4766
  * (seen live: PAIGY-5T, 2026-07-21). Remove once a newer binary is the floor. */
3493
- agent: z.string().optional(),
3494
- device: z.string().nullable(),
4767
+ agent: z2.string().optional(),
4768
+ device: z2.string().nullable(),
3495
4769
  status: PairingStatusSchema,
3496
- proto: z.string().nullable().optional(),
3497
- agent_commitment: z.string().nullable().optional(),
4770
+ proto: z2.string().nullable().optional(),
4771
+ agent_commitment: z2.string().nullable().optional(),
3498
4772
  // Ca
3499
4773
  agent_reveal: PairingRevealSchema.nullable().optional(),
3500
4774
  // present once the agent reveals
@@ -3504,48 +4778,48 @@ var DeviceInfoSchema = z.object({
3504
4778
  // withheld until e2ee=true) can compute the SAS WITHOUT a token. Public keys — same safety
3505
4779
  // class as agent_reveal above. Present only once the phone reveals; null otherwise.
3506
4780
  phone_reveal: PairingRevealSchema.nullable().optional(),
3507
- uik_pub: z.string().nullable().optional()
4781
+ uik_pub: z2.string().nullable().optional()
3508
4782
  });
3509
- var DeviceTokenRequestSchema = z.object({
3510
- device_code: z.string(),
4783
+ var DeviceTokenRequestSchema = z2.object({
4784
+ device_code: z2.string(),
3511
4785
  reveal: PairingRevealSchema.optional()
3512
4786
  // agent's reveal {x25519, ed25519, nonce}
3513
4787
  });
3514
- var DeviceTokenSchema = z.object({
3515
- access_token: z.string(),
4788
+ var DeviceTokenSchema = z2.object({
4789
+ access_token: z2.string(),
3516
4790
  /** The pairing's single name (user-typed at approval, the agent's suggestion, or
3517
4791
  * a default silly name). */
3518
- name: z.string(),
3519
- device: z.string().nullable(),
4792
+ name: z2.string(),
4793
+ device: z2.string().nullable(),
3520
4794
  /** The pairing's assigned voice, cached so the desktop can seed the SAME face the phone
3521
4795
  * draws — voice is the third ingredient of a hatchling's build (party/traits.ts). */
3522
- voice: z.string().nullable().optional(),
4796
+ voice: z2.string().nullable().optional(),
3523
4797
  /** The token's server-side id — the face's COLOUR anchor, and the only seed ingredient
3524
4798
  * that survives a rename. Cached by the host's identity beat. */
3525
- token_id: z.string().nullable().optional(),
4799
+ token_id: z2.string().nullable().optional(),
3526
4800
  /** WHERE this identity works — the folder a wake should land it in. Written by the host
3527
4801
  * at spawn and by `paigy-harness handoff` from a live terminal. Without it every wake
3528
4802
  * landed in the FIRST granted workspace and the agent rediscovered its own repo from
3529
4803
  * the thread each time (host.ts, live catch 2026-08-06 — prompt-papered until now). */
3530
- workspace: z.string().nullable().optional(),
4804
+ workspace: z2.string().nullable().optional(),
3531
4805
  phone_reveal: PairingRevealSchema.nullable().optional(),
3532
4806
  // present once the phone reveals
3533
- uik_pub: z.string().nullable().optional()
4807
+ uik_pub: z2.string().nullable().optional()
3534
4808
  });
3535
- var DeviceCommitRequestSchema = z.object({
3536
- code: z.string(),
3537
- commitment: z.string()
4809
+ var DeviceCommitRequestSchema = z2.object({
4810
+ code: z2.string(),
4811
+ commitment: z2.string()
3538
4812
  // Cb
3539
4813
  });
3540
- var DevicePeerCommitSchema = z.object({
3541
- commitment: z.string().nullable()
4814
+ var DevicePeerCommitSchema = z2.object({
4815
+ commitment: z2.string().nullable()
3542
4816
  });
3543
- var SupportRequestSchema = z.object({
3544
- email: z.string().email().max(320),
3545
- message: z.string().trim().min(1).max(5e3),
3546
- name: z.string().trim().max(120).optional()
4817
+ var SupportRequestSchema = z2.object({
4818
+ email: z2.string().email().max(320),
4819
+ message: z2.string().trim().min(1).max(5e3),
4820
+ name: z2.string().trim().max(120).optional()
3547
4821
  });
3548
- var NotificationFeedbackKindSchema = z.enum([
4822
+ var NotificationFeedbackKindSchema = z2.enum([
3549
4823
  "break_down",
3550
4824
  // "This should be more than one ask — break it down."
3551
4825
  "regenerate_options",
@@ -3559,76 +4833,30 @@ var NotificationFeedbackKindSchema = z.enum([
3559
4833
  "other"
3560
4834
  // anything else — the note carries it.
3561
4835
  ]);
3562
- var NotificationFeedbackSchema = z.object({
3563
- notificationId: z.string(),
4836
+ var NotificationFeedbackSchema = z2.object({
4837
+ notificationId: z2.string(),
3564
4838
  kind: NotificationFeedbackKindSchema,
3565
4839
  /** Optional free-text elaboration for a preset; required (non-empty) for 'other'. */
3566
- note: z.string().trim().max(2e3).optional()
4840
+ note: z2.string().trim().max(2e3).optional()
3567
4841
  }).superRefine((r, ctx) => {
3568
4842
  if (r.kind === "other" && !r.note)
3569
- ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["note"], message: "note is required for 'other' feedback" });
4843
+ ctx.addIssue({ code: z2.ZodIssueCode.custom, path: ["note"], message: "note is required for 'other' feedback" });
3570
4844
  });
3571
- var FeedbackResolutionSchema = z.enum(["broker_fixed", "sent_to_agent"]);
3572
- var FeedbackOutcomeSchema = z.object({
4845
+ var FeedbackResolutionSchema = z2.enum(["broker_fixed", "sent_to_agent"]);
4846
+ var FeedbackOutcomeSchema = z2.object({
3573
4847
  resolution: FeedbackResolutionSchema,
3574
4848
  transform: TransformSchema,
3575
- message: z.string(),
3576
- childIds: z.array(z.string()).optional()
4849
+ message: z2.string(),
4850
+ childIds: z2.array(z2.string()).optional()
4851
+ });
4852
+ var CONTACT_SCHEMA = contactSchemaFrom({
4853
+ ask: NotifyRequestFields.shape.ask,
4854
+ waiting: NotifyRequestFields.shape.waiting,
4855
+ options: NotifyRequestFields.shape.options,
4856
+ channel: NotifyRequestFields.shape.channel,
4857
+ parentId: NotifyRequestFields.shape.parentId,
4858
+ workId: NotifyRequestFields.shape.workId
3577
4859
  });
3578
- var WORD_NUMS = {
3579
- a: 1,
3580
- an: 1,
3581
- one: 1,
3582
- two: 2,
3583
- three: 3,
3584
- four: 4,
3585
- five: 5,
3586
- six: 6,
3587
- seven: 7,
3588
- eight: 8,
3589
- nine: 9,
3590
- ten: 10,
3591
- fifteen: 15,
3592
- twenty: 20,
3593
- thirty: 30,
3594
- forty: 40,
3595
- "forty-five": 45,
3596
- fifty: 50,
3597
- sixty: 60,
3598
- "half an": 0.5,
3599
- "a couple of": 2,
3600
- "a few": 3
3601
- };
3602
- function untilHour(hour, now) {
3603
- const due = new Date(now);
3604
- due.setHours(hour, 0, 0, 0);
3605
- if (due.getTime() <= now.getTime()) due.setDate(due.getDate() + 1);
3606
- return Math.round((due.getTime() - now.getTime()) / 1e3);
3607
- }
3608
- function parseDue(detail, now = /* @__PURE__ */ new Date()) {
3609
- const t = detail.toLowerCase().trim();
3610
- const rel = /(?:^|\b)in\s+(half an|a couple of|a few|an?|[\w-]+|\d+)\s*(minutes?|mins?|hours?|hrs?)\b/.exec(t);
3611
- if (rel) {
3612
- const n = /^\d+$/.test(rel[1]) ? Number(rel[1]) : WORD_NUMS[rel[1]];
3613
- if (n !== void 0) {
3614
- const unit = rel[2].startsWith("h") ? 3600 : 60;
3615
- return Math.round(n * unit);
3616
- }
3617
- }
3618
- if (/after lunch|lunchtime/.test(t)) return untilHour(13, now);
3619
- if (/tomorrow/.test(t)) {
3620
- const due = new Date(now);
3621
- due.setDate(due.getDate() + 1);
3622
- due.setHours(9, 0, 0, 0);
3623
- return Math.round((due.getTime() - now.getTime()) / 1e3);
3624
- }
3625
- if (/tonight|this evening/.test(t)) {
3626
- return now.getHours() < 20 ? untilHour(20, now) : 3600;
3627
- }
3628
- if (/end of (the )?day|eod/.test(t)) return untilHour(17, now);
3629
- if (/later|in a (bit|while)/.test(t)) return 1800;
3630
- return null;
3631
- }
3632
4860
  var import_tweetnacl = __toESM(require_nacl_fast(), 1);
3633
4861
  var import_tweetnacl2 = __toESM(require_nacl_fast(), 1);
3634
4862
  var import_tweetnacl3 = __toESM(require_nacl_fast(), 1);
@@ -3897,10 +5125,32 @@ function verifyPairingCommit(commitment, proto, role, x25519Pub, ed25519Pub, non
3897
5125
  return false;
3898
5126
  }
3899
5127
  }
3900
- function sessionSlot(sessionId) {
3901
- const id = sessionId ?? process.env.PAIGY_SESSION_ID ?? process.env.CLAUDE_CODE_SESSION_ID ?? randomUUID2();
5128
+ function sessionSlot(sessionId2) {
5129
+ const id = sessionId2 ?? sessionId();
3902
5130
  return `session:${id.slice(0, 8)}`;
3903
5131
  }
5132
+ function subagentId(env = process.env) {
5133
+ if (!env.CLAUDE_CODE_CHILD_SESSION) return null;
5134
+ const pid = env.CLAUDE_PID ?? env.CLAUDE_CODE_MESSAGING_SOCKET?.match(/(\d+)\.sock$/)?.[1];
5135
+ return pid ?? null;
5136
+ }
5137
+ function subagentThread(env = process.env, sessionId2) {
5138
+ const base = sessionId2 ?? sessionId();
5139
+ const sub = subagentId(env);
5140
+ return sub ? `${base}:sub:${sub}` : base;
5141
+ }
5142
+ function uuidFromKey(key) {
5143
+ const h = createHash("sha1").update(`paigy-thread:${key}`).digest();
5144
+ h[6] = h[6] & 15 | 80;
5145
+ h[8] = h[8] & 63 | 128;
5146
+ const hex = h.subarray(0, 16).toString("hex");
5147
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
5148
+ }
5149
+ function contactParentId(explicit, env = process.env) {
5150
+ if (explicit) return explicit;
5151
+ if (!subagentId(env)) return void 0;
5152
+ return uuidFromKey(subagentThread(env));
5153
+ }
3904
5154
  var AGENT_NAME = process.env.PAIGY_AGENT || sessionSlot();
3905
5155
  var PROTO = "paigy-pair-v2|sas=24";
3906
5156
  var SAS_BITS = 24;
@@ -3972,13 +5222,15 @@ async function revokeToken(token) {
3972
5222
  });
3973
5223
  return res.ok;
3974
5224
  }
3975
- async function requestCode(suggestedName = AGENT_NAME, e2ee) {
5225
+ async function requestCode(suggestedName = AGENT_NAME, e2ee, device) {
3976
5226
  const res = await reach(`${BACKEND_URL}/api/device/code`, {
3977
5227
  method: "POST",
3978
5228
  headers: { "content-type": "application/json" },
3979
- body: JSON.stringify(
3980
- e2ee ? { suggestedName, proto: e2ee.proto, commitment: e2ee.commitment } : { suggestedName }
3981
- )
5229
+ body: JSON.stringify({
5230
+ suggestedName,
5231
+ ...device ? { device } : {},
5232
+ ...e2ee ? { proto: e2ee.proto, commitment: e2ee.commitment } : {}
5233
+ })
3982
5234
  });
3983
5235
  if (!res.ok) throw new Error(`/api/device/code failed: ${res.status} ${await res.text()}`);
3984
5236
  return await res.json();
@@ -4162,6 +5414,16 @@ async function sealForE2ee(req, token, deps = {}) {
4162
5414
  const { context: _c, options: _o, visuals: _v, repo: _r, branch: _b, ...meta } = req;
4163
5415
  return { ...meta, envelope };
4164
5416
  }
5417
+ async function createGoal(input, opts = {}) {
5418
+ const token = authToken(opts.token) ?? "";
5419
+ const res = ensureAuthed(await reach(`${BACKEND_URL}/api/goals`, {
5420
+ method: "POST",
5421
+ headers: { "content-type": "application/json", authorization: `Bearer ${token}` },
5422
+ body: JSON.stringify(input)
5423
+ }));
5424
+ if (!res.ok) throw new Error(`create_goal failed: ${res.status} ${await res.text()}`);
5425
+ return await res.json();
5426
+ }
4165
5427
  async function submitNotification(req, opts = {}) {
4166
5428
  const token = authToken(opts.token) ?? "";
4167
5429
  const body = await sealForE2ee(req, token);
@@ -4173,18 +5435,11 @@ async function submitNotification(req, opts = {}) {
4173
5435
  if (!res.ok) throw new Error(`notify failed: ${res.status} ${await res.text()}`);
4174
5436
  return await res.json();
4175
5437
  }
4176
- function decryptAnswer(reply, deps = {}) {
4177
- if (!reply.sealed) return reply.answer;
4178
- const keyFile = (deps.readKeyFile ?? readKeyFile)();
4179
- if (!keyFile?.keypair) {
4180
- throw new Error("received a sealed answer but this agent has no device key to open it \u2014 re-pair.");
4181
- }
4182
- return openSealedAnswer(reply.sealed, keyFile.keypair);
4183
- }
5438
+ var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
4184
5439
  var AWAIT_WINDOW_MS = 45e3;
4185
5440
  var _partialSeen = /* @__PURE__ */ new Map();
4186
5441
  async function pollPartials(notificationId) {
4187
- const token = readToken();
5442
+ const token = authToken();
4188
5443
  const after = _partialSeen.get(notificationId) ?? 0;
4189
5444
  try {
4190
5445
  const res = await reach(
@@ -4201,13 +5456,26 @@ async function pollPartials(notificationId) {
4201
5456
  return null;
4202
5457
  }
4203
5458
  }
4204
- function landIntents(intents) {
4205
- if (!intents?.length) return intents;
4206
- return intents.map((i) => {
4207
- if (i.kind !== "defer") return i;
4208
- const due = parseDue(i.detail);
4209
- return due !== null ? { ...i, dueInSeconds: due } : i;
4210
- });
5459
+ async function awaitReply(notificationId, opts) {
5460
+ const intervalMs = opts.intervalMs ?? 5e3;
5461
+ const windowMs = opts.windowMs ?? AWAIT_WINDOW_MS;
5462
+ const doSleep = opts.sleep ?? sleep2;
5463
+ const now = opts.now ?? Date.now;
5464
+ const read = opts.read;
5465
+ const start = now();
5466
+ while (true) {
5467
+ if (opts.signal?.aborted) return { type: "idle" };
5468
+ try {
5469
+ const item = await read(notificationId);
5470
+ if (item.type !== "idle") return item;
5471
+ const partial = await pollPartials(notificationId);
5472
+ if (partial) return partial;
5473
+ } catch (e) {
5474
+ if (!isNetworkError(e)) throw e;
5475
+ }
5476
+ if (now() - start >= windowMs) return { type: "idle" };
5477
+ await doSleep(intervalMs);
5478
+ }
4211
5479
  }
4212
5480
  async function getThread(parentId) {
4213
5481
  const res = ensureAuthed(await reach(`${BACKEND_URL}/api/thread/${encodeURIComponent(parentId)}`, {
@@ -4223,26 +5491,16 @@ async function searchThreads(q) {
4223
5491
  if (!res.ok) throw new Error(`search_threads failed: ${res.status} ${await res.text()}`);
4224
5492
  return await res.json();
4225
5493
  }
4226
- async function checkReplies(opts = {}) {
5494
+ async function sweepLeased(opts = {}) {
4227
5495
  const token = authToken(opts.token);
4228
5496
  const res = ensureAuthed(await reach(`${BACKEND_URL}/api/pending`, {
4229
5497
  headers: {
4230
5498
  authorization: `Bearer ${token}`,
4231
- ...opts.replyAck ? { "x-paigy-await-ack": "1" } : {}
5499
+ "x-paigy-await-ack": "1"
4232
5500
  }
4233
5501
  }));
4234
5502
  if (!res.ok) throw new Error(`check_replies failed: ${res.status} ${await res.text()}`);
4235
- const pending = await res.json();
4236
- if (opts.replyAck) return pending;
4237
- return {
4238
- ...pending,
4239
- replies: pending.replies.map((raw) => {
4240
- const r = { ...raw, intents: landIntents(raw.intents) };
4241
- if (!r.sealed) return r;
4242
- const { sealed: _s, ...rest } = r;
4243
- return { ...rest, answer: decryptAnswer(r) };
4244
- })
4245
- };
5503
+ return await res.json();
4246
5504
  }
4247
5505
  async function answerCallerQuestion(notificationId, answer) {
4248
5506
  const res = ensureAuthed(await reach(`${BACKEND_URL}/api/voice/session-answer`, {
@@ -4308,7 +5566,7 @@ async function registerDelivery(mode) {
4308
5566
  return await res.json();
4309
5567
  }
4310
5568
  async function scheduleCallback(req) {
4311
- const token = readToken();
5569
+ const token = authToken();
4312
5570
  const res = ensureAuthed(await reach(`${BACKEND_URL}/api/callback`, {
4313
5571
  method: "POST",
4314
5572
  headers: { "content-type": "application/json", authorization: `Bearer ${token}` },
@@ -4318,7 +5576,7 @@ async function scheduleCallback(req) {
4318
5576
  return await res.json();
4319
5577
  }
4320
5578
  async function handoff(req) {
4321
- const token = readToken();
5579
+ const token = authToken();
4322
5580
  const res = ensureAuthed(await reach(`${BACKEND_URL}/api/handoff`, {
4323
5581
  method: "POST",
4324
5582
  headers: { "content-type": "application/json", authorization: `Bearer ${token}` },
@@ -4327,7 +5585,7 @@ async function handoff(req) {
4327
5585
  if (!res.ok) throw new Error(`handoff failed: ${res.status} ${await res.text()}`);
4328
5586
  return await res.json();
4329
5587
  }
4330
- var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
5588
+ var sleep3 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
4331
5589
  var ReplyLeaseExpiredError = class extends Error {
4332
5590
  constructor() {
4333
5591
  super(
@@ -4344,11 +5602,7 @@ var ReplyAckError = class extends Error {
4344
5602
  }
4345
5603
  retryable;
4346
5604
  };
4347
- function ensureAuthed2(res) {
4348
- if (res.status === 401) throw new UnpairedError();
4349
- return res;
4350
- }
4351
- function decryptAnswer2(reply, deps = {}) {
5605
+ function decryptAnswer(reply, deps = {}) {
4352
5606
  if (!reply.sealed) return reply.answer;
4353
5607
  const keyFile = (deps.readKeyFile ?? readKeyFile)();
4354
5608
  if (!keyFile?.keypair) {
@@ -4358,22 +5612,11 @@ function decryptAnswer2(reply, deps = {}) {
4358
5612
  }
4359
5613
  return openSealedAnswer(reply.sealed, keyFile.keypair);
4360
5614
  }
4361
- function landIntents2(intents) {
4362
- if (!intents?.length) return intents;
4363
- return intents.map((intent) => {
4364
- if (intent.kind !== "defer") return intent;
4365
- const due = parseDue(intent.detail);
4366
- return due !== null ? { ...intent, dueInSeconds: due } : intent;
4367
- });
4368
- }
4369
5615
  function decodeReply(item, deps = {}) {
4370
5616
  const { delivery: _delivery, ...withoutDelivery } = item;
4371
- const enriched = {
4372
- ...withoutDelivery,
4373
- intents: landIntents2(withoutDelivery.intents)
4374
- };
5617
+ const enriched = { ...withoutDelivery };
4375
5618
  if (!enriched.sealed) return enriched;
4376
- const answer = decryptAnswer2(enriched, deps);
5619
+ const answer = decryptAnswer(enriched, deps);
4377
5620
  const { sealed: _sealed, ...plaintext } = enriched;
4378
5621
  return { ...plaintext, answer };
4379
5622
  }
@@ -4399,11 +5642,11 @@ async function responseDetail(res) {
4399
5642
  async function acknowledge(token, leaseId, opts = {}) {
4400
5643
  const attempts = Math.max(1, Math.min(opts.attempts ?? 3, 5));
4401
5644
  const backoffMs = Math.max(0, opts.backoffMs ?? 100);
4402
- const doSleep = opts.doSleep ?? sleep2;
5645
+ const doSleep = opts.doSleep ?? sleep3;
4403
5646
  let lastError;
4404
5647
  for (let attempt = 0; attempt < attempts; attempt += 1) {
4405
5648
  try {
4406
- const res = ensureAuthed2(await reach(`${BACKEND_URL}/api/await/ack`, {
5649
+ const res = ensureAuthed(await reach(`${BACKEND_URL}/api/await/ack`, {
4407
5650
  method: "POST",
4408
5651
  headers: {
4409
5652
  authorization: `Bearer ${token}`,
@@ -4434,6 +5677,15 @@ async function acknowledge(token, leaseId, opts = {}) {
4434
5677
  `Could not acknowledge the Paigy reply after ${attempts} attempts (${detail}). The answer was not returned to the agent and remains recoverable after the lease expires.`
4435
5678
  );
4436
5679
  }
5680
+ async function ackReply(item, token, opts = {}) {
5681
+ const delivery = deliveryOf(item);
5682
+ if (!delivery) throw new Error("Paigy returned a reply without a delivery lease; nothing to acknowledge.");
5683
+ await acknowledge(token, delivery.leaseId, {
5684
+ attempts: opts.ackAttempts,
5685
+ backoffMs: opts.ackBackoffMs,
5686
+ doSleep: opts.ackSleep
5687
+ });
5688
+ }
4437
5689
  async function receiveReply(item, token, opts = {}) {
4438
5690
  const decoded = decodeReply(item, opts);
4439
5691
  const delivery = deliveryOf(item);
@@ -4452,7 +5704,7 @@ async function receiveReply(item, token, opts = {}) {
4452
5704
  }
4453
5705
  async function pollAnswer(notificationId, opts = {}) {
4454
5706
  const token = authToken() ?? "";
4455
- const res = ensureAuthed2(await reach(
5707
+ const res = ensureAuthed(await reach(
4456
5708
  `${BACKEND_URL}/api/await?notificationId=${encodeURIComponent(notificationId)}`,
4457
5709
  {
4458
5710
  headers: {
@@ -4466,24 +5718,11 @@ async function pollAnswer(notificationId, opts = {}) {
4466
5718
  if (wire.type !== "reply") return wire;
4467
5719
  return receiveReply(wire, token, opts);
4468
5720
  }
4469
- async function awaitReply(notificationId, opts = {}) {
4470
- const intervalMs = opts.intervalMs ?? 5e3;
4471
- const windowMs = opts.windowMs ?? AWAIT_WINDOW_MS;
4472
- const doSleep = opts.sleep ?? sleep2;
4473
- const now = opts.now ?? Date.now;
4474
- const start = now();
4475
- while (true) {
4476
- if (opts.signal?.aborted) return { type: "idle" };
4477
- const item = await pollAnswer(notificationId);
4478
- if (item.type !== "idle") return item;
4479
- const partial = await pollPartials(notificationId);
4480
- if (partial) return partial;
4481
- if (now() - start >= windowMs) return { type: "idle" };
4482
- await doSleep(intervalMs);
4483
- }
5721
+ async function awaitReply2(notificationId, opts = {}) {
5722
+ return awaitReply(notificationId, { ...opts, read: pollAnswer });
4484
5723
  }
4485
- async function checkReplies2(opts = {}) {
4486
- const pending = await checkReplies({ ...opts, replyAck: true });
5724
+ async function checkReplies(opts = {}) {
5725
+ const pending = await sweepLeased(opts);
4487
5726
  const token = authToken(opts.token) ?? "";
4488
5727
  const replies = await Promise.all(pending.replies.map(async (reply) => {
4489
5728
  const received = await receiveReply(
@@ -4496,17 +5735,14 @@ async function checkReplies2(opts = {}) {
4496
5735
  }));
4497
5736
  return {
4498
5737
  ...pending,
4499
- replies
5738
+ replies,
5739
+ work: pending.work ?? []
4500
5740
  };
4501
5741
  }
4502
- function ensureAuthed3(res) {
4503
- if (res.status === 401) throw new UnpairedError();
4504
- return res;
4505
- }
4506
- async function setTaskState(notificationId, state, opts = {}) {
5742
+ async function patchState(path, state, opts, operation) {
4507
5743
  const token = authToken(opts.token) ?? "";
4508
- const res = ensureAuthed3(await reach(
4509
- `${BACKEND_URL}/api/notify/${encodeURIComponent(notificationId)}/state`,
5744
+ const res = ensureAuthed(await reach(
5745
+ `${BACKEND_URL}${path}`,
4510
5746
  {
4511
5747
  method: "PATCH",
4512
5748
  headers: {
@@ -4518,22 +5754,27 @@ async function setTaskState(notificationId, state, opts = {}) {
4518
5754
  }
4519
5755
  ));
4520
5756
  if (!res.ok) {
4521
- throw new Error(`set_task_state failed: ${res.status} ${await res.text()}`);
5757
+ throw new Error(`${operation} failed: ${res.status} ${await res.text()}`);
4522
5758
  }
4523
5759
  return await res.json();
4524
5760
  }
4525
- function overrideToken2(secret) {
4526
- overrideToken(secret);
5761
+ function setTaskState(notificationId, state, opts = {}) {
5762
+ return patchState(`/api/notify/${encodeURIComponent(notificationId)}/state`, state, opts, "set_task_state");
5763
+ }
5764
+ function setWorkState(input, opts = {}) {
5765
+ const parsed = SetWorkStateSchema.parse(input);
5766
+ const path = parsed.workId ? `/api/work/${encodeURIComponent(parsed.workId)}/state` : `/api/notify/${encodeURIComponent(parsed.notificationId)}/state`;
5767
+ return patchState(path, parsed.state, opts, "set_work_state");
4527
5768
  }
4528
5769
 
4529
5770
  export {
4530
5771
  BACKEND_URL,
5772
+ isNetworkError,
4531
5773
  reach,
4532
- normalizeSpeech,
4533
- lintNotify,
4534
5774
  NotifyRequestSchema,
4535
- SetTaskStateSchema,
5775
+ SetWorkStateSchema,
4536
5776
  ScheduleCallbackSchema,
5777
+ contactParentId,
4537
5778
  AGENT_NAME,
4538
5779
  TOKEN_PATH,
4539
5780
  saveToken,
@@ -4544,7 +5785,6 @@ export {
4544
5785
  deleteToken,
4545
5786
  revokeToken,
4546
5787
  requestCode,
4547
- pollToken,
4548
5788
  saveKeyFile,
4549
5789
  readKeyFile,
4550
5790
  deleteKeyFile,
@@ -4553,10 +5793,14 @@ export {
4553
5793
  fetchCredential,
4554
5794
  pairStep,
4555
5795
  UnpairedError,
5796
+ createGoal,
4556
5797
  submitNotification,
4557
5798
  getThread,
4558
5799
  searchThreads,
5800
+ sweepLeased,
4559
5801
  answerCallerQuestion,
5802
+ overrideToken,
5803
+ authToken,
4560
5804
  hatch,
4561
5805
  whoAmI,
4562
5806
  setIdentity,
@@ -4564,8 +5808,10 @@ export {
4564
5808
  registerDelivery,
4565
5809
  scheduleCallback,
4566
5810
  handoff,
4567
- awaitReply,
4568
- checkReplies2,
5811
+ decodeReply,
5812
+ ackReply,
5813
+ awaitReply2,
5814
+ checkReplies,
4569
5815
  setTaskState,
4570
- overrideToken2
5816
+ setWorkState
4571
5817
  };