@ai-matrx/content-ir-react 0.18.0 → 0.18.1

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/react.cjs CHANGED
@@ -329,6 +329,34 @@ function classIcon(directiveClass, noun) {
329
329
 
330
330
  // directives/ApplyDirectiveButton.tsx
331
331
  var import_jsx_runtime4 = require("react/jsx-runtime");
332
+ var applyOutcomes = /* @__PURE__ */ new WeakMap();
333
+ var EMPTY_AUTHORITY = {};
334
+ var outcomeListeners = /* @__PURE__ */ new Set();
335
+ function outcomesOf(host) {
336
+ let held = applyOutcomes.get(host);
337
+ if (!held) {
338
+ held = /* @__PURE__ */ new Map();
339
+ applyOutcomes.set(host, held);
340
+ }
341
+ return held;
342
+ }
343
+ function publishOutcome(host, identity, outcome) {
344
+ outcomesOf(host).set(identity, outcome);
345
+ for (const listener of outcomeListeners) listener();
346
+ }
347
+ function subscribeOutcomes(listener) {
348
+ outcomeListeners.add(listener);
349
+ return () => {
350
+ outcomeListeners.delete(listener);
351
+ };
352
+ }
353
+ function useApplyOutcome(host, identity) {
354
+ return (0, import_react4.useSyncExternalStore)(
355
+ subscribeOutcomes,
356
+ () => applyOutcomes.get(host)?.get(identity) ?? null,
357
+ () => null
358
+ );
359
+ }
332
360
  var FINISH_POLL_MS = 2e3;
333
361
  var FINISH_POLLS_MAX = 30;
334
362
  function readsApplyLedger(host, directive) {
@@ -360,6 +388,8 @@ function ApplyDirectiveButton({
360
388
  setAskingAgain(false);
361
389
  setElapsed(0);
362
390
  }
391
+ const shared = useApplyOutcome(host.confirm ?? EMPTY_AUTHORITY, identity);
392
+ const view = state.status === "asking" || !shared ? state : shared;
363
393
  const currentIdentity = (0, import_react4.useRef)(identity);
364
394
  (0, import_react4.useEffect)(() => {
365
395
  currentIdentity.current = identity;
@@ -413,33 +443,34 @@ function ApplyDirectiveButton({
413
443
  if (timer) clearTimeout(timer);
414
444
  };
415
445
  }, [shellKey, read, report]);
416
- const appliedClean = state.status === "applied" && state.failed === 0 ? state : null;
446
+ const appliedClean = view.status === "applied" && view.failed === 0 ? view : null;
417
447
  const appliedBefore = appliedClean ? appliedClean.before : null;
418
- const phaseKey = state.status === "checking" || state.status === "finishing" ? "pending" : appliedClean ? `applied:${JSON.stringify(appliedBefore)}` : "open";
448
+ const phaseKey = view.status === "checking" || view.status === "finishing" ? "pending" : appliedClean ? `applied:${JSON.stringify(appliedBefore)}` : "open";
419
449
  (0, import_react4.useEffect)(() => {
420
450
  if (!onPhase) return;
421
451
  if (phaseKey === "pending") onPhase({ phase: "pending" });
422
452
  else if (phaseKey === "open") onPhase({ phase: "open" });
423
453
  else onPhase({ phase: "applied", before: appliedBefore });
424
454
  }, [phaseKey, onPhase, appliedBefore]);
455
+ const applyingSince = view.status === "applying" ? view.startedAt : null;
425
456
  (0, import_react4.useEffect)(() => {
426
- if (state.status !== "applying") return;
427
- startedAt.current = Date.now();
457
+ if (applyingSince === null) return;
458
+ startedAt.current = applyingSince;
428
459
  const id = setInterval(
429
460
  () => setElapsed(Math.round((Date.now() - (startedAt.current ?? 0)) / 1e3)),
430
461
  1e3
431
462
  );
432
463
  return () => clearInterval(id);
433
- }, [state.status]);
464
+ }, [applyingSince]);
434
465
  if (!directive.parsed.executes) return null;
435
466
  const confirm = host.confirm;
436
467
  if (!confirm) return null;
437
468
  async function handleApply(again = false) {
438
469
  if (!confirm) return;
439
- const prior = state;
470
+ const prior = view;
440
471
  const askedFor = identity;
441
472
  const stillHere = () => currentIdentity.current === askedFor;
442
- const priorCopies = state.status === "applied" ? state.copies : 0;
473
+ const priorCopies = view.status === "applied" ? view.copies : 0;
443
474
  if (host.ask) {
444
475
  if (again) setAskingAgain(true);
445
476
  else setState({ status: "asking" });
@@ -468,14 +499,14 @@ function ApplyDirectiveButton({
468
499
  }
469
500
  }
470
501
  setElapsed(0);
471
- setState({ status: "applying" });
502
+ setState((prev) => prev.status === "asking" ? { status: "idle" } : prev);
503
+ publishOutcome(confirm, askedFor, { status: "applying", startedAt: Date.now() });
472
504
  try {
473
505
  const shell = { __kind: directive.slug, items };
474
506
  if (conversationId) shell.conversationId = conversationId;
475
507
  if (again) shell.force = true;
476
508
  const result = await confirm(shell);
477
- if (!stillHere()) return;
478
- setState({
509
+ publishOutcome(confirm, askedFor, {
479
510
  status: "applied",
480
511
  applied: result.applied,
481
512
  failed: result.failed,
@@ -487,20 +518,19 @@ function ApplyDirectiveButton({
487
518
  // apply replaced is still the change this block made.
488
519
  before: again && prior.status === "applied" && prior.before ? prior.before : result.before ?? null
489
520
  });
490
- onApplied?.();
521
+ if (stillHere()) onApplied?.();
491
522
  } catch (error) {
492
- if (!stillHere()) return;
493
- setState({
523
+ publishOutcome(confirm, askedFor, {
494
524
  status: "error",
495
525
  message: error instanceof Error && error.message ? error.message : "That couldn't be applied just now. Please try again."
496
526
  });
497
527
  }
498
528
  }
499
- if (state.status === "applied") {
500
- const bad = state.failed > 0;
529
+ if (view.status === "applied") {
530
+ const bad = view.failed > 0;
501
531
  const trashed = directive.directiveClass === "delete";
502
532
  const label2 = nounText;
503
- const records = host.renderRecord ? state.records : [];
533
+ const records = host.renderRecord ? view.records : [];
504
534
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
505
535
  "span",
506
536
  {
@@ -514,26 +544,26 @@ function ApplyDirectiveButton({
514
544
  {
515
545
  words: failureWords(
516
546
  {
517
- raw: state.message ?? `${state.failed} failed`,
547
+ raw: view.message ?? `${view.failed} failed`,
518
548
  directiveClass: directive.directiveClass,
519
549
  noun: directive.noun,
520
550
  nounLabel: nounText,
521
- failed: state.failed,
522
- total: state.applied + state.failed
551
+ failed: view.failed,
552
+ total: view.applied + view.failed
523
553
  },
524
554
  host.explainFailure
525
555
  ),
526
- raw: state.message
556
+ raw: view.message
527
557
  }
528
- ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "min-w-0", children: state.message ?? `Applied ${state.applied}` })
558
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "min-w-0", children: view.message ?? `Applied ${view.applied}` })
529
559
  ] }),
530
- state.copies > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
560
+ view.copies > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
531
561
  "span",
532
562
  {
533
563
  className: "shrink-0 text-muted-foreground",
534
- "data-apply-copies": state.copies,
564
+ "data-apply-copies": view.copies,
535
565
  title: records.length > 0 ? directive.directiveClass === "create" ? "Links to the latest copy." : "Links to the latest run." : void 0,
536
- children: directive.directiveClass === "create" ? `${state.copies} copies` : `Ran ${state.copies} times`
566
+ children: directive.directiveClass === "create" ? `${view.copies} copies` : `Ran ${view.copies} times`
537
567
  }
538
568
  ) : null,
539
569
  records.map((record) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "inline-flex min-w-0 items-center", children: host.renderRecord?.({
@@ -560,7 +590,7 @@ function ApplyDirectiveButton({
560
590
  }
561
591
  );
562
592
  }
563
- if (state.status === "checking") {
593
+ if (view.status === "checking") {
564
594
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
565
595
  "span",
566
596
  {
@@ -572,7 +602,7 @@ function ApplyDirectiveButton({
572
602
  }
573
603
  );
574
604
  }
575
- if (state.status === "finishing") {
605
+ if (view.status === "finishing") {
576
606
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
577
607
  "span",
578
608
  {
@@ -587,7 +617,7 @@ function ApplyDirectiveButton({
587
617
  );
588
618
  }
589
619
  const destructive = directive.directiveClass === "delete";
590
- const muted = nothingToChange && state.status === "idle";
620
+ const muted = nothingToChange && view.status === "idle";
591
621
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "inline-flex items-center gap-2", children: [
592
622
  muted ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-xs text-muted-foreground", "data-apply-nothing": "", children: "Nothing to change" }) : null,
593
623
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
@@ -595,17 +625,17 @@ function ApplyDirectiveButton({
595
625
  {
596
626
  type: "button",
597
627
  onClick: () => void handleApply(),
598
- disabled: state.status === "applying" || state.status === "asking" || items.length === 0,
628
+ disabled: view.status === "applying" || view.status === "asking" || items.length === 0,
599
629
  "data-apply-tone": muted ? "muted" : destructive ? "destructive" : "default",
600
630
  title: muted ? "It sets no fields, so applying it changes nothing." : void 0,
601
631
  className: `inline-flex items-center gap-1 rounded-md border px-2 py-1 text-xs font-medium disabled:opacity-50 ${muted ? "border-border/60 bg-background text-muted-foreground hover:bg-accent" : destructive ? "border-destructive/50 bg-background text-destructive hover:bg-destructive/10" : "border-border bg-background hover:bg-accent"}`,
602
632
  children: [
603
- state.status === "applying" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PlayIcon, { className: "h-3.5 w-3.5" }),
604
- state.status === "applying" ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? "item" : "items"}` : ""}\u2026${elapsed ? ` ${elapsed}s` : ""}` : label
633
+ view.status === "applying" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PlayIcon, { className: "h-3.5 w-3.5" }),
634
+ view.status === "applying" ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? "item" : "items"}` : ""}\u2026${elapsed ? ` ${elapsed}s` : ""}` : label
605
635
  ]
606
636
  }
607
637
  ),
608
- state.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
638
+ view.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
609
639
  "span",
610
640
  {
611
641
  className: "inline-flex max-w-sm items-start gap-1 text-xs text-destructive",
@@ -617,14 +647,14 @@ function ApplyDirectiveButton({
617
647
  {
618
648
  words: failureWords(
619
649
  {
620
- raw: state.message,
650
+ raw: view.message,
621
651
  directiveClass: directive.directiveClass,
622
652
  noun: directive.noun,
623
653
  nounLabel: nounText
624
654
  },
625
655
  host.explainFailure
626
656
  ),
627
- raw: state.message
657
+ raw: view.message
628
658
  }
629
659
  )
630
660
  ]