@ai-matrx/content-ir-react 0.18.1 → 0.19.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.
@@ -44,7 +44,7 @@ function resetDirectiveRenderers() {
44
44
  }
45
45
 
46
46
  // directives/ApplyDirectiveButton.tsx
47
- import { useEffect, useRef, useState, useSyncExternalStore } from "react";
47
+ import { useEffect as useEffect2, useRef, useState as useState2, useSyncExternalStore as useSyncExternalStore2 } from "react";
48
48
  import { nounLabel } from "@ai-matrx/content-ir";
49
49
 
50
50
  // directives/item-changes.ts
@@ -123,6 +123,64 @@ function itemChanges(item, current, options = {}) {
123
123
  return out;
124
124
  }
125
125
 
126
+ // directives/record-values.ts
127
+ import { useEffect, useState, useSyncExternalStore } from "react";
128
+ var revisions = /* @__PURE__ */ new Map();
129
+ var listeners = /* @__PURE__ */ new Set();
130
+ function recordRevision(id) {
131
+ return revisions.get(id) ?? 0;
132
+ }
133
+ function noteRecordChanged(id) {
134
+ if (!id) return;
135
+ revisions.set(id, recordRevision(id) + 1);
136
+ for (const listener of listeners) listener();
137
+ }
138
+ function subscribeRevisions(listener) {
139
+ listeners.add(listener);
140
+ return () => {
141
+ listeners.delete(listener);
142
+ };
143
+ }
144
+ function useRecordRevision(id) {
145
+ return useSyncExternalStore(
146
+ subscribeRevisions,
147
+ () => recordRevision(id),
148
+ () => 0
149
+ );
150
+ }
151
+ function useRecordValues(read, ref) {
152
+ const revision = useRecordRevision(ref?.id ?? "");
153
+ const key = ref && read ? `${ref.noun}:${ref.id}#${revision}` : "";
154
+ const [result, setResult] = useState({
155
+ key: "",
156
+ values: null,
157
+ status: "idle"
158
+ });
159
+ useEffect(() => {
160
+ if (!key || !read) return;
161
+ const split = key.indexOf(":");
162
+ const target = {
163
+ noun: key.slice(0, split),
164
+ id: key.slice(split + 1, key.lastIndexOf("#"))
165
+ };
166
+ let live = true;
167
+ setResult({ key, values: null, status: "loading" });
168
+ read(target).then((values) => {
169
+ if (!live) return;
170
+ setResult({ key, values, status: values ? "ready" : "unavailable" });
171
+ }).catch(() => {
172
+ if (!live) return;
173
+ setResult({ key, values: null, status: "unavailable" });
174
+ });
175
+ return () => {
176
+ live = false;
177
+ };
178
+ }, [key, read]);
179
+ if (!key) return { values: null, status: "idle" };
180
+ if (result.key !== key) return { values: null, status: "loading" };
181
+ return { values: result.values, status: result.status };
182
+ }
183
+
126
184
  // directives/failure-words.ts
