camox 0.75.0 → 0.76.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 (30) hide show
  1. package/dist/features/provider/AuthenticatedCamoxProvider.js +75 -63
  2. package/dist/features/routes/pageRuntime.d.ts +6 -4
  3. package/dist/features/routes/pageRuntime.js +5 -1
  4. package/dist/features/studio/components/ChatWidget.js +137 -121
  5. package/dist/features/studio/components/ClearThread.js +121 -0
  6. package/dist/features/studio/components/DeleteDraftDialog.js +67 -65
  7. package/dist/features/studio/components/DraftBar.js +60 -49
  8. package/dist/features/studio/components/DraftNotices.js +149 -0
  9. package/dist/features/studio/components/DraftsControl.js +217 -180
  10. package/dist/features/studio/components/DraftsSheet.js +387 -0
  11. package/dist/features/studio/components/PublishedTab.js +511 -0
  12. package/dist/features/studio/components/ReviewDraftDialog.js +104 -89
  13. package/dist/features/studio/components/SheetTable.js +46 -0
  14. package/dist/features/studio/components/Specialists.js +1 -1
  15. package/dist/features/studio/components/ThreadMessages.js +222 -167
  16. package/dist/features/studio/draftLabel.js +15 -1
  17. package/dist/features/studio/draftNotice.js +1 -0
  18. package/dist/features/studio/studioStore.js +5 -5
  19. package/dist/features/studio/useArchiveDraft.js +60 -0
  20. package/dist/features/studio/useRestoreDraft.js +70 -0
  21. package/dist/features/studio/viewSwitch.js +19 -11
  22. package/dist/lib/draft-scope.d.ts +1 -1
  23. package/dist/lib/draft-scope.js +6 -3
  24. package/dist/lib/queries.js +12 -1
  25. package/dist/lib/studio-reads.js +22 -0
  26. package/dist/lib/use-project-room.js +19 -13
  27. package/dist/lib/use-thread.js +1 -1
  28. package/dist/package.js +1 -1
  29. package/dist/studio.css +1 -1
  30. package/package.json +4 -4
