@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/CHANGELOG.md +41 -0
- package/dist/{directive-host-Bl-ZgJWp.d.cts → directive-host-DJfF35FD.d.cts} +68 -5
- package/dist/{directive-host-Bl-ZgJWp.d.ts → directive-host-DJfF35FD.d.ts} +68 -5
- package/dist/directives.cjs +128 -10
- package/dist/directives.cjs.map +1 -1
- package/dist/directives.d.cts +9 -2
- package/dist/directives.d.ts +9 -2
- package/dist/directives.js +128 -10
- package/dist/directives.js.map +1 -1
- package/dist/{host-types-Cz-1pGHz.d.ts → host-types-9NfBeqrG.d.ts} +1 -1
- package/dist/{host-types-BgROpyjE.d.cts → host-types-DVIaaGR_.d.cts} +1 -1
- package/dist/host.cjs +1 -0
- package/dist/host.cjs.map +1 -1
- package/dist/host.d.cts +3 -3
- package/dist/host.d.ts +3 -3
- package/dist/host.js +1 -0
- package/dist/host.js.map +1 -1
- package/dist/index.cjs +127 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +127 -9
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +125 -9
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +125 -9
- package/dist/react.js.map +1 -1
- package/dist/{route-DxK1SoPh.d.cts → route-BCtPhF7W.d.cts} +68 -5
- package/dist/{route-JGZfl2nL.d.ts → route-DDbgc-ID.d.ts} +68 -5
- package/dist/route.d.cts +1 -1
- package/dist/route.d.ts +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,46 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.15.0 — 2026-10-02
|
|
4
|
+
|
|
5
|
+
- **A card in a chat message applies under its conversation.** New
|
|
6
|
+
`DirectiveScopeProvider` / `useDirectiveScope` and a `conversationId` prop on
|
|
7
|
+
`DirectiveRender`. The Apply control passes it to BOTH `confirm` and
|
|
8
|
+
`applyState` as `shell.conversationId` — the namespace an agent proposal's
|
|
9
|
+
Approve uses — so one action rendered twice (proposal card + in-message card)
|
|
10
|
+
keys once and can never apply twice. A note mounts no scope (person namespace).
|
|
11
|
+
- **Run again.** A clean tally carries "Run again": it calls `ask` with
|
|
12
|
+
`again: true` (the question must say it runs a SECOND time) and only a yes
|
|
13
|
+
sends `shell.force = true`; a no leaves the tally as it was. A tally with a
|
|
14
|
+
failed item carries "Retry" instead — a plain apply, never `force`.
|
|
15
|
+
- `confirm` / `applyState` now take `DirectiveShell` (`__kind`, `items`,
|
|
16
|
+
optional `conversationId`, optional `force`).
|
|
17
|
+
|
|
18
|
+
### Consumer action
|
|
19
|
+
|
|
20
|
+
- Pass the conversation a message renders in (`DirectiveRender conversationId`
|
|
21
|
+
or `DirectiveScopeProvider`), and forward `shell.conversationId` as
|
|
22
|
+
`conversation_id` and `shell.force` as `force` to `/directives/confirm`
|
|
23
|
+
(and `conversationId` to `/directives/apply_state`).
|
|
24
|
+
- Word your `ask` dialog for `request.again`.
|
|
25
|
+
|
|
26
|
+
## 0.14.0 — 2026-10-02
|
|
27
|
+
|
|
28
|
+
- **A card survives a reload.** New host seam `applyState(shell)` →
|
|
29
|
+
`DirectiveApplyState` (`not_applied` | `in_flight` | `applied`, with the
|
|
30
|
+
ledger's own `message` and the `records` it wrote). The Apply control reads it
|
|
31
|
+
once on mount: while it answers nothing offers a write (a quiet spinner); an
|
|
32
|
+
`applied` block mounts as its tally — the same sentence and record doors a
|
|
33
|
+
fresh apply leaves — instead of "Apply" again; `in_flight` reads "Finishing…"
|
|
34
|
+
and re-asks every 2 s for up to a minute; a read that fails is reported through
|
|
35
|
+
`reportError` and Apply is offered (safe: `confirm` is idempotent). Absent seam
|
|
36
|
+
→ unchanged behaviour.
|
|
37
|
+
|
|
38
|
+
### Consumer action
|
|
39
|
+
|
|
40
|
+
- Wire `applyState` to the server's ledger read (`POST /directives/apply_state`
|
|
41
|
+
in the SAME namespace your `confirm` applies in — for a block in a person's own
|
|
42
|
+
content, no conversation), batched if a page carries many cards.
|
|
43
|
+
|
|
3
44
|
## 0.13.18
|
|
4
45
|
|
|
5
46
|
Automatic changed-only republish (docs/metadata drift since the last tag — see
|
|
@@ -16,6 +16,25 @@ interface DirectiveApplyResult {
|
|
|
16
16
|
*/
|
|
17
17
|
records?: DirectiveRecordRef[];
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* What the server's action ledger says about ONE block, read on mount so a
|
|
21
|
+
* reloaded page never offers "Apply" for work that already ran (reviewer
|
|
22
|
+
* defect 5, 2026-10-02).
|
|
23
|
+
*
|
|
24
|
+
* - `not_applied` — still to do (or partly done: the batch re-applies, and the
|
|
25
|
+
* server replays the members it already holds). The card offers Apply.
|
|
26
|
+
* - `in_flight` — another request is applying it right now. The card says it
|
|
27
|
+
* is finishing and asks again shortly; it offers neither Apply nor a tally.
|
|
28
|
+
* - `applied` — the ledger holds every item. The card shows the tally exactly
|
|
29
|
+
* as a fresh apply would: the ledger's own sentence and the records, as doors.
|
|
30
|
+
*/
|
|
31
|
+
interface DirectiveApplyState {
|
|
32
|
+
state: "not_applied" | "in_flight" | "applied";
|
|
33
|
+
/** The ledger row's sentence ("Created task."), never composed client-side. */
|
|
34
|
+
message?: string | null;
|
|
35
|
+
/** The records the original apply wrote — the tally's doors. */
|
|
36
|
+
records?: DirectiveRecordRef[];
|
|
37
|
+
}
|
|
19
38
|
/** One record a directive names: the noun it is, and its id. */
|
|
20
39
|
interface DirectiveRecordRef {
|
|
21
40
|
noun: string;
|
|
@@ -42,6 +61,28 @@ interface DirectiveAskRequest {
|
|
|
42
61
|
items: Record<string, unknown>[];
|
|
43
62
|
/** The noun's human label ("Task"), from the host's catalog when it has one. */
|
|
44
63
|
nounLabel: string;
|
|
64
|
+
/**
|
|
65
|
+
* True for "Run again": the ledger already holds this block, and a yes runs
|
|
66
|
+
* it a SECOND time (`force`) — another copy for a create, the same fields
|
|
67
|
+
* written again for an update, another delete for a restored record. The
|
|
68
|
+
* question must say so.
|
|
69
|
+
*/
|
|
70
|
+
again?: boolean;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The shell a card hands its host — the two keys, plus WHERE it sits.
|
|
74
|
+
*
|
|
75
|
+
* `conversationId` is the conversation the card renders in (a chat message),
|
|
76
|
+
* absent in a person's own content (a note). It is the idempotency NAMESPACE:
|
|
77
|
+
* a card in an agent's message must apply under the SAME key as that
|
|
78
|
+
* proposal's Approve button, or the one action could run twice.
|
|
79
|
+
*/
|
|
80
|
+
interface DirectiveShell {
|
|
81
|
+
__kind: string;
|
|
82
|
+
items: Record<string, unknown>[];
|
|
83
|
+
conversationId?: string;
|
|
84
|
+
/** "Run again": skip the ledger's dedup and apply a second time. */
|
|
85
|
+
force?: boolean;
|
|
45
86
|
}
|
|
46
87
|
interface DirectiveOpenItemOptions {
|
|
47
88
|
/** The item, `__kind`-stamped when the shape has an item kind. */
|
|
@@ -70,10 +111,7 @@ interface DirectiveHost {
|
|
|
70
111
|
* item against the registered model and runs the ONE handler; idempotent).
|
|
71
112
|
* Reject with an Error whose message is safe to show.
|
|
72
113
|
*/
|
|
73
|
-
confirm?: (shell:
|
|
74
|
-
__kind: string;
|
|
75
|
-
items: Record<string, unknown>[];
|
|
76
|
-
}) => Promise<DirectiveApplyResult>;
|
|
114
|
+
confirm?: (shell: DirectiveShell) => Promise<DirectiveApplyResult>;
|
|
77
115
|
/**
|
|
78
116
|
* Ask the person BEFORE anything runs, naming the consequence (the records,
|
|
79
117
|
* what changes). Resolve `true` to go ahead, `false` to leave the card as it
|
|
@@ -83,6 +121,17 @@ interface DirectiveHost {
|
|
|
83
121
|
* will read "Applying…" while its dialog is up).
|
|
84
122
|
*/
|
|
85
123
|
ask?: (request: DirectiveAskRequest) => Promise<boolean>;
|
|
124
|
+
/**
|
|
125
|
+
* Has this exact block already been applied? Read ONCE when the card mounts
|
|
126
|
+
* (and again while the answer is `in_flight`), so the card survives a reload:
|
|
127
|
+
* the server ledger, not component state, is what knows. The identity is the
|
|
128
|
+
* server's (it hashes the validated items in the same namespace `confirm`
|
|
129
|
+
* applies in), so a host asks — it never computes. Batch on the host side if
|
|
130
|
+
* a page carries many cards. Reject with an Error when the ledger cannot be
|
|
131
|
+
* read: the card reports it and offers Apply, which is safe because `confirm`
|
|
132
|
+
* is idempotent. Absent → the card starts at Apply, as before.
|
|
133
|
+
*/
|
|
134
|
+
applyState?: (shell: DirectiveShell) => Promise<DirectiveApplyState>;
|
|
86
135
|
/**
|
|
87
136
|
* Draw ONE existing record by its live name, as a way to open it. Used on
|
|
88
137
|
* update/delete rows (the record that will change), in the host's own ask
|
|
@@ -101,6 +150,20 @@ interface DirectiveHost {
|
|
|
101
150
|
/** Where a decode failure or an unhonourable shell is reported. Default: console.error. */
|
|
102
151
|
reportError?: (message: string) => void;
|
|
103
152
|
}
|
|
153
|
+
/** Where a directive renders — today, the conversation it sits in (if any). */
|
|
154
|
+
interface DirectiveScope {
|
|
155
|
+
conversationId?: string | null;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Tell every card below WHERE it renders. A host draws a chat message's
|
|
159
|
+
* directives inside one of these (or passes `conversationId` to
|
|
160
|
+
* `DirectiveRender`), so the card applies in that conversation's namespace —
|
|
161
|
+
* the same key the agent's proposal approves under. A note mounts none.
|
|
162
|
+
*/
|
|
163
|
+
declare function DirectiveScopeProvider({ conversationId, children, }: DirectiveScope & {
|
|
164
|
+
children: ReactNode;
|
|
165
|
+
}): react.JSX.Element;
|
|
166
|
+
declare function useDirectiveScope(): DirectiveScope;
|
|
104
167
|
interface DirectiveHostProviderProps {
|
|
105
168
|
host: DirectiveHost;
|
|
106
169
|
children: ReactNode;
|
|
@@ -113,4 +176,4 @@ declare function DirectiveHostProvider({ host, children }: DirectiveHostProvider
|
|
|
113
176
|
*/
|
|
114
177
|
declare function useDirectiveHost(): DirectiveHost;
|
|
115
178
|
|
|
116
|
-
export { type DirectiveApplyResult as D, type
|
|
179
|
+
export { type DirectiveApplyResult as D, type DirectiveApplyState as a, type DirectiveAskRequest as b, type DirectiveCopyProps as c, type DirectiveHost as d, DirectiveHostProvider as e, type DirectiveHostProviderProps as f, type DirectiveOpenItemOptions as g, type DirectiveRecordProps as h, type DirectiveRecordRef as i, type DirectiveScope as j, DirectiveScopeProvider as k, type DirectiveShell as l, useDirectiveScope as m, useDirectiveHost as u };
|
|
@@ -16,6 +16,25 @@ interface DirectiveApplyResult {
|
|
|
16
16
|
*/
|
|
17
17
|
records?: DirectiveRecordRef[];
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* What the server's action ledger says about ONE block, read on mount so a
|
|
21
|
+
* reloaded page never offers "Apply" for work that already ran (reviewer
|
|
22
|
+
* defect 5, 2026-10-02).
|
|
23
|
+
*
|
|
24
|
+
* - `not_applied` — still to do (or partly done: the batch re-applies, and the
|
|
25
|
+
* server replays the members it already holds). The card offers Apply.
|
|
26
|
+
* - `in_flight` — another request is applying it right now. The card says it
|
|
27
|
+
* is finishing and asks again shortly; it offers neither Apply nor a tally.
|
|
28
|
+
* - `applied` — the ledger holds every item. The card shows the tally exactly
|
|
29
|
+
* as a fresh apply would: the ledger's own sentence and the records, as doors.
|
|
30
|
+
*/
|
|
31
|
+
interface DirectiveApplyState {
|
|
32
|
+
state: "not_applied" | "in_flight" | "applied";
|
|
33
|
+
/** The ledger row's sentence ("Created task."), never composed client-side. */
|
|
34
|
+
message?: string | null;
|
|
35
|
+
/** The records the original apply wrote — the tally's doors. */
|
|
36
|
+
records?: DirectiveRecordRef[];
|
|
37
|
+
}
|
|
19
38
|
/** One record a directive names: the noun it is, and its id. */
|
|
20
39
|
interface DirectiveRecordRef {
|
|
21
40
|
noun: string;
|
|
@@ -42,6 +61,28 @@ interface DirectiveAskRequest {
|
|
|
42
61
|
items: Record<string, unknown>[];
|
|
43
62
|
/** The noun's human label ("Task"), from the host's catalog when it has one. */
|
|
44
63
|
nounLabel: string;
|
|
64
|
+
/**
|
|
65
|
+
* True for "Run again": the ledger already holds this block, and a yes runs
|
|
66
|
+
* it a SECOND time (`force`) — another copy for a create, the same fields
|
|
67
|
+
* written again for an update, another delete for a restored record. The
|
|
68
|
+
* question must say so.
|
|
69
|
+
*/
|
|
70
|
+
again?: boolean;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The shell a card hands its host — the two keys, plus WHERE it sits.
|
|
74
|
+
*
|
|
75
|
+
* `conversationId` is the conversation the card renders in (a chat message),
|
|
76
|
+
* absent in a person's own content (a note). It is the idempotency NAMESPACE:
|
|
77
|
+
* a card in an agent's message must apply under the SAME key as that
|
|
78
|
+
* proposal's Approve button, or the one action could run twice.
|
|
79
|
+
*/
|
|
80
|
+
interface DirectiveShell {
|
|
81
|
+
__kind: string;
|
|
82
|
+
items: Record<string, unknown>[];
|
|
83
|
+
conversationId?: string;
|
|
84
|
+
/** "Run again": skip the ledger's dedup and apply a second time. */
|
|
85
|
+
force?: boolean;
|
|
45
86
|
}
|
|
46
87
|
interface DirectiveOpenItemOptions {
|
|
47
88
|
/** The item, `__kind`-stamped when the shape has an item kind. */
|
|
@@ -70,10 +111,7 @@ interface DirectiveHost {
|
|
|
70
111
|
* item against the registered model and runs the ONE handler; idempotent).
|
|
71
112
|
* Reject with an Error whose message is safe to show.
|
|
72
113
|
*/
|
|
73
|
-
confirm?: (shell:
|
|
74
|
-
__kind: string;
|
|
75
|
-
items: Record<string, unknown>[];
|
|
76
|
-
}) => Promise<DirectiveApplyResult>;
|
|
114
|
+
confirm?: (shell: DirectiveShell) => Promise<DirectiveApplyResult>;
|
|
77
115
|
/**
|
|
78
116
|
* Ask the person BEFORE anything runs, naming the consequence (the records,
|
|
79
117
|
* what changes). Resolve `true` to go ahead, `false` to leave the card as it
|
|
@@ -83,6 +121,17 @@ interface DirectiveHost {
|
|
|
83
121
|
* will read "Applying…" while its dialog is up).
|
|
84
122
|
*/
|
|
85
123
|
ask?: (request: DirectiveAskRequest) => Promise<boolean>;
|
|
124
|
+
/**
|
|
125
|
+
* Has this exact block already been applied? Read ONCE when the card mounts
|
|
126
|
+
* (and again while the answer is `in_flight`), so the card survives a reload:
|
|
127
|
+
* the server ledger, not component state, is what knows. The identity is the
|
|
128
|
+
* server's (it hashes the validated items in the same namespace `confirm`
|
|
129
|
+
* applies in), so a host asks — it never computes. Batch on the host side if
|
|
130
|
+
* a page carries many cards. Reject with an Error when the ledger cannot be
|
|
131
|
+
* read: the card reports it and offers Apply, which is safe because `confirm`
|
|
132
|
+
* is idempotent. Absent → the card starts at Apply, as before.
|
|
133
|
+
*/
|
|
134
|
+
applyState?: (shell: DirectiveShell) => Promise<DirectiveApplyState>;
|
|
86
135
|
/**
|
|
87
136
|
* Draw ONE existing record by its live name, as a way to open it. Used on
|
|
88
137
|
* update/delete rows (the record that will change), in the host's own ask
|
|
@@ -101,6 +150,20 @@ interface DirectiveHost {
|
|
|
101
150
|
/** Where a decode failure or an unhonourable shell is reported. Default: console.error. */
|
|
102
151
|
reportError?: (message: string) => void;
|
|
103
152
|
}
|
|
153
|
+
/** Where a directive renders — today, the conversation it sits in (if any). */
|
|
154
|
+
interface DirectiveScope {
|
|
155
|
+
conversationId?: string | null;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Tell every card below WHERE it renders. A host draws a chat message's
|
|
159
|
+
* directives inside one of these (or passes `conversationId` to
|
|
160
|
+
* `DirectiveRender`), so the card applies in that conversation's namespace —
|
|
161
|
+
* the same key the agent's proposal approves under. A note mounts none.
|
|
162
|
+
*/
|
|
163
|
+
declare function DirectiveScopeProvider({ conversationId, children, }: DirectiveScope & {
|
|
164
|
+
children: ReactNode;
|
|
165
|
+
}): react.JSX.Element;
|
|
166
|
+
declare function useDirectiveScope(): DirectiveScope;
|
|
104
167
|
interface DirectiveHostProviderProps {
|
|
105
168
|
host: DirectiveHost;
|
|
106
169
|
children: ReactNode;
|
|
@@ -113,4 +176,4 @@ declare function DirectiveHostProvider({ host, children }: DirectiveHostProvider
|
|
|
113
176
|
*/
|
|
114
177
|
declare function useDirectiveHost(): DirectiveHost;
|
|
115
178
|
|
|
116
|
-
export { type DirectiveApplyResult as D, type
|
|
179
|
+
export { type DirectiveApplyResult as D, type DirectiveApplyState as a, type DirectiveAskRequest as b, type DirectiveCopyProps as c, type DirectiveHost as d, DirectiveHostProvider as e, type DirectiveHostProviderProps as f, type DirectiveOpenItemOptions as g, type DirectiveRecordProps as h, type DirectiveRecordRef as i, type DirectiveScope as j, DirectiveScopeProvider as k, type DirectiveShell as l, useDirectiveScope as m, useDirectiveHost as u };
|
package/dist/directives.cjs
CHANGED
|
@@ -27,6 +27,7 @@ __export(directives_exports, {
|
|
|
27
27
|
DirectiveHostProvider: () => DirectiveHostProvider,
|
|
28
28
|
DirectiveProvisionalCard: () => DirectiveProvisionalCard,
|
|
29
29
|
DirectiveRender: () => DirectiveRender,
|
|
30
|
+
DirectiveScopeProvider: () => DirectiveScopeProvider,
|
|
30
31
|
SideEffectDirectiveCard: () => SideEffectDirectiveCard,
|
|
31
32
|
TARGETING_CLASSES: () => TARGETING_CLASSES,
|
|
32
33
|
fieldLabel: () => fieldLabel,
|
|
@@ -37,7 +38,8 @@ __export(directives_exports, {
|
|
|
37
38
|
recordFallbackName: () => recordFallbackName,
|
|
38
39
|
registerDirectiveRenderer: () => registerDirectiveRenderer,
|
|
39
40
|
resetDirectiveRenderers: () => resetDirectiveRenderers,
|
|
40
|
-
useDirectiveHost: () => useDirectiveHost
|
|
41
|
+
useDirectiveHost: () => useDirectiveHost,
|
|
42
|
+
useDirectiveScope: () => useDirectiveScope
|
|
41
43
|
});
|
|
42
44
|
module.exports = __toCommonJS(directives_exports);
|
|
43
45
|
|
|
@@ -45,6 +47,16 @@ module.exports = __toCommonJS(directives_exports);
|
|
|
45
47
|
var import_react = require("react");
|
|
46
48
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
47
49
|
var DirectiveHostContext = (0, import_react.createContext)(null);
|
|
50
|
+
var DirectiveScopeContext = (0, import_react.createContext)({});
|
|
51
|
+
function DirectiveScopeProvider({
|
|
52
|
+
conversationId,
|
|
53
|
+
children
|
|
54
|
+
}) {
|
|
55
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DirectiveScopeContext.Provider, { value: { conversationId: conversationId ?? null }, children });
|
|
56
|
+
}
|
|
57
|
+
function useDirectiveScope() {
|
|
58
|
+
return (0, import_react.useContext)(DirectiveScopeContext);
|
|
59
|
+
}
|
|
48
60
|
function DirectiveHostProvider({ host, children }) {
|
|
49
61
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DirectiveHostContext.Provider, { value: host, children });
|
|
50
62
|
}
|
|
@@ -197,6 +209,10 @@ var MaximizeIcon = (p) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Svg, { .
|
|
|
197
209
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("line", { x1: "3", x2: "10", y1: "21", y2: "14" })
|
|
198
210
|
] });
|
|
199
211
|
var LoaderIcon = (p) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Svg, { ...p, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
|
|
212
|
+
var RotateCcwIcon = (p) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Svg, { ...p, children: [
|
|
213
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
|
|
214
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M3 3v5h5" })
|
|
215
|
+
] });
|
|
200
216
|
var CheckCircleIcon = (p) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Svg, { ...p, children: [
|
|
201
217
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
|
|
202
218
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "m9 12 2 2 4-4" })
|
|
@@ -223,6 +239,8 @@ function classIcon(directiveClass, noun) {
|
|
|
223
239
|
|
|
224
240
|
// directives/ApplyDirectiveButton.tsx
|
|
225
241
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
242
|
+
var FINISH_POLL_MS = 2e3;
|
|
243
|
+
var FINISH_POLLS_MAX = 30;
|
|
226
244
|
function ApplyDirectiveButton({
|
|
227
245
|
directive,
|
|
228
246
|
label = "Apply",
|
|
@@ -230,9 +248,62 @@ function ApplyDirectiveButton({
|
|
|
230
248
|
onApplied
|
|
231
249
|
}) {
|
|
232
250
|
const host = useDirectiveHost();
|
|
233
|
-
const
|
|
251
|
+
const scope = useDirectiveScope();
|
|
252
|
+
const conversationId = scope.conversationId || void 0;
|
|
253
|
+
const items = directive.items;
|
|
254
|
+
const readsLedger = !!host.applyState && !!host.confirm && directive.parsed.executes && items.length > 0;
|
|
255
|
+
const [state, setState] = (0, import_react2.useState)(
|
|
256
|
+
readsLedger ? { status: "checking" } : { status: "idle" }
|
|
257
|
+
);
|
|
234
258
|
const [elapsed, setElapsed] = (0, import_react2.useState)(0);
|
|
235
259
|
const startedAt = (0, import_react2.useRef)(null);
|
|
260
|
+
const nounText = (0, import_content_ir2.nounLabel)(directive.noun, host.nouns);
|
|
261
|
+
const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : "";
|
|
262
|
+
const read = host.applyState;
|
|
263
|
+
const report = host.reportError;
|
|
264
|
+
(0, import_react2.useEffect)(() => {
|
|
265
|
+
if (!shellKey || !read) return;
|
|
266
|
+
const [slug, shellItems, inConversation] = JSON.parse(shellKey);
|
|
267
|
+
const shell = { __kind: slug, items: shellItems };
|
|
268
|
+
if (inConversation) shell.conversationId = inConversation;
|
|
269
|
+
let live = true;
|
|
270
|
+
let polls = 0;
|
|
271
|
+
let timer = null;
|
|
272
|
+
const ask = () => {
|
|
273
|
+
read(shell).then((answer) => {
|
|
274
|
+
if (!live) return;
|
|
275
|
+
if (answer.state === "applied") {
|
|
276
|
+
setState(
|
|
277
|
+
(prev) => prev.status === "checking" || prev.status === "finishing" ? {
|
|
278
|
+
status: "applied",
|
|
279
|
+
applied: shellItems.length,
|
|
280
|
+
failed: 0,
|
|
281
|
+
message: answer.message?.trim() ? answer.message.trim() : null,
|
|
282
|
+
records: answer.records ?? []
|
|
283
|
+
} : prev
|
|
284
|
+
);
|
|
285
|
+
} else if (answer.state === "in_flight" && polls < FINISH_POLLS_MAX) {
|
|
286
|
+
polls += 1;
|
|
287
|
+
setState((prev) => prev.status === "checking" || prev.status === "finishing" ? { status: "finishing" } : prev);
|
|
288
|
+
timer = setTimeout(ask, FINISH_POLL_MS);
|
|
289
|
+
} else {
|
|
290
|
+
setState((prev) => prev.status === "checking" || prev.status === "finishing" ? { status: "idle" } : prev);
|
|
291
|
+
}
|
|
292
|
+
}).catch((error) => {
|
|
293
|
+
if (!live) return;
|
|
294
|
+
const why = error instanceof Error && error.message ? error.message : String(error);
|
|
295
|
+
(report ?? console.error)(
|
|
296
|
+
`[kind-directives] Could not read whether ${slug} was already applied: ${why}`
|
|
297
|
+
);
|
|
298
|
+
setState((prev) => prev.status === "checking" || prev.status === "finishing" ? { status: "idle" } : prev);
|
|
299
|
+
});
|
|
300
|
+
};
|
|
301
|
+
ask();
|
|
302
|
+
return () => {
|
|
303
|
+
live = false;
|
|
304
|
+
if (timer) clearTimeout(timer);
|
|
305
|
+
};
|
|
306
|
+
}, [shellKey, read, report]);
|
|
236
307
|
(0, import_react2.useEffect)(() => {
|
|
237
308
|
if (state.status !== "applying") return;
|
|
238
309
|
startedAt.current = Date.now();
|
|
@@ -245,9 +316,9 @@ function ApplyDirectiveButton({
|
|
|
245
316
|
if (!directive.parsed.executes) return null;
|
|
246
317
|
const confirm = host.confirm;
|
|
247
318
|
if (!confirm) return null;
|
|
248
|
-
|
|
249
|
-
async function handleApply() {
|
|
319
|
+
async function handleApply(again = false) {
|
|
250
320
|
if (!confirm) return;
|
|
321
|
+
const before = state;
|
|
251
322
|
if (host.ask) {
|
|
252
323
|
setState({ status: "asking" });
|
|
253
324
|
let ok = false;
|
|
@@ -255,7 +326,8 @@ function ApplyDirectiveButton({
|
|
|
255
326
|
ok = await host.ask({
|
|
256
327
|
directive,
|
|
257
328
|
items,
|
|
258
|
-
nounLabel:
|
|
329
|
+
nounLabel: nounText,
|
|
330
|
+
...again ? { again: true } : {}
|
|
259
331
|
});
|
|
260
332
|
} catch (error) {
|
|
261
333
|
setState({
|
|
@@ -265,14 +337,17 @@ function ApplyDirectiveButton({
|
|
|
265
337
|
return;
|
|
266
338
|
}
|
|
267
339
|
if (!ok) {
|
|
268
|
-
setState({ status: "idle" });
|
|
340
|
+
setState(again ? before : { status: "idle" });
|
|
269
341
|
return;
|
|
270
342
|
}
|
|
271
343
|
}
|
|
272
344
|
setElapsed(0);
|
|
273
345
|
setState({ status: "applying" });
|
|
274
346
|
try {
|
|
275
|
-
const
|
|
347
|
+
const shell = { __kind: directive.slug, items };
|
|
348
|
+
if (conversationId) shell.conversationId = conversationId;
|
|
349
|
+
if (again) shell.force = true;
|
|
350
|
+
const result = await confirm(shell);
|
|
276
351
|
setState({
|
|
277
352
|
status: "applied",
|
|
278
353
|
applied: result.applied,
|
|
@@ -291,7 +366,7 @@ function ApplyDirectiveButton({
|
|
|
291
366
|
if (state.status === "applied") {
|
|
292
367
|
const bad = state.failed > 0;
|
|
293
368
|
const trashed = directive.directiveClass === "delete";
|
|
294
|
-
const label2 =
|
|
369
|
+
const label2 = nounText;
|
|
295
370
|
const records = host.renderRecord ? state.records : [];
|
|
296
371
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
297
372
|
"span",
|
|
@@ -309,7 +384,46 @@ function ApplyDirectiveButton({
|
|
|
309
384
|
fallback: recordFallbackName(label2, record.id),
|
|
310
385
|
context: "applied",
|
|
311
386
|
trashed
|
|
312
|
-
}) }, `${record.noun}:${record.id}`))
|
|
387
|
+
}) }, `${record.noun}:${record.id}`)),
|
|
388
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
389
|
+
"button",
|
|
390
|
+
{
|
|
391
|
+
type: "button",
|
|
392
|
+
onClick: () => void handleApply(!bad),
|
|
393
|
+
className: "inline-flex items-center gap-1 rounded px-1 py-0.5 text-muted-foreground hover:bg-accent hover:text-accent-foreground",
|
|
394
|
+
"data-apply-action": bad ? "retry" : "run-again",
|
|
395
|
+
children: [
|
|
396
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RotateCcwIcon, { className: "h-3 w-3" }),
|
|
397
|
+
bad ? "Retry" : "Run again"
|
|
398
|
+
]
|
|
399
|
+
}
|
|
400
|
+
)
|
|
401
|
+
]
|
|
402
|
+
}
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
if (state.status === "checking") {
|
|
406
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
407
|
+
"span",
|
|
408
|
+
{
|
|
409
|
+
className: "inline-flex h-6 w-6 items-center justify-center text-muted-foreground",
|
|
410
|
+
role: "status",
|
|
411
|
+
"aria-label": "Checking whether this already ran",
|
|
412
|
+
"data-apply-state": "checking",
|
|
413
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" })
|
|
414
|
+
}
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
if (state.status === "finishing") {
|
|
418
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
419
|
+
"span",
|
|
420
|
+
{
|
|
421
|
+
className: "inline-flex items-center gap-1 text-xs text-muted-foreground",
|
|
422
|
+
role: "status",
|
|
423
|
+
"data-apply-state": "finishing",
|
|
424
|
+
children: [
|
|
425
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
426
|
+
"Finishing\u2026"
|
|
313
427
|
]
|
|
314
428
|
}
|
|
315
429
|
);
|
|
@@ -548,7 +662,11 @@ function isWholeJson(content) {
|
|
|
548
662
|
return false;
|
|
549
663
|
}
|
|
550
664
|
}
|
|
551
|
-
function DirectiveRender({
|
|
665
|
+
function DirectiveRender({ conversationId, ...props }) {
|
|
666
|
+
if (conversationId === void 0) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DirectiveRenderInner, { ...props });
|
|
667
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DirectiveScopeProvider, { conversationId, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DirectiveRenderInner, { ...props }) });
|
|
668
|
+
}
|
|
669
|
+
function DirectiveRenderInner({ content, className, streaming }) {
|
|
552
670
|
const host = useDirectiveHost();
|
|
553
671
|
const directive = (0, import_content_ir6.tryDecodeDirectiveContent)(content, (message) => {
|
|
554
672
|
const line = `[kind-directives] ${message}`;
|