@ai-matrx/content-ir-react 0.17.0 → 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.
Files changed (43) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +1 -1
  3. package/dist/{component-resolution.types-DLO2w-0n.d.cts → component-resolution.types-DY4pGymy.d.cts} +1 -1
  4. package/dist/{component-resolution.types-DLO2w-0n.d.ts → component-resolution.types-DY4pGymy.d.ts} +1 -1
  5. package/dist/{component-resolution.types-C1MzCf2s.d.cts → component-resolution.types-DwKSF64x.d.cts} +1 -1
  6. package/dist/{component-resolution.types-C1MzCf2s.d.ts → component-resolution.types-DwKSF64x.d.ts} +1 -1
  7. package/dist/db-component.d.cts +1 -1
  8. package/dist/db-component.d.ts +1 -1
  9. package/dist/{directive-host-BOML4BQ7.d.cts → directive-host-Bw2_PrgL.d.cts} +14 -0
  10. package/dist/{directive-host-BOML4BQ7.d.ts → directive-host-Bw2_PrgL.d.ts} +14 -0
  11. package/dist/directives.cjs +56 -17
  12. package/dist/directives.cjs.map +1 -1
  13. package/dist/directives.d.cts +33 -5
  14. package/dist/directives.d.ts +33 -5
  15. package/dist/directives.js +56 -17
  16. package/dist/directives.js.map +1 -1
  17. package/dist/{host-types-Dxzs0C3f.d.cts → host-types-YP_l_Q_t.d.cts} +2 -2
  18. package/dist/{host-types-uKO1zZo3.d.ts → host-types-eSjFmXyF.d.ts} +2 -2
  19. package/dist/host.cjs.map +1 -1
  20. package/dist/host.d.cts +4 -4
  21. package/dist/host.d.ts +4 -4
  22. package/dist/host.js.map +1 -1
  23. package/dist/index.cjs +56 -17
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +36 -8
  26. package/dist/index.d.ts +36 -8
  27. package/dist/index.js +56 -17
  28. package/dist/index.js.map +1 -1
  29. package/dist/react.cjs +55 -17
  30. package/dist/react.cjs.map +1 -1
  31. package/dist/react.d.cts +4 -4
  32. package/dist/react.d.ts +4 -4
  33. package/dist/react.js +55 -17
  34. package/dist/react.js.map +1 -1
  35. package/dist/resolver.d.cts +2 -2
  36. package/dist/resolver.d.ts +2 -2
  37. package/dist/{route-CfKxIEdj.d.ts → route-CtYw2cTN.d.ts} +16 -2
  38. package/dist/{route-DjGv9skd.d.cts → route-KoRMp3Qn.d.cts} +16 -2
  39. package/dist/route.cjs.map +1 -1
  40. package/dist/route.d.cts +2 -2
  41. package/dist/route.d.ts +2 -2
  42. package/dist/route.js.map +1 -1
  43. package/package.json +3 -3
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
- import { C as ComponentResolutionSource, a as ComponentResolution, b as ContentIrErrorReporter } from './component-resolution.types-DLO2w-0n.cjs';
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, D as DirectiveFailure, b as DirectiveFailureWords, c as DirectiveRecordRef } from './route-DjGv9skd.cjs';
4
- export { d as ContentIrRenderSeams, e as DB_KIND_COMPONENT_KEY, f as DIRECTIVE_BLOCK_TYPE, g as DirectiveApplyResult, h as DirectiveApplyState, i as DirectiveAskRequest, j as DirectiveCopyProps, k as DirectiveHost, l as DirectiveHostProvider, m as DirectiveHostProviderProps, n as DirectiveOpenItemOptions, o as DirectiveRecordProps, p as DirectiveScope, q as DirectiveScopeProvider, r as DirectiveShell, G as GENERIC_STRUCTURED_COMPONENT_KEY, s as GenericFallbackReason, I as IR_PROVISIONAL_KEY, t as IR_ROUTE_KEY, u as IrRenderBlock, v as IrRoutableBlock, w as IrRouteMarker, x as KindRouteBinding, y as KindRouteOptions, P as PartialRenderOptions, z as ProvisionalKindRender, S as StructuredValueRenderProps, A as SupersededKindRender, B as applyIrKindRoute, E as createKindRouteBinding, F as envelopeFromPartialKind, H as isPartialReadyKind, J as isProvisionalBlock, L as kindServerDataFromStoredValue, M as markKindPartialUnsafe, N as readIrRouteMarker, O as resetPartialUnsafeKinds, Q as resetSourcelessDbRowReports, R as resolveAnnouncedKindLoading, T as resolveProvisionalKindRender, U as resolveSupersededKindRender, V as routeEnvOf, W as useDirectiveHost, X as useDirectiveScope } from './route-DjGv9skd.cjs';
1
+ import { C as ComponentResolutionSource, a as ComponentResolution, b as ContentIrErrorReporter } from './component-resolution.types-DY4pGymy.cjs';
2
+ export { c as ComponentRole, d as ContentIrErrorReport, J as JsonObject, K as KindComponentRow, S as SystemComponentEntry, e as consoleErrorReporter } from './component-resolution.types-DY4pGymy.cjs';
3
+ import { C as ContentIrHost, K as KindRouteEnv, a as KindDefinitionSource, D as DirectiveFailure, b as DirectiveFailureWords, c as DirectiveRecordRef } from './route-KoRMp3Qn.cjs';
4
+ export { d as ContentIrRenderSeams, e as DB_KIND_COMPONENT_KEY, f as DIRECTIVE_BLOCK_TYPE, g as DirectiveApplyResult, h as DirectiveApplyState, i as DirectiveAskRequest, j as DirectiveCopyProps, k as DirectiveHost, l as DirectiveHostProvider, m as DirectiveHostProviderProps, n as DirectiveOpenItemOptions, o as DirectiveRecordProps, p as DirectiveScope, q as DirectiveScopeProvider, r as DirectiveShell, G as GENERIC_STRUCTURED_COMPONENT_KEY, s as GenericFallbackReason, I as IR_PROVISIONAL_KEY, t as IR_ROUTE_KEY, u as IrRenderBlock, v as IrRoutableBlock, w as IrRouteMarker, x as KindRouteBinding, y as KindRouteOptions, P as PartialRenderOptions, z as ProvisionalKindRender, S as StructuredValueRenderProps, A as SupersededKindRender, B as applyIrKindRoute, E as createKindRouteBinding, F as envelopeFromPartialKind, H as isPartialReadyKind, J as isProvisionalBlock, L as kindServerDataFromStoredValue, M as markKindPartialUnsafe, N as readIrRouteMarker, O as resetPartialUnsafeKinds, Q as resetSourcelessDbRowReports, R as resolveAnnouncedKindLoading, T as resolveProvisionalKindRender, U as resolveSupersededKindRender, V as routeEnvOf, W as useDirectiveHost, X as useDirectiveScope } from './route-KoRMp3Qn.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';
@@ -105,7 +105,7 @@ declare function KindInstanceRender(props: KindInstanceRenderProps): react.JSX.E
105
105
  /**
106
106
  * The safety net + the "still arriving" affordance for a provisional kind
107
107
  * render (streaming partial kinds — see `route/partial-kind-route.ts` and
108
- * `common-docs/systems/content-ir-system/STREAMING_PARTIAL_KINDS.md`).
108
+ * `common-docs/systems/architecture/content-ir/STREAMING_PARTIAL_KINDS.md`).
109
109
  *
110
110
  * TWO JOBS
111
111
  * --------
@@ -247,14 +247,42 @@ declare function getDirectiveRenderer(directive: Pick<DecodedDirective, "slug" |
247
247
  /** Tests only. */
