@almadar/core 7.22.0 → 7.24.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,4 +1,4 @@
1
- import { a6 as EntityField, a9 as EntityPersistence, cX as TraitReference, c$ as TraitScope, a2 as Entity, br as Page, bh as OrbitalSchema, cE as Trait } from '../schema-BVni4uNf.js';
1
+ import { a6 as EntityField, a9 as EntityPersistence, cX as TraitReference, c$ as TraitScope, cS as TraitEventListener, a2 as Entity, br as Page, bh as OrbitalSchema, cE as Trait } from '../schema-BVni4uNf.js';
2
2
  import { S as SExpr } from '../expression-BVRFm0sV.js';
3
3
  import 'zod';
4
4
  import '@almadar/patterns';
@@ -472,6 +472,73 @@ interface PresentationNavItem {
472
472
  /** Optional icon key (consumer-resolved). */
473
473
  icon?: string;
474
474
  }
475
+ /**
476
+ * LLM-authored trait-level overrides keyed by trait name (matches
477
+ * `signature.traits[].name`). Each entry's `config` keys are
478
+ * validated against `signature.traits[i].overridableConfigKeys`;
479
+ * unknown trait names or unknown config keys emit typed warnings
480
+ * and are skipped. Mirrors the existing call-site override surface
481
+ * on `TraitReference` in `OrbitalSchema`.
482
+ */
483
+ type TraitOverlay = Readonly<Record<string, TraitOverlayEntry>>;
484
+ interface TraitOverlayEntry {
485
+ config?: Readonly<Record<string, FactoryParamValue>>;
486
+ linkedEntity?: string;
487
+ events?: Readonly<Record<string, string>>;
488
+ name?: string;
489
+ emitsScope?: 'internal' | 'external';
490
+ /** Reuses `TraitEventListener` from `@almadar/core/types/trait` so the
491
+ * overlay's listen entries carry the same `event` / `triggers` /
492
+ * `source` / `guard` shape as everywhere else — no narrower clone. */
493
+ listens?: ReadonlyArray<TraitEventListener>;
494
+ }
495
+ /** @deprecated Phase 4.1 placeholder — use `TraitEventListener` instead.
496
+ * Kept as a structural type alias so callers that imported it keep
497
+ * compiling through the transition; will be removed in 7.25.0. */
498
+ type TraitOverlayListener = TraitEventListener;
499
+ /**
500
+ * Rules carry a free-form `capability: string` that the translator
501
+ * matches against `signature.traits[].capabilities` (source-tagged
502
+ * in `.lolo`, propagated via `@almadar/core@7.22.0`).
503
+ *
504
+ * NO closed enum on `capability` — atoms advertise capability
505
+ * strings in their `.lolo` headers, and the catalog grows the
506
+ * vocabulary organically. The agent emits whatever capability
507
+ * string the user's domain expresses; if no trait in the catalog
508
+ * advertises that capability, the translator emits a typed warning.
509
+ */
510
+ interface RuleOverlay {
511
+ rules: ReadonlyArray<DomainRuleOverlayEntry>;
512
+ /**
513
+ * Entity-level ownership signal. Until Phase 1.5 promotes
514
+ * `ownedBy` into `DomainEntity`, ownership rides here as a
515
+ * parallel typed channel. The translator threads it into the
516
+ * matched trait's `config.ownerField` (when the matched trait
517
+ * advertises that key in `overridableConfigKeys`).
518
+ */
519
+ ownership?: ReadonlyArray<OwnershipOverlayEntry>;
520
+ }
521
+ interface DomainRuleOverlayEntry {
522
+ id: string;
523
+ /** Free-form capability label, matched against
524
+ * `signature.traits[].capabilities` by exact set membership. */
525
+ capability: string;
526
+ description: string;
527
+ /** Entity names this rule binds to. Empty array = cross-cutting:
528
+ * the rule applies to every orbital the translator visits. */
529
+ appliesTo: ReadonlyArray<string>;
530
+ /** Optional role name (e.g. `"admin"`) when the rule is role-scoped. */
531
+ role?: string;
532
+ /** Optional extra config knobs threaded into the matched trait's
533
+ * `config`. Validated against the trait's `overridableConfigKeys`. */
534
+ config?: Readonly<Record<string, FactoryParamValue>>;
535
+ }
536
+ interface OwnershipOverlayEntry {
537
+ /** Entity name (matches `DomainEntity.name`). */
538
+ entity: string;
539
+ /** Field name on the entity that carries the owner identifier. */
540
+ ownerField: string;
541
+ }
475
542
 
