@paigy/harness 0.3.32 → 0.3.34

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 +832 -441
  2. package/dist/main.js +664 -292
  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
- "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
+ "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. parentId is optional here: the question's own Goal is used. 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,153 @@ 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({ entryId: id }).strict();
10078
+ var ResultRefSchema = external_exports.union([external_exports.object({ id }).strict(), external_exports.object({ local: key }).strict()]);
10079
+ var NodeRefSchema = external_exports.object({ type: external_exports.enum(["goal", "question"]), id }).strict();
10080
+ var DependencySchema = external_exports.object({
10081
+ blocker: NodeRefSchema,
10082
+ blocked: NodeRefSchema,
10083
+ action: external_exports.enum(["start", "complete", "answer"]),
10084
+ reason: external_exports.string().max(500).optional()
10085
+ }).strict();
10086
+ var goalState = external_exports.enum(["open", "completed", "canceled"]);
10087
+ var existingGoalChanges = [
10088
+ 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"),
10089
+ external_exports.object({ kind: external_exports.literal("state"), goalId: id, state: goalState }).strict(),
10090
+ external_exports.object({ kind: external_exports.literal("assign"), goalId: id, ownerId: participant }).strict(),
10091
+ external_exports.object({ kind: external_exports.literal("defer"), goalId: id, until: external_exports.string().datetime().nullable() }).strict(),
10092
+ external_exports.object({ kind: external_exports.literal("move"), goalId: id, parentGoalId: id.nullable() }).strict(),
10093
+ external_exports.object({
10094
+ kind: external_exports.literal("dependency"),
10095
+ change: external_exports.enum(["add", "remove"]),
10096
+ goalId: id,
10097
+ dependsOnGoalId: id,
10098
+ action: external_exports.enum(["start", "complete"]),
10099
+ reason: external_exports.string().max(500).optional()
10100
+ }).strict()
10101
+ ];
10102
+ var GoalChangeSchema = external_exports.union([
10103
+ external_exports.object({
10104
+ kind: external_exports.literal("create"),
10105
+ title: external_exports.string().min(1).max(120),
10106
+ outcome: external_exports.string().min(1),
10107
+ ownerId: participant,
10108
+ parentGoalId: id.optional(),
10109
+ sourceEntryIds: external_exports.array(id)
10110
+ }).strict(),
10111
+ ...existingGoalChanges
10112
+ ]);
10113
+ var BrainGoalChangeSchema = external_exports.union([
10114
+ // newSession: Paigy starts a session to own it (owner, 2026-10-06); until it has, the person owns it.
10115
+ external_exports.object({
10116
+ kind: external_exports.literal("create"),
10117
+ outcome: external_exports.string().min(1),
10118
+ title: external_exports.string().min(1).max(120),
10119
+ ownerId: participant,
10120
+ parentGoal: ResultRefSchema.nullable(),
10121
+ newSession: external_exports.literal(true).optional()
10122
+ }).strict(),
10123
+ ...existingGoalChanges
10124
+ ]);
10125
+ 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();
10126
+ var QuestionChangeSchema = external_exports.union([
10127
+ external_exports.object({
10128
+ kind: external_exports.literal("create"),
10129
+ text: external_exports.string().min(1),
10130
+ answererId: participant,
10131
+ goal: ResultRefSchema.optional(),
10132
+ blocks: external_exports.array(external_exports.object({ question: ResultRefSchema }).strict()),
10133
+ options: external_exports.array(option).min(2).optional(),
10134
+ pickMode: external_exports.enum(["one", "many", "rank"]).optional()
10135
+ }).strict().refine((c) => c.options === void 0 === (c.pickMode === void 0), "options and pickMode come together"),
10136
+ external_exports.object({ kind: external_exports.literal("edit"), questionId: id, text: external_exports.string().min(1) }).strict(),
10137
+ external_exports.object({ kind: external_exports.literal("assign"), questionId: id, answererId: participant }).strict(),
10138
+ external_exports.object({ kind: external_exports.literal("withdraw"), questionId: id }).strict(),
10139
+ external_exports.object({ kind: external_exports.literal("dependency"), change: external_exports.enum(["add", "remove"]), edge: DependencySchema }).strict()
10140
+ ]);
10141
+ var lessonScope = external_exports.union([
10142
+ external_exports.object({ kind: external_exports.literal("user") }).strict(),
10143
+ external_exports.object({ kind: external_exports.literal("goal"), goal: ResultRefSchema }).strict()
10144
+ ]);
10145
+ var LessonChangeSchema = external_exports.union([
10146
+ external_exports.object({ kind: external_exports.literal("remember"), text: external_exports.string().min(1), scope: lessonScope }).strict(),
10147
+ external_exports.object({ kind: external_exports.literal("revise"), lessonId: id, text: external_exports.string().min(1), scope: lessonScope }).strict(),
10148
+ external_exports.object({ kind: external_exports.literal("withdraw"), lessonId: id }).strict()
10149
+ ]);
10150
+ var BrainNextSchema = external_exports.object({
10151
+ instructions: external_exports.array(external_exports.object({ entryKeys: external_exports.array(key).min(1) }).strict()),
10152
+ say: external_exports.array(key),
10153
+ then: external_exports.enum(["listen", "hold", "end", "none"]),
10154
+ waitFor: external_exports.array(ResultRefSchema),
10155
+ reason: external_exports.string()
10156
+ }).strict();
10157
+ var messageBase = {
10158
+ key,
10159
+ text: external_exports.string().min(1),
10160
+ goals: external_exports.array(ResultRefSchema),
10161
+ questions: external_exports.array(ResultRefSchema),
10162
+ entryKeys: external_exports.array(key),
10163
+ obligationIds: external_exports.array(id)
10164
+ };
10165
+ var BrainMessageSchema = external_exports.union([
10166
+ external_exports.object({ ...messageBase, to: external_exports.object({ kind: external_exports.literal("user") }).strict() }).strict(),
10167
+ external_exports.object({
10168
+ ...messageBase,
10169
+ to: external_exports.object({ kind: external_exports.literal("agent"), agentId: external_exports.string().regex(/^agent:(?!paigy$)\S+$/) }).strict(),
10170
+ call: external_exports.object({ callId: id, listen: external_exports.literal(true) }).strict().optional()
10171
+ }).strict()
10172
+ ]);
10173
+ var BrainSearchSchema = external_exports.object({
10174
+ query: external_exports.string().min(1).max(500),
10175
+ within: external_exports.array(external_exports.enum(["entries", "goals", "answers"])).min(1),
10176
+ goalId: id.optional()
10177
+ }).strict();
10178
+ var BrainResultSchema = external_exports.object({
10179
+ messages: external_exports.array(BrainMessageSchema),
10180
+ entries: external_exports.array(external_exports.object({ key, sources: external_exports.array(SourceSchema).min(1), goals: external_exports.array(ResultRefSchema) }).strict()),
10181
+ questions: external_exports.array(external_exports.object({ key, entryKeys: external_exports.array(key), change: QuestionChangeSchema }).strict()),
10182
+ answers: external_exports.array(external_exports.object({
10183
+ question: ResultRefSchema,
10184
+ entryKeys: external_exports.array(key).min(1),
10185
+ summary: external_exports.string().min(1),
10186
+ selectedOptionIds: external_exports.array(external_exports.string().min(1)).optional()
10187
+ }).strict()),
10188
+ goals: external_exports.array(external_exports.object({ key, entryKeys: external_exports.array(key), change: BrainGoalChangeSchema }).strict()),
10189
+ feedback: external_exports.array(external_exports.object({ entryKeys: external_exports.array(key).min(1) }).strict()),
10190
+ lessons: external_exports.array(external_exports.object({ entryKeys: external_exports.array(key).min(1), change: LessonChangeSchema }).strict()),
10191
+ next: BrainNextSchema,
10192
+ search: BrainSearchSchema.optional()
10193
+ }).strict();
10194
+ var str = external_exports.string();
10195
+ var strs = external_exports.array(external_exports.string());
10196
+ var CompactResultSchema = external_exports.object({
10197
+ next: external_exports.object({ say: strs, then: external_exports.enum(["listen", "hold", "end", "none"]), waitFor: strs, reason: str, instructions: strs }).strict(),
10198
+ messages: external_exports.array(external_exports.object({ key: str, to: str, text: str, about: strs, entries: strs, owed: strs, inviteToCall: external_exports.boolean() }).strict()),
10199
+ entries: external_exports.array(external_exports.object({ key: str, from: str, on: strs }).strict()),
10200
+ answers: external_exports.array(external_exports.object({ question: str, entries: strs, summary: str, picked: strs }).strict()),
10201
+ changes: external_exports.array(external_exports.object({
10202
+ key: str,
10203
+ what: external_exports.enum(["goal", "question", "lesson"]),
10204
+ op: external_exports.enum(["create", "edit", "assign", "open", "complete", "cancel", "defer", "move", "block", "unblock", "withdraw", "remember", "revise"]),
10205
+ id: str,
10206
+ text: str,
10207
+ title: str,
10208
+ who: str,
10209
+ under: str,
10210
+ gate: external_exports.enum(["start", "complete", "answer", "none"]),
10211
+ options: external_exports.array(external_exports.object({ id: str, label: str }).strict()),
10212
+ pick: external_exports.enum(["one", "many", "rank", "words"]),
10213
+ entries: strs
10214
+ }).strict()),
10215
+ feedback: external_exports.array(strs),
10216
+ search: external_exports.object({ query: str, within: strs, goal: str }).strict()
10217
+ }).strict();
10218
+ var COMPACT_RESULT_JSON_SCHEMA = (({ $schema: _, ...rest }) => rest)(
10219
+ zodToJsonSchema(CompactResultSchema, { $refStrategy: "none" })
10220
+ );
10073
10221
  var LIVE_MS = 3 * 6e4;