248
248
  declare function resetDirectiveRenderers(): void;
249
249
 
250
+ /**
251
+ * What the Apply control knows about its block, for the rest of the card:
252
+ * - `pending` — the ledger has not answered yet;
253
+ * - `open` — nothing applied: rows compare against the record as it is now;
254
+ * - `applied` — the change happened: rows draw it from `before` (the server's
255
+ * record of what it replaced), never from a live re-read, which
256
+ * now holds the NEW value.
257
+ */
258
+ type DirectiveApplyPhase = {
259
+ phase: "pending";
260
+ } | {
261
+ phase: "open";
262
+ } | {
263
+ phase: "applied";
264
+ before: ReadonlyArray<Record<string, unknown> | null> | null;
265
+ };
266
+ /** Does this card read the ledger before offering Apply? (One rule, card and control.) */
267
+ declare function readsApplyLedger(host: {
268
+ applyState?: unknown;
269
+ confirm?: unknown;
270
+ }, directive: DecodedDirective): boolean;
250
271
  interface ApplyDirectiveButtonProps {
251
272
  directive: DecodedDirective;
252
273
  label?: string;
253
274
  /** How many things this will write — shown during the wait so a long apply reads as work, not a frozen spinner. */
254
275
  itemCount?: number;
255
276
  onApplied?: () => void;
277
+ /** Told whenever what the control knows about its block changes. */
278
+ onPhase?: (phase: DirectiveApplyPhase) => void;
279
+ /**
280
+ * The block would change nothing (an update that sets no field). Apply stays
281
+ * — validation offers, never blocks — but muted, with the reason beside it.
282
+ */
283
+ nothingToChange?: boolean;
256
284
  }
