openyida 2026.9.19 → 2026.9.21
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.
- package/README.md +4 -4
- package/lib/app/application-style.js +69 -0
- package/lib/app/create-form/args.js +37 -12
- package/lib/app/create-form/batch.js +32 -5
- package/lib/app/create-form.js +94 -57
- package/lib/app/form-field-validator.js +0 -36
- package/lib/app/services/form-compiler.js +0 -2
- package/lib/app/theme-from-design.js +40 -14
- package/lib/app/update-app.js +63 -13
- package/lib/core/command-manifest.js +81 -25
- package/lib/core/locales/en.js +20 -3
- package/lib/core/locales/zh.js +20 -3
- package/lib/core/sample.js +36 -14
- package/lib/design/document.js +1 -0
- package/lib/design-plan/confirmation.js +13 -0
- package/lib/design-plan/design-plan.js +44 -2
- package/lib/design-plan/entry-navigation.js +10 -2
- package/lib/design-plan/init.js +16 -9
- package/lib/design-plan/materialize.js +85 -45
- package/lib/design-plan/normalize.js +13 -14
- package/lib/design-plan/parallel.js +62 -13
- package/lib/design-plan/patch.js +21 -7
- package/lib/design-plan/rebase.js +60 -0
- package/lib/design-plan/themes.js +16 -1
- package/lib/design-plan/validate.js +16 -1
- package/lib/design-plan/visual-policy.js +29 -4
- package/lib/samples/openyida-scaffold/canvas-form-drawer.canvas.jsx +3 -3
- package/lib/samples/openyida-scaffold/canvas-nav/mixed.jsx +6 -4
- package/lib/samples/openyida-scaffold/canvas-nav/shared.jsx +5 -5
- package/lib/samples/openyida-scaffold/canvas-nav/side.jsx +1 -2
- package/lib/samples/openyida-scaffold/canvas-nav/sidebar.jsx +1 -1
- package/lib/samples/openyida-scaffold/canvas-nav/top.jsx +5 -4
- package/package.json +1 -1
- package/yida-skills/SKILL.md +2 -2
- package/yida-skills/references/official-example-schema-patterns.md +1 -1
- package/yida-skills/references/yida-api.md +4 -0
- package/yida-skills/skills/yida-app/SKILL.md +15 -4
- package/yida-skills/skills/yida-app/references/entry-navigation.md +11 -9
- package/yida-skills/skills/yida-app/workflow/plan/step-4-deliver.md +1 -1
- package/yida-skills/skills/yida-app/workflow/plan/workflow.md +11 -4
- package/yida-skills/skills/yida-app/workflow/step-2-design.md +3 -3
- package/yida-skills/skills/yida-app/workflow/step-3-create-or-reuse-app.md +2 -2
- package/yida-skills/skills/yida-app/workflow/step-8-publish-navigation.md +3 -3
- package/yida-skills/skills/yida-app/workflow/step-9-output-finish.md +3 -2
- package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +2 -2
- package/yida-skills/skills/yida-canvas-custom-page/references/canvas-style-implementation-guide.md +1 -1
- package/yida-skills/skills/yida-canvas-custom-page/references/canvas-theme-provider.md +1 -1
- package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +140 -1
- package/yida-skills/skills/yida-canvas-custom-page/references/navigation-and-entry-guide.md +1 -1
- package/yida-skills/skills/yida-canvas-custom-page/scripts/canvas-theme-provider.template.jsx +1 -1
- package/yida-skills/skills/yida-canvas-data-binding/SKILL.md +7 -0
- package/yida-skills/skills/yida-create-form-page/SKILL.md +34 -43
- package/yida-skills/skills/yida-create-form-page/references/advanced-form-modes.md +5 -5
- package/yida-skills/skills/yida-create-form-page/references/association-form-field.md +4 -4
- package/yida-skills/skills/yida-create-form-page/references/batch-forms.md +2 -2
- package/yida-skills/skills/yida-create-form-page/references/field-definition-guide.md +4 -16
- package/yida-skills/skills/yida-create-form-page/references/form-field-properties.md +14 -37
- package/yida-skills/skills/yida-design/SKILL.md +7 -5
- package/yida-skills/skills/yida-design/references/application-style-library.md +93 -0
- package/yida-skills/skills/yida-design/references/application-theme-consistency.md +48 -7
- package/yida-skills/skills/yida-design/references/ask-human-interaction-contract.md +1 -1
- package/yida-skills/skills/yida-design/references/native-form-styles.md +208 -0
- package/yida-skills/skills/yida-design/references/navigation-decision.md +6 -4
- package/yida-skills/skills/yida-design/references/theme/app-custom-theme-template.css +110 -1
- package/yida-skills/skills/yida-design/references/theme/application-style-recipes.css +58 -0
- package/yida-skills/skills/yida-design/references/theme-selection.md +12 -11
- package/yida-skills/skills/yida-design/references/visual-decision-engine.md +1 -1
- package/yida-skills/skills/yida-design/scripts/validate_design_themes.py +49 -6
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/SKILL.md +13 -3
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-compact-schema.md +6 -2
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-schema.md +5 -3
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/visual-design.md +3 -1
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/visual-theme-selection.md +22 -23
- package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/scripts/render_build_plan.py +2 -0
- package/yida-skills/skills/yida-design/templates/application-styles.json +398 -0
- package/yida-skills/skills/yida-design/templates/design-themes/README.md +15 -10
- package/yida-skills/skills/yida-design/templates/design-themes/app-amber/app_theme.css +748 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-amber/design.md +274 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-amber/form-layout.json +15 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/app_theme.css +748 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/design.md +274 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-executive/app_theme.css +748 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-executive/design.md +274 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-executive/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-finance/app_theme.css +748 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-finance/design.md +274 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-finance/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-glass/app_theme.css +748 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-glass/design.md +274 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-glass/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/app_theme.css +748 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/design.md +274 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-line/app_theme.css +748 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-line/design.md +274 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-line/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-neon/app_theme.css +748 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-neon/design.md +274 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-neon/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/app_theme.css +754 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/design.md +279 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-paper/app_theme.css +748 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-paper/design.md +274 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-paper/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/app_theme.css +748 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/design.md +274 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-plum/app_theme.css +748 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-plum/design.md +274 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-plum/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-pop/app_theme.css +758 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-pop/design.md +281 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-pop/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-sage/app_theme.css +748 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-sage/design.md +274 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-sage/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-teal/app_theme.css +748 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-teal/design.md +274 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-teal/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/app_theme.css +754 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/design.md +279 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/app_theme.css +752 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/design.md +278 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-wire/app_theme.css +748 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-wire/design.md +274 -0
- package/yida-skills/skills/yida-design/templates/design-themes/app-wire/form-layout.json +14 -0
- package/yida-skills/skills/yida-design/templates/design-themes/basic-tokens.json +2 -1
- package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/app_theme.css +690 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{dark-inset-hairline.md → dark-inset-hairline/design.md} +107 -58
- package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/app_theme.css +691 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{dark-rail-fine-lines.md → dark-rail-fine-lines/design.md} +106 -50
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/app_theme.css +696 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{dark-rail-signal-panels.md → dark-rail-signal-panels/design.md} +66 -12
- package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/free-creative/app_theme.css +689 -0
- package/yida-skills/skills/yida-design/templates/design-themes/free-creative/design.md +238 -0
- package/yida-skills/skills/yida-design/templates/design-themes/free-creative/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/app_theme.css +692 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{graphite-bevel-grid.md → graphite-bevel-grid/design.md} +64 -10
- package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/app_theme.css +691 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{hairline-shared-bands.md → hairline-shared-bands/design.md} +66 -12
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/app_theme.css +691 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{hairline-soft-blocks.md → hairline-soft-blocks/design.md} +61 -9
- package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/index.json +399 -31
- package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/app_theme.css +701 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{ink-glow-soft-panels.md → ink-glow-soft-panels/design.md} +62 -8
- package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/app_theme.css +691 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{inset-frame-pixel-rhythm.md → inset-frame-pixel-rhythm/design.md} +63 -9
- package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/app_theme.css +698 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{outlined-texture-duotone.md → outlined-texture-duotone/design.md} +66 -12
- package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/app_theme.css +691 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{soft-inset-surfaces.md → soft-inset-surfaces/design.md} +63 -11
- package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/app_theme.css +690 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{soft-outline-rhythm.md → soft-outline-rhythm/design.md} +64 -26
- package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/app_theme.css +698 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{soft-rail-bold-band.md → soft-rail-bold-band/design.md} +103 -49
- package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/app_theme.css +692 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{soft-spectral-panels.md → soft-spectral-panels/design.md} +67 -13
- package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/app_theme.css +711 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{warm-canvas-contrast-panels.md → warm-canvas-contrast-panels/design.md} +64 -10
- package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/app_theme.css +692 -0
- package/yida-skills/skills/yida-design/templates/design-themes/{warm-rail-muted-panels.md → warm-rail-muted-panels/design.md} +102 -50
- package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/form-layout.json +13 -0
- package/yida-skills/skills/yida-design/templates/navigation-styles.json +769 -0
- package/yida-skills/skills/yida-design/workflow/output-design.md +9 -6
- package/yida-skills/skills/yida-design/workflow/step-2-theme-system.md +12 -4
- package/yida-skills/skills/yida-design/workflow/step-6-handoff.md +1 -1
- package/yida-skills/skills/yida-form-permission/SKILL.md +6 -0
- package/yida-skills/skills/yida-nav-shell/SKILL.md +1 -1
- package/yida-skills/skills/yida-nav-shell/references/nav-shell-patterns.md +6 -0
- package/yida-skills/skills/yida-page-config/SKILL.md +9 -0
- package/yida-skills/skills/yida-prd/SKILL.md +1 -0
- package/yida-skills/skills/yida-prd/workflow/output-prd.md +2 -2
- package/yida-skills/skills/yida-prd/workflow/step-2-information-architecture.md +1 -1
- package/yida-skills/skills/yida-requirement-analysis/references/experience-groups.md +45 -9
- package/yida-skills/skills/yida-requirement-analysis/references/handoff.md +5 -5
- package/yida-skills/skills/yida-requirement-analysis/workflow/prepare-brief.md +17 -4
- package/yida-skills/skills-index.json +2 -2
package/lib/core/locales/en.js
CHANGED
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
6
|
module.exports = {
|
|
7
|
+
design_plan: {
|
|
8
|
+
rebase_required: 'Before first materialization, repair the matching facts in business.json/visual.json and preserve the source baseline. If the source changed, add --rebase-parts to the original materialize command to reconcile against the saved baseline. Do not invent a digest, delete drafts, or run init again.',
|
|
9
|
+
baseline_missing: 'No trusted baseline matches these parts. Preserve the plan and facts; restore .build-plan-base.json from the original workspace. If unavailable, report the blocker instead of inventing a digest or rebuilding.',
|
|
10
|
+
rebase_stage_invalid: 'Rebasing is limited to drafts before first materialization. For presented or materialized plans use patch --materialize on the current build-plan.json, without merging initial parts again.',
|
|
11
|
+
rebase_conflict: 'The source and part changed the same field differently. Review conflicts and explicitly select the current or baseline value in the part before retrying; preserve other facts. No files were saved.',
|
|
12
|
+
repair_page_bindings: 'Repair pageApplications in visual.json to match customPageDetails in business.json one to one; exclude native forms. Each visualMemoryApplications must be an array; use [] when none apply. Keep the existing draft, fix the listed fields and retry the original command. Do not delete the directory or run init again.',
|
|
13
|
+
},
|
|
7
14
|
design_document: {
|
|
8
15
|
update_conflict: 'Cannot update {0} ({1}): the existing content differs from the last generated version. Read this section, reconcile the local edit with the plan source, and retry. No files were saved.',
|
|
9
16
|
theme_css_invalid: 'Theme CSS near line {0} has an unclosed or mismatched delimiter, string, or comment. Fix it and retry.',
|
|
@@ -174,6 +181,8 @@ module.exports = {
|
|
|
174
181
|
},
|
|
175
182
|
|
|
176
183
|
cli: {
|
|
184
|
+
design_plan_entry_mode_required: 'Choose an entry mode: shared business pages (unified), separate frontend and business backend (service-management), frontend only (frontend-only), or business backend only (backend-only).',
|
|
185
|
+
design_plan_backend_only_roles: 'For backend-only, every entry must use role management.',
|
|
177
186
|
design_plan_local_menu_binding: 'Local menu {0} requires a host page and viewKey: entry {1} sceneKey must match the page sceneKey, menu resource must equal the page name, and viewKey must be nonempty. This applies to every entry role.',
|
|
178
187
|
design_plan_visual_object_required: '{0} must be an object, not a string or array. Preserve the structure generated by init and fill in its values. Example: {1}.',
|
|
179
188
|
help: `
|
|
@@ -190,7 +199,7 @@ Commands:
|
|
|
190
199
|
create-app --name "<name>" Create an app and output appType; configure theme resources and Logo source with update-app
|
|
191
200
|
create-page <appType> "<pageName>" [--mode dashboard] [--hide-nav] Create a custom page, output pageId
|
|
192
201
|
update-app <appType> [--name "..."] [--hide-app-nav|--show-app-nav] Update app info
|
|
193
|
-
create-form create <appType> "<formName>" <fieldsJSON> [--layout
|
|
202
|
+
create-form create <appType> "<formName>" <fieldsJSON> [--layout single|double|card|section] [--theme default|compact|comfortable] [--label-align top|left|right] Create a form page
|
|
194
203
|
create-form update <appType> <formUuid> <changesJSON> Update a form page
|
|
195
204
|
list-forms <appType> [--keyword <text>] List forms/pages in an app
|
|
196
205
|
get-schema <appType> <formUuid|--all> Get one form Schema or all form Schemas
|
|
@@ -848,12 +857,12 @@ Examples:
|
|
|
848
857
|
changes_applied: ' Changes applied: {0}',
|
|
849
858
|
create_post_failure_retry_advice: 'Do not repeat create directly. First run openyida list-forms {0} --keyword "{1}" to check for an existing same-title form; if this run already created a blank/existing form, prefer create-form update or a future --resume-form-uuid flow.',
|
|
850
859
|
error: '\n❌ Error: {0}',
|
|
851
|
-
usage_create: 'Usage: openyida create-form create <appType> <formTitle> <fieldsJsonFile>',
|
|
860
|
+
usage_create: 'Usage: 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]',
|
|
852
861
|
example_create: 'Example: openyida create-form create "APP_XXX" "Employee Info" .cache/openyida/forms/employee-fields.json',
|
|
853
862
|
usage_update: 'Usage: openyida create-form update <appType> <formUuid> <changesJsonOrFile>',
|
|
854
863
|
example_update: 'Example: openyida create-form update "APP_XXX" "FORM-YYY" \'[{"action":"add","field":{"type":"TextField","label":"Note"}}]\'',
|
|
855
864
|
usage_label: 'Usage:',
|
|
856
|
-
usage_create_short: ' create: openyida create-form create <appType> <formTitle> <fieldsJsonFile>',
|
|
865
|
+
usage_create_short: ' create: 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]',
|
|
857
866
|
usage_update_short: ' update: openyida create-form update <appType> <formUuid> <changesJsonOrFile> or --data-file <changesJsonOrFile>',
|
|
858
867
|
resume_readback_failed: 'Unable to read the target form before resume.',
|
|
859
868
|
resume_ownership_unverified: 'The target form does not belong to the requested app; resume stopped.',
|
|
@@ -1152,6 +1161,7 @@ Examples:
|
|
|
1152
1161
|
theme_preset_conflict: 'A preset colour cannot be combined with custom CSS or themeColor. Use --colour custom or omit --colour.',
|
|
1153
1162
|
custom_theme_color_required: 'colour=custom requires a theme file or a valid themeColor. Pass --theme-file or --theme-color.',
|
|
1154
1163
|
theme_not_persisted: 'App theme readback failed or did not match the saved settings. The CSS resource binding is unverified. Inspect themeVerification and retry update-app <appType> --theme-file <css>; do not refresh the app.',
|
|
1164
|
+
navigation_not_persisted: 'App navigation readback failed or did not match the requested settings. Navigation changes remain unverified. Inspect the expected values, actual values and readback error in navigationVerification, then check the current app settings.',
|
|
1155
1165
|
usage: 'openyida update-app <appType> [--name "New Name"] [--theme-file ./theme.css] [--nav-theme light|dark|white|gray] [--logo-source appIcon|customImage] [--layout side|top|l_shape]',
|
|
1156
1166
|
example: 'openyida update-app APP_XXX --theme-file ./app-theme.css --nav-theme light --logo-source appIcon --layout side',
|
|
1157
1167
|
options: 'Options:\n --name, -n App name (specify at least one update field)\n --desc, -d App description\n --icon Icon name (e.g. xian-yingyong)\n --icon-color Icon color (default: #0089FF)\n --colour, --theme podBlue | podGreen | podOrange | deepBlue | teal | black | custom ...\n --theme-color Update the app primary color; the CSS primary color takes precedence when a theme file is supplied\n --theme-file Custom app theme CSS file (up to 20 MB; must declare --color-brand1-6)\n --nav-theme Navigation theme: light, dark, white, or gray\n --logo-source Navigation logo source: appIcon or customImage\n --layout Modern navigation layout: side, top, or l_shape\n --hide-app-nav Hide app navigation in visit mode, only for custom pages with self-rendered top/side navigation\n --show-app-nav Restore app navigation in visit mode',
|
|
@@ -2123,3 +2133,10 @@ module.exports.connector_e2e = {
|
|
|
2123
2133
|
Object.assign(module.exports.process_errors || (module.exports.process_errors = {}), {
|
|
2124
2134
|
action_config_invalid: 'Invalid approval action configuration for node {0}: {1}',
|
|
2125
2135
|
});
|
|
2136
|
+
|
|
2137
|
+
module.exports.cli_argument = { invalid: 'Invalid or missing argument value: {0}. Follow the command help.' };
|
|
2138
|
+
|
|
2139
|
+
module.exports.sample_options = {
|
|
2140
|
+
'theme_help': 'app-theme: --output is a CSS file; --design-file reads a completed design. Omitting it resets CSS. Set theme values in the design.',
|
|
2141
|
+
'style_help': 'application-style: --style-id is required and accepts every catalog theme; --output is a directory for three files. Existing bundle files cause an error.'
|
|
2142
|
+
};
|
package/lib/core/locales/zh.js
CHANGED
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
'use strict';
|
|
5
5
|
|
|
6
6
|
module.exports = {
|
|
7
|
+
design_plan: {
|
|
8
|
+
rebase_required: '首次物化前请修正 business.json/visual.json 中的对应 facts,保留主计划基线。如果主计划已改变,在原 materialize 命令加 --rebase-parts,CLI 会根据保存的基线核对差异;不要手填 digest、删除草稿或重新 init。',
|
|
9
|
+
baseline_missing: '未找到与片段匹配的可信原始基线。保留当前计划与 facts;从原工作区恢复 .build-plan-base.json 后重试。无法恢复时明确告知用户阻塞,不伪造摘要或自动重建。',
|
|
10
|
+
rebase_stage_invalid: '基线恢复仅用于首次物化前的草稿。已展示或已物化方案请沿用当前 build-plan.json,通过 patch --materialize 调整,不再合并初始化片段。',
|
|
11
|
+
rebase_conflict: '主计划和片段对同一字段有不同修改。按 conflicts 核对并在片段中明确采用当前值或原基线值后重试;其他 facts 保留。本次未保存文件。',
|
|
12
|
+
repair_page_bindings: '按 business.json 的 customPageDetails 逐一修复 visual.json 的 pageApplications;原生表单不加入绑定。每项 visualMemoryApplications 必须为数组,无适用项用 []。保留现有草稿,按列出的字段修复后重试原命令;不要删除目录或重新 init。',
|
|
13
|
+
},
|
|
7
14
|
design_document: {
|
|
8
15
|
update_conflict: '无法更新 {0}({1}):现有内容与上次生成结果冲突。请读取这一部分,将本地修改与计划源对齐后重试;本次未保存任何文件。',
|
|
9
16
|
theme_css_invalid: '主题 CSS 第 {0} 行附近存在未闭合或不匹配的括号、字符串或注释,请修复后重试。',
|
|
@@ -174,6 +181,8 @@ module.exports = {
|
|
|
174
181
|
},
|
|
175
182
|
|
|
176
183
|
cli: {
|
|
184
|
+
design_plan_entry_mode_required: '请明确入口方式:不分前后台(unified)、分前后台(service-management)、只有访问前台(frontend-only)或只有访问后台(backend-only)。',
|
|
185
|
+
design_plan_backend_only_roles: '只有访问后台(backend-only)时,每个入口的 role 必须为 management。',
|
|
177
186
|
design_plan_local_menu_binding: '本地菜单 {0} 必须关联承载页面和 viewKey:入口 {1} 的 sceneKey 对应页面 sceneKey,菜单 resource 等于页面 name,并填写非空 viewKey。此规则适用于所有入口身份。',
|
|
178
187
|
design_plan_visual_object_required: '{0} 必须为对象,不能写成字符串或数组。沿用 init 生成的字段结构,只补齐值;示例:{1}。',
|
|
179
188
|
help: `
|
|
@@ -190,7 +199,7 @@ openyida - 宜搭命令行工具
|
|
|
190
199
|
create-app --name "<名称>" 创建应用并输出 appType;主题资源与 Logo 来源使用 update-app 配置
|
|
191
200
|
create-page <appType> "<页面名>" [--mode dashboard] [--hide-nav] 创建自定义页面,输出 pageId
|
|
192
201
|
update-app <appType> [--name "..."] [--hide-app-nav|--show-app-nav] 更新应用信息
|
|
193
|
-
create-form create <appType> "<表单名>" <字段JSON> [--layout
|
|
202
|
+
create-form create <appType> "<表单名>" <字段JSON> [--layout single|double|card|section] [--theme default|compact|comfortable] [--label-align top|left|right] 创建表单页面
|
|
194
203
|
create-form update <appType> <formUuid> <修改JSON> 更新表单页面
|
|
195
204
|
list-forms <appType> [--keyword <关键词>] 列出应用下的表单/页面
|
|
196
205
|
get-schema <appType> <formUuid|--all> 获取单个或全部表单 Schema
|
|
@@ -819,12 +828,12 @@ openyida - 宜搭命令行工具
|
|
|
819
828
|
changes_applied: ' 已应用变更: {0}',
|
|
820
829
|
create_post_failure_retry_advice: '不要直接重复 create。先运行 openyida list-forms {0} --keyword "{1}" 确认同名表单;若是本轮创建的空白/已有表单,优先使用 create-form update 或后续 --resume-form-uuid 复用。',
|
|
821
830
|
error: '\n❌ 错误: {0}',
|
|
822
|
-
usage_create: '用法: openyida create-form create <appType> <formTitle> <fieldsJsonFile>',
|
|
831
|
+
usage_create: '用法: 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]',
|
|
823
832
|
example_create: '示例:openyida create-form create "APP_XXX" "员工信息登记" .cache/openyida/forms/employee-fields.json',
|
|
824
833
|
usage_update: '用法: openyida create-form update <appType> <formUuid> <changesJsonOrFile>',
|
|
825
834
|
example_update: '示例:openyida create-form update "APP_XXX" "FORM-YYY" \'[{"action":"add","field":{"type":"TextField","label":"备注"}}]\'',
|
|
826
835
|
usage_label: '用法:',
|
|
827
|
-
usage_create_short: ' 创建: openyida create-form create <appType> <formTitle> <fieldsJsonFile>',
|
|
836
|
+
usage_create_short: ' 创建: 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]',
|
|
828
837
|
usage_update_short: ' 更新: openyida create-form update <appType> <formUuid> <changesJsonOrFile> 或 --data-file <changesJsonOrFile>',
|
|
829
838
|
resume_readback_failed: '恢复前无法回读目标表单。',
|
|
830
839
|
resume_ownership_unverified: '目标表单不属于指定应用,已停止恢复。',
|
|
@@ -1082,6 +1091,7 @@ openyida - 宜搭命令行工具
|
|
|
1082
1091
|
theme_preset_conflict: '平台预置 colour 不能与自定义 CSS 或 themeColor 同传;请使用 colour=custom 或省略 --colour。',
|
|
1083
1092
|
custom_theme_color_required: 'colour=custom 需要主题文件或有效 themeColor;请传 --theme-file 或 --theme-color。',
|
|
1084
1093
|
theme_not_persisted: '应用主题保存后回读不一致或查询失败,CSS 资源尚未确认绑定。请查看 themeVerification,并使用 update-app <appType> --theme-file <css> 重试;不要重复创建应用。',
|
|
1094
|
+
navigation_not_persisted: '应用导航保存后回读不一致或查询失败,导航设置尚未确认生效。请查看 navigationVerification 中的期望值、实际值和查询错误,核实应用当前设置。',
|
|
1085
1095
|
usage: 'openyida update-app <appType> [--name "新名称"] [--theme-file ./theme.css] [--nav-theme light|dark|white|gray] [--logo-source appIcon|customImage] [--layout side|top|l_shape]',
|
|
1086
1096
|
example: 'openyida update-app APP_XXX --theme-file ./app-theme.css --nav-theme light --logo-source appIcon --layout side',
|
|
1087
1097
|
options: '选项:\n --name, -n 应用名称(至少指定一个更新字段)\n --desc, -d 应用描述\n --icon 图标名称(如: xian-yingyong)\n --icon-color 图标颜色(默认: #0089FF)\n --colour, --theme podBlue | podGreen | podOrange | deepBlue | teal | black | custom ...\n --theme-color 更新应用主色;与主题文件同传时以 CSS 主色为准\n --theme-file 自定义应用主题 CSS 文件(最大 20 MB,必须声明 --color-brand1-6)\n --nav-theme 导航主题 light、dark、white 或 gray\n --logo-source 导航 Logo 来源 appIcon 或 customImage\n --layout 新版导航布局 side、top 或 l_shape\n --hide-app-nav 隐藏访问态应用导航,仅在自定义页自绘顶部/侧边导航壳时使用\n --show-app-nav 恢复访问态应用导航',
|
|
@@ -2077,3 +2087,10 @@ module.exports.connector_e2e = {
|
|
|
2077
2087
|
Object.assign(module.exports.process_errors || (module.exports.process_errors = {}), {
|
|
2078
2088
|
action_config_invalid: '节点 {0} 的审批动作配置无效:{1}',
|
|
2079
2089
|
});
|
|
2090
|
+
|
|
2091
|
+
module.exports.cli_argument = { invalid: '参数无效或缺少值:{0}。请按命令帮助填写。' };
|
|
2092
|
+
|
|
2093
|
+
module.exports.sample_options = {
|
|
2094
|
+
'theme_help': 'app-theme:--output 指向 CSS 文件;--design-file 读取已完成的设计。省略设计文件会重置 CSS,主题值通过设计填写。',
|
|
2095
|
+
'style_help': 'application-style:--style-id 必填,支持目录中全部主题;--output 指向目录,输出三文件,有同名文件时报错。'
|
|
2096
|
+
};
|
package/lib/core/sample.js
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
const fs = require('fs');
|
|
19
19
|
const path = require('path');
|
|
20
20
|
const { CliError } = require('./cli-error');
|
|
21
|
+
const { t } = require('./i18n');
|
|
21
22
|
|
|
22
23
|
// ── Sample 索引表 ─────────────────────────────────────────────────────
|
|
23
24
|
|
|
@@ -111,7 +112,7 @@ const SAMPLE_HINTS = {
|
|
|
111
112
|
'openyida-page-template/canvas-nav-top': '顶部默认贴顶通栏;长页先合并 canvas-nav-content,CanvasNav 传 headerOnly,有首屏背景时传 overlay;悬浮外观仅显式 floating=true。',
|
|
112
113
|
'openyida-page-template/canvas-nav-content': '合并 CanvasNavigationContent;长页用 layout=document,CanvasNav 传 headerOnly/overlay;默认 sticky,受宿主限制时用 navigationPosition=fixed。工作区用 workspace,宿主已分配高度时传 height。',
|
|
113
114
|
'openyida-page-template/canvas-nav-data': '页内展示用 mode=local(key/viewKey/targetType=local),不请求平台菜单;platform 需真实资源 ID;independent 或声明 access 时必须接入真实 resolveAccess。保留 PRD 顺序与分组。',
|
|
114
|
-
'openyida-page-template/form-open-container': '将 import、CanvasDrawer、FormOpenContainer、useYidaFormOpen 和辅助函数合并到现有 Canvas 页面;表单按钮调用 openForm(request),页面必须渲染返回的 formOpenContainer;保留 iframe、标题栏操作、调宽和关闭刷新。普通业务内容使用 CanvasDrawer
|
|
115
|
+
'openyida-page-template/form-open-container': '将 import、CanvasDrawer、FormOpenContainer、useYidaFormOpen 和辅助函数合并到现有 Canvas 页面;表单按钮调用 openForm(request),页面必须渲染返回的 formOpenContainer;保留 iframe、标题栏操作、调宽和关闭刷新。普通业务内容使用 CanvasDrawer;抽屉背景使用 --pod-page-bg-color,文字使用 --color-text1-4,background 可按设计覆盖。',
|
|
115
116
|
'yida-design/app-theme': '已复制应用主题模板;请由 yida-design 按 design.md 定点修改需要变化的 token。',
|
|
116
117
|
};
|
|
117
118
|
|
|
@@ -148,6 +149,9 @@ function printSampleList() {
|
|
|
148
149
|
}
|
|
149
150
|
console.log('');
|
|
150
151
|
console.log(' 应用主题:openyida sample yida-design app-theme --output <app-theme.css> --design-file <design.md>');
|
|
152
|
+
console.log(' Application style: openyida sample yida-design application-style --style-id <themeId|free-creative> --output <directory>');
|
|
153
|
+
console.log(` ${t('sample_options.theme_help')}`);
|
|
154
|
+
console.log(` ${t('sample_options.style_help')}`);
|
|
151
155
|
}
|
|
152
156
|
|
|
153
157
|
/**
|
|
@@ -162,23 +166,29 @@ function ensureDirectoryExists(filePath) {
|
|
|
162
166
|
}
|
|
163
167
|
|
|
164
168
|
/**
|
|
165
|
-
* 解析
|
|
169
|
+
* 解析 sample 输出路径、设计文件、主题 ID 与模板变量;拒绝未声明参数。
|
|
166
170
|
* @param {string[]} rest
|
|
167
171
|
* @param {string} defaultOutputPath
|
|
168
|
-
* @returns {{ outputPath: string, variables: Object }}
|
|
172
|
+
* @returns {{ outputPath: string, variables: Object, designFile?: string, styleId?: string }}
|
|
169
173
|
*/
|
|
170
174
|
function parseOptions(rest, defaultOutputPath) {
|
|
171
175
|
let outputPath = defaultOutputPath;
|
|
172
176
|
let designFile;
|
|
177
|
+
let styleId;
|
|
173
178
|
const variables = {};
|
|
174
179
|
|
|
175
180
|
for (let i = 0; i < rest.length; i++) {
|
|
176
181
|
const arg = rest[i];
|
|
182
|
+
const invalid = () => {throw new CliError(t('cli_argument.invalid', arg), { code: 'SAMPLE_ARGUMENT_INVALID' });};
|
|
183
|
+
if (!['--output', '--var', '--design-file', '--style-id'].includes(arg)) {invalid();}
|
|
184
|
+
if (!rest[i + 1] || rest[i + 1].startsWith('--')) {invalid();}
|
|
185
|
+
|
|
186
|
+
if (arg === '--style-id') {
|
|
187
|
+
styleId = rest[++i];
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
177
190
|
|
|
178
191
|
if (arg === '--design-file') {
|
|
179
|
-
if (!rest[i + 1] || rest[i + 1].startsWith('--')) {
|
|
180
|
-
throw new CliError('--design-file 缺少 design.md 路径', { code: 'DESIGN_THEME_FILE_REQUIRED' });
|
|
181
|
-
}
|
|
182
192
|
designFile = rest[++i];
|
|
183
193
|
continue;
|
|
184
194
|
}
|
|
@@ -192,19 +202,15 @@ function parseOptions(rest, defaultOutputPath) {
|
|
|
192
202
|
if (arg === '--var' && rest[i + 1]) {
|
|
193
203
|
const pair = rest[i + 1];
|
|
194
204
|
const eqIndex = pair.indexOf('=');
|
|
195
|
-
if (eqIndex
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
if (key) {
|
|
199
|
-
variables[key] = value;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
205
|
+
if (eqIndex <= 0 || !pair.slice(0, eqIndex).trim()) {invalid();}
|
|
206
|
+
const key = pair.slice(0, eqIndex).trim();
|
|
207
|
+
variables[key] = pair.slice(eqIndex + 1);
|
|
202
208
|
i++;
|
|
203
209
|
continue;
|
|
204
210
|
}
|
|
205
211
|
}
|
|
206
212
|
|
|
207
|
-
return { outputPath, variables, designFile };
|
|
213
|
+
return { outputPath, variables, designFile, styleId };
|
|
208
214
|
}
|
|
209
215
|
|
|
210
216
|
/**
|
|
@@ -234,6 +240,19 @@ async function run(args) {
|
|
|
234
240
|
}
|
|
235
241
|
|
|
236
242
|
const [skill, name, ...rest] = args;
|
|
243
|
+
if (skill === 'yida-design' && name === 'application-style') {
|
|
244
|
+
const options = parseOptions(rest, path.join(process.cwd(), '.cache/samples/application-style'));
|
|
245
|
+
if (options.designFile || Object.keys(options.variables).length) {
|
|
246
|
+
throw new CliError(t('design_document.invalid', 'application-style', 'APPLICATION_STYLE_SAMPLE_INVALID'), { code: 'APPLICATION_STYLE_SAMPLE_INVALID' });
|
|
247
|
+
}
|
|
248
|
+
if (!options.styleId) {
|
|
249
|
+
throw new CliError(t('cli_argument.invalid', '--style-id'), { code: 'APPLICATION_STYLE_REQUIRED' });
|
|
250
|
+
}
|
|
251
|
+
const result = require('../app/application-style').exportApplicationStyle(options.styleId, options.outputPath);
|
|
252
|
+
console.log(JSON.stringify(result, null, 2));
|
|
253
|
+
return result;
|
|
254
|
+
}
|
|
255
|
+
if (rest.includes('--style-id')) {throw new CliError(t('design_document.invalid', '--style-id', 'APPLICATION_STYLE_SAMPLE_INVALID'), { code: 'APPLICATION_STYLE_SAMPLE_INVALID' });}
|
|
237
256
|
|
|
238
257
|
const { c, error: chalkError, success: chalkSuccess, hint: chalkHint } = require('./chalk');
|
|
239
258
|
|
|
@@ -275,6 +294,9 @@ async function run(args) {
|
|
|
275
294
|
throw new CliError('--design-file 仅用于 yida-design app-theme', { code: 'DESIGN_THEME_SAMPLE_INVALID' });
|
|
276
295
|
}
|
|
277
296
|
if (sampleKey === 'yida-design/app-theme') {
|
|
297
|
+
if (Object.keys(variables).length) {
|
|
298
|
+
throw new CliError(t('cli_argument.invalid', '--var (yida-design app-theme: --design-file)'), { code: 'SAMPLE_ARGUMENT_INVALID' });
|
|
299
|
+
}
|
|
278
300
|
const snapshotPath = `${outputPath}.tokens.md`;
|
|
279
301
|
if (designFile && path.resolve(snapshotPath) === path.resolve(designFile)) {
|
|
280
302
|
throw new CliError('输出路径不能覆盖模板或 design.md', { code: 'SAMPLE_OUTPUT_CONFLICT' });
|
package/lib/design/document.js
CHANGED
|
@@ -376,6 +376,7 @@ function validateDesignDocument(markdown, options = {}) {
|
|
|
376
376
|
if (!/^#[\da-f]{6}$/i.test(profile.themeColor) || profile.themeColor.toUpperCase() !== tokens['--color-brand1-6'].toUpperCase()) {
|
|
377
377
|
invalid('themeProfile.themeColor', 'PRIMARY_COLOR_MISMATCH');
|
|
378
378
|
}
|
|
379
|
+
if (!['light', 'dark'].includes(profile.contentTone)) {invalid('themeProfile.contentTone', 'LIGHT_OR_DARK_REQUIRED');}
|
|
379
380
|
if (!['light', 'dark'].includes(profile.navTheme)) {invalid('themeProfile.navTheme', 'LIGHT_OR_DARK_REQUIRED');}
|
|
380
381
|
if (!['app-custom-theme-file', 'current-app-theme'].includes(profile.themeDelivery)) {invalid('themeProfile.themeDelivery', 'INVALID_THEME_DELIVERY');}
|
|
381
382
|
if (typeof profile.themeFile !== 'string') {invalid('themeProfile.themeFile', 'STRING_REQUIRED');}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function confirmationPayload(outputs, revision) {
|
|
4
|
+
return {
|
|
5
|
+
question: '请确认当前搭建方案',
|
|
6
|
+
options: [{ label: '确认并开始搭建', value: 'confirm_build' }, { label: '继续调整', value: 'continue_editing' }],
|
|
7
|
+
submitLabel: '提交选择',
|
|
8
|
+
attachments: [{ name: '搭建方案.html', path: outputs.html }],
|
|
9
|
+
revision,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
module.exports = { confirmationPayload };
|
|
@@ -12,7 +12,7 @@ function usage() {
|
|
|
12
12
|
' openyida design-plan catalog [--json]',
|
|
13
13
|
' openyida design-plan init <requirement-brief.json> [--theme-id <id>] [--output-dir <dir>] [--json]',
|
|
14
14
|
' openyida design-plan preview <build-plan.json> --part-file <module.json> [--json]',
|
|
15
|
-
' openyida design-plan materialize <build-plan.json> [--from-preview | --business-file <json> --visual-file <json>] [--output-dir <dir>] [--check] [--json]',
|
|
15
|
+
' openyida design-plan materialize <build-plan.json> [--from-preview | --business-file <json> --visual-file <json>] [--output-dir <dir>] [--rebase-parts] [--check] [--json]',
|
|
16
16
|
' openyida design-plan patch <build-plan.json> --set <path=value> [--set <path=value> ...] [--materialize] [--output-dir <dir>] [--json]',
|
|
17
17
|
].join('\n');
|
|
18
18
|
}
|
|
@@ -50,6 +50,46 @@ function setValues(args) {
|
|
|
50
50
|
return values;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
const OPTION_SCHEMA = Object.freeze({
|
|
54
|
+
catalog: { flags: ['--json'], values: [] },
|
|
55
|
+
init: { flags: ['--json'], values: ['--theme-id', '--output-dir'] },
|
|
56
|
+
preview: { flags: ['--json'], values: ['--part-file'] },
|
|
57
|
+
materialize: { flags: ['--from-preview', '--rebase-parts', '--check', '--json'], values: ['--business-file', '--visual-file', '--output-dir'] },
|
|
58
|
+
patch: { flags: ['--materialize', '--json'], values: ['--set', '--output-dir'], inlineValues: ['--set'] },
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
function assertKnownOptions(subcommand, args) {
|
|
62
|
+
const schema = OPTION_SCHEMA[subcommand];
|
|
63
|
+
const flags = new Set(schema.flags);
|
|
64
|
+
const values = new Set(schema.values);
|
|
65
|
+
const inlineValues = new Set(schema.inlineValues || []);
|
|
66
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
67
|
+
const token = args[index];
|
|
68
|
+
const equalsAt = token.indexOf('=');
|
|
69
|
+
const option = equalsAt === -1 ? token : token.slice(0, equalsAt);
|
|
70
|
+
if (equalsAt !== -1 && inlineValues.has(option)) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (flags.has(token)) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (values.has(token)) {
|
|
77
|
+
if (!args[index + 1] || args[index + 1].startsWith('--')) {
|
|
78
|
+
throw new CliError(`${token} 缺少参数值`, {
|
|
79
|
+
code: 'DESIGN_PLAN_INVALID_ARGUMENT',
|
|
80
|
+
usage: usage(),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
index += 1;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
throw new CliError(`未知 ${subcommand} 参数:${token}`, {
|
|
87
|
+
code: 'DESIGN_PLAN_INVALID_ARGUMENT',
|
|
88
|
+
usage: usage(),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
53
93
|
async function run(args) {
|
|
54
94
|
const subcommand = args[0];
|
|
55
95
|
if (!subcommand || args.includes('--help') || args.includes('-h')) {
|
|
@@ -63,6 +103,7 @@ async function run(args) {
|
|
|
63
103
|
});
|
|
64
104
|
}
|
|
65
105
|
if (subcommand === 'catalog') {
|
|
106
|
+
assertKnownOptions(subcommand, args.slice(1));
|
|
66
107
|
console.log(JSON.stringify(catalog(), null, 2));
|
|
67
108
|
return;
|
|
68
109
|
}
|
|
@@ -74,13 +115,14 @@ async function run(args) {
|
|
|
74
115
|
});
|
|
75
116
|
}
|
|
76
117
|
const options = args.slice(2);
|
|
118
|
+
assertKnownOptions(subcommand, options);
|
|
77
119
|
const outputDir = optionValue(options, '--output-dir');
|
|
78
120
|
const result = subcommand === 'init'
|
|
79
121
|
? initialize(input, { outputDir, themeId: optionValue(options, '--theme-id') })
|
|
80
122
|
: subcommand === 'preview'
|
|
81
123
|
? preview(input, { partFile: optionValue(options, '--part-file') })
|
|
82
124
|
: subcommand === 'materialize'
|
|
83
|
-
? materialize(input, { outputDir, check: options.includes('--check'), fromPreview: options.includes('--from-preview'), businessFile: optionValue(options, '--business-file'), visualFile: optionValue(options, '--visual-file') })
|
|
125
|
+
? materialize(input, { outputDir, check: options.includes('--check'), rebaseParts: options.includes('--rebase-parts'), fromPreview: options.includes('--from-preview'), businessFile: optionValue(options, '--business-file'), visualFile: optionValue(options, '--visual-file') })
|
|
84
126
|
: patchPlan(input, setValues(options), { outputDir, materialize: options.includes('--materialize') });
|
|
85
127
|
|
|
86
128
|
if (options.includes('--json') || subcommand === 'preview') {
|
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
const { CliError } = require('../core/cli-error');
|
|
4
4
|
const { t } = require('../core/i18n');
|
|
5
|
+
const ENTRY_MODES = Object.freeze(['unified', 'service-management', 'frontend-only', 'backend-only']);
|
|
6
|
+
const ENTRY_MODE_SUMMARIES = Object.freeze({
|
|
7
|
+
unified: '不分前后台:使用同一套业务页面,按职责显示菜单、数据和操作。',
|
|
8
|
+
'service-management': '分前后台:办事的人使用前台,处理业务的人使用后台,两边共享业务数据。',
|
|
9
|
+
'frontend-only': '只有访问前台:本次提供办理、查询或展示页面;需要处理的业务由已有系统、人员入口或自动流程承接。',
|
|
10
|
+
'backend-only': '只有访问后台:工作人员录入、受理、处理或维护业务,办事入口在别处或本次不需要。',
|
|
11
|
+
});
|
|
5
12
|
const filled = value => typeof value === 'string' && value.trim().length > 0;
|
|
6
13
|
const object = value => value && typeof value === 'object' && !Array.isArray(value);
|
|
7
14
|
const assert = (condition, message, details) => {
|
|
@@ -12,7 +19,7 @@ const assert = (condition, message, details) => {
|
|
|
12
19
|
function buildEntryNavigation(plan, resources, pages) {
|
|
13
20
|
const recommendation = plan.execution?.entryRecommendation;
|
|
14
21
|
if (recommendation === undefined) {return null;}
|
|
15
|
-
assert(object(recommendation) &&
|
|
22
|
+
assert(object(recommendation) && ENTRY_MODES.includes(recommendation.mode), t('cli.design_plan_entry_mode_required'));
|
|
16
23
|
assert(Array.isArray(recommendation.entries) && recommendation.entries.length > 0, '入口方案缺少 entries');
|
|
17
24
|
const names = new Set(resources.map(resource => resource.name));
|
|
18
25
|
const entryKeys = new Set();
|
|
@@ -83,7 +90,8 @@ function buildEntryNavigation(plan, resources, pages) {
|
|
|
83
90
|
const roles = recommendation.entries.map(entry => entry.role);
|
|
84
91
|
assert(recommendation.mode !== 'service-management' || (roles.includes('service') && roles.includes('management')), '前后台方案必须同时包含访客端和业务管理端');
|
|
85
92
|
assert(recommendation.mode !== 'frontend-only' || roles.every(role => role === 'service'), '仅前台方案不能包含管理入口');
|
|
93
|
+
assert(recommendation.mode !== 'backend-only' || roles.every(role => role === 'management'), t('cli.design_plan_backend_only_roles'));
|
|
86
94
|
return { recommendation: JSON.parse(JSON.stringify(recommendation)), platformOrder: [...new Set(platformOrder)] };
|
|
87
95
|
}
|
|
88
96
|
|
|
89
|
-
module.exports = { buildEntryNavigation };
|
|
97
|
+
module.exports = { buildEntryNavigation, ENTRY_MODES, ENTRY_MODE_SUMMARIES };
|
package/lib/design-plan/init.js
CHANGED
|
@@ -9,7 +9,7 @@ const { planBase } = require('./parallel');
|
|
|
9
9
|
const { collectIssues } = require('./validate');
|
|
10
10
|
const { assertVisualFieldObjects } = require('./normalize');
|
|
11
11
|
|
|
12
|
-
const { PLAN_SKILL_ROOT: ROOT, loadThemeIndex, themeTemplatePath } = require('./themes');
|
|
12
|
+
const { PLAN_SKILL_ROOT: ROOT, loadThemeIndex, themeTemplatePath, themeNavTheme } = require('./themes');
|
|
13
13
|
|
|
14
14
|
function list(value) {
|
|
15
15
|
return Array.isArray(value) ? value : [];
|
|
@@ -57,7 +57,8 @@ function catalog() {
|
|
|
57
57
|
const { themes, pagePatterns } = loadCatalog();
|
|
58
58
|
return {
|
|
59
59
|
success: true,
|
|
60
|
-
themes: themes.
|
|
60
|
+
themes: themes.filter(theme => theme.mode !== 'creative').map(theme => ({ ...theme })),
|
|
61
|
+
creativeOption: themes.find(theme => theme.mode === 'creative'),
|
|
61
62
|
pagePatterns: pagePatterns.map(({ id, label, mustKeep }) => ({ id, label, mustKeep })),
|
|
62
63
|
};
|
|
63
64
|
}
|
|
@@ -138,13 +139,14 @@ function initialize(inputPath, options = {}) {
|
|
|
138
139
|
code: 'DESIGN_PLAN_THEME_UNKNOWN', details: { themes: themes.map(({ themeId, label }) => ({ themeId, label })), catalogCommand: 'openyida design-plan catalog --json' },
|
|
139
140
|
});
|
|
140
141
|
}
|
|
142
|
+
const navTheme = theme.mode === 'creative' ? brief.visualSelection?.navigationStyle?.tone || '' : themeNavTheme(theme);
|
|
141
143
|
const outputDir = path.resolve(options.outputDir || path.join('prd', project));
|
|
142
144
|
const output = path.join(outputDir, 'build-plan.json');
|
|
143
145
|
const guide = path.join(outputDir, 'authoring-context.md');
|
|
144
146
|
const business = path.join(outputDir, 'business.json');
|
|
145
147
|
const visual = path.join(outputDir, 'visual.json');
|
|
146
148
|
const materializeCommand = `openyida design-plan materialize ${quoteArgument(output)} --business-file ${quoteArgument(business)} --visual-file ${quoteArgument(visual)} --json`;
|
|
147
|
-
if ([output, guide, business, visual].some(file => fs.existsSync(file))) {
|
|
149
|
+
if ([output, guide, business, visual, path.join(outputDir, require('./rebase').BASE_FILE)].some(file => fs.existsSync(file))) {
|
|
148
150
|
throw new CliError('计划或编写上下文已存在,请继续补充现有文件', { code: 'DESIGN_PLAN_ALREADY_EXISTS' });
|
|
149
151
|
}
|
|
150
152
|
const scopedPages = list(brief.explicitScope?.pages);
|
|
@@ -211,9 +213,10 @@ function initialize(inputPath, options = {}) {
|
|
|
211
213
|
...(choice.tokens ? { tokens: choice.tokens } : {}),
|
|
212
214
|
...(choice.evidence ? { evidence: choice.evidence } : {}),
|
|
213
215
|
...(choice.constraints ? { constraints: choice.constraints } : {}),
|
|
216
|
+
...(choice.creativeDirection ? { creativeDirection: choice.creativeDirection } : {}),
|
|
214
217
|
forUser: { visualDirection: { ...(choice.visualDirection || { label: theme.label, description: theme.styleSummary }), source: visualSource },
|
|
215
218
|
colorStrategy: { primaryColor: '', primaryColorName: '', source: '', usage: '', ...normalizeColorStrategy(choice.colorStrategy) },
|
|
216
|
-
navigationStyle:
|
|
219
|
+
navigationStyle: { structure: '', source: '', selectionReason: '', ...(choice.navigationStyle || {}), tone: navTheme, toneSource: theme.mode === 'creative' ? 'project_defined' : 'theme_derived' },
|
|
217
220
|
pageApplications: pages.map(page => ({ pageId: page.pageId, firstScreenFocus: '', layout: '', responsive: '', primaryAction: '', acceptanceChecks: [],
|
|
218
221
|
visualMemoryApplications: [], ...list(choice.pageApplications).find(item => item?.pageId === page.pageId) })),
|
|
219
222
|
...(choice.assetStrategy ? { assetStrategy: choice.assetStrategy } : {}),
|
|
@@ -231,9 +234,11 @@ function initialize(inputPath, options = {}) {
|
|
|
231
234
|
`读取本上下文、编写契约和 business.json;按 authoring.pendingFields 补齐事实,保留 base 与已有需求。business facts 填写 overview、dataModels、businessFlows、pages 和可选 execution;视觉填写 visual.json。复核业务覆盖后设置片段 ready=true,再执行:${materializeCommand}。使用成功结果中的 HTML 路径展示“当前方案”,revision 仅放在内部确认字段,不写入用户可见标题、摘要或问题。视觉片段按每页实际任务补齐焦点、布局、主操作、响应式与验收;已完成的选择直接复用。`, '',
|
|
232
235
|
'## 本轮编写重点', '设计功能范围、数据与规则、页面组织、关键交互和业务验收。页面 blocks 按优先顺序填写 {name,purpose};CLI 派生默认内容优先级与内容层次,保留明确填写的独立设计。通用状态和验收检查由 CLI 补齐,interactionStates 与 acceptanceCriteria 填写项目差异。', '',
|
|
233
236
|
'首页按使用者的主要任务选择:集中办事可用门户式工作台(workbench),单项任务可直达原生业务页;只有已确认的指标分析或投屏监控任务才规划 dashboard/screen。工作台按需求组织待办、操作队列、业务列表和常用入口,辅助统计不改变页面主任务。不得从后台身份、系统名称或暗色风格自动增加驾驶舱。完整规则见 yida-requirement-analysis/references/experience-groups.md 的“首页按任务选择”。', '',
|
|
234
|
-
'
|
|
235
|
-
'入口方案沿用 execution.entryRecommendation
|
|
236
|
-
|
|
237
|
+
'无论是否分前后台,每个业务入口都要确定默认页面、菜单及分组顺序、打开后的首屏任务。menu 数组记录展示顺序,defaultMenuKey 记录默认任务;按角色需求决定,不按资源创建先后排列。平台导航通过排序命令落实,自定义导航通过页面菜单落实,frontend-only 也必须完成入口排序与首页验收。', '',
|
|
238
|
+
'入口方案沿用 execution.entryRecommendation:unified 表示不分前后台,service-management 表示分前后台,frontend-only 表示只有访问前台,backend-only 表示只有访问后台。向用户说明谁使用、看到什么、能做什么;只有前台且提交后需要处理时,在 reason 和业务流程中说明承接方式;逐入口补齐 role、menu 和 defaultMenuKey,前台关联独立页面 sceneKey。任何身份的入口含 local 菜单时,entry.sceneKey 必须关联承载页面,menu.resource 等于页面 name,viewKey 非空。管理端可直接落到原生业务视图,不强制创建首页。所有叶子菜单按资源、视图和操作记录 access 权限依赖,平台导航排序从管理菜单派生。详见 yida-app/references/entry-navigation.md。', '',
|
|
239
|
+
theme.mode === 'creative'
|
|
240
|
+
? '保留 visual.json 中 facts.visualStyle.forUser.visualDirection 和 navigationStyle 的对象结构;自由创意需明确填写 structure=top|side 和 tone=light|dark,并配套导航 Token。'
|
|
241
|
+
: `保留 visual.json 中 facts.visualStyle.forUser.visualDirection 和 navigationStyle 的对象结构,只补齐内部字段;前者包含 label/description,后者只需维护 structure=top|side。tone=${navTheme} 由已选主题模板派生,不要修改。`, '',
|
|
237
242
|
'## 页面模式', ...patterns.map(item => `- ${item.id}(${item.label}):${item.mustKeep.join(';')}`), '',
|
|
238
243
|
`## 已选风格:${theme.label}`, overview.trim(), '',
|
|
239
244
|
'平台变量清单是基础契约,不是主题能力上限。visualStyle.tokens 可新增项目命名空间的材质、布局、字体、动效和组件状态变量,并在设计正文说明消费位置;平台变量可引用同一主题中已声明且无循环的扩展变量。不要为一次性页面样式强制新增 token。', '',
|
|
@@ -257,11 +262,13 @@ function initialize(inputPath, options = {}) {
|
|
|
257
262
|
&& ['top', 'side'].includes(selectedVisual.navigationStyle.structure)
|
|
258
263
|
&& ['light', 'dark'].includes(selectedVisual.navigationStyle.tone)
|
|
259
264
|
&& ['label', 'description'].every(key => typeof selectedVisual.visualDirection[key] === 'string' && selectedVisual.visualDirection[key].trim())
|
|
260
|
-
&& !collectIssues(plan).some(issue => issue.path.startsWith('visualStyle.forUser.pageApplications[')
|
|
265
|
+
&& !collectIssues(plan).some(issue => issue.path.startsWith('visualStyle.forUser.pageApplications[')
|
|
266
|
+
|| issue.path.startsWith('visualStyle.creativeDirection.') || issue.path.startsWith('visualStyle.tokens.'));
|
|
261
267
|
const visualPart = `${JSON.stringify({ base, ready: visualReady, facts: { visualStyle: plan.visualStyle } }, null, 2)}\n`;
|
|
262
268
|
const authoring = authoringGuidance(plan, business, visual, businessReady, visualReady);
|
|
263
269
|
const formatContext = ['## 输入格式示例', '示例仅说明格式,按当前业务填写。', '```json', JSON.stringify(authoring.examples, null, 2), '```', '', authoring.completion, ''].join('\n');
|
|
264
|
-
|
|
270
|
+
const baseline = path.join(outputDir, require('./rebase').BASE_FILE);
|
|
271
|
+
writeFiles([[output, `${JSON.stringify(plan, null, 2)}\n`], [baseline, `${JSON.stringify({ schemaVersion: 1, base, plan }, null, 2)}\n`], [guide, context + formatContext], [business, businessPart], [visual, visualPart]]);
|
|
265
272
|
return { success: true, input, output, context: guide, contract: path.join(ROOT, 'references/build-plan-compact-schema.md'), draft: true,
|
|
266
273
|
materialize: { mode: 'complete_files_once', maxCalls: 1,
|
|
267
274
|
shell: process.platform === 'win32' ? 'powershell' : 'posix',
|