10074
10222
  var WORKING_MS = 60 * 6e4;
10075
10223
  var ContextSchema = external_exports.object({
@@ -10289,7 +10437,7 @@ var IntentSchema = external_exports.object({
10289
10437
  * (`parseDelay`, #1292), and a value here simply wins over that reading. */
10290
10438
  dueInSeconds: external_exports.number().int().positive().optional(),
10291
10439
  /** 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
10440
+ * already read the utterance, so `signals.kind` stops defaulting to
10293
10441
  * 'other' on every row. A table that records that something was wrong and nothing
10294
10442
  * about what cannot answer "is the bot looping less this week?". */
10295
10443
  fault: external_exports.enum(["loop", "unanswered", "overridden", "misheard", "slow", "other"]).optional()
@@ -10573,7 +10721,18 @@ var InboxItemSchema = external_exports.object({
10573
10721
  /** THAT GOAL'S NAME (#2416) — what Activity's row is headed by, since a row there is one Goal
10574
10722
  * and the cards it holds sit behind it. Stamped by the same read as `goalState`. */
10575
10723
  goalTitle: external_exports.string().optional()
10576
- }).optional()
10724
+ }).optional(),
10725
+ /** WHAT THIS CARD IS, IN TWELVE CHARACTERS (#3019) — the hash of every other field on it, stamped
10726
+ * by the one read that serves the open list (`apps/api/src/inbox/project.ts` `inboxFor`). It is
10727
+ * how the incremental read knows a card has not moved: the phone echoes back the revs it holds
10728
+ * (`POST /api/inbox/changes`) and is sent only the cards whose rev differs.
10729
+ *
10730
+ * THE PAYLOAD'S OWN HASH, NEVER A STAMP ON THE WORK — the same mechanism as `QueueItem.rev`
10731
+ * (#2928) and an entry's (#3018), for the same reason: a card shows facts no `updated_at` of its
10732
+ * own moves (its Goal's state and name, how cold the work behind it has gone, whether a ring is
10733
+ * live). Optional, so a fixture, the demo and the archive lens need not spell one, and a card
10734
+ * with no rev is simply always re-sent. */
10735
+ rev: external_exports.string().optional()
10577
10736
  });
10578
10737
  var APNS_TOKEN_RE = /^[0-9a-fA-F]{64}$/;
10579
10738
  var PushTokenSchema = external_exports.object({
@@ -10785,39 +10944,22 @@ var ReassignResultSchema = external_exports.object({
10785
10944
  moved: external_exports.object({ asks: external_exports.number(), answered: external_exports.number(), requests: external_exports.number(), goals: external_exports.number(), callbacks: external_exports.number() }),
10786
10945
  parentId: external_exports.string().nullable()
10787
10946
  });
10788
- var MoveRingSchema = external_exports.enum(["home", "travels", "retired", "quarantined"]);
10789
- var MoveSchema = external_exports.object({
10947
+ var LessonStateSchema = external_exports.enum(["active", "proposed", "retired"]);
10948
+ var LessonViewSchema = external_exports.object({
10790
10949
  id: external_exports.string(),
10791
- /** The reusable question, as distill normalized it. */
10792
- question: external_exports.string(),
10793
- /** The operative ruling. Editable by the user (PATCH) — which resets the ledger. */
10794
- answer: external_exports.string(),
10795
- /** The user's stated reason, when they gave one. Null = inherently narrow: the judge is
10796
- * told so, and the ruling only derives essentially the same question in the same scope. */
10797
- rationale: external_exports.string().nullable(),
10798
- /** Where the ruling lives: a repo/workspace, or 'global'. */
10799
- scope: external_exports.string(),
10800
- ring: MoveRingSchema,
10801
- /** True = the user pinned it with `always` (travel granted by hand, not by evidence). */
10950
+ text: external_exports.string(),
10951
+ state: LessonStateSchema,
10952
+ /** The Goal it is scoped to; null = the whole account. */
10953
+ scopeGoalId: external_exports.string().nullable(),
10954
+ goalTitle: external_exports.string().nullable(),
10955
+ version: external_exports.number(),
10802
10956
  pinned: external_exports.boolean(),
10803
- /** True = a pin the user placed was BROKEN by later counter-evidence. Surfaced so the
10804
- * break is visible instead of a pin silently disappearing. */
10805
- pinBroken: external_exports.boolean(),
10806
- /** When the ruling was distilled. */
10807
- learnedAt: external_exports.string(),
10808
- /** Last time it answered an ask. Null = never fired. */
10809
- lastUsedAt: external_exports.string().nullable(),
10810
- /** How many asks it has answered. Instrumentation — deliberately NOT an input to the
10811
- * evidence curve: firing says the question keeps arising, not that the ruling is right. */
10812
- usedCount: external_exports.number(),
10813
- /** Ledger: outcomes that said it held up. Saturating — the tenth is worth almost nothing. */
10814
- confirms: external_exports.number(),
10815
- /** Ledger: contradictions, in signal units (a full override = 1, weaker signals less).
10816
- * Linear and priced above the entire confirmation budget, so any full counter wins. */
10817
- counters: external_exports.number(),
10818
- /** The agent that asked the question this move came from, when known. Null for a move
10819
- * distilled from a clarify ruling (those carry no agent) or one whose source rows are gone. */
10820
- learnedFrom: external_exports.object({ id: external_exports.string(), name: external_exports.string() }).nullable()
10957
+ /** When the person last wrote its text themselves. */
10958
+ editedAt: external_exports.string().nullable(),
10959
+ createdAt: external_exports.string(),
10960
+ updatedAt: external_exports.string(),
10961
+ /** The Entries it came from, oldest first; `words` is null when an Entry has none to show (sealed). */
10962
+ sources: external_exports.array(external_exports.object({ entryId: external_exports.string(), words: external_exports.string().nullable(), at: external_exports.string() }))
10821
10963
  });
10822
10964
  var QueueQuestionSchema = external_exports.object({
10823
10965
  /** The decision need's id — what an answer is accepted against. */
@@ -10945,7 +11087,22 @@ var QueueItemSchema = external_exports.object({
10945
11087
  * minute after the person speaks erases their instant from it, and the durable traces the client
10946
11088
  * can see (`replies`, `questions[].answeredAt`) miss a spontaneous note entirely — a `request`
10947
11089
  * Entry with no `about_id` is in neither. */
10948
- lastPersonAt: external_exports.string().nullable().optional()
11090
+ lastPersonAt: external_exports.string().nullable().optional(),
11091
+ /** WHAT THIS ROW IS, IN TWELVE CHARACTERS (#2928) — the hash of every other field on it, stamped
11092
+ * by the one projection that builds the row (`apps/api/src/goal/queue.ts`). It is how the
11093
+ * incremental read knows a row has not moved: the phone echoes back the revs it holds
11094
+ * (`POST /api/goals/changes`) and is sent only the rows whose rev differs.
11095
+ *
11096
+ * IT IS THE PAYLOAD'S OWN HASH, NEVER A STAMP ON THE WORK. Nothing here reasons about which
11097
+ * writes change which field — the comparison is over the bytes the phone is holding, so a fact
11098
+ * the row shows that no `updated_at` moves for (a lease lapsing, a dependency's state, a
11099
+ * sibling appearing in `childGoalIds`) cannot go unnoticed. Optional because a hand-built
11100
+ * queue (a fixture, the demo) spells none, and a row with no rev is simply always re-sent. */
11101
+ rev: external_exports.string().optional()
11102
+ });
11103
+ var QueueDeltaSchema = external_exports.object({
11104
+ ids: external_exports.array(external_exports.string()),
11105
+ items: external_exports.array(QueueItemSchema)
10949
11106
  });
10950
11107
  var COLD_AFTER_MS = 3 * 24 * 60 * 60 * 1e3;
10951
11108
  var NoteSourceSchema = external_exports.enum(["app", "call"]);
@@ -11118,6 +11275,11 @@ var DeviceTokenSchema = external_exports.object({
11118
11275
  /** Local host recovery must preserve the launch's runtime and Paigy identity. */
11119
11276
  harness: external_exports.enum(["claude", "codex", "agy"]).optional(),
11120
11277
  session_id: external_exports.string().uuid().optional(),
11278
+ /** A conversation the host must not resume: its context is full, so every turn fails
11279
+ * ("Prompt is too long"). Written when a run hits it (`run.ts` `onFull`); the host skips a slot
11280
+ * whose resumable session is this one, so its Goals reach the dead-agent handoff instead of a
11281
+ * copy that types the person's words into a turn that cannot run (Calls, 2026-10-06). */
11282
+ full_session: external_exports.string().optional(),
11121
11283
  uik_pub: external_exports.string().nullable().optional()
11122
11284
  });
11123
11285
  var SupportRequestSchema = external_exports.object({
@@ -11263,8 +11425,8 @@ var CallRecapSchema = external_exports.object({
11263
11425
  more: external_exports.object({ lines: external_exports.number(), entries: external_exports.number(), topics: external_exports.number() })
11264
11426
  });
11265
11427
  function sessionSlot(sessionId2) {
11266
- const id = sessionId2 ?? sessionId();
11267
- return `session:${id.slice(0, 8)}`;
11428
+ const id22 = sessionId2 ?? sessionId();
11429
+ return `session:${id22.slice(0, 8)}`;
11268
11430
  }
11269
11431
  function agentName() {
11270
11432
  return process.env.PAIGY_AGENT || sessionSlot();
@@ -11321,7 +11483,7 @@ function updateSlot(agent2, patch) {
11321
11483
  }
11322
11484
  function slotIdentity(agent2) {
11323
11485
  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 };
11486
+ 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
11487
  }
11326
11488
  var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
11327
11489
  function readToken(agent2 = agentName()) {
@@ -11483,7 +11645,9 @@ async function recordDecision(decision, opts = {}) {
11483
11645
  async function heartbeat(runtime, opts = {}) {
11484
11646
  const body = {
11485
11647
  ...runtime !== void 0 ? { runtime } : {},
11486
- ...opts.activity !== void 0 ? { activity: opts.activity } : {}
11648
+ ...opts.activity !== void 0 ? { activity: opts.activity } : {},
11649
+ // A listener's beat (`paigy-listen`): stamps when it last swept, and is not presence.
11650
+ ...opts.listening ? { listening: true } : {}
11487
11651
  };
11488
11652
  const res = await ensureAuthed(await reach(`${BACKEND_URL}/api/presence`, {
11489
11653
  method: "POST",
@@ -11575,6 +11739,7 @@ function currentRepo(cwd = process.cwd()) {
11575
11739
  return asked;
11576
11740
  }
11577
11741
  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.";
11742
+ 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
11743
  async function contact(input, opts = {}) {
11579
11744
  const parsed = ContactSchema.parse(input);
11580
11745
  opts.signal?.throwIfAborted();
@@ -11583,6 +11748,7 @@ async function contact(input, opts = {}) {
11583
11748
  let deliveryId;
11584
11749
  let deliveries = [];
11585
11750
  let recorded = [];
11751
+ let demoted;
11586
11752
  if ("deliveryId" in parsed) {
11587
11753
  deliveryId = parsed.deliveryId;
11588
11754
  } else {
@@ -11613,13 +11779,14 @@ async function contact(input, opts = {}) {
11613
11779
  if (!res.ok) await fail("batch contact", res);
11614
11780
  const receipt = await res.json();
11615
11781
  deliveries = receipt.deliveries ?? [];
11782
+ if (parsed.channel === "call" && receipt.channel && receipt.channel !== "call") demoted = DEMOTED;
11616
11783
  recorded = receipt.recorded ?? [];
11617
11784
  if (deliveries.length === 0 && recorded.length) return { sent: false, recorded, message: NOT_SENT };
11618
11785
  if (deliveries.length === 0) throw new Error("Goal contact returned no Delivery identities");
11619
11786
  deliveryId = deliveries[0]?.deliveryId ?? "";
11620
11787
  if (!deliveryId) throw new Error("Goal contact returned no valid Delivery identity");
11621
11788
  }
11622
- const all = deliveries.filter((d) => !!d.deliveryId && !!d.goalId).map(({ id, deliveryId: deliveryId2, goalId }) => ({ ...id ? { id } : {}, deliveryId: deliveryId2, goalId }));
11789
+ const all = deliveries.filter((d) => !!d.deliveryId && !!d.goalId).map(({ id: id22, deliveryId: deliveryId2, goalId }) => ({ ...id22 ? { id: id22 } : {}, deliveryId: deliveryId2, goalId }));
11623
11790
  const joinedCard = deliveries[0]?.joinedCard === true;
11624
11791
  const joinedCall = deliveries[0]?.joinedCall === true;
11625
11792
  const read = async (signal2) => {
@@ -11631,7 +11798,8 @@ async function contact(input, opts = {}) {
11631
11798
  ...all.length > 1 ? { deliveries: all } : {},
11632
11799
  ...recorded.length ? { recorded, notSent: NOT_SENT } : {},
11633
11800
  ...joinedCard ? { joinedCard: true } : {},
11634
- ...joinedCall ? { joinedCall: true } : {}
11801
+ ...joinedCall ? { joinedCall: true } : {},
11802
+ ...demoted ? { demoted } : {}
11635
11803
  };
11636
11804
  };
11637
11805
  const settled = (d) => d.kind === "notification" || d.state === "closed" || d.answers.length > 0 || d.entries.some((e) => e.kind === "contribution");
@@ -11768,9 +11936,9 @@ function connect(line) {
11768
11936
  ws.addEventListener("error", again);
11769
11937
  }
11770
11938
  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() });
11939
+ const key22 = `${args.url} ${args.anonKey}`;
11940
+ let line = lines.get(key22);
11941
+ if (!line) lines.set(key22, line = { url: args.url, anonKey: args.anonKey, open: false, attempt: 0, ref: 0, topics: /* @__PURE__ */ new Map() });
11774
11942
  let t = line.topics.get(args.topic);
11775
11943
  if (!t) {
11776
11944
  line.topics.set(args.topic, t = { listeners: /* @__PURE__ */ new Set(), joined: false, attempt: 0 });
@@ -11792,7 +11960,7 @@ function subscribeRealtime(args) {
11792
11960
  if (line.open) frame(line, `realtime:${args.topic}`, "phx_leave", {});
11793
11961
  return;
11794
11962
  }
11795
- lines.delete(key);
11963
+ lines.delete(key22);
11796
11964
  stop(line);
11797
11965
  try {
11798
11966
  line.ws?.close();
@@ -12241,16 +12409,16 @@ function parseVerdicts(raw, knownIds, knownAgents) {
12241
12409
  const seen = /* @__PURE__ */ new Set();
12242
12410
  for (const row of rows) {
12243
12411
  const r = row;
12244
- const id = typeof r?.id === "string" ? r.id : "";
12245
- if (!id) {
12412
+ const id3 = typeof r?.id === "string" ? r.id : "";
12413
+ if (!id3) {
12246
12414
  dropped.push({ row, reason: "no id" });
12247
12415
  continue;
12248
12416
  }
12249
- if (!knownIds.has(id)) {
12417
+ if (!knownIds.has(id3)) {
12250
12418
  dropped.push({ row, reason: "id is not a note in this queue" });
12251
12419
  continue;
12252
12420
  }
12253
- if (seen.has(id)) {
12421
+ if (seen.has(id3)) {
12254
12422
  dropped.push({ row, reason: "duplicate verdict for this note" });
12255
12423
  continue;
12256
12424
  }
@@ -12265,12 +12433,12 @@ function parseVerdicts(raw, knownIds, knownAgents) {
12265
12433
  continue;
12266
12434
  }
12267
12435
  verdicts.push({
12268
- id,
12436
+ id: id3,
12269
12437
  verdict,
12270
12438
  agent: verdict === "assign" ? agent2 : null,
12271
12439
  why: typeof r?.why === "string" ? r.why.trim().slice(0, 200) : null
12272
12440
  });
12273
- seen.add(id);
12441
+ seen.add(id3);
12274
12442
  }
12275
12443
  return { ok: true, verdicts, dropped };
12276
12444
  }
@@ -12425,7 +12593,7 @@ async function runTriage(opts, deps = {}) {
12425
12593
  const acted = suggested(run);
12426
12594
  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
12595
  if (!opts.apply) return 0;
12428
- const accept = deps.accept ?? ((id, body) => acceptTriage(id, body));
12596
+ const accept = deps.accept ?? ((id3, body) => acceptTriage(id3, body));
12429
12597
  const groups = [
12430
12598
  { body: { group: "close" }, label: `close ${plural(run.close.length, "note")}`, count: run.close.length, preapproved: opts.yes.close },
12431
12599
  { body: { group: "stale" }, label: `close ${plural(run.stale.length, "stale note")}`, count: run.stale.length, preapproved: opts.yes.stale },
@@ -12848,19 +13016,19 @@ var getRefs2 = (options) => {
12848
13016
  };
12849
13017
 
12850
13018
  // ../../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) {
13019
+ function addErrorMessage2(res, key3, errorMessage, refs) {
12852
13020
  if (!refs?.errorMessages)
12853
13021
  return;
12854
13022
  if (errorMessage) {
12855
13023
  res.errorMessage = {
12856
13024
  ...res.errorMessage,
12857
- [key]: errorMessage
13025
+ [key3]: errorMessage
12858
13026
  };
12859
13027
  }
12860
13028
  }
12861
- function setResponseValueAndErrors2(res, key, value, errorMessage, refs) {
12862
- res[key] = value;
12863
- addErrorMessage2(res, key, errorMessage, refs);
13029
+ function setResponseValueAndErrors2(res, key3, value, errorMessage, refs) {
13030
+ res[key3] = value;
13031
+ addErrorMessage2(res, key3, errorMessage, refs);
12864
13032
  }
12865
13033
 
12866
13034
  // ../../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 +13620,11 @@ function parseRecordDef2(def, refs) {
13452
13620
  return {
13453
13621
  type: "object",
13454
13622
  required: def.keyType._def.values,
13455
- properties: def.keyType._def.values.reduce((acc, key) => ({
13623
+ properties: def.keyType._def.values.reduce((acc, key3) => ({
13456
13624
  ...acc,
13457
- [key]: parseDef2(def.valueType._def, {
13625
+ [key3]: parseDef2(def.valueType._def, {
13458
13626
  ...refs,
13459
- currentPath: [...refs.currentPath, "properties", key]
13627
+ currentPath: [...refs.currentPath, "properties", key3]
13460
13628
  }) ?? parseAnyDef2(refs)
13461
13629
  }), {}),
13462
13630
  additionalProperties: refs.rejectedAdditionalProperties
@@ -13523,10 +13691,10 @@ function parseMapDef2(def, refs) {
13523
13691
  // ../../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
13692
  function parseNativeEnumDef2(def) {
13525
13693
  const object = def.values;
13526
- const actualKeys = Object.keys(def.values).filter((key) => {
13527
- return typeof object[object[key]] !== "number";
13694
+ const actualKeys = Object.keys(def.values).filter((key3) => {
13695
+ return typeof object[object[key3]] !== "number";
13528
13696
  });
13529
- const actualValues = actualKeys.map((key) => object[key]);
13697
+ const actualValues = actualKeys.map((key3) => object[key3]);
13530
13698
  const parsedTypes = Array.from(new Set(actualValues.map((values) => typeof values)));
13531
13699
  return {
13532
13700
  type: parsedTypes.length === 1 ? parsedTypes[0] === "string" ? "string" : "number" : ["string", "number"],
@@ -14127,32 +14295,31 @@ function mcpInputSchema2(s) {
14127
14295
  }
14128
14296
  var AskInputSchema2 = external_exports.object({
14129
14297
  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."),
14298
+ 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
14299
  repo: external_exports.string().optional().describe("Optional repository context."),
14132
14300
  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."
14301
+ "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
14302
  ),
14135
14303
  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.
14304
+ // HOW THE OPTIONS ARE ANSWERED, SAID BY THE AGENT (owner, 2026-10-02: "one and many makes sense";
14305
+ // brain_prompts.md §1: structured agent questions need no model). Every card was pick-one while no
14306
+ // agent sent this; no read reshapes cards any more, so this is the card's shape, and the
14307
+ // description says so plainly.
14141
14308
  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.`
14309
+ '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
14310
  ),
14144
14311
  answers: external_exports.string().trim().regex(/^[0-9a-fA-F-]{8,36}$/).optional().describe(
14145
- "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."
14312
+ "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. parentId is optional here: the question's own Goal is used. The reply is sent to them as it is; to also ask something new, send that as its own ask."
14146
14313
  )
14147
14314
  }).strict();
14148
14315
  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."),
14316
+ 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
14317
  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
14318
  channel: external_exports.enum(["notification", "call"]).default("notification")
14152
14319
  }).strict();
14153
14320
  var ContactSchema2 = external_exports.union([StartContactSchema2, external_exports.object({ deliveryId: external_exports.string().uuid() }).strict()]);
14154
14321
  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.";
14322
+ 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
14323
  var CreateGoalSchema2 = external_exports.object({
14157
14324
  outcome: external_exports.string().trim().min(1).max(1e4),
14158
14325
  /** The work's NAME (#2115) — one to five words, how a person refers to it out loud ("the night
@@ -14226,6 +14393,153 @@ var AGENT_TOOLS2 = [
14226
14393
  { name: "update_goal", description: UPDATE_GOAL_DESCRIPTION2, inputSchema: mcpInputSchema2(UpdateGoalToolSchema2) }
14227
14394
  ];
14228
14395
  var AGENT_TOOL_NAMES2 = AGENT_TOOLS2.map((t) => t.name);
14396
+ var id2 = external_exports.string().uuid();
14397
+ var key2 = external_exports.string().min(1).max(40);
14398
+ var participant2 = external_exports.string().regex(/^(human|agent):.+$/, "a participant ID such as agent:<uuid>");
14399
+ var SourceSchema2 = external_exports.object({ entryId: id2 }).strict();
14400
+ var ResultRefSchema2 = external_exports.union([external_exports.object({ id: id2 }).strict(), external_exports.object({ local: key2 }).strict()]);
14401
+ var NodeRefSchema2 = external_exports.object({ type: external_exports.enum(["goal", "question"]), id: id2 }).strict();
14402
+ var DependencySchema2 = external_exports.object({
14403
+ blocker: NodeRefSchema2,
14404
+ blocked: NodeRefSchema2,
14405
+ action: external_exports.enum(["start", "complete", "answer"]),
14406
+ reason: external_exports.string().max(500).optional()
14407
+ }).strict();
14408
+ var goalState2 = external_exports.enum(["open", "completed", "canceled"]);
14409
+ var existingGoalChanges2 = [
14410
+ 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"),
14411
+ external_exports.object({ kind: external_exports.literal("state"), goalId: id2, state: goalState2 }).strict(),
14412
+ external_exports.object({ kind: external_exports.literal("assign"), goalId: id2, ownerId: participant2 }).strict(),
14413
+ external_exports.object({ kind: external_exports.literal("defer"), goalId: id2, until: external_exports.string().datetime().nullable() }).strict(),
14414
+ external_exports.object({ kind: external_exports.literal("move"), goalId: id2, parentGoalId: id2.nullable() }).strict(),
14415
+ external_exports.object({
14416
+ kind: external_exports.literal("dependency"),
14417
+ change: external_exports.enum(["add", "remove"]),
14418
+ goalId: id2,
14419
+ dependsOnGoalId: id2,
14420
+ action: external_exports.enum(["start", "complete"]),
14421
+ reason: external_exports.string().max(500).optional()
14422
+ }).strict()
14423
+ ];
14424
+ var GoalChangeSchema2 = external_exports.union([
14425
+ external_exports.object({
14426
+ kind: external_exports.literal("create"),
14427
+ title: external_exports.string().min(1).max(120),
14428
+ outcome: external_exports.string().min(1),
14429
+ ownerId: participant2,
14430
+ parentGoalId: id2.optional(),
14431
+ sourceEntryIds: external_exports.array(id2)
14432
+ }).strict(),
14433
+ ...existingGoalChanges2
14434
+ ]);
14435
+ var BrainGoalChangeSchema2 = external_exports.union([
14436
+ // newSession: Paigy starts a session to own it (owner, 2026-10-06); until it has, the person owns it.
14437
+ external_exports.object({
14438
+ kind: external_exports.literal("create"),
14439
+ outcome: external_exports.string().min(1),
14440
+ title: external_exports.string().min(1).max(120),
14441
+ ownerId: participant2,
14442
+ parentGoal: ResultRefSchema2.nullable(),
14443
+ newSession: external_exports.literal(true).optional()
14444
+ }).strict(),
14445
+ ...existingGoalChanges2
14446
+ ]);
14447
+ 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();
14448
+ var QuestionChangeSchema2 = external_exports.union([
14449
+ external_exports.object({
14450
+ kind: external_exports.literal("create"),
14451
+ text: external_exports.string().min(1),
14452
+ answererId: participant2,
14453
+ goal: ResultRefSchema2.optional(),
14454
+ blocks: external_exports.array(external_exports.object({ question: ResultRefSchema2 }).strict()),
14455
+ options: external_exports.array(option2).min(2).optional(),
14456
+ pickMode: external_exports.enum(["one", "many", "rank"]).optional()
14457
+ }).strict().refine((c) => c.options === void 0 === (c.pickMode === void 0), "options and pickMode come together"),
14458
+ external_exports.object({ kind: external_exports.literal("edit"), questionId: id2, text: external_exports.string().min(1) }).strict(),
14459
+ external_exports.object({ kind: external_exports.literal("assign"), questionId: id2, answererId: participant2 }).strict(),
14460
+ external_exports.object({ kind: external_exports.literal("withdraw"), questionId: id2 }).strict(),
14461
+ external_exports.object({ kind: external_exports.literal("dependency"), change: external_exports.enum(["add", "remove"]), edge: DependencySchema2 }).strict()
14462
+ ]);
14463
+ var lessonScope2 = external_exports.union([
14464
+ external_exports.object({ kind: external_exports.literal("user") }).strict(),
14465
+ external_exports.object({ kind: external_exports.literal("goal"), goal: ResultRefSchema2 }).strict()
14466
+ ]);
14467
+ var LessonChangeSchema2 = external_exports.union([
14468
+ external_exports.object({ kind: external_exports.literal("remember"), text: external_exports.string().min(1), scope: lessonScope2 }).strict(),
14469
+ external_exports.object({ kind: external_exports.literal("revise"), lessonId: id2, text: external_exports.string().min(1), scope: lessonScope2 }).strict(),
14470
+ external_exports.object({ kind: external_exports.literal("withdraw"), lessonId: id2 }).strict()
14471
+ ]);
14472
+ var BrainNextSchema2 = external_exports.object({
14473
+ instructions: external_exports.array(external_exports.object({ entryKeys: external_exports.array(key2).min(1) }).strict()),
14474
+ say: external_exports.array(key2),
14475
+ then: external_exports.enum(["listen", "hold", "end", "none"]),
14476
+ waitFor: external_exports.array(ResultRefSchema2),
14477
+ reason: external_exports.string()
14478
+ }).strict();
14479
+ var messageBase2 = {
14480
+ key: key2,
14481
+ text: external_exports.string().min(1),
14482
+ goals: external_exports.array(ResultRefSchema2),
14483
+ questions: external_exports.array(ResultRefSchema2),
14484
+ entryKeys: external_exports.array(key2),
14485
+ obligationIds: external_exports.array(id2)
14486
+ };
14487
+ var BrainMessageSchema2 = external_exports.union([
14488
+ external_exports.object({ ...messageBase2, to: external_exports.object({ kind: external_exports.literal("user") }).strict() }).strict(),
14489
+ external_exports.object({
14490
+ ...messageBase2,
14491
+ to: external_exports.object({ kind: external_exports.literal("agent"), agentId: external_exports.string().regex(/^agent:(?!paigy$)\S+$/) }).strict(),
14492
+ call: external_exports.object({ callId: id2, listen: external_exports.literal(true) }).strict().optional()
14493
+ }).strict()
14494
+ ]);
14495
+ var BrainSearchSchema2 = external_exports.object({
14496
+ query: external_exports.string().min(1).max(500),
14497
+ within: external_exports.array(external_exports.enum(["entries", "goals", "answers"])).min(1),
14498
+ goalId: id2.optional()
14499
+ }).strict();
14500
+ var BrainResultSchema2 = external_exports.object({
14501
+ messages: external_exports.array(BrainMessageSchema2),
14502
+ entries: external_exports.array(external_exports.object({ key: key2, sources: external_exports.array(SourceSchema2).min(1), goals: external_exports.array(ResultRefSchema2) }).strict()),
14503
+ questions: external_exports.array(external_exports.object({ key: key2, entryKeys: external_exports.array(key2), change: QuestionChangeSchema2 }).strict()),
14504
+ answers: external_exports.array(external_exports.object({
14505
+ question: ResultRefSchema2,
14506
+ entryKeys: external_exports.array(key2).min(1),
14507
+ summary: external_exports.string().min(1),
14508
+ selectedOptionIds: external_exports.array(external_exports.string().min(1)).optional()
14509
+ }).strict()),
14510
+ goals: external_exports.array(external_exports.object({ key: key2, entryKeys: external_exports.array(key2), change: BrainGoalChangeSchema2 }).strict()),
14511
+ feedback: external_exports.array(external_exports.object({ entryKeys: external_exports.array(key2).min(1) }).strict()),
14512
+ lessons: external_exports.array(external_exports.object({ entryKeys: external_exports.array(key2).min(1), change: LessonChangeSchema2 }).strict()),
14513
+ next: BrainNextSchema2,
14514
+ search: BrainSearchSchema2.optional()
14515
+ }).strict();
14516
+ var str2 = external_exports.string();
14517
+ var strs2 = external_exports.array(external_exports.string());
14518
+ var CompactResultSchema2 = external_exports.object({
14519
+ next: external_exports.object({ say: strs2, then: external_exports.enum(["listen", "hold", "end", "none"]), waitFor: strs2, reason: str2, instructions: strs2 }).strict(),
14520
+ messages: external_exports.array(external_exports.object({ key: str2, to: str2, text: str2, about: strs2, entries: strs2, owed: strs2, inviteToCall: external_exports.boolean() }).strict()),
14521
+ entries: external_exports.array(external_exports.object({ key: str2, from: str2, on: strs2 }).strict()),
14522
+ answers: external_exports.array(external_exports.object({ question: str2, entries: strs2, summary: str2, picked: strs2 }).strict()),
14523
+ changes: external_exports.array(external_exports.object({
14524
+ key: str2,
14525
+ what: external_exports.enum(["goal", "question", "lesson"]),
14526
+ op: external_exports.enum(["create", "edit", "assign", "open", "complete", "cancel", "defer", "move", "block", "unblock", "withdraw", "remember", "revise"]),
14527
+ id: str2,
14528
+ text: str2,
14529
+ title: str2,
14530
+ who: str2,
14531
+ under: str2,
14532
+ gate: external_exports.enum(["start", "complete", "answer", "none"]),
14533
+ options: external_exports.array(external_exports.object({ id: str2, label: str2 }).strict()),
14534
+ pick: external_exports.enum(["one", "many", "rank", "words"]),
14535
+ entries: strs2
14536
+ }).strict()),
14537
+ feedback: external_exports.array(strs2),
14538
+ search: external_exports.object({ query: str2, within: strs2, goal: str2 }).strict()
14539
+ }).strict();
14540
+ var COMPACT_RESULT_JSON_SCHEMA2 = (({ $schema: _, ...rest }) => rest)(
14541
+ zodToJsonSchema2(CompactResultSchema2, { $refStrategy: "none" })
14542
+ );
14229
14543
  function entryWords(entry) {
14230
14544
  const content = entry.content;
14231
14545
  if (content && "sealed" in content) return "";
@@ -14238,6 +14552,8 @@ function entryWords(entry) {
14238
14552
  const description = plain.description;
14239
14553
  const parts = [title, ...Array.isArray(description) ? description : []].filter((v) => typeof v === "string");
14240
14554
  if (parts.length) return parts.join("\n\n");
14555
+ const line = plain.line;
14556
+ if (typeof line === "string" && line.trim()) return line;
14241
14557
  }
14242
14558
  return entry.sources.map((source) => source.text).join("\n");
14243
14559
  }
@@ -14460,7 +14776,7 @@ var IntentSchema2 = external_exports.object({
14460
14776
  * (`parseDelay`, #1292), and a value here simply wins over that reading. */
14461
14777
  dueInSeconds: external_exports.number().int().positive().optional(),
14462
14778
  /** 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
14779
+ * already read the utterance, so `signals.kind` stops defaulting to
14464
14780
  * 'other' on every row. A table that records that something was wrong and nothing
14465
14781
  * about what cannot answer "is the bot looping less this week?". */
14466
14782
  fault: external_exports.enum(["loop", "unanswered", "overridden", "misheard", "slow", "other"]).optional()
@@ -14744,7 +15060,18 @@ var InboxItemSchema2 = external_exports.object({
14744
15060
  /** THAT GOAL'S NAME (#2416) — what Activity's row is headed by, since a row there is one Goal
14745
15061
  * and the cards it holds sit behind it. Stamped by the same read as `goalState`. */
14746
15062
  goalTitle: external_exports.string().optional()
14747
- }).optional()
15063
+ }).optional(),
15064
+ /** WHAT THIS CARD IS, IN TWELVE CHARACTERS (#3019) — the hash of every other field on it, stamped
15065
+ * by the one read that serves the open list (`apps/api/src/inbox/project.ts` `inboxFor`). It is
15066
+ * how the incremental read knows a card has not moved: the phone echoes back the revs it holds
15067
+ * (`POST /api/inbox/changes`) and is sent only the cards whose rev differs.
15068
+ *
15069
+ * THE PAYLOAD'S OWN HASH, NEVER A STAMP ON THE WORK — the same mechanism as `QueueItem.rev`
15070
+ * (#2928) and an entry's (#3018), for the same reason: a card shows facts no `updated_at` of its
15071
+ * own moves (its Goal's state and name, how cold the work behind it has gone, whether a ring is
15072
+ * live). Optional, so a fixture, the demo and the archive lens need not spell one, and a card
15073
+ * with no rev is simply always re-sent. */
15074
+ rev: external_exports.string().optional()
14748
15075
  });
14749
15076
  var APNS_TOKEN_RE2 = /^[0-9a-fA-F]{64}$/;
14750
15077
  var PushTokenSchema2 = external_exports.object({
@@ -14956,39 +15283,22 @@ var ReassignResultSchema2 = external_exports.object({
14956
15283
  moved: external_exports.object({ asks: external_exports.number(), answered: external_exports.number(), requests: external_exports.number(), goals: external_exports.number(), callbacks: external_exports.number() }),
14957
15284
  parentId: external_exports.string().nullable()
14958
15285
  });
14959
- var MoveRingSchema2 = external_exports.enum(["home", "travels", "retired", "quarantined"]);
14960
- var MoveSchema2 = external_exports.object({
15286
+ var LessonStateSchema2 = external_exports.enum(["active", "proposed", "retired"]);
15287
+ var LessonViewSchema2 = external_exports.object({
14961
15288
  id: external_exports.string(),
14962
- /** The reusable question, as distill normalized it. */
14963
- question: external_exports.string(),
14964
- /** The operative ruling. Editable by the user (PATCH) — which resets the ledger. */
14965
- answer: external_exports.string(),
14966
- /** The user's stated reason, when they gave one. Null = inherently narrow: the judge is
14967
- * told so, and the ruling only derives essentially the same question in the same scope. */
14968
- rationale: external_exports.string().nullable(),
14969
- /** Where the ruling lives: a repo/workspace, or 'global'. */
14970
- scope: external_exports.string(),
14971
- ring: MoveRingSchema2,
14972
- /** True = the user pinned it with `always` (travel granted by hand, not by evidence). */
15289
+ text: external_exports.string(),
15290
+ state: LessonStateSchema2,
15291
+ /** The Goal it is scoped to; null = the whole account. */
15292
+ scopeGoalId: external_exports.string().nullable(),
15293
+ goalTitle: external_exports.string().nullable(),
15294
+ version: external_exports.number(),
14973
15295
  pinned: external_exports.boolean(),
14974
- /** True = a pin the user placed was BROKEN by later counter-evidence. Surfaced so the
14975
- * break is visible instead of a pin silently disappearing. */
14976
- pinBroken: external_exports.boolean(),
14977
- /** When the ruling was distilled. */
14978
- learnedAt: external_exports.string(),
14979
- /** Last time it answered an ask. Null = never fired. */
14980
- lastUsedAt: external_exports.string().nullable(),
14981
- /** How many asks it has answered. Instrumentation — deliberately NOT an input to the
14982
- * evidence curve: firing says the question keeps arising, not that the ruling is right. */
14983
- usedCount: external_exports.number(),
14984
- /** Ledger: outcomes that said it held up. Saturating — the tenth is worth almost nothing. */
14985
- confirms: external_exports.number(),
14986
- /** Ledger: contradictions, in signal units (a full override = 1, weaker signals less).
14987
- * Linear and priced above the entire confirmation budget, so any full counter wins. */
14988
- counters: external_exports.number(),
14989
- /** The agent that asked the question this move came from, when known. Null for a move
14990
- * distilled from a clarify ruling (those carry no agent) or one whose source rows are gone. */
14991
- learnedFrom: external_exports.object({ id: external_exports.string(), name: external_exports.string() }).nullable()
15296
+ /** When the person last wrote its text themselves. */
15297
+ editedAt: external_exports.string().nullable(),
15298
+ createdAt: external_exports.string(),
15299
+ updatedAt: external_exports.string(),
15300
+ /** The Entries it came from, oldest first; `words` is null when an Entry has none to show (sealed). */
15301
+ sources: external_exports.array(external_exports.object({ entryId: external_exports.string(), words: external_exports.string().nullable(), at: external_exports.string() }))
14992
15302
  });
14993
15303
  var QueueQuestionSchema2 = external_exports.object({
14994
15304
  /** The decision need's id — what an answer is accepted against. */
@@ -15116,7 +15426,22 @@ var QueueItemSchema2 = external_exports.object({
15116
15426
  * minute after the person speaks erases their instant from it, and the durable traces the client
15117
15427
  * can see (`replies`, `questions[].answeredAt`) miss a spontaneous note entirely — a `request`
15118
15428
  * Entry with no `about_id` is in neither. */
15119
- lastPersonAt: external_exports.string().nullable().optional()
15429
+ lastPersonAt: external_exports.string().nullable().optional(),
15430
+ /** WHAT THIS ROW IS, IN TWELVE CHARACTERS (#2928) — the hash of every other field on it, stamped
15431
+ * by the one projection that builds the row (`apps/api/src/goal/queue.ts`). It is how the
15432
+ * incremental read knows a row has not moved: the phone echoes back the revs it holds
15433
+ * (`POST /api/goals/changes`) and is sent only the rows whose rev differs.
15434
+ *
15435
+ * IT IS THE PAYLOAD'S OWN HASH, NEVER A STAMP ON THE WORK. Nothing here reasons about which
15436
+ * writes change which field — the comparison is over the bytes the phone is holding, so a fact
15437
+ * the row shows that no `updated_at` moves for (a lease lapsing, a dependency's state, a
15438
+ * sibling appearing in `childGoalIds`) cannot go unnoticed. Optional because a hand-built
15439
+ * queue (a fixture, the demo) spells none, and a row with no rev is simply always re-sent. */
15440
+ rev: external_exports.string().optional()
15441
+ });
15442
+ var QueueDeltaSchema2 = external_exports.object({
15443
+ ids: external_exports.array(external_exports.string()),
15444
+ items: external_exports.array(QueueItemSchema2)
15120
15445
  });
15121
15446
  var COLD_AFTER_MS2 = 3 * 24 * 60 * 60 * 1e3;
15122
15447
  var NoteSourceSchema2 = external_exports.enum(["app", "call"]);
@@ -15287,6 +15612,11 @@ var DeviceTokenSchema2 = external_exports.object({
15287
15612
  /** Local host recovery must preserve the launch's runtime and Paigy identity. */
15288
15613
  harness: external_exports.enum(["claude", "codex", "agy"]).optional(),
15289
15614
  session_id: external_exports.string().uuid().optional(),
15615
+ /** A conversation the host must not resume: its context is full, so every turn fails
15616
+ * ("Prompt is too long"). Written when a run hits it (`run.ts` `onFull`); the host skips a slot
15617
+ * whose resumable session is this one, so its Goals reach the dead-agent handoff instead of a
15618
+ * copy that types the person's words into a turn that cannot run (Calls, 2026-10-06). */
15619
+ full_session: external_exports.string().optional(),
15290
15620
  uik_pub: external_exports.string().nullable().optional()
15291
15621
  });
15292
15622
  var SupportRequestSchema2 = external_exports.object({
@@ -15532,10 +15862,10 @@ var AcpDriver = class {
15532
15862
  return this.flush();
15533
15863
  }
15534
15864
  /** 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);
15865
+ respond(id3, decision) {
15866
+ const request = this.pending.get(id3);
15537
15867
  if (!request) return [];
15538
- this.pending.delete(id);
15868
+ this.pending.delete(id3);
15539
15869
  const optionId = optionFor(request.options, decision);
15540
15870
  return [
15541
15871
  optionId ? frame2({ id: request.id, result: { outcome: { outcome: "selected", optionId } } }) : frame2({ id: request.id, result: { outcome: { outcome: "cancelled" } } })
@@ -15689,7 +16019,7 @@ var AcpDriver = class {
15689
16019
  writes: [frame2({ id: msg.id, error: { code: -32601, message: `Method not found: ${msg.method}` } })]
15690
16020
  };
15691
16021
  }
15692
- const id = msg.id;
16022
+ const id3 = msg.id;
15693
16023
  const options = msg.params?.options ?? [];
15694
16024
  const title = msg.params?.toolCall?.title?.trim() || "a tool call";
15695
16025
  const tool = msg.params?.toolCall?.kind ?? "tool";
@@ -15700,21 +16030,21 @@ var AcpDriver = class {
15700
16030
  // means "don't stall the agent", never "don't tell the user".
15701
16031
  events: [{ kind: "turn", role: "agent", text: `auto-approved: ${title}`, tools: [tool] }],
15702
16032
  writes: [
15703
- optionId ? frame2({ id, result: { outcome: { outcome: "selected", optionId } } }) : frame2({ id, result: { outcome: { outcome: "cancelled" } } })
16033
+ optionId ? frame2({ id: id3, result: { outcome: { outcome: "selected", optionId } } }) : frame2({ id: id3, result: { outcome: { outcome: "cancelled" } } })
15704
16034
  ]
15705
16035
  };
15706
16036
  }
15707
- this.pending.set(String(id), { id, options });
16037
+ this.pending.set(String(id3), { id: id3, options });
15708
16038
  return {
15709
- events: [{ kind: "permission", id: String(id), tool, summary: title }],
16039
+ events: [{ kind: "permission", id: String(id3), tool, summary: title }],
15710
16040
  writes: []
15711
16041
  };
15712
16042
  }
15713
16043
  /** The frame that opens the conversation: a resume of `resume` while there is one to try,
15714
16044
  * else a new session. */
15715
- opening(id) {
16045
+ opening(id3) {
15716
16046
  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 };
16047
+ return this.resume ? { id: id3, method: "session/resume", params: { sessionId: this.resume, ...params } } : { id: id3, method: "session/new", params };
15718
16048
  }
15719
16049
  /** Send the queued prompts as one turn, if the agent can take one right now. */
15720
16050
  flush() {
@@ -15832,7 +16162,7 @@ function startSession(opts) {
15832
16162
  }
15833
16163
  const codexConfig = opts.harness === "codex" ? JSON.parse(process.env.CODEX_CONFIG || "{}") : null;
15834
16164
  if (codexConfig) {
15835
- const key = "mcp_servers.paigy.env_vars";
16165
+ const key3 = "mcp_servers.paigy.env_vars";
15836
16166
  const configPath = join9(process.env.CODEX_HOME || join9(homedir9(), ".codex"), "config.toml");
15837
16167
  const saved = existsSync4(configPath) ? readFileSync5(configPath, "utf8") : "";
15838
16168
  const registered = /\[mcp_servers\.paigy\][\s\S]*?(?=\n\[|$)/.exec(saved)?.[0];
@@ -15843,7 +16173,7 @@ function startSession(opts) {
15843
16173
  }
15844
16174
  const savedVars = registered?.match(/env_vars\s*=\s*\[([\s\S]*?)\]/)?.[1] ?? "";
15845
16175
  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])];
16176
+ codexConfig[key3] = [.../* @__PURE__ */ new Set([...inherited, ...codexConfig[key3] ?? codexConfig.mcp_servers?.paigy?.env_vars ?? [], ...CODEX_ENV])];
15847
16177
  }
15848
16178
  const child = (opts.spawnFn ?? spawn)(opts.bin ?? ADAPTER_BIN[opts.harness], [], {
15849
16179
  cwd,
@@ -15919,8 +16249,8 @@ function startSession(opts) {
15919
16249
  send(text) {
15920
16250
  write(driver.send(text));
15921
16251
  },
15922
- respond(id, decision) {
15923
- write(driver.respond(id, decision));
16252
+ respond(id3, decision) {
16253
+ write(driver.respond(id3, decision));
15924
16254
  },
15925
16255
  stop() {
15926
16256
  write(driver.close());
@@ -16140,17 +16470,31 @@ async function finish(result, state, rail, opts) {
16140
16470
  }
16141
16471
  async function cannotWork(report, state, rail, opts) {
16142
16472
  state.resting = true;
16473
+ const say = (parentId) => rail.contact({ asks: [{ ask: report, ...parentId ? { parentId } : {} }], waiting: "none", channel: "notification" });
16143
16474
  try {
16144
16475
  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 };
16476
+ const claimed = await rail.claim().catch(() => void 0);
16477
+ if (claimed?.goalId && claimed.revision !== void 0) state.goal = { id: claimed.goalId, revision: claimed.revision };
16478
+ }
16479
+ if (!state.goal) {
16480
+ await say();
16481
+ return;
16482
+ }
16483
+ try {
16484
+ await say(state.goal.id);
16485
+ } catch (error) {
16486
+ if (!/goal_parent_invalid/.test(error.message)) throw error;
16487
+ opts?.log?.(`\u26A0 the held Goal ${state.goal.id.slice(0, 8)} refused the notice (goal_parent_invalid) \u2014 saying it unplaced`);
16488
+ await say();
16148
16489
  }
16149
- await rail.contact({ asks: [{ ask: report, parentId: state.goal.id }], waiting: "none", channel: "notification" });
16150
16490
  } catch (error) {
16151
16491
  opts?.log?.(`\u26A0 could not say the agent cannot work: ${error.message}`);
16152
16492
  }
16153
16493
  }
16494
+ function conversationFull(result) {
16495
+ return /prompt is too long/i.test(result ?? "");
16496
+ }
16497
+ 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
16498
  async function afterTurn(event, state, rail, opts) {
16155
16499
  if (event.failed) {
16156
16500
  const limit = limitIn(event.result, (opts?.now ?? Date.now)());
@@ -16163,6 +16507,11 @@ async function afterTurn(event, state, rail, opts) {
16163
16507
  opts?.log?.(`\u23F8 paused by the usage limit until ${limit.resets}: nothing is typed in until then, and it carries on by itself`);
16164
16508
  return limit;
16165
16509
  }
16510
+ if (conversationFull(event.result)) {
16511
+ if (!state.full) await cannotWork(FULL_NOTICE, state, rail, opts);
16512
+ state.full = true;
16513
+ return void 0;
16514
+ }
16166
16515
  await cannotWork(`The agent stopped without finishing.
16167
16516
 
16168
16517
  ${event.result?.trim() || "No result reported."}`, state, rail, opts);
@@ -16232,9 +16581,9 @@ function unheard(brief, state, since = null, after = -1, reviewSince) {
16232
16581
  if (text) words2.push(text);
16233
16582
  }
16234
16583
  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);
16584
+ const key3 = `answer:${answer.decisionNeedId}`;
16585
+ if (seen.has(key3) || Date.parse(answer.acceptedAt) < pendingAt) continue;
16586
+ seen.add(key3);
16238
16587
  words2.push(`Answer to question ${answer.decisionNeedId}: ${JSON.stringify(answer.result)}`);
16239
16588
  }
16240
16589
  return words2;
@@ -16279,16 +16628,16 @@ async function gather(state, rail, held) {
16279
16628
  const listed = /* @__PURE__ */ new Set();
16280
16629
  const announced = state.announced ??= /* @__PURE__ */ new Set();
16281
16630
  if (waiting) {
16282
- for (const id of announced) if (!(waiting.assigned ?? []).some((g) => g.goalId === id)) announced.delete(id);
16631
+ for (const id3 of announced) if (!(waiting.assigned ?? []).some((g) => g.goalId === id3)) announced.delete(id3);
16283
16632
  }
16284
16633
  for (const g of waiting?.assigned ?? []) if (g.goalId !== state.goal.id && !announced.has(g.goalId)) look2(g.goalId, "assigned", g.title);
16285
16634
  for (const g of waiting?.review ?? []) {
16286
16635
  listed.add(g.goalId);
16287
16636
  look2(g.goalId, "waiting work", g.title);
16288
16637
  }
16289
- for (const d of waiting?.deliveries ?? []) for (const id of d.goalIds) {
16290
- listed.add(id);
16291
- look2(id, "waiting work");
16638
+ for (const d of waiting?.deliveries ?? []) for (const id3 of d.goalIds) {
16639
+ listed.add(id3);
16640
+ look2(id3, "waiting work");
16292
16641
  }
16293
16642
  const moved = movedBelow(held, state);
16294
16643
  for (const { goal, since } of moved) look2(goal.goalId, "subtree", goal.title, since);
@@ -16326,7 +16675,7 @@ var block = (h) => [
16326
16675
  ...h.note ? [`The last note on it, from the agent before you: ${h.note}`] : [],
16327
16676
  ...h.words
16328
16677
  ].join("\n\n");
16329
- var short = (ids) => ids.map((id) => id.slice(0, 8)).join(", ");
16678
+ var short = (ids) => ids.map((id3) => id3.slice(0, 8)).join(", ");
16330
16679
  var given = (heard) => heard.filter((h) => h.via === "assigned").map((h) => h.goalId);
16331
16680
  async function hear(session, state, rail, held, opts) {
16332
16681
  const log2 = opts?.log;
@@ -16590,7 +16939,12 @@ ${event.message}`, state, rail, { log: opts.log });
16590
16939
  tail = [];
16591
16940
  const carried = state.carriedOn && !event.failed;
16592
16941
  if (await afterTurn(event, state, rail, { log: opts.log })) LIMITS.paused(name, Date.now());
16593
- else if (carried) runningAgain();
16942
+ else if (state.full) {
16943
+ opts.log(`\u25A0 ${name}'s conversation is full \u2014 ending this run; it will not be resumed`);
16944
+ opts.onFull?.(speaksAs);
16945
+ stop2();
16946
+ return;
16947
+ } else if (carried) runningAgain();
16594
16948
  clock4.nudge("rest");
16595
16949
  }
16596
16950
  }
@@ -16751,26 +17105,33 @@ var claimedRun = (sessionId2) => {
16751
17105
  return { slot, key: runKey(slot) };
16752
17106
  };
16753
17107
  var launchRun = (spec) => ({ session: spec.sessionId });
17108
+ var BOUND_ELSEWHERE_MS = 10 * 6e4;
17109
+ var boundElsewhere = /* @__PURE__ */ new Map();
17110
+ 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
17111
  var NOTHING_WAITING = "has nothing waiting";
16755
17112
  async function waitingWork(token, session) {
17113
+ const quiet = boundElsewhere.get(token);
17114
+ if (quiet !== void 0 && Date.now() < quiet) return { skip: BOUND_SKIP };
16756
17115
  let found;
16757
17116
  try {
16758
17117
  found = await checkReplies({ token, ...session ? { reach: reachAs(session) } : {} });
16759
17118
  } catch (error) {
16760
17119
  if (error instanceof RevokedError) return { skip: "was revoked: its credential is gone for good", revoked: true };
16761
17120
  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" };
17121
+ boundElsewhere.set(token, Date.now() + BOUND_ELSEWHERE_MS);
17122
+ return { skip: BOUND_SKIP };
16763
17123
  }
16764
17124
  return { skip: `could not read what is waiting (${error.message})` };
16765
17125
  }
17126
+ boundElsewhere.delete(token);
16766
17127
  const next = found.claimable;
16767
17128
  const about = next ? { goalId: next.goalId, ...next.since ? { since: next.since } : {} } : {};
16768
17129
  const n = found.deliveries.length;
16769
17130
  if (n) return { waiting: n === 1 ? "a message" : `${n} messages`, ...about };
16770
17131
  return next ? { waiting: `Goal ${next.goalId.slice(0, 8)}${next.title ? ` "${next.title}"` : ""}`, ...about } : { skip: NOTHING_WAITING };
16771
17132
  }
16772
- function evict(runs, key, run) {
16773
- if (runs.get(key)?.run === run) runs.delete(key);
17133
+ function evict(runs, key3, run) {
17134
+ if (runs.get(key3)?.run === run) runs.delete(key3);
16774
17135
  }
16775
17136
  var PRESENCE_FRESH_MS = 3 * 6e4;
16776
17137
  var IDLE_HOLDER_MS = 30 * 6e4;
@@ -16813,9 +17174,9 @@ function startHost(opts) {
16813
17174
  const agent2 = slotIdentity(slot).tokenId;
16814
17175
  if (!agent2) return;
16815
17176
  const goalId = found?.goalId;
16816
- const key = `${decision}:${goalId ?? ""}`;
16817
- if (recorded.get(slot) === key) return;
16818
- recorded.set(slot, key);
17177
+ const key3 = `${decision}:${goalId ?? ""}`;
17178
+ if (recorded.get(slot) === key3) return;
17179
+ recorded.set(slot, key3);
16819
17180
  void recordDecision({
16820
17181
  agent: agent2,
16821
17182
  decision,
@@ -16865,7 +17226,7 @@ function startHost(opts) {
16865
17226
  const specs = await claimSessions(asHost).catch(() => []);
16866
17227
  for (const spec of specs) {
16867
17228
  const label = spec.name ?? spec.harness;
16868
- const { slot, key } = claimedRun(spec.sessionId);
17229
+ const { slot, key: key3 } = claimedRun(spec.sessionId);
16869
17230
  const log2 = (line) => opts.log(`[${label}] ${line}`);
16870
17231
  try {
16871
17232
  saveToken({
@@ -16888,14 +17249,17 @@ function startHost(opts) {
16888
17249
  token: spec.token,
16889
17250
  ...launchRun(spec),
16890
17251
  onExit: () => {
16891
- evict(runs, key, run);
17252
+ evict(runs, key3, run);
16892
17253
  goneAt.set(slot, Date.now());
16893
17254
  opts.log(`\u2716 ${label} ended`);
16894
17255
  },
17256
+ onFull: (session) => {
17257
+ updateSlot(slot, { full_session: session });
17258
+ },
16895
17259
  name: label,
16896
17260
  log: log2
16897
17261
  });
16898
- runs.set(key, { run, label, token: spec.token });
17262
+ runs.set(key3, { run, label, token: spec.token });
16899
17263
  void heartbeat(void 0, { token: spec.token }).catch(() => {
16900
17264
  });
16901
17265
  void refreshIdentities();
@@ -16947,9 +17311,9 @@ function startHost(opts) {
16947
17311
  let lastHolders = /* @__PURE__ */ new Map();
16948
17312
  async function wakeSlot(slot, { presence, holders }, cause = "sweep") {
16949
17313
  {
16950
- const key = runKey(slot);
17314
+ const key3 = runKey(slot);
16951
17315
  if (slot === "Desktop" || isRevoked(slot)) return;
16952
- const live = runs.get(key);
17316
+ const live = runs.get(key3);
16953
17317
  if (live) {
16954
17318
  const theirs = (localHolderPids().get(slot) ?? []).map((p) => p.pid).filter((pid) => !descendsFrom(pid, process.pid));
16955
17319
  if (theirs.length) {
@@ -16984,6 +17348,11 @@ function startHost(opts) {
16984
17348
  }
16985
17349
  const identity = slotIdentity(slot);
16986
17350
  const owner = !identity.harness || identity.harness === "claude" ? ownerSession(slot) : null;
17351
+ const resumes = owner?.sessionId ?? identity.sessionId;
17352
+ if (resumes && identity.fullSession === resumes) {
17353
+ skip(`has a full conversation (${resumes.slice(0, 8)}) \u2014 not resuming it; its Goals go to the dead-agent handoff`);
17354
+ return;
17355
+ }
16987
17356
  const read = async () => {
16988
17357
  const got = await waitingWork(token, identity.sessionId ?? owner?.sessionId);
16989
17358
  if (!("skip" in got)) return got;
@@ -17024,7 +17393,7 @@ function startHost(opts) {
17024
17393
  }
17025
17394
  found ??= await read() ?? void 0;
17026
17395
  if (!found) return;
17027
- if (runs.has(key)) {
17396
+ if (runs.has(key3)) {
17028
17397
  skip("was started by the wake that read it first");
17029
17398
  return;
17030
17399
  }
@@ -17040,14 +17409,17 @@ function startHost(opts) {
17040
17409
  // A dead run must not squat the slot — evict so the next wake can respawn. Only ITS entry:
17041
17410
  // a run that is no longer the slot's must not take the live one's place away with it.
17042
17411
  onExit: () => {
17043
- evict(runs, key, run);
17412
+ evict(runs, key3, run);
17044
17413
  goneAt.set(slot, Date.now());
17045
17414
  opts.log(`\u2716 ${label} ended`);
17046
17415
  },
17416
+ onFull: (session) => {
17417
+ updateSlot(slot, { full_session: session });
17418
+ },
17047
17419
  name: label,
17048
17420
  log: log2
17049
17421
  });
17050
- runs.set(key, { run, label, token });
17422
+ runs.set(key3, { run, label, token });
17051
17423
  void heartbeat(void 0, { token }).catch(() => {
17052
17424
  });
17053
17425
  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 +17472,17 @@ function startHost(opts) {
17100
17472
  void heartbeat(void 0, { token, activity: { lines: lines2, at: (/* @__PURE__ */ new Date()).toISOString() } }).catch(() => {
17101
17473
  });
17102
17474
  };
17103
- for (const [key, r] of runs) {
17475
+ for (const [key3, r] of runs) {
17104
17476
  if (!r.token) continue;
17105
17477
  const lines2 = r.run.tail();
17106
- const was = published.get(key);
17478
+ const was = published.get(key3);
17107
17479
  if (was && sameTail(was.lines, lines2)) continue;
17108
- published.set(key, { token: r.token, lines: lines2 });
17480
+ published.set(key3, { token: r.token, lines: lines2 });
17109
17481
  publishTail(r.token, lines2);
17110
17482
  }
17111
- for (const [key, was] of published) {
17112
- if (runs.has(key)) continue;
17113
- published.delete(key);
17483
+ for (const [key3, was] of published) {
17484
+ if (runs.has(key3)) continue;
17485
+ published.delete(key3);
17114
17486
  if (was.lines.length > 0) publishTail(was.token, []);
17115
17487
  }
17116
17488
  };
@@ -17141,25 +17513,25 @@ function startHost(opts) {
17141
17513
  })));
17142
17514
  };
17143
17515
  const api = {
17144
- sessions: () => [...runs.entries()].map(([id, r]) => [id, r.label]),
17516
+ sessions: () => [...runs.entries()].map(([id3, r]) => [id3, r.label]),
17145
17517
  // Every identity this machine holds, plus what it's doing right now. Slots are the
17146
17518
  // roster (hatched agents, the terminal tools, claimed sessions); a run makes one of
17147
17519
  // them live, and a run mid-turn makes it working.
17148
17520
  roster: () => {
17149
17521
  const live = new Map([...runs.values()].map((r) => [r.label, r.run]));
17150
17522
  const names2 = /* @__PURE__ */ new Map();
17151
- for (const key of listSlots()) if (key !== "Desktop" && !isRevoked(key)) names2.set(slotName(key) ?? key, key);
17523
+ for (const key3 of listSlots()) if (key3 !== "Desktop" && !isRevoked(key3)) names2.set(slotName(key3) ?? key3, key3);
17152
17524
  for (const label of live.keys()) if (!names2.has(label)) names2.set(label, null);
17153
17525
  return [...names2.entries()].map(([name, slot]) => {
17154
- const id = slot ? slotIdentity(slot) : { voice: null, tokenId: null };
17526
+ const id3 = slot ? slotIdentity(slot) : { voice: null, tokenId: null };
17155
17527
  return {
17156
17528
  name,
17157
17529
  // The slot key rides along so the window's agent page can speak AS this agent —
17158
17530
  // its pending reads (`checkReplies`, the same pure read the sweep does) need the
17159
17531
  // slot's own token, and the display name is not a key.
17160
17532
  slot,
17161
- tokenId: id.tokenId,
17162
- voice: id.voice,
17533
+ tokenId: id3.tokenId,
17534
+ voice: id3.voice,
17163
17535
  // RUNNING IS ABOUT THE IDENTITY, NOT ABOUT US (owner, 2026-09-14). This was
17164
17536
  // `live.has(name)` — "this host spawned it and it has not exited" — which is a fact
17165
17537
  // about our own process table, not about the agent. An ordinary terminal session
@@ -17167,7 +17539,7 @@ function startHost(opts) {
17167
17539
  // sessions we started ourselves. The server already knows: `last_seen_at` on the
17168
17540
  // agent's own token, the same evidence `wakeAction` stands back for. So: a run we
17169
17541
  // 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,
17542
+ running: live.has(name) || !!slot && lastHolders.has(slot) || !!id3.tokenId && Date.now() - (lastPresence.get(id3.tokenId) ?? 0) < PRESENCE_FRESH_MS,
17171
17543
  // `working` stays ours alone — it means a run WE hold is mid-turn, which is the only
17172
17544
  // thing a tail can tell us. A process we did not spawn has no tail here to read.
17173
17545
  working: live.get(name)?.working() ?? false
@@ -17349,11 +17721,11 @@ ipcMain.handle("paigy:triage-accept", async (_e, opts) => {
17349
17721
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
17350
17722
  }
17351
17723
  });
17352
- ipcMain.handle("paigy:triage-dismiss", async (_e, id) => {
17724
+ ipcMain.handle("paigy:triage-dismiss", async (_e, id3) => {
17353
17725
  const token = deviceToken();
17354
17726
  if (!token) return { ok: false, error: "This Mac isn't paired yet." };
17355
17727
  try {
17356
- await dismissTriage(id, { token });
17728
+ await dismissTriage(id3, { token });
17357
17729
  return { ok: true };
17358
17730
  } catch (e) {
17359
17731
  return { ok: false, error: e instanceof Error ? e.message : String(e) };