openyida 2026.10.9-beta.1 → 2026.10.9

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 (273) hide show
  1. package/README.md +10 -32
  2. package/bin/yida.js +16 -33
  3. package/lib/app/app-entry.js +144 -0
  4. package/lib/app/app-list.js +1 -0
  5. package/lib/app/application-entry-urls.js +27 -1
  6. package/lib/app/application-style.js +67 -0
  7. package/lib/app/canvas-compile.js +7 -1
  8. package/lib/app/canvas-theme-guard.js +127 -10
  9. package/lib/app/check-prd-completeness.js +4 -15
  10. package/lib/app/compile.js +12 -2
  11. package/lib/app/create-form/args.js +37 -12
  12. package/lib/app/create-form/batch.js +41 -35
  13. package/lib/app/create-form.js +94 -57
  14. package/lib/app/create-page.js +5 -9
  15. package/lib/app/custom-theme.js +30 -37
  16. package/lib/app/fix-theme.js +34 -0
  17. package/lib/app/form-field-validator.js +0 -36
  18. package/lib/app/get-form-config.js +6 -0
  19. package/lib/app/get-schema.js +1 -6
  20. package/lib/app/prepare-app-theme-upgrade.js +104 -0
  21. package/lib/app/publish.js +69 -8
  22. package/lib/app/services/canvas-page-compiler.js +3 -1
  23. package/lib/app/services/form-compiler.js +0 -2
  24. package/lib/app/theme-from-design.js +77 -87
  25. package/lib/app/theme-scope.js +76 -0
  26. package/lib/app/update-app.js +64 -26
  27. package/lib/app/update-form-config.js +9 -19
  28. package/lib/app/upgrade-app-theme.js +169 -0
  29. package/lib/auth/token-auth.js +6 -57
  30. package/lib/auth/token-store.js +2 -26
  31. package/lib/core/agent-capabilities.js +1 -0
  32. package/lib/core/cli-error.js +1 -0
  33. package/lib/core/command-manifest.js +300 -232
  34. package/lib/core/locales/en.js +63 -52
  35. package/lib/core/locales/zh.js +63 -52
  36. package/lib/core/sample.js +36 -14
  37. package/lib/core/source-repair.js +38 -0
  38. package/lib/core/theme-brand-scale.js +133 -0
  39. package/lib/core/update.js +1 -3
  40. package/lib/core/utils.js +0 -29
  41. package/lib/design/check-design.js +16 -6
  42. package/lib/design/document.js +37 -15
  43. package/lib/design/icon-contrast.js +1 -1
  44. package/lib/design/palette-contrast.js +77 -0
  45. package/lib/design-plan/confirmation.js +13 -0
  46. package/lib/design-plan/design-plan.js +65 -8
  47. package/lib/design-plan/entry-navigation.js +19 -2
  48. package/lib/design-plan/init.js +19 -11
  49. package/lib/design-plan/materialize.js +93 -61
  50. package/lib/design-plan/normalize.js +13 -14
  51. package/lib/design-plan/parallel.js +62 -13
  52. package/lib/design-plan/patch.js +21 -7
  53. package/lib/design-plan/preview.js +4 -1
  54. package/lib/design-plan/rebase.js +69 -0
  55. package/lib/design-plan/themes.js +16 -1
  56. package/lib/design-plan/validate.js +18 -3
  57. package/lib/design-plan/visual-policy.js +29 -4
  58. package/lib/page-config/save-share-config.js +5 -16
  59. package/lib/samples/openyida-scaffold/canvas-form-drawer.canvas.jsx +3 -3
  60. package/lib/samples/openyida-scaffold/canvas-nav/mixed.jsx +6 -4
  61. package/lib/samples/openyida-scaffold/canvas-nav/shared.jsx +5 -5
  62. package/lib/samples/openyida-scaffold/canvas-nav/side.jsx +1 -2
  63. package/lib/samples/openyida-scaffold/canvas-nav/sidebar.jsx +1 -1
  64. package/lib/samples/openyida-scaffold/canvas-nav/top.jsx +5 -4
  65. package/package.json +3 -11
  66. package/scripts/postinstall.js +1 -1
  67. package/yida-skills/SKILL.md +5 -26
  68. package/yida-skills/references/official-example-schema-patterns.md +1 -1
  69. package/yida-skills/references/source-repair.md +10 -0
  70. package/yida-skills/references/yida-api.md +4 -0
  71. package/yida-skills/skills/yida-app/SKILL.md +16 -5
  72. package/yida-skills/skills/yida-app/references/entry-navigation.md +13 -9
  73. package/yida-skills/skills/yida-app/workflow/plan/step-4-deliver.md +3 -1
  74. package/yida-skills/skills/yida-app/workflow/plan/workflow.md +21 -5
  75. package/yida-skills/skills/yida-app/workflow/step-2-design.md +4 -4
  76. package/yida-skills/skills/yida-app/workflow/step-3-create-or-reuse-app.md +2 -2
  77. package/yida-skills/skills/yida-app/workflow/step-6-main-page.md +1 -1
  78. package/yida-skills/skills/yida-app/workflow/step-7-page-code.md +1 -1
  79. package/yida-skills/skills/yida-app/workflow/step-8-publish-navigation.md +5 -5
  80. package/yida-skills/skills/yida-app/workflow/step-9-output-finish.md +27 -4
  81. package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +3 -2
  82. package/yida-skills/skills/yida-canvas-custom-page/references/canvas-style-implementation-guide.md +6 -5
  83. package/yida-skills/skills/yida-canvas-custom-page/references/canvas-theme-provider.md +4 -2
  84. package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +140 -1
  85. package/yida-skills/skills/yida-canvas-custom-page/references/navigation-and-entry-guide.md +1 -1
  86. package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +6 -6
  87. package/yida-skills/skills/yida-canvas-custom-page/references/waf-safe-authoring.md +45 -0
  88. package/yida-skills/skills/yida-canvas-custom-page/scripts/build-canvas-theme.js +2 -1
  89. package/yida-skills/skills/yida-canvas-custom-page/scripts/canvas-theme-provider.template.jsx +8 -1
  90. package/yida-skills/skills/yida-canvas-data-binding/SKILL.md +13 -0
  91. package/yida-skills/skills/yida-canvas-upgrade/SKILL.md +4 -0
  92. package/yida-skills/skills/yida-create-form-page/SKILL.md +36 -43
  93. package/yida-skills/skills/yida-create-form-page/references/advanced-form-modes.md +5 -5
  94. package/yida-skills/skills/yida-create-form-page/references/association-form-field.md +4 -4
  95. package/yida-skills/skills/yida-create-form-page/references/batch-forms.md +2 -2
  96. package/yida-skills/skills/yida-create-form-page/references/field-definition-guide.md +20 -16
  97. package/yida-skills/skills/yida-create-form-page/references/form-field-properties.md +21 -42
  98. package/yida-skills/skills/yida-create-page/SKILL.md +1 -1
  99. package/yida-skills/skills/yida-dashboard/SKILL.md +1 -1
  100. package/yida-skills/skills/yida-design/SKILL.md +25 -13
  101. package/yida-skills/skills/yida-design/references/application-style-library.md +93 -0
  102. package/yida-skills/skills/yida-design/references/application-theme-consistency.md +96 -9
  103. package/yida-skills/skills/yida-design/references/ask-human-interaction-contract.md +1 -1
  104. package/yida-skills/skills/yida-design/references/native-form-styles.md +266 -0
  105. package/yida-skills/skills/yida-design/references/navigation-decision.md +10 -6
  106. package/yida-skills/skills/yida-design/references/page-quality-gates.md +10 -4
  107. package/yida-skills/skills/yida-design/references/task-driven-visual-design.md +59 -0
  108. package/yida-skills/skills/yida-design/references/theme/app-custom-theme-template.css +596 -235
  109. package/yida-skills/skills/yida-design/references/theme/application-style-recipes.css +58 -0
  110. package/yida-skills/skills/yida-design/references/theme/theme-token-presets.md +3 -1
  111. package/yida-skills/skills/yida-design/references/theme-selection.md +24 -11
  112. package/yida-skills/skills/yida-design/references/visual-decision-engine.md +1 -1
  113. package/yida-skills/skills/yida-design/references/visual-scaffold-recipes.md +13 -40
  114. package/yida-skills/skills/yida-design/scripts/validate_design_themes.py +52 -7
  115. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/SKILL.md +16 -4
  116. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-compact-schema.md +6 -2
  117. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-schema.md +5 -3
  118. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/page-patterns.md +6 -4
  119. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/visual-design.md +3 -1
  120. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/visual-theme-selection.md +26 -27
  121. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/scripts/render_build_plan.py +2 -0
  122. package/yida-skills/skills/yida-design/templates/design-themes/README.md +20 -10
  123. package/yida-skills/skills/yida-design/templates/design-themes/app-amber/app_theme.css +809 -0
  124. package/yida-skills/skills/yida-design/templates/design-themes/app-amber/design.md +248 -0
  125. package/yida-skills/skills/yida-design/templates/design-themes/app-amber/form-layout.json +15 -0
  126. package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/app_theme.css +809 -0
  127. package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/design.md +241 -0
  128. package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/form-layout.json +14 -0
  129. package/yida-skills/skills/yida-design/templates/design-themes/app-executive/app_theme.css +809 -0
  130. package/yida-skills/skills/yida-design/templates/design-themes/app-executive/design.md +241 -0
  131. package/yida-skills/skills/yida-design/templates/design-themes/app-executive/form-layout.json +13 -0
  132. package/yida-skills/skills/yida-design/templates/design-themes/app-finance/app_theme.css +809 -0
  133. package/yida-skills/skills/yida-design/templates/design-themes/app-finance/design.md +240 -0
  134. package/yida-skills/skills/yida-design/templates/design-themes/app-finance/form-layout.json +14 -0
  135. package/yida-skills/skills/yida-design/templates/design-themes/app-glass/app_theme.css +809 -0
  136. package/yida-skills/skills/yida-design/templates/design-themes/app-glass/design.md +241 -0
  137. package/yida-skills/skills/yida-design/templates/design-themes/app-glass/form-layout.json +14 -0
  138. package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/app_theme.css +809 -0
  139. package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/design.md +241 -0
  140. package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/form-layout.json +14 -0
  141. package/yida-skills/skills/yida-design/templates/design-themes/app-line/app_theme.css +809 -0
  142. package/yida-skills/skills/yida-design/templates/design-themes/app-line/design.md +241 -0
  143. package/yida-skills/skills/yida-design/templates/design-themes/app-line/form-layout.json +13 -0
  144. package/yida-skills/skills/yida-design/templates/design-themes/app-neon/app_theme.css +809 -0
  145. package/yida-skills/skills/yida-design/templates/design-themes/app-neon/design.md +239 -0
  146. package/yida-skills/skills/yida-design/templates/design-themes/app-neon/form-layout.json +14 -0
  147. package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/app_theme.css +809 -0
  148. package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/design.md +241 -0
  149. package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/form-layout.json +13 -0
  150. package/yida-skills/skills/yida-design/templates/design-themes/app-paper/app_theme.css +809 -0
  151. package/yida-skills/skills/yida-design/templates/design-themes/app-paper/design.md +239 -0
  152. package/yida-skills/skills/yida-design/templates/design-themes/app-paper/form-layout.json +13 -0
  153. package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/app_theme.css +809 -0
  154. package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/design.md +241 -0
  155. package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/form-layout.json +14 -0
  156. package/yida-skills/skills/yida-design/templates/design-themes/app-plum/app_theme.css +809 -0
  157. package/yida-skills/skills/yida-design/templates/design-themes/app-plum/design.md +241 -0
  158. package/yida-skills/skills/yida-design/templates/design-themes/app-plum/form-layout.json +14 -0
  159. package/yida-skills/skills/yida-design/templates/design-themes/app-pop/app_theme.css +809 -0
  160. package/yida-skills/skills/yida-design/templates/design-themes/app-pop/design.md +241 -0
  161. package/yida-skills/skills/yida-design/templates/design-themes/app-pop/form-layout.json +14 -0
  162. package/yida-skills/skills/yida-design/templates/design-themes/app-sage/app_theme.css +809 -0
  163. package/yida-skills/skills/yida-design/templates/design-themes/app-sage/design.md +241 -0
  164. package/yida-skills/skills/yida-design/templates/design-themes/app-sage/form-layout.json +14 -0
  165. package/yida-skills/skills/yida-design/templates/design-themes/app-teal/app_theme.css +809 -0
  166. package/yida-skills/skills/yida-design/templates/design-themes/app-teal/design.md +241 -0
  167. package/yida-skills/skills/yida-design/templates/design-themes/app-teal/form-layout.json +14 -0
  168. package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/app_theme.css +809 -0
  169. package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/design.md +240 -0
  170. package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/form-layout.json +14 -0
  171. package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/app_theme.css +809 -0
  172. package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/design.md +243 -0
  173. package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/form-layout.json +13 -0
  174. package/yida-skills/skills/yida-design/templates/design-themes/app-wire/app_theme.css +809 -0
  175. package/yida-skills/skills/yida-design/templates/design-themes/app-wire/design.md +240 -0
  176. package/yida-skills/skills/yida-design/templates/design-themes/app-wire/form-layout.json +14 -0
  177. package/yida-skills/skills/yida-design/templates/design-themes/basic-tokens.json +2 -7
  178. package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/app_theme.css +748 -0
  179. package/yida-skills/skills/yida-design/templates/design-themes/{dark-inset-hairline.md → dark-inset-hairline/design.md} +100 -59
  180. package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/form-layout.json +13 -0
  181. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/app_theme.css +756 -0
  182. package/yida-skills/skills/yida-design/templates/design-themes/{dark-rail-fine-lines.md → dark-rail-fine-lines/design.md} +102 -53
  183. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/form-layout.json +13 -0
  184. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/app_theme.css +754 -0
  185. package/yida-skills/skills/yida-design/templates/design-themes/{dark-rail-signal-panels.md → dark-rail-signal-panels/design.md} +62 -13
  186. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/form-layout.json +13 -0
  187. package/yida-skills/skills/yida-design/templates/design-themes/free-creative/app_theme.css +750 -0
  188. package/yida-skills/skills/yida-design/templates/design-themes/free-creative/design.md +204 -0
  189. package/yida-skills/skills/yida-design/templates/design-themes/free-creative/form-layout.json +13 -0
  190. package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/app_theme.css +750 -0
  191. package/yida-skills/skills/yida-design/templates/design-themes/{graphite-bevel-grid.md → graphite-bevel-grid/design.md} +58 -11
  192. package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/form-layout.json +13 -0
  193. package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/app_theme.css +749 -0
  194. package/yida-skills/skills/yida-design/templates/design-themes/{hairline-shared-bands.md → hairline-shared-bands/design.md} +60 -13
  195. package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/form-layout.json +13 -0
  196. package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/app_theme.css +749 -0
  197. package/yida-skills/skills/yida-design/templates/design-themes/{hairline-soft-blocks.md → hairline-soft-blocks/design.md} +57 -13
  198. package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/form-layout.json +13 -0
  199. package/yida-skills/skills/yida-design/templates/design-themes/index.json +390 -35
  200. package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/app_theme.css +759 -0
  201. package/yida-skills/skills/yida-design/templates/design-themes/{ink-glow-soft-panels.md → ink-glow-soft-panels/design.md} +55 -9
  202. package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/form-layout.json +13 -0
  203. package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/app_theme.css +749 -0
  204. package/yida-skills/skills/yida-design/templates/design-themes/{inset-frame-pixel-rhythm.md → inset-frame-pixel-rhythm/design.md} +57 -10
  205. package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/form-layout.json +13 -0
  206. package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/app_theme.css +756 -0
  207. package/yida-skills/skills/yida-design/templates/design-themes/{outlined-texture-duotone.md → outlined-texture-duotone/design.md} +59 -13
  208. package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/form-layout.json +13 -0
  209. package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/app_theme.css +749 -0
  210. package/yida-skills/skills/yida-design/templates/design-themes/{soft-inset-surfaces.md → soft-inset-surfaces/design.md} +56 -12
  211. package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/form-layout.json +13 -0
  212. package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/app_theme.css +748 -0
  213. package/yida-skills/skills/yida-design/templates/design-themes/{soft-outline-rhythm.md → soft-outline-rhythm/design.md} +56 -26
  214. package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/form-layout.json +13 -0
  215. package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/app_theme.css +756 -0
  216. package/yida-skills/skills/yida-design/templates/design-themes/{soft-rail-bold-band.md → soft-rail-bold-band/design.md} +101 -55
  217. package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/form-layout.json +13 -0
  218. package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/app_theme.css +769 -0
  219. package/yida-skills/skills/yida-design/templates/design-themes/{warm-canvas-contrast-panels.md → warm-canvas-contrast-panels/design.md} +60 -14
  220. package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/form-layout.json +13 -0
  221. package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/app_theme.css +750 -0
  222. package/yida-skills/skills/yida-design/templates/design-themes/{warm-rail-muted-panels.md → warm-rail-muted-panels/design.md} +98 -54
  223. package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/form-layout.json +13 -0
  224. package/yida-skills/skills/yida-design/workflow/output-design.md +46 -8
  225. package/yida-skills/skills/yida-design/workflow/step-2-theme-system.md +21 -6
  226. package/yida-skills/skills/yida-design/workflow/step-4-wireframe-interaction.md +7 -5
  227. package/yida-skills/skills/yida-design/workflow/step-5-visual-states.md +1 -0
  228. package/yida-skills/skills/yida-design/workflow/step-6-handoff.md +3 -1
  229. package/yida-skills/skills/yida-document-markdown/SKILL.md +0 -6
  230. package/yida-skills/skills/yida-export-conversation/SKILL.md +0 -1
  231. package/yida-skills/skills/yida-form-permission/SKILL.md +6 -0
  232. package/yida-skills/skills/yida-image-assets/SKILL.md +3 -1
  233. package/yida-skills/skills/yida-image-assets/references/manifest-contract.md +2 -0
  234. package/yida-skills/skills/yida-nav-shell/SKILL.md +5 -3
  235. package/yida-skills/skills/yida-nav-shell/references/nav-shell-patterns.md +6 -0
  236. package/yida-skills/skills/yida-page-config/SKILL.md +11 -2
  237. package/yida-skills/skills/yida-prd/SKILL.md +4 -1
  238. package/yida-skills/skills/yida-prd/references/app/role-journey.md +1 -1
  239. package/yida-skills/skills/yida-prd/references/plan-content.md +1 -1
  240. package/yida-skills/skills/yida-prd/workflow/output-prd.md +7 -7
  241. package/yida-skills/skills/yida-prd/workflow/plan-business.md +2 -0
  242. package/yida-skills/skills/yida-prd/workflow/step-2-information-architecture.md +13 -4
  243. package/yida-skills/skills/yida-publish-page/SKILL.md +29 -18
  244. package/yida-skills/skills/yida-requirement-analysis/references/experience-groups.md +48 -12
  245. package/yida-skills/skills/yida-requirement-analysis/references/handoff.md +6 -6
  246. package/yida-skills/skills/yida-requirement-analysis/workflow/prepare-brief.md +17 -4
  247. package/yida-skills/skills/yida-tingji/SKILL.md +0 -4
  248. package/yida-skills/skills/yida-upgrade-app-theme/SKILL.md +61 -0
  249. package/yida-skills/skills/yida-upgrade-app-theme/references/page-migration.md +61 -0
  250. package/yida-skills/skills-index.json +35 -5
  251. package/lib/agent/PROTOCOL.md +0 -182
  252. package/lib/agent/ask-human.js +0 -151
  253. package/lib/agent/cmd.js +0 -405
  254. package/lib/agent/command-receipt.js +0 -84
  255. package/lib/agent/connection-store.js +0 -148
  256. package/lib/agent/diagnostic-log.js +0 -133
  257. package/lib/agent/frozen-bundle.js +0 -286
  258. package/lib/agent/managed-command-map.js +0 -36
  259. package/lib/agent/managed-context.js +0 -40
  260. package/lib/agent/managed-run.js +0 -85
  261. package/lib/agent/mutation-receipt.js +0 -82
  262. package/lib/agent/private-directory.js +0 -63
  263. package/lib/agent/provider-preflight.js +0 -252
  264. package/lib/agent/providers.js +0 -4
  265. package/lib/agent/runtime-catalog.json +0 -42
  266. package/lib/agent/runtime-manifest.js +0 -96
  267. package/lib/agent/runtime-package.js +0 -155
  268. package/lib/agent/stdio.js +0 -321
  269. package/lib/auth/profile-lock.js +0 -89
  270. package/lib/core/managed-policy.js +0 -81
  271. package/yida-skills/references/local-agent-diagnostics.md +0 -154
  272. package/yida-skills/references/local-agent-preflight.md +0 -56
  273. package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels.md +0 -337
