@salsita-ai/sdk 0.50.0-develop.da56a0c6c3 → 0.50.0-develop.dfac20c66b

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.
Files changed (148) hide show
  1. package/README.md +19 -11
  2. package/dist/application-spec/errors/diagnostic-codes.d.ts +6 -0
  3. package/dist/application-spec/errors/diagnostic-codes.js +1 -1
  4. package/dist/application-spec/errors/diagnostic-messages.d.ts +6 -0
  5. package/dist/application-spec/errors/diagnostic-messages.js +1 -1
  6. package/dist/application-spec/generate-application/code/domain-runtime-files.js +1 -1
  7. package/dist/application-spec/generate-application/code/templates/application-types.js +6 -6
  8. package/dist/application-spec/generate-application/code/templates/configurator-domain-code.d.ts +1 -0
  9. package/dist/application-spec/generate-application/code/templates/configurator-domain-code.js +11 -8
  10. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-domain-block.d.ts +3 -1
  11. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-domain-block.js +70 -66
  12. package/dist/application-spec/generate-application/code/templates/domain-spec/generate-phx-globals.js +3 -0
  13. package/dist/application-spec/generate-application/code/templates/domain-spec.js +5 -5
  14. package/dist/application-spec/generate-application/code/templates/domain.js +2 -2
  15. package/dist/application-spec/generate-application/code/templates/global-definition/generate-action-types.d.ts +11 -0
  16. package/dist/application-spec/generate-application/code/templates/global-definition/generate-action-types.js +8 -0
  17. package/dist/application-spec/generate-application/code/templates/global-definition/index.d.ts +1 -0
  18. package/dist/application-spec/generate-application/code/templates/global-definition/index.js +1 -1
  19. package/dist/application-spec/generate-application/code/templates/globals.js +1 -0
  20. package/dist/application-spec/generate-application/code/templates/skills/phoenix-create-configurator-skill.js +3 -1
  21. package/dist/application-spec/generate-application/code/templates/skills/phoenix-feedback-skill.js +39 -16
  22. package/dist/application-spec/generate-application/code/templates/skills/phoenix-review-skill.js +4 -2
  23. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.d.ts +3 -1
  24. package/dist/application-spec/generate-application/code/templates/skills/sdk-content.js +2 -2
  25. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-runtime.d.ts +2 -0
  26. package/dist/application-spec/generate-application/runtime/configurator-runtime/configurator-runtime.js +1 -1
  27. package/dist/application-spec/generate-application/runtime/sections/actions-runtime.d.ts +14 -0
  28. package/dist/application-spec/generate-application/runtime/sections/actions-runtime.js +1 -0
  29. package/dist/application-spec/generate-application/runtime/sections/index.d.ts +1 -0
  30. package/dist/application-spec/generate-application/runtime/sections/index.js +1 -1
  31. package/dist/application-spec/parse-application-files/categorize/categorize-files.d.ts +3 -1
  32. package/dist/application-spec/parse-application-files/categorize/categorize-files.js +1 -1
  33. package/dist/application-spec/parse-application-files/merge/index.d.ts +1 -0
  34. package/dist/application-spec/parse-application-files/merge/index.js +1 -1
  35. package/dist/application-spec/parse-application-files/merge/merged-actions.d.ts +11 -0
  36. package/dist/application-spec/parse-application-files/merge/merged-actions.js +1 -0
  37. package/dist/application-spec/parse-application-files/merge/merged-spec.d.ts +2 -0
  38. package/dist/application-spec/parse-application-files/merge/merged-spec.js +1 -1
  39. package/dist/application-spec/parse-application-files/raw-spec/index.d.ts +1 -0
  40. package/dist/application-spec/parse-application-files/raw-spec/index.js +1 -1
  41. package/dist/application-spec/parse-application-files/raw-spec/raw-actions.d.ts +18 -0
  42. package/dist/application-spec/parse-application-files/raw-spec/raw-actions.js +1 -0
  43. package/dist/application-spec/parse-application-files/raw-spec/raw-assistant.d.ts +14 -2
  44. package/dist/application-spec/parse-application-files/raw-spec/raw-assistant.js +1 -1
  45. package/dist/application-spec/parse-application-files/raw-spec/raw-spec-file.d.ts +2 -0
  46. package/dist/application-spec/parse-application-files/raw-spec/raw-spec-file.js +1 -1
  47. package/dist/application-spec/parse-application-files/resolve/resolve-import-modules.js +1 -1
  48. package/dist/application-spec/parse-application-files/spec/application/application-spec.js +1 -1
  49. package/dist/application-spec/parse-application-files/spec/application/configurator-spec/configurator-spec.d.ts +4 -2
  50. package/dist/application-spec/parse-application-files/spec/application/configurator-spec/configurator-spec.js +1 -1
  51. package/dist/application-spec/parse-application-files/spec/common/index.d.ts +1 -0
  52. package/dist/application-spec/parse-application-files/spec/common/index.js +1 -1
  53. package/dist/application-spec/parse-application-files/spec/common/schema-ref-resolver.d.ts +23 -0
  54. package/dist/application-spec/parse-application-files/spec/common/schema-ref-resolver.js +1 -0
  55. package/dist/application-spec/parse-application-files/spec/model/names/action-name.d.ts +10 -0
  56. package/dist/application-spec/parse-application-files/spec/model/names/action-name.js +1 -0
  57. package/dist/application-spec/parse-application-files/spec/model/names/index.d.ts +1 -0
  58. package/dist/application-spec/parse-application-files/spec/model/names/index.js +1 -1
  59. package/dist/application-spec/parse-application-files/spec/sections/actions.d.ts +35 -0
  60. package/dist/application-spec/parse-application-files/spec/sections/actions.js +1 -0
  61. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-field-type.d.ts +3 -14
  62. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-field-type.js +1 -1
  63. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-schema.d.ts +12 -3
  64. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant-schema.js +1 -1
  65. package/dist/application-spec/parse-application-files/spec/sections/assistant/assistant.d.ts +5 -3
  66. package/dist/application-spec/parse-application-files/spec/sections/index.d.ts +1 -0
  67. package/dist/application-spec/parse-application-files/spec/sections/index.js +1 -1
  68. package/dist/configurator/application-runtime/extensions/configurator-extension-systems.d.ts +2 -1
  69. package/dist/configurator/application-runtime/extensions/configurator-extension-systems.js +1 -1
  70. package/dist/configurator/application-runtime/extensions/selectors.d.ts +2 -1
  71. package/dist/configurator/application-runtime/extensions/selectors.js +1 -1
  72. package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.d.ts +35 -0
  73. package/dist/configurator/application-runtime/extensions/systems/assistant-system/assistant-system.js +1 -0
  74. package/dist/configurator/{assistant → application-runtime/extensions/systems/assistant-system}/browser-details.d.ts +1 -1
  75. package/dist/configurator/application-runtime/extensions/systems/assistant-system/browser-details.js +1 -0
  76. package/dist/configurator/{assistant → application-runtime/extensions/systems/assistant-system}/graphql-tools.d.ts +13 -14
  77. package/dist/configurator/application-runtime/extensions/systems/assistant-system/graphql-tools.js +1 -0
  78. package/dist/configurator/application-runtime/extensions/systems/graphql-system/graphql-system.js +1 -1
  79. package/dist/configurator/application-runtime/extensions/systems/index.d.ts +1 -0
  80. package/dist/configurator/application-runtime/extensions/systems/index.js +1 -1
  81. package/dist/configurator/assistant/use-assistant-chat.js +1 -1
  82. package/dist/docs/index.json +12 -2
  83. package/dist/docs/other-features/domain-actions.mdx +418 -0
  84. package/dist/docs/phoenix/admin.mdx +2 -2
  85. package/dist/docs/phoenix/best-practices.mdx +1 -0
  86. package/dist/docs/phoenix/finalization.mdx +1 -1
  87. package/dist/docs/phoenix/integration/headless-mode-external.mdx +5 -5
  88. package/dist/docs/phoenix/integration/widget-mode-external.mdx +5 -5
  89. package/dist/docs/phoenix/phoenix-cli.mdx +59 -19
  90. package/dist/docs/phoenix/project-structure.mdx +4 -1
  91. package/dist/docs/phoenix/sdk-builder-workflow.mdx +5 -4
  92. package/dist/domain/actions/action-factory.d.ts +10 -0
  93. package/dist/domain/actions/action-factory.js +1 -0
  94. package/dist/domain/actions/prepare-action-implementations.d.ts +15 -0
  95. package/dist/domain/actions/prepare-action-implementations.js +5 -0
  96. package/dist/domain/application/application-config.d.ts +3 -1
  97. package/dist/domain/application/assistant-mutations.d.ts +15 -14
  98. package/dist/domain/application/assistant-mutations.js +1 -1
  99. package/dist/domain/core/action.d.ts +67 -0
  100. package/dist/domain/core/action.js +1 -0
  101. package/dist/domain/core/domain-factory.d.ts +4 -0
  102. package/dist/domain/core/index.d.ts +1 -0
  103. package/dist/domain/domain-builder.d.ts +7 -0
  104. package/dist/domain/domain-builder.js +1 -1
  105. package/dist/domain/domain-context/action-system/action-system.d.ts +40 -0
  106. package/dist/domain/domain-context/action-system/action-system.js +1 -0
  107. package/dist/domain/domain-context/domain-context-systems.d.ts +5 -2
  108. package/dist/domain/domain-context/index.d.ts +1 -0
  109. package/dist/domain/domain-context/index.js +1 -1
  110. package/dist/domain/domain-runtime/domain-context/domain-context.js +1 -1
  111. package/dist/domain/domain-runtime/domain-context/selectors.d.ts +4 -0
  112. package/dist/domain/domain-runtime/domain-context/selectors.js +1 -1
  113. package/dist/domain/domain-runtime/domain-runtime.d.ts +12 -0
  114. package/dist/domain/domain-runtime/spec/initialize.js +1 -1
  115. package/dist/domain/domain-runtime/spec/types.d.ts +15 -1
  116. package/dist/domain/index.d.ts +2 -0
  117. package/dist/domain/index.js +1 -1
  118. package/dist/domain/mocks/create-mock-domain-runtime.d.ts +6 -0
  119. package/dist/editor/domain-editors/DomainSpecContext.js +1 -1
  120. package/dist/editor/domain-editors/apply-spec-update.js +1 -1
  121. package/dist/editor/domain-editors/use-implementation-files.d.ts +7 -3
  122. package/dist/editor/domain-editors/use-implementation-files.js +1 -1
  123. package/dist/phoenix/application-spec/generate-assistant-prompt.d.ts +2 -2
  124. package/dist/phoenix/application-spec/generate-assistant-prompt.js +1 -1
  125. package/dist/phoenix/cli.js +1 -1
  126. package/dist/phoenix/commands/build.d.ts +5 -0
  127. package/dist/phoenix/commands/build.js +1 -1
  128. package/dist/phoenix/commands/feedback.d.ts +2 -1
  129. package/dist/phoenix/commands/feedback.js +1 -1
  130. package/dist/phoenix/commands/login.d.ts +24 -6
  131. package/dist/phoenix/commands/login.js +2 -2
  132. package/dist/phoenix/services/index.d.ts +1 -0
  133. package/dist/phoenix/services/index.js +1 -1
  134. package/dist/phoenix/services/phx-banner-plugin.d.ts +32 -0
  135. package/dist/phoenix/services/phx-banner-plugin.js +1 -0
  136. package/dist/phoenix/services/phx-licenses-plugin.d.ts +55 -0
  137. package/dist/phoenix/services/phx-licenses-plugin.js +8 -0
  138. package/dist/phoenix/services/vite-config.d.ts +2 -0
  139. package/dist/phoenix/services/vite-config.js +1 -1
  140. package/dist/phoenix/utils/index.d.ts +1 -0
  141. package/dist/phoenix/utils/index.js +1 -1
  142. package/dist/phoenix/utils/read-git-commit.d.ts +14 -0
  143. package/dist/phoenix/utils/read-git-commit.js +1 -0
  144. package/dist/react-sdk/application-runtime/runtime/create-application-runtime.d.ts +12 -0
  145. package/dist/react-sdk/domain-context/common-hooks/use-domain-context.d.ts +3 -0
  146. package/package.json +3 -3
  147. package/dist/configurator/assistant/browser-details.js +0 -1
  148. package/dist/configurator/assistant/graphql-tools.js +0 -1