257
- declare function ApplyDirectiveButton({ directive, label, itemCount, onApplied, }: ApplyDirectiveButtonProps): react.JSX.Element | null;
285
+ declare function ApplyDirectiveButton({ directive, label, itemCount, onApplied, onPhase, nothingToChange, }: ApplyDirectiveButtonProps): react.JSX.Element | null;
258
286
 
259
287
  /**
260
288
  * WHAT A DIRECTIVE ITEM WILL DO TO AN EXISTING RECORD — for the card, the
@@ -268,7 +296,7 @@ declare function ApplyDirectiveButton({ directive, label, itemCount, onApplied,
268
296
  * not the name of the record being changed. Naming the target is the host's
269
297
  * live lookup (`DirectiveHost.renderRecord`); what changes is right here.
270
298
  *
271
- * Law: common-docs/policies/destructive-and-expensive-actions.md — the sentence
299
+ * Law: common-docs/policies/no-dead-ends.md — the sentence
272
300
  * names what changes.
273
301
  */
274
302
  /** Classes whose items point at an EXISTING record by `id`. */
@@ -665,4 +693,4 @@ declare class DbKindComponentErrorBoundary extends react.Component<DbKindCompone
665
693
  render(): react.ReactNode;
666
694
  }
667
695
 
668
- 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, DirectiveFailure, DirectiveFailureWords, DirectiveFallbackCard, type DirectiveFallbackCardProps, DirectiveProvisionalCard, type DirectiveProvisionalCardProps, DirectiveRecordRef, DirectiveRender, type DirectiveRenderProps, type DirectiveRenderer, type DirectiveRendererProps, GenericStructuredView, type GenericStructuredViewProps, type ItemChange, type ItemChangesOptions, 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, defaultFailureWords, describeChangeValue, failureWords, fieldLabel, getDirectiveRenderer, isDbKindComponentBodyPending, isRecordValue, itemChanges, itemRecordId, kindIsRoutable, provisionalDirectiveSlug, recordFallbackName, registerDirectiveRenderer, resetDirectiveRenderers, useContentIrHost, useContentIrHostOrNull, useContentIrKindVersion, useKindRouteEnv, useRecordValues };
696
+ 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, type DirectiveApplyPhase, DirectiveChangeList, DirectiveFailure, DirectiveFailureWords, DirectiveFallbackCard, type DirectiveFallbackCardProps, DirectiveProvisionalCard, type DirectiveProvisionalCardProps, DirectiveRecordRef, DirectiveRender, type DirectiveRenderProps, type DirectiveRenderer, type DirectiveRendererProps, GenericStructuredView, type GenericStructuredViewProps, type ItemChange, type ItemChangesOptions, 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, defaultFailureWords, describeChangeValue, failureWords, fieldLabel, getDirectiveRenderer, isDbKindComponentBodyPending, isRecordValue, itemChanges, itemRecordId, kindIsRoutable, provisionalDirectiveSlug, readsApplyLedger, recordFallbackName, registerDirectiveRenderer, resetDirectiveRenderers, useContentIrHost, useContentIrHostOrNull, useContentIrKindVersion, useKindRouteEnv, useRecordValues };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { C as ComponentResolutionSource, a as ComponentResolution, b as ContentIrErrorReporter } from './component-resolution.types-DLO2w-0n.js';
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, D as DirectiveFailure, b as DirectiveFailureWords, c as DirectiveRecordRef } from './route-CfKxIEdj.js';
4
- export { d as ContentIrRenderSeams, e as DB_KIND_COMPONENT_KEY, f as DIRECTIVE_BLOCK_TYPE, g as DirectiveApplyResult, h as DirectiveApplyState, i as DirectiveAskRequest, j as DirectiveCopyProps, k as DirectiveHost, l as DirectiveHostProvider, m as DirectiveHostProviderProps, n as DirectiveOpenItemOptions, o as DirectiveRecordProps, p as DirectiveScope, q as DirectiveScopeProvider, r as DirectiveShell, G as GENERIC_STRUCTURED_COMPONENT_KEY, s as GenericFallbackReason, I as IR_PROVISIONAL_KEY, t as IR_ROUTE_KEY, u as IrRenderBlock, v as IrRoutableBlock, w as IrRouteMarker, x as KindRouteBinding, y as KindRouteOptions, P as PartialRenderOptions, z as ProvisionalKindRender, S as StructuredValueRenderProps, A as SupersededKindRender, B as applyIrKindRoute, E as createKindRouteBinding, F as envelopeFromPartialKind, H as isPartialReadyKind, J as isProvisionalBlock, L as kindServerDataFromStoredValue, M as markKindPartialUnsafe, N as readIrRouteMarker, O as resetPartialUnsafeKinds, Q as resetSourcelessDbRowReports, R as resolveAnnouncedKindLoading, T as resolveProvisionalKindRender, U as resolveSupersededKindRender, V as routeEnvOf, W as useDirectiveHost, X as useDirectiveScope } from './route-CfKxIEdj.js';
1
+ import { C as ComponentResolutionSource, a as ComponentResolution, b as ContentIrErrorReporter } from './component-resolution.types-DY4pGymy.js';
2
+ export { c as ComponentRole, d as ContentIrErrorReport, J as JsonObject, K as KindComponentRow, S as SystemComponentEntry, e as consoleErrorReporter } from './component-resolution.types-DY4pGymy.js';
3
+ import { C as ContentIrHost, K as KindRouteEnv, a as KindDefinitionSource, D as DirectiveFailure, b as DirectiveFailureWords, c as DirectiveRecordRef } from './route-CtYw2cTN.js';
4
+ export { d as ContentIrRenderSeams, e as DB_KIND_COMPONENT_KEY, f as DIRECTIVE_BLOCK_TYPE, g as DirectiveApplyResult, h as DirectiveApplyState, i as DirectiveAskRequest, j as DirectiveCopyProps, k as DirectiveHost, l as DirectiveHostProvider, m as DirectiveHostProviderProps, n as DirectiveOpenItemOptions, o as DirectiveRecordProps, p as DirectiveScope, q as DirectiveScopeProvider, r as DirectiveShell, G as GENERIC_STRUCTURED_COMPONENT_KEY, s as GenericFallbackReason, I as IR_PROVISIONAL_KEY, t as IR_ROUTE_KEY, u as IrRenderBlock, v as IrRoutableBlock, w as IrRouteMarker, x as KindRouteBinding, y as KindRouteOptions, P as PartialRenderOptions, z as ProvisionalKindRender, S as StructuredValueRenderProps, A as SupersededKindRender, B as applyIrKindRoute, E as createKindRouteBinding, F as envelopeFromPartialKind, H as isPartialReadyKind, J as isProvisionalBlock, L as kindServerDataFromStoredValue, M as markKindPartialUnsafe, N as readIrRouteMarker, O as resetPartialUnsafeKinds, Q as resetSourcelessDbRowReports, R as resolveAnnouncedKindLoading, T as resolveProvisionalKindRender, U as resolveSupersededKindRender, V as routeEnvOf, W as useDirectiveHost, X as useDirectiveScope } from './route-CtYw2cTN.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';
@@ -105,7 +105,7 @@ declare function KindInstanceRender(props: KindInstanceRenderProps): react.JSX.E
105
105
  /**
106
106
  * The safety net + the "still arriving" affordance for a provisional kind
107
107
  * render (streaming partial kinds — see `route/partial-kind-route.ts` and
108
- * `common-docs/systems/content-ir-system/STREAMING_PARTIAL_KINDS.md`).
108
+ * `common-docs/systems/architecture/content-ir/STREAMING_PARTIAL_KINDS.md`).
109
109
  *
110
110
  * TWO JOBS
111
111
  * --------
@@ -247,14 +247,42 @@ declare function getDirectiveRenderer(directive: Pick<DecodedDirective, "slug" |
247
247
  /** Tests only. */
