@ai-matrx/content-ir-react 0.18.0 → 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.
- package/CHANGELOG.md +31 -0
- package/dist/directives.cjs +150 -79
- package/dist/directives.cjs.map +1 -1
- package/dist/directives.d.cts +10 -1
- package/dist/directives.d.ts +10 -1
- package/dist/directives.js +148 -77
- package/dist/directives.js.map +1 -1
- package/dist/index.cjs +152 -81
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +150 -79
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +147 -79
- package/dist/react.cjs.map +1 -1
- package/dist/react.js +145 -77
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -94,7 +94,7 @@ import { looksLikeDirectiveHead, tryDecodeDirectiveContent } from "@ai-matrx/con
|
|
|
94
94
|
import { directiveDisplay } from "@ai-matrx/content-ir";
|
|
95
95
|
|
|
96
96
|
// directives/ApplyDirectiveButton.tsx
|
|
97
|
-
import { useEffect, useRef, useState } from "react";
|
|
97
|
+
import { useEffect as useEffect2, useRef, useState as useState2, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
98
98
|
import { nounLabel } from "@ai-matrx/content-ir";
|
|
99
99
|
|
|
100
100
|
// directives/item-changes.ts
|
|
@@ -170,6 +170,64 @@ function itemChanges(item, current, options = {}) {
|
|
|
170
170
|
return out;
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
// directives/record-values.ts
|
|
174
|
+
import { useEffect, useState, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
175
|
+
var revisions = /* @__PURE__ */ new Map();
|
|
176
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
177
|
+
function recordRevision(id) {
|
|
178
|
+
return revisions.get(id) ?? 0;
|
|
179
|
+
}
|
|
180
|
+
function noteRecordChanged(id) {
|
|
181
|
+
if (!id) return;
|
|
182
|
+
revisions.set(id, recordRevision(id) + 1);
|
|
183
|
+
for (const listener of listeners) listener();
|
|
184
|
+
}
|
|
185
|
+
function subscribeRevisions(listener) {
|
|
186
|
+
listeners.add(listener);
|
|
187
|
+
return () => {
|
|
188
|
+
listeners.delete(listener);
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function useRecordRevision(id) {
|
|
192
|
+
return useSyncExternalStore2(
|
|
193
|
+
subscribeRevisions,
|
|
194
|
+
() => recordRevision(id),
|
|
195
|
+
() => 0
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
function useRecordValues(read, ref) {
|
|
199
|
+
const revision = useRecordRevision(ref?.id ?? "");
|
|
200
|
+
const key = ref && read ? `${ref.noun}:${ref.id}#${revision}` : "";
|
|
201
|
+
const [result, setResult] = useState({
|
|
202
|
+
key: "",
|
|
203
|
+
values: null,
|
|
204
|
+
status: "idle"
|
|
205
|
+
});
|
|
206
|
+
useEffect(() => {
|
|
207
|
+
if (!key || !read) return;
|
|
208
|
+
const split = key.indexOf(":");
|
|
209
|
+
const target = {
|
|
210
|
+
noun: key.slice(0, split),
|
|
211
|
+
id: key.slice(split + 1, key.lastIndexOf("#"))
|
|
212
|
+
};
|
|
213
|
+
let live = true;
|
|
214
|
+
setResult({ key, values: null, status: "loading" });
|
|
215
|
+
read(target).then((values) => {
|
|
216
|
+
if (!live) return;
|
|
217
|
+
setResult({ key, values, status: values ? "ready" : "unavailable" });
|
|
218
|
+
}).catch(() => {
|
|
219
|
+
if (!live) return;
|
|
220
|
+
setResult({ key, values: null, status: "unavailable" });
|
|
221
|
+
});
|
|
222
|
+
return () => {
|
|
223
|
+
live = false;
|
|
224
|
+
};
|
|
225
|
+
}, [key, read]);
|
|
226
|
+
if (!key) return { values: null, status: "idle" };
|
|
227
|
+
if (result.key !== key) return { values: null, status: "loading" };
|
|
228
|
+
return { values: result.values, status: result.status };
|
|
229
|
+
}
|
|
230
|
+
|
|
173
231
|
// directives/failure-words.ts
|
|
174
232
|
var PAST = {
|
|
175
233
|
create: "created",
|
|
@@ -289,6 +347,41 @@ function classIcon(directiveClass, noun) {
|
|
|
289
347
|
|
|
290
348
|
// directives/ApplyDirectiveButton.tsx
|
|
291
349
|
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
350
|
+
function announceChangedRecords(directive, items) {
|
|
351
|
+
if (!TARGETING_CLASSES.has(directive.directiveClass)) return;
|
|
352
|
+
for (const item of items) {
|
|
353
|
+
const id = itemRecordId(item);
|
|
354
|
+
if (id) noteRecordChanged(id);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
var applyOutcomes = /* @__PURE__ */ new WeakMap();
|
|
358
|
+
var EMPTY_AUTHORITY = {};
|
|
359
|
+
var outcomeListeners = /* @__PURE__ */ new Set();
|
|
360
|
+
function outcomesOf(host) {
|
|
361
|
+
let held = applyOutcomes.get(host);
|
|
362
|
+
if (!held) {
|
|
363
|
+
held = /* @__PURE__ */ new Map();
|
|
364
|
+
applyOutcomes.set(host, held);
|
|
365
|
+
}
|
|
366
|
+
return held;
|
|
367
|
+
}
|
|
368
|
+
function publishOutcome(host, identity, outcome) {
|
|
369
|
+
outcomesOf(host).set(identity, outcome);
|
|
370
|
+
for (const listener of outcomeListeners) listener();
|
|
371
|
+
}
|
|
372
|
+
function subscribeOutcomes(listener) {
|
|
373
|
+
outcomeListeners.add(listener);
|
|
374
|
+
return () => {
|
|
375
|
+
outcomeListeners.delete(listener);
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
function useApplyOutcome(host, identity) {
|
|
379
|
+
return useSyncExternalStore3(
|
|
380
|
+
subscribeOutcomes,
|
|
381
|
+
() => applyOutcomes.get(host)?.get(identity) ?? null,
|
|
382
|
+
() => null
|
|
383
|
+
);
|
|
384
|
+
}
|
|
292
385
|
var FINISH_POLL_MS = 2e3;
|
|
293
386
|
var FINISH_POLLS_MAX = 30;
|
|
294
387
|
function readsApplyLedger(host, directive) {
|
|
@@ -308,27 +401,29 @@ function ApplyDirectiveButton({
|
|
|
308
401
|
const items = directive.items;
|
|
309
402
|
const readsLedger = readsApplyLedger(host, directive);
|
|
310
403
|
const initial = readsLedger ? { status: "checking" } : { status: "idle" };
|
|
311
|
-
const [state, setState] =
|
|
312
|
-
const [elapsed, setElapsed] =
|
|
313
|
-
const [askingAgain, setAskingAgain] =
|
|
404
|
+
const [state, setState] = useState2(initial);
|
|
405
|
+
const [elapsed, setElapsed] = useState2(0);
|
|
406
|
+
const [askingAgain, setAskingAgain] = useState2(false);
|
|
314
407
|
const startedAt = useRef(null);
|
|
315
408
|
const identity = JSON.stringify([directive.slug, items, conversationId ?? null]);
|
|
316
|
-
const [stateFor, setStateFor] =
|
|
409
|
+
const [stateFor, setStateFor] = useState2(identity);
|
|
317
410
|
if (stateFor !== identity) {
|
|
318
411
|
setStateFor(identity);
|
|
319
412
|
setState(initial);
|
|
320
413
|
setAskingAgain(false);
|
|
321
414
|
setElapsed(0);
|
|
322
415
|
}
|
|
416
|
+
const shared = useApplyOutcome(host.confirm ?? EMPTY_AUTHORITY, identity);
|
|
417
|
+
const view = state.status === "asking" || !shared ? state : shared;
|
|
323
418
|
const currentIdentity = useRef(identity);
|
|
324
|
-
|
|
419
|
+
useEffect2(() => {
|
|
325
420
|
currentIdentity.current = identity;
|
|
326
421
|
}, [identity]);
|
|
327
422
|
const nounText = nounLabel(directive.noun, host.nouns);
|
|
328
423
|
const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : "";
|
|
329
424
|
const read = host.applyState;
|
|
330
425
|
const report = host.reportError;
|
|
331
|
-
|
|
426
|
+
useEffect2(() => {
|
|
332
427
|
if (!shellKey || !read) return;
|
|
333
428
|
const [slug, shellItems, inConversation] = JSON.parse(shellKey);
|
|
334
429
|
const shell = { __kind: slug, items: shellItems };
|
|
@@ -373,33 +468,34 @@ function ApplyDirectiveButton({
|
|
|
373
468
|
if (timer) clearTimeout(timer);
|
|
374
469
|
};
|
|
375
470
|
}, [shellKey, read, report]);
|
|
376
|
-
const appliedClean =
|
|
471
|
+
const appliedClean = view.status === "applied" && view.failed === 0 ? view : null;
|
|
377
472
|
const appliedBefore = appliedClean ? appliedClean.before : null;
|
|
378
|
-
const phaseKey =
|
|
379
|
-
|
|
473
|
+
const phaseKey = view.status === "checking" || view.status === "finishing" ? "pending" : appliedClean ? `applied:${JSON.stringify(appliedBefore)}` : "open";
|
|
474
|
+
useEffect2(() => {
|
|
380
475
|
if (!onPhase) return;
|
|
381
476
|
if (phaseKey === "pending") onPhase({ phase: "pending" });
|
|
382
477
|
else if (phaseKey === "open") onPhase({ phase: "open" });
|
|
383
478
|
else onPhase({ phase: "applied", before: appliedBefore });
|
|
384
479
|
}, [phaseKey, onPhase, appliedBefore]);
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
480
|
+
const applyingSince = view.status === "applying" ? view.startedAt : null;
|
|
481
|
+
useEffect2(() => {
|
|
482
|
+
if (applyingSince === null) return;
|
|
483
|
+
startedAt.current = applyingSince;
|
|
388
484
|
const id = setInterval(
|
|
389
485
|
() => setElapsed(Math.round((Date.now() - (startedAt.current ?? 0)) / 1e3)),
|
|
390
486
|
1e3
|
|
391
487
|
);
|
|
392
488
|
return () => clearInterval(id);
|
|
393
|
-
}, [
|
|
489
|
+
}, [applyingSince]);
|
|
394
490
|
if (!directive.parsed.executes) return null;
|
|
395
491
|
const confirm = host.confirm;
|
|
396
492
|
if (!confirm) return null;
|
|
397
493
|
async function handleApply(again = false) {
|
|
398
494
|
if (!confirm) return;
|
|
399
|
-
const prior =
|
|
495
|
+
const prior = view;
|
|
400
496
|
const askedFor = identity;
|
|
401
497
|
const stillHere = () => currentIdentity.current === askedFor;
|
|
402
|
-
const priorCopies =
|
|
498
|
+
const priorCopies = view.status === "applied" ? view.copies : 0;
|
|
403
499
|
if (host.ask) {
|
|
404
500
|
if (again) setAskingAgain(true);
|
|
405
501
|
else setState({ status: "asking" });
|
|
@@ -428,14 +524,20 @@ function ApplyDirectiveButton({
|
|
|
428
524
|
}
|
|
429
525
|
}
|
|
430
526
|
setElapsed(0);
|
|
431
|
-
setState({ status: "
|
|
527
|
+
setState((prev) => prev.status === "asking" ? { status: "idle" } : prev);
|
|
528
|
+
publishOutcome(confirm, askedFor, { status: "applying", startedAt: Date.now() });
|
|
432
529
|
try {
|
|
433
530
|
const shell = { __kind: directive.slug, items };
|
|
434
531
|
if (conversationId) shell.conversationId = conversationId;
|
|
435
532
|
if (again) shell.force = true;
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
533
|
+
let result;
|
|
534
|
+
try {
|
|
535
|
+
result = await confirm(shell);
|
|
536
|
+
} finally {
|
|
537
|
+
announceChangedRecords(directive, items);
|
|
538
|
+
}
|
|
539
|
+
for (const record of result.records ?? []) noteRecordChanged(record.id);
|
|
540
|
+
publishOutcome(confirm, askedFor, {
|
|
439
541
|
status: "applied",
|
|
440
542
|
applied: result.applied,
|
|
441
543
|
failed: result.failed,
|
|
@@ -447,20 +549,19 @@ function ApplyDirectiveButton({
|
|
|
447
549
|
// apply replaced is still the change this block made.
|
|
448
550
|
before: again && prior.status === "applied" && prior.before ? prior.before : result.before ?? null
|
|
449
551
|
});
|
|
450
|
-
onApplied?.();
|
|
552
|
+
if (stillHere()) onApplied?.();
|
|
451
553
|
} catch (error) {
|
|
452
|
-
|
|
453
|
-
setState({
|
|
554
|
+
publishOutcome(confirm, askedFor, {
|
|
454
555
|
status: "error",
|
|
455
556
|
message: error instanceof Error && error.message ? error.message : "That couldn't be applied just now. Please try again."
|
|
456
557
|
});
|
|
457
558
|
}
|
|
458
559
|
}
|
|
459
|
-
if (
|
|
460
|
-
const bad =
|
|
560
|
+
if (view.status === "applied") {
|
|
561
|
+
const bad = view.failed > 0;
|
|
461
562
|
const trashed = directive.directiveClass === "delete";
|
|
462
563
|
const label2 = nounText;
|
|
463
|
-
const records = host.renderRecord ?
|
|
564
|
+
const records = host.renderRecord ? view.records : [];
|
|
464
565
|
return /* @__PURE__ */ jsxs2(
|
|
465
566
|
"span",
|
|
466
567
|
{
|
|
@@ -474,26 +575,26 @@ function ApplyDirectiveButton({
|
|
|
474
575
|
{
|
|
475
576
|
words: failureWords(
|
|
476
577
|
{
|
|
477
|
-
raw:
|
|
578
|
+
raw: view.message ?? `${view.failed} failed`,
|
|
478
579
|
directiveClass: directive.directiveClass,
|
|
479
580
|
noun: directive.noun,
|
|
480
581
|
nounLabel: nounText,
|
|
481
|
-
failed:
|
|
482
|
-
total:
|
|
582
|
+
failed: view.failed,
|
|
583
|
+
total: view.applied + view.failed
|
|
483
584
|
},
|
|
484
585
|
host.explainFailure
|
|
485
586
|
),
|
|
486
|
-
raw:
|
|
587
|
+
raw: view.message
|
|
487
588
|
}
|
|
488
|
-
) : /* @__PURE__ */ jsx4("span", { className: "min-w-0", children:
|
|
589
|
+
) : /* @__PURE__ */ jsx4("span", { className: "min-w-0", children: view.message ?? `Applied ${view.applied}` })
|
|
489
590
|
] }),
|
|
490
|
-
|
|
591
|
+
view.copies > 1 ? /* @__PURE__ */ jsx4(
|
|
491
592
|
"span",
|
|
492
593
|
{
|
|
493
594
|
className: "shrink-0 text-muted-foreground",
|
|
494
|
-
"data-apply-copies":
|
|
595
|
+
"data-apply-copies": view.copies,
|
|
495
596
|
title: records.length > 0 ? directive.directiveClass === "create" ? "Links to the latest copy." : "Links to the latest run." : void 0,
|
|
496
|
-
children: directive.directiveClass === "create" ? `${
|
|
597
|
+
children: directive.directiveClass === "create" ? `${view.copies} copies` : `Ran ${view.copies} times`
|
|
497
598
|
}
|
|
498
599
|
) : null,
|
|
499
600
|
records.map((record) => /* @__PURE__ */ jsx4("span", { className: "inline-flex min-w-0 items-center", children: host.renderRecord?.({
|
|
@@ -520,7 +621,7 @@ function ApplyDirectiveButton({
|
|
|
520
621
|
}
|
|
521
622
|
);
|
|
522
623
|
}
|
|
523
|
-
if (
|
|
624
|
+
if (view.status === "checking") {
|
|
524
625
|
return /* @__PURE__ */ jsx4(
|
|
525
626
|
"span",
|
|
526
627
|
{
|
|
@@ -532,7 +633,7 @@ function ApplyDirectiveButton({
|
|
|
532
633
|
}
|
|
533
634
|
);
|
|
534
635
|
}
|
|
535
|
-
if (
|
|
636
|
+
if (view.status === "finishing") {
|
|
536
637
|
return /* @__PURE__ */ jsxs2(
|
|
537
638
|
"span",
|
|
538
639
|
{
|
|
@@ -547,7 +648,7 @@ function ApplyDirectiveButton({
|
|
|
547
648
|
);
|
|
548
649
|
}
|
|
549
650
|
const destructive = directive.directiveClass === "delete";
|
|
550
|
-
const muted = nothingToChange &&
|
|
651
|
+
const muted = nothingToChange && view.status === "idle";
|
|
551
652
|
return /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-2", children: [
|
|
552
653
|
muted ? /* @__PURE__ */ jsx4("span", { className: "text-xs text-muted-foreground", "data-apply-nothing": "", children: "Nothing to change" }) : null,
|
|
553
654
|
/* @__PURE__ */ jsxs2(
|
|
@@ -555,17 +656,17 @@ function ApplyDirectiveButton({
|
|
|
555
656
|
{
|
|
556
657
|
type: "button",
|
|
557
658
|
onClick: () => void handleApply(),
|
|
558
|
-
disabled:
|
|
659
|
+
disabled: view.status === "applying" || view.status === "asking" || items.length === 0,
|
|
559
660
|
"data-apply-tone": muted ? "muted" : destructive ? "destructive" : "default",
|
|
560
661
|
title: muted ? "It sets no fields, so applying it changes nothing." : void 0,
|
|
561
662
|
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"}`,
|
|
562
663
|
children: [
|
|
563
|
-
|
|
564
|
-
|
|
664
|
+
view.status === "applying" ? /* @__PURE__ */ jsx4(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx4(PlayIcon, { className: "h-3.5 w-3.5" }),
|
|
665
|
+
view.status === "applying" ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? "item" : "items"}` : ""}\u2026${elapsed ? ` ${elapsed}s` : ""}` : label
|
|
565
666
|
]
|
|
566
667
|
}
|
|
567
668
|
),
|
|
568
|
-
|
|
669
|
+
view.status === "error" ? /* @__PURE__ */ jsxs2(
|
|
569
670
|
"span",
|
|
570
671
|
{
|
|
571
672
|
className: "inline-flex max-w-sm items-start gap-1 text-xs text-destructive",
|
|
@@ -577,14 +678,14 @@ function ApplyDirectiveButton({
|
|
|
577
678
|
{
|
|
578
679
|
words: failureWords(
|
|
579
680
|
{
|
|
580
|
-
raw:
|
|
681
|
+
raw: view.message,
|
|
581
682
|
directiveClass: directive.directiveClass,
|
|
582
683
|
noun: directive.noun,
|
|
583
684
|
nounLabel: nounText
|
|
584
685
|
},
|
|
585
686
|
host.explainFailure
|
|
586
687
|
),
|
|
587
|
-
raw:
|
|
688
|
+
raw: view.message
|
|
588
689
|
}
|
|
589
690
|
)
|
|
590
691
|
]
|
|
@@ -596,7 +697,7 @@ function FailureNotice({
|
|
|
596
697
|
words,
|
|
597
698
|
raw
|
|
598
699
|
}) {
|
|
599
|
-
const [open, setOpen] =
|
|
700
|
+
const [open, setOpen] = useState2(false);
|
|
600
701
|
const detail = raw?.trim() ?? "";
|
|
601
702
|
return /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 flex-col gap-0.5", "data-apply-failure": true, children: [
|
|
602
703
|
/* @__PURE__ */ jsxs2("span", { className: "min-w-0", children: [
|
|
@@ -717,39 +818,6 @@ import {
|
|
|
717
818
|
nounLabel as nounLabel2,
|
|
718
819
|
nounTitleColumn
|
|
719
820
|
} from "@ai-matrx/content-ir";
|
|
720
|
-
|
|
721
|
-
// directives/record-values.ts
|
|
722
|
-
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
723
|
-
function useRecordValues(read, ref) {
|
|
724
|
-
const key = ref && read ? `${ref.noun}:${ref.id}` : "";
|
|
725
|
-
const [result, setResult] = useState2({
|
|
726
|
-
key: "",
|
|
727
|
-
values: null,
|
|
728
|
-
status: "idle"
|
|
729
|
-
});
|
|
730
|
-
useEffect2(() => {
|
|
731
|
-
if (!key || !read) return;
|
|
732
|
-
const split = key.indexOf(":");
|
|
733
|
-
const target = { noun: key.slice(0, split), id: key.slice(split + 1) };
|
|
734
|
-
let live = true;
|
|
735
|
-
setResult({ key, values: null, status: "loading" });
|
|
736
|
-
read(target).then((values) => {
|
|
737
|
-
if (!live) return;
|
|
738
|
-
setResult({ key, values, status: values ? "ready" : "unavailable" });
|
|
739
|
-
}).catch(() => {
|
|
740
|
-
if (!live) return;
|
|
741
|
-
setResult({ key, values: null, status: "unavailable" });
|
|
742
|
-
});
|
|
743
|
-
return () => {
|
|
744
|
-
live = false;
|
|
745
|
-
};
|
|
746
|
-
}, [key, read]);
|
|
747
|
-
if (!key) return { values: null, status: "idle" };
|
|
748
|
-
if (result.key !== key) return { values: null, status: "loading" };
|
|
749
|
-
return { values: result.values, status: result.status };
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
// directives/SideEffectDirectiveCard.tsx
|
|
753
821
|
import { Fragment, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
754
822
|
var ROWS_BEFORE_FOLD = 3;
|
|
755
823
|
function ItemRow({
|