@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/directives.js
CHANGED
|
@@ -44,7 +44,7 @@ function resetDirectiveRenderers() {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// directives/ApplyDirectiveButton.tsx
|
|
47
|
-
import { useEffect, useRef, useState } 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,41 @@ 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
|
+
}
|
|
310
|
+
var applyOutcomes = /* @__PURE__ */ new WeakMap();
|
|
311
|
+
var EMPTY_AUTHORITY = {};
|
|
312
|
+
var outcomeListeners = /* @__PURE__ */ new Set();
|
|
313
|
+
function outcomesOf(host) {
|
|
314
|
+
let held = applyOutcomes.get(host);
|
|
315
|
+
if (!held) {
|
|
316
|
+
held = /* @__PURE__ */ new Map();
|
|
317
|
+
applyOutcomes.set(host, held);
|
|
318
|
+
}
|
|
319
|
+
return held;
|
|
320
|
+
}
|
|
321
|
+
function publishOutcome(host, identity, outcome) {
|
|
322
|
+
outcomesOf(host).set(identity, outcome);
|
|
323
|
+
for (const listener of outcomeListeners) listener();
|
|
324
|
+
}
|
|
325
|
+
function subscribeOutcomes(listener) {
|
|
326
|
+
outcomeListeners.add(listener);
|
|
327
|
+
return () => {
|
|
328
|
+
outcomeListeners.delete(listener);
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
function useApplyOutcome(host, identity) {
|
|
332
|
+
return useSyncExternalStore2(
|
|
333
|
+
subscribeOutcomes,
|
|
334
|
+
() => applyOutcomes.get(host)?.get(identity) ?? null,
|
|
335
|
+
() => null
|
|
336
|
+
);
|
|
337
|
+
}
|
|
245
338
|
var FINISH_POLL_MS = 2e3;
|
|
246
339
|
var FINISH_POLLS_MAX = 30;
|
|
247
340
|
function readsApplyLedger(host, directive) {
|
|
@@ -261,27 +354,29 @@ function ApplyDirectiveButton({
|
|
|
261
354
|
const items = directive.items;
|
|
262
355
|
const readsLedger = readsApplyLedger(host, directive);
|
|
263
356
|
const initial = readsLedger ? { status: "checking" } : { status: "idle" };
|
|
264
|
-
const [state, setState] =
|
|
265
|
-
const [elapsed, setElapsed] =
|
|
266
|
-
const [askingAgain, setAskingAgain] =
|
|
357
|
+
const [state, setState] = useState2(initial);
|
|
358
|
+
const [elapsed, setElapsed] = useState2(0);
|
|
359
|
+
const [askingAgain, setAskingAgain] = useState2(false);
|
|
267
360
|
const startedAt = useRef(null);
|
|
268
361
|
const identity = JSON.stringify([directive.slug, items, conversationId ?? null]);
|
|
269
|
-
const [stateFor, setStateFor] =
|
|
362
|
+
const [stateFor, setStateFor] = useState2(identity);
|
|
270
363
|
if (stateFor !== identity) {
|
|
271
364
|
setStateFor(identity);
|
|
272
365
|
setState(initial);
|
|
273
366
|
setAskingAgain(false);
|
|
274
367
|
setElapsed(0);
|
|
275
368
|
}
|
|
369
|
+
const shared = useApplyOutcome(host.confirm ?? EMPTY_AUTHORITY, identity);
|
|
370
|
+
const view = state.status === "asking" || !shared ? state : shared;
|
|
276
371
|
const currentIdentity = useRef(identity);
|
|
277
|
-
|
|
372
|
+
useEffect2(() => {
|
|
278
373
|
currentIdentity.current = identity;
|
|
279
374
|
}, [identity]);
|
|
280
375
|
const nounText = nounLabel(directive.noun, host.nouns);
|
|
281
376
|
const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : "";
|
|
282
377
|
const read = host.applyState;
|
|
283
378
|
const report = host.reportError;
|
|
284
|
-
|
|
379
|
+
useEffect2(() => {
|
|
285
380
|
if (!shellKey || !read) return;
|
|
286
381
|
const [slug, shellItems, inConversation] = JSON.parse(shellKey);
|
|
287
382
|
const shell = { __kind: slug, items: shellItems };
|
|
@@ -326,33 +421,34 @@ function ApplyDirectiveButton({
|
|
|
326
421
|
if (timer) clearTimeout(timer);
|
|
327
422
|
};
|
|
328
423
|
}, [shellKey, read, report]);
|
|
329
|
-
const appliedClean =
|
|
424
|
+
const appliedClean = view.status === "applied" && view.failed === 0 ? view : null;
|
|
330
425
|
const appliedBefore = appliedClean ? appliedClean.before : null;
|
|
331
|
-
const phaseKey =
|
|
332
|
-
|
|
426
|
+
const phaseKey = view.status === "checking" || view.status === "finishing" ? "pending" : appliedClean ? `applied:${JSON.stringify(appliedBefore)}` : "open";
|
|
427
|
+
useEffect2(() => {
|
|
333
428
|
if (!onPhase) return;
|
|
334
429
|
if (phaseKey === "pending") onPhase({ phase: "pending" });
|
|
335
430
|
else if (phaseKey === "open") onPhase({ phase: "open" });
|
|
336
431
|
else onPhase({ phase: "applied", before: appliedBefore });
|
|
337
432
|
}, [phaseKey, onPhase, appliedBefore]);
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
433
|
+
const applyingSince = view.status === "applying" ? view.startedAt : null;
|
|
434
|
+
useEffect2(() => {
|
|
435
|
+
if (applyingSince === null) return;
|
|
436
|
+
startedAt.current = applyingSince;
|
|
341
437
|
const id = setInterval(
|
|
342
438
|
() => setElapsed(Math.round((Date.now() - (startedAt.current ?? 0)) / 1e3)),
|
|
343
439
|
1e3
|
|
344
440
|
);
|
|
345
441
|
return () => clearInterval(id);
|
|
346
|
-
}, [
|
|
442
|
+
}, [applyingSince]);
|
|
347
443
|
if (!directive.parsed.executes) return null;
|
|
348
444
|
const confirm = host.confirm;
|
|
349
445
|
if (!confirm) return null;
|
|
350
446
|
async function handleApply(again = false) {
|
|
351
447
|
if (!confirm) return;
|
|
352
|
-
const prior =
|
|
448
|
+
const prior = view;
|
|
353
449
|
const askedFor = identity;
|
|
354
450
|
const stillHere = () => currentIdentity.current === askedFor;
|
|
355
|
-
const priorCopies =
|
|
451
|
+
const priorCopies = view.status === "applied" ? view.copies : 0;
|
|
356
452
|
if (host.ask) {
|
|
357
453
|
if (again) setAskingAgain(true);
|
|
358
454
|
else setState({ status: "asking" });
|
|
@@ -381,14 +477,20 @@ function ApplyDirectiveButton({
|
|
|
381
477
|
}
|
|
382
478
|
}
|
|
383
479
|
setElapsed(0);
|
|
384
|
-
setState({ status: "
|
|
480
|
+
setState((prev) => prev.status === "asking" ? { status: "idle" } : prev);
|
|
481
|
+
publishOutcome(confirm, askedFor, { status: "applying", startedAt: Date.now() });
|
|
385
482
|
try {
|
|
386
483
|
const shell = { __kind: directive.slug, items };
|
|
387
484
|
if (conversationId) shell.conversationId = conversationId;
|
|
388
485
|
if (again) shell.force = true;
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
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);
|
|
493
|
+
publishOutcome(confirm, askedFor, {
|
|
392
494
|
status: "applied",
|
|
393
495
|
applied: result.applied,
|
|
394
496
|
failed: result.failed,
|
|
@@ -400,20 +502,19 @@ function ApplyDirectiveButton({
|
|
|
400
502
|
// apply replaced is still the change this block made.
|
|
401
503
|
before: again && prior.status === "applied" && prior.before ? prior.before : result.before ?? null
|
|
402
504
|
});
|
|
403
|
-
onApplied?.();
|
|
505
|
+
if (stillHere()) onApplied?.();
|
|
404
506
|
} catch (error) {
|
|
405
|
-
|
|
406
|
-
setState({
|
|
507
|
+
publishOutcome(confirm, askedFor, {
|
|
407
508
|
status: "error",
|
|
408
509
|
message: error instanceof Error && error.message ? error.message : "That couldn't be applied just now. Please try again."
|
|
409
510
|
});
|
|
410
511
|
}
|
|
411
512
|
}
|
|
412
|
-
if (
|
|
413
|
-
const bad =
|
|
513
|
+
if (view.status === "applied") {
|
|
514
|
+
const bad = view.failed > 0;
|
|
414
515
|
const trashed = directive.directiveClass === "delete";
|
|
415
516
|
const label2 = nounText;
|
|
416
|
-
const records = host.renderRecord ?
|
|
517
|
+
const records = host.renderRecord ? view.records : [];
|
|
417
518
|
return /* @__PURE__ */ jsxs2(
|
|
418
519
|
"span",
|
|
419
520
|
{
|
|
@@ -427,26 +528,26 @@ function ApplyDirectiveButton({
|
|
|
427
528
|
{
|
|
428
529
|
words: failureWords(
|
|
429
530
|
{
|
|
430
|
-
raw:
|
|
531
|
+
raw: view.message ?? `${view.failed} failed`,
|
|
431
532
|
directiveClass: directive.directiveClass,
|
|
432
533
|
noun: directive.noun,
|
|
433
534
|
nounLabel: nounText,
|
|
434
|
-
failed:
|
|
435
|
-
total:
|
|
535
|
+
failed: view.failed,
|
|
536
|
+
total: view.applied + view.failed
|
|
436
537
|
},
|
|
437
538
|
host.explainFailure
|
|
438
539
|
),
|
|
439
|
-
raw:
|
|
540
|
+
raw: view.message
|
|
440
541
|
}
|
|
441
|
-
) : /* @__PURE__ */ jsx3("span", { className: "min-w-0", children:
|
|
542
|
+
) : /* @__PURE__ */ jsx3("span", { className: "min-w-0", children: view.message ?? `Applied ${view.applied}` })
|
|
442
543
|
] }),
|
|
443
|
-
|
|
544
|
+
view.copies > 1 ? /* @__PURE__ */ jsx3(
|
|
444
545
|
"span",
|
|
445
546
|
{
|
|
446
547
|
className: "shrink-0 text-muted-foreground",
|
|
447
|
-
"data-apply-copies":
|
|
548
|
+
"data-apply-copies": view.copies,
|
|
448
549
|
title: records.length > 0 ? directive.directiveClass === "create" ? "Links to the latest copy." : "Links to the latest run." : void 0,
|
|
449
|
-
children: directive.directiveClass === "create" ? `${
|
|
550
|
+
children: directive.directiveClass === "create" ? `${view.copies} copies` : `Ran ${view.copies} times`
|
|
450
551
|
}
|
|
451
552
|
) : null,
|
|
452
553
|
records.map((record) => /* @__PURE__ */ jsx3("span", { className: "inline-flex min-w-0 items-center", children: host.renderRecord?.({
|
|
@@ -473,7 +574,7 @@ function ApplyDirectiveButton({
|
|
|
473
574
|
}
|
|
474
575
|
);
|
|
475
576
|
}
|
|
476
|
-
if (
|
|
577
|
+
if (view.status === "checking") {
|
|
477
578
|
return /* @__PURE__ */ jsx3(
|
|
478
579
|
"span",
|
|
479
580
|
{
|
|
@@ -485,7 +586,7 @@ function ApplyDirectiveButton({
|
|
|
485
586
|
}
|
|
486
587
|
);
|
|
487
588
|
}
|
|
488
|
-
if (
|
|
589
|
+
if (view.status === "finishing") {
|
|
489
590
|
return /* @__PURE__ */ jsxs2(
|
|
490
591
|
"span",
|
|
491
592
|
{
|
|
@@ -500,7 +601,7 @@ function ApplyDirectiveButton({
|
|
|
500
601
|
);
|
|
501
602
|
}
|
|
502
603
|
const destructive = directive.directiveClass === "delete";
|
|
503
|
-
const muted = nothingToChange &&
|
|
604
|
+
const muted = nothingToChange && view.status === "idle";
|
|
504
605
|
return /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-2", children: [
|
|
505
606
|
muted ? /* @__PURE__ */ jsx3("span", { className: "text-xs text-muted-foreground", "data-apply-nothing": "", children: "Nothing to change" }) : null,
|
|
506
607
|
/* @__PURE__ */ jsxs2(
|
|
@@ -508,17 +609,17 @@ function ApplyDirectiveButton({
|
|
|
508
609
|
{
|
|
509
610
|
type: "button",
|
|
510
611
|
onClick: () => void handleApply(),
|
|
511
|
-
disabled:
|
|
612
|
+
disabled: view.status === "applying" || view.status === "asking" || items.length === 0,
|
|
512
613
|
"data-apply-tone": muted ? "muted" : destructive ? "destructive" : "default",
|
|
513
614
|
title: muted ? "It sets no fields, so applying it changes nothing." : void 0,
|
|
514
615
|
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"}`,
|
|
515
616
|
children: [
|
|
516
|
-
|
|
517
|
-
|
|
617
|
+
view.status === "applying" ? /* @__PURE__ */ jsx3(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx3(PlayIcon, { className: "h-3.5 w-3.5" }),
|
|
618
|
+
view.status === "applying" ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? "item" : "items"}` : ""}\u2026${elapsed ? ` ${elapsed}s` : ""}` : label
|
|
518
619
|
]
|
|
519
620
|
}
|
|
520
621
|
),
|
|
521
|
-
|
|
622
|
+
view.status === "error" ? /* @__PURE__ */ jsxs2(
|
|
522
623
|
"span",
|
|
523
624
|
{
|
|
524
625
|
className: "inline-flex max-w-sm items-start gap-1 text-xs text-destructive",
|
|
@@ -530,14 +631,14 @@ function ApplyDirectiveButton({
|
|
|
530
631
|
{
|
|
531
632
|
words: failureWords(
|
|
532
633
|
{
|
|
533
|
-
raw:
|
|
634
|
+
raw: view.message,
|
|
534
635
|
directiveClass: directive.directiveClass,
|
|
535
636
|
noun: directive.noun,
|
|
536
637
|
nounLabel: nounText
|
|
537
638
|
},
|
|
538
639
|
host.explainFailure
|
|
539
640
|
),
|
|
540
|
-
raw:
|
|
641
|
+
raw: view.message
|
|
541
642
|
}
|
|
542
643
|
)
|
|
543
644
|
]
|
|
@@ -549,7 +650,7 @@ function FailureNotice({
|
|
|
549
650
|
words,
|
|
550
651
|
raw
|
|
551
652
|
}) {
|
|
552
|
-
const [open, setOpen] =
|
|
653
|
+
const [open, setOpen] = useState2(false);
|
|
553
654
|
const detail = raw?.trim() ?? "";
|
|
554
655
|
return /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 flex-col gap-0.5", "data-apply-failure": true, children: [
|
|
555
656
|
/* @__PURE__ */ jsxs2("span", { className: "min-w-0", children: [
|
|
@@ -590,39 +691,6 @@ import {
|
|
|
590
691
|
nounLabel as nounLabel2,
|
|
591
692
|
nounTitleColumn
|
|
592
693
|
} from "@ai-matrx/content-ir";
|
|
593
|
-
|
|
594
|
-
// directives/record-values.ts
|
|
595
|
-
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
596
|
-
function useRecordValues(read, ref) {
|
|
597
|
-
const key = ref && read ? `${ref.noun}:${ref.id}` : "";
|
|
598
|
-
const [result, setResult] = useState2({
|
|
599
|
-
key: "",
|
|
600
|
-
values: null,
|
|
601
|
-
status: "idle"
|
|
602
|
-
});
|
|
603
|
-
useEffect2(() => {
|
|
604
|
-
if (!key || !read) return;
|
|
605
|
-
const split = key.indexOf(":");
|
|
606
|
-
const target = { noun: key.slice(0, split), id: key.slice(split + 1) };
|
|
607
|
-
let live = true;
|
|
608
|
-
setResult({ key, values: null, status: "loading" });
|
|
609
|
-
read(target).then((values) => {
|
|
610
|
-
if (!live) return;
|
|
611
|
-
setResult({ key, values, status: values ? "ready" : "unavailable" });
|
|
612
|
-
}).catch(() => {
|
|
613
|
-
if (!live) return;
|
|
614
|
-
setResult({ key, values: null, status: "unavailable" });
|
|
615
|
-
});
|
|
616
|
-
return () => {
|
|
617
|
-
live = false;
|
|
618
|
-
};
|
|
619
|
-
}, [key, read]);
|
|
620
|
-
if (!key) return { values: null, status: "idle" };
|
|
621
|
-
if (result.key !== key) return { values: null, status: "loading" };
|
|
622
|
-
return { values: result.values, status: result.status };
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
// directives/SideEffectDirectiveCard.tsx
|
|
626
694
|
import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
627
695
|
var ROWS_BEFORE_FOLD = 3;
|
|
628
696
|
function ItemRow({
|
|
@@ -926,13 +994,16 @@ export {
|
|
|
926
994
|
getDirectiveRenderer,
|
|
927
995
|
itemChanges,
|
|
928
996
|
itemRecordId,
|
|
997
|
+
noteRecordChanged,
|
|
929
998
|
provisionalDirectiveSlug,
|
|
930
999
|
readsApplyLedger,
|
|
931
1000
|
recordFallbackName,
|
|
1001
|
+
recordRevision,
|
|
932
1002
|
registerDirectiveRenderer,
|
|
933
1003
|
resetDirectiveRenderers,
|
|
934
1004
|
useDirectiveHost,
|
|
935
1005
|
useDirectiveScope,
|
|
1006
|
+
useRecordRevision,
|
|
936
1007
|
useRecordValues
|
|
937
1008
|
};
|
|
938
1009
|
//# sourceMappingURL=directives.js.map
|