@ai-matrx/content-ir-react 0.15.2 → 0.16.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/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { C as ComponentResolutionSource, a as ComponentResolution, b as ContentIrErrorReporter } from './component-resolution.types-DLO2w-0n.cjs';
2
2
  export { c as ComponentRole, d as ContentIrErrorReport, J as JsonObject, K as KindComponentRow, S as SystemComponentEntry, e as consoleErrorReporter } from './component-resolution.types-DLO2w-0n.cjs';
3
- import { C as ContentIrHost, K as KindRouteEnv, a as KindDefinitionSource } from './route-BCtPhF7W.cjs';
4
- export { b as ContentIrRenderSeams, D as DB_KIND_COMPONENT_KEY, c as DIRECTIVE_BLOCK_TYPE, d as DirectiveApplyResult, e as DirectiveApplyState, f as DirectiveAskRequest, g as DirectiveCopyProps, h as DirectiveHost, i as DirectiveHostProvider, j as DirectiveHostProviderProps, k as DirectiveOpenItemOptions, l as DirectiveRecordProps, m as DirectiveRecordRef, n as DirectiveScope, o as DirectiveScopeProvider, p as DirectiveShell, G as GENERIC_STRUCTURED_COMPONENT_KEY, q as GenericFallbackReason, I as IR_PROVISIONAL_KEY, r as IR_ROUTE_KEY, s as IrRenderBlock, t as IrRoutableBlock, u as IrRouteMarker, v as KindRouteBinding, w as KindRouteOptions, P as PartialRenderOptions, x as ProvisionalKindRender, S as StructuredValueRenderProps, y as SupersededKindRender, z as applyIrKindRoute, A as createKindRouteBinding, B as envelopeFromPartialKind, E as isPartialReadyKind, F as isProvisionalBlock, H as kindServerDataFromStoredValue, J as markKindPartialUnsafe, L as readIrRouteMarker, M as resetPartialUnsafeKinds, N as resetSourcelessDbRowReports, O as resolveAnnouncedKindLoading, Q as resolveProvisionalKindRender, R as resolveSupersededKindRender, T as routeEnvOf, U as useDirectiveHost, V as useDirectiveScope } from './route-BCtPhF7W.cjs';
3
+ import { C as ContentIrHost, K as KindRouteEnv, a as KindDefinitionSource, D as DirectiveRecordRef } from './route-YcoyR3Fj.cjs';
4
+ export { b as ContentIrRenderSeams, c as DB_KIND_COMPONENT_KEY, d as DIRECTIVE_BLOCK_TYPE, e as DirectiveApplyResult, f as DirectiveApplyState, g as DirectiveAskRequest, h as DirectiveCopyProps, i as DirectiveHost, j as DirectiveHostProvider, k as DirectiveHostProviderProps, l as DirectiveOpenItemOptions, m as DirectiveRecordProps, n as DirectiveScope, o as DirectiveScopeProvider, p as DirectiveShell, G as GENERIC_STRUCTURED_COMPONENT_KEY, q as GenericFallbackReason, I as IR_PROVISIONAL_KEY, r as IR_ROUTE_KEY, s as IrRenderBlock, t as IrRoutableBlock, u as IrRouteMarker, v as KindRouteBinding, w as KindRouteOptions, P as PartialRenderOptions, x as ProvisionalKindRender, S as StructuredValueRenderProps, y as SupersededKindRender, z as applyIrKindRoute, A as createKindRouteBinding, B as envelopeFromPartialKind, E as isPartialReadyKind, F as isProvisionalBlock, H as kindServerDataFromStoredValue, J as markKindPartialUnsafe, L as readIrRouteMarker, M as resetPartialUnsafeKinds, N as resetSourcelessDbRowReports, O as resolveAnnouncedKindLoading, Q as resolveProvisionalKindRender, R as resolveSupersededKindRender, T as routeEnvOf, U as useDirectiveHost, V as useDirectiveScope } from './route-YcoyR3Fj.cjs';
5
5
  import * as react from 'react';
6
6
  import react__default, { ReactNode, ComponentType } from 'react';
7
7
  export { ComponentResolver, ComponentResolverOptions } from './resolver.cjs';
@@ -256,9 +256,75 @@ interface ApplyDirectiveButtonProps {
256
256
  }
257
257
  declare function ApplyDirectiveButton({ directive, label, itemCount, onApplied, }: ApplyDirectiveButtonProps): react.JSX.Element | null;
258
258
 
259
+ /**
260
+ * WHAT A DIRECTIVE ITEM WILL DO TO AN EXISTING RECORD — for the card, the
261
+ * confirm dialog, and anything else that must say it before the click.
262
+ *
263
+ * WHY (reviewer, 2026-09-30): an Update card and a Delete card showed each item
264
+ * as "Item" — they never named the record they would change, and an Update card
265
+ * never said what it would change. The item-summary helpers name a thing to be
266
+ * CREATED from its own fields; an update or delete item carries the TARGET's id
267
+ * and, for an update, the NEW values — so its "title" field is the new title,
268
+ * not the name of the record being changed. Naming the target is the host's
269
+ * live lookup (`DirectiveHost.renderRecord`); what changes is right here.
270
+ *
271
+ * Law: common-docs/policies/destructive-and-expensive-actions.md — the sentence
272
+ * names what changes.
273
+ */
274
+ /** Classes whose items point at an EXISTING record by `id`. */
275
+ declare const TARGETING_CLASSES: ReadonlySet<string>;
276
+ /** How long a changed value may read before it is shortened (full value on hover). */
277
+ declare const CHANGE_VALUE_MAX = 60;
278
+ /** The id of the existing record an update/delete item targets, or null. */
279
+ declare function itemRecordId(item: Record<string, unknown>): string | null;
280
+ /** "due_date" → "Due date". Underscores read as developer output. */
281
+ declare function fieldLabel(key: string): string;
282
+ /** A short, honest name for a record we could not look up: "Task 1a2b3c4d". */
283
+ declare function recordFallbackName(nounLabel: string, id: string): string;
284
+ /** One value as a row reads it: shortened, the whole of it, and whether it is empty. */
285
+ interface ChangeValue {
286
+ value: string;
287
+ full: string;
288
+ clears: boolean;
289
+ }
290
+ interface ItemChange extends ChangeValue {
291
+ key: string;
292
+ /** "Due date". */
293
+ label: string;
294
+ /**
295
+ * What the field holds NOW, when the host could read the record — so an
296
+ * update reads "old → new", never just the new value (reviewer, 2026-10-02).
297
+ * Absent when the current record is unknown.
298
+ */
299
+ before?: ChangeValue;
300
+ /** True when the record already holds exactly this value — nothing changes. */
301
+ same?: boolean;
302
+ }
303
+ /** One value, described for a change row (`value` shortened, `full` whole). */
304
+ declare function describeChangeValue(value: unknown): ChangeValue;
305
+ /**
306
+ * Every field an UPDATE item sets, in the order the item carries them — ALL of
307
+ * them, never a sample: a person approving an overwrite sees the whole of it.
308
+ *
309
+ * Pass `current` — the record as it is now (`DirectiveHost.readRecord`) — and
310
+ * each change also carries what it REPLACES (`before`) and whether it changes
311
+ * anything at all (`same`). A field the record does not carry gets no `before`.
312
+ */
313
+ declare function itemChanges(item: Record<string, unknown>, current?: Record<string, unknown> | null): ItemChange[];
314
+
259
315
  interface SideEffectDirectiveCardProps {
260
316
  directive: DecodedDirective;
261
317
  }