@@ -21,12 +21,12 @@ import { MessageScroller, MessageScrollerButton, MessageScrollerContent, Message
21
21
  * agent does, never how: thinking, looking around, making changes, building, fixing the build,
22
22
  * or starting a draft. Each editor's message shows its
23
23
  * sender's avatar, without their name. A Live turn handed off to a draft ends on the draft's
24
- * card, which `onOpenDraft` opens, and the draft's thread shows the hand-off's Brief collapsed
25
- * under the editor's messages. The thread keeps its end in view, unless the editor scrolls up.
24
+ * card, which `onOpenDraft` opens, or `onRestoreDraft` restores while the draft is archived, and
25
+ * the draft's thread shows the hand-off's Brief collapsed under the editor's messages. The thread keeps its end in view, unless the editor scrolls up.
26
26
  */
27
27
  function ThreadMessages(t0) {
28
- const $ = c(20);
29
- const { view, sending: t1, onOpenDraft } = t0;
28
+ const $ = c(21);
29
+ const { view, sending: t1, onOpenDraft, onRestoreDraft } = t0;
30
30
  const sending = t1 === void 0 ? false : t1;
31
31
  const working = view.running || sending;
32
32
  const empty = view.messages.length === 0 && !working;
@@ -60,14 +60,15 @@ function ThreadMessages(t0) {
60
60
  return t4;
61
61
  }
62
62
  let t2;
63
- if ($[5] !== onOpenDraft || $[6] !== squareling || $[7] !== view || $[8] !== working) {
63
+ if ($[5] !== onOpenDraft || $[6] !== onRestoreDraft || $[7] !== squareling || $[8] !== view || $[9] !== working) {
64
64
  t2 = view.messages.map((message, index) => /* @__PURE__ */ jsxs(MessageScrollerItem, {
65
65
  messageId: message.id,
66
66
  scrollAnchor: message.from === "editor",
67
67
  className: "flex flex-col gap-4",
68
68
  children: [/* @__PURE__ */ jsx(ThreadMessageRow, {
69
69
  message,
70
- onOpenDraft
70
+ onOpenDraft,
71
+ onRestoreDraft
71
72
  }), index === view.messages.length - 1 && /* @__PURE__ */ jsx(AgentPresence, {
72
73
  view,
73
74
  working,
@@ -75,40 +76,41 @@ function ThreadMessages(t0) {
75
76
  })]
76
77
  }, message.id));
77
78
  $[5] = onOpenDraft;
78
- $[6] = squareling;
79
- $[7] = view;
80
- $[8] = working;
81
- $[9] = t2;
82
- } else t2 = $[9];
79
+ $[6] = onRestoreDraft;
80
+ $[7] = squareling;
81
+ $[8] = view;
82
+ $[9] = working;
83
+ $[10] = t2;
84
+ } else t2 = $[10];
83
85
  let t3;
84
- if ($[10] !== squareling || $[11] !== view || $[12] !== working) {
86
+ if ($[11] !== squareling || $[12] !== view || $[13] !== working) {
85
87
  t3 = view.messages.length === 0 && /* @__PURE__ */ jsx(AgentPresence, {
86
88
  view,
87
89
  working,
88
90
  squareling
89
91
  });
90
- $[10] = squareling;
91
- $[11] = view;
92
- $[12] = working;
93
- $[13] = t3;
94
- } else t3 = $[13];
92
+ $[11] = squareling;
93
+ $[12] = view;
94
+ $[13] = working;
95
+ $[14] = t3;
96
+ } else t3 = $[14];
95
97
  let t4;
96
- if ($[14] !== t2 || $[15] !== t3) {
98
+ if ($[15] !== t2 || $[16] !== t3) {
97
99
  t4 = /* @__PURE__ */ jsx(MessageScrollerViewport, { children: /* @__PURE__ */ jsxs(MessageScrollerContent, {
98
100
  className: "flex flex-col gap-4 px-2 py-3",
99
101
  children: [t2, t3]
100
102
  }) });
101
- $[14] = t2;
102
- $[15] = t3;
103
- $[16] = t4;
104
- } else t4 = $[16];
103
+ $[15] = t2;
104
+ $[16] = t3;
105
+ $[17] = t4;
106
+ } else t4 = $[17];
105
107
  let t5;
106
- if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
108
+ if ($[18] === Symbol.for("react.memo_cache_sentinel")) {
107
109
  t5 = /* @__PURE__ */ jsx(MessageScrollerButton, {});
108
- $[17] = t5;
109
- } else t5 = $[17];
110
+ $[18] = t5;
111
+ } else t5 = $[18];
110
112
  let t6;
111
- if ($[18] !== t4) {
113
+ if ($[19] !== t4) {
112
114
  t6 = /* @__PURE__ */ jsx(MessageScrollerProvider, {
113
115
  autoScroll: true,
114
116
  children: /* @__PURE__ */ jsxs(MessageScroller, {
@@ -116,9 +118,9 @@ function ThreadMessages(t0) {
116
118
  children: [t4, t5]
117
119
  })
118
120
  });
119
- $[18] = t4;
120
- $[19] = t6;
121
- } else t6 = $[19];
121
+ $[19] = t4;
122
+ $[20] = t6;
123
+ } else t6 = $[20];
122
124
  return t6;
123
125
  }
124
126
  /** How long the greeting's squareling takes to reach the end of the thread, in ms. */
@@ -301,111 +303,113 @@ const PUSH_OUTCOMES = {
301
303
  notPreviewed: "Built, but the preview can’t show it."
302
304
  };
303
305
  function ThreadMessageRow(t0) {
304
- const $ = c(56);
305
- const { message, onOpenDraft } = t0;
306
+ const $ = c(57);
307
+ const { message, onOpenDraft, onRestoreDraft } = t0;
306
308
  if (message.from === "draft") {
307
309
  let t1;
308
- if ($[0] !== message || $[1] !== onOpenDraft) {
310
+ if ($[0] !== message || $[1] !== onOpenDraft || $[2] !== onRestoreDraft) {
309
311
  t1 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(DraftCard, {
310
312
  message,
311
- onOpenDraft
313
+ onOpenDraft,
314
+ onRestoreDraft
312
315
  }) }) });
313
316
  $[0] = message;
314
317
  $[1] = onOpenDraft;
315
- $[2] = t1;
316
- } else t1 = $[2];
318
+ $[2] = onRestoreDraft;
319
+ $[3] = t1;
320
+ } else t1 = $[3];
317
321
  return t1;
