@femtomc/mu-core 26.2.107 → 26.2.109
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/README.md +2 -15
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/ui.d.ts +28 -11
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +207 -4
- package/package.json +32 -32
- package/dist/hud.d.ts +0 -402
- package/dist/hud.d.ts.map +0 -1
- package/dist/hud.js +0 -488
- package/dist/hud_runtime.d.ts +0 -36
- package/dist/hud_runtime.d.ts.map +0 -1
- package/dist/hud_runtime.js +0 -105
package/README.md
CHANGED
|
@@ -34,28 +34,15 @@ await runContext({ runId: newRunId() }, async () => {
|
|
|
34
34
|
console.log(await jsonl.read());
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
## HUD contract helpers
|
|
38
|
-
|
|
39
|
-
`@femtomc/mu-core` exports a versioned HUD contract, deterministic JSON helper, and shared runtime loop:
|
|
40
|
-
|
|
41
|
-
- `HudDocSchema`, `HUD_CONTRACT_VERSION`
|
|
42
|
-
- `parseHudDoc(...)`, `normalizeHudDocs(...)`
|
|
43
|
-
- `resolveHudStylePresetName(...)`, `applyHudStylePreset(...)`, `hudStylePresetWarnings(...)`
|
|
44
|
-
- `serializeHudDocTextFallback(...)`, `serializeHudDocsTextFallback(...)`
|
|
45
|
-
- `stableSerializeJson(...)`
|
|
46
|
-
- `HudRuntime` + `HudProvider` for provider registration, reducer updates, ordered effect execution, and HUD snapshot emission
|
|
47
|
-
|
|
48
|
-
`HudDoc` also supports optional presentation hints (`title_style`, `snapshot_style`, chip/item/section/action style objects) and metadata style presets (`metadata.style_preset` currently `planning|subagents`) so renderers can opt into richer emphasis while preserving deterministic plain-text fallbacks.
|
|
49
|
-
|
|
50
|
-
These are runtime-agnostic primitives intended for shared HUD capture/render pipelines.
|
|
51
|
-
|
|
52
37
|
## UI contract helpers
|
|
53
38
|
|
|
54
39
|
Interactive UI documents are modeled as first-class, versioned contracts that describe renderable components, actions, and revisions so any rendering surface can stay in sync with agents. `@femtomc/mu-core` exposes the following helpers:
|
|
55
40
|
|
|
56
41
|
- `UI_CONTRACT_VERSION`, `UiDocSchema`, `UiRevisionSchema`, `UiComponentSchema`, and `UiActionSchema` for validating document payloads.
|
|
57
42
|
- `parseUiDoc(...)`, `normalizeUiDocs(...)`, and `uiDocRevisionConflict(...)` for deterministic selection, conflict detection, and safe merging of candidate documents.
|
|
43
|
+
- `resolveUiStatusProfileName(...)` and `uiStatusProfileWarnings(...)` for advisory validation of profile-scoped status docs (`planning`, `subagents`, `control-flow`, `model-routing`) carried in `metadata.profile`.
|
|
58
44
|
- `UiEventSchema` + `parseUiEvent(...)` for structured event payloads emitted by frontends (every event includes `ui_id`, `action_id`, the originating `revision`, optional `callback_token`, `payload`, and `created_at_ms`).
|
|
45
|
+
- `stableSerializeJson(...)` for deterministic metadata serialization and revision tie-breaking.
|
|
59
46
|
|
|
60
47
|
### Field limits
|
|
61
48
|
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/ui.d.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
export declare const UiToneSchema: z.ZodEnum<{
|
|
3
|
+
error: "error";
|
|
4
|
+
success: "success";
|
|
5
|
+
info: "info";
|
|
6
|
+
warning: "warning";
|
|
7
|
+
muted: "muted";
|
|
8
|
+
accent: "accent";
|
|
9
|
+
dim: "dim";
|
|
10
|
+
}>;
|
|
11
|
+
export type UiTone = z.infer<typeof UiToneSchema>;
|
|
2
12
|
export declare const UI_CONTRACT_VERSION: 1;
|
|
3
13
|
export declare const UiListItemSchema: z.ZodObject<{
|
|
4
14
|
id: z.ZodString;
|
|
@@ -6,8 +16,8 @@ export declare const UiListItemSchema: z.ZodObject<{
|
|
|
6
16
|
detail: z.ZodOptional<z.ZodString>;
|
|
7
17
|
tone: z.ZodOptional<z.ZodEnum<{
|
|
8
18
|
error: "error";
|
|
9
|
-
info: "info";
|
|
10
19
|
success: "success";
|
|
20
|
+
info: "info";
|
|
11
21
|
warning: "warning";
|
|
12
22
|
muted: "muted";
|
|
13
23
|
accent: "accent";
|
|
@@ -20,8 +30,8 @@ export declare const UiKeyValueRowSchema: z.ZodObject<{
|
|
|
20
30
|
value: z.ZodString;
|
|
21
31
|
tone: z.ZodOptional<z.ZodEnum<{
|
|
22
32
|
error: "error";
|
|
23
|
-
info: "info";
|
|
24
33
|
success: "success";
|
|
34
|
+
info: "info";
|
|
25
35
|
warning: "warning";
|
|
26
36
|
muted: "muted";
|
|
27
37
|
accent: "accent";
|
|
@@ -35,8 +45,8 @@ export declare const UiComponentTextSchema: z.ZodObject<{
|
|
|
35
45
|
text: z.ZodString;
|
|
36
46
|
tone: z.ZodOptional<z.ZodEnum<{
|
|
37
47
|
error: "error";
|
|
38
|
-
info: "info";
|
|
39
48
|
success: "success";
|
|
49
|
+
info: "info";
|
|
40
50
|
warning: "warning";
|
|
41
51
|
muted: "muted";
|
|
42
52
|
accent: "accent";
|
|
@@ -55,8 +65,8 @@ export declare const UiComponentListSchema: z.ZodObject<{
|
|
|
55
65
|
detail: z.ZodOptional<z.ZodString>;
|
|
56
66
|
tone: z.ZodOptional<z.ZodEnum<{
|
|
57
67
|
error: "error";
|
|
58
|
-
info: "info";
|
|
59
68
|
success: "success";
|
|
69
|
+
info: "info";
|
|
60
70
|
warning: "warning";
|
|
61
71
|
muted: "muted";
|
|
62
72
|
accent: "accent";
|
|
@@ -74,8 +84,8 @@ export declare const UiComponentKeyValueSchema: z.ZodObject<{
|
|
|
74
84
|
value: z.ZodString;
|
|
75
85
|
tone: z.ZodOptional<z.ZodEnum<{
|
|
76
86
|
error: "error";
|
|
77
|
-
info: "info";
|
|
78
87
|
success: "success";
|
|
88
|
+
info: "info";
|
|
79
89
|
warning: "warning";
|
|
80
90
|
muted: "muted";
|
|
81
91
|
accent: "accent";
|
|
@@ -95,8 +105,8 @@ export declare const UiComponentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
95
105
|
text: z.ZodString;
|
|
96
106
|
tone: z.ZodOptional<z.ZodEnum<{
|
|
97
107
|
error: "error";
|
|
98
|
-
info: "info";
|
|
99
108
|
success: "success";
|
|
109
|
+
info: "info";
|
|
100
110
|
warning: "warning";
|
|
101
111
|
muted: "muted";
|
|
102
112
|
accent: "accent";
|
|
@@ -113,8 +123,8 @@ export declare const UiComponentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
113
123
|
detail: z.ZodOptional<z.ZodString>;
|
|
114
124
|
tone: z.ZodOptional<z.ZodEnum<{
|
|
115
125
|
error: "error";
|
|
116
|
-
info: "info";
|
|
117
126
|
success: "success";
|
|
127
|
+
info: "info";
|
|
118
128
|
warning: "warning";
|
|
119
129
|
muted: "muted";
|
|
120
130
|
accent: "accent";
|
|
@@ -131,8 +141,8 @@ export declare const UiComponentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
131
141
|
value: z.ZodString;
|
|
132
142
|
tone: z.ZodOptional<z.ZodEnum<{
|
|
133
143
|
error: "error";
|
|
134
|
-
info: "info";
|
|
135
144
|
success: "success";
|
|
145
|
+
info: "info";
|
|
136
146
|
warning: "warning";
|
|
137
147
|
muted: "muted";
|
|
138
148
|
accent: "accent";
|
|
@@ -185,8 +195,8 @@ export declare const UiDocSchema: z.ZodObject<{
|
|
|
185
195
|
text: z.ZodString;
|
|
186
196
|
tone: z.ZodOptional<z.ZodEnum<{
|
|
187
197
|
error: "error";
|
|
188
|
-
info: "info";
|
|
189
198
|
success: "success";
|
|
199
|
+
info: "info";
|
|
190
200
|
warning: "warning";
|
|
191
201
|
muted: "muted";
|
|
192
202
|
accent: "accent";
|
|
@@ -203,8 +213,8 @@ export declare const UiDocSchema: z.ZodObject<{
|
|
|
203
213
|
detail: z.ZodOptional<z.ZodString>;
|
|
204
214
|
tone: z.ZodOptional<z.ZodEnum<{
|
|
205
215
|
error: "error";
|
|
206
|
-
info: "info";
|
|
207
216
|
success: "success";
|
|
217
|
+
info: "info";
|
|
208
218
|
warning: "warning";
|
|
209
219
|
muted: "muted";
|
|
210
220
|
accent: "accent";
|
|
@@ -221,8 +231,8 @@ export declare const UiDocSchema: z.ZodObject<{
|
|
|
221
231
|
value: z.ZodString;
|
|
222
232
|
tone: z.ZodOptional<z.ZodEnum<{
|
|
223
233
|
error: "error";
|
|
224
|
-
info: "info";
|
|
225
234
|
success: "success";
|
|
235
|
+
info: "info";
|
|
226
236
|
warning: "warning";
|
|
227
237
|
muted: "muted";
|
|
228
238
|
accent: "accent";
|
|
@@ -258,6 +268,8 @@ export declare const UiDocSchema: z.ZodObject<{
|
|
|
258
268
|
metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
259
269
|
}, z.core.$strict>;
|
|
260
270
|
export type UiDoc = z.infer<typeof UiDocSchema>;
|
|
271
|
+
export declare const UI_STATUS_PROFILE_NAMES: readonly ["planning", "subagents", "control-flow", "model-routing"];
|
|
272
|
+
export type UiStatusProfileName = (typeof UI_STATUS_PROFILE_NAMES)[number];
|
|
261
273
|
export declare const UiEventSchema: z.ZodObject<{
|
|
262
274
|
ui_id: z.ZodString;
|
|
263
275
|
action_id: z.ZodString;
|
|
@@ -272,7 +284,12 @@ export declare const UiEventSchema: z.ZodObject<{
|
|
|
272
284
|
metadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
273
285
|
}, z.core.$strict>;
|
|
274
286
|
export type UiEvent = z.infer<typeof UiEventSchema>;
|
|
287
|
+
export declare function stableSerializeJson(value: unknown, opts?: {
|
|
288
|
+
pretty?: boolean;
|
|
289
|
+
}): string;
|
|
275
290
|
export declare function parseUiDoc(input: unknown): UiDoc | null;
|
|
291
|
+
export declare function resolveUiStatusProfileName(input: unknown): UiStatusProfileName | null;
|
|
292
|
+
export declare function uiStatusProfileWarnings(input: unknown): string[];
|
|
276
293
|
export declare function normalizeUiDocs(input: unknown, opts?: {
|
|
277
294
|
maxDocs?: number;
|
|
278
295
|
}): UiDoc[];
|
package/dist/ui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"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"}
|
package/dist/ui.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
|
|
2
|
+
export const UiToneSchema = z.enum(["info", "success", "warning", "error", "muted", "accent", "dim"]);
|
|
3
3
|
export const UI_CONTRACT_VERSION = 1;
|
|
4
4
|
const UI_DOC_TITLE_MAX_LENGTH = 256;
|
|
5
5
|
const UI_DOC_SUBTITLE_MAX_LENGTH = 512;
|
|
@@ -24,14 +24,14 @@ export const UiListItemSchema = z
|
|
|
24
24
|
id: NonEmptyId,
|
|
25
25
|
label: NonEmptyText(UI_ACTION_LABEL_MAX_LENGTH),
|
|
26
26
|
detail: NonEmptyText(UI_LIST_ITEM_DETAIL_MAX_LENGTH).optional(),
|
|
27
|
-
tone:
|
|
27
|
+
tone: UiToneSchema.optional(),
|
|
28
28
|
})
|
|
29
29
|
.strict();
|
|
30
30
|
export const UiKeyValueRowSchema = z
|
|
31
31
|
.object({
|
|
32
32
|
key: NonEmptyText(UI_KEY_MAX_LENGTH),
|
|
33
33
|
value: NonEmptyText(UI_VALUE_MAX_LENGTH),
|
|
34
|
-
tone:
|
|
34
|
+
tone: UiToneSchema.optional(),
|
|
35
35
|
})
|
|
36
36
|
.strict();
|
|
37
37
|
export const UiComponentTextSchema = z
|
|
@@ -39,7 +39,7 @@ export const UiComponentTextSchema = z
|
|
|
39
39
|
kind: z.literal("text"),
|
|
40
40
|
id: NonEmptyId,
|
|
41
41
|
text: NonEmptyText(UI_TEXT_COMPONENT_MAX_LENGTH),
|
|
42
|
-
tone:
|
|
42
|
+
tone: UiToneSchema.optional(),
|
|
43
43
|
metadata: z.record(z.string(), z.unknown()).default({}),
|
|
44
44
|
})
|
|
45
45
|
.strict();
|
|
@@ -106,6 +106,7 @@ export const UiDocSchema = z
|
|
|
106
106
|
metadata: z.record(z.string(), z.unknown()).default({}),
|
|
107
107
|
})
|
|
108
108
|
.strict();
|
|
109
|
+
export const UI_STATUS_PROFILE_NAMES = ["planning", "subagents", "control-flow", "model-routing"];
|
|
109
110
|
export const UiEventSchema = z
|
|
110
111
|
.object({
|
|
111
112
|
ui_id: NonEmptyId,
|
|
@@ -128,6 +129,129 @@ function parseUiDocCandidate(value) {
|
|
|
128
129
|
}
|
|
129
130
|
return parsed.data;
|
|
130
131
|
}
|
|
132
|
+
const UI_PROFILE_VARIANTS = ["status", "interactive"];
|
|
133
|
+
const UI_STATUS_PROFILE_UI_IDS = {
|
|
134
|
+
planning: "ui:planning",
|
|
135
|
+
subagents: "ui:subagents",
|
|
136
|
+
"control-flow": "ui:control-flow",
|
|
137
|
+
"model-routing": "ui:model-routing",
|
|
138
|
+
};
|
|
139
|
+
const UI_STATUS_PROFILE_COMPONENT_RECOMMENDATIONS = {
|
|
140
|
+
planning: ["key_value", "list"],
|
|
141
|
+
subagents: ["key_value", "list"],
|
|
142
|
+
"control-flow": ["key_value"],
|
|
143
|
+
"model-routing": ["key_value", "list"],
|
|
144
|
+
};
|
|
145
|
+
const UI_PLANNING_STATUS_ROW_KEY_ALIASES = {
|
|
146
|
+
phase: ["phase"],
|
|
147
|
+
waiting: ["waiting", "waiting_on_user"],
|
|
148
|
+
confidence: ["confidence", "conf"],
|
|
149
|
+
next: ["next", "next_action"],
|
|
150
|
+
blocker: ["blocker"],
|
|
151
|
+
};
|
|
152
|
+
const UI_PLANNING_CHECKLIST_MIN_ITEMS = 3;
|
|
153
|
+
function isUiStatusProfileName(value) {
|
|
154
|
+
return UI_STATUS_PROFILE_NAMES.includes(value);
|
|
155
|
+
}
|
|
156
|
+
function isUiProfileVariant(value) {
|
|
157
|
+
return UI_PROFILE_VARIANTS.includes(value);
|
|
158
|
+
}
|
|
159
|
+
function uiProfileMetadata(doc) {
|
|
160
|
+
const raw = doc.metadata.profile;
|
|
161
|
+
if (!isPlainObject(raw)) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
return raw;
|
|
165
|
+
}
|
|
166
|
+
function uiStatusProfileNameFromDoc(doc) {
|
|
167
|
+
const profile = uiProfileMetadata(doc);
|
|
168
|
+
if (!profile) {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
const raw = profile.id;
|
|
172
|
+
if (typeof raw !== "string") {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
const normalized = raw.trim().toLowerCase();
|
|
176
|
+
if (!normalized || !isUiStatusProfileName(normalized)) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
return normalized;
|
|
180
|
+
}
|
|
181
|
+
function hasUiComponentKind(doc, kind) {
|
|
182
|
+
return doc.components.some((component) => component.kind === kind);
|
|
183
|
+
}
|
|
184
|
+
function hasProfileSnapshotCompact(profile) {
|
|
185
|
+
const snapshot = profile.snapshot;
|
|
186
|
+
if (!isPlainObject(snapshot)) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
const compact = snapshot.compact;
|
|
190
|
+
return typeof compact === "string" && compact.trim().length > 0;
|
|
191
|
+
}
|
|
192
|
+
function normalizeStatusRowKey(key) {
|
|
193
|
+
return key
|
|
194
|
+
.trim()
|
|
195
|
+
.toLowerCase()
|
|
196
|
+
.replace(/[^a-z0-9]+/g, "_");
|
|
197
|
+
}
|
|
198
|
+
function keyValueStatusRows(doc) {
|
|
199
|
+
const rows = new Set();
|
|
200
|
+
for (const component of doc.components) {
|
|
201
|
+
if (component.kind !== "key_value") {
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
for (const row of component.rows) {
|
|
205
|
+
rows.add(normalizeStatusRowKey(row.key));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return rows;
|
|
209
|
+
}
|
|
210
|
+
function firstChecklistComponent(doc) {
|
|
211
|
+
for (const component of doc.components) {
|
|
212
|
+
if (component.kind === "list") {
|
|
213
|
+
return component;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
function hasPlanningMetadataField(doc, key) {
|
|
219
|
+
const value = doc.metadata[key];
|
|
220
|
+
if (key === "waiting_on_user") {
|
|
221
|
+
return typeof value === "boolean";
|
|
222
|
+
}
|
|
223
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
224
|
+
}
|
|
225
|
+
function planningStatusProfileWarnings(doc) {
|
|
226
|
+
const warnings = [];
|
|
227
|
+
const statusRows = keyValueStatusRows(doc);
|
|
228
|
+
for (const [field, aliases] of Object.entries(UI_PLANNING_STATUS_ROW_KEY_ALIASES)) {
|
|
229
|
+
const hasField = aliases.some((alias) => statusRows.has(alias));
|
|
230
|
+
if (!hasField) {
|
|
231
|
+
warnings.push(`profile.id=planning recommends key_value row key=${field}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const checklist = firstChecklistComponent(doc);
|
|
235
|
+
if (checklist) {
|
|
236
|
+
if (checklist.items.length < UI_PLANNING_CHECKLIST_MIN_ITEMS) {
|
|
237
|
+
warnings.push(`profile.id=planning recommends checklist lists with at least ${UI_PLANNING_CHECKLIST_MIN_ITEMS} items`);
|
|
238
|
+
}
|
|
239
|
+
const detailedItems = checklist.items.filter((item) => typeof item.detail === "string" && item.detail.trim().length > 0).length;
|
|
240
|
+
if (detailedItems === 0) {
|
|
241
|
+
warnings.push("profile.id=planning recommends checklist item detail values (for example done/pending)");
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (!hasPlanningMetadataField(doc, "phase")) {
|
|
245
|
+
warnings.push("profile.id=planning recommends metadata.phase");
|
|
246
|
+
}
|
|
247
|
+
if (!hasPlanningMetadataField(doc, "waiting_on_user")) {
|
|
248
|
+
warnings.push("profile.id=planning recommends metadata.waiting_on_user");
|
|
249
|
+
}
|
|
250
|
+
if (!hasPlanningMetadataField(doc, "confidence")) {
|
|
251
|
+
warnings.push("profile.id=planning recommends metadata.confidence");
|
|
252
|
+
}
|
|
253
|
+
return warnings;
|
|
254
|
+
}
|
|
131
255
|
function uiDocCandidates(input) {
|
|
132
256
|
if (Array.isArray(input)) {
|
|
133
257
|
return input;
|
|
@@ -150,6 +274,28 @@ function normalizedUiDocLimit(limit) {
|
|
|
150
274
|
}
|
|
151
275
|
return parsed;
|
|
152
276
|
}
|
|
277
|
+
function canonicalizeJson(value) {
|
|
278
|
+
if (Array.isArray(value)) {
|
|
279
|
+
return value.map((entry) => canonicalizeJson(entry));
|
|
280
|
+
}
|
|
281
|
+
if (!isPlainObject(value)) {
|
|
282
|
+
return value;
|
|
283
|
+
}
|
|
284
|
+
const out = {};
|
|
285
|
+
for (const key of Object.keys(value).sort()) {
|
|
286
|
+
const nextValue = value[key];
|
|
287
|
+
if (nextValue === undefined) {
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
out[key] = canonicalizeJson(nextValue);
|
|
291
|
+
}
|
|
292
|
+
return out;
|
|
293
|
+
}
|
|
294
|
+
export function stableSerializeJson(value, opts = {}) {
|
|
295
|
+
const normalized = canonicalizeJson(value);
|
|
296
|
+
const text = JSON.stringify(normalized, null, opts.pretty ? 2 : undefined);
|
|
297
|
+
return text ?? "null";
|
|
298
|
+
}
|
|
153
299
|
function deterministicUiDocChoice(left, right) {
|
|
154
300
|
if (left.revision.version !== right.revision.version) {
|
|
155
301
|
return left.revision.version > right.revision.version ? left : right;
|
|
@@ -164,6 +310,63 @@ function deterministicUiDocChoice(left, right) {
|
|
|
164
310
|
export function parseUiDoc(input) {
|
|
165
311
|
return parseUiDocCandidate(input);
|
|
166
312
|
}
|
|
313
|
+
export function resolveUiStatusProfileName(input) {
|
|
314
|
+
const doc = parseUiDocCandidate(input);
|
|
315
|
+
if (!doc) {
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
return uiStatusProfileNameFromDoc(doc);
|
|
319
|
+
}
|
|
320
|
+
export function uiStatusProfileWarnings(input) {
|
|
321
|
+
const doc = parseUiDocCandidate(input);
|
|
322
|
+
if (!doc) {
|
|
323
|
+
return [];
|
|
324
|
+
}
|
|
325
|
+
const profileName = uiStatusProfileNameFromDoc(doc);
|
|
326
|
+
if (!profileName) {
|
|
327
|
+
return [];
|
|
328
|
+
}
|
|
329
|
+
const warnings = [];
|
|
330
|
+
const profile = uiProfileMetadata(doc);
|
|
331
|
+
if (!profile) {
|
|
332
|
+
return warnings;
|
|
333
|
+
}
|
|
334
|
+
const rawVariant = typeof profile.variant === "string" ? profile.variant.trim().toLowerCase() : "";
|
|
335
|
+
let variant = "status";
|
|
336
|
+
if (rawVariant.length > 0) {
|
|
337
|
+
if (isUiProfileVariant(rawVariant)) {
|
|
338
|
+
variant = rawVariant;
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
warnings.push(`profile.id=${profileName} has unsupported metadata.profile.variant=${rawVariant}`);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
if (variant !== "status") {
|
|
345
|
+
warnings.push(`profile.id=${profileName} status validation expects metadata.profile.variant=status (got ${variant})`);
|
|
346
|
+
}
|
|
347
|
+
const expectedUiId = UI_STATUS_PROFILE_UI_IDS[profileName];
|
|
348
|
+
if (doc.ui_id !== expectedUiId) {
|
|
349
|
+
warnings.push(`profile.id=${profileName} expects ui_id=${expectedUiId} (got ${doc.ui_id})`);
|
|
350
|
+
}
|
|
351
|
+
if (!doc.summary) {
|
|
352
|
+
warnings.push(`profile.id=${profileName} recommends summary for deterministic status fallback`);
|
|
353
|
+
}
|
|
354
|
+
if (!hasProfileSnapshotCompact(profile)) {
|
|
355
|
+
warnings.push(`profile.id=${profileName} recommends metadata.profile.snapshot.compact`);
|
|
356
|
+
}
|
|
357
|
+
if (doc.actions.length > 0) {
|
|
358
|
+
warnings.push(`profile.id=${profileName} status docs should omit actions (got ${doc.actions.length})`);
|
|
359
|
+
}
|
|
360
|
+
for (const kind of UI_STATUS_PROFILE_COMPONENT_RECOMMENDATIONS[profileName]) {
|
|
361
|
+
if (!hasUiComponentKind(doc, kind)) {
|
|
362
|
+
warnings.push(`profile.id=${profileName} recommends a ${kind} component`);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (profileName === "planning") {
|
|
366
|
+
warnings.push(...planningStatusProfileWarnings(doc));
|
|
367
|
+
}
|
|
368
|
+
return warnings;
|
|
369
|
+
}
|
|
167
370
|
export function normalizeUiDocs(input, opts = {}) {
|
|
168
371
|
const maxDocs = normalizedUiDocLimit(opts.maxDocs);
|
|
169
372
|
const byId = new Map();
|
package/package.json
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
2
|
+
"name": "@femtomc/mu-core",
|
|
3
|
+
"version": "26.2.109",
|
|
4
|
+
"description": "Core primitives for mu: IDs, events, schemas, and persistence interfaces.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mu",
|
|
7
|
+
"agent",
|
|
8
|
+
"core",
|
|
9
|
+
"events"
|
|
10
|
+
],
|
|
11
|
+
"type": "module",
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./browser": {
|
|
20
|
+
"types": "./dist/browser/index.d.ts",
|
|
21
|
+
"default": "./dist/browser/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./node": {
|
|
24
|
+
"types": "./dist/node/index.d.ts",
|
|
25
|
+
"default": "./dist/node/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist/**"
|
|
30
|
+
],
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"zod": "^4.1.9"
|
|
33
|
+
}
|
|
34
34
|
}
|