127
185
  var PAST = {
128
186
  create: "created",
@@ -242,6 +300,13 @@ function classIcon(directiveClass, noun) {
242
300
 
243
301
  // directives/ApplyDirectiveButton.tsx
244
302
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
303
+ function announceChangedRecords(directive, items) {
304
+ if (!TARGETING_CLASSES.has(directive.directiveClass)) return;
305
+ for (const item of items) {
306
+ const id = itemRecordId(item);
307
+ if (id) noteRecordChanged(id);
308
+ }
309
+ }
245
310
  var applyOutcomes = /* @__PURE__ */ new WeakMap();
246
311
  var EMPTY_AUTHORITY = {};
247
312
  var outcomeListeners = /* @__PURE__ */ new Set();
@@ -264,7 +329,7 @@ function subscribeOutcomes(listener) {
264
329
  };
265
330
  }
266
331
  function useApplyOutcome(host, identity) {
267
- return useSyncExternalStore(
332
+ return useSyncExternalStore2(
268
333
  subscribeOutcomes,
269
334
  () => applyOutcomes.get(host)?.get(identity) ?? null,
270
335
  () => null
@@ -289,12 +354,12 @@ function ApplyDirectiveButton({
289
354
  const items = directive.items;
290
355
  const readsLedger = readsApplyLedger(host, directive);
291
356
  const initial = readsLedger ? { status: "checking" } : { status: "idle" };
292
- const [state, setState] = useState(initial);
293
- const [elapsed, setElapsed] = useState(0);
294
- const [askingAgain, setAskingAgain] = useState(false);
357
+ const [state, setState] = useState2(initial);
358
+ const [elapsed, setElapsed] = useState2(0);
359
+ const [askingAgain, setAskingAgain] = useState2(false);
295
360
  const startedAt = useRef(null);
296
361
  const identity = JSON.stringify([directive.slug, items, conversationId ?? null]);
297
- const [stateFor, setStateFor] = useState(identity);
362
+ const [stateFor, setStateFor] = useState2(identity);
298
363
  if (stateFor !== identity) {
299
364
  setStateFor(identity);
300
365
  setState(initial);
@@ -304,14 +369,14 @@ function ApplyDirectiveButton({
304
369
  const shared = useApplyOutcome(host.confirm ?? EMPTY_AUTHORITY, identity);
305
370
  const view = state.status === "asking" || !shared ? state : shared;
306
371
  const currentIdentity = useRef(identity);
307
- useEffect(() => {
372
+ useEffect2(() => {
308
373
  currentIdentity.current = identity;
309
374
  }, [identity]);
310
375
  const nounText = nounLabel(directive.noun, host.nouns);
311
376
  const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : "";
312
377
  const read = host.applyState;
313
378
  const report = host.reportError;
314
- useEffect(() => {
379
+ useEffect2(() => {
315
380
  if (!shellKey || !read) return;
316
381
  const [slug, shellItems, inConversation] = JSON.parse(shellKey);
317
382
  const shell = { __kind: slug, items: shellItems };
@@ -359,14 +424,14 @@ function ApplyDirectiveButton({
359
424
  const appliedClean = view.status === "applied" && view.failed === 0 ? view : null;
360
425
  const appliedBefore = appliedClean ? appliedClean.before : null;
361
426
  const phaseKey = view.status === "checking" || view.status === "finishing" ? "pending" : appliedClean ? `applied:${JSON.stringify(appliedBefore)}` : "open";
362
- useEffect(() => {
427
+ useEffect2(() => {
363
428
  if (!onPhase) return;
364
429
  if (phaseKey === "pending") onPhase({ phase: "pending" });
365
430
  else if (phaseKey === "open") onPhase({ phase: "open" });
366
431
  else onPhase({ phase: "applied", before: appliedBefore });
367
432
  }, [phaseKey, onPhase, appliedBefore]);
368
433
  const applyingSince = view.status === "applying" ? view.startedAt : null;
369
- useEffect(() => {
434
+ useEffect2(() => {
370
435
  if (applyingSince === null) return;
371
436
  startedAt.current = applyingSince;
372
437
  const id = setInterval(
@@ -418,7 +483,13 @@ function ApplyDirectiveButton({
418
483
  const shell = { __kind: directive.slug, items };
419
484
  if (conversationId) shell.conversationId = conversationId;
420
485
  if (again) shell.force = true;
421
- const result = await confirm(shell);
486
+ let result;
487
+ try {
488
+ result = await confirm(shell);
489
+ } finally {
490
+ announceChangedRecords(directive, items);
491
+ }
492
+ for (const record of result.records ?? []) noteRecordChanged(record.id);
422
493
  publishOutcome(confirm, askedFor, {
423
494
  status: "applied",
424
495
  applied: result.applied,
@@ -579,7 +650,7 @@ function FailureNotice({
579
650
  words,
580
651
  raw
581
652
  }) {
582
- const [open, setOpen] = useState(false);
653
+ const [open, setOpen] = useState2(false);
583
654
  const detail = raw?.trim() ?? "";
584
655
  return /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 flex-col gap-0.5", "data-apply-failure": true, children: [
585
656
  /* @__PURE__ */ jsxs2("span", { className: "min-w-0", children: [
@@ -620,39 +691,6 @@ import {
620
691
  nounLabel as nounLabel2,
621
692
  nounTitleColumn
622
693
  } from "@ai-matrx/content-ir";
623
-
624
- // directives/record-values.ts
625
- import { useEffect as useEffect2, useState as useState2 } from "react";
626
- function useRecordValues(read, ref) {
627
- const key = ref && read ? `${ref.noun}:${ref.id}` : "";
628
- const [result, setResult] = useState2({
629
- key: "",
630
- values: null,
631
- status: "idle"
632
- });
633
- useEffect2(() => {
634
- if (!key || !read) return;
635
- const split = key.indexOf(":");
636
- const target = { noun: key.slice(0, split), id: key.slice(split + 1) };
637
- let live = true;
638
- setResult({ key, values: null, status: "loading" });
639
- read(target).then((values) => {
640
- if (!live) return;
641
- setResult({ key, values, status: values ? "ready" : "unavailable" });
642
- }).catch(() => {
643
- if (!live) return;
644
- setResult({ key, values: null, status: "unavailable" });
645
- });
646
- return () => {
647
- live = false;
648
- };
649
- }, [key, read]);
650
- if (!key) return { values: null, status: "idle" };
651
- if (result.key !== key) return { values: null, status: "loading" };
652
- return { values: result.values, status: result.status };
653
- }
654
-
655
- // directives/SideEffectDirectiveCard.tsx
656
694
  import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
657
695
  var ROWS_BEFORE_FOLD = 3;
658
696
  function ItemRow({
@@ -956,13 +994,16 @@ export {
956
994
  getDirectiveRenderer,
957
995
  itemChanges,
958
996
  itemRecordId,
997
+ noteRecordChanged,
959
998
  provisionalDirectiveSlug,
960
999
  readsApplyLedger,
961
1000
  recordFallbackName,
1001
+ recordRevision,
962
1002
  registerDirectiveRenderer,
963
1003
  resetDirectiveRenderers,
964
1004
  useDirectiveHost,
965
1005
  useDirectiveScope,
1006
+ useRecordRevision,
966
1007
  useRecordValues
967
1008
  };
968
1009
  //# sourceMappingURL=directives.js.map