@@ -1,87 +1,90 @@
1
- import{skipApplicationTypeImports as e}from"../../common/index.js";import{generateComponentOpticsCode as n}from"./generate-component-optics.js";import{generateDefaultsBlock as t}from"./generate-defaults.js";import{generateInvariantsBlock as a}from"./generate-invariants.js";import{generateRelationExpressionsCode as i}from"./generate-relation-expressions.js";import{generateStaticValueCode as o}from"./generate-static-value-code.js";import{generateValueExpressionsCode as s}from"./generate-value-expressions.js";let r="@salsita-ai/sdk/domain",l=(e,n,t)=>{let a=[],i=[];for(let o of e.modelVersion.entitySchemas){let e=JSON.stringify(o.shapeSchema,null,2);a.push(`${t}const ${o.entityType} = new DomainEntityReflection<${n}${o.entityType}>('${o.entityType}', [${e}])`),i.push(String(o.entityType))}return{entityDecls:a.join("\n"),entityNames:i}};export const generateDomainBlock=m=>{let{domainSpec:$,invariants:p,typePrefix:d,versionNsPrefix:c,isAdmin:u,modelVersionsExportName:y,relationExpressionsExportName:h,componentOpticsExportName:f,valueExpressionsExportName:E,createRecipeExportName:D,imports:R,registerApplicationTypeImports:g=e}=m;R.addImport(r,"$DomainEntityReflection"),R.addImport(r,"DomainBuilder"),R.addImport(r,"DomainComponentOpticBuilder"),R.addImport(r,"DomainEntityReflection"),R.addImport(r,"EnhancedAliasReflection"),R.addImport(r,"InvariantBuilder"),R.addImport(r,"RawAliasReflection"),R.addImport(r,"SchemaReflection"),R.addImport(r,"createCustomExpressionFactory"),R.addImport(r,"createCustomInvariantFactory"),u&&(R.addImport(r,"commonAdminCustomExpressions"),R.addImport(r,"commonAdminViolationExpressions"),R.addImport(r,"createMapPublishedRevisionDataHandlerFactory"),R.addImport(r,"createMapPublishedChunkedDataHandlerFactory"),R.addImport(r,"createDataRowValidatorHandler"),R.addImport(r,"createSheetValidatorHandler")),R.addTypeImport(r,"SchemaOfObject");let{entityTypes:S,entitySchemas:v}=$.latestModel,x=[...$.latestModel.aliases],j=x.map(([e])=>String(e)),C=j.includes("RootEntity")?"RootEntity":"AnyDomainEntity",{resolvedVersions:I}=$,M=I.latestVersion,A=d?`${d}.`:"",B=new Map([...$.expressions.constants].map(([e,n])=>[String(e),n])),w=(e,n)=>{let t=[...B.get(n)?.keys()??[]],a=t.length>0?`, ${t.map(e=>`'${e}'`).join(" | ")}`:"";return`${e}<${A}$${n}${a}>`},b=e=>{let n=B.get(e);if(!n)return"{}";let t=[...n].map(([e,n])=>{let t=o(n,R).replaceAll("\n","\n ");return` ${e}: ${t},`});return`{
1
+ import{skipApplicationTypeImports as e}from"../../common/index.js";import{generateComponentOpticsCode as n}from"./generate-component-optics.js";import{generateDefaultsBlock as t}from"./generate-defaults.js";import{generateInvariantsBlock as i}from"./generate-invariants.js";import{generateRelationExpressionsCode as a}from"./generate-relation-expressions.js";import{generateStaticValueCode as o}from"./generate-static-value-code.js";import{generateValueExpressionsCode as s}from"./generate-value-expressions.js";let r="@salsita-ai/sdk/domain",m=(e,n,t)=>{let i=[],a=[];for(let o of e.modelVersion.entitySchemas){let e=JSON.stringify(o.shapeSchema,null,2);i.push(`${t}const ${o.entityType} = new DomainEntityReflection<${n}${o.entityType}>('${o.entityType}', [${e}])`),a.push(String(o.entityType))}return{entityDecls:i.join("\n"),entityNames:a}};export const generateDomainBlock=l=>{let{domainSpec:$,invariants:p,actions:c,typePrefix:d,versionNsPrefix:u,isAdmin:y,modelVersionsExportName:h,relationExpressionsExportName:f,componentOpticsExportName:D,valueExpressionsExportName:E,createRecipeExportName:S,imports:R,registerApplicationTypeImports:g=e}=l;R.addImport(r,"$DomainEntityReflection"),R.addImport(r,"DomainBuilder"),R.addImport(r,"DomainComponentOpticBuilder"),R.addImport(r,"DomainEntityReflection"),R.addImport(r,"EnhancedAliasReflection"),R.addImport(r,"InvariantBuilder"),R.addImport(r,"RawAliasReflection"),R.addImport(r,"SchemaReflection"),R.addImport(r,"createCustomExpressionFactory"),R.addImport(r,"createCustomInvariantFactory"),y&&(R.addImport(r,"commonAdminCustomExpressions"),R.addImport(r,"commonAdminViolationExpressions"),R.addImport(r,"createMapPublishedRevisionDataHandlerFactory"),R.addImport(r,"createMapPublishedChunkedDataHandlerFactory"),R.addImport(r,"createDataRowValidatorHandler"),R.addImport(r,"createSheetValidatorHandler")),R.addTypeImport(r,"SchemaOfObject"),c&&(R.addImport(r,"createActionFactory"),R.addTypeImport(r,"ActionDefinition"));let{entityTypes:v,entitySchemas:x}=$.latestModel,A=[...$.latestModel.aliases],j=A.map(([e])=>String(e)),C=j.includes("RootEntity")?"RootEntity":"AnyDomainEntity",{resolvedVersions:I}=$,M=I.latestVersion,w=d?`${d}.`:"",B=new Map([...$.expressions.constants].map(([e,n])=>[String(e),n])),b=(e,n)=>{let t=[...B.get(n)?.keys()??[]],i=t.length>0?`, ${t.map(e=>`'${e}'`).join(" | ")}`:"";return`${e}<${w}$${n}${i}>`},P=e=>{let n=B.get(e);if(!n)return"{}";let t=[...n].map(([e,n])=>{let t=o(n,R).replaceAll("\n","\n ");return` ${e}: ${t},`});return`{
2
2
  ${t.join("\n")}
3
- }`},P=v.map(e=>{let n=JSON.stringify(e.shapeSchema,null,2);return` const ${e.entityType} = new DomainEntityReflection<${A}${e.entityType}>('${e.entityType}', [${n}])`}),k=x.map(([e,n])=>{let t=n.map(String).join(", ");return` const ${e} = new RawAliasReflection<${A}${e}>('${e}', [${t}])`}),H=[...$.latestModel.commonTypes],F=H.map(([e])=>String(e)),O=I.versionedModels.filter(e=>!e.isLatest).map(e=>`${c}${e.version}`);g(R,[...u?["Admin",...O]:[...S.map(String),...j,...F,...S.map(e=>`$${String(e)}`),...j.map(e=>`$${e}`),"Aliases","$Map",...O],"PublishedData","SessionData","FrontendData",...u?[]:["BackendData"]]);let V=H.map(([e,n])=>{let t=JSON.stringify(n.runtimeSchema,null,2);return n.schema.enum?.length&&n.schema.enum.every(e=>"string"==typeof e)?` const ${e}: EnumLike<${A}${e}> = new EnumReflection('${e}', ${t}) as EnumLike<${A}${e}>`:` const ${e}: SchemaReflection<${A}${e}> = new SchemaReflection('${e}', ${t})`}),T=[...$.latestModel.shapes],J=T.map(([e,n])=>{let t=JSON.stringify(n.runtimeSchema,null,2);return` const ${e}Shape = new SchemaReflection('${e}Shape', ${t})`}),N=T.map(([e])=>`${e}Shape`),L=j.map(e=>` ${e}: ${e}.types,`).join("\n"),_=j.map(e=>` ${e},`).join("\n"),z=F.map(e=>` ${e},`).join("\n"),G=N.map(e=>` ${e},`).join("\n"),q=S.map(e=>` ${e},`).join("\n"),K=[];for(let[e,n]of $.expressions.expressions)n.size>0&&K.push(` const ${e}Expressions = ${JSON.stringify([...n.keys()])}`);let Q=S.map(e=>{let n=$.expressions.entityExpressions.get(e),t=(n?.shapeGroups??[]).map(e=>`${e}Expressions`),a=t.length>0?t.map(e=>`...${e}`).join(", "):"",i=w("$DomainEntityReflection",String(e));return` const $${e}: ${i} = new ${i}('${e}', [${a}], ${b(String(e))})`}).join("\n"),U=S.map(e=>` ${e}: $${e},`).join("\n"),W=x.map(([e,n])=>{let t=n.map(e=>JSON.stringify(String(e))).join(", "),a=w("EnhancedAliasReflection",String(e));return` const $${e}: ${a} = new ${a}('$${e}', [${t}], ${b(String(e))})`}).join("\n"),X=[...S.map(String),...j].map(e=>` $${e},`).join("\n"),Y=[],Z=[];for(let e of I.versionedModels)if(e.isLatest)Y.push(` ${e.version}: entities,`),Z.push(` readonly ${e.version}: {
4
- ${S.map(e=>` readonly ${String(e)}: DomainEntityReflection<${A}${String(e)}>`).join("\n")}
5
- }`);else{let n=`${c}${e.version}.`,{entityDecls:t,entityNames:a}=l(e,n," "),i=a.map(e=>` ${e},`).join("\n");Y.push(` ${e.version}: (() => {
3
+ }`},k=x.map(e=>{let n=JSON.stringify(e.shapeSchema,null,2);return` const ${e.entityType} = new DomainEntityReflection<${w}${e.entityType}>('${e.entityType}', [${n}])`}),F=A.map(([e,n])=>{let t=n.map(String).join(", ");return` const ${e} = new RawAliasReflection<${w}${e}>('${e}', [${t}])`}),H=[...$.latestModel.commonTypes],V=H.map(([e])=>String(e)),O=I.versionedModels.filter(e=>!e.isLatest).map(e=>`${u}${e.version}`);g(R,[...y?["Admin",...O]:[...v.map(String),...j,...V,...v.map(e=>`$${String(e)}`),...j.map(e=>`$${e}`),"Aliases","$Map",...O,...c?["ActionTypes","NavigationState","ViewState","ToolState","ExportState"]:[]],"PublishedData","SessionData","FrontendData",...y?[]:["BackendData"]]);let T=H.map(([e,n])=>{let t=JSON.stringify(n.runtimeSchema,null,2);return n.schema.enum?.length&&n.schema.enum.every(e=>"string"==typeof e)?` const ${e}: EnumLike<${w}${e}> = new EnumReflection('${e}', ${t}) as EnumLike<${w}${e}>`:` const ${e}: SchemaReflection<${w}${e}> = new SchemaReflection('${e}', ${t})`}),N=[...$.latestModel.shapes],J=N.map(([e,n])=>{let t=JSON.stringify(n.runtimeSchema,null,2);return` const ${e}Shape = new SchemaReflection('${e}Shape', ${t})`}),L=N.map(([e])=>`${e}Shape`),_=j.map(e=>` ${e}: ${e}.types,`).join("\n"),z=j.map(e=>` ${e},`).join("\n"),G=V.map(e=>` ${e},`).join("\n"),q=L.map(e=>` ${e},`).join("\n"),K=v.map(e=>` ${e},`).join("\n"),Q=[];for(let[e,n]of $.expressions.expressions)n.size>0&&Q.push(` const ${e}Expressions = ${JSON.stringify([...n.keys()])}`);let U=v.map(e=>{let n=$.expressions.entityExpressions.get(e),t=(n?.shapeGroups??[]).map(e=>`${e}Expressions`),i=t.length>0?t.map(e=>`...${e}`).join(", "):"",a=b("$DomainEntityReflection",String(e));return` const $${e}: ${a} = new ${a}('${e}', [${i}], ${P(String(e))})`}).join("\n"),W=v.map(e=>` ${e}: $${e},`).join("\n"),X=A.map(([e,n])=>{let t=n.map(e=>JSON.stringify(String(e))).join(", "),i=b("EnhancedAliasReflection",String(e));return` const $${e}: ${i} = new ${i}('$${e}', [${t}], ${P(String(e))})`}).join("\n"),Y=[...v.map(String),...j].map(e=>` $${e},`).join("\n"),Z=[],ee=[];for(let e of I.versionedModels)if(e.isLatest)Z.push(` ${e.version}: entities,`),ee.push(` readonly ${e.version}: {
4
+ ${v.map(e=>` readonly ${String(e)}: DomainEntityReflection<${w}${String(e)}>`).join("\n")}
5
+ }`);else{let n=`${u}${e.version}.`,{entityDecls:t,entityNames:i}=m(e,n," "),a=i.map(e=>` ${e},`).join("\n");Z.push(` ${e.version}: (() => {
6
6
  ${t}
7
7
  return {
8
- ${i}
8
+ ${a}
9
9
  } as const
10
- })(),`),Z.push(` readonly ${e.version}: {
11
- ${a.map(e=>` readonly ${e}: DomainEntityReflection<${n}${e}>`).join("\n")}
12
- }`)}let ee=u?"adminDomainBuilder":"domainBuilder",en=u?"attachAdminComponent":"attachComponent",et=u?"implementAdminCustomExpressions":"implementCustomExpressions",ea=u?"implementCustomAdminInvariants":"implementCustomInvariants",ei=u?"adminInvariantBuilder":"invariantBuilder",eo=u?"adminModel":"model",es=u?"adminEnhancedModel":"enhancedModel",er=u?"implementAdminRelation":"implementRelation",el=u?"__adminDomain":"__configuratorDomain",em=`${A}AnyDomainEntity, ${A}RootEntity, ${A}$Map, PublishedData, SessionData, FrontendData, ${A}Aliases`,e$=`<${em}>`,ep=a(p,em,R),ed=(e,n)=>e===n?e:`${e}: ${n}`,ec=[...$.expressions.expressions.values()].some(e=>[...e.values()].some(e=>"relation"===e.implementation.kind));ec&&R.addImport(r,"createRelationFactory");let eu=ec?`
13
- const ${er} = createRelationFactory${e$}(aliases)
14
-
15
- const relationExpressions = ${i($.expressions,er)}`:"\n const relationExpressions = {} as const",ey=`
16
- const componentOptics = ${n($.components,R)}`,eh=`
17
- const valueExpressions = ${s($.expressions,R,"implementCustomExpressions",u?{PresetCategory:"commonAdminCustomExpressions.PresetCategory"}:{})}`;R.addImport(r,"RecipeFactoryBuilder");let ef=t($.defaults,R),eE=`
18
- const createRecipe = RecipeFactoryBuilder.forAliases<${A}AnyDomainEntity, ${A}Aliases>(aliases)
10
+ })(),`),ee.push(` readonly ${e.version}: {
11
+ ${i.map(e=>` readonly ${e}: DomainEntityReflection<${n}${e}>`).join("\n")}
12
+ }`)}let en=y?"adminDomainBuilder":"domainBuilder",et=y?"attachAdminComponent":"attachComponent",ei=y?"implementAdminCustomExpressions":"implementCustomExpressions",ea=y?"implementCustomAdminInvariants":"implementCustomInvariants",eo=y?"adminInvariantBuilder":"invariantBuilder",es=y?"adminModel":"model",er=y?"adminEnhancedModel":"enhancedModel",em=y?"implementAdminRelation":"implementRelation",el=y?"__adminDomain":"__configuratorDomain",e$="PublishedData, SessionData, FrontendData",ep=`${w}AnyDomainEntity, ${w}RootEntity, ${w}$Map, ${e$}, ${w}Aliases`,ec=`<${ep}>`,ed=i(p,ep,R),eu=(e,n)=>e===n?e:`${e}: ${n}`,ey=[...$.expressions.expressions.values()].some(e=>[...e.values()].some(e=>"relation"===e.implementation.kind));ey&&R.addImport(r,"createRelationFactory");let eh=ey?`
13
+ const ${em} = createRelationFactory${ec}(aliases)
14
+
15
+ const relationExpressions = ${a($.expressions,em)}`:"\n const relationExpressions = {} as const",ef=`
16
+ const componentOptics = ${n($.components,R)}`,eD=`
17
+ const valueExpressions = ${s($.expressions,R,"implementCustomExpressions",y?{PresetCategory:"commonAdminCustomExpressions.PresetCategory"}:{})}`;R.addImport(r,"RecipeFactoryBuilder");let eE=t($.defaults,R),eS=[...c?.values()??[]].map(e=>({name:String(e.name),...void 0===e.description?{}:{description:e.description},params:e.paramsSchema})),eR=c?`
18
+ const actionDefinitions: readonly ActionDefinition[] = ${JSON.stringify(eS,null,2).replaceAll("\n","\n ")}
19
+
20
+ const implementActions = createActionFactory<${w}AnyDomainEntity, ${w}RootEntity, ${w}$Map, ${e$}, NavigationState, ViewState, ToolState, ExportState, ActionTypes>()`:"",eg=`
21
+ const createRecipe = RecipeFactoryBuilder.forAliases<${w}AnyDomainEntity, ${w}Aliases>(aliases)
19
22
  .forEntities(AnyDomainEntity.reflections)
20
23
  .withDefaults(defaults)
21
- .build()`,eD=[...S.map(e=>` readonly ${String(e)}: DomainEntityReflection<${A}${String(e)}>`),...j.map(e=>` readonly ${e}: RawAliasReflection<${A}${e}>`),...H.map(([e,n])=>{let t=n.schema.enum?.length&&n.schema.enum.every(e=>"string"==typeof e)?"EnumLike":"SchemaReflection";return` readonly ${e}: ${t}<${A}${e}>`}),...N.map(e=>` readonly ${e}: SchemaReflection<unknown>`)].join("\n"),eR=`{
22
- ${eD}
23
- }`,eg=[...S.map(e=>` readonly $${String(e)}: ${w("$DomainEntityReflection",String(e))}`),...j.map(e=>` readonly $${e}: ${w("EnhancedAliasReflection",e)}`)].join("\n"),eS=`{
24
- ${eg}
25
- }`,ev=`{
26
- ${Z.join("\n")}
24
+ .build()`,ev=[...v.map(e=>` readonly ${String(e)}: DomainEntityReflection<${w}${String(e)}>`),...j.map(e=>` readonly ${e}: RawAliasReflection<${w}${e}>`),...H.map(([e,n])=>{let t=n.schema.enum?.length&&n.schema.enum.every(e=>"string"==typeof e)?"EnumLike":"SchemaReflection";return` readonly ${e}: ${t}<${w}${e}>`}),...L.map(e=>` readonly ${e}: SchemaReflection<unknown>`)].join("\n"),ex=`{
25
+ ${ev}
26
+ }`,eA=[...v.map(e=>` readonly $${String(e)}: ${b("$DomainEntityReflection",String(e))}`),...j.map(e=>` readonly $${e}: ${b("EnhancedAliasReflection",e)}`)].join("\n"),ej=`{
27
+ ${eA}
28
+ }`,eC=`{
29
+ ${ee.join("\n")}
27
30
  }`;return`const ${el} = (() => {
28
31
  const modelVersion = ${M}
29
32
 
30
- ${ef}
31
-
32
- ${P.join("\n")}
33
+ ${eE}
33
34
 
34
35
  ${k.join("\n")}
35
36
 
36
- ${V.join("\n")}
37
+ ${F.join("\n")}
38
+
39
+ ${T.join("\n")}
37
40
 
38
41
  ${J.join("\n")}
39
42
 
40
43
  const aliases = {
41
- ${L}
44
+ ${_}
42
45
  } as const
43
46
 
44
47
  const entities = {
45
- ${q}
48
+ ${K}
46
49
  } as const
47
50
 
48
51
  const model = {
49
- ${q}
50
- ${_}
52
+ ${K}
51
53
  ${z}
52
54
  ${G}
55
+ ${q}
53
56
  } as const
54
57
 
55
- ${K.length>0?K.join("\n")+"\n":""}
56
- ${Q}
57
- ${W}
58
- const $entityReflections = {
58
+ ${Q.length>0?Q.join("\n")+"\n":""}
59
59
  ${U}
60
+ ${X}
61
+ const $entityReflections = {
62
+ ${W}
60
63
  }
61
64
 
62
65
  const enhancedModel = {
63
- ${X}
66
+ ${Y}
64
67
  } as const
65
68
 
66
- const implementCustomExpressions = createCustomExpressionFactory${e$}({})
67
- ${eu}
68
- ${eh}
69
+ const implementCustomExpressions = createCustomExpressionFactory${ec}({})
70
+ ${eR}${eh}
71
+ ${eD}
69
72
 
70
73
  const modelVersions = {
71
- ${Y.join("\n")}
74
+ ${Z.join("\n")}
72
75
  } as const
73
- const attachComponent = DomainComponentOpticBuilder.from${e$}(aliases)
74
-
75
- ${ep}
76
- const invariantBuilder = new InvariantBuilder${e$}(aliases)${u?"\n .withInvariants(implementCustomInvariants(commonAdminViolationExpressions))":""}
77
- ${u?`
78
- const createMapPublishedRevisionDataHandler = createMapPublishedRevisionDataHandlerFactory<${A}AnyDomainEntity, ${A}RootEntity, ${A}$Map, PublishedData>()
79
- const createMapPublishedChunkedDataHandler = createMapPublishedChunkedDataHandlerFactory<${A}AnyDomainEntity, ${A}RootEntity, ${A}$Map>()
80
- `:""}${ey}
81
- ${eE}
76
+ const attachComponent = DomainComponentOpticBuilder.from${ec}(aliases)
77
+
78
+ ${ed}
79
+ const invariantBuilder = new InvariantBuilder${ec}(aliases)${y?"\n .withInvariants(implementCustomInvariants(commonAdminViolationExpressions))":""}
80
+ ${y?`
81
+ const createMapPublishedRevisionDataHandler = createMapPublishedRevisionDataHandlerFactory<${w}AnyDomainEntity, ${w}RootEntity, ${w}$Map, PublishedData>()
82
+ const createMapPublishedChunkedDataHandler = createMapPublishedChunkedDataHandlerFactory<${w}AnyDomainEntity, ${w}RootEntity, ${w}$Map>()
83
+ `:""}${ef}
84
+ ${eg}
82
85
 
83
86
  return {
84
- domainBuilder: DomainBuilder.from${e$}(
87
+ domainBuilder: DomainBuilder.from${ec}(
85
88
  entities,
86
89
  aliases,
87
90
  $entityReflections,
@@ -90,13 +93,13 @@ ${eE}
90
93
  PublishedData,
91
94
  SessionData,
92
95
  FrontendData,
93
- ${u?"undefined":"BackendData"},
94
- ${u}
95
- ).withExpressions(valueExpressions),
96
- attachComponent,
96
+ ${y?"undefined":"BackendData"},
97
+ ${y}
98
+ ).withExpressions(valueExpressions)${c?".withActions(actionDefinitions)":""},
99
+ attachComponent,${c?"\n implementActions,":""}
97
100
  implementCustomExpressions,
98
101
  implementCustomInvariants,
99
- invariantBuilder,${u?`
102
+ invariantBuilder,${y?`
100
103
  createMapPublishedRevisionDataHandler,
101
104
  createMapPublishedChunkedDataHandler,`:""}
102
105
  model,
@@ -110,20 +113,21 @@ ${eE}
110
113
  })()
111
114
 
112
115
  const {
113
- ${ed("domainBuilder",ee)},
114
- ${ed("attachComponent",en)},
115
- ${ed("implementCustomExpressions",et)},
116
- ${ed("implementCustomInvariants",ea)},
117
- ${ed("invariantBuilder",ei)},${u?`
116
+ ${eu("domainBuilder",en)},
117
+ ${eu("attachComponent",et)},
118
+ ${eu("implementCustomExpressions",ei)},
119
+ ${eu("implementCustomInvariants",ea)},
120
+ ${eu("invariantBuilder",eo)},${y?`
118
121
  createMapPublishedRevisionDataHandler,
119
- createMapPublishedChunkedDataHandler,`:""}
120
- ${ed("relationExpressions",h)},
121
- ${ed("valueExpressions",E)},
122
- ${ed("componentOptics",f)},
123
- ${ed("createRecipe",D)},
122
+ createMapPublishedChunkedDataHandler,`:`
123
+ implementActions,`}
124
+ ${eu("relationExpressions",f)},
125
+ ${eu("valueExpressions",E)},
126
+ ${eu("componentOptics",D)},
127
+ ${eu("createRecipe",S)},
124
128
  } = ${el}
125
129
 
126
- const ${eo}: ${eR} = ${el}.model
127
- const ${es}: ${eS} = ${el}.enhancedModel
128
- const ${y}: ${ev} = ${el}.modelVersions
129
- export { ${ee}, ${en}, ${et}, ${ea}, ${ei}, ${eo}, ${es}, ${h}, ${E}, ${f}, ${y}, ${D}${u?", createMapPublishedRevisionDataHandler, createMapPublishedChunkedDataHandler, createDataRowValidatorHandler, createSheetValidatorHandler":""} }`};
130
+ const ${es}: ${ex} = ${el}.model
131
+ const ${er}: ${ej} = ${el}.enhancedModel
132
+ const ${h}: ${eC} = ${el}.modelVersions
133
+ export { ${en}, ${et}, ${ei}, ${ea}, ${eo}, ${es}, ${er}, ${f}, ${E}, ${D}, ${h}, ${S}${y?", createMapPublishedRevisionDataHandler, createMapPublishedChunkedDataHandler, createDataRowValidatorHandler, createSheetValidatorHandler":", implementActions"} }`};
@@ -10,6 +10,7 @@ globalThis.phx.domain = {
10
10
  enhancedModel,
11
11
  implementCustomExpressions,
12
12
  implementCustomInvariants,
13
+ implementActions,
13
14
  attachComponent,
14
15
  createRecipe,
15
16
 
@@ -50,6 +51,7 @@ globalThis.phx.applicationTypes = {
50
51
  readonly enhancedModel: typeof enhancedModel
51
52
  readonly implementCustomExpressions: typeof implementCustomExpressions
52
53
  readonly implementCustomInvariants: typeof implementCustomInvariants
54
+ readonly implementActions: typeof implementActions
53
55
  readonly attachComponent: typeof attachComponent
54
56
  readonly createRecipe: typeof createRecipe
55
57
  readonly admin: {
@@ -69,6 +71,7 @@ globalThis.phx.applicationTypes = {
69
71
  enhancedModel,
70
72
  implementCustomExpressions,
71
73
  implementCustomInvariants,
74
+ implementActions,
72
75
  attachComponent,
73
76
  createRecipe,
74
77
 
@@ -1,5 +1,5 @@
1
- import{CodeImports as e,autoHeader as a,skipApplicationTypeImports as i}from"../common/index.js";import{generateApplicationMetadataBlock as o,generateAssistantBlock as n,generateBaseConfiguratorBuilder as t,generateChunksSpec as s,generateDataSchemaConstants as r,generateDataSpec as p,generateDomainBlock as m,generateLocaleCodegen as d,generatePhxGlobalsBlock as c,generateResourcesCodegen as l,generateStateConstants as x}from"./domain-spec/index.js";let u="@salsita-ai/sdk/domain",g="@salsita-ai/sdk/i18n";export const globalDomainSpecPhxBinding={generateBindingBlock:c,generateStateConstants:x,registerApplicationTypeImports:i};export const generateApplicationSpecDomainSpecFile=(i,c=globalDomainSpecPhxBinding)=>{let x=new e,{registerApplicationTypeImports:E}=c,f=m({domainSpec:i.configurator,invariants:i.configurator.invariants,typePrefix:"",versionNsPrefix:"ModelV",isAdmin:!1,modelVersionsExportName:"modelVersions",relationExpressionsExportName:"relationExpressions",componentOpticsExportName:"componentOptics",valueExpressionsExportName:"valueExpressions",createRecipeExportName:"createRecipe",imports:x,registerApplicationTypeImports:E}),S=m({domainSpec:i.admin,invariants:i.admin.invariants,typePrefix:"Admin",versionNsPrefix:"AdminV",isAdmin:!0,modelVersionsExportName:"adminModelVersions",relationExpressionsExportName:"adminRelationExpressions",componentOpticsExportName:"adminComponentOptics",valueExpressionsExportName:"adminValueExpressions",createRecipeExportName:"createAdminRecipe",imports:x,registerApplicationTypeImports:E}),{hasResources:$}=l(i);x.addImport(u,"ConfiguratorBuilder"),x.addImport(u,"EnumReflection"),x.addTypeImport(u,"AssistantManifest"),x.addTypeImport(u,"ChunksSpec"),x.addTypeImport(u,"DataSpec"),x.addTypeImport(u,"EnumLike"),$&&x.addImport(u,"ResourceBuilder"),x.addImport(g,"mergeCatalogs"),x.addImport(g,"sdkCatalog"),x.addImport("@lingui/core","setupI18n");let k=r(i.configurator.dataSchemas,x,E),I=c.generateStateConstants({configuratorStates:i.configurator.states,adminStates:i.admin.states},x,E),N=o(i),{importBlock:v,catalogBlock:h,createI18nExport:A}=d(i.configurator.ui.availableLocales),{preBlock:B,builderBlock:C}=t(i,x,E),y=c.generateBindingBlock();return`${a("domain-spec.ts","Domain builders, model schemas, component optics and expression definitions derived from the spec.")}
2
- ${x.toString()}${v}
1
+ import{CodeImports as e,autoHeader as a,skipApplicationTypeImports as i}from"../common/index.js";import{generateApplicationMetadataBlock as o,generateAssistantBlock as n,generateBaseConfiguratorBuilder as t,generateChunksSpec as s,generateDataSchemaConstants as r,generateDataSpec as p,generateDomainBlock as m,generateLocaleCodegen as d,generatePhxGlobalsBlock as c,generateResourcesCodegen as l,generateStateConstants as u}from"./domain-spec/index.js";let x="@salsita-ai/sdk/domain",g="@salsita-ai/sdk/i18n";export const globalDomainSpecPhxBinding={generateBindingBlock:c,generateStateConstants:u,registerApplicationTypeImports:i};export const generateApplicationSpecDomainSpecFile=(i,c=globalDomainSpecPhxBinding)=>{let u=new e,{registerApplicationTypeImports:f}=c,E=m({domainSpec:i.configurator,invariants:i.configurator.invariants,actions:i.configurator.actions,typePrefix:"",versionNsPrefix:"ModelV",isAdmin:!1,modelVersionsExportName:"modelVersions",relationExpressionsExportName:"relationExpressions",componentOpticsExportName:"componentOptics",valueExpressionsExportName:"valueExpressions",createRecipeExportName:"createRecipe",imports:u,registerApplicationTypeImports:f}),S=m({domainSpec:i.admin,invariants:i.admin.invariants,actions:void 0,typePrefix:"Admin",versionNsPrefix:"AdminV",isAdmin:!0,modelVersionsExportName:"adminModelVersions",relationExpressionsExportName:"adminRelationExpressions",componentOpticsExportName:"adminComponentOptics",valueExpressionsExportName:"adminValueExpressions",createRecipeExportName:"createAdminRecipe",imports:u,registerApplicationTypeImports:f}),{hasResources:$}=l(i);u.addImport(x,"ConfiguratorBuilder"),u.addImport(x,"EnumReflection"),u.addTypeImport(x,"AssistantManifest"),u.addTypeImport(x,"ChunksSpec"),u.addTypeImport(x,"DataSpec"),u.addTypeImport(x,"EnumLike"),$&&u.addImport(x,"ResourceBuilder"),u.addImport(g,"mergeCatalogs"),u.addImport(g,"sdkCatalog"),u.addImport("@lingui/core","setupI18n");let k=r(i.configurator.dataSchemas,u,f),v=c.generateStateConstants({configuratorStates:i.configurator.states,adminStates:i.admin.states},u,f),I=o(i),{importBlock:N,catalogBlock:h,createI18nExport:A}=d(i.configurator.ui.availableLocales),{preBlock:B,builderBlock:C}=t(i,u,f),y=c.generateBindingBlock();return`${a("domain-spec.ts","Domain builders, model schemas, component optics and expression definitions derived from the spec.")}
2
+ ${u.toString()}${N}
3
3
 
4
4
  // ---- Data schemas ----
5
5
 
@@ -11,7 +11,7 @@ ${S}
11
11
 
12
12
  // ---- Configurator domain ----
13
13
 
14
- ${f}
14
+ ${E}
15
15
 
16
16
  // ---- i18n ----
17
17
 
@@ -21,11 +21,11 @@ ${A}
21
21
 
22
22
  // ---- Application metadata ----
23
23
 
24
- ${N}
24
+ ${I}
25
25
 
26
26
  // ---- State enums ----
27
27
 
28
- ${I}
28
+ ${v}
29
29
 
30
30
  const $dataSpec: DataSpec = ${p(i.dataSpec.entries)}
31
31
 
@@ -1,9 +1,9 @@
1
- import{CodeImports as i}from"../common/code-imports.js";import{autoHeader as n}from"../common/file-headers.js";let o=/v(\d+)\.ts$/,t=(i,n)=>i.versionedModels.filter(i=>void 0!==i.migrationFile).map(i=>({version:i.version,file:i.migrationFile,importName:n?`${n}MigrateToV${i.version}`:`migrateToV${i.version}`})),s=i=>i.map(i=>{let n=i.file.replace(o,`v${i.version}.js`),t=`migrateToV${i.version}`,s=i.importName!==t?` as ${i.importName}`:"";return`import { ${t}${s} } from '../${n}'`}).join("\n"),e=(i,n,o,t)=>[`const ${t}Migrations = {`,...i.map(i=>` ${i.version}: ${i.importName},`),"}","",`const ${t} = MigrateFunctionBuilder`,` .fromVersions(${n})`,` .to(${o})`,` .using(${t}Migrations)`," .build()"].join("\n");export const generateApplicationSpecDomainFile=o=>{let r=new i,a="./domain-spec.js",m="./configurator-domain-code.js",d="./admin-domain-code.js",p=i=>[...i.expressions.values()].some(i=>[...i.values()].some(i=>"relation"===i.implementation.kind)),l=p(o.configurator.expressions),c=p(o.admin.expressions),u=t(o.configurator.resolvedVersions,""),I=t(o.admin.resolvedVersions,"admin"),g=u.length>0,h=I.length>0;r.addImport(a,"baseConfiguratorBuilder"),r.addImport(a,"domainBuilder"),r.addImport(a,"adminDomainBuilder"),r.addImport(a,"attachComponent"),r.addImport(a,"attachAdminComponent"),r.addImport(a,"implementCustomExpressions"),r.addImport(a,"implementAdminCustomExpressions"),r.addImport(a,"createI18n"),r.addImport(a,"componentOptics"),r.addImport(a,"adminComponentOptics"),r.addImport(a,"invariantBuilder"),r.addImport(a,"adminInvariantBuilder"),r.addImport(m,"customExpressions"),r.addImport(m,"customInvariants"),r.addImport(d,"customAdminExpressions"),r.addImport(d,"customAdminInvariants"),l&&r.addImport(a,"relationExpressions"),c&&r.addImport(a,"adminRelationExpressions"),(g||h)&&r.addImport("@salsita-ai/sdk/domain","MigrateFunctionBuilder"),g&&r.addImport(a,"modelVersions"),h&&r.addImport(a,"adminModelVersions");let x=[];g&&x.push(s(u)),h&&x.push(s(I));let v=x.length>0?"\n"+x.join("\n")+"\n":"",$=[];g&&$.push(e(u,"modelVersions",o.configurator.schemaVersion,"migrate")),h&&$.push(e(I,"adminModelVersions",o.admin.schemaVersion,"migrateAdmin"));let E=$.length>0?"\n"+$.join("\n\n")+"\n":"",f=["const domainFactory = domainBuilder",l?" .withExpressions(relationExpressions)":null," .withExpressions(invariantBuilder.withInvariants(customInvariants).buildViolationExpressions())"," .withExpressions(customExpressions)",g?" .withMigrate(migrate)":null," .build()"].filter(Boolean).join("\n"),w=["const adminDomainFactory = adminDomainBuilder",c?" .withExpressions(adminRelationExpressions)":null," .withExpressions(adminInvariantBuilder.withInvariants(customAdminInvariants).buildViolationExpressions())"," .withExpressions(customAdminExpressions)",h?" .withMigrate(migrateAdmin)":null," .build()"].filter(Boolean).join("\n");return`${n("domain.ts","Assembles domain and admin domain factories from builders, migrations, expressions and invariants.")}
1
+ import{CodeImports as i}from"../common/code-imports.js";import{autoHeader as n}from"../common/file-headers.js";let o=/v(\d+)\.ts$/,t=(i,n)=>i.versionedModels.filter(i=>void 0!==i.migrationFile).map(i=>({version:i.version,file:i.migrationFile,importName:n?`${n}MigrateToV${i.version}`:`migrateToV${i.version}`})),s=i=>i.map(i=>{let n=i.file.replace(o,`v${i.version}.js`),t=`migrateToV${i.version}`,s=i.importName!==t?` as ${i.importName}`:"";return`import { ${t}${s} } from '../${n}'`}).join("\n"),e=(i,n,o,t)=>[`const ${t}Migrations = {`,...i.map(i=>` ${i.version}: ${i.importName},`),"}","",`const ${t} = MigrateFunctionBuilder`,` .fromVersions(${n})`,` .to(${o})`,` .using(${t}Migrations)`," .build()"].join("\n");export const generateApplicationSpecDomainFile=o=>{let r=new i,a="./domain-spec.js",m="./configurator-domain-code.js",d="./admin-domain-code.js",p=i=>[...i.expressions.values()].some(i=>[...i.values()].some(i=>"relation"===i.implementation.kind)),l=p(o.configurator.expressions),c=p(o.admin.expressions),u=t(o.configurator.resolvedVersions,""),I=t(o.admin.resolvedVersions,"admin"),g=u.length>0,h=I.length>0;r.addImport(a,"baseConfiguratorBuilder"),r.addImport(a,"domainBuilder"),r.addImport(a,"adminDomainBuilder"),r.addImport(a,"attachComponent"),r.addImport(a,"attachAdminComponent"),r.addImport(a,"implementCustomExpressions"),r.addImport(a,"implementAdminCustomExpressions"),r.addImport(a,"createI18n"),r.addImport(a,"componentOptics"),r.addImport(a,"adminComponentOptics"),r.addImport(a,"invariantBuilder"),r.addImport(a,"adminInvariantBuilder"),r.addImport(m,"customExpressions"),r.addImport(m,"customInvariants"),r.addImport(m,"customActions"),r.addImport(d,"customAdminExpressions"),r.addImport(d,"customAdminInvariants"),l&&r.addImport(a,"relationExpressions"),c&&r.addImport(a,"adminRelationExpressions"),(g||h)&&r.addImport("@salsita-ai/sdk/domain","MigrateFunctionBuilder"),g&&r.addImport(a,"modelVersions"),h&&r.addImport(a,"adminModelVersions");let x=[];g&&x.push(s(u)),h&&x.push(s(I));let v=x.length>0?"\n"+x.join("\n")+"\n":"",$=[];g&&$.push(e(u,"modelVersions",o.configurator.schemaVersion,"migrate")),h&&$.push(e(I,"adminModelVersions",o.admin.schemaVersion,"migrateAdmin"));let E=$.length>0?"\n"+$.join("\n\n")+"\n":"",f=["const domainFactory = domainBuilder",l?" .withExpressions(relationExpressions)":null," .withExpressions(invariantBuilder.withInvariants(customInvariants).buildViolationExpressions())"," .withExpressions(customExpressions)"," .withActionImplementations(customActions)",g?" .withMigrate(migrate)":null," .build()"].filter(Boolean).join("\n"),A=["const adminDomainFactory = adminDomainBuilder",c?" .withExpressions(adminRelationExpressions)":null," .withExpressions(adminInvariantBuilder.withInvariants(customAdminInvariants).buildViolationExpressions())"," .withExpressions(customAdminExpressions)",h?" .withMigrate(migrateAdmin)":null," .build()"].filter(Boolean).join("\n");return`${n("domain.ts","Assembles domain and admin domain factories from builders, migrations, expressions and invariants.")}
2
2
  ${r.toString()}
3
3
  ${v}export { attachComponent, attachAdminComponent, implementCustomExpressions, implementAdminCustomExpressions, createI18n }
4
4
  ${E}
5
5
  ${f}
6
- ${w}
6
+ ${A}
7
7
 
8
8
  export const configuratorBuilder = baseConfiguratorBuilder
9
9
  .withDomainFactory(domainFactory)
@@ -0,0 +1,11 @@
1
+ import type { PhoenixDefinitions } from '../../../../core/phoenix-definitions.js';
2
+ import type { Actions, ModelVersion } from '../../../../parse-application-files/index.js';
3
+ import type { CodeImports } from '../../common/code-imports.js';
4
+ /**
5
+ * Generates the `ActionTypes` map of the declared actions (name → `{ params, result }`) and the
6
+ * `ActionName`, `ActionParams<NAME>` and `ActionResult<NAME>` types derived from it. A nullable
7
+ * param is optional. The `description` of an action, a param and a result member becomes the doc
8
+ * comment of its property, so it shows wherever the types are used. Without actions the map is
9
+ * empty, so `ActionName` is `never`.
10
+ */
11
+ export declare const generateActionTypeDecls: (actions: Actions, model: ModelVersion, phxDefinitions: PhoenixDefinitions, imports: CodeImports, indent: number, typeOnlyImports?: boolean) => string;
@@ -0,0 +1,8 @@
1
+ import{schemaToTypeString as e}from"../common/schema-to-type-string.js";let t=(e,t)=>{let n=(e??"").trim().replaceAll("*/","*\\/").split("\n").map(e=>e.trim());return""===n[0]||void 0===n[0]?[]:1===n.length?[`${t}/** ${n[0]} */`]:[`${t}/**`,...n.map(e=>`${t} * ${e}`.trimEnd()),`${t} */`]};export const generateActionTypeDecls=(n,r,o,a,p,s=!1)=>{let i=" ".repeat(p),$=" ".repeat(p+2),c=" ".repeat(p+4),l=" ".repeat(p+6),m={phxDefinitions:o,commonTypeNames:new Set(r.commonTypes.keys()),imports:a,typeOnlyImports:s},y=[...n.values()].map(n=>{let r=Object.entries(n.params).flatMap(([n,{schema:r,required:o}])=>[...t(r.description,l),`${l}readonly ${n}${o?"":"?"}: ${e(r,m)}`]),o=Object.entries(n.result).flatMap(([n,r])=>[...t(r.description,l),`${l}readonly ${n}: ${e(r,m)}`]),a=e=>e.length>0?`{
2
+ ${e.join("\n")}
3
+ ${c}}`:"Record<string, never>";return[...t(n.description,$),`${$}readonly ${n.name}: {`,`${c}readonly params: ${a(r)}`,`${c}readonly result: ${a(o)}`,`${$}}`].join("\n")}),A=y.length>0?`{
4
+ ${y.join("\n")}
5
+ ${i}}`:"Record<never, never>";return`${i}type ActionTypes = ${A}
6
+ ${i}type ActionName = keyof ActionTypes
7
+ ${i}type ActionParams<NAME extends ActionName> = ActionTypes[NAME]['params']
8
+ ${i}type ActionResult<NAME extends ActionName> = ActionTypes[NAME]['result']`};
@@ -1,3 +1,4 @@
1
+ export { generateActionTypeDecls } from './generate-action-types.js';
1
2
  export { generateModelTypeDecls } from './generate-model-types.js';
2
3
  export { generateExpressionTypeDecls, generateEntityExpressionComposites } from './generate-expression-types.js';
3
4
  export { generateDataSchemaTypeDecls } from './generate-data-schema-types.js';
@@ -1 +1 @@
1
- export{generateModelTypeDecls}from"./generate-model-types.js";export{generateExpressionTypeDecls,generateEntityExpressionComposites}from"./generate-expression-types.js";export{generateDataSchemaTypeDecls}from"./generate-data-schema-types.js";
1
+ export{generateActionTypeDecls}from"./generate-action-types.js";export{generateModelTypeDecls}from"./generate-model-types.js";export{generateExpressionTypeDecls,generateEntityExpressionComposites}from"./generate-expression-types.js";export{generateDataSchemaTypeDecls}from"./generate-data-schema-types.js";
@@ -73,6 +73,7 @@ ${h}
73
73
  readonly enhancedModel: typeof import('./domain-spec.js').enhancedModel
74
74
  readonly implementCustomExpressions: typeof import('./domain-spec.js').implementCustomExpressions
75
75
  readonly implementCustomInvariants: typeof import('./domain-spec.js').implementCustomInvariants
76
+ readonly implementActions: typeof import('./domain-spec.js').implementActions
76
77
  readonly attachComponent: typeof import('./domain-spec.js').attachComponent
77
78
  readonly createRecipe: typeof import('./domain-spec.js').createRecipe
78
79
 
@@ -71,7 +71,9 @@ Walk through the whole journey as the intended user: start, explore and change o
71
71
 
72
72
  Check representative valid and invalid combinations, boundaries, dependent changes, independent options on repeated parts, and hand-calculated prices where applicable. Include persistence/reload, undo/redo, exports, and integrations when implemented. Invalid configurations should produce the agreed handling, not an assumed universal blocking pattern.
73
73
 
74
- Fix gaps and regressions, update the specification, and present the complete experience for the client's final review. State what is implemented, what remains provisional or unverified, and whether it is a working draft or ready for its intended users. Publishing and connecting live systems remain separate actions governed by the client's authorization and the environment's rules; obtain any required approval against the concrete result.`,c=`## Verification evidence
74
+ Fix gaps and regressions, update the specification, and present the complete experience for the client's final review. State what is implemented, what remains provisional or unverified, and whether it is a working draft or ready for its intended users. Publishing and connecting live systems remain separate actions governed by the client's authorization and the environment's rules; obtain any required approval against the concrete result.
75
+
76
+ Once the client says they are done, or the configurator is live and they confirm the work is finished, follow the \`phoenix-feedback\` skill to interview them for an evaluation of the run. Ask for it once, and send it only with their approval.`,c=`## Verification evidence
75
77
 
76
78
  Use the project's documented verification commands and available tools throughout. Distinguish automated checks, your actual preview observations, and client feedback. A successful build does not prove preview access or interaction quality. Missing browser automation need not prevent the client from using a preview: offer a focused check and record their result as client feedback. Disclose anything you cannot test; a generic “OK” is not evidence that an untested interaction works.`,d=`# Phoenix UX guidance
77
79
 
@@ -4,7 +4,9 @@ Draft feedback for the Phoenix team when one of these happens while you work in
4
4
  - **Misleading guidance** — a doc page, a Phoenix skill or an error message sent you the wrong way, or did not say what you needed.
5
5
  - **Missing feature** — something the SDK does not support forced a workaround, or a routine task took far more steps than it should.
6
6
 
7
- Do not draft feedback for problems in this project's own specs or code, for a suspicion you have not checked, or twice for the same problem. Write one draft per distinct problem.`,o=`## Ask Before You Send
7
+ Do not draft feedback for problems in this project's own specs or code, for a suspicion you have not checked, or twice for the same problem. Write one draft per distinct problem.
8
+
9
+ The evaluation of a finished run is feedback too; the section "Evaluate the Run" says when to ask for it.`,o=`## Ask Before You Send
8
10
  Never send feedback on your own. Show the user a draft and send it only after they approve it.
9
11
 
10
12
  When to ask is your judgement:
@@ -12,20 +14,41 @@ When to ask is your judgement:
12
14
  - **At the end of the task** — everything else. Collect the details while you work and show all drafts together in your final message.
13
15
  - **When the user asks** you to send feedback — draft it and show it before sending.
14
16
 
15
- The draft is exactly what would be sent: the type, the message, the project if you name one with \`--projectSlug\`, and the contact if the user gave one. Send it unchanged after a yes; if the user edits it, send their version. If they decline, drop it and do not raise that problem again.`,a=`## Ask for a Rating After a Deploy
16
- When \`phoenix deploy\` reports that the configurator is live, tell the user the live URL first, then ask them to rate building with Phoenix so far:
17
- - Ask for a score from 0 to 10, where 10 is the best, and one optional sentence on what would have made it better. Say in the same question that the answer is sent to the Phoenix team as feedback.
18
- - Ask once per conversation, after the first deploy that goes live. Do not ask again after later deploys, and do not ask after a deploy that failed.
19
- - Never choose or guess the score yourself. If the user skips the question or declines, send nothing and do not ask again.
20
-
21
- A rating is feedback like any other, so the rules of this skill apply. Write the comment from the user's words, and take out anything the last section forbids: replace this project's product, customer and people names with generic words. Then show the user the three lines below exactly as they would be sent and send them only after a yes; if they edit the text, send their version. Use \`none\` when they gave no comment:
22
- \`\`\`bash
23
- pnpm phoenix feedback 'Rating: <score>/10
24
- Comment: <their comment, or none>
25
- Stage: after a deploy' --type other --agent '<your agent name>'
17
+ The draft is exactly what would be sent: the type, the full message, the project if you name one with \`--projectSlug\`, and the contact if the user gave one. Send it unchanged after a yes; if the user edits it, send their version. If they decline, drop it and do not raise that problem again.`,n=`## Evaluate the Run
18
+ When the work on the configurator is finished, interview the user for an evaluation of the run and send it as feedback. The run is finished when the user says they are done, or when \`phoenix deploy\` reported the configurator live and the user confirms they have nothing more to build; ask that once after a deploy goes live, and do not start the interview while they want to continue.
19
+
20
+ Say first that the answers are sent to the Phoenix team as feedback, and that the user can decline. Then ask one question at a time, in this order, and wait for each answer before asking the next. Give the short explanation with each question. Every score is a whole number from 0 to 10, where 0 is catastrophic, 5 is passable and 10 is amazing:
21
+ 1. **Minutes spent** — roughly how many minutes the user spent on the run, from the first prompt to now. This one is a number of minutes, not a score.
22
+ 2. **Agent guidance** — how clear it was what to expect and what to do, how clearly you explained yourself, and how well they understood the consequences of their choices.
23
+ 3. **Functionality** — how complete the configurator is: whether it configures the full product with all its options, keeps the user from creating or submitting a wrong configuration, and offers a way to finalize one.
24
+ 4. **UX** — how easy the configurator is to understand and operate, how clear the choices are, and how understandable incompatibilities and the ways to resolve them are.
25
+ 5. **3D quality** — how realistic and attractive the configured object and its scene are: shapes, textures, surroundings, lighting and shadows.
26
+ 6. **UI visuals** — how good the user interface looks.
27
+ 7. **Overall** — the user's subjective verdict on the configurator as a whole.
28
+ 8. **Comments** — anything else about the experience, in their own words. This one is free text and may be empty.
29
+
30
+ Rules of the interview:
31
+ - Ask once per conversation. Do not run it again after a later deploy, and do not run it after a deploy that failed.
32
+ - Never choose, guess or adjust a score, and never answer a question for the user. When they skip one, write \`skipped\` for it.
33
+ - When the user declines the evaluation, send nothing and do not ask again.
34
+
35
+ Compose the evaluation from the answers with exactly these labels, one per line, in this order. Write \`none\` when there are no comments, and fill \`Build\` and \`Configurator\` as the report template describes:
36
+ \`\`\`text
37
+ Evaluation
38
+ Minutes spent: <minutes>
39
+ Agent guidance: <score>/10
40
+ Functionality: <score>/10
41
+ UX: <score>/10
42
+ 3D quality: <score>/10
43
+ UI visuals: <score>/10
44
+ Overall: <score>/10
45
+ Comments: <their comments, or none>
46
+ Build: <build id> <Studio build page link>
47
+ Configurator: <live configurator link>
26
48
  \`\`\`
27
- Keep the three labels and their order, so the ratings can be read out of the feedback list. A rating is not a bug report: when the comment names a concrete problem, offer to draft it as its own feedback as the sections above describe.`,n=`## What Never Goes Into Feedback
49
+ Keep the labels and their order, so the scores can be read out of the feedback list and its export. Show the user the text exactly as it would be sent, and send it with \`--type other\` only after a yes; if they edit it, send their version. An evaluation is not a bug report: when a comment names a concrete problem, offer to draft it as its own report.`,a=`## What Never Goes Into Feedback
28
50
  The message leaves this project and is read by the Phoenix team. Never include:
29
- - secrets: API tokens, keys, passwords or \`.env\` values;
30
- - customer or end-user data, or personal data such as names and email addresses, other than a contact the user asked you to add;
31
- - this project's source code, specs or business rules. Describe the shape of the problem in words, or reduce it to a generic example that contains nothing of the project.`;export const generatePhoenixFeedbackSkill=()=>e({name:"phoenix-feedback",description:"Drafting feedback about the Phoenix SDK, CLI, documentation or Studio for the Phoenix team and sending it with the phoenix feedback command once the user approves the draft, covering when to raise it, how to write it, the rating asked for after a deploy and what must never be included. Use when the SDK or CLI misbehaves, a doc or skill misled you, a missing feature forced a workaround, the user asks to send feedback, or phoenix deploy has just gone live and the user should be asked to rate the experience from 0 to 10.",sections:[t,o,"## How to Send It\n```bash\npnpm phoenix feedback '<message>' --type bug --agent '<your agent name>'\n```\n- Put the message in single quotes, so the shell passes backticks, `$` and double quotes through unchanged. In bash or zsh, write a single quote inside the message as `'\\''`; in PowerShell, double it instead.\n- `--type` is `bug`, `idea` or `other` (default `other`). Use `idea` for a missing feature or an improvement.\n- `--agent` names you, the coding agent, so the team can tell agent feedback from a person's.\n- `--contact '<email>'` only when the user wants a reply and gave you the contact to use.\n- The workspace, user, SDK version and the spec's `project` are attached automatically. `--projectSlug <slug>` names another project of the workspace.\n- A message holds at most 5000 characters.\n\nWrite the message for someone who cannot see this project: what you ran or called, what you expected, what happened instead with the error text, and the workaround if you found one. Before quoting an error, replace this project's names, file paths and values in it with generic placeholders, as the list below requires.\n\nThe command needs `phoenix login`. If it answers that you are not signed in, tell the user once and continue; do not sign in yourself, because the sign-in is approved in a browser.\n\nAfter sending, confirm it to the user in one line.",a,n]});
51
+ - secrets and credentials: API tokens, keys, passwords or \`.env\` values, also when they appear inside an error or a log you quote. Replace each with \`<redacted>\`;
52
+ - personal data, or data of the project's customers and end users, such as names, email addresses and orders, other than a contact the user asked you to add.
53
+
54
+ Parts of this project may go into a message: file names and paths, snippets of its specs and code, and the user's own words. They are sent only as part of a draft the user saw and approved, which is why the draft you show is always the full text.`;export const generatePhoenixFeedbackSkill=()=>e({name:"phoenix-feedback",description:"Drafting feedback about the Phoenix SDK, CLI, documentation or Studio for the Phoenix team and sending it with the phoenix feedback command once the user approves the draft, covering when to raise it, the report template with the build and configurator links, the evaluation interview at the end of a run, how to send it and what must never be included. Use when the SDK or CLI misbehaves, a doc or skill misled you, a missing feature forced a workaround, the user asks to send feedback, or the user is done with the configurator and the run should be evaluated.",sections:[t,o,"## Report Template\nWrite a report as plain text with the labels below, in this order, so the Phoenix team reads every report the same way. Keep every label; write `none` or `not deployed yet` where you have nothing to put.\n```text\nBuild: <build id> <Studio build page link>\nConfigurator: <live configurator link>\n\nWhat I was doing:\n<the task and the step you were on>\n\nWhat happened and what I expected:\n<what you ran or called, the result you got, and the result you expected>\n\nExact error or agent output:\n<the error text or the output, copied unchanged>\n\nWorkaround:\n<what you did instead, or none>\n\nConversation log:\n<the conversation condensed to the turns that matter: what the user asked, what you tried, what failed>\n```\n- **Build** is the latest build of this project, the one whose sources show the problem. `pnpm phoenix deploy` prints its id as `Build <id> started` and its page as `Follow the build in Studio: <url>`. When that line is missing, compose the link as `https://<workspace>.<studio host>/builder/deployments/<build id>`: the workspace is the one named at `phoenix login`, and the host is `studio.eu.salsita.ai` for the `eu` region, `studio.salsita.ai` for `us` and `studio-staging.salsita.app` for staging. A Studio address passed to login with `--studioUrl` replaces the workspace and host. Never invent a build id: when the project was not deployed, write `not deployed yet`.\n- **Configurator** is the live address `pnpm phoenix deploy` prints once the build is live.\n- The team downloads the sources of the build from its Studio page, so do not paste whole files; quote only the lines that show the problem.\n- Quote errors and output exactly. A report that paraphrases an error cannot be searched for.\n- Condense the conversation log, do not dump it: keep the user's requests, your decisions and the failures, and leave out tool output that the other sections already carry.",n,"## How to Send It\nWrite a report or an evaluation to a text file and send the file, so the shell changes nothing in it:\n```bash\npnpm phoenix feedback --file <path> --type bug --agent '<your agent name>'\n```\nPut the file outside the project, in the system's temporary folder, and delete it after sending. A note of a line or two can go in as an argument instead:\n```bash\npnpm phoenix feedback '<message>' --type idea --agent '<your agent name>'\n```\n- Give either `--file` or the message argument, never both.\n- Put a message argument in single quotes, so the shell passes backticks, `$` and double quotes through unchanged. In bash or zsh, write a single quote inside the message as `'\\''`; in PowerShell, double it instead.\n- `--type` is `bug`, `idea` or `other` (default `other`). Use `idea` for a missing feature or an improvement, and `other` for an evaluation.\n- `--agent` names you, the coding agent, so the team can tell agent feedback from a person's.\n- `--contact '<email>'` only when the user wants a reply and gave you the contact to use.\n- The workspace, user, SDK version and the spec's `project` are attached automatically. `--projectSlug <slug>` names another project of the workspace.\n- A message holds at most 100,000 characters. Shorten the conversation log first when a report is longer.\n\nThe command needs `phoenix login`. If it answers that you are not signed in, tell the user once and continue; do not sign in yourself, because the sign-in is approved in a browser.\n\nAfter sending, confirm it to the user in one line.",a]});
@@ -7,13 +7,15 @@ import{renderAgentSkill as e}from"./agent-skill.js";let i=`Review all current gi
7
7
  - [ ] Relations properly define parent-child ownership (1-N, 0-1)
8
8
  - [ ] Expressions have matching implementations in src/expressions/
9
9
  - [ ] Invariants have matching implementations in src/invariants/
10
+ - [ ] Actions declared under actions: have matching implementations in src/actions/ (a missing one fails the type check of the generated barrel)
10
11
  - [ ] Component bindings use correct entity types or aliases
11
12
  - [ ] $read/$write/$bind reference valid properties or expressions
12
13
  - [ ] A model that has been deployed is unchanged under its version: the change is in \`model.latest\`, the deployed model is kept as \`model.v<N>\`, and \`src/migrations/v<N+1>.ts\` migrates saved configurations
13
14
 
14
- ### Expressions & Invariants (src/expressions/, src/invariants/)
15
+ ### Expressions, Actions & Invariants (src/expressions/, src/actions/, src/invariants/)
15
16
 
16
- - [ ] Use phx.domain.implementCustomExpressions() / implementCustomInvariants()
17
+ - [ ] Use phx.domain.implementCustomExpressions() / implementActions() / implementCustomInvariants()
18
+ - [ ] Actions only prepare: they return updates and a readResult reader, never stage or commit, and throw messages that say what to send instead
17
19
  - [ ] Expression names prefixed with $ in YAML match implementation
18
20
  - [ ] No side effects in expressions (pure computed values only)
19
21
  - [ ] Invariant violations return proper severity and messages
@@ -25,6 +25,7 @@ Declarative 3D product configurator built with Phoenix SDK. Domain model defined
25
25
  readonly projectStructure: `## Project Structure
26
26
  - \`spec/\` — Domain YAML specs (entities, relations, expressions, invariants, components, application config)
27
27
  - \`src/expressions/\` — Computed/derived entity properties (\`phx.domain.implementCustomExpressions()\`)
28
+ - \`src/actions/\` — Domain operations declared under \`actions:\` in the spec (\`phx.domain.implementActions()\`), run by controls and exposed to the assistant
28
29
  - \`src/invariants/\` — Business rule constraints (\`phx.domain.implementCustomInvariants()\`)
29
30
  - \`src/transformers/\` — Automatic state fixers (\`phx.frontend.transformerBuilder\`)
30
31
  - \`src/components/\` — ECS system components (\`phx.domain.attachComponent.withEntity()\`)
@@ -48,6 +49,7 @@ Declarative 3D product configurator built with Phoenix SDK. Domain model defined
48
49
  /** Expressions, invariants, transformers, components, webhooks, and filters at a glance. */
49
50
  readonly keyPatterns: `## Key Patterns
50
51
  - Expressions = computed properties on entities (prefix: \`$\`), implemented per-entity in src/expressions/
52
+ - Actions = named domain operations (\`actions:\` in YAML with \`params\` and \`result\` schemas), implemented in src/actions/, prepared through \`actionSystem.prepareAction()\` and exposed as assistant mutations through \`assistant.actions\`
51
53
  - Invariants = validation rules returning violations, static or dynamic
52
54
  - Transformers = auto-fixers maintaining consistency after state changes
53
55
  - Components defined in YAML with \`$read\`/\`$bind\` bindings, or custom in src/components/ using attachComponent builder
@@ -63,7 +65,7 @@ Declarative 3D product configurator built with Phoenix SDK. Domain model defined
63
65
  - Underscore folders (_shared/, _utils/) are NOT auto-imported`;
64
66
  /** The default-export rule of the SDK auto-import system. */
65
67
  readonly exportRules: `## Export Rules
66
- All files in src/expressions/, src/invariants/, src/transformers/, src/components/, src/handlers/, src/webhooks/ MUST use default exports. Can be a single item or an array. Named exports are ignored by the SDK auto-import system.`;
68
+ All files in src/expressions/, src/actions/, src/invariants/, src/transformers/, src/components/, src/handlers/, src/webhooks/ MUST use default exports. Can be a single item or an array. Named exports are ignored by the SDK auto-import system.`;
67
69
  /** Which components and handlers are bundled into the webhook. */
68
70
  readonly webhookMembership: `## Webhook Membership
69
71
  - User-authored components, admin components, and handlers are frontend-only by default.
@@ -1,13 +1,13 @@
1
1
  export const sdkGuidanceSections={projectIntro:`## Phoenix Configurator Project
2
2
 
3
- Declarative 3D product configurator built with Phoenix SDK. Domain model defined in YAML, custom logic in TypeScript.`,buildCommands:"## Build Commands\n- `pnpm phoenix build` — Full production build\n- `pnpm phoenix dev` — Development mode with hot reload\n- `pnpm phoenix sync` — Sync generated files without full build",devLogs:"## Dev Logs\n- `pnpm phoenix dev` writes all logs to `.phoenix/phoenix-dev.log`\n- Contains: spec parse errors, build errors, browser runtime errors, file watcher events\n- After making changes, always check the log for errors: `tail -50 .phoenix/phoenix-dev.log` or `grep ERROR .phoenix/phoenix-dev.log`\n- Rotated automatically at 10MB (`.log.1`, `.log.2` are older rotations)",projectStructure:"## Project Structure\n- `spec/` — Domain YAML specs (entities, relations, expressions, invariants, components, application config)\n- `src/expressions/` — Computed/derived entity properties (`phx.domain.implementCustomExpressions()`)\n- `src/invariants/` — Business rule constraints (`phx.domain.implementCustomInvariants()`)\n- `src/transformers/` — Automatic state fixers (`phx.frontend.transformerBuilder`)\n- `src/components/` — ECS system components (`phx.domain.attachComponent.withEntity()`)\n- `src/elements/` — Page-level React components (`phx.frontend.createCustomPhoenixLayoutElement()`)\n- `src/handlers/` — Event & lifecycle handlers\n- `src/webhooks/` — Server-side webhook handlers (`phx.webhooks.*Builder`)\n- `src/migrations/` — Schema version migrations (v*.ts)\n- `src/locales/` — Locale catalogs (authored .po sources; compiled .ts, do not edit)\n- `src/admin/` — Admin interface (mirrors main src/ structure)\n- `src/_shared/` — Shared utilities (NOT auto-imported, requires explicit imports)\n- `.phoenix/` — Auto-generated files (DO NOT EDIT)\n- `public/` — Static assets (3D models, textures, images, HDRI maps, fonts)\n- `assets/` — Uploadable resources (PDF templates, email assets)",architecturePrinciples:"## Architecture Principles\n- YAML-first: 99% of configuration in spec/*.yaml, custom code is last resort\n- ECS pattern: entities (domain objects) + components (behavior/UI) + systems (SDK runtime)\n- Reactive state: immutable domain state flows through RxJS pipelines\n- Data binding: `$read` (read-only), `$write` (write-only), `$bind` (bidirectional) connect components to domain\n- memoEval: all component implementations must use memoEval for stable object references",keyPatterns:"## Key Patterns\n- Expressions = computed properties on entities (prefix: `$`), implemented per-entity in src/expressions/\n- Invariants = validation rules returning violations, static or dynamic\n- Transformers = auto-fixers maintaining consistency after state changes\n- Components defined in YAML with `$read`/`$bind` bindings, or custom in src/components/ using attachComponent builder\n- Webhooks = server-side finalization tasks (PDF, email, CSV, image rendering)\n- Filters = contextual component activation via navigationStates, viewStates, modes, selectedEntityIds",fileConventions:`## File Conventions
3
+ Declarative 3D product configurator built with Phoenix SDK. Domain model defined in YAML, custom logic in TypeScript.`,buildCommands:"## Build Commands\n- `pnpm phoenix build` — Full production build\n- `pnpm phoenix dev` — Development mode with hot reload\n- `pnpm phoenix sync` — Sync generated files without full build",devLogs:"## Dev Logs\n- `pnpm phoenix dev` writes all logs to `.phoenix/phoenix-dev.log`\n- Contains: spec parse errors, build errors, browser runtime errors, file watcher events\n- After making changes, always check the log for errors: `tail -50 .phoenix/phoenix-dev.log` or `grep ERROR .phoenix/phoenix-dev.log`\n- Rotated automatically at 10MB (`.log.1`, `.log.2` are older rotations)",projectStructure:"## Project Structure\n- `spec/` — Domain YAML specs (entities, relations, expressions, invariants, components, application config)\n- `src/expressions/` — Computed/derived entity properties (`phx.domain.implementCustomExpressions()`)\n- `src/actions/` — Domain operations declared under `actions:` in the spec (`phx.domain.implementActions()`), run by controls and exposed to the assistant\n- `src/invariants/` — Business rule constraints (`phx.domain.implementCustomInvariants()`)\n- `src/transformers/` — Automatic state fixers (`phx.frontend.transformerBuilder`)\n- `src/components/` — ECS system components (`phx.domain.attachComponent.withEntity()`)\n- `src/elements/` — Page-level React components (`phx.frontend.createCustomPhoenixLayoutElement()`)\n- `src/handlers/` — Event & lifecycle handlers\n- `src/webhooks/` — Server-side webhook handlers (`phx.webhooks.*Builder`)\n- `src/migrations/` — Schema version migrations (v*.ts)\n- `src/locales/` — Locale catalogs (authored .po sources; compiled .ts, do not edit)\n- `src/admin/` — Admin interface (mirrors main src/ structure)\n- `src/_shared/` — Shared utilities (NOT auto-imported, requires explicit imports)\n- `.phoenix/` — Auto-generated files (DO NOT EDIT)\n- `public/` — Static assets (3D models, textures, images, HDRI maps, fonts)\n- `assets/` — Uploadable resources (PDF templates, email assets)",architecturePrinciples:"## Architecture Principles\n- YAML-first: 99% of configuration in spec/*.yaml, custom code is last resort\n- ECS pattern: entities (domain objects) + components (behavior/UI) + systems (SDK runtime)\n- Reactive state: immutable domain state flows through RxJS pipelines\n- Data binding: `$read` (read-only), `$write` (write-only), `$bind` (bidirectional) connect components to domain\n- memoEval: all component implementations must use memoEval for stable object references",keyPatterns:"## Key Patterns\n- Expressions = computed properties on entities (prefix: `$`), implemented per-entity in src/expressions/\n- Actions = named domain operations (`actions:` in YAML with `params` and `result` schemas), implemented in src/actions/, prepared through `actionSystem.prepareAction()` and exposed as assistant mutations through `assistant.actions`\n- Invariants = validation rules returning violations, static or dynamic\n- Transformers = auto-fixers maintaining consistency after state changes\n- Components defined in YAML with `$read`/`$bind` bindings, or custom in src/components/ using attachComponent builder\n- Webhooks = server-side finalization tasks (PDF, email, CSV, image rendering)\n- Filters = contextual component activation via navigationStates, viewStates, modes, selectedEntityIds",fileConventions:`## File Conventions
4
4
  - Components: PascalCase (.tsx)
5
5
  - Utilities: kebab-case (.ts)
6
6
  - Expressions: entity-name.ts
7
7
  - Migrations: v*.ts (sequential)
8
8
  - Specs: kebab-case.yaml
9
9
  - Underscore folders (_shared/, _utils/) are NOT auto-imported`,exportRules:`## Export Rules
10
- All files in src/expressions/, src/invariants/, src/transformers/, src/components/, src/handlers/, src/webhooks/ MUST use default exports. Can be a single item or an array. Named exports are ignored by the SDK auto-import system.`,webhookMembership:"## Webhook Membership\n- User-authored components, admin components, and handlers are frontend-only by default.\n- A handler that registers `createMapPublishedRevisionDataHandler`, `createMapPublishedChunkedDataHandler`, `createDataRowValidatorHandler`, or `createSheetValidatorHandler` is included in the webhook automatically.\n- To include another component or handler in the webhook, put `'use webhook'` as its first statement (leading comments are allowed).\n- A webhook-included file and its runtime local-import closure must not import browser SDK entrypoints (`application`, `admin`, `configurator`, `editor`, `react`, `ui`) or style/font/image assets. Spec parsing reports the unsafe import and inclusion reason as a diagnostic.\n- Keep browser rendering in an unpinned file. Move shared server-safe logic into a separate module when both frontend and webhook code need it.",doNotEdit:"## Do Not Edit\n- `.phoenix/` directory — completely regenerated on each build\n- `tsconfig.json`, `eslint.config.js`, `prettier.config.js`, `.prettierignore`, `.linguirc`, `.nvmrc`\n- `src/locales/` .ts files — compiled from .po files",modelVersioning:"## Version the Domain Model Once It Is Deployed\nA deployed model version cannot change, because saved configurations depend on it. `pnpm phoenix deploy` is refused, before anything is uploaded, when the model differs from the one already deployed under the same version. The version is not written anywhere: `model.latest` is always the highest numbered version plus one, so a spec with only `latest` is v1, and `applicationVersion` plays no part. `pnpm phoenix dev` accepts every model change, so a working preview does not show that the deploy will pass.\n\nTo change a model that has been deployed as v<N>:\n1. Keep the deployed model, unchanged, as `model.v<N>` in the spec. A file of its own, such as `spec/model-v<N>.yaml`, keeps `latest` readable.\n2. Make the change in `model.latest`, which is now v<N+1>.\n3. Add `src/migrations/v<N+1>.ts` exporting `migrateToV<N+1>`. It receives the saved entities of v<N> and returns entities that are valid in v<N+1>; `ModelV<N>` and `ModelV<N+1>` are generated global namespaces.\n\nThe admin model is versioned on its own, under `src/admin/migrations/`, with its types in `AdminV<N>`.\n\n**Replacing the starter.** When the first deployment of the workspace was the starter, its `Box` model is v1 in production. When the real model replaces it, keep the starter's model as `model.v1` and define the real model in `latest`. Configurations saved from the starter are not worth converting, so the migration returns the starting state of the new model, the `initialDomainEntities` of its preset, and drops the boxes:\n```typescript\n// src/migrations/v2.ts\nimport type { Migration } from '@salsita-ai/sdk/domain'\n\nexport const migrateToV2: Migration<ModelV1.AnyDomainEntity, ModelV2.AnyDomainEntity> = () => [\n // the entities of the new model's preset\n]\n```\nAn entity of a type the new version no longer has must not stay in the returned state. An entity id starts with its type (`Box-1`), so an entity that keeps its data under a new type name needs a new id and every relation pointing at it rewritten. Read `docs/phoenix/migrations.mdx` before writing any other migration.",sdkDocumentation:'## SDK Documentation\n\nAlways search SDK docs for relevant examples before implementing Phoenix features.\n\n### Commands\n- `pnpm phoenix docs` — Full documentation index with descriptions\n- `pnpm phoenix docs -s <term>` — Search all doc content and metadata (case-insensitive)\n- `pnpm phoenix docs --dir` — Print the absolute docs directory for grep or ripgrep\n- `pnpm phoenix docs -r <path>` — Read specific doc (raw text to stdout)\n- `pnpm phoenix docs -c <category>` — List docs in a category\n- `pnpm phoenix docs -l` — List all doc paths with titles\n\n### Key Docs\n- `docs/phoenix/getting-started.mdx` — Setup, prerequisites, first project\n- `docs/phoenix/quickstart.mdx` — End-to-end tutorial building a configurator\n- `docs/phoenix/domain-model.mdx` — Entities, attributes, relations, specs\n- `docs/phoenix/components.mdx` — ECS pattern, YAML components, custom components\n- `docs/phoenix/project-structure.mdx` — Files, folders, conventions\n- `docs/phoenix/best-practices.mdx` — YAML-first, code patterns, common pitfalls\n- `docs/phoenix/state-management.mdx` — Reactive state, RxJS pipelines, data flow\n- `docs/phoenix/expression-context.mdx` — Expression API, context object, helpers\n- `docs/phoenix/webhooks.mdx` — Server-side finalization workflows\n- `docs/phoenix/finalization.mdx` — Finalization system, PDF/email/CSV generation\n- `docs/phoenix/migrations.mdx` — Schema versioning, migration files\n\n### Agent Workflow\n1. Find relevant docs by content: `pnpm phoenix docs -s \'camera\'`\n2. Read matching doc: `pnpm phoenix docs -r docs/3d-scene/cameras/transitions.mdx`\n3. Search within a doc: `pnpm phoenix docs -r <path> | grep "example"`\n4. Search titles only as a fallback: `pnpm phoenix docs -l | grep "camera"`\n5. Search generated files directly when needed: `grep -rn "camera" "$(pnpm phoenix docs --dir)"`\n6. Browse a topic area: `pnpm phoenix docs -c "Layouts"`',assetInspection:"## 3D Asset Inspection\n\nRun `pnpm phoenix inspect:assets` to discover all glTF/GLB files in `public/` and get a summary table. Use `--file <path>` for detailed single-file inspection.\n\n**When to use:** before writing YAML/code that references objectName, materialsToOverride, morphTargetInfluences, or object positioning.\n\n**What it shows per node:**\n- Name, type (Mesh/Light/Camera/Empty), children\n- Transform: `pos=`, `rot=`, `scale=` (only non-default values shown)\n- Per-node morph targets: `morphs=Width,Height`\n- Bounding box: `bounds=WxHxD` (width x height x depth in meters)\n- Origin placement: `origin=center`, `bottom-center`, `top-center`, `bottom-corner`, etc. with numerical offset\n\n**Use cases:**\n- Find exact node names for `objectName` in scene entity components\n- Find material names for `materialsToOverride`\n- Find morph target names for `morphTargetInfluences`\n- Check model dimensions (bounds) for positioning, dimension indicators, or invariants\n- Check origin placement to understand how models anchor (center vs bottom-center)\n- Use `--json` for programmatic access to all data\n\n**Flags:** `--objects`, `--materials`, `--morphs`, `--animations`, `--json`",screenshotCli:"## Screenshot CLI\n\nCapture 3D canvas screenshots from a running dev server via `pnpm phoenix screenshot`.\n\n**Prerequisites:**\n1. `phoenix dev` must be running (starts the WebSocket server on port 3020)\n2. Configurator must be open in a browser (the browser does the actual rendering)\n\n**Options:**\n- `--output, -o` — Output file path (default: `./screenshot.png`)\n- `--width, -w` — Width in pixels (default: 1920)\n- `--height` — Height in pixels (default: 1080)\n- `--format, -f` — Image format: PNG or JPEG (default: PNG)\n- `--port` — WebSocket server port (default: 3020)\n\n**Example workflow:**\n1. Start dev server: `pnpm phoenix dev`\n2. Open configurator in browser (or via Playwright MCP)\n3. Take screenshot: `pnpm phoenix screenshot -o ./render.png -w 2560 --height 1440`\n\n**Use cases:** visual regression testing, generating product images, debugging 3D renders",inspectState:"## Inspect: State\n\nGet the current editor runtime state as JSON via `pnpm phoenix inspect:state`.\n\n**Prerequisites:** same as screenshot (dev server running + browser open)\n\n**Options:**\n- `--output, -o` — Output file path (prints to stdout if omitted)\n- `--sections, -s` — Comma-separated: entities, navigation, validation (default: all)\n- `--pretty` — Pretty-print JSON (default: true)\n- `--port` — WebSocket server port (default: 3020)\n\n**Example:** `pnpm phoenix inspect:state -o ./state.json -s entities,navigation`\n\n**Lifecycle status:** Always included in response. Shows which systems are ready:\n- `domainLoaded` — domain data loaded\n- `domainContextReady` — domain context initialized (entities available)\n- `configuratorReady` — 3D configurator initialized\n- `sessionAuthenticated` — session service active\n- `editorMode` — editor mode enabled\n\n**Tips:** Use `--sections` to limit payload size. Pipe through `head`/`tail` for partial output (e.g., `pnpm phoenix inspect:state | head -50`).\n\n**Use cases:** AI agent context, debugging entity state, inspecting navigation/validation",inspectData:`## Inspect: Data
10
+ All files in src/expressions/, src/actions/, src/invariants/, src/transformers/, src/components/, src/handlers/, src/webhooks/ MUST use default exports. Can be a single item or an array. Named exports are ignored by the SDK auto-import system.`,webhookMembership:"## Webhook Membership\n- User-authored components, admin components, and handlers are frontend-only by default.\n- A handler that registers `createMapPublishedRevisionDataHandler`, `createMapPublishedChunkedDataHandler`, `createDataRowValidatorHandler`, or `createSheetValidatorHandler` is included in the webhook automatically.\n- To include another component or handler in the webhook, put `'use webhook'` as its first statement (leading comments are allowed).\n- A webhook-included file and its runtime local-import closure must not import browser SDK entrypoints (`application`, `admin`, `configurator`, `editor`, `react`, `ui`) or style/font/image assets. Spec parsing reports the unsafe import and inclusion reason as a diagnostic.\n- Keep browser rendering in an unpinned file. Move shared server-safe logic into a separate module when both frontend and webhook code need it.",doNotEdit:"## Do Not Edit\n- `.phoenix/` directory — completely regenerated on each build\n- `tsconfig.json`, `eslint.config.js`, `prettier.config.js`, `.prettierignore`, `.linguirc`, `.nvmrc`\n- `src/locales/` .ts files — compiled from .po files",modelVersioning:"## Version the Domain Model Once It Is Deployed\nA deployed model version cannot change, because saved configurations depend on it. `pnpm phoenix deploy` is refused, before anything is uploaded, when the model differs from the one already deployed under the same version. The version is not written anywhere: `model.latest` is always the highest numbered version plus one, so a spec with only `latest` is v1, and `applicationVersion` plays no part. `pnpm phoenix dev` accepts every model change, so a working preview does not show that the deploy will pass.\n\nTo change a model that has been deployed as v<N>:\n1. Keep the deployed model, unchanged, as `model.v<N>` in the spec. A file of its own, such as `spec/model-v<N>.yaml`, keeps `latest` readable.\n2. Make the change in `model.latest`, which is now v<N+1>.\n3. Add `src/migrations/v<N+1>.ts` exporting `migrateToV<N+1>`. It receives the saved entities of v<N> and returns entities that are valid in v<N+1>; `ModelV<N>` and `ModelV<N+1>` are generated global namespaces.\n\nThe admin model is versioned on its own, under `src/admin/migrations/`, with its types in `AdminV<N>`.\n\n**Replacing the starter.** When the first deployment of the workspace was the starter, its `Box` model is v1 in production. When the real model replaces it, keep the starter's model as `model.v1` and define the real model in `latest`. Configurations saved from the starter are not worth converting, so the migration returns the starting state of the new model, the `initialDomainEntities` of its preset, and drops the boxes:\n```typescript\n// src/migrations/v2.ts\nimport type { Migration } from '@salsita-ai/sdk/domain'\n\nexport const migrateToV2: Migration<ModelV1.AnyDomainEntity, ModelV2.AnyDomainEntity> = () => [\n // the entities of the new model's preset\n]\n```\nAn entity of a type the new version no longer has must not stay in the returned state. An entity id starts with its type (`Box-1`), so an entity that keeps its data under a new type name needs a new id and every relation pointing at it rewritten. Read `docs/phoenix/migrations.mdx` before writing any other migration.",sdkDocumentation:'## SDK Documentation\n\nAlways search SDK docs for relevant examples before implementing Phoenix features.\n\n### Commands\n- `pnpm phoenix docs` — Full documentation index with descriptions\n- `pnpm phoenix docs -s <term>` — Search all doc content and metadata (case-insensitive)\n- `pnpm phoenix docs --dir` — Print the absolute docs directory for grep or ripgrep\n- `pnpm phoenix docs -r <path>` — Read specific doc (raw text to stdout)\n- `pnpm phoenix docs -c <category>` — List docs in a category\n- `pnpm phoenix docs -l` — List all doc paths with titles\n\n### Key Docs\n- `docs/phoenix/getting-started.mdx` — Setup, prerequisites, first project\n- `docs/phoenix/quickstart.mdx` — End-to-end tutorial building a configurator\n- `docs/phoenix/domain-model.mdx` — Entities, attributes, relations, specs\n- `docs/phoenix/components.mdx` — ECS pattern, YAML components, custom components\n- `docs/phoenix/project-structure.mdx` — Files, folders, conventions\n- `docs/phoenix/best-practices.mdx` — YAML-first, code patterns, common pitfalls\n- `docs/phoenix/state-management.mdx` — Reactive state, RxJS pipelines, data flow\n- `docs/phoenix/expression-context.mdx` — Expression API, context object, helpers\n- `docs/phoenix/webhooks.mdx` — Server-side finalization workflows\n- `docs/phoenix/finalization.mdx` — Finalization system, PDF/email/CSV generation\n- `docs/phoenix/migrations.mdx` — Schema versioning, migration files\n\n### Agent Workflow\n1. Find relevant docs by content: `pnpm phoenix docs -s \'camera\'`\n2. Read matching doc: `pnpm phoenix docs -r docs/3d-scene/cameras/transitions.mdx`\n3. Search within a doc: `pnpm phoenix docs -r <path> | grep "example"`\n4. Search titles only as a fallback: `pnpm phoenix docs -l | grep "camera"`\n5. Search generated files directly when needed: `grep -rn "camera" "$(pnpm phoenix docs --dir)"`\n6. Browse a topic area: `pnpm phoenix docs -c "Layouts"`',assetInspection:"## 3D Asset Inspection\n\nRun `pnpm phoenix inspect:assets` to discover all glTF/GLB files in `public/` and get a summary table. Use `--file <path>` for detailed single-file inspection.\n\n**When to use:** before writing YAML/code that references objectName, materialsToOverride, morphTargetInfluences, or object positioning.\n\n**What it shows per node:**\n- Name, type (Mesh/Light/Camera/Empty), children\n- Transform: `pos=`, `rot=`, `scale=` (only non-default values shown)\n- Per-node morph targets: `morphs=Width,Height`\n- Bounding box: `bounds=WxHxD` (width x height x depth in meters)\n- Origin placement: `origin=center`, `bottom-center`, `top-center`, `bottom-corner`, etc. with numerical offset\n\n**Use cases:**\n- Find exact node names for `objectName` in scene entity components\n- Find material names for `materialsToOverride`\n- Find morph target names for `morphTargetInfluences`\n- Check model dimensions (bounds) for positioning, dimension indicators, or invariants\n- Check origin placement to understand how models anchor (center vs bottom-center)\n- Use `--json` for programmatic access to all data\n\n**Flags:** `--objects`, `--materials`, `--morphs`, `--animations`, `--json`",screenshotCli:"## Screenshot CLI\n\nCapture 3D canvas screenshots from a running dev server via `pnpm phoenix screenshot`.\n\n**Prerequisites:**\n1. `phoenix dev` must be running (starts the WebSocket server on port 3020)\n2. Configurator must be open in a browser (the browser does the actual rendering)\n\n**Options:**\n- `--output, -o` — Output file path (default: `./screenshot.png`)\n- `--width, -w` — Width in pixels (default: 1920)\n- `--height` — Height in pixels (default: 1080)\n- `--format, -f` — Image format: PNG or JPEG (default: PNG)\n- `--port` — WebSocket server port (default: 3020)\n\n**Example workflow:**\n1. Start dev server: `pnpm phoenix dev`\n2. Open configurator in browser (or via Playwright MCP)\n3. Take screenshot: `pnpm phoenix screenshot -o ./render.png -w 2560 --height 1440`\n\n**Use cases:** visual regression testing, generating product images, debugging 3D renders",inspectState:"## Inspect: State\n\nGet the current editor runtime state as JSON via `pnpm phoenix inspect:state`.\n\n**Prerequisites:** same as screenshot (dev server running + browser open)\n\n**Options:**\n- `--output, -o` — Output file path (prints to stdout if omitted)\n- `--sections, -s` — Comma-separated: entities, navigation, validation (default: all)\n- `--pretty` — Pretty-print JSON (default: true)\n- `--port` — WebSocket server port (default: 3020)\n\n**Example:** `pnpm phoenix inspect:state -o ./state.json -s entities,navigation`\n\n**Lifecycle status:** Always included in response. Shows which systems are ready:\n- `domainLoaded` — domain data loaded\n- `domainContextReady` — domain context initialized (entities available)\n- `configuratorReady` — 3D configurator initialized\n- `sessionAuthenticated` — session service active\n- `editorMode` — editor mode enabled\n\n**Tips:** Use `--sections` to limit payload size. Pipe through `head`/`tail` for partial output (e.g., `pnpm phoenix inspect:state | head -50`).\n\n**Use cases:** AI agent context, debugging entity state, inspecting navigation/validation",inspectData:`## Inspect: Data
11
11
 
12
12
  Get the current editor context data as JSON via \`pnpm phoenix inspect:data\`.
13
13