ryugi-artifacts 1.63.0 → 1.65.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.
package/dist/server.cjs CHANGED
@@ -48383,7 +48383,7 @@ var import_node_os2 = __toESM(require("node:os"), 1);
48383
48383
  var import_node_path41 = __toESM(require("node:path"), 1);
48384
48384
 
48385
48385
  // package.json
48386
- var version = "1.63.0";
48386
+ var version = "1.65.0";
48387
48387
 
48388
48388
  // src/server/browser-focus.ts
48389
48389
  var import_node_child_process = require("node:child_process");
@@ -50268,6 +50268,16 @@ function blocksOf(diff) {
50268
50268
  }
50269
50269
  return [...blocks.values()];
50270
50270
  }
50271
+ function countStates(items) {
50272
+ const summary = /* @__PURE__ */ new Map();
50273
+ for (const item2 of items) {
50274
+ const status = item2.kind === "choose" ? item2.choice ? "chosen" : "empty" : String(item2.state ?? item2.verdict ?? item2.status ?? "unknown");
50275
+ summary.set(status, (summary.get(status) ?? 0) + 1);
50276
+ if (item2.waitingOn === "agent")
50277
+ summary.set("waitingOnAgent", (summary.get("waitingOnAgent") ?? 0) + 1);
50278
+ }
50279
+ return Object.fromEntries(summary);
50280
+ }
50271
50281
  function createAgentReview(stateDir, options2 = {}) {
50272
50282
  const root = import_node_path7.default.join(stateDir, "agent-review");
50273
50283
  const now = options2.now ?? Date.now;
@@ -50408,6 +50418,9 @@ function createAgentReview(stateDir, options2 = {}) {
50408
50418
  waitingOn: waitingOn(thread),
50409
50419
  anchor: thread.anchor,
50410
50420
  stale: item2.stale ?? false,
50421
+ ...item2.orphan === true ? { orphan: true } : {},
50422
+ ...item2.draft === true ? { draft: true } : {},
50423
+ ...typeof item2.page === "string" ? { page: item2.page } : {},
50411
50424
  preview: preview(
50412
50425
  last?.text ?? (thread.messages.some((message2) => message2.deleted) ? "[deleted]" : "")
50413
50426
  ),
@@ -50423,16 +50436,9 @@ function createAgentReview(stateDir, options2 = {}) {
50423
50436
  )
50424
50437
  )
50425
50438
  ) : materialized;
