@femtomc/mu-core 26.2.107 → 26.2.108

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 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
@@ -1,6 +1,4 @@
1
1
  export * from "./events.js";
2
- export * from "./hud.js";
3
- export * from "./hud_runtime.js";
4
2
  export * from "./ids.js";
5
3
  export * from "./persistence.js";
6
4
  export * from "./spec.js";
@@ -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,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,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
@@ -1,6 +1,4 @@
1
1
  export * from "./events.js";
2
- export * from "./hud.js";
3
- export * from "./hud_runtime.js";
4
2
  export * from "./ids.js";
5
3
  export * from "./persistence.js";
6
4
  export * from "./spec.js";
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;AAGxB,eAAO,MAAM,mBAAmB,EAAG,CAAU,CAAC;AAsB9C,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;kBAOnB,CAAC;AACX,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,mBAAmB;;;;;;;;;;;;kBAMtB,CAAC;AACX,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;kBAQxB,CAAC;AACX,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;kBAQxB,CAAC;AAEX,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;kBAQ5B,CAAC;AAEX,eAAO,MAAM,wBAAwB;;;;kBAM3B,CAAC;AAEX,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BAK5B,CAAC;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,kBAAkB;;;;;EAAqD,CAAC;AACrF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D,eAAO,MAAM,cAAc;;;;;;;;;;;;;;kBAWjB,CAAC;AACX,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,gBAAgB;;;kBAKnB,CAAC;AACX,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAYd,CAAC;AACX,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD,eAAO,MAAM,aAAa;;;;;;;;;;;;kBAWhB,CAAC;AACX,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAkDpD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,GAAG,IAAI,CAEvD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,KAAK,EAAE,CAoBxF;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAQxE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAM3D"}
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
- import { HudToneSchema, stableSerializeJson } from "./hud.js";
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: HudToneSchema.optional(),
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: HudToneSchema.optional(),
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: HudToneSchema.optional(),
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,58 @@ 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
+ function isUiStatusProfileName(value) {
146
+ return UI_STATUS_PROFILE_NAMES.includes(value);
147
+ }
148
+ function isUiProfileVariant(value) {
149
+ return UI_PROFILE_VARIANTS.includes(value);
150
+ }
151
+ function uiProfileMetadata(doc) {
152
+ const raw = doc.metadata.profile;
153
+ if (!isPlainObject(raw)) {
154
+ return null;
155
+ }
156
+ return raw;
157
+ }
158
+ function uiStatusProfileNameFromDoc(doc) {
159
+ const profile = uiProfileMetadata(doc);
160
+ if (!profile) {
161
+ return null;
162
+ }
163
+ const raw = profile.id;
164
+ if (typeof raw !== "string") {
165
+ return null;
166
+ }
167
+ const normalized = raw.trim().toLowerCase();
168
+ if (!normalized || !isUiStatusProfileName(normalized)) {
169
+ return null;
170
+ }
171
+ return normalized;
172
+ }
173
+ function hasUiComponentKind(doc, kind) {
174
+ return doc.components.some((component) => component.kind === kind);
175
+ }
176
+ function hasProfileSnapshotCompact(profile) {
177
+ const snapshot = profile.snapshot;
178
+ if (!isPlainObject(snapshot)) {
179
+ return false;
180
+ }
181
+ const compact = snapshot.compact;
182
+ return typeof compact === "string" && compact.trim().length > 0;
183
+ }
131
184
  function uiDocCandidates(input) {
132
185
  if (Array.isArray(input)) {
133
186
  return input;
@@ -150,6 +203,28 @@ function normalizedUiDocLimit(limit) {
150
203
  }
151
204
  return parsed;
152
205
  }
206
+ function canonicalizeJson(value) {
207
+ if (Array.isArray(value)) {
208
+ return value.map((entry) => canonicalizeJson(entry));
209
+ }
210
+ if (!isPlainObject(value)) {
211
+ return value;
212
+ }
213
+ const out = {};
214
+ for (const key of Object.keys(value).sort()) {
215
+ const nextValue = value[key];
216
+ if (nextValue === undefined) {
217
+ continue;
218
+ }
219
+ out[key] = canonicalizeJson(nextValue);
220
+ }
221
+ return out;
222
+ }
223
+ export function stableSerializeJson(value, opts = {}) {
224
+ const normalized = canonicalizeJson(value);
225
+ const text = JSON.stringify(normalized, null, opts.pretty ? 2 : undefined);
226
+ return text ?? "null";
227
+ }
153
228
  function deterministicUiDocChoice(left, right) {
154
229
  if (left.revision.version !== right.revision.version) {
155
230
  return left.revision.version > right.revision.version ? left : right;
@@ -164,6 +239,60 @@ function deterministicUiDocChoice(left, right) {
164
239
  export function parseUiDoc(input) {
165
240
  return parseUiDocCandidate(input);
166
241
  }
242
+ export function resolveUiStatusProfileName(input) {
243
+ const doc = parseUiDocCandidate(input);
244
+ if (!doc) {
245
+ return null;
246
+ }
247
+ return uiStatusProfileNameFromDoc(doc);
248
+ }
249
+ export function uiStatusProfileWarnings(input) {
250
+ const doc = parseUiDocCandidate(input);
251
+ if (!doc) {
252
+ return [];
253
+ }
254
+ const profileName = uiStatusProfileNameFromDoc(doc);
255
+ if (!profileName) {
256
+ return [];
257
+ }
258
+ const warnings = [];
259
+ const profile = uiProfileMetadata(doc);
260
+ if (!profile) {
261
+ return warnings;
262
+ }
263
+ const rawVariant = typeof profile.variant === "string" ? profile.variant.trim().toLowerCase() : "";
264
+ let variant = "status";
265
+ if (rawVariant.length > 0) {
266
+ if (isUiProfileVariant(rawVariant)) {
267
+ variant = rawVariant;
268
+ }
269
+ else {
270
+ warnings.push(`profile.id=${profileName} has unsupported metadata.profile.variant=${rawVariant}`);
271
+ }
272
+ }
273
+ if (variant !== "status") {
274
+ warnings.push(`profile.id=${profileName} status validation expects metadata.profile.variant=status (got ${variant})`);
275
+ }
276
+ const expectedUiId = UI_STATUS_PROFILE_UI_IDS[profileName];
277
+ if (doc.ui_id !== expectedUiId) {
278
+ warnings.push(`profile.id=${profileName} expects ui_id=${expectedUiId} (got ${doc.ui_id})`);
279
+ }
280
+ if (!doc.summary) {
281
+ warnings.push(`profile.id=${profileName} recommends summary for deterministic status fallback`);
282
+ }
283
+ if (!hasProfileSnapshotCompact(profile)) {
284
+ warnings.push(`profile.id=${profileName} recommends metadata.profile.snapshot.compact`);
285
+ }
286
+ if (doc.actions.length > 0) {
287
+ warnings.push(`profile.id=${profileName} status docs should omit actions (got ${doc.actions.length})`);
288
+ }
289
+ for (const kind of UI_STATUS_PROFILE_COMPONENT_RECOMMENDATIONS[profileName]) {
290
+ if (!hasUiComponentKind(doc, kind)) {
291
+ warnings.push(`profile.id=${profileName} recommends a ${kind} component`);
292
+ }
293
+ }
294
+ return warnings;
295
+ }
167
296
  export function normalizeUiDocs(input, opts = {}) {
168
297
  const maxDocs = normalizedUiDocLimit(opts.maxDocs);
169
298
  const byId = new Map();
package/package.json CHANGED
@@ -1,34 +1,34 @@
1
1
  {
2
- "name": "@femtomc/mu-core",
3
- "version": "26.2.107",
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
- }
2
+ "name": "@femtomc/mu-core",
3
+ "version": "26.2.108",
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
  }