@ai-matrx/content-ir-react 0.17.1 → 0.18.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 +22 -0
- package/dist/{directive-host-BOML4BQ7.d.cts → directive-host-Bw2_PrgL.d.cts} +14 -0
- package/dist/{directive-host-BOML4BQ7.d.ts → directive-host-Bw2_PrgL.d.ts} +14 -0
- package/dist/directives.cjs +56 -17
- package/dist/directives.cjs.map +1 -1
- package/dist/directives.d.cts +33 -5
- package/dist/directives.d.ts +33 -5
- package/dist/directives.js +56 -17
- package/dist/directives.js.map +1 -1
- package/dist/{host-types-CKu4ap5K.d.cts → host-types-YP_l_Q_t.d.cts} +1 -1
- package/dist/{host-types-CQ2oIzUy.d.ts → host-types-eSjFmXyF.d.ts} +1 -1
- package/dist/host.cjs.map +1 -1
- package/dist/host.d.cts +3 -3
- package/dist/host.d.ts +3 -3
- package/dist/host.js.map +1 -1
- package/dist/index.cjs +56 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -5
- package/dist/index.d.ts +33 -5
- package/dist/index.js +56 -17
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +55 -17
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +55 -17
- package/dist/react.js.map +1 -1
- package/dist/{route-D0f5H63n.d.ts → route-CtYw2cTN.d.ts} +14 -0
- package/dist/{route-D2Yz3El4.d.cts → route-KoRMp3Qn.d.cts} +14 -0
- package/dist/route.d.cts +1 -1
- package/dist/route.d.ts +1 -1
- package/package.json +1 -1
package/dist/directives.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as DirectiveFailure, a as DirectiveFailureWords, b as DirectiveRecordRef } from './directive-host-
|
|
2
|
-
export { c as DirectiveApplyResult, d as DirectiveApplyState, e as DirectiveAskRequest, f as DirectiveCopyProps, g as DirectiveHost, h as DirectiveHostProvider, i as DirectiveHostProviderProps, j as DirectiveOpenItemOptions, k as DirectiveRecordProps, l as DirectiveScope, m as DirectiveScopeProvider, n as DirectiveShell, u as useDirectiveHost, o as useDirectiveScope } from './directive-host-
|
|
1
|
+
import { D as DirectiveFailure, a as DirectiveFailureWords, b as DirectiveRecordRef } from './directive-host-Bw2_PrgL.js';
|
|
2
|
+
export { c as DirectiveApplyResult, d as DirectiveApplyState, e as DirectiveAskRequest, f as DirectiveCopyProps, g as DirectiveHost, h as DirectiveHostProvider, i as DirectiveHostProviderProps, j as DirectiveOpenItemOptions, k as DirectiveRecordProps, l as DirectiveScope, m as DirectiveScopeProvider, n as DirectiveShell, u as useDirectiveHost, o as useDirectiveScope } from './directive-host-Bw2_PrgL.js';
|
|
3
3
|
import * as react from 'react';
|
|
4
4
|
import { ComponentType } from 'react';
|
|
5
5
|
import { DecodedDirective, DirectiveClass } from '@ai-matrx/content-ir';
|
|
@@ -40,14 +40,42 @@ declare function getDirectiveRenderer(directive: Pick<DecodedDirective, "slug" |
|
|
|
40
40
|
/** Tests only. */
|
|
41
41
|
declare function resetDirectiveRenderers(): void;
|
|
42
42
|
|
|
43
|
+
/**
|
|
44
|
+
* What the Apply control knows about its block, for the rest of the card:
|
|
45
|
+
* - `pending` — the ledger has not answered yet;
|
|
46
|
+
* - `open` — nothing applied: rows compare against the record as it is now;
|
|
47
|
+
* - `applied` — the change happened: rows draw it from `before` (the server's
|
|
48
|
+
* record of what it replaced), never from a live re-read, which
|
|
49
|
+
* now holds the NEW value.
|
|
50
|
+
*/
|
|
51
|
+
type DirectiveApplyPhase = {
|
|
52
|
+
phase: "pending";
|
|
53
|
+
} | {
|
|
54
|
+
phase: "open";
|
|
55
|
+
} | {
|
|
56
|
+
phase: "applied";
|
|
57
|
+
before: ReadonlyArray<Record<string, unknown> | null> | null;
|
|
58
|
+
};
|
|
59
|
+
/** Does this card read the ledger before offering Apply? (One rule, card and control.) */
|
|
60
|
+
declare function readsApplyLedger(host: {
|
|
61
|
+
applyState?: unknown;
|
|
62
|
+
confirm?: unknown;
|
|
63
|
+
}, directive: DecodedDirective): boolean;
|
|
43
64
|
interface ApplyDirectiveButtonProps {
|
|
44
65
|
directive: DecodedDirective;
|
|
45
66
|
label?: string;
|
|
46
67
|
/** How many things this will write — shown during the wait so a long apply reads as work, not a frozen spinner. */
|
|
47
68
|
itemCount?: number;
|
|
48
69
|
onApplied?: () => void;
|
|
70
|
+
/** Told whenever what the control knows about its block changes. */
|
|
71
|
+
onPhase?: (phase: DirectiveApplyPhase) => void;
|
|
72
|
+
/**
|
|
73
|
+
* The block would change nothing (an update that sets no field). Apply stays
|
|
74
|
+
* — validation offers, never blocks — but muted, with the reason beside it.
|
|
75
|
+
*/
|
|
76
|
+
nothingToChange?: boolean;
|
|
49
77
|
}
|
|
50
|
-
declare function ApplyDirectiveButton({ directive, label, itemCount, onApplied, }: ApplyDirectiveButtonProps): react.JSX.Element | null;
|
|
78
|
+
declare function ApplyDirectiveButton({ directive, label, itemCount, onApplied, onPhase, nothingToChange, }: ApplyDirectiveButtonProps): react.JSX.Element | null;
|
|
51
79
|
|
|
52
80
|
/**
|
|
53
81
|
* WHAT A DIRECTIVE ITEM WILL DO TO AN EXISTING RECORD — for the card, the
|
|
@@ -61,7 +89,7 @@ declare function ApplyDirectiveButton({ directive, label, itemCount, onApplied,
|
|
|
61
89
|
* not the name of the record being changed. Naming the target is the host's
|
|
62
90
|
* live lookup (`DirectiveHost.renderRecord`); what changes is right here.
|
|
63
91
|
*
|
|
64
|
-
* Law: common-docs/policies/
|
|
92
|
+
* Law: common-docs/policies/no-dead-ends.md — the sentence
|
|
65
93
|
* names what changes.
|
|
66
94
|
*/
|
|
67
95
|
/** Classes whose items point at an EXISTING record by `id`. */
|
|
@@ -195,4 +223,4 @@ interface RecordValues {
|
|
|
195
223
|
type RecordReader = (ref: DirectiveRecordRef) => Promise<Record<string, unknown> | null>;
|
|
196
224
|
declare function useRecordValues(read: RecordReader | undefined, ref: DirectiveRecordRef | null): RecordValues;
|
|
197
225
|
|
|
198
|
-
export { ApplyDirectiveButton, type ApplyDirectiveButtonProps, CHANGE_VALUE_MAX, type ChangeValue, DirectiveChangeList, DirectiveFailure, DirectiveFailureWords, DirectiveFallbackCard, type DirectiveFallbackCardProps, DirectiveProvisionalCard, type DirectiveProvisionalCardProps, DirectiveRecordRef, DirectiveRender, type DirectiveRenderProps, type DirectiveRenderer, type DirectiveRendererProps, type ItemChange, type ItemChangesOptions, type RecordReader, type RecordValues, type RecordValuesStatus, SideEffectDirectiveCard, type SideEffectDirectiveCardProps, TARGETING_CLASSES, defaultFailureWords, describeChangeValue, failureWords, fieldLabel, getDirectiveRenderer, itemChanges, itemRecordId, provisionalDirectiveSlug, recordFallbackName, registerDirectiveRenderer, resetDirectiveRenderers, useRecordValues };
|
|
226
|
+
export { ApplyDirectiveButton, type ApplyDirectiveButtonProps, CHANGE_VALUE_MAX, type ChangeValue, type DirectiveApplyPhase, DirectiveChangeList, DirectiveFailure, DirectiveFailureWords, DirectiveFallbackCard, type DirectiveFallbackCardProps, DirectiveProvisionalCard, type DirectiveProvisionalCardProps, DirectiveRecordRef, DirectiveRender, type DirectiveRenderProps, type DirectiveRenderer, type DirectiveRendererProps, type ItemChange, type ItemChangesOptions, type RecordReader, type RecordValues, type RecordValuesStatus, SideEffectDirectiveCard, type SideEffectDirectiveCardProps, TARGETING_CLASSES, defaultFailureWords, describeChangeValue, failureWords, fieldLabel, getDirectiveRenderer, itemChanges, itemRecordId, provisionalDirectiveSlug, readsApplyLedger, recordFallbackName, registerDirectiveRenderer, resetDirectiveRenderers, useRecordValues };
|
package/dist/directives.js
CHANGED
|
@@ -244,17 +244,22 @@ function classIcon(directiveClass, noun) {
|
|
|
244
244
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
245
245
|
var FINISH_POLL_MS = 2e3;
|
|
246
246
|
var FINISH_POLLS_MAX = 30;
|
|
247
|
+
function readsApplyLedger(host, directive) {
|
|
248
|
+
return !!host.applyState && !!host.confirm && directive.parsed.executes && directive.items.length > 0;
|
|
249
|
+
}
|
|
247
250
|
function ApplyDirectiveButton({
|
|
248
251
|
directive,
|
|
249
252
|
label = "Apply",
|
|
250
253
|
itemCount,
|
|
251
|
-
onApplied
|
|
254
|
+
onApplied,
|
|
255
|
+
onPhase,
|
|
256
|
+
nothingToChange = false
|
|
252
257
|
}) {
|
|
253
258
|
const host = useDirectiveHost();
|
|
254
259
|
const scope = useDirectiveScope();
|
|
255
260
|
const conversationId = scope.conversationId || void 0;
|
|
256
261
|
const items = directive.items;
|
|
257
|
-
const readsLedger =
|
|
262
|
+
const readsLedger = readsApplyLedger(host, directive);
|
|
258
263
|
const initial = readsLedger ? { status: "checking" } : { status: "idle" };
|
|
259
264
|
const [state, setState] = useState(initial);
|
|
260
265
|
const [elapsed, setElapsed] = useState(0);
|
|
@@ -295,7 +300,8 @@ function ApplyDirectiveButton({
|
|
|
295
300
|
failed: 0,
|
|
296
301
|
message: answer.message?.trim() ? answer.message.trim() : null,
|
|
297
302
|
records: answer.records ?? [],
|
|
298
|
-
copies: Math.max(1, answer.copies ?? 1)
|
|
303
|
+
copies: Math.max(1, answer.copies ?? 1),
|
|
304
|
+
before: answer.before ?? null
|
|
299
305
|
} : prev
|
|
300
306
|
);
|
|
301
307
|
} else if (answer.state === "in_flight" && polls < FINISH_POLLS_MAX) {
|
|
@@ -320,6 +326,15 @@ function ApplyDirectiveButton({
|
|
|
320
326
|
if (timer) clearTimeout(timer);
|
|
321
327
|
};
|
|
322
328
|
}, [shellKey, read, report]);
|
|
329
|
+
const appliedClean = state.status === "applied" && state.failed === 0 ? state : null;
|
|
330
|
+
const appliedBefore = appliedClean ? appliedClean.before : null;
|
|
331
|
+
const phaseKey = state.status === "checking" || state.status === "finishing" ? "pending" : appliedClean ? `applied:${JSON.stringify(appliedBefore)}` : "open";
|
|
332
|
+
useEffect(() => {
|
|
333
|
+
if (!onPhase) return;
|
|
334
|
+
if (phaseKey === "pending") onPhase({ phase: "pending" });
|
|
335
|
+
else if (phaseKey === "open") onPhase({ phase: "open" });
|
|
336
|
+
else onPhase({ phase: "applied", before: appliedBefore });
|
|
337
|
+
}, [phaseKey, onPhase, appliedBefore]);
|
|
323
338
|
useEffect(() => {
|
|
324
339
|
if (state.status !== "applying") return;
|
|
325
340
|
startedAt.current = Date.now();
|
|
@@ -334,7 +349,7 @@ function ApplyDirectiveButton({
|
|
|
334
349
|
if (!confirm) return null;
|
|
335
350
|
async function handleApply(again = false) {
|
|
336
351
|
if (!confirm) return;
|
|
337
|
-
const
|
|
352
|
+
const prior = state;
|
|
338
353
|
const askedFor = identity;
|
|
339
354
|
const stillHere = () => currentIdentity.current === askedFor;
|
|
340
355
|
const priorCopies = state.status === "applied" ? state.copies : 0;
|
|
@@ -361,7 +376,7 @@ function ApplyDirectiveButton({
|
|
|
361
376
|
if (!stillHere()) return;
|
|
362
377
|
setAskingAgain(false);
|
|
363
378
|
if (!ok) {
|
|
364
|
-
setState(again ?
|
|
379
|
+
setState(again ? prior : { status: "idle" });
|
|
365
380
|
return;
|
|
366
381
|
}
|
|
367
382
|
}
|
|
@@ -380,7 +395,10 @@ function ApplyDirectiveButton({
|
|
|
380
395
|
message: result.message?.trim() ? result.message.trim() : null,
|
|
381
396
|
records: result.records ?? [],
|
|
382
397
|
// "Run again" made one more; a first apply (or a replay of one) is one.
|
|
383
|
-
copies: again ? Math.max(1, priorCopies) + 1 : Math.max(1, priorCopies)
|
|
398
|
+
copies: again ? Math.max(1, priorCopies) + 1 : Math.max(1, priorCopies),
|
|
399
|
+
// "Run again" wrote the same values over themselves; what the FIRST
|
|
400
|
+
// apply replaced is still the change this block made.
|
|
401
|
+
before: again && prior.status === "applied" && prior.before ? prior.before : result.before ?? null
|
|
384
402
|
});
|
|
385
403
|
onApplied?.();
|
|
386
404
|
} catch (error) {
|
|
@@ -482,15 +500,18 @@ function ApplyDirectiveButton({
|
|
|
482
500
|
);
|
|
483
501
|
}
|
|
484
502
|
const destructive = directive.directiveClass === "delete";
|
|
503
|
+
const muted = nothingToChange && state.status === "idle";
|
|
485
504
|
return /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-2", children: [
|
|
505
|
+
muted ? /* @__PURE__ */ jsx3("span", { className: "text-xs text-muted-foreground", "data-apply-nothing": "", children: "Nothing to change" }) : null,
|
|
486
506
|
/* @__PURE__ */ jsxs2(
|
|
487
507
|
"button",
|
|
488
508
|
{
|
|
489
509
|
type: "button",
|
|
490
510
|
onClick: () => void handleApply(),
|
|
491
511
|
disabled: state.status === "applying" || state.status === "asking" || items.length === 0,
|
|
492
|
-
"data-apply-tone": destructive ? "destructive" : "default",
|
|
493
|
-
|
|
512
|
+
"data-apply-tone": muted ? "muted" : destructive ? "destructive" : "default",
|
|
513
|
+
title: muted ? "It sets no fields, so applying it changes nothing." : void 0,
|
|
514
|
+
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"}`,
|
|
494
515
|
children: [
|
|
495
516
|
state.status === "applying" ? /* @__PURE__ */ jsx3(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx3(PlayIcon, { className: "h-3.5 w-3.5" }),
|
|
496
517
|
state.status === "applying" ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? "item" : "items"}` : ""}\u2026${elapsed ? ` ${elapsed}s` : ""}` : label
|
|
@@ -608,12 +629,13 @@ function ItemRow({
|
|
|
608
629
|
directive,
|
|
609
630
|
item,
|
|
610
631
|
index,
|
|
611
|
-
total
|
|
632
|
+
total,
|
|
633
|
+
phase
|
|
612
634
|
}) {
|
|
613
635
|
const host = useDirectiveHost();
|
|
614
636
|
const recordId = TARGETING_CLASSES.has(directive.directiveClass) ? itemRecordId(item) : null;
|
|
615
637
|
if (recordId) {
|
|
616
|
-
return /* @__PURE__ */ jsx4(TargetRow, { directive, item, recordId });
|
|
638
|
+
return /* @__PURE__ */ jsx4(TargetRow, { directive, item, recordId, index, phase });
|
|
617
639
|
}
|
|
618
640
|
const titleColumn = nounTitleColumn(directive.noun, host.nouns);
|
|
619
641
|
const title = itemTitle(item, titleColumn, index, total);
|
|
@@ -700,16 +722,20 @@ function DirectiveChangeList({
|
|
|
700
722
|
function TargetRow({
|
|
701
723
|
directive,
|
|
702
724
|
item,
|
|
703
|
-
recordId
|
|
725
|
+
recordId,
|
|
726
|
+
index,
|
|
727
|
+
phase
|
|
704
728
|
}) {
|
|
705
729
|
const host = useDirectiveHost();
|
|
706
730
|
const fallback = recordFallbackName(nounLabel2(directive.noun, host.nouns), recordId);
|
|
707
731
|
const isUpdate = directive.directiveClass === "update";
|
|
708
|
-
const
|
|
709
|
-
|
|
710
|
-
|
|
732
|
+
const readsLive = isUpdate && phase.phase === "open";
|
|
733
|
+
const live = useRecordValues(
|
|
734
|
+
readsLive ? host.readRecord : void 0,
|
|
735
|
+
readsLive ? { noun: directive.noun, id: recordId } : null
|
|
711
736
|
);
|
|
712
|
-
const
|
|
737
|
+
const compareTo = phase.phase === "applied" ? phase.before?.[index] ?? null : readsLive ? live.values : null;
|
|
738
|
+
const changes = isUpdate ? itemChanges(item, compareTo, { titleColumn: nounTitleColumn(directive.noun, host.nouns) }) : [];
|
|
713
739
|
const name = host.renderRecord ? host.renderRecord({ noun: directive.noun, id: recordId, fallback, context: "row" }) : /* @__PURE__ */ jsx4("span", { className: "truncate font-medium text-foreground", children: fallback });
|
|
714
740
|
return /* @__PURE__ */ jsxs3("div", { className: "py-1 text-xs", "data-directive-target": recordId, children: [
|
|
715
741
|
/* @__PURE__ */ jsxs3("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
@@ -726,6 +752,10 @@ function SideEffectDirectiveCard({ directive }) {
|
|
|
726
752
|
const total = items.length;
|
|
727
753
|
const display = directiveDisplay(directive.directiveClass, directive.noun, host.nouns);
|
|
728
754
|
const Icon = classIcon(directive.directiveClass, directive.noun);
|
|
755
|
+
const [phase, setPhase] = useState3(
|
|
756
|
+
() => readsApplyLedger(host, directive) ? { phase: "pending" } : { phase: "open" }
|
|
757
|
+
);
|
|
758
|
+
const nothingToChange = directive.directiveClass === "update" && total > 0 && items.every((item) => itemChanges(item).length === 0);
|
|
729
759
|
const shown = expanded ? items : items.slice(0, ROWS_BEFORE_FOLD);
|
|
730
760
|
const hidden = total - shown.length;
|
|
731
761
|
return /* @__PURE__ */ jsxs3("div", { className: "my-3 rounded-md border border-border bg-card px-2.5 py-1.5", "data-directive": directive.slug, children: [
|
|
@@ -740,13 +770,21 @@ function SideEffectDirectiveCard({ directive }) {
|
|
|
740
770
|
] }),
|
|
741
771
|
/* @__PURE__ */ jsxs3("div", { className: "ml-auto flex items-center gap-1", children: [
|
|
742
772
|
host.renderCopy?.({ label: display.title, value: directive.shell, size: "icon" }),
|
|
743
|
-
/* @__PURE__ */ jsx4(
|
|
773
|
+
/* @__PURE__ */ jsx4(
|
|
774
|
+
ApplyDirectiveButton,
|
|
775
|
+
{
|
|
776
|
+
directive,
|
|
777
|
+
itemCount: total,
|
|
778
|
+
onPhase: setPhase,
|
|
779
|
+
nothingToChange
|
|
780
|
+
}
|
|
781
|
+
)
|
|
744
782
|
] })
|
|
745
783
|
] }),
|
|
746
784
|
total === 0 ? (
|
|
747
785
|
// Stated, never silent: an empty batch is a real (and suspicious) state.
|
|
748
786
|
/* @__PURE__ */ jsx4("p", { className: "mt-1 text-xs text-muted-foreground", children: "No items \u2014 nothing would be written." })
|
|
749
|
-
) : /* @__PURE__ */ jsx4("div", { className: "mt-0.5 divide-y divide-border/60", children: shown.map((item, i) => /* @__PURE__ */ jsx4(ItemRow, { directive, item, index: i, total }, i)) }),
|
|
787
|
+
) : /* @__PURE__ */ jsx4("div", { className: "mt-0.5 divide-y divide-border/60", children: shown.map((item, i) => /* @__PURE__ */ jsx4(ItemRow, { directive, item, index: i, total, phase }, i)) }),
|
|
750
788
|
hidden > 0 || expanded ? /* @__PURE__ */ jsxs3(
|
|
751
789
|
"button",
|
|
752
790
|
{
|
|
@@ -889,6 +927,7 @@ export {
|
|
|
889
927
|
itemChanges,
|
|
890
928
|
itemRecordId,
|
|
891
929
|
provisionalDirectiveSlug,
|
|
930
|
+
readsApplyLedger,
|
|
892
931
|
recordFallbackName,
|
|
893
932
|
registerDirectiveRenderer,
|
|
894
933
|
resetDirectiveRenderers,
|