@ai-matrx/content-ir-react 0.13.18 → 0.15.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/dist/react.d.cts CHANGED
@@ -1,9 +1,9 @@
1
- import { c as KindDefinitionSource, C as ContentIrHost } from './host-types-BgROpyjE.cjs';
1
+ import { c as KindDefinitionSource, C as ContentIrHost } from './host-types-DVIaaGR_.cjs';
2
2
  import { d as ComponentResolutionSource } from './component-resolution.types-C1MzCf2s.cjs';
3
3
  import * as react from 'react';
4
4
  import react__default, { ReactNode } from 'react';
5
5
  import '@ai-matrx/content-ir';
6
- import './directive-host-Bl-ZgJWp.cjs';
6
+ import './directive-host-DJfF35FD.cjs';
7
7
 
8
8
  /**
9
9
  * The two registries this hook watches. Passed explicitly by a host whose
package/dist/react.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { c as KindDefinitionSource, C as ContentIrHost } from './host-types-Cz-1pGHz.js';
1
+ import { c as KindDefinitionSource, C as ContentIrHost } from './host-types-9NfBeqrG.js';
2
2
  import { d as ComponentResolutionSource } from './component-resolution.types-C1MzCf2s.js';
3
3
  import * as react from 'react';
4
4
  import react__default, { ReactNode } from 'react';
5
5
  import '@ai-matrx/content-ir';
6
- import './directive-host-Bl-ZgJWp.js';
6
+ import './directive-host-DJfF35FD.js';
7
7
 
8
8
  /**
9
9
  * The two registries this hook watches. Passed explicitly by a host whose
package/dist/react.js CHANGED
@@ -10,6 +10,16 @@ import { createContext as createContext2, useContext as useContext2, useMemo } f
10
10
  import { createContext, useContext } from "react";
11
11
  import { jsx } from "react/jsx-runtime";
12
12
  var DirectiveHostContext = createContext(null);
13
+ var DirectiveScopeContext = createContext({});
14
+ function DirectiveScopeProvider({
15
+ conversationId,
16
+ children
17
+ }) {
18
+ return /* @__PURE__ */ jsx(DirectiveScopeContext.Provider, { value: { conversationId: conversationId ?? null }, children });
19
+ }
20
+ function useDirectiveScope() {
21
+ return useContext(DirectiveScopeContext);
22
+ }
13
23
  var EMPTY_HOST = {};
14
24
  function useDirectiveHost() {
15
25
  return useContext(DirectiveHostContext) ?? EMPTY_HOST;
@@ -208,6 +218,10 @@ var MaximizeIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
208
218
  /* @__PURE__ */ jsx3("line", { x1: "3", x2: "10", y1: "21", y2: "14" })
209
219
  ] });