50426
- const summary = /* @__PURE__ */ new Map();
50427
- for (const item2 of values) {
50428
- const status = item2.kind === "choose" ? item2.choice ? "chosen" : "empty" : String(item2.state ?? item2.verdict ?? item2.status ?? "unknown");
50429
- summary.set(status, (summary.get(status) ?? 0) + 1);
50430
- if (item2.waitingOn === "agent")
50431
- summary.set("waitingOnAgent", (summary.get("waitingOnAgent") ?? 0) + 1);
50432
- }
50433
50439
  return {
50434
50440
  items,
50435
- summary: Object.fromEntries(summary),
50441
+ summary: snap.value.counts ?? countStates(values),
50436
50442
  snapshot: snap.id,
50437
50443
  ...receipt ? { receipt } : {},
50438
50444
  page: {
@@ -50440,6 +50446,7 @@ function createAgentReview(stateDir, options2 = {}) {
50440
50446
  total: values.length,
50441
50447
  hasMore: nextCursor !== null,
50442
50448
  nextCursor,
50449
+ offset,
50443
50450
  scope: snap.value.all ? "historical" : snap.value.kind === "threads" ? input.thread ? "thread" : "unread" : "current_state",
50444
50451
  snapshot: snap.id
50445
50452
  }
@@ -50468,9 +50475,12 @@ function createAgentReview(stateDir, options2 = {}) {
50468
50475
  return page(input, snap, !!input.detail || !!input.thread);
50469
50476
  },
50470
50477
  state(input) {
50478
+ const narrowed = !!(input.all || input.filters?.status || input.filters?.choiceState);
50479
+ const keep = !narrowed && input.actionable ? input.actionable : () => true;
50471
50480
  const snap = snapshot2(input, input.section, () => ({
50481
+ counts: countStates(input.items),
50472
50482
  items: input.items.filter(
50473
- (item2) => (!input.filters?.status || item2.state === input.filters.status || item2.verdict === input.filters.status) && (!input.filters?.kind || item2.kind === input.filters.kind) && (!input.filters?.choiceState || (input.filters.choiceState === "chosen" ? !!item2.choice : !item2.choice))
50483
+ (item2) => keep(item2) && (!input.filters?.status || item2.state === input.filters.status || item2.verdict === input.filters.status) && (!input.filters?.kind || item2.kind === input.filters.kind) && (!input.filters?.choiceState || (input.filters.choiceState === "chosen" ? !!item2.choice : !item2.choice))
50474
50484
  )
50475
50485
  }));
50476
50486
  return page(input, snap, !!input.detail);
@@ -65163,7 +65173,7 @@ function installInspector(win, properties, commentCursor = "crosshair", pointerC
65163
65173
  };
65164
65174
  const label = (el3) => (el3.getAttribute("data-layer-name") || el3.getAttribute("aria-label") || el3.id || (!el3.childElementCount ? el3.textContent?.trim() : "") || "").slice(0, 100);
65165
65175
  const selector = (el3) => (el3.id ? `#${el3.id}` : el3.tagName.toLowerCase() + Array.from(el3.classList).slice(0, 2).map((name) => `.${name}`).join("")).slice(0, 200);
65166
- const pathOf = (el3) => {
65176
+ const pathOf2 = (el3) => {
65167
65177
  const segments = [];
65168
65178
  for (let node = el3; node && node !== doc.documentElement; node = node.parentElement) {
65169
65179
  const tag = node.tagName.toLowerCase();
@@ -65253,7 +65263,7 @@ function installInspector(win, properties, commentCursor = "crosshair", pointerC
65253
65263
  name: label(el3),
65254
65264
  tag: el3.tagName.toLowerCase(),
65255
65265
  selector: selector(el3),
65256
- path: pathOf(el3),
65266
+ path: pathOf2(el3),
65257
65267
  kind: kind(el3, win.getComputedStyle(el3)),
65258
65268
  children: []
65259
65269
  };
@@ -157464,26 +157474,26 @@ var checkPartialGroup = function checkPartialGroup2(node) {
157464
157474
  }
157465
157475
  return null;
157466
157476
  };
157467
- var _getOutermostNode = function getOutermostNode(node, side) {
157477
+ var _getOutermostNode = function getOutermostNode(node, side2) {
157468
157478
  var partialGroup = checkPartialGroup(node);
157469
157479
  if (partialGroup) {
157470
157480
  var children2 = partialGroup.children;
157471
157481
  if (children2.length) {
157472
- if (side === "right") {
157482
+ if (side2 === "right") {
157473
157483
  return _getOutermostNode(children2[children2.length - 1], "right");
157474
- } else if (side === "left") {
157484
+ } else if (side2 === "left") {
157475
157485
  return _getOutermostNode(children2[0], "left");
157476
157486
  }
157477
157487
  }
157478
157488
  }
157479
157489
  return node;
157480
157490
  };
157481
- var getTypeOfDomTree = function getTypeOfDomTree2(node, side) {
157491
+ var getTypeOfDomTree = function getTypeOfDomTree2(node, side2) {
157482
157492
  if (!node) {
157483
157493
  return null;
157484
157494
  }
157485
- if (side) {
157486
- node = _getOutermostNode(node, side);
157495
+ if (side2) {
157496
+ node = _getOutermostNode(node, side2);
157487
157497
  }
157488
157498
  var className = node.classes[0];
157489
157499
  return DomEnum[className] || null;
@@ -170595,10 +170605,10 @@ var LoroList = class _LoroList {
170595
170605
  * @param {Side} side
170596
170606
  * @returns {Cursor | undefined}
170597
170607
  */
170598
- getCursor(pos, side) {
170608
+ getCursor(pos, side2) {
170599
170609
  try {
170600
170610
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
170601
- wasm.lorolist_getCursor(retptr, this.__wbg_ptr, pos, addHeapObject(side));
170611
+ wasm.lorolist_getCursor(retptr, this.__wbg_ptr, pos, addHeapObject(side2));
170602
170612
  var r02 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
170603
170613
  var r12 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
170604
170614
  var r23 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
@@ -172080,10 +172090,10 @@ var LoroMovableList = class _LoroMovableList {
172080
172090
  * @param {Side} side
172081
172091
  * @returns {Cursor | undefined}
172082
172092
  */
172083
- getCursor(pos, side) {
172093
+ getCursor(pos, side2) {
172084
172094
  try {
172085
172095
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
172086
- wasm.loromovablelist_getCursor(retptr, this.__wbg_ptr, pos, addHeapObject(side));
172096
+ wasm.loromovablelist_getCursor(retptr, this.__wbg_ptr, pos, addHeapObject(side2));
172087
172097
  var r02 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
172088
172098
  var r12 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
172089
172099
  var r23 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
@@ -172935,10 +172945,10 @@ var LoroText = class _LoroText {
172935
172945
  * @param {Side} side
172936
172946
  * @returns {Cursor | undefined}
172937
172947
  */
172938
- getCursor(pos, side) {
172948
+ getCursor(pos, side2) {
172939
172949
  try {
172940
172950
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
172941
- wasm.lorotext_getCursor(retptr, this.__wbg_ptr, pos, addHeapObject(side));
172951
+ wasm.lorotext_getCursor(retptr, this.__wbg_ptr, pos, addHeapObject(side2));
172942
172952
  var r02 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
172943
172953
  var r12 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
172944
172954
  var r23 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
@@ -182070,6 +182080,157 @@ function createVerifyRecordings(options2) {
182070
182080
  // src/server/whiteboard.ts
182071
182081
  var import_node_fs33 = __toESM(require("node:fs"), 1);
182072
182082
  var import_node_path29 = __toESM(require("node:path"), 1);
182083
+
182084
+ // src/server/whiteboard-lint.ts
182085
+ var LINE_TYPES = /* @__PURE__ */ new Set(["arrow", "line"]);
182086
+ var NOT_OBSTACLES = /* @__PURE__ */ new Set(["text", "frame", "magicframe", "freedraw", "arrow", "line"]);
182087
+ var GRAZE = 2;
182088
+ var LABEL_MARGIN = 40;
182089
+ var CROSSINGS_SHOWN = 5;
182090
+ var containerSizeFor = (dimension, type) => {
182091
+ const padded = Math.ceil(dimension) + 10;
182092
+ if (type === "ellipse") return Math.round(padded / Math.SQRT2 * 2);
182093
+ if (type === "diamond") return 2 * padded;
182094
+ return padded;
182095
+ };
182096
+ var overlaps = (a5, b6) => a5.x < b6.x + b6.w && b6.x < a5.x + a5.w && a5.y < b6.y + b6.h && b6.y < a5.y + a5.h;
182097
+ var holds = (box2, [x9, y5]) => x9 > box2.x && x9 < box2.x + box2.w && y5 > box2.y && y5 < box2.y + box2.h;
182098
+ var inset = (box2, by2) => ({
182099
+ x: box2.x + by2,
182100
+ y: box2.y + by2,
182101
+ w: box2.w - 2 * by2,
182102
+ h: box2.h - 2 * by2
182103
+ });
182104
+ var segmentHits = (a5, b6, box2) => {
182105
+ if (box2.w <= 0 || box2.h <= 0) return false;
182106
+ const dx2 = b6[0] - a5[0];
182107
+ const dy2 = b6[1] - a5[1];
182108
+ let lo4 = 0;
182109
+ let hi3 = 1;
182110
+ for (const [p7, q4] of [
182111
+ [-dx2, a5[0] - box2.x],
182112
+ [dx2, box2.x + box2.w - a5[0]],
182113
+ [-dy2, a5[1] - box2.y],
182114
+ [dy2, box2.y + box2.h - a5[1]]
182115
+ ]) {
182116
+ if (p7 === 0) {
182117
+ if (q4 < 0) return false;
182118
+ continue;
182119
+ }
182120
+ const t7 = q4 / p7;
182121
+ if (p7 < 0) lo4 = Math.max(lo4, t7);
182122
+ else hi3 = Math.min(hi3, t7);
182123
+ if (lo4 > hi3) return false;
182124
+ }
182125
+ return true;
182126
+ };
182127
+ var side = (a5, b6, c10) => Math.sign((b6[0] - a5[0]) * (c10[1] - a5[1]) - (b6[1] - a5[1]) * (c10[0] - a5[0]));
182128
+ var segmentsCross = (a5, b6, c10, d10) => side(a5, b6, c10) * side(a5, b6, d10) < 0 && side(c10, d10, a5) * side(c10, d10, b6) < 0;
182129
+ var pathOf = (element) => {
182130
+ const { points: points2 } = element;
182131
+ if (!Array.isArray(points2) || points2.length < 2) return null;
182132
+ const path44 = [];
182133
+ for (const point2 of points2) {
182134
+ if (!Array.isArray(point2) || typeof point2[0] !== "number" || typeof point2[1] !== "number")
182135
+ return null;
182136
+ path44.push([(element.x ?? 0) + point2[0], (element.y ?? 0) + point2[1]]);
182137
+ }
182138
+ return path44;
182139
+ };
182140
+ var segmentsOf = (path44) => path44.slice(1).map((end, index) => [path44[index], end]);
182141
+ var lengthOf = (path44) => segmentsOf(path44).reduce((sum2, [a5, b6]) => sum2 + Math.hypot(b6[0] - a5[0], b6[1] - a5[1]), 0);
182142
+ var boundIds = (element) => [element.startBinding?.elementId, element.endBinding?.elementId].filter(
182143
+ (id3) => typeof id3 === "string"
182144
+ );
182145
+ function overflowWarnings(live3, geometry) {
182146
+ const byId = new Map(live3.map((element) => [element.id, element]));
182147
+ const warnings = [];
182148
+ for (const text5 of live3) {
182149
+ const box2 = geometry[text5.id];
182150
+ if (text5.type !== "text" || !box2?.overflow) continue;
182151
+ const container = text5.containerId ? byId.get(text5.containerId) : void 0;
182152
+ const outer = container ? geometry[container.id] : void 0;
182153
+ if (!container || !outer) {
182154
+ warnings.push(`text ${text5.id} overflows its container`);
182155
+ continue;
182156
+ }
182157
+ const width = containerSizeFor(box2.w, container.type);
182158
+ const height = containerSizeFor(box2.h, container.type);
182159
+ const short = [width > outer.w && `${width} wide`, height > outer.h && `${height} tall`].filter(
182160
+ Boolean
182161
+ );
182162
+ const now = short.length === 2 ? `${Math.round(outer.w)}\xD7${Math.round(outer.h)}` : width > outer.w ? Math.round(outer.w) : Math.round(outer.h);
182163
+ warnings.push(
182164
+ short.length ? `label of ${container.id} does not fit \u2014 make ${container.id} at least ${short.join(" and ")} (now ${now})` : `label of ${container.id} sticks out of it \u2014 re-center the label or enlarge ${container.id}`
182165
+ );
182166
+ }
182167
+ return warnings;
182168
+ }
182169
+ function arrowWarnings(live3, geometry) {
182170
+ const obstacles = live3.filter(
182171
+ (element) => !NOT_OBSTACLES.has(element.type) && !element.containerId && geometry[element.id]
182172
+ );
182173
+ const labels = new Map(
182174
+ live3.filter((element) => element.type === "text" && element.containerId && geometry[element.id]).map((text5) => [text5.containerId, geometry[text5.id]])
182175
+ );
182176
+ const arrows = live3.flatMap((element) => {
182177
+ if (!LINE_TYPES.has(element.type) || ryugi(element).author !== "agent") return [];
182178
+ const path44 = pathOf(element);
182179
+ return path44 ? [{ element, path: path44, bound: boundIds(element) }] : [];
182180
+ });
182181
+ const warnings = [];
182182
+ for (const { element, path: path44 } of arrows) {
182183
+ const ends = [path44[0], path44.at(-1)];
182184
+ const around = obstacles.filter(
182185
+ (shape2) => !ends.some((end) => holds(geometry[shape2.id], end))
182186
+ );
182187
+ for (const shape2 of around) {
182188
+ const box2 = inset(geometry[shape2.id], GRAZE);
182189
+ if (segmentsOf(path44).some(([a5, b6]) => segmentHits(a5, b6, box2)))
182190
+ warnings.push(
182191
+ `arrow ${element.id} crosses ${shape2.id} \u2014 move ${shape2.id} or bend the arrow around it`
182192
+ );
182193
+ }
182194
+ const label = labels.get(element.id);
182195
+ if (!label) continue;
182196
+ for (const shape2 of around)
182197
+ if (overlaps(label, inset(geometry[shape2.id], GRAZE)))
182198
+ warnings.push(
182199
+ `label of arrow ${element.id} covers ${shape2.id} \u2014 move ${shape2.id} or shorten the label`
182200
+ );
182201
+ const [dx2, dy2] = [ends[1][0] - ends[0][0], ends[1][1] - ends[0][1]];
182202
+ const chord = Math.hypot(dx2, dy2);
182203
+ if (chord === 0) continue;
182204
+ const need = Math.ceil(
182205
+ (Math.abs(dx2) * label.w + Math.abs(dy2) * label.h) / chord + LABEL_MARGIN
182206
+ );
182207
+ const length = lengthOf(path44);
182208
+ if (length < need)
182209
+ warnings.push(
182210
+ `label of arrow ${element.id} needs the arrow to be at least ${need} px long (now ${Math.round(length)}) \u2014 move its ends apart or shorten the label`
182211
+ );
182212
+ }
182213
+ const crossings = [];
182214
+ for (const [index, a5] of arrows.entries())
182215
+ for (const b6 of arrows.slice(index + 1)) {
182216
+ if (a5.bound.some((id3) => b6.bound.includes(id3))) continue;
182217
+ const crossed = segmentsOf(a5.path).some(
182218
+ ([p7, q4]) => segmentsOf(b6.path).some(([r8, s7]) => segmentsCross(p7, q4, r8, s7))
182219
+ );
182220
+ if (crossed) crossings.push(`${a5.element.id} \xD7 ${b6.element.id}`);
182221
+ }
182222
+ if (crossings.length) {
182223
+ const shown = crossings.slice(0, CROSSINGS_SHOWN).join(", ");
182224
+ const more = crossings.length > CROSSINGS_SHOWN ? `, and ${crossings.length - CROSSINGS_SHOWN} more` : "";
182225
+ const places = crossings.length === 1 ? "1 place" : `${crossings.length} places`;
182226
+ warnings.push(
182227
+ `arrows cross in ${places}: ${shown}${more} \u2014 reorder the shapes so fewer arrows cross`
182228
+ );
182229
+ }
182230
+ return warnings;
182231
+ }
182232
+
182233
+ // src/server/whiteboard.ts
182073
182234
  var sceneVersionOf = (scene) => scene.elements.reduce((sum2, element) => sum2 + (element.version ?? 0), 0);
182074
182235
  function readWhiteboard(dir, id3) {
182075
182236
  const version3 = latestMtime(dir);
@@ -182092,8 +182253,8 @@ function readWhiteboard(dir, id3) {
182092
182253
  return { title: name || id3, warnings, version: version3, sceneVersion: sceneVersionOf(parsed.scene) };
182093
182254
  }
182094
182255
  var SCENE_SIZE_LIMIT = 5 * 1024 * 1024;
182095
- var LINE_TYPES = /* @__PURE__ */ new Set(["arrow", "line"]);
182096
- var overlaps = (a5, b6) => a5.x < b6.x + b6.w && b6.x < a5.x + a5.w && a5.y < b6.y + b6.h && b6.y < a5.y + a5.h;
182256
+ var LINE_TYPES2 = /* @__PURE__ */ new Set(["arrow", "line"]);
182257
+ var overlaps2 = (a5, b6) => a5.x < b6.x + b6.w && b6.x < a5.x + a5.w && a5.y < b6.y + b6.h && b6.y < a5.y + a5.h;
182097
182258
  var contains = (outer, inner2) => inner2.x >= outer.x && inner2.y >= outer.y && inner2.x + inner2.w <= outer.x + outer.w && inner2.y + inner2.h <= outer.y + outer.h;
182098
182259
  function whiteboardWarnings2(scene, context2) {
182099
182260
  const file = context2.file ?? "scene.excalidraw";
@@ -182101,7 +182262,7 @@ function whiteboardWarnings2(scene, context2) {
182101
182262
  const ids = new Set(live3.map((element) => element.id));
182102
182263
  const warnings = [];
182103
182264
  for (const element of live3) {
182104
- if (LINE_TYPES.has(element.type)) {
182265
+ if (LINE_TYPES2.has(element.type)) {
182105
182266
  for (const binding of [element.startBinding, element.endBinding])
182106
182267
  if (binding && !ids.has(binding.elementId)) {
182107
182268
  const other = context2.elsewhere?.(binding.elementId);
@@ -182129,28 +182290,27 @@ function whiteboardWarnings2(scene, context2) {
182129
182290
  );
182130
182291
  const geometry = context2.geometry?.sceneVersion === sceneVersionOf(scene) ? context2.geometry.elements : null;
182131
182292
  if (geometry) {
182132
- for (const element of live3)
182133
- if (element.type === "text" && geometry[element.id]?.overflow)
182134
- warnings.push(`text ${element.id} overflows its container`);
182293
+ warnings.push(...overflowWarnings(live3, geometry));
182135
182294
  for (const element of live3) {
182136
182295
  const box2 = geometry[element.id];
182137
182296
  const frame = element.frameId ? geometry[element.frameId] : void 0;
182138
- if (!box2 || !frame || element.containerId || LINE_TYPES.has(element.type)) continue;
182297
+ if (!box2 || !frame || element.containerId || LINE_TYPES2.has(element.type)) continue;
182139
182298
  if (ryugi(element).lastBy !== "agent" || contains(frame, box2)) continue;
182140
182299
  warnings.push(
182141
182300
  `element ${element.id} sticks out of frame ${element.frameId}, which hides the part outside \u2014 move it in or resize the frame`
182142
182301
  );
182143
182302
  }
182144
182303
  const shapes = live3.filter(
182145
- (element) => ryugi(element).author === "agent" && element.type !== "frame" && element.type !== "text" && !LINE_TYPES.has(element.type) && geometry[element.id]
182304
+ (element) => ryugi(element).author === "agent" && element.type !== "frame" && element.type !== "text" && !LINE_TYPES2.has(element.type) && geometry[element.id]
182146
182305
  );
182147
182306
  for (const [index, a5] of shapes.entries())
182148
182307
  for (const b6 of shapes.slice(index + 1)) {
182149
182308
  const boxA = geometry[a5.id];
182150
182309
  const boxB = geometry[b6.id];
182151
- if (overlaps(boxA, boxB) && !contains(boxA, boxB) && !contains(boxB, boxA))
182310
+ if (overlaps2(boxA, boxB) && !contains(boxA, boxB) && !contains(boxB, boxA))
182152
182311
  warnings.push(`elements ${a5.id} and ${b6.id} overlap`);
182153
182312
  }
182313
+ warnings.push(...arrowWarnings(live3, geometry));
182154
182314
  }
182155
182315
  const pending = live3.some(isSkeleton) ? ["skeleton_not_completed"] : [];
182156
182316
  return { warnings, pending };
@@ -182442,8 +182602,8 @@ function mergeBrowser(current, incoming, opts = {}) {
182442
182602
  for (const element of incoming) {
182443
182603
  const existing = replaced.get(element.id) ?? known.get(element.id);
182444
182604
  if (!existing) {
182445
- const side = opts.completion ? "agent" : "human";
182446
- added.push(withRyugi(element, { author: side, rev: 1, lastBy: side }));
182605
+ const side2 = opts.completion ? "agent" : "human";
182606
+ added.push(withRyugi(element, { author: side2, rev: 1, lastBy: side2 }));
182447
182607
  changed.push(element.id);
182448
182608
  continue;
182449
182609
  }
@@ -183572,7 +183732,7 @@ var import_node_path34 = __toESM(require("node:path"), 1);
183572
183732
 
183573
183733
  // src/shared/whiteboard/summary.ts
183574
183734
  var STICKY_FILL = "#ffec99";
183575
- var LINE_TYPES2 = /* @__PURE__ */ new Set(["arrow", "line"]);
183735
+ var LINE_TYPES3 = /* @__PURE__ */ new Set(["arrow", "line"]);
183576
183736
  function provenance(element) {
183577
183737
  const fields = ryugi(element);
183578
183738
  const author = fields.author ?? null;
@@ -183595,7 +183755,7 @@ function summarize(scene, opts = {}) {
183595
183755
  ...provenance(element)
183596
183756
  });
183597
183757
  const shapes = live3.filter(
183598
- (element) => element.type !== "frame" && !LINE_TYPES2.has(element.type) && !(element.type === "text" && element.containerId)
183758
+ (element) => element.type !== "frame" && !LINE_TYPES3.has(element.type) && !(element.type === "text" && element.containerId)
183599
183759
  );
183600
183760
  const frames = live3.filter((element) => element.type === "frame" && (!opts.frame || element.id === opts.frame)).map((frame) => ({
183601
183761
  id: frame.id,
@@ -183604,7 +183764,7 @@ function summarize(scene, opts = {}) {
183604
183764
  }));
183605
183765
  const loose = opts.frame ? [] : shapes.filter((element) => !element.frameId).map(item2);
183606
183766
  const inFrame = (id3) => id3 !== null && frameOf.get(id3) === opts.frame;
183607
- const arrows = live3.filter((element) => LINE_TYPES2.has(element.type)).map((arrow) => ({
183767
+ const arrows = live3.filter((element) => LINE_TYPES3.has(element.type)).map((arrow) => ({
183608
183768
  arrow,
183609
183769
  from: arrow.startBinding?.elementId ?? null,
183610
183770
  to: arrow.endBinding?.elementId ?? null
@@ -184127,6 +184287,16 @@ var agentEventRoute = {
184127
184287
  }
184128
184288
  };
184129
184289
 
184290
+ // src/server/review-defaults.ts
184291
+ function actionable(section, rounds) {
184292
+ if (section === "asks") return (item2) => item2.state === "submitted";
184293
+ if (section === "rounds") return (item2) => item2.state === "open" || item2.state === "submitted";
184294
+ const submitted = new Set(
184295
+ rounds.filter((round) => round.state === "submitted").map((round) => round.id)
184296
+ );
184297
+ return (item2) => item2.kind === "verify" ? item2.verdict === "reject" : submitted.has(item2.round);
184298
+ }
184299
+
184130
184300
  // src/server/routes/agent-review.ts
184131
184301
  var schema = "ryugi.review/v1";
184132
184302
  var text3 = (value) => typeof value === "string" ? value : void 0;
@@ -184191,13 +184361,20 @@ async function threads(ctx, type, id3, input) {
184191
184361
  }
184192
184362
  async function state(ctx, type, id3, input, section) {
184193
184363
  let items = [];
184364
+ let rounds = [];
184194
184365
  if (section === "asks" && type === "document")
184195
184366
  items = (await ctx.documents.asks(id3)).asks.map((ask) => ({ ...ask }));
184196
- else if (section === "groups" && type === "artboard")
184367
+ else if (section === "groups" && type === "artboard") {
184197
184368
  items = ctx.boardComments.groups(id3).map((group) => ({ ...group }));
184198
- else if (section === "rounds" && type === "artboard")
184369
+ rounds = ctx.boardComments.rounds(id3).map((round) => ({ ...round }));
184370
+ } else if (section === "rounds" && type === "artboard")
184199
184371
  items = ctx.boardComments.rounds(id3).map((round) => ({ ...round }));
184200
- return ctx.agentReview.state({ ...input, section, items });
184372
+ return ctx.agentReview.state({
184373
+ ...input,
184374
+ section,
184375
+ items,
184376
+ actionable: actionable(section, rounds)
184377
+ });
184201
184378
  }
184202
184379
  function validateSection(input, section) {
184203
184380
  const error = validateReviewQuery({ ...input, section });