318
322
  }
319
323
  if (message.from === "stopped" || message.from === "failed") {
320
324
  const t1 = message.from === "stopped" ? `Stopped by ${message.sender.name}` : "Camox couldn’t finish this. Send your message again to retry.";
321
325
  let t2;
322
- if ($[3] !== t1) {
326
+ if ($[4] !== t1) {
323
327
  t2 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx("p", {
324
328
  className: "text-muted-foreground text-sm",
325
329
  children: t1
326
330
  }) }) });
327
- $[3] = t1;
328
- $[4] = t2;
329
- } else t2 = $[4];
331
+ $[4] = t1;
332
+ $[5] = t2;
333
+ } else t2 = $[5];
330
334
  return t2;
331
335
  }
332
336
  if (message.from === "agent") {
333
337
  let t1;
334
- if ($[5] !== message.text) {
338
+ if ($[6] !== message.text) {
335
339
  t1 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(ThreadMarkdown, { text: message.text }) }) });
336
- $[5] = message.text;
337
- $[6] = t1;
338
- } else t1 = $[6];
340
+ $[6] = message.text;
341
+ $[7] = t1;
342
+ } else t1 = $[7];
339
343
  return t1;
340
344
  }
341
345
  if (message.from === "push") {
342
346
  const commits = message.subjects.length;
343
347
  let t1;
344
- if ($[7] !== message.sender) {
348
+ if ($[8] !== message.sender) {
345
349
  t1 = /* @__PURE__ */ jsx(MessageAvatar, { children: /* @__PURE__ */ jsx(SenderAvatar, { sender: message.sender }) });
346
- $[7] = message.sender;
347
- $[8] = t1;
348
- } else t1 = $[8];
350
+ $[8] = message.sender;
351
+ $[9] = t1;
352
+ } else t1 = $[9];
349
353
  const t2 = `${message.sender.name} pushed ${commits} ${commits === 1 ? "commit" : "commits"}`;
350
354
  let t3;
351
- if ($[9] !== t2) {
355
+ if ($[10] !== t2) {
352
356
  t3 = /* @__PURE__ */ jsx(MessageHeader, {
353
357
  className: "text-muted-foreground text-xs",
354
358
  children: t2
355
359
  });
356
- $[9] = t2;
357
- $[10] = t3;
358
- } else t3 = $[10];
360
+ $[10] = t2;
361
+ $[11] = t3;
362
+ } else t3 = $[11];
359
363
  let t4;
360
- if ($[11] !== message.subjects) {
364
+ if ($[12] !== message.subjects) {
361
365
  t4 = message.subjects.map(_temp);
362
- $[11] = message.subjects;
363
- $[12] = t4;
364
- } else t4 = $[12];
366
+ $[12] = message.subjects;
367
+ $[13] = t4;
368
+ } else t4 = $[13];
365
369
  let t5;
366
- if ($[13] !== t4) {
370
+ if ($[14] !== t4) {
367
371
  t5 = /* @__PURE__ */ jsx("ul", {
368
372
  className: "flex flex-col gap-0.5",
369
373
  children: t4
370
374
  });
371
- $[13] = t4;
372
- $[14] = t5;
373
- } else t5 = $[14];
375
+ $[14] = t4;
376
+ $[15] = t5;
377
+ } else t5 = $[15];
374
378
  const t6 = PUSH_OUTCOMES[message.outcome];
375
379
  let t7;
376
- if ($[15] !== t6) {
380
+ if ($[16] !== t6) {
377
381
  t7 = /* @__PURE__ */ jsx("span", {
378
382
  className: "text-muted-foreground text-xs",
379
383
  children: t6
380
384
  });
381
- $[15] = t6;
382
- $[16] = t7;
383
- } else t7 = $[16];
385
+ $[16] = t6;
386
+ $[17] = t7;
387
+ } else t7 = $[17];
384
388
  let t8;
385
- if ($[17] !== t5 || $[18] !== t7) {
389
+ if ($[18] !== t5 || $[19] !== t7) {
386
390
  t8 = /* @__PURE__ */ jsxs("div", {
387
391
  "data-thread-push": true,
388
392
  className: DRAFT_CARD_CLASSES,
389
393
  children: [t5, t7]
390
394
  });
391
- $[17] = t5;
392
- $[18] = t7;
393
- $[19] = t8;
394
- } else t8 = $[19];
395
+ $[18] = t5;
396
+ $[19] = t7;
397
+ $[20] = t8;
398
+ } else t8 = $[20];
395
399
  let t9;
396
- if ($[20] !== t3 || $[21] !== t8) {
400
+ if ($[21] !== t3 || $[22] !== t8) {
397
401
  t9 = /* @__PURE__ */ jsxs(MessageContent, { children: [t3, t8] });
398
- $[20] = t3;
399
- $[21] = t8;
400
- $[22] = t9;
401
- } else t9 = $[22];
402
+ $[21] = t3;
403
+ $[22] = t8;
404
+ $[23] = t9;
405
+ } else t9 = $[23];
402
406
  let t10;
403
- if ($[23] !== t1 || $[24] !== t9) {
407
+ if ($[24] !== t1 || $[25] !== t9) {
404
408
  t10 = /* @__PURE__ */ jsxs(Message, { children: [t1, t9] });
405
- $[23] = t1;
406
- $[24] = t9;
407
- $[25] = t10;
408
- } else t10 = $[25];
409
+ $[24] = t1;
410
+ $[25] = t9;
411
+ $[26] = t10;
412
+ } else t10 = $[26];
409
413
  return t10;
410
414
  }
