@almadar/core 4.5.0 → 4.7.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.
@@ -1,8 +1,52 @@
1
- import { T as TraitEventContract, E as EntityField, a as EntityPersistence, b as EntityRow, O as OrbitalDefinition, c as OrbitalSchema, d as Trait, e as Entity, P as Page } from './schema-D4VBpRZI.js';
2
- export { C as ComposeBehaviorsInput, a as ComposeBehaviorsResult, E as EventWiringEntry, L as LayoutStrategy, b as applyEventWiring, c as composeBehaviors, d as detectLayoutStrategy } from './compose-behaviors-BtjmpmIC.js';
1
+ import { T as TraitReference, a as TraitEventContract, E as Entity, S as SExpr, b as TraitEventListener, c as EntityField, d as EntityPersistence, e as EntityRow, U as UseDeclaration, f as EntityRef, g as TraitRef, P as PageRef, O as OrbitalDefinition, h as OrbitalSchema, i as Trait, j as Page, k as PageRefObject } from './schema-C-6fdZ5P.js';
2
+ export { C as ComposeBehaviorsInput, a as ComposeBehaviorsResult, E as EventWiringEntry, L as LayoutStrategy, b as applyEventWiring, c as composeBehaviors, d as detectLayoutStrategy } from './compose-behaviors-BLEoAOk6.js';
3
3
  import 'zod';
4
4
  import '@almadar/patterns';
5
5
 
6
+ /**
7
+ * Explode Behavior Composition
8
+ *
9
+ * Human-authoring primitive (Phase 5.3 of Almadar_Agent_Behaviors_Plan).
10
+ *
11
+ * Reads a behavior's compiled `.orb` from the sibling `@almadar/std`
12
+ * registry on disk and returns the flat list of `TraitReference` objects
13
+ * it's composed from — each with `from`, `ref`, `linkedEntity`, and any
14
+ * call-site overrides. **Not exposed to the agent or LLM.** The helper
15
+ * exists for developers designing new molecules or debugging compositions.
16
+ *
17
+ * The function is Node-only. It walks the filesystem under
18
+ * `packages/almadar-std/behaviors/registry/{atoms,molecules,organisms}/`
19
+ * relative to this source file and will throw a descriptive error if the
20
+ * behavior cannot be resolved.
21
+ *
22
+ * When the target is a leaf atom (no `uses:` / composition), the function
23
+ * returns a single synthetic `TraitReference` pointing at the atom's own
24
+ * inline trait so consumers always get something useful.
25
+ *
26
+ * @packageDocumentation
27
+ */
28
+
29
+ /**
30
+ * Flatten a behavior's `.orb` composition into the list of
31
+ * `TraitReference` objects it's built from.
32
+ *
33
+ * For composed behaviors (molecules, organisms) this returns every
34
+ * `TraitReference` entry from every orbital's `traits:` array, carrying
35
+ * the call-site `ref`, backfilled `from` (looked up against the orbital's
36
+ * `uses:` imports when omitted), `linkedEntity`, `events`, `effects`, and
37
+ * any other override fields declared at the call site.
38
+ *
39
+ * For leaf atoms (no composition, only an inline trait) the function
40
+ * returns a single synthetic `TraitReference` pointing at the atom's own
41
+ * trait, so consumers always get a non-empty array they can iterate.
42
+ *
43
+ * @param behaviorName - Registry name of the behavior (e.g. `"std-cart"`,
44
+ * `"std-browse"`).
45
+ * @returns Flat list of every `TraitReference` the behavior is composed of.
46
+ * @throws Error when the behavior cannot be found in any registry level.
47
+ */
48
+ declare function explodeBehaviorComposition(behaviorName: string): TraitReference[];
49
+
6
50
  /**
7
51
  * Orbital Builders
8
52
  *
@@ -52,6 +96,146 @@ declare function makePage(opts: MakePageOpts): Page;
52
96
  * Build an OrbitalDefinition from its three components.
53
97
  */
54
98
  declare function makeOrbital(name: string, entity: Entity, traits: Trait[], pages: Page[]): OrbitalDefinition;
