@graphrefly/graphrefly 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-NULSP7U4.js → chunk-2ZICUAUJ.js} +4 -4
  3. package/dist/{chunk-BRPCN2HJ.js → chunk-4APC3AFN.js} +3 -3
  4. package/dist/{chunk-VQWLA6XQ.js → chunk-CRACCCJY.js} +3 -3
  5. package/dist/{chunk-JYRHO63K.js → chunk-GKRKDYNT.js} +17 -17
  6. package/dist/chunk-GKRKDYNT.js.map +1 -0
  7. package/dist/{chunk-4F2ZFD5L.js → chunk-H243FWYP.js} +50 -51
  8. package/dist/chunk-H243FWYP.js.map +1 -0
  9. package/dist/{chunk-X732W3QA.js → chunk-QVYZD65U.js} +2 -2
  10. package/dist/{chunk-6OLNYOGU.js → chunk-XQ4UMAU7.js} +2 -2
  11. package/dist/{chunk-XWMTVV2D.js → chunk-YW6LFCFS.js} +5 -5
  12. package/dist/{chunk-IXTW3BIO.js → chunk-ZHTHUX5D.js} +3 -3
  13. package/dist/compat/nestjs/index.cjs +48 -49
  14. package/dist/compat/nestjs/index.cjs.map +1 -1
  15. package/dist/compat/nestjs/index.d.cts +4 -4
  16. package/dist/compat/nestjs/index.d.ts +4 -4
  17. package/dist/compat/nestjs/index.js +7 -7
  18. package/dist/core/index.cjs +50 -51
  19. package/dist/core/index.cjs.map +1 -1
  20. package/dist/core/index.d.cts +2 -2
  21. package/dist/core/index.d.ts +2 -2
  22. package/dist/core/index.js +5 -5
  23. package/dist/extra/index.cjs +48 -49
  24. package/dist/extra/index.cjs.map +1 -1
  25. package/dist/extra/index.d.cts +4 -4
  26. package/dist/extra/index.d.ts +4 -4
  27. package/dist/extra/index.js +3 -3
  28. package/dist/graph/index.cjs +40 -37
  29. package/dist/graph/index.cjs.map +1 -1
  30. package/dist/graph/index.d.cts +3 -3
  31. package/dist/graph/index.d.ts +3 -3
  32. package/dist/graph/index.js +4 -4
  33. package/dist/{graph-DXT95WZ3.d.ts → graph-BXIK5Dq5.d.ts} +1 -1
  34. package/dist/{graph-BE10ujU9.d.cts → graph-BhADtuFU.d.cts} +1 -1
  35. package/dist/{index-QfbXNW1N.d.cts → index-BNB0KjKe.d.ts} +24 -21
  36. package/dist/{index-C0_7g9sj.d.ts → index-BkToATim.d.ts} +1 -1
  37. package/dist/{index-CiAqgfFg.d.ts → index-CKyYg4IP.d.ts} +3 -3
  38. package/dist/{index-CCvzN5GB.d.cts → index-DANO9Gg7.d.cts} +2 -2
  39. package/dist/{index-CthwPnHQ.d.cts → index-DBhLjWSV.d.cts} +3 -3
  40. package/dist/{index-Dzdm20sx.d.ts → index-DKIyo4Bq.d.cts} +24 -21
  41. package/dist/{index-53cDGX7F.d.ts → index-DSp5R3Xq.d.ts} +3 -3
  42. package/dist/{index-aBZ2RoP0.d.cts → index-Dqemj9q0.d.cts} +3 -3
  43. package/dist/{index-nRulwTr-.d.cts → index-Wa8jXne6.d.cts} +1 -1
  44. package/dist/{index-B10Q0sQB.d.ts → index-fYObbpUw.d.ts} +2 -2
  45. package/dist/index.cjs +443 -68
  46. package/dist/index.cjs.map +1 -1
  47. package/dist/index.d.cts +369 -66
  48. package/dist/index.d.ts +369 -66
  49. package/dist/index.js +397 -22
  50. package/dist/index.js.map +1 -1
  51. package/dist/{meta-BcuDhtwu.d.cts → meta-CrZUQAJ6.d.cts} +1 -1
  52. package/dist/{meta-BcuDhtwu.d.ts → meta-CrZUQAJ6.d.ts} +1 -1
  53. package/dist/patterns/reactive-layout/index.cjs +53 -50
  54. package/dist/patterns/reactive-layout/index.cjs.map +1 -1
  55. package/dist/patterns/reactive-layout/index.d.cts +3 -3
  56. package/dist/patterns/reactive-layout/index.d.ts +3 -3
  57. package/dist/patterns/reactive-layout/index.js +4 -4
  58. package/dist/{reactive-log-OULQssZg.d.cts → reactive-log-ChbpUrY2.d.cts} +2 -2
  59. package/dist/{reactive-log-Cu0VdqkT.d.ts → reactive-log-DV--7BWd.d.ts} +2 -2
  60. package/package.json +3 -1
  61. package/dist/chunk-4F2ZFD5L.js.map +0 -1
  62. package/dist/chunk-JYRHO63K.js.map +0 -1
  63. /package/dist/{chunk-NULSP7U4.js.map → chunk-2ZICUAUJ.js.map} +0 -0
  64. /package/dist/{chunk-BRPCN2HJ.js.map → chunk-4APC3AFN.js.map} +0 -0
  65. /package/dist/{chunk-VQWLA6XQ.js.map → chunk-CRACCCJY.js.map} +0 -0
  66. /package/dist/{chunk-X732W3QA.js.map → chunk-QVYZD65U.js.map} +0 -0
  67. /package/dist/{chunk-6OLNYOGU.js.map → chunk-XQ4UMAU7.js.map} +0 -0
  68. /package/dist/{chunk-XWMTVV2D.js.map → chunk-YW6LFCFS.js.map} +0 -0
  69. /package/dist/{chunk-IXTW3BIO.js.map → chunk-ZHTHUX5D.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -134,10 +134,10 @@ __export(index_exports, {
134
134
  distill: () => distill,
135
135
  distinctUntilChanged: () => distinctUntilChanged,
136
136
  domainTemplates: () => domain_templates_exports,
137
+ downWithBatch: () => downWithBatch,
137
138
  dynamicNode: () => dynamicNode,
138
139
  effect: () => effect,
139
140
  elementAt: () => elementAt,
140
- emitWithBatch: () => emitWithBatch,
141
141
  empty: () => empty,
142
142
  escapeRegexChar: () => escapeRegexChar,
143
143
  exhaustMap: () => exhaustMap,
@@ -185,6 +185,7 @@ __export(index_exports, {
185
185
  globToRegExp: () => globToRegExp,
186
186
  graph: () => graph_exports,
187
187
  graphspec: () => graphspec_exports,
188
+ harness: () => harness_exports,
188
189
  interval: () => interval,
189
190
  isBatching: () => isBatching,
190
191
  isKnownMessageType: () => isKnownMessageType,
@@ -427,8 +428,7 @@ function drainPending() {
427
428
  if (ownsFlush) {
428
429
  flushInProgress = true;
429
430
  }
430
- let firstError;
431
- let hasError = false;
431
+ const errors = [];
432
432
  try {
433
433
  let iterations = 0;
434
434
  while (pendingPhase2.length > 0 || pendingPhase3.length > 0) {
@@ -446,10 +446,7 @@ function drainPending() {
446
446
  try {
447
447
  run();
448
448
  } catch (e) {
449
- if (!hasError) {
450
- firstError = e;
451
- hasError = true;
452
- }
449
+ errors.push(e);
453
450
  }
454
451
  }
455
452
  }
@@ -467,10 +464,7 @@ function drainPending() {
467
464
  try {
468
465
  run();
469
466
  } catch (e) {
470
- if (!hasError) {
471
- firstError = e;
472
- hasError = true;
473
- }
467
+ errors.push(e);
474
468
  }
475
469
  }
476
470
  }
@@ -480,8 +474,11 @@ function drainPending() {
480
474
  flushInProgress = false;
481
475
  }
482
476
  }
483
- if (hasError) {
484
- throw firstError;
477
+ if (errors.length === 1) {
478
+ throw errors[0];
479
+ }
480
+ if (errors.length > 1) {
481
+ throw new AggregateError(errors, "batch drain: multiple callbacks threw");
485
482
  }
486
483
  }
487
484
  function partitionForBatch(messages) {
@@ -499,12 +496,12 @@ function partitionForBatch(messages) {
499
496
  }
500
497
  return { immediate, deferred, terminal };
501
498
  }
502
- function emitWithBatch(emit, messages, phase = 2, options) {
499
+ function downWithBatch(sink, messages, phase = 2, options) {
503
500
  if (messages.length === 0) {
504
501
  return;
505
502
  }
506
503
  if (options?.strategy === "sequential") {
507
- _emitSequential(emit, messages, phase);
504
+ _downSequential(sink, messages, phase);
508
505
  return;
509
506
  }
510
507
  const queue = phase === 3 ? pendingPhase3 : pendingPhase2;
@@ -512,61 +509,61 @@ function emitWithBatch(emit, messages, phase = 2, options) {
512
509
  const t = messages[0][0];
513
510
  if (t === DATA || t === RESOLVED) {
514
511
  if (isBatching()) {
515
- queue.push(() => emit(messages));
512
+ queue.push(() => sink(messages));
516
513
  } else {
517
- emit(messages);
514
+ sink(messages);
518
515
  }
519
516
  } else if (isTerminalMessage(t)) {
520
517
  if (isBatching()) {
521
- queue.push(() => emit(messages));
518
+ queue.push(() => sink(messages));
522
519
  } else {
523
- emit(messages);
520
+ sink(messages);
524
521
  }
525
522
  } else {
526
- emit(messages);
523
+ sink(messages);
527
524
  }
528
525
  return;
529
526
  }
530
527
  const { immediate, deferred, terminal } = partitionForBatch(messages);
531
528
  if (immediate.length > 0) {
532
- emit(immediate);
529
+ sink(immediate);
533
530
  }
534
531
  if (isBatching()) {
535
532
  if (deferred.length > 0) {
536
- queue.push(() => emit(deferred));
533
+ queue.push(() => sink(deferred));
537
534
  }
538
535
  if (terminal.length > 0) {
539
- queue.push(() => emit(terminal));
536
+ queue.push(() => sink(terminal));
540
537
  }
541
538
  } else {
542
539
  if (deferred.length > 0) {
543
- emit(deferred);
540
+ sink(deferred);
544
541
  }
545
542
  if (terminal.length > 0) {
546
- emit(terminal);
543
+ sink(terminal);
547
544
  }
548
545
  }
549
546
  }
550
- function _emitSequential(emit, messages, phase = 2) {
547
+ function _downSequential(sink, messages, phase = 2) {
551
548
  const dataQueue = phase === 3 ? pendingPhase3 : pendingPhase2;
552
549
  for (const msg of messages) {
553
550
  const tier = messageTier(msg[0]);
554
551
  if (tier === 2) {
555
552
  if (isBatching()) {
556
553
  const m = msg;
557
- dataQueue.push(() => emit([m]));
554
+ dataQueue.push(() => sink([m]));
558
555
  } else {
559
- emit([msg]);
556
+ sink([msg]);
560
557
  }
561
558
  } else if (tier >= 3) {
562
559
  if (isBatching()) {
563
560
  const m = msg;
564
- pendingPhase3.push(() => emit([m]));
561
+ pendingPhase3.push(() => sink([m]));
565
562
  } else {
566
- emit([msg]);
563
+ sink([msg]);
567
564
  }
568
565
  } else {
569
- emit([msg]);
566
+ sink([msg]);
570
567
  }
571
568
  }
572
569
  }
@@ -854,7 +851,7 @@ var NodeImpl = class {
854
851
  _singleDepSinks = /* @__PURE__ */ new WeakSet();
855
852
  _upstreamUnsubs = [];
856
853
  _actions;
857
- _boundEmitToSinks;
854
+ _boundDownToSinks;
858
855
  _inspectorHook;
859
856
  _versioning;
860
857
  _hashFn;
@@ -901,7 +898,7 @@ var NodeImpl = class {
901
898
  },
902
899
  emit(value) {
903
900
  self._manualEmitUsed = true;
904
- self._emitAutoValue(value);
901
+ self._downAutoValue(value);
905
902
  },
906
903
  up(messages) {
907
904
  self._upInternal(messages);
@@ -909,7 +906,7 @@ var NodeImpl = class {
909
906
  };
910
907
  this.down = this.down.bind(this);
911
908
  this.up = this.up.bind(this);
912
- this._boundEmitToSinks = this._emitToSinks.bind(this);
909
+ this._boundDownToSinks = this._downToSinks.bind(this);
913
910
  }
914
911
  get name() {
915
912
  return this._registryName ?? this._optsName;
@@ -1015,12 +1012,12 @@ var NodeImpl = class {
1015
1012
  if (sinkMessages[i][0] !== DIRTY) filtered.push(sinkMessages[i]);
1016
1013
  }
1017
1014
  if (filtered.length > 0) {
1018
- emitWithBatch(this._boundEmitToSinks, filtered);
1015
+ downWithBatch(this._boundDownToSinks, filtered);
1019
1016
  }
1020
1017
  return;
1021
1018
  }
1022
1019
  }
1023
- emitWithBatch(this._boundEmitToSinks, sinkMessages);
1020
+ downWithBatch(this._boundDownToSinks, sinkMessages);
1024
1021
  }
1025
1022
  subscribe(sink, hints) {
1026
1023
  if (hints?.actor != null && this._guard != null) {
@@ -1107,7 +1104,7 @@ var NodeImpl = class {
1107
1104
  this._disconnectUpstream();
1108
1105
  }
1109
1106
  // --- Private methods (prototype, _ prefix) ---
1110
- _emitToSinks(messages) {
1107
+ _downToSinks(messages) {
1111
1108
  if (this._sinks == null) return;
1112
1109
  if (typeof this._sinks === "function") {
1113
1110
  this._sinks(messages);
@@ -1122,6 +1119,9 @@ var NodeImpl = class {
1122
1119
  for (const m of messages) {
1123
1120
  const t = m[0];
1124
1121
  if (t === DATA) {
1122
+ if (m.length < 2) {
1123
+ continue;
1124
+ }
1125
1125
  this._cached = m[1];
1126
1126
  if (this._versioning != null) {
1127
1127
  advanceVersion(this._versioning, m[1], this._hashFn);
@@ -1169,7 +1169,7 @@ var NodeImpl = class {
1169
1169
  _canSkipDirty() {
1170
1170
  return this._sinkCount === 1 && this._singleDepSinkCount === 1;
1171
1171
  }
1172
- _emitAutoValue(value) {
1172
+ _downAutoValue(value) {
1173
1173
  const wasDirty = this._status === "dirty";
1174
1174
  let unchanged;
1175
1175
  try {
@@ -1222,7 +1222,7 @@ var NodeImpl = class {
1222
1222
  this._cleanup = out.cleanup;
1223
1223
  if (this._manualEmitUsed) return;
1224
1224
  if ("value" in out) {
1225
- this._emitAutoValue(out.value);
1225
+ this._downAutoValue(out.value);
1226
1226
  }
1227
1227
  return;
1228
1228
  }
@@ -1232,7 +1232,7 @@ var NodeImpl = class {
1232
1232
  }
1233
1233
  if (this._manualEmitUsed) return;
1234
1234
  if (out === void 0) return;
1235
- this._emitAutoValue(out);
1235
+ this._downAutoValue(out);
1236
1236
  } catch (err) {
1237
1237
  const errMsg = err instanceof Error ? err.message : String(err);
1238
1238
  const wrapped = new Error(`Node "${this.name}": fn threw: ${errMsg}`, { cause: err });
@@ -1409,7 +1409,7 @@ var DynamicNodeImpl = class {
1409
1409
  _singleDepSinks = /* @__PURE__ */ new WeakSet();
1410
1410
  // Actions object (for onMessage handler)
1411
1411
  _actions;
1412
- _boundEmitToSinks;
1412
+ _boundDownToSinks;
1413
1413
  // Mutable state
1414
1414
  _cached = NO_VALUE;
1415
1415
  _status = "disconnected";
@@ -1456,7 +1456,7 @@ var DynamicNodeImpl = class {
1456
1456
  self._downInternal(messages);
1457
1457
  },
1458
1458
  emit(value) {
1459
- self._emitAutoValue(value);
1459
+ self._downAutoValue(value);
1460
1460
  },
1461
1461
  up(messages) {
1462
1462
  for (const dep of self._deps) {
@@ -1464,7 +1464,7 @@ var DynamicNodeImpl = class {
1464
1464
  }
1465
1465
  }
1466
1466
  };
1467
- this._boundEmitToSinks = this._emitToSinks.bind(this);
1467
+ this._boundDownToSinks = this._downToSinks.bind(this);
1468
1468
  }
1469
1469
  get name() {
1470
1470
  return this._registryName ?? this._optsName;
@@ -1544,12 +1544,12 @@ var DynamicNodeImpl = class {
1544
1544
  if (sinkMessages[i][0] !== DIRTY) filtered.push(sinkMessages[i]);
1545
1545
  }
1546
1546
  if (filtered.length > 0) {
1547
- emitWithBatch(this._boundEmitToSinks, filtered);
1547
+ downWithBatch(this._boundDownToSinks, filtered);
1548
1548
  }
1549
1549
  return;
1550
1550
  }
1551
1551
  }
1552
- emitWithBatch(this._boundEmitToSinks, sinkMessages);
1552
+ downWithBatch(this._boundDownToSinks, sinkMessages);
1553
1553
  }
1554
1554
  _canSkipDirty() {
1555
1555
  return this._sinkCount === 1 && this._singleDepSinkCount === 1;
@@ -1625,7 +1625,7 @@ var DynamicNodeImpl = class {
1625
1625
  this._disconnect();
1626
1626
  }
1627
1627
  // --- Private methods ---
1628
- _emitToSinks(messages) {
1628
+ _downToSinks(messages) {
1629
1629
  if (this._sinks == null) return;
1630
1630
  if (typeof this._sinks === "function") {
1631
1631
  this._sinks(messages);
@@ -1679,7 +1679,7 @@ var DynamicNodeImpl = class {
1679
1679
  }
1680
1680
  }
1681
1681
  }
1682
- _emitAutoValue(value) {
1682
+ _downAutoValue(value) {
1683
1683
  const wasDirty = this._status === "dirty";
1684
1684
  let unchanged;
1685
1685
  try {
@@ -1739,7 +1739,7 @@ var DynamicNodeImpl = class {
1739
1739
  const result = this._fn(get);
1740
1740
  this._rewire(trackedDeps);
1741
1741
  if (result === void 0) return;
1742
- this._emitAutoValue(result);
1742
+ this._downAutoValue(result);
1743
1743
  } catch (err) {
1744
1744
  this._downInternal([[ERROR, err]]);
1745
1745
  }
@@ -1803,14 +1803,14 @@ var DynamicNodeImpl = class {
1803
1803
  this._dirtyBits.add(index);
1804
1804
  this._settledBits.delete(index);
1805
1805
  if (this._dirtyBits.size === 1) {
1806
- emitWithBatch(this._boundEmitToSinks, [[DIRTY]]);
1806
+ downWithBatch(this._boundDownToSinks, [[DIRTY]]);
1807
1807
  }
1808
1808
  continue;
1809
1809
  }
1810
1810
  if (t === DATA || t === RESOLVED) {
1811
1811
  if (!this._dirtyBits.has(index)) {
1812
1812
  this._dirtyBits.add(index);
1813
- emitWithBatch(this._boundEmitToSinks, [[DIRTY]]);
1813
+ downWithBatch(this._boundDownToSinks, [[DIRTY]]);
1814
1814
  }
1815
1815
  this._settledBits.add(index);
1816
1816
  if (this._allDirtySettled()) {
@@ -4645,7 +4645,7 @@ var Graph = class _Graph {
4645
4645
  _createObserveResult(path, target, options) {
4646
4646
  const timeline = options.timeline === true;
4647
4647
  const causal = options.causal === true;
4648
- const derived2 = options.derived === true;
4648
+ const derived3 = options.derived === true;
4649
4649
  const minimal = options.detail === "minimal";
4650
4650
  const result = {
4651
4651
  values: {},
@@ -4658,14 +4658,14 @@ var Graph = class _Graph {
4658
4658
  let lastTriggerDepIndex;
4659
4659
  let lastRunDepValues;
4660
4660
  let detachInspectorHook;
4661
- if ((causal || derived2) && target instanceof NodeImpl) {
4661
+ if ((causal || derived3) && target instanceof NodeImpl) {
4662
4662
  detachInspectorHook = target._setInspectorHook((event) => {
4663
4663
  if (event.kind === "dep_message") {
4664
4664
  lastTriggerDepIndex = event.depIndex;
4665
4665
  return;
4666
4666
  }
4667
4667
  lastRunDepValues = [...event.depValues];
4668
- if (derived2) {
4668
+ if (derived3) {
4669
4669
  result.events.push({
4670
4670
  type: "derived",
4671
4671
  path,
@@ -5562,9 +5562,9 @@ __export(core_exports, {
5562
5562
  defaultHash: () => defaultHash,
5563
5563
  derived: () => derived,
5564
5564
  describeNode: () => describeNode,
5565
+ downWithBatch: () => downWithBatch,
5565
5566
  dynamicNode: () => dynamicNode,
5566
5567
  effect: () => effect,
5567
- emitWithBatch: () => emitWithBatch,
5568
5568
  isBatching: () => isBatching,
5569
5569
  isKnownMessageType: () => isKnownMessageType,
5570
5570
  isPhase2Message: () => isPhase2Message,
@@ -12967,6 +12967,7 @@ __export(patterns_exports, {
12967
12967
  demoShell: () => demo_shell_exports,
12968
12968
  domainTemplates: () => domain_templates_exports,
12969
12969
  graphspec: () => graphspec_exports,
12970
+ harness: () => harness_exports,
12970
12971
  layout: () => reactive_layout_exports,
12971
12972
  memory: () => memory_exports,
12972
12973
  messaging: () => messaging_exports,
@@ -14917,7 +14918,7 @@ function computeLineBreaks(segments, maxWidth, adapter, font, cache2) {
14917
14918
  hyphenWidth = adapter.measureSegment("-", font).width;
14918
14919
  fontCache.set("-", hyphenWidth);
14919
14920
  }
14920
- function emitLine(endSeg = lineEndSeg, endGrapheme = lineEndGrapheme, width = lineW) {
14921
+ function flushLine(endSeg = lineEndSeg, endGrapheme = lineEndGrapheme, width = lineW) {
14921
14922
  let text = "";
14922
14923
  for (let i = lineStartSeg; i < endSeg; i++) {
14923
14924
  const seg = segments[i];
@@ -14980,7 +14981,7 @@ function computeLineBreaks(segments, maxWidth, adapter, font, cache2) {
14980
14981
  const seg = segments[i];
14981
14982
  if (seg.kind === "hard-break") {
14982
14983
  if (hasContent) {
14983
- emitLine();
14984
+ flushLine();
14984
14985
  } else {
14985
14986
  lines.push({
14986
14987
  text: "",
@@ -15014,20 +15015,20 @@ function computeLineBreaks(segments, maxWidth, adapter, font, cache2) {
15014
15015
  lineW += w;
15015
15016
  lineEndSeg = i + 1;
15016
15017
  lineEndGrapheme = 0;
15017
- emitLine(i + 1, 0, seg.kind === "space" ? lineW - w : lineW);
15018
+ flushLine(i + 1, 0, seg.kind === "space" ? lineW - w : lineW);
15018
15019
  continue;
15019
15020
  }
15020
15021
  if (pendingBreakSeg >= 0) {
15021
- emitLine(pendingBreakSeg, 0, pendingBreakWidth);
15022
+ flushLine(pendingBreakSeg, 0, pendingBreakWidth);
15022
15023
  i--;
15023
15024
  continue;
15024
15025
  }
15025
15026
  if (w > maxWidth && seg.graphemeWidths) {
15026
- emitLine();
15027
+ flushLine();
15027
15028
  appendBreakableSegment(i, 0, seg.graphemeWidths);
15028
15029
  continue;
15029
15030
  }
15030
- emitLine();
15031
+ flushLine();
15031
15032
  i--;
15032
15033
  continue;
15033
15034
  }
@@ -15040,7 +15041,7 @@ function computeLineBreaks(segments, maxWidth, adapter, font, cache2) {
15040
15041
  }
15041
15042
  }
15042
15043
  if (hasContent) {
15043
- emitLine();
15044
+ flushLine();
15044
15045
  }
15045
15046
  return { lines, lineCount: lines.length };
15046
15047
  function appendBreakableSegment(segIdx, startG, gWidths) {
@@ -15051,7 +15052,7 @@ function computeLineBreaks(segments, maxWidth, adapter, font, cache2) {
15051
15052
  continue;
15052
15053
  }
15053
15054
  if (lineW + gw > maxWidth + 5e-3) {
15054
- emitLine();
15055
+ flushLine();
15055
15056
  startLineAtGrapheme(segIdx, g, gw);
15056
15057
  } else {
15057
15058
  lineW += gw;
@@ -15142,9 +15143,9 @@ function reactiveLayout(opts) {
15142
15143
  const hr = hitRate;
15143
15144
  const len = result.length;
15144
15145
  const el = elapsed;
15145
- emitWithBatch((msgs) => meta["cache-hit-rate"]?.down(msgs), [[DATA, hr]], 3);
15146
- emitWithBatch((msgs) => meta["segment-count"]?.down(msgs), [[DATA, len]], 3);
15147
- emitWithBatch((msgs) => meta["layout-time-ns"]?.down(msgs), [[DATA, el]], 3);
15146
+ downWithBatch((msgs) => meta["cache-hit-rate"]?.down(msgs), [[DATA, hr]], 3);
15147
+ downWithBatch((msgs) => meta["segment-count"]?.down(msgs), [[DATA, len]], 3);
15148
+ downWithBatch((msgs) => meta["layout-time-ns"]?.down(msgs), [[DATA, el]], 3);
15148
15149
  }
15149
15150
  return result;
15150
15151
  },
@@ -17383,6 +17384,59 @@ ${validation.errors.join("\n")}`);
17383
17384
  return parsed;
17384
17385
  }
17385
17386
 
17387
+ // src/patterns/harness/index.ts
17388
+ var harness_exports = {};
17389
+ __export(harness_exports, {
17390
+ DEFAULT_DECAY_RATE: () => DEFAULT_DECAY_RATE2,
17391
+ DEFAULT_QUEUE_CONFIGS: () => DEFAULT_QUEUE_CONFIGS,
17392
+ DEFAULT_SEVERITY_WEIGHTS: () => DEFAULT_SEVERITY_WEIGHTS,
17393
+ HarnessGraph: () => HarnessGraph,
17394
+ defaultErrorClassifier: () => defaultErrorClassifier,
17395
+ evalIntakeBridge: () => evalIntakeBridge,
17396
+ harnessLoop: () => harnessLoop,
17397
+ priorityScore: () => priorityScore,
17398
+ strategyKey: () => strategyKey,
17399
+ strategyModel: () => strategyModel
17400
+ });
17401
+
17402
+ // src/patterns/harness/bridge.ts
17403
+ function evalIntakeBridge(evalSource, intakeTopic, opts) {
17404
+ const defaultSeverity = opts?.defaultSeverity ?? "medium";
17405
+ return effect([evalSource], ([results]) => {
17406
+ if (results == null) return;
17407
+ const runs = Array.isArray(results) ? results : [results];
17408
+ for (const run of runs) {
17409
+ for (const task2 of run.tasks) {
17410
+ if (task2.valid && task2.judge_scores?.every((s) => s.pass)) continue;
17411
+ if (!task2.valid && (!task2.judge_scores || task2.judge_scores.length === 0)) {
17412
+ intakeTopic.publish({
17413
+ source: "eval",
17414
+ summary: `Task ${task2.task_id} invalid (model: ${run.model})`,
17415
+ evidence: `Run ${run.run_id}: task produced invalid output`,
17416
+ affectsAreas: ["graphspec"],
17417
+ affectsEvalTasks: [task2.task_id],
17418
+ severity: defaultSeverity
17419
+ });
17420
+ continue;
17421
+ }
17422
+ if (task2.judge_scores) {
17423
+ for (const score of task2.judge_scores) {
17424
+ if (score.pass) continue;
17425
+ intakeTopic.publish({
17426
+ source: "eval",
17427
+ summary: `${task2.task_id}: ${score.claim} (model: ${run.model})`,
17428
+ evidence: score.reasoning,
17429
+ affectsAreas: ["graphspec"],
17430
+ affectsEvalTasks: [task2.task_id],
17431
+ severity: defaultSeverity
17432
+ });
17433
+ }
17434
+ }
17435
+ }
17436
+ }
17437
+ });
17438
+ }
17439
+
17386
17440
  // src/patterns/messaging.ts
17387
17441
  var messaging_exports = {};
17388
17442
  __export(messaging_exports, {
@@ -18276,6 +18330,326 @@ function onFailure(graph, name, source, recover, opts) {
18276
18330
  return step;
18277
18331
  }
18278
18332
 
18333
+ // src/patterns/harness/types.ts
18334
+ function strategyKey(rootCause, intervention) {
18335
+ return `${rootCause}\u2192${intervention}`;
18336
+ }
18337
+ function defaultErrorClassifier(result) {
18338
+ const d = result.detail.toLowerCase();
18339
+ if (d.includes("parse") || d.includes("json") || d.includes("config") || d.includes("validation") || d.includes("syntax")) {
18340
+ return "self-correctable";
18341
+ }
18342
+ return "structural";
18343
+ }
18344
+ var DEFAULT_SEVERITY_WEIGHTS = {
18345
+ critical: 100,
18346
+ high: 70,
18347
+ medium: 40,
18348
+ low: 10
18349
+ };
18350
+ var DEFAULT_DECAY_RATE2 = Math.LN2 / (7 * 24 * 3600);
18351
+ var DEFAULT_QUEUE_CONFIGS = {
18352
+ "auto-fix": { gated: false },
18353
+ "needs-decision": { gated: true },
18354
+ investigation: { gated: true },
18355
+ backlog: { gated: false, startOpen: false }
18356
+ };
18357
+
18358
+ // src/patterns/harness/strategy.ts
18359
+ function strategyModel() {
18360
+ const _map = reactiveMap({ name: "strategy-entries" });
18361
+ const snapshot = derived(
18362
+ [_map.node],
18363
+ ([mapSnap]) => {
18364
+ const raw = mapSnap.value.map;
18365
+ return new Map(raw);
18366
+ },
18367
+ {
18368
+ name: "strategy-model",
18369
+ equals: (a, b) => {
18370
+ const am = a;
18371
+ const bm = b;
18372
+ if (am.size !== bm.size) return false;
18373
+ for (const [k, v] of am) {
18374
+ const bv = bm.get(k);
18375
+ if (!bv || v.attempts !== bv.attempts || v.successes !== bv.successes) return false;
18376
+ }
18377
+ return true;
18378
+ }
18379
+ }
18380
+ );
18381
+ function record(rootCause, intervention, success) {
18382
+ const key = strategyKey(rootCause, intervention);
18383
+ const existing = _map.get(key);
18384
+ const attempts = (existing?.attempts ?? 0) + 1;
18385
+ const successes = (existing?.successes ?? 0) + (success ? 1 : 0);
18386
+ _map.set(key, {
18387
+ rootCause,
18388
+ intervention,
18389
+ attempts,
18390
+ successes,
18391
+ successRate: successes / attempts
18392
+ });
18393
+ }
18394
+ function lookup(rootCause, intervention) {
18395
+ return _map.get(strategyKey(rootCause, intervention));
18396
+ }
18397
+ const _unsub = snapshot.subscribe(() => {
18398
+ });
18399
+ return { node: snapshot, record, lookup };
18400
+ }
18401
+ function priorityScore(item, strategy, lastInteractionNs, urgency, signals) {
18402
+ const severityWeights = { ...DEFAULT_SEVERITY_WEIGHTS, ...signals?.severityWeights };
18403
+ const decayRate = signals?.decayRate ?? DEFAULT_DECAY_RATE2;
18404
+ const effectivenessThreshold = signals?.effectivenessThreshold ?? 0.7;
18405
+ const effectivenessBoost = signals?.effectivenessBoost ?? 15;
18406
+ const deps = [item, strategy, lastInteractionNs];
18407
+ if (urgency) deps.push(urgency);
18408
+ return derived(
18409
+ deps,
18410
+ (values) => {
18411
+ const itm = values[0];
18412
+ const strat = values[1];
18413
+ const lastNs = values[2];
18414
+ const urg = urgency ? values[3] : 0;
18415
+ const baseWeight = severityWeights[itm.severity ?? "medium"];
18416
+ const ageSeconds = (monotonicNs() - lastNs) / 1e9;
18417
+ let score = decay(baseWeight, ageSeconds, decayRate, 0);
18418
+ const key = strategyKey(itm.rootCause, itm.intervention);
18419
+ const entry = strat.get(key);
18420
+ if (entry && entry.successRate >= effectivenessThreshold) {
18421
+ score += effectivenessBoost;
18422
+ }
18423
+ score += urg * 20;
18424
+ return score;
18425
+ },
18426
+ { name: "priority-score" }
18427
+ );
18428
+ }
18429
+
18430
+ // src/patterns/harness/loop.ts
18431
+ var DEFAULT_TRIAGE_PROMPT = `You are a triage classifier for a reactive collaboration harness.
18432
+
18433
+ Given an intake item, classify it and output JSON:
18434
+ {
18435
+ "rootCause": "composition" | "missing-fn" | "bad-docs" | "schema-gap" | "regression" | "unknown",
18436
+ "intervention": "template" | "catalog-fn" | "docs" | "wrapper" | "schema-change" | "investigate",
18437
+ "route": "auto-fix" | "needs-decision" | "investigation" | "backlog",
18438
+ "priority": <number 0-100>,
18439
+ "triageReasoning": "<one sentence>"
18440
+ }
18441
+
18442
+ Strategy model (past effectiveness):
18443
+ {{strategy}}
18444
+
18445
+ Intake item:
18446
+ {{item}}`;
18447
+ var DEFAULT_EXECUTE_PROMPT = `You are an implementation agent.
18448
+
18449
+ Given a triaged issue with root cause and intervention type, produce a fix.
18450
+
18451
+ Issue:
18452
+ {{item}}
18453
+
18454
+ Output JSON:
18455
+ {
18456
+ "outcome": "success" | "failure" | "partial",
18457
+ "detail": "<description of what was done or what failed>"
18458
+ }`;
18459
+ var DEFAULT_VERIFY_PROMPT = `You are a QA reviewer.
18460
+
18461
+ Given an execution result, verify whether the fix is correct.
18462
+
18463
+ Execution:
18464
+ {{execution}}
18465
+
18466
+ Original issue:
18467
+ {{item}}
18468
+
18469
+ Output JSON:
18470
+ {
18471
+ "verified": true/false,
18472
+ "findings": ["<finding1>", ...],
18473
+ "errorClass": "self-correctable" | "structural" // only if verified=false
18474
+ }`;
18475
+ var QUEUE_NAMES = [
18476
+ "auto-fix",
18477
+ "needs-decision",
18478
+ "investigation",
18479
+ "backlog"
18480
+ ];
18481
+ var HarnessGraph = class extends Graph {
18482
+ /** Intake topic — publish items here to enter the loop. */
18483
+ intake;
18484
+ /** Per-route queue topics. */
18485
+ queues;
18486
+ /** Per-route gate controllers (only for gated queues). */
18487
+ gates;
18488
+ /** Strategy model bundle — record outcomes, lookup effectiveness. */
18489
+ strategy;
18490
+ /** Verify results topic — subscribe to see verification outcomes. */
18491
+ verifyResults;
18492
+ constructor(name, intake, queues, gates, strategy, verifyResults) {
18493
+ super(name);
18494
+ this.intake = intake;
18495
+ this.queues = queues;
18496
+ this.gates = gates;
18497
+ this.strategy = strategy;
18498
+ this.verifyResults = verifyResults;
18499
+ }
18500
+ };
18501
+ function harnessLoop(name, opts) {
18502
+ const adapter = opts.adapter;
18503
+ const maxRetries = opts.maxRetries ?? 2;
18504
+ const retainedLimit = opts.retainedLimit ?? 1e3;
18505
+ const errorClassifier = opts.errorClassifier ?? defaultErrorClassifier;
18506
+ const queueConfigs = /* @__PURE__ */ new Map();
18507
+ for (const route of QUEUE_NAMES) {
18508
+ queueConfigs.set(route, {
18509
+ ...DEFAULT_QUEUE_CONFIGS[route],
18510
+ ...opts.queues?.[route]
18511
+ });
18512
+ }
18513
+ const intake = new TopicGraph("intake", { retainedLimit });
18514
+ const strategy = strategyModel();
18515
+ const triageNode = promptNode(
18516
+ adapter,
18517
+ [intake.latest, strategy.node],
18518
+ opts.triagePrompt ?? ((item, strat) => {
18519
+ return DEFAULT_TRIAGE_PROMPT.replace("{{strategy}}", JSON.stringify(strat)).replace(
18520
+ "{{item}}",
18521
+ JSON.stringify(item)
18522
+ );
18523
+ }),
18524
+ {
18525
+ name: "triage",
18526
+ format: "json",
18527
+ retries: 1
18528
+ }
18529
+ );
18530
+ const queueTopics = /* @__PURE__ */ new Map();
18531
+ for (const route of QUEUE_NAMES) {
18532
+ queueTopics.set(route, new TopicGraph(`queue/${route}`, { retainedLimit }));
18533
+ }
18534
+ const _router = effect([triageNode], ([triaged]) => {
18535
+ const item = triaged;
18536
+ if (!item || !item.route) return;
18537
+ const topic2 = queueTopics.get(item.route);
18538
+ if (topic2) topic2.publish(item);
18539
+ });
18540
+ const gateGraph = new Graph("gates");
18541
+ const gateControllers = /* @__PURE__ */ new Map();
18542
+ for (const route of QUEUE_NAMES) {
18543
+ const config = queueConfigs.get(route);
18544
+ const topic2 = queueTopics.get(route);
18545
+ if (config.gated) {
18546
+ gateGraph.add(`${route}/source`, topic2.latest);
18547
+ const ctrl = gate(gateGraph, `${route}/gate`, `${route}/source`, {
18548
+ maxPending: config.maxPending,
18549
+ startOpen: config.startOpen
18550
+ });
18551
+ gateControllers.set(route, ctrl);
18552
+ }
18553
+ }
18554
+ const retryTopic = new TopicGraph("retry-input", { retainedLimit });
18555
+ const queueOutputs = [];
18556
+ for (const route of QUEUE_NAMES) {
18557
+ const config = queueConfigs.get(route);
18558
+ if (config.gated && gateControllers.has(route)) {
18559
+ queueOutputs.push(gateControllers.get(route).node);
18560
+ } else {
18561
+ queueOutputs.push(queueTopics.get(route).latest);
18562
+ }
18563
+ }
18564
+ queueOutputs.push(retryTopic.latest);
18565
+ const executeInput = merge(...queueOutputs);
18566
+ const executeNode = promptNode(
18567
+ adapter,
18568
+ [executeInput],
18569
+ opts.executePrompt ?? ((item) => {
18570
+ return DEFAULT_EXECUTE_PROMPT.replace("{{item}}", JSON.stringify(item));
18571
+ }),
18572
+ {
18573
+ name: "execute",
18574
+ format: "json",
18575
+ retries: 1
18576
+ }
18577
+ );
18578
+ const verifyResults = new TopicGraph("verify-results", { retainedLimit });
18579
+ const verifyNode = promptNode(
18580
+ adapter,
18581
+ [executeNode, executeInput],
18582
+ opts.verifyPrompt ?? ((execution, item) => {
18583
+ return DEFAULT_VERIFY_PROMPT.replace("{{execution}}", JSON.stringify(execution)).replace(
18584
+ "{{item}}",
18585
+ JSON.stringify(item)
18586
+ );
18587
+ }),
18588
+ {
18589
+ name: "verify",
18590
+ format: "json",
18591
+ retries: 1
18592
+ }
18593
+ );
18594
+ const maxReingestions = opts.maxReingestions ?? 1;
18595
+ let reingestionCount = 0;
18596
+ const _fastRetry = effect([verifyNode], ([result]) => {
18597
+ const vr = result;
18598
+ if (!vr) return;
18599
+ if (vr.verified) {
18600
+ strategy.record(vr.item.rootCause, vr.item.intervention, true);
18601
+ verifyResults.publish(vr);
18602
+ return;
18603
+ }
18604
+ const errClass = vr.errorClass ?? errorClassifier({
18605
+ item: vr.item,
18606
+ outcome: "failure",
18607
+ detail: vr.findings.join("; "),
18608
+ retryCount: 0
18609
+ });
18610
+ const exec = vr.execution;
18611
+ const retryCount = exec?.retryCount ?? 0;
18612
+ if (errClass === "self-correctable" && retryCount < maxRetries) {
18613
+ const retryItem = {
18614
+ ...vr.item,
18615
+ summary: `[RETRY ${retryCount + 1}/${maxRetries}] ${vr.item.summary} \u2014 Previous attempt failed: ${vr.findings.join("; ")}`
18616
+ };
18617
+ retryTopic.publish(retryItem);
18618
+ } else {
18619
+ strategy.record(vr.item.rootCause, vr.item.intervention, false);
18620
+ verifyResults.publish(vr);
18621
+ if (reingestionCount < maxReingestions) {
18622
+ reingestionCount++;
18623
+ intake.publish({
18624
+ source: "eval",
18625
+ summary: `Verification failed for: ${vr.item.summary}`,
18626
+ evidence: vr.findings.join("\n"),
18627
+ affectsAreas: vr.item.affectsAreas,
18628
+ affectsEvalTasks: vr.item.affectsEvalTasks,
18629
+ severity: "high",
18630
+ relatedTo: [vr.item.summary]
18631
+ });
18632
+ }
18633
+ }
18634
+ });
18635
+ const harness = new HarnessGraph(
18636
+ name,
18637
+ intake,
18638
+ queueTopics,
18639
+ gateControllers,
18640
+ strategy,
18641
+ verifyResults
18642
+ );
18643
+ harness.mount("intake", intake);
18644
+ for (const [route, topic2] of queueTopics) {
18645
+ harness.mount(`queue/${route}`, topic2);
18646
+ }
18647
+ harness.mount("gates", gateGraph);
18648
+ harness.mount("retry-input", retryTopic);
18649
+ harness.mount("verify-results", verifyResults);
18650
+ return harness;
18651
+ }
18652
+
18279
18653
  // src/patterns/reactive-layout/index.ts
18280
18654
  var reactive_layout_exports = {};
18281
18655
  __export(reactive_layout_exports, {
@@ -18687,8 +19061,8 @@ function reactiveBlockLayout(opts) {
18687
19061
  const elapsed = monotonicNs() - t0;
18688
19062
  const meta = measuredBlocksNode.meta;
18689
19063
  if (meta) {
18690
- emitWithBatch((msgs) => meta["block-count"]?.down(msgs), [[DATA, result.length]], 3);
18691
- emitWithBatch((msgs) => meta["layout-time-ns"]?.down(msgs), [[DATA, elapsed]], 3);
19064
+ downWithBatch((msgs) => meta["block-count"]?.down(msgs), [[DATA, result.length]], 3);
19065
+ downWithBatch((msgs) => meta["layout-time-ns"]?.down(msgs), [[DATA, elapsed]], 3);
18692
19066
  }
18693
19067
  return result;
18694
19068
  },
@@ -18839,10 +19213,10 @@ var version = "0.0.0";
18839
19213
  distill,
18840
19214
  distinctUntilChanged,
18841
19215
  domainTemplates,
19216
+ downWithBatch,
18842
19217
  dynamicNode,
18843
19218
  effect,
18844
19219
  elementAt,
18845
- emitWithBatch,
18846
19220
  empty,
18847
19221
  escapeRegexChar,
18848
19222
  exhaustMap,
@@ -18890,6 +19264,7 @@ var version = "0.0.0";
18890
19264
  globToRegExp,
18891
19265
  graph,
18892
19266
  graphspec,
19267
+ harness,
18893
19268
  interval,
18894
19269
  isBatching,
18895
19270
  isKnownMessageType,