openyida 2026.9.20 → 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.
Files changed (162) hide show
  1. package/README.md +1 -1
  2. package/lib/app/application-style.js +3 -1
  3. package/lib/app/theme-from-design.js +38 -13
  4. package/lib/app/update-app.js +63 -13
  5. package/lib/core/command-manifest.js +32 -20
  6. package/lib/core/locales/en.js +17 -0
  7. package/lib/core/locales/zh.js +17 -0
  8. package/lib/core/sample.js +17 -14
  9. package/lib/design-plan/confirmation.js +13 -0
  10. package/lib/design-plan/design-plan.js +44 -2
  11. package/lib/design-plan/entry-navigation.js +10 -2
  12. package/lib/design-plan/init.js +11 -7
  13. package/lib/design-plan/materialize.js +62 -43
  14. package/lib/design-plan/normalize.js +13 -14
  15. package/lib/design-plan/parallel.js +62 -13
  16. package/lib/design-plan/patch.js +21 -7
  17. package/lib/design-plan/rebase.js +60 -0
  18. package/lib/design-plan/themes.js +16 -1
  19. package/lib/design-plan/validate.js +6 -1
  20. package/lib/design-plan/visual-policy.js +18 -4
  21. package/lib/samples/openyida-scaffold/canvas-form-drawer.canvas.jsx +3 -3
  22. package/lib/samples/openyida-scaffold/canvas-nav/mixed.jsx +6 -4
  23. package/lib/samples/openyida-scaffold/canvas-nav/shared.jsx +5 -5
  24. package/lib/samples/openyida-scaffold/canvas-nav/side.jsx +1 -2
  25. package/lib/samples/openyida-scaffold/canvas-nav/sidebar.jsx +1 -1
  26. package/lib/samples/openyida-scaffold/canvas-nav/top.jsx +5 -4
  27. package/package.json +1 -1
  28. package/yida-skills/SKILL.md +2 -2
  29. package/yida-skills/references/yida-api.md +4 -0
  30. package/yida-skills/skills/yida-app/SKILL.md +12 -4
  31. package/yida-skills/skills/yida-app/references/entry-navigation.md +11 -9
  32. package/yida-skills/skills/yida-app/workflow/plan/step-4-deliver.md +1 -1
  33. package/yida-skills/skills/yida-app/workflow/plan/workflow.md +11 -4
  34. package/yida-skills/skills/yida-app/workflow/step-2-design.md +3 -3
  35. package/yida-skills/skills/yida-app/workflow/step-3-create-or-reuse-app.md +2 -2
  36. package/yida-skills/skills/yida-app/workflow/step-8-publish-navigation.md +3 -3
  37. package/yida-skills/skills/yida-app/workflow/step-9-output-finish.md +3 -2
  38. package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +2 -2
  39. package/yida-skills/skills/yida-canvas-custom-page/references/canvas-style-implementation-guide.md +1 -1
  40. package/yida-skills/skills/yida-canvas-custom-page/references/canvas-theme-provider.md +1 -1
  41. package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +140 -1
  42. package/yida-skills/skills/yida-canvas-custom-page/references/navigation-and-entry-guide.md +1 -1
  43. package/yida-skills/skills/yida-canvas-custom-page/scripts/canvas-theme-provider.template.jsx +1 -1
  44. package/yida-skills/skills/yida-canvas-data-binding/SKILL.md +7 -0
  45. package/yida-skills/skills/yida-create-form-page/SKILL.md +1 -1
  46. package/yida-skills/skills/yida-design/SKILL.md +5 -3
  47. package/yida-skills/skills/yida-design/references/application-style-library.md +22 -7
  48. package/yida-skills/skills/yida-design/references/application-theme-consistency.md +45 -5
  49. package/yida-skills/skills/yida-design/references/ask-human-interaction-contract.md +1 -1
  50. package/yida-skills/skills/yida-design/references/native-form-styles.md +1 -1
  51. package/yida-skills/skills/yida-design/references/navigation-decision.md +6 -4
  52. package/yida-skills/skills/yida-design/references/theme/app-custom-theme-template.css +62 -0
  53. package/yida-skills/skills/yida-design/references/theme-selection.md +10 -9
  54. package/yida-skills/skills/yida-design/references/visual-decision-engine.md +1 -1
  55. package/yida-skills/skills/yida-design/scripts/validate_design_themes.py +35 -9
  56. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/SKILL.md +13 -3
  57. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-compact-schema.md +4 -2
  58. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/build-plan-schema.md +4 -2
  59. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/visual-design.md +3 -1
  60. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/references/visual-theme-selection.md +15 -17
  61. package/yida-skills/skills/yida-design/sub_skill/yida-design-plan/scripts/render_build_plan.py +2 -0
  62. package/yida-skills/skills/yida-design/templates/design-themes/README.md +15 -10
  63. package/yida-skills/skills/yida-design/templates/design-themes/app-amber/app_theme.css +224 -83
  64. package/yida-skills/skills/yida-design/templates/design-themes/app-amber/design.md +69 -14
  65. package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/app_theme.css +224 -83
  66. package/yida-skills/skills/yida-design/templates/design-themes/app-editorial/design.md +69 -14
  67. package/yida-skills/skills/yida-design/templates/design-themes/app-executive/app_theme.css +244 -103
  68. package/yida-skills/skills/yida-design/templates/design-themes/app-executive/design.md +68 -13
  69. package/yida-skills/skills/yida-design/templates/design-themes/app-finance/app_theme.css +223 -82
  70. package/yida-skills/skills/yida-design/templates/design-themes/app-finance/design.md +68 -13
  71. package/yida-skills/skills/yida-design/templates/design-themes/app-glass/app_theme.css +225 -84
  72. package/yida-skills/skills/yida-design/templates/design-themes/app-glass/design.md +69 -14
  73. package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/app_theme.css +244 -103
  74. package/yida-skills/skills/yida-design/templates/design-themes/app-graphite/design.md +68 -13
  75. package/yida-skills/skills/yida-design/templates/design-themes/app-line/app_theme.css +224 -83
  76. package/yida-skills/skills/yida-design/templates/design-themes/app-line/design.md +69 -14
  77. package/yida-skills/skills/yida-design/templates/design-themes/app-neon/app_theme.css +244 -103
  78. package/yida-skills/skills/yida-design/templates/design-themes/app-neon/design.md +68 -13
  79. package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/app_theme.css +236 -89
  80. package/yida-skills/skills/yida-design/templates/design-themes/app-nordic/design.md +74 -14
  81. package/yida-skills/skills/yida-design/templates/design-themes/app-paper/app_theme.css +224 -83
  82. package/yida-skills/skills/yida-design/templates/design-themes/app-paper/design.md +68 -13
  83. package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/app_theme.css +223 -82
  84. package/yida-skills/skills/yida-design/templates/design-themes/app-platinum/design.md +68 -13
  85. package/yida-skills/skills/yida-design/templates/design-themes/app-plum/app_theme.css +224 -83
  86. package/yida-skills/skills/yida-design/templates/design-themes/app-plum/design.md +68 -13
  87. package/yida-skills/skills/yida-design/templates/design-themes/app-pop/app_theme.css +240 -89
  88. package/yida-skills/skills/yida-design/templates/design-themes/app-pop/design.md +76 -14
  89. package/yida-skills/skills/yida-design/templates/design-themes/app-sage/app_theme.css +224 -83
  90. package/yida-skills/skills/yida-design/templates/design-themes/app-sage/design.md +69 -14
  91. package/yida-skills/skills/yida-design/templates/design-themes/app-teal/app_theme.css +224 -83
  92. package/yida-skills/skills/yida-design/templates/design-themes/app-teal/design.md +68 -13
  93. package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/app_theme.css +254 -107
  94. package/yida-skills/skills/yida-design/templates/design-themes/app-terminal/design.md +74 -14
  95. package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/app_theme.css +233 -88
  96. package/yida-skills/skills/yida-design/templates/design-themes/app-ticket/design.md +73 -14
  97. package/yida-skills/skills/yida-design/templates/design-themes/app-wire/app_theme.css +224 -83
  98. package/yida-skills/skills/yida-design/templates/design-themes/app-wire/design.md +69 -14
  99. package/yida-skills/skills/yida-design/templates/design-themes/basic-tokens.json +2 -1
  100. package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/app_theme.css +690 -0
  101. package/yida-skills/skills/yida-design/templates/design-themes/{dark-inset-hairline.md → dark-inset-hairline/design.md} +103 -58
  102. package/yida-skills/skills/yida-design/templates/design-themes/dark-inset-hairline/form-layout.json +13 -0
  103. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/app_theme.css +691 -0
  104. package/yida-skills/skills/yida-design/templates/design-themes/{dark-rail-fine-lines.md → dark-rail-fine-lines/design.md} +102 -50
  105. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-fine-lines/form-layout.json +13 -0
  106. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/app_theme.css +696 -0
  107. package/yida-skills/skills/yida-design/templates/design-themes/{dark-rail-signal-panels.md → dark-rail-signal-panels/design.md} +62 -12
  108. package/yida-skills/skills/yida-design/templates/design-themes/dark-rail-signal-panels/form-layout.json +13 -0
  109. package/yida-skills/skills/yida-design/templates/design-themes/free-creative/app_theme.css +278 -115
  110. package/yida-skills/skills/yida-design/templates/design-themes/free-creative/design.md +57 -10
  111. package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/app_theme.css +692 -0
  112. package/yida-skills/skills/yida-design/templates/design-themes/{graphite-bevel-grid.md → graphite-bevel-grid/design.md} +60 -10
  113. package/yida-skills/skills/yida-design/templates/design-themes/graphite-bevel-grid/form-layout.json +13 -0
  114. package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/app_theme.css +691 -0
  115. package/yida-skills/skills/yida-design/templates/design-themes/{hairline-shared-bands.md → hairline-shared-bands/design.md} +62 -12
  116. package/yida-skills/skills/yida-design/templates/design-themes/hairline-shared-bands/form-layout.json +13 -0
  117. package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/app_theme.css +691 -0
  118. package/yida-skills/skills/yida-design/templates/design-themes/{hairline-soft-blocks.md → hairline-soft-blocks/design.md} +57 -9
  119. package/yida-skills/skills/yida-design/templates/design-themes/hairline-soft-blocks/form-layout.json +13 -0
  120. package/yida-skills/skills/yida-design/templates/design-themes/index.json +141 -48
  121. package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/app_theme.css +701 -0
  122. package/yida-skills/skills/yida-design/templates/design-themes/{ink-glow-soft-panels.md → ink-glow-soft-panels/design.md} +58 -8
  123. package/yida-skills/skills/yida-design/templates/design-themes/ink-glow-soft-panels/form-layout.json +13 -0
  124. package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/app_theme.css +691 -0
  125. package/yida-skills/skills/yida-design/templates/design-themes/{inset-frame-pixel-rhythm.md → inset-frame-pixel-rhythm/design.md} +59 -9
  126. package/yida-skills/skills/yida-design/templates/design-themes/inset-frame-pixel-rhythm/form-layout.json +13 -0
  127. package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/app_theme.css +698 -0
  128. package/yida-skills/skills/yida-design/templates/design-themes/{outlined-texture-duotone.md → outlined-texture-duotone/design.md} +62 -12
  129. package/yida-skills/skills/yida-design/templates/design-themes/outlined-texture-duotone/form-layout.json +13 -0
  130. package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/app_theme.css +691 -0
  131. package/yida-skills/skills/yida-design/templates/design-themes/{soft-inset-surfaces.md → soft-inset-surfaces/design.md} +59 -11
  132. package/yida-skills/skills/yida-design/templates/design-themes/soft-inset-surfaces/form-layout.json +13 -0
  133. package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/app_theme.css +690 -0
  134. package/yida-skills/skills/yida-design/templates/design-themes/{soft-outline-rhythm.md → soft-outline-rhythm/design.md} +60 -26
  135. package/yida-skills/skills/yida-design/templates/design-themes/soft-outline-rhythm/form-layout.json +13 -0
  136. package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/app_theme.css +698 -0
  137. package/yida-skills/skills/yida-design/templates/design-themes/{soft-rail-bold-band.md → soft-rail-bold-band/design.md} +99 -49
  138. package/yida-skills/skills/yida-design/templates/design-themes/soft-rail-bold-band/form-layout.json +13 -0
  139. package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/app_theme.css +692 -0
  140. package/yida-skills/skills/yida-design/templates/design-themes/{soft-spectral-panels.md → soft-spectral-panels/design.md} +63 -13
  141. package/yida-skills/skills/yida-design/templates/design-themes/soft-spectral-panels/form-layout.json +13 -0
  142. package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/app_theme.css +711 -0
  143. package/yida-skills/skills/yida-design/templates/design-themes/{warm-canvas-contrast-panels.md → warm-canvas-contrast-panels/design.md} +60 -10
  144. package/yida-skills/skills/yida-design/templates/design-themes/warm-canvas-contrast-panels/form-layout.json +13 -0
  145. package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/app_theme.css +692 -0
  146. package/yida-skills/skills/yida-design/templates/design-themes/{warm-rail-muted-panels.md → warm-rail-muted-panels/design.md} +98 -50
  147. package/yida-skills/skills/yida-design/templates/design-themes/warm-rail-muted-panels/form-layout.json +13 -0
  148. package/yida-skills/skills/yida-design/templates/navigation-styles.json +769 -0
  149. package/yida-skills/skills/yida-design/workflow/output-design.md +5 -5
  150. package/yida-skills/skills/yida-design/workflow/step-2-theme-system.md +5 -3
  151. package/yida-skills/skills/yida-design/workflow/step-6-handoff.md +1 -1
  152. package/yida-skills/skills/yida-form-permission/SKILL.md +6 -0
  153. package/yida-skills/skills/yida-nav-shell/SKILL.md +1 -1
  154. package/yida-skills/skills/yida-nav-shell/references/nav-shell-patterns.md +6 -0
  155. package/yida-skills/skills/yida-page-config/SKILL.md +9 -0
  156. package/yida-skills/skills/yida-prd/SKILL.md +1 -0
  157. package/yida-skills/skills/yida-prd/workflow/output-prd.md +2 -2
  158. package/yida-skills/skills/yida-prd/workflow/step-2-information-architecture.md +1 -1
  159. package/yida-skills/skills/yida-requirement-analysis/references/experience-groups.md +45 -9
  160. package/yida-skills/skills/yida-requirement-analysis/references/handoff.md +5 -5
  161. package/yida-skills/skills/yida-requirement-analysis/workflow/prepare-brief.md +17 -4
  162. package/yida-skills/skills-index.json +2 -2