99
+ /**
100
+ * Options for {@link makeTraitRef}.
101
+ */
102
+ interface MakeTraitRefOpts {
103
+ /**
104
+ * Optional registry path disambiguator that pairs with {@link ref}
105
+ * (see {@link TraitReference.from}).
106
+ */
107
+ from?: string;
108
+ /** Trait reference string, e.g. "Browse.traits.BrowseItemBrowse". */
109
+ ref: string;
110
+ /** Rename the inlined trait at the call site. */
111
+ name?: string;
112
+ /** Rebind the trait to a different linkedEntity. */
113
+ linkedEntity?: string;
114
+ /** Per-key rename map, e.g. `{ OPEN: "ADD_ITEM" }`. */
115
+ events?: Record<string, string>;
116
+ /**
117
+ * Per-event SExpression effect replacement. Keys are POST-rename event
118
+ * names. See {@link TraitReference.effects} for the full contract.
119
+ */
120
+ effects?: Record<string, SExpr[]>;
121
+ /** Replace the imported trait's `listens` array entirely. */
122
+ listens?: TraitEventListener[];
123
+ /** Set every emit's scope. */
124
+ emitsScope?: 'internal' | 'external';
125
+ /**
126
+ * Nested config overrides. Matches the real {@link TraitReference.config}
127
+ * shape: `Record<string, Record<string, unknown>>` (the outer key is the
128
+ * config field name, the inner record is its value shape).
129
+ */
130
+ config?: Record<string, Record<string, unknown>>;
131
+ }
132
+ /**
133
+ * Build a {@link TraitReference} from options.
134
+ *
135
+ * Pass-through factory: copies only the fields that are actually provided,
136
+ * so optionals stay absent (no `key: undefined` slots) and the emitted
137
+ * object matches the inliner's expectation that "present = override".
138
+ */
139
+ declare function makeTraitRef(opts: MakeTraitRefOpts): TraitReference;
140
+ /**
141
+ * Options for {@link makePageRef}.
142
+ */
143
+ interface MakePageRefOpts {
144
+ /**
145
+ * Optional registry path disambiguator that pairs with {@link ref}
146
+ * (see {@link PageRefObject.from}).
147
+ */
148
+ from?: string;
149
+ /** Page reference string, e.g. "Browse.pages.BrowseItemPage". */
150
+ ref: string;
151
+ /** URL path override. */
152
+ path?: string;
153
+ /** Rebind the page's primary entity. */
154
+ linkedEntity?: string;
155
+ /** Replace the page's trait list. */
156
+ traits?: TraitRef[];
157
+ }
158
+ /**
159
+ * Build a {@link PageRefObject} from options. Pass-through factory — omits
160
+ * optional keys that are `undefined`.
161
+ */
162
+ declare function makePageRef(opts: MakePageRefOpts): PageRefObject;
163
+ /**
164
+ * Options for {@link makeOrbitalWithUses}.
165
+ */
166
+ interface MakeOrbitalWithUsesOpts {
167
+ /** Orbital name. */
168
+ name: string;
169
+ /**
170
+ * Per-orbital `uses:` header entries (see CLAUDE.md "uses: lives inside
171
+ * the orbital").
172
+ */
173
+ uses: UseDeclaration[];
174
+ /** Entity (inline or reference form). */
175
+ entity: EntityRef;
176
+ /** Trait references. */
177
+ traits: TraitRef[];
178
+ /** Optional page references (omitted entirely when not provided). */
179
+ pages?: PageRef[];
180
+ }
181
+ /**
182
+ * Build an {@link OrbitalDefinition} with the `uses:` header set. Follows
183
+ * the convention that `uses:` lives on the orbital (not the schema).
184
+ *
185
+ * When `pages` is omitted, the result has no `pages` property (matches the
186
+ * existing {@link OrbitalDefinition.pages} optionality in descriptors that
187
+ * carry trait-only atoms).
188
+ */
189
+ declare function makeOrbitalWithUses(opts: MakeOrbitalWithUsesOpts): OrbitalDefinition;
190
+ /**
191
+ * Options for {@link makeAtomOrbital}.
192
+ *
193
+ * Overrides for the single trait reference. Mirrors the {@link MakeTraitRefOpts}
194
+ * subset that is meaningful at the atom-wrapping call site.
195
+ */
196
+ interface MakeAtomOrbitalTraitOverrides {
197
+ name?: string;
198
+ events?: Record<string, string>;
199
+ effects?: Record<string, SExpr[]>;
200
+ listens?: TraitEventListener[];
201
+ emitsScope?: 'internal' | 'external';
202
+ config?: Record<string, Record<string, unknown>>;
203
+ }
204
+ /**
205
+ * Options for {@link makeAtomOrbital}.
206
+ */
207
+ interface MakeAtomOrbitalOpts {
208
+ /** Orbital name, e.g. `${entityName}Orbital`. */
209
+ name: string;
210
+ /** Atom registry path, e.g. `std/behaviors/atoms/std-browse`. */
211
+ atomPath: string;
212
+ /** Import alias (PascalCase), e.g. `Browse`. */
213
+ alias: string;
214
+ /** Entity definition to attach to the orbital. */
215
+ entity: Entity;
216
+ /** Trait reference string, e.g. `Browse.traits.BrowseItemBrowse`. */
217
+ traitRef: string;
218
+ /** Optional trait-level overrides applied at the call site. */
219
+ traitOverrides?: MakeAtomOrbitalTraitOverrides;
220
+ /** Optional page reference string, e.g. `Browse.pages.BrowseItemPage`. */
221
+ pageRef?: string;
222
+ /** Optional page-level overrides applied at the call site. */
223
+ pageOverrides?: {
224
+ path?: string;
225
+ };
226
+ }
227
+ /**
228
+ * Build a single-atom {@link OrbitalDefinition}.
229
+ *
230
+ * The common atom shape: one entity + one trait reference + (optionally) one
231
+ * page reference, all under a single `uses:` import. Wraps
232
+ * {@link makeTraitRef}, {@link makePageRef}, and {@link makeOrbitalWithUses}.
233
+ *
234
+ * The trait reference is linkedEntity-bound to `entity.name` by default so
235
+ * that the inliner's entity-substitution pass rewrites every `["ref", X]`
236
+ * and `@X.path` reference inside the atom.
237
+ */
238
+ declare function makeAtomOrbital(opts: MakeAtomOrbitalOpts): OrbitalDefinition;
55
239
  /**
56
240
  * Wrap one or more OrbitalDefinitions into an OrbitalSchema.
57
241
  * Every .orb file should be a full OrbitalSchema — this is the builder for that.
@@ -103,4 +287,4 @@ declare function compose(orbitals: (OrbitalDefinition | OrbitalSchema)[], pages:
103
287
  */
