@paigy/harness 0.3.32 → 0.3.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/cli.js +808 -377
  2. package/dist/main.js +640 -228
  3. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -901,14 +901,14 @@ var require_regex = __commonJS({
901
901
  var TEST_KANJI = new RegExp("^" + kanji + "$");
902
902
  var TEST_NUMERIC = new RegExp("^" + numeric + "$");
903
903
  var TEST_ALPHANUMERIC = new RegExp("^[A-Z0-9 $%*+\\-./:]+$");
904
- exports.testKanji = function testKanji(str) {
905
- return TEST_KANJI.test(str);
904
+ exports.testKanji = function testKanji(str3) {
905
+ return TEST_KANJI.test(str3);
906
906
  };
907
- exports.testNumeric = function testNumeric(str) {
908
- return TEST_NUMERIC.test(str);
907
+ exports.testNumeric = function testNumeric(str3) {
908
+ return TEST_NUMERIC.test(str3);
909
909
  };
910
- exports.testAlphanumeric = function testAlphanumeric(str) {
911
- return TEST_ALPHANUMERIC.test(str);
910
+ exports.testAlphanumeric = function testAlphanumeric(str3) {
911
+ return TEST_ALPHANUMERIC.test(str3);
912
912
  };
913
913
  }
914
914
  });
@@ -1358,11 +1358,11 @@ var require_dijkstra = __commonJS({
1358
1358
  */
1359
1359
  PriorityQueue: {
1360
1360
  make: function(opts) {
1361
- var T = dijkstra.PriorityQueue, t = {}, key;
1361
+ var T = dijkstra.PriorityQueue, t = {}, key3;
1362
1362
  opts = opts || {};
1363
- for (key in T) {
1364
- if (T.hasOwnProperty(key)) {
1365
- t[key] = T[key];
1363
+ for (key3 in T) {
1364
+ if (T.hasOwnProperty(key3)) {
1365
+ t[key3] = T[key3];
1366
1366
  }
1367
1367
  }
1368
1368
  t.queue = [];
@@ -1410,13 +1410,13 @@ var require_segments = __commonJS({
1410
1410
  var Regex = require_regex();
1411
1411
  var Utils = require_utils();
1412
1412
  var dijkstra = require_dijkstra();
1413
- function getStringByteLength(str) {
1414
- return unescape(encodeURIComponent(str)).length;
1413
+ function getStringByteLength(str3) {
1414
+ return unescape(encodeURIComponent(str3)).length;
1415
1415
  }
1416
- function getSegments(regex, mode, str) {
1416
+ function getSegments(regex, mode, str3) {
1417
1417
  const segments = [];
1418
1418
  let result;
1419
- while ((result = regex.exec(str)) !== null) {
1419
+ while ((result = regex.exec(str3)) !== null) {
1420
1420
  segments.push({
1421
1421
  data: result[0],
1422
1422
  index: result.index,
@@ -1513,18 +1513,18 @@ var require_segments = __commonJS({
1513
1513
  const currentNodeIds = [];
1514
1514
  for (let j = 0; j < nodeGroup.length; j++) {
1515
1515
  const node = nodeGroup[j];
1516
- const key = "" + i + j;
1517
- currentNodeIds.push(key);
1518
- table[key] = { node, lastCount: 0 };
1519
- graph[key] = {};
1516
+ const key3 = "" + i + j;
1517
+ currentNodeIds.push(key3);
1518
+ table[key3] = { node, lastCount: 0 };
1519
+ graph[key3] = {};
1520
1520
  for (let n = 0; n < prevNodeIds.length; n++) {
1521
1521
  const prevNodeId = prevNodeIds[n];
1522
1522
  if (table[prevNodeId] && table[prevNodeId].node.mode === node.mode) {
1523
- graph[prevNodeId][key] = getSegmentBitsLength(table[prevNodeId].lastCount + node.length, node.mode) - getSegmentBitsLength(table[prevNodeId].lastCount, node.mode);
1523
+ graph[prevNodeId][key3] = getSegmentBitsLength(table[prevNodeId].lastCount + node.length, node.mode) - getSegmentBitsLength(table[prevNodeId].lastCount, node.mode);
1524
1524
  table[prevNodeId].lastCount += node.length;
1525
1525
  } else {
1526
1526
  if (table[prevNodeId]) table[prevNodeId].lastCount = node.length;
1527
- graph[prevNodeId][key] = getSegmentBitsLength(node.length, node.mode) + 4 + Mode.getCharCountIndicator(node.mode, version);
1527
+ graph[prevNodeId][key3] = getSegmentBitsLength(node.length, node.mode) + 4 + Mode.getCharCountIndicator(node.mode, version);
1528
1528
  }
1529
1529
  }
1530
1530
  }
@@ -4250,13 +4250,13 @@ var require_svg_tag = __commonJS({
4250
4250
  var Utils = require_utils2();
4251
4251
  function getColorAttrib(color, attrib) {
4252
4252
  const alpha = color.a / 255;
4253
- const str = attrib + '="' + color.hex + '"';
4254
- return alpha < 1 ? str + " " + attrib + '-opacity="' + alpha.toFixed(2).slice(1) + '"' : str;
4253
+ const str3 = attrib + '="' + color.hex + '"';
4254
+ return alpha < 1 ? str3 + " " + attrib + '-opacity="' + alpha.toFixed(2).slice(1) + '"' : str3;
4255
4255
  }
4256
4256
  function svgCmd(cmd, x, y) {
4257
- let str = cmd + x;
4258
- if (typeof y !== "undefined") str += " " + y;
4259
- return str;
4257
+ let str3 = cmd + x;
4258
+ if (typeof y !== "undefined") str3 += " " + y;
4259
+ return str3;
4260
4260
  }
4261
4261
  function qrToPath(data, size, margin) {
4262
4262
  let path = "";
@@ -4738,9 +4738,9 @@ var util;
4738
4738
  };
4739
4739
  util2.objectKeys = typeof Object.keys === "function" ? (obj) => Object.keys(obj) : (object) => {
4740
4740
  const keys = [];
4741
- for (const key in object) {
4742
- if (Object.prototype.hasOwnProperty.call(object, key)) {
4743
- keys.push(key);
4741
+ for (const key3 in object) {
4742
+ if (Object.prototype.hasOwnProperty.call(object, key3)) {
4743
+ keys.push(key3);
4744
4744
  }
4745
4745
  }
4746
4746
  return keys;
@@ -5140,10 +5140,10 @@ var ParseStatus = class _ParseStatus {
5140
5140
  static async mergeObjectAsync(status, pairs) {
5141
5141
  const syncPairs = [];
5142
5142
  for (const pair of pairs) {
5143
- const key = await pair.key;
5143
+ const key3 = await pair.key;
5144
5144
  const value = await pair.value;
5145
5145
  syncPairs.push({
5146
- key,
5146
+ key: key3,
5147
5147
  value
5148
5148
  });
5149
5149
  }
@@ -5152,17 +5152,17 @@ var ParseStatus = class _ParseStatus {
5152
5152
  static mergeObjectSync(status, pairs) {
5153
5153
  const finalObject = {};
5154
5154
  for (const pair of pairs) {
5155
- const { key, value } = pair;
5156
- if (key.status === "aborted")
5155
+ const { key: key3, value } = pair;
5156
+ if (key3.status === "aborted")
5157
5157
  return INVALID;
5158
5158
  if (value.status === "aborted")
5159
5159
  return INVALID;
5160
- if (key.status === "dirty")
5160
+ if (key3.status === "dirty")
5161
5161
  status.dirty();
5162
5162
  if (value.status === "dirty")
5163
5163
  status.dirty();
5164
- if (key.value !== "__proto__" && (typeof value.value !== "undefined" || pair.alwaysSet)) {
5165
- finalObject[key.value] = value.value;
5164
+ if (key3.value !== "__proto__" && (typeof value.value !== "undefined" || pair.alwaysSet)) {
5165
+ finalObject[key3.value] = value.value;
5166
5166
  }
5167
5167
  }
5168
5168
  return { status: status.value, value: finalObject };
@@ -5187,12 +5187,12 @@ var errorUtil;
5187
5187
 
5188
5188
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
5189
5189
  var ParseInputLazyPath = class {
5190
- constructor(parent, value, path, key) {
5190
+ constructor(parent, value, path, key3) {
5191
5191
  this._cachedPath = [];
5192
5192
  this.parent = parent;
5193
5193
  this.data = value;
5194
5194
  this._path = path;
5195
- this._key = key;
5195
+ this._key = key3;
5196
5196
  }
5197
5197
  get path() {
5198
5198
  if (!this._cachedPath.length) {
@@ -5471,8 +5471,8 @@ var ZodType = class {
5471
5471
  promise() {
5472
5472
  return ZodPromise.create(this, this._def);
5473
5473
  }
5474
- or(option) {
5475
- return ZodUnion.create([this, option], this._def);
5474
+ or(option3) {
5475
+ return ZodUnion.create([this, option3], this._def);
5476
5476
  }
5477
5477
  and(incoming) {
5478
5478
  return ZodIntersection.create(this, incoming, this._def);
@@ -6937,9 +6937,9 @@ ZodArray.create = (schema, params) => {
6937
6937
  function deepPartialify(schema) {
6938
6938
  if (schema instanceof ZodObject) {
6939
6939
  const newShape = {};
6940
- for (const key in schema.shape) {
6941
- const fieldSchema = schema.shape[key];
6942
- newShape[key] = ZodOptional.create(deepPartialify(fieldSchema));
6940
+ for (const key3 in schema.shape) {
6941
+ const fieldSchema = schema.shape[key3];
6942
+ newShape[key3] = ZodOptional.create(deepPartialify(fieldSchema));
6943
6943
  }
6944
6944
  return new ZodObject({
6945
6945
  ...schema._def,
@@ -6990,29 +6990,29 @@ var ZodObject = class _ZodObject extends ZodType {
6990
6990
  const { shape, keys: shapeKeys } = this._getCached();
6991
6991
  const extraKeys = [];
6992
6992
  if (!(this._def.catchall instanceof ZodNever && this._def.unknownKeys === "strip")) {
6993
- for (const key in ctx.data) {
6994
- if (!shapeKeys.includes(key)) {
6995
- extraKeys.push(key);
6993
+ for (const key3 in ctx.data) {
6994
+ if (!shapeKeys.includes(key3)) {
6995
+ extraKeys.push(key3);
6996
6996
  }
6997
6997
  }
6998
6998
  }
6999
6999
  const pairs = [];
7000
- for (const key of shapeKeys) {
7001
- const keyValidator = shape[key];
7002
- const value = ctx.data[key];
7000
+ for (const key3 of shapeKeys) {
7001
+ const keyValidator = shape[key3];
7002
+ const value = ctx.data[key3];
7003
7003
  pairs.push({
7004
- key: { status: "valid", value: key },
7005
- value: keyValidator._parse(new ParseInputLazyPath(ctx, value, ctx.path, key)),
7006
- alwaysSet: key in ctx.data
7004
+ key: { status: "valid", value: key3 },
7005
+ value: keyValidator._parse(new ParseInputLazyPath(ctx, value, ctx.path, key3)),
7006
+ alwaysSet: key3 in ctx.data
7007
7007
  });
7008
7008
  }
7009
7009
  if (this._def.catchall instanceof ZodNever) {
7010
7010
  const unknownKeys = this._def.unknownKeys;
7011
7011
  if (unknownKeys === "passthrough") {
7012
- for (const key of extraKeys) {
7012
+ for (const key3 of extraKeys) {
7013
7013
  pairs.push({
7014
- key: { status: "valid", value: key },
7015
- value: { status: "valid", value: ctx.data[key] }
7014
+ key: { status: "valid", value: key3 },
7015
+ value: { status: "valid", value: ctx.data[key3] }
7016
7016
  });
7017
7017
  }
7018
7018
  } else if (unknownKeys === "strict") {
@@ -7029,15 +7029,15 @@ var ZodObject = class _ZodObject extends ZodType {
7029
7029
  }
7030
7030
  } else {
7031
7031
  const catchall = this._def.catchall;
7032
- for (const key of extraKeys) {
7033
- const value = ctx.data[key];
7032
+ for (const key3 of extraKeys) {
7033
+ const value = ctx.data[key3];
7034
7034
  pairs.push({
7035
- key: { status: "valid", value: key },
7035
+ key: { status: "valid", value: key3 },
7036
7036
  value: catchall._parse(
7037
- new ParseInputLazyPath(ctx, value, ctx.path, key)
7037
+ new ParseInputLazyPath(ctx, value, ctx.path, key3)
7038
7038
  //, ctx.child(key), value, getParsedType(value)
7039
7039
  ),
7040
- alwaysSet: key in ctx.data
7040
+ alwaysSet: key3 in ctx.data
7041
7041
  });
7042
7042
  }
7043
7043
  }
@@ -7045,10 +7045,10 @@ var ZodObject = class _ZodObject extends ZodType {
7045
7045
  return Promise.resolve().then(async () => {
7046
7046
  const syncPairs = [];
7047
7047
  for (const pair of pairs) {
7048
- const key = await pair.key;
7048
+ const key3 = await pair.key;
7049
7049
  const value = await pair.value;
7050
7050
  syncPairs.push({
7051
- key,
7051
+ key: key3,
7052
7052
  value,
7053
7053
  alwaysSet: pair.alwaysSet
7054
7054
  });
@@ -7173,8 +7173,8 @@ var ZodObject = class _ZodObject extends ZodType {
7173
7173
  // }) as any;
7174
7174
  // return merged;
7175
7175
  // }
7176
- setKey(key, schema) {
7177
- return this.augment({ [key]: schema });
7176
+ setKey(key3, schema) {
7177
+ return this.augment({ [key3]: schema });
7178
7178
  }
7179
7179
  // merge<Incoming extends AnyZodObject>(
7180
7180
  // merging: Incoming
@@ -7205,9 +7205,9 @@ var ZodObject = class _ZodObject extends ZodType {
7205
7205
  }
7206
7206
  pick(mask) {
7207
7207
  const shape = {};
7208
- for (const key of util.objectKeys(mask)) {
7209
- if (mask[key] && this.shape[key]) {
7210
- shape[key] = this.shape[key];
7208
+ for (const key3 of util.objectKeys(mask)) {
7209
+ if (mask[key3] && this.shape[key3]) {
7210
+ shape[key3] = this.shape[key3];
7211
7211
  }
7212
7212
  }
7213
7213
  return new _ZodObject({
@@ -7217,9 +7217,9 @@ var ZodObject = class _ZodObject extends ZodType {
7217
7217
  }
7218
7218
  omit(mask) {
7219
7219
  const shape = {};
7220
- for (const key of util.objectKeys(this.shape)) {
7221
- if (!mask[key]) {
7222
- shape[key] = this.shape[key];
7220
+ for (const key3 of util.objectKeys(this.shape)) {
7221
+ if (!mask[key3]) {
7222
+ shape[key3] = this.shape[key3];
7223
7223
  }
7224
7224
  }
7225
7225
  return new _ZodObject({
@@ -7235,12 +7235,12 @@ var ZodObject = class _ZodObject extends ZodType {
7235
7235
  }
7236
7236
  partial(mask) {
7237
7237
  const newShape = {};
7238
- for (const key of util.objectKeys(this.shape)) {
7239
- const fieldSchema = this.shape[key];
7240
- if (mask && !mask[key]) {
7241
- newShape[key] = fieldSchema;
7238
+ for (const key3 of util.objectKeys(this.shape)) {
7239
+ const fieldSchema = this.shape[key3];
7240
+ if (mask && !mask[key3]) {
7241
+ newShape[key3] = fieldSchema;
7242
7242
  } else {
7243
- newShape[key] = fieldSchema.optional();
7243
+ newShape[key3] = fieldSchema.optional();
7244
7244
  }
7245
7245
  }
7246
7246
  return new _ZodObject({
@@ -7250,16 +7250,16 @@ var ZodObject = class _ZodObject extends ZodType {
7250
7250
  }
7251
7251
  required(mask) {
7252
7252
  const newShape = {};
7253
- for (const key of util.objectKeys(this.shape)) {
7254
- if (mask && !mask[key]) {
7255
- newShape[key] = this.shape[key];
7253
+ for (const key3 of util.objectKeys(this.shape)) {
7254
+ if (mask && !mask[key3]) {
7255
+ newShape[key3] = this.shape[key3];
7256
7256
  } else {
7257
- const fieldSchema = this.shape[key];
7257
+ const fieldSchema = this.shape[key3];
7258
7258
  let newField = fieldSchema;
7259
7259
  while (newField instanceof ZodOptional) {
7260
7260
  newField = newField._def.innerType;
7261
7261
  }
7262
- newShape[key] = newField;
7262
+ newShape[key3] = newField;
7263
7263
  }
7264
7264
  }
7265
7265
  return new _ZodObject({
@@ -7322,7 +7322,7 @@ var ZodUnion = class extends ZodType {
7322
7322
  return INVALID;
7323
7323
  }
7324
7324
  if (ctx.common.async) {
7325
- return Promise.all(options.map(async (option) => {
7325
+ return Promise.all(options.map(async (option3) => {
7326
7326
  const childCtx = {
7327
7327
  ...ctx,
7328
7328
  common: {
@@ -7332,7 +7332,7 @@ var ZodUnion = class extends ZodType {
7332
7332
  parent: null
7333
7333
  };
7334
7334
  return {
7335
- result: await option._parseAsync({
7335
+ result: await option3._parseAsync({
7336
7336
  data: ctx.data,
7337
7337
  path: ctx.path,
7338
7338
  parent: childCtx
@@ -7343,7 +7343,7 @@ var ZodUnion = class extends ZodType {
7343
7343
  } else {
7344
7344
  let dirty = void 0;
7345
7345
  const issues = [];
7346
- for (const option of options) {
7346
+ for (const option3 of options) {
7347
7347
  const childCtx = {
7348
7348
  ...ctx,
7349
7349
  common: {
@@ -7352,7 +7352,7 @@ var ZodUnion = class extends ZodType {
7352
7352
  },
7353
7353
  parent: null
7354
7354
  };
7355
- const result = option._parseSync({
7355
+ const result = option3._parseSync({
7356
7356
  data: ctx.data,
7357
7357
  path: ctx.path,
7358
7358
  parent: childCtx
@@ -7433,8 +7433,8 @@ var ZodDiscriminatedUnion = class _ZodDiscriminatedUnion extends ZodType {
7433
7433
  }
7434
7434
  const discriminator = this.discriminator;
7435
7435
  const discriminatorValue = ctx.data[discriminator];
7436
- const option = this.optionsMap.get(discriminatorValue);
7437
- if (!option) {
7436
+ const option3 = this.optionsMap.get(discriminatorValue);
7437
+ if (!option3) {
7438
7438
  addIssueToContext(ctx, {
7439
7439
  code: ZodIssueCode.invalid_union_discriminator,
7440
7440
  options: Array.from(this.optionsMap.keys()),
@@ -7443,13 +7443,13 @@ var ZodDiscriminatedUnion = class _ZodDiscriminatedUnion extends ZodType {
7443
7443
  return INVALID;
7444
7444
  }
7445
7445
  if (ctx.common.async) {
7446
- return option._parseAsync({
7446
+ return option3._parseAsync({
7447
7447
  data: ctx.data,
7448
7448
  path: ctx.path,
7449
7449
  parent: ctx
7450
7450
  });
7451
7451
  } else {
7452
- return option._parseSync({
7452
+ return option3._parseSync({
7453
7453
  data: ctx.data,
7454
7454
  path: ctx.path,
7455
7455
  parent: ctx
@@ -7503,14 +7503,14 @@ function mergeValues(a, b) {
7503
7503
  return { valid: true, data: a };
7504
7504
  } else if (aType === ZodParsedType.object && bType === ZodParsedType.object) {
7505
7505
  const bKeys = util.objectKeys(b);
7506
- const sharedKeys = util.objectKeys(a).filter((key) => bKeys.indexOf(key) !== -1);
7506
+ const sharedKeys = util.objectKeys(a).filter((key3) => bKeys.indexOf(key3) !== -1);
7507
7507
  const newObj = { ...a, ...b };
7508
- for (const key of sharedKeys) {
7509
- const sharedValue = mergeValues(a[key], b[key]);
7508
+ for (const key3 of sharedKeys) {
7509
+ const sharedValue = mergeValues(a[key3], b[key3]);
7510
7510
  if (!sharedValue.valid) {
7511
7511
  return { valid: false };
7512
7512
  }
7513
- newObj[key] = sharedValue.data;
7513
+ newObj[key3] = sharedValue.data;
7514
7514
  }
7515
7515
  return { valid: true, data: newObj };
7516
7516
  } else if (aType === ZodParsedType.array && bType === ZodParsedType.array) {
@@ -7674,11 +7674,11 @@ var ZodRecord = class _ZodRecord extends ZodType {
7674
7674
  const pairs = [];
7675
7675
  const keyType = this._def.keyType;
7676
7676
  const valueType = this._def.valueType;
7677
- for (const key in ctx.data) {
7677
+ for (const key3 in ctx.data) {
7678
7678
  pairs.push({
7679
- key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, key)),
7680
- value: valueType._parse(new ParseInputLazyPath(ctx, ctx.data[key], ctx.path, key)),
7681
- alwaysSet: key in ctx.data
7679
+ key: keyType._parse(new ParseInputLazyPath(ctx, key3, ctx.path, key3)),
7680
+ value: valueType._parse(new ParseInputLazyPath(ctx, ctx.data[key3], ctx.path, key3)),
7681
+ alwaysSet: key3 in ctx.data
7682
7682
  });
7683
7683
  }
7684
7684
  if (ctx.common.async) {
@@ -7726,9 +7726,9 @@ var ZodMap = class extends ZodType {
7726
7726
  }
7727
7727
  const keyType = this._def.keyType;
7728
7728
  const valueType = this._def.valueType;
7729
- const pairs = [...ctx.data.entries()].map(([key, value], index) => {
7729
+ const pairs = [...ctx.data.entries()].map(([key3, value], index) => {
7730
7730
  return {
7731
- key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index, "key"])),
7731
+ key: keyType._parse(new ParseInputLazyPath(ctx, key3, ctx.path, [index, "key"])),
7732
7732
  value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index, "value"]))
7733
7733
  };
7734
7734
  });
@@ -7736,30 +7736,30 @@ var ZodMap = class extends ZodType {
7736
7736
  const finalMap = /* @__PURE__ */ new Map();
7737
7737
  return Promise.resolve().then(async () => {
7738
7738
  for (const pair of pairs) {
7739
- const key = await pair.key;
7739
+ const key3 = await pair.key;
7740
7740
  const value = await pair.value;
7741
- if (key.status === "aborted" || value.status === "aborted") {
7741
+ if (key3.status === "aborted" || value.status === "aborted") {
7742
7742
  return INVALID;
7743
7743
  }
7744
- if (key.status === "dirty" || value.status === "dirty") {
7744
+ if (key3.status === "dirty" || value.status === "dirty") {
7745
7745
  status.dirty();
7746
7746
  }
7747
- finalMap.set(key.value, value.value);
7747
+ finalMap.set(key3.value, value.value);
7748
7748
  }
7749
7749
  return { status: status.value, value: finalMap };
7750
7750
  });
7751
7751
  } else {
7752
7752
  const finalMap = /* @__PURE__ */ new Map();
7753
7753
  for (const pair of pairs) {
7754
- const key = pair.key;
7754
+ const key3 = pair.key;
7755
7755
  const value = pair.value;
7756
- if (key.status === "aborted" || value.status === "aborted") {
7756
+ if (key3.status === "aborted" || value.status === "aborted") {
7757
7757
  return INVALID;
7758
7758
  }
7759
- if (key.status === "dirty" || value.status === "dirty") {
7759
+ if (key3.status === "dirty" || value.status === "dirty") {
7760
7760
  status.dirty();
7761
7761
  }
7762
- finalMap.set(key.value, value.value);
7762
+ finalMap.set(key3.value, value.value);
7763
7763
  }
7764
7764
  return { status: status.value, value: finalMap };
7765
7765
  }
@@ -8641,7 +8641,7 @@ import { join as join2 } from "path";
8641
8641
  import { execFileSync as execFileSync2 } from "child_process";
8642
8642
  var import_undici = __toESM(require_undici(), 1);
8643
8643
  var require2 = __sdkCreateRequire(import.meta.url);
8644
- var CODEX_ENV = ["CODEX_THREAD_ID", "CODEX_SESSION_ID", "PAIGY_TOKEN", "PAIGY_SESSION_ID", "PAIGY_HARNESS", "PAIGY_INSTANCE_ID"];
8644
+ var CODEX_ENV = ["CODEX_THREAD_ID", "CODEX_SESSION_ID", "CODEX_HOME", "PAIGY_TOKEN", "PAIGY_SESSION_ID", "PAIGY_HARNESS", "PAIGY_INSTANCE_ID", "PAIGY_ON_WAKE"];
8645
8645
  var BACKEND_URL = process.env.PAIGY_BACKEND_URL ?? "https://paigy.ai";
8646
8646
  var NETWORK_MSG = `Can't reach ${BACKEND_URL} \u2014 the connection was blocked or dropped before an HTTP response. If this agent runs in a sandboxed environment with a network allowlist (e.g. Claude Code on the web, CI), ask the user to add the Paigy domain (paigy.ai) to the environment's allowed domains, then retry.`;
8647
8647
  var PROXY_ENV = ["HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy"];
@@ -8658,8 +8658,8 @@ var WORKSPACE_ID = (() => {
8658
8658
  return INSTANCE_ID;
8659
8659
  }
8660
8660
  })();
8661
- var envSession = (key) => {
8662
- const v = process.env[key];
8661
+ var envSession = (key22) => {
8662
+ const v = process.env[key22];
8663
8663
  return v && v.trim() ? v : void 0;
8664
8664
  };
8665
8665
  function parentOf(pid) {
@@ -8699,12 +8699,14 @@ async function reach(url, init) {
8699
8699
  function reachAs(session, instance) {
8700
8700
  return (url, init) => send(url, init, session, instance);
8701
8701
  }
8702
+ var CLIENT;
8702
8703
  async function send(url, init, session, instance = envSession("PAIGY_INSTANCE_ID") ?? INSTANCE_ID) {
8703
8704
  try {
8704
8705
  const headers = {
8705
8706
  ...init?.headers,
8706
8707
  "x-paigy-instance": instance,
8707
- "x-paigy-session": session
8708
+ "x-paigy-session": session,
8709
+ ...CLIENT ? { "x-paigy-client": CLIENT } : {}
8708
8710
  };
8709
8711
  return await fetch(url, { ...init, headers, dispatcher: await proxy() });
8710
8712
  } catch (e) {
@@ -8762,19 +8764,19 @@ var getRefs = (options) => {
8762
8764
  ]))
8763
8765
  };
8764
8766
  };
8765
- function addErrorMessage(res, key, errorMessage, refs) {
8767
+ function addErrorMessage(res, key22, errorMessage, refs) {
8766
8768
  if (!refs?.errorMessages)
8767
8769
  return;
8768
8770
  if (errorMessage) {
8769
8771
  res.errorMessage = {
8770
8772
  ...res.errorMessage,
8771
- [key]: errorMessage
8773
+ [key22]: errorMessage
8772
8774
  };
8773
8775
  }
8774
8776
  }
8775
- function setResponseValueAndErrors(res, key, value, errorMessage, refs) {
8776
- res[key] = value;
8777
- addErrorMessage(res, key, errorMessage, refs);
8777
+ function setResponseValueAndErrors(res, key22, value, errorMessage, refs) {
8778
+ res[key22] = value;
8779
+ addErrorMessage(res, key22, errorMessage, refs);
8778
8780
  }
8779
8781
  var getRelativePath = (pathA, pathB) => {
8780
8782
  let i = 0;
@@ -9336,11 +9338,11 @@ function parseRecordDef(def, refs) {
9336
9338
  return {
9337
9339
  type: "object",
9338
9340
  required: def.keyType._def.values,
9339
- properties: def.keyType._def.values.reduce((acc, key) => ({
9341
+ properties: def.keyType._def.values.reduce((acc, key22) => ({
9340
9342
  ...acc,
9341
- [key]: parseDef(def.valueType._def, {
9343
+ [key22]: parseDef(def.valueType._def, {
9342
9344
  ...refs,
9343
- currentPath: [...refs.currentPath, "properties", key]
9345
+ currentPath: [...refs.currentPath, "properties", key22]
9344
9346
  }) ?? parseAnyDef(refs)
9345
9347
  }), {}),
9346
9348
  additionalProperties: refs.rejectedAdditionalProperties
@@ -9403,10 +9405,10 @@ function parseMapDef(def, refs) {
9403
9405
  }
9404
9406
  function parseNativeEnumDef(def) {
9405
9407
  const object = def.values;
9406
- const actualKeys = Object.keys(def.values).filter((key) => {
9407
- return typeof object[object[key]] !== "number";
9408
+ const actualKeys = Object.keys(def.values).filter((key22) => {
9409
+ return typeof object[object[key22]] !== "number";
9408
9410
  });
9409
- const actualValues = actualKeys.map((key) => object[key]);
9411
+ const actualValues = actualKeys.map((key22) => object[key22]);
9410
9412
  const parsedTypes = Array.from(new Set(actualValues.map((values) => typeof values)));
9411
9413
  return {
9412
9414
  type: parsedTypes.length === 1 ? parsedTypes[0] === "string" ? "string" : "number" : ["string", "number"],
@@ -9971,32 +9973,31 @@ function mcpInputSchema(s) {
9971
9973
  }
9972
9974
  var AskInputSchema = external_exports.object({
9973
9975
  id: external_exports.string().optional().describe("Optional idempotency key or client-side ID for this specific ask."),
9974
- parentId: external_exports.string().uuid().optional().describe("The Goal this question is about \u2014 usually the one you are working on. The question goes onto that Goal and its answer comes back there. Omit it and Paigy places the question in the tree itself."),
9976
+ parentId: external_exports.string().uuid().optional().describe("The Goal this question is about \u2014 usually the one you are working on. The question goes onto that Goal and its answer comes back there. Omit it and the question starts a new Goal of yours."),
9975
9977
  repo: external_exports.string().optional().describe("Optional repository context."),
9976
9978
  ask: external_exports.string().trim().min(1).max(1e4).describe(
9977
- "ONE question, and only what is needed to answer it. Several questions are several asks in the array, one each: an answer settles the one ask it was given in the shape that ask declares, so a person who answers the part of a bundled ask that interested them settles nothing and is asked again. Paigy reads every ask once and takes a bundled one apart into its own cards anyway \u2014 each question a Question on the one Goal the ask lands on, never a Goal of its own \u2014 but the words it splits are its reading, not yours. News, progress and findings are their own contact; ANY contact for a person already on a call JOINS that call, whatever channel you asked for, so several arrive as one call."
9979
+ "ONE question, and only what is needed to answer it. Several questions are several asks in the array, one each: an answer settles the one ask it was given in the shape that ask declares, so a person who answers the part of a bundled ask that interested them settles nothing and is asked again. Paigy sends each ask exactly as you wrote it: a bundled ask arrives as one card. News, progress and findings are their own contact; ANY contact for a person already on a call JOINS that call, whatever channel you asked for, so several arrive as one call."
9978
9980
  ),
9979
9981
  options: external_exports.array(OptionInputSchema).min(1).max(6).optional(),
9980
- // YOUR VIEW OF ONE OR MANY, A HINT TO PAIGY'S READ (owner, 2026-10-02: "one and many makes sense...
9981
- // make sure the brain that formats is aware of how it should work"). Three independent fixes went
9982
- // out as "All three / 1 and 3 only / Just log it" because every card was pick-one. #2943 made this
9983
- // field override the read; no agent sent it, so nothing changed. The read now decides each card's
9984
- // shape (`goal/intake.ts` `answerOf`), and this reaches it as the agent's view, weighed, not obeyed.
9982
+ // HOW THE OPTIONS ARE ANSWERED, SAID BY THE AGENT (owner, 2026-10-02: "one and many makes sense";
9983
+ // brain_prompts.md §1: structured agent questions need no model). Every card was pick-one while no
9984
+ // agent sent this; no read reshapes cards any more, so this is the card's shape, and the
9985
+ // description says so plainly.
9985
9986
  select: external_exports.enum(["one", "many"]).optional().describe(
9986
- `Your view of how the options are answered: "one" to pick one, "many" to tick any number of them. A hint: Paigy's read decides each card's shape, a checklist when the options can all be wanted at once, a pick when choosing one rules out the others. The person can always answer in their own words as well. Ignored without options.`
9987
+ 'How the options are answered: "many" makes a checklist (they may want several, e.g. independent fixes), "one" (the default) a pick (choosing one rules out the others). Send "many" whenever more than one option could be wanted at once. The person can always answer in their own words as well. Ignored without options.'
9987
9988
  ),
9988
9989
  answers: external_exports.string().trim().regex(/^[0-9a-fA-F-]{8,36}$/).optional().describe(
9989
9990
  "Your reply answers a question the person asked you: the id the conversation shows for it (8 characters or whole). Their question closes with this reply as its answer, and any decision of yours it was holding back goes back to them. Needs parentId: the Goal the question is on. The reply is sent to them as it is; to also ask something new, send that as its own ask."
9990
9991
  )
9991
9992
  }).strict();
9992
9993
  var StartContactSchema = external_exports.object({
9993
- asks: external_exports.array(AskInputSchema).min(1).describe("The questions to pose, one per object. An ask with a parentId is filed on that Goal as it is; only an ask naming no Goal is placed in the tree by Paigy."),
9994
+ asks: external_exports.array(AskInputSchema).min(1).describe("The questions to pose, one per object. An ask with a parentId is filed on that Goal as it is; an ask naming no Goal starts a new Goal of yours."),
9994
9995
  waiting: external_exports.enum(["none", "hard"]).default("none").describe("hard requests a call even when channel is notification; user permissions and ring cooldowns still apply."),
9995
9996
  channel: external_exports.enum(["notification", "call"]).default("notification")
9996
9997
  }).strict();
9997
9998
  var ContactSchema = external_exports.union([StartContactSchema, external_exports.object({ deliveryId: external_exports.string().uuid() }).strict()]);
9998
9999
  var CONTACT_SCHEMA = { type: "object", ...mcpInputSchema(ContactSchema) };
9999
- var CONTACT_DESCRIPTION = "Contact the user with one or more asks/questions. Pass an array of asks (each with 'ask', optional 'options', 'select', 'id', 'parentId', 'repo'), plus channel:'notification'|'call', and waiting:'none'|'hard'. An ask that names a Goal (parentId) goes onto that Goal; one that names none is placed in the person's tree by Paigy. Notification returns immediately; collect durable answers with check_replies. On stdio, a Call holds one cancellable ~45s window; continue with ONLY {deliveryId}. One question per 'ask'; several questions are several objects in 'asks'. A bundled ask is taken apart into its own cards by Paigy's one intake read, every one on the Goal the ask lands on; separate pieces of work are separate asks. An ask with no options that is not blocking is a report, and a report is an UPDATE, never a claim on them: it reaches them and is listed apart from what waits on them, so no answer is owed and none should be awaited. On a Goal whose report card is still open it is added to that card, with no new push; one that only says where your work stands while under way is recorded as the Goal's progress, not sent (the result says so). Send options (or waiting:'hard') when you actually need an answer. Each option's label must stand on its own \u2014 the person may see only the labels \u2014 so never a label that points into your text ('All three', 'Option 2', '1 and 3 only'). Whether a card is a checklist or a pick is decided by Paigy's read: independent options they may want several of become a checklist, alternatives a pick. select:'many' or select:'one' tells it your view, a hint it weighs. The person can always answer in their own words, so never add an 'Other' option. If the person is already on a call, your contact joins that call automatically \u2014 whatever channel you asked for, with no ring \u2014 and the Delivery it returns IS that call: reread it with contact({deliveryId}) to see everything answered on it so far, and contact again while it is live to add information or a further question to the same call.";
10000
+ var CONTACT_DESCRIPTION = "Contact the user with one or more asks/questions. Pass an array of asks (each with 'ask', optional 'options', 'select', 'id', 'parentId', 'repo'), plus channel:'notification'|'call', and waiting:'none'|'hard'. An ask that names a Goal (parentId) goes onto that Goal; one that names none starts a new Goal of yours. Notification returns immediately; collect durable answers with check_replies. On stdio, a Call holds one cancellable ~45s window; continue with ONLY {deliveryId}. One question per 'ask'; several questions are several objects in 'asks'. Each ask is sent exactly as written, with no reading in between: a bundled ask arrives as one card, so separate questions are separate asks. An ask with no options that is not blocking is a report, and a report is an UPDATE, never a claim on them: it reaches them and is listed apart from what waits on them, so no answer is owed and none should be awaited. On a Goal whose report card is still open it is added to that card, with no new push; Where your work stands while under way is progress: report it with update_goal, not contact. Send options (or waiting:'hard') when you actually need an answer. Each option's label must stand on its own \u2014 the person may see only the labels \u2014 so never a label that points into your text ('All three', 'Option 2', '1 and 3 only'). select:'many' makes the card a checklist, for independent options they may want several of; select:'one' (the default) a pick, for alternatives. The person can always answer in their own words, so never add an 'Other' option. If the person is already on a call, your contact joins that call automatically \u2014 whatever channel you asked for, with no ring \u2014 and the Delivery it returns IS that call: reread it with contact({deliveryId}) to see everything answered on it so far, and contact again while it is live to add information or a further question to the same call.";
10000
10001
  var CreateGoalSchema = external_exports.object({
10001
10002
  outcome: external_exports.string().trim().min(1).max(1e4),
10002
10003
  /** The work's NAME (#2115) — one to five words, how a person refers to it out loud ("the night
@@ -10070,6 +10071,156 @@ var AGENT_TOOLS = [
10070
10071
  { name: "update_goal", description: UPDATE_GOAL_DESCRIPTION, inputSchema: mcpInputSchema(UpdateGoalToolSchema) }
10071
10072
  ];
10072
10073
  var AGENT_TOOL_NAMES = AGENT_TOOLS.map((t) => t.name);
10074
+ var id = external_exports.string().uuid();
10075
+ var key = external_exports.string().min(1).max(40);
10076
+ var participant = external_exports.string().regex(/^(human|agent):.+$/, "a participant ID such as agent:<uuid>");
10077
+ var SourceSchema = external_exports.object({
10078
+ entryId: id,
10079
+ span: external_exports.object({ start: external_exports.number().int().min(0), end: external_exports.number().int().min(1) }).strict().refine((s) => s.end > s.start, "a span ends after it starts").optional()
10080
+ }).strict();
10081
+ var ResultRefSchema = external_exports.union([external_exports.object({ id }).strict(), external_exports.object({ local: key }).strict()]);
10082
+ var NodeRefSchema = external_exports.object({ type: external_exports.enum(["goal", "question"]), id }).strict();
10083
+ var DependencySchema = external_exports.object({
10084
+ blocker: NodeRefSchema,
10085
+ blocked: NodeRefSchema,
10086
+ action: external_exports.enum(["start", "complete", "answer"]),
10087
+ reason: external_exports.string().max(500).optional()
10088
+ }).strict();
10089
+ var goalState = external_exports.enum(["open", "completed", "canceled"]);
10090
+ var existingGoalChanges = [
10091
+ external_exports.object({ kind: external_exports.literal("edit"), goalId: id, title: external_exports.string().min(1).max(120).optional(), outcome: external_exports.string().min(1).optional() }).strict().refine((c) => c.title !== void 0 || c.outcome !== void 0, "an edit changes the title or the outcome"),
10092
+ external_exports.object({ kind: external_exports.literal("state"), goalId: id, state: goalState }).strict(),
10093
+ external_exports.object({ kind: external_exports.literal("assign"), goalId: id, ownerId: participant }).strict(),
10094
+ external_exports.object({ kind: external_exports.literal("defer"), goalId: id, until: external_exports.string().datetime().nullable() }).strict(),
10095
+ external_exports.object({ kind: external_exports.literal("move"), goalId: id, parentGoalId: id.nullable() }).strict(),
10096
+ external_exports.object({
10097
+ kind: external_exports.literal("dependency"),
10098
+ change: external_exports.enum(["add", "remove"]),
10099
+ goalId: id,
10100
+ dependsOnGoalId: id,
10101
+ action: external_exports.enum(["start", "complete"]),
10102
+ reason: external_exports.string().max(500).optional()
10103
+ }).strict()
10104
+ ];
10105
+ var GoalChangeSchema = external_exports.union([
10106
+ external_exports.object({
10107
+ kind: external_exports.literal("create"),
10108
+ title: external_exports.string().min(1).max(120),
10109
+ outcome: external_exports.string().min(1),
10110
+ ownerId: participant,
10111
+ parentGoalId: id.optional(),
10112
+ sourceEntryIds: external_exports.array(id)
10113
+ }).strict(),
10114
+ ...existingGoalChanges
10115
+ ]);
10116
+ var BrainGoalChangeSchema = external_exports.union([
10117
+ // newSession: Paigy starts a session to own it (owner, 2026-10-06); until it has, the person owns it.
10118
+ external_exports.object({
10119
+ kind: external_exports.literal("create"),
10120
+ outcome: external_exports.string().min(1),
10121
+ title: external_exports.string().min(1).max(120),
10122
+ ownerId: participant,
10123
+ parentGoal: ResultRefSchema.nullable(),
10124
+ newSession: external_exports.literal(true).optional()
10125
+ }).strict(),
10126
+ ...existingGoalChanges
10127
+ ]);
10128
+ var option = external_exports.object({ id: external_exports.string().min(1).max(40), label: external_exports.string().min(1), hint: external_exports.string().optional() }).strict();
10129
+ var QuestionChangeSchema = external_exports.union([
10130
+ external_exports.object({
10131
+ kind: external_exports.literal("create"),
10132
+ text: external_exports.string().min(1),
10133
+ answererId: participant,
10134
+ goal: ResultRefSchema.optional(),
10135
+ blocks: external_exports.array(external_exports.object({ question: ResultRefSchema }).strict()),
10136
+ options: external_exports.array(option).min(2).optional(),
10137
+ pickMode: external_exports.enum(["one", "many", "rank"]).optional()
10138
+ }).strict().refine((c) => c.options === void 0 === (c.pickMode === void 0), "options and pickMode come together"),
10139
+ external_exports.object({ kind: external_exports.literal("edit"), questionId: id, text: external_exports.string().min(1) }).strict(),
10140
+ external_exports.object({ kind: external_exports.literal("assign"), questionId: id, answererId: participant }).strict(),
10141
+ external_exports.object({ kind: external_exports.literal("withdraw"), questionId: id }).strict(),
10142
+ external_exports.object({ kind: external_exports.literal("dependency"), change: external_exports.enum(["add", "remove"]), edge: DependencySchema }).strict()
10143
+ ]);
10144
+ var lessonScope = external_exports.union([
10145
+ external_exports.object({ kind: external_exports.literal("user") }).strict(),
10146
+ external_exports.object({ kind: external_exports.literal("goal"), goal: ResultRefSchema }).strict()
10147
+ ]);
10148
+ var LessonChangeSchema = external_exports.union([
10149
+ external_exports.object({ kind: external_exports.literal("remember"), text: external_exports.string().min(1), scope: lessonScope }).strict(),
10150
+ external_exports.object({ kind: external_exports.literal("revise"), lessonId: id, text: external_exports.string().min(1), scope: lessonScope }).strict(),
10151
+ external_exports.object({ kind: external_exports.literal("withdraw"), lessonId: id }).strict()
10152
+ ]);
10153
+ var BrainNextSchema = external_exports.object({
10154
+ instructions: external_exports.array(external_exports.object({ entryKeys: external_exports.array(key).min(1) }).strict()),
10155
+ say: external_exports.array(key),
10156
+ then: external_exports.enum(["listen", "hold", "end", "none"]),
10157
+ waitFor: external_exports.array(ResultRefSchema),
10158
+ reason: external_exports.string()
10159
+ }).strict();
10160
+ var messageBase = {
10161
+ key,
10162
+ text: external_exports.string().min(1),
10163
+ goals: external_exports.array(ResultRefSchema),
10164
+ questions: external_exports.array(ResultRefSchema),
10165
+ entryKeys: external_exports.array(key),
10166
+ obligationIds: external_exports.array(id)
10167
+ };
10168
+ var BrainMessageSchema = external_exports.union([
10169
+ external_exports.object({ ...messageBase, to: external_exports.object({ kind: external_exports.literal("user") }).strict() }).strict(),
10170
+ external_exports.object({
10171
+ ...messageBase,
10172
+ to: external_exports.object({ kind: external_exports.literal("session"), sessionId: id }).strict(),
10173
+ call: external_exports.object({ callId: id, listen: external_exports.literal(true) }).strict().optional()
10174
+ }).strict()
10175
+ ]);
10176
+ var BrainSearchSchema = external_exports.object({
10177
+ query: external_exports.string().min(1).max(500),
10178
+ within: external_exports.array(external_exports.enum(["entries", "goals", "answers"])).min(1),
10179
+ goalId: id.optional()
10180
+ }).strict();
10181
+ var BrainResultSchema = external_exports.object({
10182
+ messages: external_exports.array(BrainMessageSchema),
10183
+ entries: external_exports.array(external_exports.object({ key, sources: external_exports.array(SourceSchema).min(1), goals: external_exports.array(ResultRefSchema) }).strict()),
10184
+ questions: external_exports.array(external_exports.object({ key, entryKeys: external_exports.array(key), change: QuestionChangeSchema }).strict()),
10185
+ answers: external_exports.array(external_exports.object({
10186
+ question: ResultRefSchema,
10187
+ entryKeys: external_exports.array(key).min(1),
10188
+ summary: external_exports.string().min(1),
10189
+ selectedOptionIds: external_exports.array(external_exports.string().min(1)).optional()
10190
+ }).strict()),
10191
+ goals: external_exports.array(external_exports.object({ key, entryKeys: external_exports.array(key), change: BrainGoalChangeSchema }).strict()),
10192
+ feedback: external_exports.array(external_exports.object({ entryKeys: external_exports.array(key).min(1) }).strict()),
10193
+ lessons: external_exports.array(external_exports.object({ entryKeys: external_exports.array(key).min(1), change: LessonChangeSchema }).strict()),
10194
+ next: BrainNextSchema,
10195
+ search: BrainSearchSchema.optional()
10196
+ }).strict();
10197
+ var str = external_exports.string();
10198
+ var strs = external_exports.array(external_exports.string());
10199
+ var CompactResultSchema = external_exports.object({
10200
+ next: external_exports.object({ say: strs, then: external_exports.enum(["listen", "hold", "end", "none"]), waitFor: strs, reason: str, instructions: strs }).strict(),
10201
+ messages: external_exports.array(external_exports.object({ key: str, to: str, text: str, about: strs, entries: strs, owed: strs, inviteToCall: external_exports.boolean() }).strict()),
10202
+ entries: external_exports.array(external_exports.object({ key: str, from: str, start: external_exports.number().int(), end: external_exports.number().int(), on: strs }).strict()),
10203
+ answers: external_exports.array(external_exports.object({ question: str, entries: strs, summary: str, picked: strs }).strict()),
10204
+ changes: external_exports.array(external_exports.object({
10205
+ key: str,
10206
+ what: external_exports.enum(["goal", "question", "lesson"]),
10207
+ op: external_exports.enum(["create", "edit", "assign", "open", "complete", "cancel", "defer", "move", "block", "unblock", "withdraw", "remember", "revise"]),
10208
+ id: str,
10209
+ text: str,
10210
+ title: str,
10211
+ who: str,
10212
+ under: str,
10213
+ gate: external_exports.enum(["start", "complete", "answer", "none"]),
10214
+ options: external_exports.array(external_exports.object({ id: str, label: str }).strict()),
10215
+ pick: external_exports.enum(["one", "many", "rank", "words"]),
10216
+ entries: strs
10217
+ }).strict()),
10218
+ feedback: external_exports.array(strs),
10219
+ search: external_exports.object({ query: str, within: strs, goal: str }).strict()
10220
+ }).strict();
10221
+ var COMPACT_RESULT_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
10222
+ zodToJsonSchema(CompactResultSchema, { $refStrategy: "none" })
10223
+ );
10073
10224
  var LIVE_MS = 3 * 6e4;
10074
10225
  var WORKING_MS = 60 * 6e4;
10075
10226
  var ContextSchema = external_exports.object({
@@ -10289,7 +10440,7 @@ var IntentSchema = external_exports.object({
10289
10440
  * (`parseDelay`, #1292), and a value here simply wins over that reading. */
10290
10441
  dueInSeconds: external_exports.number().int().positive().optional(),
10291
10442
  /** Feedback only (#812): WHICH failure the complaint names — typed by the mapper that
10292
- * already read the utterance, so `feedback_from_call.kind` stops defaulting to
10443
+ * already read the utterance, so `signals.kind` stops defaulting to
10293
10444
  * 'other' on every row. A table that records that something was wrong and nothing
10294
10445
  * about what cannot answer "is the bot looping less this week?". */
10295
10446
  fault: external_exports.enum(["loop", "unanswered", "overridden", "misheard", "slow", "other"]).optional()
@@ -10573,7 +10724,18 @@ var InboxItemSchema = external_exports.object({
10573
10724
  /** THAT GOAL'S NAME (#2416) — what Activity's row is headed by, since a row there is one Goal
10574
10725
  * and the cards it holds sit behind it. Stamped by the same read as `goalState`. */
10575
10726
  goalTitle: external_exports.string().optional()
10576
- }).optional()
10727
+ }).optional(),
10728
+ /** WHAT THIS CARD IS, IN TWELVE CHARACTERS (#3019) — the hash of every other field on it, stamped
10729
+ * by the one read that serves the open list (`apps/api/src/inbox/project.ts` `inboxFor`). It is
10730
+ * how the incremental read knows a card has not moved: the phone echoes back the revs it holds
10731
+ * (`POST /api/inbox/changes`) and is sent only the cards whose rev differs.
10732
+ *
10733
+ * THE PAYLOAD'S OWN HASH, NEVER A STAMP ON THE WORK — the same mechanism as `QueueItem.rev`
10734
+ * (#2928) and an entry's (#3018), for the same reason: a card shows facts no `updated_at` of its
10735
+ * own moves (its Goal's state and name, how cold the work behind it has gone, whether a ring is
10736
+ * live). Optional, so a fixture, the demo and the archive lens need not spell one, and a card
10737
+ * with no rev is simply always re-sent. */
10738
+ rev: external_exports.string().optional()
10577
10739
  });
10578
10740
  var APNS_TOKEN_RE = /^[0-9a-fA-F]{64}$/;
10579
10741
  var PushTokenSchema = external_exports.object({
@@ -10945,7 +11107,22 @@ var QueueItemSchema = external_exports.object({
10945
11107
  * minute after the person speaks erases their instant from it, and the durable traces the client
10946
11108
  * can see (`replies`, `questions[].answeredAt`) miss a spontaneous note entirely — a `request`
10947
11109
  * Entry with no `about_id` is in neither. */
10948
- lastPersonAt: external_exports.string().nullable().optional()
11110
+ lastPersonAt: external_exports.string().nullable().optional(),
11111
+ /** WHAT THIS ROW IS, IN TWELVE CHARACTERS (#2928) — the hash of every other field on it, stamped
11112
+ * by the one projection that builds the row (`apps/api/src/goal/queue.ts`). It is how the
11113
+ * incremental read knows a row has not moved: the phone echoes back the revs it holds
11114
+ * (`POST /api/goals/changes`) and is sent only the rows whose rev differs.
11115
+ *
11116
+ * IT IS THE PAYLOAD'S OWN HASH, NEVER A STAMP ON THE WORK. Nothing here reasons about which
11117
+ * writes change which field — the comparison is over the bytes the phone is holding, so a fact
11118
+ * the row shows that no `updated_at` moves for (a lease lapsing, a dependency's state, a
11119
+ * sibling appearing in `childGoalIds`) cannot go unnoticed. Optional because a hand-built
11120
+ * queue (a fixture, the demo) spells none, and a row with no rev is simply always re-sent. */
11121
+ rev: external_exports.string().optional()
11122
+ });
11123
+ var QueueDeltaSchema = external_exports.object({
11124
+ ids: external_exports.array(external_exports.string()),
11125
+ items: external_exports.array(QueueItemSchema)
10949
11126
  });
10950
11127
  var COLD_AFTER_MS = 3 * 24 * 60 * 60 * 1e3;
10951
11128
  var NoteSourceSchema = external_exports.enum(["app", "call"]);
@@ -11118,6 +11295,11 @@ var DeviceTokenSchema = external_exports.object({
11118
11295
  /** Local host recovery must preserve the launch's runtime and Paigy identity. */
11119
11296
  harness: external_exports.enum(["claude", "codex", "agy"]).optional(),
11120
11297
  session_id: external_exports.string().uuid().optional(),
11298
+ /** A conversation the host must not resume: its context is full, so every turn fails
11299
+ * ("Prompt is too long"). Written when a run hits it (`run.ts` `onFull`); the host skips a slot
11300
+ * whose resumable session is this one, so its Goals reach the dead-agent handoff instead of a
11301
+ * copy that types the person's words into a turn that cannot run (Calls, 2026-10-06). */
11302
+ full_session: external_exports.string().optional(),
11121
11303
  uik_pub: external_exports.string().nullable().optional()
11122
11304
  });
11123
11305
  var SupportRequestSchema = external_exports.object({
@@ -11263,8 +11445,8 @@ var CallRecapSchema = external_exports.object({
11263
11445
  more: external_exports.object({ lines: external_exports.number(), entries: external_exports.number(), topics: external_exports.number() })
11264
11446
  });
11265
11447
  function sessionSlot(sessionId2) {
11266
- const id = sessionId2 ?? sessionId();
11267
- return `session:${id.slice(0, 8)}`;
11448
+ const id22 = sessionId2 ?? sessionId();
11449
+ return `session:${id22.slice(0, 8)}`;
11268
11450
  }
11269
11451
  function agentName() {
11270
11452
  return process.env.PAIGY_AGENT || sessionSlot();
@@ -11321,7 +11503,7 @@ function updateSlot(agent2, patch) {
11321
11503
  }
11322
11504
  function slotIdentity(agent2) {
11323
11505
  const t = readTokenFile()[agent2];
11324
- return { name: t?.name ?? null, voice: t?.voice ?? null, tokenId: t?.token_id ?? null, workspace: t?.workspace ?? null, harness: t?.harness ?? null, sessionId: t?.session_id ?? null };
11506
+ return { name: t?.name ?? null, voice: t?.voice ?? null, tokenId: t?.token_id ?? null, workspace: t?.workspace ?? null, harness: t?.harness ?? null, sessionId: t?.session_id ?? null, fullSession: t?.full_session ?? null };
11325
11507
  }
11326
11508
  var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
11327
11509
  function readToken(agent2 = agentName()) {
@@ -11483,7 +11665,9 @@ async function recordDecision(decision, opts = {}) {
11483
11665
  async function heartbeat(runtime, opts = {}) {
11484
11666
  const body = {
11485
11667
  ...runtime !== void 0 ? { runtime } : {},
11486
- ...opts.activity !== void 0 ? { activity: opts.activity } : {}
11668
+ ...opts.activity !== void 0 ? { activity: opts.activity } : {},
11669
+ // A listener's beat (`paigy-listen`): stamps when it last swept, and is not presence.
11670
+ ...opts.listening ? { listening: true } : {}
11487
11671
  };
11488
11672
  const res = await ensureAuthed(await reach(`${BACKEND_URL}/api/presence`, {
11489
11673
  method: "POST",
@@ -11575,6 +11759,7 @@ function currentRepo(cwd = process.cwd()) {
11575
11759
  return asked;
11576
11760
  }
11577
11761
  var NOT_SENT = "Recorded as progress, not sent: nobody was notified. If the person should see it (a result, something to try or check, a finding), contact again and say so; report progress with update_goal.";
11762
+ var DEMOTED = "Delivered as a card, not a call: the person's settings do not allow a call right now (silent, quiet hours, or a mode). It has reached them; do not send it again, with or without a Goal.";
11578
11763
  async function contact(input, opts = {}) {
11579
11764
  const parsed = ContactSchema.parse(input);
11580
11765
  opts.signal?.throwIfAborted();
@@ -11583,6 +11768,7 @@ async function contact(input, opts = {}) {
11583
11768
  let deliveryId;
11584
11769
  let deliveries = [];
11585
11770
  let recorded = [];
11771
+ let demoted;
11586
11772
  if ("deliveryId" in parsed) {
11587
11773
  deliveryId = parsed.deliveryId;
11588
11774
  } else {
@@ -11613,13 +11799,14 @@ async function contact(input, opts = {}) {
11613
11799
  if (!res.ok) await fail("batch contact", res);
11614
11800
  const receipt = await res.json();
11615
11801
  deliveries = receipt.deliveries ?? [];
11802
+ if (parsed.channel === "call" && receipt.channel && receipt.channel !== "call") demoted = DEMOTED;
11616
11803
  recorded = receipt.recorded ?? [];
11617
11804
  if (deliveries.length === 0 && recorded.length) return { sent: false, recorded, message: NOT_SENT };
11618
11805
  if (deliveries.length === 0) throw new Error("Goal contact returned no Delivery identities");
11619
11806
  deliveryId = deliveries[0]?.deliveryId ?? "";
11620
11807
  if (!deliveryId) throw new Error("Goal contact returned no valid Delivery identity");
11621
11808
  }
11622
- const all = deliveries.filter((d) => !!d.deliveryId && !!d.goalId).map(({ id, deliveryId: deliveryId2, goalId }) => ({ ...id ? { id } : {}, deliveryId: deliveryId2, goalId }));
11809
+ const all = deliveries.filter((d) => !!d.deliveryId && !!d.goalId).map(({ id: id22, deliveryId: deliveryId2, goalId }) => ({ ...id22 ? { id: id22 } : {}, deliveryId: deliveryId2, goalId }));
11623
11810
  const joinedCard = deliveries[0]?.joinedCard === true;
11624
11811
  const joinedCall = deliveries[0]?.joinedCall === true;
11625
11812
  const read = async (signal2) => {
@@ -11631,7 +11818,8 @@ async function contact(input, opts = {}) {
11631
11818
  ...all.length > 1 ? { deliveries: all } : {},
11632
11819
  ...recorded.length ? { recorded, notSent: NOT_SENT } : {},
11633
11820
  ...joinedCard ? { joinedCard: true } : {},
11634
- ...joinedCall ? { joinedCall: true } : {}
11821
+ ...joinedCall ? { joinedCall: true } : {},
11822
+ ...demoted ? { demoted } : {}
11635
11823
  };
11636
11824
  };
11637
11825
  const settled = (d) => d.kind === "notification" || d.state === "closed" || d.answers.length > 0 || d.entries.some((e) => e.kind === "contribution");
@@ -11768,9 +11956,9 @@ function connect(line) {
11768
11956
  ws.addEventListener("error", again);
11769
11957
  }
11770
11958
  function subscribeRealtime(args) {
11771
- const key = `${args.url} ${args.anonKey}`;
11772
- let line = lines.get(key);
11773
- if (!line) lines.set(key, line = { url: args.url, anonKey: args.anonKey, open: false, attempt: 0, ref: 0, topics: /* @__PURE__ */ new Map() });
11959
+ const key22 = `${args.url} ${args.anonKey}`;
11960
+ let line = lines.get(key22);
11961
+ if (!line) lines.set(key22, line = { url: args.url, anonKey: args.anonKey, open: false, attempt: 0, ref: 0, topics: /* @__PURE__ */ new Map() });
11774
11962
  let t = line.topics.get(args.topic);
11775
11963
  if (!t) {
11776
11964
  line.topics.set(args.topic, t = { listeners: /* @__PURE__ */ new Set(), joined: false, attempt: 0 });
@@ -11792,7 +11980,7 @@ function subscribeRealtime(args) {
11792
11980
  if (line.open) frame(line, `realtime:${args.topic}`, "phx_leave", {});
11793
11981
  return;
11794
11982
  }
11795
- lines.delete(key);
11983
+ lines.delete(key22);
11796
11984
  stop(line);
11797
11985
  try {
11798
11986
  line.ws?.close();
@@ -12241,16 +12429,16 @@ function parseVerdicts(raw, knownIds, knownAgents) {
12241
12429
  const seen = /* @__PURE__ */ new Set();
12242
12430
  for (const row of rows) {
12243
12431
  const r = row;
12244
- const id = typeof r?.id === "string" ? r.id : "";
12245
- if (!id) {
12432
+ const id3 = typeof r?.id === "string" ? r.id : "";
12433
+ if (!id3) {
12246
12434
  dropped.push({ row, reason: "no id" });
12247
12435
  continue;
12248
12436
  }
12249
- if (!knownIds.has(id)) {
12437
+ if (!knownIds.has(id3)) {
12250
12438
  dropped.push({ row, reason: "id is not a note in this queue" });
12251
12439
  continue;
12252
12440
  }
12253
- if (seen.has(id)) {
12441
+ if (seen.has(id3)) {
12254
12442
  dropped.push({ row, reason: "duplicate verdict for this note" });
12255
12443
  continue;
12256
12444
  }
@@ -12265,12 +12453,12 @@ function parseVerdicts(raw, knownIds, knownAgents) {
12265
12453
  continue;
12266
12454
  }
12267
12455
  verdicts.push({
12268
- id,
12456
+ id: id3,
12269
12457
  verdict,
12270
12458
  agent: verdict === "assign" ? agent2 : null,
12271
12459
  why: typeof r?.why === "string" ? r.why.trim().slice(0, 200) : null
12272
12460
  });
12273
- seen.add(id);
12461
+ seen.add(id3);
12274
12462
  }
12275
12463
  return { ok: true, verdicts, dropped };
12276
12464
  }
@@ -12425,7 +12613,7 @@ async function runTriage(opts, deps = {}) {
12425
12613
  const acted = suggested(run);
12426
12614
  log2(acted === 0 ? "Nothing to suggest \u2014 sent, so your phone shows the queue as clean." : `Sent to your phone \u2014 accept it there (${plural(acted, "suggestion")}).`);
12427
12615
  if (!opts.apply) return 0;
12428
- const accept = deps.accept ?? ((id, body) => acceptTriage(id, body));
12616
+ const accept = deps.accept ?? ((id3, body) => acceptTriage(id3, body));
12429
12617
  const groups = [
12430
12618
  { body: { group: "close" }, label: `close ${plural(run.close.length, "note")}`, count: run.close.length, preapproved: opts.yes.close },
12431
12619
  { body: { group: "stale" }, label: `close ${plural(run.stale.length, "stale note")}`, count: run.stale.length, preapproved: opts.yes.stale },
@@ -12848,19 +13036,19 @@ var getRefs2 = (options) => {
12848
13036
  };
12849
13037
 
12850
13038
  // ../../node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/errorMessages.js
12851
- function addErrorMessage2(res, key, errorMessage, refs) {
13039
+ function addErrorMessage2(res, key3, errorMessage, refs) {
12852
13040
  if (!refs?.errorMessages)
12853
13041
  return;
12854
13042
  if (errorMessage) {
12855
13043
  res.errorMessage = {
12856
13044
  ...res.errorMessage,
12857
- [key]: errorMessage
13045
+ [key3]: errorMessage
12858
13046
  };
12859
13047
  }
12860
13048
  }
12861
- function setResponseValueAndErrors2(res, key, value, errorMessage, refs) {
12862
- res[key] = value;
12863
- addErrorMessage2(res, key, errorMessage, refs);
13049
+ function setResponseValueAndErrors2(res, key3, value, errorMessage, refs) {
13050
+ res[key3] = value;
13051
+ addErrorMessage2(res, key3, errorMessage, refs);
12864
13052
  }
12865
13053
 
12866
13054
  // ../../node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js
@@ -13452,11 +13640,11 @@ function parseRecordDef2(def, refs) {
13452
13640
  return {
13453
13641
  type: "object",
13454
13642
  required: def.keyType._def.values,
13455
- properties: def.keyType._def.values.reduce((acc, key) => ({
13643
+ properties: def.keyType._def.values.reduce((acc, key3) => ({
13456
13644
  ...acc,
13457
- [key]: parseDef2(def.valueType._def, {
13645
+ [key3]: parseDef2(def.valueType._def, {
13458
13646
  ...refs,
13459
- currentPath: [...refs.currentPath, "properties", key]
13647
+ currentPath: [...refs.currentPath, "properties", key3]
13460
13648
  }) ?? parseAnyDef2(refs)
13461
13649
  }), {}),
13462
13650
  additionalProperties: refs.rejectedAdditionalProperties
@@ -13523,10 +13711,10 @@ function parseMapDef2(def, refs) {
13523
13711
  // ../../node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/nativeEnum.js
13524
13712
  function parseNativeEnumDef2(def) {
13525
13713
  const object = def.values;
13526
- const actualKeys = Object.keys(def.values).filter((key) => {
13527
- return typeof object[object[key]] !== "number";
13714
+ const actualKeys = Object.keys(def.values).filter((key3) => {
13715
+ return typeof object[object[key3]] !== "number";
13528
13716
  });
13529
- const actualValues = actualKeys.map((key) => object[key]);
13717
+ const actualValues = actualKeys.map((key3) => object[key3]);
13530
13718
  const parsedTypes = Array.from(new Set(actualValues.map((values) => typeof values)));
13531
13719
  return {
13532
13720
  type: parsedTypes.length === 1 ? parsedTypes[0] === "string" ? "string" : "number" : ["string", "number"],
@@ -14127,32 +14315,31 @@ function mcpInputSchema2(s) {
14127
14315
  }
14128
14316
  var AskInputSchema2 = external_exports.object({
14129
14317
  id: external_exports.string().optional().describe("Optional idempotency key or client-side ID for this specific ask."),
14130
- parentId: external_exports.string().uuid().optional().describe("The Goal this question is about \u2014 usually the one you are working on. The question goes onto that Goal and its answer comes back there. Omit it and Paigy places the question in the tree itself."),
14318
+ parentId: external_exports.string().uuid().optional().describe("The Goal this question is about \u2014 usually the one you are working on. The question goes onto that Goal and its answer comes back there. Omit it and the question starts a new Goal of yours."),
14131
14319
  repo: external_exports.string().optional().describe("Optional repository context."),
14132
14320
  ask: external_exports.string().trim().min(1).max(1e4).describe(
14133
- "ONE question, and only what is needed to answer it. Several questions are several asks in the array, one each: an answer settles the one ask it was given in the shape that ask declares, so a person who answers the part of a bundled ask that interested them settles nothing and is asked again. Paigy reads every ask once and takes a bundled one apart into its own cards anyway \u2014 each question a Question on the one Goal the ask lands on, never a Goal of its own \u2014 but the words it splits are its reading, not yours. News, progress and findings are their own contact; ANY contact for a person already on a call JOINS that call, whatever channel you asked for, so several arrive as one call."
14321
+ "ONE question, and only what is needed to answer it. Several questions are several asks in the array, one each: an answer settles the one ask it was given in the shape that ask declares, so a person who answers the part of a bundled ask that interested them settles nothing and is asked again. Paigy sends each ask exactly as you wrote it: a bundled ask arrives as one card. News, progress and findings are their own contact; ANY contact for a person already on a call JOINS that call, whatever channel you asked for, so several arrive as one call."
14134
14322
  ),
14135
14323
  options: external_exports.array(OptionInputSchema2).min(1).max(6).optional(),
14136
- // YOUR VIEW OF ONE OR MANY, A HINT TO PAIGY'S READ (owner, 2026-10-02: "one and many makes sense...
14137
- // make sure the brain that formats is aware of how it should work"). Three independent fixes went
14138
- // out as "All three / 1 and 3 only / Just log it" because every card was pick-one. #2943 made this
14139
- // field override the read; no agent sent it, so nothing changed. The read now decides each card's
14140
- // shape (`goal/intake.ts` `answerOf`), and this reaches it as the agent's view, weighed, not obeyed.
14324
+ // HOW THE OPTIONS ARE ANSWERED, SAID BY THE AGENT (owner, 2026-10-02: "one and many makes sense";
14325
+ // brain_prompts.md §1: structured agent questions need no model). Every card was pick-one while no
14326
+ // agent sent this; no read reshapes cards any more, so this is the card's shape, and the
14327
+ // description says so plainly.
14141
14328
  select: external_exports.enum(["one", "many"]).optional().describe(
14142
- `Your view of how the options are answered: "one" to pick one, "many" to tick any number of them. A hint: Paigy's read decides each card's shape, a checklist when the options can all be wanted at once, a pick when choosing one rules out the others. The person can always answer in their own words as well. Ignored without options.`
14329
+ 'How the options are answered: "many" makes a checklist (they may want several, e.g. independent fixes), "one" (the default) a pick (choosing one rules out the others). Send "many" whenever more than one option could be wanted at once. The person can always answer in their own words as well. Ignored without options.'
14143
14330
  ),
14144
14331
  answers: external_exports.string().trim().regex(/^[0-9a-fA-F-]{8,36}$/).optional().describe(
14145
14332
  "Your reply answers a question the person asked you: the id the conversation shows for it (8 characters or whole). Their question closes with this reply as its answer, and any decision of yours it was holding back goes back to them. Needs parentId: the Goal the question is on. The reply is sent to them as it is; to also ask something new, send that as its own ask."
14146
14333
  )
14147
14334
  }).strict();
14148
14335
  var StartContactSchema2 = external_exports.object({
14149
- asks: external_exports.array(AskInputSchema2).min(1).describe("The questions to pose, one per object. An ask with a parentId is filed on that Goal as it is; only an ask naming no Goal is placed in the tree by Paigy."),
14336
+ asks: external_exports.array(AskInputSchema2).min(1).describe("The questions to pose, one per object. An ask with a parentId is filed on that Goal as it is; an ask naming no Goal starts a new Goal of yours."),
14150
14337
  waiting: external_exports.enum(["none", "hard"]).default("none").describe("hard requests a call even when channel is notification; user permissions and ring cooldowns still apply."),
14151
14338
  channel: external_exports.enum(["notification", "call"]).default("notification")
14152
14339
  }).strict();
14153
14340
  var ContactSchema2 = external_exports.union([StartContactSchema2, external_exports.object({ deliveryId: external_exports.string().uuid() }).strict()]);
14154
14341
  var CONTACT_SCHEMA2 = { type: "object", ...mcpInputSchema2(ContactSchema2) };
14155
- var CONTACT_DESCRIPTION2 = "Contact the user with one or more asks/questions. Pass an array of asks (each with 'ask', optional 'options', 'select', 'id', 'parentId', 'repo'), plus channel:'notification'|'call', and waiting:'none'|'hard'. An ask that names a Goal (parentId) goes onto that Goal; one that names none is placed in the person's tree by Paigy. Notification returns immediately; collect durable answers with check_replies. On stdio, a Call holds one cancellable ~45s window; continue with ONLY {deliveryId}. One question per 'ask'; several questions are several objects in 'asks'. A bundled ask is taken apart into its own cards by Paigy's one intake read, every one on the Goal the ask lands on; separate pieces of work are separate asks. An ask with no options that is not blocking is a report, and a report is an UPDATE, never a claim on them: it reaches them and is listed apart from what waits on them, so no answer is owed and none should be awaited. On a Goal whose report card is still open it is added to that card, with no new push; one that only says where your work stands while under way is recorded as the Goal's progress, not sent (the result says so). Send options (or waiting:'hard') when you actually need an answer. Each option's label must stand on its own \u2014 the person may see only the labels \u2014 so never a label that points into your text ('All three', 'Option 2', '1 and 3 only'). Whether a card is a checklist or a pick is decided by Paigy's read: independent options they may want several of become a checklist, alternatives a pick. select:'many' or select:'one' tells it your view, a hint it weighs. The person can always answer in their own words, so never add an 'Other' option. If the person is already on a call, your contact joins that call automatically \u2014 whatever channel you asked for, with no ring \u2014 and the Delivery it returns IS that call: reread it with contact({deliveryId}) to see everything answered on it so far, and contact again while it is live to add information or a further question to the same call.";
14342
+ var CONTACT_DESCRIPTION2 = "Contact the user with one or more asks/questions. Pass an array of asks (each with 'ask', optional 'options', 'select', 'id', 'parentId', 'repo'), plus channel:'notification'|'call', and waiting:'none'|'hard'. An ask that names a Goal (parentId) goes onto that Goal; one that names none starts a new Goal of yours. Notification returns immediately; collect durable answers with check_replies. On stdio, a Call holds one cancellable ~45s window; continue with ONLY {deliveryId}. One question per 'ask'; several questions are several objects in 'asks'. Each ask is sent exactly as written, with no reading in between: a bundled ask arrives as one card, so separate questions are separate asks. An ask with no options that is not blocking is a report, and a report is an UPDATE, never a claim on them: it reaches them and is listed apart from what waits on them, so no answer is owed and none should be awaited. On a Goal whose report card is still open it is added to that card, with no new push; Where your work stands while under way is progress: report it with update_goal, not contact. Send options (or waiting:'hard') when you actually need an answer. Each option's label must stand on its own \u2014 the person may see only the labels \u2014 so never a label that points into your text ('All three', 'Option 2', '1 and 3 only'). select:'many' makes the card a checklist, for independent options they may want several of; select:'one' (the default) a pick, for alternatives. The person can always answer in their own words, so never add an 'Other' option. If the person is already on a call, your contact joins that call automatically \u2014 whatever channel you asked for, with no ring \u2014 and the Delivery it returns IS that call: reread it with contact({deliveryId}) to see everything answered on it so far, and contact again while it is live to add information or a further question to the same call.";
14156
14343
  var CreateGoalSchema2 = external_exports.object({
14157
14344
  outcome: external_exports.string().trim().min(1).max(1e4),
14158
14345
  /** The work's NAME (#2115) — one to five words, how a person refers to it out loud ("the night
@@ -14226,6 +14413,156 @@ var AGENT_TOOLS2 = [
14226
14413
  { name: "update_goal", description: UPDATE_GOAL_DESCRIPTION2, inputSchema: mcpInputSchema2(UpdateGoalToolSchema2) }
14227
14414
  ];
14228
14415
  var AGENT_TOOL_NAMES2 = AGENT_TOOLS2.map((t) => t.name);
14416
+ var id2 = external_exports.string().uuid();
14417
+ var key2 = external_exports.string().min(1).max(40);
14418
+ var participant2 = external_exports.string().regex(/^(human|agent):.+$/, "a participant ID such as agent:<uuid>");
14419
+ var SourceSchema2 = external_exports.object({
14420
+ entryId: id2,
14421
+ span: external_exports.object({ start: external_exports.number().int().min(0), end: external_exports.number().int().min(1) }).strict().refine((s) => s.end > s.start, "a span ends after it starts").optional()
14422
+ }).strict();
14423
+ var ResultRefSchema2 = external_exports.union([external_exports.object({ id: id2 }).strict(), external_exports.object({ local: key2 }).strict()]);
14424
+ var NodeRefSchema2 = external_exports.object({ type: external_exports.enum(["goal", "question"]), id: id2 }).strict();
14425
+ var DependencySchema2 = external_exports.object({
14426
+ blocker: NodeRefSchema2,
14427
+ blocked: NodeRefSchema2,
14428
+ action: external_exports.enum(["start", "complete", "answer"]),
14429
+ reason: external_exports.string().max(500).optional()
14430
+ }).strict();
14431
+ var goalState2 = external_exports.enum(["open", "completed", "canceled"]);
14432
+ var existingGoalChanges2 = [
14433
+ external_exports.object({ kind: external_exports.literal("edit"), goalId: id2, title: external_exports.string().min(1).max(120).optional(), outcome: external_exports.string().min(1).optional() }).strict().refine((c) => c.title !== void 0 || c.outcome !== void 0, "an edit changes the title or the outcome"),
14434
+ external_exports.object({ kind: external_exports.literal("state"), goalId: id2, state: goalState2 }).strict(),
14435
+ external_exports.object({ kind: external_exports.literal("assign"), goalId: id2, ownerId: participant2 }).strict(),
14436
+ external_exports.object({ kind: external_exports.literal("defer"), goalId: id2, until: external_exports.string().datetime().nullable() }).strict(),
14437
+ external_exports.object({ kind: external_exports.literal("move"), goalId: id2, parentGoalId: id2.nullable() }).strict(),
14438
+ external_exports.object({
14439
+ kind: external_exports.literal("dependency"),
14440
+ change: external_exports.enum(["add", "remove"]),
14441
+ goalId: id2,
14442
+ dependsOnGoalId: id2,
14443
+ action: external_exports.enum(["start", "complete"]),
14444
+ reason: external_exports.string().max(500).optional()
14445
+ }).strict()
14446
+ ];
14447
+ var GoalChangeSchema2 = external_exports.union([
14448
+ external_exports.object({
14449
+ kind: external_exports.literal("create"),
14450
+ title: external_exports.string().min(1).max(120),
14451
+ outcome: external_exports.string().min(1),
14452
+ ownerId: participant2,
14453
+ parentGoalId: id2.optional(),
14454
+ sourceEntryIds: external_exports.array(id2)
14455
+ }).strict(),
14456
+ ...existingGoalChanges2
14457
+ ]);
14458
+ var BrainGoalChangeSchema2 = external_exports.union([
14459
+ // newSession: Paigy starts a session to own it (owner, 2026-10-06); until it has, the person owns it.
14460
+ external_exports.object({
14461
+ kind: external_exports.literal("create"),
14462
+ outcome: external_exports.string().min(1),
14463
+ title: external_exports.string().min(1).max(120),
14464
+ ownerId: participant2,
14465
+ parentGoal: ResultRefSchema2.nullable(),
14466
+ newSession: external_exports.literal(true).optional()
14467
+ }).strict(),
14468
+ ...existingGoalChanges2
14469
+ ]);
14470
+ var option2 = external_exports.object({ id: external_exports.string().min(1).max(40), label: external_exports.string().min(1), hint: external_exports.string().optional() }).strict();
14471
+ var QuestionChangeSchema2 = external_exports.union([
14472
+ external_exports.object({
14473
+ kind: external_exports.literal("create"),
14474
+ text: external_exports.string().min(1),
14475
+ answererId: participant2,
14476
+ goal: ResultRefSchema2.optional(),
14477
+ blocks: external_exports.array(external_exports.object({ question: ResultRefSchema2 }).strict()),
14478
+ options: external_exports.array(option2).min(2).optional(),
14479
+ pickMode: external_exports.enum(["one", "many", "rank"]).optional()
14480
+ }).strict().refine((c) => c.options === void 0 === (c.pickMode === void 0), "options and pickMode come together"),
14481
+ external_exports.object({ kind: external_exports.literal("edit"), questionId: id2, text: external_exports.string().min(1) }).strict(),
14482
+ external_exports.object({ kind: external_exports.literal("assign"), questionId: id2, answererId: participant2 }).strict(),
14483
+ external_exports.object({ kind: external_exports.literal("withdraw"), questionId: id2 }).strict(),
14484
+ external_exports.object({ kind: external_exports.literal("dependency"), change: external_exports.enum(["add", "remove"]), edge: DependencySchema2 }).strict()
14485
+ ]);
14486
+ var lessonScope2 = external_exports.union([
14487
+ external_exports.object({ kind: external_exports.literal("user") }).strict(),
14488
+ external_exports.object({ kind: external_exports.literal("goal"), goal: ResultRefSchema2 }).strict()
14489
+ ]);
14490
+ var LessonChangeSchema2 = external_exports.union([
14491
+ external_exports.object({ kind: external_exports.literal("remember"), text: external_exports.string().min(1), scope: lessonScope2 }).strict(),
14492
+ external_exports.object({ kind: external_exports.literal("revise"), lessonId: id2, text: external_exports.string().min(1), scope: lessonScope2 }).strict(),
14493
+ external_exports.object({ kind: external_exports.literal("withdraw"), lessonId: id2 }).strict()
14494
+ ]);
14495
+ var BrainNextSchema2 = external_exports.object({
14496
+ instructions: external_exports.array(external_exports.object({ entryKeys: external_exports.array(key2).min(1) }).strict()),
14497
+ say: external_exports.array(key2),
14498
+ then: external_exports.enum(["listen", "hold", "end", "none"]),
14499
+ waitFor: external_exports.array(ResultRefSchema2),
14500
+ reason: external_exports.string()
14501
+ }).strict();
14502
+ var messageBase2 = {
14503
+ key: key2,
14504
+ text: external_exports.string().min(1),
14505
+ goals: external_exports.array(ResultRefSchema2),
14506
+ questions: external_exports.array(ResultRefSchema2),
14507
+ entryKeys: external_exports.array(key2),
14508
+ obligationIds: external_exports.array(id2)
14509
+ };
14510
+ var BrainMessageSchema2 = external_exports.union([
14511
+ external_exports.object({ ...messageBase2, to: external_exports.object({ kind: external_exports.literal("user") }).strict() }).strict(),
14512
+ external_exports.object({
14513
+ ...messageBase2,
14514
+ to: external_exports.object({ kind: external_exports.literal("session"), sessionId: id2 }).strict(),
14515
+ call: external_exports.object({ callId: id2, listen: external_exports.literal(true) }).strict().optional()
14516
+ }).strict()
14517
+ ]);
14518
+ var BrainSearchSchema2 = external_exports.object({
14519
+ query: external_exports.string().min(1).max(500),
14520
+ within: external_exports.array(external_exports.enum(["entries", "goals", "answers"])).min(1),
14521
+ goalId: id2.optional()
14522
+ }).strict();
14523
+ var BrainResultSchema2 = external_exports.object({
14524
+ messages: external_exports.array(BrainMessageSchema2),
14525
+ entries: external_exports.array(external_exports.object({ key: key2, sources: external_exports.array(SourceSchema2).min(1), goals: external_exports.array(ResultRefSchema2) }).strict()),
14526
+ questions: external_exports.array(external_exports.object({ key: key2, entryKeys: external_exports.array(key2), change: QuestionChangeSchema2 }).strict()),
14527
+ answers: external_exports.array(external_exports.object({
14528
+ question: ResultRefSchema2,
14529
+ entryKeys: external_exports.array(key2).min(1),
14530
+ summary: external_exports.string().min(1),
14531
+ selectedOptionIds: external_exports.array(external_exports.string().min(1)).optional()
14532
+ }).strict()),
14533
+ goals: external_exports.array(external_exports.object({ key: key2, entryKeys: external_exports.array(key2), change: BrainGoalChangeSchema2 }).strict()),
14534
+ feedback: external_exports.array(external_exports.object({ entryKeys: external_exports.array(key2).min(1) }).strict()),
14535
+ lessons: external_exports.array(external_exports.object({ entryKeys: external_exports.array(key2).min(1), change: LessonChangeSchema2 }).strict()),
14536
+ next: BrainNextSchema2,
14537
+ search: BrainSearchSchema2.optional()
14538
+ }).strict();
14539
+ var str2 = external_exports.string();
14540
+ var strs2 = external_exports.array(external_exports.string());
14541
+ var CompactResultSchema2 = external_exports.object({
14542
+ next: external_exports.object({ say: strs2, then: external_exports.enum(["listen", "hold", "end", "none"]), waitFor: strs2, reason: str2, instructions: strs2 }).strict(),
14543
+ messages: external_exports.array(external_exports.object({ key: str2, to: str2, text: str2, about: strs2, entries: strs2, owed: strs2, inviteToCall: external_exports.boolean() }).strict()),
14544
+ entries: external_exports.array(external_exports.object({ key: str2, from: str2, start: external_exports.number().int(), end: external_exports.number().int(), on: strs2 }).strict()),
14545
+ answers: external_exports.array(external_exports.object({ question: str2, entries: strs2, summary: str2, picked: strs2 }).strict()),
14546
+ changes: external_exports.array(external_exports.object({
14547
+ key: str2,
14548
+ what: external_exports.enum(["goal", "question", "lesson"]),
14549
+ op: external_exports.enum(["create", "edit", "assign", "open", "complete", "cancel", "defer", "move", "block", "unblock", "withdraw", "remember", "revise"]),
14550
+ id: str2,
14551
+ text: str2,
14552
+ title: str2,
14553
+ who: str2,
14554
+ under: str2,
14555
+ gate: external_exports.enum(["start", "complete", "answer", "none"]),
14556
+ options: external_exports.array(external_exports.object({ id: str2, label: str2 }).strict()),
14557
+ pick: external_exports.enum(["one", "many", "rank", "words"]),
14558
+ entries: strs2
14559
+ }).strict()),
14560
+ feedback: external_exports.array(strs2),
14561
+ search: external_exports.object({ query: str2, within: strs2, goal: str2 }).strict()
14562
+ }).strict();
14563
+ var COMPACT_RESULT_JSON_SCHEMA2 = (({ $schema: _, ...rest }) => rest)(
14564
+ zodToJsonSchema2(CompactResultSchema2, { $refStrategy: "none" })
14565
+ );
14229
14566
  function entryWords(entry) {
14230
14567
  const content = entry.content;
14231
14568
  if (content && "sealed" in content) return "";
@@ -14238,6 +14575,8 @@ function entryWords(entry) {
14238
14575
  const description = plain.description;
14239
14576
  const parts = [title, ...Array.isArray(description) ? description : []].filter((v) => typeof v === "string");
14240
14577
  if (parts.length) return parts.join("\n\n");
14578
+ const line = plain.line;
14579
+ if (typeof line === "string" && line.trim()) return line;
14241
14580
  }
14242
14581
  return entry.sources.map((source) => source.text).join("\n");
14243
14582
  }
@@ -14460,7 +14799,7 @@ var IntentSchema2 = external_exports.object({
14460
14799
  * (`parseDelay`, #1292), and a value here simply wins over that reading. */
14461
14800
  dueInSeconds: external_exports.number().int().positive().optional(),
14462
14801
  /** Feedback only (#812): WHICH failure the complaint names — typed by the mapper that
14463
- * already read the utterance, so `feedback_from_call.kind` stops defaulting to
14802
+ * already read the utterance, so `signals.kind` stops defaulting to
14464
14803
  * 'other' on every row. A table that records that something was wrong and nothing
14465
14804
  * about what cannot answer "is the bot looping less this week?". */
14466
14805
  fault: external_exports.enum(["loop", "unanswered", "overridden", "misheard", "slow", "other"]).optional()
@@ -14744,7 +15083,18 @@ var InboxItemSchema2 = external_exports.object({
14744
15083
  /** THAT GOAL'S NAME (#2416) — what Activity's row is headed by, since a row there is one Goal
14745
15084
  * and the cards it holds sit behind it. Stamped by the same read as `goalState`. */
14746
15085
  goalTitle: external_exports.string().optional()
14747
- }).optional()
15086
+ }).optional(),
15087
+ /** WHAT THIS CARD IS, IN TWELVE CHARACTERS (#3019) — the hash of every other field on it, stamped
15088
+ * by the one read that serves the open list (`apps/api/src/inbox/project.ts` `inboxFor`). It is
15089
+ * how the incremental read knows a card has not moved: the phone echoes back the revs it holds
15090
+ * (`POST /api/inbox/changes`) and is sent only the cards whose rev differs.
15091
+ *
15092
+ * THE PAYLOAD'S OWN HASH, NEVER A STAMP ON THE WORK — the same mechanism as `QueueItem.rev`
15093
+ * (#2928) and an entry's (#3018), for the same reason: a card shows facts no `updated_at` of its
15094
+ * own moves (its Goal's state and name, how cold the work behind it has gone, whether a ring is
15095
+ * live). Optional, so a fixture, the demo and the archive lens need not spell one, and a card
15096
+ * with no rev is simply always re-sent. */
15097
+ rev: external_exports.string().optional()
14748
15098
  });
14749
15099
  var APNS_TOKEN_RE2 = /^[0-9a-fA-F]{64}$/;
14750
15100
  var PushTokenSchema2 = external_exports.object({
@@ -15116,7 +15466,22 @@ var QueueItemSchema2 = external_exports.object({
15116
15466
  * minute after the person speaks erases their instant from it, and the durable traces the client
15117
15467
  * can see (`replies`, `questions[].answeredAt`) miss a spontaneous note entirely — a `request`
15118
15468
  * Entry with no `about_id` is in neither. */
15119
- lastPersonAt: external_exports.string().nullable().optional()
15469
+ lastPersonAt: external_exports.string().nullable().optional(),
15470
+ /** WHAT THIS ROW IS, IN TWELVE CHARACTERS (#2928) — the hash of every other field on it, stamped
15471
+ * by the one projection that builds the row (`apps/api/src/goal/queue.ts`). It is how the
15472
+ * incremental read knows a row has not moved: the phone echoes back the revs it holds
15473
+ * (`POST /api/goals/changes`) and is sent only the rows whose rev differs.
15474
+ *
15475
+ * IT IS THE PAYLOAD'S OWN HASH, NEVER A STAMP ON THE WORK. Nothing here reasons about which
15476
+ * writes change which field — the comparison is over the bytes the phone is holding, so a fact
15477
+ * the row shows that no `updated_at` moves for (a lease lapsing, a dependency's state, a
15478
+ * sibling appearing in `childGoalIds`) cannot go unnoticed. Optional because a hand-built
15479
+ * queue (a fixture, the demo) spells none, and a row with no rev is simply always re-sent. */
15480
+ rev: external_exports.string().optional()
15481
+ });
15482
+ var QueueDeltaSchema2 = external_exports.object({
15483
+ ids: external_exports.array(external_exports.string()),
15484
+ items: external_exports.array(QueueItemSchema2)
15120
15485
  });
15121
15486
  var COLD_AFTER_MS2 = 3 * 24 * 60 * 60 * 1e3;
15122
15487
  var NoteSourceSchema2 = external_exports.enum(["app", "call"]);
@@ -15287,6 +15652,11 @@ var DeviceTokenSchema2 = external_exports.object({
15287
15652
  /** Local host recovery must preserve the launch's runtime and Paigy identity. */
15288
15653
  harness: external_exports.enum(["claude", "codex", "agy"]).optional(),
15289
15654
  session_id: external_exports.string().uuid().optional(),
15655
+ /** A conversation the host must not resume: its context is full, so every turn fails
15656
+ * ("Prompt is too long"). Written when a run hits it (`run.ts` `onFull`); the host skips a slot
15657
+ * whose resumable session is this one, so its Goals reach the dead-agent handoff instead of a
15658
+ * copy that types the person's words into a turn that cannot run (Calls, 2026-10-06). */
15659
+ full_session: external_exports.string().optional(),
15290
15660
  uik_pub: external_exports.string().nullable().optional()
15291
15661
  });
15292
15662
  var SupportRequestSchema2 = external_exports.object({
@@ -15532,10 +15902,10 @@ var AcpDriver = class {
15532
15902
  return this.flush();
15533
15903
  }
15534
15904
  /** Answer a PermissionEvent (ask mode). The id is the request's JSON-RPC id as a string. */
15535
- respond(id, decision) {
15536
- const request = this.pending.get(id);
15905
+ respond(id3, decision) {
15906
+ const request = this.pending.get(id3);
15537
15907
  if (!request) return [];
15538
- this.pending.delete(id);
15908
+ this.pending.delete(id3);
15539
15909
  const optionId = optionFor(request.options, decision);
15540
15910
  return [
15541
15911
  optionId ? frame2({ id: request.id, result: { outcome: { outcome: "selected", optionId } } }) : frame2({ id: request.id, result: { outcome: { outcome: "cancelled" } } })
@@ -15689,7 +16059,7 @@ var AcpDriver = class {
15689
16059
  writes: [frame2({ id: msg.id, error: { code: -32601, message: `Method not found: ${msg.method}` } })]
15690
16060
  };
15691
16061
  }
15692
- const id = msg.id;
16062
+ const id3 = msg.id;
15693
16063
  const options = msg.params?.options ?? [];
15694
16064
  const title = msg.params?.toolCall?.title?.trim() || "a tool call";
15695
16065
  const tool = msg.params?.toolCall?.kind ?? "tool";
@@ -15700,21 +16070,21 @@ var AcpDriver = class {
15700
16070
  // means "don't stall the agent", never "don't tell the user".
15701
16071
  events: [{ kind: "turn", role: "agent", text: `auto-approved: ${title}`, tools: [tool] }],
15702
16072
  writes: [
15703
- optionId ? frame2({ id, result: { outcome: { outcome: "selected", optionId } } }) : frame2({ id, result: { outcome: { outcome: "cancelled" } } })
16073
+ optionId ? frame2({ id: id3, result: { outcome: { outcome: "selected", optionId } } }) : frame2({ id: id3, result: { outcome: { outcome: "cancelled" } } })
15704
16074
  ]
15705
16075
  };
15706
16076
  }
15707
- this.pending.set(String(id), { id, options });
16077
+ this.pending.set(String(id3), { id: id3, options });
15708
16078
  return {
15709
- events: [{ kind: "permission", id: String(id), tool, summary: title }],
16079
+ events: [{ kind: "permission", id: String(id3), tool, summary: title }],
15710
16080
  writes: []
15711
16081
  };
15712
16082
  }
15713
16083
  /** The frame that opens the conversation: a resume of `resume` while there is one to try,
15714
16084
  * else a new session. */
15715
- opening(id) {
16085
+ opening(id3) {
15716
16086
  const params = { cwd: this.cwd, mcpServers: [], ...this.meta ? { _meta: this.meta } : {} };
15717
- return this.resume ? { id, method: "session/resume", params: { sessionId: this.resume, ...params } } : { id, method: "session/new", params };
16087
+ return this.resume ? { id: id3, method: "session/resume", params: { sessionId: this.resume, ...params } } : { id: id3, method: "session/new", params };
15718
16088
  }
15719
16089
  /** Send the queued prompts as one turn, if the agent can take one right now. */
15720
16090
  flush() {
@@ -15832,7 +16202,7 @@ function startSession(opts) {
15832
16202
  }
15833
16203
  const codexConfig = opts.harness === "codex" ? JSON.parse(process.env.CODEX_CONFIG || "{}") : null;
15834
16204
  if (codexConfig) {
15835
- const key = "mcp_servers.paigy.env_vars";
16205
+ const key3 = "mcp_servers.paigy.env_vars";
15836
16206
  const configPath = join9(process.env.CODEX_HOME || join9(homedir9(), ".codex"), "config.toml");
15837
16207
  const saved = existsSync4(configPath) ? readFileSync5(configPath, "utf8") : "";
15838
16208
  const registered = /\[mcp_servers\.paigy\][\s\S]*?(?=\n\[|$)/.exec(saved)?.[0];
@@ -15843,7 +16213,7 @@ function startSession(opts) {
15843
16213
  }
15844
16214
  const savedVars = registered?.match(/env_vars\s*=\s*\[([\s\S]*?)\]/)?.[1] ?? "";
15845
16215
  const inherited = [...savedVars.matchAll(/["']([A-Za-z_][A-Za-z0-9_]*)["']/g)].map((match) => match[1]);
15846
- codexConfig[key] = [.../* @__PURE__ */ new Set([...inherited, ...codexConfig[key] ?? codexConfig.mcp_servers?.paigy?.env_vars ?? [], ...CODEX_ENV])];
16216
+ codexConfig[key3] = [.../* @__PURE__ */ new Set([...inherited, ...codexConfig[key3] ?? codexConfig.mcp_servers?.paigy?.env_vars ?? [], ...CODEX_ENV])];
15847
16217
  }
15848
16218
  const child = (opts.spawnFn ?? spawn)(opts.bin ?? ADAPTER_BIN[opts.harness], [], {
15849
16219
  cwd,
@@ -15919,8 +16289,8 @@ function startSession(opts) {
15919
16289
  send(text) {
15920
16290
  write(driver.send(text));
15921
16291
  },
15922
- respond(id, decision) {
15923
- write(driver.respond(id, decision));
16292
+ respond(id3, decision) {
16293
+ write(driver.respond(id3, decision));
15924
16294
  },
15925
16295
  stop() {
15926
16296
  write(driver.close());
@@ -16140,17 +16510,31 @@ async function finish(result, state, rail, opts) {
16140
16510
  }
16141
16511
  async function cannotWork(report, state, rail, opts) {
16142
16512
  state.resting = true;
16513
+ const say = (parentId) => rail.contact({ asks: [{ ask: report, ...parentId ? { parentId } : {} }], waiting: "none", channel: "notification" });
16143
16514
  try {
16144
16515
  if (!state.goal) {
16145
- const claimed = await rail.claim();
16146
- if (!claimed.goalId || claimed.revision === void 0) return;
16147
- state.goal = { id: claimed.goalId, revision: claimed.revision };
16516
+ const claimed = await rail.claim().catch(() => void 0);
16517
+ if (claimed?.goalId && claimed.revision !== void 0) state.goal = { id: claimed.goalId, revision: claimed.revision };
16518
+ }
16519
+ if (!state.goal) {
16520
+ await say();
16521
+ return;
16522
+ }
16523
+ try {
16524
+ await say(state.goal.id);
16525
+ } catch (error) {
16526
+ if (!/goal_parent_invalid/.test(error.message)) throw error;
16527
+ opts?.log?.(`\u26A0 the held Goal ${state.goal.id.slice(0, 8)} refused the notice (goal_parent_invalid) \u2014 saying it unplaced`);
16528
+ await say();
16148
16529
  }
16149
- await rail.contact({ asks: [{ ask: report, parentId: state.goal.id }], waiting: "none", channel: "notification" });
16150
16530
  } catch (error) {
16151
16531
  opts?.log?.(`\u26A0 could not say the agent cannot work: ${error.message}`);
16152
16532
  }
16153
16533
  }
16534
+ function conversationFull(result) {
16535
+ return /prompt is too long/i.test(result ?? "");
16536
+ }
16537
+ var FULL_NOTICE = "This agent's conversation is full, so it can no longer take a turn. Its session has ended and will not be resumed; its Goals go to the dead-agent handoff.";
16154
16538
  async function afterTurn(event, state, rail, opts) {
16155
16539
  if (event.failed) {
16156
16540
  const limit = limitIn(event.result, (opts?.now ?? Date.now)());
@@ -16163,6 +16547,11 @@ async function afterTurn(event, state, rail, opts) {
16163
16547
  opts?.log?.(`\u23F8 paused by the usage limit until ${limit.resets}: nothing is typed in until then, and it carries on by itself`);
16164
16548
  return limit;
16165
16549
  }
16550
+ if (conversationFull(event.result)) {
16551
+ if (!state.full) await cannotWork(FULL_NOTICE, state, rail, opts);
16552
+ state.full = true;
16553
+ return void 0;
16554
+ }
16166
16555
  await cannotWork(`The agent stopped without finishing.
16167
16556
 
16168
16557
  ${event.result?.trim() || "No result reported."}`, state, rail, opts);
@@ -16232,9 +16621,9 @@ function unheard(brief, state, since = null, after = -1, reviewSince) {
16232
16621
  if (text) words2.push(text);
16233
16622
  }
16234
16623
  if (pendingAt !== null) for (const answer of brief.answers ?? []) {
16235
- const key = `answer:${answer.decisionNeedId}`;
16236
- if (seen.has(key) || Date.parse(answer.acceptedAt) < pendingAt) continue;
16237
- seen.add(key);
16624
+ const key3 = `answer:${answer.decisionNeedId}`;
16625
+ if (seen.has(key3) || Date.parse(answer.acceptedAt) < pendingAt) continue;
16626
+ seen.add(key3);
16238
16627
  words2.push(`Answer to question ${answer.decisionNeedId}: ${JSON.stringify(answer.result)}`);
16239
16628
  }
16240
16629
  return words2;
@@ -16279,16 +16668,16 @@ async function gather(state, rail, held) {
16279
16668
  const listed = /* @__PURE__ */ new Set();
16280
16669
  const announced = state.announced ??= /* @__PURE__ */ new Set();
16281
16670
  if (waiting) {
16282
- for (const id of announced) if (!(waiting.assigned ?? []).some((g) => g.goalId === id)) announced.delete(id);
16671
+ for (const id3 of announced) if (!(waiting.assigned ?? []).some((g) => g.goalId === id3)) announced.delete(id3);
16283
16672
  }
16284
16673
  for (const g of waiting?.assigned ?? []) if (g.goalId !== state.goal.id && !announced.has(g.goalId)) look2(g.goalId, "assigned", g.title);
16285
16674
  for (const g of waiting?.review ?? []) {
16286
16675
  listed.add(g.goalId);
16287
16676
  look2(g.goalId, "waiting work", g.title);
16288
16677
  }
16289
- for (const d of waiting?.deliveries ?? []) for (const id of d.goalIds) {
16290
- listed.add(id);
16291
- look2(id, "waiting work");
16678
+ for (const d of waiting?.deliveries ?? []) for (const id3 of d.goalIds) {
16679
+ listed.add(id3);
16680
+ look2(id3, "waiting work");
16292
16681
  }
16293
16682
  const moved = movedBelow(held, state);
16294
16683
  for (const { goal, since } of moved) look2(goal.goalId, "subtree", goal.title, since);
@@ -16326,7 +16715,7 @@ var block = (h) => [
16326
16715
  ...h.note ? [`The last note on it, from the agent before you: ${h.note}`] : [],
16327
16716
  ...h.words
16328
16717
  ].join("\n\n");
16329
- var short = (ids) => ids.map((id) => id.slice(0, 8)).join(", ");
16718
+ var short = (ids) => ids.map((id3) => id3.slice(0, 8)).join(", ");
16330
16719
  var given = (heard) => heard.filter((h) => h.via === "assigned").map((h) => h.goalId);
16331
16720
  async function hear(session, state, rail, held, opts) {
16332
16721
  const log2 = opts?.log;
@@ -16590,7 +16979,12 @@ ${event.message}`, state, rail, { log: opts.log });
16590
16979
  tail = [];
16591
16980
  const carried = state.carriedOn && !event.failed;
16592
16981
  if (await afterTurn(event, state, rail, { log: opts.log })) LIMITS.paused(name, Date.now());
16593
- else if (carried) runningAgain();
16982
+ else if (state.full) {
16983
+ opts.log(`\u25A0 ${name}'s conversation is full \u2014 ending this run; it will not be resumed`);
16984
+ opts.onFull?.(speaksAs);
16985
+ stop2();
16986
+ return;
16987
+ } else if (carried) runningAgain();
16594
16988
  clock4.nudge("rest");
16595
16989
  }
16596
16990
  }
@@ -16751,26 +17145,33 @@ var claimedRun = (sessionId2) => {
16751
17145
  return { slot, key: runKey(slot) };
16752
17146
  };
16753
17147
  var launchRun = (spec) => ({ session: spec.sessionId });
17148
+ var BOUND_ELSEWHERE_MS = 10 * 6e4;
17149
+ var boundElsewhere = /* @__PURE__ */ new Map();
17150
+ var BOUND_SKIP = "is bound to the session it was paired in, which this host cannot name \u2014 run `paigy-harness handoff` as it, in its folder, to record it";
16754
17151
  var NOTHING_WAITING = "has nothing waiting";
16755
17152
  async function waitingWork(token, session) {
17153
+ const quiet = boundElsewhere.get(token);
17154
+ if (quiet !== void 0 && Date.now() < quiet) return { skip: BOUND_SKIP };
16756
17155
  let found;
16757
17156
  try {
16758
17157
  found = await checkReplies({ token, ...session ? { reach: reachAs(session) } : {} });
16759
17158
  } catch (error) {
16760
17159
  if (error instanceof RevokedError) return { skip: "was revoked: its credential is gone for good", revoked: true };
16761
17160
  if (error instanceof ApiError && error.body?.error === "identity_session_mismatch") {
16762
- return { skip: "is bound to the session it was paired in, which this host cannot name \u2014 run `paigy-harness handoff` as it, in its folder, to record it" };
17161
+ boundElsewhere.set(token, Date.now() + BOUND_ELSEWHERE_MS);
17162
+ return { skip: BOUND_SKIP };
16763
17163
  }
16764
17164
  return { skip: `could not read what is waiting (${error.message})` };
16765
17165
  }
17166
+ boundElsewhere.delete(token);
16766
17167
  const next = found.claimable;
16767
17168
  const about = next ? { goalId: next.goalId, ...next.since ? { since: next.since } : {} } : {};
16768
17169
  const n = found.deliveries.length;
16769
17170
  if (n) return { waiting: n === 1 ? "a message" : `${n} messages`, ...about };
16770
17171
  return next ? { waiting: `Goal ${next.goalId.slice(0, 8)}${next.title ? ` "${next.title}"` : ""}`, ...about } : { skip: NOTHING_WAITING };
16771
17172
  }
16772
- function evict(runs, key, run) {
16773
- if (runs.get(key)?.run === run) runs.delete(key);
17173
+ function evict(runs, key3, run) {
17174
+ if (runs.get(key3)?.run === run) runs.delete(key3);
16774
17175
  }
16775
17176
  var PRESENCE_FRESH_MS = 3 * 6e4;
16776
17177
  var IDLE_HOLDER_MS = 30 * 6e4;
@@ -16813,9 +17214,9 @@ function startHost(opts) {
16813
17214
  const agent2 = slotIdentity(slot).tokenId;
16814
17215
  if (!agent2) return;
16815
17216
  const goalId = found?.goalId;
16816
- const key = `${decision}:${goalId ?? ""}`;
16817
- if (recorded.get(slot) === key) return;
16818
- recorded.set(slot, key);
17217
+ const key3 = `${decision}:${goalId ?? ""}`;
17218
+ if (recorded.get(slot) === key3) return;
17219
+ recorded.set(slot, key3);
16819
17220
  void recordDecision({
16820
17221
  agent: agent2,
16821
17222
  decision,
@@ -16865,7 +17266,7 @@ function startHost(opts) {
16865
17266
  const specs = await claimSessions(asHost).catch(() => []);
16866
17267
  for (const spec of specs) {
16867
17268
  const label = spec.name ?? spec.harness;
16868
- const { slot, key } = claimedRun(spec.sessionId);
17269
+ const { slot, key: key3 } = claimedRun(spec.sessionId);
16869
17270
  const log2 = (line) => opts.log(`[${label}] ${line}`);
16870
17271
  try {
16871
17272
  saveToken({
@@ -16888,14 +17289,17 @@ function startHost(opts) {
16888
17289
  token: spec.token,
16889
17290
  ...launchRun(spec),
16890
17291
  onExit: () => {
16891
- evict(runs, key, run);
17292
+ evict(runs, key3, run);
16892
17293
  goneAt.set(slot, Date.now());
16893
17294
  opts.log(`\u2716 ${label} ended`);
16894
17295
  },
17296
+ onFull: (session) => {
17297
+ updateSlot(slot, { full_session: session });
17298
+ },
16895
17299
  name: label,
16896
17300
  log: log2
16897
17301
  });
16898
- runs.set(key, { run, label, token: spec.token });
17302
+ runs.set(key3, { run, label, token: spec.token });
16899
17303
  void heartbeat(void 0, { token: spec.token }).catch(() => {
16900
17304
  });
16901
17305
  void refreshIdentities();
@@ -16947,9 +17351,9 @@ function startHost(opts) {
16947
17351
  let lastHolders = /* @__PURE__ */ new Map();
16948
17352
  async function wakeSlot(slot, { presence, holders }, cause = "sweep") {
16949
17353
  {
16950
- const key = runKey(slot);
17354
+ const key3 = runKey(slot);
16951
17355
  if (slot === "Desktop" || isRevoked(slot)) return;
16952
- const live = runs.get(key);
17356
+ const live = runs.get(key3);
16953
17357
  if (live) {
16954
17358
  const theirs = (localHolderPids().get(slot) ?? []).map((p) => p.pid).filter((pid) => !descendsFrom(pid, process.pid));
16955
17359
  if (theirs.length) {
@@ -16984,6 +17388,11 @@ function startHost(opts) {
16984
17388
  }
16985
17389
  const identity = slotIdentity(slot);
16986
17390
  const owner = !identity.harness || identity.harness === "claude" ? ownerSession(slot) : null;
17391
+ const resumes = owner?.sessionId ?? identity.sessionId;
17392
+ if (resumes && identity.fullSession === resumes) {
17393
+ skip(`has a full conversation (${resumes.slice(0, 8)}) \u2014 not resuming it; its Goals go to the dead-agent handoff`);
17394
+ return;
17395
+ }
16987
17396
  const read = async () => {
16988
17397
  const got = await waitingWork(token, identity.sessionId ?? owner?.sessionId);
16989
17398
  if (!("skip" in got)) return got;
@@ -17024,7 +17433,7 @@ function startHost(opts) {
17024
17433
  }
17025
17434
  found ??= await read() ?? void 0;
17026
17435
  if (!found) return;
17027
- if (runs.has(key)) {
17436
+ if (runs.has(key3)) {
17028
17437
  skip("was started by the wake that read it first");
17029
17438
  return;
17030
17439
  }
@@ -17040,14 +17449,17 @@ function startHost(opts) {
17040
17449
  // A dead run must not squat the slot — evict so the next wake can respawn. Only ITS entry:
17041
17450
  // a run that is no longer the slot's must not take the live one's place away with it.
17042
17451
  onExit: () => {
17043
- evict(runs, key, run);
17452
+ evict(runs, key3, run);
17044
17453
  goneAt.set(slot, Date.now());
17045
17454
  opts.log(`\u2716 ${label} ended`);
17046
17455
  },
17456
+ onFull: (session) => {
17457
+ updateSlot(slot, { full_session: session });
17458
+ },
17047
17459
  name: label,
17048
17460
  log: log2
17049
17461
  });
17050
- runs.set(key, { run, label, token });
17462
+ runs.set(key3, { run, label, token });
17051
17463
  void heartbeat(void 0, { token }).catch(() => {
17052
17464
  });
17053
17465
  const woke = `\u25B6 ${owner ? "resumed" : "woke"} ${label} (${harness}) \u2014 ${found.waiting} was waiting, in ${workspace}${decided.why === "gone" ? " (its process here ended; its last heartbeat was not waited out)" : taking}`;
@@ -17100,17 +17512,17 @@ function startHost(opts) {
17100
17512
  void heartbeat(void 0, { token, activity: { lines: lines2, at: (/* @__PURE__ */ new Date()).toISOString() } }).catch(() => {
17101
17513
  });
17102
17514
  };
17103
- for (const [key, r] of runs) {
17515
+ for (const [key3, r] of runs) {
17104
17516
  if (!r.token) continue;
17105
17517
  const lines2 = r.run.tail();
17106
- const was = published.get(key);
17518
+ const was = published.get(key3);
17107
17519
  if (was && sameTail(was.lines, lines2)) continue;
17108
- published.set(key, { token: r.token, lines: lines2 });
17520
+ published.set(key3, { token: r.token, lines: lines2 });
17109
17521
  publishTail(r.token, lines2);
17110
17522
  }
17111
- for (const [key, was] of published) {
17112
- if (runs.has(key)) continue;
17113
- published.delete(key);
17523
+ for (const [key3, was] of published) {
17524
+ if (runs.has(key3)) continue;
17525
+ published.delete(key3);
17114
17526
  if (was.lines.length > 0) publishTail(was.token, []);
17115
17527
  }
17116
17528
  };
@@ -17141,25 +17553,25 @@ function startHost(opts) {
17141
17553
  })));
17142
17554
  };
17143
17555
  const api = {
17144
- sessions: () => [...runs.entries()].map(([id, r]) => [id, r.label]),
17556
+ sessions: () => [...runs.entries()].map(([id3, r]) => [id3, r.label]),
17145
17557
  // Every identity this machine holds, plus what it's doing right now. Slots are the
17146
17558
  // roster (hatched agents, the terminal tools, claimed sessions); a run makes one of
17147
17559
  // them live, and a run mid-turn makes it working.
17148
17560
  roster: () => {
17149
17561
  const live = new Map([...runs.values()].map((r) => [r.label, r.run]));
17150
17562
  const names2 = /* @__PURE__ */ new Map();
17151
- for (const key of listSlots()) if (key !== "Desktop" && !isRevoked(key)) names2.set(slotName(key) ?? key, key);
17563
+ for (const key3 of listSlots()) if (key3 !== "Desktop" && !isRevoked(key3)) names2.set(slotName(key3) ?? key3, key3);
17152
17564
  for (const label of live.keys()) if (!names2.has(label)) names2.set(label, null);
17153
17565
  return [...names2.entries()].map(([name, slot]) => {
17154
- const id = slot ? slotIdentity(slot) : { voice: null, tokenId: null };
17566
+ const id3 = slot ? slotIdentity(slot) : { voice: null, tokenId: null };
17155
17567
  return {
17156
17568
  name,
17157
17569
  // The slot key rides along so the window's agent page can speak AS this agent —
17158
17570
  // its pending reads (`checkReplies`, the same pure read the sweep does) need the
17159
17571
  // slot's own token, and the display name is not a key.
17160
17572
  slot,
17161
- tokenId: id.tokenId,
17162
- voice: id.voice,
17573
+ tokenId: id3.tokenId,
17574
+ voice: id3.voice,
17163
17575
  // RUNNING IS ABOUT THE IDENTITY, NOT ABOUT US (owner, 2026-09-14). This was
17164
17576
  // `live.has(name)` — "this host spawned it and it has not exited" — which is a fact
17165
17577
  // about our own process table, not about the agent. An ordinary terminal session
@@ -17167,7 +17579,7 @@ function startHost(opts) {
17167
17579
  // sessions we started ourselves. The server already knows: `last_seen_at` on the
17168
17580
  // agent's own token, the same evidence `wakeAction` stands back for. So: a run we
17169
17581
  // hold, OR a process the server heard from inside `PRESENCE_FRESH_MS`.
17170
- running: live.has(name) || !!slot && lastHolders.has(slot) || !!id.tokenId && Date.now() - (lastPresence.get(id.tokenId) ?? 0) < PRESENCE_FRESH_MS,
17582
+ running: live.has(name) || !!slot && lastHolders.has(slot) || !!id3.tokenId && Date.now() - (lastPresence.get(id3.tokenId) ?? 0) < PRESENCE_FRESH_MS,
17171
17583
  // `working` stays ours alone — it means a run WE hold is mid-turn, which is the only
17172
17584
  // thing a tail can tell us. A process we did not spawn has no tail here to read.
17173
17585
  working: live.get(name)?.working() ?? false
@@ -17349,11 +17761,11 @@ ipcMain.handle("paigy:triage-accept", async (_e, opts) => {
17349
17761
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
17350
17762
  }
17351
17763
  });
17352
- ipcMain.handle("paigy:triage-dismiss", async (_e, id) => {
17764
+ ipcMain.handle("paigy:triage-dismiss", async (_e, id3) => {
17353
17765
  const token = deviceToken();
17354
17766
  if (!token) return { ok: false, error: "This Mac isn't paired yet." };
17355
17767
  try {
17356
- await dismissTriage(id, { token });
17768
+ await dismissTriage(id3, { token });
17357
17769
  return { ok: true };
17358
17770
  } catch (e) {
17359
17771
  return { ok: false, error: e instanceof Error ? e.message : String(e) };