@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.cjs
CHANGED
|
@@ -134,7 +134,7 @@ var import_content_ir6 = require("@ai-matrx/content-ir");
|
|
|
134
134
|
var import_content_ir2 = require("@ai-matrx/content-ir");
|
|
135
135
|
|
|
136
136
|
// directives/ApplyDirectiveButton.tsx
|
|
137
|
-
var
|
|
137
|
+
var import_react5 = require("react");
|
|
138
138
|
var import_content_ir = require("@ai-matrx/content-ir");
|
|
139
139
|
|
|
140
140
|
// directives/item-changes.ts
|
|
@@ -210,6 +210,64 @@ function itemChanges(item, current, options = {}) {
|
|
|
210
210
|
return out;
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
+
// directives/record-values.ts
|
|
214
|
+
var import_react4 = require("react");
|
|
215
|
+
var revisions = /* @__PURE__ */ new Map();
|
|
216
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
217
|
+
function recordRevision(id) {
|
|
218
|
+
return revisions.get(id) ?? 0;
|
|
219
|
+
}
|
|
220
|
+
function noteRecordChanged(id) {
|
|
221
|
+
if (!id) return;
|
|
222
|
+
revisions.set(id, recordRevision(id) + 1);
|
|
223
|
+
for (const listener of listeners) listener();
|
|
224
|
+
}
|
|
225
|
+
function subscribeRevisions(listener) {
|
|
226
|
+
listeners.add(listener);
|
|
227
|
+
return () => {
|
|
228
|
+
listeners.delete(listener);
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function useRecordRevision(id) {
|
|
232
|
+
return (0, import_react4.useSyncExternalStore)(
|
|
233
|
+
subscribeRevisions,
|
|
234
|
+
() => recordRevision(id),
|
|
235
|
+
() => 0
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
function useRecordValues(read, ref) {
|
|
239
|
+
const revision = useRecordRevision(ref?.id ?? "");
|
|
240
|
+
const key = ref && read ? `${ref.noun}:${ref.id}#${revision}` : "";
|
|
241
|
+
const [result, setResult] = (0, import_react4.useState)({
|
|
242
|
+
key: "",
|
|
243
|
+
values: null,
|
|
244
|
+
status: "idle"
|
|
245
|
+
});
|
|
246
|
+
(0, import_react4.useEffect)(() => {
|
|
247
|
+
if (!key || !read) return;
|
|
248
|
+
const split = key.indexOf(":");
|
|
249
|
+
const target = {
|
|
250
|
+
noun: key.slice(0, split),
|
|
251
|
+
id: key.slice(split + 1, key.lastIndexOf("#"))
|
|
252
|
+
};
|
|
253
|
+
let live = true;
|
|
254
|
+
setResult({ key, values: null, status: "loading" });
|
|
255
|
+
read(target).then((values) => {
|
|
256
|
+
if (!live) return;
|
|
257
|
+
setResult({ key, values, status: values ? "ready" : "unavailable" });
|
|
258
|
+
}).catch(() => {
|
|
259
|
+
if (!live) return;
|
|
260
|
+
setResult({ key, values: null, status: "unavailable" });
|
|
261
|
+
});
|
|
262
|
+
return () => {
|
|
263
|
+
live = false;
|
|
264
|
+
};
|
|
265
|
+
}, [key, read]);
|
|
266
|
+
if (!key) return { values: null, status: "idle" };
|
|
267
|
+
if (result.key !== key) return { values: null, status: "loading" };
|
|
268
|
+
return { values: result.values, status: result.status };
|
|
269
|
+
}
|
|
270
|
+
|
|
213
271
|
// directives/failure-words.ts
|
|
214
272
|
var PAST = {
|
|
215
273
|
create: "created",
|
|
@@ -329,6 +387,41 @@ function classIcon(directiveClass, noun) {
|
|
|
329
387
|
|
|
330
388
|
// directives/ApplyDirectiveButton.tsx
|
|
331
389
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
390
|
+
function announceChangedRecords(directive, items) {
|
|
391
|
+
if (!TARGETING_CLASSES.has(directive.directiveClass)) return;
|
|
392
|
+
for (const item of items) {
|
|
393
|
+
const id = itemRecordId(item);
|
|
394
|
+
if (id) noteRecordChanged(id);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
var applyOutcomes = /* @__PURE__ */ new WeakMap();
|
|
398
|
+
var EMPTY_AUTHORITY = {};
|
|
399
|
+
var outcomeListeners = /* @__PURE__ */ new Set();
|
|
400
|
+
function outcomesOf(host) {
|
|
401
|
+
let held = applyOutcomes.get(host);
|
|
402
|
+
if (!held) {
|
|
403
|
+
held = /* @__PURE__ */ new Map();
|
|
404
|
+
applyOutcomes.set(host, held);
|
|
405
|
+
}
|
|
406
|
+
return held;
|
|
407
|
+
}
|
|
408
|
+
function publishOutcome(host, identity, outcome) {
|
|
409
|
+
outcomesOf(host).set(identity, outcome);
|
|
410
|
+
for (const listener of outcomeListeners) listener();
|
|
411
|
+
}
|
|
412
|
+
function subscribeOutcomes(listener) {
|
|
413
|
+
outcomeListeners.add(listener);
|
|
414
|
+
return () => {
|
|
415
|
+
outcomeListeners.delete(listener);
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
function useApplyOutcome(host, identity) {
|
|
419
|
+
return (0, import_react5.useSyncExternalStore)(
|
|
420
|
+
subscribeOutcomes,
|
|
421
|
+
() => applyOutcomes.get(host)?.get(identity) ?? null,
|
|
422
|
+
() => null
|
|
423
|
+
);
|
|
424
|
+
}
|
|
332
425
|
var FINISH_POLL_MS = 2e3;
|
|
333
426
|
var FINISH_POLLS_MAX = 30;
|
|
334
427
|
function readsApplyLedger(host, directive) {
|
|
@@ -348,27 +441,29 @@ function ApplyDirectiveButton({
|
|
|
348
441
|
const items = directive.items;
|
|
349
442
|
const readsLedger = readsApplyLedger(host, directive);
|
|
350
443
|
const initial = readsLedger ? { status: "checking" } : { status: "idle" };
|
|
351
|
-
const [state, setState] = (0,
|
|
352
|
-
const [elapsed, setElapsed] = (0,
|
|
353
|
-
const [askingAgain, setAskingAgain] = (0,
|
|
354
|
-
const startedAt = (0,
|
|
444
|
+
const [state, setState] = (0, import_react5.useState)(initial);
|
|
445
|
+
const [elapsed, setElapsed] = (0, import_react5.useState)(0);
|
|
446
|
+
const [askingAgain, setAskingAgain] = (0, import_react5.useState)(false);
|
|
447
|
+
const startedAt = (0, import_react5.useRef)(null);
|
|
355
448
|
const identity = JSON.stringify([directive.slug, items, conversationId ?? null]);
|
|
356
|
-
const [stateFor, setStateFor] = (0,
|
|
449
|
+
const [stateFor, setStateFor] = (0, import_react5.useState)(identity);
|
|
357
450
|
if (stateFor !== identity) {
|
|
358
451
|
setStateFor(identity);
|
|
359
452
|
setState(initial);
|
|
360
453
|
setAskingAgain(false);
|
|
361
454
|
setElapsed(0);
|
|
362
455
|
}
|
|
363
|
-
const
|
|
364
|
-
|
|
456
|
+
const shared = useApplyOutcome(host.confirm ?? EMPTY_AUTHORITY, identity);
|
|
457
|
+
const view = state.status === "asking" || !shared ? state : shared;
|
|
458
|
+
const currentIdentity = (0, import_react5.useRef)(identity);
|
|
459
|
+
(0, import_react5.useEffect)(() => {
|
|
365
460
|
currentIdentity.current = identity;
|
|
366
461
|
}, [identity]);
|
|
367
462
|
const nounText = (0, import_content_ir.nounLabel)(directive.noun, host.nouns);
|
|
368
463
|
const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : "";
|
|
369
464
|
const read = host.applyState;
|
|
370
465
|
const report = host.reportError;
|
|
371
|
-
(0,
|
|
466
|
+
(0, import_react5.useEffect)(() => {
|
|
372
467
|
if (!shellKey || !read) return;
|
|
373
468
|
const [slug, shellItems, inConversation] = JSON.parse(shellKey);
|
|
374
469
|
const shell = { __kind: slug, items: shellItems };
|
|
@@ -413,33 +508,34 @@ function ApplyDirectiveButton({
|
|
|
413
508
|
if (timer) clearTimeout(timer);
|
|
414
509
|
};
|
|
415
510
|
}, [shellKey, read, report]);
|
|
416
|
-
const appliedClean =
|
|
511
|
+
const appliedClean = view.status === "applied" && view.failed === 0 ? view : null;
|
|
417
512
|
const appliedBefore = appliedClean ? appliedClean.before : null;
|
|
418
|
-
const phaseKey =
|
|
419
|
-
(0,
|
|
513
|
+
const phaseKey = view.status === "checking" || view.status === "finishing" ? "pending" : appliedClean ? `applied:${JSON.stringify(appliedBefore)}` : "open";
|
|
514
|
+
(0, import_react5.useEffect)(() => {
|
|
420
515
|
if (!onPhase) return;
|
|
421
516
|
if (phaseKey === "pending") onPhase({ phase: "pending" });
|
|
422
517
|
else if (phaseKey === "open") onPhase({ phase: "open" });
|
|
423
518
|
else onPhase({ phase: "applied", before: appliedBefore });
|
|
424
519
|
}, [phaseKey, onPhase, appliedBefore]);
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
520
|
+
const applyingSince = view.status === "applying" ? view.startedAt : null;
|
|
521
|
+
(0, import_react5.useEffect)(() => {
|
|
522
|
+
if (applyingSince === null) return;
|
|
523
|
+
startedAt.current = applyingSince;
|
|
428
524
|
const id = setInterval(
|
|
429
525
|
() => setElapsed(Math.round((Date.now() - (startedAt.current ?? 0)) / 1e3)),
|
|
430
526
|
1e3
|
|
431
527
|
);
|
|
432
528
|
return () => clearInterval(id);
|
|
433
|
-
}, [
|
|
529
|
+
}, [applyingSince]);
|
|
434
530
|
if (!directive.parsed.executes) return null;
|
|
435
531
|
const confirm = host.confirm;
|
|
436
532
|
if (!confirm) return null;
|
|
437
533
|
async function handleApply(again = false) {
|
|
438
534
|
if (!confirm) return;
|
|
439
|
-
const prior =
|
|
535
|
+
const prior = view;
|
|
440
536
|
const askedFor = identity;
|
|
441
537
|
const stillHere = () => currentIdentity.current === askedFor;
|
|
442
|
-
const priorCopies =
|
|
538
|
+
const priorCopies = view.status === "applied" ? view.copies : 0;
|
|
443
539
|
if (host.ask) {
|
|
444
540
|
if (again) setAskingAgain(true);
|
|
445
541
|
else setState({ status: "asking" });
|
|
@@ -468,14 +564,20 @@ function ApplyDirectiveButton({
|
|
|
468
564
|
}
|
|
469
565
|
}
|
|
470
566
|
setElapsed(0);
|
|
471
|
-
setState({ status: "
|
|
567
|
+
setState((prev) => prev.status === "asking" ? { status: "idle" } : prev);
|
|
568
|
+
publishOutcome(confirm, askedFor, { status: "applying", startedAt: Date.now() });
|
|
472
569
|
try {
|
|
473
570
|
const shell = { __kind: directive.slug, items };
|
|
474
571
|
if (conversationId) shell.conversationId = conversationId;
|
|
475
572
|
if (again) shell.force = true;
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
573
|
+
let result;
|
|
574
|
+
try {
|
|
575
|
+
result = await confirm(shell);
|
|
576
|
+
} finally {
|
|
577
|
+
announceChangedRecords(directive, items);
|
|
578
|
+
}
|
|
579
|
+
for (const record of result.records ?? []) noteRecordChanged(record.id);
|
|
580
|
+
publishOutcome(confirm, askedFor, {
|
|
479
581
|
status: "applied",
|
|
480
582
|
applied: result.applied,
|
|
481
583
|
failed: result.failed,
|
|
@@ -487,20 +589,19 @@ function ApplyDirectiveButton({
|
|
|
487
589
|
// apply replaced is still the change this block made.
|
|
488
590
|
before: again && prior.status === "applied" && prior.before ? prior.before : result.before ?? null
|
|
489
591
|
});
|
|
490
|
-
onApplied?.();
|
|
592
|
+
if (stillHere()) onApplied?.();
|
|
491
593
|
} catch (error) {
|
|
492
|
-
|
|
493
|
-
setState({
|
|
594
|
+
publishOutcome(confirm, askedFor, {
|
|
494
595
|
status: "error",
|
|
495
596
|
message: error instanceof Error && error.message ? error.message : "That couldn't be applied just now. Please try again."
|
|
496
597
|
});
|
|
497
598
|
}
|
|
498
599
|
}
|
|
499
|
-
if (
|
|
500
|
-
const bad =
|
|
600
|
+
if (view.status === "applied") {
|
|
601
|
+
const bad = view.failed > 0;
|
|
501
602
|
const trashed = directive.directiveClass === "delete";
|
|
502
603
|
const label2 = nounText;
|
|
503
|
-
const records = host.renderRecord ?
|
|
604
|
+
const records = host.renderRecord ? view.records : [];
|
|
504
605
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
505
606
|
"span",
|
|
506
607
|
{
|
|
@@ -514,26 +615,26 @@ function ApplyDirectiveButton({
|
|
|
514
615
|
{
|
|
515
616
|
words: failureWords(
|
|
516
617
|
{
|
|
517
|
-
raw:
|
|
618
|
+
raw: view.message ?? `${view.failed} failed`,
|
|
518
619
|
directiveClass: directive.directiveClass,
|
|
519
620
|
noun: directive.noun,
|
|
520
621
|
nounLabel: nounText,
|
|
521
|
-
failed:
|
|
522
|
-
total:
|
|
622
|
+
failed: view.failed,
|
|
623
|
+
total: view.applied + view.failed
|
|
523
624
|
},
|
|
524
625
|
host.explainFailure
|
|
525
626
|
),
|
|
526
|
-
raw:
|
|
627
|
+
raw: view.message
|
|
527
628
|
}
|
|
528
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "min-w-0", children:
|
|
629
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "min-w-0", children: view.message ?? `Applied ${view.applied}` })
|
|
529
630
|
] }),
|
|
530
|
-
|
|
631
|
+
view.copies > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
531
632
|
"span",
|
|
532
633
|
{
|
|
533
634
|
className: "shrink-0 text-muted-foreground",
|
|
534
|
-
"data-apply-copies":
|
|
635
|
+
"data-apply-copies": view.copies,
|
|
535
636
|
title: records.length > 0 ? directive.directiveClass === "create" ? "Links to the latest copy." : "Links to the latest run." : void 0,
|
|
536
|
-
children: directive.directiveClass === "create" ? `${
|
|
637
|
+
children: directive.directiveClass === "create" ? `${view.copies} copies` : `Ran ${view.copies} times`
|
|
537
638
|
}
|
|
538
639
|
) : null,
|
|
539
640
|
records.map((record) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "inline-flex min-w-0 items-center", children: host.renderRecord?.({
|
|
@@ -560,7 +661,7 @@ function ApplyDirectiveButton({
|
|
|
560
661
|
}
|
|
561
662
|
);
|
|
562
663
|
}
|
|
563
|
-
if (
|
|
664
|
+
if (view.status === "checking") {
|
|
564
665
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
565
666
|
"span",
|
|
566
667
|
{
|
|
@@ -572,7 +673,7 @@ function ApplyDirectiveButton({
|
|
|
572
673
|
}
|
|
573
674
|
);
|
|
574
675
|
}
|
|
575
|
-
if (
|
|
676
|
+
if (view.status === "finishing") {
|
|
576
677
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
577
678
|
"span",
|
|
578
679
|
{
|
|
@@ -587,7 +688,7 @@ function ApplyDirectiveButton({
|
|
|
587
688
|
);
|
|
588
689
|
}
|
|
589
690
|
const destructive = directive.directiveClass === "delete";
|
|
590
|
-
const muted = nothingToChange &&
|
|
691
|
+
const muted = nothingToChange && view.status === "idle";
|
|
591
692
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "inline-flex items-center gap-2", children: [
|
|
592
693
|
muted ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-xs text-muted-foreground", "data-apply-nothing": "", children: "Nothing to change" }) : null,
|
|
593
694
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
@@ -595,17 +696,17 @@ function ApplyDirectiveButton({
|
|
|
595
696
|
{
|
|
596
697
|
type: "button",
|
|
597
698
|
onClick: () => void handleApply(),
|
|
598
|
-
disabled:
|
|
699
|
+
disabled: view.status === "applying" || view.status === "asking" || items.length === 0,
|
|
599
700
|
"data-apply-tone": muted ? "muted" : destructive ? "destructive" : "default",
|
|
600
701
|
title: muted ? "It sets no fields, so applying it changes nothing." : void 0,
|
|
601
702
|
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
703
|
children: [
|
|
603
|
-
|
|
604
|
-
|
|
704
|
+
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" }),
|
|
705
|
+
view.status === "applying" ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? "item" : "items"}` : ""}\u2026${elapsed ? ` ${elapsed}s` : ""}` : label
|
|
605
706
|
]
|
|
606
707
|
}
|
|
607
708
|
),
|
|
608
|
-
|
|
709
|
+
view.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
609
710
|
"span",
|
|
610
711
|
{
|
|
611
712
|
className: "inline-flex max-w-sm items-start gap-1 text-xs text-destructive",
|
|
@@ -617,14 +718,14 @@ function ApplyDirectiveButton({
|
|
|
617
718
|
{
|
|
618
719
|
words: failureWords(
|
|
619
720
|
{
|
|
620
|
-
raw:
|
|
721
|
+
raw: view.message,
|
|
621
722
|
directiveClass: directive.directiveClass,
|
|
622
723
|
noun: directive.noun,
|
|
623
724
|
nounLabel: nounText
|
|
624
725
|
},
|
|
625
726
|
host.explainFailure
|
|
626
727
|
),
|
|
627
|
-
raw:
|
|
728
|
+
raw: view.message
|
|
628
729
|
}
|
|
629
730
|
)
|
|
630
731
|
]
|
|
@@ -636,7 +737,7 @@ function FailureNotice({
|
|
|
636
737
|
words,
|
|
637
738
|
raw
|
|
638
739
|
}) {
|
|
639
|
-
const [open, setOpen] = (0,
|
|
740
|
+
const [open, setOpen] = (0, import_react5.useState)(false);
|
|
640
741
|
const detail = raw?.trim() ?? "";
|
|
641
742
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "flex min-w-0 flex-col gap-0.5", "data-apply-failure": true, children: [
|
|
642
743
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "min-w-0", children: [
|
|
@@ -747,39 +848,6 @@ function getDirectiveRenderer(directive) {
|
|
|
747
848
|
// directives/SideEffectDirectiveCard.tsx
|
|
748
849
|
var import_react6 = require("react");
|
|
749
850
|
var import_content_ir5 = require("@ai-matrx/content-ir");
|
|
750
|
-
|
|
751
|
-
// directives/record-values.ts
|
|
752
|
-
var import_react5 = require("react");
|
|
753
|
-
function useRecordValues(read, ref) {
|
|
754
|
-
const key = ref && read ? `${ref.noun}:${ref.id}` : "";
|
|
755
|
-
const [result, setResult] = (0, import_react5.useState)({
|
|
756
|
-
key: "",
|
|
757
|
-
values: null,
|
|
758
|
-
status: "idle"
|
|
759
|
-
});
|
|
760
|
-
(0, import_react5.useEffect)(() => {
|
|
761
|
-
if (!key || !read) return;
|
|
762
|
-
const split = key.indexOf(":");
|
|
763
|
-
const target = { noun: key.slice(0, split), id: key.slice(split + 1) };
|
|
764
|
-
let live = true;
|
|
765
|
-
setResult({ key, values: null, status: "loading" });
|
|
766
|
-
read(target).then((values) => {
|
|
767
|
-
if (!live) return;
|
|
768
|
-
setResult({ key, values, status: values ? "ready" : "unavailable" });
|
|
769
|
-
}).catch(() => {
|
|
770
|
-
if (!live) return;
|
|
771
|
-
setResult({ key, values: null, status: "unavailable" });
|
|
772
|
-
});
|
|
773
|
-
return () => {
|
|
774
|
-
live = false;
|
|
775
|
-
};
|
|
776
|
-
}, [key, read]);
|
|
777
|
-
if (!key) return { values: null, status: "idle" };
|
|
778
|
-
if (result.key !== key) return { values: null, status: "loading" };
|
|
779
|
-
return { values: result.values, status: result.status };
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
// directives/SideEffectDirectiveCard.tsx
|
|
783
851
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
784
852
|
var ROWS_BEFORE_FOLD = 3;
|
|
785
853
|
function ItemRow({
|