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
|
@@ -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
|
|
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 (!
|
|
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
|
|
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
|
-
|
|
106
|
-
const
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
|
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,18 +128,37 @@ 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;
|
|
133
158
|
const changed = Object.fromEntries(Object.entries(tokens).filter(([name, value]) => !previous || previous[name] !== value));
|
|
134
159
|
if (!Object.keys(changed).length && tone === previousTone) {
|
|
135
160
|
extractThemeColor(template);
|
|
136
|
-
return template;
|
|
161
|
+
return require('./application-style').applyApplicationStyle(template, metadata, tokens);
|
|
137
162
|
}
|
|
138
163
|
const root = /^:root\s*\{([\s\S]*?)^\}/m.exec(template);
|
|
139
164
|
if (!root) {throw new Error('应用主题模板缺少 :root');}
|
|
@@ -157,6 +182,7 @@ function applyDesignTokens(template, markdown, previousMarkdown) {
|
|
|
157
182
|
}
|
|
158
183
|
let css = `${template.slice(0, root.index)}:root {${body}}${tail}`;
|
|
159
184
|
if (tone) {css = applyNavigationTokens(css, tokens, changed, tone, previousTone);}
|
|
185
|
+
css = require('./application-style').applyApplicationStyle(css, metadata, tokens);
|
|
160
186
|
validateThemeCssContent(css);
|
|
161
187
|
extractThemeColor(css);
|
|
162
188
|
return css;
|
package/lib/app/update-app.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
458
|
-
|
|
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
|
-
|
|
500
|
+
const app = await fetchCurrentApp(params.appType, authRef);
|
|
501
|
+
actual = getThemeSettings(app);
|
|
502
|
+
actualNavigation = getNavigationSettings(app, navigationFields);
|
|
467
503
|
readbackError = undefined;
|
|
468
|
-
|
|
469
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: '
|
|
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
|
}),
|
|
@@ -1160,9 +1165,9 @@ const COMMAND_GROUPS = [
|
|
|
1160
1165
|
{ name: 'check', type: 'boolean', source: 'option', builder_options: ['--check'], description: 'Validate definitions and dependency groups locally.' },
|
|
1161
1166
|
{ name: 'json', type: 'boolean', source: 'option', builder_options: ['--json'] },
|
|
1162
1167
|
],
|
|
1163
|
-
notes: ['Creates independent normal forms concurrently after dependency validation. References resolve from successful schema readbacks. Existing formUuid entries are read-only reuse. Saves IDs and status beside the plan; recoveryAction and nextAction are enum values: rerun_unchanged_plan reuses successful results and resumes known form IDs; inspect_unknown_write_then_reconcile requires checking uncertain writes before rerunning. Results expose appUrl and formUrl; url remains the compatible form entry. Navigation ordering and shared app configuration follow the batch.'],
|
|
1168
|
+
notes: ['Creates independent normal forms concurrently after dependency validation. Each plan item accepts layout (single/double/card/section), theme (default/compact/comfortable), labelAlign (top/left/right), icon and locale, and forwards them to create-form create. References resolve from successful schema readbacks. Existing formUuid entries are read-only reuse. Saves IDs and status beside the plan; recoveryAction and nextAction are enum values: rerun_unchanged_plan reuses successful results and resumes known form IDs; inspect_unknown_write_then_reconcile requires checking uncertain writes before rerunning. Results expose appUrl and formUrl; url remains the compatible form entry. Navigation ordering and shared app configuration follow the batch.'],
|
|
1164
1169
|
}),
|
|
1165
|
-
command('create-form.create', ['create-form', 'create'], 'create-form create <appType> "<formTitle>" <fieldsJsonFile> [--icon auto|<iconName>] [--locale zh_CN|en_US|ja_JP] [--open|--no-open]', 'help.cmd_create_form', {
|
|
1170
|
+
command('create-form.create', ['create-form', 'create'], '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]', 'help.cmd_create_form', {
|
|
1166
1171
|
args: [
|
|
1167
1172
|
{
|
|
1168
1173
|
name: 'appType',
|
|
@@ -1193,6 +1198,36 @@ const COMMAND_GROUPS = [
|
|
|
1193
1198
|
inline_json_rejected_options: ['--fields'],
|
|
1194
1199
|
description: 'Path to a local JSON file containing field definitions.',
|
|
1195
1200
|
},
|
|
1201
|
+
{
|
|
1202
|
+
name: 'layout',
|
|
1203
|
+
type: 'string',
|
|
1204
|
+
required: false,
|
|
1205
|
+
source: 'option',
|
|
1206
|
+
builder_options: ['--layout'],
|
|
1207
|
+
default: 'single',
|
|
1208
|
+
values: ['single', 'double', 'card', 'section'],
|
|
1209
|
+
description: 'Form-wide layout preset: single, double, card or section. Numeric aliases 1 and 2 remain accepted by the CLI.',
|
|
1210
|
+
},
|
|
1211
|
+
{
|
|
1212
|
+
name: 'theme',
|
|
1213
|
+
type: 'string',
|
|
1214
|
+
required: false,
|
|
1215
|
+
source: 'option',
|
|
1216
|
+
builder_options: ['--theme'],
|
|
1217
|
+
default: 'default',
|
|
1218
|
+
values: ['default', 'compact', 'comfortable'],
|
|
1219
|
+
description: 'Form density preset: default, compact or comfortable; this is not the application visual theme.',
|
|
1220
|
+
},
|
|
1221
|
+
{
|
|
1222
|
+
name: 'labelAlign',
|
|
1223
|
+
type: 'string',
|
|
1224
|
+
required: false,
|
|
1225
|
+
source: 'option',
|
|
1226
|
+
builder_options: ['--label-align'],
|
|
1227
|
+
default: 'top',
|
|
1228
|
+
values: ['top', 'left', 'right'],
|
|
1229
|
+
description: 'PC field-label alignment: top, left or right.',
|
|
1230
|
+
},
|
|
1196
1231
|
{
|
|
1197
1232
|
name: 'icon',
|
|
1198
1233
|
type: 'string',
|
|
@@ -1203,13 +1238,24 @@ const COMMAND_GROUPS = [
|
|
|
1203
1238
|
value_catalog_command_id: 'create-form.icons',
|
|
1204
1239
|
description: 'Form navigation icon name. Use auto for semantic selection or run create-form.icons for supported values.',
|
|
1205
1240
|
},
|
|
1241
|
+
{
|
|
1242
|
+
name: 'contentLocale',
|
|
1243
|
+
type: 'string',
|
|
1244
|
+
required: false,
|
|
1245
|
+
source: 'option',
|
|
1246
|
+
builder_options: ['--locale', '--content-locale', '--lang'],
|
|
1247
|
+
values: ['zh_CN', 'en_US', 'ja_JP'],
|
|
1248
|
+
description: 'Content locale: zh_CN, en_US or ja_JP (normalized locale aliases are also accepted).',
|
|
1249
|
+
},
|
|
1250
|
+
{ name: 'open', type: 'boolean', required: false, source: 'option', builder_options: ['--open'] },
|
|
1251
|
+
{ name: 'noOpen', type: 'boolean', required: false, source: 'option', builder_options: ['--no-open'] },
|
|
1206
1252
|
],
|
|
1207
1253
|
canonical: {
|
|
1208
1254
|
command_id: 'create-form.create',
|
|
1209
1255
|
path: ['create-form', 'create'],
|
|
1210
1256
|
argv_template: ['create-form', 'create', '<appType>', '<formTitle>', '<fieldsJsonFile>'],
|
|
1211
1257
|
display: 'openyida create-form create <appType> "<formTitle>" <fieldsJsonFile>',
|
|
1212
|
-
builder: 'openyida commands build create-form.create --app-type <appType> --form-title "<formTitle>" --fields-json-file <fieldsJsonFile> [--icon <iconName>] --json',
|
|
1258
|
+
builder: 'openyida commands build create-form.create --app-type <appType> --form-title "<formTitle>" --fields-json-file <fieldsJsonFile> [--layout single|double|card|section] [--theme default|compact|comfortable] [--label-align top|left|right] [--icon <iconName>] [--locale zh_CN|en_US|ja_JP] [--open|--no-open] --json',
|
|
1213
1259
|
},
|
|
1214
1260
|
deprecatedPatterns: [
|
|
1215
1261
|
{
|
|
@@ -1239,8 +1285,8 @@ const COMMAND_GROUPS = [
|
|
|
1239
1285
|
],
|
|
1240
1286
|
examples: [
|
|
1241
1287
|
'openyida create-form create APP_XXX "访客登记" .cache/openyida/visitor/fields.json',
|
|
1242
|
-
'openyida create-form create APP_XXX "访客登记" .cache/openyida/visitor/fields.json --icon name-card',
|
|
1243
|
-
'openyida commands build create-form.create --app-type APP_XXX --form-title "访客登记" --fields-json-file .cache/openyida/visitor/fields.json --json',
|
|
1288
|
+
'openyida create-form create APP_XXX "访客登记" .cache/openyida/visitor/fields.json --layout section --theme comfortable --label-align left --icon name-card --locale zh_CN --no-open',
|
|
1289
|
+
'openyida commands build create-form.create --app-type APP_XXX --form-title "访客登记" --fields-json-file .cache/openyida/visitor/fields.json --layout section --theme comfortable --label-align left --locale zh_CN --no-open --json',
|
|
1244
1290
|
],
|
|
1245
1291
|
notes: ['Divider accepts the 23 visible platform styles (none is excluded) through field JSON dividerType, not a CLI flag. Omission falls back to bold-with-thin; invalid supplied styles fail. Choose per business page and keep same-level sections consistent; see summary.core_workflows.full_app_build.divider_style_contract.'],
|
|
1246
1292
|
}),
|
|
@@ -1539,9 +1585,15 @@ const COMMAND_GROUPS = [
|
|
|
1539
1585
|
output: 'text|json',
|
|
1540
1586
|
}),
|
|
1541
1587
|
command('copy', ['copy'], 'copy [--force]', 'help.cmd_copy', { requiresLogin: false }),
|
|
1542
|
-
command('sample', ['sample'], 'sample [--list] [<skill> <name>] [--output <file>] [--var KEY=VALUE ...] [--design-file <design.md>]', 'help.cmd_sample', {
|
|
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', {
|
|
1543
1589
|
requiresLogin: false,
|
|
1590
|
+
output: 'text|json',
|
|
1544
1591
|
notes: [
|
|
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.',
|
|
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.',
|
|
1545
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.',
|
|
1546
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.',
|
|
1547
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.',
|
|
@@ -1554,9 +1606,10 @@ const COMMAND_GROUPS = [
|
|
|
1554
1606
|
{ name: 'skill', type: 'string', source: 'positional', position: 0, description: 'Required when copying a sample.' },
|
|
1555
1607
|
{ name: 'name', type: 'string', source: 'positional', position: 1, description: 'Required when copying a sample; use --list for available names.' },
|
|
1556
1608
|
{ name: 'list', type: 'boolean', source: 'option', builder_options: ['--list'] },
|
|
1557
|
-
{ name: 'output', type: 'file', source: 'option', builder_options: ['--output'] },
|
|
1558
|
-
{ name: 'var', type: 'string', source: 'option', builder_options: ['--var'], repeatable: true, description: '
|
|
1559
|
-
{ name: 'designFile', type: 'file', source: 'option', builder_options: ['--design-file'], description: '
|
|
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.' },
|
|
1560
1613
|
],
|
|
1561
1614
|
}),
|
|
1562
1615
|
command('doctor', ['doctor'], 'doctor [--fix]', 'help.cmd_doctor', { requiresLogin: false }),
|
|
@@ -1737,7 +1790,7 @@ function summarizeLocalizedCommands(commands) {
|
|
|
1737
1790
|
join_owner_skill_id: 'yida-app',
|
|
1738
1791
|
},
|
|
1739
1792
|
ordinary_jsx_skill_id: 'yida-custom-page',
|
|
1740
|
-
form_page_policy: 'Use yida-create-form-page for form structure. Use create-form.batch to create independent normal forms concurrently, resolve dependencies from real IDs and read back fields; apply shared app configuration and navigation order afterward.
|
|
1793
|
+
form_page_policy: 'Use yida-create-form-page for form structure and business actions. Use create-form.batch to create independent normal forms concurrently, resolve dependencies from real IDs and read back fields; apply shared app configuration, application theme, and navigation order afterward.',
|
|
1741
1794
|
divider_style_contract: {
|
|
1742
1795
|
reference: 'yida-skills/skills/yida-create-form-page/references/form-field-properties.md#divider',
|
|
1743
1796
|
input: 'fields[].dividerType (also inside layout children); field JSON, not a CLI flag',
|
|
@@ -1760,18 +1813,21 @@ function summarizeLocalizedCommands(commands) {
|
|
|
1760
1813
|
plan_command_ids: ['design-plan.catalog', 'design-plan.init', 'design-plan.preview', 'design-plan.materialize', 'design-plan.patch'],
|
|
1761
1814
|
theme_command_ids: ['sample', 'create-app', 'update-app'],
|
|
1762
1815
|
navigation_command_ids: { platform: ['update-app', 'nav-group'], custom: ['update-app', 'update-form-config', 'get-form-config'] },
|
|
1763
|
-
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
|
|
1764
|
-
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
|
|
1765
|
-
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.
|
|
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.',
|
|
1766
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.',
|
|
1767
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.',
|
|
1768
|
-
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).',
|
|
1769
1822
|
entry_navigation_contract: {
|
|
1770
1823
|
reference: 'yida-skills/skills/yida-app/references/entry-navigation.md',
|
|
1771
1824
|
brief_path: 'entryRecommendation',
|
|
1772
1825
|
plan_path: 'execution.entryRecommendation',
|
|
1773
1826
|
input_transport: 'JSON file or design-plan patch --set execution.entryRecommendation=<json>; not a CLI flag',
|
|
1774
|
-
modes: [
|
|
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.',
|
|
1775
1831
|
roles: ['service', 'management', 'workspace'],
|
|
1776
1832
|
entry_required_fields: ['key', 'name', 'role', 'menu', 'defaultMenuKey'],
|
|
1777
1833
|
service_page_binding: 'sceneKey of a standalone page',
|
|
@@ -1850,7 +1906,7 @@ function summarizeLocalizedCommands(commands) {
|
|
|
1850
1906
|
'yida-data-source-connectors',
|
|
1851
1907
|
'yida-dashboard',
|
|
1852
1908
|
],
|
|
1853
|
-
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.',
|
|
1854
1910
|
},
|
|
1855
1911
|
},
|
|
1856
1912
|
};
|