411
415
  if (message.from === "connectedAgent") {
@@ -415,13 +419,13 @@ function ThreadMessageRow(t0) {
415
419
  const t1 = `${sender} added context`;
416
420
  const t2 = client.verified ? void 0 : client.name;
417
421
  let t3;
418
- if ($[26] !== message.attachments) {
422
+ if ($[27] !== message.attachments) {
419
423
  t3 = message.attachments && /* @__PURE__ */ jsx(AttachmentThumbnails, { attachments: message.attachments });
420
- $[26] = message.attachments;
421
- $[27] = t3;
422
- } else t3 = $[27];
424
+ $[27] = message.attachments;
425
+ $[28] = t3;
426
+ } else t3 = $[28];
423
427
  let t4;
424
- if ($[28] !== message.text || $[29] !== t1 || $[30] !== t2 || $[31] !== t3) {
428
+ if ($[29] !== message.text || $[30] !== t1 || $[31] !== t2 || $[32] !== t3) {
425
429
  t4 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(CollapsedNote, {
426
430
  label: t1,
427
431
  hideLabel: "Hide the context",
@@ -429,117 +433,117 @@ function ThreadMessageRow(t0) {
429
433
  text: message.text,
430
434
  children: t3
431
435
  }) }) });
432
- $[28] = message.text;
433
- $[29] = t1;
434
- $[30] = t2;
435
- $[31] = t3;
436
- $[32] = t4;
437
- } else t4 = $[32];
436
+ $[29] = message.text;
437
+ $[30] = t1;
438
+ $[31] = t2;
439
+ $[32] = t3;
440
+ $[33] = t4;
441
+ } else t4 = $[33];
438
442
  return t4;