package/README.md CHANGED
@@ -399,7 +399,7 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
399
399
  | `openyida design-plan catalog [--json]` | List available planning themes and page patterns |
400
400
  | `openyida design-plan init <requirement-brief.json> [--theme-id <id>] [--output-dir <dir>] [--json]` | Initialize a plan draft from confirmed requirements |
401
401
  | `openyida design-plan preview <build-plan.json> --part-file <module.json> [--json]` | Update plan drafts by module |
402
- | `openyida design-plan materialize <build-plan.json> [--from-preview \| --business-file <json> --visual-file <json>] [--output-dir <dir>] [--check] [--json]` | Generate or update plan documents and theme with consistency checks |
402
+ | `openyida design-plan materialize <build-plan.json> [--from-preview \| --business-file <json> --visual-file <json>] [--output-dir <dir>] [--rebase-parts] [--check] [--json]` | Generate or update plan documents and theme with consistency checks |
403
403
  | `openyida design-plan patch <build-plan.json> --set <path=value> [--set <path=value> ...] [--materialize] [--output-dir <dir>] [--json]` | Patch plan fields and optionally sync documents and theme |
404
404
  | `openyida update-app <appType> [--name "..."] [--desc "..."] [--icon <name>] [--icon-color <color>] [--colour <key>] [--theme-color <color>] [--theme-file <css>] [--nav-theme light\|dark\|white\|gray] [--logo-source appIcon\|customImage] [--layout side\|top\|l_shape] [--hide-app-nav\|--show-app-nav]` | Update app info |
405
405
  | `openyida app-online <appType> [--to-ding-app-center] [--show-app-center]` | Enable a Yida app |
@@ -13,6 +13,8 @@ const CREATIVE_TOKENS = [
13
13
  '--pod-page-footer-bg-color', '--pod-sticky-footer-box-shadow',
14
14
  '--oyd-content-width', '--oyd-content-padding', '--oyd-field-gap',
15
15
  '--oyd-heading-font', '--oyd-heading-size', '--oyd-rule-style',
16
+ '--pod-shell-theme-bg-color', '--pod-nav-item-text-color', '--pod-nav-item-text-hover-color',
17
+ '--pod-nav-item-text-selected-color', '--pod-nav-menu-bg-hover-color', '--pod-nav-menu-bg-selected-color',
16
18
  ];
17
19
 