104
288
  declare function pipe(orbitals: (OrbitalDefinition | OrbitalSchema)[], events: TraitEventContract[], appName?: string): OrbitalSchema;
105
289
 
106
- export { type ComposeConnection, type ComposePage, type MakeEntityOpts, type MakePageOpts, compose, connect, ensureIdField, extractTrait, makeEntity, makeOrbital, makePage, makeSchema, mergeOrbitals, pipe, plural, wire };
290
+ export { type ComposeConnection, type ComposePage, type MakeAtomOrbitalOpts, type MakeAtomOrbitalTraitOverrides, type MakeEntityOpts, type MakeOrbitalWithUsesOpts, type MakePageOpts, type MakePageRefOpts, type MakeTraitRefOpts, compose, connect, ensureIdField, explodeBehaviorComposition, extractTrait, makeAtomOrbital, makeEntity, makeOrbital, makeOrbitalWithUses, makePage, makePageRef, makeSchema, makeTraitRef, mergeOrbitals, pipe, plural, wire };
package/dist/builders.js CHANGED
@@ -1,4 +1,7 @@
1
1
  import { z } from 'zod';
2
+ import { readFileSync } from 'fs';
3
+ import { resolve, dirname } from 'path';
4
+ import { fileURLToPath } from 'url';
2
5
 
3
6
  // src/types/orbital.ts
4
7
  var FieldTypeSchema = z.enum([
@@ -1038,6 +1041,104 @@ function composeBehaviors(input) {
1038
1041
  }
1039
1042
  };
1040
1043
  }