476
543
  /**
477
544
  * Domain Language Tokens
@@ -1001,7 +1068,7 @@ interface TranslationResult {
1001
1068
  callSite: FactoryCallSite;
1002
1069
  warnings: ReadonlyArray<TranslationWarning>;
1003
1070
  }
1004
- declare function translateDomainToParams(binding: TranslationBinding, signature: FactorySignature, presentation?: PresentationOverlay): TranslationResult;
1071
+ declare function translateDomainToParams(binding: TranslationBinding, signature: FactorySignature, presentation?: PresentationOverlay, ruleOverlay?: RuleOverlay, traitOverlay?: TraitOverlay, catalog?: ReadonlyArray<FactorySignature>): TranslationResult;
1005
1072
 
1006
1073
  /**
1007
1074
  * Structural diff between two `FactoryCallSite[]` lists. Pure typed,
@@ -1329,4 +1396,4 @@ declare function generateDomainLanguageReference(): string;
1329
1396
  */
1330
1397
  declare function applyMutation(doc: DomainDocument, mut: DomainMutation): DomainDocument;
1331
1398
 
1332
- export { type ASTNode, type CallSiteDiff, type ComparisonCondition, type ComparisonOperator, type DomainBehavior, type DomainChunk, type DomainDocument, type DomainEffect, type DomainEntity, type DomainField, type DomainFieldDefault, type DomainFieldItems, type DomainFieldType, type DomainGuard, type DomainMutation, type DomainPage, type DomainPageAction, type DomainPageSection, type DomainRelationship, type DomainTick, type DomainToSchemaResult, type DomainTransition, EFFECT_REGISTRY, type EffectMapping, type EffectType, EntityPersistence, FIELD_TYPE_REGISTRY, type FactoryCallSite, type FactoryCallSiteParams, type FactoryEntitySignature, type FactoryPageSignature, type FactoryParamValue, type FactorySignature, type FactorySignatureCatalog, type FactorySignatureEntityField, type FactoryTraitSignature, type FieldCheckCondition, type FieldReference, type FieldTypeMapping, GUARD_REGISTRY, type GuardCondition, type GuardMapping, KEYWORDS, Lexer, type LogicalCondition, type LogicalOperator, MULTI_WORD_KEYWORDS, type MappingStore, type MergeResult, type ParseError, type ParseResult, type PresentationNavItem, type PresentationOverlay, type RelationshipType, type SchemaFieldType, type SchemaToDomainResult, type SectionMapping, type SourceLocation, type SourceRange, type Token, TokenType, TraitScope, type TranslationBinding, type TranslationResult, type TranslationWarning, type UserCheckCondition, applyMutation, applySectionUpdate, computeSchemaHash, convertDomainToSchema, convertEntitiesToDomain, convertPagesToDomain, convertSchemaToDomain, convertTraitsToDomain, createMappingStore, deleteSection, detectChanges, diffFactoryCalls, domainKeywordToSchemaType, findMapping, findMappingByPath, findMappingsByType, formatBehaviorToDomain, formatBehaviorToSchema, formatDomainGuardToSchema, formatEntityToDomain, formatEntityToSchema, formatGuardConditionToDomain, formatGuardToDomain, formatGuardToSchema, formatMergeSummary, formatPageToDomain, formatPageToSchema, formatSchemaEntityToDomain, formatSchemaGuardToDomain, formatSchemaPageToDomain, formatSchemaTraitToDomain, generateDomainLanguageReference, generateSectionId, getEffectMapping, getFieldTypeMapping, getGuardMapping, getRegisteredEffects, getRegisteredFieldTypes, getRegisteredGuards, getRegistryStats, getSchemaPath, hasSchemaChanged, isEffectRegistered, isFieldTypeRegistered, isGuardRegistered, mergeDomainChunks, parseBehavior, parseDomainEffect, parseDomainEffects, parseDomainGuard, parseEntity, parseGuard, parsePage, parseSectionId, removeMapping, resolveConflict, schemaEntityToDomainEntity, schemaPageToDomainPage, schemaTraitToDomainBehavior, schemaTypeToDomainKeyword, tokenize, translateDomainToParams, updateMappingRange, updateSchemaHash, upsertMapping, validateDomainChunk };
1399
+ export { type ASTNode, type CallSiteDiff, type ComparisonCondition, type ComparisonOperator, type DomainBehavior, type DomainChunk, type DomainDocument, type DomainEffect, type DomainEntity, type DomainField, type DomainFieldDefault, type DomainFieldItems, type DomainFieldType, type DomainGuard, type DomainMutation, type DomainPage, type DomainPageAction, type DomainPageSection, type DomainRelationship, type DomainRuleOverlayEntry, type DomainTick, type DomainToSchemaResult, type DomainTransition, EFFECT_REGISTRY, type EffectMapping, type EffectType, EntityPersistence, FIELD_TYPE_REGISTRY, type FactoryCallSite, type FactoryCallSiteParams, type FactoryEntitySignature, type FactoryPageSignature, type FactoryParamValue, type FactorySignature, type FactorySignatureCatalog, type FactorySignatureEntityField, type FactoryTraitSignature, type FieldCheckCondition, type FieldReference, type FieldTypeMapping, GUARD_REGISTRY, type GuardCondition, type GuardMapping, KEYWORDS, Lexer, type LogicalCondition, type LogicalOperator, MULTI_WORD_KEYWORDS, type MappingStore, type MergeResult, type OwnershipOverlayEntry, type ParseError, type ParseResult, type PresentationNavItem, type PresentationOverlay, type RelationshipType, type RuleOverlay, type SchemaFieldType, type SchemaToDomainResult, type SectionMapping, type SourceLocation, type SourceRange, type Token, TokenType, type TraitOverlay, type TraitOverlayEntry, type TraitOverlayListener, TraitScope, type TranslationBinding, type TranslationResult, type TranslationWarning, type UserCheckCondition, applyMutation, applySectionUpdate, computeSchemaHash, convertDomainToSchema, convertEntitiesToDomain, convertPagesToDomain, convertSchemaToDomain, convertTraitsToDomain, createMappingStore, deleteSection, detectChanges, diffFactoryCalls, domainKeywordToSchemaType, findMapping, findMappingByPath, findMappingsByType, formatBehaviorToDomain, formatBehaviorToSchema, formatDomainGuardToSchema, formatEntityToDomain, formatEntityToSchema, formatGuardConditionToDomain, formatGuardToDomain, formatGuardToSchema, formatMergeSummary, formatPageToDomain, formatPageToSchema, formatSchemaEntityToDomain, formatSchemaGuardToDomain, formatSchemaPageToDomain, formatSchemaTraitToDomain, generateDomainLanguageReference, generateSectionId, getEffectMapping, getFieldTypeMapping, getGuardMapping, getRegisteredEffects, getRegisteredFieldTypes, getRegisteredGuards, getRegistryStats, getSchemaPath, hasSchemaChanged, isEffectRegistered, isFieldTypeRegistered, isGuardRegistered, mergeDomainChunks, parseBehavior, parseDomainEffect, parseDomainEffects, parseDomainGuard, parseEntity, parseGuard, parsePage, parseSectionId, removeMapping, resolveConflict, schemaEntityToDomainEntity, schemaPageToDomainPage, schemaTraitToDomainBehavior, schemaTypeToDomainKeyword, tokenize, translateDomainToParams, updateMappingRange, updateSchemaHash, upsertMapping, validateDomainChunk };
@@ -6430,7 +6430,7 @@ var UI_SLOTS2 = [
6430
6430
  ];