248
248
  declare function resetDirectiveRenderers(): void;
249
249
 
250
+ /**
251
+ * What the Apply control knows about its block, for the rest of the card:
252
+ * - `pending` — the ledger has not answered yet;
253
+ * - `open` — nothing applied: rows compare against the record as it is now;
254
+ * - `applied` — the change happened: rows draw it from `before` (the server's
255
+ * record of what it replaced), never from a live re-read, which
256
+ * now holds the NEW value.
257
+ */
258
+ type DirectiveApplyPhase = {
259
+ phase: "pending";
260
+ } | {
261
+ phase: "open";
262
+ } | {
263
+ phase: "applied";
264
+ before: ReadonlyArray<Record<string, unknown> | null> | null;
265
+ };
266
+ /** Does this card read the ledger before offering Apply? (One rule, card and control.) */
267
+ declare function readsApplyLedger(host: {
268
+ applyState?: unknown;
269
+ confirm?: unknown;
270
+ }, directive: DecodedDirective): boolean;
250
271
  interface ApplyDirectiveButtonProps {
251
272
  directive: DecodedDirective;
252
273
  label?: string;
253
274
  /** How many things this will write — shown during the wait so a long apply reads as work, not a frozen spinner. */
254
275
  itemCount?: number;
255
276
  onApplied?: () => void;
277
+ /** Told whenever what the control knows about its block changes. */
278
+ onPhase?: (phase: DirectiveApplyPhase) => void;
279
+ /**
280
+ * The block would change nothing (an update that sets no field). Apply stays
281
+ * — validation offers, never blocks — but muted, with the reason beside it.
282
+ */
283
+ nothingToChange?: boolean;
256
284
  }
