openyida 2026.7.17 → 2026.7.18

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 (204) hide show
  1. package/README.md +23 -8
  2. package/bin/yida.js +12 -0
  3. package/lib/app/canvas-compile.js +8 -1
  4. package/lib/app/create-app.js +94 -26
  5. package/lib/app/create-form/args.js +263 -0
  6. package/lib/app/create-form/commands.js +27 -0
  7. package/lib/app/create-form/definition-reader.js +230 -0
  8. package/lib/app/create-form/field-normalizers.js +429 -0
  9. package/lib/app/create-form/rule-builder.js +9 -0
  10. package/lib/app/create-form/schema-builder.js +12 -0
  11. package/lib/app/create-form/schema-patch.js +36 -0
  12. package/lib/app/create-form/validation-builder.js +9 -0
  13. package/lib/app/create-form.js +662 -997
  14. package/lib/app/form-navigation.js +2 -13
  15. package/lib/app/generate-page.js +463 -12
  16. package/lib/app/get-form-config.js +148 -0
  17. package/lib/app/nav-group.js +2 -13
  18. package/lib/app/page-ir.js +1097 -28
  19. package/lib/app/page-linter.js +57 -0
  20. package/lib/app/publish.js +3 -3
  21. package/lib/app/theme-presets.js +44 -0
  22. package/lib/app/update-app.js +126 -35
  23. package/lib/app/update-form-config.js +116 -29
  24. package/lib/asset/ai-image.js +126 -0
  25. package/lib/asset/asset-cmd.js +217 -0
  26. package/lib/asset/asset-resolve.js +307 -0
  27. package/lib/asset/asset-status.js +87 -0
  28. package/lib/asset/url-verify.js +217 -0
  29. package/lib/auth/token-auth.js +15 -5
  30. package/lib/basic-info/basic-info.js +8 -30
  31. package/lib/bridge/bridge.js +3 -3
  32. package/lib/core/agent-capabilities.js +2 -0
  33. package/lib/core/check-data.js +1 -1
  34. package/lib/core/command-manifest.js +23 -4
  35. package/lib/core/command-router.js +30 -0
  36. package/lib/core/copy.js +37 -8
  37. package/lib/core/env.js +0 -12
  38. package/lib/core/i18n.js +11 -7
  39. package/lib/core/locales/ar.js +24 -7
  40. package/lib/core/locales/de.js +24 -7
  41. package/lib/core/locales/en.js +46 -12
  42. package/lib/core/locales/es.js +24 -7
  43. package/lib/core/locales/fr.js +24 -7
  44. package/lib/core/locales/hi.js +24 -7
  45. package/lib/core/locales/ja.js +26 -9
  46. package/lib/core/locales/ko.js +24 -7
  47. package/lib/core/locales/pt.js +24 -7
  48. package/lib/core/locales/vi.js +24 -7
  49. package/lib/core/locales/zh-HK.js +26 -9
  50. package/lib/core/locales/zh.js +46 -12
  51. package/lib/core/safe-json.js +183 -0
  52. package/lib/core/sample.js +15 -0
  53. package/lib/core/task-center.js +1 -1
  54. package/lib/core/yida-client.js +41 -0
  55. package/lib/core/yida-i18n.js +46 -0
  56. package/lib/corp-efficiency/corp-efficiency.js +13 -25
  57. package/lib/mcp/server.js +1 -11
  58. package/lib/process/ai-form-setting.js +2 -14
  59. package/lib/samples/yida-canvas-custom-page/business-list.canvas.jsx +625 -0
  60. package/lib/samples/yida-canvas-custom-page/dashboard-overview.canvas.jsx +571 -0
  61. package/lib/samples/yida-canvas-custom-page/dashboard-starter.canvas.jsx +386 -0
  62. package/lib/samples/yida-canvas-custom-page/data-management.canvas.jsx +1116 -0
  63. package/lib/samples/yida-canvas-custom-page/data-screen.canvas.jsx +1034 -0
  64. package/lib/samples/yida-canvas-custom-page/detail-profile.canvas.jsx +421 -0
  65. package/lib/samples/yida-canvas-custom-page/native-components-smoke.canvas.jsx +773 -0
  66. package/lib/samples/yida-canvas-custom-page/official-homepage.canvas.jsx +936 -0
  67. package/lib/samples/yida-canvas-custom-page/portal-native-components.canvas.jsx +1259 -0
  68. package/lib/samples/yida-canvas-custom-page/portal-shell-home.canvas.jsx +471 -0
  69. package/lib/samples/yida-canvas-custom-page/product-homepage.canvas.jsx +777 -0
  70. package/lib/samples/yida-canvas-custom-page/split-pane-detail.canvas.jsx +353 -0
  71. package/lib/samples/yida-canvas-custom-page/todo-mvc.canvas.jsx +614 -0
  72. package/lib/samples/yida-canvas-custom-page/workbench-home.canvas.jsx +662 -0
  73. package/lib/samples/yida-chart/china-map.js +46 -18
  74. package/lib/samples/yida-chart/dashboard-bindform.js +54 -25
  75. package/lib/samples/yida-chart/line-trend.js +51 -22
  76. package/lib/samples/yida-chart/multi-bar-compare.js +114 -43
  77. package/lib/samples/yida-chart/radar-chart.js +45 -17
  78. package/lib/samples/yida-chart/scatter-bindform.js +35 -6
  79. package/lib/samples/yida-chart/stacked-area.js +34 -6
  80. package/lib/samples/yida-custom-page/business-list.oyd.jsx +443 -0
  81. package/lib/samples/yida-custom-page/custom-page-template.js +432 -109
  82. package/lib/samples/yida-custom-page/dashboard-overview.oyd.jsx +327 -0
  83. package/lib/samples/yida-custom-page/data-management.oyd.jsx +263 -0
  84. package/lib/samples/yida-custom-page/data-screen.oyd.jsx +348 -0
  85. package/lib/samples/yida-custom-page/design-tokens.js +53 -11
  86. package/lib/samples/yida-custom-page/detail-profile.oyd.jsx +241 -0
  87. package/lib/samples/yida-custom-page/official-homepage.oyd.jsx +218 -0
  88. package/lib/samples/yida-custom-page/portal-shell-home.oyd.jsx +263 -0
  89. package/lib/samples/yida-custom-page/product-homepage.jsx +361 -119
  90. package/lib/samples/yida-custom-page/split-pane-detail.oyd.jsx +244 -0
  91. package/lib/samples/yida-custom-page/todo-mvc.oyd.jsx +328 -52
  92. package/lib/samples/yida-custom-page/workbench-home.oyd.jsx +707 -0
  93. package/lib/samples/yida-density/density-switch-page.js +236 -77
  94. package/lib/samples/yida-table-form/table-form-batch-submit.js +395 -61
  95. package/package.json +8 -2
  96. package/project/prd/demo-birthday-game.md +9 -0
  97. package/scripts/check-syntax.js +48 -1
  98. package/scripts/generate-command-docs.js +70 -29
  99. package/scripts/i18n-baseline.json +50 -0
  100. package/scripts/postinstall.js +17 -29
  101. package/scripts/validate-ci.sh +10 -6
  102. package/scripts/validate-command-manifest.js +11 -6
  103. package/scripts/validate-i18n.js +176 -0
  104. package/scripts/validate-package-size.js +23 -6
  105. package/scripts/validate-skills.js +34 -0
  106. package/yida-skills/SKILL.md +62 -72
  107. package/yida-skills/references/development-rules.md +3 -3
  108. package/yida-skills/references/task-retrospective.md +134 -0
  109. package/yida-skills/skills/yida-app/SKILL.md +143 -7
  110. package/yida-skills/skills/yida-app-uiux/SKILL.md +95 -0
  111. package/yida-skills/skills/yida-business-rule/SKILL.md +1 -11
  112. package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +156 -72
  113. package/yida-skills/skills/yida-canvas-custom-page/references/canvas-authoring-examples.md +2 -2
  114. package/yida-skills/skills/yida-canvas-custom-page/references/canvas-design-system.md +137 -11
  115. package/yida-skills/skills/yida-canvas-custom-page/references/component-library-guide.md +70 -0
  116. package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +272 -25
  117. package/yida-skills/skills/yida-canvas-custom-page/references/employeefield-verification.md +1 -1
  118. package/yida-skills/skills/yida-canvas-custom-page/references/native-components-bridge.md +237 -0
  119. package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +136 -0
  120. package/yida-skills/skills/yida-canvas-data-binding/SKILL.md +174 -0
  121. package/yida-skills/skills/yida-canvas-upgrade/SKILL.md +3 -5
  122. package/yida-skills/skills/yida-canvas-upgrade/references/migration-examples.md +1 -1
  123. package/yida-skills/skills/yida-chart/SKILL.md +16 -10
  124. package/yida-skills/skills/yida-create-app/SKILL.md +20 -4
  125. package/yida-skills/skills/yida-create-form-page/SKILL.md +119 -308
  126. package/yida-skills/skills/yida-create-form-page/references/advanced-form-modes.md +178 -0
  127. package/yida-skills/skills/yida-create-form-page/references/field-definition-guide.md +130 -0
  128. package/yida-skills/skills/yida-create-form-page/references/form-field-properties.md +100 -0
  129. package/yida-skills/skills/yida-create-page/SKILL.md +4 -2
  130. package/yida-skills/skills/yida-custom-page/SKILL.md +13 -11
  131. package/yida-skills/skills/yida-custom-page/references/coding-guide.md +36 -6
  132. package/yida-skills/skills/yida-custom-page/references/component-jsx-guide.md +93 -17
  133. package/yida-skills/skills/yida-custom-page/references/design-system.md +13 -2
  134. package/yida-skills/skills/yida-dashboard/SKILL.md +2 -17
  135. package/yida-skills/skills/yida-data-source-connectors/SKILL.md +4 -12
  136. package/yida-skills/skills/yida-flash-note-to-prd/SKILL.md +0 -26
  137. package/yida-skills/skills/yida-formula/SKILL.md +5 -26
  138. package/yida-skills/skills/yida-formula-evaluate/SKILL.md +0 -8
  139. package/yida-skills/skills/yida-get-schema/SKILL.md +0 -10
  140. package/yida-skills/skills/yida-integration/SKILL.md +0 -11
  141. package/yida-skills/skills/yida-nav-shell/SKILL.md +7 -18
  142. package/yida-skills/skills/yida-nav-shell/references/nav-shell-patterns.md +4 -4
  143. package/yida-skills/skills/yida-page-uiux/SKILL.md +76 -15
  144. package/yida-skills/skills/yida-page-uiux/references/app/blueprint.md +21 -0
  145. package/yida-skills/skills/yida-page-uiux/references/app/navigation-patterns.md +32 -0
  146. package/yida-skills/skills/yida-page-uiux/references/app/role-journey.md +31 -0
  147. package/yida-skills/skills/yida-page-uiux/references/asset-workflow.md +112 -0
  148. package/yida-skills/skills/yida-page-uiux/references/dashboard/app-blueprint.md +19 -0
  149. package/yida-skills/skills/yida-page-uiux/references/dashboard/chart-contracts.md +17 -0
  150. package/yida-skills/skills/yida-page-uiux/references/dashboard/component-contracts.md +19 -0
  151. package/yida-skills/skills/yida-page-uiux/references/dashboard/layout-patterns.md +32 -0
  152. package/yida-skills/skills/yida-page-uiux/references/dashboard/theme-recipes.md +23 -0
  153. package/yida-skills/skills/yida-page-uiux/references/detail/object-narrative.md +19 -0
  154. package/yida-skills/skills/yida-page-uiux/references/detail/section-patterns.md +16 -0
  155. package/yida-skills/skills/yida-page-uiux/references/detail/timeline-and-related.md +18 -0
  156. package/yida-skills/skills/yida-page-uiux/references/landing/assets-workflow.md +26 -0
  157. package/yida-skills/skills/yida-page-uiux/references/landing/industry-playbooks.md +26 -0
  158. package/yida-skills/skills/yida-page-uiux/references/landing/realistic-brand-homepage.md +82 -0
  159. package/yida-skills/skills/yida-page-uiux/references/landing/research-levels.md +11 -0
  160. package/yida-skills/skills/yida-page-uiux/references/landing/section-patterns.md +17 -0
  161. package/yida-skills/skills/yida-page-uiux/references/list/drawer-detail.md +19 -0
  162. package/yida-skills/skills/yida-page-uiux/references/list/empty-loading-error.md +18 -0
  163. package/yida-skills/skills/yida-page-uiux/references/list/filter-patterns.md +16 -0
  164. package/yida-skills/skills/yida-page-uiux/references/list/table-patterns.md +14 -0
  165. package/yida-skills/skills/yida-page-uiux/references/scenes/landing.md +13 -2
  166. package/yida-skills/skills/yida-page-uiux/references/scenes/screen.md +36 -0
  167. package/yida-skills/skills/yida-page-uiux/references/visual-decision-engine.md +2 -2
  168. package/yida-skills/skills/yida-page-uiux/references/workbench/entry-patterns.md +19 -0
  169. package/yida-skills/skills/yida-page-uiux/references/workbench/portal-layouts.md +20 -0
  170. package/yida-skills/skills/yida-page-uiux/references/workbench/task-feed.md +21 -0
  171. package/yida-skills/skills/yida-page-uiux/workflow/output-decision-block.md +68 -4
  172. package/yida-skills/skills/yida-page-uiux/workflow/step-0-nav-shape.md +3 -3
  173. package/yida-skills/skills/yida-page-uiux/workflow/step-1-page-type.md +17 -0
  174. package/yida-skills/skills/yida-page-uiux/workflow/step-3-scene-routing.md +27 -7
  175. package/yida-skills/skills/yida-page-uiux/workflow/step-4-visual-decision.md +12 -0
  176. package/yida-skills/skills/yida-page-uiux/workflow/step-5-icon-and-assets.md +2 -2
  177. package/yida-skills/skills/yida-page-uiux/workflow/step-6-deai-selfcheck.md +4 -1
  178. package/yida-skills/skills/yida-process-rule/SKILL.md +4 -23
  179. package/yida-skills/skills/yida-publish-page/SKILL.md +13 -32
  180. package/yida-skills/skills/yida-report/SKILL.md +15 -2
  181. package/yida-skills/skills/yida-table-form/SKILL.md +0 -16
  182. package/yida-skills/skills/yida-theme/SKILL.md +238 -0
  183. package/yida-skills/skills-index.json +690 -145
  184. package/scripts/e2e-real/cleanup.js +0 -67
  185. package/scripts/e2e-real/fixtures/form-fields.json +0 -18
  186. package/scripts/e2e-real/full-runner.js +0 -1558
  187. package/scripts/e2e-real/runner.js +0 -262
  188. package/scripts/e2e-real/skill-coverage.js +0 -120
  189. package/scripts/eval/VERIFY.md +0 -169
  190. package/scripts/eval/agent.js +0 -148
  191. package/scripts/eval/config.js +0 -276
  192. package/scripts/eval/dashboard/index.html +0 -389
  193. package/scripts/eval/dashboard/server.js +0 -344
  194. package/scripts/eval/eval.config.json +0 -8
  195. package/scripts/eval/generate.js +0 -362
  196. package/scripts/eval/guardrail.js +0 -130
  197. package/scripts/eval/manifest.js +0 -117
  198. package/scripts/eval/report.js +0 -262
  199. package/scripts/eval/routing.js +0 -217
  200. package/scripts/eval/runner.js +0 -318
  201. package/scripts/eval/scenarios/generation/generation-core.json +0 -32
  202. package/scripts/eval/scenarios/routing-core.json +0 -101
  203. package/scripts/eval/score.js +0 -205
  204. package/scripts/eval/screenshot.js +0 -151
