@ai-matrx/agents 0.31.0 โ 0.33.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 +16 -0
- package/dist/content-transfer/index.cjs.map +1 -1
- package/dist/content-transfer/index.js.map +1 -1
- package/dist/content-transfer/react/index.cjs.map +1 -1
- package/dist/content-transfer/react/index.js.map +1 -1
- package/dist/context/index.cjs.map +1 -1
- package/dist/context/index.d.cts +13 -2
- package/dist/context/index.d.ts +13 -2
- package/dist/context/index.js.map +1 -1
- package/dist/context/react/index.cjs +23 -10
- package/dist/context/react/index.cjs.map +1 -1
- package/dist/context/react/index.d.cts +14 -3
- package/dist/context/react/index.d.ts +14 -3
- package/dist/context/react/index.js +23 -10
- package/dist/context/react/index.js.map +1 -1
- package/dist/envelope/index.cjs +208 -0
- package/dist/envelope/index.cjs.map +1 -0
- package/dist/envelope/index.d.cts +314 -0
- package/dist/envelope/index.d.ts +314 -0
- package/dist/envelope/index.js +192 -0
- package/dist/envelope/index.js.map +1 -0
- package/dist/field-flags/index.cjs +63 -0
- package/dist/field-flags/index.cjs.map +1 -0
- package/dist/field-flags/index.d.cts +40 -0
- package/dist/field-flags/index.d.ts +40 -0
- package/dist/field-flags/index.js +42 -0
- package/dist/field-flags/index.js.map +1 -0
- package/dist/mandates/index.cjs +57 -2
- package/dist/mandates/index.cjs.map +1 -1
- package/dist/mandates/index.d.cts +85 -5
- package/dist/mandates/index.d.ts +85 -5
- package/dist/mandates/index.js +57 -2
- package/dist/mandates/index.js.map +1 -1
- package/dist/models/index.cjs +267 -0
- package/dist/models/index.cjs.map +1 -0
- package/dist/models/index.d.cts +118 -0
- package/dist/models/index.d.ts +118 -0
- package/dist/models/index.js +244 -0
- package/dist/models/index.js.map +1 -0
- package/mandates/snapshots/keys.0.32.0.json +653 -0
- package/mandates/snapshots/keys.0.33.0.json +653 -0
- package/package.json +35 -4
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { DirectiveClass, buildDirectiveSlug, DecodedDirective } from '@ai-matrx/content-ir';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Matrx reference taxonomy + the directive-apply receipt events.
|
|
5
|
+
*
|
|
6
|
+
* ๐จ THE SHELL NO LONGER LIVES HERE. A directive is
|
|
7
|
+
* `{"__kind":"directive_v1_<class>_<noun>","items":[โฆ]}` and its grammar,
|
|
8
|
+
* detector and decoder are `@ai-matrx/content-ir/directives` โ one shape, one
|
|
9
|
+
* discriminator, shared with every other kind. What remains in this module is
|
|
10
|
+
* what is genuinely reference-specific: the reference NOUN taxonomy and the
|
|
11
|
+
* per-noun item shapes the chips render, plus the typed stream receipts.
|
|
12
|
+
*
|
|
13
|
+
* The retired 4-key shell (`matrx_version`/`kind`/`type`/`items`) is READ-ONLY
|
|
14
|
+
* and understood in exactly one place โ `directives/legacyShell.ts`, reachable
|
|
15
|
+
* only through `decodeDirective`. Nothing here emits it and nothing here
|
|
16
|
+
* detects it. See docs/protocol/KIND_DIRECTIVES.md.
|
|
17
|
+
*/
|
|
18
|
+
type DirectiveApplyStatus = "applied" | "already_applied" | "failed";
|
|
19
|
+
type DirectiveFault = "agent" | "processor";
|
|
20
|
+
/**
|
|
21
|
+
* ๐จ EVERY receipt's identity field is `directive` and it carries the SLUG.
|
|
22
|
+
* There is deliberately no second field and no alias: the slug is the identity,
|
|
23
|
+
* and a receipt that named the thing differently from the payload it describes
|
|
24
|
+
* is the exact split the Kind Directives merge closed. Server contract:
|
|
25
|
+
* aidream `services/output_directives/events.py`.
|
|
26
|
+
*/
|
|
27
|
+
interface DirectiveApplyStarted {
|
|
28
|
+
kind: "directive_apply.started";
|
|
29
|
+
directive: string;
|
|
30
|
+
item_count: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* ๐จ THE RECEIPT SENTENCE (DD-118). Every outcome-bearing receipt carries
|
|
34
|
+
* `message`: ONE sentence, in ordinary words, authored by the SERVER
|
|
35
|
+
* (`aidream/services/output_directives/receipt_words.py`) from the apply's own
|
|
36
|
+
* result. A client may never compose it โ only the server knows whether the
|
|
37
|
+
* ledger replayed, what the write-tree touched, or what the handler called it.
|
|
38
|
+
* Before this field an applied write, a deduped re-send and an unconfirmed
|
|
39
|
+
* proposal all rendered identically, which is how a user came to see two
|
|
40
|
+
* identical cards for one project (walk K-1, 2026-09-12).
|
|
41
|
+
*/
|
|
42
|
+
interface DirectiveItemApplied {
|
|
43
|
+
kind: "directive_apply.item";
|
|
44
|
+
directive: string;
|
|
45
|
+
index: number;
|
|
46
|
+
status: Exclude<DirectiveApplyStatus, "failed">;
|
|
47
|
+
resource_kind: string;
|
|
48
|
+
resource_ids: string[];
|
|
49
|
+
summary: string;
|
|
50
|
+
/** The server's own sentence for THIS outcome. Render verbatim. */
|
|
51
|
+
message: string;
|
|
52
|
+
}
|
|
53
|
+
interface DirectiveItemFailed {
|
|
54
|
+
kind: "directive_apply.failed";
|
|
55
|
+
directive: string;
|
|
56
|
+
index: number;
|
|
57
|
+
error: string;
|
|
58
|
+
fault: DirectiveFault;
|
|
59
|
+
/** The server's own sentence: what did not happen, and why. */
|
|
60
|
+
message: string;
|
|
61
|
+
}
|
|
62
|
+
interface DirectiveApplyCompleted {
|
|
63
|
+
kind: "directive_apply.completed";
|
|
64
|
+
directive: string;
|
|
65
|
+
applied: number;
|
|
66
|
+
failed: number;
|
|
67
|
+
/** The server's own closing line for the batch. */
|
|
68
|
+
message: string;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A model-emitted directive whose resolved apply policy is `ask` โ NOT applied.
|
|
72
|
+
* The client renders an approve/decline card and, on accept, POSTs `shell`
|
|
73
|
+
* back to `/directives/confirm`. Idempotent by `proposal_id`. See the backend
|
|
74
|
+
* cascade: aidream services/output_directives/policy.py + confirm.py.
|
|
75
|
+
*/
|
|
76
|
+
interface DirectiveProposed {
|
|
77
|
+
kind: "directive_apply.proposed";
|
|
78
|
+
directive: string;
|
|
79
|
+
proposal_id: string;
|
|
80
|
+
item_count: number;
|
|
81
|
+
/** Display hints DERIVED from the slug โ never a second source of identity. */
|
|
82
|
+
directive_class: string;
|
|
83
|
+
noun: string;
|
|
84
|
+
summary: string | null;
|
|
85
|
+
/** The server's own sentence: what confirming WILL make. Render verbatim. */
|
|
86
|
+
message: string;
|
|
87
|
+
/** The two-key shell, POSTed back to /directives/confirm verbatim. */
|
|
88
|
+
shell: Record<string, unknown>;
|
|
89
|
+
}
|
|
90
|
+
/** A directive suppressed by the cascade (`off`, or `ask` with no human). */
|
|
91
|
+
interface DirectiveApplyBlocked {
|
|
92
|
+
kind: "directive_apply.blocked";
|
|
93
|
+
directive: string;
|
|
94
|
+
reason: string;
|
|
95
|
+
/** The server's own sentence: nothing was written, and why. */
|
|
96
|
+
message: string;
|
|
97
|
+
}
|
|
98
|
+
type DirectiveApplyEvent = DirectiveApplyStarted | DirectiveItemApplied | DirectiveItemFailed | DirectiveApplyCompleted | DirectiveProposed | DirectiveApplyBlocked;
|
|
99
|
+
declare function isDirectiveApplyEvent(value: unknown): value is DirectiveApplyEvent;
|
|
100
|
+
declare function isDirectiveProposed(value: unknown): value is DirectiveProposed;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* UDT + record reference taxonomy. `dataset_cell` is a legacy alias of `table_cell`.
|
|
104
|
+
* Record types (`task`, `note`, โฆ) share the backend `RecordRef { id }` item shape.
|
|
105
|
+
*/
|
|
106
|
+
declare const REFERENCE_TYPES: readonly ["structured_list", "structured_list_group", "structured_list_item", "picklist", "picklist_group", "picklist_item", "table", "table_schema", "table_column", "table_row", "table_cell", "task", "note", "project", "agent", "agent_app", "transcript", "transcript_segment", "transcript_session", "session_transcript", "workbook", "workbook_sheet", "document", "document_page", "file", "file_page", "organization", "scope_type", "scope", "context_item", "context_value", "url"];
|
|
107
|
+
type ReferenceType = (typeof REFERENCE_TYPES)[number];
|
|
108
|
+
/**
|
|
109
|
+
* Display hints โ all optional, all non-authoritative (re-fetched live on every
|
|
110
|
+
* read). Present only for instant paint + offline/LLM readability. `extra="allow"`
|
|
111
|
+
* on the backend item model is mirrored here by the open-ended index signature so
|
|
112
|
+
* UI fetch hints (limit / offset / sort) survive a round-trip.
|
|
113
|
+
*/
|
|
114
|
+
interface ReferenceItemHints {
|
|
115
|
+
label?: string;
|
|
116
|
+
table_name?: string;
|
|
117
|
+
list_name?: string;
|
|
118
|
+
column_display_name?: string;
|
|
119
|
+
description?: string;
|
|
120
|
+
[extra: string]: unknown;
|
|
121
|
+
}
|
|
122
|
+
interface PicklistRefItem extends ReferenceItemHints {
|
|
123
|
+
list_id: string;
|
|
124
|
+
}
|
|
125
|
+
interface PicklistGroupRefItem extends ReferenceItemHints {
|
|
126
|
+
list_id: string;
|
|
127
|
+
group_name: string;
|
|
128
|
+
}
|
|
129
|
+
interface PicklistItemRefItem extends ReferenceItemHints {
|
|
130
|
+
list_id: string;
|
|
131
|
+
item_id: string;
|
|
132
|
+
}
|
|
133
|
+
interface TableRefItem extends ReferenceItemHints {
|
|
134
|
+
table_id: string;
|
|
135
|
+
}
|
|
136
|
+
/** Column definitions only โ no row payload (`table_schema` / bookmark `table_schema`). */
|
|
137
|
+
interface TableSchemaRefItem extends ReferenceItemHints {
|
|
138
|
+
table_id: string;
|
|
139
|
+
}
|
|
140
|
+
interface TranscriptSegmentRefItem extends ReferenceItemHints {
|
|
141
|
+
transcript_id: string;
|
|
142
|
+
segment_index: string;
|
|
143
|
+
}
|
|
144
|
+
interface SessionTranscriptRefItem extends ReferenceItemHints {
|
|
145
|
+
session_id: string;
|
|
146
|
+
transcript_id: string;
|
|
147
|
+
}
|
|
148
|
+
interface WorkbookSheetRefItem extends ReferenceItemHints {
|
|
149
|
+
workbook_id: string;
|
|
150
|
+
sheet_id: string;
|
|
151
|
+
}
|
|
152
|
+
interface DocumentPageRefItem extends ReferenceItemHints {
|
|
153
|
+
document_id: string;
|
|
154
|
+
page_index: string;
|
|
155
|
+
}
|
|
156
|
+
interface FilePageRefItem extends ReferenceItemHints {
|
|
157
|
+
file_id: string;
|
|
158
|
+
page_number: string;
|
|
159
|
+
}
|
|
160
|
+
/** Filled cell at scope ร context_item (`ctx_context_item_values`, current row). */
|
|
161
|
+
interface ContextValueRefItem extends ReferenceItemHints {
|
|
162
|
+
scope_id: string;
|
|
163
|
+
context_item_id: string;
|
|
164
|
+
}
|
|
165
|
+
interface TableColumnRefItem extends ReferenceItemHints {
|
|
166
|
+
table_id: string;
|
|
167
|
+
column_name: string;
|
|
168
|
+
}
|
|
169
|
+
interface TableRowRefItem extends ReferenceItemHints {
|
|
170
|
+
table_id: string;
|
|
171
|
+
row_id: string;
|
|
172
|
+
}
|
|
173
|
+
interface TableCellRefItem extends ReferenceItemHints {
|
|
174
|
+
table_id: string;
|
|
175
|
+
row_id: string;
|
|
176
|
+
column_name: string;
|
|
177
|
+
}
|
|
178
|
+
/** Generic id-keyed record (`task`, `note`, `agent`, โฆ). */
|
|
179
|
+
interface RecordRefItem extends ReferenceItemHints {
|
|
180
|
+
id: string;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* An arbitrary external URL โ the one reference type with no Matrx-owned id.
|
|
184
|
+
* Covers anything not already modeled by a canonical entity type (a public
|
|
185
|
+
* web page, a third-party doc link, โฆ). Context items that allow `file` for
|
|
186
|
+
* "our" documents allow `url` alongside it for links we don't own.
|
|
187
|
+
*/
|
|
188
|
+
interface UrlRefItem extends ReferenceItemHints {
|
|
189
|
+
url: string;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* The canonical reference item โ a flat union over the reference taxonomy. Every
|
|
193
|
+
* member is identity ids + {@link ReferenceItemHints}. The open index signature
|
|
194
|
+
* keeps it assignable from a generic decoded envelope (`Record<string,unknown>`).
|
|
195
|
+
*/
|
|
196
|
+
type ReferenceItem = PicklistRefItem | PicklistGroupRefItem | PicklistItemRefItem | TableRefItem | TableSchemaRefItem | TableColumnRefItem | TableRowRefItem | TableCellRefItem | TranscriptSegmentRefItem | SessionTranscriptRefItem | WorkbookSheetRefItem | DocumentPageRefItem | FilePageRefItem | ContextValueRefItem | RecordRefItem | UrlRefItem;
|
|
197
|
+
type JsonSchema = Record<string, unknown>;
|
|
198
|
+
/**
|
|
199
|
+
* Build the strict output_schema (`{ name, schema, strict }`) for a directive
|
|
200
|
+
* shape: the two-key shell with `__kind` pinned `const` and FIRST, plus `items`
|
|
201
|
+
* as an array of the provided per-item JSON schema.
|
|
202
|
+
*
|
|
203
|
+
* `__kind` first is load-bearing, not cosmetic โ the streaming detector types a
|
|
204
|
+
* JSON document by its first key alone, and a provider that emits the keys in
|
|
205
|
+
* declaration order is what makes a directive route through the kind pipeline
|
|
206
|
+
* from its first bytes instead of arriving as raw text and swapping at the end.
|
|
207
|
+
*
|
|
208
|
+
* `additionalProperties: false` mirrors the server's `extra="forbid"`: it makes
|
|
209
|
+
* "everything lives inside items" structurally true, so a stray top-level key
|
|
210
|
+
* is a hard error and never a silent passthrough. The server owns the canonical
|
|
211
|
+
* generator (`scripts/generate_kind_directive_registry.py`); this mirrors it for
|
|
212
|
+
* FE authoring.
|
|
213
|
+
*/
|
|
214
|
+
declare function buildDirectiveOutputSchema(args: {
|
|
215
|
+
name: string;
|
|
216
|
+
directiveClass: DirectiveClass;
|
|
217
|
+
noun: string;
|
|
218
|
+
itemSchema: JsonSchema;
|
|
219
|
+
strict?: boolean;
|
|
220
|
+
}): {
|
|
221
|
+
name: string;
|
|
222
|
+
strict: boolean;
|
|
223
|
+
schema: JsonSchema;
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Matrx Envelope โ reference-fence serializer + reader (the missing authoring
|
|
228
|
+
* primitive named in the backend handoff).
|
|
229
|
+
*
|
|
230
|
+
* ONE in-content encoding for a reference: a ```matrx fence carrying the two-key
|
|
231
|
+
* Kind Directive shell `{"__kind":"directive_v1_reference_<noun>","items":[โฆ]}`.
|
|
232
|
+
* This module is the
|
|
233
|
+
* single FE home for PRODUCING that fence (authoring) and READING it back
|
|
234
|
+
* (round-trip + display) โ used by the picklist variable path today, by table /
|
|
235
|
+
* secret authoring later. Never hand-assemble a fence string elsewhere.
|
|
236
|
+
*
|
|
237
|
+
* `readPicklistSelection` normalizes a stored picklist value (fence string, or a
|
|
238
|
+
* multi-select array of fence strings + "Other" free text) into `{refs, otherText,
|
|
239
|
+
* labels}`. The fence is the ONLY encoding โ the legacy `picklist_ref` envelope and
|
|
240
|
+
* its `legacyTranslate.ts` dual-read seam were retired 2026-07-08 after every stored
|
|
241
|
+
* value was backfilled to fences.
|
|
242
|
+
*/
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Serialize a reference directive as the canonical ```matrx fence string
|
|
246
|
+
* (verbatim-persistable). Items are the FLAT canonical shape typed per the
|
|
247
|
+
* reference noun (`structured_list_item`, `table_cell`, โฆ).
|
|
248
|
+
*
|
|
249
|
+
* THE ONE PLACE THE CLIENT MINTS A FENCE. Every copy-shortcut builder in this
|
|
250
|
+
* feature funnels here, so the wire shape is decided once: the two-key Kind
|
|
251
|
+
* Directive shell with `__kind` FIRST, serialized as one minified JSON line
|
|
252
|
+
* (`{"__kind":"directive_v1_reference_<noun>","items":[โฆ]}`). The retired 4-key
|
|
253
|
+
* shell is never emitted again โ it is only ever READ, by the decoder's shim.
|
|
254
|
+
*
|
|
255
|
+
* `type` is passed as a NOUN and the slug is BUILT by the grammar, so a fence
|
|
256
|
+
* whose slug could not be parsed back is unmintable: an unknown noun throws
|
|
257
|
+
* here rather than shipping a string nothing can route.
|
|
258
|
+
*/
|
|
259
|
+
declare function buildReferenceFence(args: {
|
|
260
|
+
type: ReferenceType | string;
|
|
261
|
+
items: ReferenceItem[];
|
|
262
|
+
}): string;
|
|
263
|
+
/**
|
|
264
|
+
* The class-generic form of `buildReferenceFence` โ same fence, same minified
|
|
265
|
+
* shell, any grammar class (`reference`, `delete`, โฆ). The slug is still built
|
|
266
|
+
* by the grammar, so an unroutable class/noun pair throws instead of shipping.
|
|
267
|
+
* Side-effect classes found in content render as a button and only run on a
|
|
268
|
+
* human click (KIND_DIRECTIVES.md ยง4, THE POSITION LAW).
|
|
269
|
+
*/
|
|
270
|
+
declare function buildDirectiveFence(directiveClass: Parameters<typeof buildDirectiveSlug>[0], noun: string, items: ReferenceItem[]): string;
|
|
271
|
+
/**
|
|
272
|
+
* Convenience builder for a picklist selection: one `picklist_item` reference
|
|
273
|
+
* fence carrying N FLAT items (`{ list_id, item_id, label? }`). The model
|
|
274
|
+
* resolves each to the item's hidden description on the wire. There is no
|
|
275
|
+
* `purpose` / `slot` / `ref` / `display` โ intent is decided by position; the
|
|
276
|
+
* variable-map key the fence is bound to IS the slot.
|
|
277
|
+
*/
|
|
278
|
+
declare function buildPicklistItemFence(args: {
|
|
279
|
+
listId: string;
|
|
280
|
+
selections: Array<{
|
|
281
|
+
itemId: string;
|
|
282
|
+
label: string;
|
|
283
|
+
}>;
|
|
284
|
+
}): string;
|
|
285
|
+
/**
|
|
286
|
+
* Parse the first `reference` directive from a fence string (with or without
|
|
287
|
+
* the ``` wrapper). Returns `null` when nothing decodes โ never throws.
|
|
288
|
+
*/
|
|
289
|
+
declare function parseReferenceFence(value: string): {
|
|
290
|
+
directive: DecodedDirective;
|
|
291
|
+
items: ReferenceItem[];
|
|
292
|
+
} | null;
|
|
293
|
+
interface PicklistRefRead {
|
|
294
|
+
list_id?: string | undefined;
|
|
295
|
+
item_id: string;
|
|
296
|
+
label: string;
|
|
297
|
+
}
|
|
298
|
+
interface PicklistSelectionRead {
|
|
299
|
+
/** Ordered picklist-item refs read from the ```matrx fence(s). */
|
|
300
|
+
refs: PicklistRefRead[];
|
|
301
|
+
/** Ordered free-text ("Other") entries that are not picklist items. */
|
|
302
|
+
otherText: string[];
|
|
303
|
+
/** `refs` labels, non-empty โ convenience for display. */
|
|
304
|
+
labels: string[];
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Normalize a stored picklist value into `{ refs, otherText, labels }` โ a
|
|
308
|
+
* ```matrx reference fence string, or a multi-select array of fence strings +
|
|
309
|
+
* "Other" free-text entries. The single read-site every picklist display /
|
|
310
|
+
* round-trip caller uses.
|
|
311
|
+
*/
|
|
312
|
+
declare function readPicklistSelection(value: unknown): PicklistSelectionRead;
|
|
313
|
+
|
|
314
|
+
export { type ContextValueRefItem, type DirectiveApplyBlocked, type DirectiveApplyCompleted, type DirectiveApplyEvent, type DirectiveApplyStarted, type DirectiveApplyStatus, type DirectiveFault, type DirectiveItemApplied, type DirectiveItemFailed, type DirectiveProposed, type DocumentPageRefItem, type FilePageRefItem, type PicklistGroupRefItem, type PicklistItemRefItem, type PicklistRefItem, type PicklistRefRead, type PicklistSelectionRead, REFERENCE_TYPES, type RecordRefItem, type ReferenceItem, type ReferenceItemHints, type ReferenceType, type SessionTranscriptRefItem, type TableCellRefItem, type TableColumnRefItem, type TableRefItem, type TableRowRefItem, type TableSchemaRefItem, type TranscriptSegmentRefItem, type UrlRefItem, type WorkbookSheetRefItem, buildDirectiveFence, buildDirectiveOutputSchema, buildPicklistItemFence, buildReferenceFence, isDirectiveApplyEvent, isDirectiveProposed, parseReferenceFence, readPicklistSelection };
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
// envelope/envelope.ts
|
|
2
|
+
import {
|
|
3
|
+
KIND_KEY,
|
|
4
|
+
buildDirectiveSlug
|
|
5
|
+
} from "@ai-matrx/content-ir";
|
|
6
|
+
function isDirectiveApplyEvent(value) {
|
|
7
|
+
if (typeof value !== "object" || value === null) return false;
|
|
8
|
+
const k = value.kind;
|
|
9
|
+
return k === "directive_apply.started" || k === "directive_apply.item" || k === "directive_apply.failed" || k === "directive_apply.completed" || k === "directive_apply.proposed" || k === "directive_apply.blocked";
|
|
10
|
+
}
|
|
11
|
+
function isDirectiveProposed(value) {
|
|
12
|
+
return typeof value === "object" && value !== null && value.kind === "directive_apply.proposed";
|
|
13
|
+
}
|
|
14
|
+
var REFERENCE_TYPES = [
|
|
15
|
+
"structured_list",
|
|
16
|
+
"structured_list_group",
|
|
17
|
+
"structured_list_item",
|
|
18
|
+
// Legacy (read-only): pre-rename historical references. NEW content emits the
|
|
19
|
+
// structured_list* tokens above. See common-docs/projects/structured-lists-rename.
|
|
20
|
+
"picklist",
|
|
21
|
+
"picklist_group",
|
|
22
|
+
"picklist_item",
|
|
23
|
+
"table",
|
|
24
|
+
"table_schema",
|
|
25
|
+
"table_column",
|
|
26
|
+
"table_row",
|
|
27
|
+
"table_cell",
|
|
28
|
+
"task",
|
|
29
|
+
"note",
|
|
30
|
+
"project",
|
|
31
|
+
"agent",
|
|
32
|
+
"agent_app",
|
|
33
|
+
"transcript",
|
|
34
|
+
"transcript_segment",
|
|
35
|
+
"transcript_session",
|
|
36
|
+
"session_transcript",
|
|
37
|
+
"workbook",
|
|
38
|
+
"workbook_sheet",
|
|
39
|
+
"document",
|
|
40
|
+
"document_page",
|
|
41
|
+
"file",
|
|
42
|
+
"file_page",
|
|
43
|
+
"organization",
|
|
44
|
+
"scope_type",
|
|
45
|
+
"scope",
|
|
46
|
+
"context_item",
|
|
47
|
+
"context_value",
|
|
48
|
+
"url"
|
|
49
|
+
];
|
|
50
|
+
function buildDirectiveOutputSchema(args) {
|
|
51
|
+
const { name, directiveClass, noun, itemSchema, strict = false } = args;
|
|
52
|
+
return {
|
|
53
|
+
name,
|
|
54
|
+
strict,
|
|
55
|
+
schema: {
|
|
56
|
+
type: "object",
|
|
57
|
+
additionalProperties: false,
|
|
58
|
+
required: [KIND_KEY, "items"],
|
|
59
|
+
properties: {
|
|
60
|
+
[KIND_KEY]: {
|
|
61
|
+
type: "string",
|
|
62
|
+
const: buildDirectiveSlug(directiveClass, noun)
|
|
63
|
+
},
|
|
64
|
+
items: { type: "array", items: itemSchema }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// envelope/referenceFence.ts
|
|
71
|
+
import {
|
|
72
|
+
buildDirectiveSlug as buildDirectiveSlug2,
|
|
73
|
+
buildKindDirective,
|
|
74
|
+
tryDecodeDirective
|
|
75
|
+
} from "@ai-matrx/content-ir";
|
|
76
|
+
var FENCE_OPEN = "```matrx";
|
|
77
|
+
var FENCE_CLOSE = "```";
|
|
78
|
+
var matrxFenceRe = () => /```matrx[ \t]*\r?\n([\s\S]*?)\r?\n```/g;
|
|
79
|
+
function tryParseJson(raw) {
|
|
80
|
+
try {
|
|
81
|
+
return JSON.parse(raw);
|
|
82
|
+
} catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function buildReferenceFence(args) {
|
|
87
|
+
return buildDirectiveFence("reference", args.type, args.items);
|
|
88
|
+
}
|
|
89
|
+
function buildDirectiveFence(directiveClass, noun, items) {
|
|
90
|
+
const shell = buildKindDirective(
|
|
91
|
+
buildDirectiveSlug2(directiveClass, noun),
|
|
92
|
+
items
|
|
93
|
+
);
|
|
94
|
+
return `${FENCE_OPEN}
|
|
95
|
+
${JSON.stringify(shell)}
|
|
96
|
+
${FENCE_CLOSE}`;
|
|
97
|
+
}
|
|
98
|
+
function buildPicklistItemFence(args) {
|
|
99
|
+
const { listId, selections } = args;
|
|
100
|
+
const items = selections.map((s) => {
|
|
101
|
+
const item = {
|
|
102
|
+
list_id: listId,
|
|
103
|
+
item_id: s.itemId
|
|
104
|
+
};
|
|
105
|
+
if (s.label) item.label = s.label;
|
|
106
|
+
return item;
|
|
107
|
+
});
|
|
108
|
+
return buildReferenceFence({ type: "structured_list_item", items });
|
|
109
|
+
}
|
|
110
|
+
function extractDirectives(text) {
|
|
111
|
+
const out = [];
|
|
112
|
+
if (!text) return out;
|
|
113
|
+
if (text.includes(FENCE_OPEN)) {
|
|
114
|
+
for (const match of text.matchAll(matrxFenceRe())) {
|
|
115
|
+
const decoded2 = tryDecodeDirective(tryParseJson(match[1] ?? ""));
|
|
116
|
+
if (decoded2) out.push(decoded2);
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
const decoded = tryDecodeDirective(tryParseJson(text.trim()));
|
|
121
|
+
if (decoded) out.push(decoded);
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
function parseReferenceFence(value) {
|
|
125
|
+
const directive = extractDirectives(value).find(
|
|
126
|
+
(d) => d.directiveClass === "reference"
|
|
127
|
+
);
|
|
128
|
+
if (!directive) return null;
|
|
129
|
+
return { directive, items: directive.items };
|
|
130
|
+
}
|
|
131
|
+
function refsFromItems(items, into) {
|
|
132
|
+
if (!Array.isArray(items)) return;
|
|
133
|
+
for (const raw of items) {
|
|
134
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) continue;
|
|
135
|
+
const o = raw;
|
|
136
|
+
const itemId = typeof o.item_id === "string" ? o.item_id : void 0;
|
|
137
|
+
if (!itemId) continue;
|
|
138
|
+
const listId = typeof o.list_id === "string" ? o.list_id : void 0;
|
|
139
|
+
const label = typeof o.label === "string" ? o.label : "";
|
|
140
|
+
into.push({ list_id: listId, item_id: itemId, label });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function finalize(refs, otherText) {
|
|
144
|
+
return { refs, otherText, labels: refs.map((r) => r.label).filter(Boolean) };
|
|
145
|
+
}
|
|
146
|
+
function readPicklistSelection(value) {
|
|
147
|
+
const refs = [];
|
|
148
|
+
const otherText = [];
|
|
149
|
+
if (Array.isArray(value)) {
|
|
150
|
+
for (const entry of value) {
|
|
151
|
+
if (typeof entry === "string" && entry.trim()) {
|
|
152
|
+
const sub = readPicklistSelection(entry);
|
|
153
|
+
if (sub.refs.length) {
|
|
154
|
+
refs.push(...sub.refs);
|
|
155
|
+
otherText.push(...sub.otherText);
|
|
156
|
+
} else {
|
|
157
|
+
otherText.push(entry.trim());
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return finalize(refs, otherText);
|
|
162
|
+
}
|
|
163
|
+
if (typeof value === "string" && value.trim()) {
|
|
164
|
+
const directives = extractDirectives(value);
|
|
165
|
+
for (const d of directives) {
|
|
166
|
+
if (d.directiveClass === "reference") refsFromItems(d.items, refs);
|
|
167
|
+
}
|
|
168
|
+
if (directives.length === 0) {
|
|
169
|
+
otherText.push(value.trim());
|
|
170
|
+
} else {
|
|
171
|
+
const residual = value.replace(matrxFenceRe(), "").trim();
|
|
172
|
+
for (const line of residual.split("\n")) {
|
|
173
|
+
const t = line.trim();
|
|
174
|
+
if (t) otherText.push(t);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return finalize(refs, otherText);
|
|
178
|
+
}
|
|
179
|
+
return finalize(refs, otherText);
|
|
180
|
+
}
|
|
181
|
+
export {
|
|
182
|
+
REFERENCE_TYPES,
|
|
183
|
+
buildDirectiveFence,
|
|
184
|
+
buildDirectiveOutputSchema,
|
|
185
|
+
buildPicklistItemFence,
|
|
186
|
+
buildReferenceFence,
|
|
187
|
+
isDirectiveApplyEvent,
|
|
188
|
+
isDirectiveProposed,
|
|
189
|
+
parseReferenceFence,
|
|
190
|
+
readPicklistSelection
|
|
191
|
+
};
|
|
192
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../envelope/envelope.ts","../../envelope/referenceFence.ts"],"sourcesContent":["/**\n * Matrx reference taxonomy + the directive-apply receipt events.\n *\n * ๐จ THE SHELL NO LONGER LIVES HERE. A directive is\n * `{\"__kind\":\"directive_v1_<class>_<noun>\",\"items\":[โฆ]}` and its grammar,\n * detector and decoder are `@ai-matrx/content-ir/directives` โ one shape, one\n * discriminator, shared with every other kind. What remains in this module is\n * what is genuinely reference-specific: the reference NOUN taxonomy and the\n * per-noun item shapes the chips render, plus the typed stream receipts.\n *\n * The retired 4-key shell (`matrx_version`/`kind`/`type`/`items`) is READ-ONLY\n * and understood in exactly one place โ `directives/legacyShell.ts`, reachable\n * only through `decodeDirective`. Nothing here emits it and nothing here\n * detects it. See docs/protocol/KIND_DIRECTIVES.md.\n */\n\n// โโ Output-directive receipt events (stream `data` events) โโโโโโโโโโโโโโโโโโโ\n\nexport type DirectiveApplyStatus = \"applied\" | \"already_applied\" | \"failed\";\nexport type DirectiveFault = \"agent\" | \"processor\";\n\n/**\n * ๐จ EVERY receipt's identity field is `directive` and it carries the SLUG.\n * There is deliberately no second field and no alias: the slug is the identity,\n * and a receipt that named the thing differently from the payload it describes\n * is the exact split the Kind Directives merge closed. Server contract:\n * aidream `services/output_directives/events.py`.\n */\nexport interface DirectiveApplyStarted {\n kind: \"directive_apply.started\";\n directive: string;\n item_count: number;\n}\n/**\n * ๐จ THE RECEIPT SENTENCE (DD-118). Every outcome-bearing receipt carries\n * `message`: ONE sentence, in ordinary words, authored by the SERVER\n * (`aidream/services/output_directives/receipt_words.py`) from the apply's own\n * result. A client may never compose it โ only the server knows whether the\n * ledger replayed, what the write-tree touched, or what the handler called it.\n * Before this field an applied write, a deduped re-send and an unconfirmed\n * proposal all rendered identically, which is how a user came to see two\n * identical cards for one project (walk K-1, 2026-09-12).\n */\nexport interface DirectiveItemApplied {\n kind: \"directive_apply.item\";\n directive: string;\n index: number;\n status: Exclude<DirectiveApplyStatus, \"failed\">;\n resource_kind: string;\n resource_ids: string[];\n summary: string;\n /** The server's own sentence for THIS outcome. Render verbatim. */\n message: string;\n}\nexport interface DirectiveItemFailed {\n kind: \"directive_apply.failed\";\n directive: string;\n index: number;\n error: string;\n fault: DirectiveFault;\n /** The server's own sentence: what did not happen, and why. */\n message: string;\n}\nexport interface DirectiveApplyCompleted {\n kind: \"directive_apply.completed\";\n directive: string;\n applied: number;\n failed: number;\n /** The server's own closing line for the batch. */\n message: string;\n}\n/**\n * A model-emitted directive whose resolved apply policy is `ask` โ NOT applied.\n * The client renders an approve/decline card and, on accept, POSTs `shell`\n * back to `/directives/confirm`. Idempotent by `proposal_id`. See the backend\n * cascade: aidream services/output_directives/policy.py + confirm.py.\n */\nexport interface DirectiveProposed {\n kind: \"directive_apply.proposed\";\n directive: string;\n proposal_id: string;\n item_count: number;\n /** Display hints DERIVED from the slug โ never a second source of identity. */\n directive_class: string;\n noun: string;\n summary: string | null;\n /** The server's own sentence: what confirming WILL make. Render verbatim. */\n message: string;\n /** The two-key shell, POSTed back to /directives/confirm verbatim. */\n shell: Record<string, unknown>;\n}\n/** A directive suppressed by the cascade (`off`, or `ask` with no human). */\nexport interface DirectiveApplyBlocked {\n kind: \"directive_apply.blocked\";\n directive: string;\n reason: string;\n /** The server's own sentence: nothing was written, and why. */\n message: string;\n}\nexport type DirectiveApplyEvent =\n | DirectiveApplyStarted\n | DirectiveItemApplied\n | DirectiveItemFailed\n | DirectiveApplyCompleted\n | DirectiveProposed\n | DirectiveApplyBlocked;\n\nexport function isDirectiveApplyEvent(\n value: unknown,\n): value is DirectiveApplyEvent {\n if (typeof value !== \"object\" || value === null) return false;\n const k = (value as { kind?: unknown }).kind;\n return (\n k === \"directive_apply.started\" ||\n k === \"directive_apply.item\" ||\n k === \"directive_apply.failed\" ||\n k === \"directive_apply.completed\" ||\n k === \"directive_apply.proposed\" ||\n k === \"directive_apply.blocked\"\n );\n}\n\nexport function isDirectiveProposed(\n value: unknown,\n): value is DirectiveProposed {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { kind?: unknown }).kind === \"directive_apply.proposed\"\n );\n}\n\nimport {\n type DirectiveClass,\n KIND_KEY,\n buildDirectiveSlug,\n} from \"@ai-matrx/content-ir\";\n\n// โโ Reference item (in a ```matrx fence) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n//\n// The CANONICAL reference item is PURE FLAT IDENTITY: the typed ids that name\n// the thing + optional, non-authoritative display hints. NOTHING ELSE. There is\n// no `purpose` / `slot` / `ref` / `display` nesting โ intent is decided by the\n// item's POSITION (in-content fence = resolve in place; variable binding = the\n// map key is the slot), never a field on the item. (See\n// docs/protocol/MATRX_REFERENCES.md โ \"The item shape\" + \"Where purpose went\".)\n\n// (The legacy `purpose` intent field and the `legacyTranslate.ts` translation layer were\n// deleted 2026-07-08 โ no stored value carries the old nested/`picklist_ref` shapes anymore;\n// resolution intent is decided by POSITION only.)\n\n/**\n * UDT + record reference taxonomy. `dataset_cell` is a legacy alias of `table_cell`.\n * Record types (`task`, `note`, โฆ) share the backend `RecordRef { id }` item shape.\n */\nexport const REFERENCE_TYPES = [\n \"structured_list\",\n \"structured_list_group\",\n \"structured_list_item\",\n // Legacy (read-only): pre-rename historical references. NEW content emits the\n // structured_list* tokens above. See common-docs/projects/structured-lists-rename.\n \"picklist\",\n \"picklist_group\",\n \"picklist_item\",\n \"table\",\n \"table_schema\",\n \"table_column\",\n \"table_row\",\n \"table_cell\",\n \"task\",\n \"note\",\n \"project\",\n \"agent\",\n \"agent_app\",\n \"transcript\",\n \"transcript_segment\",\n \"transcript_session\",\n \"session_transcript\",\n \"workbook\",\n \"workbook_sheet\",\n \"document\",\n \"document_page\",\n \"file\",\n \"file_page\",\n \"organization\",\n \"scope_type\",\n \"scope\",\n \"context_item\",\n \"context_value\",\n \"url\",\n] as const;\n\nexport type ReferenceType = (typeof REFERENCE_TYPES)[number];\n\n/**\n * Display hints โ all optional, all non-authoritative (re-fetched live on every\n * read). Present only for instant paint + offline/LLM readability. `extra=\"allow\"`\n * on the backend item model is mirrored here by the open-ended index signature so\n * UI fetch hints (limit / offset / sort) survive a round-trip.\n */\nexport interface ReferenceItemHints {\n label?: string;\n table_name?: string;\n list_name?: string;\n column_display_name?: string;\n description?: string;\n [extra: string]: unknown;\n}\n\nexport interface PicklistRefItem extends ReferenceItemHints {\n list_id: string;\n}\nexport interface PicklistGroupRefItem extends ReferenceItemHints {\n list_id: string;\n group_name: string;\n}\nexport interface PicklistItemRefItem extends ReferenceItemHints {\n list_id: string;\n item_id: string;\n}\nexport interface TableRefItem extends ReferenceItemHints {\n table_id: string;\n}\n/** Column definitions only โ no row payload (`table_schema` / bookmark `table_schema`). */\nexport interface TableSchemaRefItem extends ReferenceItemHints {\n table_id: string;\n}\nexport interface TranscriptSegmentRefItem extends ReferenceItemHints {\n transcript_id: string;\n segment_index: string;\n}\nexport interface SessionTranscriptRefItem extends ReferenceItemHints {\n session_id: string;\n transcript_id: string;\n}\nexport interface WorkbookSheetRefItem extends ReferenceItemHints {\n workbook_id: string;\n sheet_id: string;\n}\nexport interface DocumentPageRefItem extends ReferenceItemHints {\n document_id: string;\n page_index: string;\n}\nexport interface FilePageRefItem extends ReferenceItemHints {\n file_id: string;\n page_number: string;\n}\n/** Filled cell at scope ร context_item (`ctx_context_item_values`, current row). */\nexport interface ContextValueRefItem extends ReferenceItemHints {\n scope_id: string;\n context_item_id: string;\n}\nexport interface TableColumnRefItem extends ReferenceItemHints {\n table_id: string;\n column_name: string;\n}\nexport interface TableRowRefItem extends ReferenceItemHints {\n table_id: string;\n row_id: string;\n}\nexport interface TableCellRefItem extends ReferenceItemHints {\n table_id: string;\n row_id: string;\n column_name: string;\n}\n\n/** Generic id-keyed record (`task`, `note`, `agent`, โฆ). */\nexport interface RecordRefItem extends ReferenceItemHints {\n id: string;\n}\n/**\n * An arbitrary external URL โ the one reference type with no Matrx-owned id.\n * Covers anything not already modeled by a canonical entity type (a public\n * web page, a third-party doc link, โฆ). Context items that allow `file` for\n * \"our\" documents allow `url` alongside it for links we don't own.\n */\nexport interface UrlRefItem extends ReferenceItemHints {\n url: string;\n}\n\n/**\n * The canonical reference item โ a flat union over the reference taxonomy. Every\n * member is identity ids + {@link ReferenceItemHints}. The open index signature\n * keeps it assignable from a generic decoded envelope (`Record<string,unknown>`).\n */\nexport type ReferenceItem =\n | PicklistRefItem\n | PicklistGroupRefItem\n | PicklistItemRefItem\n | TableRefItem\n | TableSchemaRefItem\n | TableColumnRefItem\n | TableRowRefItem\n | TableCellRefItem\n | TranscriptSegmentRefItem\n | SessionTranscriptRefItem\n | WorkbookSheetRefItem\n | DocumentPageRefItem\n | FilePageRefItem\n | ContextValueRefItem\n | RecordRefItem\n | UrlRefItem;\n\n// โโ Output-schema builder (generic; mirrors aidream's schema_gen) โโโโโโโโโโโโโ\n\ntype JsonSchema = Record<string, unknown>;\n\n/**\n * Build the strict output_schema (`{ name, schema, strict }`) for a directive\n * shape: the two-key shell with `__kind` pinned `const` and FIRST, plus `items`\n * as an array of the provided per-item JSON schema.\n *\n * `__kind` first is load-bearing, not cosmetic โ the streaming detector types a\n * JSON document by its first key alone, and a provider that emits the keys in\n * declaration order is what makes a directive route through the kind pipeline\n * from its first bytes instead of arriving as raw text and swapping at the end.\n *\n * `additionalProperties: false` mirrors the server's `extra=\"forbid\"`: it makes\n * \"everything lives inside items\" structurally true, so a stray top-level key\n * is a hard error and never a silent passthrough. The server owns the canonical\n * generator (`scripts/generate_kind_directive_registry.py`); this mirrors it for\n * FE authoring.\n */\nexport function buildDirectiveOutputSchema(args: {\n name: string;\n directiveClass: DirectiveClass;\n noun: string;\n itemSchema: JsonSchema;\n strict?: boolean;\n}): { name: string; strict: boolean; schema: JsonSchema } {\n const { name, directiveClass, noun, itemSchema, strict = false } = args;\n return {\n name,\n strict,\n schema: {\n type: \"object\",\n additionalProperties: false,\n required: [KIND_KEY, \"items\"],\n properties: {\n [KIND_KEY]: {\n type: \"string\",\n const: buildDirectiveSlug(directiveClass, noun),\n },\n items: { type: \"array\", items: itemSchema },\n },\n },\n };\n}\n","/**\n * Matrx Envelope โ reference-fence serializer + reader (the missing authoring\n * primitive named in the backend handoff).\n *\n * ONE in-content encoding for a reference: a ```matrx fence carrying the two-key\n * Kind Directive shell `{\"__kind\":\"directive_v1_reference_<noun>\",\"items\":[โฆ]}`.\n * This module is the\n * single FE home for PRODUCING that fence (authoring) and READING it back\n * (round-trip + display) โ used by the picklist variable path today, by table /\n * secret authoring later. Never hand-assemble a fence string elsewhere.\n *\n * `readPicklistSelection` normalizes a stored picklist value (fence string, or a\n * multi-select array of fence strings + \"Other\" free text) into `{refs, otherText,\n * labels}`. The fence is the ONLY encoding โ the legacy `picklist_ref` envelope and\n * its `legacyTranslate.ts` dual-read seam were retired 2026-07-08 after every stored\n * value was backfilled to fences.\n */\n\nimport {\n type DecodedDirective,\n buildDirectiveSlug,\n buildKindDirective,\n tryDecodeDirective,\n} from \"@ai-matrx/content-ir\";\nimport type {\n ReferenceItem,\n ReferenceType,\n} from \"./envelope\";\n\nconst FENCE_OPEN = \"```matrx\";\nconst FENCE_CLOSE = \"```\";\n\n/**\n * Fresh global regex each call โ a shared global regex carries `lastIndex`\n * state that would corrupt interleaved `matchAll` / `replace` calls.\n */\nconst matrxFenceRe = (): RegExp => /```matrx[ \\t]*\\r?\\n([\\s\\S]*?)\\r?\\n```/g;\n\nfunction tryParseJson(raw: string): unknown {\n try {\n return JSON.parse(raw);\n } catch {\n return null;\n }\n}\n\n// โโ Build (authoring) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n/**\n * Serialize a reference directive as the canonical ```matrx fence string\n * (verbatim-persistable). Items are the FLAT canonical shape typed per the\n * reference noun (`structured_list_item`, `table_cell`, โฆ).\n *\n * THE ONE PLACE THE CLIENT MINTS A FENCE. Every copy-shortcut builder in this\n * feature funnels here, so the wire shape is decided once: the two-key Kind\n * Directive shell with `__kind` FIRST, serialized as one minified JSON line\n * (`{\"__kind\":\"directive_v1_reference_<noun>\",\"items\":[โฆ]}`). The retired 4-key\n * shell is never emitted again โ it is only ever READ, by the decoder's shim.\n *\n * `type` is passed as a NOUN and the slug is BUILT by the grammar, so a fence\n * whose slug could not be parsed back is unmintable: an unknown noun throws\n * here rather than shipping a string nothing can route.\n */\nexport function buildReferenceFence(args: {\n type: ReferenceType | string;\n items: ReferenceItem[];\n}): string {\n return buildDirectiveFence(\"reference\", args.type, args.items);\n}\n\n/**\n * The class-generic form of `buildReferenceFence` โ same fence, same minified\n * shell, any grammar class (`reference`, `delete`, โฆ). The slug is still built\n * by the grammar, so an unroutable class/noun pair throws instead of shipping.\n * Side-effect classes found in content render as a button and only run on a\n * human click (KIND_DIRECTIVES.md ยง4, THE POSITION LAW).\n */\nexport function buildDirectiveFence(\n directiveClass: Parameters<typeof buildDirectiveSlug>[0],\n noun: string,\n items: ReferenceItem[],\n): string {\n const shell = buildKindDirective(\n buildDirectiveSlug(directiveClass, noun),\n items,\n );\n return `${FENCE_OPEN}\\n${JSON.stringify(shell)}\\n${FENCE_CLOSE}`;\n}\n\n/**\n * Convenience builder for a picklist selection: one `picklist_item` reference\n * fence carrying N FLAT items (`{ list_id, item_id, label? }`). The model\n * resolves each to the item's hidden description on the wire. There is no\n * `purpose` / `slot` / `ref` / `display` โ intent is decided by position; the\n * variable-map key the fence is bound to IS the slot.\n */\nexport function buildPicklistItemFence(args: {\n listId: string;\n selections: Array<{ itemId: string; label: string }>;\n}): string {\n const { listId, selections } = args;\n const items: ReferenceItem[] = selections.map((s) => {\n const item: { list_id: string; item_id: string; label?: string } = {\n list_id: listId,\n item_id: s.itemId,\n };\n if (s.label) item.label = s.label;\n return item as ReferenceItem;\n });\n return buildReferenceFence({ type: \"structured_list_item\", items });\n}\n\n// โโ Parse (round-trip) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\n/**\n * Every Kind Directive embedded in a host string (each ```matrx fence that\n * decodes). Stored 4-key fences decode here too โ that is the decoder's shim\n * doing its one job โ so a value saved in 2025 reads back identically.\n */\nfunction extractDirectives(text: string): DecodedDirective[] {\n const out: DecodedDirective[] = [];\n if (!text) return out;\n\n if (text.includes(FENCE_OPEN)) {\n for (const match of text.matchAll(matrxFenceRe())) {\n const decoded = tryDecodeDirective(tryParseJson(match[1] ?? \"\"));\n if (decoded) out.push(decoded);\n }\n return out;\n }\n\n // Tolerant: a bare shell JSON with no fence wrapper.\n const decoded = tryDecodeDirective(tryParseJson(text.trim()));\n if (decoded) out.push(decoded);\n return out;\n}\n\n/**\n * Parse the first `reference` directive from a fence string (with or without\n * the ``` wrapper). Returns `null` when nothing decodes โ never throws.\n */\nexport function parseReferenceFence(\n value: string,\n): { directive: DecodedDirective; items: ReferenceItem[] } | null {\n const directive = extractDirectives(value).find(\n (d) => d.directiveClass === \"reference\",\n );\n if (!directive) return null;\n return { directive, items: directive.items as unknown as ReferenceItem[] };\n}\n\n// โโ Dual-read (migration bridge) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n\nexport interface PicklistRefRead {\n list_id?: string | undefined;\n item_id: string;\n label: string;\n}\n\nexport interface PicklistSelectionRead {\n /** Ordered picklist-item refs read from the ```matrx fence(s). */\n refs: PicklistRefRead[];\n /** Ordered free-text (\"Other\") entries that are not picklist items. */\n otherText: string[];\n /** `refs` labels, non-empty โ convenience for display. */\n labels: string[];\n}\n\nfunction refsFromItems(items: unknown, into: PicklistRefRead[]): void {\n if (!Array.isArray(items)) return;\n for (const raw of items) {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) continue;\n const o = raw as Record<string, unknown>;\n const itemId = typeof o.item_id === \"string\" ? o.item_id : undefined;\n if (!itemId) continue;\n const listId = typeof o.list_id === \"string\" ? o.list_id : undefined;\n const label = typeof o.label === \"string\" ? o.label : \"\";\n into.push({ list_id: listId, item_id: itemId, label });\n }\n}\n\nfunction finalize(\n refs: PicklistRefRead[],\n otherText: string[],\n): PicklistSelectionRead {\n return { refs, otherText, labels: refs.map((r) => r.label).filter(Boolean) };\n}\n\n/**\n * Normalize a stored picklist value into `{ refs, otherText, labels }` โ a\n * ```matrx reference fence string, or a multi-select array of fence strings +\n * \"Other\" free-text entries. The single read-site every picklist display /\n * round-trip caller uses.\n */\nexport function readPicklistSelection(value: unknown): PicklistSelectionRead {\n const refs: PicklistRefRead[] = [];\n const otherText: string[] = [];\n\n // Multi array: fence-string elements + \"Other\" free-text strings.\n if (Array.isArray(value)) {\n for (const entry of value) {\n if (typeof entry === \"string\" && entry.trim()) {\n const sub = readPicklistSelection(entry);\n if (sub.refs.length) {\n refs.push(...sub.refs);\n otherText.push(...sub.otherText);\n } else {\n otherText.push(entry.trim());\n }\n }\n }\n return finalize(refs, otherText);\n }\n\n // New string form: zero+ ```matrx fences with residual \"Other\" lines, OR pure\n // free text with no fence.\n if (typeof value === \"string\" && value.trim()) {\n const directives = extractDirectives(value);\n for (const d of directives) {\n if (d.directiveClass === \"reference\") refsFromItems(d.items, refs);\n }\n if (directives.length === 0) {\n otherText.push(value.trim()); // pure free text โ preserve as one entry\n } else {\n const residual = value.replace(matrxFenceRe(), \"\").trim();\n for (const line of residual.split(\"\\n\")) {\n const t = line.trim();\n if (t) otherText.push(t);\n }\n }\n return finalize(refs, otherText);\n }\n\n return finalize(refs, otherText);\n}\n"],"mappings":"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","names":["buildDirectiveSlug","decoded"]}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// field-flags/index.ts
|
|
21
|
+
var field_flags_exports = {};
|
|
22
|
+
__export(field_flags_exports, {
|
|
23
|
+
addField: () => addField,
|
|
24
|
+
assignField: () => assignField,
|
|
25
|
+
createFieldFlags: () => createFieldFlags,
|
|
26
|
+
fieldFlagsKeys: () => fieldFlagsKeys,
|
|
27
|
+
fieldFlagsSize: () => fieldFlagsSize,
|
|
28
|
+
forEachField: () => forEachField,
|
|
29
|
+
hasField: () => hasField,
|
|
30
|
+
readField: () => readField,
|
|
31
|
+
removeField: () => removeField
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(field_flags_exports);
|
|
34
|
+
function createFieldFlags() {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
function hasField(flags, field) {
|
|
38
|
+
return flags[field] === true;
|
|
39
|
+
}
|
|
40
|
+
function addField(flags, field) {
|
|
41
|
+
flags[field] = true;
|
|
42
|
+
}
|
|
43
|
+
function removeField(flags, field) {
|
|
44
|
+
delete flags[field];
|
|
45
|
+
}
|
|
46
|
+
function fieldFlagsSize(flags) {
|
|
47
|
+
return Object.keys(flags).length;
|
|
48
|
+
}
|
|
49
|
+
function fieldFlagsKeys(flags) {
|
|
50
|
+
return Object.keys(flags);
|
|
51
|
+
}
|
|
52
|
+
function forEachField(flags, fn) {
|
|
53
|
+
for (const key of Object.keys(flags)) {
|
|
54
|
+
fn(key);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function assignField(record, field, value) {
|
|
58
|
+
record[field] = value;
|
|
59
|
+
}
|
|
60
|
+
function readField(record, field) {
|
|
61
|
+
return record[field];
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../field-flags/index.ts"],"sourcesContent":["/**\n * FieldFlags โ serializable replacement for `Set<keyof T>` used in per-record\n * dirty/loaded tracking across the agent-definition and agent-shortcuts slices.\n *\n * `Set` is not JSON-serializable, which blocks:\n * - Redux state persistence (localStorage, AsyncStorage)\n * - Extracting the agent Redux stack into a framework-agnostic shared package\n * - DevTools time-travel (Sets render as opaque placeholders)\n *\n * Replacement shape: `Partial<Record<K, true>>`. The presence of a key means\n * the flag is set; `true` is the canonical marker. `delete record[key]` clears.\n *\n * Use the helpers below instead of raw object access so the intent at each\n * callsite remains readable (`hasField(flags, \"messages\")` vs `!!flags.messages`).\n */\n\nexport type FieldFlags<K extends string> = Partial<Record<K, true>>;\n\nexport function createFieldFlags<K extends string>(): FieldFlags<K> {\n return {};\n}\n\nexport function hasField<K extends string>(flags: FieldFlags<K>, field: K): boolean {\n return flags[field] === true;\n}\n\nexport function addField<K extends string>(flags: FieldFlags<K>, field: K): void {\n flags[field] = true;\n}\n\nexport function removeField<K extends string>(flags: FieldFlags<K>, field: K): void {\n delete flags[field];\n}\n\nexport function fieldFlagsSize<K extends string>(flags: FieldFlags<K>): number {\n return Object.keys(flags).length;\n}\n\nexport function fieldFlagsKeys<K extends string>(flags: FieldFlags<K>): K[] {\n return Object.keys(flags) as K[];\n}\n\nexport function forEachField<K extends string>(\n flags: FieldFlags<K>,\n fn: (field: K) => void,\n): void {\n for (const key of Object.keys(flags) as K[]) {\n fn(key);\n }\n}\n\n/**\n * Assign a single dynamically-keyed field on a record without an `as any`\n * escape hatch. The generic binds `K extends keyof T` and `value: T[K]`\n * together at the call site, so the write stays type-sound โ TypeScript\n * just can't prove `record[field] = value` is safe at a *computed* index\n * without this indirection (a known inference gap for mapped-object writes,\n * not an unsoundness).\n */\nexport function assignField<T, K extends keyof T>(\n record: T,\n field: K,\n value: T[K],\n): void {\n record[field] = value;\n}\n\n/**\n * Read a single dynamically-keyed field off a record without an\n * `as unknown as Record<string, unknown>` whole-row cast. Same generic\n * bridging as `assignField`, for the read direction.\n */\nexport function readField<T, K extends keyof T>(record: T, field: K): T[K] {\n return record[field];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBO,SAAS,mBAAoD;AAClE,SAAO,CAAC;AACV;AAEO,SAAS,SAA2B,OAAsB,OAAmB;AAClF,SAAO,MAAM,KAAK,MAAM;AAC1B;AAEO,SAAS,SAA2B,OAAsB,OAAgB;AAC/E,QAAM,KAAK,IAAI;AACjB;AAEO,SAAS,YAA8B,OAAsB,OAAgB;AAClF,SAAO,MAAM,KAAK;AACpB;AAEO,SAAS,eAAiC,OAA8B;AAC7E,SAAO,OAAO,KAAK,KAAK,EAAE;AAC5B;AAEO,SAAS,eAAiC,OAA2B;AAC1E,SAAO,OAAO,KAAK,KAAK;AAC1B;AAEO,SAAS,aACd,OACA,IACM;AACN,aAAW,OAAO,OAAO,KAAK,KAAK,GAAU;AAC3C,OAAG,GAAG;AAAA,EACR;AACF;AAUO,SAAS,YACd,QACA,OACA,OACM;AACN,SAAO,KAAK,IAAI;AAClB;AAOO,SAAS,UAAgC,QAAW,OAAgB;AACzE,SAAO,OAAO,KAAK;AACrB;","names":[]}
|