6431
6431
 
6432
6432
  // src/domain-language/sync/translate-domain-to-params.ts
6433
- function translateDomainToParams(binding, signature, presentation) {
6433
+ function translateDomainToParams(binding, signature, presentation, ruleOverlay, traitOverlay, catalog) {
6434
6434
  const warnings = [];
6435
6435
  const params = {};
6436
6436
  applyEntityName(binding.entity, signature, params);
@@ -6438,6 +6438,8 @@ function translateDomainToParams(binding, signature, presentation) {
6438
6438
  applyPersistence(binding.entity, signature, params, warnings);
6439
6439
  applyPagePaths(binding.pages ?? [], signature, params, warnings);
6440
6440
  applyPresentation(presentation, signature, params, warnings);
6441
+ applyTraitOverlay(traitOverlay, signature, params, warnings);
6442
+ applyRuleOverlay(ruleOverlay, signature, binding, catalog, params, warnings);
6441
6443
  return {
6442
6444
  callSite: {
6443
6445
  organism: signature.organism,
@@ -6526,6 +6528,165 @@ function applyPresentation(overlay, signature, params, warnings) {
6526
6528
  }
6527
6529
  };
6528
6530
  }
6531
+ function applyTraitOverlay(overlay, signature, params, warnings) {
6532
+ if (!overlay) return;
6533
+ const traitsByName = new Map(signature.traits.map((t) => [t.name, t]));
6534
+ for (const [traitName, entry] of Object.entries(overlay)) {
6535
+ const trait = traitsByName.get(traitName);
6536
+ if (!trait) {
6537
+ warnings.push({
6538
+ field: `traitOverlay.${traitName}`,
6539
+ reason: `factory signature has no trait named "${traitName}"`
6540
+ });
6541
+ continue;
6542
+ }
6543
+ mergeTraitOverride(traitName, entry, trait, params, warnings);
6544
+ }
6545
+ }
6546
+ function mergeTraitOverride(traitName, entry, trait, params, warnings) {
6547
+ const advertised = new Set(trait.overridableConfigKeys);
6548
+ const existing = params.traitOverrides?.[traitName] ?? {};
6549
+ const existingConfig = existing.config ?? {};
6550
+ const mergedConfig = { ...existingConfig };
6551
+ if (entry.config) {
6552
+ for (const [k, v] of Object.entries(entry.config)) {
6553
+ if (!advertised.has(k)) {
6554
+ warnings.push({
6555
+ field: `traitOverlay.${traitName}.config.${k}`,
6556
+ reason: `trait does not advertise config key "${k}" (overridableConfigKeys: [${trait.overridableConfigKeys.join(", ")}])`
6557
+ });
6558
+ continue;
6559
+ }
6560
+ mergedConfig[k] = v;
6561
+ }
6562
+ }
6563
+ const next = {
6564
+ ...existing,
6565
+ ...Object.keys(mergedConfig).length > 0 ? { config: mergedConfig } : {}
6566
+ };
6567
+ params.traitOverrides = {
6568
+ ...params.traitOverrides,
6569
+ [traitName]: next
6570
+ };
6571
+ }
6572
+ function applyRuleOverlay(overlay, signature, binding, catalog, params, warnings) {
6573
+ if (!overlay) return;
6574
+ for (const rule of overlay.rules) {
6575
+ if (!ruleAppliesToBinding(rule, binding)) continue;
6576
+ if (!catalog) {
6577
+ warnings.push({
6578
+ field: `ruleOverlay.rules.${rule.id}`,
6579
+ reason: "rule overlay supplied without a catalog \u2014 capability lookup requires one"
6580
+ });
6581
+ continue;
6582
+ }
6583
+ const match = findTraitByCapability(catalog, rule.capability);
6584
+ if (!match) {
6585
+ warnings.push({
6586
+ field: `ruleOverlay.rules.${rule.id}`,
6587
+ reason: `no trait in the catalog advertises capability "${rule.capability}"`
6588
+ });
6589
+ continue;
6590
+ }
6591
+ appendRuleExtraTrait(rule, match, binding, params);
6592
+ if (rule.config) {
6593
+ threadRuleConfig(rule, match.trait, params, warnings);
6594
+ }
6595
+ }
6596
+ if (overlay.ownership) {
6597
+ for (const entry of overlay.ownership) {
6598
+ if (entry.entity !== binding.entity.name) continue;
6599
+ applyOwnership(entry, params, signature, catalog, warnings);
6600
+ }
6601
+ }
6602
+ }
6603
+ function ruleAppliesToBinding(rule, binding) {
6604
+ if (rule.appliesTo.length === 0) return true;
6605
+ return rule.appliesTo.includes(binding.entity.name);
6606
+ }
6607
+ function findTraitByCapability(catalog, capability) {
6608
+ for (const sig of catalog) {
6609
+ for (const trait of sig.traits) {
6610
+ if (trait.capabilities.includes(capability)) {
6611
+ return { signature: sig, trait };
6612
+ }
6613
+ }
6614
+ }
6615
+ return void 0;
6616
+ }
6617
+ function appendRuleExtraTrait(rule, match, binding, params) {
6618
+ const fromPath = `std/behaviors/${match.signature.organism}`;
6619
+ const alias = organismToAlias(match.signature.organism);
6620
+ const ref2 = {
6621
+ from: fromPath,
6622
+ ref: `${alias}.traits.${match.trait.name}`,
6623
+ linkedEntity: binding.entity.name
6624
+ };
6625
+ const existing = params.extraTraits ?? [];
6626
+ params.extraTraits = [...existing, ref2];
6627
+ }
6628
+ function organismToAlias(organism) {
6629
+ const trimmed = organism.startsWith("std-") ? organism.slice(4) : organism;
6630
+ return trimmed.split("-").filter((s) => s.length > 0).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
6631
+ }
6632
+ function threadRuleConfig(rule, trait, params, warnings) {
6633
+ if (!rule.config) return;
6634
+ const advertised = new Set(trait.overridableConfigKeys);
6635
+ const existing = params.traitOverrides?.[trait.name] ?? {};
6636
+ const existingConfig = existing.config ?? {};
6637
+ const merged = { ...existingConfig };
6638
+ for (const [k, v] of Object.entries(rule.config)) {
6639
+ if (!advertised.has(k)) {
6640
+ warnings.push({
6641
+ field: `ruleOverlay.rules.${rule.id}.config.${k}`,
6642
+ reason: `trait "${trait.name}" does not advertise config key "${k}"`
6643
+ });
6644
+ continue;
6645
+ }
6646
+ merged[k] = v;
6647
+ }
6648
+ if (Object.keys(merged).length > 0) {
6649
+ params.traitOverrides = {
6650
+ ...params.traitOverrides,
6651
+ [trait.name]: { ...existing, config: merged }
6652
+ };
6653
+ }
6654
+ }
6655
+ function applyOwnership(entry, params, signature, catalog, warnings) {
6656
+ const local = signature.traits.find(
6657
+ (t) => t.overridableConfigKeys.includes("ownerField")
6658
+ );
6659
+ if (local) {
6660
+ writeOwnerField(local.name, entry.ownerField, params);
6661
+ return;
6662
+ }
6663
+ if (catalog) {
6664
+ for (const sig of catalog) {
6665
+ const trait = sig.traits.find(
6666
+ (t) => t.overridableConfigKeys.includes("ownerField")
6667
+ );
6668
+ if (trait) {
6669
+ writeOwnerField(trait.name, entry.ownerField, params);
6670
+ return;
6671
+ }
6672
+ }
6673
+ }
6674
+ warnings.push({
6675
+ field: `ruleOverlay.ownership.${entry.entity}`,
6676
+ reason: "no trait in the bound signature or catalog advertises an `ownerField` config knob"
6677
+ });
6678
+ }
6679
+ function writeOwnerField(traitName, ownerField, params) {
6680
+ const existing = params.traitOverrides?.[traitName] ?? {};
6681
+ const existingConfig = existing.config ?? {};
6682
+ params.traitOverrides = {
6683
+ ...params.traitOverrides,
6684
+ [traitName]: {
6685
+ ...existing,
6686
+ config: { ...existingConfig, ownerField }
6687
+ }
6688
+ };
6689
+ }
6529
6690
  function lowerField(f) {
6530
6691
  const schemaType = DOMAIN_TO_SCHEMA_FIELD_TYPE[f.fieldType];
6531
6692
  if (!schemaType) return void 0;