439
443
  }
440
444
  const t1 = client.verified ? void 0 : client.name;
441
445
  let t2;
442
- if ($[33] !== sender || $[34] !== t1) {
446
+ if ($[34] !== sender || $[35] !== t1) {
443
447
  t2 = /* @__PURE__ */ jsx(MessageHeader, {
444
448
  className: "text-muted-foreground text-xs",
445
449
  title: t1,
446
450
  children: sender
447
451
  });
448
- $[33] = sender;
449
- $[34] = t1;
450
- $[35] = t2;
451
- } else t2 = $[35];
452
+ $[34] = sender;
453
+ $[35] = t1;
454
+ $[36] = t2;
455
+ } else t2 = $[36];
452
456
  let t3;
453
- if ($[36] !== message.text) {
457
+ if ($[37] !== message.text) {
454
458
  t3 = /* @__PURE__ */ jsx(Bubble, {
455
459
  variant: "muted",
456
460
  className: "max-w-full",
457
461
  children: /* @__PURE__ */ jsx(BubbleContent, { children: /* @__PURE__ */ jsx(CroppedText, { text: message.text }) })
458
462
  });
459
- $[36] = message.text;
460
- $[37] = t3;
461
- } else t3 = $[37];
463
+ $[37] = message.text;
464
+ $[38] = t3;
465
+ } else t3 = $[38];
462
466
  let t4;
463
- if ($[38] !== message.attachments) {
467
+ if ($[39] !== message.attachments) {
464
468
  t4 = message.attachments && /* @__PURE__ */ jsx(AttachmentThumbnails, { attachments: message.attachments });
465
- $[38] = message.attachments;
466
- $[39] = t4;
467
- } else t4 = $[39];
469
+ $[39] = message.attachments;
470
+ $[40] = t4;
471
+ } else t4 = $[40];
468
472
  let t5;
469
- if ($[40] !== t2 || $[41] !== t3 || $[42] !== t4) {
473
+ if ($[41] !== t2 || $[42] !== t3 || $[43] !== t4) {
470
474
  t5 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsxs(MessageContent, { children: [
471
475
  t2,
472
476
  t3,
473
477
  t4
474
478
  ] }) });
475
- $[40] = t2;
476
- $[41] = t3;
477
- $[42] = t4;
478
- $[43] = t5;
479
- } else t5 = $[43];
479
+ $[41] = t2;
480
+ $[42] = t3;
481
+ $[43] = t4;
482
+ $[44] = t5;
483
+ } else t5 = $[44];
480
484
  return t5;
481
485
  }
482
486
  if (message.from === "brief") {
483
487
  let t1;
484
- if ($[44] !== message.text) {
488
+ if ($[45] !== message.text) {
485
489
  t1 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(CollapsedNote, {
486
490
  label: "Camox briefed the agent",
487
491
  hideLabel: "Hide the brief",
488
492
  text: message.text
489
493
  }) }) });
490
- $[44] = message.text;
491
- $[45] = t1;
492
- } else t1 = $[45];
494
+ $[45] = message.text;
495
+ $[46] = t1;
496
+ } else t1 = $[46];
493
497
  return t1;
494
498
  }