210
220
  var LoaderIcon = (p) => /* @__PURE__ */ jsx3(Svg, { ...p, children: /* @__PURE__ */ jsx3("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
221
+ var RotateCcwIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
222
+ /* @__PURE__ */ jsx3("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
223
+ /* @__PURE__ */ jsx3("path", { d: "M3 3v5h5" })
224
+ ] });
211
225
  var CheckCircleIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
212
226
  /* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "10" }),
213
227
  /* @__PURE__ */ jsx3("path", { d: "m9 12 2 2 4-4" })
@@ -234,6 +248,8 @@ function classIcon(directiveClass, noun) {
234
248
 
235
249
  // directives/ApplyDirectiveButton.tsx
236
250
  import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
251
+ var FINISH_POLL_MS = 2e3;
252
+ var FINISH_POLLS_MAX = 30;
237
253
  function ApplyDirectiveButton({
238
254
  directive,
239
255
  label = "Apply",
@@ -241,9 +257,62 @@ function ApplyDirectiveButton({
241
257
  onApplied
242
258
  }) {
243
259
  const host = useDirectiveHost();
244
- const [state, setState] = useState({ status: "idle" });
260
+ const scope = useDirectiveScope();
261
+ const conversationId = scope.conversationId || void 0;
262
+ const items = directive.items;
263
+ const readsLedger = !!host.applyState && !!host.confirm && directive.parsed.executes && items.length > 0;
264
+ const [state, setState] = useState(
265
+ readsLedger ? { status: "checking" } : { status: "idle" }
266
+ );
245
267
  const [elapsed, setElapsed] = useState(0);
246
268
  const startedAt = useRef(null);
269
+ const nounText = nounLabel(directive.noun, host.nouns);
270
+ const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : "";
271
+ const read = host.applyState;
272
+ const report = host.reportError;
273
+ useEffect(() => {
274
+ if (!shellKey || !read) return;
275
+ const [slug, shellItems, inConversation] = JSON.parse(shellKey);
276
+ const shell = { __kind: slug, items: shellItems };
277
+ if (inConversation) shell.conversationId = inConversation;
278
+ let live = true;
279
+ let polls = 0;
280
+ let timer = null;
281
+ const ask = () => {
282
+ read(shell).then((answer) => {
283
+ if (!live) return;
284
+ if (answer.state === "applied") {
285
+ setState(
286
+ (prev) => prev.status === "checking" || prev.status === "finishing" ? {
287
+ status: "applied",
288
+ applied: shellItems.length,
289
+ failed: 0,
290
+ message: answer.message?.trim() ? answer.message.trim() : null,
291
+ records: answer.records ?? []
292
+ } : prev
293
+ );
294
+ } else if (answer.state === "in_flight" && polls < FINISH_POLLS_MAX) {
295
+ polls += 1;
296
+ setState((prev) => prev.status === "checking" || prev.status === "finishing" ? { status: "finishing" } : prev);
297
+ timer = setTimeout(ask, FINISH_POLL_MS);
298
+ } else {
299
+ setState((prev) => prev.status === "checking" || prev.status === "finishing" ? { status: "idle" } : prev);
300
+ }
301
+ }).catch((error) => {
302
+ if (!live) return;
303
+ const why = error instanceof Error && error.message ? error.message : String(error);
304
+ (report ?? console.error)(
305
+ `[kind-directives] Could not read whether ${slug} was already applied: ${why}`
306
+ );
307
+ setState((prev) => prev.status === "checking" || prev.status === "finishing" ? { status: "idle" } : prev);
308
+ });
309
+ };
310
+ ask();
311
+ return () => {
312
+ live = false;
313
+ if (timer) clearTimeout(timer);
314
+ };
315
+ }, [shellKey, read, report]);
247
316
  useEffect(() => {
248
317
  if (state.status !== "applying") return;
249
318
  startedAt.current = Date.now();
@@ -256,9 +325,9 @@ function ApplyDirectiveButton({
256
325
  if (!directive.parsed.executes) return null;
257
326
  const confirm = host.confirm;
258
327
  if (!confirm) return null;
259
- const items = directive.items;
260
- async function handleApply() {
328
+ async function handleApply(again = false) {
261
329
  if (!confirm) return;
330
+ const before = state;
262
331
  if (host.ask) {
263
332
  setState({ status: "asking" });
264
333
  let ok = false;
@@ -266,7 +335,8 @@ function ApplyDirectiveButton({
266
335
  ok = await host.ask({
267
336
  directive,
268
337
  items,
269
- nounLabel: nounLabel(directive.noun, host.nouns)
338
+ nounLabel: nounText,
339
+ ...again ? { again: true } : {}
270
340
  });
271
341
  } catch (error) {
272
342
  setState({
@@ -276,14 +346,17 @@ function ApplyDirectiveButton({
276
346
  return;
277
347
  }
278
348
  if (!ok) {
279
- setState({ status: "idle" });
349
+ setState(again ? before : { status: "idle" });
280
350
  return;
281
351
  }
282
352
  }
283
353
  setElapsed(0);
284
354
  setState({ status: "applying" });
285
355
  try {
286
- const result = await confirm({ __kind: directive.slug, items });
356
+ const shell = { __kind: directive.slug, items };
357
+ if (conversationId) shell.conversationId = conversationId;
358
+ if (again) shell.force = true;
359
+ const result = await confirm(shell);
287
360
  setState({
288
361
  status: "applied",
289
362
  applied: result.applied,
@@ -302,7 +375,7 @@ function ApplyDirectiveButton({
302
375
  if (state.status === "applied") {
303
376
  const bad = state.failed > 0;
304
377
  const trashed = directive.directiveClass === "delete";
305
- const label2 = nounLabel(directive.noun, host.nouns);
378
+ const label2 = nounText;
306
379
  const records = host.renderRecord ? state.records : [];
307
380
  return /* @__PURE__ */ jsxs2(
308
381
  "span",
@@ -320,7 +393,46 @@ function ApplyDirectiveButton({
320
393
  fallback: recordFallbackName(label2, record.id),
321
394
  context: "applied",
322
395
  trashed
323
- }) }, `${record.noun}:${record.id}`))
396
+ }) }, `${record.noun}:${record.id}`)),
397
+ /* @__PURE__ */ jsxs2(
398
+ "button",
399
+ {
400
+ type: "button",
401
+ onClick: () => void handleApply(!bad),
402
+ className: "inline-flex items-center gap-1 rounded px-1 py-0.5 text-muted-foreground hover:bg-accent hover:text-accent-foreground",
403
+ "data-apply-action": bad ? "retry" : "run-again",
404
+ children: [
405
+ /* @__PURE__ */ jsx4(RotateCcwIcon, { className: "h-3 w-3" }),
406
+ bad ? "Retry" : "Run again"
407
+ ]
408
+ }
409
+ )
410
+ ]
411
+ }
412
+ );
413
+ }
414
+ if (state.status === "checking") {
415
+ return /* @__PURE__ */ jsx4(
416
+ "span",
417
+ {
418
+ className: "inline-flex h-6 w-6 items-center justify-center text-muted-foreground",
419
+ role: "status",
420
+ "aria-label": "Checking whether this already ran",
421
+ "data-apply-state": "checking",
422
+ children: /* @__PURE__ */ jsx4(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" })
423
+ }
424
+ );
425
+ }
426
+ if (state.status === "finishing") {
427
+ return /* @__PURE__ */ jsxs2(
428
+ "span",
429
+ {
430
+ className: "inline-flex items-center gap-1 text-xs text-muted-foreground",
431
+ role: "status",
432
+ "data-apply-state": "finishing",
433
+ children: [
434
+ /* @__PURE__ */ jsx4(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" }),
435
+ "Finishing\u2026"
324
436
  ]
325
437
  }
326
438
  );
@@ -578,7 +690,11 @@ function isWholeJson(content) {
578
690
  return false;
579
691
  }
580
692
  }
581
- function DirectiveRender({ content, className, streaming }) {
693
+ function DirectiveRender({ conversationId, ...props }) {
694
+ if (conversationId === void 0) return /* @__PURE__ */ jsx8(DirectiveRenderInner, { ...props });
695
+ return /* @__PURE__ */ jsx8(DirectiveScopeProvider, { conversationId, children: /* @__PURE__ */ jsx8(DirectiveRenderInner, { ...props }) });
696
+ }
697
+ function DirectiveRenderInner({ content, className, streaming }) {
582
698
  const host = useDirectiveHost();
583
699
  const directive = tryDecodeDirectiveContent(content, (message) => {
584
700
  const line = `[kind-directives] ${message}`;