package/README.md CHANGED
@@ -18,6 +18,8 @@ OpenYida connects AI coding agents with Yida's low-code platform, so developers
18
18
 
19
19
  **Documentation:** [English](https://openyida.ai/docs/en) · [简体中文](https://openyida.ai/docs) · [繁體中文](https://openyida.ai/docs/zh-Hant/) · [日本語](https://openyida.ai/docs/ja/) · [한국어](https://openyida.ai/docs/ko/) · [Français](https://openyida.ai/docs/fr/) · [Deutsch](https://openyida.ai/docs/de/) · [Español](https://openyida.ai/docs/es/) · [Português](https://openyida.ai/docs/pt/) · [Tiếng Việt](https://openyida.ai/docs/vi/) · [हिन्दी](https://openyida.ai/docs/hi/) · [العربية](https://openyida.ai/docs/ar/)
20
20
 
21
+ [English README](./README.md) · [简体中文 README](./README_zhCN.md)
22
+
21
23
  </div>
22
24
 
23
25
  ---
@@ -175,19 +177,28 @@ openyida get-schema APP_XXX FORM_XXX
175
177
  openyida get-schema APP_XXX --all --output-dir .cache/schemas
176
178
  ```
177
179
 
180
+ Form definitions support 19 business field types plus verified `@ali/vc-deep-yida` 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.
181
+
178
182
  ### Custom Page Development
179
183
 
180
184
  ```bash
181
185
  openyida create-page APP_XXX "Dashboard" --mode dashboard
182
- openyida generate-page product-homepage --spec .cache/openyida/page-specs/home.json --output pages/src/home.oyd.jsx --compile
183
- openyida generate-page todo-mvc --output pages/src/todo-mvc.oyd.jsx --compile
184
- openyida check-page pages/src/home.oyd.jsx
185
- openyida compile pages/src/home.oyd.jsx
186
- openyida publish pages/src/home.oyd.jsx APP_XXX FORM_XXX
186
+ openyida generate-page product-homepage --scene workbench --theme-profile yida-app-theme --theme-scope page --spec .cache/openyida/page-specs/home.json --output pages/src/home.canvas.jsx --compile
187
+ openyida generate-page official-homepage --theme-profile yida-app-theme --spec .cache/openyida/page-specs/official-home.json --resolve-assets --upload-assets --output pages/src/official-home.canvas.jsx --compile
188
+ openyida generate-page data-screen --theme-profile yida-app-theme --output pages/src/data-screen.canvas.jsx --compile
189
+ openyida generate-page split-pane-detail --theme-profile yida-app-theme --output pages/src/split-pane-detail.canvas.jsx --compile
190
+ openyida generate-page portal-shell-home --theme-profile yida-app-theme --output pages/src/portal-shell-home.canvas.jsx --compile
191
+ openyida sample yida-canvas-custom-page dashboard-starter --output pages/src/dashboard-starter.canvas.jsx
192
+ openyida sample yida-canvas-custom-page native-components-smoke --output pages/src/native-components-smoke.canvas.jsx
193
+ openyida sample yida-canvas-custom-page portal-native-components --output pages/src/portal-native-components.canvas.jsx
194
+ openyida generate-page todo-mvc --output pages/src/todo-mvc.canvas.jsx --compile
195
+ openyida publish pages/src/home.canvas.jsx APP_XXX FORM_XXX
187
196
  ```
188
197
 
189
- `generate-page` turns a structured spec into a Page IR, renders a curated React 16-compatible template, writes a `.openyida-page.json` manifest, and optionally compiles the result. The manifest makes follow-up AI edits safer because agents can update known blocks instead of rewriting a large JSX file by hand.
190
- Built-in templates currently include `product-homepage` for product/portal pages and `todo-mvc` for a full interaction smoke page covering events, custom state, list rendering, editing, filtering, and localStorage persistence.
198
+ `generate-page` turns a structured spec into a Page IR, renders a curated template, writes a `.openyida-page.json` manifest, and optionally compiles the result. Code Canvas is the default output (`.canvas.jsx`); pass `--native` or output `.oyd.jsx` only when the page must use the 普通自定义页面 JSX/Jsx 组件链路. Pass `--scene workbench|dashboard|list|detail|landing|screen` and `--theme-profile <name-or-json>` / `--visual-profile <name-or-json>` to preserve the visual direction decision in both source comments and the manifest. The user-facing default theme profile is `yida-app-theme`, which follows Yida application theme styling, compact business density, and layered 12/8/6/4 radii. `--theme-scope page` only injects theme variables into the generated page root; `--theme-scope app` additionally calls `window.__YIDA__.updateShellConfig({ themeConfig })` so the application shell can adopt the same theme. Landing pages should declare `spec.assets.heroImage` / `productImages`; use `--resolve-assets` to verify public image URLs and `--upload-assets` to mirror local or verified external images to CDN when CDN is configured. Use `--offline-assets` only for draft/offline gating. The manifest makes follow-up AI edits safer because agents can update known blocks and visual constraints instead of rewriting a large JSX file by hand.
199
+ Built-in templates currently include `official-homepage` for brand/law-firm/product official sites, `data-screen` for immersive monitoring screens, `dashboard-overview` for business dashboards, `workbench-home` for task/entry workbenches, `business-list` for list management pages, `detail-profile` for single-object detail pages, `split-pane-detail` for left-list/right-detail processing consoles, `portal-shell-home` for in-page portal shells, `native-components-smoke` for runtime probing existing Yida host components without changing `vc-deep-yida`, `portal-native-components` for runtime-bridged portal, member, department, and upload components, `product-homepage` for legacy workbench-style pages, and `todo-mvc` for a full interaction smoke page covering events, custom state, list rendering, editing, filtering, and localStorage persistence.
200
+
201
+ For member, department, attachment, and image upload components, choose the page chain first. Code Canvas pages should start with `native-components-smoke` or `portal-native-components` and follow `yida-canvas-custom-page/references/native-components-bridge.md` for feature detection, fallback, and value normalization. 普通自定义页面 JSX/Jsx pages should use `.oyd.jsx`, read `yida-custom-page/references/component-jsx-guide.md`, and read `attachment-upload-guide.md` when upload fields are involved.
191
202
 
192
203
  ### Workflow, Data, and Permissions
193
204
 
@@ -270,7 +281,7 @@ npm run eval:routing
270
281
  # sub-skill, adds guardrail assertions, screenshots the published page, and writes a
271
282
  # human scoring template. Runs deterministic CLI commands (no agent) so it serves as
272
283
  # a control that proves the build→publish→screenshot→score plumbing itself works.
273
- # Requires OPENYIDA_E2E=1 and a valid cookie cache.
284
+ # Requires OPENYIDA_E2E=1 and a valid token session.
274
285
  OPENYIDA_E2E=1 npm run eval:e2e -- --skill yida-dashboard --screenshot
275
286
 
276
287
  # Same, plus automatic screenshot scoring via the local multimodal `claude -p`.
@@ -375,6 +386,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
375
386
  | `openyida compile <src>` | Compile custom page locally |
376
387
  | `openyida publish <src> <appType> <formUuid> [--health-check] [--force] [--canvas] [--open\|--no-open]` | Compile and publish custom page |
377
388
  | `openyida update-form-config <appType> ...` | Update form configuration |
389
+ | `openyida get-form-config <appType> <formUuid> [--json]` | Query form configuration |
378
390
 
379
391
  ### Data & Permissions
380
392
 
@@ -464,6 +476,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
464
476
  | `openyida batch <file>\|--commands "cmd1 ; cmd2" [--stop-on-error] [--json]` | Run OpenYida commands in batch |
465
477
  | `openyida flash-to-prd --file <path> --name "<project>"` | Convert flash notes or meeting notes to a PRD prompt |
466
478
  | `openyida ai <text\|image> [options]` | Call Yida AI text and image recognition APIs |
479
+ | `openyida asset <status\|verify-url\|resolve\|generate> [options]` | Detect asset capability / verify image URLs / resolve materials |
467
480
  | `openyida cdn-config [options]` | Configure CDN / OSS upload |
468
481
  | `openyida cdn-upload <image-path>` | Upload image to CDN |
469
482
  | `openyida cdn-refresh [options]` | Refresh CDN cache |
@@ -472,6 +485,8 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
472
485
 
473
486
  ### CLI Notes
474
487
 
488
+ `openyida asset resolve --hero <path-or-url> --product <path-or-url> --require-hero --upload-assets --json` is the preferred preflight for homepage visuals. It verifies public image URLs, uploads local images when CDN is configured, mirrors verified external images to CDN when `--upload-assets` is passed, and returns `materialStatus: final|draft|none` so agents do not claim an unfinished visual page is final.
489
+
475
490
  #### Environment and Localization
476
491
 
477
492
  Environment selectors such as `--env intl`, `--intl`, `--overseas`, `--global`, and `--yidaapps` can be used on login-required commands to choose the target Yida environment for that run. The `intl` preset uses `https://www.yidaapps.com` as the built-in Global YiDA entrypoint (not the bare `https://yidaapps.com` domain) and DingTalk International OAuth at `https://login.dingtalk.io`; business API requests still use the authenticated environment `baseUrl`, so customer custom subdomains are supported.
package/bin/yida.js CHANGED
@@ -707,6 +707,12 @@ async function main() {
707
707
  break;
708
708
  }
709
709
 
710
+ case 'get-form-config': {
711
+ const { run: runGetFormConfig } = require('../lib/app/get-form-config');
712
+ await runGetFormConfig(args);
713
+ break;
714
+ }
715
+
710
716
  case 'update-app': {
711
717
  if (args.length < 2) {
712
718
  throwCliUsage(t('cli.update_app_usage'), t('cli.update_app_example'));
@@ -867,6 +873,12 @@ async function main() {
867
873
  break;
868
874
  }
869
875
 
876
+ case 'asset': {
877
+ const { run: runAsset } = require('../lib/asset/asset-cmd');
878
+ await runAsset(args);
879
+ break;
880
+ }
881
+
870
882
  case 'connector': {
871
883
  const subCommand = args[0];
872
884
  const subArgs = args.slice(1);
@@ -59,6 +59,12 @@ const IMPORT_SIDE_EFFECT_PATTERN = /import\s+['"]([^'"]+)['"]/g;
59
59
  const REQUIRE_PATTERN = /require\(\s*['"]([^'"]+)['"]\s*\)/g;
60
60
  const DYNAMIC_IMPORT_PATTERN = /import\(\s*['"]([^'"]+)['"]\s*\)/g;
61
61
 
62
+ function stripJsComments(code) {
63
+ return String(code || '')
64
+ .replace(/\/\*[\s\S]*?\*\//g, '')
65
+ .replace(/(^|[^:])\/\/.*$/gm, '$1');
66
+ }
67
+
62
68
  /**
63
69
  * 从源码里正则抽取裸包名(过滤相对/绝对路径),去重排序。
64
70
  * 对齐 dingtalk-ai-app 的 _extract_imported_modules 行为。
@@ -67,11 +73,12 @@ const DYNAMIC_IMPORT_PATTERN = /import\(\s*['"]([^'"]+)['"]\s*\)/g;
67
73
  */
68
74
  function extractImportedModules(code) {
69
75
  const modules = new Set();
76
+ const source = stripJsComments(code);
70
77
  const patterns = [IMPORT_PATTERN, IMPORT_SIDE_EFFECT_PATTERN, REQUIRE_PATTERN, DYNAMIC_IMPORT_PATTERN];
71
78
  for (const pattern of patterns) {
72
79
  pattern.lastIndex = 0;
73
80
  let match;
74
- while ((match = pattern.exec(code)) !== null) {
81
+ while ((match = pattern.exec(source)) !== null) {
75
82
  const name = match[1];
76
83
  if (name && !name.startsWith('.') && !name.startsWith('/')) {
77
84
  modules.add(name);
@@ -17,15 +17,59 @@ const { createAuthRef } = require('../core/yida-client');
17
17
  const { t } = require('../core/i18n');
18
18
  const { buildYidaI18n, normalizeYidaLocale, resolveContentLocale } = require('../core/yida-i18n');
19
19
  const { parseOpenOption, withBrowserHandoff } = require('../core/browser-handoff');
20
+ const { assertPresetThemeKey } = require('./theme-presets');
20
21
 
21
22
  const DEFAULT_APP_OPTIONS = {
22
23
  icon: 'xian-yingyong',
23
24
  iconColor: '#0089FF',
24
25
  colour: 'deepBlue',
25
- navTheme: 'dark',
26
- layoutDirection: 'slide',
27
26
  };
28
27
 
28
+ const INDUSTRY_APP_DEFAULTS = [
29
+ {
30
+ name: 'legal',
31
+ pattern: /(律所|律师|法律|法务|合规|仲裁|知识产权|诉讼|legal|law\s*firm|lawyer)/i,
32
+ options: {
33
+ icon: 'xian-falv',
34
+ iconColor: '#5C72FF',
35
+ colour: 'greyBlue',
36
+ },
37
+ },
38
+ {
39
+ name: 'tea-ecology',
40
+ pattern: /(茶叶|茶园|茶业|茶庄|茶文化|农业|生态|环保|有机|健康|tea|agri|eco|green)/i,
41
+ options: {
42
+ icon: 'xian-diqiu',
43
+ iconColor: '#00B853',
44
+ colour: 'teal',
45
+ },
46
+ },
47
+ {
48
+ name: 'command-screen',
49
+ pattern: /(数据大屏|大屏|实时监控|监测预警|预警系统|态势|指挥舱|水质|物联网|iot|screen|monitoring|command\s*center)/i,
50
+ options: {
51
+ icon: 'xian-baogao',
52
+ iconColor: '#14A9FF',
53
+ colour: 'greyBlue',
54
+ },
55
+ },
56
+ {
57
+ name: 'professional-service',
58
+ pattern: /(咨询|审计|会计|投顾|专业服务|企业服务|consulting|audit|advisory)/i,
59
+ options: {
60
+ icon: 'xian-qiye',
61
+ iconColor: '#5C72FF',
62
+ colour: 'royalBlue',
63
+ },
64
+ },
65
+ ];
66
+
67
+ function inferAppDefaults(appName, description) {
68
+ const text = `${appName || ''} ${description || ''}`;
69
+ const matched = INDUSTRY_APP_DEFAULTS.find((item) => item.pattern.test(text));
70
+ return matched ? { industry: matched.name, ...matched.options } : { industry: 'default', ...DEFAULT_APP_OPTIONS };
71
+ }
72
+
29
73
  // ── prd 文档更新 ──────────────────────────────────────
30
74
 
31
75
  function findPrdFile() {
@@ -177,11 +221,15 @@ function parseCreateAppArgs(args) {
177
221
 
178
222
  params.appName = params.appName || positional[0] || null;
179
223
  params.description = params.description || positional[1] || params.appName;
180
- params.icon = params.icon || positional[2] || DEFAULT_APP_OPTIONS.icon;
181
- params.iconColor = params.iconColor || positional[3] || DEFAULT_APP_OPTIONS.iconColor;
182
- params.colour = params.colour || positional[4] || DEFAULT_APP_OPTIONS.colour;
183
- params.navTheme = params.navTheme || positional[5] || DEFAULT_APP_OPTIONS.navTheme;
184
- params.layoutDirection = params.layoutDirection || positional[6] || DEFAULT_APP_OPTIONS.layoutDirection;
224
+
225
+ const inferredDefaults = inferAppDefaults(params.appName, params.description);
226
+ params.icon = params.icon || positional[2] || inferredDefaults.icon;
227
+ params.iconColor = params.iconColor || positional[3] || inferredDefaults.iconColor;
228
+ params.colour = params.colour || positional[4] || inferredDefaults.colour;
229
+ assertPresetThemeKey(params.colour);
230
+ params.navTheme = params.navTheme || positional[5] || null;
231
+ params.layoutDirection = params.layoutDirection || positional[6] || null;
232
+ params.industry = inferredDefaults.industry;
185
233
 
186
234
  return params;
187
235
  }
@@ -196,6 +244,40 @@ function printUsage() {
196
244
  process.stderr.write(` ${c.dim}${t('create_app.colors_list')}${c.reset}\n`);
197
245
  }
198
246
 
247
+ function buildCreateAppPayload(params, auth, contentLocale, openExclusive, openPhysicColumn) {
248
+ const {
249
+ appName,
250
+ description,
251
+ icon,
252
+ iconColor,
253
+ colour,
254
+ navTheme,
255
+ layoutDirection,
256
+ } = params;
257
+ const iconValue = `${icon}%%${iconColor}`;
258
+ const payload = {
259
+ _csrf_token: auth.csrfToken,
260
+ appName: JSON.stringify(buildYidaI18n(appName, { en_US: appName, ja_JP: appName })),
261
+ description: JSON.stringify(buildYidaI18n(description, { en_US: description, ja_JP: description })),
262
+ icon: iconValue,
263
+ iconUrl: iconValue,
264
+ colour,
265
+ defaultLanguage: contentLocale,
266
+ openExclusive,
267
+ openPhysicColumn,
268
+ openIsolationDatabase: 'n',
269
+ openExclusiveUnit: 'n',
270
+ group: 'ALL',
271
+ };
272
+ if (navTheme) {
273
+ payload.navTheme = navTheme;
274
+ }
275
+ if (layoutDirection) {
276
+ payload.layoutDirection = layoutDirection;
277
+ }
278
+ return payload;
279
+ }
280
+
199
281
  async function run(args) {
200
282
  const openOption = parseOpenOption(args);
201
283
  args = openOption.args;
@@ -220,13 +302,13 @@ async function run(args) {
220
302
 
221
303
  const { appName, description, icon, iconColor, colour, navTheme, layoutDirection } = params;
222
304
 
223
- const { c, banner, step, label, info, success: chalkSuccess, result: chalkResult } = require('../core/chalk');
305
+ const { c, banner, step, label, success: chalkSuccess, result: chalkResult } = require('../core/chalk');
224
306
 
225
307
  banner(t('create_app.title'));
226
308
  label('Name', appName);
227
309
  label('Desc', description);
228
310
  label('Icon', `${icon} ${c.dim}(${iconColor})${c.reset}`);
229
- label('Theme', `${colour} / ${navTheme} / ${layoutDirection}`);
311
+ label('Theme', `${colour} / ${navTheme || 'default'} / ${layoutDirection || 'default'}`);
230
312
 
231
313
  // Step 1: 读取登录态
232
314
  step(1, t('common.step_login', 1));
@@ -257,23 +339,9 @@ async function run(args) {
257
339
  // 查询失败时使用默认值,不影响主流程
258
340
  }
259
341
 
260
- const iconValue = `${icon}%%${iconColor}`;
261
342
  const response = await requestWithAutoLogin((auth) => {
262
- const postData = querystring.stringify({
263
- appName: JSON.stringify(buildYidaI18n(appName, { en_US: appName, ja_JP: appName })),
264
- description: JSON.stringify(buildYidaI18n(description, { en_US: description, ja_JP: description })),
265
- icon: iconValue,
266
- iconUrl: iconValue,
267
- colour,
268
- navTheme,
269
- layoutDirection,
270
- defaultLanguage: contentLocale,
271
- openExclusive: openExclusive,
272
- openPhysicColumn: openPhysicColumn,
273
- openIsolationDatabase: 'n',
274
- openExclusiveUnit: 'n',
275
- group: 'ALL',
276
- });
343
+ const payload = buildCreateAppPayload(params, auth, contentLocale, openExclusive, openPhysicColumn);
344
+ const postData = querystring.stringify(payload);
277
345
  return httpPost(auth.baseUrl, '/query/app/registerApp.json', postData);
278
346
  }, authRef);
279
347
 
@@ -306,4 +374,4 @@ async function run(args) {
306
374
  }
307
375
  }
308
376
 
309
- module.exports = { run, parseCreateAppArgs };
377
+ module.exports = { run, parseCreateAppArgs, inferAppDefaults, buildCreateAppPayload };
@@ -0,0 +1,263 @@
1
+ 'use strict';
2
+
3
+ function parseMaybeJsonValue(value) {
4
+ if (typeof value !== 'string') {
5
+ return value;
6
+ }
7
+ const trimmed = value.trim();
8
+ if (!trimmed) {
9
+ return value;
10
+ }
11
+ if (
12
+ (trimmed.startsWith('{') && trimmed.endsWith('}')) ||
13
+ (trimmed.startsWith('[') && trimmed.endsWith(']'))
14
+ ) {
15
+ try {
16
+ return JSON.parse(trimmed);
17
+ } catch {
18
+ return value;
19
+ }
20
+ }
21
+ return value;
22
+ }
23
+
24
+ function parseInlineValidationOptions(tokens) {
25
+ if (!Array.isArray(tokens) || tokens.length === 0) {
26
+ return null;
27
+ }
28
+
29
+ const rule = {};
30
+ for (let index = 0; index < tokens.length; index++) {
31
+ const token = tokens[index];
32
+ if (!token || !token.startsWith('--')) {
33
+ continue;
34
+ }
35
+ const key = token.slice(2).replace(/-/g, '_');
36
+ const next = tokens[index + 1];
37
+ if (next && !next.startsWith('--')) {
38
+ rule[key] = parseMaybeJsonValue(next);
39
+ index++;
40
+ } else {
41
+ rule[key] = true;
42
+ }
43
+ }
44
+
45
+ if (!rule.field && !rule.field_id && !rule.label && !rule.target && !rule.type) {
46
+ return null;
47
+ }
48
+
49
+ if (rule.field_id && !rule.fieldId) {
50
+ rule.fieldId = rule.field_id;
51
+ }
52
+ if (rule.domain_whitelist && !rule.domainWhitelist) {
53
+ rule.domainWhitelist = String(rule.domain_whitelist).split(',').map(function (item) {
54
+ return item.trim();
55
+ }).filter(Boolean);
56
+ }
57
+ if (rule.compare_to && !rule.compareTo) {
58
+ rule.compareTo = rule.compare_to;
59
+ }
60
+ if (rule.other_field && !rule.otherField) {
61
+ rule.otherField = rule.other_field;
62
+ }
63
+
64
+ return rule;
65
+ }
66
+
67
+ function createParseArgs(dependencies) {
68
+ const {
69
+ parseOpenOption,
70
+ normalizeYidaLocale,
71
+ usage,
72
+ hint,
73
+ error,
74
+ t,
75
+ throwCreateFormError,
76
+ } = dependencies;
77
+
78
+ return function parseArgs(inputArgs) {
79
+ const openOption = parseOpenOption(inputArgs || process.argv.slice(2));
80
+ const rawArgs = openOption.args;
81
+
82
+ const options = {
83
+ layout: 'single',
84
+ theme: 'default',
85
+ labelAlign: 'top',
86
+ contentLocale: null,
87
+ browserOpenMode: openOption.mode,
88
+ };
89
+
90
+ const args = [...rawArgs];
91
+
92
+ for (let i = 0; i < args.length; i++) {
93
+ if (args[i] === '--layout' && i + 1 < args.length) {
94
+ options.layout = args[i + 1];
95
+ args.splice(i, 2);
96
+ i--;
97
+ } else if (args[i] === '--theme' && i + 1 < args.length) {
98
+ options.theme = args[i + 1];
99
+ args.splice(i, 2);
100
+ i--;
101
+ } else if (args[i] === '--label-align' && i + 1 < args.length) {
102
+ options.labelAlign = args[i + 1];
103
+ args.splice(i, 2);
104
+ i--;
105
+ } else if ((args[i] === '--locale' || args[i] === '--content-locale' || args[i] === '--lang') && i + 1 < args.length) {
106
+ options.contentLocale = args[i + 1];
107
+ if (!normalizeYidaLocale(options.contentLocale)) {
108
+ error(`Unsupported locale: ${options.contentLocale}`);
109
+ throwCreateFormError(`Unsupported locale: ${options.contentLocale}`, 'CREATE_FORM_INVALID_ARGUMENTS');
110
+ }
111
+ process.env.OPENYIDA_CONTENT_LOCALE = normalizeYidaLocale(options.contentLocale);
112
+ args.splice(i, 2);
113
+ i--;
114
+ } else if (args[i] === '--force') {
115
+ options.force = true;
116
+ args.splice(i, 1);
117
+ i--;
118
+ }
119
+ }
120
+
121
+ const mode = args[0];
122
+
123
+ if (mode === 'create') {
124
+ if (args.length < 4) {
125
+ usage(t('create_form.usage_create'), t('create_form.example_create'));
126
+ throwCreateFormError(t('create_form.usage_create'), 'CREATE_FORM_INVALID_ARGUMENTS');
127
+ }
128
+ return {
129
+ mode: 'create',
130
+ appType: args[1],
131
+ formTitle: args[2],
132
+ fieldsJsonOrFile: args[3],
133
+ ...options
134
+ };
135
+ }
136
+
137
+ if (mode === 'update') {
138
+ if (args.length < 4) {
139
+ usage(t('create_form.usage_update'), t('create_form.example_update'));
140
+ throwCreateFormError(t('create_form.usage_update'), 'CREATE_FORM_INVALID_ARGUMENTS');
141
+ }
142
+ return {
143
+ mode: 'update',
144
+ appType: args[1],
145
+ formUuid: args[2],
146
+ changesJsonOrFile: args[3],
147
+ ...options
148
+ };
149
+ }
150
+
151
+ if (mode === 'patch') {
152
+ if (args.length < 4) {
153
+ usage(
154
+ 'openyida create-form patch <appType> <formUuid> <patchJsonOrFile>',
155
+ 'openyida create-form patch APP_XXX FORM-XXX .cache/openyida/forms/form-patch.json'
156
+ );
157
+ throwCreateFormError('openyida create-form patch <appType> <formUuid> <patchJsonOrFile>', 'CREATE_FORM_INVALID_ARGUMENTS');
158
+ }
159
+ return {
160
+ mode: 'patch',
161
+ appType: args[1],
162
+ formUuid: args[2],
163
+ patchJsonOrFile: args[3],
164
+ ...options
165
+ };
166
+ }
167
+
168
+ if (mode === 'rule' || mode === 'rules') {
169
+ if (args.length < 4) {
170
+ usage(
171
+ 'openyida create-form rule <appType> <formUuid> <rulesJsonOrFile>',
172
+ 'openyida create-form rule APP_XXX FORM-XXX .cache/openyida/forms/form-rules.json'
173
+ );
174
+ throwCreateFormError('openyida create-form rule <appType> <formUuid> <rulesJsonOrFile>', 'CREATE_FORM_INVALID_ARGUMENTS');
175
+ }
176
+ return {
177
+ mode: 'rule',
178
+ appType: args[1],
179
+ formUuid: args[2],
180
+ rulesJsonOrFile: args[3],
181
+ ...options
182
+ };
183
+ }
184
+
185
+ if (mode === 'validation' || mode === 'validate' || mode === 'validations') {
186
+ const inlineRule = parseInlineValidationOptions(args.slice(3));
187
+ if (args.length < 4 && !inlineRule) {
188
+ usage(
189
+ 'openyida create-form validation <appType> <formUuid> <validationsJsonOrFile>',
190
+ 'openyida create-form validation APP_XXX FORM-XXX .cache/openyida/forms/form-validations.json'
191
+ );
192
+ hint('openyida add-validation APP_XXX FORM-XXX --field "手机号" --type phone --message "请输入正确的手机号"');
193
+ throwCreateFormError('openyida create-form validation <appType> <formUuid> <validationsJsonOrFile>', 'CREATE_FORM_INVALID_ARGUMENTS');
194
+ }
195
+ return {
196
+ mode: 'validation',
197
+ appType: args[1],
198
+ formUuid: args[2],
199
+ validationJsonOrFile: inlineRule ? '' : args[3],
200
+ inlineValidationRule: inlineRule,
201
+ ...options
202
+ };
203
+ }
204
+
205
+ if (mode === 'bind-datasource' || mode === 'datasource' || mode === 'data-source') {
206
+ if (args.length < 5) {
207
+ usage(
208
+ 'openyida create-form bind-datasource <appType> <formUuid> <fieldLabelOrId> <dataSourceJsonOrFile>',
209
+ 'openyida create-form bind-datasource APP_XXX FORM-XXX "客户" .cache/openyida/forms/customer-datasource.json'
210
+ );
211
+ throwCreateFormError('openyida create-form bind-datasource <appType> <formUuid> <fieldLabelOrId> <dataSourceJsonOrFile>', 'CREATE_FORM_INVALID_ARGUMENTS');
212
+ }
213
+ return {
214
+ mode: 'bind-datasource',
215
+ appType: args[1],
216
+ formUuid: args[2],
217
+ fieldLabel: args[3],
218
+ dataSourceJsonOrFile: args[4],
219
+ ...options
220
+ };
221
+ }
222
+
223
+ if (mode === 'add-option') {
224
+ if (args.length < 5) {
225
+ usage(
226
+ 'openyida create-form add-option <appType> <formUuid> <fieldLabel> <option1> [option2] ...',
227
+ 'openyida create-form add-option APP_XXX FORM-XXX "优先级" "P0" "P1"'
228
+ );
229
+ throwCreateFormError('openyida create-form add-option <appType> <formUuid> <fieldLabel> <option1> [option2] ...', 'CREATE_FORM_INVALID_ARGUMENTS');
230
+ }
231
+ return {
232
+ mode: 'add-option',
233
+ appType: args[1],
234
+ formUuid: args[2],
235
+ fieldLabel: args[3],
236
+ newOptions: args.slice(4).filter(function (arg) { return !arg.startsWith('--'); }),
237
+ ...options
238
+ };
239
+ }
240
+
241
+ if (args.length >= 3 && mode !== 'create' && mode !== 'update' && mode !== 'patch' && mode !== 'rule' && mode !== 'rules' && mode !== 'validation' && mode !== 'validate' && mode !== 'validations' && mode !== 'bind-datasource' && mode !== 'datasource' && mode !== 'data-source') {
242
+ return {
243
+ mode: 'create',
244
+ appType: args[0],
245
+ formTitle: args[1],
246
+ fieldsJsonOrFile: args[2],
247
+ ...options
248
+ };
249
+ }
250
+
251
+ usage(t('create_form.usage_create_short'));
252
+ hint(t('create_form.usage_update_short'));
253
+ hint(t('create_form.example_create'));
254
+ hint(t('create_form.example_update'));
255
+ throwCreateFormError(t('create_form.usage_create_short'), 'CREATE_FORM_INVALID_ARGUMENTS');
256
+ };
257
+ }
258
+
259
+ module.exports = {
260
+ createParseArgs,
261
+ parseInlineValidationOptions,
262
+ parseMaybeJsonValue,
263
+ };
@@ -0,0 +1,27 @@
1
+ 'use strict';
2
+
3
+ function dispatchCreateFormCommand(parsedArgs, authContext, handlers) {
4
+ const args = [parsedArgs, authContext];
5
+
6
+ switch (parsedArgs.mode) {
7
+ case 'update':
8
+ return handlers.update(...args);
9
+ case 'patch':
10
+ return handlers.patch(...args);
11
+ case 'rule':
12
+ return handlers.rule(...args);
13
+ case 'validation':
14
+ return handlers.validation(...args);
15
+ case 'bind-datasource':
16
+ return handlers.bindDataSource(...args);
17
+ case 'add-option':
18
+ return handlers.addOption(...args);
19
+ case 'create':
20
+ default:
21
+ return handlers.create(...args);
22
+ }
23
+ }
24
+
25
+ module.exports = {
26
+ dispatchCreateFormCommand,
27
+ };