package/README.md CHANGED
@@ -118,6 +118,7 @@ The agent can then call OpenYida commands to create the application, generate so
118
118
  | [Codex](https://openai.com/codex/) | Full support |
119
119
  | [Claude Code](https://claude.ai/code) | Full support |
120
120
  | [MuleRun](https://mulerun.com) | Full support |
121
+ | [OpenCode](https://opencode.ai) | Full support |
121
122
  | [Cursor](https://cursor.com/) | Full support |
122
123
  | [Visual Studio Code](https://code.visualstudio.com/) | Full support |
123
124
  | QwenWork(千问办公) | Full support |
@@ -182,7 +183,7 @@ openyida get-schema APP_XXX FORM_XXX --compact --resolve-fields "Customer Name,S
182
183
  openyida get-schema APP_XXX --all --output-dir .cache/schemas
183
184
  ```
184
185
 
185
- Form definitions support 19 business field types plus verified presentation/layout components. Prefer `Divider` for section titles and `ColumnContainer` (mapped to `ColumnsLayout` + `Column`) for multi-column layout; use `GroupContainer` / `PageSection` only when an actual grouping container is needed.
186
+ Native forms use a component tree: business fields capture data, tabs switch content, action groups trigger business actions, images establish visual focus, status areas provide feedback, and `Divider` plus `ColumnContainer` organize hierarchy and columns. `create-form` field definitions create 19 business field types plus `Divider` and `ColumnContainer` (mapped to `ColumnsLayout` + `Column`), while updates retain other existing components.
186
187
 
187
188
  ### Custom Page Development
188
189
 
@@ -392,15 +393,18 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
392
393
 
393
394
  | Command | Description |
394
395
  |---------|-------------|
396
+ | `openyida app-entry get <appType> [--json]` | Read frontend and management runtime entries |
397
+ | `openyida app-entry set <appType> [--frontend <url>\|--frontend-page <formUuid>] [--management <url>\|--management-page <formUuid>] [--clear-frontend] [--clear-management] [--json]` | Register application entries with partial update and readback |
395
398
  | `openyida app-list [--type managed\|created] [--page N] [--size N]` | Page through apps I manage or created |
396
399
  | `openyida corp-efficiency [overview\|details\|detail\|groups\|notify] [options] [--open\|--no-open]` | Query enterprise efficiency overview and detail reports |
397
400
  | `openyida create-app "<name>"\|--name <name> [options] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a Yida app |
398
401
  | `openyida design-plan catalog [--json]` | List available planning themes and page patterns |
399
402
  | `openyida design-plan init <requirement-brief.json> [--theme-id <id>] [--output-dir <dir>] [--json]` | Initialize a plan draft from confirmed requirements |
400
403
  | `openyida design-plan preview <build-plan.json> --part-file <module.json> [--json]` | Update plan drafts by module |
401
- | `openyida design-plan materialize <build-plan.json> [--from-preview \| --business-file <json> --visual-file <json>] [--output-dir <dir>] [--check] [--json]` | Generate or update plan documents and theme with consistency checks |
404
+ | `openyida design-plan materialize <build-plan.json> [--from-preview \| --business-file <json> --visual-file <json>] [--output-dir <dir>] [--rebase-parts] [--check] [--json]` | Generate or update plan documents and theme with consistency checks |
402
405
  | `openyida design-plan patch <build-plan.json> --set <path=value> [--set <path=value> ...] [--materialize] [--output-dir <dir>] [--json]` | Patch plan fields and optionally sync documents and theme |
403
406
  | `openyida update-app <appType> [--name "..."] [--desc "..."] [--icon <name>] [--icon-color <color>] [--colour <key>] [--theme-color <color>] [--theme-file <css>] [--nav-theme light\|dark\|white\|gray] [--logo-source appIcon\|customImage] [--layout side\|top\|l_shape] [--hide-app-nav\|--show-app-nav]` | Update app info |
407
+ | `openyida upgrade-app-theme <appType> --explicit-request [--confirm \| --prepare --output-dir <dir>] [--json]` | Upgrade an AI-built legacy app theme (explicit request and ask_human confirmation required) |
404
408
  | `openyida app-online <appType> [--to-ding-app-center] [--show-app-center]` | Enable a Yida app |
405
409
  | `openyida app-offline <appType> [--to-ding-app-center] [--show-app-center]` | Disable a Yida app |
406
410
  | `openyida nav-group <list\|create\|rename\|delete\|move\|order\|auto-order\|hide\|show> <appType> ...` | Manage app sidebar navigation groups |
@@ -414,7 +418,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
414
418
  | Command | Description |
415
419
  |---------|-------------|
416
420
  | `openyida create-form batch <appType> <plan.json> [--concurrency 1..4] [--check] [--json]` | Create forms concurrently by dependency |
417
- | `openyida create-form create <appType> "<formTitle>" <fieldsJsonFile> [--icon auto\|<iconName>] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a form page |
421
+ | `openyida create-form create <appType> "<formTitle>" <fieldsJsonFile> [--layout single\|double\|card\|section] [--theme default\|compact\|comfortable] [--label-align top\|left\|right] [--icon auto\|<iconName>] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a form page |
418
422
  | `openyida create-form icons [--json]` | List available form navigation icons |
419
423
  | `openyida create-form validate-fields <fieldsJsonOrFile> [--json]` | Validate form field JSON locally |
420
424
  | `openyida create-form update <appType> <formUuid> (<changesJsonOrFile> \| --data-file <changesJsonOrFile>) [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Update a form page |
@@ -434,8 +438,8 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
434
438
  | `openyida create-page <appType> "<name>" [--mode dashboard] [--hide-nav] [--locale zh_CN\|en_US\|ja_JP] [--open\|--no-open]` | Create a custom display page |
435
439
  | `openyida build-page <sourceFile> [--output file\|--write]` | Build Yida-compatible page source |
436
440
  | `openyida check-page <src> [--compat] [--json]` | Check custom page standards |
437
- | `openyida compile <src> [--canvas] [--compat] [--skip-lint] [--json]` | Compile custom page locally |
438
- | `openyida publish <src> <appType> <formUuid> [--health-check] [--force] [--canvas] [--compat] [--skip-lint] [--auto-nav-order] [--open\|--no-open] [--json]` | Compile and publish custom page |
441
+ | `openyida compile <src> [--canvas] [--compat] [--skip-lint] [--strict-theme\|--allow-fixed-brand] [--json]` | Compile custom page locally |
442
+ | `openyida publish <src> <appType> <formUuid> [--health-check] [--force] [--canvas] [--compat] [--skip-lint] [--fix-theme] [--strict-theme] [--allow-fixed-brand] [--auto-nav-order] [--open\|--no-open] [--json]` | Compile and publish custom page |
439
443
  | `openyida update-form-config <appType> <formUuid> <true\|false\|keep> "<title>" [--locale zh_CN\|en_US\|ja_JP]` | Update form configuration |
440
444
  | `openyida get-form-config <appType> <formUuid> [--json]` | Query form configuration |
441
445
 
@@ -519,11 +523,10 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
519
523
  |---------|-------------|
520
524
  | `openyida commands [--json]` | Output machine-readable command manifest |
521
525
  | `openyida agent-capabilities [--json] [--summary-json\|--compact]` | Output one-shot agent capability snapshot |
522
- | `openyida agent <doctor\|diagnose\|status\|connect\|run\|disconnect\|logout\|logs> [options]` | Connect a local Agent (Go runtime, development preview) |
523
526
  | `openyida a2a <serve\|agent-card> [options]` | Start local read-only A2A adapter or print Agent Card |
524
527
  | `openyida bridge start [--token <pair-token>] [--port 6736] [--origin https://demo.aliwork.com] [--open\|--no-open]` | Start OpenYida local web bridge service |
525
528
  | `openyida copy [--force]` | Copy project working directory |
526
- | `openyida sample [--list] [<skill> <name>] [--output <file>] [--var KEY=VALUE ...] [--design-file <design.md>]` | Output code samples/templates |
529
+ | `openyida sample [--list] [<skill> <name>] [--output <file-or-directory>] [--var KEY=VALUE ...] [--design-file <design.md>] [--style-id <themeId\|free-creative>]` | Output code samples/templates |
527
530
  | `openyida doctor [--fix]` | Environment diagnostics & auto-fix |
528
531
  | `openyida db-seq-fix [--fix]` | Detect and repair PostgreSQL sequence drift |
529
532
  | `openyida formula evaluate <formula\|file> [--schema file]` | Static-check Yida formula syntax and field refs |
@@ -588,31 +591,6 @@ Form field definitions can include `alias` or `componentAlias` to populate Yida
588
591
 
589
592
  `openyida integration create` supports form events (`insert`, `update`, `delete`, `comment`) and approval events (`processFinish`, `activityTask`; aliases: `approval`, `approvalNode`). Approval events require `--approval-actions agree,disagree,terminated`; `activityTask` also requires `--approval-node-ids <nodeId,...>`. Passing `--process-code` selects a full graph replacement and now requires explicit `--replace`; it is not a safe update. `integration update` currently performs capability detection only: because full platform `processJson` + `viewJson` readback is unproven, it writes a redacted local probe artifact and returns `PLATFORM_PROBE_REQUIRED` before authentication, spec reading, or remote writes. It does not edit a flow.
590
593
 
591
- ### Local Agent development preview
592
-
593
- `openyida agent` is a thin Node launcher for a separately supplied Go runtime. Node does not connect to the agent service or manage provider sessions. Platform runtime packages are **not published** in this preview; no Go executable is discovered on `PATH` and no provider is installed or invoked by Node.
594
-
595
- The Local Agent Beta production allowlist contains macOS and Windows only. Linux remains supported by the ordinary OpenYida CLI and by the explicit development-runtime workflow below, but Linux Local Agent packages are not published and production `connect`/`run` are rejected until native acceptance is complete.
596
-
597
- ```bash
598
- openyida agent doctor --json
599
- openyida agent doctor --development-runtime --runtime-path /absolute/path/openyida-runtime --runtime-manifest /absolute/path/runtime-manifest.json
600
- openyida agent connect --development-runtime --runtime-path /absolute/path/openyida-runtime --runtime-manifest /absolute/path/runtime-manifest.json --endpoint https://agent.example.test --endpoint-id configured-platform-id
601
- openyida agent run --development-runtime --runtime-path /absolute/path/openyida-runtime --runtime-manifest /absolute/path/runtime-manifest.json --endpoint https://agent.example.test --endpoint-id configured-platform-id --provider qoder --provider-path /absolute/path/qodercli
602
- ```
603
-
604
- Development manifest v1 specifies runtime version, protocol `1`, Node-style OS/architecture names, and `binary: {file, sha256}`; it requires the explicit `--development-runtime` flag. This is an integrity check, **not a publisher signature**. The production loader requires a strictly validated v2 manifest, exact approved platform-package version/digest, and an Ed25519 signature over the original manifest bytes using trust roots bundled in the Node host. The release catalog is currently empty: no production signing key or package is implied to exist. See the [launcher contract](lib/agent/PROTOCOL.md).
605
-
606
- `connect` supports two equivalent enrollment entries. CLI-first opens the Yida browser approval page and returns through a state/PKCE-protected loopback callback. Web-first copies one five-minute command containing `--enroll`; the token is single-use and carries no business authority. Neither path reads or uploads an ordinary OpenYida login profile.
607
-
608
- One installation may connect to multiple organizations. Node keeps only a shared Installation ID at the installation root; each organization authorization gets an isolated private Connection state directory, device credentials, journals, control socket, and frozen bundle. `agent connect` keeps the new Connection online in the foreground, while `agent run`, `status`, `disconnect`, and `logout` enumerate every valid Connection. Each Connection registers all locally discovered Qoder and Codex Runtimes, and the web UI selects computer, CLI, and model.
609
-
610
- For each attempt, Go injects `OPENYIDA_MANAGED_RUN=1`, the cloud user/corp/app/run/attempt context, and a fixed-value Tianshu task grant with an initial 60-minute lease. The CLI uses that grant instead of local auth and sends scope-correlation headers. While the authenticated device connection and server-side Run remain active, yida-agent can renew the same bearer server-to-server; the CLI cannot renew it and never receives a task refresh token. Tianshu independently checks the grant against the requested app and rejects application creation, identity/environment changes, arbitrary batches, and cross-application requests. `formUuid` remains optional per-turn page-focus context, so one app-bound session can work across pages in that application. Without `OPENYIDA_MANAGED_RUN`, existing login, token refresh, and command behavior are unchanged.
611
-
612
- Before `connect` or `run`, Node now freezes the verified runtime bytes, CLI, full production dependency closure, and packaged Skills into a private content-addressed bundle. Source changes during copying fail closed. Existing bundles are verified, never silently repaired or garbage-collected by Node, and survive replacement/removal of the original npm directory. Go owns active/session references and version activation; the external Node executable and provider installations are not copied or managed by npm. A separate parent-watch pipe and a 15-second stop grace prevent normal config EOF from being mistaken for parent death; an unconfirmed forced stop remains unknown.
613
-
614
- This is not an OS sandbox or an authorization boundary against arbitrary shell code. Production signing/release infrastructure, full Go/provider recovery and upgrade acceptance, and OS/architecture-specific provider E2E are not claimed by these fake-process tests. Auto-update is disabled for `agent` and managed invocations; ordinary CLI commands neither spawn nor download the runtime.
615
-
616
594
  ## Agent Skills
617
595
 
618
596
  The `yida-skills/` directory is the source skill library used by OpenYida during development and distributed with the npm package.
package/bin/yida.js CHANGED
@@ -24,8 +24,6 @@ const { COMMAND_GROUPS, buildCommandManifest, findCommandSuggestion } = require(
24
24
  const command = process.argv[2];
25
25
  const args = process.argv.slice(3);
26
26
  const rawArgs = process.argv.slice(3);
27
- const { beginCommandReceipt } = require('../lib/agent/command-receipt');
28
- let commandReceipt;
29
27
 
30
28
  function shouldUseEnvManagement(argsList) {
31
29
  const subCommand = argsList[0];
@@ -573,26 +571,6 @@ function assertNoUnsupportedLegacyLoginFlags(...argLists) {
573
571
  }
574
572
 
575
573
  async function main() {
576
- const { assertManagedInvocation, resolveManagedHelp } = require('../lib/agent/managed-run');
577
- const { readManagedContext } = require('../lib/agent/managed-context');
578
- if (readManagedContext() && [command, ...rawArgs].some(arg => arg === '--help' || arg === '-h')) {
579
- assertManagedInvocation(command, rawArgs);
580
- const entries = resolveManagedHelp(command, rawArgs, { t, version: currentVersion });
581
- // Managed help is static and local: no Receipt, auth, update, first-run
582
- // guide or business command module may run on this path.
583
- commandReceipt = { finish() {} };
584
- if (rawArgs.includes('--json')) {
585
- console.log(JSON.stringify({ name: 'openyida', version: currentVersion, commands: entries }, null, 2));
586
- } else {
587
- printCommandUsage(...entries.flatMap(entry => [entry.usage, entry.description, ...(entry.examples || [])]));
588
- }
589
- return;
590
- }
591
- commandReceipt = beginCommandReceipt({ command, args: rawArgs });
592
- process.once('exit', code => {
593
- try {commandReceipt.finish(code);} catch {process.exitCode = 1;}
594
- });
595
- assertManagedInvocation(command, rawArgs);
596
574
  applyQuietFlag();
597
575
  applyGlobalEnvironmentFlags();
598
576
 
@@ -641,12 +619,6 @@ async function main() {
641
619
  break;
642
620
  }
643
621
 
644
- case 'agent': {
645
- const { run } = require('../lib/agent/cmd');
646
- await run(args);
647
- break;
648
- }
649
-
650
622
  case 'mcp': {
651
623
  const { runStdioServer } = require('../lib/mcp/server');
652
624
  runStdioServer();
@@ -761,6 +733,12 @@ async function main() {
761
733
  break;
762
734
  }
763
735
 
736
+ case 'app-entry': {
737
+ const { run } = require('../lib/app/app-entry');
738
+ await run(args);
739
+ break;
740
+ }
741
+
764
742
  case 'app-list': {
765
743
  const { run } = require('../lib/app/app-list');
766
744
  await run(args);
@@ -916,8 +894,8 @@ async function main() {
916
894
  if (args.length < 4) {
917
895
  throwCliUsage(t('cli.form_config_usage'), t('cli.form_config_example'));
918
896
  }
919
- const { run: runUpdateFormConfig } = require('../lib/app/update-form-config');
920
- await runUpdateFormConfig(args);
897
+ process.argv = [process.argv[0], process.argv[1], ...args];
898
+ require('../lib/app/update-form-config');
921
899
  break;
922
900
  }
923
901
 
@@ -936,6 +914,11 @@ async function main() {
936
914
  break;
937
915
  }
938
916
 
917
+ case 'upgrade-app-theme': {
918
+ await require('../lib/app/upgrade-app-theme').run(args);
919
+ break;
920
+ }
921
+
939
922
  case 'app-online':
940
923
  case 'app-offline': {
941
924
  const { run: runAppLifecycle } = require('../lib/app/app-lifecycle');
@@ -1303,9 +1286,7 @@ async function main() {
1303
1286
  }
1304
1287
 
1305
1288
  main()
1306
- .then(() => { commandReceipt.finish(process.exitCode || 0); })
1307
1289
  .catch((err) => {
1308
- try {commandReceipt?.finish(err && err.exitCode ? err.exitCode : 1);} catch { /* Intent remains recoverable. */ }
1309
1290
  if (shouldUseStructuredErrorOutput(err, args)) {
1310
1291
  console.error(JSON.stringify(toErrorPayload(err), null, 2));
1311
1292
  } else if (isCliError(err)) {
@@ -1316,5 +1297,7 @@ main()
1316
1297
  } else {
1317
1298
  warn(t('cli.exec_failed', err.message));
1318
1299
  }
1319
- process.exit(err && err.exitCode ? err.exitCode : 1);
1300
+ // Let pending stdout/stderr writes drain, especially large JSON diagnostics
1301
+ // sent through pipes on macOS/Linux. process.exit() can truncate them.
1302
+ process.exitCode = err && err.exitCode ? err.exitCode : 1;
1320
1303
  });
@@ -0,0 +1,144 @@
1
+ 'use strict';
2
+
3
+ const { createAuthRef, createYidaClient, unwrapYidaResponse } = require('../core/yida-client');
4
+ const { t } = require('../core/i18n');
5
+ const { throwUsage } = require('../core/command-errors');
6
+ const { fetchFormPageList } = require('./form-navigation');
7
+
8
+ /** Keep complete runtime URLs; the server verifies tenant and resource ownership. */
9
+ function normalizeUrl(value, appType) {
10
+ const input = String(value || '').trim();
11
+ if (!input) { throw new Error(t('app_entry.invalid_url')); }
12
+ // eslint-disable-next-line no-control-regex -- reject control characters in persisted URLs
13
+ if (input.length > 2048 || /[\\\s\x00-\x1f\x7f]/.test(input)) {
14
+ throw new Error(t('app_entry.invalid_url'));
15
+ }
16
+ const match = /^https?:\/\/[^/?#]+(\/[^?#]*)(?:\?([^#]*))?(?:#(.*))?$/i.exec(input);
17
+ if (!match) { throw new Error(t('app_entry.invalid_url')); }
18
+ const url = new URL(input);
19
+ const route = match[1];
20
+ const prefix = `/${appType}/`;
21
+ const parts = route.startsWith(prefix) ? route.slice(prefix.length).split('/') : [];
22
+ const short = /^\/(?:s\/[A-Za-z0-9_-]+|o\/[A-Za-z0-9_-]+(?:\/FORM-[A-Za-z0-9_-]+)?)$/.test(route);
23
+ const runtime = ['custom', 'workbench', 'submission', 'manage'].includes(parts[0]) &&
24
+ ((parts.length === 1 && parts[0] === 'workbench') ||
25
+ (parts.length === 2 && /^[A-Za-z0-9_-]+$/.test(parts[1])));
26
+ if (url.username || url.password || url.pathname !== route || (!short && !runtime)) {
27
+ throw new Error(t('app_entry.invalid_url'));
28
+ }
29
+ if (match[2] !== undefined) {
30
+ const seen = new Set();
31
+ for (const parameter of match[2].split('&')) {
32
+ const pair = /^(corpid|locale|viewUuid|processCode|hideLeftNav|noShowTopBottom)=([A-Za-z0-9_-]+)$/.exec(parameter);
33
+ if (!pair || seen.has(pair[1]) ||
34
+ (['hideLeftNav', 'noShowTopBottom'].includes(pair[1]) && !/^(true|false|y|n|0|1)$/.test(pair[2]))) {
35
+ throw new Error(t('app_entry.invalid_url'));
36
+ }
37
+ seen.add(pair[1]);
38
+ }
39
+ }
40
+ if (match[3] !== undefined && !/^[A-Za-z0-9_/-]+$/.test(match[3])) {
41
+ throw new Error(t('app_entry.invalid_url'));
42
+ }
43
+ return input;
44
+ }
45
+
46
+ /** Resolve a page identifier into the canonical entry URL the platform expects. */
47
+ async function resolveEntryUrl(authRef, appType, key, formUuid) {
48
+ if (!/^[A-Za-z0-9_-]+$/.test(String(formUuid || ''))) {
49
+ throw new Error(t('app_entry.invalid_url'));
50
+ }
51
+ const forms = await fetchFormPageList(appType, authRef);
52
+ const form = Array.isArray(forms) ? forms.find((item) => item.formUuid === formUuid) : null;
53
+ if (!form) { throw new Error(t('app_entry.page_not_in_app', formUuid)); }
54
+ if (key === 'frontend') {
55
+ if (String(form.formType).toLowerCase() !== 'display') { throw new Error(t('app_entry.frontend_display_required', formUuid)); }
56
+ if (!form.pathName) { throw new Error(t('app_entry.page_offline', formUuid)); }
57
+ return normalizeUrl(`${authRef.baseUrl}/${appType}/custom/${formUuid}`, appType);
58
+ }
59
+ return normalizeUrl(`${authRef.baseUrl}/${appType}/workbench/${formUuid}`, appType);
60
+ }
61
+
62
+ /** Reject duplicate or ambiguous flags; omissions never clear stored entries. */
63
+ function parseArgs(args) {
64
+ const [action, appType, ...flags] = args;
65
+ if (!['get', 'set'].includes(action) || !/^[A-Za-z0-9_-]+$/.test(appType || '')) {
66
+ throwUsage(t('app_entry.usage'));
67
+ }
68
+ const values = {};
69
+ for (let index = 0; index < flags.length; index++) {
70
+ const flag = flags[index];
71
+ if (flag === '--json') {
72
+ continue;
73
+ }
74
+ const match = /^--(clear-)?(frontend|management)(-page)?$/.exec(flag);
75
+ if (action !== 'set' || !match || (match[1] && match[3]) ||
76
+ Object.prototype.hasOwnProperty.call(values, match[2])) {
77
+ throwUsage(t('app_entry.usage'));
78
+ }
79
+ const kind = match[1] ? 'clear' : (match[3] ? 'page' : 'url');
80
+ const value = kind === 'clear' ? null : flags[++index];
81
+ if (kind !== 'clear' && (!value || value.startsWith('--'))) {
82
+ throwUsage(t('app_entry.usage'));
83
+ }
84
+ values[match[2]] = { kind, value };
85
+ }
86
+ if (action === 'set' && !Object.keys(values).length) {
87
+ throwUsage(t('app_entry.usage'));
88
+ }
89
+ return { action, appType, values };
90
+ }
91
+
92
+ /** Read the revision used for a conditional partial write. */
93
+ async function readEntries(client, appType) {
94
+ const result = unwrapYidaResponse(await client.get(`/${appType}/query/app/getAccessEntries.json`));
95
+ if (!result || typeof result.revision !== 'string' || !result.revision ||
96
+ !result.accessEntries || typeof result.accessEntries !== 'object' || Array.isArray(result.accessEntries)) {
97
+ throw new Error(t('app_entry.invalid_response'));
98
+ }
99
+ return result;
100
+ }
101
+
102
+ /** Persist only supplied entries and verify them through a separate read. */
103
+ async function run(args = []) {
104
+ if (args.includes('--help') || args.includes('-h')) {
105
+ console.log(t('app_entry.usage'));
106
+ return;
107
+ }
108
+ const { action, appType, values } = parseArgs(args);
109
+ const authRef = createAuthRef();
110
+ const client = createYidaClient({ authRef });
111
+ const patch = {};
112
+ for (const [key, spec] of Object.entries(values)) {
113
+ if (spec.kind === 'clear') {
114
+ patch[key] = null;
115
+ } else if (spec.kind === 'page') {
116
+ patch[key] = { url: await resolveEntryUrl(authRef, appType, key, spec.value) };
117
+ } else {
118
+ const url = normalizeUrl(spec.value, appType);
119
+ patch[key] = { url };
120
+ }
121
+ }
122
+ let result = await readEntries(client, appType);
123
+ if (action === 'set') {
124
+ unwrapYidaResponse(await client.postForm(`/${appType}/query/app/saveAccessEntries.json`, {
125
+ accessEntries: JSON.stringify(patch), revision: result.revision,
126
+ }));
127
+ result = await readEntries(client, appType);
128
+ for (const [key, entry] of Object.entries(patch)) {
129
+ if ((result.accessEntries[key]?.url || '') !== (entry?.url || '')) {
130
+ throw new Error(t('app_entry.readback_failed'));
131
+ }
132
+ }
133
+ }
134
+ const urls = {};
135
+ for (const key of ['frontend', 'management']) {
136
+ if (result.accessEntries[key]?.url) {
137
+ urls[key] = normalizeUrl(result.accessEntries[key].url, appType);
138
+ }
139
+ }
140
+ console.log(JSON.stringify({ appType, ...result, urls }, null, 2));
141
+ return result;
142
+ }
143
+
144
+ module.exports = { run, parseArgs, normalizeUrl, resolveEntryUrl };
@@ -84,6 +84,7 @@ function formatApp(app, baseUrl) {
84
84
  appName: (app.appName && app.appName.zh_CN) || '',
85
85
  appType: app.appType || '',
86
86
  systemLink: app.systemLink || '',
87
+ ...(app.accessEntries ? { accessEntries: app.accessEntries } : {}),
87
88
  ...buildApplicationEntryUrls({ appType: app.appType, systemLink: app.systemLink, baseUrl }),
88
89
  };
89
90
  }
@@ -28,4 +28,30 @@ function buildApplicationEntryUrls({ appType, baseUrl, systemLink }) {
28
28
  return { appUrl: workbenchUrl, workbenchUrl, adminUrl: `${origin}/${appType}/admin${suffix}` };
29
29
  }
30
30
 
31
- module.exports = { buildApplicationEntryUrls };
31
+ function readRenderNav(config) {
32
+ const value = config && Object.prototype.hasOwnProperty.call(config, 'renderNav')
33
+ ? config.renderNav : config?.isRenderNav;
34
+ if (value === false || value === 'false') {return false;}
35
+ if (value === true || value === 'true') {return true;}
36
+ return null;
37
+ }
38
+
39
+ function buildDisplayPageEntryUrls({ appType, formUuid, baseUrl, config, formType = config?.formType }) {
40
+ if (formType !== 'display' || !/^FORM[-_][A-Za-z0-9_-]+$/.test(formUuid || '')) {return {};}
41
+ if (config?.formType && config.formType !== 'display') {return {};}
42
+ if ((config?.appType && config.appType !== appType) || (config?.formUuid && config.formUuid !== formUuid)) {return {};}
43
+ const appUrls = buildApplicationEntryUrls({ appType, baseUrl });
44
+ if (!appUrls.workbenchUrl) {return {};}
45
+ const origin = new URL(appUrls.workbenchUrl).origin;
46
+ const renderNav = readRenderNav(config);
47
+ const workbenchUrl = `${origin}/${appType}/workbench/${formUuid}`;
48
+ const standaloneUrl = renderNav === false ? `${origin}/${appType}/custom/${formUuid}` : null;
49
+ return {
50
+ url: standaloneUrl || workbenchUrl,
51
+ workbenchUrl,
52
+ standaloneUrl,
53
+ navigationVerification: { renderNav, verified: renderNav !== null },
54
+ };
55
+ }
56
+
57
+ module.exports = { buildApplicationEntryUrls, buildDisplayPageEntryUrls, readRenderNav };
@@ -0,0 +1,67 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { CliError } = require('../core/cli-error');
6
+ const { t } = require('../core/i18n');
7
+ const { DESIGN_SKILL_ROOT, loadThemeIndex } = require('../design-plan/themes');
8
+ const START = '/* OPENYIDA APPLICATION STYLE RECIPES START';
9
+ const END = '/* OPENYIDA APPLICATION STYLE RECIPES END */';
10
+ const CREATIVE_TOKENS = [
11
+ '--pod-page-bg-color', '--pod-card-bg-color', '--color-text1-4',
12
+ '--form-element-medium-corner', '--form-element-medium-height',
13
+ '--pod-page-footer-bg-color', '--pod-sticky-footer-box-shadow',
14
+ '--oyd-content-width', '--oyd-content-padding', '--oyd-field-gap',
15
+ '--oyd-heading-font', '--oyd-heading-size', '--oyd-rule-style',
16
+ ];
17
+
18
+ function validateCreativeDirection(direction, tokens) {
19
+ const missing = ['businessRationale', 'composition', 'typography', 'material', 'formLayout']
20
+ .filter(key => typeof direction?.[key] !== 'string' || !direction[key].trim());
21
+ missing.push(...CREATIVE_TOKENS.filter(key => typeof tokens?.[key] !== 'string' || !tokens[key].trim()));
22
+ if (missing.length) {
23
+ throw new CliError(t('design_document.invalid', 'creativeDirection', missing.join(', ')), {
24
+ code: 'APPLICATION_STYLE_CREATIVE_INCOMPLETE', details: { missing },
25
+ });
26
+ }
27
+ }
28
+
29
+ function applyApplicationStyle(css, metadata, tokens) {
30
+ const style = metadata.applicationStyle;
31
+ if (style && (style.recipe !== 'application-style-v1' || !['template', 'creative'].includes(style.mode))) {
32
+ throw new CliError(t('design_document.invalid', 'applicationStyle', 'APPLICATION_STYLE_INVALID'), { code: 'APPLICATION_STYLE_INVALID' });
33
+ }
34
+ if (style?.mode === 'creative') {validateCreativeDirection(metadata.creativeDirection, tokens);}
35
+ const first = css.indexOf(START);
36
+ const last = css.indexOf(END);
37
+ if (first >= 0 && last < first) {
38
+ throw new CliError(t('design_document.invalid', 'app_theme.css', 'APPLICATION_STYLE_CSS_INVALID'), { code: 'APPLICATION_STYLE_CSS_INVALID' });
39
+ }
40
+ const recipe = style
41
+ ? fs.readFileSync(path.join(DESIGN_SKILL_ROOT, 'references/theme/application-style-recipes.css'), 'utf8').trim()
42
+ : '';
43
+ // Only the managed recipe block is replaced. User-authored rules stay intact.
44
+ if (first >= 0) {return css.slice(0, first) + recipe + css.slice(last + END.length);}
45
+ return recipe ? `${css.trimEnd()}\n\n${recipe}\n` : css;
46
+ }
47
+
48
+ function exportApplicationStyle(id, outputDirectory) {
49
+ const theme = loadThemeIndex().themes.find(item => item.themeId === id);
50
+ if (!theme) {throw new CliError(t('design_document.invalid', id || '--style-id', 'APPLICATION_STYLE_UNKNOWN'), { code: 'APPLICATION_STYLE_UNKNOWN' });}
51
+ const directory = path.resolve(outputDirectory);
52
+ const assets = [['design.md', theme.templatePath], ['app_theme.css', theme.cssTemplatePath], ['form-layout.json', theme.formLayoutPath]];
53
+ const outputs = assets.map(([name, relative]) => {
54
+ const source = path.resolve(DESIGN_SKILL_ROOT, relative);
55
+ const target = path.join(directory, name);
56
+ const root = path.resolve(DESIGN_SKILL_ROOT, 'templates/design-themes') + path.sep;
57
+ if (!source.startsWith(root) || fs.existsSync(target)) {
58
+ throw new CliError(t('design_document.invalid', target, 'APPLICATION_STYLE_OUTPUT_CONFLICT'), { code: 'APPLICATION_STYLE_OUTPUT_CONFLICT' });
59
+ }
60
+ return { source, target, content: fs.readFileSync(source, 'utf8') };
61
+ });
62
+ fs.mkdirSync(directory, { recursive: true });
63
+ for (const item of outputs) {fs.writeFileSync(item.target, item.content, { flag: 'wx' });}
64
+ return { success: true, mode: theme.mode, themeId: id, authoringRequired: true, outputs: outputs.map(item => item.target) };
65
+ }
66
+
67
+ module.exports = { applyApplicationStyle, validateCreativeDirection, CREATIVE_TOKENS, exportApplicationStyle };
@@ -976,7 +976,12 @@ function compileCanvasLocal(source, options = {}) {
976
976
  assertCanvasNavigationStructure(source, options);
977
977
  assertCanvasNavigationPaths(source, options);
978
978
  assertInlineCssStructure(source, options);
979
- assertCanvasThemeStructure(source, options);
979
+ const warnings = [];
980
+ assertCanvasThemeStructure(source, { ...options, onThemeWarning(message, details) {
981
+ warnings.push({ ...details, message });
982
+ if (options.onThemeWarning) { options.onThemeWarning(message, details); }
983
+ else { require('../core/chalk').warn(message); }
984
+ } });
980
985
 
981
986
  const importedModules = extractImportedModules(source);
982
987
 
@@ -1036,6 +1041,7 @@ function compileCanvasLocal(source, options = {}) {
1036
1041
  return {
1037
1042
  runtimeCode,
1038
1043
  importedModules: JSON.stringify(importedModules),
1044
+ warnings,
1039
1045
  };
1040
1046
  }
1041
1047