1044
+ function registryRoot() {
1045
+ const here = dirname(fileURLToPath(import.meta.url));
1046
+ return resolve(here, "..", "..", "..", "almadar-std", "behaviors", "registry");
1047
+ }
1048
+ var LEVELS = ["atoms", "molecules", "organisms"];
1049
+ function resolveBehavior(behaviorName) {
1050
+ const root = registryRoot();
1051
+ const searched = [];
1052
+ for (const level of LEVELS) {
1053
+ const path = resolve(root, level, `${behaviorName}.orb`);
1054
+ searched.push(path);
1055
+ let source;
1056
+ try {
1057
+ source = readFileSync(path, "utf8");
1058
+ } catch {
1059
+ continue;
1060
+ }
1061
+ let parsed;
1062
+ try {
1063
+ parsed = JSON.parse(source);
1064
+ } catch (err) {
1065
+ const message = err instanceof Error ? err.message : String(err);
1066
+ throw new Error(
1067
+ `explodeBehaviorComposition: failed to parse ${path} as JSON: ${message}`
1068
+ );
1069
+ }
1070
+ return { level, path, schema: parsed };
1071
+ }
1072
+ throw new Error(
1073
+ `explodeBehaviorComposition: behavior "${behaviorName}" not found. Searched:
1074
+ - ${searched.join("\n - ")}`
1075
+ );
1076
+ }
1077
+ function isTraitReferenceObject(entry) {
1078
+ return typeof entry === "object" && entry !== null && "ref" in entry && typeof entry.ref === "string" && !isInlineTrait(entry);
1079
+ }
1080
+ function aliasToFromMap(uses) {
1081
+ const map = /* @__PURE__ */ new Map();
1082
+ if (!uses) return map;
1083
+ for (const use of uses) {
1084
+ map.set(use.as, use.from);
1085
+ }
1086
+ return map;
1087
+ }
1088
+ function extractAlias(ref) {
1089
+ const match = ref.match(/^([A-Z][a-zA-Z0-9]*)\.traits\.[A-Z][a-zA-Z0-9]*$/);
1090
+ return match ? match[1] : null;
1091
+ }
1092
+ function findAtomInlineTrait(orbital) {
1093
+ for (const entry of orbital.traits) {
1094
+ if (typeof entry === "object" && entry !== null && isInlineTrait(entry)) {
1095
+ return entry;
1096
+ }
1097
+ }
1098
+ return void 0;
1099
+ }
1100
+ function syntheticLeafReference(behaviorName, orbital, trait) {
1101
+ const base = behaviorName.replace(/^std-/, "");
1102
+ const alias = base.split("-").filter((segment) => segment.length > 0).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join("") || "Behavior";
1103
+ const entityName = typeof orbital.entity === "string" ? orbital.entity : "name" in orbital.entity && typeof orbital.entity.name === "string" ? orbital.entity.name : void 0;
1104
+ const reference = {
1105
+ ref: `${alias}.traits.${trait.name}`,
1106
+ from: `std/behaviors/${behaviorName}`
1107
+ };
1108
+ if (trait.linkedEntity !== void 0) {
1109
+ reference.linkedEntity = trait.linkedEntity;
1110
+ } else if (entityName !== void 0) {
1111
+ reference.linkedEntity = entityName;
1112
+ }
1113
+ return reference;
1114
+ }
1115
+ function explodeBehaviorComposition(behaviorName) {
1116
+ const resolved = resolveBehavior(behaviorName);
1117
+ const orbitals = Array.isArray(resolved.schema.orbitals) ? resolved.schema.orbitals : [];
1118
+ const references = [];
1119
+ for (const orbital of orbitals) {
1120
+ const aliasMap = aliasToFromMap(orbital.uses);
1121
+ for (const entry of orbital.traits ?? []) {
1122
+ if (!isTraitReferenceObject(entry)) continue;
1123
+ const copy = { ...entry };
1124
+ if (copy.from === void 0) {
1125
+ const alias = extractAlias(copy.ref);
1126
+ const fromPath = alias !== null ? aliasMap.get(alias) : void 0;
1127
+ if (fromPath !== void 0) {
1128
+ copy.from = fromPath;
1129
+ }
1130
+ }
1131
+ references.push(copy);
1132
+ }
1133
+ }
1134
+ if (references.length > 0) return references;
1135
+ const firstOrbital = orbitals[0];
1136
+ const inlineTrait = firstOrbital ? findAtomInlineTrait(firstOrbital) : void 0;
1137
+ if (firstOrbital && inlineTrait) {
1138
+ return [syntheticLeafReference(behaviorName, firstOrbital, inlineTrait)];
1139
+ }
1140
+ return [];
1141
+ }
1041
1142
 
1042
1143
  // src/builders.ts