318
+ /**
319
+ * THE CHANGE LIST — every field an update sets, as "Label old → new" when the
320
+ * record's current value is known, "Label → new" when it is not. ONE component
321
+ * for the card row and the host's confirm dialog, so the two can never read
322
+ * differently (reviewer, 2026-10-02: the confirm showed only the new value).
323
+ */
324
+ declare function DirectiveChangeList({ changes, className, }: {
325
+ changes: ItemChange[];
326
+ className?: string;
327
+ }): react.JSX.Element;
262
328
  declare function SideEffectDirectiveCard({ directive }: SideEffectDirectiveCardProps): react.JSX.Element;
263
329
 
264
330
  interface DirectiveFallbackCardProps {
@@ -302,46 +368,14 @@ interface DirectiveRenderProps {
302
368
  }
303
369
  declare function DirectiveRender({ conversationId, ...props }: DirectiveRenderProps): react.JSX.Element;
304
370
 
305
- /**
306
- * WHAT A DIRECTIVE ITEM WILL DO TO AN EXISTING RECORD — for the card, the
307
- * confirm dialog, and anything else that must say it before the click.
308
- *
309
- * WHY (reviewer, 2026-09-30): an Update card and a Delete card showed each item
310
- * as "Item" — they never named the record they would change, and an Update card
311
- * never said what it would change. The item-summary helpers name a thing to be
312
- * CREATED from its own fields; an update or delete item carries the TARGET's id
313
- * and, for an update, the NEW values — so its "title" field is the new title,
314
- * not the name of the record being changed. Naming the target is the host's
315
- * live lookup (`DirectiveHost.renderRecord`); what changes is right here.
316
- *
317
- * Law: common-docs/policies/destructive-and-expensive-actions.md — the sentence
318
- * names what changes.
319
- */
320
- /** Classes whose items point at an EXISTING record by `id`. */
321
- declare const TARGETING_CLASSES: ReadonlySet<string>;
322
- /** How long a changed value may read before it is shortened (full value on hover). */
323
- declare const CHANGE_VALUE_MAX = 60;
324
- /** The id of the existing record an update/delete item targets, or null. */
325
- declare function itemRecordId(item: Record<string, unknown>): string | null;
326
- /** "due_date" → "Due date". Underscores read as developer output. */
327
- declare function fieldLabel(key: string): string;
328
- /** A short, honest name for a record we could not look up: "Task 1a2b3c4d". */
329
- declare function recordFallbackName(nounLabel: string, id: string): string;
330
- interface ItemChange {
331
- key: string;
332
- /** "Due date". */
333
- label: string;
334
- /** What it becomes, shortened for a row; `full` carries the whole value. */
335
- value: string;
336
- full: string;
337
- /** True when the new value empties the field. */
338
- clears: boolean;
371
+ type RecordValuesStatus = "idle" | "loading" | "ready" | "unavailable";
372
+ interface RecordValues {
373
+ /** The record's fields now, or null until (or unless) they are read. */
374
+ values: Record<string, unknown> | null;
375
+ status: RecordValuesStatus;
339
376
  }
340
- /**
341
- * Every field an UPDATE item sets, in the order the item carries them — ALL of
342
- * them, never a sample: a person approving an overwrite sees the whole of it.
343
- */
344
- declare function itemChanges(item: Record<string, unknown>): ItemChange[];
377
+ type RecordReader = (ref: DirectiveRecordRef) => Promise<Record<string, unknown> | null>;
378
+ declare function useRecordValues(read: RecordReader | undefined, ref: DirectiveRecordRef | null): RecordValues;
345
379
 
346
380
  /**
347
381
  * The DB-component COMPILE CACHE — session-scoped, keyed per winning row
@@ -606,4 +640,4 @@ declare class DbKindComponentErrorBoundary extends react.Component<DbKindCompone
606
640
  render(): react.ReactNode;
607
641
  }
608
642
 
609
- export { ApplyDirectiveButton, type ApplyDirectiveButtonProps, CHANGE_VALUE_MAX, type CompiledDbKindComponent, ComponentResolution, ComponentResolutionSource, ContentIrErrorReporter, ContentIrHost, ContentIrRenderProvider, type ContentIrRenderProviderProps, type DbKindActionResult, type DbKindCompileResult, type DbKindComponentCache, type DbKindComponentCachePorts, type DbKindComponentCompiler, DbKindComponentErrorBoundary, type DbKindComponentErrorBoundaryProps, type DbKindComponentIncident, type DbKindComponentIncidentSink, type DbKindComponentIncidentType, type DbKindComponentRenderProps, DelegatedOutput, type DelegatedOutputProps, DirectiveFallbackCard, type DirectiveFallbackCardProps, DirectiveProvisionalCard, type DirectiveProvisionalCardProps, DirectiveRender, type DirectiveRenderProps, type DirectiveRenderer, type DirectiveRendererProps, GenericStructuredView, type GenericStructuredViewProps, type ItemChange, type KindComponentUiOptions, KindDefinitionSource, KindInstanceRender, type KindInstanceRenderProps, KindRouteEnv, type KindVersionSources, NodeOutcomeView, type NodeOutcomeViewProps, ProvisionalKindBoundary, ProvisionalKindFrame, type ResolveKindValue, type RunDbKindAction, RunResultView, type RunResultViewProps, SideEffectDirectiveCard, type SideEffectDirectiveCardProps, TARGETING_CLASSES, createDbKindComponentCache, fieldLabel, getDirectiveRenderer, isDbKindComponentBodyPending, isRecordValue, itemChanges, itemRecordId, kindIsRoutable, provisionalDirectiveSlug, recordFallbackName, registerDirectiveRenderer, resetDirectiveRenderers, useContentIrHost, useContentIrHostOrNull, useContentIrKindVersion, useKindRouteEnv };
643
+ export { ApplyDirectiveButton, type ApplyDirectiveButtonProps, CHANGE_VALUE_MAX, type ChangeValue, type CompiledDbKindComponent, ComponentResolution, ComponentResolutionSource, ContentIrErrorReporter, ContentIrHost, ContentIrRenderProvider, type ContentIrRenderProviderProps, type DbKindActionResult, type DbKindCompileResult, type DbKindComponentCache, type DbKindComponentCachePorts, type DbKindComponentCompiler, DbKindComponentErrorBoundary, type DbKindComponentErrorBoundaryProps, type DbKindComponentIncident, type DbKindComponentIncidentSink, type DbKindComponentIncidentType, type DbKindComponentRenderProps, DelegatedOutput, type DelegatedOutputProps, DirectiveChangeList, DirectiveFallbackCard, type DirectiveFallbackCardProps, DirectiveProvisionalCard, type DirectiveProvisionalCardProps, DirectiveRecordRef, DirectiveRender, type DirectiveRenderProps, type DirectiveRenderer, type DirectiveRendererProps, GenericStructuredView, type GenericStructuredViewProps, type ItemChange, type KindComponentUiOptions, KindDefinitionSource, KindInstanceRender, type KindInstanceRenderProps, KindRouteEnv, type KindVersionSources, NodeOutcomeView, type NodeOutcomeViewProps, ProvisionalKindBoundary, ProvisionalKindFrame, type RecordReader, type RecordValues, type RecordValuesStatus, type ResolveKindValue, type RunDbKindAction, RunResultView, type RunResultViewProps, SideEffectDirectiveCard, type SideEffectDirectiveCardProps, TARGETING_CLASSES, createDbKindComponentCache, describeChangeValue, fieldLabel, getDirectiveRenderer, isDbKindComponentBodyPending, isRecordValue, itemChanges, itemRecordId, kindIsRoutable, provisionalDirectiveSlug, recordFallbackName, registerDirectiveRenderer, resetDirectiveRenderers, useContentIrHost, useContentIrHostOrNull, useContentIrKindVersion, useKindRouteEnv, useRecordValues };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { C as ComponentResolutionSource, a as ComponentResolution, b as ContentIrErrorReporter } from './component-resolution.types-DLO2w-0n.js';
2
2
  export { c as ComponentRole, d as ContentIrErrorReport, J as JsonObject, K as KindComponentRow, S as SystemComponentEntry, e as consoleErrorReporter } from './component-resolution.types-DLO2w-0n.js';
3
- import { C as ContentIrHost, K as KindRouteEnv, a as KindDefinitionSource } from './route-DDbgc-ID.js';
4
- export { b as ContentIrRenderSeams, D as DB_KIND_COMPONENT_KEY, c as DIRECTIVE_BLOCK_TYPE, d as DirectiveApplyResult, e as DirectiveApplyState, f as DirectiveAskRequest, g as DirectiveCopyProps, h as DirectiveHost, i as DirectiveHostProvider, j as DirectiveHostProviderProps, k as DirectiveOpenItemOptions, l as DirectiveRecordProps, m as DirectiveRecordRef, n as DirectiveScope, o as DirectiveScopeProvider, p as DirectiveShell, G as GENERIC_STRUCTURED_COMPONENT_KEY, q as GenericFallbackReason, I as IR_PROVISIONAL_KEY, r as IR_ROUTE_KEY, s as IrRenderBlock, t as IrRoutableBlock, u as IrRouteMarker, v as KindRouteBinding, w as KindRouteOptions, P as PartialRenderOptions, x as ProvisionalKindRender, S as StructuredValueRenderProps, y as SupersededKindRender, z as applyIrKindRoute, A as createKindRouteBinding, B as envelopeFromPartialKind, E as isPartialReadyKind, F as isProvisionalBlock, H as kindServerDataFromStoredValue, J as markKindPartialUnsafe, L as readIrRouteMarker, M as resetPartialUnsafeKinds, N as resetSourcelessDbRowReports, O as resolveAnnouncedKindLoading, Q as resolveProvisionalKindRender, R as resolveSupersededKindRender, T as routeEnvOf, U as useDirectiveHost, V as useDirectiveScope } from './route-DDbgc-ID.js';
3
+ import { C as ContentIrHost, K as KindRouteEnv, a as KindDefinitionSource, D as DirectiveRecordRef } from './route-De9c5YgW.js';
4
+ export { b as ContentIrRenderSeams, c as DB_KIND_COMPONENT_KEY, d as DIRECTIVE_BLOCK_TYPE, e as DirectiveApplyResult, f as DirectiveApplyState, g as DirectiveAskRequest, h as DirectiveCopyProps, i as DirectiveHost, j as DirectiveHostProvider, k as DirectiveHostProviderProps, l as DirectiveOpenItemOptions, m as DirectiveRecordProps, n as DirectiveScope, o as DirectiveScopeProvider, p as DirectiveShell, G as GENERIC_STRUCTURED_COMPONENT_KEY, q as GenericFallbackReason, I as IR_PROVISIONAL_KEY, r as IR_ROUTE_KEY, s as IrRenderBlock, t as IrRoutableBlock, u as IrRouteMarker, v as KindRouteBinding, w as KindRouteOptions, P as PartialRenderOptions, x as ProvisionalKindRender, S as StructuredValueRenderProps, y as SupersededKindRender, z as applyIrKindRoute, A as createKindRouteBinding, B as envelopeFromPartialKind, E as isPartialReadyKind, F as isProvisionalBlock, H as kindServerDataFromStoredValue, J as markKindPartialUnsafe, L as readIrRouteMarker, M as resetPartialUnsafeKinds, N as resetSourcelessDbRowReports, O as resolveAnnouncedKindLoading, Q as resolveProvisionalKindRender, R as resolveSupersededKindRender, T as routeEnvOf, U as useDirectiveHost, V as useDirectiveScope } from './route-De9c5YgW.js';
5
5
  import * as react from 'react';
6
6
  import react__default, { ReactNode, ComponentType } from 'react';
7
7
  export { ComponentResolver, ComponentResolverOptions } from './resolver.js';
@@ -256,9 +256,75 @@ interface ApplyDirectiveButtonProps {
256
256
  }
257
257
  declare function ApplyDirectiveButton({ directive, label, itemCount, onApplied, }: ApplyDirectiveButtonProps): react.JSX.Element | null;
258
258
 
259
+ /**
260
+ * WHAT A DIRECTIVE ITEM WILL DO TO AN EXISTING RECORD — for the card, the
261
+ * confirm dialog, and anything else that must say it before the click.
262
+ *
263
+ * WHY (reviewer, 2026-09-30): an Update card and a Delete card showed each item
264
+ * as "Item" — they never named the record they would change, and an Update card
265
+ * never said what it would change. The item-summary helpers name a thing to be
266
+ * CREATED from its own fields; an update or delete item carries the TARGET's id
267
+ * and, for an update, the NEW values — so its "title" field is the new title,
268
+ * not the name of the record being changed. Naming the target is the host's
269
+ * live lookup (`DirectiveHost.renderRecord`); what changes is right here.
270
+ *
271
+ * Law: common-docs/policies/destructive-and-expensive-actions.md — the sentence
272
+ * names what changes.
273
+ */
274
+ /** Classes whose items point at an EXISTING record by `id`. */
275
+ declare const TARGETING_CLASSES: ReadonlySet<string>;
276
+ /** How long a changed value may read before it is shortened (full value on hover). */
277
+ declare const CHANGE_VALUE_MAX = 60;
278
+ /** The id of the existing record an update/delete item targets, or null. */
279
+ declare function itemRecordId(item: Record<string, unknown>): string | null;
280
+ /** "due_date" → "Due date". Underscores read as developer output. */
281
+ declare function fieldLabel(key: string): string;
282
+ /** A short, honest name for a record we could not look up: "Task 1a2b3c4d". */
283
+ declare function recordFallbackName(nounLabel: string, id: string): string;
284
+ /** One value as a row reads it: shortened, the whole of it, and whether it is empty. */
285
+ interface ChangeValue {
286
+ value: string;
287
+ full: string;
288
+ clears: boolean;
289
+ }
290
+ interface ItemChange extends ChangeValue {
291
+ key: string;
292
+ /** "Due date". */
293
+ label: string;
294
+ /**
295
+ * What the field holds NOW, when the host could read the record — so an
296
+ * update reads "old → new", never just the new value (reviewer, 2026-10-02).
297
+ * Absent when the current record is unknown.
298
+ */
299
+ before?: ChangeValue;
300
+ /** True when the record already holds exactly this value — nothing changes. */
301
+ same?: boolean;
302
+ }
303
+ /** One value, described for a change row (`value` shortened, `full` whole). */
304
+ declare function describeChangeValue(value: unknown): ChangeValue;
305
+ /**
306
+ * Every field an UPDATE item sets, in the order the item carries them — ALL of
307
+ * them, never a sample: a person approving an overwrite sees the whole of it.
308
+ *
309
+ * Pass `current` — the record as it is now (`DirectiveHost.readRecord`) — and
310
+ * each change also carries what it REPLACES (`before`) and whether it changes
311
+ * anything at all (`same`). A field the record does not carry gets no `before`.
312
+ */
313
+ declare function itemChanges(item: Record<string, unknown>, current?: Record<string, unknown> | null): ItemChange[];
314
+
259
315
  interface SideEffectDirectiveCardProps {
260
316
  directive: DecodedDirective;
261
317
  }
318
+ /**
319
+ * THE CHANGE LIST — every field an update sets, as "Label old → new" when the
320
+ * record's current value is known, "Label → new" when it is not. ONE component
321
+ * for the card row and the host's confirm dialog, so the two can never read
322
+ * differently (reviewer, 2026-10-02: the confirm showed only the new value).
323
+ */
324
+ declare function DirectiveChangeList({ changes, className, }: {
325
+ changes: ItemChange[];
326
+ className?: string;
327
+ }): react.JSX.Element;
262
328
  declare function SideEffectDirectiveCard({ directive }: SideEffectDirectiveCardProps): react.JSX.Element;
263
329
 
264
330
  interface DirectiveFallbackCardProps {
@@ -302,46 +368,14 @@ interface DirectiveRenderProps {
302
368
  }
303
369
  declare function DirectiveRender({ conversationId, ...props }: DirectiveRenderProps): react.JSX.Element;
304
370
 
305
- /**
306
- * WHAT A DIRECTIVE ITEM WILL DO TO AN EXISTING RECORD — for the card, the
307
- * confirm dialog, and anything else that must say it before the click.
308
- *
309
- * WHY (reviewer, 2026-09-30): an Update card and a Delete card showed each item
310
- * as "Item" — they never named the record they would change, and an Update card
311
- * never said what it would change. The item-summary helpers name a thing to be
312
- * CREATED from its own fields; an update or delete item carries the TARGET's id
313
- * and, for an update, the NEW values — so its "title" field is the new title,
314
- * not the name of the record being changed. Naming the target is the host's
315
- * live lookup (`DirectiveHost.renderRecord`); what changes is right here.
316
- *
317
- * Law: common-docs/policies/destructive-and-expensive-actions.md — the sentence
318
- * names what changes.
319
- */
320
- /** Classes whose items point at an EXISTING record by `id`. */
321
- declare const TARGETING_CLASSES: ReadonlySet<string>;
322
- /** How long a changed value may read before it is shortened (full value on hover). */
323
- declare const CHANGE_VALUE_MAX = 60;
324
- /** The id of the existing record an update/delete item targets, or null. */
325
- declare function itemRecordId(item: Record<string, unknown>): string | null;
326
- /** "due_date" → "Due date". Underscores read as developer output. */
327
- declare function fieldLabel(key: string): string;
328
- /** A short, honest name for a record we could not look up: "Task 1a2b3c4d". */
329
- declare function recordFallbackName(nounLabel: string, id: string): string;
330
- interface ItemChange {
331
- key: string;
332
- /** "Due date". */
333
- label: string;
334
- /** What it becomes, shortened for a row; `full` carries the whole value. */
335
- value: string;
336
- full: string;
337
- /** True when the new value empties the field. */
338
- clears: boolean;
371
+ type RecordValuesStatus = "idle" | "loading" | "ready" | "unavailable";
372
+ interface RecordValues {
373
+ /** The record's fields now, or null until (or unless) they are read. */
374
+ values: Record<string, unknown> | null;
375
+ status: RecordValuesStatus;
339
376
  }
340
- /**
341
- * Every field an UPDATE item sets, in the order the item carries them — ALL of
342
- * them, never a sample: a person approving an overwrite sees the whole of it.
343
- */
344
- declare function itemChanges(item: Record<string, unknown>): ItemChange[];
377
+ type RecordReader = (ref: DirectiveRecordRef) => Promise<Record<string, unknown> | null>;
378
+ declare function useRecordValues(read: RecordReader | undefined, ref: DirectiveRecordRef | null): RecordValues;
345
379
 
346
380
  /**
347
381
  * The DB-component COMPILE CACHE — session-scoped, keyed per winning row
@@ -606,4 +640,4 @@ declare class DbKindComponentErrorBoundary extends react.Component<DbKindCompone
606
640
  render(): react.ReactNode;
607
641
  }
608
642
 
609
- export { ApplyDirectiveButton, type ApplyDirectiveButtonProps, CHANGE_VALUE_MAX, type CompiledDbKindComponent, ComponentResolution, ComponentResolutionSource, ContentIrErrorReporter, ContentIrHost, ContentIrRenderProvider, type ContentIrRenderProviderProps, type DbKindActionResult, type DbKindCompileResult, type DbKindComponentCache, type DbKindComponentCachePorts, type DbKindComponentCompiler, DbKindComponentErrorBoundary, type DbKindComponentErrorBoundaryProps, type DbKindComponentIncident, type DbKindComponentIncidentSink, type DbKindComponentIncidentType, type DbKindComponentRenderProps, DelegatedOutput, type DelegatedOutputProps, DirectiveFallbackCard, type DirectiveFallbackCardProps, DirectiveProvisionalCard, type DirectiveProvisionalCardProps, DirectiveRender, type DirectiveRenderProps, type DirectiveRenderer, type DirectiveRendererProps, GenericStructuredView, type GenericStructuredViewProps, type ItemChange, type KindComponentUiOptions, KindDefinitionSource, KindInstanceRender, type KindInstanceRenderProps, KindRouteEnv, type KindVersionSources, NodeOutcomeView, type NodeOutcomeViewProps, ProvisionalKindBoundary, ProvisionalKindFrame, type ResolveKindValue, type RunDbKindAction, RunResultView, type RunResultViewProps, SideEffectDirectiveCard, type SideEffectDirectiveCardProps, TARGETING_CLASSES, createDbKindComponentCache, fieldLabel, getDirectiveRenderer, isDbKindComponentBodyPending, isRecordValue, itemChanges, itemRecordId, kindIsRoutable, provisionalDirectiveSlug, recordFallbackName, registerDirectiveRenderer, resetDirectiveRenderers, useContentIrHost, useContentIrHostOrNull, useContentIrKindVersion, useKindRouteEnv };
643
+ export { ApplyDirectiveButton, type ApplyDirectiveButtonProps, CHANGE_VALUE_MAX, type ChangeValue, type CompiledDbKindComponent, ComponentResolution, ComponentResolutionSource, ContentIrErrorReporter, ContentIrHost, ContentIrRenderProvider, type ContentIrRenderProviderProps, type DbKindActionResult, type DbKindCompileResult, type DbKindComponentCache, type DbKindComponentCachePorts, type DbKindComponentCompiler, DbKindComponentErrorBoundary, type DbKindComponentErrorBoundaryProps, type DbKindComponentIncident, type DbKindComponentIncidentSink, type DbKindComponentIncidentType, type DbKindComponentRenderProps, DelegatedOutput, type DelegatedOutputProps, DirectiveChangeList, DirectiveFallbackCard, type DirectiveFallbackCardProps, DirectiveProvisionalCard, type DirectiveProvisionalCardProps, DirectiveRecordRef, DirectiveRender, type DirectiveRenderProps, type DirectiveRenderer, type DirectiveRendererProps, GenericStructuredView, type GenericStructuredViewProps, type ItemChange, type KindComponentUiOptions, KindDefinitionSource, KindInstanceRender, type KindInstanceRenderProps, KindRouteEnv, type KindVersionSources, NodeOutcomeView, type NodeOutcomeViewProps, ProvisionalKindBoundary, ProvisionalKindFrame, type RecordReader, type RecordValues, type RecordValuesStatus, type ResolveKindValue, type RunDbKindAction, RunResultView, type RunResultViewProps, SideEffectDirectiveCard, type SideEffectDirectiveCardProps, TARGETING_CLASSES, createDbKindComponentCache, describeChangeValue, fieldLabel, getDirectiveRenderer, isDbKindComponentBodyPending, isRecordValue, itemChanges, itemRecordId, kindIsRoutable, provisionalDirectiveSlug, recordFallbackName, registerDirectiveRenderer, resetDirectiveRenderers, useContentIrHost, useContentIrHostOrNull, useContentIrKindVersion, useKindRouteEnv, useRecordValues };
package/dist/index.js CHANGED
@@ -739,7 +739,7 @@ function useContentIrKindVersion(kind, sources) {
739
739
  }
740
740
 
741
741
  // react/KindInstanceRender.tsx
742
- import { useEffect as useEffect2, useState as useState3 } from "react";
742
+ import { useEffect as useEffect3, useState as useState4 } from "react";
743
743
  import {
744
744
  envelopeFromCompleteValue as envelopeFromCompleteValue3,
745
745
  IR_ENVELOPE_KEY as IR_ENVELOPE_KEY2,
@@ -775,6 +775,9 @@ function recordFallbackName(nounLabel3, id) {
775
775
  const short = isUuidShape(id) ? id.slice(0, 8) : id.length > 12 ? `${id.slice(0, 12)}\u2026` : id;
776
776
  return `${nounLabel3} ${short}`;
777
777
  }
778
+ function describeChangeValue(value) {
779
+ return describeValue(value);
780
+ }
778
781
  function describeValue(value) {
779
782
  if (value === null || value === void 0) return { value: "cleared", full: "cleared", clears: true };
780
783
  if (typeof value === "string") {
@@ -803,11 +806,26 @@ function safeJson(value) {
803
806
  return String(value);
804
807
  }
805
808
  }
806
- function itemChanges(item) {
809
+ function sameValue(a, b) {
810
+ if (a === b) return true;
811
+ if (a === null || a === void 0 || b === null || b === void 0) {
812
+ const emptyA = a === null || a === void 0 || a === "";
813
+ const emptyB = b === null || b === void 0 || b === "";
814
+ return emptyA && emptyB;
815
+ }
816
+ if (typeof a === "object" || typeof b === "object") return safeJson(a) === safeJson(b);
817
+ return false;
818
+ }
819
+ function itemChanges(item, current) {
807
820
  const out = [];
808
821
  for (const [key, raw] of Object.entries(item)) {
809
822
  if (NOT_A_CHANGE.has(key)) continue;
810
- out.push({ key, label: fieldLabel(key), ...describeValue(raw) });
823
+ const change = { key, label: fieldLabel(key), ...describeValue(raw) };
824
+ if (current && Object.prototype.hasOwnProperty.call(current, key)) {
825
+ change.before = describeValue(current[key]);
826
+ change.same = sameValue(current[key], raw);
827
+ }
828
+ out.push(change);
811
829
  }
812
830
  return out;
813
831
  }
@@ -920,12 +938,23 @@ function ApplyDirectiveButton({
920
938
  const conversationId = scope.conversationId || void 0;
921
939
  const items = directive.items;
922
940
  const readsLedger = !!host.applyState && !!host.confirm && directive.parsed.executes && items.length > 0;
923
- const [state, setState] = useState(
924
- readsLedger ? { status: "checking" } : { status: "idle" }
925
- );
941
+ const initial = readsLedger ? { status: "checking" } : { status: "idle" };
942
+ const [state, setState] = useState(initial);
926
943
  const [elapsed, setElapsed] = useState(0);
927
944
  const [askingAgain, setAskingAgain] = useState(false);
928
945
  const startedAt = useRef(null);
946
+ const identity = JSON.stringify([directive.slug, items, conversationId ?? null]);
947
+ const [stateFor, setStateFor] = useState(identity);
948
+ if (stateFor !== identity) {
949
+ setStateFor(identity);
950
+ setState(initial);
951
+ setAskingAgain(false);
952
+ setElapsed(0);
953
+ }
954
+ const currentIdentity = useRef(identity);
955
+ useEffect(() => {
956
+ currentIdentity.current = identity;
957
+ }, [identity]);
929
958
  const nounText = nounLabel(directive.noun, host.nouns);
930
959
  const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : "";
931
960
  const read = host.applyState;
@@ -948,7 +977,8 @@ function ApplyDirectiveButton({
948
977
  applied: shellItems.length,
949
978
  failed: 0,
950
979
  message: answer.message?.trim() ? answer.message.trim() : null,
951
- records: answer.records ?? []
980
+ records: answer.records ?? [],
981
+ copies: Math.max(1, answer.copies ?? 1)
952
982
  } : prev
953
983
  );
954
984
  } else if (answer.state === "in_flight" && polls < FINISH_POLLS_MAX) {
@@ -988,6 +1018,9 @@ function ApplyDirectiveButton({
988
1018
  async function handleApply(again = false) {
989
1019
  if (!confirm) return;
990
1020
  const before = state;
1021
+ const askedFor = identity;
1022
+ const stillHere = () => currentIdentity.current === askedFor;
1023
+ const priorCopies = state.status === "applied" ? state.copies : 0;
991
1024
  if (host.ask) {
992
1025
  if (again) setAskingAgain(true);
993
1026
  else setState({ status: "asking" });
@@ -1000,6 +1033,7 @@ function ApplyDirectiveButton({
1000
1033
  ...again ? { again: true } : {}
1001
1034
  });
1002
1035
  } catch (error) {
1036
+ if (!stillHere()) return;
1003
1037
  setAskingAgain(false);
1004
1038
  setState({
1005
1039
  status: "error",
@@ -1007,6 +1041,7 @@ function ApplyDirectiveButton({
1007
1041
  });
1008
1042
  return;
1009
1043
  }
1044
+ if (!stillHere()) return;
1010
1045
  setAskingAgain(false);
1011
1046
  if (!ok) {
1012
1047
  setState(again ? before : { status: "idle" });
@@ -1020,15 +1055,19 @@ function ApplyDirectiveButton({
1020
1055
  if (conversationId) shell.conversationId = conversationId;
1021
1056
  if (again) shell.force = true;
1022
1057
  const result = await confirm(shell);
1058
+ if (!stillHere()) return;
1023
1059
  setState({
1024
1060
  status: "applied",
1025
1061
  applied: result.applied,
1026
1062
  failed: result.failed,
1027
1063
  message: result.message?.trim() ? result.message.trim() : null,
1028
- records: result.records ?? []
1064
+ records: result.records ?? [],
1065
+ // "Run again" made one more; a first apply (or a replay of one) is one.
1066
+ copies: again ? Math.max(1, priorCopies) + 1 : Math.max(1, priorCopies)
1029
1067
  });
1030
1068
  onApplied?.();
1031
1069
  } catch (error) {
1070
+ if (!stillHere()) return;
1032
1071
  setState({
1033
1072
  status: "error",
1034
1073
  message: error instanceof Error && error.message ? error.message : "That couldn't be applied just now. Please try again."
@@ -1053,6 +1092,15 @@ function ApplyDirectiveButton({
1053
1092
  bad && !state.message ? ` \xB7 ${state.failed} failed` : ""
1054
1093
  ] })
1055
1094
  ] }),
1095
+ state.copies > 1 ? /* @__PURE__ */ jsx4(
1096
+ "span",
1097
+ {
1098
+ className: "shrink-0 text-muted-foreground",
1099
+ "data-apply-copies": state.copies,
1100
+ title: records.length > 0 ? directive.directiveClass === "create" ? "Links to the latest copy." : "Links to the latest run." : void 0,
1101
+ children: directive.directiveClass === "create" ? `${state.copies} copies` : `Ran ${state.copies} times`
1102
+ }
1103
+ ) : null,
1056
1104
  records.map((record) => /* @__PURE__ */ jsx4("span", { className: "inline-flex min-w-0 items-center", children: host.renderRecord?.({
1057
1105
  ...record,
1058
1106
  fallback: recordFallbackName(label2, record.id),
@@ -1103,6 +1151,7 @@ function ApplyDirectiveButton({
1103
1151
  }
1104
1152
  );
1105
1153
  }
1154
+ const destructive = directive.directiveClass === "delete";
1106
1155
  return /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-2", children: [
1107
1156
  /* @__PURE__ */ jsxs2(
1108
1157
  "button",
@@ -1110,7 +1159,8 @@ function ApplyDirectiveButton({
1110
1159
  type: "button",
1111
1160
  onClick: () => void handleApply(),
1112
1161
  disabled: state.status === "applying" || state.status === "asking" || items.length === 0,
1113
- className: "inline-flex items-center gap-1 rounded-md border border-border bg-background px-2 py-1 text-xs font-medium hover:bg-accent disabled:opacity-50",
1162
+ "data-apply-tone": destructive ? "destructive" : "default",
1163
+ className: `inline-flex items-center gap-1 rounded-md border px-2 py-1 text-xs font-medium disabled:opacity-50 ${destructive ? "border-destructive/50 bg-background text-destructive hover:bg-destructive/10" : "border-border bg-background hover:bg-accent"}`,
1114
1164
  children: [
1115
1165
  state.status === "applying" ? /* @__PURE__ */ jsx4(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx4(PlayIcon, { className: "h-3.5 w-3.5" }),
1116
1166
  state.status === "applying" ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? "item" : "items"}` : ""}\u2026${elapsed ? ` ${elapsed}s` : ""}` : label
@@ -1213,7 +1263,7 @@ function resetDirectiveRenderers() {
1213
1263
  }
1214
1264
 
1215
1265
  // directives/SideEffectDirectiveCard.tsx
1216
- import { useState as useState2 } from "react";
1266
+ import { useState as useState3 } from "react";
1217
1267
  import {
1218
1268
  asKindInstance,
1219
1269
  directiveDisplay as directiveDisplay3,
@@ -1223,6 +1273,39 @@ import {
1223
1273
  nounLabel as nounLabel2,
1224
1274
  nounTitleColumn
1225
1275
  } from "@ai-matrx/content-ir";
1276
+
1277
+ // directives/record-values.ts
1278
+ import { useEffect as useEffect2, useState as useState2 } from "react";
1279
+ function useRecordValues(read, ref) {
1280
+ const key = ref && read ? `${ref.noun}:${ref.id}` : "";
1281
+ const [result, setResult] = useState2({
1282
+ key: "",
1283
+ values: null,
1284
+ status: "idle"
1285
+ });
1286
+ useEffect2(() => {
1287
+ if (!key || !read) return;
1288
+ const split = key.indexOf(":");
1289
+ const target = { noun: key.slice(0, split), id: key.slice(split + 1) };
1290
+ let live = true;
1291
+ setResult({ key, values: null, status: "loading" });
1292
+ read(target).then((values) => {
1293
+ if (!live) return;
1294
+ setResult({ key, values, status: values ? "ready" : "unavailable" });
1295
+ }).catch(() => {
1296
+ if (!live) return;
1297
+ setResult({ key, values: null, status: "unavailable" });
1298
+ });
1299
+ return () => {
1300
+ live = false;
1301
+ };
1302
+ }, [key, read]);
1303
+ if (!key) return { values: null, status: "idle" };
1304
+ if (result.key !== key) return { values: null, status: "loading" };
1305
+ return { values: result.values, status: result.status };
1306
+ }
1307
+
1308
+ // directives/SideEffectDirectiveCard.tsx
1226
1309
  import { Fragment, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1227
1310
  var ROWS_BEFORE_FOLD = 3;
1228
1311
  function ItemRow({
@@ -1276,44 +1359,73 @@ function ItemRow({
1276
1359
  host.renderCopy?.({ label: title, value: item, kind, size: "xs" })
1277
1360
  ] });
1278
1361
  }
1279
- function TargetRow({
1280
- directive,
1281
- item,
1282
- recordId
1362
+ function DirectiveChangeList({
1363
+ changes,
1364
+ className
1283
1365
  }) {
1284
- const host = useDirectiveHost();
1285
- const fallback = recordFallbackName(nounLabel2(directive.noun, host.nouns), recordId);
1286
- const changes = directive.directiveClass === "update" ? itemChanges(item) : [];
1287
- const name = host.renderRecord ? host.renderRecord({ noun: directive.noun, id: recordId, fallback, context: "row" }) : /* @__PURE__ */ jsx7("span", { className: "truncate font-medium text-foreground", children: fallback });
1288
- return /* @__PURE__ */ jsxs5("div", { className: "py-1 text-xs", "data-directive-target": recordId, children: [
1289
- /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 items-center gap-2", children: [
1290
- /* @__PURE__ */ jsx7("span", { className: "flex min-w-0 flex-1 items-center gap-1 px-1", children: name }),
1291
- host.renderCopy?.({ label: fallback, value: item, size: "xs" })
1292
- ] }),
1293
- directive.directiveClass === "update" ? changes.length === 0 ? /* @__PURE__ */ jsx7("p", { className: "px-1 text-[11px] text-muted-foreground", children: "Sets no fields \u2014 nothing would change." }) : /* @__PURE__ */ jsx7("ul", { className: "mt-0.5 space-y-0.5 px-1", children: changes.map((change) => /* @__PURE__ */ jsxs5(
1366
+ if (changes.length === 0) {
1367
+ return /* @__PURE__ */ jsx7("p", { className: `text-[11px] text-muted-foreground${className ? ` ${className}` : ""}`, children: "Sets no fields \u2014 nothing would change." });
1368
+ }
1369
+ return /* @__PURE__ */ jsx7("ul", { className: `space-y-0.5${className ? ` ${className}` : ""}`, "data-directive-changes": "", children: changes.map((change) => {
1370
+ const before = change.before && !change.same ? change.before : null;
1371
+ const was = before ? before.clears ? "empty" : before.value : null;
1372
+ return /* @__PURE__ */ jsxs5(
1294
1373
  "li",
1295
1374
  {
1296
1375
  className: "flex min-w-0 items-baseline gap-1.5 text-[11px]",
1297
- title: `${change.label} \u2192 ${change.full}`,
1376
+ title: before ? `${change.label}: ${before.clears ? "empty" : before.full} \u2192 ${change.full}` : `${change.label} \u2192 ${change.full}`,
1377
+ "data-change-key": change.key,
1298
1378
  children: [
1299
1379
  /* @__PURE__ */ jsx7("span", { className: "shrink-0 text-muted-foreground", children: change.label }),
1380
+ was !== null ? /* @__PURE__ */ jsx7(
1381
+ "span",
1382
+ {
1383
+ className: "min-w-0 max-w-[40%] shrink truncate text-muted-foreground line-through",
1384
+ "data-change-before": "",
1385
+ children: was
1386
+ }
1387
+ ) : null,
1300
1388
  /* @__PURE__ */ jsx7("span", { "aria-hidden": true, className: "shrink-0 text-muted-foreground", children: "\u2192" }),
1301
1389
  /* @__PURE__ */ jsx7(
1302
1390
  "span",
1303
1391
  {
1304
1392
  className: `min-w-0 truncate ${change.clears ? "italic text-muted-foreground" : "text-foreground"}`,
1393
+ "data-change-after": "",
1305
1394
  children: change.value
1306
1395
  }
1307
- )
1396
+ ),
1397
+ change.same ? /* @__PURE__ */ jsx7("span", { className: "shrink-0 text-muted-foreground", children: "(no change)" }) : null
1308
1398
  ]
1309
1399
  },
1310
1400
  change.key
1311
- )) }) : null
1401
+ );
1402
+ }) });
1403
+ }
1404
+ function TargetRow({
1405
+ directive,
1406
+ item,
1407
+ recordId
1408
+ }) {
1409
+ const host = useDirectiveHost();
1410
+ const fallback = recordFallbackName(nounLabel2(directive.noun, host.nouns), recordId);
1411
+ const isUpdate = directive.directiveClass === "update";
1412
+ const current = useRecordValues(
1413
+ isUpdate ? host.readRecord : void 0,
1414
+ isUpdate ? { noun: directive.noun, id: recordId } : null
1415
+ );
1416
+ const changes = isUpdate ? itemChanges(item, current.values) : [];
1417
+ const name = host.renderRecord ? host.renderRecord({ noun: directive.noun, id: recordId, fallback, context: "row" }) : /* @__PURE__ */ jsx7("span", { className: "truncate font-medium text-foreground", children: fallback });
1418
+ return /* @__PURE__ */ jsxs5("div", { className: "py-1 text-xs", "data-directive-target": recordId, children: [
1419
+ /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 items-center gap-2", children: [
1420
+ /* @__PURE__ */ jsx7("span", { className: "flex min-w-0 flex-1 items-center gap-1 px-1", children: name }),
1421
+ host.renderCopy?.({ label: fallback, value: item, size: "xs" })
1422
+ ] }),
1423
+ isUpdate ? /* @__PURE__ */ jsx7(DirectiveChangeList, { changes, className: "mt-0.5 px-1" }) : null
1312
1424
  ] });
1313
1425
  }
1314
1426
  function SideEffectDirectiveCard({ directive }) {
1315
1427
  const host = useDirectiveHost();
1316
- const [expanded, setExpanded] = useState2(false);
1428
+ const [expanded, setExpanded] = useState3(false);
1317
1429
  const items = directive.items;
1318
1430
  const total = items.length;
1319
1431
  const display = directiveDisplay3(directive.directiveClass, directive.noun, host.nouns);
@@ -1427,10 +1539,10 @@ function KindInstanceRenderInner({
1427
1539
  className
1428
1540
  }) {
1429
1541
  const host = useContentIrHost();
1430
- const [routingStatus, setRoutingStatus] = useState3(
1542
+ const [routingStatus, setRoutingStatus] = useState4(
1431
1543
  () => kindIsRoutable(kind, host) ? "routable" : "checking"
1432
1544
  );
1433
- useEffect2(() => {
1545
+ useEffect3(() => {
1434
1546
  let cancelled = false;
1435
1547
  let warmed = false;
1436
1548
  const syncRoutingStatus = () => {
@@ -1828,6 +1940,7 @@ export {
1828
1940
  DIRECTIVE_BLOCK_TYPE,
1829
1941
  DbKindComponentErrorBoundary,
1830
1942
  DelegatedOutput,
1943
+ DirectiveChangeList,
1831
1944
  DirectiveFallbackCard,
1832
1945
  DirectiveHostProvider,
1833
1946
  DirectiveProvisionalCard,
@@ -1848,6 +1961,7 @@ export {
1848
1961
  consoleErrorReporter,
1849
1962
  createDbKindComponentCache,
1850
1963
  createKindRouteBinding,
1964
+ describeChangeValue,
1851
1965
  envelopeFromPartialKind,
1852
1966
  fieldLabel,
1853
1967
  getDirectiveRenderer,
@@ -1876,6 +1990,7 @@ export {
1876
1990
  useContentIrKindVersion,
1877
1991
  useDirectiveHost,
1878
1992
  useDirectiveScope,
1879
- useKindRouteEnv
1993
+ useKindRouteEnv,
1994
+ useRecordValues
1880
1995
  };
1881
1996
  //# sourceMappingURL=index.js.map