495
499
  if (message.from === "camox") {
496
500
  let t1;
497
- if ($[46] === Symbol.for("react.memo_cache_sentinel")) {
501
+ if ($[47] === Symbol.for("react.memo_cache_sentinel")) {
498
502
  t1 = /* @__PURE__ */ jsx(MessageHeader, {
499
503
  className: "text-muted-foreground text-xs",
500
504
  children: "Camox"
501
505
  });
502
- $[46] = t1;
503
- } else t1 = $[46];
506
+ $[47] = t1;
507
+ } else t1 = $[47];
504
508
  let t2;
505
- if ($[47] !== message.text) {
509
+ if ($[48] !== message.text) {
506
510
  t2 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsxs(MessageContent, { children: [t1, /* @__PURE__ */ jsx(Bubble, {
507
511
  variant: "muted",
508
512
  className: "max-w-full",
509
513
  children: /* @__PURE__ */ jsx(BubbleContent, { children: /* @__PURE__ */ jsx(CroppedText, { text: message.text }) })
510
514
  })] }) });
511
- $[47] = message.text;
512
- $[48] = t2;
513
- } else t2 = $[48];
515
+ $[48] = message.text;
516
+ $[49] = t2;
517
+ } else t2 = $[49];
514
518
  return t2;
515
519
  }
516
520
  let t1;
517
- if ($[49] !== message.sender) {
521
+ if ($[50] !== message.sender) {
518
522
  t1 = /* @__PURE__ */ jsx(MessageAvatar, { children: /* @__PURE__ */ jsx(SenderAvatar, { sender: message.sender }) });
519
- $[49] = message.sender;
520
- $[50] = t1;
521
- } else t1 = $[50];
523
+ $[50] = message.sender;
524
+ $[51] = t1;
525
+ } else t1 = $[51];
522
526
  let t2;
523
- if ($[51] !== message.text) {
527
+ if ($[52] !== message.text) {
524
528
  t2 = /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(Bubble, {
525
529
  align: "end",
526
530
  variant: "muted",
527
531
  className: "max-w-full",
528
532
  children: /* @__PURE__ */ jsx(BubbleContent, { children: /* @__PURE__ */ jsx(CroppedText, { text: message.text }) })
529
533
  }) });
530
- $[51] = message.text;
531
- $[52] = t2;
532
- } else t2 = $[52];
534
+ $[52] = message.text;
535
+ $[53] = t2;
536
+ } else t2 = $[53];
533
537
  let t3;
534
- if ($[53] !== t1 || $[54] !== t2) {
538
+ if ($[54] !== t1 || $[55] !== t2) {
535
539
  t3 = /* @__PURE__ */ jsxs(Message, {
536
540
  align: "end",
537
541
  children: [t1, t2]
538
542
  });
539
- $[53] = t1;
540
- $[54] = t2;
541
- $[55] = t3;
542
- } else t3 = $[55];
543
+ $[54] = t1;
544
+ $[55] = t2;
545
+ $[56] = t3;
546
+ } else t3 = $[56];
543
547
  return t3;
544
548
  }