1043
1144
  function ensureIdField(fields) {
@@ -1080,6 +1181,64 @@ function makePage(opts) {
1080
1181
  function makeOrbital(name, entity, traits, pages) {
1081
1182
  return { name, entity, traits, pages };
1082
1183
  }
1184
+ function makeTraitRef(opts) {
1185
+ const ref = { ref: opts.ref };
1186
+ if (opts.from !== void 0) ref.from = opts.from;
1187
+ if (opts.name !== void 0) ref.name = opts.name;
1188
+ if (opts.linkedEntity !== void 0) ref.linkedEntity = opts.linkedEntity;
1189
+ if (opts.events !== void 0) ref.events = opts.events;
1190
+ if (opts.effects !== void 0) ref.effects = opts.effects;
1191
+ if (opts.listens !== void 0) ref.listens = opts.listens;
1192
+ if (opts.emitsScope !== void 0) ref.emitsScope = opts.emitsScope;
1193
+ if (opts.config !== void 0) ref.config = opts.config;
1194
+ return ref;
1195
+ }
1196
+ function makePageRef(opts) {
1197
+ const ref = { ref: opts.ref };
1198
+ if (opts.from !== void 0) ref.from = opts.from;
1199
+ if (opts.path !== void 0) ref.path = opts.path;
1200
+ if (opts.linkedEntity !== void 0) ref.linkedEntity = opts.linkedEntity;
1201
+ if (opts.traits !== void 0) ref.traits = opts.traits;
1202
+ return ref;
1203
+ }
1204
+ function makeOrbitalWithUses(opts) {
1205
+ const orbital = {
1206
+ name: opts.name,
1207
+ uses: opts.uses,
1208
+ entity: opts.entity,
1209
+ traits: opts.traits,
1210
+ pages: opts.pages ?? []
1211
+ };
1212
+ return orbital;
1213
+ }
1214
+ function makeAtomOrbital(opts) {
1215
+ const traitRef = makeTraitRef({
1216
+ from: opts.atomPath,
1217
+ ref: opts.traitRef,
1218
+ linkedEntity: opts.entity.name,
1219
+ ...opts.traitOverrides?.name !== void 0 ? { name: opts.traitOverrides.name } : {},
1220
+ ...opts.traitOverrides?.events !== void 0 ? { events: opts.traitOverrides.events } : {},
1221
+ ...opts.traitOverrides?.effects !== void 0 ? { effects: opts.traitOverrides.effects } : {},
1222
+ ...opts.traitOverrides?.listens !== void 0 ? { listens: opts.traitOverrides.listens } : {},
1223
+ ...opts.traitOverrides?.emitsScope !== void 0 ? { emitsScope: opts.traitOverrides.emitsScope } : {},
1224
+ ...opts.traitOverrides?.config !== void 0 ? { config: opts.traitOverrides.config } : {}
1225
+ });
1226
+ const pages = opts.pageRef ? [
1227
+ makePageRef({
1228
+ from: opts.atomPath,
1229
+ ref: opts.pageRef,
1230
+ linkedEntity: opts.entity.name,
1231
+ ...opts.pageOverrides?.path !== void 0 ? { path: opts.pageOverrides.path } : {}
1232
+ })
1233
+ ] : void 0;
1234
+ return makeOrbitalWithUses({
1235
+ name: opts.name,
1236
+ uses: [{ from: opts.atomPath, as: opts.alias }],
1237
+ entity: opts.entity,
1238
+ traits: [traitRef],
1239
+ ...pages !== void 0 ? { pages } : {}
1240
+ });
1241
+ }
1083
1242
  function makeSchema(name, ...definitions) {
1084
1243
  return { name, version: "1.0.0", orbitals: definitions };
1085
1244
  }
@@ -1227,6 +1386,6 @@ function pipe(orbitals, events, appName) {
1227
1386
  };
1228
1387
  }
1229
1388
 
1230
- export { applyEventWiring, compose, composeBehaviors, connect, detectLayoutStrategy, ensureIdField, extractTrait, makeEntity, makeOrbital, makePage, makeSchema, mergeOrbitals, pipe, plural, wire };
1389
+ export { applyEventWiring, compose, composeBehaviors, connect, detectLayoutStrategy, ensureIdField, explodeBehaviorComposition, extractTrait, makeAtomOrbital, makeEntity, makeOrbital, makeOrbitalWithUses, makePage, makePageRef, makeSchema, makeTraitRef, mergeOrbitals, pipe, plural, wire };
1231
1390
  //# sourceMappingURL=builders.js.map
1232
1391
  //# sourceMappingURL=builders.js.map