257
- declare function ApplyDirectiveButton({ directive, label, itemCount, onApplied, }: ApplyDirectiveButtonProps): react.JSX.Element | null;
285
+ declare function ApplyDirectiveButton({ directive, label, itemCount, onApplied, onPhase, nothingToChange, }: ApplyDirectiveButtonProps): react.JSX.Element | null;
258
286
 
259
287
  /**
260
288
  * WHAT A DIRECTIVE ITEM WILL DO TO AN EXISTING RECORD — for the card, the
@@ -268,7 +296,7 @@ declare function ApplyDirectiveButton({ directive, label, itemCount, onApplied,
268
296
  * not the name of the record being changed. Naming the target is the host's
269
297
  * live lookup (`DirectiveHost.renderRecord`); what changes is right here.
270
298
  *
271
- * Law: common-docs/policies/destructive-and-expensive-actions.md — the sentence
299
+ * Law: common-docs/policies/no-dead-ends.md — the sentence
272
300
  * names what changes.
273
301
  */
274
302
  /** Classes whose items point at an EXISTING record by `id`. */
@@ -665,4 +693,4 @@ declare class DbKindComponentErrorBoundary extends react.Component<DbKindCompone
665
693
  render(): react.ReactNode;
666
694
  }
667
695
 
668
- 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, DirectiveFailure, DirectiveFailureWords, DirectiveFallbackCard, type DirectiveFallbackCardProps, DirectiveProvisionalCard, type DirectiveProvisionalCardProps, DirectiveRecordRef, DirectiveRender, type DirectiveRenderProps, type DirectiveRenderer, type DirectiveRendererProps, GenericStructuredView, type GenericStructuredViewProps, type ItemChange, type ItemChangesOptions, 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, defaultFailureWords, describeChangeValue, failureWords, fieldLabel, getDirectiveRenderer, isDbKindComponentBodyPending, isRecordValue, itemChanges, itemRecordId, kindIsRoutable, provisionalDirectiveSlug, recordFallbackName, registerDirectiveRenderer, resetDirectiveRenderers, useContentIrHost, useContentIrHostOrNull, useContentIrKindVersion, useKindRouteEnv, useRecordValues };
696
+ 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, type DirectiveApplyPhase, DirectiveChangeList, DirectiveFailure, DirectiveFailureWords, DirectiveFallbackCard, type DirectiveFallbackCardProps, DirectiveProvisionalCard, type DirectiveProvisionalCardProps, DirectiveRecordRef, DirectiveRender, type DirectiveRenderProps, type DirectiveRenderer, type DirectiveRendererProps, GenericStructuredView, type GenericStructuredViewProps, type ItemChange, type ItemChangesOptions, 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, defaultFailureWords, describeChangeValue, failureWords, fieldLabel, getDirectiveRenderer, isDbKindComponentBodyPending, isRecordValue, itemChanges, itemRecordId, kindIsRoutable, provisionalDirectiveSlug, readsApplyLedger, recordFallbackName, registerDirectiveRenderer, resetDirectiveRenderers, useContentIrHost, useContentIrHostOrNull, useContentIrKindVersion, useKindRouteEnv, useRecordValues };
package/dist/index.js CHANGED
@@ -953,17 +953,22 @@ function classIcon(directiveClass, noun) {
953
953
  import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
954
954
  var FINISH_POLL_MS = 2e3;
955
955
  var FINISH_POLLS_MAX = 30;
956
+ function readsApplyLedger(host, directive) {
957
+ return !!host.applyState && !!host.confirm && directive.parsed.executes && directive.items.length > 0;
958
+ }
956
959
  function ApplyDirectiveButton({
957
960
  directive,
958
961
  label = "Apply",
959
962
  itemCount,
960
- onApplied
963
+ onApplied,
964
+ onPhase,
965
+ nothingToChange = false
961
966
  }) {
962
967
  const host = useDirectiveHost();
963
968
  const scope = useDirectiveScope();
964
969
  const conversationId = scope.conversationId || void 0;
965
970
  const items = directive.items;
966
- const readsLedger = !!host.applyState && !!host.confirm && directive.parsed.executes && items.length > 0;
971
+ const readsLedger = readsApplyLedger(host, directive);
967
972
  const initial = readsLedger ? { status: "checking" } : { status: "idle" };
968
973
  const [state, setState] = useState(initial);
969
974
  const [elapsed, setElapsed] = useState(0);
@@ -1004,7 +1009,8 @@ function ApplyDirectiveButton({
1004
1009
  failed: 0,
1005
1010
  message: answer.message?.trim() ? answer.message.trim() : null,
1006
1011
  records: answer.records ?? [],
1007
- copies: Math.max(1, answer.copies ?? 1)
1012
+ copies: Math.max(1, answer.copies ?? 1),
1013
+ before: answer.before ?? null
1008
1014
  } : prev
1009
1015
  );
1010
1016
  } else if (answer.state === "in_flight" && polls < FINISH_POLLS_MAX) {
@@ -1029,6 +1035,15 @@ function ApplyDirectiveButton({
1029
1035
  if (timer) clearTimeout(timer);
1030
1036
  };
1031
1037
  }, [shellKey, read, report]);
1038
+ const appliedClean = state.status === "applied" && state.failed === 0 ? state : null;
1039
+ const appliedBefore = appliedClean ? appliedClean.before : null;
1040
+ const phaseKey = state.status === "checking" || state.status === "finishing" ? "pending" : appliedClean ? `applied:${JSON.stringify(appliedBefore)}` : "open";
1041
+ useEffect(() => {
1042
+ if (!onPhase) return;
1043
+ if (phaseKey === "pending") onPhase({ phase: "pending" });
1044
+ else if (phaseKey === "open") onPhase({ phase: "open" });
1045
+ else onPhase({ phase: "applied", before: appliedBefore });
1046
+ }, [phaseKey, onPhase, appliedBefore]);
1032
1047
  useEffect(() => {
1033
1048
  if (state.status !== "applying") return;
1034
1049
  startedAt.current = Date.now();
@@ -1043,7 +1058,7 @@ function ApplyDirectiveButton({
1043
1058
  if (!confirm) return null;
1044
1059
  async function handleApply(again = false) {
1045
1060
  if (!confirm) return;
1046
- const before = state;
1061
+ const prior = state;
1047
1062
  const askedFor = identity;
1048
1063
  const stillHere = () => currentIdentity.current === askedFor;
1049
1064
  const priorCopies = state.status === "applied" ? state.copies : 0;
@@ -1070,7 +1085,7 @@ function ApplyDirectiveButton({
1070
1085
  if (!stillHere()) return;
1071
1086
  setAskingAgain(false);
1072
1087
  if (!ok) {
1073
- setState(again ? before : { status: "idle" });
1088
+ setState(again ? prior : { status: "idle" });
1074
1089
  return;
1075
1090
  }
1076
1091
  }
@@ -1089,7 +1104,10 @@ function ApplyDirectiveButton({
1089
1104
  message: result.message?.trim() ? result.message.trim() : null,
1090
1105
  records: result.records ?? [],
1091
1106
  // "Run again" made one more; a first apply (or a replay of one) is one.
1092
- copies: again ? Math.max(1, priorCopies) + 1 : Math.max(1, priorCopies)
1107
+ copies: again ? Math.max(1, priorCopies) + 1 : Math.max(1, priorCopies),
1108
+ // "Run again" wrote the same values over themselves; what the FIRST
1109
+ // apply replaced is still the change this block made.
1110
+ before: again && prior.status === "applied" && prior.before ? prior.before : result.before ?? null
1093
1111
  });
1094
1112
  onApplied?.();
1095
1113
  } catch (error) {
@@ -1191,15 +1209,18 @@ function ApplyDirectiveButton({
1191
1209
  );
1192
1210
  }
1193
1211
  const destructive = directive.directiveClass === "delete";
1212
+ const muted = nothingToChange && state.status === "idle";
1194
1213
  return /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-2", children: [
1214
+ muted ? /* @__PURE__ */ jsx4("span", { className: "text-xs text-muted-foreground", "data-apply-nothing": "", children: "Nothing to change" }) : null,
1195
1215
  /* @__PURE__ */ jsxs2(
1196
1216
  "button",
1197
1217
  {
1198
1218
  type: "button",
1199
1219
  onClick: () => void handleApply(),
1200
1220
  disabled: state.status === "applying" || state.status === "asking" || items.length === 0,
1201
- "data-apply-tone": destructive ? "destructive" : "default",
1202
- 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"}`,
1221
+ "data-apply-tone": muted ? "muted" : destructive ? "destructive" : "default",
1222
+ title: muted ? "It sets no fields, so applying it changes nothing." : void 0,
1223
+ 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"}`,
1203
1224
  children: [
1204
1225
  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" }),
1205
1226
  state.status === "applying" ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? "item" : "items"}` : ""}\u2026${elapsed ? ` ${elapsed}s` : ""}` : label
@@ -1405,12 +1426,13 @@ function ItemRow({
1405
1426
  directive,
1406
1427
  item,
1407
1428
  index,
1408
- total
1429
+ total,
1430
+ phase
1409
1431
  }) {
1410
1432
  const host = useDirectiveHost();
1411
1433
  const recordId = TARGETING_CLASSES.has(directive.directiveClass) ? itemRecordId(item) : null;
1412
1434
  if (recordId) {
1413
- return /* @__PURE__ */ jsx7(TargetRow, { directive, item, recordId });
1435
+ return /* @__PURE__ */ jsx7(TargetRow, { directive, item, recordId, index, phase });
1414
1436
  }
1415
1437
  const titleColumn = nounTitleColumn(directive.noun, host.nouns);
1416
1438
  const title = itemTitle(item, titleColumn, index, total);
@@ -1497,16 +1519,20 @@ function DirectiveChangeList({
1497
1519
  function TargetRow({
1498
1520
  directive,
1499
1521
  item,
1500
- recordId
1522
+ recordId,
1523
+ index,
1524
+ phase
1501
1525
  }) {
1502
1526
  const host = useDirectiveHost();
1503
1527
  const fallback = recordFallbackName(nounLabel2(directive.noun, host.nouns), recordId);
1504
1528
  const isUpdate = directive.directiveClass === "update";
1505
- const current = useRecordValues(
1506
- isUpdate ? host.readRecord : void 0,
1507
- isUpdate ? { noun: directive.noun, id: recordId } : null
1529
+ const readsLive = isUpdate && phase.phase === "open";
1530
+ const live = useRecordValues(
1531
+ readsLive ? host.readRecord : void 0,
1532
+ readsLive ? { noun: directive.noun, id: recordId } : null
1508
1533
  );
1509
- const changes = isUpdate ? itemChanges(item, current.values, { titleColumn: nounTitleColumn(directive.noun, host.nouns) }) : [];
1534
+ const compareTo = phase.phase === "applied" ? phase.before?.[index] ?? null : readsLive ? live.values : null;
1535
+ const changes = isUpdate ? itemChanges(item, compareTo, { titleColumn: nounTitleColumn(directive.noun, host.nouns) }) : [];
1510
1536
  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 });
1511
1537
  return /* @__PURE__ */ jsxs5("div", { className: "py-1 text-xs", "data-directive-target": recordId, children: [
1512
1538
  /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 items-center gap-2", children: [
@@ -1523,6 +1549,10 @@ function SideEffectDirectiveCard({ directive }) {
1523
1549
  const total = items.length;
1524
1550
  const display = directiveDisplay3(directive.directiveClass, directive.noun, host.nouns);
1525
1551
  const Icon = classIcon(directive.directiveClass, directive.noun);
1552
+ const [phase, setPhase] = useState3(
1553
+ () => readsApplyLedger(host, directive) ? { phase: "pending" } : { phase: "open" }
1554
+ );
1555
+ const nothingToChange = directive.directiveClass === "update" && total > 0 && items.every((item) => itemChanges(item).length === 0);
1526
1556
  const shown = expanded ? items : items.slice(0, ROWS_BEFORE_FOLD);
1527
1557
  const hidden = total - shown.length;
1528
1558
  return /* @__PURE__ */ jsxs5("div", { className: "my-3 rounded-md border border-border bg-card px-2.5 py-1.5", "data-directive": directive.slug, children: [
@@ -1537,13 +1567,21 @@ function SideEffectDirectiveCard({ directive }) {
1537
1567
  ] }),
1538
1568
  /* @__PURE__ */ jsxs5("div", { className: "ml-auto flex items-center gap-1", children: [
1539
1569
  host.renderCopy?.({ label: display.title, value: directive.shell, size: "icon" }),
1540
- /* @__PURE__ */ jsx7(ApplyDirectiveButton, { directive, itemCount: total })
1570
+ /* @__PURE__ */ jsx7(
1571
+ ApplyDirectiveButton,
1572
+ {
1573
+ directive,
1574
+ itemCount: total,
1575
+ onPhase: setPhase,
1576
+ nothingToChange
1577
+ }
1578
+ )
1541
1579
  ] })
1542
1580
  ] }),
1543
1581
  total === 0 ? (
1544
1582
  // Stated, never silent: an empty batch is a real (and suspicious) state.
1545
1583
  /* @__PURE__ */ jsx7("p", { className: "mt-1 text-xs text-muted-foreground", children: "No items \u2014 nothing would be written." })
1546
- ) : /* @__PURE__ */ jsx7("div", { className: "mt-0.5 divide-y divide-border/60", children: shown.map((item, i) => /* @__PURE__ */ jsx7(ItemRow, { directive, item, index: i, total }, i)) }),
1584
+ ) : /* @__PURE__ */ jsx7("div", { className: "mt-0.5 divide-y divide-border/60", children: shown.map((item, i) => /* @__PURE__ */ jsx7(ItemRow, { directive, item, index: i, total, phase }, i)) }),
1547
1585
  hidden > 0 || expanded ? /* @__PURE__ */ jsxs5(
1548
1586
  "button",
1549
1587
  {
@@ -2071,6 +2109,7 @@ export {
2071
2109
  markKindPartialUnsafe,
2072
2110
  provisionalDirectiveSlug,
2073
2111
  readIrRouteMarker,
2112
+ readsApplyLedger,
2074
2113
  recordFallbackName,
2075
2114
  registerDirectiveRenderer,
2076
2115
  resetDirectiveRenderers,