545
549
  function _temp(subject, index) {
@@ -822,10 +826,11 @@ const DRAFT_CARD_CLASSES = "bg-muted/50 flex w-full flex-col items-start gap-0.5
822
826
  /**
823
827
  * The card of the draft the agent on Live handed the request off to, where its agent does the
824
828
  * work: it opens the draft. Once the draft ended, there's nothing to open: it says how it ended.
829
+ * While the draft is archived, it says so and offers to restore it (ADR 0046).
825
830
  */
826
831
  function DraftCard(t0) {
827
- const $ = c(15);
828
- const { message, onOpenDraft } = t0;
832
+ const $ = c(27);
833
+ const { message, onOpenDraft, onRestoreDraft } = t0;
829
834
  let t1;
830
835
  if ($[0] !== message.name) {
831
836
  t1 = /* @__PURE__ */ jsx("span", {
@@ -836,65 +841,115 @@ function DraftCard(t0) {
836
841
  $[1] = t1;
837
842
  } else t1 = $[1];
838
843
  const name = t1;
844
+ if (message.archived) {
845
+ let t2;
846
+ if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
847
+ t2 = cn(DRAFT_CARD_CLASSES, "flex-row items-center gap-3");
848
+ $[2] = t2;
849
+ } else t2 = $[2];
850
+ let t3;
851
+ if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
852
+ t3 = /* @__PURE__ */ jsx("span", {
853
+ className: "text-muted-foreground text-xs",
854
+ children: "Archived"
855
+ });
856
+ $[3] = t3;
857
+ } else t3 = $[3];
858
+ let t4;
859
+ if ($[4] !== name) {
860
+ t4 = /* @__PURE__ */ jsxs("div", {
861
+ className: "flex min-w-0 flex-1 flex-col gap-0.5",
862
+ children: [t3, name]
863
+ });
864
+ $[4] = name;
865
+ $[5] = t4;
866
+ } else t4 = $[5];
867
+ let t5;
868
+ if ($[6] !== message.draftId || $[7] !== onRestoreDraft) {
869
+ t5 = /* @__PURE__ */ jsx(Button, {
870
+ variant: "outline",
871
+ size: "sm",
872
+ onClick: () => onRestoreDraft?.(message.draftId),
873
+ children: "Restore"
874
+ });
875
+ $[6] = message.draftId;
876
+ $[7] = onRestoreDraft;
877
+ $[8] = t5;
878
+ } else t5 = $[8];
879
+ let t6;
880
+ if ($[9] !== t4 || $[10] !== t5) {
881
+ t6 = /* @__PURE__ */ jsxs("div", {
882
+ "data-thread-draft-card": true,
883
+ className: t2,
884
+ children: [t4, t5]
885
+ });
886
+ $[9] = t4;
887
+ $[10] = t5;
888
+ $[11] = t6;
889
+ } else t6 = $[11];
890
+ return t6;
891
+ }
839
892
  if (message.ended) {
840
893
  const t2 = message.ended === "published" ? "Published" : "Deleted";
841
894
  let t3;
842
- if ($[2] !== t2) {
895
+ if ($[12] !== t2) {
843
896
  t3 = /* @__PURE__ */ jsx("span", {
844
897
  className: "text-muted-foreground text-xs",
845
898
  children: t2
846
899
  });
847
- $[2] = t2;
848
- $[3] = t3;
849
- } else t3 = $[3];
900
+ $[12] = t2;
901
+ $[13] = t3;
902
+ } else t3 = $[13];
850
903
  let t4;
851
- if ($[4] !== name || $[5] !== t3) {
904
+ if ($[14] !== name || $[15] !== t3) {
852
905
  t4 = /* @__PURE__ */ jsxs("div", {
853
906
  "data-thread-draft-card": true,
854
907
  className: DRAFT_CARD_CLASSES,
855
908
  children: [t3, name]
856
909
  });
857
- $[4] = name;
858
- $[5] = t3;
859
- $[6] = t4;
860
- } else t4 = $[6];
910
+ $[14] = name;
911
+ $[15] = t3;
912
+ $[16] = t4;
913
+ } else t4 = $[16];
861
914
  return t4;
862
915
  }
863
916
  let t2;
864
- if ($[7] !== message.draftId || $[8] !== onOpenDraft) {
917
+ if ($[17] !== message.draftId || $[18] !== onOpenDraft) {
865
918
  t2 = () => onOpenDraft?.(message.draftId);
866
- $[7] = message.draftId;
867
- $[8] = onOpenDraft;
868
- $[9] = t2;
869
- } else t2 = $[9];
919
+ $[17] = message.draftId;
920
+ $[18] = onOpenDraft;
921
+ $[19] = t2;
922
+ } else t2 = $[19];
870
923
  let t3;
871
- let t4;
872
- if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
924
+ if ($[20] === Symbol.for("react.memo_cache_sentinel")) {
873
925
  t3 = cn(DRAFT_CARD_CLASSES, "hover:bg-muted focus-visible:ring-ring transition-colors focus-visible:ring-2 focus-visible:outline-none");
874
- t4 = /* @__PURE__ */ jsx("span", {
926
+ $[20] = t3;
927
+ } else t3 = $[20];
928
+ const t4 = message.restored ? "Restored a draft" : "Started a draft";
929
+ let t5;
930
+ if ($[21] !== t4) {
931
+ t5 = /* @__PURE__ */ jsx("span", {
875
932
  className: "text-muted-foreground text-xs",
876
- children: "Started a draft"
933
+ children: t4
877
934
  });
878
- $[10] = t3;
879
- $[11] = t4;
880
- } else {
881
- t3 = $[10];
882
- t4 = $[11];
883
- }
884
- let t5;
885
- if ($[12] !== name || $[13] !== t2) {
886
- t5 = /* @__PURE__ */ jsxs("button", {
935
+ $[21] = t4;
936
+ $[22] = t5;
937
+ } else t5 = $[22];
938
+ let t6;
939
+ if ($[23] !== name || $[24] !== t2 || $[25] !== t5) {
940
+ t6 = /* @__PURE__ */ jsxs("button", {
887
941
  type: "button",
888
942
  "data-thread-draft-card": true,
889
943
  onClick: t2,
890
944
  className: t3,
891
- children: [t4, name]
945
+ children: [t5, name]
892
946
  });
893
- $[12] = name;
894
- $[13] = t2;
895
- $[14] = t5;
896
- } else t5 = $[14];
897
- return t5;
947
+ $[23] = name;
948
+ $[24] = t2;
949
+ $[25] = t5;
950
+ $[26] = t6;
951
+ } else t6 = $[26];
952
+ return t6;
898
953
  }
899
954
  function SenderAvatar(t0) {
900
955
  const $ = c(10);
@@ -11,6 +11,14 @@ function draftLabel(draft) {
11
11
  if (draft.name) return draft.name;
12
12
  return `${draft.createdBy.name}, ${dayFormat.format(draft.createdAt)}`;
13
13
  }
14
+ /**
15
+ * A Publication's name: its draft's, or for a draft published before it was named, who published
16
+ * it and when, e.g. "Rémi, Oct 13".
17
+ */
18
+ function publicationLabel(publication) {
19
+ if (publication.name) return publication.name;
20
+ return `${publication.publishedBy.name}, ${dayFormat.format(publication.publishedAt)}`;
21
+ }
14
22
  const relative = new Intl.RelativeTimeFormat(void 0, { numeric: "auto" });
15
23
  const units = [
16
24
  ["year", 31536e6],
@@ -26,7 +34,13 @@ function timeAgo(at, now = Date.now()) {
26
34
  for (const [unit, size] of units) if (elapsed >= size) return relative.format(-Math.round(elapsed / size), unit);
27
35
  return relative.format(0, "minute");
28
36
  }
37
+ const DAY_MS = 864e5;
38
+ /** How long until a moment, in whole days: "12 days", or "Less than a day" on its last day. */
39
+ function daysLeft(until, now = Date.now()) {
40
+ const days = Math.floor((until - now) / DAY_MS);
41
+ return days < 1 ? "Less than a day" : plural(days, "day");
42
+ }
29
43
  const plural = (count, word) => `${count} ${word}${count === 1 ? "" : "s"}`;
30
44
 
31
45
  //#endregion
32
- export { draftLabel, plural, timeAgo };
46
+ export { daysLeft, draftLabel, plural, publicationLabel, timeAgo };
@@ -5,6 +5,7 @@ function draftNoticeMessage(notice) {
5
5
  case "missing": return "This draft doesn't exist, so you're viewing Live.";
6
6
  case "forbidden": return "You can't open this draft, so you're viewing Live.";
7
7
  case "ended": return `${notice.endedBy.name} ${notice.outcome} this draft, so you're viewing Live.`;
8
+ case "archived": return `${notice.archivedBy.name} archived this draft, so you're viewing Live.`;
8
9
  }
9
10
  }
10
11