18
20
  function validateCreativeDirection(direction, tokens) {
@@ -46,7 +48,7 @@ function applyApplicationStyle(css, metadata, tokens) {
46
48
  }
47
49
 
48
50
  function exportApplicationStyle(id, outputDirectory) {
49
- const theme = loadThemeIndex().themes.find(item => item.themeId === id && item.collection === 'application-styles');
51
+ const theme = loadThemeIndex().themes.find(item => item.themeId === id);
50
52
  if (!theme) {throw new CliError(t('design_document.invalid', id || '--style-id', 'APPLICATION_STYLE_UNKNOWN'), { code: 'APPLICATION_STYLE_UNKNOWN' });}
51
53
  const directory = path.resolve(outputDirectory);
52
54
  const assets = [['design.md', theme.templatePath], ['app_theme.css', theme.cssTemplatePath], ['form-layout.json', theme.formLayoutPath]];
@@ -5,7 +5,7 @@ const path = require('path');
5
5
  const { CliError } = require('../core/cli-error');
6
6
  const { REQUIRED_BRAND_SCALE_TOKENS, validateThemeCssContent, extractThemeColor } = require('./custom-theme');
7
7
  const { parseDesignDocument, extractDesignTokens } = require('../design/document');
8
- const NAVIGATION_TOKENS = [
8
+ const NAVIGATION_COLOR_TOKENS = [
9
9
  '--pod-shell-theme-bg-color', '--pod-nav-item-text-color', '--pod-nav-item-text-hover-color',
10
10
  '--pod-nav-item-text-selected-color', '--pod-nav-menu-bg-hover-color', '--pod-nav-menu-bg-selected-color',
11
11
  ];
@@ -48,7 +48,7 @@ function resolveDesignTokens(metadata) {
48
48
  }
49
49
 
50
50
  function navigationTone(metadata, tokens) {
51
- if (!NAVIGATION_TOKENS.every(name => tokens[name])) {return null;}
51
+ if (!NAVIGATION_COLOR_TOKENS.every(name => tokens[name])) {return null;}
52
52
  const tone = metadata.themeProfile?.navTheme;
53
53
  if (['light', 'dark'].includes(tone)) {return tone;}
54
54
  if (tone !== undefined) {throw new CliError('themeProfile.navTheme 必须是 light 或 dark', { code: 'DESIGN_THEME_NAVIGATION_INVALID' });}
@@ -91,7 +91,9 @@ function applyNavigationTokens(css, tokens, changed, tone, previousTone) {
91
91
  const source = fs.readFileSync(path.resolve(__dirname,
92
92
  '../../yida-skills/skills/yida-design/references/theme/app-custom-theme-template.css'), 'utf8');
93
93
  const defaults = Object.assign({}, ...[...source.matchAll(/^:root\s*\{([^}]+)\}/gm)].map(match => declarationValues(match[1])));
94
- const navigationChanged = Object.fromEntries(NAVIGATION_TOKENS.filter(name => name in changed).map(name => [name, tokens[name]]));
94
+ const isNavigation = name => /^(--pod-nav-|--pod-shell-|--pod-page-header-)/.test(name);
95
+ const navigationNames = Object.keys(tokens).filter(isNavigation);
96
+ const navigationChanged = Object.fromEntries(navigationNames.filter(name => name in changed).map(name => [name, tokens[name]]));
95
97
  let output = css.replace(/(^:root\s*\{)([^}]+)(\})/gm,
96
98
  (block, start, body, close) => start + replaceDeclarations(body, navigationChanged) + close);
97
99
  for (const mode of ['light', 'dark']) {
@@ -102,19 +104,23 @@ function applyNavigationTokens(css, tokens, changed, tone, previousTone) {
102
104
  // A first application or a mode change establishes both palettes. Delta
103
105
  // updates otherwise leave unrelated, manually customized declarations alone.
104
106
  const resetMode = !previousTone || previousTone !== tone;
105
- const names = resetMode ? NAVIGATION_TOKENS : (mode === tone ? Object.keys(navigationChanged) : []);
106
- const values = Object.fromEntries(names.map(name => [name, mode === tone ? tokens[name] : modeDefaults[name]]));
107
+ // The selected marker is a mode-independent shape, not a navigation palette.
108
+ const names = (resetMode ? navigationNames : (mode === tone ? Object.keys(navigationChanged) : []))
109
+ .filter(name => name !== '--pod-nav-menu-item-selected-shadow');
110
+ const values = Object.fromEntries(names.map(name => [name, mode === tone ? tokens[name] : modeDefaults[name]])
111
+ .filter(([, value]) => value !== undefined));
107
112
  if (!Object.keys(values).length) {continue;}
113
+ const isForeground = name => name.startsWith('--pod-nav-') || name === '--pod-page-header-text-color';
114
+ const background = Object.fromEntries(Object.entries(values).filter(([name]) => !isForeground(name)));
108
115
  const shell = values['--pod-shell-theme-bg-color'];
109
- if (shell) {
110
- const background = {
111
- '--pod-shell-theme-bg-color': shell,
112
- '--pod-page-header-bg-color': mode === tone ? shell : modeDefaults['--pod-page-header-bg-color'],
113
- };
116
+ if (shell && !tokens['--pod-page-header-bg-color']) {
117
+ background['--pod-page-header-bg-color'] = mode === tone ? shell : modeDefaults['--pod-page-header-bg-color'];
118
+ }
119
+ if (Object.keys(background).length) {
114
120
  output = output.replace(new RegExp(`(\\.pod-premium\\.nav-${mode}\\s*\\{)([^}]*)(\\})`, 'g'),
115
121
  (block, start, body, close) => start + replaceDeclarations(body, background, true) + close);
116
122
  }
117
- const foregrounds = Object.fromEntries(Object.entries(values).filter(([name]) => name !== '--pod-shell-theme-bg-color'));
123
+ const foregrounds = Object.fromEntries(Object.entries(values).filter(([name]) => isForeground(name)));
118
124
  output = output.replace(new RegExp(`(\\.pod-premium\\.is-${mode}\\s*\\{)([^}]*)(\\})`, 'g'),
119
125
  (block, start, body, close) => start + replaceDeclarations(body, foregrounds, true) + close);
120
126
  }
@@ -122,11 +128,30 @@ function applyNavigationTokens(css, tokens, changed, tone, previousTone) {
122
128
  }
123
129
 
124
130
  function applyDesignTokens(template, markdown, previousMarkdown) {
125
- // Reject damaged templates or existing stylesheets before the scope rewrite.
126
- validateThemeCssContent(template);
127
131
  const metadata = designMetadata(markdown);
128
132
  const previousMetadata = previousMarkdown === markdown ? metadata : (previousMarkdown ? designMetadata(previousMarkdown) : null);
129
133
  const tokens = resolveDesignTokens(metadata);
134
+ // Bundled CSS is an authoring template. Fill only unresolved declarations from
135
+ // the completed design before validating and rewriting CSS scopes.
136
+ template = template.replace(/^([ \t]*)(--[\w-]+)(\s*:\s*)([^;\n]+);/gm,
137
+ (line, indent, name, separator, value) => {
138
+ if (!/\{\{PRIMARY_COLOR\}\}|<生成实际色值:/.test(value)) {return line;}
139
+ if (!tokens[name] || /\{\{|<生成实际色值:/.test(tokens[name])) {
140
+ throw new CliError(`design.md 缺少品牌 token:${name}`, { code: 'DESIGN_THEME_TOKENS_REQUIRED' });
141
+ }
142
+ return `${indent}${name}${separator}${tokens[name]};`;
143
+ });
144
+ // Reject damaged templates or existing stylesheets before the scope rewrite.
145
+ validateThemeCssContent(template);
146
+ // Older generated files have the selected-shadow rule only. Bring in the
147
+ // shared consumer once when a design opts into menu borders, retaining all
148
+ // existing project rules and declarations during incremental updates.
149
+ if (tokens['--pod-nav-menu-item-border'] && !template.includes('border: var(--pod-nav-menu-item-border,')) {
150
+ const source = fs.readFileSync(path.resolve(__dirname,
151
+ '../../yida-skills/skills/yida-design/references/theme/app-custom-theme-template.css'), 'utf8');
152
+ const shapeRules = source.match(/\/\* openyida-navigation-shape:start \*\/[\s\S]*?\/\* openyida-navigation-shape:end \*\//)[0];
153
+ template += `\n${shapeRules}\n`;
154
+ }
130
155
  const previous = previousMetadata === metadata ? tokens : (previousMetadata ? resolveDesignTokens(previousMetadata) : null);
131
156
  const tone = navigationTone(metadata, tokens);
132
157
  const previousTone = previous ? navigationTone(previousMetadata, previous) : null;
@@ -92,11 +92,18 @@ function parseArgs(args) {
92
92
  return result;
93
93
  }
94
94
  result.appType = args[0];
95
+ if (args.includes('--hide-app-nav') && args.includes('--show-app-nav')) {
96
+ throwCommandError(t('cli_argument.invalid', '--hide-app-nav / --show-app-nav'), { code: 'CLI_INVALID_ARGUMENTS' });
97
+ }
95
98
 
96
99
  // 解析选项参数
97
100
  for (let i = 1; i < args.length; i++) {
98
101
  const arg = args[i];
99
102
  const nextArg = args[i + 1];
103
+ if (!['--hide-app-nav', '--show-app-nav'].includes(arg) &&
104
+ (!nextArg || nextArg.startsWith('--') || ['-n', '-d'].includes(nextArg))) {
105
+ throwCommandError(t('cli_argument.invalid', arg), { code: 'CLI_INVALID_ARGUMENTS' });
106
+ }
100
107
 
101
108
  switch (arg) {
102
109
  case '--name':
@@ -174,6 +181,8 @@ function parseArgs(args) {
174
181
  case '--show-app-nav':
175
182
  result.hideAppNav = 'n';
176
183
  break;
184
+ default:
185
+ throwCommandError(t('cli_argument.invalid', arg), { code: 'CLI_INVALID_ARGUMENTS' });
177
186
  }
178
187
  }
179
188
 
@@ -308,6 +317,7 @@ function buildUpdateAppPostData(params, currentApp = {}, authRef) {
308
317
  const sentryMode = pickAppField(currentApp, 'sentryMode', 'SENTRY_MODE');
309
318
  const currentNavType = currentApp.navType || (currentApp.config && currentApp.config.NAVTYPE);
310
319
  const currentLayoutDirection = currentApp.layoutDirection || (currentApp.config && currentApp.config.LAY_OUT_DIRECTION);
320
+ const currentNavTheme = currentApp.navTheme || (currentApp.config && currentApp.config.NAV_THEME);
311
321
  if (params.colour === 'custom' && !params.themeColor && !currentThemeColor) {
312
322
  throw new Error(t('update_app.custom_theme_color_required'));
313
323
  }
@@ -330,7 +340,6 @@ function buildUpdateAppPostData(params, currentApp = {}, authRef) {
330
340
  // updateApp 的报错文案叫 appMode,但实际接受的请求字段是 mode。
331
341
  mode: currentApp.mode || (currentApp.config && currentApp.config.APPMODE) || 'normal',
332
342
  type: currentApp.type || (currentApp.config && currentApp.config.APPTYPE) || 'single',
333
- navTheme: params.navTheme || currentApp.navTheme || (currentApp.config && currentApp.config.NAV_THEME) || 'light',
334
343
  navLayout: currentApp.navLayout || (currentApp.config && currentApp.config.NAVLAYOUT) || 'auto',
335
344
  layoutDirection: params.layoutDirection
336
345
  ? normalizeLayoutDirection(params.layoutDirection)
@@ -361,6 +370,8 @@ function buildUpdateAppPostData(params, currentApp = {}, authRef) {
361
370
 
362
371
  // ThemeNavSetting 保存现有 navType;新布局由 layoutDirection 控制,不反写或补造旧字段。
363
372
  if (currentNavType) {postDataObj.navType = currentNavType;}
373
+ const navTheme = params.navTheme || currentNavTheme;
374
+ if (navTheme) {postDataObj.navTheme = navTheme;}
364
375
  if (addWaterMark !== undefined && addWaterMark !== null) {
365
376
  postDataObj.addWaterMark = addWaterMark;
366
377
  }
@@ -442,7 +453,26 @@ function themeSettingsMatch(expected, actual) {
442
453
  ['cssUrl', 'cssFileName'].every((key) => (expectedStyle[key] || '') === (actualStyle[key] || ''));
443
454
  }
444
455
 
445
- /** updateApp 整包保存;与基础设置页一致,读取最新配置后合并,并核验主题资源。 */
456
+ function getRequestedNavigationSettings(params, payload) {
457
+ return Object.fromEntries(['navTheme', 'layoutDirection', 'hideAppNav', 'logoSource']
458
+ .filter((name) => params[name] !== undefined && params[name] !== null && params[name] !== '')
459
+ .map((name) => [name, payload[name]]));
460
+ }
461
+
462
+ function getNavigationSettings(app, fields) {
463
+ const configKeys = { navTheme: 'NAV_THEME', layoutDirection: 'LAY_OUT_DIRECTION', hideAppNav: 'HIDE_APP_NAV', logoSource: 'LOGO_SOURCE' };
464
+ return Object.fromEntries(fields.map((name) => {
465
+ let value = pickAppField(app, name, configKeys[name]);
466
+ if (name === 'layoutDirection') {
467
+ const navType = pickAppField(app, 'navType', 'NAVTYPE');
468
+ // A missing response field is not evidence that the requested default was saved.
469
+ value = value || navType ? normalizeStoredLayoutDirection(value, navType) : null;
470
+ }
471
+ return [name, value === undefined ? null : value];
472
+ }));
473
+ }
474
+
475
+ /** updateApp 整包保存;读取最新配置后合并,并核验主题资源和本次请求的导航设置。 */
446
476
  async function saveAppSettings(params, authRef) {
447
477
  const currentApp = await fetchCurrentApp(params.appType, authRef);
448
478
  const payload = buildUpdateAppPostData(params, currentApp, authRef);
@@ -454,29 +484,46 @@ async function saveAppSettings(params, authRef) {
454
484
  if (!response || !response.success) { return response; }
455
485
 
456
486
  const expected = getThemeSettings(payload);
457
- if (!params.colour && !params.themeColor && !params.customThemeStyle && !expected.themeColor && !expected.customThemeStyle) {
458
- return response;
459
- }
487
+ const verifyTheme = !!(params.colour || params.themeColor || params.customThemeStyle || expected.themeColor || expected.customThemeStyle);
488
+ const expectedNavigation = getRequestedNavigationSettings(params, payload);
489
+ const navigationFields = Object.keys(expectedNavigation);
490
+ if (!verifyTheme && !navigationFields.length) {return response;}
460
491
  let actual;
492
+ let actualNavigation;
461
493
  let readbackError;
494
+ let themeVerified = !verifyTheme;
495
+ let navigationVerified = !navigationFields.length;
462
496
  // 只重试查询,避免重复上传资源或用旧快照再次覆盖设置。
463
497
  for (let attempt = 0; attempt < 3; attempt++) {
464
498
  if (attempt) { await new Promise((resolve) => setTimeout(resolve, attempt * 250)); }
465
499
  try {
466
- actual = getThemeSettings(await fetchCurrentApp(params.appType, authRef));
500
+ const app = await fetchCurrentApp(params.appType, authRef);
501
+ actual = getThemeSettings(app);
502
+ actualNavigation = getNavigationSettings(app, navigationFields);
467
503
  readbackError = undefined;
468
- if (themeSettingsMatch(expected, actual)) {
469
- return { ...response, themeVerification: { verified: true, ...actual } };
504
+ themeVerified = !verifyTheme || themeSettingsMatch(expected, actual);
505
+ navigationVerified = navigationFields.every((name) => expectedNavigation[name] === actualNavigation[name]);
506
+ if (themeVerified && navigationVerified) {
507
+ return { ...response,
508
+ ...(verifyTheme ? { themeVerification: { verified: true, ...actual } } : {}),
509
+ ...(navigationFields.length ? { navigationVerification: { verified: true, ...actualNavigation } } : {}),
510
+ };
470
511
  }
471
512
  } catch (error) {
472
513
  readbackError = error.message;
514
+ themeVerified = !verifyTheme;
515
+ navigationVerified = !navigationFields.length;
473
516
  }
474
517
  }
475
518
  return {
476
519
  success: false,
477
- errorCode: 'APP_THEME_NOT_PERSISTED',
478
- errorMsg: t('update_app.theme_not_persisted'),
479
- themeVerification: { verified: false, expected, actual, readbackError },
520
+ errorCode: themeVerified ? 'APP_NAVIGATION_NOT_PERSISTED' : 'APP_THEME_NOT_PERSISTED',
521
+ errorMsg: t(themeVerified ? 'update_app.navigation_not_persisted' : 'update_app.theme_not_persisted'),
522
+ ...(verifyTheme ? { themeVerification: themeVerified
523
+ ? { verified: true, ...actual } : { verified: false, expected, actual, readbackError } } : {}),
524
+ ...(navigationFields.length ? { navigationVerification: navigationVerified
525
+ ? { verified: true, ...actualNavigation }
526
+ : { verified: false, expected: expectedNavigation, actual: actualNavigation, readbackError } } : {}),
480
527
  };
481
528
  }
482
529
 
@@ -594,6 +641,7 @@ async function run(args) {
594
641
  success: true,
595
642
  appType: params.appType,
596
643
  themeVerification: response.themeVerification,
644
+ navigationVerification: response.navigationVerification,
597
645
  updatedFields: {
598
646
  name: params.name || undefined,
599
647
  desc: params.desc || undefined,
@@ -611,8 +659,10 @@ async function run(args) {
611
659
  const errorMsg = response ? response.errorMsg || t('common.unknown_error') : t('common.request_failed');
612
660
  chalkResult(false, t('update_app.failed', errorMsg));
613
661
  console.log(JSON.stringify({ success: false, appType: params.appType, error: errorMsg,
614
- errorCode: response && response.errorCode, themeVerification: response && response.themeVerification }));
615
- throwCommandError(errorMsg, { code: response && response.errorCode, details: response && response.themeVerification });
662
+ errorCode: response && response.errorCode, themeVerification: response && response.themeVerification,
663
+ navigationVerification: response && response.navigationVerification }));
664
+ throwCommandError(errorMsg, { code: response && response.errorCode,
665
+ details: response && (response.errorCode === 'APP_NAVIGATION_NOT_PERSISTED' ? response.navigationVerification : response.themeVerification) });
616
666
  }
617
667
  }
618
668
 
@@ -3,6 +3,7 @@
3
3
  const { getMaterialSourcingGuidance } = require('../asset/ai-image');
4
4
  const { getVisualDecisionPolicy } = require('../design-plan/visual-policy');
5
5
  const { getPageNavigationContract } = require('../design-plan/navigation-policy');
6
+ const { ENTRY_MODES } = require('../design-plan/entry-navigation');
6
7
  const { DIVIDER_TYPES, DEFAULT_DIVIDER_TYPE } = require('../app/form-field-validator');
7
8
 
8
9
  const SIDE_EFFECT_BASES = Object.freeze({
@@ -1058,12 +1059,12 @@ const COMMAND_GROUPS = [
1058
1059
  command('design-plan.catalog', ['design-plan', 'catalog'], 'design-plan catalog [--json]', 'help.cmd_design_plan_catalog', {
1059
1060
  requiresLogin: false, output: 'json',
1060
1061
  args: [{ name: 'json', type: 'boolean', source: 'option', builder_options: ['--json'] }],
1061
- notes: ['Read available theme IDs and page patterns before init when the theme mapping is unknown. Reuse this result for the current planning session.'],
1062
+ notes: ['Read available theme IDs and page patterns before init when the theme mapping is unknown. Theme summaries describe deep/light navigation and deep/light content in natural language; they do not expose navTheme/contentTheme assignment syntax. Reuse this result for the current planning session.'],
1062
1063
  }),
1063
1064
  command('design-plan.init', ['design-plan', 'init'], 'design-plan init <requirement-brief.json> [--theme-id <id>] [--output-dir <dir>] [--json]', 'help.cmd_design_plan_init', {
1064
1065
  requiresLogin: false,
1065
1066
  output: 'text|json',
1066
- notes: ['Returns preserved business facts, authoring.pendingFields with file/path/message, typed examples in authoring-context.md, and materialize.command with materialize.shell (powershell on Windows, posix elsewhere). Execute the command in that shell. Complete the pending facts, review business coverage, then set ready=true. Author ordered page blocks as {name,purpose}; omitted contentPriority and contentRichness.contentLayers derive from these blocks, preserving explicit overrides. Author project-specific acceptanceCriteria; materialize merges them with resource-based checks. A string visualSelection.colorStrategy is preserved as usage text with primaryColor pending; invalid types fail before files are written. Init guidance is preliminary; materialize still validates the completed plan.'],
1067
+ notes: ['Requires a selected theme from --theme-id or visualSelection.themeId. There is no navigation-tone argument: init reads navTheme from the selected theme template, overwrites stale navigationStyle.tone, and records toneSource=theme_derived. Free creative preserves an explicitly authored navigationStyle.tone and records toneSource=project_defined. Returns preserved business facts, authoring.pendingFields with file/path/message, typed examples in authoring-context.md, and materialize.command with materialize.shell (powershell on Windows, posix elsewhere). Execute the command in that shell. Complete the pending facts, review business coverage, then set ready=true. Author ordered page blocks as {name,purpose}; omitted contentPriority and contentRichness.contentLayers derive from these blocks, preserving explicit overrides. Author project-specific acceptanceCriteria; materialize merges them with resource-based checks. A string visualSelection.colorStrategy is preserved as usage text with primaryColor pending; invalid types fail before files are written. Init guidance is preliminary; materialize still validates the completed plan.'],
1067
1068
  args: [
1068
1069
  { name: 'requirementBrief', type: 'file', required: true, source: 'positional', position: 0, builder_options: ['--requirement-brief'] },
1069
1070
  { name: 'themeId', type: 'string', required: false, source: 'option', builder_options: ['--theme-id'] },
@@ -1080,13 +1081,14 @@ const COMMAND_GROUPS = [
1080
1081
  ],
1081
1082
  notes: ['Updates completed fact modules in preview/ drafts. Modules share a source base; one writer updates changed sections and preserves custom CSS. Final materialize validates the complete plan and writes PRD, design, HTML and theme together.'],
1082
1083
  }),
1083
- command('design-plan.materialize', ['design-plan', 'materialize'], 'design-plan materialize <build-plan.json> [--from-preview | --business-file <json> --visual-file <json>] [--output-dir <dir>] [--check] [--json]', 'help.cmd_design_plan_materialize', {
1084
- notes: ['Validates image slots before writing artifacts. JSON assetTasks lists taskKey/taskState, independent searches ordered by required/hero/design order, collection-wide concurrency, host-enforced time budgets, two-round limits, resume policy, output paths and resolve argv. After matching plan confirmation, executionContract requires checking background Agent and Bash separately, dispatching only verified nonblocking tools or doing authorized business work before synchronous asset batches; record real job IDs and continue app/form/page work; replace <appType> with the real ID for upload. Materialized PRD execution pages include navigationPolicy derived from app/page navigation: platform-shell is content-only; standalone without a planned menu renders no application menu. This command performs no search or upload. Local asset inputs resolve against the command cwd; absolute paths survive page-task directory changes.'],
1084
+ command('design-plan.materialize', ['design-plan', 'materialize'], 'design-plan materialize <build-plan.json> [--from-preview | --business-file <json> --visual-file <json>] [--output-dir <dir>] [--rebase-parts] [--check] [--json]', 'help.cmd_design_plan_materialize', {
1085
+ notes: ['Derives navigationStyle.tone and appConfig.navTheme from the selected theme template. Navigation appearance tokens come directly from that template plus explicit visualStyle.tokens; mode-independent tokens such as --pod-nav-menu-item-selected-shadow flow through the base token contract; materialize does not synthesize a light/dark replacement palette. Free creative uses project-authored navigation tone and tokens. Validates image slots before writing artifacts. JSON assetTasks lists taskKey/taskState, independent searches ordered by required/hero/design order, collection-wide concurrency, host-enforced time budgets, two-round limits, resume policy, output paths and resolve argv. After matching plan confirmation, executionContract requires checking background Agent and Bash separately, dispatching only verified nonblocking tools or doing authorized business work before synchronous asset batches; record real job IDs and continue app/form/page work; replace <appType> with the real ID for upload. Materialized PRD execution pages include navigationPolicy derived from app/page navigation: platform-shell is content-only; standalone without a planned menu renders no application menu. This command performs no search or upload. Local asset inputs resolve against the command cwd; absolute paths survive page-task directory changes.'],
1085
1086
  requiresLogin: false,
1086
1087
  output: 'text|json',
1087
1088
  args: [
1088
1089
  { name: 'buildPlan', type: 'file', required: true, source: 'positional', position: 0, builder_options: ['--build-plan'] },
1089
1090
  { name: 'fromPreview', type: 'boolean', required: false, source: 'option', builder_options: ['--from-preview'] },
1091
+ { name: 'rebaseParts', type: 'boolean', source: 'option', builder_options: ['--rebase-parts'] },
1090
1092
  { name: 'businessFile', type: 'file', required: false, source: 'option', builder_options: ['--business-file'] },
1091
1093
  { name: 'visualFile', type: 'file', required: false, source: 'option', builder_options: ['--visual-file'] },
1092
1094
  { name: 'outputDir', type: 'string', required: false, source: 'option', builder_options: ['--output-dir'] },
@@ -1095,12 +1097,12 @@ const COMMAND_GROUPS = [
1095
1097
  ],
1096
1098
  }),
1097
1099
  command('design-plan.patch', ['design-plan', 'patch'], 'design-plan patch <build-plan.json> --set <path=value> [--set <path=value> ...] [--materialize] [--output-dir <dir>] [--json]', 'help.cmd_design_plan_patch', {
1098
- notes: ['Edit the existing plan with one batch of --set assignments; do not restart init or rewrite business.json/visual.json. With --materialize, update changed PRD/design/HTML sections and theme tokens, preserving unrelated local content and custom CSS. JSON updated lists artifact files actually written. The CLI maintains .build-plan-artifacts.json as the generated baseline; overlapping local edits fail before any writes. Without --materialize, validate and save source facts without rendering HTML or writing artifacts. Unpresented edits keep the draft revision; substantive edits to a presented version advance once and clear approval. Asset materialStatus/missingAssets updates preserve approval.'],
1100
+ notes: ['Edit the existing plan with one batch of --set assignments; do not restart init or rewrite business.json/visual.json. navigationStyle.tone, navigationStyle.toneSource and execution.appConfig.navTheme are derived and cannot be patched; change the selected theme instead. For free-creative only, navigationStyle.tone is authored and can be patched. With --materialize, update changed PRD/design/HTML sections and theme tokens, preserving unrelated local content and custom CSS. JSON updated lists artifact files actually written. The CLI maintains .build-plan-artifacts.json as the generated baseline; overlapping local edits fail before any writes. Without --materialize, validate and save source facts without rendering HTML or writing artifacts. Unpresented edits keep the draft revision; substantive edits to a presented version advance once and clear approval. Asset materialStatus/missingAssets updates preserve approval.'],
1099
1101
  requiresLogin: false,
1100
1102
  output: 'text|json',
1101
1103
  args: [
1102
1104
  { name: 'buildPlan', type: 'file', required: true, source: 'positional', position: 0, builder_options: ['--build-plan'] },
1103
- { name: 'set', type: 'string', required: true, source: 'option', builder_options: ['--set'], repeatable: true, description: 'Field assignment path=value; repeat --set for multiple changes.' },
1105
+ { name: 'set', type: 'string', required: true, source: 'option', builder_options: ['--set'], repeatable: true, description: 'Field assignment path=value; repeat --set for multiple changes. CSS token overrides use visualStyle.tokens.<token>=<value>.' },
1104
1106
  { name: 'materialize', type: 'boolean', source: 'option', builder_options: ['--materialize'] },
1105
1107
  { name: 'outputDir', type: 'string', source: 'option', builder_options: ['--output-dir'] },
1106
1108
  { name: 'json', type: 'boolean', source: 'option', builder_options: ['--json'] },
@@ -1115,15 +1117,18 @@ const COMMAND_GROUPS = [
1115
1117
  { name: 'iconColor', type: 'string', source: 'option', builder_options: ['--icon-color'] },
1116
1118
  { name: 'colour', type: 'string', source: 'option', builder_options: ['--colour', '--theme'], description: 'Platform theme key or custom; CSS colors belong in themeColor.' },
1117
1119
  { name: 'themeColor', type: 'string', source: 'option', builder_options: ['--theme-color', '--themeColor'], description: 'App primary color; themeFile supplies the effective color when both are provided.' },
1118
- { name: 'themeFile', type: 'file', source: 'option', builder_options: ['--theme-file', '--custom-theme-file'], description: 'Application theme CSS; declares --color-brand1-6 and sets colour=custom.' },
1119
- { name: 'navTheme', type: 'string', source: 'option', builder_options: ['--nav-theme', '--navTheme'], description: 'light, dark, white or gray.' },
1120
+ { name: 'themeFile', type: 'file', source: 'option', builder_options: ['--theme-file', '--custom-theme-file'], description: 'Completed application theme CSS, not a placeholder authoring bundle. Reads --color-brand1-6, uploads CSS and sets colour=custom. Supports app-theme.css or app_theme.css; use the actual generated path.' },
1121
+ { name: 'navTheme', type: 'string', source: 'option', builder_options: ['--nav-theme', '--navTheme'], description: 'Platform value: light, dark, white or gray. Generated design flows pass the selected template-derived light/dark value explicitly; this option has no implicit light default.' },
1120
1122
  { name: 'logoSource', type: 'string', source: 'option', builder_options: ['--logo-source', '--logoSource'], description: 'appIcon or customImage; customImage requires an existing homepageLogo.' },
1121
1123
  { name: 'layoutDirection', type: 'string', source: 'option', builder_options: ['--layout', '--layout-direction', '--layoutDirection'], description: 'side, top or l_shape.' },
1122
1124
  { name: 'hideAppNav', type: 'boolean', source: 'option', builder_options: ['--hide-app-nav'] },
1123
1125
  { name: 'showAppNav', type: 'boolean', source: 'option', builder_options: ['--show-app-nav'] },
1124
1126
  ],
1125
1127
  notes: [
1126
- 'Upload application CSS with --theme-file; the primary color is read from CSS and saved with the theme resource.',
1128
+ 'Upload application CSS with --theme-file; the primary color is read from CSS and saved with the theme resource. Edit navigation radius, three border states and selected shadow in design.md, regenerate CSS, then upload; these tokens are not separate update-app flags. Unknown options, missing values and combined --hide-app-nav/--show-app-nav are rejected.',
1129
+ 'One design document and theme CSS cover navigation, application shell, native forms, custom pages and record details. tokens.application-global.appearance.navigation defines navigation surfaces, text and interaction states, logo, groups, search, popups, borders, radius and density. Platform-supported tokens are applied through the active navigation mode; page content consumes the same application theme.',
1130
+ 'navigationVerification reads back explicitly requested navTheme, layoutDirection, hideAppNav and logoSource. A mismatch returns APP_NAVIGATION_NOT_PERSISTED and a nonzero exit code; only readback is retried. themeVerification independently verifies the uploaded theme resource. Verify rendered navigation, form, custom page and record detail after both checks pass.',
1131
+ 'For generated design artifacts, pass themeProfile.navTheme from design.md to --nav-theme. Do not infer it from the business brief or omit it expecting a light default.',
1127
1132
  'Platform preset keys are used independently of --theme-file and --theme-color. Choose --hide-app-nav or --show-app-nav to set navigation visibility.',
1128
1133
  ],
1129
1134
  }),
@@ -1582,9 +1587,13 @@ const COMMAND_GROUPS = [
1582
1587
  command('copy', ['copy'], 'copy [--force]', 'help.cmd_copy', { requiresLogin: false }),
1583
1588
  command('sample', ['sample'], 'sample [--list] [<skill> <name>] [--output <file-or-directory>] [--var KEY=VALUE ...] [--design-file <design.md>] [--style-id <themeId|free-creative>]', 'help.cmd_sample', {
1584
1589
  requiresLogin: false,
1590
+ output: 'text|json',
1585
1591
  notes: [
1586
- 'yida-design application-style --style-id exports a design/CSS/native-layout authoring bundle to an output directory without overwriting files. Use design-plan catalog for presets and its separate creativeOption; free creative requires independent business decisions and explicit design tokens.',
1592
+ 'yida-design app-theme reads concrete tokens from --design-file and writes CSS plus a sibling <output>.tokens.md update snapshot. The same output path preserves project CSS and applies changed tokens. Without --design-file it resets the output to the public base template. Menu radius, normal/hover/selected borders and selected shadow apply to side, L-shaped and top navigation; older CSS gains missing menu-shape rules when the design supplies menu-border tokens.',
1593
+ 'yida-design application-style --style-id supports every catalog theme and exports a three-file design.md/app_theme.css/form-layout.json authoring bundle to an output directory without overwriting files. Brand primary and hover values remain project placeholders until app-theme --design-file generates concrete CSS. Use design-plan catalog for presets and its separate creativeOption; free creative requires independent business decisions and explicit design tokens.',
1594
+ 'Author menu radius, normal/hover/selected borders, selected shadow, item height, padding, gap and shell spacing together in design.md navigation tokens (Fast) or visualStyle.tokens (Plan). These are design values, not separate CLI flags. Preset appearance does not override the business navigation layout. Verify native data-management navigation and business pages in workbench access mode; /admin is the development configuration surface.',
1587
1595
  'Native forms use a component tree with top, left, main, right and between-field regions. Platform form components include tabs, button groups, images/graphics, status areas, dividers, columns and business fields, serving navigation, actions, visual focus, feedback, hierarchy, decoration and data capture. Application-style form-layout.json provides an editable starting layout for openyida create-form: use the supported business fields, Divider and ColumnContainer, and retain other existing components when updating a form.',
1596
+ 'canvas-nav-side/top/mixed/dock consume the same menu radius, normal/hover/selected borders and selected shadow as platform navigation. Side and Dock items read menu item height/padding; top and mixed header items read top-tab height/padding/max-width. Side/top/mixed menus read menu-gap; Dock reads slide-collapsed-menu-gap. Side shell padding uses slide-aside-padding and mixed uses l-aside-padding. Re-export the fragment, integrate it into existing page source and republish to upgrade existing custom navigation. canvas-nav-tabs remains an in-page tab control.',
1588
1597
  'Canvas form-drawer, table-form and trend-combo samples include the maintained CanvasThemeProvider, read the current application CSS variables, and prevent loading-mask border flashes caused by late CSS resets.',
1589
1598
  'form-fields demonstrates field layout, not a default divider design. Choose dividerType for the current business page before creating forms; keep same-level sections consistent and vary different business pages when appropriate.',
1590
1599
  'openyida-page-template canvas-theme outputs the same provider as a reusable fragment; combine its imports and code with the business page in one Canvas file, keeping its scoped loading-mask style. Existing pages must update their provider and be republished; changing application theme CSS alone does not upgrade embedded provider code.',
@@ -1597,10 +1606,10 @@ const COMMAND_GROUPS = [
1597
1606
  { name: 'skill', type: 'string', source: 'positional', position: 0, description: 'Required when copying a sample.' },
1598
1607
  { name: 'name', type: 'string', source: 'positional', position: 1, description: 'Required when copying a sample; use --list for available names.' },
1599
1608
  { name: 'list', type: 'boolean', source: 'option', builder_options: ['--list'] },
1600
- { name: 'output', type: 'file', source: 'option', builder_options: ['--output'] },
1601
- { name: 'var', type: 'string', source: 'option', builder_options: ['--var'], repeatable: true, description: 'Template assignment KEY=VALUE; repeat --var for multiple variables.' },
1602
- { name: 'designFile', type: 'file', source: 'option', builder_options: ['--design-file'], description: 'Design tokens for yida-design app-theme; preserves custom CSS when updating.' },
1603
- { name: 'styleId', type: 'string', source: 'option', builder_options: ['--style-id'], description: 'For yida-design application-style: export paired design.md, app_theme.css and native form-layout.json to --output directory. Includes independent free-creative authoring.' },
1609
+ { name: 'output', type: 'file', source: 'option', builder_options: ['--output'], description: 'Output file for ordinary samples/app-theme; output directory for application-style. Defaults under cwd/.cache/samples; application-style defaults to its application-style subdirectory and rejects an existing bundle file.' },
1610
+ { name: 'var', type: 'string', source: 'option', builder_options: ['--var'], repeatable: true, description: 'Ordinary sample assignment KEY=VALUE; repeat --var for multiple variables. Not accepted by yida-design app-theme or application-style; complete design.md before generating theme CSS.' },
1611
+ { name: 'designFile', type: 'file', source: 'option', builder_options: ['--design-file'], description: 'Only for yida-design app-theme: completed design.md with concrete tokens. Optional for a base-template reset; supply it to generate or incrementally update project CSS.' },
1612
+ { name: 'styleId', type: 'string', source: 'option', builder_options: ['--style-id'], description: 'Required only for yida-design application-style. Accepts any themeId from design-plan catalog, including shared themes and free-creative. Exports design.md, app_theme.css and form-layout.json with brand placeholders; accepts neither --design-file nor --var.' },
1604
1613
  ],
1605
1614
  }),
1606
1615
  command('doctor', ['doctor'], 'doctor [--fix]', 'help.cmd_doctor', { requiresLogin: false }),
@@ -1804,18 +1813,21 @@ function summarizeLocalizedCommands(commands) {
1804
1813
  plan_command_ids: ['design-plan.catalog', 'design-plan.init', 'design-plan.preview', 'design-plan.materialize', 'design-plan.patch'],
1805
1814
  theme_command_ids: ['sample', 'create-app', 'update-app'],
1806
1815
  navigation_command_ids: { platform: ['update-app', 'nav-group'], custom: ['update-app', 'update-form-config', 'get-form-config'] },
1807
- navigation_policy: 'Before PRD planning in Fast and Plan, the agent determines navigation ownership and layout from business context. Follow yida-design/references/navigation-decision.md for entry and layout decisions. Preserve explicit user requirements and existing navigation for local changes; resource-only requests operate on their specified resources and settings. Use native navigation by default for the application workspace, and custom navigation only for an explicitly justified application-level branded menu or special navigation interaction. A service frontend defaults to one coding page with its own menu and all selected business views; a single-step entry can use navigation.type=none. Choose backend native or coding pages by task efficiency. Backend coding pages in platform-shell are content-only: platform menus own cross-module navigation; local Tabs cover categories or states of the current task only. Never turn the management entry menu into a second page navbar, sidebar or module Tabs. Persistent filters/state alone do not justify custom application navigation. Plan handoff pages include derived navigationPolicy; Fast records the same boundary. Do not hide platform navigation to repair duplicate page menus. Store application navigation in navigationType and standalone entry menus in pageSpecHandoff.navigation. Configure a custom frontend menu at page scope and preserve workspace navigation. Record type/source/reason/variant using ai_default for agent ownership decisions and user_selected for explicit user requirements. Include navigation in the overall Plan confirmation; Fast implements the recorded decision. Platform navigation uses update-app --layout top|side|l_shape --show-app-nav, persisting layoutDirection and hideAppNav=n. Preserve stored navType. Without --layout, normalize legacy layoutDirection and navType using the application layout compatibility rules (hoz plus top_side means l_shape; missing layout uses top_fold/top_side for top/l_shape). Apply shell top_fold/none overrides at page scope. Application-wide custom side/top/mixed/dock uses app hiding plus per-page hiding within scope; a standalone frontend in a platform-navigation app uses only page configuration. Read back layoutDirection, hideAppNav and each configured page, then verify the planned frontend and workspace links. Navigation tone is separate from layout. Custom top navigation defaults to edge-to-edge, not floating. Over a hero image, start transparent, add a surface on scroll, restore transparency at the top; expanded menus stay readable. Follow yida-design/references/page-continuity.md; floating requires an explicit design.',
1808
- design_mode_policy: 'Analyze requirements first with yida-requirement-analysis: read only necessary sources before the first question, offer concrete core-function candidates, clarify key usage, and preserve explicit scope and valid answers. Initial intake focuses on core functions and actual usage. Record actual user replies; proceed with dependent planning after a reply or explicit delegation. First-time builds include new apps and existing apps without business pages. After intake, reuse explicit mode choices and detailed supplied plans; if the user delegates the mode or asks for no more questions, use Fast unless Plan is explicit; otherwise, if the mode is unspecified, ask whether to prepare a PRD for confirmation (Plan, more detailed and slower) or build from the supplied requirements (Fast). Without detailed requirements, offer Fast and Plan neutrally. intake.confirmed records scope and key-usage clarification; the plan revision tracks plan approval separately. Planning preparation derives page scenes, theme mapping and navigation before design-plan init; mark AI suggestions and apply navigation_policy. Existing business apps only clarify the current change. A named resource-only request with explicitScope.allowInferredResources=false keeps planning within the specified resources. When theme mapping is missing, query design-plan catalog once and reuse its themes and pagePatterns. Init returns authoring.pendingFields and context with typed examples; complete pending facts and review coverage before setting ready=true. Reuse one complete agent-capabilities summary per unchanged environment. Standard Plan uses design-plan init parallelTasks, then executes the returned materialize.command exactly once with business-file and visual-file; preview and --from-preview are only for explicitly incremental large plans. Present the current plan without revision numbers in user-visible titles, summaries, attachments or questions. Keep revision in internal confirmation fields, validate it before building, and execute its generated artifacts.',
1809
- product_design_policy: 'yida-requirement-analysis owns shared facts and first-time intake. yida-prd owns business planning; yida-design owns visual design. Reuse the same confirmed brief and supplied details. Prepare business and base visuals concurrently, then bind visuals to settled page tasks. yida-app merges and checks the artifacts before creating resources. Plan authors scope, data and rules, page organization, business interactions and acceptance once. Ordered blocks {name,purpose} supply default priority and content layers; explicit designs remain authoritative. Project-specific acceptance criteria are merged with generated resource checks. Plan uses the compact authoring contract and selected theme context; the CLI reads full templates and renders all artifacts. Fast, Plan and single-page design share yida-design/templates/design-themes. Theme templates declare application-global variables from basic-tokens.json with fixed typography, spacing and Tooltip colors, plus scoped custom-page variables; component recipes consume those variables. Explicit project customization stays in visualStyle.tokens. CSS binds light and dark platform navigation to their respective brand colors and preserves white and gray modes.',
1816
+ navigation_policy: 'Before PRD planning in Fast and Plan, the agent determines navigation ownership and layout from business context. Follow yida-design/references/navigation-decision.md for entry and layout decisions. Preserve explicit user requirements and existing navigation for local changes; resource-only requests operate on their specified resources and settings. Use native navigation by default for the application workspace, and custom navigation only for an explicitly justified application-level branded menu or special navigation interaction. A service frontend defaults to one coding page with its own menu and all selected business views; a single-step entry can use navigation.type=none. Choose backend native or coding pages by task efficiency. Backend coding pages in platform-shell are content-only: platform menus own cross-module navigation; local Tabs cover categories or states of the current task only. Never turn the management entry menu into a second page navbar, sidebar or module Tabs. Persistent filters/state alone do not justify custom application navigation. Plan handoff pages include derived navigationPolicy; Fast records the same boundary. Do not hide platform navigation to repair duplicate page menus. Store application navigation in navigationType and standalone entry menus in pageSpecHandoff.navigation. Configure a custom frontend menu at page scope and preserve workspace navigation. Record type/source/reason/variant using ai_default for agent ownership decisions and user_selected for explicit user requirements. Include navigation in the overall Plan confirmation; Fast implements the recorded decision. Platform navigation uses update-app --layout top|side|l_shape --show-app-nav, persisting layoutDirection and hideAppNav=n. Preserve stored navType. Without --layout, normalize legacy layoutDirection and navType using the application layout compatibility rules (hoz plus top_side means l_shape; missing layout uses top_fold/top_side for top/l_shape). Apply shell top_fold/none overrides at page scope. Application-wide custom side/top/mixed/dock uses app hiding plus per-page hiding within scope; a standalone frontend in a platform-navigation app uses only page configuration. Read back layoutDirection, hideAppNav and each configured page, then verify the planned frontend and workspace links. Navigation structure is separate from tone. Navigation tone is derived from the final selected theme template, never guessed from the business brief or implicitly defaulted to light; apply that explicit value with update-app --nav-theme. Custom top navigation defaults to edge-to-edge, not floating. Over a hero image, start transparent, add a surface on scroll, restore transparency at the top; expanded menus stay readable. Follow yida-design/references/page-continuity.md; floating requires an explicit design.',
1817
+ design_mode_policy: 'Analyze requirements first with yida-requirement-analysis: read only necessary sources before the first question, offer concrete core-function candidates, clarify key usage, and preserve explicit scope and valid answers. Initial intake focuses on core functions and actual usage. Record actual user replies; proceed with dependent planning after a reply or explicit delegation. First-time builds include new apps and existing apps without business pages. After intake, reuse explicit mode choices and detailed supplied plans; if the user delegates the mode or asks for no more questions, use Fast unless Plan is explicit; otherwise, if the mode is unspecified, ask whether to prepare a PRD for confirmation (Plan, more detailed and slower) or build from the supplied requirements (Fast). Without detailed requirements, offer Fast and Plan neutrally. intake.confirmed records scope and key-usage clarification; the plan revision tracks plan approval separately. Fast and Plan share one three-direction visual generation rule. Fast compares exactly three directions internally and keeps the selected result. When Plan is explicit and the user has not supplied a complete visual direction, generate exactly three directions and use ask_human for the style choice before design-plan init; do not wait for the user to request a comparison. Planning preparation derives page scenes, selected theme mapping and navigation structure before init; mark AI suggestions and apply navigation_policy. Existing business apps only clarify the current change. A named resource-only request with explicitScope.allowInferredResources=false keeps planning within the specified resources. When theme mapping is missing, query design-plan catalog once and reuse its themes and pagePatterns. Init returns authoring.pendingFields and context with typed examples; complete pending facts and review coverage before setting ready=true. Reuse one complete agent-capabilities summary per unchanged environment. Standard Plan uses design-plan init parallelTasks, then executes the returned materialize.command exactly once with business-file and visual-file; preview and --from-preview are only for explicitly incremental large plans. Present the current plan without revision numbers in user-visible titles, summaries, attachments or questions. Keep revision in internal confirmation fields, validate it before building, and execute its generated artifacts.',
1818
+ product_design_policy: 'yida-requirement-analysis owns shared facts and first-time intake. yida-prd owns business planning; yida-design owns visual design. Reuse the same confirmed brief and supplied details. Prepare business and base visuals concurrently, then bind visuals to settled page tasks. yida-app merges and checks the artifacts before creating resources. Plan authors scope, data and rules, page organization, business interactions and acceptance once. Ordered blocks {name,purpose} supply default priority and content layers; explicit designs remain authoritative. Project-specific acceptance criteria are merged with generated resource checks. Plan uses the compact authoring contract and selected theme context; the CLI reads full templates and renders all artifacts. Fast, Plan and single-page design share yida-design/templates/design-themes and the same three-direction generation rule. Theme templates declare application-global variables from basic-tokens.json with fixed typography, spacing and Tooltip colors, plus scoped custom-page variables; component recipes consume those variables. Each selected template is the authority for navTheme, its six navigation color tokens, and its selected-item shadow token; free-creative authors its own navigation tone and tokens. Explicit project customization stays in visualStyle.tokens. The CLI applies the selected template palette to its derived light or dark navigation mode, preserves mode-independent navigation appearance tokens, preserves inactive and white/gray platform modes, and never synthesizes a replacement navigation palette.',
1810
1819
  ui_guidance_policy: 'Page implementation consumes yida-prd prd.md for positioning, information architecture, page prototype, native form entry policy, material strategy, business-specific checks, resource creation order, page implementation delivery order, navigation order, and acceptance criteria; it consumes yida-design design.md for app custom theme CSS delivery, themeColor/navTheme, visual states, visualScaffold, surface material, rounded rules, density rules, components, state styling, and page-level imageNeed. When a page is imageNeed=required, or beneficial with declared image slots, yida-image-assets prepares a traceable asset manifest alongside page layout and interaction work; wait for final images only at that page\'s image binding and acceptance. imageNeed=none skips the branch. prd.md and design.md remain the only design sources of truth. Page implementation may extract page-spec.json as a derived implementation handoff from prd.md + design.md; conflicts are resolved by sending business conflicts to yida-prd and visual conflicts to yida-design before regenerating the spec. Core normal forms default to 1-3 business sample records before page implementation, followed by query readback. An explicit opt-out, configuration dictionary, sensitive data, or lack of safely constructible values requires a recorded skip reason. Screenshots, public sharing, data-source deep binding, and fine navigation grouping are optional after explicit user request or PRD acceptance criteria.',
1811
1820
  default_nav_order_policy: 'For application-wide custom navigation, implement each entry menu and verify app/page navigation hiding. A standalone frontend preserves platform navigation for the management workspace; frontend-only delivery skips platform ordering. After all scoped resources and page publications finish, perform exactly one navigation order operation. Use management tasks and their default destination, without creating a homepage or putting a frontend page first. When execution.entryRecommendation exists, derive navigationOrder from its management/workspace menus. Call openyida nav-group order <appType> <items...> for an explicit order; otherwise call openyida nav-group auto-order <appType> once for legacy single-workspace plans. Do not use openyida publish ... --auto-nav-order for per-page application builds. Explicit and automatic ordering are mutually exclusive; never generate per-item move loops.',
1812
- final_link_policy: 'Return exactly one user-visible application entry group, never one artifact or link card per form, process, report, schema, manifest, PRD, design file, or intermediate artifact. Include one verified management entry when a management or unified workspace is in scope: the app workbench URL or a planned workbench/formUuid URL with its real viewUuid. Native management does not require a display homepage; frontend-only delivery includes its verified frontend entry and developer admin URL, without inventing a business backend. Add the clean custom page URL only when PRD entryMode=standalone and get-form-config readback confirms renderNav=false (fallback to isRenderNav only when renderNav is absent). Complete application delivery defaults to 2-3 distinct entries: frontend or unified workspace, business backend when separately planned, and developer admin. agent-capabilities application_entry_policy.entries.admin=include is independent of auth runtime. Read adminUrl from create-app or app-list results; route construction does not verify recipient permissions. Explicit user exclusions take precedence; single-page tasks retain their scope. Put the business summary, verification results and remaining work in the terminal delivery artifact description; when no delivery tool is available, return the same content and entry group in the final response. Summarize business resources by capability or count, but every resource count, seed-record count, and completed/verified claim must come from that resource\'s own successful result or readback. When the user or caller explicitly requests a resource manifest, resource UUIDs/IDs, publish status, or test-data summary, include one concise verified delivery manifest in that description (or the final response when no delivery tool is available).',
1821
+ final_link_policy: 'Return exactly one user-visible application entry group, never one artifact or link card per form, process, report, schema, manifest, PRD, design file, or intermediate artifact. Include one verified management entry when a management or unified workspace is in scope: the app workbench URL or a planned workbench/formUuid URL with its real viewUuid. Backend-only returns its verified business backend entry and developer admin URL without adding a frontend. Native management does not require a display homepage; frontend-only delivery includes its verified frontend entry and developer admin URL, without inventing a business backend. Add the clean custom page URL only when PRD entryMode=standalone and get-form-config readback confirms renderNav=false (fallback to isRenderNav only when renderNav is absent). Complete application delivery defaults to 2-3 distinct entries: frontend or unified workspace, business backend when separately planned, and developer admin. agent-capabilities application_entry_policy.entries.admin=include is independent of auth runtime. Read adminUrl from create-app or app-list results; route construction does not verify recipient permissions. Explicit user exclusions take precedence; single-page tasks retain their scope. Put the business summary, verification results and remaining work in the terminal delivery artifact description; when no delivery tool is available, return the same content and entry group in the final response. Summarize business resources by capability or count, but every resource count, seed-record count, and completed/verified claim must come from that resource\'s own successful result or readback. When the user or caller explicitly requests a resource manifest, resource UUIDs/IDs, publish status, or test-data summary, include one concise verified delivery manifest in that description (or the final response when no delivery tool is available).',
1813
1822
  entry_navigation_contract: {
1814
1823
  reference: 'yida-skills/skills/yida-app/references/entry-navigation.md',
1815
1824
  brief_path: 'entryRecommendation',
1816
1825
  plan_path: 'execution.entryRecommendation',
1817
1826
  input_transport: 'JSON file or design-plan patch --set execution.entryRecommendation=<json>; not a CLI flag',
1818
- modes: ['unified', 'service-management', 'frontend-only'],
1827
+ modes: [...ENTRY_MODES],
1828
+ mode_meaning: 'These modes describe how people use the application, not developer administration: unified shares business pages with role-based menus and permissions; service-management separates pages for people requesting a service and people processing it; frontend-only delivers only the requested frontend; backend-only delivers staff pages for recording, processing or maintaining business, with service requests originating elsewhere or no service entry required. For frontend-only submissions that need processing, record the existing system, staff entry or automation in reason and business flows; unresolved handling remains an open question. Backend-only entries use role management; new unified plans normally use workspace, while legacy unified plans retain their roles. Different roles alone do not require separate frontends and backends. Separate entries can share one application and its data.',
1829
+ user_facing_explanation: 'Say whether the system has separate frontend and business-backend pages, then explain who uses each entry, what they see and what they can do. Choose from confirmed tasks; if actual usage is unclear and changes the page plan, ask a concrete business-use question.',
1830
+ derived_summary: 'execution.entryModeSummary is generated for PRD and preview from the selected mode; do not author it in build-plan.json.',
1819
1831
  roles: ['service', 'management', 'workspace'],
1820
1832
  entry_required_fields: ['key', 'name', 'role', 'menu', 'defaultMenuKey'],
1821
1833
  service_page_binding: 'sceneKey of a standalone page',
@@ -1894,7 +1906,7 @@ function summarizeLocalizedCommands(commands) {
1894
1906
  'yida-data-source-connectors',
1895
1907
  'yida-dashboard',
1896
1908
  ],
1897
- completion_contract: 'Clarify core functions and actual usage first, then resolve the required resource context and settle entry navigation before PRD planning. Fast generates prd.md and design.md in parallel; Plan uses design-plan init/preview/materialize/patch and confirms the current revision. Validate both artifacts, create or reuse app and core forms/processes, seed and query-check core normal-form samples or record an allowed skip reason, then implement the primary page in PRD resource order, publish it, apply PRD navigation order or lightweight fallback navigation order for platform navigation, or verify app and per-page hiding for application-wide custom navigation. For a standalone frontend in a platform-navigation app, verify that page independently and retain workspace navigation. Return one named application entry group. Include workbench when a management or unified workspace is in scope; frontend-only delivery includes its verified frontend entry and developer admin URL, without inventing a business backend. Always include developer adminUrl for complete application delivery unless explicitly excluded by the user, regardless of auth runtime; this is separate from the optional business backend. Use create-app or app-list URL fields and state any unavailable entry instead of silently omitting it. Put the verified business summary, results and remaining work in the delivery artifact description; use the final response when no delivery tool is available.',
1909
+ completion_contract: 'Clarify core functions and actual usage first, then resolve the required resource context and settle entry navigation before PRD planning. Fast generates prd.md and design.md in parallel; Plan uses design-plan init/preview/materialize/patch and confirms the current revision. Validate both artifacts, create or reuse app and core forms/processes, seed and query-check core normal-form samples or record an allowed skip reason, then implement the primary page in PRD resource order, publish it, apply PRD navigation order or lightweight fallback navigation order for platform navigation, or verify app and per-page hiding for application-wide custom navigation. For a standalone frontend in a platform-navigation app, verify that page independently and retain workspace navigation. Return one named application entry group. Include workbench when a management or unified workspace is in scope; backend-only delivers its business backend and developer admin URL without adding a frontend; frontend-only delivery includes its verified frontend entry and developer admin URL, without inventing a business backend. Always include developer adminUrl for complete application delivery unless explicitly excluded by the user, regardless of auth runtime; this is separate from the optional business backend. Use create-app or app-list URL fields and state any unavailable entry instead of silently omitting it. Put the verified business summary, results and remaining work in the delivery artifact description; use the final response when no delivery tool is available.',
1898
1910
  },
1899
1911
  },
1900
1912
  };
@@ -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: `
@@ -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
+ };
@@ -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: `
@@ -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
+ };